http-proxy
Advanced tools
Comparing version 0.8.0 to 0.8.1
## ChangeLog for: node-http-proxy | ||
## Version 0.8.1 - 6/5/2012 | ||
- Fix re-emitting of events in RoutingProxy (coderarity) | ||
- New load balancer and middleware examples (marak) | ||
- Docs updated including changelog (lot of gently people) | ||
## Version 0.8.0 - 12/23/2011 | ||
- Improve support and tests for url segment routing (maxogden) | ||
- Fix aborting connections when request close (c4milo) | ||
- Avoid 'Transfer-Encoding' on HTTP/1.0 clients (koichik). | ||
- Support for Node.js 0.6.x (mmalecki) | ||
## Version 0.7.3 - 10/4/2011 | ||
- Fix setting x-forwarded headers (jesusabdullah) | ||
- Updated examples (AvianFlu) | ||
## Version 0.7.0 - 9/10/2011 | ||
- Handles to every throw-able resume() call (isaacs) | ||
- Updated tests, README and package.json (indexzero) | ||
- Added HttpProxy.close() method (indexzero) | ||
## Version 0.6.6 - 8/31/2011 | ||
- Add more examples (dominictarr) | ||
- Use of 'pkginfo' (indexzero) | ||
- Handle cases where res.write throws (isaacs) | ||
- Handles to every throw-able res.end call (isaacs) | ||
## Version 0.5.11 - 6/21/2011 | ||
- Add more examples with WebSockets (indexzero) | ||
- Update the documentation (indexzero) | ||
## Version 0.5.7 - 5/19/2011 | ||
- Fix to README related to markup and fix some examples (benatkin) | ||
- Improve WebSockets handling (indexzero) | ||
- Improve WebSockets tests (indexzero) | ||
- Improve https tests (olauzon) | ||
- Add devDependencies to package.json (olauzon) | ||
- Add 'proxyError' event (indexzero) | ||
- Add 'x-forwarded-{port|proto}' headers support (indexzero) | ||
- Keep-Alive connection supported (indexzero) | ||
## Version 0.5.0 - 4/15/2011 | ||
@@ -4,0 +44,0 @@ - Remove winston in favor of custom events (indexzero) |
@@ -37,3 +37,3 @@ /* | ||
// | ||
// Crete the target HTTPS server | ||
// Create the target HTTPS server | ||
// | ||
@@ -47,3 +47,3 @@ http.createServer(function (req, res) { | ||
// | ||
// Create the proxy server listening on port 443. | ||
// Create the proxy server listening on port 443 | ||
// | ||
@@ -50,0 +50,0 @@ httpProxy.createServer(8000, 'localhost', { |
@@ -37,3 +37,3 @@ /* | ||
// | ||
// Crete the target HTTPS server | ||
// Create the target HTTPS server | ||
// | ||
@@ -47,3 +47,3 @@ https.createServer(opts, function (req, res) { | ||
// | ||
// Create the proxy server listening on port 443. | ||
// Create the proxy server listening on port 443 | ||
// | ||
@@ -50,0 +50,0 @@ httpProxy.createServer(8000, 'localhost', { |
@@ -151,3 +151,3 @@ /* | ||
if (req.headers['x-forwarded-proto']){ | ||
var protoToAppend = "," + req.connection.pair ? 'https' : 'http'; | ||
var protoToAppend = "," + (req.connection.pair) ? 'https' : 'http'; | ||
req.headers['x-forwarded-proto'] += protoToAppend; | ||
@@ -257,43 +257,20 @@ } | ||
// | ||
// For each data `chunk` received from the `reverseProxy` | ||
// `response` write it to the outgoing `res`. | ||
// If the res socket has been killed already, then write() | ||
// will throw. Nevertheless, try our best to end it nicely. | ||
// | ||
var paused = false; | ||
response.on('data', function (chunk) { | ||
if (req.method !== 'HEAD' && res.writable) { | ||
try { | ||
var flushed = res.write(chunk); | ||
} | ||
catch (ex) { | ||
console.error("res.write error: %s", ex.message); | ||
try { res.end() } | ||
catch (ex) { console.error("res.end error: %s", ex.message) } | ||
return; | ||
} | ||
if (!flushed && !paused) { | ||
paused = true; | ||
function ondata(chunk) { | ||
if (res.writable) { | ||
if (false === res.write(chunk) && response.pause) { | ||
response.pause(); | ||
res.once('drain', function () { | ||
paused = false; | ||
try { response.resume() } | ||
catch (er) { console.error("response.resume error: %s", er.message) } | ||
}); | ||
// | ||
// Force the `drain` event in 100ms if it hasn't | ||
// happened on its own. | ||
// | ||
setTimeout(function () { | ||
res.emit('drain'); | ||
}, 100); | ||
} | ||
} | ||
}); | ||
} | ||
response.on('data', ondata); | ||
function ondrain() { | ||
if (response.readable && response.resume) { | ||
response.resume(); | ||
} | ||
} | ||
res.on('drain', ondrain); | ||
// | ||
@@ -443,3 +420,3 @@ // When the `reverseProxy` `response` ends, end the | ||
if (req.headers['x-forwarded-proto']){ | ||
var protoToAppend = "," + req.connection.pair ? 'wss' : 'ws'; | ||
var protoToAppend = "," + (req.connection.pair) ? 'wss' : 'ws'; | ||
req.headers['x-forwarded-proto'] += protoToAppend; | ||
@@ -446,0 +423,0 @@ } |
@@ -29,3 +29,4 @@ /* | ||
events = require('events'), | ||
fs = require('fs'); | ||
fs = require('fs'), | ||
url = require('url'); | ||
@@ -141,14 +142,14 @@ // | ||
if (target.match(route.route)) { | ||
var pathSegments = route.path.split('/'); | ||
if (pathSegments.length > 1) { | ||
// don't include the proxytable path segments in the proxied request url | ||
pathSegments = new RegExp("/" + pathSegments.slice(1).join('/')); | ||
req.url = req.url.replace(pathSegments, ''); | ||
} | ||
var location = route.target.split(':'), | ||
host = location[0], | ||
port = location.length === 1 ? 80 : location[1]; | ||
var requrl = url.parse(req.url); | ||
//add the 'http://'' to get around a url.parse bug, it won't actually be used. | ||
var targeturl = url.parse('http://'+route.target); | ||
var pathurl = url.parse('http://'+route.path); | ||
//This replaces the path's part of the URL to the target's part of the URL. | ||
requrl.pathname = requrl.pathname.replace(pathurl.pathname, targeturl.pathname); | ||
req.url = url.format(requrl); | ||
var host = targeturl.hostname, | ||
port = targeturl.port || 80; | ||
return { | ||
@@ -155,0 +156,0 @@ port: port, |
@@ -26,3 +26,3 @@ /* | ||
options = options || {}; | ||
if (options.router) { | ||
@@ -34,15 +34,15 @@ this.proxyTable = new ProxyTable(options); | ||
} | ||
// | ||
// Create a set of `HttpProxy` objects to be used later on calls | ||
// Create a set of `HttpProxy` objects to be used later on calls | ||
// to `.proxyRequest()` and `.proxyWebSocketRequest()`. | ||
// | ||
this.proxies = {}; | ||
// | ||
// Setup default target options (such as `https`). | ||
// | ||
this.target = {}; | ||
this.target = {}; | ||
this.target.https = options.target && options.target.https; | ||
// | ||
@@ -56,2 +56,14 @@ // Setup other default options to be used for instances of | ||
this.forward = options.forward; | ||
// | ||
// Listen for 'newListener' events so that we can bind 'proxyError' | ||
// listeners to each HttpProxy's 'proxyError' event. | ||
// | ||
this.on('newListener', function (evt) { | ||
if (evt === 'proxyError' || evt === 'webSocketProxyError') { | ||
Object.keys(self.proxies).forEach(function (key) { | ||
self.proxies[key].on(evt, this.emit.bind(this, evt)); | ||
}); | ||
} | ||
}); | ||
}; | ||
@@ -74,3 +86,3 @@ | ||
key = this._getKey(options); | ||
// | ||
@@ -82,9 +94,9 @@ // TODO: Consume properties in `options` related to the `ProxyTable`. | ||
options.target.port = options.target.port || options.port; | ||
options.target.https = this.target && this.target.https || | ||
options.target && options.target.https || | ||
options.target.https = this.target && this.target.https || | ||
options.target && options.target.https || | ||
options.https; | ||
// | ||
// Setup options to pass-thru to the new `HttpProxy` instance | ||
// for the specified `options.host` and `options.port` pair. | ||
// for the specified `options.host` and `options.port` pair. | ||
// | ||
@@ -96,6 +108,13 @@ ['https', 'enable', 'forward'].forEach(function (key) { | ||
}); | ||
this.proxies[key] = new HttpProxy(options); | ||
this.proxies[key].on('proxyError', this.emit.bind(this, 'proxyError')); | ||
this.proxies[key].on('webSocketProxyError', this.emit.bind(this, 'webSocketProxyError')); | ||
if (this.listeners('proxyError').length > 0) { | ||
this.proxies[key].on('proxyError', this.emit.bind(this, 'proxyError')); | ||
} | ||
if (this.listeners('webSocketProxyError').length > 0) { | ||
this.proxies[key].on('webSocketProxyError', this.emit.bind(this, 'webSocketProxyError')); | ||
} | ||
this.proxies[key].on('start', this.emit.bind(this, 'start')); | ||
this.proxies[key].on('forward', this.emit.bind(this, 'forward')); | ||
this.proxies[key].on('end', this.emit.bind(this, 'end')); | ||
}; | ||
@@ -120,6 +139,6 @@ | ||
var self = this; | ||
if (this.proxyTable) { | ||
// | ||
// Close the `RoutingTable` associated with | ||
// Close the `RoutingTable` associated with | ||
// this instance (if any). | ||
@@ -129,6 +148,6 @@ // | ||
} | ||
// | ||
// Close all sockets for all `HttpProxy` object(s) | ||
// associated with this instance. | ||
// associated with this instance. | ||
// | ||
@@ -171,7 +190,7 @@ Object.keys(this.proxies).forEach(function (key) { | ||
res.end(); | ||
} | ||
} | ||
catch (er) { | ||
console.error("res.writeHead/res.end error: %s", er.message); | ||
} | ||
return; | ||
@@ -191,11 +210,10 @@ } | ||
} | ||
var key = this._getKey(options), | ||
proxy; | ||
if (!this.proxies[key]) { | ||
this.add(options); | ||
} | ||
} | ||
proxy = this.proxies[key]; | ||
@@ -219,3 +237,3 @@ proxy.proxyRequest(req, res, options.buffer); | ||
options = options || {}; | ||
if (this.proxyTable && !options.host) { | ||
@@ -231,3 +249,3 @@ location = this.proxyTable.getProxyLocation(req); | ||
} | ||
var key = this._getKey(options), | ||
@@ -240,3 +258,3 @@ proxy; | ||
proxy = this.proxies[key]; | ||
proxy = this.proxies[key]; | ||
proxy.proxyWebSocketRequest(req, socket, head, options.buffer); | ||
@@ -253,3 +271,3 @@ }; | ||
RoutingProxy.prototype._getKey = function (options) { | ||
if (!options || ((!options.host || !options.port) | ||
if (!options || ((!options.host || !options.port) | ||
&& (!options.target || !options.target.host || !options.target.port))) { | ||
@@ -261,5 +279,5 @@ throw new Error('options.host and options.port or options.target are required.'); | ||
return [ | ||
options.host || options.target.host, | ||
options.host || options.target.host, | ||
options.port || options.target.port | ||
].join(':'); | ||
} |
{ | ||
"name": "http-proxy", | ||
"version": "0.8.0", | ||
"version": "0.8.1", | ||
"description": "A full-featured http reverse proxy for node.js", | ||
"author": "Charlie Robbins <charlie.robbins@gmail.com>", | ||
"contributors": [ | ||
{ "name": "Mikeal Rogers", "email": "mikeal.rogers@gmail.com" }, | ||
{ "name": "Marak Squires", "email": "marak.squires@gmail.com" }, | ||
{ "name": "Fedor Indutny", "email": "fedor.indutny@gmail.com" }, | ||
{ "name": "Dominic Tarr", "email": "dominic@nodejitsu.com" } | ||
"author": "Nodejitsu Inc. <info@nodejitsu.com>", | ||
"maintainers": [ | ||
"indexzero <charlie@nodejitsu.com>", | ||
"AvianFlu <avianflu@nodejitsu.com>" | ||
], | ||
"repository": { | ||
"type": "git", | ||
"url": "http://github.com/nodejitsu/node-http-proxy.git" | ||
"url": "http://github.com/nodejitsu/node-http-proxy.git" | ||
}, | ||
"keywords": ["reverse", "proxy", "http"], | ||
"keywords": [ | ||
"reverse", | ||
"proxy", | ||
"http" | ||
], | ||
"dependencies": { | ||
@@ -26,7 +28,9 @@ "colors": "0.x.x", | ||
"async": "0.1.x", | ||
"socket.io": "0.6.x" | ||
"socket.io": "0.6.17" | ||
}, | ||
"main": "./lib/node-http-proxy", | ||
"bin": { "node-http-proxy": "./bin/node-http-proxy" }, | ||
"scripts": { | ||
"bin": { | ||
"node-http-proxy": "./bin/node-http-proxy" | ||
}, | ||
"scripts": { | ||
"test": "npm run-script test-http && npm run-script test-https && npm run-script test-core", | ||
@@ -37,3 +41,6 @@ "test-http": "vows --spec && vows --spec --target=secure", | ||
}, | ||
"engines": { "node": ">= 0.6.6" } | ||
"engines": { | ||
"node": ">= 0.6.6" | ||
} | ||
} | ||
@@ -220,3 +220,29 @@ # node-http-proxy | ||
### Listening for proxy events | ||
Sometimes you want to listen to an event on a proxy. For example, you may want to listen to the 'end' event, which represents when the proxy has finished proxying a request. | ||
``` js | ||
var httpProxy = require('http-proxy'); | ||
var server = httpProxy.createServer(function (req, res, proxy) { | ||
var buffer = httpProxy.buffer(req); | ||
proxy.proxyRequest(req, res, { | ||
host: '127.0.0.1', | ||
port: 9000, | ||
buffer: buffer | ||
}); | ||
}); | ||
server.proxy.on('end', function() { | ||
console.log("The request was proxied."); | ||
}); | ||
server.listen(8000); | ||
``` | ||
It's important to remember not to listen for events on the proxy object in the function passed to `httpProxy.createServer`. Doing so would add a new listener on every request, which would end up being a disaster. | ||
## Using HTTPS | ||
@@ -339,7 +365,8 @@ You have all the full flexibility of node-http-proxy offers in HTTPS as well as HTTP. The two basic scenarios are: with a stand-alone proxy server or in conjunction with another HTTPS server. | ||
// | ||
var proxy = new httpProxy.HttpProxy( | ||
target: { | ||
host: 'localhost', | ||
port: 8000 | ||
}); | ||
var proxy = new httpProxy.HttpProxy({ | ||
target: { | ||
host: 'localhost', | ||
port: 8000 | ||
} | ||
}); | ||
@@ -359,2 +386,4 @@ var server = http.createServer(function (req, res) { | ||
}); | ||
server.listen(8080); | ||
``` | ||
@@ -369,2 +398,8 @@ | ||
## POST requests and buffering | ||
express.bodyParser will interfere with proxying of POST requests (and other methods that have a request | ||
body). With bodyParser active, proxied requests will never send anything to the upstream server, and | ||
the original client will just hang. See https://github.com/nodejitsu/node-http-proxy/issues/180 for options. | ||
## Using node-http-proxy from the command line | ||
@@ -433,7 +468,7 @@ When you install this package with npm, a node-http-proxy binary will become available to you. Using this binary is easy with some simple options: | ||
[0]: http://nodejitsu.com | ||
[1]: https://github.com/nodejitsu/node-http-proxy/blob/master/examples/web-socket-proxy.js | ||
[2]: https://github.com/nodejitsu/node-http-proxy/blob/master/examples/basic-proxy-https.js | ||
[3]: https://github.com/nodejitsu/node-http-proxy/tree/v0.5.0/examples | ||
[1]: https://github.com/nodejitsu/node-http-proxy/blob/master/examples/websocket/websocket-proxy.js | ||
[2]: https://github.com/nodejitsu/node-http-proxy/blob/master/examples/http/proxy-https-to-http.js | ||
[3]: https://github.com/nodejitsu/node-http-proxy/tree/master/examples | ||
[4]: http://www.ietf.org/rfc/rfc2616.txt | ||
[5]: http://socket.io | ||
[6]: http://github.com/nodejitsu/node-http-proxy/issues |
@@ -35,2 +35,5 @@ /* | ||
"pizza.com/taco/muffins": "127.0.0.1:8099", | ||
"blah.com/me": "127.0.0.1:8088/remapped", | ||
"bleh.com/remap/this": "127.0.0.1:8087/remap/remapped", | ||
"test.com/double/tap": "127.0.0.1:8086/remap", | ||
} | ||
@@ -57,3 +60,6 @@ }; | ||
"an incoming request to baz.com/taco": runner.assertProxied('baz.com', 8090, 8098, "/taco", "/"), | ||
"an incoming request to pizza.com/taco/muffins": runner.assertProxied('pizza.com', 8090, 8099, "/taco/muffins", "/taco"), | ||
"an incoming request to pizza.com/taco/muffins": runner.assertProxied('pizza.com', 8090, 8099, "/taco/muffins", "/"), | ||
"an incoming request to blah.com/me/fun": runner.assertProxied('blah.com', 8090, 8088, "/me/fun", "/remapped/fun"), | ||
"an incoming request to bleh.com/remap/this": runner.assertProxied('bleh.com', 8090, 8087, "/remap/this", "/remap/remapped"), | ||
"an incoming request to test.com/double/tap/double/tap": runner.assertProxied('test.com', 8090, 8086, "/double/tap/double/tap", "/remap/double/tap"), | ||
"an incoming request to unknown.com": runner.assertResponseCode(8090, 404) | ||
@@ -60,0 +66,0 @@ }, |
@@ -42,3 +42,3 @@ /* | ||
console.error('Socket.io is required for this example:'); | ||
console.error('npm ' + 'install'.green + ' socket.io@0.6.18'.magenta); | ||
console.error('npm ' + 'install'.green + ' socket.io@0.6.17'.magenta); | ||
process.exit(1); | ||
@@ -45,0 +45,0 @@ } |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
391364
5496
470
76