wget: fix --header to not append duplicate headers
authorBernhard Reutner-Fischer <rep.dot.nop@gmail.com>
Wed, 18 Feb 2015 19:41:02 +0000 (20:41 +0100)
committerDenys Vlasenko <vda.linux@googlemail.com>
Wed, 18 Feb 2015 19:41:02 +0000 (20:41 +0100)
function                                             old     new   delta
wget_main                                           2551    2715    +164
wget_user_headers                                      -      62     +62
------------------------------------------------------------------------------
(add/remove: 1/0 grow/shrink: 1/0 up/down: 226/0)             Total: 226 bytes

Signed-off-by: Bernhard Reutner-Fischer <rep.dot.nop@gmail.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
networking/wget.c

index 1013f66cb46cbbbfb6e64d386efd3c2766eeef33..6c8bd90a8fe9262bce151d1a21eba937aa324de4 100644 (file)
 
 #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