Skip to content

Commit 779f021

Browse files
bdracopatchback[bot]
authored andcommitted
Revert: Close the socket if there's a failure in start_connection() #10464 (#10656)
Reverts #10464 While this change improved the situation for uvloop users, it caused a regression with `SelectorEventLoop` (issue #10617) The alternative fix is MagicStack/uvloop#646 (not merged at the time of this PR) issue #10617 appears to be very similar to python/cpython@d5aeccf If someone can come up with a working reproducer for #10617 we can revisit this. cc @top-oai Minimal implementation that shows on cancellation the socket is cleaned up without the explicit `close` #10617 (comment) so this should be unneeded unless I've missed something (very possible with all the moving parts here) ## Related issue number fixes #10617 (cherry picked from commit 06db052)
1 parent 7c3c536 commit 779f021

File tree

5 files changed

+6
-65
lines changed

5 files changed

+6
-65
lines changed

CHANGES/10464.bugfix.rst

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
10656.bugfix.rst

CHANGES/10617.bugfix.rst

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
10656.bugfix.rst

CHANGES/10656.bugfix.rst

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Reverted explicitly closing sockets if an exception is raised during ``create_connection`` -- by :user:`bdraco`.
2+
3+
This change originally appeared in aiohttp 3.11.13

aiohttp/connector.py

+1-15
Original file line numberDiff line numberDiff line change
@@ -1126,7 +1126,6 @@ async def _wrap_create_connection(
11261126
client_error: Type[Exception] = ClientConnectorError,
11271127
**kwargs: Any,
11281128
) -> Tuple[asyncio.Transport, ResponseHandler]:
1129-
sock: Union[socket.socket, None] = None
11301129
try:
11311130
async with ceil_timeout(
11321131
timeout.sock_connect, ceil_threshold=timeout.ceil_threshold
@@ -1139,11 +1138,7 @@ async def _wrap_create_connection(
11391138
loop=self._loop,
11401139
socket_factory=self._socket_factory,
11411140
)
1142-
connection = await self._loop.create_connection(
1143-
*args, **kwargs, sock=sock
1144-
)
1145-
sock = None
1146-
return connection
1141+
return await self._loop.create_connection(*args, **kwargs, sock=sock)
11471142
except cert_errors as exc:
11481143
raise ClientConnectorCertificateError(req.connection_key, exc) from exc
11491144
except ssl_errors as exc:
@@ -1152,15 +1147,6 @@ async def _wrap_create_connection(
11521147
if exc.errno is None and isinstance(exc, asyncio.TimeoutError):
11531148
raise
11541149
raise client_error(req.connection_key, exc) from exc
1155-
finally:
1156-
if sock is not None:
1157-
# Will be hit if an exception is thrown before the event loop takes the socket.
1158-
# In that case, proactively close the socket to guard against event loop leaks.
1159-
# For example, see https://github.com/MagicStack/uvloop/issues/653.
1160-
try:
1161-
sock.close()
1162-
except OSError as exc:
1163-
raise client_error(req.connection_key, exc) from exc
11641150

11651151
async def _wrap_existing_connection(
11661152
self,

tests/test_connector.py

-50
Original file line numberDiff line numberDiff line change
@@ -627,56 +627,6 @@ async def certificate_error(*args, **kwargs):
627627
await conn.close()
628628

629629

630-
async def test_tcp_connector_closes_socket_on_error(
631-
loop: asyncio.AbstractEventLoop, start_connection: mock.AsyncMock
632-
) -> None:
633-
req = ClientRequest("GET", URL("https://127.0.0.1:443"), loop=loop)
634-
635-
conn = aiohttp.TCPConnector()
636-
with (
637-
mock.patch.object(
638-
conn._loop,
639-
"create_connection",
640-
autospec=True,
641-
spec_set=True,
642-
side_effect=ValueError,
643-
),
644-
pytest.raises(ValueError),
645-
):
646-
await conn.connect(req, [], ClientTimeout())
647-
648-
assert start_connection.return_value.close.called
649-
650-
await conn.close()
651-
652-
653-
async def test_tcp_connector_closes_socket_on_error_results_in_another_error(
654-
loop: asyncio.AbstractEventLoop, start_connection: mock.AsyncMock
655-
) -> None:
656-
"""Test that when error occurs while closing the socket."""
657-
req = ClientRequest("GET", URL("https://127.0.0.1:443"), loop=loop)
658-
start_connection.return_value.close.side_effect = OSError(
659-
1, "error from closing socket"
660-
)
661-
662-
conn = aiohttp.TCPConnector()
663-
with (
664-
mock.patch.object(
665-
conn._loop,
666-
"create_connection",
667-
autospec=True,
668-
spec_set=True,
669-
side_effect=ValueError,
670-
),
671-
pytest.raises(aiohttp.ClientConnectionError, match="error from closing socket"),
672-
):
673-
await conn.connect(req, [], ClientTimeout())
674-
675-
assert start_connection.return_value.close.called
676-
677-
await conn.close()
678-
679-
680630
async def test_tcp_connector_server_hostname_default(
681631
loop: Any, start_connection: mock.AsyncMock
682632
) -> None:

0 commit comments

Comments
 (0)