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

[3.6] Reset the sock_read timeout when data arrives (#4142) #4143

Merged
merged 1 commit into from
Oct 7, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGES/3808.bugfix
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Reset the ``sock_read`` timeout each time data is received for a ``aiohttp.client`` response.
1 change: 1 addition & 0 deletions CONTRIBUTORS.txt
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ Manuel Miranda
Marat Sharafutdinov
Marco Paolini
Mariano Anaya
Martijn Pieters
Martin Melka
Martin Richard
Mathias Fröjdman
Expand Down
2 changes: 2 additions & 0 deletions aiohttp/client_proto.py
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,8 @@ def _on_read_timeout(self) -> None:
self._payload.set_exception(exc)

def data_received(self, data: bytes) -> None:
self._reschedule_timeout()

if not data:
return

Expand Down
50 changes: 50 additions & 0 deletions tests/test_client_functional.py
Original file line number Diff line number Diff line change
Expand Up @@ -598,6 +598,56 @@ async def handler(request):
await client.get('/')


async def test_read_timeout_between_chunks(aiohttp_client, mocker) -> None:
mocker.patch('aiohttp.helpers.ceil').side_effect = ceil

async def handler(request):
resp = aiohttp.web.StreamResponse()
await resp.prepare(request)
# write data 4 times, with pauses. Total time 0.4 seconds.
for _ in range(4):
await asyncio.sleep(0.1)
await resp.write(b'data\n')
return resp

app = web.Application()
app.add_routes([web.get('/', handler)])

# A timeout of 0.2 seconds should apply per read.
timeout = aiohttp.ClientTimeout(sock_read=0.2)
client = await aiohttp_client(app, timeout=timeout)

res = b''
async with await client.get('/') as resp:
res += await resp.read()

assert res == b'data\n' * 4


async def test_read_timeout_on_reading_chunks(aiohttp_client, mocker) -> None:
mocker.patch('aiohttp.helpers.ceil').side_effect = ceil

async def handler(request):
resp = aiohttp.web.StreamResponse()
await resp.prepare(request)
await resp.write(b'data\n')
await asyncio.sleep(1)
await resp.write(b'data\n')
return resp

app = web.Application()
app.add_routes([web.get('/', handler)])

# A timeout of 0.2 seconds should apply per read.
timeout = aiohttp.ClientTimeout(sock_read=0.2)
client = await aiohttp_client(app, timeout=timeout)

async with await client.get('/') as resp:
assert (await resp.content.read(5)) == b'data\n'
with pytest.raises(asyncio.TimeoutError):
await resp.content.read()


async def test_timeout_on_reading_data(aiohttp_client, mocker) -> None:
loop = asyncio.get_event_loop()

Expand Down