diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2014-02-22 14:12:29 +0100 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2014-02-22 14:12:29 +0100 |
commit | 8b7e8ae2249ffd9aa2c67536554eb9f6b6636ba5 (patch) | |
tree | 1b728b46f7f7143f67b603fdd78f023a92f2b649 | |
parent | 192c14bd87aa2ea930bc4a3954a07c1cab46a3cc (diff) | |
download | busybox-w32-8b7e8ae2249ffd9aa2c67536554eb9f6b6636ba5.tar.gz busybox-w32-8b7e8ae2249ffd9aa2c67536554eb9f6b6636ba5.tar.bz2 busybox-w32-8b7e8ae2249ffd9aa2c67536554eb9f6b6636ba5.zip |
wget: add support for https using "openssl s_client" as a helper
www.kernel.org started redirecting http:// to https://
making https support mandatory for any auto build scripts.
function old new delta
wget_main 2631 2971 +340
parse_url 409 471 +62
.rodata 115607 115626 +19
P_HTTPS - 6 +6
P_HTTP - 5 +5
P_FTP - 4 +4
------------------------------------------------------------------------------
(add/remove: 3/0 grow/shrink: 3/0 up/down: 436/0) Total: 436 bytes
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r-- | networking/wget.c | 118 |
1 files changed, 92 insertions, 26 deletions
diff --git a/networking/wget.c b/networking/wget.c index 7ca947aec..dfea3d4d2 100644 --- a/networking/wget.c +++ b/networking/wget.c | |||
@@ -47,10 +47,13 @@ struct host_info { | |||
47 | char *allocated; | 47 | char *allocated; |
48 | const char *path; | 48 | const char *path; |
49 | char *user; | 49 | char *user; |
50 | const char *protocol; | ||
50 | char *host; | 51 | char *host; |
51 | int port; | 52 | int port; |
52 | smallint is_ftp; | ||
53 | }; | 53 | }; |
54 | static const char P_FTP[] = "ftp"; | ||
55 | static const char P_HTTP[] = "http"; | ||
56 | static const char P_HTTPS[] = "https"; | ||
54 | 57 | ||
55 | 58 | ||
56 | /* Globals */ | 59 | /* Globals */ |
@@ -219,7 +222,7 @@ static FILE *open_socket(len_and_sockaddr *lsa) | |||
219 | /* glibc 2.4 seems to try seeking on it - ??! */ | 222 | /* glibc 2.4 seems to try seeking on it - ??! */ |
220 | /* hopefully it understands what ESPIPE means... */ | 223 | /* hopefully it understands what ESPIPE means... */ |
221 | fp = fdopen(fd, "r+"); | 224 | fp = fdopen(fd, "r+"); |
222 | if (fp == NULL) | 225 | if (!fp) |
223 | bb_perror_msg_and_die(bb_msg_memory_exhausted); | 226 | bb_perror_msg_and_die(bb_msg_memory_exhausted); |
224 | 227 | ||
225 | return fp; | 228 | return fp; |
@@ -274,23 +277,31 @@ static void parse_url(const char *src_url, struct host_info *h) | |||
274 | free(h->allocated); | 277 | free(h->allocated); |
275 | h->allocated = url = xstrdup(src_url); | 278 | h->allocated = url = xstrdup(src_url); |
276 | 279 | ||
277 | if (strncmp(url, "ftp://", 6) == 0) { | 280 | h->protocol = P_FTP; |
278 | h->port = bb_lookup_port("ftp", "tcp", 21); | 281 | p = strstr(url, "://"); |
279 | h->host = url + 6; | 282 | if (p) { |
280 | h->is_ftp = 1; | 283 | *p = '\0'; |
281 | } else | 284 | h->host = p + 3; |
282 | if (strncmp(url, "http://", 7) == 0) { | 285 | if (strcmp(url, P_FTP) == 0) { |
283 | h->host = url + 7; | 286 | h->port = bb_lookup_port(P_FTP, "tcp", 21); |
287 | } else | ||
288 | if (strcmp(url, P_HTTPS) == 0) { | ||
289 | h->port = bb_lookup_port(P_HTTPS, "tcp", 443); | ||
290 | h->protocol = P_HTTPS; | ||
291 | } else | ||
292 | if (strcmp(url, P_HTTP) == 0) { | ||
284 | http: | 293 | http: |
285 | h->port = bb_lookup_port("http", "tcp", 80); | 294 | h->port = bb_lookup_port(P_HTTP, "tcp", 80); |
286 | h->is_ftp = 0; | 295 | h->protocol = P_HTTP; |
287 | } else | 296 | } else { |
288 | if (!strstr(url, "//")) { | 297 | *p = ':'; |
298 | bb_error_msg_and_die("not an http or ftp url: %s", sanitize_string(url)); | ||
299 | } | ||
300 | } else { | ||
289 | // GNU wget is user-friendly and falls back to http:// | 301 | // GNU wget is user-friendly and falls back to http:// |
290 | h->host = url; | 302 | h->host = url; |
291 | goto http; | 303 | goto http; |
292 | } else | 304 | } |
293 | bb_error_msg_and_die("not an http or ftp url: %s", sanitize_string(url)); | ||
294 | 305 | ||
295 | // FYI: | 306 | // FYI: |
296 | // "Real" wget 'http://busybox.net?var=a/b' sends this request: | 307 | // "Real" wget 'http://busybox.net?var=a/b' sends this request: |
@@ -472,6 +483,56 @@ static FILE* prepare_ftp_session(FILE **dfpp, struct host_info *target, len_and_ | |||
472 | return sfp; | 483 | return sfp; |
473 | } | 484 | } |
474 | 485 | ||
486 | static int spawn_https_helper(const char *host, unsigned port) | ||
487 | { | ||
488 | char *allocated = NULL; | ||
489 | int sp[2]; | ||
490 | int pid; | ||
491 | |||
492 | if (socketpair(AF_UNIX, SOCK_STREAM, 0, sp) != 0) | ||
493 | /* Kernel can have AF_UNIX support disabled */ | ||
494 | bb_perror_msg_and_die("socketpair"); | ||
495 | |||
496 | if (!strchr(host, ':')) | ||
497 | host = allocated = xasprintf("%s:%u", host, port); | ||
498 | |||
499 | pid = BB_MMU ? xfork() : xvfork(); | ||
500 | if (pid == 0) { | ||
501 | /* Child */ | ||
502 | char *argv[6]; | ||
503 | |||
504 | close(sp[0]); | ||
505 | xmove_fd(sp[1], 0); | ||
506 | xdup2(0, 1); | ||
507 | /* | ||
508 | * TODO: develop a tiny ssl/tls helper (using matrixssl?), | ||
509 | * try to exec it here before falling back to big fat openssl. | ||
510 | */ | ||
511 | /* | ||
512 | * openssl s_client -quiet -connect www.kernel.org:443 2>/dev/null | ||
513 | * It prints some debug stuff on stderr, don't know how to suppress it. | ||
514 | * Work around by dev-nulling stderr. We lose all error messages :( | ||
515 | */ | ||
516 | xmove_fd(2, 3); | ||
517 | xopen("/dev/null", O_RDWR); | ||
518 | argv[0] = (char*)"openssl"; | ||
519 | argv[1] = (char*)"s_client"; | ||
520 | argv[2] = (char*)"-quiet"; | ||
521 | argv[3] = (char*)"-connect"; | ||
522 | argv[4] = (char*)host; | ||
523 | argv[5] = NULL; | ||
524 | BB_EXECVP(argv[0], argv); | ||
525 | xmove_fd(3, 2); | ||
526 | bb_perror_msg_and_die("can't execute '%s'", argv[0]); | ||
527 | /* notreached */ | ||
528 | } | ||
529 | |||
530 | /* parent process */ | ||
531 | free(allocated); | ||
532 | close(sp[1]); | ||
533 | return sp[0]; | ||
534 | } | ||
535 | |||
475 | static void NOINLINE retrieve_file_data(FILE *dfp) | 536 | static void NOINLINE retrieve_file_data(FILE *dfp) |
476 | { | 537 | { |
477 | #if ENABLE_FEATURE_WGET_STATUSBAR || ENABLE_FEATURE_WGET_TIMEOUT | 538 | #if ENABLE_FEATURE_WGET_STATUSBAR || ENABLE_FEATURE_WGET_TIMEOUT |
@@ -644,7 +705,8 @@ static void download_one_url(const char *url) | |||
644 | /* Use the proxy if necessary */ | 705 | /* Use the proxy if necessary */ |
645 | use_proxy = (strcmp(G.proxy_flag, "off") != 0); | 706 | use_proxy = (strcmp(G.proxy_flag, "off") != 0); |
646 | if (use_proxy) { | 707 | if (use_proxy) { |
647 | proxy = getenv(target.is_ftp ? "ftp_proxy" : "http_proxy"); | 708 | proxy = getenv(target.protocol == P_FTP ? "ftp_proxy" : "http_proxy"); |
709 | //FIXME: what if protocol is https? Ok to use http_proxy? | ||
648 | use_proxy = (proxy && proxy[0]); | 710 | use_proxy = (proxy && proxy[0]); |
649 | if (use_proxy) | 711 | if (use_proxy) |
650 | parse_url(proxy, &server); | 712 | parse_url(proxy, &server); |
@@ -704,27 +766,31 @@ static void download_one_url(const char *url) | |||
704 | /*G.content_len = 0; - redundant, got_clen = 0 is enough */ | 766 | /*G.content_len = 0; - redundant, got_clen = 0 is enough */ |
705 | G.got_clen = 0; | 767 | G.got_clen = 0; |
706 | G.chunked = 0; | 768 | G.chunked = 0; |
707 | if (use_proxy || !target.is_ftp) { | 769 | if (use_proxy || target.protocol != P_FTP) { |
708 | /* | 770 | /* |
709 | * HTTP session | 771 | * HTTP session |
710 | */ | 772 | */ |
711 | char *str; | 773 | char *str; |
712 | int status; | 774 | int status; |
713 | 775 | ||
714 | 776 | /* Open socket to http(s) server */ | |
715 | /* Open socket to http server */ | 777 | if (target.protocol == P_HTTPS) { |
716 | sfp = open_socket(lsa); | 778 | int fd = spawn_https_helper(server.host, server.port); |
779 | sfp = fdopen(fd, "r+"); | ||
780 | if (!sfp) | ||
781 | bb_perror_msg_and_die(bb_msg_memory_exhausted); | ||
782 | } else | ||
783 | sfp = open_socket(lsa); | ||
717 | 784 | ||
718 | /* Send HTTP request */ | 785 | /* Send HTTP request */ |
719 | if (use_proxy) { | 786 | if (use_proxy) { |
720 | fprintf(sfp, "GET %stp://%s/%s HTTP/1.1\r\n", | 787 | fprintf(sfp, "GET %s://%s/%s HTTP/1.1\r\n", |
721 | target.is_ftp ? "f" : "ht", target.host, | 788 | target.protocol, target.host, |
722 | target.path); | 789 | target.path); |
723 | } else { | 790 | } else { |
724 | if (option_mask32 & WGET_OPT_POST_DATA) | 791 | fprintf(sfp, "%s /%s HTTP/1.1\r\n", |
725 | fprintf(sfp, "POST /%s HTTP/1.1\r\n", target.path); | 792 | (option_mask32 & WGET_OPT_POST_DATA) ? "POST" : "GET", |
726 | else | 793 | target.path); |
727 | fprintf(sfp, "GET /%s HTTP/1.1\r\n", target.path); | ||
728 | } | 794 | } |
729 | 795 | ||
730 | fprintf(sfp, "Host: %s\r\nUser-Agent: %s\r\n", | 796 | fprintf(sfp, "Host: %s\r\nUser-Agent: %s\r\n", |