Skip to content

Commit

Permalink
When writing a payload from a StreamReader, use readany instead of re…
Browse files Browse the repository at this point in the history
…adline: the lines could be arbitrarily long (#3054)
  • Loading branch information
arthurdarcet authored and asvetlov committed Jun 5, 2018
1 parent e6acb30 commit 5afccb1
Show file tree
Hide file tree
Showing 3 changed files with 28 additions and 2 deletions.
1 change: 1 addition & 0 deletions CHANGES/3054.bugfix
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
When using a server-request body as the `data=` argument of a client request, iterate over the content with `readany` instead of `readline` to avoid `Line too long` errors.
9 changes: 8 additions & 1 deletion aiohttp/payload.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
from . import hdrs
from .helpers import (PY_36, content_disposition_header, guess_filename,
parse_mimetype, sentinel)
from .streams import DEFAULT_LIMIT
from .streams import DEFAULT_LIMIT, StreamReader


__all__ = ('PAYLOAD_REGISTRY', 'get_payload', 'payload_type', 'Payload',
Expand Down Expand Up @@ -325,6 +325,12 @@ async def write(self, writer):
self._iter = None


class StreamReaderPayload(AsyncIterablePayload):

def __init__(self, value, *args, **kwargs):
super().__init__(value.iter_any(), *args, **kwargs)


PAYLOAD_REGISTRY = PayloadRegistry()
PAYLOAD_REGISTRY.register(BytesPayload, (bytes, bytearray, memoryview))
PAYLOAD_REGISTRY.register(StringPayload, str)
Expand All @@ -334,6 +340,7 @@ async def write(self, writer):
PAYLOAD_REGISTRY.register(
BufferedReaderPayload, (io.BufferedReader, io.BufferedRandom))
PAYLOAD_REGISTRY.register(IOBasePayload, io.IOBase)
PAYLOAD_REGISTRY.register(StreamReaderPayload, StreamReader)
# try_last for giving a chance to more specialized async interables like
# multidict.BodyPartReaderPayload override the default
PAYLOAD_REGISTRY.register(AsyncIterablePayload, AsyncIterable,
Expand Down
20 changes: 19 additions & 1 deletion tests/test_payload.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
from io import StringIO
from unittest import mock

import pytest
from async_generator import async_generator

from aiohttp import payload
from aiohttp import payload, streams


@pytest.fixture
Expand Down Expand Up @@ -111,3 +112,20 @@ def test_async_iterable_payload_not_async_iterable():

with pytest.raises(TypeError):
payload.AsyncIterablePayload(object())


async def test_stream_reader_long_lines(loop):
DATA = b'0' * 1024 ** 3

stream = streams.StreamReader(mock.Mock(), loop=loop)
stream.feed_data(DATA)
stream.feed_eof()
body = payload.get_payload(stream)

writer = mock.Mock()
writer.write.return_value = loop.create_future()
writer.write.return_value.set_result(None)
await body.write(writer)
writer.write.assert_called_once_with(mock.ANY)
(chunk,), _ = writer.write.call_args
assert len(chunk) == len(DATA)

0 comments on commit 5afccb1

Please sign in to comment.