diff --git a/lib/ws/connection.js b/lib/ws/connection.js index 1d4a1dd..029798f 100644 --- a/lib/ws/connection.js +++ b/lib/ws/connection.js @@ -28,9 +28,6 @@ function Connection(server, req, socket, upgradeHead){ if(! checkVersion.call(this)){ this.reject("Invalid version."); - } else if(this.version == "draft76"){ - debug.call(this, this.version+" connection"); - this.reject("Draft76 is not yet supported."); } else { debug.call(this, this.version+" connection"); @@ -60,8 +57,9 @@ Connection.prototype.__state__ = 0; Object.defineProperty(Connection.prototype, "readyState", { set: function(state){ if(typeof state == "number"){ + var oldstate = this.__state__; this.__state__ = state; - this.emit("readyStateChange", this.__state__); + this.emit("readyStateChange", this.__state__, oldstate); } else { throw new Error("The value must be a number"); } @@ -146,10 +144,10 @@ function setup(){ parser.write(data); }); - conn.addListener("readyStateChange", function(state){ + conn.addListener("readyStateChange", function(state, oldstate){ if(state == 4){ attachClient.call(conn); - } else if( state == 5 ){ + } else if( state == 5 && oldstate == 4){ detachClient.call(conn); conn.emit("close"); } @@ -356,5 +354,45 @@ handshake.draft75 = function(){ }; /* Using draft76 (security model), work out and send the handshake. */ +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; +}; + handshake.draft76 = function(){ + var data = "HTTP/1.1 101 Web Socket Protocol Handshake\r\n" + + "Upgrade: WebSocket\r\n" + + "Connection: Upgrade\r\n" + + "Sec-WebSocket-Origin: "+websocket_origin.call(this)+"\r\n" + + "Sec-WebSocket-Location: "+websocket_location.call(this); + + var strkey1 = this._req.headers['sec-websocket-key1'] + , strkey2 = this._req.headers['sec-websocket-key2']; + + var numkey1 = parseInt(strkey1.replace(/[^\d]/g, ""), 10) + , numkey2 = parseInt(strkey2.replace(/[^\d]/g, ""), 10); + + var spaces1 = strkey1.replace(/[^\ ]/g, "").length + , spaces2 = strkey2.replace(/[^\ ]/g, "").length; + + if (spaces1 == 0 || spaces2 == 0 || numkey1 % spaces1 != 0 || numkey2 % spaces2 != 0) { + this.reject("WebSocket contained an invalid key -- closing connection."); + } else { + var key1 = pack(parseInt(numkey1/spaces1)) + , key2 = pack(parseInt(numkey2/spaces2)); + + var hash = require("crypto").createHash("md5"); + hash.update([key1, key2, this._upgradeHead.toString("binary")].join("")); + + data += "\r\n\r\n"; + data += hash.digest("binary"); + + this._req.socket.write(data, "binary"); + this._req.socket.flush(); + this.readyState = 4; + } }; \ No newline at end of file