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.

--
Brian Akins
Lead Systems Engineer
CNN Internet Technologies
--- 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 =

Reply via email to