]> granicus.if.org Git - apache/commitdiff
Implement "Early" mode in mod_headers, and document it.
authorNick Kew <niq@apache.org>
Mon, 5 Jul 2004 04:49:45 +0000 (04:49 +0000)
committerNick Kew <niq@apache.org>
Mon, 5 Jul 2004 04:49:45 +0000 (04:49 +0000)
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@104170 13f79535-47bb-0310-9956-ffa450edef68

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

diff --git a/CHANGES b/CHANGES
index 5e427e56956728e6e5b0a637cfb87f5738ae32ea..5f25e02f5b28f85c87a6941f7ce7bca17cdd40b8 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -2,6 +2,10 @@ Changes with Apache 2.1.0-dev
 
   [Remove entries to the current 2.0 section below, when backported]
 
+  *) mod_headers: implement "Early" processing option in post_read_request
+     to enable Header and RequestHeader directives to be used to set up
+     testcases for pre-fixups request phases [Nick Kew]
+
   *) mod_dir: the trailing-slash behaviour is now configurable using the
      DirectorySlash directive.  [AndrĂ© Malo]
 
index 1003d746b7b563347402d46d4518b22ea37cb36d..030aaab73274fdb4551c2e6222060dfe3eeb5cb3 100644 (file)
@@ -1,7 +1,7 @@
 <?xml version="1.0"?>
 <!DOCTYPE modulesynopsis SYSTEM "../style/modulesynopsis.dtd">
 <?xml-stylesheet type="text/xsl" href="../style/manual.en.xsl"?>
-<!-- $Revision: 1.17 $ -->
+<!-- $Revision: 1.18 $ -->
 
 <!--
  Copyright 2002-2004 The Apache Software Foundation
@@ -57,6 +57,27 @@ is available only in Apache 2.0</compatibility>
     reversed, the MirrorID header is set to "mirror 12".</p>
 </section>
 
+<section id="early"><title>Early and Late Processing</title>
+    <p><module>mod_headers</module> can be applied either early or late
+    in the request.  The normal mode is late, when Request Headers are
+    set immediately before running the content generator and Response
+    Headers just as the response is sent down the wire.  Always use
+    Late mode in an operational server.</p>
+
+    <p>Early mode is designed as a test/debugging aid for developers.
+    Directives defined using the <code>early</code> keyword are set
+    right at the beginning of processing the request.  This means
+    they can be used to simulate different requests and set up test
+    cases, but it also means that headers may be changed at any time
+    by other modules before generating a Response.</p>
+
+    <p>Because early directives are processed before the request path's
+    configuration is traversed, early headers can only be set in a
+    main server or virtual host context.  Early directives cannot depend
+    on a request path, so they will fail in contexts such as
+    <code>&lt;Directory&gt;</code> or <code>&lt;Location&gt;</code>.</p>
+</section>
+
 <section id="examples"><title>Examples</title>
 
     <ol>
@@ -129,7 +150,7 @@ is available only in Apache 2.0</compatibility>
 <name>RequestHeader</name>
 <description>Configure HTTP request headers</description>
 <syntax>RequestHeader set|append|add|unset <var>header</var>
-[<var>value</var>] [env=[!]<var>variable</var>]</syntax>
+[<var>value</var>] [early|env=[!]<var>variable</var>]</syntax>
 <contextlist><context>server config</context><context>virtual host</context>
 <context>directory</context><context>.htaccess</context></contextlist>
 <override>FileInfo</override>
@@ -179,14 +200,17 @@ is available only in Apache 2.0</compatibility>
 
     <p>The <directive>RequestHeader</directive> directive may be followed by
     an additional argument, which may be used to specify conditions under
-    which the action will be taken. If the <a href="../env.html">environment
+    which the action will be taken, or may be the keyword <code>early</code>
+    to specify <a href="#early">early processing</a>. If the
+    <a href="../env.html">environment
     variable</a> specified in the <code>env=<var>...</var></code> argument
     exists (or if the environment variable does not exist and
     <code>env=!<var>...</var></code> is specified) then the action specified
     by the <directive>RequestHeader</directive> directive will take effect.
     Otherwise, the directive will have no effect on the request.</p>
 
-    <p>The <directive>RequestHeader</directive> directive is processed
+    <p>Except in <a href="#early">early</a> mode, the
+    <directive>RequestHeader</directive> directive is processed
     just before the request is run by its handler in the fixup phase.
     This should allow headers generated by the browser, or by Apache
     input filters to be overridden or modified.</p>
@@ -197,7 +221,7 @@ is available only in Apache 2.0</compatibility>
 <name>Header</name>
 <description>Configure HTTP response headers</description>
 <syntax>Header [<var>condition</var>] set|append|add|unset|echo
-<var>header</var> [<var>value</var>] [env=[!]<var>variable</var>]</syntax>
+<var>header</var> [<var>value</var>] [early|env=[!]<var>variable</var>]</syntax>
 <contextlist><context>server config</context><context>virtual host</context>
 <context>directory</context><context>.htaccess</context></contextlist>
 <override>FileInfo</override>
@@ -296,16 +320,18 @@ is available only in Apache 2.0</compatibility>
     </note> 
 
     <p>The <directive>Header</directive> directive may be followed by an
