You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by ch...@apache.org on 2007/08/22 01:22:01 UTC

svn commit: r568323 - in /httpd/httpd/trunk: docs/manual/mod/mod_headers.xml modules/metadata/mod_headers.c

Author: chrisd
Date: Tue Aug 21 16:22:00 2007
New Revision: 568323

URL: http://svn.apache.org/viewvc?rev=568323&view=rev
Log:
add merge option to avoid duplicate values within the same header

Modified:
    httpd/httpd/trunk/docs/manual/mod/mod_headers.xml
    httpd/httpd/trunk/modules/metadata/mod_headers.c

Modified: httpd/httpd/trunk/docs/manual/mod/mod_headers.xml
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/docs/manual/mod/mod_headers.xml?rev=568323&r1=568322&r2=568323&view=diff
==============================================================================
--- httpd/httpd/trunk/docs/manual/mod/mod_headers.xml (original)
+++ httpd/httpd/trunk/docs/manual/mod/mod_headers.xml Tue Aug 21 16:22:00 2007
@@ -153,13 +153,41 @@
           RequestHeader edit Destination ^https: http: early
         </example>
       </li>
+
+      <li>
+        Set the same header value under multiple non-exclusive conditions,
+        but do not duplicate the value in the final header.
+        If all of the following conditions applied to a request (i.e.,
+        if the <code>CGI</code>, <code>NO_CACHE</code> and
+        <code>NO_STORE</code> environment variables all existed for the
+        request):
+
+        <example>
+          Header merge Cache-Control no-cache env=CGI<br />
+          Header merge Cache-Control no-cache env=NO_CACHE<br />
+          Header merge Cache-Control no-store env=NO_STORE
+        </example>
+
+        <p>then the response would contain the following header:</p>
+
+        <example>
+          Cache-Control: no-cache, no-store
+        </example>
+
+        <p>If <code>append</code> was used instead of <code>merge</code>,
+        then the response would contain the following header:</p>
+
+        <example>
+          Cache-Control: no-cache, no-cache, no-store
+        </example>
+      </li>
     </ol>
 </section>
 
 <directivesynopsis>
 <name>RequestHeader</name>
 <description>Configure HTTP request headers</description>
-<syntax>RequestHeader set|append|add|unset|edit <var>header</var>
+<syntax>RequestHeader set|append|merge|add|unset|edit <var>header</var>
 [<var>value</var>] [<var>replacement</var>] [early|env=[!]<var>variable</var>]</syntax>
 <contextlist><context>server config</context><context>virtual host</context>
 <context>directory</context><context>.htaccess</context></contextlist>
@@ -184,12 +212,22 @@
     is the HTTP standard way of giving a header multiple
     values.</dd>
 
+    <dt><code>merge</code></dt>
+    <dd>The response header is appended to any existing header of
+    the same name, unless the value to be appended already appears in the
+    existing header's comma-delimited list of values.  When a new value is
+    merged onto an existing header it is separated from the existing header
+    with a comma.  This is the HTTP standard way of giving a header multiple
+    values.  Values are compared in a case sensitive manner, and after
+    all format specifiers have been processed.  Values in double quotes
+    are considered different from otherwise identical unquoted values.</dd>
+
     <dt><code>add</code></dt>
     <dd>The request header is added to the existing set of headers,
     even if this header already exists. This can result in two
     (or more) headers having the same name. This can lead to
-    unforeseen consequences, and in general <code>set</code> or
-    <code>append</code> should be used instead.</dd>
+    unforeseen consequences, and in general <code>set</code>,
+    <code>append</code> or <code>merge</code> should be used instead.</dd>
 
     <dt><code>unset</code></dt>
     <dd>The request header of this name is removed, if it exists. If
@@ -206,7 +244,7 @@
 
     <p>This argument is followed by a header name, which can
     include the final colon, but it is not required. Case is
-    ignored. For <code>set</code>, <code>append</code> and
+    ignored. For <code>set</code>, <code>append</code>, <code>merge</code> and
     <code>add</code> a <var>value</var> is given as the third argument. If a
     <var>value</var> contains spaces, it should be surrounded by double
     quotes. For <code>unset</code>, no <var>value</var> should be given.
@@ -240,7 +278,7 @@
 <directivesynopsis>
 <name>Header</name>
 <description>Configure HTTP response headers</description>
-<syntax>Header [<var>condition</var>] set|append|add|unset|echo|edit
+<syntax>Header [<var>condition</var>] set|append|merge|add|unset|echo|edit
 <var>header</var> [<var>value</var>] [early|env=[!]<var>variable</var>]</syntax>
 <contextlist><context>server config</context><context>virtual host</context>
 <context>directory</context><context>.htaccess</context></contextlist>
@@ -273,12 +311,22 @@
     header it is separated from the existing header with a comma.
     This is the HTTP standard way of giving a header multiple values.</dd>
 
