Skip to content

Commit 05e1278

Browse files
fix: fix race condition in dynamic namespaces
Using an async operation with `io.use()` could lead to the creation of several instances of a same namespace, each of them overriding the previous one. Example: ```js io.use(async (nsp, auth, next) => { await anOperationThatTakesSomeTime(); next(); }); ``` Related: #4136 Backported from 9d86397
1 parent 22d4bdf commit 05e1278

File tree

3 files changed

+46
-5
lines changed

3 files changed

+46
-5
lines changed

lib/client.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,6 @@ Client.prototype.connect = function(name, query){
6868

6969
this.server.checkNamespace(name, query, (dynamicNsp) => {
7070
if (dynamicNsp) {
71-
debug('dynamic namespace %s was created', dynamicNsp.name);
7271
this.doConnect(name, query);
7372
} else {
7473
debug('creation of namespace %s was denied', name);

lib/index.js

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -182,11 +182,17 @@ Server.prototype.checkNamespace = function(name, query, fn){
182182
return fn(false);
183183
}
184184
nextFn.value(name, query, (err, allow) => {
185-
if (err || !allow) {
186-
run();
187-
} else {
188-
fn(this.parentNsps.get(nextFn.value).createChild(name));
185+
if (err || !allow) {
186+
return run();
189187
}
188+
if (this.nsps[name]) {
189+
// the namespace was created in the meantime
190+
debug("dynamic namespace %s already exists", name);
191+
return fn(this.nsps[name]);
192+
}
193+
const namespace = this.parentNsps.get(nextFn.value).createChild(name);
194+
debug("dynamic namespace %s was created", name);
195+
fn(namespace);
190196
});
191197
};
192198

test/socket.io.js

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -945,6 +945,42 @@ describe('socket.io', function(){
945945
});
946946
});
947947
});
948+
949+
it("should handle race conditions with dynamic namespaces (#4136)", (done) => {
950+
const srv = http();
951+
const sio = io(srv);
952+
const counters = {
953+
connected: 0,
954+
created: 0,
955+
events: 0,
956+
};
957+
const buffer = [];
958+
srv.listen(() => {
959+
const handler = () => {
960+
if (++counters.events === 2) {
961+
done();
962+
}
963+
};
964+
965+
sio
966+
.of((name, query, next) => {
967+
buffer.push(next);
968+
if (buffer.length === 2) {
969+
buffer.forEach((next) => next(null, true));
970+
}
971+
})
972+
.on("connection", (socket) => {
973+
if (++counters.connected === 2) {
974+
sio.of("/dynamic-101").emit("message");
975+
}
976+
});
977+
978+
let one = client(srv, "/dynamic-101");
979+
let two = client(srv, "/dynamic-101");
980+
one.on("message", handler);
981+
two.on("message", handler);
982+
});
983+
});
948984
});
949985
});
950986

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy