From: Chris Darroch Date: Tue, 21 Aug 2007 23:22:00 +0000 (+0000) Subject: add merge option to avoid duplicate values within the same header X-Git-Tag: 2.3.0~1577 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=169e22c568accf5317fb3ae8b407fdf532f1c448;p=apache add merge option to avoid duplicate values within the same header git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@568323 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/docs/manual/mod/mod_headers.xml b/docs/manual/mod/mod_headers.xml index 4cc57b6005..4f56a66cc0 100644 --- a/docs/manual/mod/mod_headers.xml +++ b/docs/manual/mod/mod_headers.xml @@ -153,13 +153,41 @@ headers RequestHeader edit Destination ^https: http: early + +
  • + 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 CGI, NO_CACHE and + NO_STORE environment variables all existed for the + request): + + + Header merge Cache-Control no-cache env=CGI
    + Header merge Cache-Control no-cache env=NO_CACHE
    + Header merge Cache-Control no-store env=NO_STORE +
    + +

    then the response would contain the following header:

    + + + Cache-Control: no-cache, no-store + + +

    If append was used instead of merge, + then the response would contain the following header:

    + + + Cache-Control: no-cache, no-cache, no-store + +
  • RequestHeader Configure HTTP request headers -RequestHeader set|append|add|unset|edit header +RequestHeader set|append|merge|add|unset|edit header [value] [replacement] [early|env=[!]variable] server configvirtual host directory.htaccess @@ -184,12 +212,22 @@ headers is the HTTP standard way of giving a header multiple values. +
    merge
    +
    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.
    +
    add
    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 set or - append should be used instead.
    + unforeseen consequences, and in general set, + append or merge should be used instead.
    unset
    The request header of this name is removed, if it exists. If @@ -206,7 +244,7 @@ headers

    This argument is followed by a header name, which can include the final colon, but it is not required. Case is - ignored. For set, append and + ignored. For set, append, merge and add a value is given as the third argument. If a value contains spaces, it should be surrounded by double quotes. For unset, no value should be given. @@ -240,7 +278,7 @@ headers Header Configure HTTP response headers -Header [condition] set|append|add|unset|echo|edit +Header [condition] set|append|merge|add|unset|echo|edit header [value] [early|env=[!]variable] server configvirtual host directory.htaccess @@ -273,12 +311,22 @@ headers header it is separated from the existing header with a comma. This is the HTTP standard way of giving a header multiple values.

    +
    merge
    +
    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.
    +
    add
    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 set or - append should be used instead.
    + unforeseen consequences, and in general set, + append or merge should be used instead.
    unset
    The response header of this name is removed, if it exists. @@ -301,14 +349,15 @@ headers

    This argument is followed by a header name, which can include the final colon, but it is not required. Case is - ignored for set, append, add, - unset, and edit. + ignored for set, append, merge, + add, unset and edit. The header name for echo is case sensitive and may be a regular expression.

    -

    For set, append and add a - value is specified as the third argument. If value +

    For set, append, merge and + add a value is specified as the third argument. + If value contains spaces, it should be surrounded by double quotes. value may be a character string, a string containing format specifiers or a combination of both. The following format specifiers diff --git a/modules/metadata/mod_headers.c b/modules/metadata/mod_headers.c index e139b5db9f..6d459b880b 100644 --- a/modules/metadata/mod_headers.c +++ b/modules/metadata/mod_headers.c @@ -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 @@ typedef enum { 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 @@ static APR_INLINE const char *header_inout_cmd(cmd_parms *cmd, 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 @@ static APR_INLINE const char *header_inout_cmd(cmd_parms *cmd, 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) { @@ -610,6 +616,46 @@ static void do_headers_fixup(request_rec *r, apr_table_t *headers, 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)); break;