Return-Path: Delivered-To: apmail-httpd-dev-archive@www.apache.org Received: (qmail 7841 invoked from network); 28 Sep 2006 16:16:43 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (209.237.227.199) by minotaur.apache.org with SMTP; 28 Sep 2006 16:16:43 -0000 Received: (qmail 67517 invoked by uid 500); 28 Sep 2006 16:16:41 -0000 Delivered-To: apmail-httpd-dev-archive@httpd.apache.org Received: (qmail 67125 invoked by uid 500); 28 Sep 2006 16:16:39 -0000 Mailing-List: contact dev-help@httpd.apache.org; run by ezmlm Precedence: bulk Reply-To: dev@httpd.apache.org list-help: list-unsubscribe: List-Post: List-Id: Delivered-To: mailing list dev@httpd.apache.org Received: (qmail 67106 invoked by uid 99); 28 Sep 2006 16:16:39 -0000 Received: from idunn.apache.osuosl.org (HELO idunn.apache.osuosl.org) (140.211.166.84) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 28 Sep 2006 09:16:39 -0700 X-ASF-Spam-Status: No, hits=0.0 required=5.0 tests= Received: from [80.229.52.226] ([80.229.52.226:47711] helo=asgard.webthing.com) by idunn.apache.osuosl.org (ecelerity 2.1.1.8 r(12930)) with ESMTP id C5/16-17533-065FB154 for ; Thu, 28 Sep 2006 09:16:37 -0700 Received: from asgard (asgard [192.168.1.2]) by asgard.webthing.com (Postfix) with ESMTP id D48E96451C for ; Thu, 28 Sep 2006 17:16:26 +0100 (BST) From: Nick Kew Organization: WebThing Ltd To: dev@httpd.apache.org Subject: Regexp-based rewriting for mod_headers? Date: Thu, 28 Sep 2006 17:16:24 +0100 User-Agent: KMail/1.9.1 MIME-Version: 1.0 Content-Type: Multipart/Mixed; boundary="Boundary-00=_aV/GFr60OFnJtPJ" Message-Id: <200609281716.26385.nick@webthing.com> X-Spam-Rating: minotaur.apache.org 1.6.2 0/1000/N --Boundary-00=_aV/GFr60OFnJtPJ Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Content-Disposition: inline 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 --Boundary-00=_aV/GFr60OFnJtPJ Content-Type: text/x-diff; charset="us-ascii"; name="headers-patch" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="headers-patch" 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; } - } } } --Boundary-00=_aV/GFr60OFnJtPJ--