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,
* 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) {
*/
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);