Skip to content

Commit

Permalink
[3.5] handle ConnectionResetError, closes #3648 (#3699). (#3734)
Browse files Browse the repository at this point in the history
(cherry picked from commit 7846174)

Co-authored-by: Gustavo J. A. M. Carneiro <[email protected]>
  • Loading branch information
asvetlov and Gustavo J. A. M. Carneiro authored May 8, 2019
1 parent c9a1086 commit 167fe9f
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 2 deletions.
2 changes: 2 additions & 0 deletions CHANGES/3648.bugfix
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Properly handle ConnectionResetError, to silence the "Cannot write to closing
transport" exception when clients disconnect uncleanly.
18 changes: 16 additions & 2 deletions aiohttp/web_protocol.py
Original file line number Diff line number Diff line change
Expand Up @@ -444,8 +444,22 @@ async def start(self) -> None:
raise RuntimeError("Web-handler should return "
"a response instance, "
"got {!r}".format(resp))
await resp.prepare(request)
await resp.write_eof()
try:
prepare_meth = resp.prepare
except AttributeError:
if resp is None:
raise RuntimeError("Missing return "
"statement on request handler")
else:
raise RuntimeError("Web-handler should return "
"a response instance, "
"got {!r}".format(resp))
try:
await prepare_meth(request)
await resp.write_eof()
except ConnectionResetError:
self.log_debug('Ignored premature client disconnection 2')
break

# notify server about keep-alive
self._keepalive = bool(resp.keep_alive)
Expand Down
27 changes: 27 additions & 0 deletions tests/test_web_protocol.py
Original file line number Diff line number Diff line change
Expand Up @@ -858,3 +858,30 @@ async def test_two_data_received_without_waking_up_start_task(srv) -> None:
assert len(srv._messages) == 2
assert srv._waiter.done()
await asyncio.sleep(0.01)


async def test_client_disconnect(aiohttp_server) -> None:

async def handler(request):
await request.content.read(10)
return web.Response()

logger = mock.Mock()
app = web.Application()
app._debug = True
app.router.add_route('POST', '/', handler)
server = await aiohttp_server(app, logger=logger)

_, writer = await asyncio.open_connection('127.0.0.1', server.port)
writer.write("""POST / HTTP/1.1\r
Connection: keep-alive\r
Content-Length: 10\r
Host: localhost:{port}\r
\r
""".format(port=server.port).encode("ascii"))
await writer.drain()
await asyncio.sleep(0.1)
writer.write(b"x")
writer.close()
await asyncio.sleep(0.1)
logger.debug.assert_called_with('Ignored premature client disconnection 2')

0 comments on commit 167fe9f

Please sign in to comment.