diff options
-rw-r--r-- | CHANGES | 6 | ||||
-rw-r--r-- | changes-entries/ab-ssl-sense-fix.txt | 5 | ||||
-rw-r--r-- | include/ap_mmn.h | 2 | ||||
-rw-r--r-- | include/ap_mpm.h | 2 | ||||
-rw-r--r-- | include/httpd.h | 3 | ||||
-rw-r--r-- | include/scoreboard.h | 1 | ||||
-rw-r--r-- | modules/generators/mod_status.c | 15 | ||||
-rw-r--r-- | modules/ssl/mod_ssl.c | 76 | ||||
-rw-r--r-- | modules/ssl/ssl_engine_io.c | 53 | ||||
-rw-r--r-- | server/mpm/event/event.c | 106 | ||||
-rw-r--r-- | support/ab.c | 123 | ||||
-rw-r--r-- | test/modules/http2/test_105_timeout.py | 1 |
12 files changed, 81 insertions, 312 deletions
@@ -1,12 +1,6 @@ -*- coding: utf-8 -*- Changes with Apache 2.5.1 - *) event: Add support for non blocking behaviour in the - CONN_STATE_READ_REQUEST_LINE phase, in addition to the existing - CONN_STATE_WRITE_COMPLETION phase. Add AP_MPM_CAN_AGAIN and AGAIN to - signal to the MPM that non blocking behaviour is requested. Update - mod_ssl to perform non blocking TLS handshakes. [Graham Leggett] - *) http: Enforce that fully qualified uri-paths not to be forward-proxied have an http(s) scheme, and that the ones to be forward proxied have a hostname, per HTTP specifications. [Ruediger Pluem, Yann Ylavic] diff --git a/changes-entries/ab-ssl-sense-fix.txt b/changes-entries/ab-ssl-sense-fix.txt deleted file mode 100644 index 289498c7ab..0000000000 --- a/changes-entries/ab-ssl-sense-fix.txt +++ /dev/null @@ -1,5 +0,0 @@ - *) ab: Respond appropriately to SSL_ERROR_WANT_READ and SSL_ERROR_WANT_WRITE. - Previously the correct event was polled for, but the response to the poll - would call write instead of read, and read instead of write. PR 55952 - [Graham Leggett] - diff --git a/include/ap_mmn.h b/include/ap_mmn.h index 6060c766d7..4fda68b1b3 100644 --- a/include/ap_mmn.h +++ b/include/ap_mmn.h @@ -698,8 +698,6 @@ * 20210926.2 (2.5.1-dev) Add ap_post_read_request() * 20211221.0 (2.5.1-dev) Bump PROXY_WORKER_MAX_NAME_SIZE from 256 to 384, * add PROXY_WORKER_UDS_PATH_SIZE. - * 20211221.1 (2.5.1-dev) Add read_line to scoreboard. - * 20211221.2 (2.5.1-dev) Add AGAIN, AP_MPMQ_CAN_AGAIN. * 20211221.3 (2.5.1-dev) Add ap_thread_create(), ap_thread_main_create() * and ap_thread_current() * diff --git a/include/ap_mpm.h b/include/ap_mpm.h index 82075a4488..6698d0e7c6 100644 --- a/include/ap_mpm.h +++ b/include/ap_mpm.h @@ -182,8 +182,6 @@ AP_DECLARE(apr_status_t) ap_os_create_privileged_process( #define AP_MPMQ_CAN_SUSPEND 17 /** MPM supports additional pollfds */ #define AP_MPMQ_CAN_POLL 18 -/** MPM reacts to AGAIN response */ -#define AP_MPMQ_CAN_AGAIN 19 /** @} */ /** diff --git a/include/httpd.h b/include/httpd.h index 906bed6927..dfd0304093 100644 --- a/include/httpd.h +++ b/include/httpd.h @@ -465,9 +465,6 @@ AP_DECLARE(const char *) ap_get_server_built(void); */ #define SUSPENDED -3 /**< Module will handle the remainder of the request. * The core will never invoke the request again, */ -#define AGAIN -4 /**< Module wants to be called again when - * more data is availble. - */ /** Returned by the bottom-most filter if no data was written. * @see ap_pass_brigade(). */ diff --git a/include/scoreboard.h b/include/scoreboard.h index b0bdc6f13b..321b32778a 100644 --- a/include/scoreboard.h +++ b/include/scoreboard.h @@ -148,7 +148,6 @@ struct process_score { apr_uint32_t lingering_close; /* async connections in lingering close */ apr_uint32_t keep_alive; /* async connections in keep alive */ apr_uint32_t suspended; /* connections suspended by some module */ - apr_uint32_t read_line; /* async connections doing read line */ }; /* Scoreboard is now in 'local' memory, since it isn't updated once created, diff --git a/modules/generators/mod_status.c b/modules/generators/mod_status.c index 8707ebe58b..8e80202c44 100644 --- a/modules/generators/mod_status.c +++ b/modules/generators/mod_status.c @@ -557,7 +557,7 @@ static int status_handler(request_rec *r) ap_rputs("</dl>", r); if (is_async) { - int read_line = 0, write_completion = 0, lingering_close = 0, keep_alive = 0, + int write_completion = 0, lingering_close = 0, keep_alive = 0, connections = 0, stopping = 0, procs = 0; /* * These differ from 'busy' and 'ready' in how gracefully finishing @@ -574,12 +574,11 @@ static int status_handler(request_rec *r) "<th colspan=\"3\">Async connections</th></tr>\n" "<tr><th>total</th><th>accepting</th>" "<th>busy</th><th>idle</th>" - "<th>reading</th><th>writing</th><th>keep-alive</th><th>closing</th></tr>\n", r); + "<th>writing</th><th>keep-alive</th><th>closing</th></tr>\n", r); for (i = 0; i < server_limit; ++i) { ps_record = ap_get_scoreboard_process(i); if (ps_record->pid) { connections += ps_record->connections; - read_line += ps_record->read_line; write_completion += ps_record->write_completion; keep_alive += ps_record->keep_alive; lingering_close += ps_record->lingering_close; @@ -601,7 +600,7 @@ static int status_handler(request_rec *r) "<td>%s%s</td>" "<td>%u</td><td>%s</td>" "<td>%u</td><td>%u</td>" - "<td>%u</td><td>%u</td><td>%u</td><td>%u</td>" + "<td>%u</td><td>%u</td><td>%u</td>" "</tr>\n", i, ps_record->pid, dying, old, @@ -609,7 +608,6 @@ static int status_handler(request_rec *r) ps_record->not_accepting ? "no" : "yes", thread_busy_buffer[i], thread_idle_buffer[i], - ps_record->read_line, ps_record->write_completion, ps_record->keep_alive, ps_record->lingering_close); @@ -621,12 +619,12 @@ static int status_handler(request_rec *r) "<td>%d</td><td>%d</td>" "<td>%d</td><td> </td>" "<td>%d</td><td>%d</td>" - "<td>%d</td><td>%d</td><td>%d</td><td>%d</td>" + "<td>%d</td><td>%d</td><td>%d</td>" "</tr>\n</table>\n", procs, stopping, connections, busy_workers, idle_workers, - read_line, write_completion, keep_alive, lingering_close); + write_completion, keep_alive, lingering_close); } else { ap_rprintf(r, "Processes: %d\n" @@ -634,14 +632,13 @@ static int status_handler(request_rec *r) "BusyWorkers: %d\n" "IdleWorkers: %d\n" "ConnsTotal: %d\n" - "ConnsAsyncReading: %d\n" "ConnsAsyncWriting: %d\n" "ConnsAsyncKeepAlive: %d\n" "ConnsAsyncClosing: %d\n", procs, stopping, busy_workers, idle_workers, connections, - read_line, write_completion, keep_alive, lingering_close); + write_completion, keep_alive, lingering_close); } } diff --git a/modules/ssl/mod_ssl.c b/modules/ssl/mod_ssl.c index b06c7beabe..d1f6fbbc1f 100644 --- a/modules/ssl/mod_ssl.c +++ b/modules/ssl/mod_ssl.c @@ -30,7 +30,6 @@ #include "util_md5.h" #include "util_mutex.h" #include "ap_provider.h" -#include "ap_mpm.h" #include "http_config.h" #include "mod_proxy.h" /* for proxy_hook_section_post_config() */ @@ -690,80 +689,31 @@ static int ssl_hook_process_connection(conn_rec* c) { SSLConnRec *sslconn = myConnConfig(c); - int status = DECLINED; - if (sslconn && !sslconn->disabled) { /* On an active SSL connection, let the input filters initialize * themselves which triggers the handshake, which again triggers * all kinds of useful things such as SNI and ALPN. */ apr_bucket_brigade* temp; - - int again_mpm = 0; + apr_status_t rv; temp = apr_brigade_create(c->pool, c->bucket_alloc); + rv = ap_get_brigade(c->input_filters, temp, + AP_MODE_INIT, APR_BLOCK_READ, 0); + apr_brigade_destroy(temp); - if (ap_mpm_query(AP_MPMQ_CAN_AGAIN, &again_mpm) != APR_SUCCESS) { - again_mpm = 0; - } - - if (again_mpm) { - - /* Take advantage of an async MPM. If we see an EAGAIN, - * loop round and don't block. - */ - conn_state_t *cs = c->cs; - - apr_status_t rv; - - rv = ap_get_brigade(c->input_filters, temp, - AP_MODE_INIT, APR_NONBLOCK_READ, 0); - - if (rv == APR_SUCCESS) { - /* great news, lets continue */ - - ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, APLOGNO(10370) - "SSL handshake completed, continuing"); - - status = DECLINED; - } - else if (rv == APR_EAGAIN) { - /* we've been asked to come around again, don't block */ - - ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, APLOGNO(10371) - "SSL handshake in progress, continuing"); - - status = AGAIN; - } - else if (rv == AP_FILTER_ERROR) { - /* handshake error, but mod_ssl handled it */ - - ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, APLOGNO(10372) - "SSL handshake failed, returning error response"); - - status = DECLINED; - } - else { - /* we failed, give up */ - - cs->state = CONN_STATE_LINGER; - - ap_log_cerror(APLOG_MARK, APLOG_ERR, rv, c, APLOGNO(10373) - "SSL handshake was not completed, " - "closing connection"); - - status = OK; + if (APR_SUCCESS != APR_SUCCESS) { + if (c->cs) { + c->cs->state = CONN_STATE_LINGER; } + ap_log_cerror(APLOG_MARK, APLOG_ERR, rv, c, APLOGNO(10373) + "SSL handshake was not completed, " + "closing connection"); + return OK; } - else { - ap_get_brigade(c->input_filters, temp, - AP_MODE_INIT, APR_BLOCK_READ, 0); - } - - apr_brigade_destroy(temp); } - - return status; + + return DECLINED; } /* diff --git a/modules/ssl/ssl_engine_io.c b/modules/ssl/ssl_engine_io.c index 4445b1f787..47e3f30cdc 100644 --- a/modules/ssl/ssl_engine_io.c +++ b/modules/ssl/ssl_engine_io.c @@ -323,7 +323,6 @@ typedef struct { } char_buffer_t; typedef struct { - conn_rec *c; SSL *ssl; BIO *bio_out; ap_filter_t *f; @@ -796,32 +795,6 @@ static apr_status_t ssl_io_input_read(bio_filter_in_ctx_t *inctx, * (This is usually the case when the client forces an SSL * renegotiation which is handled implicitly by OpenSSL.) */ - if (inctx->c->cs) { - inctx->c->cs->sense = CONN_SENSE_WANT_READ; - } - inctx->rc = APR_EAGAIN; - - if (*len > 0) { - inctx->rc = APR_SUCCESS; - break; - } - if (inctx->block == APR_NONBLOCK_READ) { - break; - } - continue; /* Blocking and nothing yet? Try again. */ - } - if (ssl_err == SSL_ERROR_WANT_WRITE) { - /* - * If OpenSSL wants to write during read, and we were - * nonblocking, report as an EAGAIN. Otherwise loop, - * pulling more data from network filter. - * - * (This is usually the case when the client forces an SSL - * renegotiation which is handled implicitly by OpenSSL.) - */ - if (inctx->c->cs) { - inctx->c->cs->sense = CONN_SENSE_WANT_WRITE; - } inctx->rc = APR_EAGAIN; if (*len > 0) { @@ -987,9 +960,7 @@ static apr_status_t ssl_filter_write(ap_filter_t *f, * (This is usually the case when the client forces an SSL * renegotiation which is handled implicitly by OpenSSL.) */ - if (outctx->c->cs) { - outctx->c->cs->sense = CONN_SENSE_WANT_READ; - } + outctx->c->cs->sense = CONN_SENSE_WANT_READ; outctx->rc = APR_EAGAIN; ap_log_cerror(APLOG_MARK, APLOG_TRACE6, 0, outctx->c, "Want read during nonblocking write"); @@ -1518,25 +1489,10 @@ static apr_status_t ssl_io_filter_handshake(ssl_filter_ctx_t *filter_ctx) } else if (ssl_err == SSL_ERROR_WANT_READ) { /* - * Call us back when ready to read *\/ + * This is in addition to what was present earlier. It is + * borrowed from openssl_state_machine.c [mod_tls]. + * TBD. */ - ap_log_cerror(APLOG_MARK, APLOG_TRACE6, 0, outctx->c, - "Want read during nonblocking accept"); - if (outctx->c->cs) { - outctx->c->cs->sense = CONN_SENSE_WANT_READ; - } - outctx->rc = APR_EAGAIN; - return APR_EAGAIN; - } - else if (ssl_err == SSL_ERROR_WANT_WRITE) { - /* - * Call us back when ready to write *\/ - */ - ap_log_cerror(APLOG_MARK, APLOG_TRACE6, 0, outctx->c, - "Want write during nonblocking accept"); - if (outctx->c->cs) { - outctx->c->cs->sense = CONN_SENSE_WANT_WRITE; - } outctx->rc = APR_EAGAIN; return APR_EAGAIN; } @@ -2339,7 +2295,6 @@ static apr_status_t ssl_io_input_add_filter(ssl_filter_ctx_t *filter_ctx, conn_r } BIO_set_data(filter_ctx->pbioRead, (void *)inctx); - inctx->c = c; inctx->ssl = ssl; inctx->bio_out = filter_ctx->pbioWrite; inctx->f = filter_ctx->pInputFilter; diff --git a/server/mpm/event/event.c b/server/mpm/event/event.c index aab61ac11d..9e0eeca0fb 100644 --- a/server/mpm/event/event.c +++ b/server/mpm/event/event.c @@ -268,14 +268,12 @@ struct timeout_queue { /* * Several timeout queues that use different timeouts, so that we always can * simply append to the end. - * read_line_q uses vhost's TimeOut FIXME - we can use a short timeout here * write_completion_q uses vhost's TimeOut * keepalive_q uses vhost's KeepAliveTimeOut * linger_q uses MAX_SECS_TO_LINGER * short_linger_q uses SECONDS_TO_LINGER */ -static struct timeout_queue *read_line_q, - *write_completion_q, +static struct timeout_queue *write_completion_q, *keepalive_q, *linger_q, *short_linger_q; @@ -448,8 +446,7 @@ static event_retained_data *retained; static int max_spawn_rate_per_bucket = MAX_SPAWN_RATE / 1; struct event_srv_cfg_s { - struct timeout_queue *rl_q, - *wc_q, + struct timeout_queue *wc_q, *ka_q; }; @@ -734,9 +731,6 @@ static int event_query(int query_code, int *result, apr_status_t *rv) case AP_MPMQ_CAN_POLL: *result = 1; break; - case AP_MPMQ_CAN_AGAIN: - *result = 1; - break; default: *rv = APR_ENOTIMPL; break; @@ -985,19 +979,15 @@ static void process_lingering_close(event_conn_state_t *cs); static void update_reqevents_from_sense(event_conn_state_t *cs, int sense) { - /* has the desired sense been overridden? */ - if (cs->pub.sense != CONN_SENSE_DEFAULT) { + if (sense < 0) { sense = cs->pub.sense; } - - /* read or write */ if (sense == CONN_SENSE_WANT_READ) { cs->pfd.reqevents = APR_POLLIN | APR_POLLHUP; } - else if (sense == CONN_SENSE_WANT_WRITE) { + else { cs->pfd.reqevents = APR_POLLOUT; } - /* POLLERR is usually returned event only, but some pollset * backends may require it in reqevents to do the right thing, * so it shouldn't hurt (ignored otherwise). @@ -1044,7 +1034,6 @@ static void process_socket(apr_thread_t *thd, apr_pool_t * p, apr_socket_t * soc &mpm_event_module); cs->pfd.desc_type = APR_POLL_SOCKET; cs->pfd.desc.s = sock; - cs->pub.sense = CONN_SENSE_DEFAULT; update_reqevents_from_sense(cs, CONN_SENSE_WANT_READ); pt->type = PT_CSD; pt->baton = cs; @@ -1075,6 +1064,7 @@ static void process_socket(apr_thread_t *thd, apr_pool_t * p, apr_socket_t * soc */ cs->pub.state = CONN_STATE_READ_REQUEST_LINE; + cs->pub.sense = CONN_SENSE_DEFAULT; rc = OK; } else { @@ -1125,8 +1115,6 @@ read_request: /* * The process_connection hooks above should set the connection state * appropriately upon return, for event MPM to either: - * - call the hooks again after waiting for a read or write, or react to an - * overridden CONN_SENSE_WANT_READ / CONN_SENSE_WANT_WRITE. * - do lingering close (CONN_STATE_LINGER), * - wait for readability of the next request with respect to the keepalive * timeout (state CONN_STATE_CHECK_REQUEST_LINE_READABLE), @@ -1152,12 +1140,11 @@ read_request: * while this was expected to do lingering close unconditionally with * worker or prefork MPMs for instance. */ - if (rc != AGAIN && ( - rc != OK || (cs->pub.state >= CONN_STATE_NUM) + if (rc != OK || (cs->pub.state >= CONN_STATE_NUM) || (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))) { + && 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) @@ -1166,41 +1153,6 @@ read_request: cs->pub.state = CONN_STATE_LINGER; } - if (cs->pub.state == CONN_STATE_READ_REQUEST_LINE) { - ap_update_child_status(cs->sbh, SERVER_BUSY_READ, NULL); - - /* It greatly simplifies the logic to use a single timeout value per q - * because the new element can just be added to the end of the list and - * it will stay sorted in expiration time sequence. If brand new - * sockets are sent to the event thread for a readability check, this - * will be a slight behavior change - they use the non-keepalive - * timeout today. With a normal client, the socket will be readable in - * a few milliseconds anyway. - */ - cs->queue_timestamp = apr_time_now(); - notify_suspend(cs); - - /* Add work to pollset. */ - update_reqevents_from_sense(cs, CONN_SENSE_WANT_READ); - apr_thread_mutex_lock(timeout_mutex); - TO_QUEUE_APPEND(cs->sc->rl_q, cs); - rv = apr_pollset_add(event_pollset, &cs->pfd); - if (rv != APR_SUCCESS && !APR_STATUS_IS_EEXIST(rv)) { - AP_DEBUG_ASSERT(0); - TO_QUEUE_REMOVE(cs->sc->rl_q, cs); - apr_thread_mutex_unlock(timeout_mutex); - ap_log_error(APLOG_MARK, APLOG_ERR, rv, ap_server_conf, APLOGNO(10374) - "process_socket: apr_pollset_add failure for " - "read request line"); - close_connection(cs); - signal_threads(ST_GRACEFUL); - } - else { - apr_thread_mutex_unlock(timeout_mutex); - } - return; - } - if (cs->pub.state == CONN_STATE_WRITE_COMPLETION) { int pending = DECLINED; @@ -1222,7 +1174,7 @@ read_request: cs->queue_timestamp = apr_time_now(); notify_suspend(cs); - update_reqevents_from_sense(cs, CONN_SENSE_WANT_WRITE); + update_reqevents_from_sense(cs, -1); apr_thread_mutex_lock(timeout_mutex); TO_QUEUE_APPEND(cs->sc->wc_q, cs); rv = apr_pollset_add(event_pollset, &cs->pfd); @@ -1328,7 +1280,7 @@ static apr_status_t event_resume_suspended (conn_rec *c) cs->pub.state = CONN_STATE_WRITE_COMPLETION; notify_suspend(cs); - update_reqevents_from_sense(cs, CONN_SENSE_WANT_WRITE); + update_reqevents_from_sense(cs, -1); apr_thread_mutex_lock(timeout_mutex); TO_QUEUE_APPEND(cs->sc->wc_q, cs); apr_pollset_add(event_pollset, &cs->pfd); @@ -1786,7 +1738,6 @@ static void process_lingering_close(event_conn_state_t *cs) } /* (Re)queue the connection to come back when readable */ - cs->pub.sense = CONN_SENSE_DEFAULT; update_reqevents_from_sense(cs, CONN_SENSE_WANT_READ); q = (cs->pub.state == CONN_STATE_LINGER_SHORT) ? short_linger_q : linger_q; apr_thread_mutex_lock(timeout_mutex); @@ -1960,11 +1911,10 @@ static void * APR_THREAD_FUNC listener_thread(apr_thread_t * thd, void *dummy) last_log = now; apr_thread_mutex_lock(timeout_mutex); ap_log_error(APLOG_MARK, APLOG_TRACE6, 0, ap_server_conf, - "connections: %u (clogged: %u read-line: %d write-completion: %d " + "connections: %u (clogged: %u write-completion: %d " "keep-alive: %d lingering: %d suspended: %u)", apr_atomic_read32(&connection_count), apr_atomic_read32(&clogged_count), - apr_atomic_read32(read_line_q->total), apr_atomic_read32(write_completion_q->total), apr_atomic_read32(keepalive_q->total), apr_atomic_read32(&lingering_count), @@ -2097,11 +2047,6 @@ static void * APR_THREAD_FUNC listener_thread(apr_thread_t * thd, void *dummy) int blocking = 0; switch (cs->pub.state) { - case CONN_STATE_READ_REQUEST_LINE: - remove_from_q = cs->sc->rl_q; - blocking = 1; - break; - case CONN_STATE_WRITE_COMPLETION: remove_from_q = cs->sc->wc_q; blocking = 1; @@ -2318,19 +2263,16 @@ do_maintenance: else { process_keepalive_queue(now); } - /* Step 2: read line timeouts */ - process_timeout_queue(read_line_q, now, - shutdown_connection); - /* Step 3: write completion timeouts */ + /* Step 2: write completion timeouts */ process_timeout_queue(write_completion_q, now, defer_lingering_close); - /* Step 4: (normal) lingering close completion timeouts */ + /* Step 3: (normal) lingering close completion timeouts */ if (dying && linger_q->timeout > short_linger_q->timeout) { /* Dying, force short timeout for normal lingering close */ linger_q->timeout = short_linger_q->timeout; } process_timeout_queue(linger_q, now, shutdown_connection); - /* Step 5: (short) lingering close completion timeouts */ + /* Step 4: (short) lingering close completion timeouts */ process_timeout_queue(short_linger_q, now, shutdown_connection); apr_thread_mutex_unlock(timeout_mutex); @@ -2340,7 +2282,6 @@ do_maintenance: : -1); ps->keep_alive = apr_atomic_read32(keepalive_q->total); - ps->read_line = apr_atomic_read32(read_line_q->total); ps->write_completion = apr_atomic_read32(write_completion_q->total); ps->connections = apr_atomic_read32(&connection_count); ps->suspended = apr_atomic_read32(&suspended_count); @@ -3969,15 +3910,14 @@ static int event_post_config(apr_pool_t *pconf, apr_pool_t *plog, struct { struct timeout_queue *tail, *q; apr_hash_t *hash; - } rl, wc, ka; + } wc, ka; /* Not needed in pre_config stage */ if (ap_state_query(AP_SQ_MAIN_STATE) == AP_SQ_MS_CREATE_PRE_CONFIG) { return OK; } - rl.tail = wc.tail = ka.tail = NULL; - rl.hash = apr_hash_make(ptemp); + wc.tail = ka.tail = NULL; wc.hash = apr_hash_make(ptemp); ka.hash = apr_hash_make(ptemp); @@ -3991,13 +3931,7 @@ static int event_post_config(apr_pool_t *pconf, apr_pool_t *plog, ap_set_module_config(s->module_config, &mpm_event_module, sc); if (!wc.tail) { - /* The main server uses the global queues */ - - rl.q = TO_QUEUE_MAKE(pconf, s->timeout, NULL); - apr_hash_set(rl.hash, &s->timeout, sizeof s->timeout, rl.q); - rl.tail = read_line_q = rl.q; - wc.q = TO_QUEUE_MAKE(pconf, s->timeout, NULL); apr_hash_set(wc.hash, &s->timeout, sizeof s->timeout, wc.q); wc.tail = write_completion_q = wc.q; @@ -4008,17 +3942,8 @@ static int event_post_config(apr_pool_t *pconf, apr_pool_t *plog, ka.tail = keepalive_q = ka.q; } else { - /* The vhosts use any existing queue with the same timeout, * or their own queue(s) if there isn't */ - - rl.q = apr_hash_get(rl.hash, &s->timeout, sizeof s->timeout); - if (!rl.q) { - rl.q = TO_QUEUE_MAKE(pconf, s->timeout, rl.tail); - apr_hash_set(rl.hash, &s->timeout, sizeof s->timeout, rl.q); - rl.tail = rl.tail->next = rl.q; - } - wc.q = apr_hash_get(wc.hash, &s->timeout, sizeof s->timeout); if (!wc.q) { wc.q = TO_QUEUE_MAKE(pconf, s->timeout, wc.tail); @@ -4035,7 +3960,6 @@ static int event_post_config(apr_pool_t *pconf, apr_pool_t *plog, ka.tail = ka.tail->next = ka.q; } } - sc->rl_q = rl.q; sc->wc_q = wc.q; sc->ka_q = ka.q; } diff --git a/support/ab.c b/support/ab.c index 20de3a844c..38715ebd2d 100644 --- a/support/ab.c +++ b/support/ab.c @@ -237,11 +237,7 @@ typedef enum { * know if it worked yet */ STATE_CONNECTED, /* we know TCP connect completed */ -#ifdef USE_SSL - STATE_HANDSHAKE, /* in the handshake phase */ -#endif - STATE_WRITE, /* in the write phase */ - STATE_READ /* in the read phase */ + STATE_READ } connect_state_e; #define CBUFFSIZE (8192) @@ -524,13 +520,21 @@ static void set_polled_events(struct connection *c, apr_int16_t new_reqevents) } } -static void set_conn_state(struct connection *c, connect_state_e new_state, - apr_int16_t events) +static void set_conn_state(struct connection *c, connect_state_e new_state) { + apr_int16_t events_by_state[] = { + 0, /* for STATE_UNCONNECTED */ + APR_POLLOUT, /* for STATE_CONNECTING */ + APR_POLLIN, /* for STATE_CONNECTED; we don't poll in this state, + * so prepare for polling in the following state -- + * STATE_READ + */ + APR_POLLIN /* for STATE_READ */ + }; c->state = new_state; - set_polled_events(c, events); + set_polled_events(c, events_by_state[new_state]); } /* --------------------------------------------------------- */ @@ -703,7 +707,7 @@ static void ssl_print_info(struct connection *c) } ssl_print_connection_info(bio_err,c->ssl); SSL_SESSION_print(bio_err, SSL_get_session(c->ssl)); -} + } static void ssl_proceed_handshake(struct connection *c) { @@ -779,19 +783,14 @@ static void ssl_proceed_handshake(struct connection *c) } #endif write_request(c); - do_next = 0; break; case SSL_ERROR_WANT_READ: - - set_conn_state(c, STATE_HANDSHAKE, APR_POLLIN); - + set_polled_events(c, APR_POLLIN); do_next = 0; break; case SSL_ERROR_WANT_WRITE: - - set_conn_state(c, STATE_HANDSHAKE, APR_POLLOUT); - + set_polled_events(c, APR_POLLOUT); do_next = 0; break; case SSL_ERROR_WANT_CONNECT: @@ -811,6 +810,9 @@ static void ssl_proceed_handshake(struct connection *c) static void write_request(struct connection * c) { + if (started >= requests) { + return; + } do { apr_time_t tnow; @@ -843,14 +845,10 @@ static void write_request(struct connection * c) if (e <= 0) { switch (SSL_get_error(c->ssl, e)) { case SSL_ERROR_WANT_READ: - - set_conn_state(c, STATE_WRITE, APR_POLLIN); - + set_polled_events(c, APR_POLLIN); break; case SSL_ERROR_WANT_WRITE: - - set_conn_state(c, STATE_WRITE, APR_POLLOUT); - + set_polled_events(c, APR_POLLOUT); break; default: BIO_printf(bio_err, "SSL write failed - closing connection\n"); @@ -873,7 +871,7 @@ static void write_request(struct connection * c) close_connection(c); } else { - set_conn_state(c, STATE_WRITE, APR_POLLOUT); + set_polled_events(c, APR_POLLOUT); } return; } @@ -885,8 +883,7 @@ static void write_request(struct connection * c) c->endwrite = lasttime = apr_time_now(); started++; - - set_conn_state(c, STATE_READ, APR_POLLIN); + set_conn_state(c, STATE_READ); } /* --------------------------------------------------------- */ @@ -1358,9 +1355,8 @@ static void start_connect(struct connection * c) { apr_status_t rv; - if (!(started < requests)) { + if (!(started < requests)) return; - } c->read = 0; c->bread = 0; @@ -1443,12 +1439,12 @@ static void start_connect(struct connection * c) #endif if ((rv = apr_socket_connect(c->aprsock, destsa)) != APR_SUCCESS) { if (APR_STATUS_IS_EINPROGRESS(rv)) { - set_conn_state(c, STATE_CONNECTING, APR_POLLOUT); + set_conn_state(c, STATE_CONNECTING); c->rwrite = 0; return; } else { - set_conn_state(c, STATE_UNCONNECTED, 0); + set_conn_state(c, STATE_UNCONNECTED); apr_socket_close(c->aprsock); if (good == 0 && destsa->next) { destsa = destsa->next; @@ -1469,6 +1465,7 @@ static void start_connect(struct connection * c) } /* connected first time */ + set_conn_state(c, STATE_CONNECTED); #ifdef USE_SSL if (c->ssl) { ssl_proceed_handshake(c); @@ -1516,7 +1513,7 @@ static void close_connection(struct connection * c) } } - set_conn_state(c, STATE_UNCONNECTED, 0); + set_conn_state(c, STATE_UNCONNECTED); #ifdef USE_SSL if (c->ssl) { SSL_shutdown(c->ssl); @@ -1574,14 +1571,10 @@ read_more: return; } else if (scode == SSL_ERROR_WANT_READ) { - - set_conn_state(c, STATE_READ, APR_POLLIN); - + set_polled_events(c, APR_POLLIN); } else if (scode == SSL_ERROR_WANT_WRITE) { - - set_conn_state(c, STATE_READ, APR_POLLOUT); - + set_polled_events(c, APR_POLLOUT); } else { /* some fatal error: */ @@ -1675,7 +1668,7 @@ read_more: } else { /* header is in invalid or too big - close connection */ - set_conn_state(c, STATE_UNCONNECTED, 0); + set_conn_state(c, STATE_UNCONNECTED); apr_socket_close(c->aprsock); err_response++; if (bad++ > 10) { @@ -1765,13 +1758,7 @@ read_more: goto read_more; } - /* are we done? */ - if (started >= requests && (c->bread >= c->length)) { - close_connection(c); - } - - /* are we keepalive? if so, reuse existing connection */ - else if (c->keepalive && (c->bread >= c->length)) { + if (c->keepalive && (c->bread >= c->length)) { /* finished a keep-alive connection */ good++; /* save out time */ @@ -1803,7 +1790,7 @@ read_more: c->read = c->bread = 0; /* zero connect time with keep-alive */ c->start = c->connect = lasttime = apr_time_now(); - + set_conn_state(c, STATE_CONNECTED); write_request(c); } } @@ -1993,7 +1980,6 @@ static void test(void) do { status = apr_pollset_poll(readbits, aprtimeout, &n, &pollresults); } while (APR_STATUS_IS_EINTR(status)); - if (status != APR_SUCCESS) apr_err("apr_pollset_poll", status); @@ -2029,23 +2015,8 @@ static void test(void) * connection is done and we loop here endlessly calling * apr_poll(). */ - if ((rtnev & APR_POLLIN) || (rtnev & APR_POLLPRI) || (rtnev & APR_POLLHUP)) { - - switch (c->state) { -#ifdef USE_SSL - case STATE_HANDSHAKE: - ssl_proceed_handshake(c); - break; -#endif - case STATE_WRITE: - write_request(c); - break; - case STATE_READ: - read_connection(c); - break; - } - - } + if ((rtnev & APR_POLLIN) || (rtnev & APR_POLLPRI) || (rtnev & APR_POLLHUP)) + read_connection(c); if ((rtnev & APR_POLLERR) || (rtnev & APR_POLLNVAL)) { if (destsa->next && c->state == STATE_CONNECTING && good == 0) { destsa = destsa->next; @@ -2069,7 +2040,7 @@ static void test(void) /* call connect() again to detect errors */ rv = apr_socket_connect(c->aprsock, destsa); if (rv != APR_SUCCESS) { - set_conn_state(c, STATE_UNCONNECTED, 0); + set_conn_state(c, STATE_UNCONNECTED); apr_socket_close(c->aprsock); err_conn++; if (bad++ > 10) { @@ -2081,7 +2052,7 @@ static void test(void) continue; } else { - + set_conn_state(c, STATE_CONNECTED); #ifdef USE_SSL if (c->ssl) ssl_proceed_handshake(c); @@ -2089,24 +2060,16 @@ static void test(void) #endif write_request(c); } - } else { - - switch (c->state) { -#ifdef USE_SSL - case STATE_HANDSHAKE: - ssl_proceed_handshake(c); - break; -#endif - case STATE_WRITE: - write_request(c); - break; - case STATE_READ: + /* POLLOUT is one shot */ + set_polled_events(c, APR_POLLIN); + if (c->state == STATE_READ) { read_connection(c); - break; } - + else { + write_request(c); + } } } } @@ -2729,7 +2692,7 @@ int main(int argc, const char * const argv[]) if (ssl_cert != NULL) { if (SSL_CTX_use_certificate_chain_file(ssl_ctx, ssl_cert) <= 0) { BIO_printf(bio_err, "unable to get certificate from '%s'\n", - ssl_cert); + ssl_cert); ERR_print_errors(bio_err); exit(1); } diff --git a/test/modules/http2/test_105_timeout.py b/test/modules/http2/test_105_timeout.py index 3b030cdd0d..24133ae52c 100644 --- a/test/modules/http2/test_105_timeout.py +++ b/test/modules/http2/test_105_timeout.py @@ -44,7 +44,6 @@ class TestTimeout: sock.close() # Check that mod_reqtimeout handshake setting takes effect - @pytest.mark.skip(reason="SSL handshake timeout currently broken") def test_h2_105_02(self, env): conf = H2Conf(env) conf.add(""" |