From 46213a647ea0d4453b00bca09268f69ffd259509 Mon Sep 17 00:00:00 2001 From: Damien Arrachequesne Date: Mon, 20 Feb 2023 16:52:06 +0100 Subject: [PATCH] fix: prevent duplicate connections when multiplexing This bug was introduced in [1]: a multiplexed socket could in some cases send multiple CONNECT packets, resulting in duplicate connections on the server side. A cached socket will now be reopened only if it was inactive, that is, if one had explicitly called socket.disconnect() before. Related: https://github.com/socketio/socket.io-client/issues/1460 [1]: https://github.com/socketio/socket.io-client/commit/b7dd891e890461d33a104ca9187d5cd30d6f76af --- lib/manager.ts | 4 +--- test/connection.ts | 53 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 3 deletions(-) diff --git a/lib/manager.ts b/lib/manager.ts index 5a705977..fe5c3fa3 100644 --- a/lib/manager.ts +++ b/lib/manager.ts @@ -465,9 +465,7 @@ export class Manager< if (!socket) { socket = new Socket(this, nsp, opts); this.nsps[nsp] = socket; - } - - if (this._autoConnect) { + } else if (this._autoConnect && !socket.active) { socket.connect(); } diff --git a/test/connection.ts b/test/connection.ts index af0215de..1034cb2b 100644 --- a/test/connection.ts +++ b/test/connection.ts @@ -838,4 +838,57 @@ describe("connection", () => { }); }); }); + + it("should not reopen a cached but active socket", () => { + return wrap((done) => { + const manager = new Manager(BASE_URL, { + autoConnect: true, + }); + + let i = 0; + const expected = ["0", "1"]; + + manager.engine.on("packetCreate", ({ data }) => { + expect(data).to.eql(expected[i++]); + }); + + manager.once("open", () => { + const socket = manager.socket("/"); + const socket2 = manager.socket("/"); + + expect(socket2 === socket).to.be(true); + + socket.on("connect", () => { + socket.disconnect(); + done(); + }); + }); + }); + }); + + it("should not reopen an already active socket", () => { + return wrap((done) => { + const manager = new Manager(BASE_URL, { + autoConnect: true, + }); + + let i = 0; + const expected = ["0", "0/foo,", "1", "1/foo,"]; + + manager.engine.on("packetCreate", ({ data }) => { + expect(data).to.eql(expected[i++]); + }); + + manager.once("open", () => { + const socket = manager.socket("/"); + const socketFoo = manager.socket("/foo"); + + socket.on("connect", () => { + socket.disconnect(); + socketFoo.disconnect(); + done(); + }); + }); + }); + }); });