diff --git a/spec/ParseLiveQuery.spec.js b/spec/ParseLiveQuery.spec.js index 74faa9aedc..fa83588b9d 100644 --- a/spec/ParseLiveQuery.spec.js +++ b/spec/ParseLiveQuery.spec.js @@ -24,6 +24,43 @@ describe('ParseLiveQuery', function() { await object.save(); }); + it('handle invalid websocket payload length', async done => { + await reconfigureServer({ + liveQuery: { + classNames: ['TestObject'], + }, + startLiveQueryServer: true, + verbose: false, + silent: true, + websocketTimeout: 100, + }); + const object = new TestObject(); + await object.save(); + + const query = new Parse.Query(TestObject); + query.equalTo('objectId', object.id); + const subscription = await query.subscribe(); + + // All control frames must have a payload length of 125 bytes or less. + // https://tools.ietf.org/html/rfc6455#section-5.5 + // + // 0x89 = 10001001 = ping + // 0xfe = 11111110 = first bit is masking the remaining 7 are 1111110 or 126 the payload length + // https://tools.ietf.org/html/rfc6455#section-5.2 + const client = await Parse.CoreManager.getLiveQueryController().getDefaultLiveQueryClient(); + client.socket._socket.write(Buffer.from([0x89, 0xfe])); + + subscription.on('update', async object => { + expect(object.get('foo')).toBe('bar'); + done(); + }); + // Wait for Websocket timeout to reconnect + setTimeout(async () => { + object.set({ foo: 'bar' }); + await object.save(); + }, 1000); + }); + afterEach(async function(done) { const client = await Parse.CoreManager.getLiveQueryController().getDefaultLiveQueryClient(); client.close(); diff --git a/spec/ParseWebSocketServer.spec.js b/spec/ParseWebSocketServer.spec.js index c9416f4c08..7bf8a5c57d 100644 --- a/spec/ParseWebSocketServer.spec.js +++ b/spec/ParseWebSocketServer.spec.js @@ -1,11 +1,12 @@ const { ParseWebSocketServer, } = require('../lib/LiveQuery/ParseWebSocketServer'); +const EventEmitter = require('events'); describe('ParseWebSocketServer', function() { beforeEach(function(done) { // Mock ws server - const EventEmitter = require('events'); + const mockServer = function() { return new EventEmitter(); }; @@ -22,11 +23,11 @@ describe('ParseWebSocketServer', function() { onConnectCallback, { websocketTimeout: 5 } ).server; - const ws = { - readyState: 0, - OPEN: 0, - ping: jasmine.createSpy('ping'), - }; + const ws = new EventEmitter(); + ws.readyState = 0; + ws.OPEN = 0; + ws.ping = jasmine.createSpy('ping'); + parseWebSocketServer.onConnection(ws); // Make sure callback is called diff --git a/src/LiveQuery/ParseWebSocketServer.js b/src/LiveQuery/ParseWebSocketServer.js index 9e0d18d2a1..606056fc2e 100644 --- a/src/LiveQuery/ParseWebSocketServer.js +++ b/src/LiveQuery/ParseWebSocketServer.js @@ -13,6 +13,10 @@ export class ParseWebSocketServer { logger.info('Parse LiveQuery Server starts running'); }; wss.onConnection = ws => { + ws.on('error', error => { + logger.error(error.message); + logger.error(JSON.stringify(ws)); + }); onConnect(new ParseWebSocket(ws)); // Send ping to client periodically const pingIntervalId = setInterval(() => {