From: Bill Stoddard Date: Tue, 5 Jun 2001 21:44:48 +0000 (+0000) Subject: Extend mod_headers to support conditional driven Header X-Git-Tag: 2.0.19~142 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=80ed810f66a0483ea0b91e500d17febc95293d42;p=thirdparty%2Fapache%2Fhttpd.git Extend mod_headers to support conditional driven Header add, append and set. Use SetEnvIf to set an envar and conditionally add/append/set headers based on this envar thusly: SetEnvIf TSMyHeader value HAVE_TSMyHeader Header add MyHeader "%t %D" env=HAVE_TSMyHeader If the request contains header "TSMyHeader: value" then header MyHeader: "t=xxxxxxxxxx D=yyyy" will be sent on the response. Update mod_headers.html. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@89271 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/CHANGES b/CHANGES index 82946ab7618..cbce958d046 100644 --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,32 @@ Changes with Apache 2.0.19-dev + *) Extend mod_headers to support conditional driven Header + add, append and set. Use SetEnvIf to set an envar and conditionally + add/append/set headers based on this envar thusly: + + SetEnvIf TSMyHeader value HAVE_TSMyHeader + Header add MyHeader "%t %D" env=HAVE_TSMyHeader + + If the request contains header "TSMyHeader: value" then header + MyHeader: "t=xxxxxxxxxx D=yyyy" will be sent on the response. + [Bill Stoddard] + + *) Extend mod_headers to support using format specifiers on Header + add, append and set header values. Two format specifiers are supported: + + %t - reports, in UTC microseconds since the epoch, when the + request was received. + + %D - reports the time, in microseconds, between when the request was + received and the response sent. + + Examples: + Header add MyHeader "This request served in %D microseconds. %t" + + results in a header being added to the response that looks like this: + + MyHeader: This request served in D=5438 microseconds. t=991424704447256 + + [Bill Stoddard] *) Fix reset_filter(). We need to be careful how we remove filters. If we set r->output_filters to NULL, we also have to reset the diff --git a/docs/manual/mod/mod_headers.html b/docs/manual/mod/mod_headers.html index 9db90abbe68..72b2ea0e551 100644 --- a/docs/manual/mod/mod_headers.html +++ b/docs/manual/mod/mod_headers.html @@ -152,7 +152,7 @@ the browser, or by Apache input filters to be overridden or modified. HREF="directive-dict.html#Syntax" REL="Help" >Syntax: Header set|append|add - header value
+ header value [env=[!]environment-variable]
  • set
    - The response header is set, replacing any previous header with this name + The response header is set, replacing any previous header with this name. + The value may be a format string.
  • append
    The response header is appended to any existing header of the same @@ -206,20 +207,30 @@ by the first argument. This can be one of the following values:
  • echo
    Request headers with this name are echoed back in the response headers. - header may be a regular expression. For example, the directive -

    - Header echo ^TS* -

    - will cause all request headers that begin with TS to be echoed - or copied over to the response headers. + header may be a regular expression. -This argument is followed by a header name, which can include the +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 -and unset. The header name for echo is case sensitive and may be a -regular expression. For add, append and set a value is given as the third -argument. If this value contains spaces, it should be surrounded by double -quotes. For unset and echo, no value should be given. +and unset. The header name for echo is case sensitive and may be a +regular expression. +

    +add, append and set take a value as the third argument. If +value contains spaces, it should be surrounded by doublequotes. +value may be a character string, a string containing format +specifiers or a combination of both. The following format specifiers +are supported in value: +

    +%t:	The time the request was received in Universal Coordinated Time
    +	since the epoch (Jan. 1, 1970) measured in microseconds. The
    +	value is preceeded by "t=".
    +%D:     The time from when the request was received to the time the
    +        headers are sent on the wire. This is a measure of the
    +	duration of the request. The value is preceeded by "D=".
    +
    +add, append and set may take an optional conditional clause +as the fourth argument. The header action (add, append, set) is +done only if the conditional clause evaluates as TRUE.

    Order of Processing

    @@ -251,7 +262,49 @@ The Header directives are processed just before the response is sent to the network. These means that it is possible to set and/or override most headers, except for those headers added by the header filter.

    +


    +

    Examples

    +
      +
    1. Copy all request headers that begin with "TS" to the response headers:
    2. +
      +   Header echo ^TS*
      +
      + +
    3. Add a header, MyHeader, to the response including a timestamp for when +the request was received and how long it took to begin serving the +request. This header can be used by the client to intuit load on +the server or in isolating bottlenecks between the client and the +server.
    4. +
      +   Header add MyHeader "%D %t"
      +
      +results in this header being added to the response: +
      +   MyHeader: D=3775428 t=991424704447256
      +
      +
    5. Say hello to Joe
    6. +
      +   Header add MyHeader "Hello Joe. It took %D microseconds for Apache to serve this request."
      +
      +results in this header being added to the response: +
      +   MyHeader: Hello Joe. It took D=3775428 microseconds for Apache to serve this request.
      +
      +
    7. Conditionally send MyHeader on the response if and only if header +"MyRequestHeader" is present on the request. This is useful for +constructing headers in response to some client stimulus. Note that +this example requires the services of the mod_setenvif module.
    8. +
      +   SetEnvIf MyRequestHeader value HAVE_MyRequestHeader
      + Header add MyHeader "%D %t mytext" env=HAVE_MyRequestHeader +
      +If the header "MyRequestHeader: value" is present on the HTTP request, the response +will contain the following header: +
      +   MyHeader: D=3775428 t=991424704447256 mytext
      +
      +
    diff --git a/modules/metadata/mod_headers.c b/modules/metadata/mod_headers.c index da354d6d2f7..2d8fd19a149 100644 --- a/modules/metadata/mod_headers.c +++ b/modules/metadata/mod_headers.c @@ -153,6 +153,7 @@ typedef struct { char *header; apr_array_header_t *ta; /* Array of format_tag structs */ regex_t *regex; + const char *condition_var; } header_entry; /* echo_do is used for Header echo to iterate through the request headers*/ @@ -338,15 +339,16 @@ static char *parse_format_string(apr_pool_t *p, header_entry *hdr, const char *s /* handle RequestHeader and Header directive */ static const char *header_inout_cmd(hdr_inout inout, cmd_parms *cmd, void *indirconf, const char *action, const char *inhdr, - const char *value) + const char *value, const char* envclause) { headers_conf *dirconf = indirconf; + const char *condition_var; + char *colon; char *hdr = apr_pstrdup(cmd->pool, inhdr); header_entry *new; server_rec *s = cmd->server; headers_conf *serverconf = ap_get_module_config(s->module_config, &headers_module); - char *colon; if (cmd->path) { new = (header_entry *) apr_array_push((hdr_in == inout) ? dirconf->fixup_in : dirconf->fixup_out); @@ -389,20 +391,47 @@ static const char *header_inout_cmd(hdr_inout inout, cmd_parms *cmd, void *indir else if (!value) return "header requires three arguments"; + /* Handle the envclause on Header */ + if (envclause != NULL) { + if (inout != hdr_out) { + return "error: envclause (env=...) only valid on Header directive"; + } + if (strncasecmp(envclause, "env=", 4) != 0) { + return "error: envclause should be in the form env=envar"; + } + if ((envclause[4] == '\0') + || ((envclause[4] == '!') && (envclause[5] == '\0'))) { + return "error: missing environment variable name. envclause should be in the form env=envar "; + } + condition_var = apr_pstrdup(cmd->pool, &envclause[4]); + } + if ((colon = strchr(hdr, ':'))) *colon = '\0'; new->header = hdr; + new->condition_var = condition_var; return parse_format_string(cmd->pool, new, value); } /* Handle Header directive */ static const char *header_cmd(cmd_parms *cmd, void *indirconf, - const char *action, const char *inhdr, - const char *value) + const char *args) { - return header_inout_cmd(hdr_out, cmd, indirconf, action, inhdr, value); + char *s; + const char *action; + const char *hdr; + const char *val; + const char *envclause; + + s = apr_pstrdup(cmd->pool, args); + action = ap_getword_conf(cmd->pool, &s); + hdr = ap_getword_conf(cmd->pool, &s); + val = *s ? ap_getword_conf(cmd->pool, &s) : NULL; + envclause = *s ? ap_getword_conf(cmd->pool, &s) : NULL; + + return header_inout_cmd(hdr_out, cmd, indirconf, action, hdr, val, envclause); } /* handle RequestHeader directive */ @@ -410,7 +439,7 @@ static const char *request_header_cmd(cmd_parms *cmd, void *indirconf, const char *action, const char *inhdr, const char *value) { - return header_inout_cmd(hdr_in, cmd, indirconf, action, inhdr, value); + return header_inout_cmd(hdr_in, cmd, indirconf, action, inhdr, value, NULL); } /* @@ -458,6 +487,20 @@ static void do_headers_fixup(request_rec *r, hdr_inout inout, for (i = 0; i < fixup->nelts; ++i) { header_entry *hdr = &((header_entry *) (fixup->elts))[i]; + + /* Have any conditional envar-controlled Header processing to do? */ + if (hdr->condition_var) { + const char *envar = hdr->condition_var; + if (*envar != '!') { + if (apr_table_get(r->subprocess_env, envar) == NULL) + continue; + } + else { + if (apr_table_get(r->subprocess_env, &envar[1]) != NULL) + continue; + } + } + switch (hdr->action) { case hdr_add: apr_table_addn(headers, hdr->header, process_tags(hdr, r)); @@ -536,8 +579,8 @@ static apr_status_t ap_headers_fixup(request_rec *r) static const command_rec headers_cmds[] = { - AP_INIT_TAKE23("Header", header_cmd, NULL, OR_FILEINFO, - "an action, header and value"), + AP_INIT_RAW_ARGS("Header", header_cmd, NULL, OR_FILEINFO, + "an action, header and value followed by optional env clause"), AP_INIT_TAKE23("RequestHeader", request_header_cmd, NULL, OR_FILEINFO, "an action, header and value"), {NULL}