From 0464a54eee09dfdf66d65bf539a4d8f596be2697 Mon Sep 17 00:00:00 2001 From: Benjie Gillam Date: Wed, 4 Nov 2020 20:01:30 +0000 Subject: [PATCH] fix(server): Close socket if `onSubscribe` returns invalid array (#53) * fix: throw useful error if onSubscribe returns invalid array * refactor: misconfiguration is serious * test: close socket Co-authored-by: enisdenjo --- src/server.ts | 4 ++++ src/tests/server.ts | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/src/server.ts b/src/server.ts index feb668f6..8994a49f 100644 --- a/src/server.ts +++ b/src/server.ts @@ -552,6 +552,10 @@ export function createServer( if (maybeExecArgsOrErrors) { if (areGraphQLErrors(maybeExecArgsOrErrors)) { return await emit.error(maybeExecArgsOrErrors); + } else if (Array.isArray(maybeExecArgsOrErrors)) { + throw new Error( + 'Invalid return value from onSubscribe hook, expected an array of GraphQLError objects', + ); } // not errors, is exec args execArgs = maybeExecArgsOrErrors; diff --git a/src/tests/server.ts b/src/tests/server.ts index c3ccfc65..06b77ee4 100644 --- a/src/tests/server.ts +++ b/src/tests/server.ts @@ -941,6 +941,44 @@ describe('Subscribe', () => { }, 30); }); + it('should close the socket on empty arrays returned from `onSubscribe`', async () => { + const { url } = await startTServer({ + onSubscribe: () => { + return []; + }, + }); + + const client = await createTClient(url); + + client.ws.send( + stringifyMessage({ + type: MessageType.ConnectionInit, + }), + ); + + await client.waitForMessage(({ data }) => { + expect(parseMessage(data).type).toBe(MessageType.ConnectionAck); + }); + + client.ws.send( + stringifyMessage({ + id: '1', + type: MessageType.Subscribe, + payload: { + query: 'subscription { ping }', + }, + }), + ); + + await client.waitForClose((event) => { + expect(event.code).toBe(4400); + expect(event.reason).toBe( + 'Invalid return value from onSubscribe hook, expected an array of GraphQLError objects', + ); + expect(event.wasClean).toBeTruthy(); + }); + }); + it('should use the execution result returned from `onNext`', async () => { const { url } = await startTServer({ onNext: (_ctx, _message) => {