From: Nick Coutsos Date: Wed, 8 Jun 2016 01:15:17 +0000 (-0400) Subject: Allow 204 responses without Content-Length/Transfer-Encoding X-Git-Tag: v4.4.0b1~2^2~2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=48d8144a03de8eea2740bfa4ddcc696816b8f7a4;p=thirdparty%2Ftornado.git Allow 204 responses without Content-Length/Transfer-Encoding --- diff --git a/tornado/http1connection.py b/tornado/http1connection.py index 43034c6b5..d0e91b827 100644 --- a/tornado/http1connection.py +++ b/tornado/http1connection.py @@ -351,7 +351,7 @@ class HTTP1Connection(httputil.HTTPConnection): # 304 responses have no body (not even a zero-length body), and so # should not have either Content-Length or Transfer-Encoding. # headers. - start_line.code != 304 and + start_line.code not in (204, 304) and # No need to chunk the output if a Content-Length is specified. 'Content-Length' not in headers and # Applications are discouraged from touching Transfer-Encoding, diff --git a/tornado/test/simple_httpclient_test.py b/tornado/test/simple_httpclient_test.py index 74073182d..58ea14801 100644 --- a/tornado/test/simple_httpclient_test.py +++ b/tornado/test/simple_httpclient_test.py @@ -73,10 +73,18 @@ class OptionsHandler(RequestHandler): class NoContentHandler(RequestHandler): def get(self): + start_line = ResponseStartLine("HTTP/1.1", 204, "No Content") + headers = HTTPHeaders() + chunk = None + if self.get_argument("error", None): - self.set_header("Content-Length", "5") - self.write("hello") - self.set_status(204) + headers['Content-Length'] = "5" + chunk = b"hello" + + # write directly to the connection because .write() and .finish() won't + # allow us to generate malformed responses + self.request.connection.write_headers(start_line, headers, chunk) + self.request.finish() class SeeOtherPostHandler(RequestHandler): @@ -322,12 +330,11 @@ class SimpleHTTPClientTestMixin(object): def test_no_content(self): response = self.fetch("/no_content") self.assertEqual(response.code, 204) - # 204 status doesn't need a content-length, but tornado will - # add a zero content-length anyway. + # 204 status shouldn't have a content-length # # A test without a content-length header is included below # in HTTP204NoContentTestCase. - self.assertEqual(response.headers["Content-length"], "0") + self.assertNotIn("Content-Length", response.headers) # 204 status with non-zero content length is malformed with ExpectLog(gen_log, "Malformed HTTP message"): diff --git a/tornado/test/web_test.py b/tornado/test/web_test.py index 744803a1b..745d0fa84 100644 --- a/tornado/test/web_test.py +++ b/tornado/test/web_test.py @@ -1397,6 +1397,19 @@ class ClearHeaderTest(SimpleHandlerTestCase): self.assertEqual(response.headers["h2"], "bar") +class Header204Test(SimpleHandlerTestCase): + class Handler(RequestHandler): + def get(self): + self.set_status(204) + self.finish() + + def test_204_headers(self): + response = self.fetch('/') + self.assertEqual(response.code, 204) + self.assertNotIn("Content-Length", response.headers) + self.assertNotIn("Transfer-Encoding", response.headers) + + @wsgi_safe class Header304Test(SimpleHandlerTestCase): class Handler(RequestHandler): diff --git a/tornado/web.py b/tornado/web.py index 254a91ac5..479dd2457 100644 --- a/tornado/web.py +++ b/tornado/web.py @@ -935,8 +935,8 @@ class RequestHandler(object): if self.check_etag_header(): self._write_buffer = [] self.set_status(304) - if self._status_code == 304: - assert not self._write_buffer, "Cannot send body with 304" + if self._status_code in (204, 304): + assert not self._write_buffer, "Cannot send body with %s" % self._status_code self._clear_headers_for_304() elif "Content-Length" not in self._headers: content_length = sum(len(part) for part in self._write_buffer)