Skip to content

terminate twisted websocket connections over TLS after the close handshake - #55

Merged
bentsku merged 1 commit into
mainfrom
twisted-websocket-tls-close
Oct 7, 2026
Merged

bentsku merged 1 commit into
mainfrom
twisted-websocket-tls-close

Conversation

@bentsku

@bentsku bentsku commented Oct 7, 2026 •

Copy link
Copy Markdown
Collaborator

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 Python websockets client) on each disconnect. Plain ws:// 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() called loseConnection() 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 through HTTPChannel.loseConnection(), which unregisters the channel as producer first. The channel is taken from the request before Request.finish(), which detaches it.

Testing

  • New 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 on main with a read timeout and passes with the change.
  • The full suite passes (196 tests) and lint is clean.
  • With the change applied in LocalStack, wss:// disconnects complete immediately instead of after the client's close timeout
    🤖 Generated with Claude Code

…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
bentsku force-pushed the twisted-websocket-tls-close branch from 47674bc to e4e39b7 Compare October 7, 2026 10:26
@bentsku
bentsku merged commit 4934513 into main Oct 7, 2026
5 checks passed
@bentsku
bentsku deleted the twisted-websocket-tls-close branch October 7, 2026 10:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant