Skip to content

http3: curl stalls when stream is closed before sending all upload data #9122

@tatsuhiro-t

Description

@tatsuhiro-t

I did this

In order to reproduce this issue, the following tweak makes curl send invalid pseudo header field, and ngtcp2 server will respond with STOP_SENDING and RESET_STREAM, leading stream closure:

diff --git a/lib/vquic/ngtcp2.c b/lib/vquic/ngtcp2.c
index 2d5f7f3c1..3d7552bfa 100644
--- a/lib/vquic/ngtcp2.c
+++ b/lib/vquic/ngtcp2.c
@@ -1361,7 +1361,7 @@ static CURLcode http_request(struct Curl_easy *data, const void *mem,
   result = Curl_pseudo_headers(data, mem, len, &hreq);
   if(result)
     goto fail;
-  nheader = hreq->entries;
+  nheader = hreq->entries + 1;
 
   nva = malloc(sizeof(nghttp3_nv) * nheader);
   if(!nva) {
@@ -1370,13 +1370,18 @@ static CURLcode http_request(struct Curl_easy *data, const void *mem,
   }
   else {
     unsigned int i;
-    for(i = 0; i < nheader; i++) {
+    for(i = 0; i < nheader - 1; i++) {
       nva[i].name = (unsigned char *)hreq->header[i].name;
       nva[i].namelen = hreq->header[i].namelen;
       nva[i].value = (unsigned char *)hreq->header[i].value;
       nva[i].valuelen = hreq->header[i].valuelen;
       nva[i].flags = NGHTTP3_NV_FLAG_NONE;
     }
+    nva[nheader - 1].name = (unsigned char *)":foo";
+    nva[nheader - 1].namelen = sizeof(":foo") - 1;
+    nva[nheader - 1].value = (unsigned char *)"foo";
+    nva[nheader - 1].valuelen = sizeof("foo") - 1;
+    nva[nheader - 1].flags = NGHTTP3_NV_FLAG_NONE;
   }
 
   switch(data->state.httpreq) {
curl --http3 https://127.0.0.1 -T uploadfile -v
...
* ngh3_stream_recv returns 0 bytes and EAGAIN
* ngh3_stream_send() wants to send 65536 bytes
* cb_h3_stream_close CALLED
* ngh3_stream_send() wants to send 65536 bytes
* Curl_readwrite: forcibly told to drain data
* Curl_readwrite: forcibly told to drain data
* Curl_readwrite: forcibly told to drain data
* Curl_readwrite: forcibly told to drain data
* Curl_readwrite: forcibly told to drain data
(repeated)

Another way to reproduce this issue does not require any modification to curl. Make server return response without waiting for request data, which may trigger STOP_SENDING from server. ngtcp2 server --early-response does this.

I expected the following

curl stops with some indication of error.

curl/libcurl version

[curl -V output]
curl 7.85.0-DEV
master branch

operating system

linux

Metadata

Metadata

Assignees

No one assigned

    Labels

    HTTP/3h3 or quic related

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions