From 380fe02cf562adde6c7130b0d710c65415ae8502 Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Mon, 17 Jul 2023 12:38:28 +0200 Subject: [PATCH] http2: treat initial SETTINGS as a WINDOW_UPDATE - refs #11426 where spurious stalls on large POST requests are reported - the issue seems to involve the following * first stream on connection adds up to 64KB of POST data, which is the max default HTTP/2 stream window size transfer is set to HOLD * initial SETTINGS from server arrive, enlarging the stream window. But no WINDOW_UPDATE is received. * curl stalls - the fix un-HOLDs a stream on receiving SETTINGS, not relying on a WINDOW_UPDATE from lazy servers Closes #11450 --- lib/http2.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/lib/http2.c b/lib/http2.c index 2d4bbce41c..64a066b84f 100644 --- a/lib/http2.c +++ b/lib/http2.c @@ -1122,6 +1122,21 @@ static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame, ctx->max_concurrent_streams)); multi_connchanged(data->multi); } + /* Since the initial stream window is 64K, a request might be on HOLD, + * due to exhaustion. The (initial) SETTINGS may announce a much larger + * window and *assume* that we treat this like a WINDOW_UPDATE. Some + * servers send an explicit WINDOW_UPDATE, but not all seem to do that. + * To be safe, we UNHOLD a stream in order not to stall. */ + if((data->req.keepon & KEEP_SEND_HOLD) && + (data->req.keepon & KEEP_SEND)) { + struct stream_ctx *stream = H2_STREAM_CTX(data); + data->req.keepon &= ~KEEP_SEND_HOLD; + if(stream) { + drain_stream(cf, data, stream); + DEBUGF(LOG_CF(data, cf, "[h2sid=%d] un-holding after SETTINGS", + stream_id)); + } + } break; } case NGHTTP2_GOAWAY: