Loading modules/experimental/mod_filter.c +549 −476 Original line number Diff line number Diff line Loading @@ -13,7 +13,7 @@ * limitations under the License. */ /* Originally by Nick Kew <nick@webthing.com> /* Originally contributed by Nick Kew <nick webthing.com> * * At the time of writing, this is designed primarily for use with * httpd 2.2, but is also back-compatible with 2.0. It is likely Loading @@ -23,14 +23,13 @@ * 21/9/04: Unifying data structures with util_filter. * From now on, until and unless we backport, mod_filter requires * util_filter.h from CVS or httpd-2.1+ to compile. * I'll keep a minimal patch for httpd-2.0 users to compile mod_filter * at http://www.apache.org/~niq/ * There's a minimal patch for httpd-2.0 users maintained by Nick * to compile mod_filter at http://www.apache.org/~niq/ */ #include <ctype.h> #include <string.h> /* apache */ #define APR_WANT_STRFUNC #include "apr_want.h" #include "apr_lib.h" #include "apr_strings.h" #include "apr_hash.h" #include "httpd.h" Loading Loading @@ -76,13 +75,16 @@ static const char* filter_bucket_type(apr_bucket* b) { NULL, NULL } }; int i = 0; do { if (b->type == types[i].fn) { return types[i].desc; } } while (types[++i].fn != NULL); return "(error)"; } static void filter_trace(apr_pool_t *pool, int debug, const char *fname, apr_bucket_brigade *bb) { Loading @@ -109,6 +111,7 @@ static int filter_init(ap_filter_t* f) mod_filter_cfg *cfg = ap_get_module_config(f->r->per_dir_config, &filter_module); ap_filter_rec_t *filter = f->frec; f->ctx = apr_pcalloc(f->r->pool, sizeof(harness_ctx)); for (p = filter->providers; p; p = p->next) { if (p->frec->filter_init_func) { Loading @@ -119,8 +122,10 @@ static int filter_init(ap_filter_t* f) } } } return err; } static ap_out_filter_func filter_lookup(request_rec *r, ap_filter_rec_t *filter) { ap_filter_provider_t *provider; Loading Loading @@ -149,18 +154,19 @@ static ap_out_filter_func filter_lookup(request_rec* r, ap_filter_rec_t* filter) str = r->handler; break; } /* treat nulls so we don't have to check every strcmp individually * Not sure if there's anything better to do with them */ if ( str == NULL ) { if ( provider->match_type == DEFINED ) { if ( provider->match.c != NULL ) { if (!str) { if (provider->match_type == DEFINED && provider->match.c) { match = 0; } } } else if ( provider->match.c == NULL ) { else if (!provider->match.c) { match = 0; } else { } else { /* Now we have no nulls, so we can do string and regexp matching */ switch (provider->match_type) { case STRING_MATCH: Loading Loading @@ -200,6 +206,7 @@ static ap_out_filter_func filter_lookup(request_rec* r, ap_filter_rec_t* filter) break; } } if (match != provider->not) { /* condition matches this provider */ #ifndef NO_PROTOCOL Loading @@ -223,6 +230,7 @@ static ap_out_filter_func filter_lookup(request_rec* r, ap_filter_rec_t* filter) /* can't use this provider; try next */ continue; } if (proto_flags & AP_FILTER_PROTO_TRANSFORM) { str = apr_table_get(r->headers_out, "Cache-Control"); if (str) { Loading @@ -233,10 +241,13 @@ static ap_out_filter_func filter_lookup(request_rec* r, ap_filter_rec_t* filter) continue; } } apr_table_addn(r->headers_out, "Warning", apr_psprintf( r->pool, "214 %s Transformation applied", r->hostname) ) ; apr_table_addn(r->headers_out, "Warning", apr_psprintf(r->pool, "214 %s Transformation applied", r->hostname)); } } /* things that are invalidated if the filter transforms content */ if (proto_flags & AP_FILTER_PROTO_CHANGE) { apr_table_unset(r->headers_out, "Content-MD5"); Loading @@ -245,26 +256,30 @@ static ap_out_filter_func filter_lookup(request_rec* r, ap_filter_rec_t* filter) apr_table_unset(r->headers_out, "Content-Length"); } } /* no-cache is for a filter that has different effect per-hit */ if (proto_flags & AP_FILTER_PROTO_NO_CACHE) { apr_table_unset(r->headers_out, "Last-Modified"); apr_table_addn(r->headers_out, "Cache-Control", "no-cache"); } if (proto_flags & AP_FILTER_PROTO_NO_BYTERANGE) { apr_table_unset(r->headers_out, "Accept-Ranges"); } else if ( filter->range ) { } else if (filter->range) { apr_table_setn(r->headers_in, "Range", filter->range); } #endif return provider->frec->filter_func.out_func; } } /* No provider matched */ return NULL; } static apr_status_t filter_harness(ap_filter_t *f, apr_bucket_brigade *bb) { apr_status_t ret; const char *cachecontrol; char *str; Loading @@ -275,19 +290,21 @@ static apr_status_t filter_harness(ap_filter_t* f, apr_bucket_brigade* bb) ap_remove_output_filter(f); return ap_pass_brigade(f->next, bb); } filter_trace(f->c->pool, filter->debug, f->frec->name, bb); /* look up a handler function if we haven't already set it */ if (!ctx->func) { #ifndef NO_PROTOCOL if (f->r->proxyreq) { if (filter->proto_flags & AP_FILTER_PROTO_NO_PROXY) { ap_remove_output_filter(f); return ap_pass_brigade(f->next, bb); } if (filter->proto_flags & AP_FILTER_PROTO_TRANSFORM) { cachecontrol = apr_table_get(f->r->headers_out, "Cache-Control") ; cachecontrol = apr_table_get(f->r->headers_out, "Cache-Control"); if (cachecontrol) { str = apr_pstrdup(f->r->pool, cachecontrol); ap_str_tolower(str); Loading @@ -306,27 +323,29 @@ static apr_status_t filter_harness(ap_filter_t* f, apr_bucket_brigade* bb) } } /* call the content filter with its own context, then restore our context */ /* call the content filter with its own context, then restore our * context */ f->ctx = ctx->fctx; ret = ctx->func(f, bb); ctx->fctx = f->ctx; f->ctx = ctx; return ret; } #ifndef NO_PROTOCOL static const char* filter_protocol(cmd_parms* cmd, void* CFG, const char* fname, const char* pname, const char* proto) static const char *filter_protocol(cmd_parms *cmd, void *CFG, const char *fname, const char *pname, const char *proto) { static const char* sep = " ;, " ; static const char *sep = ";,\t"; char *arg; char *tok = 0; unsigned int flags = 0; mod_filter_cfg *cfg = CFG; ap_filter_provider_t *provider = NULL; ap_filter_rec_t* filter = apr_hash_get(cfg->live_filters, fname, APR_HASH_KEY_STRING) ; ap_filter_rec_t *filter = apr_hash_get(cfg->live_filters, fname, APR_HASH_KEY_STRING); if (!provider) { return "FilterProtocol: No such filter"; Loading @@ -336,49 +355,59 @@ static const char* filter_protocol(cmd_parms* cmd, void* CFG, if (proto == NULL) { proto = pname; pname = NULL; } else { } else { /* Find provider */ for (provider = filter->providers; provider; provider = provider->next) { if ( !strcasecmp(provider->frec->name, pname) ) if (!strcasecmp(provider->frec->name, pname)) { break; } } if (!provider) { return "FilterProtocol: No such provider for this filter"; } } /* Now set flags from our args */ for (arg = apr_strtok(apr_pstrdup(cmd->pool, proto), sep, &tok); arg; arg = apr_strtok(NULL, sep, &tok)) { if (!strcasecmp(arg, "change=yes")) { flags != AP_FILTER_PROTO_CHANGE | AP_FILTER_PROTO_CHANGE_LENGTH; } else if ( !strcasecmp(arg, "change=1:1") ) { } else if (!strcasecmp(arg, "change=1:1")) { flags |= AP_FILTER_PROTO_CHANGE; } else if ( !strcasecmp(arg, "byteranges=no") ) { } else if (!strcasecmp(arg, "byteranges=no")) { flags |= AP_FILTER_PROTO_NO_BYTERANGE; } else if ( !strcasecmp(arg, "proxy=no") ) { } else if (!strcasecmp(arg, "proxy=no")) { flags |= AP_FILTER_PROTO_NO_PROXY; } else if ( !strcasecmp(arg, "proxy=transform") ) { } else if (!strcasecmp(arg, "proxy=transform")) { flags |= AP_FILTER_PROTO_TRANSFORM; } else if ( !strcasecmp(arg, "cache=no") ) { } else if (!strcasecmp(arg, "cache=no")) { flags |= AP_FILTER_PROTO_NO_CACHE; } } if (pname) { provider->frec->proto_flags = flags; } else { } else { filter->proto_flags = flags; } return NULL; } #endif static const char* filter_declare(cmd_parms* cmd, void* CFG, const char* fname, const char* condition, const char* place) static const char *filter_declare(cmd_parms *cmd, void *CFG, const char *fname, const char *condition, const char *place) { const char *eq; char *tmpname = ""; mod_filter_cfg *cfg = (mod_filter_cfg *)CFG; ap_filter_rec_t *filter; Loading @@ -392,27 +421,33 @@ static const char* filter_declare(cmd_parms* cmd, void* CFG, filter->next = NULL; /* determine what this filter will dispatch on */ eq = strchr(condition, '=') ; eq = ap_strchr_c(condition, '='); if (eq) { tmpname = apr_pstrdup(cmd->pool, eq+1); if (!strncasecmp(condition, "env=", 4)) { filter->dispatch = SUBPROCESS_ENV; } else if ( !strncasecmp(condition, "req=", 4) ) { } else if (!strncasecmp(condition, "req=", 4)) { filter->dispatch = REQUEST_HEADERS; } else if ( !strncasecmp(condition, "resp=", 5) ) { } else if (!strncasecmp(condition, "resp=", 5)) { filter->dispatch = RESPONSE_HEADERS; } else { return "FilterCondition: unrecognised dispatch table" ; } } else { else { return "FilterCondition: unrecognized dispatch table"; } } else { if (!strcasecmp(condition, "handler")) { filter->dispatch = HANDLER; } else { } else { filter->dispatch = RESPONSE_HEADERS; } tmpname = apr_pstrdup(cmd->pool, condition); ap_str_tolower(tmpname); } if ( (filter->dispatch == RESPONSE_HEADERS) && !strcmp(tmpname, "content-type")) { filter->dispatch = CONTENT_TYPE; Loading @@ -422,11 +457,14 @@ static const char* filter_declare(cmd_parms* cmd, void* CFG, if (place) { if (!strcasecmp(place, "CONTENT_SET")) { filter->ftype = AP_FTYPE_CONTENT_SET; } else if ( !strcasecmp(place, "PROTOCOL") ) { } else if (!strcasecmp(place, "PROTOCOL")) { filter->ftype = AP_FTYPE_PROTOCOL; } else if ( !strcasecmp(place, "CONNECTION") ) { } else if (!strcasecmp(place, "CONNECTION")) { filter->ftype = AP_FTYPE_CONNECTION; } else if ( !strcasecmp(place, "NETWORK") ) { } else if (!strcasecmp(place, "NETWORK")) { filter->ftype = AP_FTYPE_NETWORK; } } Loading @@ -449,21 +487,28 @@ static const char* filter_provider(cmd_parms* cmd, void* CFG, /* if provider has been registered, we can look it up */ ap_filter_rec_t *provider_frec = ap_get_output_filter_handle(pname); /* or if provider is mod_filter itself, we can also look it up */ if (!provider_frec) { provider_frec = apr_hash_get(cfg->live_filters, pname, APR_HASH_KEY_STRING); } if (!frec) { return apr_psprintf(cmd->pool, "Undeclared smart filter %s", fname); } else if ( !provider_frec ) { } else if (!provider_frec) { return apr_psprintf(cmd->pool, "Unknown filter provider %s", pname); } else { } else { provider = apr_palloc(cmd->pool, sizeof(ap_filter_provider_t)); if (match[0] == '!') { provider->not = 1; ++match; } else { } else { provider->not = 0; } switch (match[0]) { case '<': provider->match_type = INT_LT; Loading Loading @@ -491,7 +536,9 @@ static const char* filter_provider(cmd_parms* cmd, void* CFG, } } provider->match.r = ap_pregcomp(cmd->pool, apr_pstrndup(cmd->pool, match+1, rxend-match-1), flags) ; apr_pstrndup(cmd->pool, match+1, rxend-match-1), flags); break; case '*': provider->match_type = DEFINED; Loading @@ -512,8 +559,10 @@ static const char* filter_provider(cmd_parms* cmd, void* CFG, provider->next = frec->providers; frec->providers = provider; } return NULL; } static const char *filter_chain(cmd_parms *cmd, void *CFG, const char *arg) { mod_filter_chain *p; Loading @@ -527,16 +576,19 @@ static const char* filter_chain(cmd_parms* cmd, void* CFG, const char* arg) if (cfg->chain) { for (q = cfg->chain; q->next; q = q->next); q->next = p; } else { } else { cfg->chain = p; } break; case '@': /* add to start of chain */ p = apr_palloc(cmd->pool, sizeof(mod_filter_chain)); p->fname = arg+1; p->next = cfg->chain; cfg->chain = p; break; case '-': /* remove from chain */ if (cfg->chain) { if (strcasecmp(cfg->chain->fname, arg+1)) { Loading @@ -545,61 +597,56 @@ static const char* filter_chain(cmd_parms* cmd, void* CFG, const char* arg) p->next = p->next->next; } } } else { } else { cfg->chain = cfg->chain->next; } } break; case '!': /* Empty the chain */ cfg->chain = NULL; break; case '=': /* initialise chain with this arg */ p = apr_pcalloc(cmd->pool, sizeof(mod_filter_chain)); p->fname = arg+1; cfg->chain = p; break; default: /* add to end */ p = apr_pcalloc(cmd->pool, sizeof(mod_filter_chain)); p->fname = arg; if (cfg->chain) { for (q = cfg->chain; q->next; q = q->next); q->next = p; } else { } else { cfg->chain = p; } break; } return NULL; } static const char* filter_debug(cmd_parms* cmd, void* CFG, const char* fname, const char* level){ static const char *filter_debug(cmd_parms *cmd, void *CFG, const char *fname, const char *level) { mod_filter_cfg *cfg = CFG; ap_filter_rec_t *frec = apr_hash_get(cfg->live_filters, fname, APR_HASH_KEY_STRING); frec->debug = atoi(level); return NULL; } static const command_rec filter_cmds[] = { AP_INIT_TAKE23("FilterDeclare", filter_declare, NULL, OR_ALL, "filter-name, dispatch-criterion [, filter-type]") , AP_INIT_TAKE3("FilterProvider", filter_provider, NULL, OR_ALL, "filter-name, provider-name, dispatch-match") , AP_INIT_ITERATE("FilterChain", filter_chain, NULL, OR_ALL, "list of filter names with optional [+-=!@]") , AP_INIT_TAKE2("FilterTrace", filter_debug, NULL, OR_ALL, "Debug level") , #ifndef NO_PROTOCOL AP_INIT_TAKE23("FilterProtocol", filter_protocol, NULL, OR_ALL, "filter-name [provider-name] protocol-args") , #endif { NULL } } ; static int filter_insert(request_rec *r) { mod_filter_chain *p; ap_filter_rec_t *filter; mod_filter_cfg* cfg = ap_get_module_config(r->per_dir_config, &filter_module) ; mod_filter_cfg *cfg = ap_get_module_config(r->per_dir_config, &filter_module); #ifndef NO_PROTOCOL int ranges = 1; #endif Loading @@ -608,15 +655,19 @@ static int filter_insert(request_rec* r) filter = apr_hash_get(cfg->live_filters, p->fname, APR_HASH_KEY_STRING); ap_add_output_filter_handle(filter, NULL, r, r->connection); #ifndef NO_PROTOCOL if ( ranges && (filter->proto_flags & (AP_FILTER_PROTO_NO_BYTERANGE|AP_FILTER_PROTO_CHANGE_LENGTH)) ) { if (ranges && (filter->proto_flags & (AP_FILTER_PROTO_NO_BYTERANGE | AP_FILTER_PROTO_CHANGE_LENGTH))) { filter->range = apr_table_get(r->headers_in, "Range"); apr_table_unset(r->headers_in, "Range"); ranges = 0; } #endif } return OK; } static void filter_hooks(apr_pool_t *pool) { ap_hook_insert_filter(filter_insert, NULL, NULL, APR_HOOK_MIDDLE); Loading @@ -629,6 +680,7 @@ static void* filter_config(apr_pool_t* pool, char* x) cfg->chain = NULL; return cfg; } static void *filter_merge(apr_pool_t *pool, void *BASE, void *ADD) { mod_filter_cfg *base = BASE; Loading @@ -638,30 +690,51 @@ static void* filter_merge(apr_pool_t* pool, void* BASE, void* ADD) mod_filter_chain *p; mod_filter_cfg *conf = apr_palloc(pool, sizeof(mod_filter_cfg)); conf->live_filters = apr_hash_overlay(pool, add->live_filters, base->live_filters) ; conf->live_filters = apr_hash_overlay(pool, add->live_filters, base->live_filters); if (base->chain && add->chain) { for (p = base->chain; p; p = p->next) { newlink = apr_pmemdup(pool, p, sizeof(mod_filter_chain)); if (savelink) { savelink->next = newlink; savelink = newlink; } else { } else { conf->chain = savelink = newlink; } } for (p = add->chain; p; p = p->next) { newlink = apr_pmemdup(pool, p, sizeof(mod_filter_chain)); savelink->next = newlink; savelink = newlink; } } else if ( add->chain ) { } else if (add->chain) { conf->chain = add->chain; } else { } else { conf->chain = base->chain; } return conf; } static const command_rec filter_cmds[] = { AP_INIT_TAKE23("FilterDeclare", filter_declare, NULL, OR_ALL, "filter-name, dispatch-criterion [, filter-type]") , AP_INIT_TAKE3("FilterProvider", filter_provider, NULL, OR_ALL, "filter-name, provider-name, dispatch-match") , AP_INIT_ITERATE("FilterChain", filter_chain, NULL, OR_ALL, "list of filter names with optional [+-=!@]") , AP_INIT_TAKE2("FilterTrace", filter_debug, NULL, OR_ALL, "Debug level") , #ifndef NO_PROTOCOL AP_INIT_TAKE23("FilterProtocol", filter_protocol, NULL, OR_ALL, "filter-name [provider-name] protocol-args") , #endif { NULL } }; module AP_MODULE_DECLARE_DATA filter_module = { STANDARD20_MODULE_STUFF, filter_config, Loading Loading
modules/experimental/mod_filter.c +549 −476 Original line number Diff line number Diff line Loading @@ -13,7 +13,7 @@ * limitations under the License. */ /* Originally by Nick Kew <nick@webthing.com> /* Originally contributed by Nick Kew <nick webthing.com> * * At the time of writing, this is designed primarily for use with * httpd 2.2, but is also back-compatible with 2.0. It is likely Loading @@ -23,14 +23,13 @@ * 21/9/04: Unifying data structures with util_filter. * From now on, until and unless we backport, mod_filter requires * util_filter.h from CVS or httpd-2.1+ to compile. * I'll keep a minimal patch for httpd-2.0 users to compile mod_filter * at http://www.apache.org/~niq/ * There's a minimal patch for httpd-2.0 users maintained by Nick * to compile mod_filter at http://www.apache.org/~niq/ */ #include <ctype.h> #include <string.h> /* apache */ #define APR_WANT_STRFUNC #include "apr_want.h" #include "apr_lib.h" #include "apr_strings.h" #include "apr_hash.h" #include "httpd.h" Loading Loading @@ -76,13 +75,16 @@ static const char* filter_bucket_type(apr_bucket* b) { NULL, NULL } }; int i = 0; do { if (b->type == types[i].fn) { return types[i].desc; } } while (types[++i].fn != NULL); return "(error)"; } static void filter_trace(apr_pool_t *pool, int debug, const char *fname, apr_bucket_brigade *bb) { Loading @@ -109,6 +111,7 @@ static int filter_init(ap_filter_t* f) mod_filter_cfg *cfg = ap_get_module_config(f->r->per_dir_config, &filter_module); ap_filter_rec_t *filter = f->frec; f->ctx = apr_pcalloc(f->r->pool, sizeof(harness_ctx)); for (p = filter->providers; p; p = p->next) { if (p->frec->filter_init_func) { Loading @@ -119,8 +122,10 @@ static int filter_init(ap_filter_t* f) } } } return err; } static ap_out_filter_func filter_lookup(request_rec *r, ap_filter_rec_t *filter) { ap_filter_provider_t *provider; Loading Loading @@ -149,18 +154,19 @@ static ap_out_filter_func filter_lookup(request_rec* r, ap_filter_rec_t* filter) str = r->handler; break; } /* treat nulls so we don't have to check every strcmp individually * Not sure if there's anything better to do with them */ if ( str == NULL ) { if ( provider->match_type == DEFINED ) { if ( provider->match.c != NULL ) { if (!str) { if (provider->match_type == DEFINED && provider->match.c) { match = 0; } } } else if ( provider->match.c == NULL ) { else if (!provider->match.c) { match = 0; } else { } else { /* Now we have no nulls, so we can do string and regexp matching */ switch (provider->match_type) { case STRING_MATCH: Loading Loading @@ -200,6 +206,7 @@ static ap_out_filter_func filter_lookup(request_rec* r, ap_filter_rec_t* filter) break; } } if (match != provider->not) { /* condition matches this provider */ #ifndef NO_PROTOCOL Loading @@ -223,6 +230,7 @@ static ap_out_filter_func filter_lookup(request_rec* r, ap_filter_rec_t* filter) /* can't use this provider; try next */ continue; } if (proto_flags & AP_FILTER_PROTO_TRANSFORM) { str = apr_table_get(r->headers_out, "Cache-Control"); if (str) { Loading @@ -233,10 +241,13 @@ static ap_out_filter_func filter_lookup(request_rec* r, ap_filter_rec_t* filter) continue; } } apr_table_addn(r->headers_out, "Warning", apr_psprintf( r->pool, "214 %s Transformation applied", r->hostname) ) ; apr_table_addn(r->headers_out, "Warning", apr_psprintf(r->pool, "214 %s Transformation applied", r->hostname)); } } /* things that are invalidated if the filter transforms content */ if (proto_flags & AP_FILTER_PROTO_CHANGE) { apr_table_unset(r->headers_out, "Content-MD5"); Loading @@ -245,26 +256,30 @@ static ap_out_filter_func filter_lookup(request_rec* r, ap_filter_rec_t* filter) apr_table_unset(r->headers_out, "Content-Length"); } } /* no-cache is for a filter that has different effect per-hit */ if (proto_flags & AP_FILTER_PROTO_NO_CACHE) { apr_table_unset(r->headers_out, "Last-Modified"); apr_table_addn(r->headers_out, "Cache-Control", "no-cache"); } if (proto_flags & AP_FILTER_PROTO_NO_BYTERANGE) { apr_table_unset(r->headers_out, "Accept-Ranges"); } else if ( filter->range ) { } else if (filter->range) { apr_table_setn(r->headers_in, "Range", filter->range); } #endif return provider->frec->filter_func.out_func; } } /* No provider matched */ return NULL; } static apr_status_t filter_harness(ap_filter_t *f, apr_bucket_brigade *bb) { apr_status_t ret; const char *cachecontrol; char *str; Loading @@ -275,19 +290,21 @@ static apr_status_t filter_harness(ap_filter_t* f, apr_bucket_brigade* bb) ap_remove_output_filter(f); return ap_pass_brigade(f->next, bb); } filter_trace(f->c->pool, filter->debug, f->frec->name, bb); /* look up a handler function if we haven't already set it */ if (!ctx->func) { #ifndef NO_PROTOCOL if (f->r->proxyreq) { if (filter->proto_flags & AP_FILTER_PROTO_NO_PROXY) { ap_remove_output_filter(f); return ap_pass_brigade(f->next, bb); } if (filter->proto_flags & AP_FILTER_PROTO_TRANSFORM) { cachecontrol = apr_table_get(f->r->headers_out, "Cache-Control") ; cachecontrol = apr_table_get(f->r->headers_out, "Cache-Control"); if (cachecontrol) { str = apr_pstrdup(f->r->pool, cachecontrol); ap_str_tolower(str); Loading @@ -306,27 +323,29 @@ static apr_status_t filter_harness(ap_filter_t* f, apr_bucket_brigade* bb) } } /* call the content filter with its own context, then restore our context */ /* call the content filter with its own context, then restore our * context */ f->ctx = ctx->fctx; ret = ctx->func(f, bb); ctx->fctx = f->ctx; f->ctx = ctx; return ret; } #ifndef NO_PROTOCOL static const char* filter_protocol(cmd_parms* cmd, void* CFG, const char* fname, const char* pname, const char* proto) static const char *filter_protocol(cmd_parms *cmd, void *CFG, const char *fname, const char *pname, const char *proto) { static const char* sep = " ;, " ; static const char *sep = ";,\t"; char *arg; char *tok = 0; unsigned int flags = 0; mod_filter_cfg *cfg = CFG; ap_filter_provider_t *provider = NULL; ap_filter_rec_t* filter = apr_hash_get(cfg->live_filters, fname, APR_HASH_KEY_STRING) ; ap_filter_rec_t *filter = apr_hash_get(cfg->live_filters, fname, APR_HASH_KEY_STRING); if (!provider) { return "FilterProtocol: No such filter"; Loading @@ -336,49 +355,59 @@ static const char* filter_protocol(cmd_parms* cmd, void* CFG, if (proto == NULL) { proto = pname; pname = NULL; } else { } else { /* Find provider */ for (provider = filter->providers; provider; provider = provider->next) { if ( !strcasecmp(provider->frec->name, pname) ) if (!strcasecmp(provider->frec->name, pname)) { break; } } if (!provider) { return "FilterProtocol: No such provider for this filter"; } } /* Now set flags from our args */ for (arg = apr_strtok(apr_pstrdup(cmd->pool, proto), sep, &tok); arg; arg = apr_strtok(NULL, sep, &tok)) { if (!strcasecmp(arg, "change=yes")) { flags != AP_FILTER_PROTO_CHANGE | AP_FILTER_PROTO_CHANGE_LENGTH; } else if ( !strcasecmp(arg, "change=1:1") ) { } else if (!strcasecmp(arg, "change=1:1")) { flags |= AP_FILTER_PROTO_CHANGE; } else if ( !strcasecmp(arg, "byteranges=no") ) { } else if (!strcasecmp(arg, "byteranges=no")) { flags |= AP_FILTER_PROTO_NO_BYTERANGE; } else if ( !strcasecmp(arg, "proxy=no") ) { } else if (!strcasecmp(arg, "proxy=no")) { flags |= AP_FILTER_PROTO_NO_PROXY; } else if ( !strcasecmp(arg, "proxy=transform") ) { } else if (!strcasecmp(arg, "proxy=transform")) { flags |= AP_FILTER_PROTO_TRANSFORM; } else if ( !strcasecmp(arg, "cache=no") ) { } else if (!strcasecmp(arg, "cache=no")) { flags |= AP_FILTER_PROTO_NO_CACHE; } } if (pname) { provider->frec->proto_flags = flags; } else { } else { filter->proto_flags = flags; } return NULL; } #endif static const char* filter_declare(cmd_parms* cmd, void* CFG, const char* fname, const char* condition, const char* place) static const char *filter_declare(cmd_parms *cmd, void *CFG, const char *fname, const char *condition, const char *place) { const char *eq; char *tmpname = ""; mod_filter_cfg *cfg = (mod_filter_cfg *)CFG; ap_filter_rec_t *filter; Loading @@ -392,27 +421,33 @@ static const char* filter_declare(cmd_parms* cmd, void* CFG, filter->next = NULL; /* determine what this filter will dispatch on */ eq = strchr(condition, '=') ; eq = ap_strchr_c(condition, '='); if (eq) { tmpname = apr_pstrdup(cmd->pool, eq+1); if (!strncasecmp(condition, "env=", 4)) { filter->dispatch = SUBPROCESS_ENV; } else if ( !strncasecmp(condition, "req=", 4) ) { } else if (!strncasecmp(condition, "req=", 4)) { filter->dispatch = REQUEST_HEADERS; } else if ( !strncasecmp(condition, "resp=", 5) ) { } else if (!strncasecmp(condition, "resp=", 5)) { filter->dispatch = RESPONSE_HEADERS; } else { return "FilterCondition: unrecognised dispatch table" ; } } else { else { return "FilterCondition: unrecognized dispatch table"; } } else { if (!strcasecmp(condition, "handler")) { filter->dispatch = HANDLER; } else { } else { filter->dispatch = RESPONSE_HEADERS; } tmpname = apr_pstrdup(cmd->pool, condition); ap_str_tolower(tmpname); } if ( (filter->dispatch == RESPONSE_HEADERS) && !strcmp(tmpname, "content-type")) { filter->dispatch = CONTENT_TYPE; Loading @@ -422,11 +457,14 @@ static const char* filter_declare(cmd_parms* cmd, void* CFG, if (place) { if (!strcasecmp(place, "CONTENT_SET")) { filter->ftype = AP_FTYPE_CONTENT_SET; } else if ( !strcasecmp(place, "PROTOCOL") ) { } else if (!strcasecmp(place, "PROTOCOL")) { filter->ftype = AP_FTYPE_PROTOCOL; } else if ( !strcasecmp(place, "CONNECTION") ) { } else if (!strcasecmp(place, "CONNECTION")) { filter->ftype = AP_FTYPE_CONNECTION; } else if ( !strcasecmp(place, "NETWORK") ) { } else if (!strcasecmp(place, "NETWORK")) { filter->ftype = AP_FTYPE_NETWORK; } } Loading @@ -449,21 +487,28 @@ static const char* filter_provider(cmd_parms* cmd, void* CFG, /* if provider has been registered, we can look it up */ ap_filter_rec_t *provider_frec = ap_get_output_filter_handle(pname); /* or if provider is mod_filter itself, we can also look it up */ if (!provider_frec) { provider_frec = apr_hash_get(cfg->live_filters, pname, APR_HASH_KEY_STRING); } if (!frec) { return apr_psprintf(cmd->pool, "Undeclared smart filter %s", fname); } else if ( !provider_frec ) { } else if (!provider_frec) { return apr_psprintf(cmd->pool, "Unknown filter provider %s", pname); } else { } else { provider = apr_palloc(cmd->pool, sizeof(ap_filter_provider_t)); if (match[0] == '!') { provider->not = 1; ++match; } else { } else { provider->not = 0; } switch (match[0]) { case '<': provider->match_type = INT_LT; Loading Loading @@ -491,7 +536,9 @@ static const char* filter_provider(cmd_parms* cmd, void* CFG, } } provider->match.r = ap_pregcomp(cmd->pool, apr_pstrndup(cmd->pool, match+1, rxend-match-1), flags) ; apr_pstrndup(cmd->pool, match+1, rxend-match-1), flags); break; case '*': provider->match_type = DEFINED; Loading @@ -512,8 +559,10 @@ static const char* filter_provider(cmd_parms* cmd, void* CFG, provider->next = frec->providers; frec->providers = provider; } return NULL; } static const char *filter_chain(cmd_parms *cmd, void *CFG, const char *arg) { mod_filter_chain *p; Loading @@ -527,16 +576,19 @@ static const char* filter_chain(cmd_parms* cmd, void* CFG, const char* arg) if (cfg->chain) { for (q = cfg->chain; q->next; q = q->next); q->next = p; } else { } else { cfg->chain = p; } break; case '@': /* add to start of chain */ p = apr_palloc(cmd->pool, sizeof(mod_filter_chain)); p->fname = arg+1; p->next = cfg->chain; cfg->chain = p; break; case '-': /* remove from chain */ if (cfg->chain) { if (strcasecmp(cfg->chain->fname, arg+1)) { Loading @@ -545,61 +597,56 @@ static const char* filter_chain(cmd_parms* cmd, void* CFG, const char* arg) p->next = p->next->next; } } } else { } else { cfg->chain = cfg->chain->next; } } break; case '!': /* Empty the chain */ cfg->chain = NULL; break; case '=': /* initialise chain with this arg */ p = apr_pcalloc(cmd->pool, sizeof(mod_filter_chain)); p->fname = arg+1; cfg->chain = p; break; default: /* add to end */ p = apr_pcalloc(cmd->pool, sizeof(mod_filter_chain)); p->fname = arg; if (cfg->chain) { for (q = cfg->chain; q->next; q = q->next); q->next = p; } else { } else { cfg->chain = p; } break; } return NULL; } static const char* filter_debug(cmd_parms* cmd, void* CFG, const char* fname, const char* level){ static const char *filter_debug(cmd_parms *cmd, void *CFG, const char *fname, const char *level) { mod_filter_cfg *cfg = CFG; ap_filter_rec_t *frec = apr_hash_get(cfg->live_filters, fname, APR_HASH_KEY_STRING); frec->debug = atoi(level); return NULL; } static const command_rec filter_cmds[] = { AP_INIT_TAKE23("FilterDeclare", filter_declare, NULL, OR_ALL, "filter-name, dispatch-criterion [, filter-type]") , AP_INIT_TAKE3("FilterProvider", filter_provider, NULL, OR_ALL, "filter-name, provider-name, dispatch-match") , AP_INIT_ITERATE("FilterChain", filter_chain, NULL, OR_ALL, "list of filter names with optional [+-=!@]") , AP_INIT_TAKE2("FilterTrace", filter_debug, NULL, OR_ALL, "Debug level") , #ifndef NO_PROTOCOL AP_INIT_TAKE23("FilterProtocol", filter_protocol, NULL, OR_ALL, "filter-name [provider-name] protocol-args") , #endif { NULL } } ; static int filter_insert(request_rec *r) { mod_filter_chain *p; ap_filter_rec_t *filter; mod_filter_cfg* cfg = ap_get_module_config(r->per_dir_config, &filter_module) ; mod_filter_cfg *cfg = ap_get_module_config(r->per_dir_config, &filter_module); #ifndef NO_PROTOCOL int ranges = 1; #endif Loading @@ -608,15 +655,19 @@ static int filter_insert(request_rec* r) filter = apr_hash_get(cfg->live_filters, p->fname, APR_HASH_KEY_STRING); ap_add_output_filter_handle(filter, NULL, r, r->connection); #ifndef NO_PROTOCOL if ( ranges && (filter->proto_flags & (AP_FILTER_PROTO_NO_BYTERANGE|AP_FILTER_PROTO_CHANGE_LENGTH)) ) { if (ranges && (filter->proto_flags & (AP_FILTER_PROTO_NO_BYTERANGE | AP_FILTER_PROTO_CHANGE_LENGTH))) { filter->range = apr_table_get(r->headers_in, "Range"); apr_table_unset(r->headers_in, "Range"); ranges = 0; } #endif } return OK; } static void filter_hooks(apr_pool_t *pool) { ap_hook_insert_filter(filter_insert, NULL, NULL, APR_HOOK_MIDDLE); Loading @@ -629,6 +680,7 @@ static void* filter_config(apr_pool_t* pool, char* x) cfg->chain = NULL; return cfg; } static void *filter_merge(apr_pool_t *pool, void *BASE, void *ADD) { mod_filter_cfg *base = BASE; Loading @@ -638,30 +690,51 @@ static void* filter_merge(apr_pool_t* pool, void* BASE, void* ADD) mod_filter_chain *p; mod_filter_cfg *conf = apr_palloc(pool, sizeof(mod_filter_cfg)); conf->live_filters = apr_hash_overlay(pool, add->live_filters, base->live_filters) ; conf->live_filters = apr_hash_overlay(pool, add->live_filters, base->live_filters); if (base->chain && add->chain) { for (p = base->chain; p; p = p->next) { newlink = apr_pmemdup(pool, p, sizeof(mod_filter_chain)); if (savelink) { savelink->next = newlink; savelink = newlink; } else { } else { conf->chain = savelink = newlink; } } for (p = add->chain; p; p = p->next) { newlink = apr_pmemdup(pool, p, sizeof(mod_filter_chain)); savelink->next = newlink; savelink = newlink; } } else if ( add->chain ) { } else if (add->chain) { conf->chain = add->chain; } else { } else { conf->chain = base->chain; } return conf; } static const command_rec filter_cmds[] = { AP_INIT_TAKE23("FilterDeclare", filter_declare, NULL, OR_ALL, "filter-name, dispatch-criterion [, filter-type]") , AP_INIT_TAKE3("FilterProvider", filter_provider, NULL, OR_ALL, "filter-name, provider-name, dispatch-match") , AP_INIT_ITERATE("FilterChain", filter_chain, NULL, OR_ALL, "list of filter names with optional [+-=!@]") , AP_INIT_TAKE2("FilterTrace", filter_debug, NULL, OR_ALL, "Debug level") , #ifndef NO_PROTOCOL AP_INIT_TAKE23("FilterProtocol", filter_protocol, NULL, OR_ALL, "filter-name [provider-name] protocol-args") , #endif { NULL } }; module AP_MODULE_DECLARE_DATA filter_module = { STANDARD20_MODULE_STUFF, filter_config, Loading