wget: fix --header to not append duplicate headers
No binary (build failed)
—
(log yok)
| @@ -38,8 +38,14 @@ | |
| #if 0 | |
| # define log_io(...) bb_error_msg(__VA_ARGS__) | |
| + | # define SENDFMT(fp, fmt, ...) \ |
| + | do { \ |
| + | log_io("> " fmt, ##__VA_ARGS__); \ |
| + | fprintf(fp, fmt, ##__VA_ARGS__); \ |
| + | } while (0); |
| #else | |
| # define log_io(...) ((void)0) | |
| + | # define SENDFMT(fp, fmt, ...) fprintf(fp, fmt, ##__VA_ARGS__) |
| #endif | |
| @@ -55,6 +61,36 @@ static const char P_FTP[] = "ftp"; | |
| static const char P_HTTP[] = "http"; | |
| static const char P_HTTPS[] = "https"; | |
| + | #if ENABLE_FEATURE_WGET_LONG_OPTIONS |
| + | /* User-specified headers prevent using our corresponding built-in headers. */ |
| + | enum { |
| + | HDR_HOST = (1<<0), |
| + | HDR_USER_AGENT = (1<<1), |
| + | HDR_RANGE = (1<<2), |
| + | HDR_AUTH = (1<<3) * ENABLE_FEATURE_WGET_AUTHENTICATION, |
| + | HDR_PROXY_AUTH = (1<<4) * ENABLE_FEATURE_WGET_AUTHENTICATION, |
| + | }; |
| + | static const char wget_user_headers[] ALIGN1 = |
| + | "Host:\0" |
| + | "User-Agent:\0" |
| + | "Range:\0" |
| + | # if ENABLE_FEATURE_WGET_AUTHENTICATION |
| + | "Authorization:\0" |
| + | "Proxy-Authorization:\0" |
| + | # endif |
| + | ; |
| + | # define USR_HEADER_HOST (G.user_headers & HDR_HOST) |
| + | # define USR_HEADER_USER_AGENT (G.user_headers & HDR_USER_AGENT) |
| + | # define USR_HEADER_RANGE (G.user_headers & HDR_RANGE) |
| + | # define USR_HEADER_AUTH (G.user_headers & HDR_AUTH) |
| + | # define USR_HEADER_PROXY_AUTH (G.user_headers & HDR_PROXY_AUTH) |
| + | #else /* No long options, no user-headers :( */ |
| + | # define USR_HEADER_HOST 0 |
| + | # define USR_HEADER_USER_AGENT 0 |
| + | # define USR_HEADER_RANGE 0 |
| + | # define USR_HEADER_AUTH 0 |
| + | # define USR_HEADER_PROXY_AUTH 0 |
| + | #endif |
| /* Globals */ | |
| struct globals { | |
| @@ -69,6 +105,7 @@ struct globals { | |
| #if ENABLE_FEATURE_WGET_LONG_OPTIONS | |
| char *post_data; | |
| char *extra_headers; | |
| + | unsigned char user_headers; /* Headers mentioned by the user */ |
| #endif | |
| char *fname_out; /* where to direct output (-O) */ | |
| const char *proxy_flag; /* Use proxies if env vars are set */ | |
| @@ -830,43 +867,46 @@ static void download_one_url(const char *url) | |
| #endif | |
| /* Send HTTP request */ | |
| if (use_proxy) { | |
| - | fprintf(sfp, "GET %s://%s/%s HTTP/1.1\r\n", |
| + | SENDFMT(sfp, "GET %s://%s/%s HTTP/1.1\r\n", |
| target.protocol, target.host, | |
| target.path); | |
| } else { | |
| - | fprintf(sfp, "%s /%s HTTP/1.1\r\n", |
| + | SENDFMT(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", |
| - | target.host, G.user_agent); |
| + | if (!USR_HEADER_HOST) |
| + | SENDFMT(sfp, "Host: %s\r\n", target.host); |
| + | if (!USR_HEADER_USER_AGENT) |
| + | SENDFMT(sfp, "User-Agent: %s\r\n", G.user_agent); |
| /* Ask server to close the connection as soon as we are done | |
| * (IOW: we do not intend to send more requests) | |
| */ | |
| - | fprintf(sfp, "Connection: close\r\n"); |
| + | SENDFMT(sfp, "Connection: close\r\n"); |
| #if ENABLE_FEATURE_WGET_AUTHENTICATION | |
| - | if (target.user) { |
| - | fprintf(sfp, "Proxy-Authorization: Basic %s\r\n"+6, |
| + | if (target.user && !USR_HEADER_AUTH) { |
| + | SENDFMT(sfp, "Proxy-Authorization: Basic %s\r\n"+6, |
| base64enc(target.user)); | |
| } | |
| - | if (use_proxy && server.user) { |
| - | fprintf(sfp, "Proxy-Authorization: Basic %s\r\n", |
| + | if (use_proxy && server.user && !USR_HEADER_PROXY_AUTH) { |
| + | SENDFMT(sfp, "Proxy-Authorization: Basic %s\r\n", |
| base64enc(server.user)); | |
| } | |
| #endif | |
| - | if (G.beg_range != 0) |
| - | fprintf(sfp, "Range: bytes=%"OFF_FMT"u-\r\n", G.beg_range); |
| + | if (G.beg_range != 0 && !USR_HEADER_RANGE) |
| + | SENDFMT(sfp, "Range: bytes=%"OFF_FMT"u-\r\n", G.beg_range); |
| #if ENABLE_FEATURE_WGET_LONG_OPTIONS | |
| - | if (G.extra_headers) |
| + | if (G.extra_headers) { |
| + | log_io(G.extra_headers); |
| fputs(G.extra_headers, sfp); | |
| + | } |
| if (option_mask32 & WGET_OPT_POST_DATA) { | |
| - | fprintf(sfp, |
| + | SENDFMT(sfp, |
| "Content-Type: application/x-www-form-urlencoded\r\n" | |
| "Content-Length: %u\r\n" | |
| "\r\n" | |
| @@ -876,7 +916,7 @@ static void download_one_url(const char *url) | |
| } else | |
| #endif | |
| { | |
| - | fprintf(sfp, "\r\n"); |
| + | SENDFMT(sfp, "\r\n"); |
| } | |
| fflush(sfp); | |
| @@ -1093,7 +1133,9 @@ int wget_main(int argc UNUSED_PARAM, char **argv) | |
| #if ENABLE_FEATURE_WGET_LONG_OPTIONS | |
| applet_long_options = wget_longopts; | |
| #endif | |
| - | opt_complementary = "-1" IF_FEATURE_WGET_TIMEOUT(":T+") IF_FEATURE_WGET_LONG_OPTIONS(":\xfe::"); |
| + | opt_complementary = "-1" |
| + | IF_FEATURE_WGET_TIMEOUT(":T+") |
| + | IF_FEATURE_WGET_LONG_OPTIONS(":\xfe::"); |
| getopt32(argv, "csqO:P:Y:U:T:" /*ignored:*/ "t:", | |
| &G.fname_out, &G.dir_prefix, | |
| &G.proxy_flag, &G.user_agent, | |
| @@ -1106,16 +1148,32 @@ int wget_main(int argc UNUSED_PARAM, char **argv) | |
| #if ENABLE_FEATURE_WGET_LONG_OPTIONS | |
| if (headers_llist) { | |
| - | int size = 1; |
| - | char *cp; |
| + | int size = 0; |
| + | char *hdr; |
| llist_t *ll = headers_llist; | |
| while (ll) { | |
| size += strlen(ll->data) + 2; | |
| ll = ll->link; | |
| } | |
| - | G.extra_headers = cp = xmalloc(size); |
| + | G.extra_headers = hdr = xmalloc(size + 1); |
| while (headers_llist) { | |
| - | cp += sprintf(cp, "%s\r\n", (char*)llist_pop(&headers_llist)); |
| + | int bit; |
| + | const char *words; |
| + | |
| + | size = sprintf(hdr, "%s\r\n", |
| + | (char*)llist_pop(&headers_llist)); |
| + | /* a bit like index_in_substrings but don't match full key */ |
| + | bit = 1; |
| + | words = wget_user_headers; |
| + | while (*words) { |
| + | if (strstr(hdr, words) == hdr) { |
| + | G.user_headers |= bit; |
| + | break; |
| + | } |
| + | bit <<= 1; |
| + | words += strlen(words) + 1; |
| + | } |
| + | hdr += size; |
| } | |
| } | |
| #endif | |