Closed
Description
@asvetlov looks like the new sock_read timeout implementation is not working, see testcase:
import multiprocessing
import asyncio
import aiohttp
import socket
host = "localhost"
def get_free_tcp_port():
sckt = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sckt.bind((host, 0))
addr, port = sckt.getsockname()
sckt.close()
return port
class AIOServer(multiprocessing.Process):
"""
This is a mock AWS service which will 5 seconds before returning
a response to test socket timeouts.
"""
def __init__(self):
super().__init__(target=self._run)
self._loop = None
self._port = get_free_tcp_port()
self.endpoint_url = 'http://{}:{}'.format(host, self._port)
self.daemon = True # die when parent dies
def _run(self):
asyncio.set_event_loop(asyncio.new_event_loop())
app = aiohttp.web.Application()
app.router.add_route('*', '/ok', self.ok)
app.router.add_route('*', '/{anything:.*}', self.stream_handler)
try:
aiohttp.web.run_app(app, host=host, port=self._port,
handle_signals=False)
except BaseException:
pytest.fail('unable to start and connect to aiohttp server')
raise
async def __aenter__(self):
self.start()
await self._wait_until_up()
return self
async def __aexit__(self, exc_type, exc_val, exc_tb):
try:
self.terminate()
except:
pytest.fail("Unable to shut down server")
raise
async def ok(self, request):
return aiohttp.web.Response()
async def stream_handler(self, request):
# Without the Content-Type, most (all?) browsers will not render
# partially downloaded content. Note, the response type is
# StreamResponse not Response.
resp = aiohttp.web.StreamResponse(status=200, reason='OK',
headers={'Content-Type': 'text/html'})
await resp.prepare(request)
await asyncio.sleep(5, loop=self._loop)
await resp.drain()
return resp
async def _wait_until_up(self):
async with aiohttp.ClientSession() as session:
for i in range(0, 30):
if self.exitcode is not None:
pytest.fail('unable to start and connect to aiohttp server')
return
try:
# we need to bypass the proxies due to monkey patches
await session.get(self.endpoint_url + '/ok', timeout=0.5)
return
except (aiohttp.ClientConnectionError, asyncio.TimeoutError):
await asyncio.sleep(0.5)
except BaseException:
pytest.fail('unable to start and connect to aiohttp server')
raise
pytest.fail('unable to start and connect to aiohttp server')
async def main():
async with AIOServer() as server, \
aiohttp.ClientSession(timeout=aiohttp.ClientTimeout(sock_connect=1, sock_read=1)) as session:
try:
response = await session.get(server.endpoint_url)
await response.read()
except asyncio.TimeoutError:
print("Success")
print("failure")
if __name__ == '__main__':
asyncio.get_event_loop().run_until_complete(main())