mirror of
https://github.com/socketio/socket.io.git
synced 2026-04-30 03:00:39 -04:00
@@ -24,6 +24,7 @@ function SocketNamespace (mgr, name) {
|
||||
this.manager = mgr;
|
||||
this.name = name || '';
|
||||
this.sockets = {};
|
||||
this.auth = false;
|
||||
this.setFlags();
|
||||
};
|
||||
|
||||
@@ -199,6 +200,17 @@ SocketNamespace.prototype.socket = function (sid, readable) {
|
||||
return this.sockets[sid];
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets authorization for this namespace
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
SocketNamespace.prototype.authorization = function (fn) {
|
||||
this.auth = fn;
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Called when a socket disconnects entirely.
|
||||
*
|
||||
@@ -211,6 +223,30 @@ SocketNamespace.prototype.handleDisconnect = function (sid, reason) {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Performs authentication.
|
||||
*
|
||||
* @param Object client request data
|
||||
* @api private
|
||||
*/
|
||||
|
||||
SocketNamespace.prototype.authorize = function (data, fn) {
|
||||
if (this.auth) {
|
||||
var self = this;
|
||||
|
||||
this.auth.call(this, data, function (err, authorized) {
|
||||
self.log.debug('client ' +
|
||||
(authorized ? '' : 'un') + 'authorized for ' + self.name);
|
||||
fn(err, authorized);
|
||||
});
|
||||
} else {
|
||||
this.log.debug('client authorized for ' + this.name);
|
||||
fn(null, true);
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Handles a packet.
|
||||
*
|
||||
@@ -231,16 +267,42 @@ SocketNamespace.prototype.handlePacket = function (sessid, packet) {
|
||||
});
|
||||
};
|
||||
|
||||
function error (err) {
|
||||
self.log.warn('handshake error ' + err + ' for ' + self.name);
|
||||
socket.packet({ type: 'error', reason: err });
|
||||
};
|
||||
|
||||
function connect () {
|
||||
self.manager.onJoin(sessid, self.name);
|
||||
self.store.publish('join', sessid, self.name);
|
||||
|
||||
// packet echo
|
||||
socket.packet({ type: 'connect' });
|
||||
|
||||
// emit connection event
|
||||
self.emit('connection', socket);
|
||||
};
|
||||
|
||||
switch (packet.type) {
|
||||
case 'connect':
|
||||
this.manager.onJoin(sessid, this.name);
|
||||
this.store.publish('join', sessid, this.name);
|
||||
if (packet.endpoint == '') {
|
||||
connect();
|
||||
} else {
|
||||
var manager = this.manager
|
||||
, handshakeData = manager.handshaken[sessid];
|
||||
|
||||
// packet echo
|
||||
socket.packet({ type: 'connect' });
|
||||
this.authorize(handshakeData, function (err, authorized, newData) {
|
||||
if (err) return error(err);
|
||||
|
||||
// emit connection event
|
||||
self.emit('connection', socket);
|
||||
if (authorized) {
|
||||
manager.onHandshake(sessid, newData || handshakeData);
|
||||
self.store.publish('handshake', sessid, newData || handshakeData);
|
||||
connect();
|
||||
} else {
|
||||
error('unauthorized');
|
||||
}
|
||||
});
|
||||
}
|
||||
break;
|
||||
|
||||
case 'ack':
|
||||
|
||||
@@ -12,7 +12,8 @@
|
||||
var io = require('socket.io')
|
||||
, parser = io.parser
|
||||
, http = require('http')
|
||||
, https = require('https');
|
||||
, https = require('https')
|
||||
, WebSocket = require('../support/node-websocket-client/lib/websocket').WebSocket;
|
||||
|
||||
/**
|
||||
* Exports.
|
||||
@@ -181,3 +182,61 @@ create = function (cl) {
|
||||
console.log('');
|
||||
return io.listen(cl.port);
|
||||
};
|
||||
|
||||
/**
|
||||
* WebSocket socket.io client.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
function WSClient (port, sid) {
|
||||
this.sid = sid;
|
||||
this.port = port;
|
||||
|
||||
WebSocket.call(
|
||||
this
|
||||
, 'ws://localhost:' + port + '/socket.io/'
|
||||
+ io.protocol + '/websocket/' + sid
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Inherits from WebSocket.
|
||||
*/
|
||||
|
||||
WSClient.prototype.__proto__ = WebSocket.prototype;
|
||||
|
||||
/**
|
||||
* Overrides message event emission.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
WSClient.prototype.emit = function (name) {
|
||||
var args = arguments;
|
||||
|
||||
if (name == 'message' || name == 'data') {
|
||||
args[1] = parser.decodePacket(args[1].toString());
|
||||
}
|
||||
|
||||
return WebSocket.prototype.emit.apply(this, arguments);
|
||||
};
|
||||
|
||||
/**
|
||||
* Writes a packet
|
||||
*/
|
||||
|
||||
WSClient.prototype.packet = function (pack) {
|
||||
this.write(parser.encodePacket(pack));
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a websocket client.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
websocket = function (cl, sid) {
|
||||
return new WSClient(cl.port, sid);
|
||||
};
|
||||
|
||||
143
test/namespace.test.js
Normal file
143
test/namespace.test.js
Normal file
@@ -0,0 +1,143 @@
|
||||
|
||||
/*!
|
||||
* socket.io-node
|
||||
* Copyright(c) 2011 LearnBoost <dev@learnboost.com>
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
/**
|
||||
* Test dependencies.
|
||||
*/
|
||||
|
||||
var sio = require('socket.io')
|
||||
, should = require('./common')
|
||||
, ports = 15700;
|
||||
|
||||
/**
|
||||
* Test.
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
'namespace pass no authentication': function (done) {
|
||||
var cl = client(++ports)
|
||||
, io = create(cl)
|
||||
, ws;
|
||||
|
||||
io.of('/a')
|
||||
.on('connection', function (socket) {
|
||||
cl.end();
|
||||
ws.finishClose();
|
||||
io.server.close()
|
||||
done();
|
||||
});
|
||||
|
||||
cl.handshake(function (sid) {
|
||||
ws = websocket(cl, sid);
|
||||
ws.on('open', function () {
|
||||
ws.packet({
|
||||
type: 'connect'
|
||||
, endpoint: '/a'
|
||||
});
|
||||
})
|
||||
});
|
||||
},
|
||||
|
||||
'namespace pass authentication': function (done) {
|
||||
var cl = client(++ports)
|
||||
, io = create(cl)
|
||||
, ws;
|
||||
|
||||
io.of('/a')
|
||||
.authorization(function (data, fn) {
|
||||
fn(null, true);
|
||||
})
|
||||
.on('connection', function (socket) {
|
||||
cl.end();
|
||||
ws.finishClose();
|
||||
io.server.close()
|
||||
done();
|
||||
});
|
||||
|
||||
cl.handshake(function (sid) {
|
||||
ws = websocket(cl, sid);
|
||||
ws.on('open', function () {
|
||||
ws.packet({
|
||||
type: 'connect'
|
||||
, endpoint: '/a'
|
||||
});
|
||||
})
|
||||
});
|
||||
},
|
||||
|
||||
'namespace authentication handshake data': function (done) {
|
||||
var cl = client(++ports)
|
||||
, io = create(cl)
|
||||
, ws;
|
||||
|
||||
io.of('/a')
|
||||
.authorization(function (data, fn) {
|
||||
data.foo = 'bar';
|
||||
fn(null, true);
|
||||
})
|
||||
.on('connection', function (socket) {
|
||||
socket.handshake.address.address.should.equal('127.0.0.1');
|
||||
socket.handshake.address.port.should.equal(ports);
|
||||
socket.handshake.headers.host.should.equal('localhost');
|
||||
socket.handshake.headers.connection.should.equal('keep-alive');
|
||||
socket.handshake.time.should.match(/GMT/);
|
||||
socket.handshake.foo.should.equal('bar');
|
||||
|
||||
cl.end();
|
||||
ws.finishClose();
|
||||
io.server.close()
|
||||
done();
|
||||
});
|
||||
|
||||
cl.handshake(function (sid) {
|
||||
ws = websocket(cl, sid);
|
||||
ws.on('open', function () {
|
||||
ws.packet({
|
||||
type: 'connect'
|
||||
, endpoint: '/a'
|
||||
});
|
||||
})
|
||||
});
|
||||
},
|
||||
|
||||
'namespace fail authentication': function (done) {
|
||||
var cl = client(++ports)
|
||||
, io = create(cl)
|
||||
, calls = 0
|
||||
, ws;
|
||||
|
||||
io.of('/a')
|
||||
.authorization(function (data, fn) {
|
||||
fn(null, false);
|
||||
})
|
||||
.on('connection', function (socket) {
|
||||
throw new Error('Should not be called');
|
||||
});
|
||||
|
||||
cl.handshake(function (sid) {
|
||||
ws = websocket(cl, sid);
|
||||
ws.on('open', function () {
|
||||
ws.packet({
|
||||
type: 'connect'
|
||||
, endpoint: '/a'
|
||||
});
|
||||
});
|
||||
|
||||
ws.on('message', function (data) {
|
||||
if (data.endpoint == '/a') {
|
||||
data.type.should.eql('error');
|
||||
data.reason.should.eql('unauthorized')
|
||||
|
||||
cl.end();
|
||||
ws.finishClose();
|
||||
io.server.close()
|
||||
done();
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -11,75 +11,9 @@
|
||||
|
||||
var sio = require('socket.io')
|
||||
, should = require('./common')
|
||||
, HTTPClient = should.HTTPClient
|
||||
, WebSocket = require('../support/node-websocket-client/lib/websocket').WebSocket
|
||||
, parser = sio.parser
|
||||
, ports = 15400;
|
||||
|
||||
/**
|
||||
* Exports WSClient.
|
||||
*/
|
||||
|
||||
module.exports = exports = WSClient;
|
||||
|
||||
/**
|
||||
* WebSocket socket.io client.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
function WSClient (port, sid) {
|
||||
this.sid = sid;
|
||||
this.port = port;
|
||||
|
||||
WebSocket.call(
|
||||
this
|
||||
, 'ws://localhost:' + port + '/socket.io/'
|
||||
+ sio.protocol + '/websocket/' + sid
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Inherits from WebSocket.
|
||||
*/
|
||||
|
||||
WSClient.prototype.__proto__ = WebSocket.prototype;
|
||||
|
||||
/**
|
||||
* Overrides message event emission.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
WSClient.prototype.emit = function (name) {
|
||||
var args = arguments;
|
||||
|
||||
if (name == 'message' || name == 'data') {
|
||||
args[1] = parser.decodePacket(args[1].toString());
|
||||
}
|
||||
|
||||
return WebSocket.prototype.emit.apply(this, arguments);
|
||||
};
|
||||
|
||||
/**
|
||||
* Writes a packet
|
||||
*/
|
||||
|
||||
WSClient.prototype.packet = function (pack) {
|
||||
this.write(parser.encodePacket(pack));
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a websocket client.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
function websocket (cl, sid) {
|
||||
return new WSClient(cl.port, sid);
|
||||
};
|
||||
|
||||
/**
|
||||
* Tests.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user