From fed0a3df80bbaaa8eae10b926819e09df0dcffd7 Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Tue, 28 Feb 2023 11:43:50 +0100 Subject: [PATCH] Fix for http2-prior-knowledge when reusing connections. - refs #10634 where errors in the HTTP/2 framing layer are observed. - the bug was that on connection reuse, the code attempted to switch in yet another layer of HTTP/2 handling instead of detecting that this was already in place. - added pytest testcase reproducing the issue. --- lib/http2.c | 3 ++- tests/tests-httpd/test_02_download.py | 24 ++++++++++++++++++++++++ tests/tests-httpd/testenv/httpd.py | 2 ++ 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/lib/http2.c b/lib/http2.c index bdb5e7378e9cbd..f45b0ac5b1d0d1 100644 --- a/lib/http2.c +++ b/lib/http2.c @@ -2479,7 +2479,8 @@ bool Curl_http2_may_switch(struct Curl_easy *data, int sockindex) { (void)sockindex; - if(data->state.httpwant == CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE) { + if(!Curl_conn_is_http2(data, conn, sockindex) && + data->state.httpwant == CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE) { #ifndef CURL_DISABLE_PROXY if(conn->bits.httpproxy && !conn->bits.tunnel_proxy) { /* We don't support HTTP/2 proxies yet. Also it's debatable diff --git a/tests/tests-httpd/test_02_download.py b/tests/tests-httpd/test_02_download.py index 22cb260657cfde..680c9ea063083f 100644 --- a/tests/tests-httpd/test_02_download.py +++ b/tests/tests-httpd/test_02_download.py @@ -221,6 +221,30 @@ def test_02_11_10MB_parallel(self, env: Env, assert r.exit_code == 0 r.check_stats(count=count, exp_status=200) + @pytest.mark.parametrize("proto", ['http/1.1', 'h2', 'h3']) + def test_02_12_head_serial_https(self, env: Env, + httpd, nghttpx, repeat, proto): + count = 100 + urln = f'https://{env.authority_for(env.domain1, proto)}/data-10m?[0-{count-1}]' + curl = CurlClient(env=env) + r = curl.http_download(urls=[urln], alpn_proto=proto, extra_args=[ + '--head' + ]) + assert r.exit_code == 0 + r.check_stats(count=count, exp_status=200) + + @pytest.mark.parametrize("proto", ['h2']) + def test_02_13_head_serial_h2c(self, env: Env, + httpd, nghttpx, repeat, proto): + count = 100 + urln = f'http://{env.domain1}:{env.http_port}/data-10m?[0-{count-1}]' + curl = CurlClient(env=env) + r = curl.http_download(urls=[urln], alpn_proto=proto, extra_args=[ + '--head', '--http2-prior-knowledge', '--fail-early' + ]) + assert r.exit_code == 0 + r.check_stats(count=count, exp_status=200) + def test_02_20_h2_small_frames(self, env: Env, httpd, repeat): # Test case to reproduce content corruption as observed in # https://github.com/curl/curl/issues/10525 diff --git a/tests/tests-httpd/testenv/httpd.py b/tests/tests-httpd/testenv/httpd.py index 4e027dfb54c570..8b8859f9a21e2f 100644 --- a/tests/tests-httpd/testenv/httpd.py +++ b/tests/tests-httpd/testenv/httpd.py @@ -224,6 +224,7 @@ def _write_config(self): f'LogLevel proxy_http:trace4', f'H2MinWorkers 16', f'H2MaxWorkers 128', + f'H2Direct on', f'Listen {self.env.http_port}', f'Listen {self.env.https_port}', f'Listen {self.env.proxy_port}', @@ -235,6 +236,7 @@ def _write_config(self): f' ServerName {domain1}', f' ServerAlias localhost', f' DocumentRoot "{self._docs_dir}"', + f' Protocols h2c http/1.1', ]) conf.extend(self._curltest_conf()) conf.extend([