]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
vquic: use ngtcp2 v1.25.0 new close2 callback
authorStefan Eissing <stefan@eissing.org>
Mon, 20 Jul 2026 12:37:13 +0000 (14:37 +0200)
committerViktor Szakats <commit@vsz.me>
Mon, 27 Jul 2026 09:36:56 +0000 (11:36 +0200)
Forward only the app error code from the receiving side to the h3 layer.

This only takes effect when building against ngtcp2 v1.25.0 or higher.

Fixes #22270

Closes #22356

lib/vquic/cf-ngtcp2-cmn.c
tests/http/test_14_auth.py

index 9cc3cad5c0f79541ea4ebb99fb7217008cbf8561..ea214ff8b06b73ba31c4508c1602ffe6daf274c2 100644 (file)
@@ -388,6 +388,42 @@ static int cb_stream_close(ngtcp2_conn *tconn, uint32_t flags,
   return 0;
 }
 
+#ifdef NGTCP2_CALLBACKS_V5  /* ngtcp2 v1.25.0+ */
+static int cb_stream_close2(ngtcp2_conn *tconn, uint32_t flags,
+                           int64_t stream_id,
+                           uint64_t rx_app_error_code,
+                           uint64_t tx_app_error_code,
+                           void *user_data, void *stream_user_data)
+{
+  struct Curl_cfilter *cf = user_data;
+  struct cf_ngtcp2_ctx *ctx = cf->ctx;
+  struct Curl_easy *data = stream_user_data;
+  uint64_t h3_app_error_code = NGHTTP3_H3_NO_ERROR;
+  int rv;
+
+  (void)tconn;
+  (void)tx_app_error_code;
+  /* stream is closed... */
+  if(!data)
+    data = CF_DATA_CURRENT(cf);
+  if(!data)
+    return NGTCP2_ERR_CALLBACK_FAILURE;
+
+  if(flags & NGTCP2_STREAM_CLOSE2_FLAG_RX_APP_ERROR_CODE_SET)
+    h3_app_error_code = rx_app_error_code;
+
+  rv = nghttp3_conn_close_stream(ctx->h3conn, stream_id, h3_app_error_code);
+  CURL_TRC_CF(data, cf, "[%" PRId64 "] quic close(app_error=%"
+              PRIu64 ") -> %d", stream_id, h3_app_error_code, rv);
+  if(rv && rv != NGHTTP3_ERR_STREAM_NOT_FOUND) {
+    Curl_cf_ngtcp2_h3_err_set(cf, data, rv);
+    return NGTCP2_ERR_CALLBACK_FAILURE;
+  }
+
+  return 0;
+}
+#endif
+
 static int cb_stream_reset(ngtcp2_conn *tconn, int64_t stream_id,
                            uint64_t final_size, uint64_t app_error_code,
                            void *user_data, void *stream_user_data)
@@ -603,6 +639,9 @@ static ngtcp2_callbacks ng_callbacks = {
 #ifdef NGTCP2_CALLBACKS_V4  /* ngtcp2 v1.24.0+ */
   NULL, /* recv_stop_sending */
 #endif
+#ifdef NGTCP2_CALLBACKS_V5  /* ngtcp2 v1.25.0+ */
+  cb_stream_close2, /* is called instead of cb_stream_close when set */
+#endif
 };
 #ifdef CURL_HAVE_DIAG
 #pragma GCC diagnostic pop
index 095dc382baf707ef7bb53268937ba04fdb6f9320..ca808e007795ae212abda916882b75ad5ff34934 100644 (file)
@@ -104,14 +104,12 @@ class TestAuth:
             '--basic', '--user', f'test:{password}',
             '--trace-config', 'http/2,http/3'
         ])
-        # but apache either denies on length limit or gives a 400
-        if proto == 'h3':
-            # depends on nghttp3 version
-            assert r.exit_code in (0, 56), f'expected exit code 0 or 56, '\
-                                           f'got {r.exit_code}\n{r.dump_logs()}'
+        if proto == 'h3' and r.exit_code != 0:
+            # nghttpx violently closes the connection now
+            assert r.exit_code in [55, 56, 95], f'{r.dump_logs()}'
         else:
+            # but apache either denies on length limit or gives a 400
             r.check_exit_code(0)
-        if r.exit_code == 0:
             assert r.stats[0]['http_code'] in [400, 431]
 
     # PUT data, basic auth with very large pw