qws
Version:
An HTML5 Web Sockets Server Module
116 lines (102 loc) • 3.9 kB
JavaScript
// Generated by CoffeeScript 1.6.3
var EventEmitter, Message, Server, crypto, os, urlParse,
__hasProp = {}.hasOwnProperty,
__extends = 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; };
Message = require('./message').Message;
EventEmitter = require('events').EventEmitter;
urlParse = require('url').parse;
crypto = require('crypto');
os = require('options-stream');
Server = (function(_super) {
__extends(Server, _super);
function Server(server, options, cb) {
var _this = this;
this.server = server;
this.serverConfigList = [];
this.addServer(options, cb);
server.on('upgrade', function(req, socket) {
var config, msg, path, result, _i, _len, _ref;
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 (_i = 0, _len = _ref.length; _i < _len; _i++) {
config = _ref[_i];
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');
});
}
Server.prototype.addServer = function(options, cb) {
var i, origin, serverConfig, _i, _len, _ref;
serverConfig = os({
url: '/ws',
deflate: false,
min_deflate_length: 32,
origins: [],
cb: cb
}, options);
if (serverConfig.origins.length) {
_ref = serverConfig.origins;
for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) {
origin = _ref[i];
serverConfig.origins[i] = origin.replace(/\/$/g, '');
}
}
return this.serverConfigList.push(serverConfig);
};
Server.prototype._handShake = function(req, socket) {
var head, key, 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';
}
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-Extensions: x-webkit-deflate-frame\r\nSec-WebSocket-Origin: " + req.headers.origin + "\r\nSec-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, origin, origins, reqOrigin, _i, _len;
origins = config.origins;
host = urlParse(req.headers.origin).host;
reqOrigin = req.headers.origin.replace(/\/$/g, '');
if (host !== req.headers.host) {
for (_i = 0, _len = origins.length; _i < _len; _i++) {
origin = origins[_i];
if (origin === '*' || origin === reqOrigin) {
return false;
}
}
return "Origin " + req.headers.origin + " is not allowed";
}
return false;
};
return Server;
})(EventEmitter);
exports.Server = Server;