mirror of
https://github.com/python/cpython.git
synced 2025-11-11 19:12:05 +00:00
[3.13] gh-135836: Fix IndexError in asyncio.create_connection with empty exceptions list (GH-135845) (#136168)
gh-135836: Fix `IndexError` in `asyncio.create_connection` with empty exceptions list (GH-135845)
(cherry picked from commit 0e19db653d)
Co-authored-by: heliang666s <147408835+heliang666s@users.noreply.github.com>
Co-authored-by: Kumar Aditya <kumaraditya@python.org>
This commit is contained in:
parent
004f464338
commit
1994d2e5b1
3 changed files with 35 additions and 1 deletions
|
|
@ -1164,7 +1164,7 @@ async def create_connection(
|
||||||
raise ExceptionGroup("create_connection failed", exceptions)
|
raise ExceptionGroup("create_connection failed", exceptions)
|
||||||
if len(exceptions) == 1:
|
if len(exceptions) == 1:
|
||||||
raise exceptions[0]
|
raise exceptions[0]
|
||||||
else:
|
elif exceptions:
|
||||||
# If they all have the same str(), raise one.
|
# If they all have the same str(), raise one.
|
||||||
model = str(exceptions[0])
|
model = str(exceptions[0])
|
||||||
if all(str(exc) == model for exc in exceptions):
|
if all(str(exc) == model for exc in exceptions):
|
||||||
|
|
@ -1173,6 +1173,9 @@ async def create_connection(
|
||||||
# the various error messages.
|
# the various error messages.
|
||||||
raise OSError('Multiple exceptions: {}'.format(
|
raise OSError('Multiple exceptions: {}'.format(
|
||||||
', '.join(str(exc) for exc in exceptions)))
|
', '.join(str(exc) for exc in exceptions)))
|
||||||
|
else:
|
||||||
|
# No exceptions were collected, raise a timeout error
|
||||||
|
raise TimeoutError('create_connection failed')
|
||||||
finally:
|
finally:
|
||||||
exceptions = None
|
exceptions = None
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1190,6 +1190,36 @@ def getaddrinfo(*args, **kw):
|
||||||
self.loop.run_until_complete(coro)
|
self.loop.run_until_complete(coro)
|
||||||
self.assertTrue(sock.close.called)
|
self.assertTrue(sock.close.called)
|
||||||
|
|
||||||
|
@patch_socket
|
||||||
|
def test_create_connection_happy_eyeballs_empty_exceptions(self, m_socket):
|
||||||
|
# See gh-135836: Fix IndexError when Happy Eyeballs algorithm
|
||||||
|
# results in empty exceptions list
|
||||||
|
|
||||||
|
async def getaddrinfo(*args, **kw):
|
||||||
|
return [(socket.AF_INET, socket.SOCK_STREAM, 0, '', ('127.0.0.1', 80)),
|
||||||
|
(socket.AF_INET6, socket.SOCK_STREAM, 0, '', ('::1', 80))]
|
||||||
|
|
||||||
|
def getaddrinfo_task(*args, **kwds):
|
||||||
|
return self.loop.create_task(getaddrinfo(*args, **kwds))
|
||||||
|
|
||||||
|
self.loop.getaddrinfo = getaddrinfo_task
|
||||||
|
|
||||||
|
# Mock staggered_race to return empty exceptions list
|
||||||
|
# This simulates the scenario where Happy Eyeballs algorithm
|
||||||
|
# cancels all attempts but doesn't properly collect exceptions
|
||||||
|
with mock.patch('asyncio.staggered.staggered_race') as mock_staggered:
|
||||||
|
# Return (None, []) - no winner, empty exceptions list
|
||||||
|
async def mock_race(coro_fns, delay, loop):
|
||||||
|
return None, []
|
||||||
|
mock_staggered.side_effect = mock_race
|
||||||
|
|
||||||
|
coro = self.loop.create_connection(
|
||||||
|
MyProto, 'example.com', 80, happy_eyeballs_delay=0.1)
|
||||||
|
|
||||||
|
# Should raise TimeoutError instead of IndexError
|
||||||
|
with self.assertRaisesRegex(TimeoutError, "create_connection failed"):
|
||||||
|
self.loop.run_until_complete(coro)
|
||||||
|
|
||||||
def test_create_connection_host_port_sock(self):
|
def test_create_connection_host_port_sock(self):
|
||||||
coro = self.loop.create_connection(
|
coro = self.loop.create_connection(
|
||||||
MyProto, 'example.com', 80, sock=object())
|
MyProto, 'example.com', 80, sock=object())
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
Fix :exc:`IndexError` in :meth:`asyncio.loop.create_connection` that could occur when the Happy Eyeballs algorithm resulted in an empty exceptions list during connection attempts.
|
||||||
Loading…
Add table
Add a link
Reference in a new issue