xref: /aosp_15_r20/external/curl/tests/http/test_10_proxy.py (revision 6236dae45794135f37c4eb022389c904c8b0090d)
1*6236dae4SAndroid Build Coastguard Worker#!/usr/bin/env python3
2*6236dae4SAndroid Build Coastguard Worker# -*- coding: utf-8 -*-
3*6236dae4SAndroid Build Coastguard Worker#***************************************************************************
4*6236dae4SAndroid Build Coastguard Worker#                                  _   _ ____  _
5*6236dae4SAndroid Build Coastguard Worker#  Project                     ___| | | |  _ \| |
6*6236dae4SAndroid Build Coastguard Worker#                             / __| | | | |_) | |
7*6236dae4SAndroid Build Coastguard Worker#                            | (__| |_| |  _ <| |___
8*6236dae4SAndroid Build Coastguard Worker#                             \___|\___/|_| \_\_____|
9*6236dae4SAndroid Build Coastguard Worker#
10*6236dae4SAndroid Build Coastguard Worker# Copyright (C) Daniel Stenberg, <[email protected]>, et al.
11*6236dae4SAndroid Build Coastguard Worker#
12*6236dae4SAndroid Build Coastguard Worker# This software is licensed as described in the file COPYING, which
13*6236dae4SAndroid Build Coastguard Worker# you should have received as part of this distribution. The terms
14*6236dae4SAndroid Build Coastguard Worker# are also available at https://curl.se/docs/copyright.html.
15*6236dae4SAndroid Build Coastguard Worker#
16*6236dae4SAndroid Build Coastguard Worker# You may opt to use, copy, modify, merge, publish, distribute and/or sell
17*6236dae4SAndroid Build Coastguard Worker# copies of the Software, and permit persons to whom the Software is
18*6236dae4SAndroid Build Coastguard Worker# furnished to do so, under the terms of the COPYING file.
19*6236dae4SAndroid Build Coastguard Worker#
20*6236dae4SAndroid Build Coastguard Worker# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
21*6236dae4SAndroid Build Coastguard Worker# KIND, either express or implied.
22*6236dae4SAndroid Build Coastguard Worker#
23*6236dae4SAndroid Build Coastguard Worker# SPDX-License-Identifier: curl
24*6236dae4SAndroid Build Coastguard Worker#
25*6236dae4SAndroid Build Coastguard Worker###########################################################################
26*6236dae4SAndroid Build Coastguard Worker#
27*6236dae4SAndroid Build Coastguard Workerimport filecmp
28*6236dae4SAndroid Build Coastguard Workerimport logging
29*6236dae4SAndroid Build Coastguard Workerimport os
30*6236dae4SAndroid Build Coastguard Workerimport re
31*6236dae4SAndroid Build Coastguard Workerimport pytest
32*6236dae4SAndroid Build Coastguard Worker
33*6236dae4SAndroid Build Coastguard Workerfrom testenv import Env, CurlClient, ExecResult
34*6236dae4SAndroid Build Coastguard Worker
35*6236dae4SAndroid Build Coastguard Worker
36*6236dae4SAndroid Build Coastguard Workerlog = logging.getLogger(__name__)
37*6236dae4SAndroid Build Coastguard Worker
38*6236dae4SAndroid Build Coastguard Worker
39*6236dae4SAndroid Build Coastguard Workerclass TestProxy:
40*6236dae4SAndroid Build Coastguard Worker
41*6236dae4SAndroid Build Coastguard Worker    @pytest.fixture(autouse=True, scope='class')
42*6236dae4SAndroid Build Coastguard Worker    def _class_scope(self, env, httpd, nghttpx_fwd):
43*6236dae4SAndroid Build Coastguard Worker        push_dir = os.path.join(httpd.docs_dir, 'push')
44*6236dae4SAndroid Build Coastguard Worker        if not os.path.exists(push_dir):
45*6236dae4SAndroid Build Coastguard Worker            os.makedirs(push_dir)
46*6236dae4SAndroid Build Coastguard Worker        if env.have_nghttpx():
47*6236dae4SAndroid Build Coastguard Worker            nghttpx_fwd.start_if_needed()
48*6236dae4SAndroid Build Coastguard Worker        env.make_data_file(indir=env.gen_dir, fname="data-100k", fsize=100*1024)
49*6236dae4SAndroid Build Coastguard Worker        env.make_data_file(indir=env.gen_dir, fname="data-10m", fsize=10*1024*1024)
50*6236dae4SAndroid Build Coastguard Worker        httpd.clear_extra_configs()
51*6236dae4SAndroid Build Coastguard Worker        httpd.reload()
52*6236dae4SAndroid Build Coastguard Worker
53*6236dae4SAndroid Build Coastguard Worker    def get_tunnel_proto_used(self, r: ExecResult):
54*6236dae4SAndroid Build Coastguard Worker        for line in r.trace_lines:
55*6236dae4SAndroid Build Coastguard Worker            m = re.match(r'.* CONNECT tunnel: (\S+) negotiated$', line)
56*6236dae4SAndroid Build Coastguard Worker            if m:
57*6236dae4SAndroid Build Coastguard Worker                return m.group(1)
58*6236dae4SAndroid Build Coastguard Worker        assert False, f'tunnel protocol not found in:\n{"".join(r.trace_lines)}'
59*6236dae4SAndroid Build Coastguard Worker        return None
60*6236dae4SAndroid Build Coastguard Worker
61*6236dae4SAndroid Build Coastguard Worker    # download via http: proxy (no tunnel)
62*6236dae4SAndroid Build Coastguard Worker    def test_10_01_proxy_http(self, env: Env, httpd, repeat):
63*6236dae4SAndroid Build Coastguard Worker        curl = CurlClient(env=env)
64*6236dae4SAndroid Build Coastguard Worker        url = f'http://localhost:{env.http_port}/data.json'
65*6236dae4SAndroid Build Coastguard Worker        r = curl.http_download(urls=[url], alpn_proto='http/1.1', with_stats=True,
66*6236dae4SAndroid Build Coastguard Worker                               extra_args=curl.get_proxy_args(proxys=False))
67*6236dae4SAndroid Build Coastguard Worker        r.check_response(count=1, http_status=200)
68*6236dae4SAndroid Build Coastguard Worker
69*6236dae4SAndroid Build Coastguard Worker    # download via https: proxy (no tunnel)
70*6236dae4SAndroid Build Coastguard Worker    @pytest.mark.skipif(condition=not Env.curl_has_feature('HTTPS-proxy'),
71*6236dae4SAndroid Build Coastguard Worker                        reason='curl lacks HTTPS-proxy support')
72*6236dae4SAndroid Build Coastguard Worker    @pytest.mark.parametrize("proto", ['http/1.1', 'h2'])
73*6236dae4SAndroid Build Coastguard Worker    def test_10_02_proxys_down(self, env: Env, httpd, proto, repeat):
74*6236dae4SAndroid Build Coastguard Worker        if proto == 'h2' and not env.curl_uses_lib('nghttp2'):
75*6236dae4SAndroid Build Coastguard Worker            pytest.skip('only supported with nghttp2')
76*6236dae4SAndroid Build Coastguard Worker        curl = CurlClient(env=env)
77*6236dae4SAndroid Build Coastguard Worker        url = f'http://localhost:{env.http_port}/data.json'
78*6236dae4SAndroid Build Coastguard Worker        xargs = curl.get_proxy_args(proto=proto)
79*6236dae4SAndroid Build Coastguard Worker        r = curl.http_download(urls=[url], alpn_proto='http/1.1', with_stats=True,
80*6236dae4SAndroid Build Coastguard Worker                               extra_args=xargs)
81*6236dae4SAndroid Build Coastguard Worker        r.check_response(count=1, http_status=200,
82*6236dae4SAndroid Build Coastguard Worker                         protocol='HTTP/2' if proto == 'h2' else 'HTTP/1.1')
83*6236dae4SAndroid Build Coastguard Worker
84*6236dae4SAndroid Build Coastguard Worker    # upload via https: with proto (no tunnel)
85*6236dae4SAndroid Build Coastguard Worker    @pytest.mark.skipif(condition=not Env.have_ssl_curl(), reason="curl without SSL")
86*6236dae4SAndroid Build Coastguard Worker    @pytest.mark.parametrize("proto", ['http/1.1', 'h2'])
87*6236dae4SAndroid Build Coastguard Worker    @pytest.mark.parametrize("fname, fcount", [
88*6236dae4SAndroid Build Coastguard Worker        ['data.json', 5],
89*6236dae4SAndroid Build Coastguard Worker        ['data-100k', 5],
90*6236dae4SAndroid Build Coastguard Worker        ['data-1m', 2]
91*6236dae4SAndroid Build Coastguard Worker    ])
92*6236dae4SAndroid Build Coastguard Worker    @pytest.mark.skipif(condition=not Env.have_nghttpx(),
93*6236dae4SAndroid Build Coastguard Worker                        reason="no nghttpx available")
94*6236dae4SAndroid Build Coastguard Worker    def test_10_02_proxys_up(self, env: Env, httpd, nghttpx, proto,
95*6236dae4SAndroid Build Coastguard Worker                             fname, fcount, repeat):
96*6236dae4SAndroid Build Coastguard Worker        if proto == 'h2' and not env.curl_uses_lib('nghttp2'):
97*6236dae4SAndroid Build Coastguard Worker            pytest.skip('only supported with nghttp2')
98*6236dae4SAndroid Build Coastguard Worker        count = fcount
99*6236dae4SAndroid Build Coastguard Worker        srcfile = os.path.join(httpd.docs_dir, fname)
100*6236dae4SAndroid Build Coastguard Worker        curl = CurlClient(env=env)
101*6236dae4SAndroid Build Coastguard Worker        url = f'http://localhost:{env.http_port}/curltest/echo?id=[0-{count-1}]'
102*6236dae4SAndroid Build Coastguard Worker        xargs = curl.get_proxy_args(proto=proto)
103*6236dae4SAndroid Build Coastguard Worker        r = curl.http_upload(urls=[url], data=f'@{srcfile}', alpn_proto=proto,
104*6236dae4SAndroid Build Coastguard Worker                             extra_args=xargs)
105*6236dae4SAndroid Build Coastguard Worker        r.check_response(count=count, http_status=200,
106*6236dae4SAndroid Build Coastguard Worker                         protocol='HTTP/2' if proto == 'h2' else 'HTTP/1.1')
107*6236dae4SAndroid Build Coastguard Worker        indata = open(srcfile).readlines()
108*6236dae4SAndroid Build Coastguard Worker        for i in range(count):
109*6236dae4SAndroid Build Coastguard Worker            respdata = open(curl.response_file(i)).readlines()
110*6236dae4SAndroid Build Coastguard Worker            assert respdata == indata
111*6236dae4SAndroid Build Coastguard Worker
112*6236dae4SAndroid Build Coastguard Worker    # download http: via http: proxytunnel
113*6236dae4SAndroid Build Coastguard Worker    def test_10_03_proxytunnel_http(self, env: Env, httpd, repeat):
114*6236dae4SAndroid Build Coastguard Worker        curl = CurlClient(env=env)
115*6236dae4SAndroid Build Coastguard Worker        url = f'http://localhost:{env.http_port}/data.json'
116*6236dae4SAndroid Build Coastguard Worker        xargs = curl.get_proxy_args(proxys=False, tunnel=True)
117*6236dae4SAndroid Build Coastguard Worker        r = curl.http_download(urls=[url], alpn_proto='http/1.1', with_stats=True,
118*6236dae4SAndroid Build Coastguard Worker                               extra_args=xargs)
119*6236dae4SAndroid Build Coastguard Worker        r.check_response(count=1, http_status=200)
120*6236dae4SAndroid Build Coastguard Worker
121*6236dae4SAndroid Build Coastguard Worker    # download http: via https: proxytunnel
122*6236dae4SAndroid Build Coastguard Worker    @pytest.mark.skipif(condition=not Env.curl_has_feature('HTTPS-proxy'),
123*6236dae4SAndroid Build Coastguard Worker                        reason='curl lacks HTTPS-proxy support')
124*6236dae4SAndroid Build Coastguard Worker    @pytest.mark.skipif(condition=not Env.have_nghttpx(), reason="no nghttpx available")
125*6236dae4SAndroid Build Coastguard Worker    def test_10_04_proxy_https(self, env: Env, httpd, nghttpx_fwd, repeat):
126*6236dae4SAndroid Build Coastguard Worker        curl = CurlClient(env=env)
127*6236dae4SAndroid Build Coastguard Worker        url = f'http://localhost:{env.http_port}/data.json'
128*6236dae4SAndroid Build Coastguard Worker        xargs = curl.get_proxy_args(tunnel=True)
129*6236dae4SAndroid Build Coastguard Worker        r = curl.http_download(urls=[url], alpn_proto='http/1.1', with_stats=True,
130*6236dae4SAndroid Build Coastguard Worker                               extra_args=xargs)
131*6236dae4SAndroid Build Coastguard Worker        r.check_response(count=1, http_status=200)
132*6236dae4SAndroid Build Coastguard Worker
133*6236dae4SAndroid Build Coastguard Worker    # download https: with proto via http: proxytunnel
134*6236dae4SAndroid Build Coastguard Worker    @pytest.mark.parametrize("proto", ['http/1.1', 'h2'])
135*6236dae4SAndroid Build Coastguard Worker    @pytest.mark.skipif(condition=not Env.have_ssl_curl(), reason="curl without SSL")
136*6236dae4SAndroid Build Coastguard Worker    def test_10_05_proxytunnel_http(self, env: Env, httpd, proto, repeat):
137*6236dae4SAndroid Build Coastguard Worker        curl = CurlClient(env=env)
138*6236dae4SAndroid Build Coastguard Worker        url = f'https://localhost:{env.https_port}/data.json'
139*6236dae4SAndroid Build Coastguard Worker        xargs = curl.get_proxy_args(proxys=False, tunnel=True)
140*6236dae4SAndroid Build Coastguard Worker        r = curl.http_download(urls=[url], alpn_proto=proto, with_stats=True,
141*6236dae4SAndroid Build Coastguard Worker                               extra_args=xargs)
142*6236dae4SAndroid Build Coastguard Worker        r.check_response(count=1, http_status=200,
143*6236dae4SAndroid Build Coastguard Worker                         protocol='HTTP/2' if proto == 'h2' else 'HTTP/1.1')
144*6236dae4SAndroid Build Coastguard Worker
145*6236dae4SAndroid Build Coastguard Worker    # download https: with proto via https: proxytunnel
146*6236dae4SAndroid Build Coastguard Worker    @pytest.mark.skipif(condition=not Env.curl_has_feature('HTTPS-proxy'),
147*6236dae4SAndroid Build Coastguard Worker                        reason='curl lacks HTTPS-proxy support')
148*6236dae4SAndroid Build Coastguard Worker    @pytest.mark.parametrize("proto", ['http/1.1', 'h2'])
149*6236dae4SAndroid Build Coastguard Worker    @pytest.mark.parametrize("tunnel", ['http/1.1', 'h2'])
150*6236dae4SAndroid Build Coastguard Worker    @pytest.mark.skipif(condition=not Env.have_nghttpx(), reason="no nghttpx available")
151*6236dae4SAndroid Build Coastguard Worker    def test_10_06_proxytunnel_https(self, env: Env, httpd, nghttpx_fwd, proto, tunnel, repeat):
152*6236dae4SAndroid Build Coastguard Worker        if tunnel == 'h2' and not env.curl_uses_lib('nghttp2'):
153*6236dae4SAndroid Build Coastguard Worker            pytest.skip('only supported with nghttp2')
154*6236dae4SAndroid Build Coastguard Worker        curl = CurlClient(env=env)
155*6236dae4SAndroid Build Coastguard Worker        url = f'https://localhost:{env.https_port}/data.json?[0-0]'
156*6236dae4SAndroid Build Coastguard Worker        xargs = curl.get_proxy_args(tunnel=True, proto=tunnel)
157*6236dae4SAndroid Build Coastguard Worker        r = curl.http_download(urls=[url], alpn_proto=proto, with_stats=True,
158*6236dae4SAndroid Build Coastguard Worker                               extra_args=xargs)
159*6236dae4SAndroid Build Coastguard Worker        r.check_response(count=1, http_status=200,
160*6236dae4SAndroid Build Coastguard Worker                         protocol='HTTP/2' if proto == 'h2' else 'HTTP/1.1')
161*6236dae4SAndroid Build Coastguard Worker        assert self.get_tunnel_proto_used(r) == 'HTTP/2' \
162*6236dae4SAndroid Build Coastguard Worker            if tunnel == 'h2' else 'HTTP/1.1'
163*6236dae4SAndroid Build Coastguard Worker        srcfile = os.path.join(httpd.docs_dir, 'data.json')
164*6236dae4SAndroid Build Coastguard Worker        dfile = curl.download_file(0)
165*6236dae4SAndroid Build Coastguard Worker        assert filecmp.cmp(srcfile, dfile, shallow=False)
166*6236dae4SAndroid Build Coastguard Worker
167*6236dae4SAndroid Build Coastguard Worker    # download many https: with proto via https: proxytunnel
168*6236dae4SAndroid Build Coastguard Worker    @pytest.mark.skipif(condition=not Env.have_ssl_curl(), reason="curl without SSL")
169*6236dae4SAndroid Build Coastguard Worker    @pytest.mark.parametrize("proto", ['http/1.1', 'h2'])
170*6236dae4SAndroid Build Coastguard Worker    @pytest.mark.parametrize("tunnel", ['http/1.1', 'h2'])
171*6236dae4SAndroid Build Coastguard Worker    @pytest.mark.parametrize("fname, fcount", [
172*6236dae4SAndroid Build Coastguard Worker        ['data.json', 100],
173*6236dae4SAndroid Build Coastguard Worker        ['data-100k', 20],
174*6236dae4SAndroid Build Coastguard Worker        ['data-1m', 5]
175*6236dae4SAndroid Build Coastguard Worker    ])
176*6236dae4SAndroid Build Coastguard Worker    @pytest.mark.skipif(condition=not Env.have_nghttpx(), reason="no nghttpx available")
177*6236dae4SAndroid Build Coastguard Worker    def test_10_07_pts_down_small(self, env: Env, httpd, nghttpx_fwd, proto,
178*6236dae4SAndroid Build Coastguard Worker                                  tunnel, fname, fcount, repeat):
179*6236dae4SAndroid Build Coastguard Worker        if tunnel == 'h2' and not env.curl_uses_lib('nghttp2'):
180*6236dae4SAndroid Build Coastguard Worker            pytest.skip('only supported with nghttp2')
181*6236dae4SAndroid Build Coastguard Worker        count = fcount
182*6236dae4SAndroid Build Coastguard Worker        curl = CurlClient(env=env)
183*6236dae4SAndroid Build Coastguard Worker        url = f'https://localhost:{env.https_port}/{fname}?[0-{count-1}]'
184*6236dae4SAndroid Build Coastguard Worker        xargs = curl.get_proxy_args(tunnel=True, proto=tunnel)
185*6236dae4SAndroid Build Coastguard Worker        r = curl.http_download(urls=[url], alpn_proto=proto, with_stats=True,
186*6236dae4SAndroid Build Coastguard Worker                               extra_args=xargs)
187*6236dae4SAndroid Build Coastguard Worker        r.check_response(count=count, http_status=200,
188*6236dae4SAndroid Build Coastguard Worker                         protocol='HTTP/2' if proto == 'h2' else 'HTTP/1.1')
189*6236dae4SAndroid Build Coastguard Worker        assert self.get_tunnel_proto_used(r) == 'HTTP/2' \
190*6236dae4SAndroid Build Coastguard Worker            if tunnel == 'h2' else 'HTTP/1.1'
191*6236dae4SAndroid Build Coastguard Worker        srcfile = os.path.join(httpd.docs_dir, fname)
192*6236dae4SAndroid Build Coastguard Worker        for i in range(count):
193*6236dae4SAndroid Build Coastguard Worker            dfile = curl.download_file(i)
194*6236dae4SAndroid Build Coastguard Worker            assert filecmp.cmp(srcfile, dfile, shallow=False)
195*6236dae4SAndroid Build Coastguard Worker        assert r.total_connects == 1, r.dump_logs()
196*6236dae4SAndroid Build Coastguard Worker
197*6236dae4SAndroid Build Coastguard Worker    # upload many https: with proto via https: proxytunnel
198*6236dae4SAndroid Build Coastguard Worker    @pytest.mark.skipif(condition=not Env.have_ssl_curl(), reason="curl without SSL")
199*6236dae4SAndroid Build Coastguard Worker    @pytest.mark.parametrize("proto", ['http/1.1', 'h2'])
200*6236dae4SAndroid Build Coastguard Worker    @pytest.mark.parametrize("tunnel", ['http/1.1', 'h2'])
201*6236dae4SAndroid Build Coastguard Worker    @pytest.mark.parametrize("fname, fcount", [
202*6236dae4SAndroid Build Coastguard Worker        ['data.json', 50],
203*6236dae4SAndroid Build Coastguard Worker        ['data-100k', 20],
204*6236dae4SAndroid Build Coastguard Worker        ['data-1m', 5]
205*6236dae4SAndroid Build Coastguard Worker    ])
206*6236dae4SAndroid Build Coastguard Worker    @pytest.mark.skipif(condition=not Env.have_nghttpx(), reason="no nghttpx available")
207*6236dae4SAndroid Build Coastguard Worker    def test_10_08_upload_seq_large(self, env: Env, httpd, nghttpx, proto,
208*6236dae4SAndroid Build Coastguard Worker                                    tunnel, fname, fcount, repeat):
209*6236dae4SAndroid Build Coastguard Worker        if tunnel == 'h2' and not env.curl_uses_lib('nghttp2'):
210*6236dae4SAndroid Build Coastguard Worker            pytest.skip('only supported with nghttp2')
211*6236dae4SAndroid Build Coastguard Worker        count = fcount
212*6236dae4SAndroid Build Coastguard Worker        srcfile = os.path.join(httpd.docs_dir, fname)
213*6236dae4SAndroid Build Coastguard Worker        curl = CurlClient(env=env)
214*6236dae4SAndroid Build Coastguard Worker        url = f'https://localhost:{env.https_port}/curltest/echo?id=[0-{count-1}]'
215*6236dae4SAndroid Build Coastguard Worker        xargs = curl.get_proxy_args(tunnel=True, proto=tunnel)
216*6236dae4SAndroid Build Coastguard Worker        r = curl.http_upload(urls=[url], data=f'@{srcfile}', alpn_proto=proto,
217*6236dae4SAndroid Build Coastguard Worker                             extra_args=xargs)
218*6236dae4SAndroid Build Coastguard Worker        assert self.get_tunnel_proto_used(r) == 'HTTP/2' \
219*6236dae4SAndroid Build Coastguard Worker            if tunnel == 'h2' else 'HTTP/1.1'
220*6236dae4SAndroid Build Coastguard Worker        r.check_response(count=count, http_status=200)
221*6236dae4SAndroid Build Coastguard Worker        indata = open(srcfile).readlines()
222*6236dae4SAndroid Build Coastguard Worker        for i in range(count):
223*6236dae4SAndroid Build Coastguard Worker            respdata = open(curl.response_file(i)).readlines()
224*6236dae4SAndroid Build Coastguard Worker            assert respdata == indata, f'resonse {i} differs'
225*6236dae4SAndroid Build Coastguard Worker        assert r.total_connects == 1, r.dump_logs()
226*6236dae4SAndroid Build Coastguard Worker
227*6236dae4SAndroid Build Coastguard Worker    @pytest.mark.skipif(condition=not Env.have_ssl_curl(), reason="curl without SSL")
228*6236dae4SAndroid Build Coastguard Worker    @pytest.mark.parametrize("tunnel", ['http/1.1', 'h2'])
229*6236dae4SAndroid Build Coastguard Worker    @pytest.mark.skipif(condition=not Env.have_nghttpx(), reason="no nghttpx available")
230*6236dae4SAndroid Build Coastguard Worker    def test_10_09_reuse_ser(self, env: Env, httpd, nghttpx_fwd, tunnel, repeat):
231*6236dae4SAndroid Build Coastguard Worker        if tunnel == 'h2' and not env.curl_uses_lib('nghttp2'):
232*6236dae4SAndroid Build Coastguard Worker            pytest.skip('only supported with nghttp2')
233*6236dae4SAndroid Build Coastguard Worker        curl = CurlClient(env=env)
234*6236dae4SAndroid Build Coastguard Worker        url1 = f'https://localhost:{env.https_port}/data.json'
235*6236dae4SAndroid Build Coastguard Worker        url2 = f'http://localhost:{env.http_port}/data.json'
236*6236dae4SAndroid Build Coastguard Worker        xargs = curl.get_proxy_args(tunnel=True, proto=tunnel)
237*6236dae4SAndroid Build Coastguard Worker        r = curl.http_download(urls=[url1, url2], alpn_proto='http/1.1', with_stats=True,
238*6236dae4SAndroid Build Coastguard Worker                               extra_args=xargs)
239*6236dae4SAndroid Build Coastguard Worker        r.check_response(count=2, http_status=200)
240*6236dae4SAndroid Build Coastguard Worker        assert self.get_tunnel_proto_used(r) == 'HTTP/2' \
241*6236dae4SAndroid Build Coastguard Worker            if tunnel == 'h2' else 'HTTP/1.1'
242*6236dae4SAndroid Build Coastguard Worker        if tunnel == 'h2':
243*6236dae4SAndroid Build Coastguard Worker            # TODO: we would like to reuse the first connection for the
244*6236dae4SAndroid Build Coastguard Worker            # second URL, but this is currently not possible
245*6236dae4SAndroid Build Coastguard Worker            # assert r.total_connects == 1
246*6236dae4SAndroid Build Coastguard Worker            assert r.total_connects == 2
247*6236dae4SAndroid Build Coastguard Worker        else:
248*6236dae4SAndroid Build Coastguard Worker            assert r.total_connects == 2
249*6236dae4SAndroid Build Coastguard Worker
250*6236dae4SAndroid Build Coastguard Worker    @pytest.mark.skipif(condition=not Env.have_ssl_curl(), reason="curl without SSL")
251*6236dae4SAndroid Build Coastguard Worker    @pytest.mark.parametrize("tunnel", ['http/1.1', 'h2'])
252*6236dae4SAndroid Build Coastguard Worker    @pytest.mark.skipif(condition=not Env.have_nghttpx(), reason="no nghttpx available")
253*6236dae4SAndroid Build Coastguard Worker    def test_10_10_reuse_proxy(self, env: Env, httpd, nghttpx_fwd, tunnel, repeat):
254*6236dae4SAndroid Build Coastguard Worker        # url twice via https: proxy separated with '--next', will reuse
255*6236dae4SAndroid Build Coastguard Worker        if tunnel == 'h2' and not env.curl_uses_lib('nghttp2'):
256*6236dae4SAndroid Build Coastguard Worker            pytest.skip('only supported with nghttp2')
257*6236dae4SAndroid Build Coastguard Worker        curl = CurlClient(env=env)
258*6236dae4SAndroid Build Coastguard Worker        url = f'https://localhost:{env.https_port}/data.json'
259*6236dae4SAndroid Build Coastguard Worker        proxy_args = curl.get_proxy_args(tunnel=True, proto=tunnel)
260*6236dae4SAndroid Build Coastguard Worker        r1 = curl.http_download(urls=[url], alpn_proto='http/1.1', with_stats=True,
261*6236dae4SAndroid Build Coastguard Worker                               extra_args=proxy_args)
262*6236dae4SAndroid Build Coastguard Worker        r1.check_response(count=1, http_status=200)
263*6236dae4SAndroid Build Coastguard Worker        assert self.get_tunnel_proto_used(r1) == 'HTTP/2' \
264*6236dae4SAndroid Build Coastguard Worker            if tunnel == 'h2' else 'HTTP/1.1'
265*6236dae4SAndroid Build Coastguard Worker        # get the args, duplicate separated with '--next'
266*6236dae4SAndroid Build Coastguard Worker        x2_args = r1.args[1:]
267*6236dae4SAndroid Build Coastguard Worker        x2_args.append('--next')
268*6236dae4SAndroid Build Coastguard Worker        x2_args.extend(proxy_args)
269*6236dae4SAndroid Build Coastguard Worker        r2 = curl.http_download(urls=[url], alpn_proto='http/1.1', with_stats=True,
270*6236dae4SAndroid Build Coastguard Worker                               extra_args=x2_args)
271*6236dae4SAndroid Build Coastguard Worker        r2.check_response(count=2, http_status=200)
272*6236dae4SAndroid Build Coastguard Worker        assert r2.total_connects == 1
273*6236dae4SAndroid Build Coastguard Worker
274*6236dae4SAndroid Build Coastguard Worker    @pytest.mark.skipif(condition=not Env.have_ssl_curl(), reason="curl without SSL")
275*6236dae4SAndroid Build Coastguard Worker    @pytest.mark.parametrize("tunnel", ['http/1.1', 'h2'])
276*6236dae4SAndroid Build Coastguard Worker    @pytest.mark.skipif(condition=not Env.have_nghttpx(), reason="no nghttpx available")
277*6236dae4SAndroid Build Coastguard Worker    @pytest.mark.skipif(condition=not Env.curl_uses_lib('openssl'), reason="tls13-ciphers not supported")
278*6236dae4SAndroid Build Coastguard Worker    def test_10_11_noreuse_proxy_https(self, env: Env, httpd, nghttpx_fwd, tunnel, repeat):
279*6236dae4SAndroid Build Coastguard Worker        # different --proxy-tls13-ciphers, no reuse of connection for https:
280*6236dae4SAndroid Build Coastguard Worker        curl = CurlClient(env=env)
281*6236dae4SAndroid Build Coastguard Worker        if tunnel == 'h2' and not env.curl_uses_lib('nghttp2'):
282*6236dae4SAndroid Build Coastguard Worker            pytest.skip('only supported with nghttp2')
283*6236dae4SAndroid Build Coastguard Worker        url = f'https://localhost:{env.https_port}/data.json'
284*6236dae4SAndroid Build Coastguard Worker        proxy_args = curl.get_proxy_args(tunnel=True, proto=tunnel)
285*6236dae4SAndroid Build Coastguard Worker        r1 = curl.http_download(urls=[url], alpn_proto='http/1.1', with_stats=True,
286*6236dae4SAndroid Build Coastguard Worker                               extra_args=proxy_args)
287*6236dae4SAndroid Build Coastguard Worker        r1.check_response(count=1, http_status=200)
288*6236dae4SAndroid Build Coastguard Worker        assert self.get_tunnel_proto_used(r1) == 'HTTP/2' \
289*6236dae4SAndroid Build Coastguard Worker            if tunnel == 'h2' else 'HTTP/1.1'
290*6236dae4SAndroid Build Coastguard Worker        # get the args, duplicate separated with '--next'
291*6236dae4SAndroid Build Coastguard Worker        x2_args = r1.args[1:]
292*6236dae4SAndroid Build Coastguard Worker        x2_args.append('--next')
293*6236dae4SAndroid Build Coastguard Worker        x2_args.extend(proxy_args)
294*6236dae4SAndroid Build Coastguard Worker        x2_args.extend(['--proxy-tls13-ciphers', 'TLS_AES_256_GCM_SHA384'])
295*6236dae4SAndroid Build Coastguard Worker        r2 = curl.http_download(urls=[url], alpn_proto='http/1.1', with_stats=True,
296*6236dae4SAndroid Build Coastguard Worker                               extra_args=x2_args)
297*6236dae4SAndroid Build Coastguard Worker        r2.check_response(count=2, http_status=200)
298*6236dae4SAndroid Build Coastguard Worker        assert r2.total_connects == 2
299*6236dae4SAndroid Build Coastguard Worker
300*6236dae4SAndroid Build Coastguard Worker    @pytest.mark.skipif(condition=not Env.have_ssl_curl(), reason="curl without SSL")
301*6236dae4SAndroid Build Coastguard Worker    @pytest.mark.parametrize("tunnel", ['http/1.1', 'h2'])
302*6236dae4SAndroid Build Coastguard Worker    @pytest.mark.skipif(condition=not Env.have_nghttpx(), reason="no nghttpx available")
303*6236dae4SAndroid Build Coastguard Worker    @pytest.mark.skipif(condition=not Env.curl_uses_lib('openssl'), reason="tls13-ciphers not supported")
304*6236dae4SAndroid Build Coastguard Worker    def test_10_12_noreuse_proxy_http(self, env: Env, httpd, nghttpx_fwd, tunnel, repeat):
305*6236dae4SAndroid Build Coastguard Worker        # different --proxy-tls13-ciphers, no reuse of connection for http:
306*6236dae4SAndroid Build Coastguard Worker        if tunnel == 'h2' and not env.curl_uses_lib('nghttp2'):
307*6236dae4SAndroid Build Coastguard Worker            pytest.skip('only supported with nghttp2')
308*6236dae4SAndroid Build Coastguard Worker        curl = CurlClient(env=env)
309*6236dae4SAndroid Build Coastguard Worker        url = f'http://localhost:{env.http_port}/data.json'
310*6236dae4SAndroid Build Coastguard Worker        proxy_args = curl.get_proxy_args(tunnel=True, proto=tunnel)
311*6236dae4SAndroid Build Coastguard Worker        r1 = curl.http_download(urls=[url], alpn_proto='http/1.1', with_stats=True,
312*6236dae4SAndroid Build Coastguard Worker                               extra_args=proxy_args)
313*6236dae4SAndroid Build Coastguard Worker        r1.check_response(count=1, http_status=200)
314*6236dae4SAndroid Build Coastguard Worker        assert self.get_tunnel_proto_used(r1) == 'HTTP/2' \
315*6236dae4SAndroid Build Coastguard Worker            if tunnel == 'h2' else 'HTTP/1.1'
316*6236dae4SAndroid Build Coastguard Worker        # get the args, duplicate separated with '--next'
317*6236dae4SAndroid Build Coastguard Worker        x2_args = r1.args[1:]
318*6236dae4SAndroid Build Coastguard Worker        x2_args.append('--next')
319*6236dae4SAndroid Build Coastguard Worker        x2_args.extend(proxy_args)
320*6236dae4SAndroid Build Coastguard Worker        x2_args.extend(['--proxy-tls13-ciphers', 'TLS_AES_256_GCM_SHA384'])
321*6236dae4SAndroid Build Coastguard Worker        r2 = curl.http_download(urls=[url], alpn_proto='http/1.1', with_stats=True,
322*6236dae4SAndroid Build Coastguard Worker                               extra_args=x2_args)
323*6236dae4SAndroid Build Coastguard Worker        r2.check_response(count=2, http_status=200)
324*6236dae4SAndroid Build Coastguard Worker        assert r2.total_connects == 2
325*6236dae4SAndroid Build Coastguard Worker
326*6236dae4SAndroid Build Coastguard Worker    @pytest.mark.skipif(condition=not Env.have_ssl_curl(), reason="curl without SSL")
327*6236dae4SAndroid Build Coastguard Worker    @pytest.mark.parametrize("tunnel", ['http/1.1', 'h2'])
328*6236dae4SAndroid Build Coastguard Worker    @pytest.mark.skipif(condition=not Env.have_nghttpx(), reason="no nghttpx available")
329*6236dae4SAndroid Build Coastguard Worker    @pytest.mark.skipif(condition=not Env.curl_uses_lib('openssl'), reason="tls13-ciphers not supported")
330*6236dae4SAndroid Build Coastguard Worker    def test_10_13_noreuse_https(self, env: Env, httpd, nghttpx_fwd, tunnel, repeat):
331*6236dae4SAndroid Build Coastguard Worker        # different --tls13-ciphers on https: same proxy config
332*6236dae4SAndroid Build Coastguard Worker        if tunnel == 'h2' and not env.curl_uses_lib('nghttp2'):
333*6236dae4SAndroid Build Coastguard Worker            pytest.skip('only supported with nghttp2')
334*6236dae4SAndroid Build Coastguard Worker        curl = CurlClient(env=env)
335*6236dae4SAndroid Build Coastguard Worker        url = f'https://localhost:{env.https_port}/data.json'
336*6236dae4SAndroid Build Coastguard Worker        proxy_args = curl.get_proxy_args(tunnel=True, proto=tunnel)
337*6236dae4SAndroid Build Coastguard Worker        r1 = curl.http_download(urls=[url], alpn_proto='http/1.1', with_stats=True,
338*6236dae4SAndroid Build Coastguard Worker                               extra_args=proxy_args)
339*6236dae4SAndroid Build Coastguard Worker        r1.check_response(count=1, http_status=200)
340*6236dae4SAndroid Build Coastguard Worker        assert self.get_tunnel_proto_used(r1) == 'HTTP/2' \
341*6236dae4SAndroid Build Coastguard Worker            if tunnel == 'h2' else 'HTTP/1.1'
342*6236dae4SAndroid Build Coastguard Worker        # get the args, duplicate separated with '--next'
343*6236dae4SAndroid Build Coastguard Worker        x2_args = r1.args[1:]
344*6236dae4SAndroid Build Coastguard Worker        x2_args.append('--next')
345*6236dae4SAndroid Build Coastguard Worker        x2_args.extend(proxy_args)
346*6236dae4SAndroid Build Coastguard Worker        x2_args.extend(['--tls13-ciphers', 'TLS_AES_256_GCM_SHA384'])
347*6236dae4SAndroid Build Coastguard Worker        r2 = curl.http_download(urls=[url], alpn_proto='http/1.1', with_stats=True,
348*6236dae4SAndroid Build Coastguard Worker                               extra_args=x2_args)
349*6236dae4SAndroid Build Coastguard Worker        r2.check_response(count=2, http_status=200)
350*6236dae4SAndroid Build Coastguard Worker        assert r2.total_connects == 2
351*6236dae4SAndroid Build Coastguard Worker
352*6236dae4SAndroid Build Coastguard Worker    # download via https: proxy (no tunnel) using IP address
353*6236dae4SAndroid Build Coastguard Worker    @pytest.mark.skipif(condition=not Env.curl_has_feature('HTTPS-proxy'),
354*6236dae4SAndroid Build Coastguard Worker                        reason='curl lacks HTTPS-proxy support')
355*6236dae4SAndroid Build Coastguard Worker    @pytest.mark.skipif(condition=Env.curl_uses_lib('bearssl'), reason="ip address cert verification not supported")
356*6236dae4SAndroid Build Coastguard Worker    @pytest.mark.parametrize("proto", ['http/1.1', 'h2'])
357*6236dae4SAndroid Build Coastguard Worker    def test_10_14_proxys_ip_addr(self, env: Env, httpd, proto, repeat):
358*6236dae4SAndroid Build Coastguard Worker        if proto == 'h2' and not env.curl_uses_lib('nghttp2'):
359*6236dae4SAndroid Build Coastguard Worker            pytest.skip('only supported with nghttp2')
360*6236dae4SAndroid Build Coastguard Worker        curl = CurlClient(env=env)
361*6236dae4SAndroid Build Coastguard Worker        url = f'http://localhost:{env.http_port}/data.json'
362*6236dae4SAndroid Build Coastguard Worker        xargs = curl.get_proxy_args(proto=proto, use_ip=True)
363*6236dae4SAndroid Build Coastguard Worker        r = curl.http_download(urls=[url], alpn_proto='http/1.1', with_stats=True,
364*6236dae4SAndroid Build Coastguard Worker                               extra_args=xargs)
365*6236dae4SAndroid Build Coastguard Worker        if env.curl_uses_lib('mbedtls') and \
366*6236dae4SAndroid Build Coastguard Worker                not env.curl_lib_version_at_least('mbedtls', '3.5.0'):
367*6236dae4SAndroid Build Coastguard Worker            r.check_exit_code(60) # CURLE_PEER_FAILED_VERIFICATION
368*6236dae4SAndroid Build Coastguard Worker        else:
369*6236dae4SAndroid Build Coastguard Worker            r.check_response(count=1, http_status=200,
370*6236dae4SAndroid Build Coastguard Worker                             protocol='HTTP/2' if proto == 'h2' else 'HTTP/1.1')
371