diff --git a/aiohttp/_http_parser.pyx b/aiohttp/_http_parser.pyx index d53be214fa5..85fae3a30c4 100644 --- a/aiohttp/_http_parser.pyx +++ b/aiohttp/_http_parser.pyx @@ -137,9 +137,16 @@ cdef class HttpParser: self._raw_headers.append((raw_name, raw_value)) cdef _on_header_field(self, str field, bytes raw_field): - self._process_header() - self._header_name = field - self._raw_header_name = raw_field + if self._header_value is not None: + self._process_header() + self._header_value = None + + if self._header_name is None: + self._header_name = field + self._raw_header_name = raw_field + else: + self._header_name += field + self._raw_header_name += raw_field cdef _on_header_value(self, str val, bytes raw_val): if self._header_value is None: diff --git a/changes/2183.bugfix b/changes/2183.bugfix new file mode 100644 index 00000000000..39be9cea140 --- /dev/null +++ b/changes/2183.bugfix @@ -0,0 +1 @@ +Fix header name parsing, if name is split into multiple lines diff --git a/tests/test_http_parser.py b/tests/test_http_parser.py index ac2011ed2ea..fad479fe151 100644 --- a/tests/test_http_parser.py +++ b/tests/test_http_parser.py @@ -141,6 +141,27 @@ def test_headers_multi_feed(parser): assert not msg.upgrade +def test_headers_split_field(parser): + text1 = b'GET /test HTTP/1.1\r\n' + text2 = b't' + text3 = b'es' + text4 = b't: value\r\n\r\n' + + messages, upgrade, tail = parser.feed_data(text1) + messages, upgrade, tail = parser.feed_data(text2) + messages, upgrade, tail = parser.feed_data(text3) + assert len(messages) == 0 + messages, upgrade, tail = parser.feed_data(text4) + assert len(messages) == 1 + + msg = messages[0][0] + assert list(msg.headers.items()) == [('test', 'value')] + assert msg.raw_headers == ((b'test', b'value'),) + assert not msg.should_close + assert msg.compression is None + assert not msg.upgrade + + def test_parse_headers_multi(parser): text = (b'GET /test HTTP/1.1\r\n' b'Set-Cookie: c1=cookie1\r\n'