# RFC 7230 section allows for both CRLF and bare LF.
eol = data.find("\n")
start_line = data[:eol].rstrip("\r")
- try:
- headers = httputil.HTTPHeaders.parse(data[eol:])
- except ValueError:
- # probably form split() if there was no ':' in the line
- raise httputil.HTTPInputError("Malformed HTTP headers: %r" %
- data[eol:100])
+ headers = httputil.HTTPHeaders.parse(data[eol:])
return start_line, headers
def _read_body(self, code, headers, delegate):
"""
if line[0].isspace():
# continuation of a multi-line header
+ if self._last_key is None:
+ raise HTTPInputError("first header line cannot start with whitespace")
new_part = ' ' + line.lstrip()
self._as_list[self._last_key][-1] += new_part
self._dict[self._last_key] += new_part
else:
- name, value = line.split(":", 1)
+ try:
+ name, value = line.split(":", 1)
+ except ValueError:
+ raise HTTPInputError("no colon in header line")
self.add(name, value.strip())
@classmethod
>>> h = HTTPHeaders.parse("Content-Type: text/html\\r\\nContent-Length: 42\\r\\n")
>>> sorted(h.items())
[('Content-Length', '42'), ('Content-Type', 'text/html')]
+
+ .. versionchanged:: 5.1
+
+ Raises `HTTPInputError` on malformed headers instead of a
+ mix of `KeyError`, and `ValueError`.
+
"""
h = cls()
for line in _CRLF_RE.split(headers):
self.wait()
def test_malformed_headers(self):
- with ExpectLog(gen_log, '.*Malformed HTTP headers'):
+ with ExpectLog(gen_log, '.*Malformed HTTP message.*no colon in header line'):
self.stream.write(b'GET / HTTP/1.0\r\nasdf\r\n\r\n')
self.io_loop.add_timeout(datetime.timedelta(seconds=0.05),
self.stop)
from tornado.httputil import (
url_concat, parse_multipart_form_data, HTTPHeaders, format_timestamp,
HTTPServerRequest, parse_request_start_line, parse_cookie, qs_to_qsl,
+ HTTPInputError,
)
from tornado.escape import utf8, native_str
from tornado.util import PY3
("Foo", "bar baz"),
("Foo", "even more lines")])
+ def test_malformed_continuation(self):
+ # If the first line starts with whitespace, it's a
+ # continuation line with nothing to continue, so reject it
+ # (with a proper error).
+ data = " Foo: bar"
+ self.assertRaises(HTTPInputError, HTTPHeaders.parse, data)
+
def test_unicode_newlines(self):
# Ensure that only \r\n is recognized as a header separator, and not
# the other newline-like unicode characters.