mirror of
https://github.com/curl/curl.git
synced 2026-05-30 06:17:28 +03:00
http: negotiation and room for alt-svc/https rr to navigate
Add a 'wanted' major HTTP version bitmask next to the 'allowed' bitmask in HTTP version negotiation. This will try connections as specified in 'wanted', but enabled Alt-Svc and HTTPS-RR to redirect to other major HTTP versions, if those are 'allowed'. Changes libcurl internal default to `CURL_HTTP_VERSION_NONE` and removes the code in curl that sets `CURL_HTTP_VERSION_2TLS` if the command line does not say anything else. Closes #16117
This commit is contained in:
parent
a1850ad7de
commit
279a4772ae
11 changed files with 143 additions and 96 deletions
|
|
@ -192,7 +192,7 @@ static void cf_hc_reset(struct Curl_cfilter *cf, struct Curl_easy *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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -263,8 +263,8 @@ static bool time_to_start_next(struct Curl_cfilter *cf,
|
|||
break;
|
||||
}
|
||||
if(i == idx) {
|
||||
CURL_TRC_CF(data, cf, "all previous ballers have failed, time to start "
|
||||
"baller %zu [%s]", idx, ctx->ballers[idx].name);
|
||||
CURL_TRC_CF(data, cf, "all previous attempts failed, starting %s",
|
||||
ctx->ballers[idx].name);
|
||||
return TRUE;
|
||||
}
|
||||
elapsed_ms = Curl_timediff(now, ctx->started);
|
||||
|
|
@ -315,7 +315,7 @@ static CURLcode cf_hc_connect(struct Curl_cfilter *cf,
|
|||
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 expire for starting next baller in %ums",
|
||||
CURL_TRC_CF(data, cf, "set next attempt to start in %ums",
|
||||
ctx->soft_eyeballs_timeout_ms);
|
||||
}
|
||||
ctx->state = CF_HC_CONNECT;
|
||||
|
|
@ -351,7 +351,7 @@ static CURLcode cf_hc_connect(struct Curl_cfilter *cf,
|
|||
|
||||
if(failed_ballers == ctx->baller_count) {
|
||||
/* all have failed. we give up */
|
||||
CURL_TRC_CF(data, cf, "connect, all failed");
|
||||
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;
|
||||
|
|
@ -450,7 +450,6 @@ static bool cf_hc_data_pending(struct Curl_cfilter *cf,
|
|||
if(cf->connected)
|
||||
return cf->next->cft->has_data_pending(cf->next, data);
|
||||
|
||||
CURL_TRC_CF((struct Curl_easy *)data, cf, "data_pending");
|
||||
for(i = 0; i < ctx->baller_count; i++)
|
||||
if(cf_hc_baller_data_pending(&ctx->ballers[i], data))
|
||||
return TRUE;
|
||||
|
|
@ -606,8 +605,6 @@ static CURLcode cf_hc_create(struct Curl_cfilter **pcf,
|
|||
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;
|
||||
|
|
@ -637,6 +634,17 @@ 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,
|
||||
|
|
@ -645,41 +653,55 @@ CURLcode Curl_cf_https_setup(struct Curl_easy *data,
|
|||
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;
|
||||
/* 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 a HTTPSRR and if so, do its ALPNs it apply 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. */
|
||||
if(conn->dns_entry && conn->dns_entry->hinfo &&
|
||||
!conn->dns_entry->hinfo->no_def_alpn) {
|
||||
size_t i, j;
|
||||
!conn->dns_entry->hinfo->no_def_alpn && /* ALPNs are defaults */
|
||||
(!conn->dns_entry->hinfo->target || /* for same host */
|
||||
!conn->dns_entry->hinfo->target[0] ||
|
||||
(conn->dns_entry->hinfo->target[0] == '.' &&
|
||||
!conn->dns_entry->hinfo->target[0])) &&
|
||||
(conn->dns_entry->hinfo->port < 0 || /* for same port */
|
||||
conn->dns_entry->hinfo->port == conn->remote_port)) {
|
||||
size_t i;
|
||||
for(i = 0; i < CURL_ARRAYSIZE(conn->dns_entry->hinfo->alpns) &&
|
||||
alpn_count < CURL_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)
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
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;
|
||||
|
|
@ -688,18 +710,28 @@ CURLcode Curl_cf_https_setup(struct Curl_easy *data,
|
|||
}
|
||||
#endif
|
||||
|
||||
if(!alpn_count) {
|
||||
if(data->state.http_neg.allowed & CURL_HTTP_V3x) {
|
||||
result = Curl_conn_may_http3(data, conn);
|
||||
if(!result)
|
||||
alpn_ids[alpn_count++] = ALPN_h3;
|
||||
else if(data->state.http_neg.allowed == 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_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;
|
||||
}
|
||||
if(data->state.http_neg.allowed & CURL_HTTP_V2x)
|
||||
alpn_ids[alpn_count++] = ALPN_h2;
|
||||
else if(data->state.http_neg.allowed & CURL_HTTP_V1x)
|
||||
alpn_ids[alpn_count++] = ALPN_h1;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue