aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--networking/wget.c118
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};
54static const char P_FTP[] = "ftp";
55static const char P_HTTP[] = "http";
56static 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
486static 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
475static void NOINLINE retrieve_file_data(FILE *dfp) 536static 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",