Here's a newer version with some special handling for content-type. In
response headers, we need to match r->content_type rather than the header.
------------------------------------------------------------------------
--- mod_setenvif.c.bak 2006-05-23 10:08:56.000000000 -0400
+++ mod_setenvif.c 2006-05-23 16:55:50.000000000 -0400
@@ -94,6 +94,8 @@
#include "http_log.h"
#include "http_protocol.h"
+#define SETENVIF_REQUEST 1
+#define SETENVIF_RESPONSE 2
enum special {
SPECIAL_NOT,
@@ -102,7 +104,8 @@
SPECIAL_REQUEST_URI,
SPECIAL_REQUEST_METHOD,
SPECIAL_REQUEST_PROTOCOL,
- SPECIAL_SERVER_ADDR
+ SPECIAL_SERVER_ADDR,
+ SPECIAL_CONTENT_TYPE
};
typedef struct {
char *name; /* header name */
@@ -113,12 +116,15 @@
apr_table_t *features; /* env vars to set (or unset) */
enum special special_type; /* is it a "special" header ? */
int icase; /* ignoring case? */
+ int mode; /*request or response*/
} sei_entry;
typedef struct {
apr_array_header_t *conditionals;
} sei_cfg_rec;
+static ap_filter_rec_t *setenvif_output_filter_handle = NULL;
+
module AP_MODULE_DECLARE_DATA setenvif_module;
/*
@@ -249,7 +255,7 @@
}
static const char *add_setenvif_core(cmd_parms *cmd, void *mconfig,
- char *fname, const char *args)
+ char *fname, int mode, const char *args)
{
char *regex;
const char *simple_pattern;
@@ -304,6 +310,7 @@
/* no match, create a new entry */
new = apr_array_push(sconf->conditionals);
+ new->mode = mode;
new->name = fname;
new->regex = regex;
new->icase = icase;
@@ -345,6 +352,9 @@
else if (!strcasecmp(fname, "server_addr")) {
new->special_type = SPECIAL_SERVER_ADDR;
}
+ else if ((SETENVIF_RESPONSE == mode) && !strcasecmp(fname,
"content-type")) {
+ new->special_type = SPECIAL_CONTENT_TYPE;
+ }
else {
new->special_type = SPECIAL_NOT;
/* Handle fname as a regular expression.
@@ -400,15 +410,35 @@
static const char *add_setenvif(cmd_parms *cmd, void *mconfig,
const char *args)
{
- char *fname;
-
+ char *fname = NULL;
+ int mode = SETENVIF_REQUEST;
+
/* get header name */
fname = ap_getword_conf(cmd->pool, &args);
- if (!*fname) {
+ /*is this a mode?*/
+
+ if (!fname) {
+ return apr_pstrcat(cmd->pool, "Missing header-field name for ",
+ cmd->cmd->name, NULL);
+ }
+
+ if(!strcasecmp(fname, "request")) {
+ mode = SETENVIF_REQUEST;
+ fname = NULL;
+ } else if (!strcasecmp(fname, "response")) {
+ mode = SETENVIF_RESPONSE;
+ fname = NULL;
+ }
+
+ if(!fname) {
+ fname = ap_getword_conf(cmd->pool, &args);
+ }
+
+ if (!fname) {
return apr_pstrcat(cmd->pool, "Missing header-field name for ",
cmd->cmd->name, NULL);
}
- return add_setenvif_core(cmd, mconfig, fname, args);
+ return add_setenvif_core(cmd, mconfig, fname, mode, args);
}
/*
@@ -418,7 +448,7 @@
*/
static const char *add_browser(cmd_parms *cmd, void *mconfig, const char *args)
{
- return add_setenvif_core(cmd, mconfig, "User-Agent", args);
+ return add_setenvif_core(cmd, mconfig, "User-Agent", SETENVIF_REQUEST,
args);
}
static const command_rec setenvif_module_cmds[] =
@@ -444,7 +474,7 @@
* signal which call it is by having the earlier one pass a flag to the
* later one.
*/
-static int match_headers(request_rec *r)
+static int match_headers(request_rec *r, int mode)
{
sei_cfg_rec *sconf;
sei_entry *entries;
@@ -454,7 +484,14 @@
int i, j;
char *last_name;
ap_regmatch_t regm[AP_MAX_REG_MATCH];
-
+ apr_table_t *headers;
+
+ if(SETENVIF_RESPONSE == mode) {
+ headers = r->headers_out;
+ } else {
+ headers = r->headers_in;
+ }
+
if (!ap_get_module_config(r->request_config, &setenvif_module)) {
ap_set_module_config(r->request_config, &setenvif_module,
SEI_MAGIC_HEIRLOOM);
@@ -468,9 +505,17 @@
entries = (sei_entry *) sconf->conditionals->elts;
last_name = NULL;
val = NULL;
+
for (i = 0; i < sconf->conditionals->nelts; ++i) {
sei_entry *b = &entries[i];
-
+
+ if(b->mode != mode) {
+ continue;
+ }
+
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+ "setenvif: trying %s", b->name);
+
/* Optimize the case where a bunch of directives in a row use the
* same header. Remember we don't need to strcmp the two header
* names because we made sure the pointers were equal during
@@ -498,6 +543,10 @@
case SPECIAL_REQUEST_PROTOCOL:
val = r->protocol;
break;
+ /*we only set this in config in !RESPONSE*/
+ case SPECIAL_CONTENT_TYPE:
+ val = r->content_type;
+ break;
case SPECIAL_NOT:
if (b->pnamereg) {
/* Matching headers_in against a regex. Iterate through
@@ -505,7 +554,7 @@
* headers.
*/
const apr_array_header_t
- *arr = apr_table_elts(r->headers_in);
+ *arr = apr_table_elts(headers);
elts = (const apr_table_entry_t *) arr->elts;
val = NULL;
@@ -517,7 +566,7 @@
}
else {
/* Not matching against a regex */
- val = apr_table_get(r->headers_in, b->name);
+ val = apr_table_get(headers, b->name);
if (val == NULL) {
val = apr_table_get(r->subprocess_env, b->name);
}
@@ -537,12 +586,19 @@
val_len = 0;
}
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+ "setenvif: val = %s", val);
+
+
if ((b->pattern && apr_strmatch(b->pattern, val, val_len)) ||
(!b->pattern && !ap_regexec(b->preg, val, AP_MAX_REG_MATCH, regm,
0))) {
const apr_array_header_t *arr = apr_table_elts(b->features);
elts = (const apr_table_entry_t *) arr->elts;
-
+
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+ "setenvif: matched: %s, %s", b->name, val);
+
for (j = 0; j < arr->nelts; ++j) {
if (*(elts[j].val) == '!') {
apr_table_unset(r->subprocess_env, elts[j].key);
@@ -568,10 +624,57 @@
return DECLINED;
}
+static int setenvif_request(request_rec *r)
+{
+ return match_headers(r, SETENVIF_REQUEST);
+
+}
+static apr_status_t setenvif_output_filter(ap_filter_t *f,
+ apr_bucket_brigade *in)
+{
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, f->r->server,
+ "setenvif: setenvif_output_filter()");
+
+ ap_set_module_config(f->r->request_config, &setenvif_module,
+ NULL);
+ match_headers(f->r, SETENVIF_RESPONSE);
+ /*have to run twice, once to get server, then dir*/
+ match_headers(f->r, SETENVIF_RESPONSE);
+ /* remove ourselves from the filter chain */
+ ap_remove_output_filter(f);
+
+ /* send the data up the stack */
+ return ap_pass_brigade(f->next,in);
+}
+
+static void setenvif_insert_output_filter(request_rec *r)
+{
+ sei_cfg_rec *sconf;
+ int count = 0;
+
+ /*only add it if we have some*/
+ sconf = (sei_cfg_rec *) ap_get_module_config(r->server->module_config,
+ &setenvif_module);
+ count += sconf->conditionals->nelts;
+
+ sconf = (sei_cfg_rec *) ap_get_module_config(r->per_dir_config,
+ &setenvif_module);
+ count += sconf->conditionals->nelts;
+
+ if(count) {
+ ap_add_output_filter_handle(setenvif_output_filter_handle, NULL, r,
+ r->connection);
+ }
+}
+
static void register_hooks(apr_pool_t *p)
{
- ap_hook_header_parser(match_headers, NULL, NULL, APR_HOOK_MIDDLE);
- ap_hook_post_read_request(match_headers, NULL, NULL, APR_HOOK_MIDDLE);
+ ap_hook_header_parser(setenvif_request, NULL, NULL, APR_HOOK_MIDDLE);
+ ap_hook_post_read_request(setenvif_request, NULL, NULL, APR_HOOK_MIDDLE);
+ setenvif_output_filter_handle = ap_register_output_filter("SETENVIF_OUT",
+ setenvif_output_filter,
+ NULL, AP_FTYPE_CONTENT_SET);
+ ap_hook_insert_filter(setenvif_insert_output_filter, NULL, NULL, APR_HOOK_LAST);
}
module AP_MODULE_DECLARE_DATA setenvif_module =