Skip to content

Commit ca1ae33

Browse files
authored
Websocket: unhandle rejection (#6418)
* Websocket: unhandle rejection Closes: #6413, #6173 Prevent crashing on websocket error. Bonus points to anybody who can post a specific payload that the client sends that returns an error. * log the socket * fix tests * fix payload reference link
1 parent 84b0878 commit ca1ae33

File tree

3 files changed

+48
-6
lines changed

3 files changed

+48
-6
lines changed

spec/ParseLiveQuery.spec.js

+37
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,43 @@ describe('ParseLiveQuery', function() {
2424
await object.save();
2525
});
2626

27+
it('handle invalid websocket payload length', async done => {
28+
await reconfigureServer({
29+
liveQuery: {
30+
classNames: ['TestObject'],
31+
},
32+
startLiveQueryServer: true,
33+
verbose: false,
34+
silent: true,
35+
websocketTimeout: 100,
36+
});
37+
const object = new TestObject();
38+
await object.save();
39+
40+
const query = new Parse.Query(TestObject);
41+
query.equalTo('objectId', object.id);
42+
const subscription = await query.subscribe();
43+
44+
// All control frames must have a payload length of 125 bytes or less.
45+
// https://tools.ietf.org/html/rfc6455#section-5.5
46+
//
47+
// 0x89 = 10001001 = ping
48+
// 0xfe = 11111110 = first bit is masking the remaining 7 are 1111110 or 126 the payload length
49+
// https://tools.ietf.org/html/rfc6455#section-5.2
50+
const client = await Parse.CoreManager.getLiveQueryController().getDefaultLiveQueryClient();
51+
client.socket._socket.write(Buffer.from([0x89, 0xfe]));
52+
53+
subscription.on('update', async object => {
54+
expect(object.get('foo')).toBe('bar');
55+
done();
56+
});
57+
// Wait for Websocket timeout to reconnect
58+
setTimeout(async () => {
59+
object.set({ foo: 'bar' });
60+
await object.save();
61+
}, 1000);
62+
});
63+
2764
afterEach(async function(done) {
2865
const client = await Parse.CoreManager.getLiveQueryController().getDefaultLiveQueryClient();
2966
client.close();

spec/ParseWebSocketServer.spec.js

+7-6
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
const {
22
ParseWebSocketServer,
33
} = require('../lib/LiveQuery/ParseWebSocketServer');
4+
const EventEmitter = require('events');
45

56
describe('ParseWebSocketServer', function() {
67
beforeEach(function(done) {
78
// Mock ws server
8-
const EventEmitter = require('events');
9+
910
const mockServer = function() {
1011
return new EventEmitter();
1112
};
@@ -22,11 +23,11 @@ describe('ParseWebSocketServer', function() {
2223
onConnectCallback,
2324
{ websocketTimeout: 5 }
2425
).server;
25-
const ws = {
26-
readyState: 0,
27-
OPEN: 0,
28-
ping: jasmine.createSpy('ping'),
29-
};
26+
const ws = new EventEmitter();
27+
ws.readyState = 0;
28+
ws.OPEN = 0;
29+
ws.ping = jasmine.createSpy('ping');
30+
3031
parseWebSocketServer.onConnection(ws);
3132

3233
// Make sure callback is called

src/LiveQuery/ParseWebSocketServer.js

+4
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ export class ParseWebSocketServer {
1313
logger.info('Parse LiveQuery Server starts running');
1414
};
1515
wss.onConnection = ws => {
16+
ws.on('error', error => {
17+
logger.error(error.message);
18+
logger.error(JSON.stringify(ws));
19+
});
1620
onConnect(new ParseWebSocket(ws));
1721
// Send ping to client periodically
1822
const pingIntervalId = setInterval(() => {

0 commit comments

Comments
 (0)