Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Support dynamic namespaces
  • Loading branch information
dylanlingelbach committed Dec 19, 2014
commit 1f8bb8a0ece6eae2a57c529448267daf7549c300
47 changes: 29 additions & 18 deletions lib/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,27 +59,38 @@ Client.prototype.setup = function(){
*/

Client.prototype.connect = function(name){
debug('connecting to namespace %s', name);
if (!this.server.nsps[name]) {
this.packet({ type: parser.ERROR, nsp: name, data : 'Invalid namespace'});
return;
}
var nsp = this.server.of(name);
if ('/' != name && !this.nsps['/']) {
this.connectBuffer.push(name);
return;
}

var self = this;
var socket = nsp.add(this, function(){
self.sockets.push(socket);
self.nsps[nsp.name] = socket;
debug('connecting to namespace %s', name);

if ('/' == nsp.name && self.connectBuffer.length > 0) {
self.connectBuffer.forEach(self.connect, self);
self.connectBuffer = [];
function connectNamespace() {
var nsp = self.server.of(name);
if ('/' != name && !self.nsps['/']) {
self.connectBuffer.push(name);
return;
}
});

var socket = nsp.add(self, function(){
self.sockets.push(socket);
self.nsps[nsp.name] = socket;

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

if (!self.server.nsps[name]) {
self.server.checkNamespace(name, function(allow) {
if (allow) {
connectNamespace();
} else {
self.packet({ type: parser.ERROR, nsp: name, data : 'Invalid namespace'});
}
});
} else {
connectNamespace();
}
};

/**
Expand Down
48 changes: 48 additions & 0 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ function Server(srv, opts){
}
opts = opts || {};
this.nsps = {};
this.fns = [];
this.path(opts.path || '/socket.io');
this.serveClient(false !== opts.serveClient);
this.adapter(opts.adapter || Adapter);
Expand Down Expand Up @@ -134,6 +135,53 @@ Server.prototype.set = function(key, val){
return this;
};

/**
* Sets up server middleware to check incoming namespaces.
*
* @return {Server} self
* @api public
*/

Server.prototype.useNamespace = function(fn){
this.fns.push(fn);
return this;
};

/**
* Executes the middleware for an incoming connection.
*
* @param name of incomming namespace
* @param {Function} last fn call in the middleware
* @api private
*/

Server.prototype.checkNamespace = function(name, fn){
var fns = this.fns.slice(0);
if (!fns.length) return fn(false);

var namespaceAllowed = false; // Deny unknown namespaces by default

function run(i){
fns[i](name, function(err, allow){
// upon error, short-circuit
if (err) return fn(false);

// if one piece of middleware explicitly denies namespace, short-circuit
if (allow === false) return fn(false);

namespaceAllowed = namespaceAllowed || allow === true;

// if no middleware left, summon callback
if (!fns[i + 1]) return fn(namespaceAllowed);

// go on to next
run(i + 1);
});
}

run(0);
};

/**
* Sets the client serving path.
*
Expand Down
28 changes: 28 additions & 0 deletions test/socket.io.js
Original file line number Diff line number Diff line change
Expand Up @@ -571,6 +571,34 @@ describe('socket.io', function(){
});
});
});

it('should allow connections to dynamic namespaces', function(done){
var srv = http();
var sio = io(srv);
srv.listen(function(){
var namespace = '/dynamic';
var dynamic = client(srv,namespace);
sio.useNamespace(function(nsp, next) {
expect(nsp).to.be(namespace);
next(null, true);
});
dynamic.on('error', function(err) {
expect(err).to.be(null);
done();
});
var total = 2;
dynamic.on('connect', function() {
--total || done();
});
sio.on('connect', function(socket){
if (socket.nsp.name === '/') return;

expect(socket).to.be.a(Socket);
expect(socket.nsp.name).to.be(namespace);
--total || done();
});
});
});
});

describe('socket', function(){
Expand Down