mirror of
https://github.com/http-party/node-http-proxy.git
synced 2025-12-08 20:59:18 +00:00
[doc] Added more documentation
This commit is contained in:
parent
d8c54063dc
commit
973f19fd5a
1
demo.js
1
demo.js
@ -39,7 +39,6 @@ var welcome = '\
|
|||||||
# # # # # # # # #### # # # \n';
|
# # # # # # # # #### # # # \n';
|
||||||
util.puts(welcome.rainbow.bold);
|
util.puts(welcome.rainbow.bold);
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Basic Http Proxy Server
|
// Basic Http Proxy Server
|
||||||
//
|
//
|
||||||
|
|||||||
@ -32,7 +32,13 @@ var util = require('util'),
|
|||||||
ProxyTable = require('./proxy-table').ProxyTable,
|
ProxyTable = require('./proxy-table').ProxyTable,
|
||||||
maxSockets = 100;
|
maxSockets = 100;
|
||||||
|
|
||||||
|
//
|
||||||
|
// ### function _getAgent (host, port)
|
||||||
|
// #### @host {string} Host of the agent to get
|
||||||
|
// #### @port {number} Port of the agent to get
|
||||||
|
// Retreives an agent from the `http` module
|
||||||
|
// and sets the `maxSockets` property appropriately.
|
||||||
|
//
|
||||||
function _getAgent (host, port) {
|
function _getAgent (host, port) {
|
||||||
//
|
//
|
||||||
// TODO (indexzero): Make this configurable for http / https
|
// TODO (indexzero): Make this configurable for http / https
|
||||||
@ -42,17 +48,33 @@ function _getAgent (host, port) {
|
|||||||
return agent;
|
return agent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// ### function getMaxSockets ()
|
||||||
|
// Returns the maximum number of sockets
|
||||||
|
// allowed on __every__ outgoing request
|
||||||
|
// made by __all__ instances of `HttpProxy`
|
||||||
|
//
|
||||||
exports.getMaxSockets = function () {
|
exports.getMaxSockets = function () {
|
||||||
return maxSockets;
|
return maxSockets;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
// ### function setMaxSockets ()
|
||||||
|
// Sets the maximum number of sockets
|
||||||
|
// allowed on __every__ outgoing request
|
||||||
|
// made by __all__ instances of `HttpProxy`
|
||||||
|
//
|
||||||
exports.setMaxSockets = function (value) {
|
exports.setMaxSockets = function (value) {
|
||||||
maxSockets = value;
|
maxSockets = value;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
// ### function createServer ([port, host, options], handler)
|
||||||
|
//
|
||||||
|
//
|
||||||
exports.createServer = function () {
|
exports.createServer = function () {
|
||||||
var args, callback, port, host, forward,
|
var args, callback, port, host, forward,
|
||||||
silent, proxyTable, options = {};
|
silent, options, proxy, server;
|
||||||
|
|
||||||
args = Array.prototype.slice.call(arguments);
|
args = Array.prototype.slice.call(arguments);
|
||||||
callback = typeof args[args.length - 1] === 'function' && args.pop();
|
callback = typeof args[args.length - 1] === 'function' && args.pop();
|
||||||
@ -69,9 +91,8 @@ exports.createServer = function () {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var proxy = new HttpProxy(options);
|
proxy = new HttpProxy(options);
|
||||||
|
server = http.createServer(function (req, res) {
|
||||||
var server = http.createServer(function (req, res) {
|
|
||||||
winston.verbose('Incoming HTTP request to: ' + req.headers.host + req.url);
|
winston.verbose('Incoming HTTP request to: ' + req.headers.host + req.url);
|
||||||
|
|
||||||
// If we were passed a callback to process the request
|
// If we were passed a callback to process the request
|
||||||
@ -98,13 +119,14 @@ exports.createServer = function () {
|
|||||||
|
|
||||||
proxy.on('routes', function (routes) {
|
proxy.on('routes', function (routes) {
|
||||||
server.emit('routes', routes);
|
server.emit('routes', routes);
|
||||||
})
|
});
|
||||||
|
|
||||||
if (!callback) {
|
if (!callback) {
|
||||||
// WebSocket support: if callback is empty tunnel
|
// WebSocket support: if callback is empty tunnel
|
||||||
// websocket request automatically
|
// websocket request automatically
|
||||||
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(port, host);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -112,6 +134,25 @@ exports.createServer = function () {
|
|||||||
return server;
|
return server;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
// ### function HttpProxy (options)
|
||||||
|
// #### @options {Object} Options for this instance.
|
||||||
|
// Constructor function for new instances of HttpProxy responsible
|
||||||
|
// for managing the life-cycle of streaming reverse proxyied HTTP requests.
|
||||||
|
//
|
||||||
|
// Example options:
|
||||||
|
//
|
||||||
|
// {
|
||||||
|
// router: {
|
||||||
|
// 'foo.com': 'localhost:8080',
|
||||||
|
// 'bar.com': 'localhost:8081'
|
||||||
|
// },
|
||||||
|
// forward: {
|
||||||
|
// host: 'localhost',
|
||||||
|
// port: 9001
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
var HttpProxy = exports.HttpProxy = function (options) {
|
var HttpProxy = exports.HttpProxy = function (options) {
|
||||||
events.EventEmitter.call(this);
|
events.EventEmitter.call(this);
|
||||||
|
|
||||||
@ -127,38 +168,36 @@ var HttpProxy = exports.HttpProxy = function (options) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Inherit from events.EventEmitter
|
||||||
util.inherits(HttpProxy, events.EventEmitter);
|
util.inherits(HttpProxy, events.EventEmitter);
|
||||||
|
|
||||||
HttpProxy.prototype.close = function () {
|
//
|
||||||
if (this.proxyTable) this.proxyTable.close();
|
// ### function pause (obj)
|
||||||
};
|
// #### @obj {Object} Object to pause events from
|
||||||
|
// Pause `data` and `end` events on the given `obj`.
|
||||||
/**
|
// Consumers of HttpProxy performing async tasks
|
||||||
* Pause `data` and `end` events on the given `obj`.
|
// __must__ utilize this utility, to re-emit data once
|
||||||
* Middleware performing async tasks _should_ utilize
|
// the async operation has completed, otherwise these
|
||||||
* this utility (or similar), to re-emit data once
|
// __events will be lost.__
|
||||||
* the async operation has completed, otherwise these
|
//
|
||||||
* events may be lost.
|
// var pause = httpProxy.pause(req);
|
||||||
*
|
// fs.readFile(path, function(){
|
||||||
* var pause = utils.pause(req);
|
// httpProxy.proxyRequest(req, res, host, port, paused);
|
||||||
* fs.readFile(path, function(){
|
// });
|
||||||
* next();
|
//
|
||||||
* pause.resume();
|
// __Attribution:__ This approach is based heavily on
|
||||||
* });
|
// [Connect](https://github.com/senchalabs/connect/blob/master/lib/utils.js#L157).
|
||||||
*
|
// However, this is not a big leap from the implementation in node-http-proxy < 0.4.0.
|
||||||
* @param {Object} obj
|
// This simply chooses to manage the scope of the events on a new Object literal as opposed to
|
||||||
* @return {Object}
|
// [on the HttpProxy instance](https://github.com/nodejitsu/node-http-proxy/blob/v0.3.1/lib/node-http-proxy.js#L154).
|
||||||
* @api public
|
//
|
||||||
*/
|
|
||||||
HttpProxy.prototype.pause = function (obj) {
|
HttpProxy.prototype.pause = function (obj) {
|
||||||
var onData, onEnd, events = [];
|
var onData, onEnd, events = [];
|
||||||
|
|
||||||
// buffer data
|
|
||||||
obj.on('data', onData = function (data, encoding) {
|
obj.on('data', onData = function (data, encoding) {
|
||||||
events.push(['data', data, encoding]);
|
events.push(['data', data, encoding]);
|
||||||
});
|
});
|
||||||
|
|
||||||
// buffer end
|
|
||||||
obj.on('end', onEnd = function (data, encoding) {
|
obj.on('end', onEnd = function (data, encoding) {
|
||||||
events.push(['end', data, encoding]);
|
events.push(['end', data, encoding]);
|
||||||
});
|
});
|
||||||
@ -177,8 +216,25 @@ HttpProxy.prototype.pause = function (obj) {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
// ### function close ()
|
||||||
|
// Frees the resources associated with this instance,
|
||||||
|
// if they exist.
|
||||||
|
//
|
||||||
|
HttpProxy.prototype.close = function () {
|
||||||
|
if (this.proxyTable) this.proxyTable.close();
|
||||||
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
// ### function proxyRequest (req, res, [port, host, paused])
|
||||||
|
// #### @req {ServerRequest} Incoming HTTP Request to proxy.
|
||||||
|
// #### @res {ServerResponse} Outgoing HTTP Request to write proxied data to.
|
||||||
|
// #### @port {number} **Optional** Port to use on the proxy target host.
|
||||||
|
// #### @host {string} **Optional** Host of the proxy target.
|
||||||
|
// #### @paused {Object} **Optional** Result from `httpProxy.pause(req)`
|
||||||
|
//
|
||||||
HttpProxy.prototype.proxyRequest = function (req, res, port, host, paused) {
|
HttpProxy.prototype.proxyRequest = function (req, res, port, host, paused) {
|
||||||
var self = this, reverseProxy, location;
|
var self = this, reverseProxy, location, errState = false;
|
||||||
|
|
||||||
//
|
//
|
||||||
// Check the proxy table for this instance to see if we need
|
// Check the proxy table for this instance to see if we need
|
||||||
@ -189,6 +245,10 @@ HttpProxy.prototype.proxyRequest = function (req, res, port, host, paused) {
|
|||||||
if (this.proxyTable && !host) {
|
if (this.proxyTable && !host) {
|
||||||
location = this.proxyTable.getProxyLocation(req);
|
location = this.proxyTable.getProxyLocation(req);
|
||||||
|
|
||||||
|
//
|
||||||
|
// If no location is returned from the ProxyTable instance
|
||||||
|
// then respond with `404` since we do not have a valid proxy target.
|
||||||
|
//
|
||||||
if (!location) {
|
if (!location) {
|
||||||
res.writeHead(404);
|
res.writeHead(404);
|
||||||
return res.end();
|
return res.end();
|
||||||
@ -198,36 +258,34 @@ HttpProxy.prototype.proxyRequest = function (req, res, port, host, paused) {
|
|||||||
// 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, paused): This will be skipped
|
// * `proxy.proxyRequest(req, res, port, host, paused)`: This will be skipped
|
||||||
// * proxy.proxyRequest(req, res, paused): Paused will get updated appropriately
|
// * `proxy.proxyRequest(req, res, paused)`: Paused will get updated appropriately
|
||||||
// * proxy.proxyRequest(req, res): No effect `undefined = undefined`
|
// * `proxy.proxyRequest(req, res)`: No effect `undefined = undefined`
|
||||||
//
|
//
|
||||||
paused = port;
|
paused = port;
|
||||||
port = location.port;
|
port = location.port;
|
||||||
host = location.host;
|
host = location.host;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// If forwarding is enabled for this instance, foward proxy the
|
||||||
|
// specified request to the address provided in `this.options.forward`
|
||||||
|
//
|
||||||
if (this.options.forward) {
|
if (this.options.forward) {
|
||||||
winston.verbose('Forwarding HTTP request to: ' + this.options.forward.host + ':' + this.options.forward.port);
|
winston.verbose('Forwarding HTTP request to: ' + this.options.forward.host + ':' + this.options.forward.port);
|
||||||
this._forwardRequest(req);
|
this._forwardRequest(req);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create an error handler so we can use it temporarily
|
function proxyError(err) {
|
||||||
function error (obj) {
|
errState = true;
|
||||||
var fn = function (err) {
|
res.writeHead(500, { 'Content-Type': 'text/plain' });
|
||||||
res.writeHead(500, {'Content-Type': 'text/plain'});
|
|
||||||
|
|
||||||
if (req.method !== 'HEAD') {
|
if (req.method !== 'HEAD') {
|
||||||
res.write('An error has occurred: ' + JSON.stringify(err));
|
res.write('An error has occurred: ' + JSON.stringify(err));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Response end may never come so removeListener here
|
|
||||||
obj.removeListener('error', fn);
|
|
||||||
res.end();
|
|
||||||
};
|
|
||||||
|
|
||||||
return fn;
|
res.end();
|
||||||
};
|
}
|
||||||
|
|
||||||
// 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({
|
reverseProxy = http.request({
|
||||||
@ -263,26 +321,31 @@ HttpProxy.prototype.proxyRequest = function (req, res, port, host, paused) {
|
|||||||
|
|
||||||
// Add event listener for end of proxied response
|
// Add event listener for end of proxied response
|
||||||
response.on('end', function () {
|
response.on('end', function () {
|
||||||
reverseProxy.removeListener('error', reverseProxyError);
|
if (!errState) {
|
||||||
res.end();
|
reverseProxy.removeListener('error', proxyError);
|
||||||
|
res.end();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Add a listener for the connection timeout event
|
// Add a listener for the connection timeout event
|
||||||
var reverseProxyError = error(reverseProxy);
|
reverseProxy.once('error', proxyError);
|
||||||
reverseProxy.on('error', reverseProxyError);
|
|
||||||
|
|
||||||
// Chunk the client request body as chunks from the proxied request come in
|
// Chunk the client request body as chunks from the proxied request come in
|
||||||
req.on('data', function (chunk) {
|
req.on('data', function (chunk) {
|
||||||
reverseProxy.write(chunk);
|
if (!errState) {
|
||||||
|
reverseProxy.write(chunk);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// At the end of the client request, we are going to stop the proxied request
|
// At the end of the client request, we are going to stop the proxied request
|
||||||
req.on('end', function () {
|
req.on('end', function () {
|
||||||
reverseProxy.end();
|
if (!errState) {
|
||||||
|
reverseProxy.end();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (paused) {
|
if (paused && !errState) {
|
||||||
paused.resume();
|
paused.resume();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -308,11 +371,12 @@ HttpProxy.prototype._forwardRequest = function (req) {
|
|||||||
//
|
//
|
||||||
});
|
});
|
||||||
|
|
||||||
// Add a listener for the connection timeout event
|
// Add a listener for the connection timeout event.
|
||||||
forwardProxy.on('error', function (err) {
|
//
|
||||||
// Remark: Ignoring this error in the event
|
// Remark: Ignoring this error in the event
|
||||||
// forward target doesn't exist.
|
// forward target doesn't exist.
|
||||||
});
|
//
|
||||||
|
forwardProxy.on('error', function (err) { });
|
||||||
|
|
||||||
// Chunk the client request body as chunks from the proxied request come in
|
// Chunk the client request body as chunks from the proxied request come in
|
||||||
req.on('data', function (chunk) {
|
req.on('data', function (chunk) {
|
||||||
|
|||||||
@ -26,7 +26,8 @@
|
|||||||
|
|
||||||
var util = require('util'),
|
var util = require('util'),
|
||||||
events = require('events'),
|
events = require('events'),
|
||||||
fs = require('fs');
|
fs = require('fs'),
|
||||||
|
winston = require('winston');
|
||||||
|
|
||||||
//
|
//
|
||||||
// ### function ProxyTable (router, silent)
|
// ### function ProxyTable (router, silent)
|
||||||
@ -109,9 +110,7 @@ ProxyTable.prototype.getProxyLocation = function (req) {
|
|||||||
host = location[0],
|
host = location[0],
|
||||||
port = location.length === 1 ? 80 : location[1];
|
port = location.length === 1 ? 80 : location[1];
|
||||||
|
|
||||||
if (!this.silent) {
|
winston.verbose('Proxy Table proxying request to: ' + host + ':' + port);
|
||||||
util.log('Proxy Table proxying request to: ' + host + ':' + port);
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
port: port,
|
port: port,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user