Skip to content

Commit 0669cae

Browse files
committed
Merge pull request #688 from agilethomas/hixie76_haproxy
Fix for #687 Hixie-76 doesn't work behind HAProxy
2 parents 872bbbd + 9abd43d commit 0669cae

File tree

1 file changed

+46
-16
lines changed

1 file changed

+46
-16
lines changed

lib/WebSocketServer.js

Lines changed: 46 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -369,8 +369,42 @@ function handleHixieUpgrade(req, socket, upgradeHead, cb) {
369369
var location = ((req.headers['x-forwarded-proto'] === 'https' || socket.encrypted) ? 'wss' : 'ws') + '://' + wshost + req.url
370370
, protocol = req.headers['sec-websocket-protocol'];
371371

372+
// build the response header and return a Buffer
373+
var buildResponseHeader = function() {
374+
var headers = [
375+
'HTTP/1.1 101 Switching Protocols'
376+
, 'Upgrade: WebSocket'
377+
, 'Connection: Upgrade'
378+
, 'Sec-WebSocket-Location: ' + location
379+
];
380+
if (typeof protocol != 'undefined') headers.push('Sec-WebSocket-Protocol: ' + protocol);
381+
if (typeof origin != 'undefined') headers.push('Sec-WebSocket-Origin: ' + origin);
382+
383+
return new Buffer(headers.concat('', '').join('\r\n'));
384+
};
385+
386+
// send handshake response before receiving the nonce
387+
var handshakeResponse = function() {
388+
389+
socket.setTimeout(0);
390+
socket.setNoDelay(true);
391+
392+
var headerBuffer = buildResponseHeader();
393+
394+
try {
395+
socket.write(headerBuffer, 'binary', function(err) {
396+
// remove listener if there was an error
397+
if (err) socket.removeListener('data', handler);
398+
return;
399+
});
400+
} catch (e) {
401+
try { socket.destroy(); } catch (e) {}
402+
return;
403+
};
404+
};
405+
372406
// handshake completion code to run once nonce has been successfully retrieved
373-
var completeHandshake = function(nonce, rest) {
407+
var completeHandshake = function(nonce, rest, headerBuffer) {
374408
// calculate key
375409
var k1 = req.headers['sec-websocket-key1']
376410
, k2 = req.headers['sec-websocket-key2']
@@ -392,20 +426,10 @@ function handleHixieUpgrade(req, socket, upgradeHead, cb) {
392426
});
393427
md5.update(nonce.toString('binary'));
394428

395-
var headers = [
396-
'HTTP/1.1 101 Switching Protocols'
397-
, 'Upgrade: WebSocket'
398-
, 'Connection: Upgrade'
399-
, 'Sec-WebSocket-Location: ' + location
400-
];
401-
if (typeof protocol != 'undefined') headers.push('Sec-WebSocket-Protocol: ' + protocol);
402-
if (typeof origin != 'undefined') headers.push('Sec-WebSocket-Origin: ' + origin);
403-
404429
socket.setTimeout(0);
405430
socket.setNoDelay(true);
431+
406432
try {
407-
// merge header and hash buffer
408-
var headerBuffer = new Buffer(headers.concat('', '').join('\r\n'));
409433
var hashBuffer = new Buffer(md5.digest('binary'), 'binary');
410434
var handshakeBuffer = new Buffer(headerBuffer.length + hashBuffer.length);
411435
headerBuffer.copy(handshakeBuffer, 0);
@@ -444,11 +468,10 @@ function handleHixieUpgrade(req, socket, upgradeHead, cb) {
444468
if (upgradeHead && upgradeHead.length >= nonceLength) {
445469
var nonce = upgradeHead.slice(0, nonceLength);
446470
var rest = upgradeHead.length > nonceLength ? upgradeHead.slice(nonceLength) : null;
447-
completeHandshake.call(self, nonce, rest);
471+
completeHandshake.call(self, nonce, rest, buildResponseHeader());
448472
}
449473
else {
450-
// nonce not present in upgradeHead, so we must wait for enough data
451-
// data to arrive before continuing
474+
// nonce not present in upgradeHead
452475
var nonce = new Buffer(nonceLength);
453476
upgradeHead.copy(nonce, 0);
454477
var received = upgradeHead.length;
@@ -461,10 +484,17 @@ function handleHixieUpgrade(req, socket, upgradeHead, cb) {
461484
if (received == nonceLength) {
462485
socket.removeListener('data', handler);
463486
if (toRead < data.length) rest = data.slice(toRead);
464-
completeHandshake.call(self, nonce, rest);
487+
488+
// complete the handshake but send empty buffer for headers since they have already been sent
489+
completeHandshake.call(self, nonce, rest, new Buffer(0));
465490
}
466491
}
492+
493+
// handle additional data as we receive it
467494
socket.on('data', handler);
495+
496+
// send header response before we have the nonce to fix haproxy buffering
497+
handshakeResponse();
468498
}
469499
}
470500

0 commit comments

Comments
 (0)