Skip to content

Commit

Permalink
Fixed WebSockets to follow latest 76 draft.
Browse files Browse the repository at this point in the history
TODO: Implement the closing handshake, specified in draft-76
  • Loading branch information
Oliver Morgan committed Jun 27, 2010
1 parent 57c8d37 commit b971a18
Showing 1 changed file with 57 additions and 39 deletions.
96 changes: 57 additions & 39 deletions lib/socket.io/transports/websocket.js
Original file line number Diff line number Diff line change
@@ -1,56 +1,74 @@
var Client = require('../client').Client,
var Client = require('../client').Client,
url = require('url'),
Buffer = require('buffer').Buffer,
crypto = require('crypto');

exports.websocket = Client.extend({

_onConnect: function(req, socket){
var self = this, headers = [];
this.request = req;
this.connection = socket;
this.data = '';

if (this.request.headers.upgrade !== 'WebSocket' || !this._verifyOrigin(this.request.headers.origin)){
this.listener.options.log('WebSocket connection invalid');
this.connection.end();
}

this.connection.setTimeout(0);
this.connection.setEncoding('utf8');
this.connection.setNoDelay(true);

headers = [
'HTTP/1.1 101 Web Socket Protocol Handshake',
'Upgrade: WebSocket',
'Connection: Upgrade',
'WebSocket-Origin: ' + this.request.headers.origin,
'WebSocket-Location: ws://' + this.request.headers.host + this.request.url
];

if ('sec-websocket-key1' in this.request.headers){
headers.push(
'Sec-WebSocket-Origin: ' + this.request.headers.origin,
'Sec-WebSocket-Location: ws://' + this.request.headers.host + this.request.url);

if ('sec-websocket-key1' in this.request.headers) {
this.draft = 76;
}

if (this.draft == 76) {

var origin = this.request.headers.origin;

headers = [
'HTTP/1.1 101 WebSocket Protocol Handshake',
'Upgrade: WebSocket',
'Connection: Upgrade',
'Sec-WebSocket-Origin: ' + origin ? origin : "null",
'Sec-WebSocket-Location: ws://' + this.request.headers.host + this.request.url
];

if ('sec-websocket-protocol' in this.request.headers) {
headers.push('Sec-WebSocket-Protocol: ' + this.request.headers['sec-websocket-protocol']);
}
}
else {

headers = [
'HTTP/1.1 101 Web Socket Protocol Handshake',
'Upgrade: WebSocket',
'Connection: Upgrade',
'WebSocket-Origin: ' + this.request.headers.origin,
'WebSocket-Location: ws://' + this.request.headers.host + this.request.url
];

this.connection.write(headers.concat('', '').join('\r\n'));
}

this.connection.write(headers.concat('', '').join('\r\n'));
this.connection.addListener('end', function(){ self._onClose(); });
this.connection.addListener('data', function(data){ self._handle(data); });

if (this._proveReception()){
this.connection.addListener('end', function(){self._onClose();});
this.connection.addListener('data', function(data){self._handle(data);});

if (this._proveReception(headers)){
this._payload();
}

setInterval(function(){
self._write(JSON.stringify({heartbeat: '1'}));
}, 10000);
},

_handle: function(data){
var chunk, chunks, chunk_count;
this.data += data;
chunks = this.data.split('\ufffd');
chunks = this.data.split(this.draft == 76 ? '\ufffd' : '\u00ff');
chunk_count = chunks.length - 1;
for (var i = 0; i < chunk_count; i++) {
chunk = chunks[i];
Expand All @@ -65,33 +83,33 @@ exports.websocket = Client.extend({
},

// http://www.whatwg.org/specs/web-apps/current-work/complete/network.html#opening-handshake
_proveReception: function(){
_proveReception: function(headers){
var k1 = this.request.headers['sec-websocket-key1'],
k2 = this.request.headers['sec-websocket-key2'];
if (k1 && k2) {
var md5 = crypto.createHash('md5');

[k1, k2].forEach(function(k) {
var n = k.replace(/[^\d]/g, ''),
spaces = k.replace(/[^ ]/g, '').length,
buf = new Buffer(4);
if (spaces === 0) {
var n = parseInt(k.replace(/[^\d]/g, '')),
spaces = k.replace(/[^ ]/g, '').length;

if (spaces === 0 || n % spaces !== 0) {
this.listener.options.log('Invalid WebSocket key: "' + k + '". Dropping connection');
this.connection.destroy();
return false;
}

n /= spaces;
buf[3] = n & 0xff;
buf[2] = (n >>= 8) & 0xff;
buf[1] = (n >>= 8) & 0xff;
buf[0] = (n >>= 8) & 0xff;

md5.update(buf.toString('binary'));

md5.update(String.fromCharCode(
n >> 24 & 0xFF,
n >> 16 & 0xFF,
n >> 8 & 0xFF,
n & 0xFF));
});

md5.update(this.upgradeHead.toString('binary'));
this.connection.write(md5.digest('binary'), 'binary');
this.connection.write(headers.concat('', '').join('\r\n') + md5.digest('binary'), 'binary');
}
return true;
},
Expand All @@ -105,7 +123,7 @@ exports.websocket = Client.extend({
this._onClose();
}
}

});

exports.websocket.httpUpgrade = true;

0 comments on commit b971a18

Please sign in to comment.