mirror of
https://github.com/http-party/node-http-proxy.git
synced 2025-12-08 20:59:18 +00:00
[api] Update WebSocket support to use http.Agent APIs
This commit is contained in:
parent
5681fc1a28
commit
b0b0183c2b
@ -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,
|
||||||
|
agent: agent,
|
||||||
|
method: 'GET',
|
||||||
|
path: req.url,
|
||||||
|
headers: req.headers
|
||||||
|
}
|
||||||
|
|
||||||
p.getClient(function(client) {
|
// Make the outgoing WebSocket request
|
||||||
// Based on 'pool/main.js'
|
var request = http.request(opts, function () { });
|
||||||
var request = client.request('GET', req.url, headers);
|
|
||||||
|
|
||||||
var errorListener = function (error) {
|
// Not disconnect on update
|
||||||
client.removeListener('error', errorListener);
|
agent.on('upgrade', function(request, remoteSocket, head) {
|
||||||
|
// Prepare socket
|
||||||
|
_socket(remoteSocket, true);
|
||||||
|
|
||||||
// Remove the client from the pool's available clients since it has errored
|
// Emit event
|
||||||
p.clients.splice(p.clients.indexOf(client), 1);
|
onUpgrade(remoteSocket);
|
||||||
socket.end();
|
});
|
||||||
}
|
|
||||||
|
|
||||||
// Not disconnect on update
|
var handshake;
|
||||||
client.on('upgrade', function(request, remote_socket, head) {
|
if (typeof request.socket !== 'undefined') {
|
||||||
// Prepare socket
|
|
||||||
_socket(remote_socket, true);
|
|
||||||
|
|
||||||
// Emit event
|
|
||||||
onUpgrade(remote_socket);
|
|
||||||
});
|
|
||||||
|
|
||||||
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;
|
|
||||||
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();
|
|
||||||
});
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
Loading…
x
Reference in New Issue
Block a user