Skip to content

fix(parser): honor toJSON() when deconstructing a binary packet#5518

Open
spokodev wants to merge 1 commit into
socketio:mainfrom
spokodev:w32/socketio-tojson
Open

fix(parser): honor toJSON() when deconstructing a binary packet#5518
spokodev wants to merge 1 commit into
socketio:mainfrom
spokodev:w32/socketio-tojson

Conversation

@spokodev

@spokodev spokodev commented Jul 2, 2026

Copy link
Copy Markdown

Description

socket.io-parser gives a binary packet a different shape depending on whether it contains binary, because deconstructPacket does not honor toJSON().

hasBinary() (which decides whether a packet takes the binary-encoding path) follows an object's toJSON(). But _deconstructPacket() walked the original object instead of its toJSON() output. So for a class instance whose toJSON() returns the data to send:

  • the wire used the object's own (often private) property names instead of the toJSON() keys, and
  • binary nested inside the toJSON() result was never extracted as an attachment (a Buffer returned directly by toJSON() was corrupted into {"0":..,"1":..}).

The same object is therefore delivered with a different structure depending only on whether it carries binary.

Reproduction

Emitting a model instance (Mongoose document, ORM entity, DTO) that exposes toJSON() and holds a file or avatar buffer, a common pattern:

class Doc {
  #buf = Buffer.from("abc");
  toJSON() { return { file: this.#buf }; }
}
socket.emit("save", new Doc());
// received as { internal: <Buffer> } (private field name) instead of { file: <Buffer> }

Fix

Apply toJSON() in _deconstructPacket() with the same one-shot recursion guard that hasBinary() and JSON.stringify use, so both the binary-detection and the deconstruction paths walk an identical tree. The pre-existing Date guard is preserved, so Date serialization is unchanged.

Test

Added a case to packages/socket.io-parser/test/buffer.js for a Buffer nested behind a toJSON(). It fails before the change (private key leaks, attachment shape wrong) and passes after. Full parser suite stays green (34 passing).

hasBinary() follows an object's toJSON() method, so a packet whose
toJSON() returns binary is encoded as a binary packet. However
deconstructPacket() did not call toJSON(), so it walked the original
object instead of its serialized form: binary nested in the toJSON()
result was not extracted as an attachment and the emitted shape did not
match the toJSON() output (as it does for non-binary packets via
JSON.stringify).

Apply toJSON() in _deconstructPacket() as hasBinary() and JSON.stringify
already do, so the two encoding paths stay consistent.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant