Browse Source

[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)
personal/stbuehler/ci-build
Glenn Strauss 2 years ago
parent
commit
aca9d45adf
  1. 18
      src/base.h
  2. 12
      src/connections-glue.c
  3. 56
      src/connections.c
  4. 4
      src/connections.h
  5. 2
      src/gw_backend.c
  6. 2
      src/http-header-glue.c
  7. 2
      src/mod_accesslog.c
  8. 2
      src/mod_evasive.c
  9. 14
      src/mod_status.c
  10. 8
      src/mod_webdav.c
  11. 17
      src/request.h

18
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;

12
src/connections-glue.c

@ -12,7 +12,7 @@
#include <stdlib.h>
#include <string.h>
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) {

56
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);

4
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);

2
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 */

2
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) {

2
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 {

2
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++;

14
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("</td><td class=\"string\">"));
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("</td><td class=\"int\">"));
@ -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) {

8
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;
}

17
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 */

Loading…
Cancel
Save