-    additional argument, which may be used to specify conditions
-    under which the action will be taken. If the <a
-    href="../env.html">environment variable</a> specified in the
+    an additional argument, which may be used to specify conditions under
+    which the action will be taken, or may be the keyword <code>early</code>
+    to specify <a href="#early">early processing</a>. If the
+    <a href="../env.html">environment variable</a> specified in the
     <code>env=<var>...</var></code> argument exists (or if the environment
     variable does not exist and <code>env=!<var>...</var></code> is specified)
     then the action specified by the <directive>Header</directive> directive
     will take effect. Otherwise, the directive will have no effect
     on the request.</p>
 
-    <p>The <directive>Header</directive> directives are processed just
+    <p>Except in <a href="#early">early</a> mode, the
+    <directive>Header</directive> 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>
index c85d69808fe27bfe1e804b1e4493c41ddf0e513c..988473f8c49986fd9fae01e611e9951b760667ed 100644 (file)
@@ -107,6 +107,8 @@ typedef struct {
     char *arg;
 } format_tag;
 
+/* 'Magic' condition_var value to run action in post_read_request */
+static const char* condition_early = "early";
 /*
  * There is one "header_entry" per Header/RequestHeader config directive
  */
@@ -428,15 +430,20 @@ static APR_INLINE const char *header_inout_cmd(cmd_parms *cmd,
 
     /* Handle the envclause on Header */
     if (envclause != NULL) {
-        if (strncasecmp(envclause, "env=", 4) != 0) {
-            return "error: envclause should be in the form env=envar";
+        if (strcasecmp(envclause, "early") == 0) {
+            condition_var = condition_early;
         }
-        if ((envclause[4] == '\0')
-            || ((envclause[4] == '!') && (envclause[5] == '\0'))) {
-            return "error: missing environment variable name. "
-                "envclause should be in the form env=envar ";
+        else {
+            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 = envclause + 4;
         }
-        condition_var = envclause + 4;
     }
     
     if ((colon = ap_strchr_c(hdr, ':'))) {
@@ -518,16 +525,24 @@ static int echo_header(echo_do *v, const char *key, const char *val)
 }
 
 static void do_headers_fixup(request_rec *r, apr_table_t *headers,
-                             apr_array_header_t *fixup)
+                             apr_array_header_t *fixup, int early)
 {
     int i;
 
     for (i = 0; i < fixup->nelts; ++i) {
         header_entry *hdr = &((header_entry *) (fixup->elts))[i];
+        const char *envar = hdr->condition_var;
 
+       /* ignore early headers in late calls */
+        if (!early && (envar == condition_early)) {
+            continue;
+        }
+       /* ignore late headers in early calls */
+        else if (early && (envar != condition_early)) {
+            continue;
+        }
         /* Have any conditional envar-controlled Header processing to do? */
-        if (hdr->condition_var) {
-            const char *envar = hdr->condition_var;
+        else if (envar && !early) {
             if (*envar != '!') {
                 if (apr_table_get(r->subprocess_env, envar) == NULL)
                     continue;
@@ -597,8 +612,8 @@ static apr_status_t ap_headers_output_filter(ap_filter_t *f,
                  "headers: ap_headers_output_filter()");
 
     /* do the fixup */
-    do_headers_fixup(f->r, f->r->err_headers_out, dirconf->fixup_err);
-    do_headers_fixup(f->r, f->r->headers_out, dirconf->fixup_out);
+    do_headers_fixup(f->r, f->r->err_headers_out, dirconf->fixup_err, 0);
+    do_headers_fixup(f->r, f->r->headers_out, dirconf->fixup_out, 0);
 
     /* remove ourselves from the filter chain */
     ap_remove_output_filter(f);
@@ -625,7 +640,7 @@ static apr_status_t ap_headers_error_filter(ap_filter_t *f,
      * Add any header fields defined by "Header always" to r->err_headers_out.
      * Server-wide first, then per-directory to allow overriding.
      */
-    do_headers_fixup(f->r, f->r->err_headers_out, dirconf->fixup_err);
+    do_headers_fixup(f->r, f->r->err_headers_out, dirconf->fixup_err, 0);
 
     /*
      * We've done our bit; remove ourself from the filter chain so there's
@@ -646,7 +661,25 @@ static apr_status_t ap_headers_fixup(request_rec *r)
 
     /* do the fixup */
     if (dirconf->fixup_in->nelts) {
-        do_headers_fixup(r, r->headers_in, dirconf->fixup_in);
+        do_headers_fixup(r, r->headers_in, dirconf->fixup_in, 0);
+    }
+
+    return DECLINED;
+}
+static apr_status_t ap_headers_early(request_rec *r)
+{
+    headers_conf *dirconf = ap_get_module_config(r->per_dir_config,
+                                                 &headers_module);
+
+    /* do the fixup */
+    if (dirconf->fixup_in->nelts) {
+        do_headers_fixup(r, r->headers_in, dirconf->fixup_in, 1);
+    }
+    if (dirconf->fixup_err->nelts) {
+        do_headers_fixup(r, r->err_headers_out, dirconf->fixup_err, 1);
+    }
+    if (dirconf->fixup_out->nelts) {
+        do_headers_fixup(r, r->headers_out, dirconf->fixup_out, 1);
     }
 
     return DECLINED;
@@ -699,6 +732,7 @@ static void register_hooks(apr_pool_t *p)
     ap_hook_insert_error_filter(ap_headers_insert_error_filter,
                                 NULL, NULL, APR_HOOK_LAST);
     ap_hook_fixups(ap_headers_fixup, NULL, NULL, APR_HOOK_LAST);
+    ap_hook_post_read_request(ap_headers_early, NULL, NULL, APR_HOOK_FIRST);
 }
 
 module AP_MODULE_DECLARE_DATA headers_module =