diff options
author | Bert JW Regeer <bertjw@regeer.org> | 2022-03-12 18:42:51 -0700 |
---|---|---|
committer | Bert JW Regeer <bertjw@regeer.org> | 2022-03-12 19:48:25 -0700 |
commit | d032a669682838b26d6a1a1b513b9da83b0e0f90 (patch) | |
tree | f94582525d95d39c8117abf69c0a7f158f036ff8 /tests | |
parent | 884bed167d09c3d5fdf0730e2ca2564eefdd4534 (diff) | |
download | waitress-d032a669682838b26d6a1a1b513b9da83b0e0f90.tar.gz |
Error when receiving back Chunk Extension
Waitress discards chunked extensions and does no further processing on
them, however it failed to validate that the chunked encoding extension
did not contain invalid data.
We now validate that if there are any chunked extensions that they are
well-formed, if they are not and contain invalid characters, then
Waitress will now correctly return a Bad Request and stop any further
processing of the request.
Diffstat (limited to 'tests')
-rw-r--r-- | tests/test_functional.py | 22 | ||||
-rw-r--r-- | tests/test_receiver.py | 37 |
2 files changed, 59 insertions, 0 deletions
diff --git a/tests/test_functional.py b/tests/test_functional.py index d1366ca..9e33fc0 100644 --- a/tests/test_functional.py +++ b/tests/test_functional.py @@ -364,6 +364,28 @@ class EchoTests: self.send_check_error(to_send) self.assertRaises(ConnectionClosed, read_http, fp) + def test_broken_chunked_encoding_invalid_extension(self): + control_line = b"20;invalid=\r\n" # 20 hex = 32 dec + s = b"This string has 32 characters.\r\n" + to_send = b"GET / HTTP/1.1\r\nTransfer-Encoding: chunked\r\n\r\n" + to_send += control_line + s + b"\r\n" + self.connect() + self.sock.send(to_send) + with self.sock.makefile("rb", 0) as fp: + line, headers, response_body = read_http(fp) + self.assertline(line, "400", "Bad Request", "HTTP/1.1") + cl = int(headers["content-length"]) + self.assertEqual(cl, len(response_body)) + self.assertIn(b"Invalid chunk extension", response_body) + self.assertEqual( + sorted(headers.keys()), + ["connection", "content-length", "content-type", "date", "server"], + ) + self.assertEqual(headers["content-type"], "text/plain") + # connection has been closed + self.send_check_error(to_send) + self.assertRaises(ConnectionClosed, read_http, fp) + def test_broken_chunked_encoding_missing_chunk_end(self): control_line = b"20\r\n" # 20 hex = 32 dec s = b"This string has 32 characters.\r\n" diff --git a/tests/test_receiver.py b/tests/test_receiver.py index f55aa68..a3b6f99 100644 --- a/tests/test_receiver.py +++ b/tests/test_receiver.py @@ -1,5 +1,7 @@ import unittest +import pytest + class TestFixedStreamReceiver(unittest.TestCase): def _makeOne(self, cl, buf): @@ -226,6 +228,41 @@ class TestChunkedReceiver(unittest.TestCase): self.assertEqual(inst.error, None) +class TestChunkedReceiverParametrized: + def _makeOne(self, buf): + from waitress.receiver import ChunkedReceiver + + return ChunkedReceiver(buf) + + @pytest.mark.parametrize( + "invalid_extension", [b"\n", b"invalid=", b"\r", b"invalid = true"] + ) + def test_received_invalid_extensions(self, invalid_extension): + from waitress.utilities import BadRequest + + buf = DummyBuffer() + inst = self._makeOne(buf) + data = b"4;" + invalid_extension + b"\r\ntest\r\n" + result = inst.received(data) + assert result == len(data) + assert inst.error.__class__ == BadRequest + assert inst.error.body == "Invalid chunk extension" + + @pytest.mark.parametrize( + "valid_extension", [b"test", b"valid=true", b"valid=true;other=true"] + ) + def test_received_valid_extensions(self, valid_extension): + # While waitress may ignore extensions in Chunked Encoding, we do want + # to make sure that we don't fail when we do encounter one that is + # valid + buf = DummyBuffer() + inst = self._makeOne(buf) + data = b"4;" + valid_extension + b"\r\ntest\r\n" + result = inst.received(data) + assert result == len(data) + assert inst.error == None + + class DummyBuffer: def __init__(self, data=None): if data is None: |