]> git.ipfire.org Git - thirdparty/tornado.git/commitdiff
Fix HTTP1Connection for responses without content-length
authorBen Darnell <ben@bendarnell.com>
Mon, 15 Feb 2016 00:04:27 +0000 (19:04 -0500)
committerBen Darnell <ben@bendarnell.com>
Mon, 15 Feb 2016 00:04:27 +0000 (19:04 -0500)
Fixes #1598

tornado/http1connection.py
tornado/test/http1connection_test.py [new file with mode: 0644]
tornado/test/runtests.py

index 71f0790d457c6a65c89028478d4fc076ff661efa..7632214544446d0ac8dbfba6ac5d7639498b9371 100644 (file)
@@ -481,7 +481,9 @@ class HTTP1Connection(httputil.HTTPConnection):
             return connection_header != "close"
         elif ("Content-Length" in headers
               or headers.get("Transfer-Encoding", "").lower() == "chunked"
-              or start_line.method in ("HEAD", "GET")):
+              or getattr(start_line, 'method', None) in ("HEAD", "GET")):
+            # start_line may be a request or reponse start line; only
+            # the former has a method attribute.
             return connection_header == "keep-alive"
         return False
 
diff --git a/tornado/test/http1connection_test.py b/tornado/test/http1connection_test.py
new file mode 100644 (file)
index 0000000..815051b
--- /dev/null
@@ -0,0 +1,61 @@
+from __future__ import absolute_import, division, print_function, with_statement
+
+import socket
+
+from tornado.http1connection import HTTP1Connection
+from tornado.httputil import HTTPMessageDelegate
+from tornado.iostream import IOStream
+from tornado.locks import Event
+from tornado.netutil import add_accept_handler
+from tornado.testing import AsyncTestCase, bind_unused_port, gen_test
+
+
+class HTTP1ConnectionTest(AsyncTestCase):
+    def setUp(self):
+        super(HTTP1ConnectionTest, self).setUp()
+        self.asyncSetUp()
+
+    @gen_test
+    def asyncSetUp(self):
+        listener, port = bind_unused_port()
+        event = Event()
+
+        def accept_callback(conn, addr):
+            self.server_stream = IOStream(conn)
+            self.addCleanup(self.server_stream.close)
+            event.set()
+
+        add_accept_handler(listener, accept_callback)
+        self.client_stream = IOStream(socket.socket())
+        self.addCleanup(self.client_stream.close)
+        yield [self.client_stream.connect(('127.0.0.1', port)),
+               event.wait()]
+        self.io_loop.remove_handler(listener)
+        listener.close()
+
+    @gen_test
+    def test_http10_no_content_length(self):
+        # Regression test for a bug in which can_keep_alive would crash
+        # for an HTTP/1.0 (not 1.1) response with no content-length.
+        conn = HTTP1Connection(self.client_stream, True)
+        self.server_stream.write(b"HTTP/1.0 200 Not Modified\r\n\r\nhello")
+        self.server_stream.close()
+
+        event = Event()
+        test = self
+        body = []
+
+        class Delegate(HTTPMessageDelegate):
+            def headers_received(self, start_line, headers):
+                test.code = start_line.code
+
+            def data_received(self, data):
+                body.append(data)
+
+            def finish(self):
+                event.set()
+
+        yield conn.read_response(Delegate())
+        yield event.wait()
+        self.assertEqual(self.code, 200)
+        self.assertEqual(b''.join(body), b'hello')
index ad9b0b8357be9271158502ba42d1dcc464e2763b..3b22d396eb42922f89a9c98eb3dc53f5f0a4d33a 100644 (file)
@@ -29,6 +29,7 @@ TEST_MODULES = [
     'tornado.test.curl_httpclient_test',
     'tornado.test.escape_test',
     'tornado.test.gen_test',
+    'tornado.test.http1connection_test',
     'tornado.test.httpclient_test',
     'tornado.test.httpserver_test',
     'tornado.test.httputil_test',