]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
http2: reset stream on response header error
authorStefan Eissing <stefan@eissing.org>
Mon, 3 Mar 2025 13:05:34 +0000 (14:05 +0100)
committerDaniel Stenberg <daniel@haxx.se>
Wed, 5 Mar 2025 09:58:52 +0000 (10:58 +0100)
We send a GOAWAY, but some servers ignore that and happily continue
sending the stream response. RST the stream when response header errors
are encountered.

Fixes #16535
Reported-by: Peng-Yu Chen
Closes #16544

lib/http2.c

index b8cace3a4e8859a80ec4709dcb524f9536347944..ef95d03e00dfcf03236e11c195cfd14e8cd1388c 100644 (file)
@@ -1500,10 +1500,21 @@ static int on_begin_headers(nghttp2_session *session,
   return 0;
 }
 
-static void report_header_error(struct Curl_easy *data, CURLcode result)
+static void cf_h2_header_error(struct Curl_cfilter *cf,
+                               struct Curl_easy *data,
+                               struct h2_stream_ctx *stream,
+                               CURLcode result)
 {
+  struct cf_h2_ctx *ctx = cf->ctx;
+
   failf(data, "Error receiving HTTP2 header: %d(%s)", result,
         curl_easy_strerror(result));
+  if(stream) {
+    nghttp2_submit_rst_stream(ctx->h2, NGHTTP2_FLAG_NONE,
+                              stream->id, NGHTTP2_STREAM_CLOSED);
+    stream->closed = TRUE;
+    stream->reset = TRUE;
+  }
 }
 
 /* frame->hd.type is either NGHTTP2_HEADERS or NGHTTP2_PUSH_PROMISE */
@@ -1606,7 +1617,7 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
                              (const char *)name, namelen,
                              (const char *)value, valuelen);
     if(result) {
-      report_header_error(data_s, result);
+      cf_h2_header_error(cf, data_s, stream, result);
       return NGHTTP2_ERR_CALLBACK_FAILURE;
     }
 
@@ -1620,14 +1631,14 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
     result = Curl_http_decode_status(&stream->status_code,
                                      (const char *)value, valuelen);
     if(result) {
-      report_header_error(data_s, result);
+      cf_h2_header_error(cf, data_s, stream, result);
       return NGHTTP2_ERR_CALLBACK_FAILURE;
     }
     msnprintf(buffer, sizeof(buffer), HTTP_PSEUDO_STATUS ":%u\r",
               stream->status_code);
     result = Curl_headers_push(data_s, buffer, CURLH_PSEUDO);
     if(result) {
-      report_header_error(data_s, result);
+      cf_h2_header_error(cf, data_s, stream, result);
       return NGHTTP2_ERR_CALLBACK_FAILURE;
     }
     Curl_dyn_reset(&ctx->scratch);
@@ -1640,7 +1651,7 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
       h2_xfer_write_resp_hd(cf, data_s, stream, Curl_dyn_ptr(&ctx->scratch),
                             Curl_dyn_len(&ctx->scratch), FALSE);
     if(result) {
-      report_header_error(data_s, result);
+      cf_h2_header_error(cf, data_s, stream, result);
       return NGHTTP2_ERR_CALLBACK_FAILURE;
     }
     /* if we receive data for another handle, wake that up */
@@ -1667,7 +1678,7 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
     h2_xfer_write_resp_hd(cf, data_s, stream, Curl_dyn_ptr(&ctx->scratch),
                           Curl_dyn_len(&ctx->scratch), FALSE);
   if(result) {
-    report_header_error(data_s, result);
+    cf_h2_header_error(cf, data_s, stream, result);
     return NGHTTP2_ERR_CALLBACK_FAILURE;
   }
   /* if we receive data for another handle, wake that up */