Skip to content

Commit f45e3ff

Browse files
authored
Merge pull request #246 from abebus/microopts
Small micro optimisations in w3lib.http
2 parents 5423e0a + a5d30c0 commit f45e3ff

File tree

2 files changed

+32
-13
lines changed

2 files changed

+32
-13
lines changed

tests/test_http.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,10 @@ def test_headers_raw_dict_none(self):
3535
assert headers_raw_to_dict(None) is None
3636
assert headers_dict_to_raw(None) is None
3737

38+
def test_headers_raw_dict_empty(self):
39+
assert headers_raw_to_dict(b"") == {}
40+
assert headers_dict_to_raw({}) == b""
41+
3842
def test_headers_raw_to_dict(self):
3943
raw = b"Content-type: text/html\n\rAccept: gzip\n\r\
4044
Cache-Control: no-cache\n\rCache-Control: no-store\n\n"

w3lib/http.py

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
from base64 import b64encode
44
from collections.abc import Mapping, MutableMapping, Sequence
5+
from io import BytesIO
56
from typing import Any, Union, overload
67

78
from w3lib.util import to_bytes, to_unicode
@@ -44,21 +45,23 @@ def headers_raw_to_dict(headers_raw: bytes | None) -> HeadersDictOutput | None:
4445

4546
if headers_raw is None:
4647
return None
47-
headers = headers_raw.splitlines()
48-
headers_tuples = [header.split(b":", 1) for header in headers]
48+
49+
if not headers_raw:
50+
return {}
4951

5052
result_dict: HeadersDictOutput = {}
51-
for header_item in headers_tuples:
52-
if len(header_item) != 2:
53+
54+
for header in BytesIO(headers_raw):
55+
key, sep, value = header.partition(b":")
56+
if not sep:
5357
continue
5458

55-
item_key = header_item[0].strip()
56-
item_value = header_item[1].strip()
59+
key, value = key.strip(), value.strip()
5760

58-
if item_key in result_dict:
59-
result_dict[item_key].append(item_value)
61+
if key in result_dict:
62+
result_dict[key].append(value)
6063
else:
61-
result_dict[item_key] = [item_value]
64+
result_dict[key] = [value]
6265

6366
return result_dict
6467

@@ -93,13 +96,25 @@ def headers_dict_to_raw(headers_dict: HeadersDictInput | None) -> bytes | None:
9396

9497
if headers_dict is None:
9598
return None
96-
raw_lines = []
99+
100+
if not headers_dict:
101+
return b""
102+
103+
parts = bytearray()
104+
97105
for key, value in headers_dict.items():
98106
if isinstance(value, bytes):
99-
raw_lines.append(b": ".join([key, value]))
107+
if parts:
108+
parts.extend(b"\r\n")
109+
parts.extend(key + b": " + value)
110+
100111
elif isinstance(value, (list, tuple)):
101-
raw_lines.extend(b": ".join([key, v]) for v in value)
102-
return b"\r\n".join(raw_lines)
112+
for v in value:
113+
if parts:
114+
parts.extend(b"\r\n")
115+
parts.extend(key + b": " + v)
116+
117+
return bytes(parts)
103118

104119

105120
def basic_auth_header(

0 commit comments

Comments
 (0)