diff --git a/README.md b/README.md index 5615da2d..3833dd4d 100644 --- a/README.md +++ b/README.md @@ -196,6 +196,12 @@ to a single process. - `maxHttpBufferSize` (`Number`): how many bytes or characters a message can be when polling, before closing the session (to avoid DoS). Default value is `10E7`. + - `allowRequest` (`Function`): A function that receives a given handshake + or upgrade request as its first parameter, and can decide whether to + continue or not. The second argument is a function that needs to be + called with the decided information: `fn(err, success)`, where + `success` is a boolean value where false means that the request is + rejected, and err is an error code. - `transports` (` String`): transports to allow connections to (`['polling', 'websocket', 'flashsocket']`) - `allowUpgrades` (`Boolean`): whether to allow transport upgrades diff --git a/lib/server.js b/lib/server.js index fe75d5d5..6209d681 100644 --- a/lib/server.js +++ b/lib/server.js @@ -38,6 +38,7 @@ function Server(opts){ this.maxHttpBufferSize = opts.maxHttpBufferSize || 10E7; this.transports = opts.transports || Object.keys(transports); this.allowUpgrades = false !== opts.allowUpgrades; + this.allowRequest = opts.allowRequest; this.cookie = false !== opts.cookie ? (opts.cookie || 'io') : false; // initialize websocket server @@ -98,30 +99,31 @@ Server.prototype.upgrades = function(transport){ * @api private */ -Server.prototype.verify = function(req, upgrade){ +Server.prototype.verify = function(req, upgrade, fn){ // transport check var transport = req._query.transport; if (!~this.transports.indexOf(transport)) { debug('unknown transport "%s"', transport); - return Server.errors.UNKNOWN_TRANSPORT; + return fn(Server.errors.UNKNOWN_TRANSPORT, false); } // sid check var sid = req._query.sid; if (sid) { if (!this.clients.hasOwnProperty(sid)) - return Server.errors.UNKNOWN_SID; + return fn(Server.errors.UNKNOWN_SID, false); if (!upgrade && this.clients[sid].transport.name !== transport) { debug('bad request: unexpected transport without upgrade'); - return Server.errors.BAD_REQUEST; + return fn(Server.errors.BAD_REQUEST, false); } } else { // handshake is GET only - return 'GET' == req.method || - Server.errors.BAD_HANDSHAKE_METHOD; + if ('GET' != req.method) return fn(Server.errors.BAD_HANDSHAKE_METHOD, false); + if (!this.allowRequest) return fn(null, true); + return this.allowRequest(req, fn); } - return true; + fn(null, true); }; /** @@ -164,20 +166,20 @@ Server.prototype.handleRequest = function(req, res){ this.prepare(req); req.res = res; - var code = this.verify(req, false); - if (code !== true) { - sendErrorMessage(res, code); - return this; - } + var self = this; + this.verify(req, false, function(err, success) { + if (!success) { + sendErrorMessage(res, err); + return; + } - if (req._query.sid) { - debug('setting new request for existing client'); - this.clients[req._query.sid].transport.onRequest(req); - } else { - this.handshake(req._query.transport, req); - } - - return this; + if (req._query.sid) { + debug('setting new request for existing client'); + self.clients[req._query.sid].transport.onRequest(req); + } else { + self.handshake(req._query.transport, req); + } + }); }; /** @@ -257,15 +259,17 @@ Server.prototype.handshake = function(transport, req){ Server.prototype.handleUpgrade = function(req, socket, head){ this.prepare(req); - if (this.verify(req, true) !== true) { - socket.end(); - return; - } - - // delegate to ws var self = this; - this.ws.handleUpgrade(req, socket, head, function(conn){ - self.onWebSocket(req, conn); + this.verify(req, true, function(err, success) { + if (!success) { + socket.end(); + return; + } + + // delegate to ws + self.ws.handleUpgrade(req, socket, head, function(conn){ + self.onWebSocket(req, conn); + }); }); };