diff options
Diffstat (limited to 'meta-python/recipes-devtools/python/python3-aiohttp/CVE-2025-53643.patch')
-rw-r--r-- | meta-python/recipes-devtools/python/python3-aiohttp/CVE-2025-53643.patch | 526 |
1 files changed, 526 insertions, 0 deletions
diff --git a/meta-python/recipes-devtools/python/python3-aiohttp/CVE-2025-53643.patch b/meta-python/recipes-devtools/python/python3-aiohttp/CVE-2025-53643.patch new file mode 100644 index 0000000000..fd8f83d563 --- /dev/null +++ b/meta-python/recipes-devtools/python/python3-aiohttp/CVE-2025-53643.patch | |||
@@ -0,0 +1,526 @@ | |||
1 | From 5a3e141bca22757e60b3c584b8ac7eee90708b8b Mon Sep 17 00:00:00 2001 | ||
2 | From: Sam Bull <git@sambull.org> | ||
3 | Date: Wed, 9 Jul 2025 19:55:22 +0100 | ||
4 | Subject: [PATCH] Add trailer parsing logic (#11269) (#11287) | ||
5 | |||
6 | (cherry picked from commit 7dd4b5535e6bf9c2d2f05fde638517bff065ba74) | ||
7 | |||
8 | CVE-2025-53643.patch | ||
9 | |||
10 | Upstream-Status: Backport | ||
11 | [https://github.com/aio-libs/aiohttp/commit/e8d774f635dc6d1cd3174d0e38891da5de0e2b6a] | ||
12 | |||
13 | Signed-off-by: Jiaying Song <jiaying.song.cn@windriver.com> | ||
14 | --- | ||
15 | CHANGES/11269.feature.rst | 1 + | ||
16 | aiohttp/http_parser.py | 70 +++++++++--------- | ||
17 | aiohttp/multipart.py | 2 +- | ||
18 | tests/test_http_parser.py | 148 ++++++++++++++++---------------------- | ||
19 | 4 files changed, 100 insertions(+), 121 deletions(-) | ||
20 | create mode 100644 CHANGES/11269.feature.rst | ||
21 | |||
22 | diff --git a/CHANGES/11269.feature.rst b/CHANGES/11269.feature.rst | ||
23 | new file mode 100644 | ||
24 | index 000000000..92cf173be | ||
25 | --- /dev/null | ||
26 | +++ b/CHANGES/11269.feature.rst | ||
27 | @@ -0,0 +1 @@ | ||
28 | +Added initial trailer parsing logic to Python HTTP parser -- by :user:`Dreamsorcerer`. | ||
29 | diff --git a/aiohttp/http_parser.py b/aiohttp/http_parser.py | ||
30 | index 1b8b5b4d4..7d8db6d6f 100644 | ||
31 | --- a/aiohttp/http_parser.py | ||
32 | +++ b/aiohttp/http_parser.py | ||
33 | @@ -142,8 +142,8 @@ class HeadersParser: | ||
34 | # note: "raw" does not mean inclusion of OWS before/after the field value | ||
35 | raw_headers = [] | ||
36 | |||
37 | - lines_idx = 1 | ||
38 | - line = lines[1] | ||
39 | + lines_idx = 0 | ||
40 | + line = lines[lines_idx] | ||
41 | line_count = len(lines) | ||
42 | |||
43 | while line: | ||
44 | @@ -400,6 +400,7 @@ class HttpParser(abc.ABC, Generic[_MsgT]): | ||
45 | response_with_body=self.response_with_body, | ||
46 | auto_decompress=self._auto_decompress, | ||
47 | lax=self.lax, | ||
48 | + headers_parser=self._headers_parser, | ||
49 | ) | ||
50 | if not payload_parser.done: | ||
51 | self._payload_parser = payload_parser | ||
52 | @@ -418,6 +419,7 @@ class HttpParser(abc.ABC, Generic[_MsgT]): | ||
53 | compression=msg.compression, | ||
54 | auto_decompress=self._auto_decompress, | ||
55 | lax=self.lax, | ||
56 | + headers_parser=self._headers_parser, | ||
57 | ) | ||
58 | elif not empty_body and length is None and self.read_until_eof: | ||
59 | payload = StreamReader( | ||
60 | @@ -436,6 +438,7 @@ class HttpParser(abc.ABC, Generic[_MsgT]): | ||
61 | response_with_body=self.response_with_body, | ||
62 | auto_decompress=self._auto_decompress, | ||
63 | lax=self.lax, | ||
64 | + headers_parser=self._headers_parser, | ||
65 | ) | ||
66 | if not payload_parser.done: | ||
67 | self._payload_parser = payload_parser | ||
68 | @@ -473,6 +476,10 @@ class HttpParser(abc.ABC, Generic[_MsgT]): | ||
69 | |||
70 | eof = True | ||
71 | data = b"" | ||
72 | + if isinstance( | ||
73 | + underlying_exc, (InvalidHeader, TransferEncodingError) | ||
74 | + ): | ||
75 | + raise | ||
76 | |||
77 | if eof: | ||
78 | start_pos = 0 | ||
79 | @@ -635,7 +642,7 @@ class HttpRequestParser(HttpParser[RawRequestMessage]): | ||
80 | compression, | ||
81 | upgrade, | ||
82 | chunked, | ||
83 | - ) = self.parse_headers(lines) | ||
84 | + ) = self.parse_headers(lines[1:]) | ||
85 | |||
86 | if close is None: # then the headers weren't set in the request | ||
87 | if version_o <= HttpVersion10: # HTTP 1.0 must asks to not close | ||
88 | @@ -721,7 +728,7 @@ class HttpResponseParser(HttpParser[RawResponseMessage]): | ||
89 | compression, | ||
90 | upgrade, | ||
91 | chunked, | ||
92 | - ) = self.parse_headers(lines) | ||
93 | + ) = self.parse_headers(lines[1:]) | ||
94 | |||
95 | if close is None: | ||
96 | if version_o <= HttpVersion10: | ||
97 | @@ -764,6 +771,8 @@ class HttpPayloadParser: | ||
98 | response_with_body: bool = True, | ||
99 | auto_decompress: bool = True, | ||
100 | lax: bool = False, | ||
101 | + *, | ||
102 | + headers_parser: HeadersParser, | ||
103 | ) -> None: | ||
104 | self._length = 0 | ||
105 | self._type = ParseState.PARSE_UNTIL_EOF | ||
106 | @@ -772,6 +781,8 @@ class HttpPayloadParser: | ||
107 | self._chunk_tail = b"" | ||
108 | self._auto_decompress = auto_decompress | ||
109 | self._lax = lax | ||
110 | + self._headers_parser = headers_parser | ||
111 | + self._trailer_lines: list[bytes] = [] | ||
112 | self.done = False | ||
113 | |||
114 | # payload decompression wrapper | ||
115 | @@ -848,7 +859,7 @@ class HttpPayloadParser: | ||
116 | size_b = chunk[:i] # strip chunk-extensions | ||
117 | # Verify no LF in the chunk-extension | ||
118 | if b"\n" in (ext := chunk[i:pos]): | ||
119 | - exc = BadHttpMessage( | ||
120 | + exc = TransferEncodingError( | ||
121 | f"Unexpected LF in chunk-extension: {ext!r}" | ||
122 | ) | ||
123 | set_exception(self.payload, exc) | ||
124 | @@ -869,7 +880,7 @@ class HttpPayloadParser: | ||
125 | |||
126 | chunk = chunk[pos + len(SEP) :] | ||
127 | if size == 0: # eof marker | ||
128 | - self._chunk = ChunkState.PARSE_MAYBE_TRAILERS | ||
129 | + self._chunk = ChunkState.PARSE_TRAILERS | ||
130 | if self._lax and chunk.startswith(b"\r"): | ||
131 | chunk = chunk[1:] | ||
132 | else: | ||
133 | @@ -907,38 +918,31 @@ class HttpPayloadParser: | ||
134 | self._chunk_tail = chunk | ||
135 | return False, b"" | ||
136 | |||
137 | - # if stream does not contain trailer, after 0\r\n | ||
138 | - # we should get another \r\n otherwise | ||
139 | - # trailers needs to be skipped until \r\n\r\n | ||
140 | - if self._chunk == ChunkState.PARSE_MAYBE_TRAILERS: | ||
141 | - head = chunk[: len(SEP)] | ||
142 | - if head == SEP: | ||
143 | - # end of stream | ||
144 | - self.payload.feed_eof() | ||
145 | - return True, chunk[len(SEP) :] | ||
146 | - # Both CR and LF, or only LF may not be received yet. It is | ||
147 | - # expected that CRLF or LF will be shown at the very first | ||
148 | - # byte next time, otherwise trailers should come. The last | ||
149 | - # CRLF which marks the end of response might not be | ||
150 | - # contained in the same TCP segment which delivered the | ||
151 | - # size indicator. | ||
152 | - if not head: | ||
153 | - return False, b"" | ||
154 | - if head == SEP[:1]: | ||
155 | - self._chunk_tail = head | ||
156 | - return False, b"" | ||
157 | - self._chunk = ChunkState.PARSE_TRAILERS | ||
158 | - | ||
159 | - # read and discard trailer up to the CRLF terminator | ||
160 | if self._chunk == ChunkState.PARSE_TRAILERS: | ||
161 | pos = chunk.find(SEP) | ||
162 | - if pos >= 0: | ||
163 | - chunk = chunk[pos + len(SEP) :] | ||
164 | - self._chunk = ChunkState.PARSE_MAYBE_TRAILERS | ||
165 | - else: | ||
166 | + if pos < 0: # No line found | ||
167 | self._chunk_tail = chunk | ||
168 | return False, b"" | ||
169 | |||
170 | + line = chunk[:pos] | ||
171 | + chunk = chunk[pos + len(SEP) :] | ||
172 | + if SEP == b"\n": # For lax response parsing | ||
173 | + line = line.rstrip(b"\r") | ||
174 | + self._trailer_lines.append(line) | ||
175 | + | ||
176 | + # \r\n\r\n found, end of stream | ||
177 | + if self._trailer_lines[-1] == b"": | ||
178 | + # Headers and trailers are defined the same way, | ||
179 | + # so we reuse the HeadersParser here. | ||
180 | + try: | ||
181 | + trailers, raw_trailers = self._headers_parser.parse_headers( | ||
182 | + self._trailer_lines | ||
183 | + ) | ||
184 | + finally: | ||
185 | + self._trailer_lines.clear() | ||
186 | + self.payload.feed_eof() | ||
187 | + return True, chunk | ||
188 | + | ||
189 | # Read all bytes until eof | ||
190 | elif self._type == ParseState.PARSE_UNTIL_EOF: | ||
191 | self.payload.feed_data(chunk, len(chunk)) | ||
192 | diff --git a/aiohttp/multipart.py b/aiohttp/multipart.py | ||
193 | index bd4d8ae1d..6faff0e9f 100644 | ||
194 | --- a/aiohttp/multipart.py | ||
195 | +++ b/aiohttp/multipart.py | ||
196 | @@ -767,7 +767,7 @@ class MultipartReader: | ||
197 | raise ValueError(f"Invalid boundary {chunk!r}, expected {self._boundary!r}") | ||
198 | |||
199 | async def _read_headers(self) -> "CIMultiDictProxy[str]": | ||
200 | - lines = [b""] | ||
201 | + lines = [] | ||
202 | while True: | ||
203 | chunk = await self._content.readline() | ||
204 | chunk = chunk.strip() | ||
205 | diff --git a/tests/test_http_parser.py b/tests/test_http_parser.py | ||
206 | index 58fef625f..385452c1c 100644 | ||
207 | --- a/tests/test_http_parser.py | ||
208 | +++ b/tests/test_http_parser.py | ||
209 | @@ -17,6 +17,7 @@ from aiohttp.base_protocol import BaseProtocol | ||
210 | from aiohttp.http_parser import ( | ||
211 | NO_EXTENSIONS, | ||
212 | DeflateBuffer, | ||
213 | + HeadersParser, | ||
214 | HttpPayloadParser, | ||
215 | HttpRequestParser, | ||
216 | HttpRequestParserPy, | ||
217 | @@ -244,41 +245,13 @@ def test_content_length_transfer_encoding(parser: Any) -> None: | ||
218 | parser.feed_data(text) | ||
219 | |||
220 | |||
221 | -def test_bad_chunked_py(loop: Any, protocol: Any) -> None: | ||
222 | +def test_bad_chunked(parser: HttpRequestParser) -> None: | ||
223 | """Test that invalid chunked encoding doesn't allow content-length to be used.""" | ||
224 | - parser = HttpRequestParserPy( | ||
225 | - protocol, | ||
226 | - loop, | ||
227 | - 2**16, | ||
228 | - max_line_size=8190, | ||
229 | - max_field_size=8190, | ||
230 | - ) | ||
231 | - text = ( | ||
232 | - b"GET / HTTP/1.1\r\nHost: a\r\nTransfer-Encoding: chunked\r\n\r\n0_2e\r\n\r\n" | ||
233 | - + b"GET / HTTP/1.1\r\nHost: a\r\nContent-Length: 5\r\n\r\n0\r\n\r\n" | ||
234 | - ) | ||
235 | - messages, upgrade, tail = parser.feed_data(text) | ||
236 | - assert isinstance(messages[0][1].exception(), http_exceptions.TransferEncodingError) | ||
237 | - | ||
238 | - | ||
239 | -@pytest.mark.skipif( | ||
240 | - "HttpRequestParserC" not in dir(aiohttp.http_parser), | ||
241 | - reason="C based HTTP parser not available", | ||
242 | -) | ||
243 | -def test_bad_chunked_c(loop: Any, protocol: Any) -> None: | ||
244 | - """C parser behaves differently. Maybe we should align them later.""" | ||
245 | - parser = HttpRequestParserC( | ||
246 | - protocol, | ||
247 | - loop, | ||
248 | - 2**16, | ||
249 | - max_line_size=8190, | ||
250 | - max_field_size=8190, | ||
251 | - ) | ||
252 | text = ( | ||
253 | b"GET / HTTP/1.1\r\nHost: a\r\nTransfer-Encoding: chunked\r\n\r\n0_2e\r\n\r\n" | ||
254 | + b"GET / HTTP/1.1\r\nHost: a\r\nContent-Length: 5\r\n\r\n0\r\n\r\n" | ||
255 | ) | ||
256 | - with pytest.raises(http_exceptions.BadHttpMessage): | ||
257 | + with pytest.raises(http_exceptions.BadHttpMessage, match="0_2e"): | ||
258 | parser.feed_data(text) | ||
259 | |||
260 | |||
261 | @@ -1158,8 +1131,8 @@ async def test_http_response_parser_bad_chunked_strict_py(loop, protocol) -> Non | ||
262 | text = ( | ||
263 | b"HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n5 \r\nabcde\r\n0\r\n\r\n" | ||
264 | ) | ||
265 | - messages, upgrade, tail = response.feed_data(text) | ||
266 | - assert isinstance(messages[0][1].exception(), http_exceptions.TransferEncodingError) | ||
267 | + with pytest.raises(http_exceptions.TransferEncodingError, match="5"): | ||
268 | + response.feed_data(text) | ||
269 | |||
270 | |||
271 | @pytest.mark.dev_mode | ||
272 | @@ -1295,7 +1268,27 @@ def test_parse_chunked_payload_chunk_extension(parser) -> None: | ||
273 | assert payload.is_eof() | ||
274 | |||
275 | |||
276 | -def test_parse_no_length_or_te_on_post(loop: Any, protocol: Any, request_cls: Any): | ||
277 | +async def test_request_chunked_with_trailer(parser: HttpRequestParser) -> None: | ||
278 | + text = b"GET /test HTTP/1.1\r\nTransfer-Encoding: chunked\r\n\r\n4\r\ntest\r\n0\r\ntest: trailer\r\nsecond: test trailer\r\n\r\n" | ||
279 | + messages, upgraded, tail = parser.feed_data(text) | ||
280 | + assert not tail | ||
281 | + msg, payload = messages[0] | ||
282 | + assert await payload.read() == b"test" | ||
283 | + | ||
284 | + # TODO: Add assertion of trailers when API added. | ||
285 | + | ||
286 | + | ||
287 | +async def test_request_chunked_reject_bad_trailer(parser: HttpRequestParser) -> None: | ||
288 | + text = b"GET /test HTTP/1.1\r\nTransfer-Encoding: chunked\r\n\r\n0\r\nbad\ntrailer\r\n\r\n" | ||
289 | + with pytest.raises(http_exceptions.BadHttpMessage, match=r"b'bad\\ntrailer'"): | ||
290 | + parser.feed_data(text) | ||
291 | + | ||
292 | + | ||
293 | +def test_parse_no_length_or_te_on_post( | ||
294 | + loop: asyncio.AbstractEventLoop, | ||
295 | + protocol: BaseProtocol, | ||
296 | + request_cls: type[HttpRequestParser], | ||
297 | +) -> None: | ||
298 | parser = request_cls(protocol, loop, limit=2**16) | ||
299 | text = b"POST /test HTTP/1.1\r\n\r\n" | ||
300 | msg, payload = parser.feed_data(text)[0][0] | ||
301 | @@ -1478,19 +1471,10 @@ async def test_parse_chunked_payload_split_chunks(response: Any) -> None: | ||
302 | assert await reader.read() == b"firstsecond" | ||
303 | |||
304 | |||
305 | -@pytest.mark.skipif(NO_EXTENSIONS, reason="Only tests C parser.") | ||
306 | -async def test_parse_chunked_payload_with_lf_in_extensions_c_parser( | ||
307 | - loop: asyncio.AbstractEventLoop, protocol: BaseProtocol | ||
308 | +async def test_parse_chunked_payload_with_lf_in_extensions( | ||
309 | + parser: HttpRequestParser, | ||
310 | ) -> None: | ||
311 | - """Test the C-parser with a chunked payload that has a LF in the chunk extensions.""" | ||
312 | - # The C parser will raise a BadHttpMessage from feed_data | ||
313 | - parser = HttpRequestParserC( | ||
314 | - protocol, | ||
315 | - loop, | ||
316 | - 2**16, | ||
317 | - max_line_size=8190, | ||
318 | - max_field_size=8190, | ||
319 | - ) | ||
320 | + """Test chunked payload that has a LF in the chunk extensions.""" | ||
321 | payload = ( | ||
322 | b"GET / HTTP/1.1\r\nHost: localhost:5001\r\n" | ||
323 | b"Transfer-Encoding: chunked\r\n\r\n2;\nxx\r\n4c\r\n0\r\n\r\n" | ||
324 | @@ -1501,31 +1485,6 @@ async def test_parse_chunked_payload_with_lf_in_extensions_c_parser( | ||
325 | parser.feed_data(payload) | ||
326 | |||
327 | |||
328 | -async def test_parse_chunked_payload_with_lf_in_extensions_py_parser( | ||
329 | - loop: asyncio.AbstractEventLoop, protocol: BaseProtocol | ||
330 | -) -> None: | ||
331 | - """Test the py-parser with a chunked payload that has a LF in the chunk extensions.""" | ||
332 | - # The py parser will not raise the BadHttpMessage directly, but instead | ||
333 | - # it will set the exception on the StreamReader. | ||
334 | - parser = HttpRequestParserPy( | ||
335 | - protocol, | ||
336 | - loop, | ||
337 | - 2**16, | ||
338 | - max_line_size=8190, | ||
339 | - max_field_size=8190, | ||
340 | - ) | ||
341 | - payload = ( | ||
342 | - b"GET / HTTP/1.1\r\nHost: localhost:5001\r\n" | ||
343 | - b"Transfer-Encoding: chunked\r\n\r\n2;\nxx\r\n4c\r\n0\r\n\r\n" | ||
344 | - b"GET /admin HTTP/1.1\r\nHost: localhost:5001\r\n" | ||
345 | - b"Transfer-Encoding: chunked\r\n\r\n0\r\n\r\n" | ||
346 | - ) | ||
347 | - messages, _, _ = parser.feed_data(payload) | ||
348 | - reader = messages[0][1] | ||
349 | - assert isinstance(reader.exception(), http_exceptions.BadHttpMessage) | ||
350 | - assert "\\nxx" in str(reader.exception()) | ||
351 | - | ||
352 | - | ||
353 | def test_partial_url(parser: HttpRequestParser) -> None: | ||
354 | messages, upgrade, tail = parser.feed_data(b"GET /te") | ||
355 | assert len(messages) == 0 | ||
356 | @@ -1612,7 +1571,7 @@ def test_parse_bad_method_for_c_parser_raises(loop, protocol): | ||
357 | class TestParsePayload: | ||
358 | async def test_parse_eof_payload(self, protocol: BaseProtocol) -> None: | ||
359 | out = aiohttp.StreamReader(protocol, 2**16, loop=asyncio.get_running_loop()) | ||
360 | - p = HttpPayloadParser(out) | ||
361 | + p = HttpPayloadParser(out, headers_parser=HeadersParser()) | ||
362 | p.feed_data(b"data") | ||
363 | p.feed_eof() | ||
364 | |||
365 | @@ -1622,7 +1581,7 @@ class TestParsePayload: | ||
366 | async def test_parse_length_payload_eof(self, protocol: BaseProtocol) -> None: | ||
367 | out = aiohttp.StreamReader(protocol, 2**16, loop=asyncio.get_running_loop()) | ||
368 | |||
369 | - p = HttpPayloadParser(out, length=4) | ||
370 | + p = HttpPayloadParser(out, length=4, headers_parser=HeadersParser()) | ||
371 | p.feed_data(b"da") | ||
372 | |||
373 | with pytest.raises(http_exceptions.ContentLengthError): | ||
374 | @@ -1632,7 +1591,7 @@ class TestParsePayload: | ||
375 | self, protocol: BaseProtocol | ||
376 | ) -> None: | ||
377 | out = aiohttp.StreamReader(protocol, 2**16, loop=asyncio.get_running_loop()) | ||
378 | - p = HttpPayloadParser(out, chunked=True) | ||
379 | + p = HttpPayloadParser(out, chunked=True, headers_parser=HeadersParser()) | ||
380 | with pytest.raises(http_exceptions.TransferEncodingError): | ||
381 | p.feed_data(b"blah\r\n") | ||
382 | assert isinstance(out.exception(), http_exceptions.TransferEncodingError) | ||
383 | @@ -1641,7 +1600,7 @@ class TestParsePayload: | ||
384 | self, protocol: BaseProtocol | ||
385 | ) -> None: | ||
386 | out = aiohttp.StreamReader(protocol, 2**16, loop=asyncio.get_running_loop()) | ||
387 | - p = HttpPayloadParser(out, chunked=True) | ||
388 | + p = HttpPayloadParser(out, chunked=True, headers_parser=HeadersParser()) | ||
389 | p.feed_data(b"4\r\nasdf\r\n0\r\n") | ||
390 | p.feed_data(b"\r\n") | ||
391 | |||
392 | @@ -1652,7 +1611,7 @@ class TestParsePayload: | ||
393 | self, protocol: BaseProtocol | ||
394 | ) -> None: | ||
395 | out = aiohttp.StreamReader(protocol, 2**16, loop=asyncio.get_running_loop()) | ||
396 | - p = HttpPayloadParser(out, chunked=True) | ||
397 | + p = HttpPayloadParser(out, chunked=True, headers_parser=HeadersParser()) | ||
398 | p.feed_data(b"4\r\nasdf\r\n0\r\n\r") | ||
399 | p.feed_data(b"\n") | ||
400 | |||
401 | @@ -1663,7 +1622,7 @@ class TestParsePayload: | ||
402 | self, protocol: BaseProtocol | ||
403 | ) -> None: | ||
404 | out = aiohttp.StreamReader(protocol, 2**16, loop=asyncio.get_running_loop()) | ||
405 | - p = HttpPayloadParser(out, chunked=True) | ||
406 | + p = HttpPayloadParser(out, chunked=True, headers_parser=HeadersParser()) | ||
407 | p.feed_data(b"4\r\nasdf\r\n0\r\n") | ||
408 | p.feed_data(b"Content-MD5: 912ec803b2ce49e4a541068d495ab570\r\n") | ||
409 | p.feed_data(b"\r\n") | ||
410 | @@ -1675,7 +1634,7 @@ class TestParsePayload: | ||
411 | self, protocol: BaseProtocol | ||
412 | ) -> None: | ||
413 | out = aiohttp.StreamReader(protocol, 2**16, loop=asyncio.get_running_loop()) | ||
414 | - p = HttpPayloadParser(out, chunked=True) | ||
415 | + p = HttpPayloadParser(out, chunked=True, headers_parser=HeadersParser()) | ||
416 | p.feed_data(b"4\r\nasdf\r\n0\r\n") | ||
417 | p.feed_data(b"Content-MD5: 912ec803b2ce49e4a541068d495ab570\r\n\r") | ||
418 | p.feed_data(b"\n") | ||
419 | @@ -1687,7 +1646,7 @@ class TestParsePayload: | ||
420 | self, protocol: BaseProtocol | ||
421 | ) -> None: | ||
422 | out = aiohttp.StreamReader(protocol, 2**16, loop=asyncio.get_running_loop()) | ||
423 | - p = HttpPayloadParser(out, chunked=True) | ||
424 | + p = HttpPayloadParser(out, chunked=True, headers_parser=HeadersParser()) | ||
425 | p.feed_data(b"4\r\nasdf\r\n0\r\nContent-MD5: ") | ||
426 | p.feed_data(b"912ec803b2ce49e4a541068d495ab570\r\n\r\n") | ||
427 | |||
428 | @@ -1698,7 +1657,7 @@ class TestParsePayload: | ||
429 | self, protocol: BaseProtocol | ||
430 | ) -> None: | ||
431 | out = aiohttp.StreamReader(protocol, 2**16, loop=asyncio.get_running_loop()) | ||
432 | - p = HttpPayloadParser(out, chunked=True) | ||
433 | + p = HttpPayloadParser(out, chunked=True, headers_parser=HeadersParser()) | ||
434 | p.feed_data(b"4\r\nasdf\r\n0\r\nC") | ||
435 | p.feed_data(b"ontent-MD5: 912ec803b2ce49e4a541068d495ab570\r\n\r\n") | ||
436 | |||
437 | @@ -1707,7 +1666,7 @@ class TestParsePayload: | ||
438 | |||
439 | async def test_http_payload_parser_length(self, protocol: BaseProtocol) -> None: | ||
440 | out = aiohttp.StreamReader(protocol, 2**16, loop=asyncio.get_running_loop()) | ||
441 | - p = HttpPayloadParser(out, length=2) | ||
442 | + p = HttpPayloadParser(out, length=2, headers_parser=HeadersParser()) | ||
443 | eof, tail = p.feed_data(b"1245") | ||
444 | assert eof | ||
445 | |||
446 | @@ -1720,7 +1679,9 @@ class TestParsePayload: | ||
447 | |||
448 | length = len(COMPRESSED) | ||
449 | out = aiohttp.StreamReader(protocol, 2**16, loop=asyncio.get_running_loop()) | ||
450 | - p = HttpPayloadParser(out, length=length, compression="deflate") | ||
451 | + p = HttpPayloadParser( | ||
452 | + out, length=length, compression="deflate", headers_parser=HeadersParser() | ||
453 | + ) | ||
454 | p.feed_data(COMPRESSED) | ||
455 | assert b"data" == out._buffer[0] | ||
456 | assert out.is_eof() | ||
457 | @@ -1734,7 +1695,9 @@ class TestParsePayload: | ||
458 | |||
459 | length = len(COMPRESSED) | ||
460 | out = aiohttp.StreamReader(protocol, 2**16, loop=asyncio.get_running_loop()) | ||
461 | - p = HttpPayloadParser(out, length=length, compression="deflate") | ||
462 | + p = HttpPayloadParser( | ||
463 | + out, length=length, compression="deflate", headers_parser=HeadersParser() | ||
464 | + ) | ||
465 | p.feed_data(COMPRESSED) | ||
466 | assert b"data" == out._buffer[0] | ||
467 | assert out.is_eof() | ||
468 | @@ -1747,7 +1710,9 @@ class TestParsePayload: | ||
469 | |||
470 | length = len(COMPRESSED) | ||
471 | out = aiohttp.StreamReader(protocol, 2**16, loop=asyncio.get_running_loop()) | ||
472 | - p = HttpPayloadParser(out, length=length, compression="deflate") | ||
473 | + p = HttpPayloadParser( | ||
474 | + out, length=length, compression="deflate", headers_parser=HeadersParser() | ||
475 | + ) | ||
476 | p.feed_data(COMPRESSED) | ||
477 | |||
478 | assert b"data" == out._buffer[0] | ||
479 | @@ -1757,7 +1722,9 @@ class TestParsePayload: | ||
480 | self, protocol: BaseProtocol | ||
481 | ) -> None: | ||
482 | out = aiohttp.StreamReader(protocol, 2**16, loop=asyncio.get_running_loop()) | ||
483 | - p = HttpPayloadParser(out, compression="deflate") | ||
484 | + p = HttpPayloadParser( | ||
485 | + out, compression="deflate", headers_parser=HeadersParser() | ||
486 | + ) | ||
487 | # Feeding one correct byte should be enough to choose exact | ||
488 | # deflate decompressor | ||
489 | p.feed_data(b"x") | ||
490 | @@ -1769,7 +1736,9 @@ class TestParsePayload: | ||
491 | self, protocol: BaseProtocol | ||
492 | ) -> None: | ||
493 | out = aiohttp.StreamReader(protocol, 2**16, loop=asyncio.get_running_loop()) | ||
494 | - p = HttpPayloadParser(out, compression="deflate") | ||
495 | + p = HttpPayloadParser( | ||
496 | + out, compression="deflate", headers_parser=HeadersParser() | ||
497 | + ) | ||
498 | # Feeding one wrong byte should be enough to choose exact | ||
499 | # deflate decompressor | ||
500 | p.feed_data(b"K") | ||
501 | @@ -1781,7 +1750,7 @@ class TestParsePayload: | ||
502 | self, protocol: BaseProtocol | ||
503 | ) -> None: | ||
504 | out = aiohttp.StreamReader(protocol, 2**16, loop=asyncio.get_running_loop()) | ||
505 | - p = HttpPayloadParser(out, length=0) | ||
506 | + p = HttpPayloadParser(out, length=0, headers_parser=HeadersParser()) | ||
507 | assert p.done | ||
508 | assert out.is_eof() | ||
509 | |||
510 | @@ -1789,7 +1758,12 @@ class TestParsePayload: | ||
511 | async def test_http_payload_brotli(self, protocol: BaseProtocol) -> None: | ||
512 | compressed = brotli.compress(b"brotli data") | ||
513 | out = aiohttp.StreamReader(protocol, 2**16, loop=asyncio.get_running_loop()) | ||
514 | - p = HttpPayloadParser(out, length=len(compressed), compression="br") | ||
515 | + p = HttpPayloadParser( | ||
516 | + out, | ||
517 | + length=len(compressed), | ||
518 | + compression="br", | ||
519 | + headers_parser=HeadersParser(), | ||
520 | + ) | ||
521 | p.feed_data(compressed) | ||
522 | assert b"brotli data" == out._buffer[0] | ||
523 | assert out.is_eof() | ||
524 | -- | ||
525 | 2.34.1 | ||
526 | |||