Skip to content

Commit

Permalink
fix(fastify-websocket): Handle server emitted errors
Browse files Browse the repository at this point in the history
  • Loading branch information
enisdenjo committed Oct 27, 2021
1 parent cb16588 commit 3fa17a7
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 5 deletions.
6 changes: 2 additions & 4 deletions src/__tests__/use.ts
Original file line number Diff line number Diff line change
Expand Up @@ -355,8 +355,7 @@ for (const { tServer, itForWS, skipUWS, startTServer } of tServers) {
});

// uWebSocket.js cannot have errors emitted on the server instance
// TODO-db-211027 fastify-websocket
itForWS(
skipUWS(
'should report server emitted errors to clients by closing the connection',
async () => {
const { url, server } = await startTServer();
Expand All @@ -376,8 +375,7 @@ for (const { tServer, itForWS, skipUWS, startTServer } of tServers) {
);

// uWebSocket.js cannot have errors emitted on the server instance
// TODO-db-211027 fastify-websocket
itForWS('should limit the server emitted error message size', async () => {
skipUWS('should limit the server emitted error message size', async () => {
const { url, server, waitForClient } = await startTServer();

const client = await createTClient(url);
Expand Down
38 changes: 37 additions & 1 deletion src/use/fastify-websocket.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,45 @@ export function makeHandler<
const isProd = process.env.NODE_ENV === 'production';
const server = makeServer(options);

return (connection, request) => {
// we dont have access to the fastify-websocket server instance yet,
// register an error handler on first connection ONCE only
let handlingServerEmittedErrors = false;

return function handler(connection, request) {
const { socket } = connection;

// handle server emitted errors only if not already handling
if (!handlingServerEmittedErrors) {
handlingServerEmittedErrors = true;
this.websocketServer.once('error', (err) => {
console.error(
'Internal error emitted on the WebSocket server. ' +
'Please check your implementation.',
err,
);

// catch the first thrown error and re-throw it once all clients have been notified
let firstErr: Error | null = null;

// report server errors by erroring out all clients with the same error
for (const client of this.websocketServer.clients) {
try {
client.close(
CloseCode.InternalServerError,
// close reason should fit in one frame https://datatracker.ietf.org/doc/html/rfc6455#section-5.2
isProd || err.message.length > 123
? 'Internal server error'
: err.message,
);
} catch (err) {
firstErr = firstErr ?? err;
}
}

if (firstErr) throw firstErr;
});
}

// used as listener on two streams, prevent superfluous calls on close
let emittedErrorHandled = false;
function handleEmittedError(err: Error) {
Expand Down

0 comments on commit 3fa17a7

Please sign in to comment.