url: url_match_destination fix

Match origin/via_peer also for non-SSL schemes.

Closes #21573
This commit is contained in:
Stefan Eissing 2026-05-12 17:58:03 +02:00 committed by Daniel Stenberg
parent 61d59c9e39
commit 91dcf4e610
No known key found for this signature in database
GPG key ID: 5CC908FDB71E12C2
2 changed files with 38 additions and 30 deletions

View file

@ -956,36 +956,36 @@ static bool url_match_auth(struct connectdata *conn,
static bool url_match_destination(struct connectdata *conn,
struct url_conn_match *m)
{
/* Additional match requirements if talking TLS OR
* not talking to an HTTP proxy OR using a tunnel through a proxy */
if((m->needle->scheme->flags & PROTOPT_SSL)
#ifndef CURL_DISABLE_PROXY
|| !m->needle->bits.httpproxy || m->needle->bits.tunnel_proxy
#endif
) {
if(m->needle->scheme != conn->scheme) {
/* `needle` and `conn` do not have the same scheme... */
if(get_protocol_family(conn->scheme) != m->needle->scheme->protocol) {
/* and `conn`s protocol family is not the protocol `needle` wants.
* IMAPS would work for IMAP, but no vice versa. */
return FALSE;
}
/* We are in an IMAPS vs IMAP like case. We expect `conn` to have SSL */
if(!Curl_conn_is_ssl(conn, FIRSTSOCKET)) {
DEBUGF(infof(m->data, "Connection #%" FMT_OFF_T
" has compatible protocol family, but no SSL, no match",
conn->connection_id));
return FALSE;
}
}
/* Different connect-to peers never match */
if(!Curl_peer_same_destination(m->needle->via_peer, conn->via_peer))
return FALSE;
/* `needle` must have the same hostname and port in origin and
* via_peer (if present, NULL peers are equal) */
if(!Curl_peer_same_destination(m->needle->origin, conn->origin) ||
!Curl_peer_same_destination(m->needle->via_peer, conn->via_peer))
return FALSE;
#ifndef CURL_DISABLE_PROXY
if(m->needle->bits.httpproxy && !m->needle->bits.tunnel_proxy) {
/* Talking to a non-tunneling HTTP proxy matches on proxy peers. */
return Curl_peer_equal(m->needle->http_proxy.peer,
conn->http_proxy.peer);
}
return TRUE;
#endif
if(m->needle->origin->scheme != conn->origin->scheme) {
/* `needle` and `conn` not having the same scheme.
* This is allowed for the same family *if* conn is using TLS.
* - IMAP+STARTTLS works for IMAPS.
* - IMAPS works for IMAP. */
if(get_protocol_family(conn->origin->scheme) !=
m->needle->scheme->protocol) {
return FALSE;
}
if(!url_match_ssl_use(conn, m)) {
DEBUGF(infof(m->data, "Connection #%" FMT_OFF_T
" has compatible protocol family, but no SSL, no match",
conn->connection_id));
return FALSE;
}
}
/* Scheme mismatch is acceptable, just compare hostname/port */
return Curl_peer_same_destination(m->needle->origin, conn->origin);
}
static bool url_match_ssl_config(struct connectdata *conn,
@ -1144,8 +1144,6 @@ static bool url_match_conn(struct connectdata *conn, void *userdata)
if(!url_match_multiplex_needs(conn, m))
return FALSE;
if(!url_match_ssl_use(conn, m))
return FALSE;
if(!url_match_proxy_use(conn, m))
return FALSE;
if(!url_match_ssl_config(conn, m))

View file

@ -413,3 +413,13 @@ class TestProxy:
extra_args=xargs)
r.check_exit_code(0), f'{r}'
r.check_response(count=1, http_status=200, protocol='HTTP/1.1')
# download via http: proxy (no tunnel), check connection reuse
def test_10_17_proxy_http(self, env: Env, httpd):
curl = CurlClient(env=env)
url1 = f'http://localhost:{env.http_port}/data.json'
url2 = f'http://127.0.0.1:{env.http_port}/data.json'
r = curl.http_download(urls=[url1, url2], alpn_proto='http/1.1', with_stats=True,
extra_args=curl.get_proxy_args(proxys=False))
r.check_response(count=2, http_status=200)
assert r.total_connects == 1, r.dump_logs()