Skip to content

Commit

Permalink
Don't crash when acknowledging a cancelled ping.
Browse files Browse the repository at this point in the history
Fix #1566.
  • Loading branch information
aaugustin committed Jan 3, 2025
1 parent d852df7 commit 197b3ec
Show file tree
Hide file tree
Showing 3 changed files with 25 additions and 3 deletions.
3 changes: 2 additions & 1 deletion src/websockets/asyncio/connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -750,7 +750,8 @@ def acknowledge_pings(self, data: bytes) -> None:
for ping_id, (pong_waiter, ping_timestamp) in self.pong_waiters.items():
ping_ids.append(ping_id)
latency = pong_timestamp - ping_timestamp
pong_waiter.set_result(latency)
if not pong_waiter.done():
pong_waiter.set_result(latency)
if ping_id == data:
self.latency = latency
break
Expand Down
23 changes: 22 additions & 1 deletion tests/asyncio/test_connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -892,6 +892,15 @@ async def test_acknowledge_ping(self):
async with asyncio_timeout(MS):
await pong_waiter

async def test_acknowledge_canceled_ping(self):
"""ping is acknowledged by a pong with the same payload after being canceled."""
async with self.drop_frames_rcvd(): # drop automatic response to ping
pong_waiter = await self.connection.ping("this")
pong_waiter.cancel()
await self.remote_connection.pong("this")
with self.assertRaises(asyncio.CancelledError):
await pong_waiter

async def test_acknowledge_ping_non_matching_pong(self):
"""ping isn't acknowledged by a pong with a different payload."""
async with self.drop_frames_rcvd(): # drop automatic response to ping
Expand All @@ -902,14 +911,26 @@ async def test_acknowledge_ping_non_matching_pong(self):
await pong_waiter

async def test_acknowledge_previous_ping(self):
"""ping is acknowledged by a pong with the same payload as a later ping."""
"""ping is acknowledged by a pong for a later ping."""
async with self.drop_frames_rcvd(): # drop automatic response to ping
pong_waiter = await self.connection.ping("this")
await self.connection.ping("that")
await self.remote_connection.pong("that")
async with asyncio_timeout(MS):
await pong_waiter

async def test_acknowledge_previous_canceled_ping(self):
"""ping is acknowledged by a pong for a later ping after being canceled."""
async with self.drop_frames_rcvd(): # drop automatic response to ping
pong_waiter = await self.connection.ping("this")
pong_waiter_2 = await self.connection.ping("that")
pong_waiter.cancel()
await self.remote_connection.pong("that")
async with asyncio_timeout(MS):
await pong_waiter_2
with self.assertRaises(asyncio.CancelledError):
await pong_waiter

async def test_ping_duplicate_payload(self):
"""ping rejects the same payload until receiving the pong."""
async with self.drop_frames_rcvd(): # drop automatic response to ping
Expand Down
2 changes: 1 addition & 1 deletion tests/sync/test_connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -678,7 +678,7 @@ def test_acknowledge_ping_non_matching_pong(self):
self.assertFalse(pong_waiter.wait(MS))

def test_acknowledge_previous_ping(self):
"""ping is acknowledged by a pong with the same payload as a later ping."""
"""ping is acknowledged by a pong for as a later ping."""
with self.drop_frames_rcvd(): # drop automatic response to ping
pong_waiter = self.connection.ping("this")
self.connection.ping("that")
Expand Down

0 comments on commit 197b3ec

Please sign in to comment.