<seealso><a href="../howto/htaccess.html">.htaccess Files</a></seealso>
</directivesynopsis>
+<directivesynopsis>
+ <name>AsyncFilter</name>
+ <description>Set the minimum filter type eligible for asynchronous handling</description>
+ <syntax>AsyncFilter request|connection|network</syntax>
+ <default>AsyncFilter request</default>
+ <contextlist><context>server config</context><context>virtual host</context></contextlist>
+ <compatibility>Only available from Apache 2.5.0 and later.</compatibility>
+
+ <usage>
+ <p>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.</p>
+
+ <p>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 <module>mod_ssl</module>.
+ If set to "request", all filters will be eligible for asynchronous handling.</p>
+
+ <p>With <directive>ProtocolsHonorOrder</directive> set to <code>on</code>
+ (default), the client ordering does not matter and only the ordering
+ in the server settings influences the outcome of the protocol
+ negotiation.</p>
+
+ </usage>
+</directivesynopsis>
+
<directivesynopsis>
<name>CGIMapExtension</name>
<description>Technique for locating the interpreter for CGI
* 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" */
#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
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 */
/** 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 {
conf->protocols = apr_array_make(a, 5, sizeof(const char *));
conf->protocols_honor_order = -1;
-
+ conf->async_filter = 0;
+
return (void *)conf;
}
? 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;
}
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);
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 }
};
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;
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);
}
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