]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
http2: treat initial SETTINGS as a WINDOW_UPDATE
authorStefan Eissing <stefan@eissing.org>
Mon, 17 Jul 2023 10:38:28 +0000 (12:38 +0200)
committerDaniel Stenberg <daniel@haxx.se>
Mon, 17 Jul 2023 21:26:09 +0000 (23:26 +0200)
- 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

index 2d4bbce41c7b641c0ea465ac82ab39c43a547ed1..64a066b84f68845529fd2ad7f6773e3f6c81cf6c 100644 (file)
@@ -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: