aboutsummaryrefslogtreecommitdiffhomepage
path: root/node_modules/socket.io/lib/index.js
diff options
context:
space:
mode:
Diffstat (limited to 'node_modules/socket.io/lib/index.js')
-rw-r--r--node_modules/socket.io/lib/index.js474
1 files changed, 474 insertions, 0 deletions
diff --git a/node_modules/socket.io/lib/index.js b/node_modules/socket.io/lib/index.js
new file mode 100644
index 0000000..e16133a
--- /dev/null
+++ b/node_modules/socket.io/lib/index.js
@@ -0,0 +1,474 @@
+
+/**
+ * Module dependencies.
+ */
+
+var http = require('http');
+var read = require('fs').readFileSync;
+var path = require('path');
+var exists = require('fs').existsSync;
+var engine = require('engine.io');
+var clientVersion = require('socket.io-client/package.json').version;
+var Client = require('./client');
+var Emitter = require('events').EventEmitter;
+var Namespace = require('./namespace');
+var Adapter = require('socket.io-adapter');
+var parser = require('socket.io-parser');
+var debug = require('debug')('socket.io:server');
+var url = require('url');
+
+/**
+ * Module exports.
+ */
+
+module.exports = Server;
+
+/**
+ * Socket.IO client source.
+ */
+
+var clientSource = undefined;
+var clientSourceMap = undefined;
+
+/**
+ * Server constructor.
+ *
+ * @param {http.Server|Number|Object} srv http server, port or options
+ * @param {Object} [opts]
+ * @api public
+ */
+
+function Server(srv, opts){
+ if (!(this instanceof Server)) return new Server(srv, opts);
+ if ('object' == typeof srv && srv instanceof Object && !srv.listen) {
+ opts = srv;
+ srv = null;
+ }
+ opts = opts || {};
+ this.nsps = {};
+ this.path(opts.path || '/socket.io');
+ this.serveClient(false !== opts.serveClient);
+ this.parser = opts.parser || parser;
+ this.encoder = new this.parser.Encoder();
+ this.adapter(opts.adapter || Adapter);
+ this.origins(opts.origins || '*:*');
+ this.sockets = this.of('/');
+ if (srv) this.attach(srv, opts);
+}
+
+/**
+ * Server request verification function, that checks for allowed origins
+ *
+ * @param {http.IncomingMessage} req request
+ * @param {Function} fn callback to be called with the result: `fn(err, success)`
+ */
+
+Server.prototype.checkRequest = function(req, fn) {
+ var origin = req.headers.origin || req.headers.referer;
+
+ // file:// URLs produce a null Origin which can't be authorized via echo-back
+ if ('null' == origin || null == origin) origin = '*';
+
+ if (!!origin && typeof(this._origins) == 'function') return this._origins(origin, fn);
+ if (this._origins.indexOf('*:*') !== -1) return fn(null, true);
+ if (origin) {
+ try {
+ var parts = url.parse(origin);
+ var defaultPort = 'https:' == parts.protocol ? 443 : 80;
+ parts.port = parts.port != null
+ ? parts.port
+ : defaultPort;
+ var ok =
+ ~this._origins.indexOf(parts.hostname + ':' + parts.port) ||
+ ~this._origins.indexOf(parts.hostname + ':*') ||
+ ~this._origins.indexOf('*:' + parts.port);
+ return fn(null, !!ok);
+ } catch (ex) {
+ }
+ }
+ fn(null, false);
+};
+
+/**
+ * Sets/gets whether client code is being served.
+ *
+ * @param {Boolean} v whether to serve client code
+ * @return {Server|Boolean} self when setting or value when getting
+ * @api public
+ */
+
+Server.prototype.serveClient = function(v){
+ if (!arguments.length) return this._serveClient;
+ this._serveClient = v;
+ var resolvePath = function(file){
+ var filepath = path.resolve(__dirname, './../../', file);
+ if (exists(filepath)) {
+ return filepath;
+ }
+ return require.resolve(file);
+ };
+ if (v && !clientSource) {
+ clientSource = read(resolvePath( 'socket.io-client/dist/socket.io.js'), 'utf-8');
+ try {
+ clientSourceMap = read(resolvePath( 'socket.io-client/dist/socket.io.js.map'), 'utf-8');
+ } catch(err) {
+ debug('could not load sourcemap file');
+ }
+ }
+ return this;
+};
+
+/**
+ * Old settings for backwards compatibility
+ */
+
+var oldSettings = {
+ "transports": "transports",
+ "heartbeat timeout": "pingTimeout",
+ "heartbeat interval": "pingInterval",
+ "destroy buffer size": "maxHttpBufferSize"
+};
+
+/**
+ * Backwards compatibility.
+ *
+ * @api public
+ */
+
+Server.prototype.set = function(key, val){
+ if ('authorization' == key && val) {
+ this.use(function(socket, next) {
+ val(socket.request, function(err, authorized) {
+ if (err) return next(new Error(err));
+ if (!authorized) return next(new Error('Not authorized'));
+ next();
+ });
+ });
+ } else if ('origins' == key && val) {
+ this.origins(val);
+ } else if ('resource' == key) {
+ this.path(val);
+ } else if (oldSettings[key] && this.eio[oldSettings[key]]) {
+ this.eio[oldSettings[key]] = val;
+ } else {
+ console.error('Option %s is not valid. Please refer to the README.', key);
+ }
+
+ return this;
+};
+
+/**
+ * Sets the client serving path.
+ *
+ * @param {String} v pathname
+ * @return {Server|String} self when setting or value when getting
+ * @api public
+ */
+
+Server.prototype.path = function(v){
+ if (!arguments.length) return this._path;
+ this._path = v.replace(/\/$/, '');
+ return this;
+};
+
+/**
+ * Sets the adapter for rooms.
+ *
+ * @param {Adapter} v pathname
+ * @return {Server|Adapter} self when setting or value when getting
+ * @api public
+ */
+
+Server.prototype.adapter = function(v){
+ if (!arguments.length) return this._adapter;
+ this._adapter = v;
+ for (var i in this.nsps) {
+ if (this.nsps.hasOwnProperty(i)) {
+ this.nsps[i].initAdapter();
+ }
+ }
+ return this;
+};
+
+/**
+ * Sets the allowed origins for requests.
+ *
+ * @param {String} v origins
+ * @return {Server|Adapter} self when setting or value when getting
+ * @api public
+ */
+
+Server.prototype.origins = function(v){
+ if (!arguments.length) return this._origins;
+
+ this._origins = v;
+ return this;
+};
+
+/**
+ * Attaches socket.io to a server or port.
+ *
+ * @param {http.Server|Number} server or port
+ * @param {Object} options passed to engine.io
+ * @return {Server} self
+ * @api public
+ */
+
+Server.prototype.listen =
+Server.prototype.attach = function(srv, opts){
+ if ('function' == typeof srv) {
+ var msg = 'You are trying to attach socket.io to an express ' +
+ 'request handler function. Please pass a http.Server instance.';
+ throw new Error(msg);
+ }
+
+ // handle a port as a string
+ if (Number(srv) == srv) {
+ srv = Number(srv);
+ }
+
+ if ('number' == typeof srv) {
+ debug('creating http server and binding to %d', srv);
+ var port = srv;
+ srv = http.Server(function(req, res){
+ res.writeHead(404);
+ res.end();
+ });
+ srv.listen(port);
+
+ }
+
+ // set engine.io path to `/socket.io`
+ opts = opts || {};
+ 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;
+ }
+
+ var self = this;
+ var connectPacket = { type: parser.CONNECT, nsp: '/' };
+ this.encoder.encode(connectPacket, function (encodedPacket){
+ // the CONNECT packet will be merged with Engine.IO handshake,
+ // to reduce the number of round trips
+ opts.initialPacket = encodedPacket;
+
+ self.initEngine(srv, opts);
+ });
+ return this;
+};
+
+/**
+ * Initialize engine
+ *
+ * @param {Object} options passed to engine.io
+ * @api private
+ */
+
+Server.prototype.initEngine = function(srv, opts){
+ // initialize engine
+ debug('creating engine.io instance with opts %j', opts);
+ this.eio = engine.attach(srv, opts);
+
+ // attach static file serving
+ if (this._serveClient) this.attachServe(srv);
+
+ // Export http server
+ this.httpServer = srv;
+
+ // bind to engine events
+ this.bind(this.eio);
+};
+
+/**
+ * Attaches the static file serving.
+ *
+ * @param {Function|http.Server} srv http server
+ * @api private
+ */
+
+Server.prototype.attachServe = function(srv){
+ debug('attaching client serving req handler');
+ var url = this._path + '/socket.io.js';
+ var urlMap = this._path + '/socket.io.js.map';
+ var evs = srv.listeners('request').slice(0);
+ var self = this;
+ srv.removeAllListeners('request');
+ srv.on('request', function(req, res) {
+ if (0 === req.url.indexOf(urlMap)) {
+ self.serveMap(req, res);
+ } else if (0 === req.url.indexOf(url)) {
+ self.serve(req, res);
+ } else {
+ for (var i = 0; i < evs.length; i++) {
+ evs[i].call(srv, req, res);
+ }
+ }
+ });
+};
+
+/**
+ * Handles a request serving `/socket.io.js`
+ *
+ * @param {http.Request} req
+ * @param {http.Response} res
+ * @api private
+ */
+
+Server.prototype.serve = function(req, res){
+ // Per the standard, ETags must be quoted:
+ // https://tools.ietf.org/html/rfc7232#section-2.3
+ var expectedEtag = '"' + clientVersion + '"';
+
+ var etag = req.headers['if-none-match'];
+ if (etag) {
+ if (expectedEtag == etag) {
+ debug('serve client 304');
+ res.writeHead(304);
+ res.end();
+ return;
+ }
+ }
+
+ debug('serve client source');
+ res.setHeader('Content-Type', 'application/javascript');
+ res.setHeader('ETag', expectedEtag);
+ res.writeHead(200);
+ res.end(clientSource);
+};
+
+/**
+ * Handles a request serving `/socket.io.js.map`
+ *
+ * @param {http.Request} req
+ * @param {http.Response} res
+ * @api private
+ */
+
+Server.prototype.serveMap = function(req, res){
+ // Per the standard, ETags must be quoted:
+ // https://tools.ietf.org/html/rfc7232#section-2.3
+ var expectedEtag = '"' + clientVersion + '"';
+
+ var etag = req.headers['if-none-match'];
+ if (etag) {
+ if (expectedEtag == etag) {
+ debug('serve client 304');
+ res.writeHead(304);
+ res.end();
+ return;
+ }
+ }
+
+ debug('serve client sourcemap');
+ res.setHeader('Content-Type', 'application/json');
+ res.setHeader('ETag', expectedEtag);
+ res.writeHead(200);
+ res.end(clientSourceMap);
+};
+
+/**
+ * Binds socket.io to an engine.io instance.
+ *
+ * @param {engine.Server} engine engine.io (or compatible) server
+ * @return {Server} self
+ * @api public
+ */
+
+Server.prototype.bind = function(engine){
+ this.engine = engine;
+ this.engine.on('connection', this.onconnection.bind(this));
+ return this;
+};
+
+/**
+ * Called with each incoming transport connection.
+ *
+ * @param {engine.Socket} conn
+ * @return {Server} self
+ * @api public
+ */
+
+Server.prototype.onconnection = function(conn){
+ debug('incoming connection with id %s', conn.id);
+ var client = new Client(this, conn);
+ client.connect('/');
+ return this;
+};
+
+/**
+ * Looks up a namespace.
+ *
+ * @param {String} name nsp name
+ * @param {Function} [fn] optional, nsp `connection` ev handler
+ * @api public
+ */
+
+Server.prototype.of = function(name, fn){
+ if (String(name)[0] !== '/') name = '/' + name;
+
+ var nsp = this.nsps[name];
+ if (!nsp) {
+ debug('initializing namespace %s', name);
+ nsp = new Namespace(this, name);
+ this.nsps[name] = nsp;
+ }
+ if (fn) nsp.on('connect', fn);
+ return nsp;
+};
+
+/**
+ * Closes server connection
+ *
+ * @param {Function} [fn] optional, called as `fn([err])` on error OR all conns closed
+ * @api public
+ */
+
+Server.prototype.close = function(fn){
+ for (var id in this.nsps['/'].sockets) {
+ if (this.nsps['/'].sockets.hasOwnProperty(id)) {
+ this.nsps['/'].sockets[id].onclose();
+ }
+ }
+
+ this.engine.close();
+
+ if (this.httpServer) {
+ this.httpServer.close(fn);
+ } else {
+ fn && fn();
+ }
+};
+
+/**
+ * Expose main namespace (/).
+ */
+
+var emitterMethods = Object.keys(Emitter.prototype).filter(function(key){
+ return typeof Emitter.prototype[key] === 'function';
+});
+
+emitterMethods.concat(['to', 'in', 'use', 'send', 'write', 'clients', 'compress']).forEach(function(fn){
+ Server.prototype[fn] = function(){
+ return this.sockets[fn].apply(this.sockets, arguments);
+ };
+});
+
+Namespace.flags.forEach(function(flag){
+ Object.defineProperty(Server.prototype, flag, {
+ get: function() {
+ this.sockets.flags = this.sockets.flags || {};
+ this.sockets.flags[flag] = true;
+ return this;
+ }
+ });
+});
+
+/**
+ * BC with `io.listen`
+ */
+
+Server.listen = Server;