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

-1
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

+10-4
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

+36
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)