--- include/httpd.h.orig +++ include/httpd.h @@ -1175,12 +1175,20 @@ typedef enum { CONN_STATE_LINGER_SHORT /* MPM has started lingering close with short timeout */ } conn_state_e; +typedef enum { + CONN_SENSE_DEFAULT, + CONN_SENSE_WANT_READ, /* next event must be read */ + CONN_SENSE_WANT_WRITE /* next event must be write */ +} conn_sense_e; + /** * @brief A structure to contain connection state information */ struct conn_state_t { /** Current state of the connection */ conn_state_e state; + /** Whether to read instead of write, or write instead of read */ + conn_sense_e sense; }; /* Per-vhost config... */ --- modules/ssl/ssl_engine_io.c.orig +++ modules/ssl/ssl_engine_io.c @@ -775,6 +775,18 @@ static apr_status_t ssl_filter_write(ap_ */ outctx->rc = APR_EAGAIN; } + else if (ssl_err == SSL_ERROR_WANT_READ) { + /* + * If OpenSSL wants to read during write, and we were + * nonblocking, set the sense explicitly to read and + * report as an EAGAIN. + * + * (This is usually the case when the client forces an SSL + * renegotiation which is handled implicitly by OpenSSL.) + */ + outctx->c->cs->sense = CONN_SENSE_WANT_READ; + outctx->rc = APR_EAGAIN; + } else if (ssl_err == SSL_ERROR_SYSCALL) { ap_log_cerror(APLOG_MARK, APLOG_INFO, outctx->rc, c, APLOGNO(01993) "SSL output filter write failed."); @@ -1902,8 +1914,10 @@ void ssl_io_filter_init(conn_rec *c, req filter_ctx->pbioWrite = BIO_new(&bio_filter_out_method); filter_ctx->pbioWrite->ptr = (void *)bio_filter_out_ctx_new(filter_ctx, c); - /* We insert a clogging input filter. Let the core know. */ - c->clogging_input_filters = 1; + /* write is non blocking for the benefit of async mpm */ + if (c->cs) { + BIO_set_nbio(filter_ctx->pbioWrite, 1); + } ssl_io_input_add_filter(filter_ctx, c, r, ssl); --- server/mpm/event/event.c.orig +++ server/mpm/event/event.c @@ -790,7 +790,10 @@ static int start_lingering_close_common( apr_atomic_inc32(&lingering_count); apr_thread_mutex_lock(timeout_mutex); TO_QUEUE_APPEND(*q, cs); - cs->pfd.reqevents = APR_POLLIN | APR_POLLHUP | APR_POLLERR; + cs->pfd.reqevents = ( + cs->pub.sense == CONN_SENSE_WANT_WRITE ? APR_POLLOUT : + APR_POLLIN) | APR_POLLHUP | APR_POLLERR; + cs->pub.sense = CONN_SENSE_DEFAULT; rv = apr_pollset_add(event_pollset, &cs->pfd); apr_thread_mutex_unlock(timeout_mutex); if (rv != APR_SUCCESS && !APR_STATUS_IS_EEXIST(rv)) { @@ -938,6 +941,7 @@ static void process_socket(apr_thread_t */ cs->pub.state = CONN_STATE_READ_REQUEST_LINE; + cs->pub.sense = CONN_SENSE_DEFAULT; } else { c = cs->c; @@ -946,9 +950,11 @@ static void process_socket(apr_thread_t } if (c->clogging_input_filters && !c->aborted) { - /* Since we have an input filter which 'cloggs' the input stream, - * like mod_ssl, lets just do the normal read from input filters, - * like the Worker MPM does. + /* Since we have an input filter which 'clogs' the input stream, + * like mod_ssl used to, lets just do the normal read from input + * filters, like the Worker MPM does. Filters that need to write + * where they would otherwise read, or read where they would + * otherwise write, should set the sense appropriately. */ apr_atomic_inc32(&clogged_count); ap_run_process_connection(c); @@ -994,7 +1000,10 @@ read_request: cs->expiration_time = ap_server_conf->timeout + apr_time_now(); apr_thread_mutex_lock(timeout_mutex); TO_QUEUE_APPEND(write_completion_q, cs); - cs->pfd.reqevents = APR_POLLOUT | APR_POLLHUP | APR_POLLERR; + cs->pfd.reqevents = ( + cs->pub.sense == CONN_SENSE_WANT_READ ? APR_POLLIN : + APR_POLLOUT) | APR_POLLHUP | APR_POLLERR; + cs->pub.sense = CONN_SENSE_DEFAULT; rc = apr_pollset_add(event_pollset, &cs->pfd); apr_thread_mutex_unlock(timeout_mutex); return;