summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBert JW Regeer <bertjw@regeer.org>2019-12-12 20:01:41 -0800
committerBert JW Regeer <bertjw@regeer.org>2019-12-19 15:59:58 +0100
commit60f92b822538230f279efcfb9561dd2c2524d696 (patch)
treee65f24486503218c7d255af4f98264d294e2d7b6
parent8ecd8dc4be000a0e1be2212dc35ea6a418a8523e (diff)
downloadwaitress-60f92b822538230f279efcfb9561dd2c2524d696.tar.gz
Allow end of chunk parser to be resumeable
-rw-r--r--waitress/receiver.py26
-rw-r--r--waitress/tests/test_receiver.py27
2 files changed, 44 insertions, 9 deletions
diff --git a/waitress/receiver.py b/waitress/receiver.py
index 693c7d5..5d1568d 100644
--- a/waitress/receiver.py
+++ b/waitress/receiver.py
@@ -64,6 +64,7 @@ class ChunkedReceiver(object):
chunk_remainder = 0
validate_chunk_end = False
control_line = b""
+ chunk_end = b""
all_chunks_received = False
trailer = b""
completed = False
@@ -100,17 +101,24 @@ class ChunkedReceiver(object):
if self.chunk_remainder == 0:
self.validate_chunk_end = True
elif self.validate_chunk_end:
+ s = self.chunk_end + s
+
pos = s.find(b"\r\n")
- if pos == 0:
- # Chop off the terminating CR LF from the chunk
- s = s[2:]
+ if pos < 0 and len(s) < 2:
+ self.chunk_end = s
+ s = b""
else:
- self.error = BadRequest("Chunk not properly terminated")
- self.all_chunks_received = True
-
- # Always exit this loop
- self.validate_chunk_end = False
+ self.chunk_end = b""
+ if pos == 0:
+ # Chop off the terminating CR LF from the chunk
+ s = s[2:]
+ else:
+ self.error = BadRequest("Chunk not properly terminated")
+ self.all_chunks_received = True
+
+ # Always exit this loop
+ self.validate_chunk_end = False
elif not self.all_chunks_received:
# Receive a control line.
s = self.control_line + s
@@ -119,7 +127,7 @@ class ChunkedReceiver(object):
if pos < 0:
# Control line not finished.
self.control_line = s
- s = ""
+ s = b""
else:
# Control line finished.
line = s[:pos]
diff --git a/waitress/tests/test_receiver.py b/waitress/tests/test_receiver.py
index 92b66ad..b4910bb 100644
--- a/waitress/tests/test_receiver.py
+++ b/waitress/tests/test_receiver.py
@@ -198,6 +198,33 @@ class TestChunkedReceiver(unittest.TestCase):
self.assertEqual(b"".join(buf.data), b"Wikipedia in\r\n\r\nchunks.")
self.assertEqual(inst.error, None)
+ def test_received_multiple_chunks_split(self):
+ from waitress.utilities import BadRequest
+
+ buf = DummyBuffer()
+ inst = self._makeOne(buf)
+ data1 = b"4\r\nWiki\r"
+ result = inst.received(data1)
+ self.assertEqual(result, len(data1))
+
+ data2 = (
+ b"\n5\r\n"
+ b"pedia\r\n"
+ b"E\r\n"
+ b" in\r\n"
+ b"\r\n"
+ b"chunks.\r\n"
+ b"0\r\n"
+ b"\r\n"
+ )
+
+ result = inst.received(data2)
+ self.assertEqual(result, len(data2))
+
+ self.assertEqual(inst.completed, True)
+ self.assertEqual(b"".join(buf.data), b"Wikipedia in\r\n\r\nchunks.")
+ self.assertEqual(inst.error, None)
+
class DummyBuffer(object):
def __init__(self, data=None):