Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/pkg
Path: blob/main/external/curl/tests/http/test_12_reuse.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 logging
28
import os
29
from datetime import datetime, timedelta
30
import pytest
31
32
from testenv import Env, CurlClient
33
34
35
log = logging.getLogger(__name__)
36
37
38
@pytest.mark.skipif(condition=not Env.have_ssl_curl(), reason="curl without SSL")
39
class TestReuse:
40
41
# check if HTTP/1.1 handles 'Connection: close' correctly
42
@pytest.mark.parametrize("proto", ['http/1.1'])
43
def test_12_01_h1_conn_close(self, env: Env, httpd, configures_httpd, nghttpx, proto):
44
httpd.reset_config()
45
httpd.set_extra_config('base', [
46
'MaxKeepAliveRequests 1',
47
])
48
httpd.reload_if_config_changed()
49
count = 100
50
curl = CurlClient(env=env)
51
urln = f'https://{env.authority_for(env.domain1, proto)}/data.json?[0-{count-1}]'
52
r = curl.http_download(urls=[urln], alpn_proto=proto)
53
r.check_response(count=count, http_status=200)
54
# Server sends `Connection: close` on every 2nd request, requiring
55
# a new connection
56
delta = 5
57
assert (count/2 - delta) < r.total_connects < (count/2 + delta)
58
59
@pytest.mark.skipif(condition=Env.httpd_is_at_least('2.5.0'),
60
reason="httpd 2.5+ handles KeepAlives different")
61
@pytest.mark.parametrize("proto", ['http/1.1'])
62
def test_12_02_h1_conn_timeout(self, env: Env, httpd, configures_httpd, nghttpx, proto):
63
httpd.reset_config()
64
httpd.set_extra_config('base', [
65
'KeepAliveTimeout 1',
66
])
67
httpd.reload_if_config_changed()
68
count = 5
69
curl = CurlClient(env=env)
70
urln = f'https://{env.authority_for(env.domain1, proto)}/data.json?[0-{count-1}]'
71
r = curl.http_download(urls=[urln], alpn_proto=proto, extra_args=[
72
'--rate', '30/m',
73
])
74
r.check_response(count=count, http_status=200)
75
# Connections time out on server before we send another request,
76
assert r.total_connects == count
77
78
@pytest.mark.skipif(condition=not Env.have_h3(), reason="h3 not supported")
79
def test_12_03_as_follow_h2h3(self, env: Env, httpd, configures_httpd, nghttpx):
80
# write an alt-svc file that advises h3 instead of h2
81
asfile = os.path.join(env.gen_dir, 'alt-svc-12_03.txt')
82
self.create_asfile(asfile, f'h2 {env.domain1} {env.https_port} h3 {env.domain1} {env.h3_port}')
83
curl = CurlClient(env=env)
84
urln = f'https://{env.authority_for(env.domain1, "h2")}/data.json'
85
r = curl.http_download(urls=[urln], with_stats=True, extra_args=[
86
'--alt-svc', f'{asfile}',
87
])
88
r.check_response(count=1, http_status=200)
89
assert r.stats[0]['http_version'] == '3', f'{r.stats}'
90
91
@pytest.mark.skipif(condition=not Env.have_h3(), reason="h3 not supported")
92
def test_12_04_as_follow_h3h2(self, env: Env, httpd, configures_httpd, nghttpx):
93
count = 2
94
# write an alt-svc file the advises h2 instead of h3
95
asfile = os.path.join(env.gen_dir, 'alt-svc-12_04.txt')
96
ts = datetime.now() + timedelta(hours=24)
97
expires = f'{ts.year:04}{ts.month:02}{ts.day:02} {ts.hour:02}:{ts.minute:02}:{ts.second:02}'
98
with open(asfile, 'w') as fd:
99
fd.write(f'h3 {env.domain1} {env.https_port} h2 {env.domain1} {env.https_port} "{expires}" 0 0')
100
log.info(f'altscv: {open(asfile).readlines()}')
101
curl = CurlClient(env=env)
102
urln = f'https://{env.authority_for(env.domain1, "h3")}/data.json?[0-{count-1}]'
103
r = curl.http_download(urls=[urln], with_stats=True, extra_args=[
104
'--alt-svc', f'{asfile}', '--http3'
105
])
106
r.check_response(count=count, http_status=200)
107
# We expect the connection to be reused and use HTTP/2
108
assert r.total_connects == 1
109
for s in r.stats:
110
assert s['http_version'] == '2', f'{s}'
111
112
@pytest.mark.skipif(condition=not Env.have_h3(), reason="h3 not supported")
113
def test_12_05_as_follow_h3h1(self, env: Env, httpd, configures_httpd, nghttpx):
114
# With '--http3` an Alt-Svc redirection from h3 to h1 is allowed
115
count = 2
116
# write an alt-svc file the advises h1 instead of h3
117
asfile = os.path.join(env.gen_dir, 'alt-svc-12_05.txt')
118
ts = datetime.now() + timedelta(hours=24)
119
expires = f'{ts.year:04}{ts.month:02}{ts.day:02} {ts.hour:02}:{ts.minute:02}:{ts.second:02}'
120
with open(asfile, 'w') as fd:
121
fd.write(f'h3 {env.domain1} {env.https_port} http/1.1 {env.domain1} {env.https_port} "{expires}" 0 0')
122
log.info(f'altscv: {open(asfile).readlines()}')
123
curl = CurlClient(env=env)
124
urln = f'https://{env.authority_for(env.domain1, "h3")}/data.json?[0-{count-1}]'
125
r = curl.http_download(urls=[urln], with_stats=True, extra_args=[
126
'--alt-svc', f'{asfile}', '--http3'
127
])
128
r.check_response(count=count, http_status=200)
129
# We expect the connection to be reused and use HTTP/1.1
130
assert r.total_connects == 1
131
for s in r.stats:
132
assert s['http_version'] == '1.1', f'{s}'
133
134
@pytest.mark.skipif(condition=not Env.have_h3(), reason="h3 not supported")
135
def test_12_06_as_ignore_h3h1(self, env: Env, httpd, configures_httpd, nghttpx):
136
# With '--http3-only` an Alt-Svc redirection from h3 to h1 is ignored
137
count = 2
138
# write an alt-svc file the advises h1 instead of h3
139
asfile = os.path.join(env.gen_dir, 'alt-svc-12_05.txt')
140
ts = datetime.now() + timedelta(hours=24)
141
expires = f'{ts.year:04}{ts.month:02}{ts.day:02} {ts.hour:02}:{ts.minute:02}:{ts.second:02}'
142
with open(asfile, 'w') as fd:
143
fd.write(f'h3 {env.domain1} {env.https_port} http/1.1 {env.domain1} {env.https_port} "{expires}" 0 0')
144
log.info(f'altscv: {open(asfile).readlines()}')
145
curl = CurlClient(env=env)
146
urln = f'https://{env.authority_for(env.domain1, "h3")}/data.json?[0-{count-1}]'
147
r = curl.http_download(urls=[urln], with_stats=True, extra_args=[
148
'--alt-svc', f'{asfile}', '--http3-only'
149
])
150
r.check_response(count=count, http_status=200)
151
# We expect the connection to be stay on h3, since we used --http3-only
152
assert r.total_connects == 1
153
for s in r.stats:
154
assert s['http_version'] == '3', f'{s}'
155
156
@pytest.mark.skipif(condition=not Env.have_h3(), reason="h3 not supported")
157
def test_12_07_as_ignore_h2h3(self, env: Env, httpd, configures_httpd, nghttpx):
158
# With '--http2` an Alt-Svc redirection from h2 to h3 is ignored
159
# write an alt-svc file that advises h3 instead of h2
160
asfile = os.path.join(env.gen_dir, 'alt-svc-12_03.txt')
161
self.create_asfile(asfile, f'h2 {env.domain1} {env.https_port} h3 {env.domain1} {env.h3_port}')
162
curl = CurlClient(env=env)
163
urln = f'https://{env.authority_for(env.domain1, "h2")}/data.json'
164
r = curl.http_download(urls=[urln], with_stats=True, extra_args=[
165
'--alt-svc', f'{asfile}', '--http2'
166
])
167
r.check_response(count=1, http_status=200)
168
assert r.stats[0]['http_version'] == '2', f'{r.stats}'
169
170
def create_asfile(self, fpath, line):
171
ts = datetime.now() + timedelta(hours=24)
172
expires = f'{ts.year:04}{ts.month:02}{ts.day:02} {ts.hour:02}:{ts.minute:02}:{ts.second:02}'
173
with open(fpath, 'w') as fd:
174
fd.write(f'{line} "{expires}" 0 0')
175
log.info(f'altscv: {open(fpath).readlines()}')
176
177