summaryrefslogtreecommitdiff
path: root/libs/libcurl/src/cf-https-connect.c
diff options
context:
space:
mode:
Diffstat (limited to 'libs/libcurl/src/cf-https-connect.c')
-rw-r--r--libs/libcurl/src/cf-https-connect.c399
1 files changed, 261 insertions, 138 deletions
diff --git a/libs/libcurl/src/cf-https-connect.c b/libs/libcurl/src/cf-https-connect.c
index 3d1cdca111..49b3332cac 100644
--- a/libs/libcurl/src/cf-https-connect.c
+++ b/libs/libcurl/src/cf-https-connect.c
@@ -24,13 +24,14 @@
#include "curl_setup.h"
-#if !defined(CURL_DISABLE_HTTP) && !defined(USE_HYPER)
+#if !defined(CURL_DISABLE_HTTP)
#include "urldata.h"
#include <curl/curl.h>
#include "curl_trc.h"
#include "cfilters.h"
#include "connect.h"
+#include "hostip.h"
#include "multiif.h"
#include "cf-https-connect.h"
#include "http2.h"
@@ -41,7 +42,6 @@
#include "curl_memory.h"
#include "memdebug.h"
-
typedef enum {
CF_HC_INIT,
CF_HC_CONNECT,
@@ -55,7 +55,7 @@ struct cf_hc_baller {
CURLcode result;
struct curltime started;
int reply_ms;
- BIT(enabled);
+ enum alpnid alpn_id;
BIT(shutdown);
};
@@ -73,7 +73,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 +84,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;
@@ -113,29 +113,54 @@ static CURLcode cf_hc_baller_cntrl(struct cf_hc_baller *b,
struct cf_hc_ctx {
cf_hc_state state;
- 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;
};
+static void cf_hc_baller_assign(struct cf_hc_baller *b,
+ enum alpnid alpn_id)
+{
+ b->alpn_id = alpn_id;
+ switch(b->alpn_id) {
+ case ALPN_h3:
+ b->name = "h3";
+ break;
+ case ALPN_h2:
+ b->name = "h2";
+ break;
+ case ALPN_h1:
+ b->name = "h1";
+ break;
+ default:
+ b->result = CURLE_FAILED_INIT;
+ break;
+ }
+}
+
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);
+ b->started = curlx_now();
+ switch(b->alpn_id) {
+ case ALPN_h3:
+ transport = TRNSPRT_QUIC;
+ break;
+ default:
+ break;
+ }
+
+ if(!b->result)
+ b->result = Curl_cf_setup_insert_after(cf, data, transport,
+ CURL_CF_SSL_ENABLE);
b->cf = cf->next;
cf->next = save;
}
@@ -148,7 +173,7 @@ static CURLcode cf_hc_baller_connect(struct cf_hc_baller *b,
struct Curl_cfilter *save = cf->next;
cf->next = b->cf;
- b->result = Curl_conn_cf_connect(cf->next, data, FALSE, done);
+ b->result = Curl_conn_cf_connect(cf->next, data, done);
b->cf = cf->next; /* it might mutate */
cf->next = save;
return b->result;
@@ -157,14 +182,15 @@ 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;
- ctx->soft_eyeballs_timeout_ms = data->set.happy_eyeballs_timeout / 2;
+ ctx->soft_eyeballs_timeout_ms = data->set.happy_eyeballs_timeout / 4;
}
}
@@ -175,21 +201,22 @@ 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)
CURL_TRC_CF(data, cf, "connect+handshake %s: %dms, 1st data: %dms",
- winner->name, (int)Curl_timediff(Curl_now(), winner->started),
- reply_ms);
+ winner->name, (int)curlx_timediff(curlx_now(),
+ winner->started), reply_ms);
else
CURL_TRC_CF(data, cf, "deferred handshake %s: %dms",
- winner->name, (int)Curl_timediff(Curl_now(), winner->started));
+ winner->name, (int)curlx_timediff(curlx_now(),
+ winner->started));
cf->next = winner->cf;
winner->cf = NULL;
@@ -218,31 +245,40 @@ 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;
+ size_t i;
- if(!ctx->h21_baller.enabled || cf_hc_baller_has_started(&ctx->h21_baller))
+ if(idx >= ctx->baller_count)
return FALSE;
-
- if(!ctx->h3_baller.enabled || !cf_hc_baller_is_active(&ctx->h3_baller))
+ if(cf_hc_baller_has_started(&ctx->ballers[idx]))
+ return FALSE;
+ for(i = 0; i < idx; i++) {
+ if(!ctx->ballers[i].result)
+ break;
+ }
+ if(i == idx) {
+ CURL_TRC_CF(data, cf, "all previous attempts failed, starting %s",
+ ctx->ballers[idx].name);
return TRUE;
-
- elapsed_ms = Curl_timediff(now, ctx->started);
+ }
+ elapsed_ms = curlx_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 */
@@ -254,67 +290,73 @@ static bool time_to_start_h21(struct Curl_cfilter *cf,
static CURLcode cf_hc_connect(struct Curl_cfilter *cf,
struct Curl_easy *data,
- bool blocking, bool *done)
+ bool *done)
{
struct cf_hc_ctx *ctx = cf->ctx;
struct curltime now;
CURLcode result = CURLE_OK;
+ size_t i, failed_ballers;
- (void)blocking;
if(cf->connected) {
*done = TRUE;
return CURLE_OK;
}
*done = FALSE;
- now = Curl_now();
+ now = curlx_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);
+ 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);
+ CURL_TRC_CF(data, cf, "set next attempt to start in %ums",
+ ctx->soft_eyeballs_timeout_ms);
}
- else if(ctx->h21_baller.enabled)
- cf_hc_baller_init(&ctx->h21_baller, cf, data, "h21",
- cf->conn->transport);
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 */
- CURL_TRC_CF(data, cf, "connect, all failed");
- result = ctx->result = ctx->h3_baller.enabled ?
- ctx->h3_baller.result : ctx->h21_baller.result;
+ 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 attempts failed");
+ 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 +386,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 +397,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 +408,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 +428,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 +444,15 @@ 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 +460,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) && curlx_timediff_us(t, tmax) > 0)
+ tmax = t;
+ }
}
return tmax;
}
@@ -446,6 +480,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 +495,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 +517,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;
}
@@ -536,22 +574,32 @@ 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 <= CURL_ARRAYSIZE(ctx->ballers));
+ if(!alpn_count || (alpn_count > CURL_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)
+ cf_hc_baller_assign(&ctx->ballers[i], alpnids[i]);
+ for(; i < CURL_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);
if(result)
@@ -568,14 +616,13 @@ out:
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, alpn_ids, alpn_count);
if(result)
goto out;
Curl_conn_cf_add(data, conn, sockindex, cf);
@@ -583,38 +630,114 @@ out:
return result;
}
+static bool cf_https_alpns_contain(enum alpnid id,
+ enum alpnid *list, size_t len)
+{
+ size_t i;
+ for(i = 0; i < len; ++i) {
+ if(id == list[i])
+ return TRUE;
+ }
+ return FALSE;
+}
+
CURLcode Curl_cf_https_setup(struct Curl_easy *data,
struct connectdata *conn,
- int sockindex,
- const struct Curl_dns_entry *remotehost)
+ int sockindex)
{
- bool try_h3 = FALSE, try_h21 = TRUE; /* defaults, for now */
+ enum alpnid alpn_ids[2];
+ size_t alpn_count = 0;
CURLcode result = CURLE_OK;
+ struct Curl_cfilter cf_fake, *cf = NULL;
(void)sockindex;
- (void)remotehost;
-
- if(!conn->bits.tls_enable_alpn)
- goto out;
+ /* we want to log for the filter before we create it, fake it. */
+ memset(&cf_fake, 0, sizeof(cf_fake));
+ cf_fake.cft = &Curl_cft_http_connect;
+ cf = &cf_fake;
+
+ if(conn->bits.tls_enable_alpn) {
+#ifdef USE_HTTPSRR
+ /* Is there an HTTPSRR use its ALPNs here.
+ * We are here after having selected a connection to a host+port and
+ * can no longer change that. Any HTTPSRR advice for other hosts and ports
+ * we need to ignore. */
+ struct Curl_dns_entry *dns = data->state.dns[sockindex];
+ struct Curl_https_rrinfo *rr = dns ? dns->hinfo : NULL;
+ if(rr && !rr->no_def_alpn && /* ALPNs are defaults */
+ (!rr->target || /* for same host */
+ !rr->target[0] ||
+ (rr->target[0] == '.' &&
+ !rr->target[1])) &&
+ (rr->port < 0 || /* for same port */
+ rr->port == conn->remote_port)) {
+ size_t i;
+ for(i = 0; i < CURL_ARRAYSIZE(rr->alpns) &&
+ alpn_count < CURL_ARRAYSIZE(alpn_ids); ++i) {
+ enum alpnid alpn = rr->alpns[i];
+ if(cf_https_alpns_contain(alpn, alpn_ids, alpn_count))
+ continue;
+ switch(alpn) {
+ case ALPN_h3:
+ if(Curl_conn_may_http3(data, conn))
+ break; /* not possible */
+ if(data->state.http_neg.allowed & CURL_HTTP_V3x) {
+ CURL_TRC_CF(data, cf, "adding h3 via HTTPS-RR");
+ alpn_ids[alpn_count++] = alpn;
+ }
+ break;
+ case ALPN_h2:
+ if(data->state.http_neg.allowed & CURL_HTTP_V2x) {
+ CURL_TRC_CF(data, cf, "adding h2 via HTTPS-RR");
+ alpn_ids[alpn_count++] = alpn;
+ }
+ break;
+ case ALPN_h1:
+ if(data->state.http_neg.allowed & CURL_HTTP_V1x) {
+ CURL_TRC_CF(data, cf, "adding h1 via HTTPS-RR");
+ alpn_ids[alpn_count++] = alpn;
+ }
+ break;
+ default: /* ignore */
+ break;
+ }
+ }
+ }
+#endif
- 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((alpn_count < CURL_ARRAYSIZE(alpn_ids)) &&
+ (data->state.http_neg.wanted & CURL_HTTP_V3x) &&
+ !cf_https_alpns_contain(ALPN_h3, alpn_ids, alpn_count)) {
+ result = Curl_conn_may_http3(data, conn);
+ if(!result) {
+ CURL_TRC_CF(data, cf, "adding wanted h3");
+ alpn_ids[alpn_count++] = ALPN_h3;
+ }
+ else if(data->state.http_neg.wanted == CURL_HTTP_V3x)
+ goto out; /* only h3 allowed, not possible, error out */
+ }
+ if((alpn_count < CURL_ARRAYSIZE(alpn_ids)) &&
+ (data->state.http_neg.wanted & CURL_HTTP_V2x) &&
+ !cf_https_alpns_contain(ALPN_h2, alpn_ids, alpn_count)) {
+ CURL_TRC_CF(data, cf, "adding wanted h2");
+ alpn_ids[alpn_count++] = ALPN_h2;
+ }
+ else if((alpn_count < CURL_ARRAYSIZE(alpn_ids)) &&
+ (data->state.http_neg.wanted & CURL_HTTP_V1x) &&
+ !cf_https_alpns_contain(ALPN_h1, alpn_ids, alpn_count)) {
+ CURL_TRC_CF(data, cf, "adding wanted h1");
+ alpn_ids[alpn_count++] = ALPN_h1;
+ }
}
- 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, alpn_ids, alpn_count);
}
- result = cf_http_connect_add(data, conn, sockindex, remotehost,
- try_h3, try_h21);
out:
return result;
}
-#endif /* !defined(CURL_DISABLE_HTTP) && !defined(USE_HYPER) */
+#endif /* !defined(CURL_DISABLE_HTTP) */