We have a problem with DAV + SSL hardware.
It appears to be the issue described in
http://svn.haxx.se/users/archive-2006-03/0549.shtml

It seems to me that the ability to rewrite a request header
will fix that.  As a generic fix, I've patched mod_headers
to support regexp-based rewriting of arbitrary headers.

Please review.  If people like this (or if noone objects and I
find the time), I'll document it and commit to /trunk/.

-- 
Nick Kew
Index: mod_headers.c
===================================================================
--- mod_headers.c	(revision 450806)
+++ mod_headers.c	(working copy)
@@ -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,27 @@
     }
     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);
+    /* recurse over matches */
+    return process_regexp(hdr, ret, pool);
+}
 
 static int echo_header(echo_do *v, const char *key, const char *val)
 {
@@ -528,7 +574,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,15 +616,19 @@
             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;
         }
-        }
     }
 }
 

Reply via email to