ah move more_rx_waiting to wsi scope
authorAndy Green <andy.green@linaro.org>
Sun, 28 Feb 2016 03:02:42 +0000 (11:02 +0800)
committerAndy Green <andy.green@linaro.org>
Sun, 28 Feb 2016 03:02:42 +0000 (11:02 +0800)
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>
changelog
lib/parsers.c
lib/private-libwebsockets.h
lib/server.c

index 2e99106..f8e9288 100644 (file)
--- a/changelog
+++ b/changelog
@@ -7,6 +7,12 @@ Fixes
 1) MAJOR connections on ah waiting list that closed did not get removed from
 the waiting list...
 
+2) 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.
+
 
 v1.7.2
 ======
index 0dee8ca..360e261 100644 (file)
@@ -216,7 +216,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 */
index af62e8f..9c3609a 100644 (file)
@@ -948,7 +948,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 {
@@ -1056,6 +1055,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
index 1d044ff..5ab695e 100644 (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);
@@ -744,7 +746,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