Return-Path: Delivered-To: apmail-httpd-dev-archive@www.apache.org Received: (qmail 32321 invoked from network); 23 May 2006 15:10:51 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (209.237.227.199) by minotaur.apache.org with SMTP; 23 May 2006 15:10:51 -0000 Received: (qmail 82867 invoked by uid 500); 23 May 2006 15:10:46 -0000 Delivered-To: apmail-httpd-dev-archive@httpd.apache.org Received: (qmail 82798 invoked by uid 500); 23 May 2006 15:10:45 -0000 Mailing-List: contact dev-help@httpd.apache.org; run by ezmlm Precedence: bulk Reply-To: dev@httpd.apache.org list-help: list-unsubscribe: List-Post: List-Id: Delivered-To: mailing list dev@httpd.apache.org Received: (qmail 82787 invoked by uid 99); 23 May 2006 15:10:45 -0000 Received: from asf.osuosl.org (HELO asf.osuosl.org) (140.211.166.49) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 23 May 2006 08:10:45 -0700 X-ASF-Spam-Status: No, hits=1.4 required=10.0 tests=DNS_FROM_RFC_POST X-Spam-Check-By: apache.org Received-SPF: pass (asf.osuosl.org: local policy) Received: from [64.236.25.90] (HELO cnnimail33.turner.com) (64.236.25.90) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 23 May 2006 08:10:43 -0700 Received: from turner.com (10.165.244.17) by cnnimail33.turner.com with ESMTP; 23 May 2006 11:10:10 -0400 Received: from [10.188.50.115] (dcs-vaio.turner.com [10.188.50.115]) by web.turner.com (Postfix) with ESMTP id 8B733C12BA for ; Tue, 23 May 2006 11:10:04 -0400 (EDT) Message-ID: <447325C8.8000502@turner.com> Date: Tue, 23 May 2006 11:10:00 -0400 From: Brian Akins User-Agent: Thunderbird 1.5.0.2 (Macintosh/20060308) MIME-Version: 1.0 To: dev@httpd.apache.org Subject: [PATCH] setenvif filter Content-Type: multipart/mixed; boundary="------------020607040403000102070508" X-Virus-Checked: Checked by ClamAV on apache.org X-Spam-Rating: minotaur.apache.org 1.6.2 0/1000/N This is a multi-part message in MIME format. --------------020607040403000102070508 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit This patch add a filter to mod_setenvif that lets it match against response headers as well as request headers. It is probably a horrible implementation, but submitted to encourage others to think of the idea. This changes the configuration to allow another optional field to designate the "mode" of the match (default is request) SetEnvIf response Content-Type text/* is_text=1 will match against the response header content-type. The main purpose of this is to allow configurations such as: AddOutputFilterByType DEFLATE text/html BrowserMatch ^Mozilla/4\.0[678] no-gzip SetEnvIf response Content-Type text/html user-agent-vary=1 Header append Vary User-Agent env=user-agent-vary With this patch, the correct vary headers are added in a reverse proxy situation. most of the code was adapted from mod_headers. Thoughts? -- Brian Akins Lead Systems Engineer CNN Internet Technologies --------------020607040403000102070508 Content-Type: text/plain; x-mac-type="0"; x-mac-creator="0"; name="setenvif.patch" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="setenvif.patch" --- mod_setenvif.c.bak 2006-05-23 10:08:56.000000000 -0400 +++ mod_setenvif.c 2006-05-23 11:03:06.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, @@ -113,12 +115,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 +254,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 +309,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; @@ -400,15 +406,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 +444,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 +470,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 +480,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 +501,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 @@ -505,7 +546,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 +558,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); } @@ -542,7 +583,10 @@ 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", b->name); + for (j = 0; j < arr->nelts; ++j) { if (*(elts[j].val) == '!') { apr_table_unset(r->subprocess_env, elts[j].key); @@ -568,10 +612,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 = --------------020607040403000102070508--