socket.io authentication with sharing session data, how io.use() works socket.io authentication with sharing session data, how io.use() works express express

socket.io authentication with sharing session data, how io.use() works


Despite @oLeduc is kind of correct, there are a few more things to explain..

Why the handshake's request is not in scope of express-session middleware?

The biggest reason here is that the middleware in express is designed to handle request specific tasks. Not all, but most of the handlers use the standard req, res, next syntax. And sockets are "request-less" if I can say. The fact that you have socket.request is due to the way the handshake is made, and that it is using HTTP for that. So the guys at socket.io hacked that first request into your socket class so that you can use it. It was not designed by the express team to ever work with sockets and TCP.

What are the scenarios in which middlewares defined with io.use() will fire?

io.use is a close representation of the express use middleware way. In express, the middleware is executed on each request, right? But sockets do not have requests and it will be awkward to use middleware on each socket emit, so they've made it to be executed on each connection. But as well as the express middleware is stacked and used before the actual request is handled (and responded), Socket.IO uses the middleware on connection and even before the actual handshake! You can intercept the handshake if you want to, using that kind of middleware, which is very handy (in order to protect your server from spamming). More on this can be found in the code of passport-socketio

Why io.use() fires before io.of('/abc').use()?

The real explanation on this can be found here, which is this code:

Server.prototype.of = function(name, fn){    if (String(name)[0] !== '/') name = '/' + name;    if (!this.nsps[name]) {        debug('initializing namespace %s', name);        var nsp = new Namespace(this, name);        this.nsps[name] = nsp;    }    if (fn) this.nsps[name].on('connect', fn);    return this.nsps[name];};

And in the beginning of the code, there is this line of code:

this.sockets = this.of('/');

So, there is a default namespace created at the very beginning. And right there, you can see that it has immediately a connect listener attached to it. Later on, each namespace gets the very same connect listener, but because Namespace is EventEmitter, the listeners are added one after another, so they fire one after another. In other words, the default namespace has it's listener at first place, so it fires first.

I don't think this is designed on purpose, but it just happened to be this way :)

Why is socket.request.res undefined?

To be honest, I'm not pretty sure about that. It's because of how engine.io is implemented - you can read a bit more here. It attaches to the regular server, and sends requests in order to make a handshake. I can only imagine that sometimes on errors the headers are separated from the response and that's why you won't get any. Anyways, still just guessing.

Hope information helps.


Why the handshake's request is not in scope of express-session middleware?

Because socket.io will attach to a http.Server which is the layer under express. It is mentioned in a comment in the source of socket.io.

The reason for this is because the first request is a regular http request used to upgrade the reqular stateless http connection into a state-full websocket connection. So it wouldn't make much sense for it to have to go through all the logic that applies to regular http requests.

What are the scenarios in which middlewares defined with io.use() will fire?

Whenever a new socket connection is created.

So every time a client connects it will call the middlewares registed using io.use(). Once the client is connected however, it is not called when a packet is received from the client. It doesn't matter if the connection is initiated on a custom namespace or on the main namespace, it will always be called.

Why io.use() fires before io.of('/abc').use()?

Namespaces are a detail of socket.io's implementation, in reality, websockets will always hit the main namespace first.

To illustrate the situation, look at this snippet and the output it produces:

var customeNamespace = io.of('/abc');customeNamespace.use(function(socket, next){  console.log('Use -> /abc');  return next();});io.of('/abc').on('connection', function (socket) {  console.log('Connected to namespace!')});io.use(function(socket, next){  console.log('Use -> /');  return next();});io.on('connection', function (socket) {  console.log('Connected to namespace!')});

Output:

Use -> /Main namespaceUse -> /abcConnected to namespace!

See the warning that the socket.io team added to their documentation:

Important note: The namespace is an implementation detail of the Socket.IO protocol, and is not related to the actual URL of the underlying transport, which defaults to /socket.io/….

Why is socket.request.res undefined?

As far as I know it should never be undefined. It might be related to your specific implementation.