Skip to content

Commit f223178

Browse files
committedJun 26, 2022
fix: prevent the socket from joining a room after disconnection
Calling `socket.join()` after disconnection would lead to a memory leak, because the room was never removed from the memory: ```js io.on("connection", (socket) => { socket.disconnect(); socket.join("room1"); // leak }); ``` Related: - #4067 - #4380 Backported from 18f3fda
1 parent 226cc16 commit f223178

File tree

3 files changed

+67
-19
lines changed

3 files changed

+67
-19
lines changed
 

‎lib/namespace.js

+24-18
Original file line numberDiff line numberDiff line change
@@ -163,25 +163,31 @@ Namespace.prototype.add = function(client, query, fn){
163163
var self = this;
164164
this.run(socket, function(err){
165165
process.nextTick(function(){
166-
if ('open' == client.conn.readyState) {
167-
if (err) return socket.error(err.data || err.message);
168-
169-
// track socket
170-
self.sockets[socket.id] = socket;
171-
172-
// it's paramount that the internal `onconnect` logic
173-
// fires before user-set events to prevent state order
174-
// violations (such as a disconnection before the connection
175-
// logic is complete)
176-
socket.onconnect();
177-
if (fn) fn();
178-
179-
// fire user-set events
180-
self.emit('connect', socket);
181-
self.emit('connection', socket);
182-
} else {
183-
debug('next called after client was closed - ignoring socket');
166+
if ("open" !== client.conn.readyState) {
167+
debug("next called after client was closed - ignoring socket");
168+
socket._cleanup();
169+
return;
184170
}
171+
172+
if (err) {
173+
debug("middleware error, sending CONNECT_ERROR packet to the client");
174+
socket._cleanup();
175+
return socket.error(err.data || err.message);
176+
}
177+
178+
// track socket
179+
self.sockets[socket.id] = socket;
180+
181+
// it's paramount that the internal `onconnect` logic
182+
// fires before user-set events to prevent state order
183+
// violations (such as a disconnection before the connection
184+
// logic is complete)
185+
socket.onconnect();
186+
if (fn) fn();
187+
188+
// fire user-set events
189+
self.emit('connect', socket);
190+
self.emit('connection', socket);
185191
});
186192
});
187193
return socket;

‎lib/socket.js

+6-1
Original file line numberDiff line numberDiff line change
@@ -447,7 +447,7 @@ Socket.prototype.onclose = function(reason){
447447
if (!this.connected) return this;
448448
debug('closing socket - reason %s', reason);
449449
this.emit('disconnecting', reason);
450-
this.leaveAll();
450+
this._cleanup();
451451
this.nsp.remove(this);
452452
this.client.remove(this);
453453
this.connected = false;
@@ -576,3 +576,8 @@ Socket.prototype.run = function(event, fn){
576576

577577
run(0);
578578
};
579+
580+
Socket.prototype._cleanup = function () {
581+
this.leaveAll();
582+
this.join = function noop() {};
583+
}

‎test/socket.io.js

+37
Original file line numberDiff line numberDiff line change
@@ -1901,6 +1901,43 @@ describe('socket.io', function(){
19011901
});
19021902
});
19031903

1904+
it("should leave all rooms joined after a middleware failure", (done) => {
1905+
const srv = http().listen(0);
1906+
const sio = io(srv);
1907+
const clientSocket = client(srv, "/");
1908+
1909+
sio.use((socket, next) => {
1910+
socket.join("room1");
1911+
next(new Error("nope"));
1912+
});
1913+
1914+
clientSocket.on("error", () => {
1915+
expect(sio.of("/").adapter.rooms).to.eql(0);
1916+
1917+
clientSocket.disconnect();
1918+
sio.close();
1919+
done();
1920+
});
1921+
});
1922+
1923+
it("should not join rooms after disconnection", (done) => {
1924+
const srv = http().listen(0);
1925+
const sio = io(srv);
1926+
const clientSocket = client(srv, "/");
1927+
1928+
sio.on("connection", (socket) => {
1929+
socket.disconnect();
1930+
socket.join("room1");
1931+
});
1932+
1933+
clientSocket.on("disconnect", () => {
1934+
expect(sio.of("/").adapter.rooms).to.eql(0);
1935+
1936+
sio.close();
1937+
done();
1938+
});
1939+
});
1940+
19041941
it('should always trigger the callback (if provided) when joining a room', function(done){
19051942
var srv = http();
19061943
var sio = io(srv);

0 commit comments

Comments
 (0)
Please sign in to comment.