From: Graham Leggett Date: Tue, 6 Oct 2015 22:33:03 +0000 (+0000) Subject: Add the AsyncFilter directive that allows the asynchronous filter X-Git-Tag: 2.5.0-alpha~2748 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=2da6c9a57a7473c52d81b87e541228225691db6f;p=apache Add the AsyncFilter directive that allows the asynchronous filter functionality to be switched off for certain classes of filters. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1707161 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/docs/manual/mod/core.xml b/docs/manual/mod/core.xml index e4974c86bc..effedee540 100644 --- a/docs/manual/mod/core.xml +++ b/docs/manual/mod/core.xml @@ -551,6 +551,32 @@ AllowOverrideList CookieTracking CookieName .htaccess Files + + AsyncFilter + Set the minimum filter type eligible for asynchronous handling + AsyncFilter request|connection|network + AsyncFilter request + server configvirtual host + Only available from Apache 2.5.0 and later. + + +

This directive controls the minimum filter levels that are eligible + for asynchronous handling. This may be necessary to support legacy external + filters that did not handle meta buckets correctly.

+ +

If set to "network", asynchronous handling will be limited to the network + filter only. If set to "connection", all connection and network filters + will be eligible for asynchronous handling, including mod_ssl. + If set to "request", all filters will be eligible for asynchronous handling.

+ +

With ProtocolsHonorOrder set to on + (default), the client ordering does not matter and only the ordering + in the server settings influences the outcome of the protocol + negotiation.

