-/* 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.
* 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
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
*/
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;
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 == '{') {
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;
"'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";
}
/* 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, ':'))) {
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);
}
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;
"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);
}
/*
- * 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,
"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
/* 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;
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}
};
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 =