'use strict'; var util = require('util'), HttpParser = require('../http_parser'), Base = require('./base'), Draft75 = require('./draft75'), Draft76 = require('./draft76'), Hybi = require('./hybi'); var Server = function(options) { Base.call(this, null, null, options); this._http = new HttpParser('request'); }; util.inherits(Server, Base); var instance = { EVENTS: ['open', 'message', 'error', 'close'], _bindEventListeners: function() { this.messages.on('error', function() {}); this.on('error', function() {}); }, parse: function(chunk) { if (this._delegate) return this._delegate.parse(chunk); this._http.parse(chunk); if (!this._http.isComplete()) return; this.method = this._http.method; this.url = this._http.url; this.headers = this._http.headers; this.body = this._http.body; var self = this; this._delegate = Server.http(this, this._options); this._delegate.messages = this.messages; this._delegate.io = this.io; this._open(); this.EVENTS.forEach(function(event) { this._delegate.on(event, function(e) { self.emit(event, e) }); }, this); this.protocol = this._delegate.protocol; this.version = this._delegate.version; this.parse(this._http.body); this.emit('connect', new Base.ConnectEvent()); }, _open: function() { this.__queue.forEach(function(msg) { this._delegate[msg[0]].apply(this._delegate, msg[1]); }, this); this.__queue = []; } }; ['addExtension', 'setHeader', 'start', 'frame', 'text', 'binary', 'ping', 'close'].forEach(function(method) { instance[method] = function() { if (this._delegate) { return this._delegate[method].apply(this._delegate, arguments); } else { this.__queue.push([method, arguments]); return true; } }; }); for (var key in instance) Server.prototype[key] = instance[key]; Server.http = function(request, options) { options = options || {}; if (options.requireMasking === undefined) options.requireMasking = true; var klass = this.getDriverClass(request), url = this.determineUrl(request); return klass && new klass(request, url, options); }; Server.isWebSocket = function(request) { var klass = this.getDriverClass(request); return !!klass; }; Server.getDriverClass = function(request) { var headers = request.headers; var connection = headers['connection'] || '', key = headers['sec-websocket-key'], key1 = headers['sec-websocket-key1'], key2 = headers['sec-websocket-key2'], origin = headers['origin'], upgrade = headers['upgrade'] || '', version = headers['sec-websocket-version']; if (request.method !== 'GET' || connection.toLowerCase().split(/ *, */).indexOf('upgrade') < 0 || upgrade.toLowerCase() !== 'websocket') return null; if (typeof version === 'string' || typeof key === 'string') return (version === '13' && key.length > 0) ? Hybi : null; if (typeof origin !== 'string' || origin.length === 0) return null; if (typeof key1 === 'string' && typeof key2 === 'string') return Draft76; return Draft75; }; Server.determineUrl = function(request) { var scheme = this.isSecureRequest(request) ? 'wss:' : 'ws:'; return scheme + '//' + request.headers.host + request.url; }; Server.isSecureRequest = function(request) { if (request.connection && request.connection.authorized !== undefined) return true; if (request.socket && request.socket.secure) return true; var headers = request.headers; if (!headers) return false; if (headers['https'] === 'on') return true; if (headers['x-forwarded-ssl'] === 'on') return true; if (headers['x-forwarded-scheme'] === 'https') return true; if (headers['x-forwarded-proto'] === 'https') return true; return false; }; module.exports = Server;