Skip to content

Commit 4f90259

Browse files
committed
Add support for 10x responses in curlcmd output
1 parent 1fa63e3 commit 4f90259

File tree

3 files changed

+99
-5
lines changed

3 files changed

+99
-5
lines changed

hublot/engines/curlcmd.py

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,10 +50,19 @@ def request(self, creq: CompiledRequest, config: Config) -> Response:
5050
else:
5151
raise HublotException(output)
5252

53-
headers_match = re.search(rb"\r?\n\r?\n", curl.stdout)
53+
curl_output = curl.stdout
54+
55+
# completely ignore 10x headers
56+
curl_output = re.sub(
57+
rb"^HTTP/\d+(?:\.\d+)? 10\d\b(?:.*\r?\n)+\r?\n(?=HTTP/2 )",
58+
b"",
59+
curl_output,
60+
)
61+
62+
headers_match = re.search(rb"\r?\n\r?\n", curl_output)
5463
if not headers_match: # pragma: no cover
5564
raise Exception("Failed to find headers in curl output")
56-
headers_str = curl.stdout[: headers_match.start()].decode("ISO-8859-1")
65+
headers_str = curl_output[: headers_match.start()].decode("ISO-8859-1")
5766

5867
status_code, reason, headers_str = self._parse_status_line(headers_str)
5968
return Response(
@@ -63,7 +72,7 @@ def request(self, creq: CompiledRequest, config: Config) -> Response:
6372
status_code=status_code,
6473
reason=reason,
6574
headers=self._parse_headers(headers_str),
66-
content=curl.stdout[headers_match.end() :],
75+
content=curl_output[headers_match.end() :],
6776
)
6877

6978
def _compose_curl_command(self, creq: CompiledRequest, config: Config) -> Iterable[str]:

hublot/engines/pycurl.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,12 @@
2626

2727

2828
RE_STATUS = re.compile(
29-
r"^\s* HTTP/\d+(?:\.\d+)? \s+ (\d\d\d) \s* (?: (\S.+?) \s* )? $",
29+
r"^\s* HTTP/\d+(?:\.\d+)? \ + (\d\d\d) \ * (?: (\S.+?) \ * )? \r?\n",
3030
flags=re.M | re.X,
3131
)
3232

3333
RE_HEADER = re.compile(
34-
r"^\s* ([^:]+?) \s*:\s* (.+?) \s*$",
34+
r"^\ * ([^:]+?) \ *:\ * (.+?) \ *\r?$",
3535
flags=re.M | re.X,
3636
)
3737

test/test_engine_curlcmd.py

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
#!/usr/bin/env python3
2+
3+
# srandards
4+
from inspect import cleandoc
5+
import subprocess
6+
7+
# 3rd parties
8+
import pytest
9+
10+
# hublot
11+
from hublot import Headers, HttpClient, Request, Response
12+
from hublot.compile import compile_request
13+
14+
15+
@pytest.mark.parametrize(
16+
"curl_output, get_expected_response",
17+
[
18+
pytest.param(
19+
"""
20+
HTTP/2 200
21+
Content-Type: text/plain; charset=UTF-8
22+
Content-Length: 2
23+
24+
OK
25+
""",
26+
lambda creq: Response(
27+
creq,
28+
from_cache=False,
29+
history=[],
30+
status_code=200,
31+
reason=None,
32+
headers=Headers(
33+
{
34+
"Content-Type": "text/plain; charset=UTF-8",
35+
"Content-Length": "2",
36+
}
37+
),
38+
content=b"OK",
39+
),
40+
id="simple 200 response",
41+
),
42+
pytest.param(
43+
"""
44+
HTTP/1.1 101 Switching Protocols
45+
Connection: Upgrade
46+
Upgrade: h2c
47+
48+
HTTP/2 200
49+
Content-Type: text/plain; charset=UTF-8
50+
Content-Length: 2
51+
52+
OK
53+
""",
54+
lambda creq: Response(
55+
creq,
56+
from_cache=False,
57+
history=[],
58+
status_code=200,
59+
reason=None,
60+
headers=Headers(
61+
{
62+
"Content-Type": "text/plain; charset=UTF-8",
63+
"Content-Length": "2",
64+
}
65+
),
66+
content=b"OK",
67+
),
68+
id="101+200 double-response",
69+
),
70+
],
71+
)
72+
def test_engine_curlcmd(mocker, curl_output, get_expected_response):
73+
client = HttpClient(engines=["curlcmd"])
74+
mocker.patch(
75+
"hublot.engines.curlcmd.subprocess.run",
76+
return_value=subprocess.CompletedProcess(
77+
args=[],
78+
returncode=0,
79+
stdout=cleandoc(curl_output).replace("\n", "\r\n").encode("UTF-8"),
80+
),
81+
)
82+
req = Request("http://test.test/", method="GET")
83+
creq = compile_request(req, client.config, client.cookies, num_retries=0)
84+
res = client.fetch(req)
85+
assert res == get_expected_response(creq)

0 commit comments

Comments
 (0)