diff --git a/LICENSE b/LICENSE index 3db72a663..19d4a54c1 100644 --- a/LICENSE +++ b/LICENSE @@ -1,7 +1,7 @@ node-http-proxy - Copyright (c) 2010 Charlie Robbins & Marak Squires http://github.com/nodejitsu/node-http-proxy + Copyright (c) 2010 Charlie Robbins, Mikeal Rogers, & Marak Squires Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the diff --git a/README.md b/README.md index 18fb61702..5a1f6bd54 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# node-http-proxy - v0.1.5 +# node-http-proxy - v0.3.0 @@ -19,7 +19,6 @@ Let's suppose you were running multiple http application servers, but you only wanted to expose one machine to the internet. You could setup node-http-proxy on that one machine and then reverse-proxy the incoming http requests to locally running services which were not exposed to the outside network. - ### Installing npm (node package manager)
   curl http://npmjs.org/install.sh | sh
@@ -44,7 +43,7 @@ Let's suppose you were running multiple http application servers, but you only w
   }).listen(9000);
 
-see the [demo](http://github.com/nodejitsu/node-http-proxy/blob/master/demo.js) for further examples. +See the [demo](http://github.com/nodejitsu/node-http-proxy/blob/master/demo.js) for further examples. ### How to setup a proxy server with custom server logic
@@ -54,7 +53,27 @@ see the [demo](http://github.com/nodejitsu/node-http-proxy/blob/master/demo.js)
   // create a proxy server with custom application logic
   httpProxy.createServer(function (req, res, proxy) {
     // Put your custom server logic here
-    proxy.proxyRequest(9000, 'localhost', req, res);
+    proxy.proxyRequest(9000, 'localhost');
+  }).listen(8000);
+
+  http.createServer(function (req, res){
+    res.writeHead(200, {'Content-Type': 'text/plain'});
+    res.write('request successfully proxied: ' + req.url +'\n' + JSON.stringify(req.headers, true, 2));
+    res.end();
+  }).listen(9000);
+
+ +### How to setup a proxy server with latency (e.g. IO, etc) +
+  var http = require('http'),
+      httpProxy = require('http-proxy');
+
+  // create a proxy server with custom application logic
+  httpProxy.createServer(function (req, res, proxy) {
+    // Wait for two seconds then respond
+    setTimeout(function () {
+      proxy.proxyRequest(9000, 'localhost');      
+    }, 2000);
   }).listen(8000);
 
   http.createServer(function (req, res){
@@ -62,7 +81,6 @@ see the [demo](http://github.com/nodejitsu/node-http-proxy/blob/master/demo.js)
     res.write('request successfully proxied: ' + req.url +'\n' + JSON.stringify(req.headers, true, 2));
     res.end();
   }).listen(9000);
-  
 
### How to proxy requests with a regular http server @@ -72,9 +90,14 @@ see the [demo](http://github.com/nodejitsu/node-http-proxy/blob/master/demo.js) // create a regular http server and proxy its handler http.createServer(function (req, res){ - var proxy = new httpProxy.HttpProxy; - proxy.watch(req, res); - // Put your custom server logic here + // Create a new instance of HttProxy for this request + // each instance is only valid for serving one request + // + // Don't worry benchmarks show the object + // creation is lightning fast + var proxy = new httpProxy.HttpProxy(req, res); + + // Put your custom server logic here, then proxy proxy.proxyRequest(9000, 'localhost', req, res); }).listen(8001); @@ -82,20 +105,19 @@ see the [demo](http://github.com/nodejitsu/node-http-proxy/blob/master/demo.js) res.writeHead(200, {'Content-Type': 'text/plain'}); res.write('request successfully proxied: ' + req.url +'\n' + JSON.stringify(req.headers, true, 2)); res.end(); - }).listen(9000); - + }).listen(9000); ### Why doesn't node-http-proxy have more advanced features like x, y, or z? If you have a suggestion for a feature currently not supported, feel free to open a [support issue](http://github.com/nodejitsu/node-http-proxy/issues). node-http-proxy is designed to just proxy http requests from one server to another, but we will be soon releasing many other complimentary projects that can be used in conjunction with node-http-proxy. -

+
### License (The MIT License) -Copyright (c) 2010 Charlie Robbins & Marak Squires http://github.com/nodejitsu/ +Copyright (c) 2010 Charlie Robbins, Mikeal Rogers, & Marak Squires Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the @@ -116,4 +138,4 @@ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -[0]:http://nodejitsu.com "nodejitsu.com" \ No newline at end of file +[0]: http://nodejitsu.com \ No newline at end of file diff --git a/benchmarks/http-server-base b/benchmarks/http-server-base index e047e4a0d..a880fd3bd 100644 --- a/benchmarks/http-server-base +++ b/benchmarks/http-server-base @@ -1,4 +1,4 @@ - [Marak@Maraks-MacBook-Pro ~/dev/zalgo.js]$ ab -c 50 -n 1000 -k http://127.0.0.1:9000/ +$ ab -c 50 -n 1000 -k http://127.0.0.1:9000/ This is ApacheBench, Version 2.3 <$Revision: 655654 $> Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/ Licensed to The Apache Software Foundation, http://www.apache.org/ diff --git a/benchmarks/proxy-to-http b/benchmarks/proxy-to-http index 3d2bc33ed..d6e354bfa 100644 --- a/benchmarks/proxy-to-http +++ b/benchmarks/proxy-to-http @@ -1,4 +1,4 @@ - [Marak@Maraks-MacBook-Pro ~]$ ab -c 5 -n 1000 http://127.0.0.1:8000/ +$ ab -c 5 -n 1000 http://127.0.0.1:8000/ This is ApacheBench, Version 2.3 <$Revision: 655654 $> Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/ Licensed to The Apache Software Foundation, http://www.apache.org/ @@ -22,35 +22,35 @@ Server Hostname: 127.0.0.1 Server Port: 8000 Document Path: / -Document Length: 155 bytes +Document Length: 160 bytes Concurrency Level: 5 -Time taken for tests: 0.602 seconds +Time taken for tests: 0.450 seconds Complete requests: 1000 -Failed requests: 5 - (Connect: 0, Receive: 0, Length: 5, Exceptions: 0) +Failed requests: 1 + (Connect: 0, Receive: 0, Length: 1, Exceptions: 0) Write errors: 0 -Total transferred: 247030 bytes -HTML transferred: 155030 bytes -Requests per second: 1660.64 [#/sec] (mean) -Time per request: 3.011 [ms] (mean) -Time per request: 0.602 [ms] (mean, across all concurrent requests) -Transfer rate: 400.61 [Kbytes/sec] received +Total transferred: 252006 bytes +HTML transferred: 160006 bytes +Requests per second: 2219.97 [#/sec] (mean) +Time per request: 2.252 [ms] (mean) +Time per request: 0.450 [ms] (mean, across all concurrent requests) +Transfer rate: 546.33 [Kbytes/sec] received Connection Times (ms) min mean[+/-sd] median max -Connect: 0 0 0.1 0 1 -Processing: 2 3 0.8 3 10 -Waiting: 2 3 0.8 3 10 -Total: 2 3 0.8 3 10 +Connect: 0 0 0.0 0 0 +Processing: 1 2 0.9 2 10 +Waiting: 1 2 0.9 2 10 +Total: 1 2 0.9 2 10 Percentage of the requests served within a certain time (ms) - 50% 3 - 66% 3 + 50% 2 + 66% 2 75% 3 80% 3 90% 3 - 95% 4 - 98% 5 - 99% 9 - 100% 10 (longest request) + 95% 3 + 98% 3 + 99% 7 + 100% 10 (longest request) \ No newline at end of file diff --git a/demo.js b/demo.js index fcf16f998..cbc22766b 100644 --- a/demo.js +++ b/demo.js @@ -45,23 +45,22 @@ httpProxy.createServer(9000, 'localhost').listen(8000); sys.puts('http proxy server'.blue + ' started '.green.bold + 'on port '.blue + '8000'.yellow); /****** http proxy server with latency******/ -/*httpProxy.createServer(function (req, res, proxy){ +httpProxy.createServer(function (req, res, proxy){ setTimeout(function(){ - proxy.proxyRequest(9000, 'localhost', req, res); + proxy.proxyRequest(9000, 'localhost'); }, 200) }).listen(8001); -sys.puts('http proxy server '.blue + 'started '.green.bold + 'on port '.blue + '8001 '.yellow + 'with latency'.magenta.underline );*/ +sys.puts('http proxy server '.blue + 'started '.green.bold + 'on port '.blue + '8001 '.yellow + 'with latency'.magenta.underline ); /****** http server with proxyRequest handler and latency******/ -/*http.createServer(function (req, res){ - var proxy = new httpProxy.HttpProxy; - proxy.watch(req, res); +http.createServer(function (req, res){ + var proxy = new httpProxy.HttpProxy(req, res); setTimeout(function(){ - proxy.proxyRequest(9000, 'localhost', req, res); + proxy.proxyRequest(9000, 'localhost'); }, 200); }).listen(8002); -sys.puts('http server '.blue + 'started '.green.bold + 'on port '.blue + '8002 '.yellow + 'with proxyRequest handler'.cyan.underline + ' and latency'.magenta);*/ +sys.puts('http server '.blue + 'started '.green.bold + 'on port '.blue + '8002 '.yellow + 'with proxyRequest handler'.cyan.underline + ' and latency'.magenta); /****** regular http server ******/ http.createServer(function (req, res){ diff --git a/lib/node-http-proxy.js b/lib/node-http-proxy.js index c7c3f0eb5..c70f33cd5 100644 --- a/lib/node-http-proxy.js +++ b/lib/node-http-proxy.js @@ -26,8 +26,6 @@ var sys = require('sys'), http = require('http'), - eyes = require('eyes'), - pool = require('pool'), events = require('events'), pool = require('pool'), min = 0, @@ -48,6 +46,10 @@ exports.createServer = function () { var server = http.createServer(function (req, res){ var proxy = new HttpProxy(req, res); + proxy.emitter.on('proxy', function (err, body) { + server.emit('proxy', err, body); + }); + // If we were passed a callback to process the request // or response in some way, then call it. if(callback) { @@ -110,7 +112,7 @@ HttpProxy.prototype = { // Rebroadcast any events that have been buffered for (var i = 0, len = this.events.length; i < len; ++i) { - req.emit.apply(req, this.events[i]); + req.emit.apply(req, this.events[i]); } }, @@ -133,6 +135,7 @@ HttpProxy.prototype = { res.end(); }; + // Add a listener for the connection timeout event reverse_proxy.connection.addListener('error', error); @@ -157,8 +160,7 @@ HttpProxy.prototype = { // Add event listener for end of proxied response response.addListener('end', function () { // Remark: Emit the end event for testability - self.emitter.emit('end', null, self.body); - + self.emitter.emit('proxy', null, self.body); res.end(); }); }); @@ -179,57 +181,4 @@ HttpProxy.prototype = { } }; -exports.HttpProxy = HttpProxy; - -/*// Create an error handler so we can use it temporarily -var error = function (err) { - res.writeHead(200, {'Content-Type': 'text/plain'}); - - if(req.method !== 'HEAD') { - res.write('An error has occurred: ' + sys.puts(JSON.stringify(err))); - } - - res.end(); -}; -// Add a listener for the connection timeout event -reverse_proxy.connection.addListener('error', error); - -// Add a listener for the reverse_proxy response event -reverse_proxy.addListener('response', function (response) { - if (response.headers.connection) { - if (req.headers.connection) response.headers.connection = req.headers.connection; - else response.headers.connection = 'close'; - } - - // Set the response headers of the client response - res.writeHead(response.statusCode, response.headers); - - // Add event handler for the proxied response in chunks - response.addListener('data', function (chunk) { - if(req.method !== 'HEAD') { - res.write(chunk, 'binary'); - self.body += chunk; - } - }); - - // Add event listener for end of proxied response - response.addListener('end', function () { - // Remark: Emit the end event for testability - self.emitter.emit('end', null, self.body); - - res.end(); - }); -}); - -// Chunk the client request body as chunks from the proxied request come in -req.addListener('data', function (chunk) { - reverse_proxy.write(chunk, 'binary'); -}) - -// At the end of the client request, we are going to stop the proxied request -req.addListener('end', function () { - reverse_proxy.end(); - //reverse_proxy.connection.removeListener('error', error); -}); - -self.unwatch(req);*/ +exports.HttpProxy = HttpProxy; \ No newline at end of file diff --git a/package.json b/package.json index 07b9a930e..ffd3a74f4 100644 --- a/package.json +++ b/package.json @@ -1,9 +1,10 @@ { "name": "http-proxy", "description": "A full-featured http reverse proxy for node.js", - "version": "0.1.6", + "version": "0.3.0", "author": "Charlie Robbins ", - "contributors": [ + "contributors": [ + { "name": "Mikeal Rogers", "email": 'mikeal.rogers@gmail.com' }, { "name": "Marak Squires", "email": "marak.squires@gmail.com" } ], "repository": { @@ -12,9 +13,10 @@ }, "keywords": ["reverse", "proxy", "http"], "dependencies": { - "colors": ">= 0.3.0" + "colors": ">= 0.3.0", + "pool": ">= 0.4.1" }, "main": "./lib/node-http-proxy", "scripts": { "test": "vows" }, - "engines": { "node": ">= 0.1.98" } + "engines": { "node": ">= 0.2.0" } } \ No newline at end of file diff --git a/test/node-http-proxy-test.js b/test/node-http-proxy-test.js index 4880bdf78..ac786ffcb 100644 --- a/test/node-http-proxy-test.js +++ b/test/node-http-proxy-test.js @@ -29,14 +29,14 @@ var vows = require('vows'), assert = require('assert'), http = require('http'); -var httpProxy = require('http-proxy'); +var httpProxy = require('./../lib/node-http-proxy'); var testServers = {}; // // Creates the reverse proxy server // -var startProxyServer = function (port, server, proxy) { - var proxyServer = proxy.createServer(port, server); +var startProxyServer = function (port, server) { + var proxyServer = httpProxy.createServer(port, server); proxyServer.listen(8080); return proxyServer; }; @@ -44,11 +44,11 @@ var startProxyServer = function (port, server, proxy) { // // Creates the reverse proxy server with a specified latency // -var startLatentProxyServer = function (port, server, proxy, latency) { +var startLatentProxyServer = function (port, server, latency) { // Initialize the nodeProxy and start proxying the request - var proxyServer = proxy.createServer(function (req, res, proxy) { + var proxyServer = httpProxy.createServer(function (req, res, proxy) { setTimeout(function () { - proxy.proxyRequest(port, server, req, res); + proxy.proxyRequest(port, server); }, latency); }); @@ -73,19 +73,29 @@ var startTargetServer = function (port) { // // The default test bootstrapper with no latency // -var startTest = function (proxy, port) { +var startTest = function (port) { + var proxyServer = startProxyServer(port, 'localhost'), + targetServer = startTargetServer(port); + testServers.noLatency = []; - testServers.noLatency.push(startProxyServer(port, 'localhost', proxy)); - testServers.noLatency.push(startTargetServer(port)); + testServers.noLatency.push(proxyServer); + testServers.noLatency.push(targetServer); + + return proxyServer; }; // // The test bootstrapper with some latency // -var startTestWithLatency = function (proxy, port) { +var startTestWithLatency = function (port) { + var proxyServer = startLatentProxyServer(port, 'localhost', 2000), + targetServer = startTargetServer(port); + testServers.latency = []; - testServers.latency.push(startLatentProxyServer(port, 'localhost', proxy, 2000)); - testServers.latency.push(startTargetServer(port)); + testServers.latency.push(proxyServer); + testServers.latency.push(targetServer); + + return proxyServer; }; vows.describe('node-http-proxy').addBatch({ @@ -94,9 +104,8 @@ vows.describe('node-http-proxy').addBatch({ "and an incoming request is proxied to the helloNode server" : { "with no latency" : { topic: function () { - var proxy = new (httpProxy.HttpProxy); - startTest(proxy, 8082); - proxy.emitter.addListener('end', this.callback); + var proxy = startTest(8082); + proxy.addListener('proxy', this.callback); var client = http.createClient(8080, 'localhost'); var request = client.request('GET', '/'); @@ -111,9 +120,8 @@ vows.describe('node-http-proxy').addBatch({ }, "with latency": { topic: function () { - var proxy = new (httpProxy.HttpProxy); - startTestWithLatency(proxy, 8083); - proxy.emitter.addListener('end', this.callback); + var proxy = startTestWithLatency(8083); + proxy.addListener('proxy', this.callback); var client = http.createClient(8081, 'localhost'); var request = client.request('GET', '/');