Repository navigation
shutdown after peer WebSocket close can raise before connection_lost #3242
Unanswered
sunxiuguo
asked this question in
Potential Issue
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
A downstream report prompted this investigation: itda-work/django-wireview#226 . I am not the downstream reporter. This is an AI-assisted, independently rerun controlled protocol-level reproduction, not a real-socket integration test.
On Uvicorn main
9d81c12a2c411d3bf104368472b708a3218d9b4e, a client completes the handshake and sends a normal close frame. Before the transport's deferredconnection_lostcallback, calling the protocol'sshutdown()raises:WebSocketsSansIOProtocol:InvalidState: connection is closingWSProtocol:LocalProtocolError: Event CloseConnection(code=1012, reason=None) cannot be sent in state ConnectionState.CLOSED.Both corresponding open-connection controls shut down without exceptions. The close frames are produced by the real websockets client codec and passed through production
data_received; the synthetic transport controls the callback gap.close_sentremains false although peer-close handling has already advanced the codec and requested transport closure.Expected: shutdown during this already-closing interval should be safe. I have not run
Server.shutdown()or demonstrated how often real sockets hit this interval. Its unguarded connection-shutdown loop suggests a possible interruption of later cleanup, but that impact is only static inference here. The reproduction's finally block manually cleans up; it is not evidence of successful production cleanup.Environment: Linux, Python 3.12.14; click 8.5.0, h11 0.16.0, websockets 17.1, wsproto 1.3.2. From the source checkout with those dependencies installed:
PYTHONPATH="$PWD" python ../reproduce.pyWould maintainers consider this an upstream issue and welcome a focused regression test/fix? Adjacent merged #3053 and #3138 concern server-initiated close and handshake denial respectively; open #3163's inspected diff does not change these shutdown/close handlers. Please point me to an existing discussion if this is already tracked.
Complete synthetic reproduction
Observed output
[ { "protocol": "WebSocketsSansIOProtocol", "peer_close": false, "before": { "protocol_close_sent": false, "transport_closing": false, "codec_state": "1" }, "exception": null, "app_events": [ { "type": "websocket.connect" }, { "type": "websocket.disconnect", "code": 1012 } ] }, { "protocol": "WebSocketsSansIOProtocol", "peer_close": true, "before": { "protocol_close_sent": false, "transport_closing": true, "codec_state": "2" }, "exception": { "type": "InvalidState", "message": "connection is closing" }, "app_events": [ { "type": "websocket.connect" }, { "type": "websocket.disconnect", "code": 1000, "reason": "" } ] }, { "protocol": "WSProtocol", "peer_close": false, "before": { "protocol_close_sent": false, "transport_closing": false, "codec_state": "ConnectionState.OPEN" }, "exception": null, "app_events": [ { "type": "websocket.connect" }, { "type": "websocket.disconnect", "code": 1012 } ] }, { "protocol": "WSProtocol", "peer_close": true, "before": { "protocol_close_sent": false, "transport_closing": true, "codec_state": "ConnectionState.CLOSED" }, "exception": { "type": "LocalProtocolError", "message": "Event CloseConnection(code=1012, reason=None) cannot be sent in state ConnectionState.CLOSED." }, "app_events": [ { "type": "websocket.connect" }, { "type": "websocket.disconnect", "code": 1000, "reason": "" } ] } ]All reactions