Skip to content

Commit 613f3f0

Browse files
committedJan 19, 2025
Prevent close() from blocking when reading is paused.
Closing the transport normally is achieved with transport.write_eof(). Closing it in abnormal situations relied on transport.close(). However, that didn't lead to connection_lost() when reading is paused. Replacing it with transport.abort() ensures that buffers are dropped (which is what we want in abnormal situations) and connection_lost() called quickly. Fix #1555 (for real!)
1 parent e7a098e commit 613f3f0

File tree

5 files changed

+10
-17
lines changed

5 files changed

+10
-17
lines changed
 

‎docs/project/changelog.rst

+3-2
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,9 @@ Bug fixes
4444
:mod:`threading` implementation. If a message is already received, it is
4545
returned. Previously, :exc:`TimeoutError` was raised incorrectly.
4646

47-
* Prevented :meth:`~sync.connection.Connection.close` from blocking when
48-
receive buffers are saturated in the :mod:`threading` implementation.
47+
* Prevented :meth:`~asyncio.connection.Connection.close` from blocking when
48+
receive buffers are saturated in the :mod:`asyncio` and :mod:`threading`
49+
implementations.
4950

5051
.. _14.1:
5152

‎src/websockets/asyncio/client.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -445,7 +445,7 @@ async def __await_impl__(self) -> ClientConnection:
445445
try:
446446
await self.connection.handshake(*self.handshake_args)
447447
except asyncio.CancelledError:
448-
self.connection.close_transport()
448+
self.connection.transport.abort()
449449
raise
450450
except Exception as exc:
451451
# Always close the connection even though keep-alive is
@@ -454,7 +454,7 @@ async def __await_impl__(self) -> ClientConnection:
454454
# protocol. In the current design of connect(), there is
455455
# no easy way to reuse the network connection that works
456456
# in every case nor to reinitialize the protocol.
457-
self.connection.close_transport()
457+
self.connection.transport.abort()
458458

459459
uri_or_exc = self.process_redirect(exc)
460460
# Response is a valid redirect; follow it.

‎src/websockets/asyncio/connection.py

+1-9
Original file line numberDiff line numberDiff line change
@@ -928,7 +928,7 @@ async def send_context(
928928
# If an error occurred, close the transport to terminate the connection and
929929
# raise an exception.
930930
if raise_close_exc:
931-
self.close_transport()
931+
self.transport.abort()
932932
# Wait for the protocol state to be CLOSED before accessing close_exc.
933933
await asyncio.shield(self.connection_lost_waiter)
934934
raise self.protocol.close_exc from original_exc
@@ -969,14 +969,6 @@ def set_recv_exc(self, exc: BaseException | None) -> None:
969969
if self.recv_exc is None:
970970
self.recv_exc = exc
971971

972-
def close_transport(self) -> None:
973-
"""
974-
Close transport and message assembler.
975-
976-
"""
977-
self.transport.close()
978-
self.recv_messages.close()
979-
980972
# asyncio.Protocol methods
981973

982974
# Connection callbacks

‎src/websockets/asyncio/server.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -356,16 +356,16 @@ async def conn_handler(self, connection: ServerConnection) -> None:
356356
self.server_header,
357357
)
358358
except asyncio.CancelledError:
359-
connection.close_transport()
359+
connection.transport.abort()
360360
raise
361361
except Exception:
362362
connection.logger.error("opening handshake failed", exc_info=True)
363-
connection.close_transport()
363+
connection.transport.abort()
364364
return
365365

366366
if connection.protocol.state is not OPEN:
367367
# process_request or process_response rejected the handshake.
368-
connection.close_transport()
368+
connection.transport.abort()
369369
return
370370

371371
try:

‎tests/asyncio/test_client.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -393,7 +393,7 @@ async def test_connection_closed_during_handshake(self):
393393
"""Client reads EOF before receiving handshake response from server."""
394394

395395
def close_connection(self, request):
396-
self.close_transport()
396+
self.transport.close()
397397

398398
async with serve(*args, process_request=close_connection) as server:
399399
with self.assertRaises(InvalidMessage) as raised:

0 commit comments

Comments
 (0)