From 9b8fb6ee8fd9fdf3a965267e81015639b5a34988 Mon Sep 17 00:00:00 2001 From: Sergey Tikhonov Date: Sun, 31 Jan 2016 12:51:14 +0300 Subject: [PATCH 1/4] allow unread_data to stream at eof state --- aiohttp/streams.py | 2 -- tests/test_streams.py | 5 +++++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/aiohttp/streams.py b/aiohttp/streams.py index d7b998ece73..1cfab77ca84 100644 --- a/aiohttp/streams.py +++ b/aiohttp/streams.py @@ -159,8 +159,6 @@ def wait_eof(self): def unread_data(self, data): """ rollback reading some data from stream, inserting it to buffer head. """ - assert not self._eof, 'unread_data after feed_eof' - if not data: return diff --git a/tests/test_streams.py b/tests/test_streams.py index 8fab257b233..8ff025120bd 100644 --- a/tests/test_streams.py +++ b/tests/test_streams.py @@ -409,6 +409,11 @@ def test_unread_data(self): data = self.loop.run_until_complete(stream.read(4)) self.assertEqual(b'line', data) + stream.feed_eof() + stream.unread_data(b'at_eof') + data = self.loop.run_until_complete(stream.read(6)) + self.assertEqual(b'at_eof', data) + def test_exception(self): stream = self._make_one() self.assertIsNone(stream.exception()) From b622fc2f735a7d2efa2bf8842021f5b44619b7d8 Mon Sep 17 00:00:00 2001 From: Sergey Tikhonov Date: Sun, 31 Jan 2016 12:51:43 +0300 Subject: [PATCH 2/4] fix result cutting for incomplete prev_chunk in multipart --- aiohttp/multipart.py | 2 +- tests/test_multipart.py | 21 +++++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/aiohttp/multipart.py b/aiohttp/multipart.py index e85a5249176..005257761d2 100644 --- a/aiohttp/multipart.py +++ b/aiohttp/multipart.py @@ -318,7 +318,7 @@ def _read_chunk_from_stream(self, size): self._content.unread_data(window[idx:]) if size > idx: self._prev_chunk = self._prev_chunk[:idx] - chunk = window[size:idx] + chunk = window[len(self._prev_chunk):idx] if not chunk: self._at_eof = True result = self._prev_chunk diff --git a/tests/test_multipart.py b/tests/test_multipart.py index 05bda3497c8..f03b996f1ec 100644 --- a/tests/test_multipart.py +++ b/tests/test_multipart.py @@ -168,6 +168,27 @@ def test_read_chunk_without_content_length(self): self.assertEqual(c1 + c2, b'Hello, world!') self.assertEqual(c3, b'') + def test_read_incomplete_chunk(self): + stream = Stream(b'') + def prepare(data): + f = asyncio.Future(loop=self.loop) + f.set_result(data) + return f + with mock.patch.object(stream, 'read', side_effect=[ + prepare(b'Hello, '), + prepare(b'World'), + prepare(b'!\r\n--:'), + prepare(b'') + ]): + obj = aiohttp.multipart.BodyPartReader( + self.boundary, {}, stream) + c1 = yield from obj.read_chunk(8) + self.assertEqual(c1, b'Hello, ') + c2 = yield from obj.read_chunk(8) + self.assertEqual(c2, b'World') + c3 = yield from obj.read_chunk(8) + self.assertEqual(c3, b'!') + def test_multi_read_chunk(self): stream = Stream(b'Hello,\r\n--:\r\n\r\nworld!\r\n--:--') obj = aiohttp.multipart.BodyPartReader(self.boundary, {}, stream) From 960b1485bd205c3d3131c791f26ee4a069185344 Mon Sep 17 00:00:00 2001 From: Sergey Tikhonov Date: Sun, 31 Jan 2016 13:42:46 +0300 Subject: [PATCH 3/4] fix pep8 --- tests/test_multipart.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/test_multipart.py b/tests/test_multipart.py index f03b996f1ec..bd736a261e2 100644 --- a/tests/test_multipart.py +++ b/tests/test_multipart.py @@ -170,10 +170,12 @@ def test_read_chunk_without_content_length(self): def test_read_incomplete_chunk(self): stream = Stream(b'') + def prepare(data): f = asyncio.Future(loop=self.loop) f.set_result(data) return f + with mock.patch.object(stream, 'read', side_effect=[ prepare(b'Hello, '), prepare(b'World'), From 30105790b6de43cd2798b025e4586de9ffdfe275 Mon Sep 17 00:00:00 2001 From: Sergey Tikhonov Date: Sun, 31 Jan 2016 14:22:48 +0300 Subject: [PATCH 4/4] fix first chunk substring search --- aiohttp/multipart.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/aiohttp/multipart.py b/aiohttp/multipart.py index 005257761d2..35f0f8f1164 100644 --- a/aiohttp/multipart.py +++ b/aiohttp/multipart.py @@ -305,14 +305,18 @@ def _read_chunk_from_stream(self, size): """ assert size >= len(self._boundary) + 2, \ 'Chunk size must be greater or equal than boundary length + 2' - if self._prev_chunk is None: + first_chunk = self._prev_chunk is None + if first_chunk: self._prev_chunk = yield from self._content.read(size) chunk = yield from self._content.read(size) window = self._prev_chunk + chunk sub = b'\r\n' + self._boundary - idx = window.find(sub, len(self._prev_chunk) - len(sub)) + if first_chunk: + idx = window.find(sub) + else: + idx = window.find(sub, len(self._prev_chunk) - len(sub)) if idx >= 0: # pushing boundary back to content self._content.unread_data(window[idx:])