arnaucube
arnaucube/comunicationLeapPublic Self-hosted repository
comunicationLeap/node_modules/socket.io/lib/index.js
node_modules/socket.io/lib/index.jsRaw
  1
  2/**
  3 * Module dependencies.
  4 */
  5
  6var http = require('http');
  7var read = require('fs').readFileSync;
  8var parse = require('url').parse;
  9var engine = require('engine.io');
 10var client = require('socket.io-client');
 11var clientVersion = require('socket.io-client/package').version;
 12var Client = require('./client');
 13var Namespace = require('./namespace');
 14var Adapter = require('socket.io-adapter');
 15var debug = require('debug')('socket.io:server');
 16var url = require('url');
 17
 18/**
 19 * Module exports.
 20 */
 21
 22module.exports = Server;
 23
 24/**
 25 * Socket.IO client source.
 26 */
 27
 28var clientSource = read(require.resolve('socket.io-client/socket.io.js'), 'utf-8');
 29
 30/**
 31 * Server constructor.
 32 *
 33 * @param {http.Server|Number|Object} http server, port or options
 34 * @param {Object} options
 35 * @api public
 36 */
 37
 38function Server(srv, opts){
 39  if (!(this instanceof Server)) return new Server(srv, opts);
 40  if ('object' == typeof srv && !srv.listen) {
 41    opts = srv;
 42    srv = null;
 43  }
 44  opts = opts || {};
 45  this.nsps = {};
 46  this.path(opts.path || '/socket.io');
 47  this.serveClient(false !== opts.serveClient);
 48  this.adapter(opts.adapter || Adapter);
 49  this.origins(opts.origins || '*:*');
 50  this.sockets = this.of('/');
 51  if (srv) this.attach(srv, opts);
 52}
 53
 54/**
 55 * Server request verification function, that checks for allowed origins
 56 *
 57 * @param {http.IncomingMessage} request
 58 * @param {Function} callback to be called with the result: `fn(err, success)`
 59 */
 60
 61Server.prototype.checkRequest = function(req, fn) {
 62  var origin = req.headers.origin || req.headers.referer;
 63
 64  // file:// URLs produce a null Origin which can't be authorized via echo-back
 65  if ('null' == origin) origin = '*';
 66
 67  if (!!origin && typeof(this._origins) == 'function') return this._origins(origin, fn);
 68  if (this._origins.indexOf('*:*') !== -1) return fn(null, true);
 69  if (origin) {
 70    try {
 71      var parts = url.parse(origin);
 72      parts.port = parts.port || 80;
 73      var ok =
 74        ~this._origins.indexOf(parts.hostname + ':' + parts.port) ||
 75        ~this._origins.indexOf(parts.hostname + ':*') ||
 76        ~this._origins.indexOf('*:' + parts.port);
 77      return fn(null, !!ok);
 78    } catch (ex) {
 79    }
 80  }
 81  fn(null, false);
 82};
 83
 84/**
 85 * Sets/gets whether client code is being served.
 86 *
 87 * @param {Boolean} whether to serve client code
 88 * @return {Server|Boolean} self when setting or value when getting
 89 * @api public
 90 */
 91
 92Server.prototype.serveClient = function(v){
 93  if (!arguments.length) return this._serveClient;
 94  this._serveClient = v;
 95  return this;
 96};
 97
 98/**
 99 * Old settings for backwards compatibility
100 */
101
102var oldSettings = {
103  "transports": "transports",
104  "heartbeat timeout": "pingTimeout",
105  "heartbeat interval": "pingInterval",
106  "destroy buffer size": "maxHttpBufferSize"
107};
108
109/**
110 * Backwards compatiblity.
111 *
112 * @api public
113 */
114
115Server.prototype.set = function(key, val){
116  if ('authorization' == key && val) {
117    this.use(function(socket, next) {
118      val(socket.request, function(err, authorized) {
119        if (err) return next(new Error(err));
120        if (!authorized) return next(new Error('Not authorized'));
121        next();
122      });
123    });
124  } else if ('origins' == key && val) {
125    this.origins(val);
126  } else if ('resource' == key) {
127    this.path(val);
128  } else if (oldSettings[key] && this.eio[oldSettings[key]]) {
129    this.eio[oldSettings[key]] = val;
130  } else {
131    console.error('Option %s is not valid. Please refer to the README.', key);
132  }
133
134  return this;
135};
136
137/**
138 * Sets the client serving path.
139 *
140 * @param {String} pathname
141 * @return {Server|String} self when setting or value when getting
142 * @api public
143 */
144
145Server.prototype.path = function(v){
146  if (!arguments.length) return this._path;
147  this._path = v.replace(/\/$/, '');
148  return this;
149};
150
151/**
152 * Sets the adapter for rooms.
153 *
154 * @param {Adapter} pathname
155 * @return {Server|Adapter} self when setting or value when getting
156 * @api public
157 */
158
159Server.prototype.adapter = function(v){
160  if (!arguments.length) return this._adapter;
161  this._adapter = v;
162  for (var i in this.nsps) {
163    if (this.nsps.hasOwnProperty(i)) {
164      this.nsps[i].initAdapter();
165    }
166  }
167  return this;
168};
169
170/**
171 * Sets the allowed origins for requests.
172 *
173 * @param {String} origins
174 * @return {Server|Adapter} self when setting or value when getting
175 * @api public
176 */
177
178Server.prototype.origins = function(v){
179  if (!arguments.length) return this._origins;
180
181  this._origins = v;
182  return this;
183};
184
185/**
186 * Attaches socket.io to a server or port.
187 *
188 * @param {http.Server|Number} server or port
189 * @param {Object} options passed to engine.io
190 * @return {Server} self
191 * @api public
192 */
193
194Server.prototype.listen =
195Server.prototype.attach = function(srv, opts){
196  if ('function' == typeof srv) {
197    var msg = 'You are trying to attach socket.io to an express' +
198    'request handler function. Please pass a http.Server instance.';
199    throw new Error(msg);
200  }
201
202  // handle a port as a string
203  if (Number(srv) == srv) {
204    srv = Number(srv);
205  }
206
207  if ('number' == typeof srv) {
208    debug('creating http server and binding to %d', srv);
209    var port = srv;
210    srv = http.Server(function(req, res){
211      res.writeHead(404);
212      res.end();
213    });
214    srv.listen(port);
215
216  }
217
218  // set engine.io path to `/socket.io`
219  opts = opts || {};
220  opts.path = opts.path || this.path();
221  // set origins verification
222  opts.allowRequest = this.checkRequest.bind(this);
223
224  // initialize engine
225  debug('creating engine.io instance with opts %j', opts);
226  this.eio = engine.attach(srv, opts);
227
228  // attach static file serving
229  if (this._serveClient) this.attachServe(srv);
230
231  // Export http server
232  this.httpServer = srv;
233
234  // bind to engine events
235  this.bind(this.eio);
236
237  return this;
238};
239
240/**
241 * Attaches the static file serving.
242 *
243 * @param {Function|http.Server} http server
244 * @api private
245 */
246
247Server.prototype.attachServe = function(srv){
248  debug('attaching client serving req handler');
249  var url = this._path + '/socket.io.js';
250  var evs = srv.listeners('request').slice(0);
251  var self = this;
252  srv.removeAllListeners('request');
253  srv.on('request', function(req, res) {
254    if (0 == req.url.indexOf(url)) {
255      self.serve(req, res);
256    } else {
257      for (var i = 0; i < evs.length; i++) {
258        evs[i].call(srv, req, res);
259      }
260    }
261  });
262};
263
264/**
265 * Handles a request serving `/socket.io.js`
266 *
267 * @param {http.Request} req
268 * @param {http.Response} res
269 * @api private
270 */
271
272Server.prototype.serve = function(req, res){
273  var etag = req.headers['if-none-match'];
274  if (etag) {
275    if (clientVersion == etag) {
276      debug('serve client 304');
277      res.writeHead(304);
278      res.end();
279      return;
280    }
281  }
282
283  debug('serve client source');
284  res.setHeader('Content-Type', 'application/javascript');
285  res.setHeader('ETag', clientVersion);
286  res.writeHead(200);
287  res.end(clientSource);
288};
289
290/**
291 * Binds socket.io to an engine.io instance.
292 *
293 * @param {engine.Server} engine.io (or compatible) server
294 * @return {Server} self
295 * @api public
296 */
297
298Server.prototype.bind = function(engine){
299  this.engine = engine;
300  this.engine.on('connection', this.onconnection.bind(this));
301  return this;
302};
303
304/**
305 * Called with each incoming transport connection.
306 *
307 * @param {engine.Socket} socket
308 * @return {Server} self
309 * @api public
310 */
311
312Server.prototype.onconnection = function(conn){
313  debug('incoming connection with id %s', conn.id);
314  var client = new Client(this, conn);
315  client.connect('/');
316  return this;
317};
318
319/**
320 * Looks up a namespace.
321 *
322 * @param {String} nsp name
323 * @param {Function} optional, nsp `connection` ev handler
324 * @api public
325 */
326
327Server.prototype.of = function(name, fn){
328  if (String(name)[0] !== '/') name = '/' + name;
329  
330  if (!this.nsps[name]) {
331    debug('initializing namespace %s', name);
332    var nsp = new Namespace(this, name);
333    this.nsps[name] = nsp;
334  }
335  if (fn) this.nsps[name].on('connect', fn);
336  return this.nsps[name];
337};
338
339/**
340 * Closes server connection
341 *
342 * @api public
343 */
344
345Server.prototype.close = function(){
346  this.nsps['/'].sockets.forEach(function(socket){
347    socket.onclose();
348  });
349
350  this.engine.close();
351
352  if(this.httpServer){
353    this.httpServer.close();
354  }
355};
356
357/**
358 * Expose main namespace (/).
359 */
360
361['on', 'to', 'in', 'use', 'emit', 'send', 'write'].forEach(function(fn){
362  Server.prototype[fn] = function(){
363    var nsp = this.sockets[fn];
364    return nsp.apply(this.sockets, arguments);
365  };
366});
367
368Namespace.flags.forEach(function(flag){
369  Server.prototype.__defineGetter__(flag, function(name){
370    this.flags.push(name);
371    return this;
372  });
373});
374
375/**
376 * BC with `io.listen`
377 */
378
379Server.listen = Server;