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
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"
<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
<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>
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>
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*/
/* 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);
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 */
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);
}
/*
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));
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}