Skip to content

Commit f627e91

Browse files
committed
web: do not send content on HTTPError(204)
Change `write_error()` to not send body if status code in (204, 304) or (100 <= status code < 200) - refactored into `RequestHandler._should_not_send_content(status_code)` Change `get_arguments()` to raise `ValueError` if `strip` is not boolean - as opposed to `AssertionError`. Fixes #3360
1 parent 65a9e48 commit f627e91

File tree

2 files changed

+23
-5
lines changed

2 files changed

+23
-5
lines changed

Diff for: tornado/test/web_test.py

+12
Original file line numberDiff line numberDiff line change
@@ -1687,6 +1687,18 @@ def test_204_headers(self):
16871687
self.assertNotIn("Transfer-Encoding", response.headers)
16881688

16891689

1690+
class Header204viaHTTPErrorTest(SimpleHandlerTestCase):
1691+
class Handler(RequestHandler):
1692+
def get(self):
1693+
raise HTTPError(204)
1694+
1695+
def test_204_headers_via_httperror(self):
1696+
response = self.fetch("/")
1697+
self.assertEqual(response.code, 204)
1698+
self.assertNotIn("Content-Length", response.headers)
1699+
self.assertNotIn("Transfer-Encoding", response.headers)
1700+
1701+
16901702
class Header304Test(SimpleHandlerTestCase):
16911703
class Handler(RequestHandler):
16921704
def get(self):

Diff for: tornado/web.py

+11-5
Original file line numberDiff line numberDiff line change
@@ -466,7 +466,8 @@ def get_arguments(self, name: str, strip: bool = True) -> List[str]:
466466
# Make sure `get_arguments` isn't accidentally being called with a
467467
# positional argument that's assumed to be a default (like in
468468
# `get_argument`.)
469-
assert isinstance(strip, bool)
469+
if not isinstance(strip, bool):
470+
raise ValueError("`strip` must be boolean")
470471

471472
return self._get_arguments(name, self.request.arguments, strip)
472473

@@ -1186,6 +1187,10 @@ def flush(self, include_footers: bool = False) -> "Future[None]":
11861187
future.set_result(None)
11871188
return future
11881189

1190+
def _should_not_send_content(self, status_code: int) -> bool:
1191+
"""Check if we should not send body content for given `status_code`"""
1192+
return status_code in (204, 304) or (100 <= status_code < 200)
1193+
11891194
def finish(self, chunk: Optional[Union[str, bytes, dict]] = None) -> "Future[None]":
11901195
"""Finishes this response, ending the HTTP request.
11911196
@@ -1219,10 +1224,9 @@ def finish(self, chunk: Optional[Union[str, bytes, dict]] = None) -> "Future[Non
12191224
if self.check_etag_header():
12201225
self._write_buffer = []
12211226
self.set_status(304)
1222-
if self._status_code in (204, 304) or (100 <= self._status_code < 200):
1223-
assert not self._write_buffer, (
1224-
"Cannot send body with %s" % self._status_code
1225-
)
1227+
if self._should_not_send_content(self._status_code):
1228+
if self._write_buffer:
1229+
raise RuntimeError(f"Cannot send body with status code HTTP{self._status_code}")
12261230
self._clear_representation_headers()
12271231
elif "Content-Length" not in self._headers:
12281232
content_length = sum(len(part) for part in self._write_buffer)
@@ -1319,6 +1323,8 @@ def write_error(self, status_code: int, **kwargs: Any) -> None:
13191323
for line in traceback.format_exception(*kwargs["exc_info"]):
13201324
self.write(line)
13211325
self.finish()
1326+
elif self._should_not_send_content(status_code):
1327+
self.finish()
13221328
else:
13231329
self.finish(
13241330
"<html><title>%(code)d: %(message)s</title>"

0 commit comments

Comments
 (0)