Skip to content

Commit ff7190e

Browse files
committed
Ensure mounted transports are closed even if main transport raises
When closing a client with proxy mounts, if the main transport's close/exit raises an exception, the mounted transports would never be cleaned up. This could lead to leaked connections. Wrap the main transport cleanup in try/finally to ensure mounted transports are always properly closed.
1 parent ae1b9f6 commit ff7190e

1 file changed

Lines changed: 24 additions & 16 deletions

File tree

httpx/_client.py

Lines changed: 24 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1267,10 +1267,12 @@ def close(self) -> None:
12671267
if self._state != ClientState.CLOSED:
12681268
self._state = ClientState.CLOSED
12691269

1270-
self._transport.close()
1271-
for transport in self._mounts.values():
1272-
if transport is not None:
1273-
transport.close()
1270+
try:
1271+
self._transport.close()
1272+
finally:
1273+
for transport in self._mounts.values():
1274+
if transport is not None:
1275+
transport.close()
12741276

12751277
def __enter__(self: T) -> T:
12761278
if self._state != ClientState.UNOPENED:
@@ -1298,10 +1300,12 @@ def __exit__(
12981300
) -> None:
12991301
self._state = ClientState.CLOSED
13001302

1301-
self._transport.__exit__(exc_type, exc_value, traceback)
1302-
for transport in self._mounts.values():
1303-
if transport is not None:
1304-
transport.__exit__(exc_type, exc_value, traceback)
1303+
try:
1304+
self._transport.__exit__(exc_type, exc_value, traceback)
1305+
finally:
1306+
for transport in self._mounts.values():
1307+
if transport is not None:
1308+
transport.__exit__(exc_type, exc_value, traceback)
13051309

13061310

13071311
class AsyncClient(BaseClient):
@@ -1982,10 +1986,12 @@ async def aclose(self) -> None:
19821986
if self._state != ClientState.CLOSED:
19831987
self._state = ClientState.CLOSED
19841988

1985-
await self._transport.aclose()
1986-
for proxy in self._mounts.values():
1987-
if proxy is not None:
1988-
await proxy.aclose()
1989+
try:
1990+
await self._transport.aclose()
1991+
finally:
1992+
for proxy in self._mounts.values():
1993+
if proxy is not None:
1994+
await proxy.aclose()
19891995

19901996
async def __aenter__(self: U) -> U:
19911997
if self._state != ClientState.UNOPENED:
@@ -2013,7 +2019,9 @@ async def __aexit__(
20132019
) -> None:
20142020
self._state = ClientState.CLOSED
20152021

2016-
await self._transport.__aexit__(exc_type, exc_value, traceback)
2017-
for proxy in self._mounts.values():
2018-
if proxy is not None:
2019-
await proxy.__aexit__(exc_type, exc_value, traceback)
2022+
try:
2023+
await self._transport.__aexit__(exc_type, exc_value, traceback)
2024+
finally:
2025+
for proxy in self._mounts.values():
2026+
if proxy is not None:
2027+
await proxy.__aexit__(exc_type, exc_value, traceback)

0 commit comments

Comments
 (0)