From 72176b2a470b20cc93665e2f435ae7eb9c6ca608 Mon Sep 17 00:00:00 2001 From: hh-h Date: Sun, 26 Jan 2020 23:30:27 +0300 Subject: [PATCH] body_exists for requests without body should be False (#4529) --- CHANGES/4528.bugfix | 1 + aiohttp/_http_parser.pyx | 19 ++++++++++++++----- tests/test_web_functional.py | 10 +++++++--- 3 files changed, 22 insertions(+), 8 deletions(-) create mode 100644 CHANGES/4528.bugfix diff --git a/CHANGES/4528.bugfix b/CHANGES/4528.bugfix new file mode 100644 index 00000000000..7ccbe34dcae --- /dev/null +++ b/CHANGES/4528.bugfix @@ -0,0 +1 @@ +Fixed request.body_exists returns wrong value for methods without body. diff --git a/aiohttp/_http_parser.pyx b/aiohttp/_http_parser.pyx index 1160c4120f6..153d9529b0d 100644 --- a/aiohttp/_http_parser.pyx +++ b/aiohttp/_http_parser.pyx @@ -5,6 +5,7 @@ from __future__ import absolute_import, print_function from cpython.mem cimport PyMem_Malloc, PyMem_Free from libc.string cimport memcpy +from libc.limits cimport ULLONG_MAX from cpython cimport (PyObject_GetBuffer, PyBuffer_Release, PyBUF_SIMPLE, Py_buffer, PyBytes_AsString, PyBytes_AsStringAndSize) @@ -270,6 +271,7 @@ cdef class HttpParser: size_t _max_field_size size_t _max_headers bint _response_with_body + bint _read_until_eof bint _started object _url @@ -309,7 +311,8 @@ cdef class HttpParser: object protocol, object loop, object timer=None, size_t max_line_size=8190, size_t max_headers=32768, size_t max_field_size=8190, payload_exception=None, - bint response_with_body=True, bint auto_decompress=True): + bint response_with_body=True, bint read_until_eof=False, + bint auto_decompress=True): cparser.http_parser_init(self._cparser, mode) self._cparser.data = self self._cparser.content_length = 0 @@ -334,6 +337,7 @@ cdef class HttpParser: self._max_headers = max_headers self._max_field_size = max_field_size self._response_with_body = response_with_body + self._read_until_eof = read_until_eof self._upgraded = False self._auto_decompress = auto_decompress self._content_encoding = None @@ -427,8 +431,12 @@ cdef class HttpParser: headers, raw_headers, should_close, encoding, upgrade, chunked) - if (self._cparser.content_length > 0 or chunked or - self._cparser.method == 5): # CONNECT: 5 + if (ULLONG_MAX > self._cparser.content_length > 0 or chunked or + self._cparser.method == 5 or # CONNECT: 5 + (self._cparser.status_code >= 199 and + self._cparser.content_length == ULLONG_MAX and + self._read_until_eof) + ): payload = StreamReader( self._protocol, timer=self._timer, loop=self._loop) else: @@ -545,7 +553,7 @@ cdef class HttpRequestParser(HttpParser): bint response_with_body=True, bint read_until_eof=False): self._init(cparser.HTTP_REQUEST, protocol, loop, timer, max_line_size, max_headers, max_field_size, - payload_exception, response_with_body) + payload_exception, response_with_body, read_until_eof) cdef object _on_status_complete(self): cdef Py_buffer py_buf @@ -573,7 +581,8 @@ cdef class HttpResponseParser(HttpParser): bint auto_decompress=True): self._init(cparser.HTTP_RESPONSE, protocol, loop, timer, max_line_size, max_headers, max_field_size, - payload_exception, response_with_body, auto_decompress) + payload_exception, response_with_body, read_until_eof, + auto_decompress) cdef object _on_status_complete(self): if self._buf: diff --git a/tests/test_web_functional.py b/tests/test_web_functional.py index 4a8a71370de..5ba90e1c653 100644 --- a/tests/test_web_functional.py +++ b/tests/test_web_functional.py @@ -685,7 +685,11 @@ async def handler(request): assert 200 == resp.status -async def test_empty_content_for_query_without_body(aiohttp_client) -> None: +@pytest.mark.parametrize("method", [ + "get", "post", "options", "post", "put", "patch", "delete" +]) +async def test_empty_content_for_query_without_body( + method, aiohttp_client) -> None: async def handler(request): assert not request.body_exists @@ -693,10 +697,10 @@ async def handler(request): return web.Response() app = web.Application() - app.router.add_post('/', handler) + app.router.add_route(method, '/', handler) client = await aiohttp_client(app) - resp = await client.post('/') + resp = await client.request(method, '/') assert 200 == resp.status