mirror of
https://github.com/http-party/node-http-proxy.git
synced 2025-12-08 20:59:18 +00:00
[api] Update .proxyRequest() and .proxyWebSocketRequest() APIs to take an options hash instead of a set of arguments. Add HTTPS support.
This commit is contained in:
parent
6e4bf6a9cb
commit
cfddd12e82
@ -35,7 +35,11 @@ var util = require('util'),
|
|||||||
httpProxy.createServer(function (req, res, proxy) {
|
httpProxy.createServer(function (req, res, proxy) {
|
||||||
var buffer = proxy.buffer(req);
|
var buffer = proxy.buffer(req);
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
proxy.proxyRequest(req, res, 9000, 'localhost', buffer);
|
proxy.proxyRequest(req, res, {
|
||||||
|
port: 9000,
|
||||||
|
host: 'localhost',
|
||||||
|
buffer: buffer
|
||||||
|
});
|
||||||
}, 200)
|
}, 200)
|
||||||
}).listen(8002);
|
}).listen(8002);
|
||||||
|
|
||||||
|
|||||||
@ -36,7 +36,11 @@ var proxy = new httpProxy.HttpProxy();
|
|||||||
http.createServer(function (req, res) {
|
http.createServer(function (req, res) {
|
||||||
var buffer = proxy.buffer(req);
|
var buffer = proxy.buffer(req);
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
proxy.proxyRequest(req, res, 9000, 'localhost', buffer);
|
proxy.proxyRequest(req, res, {
|
||||||
|
port: 9000,
|
||||||
|
host: 'localhost',
|
||||||
|
buffer: buffer
|
||||||
|
});
|
||||||
}, 200);
|
}, 200);
|
||||||
}).listen(8004);
|
}).listen(8004);
|
||||||
|
|
||||||
|
|||||||
@ -26,6 +26,7 @@
|
|||||||
|
|
||||||
var util = require('util'),
|
var util = require('util'),
|
||||||
http = require('http'),
|
http = require('http'),
|
||||||
|
https = require('https'),
|
||||||
events = require('events'),
|
events = require('events'),
|
||||||
ProxyTable = require('./proxy-table').ProxyTable,
|
ProxyTable = require('./proxy-table').ProxyTable,
|
||||||
maxSockets = 100;
|
maxSockets = 100;
|
||||||
@ -36,21 +37,46 @@ var util = require('util'),
|
|||||||
exports.version = [0, 4, 2];
|
exports.version = [0, 4, 2];
|
||||||
|
|
||||||
//
|
//
|
||||||
// ### function _getAgent (host, port)
|
// ### function _getAgent (host, port, secure)
|
||||||
// #### @host {string} Host of the agent to get
|
// #### @host {string} Host of the agent to get
|
||||||
// #### @port {number} Port of the agent to get
|
// #### @port {number} Port of the agent to get
|
||||||
|
// #### @secure {boolean} Value indicating whether or not to use HTTPS
|
||||||
// Retreives an agent from the `http` module
|
// Retreives an agent from the `http` module
|
||||||
// and sets the `maxSockets` property appropriately.
|
// and sets the `maxSockets` property appropriately.
|
||||||
//
|
//
|
||||||
function _getAgent (host, port) {
|
function _getAgent (host, port, secure) {
|
||||||
//
|
var agent = !secure ? http.getAgent(host, port) : https.getAgent({
|
||||||
// TODO (indexzero): Make this configurable for http / https
|
host: host,
|
||||||
//
|
port: port
|
||||||
var agent = http.getAgent(host, port);
|
});
|
||||||
|
|
||||||
agent.maxSockets = maxSockets;
|
agent.maxSockets = maxSockets;
|
||||||
return agent;
|
return agent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// ### function _getProtocol (outgoing, https)
|
||||||
|
// #### @outgoing {Object} Outgoing request options
|
||||||
|
// #### @secure {Object|boolean} Settings for `https`
|
||||||
|
// Returns the appropriate protocol based on the settings in
|
||||||
|
// `secure`. If the protocol is `https` this function will update
|
||||||
|
// the options in `outgoing` as appropriate by adding `ca`, `key`,
|
||||||
|
// and `cert` if they exist in `secure`.
|
||||||
|
//
|
||||||
|
function _getProtocol (outgoing, secure) {
|
||||||
|
var protocol = secure ? https : http;
|
||||||
|
|
||||||
|
if (typeof secure === 'object') {
|
||||||
|
['ca', 'cert', 'key'].forEach(function (prop) {
|
||||||
|
if (secure[prop]) {
|
||||||
|
outgoing[prop] = secure[prop];
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return protocol;
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// ### function getMaxSockets ()
|
// ### function getMaxSockets ()
|
||||||
// Returns the maximum number of sockets
|
// Returns the maximum number of sockets
|
||||||
@ -104,20 +130,34 @@ exports.createServer = function () {
|
|||||||
|
|
||||||
proxy = new HttpProxy(options);
|
proxy = new HttpProxy(options);
|
||||||
server = http.createServer(function (req, res) {
|
server = http.createServer(function (req, res) {
|
||||||
proxy.emit('request', req, res, req.headers.host, req.url);
|
if (callback) {
|
||||||
|
//
|
||||||
// If we were passed a callback to process the request
|
// If we were passed a callback to process the request
|
||||||
// or response in some way, then call it.
|
// or response in some way, then call it.
|
||||||
if (callback) {
|
//
|
||||||
callback(req, res, proxy);
|
callback(req, res, proxy);
|
||||||
}
|
}
|
||||||
else if (port && host) {
|
else if (port && host) {
|
||||||
proxy.proxyRequest(req, res, port, host);
|
//
|
||||||
|
// If we have a target host and port for the request
|
||||||
|
// then proxy to the specified location.
|
||||||
|
//
|
||||||
|
proxy.proxyRequest(req, res, {
|
||||||
|
port: port,
|
||||||
|
host: host
|
||||||
|
});
|
||||||
}
|
}
|
||||||
else if (proxy.proxyTable) {
|
else if (proxy.proxyTable) {
|
||||||
|
//
|
||||||
|
// If the proxy is configured with a ProxyTable
|
||||||
|
// instance then use that before failing.
|
||||||
|
//
|
||||||
proxy.proxyRequest(req, res);
|
proxy.proxyRequest(req, res);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
//
|
||||||
|
// Otherwise this server is improperly configured.
|
||||||
|
//
|
||||||
throw new Error('Cannot proxy without port, host, or router.')
|
throw new Error('Cannot proxy without port, host, or router.')
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -136,10 +176,19 @@ 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(req, socket, head, port, host);
|
proxy.proxyWebSocketRequest(req, socket, head, {
|
||||||
|
port: port,
|
||||||
|
host: host
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Set the proxy on the server so it is available
|
||||||
|
// to the consumer of the server
|
||||||
|
//
|
||||||
|
server.proxy = proxy;
|
||||||
|
|
||||||
return server;
|
return server;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -165,11 +214,12 @@ exports.createServer = function () {
|
|||||||
var HttpProxy = exports.HttpProxy = function (options) {
|
var HttpProxy = exports.HttpProxy = function (options) {
|
||||||
events.EventEmitter.call(this);
|
events.EventEmitter.call(this);
|
||||||
|
|
||||||
|
var self = this;
|
||||||
options = options || {};
|
options = options || {};
|
||||||
this.options = options;
|
this.forward = options.forward;
|
||||||
|
this.https = options.https;
|
||||||
|
|
||||||
if (options.router) {
|
if (options.router) {
|
||||||
var self = this;
|
|
||||||
this.proxyTable = new ProxyTable(options.router, options.silent, options.hostnameOnly);
|
this.proxyTable = new ProxyTable(options.router, options.silent, options.hostnameOnly);
|
||||||
this.proxyTable.on('routes', function (routes) {
|
this.proxyTable.on('routes', function (routes) {
|
||||||
self.emit('routes', routes);
|
self.emit('routes', routes);
|
||||||
@ -238,12 +288,17 @@ HttpProxy.prototype.close = function () {
|
|||||||
// ### function proxyRequest (req, res, [port, host, paused])
|
// ### function proxyRequest (req, res, [port, host, paused])
|
||||||
// #### @req {ServerRequest} Incoming HTTP Request to proxy.
|
// #### @req {ServerRequest} Incoming HTTP Request to proxy.
|
||||||
// #### @res {ServerResponse} Outgoing HTTP Request to write proxied data to.
|
// #### @res {ServerResponse} Outgoing HTTP Request to write proxied data to.
|
||||||
// #### @port {number} **Optional** Port to use on the proxy target host.
|
// #### @options {Object} Options for the outgoing proxy request.
|
||||||
// #### @host {string} **Optional** Host of the proxy target.
|
// options.port {number} Port to use on the proxy target host.
|
||||||
// #### @buffer {Object} **Optional** Result from `httpProxy.buffer(req)`
|
// options.host {string} Host of the proxy target.
|
||||||
|
// options.buffer {Object} Result from `httpProxy.buffer(req)`
|
||||||
|
// options.https {Object|boolean} Settings for https.
|
||||||
//
|
//
|
||||||
HttpProxy.prototype.proxyRequest = function (req, res, port, host, buffer) {
|
HttpProxy.prototype.proxyRequest = function (req, res, options) {
|
||||||
var self = this, reverseProxy, location, errState = false, opts;
|
var self = this, errState = false, location, outgoing, protocol, reverseProxy;
|
||||||
|
|
||||||
|
// Create an empty options hash if none is passed.
|
||||||
|
options = options || {};
|
||||||
|
|
||||||
//
|
//
|
||||||
// Check the proxy table for this instance to see if we need
|
// Check the proxy table for this instance to see if we need
|
||||||
@ -251,7 +306,7 @@ HttpProxy.prototype.proxyRequest = function (req, res, port, host, buffer) {
|
|||||||
// always ignore the proxyTable if an explicit `port` and `host`
|
// always ignore the proxyTable if an explicit `port` and `host`
|
||||||
// arguments are supplied to `proxyRequest`.
|
// arguments are supplied to `proxyRequest`.
|
||||||
//
|
//
|
||||||
if (this.proxyTable && !host) {
|
if (this.proxyTable && !options.host) {
|
||||||
location = this.proxyTable.getProxyLocation(req);
|
location = this.proxyTable.getProxyLocation(req);
|
||||||
|
|
||||||
//
|
//
|
||||||
@ -267,13 +322,12 @@ HttpProxy.prototype.proxyRequest = function (req, res, port, host, buffer) {
|
|||||||
// When using the ProxyTable in conjunction with an HttpProxy instance
|
// When using the ProxyTable in conjunction with an HttpProxy instance
|
||||||
// only the following arguments are valid:
|
// only the following arguments are valid:
|
||||||
//
|
//
|
||||||
// * `proxy.proxyRequest(req, res, port, host, buffer)`: This will be skipped
|
// * `proxy.proxyRequest(req, res, { host: 'localhost' })`: This will be skipped
|
||||||
// * `proxy.proxyRequest(req, res, buffer)`: Buffer will get updated appropriately
|
// * `proxy.proxyRequest(req, res, { buffer: buffer })`: Buffer will get updated appropriately
|
||||||
// * `proxy.proxyRequest(req, res)`: No effect `undefined = undefined`
|
// * `proxy.proxyRequest(req, res)`: Options will be assigned appropriately.
|
||||||
//
|
//
|
||||||
buffer = port;
|
options.port = location.port;
|
||||||
port = location.port;
|
options.host = location.host;
|
||||||
host = location.host;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
@ -284,14 +338,14 @@ HttpProxy.prototype.proxyRequest = function (req, res, port, host, buffer) {
|
|||||||
//
|
//
|
||||||
// Emit the `start` event indicating that we have begun the proxy operation.
|
// Emit the `start` event indicating that we have begun the proxy operation.
|
||||||
//
|
//
|
||||||
this.emit('start', req, res, host, port);
|
this.emit('start', req, res, options);
|
||||||
|
|
||||||
//
|
//
|
||||||
// If forwarding is enabled for this instance, foward proxy the
|
// If forwarding is enabled for this instance, foward proxy the
|
||||||
// specified request to the address provided in `this.options.forward`
|
// specified request to the address provided in `this.forward`
|
||||||
//
|
//
|
||||||
if (this.options.forward) {
|
if (this.forward) {
|
||||||
this.emit('forward', req, res, this.options.forward.host, this.options.forward.port);
|
this.emit('forward', req, res, this.forward);
|
||||||
this._forwardRequest(req);
|
this._forwardRequest(req);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -312,10 +366,10 @@ HttpProxy.prototype.proxyRequest = function (req, res, port, host, buffer) {
|
|||||||
res.end();
|
res.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
var opts = {
|
outgoing = {
|
||||||
host: host,
|
host: options.host,
|
||||||
port: port,
|
port: options.port,
|
||||||
agent: _getAgent(host, port),
|
agent: _getAgent(options.host, options.port, options.https || this.https),
|
||||||
method: req.method,
|
method: req.method,
|
||||||
path: req.url,
|
path: req.url,
|
||||||
headers: req.headers
|
headers: req.headers
|
||||||
@ -323,10 +377,12 @@ HttpProxy.prototype.proxyRequest = function (req, res, port, host, buffer) {
|
|||||||
|
|
||||||
// Force the `connection` header to be 'close' until
|
// Force the `connection` header to be 'close' until
|
||||||
// node.js core re-implements 'keep-alive'.
|
// node.js core re-implements 'keep-alive'.
|
||||||
opts.headers['connection'] = 'close';
|
outgoing.headers['connection'] = 'close';
|
||||||
|
|
||||||
|
protocol = _getProtocol(outgoing, options.https || this.https);
|
||||||
|
|
||||||
// Open new HTTP request to internal resource with will act as a reverse proxy pass
|
// Open new HTTP request to internal resource with will act as a reverse proxy pass
|
||||||
reverseProxy = http.request(opts, function (response) {
|
reverseProxy = protocol.request(outgoing, function (response) {
|
||||||
|
|
||||||
// Process the `reverseProxy` `response` when it's received.
|
// Process the `reverseProxy` `response` when it's received.
|
||||||
if (response.headers.connection) {
|
if (response.headers.connection) {
|
||||||
@ -388,8 +444,8 @@ HttpProxy.prototype.proxyRequest = function (req, res, port, host, buffer) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// If we have been passed buffered data, resume it.
|
// If we have been passed buffered data, resume it.
|
||||||
if (buffer && !errState) {
|
if (options.buffer && !errState) {
|
||||||
buffer.resume();
|
options.buffer.resume();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -397,18 +453,18 @@ HttpProxy.prototype.proxyRequest = function (req, res, port, host, buffer) {
|
|||||||
// ### @private function _forwardRequest (req)
|
// ### @private function _forwardRequest (req)
|
||||||
// #### @req {ServerRequest} Incoming HTTP Request to proxy.
|
// #### @req {ServerRequest} Incoming HTTP Request to proxy.
|
||||||
// Forwards the specified `req` to the location specified
|
// Forwards the specified `req` to the location specified
|
||||||
// by `this.options.forward` ignoring errors and the subsequent response.
|
// by `this.forward` ignoring errors and the subsequent response.
|
||||||
//
|
//
|
||||||
HttpProxy.prototype._forwardRequest = function (req) {
|
HttpProxy.prototype._forwardRequest = function (req) {
|
||||||
var self = this, port, host, forwardProxy, opts;
|
var self = this, port, host, outgoing, protocol, forwardProxy;
|
||||||
|
|
||||||
port = this.options.forward.port;
|
port = this.forward.port;
|
||||||
host = this.options.forward.host;
|
host = this.forward.host;
|
||||||
|
|
||||||
opts = {
|
outgoing = {
|
||||||
host: host,
|
host: host,
|
||||||
port: port,
|
port: port,
|
||||||
agent: _getAgent(host, port),
|
agent: _getAgent(host, port, this.forward.https),
|
||||||
method: req.method,
|
method: req.method,
|
||||||
path: req.url,
|
path: req.url,
|
||||||
headers: req.headers
|
headers: req.headers
|
||||||
@ -416,10 +472,12 @@ HttpProxy.prototype._forwardRequest = function (req) {
|
|||||||
|
|
||||||
// Force the `connection` header to be 'close' until
|
// Force the `connection` header to be 'close' until
|
||||||
// node.js core re-implements 'keep-alive'.
|
// node.js core re-implements 'keep-alive'.
|
||||||
opts.headers['connection'] = 'close';
|
outgoing.headers['connection'] = 'close';
|
||||||
|
|
||||||
|
protocol = _getProtocol(outgoing, this.forward.https);
|
||||||
|
|
||||||
// Open new HTTP request to internal resource with will act as a reverse proxy pass
|
// Open new HTTP request to internal resource with will act as a reverse proxy pass
|
||||||
forwardProxy = http.request(opts, function (response) {
|
forwardProxy = protocol.request(outgoing, function (response) {
|
||||||
//
|
//
|
||||||
// Ignore the response from the forward proxy since this is a 'fire-and-forget' proxy.
|
// Ignore the response from the forward proxy since this is a 'fire-and-forget' proxy.
|
||||||
// Remark (indexzero): We will eventually emit a 'forward' event here for performance tuning.
|
// Remark (indexzero): We will eventually emit a 'forward' event here for performance tuning.
|
||||||
@ -444,8 +502,8 @@ HttpProxy.prototype._forwardRequest = function (req) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
HttpProxy.prototype.proxyWebSocketRequest = function (req, socket, head, port, host, buffer) {
|
HttpProxy.prototype.proxyWebSocketRequest = function (req, socket, head, options) {
|
||||||
var self = this, CRLF = '\r\n';
|
var self = this, outgoing, errState = false, CRLF = '\r\n';
|
||||||
|
|
||||||
// WebSocket requests has method = GET
|
// WebSocket requests has method = GET
|
||||||
if (req.method !== 'GET' || req.headers.upgrade.toLowerCase() !== 'websocket') {
|
if (req.method !== 'GET' || req.headers.upgrade.toLowerCase() !== 'websocket') {
|
||||||
@ -519,24 +577,24 @@ HttpProxy.prototype.proxyWebSocketRequest = function (req, socket, head, port, h
|
|||||||
_socket(socket);
|
_socket(socket);
|
||||||
|
|
||||||
// Remote host address
|
// Remote host address
|
||||||
var remoteHost = host + (port - 80 === 0 ? '' : ':' + port),
|
var agent = _getAgent(options.host, options.port),
|
||||||
agent = _getAgent(host, port);
|
remoteHost = options.host + (options.port - 80 === 0 ? '' : ':' + options.port);
|
||||||
|
|
||||||
// Change headers
|
// Change headers
|
||||||
req.headers.host = remoteHost;
|
req.headers.host = remoteHost;
|
||||||
req.headers.origin = 'http://' + host;
|
req.headers.origin = 'http://' + options.host;
|
||||||
|
|
||||||
var opts = {
|
outgoing = {
|
||||||
host: host,
|
host: options.host,
|
||||||
port: port,
|
port: options.port,
|
||||||
agent: agent,
|
agent: agent,
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
path: req.url,
|
path: req.url,
|
||||||
headers: req.headers
|
headers: req.headers
|
||||||
}
|
};
|
||||||
|
|
||||||
// Make the outgoing WebSocket request
|
// Make the outgoing WebSocket request
|
||||||
var request = http.request(opts, function () { });
|
var request = http.request(outgoing, function () { });
|
||||||
|
|
||||||
// Not disconnect on update
|
// Not disconnect on update
|
||||||
agent.on('upgrade', function(request, remoteSocket, head) {
|
agent.on('upgrade', function(request, remoteSocket, head) {
|
||||||
@ -567,8 +625,8 @@ HttpProxy.prototype.proxyWebSocketRequest = function (req, socket, head, port, h
|
|||||||
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(remoteHost, host)
|
sdata = sdata.replace(remoteHost, options.host)
|
||||||
.replace(remoteHost, host);
|
.replace(remoteHost, options.host);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Write printable
|
// Write printable
|
||||||
@ -602,7 +660,7 @@ HttpProxy.prototype.proxyWebSocketRequest = function (req, socket, head, port, h
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If we have been passed buffered data, resume it.
|
// If we have been passed buffered data, resume it.
|
||||||
if (buffer && !errState) {
|
if (options.buffer && !errState) {
|
||||||
buffer.resume();
|
options.buffer.resume();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -100,10 +100,14 @@ TestRunner.prototype.startProxyServer = function (port, targetPort, host, callba
|
|||||||
TestRunner.prototype.startLatentProxyServer = function (port, targetPort, host, latency, callback) {
|
TestRunner.prototype.startLatentProxyServer = function (port, targetPort, host, latency, callback) {
|
||||||
// Initialize the nodeProxy and start proxying the request
|
// Initialize the nodeProxy and start proxying the request
|
||||||
var that = this, proxyServer = httpProxy.createServer(function (req, res, proxy) {
|
var that = this, proxyServer = httpProxy.createServer(function (req, res, proxy) {
|
||||||
var data = proxy.buffer(req);
|
var buffer = proxy.buffer(req);
|
||||||
|
|
||||||
setTimeout(function () {
|
setTimeout(function () {
|
||||||
proxy.proxyRequest(req, res, targetPort, host, data);
|
proxy.proxyRequest(req, res, {
|
||||||
|
port: targetPort,
|
||||||
|
host: host,
|
||||||
|
buffer: buffer
|
||||||
|
});
|
||||||
}, latency);
|
}, latency);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -135,7 +139,9 @@ TestRunner.prototype.startProxyServerWithTableAndLatency = function (port, laten
|
|||||||
proxyServer = http.createServer(function (req, res) {
|
proxyServer = http.createServer(function (req, res) {
|
||||||
var buffer = proxy.buffer(req);
|
var buffer = proxy.buffer(req);
|
||||||
setTimeout(function () {
|
setTimeout(function () {
|
||||||
proxy.proxyRequest(req, res, buffer);
|
proxy.proxyRequest(req, res, {
|
||||||
|
buffer: buffer
|
||||||
|
});
|
||||||
}, latency);
|
}, latency);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user