Skip to content

Commit

Permalink
Fix HTTP1Connection for responses without content-length
Browse files Browse the repository at this point in the history
  • Loading branch information
bdarnell committed Feb 15, 2016
1 parent d7d9c46 commit 34903f9
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 1 deletion.
4 changes: 3 additions & 1 deletion tornado/http1connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -481,7 +481,9 @@ def _can_keep_alive(self, start_line, headers):
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

Expand Down
61 changes: 61 additions & 0 deletions tornado/test/http1connection_test.py
Original file line number Diff line number Diff line change
@@ -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')
1 change: 1 addition & 0 deletions tornado/test/runtests.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
'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',
Expand Down

0 comments on commit 34903f9

Please sign in to comment.