Compare commits

...

3 Commits
4.3.1 ... 4.3.2

Author SHA1 Message Date
Damien Arrachequesne
ed8483da4d chore(release): 4.3.2
Diff: https://github.com/socketio/socket.io/compare/4.3.1...4.3.2
2021-11-08 06:39:20 +01:00
Sebastiaan Marynissen
9d86397243 fix: fix race condition in dynamic namespaces (#4137)
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: https://github.com/socketio/socket.io/pull/4136
2021-10-24 07:46:29 +02:00
Naseem
44e20ba5bf refactor: add event type for use() (#4138) 2021-10-24 07:19:43 +02:00
15 changed files with 84 additions and 40 deletions

View File

@@ -1,3 +1,11 @@
## [4.3.2](https://github.com/socketio/socket.io/compare/4.3.1...4.3.2) (2021-11-08)
### Bug Fixes
* fix race condition in dynamic namespaces ([#4137](https://github.com/socketio/socket.io/issues/4137)) ([9d86397](https://github.com/socketio/socket.io/commit/9d86397243bcbb5775a29d96e5ef03e17148a8e7))
## [4.3.1](https://github.com/socketio/socket.io/compare/4.3.0...4.3.1) (2021-10-16)

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,5 +1,5 @@
/*!
* Socket.IO v4.3.1
* Socket.IO v4.3.2
* (c) 2014-2021 Guillermo Rauch
* Released under the MIT License.
*/
@@ -4175,10 +4175,6 @@
connect: lookup
});
if (typeof module !== "undefined") {
module.exports = lookup;
}
return lookup;
}));

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -116,7 +116,6 @@ export class Client<
| false
) => {
if (dynamicNspName) {
debug("dynamic namespace %s was created", dynamicNspName);
this.doConnect(name, auth);
} else {
debug("creation of namespace %s was denied", name);

View File

@@ -202,15 +202,18 @@ export class Server<
}
nextFn.value(name, auth, (err, allow) => {
if (err || !allow) {
run();
} else {
const namespace = this.parentNsps
.get(nextFn.value)!
.createChild(name);
// @ts-ignore
this.sockets.emitReserved("new_namespace", namespace);
fn(namespace);
return run();
}
if (this._nsps.has(name)) {
// the namespace was created in the meantime
debug("dynamic namespace %s already exists", name);
return fn(this._nsps.get(name) as Namespace);
}
const namespace = this.parentNsps.get(nextFn.value)!.createChild(name);
debug("dynamic namespace %s was created", name);
// @ts-ignore
this.sockets.emitReserved("new_namespace", namespace);
fn(namespace);
});
};

View File

@@ -108,6 +108,8 @@ export interface Handshake {
auth: { [key: string]: any };
}
type Event = [eventName: string, ...args: any[]];
export class Socket<
ListenEvents extends EventsMap = DefaultEventsMap,
EmitEvents extends EventsMap = ListenEvents,
@@ -130,8 +132,7 @@ export class Socket<
private readonly server: Server<ListenEvents, EmitEvents, ServerSideEvents>;
private readonly adapter: Adapter;
private acks: Map<number, () => void> = new Map();
private fns: Array<(event: Array<any>, next: (err?: Error) => void) => void> =
[];
private fns: Array<(event: Event, next: (err?: Error) => void) => void> = [];
private flags: BroadcastFlags = {};
private _anyListeners?: Array<(...args: any[]) => void>;
@@ -569,7 +570,7 @@ export class Socket<
* @param {Array} event - event that will get emitted
* @private
*/
private dispatch(event: [eventName: string, ...args: any[]]): void {
private dispatch(event: Event): void {
debug("dispatching an event %j", event);
this.run(event, (err) => {
process.nextTick(() => {
@@ -592,9 +593,7 @@ export class Socket<
* @return {Socket} self
* @public
*/
public use(
fn: (event: Array<any>, next: (err?: Error) => void) => void
): this {
public use(fn: (event: Event, next: (err?: Error) => void) => void): this {
this.fns.push(fn);
return this;
}
@@ -606,10 +605,7 @@ export class Socket<
* @param {Function} fn - last fn call in the middleware
* @private
*/
private run(
event: [eventName: string, ...args: any[]],
fn: (err: Error | null) => void
): void {
private run(event: Event, fn: (err: Error | null) => void): void {
const fns = this.fns.slice(0);
if (!fns.length) return fn(null);

8
package-lock.json generated
View File

@@ -1,6 +1,6 @@
{
"name": "socket.io",
"version": "4.3.1",
"version": "4.3.2",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@@ -2451,9 +2451,9 @@
"integrity": "sha512-PBZpxUPYjmoogY0aoaTmo1643JelsaS1CiAwNjRVdrI0X9Seuc19Y2Wife8k88avW6haG8cznvwbubAZwH4Mtg=="
},
"socket.io-client": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.3.1.tgz",
"integrity": "sha512-Few8Zw4Au4dEWAfwAR4QRf8aVmNP22kxHQYtGQqkZwLuDFhX9XgcZoAZJiGXnHNIydcL2r2wgRGMOaEW7Dx6pw==",
"version": "4.3.2",
"resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.3.2.tgz",
"integrity": "sha512-2B9LqSunN60yV8F7S84CCEEcgbYNfrn7ejIInZtLZ7ppWtiX8rGZAjvdCvbnC8bqo/9RlCNOUsORLyskxSFP1g==",
"dev": true,
"requires": {
"@socket.io/component-emitter": "~3.0.0",

View File

@@ -1,6 +1,6 @@
{
"name": "socket.io",
"version": "4.3.1",
"version": "4.3.2",
"description": "node.js realtime framework server",
"keywords": [
"realtime",
@@ -59,7 +59,7 @@
"nyc": "^15.1.0",
"prettier": "^2.3.2",
"rimraf": "^3.0.2",
"socket.io-client": "4.3.1",
"socket.io-client": "4.3.2",
"socket.io-client-v2": "npm:socket.io-client@^2.4.0",
"superagent": "^6.1.0",
"supertest": "^6.1.6",

View File

@@ -15,6 +15,8 @@ import { io as ioc, Socket as ClientSocket } from "socket.io-client";
import "./support/util";
import "./utility-methods";
type callback = (err: Error | null, success: boolean) => void;
// Creates a socket.io client for the given server
function client(srv, nsp?: string | object, opts?: object): ClientSocket {
if ("object" == typeof nsp) {
@@ -998,6 +1000,46 @@ describe("socket.io", () => {
const socket = client(srv, "/dynamic-101");
});
});
it("should handle race conditions with dynamic namespaces (#4136)", (done) => {
const srv = createServer();
const sio = new Server(srv);
const counters = {
connected: 0,
created: 0,
events: 0,
};
const buffer: callback[] = [];
sio.on("new_namespace", (namespace) => {
counters.created++;
});
srv.listen(() => {
const handler = () => {
if (++counters.events === 2) {
expect(counters.created).to.equal(1);
done();
}
};
sio
.of((name, query, next) => {
buffer.push(next);
if (buffer.length === 2) {
buffer.forEach((next) => next(null, true));
}
})
.on("connection", (socket) => {
if (++counters.connected === 2) {
sio.of("/dynamic-101").emit("message");
}
});
let one = client(srv, "/dynamic-101");
let two = client(srv, "/dynamic-101");
one.on("message", handler);
two.on("message", handler);
});
});
});
});