[core] fix rare race condition from backends (fixes #2878)

fix rare race condition from backends with server.stream-response-body=2

(thx abelbeck)

x-ref:
  "fastcgi and stream-response-body=2 hangs on last chunk"
  https://redmine.lighttpd.net/issues/2878
personal/stbuehler/fix-fdevent
Glenn Strauss 2018-03-18 19:01:32 -04:00
parent 957916a90e
commit 210b57708e
5 changed files with 21 additions and 5 deletions

View File

@ -25,8 +25,9 @@ typedef handler_t (*fdevent_handler)(struct server *srv, void *ctx, int revents)
#define FDEVENT_STREAM_REQUEST_BUFMIN BV(1)
#define FDEVENT_STREAM_REQUEST_POLLIN BV(15)
#define FDEVENT_STREAM_RESPONSE BV(0)
#define FDEVENT_STREAM_RESPONSE_BUFMIN BV(1)
#define FDEVENT_STREAM_RESPONSE BV(0)
#define FDEVENT_STREAM_RESPONSE_BUFMIN BV(1)
#define FDEVENT_STREAM_RESPONSE_POLLRDHUP BV(15)
int fdevent_config(server *srv);
const char * fdevent_show_event_handlers(void);

View File

@ -2167,9 +2167,13 @@ static handler_t gw_handle_fdevent(server *srv, void *ctx, int revents) {
* since event loop will spin on fd FDEVENT_HUP event
* until unregistered. */
handler_t rc;
const unsigned short flags = con->conf.stream_response_body;
con->conf.stream_response_body &= ~FDEVENT_STREAM_RESPONSE_BUFMIN;
con->conf.stream_response_body |= FDEVENT_STREAM_RESPONSE_POLLRDHUP;
do {
rc = gw_recv_response(srv,hctx); /*(might invalidate hctx)*/
} while (rc == HANDLER_GO_ON); /*(unless HANDLER_GO_ON)*/
con->conf.stream_response_body = flags;
return rc; /* HANDLER_FINISHED or HANDLER_ERROR */
} else {
gw_proc *proc = hctx->proc;

View File

@ -1213,8 +1213,11 @@ handler_t http_response_read(server *srv, connection *con, http_response_opts *o
? HANDLER_FINISHED /* read finished */
: HANDLER_GO_ON; /* optimistic read; data not ready */
#else
if (!(fdevent_event_get_interest(srv->ev, fd) & FDEVENT_IN))
return HANDLER_GO_ON; /* optimistic read; data not ready */
if (!(fdevent_event_get_interest(srv->ev, fd) & FDEVENT_IN)) {
if (!(con->conf.stream_response_body
& FDEVENT_STREAM_RESPONSE_POLLRDHUP))
return HANDLER_GO_ON;/*optimistic read; data not ready*/
}
toread = 4096; /* let read() below indicate if EOF or EAGAIN */
#endif
}

View File

@ -425,9 +425,13 @@ static handler_t cgi_handle_fdevent(server *srv, void *ctx, int revents) {
* since event loop will spin on fd FDEVENT_HUP event
* until unregistered. */
handler_t rc;
const unsigned short flags = con->conf.stream_response_body;
con->conf.stream_response_body &= ~FDEVENT_STREAM_RESPONSE_BUFMIN;
con->conf.stream_response_body |= FDEVENT_STREAM_RESPONSE_POLLRDHUP;
do {
rc = cgi_recv_response(srv,hctx);/*(might invalidate hctx)*/
} while (rc == HANDLER_GO_ON); /*(unless HANDLER_GO_ON)*/
con->conf.stream_response_body = flags;
return rc; /* HANDLER_FINISHED or HANDLER_COMEBACK or HANDLER_ERROR */
} else if (!buffer_string_is_empty(hctx->response)) {
/* unfinished header package which is a body in reality */

View File

@ -368,7 +368,10 @@ static handler_t fcgi_recv_parse(server *srv, connection *con, struct http_respo
int fin = 0;
if (0 == n) {
if (!(fdevent_event_get_interest(srv->ev, hctx->fd) & FDEVENT_IN)) return HANDLER_GO_ON;
if (-1 == hctx->request_id) return HANDLER_FINISHED; /*(flag request ended)*/
if (!(fdevent_event_get_interest(srv->ev, hctx->fd) & FDEVENT_IN)
&& !(con->conf.stream_response_body & FDEVENT_STREAM_RESPONSE_POLLRDHUP))
return HANDLER_GO_ON;
log_error_write(srv, __FILE__, __LINE__, "ssdsb",
"unexpected end-of-file (perhaps the fastcgi process died):",
"pid:", hctx->proc->pid,
@ -436,6 +439,7 @@ static handler_t fcgi_recv_parse(server *srv, connection *con, struct http_respo
break;
case FCGI_END_REQUEST:
hctx->request_id = -1; /*(flag request ended)*/
fin = 1;
break;
default: