]> granicus.if.org Git - apache/blobdiff - modules/metadata/mod_headers.c
Move the POSIX reg* implementations into the ap_* namespace;
[apache] / modules / metadata / mod_headers.c
index bcdb436ead94df7499c02c82aa2471172e158c3f..82f29938bf37ebf4919e896ed3c5444cc9f358bb 100644 (file)
@@ -1,4 +1,5 @@
-/* Copyright 1999-2004 The Apache Software Foundation
+/* Copyright 1999-2005 The Apache Software Foundation or its licensors, as
+ * applicable.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -95,8 +96,8 @@ typedef enum {
  * magic cmd->info values
  */
 static char hdr_in  = '0';  /* RequestHeader */
-static char hdr_out = '1';  /* Header */
-static char hdr_err = '2';  /* ErrorHeader */
+static char hdr_out = '1';  /* Header onsuccess */
+static char hdr_err = '2';  /* Header always */
 
 /*
  * There is an array of struct format_tag per Header/RequestHeader 
@@ -107,6 +108,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
  */
@@ -114,7 +117,7 @@ typedef struct {
     hdr_actions action;
     const char *header;
     apr_array_header_t *ta;   /* Array of format_tag structs */
-    regex_t *regex;
+    ap_regex_t *regex;
     const char *condition_var;
 } header_entry;
 
@@ -299,6 +302,15 @@ static char *parse_format_tag(apr_pool_t *p, format_tag *tag, const char **sa)
         return parse_misc_string(p, tag, sa);
     }
     s++; /* skip the % */
+
+    /* Pass through %% as % */
+    if (*s == '%') {
+        tag->func = constant_item;
+        tag->arg = "%";
+        *sa = ++s;
+        return NULL;
+    }
+
     tag->arg = '\0';
     /* grab the argument if there is one */
     if (*s == '{') {
@@ -312,8 +324,7 @@ static char *parse_format_tag(apr_pool_t *p, format_tag *tag, const char **sa)
         char dummy[2];
         dummy[0] = s[-1];
         dummy[1] = '\0';
-        return apr_pstrcat(p, "Unrecognized Header or RequestHeader directive %",
-                           dummy, NULL);
+        return apr_pstrcat(p, "Unrecognized header format %", dummy, NULL);
     }
     tag->func = tag_handler;
 
@@ -386,19 +397,29 @@ static APR_INLINE const char *header_inout_cmd(cmd_parms *cmd,
                "'echo'.";
 
     if (new->action == hdr_unset) {
-        if (value)
-            return "header unset takes two arguments";
+        if (value) {
+            if (envclause) {
+                return "header unset takes two arguments";
+            }
+            envclause = value;
+            value = NULL;
+        }
     }
     else if (new->action == hdr_echo) {
-        regex_t *regex;
+        ap_regex_t *regex;
 
-        if (value)
-            return "Header echo takes two arguments";
-        else if (cmd->info != &hdr_out && cmd->info != &hdr_err)
-            return "Header echo only valid on Header and ErrorHeader "
+        if (value) {
+            if (envclause) {
+                return "Header echo takes two arguments";
+            }
+            envclause = value;
+            value = NULL;
+        }
+        if (cmd->info != &hdr_out && cmd->info != &hdr_err)
+            return "Header echo only valid on Header "
                    "directives";
         else {
-            regex = ap_pregcomp(cmd->pool, hdr, REG_EXTENDED | REG_NOSUB);
+            regex = ap_pregcomp(cmd->pool, hdr, AP_REG_EXTENDED | AP_REG_NOSUB);
             if (regex == NULL) {
                 return "Header echo regex could not be compiled";
             }
@@ -410,15 +431,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, ':'))) {
@@ -441,13 +467,22 @@ static const char *header_cmd(cmd_parms *cmd, void *indirconf,
     const char *envclause;
 
     action = ap_getword_conf(cmd->pool, &args);
+    if (cmd->info == &hdr_out) {
+        if (!strcasecmp(action, "always")) {
+            cmd->info = &hdr_err;
+            action = ap_getword_conf(cmd->pool, &args);
+        }
+        else if (!strcasecmp(action, "onsuccess")) {
+            action = ap_getword_conf(cmd->pool, &args);
+        }
+    }
     hdr = ap_getword_conf(cmd->pool, &args);
     val = *args ? ap_getword_conf(cmd->pool, &args) : NULL;
     envclause = *args ? ap_getword_conf(cmd->pool, &args) : NULL;
 
     if (*args) {
         return apr_pstrcat(cmd->pool, cmd->cmd->name,
-                           " takes only 4 arguments at max.", NULL);
+                           " has too many arguments", NULL);
     }
 
     return header_inout_cmd(cmd, indirconf, action, hdr, val, envclause);
@@ -491,16 +526,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;
@@ -570,8 +613,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);
@@ -581,7 +624,7 @@ static apr_status_t ap_headers_output_filter(ap_filter_t *f,
 }
 
 /*
- * Make sure we propagate any ErrorHeader settings on the error
+ * Make sure we propagate any "Header always" settings on the error
  * path through http_protocol.c.
  */
 static apr_status_t ap_headers_error_filter(ap_filter_t *f,
@@ -595,10 +638,10 @@ static apr_status_t ap_headers_error_filter(ap_filter_t *f,
                  "headers: ap_headers_error_filter()");
 
     /*
-     * Add any header fields defined by ErrorHeader to r->err_headers_out.
+     * 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
@@ -619,7 +662,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;
@@ -628,14 +689,11 @@ static apr_status_t ap_headers_fixup(request_rec *r)
 static const command_rec headers_cmds[] =
 {
     AP_INIT_RAW_ARGS("Header", header_cmd, &hdr_out, OR_FILEINFO,
-                     "an action, header and value followed by optional env "
-                     "clause"),
+                     "an optional condition, an action, header and value "
+                     "followed by optional env clause"),
     AP_INIT_RAW_ARGS("RequestHeader", header_cmd, &hdr_in, OR_FILEINFO,
                      "an action, header and value followed by optional env "
                      "clause"),
-    AP_INIT_RAW_ARGS("ErrorHeader", header_cmd, &hdr_err, OR_FILEINFO,
-                     "an action, header and value followed by optional env "
-                     "clause"),
     {NULL}
 };
 
@@ -675,6 +733,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 =