]> granicus.if.org Git - apache/blobdiff - server/mpm/event/event.c
Merge r1818804, r1818951, r1818958, r1818960, r1819027, r1819214, r1820035 from trunk:
[apache] / server / mpm / event / event.c
index 2efde3982dee377a589a66edf10163802e1d50ff..54c9256074106424d3845d1816600991b1ec42bc 100644 (file)
@@ -993,14 +993,12 @@ static void process_socket(apr_thread_t *thd, apr_pool_t * p, apr_socket_t * soc
         c->current_thread = thd;
         /* Subsequent request on a conn, and thread number is part of ID */
         c->id = conn_id;
-
-        if (c->aborted) {
-            cs->pub.state = CONN_STATE_LINGER;
-        }
     }
 
-    if (cs->pub.state == CONN_STATE_LINGER) {
+    rc = OK;
+    if (c->aborted || cs->pub.state == CONN_STATE_LINGER) {
         /* do lingering close below */
+        cs->pub.state = CONN_STATE_LINGER;
     }
     else if (c->clogging_input_filters) {
         /* Since we have an input filter which 'clogs' the input stream,
@@ -1010,20 +1008,54 @@ static void process_socket(apr_thread_t *thd, apr_pool_t * p, apr_socket_t * soc
          * otherwise write, should set the sense appropriately.
          */
         apr_atomic_inc32(&clogged_count);
-        ap_run_process_connection(c);
-        if (cs->pub.state != CONN_STATE_SUSPENDED) {
-            cs->pub.state = CONN_STATE_LINGER;
-        }
+        rc = ap_run_process_connection(c);
         apr_atomic_dec32(&clogged_count);
+        if (rc == DONE) {
+            rc = OK;
+        }
     }
     else if (cs->pub.state == CONN_STATE_READ_REQUEST_LINE) {
 read_request:
-        ap_run_process_connection(c);
-
-        /* state will be updated upon return
-         * fall thru to either wait for readability/timeout or
-         * do lingering close
-         */
+        rc = ap_run_process_connection(c);
+        if (rc == DONE) {
+            rc = OK;
+        }
+    }
+    /*
+     * The process_connection hooks above should set the connection state
+     * appropriately upon return, for event MPM to either:
+     * - do lingering close (CONN_STATE_LINGER),
+     * - wait for readability of the next request with respect to the keepalive
+     *   timeout (CONN_STATE_CHECK_REQUEST_LINE_READABLE),
+     * - keep flushing the output filters stack in nonblocking mode, and then
+     *   if required wait for read/write-ability of the underlying socket with
+     *   respect to its own timeout (CONN_STATE_WRITE_COMPLETION); since write
+     *   completion at some point may require reads (e.g. SSL_ERROR_WANT_READ),
+     *   an output filter can set the sense to CONN_SENSE_WANT_READ at any time
+     *   for event MPM to do the right thing,
+     * - suspend the connection (SUSPENDED) such that it now interracts with
+     *   the MPM through suspend/resume_connection() hooks, and/or registered
+     *   poll callbacks (PT_USER), and/or registered timed callbacks triggered
+     *   by timer events.
+     * If a process_connection hook returns an error or no hook sets the state
+     * to one of the above expected value, we forcibly close the connection w/
+     * CONN_STATE_LINGER.  This covers the cases where no process_connection
+     * hook executes (DECLINED), or one returns OK w/o touching the state (i.e.
+     * CONN_STATE_READ_REQUEST_LINE remains after the call) which can happen
+     * with third-party modules not updated to work specifically with event MPM
+     * while this was expected to do lingering close unconditionally with
+     * worker or prefork MPMs for instance.
+     */
+    if (rc != OK || (cs->pub.state != CONN_STATE_LINGER
+                     && cs->pub.state != CONN_STATE_WRITE_COMPLETION
+                     && cs->pub.state != CONN_STATE_CHECK_REQUEST_LINE_READABLE
+                     && cs->pub.state != CONN_STATE_SUSPENDED)) {
+        ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, APLOGNO(10111)
+                      "process_socket: connection processing %s: closing",
+                      rc ? apr_psprintf(c->pool, "returned error %i", rc)
+                         : apr_psprintf(c->pool, "unexpected state %i",
+                                                 (int)cs->pub.state));
+        cs->pub.state = CONN_STATE_LINGER;
     }
 
     if (cs->pub.state == CONN_STATE_WRITE_COMPLETION) {
@@ -1046,10 +1078,20 @@ read_request:
              */
             cs->queue_timestamp = apr_time_now();
             notify_suspend(cs);
-            cs->pfd.reqevents = (
-                    cs->pub.sense == CONN_SENSE_WANT_READ ? APR_POLLIN :
-                            APR_POLLOUT) | APR_POLLHUP | APR_POLLERR;
+
+            if (cs->pub.sense == CONN_SENSE_WANT_READ) {
+                cs->pfd.reqevents = APR_POLLIN;
+            }
+            else {
+                cs->pfd.reqevents = APR_POLLOUT;
+            }
+            /* POLLHUP/ERR are usually returned event only (ignored here), but
+             * some pollset backends may require them in reqevents to do the
+             * right thing, so it shouldn't hurt.
+             */
+            cs->pfd.reqevents |= APR_POLLHUP | APR_POLLERR;
             cs->pub.sense = CONN_SENSE_DEFAULT;
+
             apr_thread_mutex_lock(timeout_mutex);
             TO_QUEUE_APPEND(cs->sc->wc_q, cs);
             rc = apr_pollset_add(event_pollset, &cs->pfd);