Any thoughts on this?  This has been brought up a few times.

Good usage example, I need to be able to set a header based upon a reponse's content type. I would like to be able to do:


SetEnvIf response Content-Type text/html is_html=1
Header append Cache-Control private env=is_html


But there seems to be no intuitive way with current code...


Brian Akins wrote:
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 =


--
Brian Akins
Chief Operations Engineer
Turner Digital Media Technologies

Reply via email to