From: Ben Darnell Date: Sun, 25 Nov 2012 16:26:13 +0000 (-0500) Subject: Accept Content-Length headers in 304 responses. X-Git-Tag: v3.0.0~213 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=5f4d98c4578f7f8138cd660dcdb5bcf7e5b5ec4c;p=thirdparty%2Ftornado.git Accept Content-Length headers in 304 responses. Closes #639. --- diff --git a/tornado/simple_httpclient.py b/tornado/simple_httpclient.py index be5fb6737..faff83c8f 100644 --- a/tornado/simple_httpclient.py +++ b/tornado/simple_httpclient.py @@ -365,12 +365,12 @@ class _HTTPConnection(object): self.request.header_callback("%s: %s\r\n" % (k, v)) self.request.header_callback('\r\n') - if self.request.method == "HEAD": - # HEAD requests never have content, even though they may have - # content-length headers + if self.request.method == "HEAD" or self.code == 304: + # HEAD requests and 304 responses never have content, even + # though they may have content-length headers self._on_body(b("")) return - if 100 <= self.code < 200 or self.code in (204, 304): + if 100 <= self.code < 200 or self.code == 204: # These response codes never have bodies # http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.3 if ("Transfer-Encoding" in self.headers or diff --git a/tornado/test/httpclient_test.py b/tornado/test/httpclient_test.py index 88a858824..6cc431715 100644 --- a/tornado/test/httpclient_test.py +++ b/tornado/test/httpclient_test.py @@ -63,6 +63,17 @@ class UserAgentHandler(RequestHandler): self.write(self.request.headers.get('User-Agent', 'User agent not set')) +class ContentLength304Handler(RequestHandler): + def get(self): + self.set_status(304) + self.set_header('Content-Length', 42) + + def _clear_headers_for_304(self): + # Tornado strips content-length from 304 responses, but here we + # want to simulate servers that include the headers anyway. + pass + + # These tests end up getting run redundantly: once here with the default # HTTPClient implementation, and then again in each implementation's own # test suite. @@ -78,6 +89,7 @@ class HTTPClientCommonTestCase(AsyncHTTPTestCase): url("/countdown/([0-9]+)", CountdownHandler, name="countdown"), url("/echopost", EchoPostHandler), url("/user_agent", UserAgentHandler), + url("/304_with_content_length", ContentLength304Handler), ], gzip=True) def test_hello_world(self): @@ -268,6 +280,14 @@ Transfer-Encoding: chunked response = self.wait() self.assertEqual(response.body, b('TestDefaultUserAgent')) + def test_304_with_content_length(self): + # According to the spec 304 responses SHOULD NOT include + # Content-Length or other entity headers, but some servers do it + # anyway. + # http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.5 + response = self.fetch('/304_with_content_length') + self.assertEqual(response.code, 304) + self.assertEqual(response.headers['Content-Length'], '42') class RequestProxyTest(unittest.TestCase): def test_request_set(self): diff --git a/website/sphinx/releases/next.rst b/website/sphinx/releases/next.rst index 36bfaa130..32ea2b819 100644 --- a/website/sphinx/releases/next.rst +++ b/website/sphinx/releases/next.rst @@ -178,3 +178,5 @@ In progress ``use_gzip``, ``proxy_password``, ``allow_nonstandard_methods``, and ``validate_cert`` have been moved from `HTTPRequest` to the client implementations. +* `simple_httpclient` now accepts responses with a 304 status code that + include a ``Content-Length`` header.