[api] Update WebSocket support to use http.Agent APIs

This commit is contained in:
indexzero 2011-04-16 03:19:22 -04:00
parent 5681fc1a28
commit b0b0183c2b

View File

@ -136,7 +136,7 @@ exports.createServer = function () {
server.on('upgrade', function(req, socket, head) { server.on('upgrade', function(req, socket, head) {
// Tunnel websocket requests too // Tunnel websocket requests too
proxy.proxyWebSocketRequest(port, host); proxy.proxyWebSocketRequest(req, socket, head, port, host);
}); });
} }
@ -444,22 +444,11 @@ HttpProxy.prototype._forwardRequest = function (req) {
}); });
}; };
HttpProxy.prototype.proxyWebSocketRequest = function (port, server, host, data) { HttpProxy.prototype.proxyWebSocketRequest = function (req, socket, head, port, host, buffer) {
var self = this, req = self.req, socket = self.sock, head = self.head, var self = this, CRLF = '\r\n';
headers = new _headers(req.headers), CRLF = '\r\n';
// Will generate clone of headers
// To not change original
function _headers(headers) {
var h = {};
for (var i in headers) {
h[i] = headers[i];
}
return h;
}
// WebSocket requests has method = GET // WebSocket requests has method = GET
if (req.method !== 'GET' || headers.upgrade.toLowerCase() !== 'websocket') { if (req.method !== 'GET' || req.headers.upgrade.toLowerCase() !== 'websocket') {
// This request is not WebSocket request // This request is not WebSocket request
return; return;
} }
@ -467,10 +456,10 @@ HttpProxy.prototype.proxyWebSocketRequest = function (port, server, host, data)
// Turn of all bufferings // Turn of all bufferings
// For server set KeepAlive // For server set KeepAlive
// For client set encoding // For client set encoding
function _socket(socket, server) { function _socket(socket, keepAlive) {
socket.setTimeout(0); socket.setTimeout(0);
socket.setNoDelay(true); socket.setNoDelay(true);
if (server) { if (keepAlive) {
socket.setKeepAlive(true, 0); socket.setKeepAlive(true, 0);
} }
else { else {
@ -478,57 +467,88 @@ HttpProxy.prototype.proxyWebSocketRequest = function (port, server, host, data)
} }
} }
function onUpgrade(reverseProxy) {
var listeners = {};
// We're now connected to the server, so lets change server socket
reverseProxy.on('data', listeners._r_data = function(data) {
// Pass data to client
if (socket.writable) {
try {
socket.write(data);
}
catch (e) {
socket.end();
reverseProxy.end();
}
}
});
socket.on('data', listeners._data = function(data) {
// Pass data from client to server
try {
reverseProxy.write(data);
}
catch (e) {
reverseProxy.end();
socket.end();
}
});
// Detach event listeners from reverseProxy
function detach() {
reverseProxy.removeListener('close', listeners._r_close);
reverseProxy.removeListener('data', listeners._r_data);
socket.removeListener('data', listeners._data);
socket.removeListener('close', listeners._close);
}
// Hook disconnections
reverseProxy.on('end', listeners._r_close = function() {
socket.end();
detach();
});
socket.on('end', listeners._close = function() {
reverseProxy.end();
detach();
});
};
// Client socket // Client socket
_socket(socket); _socket(socket);
// If host is undefined
// Get it from headers
if (!host) {
host = headers.Host;
}
// Remote host address // Remote host address
var remote_host = server + (port - 80 === 0 ? '' : ':' + port); var remoteHost = host + (port - 80 === 0 ? '' : ':' + port),
agent = _getAgent(host, port);
// Change headers // Change headers
headers.Host = remote_host; req.headers.host = remoteHost;
headers.Origin = 'http://' + remote_host; req.headers.origin = 'http://' + host;
// Open request var opts = {
var p = manager.getPool(port, server); host: host,
port: port,
p.getClient(function(client) { agent: agent,
// Based on 'pool/main.js' method: 'GET',
var request = client.request('GET', req.url, headers); path: req.url,
headers: req.headers
var errorListener = function (error) {
client.removeListener('error', errorListener);
// Remove the client from the pool's available clients since it has errored
p.clients.splice(p.clients.indexOf(client), 1);
socket.end();
} }
// Make the outgoing WebSocket request
var request = http.request(opts, function () { });
// Not disconnect on update // Not disconnect on update
client.on('upgrade', function(request, remote_socket, head) { agent.on('upgrade', function(request, remoteSocket, head) {
// Prepare socket // Prepare socket
_socket(remote_socket, true); _socket(remoteSocket, true);
// Emit event // Emit event
onUpgrade(remote_socket); onUpgrade(remoteSocket);
}); });
client.on('error', errorListener);
request.on('response', function (response) {
response.on('end', function () {
client.removeListener('error', errorListener);
client.busy = false;
p.onFree(client);
})
})
client.busy = true;
var handshake; var handshake;
if (typeof request.socket !== 'undefined') {
request.socket.on('data', handshake = function(data) { request.socket.on('data', handshake = function(data) {
// Handshaking // Handshaking
@ -547,8 +567,8 @@ HttpProxy.prototype.proxyWebSocketRequest = function (port, server, host, data)
data = data.slice(Buffer.byteLength(sdata), data.length); data = data.slice(Buffer.byteLength(sdata), data.length);
// Replace host and origin // Replace host and origin
sdata = sdata.replace(remote_host, host) sdata = sdata.replace(remoteHost, host)
.replace(remote_host, host); .replace(remoteHost, host);
try { try {
// Write printable // Write printable
@ -570,65 +590,19 @@ HttpProxy.prototype.proxyWebSocketRequest = function (port, server, host, data)
// Remove data listener now that the 'handshake' is complete // Remove data listener now that the 'handshake' is complete
request.socket.removeListener('data', handshake); request.socket.removeListener('data', handshake);
}); });
}
// Write upgrade-head // Write upgrade-head
try { try {
request.write(head); request.write(head);
} }
catch(e) { catch (ex) {
request.end(); request.end();
socket.end(); socket.end();
} }
self.unwatch(socket);
});
// Request // If we have been passed buffered data, resume it.
if (buffer && !errState) {
function onUpgrade(reverse_proxy) { buffer.resume();
var listeners = {};
// We're now connected to the server, so lets change server socket
reverse_proxy.on('data', listeners._r_data = function(data) {
// Pass data to client
if (socket.writable) {
try {
socket.write(data);
} }
catch (e) {
socket.end();
reverse_proxy.end();
}
}
});
socket.on('data', listeners._data = function(data) {
// Pass data from client to server
try {
reverse_proxy.write(data);
}
catch (e) {
reverse_proxy.end();
socket.end();
}
});
// Detach event listeners from reverse_proxy
function detach() {
reverse_proxy.removeListener('close', listeners._r_close);
reverse_proxy.removeListener('data', listeners._r_data);
socket.removeListener('data', listeners._data);
socket.removeListener('close', listeners._close);
}
// Hook disconnections
reverse_proxy.on('end', listeners._r_close = function() {
socket.end();
detach();
});
socket.on('end', listeners._close = function() {
reverse_proxy.end();
detach();
});
};
}; };