diff options
author | Bert JW Regeer <bertjw@regeer.org> | 2019-12-12 13:33:41 -0800 |
---|---|---|
committer | Bert JW Regeer <bertjw@regeer.org> | 2019-12-19 15:59:57 +0100 |
commit | 7009d1bd03866ad7ffce6a9c64182ff8b1906b32 (patch) | |
tree | 9e383a30d611723b227c6357de2dc5e1774a5859 /waitress | |
parent | 1809765a65076844b67a122b4a573bcba36e2dcd (diff) | |
download | waitress-7009d1bd03866ad7ffce6a9c64182ff8b1906b32.tar.gz |
Upon processing errors, set Connection: close header
When we start sending out an exception that has happened we want to drop
any further pipelined requests that may be waiting. The way we do this
is by slamming the connection shut after we send the response to the
received request that has errored.
This avoids potential issues with attempting to parse the rest of the
data that is in the TCP/IP connection that may contain invalid data.
Diffstat (limited to 'waitress')
-rw-r--r-- | waitress/task.py | 12 | ||||
-rw-r--r-- | waitress/tests/test_functional.py | 6 | ||||
-rw-r--r-- | waitress/tests/test_task.py | 36 |
3 files changed, 26 insertions, 28 deletions
diff --git a/waitress/task.py b/waitress/task.py index c12b0f9..8e7ab18 100644 --- a/waitress/task.py +++ b/waitress/task.py @@ -353,14 +353,10 @@ class ErrorTask(Task): status, headers, body = e.to_response() self.status = status self.response_headers.extend(headers) - if self.version == "1.1": - connection = self.request.headers.get("CONNECTION", "").lower() - if connection == "close": - self.response_headers.append(("Connection", "close")) - # under HTTP 1.1 keep-alive is default, no need to set the header - else: - # HTTP 1.0 - self.response_headers.append(("Connection", "close")) + # We need to explicitly tell the remote client we are closing the + # connection, because self.close_on_finish is set, and we are going to + # slam the door in the clients face. + self.response_headers.append(("Connection", "close")) self.close_on_finish = True self.content_length = len(body) self.write(tobytes(body)) diff --git a/waitress/tests/test_functional.py b/waitress/tests/test_functional.py index bfe5072..a278d54 100644 --- a/waitress/tests/test_functional.py +++ b/waitress/tests/test_functional.py @@ -336,7 +336,7 @@ class EchoTests(object): cl = int(headers["content-length"]) self.assertEqual(cl, len(response_body)) self.assertEqual( - sorted(headers.keys()), ["content-length", "content-type", "date", "server"] + sorted(headers.keys()), ["connection", "content-length", "content-type", "date", "server"] ) self.assertEqual(headers["content-type"], "text/plain") # connection has been closed @@ -1069,7 +1069,7 @@ class InternalServerErrorTests(object): self.assertEqual(cl, len(response_body)) self.assertTrue(response_body.startswith(b"Internal Server Error")) self.assertEqual( - sorted(headers.keys()), ["content-length", "content-type", "date", "server"] + sorted(headers.keys()), ["connection", "content-length", "content-type", "date", "server"] ) # connection has been closed self.send_check_error(to_send) @@ -1128,7 +1128,7 @@ class InternalServerErrorTests(object): self.assertEqual(cl, len(response_body)) self.assertTrue(response_body.startswith(b"Internal Server Error")) self.assertEqual( - sorted(headers.keys()), ["content-length", "content-type", "date", "server"] + sorted(headers.keys()), ["connection", "content-length", "content-type", "date", "server"] ) # connection has been closed self.send_check_error(to_send) diff --git a/waitress/tests/test_task.py b/waitress/tests/test_task.py index 584add1..1a86245 100644 --- a/waitress/tests/test_task.py +++ b/waitress/tests/test_task.py @@ -876,15 +876,16 @@ class TestErrorTask(unittest.TestCase): inst.version = "1.1" inst.execute() lines = filter_lines(inst.channel.written) - self.assertEqual(len(lines), 8) + self.assertEqual(len(lines), 9) self.assertEqual(lines[0], b"HTTP/1.1 432 Too Ugly") - self.assertEqual(lines[1], b"Content-Length: 43") - self.assertEqual(lines[2], b"Content-Type: text/plain") - self.assertTrue(lines[3]) - self.assertEqual(lines[4], b"Server: waitress") - self.assertEqual(lines[5], b"Too Ugly") - self.assertEqual(lines[6], b"body") - self.assertEqual(lines[7], b"(generated by waitress)") + self.assertEqual(lines[1], b"Connection: close") + self.assertEqual(lines[2], b"Content-Length: 43") + self.assertEqual(lines[3], b"Content-Type: text/plain") + self.assertTrue(lines[4]) + self.assertEqual(lines[5], b"Server: waitress") + self.assertEqual(lines[6], b"Too Ugly") + self.assertEqual(lines[7], b"body") + self.assertEqual(lines[8], b"(generated by waitress)") def test_execute_http_11_close(self): inst = self._makeOne() @@ -903,21 +904,22 @@ class TestErrorTask(unittest.TestCase): self.assertEqual(lines[7], b"body") self.assertEqual(lines[8], b"(generated by waitress)") - def test_execute_http_11_keep(self): + def test_execute_http_11_keep_forces_close(self): inst = self._makeOne() inst.version = "1.1" inst.request.headers["CONNECTION"] = "keep-alive" inst.execute() lines = filter_lines(inst.channel.written) - self.assertEqual(len(lines), 8) + self.assertEqual(len(lines), 9) self.assertEqual(lines[0], b"HTTP/1.1 432 Too Ugly") - self.assertEqual(lines[1], b"Content-Length: 43") - self.assertEqual(lines[2], b"Content-Type: text/plain") - self.assertTrue(lines[3]) - self.assertEqual(lines[4], b"Server: waitress") - self.assertEqual(lines[5], b"Too Ugly") - self.assertEqual(lines[6], b"body") - self.assertEqual(lines[7], b"(generated by waitress)") + self.assertEqual(lines[1], b"Connection: close") + self.assertEqual(lines[2], b"Content-Length: 43") + self.assertEqual(lines[3], b"Content-Type: text/plain") + self.assertTrue(lines[4]) + self.assertEqual(lines[5], b"Server: waitress") + self.assertEqual(lines[6], b"Too Ugly") + self.assertEqual(lines[7], b"body") + self.assertEqual(lines[8], b"(generated by waitress)") class DummyTask(object): |