Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ServerDisconnectedError if view don't read POST body #3597

Closed
Cykooz opened this issue Feb 6, 2019 · 5 comments
Closed

ServerDisconnectedError if view don't read POST body #3597

Cykooz opened this issue Feb 6, 2019 · 5 comments
Labels

Comments

@Cykooz
Copy link
Member

Cykooz commented Feb 6, 2019

Long story short

If I use ClientSession with persistent connection (keep-alive) and sends two POST-requests with form-data that contains a file represented as io.BytesIO(), and web.Application() don't reads body of request, then second client's request fails with exception ServerDisconnectedError.

Steps to reproduce

Shot example to reproduce the problem:

import asyncio
from io import BytesIO

from aiohttp import FormData, web
from aiohttp.test_utils import TestServer, TestClient


async def view(request):
    return web.Response(body=b'')


async def test_example():
    app = web.Application()
    app.router.add_post('/', view)
    async with TestClient(TestServer(app)) as client:
        for i in range(3):
            print(f'Send request {i + 1}')
            form_data = FormData([('file', BytesIO(b'*'))])
            res = await client.post('/', data=form_data)
            assert res.status == 200
        print('Done')


asyncio.run(test_example())
$ python3.7 example.py
Send request 1
Send request 2
Traceback (most recent call last):
  File "example.py", line 28, in <module>
    asyncio.run(test_example())
  File "/usr/lib/python3.7/asyncio/runners.py", line 43, in run
    return loop.run_until_complete(main)
  File "/usr/lib/python3.7/asyncio/base_events.py", line 573, in run_until_complete
    return future.result()
  File "test_example.py", line 23, in test_example
    res = await client.post('/', data=form_data)
  File "/home/cykooz/buildout-eggs/cp37m/aiohttp-3.5.4-py3.7-linux-x86_64.egg/aiohttp/test_utils.py", line 295, in request
    method, self.make_url(path), **kwargs
  File "/home/cykooz/buildout-eggs/cp37m/aiohttp-3.5.4-py3.7-linux-x86_64.egg/aiohttp/client.py", line 497, in _request
    await resp.start(conn)
  File "/home/cykooz/buildout-eggs/cp37m/aiohttp-3.5.4-py3.7-linux-x86_64.egg/aiohttp/client_reqrep.py", line 844, in start
    message, payload = await self._protocol.read()  # type: ignore  # noqa
  File "/home/cykooz/buildout-eggs/cp37m/aiohttp-3.5.4-py3.7-linux-x86_64.egg/aiohttp/streams.py", line 588, in read
    await self._waiter
aiohttp.client_exceptions.ServerDisconnectedError: None

Your environment

Ubuntu 18.04
Python 3.7.1
aiohttp 3.5.4

@aio-libs-bot
Copy link

GitMate.io thinks the contributor most likely able to help you is @asvetlov.

Possibly related issues are #3087 (request.post() should raise HTTPRequestEntityTooLarge same as request.read()), #2895 (Raise an exception on request body reading after sending response), #2908 (How to use make_mocked_request to make a post request with body?), #394 (ServerDisconnectedError is trigger happy), and #96 (Close connection if response body is not consumed.).

@asvetlov
Copy link
Member

asvetlov commented Feb 6, 2019

Thanks for the report!
Perhaps FormData in the example can be replaced with sending raw data bytes.

@Cykooz
Copy link
Member Author

Cykooz commented Feb 7, 2019

Perhaps FormData in the example can be replaced with sending raw data bytes.

No, the error does not occur if change code to this:

res = await client.post('/', data=BytesIO(b'*'))

or to this

res = await client.post('/', data=b'*')

Also the error does not occur if change code to this:

form_data = FormData([('file', b'*')])
res = await client.post('/', data=form_data)

or to this:

form_data = FormData([('file', BytesIO(b'*'))])
res = await client.post('/', data=form_data, headers={'Connection': 'close'})

@Cykooz
Copy link
Member Author

Cykooz commented Feb 7, 2019

I have found case then error is occur with raw data bytes:

size = 128 * 1024 + 1
res = await client.post('/', data=BytesIO(b'*' * size))
# and without BytesIO too
res = await client.post('/', data=b'*' * size)

@asvetlov
Copy link
Member

Related to #5220

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants