From 83af0716c52e0724c5d6b92fc8dd874be19337dc Mon Sep 17 00:00:00 2001 From: Andy Green Date: Thu, 7 Dec 2017 13:03:06 +0800 Subject: [PATCH] h2: ensure only one path to close Add a flag to protect the case both the recursed lws_read() and the outer, grandfather lws_read() don't both try to close the wsi. --- lib/handshake.c | 11 +++++++++-- lib/http2/http2.c | 4 +++- lib/private-libwebsockets.h | 1 + 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/lib/handshake.c b/lib/handshake.c index e1bafb60..22453814 100644 --- a/lib/handshake.c +++ b/lib/handshake.c @@ -298,12 +298,19 @@ postbody_completion: read_ok: /* Nothing more to do for now */ - lwsl_info("%s: %p: read_ok, used %ld (len %d, state %d)\n", __func__, wsi, (long)(buf - oldbuf), (int)len, wsi->state); + lwsl_info("%s: %p: read_ok, used %ld (len %d, state %d)\n", __func__, + wsi, (long)(buf - oldbuf), (int)len, wsi->state); return lws_ptr_diff(buf, oldbuf); bail: - lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS); + /* + * h2 / h2-ws calls us recursively in lws_read()->lws_h2_parser()-> + * lws_read() pattern. Make sure that only the outer lws_read() does + * the wsi close. + */ + if (!wsi->outer_will_close) + lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS); return -1; } diff --git a/lib/http2/http2.c b/lib/http2/http2.c index e875f501..87cc1c17 100644 --- a/lib/http2/http2.c +++ b/lib/http2/http2.c @@ -1485,9 +1485,11 @@ lws_h2_parser(struct lws *wsi, unsigned char *in, lws_filepos_t inlen, break; } + h2n->swsi->outer_will_close = 1; n = lws_read(h2n->swsi, in - 1, inlen + 1); + h2n->swsi->outer_will_close = 0; if (n < 0) - break; + goto fail; inlen -= n - 1; in += n - 1; diff --git a/lib/private-libwebsockets.h b/lib/private-libwebsockets.h index 26eb90a7..aa6a100e 100644 --- a/lib/private-libwebsockets.h +++ b/lib/private-libwebsockets.h @@ -1931,6 +1931,7 @@ struct lws { unsigned int could_have_pending:1; /* detect back-to-back writes */ unsigned int timer_active:1; + unsigned int outer_will_close:1; #ifdef LWS_WITH_ACCESS_LOG unsigned int access_log_pending:1;