From 5480c85eb5a8dbc9ac4cc6ccb3d84e8d75ce93e0 Mon Sep 17 00:00:00 2001 From: Marcelo Trylesinski Date: Sun, 11 Oct 2026 16:06:15 +0200 Subject: [PATCH] Parse the request body before raising `HttpParserUpgrade` --- httptools/parser/parser.pyx | 5 +---- tests/test_parser.py | 25 +++++++++++++++++++++++++ 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/httptools/parser/parser.pyx b/httptools/parser/parser.pyx index 2fa5026..df95976 100644 --- a/httptools/parser/parser.pyx +++ b/httptools/parser/parser.pyx @@ -358,10 +358,7 @@ cdef int cb_on_headers_complete(cparser.llhttp_t* parser) except -1: pyparser._last_error = ex return -1 else: - if pyparser._cparser.upgrade: - return 1 - else: - return 0 + return 0 cdef int cb_on_body(cparser.llhttp_t* parser, diff --git a/tests/test_parser.py b/tests/test_parser.py index 96dc6f0..99c5ac4 100644 --- a/tests/test_parser.py +++ b/tests/test_parser.py @@ -439,6 +439,31 @@ def on_message_complete(self): else: self.fail('HttpParserUpgrade was not raised') + def test_parser_request_upgrade_with_body(self): + next_request = b'GET / HTTP/1.1\r\n\r\n' + for framing, body, expected in [ + (b'Content-Length: 5', b'hello', [b'hello']), + (b'Transfer-Encoding: chunked', b'3\r\nabc\r\n0\r\n\r\n', [b'abc']), + ]: + with self.subTest(framing=framing): + request = ( + b'POST / HTTP/1.1\r\n' + b'Connection: Upgrade, HTTP2-Settings\r\n' + b'Upgrade: h2c\r\n' + b'HTTP2-Settings: AAMAAABkAAQAoAAAAAIAAAAA\r\n' + + framing + b'\r\n\r\n' + body + ) + m = mock.Mock() + p = httptools.HttpRequestParser(m) + + with self.assertRaises(httptools.HttpParserUpgrade) as cm: + p.feed_data(request + next_request) + + self.assertEqual(cm.exception.args[0], len(request)) + self.assertEqual( + [c.args[0] for c in m.on_body.call_args_list], expected) + m.on_message_complete.assert_called_once_with() + def test_parser_request_error_in_on_header(self): class Error(Exception): pass