diff options
Diffstat (limited to 'school/node_modules/node-forge/tests/ws.js')
-rw-r--r-- | school/node_modules/node-forge/tests/ws.js | 237 |
1 files changed, 237 insertions, 0 deletions
diff --git a/school/node_modules/node-forge/tests/ws.js b/school/node_modules/node-forge/tests/ws.js new file mode 100644 index 0000000..ba0b39d --- /dev/null +++ b/school/node_modules/node-forge/tests/ws.js @@ -0,0 +1,237 @@ +// Github: http://github.com/ncr/node.ws.js +// Compatible with node v0.1.91 +// Author: Jacek Becela +// Contributors: +// Michael Stillwell http://github.com/ithinkihaveacat +// Nick Chapman http://github.com/nchapman +// Dmitriy Shalashov http://github.com/skaurus +// Johan Dahlberg +// Andreas Kompanez +// Samuel Cyprian http://github.com/samcyp +// License: MIT +// Based on: http://github.com/Guille/node.websocket.js + +function nano(template, data) { + return template.replace(/\{([\w\.]*)}/g, function (str, key) { + var keys = key.split("."), value = data[keys.shift()]; + keys.forEach(function (key) { value = value[key];}); + return value; + }); +} + +function pack(num) { + var result = ''; + result += String.fromCharCode(num >> 24 & 0xFF); + result += String.fromCharCode(num >> 16 & 0xFF); + result += String.fromCharCode(num >> 8 & 0xFF); + result += String.fromCharCode(num & 0xFF); + return result; +} + +var sys = require("sys"), + net = require("net"), + crypto = require("crypto"), + requiredHeaders = { + 'get': /^GET (\/[^\s]*)/, + 'upgrade': /^WebSocket$/, + 'connection': /^Upgrade$/, + 'host': /^(.+)$/, + 'origin': /^(.+)$/ + }, + handshakeTemplate75 = [ + 'HTTP/1.1 101 Web Socket Protocol Handshake', + 'Upgrade: WebSocket', + 'Connection: Upgrade', + 'WebSocket-Origin: {origin}', + 'WebSocket-Location: {protocol}://{host}{resource}', + '', + '' + ].join("\r\n"), + handshakeTemplate76 = [ + 'HTTP/1.1 101 WebSocket Protocol Handshake', // note a diff here + 'Upgrade: WebSocket', + 'Connection: Upgrade', + 'Sec-WebSocket-Origin: {origin}', + 'Sec-WebSocket-Location: {protocol}://{host}{resource}', + '', + '{data}' + ].join("\r\n"), + flashPolicy = '<cross-domain-policy><allow-access-from domain="*" to-ports="*" /></cross-domain-policy>'; + + + +exports.createSecureServer = function (websocketListener, credentials, options) { + if (!options) options = {}; + options.secure = credentials; + return this.createServer(websocketListener, options); +}; + +exports.createServer = function (websocketListener, options) { + if (!options) options = {}; + if (!options.flashPolicy) options.flashPolicy = flashPolicy; + // The value should be a crypto credentials + if (!options.secure) options.secure = null; + + return net.createServer(function (socket) { + //Secure WebSockets + var wsProtocol = 'ws'; + if(options.secure) { + wsProtocol = 'wss'; + socket.setSecure(options.secure); + } + socket.setTimeout(0); + socket.setNoDelay(true); + socket.setKeepAlive(true, 0); + + var emitter = new process.EventEmitter(), + handshaked = false, + buffer = ""; + + function handle(data) { + buffer += data; + + var chunks = buffer.split("\ufffd"), + count = chunks.length - 1; // last is "" or a partial packet + + for(var i = 0; i < count; i++) { + var chunk = chunks[i]; + if(chunk[0] == "\u0000") { + emitter.emit("data", chunk.slice(1)); + } else { + socket.end(); + return; + } + } + + buffer = chunks[count]; + } + + function handshake(data) { + var _headers = data.split("\r\n"); + + if ( /<policy-file-request.*>/.exec(_headers[0]) ) { + socket.write( options.flashPolicy ); + socket.end(); + return; + } + + // go to more convenient hash form + var headers = {}, upgradeHead, len = _headers.length; + if ( _headers[0].match(/^GET /) ) { + headers["get"] = _headers[0]; + } else { + socket.end(); + return; + } + if ( _headers[ _headers.length - 1 ] ) { + upgradeHead = _headers[ _headers.length - 1 ]; + len--; + } + while (--len) { // _headers[0] will be skipped + var header = _headers[len]; + if (!header) continue; + + var split = header.split(": ", 2); // second parameter actually seems to not work in node + headers[ split[0].toLowerCase() ] = split[1]; + } + + // check if we have all needed headers and fetch data from them + var data = {}, match; + for (var header in requiredHeaders) { + // regexp actual header value + if ( match = requiredHeaders[ header ].exec( headers[header] ) ) { + data[header] = match; + } else { + socket.end(); + return; + } + } + + // draft auto-sensing + if ( headers["sec-websocket-key1"] && headers["sec-websocket-key2"] && upgradeHead ) { // 76 + var strkey1 = headers["sec-websocket-key1"] + , strkey2 = headers["sec-websocket-key2"] + + , numkey1 = parseInt(strkey1.replace(/[^\d]/g, ""), 10) + , numkey2 = parseInt(strkey2.replace(/[^\d]/g, ""), 10) + + , spaces1 = strkey1.replace(/[^\ ]/g, "").length + , spaces2 = strkey2.replace(/[^\ ]/g, "").length; + + if (spaces1 == 0 || spaces2 == 0 || numkey1 % spaces1 != 0 || numkey2 % spaces2 != 0) { + socket.end(); + return; + } + + var hash = crypto.createHash("md5") + , key1 = pack(parseInt(numkey1/spaces1)) + , key2 = pack(parseInt(numkey2/spaces2)); + + hash.update(key1); + hash.update(key2); + hash.update(upgradeHead); + + socket.write(nano(handshakeTemplate76, { + protocol: wsProtocol, + resource: data.get[1], + host: data.host[1], + origin: data.origin[1], + data: hash.digest("binary") + }), "binary"); + + } else { // 75 + socket.write(nano(handshakeTemplate75, { + protocol: wsProtocol, + resource: data.get[1], + host: data.host[1], + origin: data.origin[1] + })); + + } + + handshaked = true; + emitter.emit("connect", data.get[1]); + } + + socket.addListener("data", function (data) { + if(handshaked) { + handle(data.toString("utf8")); + } else { + handshake(data.toString("binary")); // because of draft76 handshakes + } + }).addListener("end", function () { + socket.end(); + }).addListener("close", function () { + if (handshaked) { // don't emit close from policy-requests + emitter.emit("close"); + } + }).addListener("error", function (exception) { + if (emitter.listeners("error").length > 0) { + emitter.emit("error", exception); + } else { + throw exception; + } + }); + + emitter.remoteAddress = socket.remoteAddress; + + emitter.write = function (data) { + try { + socket.write('\u0000', 'binary'); + socket.write(data, 'utf8'); + socket.write('\uffff', 'binary'); + } catch(e) { + // Socket not open for writing, + // should get "close" event just before. + socket.end(); + } + }; + + emitter.end = function () { + socket.end(); + }; + + websocketListener(emitter); // emits: "connect", "data", "close", provides: write(data), end() + }); +}; + |