You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by ni...@apache.org on 2006/12/08 00:23:42 UTC

svn commit: r483732 - in /httpd/httpd/branches/2.2.x: CHANGES STATUS docs/manual/mod/mod_headers.xml modules/metadata/mod_headers.c

Author: niq
Date: Thu Dec  7 15:23:40 2006
New Revision: 483732

URL: http://svn.apache.org/viewvc?view=rev&rev=483732
Log:
Backport R452330: header editing in mod_headers
+1 niq, chrisd, wrowe

Modified:
    httpd/httpd/branches/2.2.x/CHANGES
    httpd/httpd/branches/2.2.x/STATUS
    httpd/httpd/branches/2.2.x/docs/manual/mod/mod_headers.xml
    httpd/httpd/branches/2.2.x/modules/metadata/mod_headers.c

Modified: httpd/httpd/branches/2.2.x/CHANGES
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.2.x/CHANGES?view=diff&rev=483732&r1=483731&r2=483732
==============================================================================
--- httpd/httpd/branches/2.2.x/CHANGES [utf-8] (original)
+++ httpd/httpd/branches/2.2.x/CHANGES [utf-8] Thu Dec  7 15:23:40 2006
@@ -1,6 +1,8 @@
                                                         -*- coding: utf-8 -*-
 Changes with Apache 2.2.4
 
+  *) mod_headers: support regexp-based editing of HTTP headers [Nick Kew]
+
    * mod_proxy: Add explicit flushing feature.
      When Servlet container sends AJP body message with size 0,
      this means that Servlet container has asked for an explicit flush.

Modified: httpd/httpd/branches/2.2.x/STATUS
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.2.x/STATUS?view=diff&rev=483732&r1=483731&r2=483732
==============================================================================
--- httpd/httpd/branches/2.2.x/STATUS (original)
+++ httpd/httpd/branches/2.2.x/STATUS Thu Dec  7 15:23:40 2006
@@ -255,12 +255,6 @@
        Trunk version works
      +1: trawick, jim, wrowe
 
-   * mod_headers: support regexp-based manipulation
-     http://svn.apache.org/viewvc?view=rev&revision=452330
-     +1: niq, chrisd, wrowe
-     chrisd: Note that the docs need to be back-ported, and
-             new_features_2_4.xml revised too.
-
    * mod_ldap: Better detection and clean up of ldap connection
      that have been terminated by the ldap server.
      http://svn.apache.org/viewvc?view=rev&revision=472633

Modified: httpd/httpd/branches/2.2.x/docs/manual/mod/mod_headers.xml
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.2.x/docs/manual/mod/mod_headers.xml?view=diff&rev=483732&r1=483731&r2=483732
==============================================================================
--- httpd/httpd/branches/2.2.x/docs/manual/mod/mod_headers.xml (original)
+++ httpd/httpd/branches/2.2.x/docs/manual/mod/mod_headers.xml Thu Dec  7 15:23:40 2006
@@ -144,20 +144,29 @@
          MyHeader: D=3775428 t=991424704447256 mytext
        </example>
       </li>
+      <li>Enable DAV to work with Apache running HTTP through SSL hardware
+      (<a href="http://svn.haxx.se/users/archive-2006-03/0549.shtml"
+      >problem description</a>) by replacing <var>https:</var> with
+      <var>http:</var> in the <var>Destination</var> header:
+      <example>
+        RequestHeader edit Destination ^https: http: early
+      </example>
+      </li>
+
     </ol>
 </section>
 
 <directivesynopsis>
 <name>RequestHeader</name>
 <description>Configure HTTP request headers</description>
-<syntax>RequestHeader set|append|add|unset <var>header</var>
-[<var>value</var>] [early|env=[!]<var>variable</var>]</syntax>
+<syntax>RequestHeader set|append|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>
 <override>FileInfo</override>
 
 <usage>
-    <p>This directive can replace, merge or remove HTTP request
+    <p>This directive can replace, merge, change or remove HTTP request
     headers. The header is modified just before the content handler
     is run, allowing incoming headers to be modified. The action it
     performs is determined by the first argument. This can be one
