url: fix connection reuse for HTTP/2 upgrades

Normally, when a connection's filters have all connected, the
multiplex status is determined. However, HTTP/2 Upgrade:
requests will only do this when the first server response
has been received.

The current connection reuse mechanism does not accomodate
that and when the time between connect and response is large
enough, connection reuse may not happen as desired.

See test case 2405 failures, such as in
https://github.com/curl/curl/actions/runs/10629497461/job/29467166451

Add 'conn->bits.asks_multiplex' as indicator that a connection is
still being evaluated for mulitplexing, so that new transfers
may wait on this to be cleared.

Closes #14739
This commit is contained in:
Stefan Eissing 2024-08-30 13:25:26 +02:00 committed by Daniel Stenberg
parent 76212cbf3e
commit 00ef607326
No known key found for this signature in database
GPG Key ID: 5CC908FDB71E12C2
4 changed files with 8 additions and 1 deletions

View File

@ -3439,6 +3439,7 @@ static CURLcode http_on_response(struct Curl_easy *data,
/* Switching to HTTP/2, where we will get more responses */ /* Switching to HTTP/2, where we will get more responses */
infof(data, "Received 101, Switching to HTTP/2"); infof(data, "Received 101, Switching to HTTP/2");
k->upgr101 = UPGR101_RECEIVED; k->upgr101 = UPGR101_RECEIVED;
data->conn->bits.asks_multiplex = FALSE;
/* We expect more response from HTTP/2 later */ /* We expect more response from HTTP/2 later */
k->header = TRUE; k->header = TRUE;
k->headerline = 0; /* restart the header line counter */ k->headerline = 0; /* restart the header line counter */
@ -3485,6 +3486,7 @@ static CURLcode http_on_response(struct Curl_easy *data,
if(k->upgr101 == UPGR101_H2) { if(k->upgr101 == UPGR101_H2) {
/* A requested upgrade was denied, poke the multi handle to possibly /* A requested upgrade was denied, poke the multi handle to possibly
allow a pending pipewait to continue */ allow a pending pipewait to continue */
data->conn->bits.asks_multiplex = FALSE;
Curl_multi_connchanged(data->multi); Curl_multi_connchanged(data->multi);
} }

View File

@ -1736,6 +1736,7 @@ CURLcode Curl_http2_request_upgrade(struct dynbuf *req,
free(base64); free(base64);
k->upgr101 = UPGR101_H2; k->upgr101 = UPGR101_H2;
data->conn->bits.asks_multiplex = TRUE;
return result; return result;
} }

View File

@ -907,7 +907,10 @@ static bool url_match_conn(struct connectdata *conn, void *userdata)
* connections that do not use this feature */ * connections that do not use this feature */
return FALSE; return FALSE;
if(!Curl_conn_is_connected(conn, FIRSTSOCKET)) { if(!Curl_conn_is_connected(conn, FIRSTSOCKET) ||
conn->bits.asks_multiplex) {
/* Not yet connected, or not yet decided if it multiplexes. The later
* happens for HTTP/2 Upgrade: requests that need a response. */
if(match->may_multiplex) { if(match->may_multiplex) {
match->seen_pending_conn = TRUE; match->seen_pending_conn = TRUE;
/* Do not pick a connection that has not connected yet */ /* Do not pick a connection that has not connected yet */

View File

@ -535,6 +535,7 @@ struct ConnectBits {
#endif #endif
BIT(bound); /* set true if bind() has already been done on this socket/ BIT(bound); /* set true if bind() has already been done on this socket/
connection */ connection */
BIT(asks_multiplex); /* connection asks for multiplexing, but is not yet */
BIT(multiplex); /* connection is multiplexed */ BIT(multiplex); /* connection is multiplexed */
BIT(tcp_fastopen); /* use TCP Fast Open */ BIT(tcp_fastopen); /* use TCP Fast Open */
BIT(tls_enable_alpn); /* TLS ALPN extension? */ BIT(tls_enable_alpn); /* TLS ALPN extension? */