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>
This commit is contained in:
parent
192c14bd87
commit
8b7e8ae224
@ -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",
|
||||
|
Loading…
Reference in New Issue
Block a user