socket.io-parser icon indicating copy to clipboard operation
socket.io-parser copied to clipboard

Fix "RangeError: Maximum call stack size exceeded" in hasBinary

Open ayan4m1 opened this issue 4 years ago • 4 comments

Background

serialport 9.2.0
socket.io 4.3.0
import { createServer } from 'socket.io';
import SerialPort from 'serialport';

const serialPort = new SerialPort('/dev/ttyUSB0');
const io = createServer(8080);

serialPort.on('open', () => {
  io.on('connection', (socket) => {
    // this works
    serialPort.on('data', (data) => {
      socket.emit('data', data);
    });
    // but this does not
    serialPort.pipe(socket);
  });
});

When piping a SerialPort instance to a socket.io Socket, the following occurs:

RangeError: Maximum call stack size exceeded
    at hasBinary (/code/project/node_modules/socket.io-parser/dist/is-binary.js:28:19)
    at hasBinary (/code/project/node_modules/socket.io-parser/dist/is-binary.js:49:63)
    at hasBinary (/code/project/node_modules/socket.io-parser/dist/is-binary.js:49:63)

Investigating further, I found this issue which was resolved by patching socket.io-parser like this. I cleaned up and modernized that patch for this repo. All credit to the original authors for their fix.

Changes

  • Use flatted to parse and stringify JSON, allowing circular objects to be handled
  • Prevent infinite recursion in _deconstructPacket
  • Prevent infinite recursion in hasBinary
  • Detect Buffer instances as binary
  • Add type hints to reconstructPacket
  • Update existing test case now that exceptions are not thrown for circular objects
  • Add test case to ensure that circular data is flattened appropriately

I tried to fix the RangeError without adding flatted, but it seems to be necessary as part of this solution. Hopefully the small additional dependency is worth the benefits in terms of preventing infinite recursion.

ayan4m1 avatar Aug 21 '21 18:08 ayan4m1

Hi! Thanks for your work on this.

I'm afraid of the increase of the package size in the browser, but we could release this under another package name (and provide it as a custom parser). What do you think?

darrachequesne avatar Sep 01 '21 06:09 darrachequesne

I seem to be having the issue this is fixing.

MarcGodard avatar Sep 02 '21 03:09 MarcGodard

Hi! Thanks for your work on this.

I'm afraid of the increase of the package size in the browser, but we could release this under another package name (and provide it as a custom parser). What do you think?

flatted is 0.5kb gzipped - it wouldn't be a concern for me, but up to you as to how it's handled.

It could potentially be broken out as two separate changes - handling circular JSON structures (which would be a custom parser) and "fixing the RangeError itself" (which would go into socket.io-parser) but I wasn't able to successfully separate the concerns on my first try.

I'd rather try again to split them up into separate branches than make a custom parser which overrides bits and pieces of the existing one (I can see that being fairly messy) in order to both fix the RangeError and provide circular JSON support.

@darrachequesne Any thoughts?

ayan4m1 avatar Sep 06 '21 03:09 ayan4m1