From: Ben Darnell Date: Mon, 21 Apr 2014 03:26:11 +0000 (-0400) Subject: Move HTTP/1.0 Connection: keep-alive behavior to http1connection. X-Git-Tag: v4.0.0b1~91^2~13 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ce3ca51495bfe72acf7a850203e5c6816d6c1fb4;p=thirdparty%2Ftornado.git Move HTTP/1.0 Connection: keep-alive behavior to http1connection. Also remove the supports_http_1_1 check from GzipContentEncoding since versions don't really matter with the accept-encoding check. --- diff --git a/tornado/http1connection.py b/tornado/http1connection.py index b06680031..342d9efc8 100644 --- a/tornado/http1connection.py +++ b/tornado/http1connection.py @@ -77,6 +77,7 @@ class HTTP1Connection(object): # have content-length but no bodies) self._request_start_line = None self._response_start_line = None + self._request_headers = None # True if we are writing output with chunked encoding. self._chunking_output = None # While reading a body with a content-length, this is the @@ -112,6 +113,7 @@ class HTTP1Connection(object): else: start_line = httputil.parse_request_start_line(start_line) self._request_start_line = start_line + self._request_headers = headers self._disconnect_on_finish = not self._can_keep_alive( start_line, headers) @@ -238,6 +240,11 @@ class HTTP1Connection(object): # Applications are discouraged from touching Transfer-Encoding, # but if they do, leave it alone. 'Transfer-Encoding' not in headers) + # If a 1.0 client asked for keep-alive, add the header. + if (self._request_start_line.version == 'HTTP/1.0' and + (self._request_headers.get('Connection', '').lower() + == 'keep-alive')): + headers['Connection'] = 'Keep-Alive' if self._chunking_output: headers['Transfer-Encoding'] = 'chunked' if (not self.is_client and diff --git a/tornado/test/httpserver_test.py b/tornado/test/httpserver_test.py index 22ef7eccc..dc31dc54c 100644 --- a/tornado/test/httpserver_test.py +++ b/tornado/test/httpserver_test.py @@ -33,14 +33,18 @@ except ImportError: def read_stream_body(stream, callback): - """Reads an HTTP response from `stream` and runs callback with its body.""" + """Reads an HTTP response from `stream` and runs callback with its + headers and body.""" chunks = [] class Delegate(HTTPMessageDelegate): + def headers_received(self, start_line, headers): + self.headers = headers + def data_received(self, chunk): chunks.append(chunk) def finish(self): - callback(b''.join(chunks)) + callback((self.headers, b''.join(chunks))) conn = HTTP1Connection(stream, True) conn.read_response(Delegate()) @@ -202,7 +206,8 @@ class HTTPConnectionTest(AsyncHTTPTestCase): [utf8("Content-Length: %d\r\n" % len(body))]) + b"\r\n" + body) read_stream_body(stream, self.stop) - return self.wait() + headers, body = self.wait() + return body def test_multipart_form(self): # Encodings here are tricky: Headers are latin1, bodies can be @@ -415,7 +420,7 @@ bar """.replace(b"\n", b"\r\n")) read_stream_body(self.stream, self.stop) - response = self.wait() + headers, response = self.wait() self.assertEqual(json_decode(response), {u('foo'): [u('bar')]}) @@ -631,8 +636,8 @@ class KeepAliveTest(AsyncHTTPTestCase): return headers def read_response(self): - headers = self.read_headers() - self.stream.read_bytes(int(headers['Content-Length']), self.stop) + self.headers = self.read_headers() + self.stream.read_bytes(int(self.headers['Content-Length']), self.stop) body = self.wait() self.assertEqual(b'Hello world', body) @@ -666,6 +671,7 @@ class KeepAliveTest(AsyncHTTPTestCase): self.stream.read_until_close(callback=self.stop) data = self.wait() self.assertTrue(not data) + self.assertTrue('Connection' not in self.headers) self.close() def test_http10_keepalive(self): @@ -673,8 +679,10 @@ class KeepAliveTest(AsyncHTTPTestCase): self.connect() self.stream.write(b'GET / HTTP/1.0\r\nConnection: keep-alive\r\n\r\n') self.read_response() + self.assertEqual(self.headers['Connection'], 'Keep-Alive') self.stream.write(b'GET / HTTP/1.0\r\nConnection: keep-alive\r\n\r\n') self.read_response() + self.assertEqual(self.headers['Connection'], 'Keep-Alive') self.close() def test_pipelined_requests(self): @@ -993,7 +1001,7 @@ class BodyLimitsTest(AsyncHTTPTestCase): stream.write(b'PUT /streaming?expected_size=10240 HTTP/1.1\r\n' b'Content-Length: 10240\r\n\r\n') stream.write(b'a'*10240) - response = yield gen.Task(read_stream_body, stream) + headers, response = yield gen.Task(read_stream_body, stream) self.assertEqual(response, b'10240') # Without the ?expected_size parameter, we get the old default value stream.write(b'PUT /streaming HTTP/1.1\r\n' diff --git a/tornado/web.py b/tornado/web.py index c318f33c0..37c5f715b 100644 --- a/tornado/web.py +++ b/tornado/web.py @@ -244,12 +244,6 @@ class RequestHandler(object): "Date": httputil.format_timestamp(time.time()), }) self.set_default_headers() - if (not self.request.supports_http_1_1() and - getattr(self.request, 'connection', None) and - not self.request.connection.no_keep_alive): - conn_header = self.request.headers.get("Connection") - if conn_header and (conn_header.lower() == "keep-alive"): - self._headers["Connection"] = "Keep-Alive" self._write_buffer = [] self._status_code = 200 self._reason = httputil.responses[200] @@ -2380,8 +2374,7 @@ class GZipContentEncoding(OutputTransform): MIN_LENGTH = 5 def __init__(self, request): - self._gzipping = request.supports_http_1_1() and \ - "gzip" in request.headers.get("Accept-Encoding", "") + self._gzipping = "gzip" in request.headers.get("Accept-Encoding", "") def _compressible_type(self, ctype): return ctype.startswith('text/') or ctype in self.CONTENT_TYPES