diff --git a/aiohttp/payload.py b/aiohttp/payload.py index e21b7bda72d..cab72a2eb84 100644 --- a/aiohttp/payload.py +++ b/aiohttp/payload.py @@ -3,6 +3,7 @@ import json import mimetypes import os +import warnings from abc import ABC, abstractmethod from multidict import CIMultiDict @@ -18,6 +19,7 @@ 'IOBasePayload', 'BytesIOPayload', 'BufferedReaderPayload', 'TextIOPayload', 'StringIOPayload', 'JsonPayload') +TOO_LARGE_BYTES_BODY = 2 ** 20 class LookupError(Exception): pass @@ -150,6 +152,11 @@ def __init__(self, value, *args, **kwargs): self._size = len(value) + if self._size > TOO_LARGE_BYTES_BODY: + warnings.warn("Sending a large body directly with raw bytes might" + " lock the event loop. You should probably pass an " + "io.BytesIO object instead", ResourceWarning) + @asyncio.coroutine def write(self, writer): yield from writer.write(self._value) diff --git a/tests/test_client_functional.py b/tests/test_client_functional.py index 48bcc9a2971..3804a01d3f7 100644 --- a/tests/test_client_functional.py +++ b/tests/test_client_functional.py @@ -1286,6 +1286,46 @@ def handler(request): resp.close() +@asyncio.coroutine +def test_POST_bytes(loop, test_client): + body = b'0' * 12345 + + @asyncio.coroutine + def handler(request): + data = yield from request.read() + assert body == data + return web.HTTPOk() + + app = web.Application() + app.router.add_post('/', handler) + client = yield from test_client(app) + + resp = yield from client.post('/', data=body) + assert 200 == resp.status + resp.close() + + +@asyncio.coroutine +def test_POST_bytes_too_large(loop, test_client): + body = b'0' * 2 ** 17 + + @asyncio.coroutine + def handler(request): + data = yield from request.read() + assert body == data + return web.HTTPOk() + + app = web.Application() + app.router.add_post('/', handler) + client = yield from test_client(app) + + with pytest.warns(ResourceWarning): + resp = yield from client.post('/', data=body) + + assert 200 == resp.status + resp.close() + + @asyncio.coroutine def test_POST_FILES_STR(loop, test_client, fname): @asyncio.coroutine