Repository navigation
terminate twisted websocket connections over TLS after the close handshake - #55
Merged
Merged
Conversation
…shake The HTTP channel is registered as producer of its transport, and a TLS transport defers its shutdown until no producer is registered, so calling loseConnection on the TLS transport directly never closed the connection and clients waited for their close timeout. Lose the connection through the HTTP channel, which unregisters itself first. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
bentsku
force-pushed
the
twisted-websocket-tls-close
branch
from
October 7, 2026 10:26
47674bc to
e4e39b7
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Motivation
Over TLS, the twisted server never terminated a websocket connection after the closing handshake. The close frames were exchanged, but the TCP connection stayed open until the client gave up, so every
wss://client waited for its full close timeout (e.g. 10s with the Pythonwebsocketsclient) on each disconnect. Plainws://connections were not affected.The HTTP channel registers itself as producer of its transport when the connection is made, and
TLSMemoryBIOProtocol.loseConnection()defers the TLS shutdown until no producer is registered.WebSocketChannel.close()calledloseConnection()on the TLS transport directly, so the producer was never unregistered and the shutdown never happened. TCP transports don't wait for producers, which is why only TLS connections hung.Changes
WebSocketChannel.close()terminates the connection throughHTTPChannel.loseConnection(), which unregisters the channel as producer first. The channel is taken from the request beforeRequest.finish(), which detaches it.Testing
test_websocket_tls_close_handshake_client_initiated: the client sends a close frame over TLS, and must receive the echoed close frame and then EOF. It fails onmainwith a read timeout and passes with the change.wss://disconnects complete immediately instead of after the client's close timeout🤖 Generated with Claude Code