diff --git a/src/rpc.js b/src/rpc.js index cd2d9e8b..459668a5 100644 --- a/src/rpc.js +++ b/src/rpc.js @@ -112,14 +112,23 @@ class RPC { * @param {Object} event - The event describing the message. */ onMessage(event) { - const data = JSON.parse(event.data); - const resolver = this.resolvers[data.id] || {}; - this.emit('traffic', 'received', data, resolver.handle); - if (typeof data.id !== 'undefined' && this.resolvers[data.id]) { - this.emit('message', data); - this.resolvers[data.id].resolveWith(data); - } else { - this.emit(data.params ? 'notification' : 'message', data); + try { + const data = JSON.parse(event.data); + const resolver = this.resolvers[data.id] || {}; + this.emit('traffic', 'received', data, resolver.handle); + if (typeof data.id !== 'undefined' && this.resolvers[data.id]) { + this.emit('message', data); + this.resolvers[data.id].resolveWith(data); + } else { + this.emit(data.params ? 'notification' : 'message', data); + } + } catch (error) { + this.emit('socket-error', { + type: 'parse-error', + message: 'Failed to parse WebSocket message', + error, + rawData: event.data, + }); } } diff --git a/test/unit/rpc.spec.js b/test/unit/rpc.spec.js index 427bb291..8b37e658 100644 --- a/test/unit/rpc.spec.js +++ b/test/unit/rpc.spec.js @@ -194,4 +194,36 @@ describe('RPC', () => { expect(errArg.code).to.be.equal(-1); expect(errArg.message).to.be.equal('Socket error'); }); + + it('should emit socket-error with parse-error type when receiving malformed JSON', (done) => { + const malformedJson = '{"invalid": "json with \x00 control character"}'; + + rpc.once('socket-error', (error) => { + expect(error.type).to.equal('parse-error'); + expect(error.message).to.equal('Failed to parse WebSocket message'); + expect(error.error).to.be.instanceOf(SyntaxError); + expect(error.rawData).to.equal(malformedJson); + done(); + }); + + rpc.open().then(() => { + rpc.socket.message({ data: malformedJson }); + }); + rpc.socket.open(); + }); + + it('should not throw when receiving malformed JSON', (done) => { + const malformedJson = 'not valid json at all'; + + rpc.once('socket-error', () => { + // If we reach here without throwing, the test passes + done(); + }); + + rpc.open().then(() => { + // This should not throw an uncaught exception + expect(() => rpc.socket.message({ data: malformedJson })).to.not.throw(); + }); + rpc.socket.open(); + }); });