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
2654 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: \'(\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
@pytest.mark.skipif(condition=not Env.curl_is_debug(), reason="needs curl debug")
154
@pytest.mark.skipif(condition=not Env.curl_is_verbose(), reason="needs curl verbose strings")
155
def test_10_06_proxytunnel_https(self, env: Env, httpd, nghttpx_fwd, proto, tunnel):
156
if tunnel == 'h2' and not env.curl_uses_lib('nghttp2'):
157
pytest.skip('only supported with nghttp2')
158
curl = CurlClient(env=env)
159
url = f'https://localhost:{env.https_port}/data.json?[0-0]'
160
xargs = curl.get_proxy_args(tunnel=True, proto=tunnel)
161
r = curl.http_download(urls=[url], alpn_proto=proto, with_stats=True,
162
extra_args=xargs)
163
r.check_response(count=1, http_status=200,
164
protocol='HTTP/2' if proto == 'h2' else 'HTTP/1.1')
165
assert self.get_tunnel_proto_used(r) == tunnel
166
srcfile = os.path.join(httpd.docs_dir, 'data.json')
167
dfile = curl.download_file(0)
168
assert filecmp.cmp(srcfile, dfile, shallow=False)
169
170
# download many https: with proto via https: proxytunnel
171
@pytest.mark.skipif(condition=not Env.have_ssl_curl(), reason="curl without SSL")
172
@pytest.mark.skipif(condition=not Env.curl_is_debug(), reason="needs curl debug")
173
@pytest.mark.skipif(condition=not Env.curl_is_verbose(), reason="needs curl verbose strings")
174
@pytest.mark.parametrize("proto", ['http/1.1', 'h2'])
175
@pytest.mark.parametrize("tunnel", ['http/1.1', 'h2'])
176
@pytest.mark.parametrize("fname, fcount", [
177
['data.json', 100],
178
['data-100k', 20],
179
['data-1m', 5]
180
])
181
@pytest.mark.skipif(condition=not Env.have_nghttpx(), reason="no nghttpx available")
182
def test_10_07_pts_down_small(self, env: Env, httpd, nghttpx_fwd, proto,
183
tunnel, fname, fcount):
184
if tunnel == 'h2' and not env.curl_uses_lib('nghttp2'):
185
pytest.skip('only supported with nghttp2')
186
if env.curl_uses_lib('mbedtls') and \
187
sys.platform.startswith('darwin') and env.ci_run:
188
pytest.skip('mbedtls 3.6.3 fails this test on macOS CI runners')
189
count = fcount
190
curl = CurlClient(env=env)
191
url = f'https://localhost:{env.https_port}/{fname}?[0-{count-1}]'
192
xargs = curl.get_proxy_args(tunnel=True, proto=tunnel)
193
r = curl.http_download(urls=[url], alpn_proto=proto, with_stats=True,
194
extra_args=xargs)
195
r.check_response(count=count, http_status=200,
196
protocol='HTTP/2' if proto == 'h2' else 'HTTP/1.1')
197
assert self.get_tunnel_proto_used(r) == tunnel
198
srcfile = os.path.join(httpd.docs_dir, fname)
199
for i in range(count):
200
dfile = curl.download_file(i)
201
assert filecmp.cmp(srcfile, dfile, shallow=False)
202
assert r.total_connects == 1, r.dump_logs()
203
204
# upload many https: with proto via https: proxytunnel
205
@pytest.mark.skipif(condition=not Env.have_ssl_curl(), reason="curl without SSL")
206
@pytest.mark.parametrize("proto", ['http/1.1', 'h2'])
207
@pytest.mark.parametrize("tunnel", ['http/1.1', 'h2'])
208
@pytest.mark.parametrize("fname, fcount", [
209
['data.json', 50],
210
['data-100k', 20],
211
['data-1m', 5]
212
])
213
@pytest.mark.skipif(condition=not Env.curl_is_debug(), reason="needs curl debug")
214
@pytest.mark.skipif(condition=not Env.curl_is_verbose(), reason="needs curl verbose strings")
215
@pytest.mark.skipif(condition=not Env.have_nghttpx(), reason="no nghttpx available")
216
def test_10_08_upload_seq_large(self, env: Env, httpd, nghttpx, proto,
217
tunnel, fname, fcount):
218
if tunnel == 'h2' and not env.curl_uses_lib('nghttp2'):
219
pytest.skip('only supported with nghttp2')
220
if env.curl_uses_lib('mbedtls') and \
221
sys.platform.startswith('darwin') and env.ci_run:
222
pytest.skip('mbedtls 3.6.3 fails this test on macOS CI runners')
223
count = fcount
224
srcfile = os.path.join(httpd.docs_dir, fname)
225
curl = CurlClient(env=env)
226
url = f'https://localhost:{env.https_port}/curltest/echo?id=[0-{count-1}]'
227
xargs = curl.get_proxy_args(tunnel=True, proto=tunnel)
228
r = curl.http_upload(urls=[url], data=f'@{srcfile}', alpn_proto=proto,
229
extra_args=xargs)
230
assert self.get_tunnel_proto_used(r) == tunnel
231
r.check_response(count=count, http_status=200)
232
assert r.total_connects == 1, r.dump_logs()
233
indata = open(srcfile).readlines()
234
for i in range(count):
235
respdata = open(curl.response_file(i)).readlines()
236
assert respdata == indata, f'response {i} differs'
237
238
@pytest.mark.skipif(condition=not Env.have_ssl_curl(), reason="curl without SSL")
239
@pytest.mark.parametrize("tunnel", ['http/1.1', 'h2'])
240
@pytest.mark.skipif(condition=not Env.have_nghttpx(), reason="no nghttpx available")
241
@pytest.mark.skipif(condition=not Env.curl_is_debug(), reason="needs curl debug")
242
@pytest.mark.skipif(condition=not Env.curl_is_verbose(), reason="needs curl verbose strings")
243
def test_10_09_reuse_server(self, env: Env, httpd, nghttpx_fwd, tunnel):
244
if tunnel == 'h2' and not env.curl_uses_lib('nghttp2'):
245
pytest.skip('only supported with nghttp2')
246
curl = CurlClient(env=env)
247
url1 = f'https://localhost:{env.https_port}/data.json'
248
url2 = f'http://localhost:{env.http_port}/data.json'
249
xargs = curl.get_proxy_args(tunnel=True, proto=tunnel)
250
r = curl.http_download(urls=[url1, url2], alpn_proto='http/1.1', with_stats=True,
251
extra_args=xargs)
252
r.check_response(count=2, http_status=200)
253
assert self.get_tunnel_proto_used(r) == tunnel
254
if tunnel == 'h2':
255
# TODO: we would like to reuse the first connection for the
256
# second URL, but this is currently not possible
257
# assert r.total_connects == 1
258
assert r.total_connects == 2
259
else:
260
assert r.total_connects == 2
261
262
@pytest.mark.skipif(condition=not Env.have_ssl_curl(), reason="curl without SSL")
263
@pytest.mark.parametrize("tunnel", ['http/1.1', 'h2'])
264
@pytest.mark.skipif(condition=not Env.have_nghttpx(), reason="no nghttpx available")
265
@pytest.mark.skipif(condition=not Env.curl_is_debug(), reason="needs curl debug")
266
@pytest.mark.skipif(condition=not Env.curl_is_verbose(), reason="needs curl verbose strings")
267
def test_10_10_reuse_proxy(self, env: Env, httpd, nghttpx_fwd, tunnel):
268
# url twice via https: proxy separated with '--next', will reuse
269
if tunnel == 'h2' and not env.curl_uses_lib('nghttp2'):
270
pytest.skip('only supported with nghttp2')
271
if env.curl_uses_lib('mbedtls') and \
272
sys.platform.startswith('darwin') and env.ci_run:
273
pytest.skip('mbedtls 3.6.3 fails this test on macOS CI runners')
274
curl = CurlClient(env=env)
275
url = f'https://localhost:{env.https_port}/data.json'
276
proxy_args = curl.get_proxy_args(tunnel=True, proto=tunnel)
277
r1 = curl.http_download(urls=[url], alpn_proto='http/1.1', with_stats=True,
278
extra_args=proxy_args)
279
r1.check_response(count=1, http_status=200)
280
assert self.get_tunnel_proto_used(r1) == tunnel
281
# get the args, duplicate separated with '--next'
282
x2_args = r1.args[1:]
283
x2_args.append('--next')
284
x2_args.extend(proxy_args)
285
r2 = curl.http_download(urls=[url], alpn_proto='http/1.1', with_stats=True,
286
extra_args=x2_args)
287
r2.check_response(count=2, http_status=200)
288
assert r2.total_connects == 1
289
290
@pytest.mark.skipif(condition=not Env.have_ssl_curl(), reason="curl without SSL")
291
@pytest.mark.parametrize("tunnel", ['http/1.1', 'h2'])
292
@pytest.mark.skipif(condition=not Env.have_nghttpx(), reason="no nghttpx available")
293
@pytest.mark.skipif(condition=not Env.curl_uses_lib('openssl'), reason="tls13-ciphers not supported")
294
@pytest.mark.skipif(condition=not Env.curl_is_debug(), reason="needs curl debug")
295
@pytest.mark.skipif(condition=not Env.curl_is_verbose(), reason="needs curl verbose strings")
296
def test_10_11_noreuse_proxy_https(self, env: Env, httpd, nghttpx_fwd, tunnel):
297
# different --proxy-tls13-ciphers, no reuse of connection for https:
298
curl = CurlClient(env=env)
299
if tunnel == 'h2' and not env.curl_uses_lib('nghttp2'):
300
pytest.skip('only supported with nghttp2')
301
url = f'https://localhost:{env.https_port}/data.json'
302
proxy_args = curl.get_proxy_args(tunnel=True, proto=tunnel)
303
r1 = curl.http_download(urls=[url], alpn_proto='http/1.1', with_stats=True,
304
extra_args=proxy_args)
305
r1.check_response(count=1, http_status=200)
306
assert self.get_tunnel_proto_used(r1) == tunnel
307
# get the args, duplicate separated with '--next'
308
x2_args = r1.args[1:]
309
x2_args.append('--next')
310
x2_args.extend(proxy_args)
311
x2_args.extend(['--proxy-tls13-ciphers', 'TLS_AES_256_GCM_SHA384'])
312
r2 = curl.http_download(urls=[url], alpn_proto='http/1.1', with_stats=True,
313
extra_args=x2_args)
314
r2.check_response(count=2, http_status=200)
315
assert r2.total_connects == 2
316
317
@pytest.mark.skipif(condition=not Env.have_ssl_curl(), reason="curl without SSL")
318
@pytest.mark.parametrize("tunnel", ['http/1.1', 'h2'])
319
@pytest.mark.skipif(condition=not Env.have_nghttpx(), reason="no nghttpx available")
320
@pytest.mark.skipif(condition=not Env.curl_uses_lib('openssl'), reason="tls13-ciphers not supported")
321
@pytest.mark.skipif(condition=not Env.curl_is_debug(), reason="needs curl debug")
322
@pytest.mark.skipif(condition=not Env.curl_is_verbose(), reason="needs curl verbose strings")
323
def test_10_12_noreuse_proxy_http(self, env: Env, httpd, nghttpx_fwd, tunnel):
324
# different --proxy-tls13-ciphers, no reuse of connection for http:
325
if tunnel == 'h2' and not env.curl_uses_lib('nghttp2'):
326
pytest.skip('only supported with nghttp2')
327
curl = CurlClient(env=env)
328
url = f'http://localhost:{env.http_port}/data.json'
329
proxy_args = curl.get_proxy_args(tunnel=True, proto=tunnel)
330
r1 = curl.http_download(urls=[url], alpn_proto='http/1.1', with_stats=True,
331
extra_args=proxy_args)
332
r1.check_response(count=1, http_status=200)
333
assert self.get_tunnel_proto_used(r1) == tunnel
334
# get the args, duplicate separated with '--next'
335
x2_args = r1.args[1:]
336
x2_args.append('--next')
337
x2_args.extend(proxy_args)
338
x2_args.extend(['--proxy-tls13-ciphers', 'TLS_AES_256_GCM_SHA384'])
339
r2 = curl.http_download(urls=[url], alpn_proto='http/1.1', with_stats=True,
340
extra_args=x2_args)
341
r2.check_response(count=2, http_status=200)
342
assert r2.total_connects == 2
343
344
@pytest.mark.skipif(condition=not Env.have_ssl_curl(), reason="curl without SSL")
345
@pytest.mark.parametrize("tunnel", ['http/1.1', 'h2'])
346
@pytest.mark.skipif(condition=not Env.have_nghttpx(), reason="no nghttpx available")
347
@pytest.mark.skipif(condition=not Env.curl_uses_lib('openssl'), reason="tls13-ciphers not supported")
348
@pytest.mark.skipif(condition=not Env.curl_is_debug(), reason="needs curl debug")
349
@pytest.mark.skipif(condition=not Env.curl_is_verbose(), reason="needs curl verbose strings")
350
def test_10_13_noreuse_https(self, env: Env, httpd, nghttpx_fwd, tunnel):
351
# different --tls13-ciphers on https: same proxy config
352
if tunnel == 'h2' and not env.curl_uses_lib('nghttp2'):
353
pytest.skip('only supported with nghttp2')
354
curl = CurlClient(env=env)
355
url = f'https://localhost:{env.https_port}/data.json'
356
proxy_args = curl.get_proxy_args(tunnel=True, proto=tunnel)
357
r1 = curl.http_download(urls=[url], alpn_proto='http/1.1', with_stats=True,
358
extra_args=proxy_args)
359
r1.check_response(count=1, http_status=200)
360
assert self.get_tunnel_proto_used(r1) == tunnel
361
# get the args, duplicate separated with '--next'
362
x2_args = r1.args[1:]
363
x2_args.append('--next')
364
x2_args.extend(proxy_args)
365
x2_args.extend(['--tls13-ciphers', 'TLS_AES_256_GCM_SHA384'])
366
r2 = curl.http_download(urls=[url], alpn_proto='http/1.1', with_stats=True,
367
extra_args=x2_args)
368
r2.check_response(count=2, http_status=200)
369
assert r2.total_connects == 2
370
371
# download via https: proxy (no tunnel) using IP address
372
@pytest.mark.skipif(condition=not Env.curl_has_feature('HTTPS-proxy'),
373
reason='curl lacks HTTPS-proxy support')
374
@pytest.mark.parametrize("proto", ['http/1.1', 'h2'])
375
def test_10_14_proxys_ip_addr(self, env: Env, httpd, proto):
376
if proto == 'h2' and not env.curl_uses_lib('nghttp2'):
377
pytest.skip('only supported with nghttp2')
378
curl = CurlClient(env=env)
379
url = f'http://localhost:{env.http_port}/data.json'
380
xargs = curl.get_proxy_args(proto=proto, use_ip=True)
381
r = curl.http_download(urls=[url], alpn_proto='http/1.1', with_stats=True,
382
extra_args=xargs)
383
if env.curl_uses_lib('mbedtls') and \
384
not env.curl_lib_version_at_least('mbedtls', '3.5.0'):
385
r.check_exit_code(60) # CURLE_PEER_FAILED_VERIFICATION
386
else:
387
r.check_response(count=1, http_status=200,
388
protocol='HTTP/2' if proto == 'h2' else 'HTTP/1.1')
389
390