[core] option to propagate TCP FIN to backend host
(experimental support for mod_sockproxy) "tcp-fin-propagate" = "enable" for each host in *.server backend defspersonal/stbuehler/fix-fdevent
parent
bbf01a3a6c
commit
7c8cc6f7c5
|
@ -918,6 +918,7 @@ static handler_t connection_handle_fdevent(server *srv, void *context, int reven
|
|||
int events = fdevent_event_get_interest(srv->ev, con->fd);
|
||||
events &= ~(FDEVENT_IN|FDEVENT_RDHUP);
|
||||
con->conf.stream_request_body &= ~(FDEVENT_STREAM_REQUEST_BUFMIN|FDEVENT_STREAM_REQUEST_POLLIN);
|
||||
con->conf.stream_request_body |= FDEVENT_STREAM_REQUEST_POLLRDHUP;
|
||||
con->is_readable = 1; /*(can read 0 for end-of-stream)*/
|
||||
con->keep_alive = 0;
|
||||
if (con->request.content_length < -1) { /*(transparent proxy mode; no more data to read)*/
|
||||
|
@ -934,6 +935,7 @@ static handler_t connection_handle_fdevent(server *srv, void *context, int reven
|
|||
* future: might getpeername() to check for TCP RST on half-closed sockets
|
||||
* (without FDEVENT_RDHUP interest) when checking for write timeouts
|
||||
* once a second in server.c, though getpeername() on Windows might not indicate this */
|
||||
con->conf.stream_request_body |= FDEVENT_STREAM_REQUEST_TCP_FIN;
|
||||
fdevent_event_set(srv->ev, &con->fde_ndx, con->fd, events);
|
||||
} else {
|
||||
/* Failure of fdevent_is_tcp_half_closed() indicates TCP RST
|
||||
|
|
|
@ -20,9 +20,12 @@ typedef handler_t (*fdevent_handler)(struct server *srv, void *ctx, int revents)
|
|||
#define FDEVENT_NVAL BV(5)
|
||||
#define FDEVENT_RDHUP BV(13)
|
||||
|
||||
#define FDEVENT_STREAM_REQUEST BV(0)
|
||||
#define FDEVENT_STREAM_REQUEST_BUFMIN BV(1)
|
||||
#define FDEVENT_STREAM_REQUEST_POLLIN BV(15)
|
||||
#define FDEVENT_STREAM_REQUEST BV(0)
|
||||
#define FDEVENT_STREAM_REQUEST_BUFMIN BV(1)
|
||||
#define FDEVENT_STREAM_REQUEST_POLLRDHUP BV(12)
|
||||
#define FDEVENT_STREAM_REQUEST_TCP_FIN BV(13)
|
||||
#define FDEVENT_STREAM_REQUEST_BACKEND_SHUT_WR BV(14)
|
||||
#define FDEVENT_STREAM_REQUEST_POLLIN BV(15)
|
||||
|
||||
#define FDEVENT_STREAM_RESPONSE BV(0)
|
||||
#define FDEVENT_STREAM_RESPONSE_BUFMIN BV(1)
|
||||
|
|
|
@ -1269,6 +1269,7 @@ int gw_set_defaults_backend(server *srv, gw_plugin_data *p, data_unset *du, size
|
|||
{ "listen-backlog", NULL, T_CONFIG_INT, T_CONFIG_SCOPE_CONNECTION }, /* 19 */
|
||||
{ "x-sendfile", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 20 */
|
||||
{ "x-sendfile-docroot",NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 21 */
|
||||
{ "tcp-fin-propagate", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 22 */
|
||||
|
||||
{ NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
|
||||
};
|
||||
|
@ -1324,6 +1325,7 @@ int gw_set_defaults_backend(server *srv, gw_plugin_data *p, data_unset *du, size
|
|||
fcv[19].destination = &(host->listen_backlog);
|
||||
fcv[20].destination = &(host->xsendfile_allow);
|
||||
fcv[21].destination = host->xsendfile_docroot;
|
||||
fcv[22].destination = &(host->tcp_fin_propagate);
|
||||
|
||||
if (0 != config_insert_values_internal(srv, da_host->value, fcv, T_CONFIG_SCOPE_CONNECTION)) {
|
||||
goto error;
|
||||
|
@ -1715,6 +1717,23 @@ handler_t gw_connection_reset(server *srv, connection *con, void *p_d) {
|
|||
}
|
||||
|
||||
|
||||
static void gw_conditional_tcp_fin(server *srv, gw_handler_ctx *hctx) {
|
||||
connection *con = hctx->remote_conn;
|
||||
/*assert(con->conf.stream_request_body & FDEVENT_STREAM_REQUEST_TCP_FIN);*/
|
||||
if (!chunkqueue_is_empty(hctx->wb)) return;
|
||||
if (!hctx->host->tcp_fin_propagate) return;
|
||||
if (hctx->gw_mode == GW_AUTHORIZER) return;
|
||||
if (con->conf.stream_request_body & FDEVENT_STREAM_REQUEST_BACKEND_SHUT_WR)
|
||||
return;
|
||||
|
||||
/* propagate shutdown SHUT_WR to backend if TCP half-close on con->fd */
|
||||
con->conf.stream_request_body |= FDEVENT_STREAM_REQUEST_BACKEND_SHUT_WR;
|
||||
con->conf.stream_request_body &= ~FDEVENT_STREAM_REQUEST_POLLIN;
|
||||
con->is_readable = 0;
|
||||
shutdown(hctx->fd, SHUT_WR);
|
||||
fdevent_event_clr(srv->ev, &hctx->fde_ndx, hctx->fd, FDEVENT_OUT);
|
||||
}
|
||||
|
||||
static handler_t gw_write_request(server *srv, gw_handler_ctx *hctx) {
|
||||
switch(hctx->state) {
|
||||
case GW_STATE_INIT:
|
||||
|
@ -1880,6 +1899,10 @@ static handler_t gw_write_request(server *srv, gw_handler_ctx *hctx) {
|
|||
}
|
||||
}
|
||||
|
||||
if (hctx->remote_conn->conf.stream_request_body
|
||||
& FDEVENT_STREAM_REQUEST_TCP_FIN)
|
||||
gw_conditional_tcp_fin(srv, hctx);
|
||||
|
||||
return HANDLER_WAIT_FOR_EVENT;
|
||||
case GW_STATE_READ:
|
||||
/* waiting for a response */
|
||||
|
@ -2001,10 +2024,18 @@ handler_t gw_handle_subrequest(server *srv, connection *con, void *p_d) {
|
|||
}
|
||||
}
|
||||
|
||||
return ((0 == hctx->wb->bytes_in || !chunkqueue_is_empty(hctx->wb))
|
||||
&& hctx->state != GW_STATE_CONNECT_DELAYED)
|
||||
? gw_send_request(srv, hctx)
|
||||
: HANDLER_WAIT_FOR_EVENT;
|
||||
{
|
||||
handler_t rc =((0==hctx->wb->bytes_in || !chunkqueue_is_empty(hctx->wb))
|
||||
&& hctx->state != GW_STATE_CONNECT_DELAYED)
|
||||
? gw_send_request(srv, hctx)
|
||||
: HANDLER_WAIT_FOR_EVENT;
|
||||
if (HANDLER_WAIT_FOR_EVENT != rc) return rc;
|
||||
}
|
||||
|
||||
if (con->conf.stream_request_body & FDEVENT_STREAM_REQUEST_TCP_FIN)
|
||||
gw_conditional_tcp_fin(srv, hctx);
|
||||
|
||||
return HANDLER_WAIT_FOR_EVENT;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -203,6 +203,7 @@ typedef struct {
|
|||
|
||||
buffer *strip_request_uri;
|
||||
|
||||
unsigned short tcp_fin_propagate;
|
||||
unsigned short kill_signal; /* we need a setting for this as libfcgi
|
||||
applications prefer SIGUSR1 while the
|
||||
rest of the world would use SIGTERM
|
||||
|
|
Loading…
Reference in New Issue