Skip to content

Commit

Permalink
fix(server): Receiving more than one ConnectionInit message closes …
Browse files Browse the repository at this point in the history
…the socket immediately
  • Loading branch information
enisdenjo committed Sep 16, 2020
1 parent edc1d38 commit 757c6e9
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 0 deletions.
2 changes: 2 additions & 0 deletions PROTOCOL.md
Expand Up @@ -40,6 +40,8 @@ The client can specify additional `connectionParams` which are sent through the

The server must receive the connection initialisation message within the allowed waiting time specified in the `connectionInitWaitTimeout` parameter during the server setup. If the client does not request a connection within the allowed timeout, the server will terminate the socket with the close event: `4408: Connection initialisation timeout`.

If the server receives more than one `ConnectionInit` message at any given time, the server will terminate the socket with the close event `4429: Too many initialisation requests`.

```typescript
interface ConnectionInitMessage {
type: 'connection_init';
Expand Down
3 changes: 3 additions & 0 deletions src/server.ts
Expand Up @@ -357,6 +357,9 @@ export function createServer(
const message = parseMessage(event.data);
switch (message.type) {
case MessageType.ConnectionInit: {
if (ctx.connectionInitReceived) {
return ctx.socket.close(4429, 'Too many initialisation requests');
}
ctx.connectionInitReceived = true;

if (isObject(message.payload)) {
Expand Down
70 changes: 70 additions & 0 deletions src/tests/server.ts
Expand Up @@ -295,6 +295,76 @@ describe('Connect', () => {

expect(closeFn).not.toBeCalled();
});

it('should close the socket if an additional `ConnectionInit` message is received while one is pending', async () => {
expect.assertions(3);

await makeServer({
connectionInitWaitTimeout: 10,
onConnect: () =>
new Promise((resolve) => setTimeout(() => resolve(true), 50)),
});

const client = new WebSocket(url, GRAPHQL_TRANSPORT_WS_PROTOCOL);
client.onclose = (event) => {
expect(event.code).toBe(4429);
expect(event.reason).toBe('Too many initialisation requests');
expect(event.wasClean).toBeTruthy();
};
client.onopen = () => {
client.send(
stringifyMessage<MessageType.ConnectionInit>({
type: MessageType.ConnectionInit,
}),
);

// issue an additional one a bit later
setTimeout(() => {
client.send(
stringifyMessage<MessageType.ConnectionInit>({
type: MessageType.ConnectionInit,
}),
);
}, 10);
};

await wait(30);
});

it('should close the socket if more than one `ConnectionInit` message is received at any given time', async () => {
expect.assertions(4);

await makeServer();

const client = new WebSocket(url, GRAPHQL_TRANSPORT_WS_PROTOCOL);
client.onclose = (event) => {
expect(event.code).toBe(4429);
expect(event.reason).toBe('Too many initialisation requests');
expect(event.wasClean).toBeTruthy();
};
client.onmessage = ({ data }) => {
const message = parseMessage(data);
expect(message.type).toBe(MessageType.ConnectionAck);
};
client.onopen = () => {
client.send(
stringifyMessage<MessageType.ConnectionInit>({
type: MessageType.ConnectionInit,
}),
);
};

await wait(10);

// random connection init message even after acknowledgement
client.send(
stringifyMessage<MessageType.ConnectionInit>({
type: MessageType.ConnectionInit,
}),
);

await wait(10);
});
});

describe('Subscribe', () => {
Expand Down

0 comments on commit 757c6e9

Please sign in to comment.