-
-
Notifications
You must be signed in to change notification settings - Fork 663
Description
Bug Description
After a WebSocket connection is established, the error
event is not dispatched on network failures; only the close
event is emitted.
Reproducible By
const { WebSocketServer } = require('ws')
const { setGlobalDispatcher, Agent, WebSocket } = require('undici')
let socket
// extract the underlying socket, so we can destroy it later
setGlobalDispatcher(new (class foo extends Agent {
dispatch(opts, handler) {
return super.dispatch(opts, {
...handler,
onUpgrade(statusCode, headers, _socket) {
socket = _socket
return handler.onUpgrade(statusCode, headers, _socket)
}
})
}
})())
const server = new WebSocketServer({ port: 0 })
const ws = new WebSocket(`ws://localhost:${server.address().port}`)
ws.onopen = () => {
console.log('open')
setTimeout(() => {
console.log('destroying socket')
socket.destroy(new Error('foo'))
}, 1000)
}
ws.onerror = () => console.log('error')
ws.onclose = e => console.log('close', e.code)
Expected Behavior
According to WHATWG WebSockets Standard section 4. Feedback from the protocol:
When the WebSocket connection is closed, possibly cleanly, the user agent must queue a task to run the following substeps:
- Change the ready state to CLOSED (3).
- If the user agent was required to fail the WebSocket connection, or if the WebSocket connection was closed after being flagged as full, fire an event named error at the WebSocket object. [WSP]
- Fire an event named close at the WebSocket object, [...]
Note the 2. If the user agent was required to fail the WebSocket connection, [...], fire an event named error
.
According to RFC 6455 section 7.1.7. Client-Initiated Closure:
If at any point the underlying transport layer connection is unexpectedly lost, the client MUST _Fail the WebSocket Connection_.
A net.Socket
is destroyed with an ErrnoException
when the network connection is lost. Therefore, the WebSocket client should fail the connection and dispatch an error
event.
Logs & Screenshots
Running the reproduction:
$ node index.js
open
destroying socket
close 1006
^ Notice that no error
message is logged.
I tried this in Firefox: connected to the remote WebSocket and then brought the network interface down. In that case, the error
listener was called after the connection was lost.
