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
--- /dev/null
+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')
'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',