# HG changeset patch # User Marton Balint # Date 1227989647 -3600 # Node ID 7196e66f974acbfed6c5c9728a75749245afb5e9 # Parent dd1cd4ad2b27d3abc38e991e80f31a18517a8c80 Add support for multiple headers of the same type The --header option overwrites any existing HTTP header with the same type, this patch introduces the --append-header option which simply appends the specified header to the headers. It fixes the following bug reports: https://savannah.gnu.org/bugs/?20521 http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=366434 diff -r dd1cd4ad2b27 -r 7196e66f974a doc/ChangeLog --- a/doc/ChangeLog Wed Nov 26 21:53:40 2008 -0800 +++ b/doc/ChangeLog Sat Nov 29 21:14:07 2008 +0100 @@ -1,3 +1,8 @@ +2008-11-29 Marton Balint + + * wget.texi (Download Options): Document new command line option + --append-header. + 2008-11-15 Steven Schubiger * sample.wgetrc: Comment the waitretry "default" value, diff -r dd1cd4ad2b27 -r 7196e66f974a doc/wget.texi --- a/doc/wget.texi Wed Nov 26 21:53:40 2008 -0800 +++ b/doc/wget.texi Sat Nov 29 21:14:07 2008 +0100 @@ -1285,7 +1285,21 @@ @end example In versions of Wget prior to 1.10 such use of @samp{--header} caused -sending of duplicate headers. +sending of duplicate headers. If you want to specify duplicate headers +use the @samp{--append-header} option. + address@hidden header, add address@hidden address@hidden +Basically the same as option @samp{--header}, but you may specify the same +header multiple times. + address@hidden address@hidden +wget --append-header "Pragma: no-cache" \ + --append-header "Pragma: custom-directive" \ + http://foo/service address@hidden group address@hidden example @cindex redirect @item address@hidden diff -r dd1cd4ad2b27 -r 7196e66f974a src/ChangeLog --- a/src/ChangeLog Wed Nov 26 21:53:40 2008 -0800 +++ b/src/ChangeLog Sat Nov 29 21:14:07 2008 +0100 @@ -1,3 +1,13 @@ +2008-11-29 Marton Balint + + * http.c (request_set_header, request_set_user_header): New arg + append_header to specify whether the header should be appended or + replaced. All callers changed. + (gethttp): append --append-header headers to the HTTP headers. + + * init.c (cmd_spec_append_header), main.c options.h: add new option + --append-header. + 2008-11-13 Micah Cowan * http.c (gethttp): Don't do anything when content-length >= our diff -r dd1cd4ad2b27 -r 7196e66f974a src/http.c --- a/src/http.c Wed Nov 26 21:53:40 2008 -0800 +++ b/src/http.c Sat Nov 29 21:14:07 2008 +0100 @@ -216,20 +216,20 @@ sources. For example: // Don't free literal strings! - request_set_header (req, "Pragma", "no-cache", rel_none); + request_set_header (req, "Pragma", "no-cache", rel_none, false); // Don't free a global variable, we'll need it later. - request_set_header (req, "Referer", opt.referer, rel_none); + request_set_header (req, "Referer", opt.referer, rel_none, false); // Value freshly allocated, free it when done. request_set_header (req, "Range", aprintf ("bytes=%s-", number_to_static_string (hs->restval)), - rel_value); + rel_value, false); */ static void request_set_header (struct request *req, char *name, char *value, - enum rp release_policy) + enum rp release_policy, bool append_header) { struct request_header *hdr; int i; @@ -243,17 +243,20 @@ return; } - for (i = 0; i < req->hcount; i++) + if (!append_header) { - hdr = &req->headers[i]; - if (0 == strcasecmp (name, hdr->name)) + for (i = 0; i < req->hcount; i++) { - /* Replace existing header. */ - release_header (hdr); - hdr->name = name; - hdr->value = value; - hdr->release_policy = release_policy; - return; + hdr = &req->headers[i]; + if (0 == strcasecmp (name, hdr->name)) + { + /* Replace existing header. */ + release_header (hdr); + hdr->name = name; + hdr->value = value; + hdr->release_policy = release_policy; + return; + } } } @@ -276,7 +279,7 @@ request_set_header (req, "Foo", "bar"). */ static void -request_set_user_header (struct request *req, const char *header) +request_set_user_header (struct request *req, const char *header, bool append_header) { char *name; const char *p = strchr (header, ':'); @@ -286,7 +289,7 @@ ++p; while (c_isspace (*p)) ++p; - request_set_header (req, xstrdup (name), (char *) p, rel_name); + request_set_header (req, xstrdup (name), (char *) p, rel_name, append_header); } /* Remove the header with specified name from REQ. Returns true if @@ -420,7 +423,7 @@ { request_set_header (req, "Authorization", basic_authentication_encode (user, passwd), - rel_value); + rel_value, false); } return do_challenge; } @@ -1344,9 +1347,11 @@ #define SET_USER_AGENT(req) do { \ if (!opt.useragent) \ request_set_header (req, "User-Agent", \ - aprintf ("Wget/%s", version_string), rel_value); \ + aprintf ("Wget/%s", version_string), \ + rel_value, false); \ else if (*opt.useragent) \ - request_set_header (req, "User-Agent", opt.useragent, rel_none); \ + request_set_header (req, "User-Agent", opt.useragent, \ + rel_none, false); \ } while (0) /* The flags that allow clobbering the file (opening with "wb"). @@ -1479,16 +1484,16 @@ request_set_method (req, meth, meth_arg); } - request_set_header (req, "Referer", (char *) hs->referer, rel_none); + request_set_header (req, "Referer", (char *) hs->referer, rel_none, false); if (*dt & SEND_NOCACHE) - request_set_header (req, "Pragma", "no-cache", rel_none); + request_set_header (req, "Pragma", "no-cache", rel_none, false); if (hs->restval) request_set_header (req, "Range", aprintf ("bytes=%s-", number_to_static_string (hs->restval)), - rel_value); + rel_value, false); SET_USER_AGENT (req); - request_set_header (req, "Accept", "*/*", rel_none); + request_set_header (req, "Accept", "*/*", rel_none, false); /* Find the username and password for authentication. */ user = u->user; @@ -1525,11 +1530,11 @@ int add_squares = strchr (u->host, ':') != NULL; request_set_header (req, "Host", aprintf (hfmt[add_port][add_squares], u->host, u->port), - rel_value); + rel_value, false); } if (!inhibit_keep_alive) - request_set_header (req, "Connection", "Keep-Alive", rel_none); + request_set_header (req, "Connection", "Keep-Alive", rel_none, false); if (opt.cookies) request_set_header (req, "Cookie", @@ -1541,12 +1546,12 @@ 0 #endif ), - rel_value); + rel_value, false); if (opt.post_data || opt.post_file_name) { request_set_header (req, "Content-Type", - "application/x-www-form-urlencoded", rel_none); + "application/x-www-form-urlencoded", rel_none, false); if (opt.post_data) post_data_size = strlen (opt.post_data); else @@ -1561,7 +1566,7 @@ } request_set_header (req, "Content-Length", xstrdup (number_to_static_string (post_data_size)), - rel_value); + rel_value, false); } /* Add the user headers. */ @@ -1569,7 +1574,15 @@ { int i; for (i = 0; opt.user_headers[i]; i++) - request_set_user_header (req, opt.user_headers[i]); + request_set_user_header (req, opt.user_headers[i], false); + } + + /* Append the user headers. */ + if (opt.user_headers_append) + { + int i; + for (i = 0; opt.user_headers_append[i]; i++) + request_set_user_header (req, opt.user_headers_append[i], true); } retry_with_auth: @@ -1609,7 +1622,8 @@ #ifdef HAVE_SSL if (u->scheme != SCHEME_HTTPS) #endif - request_set_header (req, "Proxy-Authorization", proxyauth, rel_value); + request_set_header (req, "Proxy-Authorization", proxyauth, rel_value, + false); } keep_alive = false; @@ -1685,7 +1699,7 @@ if (proxyauth) { request_set_header (connreq, "Proxy-Authorization", - proxyauth, rel_value); + proxyauth, rel_value, false); /* Now that PROXYAUTH is part of the CONNECT request, zero it out so we don't send proxy authorization with the regular request below. */ @@ -2006,7 +2020,7 @@ request_method (req), pth, &auth_finished), - rel_value); + rel_value, false); if (BEGINS_WITH (www_authenticate, "NTLM")) ntlm_seen = true; else if (!u->user && BEGINS_WITH (www_authenticate, "Basic")) diff -r dd1cd4ad2b27 -r 7196e66f974a src/init.c --- a/src/init.c Wed Nov 26 21:53:40 2008 -0800 +++ b/src/init.c Sat Nov 29 21:14:07 2008 +0100 @@ -84,6 +84,7 @@ CMD_DECLARE (cmd_spec_dirstruct); CMD_DECLARE (cmd_spec_header); +CMD_DECLARE (cmd_spec_append_header); CMD_DECLARE (cmd_spec_htmlify); CMD_DECLARE (cmd_spec_mirror); CMD_DECLARE (cmd_spec_prefer_family); @@ -113,6 +114,7 @@ { "accept", &opt.accepts, cmd_vector }, { "addhostdir", &opt.add_hostdir, cmd_boolean }, { "alwaysrest", &opt.always_rest, cmd_boolean }, /* deprecated */ + { "appendheader", NULL, cmd_spec_append_header }, { "askpassword", &opt.ask_passwd, cmd_boolean }, { "authnochallenge", &opt.auth_without_challenge, cmd_boolean }, @@ -1152,6 +1154,27 @@ } static bool +cmd_spec_append_header (const char *com, const char *val, void *place_ignored) +{ + /* Empty value means reset the list of headers. */ + if (*val == '\0') + { + fprintf (stderr, _("%s: %s: Missing append header.\n"), + exec_name, com); + return false; + } + + if (!check_user_specified_header (val)) + { + fprintf (stderr, _("%s: %s: Invalid append header %s.\n"), + exec_name, com, quote (val)); + return false; + } + opt.user_headers_append = vec_append (opt.user_headers_append, val); + return true; +} + +static bool cmd_spec_htmlify (const char *com, const char *val, void *place_ignored) { int flag = cmd_boolean (com, val, &opt.htmlify); @@ -1549,6 +1572,7 @@ xfree_null (opt.http_user); xfree_null (opt.http_passwd); free_vec (opt.user_headers); + free_vec (opt.user_headers_append); # ifdef HAVE_SSL xfree_null (opt.cert_file); xfree_null (opt.private_key); diff -r dd1cd4ad2b27 -r 7196e66f974a src/main.c --- a/src/main.c Wed Nov 26 21:53:40 2008 -0800 +++ b/src/main.c Sat Nov 29 21:14:07 2008 +0100 @@ -142,6 +142,7 @@ static struct cmdline_option option_data[] = { { "accept", 'A', OPT_VALUE, "accept", -1 }, + { "append-header", 0, OPT_VALUE, "appendheader", -1 }, { "append-output", 'a', OPT__APPEND_OUTPUT, NULL, required_argument }, { "ask-password", 0, OPT_BOOLEAN, "askpassword", -1 }, { "auth-no-challenge", 0, OPT_BOOLEAN, "authnochallenge", -1 }, @@ -524,6 +525,8 @@ --ignore-length ignore `Content-Length' header field.\n"), N_("\ --header=STRING insert STRING among the headers.\n"), + N_("\ + --append-header=STRING append STRING after the headers.\n"), N_("\ --max-redirect maximum redirections allowed per page.\n"), N_("\ diff -r dd1cd4ad2b27 -r 7196e66f974a src/options.h --- a/src/options.h Wed Nov 26 21:53:40 2008 -0800 +++ b/src/options.h Sat Nov 29 21:14:07 2008 +0100 @@ -99,6 +99,7 @@ char *http_user; /* HTTP username. */ char *http_passwd; /* HTTP password. */ char **user_headers; /* User-defined header(s). */ + char **user_headers_append; /* User-defined append header(s). */ bool http_keep_alive; /* whether we use keep-alive */ bool use_proxy; /* Do we use proxy? */