From aca9d45adf4fa0f98b98641ef515882580c0f1f9 Mon Sep 17 00:00:00 2001 From: Glenn Strauss Date: Fri, 10 Jan 2020 00:17:12 -0500 Subject: [PATCH] [core] move request state into (request_st *) NB: in the future, a separate connection state may be needed for connection-level state (different from request state) --- src/base.h | 18 -------------- src/connections-glue.c | 12 ++++----- src/connections.c | 56 +++++++++++++++++++++--------------------- src/connections.h | 4 +-- src/gw_backend.c | 2 +- src/http-header-glue.c | 2 +- src/mod_accesslog.c | 2 +- src/mod_evasive.c | 2 +- src/mod_status.c | 14 +++++------ src/mod_webdav.c | 8 +++--- src/request.h | 17 +++++++++++++ 11 files changed, 68 insertions(+), 69 deletions(-) diff --git a/src/base.h b/src/base.h index 8040ed49..9299a57a 100644 --- a/src/base.h +++ b/src/base.h @@ -50,25 +50,7 @@ typedef struct { buffer *etag; } physical; -/* the order of the items should be the same as they are processed - * read before write as we use this later */ -typedef enum { - CON_STATE_CONNECT, - CON_STATE_REQUEST_START, - CON_STATE_READ, - CON_STATE_REQUEST_END, - CON_STATE_READ_POST, - CON_STATE_HANDLE_REQUEST, - CON_STATE_RESPONSE_START, - CON_STATE_WRITE, - CON_STATE_RESPONSE_END, - CON_STATE_ERROR, - CON_STATE_CLOSE -} connection_state_t; - struct connection { - connection_state_t state; - /* timestamps */ time_t read_idle_ts; time_t close_timeout_ts; diff --git a/src/connections-glue.c b/src/connections-glue.c index d4b9b1e3..c875851e 100644 --- a/src/connections-glue.c +++ b/src/connections-glue.c @@ -12,7 +12,7 @@ #include #include -const char *connection_get_state(connection_state_t state) { +const char *connection_get_state(request_state_t state) { switch (state) { case CON_STATE_CONNECT: return "connect"; case CON_STATE_READ: return "read"; @@ -29,7 +29,7 @@ const char *connection_get_state(connection_state_t state) { } } -const char *connection_get_short_state(connection_state_t state) { +const char *connection_get_short_state(request_state_t state) { switch (state) { case CON_STATE_CONNECT: return "."; case CON_STATE_READ: return "r"; @@ -394,7 +394,7 @@ static int connection_write_100_continue(connection *con) { *(con->conf.global_bytes_per_second_cnt_ptr) += written; if (rc < 0) { - con->state = CON_STATE_ERROR; + con->request.state = CON_STATE_ERROR; return 0; /* error */ } @@ -423,7 +423,7 @@ handler_t connection_handle_read_post_state(connection *con) { switch(con->network_read(con, con->read_queue, MAX_READ_LIMIT)) { case -1: - con->state = CON_STATE_ERROR; + con->request.state = CON_STATE_ERROR; return HANDLER_ERROR; case -2: is_closed = 1; @@ -470,8 +470,8 @@ handler_t connection_handle_read_post_state(connection *con) { if (dst_cq->bytes_in == (off_t)con->request.reqbody_length) { /* Content is ready */ con->conf.stream_request_body &= ~FDEVENT_STREAM_REQUEST_POLLIN; - if (con->state == CON_STATE_READ_POST) { - con->state = CON_STATE_HANDLE_REQUEST; + if (con->request.state == CON_STATE_READ_POST) { + con->request.state = CON_STATE_HANDLE_REQUEST; } return HANDLER_GO_ON; } else if (is_closed) { diff --git a/src/connections.c b/src/connections.c index 48f9085d..46339ec6 100644 --- a/src/connections.c +++ b/src/connections.c @@ -34,7 +34,7 @@ #define HTTP_LINGER_TIMEOUT 5 -#define connection_set_state(con, n) ((con)->state = (n)) +#define connection_set_state(con, n) ((con)->request.state = (n)) __attribute_cold__ static connection *connection_init(server *srv); @@ -227,10 +227,10 @@ static void connection_handle_response_end_state(connection *con) { plugins_call_handle_request_done(con); } - if (con->state != CON_STATE_ERROR) ++con->srv->con_written; + if (con->request.state != CON_STATE_ERROR) ++con->srv->con_written; if (con->request.reqbody_length != con->request.reqbody_queue->bytes_in - || con->state == CON_STATE_ERROR) { + || con->request.state == CON_STATE_ERROR) { /* request body is present and has not been read completely */ con->request.keep_alive = 0; } @@ -490,7 +490,7 @@ static void connection_handle_write_state(connection *con) { if (!chunkqueue_is_empty(con->write_queue)) { if (con->is_writable) { connection_handle_write(con); - if (con->state != CON_STATE_WRITE) break; + if (con->request.state != CON_STATE_WRITE) break; } } else if (con->response.resp_body_finished) { connection_set_state(con, CON_STATE_RESPONSE_END); @@ -518,7 +518,7 @@ static void connection_handle_write_state(connection *con) { break; } } - } while (con->state == CON_STATE_WRITE + } while (con->request.state == CON_STATE_WRITE && (!chunkqueue_is_empty(con->write_queue) ? con->is_writable : con->response.resp_body_finished)); @@ -888,17 +888,17 @@ static handler_t connection_handle_fdevent(void *context, int revents) { } - if (con->state == CON_STATE_READ) { + if (con->request.state == CON_STATE_READ) { connection_handle_read_state(con); } - if (con->state == CON_STATE_WRITE && + if (con->request.state == CON_STATE_WRITE && !chunkqueue_is_empty(con->write_queue) && con->is_writable) { connection_handle_write(con); } - if (con->state == CON_STATE_CLOSE) { + if (con->request.state == CON_STATE_CLOSE) { /* flush the read buffers */ connection_read_for_eos(con); } @@ -907,8 +907,8 @@ static handler_t connection_handle_fdevent(void *context, int revents) { /* attempt (above) to read data in kernel socket buffers * prior to handling FDEVENT_HUP and FDEVENT_ERR */ - if ((revents & ~(FDEVENT_IN | FDEVENT_OUT)) && con->state != CON_STATE_ERROR) { - if (con->state == CON_STATE_CLOSE) { + if ((revents & ~(FDEVENT_IN | FDEVENT_OUT)) && con->request.state != CON_STATE_ERROR) { + if (con->request.state == CON_STATE_CLOSE) { con->close_timeout_ts = log_epoch_secs - (HTTP_LINGER_TIMEOUT+1); } else if (revents & FDEVENT_HUP) { connection_set_state(con, CON_STATE_ERROR); @@ -1243,22 +1243,22 @@ static int connection_handle_request(connection *con) { int connection_state_machine(connection *con) { - connection_state_t ostate; + request_state_t ostate; int rc; const int log_state_handling = con->conf.log_state_handling; if (log_state_handling) { log_error(con->conf.errh, __FILE__, __LINE__, - "state at enter %d %s", con->fd, connection_get_state(con->state)); + "state at enter %d %s", con->fd, connection_get_state(con->request.state)); } do { if (log_state_handling) { log_error(con->conf.errh, __FILE__, __LINE__, - "state for fd %d %s", con->fd, connection_get_state(con->state)); + "state for fd %d %s", con->fd, connection_get_state(con->request.state)); } - switch ((ostate = con->state)) { + switch ((ostate = con->request.state)) { case CON_STATE_REQUEST_START: /* transient */ con->request.start_ts = con->read_idle_ts = log_epoch_secs; if (con->conf.high_precision_timestamps) @@ -1271,7 +1271,7 @@ int connection_state_machine(connection *con) { /* fall through */ case CON_STATE_READ: if (!connection_handle_read_state(con)) break; - /*if (con->state != CON_STATE_REQUEST_END) break;*/ + /*if (con->request.state != CON_STATE_REQUEST_END) break;*/ /* fall through */ case CON_STATE_REQUEST_END: /* transient */ ostate = (0 == con->request.reqbody_length) @@ -1282,17 +1282,17 @@ int connection_state_machine(connection *con) { case CON_STATE_READ_POST: case CON_STATE_HANDLE_REQUEST: if (connection_handle_request(con)) { - /* redo loop; will not match con->state */ + /* redo loop; will not match con->request.state */ ostate = CON_STATE_CONNECT; break; } - if (con->state == CON_STATE_HANDLE_REQUEST + if (con->request.state == CON_STATE_HANDLE_REQUEST && ostate == CON_STATE_READ_POST) { ostate = CON_STATE_HANDLE_REQUEST; } - if (con->state != CON_STATE_RESPONSE_START) break; + if (con->request.state != CON_STATE_RESPONSE_START) break; /* fall through */ case CON_STATE_RESPONSE_START: /* transient */ if (-1 == connection_handle_write_prepare(con)) { @@ -1303,7 +1303,7 @@ int connection_state_machine(connection *con) { /* fall through */ case CON_STATE_WRITE: connection_handle_write_state(con); - if (con->state != CON_STATE_RESPONSE_END) break; + if (con->request.state != CON_STATE_RESPONSE_END) break; /* fall through */ case CON_STATE_RESPONSE_END: /* transient */ case CON_STATE_ERROR: /* transient */ @@ -1316,18 +1316,18 @@ int connection_state_machine(connection *con) { break; default: log_error(con->conf.errh, __FILE__, __LINE__, - "unknown state: %d %d", con->fd, con->state); + "unknown state: %d %d", con->fd, con->request.state); break; } - } while (ostate != con->state); + } while (ostate != (request_state_t)con->request.state); if (log_state_handling) { log_error(con->conf.errh, __FILE__, __LINE__, - "state at exit: %d %s", con->fd, connection_get_state(con->state)); + "state at exit: %d %s", con->fd, connection_get_state(con->request.state)); } rc = 0; - switch(con->state) { + switch(con->request.state) { case CON_STATE_READ: rc = FDEVENT_IN | FDEVENT_RDHUP; break; @@ -1386,12 +1386,12 @@ static void connection_check_timeout (connection * const con, const time_t cur_t int changed = 0; int t_diff; - if (con->state == CON_STATE_CLOSE) { + if (con->request.state == CON_STATE_CLOSE) { if (cur_ts - con->close_timeout_ts > HTTP_LINGER_TIMEOUT) { changed = 1; } } else if (waitevents & FDEVENT_IN) { - if (con->request_count == 1 || con->state != CON_STATE_READ) { + if (con->request_count == 1 || con->request.state != CON_STATE_READ) { /* e.g. CON_STATE_READ_POST || CON_STATE_WRITE */ if (cur_ts - con->read_idle_ts > con->conf.max_read_idle) { /* time - out */ @@ -1423,7 +1423,7 @@ static void connection_check_timeout (connection * const con, const time_t cur_t * future: have separate backend timeout, and then change this * to check for write interest before checking for timeout */ /*if (waitevents & FDEVENT_OUT)*/ - if ((con->state == CON_STATE_WRITE) && + if ((con->request.state == CON_STATE_WRITE) && (con->write_request_ts != 0)) { #if 0 if (cur_ts - con->write_request_ts > 60) { @@ -1481,7 +1481,7 @@ void connection_graceful_shutdown_maint (server *srv) { connection * const con = conns->ptr[ndx]; int changed = 0; - if (con->state == CON_STATE_CLOSE) { + if (con->request.state == CON_STATE_CLOSE) { /* reduce remaining linger timeout to be * (from zero) *up to* one more second, but no more */ if (HTTP_LINGER_TIMEOUT > 1) @@ -1489,7 +1489,7 @@ void connection_graceful_shutdown_maint (server *srv) { if (log_epoch_secs - con->close_timeout_ts > HTTP_LINGER_TIMEOUT) changed = 1; } - else if (con->state == CON_STATE_READ && con->request_count > 1 + else if (con->request.state == CON_STATE_READ && con->request_count > 1 && chunkqueue_is_empty(con->read_queue)) { /* close connections in keep-alive waiting for next request */ connection_set_state(con, CON_STATE_ERROR); diff --git a/src/connections.h b/src/connections.h index 875da1e1..263e51b3 100644 --- a/src/connections.h +++ b/src/connections.h @@ -15,8 +15,8 @@ void connection_periodic_maint (server *srv, time_t cur_ts); connection * connection_accept(server *srv, server_socket *srv_sock); connection * connection_accepted(server *srv, server_socket *srv_socket, sock_addr *cnt_addr, int cnt); -const char * connection_get_state(connection_state_t state); -const char * connection_get_short_state(connection_state_t state); +const char * connection_get_state(request_state_t state); +const char * connection_get_short_state(request_state_t state); int connection_state_machine(connection *con); handler_t connection_handle_read_post_state(connection *con); handler_t connection_handle_read_post_error(connection *con, int http_status); diff --git a/src/gw_backend.c b/src/gw_backend.c index 607b2725..85643426 100644 --- a/src/gw_backend.c +++ b/src/gw_backend.c @@ -2031,7 +2031,7 @@ handler_t gw_handle_subrequest(connection *con, void *p_d) { if (hctx->gw_mode != GW_AUTHORIZER && (0 == hctx->wb->bytes_in - ? (con->state == CON_STATE_READ_POST || -1 == hctx->wb_reqlen) + ? (con->request.state==CON_STATE_READ_POST || -1 == hctx->wb_reqlen) : (hctx->wb->bytes_in < hctx->wb_reqlen || hctx->wb_reqlen < 0))) { /* leave excess data in con->request.reqbody_queue, which is * buffered to disk if too large and backend can not keep up */ diff --git a/src/http-header-glue.c b/src/http-header-glue.c index 1eb0e057..154147f4 100644 --- a/src/http-header-glue.c +++ b/src/http-header-glue.c @@ -826,7 +826,7 @@ void http_response_backend_done (connection *con) { /* (not CON_STATE_ERROR and not CON_STATE_RESPONSE_END, * i.e. not called from handle_connection_close or connection_reset * hooks, except maybe from errdoc handler, which later resets state)*/ - switch (con->state) { + switch (con->request.state) { case CON_STATE_HANDLE_REQUEST: case CON_STATE_READ_POST: if (!con->response.resp_body_started) { diff --git a/src/mod_accesslog.c b/src/mod_accesslog.c index 11125ea8..8fb36da9 100644 --- a/src/mod_accesslog.c +++ b/src/mod_accesslog.c @@ -1074,7 +1074,7 @@ static int log_access_record (const connection * const con, buffer * const b, fo accesslog_append_escaped(b, con->uri.path_raw); break; case FORMAT_CONNECTION_STATUS: - if (con->state == CON_STATE_RESPONSE_END) { + if (con->request.state == CON_STATE_RESPONSE_END) { if (0 == con->request.keep_alive) { buffer_append_string_len(b, CONST_STR_LEN("-")); } else { diff --git a/src/mod_evasive.c b/src/mod_evasive.c index 61fd8b9d..46071469 100644 --- a/src/mod_evasive.c +++ b/src/mod_evasive.c @@ -117,7 +117,7 @@ URIHANDLER_FUNC(mod_evasive_uri_handler) { /* check if other connections are already actively serving data for the same IP * we can only ban connections which are already behind the 'read request' state * */ - if (c->state <= CON_STATE_REQUEST_END) continue; + if (c->request.state <= CON_STATE_REQUEST_END) continue; if (!sock_addr_is_addr_eq(&c->dst_addr, &con->dst_addr)) continue; conns_by_ip++; diff --git a/src/mod_status.c b/src/mod_status.c index 29d3d1ac..154bcb3f 100644 --- a/src/mod_status.c +++ b/src/mod_status.c @@ -439,12 +439,12 @@ static handler_t mod_status_handle_server_status_html(server *srv, connection *c connection *c = srv->conns.ptr[j]; const char *state; - if (CON_STATE_READ == c->state && !buffer_string_is_empty(c->request.target_orig)) { + if (CON_STATE_READ == c->request.state && !buffer_string_is_empty(c->request.target_orig)) { state = "k"; ++cstates[CON_STATE_CLOSE+2]; } else { - state = connection_get_short_state(c->state); - ++cstates[(c->state <= CON_STATE_CLOSE ? c->state : CON_STATE_CLOSE+1)]; + state = connection_get_short_state(c->request.state); + ++cstates[(c->request.state <= CON_STATE_CLOSE ? c->request.state : CON_STATE_CLOSE+1)]; } buffer_append_string_len(b, state, 1); @@ -509,10 +509,10 @@ static handler_t mod_status_handle_server_status_html(server *srv, connection *c buffer_append_string_len(b, CONST_STR_LEN("")); - if (CON_STATE_READ == c->state && !buffer_string_is_empty(c->request.target_orig)) { + if (CON_STATE_READ == c->request.state && !buffer_string_is_empty(c->request.target_orig)) { buffer_append_string_len(b, CONST_STR_LEN("keep-alive")); } else { - buffer_append_string(b, connection_get_state(c->state)); + buffer_append_string(b, connection_get_state(c->request.state)); } buffer_append_string_len(b, CONST_STR_LEN("")); @@ -607,9 +607,9 @@ static handler_t mod_status_handle_server_status_text(server *srv, connection *c for (uint32_t i = 0; i < srv->conns.used; ++i) { connection *c = srv->conns.ptr[i]; const char *state = - (CON_STATE_READ == c->state && !buffer_string_is_empty(c->request.target_orig)) + (CON_STATE_READ == c->request.state && !buffer_string_is_empty(c->request.target_orig)) ? "k" - : connection_get_short_state(c->state); + : connection_get_short_state(c->request.state); buffer_append_string_len(b, state, 1); } for (uint32_t i = 0; i < srv->conns.size - srv->conns.used; ++i) { diff --git a/src/mod_webdav.c b/src/mod_webdav.c index df5fe358..14eeda55 100644 --- a/src/mod_webdav.c +++ b/src/mod_webdav.c @@ -3739,7 +3739,7 @@ mod_webdav_propfind (connection * const con, const plugin_config * const pconf) { if (con->request.reqbody_length) { #ifdef USE_PROPPATCH - if (con->state == CON_STATE_READ_POST) { + if (con->request.state == CON_STATE_READ_POST) { handler_t rc = connection_handle_read_post_state(con); if (rc != HANDLER_GO_ON) return rc; } @@ -4443,7 +4443,7 @@ mod_webdav_put_deprecated_unsafe_partial_put_compat (connection * const con, static handler_t mod_webdav_put (connection * const con, const plugin_config * const pconf) { - if (con->state == CON_STATE_READ_POST) { + if (con->request.state == CON_STATE_READ_POST) { int first_read = chunkqueue_is_empty(con->request.reqbody_queue); handler_t rc = connection_handle_read_post_state(con); if (rc != HANDLER_GO_ON) { @@ -4978,7 +4978,7 @@ mod_webdav_proppatch (connection * const con, const plugin_config * const pconf) return HANDLER_FINISHED; } - if (con->state == CON_STATE_READ_POST) { + if (con->request.state == CON_STATE_READ_POST) { handler_t rc = connection_handle_read_post_state(con); if (rc != HANDLER_GO_ON) return rc; } @@ -5194,7 +5194,7 @@ mod_webdav_lock (connection * const con, const plugin_config * const pconf) */ if (con->request.reqbody_length) { - if (con->state == CON_STATE_READ_POST) { + if (con->request.state == CON_STATE_READ_POST) { handler_t rc = connection_handle_read_post_state(con); if (rc != HANDLER_GO_ON) return rc; } diff --git a/src/request.h b/src/request.h index a8c38537..da81eb71 100644 --- a/src/request.h +++ b/src/request.h @@ -76,8 +76,25 @@ typedef struct { struct log_error_st *serrh; /* script errh */ } request_config; +/* the order of the items should be the same as they are processed + * read before write as we use this later e.g. <= CON_STATE_REQUEST_END */ +typedef enum { + CON_STATE_CONNECT, + CON_STATE_REQUEST_START, + CON_STATE_READ, + CON_STATE_REQUEST_END, + CON_STATE_READ_POST, + CON_STATE_HANDLE_REQUEST, + CON_STATE_RESPONSE_START, + CON_STATE_WRITE, + CON_STATE_RESPONSE_END, + CON_STATE_ERROR, + CON_STATE_CLOSE +} request_state_t; + struct request_st { request_config *conf; + request_state_t state; /*(modules should not modify request state)*/ connection *con; /** HEADER */