Skip to content

Commit

Permalink
Updating websocket transport to be usable behind an haproxy load bala…
Browse files Browse the repository at this point in the history
…ncer.
  • Loading branch information
theturtle32 committed Aug 7, 2010
1 parent e9ffd89 commit 9982232
Showing 1 changed file with 44 additions and 8 deletions.
52 changes: 44 additions & 8 deletions lib/socket.io/transports/websocket.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,22 @@ WebSocket.prototype._onConnect = function(req, socket){
}

if (this.draft == 76){
/* We need to send the 101 response immediately when using Draft 76 with
a load balancing proxy, such as HAProxy. In order to protect an
unsuspecting non-websocket HTTP server, HAProxy will not send the
8-byte nonce through the connection until the Upgrade: WebSocket
request has been confirmed by the WebSocket server by a 101 response
indicating that the server can handle the upgraded protocol. We
therefore must send the 101 response immediately, and then wait for
the nonce to be forwarded to us afterward in order to finish the
Draft 76 handshake.
*/

// If we don't have the nonce yet, wait for it.
if (!(this.upgradeHead && this.upgradeHead.length >= 8)) {
this.waitingForNonce = true;
}

var origin = this.request.headers.origin;

headers = [
Expand All @@ -51,12 +67,12 @@ WebSocket.prototype._onConnect = function(req, socket){
'WebSocket-Origin: ' + this.request.headers.origin,
'WebSocket-Location: ws://' + this.request.headers.host + this.request.url
];
try {
this.connection.write(headers.concat('', '').join('\r\n'));
} catch(e){
this._onClose();
}
}

try {
this.connection.write(headers.concat('', '').join('\r\n'));
} catch(e){
this._onClose();
}

this.connection.addListener('end', function(){
Expand All @@ -67,12 +83,32 @@ WebSocket.prototype._onConnect = function(req, socket){
self._handle(data);
});

if (this._proveReception(headers)) this._payload();
if (this.waitingForNonce) {
// Since we will be receiving the binary nonce through the normal HTTP
// data event, set the connection to 'binary' temporarily
this.connection.setEncoding('binary');
this._headers = headers;
}
else {
if (this._proveReception(headers)) this._payload();
}
};

WebSocket.prototype._handle = function(data){
var chunk, chunks, chunk_count;
this.data += data;
if (this.waitingForNonce) {
if (this.data.length < 8) { return; }
// Restore the connection to utf8 encoding after receiving the nonce
this.connection.setEncoding('utf8');
this.waitingForNonce = false;
// Stuff the nonce into the location where it's expected to be
this.upgradeHead = this.data.substr(0,8);
this.data = this.data.substr(8);
if (this._proveReception(this._headers)) { this._payload(); }
return;
}

chunks = this.data.split('\ufffd');
chunk_count = chunks.length - 1;
for (var i = 0; i < chunk_count; i++){
Expand Down Expand Up @@ -117,7 +153,7 @@ WebSocket.prototype._proveReception = function(headers){
md5.update(this.upgradeHead.toString('binary'));

try {
this.connection.write(headers.concat('', '').join('\r\n') + md5.digest('binary'), 'binary');
this.connection.write(md5.digest('binary'), 'binary');
} catch(e){
this._onClose();
}
Expand Down

0 comments on commit 9982232

Please sign in to comment.