summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNick Kew <niq@apache.org>2009-12-27 01:05:12 +0100
committerNick Kew <niq@apache.org>2009-12-27 01:05:12 +0100
commit76ea26f7a0a7da2e29bf3dc19941647dd9d90518 (patch)
treec6e7c7d51d672a0c24d6e1d67505090c3b423e4d
parentmod_headers: align Header Edit with Header Set on Content-Type (diff)
downloadapache2-76ea26f7a0a7da2e29bf3dc19941647dd9d90518.tar.xz
apache2-76ea26f7a0a7da2e29bf3dc19941647dd9d90518.zip
mod_headers: Enable multi-match-and-replace edit option
PR 47066 git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@894036 13f79535-47bb-0310-9956-ffa450edef68
-rw-r--r--CHANGES3
-rw-r--r--docs/manual/mod/mod_headers.xml9
-rw-r--r--modules/metadata/mod_headers.c19
3 files changed, 26 insertions, 5 deletions
diff --git a/CHANGES b/CHANGES
index 81e0854f87..87f11b30b5 100644
--- a/CHANGES
+++ b/CHANGES
@@ -36,6 +36,9 @@ Changes with Apache 2.3.5
*) mod_headers: align Header Edit with Header Set when used on Content-Type
PR 48422 [Cyril Bonté <cyril.bonte free.fr>, Nick Kew>]
+ *) mod_headers: Enable multi-match-and-replace edit option
+ PR 47066 [Nick Kew]
+
Changes with Apache 2.3.4
*) Replace AcceptMutex, LockFile, RewriteLock, SSLMutex, SSLStaplingMutex,
diff --git a/docs/manual/mod/mod_headers.xml b/docs/manual/mod/mod_headers.xml
index f23b965203..cc377a60e3 100644
--- a/docs/manual/mod/mod_headers.xml
+++ b/docs/manual/mod/mod_headers.xml
@@ -193,7 +193,7 @@ headers</description>
<directivesynopsis>
<name>RequestHeader</name>
<description>Configure HTTP request headers</description>
-<syntax>RequestHeader add|append|edit|merge|set|unset <var>header</var>
+<syntax>RequestHeader add|append|edit|edit*|merge|set|unset <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>
@@ -223,11 +223,16 @@ headers</description>
values.</dd>
<dt><code>edit</code></dt>
+ <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>
+ is a replacement string, which may contain backreferences.
+ The <code>edit</code> form will match and replace exactly once
+ in a header value, whereas the <code>edit*</code> form will replace
+ <em>every</em> instance of the search pattern if it appears more
+ than once.</dd>
<dt><code>merge</code></dt>
<dd>The response header is appended to any existing header of
diff --git a/modules/metadata/mod_headers.c b/modules/metadata/mod_headers.c
index e27f504ae6..5e7834aecc 100644
--- a/modules/metadata/mod_headers.c
+++ b/modules/metadata/mod_headers.c
@@ -95,7 +95,8 @@ typedef enum {
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 */
+ hdr_edit = 'r', /* change value by regexp, match once */
+ hdr_edit_r = 'R' /* change value by regexp, everymatch */
} hdr_actions;
/*
@@ -366,6 +367,7 @@ static char *parse_format_string(apr_pool_t *p, header_entry *hdr, const char *s
/* No string to parse with unset and echo commands */
if (hdr->action == hdr_unset ||
hdr->action == hdr_edit ||
+ hdr->action == hdr_edit_r ||
hdr->action == hdr_echo) {
return NULL;
}
@@ -416,11 +418,13 @@ static APR_INLINE const char *header_inout_cmd(cmd_parms *cmd,
new->action = hdr_echo;
else if (!strcasecmp(action, "edit"))
new->action = hdr_edit;
+ else if (!strcasecmp(action, "edit*"))
+ new->action = hdr_edit_r;
else
return "first argument must be 'add', 'set', 'append', 'merge', "
- "'unset', 'echo', or 'edit'.";
+ "'unset', 'echo', 'edit', or 'edit*'.";
- if (new->action == hdr_edit) {
+ if (new->action == hdr_edit || new->action == hdr_edit_r) {
if (subs == NULL) {
return "Header edit requires a match and a substitution";
}
@@ -566,6 +570,7 @@ static const char *process_regexp(header_entry *hdr, const char *value,
unsigned int nmatch = 10;
ap_regmatch_t pmatch[10];
const char *subs;
+ const char *remainder;
char *ret;
int diffsz;
if (ap_regexec(hdr->regex, value, nmatch, pmatch, 0)) {
@@ -574,6 +579,13 @@ static const char *process_regexp(header_entry *hdr, const char *value,
}
subs = ap_pregsub(pool, hdr->subs, value, nmatch, pmatch);
diffsz = strlen(subs) - (pmatch[0].rm_eo - pmatch[0].rm_so);
+ if (hdr->action == hdr_edit) {
+ remainder = value + pmatch[0].rm_eo;
+ }
+ else { /* recurse to edit multiple matches if applicable */
+ remainder = process_regexp(hdr, value + pmatch[0].rm_eo, pool);
+ diffsz += strlen(remainder) - strlen(value + pmatch[0].rm_eo);
+ }
ret = apr_palloc(pool, strlen(value) + 1 + diffsz);
memcpy(ret, value, pmatch[0].rm_so);
strcpy(ret + pmatch[0].rm_so, subs);
@@ -722,6 +734,7 @@ static void do_headers_fixup(request_rec *r, apr_table_t *headers,
echo_header, (void *) &v, r->headers_in, NULL);
break;
case hdr_edit:
+ case hdr_edit_r:
if (!strcasecmp(hdr->header, "Content-Type") && r->content_type) {
ap_set_content_type(r, process_regexp(hdr, r->content_type,
r->pool));