UNPKG

qws

Version:

An HTML5 Web Sockets Server Module

124 lines (110 loc) 4.1 kB
// Generated by CoffeeScript 1.9.2 var EventEmitter, Message, Server, crypto, os, urlParse, extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, hasProp = {}.hasOwnProperty; Message = require('./message').Message; EventEmitter = require('events').EventEmitter; urlParse = require('url').parse; crypto = require('crypto'); os = require('options-stream'); Server = (function(superClass) { extend(Server, superClass); function Server(server1, options, cb) { var server; this.server = server1; this.serverConfigList = []; this.addServer(options, cb); server = this.server; server.on('upgrade', (function(_this) { return function(req, socket) { var config, j, len, msg, path, ref, result; if (result = _this._handShake(req, socket)) { socket.end("HTTP/1.1 400 Bad Request\r\n\r\n" + result + "\r\n"); return; } msg = new Message(socket, { deflate: false }); msg.request = req; path = urlParse(req.url).path; ref = _this.serverConfigList; for (j = 0, len = ref.length; j < len; j++) { config = ref[j]; if (path === config.url) { if (result = _this._domainCheck(req, config)) { msg.errorHandle("HTTP/1.1 403 Forbidden\r\n\r\n" + result + "\r\n"); return; } msg.reset(config); return _this.emit('connect', msg); } } msg.errorHandle('HTTP/1.1 400 Bad Request\r\n\r\nurl not matched\r\n'); }; })(this)); } Server.prototype.addServer = function(options, cb) { var i, j, len, origin, ref, serverConfig; serverConfig = os({ url: '/ws', deflate: false, min_deflate_length: 32, origins: [], cb: cb }, options); if (serverConfig.origins.length) { ref = serverConfig.origins; for (i = j = 0, len = ref.length; j < len; i = ++j) { origin = ref[i]; serverConfig.origins[i] = origin.replace(/\/$/g, ''); } } return this.serverConfigList.push(serverConfig); }; Server.prototype._handShake = function(req, socket) { var head, key, protocol, sha1, sign, uinfo; uinfo = urlParse(req.url); if (uinfo.protocol && uinfo.protocol !== 'ws:') { return 'protocol not match'; } if ('websocket' !== req.headers.upgrade) { return 'upgrade not match'; } if ('13' !== req.headers['sec-websocket-version']) { return 'version not match'; } if (!req.headers['sec-websocket-key']) { return 'key missed'; } protocol = req.headers['sec-websocket-protocol']; key = req.headers['sec-websocket-key']; sha1 = crypto.createHash('sha1'); sha1.update(key + '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'); sign = sha1.digest('base64'); head = "HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: " + sign + "\r\nSec-WebSocket-Origin: " + req.headers.origin + "\r\n"; if (protocol) { head += "Sec-WebSocket-Protocol: " + protocol + "\r\n"; } head += "Sec-WebSocket-Location: ws://" + (req.headers.host + req.url) + "\r\n\r\n"; socket.write(head); return false; }; Server.prototype._domainCheck = function(req, config) { var host, j, len, origin, origins, reqOrigin; origins = config.origins; host = urlParse(req.headers.origin).host; reqOrigin = req.headers.origin.replace(/\/$/g, ''); if (host !== req.headers.host) { for (j = 0, len = origins.length; j < len; j++) { origin = origins[j]; if (origin === '*' || origin === reqOrigin) { return false; } } return "Origin " + req.headers.origin + " is not allowed"; } return false; }; return Server; })(EventEmitter); exports.Server = Server;