From ec0051094afadc3d7e822f75fc255e15250a14ec Mon Sep 17 00:00:00 2001 From: Nick Kew Date: Thu, 22 Jul 2010 21:54:39 +0000 Subject: [PATCH] Move AddOutputFilterByType implementation from core to mod_filter. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@966869 13f79535-47bb-0310-9956-ffa450edef68 --- CHANGES | 5 ++ include/http_core.h | 2 - modules/filters/mod_filter.c | 45 ++++++++++- modules/http/http_protocol.c | 7 -- server/core.c | 153 ----------------------------------- 5 files changed, 49 insertions(+), 163 deletions(-) diff --git a/CHANGES b/CHANGES index 96d99b42d5..66a3d15b2f 100644 --- a/CHANGES +++ b/CHANGES @@ -46,6 +46,11 @@ Changes with Apache 2.3.7 *) Update SSL cipher suite and add example for SSLHonorCipherOrder. [Lars Eilebrecht, Rainer Jung] + *) move AddOutputFilterByType from core to mod_filter. This should + fix nasty side-effects that happen when content_type is set + more than once in processing a request, and make it fully + compatible with dynamic and proxied contents. [Nick Kew] + Changes with Apache 2.3.6 *) SECURITY: CVE-2009-3555 (cve.mitre.org) diff --git a/include/http_core.h b/include/http_core.h index ed334ba503..82a0a4687c 100644 --- a/include/http_core.h +++ b/include/http_core.h @@ -507,8 +507,6 @@ typedef struct { const char *input_filters; /* forced with SetInputFilters */ int accept_path_info; /* forced with AcceptPathInfo */ - apr_hash_t *ct_output_filters; /* added with AddOutputFilterByType */ - /* * What attributes/data should be included in ETag generation? */ diff --git a/modules/filters/mod_filter.c b/modules/filters/mod_filter.c index dd2c979516..dc48a80b5f 100644 --- a/modules/filters/mod_filter.c +++ b/modules/filters/mod_filter.c @@ -436,7 +436,6 @@ static const char *filter_provider(cmd_parms *cmd, void *CFG, return NULL; } - static const char *filter_chain(cmd_parms *cmd, void *CFG, const char *arg) { mod_filter_chain *p; @@ -511,6 +510,48 @@ static const char *filter_chain(cmd_parms *cmd, void *CFG, const char *arg) return NULL; } +static const char *filter_bytype(cmd_parms *cmd, void *CFG, + const char *pname, const char *type) +{ + char *etype; + char *p; + const char *rv; + const char *fname; + const char *expr; + int seen_name = 0; + mod_filter_cfg *cfg = CFG; + + /* construct fname from name */ + fname = apr_pstrcat(cmd->pool, "BYTYPE:", pname, NULL); + + /* check whether this is already registered, in which case + * it's already in the filter chain + */ + if (apr_hash_get(cfg->live_filters, fname, APR_HASH_KEY_STRING)) { + seen_name = 1; + } + + /* build expression: "$content-type = /^type/" + * Need to escape slashes in content-type + */ + p = etype = apr_palloc(cmd->temp_pool, 2*strlen(type)+1); + do { + if (*type == '/') { + *p++ = '\\'; + } + *p++ = *type++; + } while (*type); + *p = 0; + expr = apr_psprintf(cmd->temp_pool, "$content-type = /^%s/", etype); + + rv = filter_provider(cmd, CFG, fname, pname, expr); + + /* If it's the first time through, add to filterchain */ + if (rv == NULL && !seen_name) { + rv = filter_chain(cmd, CFG, fname); + } + return rv; +} static const char *filter_debug(cmd_parms *cmd, void *CFG, const char *fname, const char *level) @@ -642,6 +683,8 @@ static const command_rec filter_cmds[] = { "list of filter names with optional [+-=!@]"), AP_INIT_TAKE2("FilterTrace", filter_debug, NULL, RSRC_CONF | ACCESS_CONF, "filter-name debug-level"), + AP_INIT_ITERATE2("AddOutputFilterByType", filter_bytype, NULL, OR_FILEINFO, + "DEPRECATED: output filter name followed by one or more content-types"), #ifndef NO_PROTOCOL AP_INIT_TAKE23("FilterProtocol", filter_protocol, NULL, OR_OPTIONS, "filter-name [provider-name] protocol-args"), diff --git a/modules/http/http_protocol.c b/modules/http/http_protocol.c index 54814a92d9..f8010b294f 100644 --- a/modules/http/http_protocol.c +++ b/modules/http/http_protocol.c @@ -846,13 +846,6 @@ AP_DECLARE(void) ap_set_content_type(request_rec *r, const char *ct) } else if (!r->content_type || strcmp(r->content_type, ct)) { r->content_type = ct; - - /* Insert filters requested by the AddOutputFiltersByType - * configuration directive. Content-type filters must be - * inserted after the content handlers have run because - * only then, do we reliably know the content-type. - */ - ap_add_output_filters_by_type(r); } } diff --git a/server/core.c b/server/core.c index ce8e4cd4c9..98a183bf2f 100644 --- a/server/core.c +++ b/server/core.c @@ -161,60 +161,6 @@ static void *create_core_dir_config(apr_pool_t *a, char *dir) return (void *)conf; } -/* - * Overlay one hash table of ct_output_filters onto another - */ -static void *merge_ct_filters(apr_pool_t *p, - const void *key, - apr_ssize_t klen, - const void *overlay_val, - const void *base_val, - const void *data) -{ - ap_filter_rec_t *cur; - const ap_filter_rec_t *overlay_info = (const ap_filter_rec_t *)overlay_val; - const ap_filter_rec_t *base_info = (const ap_filter_rec_t *)base_val; - - cur = NULL; - - while (overlay_info) { - ap_filter_rec_t *new; - - new = apr_pcalloc(p, sizeof(ap_filter_rec_t)); - new->name = apr_pstrdup(p, overlay_info->name); - new->next = cur; - cur = new; - overlay_info = overlay_info->next; - } - - while (base_info) { - ap_filter_rec_t *f; - int found = 0; - - /* We can't have dups. */ - f = cur; - while (f) { - if (!strcasecmp(base_info->name, f->name)) { - found = 1; - break; - } - - f = f->next; - } - - if (!found) { - f = apr_pcalloc(p, sizeof(ap_filter_rec_t)); - f->name = apr_pstrdup(p, base_info->name); - f->next = cur; - cur = f; - } - - base_info = base_info->next; - } - - return cur; -} - static void *merge_core_dir_configs(apr_pool_t *a, void *basev, void *newv) { core_dir_config *base = (core_dir_config *)basev; @@ -373,21 +319,6 @@ static void *merge_core_dir_configs(apr_pool_t *a, void *basev, void *newv) conf->input_filters = new->input_filters; } - if (conf->ct_output_filters && new->ct_output_filters) { - conf->ct_output_filters = apr_hash_merge(a, - new->ct_output_filters, - conf->ct_output_filters, - merge_ct_filters, - NULL); - } - else if (new->ct_output_filters) { - conf->ct_output_filters = apr_hash_copy(a, new->ct_output_filters); - } - else if (conf->ct_output_filters) { - /* That memcpy above isn't enough. */ - conf->ct_output_filters = apr_hash_copy(a, base->ct_output_filters); - } - /* * Now merge the setting of the FileETag directive. */ @@ -3154,87 +3085,6 @@ AP_DECLARE(int) ap_is_recursion_limit_exceeded(const request_rec *r) return 0; } -static const char *add_ct_output_filters(cmd_parms *cmd, void *conf_, - const char *arg, const char *arg2) -{ - core_dir_config *conf = conf_; - ap_filter_rec_t *old, *new = NULL; - const char *filter_name; - - if (!conf->ct_output_filters) { - conf->ct_output_filters = apr_hash_make(cmd->pool); - old = NULL; - } - else { - old = (ap_filter_rec_t*) apr_hash_get(conf->ct_output_filters, arg2, - APR_HASH_KEY_STRING); - /* find last entry */ - if (old) { - while (old->next) { - old = old->next; - } - } - } - - while (*arg && - (filter_name = ap_getword(cmd->pool, &arg, ';')) && - strcmp(filter_name, "")) { - new = apr_pcalloc(cmd->pool, sizeof(ap_filter_rec_t)); - new->name = filter_name; - - /* We found something, so let's append it. */ - if (old) { - old->next = new; - } - else { - apr_hash_set(conf->ct_output_filters, arg2, - APR_HASH_KEY_STRING, new); - } - old = new; - } - - if (!new) { - return "invalid filter name"; - } - - return NULL; -} -/* - * Insert filters requested by the AddOutputFilterByType - * configuration directive. We cannot add filters based - * on content-type until after the handler has started - * to run. Only then do we reliably know the content-type. - */ -void ap_add_output_filters_by_type(request_rec *r) -{ - core_dir_config *conf; - const char *ctype; - - conf = (core_dir_config *)ap_get_module_config(r->per_dir_config, - &core_module); - - /* We can't do anything with no content-type or if we don't have a - * filter configured. - */ - if (!r->content_type || !conf->ct_output_filters) { - return; - } - - /* remove c-t decoration */ - ctype = ap_field_noparam(r->pool, r->content_type); - if (ctype) { - ap_filter_rec_t *ct_filter; - ct_filter = apr_hash_get(conf->ct_output_filters, ctype, - APR_HASH_KEY_STRING); - while (ct_filter) { - ap_add_output_filter(ct_filter->name, NULL, r, r->connection); - ct_filter = ct_filter->next; - } - } - - return; -} - static const char *set_trace_enable(cmd_parms *cmd, void *dummy, const char *arg1) { @@ -3445,9 +3295,6 @@ AP_INIT_TAKE1("SetOutputFilter", ap_set_string_slot, AP_INIT_TAKE1("SetInputFilter", ap_set_string_slot, (void *)APR_OFFSETOF(core_dir_config, input_filters), OR_FILEINFO, "filter (or ; delimited list of filters) to be run on the request body"), -AP_INIT_ITERATE2("AddOutputFilterByType", add_ct_output_filters, - (void *)APR_OFFSETOF(core_dir_config, ct_output_filters), OR_FILEINFO, - "output filter name followed by one or more content-types"), AP_INIT_FLAG("AllowEncodedSlashes", set_allow2f, NULL, RSRC_CONF, "Allow URLs containing '/' encoded as '%2F'"), -- 2.50.1