diff --git a/cyclone/tests/test_web.py b/cyclone/tests/test_web.py index 6f994079d6..2b701de477 100644 --- a/cyclone/tests/test_web.py +++ b/cyclone/tests/test_web.py @@ -16,6 +16,7 @@ from twisted.trial import unittest from cyclone.web import RequestHandler, HTTPError from cyclone.web import Application, URLSpec, URLReverseError +from cyclone.web import ChunkedTransferEncoding from cyclone.escape import unicode_type from unittest.mock import Mock from datetime import datetime @@ -409,6 +410,43 @@ def test_deferred_arg_in_render(self): page = yield self._execute_request(False) self.assertEqual(page, b"simple: it works!") + @defer.inlineCallbacks + def test_chunked_transfer_encoding(self): + """ + Test that a response using chunked transfer encoding with multiple + chunks is correctly formed. + """ + def get(): + response_bytes = b"abcdefg\x00\xff" + chunk_size = 4 + for i in range(0, len(response_bytes), chunk_size): + response_chunk = response_bytes[i : (i + chunk_size)] + self.handler.write(response_chunk) + self.handler.flush() + + self.request.supports_http_1_1.return_value = True + self.handler.get = get + body = yield self._execute_request(False) + + expected_body = ( + # Chunk 1/3 + b"4\r\n" # 4 bytes in the chunk + b"abcd" # chunk contents + b"\r\n" + # Chunk 2/3 + b"4\r\n" # 4 bytes in the chunk + b"efg\x00" # chunk contents + b"\r\n" + # Chunk 3/3 + b"1\r\n" # 1 byte in the chunk + b"\xff" # chunk contents + b"\r\n" + # End message + b"0" + b"\r\n\r\n" + ) + self.assertEqual(body, expected_body) + def setUp(self): self.app = app = Mock() app.ui_methods = {} @@ -424,7 +462,7 @@ def setUp(self): request.method = "GET" request.version = "HTTP MOCK" request.notifyFinish.return_value = defer.Deferred() - request.supports_http_1_1.return_value = True + request.supports_http_1_1.return_value = False self.handler = RequestHandler(app, request) self._onFinishD = defer.Deferred() @@ -454,7 +492,8 @@ def _execute_request(self, outputHeaders): handler = self.handler handler._headers_written = True - handler._execute([]) + transforms = [ChunkedTransferEncoding(self.request)] + handler._execute(transforms) yield self._onFinishD out = b"" for (args, kwargs) in self.request.write.call_args_list: diff --git a/cyclone/web.py b/cyclone/web.py index c2e7b9a17f..58c4f83c8d 100644 --- a/cyclone/web.py +++ b/cyclone/web.py @@ -1921,9 +1921,9 @@ def transform_chunk(self, block, finishing): # Don't write out empty chunks because that means END-OF-STREAM # with chunked encoding if block: - block = "%s\r\n%s\r\n" % (utf8("%x" % len(block)), block) + block = b"%s\r\n%s\r\n" % (b"%x" % len(block), block) if finishing: - block = "%s0\r\n\r\n" % block + block = b"%s0\r\n\r\n" % block return block