Skip to content

Commit

Permalink
Close a connection if an unexpected exception occurs while sending a …
Browse files Browse the repository at this point in the history
…request (#2828)
  • Loading branch information
brycedrennan authored and asvetlov committed Mar 14, 2018
1 parent c4058a4 commit 1b45e57
Show file tree
Hide file tree
Showing 5 changed files with 50 additions and 4 deletions.
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
.cache
.coverage
.coverage.*
.direnv
.envrc
.idea
.installed.cfg
.noseids
Expand Down Expand Up @@ -47,4 +49,5 @@ virtualenv.py
.gitconfig
.flake
.python-version
.pytest_cache
.pytest_cache
.vscode
1 change: 1 addition & 0 deletions CHANGES/2827.bugfix
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Close a connection if an unexpected exception occurs while sending a request
1 change: 1 addition & 0 deletions CONTRIBUTORS.txt
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ Boyi Chen
Brett Cannon
Brian C. Lane
Brian Muller
Bryce Drennan
Carl George
Cecile Tonglet
Chien-Wei Huang
Expand Down
9 changes: 6 additions & 3 deletions aiohttp/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -326,11 +326,14 @@ async def _request(self, method, url, *,
tcp_nodelay(conn.transport, True)
tcp_cork(conn.transport, False)
try:
resp = req.send(conn)
try:
await resp.start(conn, read_until_eof)
resp = req.send(conn)
try:
await resp.start(conn, read_until_eof)
except BaseException:
resp.close()
raise
except BaseException:
resp.close()
conn.close()
raise
except ClientError:
Expand Down
38 changes: 38 additions & 0 deletions tests/test_client_session.py
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,7 @@ async def create_connection(req, traces=None):
# return self.transport, self.protocol
return mock.Mock()
session._connector._create_connection = create_connection
session._connector._release = mock.Mock()

with pytest.raises(aiohttp.ClientOSError) as ctx:
await session.request('get', 'http://example.com')
Expand All @@ -377,6 +378,43 @@ async def create_connection(req, traces=None):
assert e.strerror == err.strerror


async def test_close_conn_on_error(create_session):
class UnexpectedException(BaseException):
pass

err = UnexpectedException("permission error")
req = mock.Mock()
req_factory = mock.Mock(return_value=req)
req.send = mock.Mock(side_effect=err)
session = create_session(request_class=req_factory)

connections = []
original_connect = session._connector.connect

async def connect(req, traces=None):
conn = await original_connect(req, traces=traces)
connections.append(conn)
return conn

async def create_connection(req, traces=None):
# return self.transport, self.protocol
conn = mock.Mock()
return conn

session._connector.connect = connect
session._connector._create_connection = create_connection
session._connector._release = mock.Mock()

with pytest.raises(UnexpectedException):
async with session.request('get', 'http://example.com') as resp:
await resp.text()

# normally called during garbage collection. triggers an exception
# if the connection wasn't already closed
for c in connections:
c.__del__()


async def test_cookie_jar_usage(loop, aiohttp_client):
req_url = None

Expand Down

0 comments on commit 1b45e57

Please sign in to comment.