]> granicus.if.org Git - apache/commitdiff
mpm: Add a complete_connection hook that confirms whether an MPM is allowed
authorGraham Leggett <minfrin@apache.org>
Fri, 19 Feb 2016 15:00:05 +0000 (15:00 +0000)
committerGraham Leggett <minfrin@apache.org>
Fri, 19 Feb 2016 15:00:05 +0000 (15:00 +0000)
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

CHANGES
include/ap_mmn.h
include/mpm_common.h
include/util_filter.h
server/core.c
server/mpm/event/event.c
server/mpm/motorz/motorz.c
server/mpm/simple/simple_io.c
server/mpm_common.c
server/util_filter.c

diff --git a/CHANGES b/CHANGES
index a6d5a8e54ab3c91c522b0287bb3a53273733ea05..26504f16c76213311c4a26a139517ae2dcbc101e 100644 (file)
--- 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]
index d00265edc789c1717b91bafdb7c6ae62e17a0972..9789081d6f5831152f3d62433ddd8ad812007f3a 100644 (file)
  *                         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" */
 #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
index 4031b51ddf1f96175f044f74cdac07d77387d13e..9cc715b74b976e7541c6679a579e10867b41798b 100644 (file)
@@ -457,6 +457,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)
index 0e013c68bff1c3e71d61e0a8fd677d2f7aaf6efd..cf6f09cf22312dc53124764b71681d3b2dc863f3 100644 (file)
@@ -589,6 +589,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.
index b440e27bd9a6caab1ac00a2723fb02896b5ac87b..c7cc97538ab4c2cbc014e9ed26e4cd06b7d897c9 100644 (file)
@@ -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
      */
index fa6a8119ea4d7f3934f05f54ef1a8f31a850c41a..4d5e38384d1d1a76a7d7eea45f70c2600345f5a0 100644 (file)
@@ -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.
index 8522e1b15d00ac2b83e911937810d6fe8bab58bd..682b3808fa58ee4b2eaebd701cfcfa3083f6e126 100644 (file)
@@ -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.
index 47c13d71c6ebf8cdd30f98ceedd8711d69b7587a..6d98935e8b69f7b65cf8c5fcaf1849cf66d06a1f 100644 (file)
@@ -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.
index 9a010f34af4fdc15a32f52da63cfb03e70c7ed58..b2133df1a18b84f6e1abe9df8a4c28b3144cede7 100644 (file)
@@ -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),
index 316a0d0dd0ca74c2aadc61bbb6ca5c67b667b1bb..aaf0173a5abc3a1c6e1942df871e11951050e5ca 100644 (file)
@@ -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)
 {