]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
vtls: set seen http version on successful ALPN
authorStefan Eissing <stefan@eissing.org>
Tue, 5 Aug 2025 11:37:12 +0000 (13:37 +0200)
committerDaniel Stenberg <daniel@haxx.se>
Tue, 5 Aug 2025 14:01:39 +0000 (16:01 +0200)
When a HTTP version has been negotiated via ALPN, set the member
`conn->httpversion_seen` accordingly. This allows pending transfers to
reuse multiplexed http connections before the response to the first
transfer has arrived.

Fixes #18177
Reported-by: IoannisGS on github
Closes #18181

lib/http.c
lib/urldata.h
lib/vquic/curl_ngtcp2.c
lib/vquic/curl_osslq.c
lib/vquic/curl_quiche.c
lib/vtls/vtls.c

index d41aefdfaa37d6850ec3530580fd33fdb17bbb8b..8eb13788516c9c3f5abdf8b55cc1a7258c9df065 100644 (file)
@@ -2704,6 +2704,8 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
       if(result)
         goto fail;
       info_version = "HTTP/2";
+      /* There is no ALPN here, but the connection is now definitely h2 */
+      conn->httpversion_seen = 20;
     }
     else
       info_version = "HTTP/1.x";
index 438f11218c509d2835e803a815b38a0b3bcfa615..b9cc25b9b03b6fd184c1a2cf121fb27b8025241d 100644 (file)
@@ -768,7 +768,7 @@ struct connectdata {
    and happy eyeballing. Use `Curl_conn_get_transport() for actual value
    once the connection is set up. */
   unsigned char ip_version; /* copied from the Curl_easy at creation time */
-  /* HTTP version last responded with by the server.
+  /* HTTP version last responded with by the server or negotiated via ALPN.
    * 0 at start, then one of 09, 10, 11, etc. */
   unsigned char httpversion_seen;
   unsigned char connect_only;
index 1cb99aaea8694bb3240623696cf362ac8222e738..64670251375074af3974859855fec57ff376fb03 100644 (file)
@@ -1955,9 +1955,9 @@ static CURLcode h3_data_pause(struct Curl_cfilter *cf,
   return CURLE_OK;
 }
 
-static CURLcode cf_ngtcp2_data_event(struct Curl_cfilter *cf,
-                                     struct Curl_easy *data,
-                                     int event, int arg1, void *arg2)
+static CURLcode cf_ngtcp2_cntrl(struct Curl_cfilter *cf,
+                                struct Curl_easy *data,
+                                int event, int arg1, void *arg2)
 {
   struct cf_ngtcp2_ctx *ctx = cf->ctx;
   CURLcode result = CURLE_OK;
@@ -1995,6 +1995,10 @@ static CURLcode cf_ngtcp2_data_event(struct Curl_cfilter *cf,
     }
     break;
   }
+  case CF_CTRL_CONN_INFO_UPDATE:
+    if(!cf->sockindex && cf->connected)
+      cf->conn->httpversion_seen = 30;
+    break;
   default:
     break;
   }
@@ -2733,7 +2737,7 @@ struct Curl_cftype Curl_cft_http3 = {
   Curl_cf_def_data_pending,
   cf_ngtcp2_send,
   cf_ngtcp2_recv,
-  cf_ngtcp2_data_event,
+  cf_ngtcp2_cntrl,
   cf_ngtcp2_conn_is_alive,
   Curl_cf_def_conn_keep_alive,
   cf_ngtcp2_query,
index c18801d811f6aec900db63bd5cad044831bc738a..fa2c0a2899e88bb93677afc7941a1858cbc0c2af 100644 (file)
@@ -2168,9 +2168,9 @@ static bool cf_osslq_data_pending(struct Curl_cfilter *cf,
   return stream && !Curl_bufq_is_empty(&stream->recvbuf);
 }
 
-static CURLcode cf_osslq_data_event(struct Curl_cfilter *cf,
-                                    struct Curl_easy *data,
-                                    int event, int arg1, void *arg2)
+static CURLcode cf_osslq_cntrl(struct Curl_cfilter *cf,
+                               struct Curl_easy *data,
+                               int event, int arg1, void *arg2)
 {
   struct cf_osslq_ctx *ctx = cf->ctx;
   CURLcode result = CURLE_OK;
@@ -2206,6 +2206,10 @@ static CURLcode cf_osslq_data_event(struct Curl_cfilter *cf,
     }
     break;
   }
+  case CF_CTRL_CONN_INFO_UPDATE:
+    if(!cf->sockindex && cf->connected)
+      cf->conn->httpversion_seen = 30;
+    break;
   default:
     break;
   }
@@ -2384,7 +2388,7 @@ struct Curl_cftype Curl_cft_http3 = {
   cf_osslq_data_pending,
   cf_osslq_send,
   cf_osslq_recv,
-  cf_osslq_data_event,
+  cf_osslq_cntrl,
   cf_osslq_conn_is_alive,
   Curl_cf_def_conn_keep_alive,
   cf_osslq_query,
index b981f4d780c154aab4ab556142bcbb2c8c099758..f22566781129ee344fe9dd375e89b8b3bdd2923d 100644 (file)
@@ -1197,9 +1197,9 @@ static CURLcode h3_data_pause(struct Curl_cfilter *cf,
   return CURLE_OK;
 }
 
-static CURLcode cf_quiche_data_event(struct Curl_cfilter *cf,
-                                     struct Curl_easy *data,
-                                     int event, int arg1, void *arg2)
+static CURLcode cf_quiche_cntrl(struct Curl_cfilter *cf,
+                                struct Curl_easy *data,
+                                int event, int arg1, void *arg2)
 {
   struct cf_quiche_ctx *ctx = cf->ctx;
   CURLcode result = CURLE_OK;
@@ -1238,6 +1238,10 @@ static CURLcode cf_quiche_data_event(struct Curl_cfilter *cf,
     }
     break;
   }
+  case CF_CTRL_CONN_INFO_UPDATE:
+    if(!cf->sockindex && cf->connected)
+      cf->conn->httpversion_seen = 30;
+    break;
   default:
     break;
   }
@@ -1621,7 +1625,7 @@ struct Curl_cftype Curl_cft_http3 = {
   cf_quiche_data_pending,
   cf_quiche_send,
   cf_quiche_recv,
-  cf_quiche_data_event,
+  cf_quiche_cntrl,
   cf_quiche_conn_is_alive,
   Curl_cf_def_conn_keep_alive,
   cf_quiche_query,
index 96d64dd606fdca96e8c84111313eaddaf35565c0..f17f9142bed1964ca7a84820f9fcc629020629ae 100644 (file)
@@ -1605,6 +1605,30 @@ static CURLcode ssl_cf_query(struct Curl_cfilter *cf,
     CURLE_UNKNOWN_OPTION;
 }
 
+static CURLcode ssl_cf_cntrl(struct Curl_cfilter *cf,
+                             struct Curl_easy *data,
+                             int event, int arg1, void *arg2)
+{
+  struct ssl_connect_data *connssl = cf->ctx;
+
+  (void)arg1;
+  (void)arg2;
+  (void)data;
+  switch(event) {
+  case CF_CTRL_CONN_INFO_UPDATE:
+    if(connssl->negotiated.alpn && !cf->sockindex) {
+      if(!strcmp("http/1.1", connssl->negotiated.alpn))
+        cf->conn->httpversion_seen = 11;
+      else if(!strcmp("h2", connssl->negotiated.alpn))
+        cf->conn->httpversion_seen = 20;
+      else if(!strcmp("h3", connssl->negotiated.alpn))
+        cf->conn->httpversion_seen = 30;
+    }
+    break;
+  }
+  return CURLE_OK;
+}
+
 static bool cf_ssl_is_alive(struct Curl_cfilter *cf, struct Curl_easy *data,
                             bool *input_pending)
 {
@@ -1628,7 +1652,7 @@ struct Curl_cftype Curl_cft_ssl = {
   ssl_cf_data_pending,
   ssl_cf_send,
   ssl_cf_recv,
-  Curl_cf_def_cntrl,
+  ssl_cf_cntrl,
   cf_ssl_is_alive,
   Curl_cf_def_conn_keep_alive,
   ssl_cf_query,