From: Stefan Eissing Date: Thu, 17 Jul 2025 09:53:31 +0000 (+0200) Subject: alpn: query filter X-Git-Tag: curl-8_16_0~357 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=21e885eb39c72c9a4ad59432e5de8a9859934436;p=thirdparty%2Fcurl.git alpn: query filter Add a connection filter query to obtained the negotiated ALPN protocol to check in setup/protocols how the connection needs to behave. Remove the members `alpn` and `proxy_alpn` from `connectdata`. Closes #17947 --- diff --git a/lib/cf-h2-proxy.c b/lib/cf-h2-proxy.c index 7cfdbf988d..162881b17e 100644 --- a/lib/cf-h2-proxy.c +++ b/lib/cf-h2-proxy.c @@ -1534,6 +1534,12 @@ static CURLcode cf_h2_proxy_query(struct Curl_cfilter *cf, } break; } + case CF_QUERY_ALPN_NEGOTIATED: { + const char **palpn = pres2; + DEBUGASSERT(palpn); + *palpn = NULL; + return CURLE_OK; + } default: break; } diff --git a/lib/cf-https-connect.c b/lib/cf-https-connect.c index bbf1ffaa78..f36d227b11 100644 --- a/lib/cf-https-connect.c +++ b/lib/cf-https-connect.c @@ -226,24 +226,22 @@ static CURLcode baller_connected(struct Curl_cfilter *cf, cf->next = winner->cf; winner->cf = NULL; - switch(cf->conn->alpn) { - case CURL_HTTP_VERSION_3: - break; - case CURL_HTTP_VERSION_2: #ifdef USE_NGHTTP2 + { /* Using nghttp2, we add the filter "below" us, so when the conn * closes, we tear it down for a fresh reconnect */ - result = Curl_http2_switch_at(cf, data); - if(result) { - ctx->state = CF_HC_FAILURE; - ctx->result = result; - return result; + const char *alpn = Curl_conn_cf_get_alpn_negotiated(cf->next, data); + if(alpn && !strcmp("h2", alpn)) { + result = Curl_http2_switch_at(cf, data); + if(result) { + ctx->state = CF_HC_FAILURE; + ctx->result = result; + return result; + } } -#endif - break; - default: - break; } +#endif + ctx->state = CF_HC_SUCCESS; cf->connected = TRUE; return result; diff --git a/lib/cfilters.c b/lib/cfilters.c index 6326f79f78..069d6a24a3 100644 --- a/lib/cfilters.c +++ b/lib/cfilters.c @@ -564,7 +564,7 @@ bool Curl_conn_is_ip_connected(struct Curl_easy *data, int sockindex) return FALSE; } -bool Curl_conn_cf_is_ssl(struct Curl_cfilter *cf) +static bool cf_is_ssl(struct Curl_cfilter *cf) { for(; cf; cf = cf->next) { if(cf->cft->flags & CF_TYPE_SSL) @@ -577,7 +577,7 @@ bool Curl_conn_cf_is_ssl(struct Curl_cfilter *cf) bool Curl_conn_is_ssl(struct connectdata *conn, int sockindex) { - return conn ? Curl_conn_cf_is_ssl(conn->cfilter[sockindex]) : FALSE; + return conn ? cf_is_ssl(conn->cfilter[sockindex]) : FALSE; } bool Curl_conn_get_ssl_info(struct Curl_easy *data, @@ -613,6 +613,13 @@ unsigned char Curl_conn_get_transport(struct Curl_easy *data, return Curl_conn_cf_get_transport(cf, data); } +const char *Curl_conn_get_alpn_negotiated(struct Curl_easy *data, + struct connectdata *conn) +{ + struct Curl_cfilter *cf = conn->cfilter[FIRSTSOCKET]; + return Curl_conn_cf_get_alpn_negotiated(cf, data); +} + unsigned char Curl_conn_http_version(struct Curl_easy *data, struct connectdata *conn) { @@ -810,6 +817,17 @@ unsigned char Curl_conn_cf_get_transport(struct Curl_cfilter *cf, return (unsigned char)(data->conn ? data->conn->transport_wanted : 0); } +const char *Curl_conn_cf_get_alpn_negotiated(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + const char *alpn = NULL; + CURL_TRC_CF(data, cf, "query ALPN"); + if(cf && !cf->cft->query(cf, data, CF_QUERY_ALPN_NEGOTIATED, NULL, + CURL_UNCONST(&alpn))) + return alpn; + return NULL; +} + static const struct Curl_sockaddr_ex * cf_get_remote_addr(struct Curl_cfilter *cf, struct Curl_easy *data) { diff --git a/lib/cfilters.h b/lib/cfilters.h index 39d906d673..d468e5ad85 100644 --- a/lib/cfilters.h +++ b/lib/cfilters.h @@ -158,6 +158,10 @@ typedef CURLcode Curl_cft_cntrl(struct Curl_cfilter *cf, * - CF_QUERY_SSL_CTX_INFO: same as CF_QUERY_SSL_INFO, but give the SSL_CTX * when available, or the same internal pointer * when the TLS stack does not differentiate. + * - CF_QUERY_ALPN_NEGOTIATED: The ALPN selected by the server as + null-terminated string or NULL if none + selected/handshake not done. Implemented by filter + types CF_TYPE_SSL or CF_TYPE_IP_CONNECT. */ /* query res1 res2 */ #define CF_QUERY_MAX_CONCURRENT 1 /* number - */ @@ -176,6 +180,7 @@ typedef CURLcode Curl_cft_cntrl(struct Curl_cfilter *cf, #define CF_QUERY_SSL_INFO 12 /* - struct curl_tlssessioninfo * */ #define CF_QUERY_SSL_CTX_INFO 13 /* - struct curl_tlssessioninfo * */ #define CF_QUERY_TRANSPORT 14 /* TRNSPRT_* - * */ +#define CF_QUERY_ALPN_NEGOTIATED 15 /* - const char * */ /** * Query the cfilter for properties. Filters ignorant of a query will @@ -331,12 +336,6 @@ CURLcode Curl_conn_cf_cntrl(struct Curl_cfilter *cf, bool ignore_result, int event, int arg1, void *arg2); -/** - * Determine if the connection filter chain is using SSL to the remote host - * (or will be once connected). - */ -bool Curl_conn_cf_is_ssl(struct Curl_cfilter *cf); - /** * Get the socket used by the filter chain starting at `cf`. * Returns CURL_SOCKET_BAD if not available. @@ -354,6 +353,9 @@ bool Curl_conn_cf_needs_flush(struct Curl_cfilter *cf, unsigned char Curl_conn_cf_get_transport(struct Curl_cfilter *cf, struct Curl_easy *data); +const char *Curl_conn_cf_get_alpn_negotiated(struct Curl_cfilter *cf, + struct Curl_easy *data); + #define CURL_CF_SSL_DEFAULT -1 #define CURL_CF_SSL_DISABLE 0 #define CURL_CF_SSL_ENABLE 1 @@ -418,6 +420,10 @@ unsigned char Curl_conn_http_version(struct Curl_easy *data, unsigned char Curl_conn_get_transport(struct Curl_easy *data, struct connectdata *conn); +/* Get the negotiated ALPN protocol or NULL if none in play */ +const char *Curl_conn_get_alpn_negotiated(struct Curl_easy *data, + struct connectdata *conn); + /** * Close the filter chain at `sockindex` for connection `data->conn`. * Filters remain in place and may be connected again afterwards. diff --git a/lib/http.c b/lib/http.c index 94b3d2cc71..c3f9d4e9b0 100644 --- a/lib/http.c +++ b/lib/http.c @@ -2673,17 +2673,17 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done) char *altused = NULL; const char *p_accept; /* Accept: string */ unsigned char httpversion; + const char *alpn; /* Always consider the DO phase done after this function call, even if there may be parts of the request that are not yet sent, since we can deal with the rest of the request in the PERFORM phase. */ *done = TRUE; - - switch(conn->alpn) { - case CURL_HTTP_VERSION_3: + alpn = Curl_conn_get_alpn_negotiated(data, conn); + if(alpn && !strcmp("h3", alpn)) { DEBUGASSERT(Curl_conn_http_version(data, conn) == 30); - break; - case CURL_HTTP_VERSION_2: + } + else if(alpn && !strcmp("h2", alpn)) { #ifndef CURL_DISABLE_PROXY if((Curl_conn_http_version(data, conn) != 20) && conn->bits.proxy && !conn->bits.tunnel_proxy @@ -2695,11 +2695,8 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done) else #endif DEBUGASSERT(Curl_conn_http_version(data, conn) == 20); - break; - case CURL_HTTP_VERSION_1_1: - /* continue with HTTP/1.x when explicitly requested */ - break; - default: + } + else { /* Check if user wants to use HTTP/2 with clear TCP */ if(Curl_http2_may_switch(data)) { DEBUGF(infof(data, "HTTP/2 over clean TCP")); @@ -2707,7 +2704,6 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done) if(result) goto fail; } - break; } /* Add collecting of headers written to client. For a new connection, diff --git a/lib/http_proxy.c b/lib/http_proxy.c index 6f435a8674..df51484eb9 100644 --- a/lib/http_proxy.c +++ b/lib/http_proxy.c @@ -325,36 +325,42 @@ connect_sub: if(!ctx->cf_protocol) { struct Curl_cfilter *cf_protocol = NULL; int httpversion = 0; - int alpn = Curl_conn_cf_is_ssl(cf->next) ? - cf->conn->proxy_alpn : CURL_HTTP_VERSION_1_1; - - /* First time call after the subchain connected */ - switch(alpn) { - case CURL_HTTP_VERSION_NONE: - case CURL_HTTP_VERSION_1_0: - case CURL_HTTP_VERSION_1_1: + const char *alpn = Curl_conn_cf_get_alpn_negotiated(cf->next, data); + + if(alpn) + infof(data, "CONNECT: '%s' negotiated", alpn); + else + infof(data, "CONNECT: no ALPN negotiated"); + + if(alpn && !strcmp(alpn, "http/1.0")) { + CURL_TRC_CF(data, cf, "installing subfilter for HTTP/1.0"); + result = Curl_cf_h1_proxy_insert_after(cf, data); + if(result) + goto out; + cf_protocol = cf->next; + httpversion = 10; + } + else if(!alpn || !strcmp(alpn, "http/1.1")) { CURL_TRC_CF(data, cf, "installing subfilter for HTTP/1.1"); - infof(data, "CONNECT tunnel: HTTP/1.%d negotiated", - (alpn == CURL_HTTP_VERSION_1_0) ? 0 : 1); result = Curl_cf_h1_proxy_insert_after(cf, data); if(result) goto out; cf_protocol = cf->next; - httpversion = (alpn == CURL_HTTP_VERSION_1_0) ? 10 : 11; - break; + /* Assume that without an ALPN, we are talking to an ancient one */ + httpversion = 11; + } #ifdef USE_NGHTTP2 - case CURL_HTTP_VERSION_2: + else if(!strcmp(alpn, "h2")) { CURL_TRC_CF(data, cf, "installing subfilter for HTTP/2"); - infof(data, "CONNECT tunnel: HTTP/2 negotiated"); result = Curl_cf_h2_proxy_insert_after(cf, data); if(result) goto out; cf_protocol = cf->next; httpversion = 20; - break; + } #endif - default: - infof(data, "CONNECT tunnel: unsupported ALPN(%d) negotiated", alpn); + else { + failf(data, "CONNECT: negotiated ALPN '%s' not supported", alpn); result = CURLE_COULDNT_CONNECT; goto out; } @@ -391,6 +397,12 @@ CURLcode Curl_cf_http_proxy_query(struct Curl_cfilter *cf, *pres1 = (int)cf->conn->http_proxy.port; *((const char **)pres2) = cf->conn->http_proxy.host.name; return CURLE_OK; + case CF_QUERY_ALPN_NEGOTIATED: { + const char **palpn = pres2; + DEBUGASSERT(palpn); + *palpn = NULL; + return CURLE_OK; + } default: break; } diff --git a/lib/socks.c b/lib/socks.c index 5fc6cebcb5..66c3a601a8 100644 --- a/lib/socks.c +++ b/lib/socks.c @@ -1195,15 +1195,22 @@ static CURLcode socks_cf_query(struct Curl_cfilter *cf, { struct socks_state *sx = cf->ctx; - if(sx) { - switch(query) { - case CF_QUERY_HOST_PORT: + switch(query) { + case CF_QUERY_HOST_PORT: + if(sx) { *pres1 = sx->remote_port; *((const char **)pres2) = sx->hostname; return CURLE_OK; - default: - break; } + break; + case CF_QUERY_ALPN_NEGOTIATED: { + const char **palpn = pres2; + DEBUGASSERT(palpn); + *palpn = NULL; + return CURLE_OK; + } + default: + break; } return cf->next ? cf->next->cft->query(cf->next, data, query, pres1, pres2) : diff --git a/lib/url.c b/lib/url.c index f25a58eb7f..204f380137 100644 --- a/lib/url.c +++ b/lib/url.c @@ -1400,17 +1400,15 @@ void Curl_verboseconnect(struct Curl_easy *data, conn->primary.remote_port); #ifndef CURL_DISABLE_HTTP if(conn->handler->protocol & PROTO_FAMILY_HTTP) { - switch(conn->alpn) { - case CURL_HTTP_VERSION_3: - infof(data, "using HTTP/3"); - break; - case CURL_HTTP_VERSION_2: - infof(data, "using HTTP/2"); - break; - default: + const char *alpn = Curl_conn_get_alpn_negotiated(data, conn); + if(!alpn || !strcmp("http/1.1", alpn) || !strcmp("http/1.0", alpn)) infof(data, "using HTTP/1.x"); - break; - } + else if(!strcmp("h2", alpn)) + infof(data, "using HTTP/2"); + else if(!strcmp("h3", alpn)) + infof(data, "using HTTP/3"); + else + infof(data, "using ALPN protocol '%s'", alpn); } #endif } diff --git a/lib/urldata.h b/lib/urldata.h index 1f3312be0f..fffc38a614 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -780,11 +780,6 @@ struct connectdata { unsigned short localport; unsigned short secondary_port; /* secondary socket remote port to connect to (ftp) */ - unsigned char alpn; /* APLN TLS negotiated protocol, a CURL_HTTP_VERSION* - value */ -#ifndef CURL_DISABLE_PROXY - unsigned char proxy_alpn; /* APLN of proxy tunnel, CURL_HTTP_VERSION* */ -#endif unsigned char transport_wanted; /* one of the TRNSPRT_* defines. Not necessarily the transport the connection ends using due to Alt-Svc and happy eyeballing. Use `Curl_conn_get_transport() for actual value diff --git a/lib/vquic/curl_ngtcp2.c b/lib/vquic/curl_ngtcp2.c index 052f280afc..5ec11c4171 100644 --- a/lib/vquic/curl_ngtcp2.c +++ b/lib/vquic/curl_ngtcp2.c @@ -2544,7 +2544,6 @@ static CURLcode cf_ngtcp2_connect(struct Curl_cfilter *cf, if(result) goto out; if(cf->connected) { - cf->conn->alpn = CURL_HTTP_VERSION_3; *done = TRUE; goto out; } @@ -2566,7 +2565,6 @@ static CURLcode cf_ngtcp2_connect(struct Curl_cfilter *cf, if(!result) { CURL_TRC_CF(data, cf, "peer verified"); cf->connected = TRUE; - cf->conn->alpn = CURL_HTTP_VERSION_3; *done = TRUE; connkeep(cf->conn, "HTTP/3 default"); } @@ -2665,6 +2663,12 @@ static CURLcode cf_ngtcp2_query(struct Curl_cfilter *cf, return CURLE_OK; break; } + case CF_QUERY_ALPN_NEGOTIATED: { + const char **palpn = pres2; + DEBUGASSERT(palpn); + *palpn = cf->connected ? "h3" : NULL; + return CURLE_OK; + } default: break; } diff --git a/lib/vquic/curl_osslq.c b/lib/vquic/curl_osslq.c index 3371fd3848..29a912000c 100644 --- a/lib/vquic/curl_osslq.c +++ b/lib/vquic/curl_osslq.c @@ -1802,7 +1802,6 @@ static CURLcode cf_osslq_connect(struct Curl_cfilter *cf, if(!result) { CURL_TRC_CF(data, cf, "peer verified"); cf->connected = TRUE; - cf->conn->alpn = CURL_HTTP_VERSION_3; *done = TRUE; connkeep(cf->conn, "HTTP/3 default"); } @@ -2357,6 +2356,12 @@ static CURLcode cf_osslq_query(struct Curl_cfilter *cf, return CURLE_OK; break; } + case CF_QUERY_ALPN_NEGOTIATED: { + const char **palpn = pres2; + DEBUGASSERT(palpn); + *palpn = cf->connected ? "h3" : NULL; + return CURLE_OK; + } default: break; } diff --git a/lib/vquic/curl_quiche.c b/lib/vquic/curl_quiche.c index 8a4243469b..aafd474bab 100644 --- a/lib/vquic/curl_quiche.c +++ b/lib/vquic/curl_quiche.c @@ -1416,7 +1416,6 @@ static CURLcode cf_quiche_connect(struct Curl_cfilter *cf, goto out; } cf->connected = TRUE; - cf->conn->alpn = CURL_HTTP_VERSION_3; *done = TRUE; connkeep(cf->conn, "HTTP/3 default"); } @@ -1556,6 +1555,12 @@ static CURLcode cf_quiche_query(struct Curl_cfilter *cf, return CURLE_OK; break; } + case CF_QUERY_ALPN_NEGOTIATED: { + const char **palpn = pres2; + DEBUGASSERT(palpn); + *palpn = cf->connected ? "h3" : NULL; + return CURLE_OK; + } default: break; } diff --git a/lib/vtls/schannel.c b/lib/vtls/schannel.c index fe997ee200..fb8d6eb0b2 100644 --- a/lib/vtls/schannel.c +++ b/lib/vtls/schannel.c @@ -1591,19 +1591,18 @@ schannel_connect_step3(struct Curl_cfilter *cf, struct Curl_easy *data) if(alpn_result.ProtoNegoStatus == SecApplicationProtocolNegotiationStatus_Success) { - unsigned char prev_alpn = cf->conn->alpn; - + if(backend->recv_renegotiating && + connssl->negotiated.alpn && + strncmp(connssl->negotiated.alpn, + (const char *)alpn_result.ProtocolId, + alpn_result.ProtocolIdSize)) { + /* Renegotiation selected a different protocol now, we cannot + * deal with this */ + failf(data, "schannel: server selected an ALPN protocol too late"); + return CURLE_SSL_CONNECT_ERROR; + } Curl_alpn_set_negotiated(cf, data, connssl, alpn_result.ProtocolId, alpn_result.ProtocolIdSize); - if(backend->recv_renegotiating) { - if(prev_alpn != cf->conn->alpn && - prev_alpn != CURL_HTTP_VERSION_NONE) { - /* Renegotiation selected a different protocol now, we cannot - * deal with this */ - failf(data, "schannel: server selected an ALPN protocol too late"); - return CURLE_SSL_CONNECT_ERROR; - } - } } else { if(!backend->recv_renegotiating) diff --git a/lib/vtls/vtls.c b/lib/vtls/vtls.c index 104afd1f84..0ff79ea70b 100644 --- a/lib/vtls/vtls.c +++ b/lib/vtls/vtls.c @@ -1571,15 +1571,24 @@ static CURLcode ssl_cf_query(struct Curl_cfilter *cf, return CURLE_OK; } case CF_QUERY_SSL_INFO: - case CF_QUERY_SSL_CTX_INFO: { - struct curl_tlssessioninfo *info = pres2; - struct cf_call_data save; - CF_DATA_SAVE(save, cf, data); - info->backend = Curl_ssl_backend(); - info->internals = connssl->ssl_impl->get_internals( - cf->ctx, (query == CF_QUERY_SSL_INFO) ? - CURLINFO_TLS_SSL_PTR : CURLINFO_TLS_SESSION); - CF_DATA_RESTORE(cf, save); + case CF_QUERY_SSL_CTX_INFO: + if(!Curl_ssl_cf_is_proxy(cf)) { + struct curl_tlssessioninfo *info = pres2; + struct cf_call_data save; + CF_DATA_SAVE(save, cf, data); + info->backend = Curl_ssl_backend(); + info->internals = connssl->ssl_impl->get_internals( + cf->ctx, (query == CF_QUERY_SSL_INFO) ? + CURLINFO_TLS_SSL_PTR : CURLINFO_TLS_SESSION); + CF_DATA_RESTORE(cf, save); + return CURLE_OK; + } + break; + case CF_QUERY_ALPN_NEGOTIATED: { + const char **palpn = pres2; + DEBUGASSERT(palpn); + *palpn = connssl->negotiated.alpn; + CURL_TRC_CF(data, cf, "query ALPN: returning '%s'", *palpn); return CURLE_OK; } default: @@ -1636,7 +1645,7 @@ struct Curl_cftype Curl_cft_ssl_proxy = { Curl_cf_def_cntrl, cf_ssl_is_alive, Curl_cf_def_conn_keep_alive, - Curl_cf_def_query, + ssl_cf_query, }; #endif /* !CURL_DISABLE_PROXY */ @@ -1708,9 +1717,11 @@ static CURLcode cf_ssl_proxy_create(struct Curl_cfilter **pcf, struct Curl_cfilter *cf = NULL; struct ssl_connect_data *ctx; CURLcode result; - bool use_alpn = conn->bits.tls_enable_alpn; + /* ALPN is default, but if user explicitly disables it, obey */ + bool use_alpn = data->set.ssl_enable_alpn; http_majors allowed = CURL_HTTP_V1x; + (void)conn; #ifdef USE_HTTP2 if(conn->http_proxy.proxytype == CURLPROXY_HTTPS2) { use_alpn = TRUE; @@ -1939,14 +1950,7 @@ CURLcode Curl_alpn_set_negotiated(struct Curl_cfilter *cf, size_t proto_len) { CURLcode result = CURLE_OK; - unsigned char *palpn = -#ifndef CURL_DISABLE_PROXY - (cf->conn->bits.tunnel_proxy && Curl_ssl_cf_is_proxy(cf)) ? - &cf->conn->proxy_alpn : &cf->conn->alpn -#else - &cf->conn->alpn -#endif - ; + (void)cf; if(connssl->negotiated.alpn) { /* When we ask for a specific ALPN protocol, we need the confirmation @@ -1988,38 +1992,12 @@ CURLcode Curl_alpn_set_negotiated(struct Curl_cfilter *cf, } if(proto && proto_len) { - if(proto_len == ALPN_HTTP_1_1_LENGTH && - !memcmp(ALPN_HTTP_1_1, proto, ALPN_HTTP_1_1_LENGTH)) { - *palpn = CURL_HTTP_VERSION_1_1; - } -#ifdef USE_HTTP2 - else if(proto_len == ALPN_H2_LENGTH && - !memcmp(ALPN_H2, proto, ALPN_H2_LENGTH)) { - *palpn = CURL_HTTP_VERSION_2; - } -#endif -#ifdef USE_HTTP3 - else if(proto_len == ALPN_H3_LENGTH && - !memcmp(ALPN_H3, proto, ALPN_H3_LENGTH)) { - *palpn = CURL_HTTP_VERSION_3; - } -#endif - else { - *palpn = CURL_HTTP_VERSION_NONE; - failf(data, "unsupported ALPN protocol: '%.*s'", (int)proto_len, proto); - /* Previous code just ignored it and some vtls backends even ignore the - * return code of this function. */ - /* return CURLE_NOT_BUILT_IN; */ - goto out; - } - if(connssl->state == ssl_connection_deferred) infof(data, VTLS_INFOF_ALPN_DEFERRED, (int)proto_len, proto); else infof(data, VTLS_INFOF_ALPN_ACCEPTED, (int)proto_len, proto); } else { - *palpn = CURL_HTTP_VERSION_NONE; if(connssl->state == ssl_connection_deferred) infof(data, VTLS_INFOF_NO_ALPN_DEFERRED); else diff --git a/tests/http/test_10_proxy.py b/tests/http/test_10_proxy.py index 1138f945d1..ac70ec3eb2 100644 --- a/tests/http/test_10_proxy.py +++ b/tests/http/test_10_proxy.py @@ -54,7 +54,7 @@ class TestProxy: def get_tunnel_proto_used(self, r: ExecResult): for line in r.trace_lines: - m = re.match(r'.* CONNECT tunnel: (\S+) negotiated$', line) + m = re.match(r'.* CONNECT: \'(\S+)\' negotiated$', line) if m: return m.group(1) assert False, f'tunnel protocol not found in:\n{"".join(r.trace_lines)}' @@ -161,8 +161,7 @@ class TestProxy: extra_args=xargs) r.check_response(count=1, http_status=200, protocol='HTTP/2' if proto == 'h2' else 'HTTP/1.1') - assert self.get_tunnel_proto_used(r) == 'HTTP/2' \ - if tunnel == 'h2' else 'HTTP/1.1' + assert self.get_tunnel_proto_used(r) == tunnel srcfile = os.path.join(httpd.docs_dir, 'data.json') dfile = curl.download_file(0) assert filecmp.cmp(srcfile, dfile, shallow=False) @@ -193,8 +192,7 @@ class TestProxy: extra_args=xargs) r.check_response(count=count, http_status=200, protocol='HTTP/2' if proto == 'h2' else 'HTTP/1.1') - assert self.get_tunnel_proto_used(r) == 'HTTP/2' \ - if tunnel == 'h2' else 'HTTP/1.1' + assert self.get_tunnel_proto_used(r) == tunnel srcfile = os.path.join(httpd.docs_dir, fname) for i in range(count): dfile = curl.download_file(i) @@ -226,8 +224,7 @@ class TestProxy: xargs = curl.get_proxy_args(tunnel=True, proto=tunnel) r = curl.http_upload(urls=[url], data=f'@{srcfile}', alpn_proto=proto, extra_args=xargs) - assert self.get_tunnel_proto_used(r) == 'HTTP/2' \ - if tunnel == 'h2' else 'HTTP/1.1' + assert self.get_tunnel_proto_used(r) == tunnel r.check_response(count=count, http_status=200) indata = open(srcfile).readlines() for i in range(count): @@ -249,8 +246,7 @@ class TestProxy: r = curl.http_download(urls=[url1, url2], alpn_proto='http/1.1', with_stats=True, extra_args=xargs) r.check_response(count=2, http_status=200) - assert self.get_tunnel_proto_used(r) == 'HTTP/2' \ - if tunnel == 'h2' else 'HTTP/1.1' + assert self.get_tunnel_proto_used(r) == tunnel if tunnel == 'h2': # TODO: we would like to reuse the first connection for the # second URL, but this is currently not possible @@ -276,8 +272,7 @@ class TestProxy: r1 = curl.http_download(urls=[url], alpn_proto='http/1.1', with_stats=True, extra_args=proxy_args) r1.check_response(count=1, http_status=200) - assert self.get_tunnel_proto_used(r1) == 'HTTP/2' \ - if tunnel == 'h2' else 'HTTP/1.1' + assert self.get_tunnel_proto_used(r1) == tunnel # get the args, duplicate separated with '--next' x2_args = r1.args[1:] x2_args.append('--next') @@ -302,8 +297,7 @@ class TestProxy: r1 = curl.http_download(urls=[url], alpn_proto='http/1.1', with_stats=True, extra_args=proxy_args) r1.check_response(count=1, http_status=200) - assert self.get_tunnel_proto_used(r1) == 'HTTP/2' \ - if tunnel == 'h2' else 'HTTP/1.1' + assert self.get_tunnel_proto_used(r1) == tunnel # get the args, duplicate separated with '--next' x2_args = r1.args[1:] x2_args.append('--next') @@ -329,8 +323,7 @@ class TestProxy: r1 = curl.http_download(urls=[url], alpn_proto='http/1.1', with_stats=True, extra_args=proxy_args) r1.check_response(count=1, http_status=200) - assert self.get_tunnel_proto_used(r1) == 'HTTP/2' \ - if tunnel == 'h2' else 'HTTP/1.1' + assert self.get_tunnel_proto_used(r1) == tunnel # get the args, duplicate separated with '--next' x2_args = r1.args[1:] x2_args.append('--next') @@ -356,8 +349,7 @@ class TestProxy: r1 = curl.http_download(urls=[url], alpn_proto='http/1.1', with_stats=True, extra_args=proxy_args) r1.check_response(count=1, http_status=200) - assert self.get_tunnel_proto_used(r1) == 'HTTP/2' \ - if tunnel == 'h2' else 'HTTP/1.1' + assert self.get_tunnel_proto_used(r1) == tunnel # get the args, duplicate separated with '--next' x2_args = r1.args[1:] x2_args.append('--next') diff --git a/tests/http/test_13_proxy_auth.py b/tests/http/test_13_proxy_auth.py index 57575953cc..fe45ae40ec 100644 --- a/tests/http/test_13_proxy_auth.py +++ b/tests/http/test_13_proxy_auth.py @@ -45,7 +45,7 @@ class TestProxyAuth: def get_tunnel_proto_used(self, r: ExecResult): for line in r.trace_lines: - m = re.match(r'.* CONNECT tunnel: (\S+) negotiated$', line) + m = re.match(r'.* CONNECT: \'(\S+)\' negotiated$', line) if m: return m.group(1) assert False, f'tunnel protocol not found in:\n{"".join(r.trace_lines)}' @@ -133,8 +133,7 @@ class TestProxyAuth: extra_args=xargs) # expect "COULD_NOT_CONNECT" r.check_response(exitcode=56, http_status=None) - assert self.get_tunnel_proto_used(r) == 'HTTP/2' \ - if tunnel == 'h2' else 'HTTP/1.1' + assert self.get_tunnel_proto_used(r) == tunnel @pytest.mark.skipif(condition=not Env.have_nghttpx(), reason="no nghttpx available") @pytest.mark.skipif(condition=not Env.curl_has_feature('HTTPS-proxy'), @@ -154,8 +153,7 @@ class TestProxyAuth: extra_args=xargs) r.check_response(count=1, http_status=200, protocol='HTTP/2' if proto == 'h2' else 'HTTP/1.1') - assert self.get_tunnel_proto_used(r) == 'HTTP/2' \ - if tunnel == 'h2' else 'HTTP/1.1' + assert self.get_tunnel_proto_used(r) == tunnel @pytest.mark.skipif(condition=not Env.curl_has_feature('SPNEGO'), reason='curl lacks SPNEGO support')