Skip to content

Commit

Permalink
feat: remove the implicit connection to the default namespace
Browse files Browse the repository at this point in the history
In previous versions, a client was always connected to the default
namespace, even if it requested access to another namespace.

This meant that the middlewares registered for the default namespace
were triggered in any case, which is a surprising behavior for end
users.

This also meant that the query option of the Socket on the client-side
was not sent in the Socket.IO CONNECT packet for the default namespace:

```js
// default namespace: query sent in the query params
const socket = io({
  query: {
    abc: "def"
  }
});

// another namespace: query sent in the query params + the CONNECT packet
const socket = io("/admin", {
  query: {
    abc: "def"
  }
});
```

The client will now send a CONNECT packet in any case, and the query
option of the Socket is renamed to "auth", in order to make a clear
distinction with the query option of the Manager (included in the query
parameters of the HTTP requests).

```js
// server-side
io.use((socket, next) => {
  // not triggered anymore
});

io.of("/admin").use((socket, next => {
  // triggered
  console.log(socket.handshake.query.abc); // "def"
  console.log(socket.handshake.auth.abc); // "123"
});

// client-side
const socket = io("/admin", {
  query: {
    abc: "def"
  },
  auth: {
    abc: "123"
  }
});
```
  • Loading branch information
darrachequesne committed Oct 13, 2020
1 parent 7a51c76 commit 3289f7e
Show file tree
Hide file tree
Showing 13 changed files with 85 additions and 196 deletions.
11 changes: 5 additions & 6 deletions dist/client.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ export declare class Client {
private readonly decoder;
private sockets;
private nsps;
private connectBuffer;
/**
* Client constructor.
*
Expand All @@ -31,16 +30,16 @@ export declare class Client {
/**
* Connects a client to a namespace.
*
* @param {String} name namespace
* @param {Object} query the query parameters
* @param {String} name - the namespace
* @param {Object} auth - the auth parameters
* @package
*/
connect(name: any, query?: {}): void;
connect(name: string, auth?: object): void;
/**
* Connects a client to a namespace.
*
* @param {String} name namespace
* @param {String} query the query parameters
* @param {String} name - the namespace
* @param {Object} auth - the auth parameters
*/
private doConnect;
/**
Expand Down
35 changes: 11 additions & 24 deletions dist/client.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Client = void 0;
const socket_io_parser_1 = require("socket.io-parser");
const url_1 = __importDefault(require("url"));
const debugModule = require("debug");
const debug = debugModule("socket.io:client");
class Client {
Expand All @@ -19,7 +15,6 @@ class Client {
constructor(server, conn) {
this.sockets = new Map();
this.nsps = new Map();
this.connectBuffer = [];
this.server = server;
this.conn = conn;
this.encoder = server.encoder;
Expand Down Expand Up @@ -50,19 +45,19 @@ class Client {
/**
* Connects a client to a namespace.
*
* @param {String} name namespace
* @param {Object} query the query parameters
* @param {String} name - the namespace
* @param {Object} auth - the auth parameters
* @package
*/
connect(name, query = {}) {
connect(name, auth = {}) {
if (this.server.nsps.has(name)) {
debug("connecting to namespace %s", name);
return this.doConnect(name, query);
return this.doConnect(name, auth);
}
this.server.checkNamespace(name, query, dynamicNsp => {
this.server.checkNamespace(name, auth, dynamicNsp => {
if (dynamicNsp) {
debug("dynamic namespace %s was created", dynamicNsp.name);
this.doConnect(name, query);
this.doConnect(name, auth);
}
else {
debug("creation of namespace %s was denied", name);
Expand All @@ -77,22 +72,14 @@ class Client {
/**
* Connects a client to a namespace.
*
* @param {String} name namespace
* @param {String} query the query parameters
* @param {String} name - the namespace
* @param {Object} auth - the auth parameters
*/
doConnect(name, query) {
doConnect(name, auth) {
const nsp = this.server.of(name);
if ("/" != name && !this.nsps.has("/")) {
this.connectBuffer.push(name);
return;
}
const socket = nsp.add(this, query, () => {
const socket = nsp.add(this, auth, () => {
this.sockets.set(socket.id, socket);
this.nsps.set(nsp.name, socket);
if ("/" == nsp.name && this.connectBuffer.length > 0) {
this.connectBuffer.forEach(this.connect, this);
this.connectBuffer = [];
}
});
}
/**
Expand Down Expand Up @@ -182,7 +169,7 @@ class Client {
*/
ondecoded(packet) {
if (socket_io_parser_1.PacketType.CONNECT == packet.type) {
this.connect(url_1.default.parse(packet.nsp).pathname, url_1.default.parse(packet.nsp, true).query);
this.connect(packet.nsp, packet.data);
}
else {
const socket = this.nsps.get(packet.nsp);
Expand Down
4 changes: 2 additions & 2 deletions dist/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -149,12 +149,12 @@ declare class Server extends EventEmitter {
* Executes the middleware for an incoming namespace not already created on the server.
*
* @param {String} name - name of incoming namespace
* @param {Object} query - the query parameters
* @param {Object} auth - the auth parameters
* @param {Function} fn - callback
*
* @package
*/
checkNamespace(name: string, query: object, fn: (nsp: Namespace | boolean) => void): void;
checkNamespace(name: string, auth: object, fn: (nsp: Namespace | boolean) => void): void;
/**
* Sets the client serving path.
*
Expand Down
18 changes: 4 additions & 14 deletions dist/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ const parent_namespace_1 = require("./parent-namespace");
Object.defineProperty(exports, "ParentNamespace", { enumerable: true, get: function () { return parent_namespace_1.ParentNamespace; } });
const socket_io_adapter_1 = require("socket.io-adapter");
const parser = __importStar(require("socket.io-parser"));
const socket_io_parser_1 = require("socket.io-parser");
const url_1 = __importDefault(require("url"));
const debug_1 = __importDefault(require("debug"));
const debug = debug_1.default("socket.io:server");
Expand Down Expand Up @@ -131,12 +130,12 @@ class Server extends events_1.EventEmitter {
* Executes the middleware for an incoming namespace not already created on the server.
*
* @param {String} name - name of incoming namespace
* @param {Object} query - the query parameters
* @param {Object} auth - the auth parameters
* @param {Function} fn - callback
*
* @package
*/
checkNamespace(name, query, fn) {
checkNamespace(name, auth, fn) {
if (this.parentNsps.size === 0)
return fn(false);
const keysIterator = this.parentNsps.keys();
Expand All @@ -145,7 +144,7 @@ class Server extends events_1.EventEmitter {
if (nextFn.done) {
return fn(false);
}
nextFn.value(name, query, (err, allow) => {
nextFn.value(name, auth, (err, allow) => {
if (err || !allow) {
run();
}
Expand Down Expand Up @@ -221,14 +220,6 @@ class Server extends events_1.EventEmitter {
opts.path = opts.path || this._path;
// set origins verification
opts.allowRequest = opts.allowRequest || this.checkRequest.bind(this);
if (this.sockets.fns.length > 0) {
this.initEngine(srv, opts);
return this;
}
const connectPacket = { type: socket_io_parser_1.PacketType.CONNECT, nsp: "/" };
// the CONNECT packet will be merged with Engine.IO handshake,
// to reduce the number of round trips
opts.initialPacket = this.encoder.encode(connectPacket);
this.initEngine(srv, opts);
return this;
}
Expand Down Expand Up @@ -346,8 +337,7 @@ class Server extends events_1.EventEmitter {
*/
onconnection(conn) {
debug("incoming connection with id %s", conn.id);
const client = new client_1.Client(this, conn);
client.connect("/");
new client_1.Client(this, conn);
return this;
}
/**
Expand Down
4 changes: 0 additions & 4 deletions dist/namespace.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,6 @@ class Namespace extends events_1.EventEmitter {
* @return {Namespace} self
*/
use(fn) {
if (this.server.eio && this.name === "/") {
debug("removing initial packet");
delete this.server.eio.opts.initialPacket;
}
this.fns.push(fn);
return this;
}
Expand Down
8 changes: 6 additions & 2 deletions dist/socket.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ export interface Handshake {
* The query object
*/
query: object;
/**
* The auth object
*/
auth: object;
}
export declare class Socket extends EventEmitter {
readonly nsp: Namespace;
Expand All @@ -58,10 +62,10 @@ export declare class Socket extends EventEmitter {
*
* @param {Namespace} nsp
* @param {Client} client
* @param {Object} query
* @param {Object} auth
* @package
*/
constructor(nsp: Namespace, client: Client, query: any);
constructor(nsp: Namespace, client: Client, auth: object);
/**
* Builds the `handshake` BC object
*/
Expand Down
25 changes: 7 additions & 18 deletions dist/socket.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,10 @@ class Socket extends events_1.EventEmitter {
*
* @param {Namespace} nsp
* @param {Client} client
* @param {Object} query
* @param {Object} auth
* @package
*/
constructor(nsp, client, query) {
constructor(nsp, client, auth) {
super();
this.nsp = nsp;
this.client = client;
Expand All @@ -43,18 +43,12 @@ class Socket extends events_1.EventEmitter {
this.id = nsp.name !== "/" ? nsp.name + "#" + client.id : client.id;
this.connected = true;
this.disconnected = false;
this.handshake = this.buildHandshake(query);
this.handshake = this.buildHandshake(auth);
}
/**
* Builds the `handshake` BC object
*/
buildHandshake(query) {
const self = this;
function buildQuery() {
const requestQuery = url_1.default.parse(self.request.url, true).query;
//if socket-specific query exist, replace query strings in requestQuery
return Object.assign({}, query, requestQuery);
}
buildHandshake(auth) {
return {
headers: this.request.headers,
time: new Date() + "",
Expand All @@ -64,7 +58,8 @@ class Socket extends events_1.EventEmitter {
secure: !!this.request.connection.encrypted,
issued: +new Date(),
url: this.request.url,
query: buildQuery()
query: url_1.default.parse(this.request.url, true).query,
auth
};
}
/**
Expand Down Expand Up @@ -211,13 +206,7 @@ class Socket extends events_1.EventEmitter {
debug("socket connected - writing packet");
this.nsp.connected.set(this.id, this);
this.join(this.id);
const skip = this.nsp.name === "/" && this.nsp.fns.length === 0;
if (skip) {
debug("packet already sent in initial handshake");
}
else {
this.packet({ type: socket_io_parser_1.PacketType.CONNECT });
}
this.packet({ type: socket_io_parser_1.PacketType.CONNECT });
}
/**
* Called with each packet. Called by `Client`.
Expand Down
41 changes: 13 additions & 28 deletions lib/client.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { Decoder, Encoder, PacketType } from "socket.io-parser";
import url from "url";
import { Decoder, Encoder, Packet, PacketType } from "socket.io-parser";
import debugModule = require("debug");
import { IncomingMessage } from "http";
import { Server } from "./index";
Expand All @@ -18,7 +17,6 @@ export class Client {
private readonly decoder: Decoder;
private sockets: Map<SocketId, Socket> = new Map();
private nsps: Map<string, Socket> = new Map();
private connectBuffer: Array<string> = [];

/**
* Client constructor.
Expand Down Expand Up @@ -62,20 +60,20 @@ export class Client {
/**
* Connects a client to a namespace.
*
* @param {String} name namespace
* @param {Object} query the query parameters
* @param {String} name - the namespace
* @param {Object} auth - the auth parameters
* @package
*/
public connect(name, query = {}) {
public connect(name: string, auth: object = {}) {
if (this.server.nsps.has(name)) {
debug("connecting to namespace %s", name);
return this.doConnect(name, query);
return this.doConnect(name, auth);
}

this.server.checkNamespace(name, query, dynamicNsp => {
this.server.checkNamespace(name, auth, dynamicNsp => {
if (dynamicNsp) {
debug("dynamic namespace %s was created", dynamicNsp.name);
this.doConnect(name, query);
this.doConnect(name, auth);
} else {
debug("creation of namespace %s was denied", name);
this.packet({
Expand All @@ -90,25 +88,15 @@ export class Client {
/**
* Connects a client to a namespace.
*
* @param {String} name namespace
* @param {String} query the query parameters
* @param {String} name - the namespace
* @param {Object} auth - the auth parameters
*/
private doConnect(name, query) {
private doConnect(name: string, auth: object) {
const nsp = this.server.of(name);

if ("/" != name && !this.nsps.has("/")) {
this.connectBuffer.push(name);
return;
}

const socket = nsp.add(this, query, () => {
const socket = nsp.add(this, auth, () => {
this.sockets.set(socket.id, socket);
this.nsps.set(nsp.name, socket);

if ("/" == nsp.name && this.connectBuffer.length > 0) {
this.connectBuffer.forEach(this.connect, this);
this.connectBuffer = [];
}
});
}

Expand Down Expand Up @@ -199,12 +187,9 @@ export class Client {
/**
* Called when parser fully decodes a packet.
*/
private ondecoded(packet) {
private ondecoded(packet: Packet) {
if (PacketType.CONNECT == packet.type) {
this.connect(
url.parse(packet.nsp).pathname,
url.parse(packet.nsp, true).query
);
this.connect(packet.nsp, packet.data);
} else {
const socket = this.nsps.get(packet.nsp);
if (socket) {
Expand Down
Loading

0 comments on commit 3289f7e

Please sign in to comment.