+    <dt><code>merge</code></dt>
+    <dd>The response header is appended to any existing header of
+    the same name, unless the value to be appended already appears in the
+    header's comma-delimited list of values.  When a new value is merged onto
+    an existing header it is separated from the existing header with a comma.
+    This is the HTTP standard way of giving a header multiple values.
+    Values are compared in a case sensitive manner, and after
+    all format specifiers have been processed.  Values in double quotes
+    are considered different from otherwise identical unquoted values.</dd>
+
     <dt><code>add</code></dt>
     <dd>The response header is added to the existing set of headers,
     even if this header already exists. This can result in two
     (or more) headers having the same name. This can lead to
-    unforeseen consequences, and in general <code>set</code> or
-    <code>append</code> should be used instead.</dd>
+    unforeseen consequences, and in general <code>set</code>,
+    <code>append</code> or <code>merge</code> should be used instead.</dd>
 
     <dt><code>unset</code></dt>
     <dd>The response header of this name is removed, if it exists.
@@ -301,14 +349,15 @@
 
     <p>This argument is followed by a <var>header</var> name, which
     can include the final colon, but it is not required. Case is
-    ignored for <code>set</code>, <code>append</code>, <code>add</code>,
-    <code>unset</code>, and <code>edit</code>.
+    ignored for <code>set</code>, <code>append</code>, <code>merge</code>,
+    <code>add</code>, <code>unset</code> and <code>edit</code>.
     The <var>header</var> name for <code>echo</code>
     is case sensitive and may be a <glossary ref="regex">regular
     expression</glossary>.</p>
 
-    <p>For <code>set</code>, <code>append</code> and <code>add</code> a
-    <var>value</var> is specified as the third argument. If <var>value</var>
+    <p>For <code>set</code>, <code>append</code>, <code>merge</code> and
+    <code>add</code> a <var>value</var> is specified as the third argument.
+    If <var>value</var>
     contains spaces, it should be surrounded by double quotes.
     <var>value</var> may be a character string, a string containing format
     specifiers or a combination of both. The following format specifiers

Modified: httpd/httpd/trunk/modules/metadata/mod_headers.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/metadata/mod_headers.c?rev=568323&r1=568322&r2=568323&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/metadata/mod_headers.c (original)
+++ httpd/httpd/trunk/modules/metadata/mod_headers.c Tue Aug 21 16:22:00 2007
@@ -33,7 +33,10 @@
  *     add    - add this header, possible resulting in two or more
  *              headers with the same name
  *     append - append this text onto any existing header of this same
+ *     merge  - merge this text onto any existing header of this same,
+ *              avoiding duplicate values
  *     unset  - remove this header
+ *      edit  - transform the header value according to a regexp
  *
  * Where action is unset, the third argument (value) should not be given.
  * The header name can include the colon, or not.
@@ -88,6 +91,7 @@
     hdr_add = 'a',              /* add header (could mean multiple hdrs) */
     hdr_set = 's',              /* set (replace old value) */
     hdr_append = 'm',           /* append (merge into any old value) */
+    hdr_merge = 'g',            /* merge (merge, but avoid duplicates) */
     hdr_unset = 'u',            /* unset header */
     hdr_echo = 'e',             /* echo headers from request to response */
     hdr_edit = 'r'              /* change value by regexp */
@@ -394,6 +398,8 @@
         new->action = hdr_add;
     else if (!strcasecmp(action, "append"))
         new->action = hdr_append;
+    else if (!strcasecmp(action, "merge"))
+        new->action = hdr_merge;
     else if (!strcasecmp(action, "unset"))
         new->action = hdr_unset;
     else if (!strcasecmp(action, "echo"))
@@ -401,8 +407,8 @@
     else if (!strcasecmp(action, "edit"))
         new->action = hdr_edit;
     else
-        return "first argument must be 'add', 'set', 'append', 'unset', "
-               "'echo' or 'edit'.";
+        return "first argument must be 'add', 'set', 'append', 'merge', "
+               "'unset', 'echo', or 'edit'.";
 
     if (new->action == hdr_edit) {
         if (subs == NULL) {
@@ -609,6 +615,46 @@
             break;
         case hdr_append:
             apr_table_mergen(headers, hdr->header, process_tags(hdr, r));
+            break;
+        case hdr_merge:
+            val = apr_table_get(headers, hdr->header);
+            if (val == NULL) {
+                apr_table_addn(headers, hdr->header, process_tags(hdr, r));
+            } else {
+                char *new_val = process_tags(hdr, r);
+                apr_size_t new_val_len = strlen(new_val);
+                int tok_found = 0;
+
+                /* modified version of logic in ap_get_token() */
+                while (*val) {
+                    const char *tok_start;
+
+                    while (*val && apr_isspace(*val))
+                        ++val;
+
+                    tok_start = val;
+
+                    while (*val && *val != ',') {
+                        if (*val++ == '"')
+                            while (*val)
+                                if (*val++ == '"')
+                                    break;
+                    }
+
+                    if (new_val_len == (val - tok_start)
+                        && !strncmp(tok_start, new_val, new_val_len)) {
+                        tok_found = 1;
+                        break;
+                    }
+
+                    if (*val)
+                        ++val;
+                }
+
+                if (!tok_found) {
+                    apr_table_mergen(headers, hdr->header, new_val);
+                }
+            }
             break;
         case hdr_set:
             apr_table_setn(headers, hdr->header, process_tags(hdr, r));