-/* 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.
hdr_echo = 'e' /* echo headers from request to response */
} hdr_actions;
-typedef enum {
- hdr_in = 0, /* RequestHeader */
- hdr_out = 1, /* Header */
- hdr_err = 2 /* ErrorHeader */
-} hdr_inout;
+/*
+ * magic cmd->info values
+ */
+static char hdr_in = '0'; /* RequestHeader */
+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
*/
typedef struct {
hdr_actions action;
- char *header;
+ 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;
/*
* Config routines
*/
-static void *create_headers_config(apr_pool_t *p, server_rec *s)
+
+static void *create_headers_dir_config(apr_pool_t *p, char *d)
{
headers_conf *conf = apr_pcalloc(p, sizeof(*conf));
return conf;
}
-static void *create_headers_dir_config(apr_pool_t *p, char *d)
-{
- return create_headers_config(p, NULL);
-}
-
static void *merge_headers_config(apr_pool_t *p, void *basev, void *overridesv)
{
headers_conf *newconf = apr_pcalloc(p, sizeof(*newconf));
headers_conf *base = basev;
headers_conf *overrides = overridesv;
- newconf->fixup_in = apr_array_append(p, base->fixup_in, overrides->fixup_in);
- newconf->fixup_out = apr_array_append(p, base->fixup_out, overrides->fixup_out);
+ newconf->fixup_in = apr_array_append(p, base->fixup_in,
+ overrides->fixup_in);
+ newconf->fixup_out = apr_array_append(p, base->fixup_out,
+ overrides->fixup_out);
newconf->fixup_err = apr_array_append(p, base->fixup_err,
overrides->fixup_err);
*d++ = '\n';
s++;
break;
- case 't':
+ case 't':
*d++ = '\t';
s++;
break;
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;
{
char *res;
- /* No string to parse with unset and copy commands */
+ /* No string to parse with unset and echo commands */
if (hdr->action == hdr_unset ||
hdr->action == hdr_echo) {
return NULL;
}
/* 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* envclause)
+static APR_INLINE const char *header_inout_cmd(cmd_parms *cmd,
+ void *indirconf,
+ const char *action,
+ const char *hdr,
+ const char *value,
+ const char* envclause)
{
headers_conf *dirconf = indirconf;
const char *condition_var = NULL;
- char *colon;
- char *hdr = apr_pstrdup(cmd->pool, inhdr);
+ const char *colon;
header_entry *new;
- server_rec *s = cmd->server;
- headers_conf *serverconf = ap_get_module_config(s->module_config,
- &headers_module);
- apr_array_header_t *fixup = dirconf->fixup_out;
-
- switch (inout) {
- case hdr_in:
- fixup = (cmd->path != NULL)
- ? dirconf->fixup_in
- : serverconf->fixup_in;
- break;
- case hdr_out:
- fixup = (cmd->path != NULL)
- ? dirconf->fixup_out
- : serverconf->fixup_out;
- break;
- case hdr_err:
- fixup = (cmd->path != NULL)
- ? dirconf->fixup_err
- : serverconf->fixup_err;
- break;
- }
+
+ apr_array_header_t *fixup = (cmd->info == &hdr_in)
+ ? dirconf->fixup_in : (cmd->info == &hdr_err)
+ ? dirconf->fixup_err
+ : dirconf->fixup_out;
new = (header_entry *) apr_array_push(fixup);
else if (!strcasecmp(action, "echo"))
new->action = hdr_echo;
else
- return "first argument must be add, set, append, unset or echo.";
+ return "first argument must be 'add', 'set', 'append', 'unset' or "
+ "'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;
- if (value)
- return "Header echo takes two arguments";
- else if (inout != hdr_out)
- return "Header echo only valid on Header directive";
+ ap_regex_t *regex;
+
+ 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";
}
new->regex = regex;
}
else if (!value)
- return "header requires three arguments";
+ return "Header requires three arguments";
/* Handle the envclause on Header */
if (envclause != NULL) {
- if (inout == hdr_in) {
- return "error: envclause (env=...) only valid on "
- "Header and ErrorHeader directives";
- }
- 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 = apr_pstrdup(cmd->pool, &envclause[4]);
}
- if ((colon = strchr(hdr, ':')))
- *colon = '\0';
+ if ((colon = ap_strchr_c(hdr, ':'))) {
+ hdr = apr_pstrmemdup(cmd->pool, hdr, colon-hdr);
+ }
new->header = hdr;
new->condition_var = condition_var;
return parse_format_string(cmd->pool, new, value);
}
-/* Handle Header directive */
+/* Handle all (xxx)Header directives */
static const char *header_cmd(cmd_parms *cmd, void *indirconf,
const char *args)
{
- const char *s;
const char *action;
const char *hdr;
const char *val;
const char *envclause;
- hdr_inout outbl;
- 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;
- outbl = (cmd->info == NULL) ? hdr_out : hdr_err;
+ 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;
- return header_inout_cmd(outbl, cmd, indirconf, action, hdr, val, envclause);
-}
+ if (*args) {
+ return apr_pstrcat(cmd->pool, cmd->cmd->name,
+ " has too many arguments", NULL);
+ }
-/* handle RequestHeader directive */
-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, NULL);
+ return header_inout_cmd(cmd, indirconf, action, hdr, val, envclause);
}
/*
else
str = apr_pstrcat(r->pool, str, s, NULL);
}
- return str;
+ return str ? str : "";
}
static int echo_header(echo_do *v, const char *key, const char *val)
return 1;
}
-static void do_headers_fixup(request_rec *r, hdr_inout inout,
- apr_array_header_t *fixup)
+static void do_headers_fixup(request_rec *r, apr_table_t *headers,
+ apr_array_header_t *fixup, int early)
{
int i;
- apr_table_t *headers = r->headers_out;
-
- switch (inout) {
- case hdr_in:
- headers = r->headers_in;
- break;
- case hdr_out:
- headers = r->headers_out;
- break;
- case hdr_err:
- headers = r->err_headers_out;
- break;
- }
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;
static void ap_headers_insert_output_filter(request_rec *r)
{
- headers_conf *serverconf = ap_get_module_config(r->server->module_config,
- &headers_module);
headers_conf *dirconf = ap_get_module_config(r->per_dir_config,
&headers_module);
- if (serverconf->fixup_out->nelts || dirconf->fixup_out->nelts
- || serverconf->fixup_err->nelts || dirconf->fixup_err->nelts) {
+ if (dirconf->fixup_out->nelts || dirconf->fixup_err->nelts) {
ap_add_output_filter("FIXUP_HEADERS_OUT", NULL, r, r->connection);
}
}
*/
static void ap_headers_insert_error_filter(request_rec *r)
{
- headers_conf *serverconf = ap_get_module_config(r->server->module_config,
- &headers_module);
headers_conf *dirconf = ap_get_module_config(r->per_dir_config,
&headers_module);
- if (serverconf->fixup_err->nelts || dirconf->fixup_err->nelts) {
+ if (dirconf->fixup_err->nelts) {
ap_add_output_filter("FIXUP_HEADERS_ERR", NULL, r, r->connection);
}
}
static apr_status_t ap_headers_output_filter(ap_filter_t *f,
apr_bucket_brigade *in)
{
- headers_conf *serverconf = ap_get_module_config(f->r->server->module_config,
- &headers_module);
headers_conf *dirconf = ap_get_module_config(f->r->per_dir_config,
&headers_module);
"headers: ap_headers_output_filter()");
/* do the fixup */
- do_headers_fixup(f->r, hdr_err, serverconf->fixup_err);
- do_headers_fixup(f->r, hdr_out, serverconf->fixup_out);
- do_headers_fixup(f->r, hdr_err, dirconf->fixup_err);
- do_headers_fixup(f->r, hdr_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,
apr_bucket_brigade *in)
{
- headers_conf *serverconf;
headers_conf *dirconf;
- serverconf = ap_get_module_config(f->r->server->module_config,
- &headers_module);
dirconf = ap_get_module_config(f->r->per_dir_config,
&headers_module);
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, f->r->server,
"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, hdr_err, serverconf->fixup_err);
- do_headers_fixup(f->r, hdr_err, 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
static apr_status_t ap_headers_fixup(request_rec *r)
{
- headers_conf *serverconf = ap_get_module_config(r->server->module_config,
- &headers_module);
headers_conf *dirconf = ap_get_module_config(r->per_dir_config,
&headers_module);
/* do the fixup */
- if (serverconf->fixup_in->nelts || dirconf->fixup_in->nelts) {
- do_headers_fixup(r, hdr_in, serverconf->fixup_in);
- do_headers_fixup(r, hdr_in, dirconf->fixup_in);
+ if (dirconf->fixup_in->nelts) {
+ 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, NULL, OR_FILEINFO,
- "an action, header and value followed by optional env clause"),
- AP_INIT_RAW_ARGS("ErrorHeader", header_cmd, "", OR_FILEINFO,
- "an action, header and value "
+ AP_INIT_RAW_ARGS("Header", header_cmd, &hdr_out, OR_FILEINFO,
+ "an optional condition, 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"),
+ AP_INIT_RAW_ARGS("RequestHeader", header_cmd, &hdr_in, OR_FILEINFO,
+ "an action, header and value followed by optional env "
+ "clause"),
{NULL}
};
-static void register_format_tag_handler(apr_pool_t *p, char *tag, void *tag_handler, int def)
+static void register_format_tag_handler(const char *tag,
+ const void *tag_handler)
{
- const void *h = apr_palloc(p, sizeof(h));
- h = tag_handler;
- apr_hash_set(format_tag_hash, tag, 1, h);
+ apr_hash_set(format_tag_hash, tag, 1, tag_handler);
}
+
static int header_pre_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp)
{
format_tag_hash = apr_hash_make(p);
- register_format_tag_handler(p, "D", (void*) header_request_duration, 0);
- register_format_tag_handler(p, "t", (void*) header_request_time, 0);
- register_format_tag_handler(p, "e", (void*) header_request_env_var, 0);
- register_format_tag_handler(p, "s", (void*) header_request_ssl_var, 0);
+ register_format_tag_handler("D", (const void *)header_request_duration);
+ register_format_tag_handler("t", (const void *)header_request_time);
+ register_format_tag_handler("e", (const void *)header_request_env_var);
+ register_format_tag_handler("s", (const void *)header_request_ssl_var);
+
return OK;
}
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 =
STANDARD20_MODULE_STUFF,
create_headers_dir_config, /* dir config creater */
merge_headers_config, /* dir merger --- default is to override */
- create_headers_config, /* server config */
- merge_headers_config, /* merge server configs */
+ NULL, /* server config */
+ NULL, /* merge server configs */
headers_cmds, /* command apr_table_t */
- register_hooks /* register hooks */
+ register_hooks /* register hooks */
};