1
0
Fork 0
mirror of https://github.com/warmcat/libwebsockets.git synced 2025-03-16 00:00:07 +01:00

cgi: stdout POLLHUP holy grail

This a) directly discovers cgi stdout POLLUP and b) modulates rx flow control on CGI STDOUT
according to the outgoing writeable service.  When the outgoing writeable service finally sees
0 read() waiting for it even though it was signalled for POLLIN, it knows it is a POLLHUP.

Critically when it sees POLLHUP like that, it leaves the rx flow control defeating any
further stdout POLLIN signalling while the rest of the CGI lifecycle completes, eliminating
busywaiting during the CGI.
This commit is contained in:
Andy Green 2017-09-07 12:55:12 +08:00
parent 04ed8d2673
commit d78c93254b
4 changed files with 27 additions and 11 deletions

View file

@ -246,9 +246,14 @@ lws_callback_http_dummy(struct lws *wsi, enum lws_callback_reasons reason,
case LWS_CALLBACK_HTTP_WRITEABLE:
#ifdef LWS_WITH_CGI
if (wsi->reason_bf & LWS_CB_REASON_AUX_BF__CGI) {
if (lws_cgi_write_split_stdout_headers(wsi) < 0)
if (wsi->reason_bf & (LWS_CB_REASON_AUX_BF__CGI_HEADERS | LWS_CB_REASON_AUX_BF__CGI)) {
n = lws_cgi_write_split_stdout_headers(wsi);
if (n < 0) {
lwsl_debug("LWS_CB_REASON_AUX_BF__CGI forcing close\n");
return -1;
}
if (!n)
lws_rx_flow_control(wsi->cgi->stdwsi[LWS_STDOUT], 1);
if (wsi->reason_bf & LWS_CB_REASON_AUX_BF__CGI_HEADERS)
wsi->reason_bf &= ~LWS_CB_REASON_AUX_BF__CGI_HEADERS;
@ -258,6 +263,7 @@ lws_callback_http_dummy(struct lws *wsi, enum lws_callback_reasons reason,
}
if (wsi->reason_bf & LWS_CB_REASON_AUX_BF__CGI_CHUNK_END) {
lwsl_debug("writing chunk terminator and exiting\n");
n = lws_write(wsi, (unsigned char *)"0\x0d\x0a\x0d\x0a",
5, LWS_WRITE_HTTP);
/* always close after sending it */
@ -363,6 +369,8 @@ lws_callback_http_dummy(struct lws *wsi, enum lws_callback_reasons reason,
/* TBD stdin rx flow control */
break;
case LWS_STDOUT:
/* quench POLLIN on STDOUT until MASTER got writeable */
lws_rx_flow_control(args->stdwsi[LWS_STDOUT], 0);
wsi->reason_bf |= LWS_CB_REASON_AUX_BF__CGI;
/* when writing to MASTER would not block */
lws_callback_on_writable(wsi);
@ -385,6 +393,7 @@ lws_callback_http_dummy(struct lws *wsi, enum lws_callback_reasons reason,
wsi->cgi->explicitly_chunked, (uint64_t)wsi->cgi->content_length);
if (!wsi->cgi->explicitly_chunked && !wsi->cgi->content_length) {
/* send terminating chunk */
lwsl_debug("LWS_CALLBACK_CGI_TERMINATED: looking to send terminating chunk\n");
wsi->reason_bf |= LWS_CB_REASON_AUX_BF__CGI_CHUNK_END;
lws_callback_on_writable(wsi);
lws_set_timeout(wsi, PENDING_TIMEOUT_CGI, 3);

View file

@ -3028,8 +3028,13 @@ lws_cgi_write_split_stdout_headers(struct lws *wsi)
return -1;
}
wsi->cgi->content_length_seen += m;
} else {
if (wsi->cgi_stdout_zero_length) {
lwsl_debug("%s: failed to read anything: stdout is POLLHUP'd\n", __func__);
return 1;
}
wsi->cgi_stdout_zero_length = 1;
}
return 0;
}
@ -3153,7 +3158,7 @@ lws_cgi_kill_terminated(struct lws_context_per_thread *pt)
if (!cgi->content_length) {
/*
* well, if he sends chunked... give him 5s after the
* well, if he sends chunked... give him 2s after the
* cgi terminated to send buffered
*/
cgi->chunked_grace++;
@ -3192,7 +3197,7 @@ lws_cgi_kill_terminated(struct lws_context_per_thread *pt)
/* we deferred killing him after reaping his PID */
if (cgi->chunked_grace) {
cgi->chunked_grace++;
if (cgi->chunked_grace < 5)
if (cgi->chunked_grace < 2)
continue;
goto finish_him;
}
@ -3214,7 +3219,7 @@ lws_cgi_kill_terminated(struct lws_context_per_thread *pt)
if (!cgi->content_length) {
/*
* well, if he sends chunked... give him 5s after the
* well, if he sends chunked... give him 2s after the
* cgi terminated to send buffered
*/
cgi->chunked_grace++;

View file

@ -1671,6 +1671,7 @@ struct lws {
unsigned int ipv6:1;
unsigned int parent_carries_io:1;
unsigned int parent_pending_cb_on_writable:1;
unsigned int cgi_stdout_zero_length:1;
#if defined(LWS_WITH_ESP8266)
unsigned int pending_send_completion:3;

View file

@ -902,7 +902,7 @@ lws_service_fd_tsi(struct lws_context *context, struct lws_pollfd *pollfd, int t
wsi, buf, pt->ah_pool[n].rxpos,
pt->ah_pool[n].rxlen,
pt->ah_pool[n].pos);
buf[0] = '\0';
m = 0;
do {
c = lws_token_to_string(m);
@ -915,11 +915,12 @@ lws_service_fd_tsi(struct lws_context *context, struct lws_pollfd *pollfd, int t
continue;
}
lws_hdr_copy(wsi, buf, sizeof buf, m);
buf[sizeof(buf) - 1] = '\0';
if (lws_hdr_copy(wsi, buf, sizeof buf, m) > 0) {
buf[sizeof(buf) - 1] = '\0';
lwsl_notice(" %s = %s\n",
(const char *)c, buf);
lwsl_notice(" %s = %s\n",
(const char *)c, buf);
}
m++;
} while (1);