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';
|
||||
util.puts(welcome.rainbow.bold);
|
||||
|
||||
|
||||
//
|
||||
// Basic Http Proxy Server
|
||||
//
|
||||
|
||||
@ -32,7 +32,13 @@ var util = require('util'),
|
||||
ProxyTable = require('./proxy-table').ProxyTable,
|
||||
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) {
|
||||
//
|
||||
// TODO (indexzero): Make this configurable for http / https
|
||||
@ -42,17 +48,33 @@ function _getAgent (host, port) {
|
||||
return agent;
|
||||
}
|
||||
|
||||
//
|
||||
// ### function getMaxSockets ()
|
||||
// Returns the maximum number of sockets
|
||||
// allowed on __every__ outgoing request
|
||||
// made by __all__ instances of `HttpProxy`
|
||||
//
|
||||
exports.getMaxSockets = function () {
|
||||
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) {
|
||||
maxSockets = value;
|
||||
};
|
||||
|
||||
//
|
||||
// ### function createServer ([port, host, options], handler)
|
||||
//
|
||||
//
|
||||
exports.createServer = function () {
|
||||
var args, callback, port, host, forward,
|
||||
silent, proxyTable, options = {};
|
||||
silent, options, proxy, server;
|
||||
|
||||
args = Array.prototype.slice.call(arguments);
|
||||
callback = typeof args[args.length - 1] === 'function' && args.pop();
|
||||
@ -69,9 +91,8 @@ exports.createServer = function () {
|
||||
}
|
||||
}
|
||||
|
||||
var proxy = new HttpProxy(options);
|
||||
|
||||
var server = http.createServer(function (req, res) {
|
||||
proxy = new HttpProxy(options);
|
||||
server = http.createServer(function (req, res) {
|
||||
winston.verbose('Incoming HTTP request to: ' + req.headers.host + req.url);
|
||||
|
||||
// If we were passed a callback to process the request
|
||||
@ -98,13 +119,14 @@ exports.createServer = function () {
|
||||
|
||||
proxy.on('routes', function (routes) {
|
||||
server.emit('routes', routes);
|
||||
})
|
||||
});
|
||||
|
||||
if (!callback) {
|
||||
// WebSocket support: if callback is empty tunnel
|
||||
// websocket request automatically
|
||||
server.on('upgrade', function(req, socket, head) {
|
||||
// Tunnel websocket requests too
|
||||
|
||||
proxy.proxyWebSocketRequest(port, host);
|
||||
});
|
||||
}
|
||||
@ -112,6 +134,25 @@ exports.createServer = function () {
|
||||
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) {
|
||||
events.EventEmitter.call(this);
|
||||
|
||||
@ -127,38 +168,36 @@ var HttpProxy = exports.HttpProxy = function (options) {
|
||||
}
|
||||
};
|
||||
|
||||
// Inherit from events.EventEmitter
|
||||
util.inherits(HttpProxy, events.EventEmitter);
|
||||
|
||||
HttpProxy.prototype.close = function () {
|
||||
if (this.proxyTable) this.proxyTable.close();
|
||||
};
|
||||
|
||||
/**
|
||||
* Pause `data` and `end` events on the given `obj`.
|
||||
* Middleware performing async tasks _should_ utilize
|
||||
* this utility (or similar), to re-emit data once
|
||||
* the async operation has completed, otherwise these
|
||||
* events may be lost.
|
||||
*
|
||||
* var pause = utils.pause(req);
|
||||
* fs.readFile(path, function(){
|
||||
* next();
|
||||
* pause.resume();
|
||||
* });
|
||||
*
|
||||
* @param {Object} obj
|
||||
* @return {Object}
|
||||
* @api public
|
||||
*/
|
||||
//
|
||||
// ### 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
|
||||
// __must__ utilize this utility, to re-emit data once
|
||||
// the async operation has completed, otherwise these
|
||||
// __events will be lost.__
|
||||
//
|
||||
// var pause = httpProxy.pause(req);
|
||||
// fs.readFile(path, function(){
|
||||
// httpProxy.proxyRequest(req, res, host, port, paused);
|
||||
// });
|
||||
//
|
||||
// __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.
|
||||
// This simply chooses to manage the scope of the events on a new Object literal as opposed to
|
||||
// [on the HttpProxy instance](https://github.com/nodejitsu/node-http-proxy/blob/v0.3.1/lib/node-http-proxy.js#L154).
|
||||
//
|
||||
HttpProxy.prototype.pause = function (obj) {
|
||||
var onData, onEnd, events = [];
|
||||
|
||||
// buffer data
|
||||
obj.on('data', onData = function (data, encoding) {
|
||||
events.push(['data', data, encoding]);
|
||||
});
|
||||
|
||||
// buffer end
|
||||
obj.on('end', onEnd = function (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) {
|
||||
var self = this, reverseProxy, location;
|
||||
var self = this, reverseProxy, location, errState = false;
|
||||
|
||||
//
|
||||
// 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) {
|
||||
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) {
|
||||
res.writeHead(404);
|
||||
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
|
||||
// only the following arguments are valid:
|
||||
//
|
||||
// * 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): No effect `undefined = undefined`
|
||||
// * `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)`: No effect `undefined = undefined`
|
||||
//
|
||||
paused = port;
|
||||
port = location.port;
|
||||
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) {
|
||||
winston.verbose('Forwarding HTTP request to: ' + this.options.forward.host + ':' + this.options.forward.port);
|
||||
this._forwardRequest(req);
|
||||
}
|
||||
|
||||
// Create an error handler so we can use it temporarily
|
||||
function error (obj) {
|
||||
var fn = function (err) {
|
||||
res.writeHead(500, {'Content-Type': 'text/plain'});
|
||||
function proxyError(err) {
|
||||
errState = true;
|
||||
res.writeHead(500, { 'Content-Type': 'text/plain' });
|
||||
|
||||
if (req.method !== 'HEAD') {
|
||||
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;
|
||||
};
|
||||
}
|
||||
|
||||
// Open new HTTP request to internal resource with will act as a reverse proxy pass
|
||||
reverseProxy = http.request({
|
||||
@ -263,26 +321,31 @@ HttpProxy.prototype.proxyRequest = function (req, res, port, host, paused) {
|
||||
|
||||
// Add event listener for end of proxied response
|
||||
response.on('end', function () {
|
||||
reverseProxy.removeListener('error', reverseProxyError);
|
||||
if (!errState) {
|
||||
reverseProxy.removeListener('error', proxyError);
|
||||
res.end();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Add a listener for the connection timeout event
|
||||
var reverseProxyError = error(reverseProxy);
|
||||
reverseProxy.on('error', reverseProxyError);
|
||||
reverseProxy.once('error', proxyError);
|
||||
|
||||
// Chunk the client request body as chunks from the proxied request come in
|
||||
req.on('data', function (chunk) {
|
||||
if (!errState) {
|
||||
reverseProxy.write(chunk);
|
||||
}
|
||||
});
|
||||
|
||||
// At the end of the client request, we are going to stop the proxied request
|
||||
req.on('end', function () {
|
||||
if (!errState) {
|
||||
reverseProxy.end();
|
||||
}
|
||||
});
|
||||
|
||||
if (paused) {
|
||||
if (paused && !errState) {
|
||||
paused.resume();
|
||||
}
|
||||
};
|
||||
@ -308,11 +371,12 @@ HttpProxy.prototype._forwardRequest = function (req) {
|
||||
//
|
||||
});
|
||||
|
||||
// Add a listener for the connection timeout event
|
||||
forwardProxy.on('error', function (err) {
|
||||
// Add a listener for the connection timeout event.
|
||||
//
|
||||
// Remark: Ignoring this error in the event
|
||||
// forward target doesn't exist.
|
||||
});
|
||||
//
|
||||
forwardProxy.on('error', function (err) { });
|
||||
|
||||
// Chunk the client request body as chunks from the proxied request come in
|
||||
req.on('data', function (chunk) {
|
||||
|
||||
@ -26,7 +26,8 @@
|
||||
|
||||
var util = require('util'),
|
||||
events = require('events'),
|
||||
fs = require('fs');
|
||||
fs = require('fs'),
|
||||
winston = require('winston');
|
||||
|
||||
//
|
||||
// ### function ProxyTable (router, silent)
|
||||
@ -109,9 +110,7 @@ ProxyTable.prototype.getProxyLocation = function (req) {
|
||||
host = location[0],
|
||||
port = location.length === 1 ? 80 : location[1];
|
||||
|
||||
if (!this.silent) {
|
||||
util.log('Proxy Table proxying request to: ' + host + ':' + port);
|
||||
}
|
||||
winston.verbose('Proxy Table proxying request to: ' + host + ':' + port);
|
||||
|
||||
return {
|
||||
port: port,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user