From 9c65fcfc728910c48ca532cb898be5ce9ca35e15 Mon Sep 17 00:00:00 2001 From: Ben Kallus <49924171+kenballus@users.noreply.github.com> Date: Sun, 15 Oct 2023 10:20:50 -0400 Subject: [PATCH] Require full version and method regex matches (#7701) ## What do these changes do? These changes ensure that HTTP versions and methods fully match the regular expressions for those constructs. AIOHTTP currently only applies prefix-matching, which I assume was unintentional. ## Are there changes in behavior for the user? There should be no observable changes to the user, unless they use HTTP servers/clients that generate very malformed request lines. Such clients/servers are unlikely to exist because most other web servers reject these malformed messages. ## Related issue number Fixes #7700 (cherry picked from commit 312f747de91f20fa33af03fd368f857fbd32f36a) --- CHANGES/7700.bugfix | 1 + CONTRIBUTORS.txt | 1 + aiohttp/http_parser.py | 6 +++--- tests/test_http_parser.py | 4 ++-- 4 files changed, 7 insertions(+), 5 deletions(-) create mode 100644 CHANGES/7700.bugfix diff --git a/CHANGES/7700.bugfix b/CHANGES/7700.bugfix new file mode 100644 index 00000000000..26fdfa9076b --- /dev/null +++ b/CHANGES/7700.bugfix @@ -0,0 +1 @@ +Fix issue with insufficient HTTP method and version validation. diff --git a/CONTRIBUTORS.txt b/CONTRIBUTORS.txt index fcecdb91920..11dd39299bc 100644 --- a/CONTRIBUTORS.txt +++ b/CONTRIBUTORS.txt @@ -51,6 +51,7 @@ Arthur Darcet Austin Scola Ben Bader Ben Greiner +Ben Kallus Ben Timby Benedikt Reinartz Bob Haddleton diff --git a/aiohttp/http_parser.py b/aiohttp/http_parser.py index a8f43407f10..17cc004eba7 100644 --- a/aiohttp/http_parser.py +++ b/aiohttp/http_parser.py @@ -556,11 +556,11 @@ def parse_message(self, lines: List[bytes]) -> RawRequestMessage: ) # method - if not METHRE.match(method): + if not METHRE.fullmatch(method): raise BadStatusLine(method) # version - match = VERSRE.match(version) + match = VERSRE.fullmatch(version) if match is None: raise BadStatusLine(line) version_o = HttpVersion(int(match.group(1)), int(match.group(2))) @@ -659,7 +659,7 @@ def parse_message(self, lines: List[bytes]) -> RawResponseMessage: ) # version - match = VERSRE.match(version) + match = VERSRE.fullmatch(version) if match is None: raise BadStatusLine(line) version_o = HttpVersion(int(match.group(1)), int(match.group(2))) diff --git a/tests/test_http_parser.py b/tests/test_http_parser.py index fe8977258dc..fa0e8909a73 100644 --- a/tests/test_http_parser.py +++ b/tests/test_http_parser.py @@ -728,7 +728,7 @@ def test_http_request_parser_two_slashes(parser) -> None: def test_http_request_parser_bad_method(parser) -> None: with pytest.raises(http_exceptions.BadStatusLine): - parser.feed_data(b'=":(e),[T];?" /get HTTP/1.1\r\n\r\n') + parser.feed_data(b'G=":<>(e),[T];?" /get HTTP/1.1\r\n\r\n') def test_http_request_parser_bad_version(parser) -> None: @@ -738,7 +738,7 @@ def test_http_request_parser_bad_version(parser) -> None: def test_http_request_parser_bad_version_number(parser: Any) -> None: with pytest.raises(http_exceptions.BadHttpMessage): - parser.feed_data(b"GET /test HTTP/12.3\r\n\r\n") + parser.feed_data(b"GET /test HTTP/1.32\r\n\r\n") @pytest.mark.parametrize("size", [40965, 8191])