]> git.ipfire.org Git - thirdparty/apache/httpd.git/commitdiff
Extend mod_headers to support conditional driven Header
authorBill Stoddard <stoddard@apache.org>
Tue, 5 Jun 2001 21:44:48 +0000 (21:44 +0000)
committerBill Stoddard <stoddard@apache.org>
Tue, 5 Jun 2001 21:44:48 +0000 (21:44 +0000)
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

CHANGES
docs/manual/mod/mod_headers.html
modules/metadata/mod_headers.c

diff --git a/CHANGES b/CHANGES
index 82946ab76181711fdb8644ebeb3443049b2f68ae..cbce958d0460cbfd0cdcbedee79fd29d22c6bdd2 100644 (file)
--- 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
index 9db90abbe689019be0f7fed14d65ab9a3dfed7e8..72b2ea0e551a2dbba24ea751cb1a8f9ff6adc916 100644 (file)
@@ -152,7 +152,7 @@ the browser, or by Apache input filters to be overridden or modified.
  HREF="directive-dict.html#Syntax"
  REL="Help"
 ><STRONG>Syntax:</STRONG></A> Header set|append|add
- <EM>header</EM> <EM>value</EM><BR>
+ <EM>header</EM> <EM>value</EM> <EM>[env=[!]environment-variable]</EM><BR>
 <A
  HREF="directive-dict.html#Syntax"
  REL="Help"
@@ -186,7 +186,8 @@ by the first argument. This can be one of the following values:
 
 <UL>
 <LI><STRONG>set</STRONG><BR>
-  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 <EM>value</EM> may be a format string.
 
 <LI><STRONG>append</STRONG><BR>
   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:
 
 <LI><STRONG>echo</STRONG><BR>
   Request headers with this name are echoed back in the response headers.
-  <EM>header</EM> may be a regular expression. For example, the directive
-  <P>
-  Header echo ^TS*
-  <P>
-  will cause all request headers that begin with TS to be echoed
-  or copied over to the response headers.
+  <EM>header</EM> may be a regular expression. 
 </UL>
 
-This argument is followed by a header name, which can include the
+This argument is followed by a <EM>header</EM> 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 <EM>header</EM> name for echo is case sensitive and may be a
+regular expression. 
+<P>
+add, append and set take a <EM>value</EM> as the third argument. If 
+<EM>value</EM> contains spaces, it should be surrounded by doublequotes. 
+<EM>value</EM> may be a character string, a string containing format
+specifiers or a combination of both. The following format specifiers
+are supported in <EM>value</EM>:
+<PRE>
+%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=".
+</PRE>
+add, append and set may take an optional <EM>conditional clause</EM>
+as the fourth argument. The header action (add, append, set) is 
+done only if the <EM>conditional clause</EM> evaluates as TRUE.
 
 <H3>Order of Processing</H3>
 
@@ -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.
 <P>
+<HR>
+<H2>Examples</H2>
+<OL>
+<LI>Copy all request headers that begin with "TS" to the response headers:</LI>
+<PRE>
+   Header echo ^TS*
+</PRE>
+
+<LI>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.</LI>
+<PRE>
+   Header add MyHeader "%D %t"
+</PRE>
+results in this header being added to the response:
+<PRE>
+   MyHeader: D=3775428 t=991424704447256
+</PRE>
+<LI>Say hello to Joe</LI>
+<PRE>
+   Header add MyHeader "Hello Joe. It took %D microseconds for Apache to serve this request."
+</PRE>
+results in this header being added to the response:
+<PRE>
+   MyHeader: Hello Joe. It took D=3775428 microseconds for Apache to serve this request.
+</PRE>
 
+<LI>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.</LI>
+<PRE>
+   SetEnvIf MyRequestHeader value HAVE_MyRequestHeader<BR>
+   Header add MyHeader "%D %t mytext" env=HAVE_MyRequestHeader
+</PRE> 
+If the header "MyRequestHeader: value" is present on the HTTP request, the response
+will contain the following header:
+<PRE>
+   MyHeader: D=3775428 t=991424704447256 mytext
+</PRE>
+</OL>
 <!--#include virtual="footer.html" -->
 </BODY>
 </HTML>
index da354d6d2f74c843c8f976aee78723ec77afdb99..2d8fd19a1496dd72cf0340f8ba57840cebb847b0 100644 (file)
@@ -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}