+ +
+
+ CGIMapExtension Technique for locating the interpreter for CGI diff --git a/include/ap_mmn.h b/include/ap_mmn.h index 631562e4af..ea2e0f148f 100644 --- a/include/ap_mmn.h +++ b/include/ap_mmn.h @@ -494,6 +494,7 @@ * ap_filter_reinstate_brigade() and * ap_filter_should_yield(). Add empty and filters to * conn_rec. + * 20150222.6 (2.5.0-dev) Add async_filter to conn_rec. */ #define MODULE_MAGIC_COOKIE 0x41503235UL /* "AP25" */ @@ -501,7 +502,7 @@ #ifndef MODULE_MAGIC_NUMBER_MAJOR #define MODULE_MAGIC_NUMBER_MAJOR 20150222 #endif -#define MODULE_MAGIC_NUMBER_MINOR 5 /* 0...n */ +#define MODULE_MAGIC_NUMBER_MINOR 6 /* 0...n */ /** * Determine if the server's current MODULE_MAGIC_NUMBER is at least a diff --git a/include/http_core.h b/include/http_core.h index dbb310db8e..cbd4b81d10 100644 --- a/include/http_core.h +++ b/include/http_core.h @@ -711,6 +711,8 @@ typedef struct { apr_array_header_t *protocols; int protocols_honor_order; + int async_filter; + int async_filter_set:1; } core_server_config; /* for AddOutputFiltersByType in core.c */ diff --git a/include/httpd.h b/include/httpd.h index d36ed10a02..91cd45a86a 100644 --- a/include/httpd.h +++ b/include/httpd.h @@ -1198,6 +1198,9 @@ struct conn_rec { /** Hashtable of filters with setaside buckets for write completion */ apr_hash_t *filters; + + /** The minimum level of filter type to allow setaside buckets */ + int async_filter; }; struct conn_slave_rec { diff --git a/server/core.c b/server/core.c index de3fa23f91..d340d5e3de 100644 --- a/server/core.c +++ b/server/core.c @@ -481,7 +481,8 @@ static void *create_core_server_config(apr_pool_t *a, server_rec *s) conf->protocols = apr_array_make(a, 5, sizeof(const char *)); conf->protocols_honor_order = -1; - + conf->async_filter = 0; + return (void *)conf; } @@ -555,12 +556,16 @@ static void *merge_core_server_configs(apr_pool_t *p, void *basev, void *virtv) ? virt->merge_trailers : base->merge_trailers; - conf->protocols = ((virt->protocols->nelts > 0)? + conf->protocols = ((virt->protocols->nelts > 0) ? virt->protocols : base->protocols); - conf->protocols_honor_order = ((virt->protocols_honor_order < 0)? + conf->protocols_honor_order = ((virt->protocols_honor_order < 0) ? base->protocols_honor_order : virt->protocols_honor_order); - + conf->async_filter = ((virt->async_filter_set) ? + virt->async_filter : + base->async_filter); + conf->async_filter_set = base->async_filter_set || virt->async_filter_set; + return conf; } @@ -3887,6 +3892,34 @@ static const char *set_http_protocol(cmd_parms *cmd, void *dummy, return NULL; } +static const char *set_async_filter(cmd_parms *cmd, void *dummy, + const char *arg) +{ + core_server_config *conf = + ap_get_core_module_config(cmd->server->module_config); + const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE); + + if (err) { + return err; + } + + if (strcasecmp(arg, "network") == 0) { + conf->async_filter = AP_FTYPE_NETWORK; + } + else if (strcasecmp(arg, "connection") == 0) { + conf->async_filter = AP_FTYPE_CONNECTION; + } + else if (strcasecmp(arg, "request") == 0) { + conf->async_filter = 0; + } + else { + return "AsyncFilter must be 'network', 'connection' or 'request'"; + } + conf->async_filter_set = 1; + + return NULL; +} + static const char *set_http_method(cmd_parms *cmd, void *conf, const char *arg) { const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); @@ -4502,6 +4535,9 @@ AP_INIT_ITERATE("Protocols", set_protocols, NULL, RSRC_CONF, AP_INIT_TAKE1("ProtocolsHonorOrder", set_protocols_honor_order, NULL, RSRC_CONF, "'off' (default) or 'on' to respect given order of protocols, " "by default the client specified order determines selection"), +AP_INIT_TAKE1("AsyncFilter", set_async_filter, NULL, RSRC_CONF, + "'network', 'connection' (default) or 'request' to limit the " + "types of filters that support asynchronous handling"), { NULL } }; @@ -5010,6 +5046,7 @@ static conn_rec *core_create_conn(apr_pool_t *ptrans, server_rec *s, c->bucket_alloc = alloc; c->empty = apr_brigade_create(c->pool, c->bucket_alloc); c->filters = apr_hash_make(c->pool); + c->async_filter = sconf->async_filter; c->clogging_input_filters = 0; diff --git a/server/request.c b/server/request.c index 9c9ad9f93b..abf084e31a 100644 --- a/server/request.c +++ b/server/request.c @@ -2043,6 +2043,15 @@ AP_CORE_DECLARE_NONSTD(apr_status_t) ap_request_core_filter(ap_filter_t *f, apr_status_t status = APR_SUCCESS; apr_bucket_brigade *tmp_bb = f->ctx; + /* + * Handle the AsyncFilter directive. We limit the filters that are + * eligible for asynchronous handling here. + */ + if (f->frec->ftype < f->c->async_filter) { + ap_remove_output_filter(f); + return ap_pass_brigade(f->next, bb); + } + if (!tmp_bb) { tmp_bb = f->ctx = apr_brigade_create(f->r->pool, f->c->bucket_alloc); } diff --git a/server/util_filter.c b/server/util_filter.c index ad14112ddb..949d13e0a8 100644 --- a/server/util_filter.c +++ b/server/util_filter.c @@ -893,6 +893,14 @@ AP_DECLARE(apr_status_t) ap_filter_reinstate_brigade(ap_filter_t *f, AP_DECLARE(int) ap_filter_should_yield(ap_filter_t *f) { + /* + * Handle the AsyncFilter directive. We limit the filters that are + * eligible for asynchronous handling here. + */ + if (f->frec->ftype < f->c->async_filter) { + return 0; + } + /* * This function decides whether a filter should yield due to buffered * data in a downstream filter. If a downstream filter buffers we