]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
quiche: return CURLE_HTTP3 on send to invalid stream
authorJay Satiro <raysatiro@yahoo.com>
Tue, 26 Dec 2023 06:55:54 +0000 (01:55 -0500)
committerJay Satiro <raysatiro@yahoo.com>
Tue, 2 Jan 2024 05:54:15 +0000 (00:54 -0500)
Prior to this change if a send failed on a stream in an invalid state
(according to quiche) and not marked as closed (according to libcurl)
then the send function would return CURLE_SEND_ERROR.

We already have similar code for ngtcp2 to return CURLE_HTTP3 in this
case.

Caught by test test_07_upload.py: test_07_22_upload_parallel_fail.

Fixes https://github.com/curl/curl/issues/12590
Closes https://github.com/curl/curl/pull/12597

lib/vquic/curl_ngtcp2.c
lib/vquic/curl_quiche.c

index fb1ef60a0a4ec3c3113506704cad1cdc57589144..f4edf2d636ef9397cf780d28f7ad00eac7958a7c 100644 (file)
@@ -1894,6 +1894,8 @@ static ssize_t cf_ngtcp2_send(struct Curl_cfilter *cf, struct Curl_easy *data,
       sent = (ssize_t)len;
       goto out;
     }
+    CURL_TRC_CF(data, cf, "[%" PRId64 "] send_body(len=%zu) "
+                "-> stream closed", stream->id, len);
     *err = CURLE_HTTP3;
     sent = -1;
     goto out;
index 91395876b46e9b7f97a2a753952ec53d2ae5aff8..227adbdd9a69a05f8e5617c6a1f6558794e1c436 100644 (file)
@@ -1078,6 +1078,28 @@ static ssize_t cf_quiche_send(struct Curl_cfilter *cf, struct Curl_easy *data,
       goto out;
     stream = H3_STREAM_CTX(data);
   }
+  else if(stream->closed) {
+    if(stream->resp_hds_complete) {
+      /* sending request body on a stream that has been closed by the
+       * server. If the server has send us a final response, we should
+       * silently discard the send data.
+       * This happens for example on redirects where the server, instead
+       * of reading the full request body just closed the stream after
+       * sending the 30x response.
+       * This is sort of a race: had the transfer loop called recv first,
+       * it would see the response and stop/discard sending on its own- */
+      CURL_TRC_CF(data, cf, "[%" PRId64 "] discarding data"
+                  "on closed stream with response", stream->id);
+      *err = CURLE_OK;
+      nwritten = (ssize_t)len;
+      goto out;
+    }
+    CURL_TRC_CF(data, cf, "[%" PRId64 "] send_body(len=%zu) "
+                "-> stream closed", stream->id, len);
+    *err = CURLE_HTTP3;
+    nwritten = -1;
+    goto out;
+  }
   else {
     bool eof = (stream->upload_left >= 0 &&
                 (curl_off_t)len >= stream->upload_left);
@@ -1095,20 +1117,11 @@ static ssize_t cf_quiche_send(struct Curl_cfilter *cf, struct Curl_easy *data,
       nwritten = -1;
       goto out;
     }
-    else if(nwritten == QUICHE_H3_TRANSPORT_ERR_INVALID_STREAM_STATE &&
-            stream->closed && stream->resp_hds_complete) {
-      /* sending request body on a stream that has been closed by the
-       * server. If the server has send us a final response, we should
-       * silently discard the send data.
-       * This happens for example on redirects where the server, instead
-       * of reading the full request body just closed the stream after
-       * sending the 30x response.
-       * This is sort of a race: had the transfer loop called recv first,
-       * it would see the response and stop/discard sending on its own- */
-      CURL_TRC_CF(data, cf, "[%" PRId64 "] discarding data"
-                  "on closed stream with response", stream->id);
-      *err = CURLE_OK;
-      nwritten = (ssize_t)len;
+    else if(nwritten == QUICHE_H3_TRANSPORT_ERR_INVALID_STREAM_STATE) {
+      CURL_TRC_CF(data, cf, "[%" PRId64 "] send_body(len=%zu) "
+                  "-> invalid stream state", stream->id, len);
+      *err = CURLE_HTTP3;
+      nwritten = -1;
       goto out;
     }
     else if(nwritten == QUICHE_H3_TRANSPORT_ERR_FINAL_SIZE) {