@@ -186,18 +195,28 @@
     <dd>The request header of this name is removed, if it exists. If
     there are multiple headers of the same name, all will be removed.
     <var>value</var> must be omitted.</dd>
+
+    <dt><code>edit</code></dt>
+    <dd>If this request header exists, its value is transformed according
+    to a <glossary ref="regex">regular expression</glossary>
+    search-and-replace.  The <var>value</var> argument is a <glossary
+    ref="regex">regular expression</glossary>, and the <var>replacement</var>
+    is a replacement string, which may contain backreferences.</dd>
     </dl>
 
     <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>add</code>, <code>append</code> and
-    <code>set</code> a <var>value</var> is given as the third argument. If
+    <code>set</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 unset, no <var>value</var> should be given.
     <var>value</var> may be a character string, a string containing format
     specifiers or a combination of both. The supported format specifiers
     are the same as for the <directive module="mod_headers">Header</directive>,
-    please have a look there for details.</p>
+    please have a look there for details.  For <code>edit</code> both
+    a <var>value</var> and a <var>replacement</var> are required, and are
+    a <glossary ref="regex">regular expression</glossary> and a
+    replacement string respectively.</p>
 
     <p>The <directive>RequestHeader</directive> directive may be followed by
     an additional argument, which may be used to specify conditions under
@@ -221,7 +240,7 @@
 <directivesynopsis>
 <name>Header</name>
 <description>Configure HTTP response headers</description>
-<syntax>Header [<var>condition</var>] set|append|add|unset|echo
+<syntax>Header [<var>condition</var>] set|append|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>
@@ -271,6 +290,13 @@
     response headers. <var>header</var> may be a 
     <glossary ref="regex">regular expression</glossary>.
     <var>value</var> must be omitted.</dd>
+
+    <dt><code>edit</code></dt>
+    <dd>If this request header exists, its value is transformed according
+    to a <glossary ref="regex">regular expression</glossary>
+    search-and-replace.  The <var>value</var> argument is a <glossary
+    ref="regex">regular expression</glossary>, and the <var>replacement</var>
+    is a replacement string, which may contain backreferences.</dd>
     </dl>
 
     <p>This argument is followed by a <var>header</var> name, which
@@ -321,6 +347,10 @@
       be enabled anyway for some other reason, <code>%e</code> will be
       more efficient than <code>%s</code>.</p>
     </note> 
+
+    <p>For <code>edit</code> there is both a <var>value</var> argument
+    which is a <glossary ref="regex">regular expression</glossary>,
+    and an additional <var>replacement</var> string.</p>
 
     <p>The <directive>Header</directive> directive may be followed by an
     an additional argument, which may be used to specify conditions under

Modified: httpd/httpd/branches/2.2.x/modules/metadata/mod_headers.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.2.x/modules/metadata/mod_headers.c?view=diff&rev=483732&r1=483731&r2=483732
==============================================================================
--- httpd/httpd/branches/2.2.x/modules/metadata/mod_headers.c (original)
+++ httpd/httpd/branches/2.2.x/modules/metadata/mod_headers.c Thu Dec  7 15:23:40 2006
@@ -89,7 +89,8 @@
     hdr_set = 's',              /* set (replace old value) */
     hdr_append = 'm',           /* append (merge into any old value) */
     hdr_unset = 'u',            /* unset header */
-    hdr_echo = 'e'              /* echo headers from request to response */
+    hdr_echo = 'e',             /* echo headers from request to response */
+    hdr_edit = 'r'              /* change value by regexp */
 } hdr_actions;
 
 /*
@@ -119,6 +120,7 @@
     apr_array_header_t *ta;   /* Array of format_tag structs */
     ap_regex_t *regex;
     const char *condition_var;
+    const char *subs;
 } header_entry;
 
 /* echo_do is used for Header echo to iterate through the request headers*/
@@ -348,6 +350,7 @@
 
     /* No string to parse with unset and echo commands */
     if (hdr->action == hdr_unset ||
+        hdr->action == hdr_edit ||
         hdr->action == hdr_echo) {
         return NULL;
     }
@@ -368,7 +371,8 @@
                                                const char *action,
                                                const char *hdr,
                                                const char *value,
-                                               const char* envclause)
+                                               const char *subs,
+                                               const char *envclause)
 {
     headers_conf *dirconf = indirconf;
     const char *condition_var = NULL;
@@ -392,10 +396,29 @@
         new->action = hdr_unset;
     else if (!strcasecmp(action, "echo"))
         new->action = hdr_echo;
+    else if (!strcasecmp(action, "edit"))
+        new->action = hdr_edit;
     else
-        return "first argument must be 'add', 'set', 'append', 'unset' or "
-               "'echo'.";
+        return "first argument must be 'add', 'set', 'append', 'unset', "
+               "'echo' or 'edit'.";
 
+    if (new->action == hdr_edit) {
+        if (subs == NULL) {
+            return "Header edit requires a match and a substitution";
+        }
+        new->regex = ap_pregcomp(cmd->pool, value, AP_REG_EXTENDED);
+        if (new->regex == NULL) {
+            return "Header edit regex could not be compiled";
+        }
+        new->subs = subs;
+    }
+    else {
+        /* there's no subs, so envclause is really that argument */
+        if (envclause != NULL) {
+            return "Too many arguments to directive";
+        }
+        envclause = subs;
+    }
     if (new->action == hdr_unset) {
         if (value) {
             if (envclause) {
@@ -465,6 +488,7 @@
     const char *hdr;
     const char *val;
     const char *envclause;
+    const char *subs;
 
     action = ap_getword_conf(cmd->pool, &args);
     if (cmd->info == &hdr_out) {
@@ -478,6 +502,7 @@
     }
     hdr = ap_getword_conf(cmd->pool, &args);
     val = *args ? ap_getword_conf(cmd->pool, &args) : NULL;
+    subs = *args ? ap_getword_conf(cmd->pool, &args) : NULL;
     envclause = *args ? ap_getword_conf(cmd->pool, &args) : NULL;
 
     if (*args) {
@@ -485,7 +510,7 @@
                            " has too many arguments", NULL);
     }
 
-    return header_inout_cmd(cmd, indirconf, action, hdr, val, envclause);
+    return header_inout_cmd(cmd, indirconf, action, hdr, val, subs, envclause);
 }
 
 /*
@@ -512,6 +537,26 @@
     }
     return str ? str : "";
 }
+static const char *process_regexp(header_entry *hdr, const char *value,
+                                  apr_pool_t *pool)
+{
+    unsigned int nmatch = 10;
+    ap_regmatch_t pmatch[10];
+    const char *subs;
+    char *ret;
+    int diffsz;
+    if (ap_regexec(hdr->regex, value, nmatch, pmatch, 0)) {
+        /* no match, nothing to do */
+        return value;
+    }
+    subs = ap_pregsub(pool, hdr->subs, value, nmatch, pmatch);
+    diffsz = strlen(subs) - (pmatch[0].rm_eo - pmatch[0].rm_so);
+    ret = apr_palloc(pool, strlen(value) + 1 + diffsz);
+    memcpy(ret, value, pmatch[0].rm_so);
+    strcpy(ret + pmatch[0].rm_so, subs);
+    strcat(ret, value + pmatch[0].rm_eo);
+    return ret;
+}
 
 static int echo_header(echo_do *v, const char *key, const char *val)
 {
@@ -528,7 +573,9 @@
 static void do_headers_fixup(request_rec *r, apr_table_t *headers,
                              apr_array_header_t *fixup, int early)
 {
+    echo_do v;
     int i;
+    const char *val;
 
     for (i = 0; i < fixup->nelts; ++i) {
         header_entry *hdr = &((header_entry *) (fixup->elts))[i];
@@ -568,14 +615,18 @@
             apr_table_unset(headers, hdr->header);
             break;
         case hdr_echo:
-        {
-            echo_do v;
             v.r = r;
             v.hdr = hdr;
             apr_table_do((int (*) (void *, const char *, const char *))
                          echo_header, (void *) &v, r->headers_in, NULL);
             break;
-        }
+        case hdr_edit:
+            val = apr_table_get(headers, hdr->header);
+            if (val != NULL) {
+                apr_table_setn(headers, hdr->header,
+                               process_regexp(hdr, val, r->pool));
+            }
+            break;
         }
     }
 }