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