]> git.ipfire.org Git - thirdparty/tornado.git/commitdiff
httputil: Clean up error handling in HTTPHeaders.parse 2307/head
authorBen Darnell <ben@bendarnell.com>
Sun, 11 Mar 2018 22:34:32 +0000 (18:34 -0400)
committerBen Darnell <ben@bendarnell.com>
Sun, 11 Mar 2018 22:34:32 +0000 (18:34 -0400)
Fixes #2280

tornado/http1connection.py
tornado/httputil.py
tornado/test/httpserver_test.py
tornado/test/httputil_test.py

index ed906223a3f6788820e65f0516dcf81c18b0588c..0349e171add5dabe6f2aee21c38ec98e52870840 100644 (file)
@@ -519,12 +519,7 @@ class HTTP1Connection(httputil.HTTPConnection):
         # 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):
index ceff7350973ef41aa8a9603f5885b4d718b3c63e..3d2d3359d745bf95f558b1fe805bfdad5e7283fc 100644 (file)
@@ -183,11 +183,16 @@ class HTTPHeaders(collections.MutableMapping):
         """
         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
@@ -197,6 +202,12 @@ class HTTPHeaders(collections.MutableMapping):
         >>> 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):
index a626369b43eb82b133671b7609bc5738e7eabc99..30696a04a5d3722190c7e6d2362cb7aeca4d09f6 100644 (file)
@@ -425,7 +425,7 @@ class HTTPServerRawTest(AsyncHTTPTestCase):
             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)
index 5c064ddea42b49449612cf2a1bea5729b6e52702..bd5832bcde40c776dd8f7a9bffa745751fe0a31f 100644 (file)
@@ -4,6 +4,7 @@ from __future__ import absolute_import, division, print_function
 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
@@ -283,6 +284,13 @@ Foo: even
                           ("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.