-
-
Notifications
You must be signed in to change notification settings - Fork 2.5k
Description
Extracted from #1892
Right now, when WS sees an error, it emits an error event, stops emitting data, and immediately destroys the socket (here). The destroy results in a close event firing, using the close code from the error that was thrown.
As far as I can tell, this isn't totally illegal, but it's not the correct behaviour.
Section 7 in the websocket RFC covers a bunch of definitions about how websockets should be cleanly or unhappily closed. From my reading, it says that when you want to fail an established websocket connection due to an error:
- You should first send a close frame to the remote peer (see 7.1.7)
- You should ignore any more incoming data, including remote close frames (see 7.1.7).
- If the local peer is a server then it should half-close (SHUT_WR in TCP speak,
socket.end()in node) the TCP connection, but not close it completely (notsocket.destroy()it) until all incoming data has been read (see 7.1.1). - If the local peer is a client then it shouldn't shutdown the connection at all, and instead it should wait for the server to send a close frame and initiate TCP shutdown before it half-closes the socket itself (i.e. it should wait for an 'end' event, then call
.end()itself), unless a timeout has passed which suggests the server isn't going to shut the socket (see 7.1.1). - When the connection is fully closed, it should be considered to be closed with close code 1006. The connection should only be considered to be closed with other error close codes if the peer received that error code (see 7.1.5).
This is designed to make sure that all peers know why a connection closed, and to make sure the underlying TCP connection is closed cleanly wherever possible.
Hard closing connections is allowed, but only if strictly required (e.g. if the server is under attack) or if there's good reason to believe the remote client can't handle normal shutdown (e.g. the TCP connection itself is broken already).
The main practical differences I see are that right now when there's an error, WS:
- doesn't send a close code to the remote peer.
- always completely destroys the socket immediately.
- fires a 'close' event using the sent status code, not 1006.
I think I'm translating between the TCP-based descriptions in the spec and the node world correctly here, but it would be good to check that - it might be that node handles some of this for us under the hood.