{"schema":"libjg2-1",
"vpath":"/git/",
"avatar":"/git/avatar/",
"alang":"",
"gen_ut":1746421360,
"reponame":"libwebsockets",
"desc":"libwebsockets lightweight C networking library",
"owner": { "name": "Andy Green", "email": "andy@warmcat.com", "md5": "c50933ca2aa61e0fe2c43d46bb6b59cb" },"url":"https://libwebsockets.org/repo/libwebsockets",
"f":3,
"items": [
{"schema":"libjg2-1",
"cid":"433bbe042311ae53b2ec1961340750fb",
"commit": {"type":"commit",
"time": 1504875473,
"time_ofs": 480,
"oid_tree": { "oid": "a6a0557dad151029deeb3e3997fd7ea73055693f", "alias": []},
"oid":{ "oid": "d78c93254b1f49359713af897abe3206fa7823a1", "alias": []},
"msg": "cgi: stdout POLLHUP holy grail",
"sig_commit": { "git_time": { "time": 1504875473, "offset": 480 }, "name": "Andy Green", "email": "andy@warmcat.com", "md5": "c50933ca2aa61e0fe2c43d46bb6b59cb" },
"sig_author": { "git_time": { "time": 1504760112, "offset": 480 }, "name": "Andy Green", "email": "andy@warmcat.com", "md5": "c50933ca2aa61e0fe2c43d46bb6b59cb" }},
"body": "cgi: stdout POLLHUP holy grail\n\nThis a) directly discovers cgi stdout POLLUP and b) modulates rx flow control on CGI STDOUT\naccording to the outgoing writeable service. When the outgoing writeable service finally sees\n0 read() waiting for it even though it was signalled for POLLIN, it knows it is a POLLHUP.\n\nCritically when it sees POLLHUP like that, it leaves the rx flow control defeating any\nfurther stdout POLLIN signalling while the rest of the CGI lifecycle completes, eliminating\nbusywaiting during the CGI."
,
"diff": "diff --git a/lib/context.c b/lib/context.c\nindex 7d76c80..e11af45 100644\n--- a/lib/context.c\n+++ b/lib/context.c\n@@ -246,9 +246,14 @@ lws_callback_http_dummy(struct lws *wsi, enum lws_callback_reasons reason,\n \n \tcase LWS_CALLBACK_HTTP_WRITEABLE:\n #ifdef LWS_WITH_CGI\n-\t\tif (wsi-\u003ereason_bf \u0026 LWS_CB_REASON_AUX_BF__CGI) {\n-\t\t\tif (lws_cgi_write_split_stdout_headers(wsi) \u003c 0)\n+\t\tif (wsi-\u003ereason_bf \u0026 (LWS_CB_REASON_AUX_BF__CGI_HEADERS | LWS_CB_REASON_AUX_BF__CGI)) {\n+\t\t\tn \u003d lws_cgi_write_split_stdout_headers(wsi);\n+\t\t\tif (n \u003c 0) {\n+\t\t\t\tlwsl_debug(\u0022LWS_CB_REASON_AUX_BF__CGI forcing close\u005cn\u0022);\n \t\t\t\treturn -1;\n+\t\t\t}\n+\t\t\tif (!n)\n+\t\t\t\tlws_rx_flow_control(wsi-\u003ecgi-\u003estdwsi[LWS_STDOUT], 1);\n \n \t\t\tif (wsi-\u003ereason_bf \u0026 LWS_CB_REASON_AUX_BF__CGI_HEADERS)\n \t\t\t\twsi-\u003ereason_bf \u0026\u003d ~LWS_CB_REASON_AUX_BF__CGI_HEADERS;\n@@ -258,6 +263,7 @@ lws_callback_http_dummy(struct lws *wsi, enum lws_callback_reasons reason,\n \t\t}\n \n \t\tif (wsi-\u003ereason_bf \u0026 LWS_CB_REASON_AUX_BF__CGI_CHUNK_END) {\n+\t\t\tlwsl_debug(\u0022writing chunk terminator and exiting\u005cn\u0022);\n \t\t\tn \u003d lws_write(wsi, (unsigned char *)\u00220\u005cx0d\u005cx0a\u005cx0d\u005cx0a\u0022,\n \t\t\t\t 5, LWS_WRITE_HTTP);\n \t\t\t/* always close after sending it */\n@@ -363,6 +369,8 @@ lws_callback_http_dummy(struct lws *wsi, enum lws_callback_reasons reason,\n \t\t\t/* TBD stdin rx flow control */\n \t\t\tbreak;\n \t\tcase LWS_STDOUT:\n+\t\t\t/* quench POLLIN on STDOUT until MASTER got writeable */\n+\t\t\tlws_rx_flow_control(args-\u003estdwsi[LWS_STDOUT], 0);\n \t\t\twsi-\u003ereason_bf |\u003d LWS_CB_REASON_AUX_BF__CGI;\n \t\t\t/* when writing to MASTER would not block */\n \t\t\tlws_callback_on_writable(wsi);\n@@ -385,6 +393,7 @@ lws_callback_http_dummy(struct lws *wsi, enum lws_callback_reasons reason,\n \t\t\t\twsi-\u003ecgi-\u003eexplicitly_chunked, (uint64_t)wsi-\u003ecgi-\u003econtent_length);\n \t\tif (!wsi-\u003ecgi-\u003eexplicitly_chunked \u0026\u0026 !wsi-\u003ecgi-\u003econtent_length) {\n \t\t\t/* send terminating chunk */\n+\t\t\tlwsl_debug(\u0022LWS_CALLBACK_CGI_TERMINATED: looking to send terminating chunk\u005cn\u0022);\n \t\t\twsi-\u003ereason_bf |\u003d LWS_CB_REASON_AUX_BF__CGI_CHUNK_END;\n \t\t\tlws_callback_on_writable(wsi);\n \t\t\tlws_set_timeout(wsi, PENDING_TIMEOUT_CGI, 3);\ndiff --git a/lib/libwebsockets.c b/lib/libwebsockets.c\nindex 32b2732..3ce469f 100755\n--- a/lib/libwebsockets.c\n+++ b/lib/libwebsockets.c\n@@ -3028,8 +3028,13 @@ lws_cgi_write_split_stdout_headers(struct lws *wsi)\n \t\t\treturn -1;\n \t\t}\n \t\twsi-\u003ecgi-\u003econtent_length_seen +\u003d m;\n+\t} else {\n+\t\tif (wsi-\u003ecgi_stdout_zero_length) {\n+\t\t\tlwsl_debug(\u0022%s: failed to read anything: stdout is POLLHUP'd\u005cn\u0022, __func__);\n+\t\t\treturn 1;\n+\t\t}\n+\t\twsi-\u003ecgi_stdout_zero_length \u003d 1;\n \t}\n-\n \treturn 0;\n }\n \n@@ -3153,7 +3158,7 @@ lws_cgi_kill_terminated(struct lws_context_per_thread *pt)\n \n \t\t\t\tif (!cgi-\u003econtent_length) {\n \t\t\t\t\t/*\n-\t\t\t\t\t * well, if he sends chunked... give him 5s after the\n+\t\t\t\t\t * well, if he sends chunked... give him 2s after the\n \t\t\t\t\t * cgi terminated to send buffered\n \t\t\t\t\t */\n \t\t\t\t\tcgi-\u003echunked_grace++;\n@@ -3192,7 +3197,7 @@ lws_cgi_kill_terminated(struct lws_context_per_thread *pt)\n \t\t/* we deferred killing him after reaping his PID */\n \t\tif (cgi-\u003echunked_grace) {\n \t\t\tcgi-\u003echunked_grace++;\n-\t\t\tif (cgi-\u003echunked_grace \u003c 5)\n+\t\t\tif (cgi-\u003echunked_grace \u003c 2)\n \t\t\t\tcontinue;\n \t\t\tgoto finish_him;\n \t\t}\n@@ -3214,7 +3219,7 @@ lws_cgi_kill_terminated(struct lws_context_per_thread *pt)\n \n \t\t\tif (!cgi-\u003econtent_length) {\n \t\t\t\t/*\n-\t\t\t\t * well, if he sends chunked... give him 5s after the\n+\t\t\t\t * well, if he sends chunked... give him 2s after the\n \t\t\t\t * cgi terminated to send buffered\n \t\t\t\t */\n \t\t\t\tcgi-\u003echunked_grace++;\ndiff --git a/lib/private-libwebsockets.h b/lib/private-libwebsockets.h\nindex 5c75bed..ee2edd3 100644\n--- a/lib/private-libwebsockets.h\n+++ b/lib/private-libwebsockets.h\n@@ -1671,6 +1671,7 @@ struct lws {\n \tunsigned int ipv6:1;\n \tunsigned int parent_carries_io:1;\n \tunsigned int parent_pending_cb_on_writable:1;\n+\tunsigned int cgi_stdout_zero_length:1;\n \n #if defined(LWS_WITH_ESP8266)\n \tunsigned int pending_send_completion:3;\ndiff --git a/lib/service.c b/lib/service.c\nindex 1850426..184ded0 100644\n--- a/lib/service.c\n+++ b/lib/service.c\n@@ -902,7 +902,7 @@ lws_service_fd_tsi(struct lws_context *context, struct lws_pollfd *pollfd, int t\n \t\t\t\t\t wsi, buf, pt-\u003eah_pool[n].rxpos,\n \t\t\t\t\t pt-\u003eah_pool[n].rxlen,\n \t\t\t\t\t pt-\u003eah_pool[n].pos);\n-\n+\t\t\t\tbuf[0] \u003d '\u005c0';\n \t\t\t\tm \u003d 0;\n \t\t\t\tdo {\n \t\t\t\t\tc \u003d lws_token_to_string(m);\n@@ -915,11 +915,12 @@ lws_service_fd_tsi(struct lws_context *context, struct lws_pollfd *pollfd, int t\n \t\t\t\t\t\tcontinue;\n \t\t\t\t\t}\n \n-\t\t\t\t\tlws_hdr_copy(wsi, buf, sizeof buf, m);\n-\t\t\t\t\tbuf[sizeof(buf) - 1] \u003d '\u005c0';\n+\t\t\t\t\tif (lws_hdr_copy(wsi, buf, sizeof buf, m) \u003e 0) {\n+\t\t\t\t\t\tbuf[sizeof(buf) - 1] \u003d '\u005c0';\n \n-\t\t\t\t\tlwsl_notice(\u0022 %s \u003d %s\u005cn\u0022,\n-\t\t\t\t\t\t (const char *)c, buf);\n+\t\t\t\t\t\tlwsl_notice(\u0022 %s \u003d %s\u005cn\u0022,\n+\t\t\t\t\t\t\t\t(const char *)c, buf);\n+\t\t\t\t\t}\n \t\t\t\t\tm++;\n \t\t\t\t} while (1);\n \n","s":{"c":1746389876,"u": 7268}}
],"g": 766,"chitpc": 0,"ehitpc": 0,"indexed":0
,
"ab": 0, "si": 0, "db":0, "di":0, "sat":0, "lfc": "7d0a"}