Hi,

The attached patch adds support for multiple headers of the same type by 
introducing a new option --append-header.

References:

http://www.mail-archive.com/[EMAIL PROTECTED]/msg09021.html
https://savannah.gnu.org/bugs/?20521
http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=366434

Regards,
  Marton
# HG changeset patch
# User Marton Balint <[EMAIL PROTECTED]>
# 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 <[EMAIL PROTECTED]>
+
+	* wget.texi (Download Options): Document new command line option
+	  --append-header.
+
 2008-11-15  Steven Schubiger  <[EMAIL PROTECTED]>
 
 	* 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.
+
[EMAIL PROTECTED] header, add
[EMAIL PROTECTED] [EMAIL PROTECTED]
+Basically the same as option @samp{--header}, but you may specify the same
+header multiple times.
+
[EMAIL PROTECTED]
[EMAIL PROTECTED]
+wget --append-header "Pragma: no-cache" \
+     --append-header "Pragma: custom-directive" \
+       http://foo/service
[EMAIL PROTECTED] group
[EMAIL PROTECTED] example
 
 @cindex redirect
 @item [EMAIL PROTECTED]
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 <[EMAIL PROTECTED]>
+
+	* 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  <[EMAIL PROTECTED]>
 
 	* 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? */

Reply via email to