Skip to content

Commit

Permalink
Use lenient headers for response parser (#7490)
Browse files Browse the repository at this point in the history
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
(cherry picked from commit 6396531)
  • Loading branch information
Dreamsorcerer committed Aug 7, 2023
1 parent 5a5f65a commit 44e3415
Show file tree
Hide file tree
Showing 5 changed files with 41 additions and 0 deletions.
7 changes: 7 additions & 0 deletions .github/workflows/ci-cd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,13 @@ jobs:
run: >- # `exit 1` makes sure that the job remains red with flaky runs
pytest --no-cov -vvvvv --lf && exit 1
shell: bash
- name: Run dev_mode tests
env:
COLOR: yes
AIOHTTP_NO_EXTENSIONS: ${{ matrix.no-extensions }}
PIP_USER: 1
run: python -X dev -m pytest -m dev_mode --cov-append
shell: bash
- name: Turn coverage into xml
env:
COLOR: 'yes'
Expand Down
1 change: 1 addition & 0 deletions CHANGES/7490.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Enabled lenient headers for more flexible parsing in the client. -- by :user:`Dreamsorcerer`
4 changes: 4 additions & 0 deletions aiohttp/_http_parser.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ from multidict import CIMultiDict as _CIMultiDict, CIMultiDictProxy as _CIMultiD
from yarl import URL as _URL

from aiohttp import hdrs
from aiohttp.helpers import DEBUG

from .http_exceptions import (
BadHttpMessage,
Expand Down Expand Up @@ -648,6 +649,9 @@ cdef class HttpResponseParser(HttpParser):
max_line_size, max_headers, max_field_size,
payload_exception, response_with_body, read_until_eof,
auto_decompress)
# Use strict parsing on dev mode, so users are warned about broken servers.
if not DEBUG:
cparser.llhttp_set_lenient_headers(self._cparser, 1)

cdef object _on_status_complete(self):
if self._buf:
Expand Down
12 changes: 12 additions & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,18 @@ Server example:
For more information please visit :ref:`aiohttp-client` and
:ref:`aiohttp-web` pages.

Development mode
================

When writing your code, we recommend enabling Python's
`development mode <https://docs.python.org/3/library/devmode.html>`_
(``python -X dev``). In addition to the extra features enabled for asyncio, aiohttp
will:

- Use a strict parser in the client code (which can help detect malformed responses
from a server).
- Enable some additional checks (resulting in warnings in certain situations).

What's new in aiohttp 3?
========================

Expand Down
17 changes: 17 additions & 0 deletions tests/test_http_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -729,6 +729,23 @@ def test_http_response_parser_no_reason(response) -> None:
assert msg.reason == ""


def test_http_response_parser_lenient_headers(response) -> None:
messages, upgrade, tail = response.feed_data(
b"HTTP/1.1 200 test\r\nFoo: abc\x01def\r\n\r\n"
)
msg = messages[0][0]

assert msg.headers["Foo"] == "abc\x01def"


@pytest.mark.dev_mode
def test_http_response_parser_strict_headers(response) -> None:
if isinstance(response, HttpResponseParserPy):
pytest.xfail("Py parser is lenient. May update py-parser later.")
with pytest.raises(http_exceptions.BadHttpMessage):
response.feed_data(b"HTTP/1.1 200 test\r\nFoo: abc\x01def\r\n\r\n")


def test_http_response_parser_bad(response) -> None:
with pytest.raises(http_exceptions.BadHttpMessage):
response.feed_data(b"HTT/1\r\n\r\n")
Expand Down

0 comments on commit 44e3415

Please sign in to comment.