Skip to content

Commit 206be2f

Browse files
authored
remove all pre-existing upgrade listeners (#253)
* remove all pre-existing upgrade listeners Signed-off-by: Matteo Collina <[email protected]> * rewrite Signed-off-by: Matteo Collina <[email protected]> * fixup Signed-off-by: Matteo Collina <[email protected]> * fixup Signed-off-by: Matteo Collina <[email protected]> --------- Signed-off-by: Matteo Collina <[email protected]>
1 parent 1d1f8fa commit 206be2f

File tree

3 files changed

+59
-35
lines changed

3 files changed

+59
-35
lines changed

index.js

Lines changed: 20 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -38,21 +38,19 @@ function fastifyWebsocket (fastify, opts, next) {
3838
const wss = new WebSocket.Server(wssOptions)
3939
fastify.decorate('websocketServer', wss)
4040

41-
websocketListenServer.on('upgrade', (rawRequest, socket, head) => {
41+
function onUpgrade (rawRequest, socket, head) {
4242
// Save a reference to the socket and then dispatch the request through the normal fastify router so that it will invoke hooks and then eventually a route handler that might upgrade the socket.
4343
rawRequest[kWs] = socket
4444
rawRequest[kWsHead] = head
45-
46-
if (closing) {
47-
handleUpgrade(rawRequest, (connection) => {
48-
connection.socket.close(1001)
49-
})
50-
} else {
51-
const rawResponse = new ServerResponse(rawRequest)
45+
const rawResponse = new ServerResponse(rawRequest)
46+
try {
5247
rawResponse.assignSocket(socket)
5348
fastify.routing(rawRequest, rawResponse)
49+
} catch (err) {
50+
fastify.log.warn({ err }, 'websocket upgrade failed')
5451
}
55-
})
52+
}
53+
websocketListenServer.on('upgrade', onUpgrade)
5654

5755
const handleUpgrade = (rawRequest, callback) => {
5856
wss.handleUpgrade(rawRequest, rawRequest[kWs], rawRequest[kWsHead], (socket) => {
@@ -147,24 +145,23 @@ function fastifyWebsocket (fastify, opts, next) {
147145

148146
fastify.addHook('onClose', close)
149147

150-
let closing = false
151-
152148
// Fastify is missing a pre-close event, or the ability to
153149
// add a hook before the server.close call. We need to resort
154150
// to monkeypatching for now.
155-
const oldClose = fastify.server.close
156-
fastify.server.close = function (cb) {
157-
closing = true
158-
159-
// Call oldClose first so that we stop listening. This ensures the
160-
// server.clients list will be up to date when we start closing below.
161-
oldClose.call(this, cb)
151+
fastify.addHook('preClose', function (done) {
152+
const server = this.websocketServer
153+
if (server.clients) {
154+
for (const client of server.clients) {
155+
client.close()
156+
}
157+
}
158+
fastify.server.removeListener('upgrade', onUpgrade)
159+
done()
160+
})
162161

162+
function close (fastify, done) {
163163
const server = fastify.websocketServer
164-
if (!server.clients) return
165-
for (const client of server.clients) {
166-
client.close()
167-
}
164+
server.close(done)
168165
}
169166

170167
function noHandle (connection, rawRequest) {
@@ -185,13 +182,8 @@ function fastifyWebsocket (fastify, opts, next) {
185182
next()
186183
}
187184

188-
function close (fastify, done) {
189-
const server = fastify.websocketServer
190-
server.close(done)
191-
}
192-
193185
module.exports = fp(fastifyWebsocket, {
194-
fastify: '>= 4.0.0',
186+
fastify: '^4.16.0',
195187
name: '@fastify/websocket'
196188
})
197189
module.exports.default = fastifyWebsocket

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
"@sinclair/typebox": "^0.25.10",
3131
"@types/node": "^18.15.0",
3232
"@types/ws": "^8.2.2",
33-
"fastify": "^4.0.0",
33+
"fastify": "^4.16.0",
3434
"split2": "^4.1.0",
3535
"standard": "^17.0.0",
3636
"tap": "^16.0.0",

test/base.test.js

Lines changed: 38 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -398,11 +398,8 @@ test('Should gracefully close when clients attempt to connect after calling clos
398398
fastify.server.close = function (cb) {
399399
const ws = new WebSocket('ws://localhost:' + fastify.server.address().port)
400400

401-
p = once(ws, 'close').then(() => {
402-
t.pass('client 2 closed')
403-
})
404-
405-
ws.on('open', () => {
401+
p = once(ws, 'close').catch((err) => {
402+
t.equal(err.message, 'Unexpected server response: 503')
406403
oldClose.call(this, cb)
407404
})
408405
}
@@ -411,7 +408,7 @@ test('Should gracefully close when clients attempt to connect after calling clos
411408

412409
fastify.get('/', { websocket: true }, (connection) => {
413410
t.pass('received client connection')
414-
t.teardown(() => connection.destroy())
411+
connection.destroy()
415412
// this connection stays alive until we close the server
416413
})
417414

@@ -586,3 +583,38 @@ test('Should Handle WebSocket errors to avoid Node.js crashes', async t => {
586583

587584
await fastify.close()
588585
})
586+
587+
test('remove all others websocket handlers on close', async (t) => {
588+
const fastify = Fastify()
589+
590+
await fastify.register(fastifyWebsocket)
591+
592+
await fastify.listen({ port: 0 })
593+
594+
await fastify.close()
595+
596+
t.equal(fastify.server.listeners('upgrade').length, 0)
597+
})
598+
599+
test('clashing upgrade handler', async (t) => {
600+
const fastify = Fastify()
601+
t.teardown(() => fastify.close())
602+
603+
fastify.server.on('upgrade', (req, socket, head) => {
604+
const res = new http.ServerResponse(req)
605+
res.assignSocket(socket)
606+
res.end()
607+
socket.destroy()
608+
})
609+
610+
await fastify.register(fastifyWebsocket)
611+
612+
fastify.get('/', { websocket: true }, (connection) => {
613+
t.fail('this should never be invoked')
614+
})
615+
616+
await fastify.listen({ port: 0 })
617+
618+
const ws = new WebSocket('ws://localhost:' + fastify.server.address().port)
619+
await once(ws, 'error')
620+
})

0 commit comments

Comments
 (0)