ah move more_rx_waiting to wsi scope

Originally this was alright in wsi->u.hdr, because ah implied header
processing.  But since we allowed ah to be held across http
keep-alive transactions if we saw we had more header data, it means
we were trying to read this union member out of scope after it had
transitioned.

Moving the more_rx_waiting member to be a 1-bit bifield in the wsi
solves it and lets us check the state any time later at http
transaction completion.

https://github.com/warmcat/libwebsockets/issues/441

Signed-off-by: Andy Green <andy.green@linaro.org>
This commit is contained in:
Andy Green 2016-02-28 10:55:31 +08:00
parent 03384721e7
commit 83af28a747
4 changed files with 16 additions and 5 deletions

View file

@ -30,6 +30,12 @@ trips around the event loop (and cgi...).
6) MAJOR connections on ah waiting list that closed did not get removed from
the waiting list...
7) MAJOR since we added the ability to hold an ah across http keepalive
transactions where more headers had already arrived, we broke the ability
to tell if more headers had arrived. Result was if the browser didn't
close the keepalive, we retained ah for the lifetime of the keepalive,
using up the pool.
Changes
-------

View file

@ -229,7 +229,7 @@ int lws_header_table_detach(struct lws *wsi)
"wsi->more_rx_waiting %d\n", __func__, wsi,
(int)(now - wsi->u.hdr.ah->assigned),
ah->rxpos, ah->rxlen, wsi->mode, wsi->state,
wsi->u.hdr.more_rx_waiting);
wsi->more_rx_waiting);
}
/* if we think we're detaching one, there should be one in use */

View file

@ -964,7 +964,6 @@ struct _lws_header_related {
char post_literal_equal;
unsigned char parser_state; /* enum lws_token_indexes */
char redirects;
char more_rx_waiting;
};
struct _lws_websocket_related {
@ -1091,6 +1090,7 @@ struct lws {
unsigned int user_space_externally_allocated:1;
unsigned int socket_is_permanently_unusable:1;
unsigned int rxflow_change_to:2;
unsigned int more_rx_waiting:1; /* has to live here since ah may stick to end */
#ifndef LWS_NO_EXTENSIONS
unsigned int extension_data_pending:1;
#endif

View file

@ -352,7 +352,7 @@ lws_handshake_server(struct lws *wsi, unsigned char **buf, size_t len)
assert(wsi->u.hdr.ah);
while (len--) {
wsi->u.hdr.more_rx_waiting = !!len;
wsi->more_rx_waiting = !!len;
assert(wsi->mode == LWSCM_HTTP_SERVING);
@ -364,7 +364,9 @@ lws_handshake_server(struct lws *wsi, unsigned char **buf, size_t len)
if (wsi->u.hdr.parser_state != WSI_PARSING_COMPLETE)
continue;
lwsl_parser("lws_parse sees parsing complete\n");
lwsl_parser("%s: lws_parse sees parsing complete\n", __func__);
lwsl_debug("%s: wsi->more_rx_waiting=%d\n", __func__,
wsi->more_rx_waiting);
wsi->mode = LWSCM_PRE_WS_SERVING_ACCEPT;
lws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
@ -746,7 +748,10 @@ lws_http_transaction_completed(struct lws *wsi)
* reset the existing header table and keep it.
*/
if (wsi->u.hdr.ah) {
if (!wsi->u.hdr.more_rx_waiting) {
lwsl_info("%s: wsi->more_rx_waiting=%d\n", __func__,
wsi->more_rx_waiting);
if (!wsi->more_rx_waiting) {
wsi->u.hdr.ah->rxpos = wsi->u.hdr.ah->rxlen;
lws_header_table_detach(wsi);
} else