More complex error codes logic for closing WebSocketConnections/WebSocketStreams
tegefaulkes opened this issue · comments
Specification
WebSocket/WebSocketConnection
Similarly to QUIC, when we close a WebSocket
we can provide a code and message. When closing during normal operation we provide a code of 1000
to imply normal closing.
The Node ws
library allows us to provide a type of Buffer or string for the reason
. However, the spec states that it must be a utf-8 encoded string, and the browser WebSocket
class will only accept a string as a valid reason for .close(code, reason)
.
Error Codes
The WebSocket
instance or may not use the predefined IANA defined close codes when closing a connection based on an error of some sort. We will be using these codes in the 1000-1999 space to define our errors.
IANA gives applications the space of 4000 - 4999 for error codes, these will be what we recommend to the user for stopping a WebSocketConnection
.
WebSocketStream
Similarly to QUIC the WebSocketStream spec defined in #2 only has error codes, with all application level errors produced by the user of the API converted with the injected codeToReason
and reasonToCode
functions.
To note is that the ReadableStream and the WritableStream can be closed independently. When calling .error
on a WebStream, a message should be sent to the peer with a shutdown byte that represents whether the ReadableStream
or the WritableStream
of the peer should be given the error
enum StreamShutdown {
Read = 0,
Write = 1,
}
Error Codes
These are the following non-application errors:
const enum StreamErrorCode {
Unknown = 0,
// an error parsing the structure of the message
ErrorReadableStreamParse = 1,
// an error occurring from the buffer of a readablestream going over the maximum size
ErrorReadableStreamBufferOverflow = 2,
}
All non-application errors will not be handled by the injected codeToReason
and reasonToCode
functions.
Additional context
- Related MatrixAI/Polykey#509
- Related MatrixAI/Polykey#506
- Related MatrixAI/Polykey#495
- Related MatrixAI/Polykey#513
- https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/close
- https://www.iana.org/assignments/websocket/websocket.xml
- https://datatracker.ietf.org/doc/html/rfc6455#section-7.1.5
- https://stackoverflow.com/questions/19304157/getting-the-reason-why-websockets-closed-with-close-code-1006
Tasks
- 1. Implement stopping
WebSocketConnection
with error codes and reasons - 2. Implement cancelling
WebSocketStream
on Readable or Writable sides independently
With the idea of having:
WebSocket
WebSocketConnection
WebSocketStream
This means there are 4 layers of errors:
- RPC layer
- Stream layer
- Connection layer
- Socket layer
In the case of the websocket, connection and socket is 1 to 1, so it's possible that there's no separate connection layer error. But it all depends on the user. The user should see a similar structure to how the js-quic works. We want the transport layers to function almost identically. So we encapsulate any of the details to achieve this!