]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
cf-https-connect: look into httpsrr alpns when available
authorStefan Eissing <stefan@eissing.org>
Wed, 15 Jan 2025 15:45:25 +0000 (16:45 +0100)
committerDaniel Stenberg <daniel@haxx.se>
Thu, 16 Jan 2025 07:23:02 +0000 (08:23 +0100)
Improved the filter implementation to be flexible in which order h3 and
h2/h1 are attempted. When HTTPSRR is enabled, look at the ALPNs it found
and use the order given for connecting in default setups.

Closes #16012

lib/cf-https-connect.c
lib/doh.c

index 9eb38f415c2cfddbac0505956abfe7bd54dc6157..cb06d2d07014c75af8d4400232311593b85a898a 100644 (file)
@@ -31,6 +31,7 @@
 #include "curl_trc.h"
 #include "cfilters.h"
 #include "connect.h"
+#include "hostip.h"
 #include "multiif.h"
 #include "cf-https-connect.h"
 #include "http2.h"
 #include "memdebug.h"
 
 
+#ifndef ARRAYSIZE
+#define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0]))
+#endif
+
 typedef enum {
   CF_HC_INIT,
   CF_HC_CONNECT,
@@ -55,7 +60,7 @@ struct cf_hc_baller {
   CURLcode result;
   struct curltime started;
   int reply_ms;
-  BIT(enabled);
+  enum alpnid alpn_id;
   BIT(shutdown);
 };
 
@@ -73,7 +78,7 @@ static void cf_hc_baller_reset(struct cf_hc_baller *b,
 
 static bool cf_hc_baller_is_active(struct cf_hc_baller *b)
 {
-  return b->enabled && b->cf && !b->result;
+  return b->cf && !b->result;
 }
 
 static bool cf_hc_baller_has_started(struct cf_hc_baller *b)
@@ -84,7 +89,7 @@ static bool cf_hc_baller_has_started(struct cf_hc_baller *b)
 static int cf_hc_baller_reply_ms(struct cf_hc_baller *b,
                                  struct Curl_easy *data)
 {
-  if(b->reply_ms < 0)
+  if(b->cf && (b->reply_ms < 0))
     b->cf->cft->query(b->cf, data, CF_QUERY_CONNECT_REPLY_MS,
                       &b->reply_ms, NULL);
   return b->reply_ms;
@@ -116,8 +121,8 @@ struct cf_hc_ctx {
   const struct Curl_dns_entry *remotehost;
   struct curltime started;  /* when connect started */
   CURLcode result;          /* overall result */
-  struct cf_hc_baller h3_baller;
-  struct cf_hc_baller h21_baller;
+  struct cf_hc_baller ballers[2];
+  size_t baller_count;
   unsigned int soft_eyeballs_timeout_ms;
   unsigned int hard_eyeballs_timeout_ms;
 };
@@ -125,17 +130,32 @@ struct cf_hc_ctx {
 static void cf_hc_baller_init(struct cf_hc_baller *b,
                               struct Curl_cfilter *cf,
                               struct Curl_easy *data,
-                              const char *name,
                               int transport)
 {
   struct cf_hc_ctx *ctx = cf->ctx;
   struct Curl_cfilter *save = cf->next;
 
-  b->name = name;
   cf->next = NULL;
   b->started = Curl_now();
-  b->result = Curl_cf_setup_insert_after(cf, data, ctx->remotehost,
-                                         transport, CURL_CF_SSL_ENABLE);
+  switch(b->alpn_id) {
+  case ALPN_h3:
+    b->name = "h3";
+    transport = TRNSPRT_QUIC;
+    break;
+  case ALPN_h2:
+    b->name = "h2";
+    break;
+  case ALPN_h1:
+    b->name = "h1";
+    break;
+  default:
+    b->result = CURLE_FAILED_INIT;
+    break;
+  }
+
+  if(!b->result)
+    b->result = Curl_cf_setup_insert_after(cf, data, ctx->remotehost,
+                                           transport, CURL_CF_SSL_ENABLE);
   b->cf = cf->next;
   cf->next = save;
 }
@@ -157,10 +177,11 @@ static CURLcode cf_hc_baller_connect(struct cf_hc_baller *b,
 static void cf_hc_reset(struct Curl_cfilter *cf, struct Curl_easy *data)
 {
   struct cf_hc_ctx *ctx = cf->ctx;
+  size_t i;
 
   if(ctx) {
-    cf_hc_baller_reset(&ctx->h3_baller, data);
-    cf_hc_baller_reset(&ctx->h21_baller, data);
+    for(i = 0; i < ctx->baller_count; ++i)
+      cf_hc_baller_reset(&ctx->ballers[i], data);
     ctx->state = CF_HC_INIT;
     ctx->result = CURLE_OK;
     ctx->hard_eyeballs_timeout_ms = data->set.happy_eyeballs_timeout;
@@ -175,12 +196,12 @@ static CURLcode baller_connected(struct Curl_cfilter *cf,
   struct cf_hc_ctx *ctx = cf->ctx;
   CURLcode result = CURLE_OK;
   int reply_ms;
+  size_t i;
 
   DEBUGASSERT(winner->cf);
-  if(winner != &ctx->h3_baller)
-    cf_hc_baller_reset(&ctx->h3_baller, data);
-  if(winner != &ctx->h21_baller)
-    cf_hc_baller_reset(&ctx->h21_baller, data);
+  for(i = 0; i < ctx->baller_count; ++i)
+    if(winner != &ctx->ballers[i])
+      cf_hc_baller_reset(&ctx->ballers[i], data);
 
   reply_ms = cf_hc_baller_reply_ms(winner, data);
   if(reply_ms >= 0)
@@ -218,31 +239,31 @@ static CURLcode baller_connected(struct Curl_cfilter *cf,
 }
 
 
-static bool time_to_start_h21(struct Curl_cfilter *cf,
-                              struct Curl_easy *data,
-                              struct curltime now)
+static bool time_to_start_next(struct Curl_cfilter *cf,
+                               struct Curl_easy *data,
+                               size_t idx, struct curltime now)
 {
   struct cf_hc_ctx *ctx = cf->ctx;
   timediff_t elapsed_ms;
 
-  if(!ctx->h21_baller.enabled || cf_hc_baller_has_started(&ctx->h21_baller))
+  if(idx >= ctx->baller_count)
+    return FALSE;
+  if(cf_hc_baller_has_started(&ctx->ballers[idx]))
     return FALSE;
-
-  if(!ctx->h3_baller.enabled || !cf_hc_baller_is_active(&ctx->h3_baller))
-    return TRUE;
 
   elapsed_ms = Curl_timediff(now, ctx->started);
   if(elapsed_ms >= ctx->hard_eyeballs_timeout_ms) {
-    CURL_TRC_CF(data, cf, "hard timeout of %dms reached, starting h21",
-                ctx->hard_eyeballs_timeout_ms);
+    CURL_TRC_CF(data, cf, "hard timeout of %dms reached, starting %s",
+                ctx->hard_eyeballs_timeout_ms, ctx->ballers[idx].name);
     return TRUE;
   }
 
-  if(elapsed_ms >= ctx->soft_eyeballs_timeout_ms) {
-    if(cf_hc_baller_reply_ms(&ctx->h3_baller, data) < 0) {
-      CURL_TRC_CF(data, cf, "soft timeout of %dms reached, h3 has not "
-                  "seen any data, starting h21",
-                  ctx->soft_eyeballs_timeout_ms);
+  if((idx > 0) && (elapsed_ms >= ctx->soft_eyeballs_timeout_ms)) {
+    if(cf_hc_baller_reply_ms(&ctx->ballers[idx - 1], data) < 0) {
+      CURL_TRC_CF(data, cf, "soft timeout of %dms reached, %s has not "
+                  "seen any data, starting %s",
+                  ctx->soft_eyeballs_timeout_ms,
+                  ctx->ballers[idx - 1].name, ctx->ballers[idx].name);
       return TRUE;
     }
     /* set the effective hard timeout again */
@@ -259,6 +280,7 @@ static CURLcode cf_hc_connect(struct Curl_cfilter *cf,
   struct cf_hc_ctx *ctx = cf->ctx;
   struct curltime now;
   CURLcode result = CURLE_OK;
+  size_t i, failed_ballers;
 
   (void)blocking;
   if(cf->connected) {
@@ -270,51 +292,54 @@ static CURLcode cf_hc_connect(struct Curl_cfilter *cf,
   now = Curl_now();
   switch(ctx->state) {
   case CF_HC_INIT:
-    DEBUGASSERT(!ctx->h3_baller.cf);
-    DEBUGASSERT(!ctx->h21_baller.cf);
     DEBUGASSERT(!cf->next);
+    for(i = 0; i < ctx->baller_count; i++)
+      DEBUGASSERT(!ctx->ballers[i].cf);
     CURL_TRC_CF(data, cf, "connect, init");
     ctx->started = now;
-    if(ctx->h3_baller.enabled) {
-      cf_hc_baller_init(&ctx->h3_baller, cf, data, "h3", TRNSPRT_QUIC);
-      if(ctx->h21_baller.enabled)
-        Curl_expire(data, ctx->soft_eyeballs_timeout_ms, EXPIRE_ALPN_EYEBALLS);
-    }
-    else if(ctx->h21_baller.enabled)
-      cf_hc_baller_init(&ctx->h21_baller, cf, data, "h21",
-                        cf->conn->transport);
+    cf_hc_baller_init(&ctx->ballers[0], cf, data, cf->conn->transport);
+    if(ctx->baller_count > 1)
+      Curl_expire(data, ctx->soft_eyeballs_timeout_ms, EXPIRE_ALPN_EYEBALLS);
     ctx->state = CF_HC_CONNECT;
     FALLTHROUGH();
 
   case CF_HC_CONNECT:
-    if(cf_hc_baller_is_active(&ctx->h3_baller)) {
-      result = cf_hc_baller_connect(&ctx->h3_baller, cf, data, done);
+    if(cf_hc_baller_is_active(&ctx->ballers[0])) {
+      result = cf_hc_baller_connect(&ctx->ballers[0], cf, data, done);
       if(!result && *done) {
-        result = baller_connected(cf, data, &ctx->h3_baller);
+        result = baller_connected(cf, data, &ctx->ballers[0]);
         goto out;
       }
     }
 
-    if(time_to_start_h21(cf, data, now)) {
-      cf_hc_baller_init(&ctx->h21_baller, cf, data, "h21",
-                        cf->conn->transport);
+    if(time_to_start_next(cf, data, 1, now)) {
+      cf_hc_baller_init(&ctx->ballers[1], cf, data, cf->conn->transport);
     }
 
-    if(cf_hc_baller_is_active(&ctx->h21_baller)) {
-      CURL_TRC_CF(data, cf, "connect, check h21");
-      result = cf_hc_baller_connect(&ctx->h21_baller, cf, data, done);
+    if((ctx->baller_count > 1) && cf_hc_baller_is_active(&ctx->ballers[1])) {
+      CURL_TRC_CF(data, cf, "connect, check %s", ctx->ballers[1].name);
+      result = cf_hc_baller_connect(&ctx->ballers[1], cf, data, done);
       if(!result && *done) {
-        result = baller_connected(cf, data, &ctx->h21_baller);
+        result = baller_connected(cf, data, &ctx->ballers[1]);
         goto out;
       }
     }
 
-    if((!ctx->h3_baller.enabled || ctx->h3_baller.result) &&
-       (!ctx->h21_baller.enabled || ctx->h21_baller.result)) {
-      /* both failed or disabled. we give up */
+    failed_ballers = 0;
+    for(i = 0; i < ctx->baller_count; i++) {
+      if(ctx->ballers[i].result)
+        ++failed_ballers;
+    }
+
+    if(failed_ballers == ctx->baller_count) {
+      /* all have failed. we give up */
       CURL_TRC_CF(data, cf, "connect, all failed");
-      result = ctx->result = ctx->h3_baller.enabled ?
-        ctx->h3_baller.result : ctx->h21_baller.result;
+      for(i = 0; i < ctx->baller_count; i++) {
+        if(ctx->ballers[i].result) {
+          result = ctx->ballers[i].result;
+          break;
+        }
+      }
       ctx->state = CF_HC_FAILURE;
       goto out;
     }
@@ -344,7 +369,6 @@ static CURLcode cf_hc_shutdown(struct Curl_cfilter *cf,
                                struct Curl_easy *data, bool *done)
 {
   struct cf_hc_ctx *ctx = cf->ctx;
-  struct cf_hc_baller *ballers[2];
   size_t i;
   CURLcode result = CURLE_OK;
 
@@ -356,10 +380,8 @@ static CURLcode cf_hc_shutdown(struct Curl_cfilter *cf,
 
   /* shutdown all ballers that have not done so already. If one fails,
    * continue shutting down others until all are shutdown. */
-  ballers[0] = &ctx->h3_baller;
-  ballers[1] = &ctx->h21_baller;
-  for(i = 0; i < sizeof(ballers)/sizeof(ballers[0]); i++) {
-    struct cf_hc_baller *b = ballers[i];
+  for(i = 0; i < ctx->baller_count; i++) {
+    struct cf_hc_baller *b = &ctx->ballers[i];
     bool bdone = FALSE;
     if(!cf_hc_baller_is_active(b) || b->shutdown)
       continue;
@@ -369,14 +391,14 @@ static CURLcode cf_hc_shutdown(struct Curl_cfilter *cf,
   }
 
   *done = TRUE;
-  for(i = 0; i < sizeof(ballers)/sizeof(ballers[0]); i++) {
-    if(ballers[i] && !ballers[i]->shutdown)
+  for(i = 0; i < ctx->baller_count; i++) {
+    if(!ctx->ballers[i].shutdown)
       *done = FALSE;
   }
   if(*done) {
-    for(i = 0; i < sizeof(ballers)/sizeof(ballers[0]); i++) {
-      if(ballers[i] && ballers[i]->result)
-        result = ballers[i]->result;
+    for(i = 0; i < ctx->baller_count; i++) {
+      if(ctx->ballers[i].result)
+        result = ctx->ballers[i].result;
     }
   }
   CURL_TRC_CF(data, cf, "shutdown -> %d, done=%d", result, *done);
@@ -389,13 +411,10 @@ static void cf_hc_adjust_pollset(struct Curl_cfilter *cf,
 {
   if(!cf->connected) {
     struct cf_hc_ctx *ctx = cf->ctx;
-    struct cf_hc_baller *ballers[2];
     size_t i;
 
-    ballers[0] = &ctx->h3_baller;
-    ballers[1] = &ctx->h21_baller;
-    for(i = 0; i < sizeof(ballers)/sizeof(ballers[0]); i++) {
-      struct cf_hc_baller *b = ballers[i];
+    for(i = 0; i < ctx->baller_count; i++) {
+      struct cf_hc_baller *b = &ctx->ballers[i];
       if(!cf_hc_baller_is_active(b))
         continue;
       Curl_conn_cf_adjust_pollset(b->cf, data, ps);
@@ -408,13 +427,16 @@ static bool cf_hc_data_pending(struct Curl_cfilter *cf,
                                const struct Curl_easy *data)
 {
   struct cf_hc_ctx *ctx = cf->ctx;
+  size_t i;
 
   if(cf->connected)
     return cf->next->cft->has_data_pending(cf->next, data);
 
   CURL_TRC_CF((struct Curl_easy *)data, cf, "data_pending");
-  return cf_hc_baller_data_pending(&ctx->h3_baller, data)
-         || cf_hc_baller_data_pending(&ctx->h21_baller, data);
+  for(i = 0; i < ctx->baller_count; i++)
+    if(cf_hc_baller_data_pending(&ctx->ballers[i], data))
+      return TRUE;
+  return FALSE;
 }
 
 static struct curltime cf_get_max_baller_time(struct Curl_cfilter *cf,
@@ -422,21 +444,17 @@ static struct curltime cf_get_max_baller_time(struct Curl_cfilter *cf,
                                               int query)
 {
   struct cf_hc_ctx *ctx = cf->ctx;
-  struct Curl_cfilter *cfb;
   struct curltime t, tmax;
+  size_t i;
 
   memset(&tmax, 0, sizeof(tmax));
-  memset(&t, 0, sizeof(t));
-  cfb = ctx->h21_baller.enabled ? ctx->h21_baller.cf : NULL;
-  if(cfb && !cfb->cft->query(cfb, data, query, NULL, &t)) {
-    if((t.tv_sec || t.tv_usec) && Curl_timediff_us(t, tmax) > 0)
-      tmax = t;
-  }
-  memset(&t, 0, sizeof(t));
-  cfb = ctx->h3_baller.enabled ? ctx->h3_baller.cf : NULL;
-  if(cfb && !cfb->cft->query(cfb, data, query, NULL, &t)) {
-    if((t.tv_sec || t.tv_usec) && Curl_timediff_us(t, tmax) > 0)
-      tmax = t;
+  for(i = 0; i < ctx->baller_count; i++) {
+    struct Curl_cfilter *cfb = ctx->ballers[i].cf;
+    memset(&t, 0, sizeof(t));
+    if(cfb && !cfb->cft->query(cfb, data, query, NULL, &t)) {
+      if((t.tv_sec || t.tv_usec) && Curl_timediff_us(t, tmax) > 0)
+        tmax = t;
+    }
   }
   return tmax;
 }
@@ -446,6 +464,7 @@ static CURLcode cf_hc_query(struct Curl_cfilter *cf,
                             int query, int *pres1, void *pres2)
 {
   struct cf_hc_ctx *ctx = cf->ctx;
+  size_t i;
 
   if(!cf->connected) {
     switch(query) {
@@ -460,11 +479,11 @@ static CURLcode cf_hc_query(struct Curl_cfilter *cf,
       return CURLE_OK;
     }
     case CF_QUERY_NEED_FLUSH: {
-      if(cf_hc_baller_needs_flush(&ctx->h3_baller, data)
-         || cf_hc_baller_needs_flush(&ctx->h21_baller, data)) {
-        *pres1 = TRUE;
-        return CURLE_OK;
-      }
+      for(i = 0; i < ctx->baller_count; i++)
+        if(cf_hc_baller_needs_flush(&ctx->ballers[i], data)) {
+          *pres1 = TRUE;
+          return CURLE_OK;
+        }
       break;
     }
     default:
@@ -482,14 +501,17 @@ static CURLcode cf_hc_cntrl(struct Curl_cfilter *cf,
 {
   struct cf_hc_ctx *ctx = cf->ctx;
   CURLcode result = CURLE_OK;
+  size_t i;
 
   if(!cf->connected) {
-    result = cf_hc_baller_cntrl(&ctx->h3_baller, data, event, arg1, arg2);
-    if(!result || (result == CURLE_AGAIN))
-      result = cf_hc_baller_cntrl(&ctx->h21_baller, data, event, arg1, arg2);
-    if(result == CURLE_AGAIN)
-      result = CURLE_OK;
+    for(i = 0; i < ctx->baller_count; i++) {
+      result = cf_hc_baller_cntrl(&ctx->ballers[i], data, event, arg1, arg2);
+      if(result && (result != CURLE_AGAIN))
+        goto out;
+    }
+    result = CURLE_OK;
   }
+out:
   return result;
 }
 
@@ -537,23 +559,37 @@ struct Curl_cftype Curl_cft_http_connect = {
 static CURLcode cf_hc_create(struct Curl_cfilter **pcf,
                              struct Curl_easy *data,
                              const struct Curl_dns_entry *remotehost,
-                             bool try_h3, bool try_h21)
+                             enum alpnid *alpnids, size_t alpn_count)
 {
   struct Curl_cfilter *cf = NULL;
   struct cf_hc_ctx *ctx;
   CURLcode result = CURLE_OK;
+  size_t i;
+
+  DEBUGASSERT(alpnids);
+  DEBUGASSERT(alpn_count);
+  DEBUGASSERT(alpn_count <= ARRAYSIZE(ctx->ballers));
+  if(!alpn_count || (alpn_count > ARRAYSIZE(ctx->ballers))) {
+    failf(data, "https-connect filter create with unsupported %zu ALPN ids",
+          alpn_count);
+    return CURLE_FAILED_INIT;
+  }
 
-  (void)data;
   ctx = calloc(1, sizeof(*ctx));
   if(!ctx) {
     result = CURLE_OUT_OF_MEMORY;
     goto out;
   }
   ctx->remotehost = remotehost;
-  ctx->h3_baller.enabled = try_h3;
-  ctx->h21_baller.enabled = try_h21;
+  for(i = 0; i < alpn_count; ++i)
+    ctx->ballers[i].alpn_id = alpnids[i];
+  for(; i < ARRAYSIZE(ctx->ballers); ++i)
+    ctx->ballers[i].alpn_id = ALPN_none;
+  ctx->baller_count = alpn_count;
 
   result = Curl_cf_create(&cf, &Curl_cft_http_connect, ctx);
+  CURL_TRC_CF(data, cf, "created with %zu ALPNs -> %d",
+              ctx->baller_count, result);
   if(result)
     goto out;
   ctx = NULL;
@@ -569,13 +605,13 @@ static CURLcode cf_http_connect_add(struct Curl_easy *data,
                                     struct connectdata *conn,
                                     int sockindex,
                                     const struct Curl_dns_entry *remotehost,
-                                    bool try_h3, bool try_h21)
+                                    enum alpnid *alpn_ids, size_t alpn_count)
 {
   struct Curl_cfilter *cf;
   CURLcode result = CURLE_OK;
 
   DEBUGASSERT(data);
-  result = cf_hc_create(&cf, data, remotehost, try_h3, try_h21);
+  result = cf_hc_create(&cf, data, remotehost, alpn_ids, alpn_count);
   if(result)
     goto out;
   Curl_conn_cf_add(data, conn, sockindex, cf);
@@ -588,31 +624,86 @@ CURLcode Curl_cf_https_setup(struct Curl_easy *data,
                              int sockindex,
                              const struct Curl_dns_entry *remotehost)
 {
-  bool try_h3 = FALSE, try_h21 = TRUE; /* defaults, for now */
+  enum alpnid alpn_ids[2];
+  size_t alpn_count = 0;
   CURLcode result = CURLE_OK;
 
   (void)sockindex;
   (void)remotehost;
 
-  if(!conn->bits.tls_enable_alpn)
-    goto out;
-
-  if(data->state.httpwant == CURL_HTTP_VERSION_3ONLY) {
-    result = Curl_conn_may_http3(data, conn);
-    if(result) /* cannot do it */
-      goto out;
-    try_h3 = TRUE;
-    try_h21 = FALSE;
+  if(conn->bits.tls_enable_alpn) {
+    switch(data->state.httpwant) {
+    case CURL_HTTP_VERSION_NONE:
+      /* No preferences by transfer setup. Choose best defaults */
+#ifdef USE_HTTPSRR
+      if(conn->dns_entry && conn->dns_entry->hinfo &&
+         !conn->dns_entry->hinfo->no_def_alpn) {
+        size_t i, j;
+        for(i = 0; i < ARRAYSIZE(conn->dns_entry->hinfo->alpns) &&
+                   alpn_count < ARRAYSIZE(alpn_ids); ++i) {
+          bool present = FALSE;
+          enum alpnid alpn = conn->dns_entry->hinfo->alpns[i];
+          for(j = 0; j < alpn_count; ++j) {
+            if(alpn == alpn_ids[j]) {
+              present = TRUE;
+              break;
+            }
+          }
+          if(!present) {
+            switch(alpn) {
+            case ALPN_h3:
+              if(Curl_conn_may_http3(data, conn))
+                break;  /* not possible */
+              FALLTHROUGH();
+            case ALPN_h2:
+            case ALPN_h1:
+              alpn_ids[alpn_count++] = alpn;
+              break;
+            default: /* ignore */
+              break;
+            }
+          }
+        }
+      }
+#endif
+      if(!alpn_count)
+        alpn_ids[alpn_count++] = ALPN_h2;
+      break;
+    case CURL_HTTP_VERSION_3ONLY:
+      result = Curl_conn_may_http3(data, conn);
+      if(result) /* cannot do it */
+        goto out;
+      alpn_ids[alpn_count++] = ALPN_h3;
+      break;
+    case CURL_HTTP_VERSION_3:
+      /* We assume that silently not even trying H3 is ok here */
+      /* TODO: should we fail instead? */
+      if(Curl_conn_may_http3(data, conn) == CURLE_OK)
+        alpn_ids[alpn_count++] = ALPN_h3;
+      alpn_ids[alpn_count++] = ALPN_h2;
+      break;
+    case CURL_HTTP_VERSION_2_0:
+    case CURL_HTTP_VERSION_2TLS:
+    case CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE:
+      alpn_ids[alpn_count++] = ALPN_h2;
+      break;
+    case CURL_HTTP_VERSION_1_0:
+    case CURL_HTTP_VERSION_1_1:
+      alpn_ids[alpn_count++] = ALPN_h1;
+      break;
+    default:
+      alpn_ids[alpn_count++] = ALPN_h2;
+      break;
+    }
   }
-  else if(data->state.httpwant >= CURL_HTTP_VERSION_3) {
-    /* We assume that silently not even trying H3 is ok here */
-    /* TODO: should we fail instead? */
-    try_h3 = (Curl_conn_may_http3(data, conn) == CURLE_OK);
-    try_h21 = TRUE;
+
+  /* If we identified ALPNs to use, install our filter. Otherwise,
+   * install nothing, so our call will use a default connect setup. */
+  if(alpn_count) {
+    result = cf_http_connect_add(data, conn, sockindex, remotehost,
+                                 alpn_ids, alpn_count);
   }
 
-  result = cf_http_connect_add(data, conn, sockindex, remotehost,
-                               try_h3, try_h21);
 out:
   return result;
 }
index 834c00346bb438923b0f4945943d4e420303007a..d4500b3bd50bd0932bb421ac18071b788303af2d 100644 (file)
--- a/lib/doh.c
+++ b/lib/doh.c
@@ -1105,7 +1105,7 @@ static CURLcode doh_decode_rdata_alpn(unsigned char *cp, size_t len,
     if(id != ALPN_none) {
       if(idnum == MAX_HTTPSRR_ALPNS)
         break;
-      alpns[idnum++] = id;
+      alpns[idnum++] = (unsigned char)id;
     }
     Curl_dyn_reset(&dval);
   }