summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko2014-02-22 14:12:29 +0100
committerDenys Vlasenko2014-02-22 14:12:29 +0100
commit8b7e8ae2249ffd9aa2c67536554eb9f6b6636ba5 (patch)
tree1b728b46f7f7143f67b603fdd78f023a92f2b649
parent192c14bd87aa2ea930bc4a3954a07c1cab46a3cc (diff)
downloadbusybox-8b7e8ae2249ffd9aa2c67536554eb9f6b6636ba5.zip
busybox-8b7e8ae2249ffd9aa2c67536554eb9f6b6636ba5.tar.gz
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.c118
1 files changed, 92 insertions, 26 deletions
diff --git a/networking/wget.c b/networking/wget.c
index 7ca947a..dfea3d4 100644
--- a/networking/wget.c
+++ b/networking/wget.c
@@ -47,10 +47,13 @@ struct host_info {
char *allocated;
const char *path;
char *user;
+ const char *protocol;
char *host;
int port;
- smallint is_ftp;
};
+static const char P_FTP[] = "ftp";
+static const char P_HTTP[] = "http";
+static const char P_HTTPS[] = "https";
/* Globals */
@@ -219,7 +222,7 @@ static FILE *open_socket(len_and_sockaddr *lsa)
/* glibc 2.4 seems to try seeking on it - ??! */
/* hopefully it understands what ESPIPE means... */
fp = fdopen(fd, "r+");
- if (fp == NULL)
+ if (!fp)
bb_perror_msg_and_die(bb_msg_memory_exhausted);
return fp;
@@ -274,23 +277,31 @@ static void parse_url(const char *src_url, struct host_info *h)
free(h->allocated);
h->allocated = url = xstrdup(src_url);
- if (strncmp(url, "ftp://", 6) == 0) {
- h->port = bb_lookup_port("ftp", "tcp", 21);
- h->host = url + 6;
- h->is_ftp = 1;
- } else
- if (strncmp(url, "http://", 7) == 0) {
- h->host = url + 7;
+ h->protocol = P_FTP;
+ p = strstr(url, "://");
+ if (p) {
+ *p = '\0';
+ h->host = p + 3;
+ if (strcmp(url, P_FTP) == 0) {
+ h->port = bb_lookup_port(P_FTP, "tcp", 21);
+ } else
+ if (strcmp(url, P_HTTPS) == 0) {
+ h->port = bb_lookup_port(P_HTTPS, "tcp", 443);
+ h->protocol = P_HTTPS;
+ } else
+ if (strcmp(url, P_HTTP) == 0) {
http:
- h->port = bb_lookup_port("http", "tcp", 80);
- h->is_ftp = 0;
- } else
- if (!strstr(url, "//")) {
+ h->port = bb_lookup_port(P_HTTP, "tcp", 80);
+ h->protocol = P_HTTP;
+ } else {
+ *p = ':';
+ bb_error_msg_and_die("not an http or ftp url: %s", sanitize_string(url));
+ }
+ } else {
// GNU wget is user-friendly and falls back to http://
h->host = url;
goto http;
- } else
- bb_error_msg_and_die("not an http or ftp url: %s", sanitize_string(url));
+ }
// FYI:
// "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_
return sfp;
}
+static int spawn_https_helper(const char *host, unsigned port)
+{
+ char *allocated = NULL;
+ int sp[2];
+ int pid;
+
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, sp) != 0)
+ /* Kernel can have AF_UNIX support disabled */
+ bb_perror_msg_and_die("socketpair");
+
+ if (!strchr(host, ':'))
+ host = allocated = xasprintf("%s:%u", host, port);
+
+ pid = BB_MMU ? xfork() : xvfork();
+ if (pid == 0) {
+ /* Child */
+ char *argv[6];
+
+ close(sp[0]);
+ xmove_fd(sp[1], 0);
+ xdup2(0, 1);
+ /*
+ * TODO: develop a tiny ssl/tls helper (using matrixssl?),
+ * try to exec it here before falling back to big fat openssl.
+ */
+ /*
+ * openssl s_client -quiet -connect www.kernel.org:443 2>/dev/null
+ * It prints some debug stuff on stderr, don't know how to suppress it.
+ * Work around by dev-nulling stderr. We lose all error messages :(
+ */
+ xmove_fd(2, 3);
+ xopen("/dev/null", O_RDWR);
+ argv[0] = (char*)"openssl";
+ argv[1] = (char*)"s_client";
+ argv[2] = (char*)"-quiet";
+ argv[3] = (char*)"-connect";
+ argv[4] = (char*)host;
+ argv[5] = NULL;
+ BB_EXECVP(argv[0], argv);
+ xmove_fd(3, 2);
+ bb_perror_msg_and_die("can't execute '%s'", argv[0]);
+ /* notreached */
+ }
+
+ /* parent process */
+ free(allocated);
+ close(sp[1]);
+ return sp[0];
+}
+
static void NOINLINE retrieve_file_data(FILE *dfp)
{
#if ENABLE_FEATURE_WGET_STATUSBAR || ENABLE_FEATURE_WGET_TIMEOUT
@@ -644,7 +705,8 @@ static void download_one_url(const char *url)
/* Use the proxy if necessary */
use_proxy = (strcmp(G.proxy_flag, "off") != 0);
if (use_proxy) {
- proxy = getenv(target.is_ftp ? "ftp_proxy" : "http_proxy");
+ proxy = getenv(target.protocol == P_FTP ? "ftp_proxy" : "http_proxy");
+//FIXME: what if protocol is https? Ok to use http_proxy?
use_proxy = (proxy && proxy[0]);
if (use_proxy)
parse_url(proxy, &server);
@@ -704,27 +766,31 @@ static void download_one_url(const char *url)
/*G.content_len = 0; - redundant, got_clen = 0 is enough */
G.got_clen = 0;
G.chunked = 0;
- if (use_proxy || !target.is_ftp) {
+ if (use_proxy || target.protocol != P_FTP) {
/*
* HTTP session
*/
char *str;
int status;
-
- /* Open socket to http server */
- sfp = open_socket(lsa);
+ /* Open socket to http(s) server */
+ if (target.protocol == P_HTTPS) {
+ int fd = spawn_https_helper(server.host, server.port);
+ sfp = fdopen(fd, "r+");
+ if (!sfp)
+ bb_perror_msg_and_die(bb_msg_memory_exhausted);
+ } else
+ sfp = open_socket(lsa);
/* Send HTTP request */
if (use_proxy) {
- fprintf(sfp, "GET %stp://%s/%s HTTP/1.1\r\n",
- target.is_ftp ? "f" : "ht", target.host,
+ fprintf(sfp, "GET %s://%s/%s HTTP/1.1\r\n",
+ target.protocol, target.host,
target.path);
} else {
- if (option_mask32 & WGET_OPT_POST_DATA)
- fprintf(sfp, "POST /%s HTTP/1.1\r\n", target.path);
- else
- fprintf(sfp, "GET /%s HTTP/1.1\r\n", target.path);
+ fprintf(sfp, "%s /%s HTTP/1.1\r\n",
+ (option_mask32 & WGET_OPT_POST_DATA) ? "POST" : "GET",
+ target.path);
}
fprintf(sfp, "Host: %s\r\nUser-Agent: %s\r\n",