From b1d0a7fd87de9abeb9726928a14aa59a9e29bb63 Mon Sep 17 00:00:00 2001 From: Matteo Collina Date: Sun, 8 Jan 2023 15:54:01 +0000 Subject: [PATCH] Catch errors on websocket connections (#940) * Catch errors on websocket connections Signed-off-by: Matteo Collina * fixup Signed-off-by: Matteo Collina Signed-off-by: Matteo Collina --- lib/subscription-connection.js | 8 +++++++- test/subscription.js | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/lib/subscription-connection.js b/lib/subscription-connection.js index 6911cef1..93fb864c 100644 --- a/lib/subscription-connection.js +++ b/lib/subscription-connection.js @@ -37,7 +37,11 @@ module.exports = class SubscriptionConnection { this.protocolMessageTypes = getProtocolByName(socket.protocol) this.socket.on('error', this.handleConnectionClose.bind(this)) - this.handleConnection() + + // We need a catch here because the socket might be closed before the connection is established + // and we don't want to crash the server. Note that the errors are already + // logged elsewhere @fastify/websocket so there is no need to log them again. + this.handleConnection().catch(noop) } async handleConnection () { @@ -301,3 +305,5 @@ module.exports = class SubscriptionConnection { this.handleConnectionClose() } } + +function noop () {} diff --git a/test/subscription.js b/test/subscription.js index 6d5064a4..8c420c67 100644 --- a/test/subscription.js +++ b/test/subscription.js @@ -5,6 +5,7 @@ const mq = require('mqemitter') const { EventEmitter } = require('events') const fastifyWebsocket = require('@fastify/websocket') const GQL = require('..') +const { once } = require('events') const FakeTimers = require('@sinonjs/fake-timers') @@ -2049,3 +2050,34 @@ test('subscription passes context to its loaders', t => { }) }) }) + +test('wrong messages do not crash the server', async (t) => { + const schema = ` + type Query { + add(x: Int, y: Int): Int + } + ` + + const resolvers = { + Query: { + add: async (_, { x, y }) => x + y + } + } + + const fastify = Fastify() + fastify.register(GQL, { + schema, + resolvers, + subscription: true + }) + + await fastify.listen({ port: 0 }) + + t.teardown(fastify.close.bind(fastify)) + + const ws = new WebSocket(`ws://127.0.0.1:${fastify.server.address().port}/graphql`, 'graphql-ws') + + await once(ws, 'open') + ws._socket.write(Buffer.from([0xa2, 0x00])) + await once(ws, 'close') +})