summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGraham Leggett <minfrin@apache.org>2016-02-19 16:00:05 +0100
committerGraham Leggett <minfrin@apache.org>2016-02-19 16:00:05 +0100
commit84051c1c9fa812575a94091b224e192118201778 (patch)
treeab9d2eac03478ef9b9eee1e3c3dc47cd0e86498b
parentDocumentation rebuild (diff)
downloadapache2-84051c1c9fa812575a94091b224e192118201778.tar.xz
apache2-84051c1c9fa812575a94091b224e192118201778.zip
mpm: Add a complete_connection hook that confirms whether an MPM is allowed
to leave the WRITE_COMPLETION phase. Move filter code out of the MPMs. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1731253 13f79535-47bb-0310-9956-ffa450edef68
-rw-r--r--CHANGES4
-rw-r--r--include/ap_mmn.h4
-rw-r--r--include/mpm_common.h10
-rw-r--r--include/util_filter.h12
-rw-r--r--server/core.c4
-rw-r--r--server/mpm/event/event.c32
-rw-r--r--server/mpm/motorz/motorz.c31
-rw-r--r--server/mpm/simple/simple_io.c32
-rw-r--r--server/mpm_common.c4
-rw-r--r--server/util_filter.c33
10 files changed, 83 insertions, 83 deletions
diff --git a/CHANGES b/CHANGES
index a6d5a8e54a..26504f16c7 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,6 +1,10 @@
-*- coding: utf-8 -*-
Changes with Apache 2.5.0
+ *) mpm: Add a complete_connection hook that confirms whether an MPM is allowed
+ to leave the WRITE_COMPLETION phase. Move filter code out of the MPMs.
+ [Graham Leggett]
+
*) mod_proxy_http2: using single connection for several requests *if*
master connection uses HTTP/2 itself. Not yet hardened under load.
[Stefan Eissing]
diff --git a/include/ap_mmn.h b/include/ap_mmn.h
index d00265edc7..9789081d6f 100644
--- a/include/ap_mmn.h
+++ b/include/ap_mmn.h
@@ -504,6 +504,8 @@
* ap_prep_lingering_close().
* 20150222.11 (2.5.0-dev) Split useragent_host from the conn_rec into
* the request_rec, with ap_get_useragent_host()
+ * 20150222.12 (2.5.0-dev) Add complete_connection hook,
+ * ap_filter_complete_connection().
*/
#define MODULE_MAGIC_COOKIE 0x41503235UL /* "AP25" */
@@ -511,7 +513,7 @@
#ifndef MODULE_MAGIC_NUMBER_MAJOR
#define MODULE_MAGIC_NUMBER_MAJOR 20150222
#endif
-#define MODULE_MAGIC_NUMBER_MINOR 11 /* 0...n */
+#define MODULE_MAGIC_NUMBER_MINOR 12 /* 0...n */
/**
* Determine if the server's current MODULE_MAGIC_NUMBER is at least a
diff --git a/include/mpm_common.h b/include/mpm_common.h
index 4031b51ddf..9cc715b74b 100644
--- a/include/mpm_common.h
+++ b/include/mpm_common.h
@@ -458,6 +458,16 @@ AP_DECLARE_HOOK(apr_status_t, mpm_resume_suspended, (conn_rec*))
AP_DECLARE_HOOK(const char *,mpm_get_name,(void))
/**
+ * Hook called to determine whether we should stay within the write completion
+ * phase.
+ * @param c The current connection
+ * @return OK if write completion should continue, DECLINED if write completion
+ * should end gracefully, or a positive error if we should begin to linger.
+ * @ingroup hooks
+ */
+AP_DECLARE_HOOK(int, complete_connection, (conn_rec *c))
+
+/**
* Notification that connection handling is suspending (disassociating from the
* current thread)
* @param c The current connection
diff --git a/include/util_filter.h b/include/util_filter.h
index 0e013c68bf..cf6f09cf22 100644
--- a/include/util_filter.h
+++ b/include/util_filter.h
@@ -590,6 +590,18 @@ AP_DECLARE(apr_status_t) ap_filter_reinstate_brigade(ap_filter_t *f,
AP_DECLARE(int) ap_filter_should_yield(ap_filter_t *f);
/**
+ * This function determines whether there is unwritten data in the output
+ * filters, and if so, attempts to make a single write to each filter
+ * with unwritten data.
+ *
+ * @param c The connection.
+ * @return If no unwritten data remains, this function returns DECLINED.
+ * If some unwritten data remains, this function returns OK. If any
+ * attempt to write data failed, this functions returns a positive integer.
+ */
+AP_DECLARE(int) ap_filter_complete_connection(conn_rec *c);
+
+/**
* Flush function for apr_brigade_* calls. This calls ap_pass_brigade
* to flush the brigade if the brigade buffer overflows.
* @param bb The brigade to flush
diff --git a/server/core.c b/server/core.c
index b440e27bd9..c7cc97538a 100644
--- a/server/core.c
+++ b/server/core.c
@@ -5559,7 +5559,9 @@ static void register_hooks(apr_pool_t *p)
ap_hook_open_htaccess(ap_open_htaccess, NULL, NULL, APR_HOOK_REALLY_LAST);
ap_hook_optional_fn_retrieve(core_optional_fn_retrieve, NULL, NULL,
APR_HOOK_MIDDLE);
-
+ ap_hook_complete_connection(ap_filter_complete_connection, NULL, NULL,
+ APR_HOOK_MIDDLE);
+
/* register the core's insert_filter hook and register core-provided
* filters
*/
diff --git a/server/mpm/event/event.c b/server/mpm/event/event.c
index fa6a8119ea..4d5e38384d 100644
--- a/server/mpm/event/event.c
+++ b/server/mpm/event/event.c
@@ -1147,38 +1147,16 @@ read_request:
}
if (cs->pub.state == CONN_STATE_WRITE_COMPLETION) {
- apr_hash_index_t *rindex;
- apr_status_t rv = APR_SUCCESS;
- int data_in_output_filters = 0;
- ap_update_child_status_from_conn(sbh, SERVER_BUSY_WRITE, c);
-
- rindex = apr_hash_first(NULL, c->filters);
- while (rindex) {
- ap_filter_t *f = apr_hash_this_val(rindex);
-
- if (!APR_BRIGADE_EMPTY(f->bb)) {
-
- rv = ap_pass_brigade(f, c->empty);
- apr_brigade_cleanup(c->empty);
- if (APR_SUCCESS != rv) {
- ap_log_cerror(
- APLOG_MARK, APLOG_DEBUG, rv, c, APLOGNO(00470)
- "write failure in '%s' output filter", f->frec->name);
- break;
- }
+ int not_complete_yet;
- if (ap_filter_should_yield(f)) {
- data_in_output_filters = 1;
- }
- }
+ ap_update_child_status_from_conn(sbh, SERVER_BUSY_WRITE, c);
- rindex = apr_hash_next(rindex);
- }
+ not_complete_yet = ap_run_complete_connection(c);
- if (rv != APR_SUCCESS) {
+ if (not_complete_yet > OK) {
cs->pub.state = CONN_STATE_LINGER;
}
- else if (data_in_output_filters) {
+ else if (not_complete_yet == OK) {
/* Still in WRITE_COMPLETION_STATE:
* Set a write timeout for this connection, and let the
* event thread poll for writeability.
diff --git a/server/mpm/motorz/motorz.c b/server/mpm/motorz/motorz.c
index 8522e1b15d..682b3808fa 100644
--- a/server/mpm/motorz/motorz.c
+++ b/server/mpm/motorz/motorz.c
@@ -395,42 +395,19 @@ read_request:
}
if (scon->cs.state == CONN_STATE_WRITE_COMPLETION) {
- apr_hash_index_t *rindex;
- apr_status_t rv = APR_SUCCESS;
- int data_in_output_filters = 0;
+ int not_complete_yet;
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, APLOGNO()
"motorz_io_process(): CONN_STATE_WRITE_COMPLETION");
ap_update_child_status_from_conn(scon->sbh, SERVER_BUSY_WRITE, c);
- rindex = apr_hash_first(NULL, c->filters);
- while (rindex) {
- ap_filter_t *f = apr_hash_this_val(rindex);
+ not_complete_yet = ap_run_complete_connection(c);
- if (!APR_BRIGADE_EMPTY(f->bb)) {
-
- rv = ap_pass_brigade(f, c->empty);
- apr_brigade_cleanup(c->empty);
- if (APR_SUCCESS != rv) {
- ap_log_cerror(
- APLOG_MARK, APLOG_DEBUG, rv, c, APLOGNO(02848)
- "write failure in '%s' output filter", f->frec->name);
- break;
- }
-
- if (ap_filter_should_yield(f)) {
- data_in_output_filters = 1;
- }
- }
-
- rindex = apr_hash_next(rindex);
- }
-
- if (rv != APR_SUCCESS) {
+ if (not_complete_yet > OK) {
scon->cs.state = CONN_STATE_LINGER;
}
- else if (data_in_output_filters) {
+ else if (not_complete_yet == OK) {
/* Still in WRITE_COMPLETION_STATE:
* Set a write timeout for this connection, and let the
* event thread poll for writeability.
diff --git a/server/mpm/simple/simple_io.c b/server/mpm/simple/simple_io.c
index 47c13d71c6..6d98935e8b 100644
--- a/server/mpm/simple/simple_io.c
+++ b/server/mpm/simple/simple_io.c
@@ -92,37 +92,15 @@ static apr_status_t simple_io_process(simple_conn_t * scon)
}
if (scon->cs.state == CONN_STATE_WRITE_COMPLETION) {
- apr_hash_index_t *rindex;
- apr_status_t rv = APR_SUCCESS;
- int data_in_output_filters = 0;
-
- rindex = apr_hash_first(NULL, c->filters);
- while (rindex) {
- ap_filter_t *f = apr_hash_this_val(rindex);
-
- if (!APR_BRIGADE_EMPTY(f->bb)) {
-
- rv = ap_pass_brigade(f, c->empty);
- apr_brigade_cleanup(c->empty);
- if (APR_SUCCESS != rv) {
- ap_log_cerror(
- APLOG_MARK, APLOG_DEBUG, rv, c, APLOGNO(00249)
- "write failure in '%s' output filter", f->frec->name);
- break;
- }
-
- if (ap_filter_should_yield(f)) {
- data_in_output_filters = 1;
- }
- }
+ int not_complete_yet;
- rindex = apr_hash_next(rindex);
- }
+ ap_update_child_status_from_conn(sbh, SERVER_BUSY_WRITE, c);
+ not_complete_yet = ap_run_complete_connection(c);
- if (rv != APR_SUCCESS) {
+ if (not_complete_yet > OK) {
scon->cs.state = CONN_STATE_LINGER;
}
- else if (data_in_output_filters) {
+ else if (not_complete_yet == OK) {
/* Still in WRITE_COMPLETION_STATE:
* Set a write timeout for this connection, and let the
* event thread poll for writeability.
diff --git a/server/mpm_common.c b/server/mpm_common.c
index 9a010f34af..b2133df1a1 100644
--- a/server/mpm_common.c
+++ b/server/mpm_common.c
@@ -75,6 +75,7 @@
APR_HOOK_LINK(mpm_resume_suspended) \
APR_HOOK_LINK(end_generation) \
APR_HOOK_LINK(child_status) \
+ APR_HOOK_LINK(complete_connection) \
APR_HOOK_LINK(suspend_connection) \
APR_HOOK_LINK(resume_connection)
@@ -95,6 +96,7 @@ AP_IMPLEMENT_HOOK_RUN_ALL(int, monitor,
AP_IMPLEMENT_HOOK_RUN_ALL(int, drop_privileges,
(apr_pool_t * pchild, server_rec * s),
(pchild, s), OK, DECLINED)
+
AP_IMPLEMENT_HOOK_RUN_FIRST(int, mpm,
(apr_pool_t *pconf, apr_pool_t *plog, server_rec *s),
(pconf, plog, s), DECLINED)
@@ -116,6 +118,8 @@ AP_IMPLEMENT_HOOK_RUN_FIRST(apr_status_t, mpm_register_socket_callback_timeout,
AP_IMPLEMENT_HOOK_RUN_FIRST(apr_status_t, mpm_unregister_socket_callback,
(apr_socket_t **s, apr_pool_t *p),
(s, p), APR_ENOTIMPL)
+AP_IMPLEMENT_HOOK_RUN_FIRST(int, complete_connection,
+ (conn_rec *c), (c), DECLINED)
AP_IMPLEMENT_HOOK_VOID(end_generation,
(server_rec *s, ap_generation_t gen),
diff --git a/server/util_filter.c b/server/util_filter.c
index 316a0d0dd0..aaf0173a5a 100644
--- a/server/util_filter.c
+++ b/server/util_filter.c
@@ -953,6 +953,39 @@ AP_DECLARE(int) ap_filter_should_yield(ap_filter_t *f)
return 0;
}
+AP_DECLARE(int) ap_filter_complete_connection(conn_rec *c)
+{
+ apr_hash_index_t *rindex;
+ int data_in_output_filters = DECLINED;
+
+ rindex = apr_hash_first(NULL, c->filters);
+ while (rindex) {
+ ap_filter_t *f = apr_hash_this_val(rindex);
+
+ if (!APR_BRIGADE_EMPTY(f->bb)) {
+
+ apr_status_t rv;
+
+ rv = ap_pass_brigade(f, c->empty);
+ apr_brigade_cleanup(c->empty);
+ if (APR_SUCCESS != rv) {
+ ap_log_cerror(
+ APLOG_MARK, APLOG_DEBUG, rv, c, APLOGNO(00470)
+ "write failure in '%s' output filter", f->frec->name);
+ return rv;
+ }
+
+ if (ap_filter_should_yield(f)) {
+ data_in_output_filters = OK;
+ }
+ }
+
+ rindex = apr_hash_next(rindex);
+ }
+
+ return data_in_output_filters;
+}
+
AP_DECLARE_NONSTD(apr_status_t) ap_filter_flush(apr_bucket_brigade *bb,
void *ctx)
{