From 8ca13ef006b9d223d9e63d416318a2d11fe17754 Mon Sep 17 00:00:00 2001 From: Ben Darnell Date: Sat, 13 Apr 2013 20:35:24 -0400 Subject: [PATCH] Handle malformed headers more gracefully. Closes #699. --- tornado/httpserver.py | 6 +++++- tornado/test/httpserver_test.py | 38 +++++++++++++++++++++++++++++---- 2 files changed, 39 insertions(+), 5 deletions(-) diff --git a/tornado/httpserver.py b/tornado/httpserver.py index cfc2a5175..16472fa44 100644 --- a/tornado/httpserver.py +++ b/tornado/httpserver.py @@ -294,7 +294,11 @@ class HTTPConnection(object): raise _BadRequestException("Malformed HTTP request line") if not version.startswith("HTTP/"): raise _BadRequestException("Malformed HTTP version in HTTP Request-Line") - headers = httputil.HTTPHeaders.parse(data[eol:]) + try: + headers = httputil.HTTPHeaders.parse(data[eol:]) + except ValueError: + # Probably from split() if there was no ':' in the line + raise _BadRequestException("Malformed HTTP headers") # HTTPRequest wants an IP, not a full socket address if self.address_family in (socket.AF_INET, socket.AF_INET6): diff --git a/tornado/test/httpserver_test.py b/tornado/test/httpserver_test.py index 54b38b464..ba23a15ba 100644 --- a/tornado/test/httpserver_test.py +++ b/tornado/test/httpserver_test.py @@ -341,14 +341,44 @@ class HTTPServerTest(AsyncHTTPTestCase): self.assertEqual(200, response.code) self.assertEqual(json_decode(response.body), {}) - def test_empty_request(self): - stream = IOStream(socket.socket(), io_loop=self.io_loop) - stream.connect(('localhost', self.get_http_port()), self.stop) + +class HTTPServerRawTest(AsyncHTTPTestCase): + def get_app(self): + return Application([ + ('/echo', EchoHandler), + ]) + + def setUp(self): + super(HTTPServerRawTest, self).setUp() + self.stream = IOStream(socket.socket()) + self.stream.connect(('localhost', self.get_http_port()), self.stop) self.wait() - stream.close() + + def tearDown(self): + self.stream.close() + super(HTTPServerRawTest, self).tearDown() + + def test_empty_request(self): + self.stream.close() self.io_loop.add_timeout(datetime.timedelta(seconds=0.001), self.stop) self.wait() + def test_malformed_first_line(self): + with ExpectLog(gen_log, '.*Malformed HTTP request line'): + self.stream.write(b'asdf\r\n\r\n') + # TODO: need an async version of ExpectLog so we don't need + # hard-coded timeouts here. + self.io_loop.add_timeout(datetime.timedelta(seconds=0.01), + self.stop) + self.wait() + + def test_malformed_headers(self): + with ExpectLog(gen_log, '.*Malformed HTTP headers'): + self.stream.write(b'GET / HTTP/1.0\r\nasdf\r\n\r\n') + self.io_loop.add_timeout(datetime.timedelta(seconds=0.01), + self.stop) + self.wait() + class XHeaderTest(HandlerBaseTestCase): class Handler(RequestHandler): -- 2.47.2