Skip to content

Commit

Permalink
fix: do not modify the input packet upon encoding
Browse files Browse the repository at this point in the history
Note: this issue has existed since Socket.IO v1.0 (see [1]), because
the `deconstructPacket()` method also mutates its input argument.

This also explains why some adapters (like [2]) need to use
`process.nextTick()` when extending the `broadcast()` method, because
`Adapter.broadcast()` calls `Encoder.encode()` ([3]).

Related:

- socketio/socket.io#4374
- socketio/socket.io-mongo-adapter#10

[1]: 299849b
[2]: https://github.com/socketio/socket.io-postgres-adapter/blob/0.3.0/lib/index.ts#L587-L590
[3]: https://github.com/socketio/socket.io-adapter/blob/2.4.0/lib/index.ts#L148
  • Loading branch information
darrachequesne committed Jan 19, 2023
1 parent 9143aa4 commit ae8dd88
Show file tree
Hide file tree
Showing 4 changed files with 29 additions and 13 deletions.
2 changes: 1 addition & 1 deletion lib/binary.ts
Expand Up @@ -53,7 +53,7 @@ function _deconstructPacket(data, buffers) {

export function reconstructPacket(packet, buffers) {
packet.data = _reconstructPacket(packet.data, buffers);
packet.attachments = undefined; // no longer useful
delete packet.attachments; // no longer useful
return packet;
}

Expand Down
21 changes: 12 additions & 9 deletions lib/index.ts
Expand Up @@ -53,11 +53,15 @@ export class Encoder {

if (obj.type === PacketType.EVENT || obj.type === PacketType.ACK) {
if (hasBinary(obj)) {
obj.type =
obj.type === PacketType.EVENT
? PacketType.BINARY_EVENT
: PacketType.BINARY_ACK;
return this.encodeAsBinary(obj);
return this.encodeAsBinary({
type:
obj.type === PacketType.EVENT
? PacketType.BINARY_EVENT
: PacketType.BINARY_ACK,
nsp: obj.nsp,
data: obj.data,
id: obj.id,
});
}
}
return [this.encodeAsString(obj)];
Expand Down Expand Up @@ -149,10 +153,9 @@ export class Decoder extends Emitter<{}, {}, DecoderReservedEvents> {
throw new Error("got plaintext data when reconstructing a packet");
}
packet = this.decodeString(obj);
if (
packet.type === PacketType.BINARY_EVENT ||
packet.type === PacketType.BINARY_ACK
) {
const isBinaryEvent = packet.type === PacketType.BINARY_EVENT;
if (isBinaryEvent || packet.type === PacketType.BINARY_ACK) {
packet.type = isBinaryEvent ? PacketType.EVENT : PacketType.ACK;
// binary packet's json
this.reconstructor = new BinaryReconstructor(packet);

Expand Down
16 changes: 16 additions & 0 deletions test/arraybuffer.js
Expand Up @@ -89,4 +89,20 @@ describe("ArrayBuffer", () => {
decoder.destroy(); // destroy before all data added
expect(decoder.reconstructor.buffers.length).to.be(0); // expect that buffer is clean
});

it("should not modify the input packet", () => {
const packet = {
type: PacketType.EVENT,
nsp: "/",
data: ["a", Uint8Array.of(1, 2, 3), Uint8Array.of(4, 5, 6)],
};

encoder.encode(packet);

expect(packet).to.eql({
type: PacketType.EVENT,
nsp: "/",
data: ["a", Uint8Array.of(1, 2, 3), Uint8Array.of(4, 5, 6)],
});
});
});
3 changes: 0 additions & 3 deletions test/helpers.js
Expand Up @@ -20,13 +20,10 @@ module.exports.test = (obj) => {
// tests encoding of binary packets
module.exports.test_bin = (obj) => {
return new Promise((resolve) => {
const originalData = obj.data;
const encodedPackets = encoder.encode(obj);

const decoder = new parser.Decoder();
decoder.on("decoded", (packet) => {
obj.data = originalData;
obj.attachments = undefined;
expect(obj).to.eql(packet);
resolve();
});
Expand Down

0 comments on commit ae8dd88

Please sign in to comment.