diff --git a/README.md b/README.md index 3fb06f84a..0aacee39d 100644 --- a/README.md +++ b/README.md @@ -29,14 +29,25 @@ Let's suppose you were running multiple http application servers, but you only w npm install http-proxy -### How to setup a basic proxy server +## Using node-http-proxy + +There are several ways to use node-http-proxy; the library is designed to be flexible so that it can be used by itself, or in conjunction with other node.js libraries / tools: + +1. Standalone HTTP Proxy server +2. Inside of another HTTP server (like Connect) +3. From the command-line as a proxy daemon +4. In conjunction with a Proxy Routing Table + +### Setup a basic stand-alone proxy server
var http = require('http'), httpProxy = require('http-proxy'); + // Create your proxy server httpProxy.createServer(9000, 'localhost').listen(8000); - http.createServer(function (req, res){ + // Create your target server + http.createServer(function (req, res) { res.writeHead(200, {'Content-Type': 'text/plain'}); res.write('request successfully proxied!' + '\n' + JSON.stringify(req.headers, true, 2)); res.end(); @@ -45,7 +56,7 @@ Let's suppose you were running multiple http application servers, but you only w 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 +### Setup a stand-alone proxy server with custom server logicvar http = require('http'), httpProxy = require('http-proxy'); @@ -56,58 +67,73 @@ See the [demo](http://github.com/nodejitsu/node-http-proxy/blob/master/demo.js) proxy.proxyRequest(9000, 'localhost'); }).listen(8000); - http.createServer(function (req, res){ + 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) +### Setup a stand-alone 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 + // Wait for two seconds then respond: this simulates + // performing async actions before proxying a request setTimeout(function () { proxy.proxyRequest(9000, 'localhost'); }, 2000); }).listen(8000); - http.createServer(function (req, res){ + 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 proxy requests with a regular http server +### Proxy requests within another http servervar http = require('http'), httpProxy = require('http-proxy'); // create a regular http server and proxy its handler - http.createServer(function (req, res){ + http.createServer(function (req, res) { // 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); - http.createServer(function (req, res){ + 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);+### Proxy requests using a ProxyTable +A Proxy Table is a simple lookup table that maps incoming requests to proxy target locations. Take a look at an example of the options you need to pass to httpProxy.createServer: ++ var options = { + router: { + 'foo.com': '127.0.0.1:8001', + 'bar.com': '127.0.0.1:8002' + } + }; ++ +The above route table will take incoming requests to 'foo.com' and forward them to '127.0.0.1:8001'. Likewise it will take incoming requests to 'bar.com' and forward them to '127.0.0.1:8002'. The routes themselves are later converted to regular expressions to enable more complex matching functionality. We can create a proxy server with these options by using the following code: ++ var proxyServer = httpProxy.createServer(options); + proxyServer.listen(80); ++ ### 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. diff --git a/demo.js b/demo.js index d46b548e8..9cebe667d 100644 --- a/demo.js +++ b/demo.js @@ -40,30 +40,48 @@ var welcome = '\ sys.puts(welcome.rainbow.bold); -/****** basic http proxy server ******/ +// +// Basic Http Proxy Server +// 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){ - setTimeout(function(){ +// +// Http Proxy Server with Proxy Table +// +httpProxy.createServer({ + router: { + '127.0.0.1': 'localhost:9000' + } +}).listen(8001); +sys.puts('http proxy server '.blue + 'started '.green.bold + 'on port '.blue + '8001 '.yellow + 'with proxy table'.magenta.underline) + +// +// Http Proxy Server with Latency +// +httpProxy.createServer(function (req, res, proxy) { + setTimeout(function() { 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 ); +}).listen(8002); +sys.puts('http proxy server '.blue + 'started '.green.bold + 'on port '.blue + '8002 '.yellow + 'with latency'.magenta.underline); -/****** http server with proxyRequest handler and latency******/ -http.createServer(function (req, res){ +// +// Http Server with proxyRequest Handler and Latency +// +http.createServer(function (req, res) { var proxy = new httpProxy.HttpProxy(req, res); - setTimeout(function(){ + setTimeout(function() { 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); +}).listen(8003); +sys.puts('http server '.blue + 'started '.green.bold + 'on port '.blue + '8003 '.yellow + 'with proxyRequest handler'.cyan.underline + ' and latency'.magenta); -/****** regular http server ******/ -http.createServer(function (req, res){ +// +// Target Http Server +// +http.createServer(function (req, res) { res.writeHead(200, {'Content-Type': 'text/plain'}); res.write('request successfully proxied to: ' + req.url + '\n' + JSON.stringify(req.headers, true, 2)); res.end(); diff --git a/lib/node-http-proxy.js b/lib/node-http-proxy.js index 4758a8896..41f840f9b 100644 --- a/lib/node-http-proxy.js +++ b/lib/node-http-proxy.js @@ -28,6 +28,7 @@ var sys = require('sys'), http = require('http'), events = require('events'), pool = require('./../vendor/pool/main'), + ProxyTable = require('./proxy-table').ProxyTable, min = 0, max = 100; @@ -37,23 +38,43 @@ manager.setMinClients(min); manager.setMaxClients(max); exports.createServer = function () { - var args, callback, port, host; + var args, callback, port, host, options, proxyTable; args = Array.prototype.slice.call(arguments); callback = typeof args[args.length - 1] === 'function' && args.pop(); - if (args[0]) port = args[0]; - if (args[1]) host = args[1]; + + if (args.length >= 2) { + port = args[0]; + host = args[1]; + if (args[2]) options = args[2]; + } else if (args.length === 1) { + options = args[0]; + } + + if (options && options.router) { + proxyTable = new ProxyTable(options.router); + proxyTable.on('updateRoutes', function (routes) { + server.emit('updateRoutes', routes); + }); + } var server = http.createServer(function (req, res) { var proxy = new HttpProxy(req, res); // If we were passed a callback to process the request // or response in some way, then call it. - if(callback) { + if (callback) { callback(req, res, proxy); + } else if (port && host) { + proxy.proxyRequest(port, host); + } else if (proxyTable) { + proxyTable.proxyRequest(proxy); + } else { + throw new Error('Cannot proxy without port, host, or router.') } - else { - proxy.proxyRequest(port, server); - } + }); + + server.on('close', function () { + if (proxyTable) proxyTable.close(); }); if (!callback) { @@ -98,7 +119,7 @@ var HttpProxy = function (req, res, head) { }; HttpProxy.prototype = { - toArray: function (obj){ + toArray: function (obj) { var len = obj.length, arr = new Array(len); for (var i = 0; i < len; ++i) { @@ -149,11 +170,11 @@ HttpProxy.prototype = { var client = http.createClient(port, server); p.request(req.method, req.url, req.headers, function (reverse_proxy) { // Create an error handler so we can use it temporarily - function error(obj) { + function error (obj) { var fn = function (err) { res.writeHead(500, {'Content-Type': 'text/plain'}); - if(req.method !== 'HEAD') { + if (req.method !== 'HEAD') { res.write('An error has occurred: ' + JSON.stringify(err)); } @@ -191,7 +212,7 @@ HttpProxy.prototype = { // Add event handler for the proxied response in chunks response.addListener('data', function (chunk) { - if(req.method !== 'HEAD') { + if (req.method !== 'HEAD') { res.write(chunk, 'binary'); self.body += chunk; } @@ -220,7 +241,6 @@ HttpProxy.prototype = { }); self.unwatch(req); - }); }, @@ -381,7 +401,7 @@ HttpProxy.prototype = { } }); - socket.on('data', listeners._data = function(data){ + socket.on('data', listeners._data = function(data) { // Pass data from client to server try { reverse_proxy.write(data); @@ -414,4 +434,5 @@ HttpProxy.prototype = { } }; -exports.HttpProxy = HttpProxy; \ No newline at end of file +exports.HttpProxy = HttpProxy; +exports.ProxyTable = ProxyTable; \ No newline at end of file diff --git a/lib/proxy-table.js b/lib/proxy-table.js new file mode 100644 index 000000000..c7d4ea3b6 --- /dev/null +++ b/lib/proxy-table.js @@ -0,0 +1,108 @@ +/* + node-http-proxy.js: Lookup table for proxy targets in node.js + + Copyright (c) 2010 Charlie Robbins + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + 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. + +*/ + +var util = require('util'), + events = require('events'), + fs = require('fs'); + +var ProxyTable = function (router) { + events.EventEmitter.call(this); + + if (typeof router === 'object') { + // If we are passed an object literal setup + // the routes with RegExps from the router + this.updateRoutes(router); + } + else if (typeof router === 'string') { + // If we are passed a string then assume it is a + // file path, parse that file and watch it for changes + var self = this; + this.routeFile = router; + this.updateRoutes(JSON.parse(fs.readFileSync(router)).router); + + fs.watchFile(this.routeFile, function (c,p) { + fs.readFile(self.routeFile, function (err, data) { + if (err) throw err; + self.updateRoutes(JSON.parse(data).router); + self.emit('updateRoutes', self.routes); + }); + }); + } + else { + throw new Error('Cannot parse router with unknown type: ' + typeof router); + } +}; + +util.inherits(ProxyTable, events.EventEmitter); + +ProxyTable.prototype.updateRoutes = function (router) { + if (!router) throw new Error('Cannot update ProxyTable routes without router.'); + + var self = this; + this.router = router; + this.routes = []; + + Object.keys(router).forEach(function (path) { + var route = new RegExp(path, 'i'); + + self.routes.push({ + route: route, + target: router[path] + }); + }); +}; + +ProxyTable.prototype.proxyRequest = function (proxy) { + var target = proxy.req.headers.host.split(':')[0] + proxy.req.url; + for (var i in this.routes) { + var match, route = this.routes[i]; + if (match = target.match(route.route)) { + var location = route.target.split(':'), + host = location[0], + port = location.length === 1 ? 80 : location[1]; + + proxy.proxyRequest(port, host); + return; + } + } + + if (proxy.res) { + proxy.res.writeHead(404, {'Content-Type': 'text/plain'}); + proxy.res.end(); + } + else if (proxy.sock) { + // Remark: How do we perform '404' over a socket? + proxy.sock.destroy(); + } +}; + +ProxyTable.prototype.close = function () { + if (typeof this.routeFile === 'string') { + fs.unwatchFile(this.routeFile); + } +}; + +exports.ProxyTable = ProxyTable; \ No newline at end of file diff --git a/package.json b/package.json index ffd3a74f4..b78b1e400 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "version": "0.3.0", "author": "Charlie Robbins", "contributors": [ - { "name": "Mikeal Rogers", "email": 'mikeal.rogers@gmail.com' }, + { "name": "Mikeal Rogers", "email": "mikeal.rogers@gmail.com" }, { "name": "Marak Squires", "email": "marak.squires@gmail.com" } ], "repository": { @@ -14,9 +14,13 @@ "keywords": ["reverse", "proxy", "http"], "dependencies": { "colors": ">= 0.3.0", - "pool": ">= 0.4.1" + "optimist": ">= 0.0.6", + "pool": ">= 0.4.1", + "request": ">= 0.10.0", + "vows": ">= 0.5.2" }, "main": "./lib/node-http-proxy", - "scripts": { "test": "vows" }, - "engines": { "node": ">= 0.2.0" } + "bin": { "http-proxy": "./bin/node-http-proxy" }, + "scripts": { "test": "vows test/*-test.js --spec" }, + "engines": { "node": ">= 0.3.0" } } \ No newline at end of file diff --git a/test/helpers.js b/test/helpers.js new file mode 100644 index 000000000..5d33cd0dc --- /dev/null +++ b/test/helpers.js @@ -0,0 +1,99 @@ +/* + * helpers.js: Helpers for node-http-proxy tests. + * + * (C) 2010, Charlie Robbins + * + */ + +var http = require('http'), + httpProxy = require('./../lib/node-http-proxy'); + +var TestRunner = function () { + this.testServers = []; +} + +// +// Creates the reverse proxy server +// +TestRunner.prototype.startProxyServer = function (port, targetPort, host) { + var proxyServer = httpProxy.createServer(targetPort, host); + proxyServer.listen(port); + this.testServers.push(proxyServer); + return proxyServer; +}; + +// +// Creates the reverse proxy server with a specified latency +// +TestRunner.prototype.startLatentProxyServer = function (port, targetPort, host, latency) { + // Initialize the nodeProxy and start proxying the request + var proxyServer = httpProxy.createServer(function (req, res, proxy) { + setTimeout(function () { + proxy.proxyRequest(targetPort, host); + }, latency); + }); + + proxyServer.listen(port); + this.testServers.push(proxyServer); + return proxyServer; +}; + +// +// Creates the reverse proxy server with a ProxyTable +// +TestRunner.prototype.startProxyServerWithTable = function (port, options) { + var proxyServer = httpProxy.createServer(options); + proxyServer.listen(port); + this.testServers.push(proxyServer); + return proxyServer; +}; + +// +// Creates a latent reverse proxy server using a ProxyTable +// +TestRunner.prototype.startProxyServerWithTableAndLatency = function (port, latency, router) { + // Initialize the nodeProxy and start proxying the request + var proxyTable = new httpProxy.ProxyTable(router); + var proxyServer = http.createServer(function (req, res) { + var proxy = new httpProxy.HttpProxy(req, res); + setTimeout(function () { + proxyTable.proxyRequest(proxy); + }, latency); + }); + + proxyServer.on('close', function () { + proxyTable.close(); + }); + + proxyServer.listen(port); + this.testServers.push(proxyServer); + return proxyServer; +}; + +// +// Creates the 'hellonode' server +// +TestRunner.prototype.startTargetServer = function (port, output) { + var targetServer = http.createServer(function (req, res) { + res.writeHead(200, {'Content-Type': 'text/plain'}); + res.write(output) + res.end(); + }); + + targetServer.listen(port); + this.testServers.push(targetServer); + return targetServer; +}; + +// +// Close all of the testServers +// +TestRunner.prototype.closeServers = function () { + this.testServers.forEach(function (server) { + server.close(); + }); + + return this.testServers; +}; + +exports.TestRunner = TestRunner; \ No newline at end of file diff --git a/test/node-http-proxy-test.js b/test/node-http-proxy-test.js index d1270b26f..0d0c20e90 100644 --- a/test/node-http-proxy-test.js +++ b/test/node-http-proxy-test.js @@ -1,7 +1,7 @@ /* node-http-proxy-test.js: http proxy for node.js - Copyright (c) 2010 Charlie Robbins & Marak Squires http://github.com/nodejitsu/node-http-proxy + Copyright (c) 2010 Charlie Robbins, Marak Squires and Fedor Indutny Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the @@ -28,72 +28,35 @@ var vows = require('vows'), sys = require('sys'), request = require('request'), assert = require('assert'), - http = require('http'); + TestRunner = require('./helpers').TestRunner; -var httpProxy = require('./../lib/node-http-proxy'); -var testServers = []; - -// -// Creates the reverse proxy server -// -var startProxyServer = function (port, targetPort, server) { - var proxyServer = httpProxy.createServer(targetPort, server); - proxyServer.listen(port); - testServers.push(proxyServer); -}; - -// -// Creates the reverse proxy server with a specified latency -// -var startLatentProxyServer = function (port, targetPort, server, latency) { - // Initialize the nodeProxy and start proxying the request - var proxyServer = httpProxy.createServer(function (req, res, proxy) { - setTimeout(function () { - proxy.proxyRequest(targetPort, server); - }, latency); - }); - - proxyServer.listen(port); - testServers.push(proxyServer); -}; - -// -// Creates the 'hellonode' server -// -var startTargetServer = function (port) { - var targetServer = http.createServer(function (req, res) { - res.writeHead(200, {'Content-Type': 'text/plain'}); - res.write('hello world') - res.end(); - }); - - targetServer.listen(port); - testServers.push(targetServer); - return targetServer; -}; +var runner = new TestRunner(); vows.describe('node-http-proxy').addBatch({ - "An instance of HttpProxy": { + "When using server created by httpProxy.createServer()": { "an incoming request to the helloNode server": { "with no latency" : { "and a valid target server": { topic: function () { - startProxyServer(8080, 8081, 'localhost'), - startTargetServer(8081); + this.output = 'hello world'; var options = { method: 'GET', uri: 'http://localhost:8080' }; + + runner.startProxyServer(8080, 8081, 'localhost'), + runner.startTargetServer(8081, this.output); + request(options, this.callback); }, - "it should received 'hello world'": function (err, res, body) { - assert.equal(body, 'hello world'); + "should received 'hello world'": function (err, res, body) { + assert.equal(body, this.output); } }, "and without a valid target server": { topic: function () { - startProxyServer(8082, 9000, 'localhost'); + runner.startProxyServer(8082, 9000, 'localhost'); var options = { method: 'GET', uri: 'http://localhost:8082' @@ -101,7 +64,7 @@ vows.describe('node-http-proxy').addBatch({ request(options, this.callback); }, - "it should receive 500 response code": function (err, res, body) { + "should receive 500 response code": function (err, res, body) { assert.equal(res.statusCode, 500); } } @@ -109,22 +72,25 @@ vows.describe('node-http-proxy').addBatch({ "with latency": { "and a valid target server": { topic: function () { - startLatentProxyServer(8083, 8084, 'localhost', 1000), - startTargetServer(8084); + this.output = 'hello world'; var options = { method: 'GET', uri: 'http://localhost:8083' }; + runner.startLatentProxyServer(8083, 8084, 'localhost', 1000), + runner.startTargetServer(8084, this.output); + + request(options, this.callback); }, - "it should receive 'hello world'": function (err, res, body) { - assert.equal(body, 'hello world'); + "should receive 'hello world'": function (err, res, body) { + assert.equal(body, this.output); } }, "and without a valid target server": { topic: function () { - startLatentProxyServer(8085, 9000, 'localhost', 1000); + runner.startLatentProxyServer(8085, 9000, 'localhost', 1000); var options = { method: 'GET', uri: 'http://localhost:8085' @@ -132,7 +98,7 @@ vows.describe('node-http-proxy').addBatch({ request(options, this.callback); }, - "it should receive 500 response code": function (err, res, body) { + "should receive 500 response code": function (err, res, body) { assert.equal(res.statusCode, 500); } } @@ -140,13 +106,13 @@ vows.describe('node-http-proxy').addBatch({ } } }).addBatch({ - "An instance of HttpProxy": { + "When using server created by httpProxy.createServer()": { "an incoming WebSocket request to the helloNode server": { "with no latency" : { // Remark: This test is not working /*topic: function () { - startProxyServer(8086, 8087, 'localhost'), - startTargetServer(8087); + runner.startProxyServer(8086, 8087, 'localhost'), + runner.startTargetServer(8087, 'hello world'); var options = { method: 'GET', uri: 'http://localhost:8086', @@ -159,7 +125,7 @@ vows.describe('node-http-proxy').addBatch({ request(options, this.callback); }, - "it should receive 'hello world'": function (err, res, body) { + "should receive 'hello world'": function (err, res, body) { assert.equal(body, 'hello world'); }*/ } @@ -168,11 +134,7 @@ vows.describe('node-http-proxy').addBatch({ }).addBatch({ "When the tests are over": { topic: function () { - testServers.forEach(function (server) { - server.close(); - }); - - return testServers; + return runner.closeServers(); }, "the servers should clean up": function () { assert.isTrue(true); diff --git a/test/proxy-table-test.js b/test/proxy-table-test.js new file mode 100644 index 000000000..c8acce488 --- /dev/null +++ b/test/proxy-table-test.js @@ -0,0 +1,155 @@ +/* + * proxy-table-test.js: Tests for the ProxyTable object. + * + * (C) 2010, Charlie Robbins + * + */ + +var fs = require('fs'), + vows = require('vows'), + sys = require('sys'), + path = require('path'), + request = require('request'), + assert = require('assert'), + TestRunner = require('./helpers').TestRunner; + +var runner = new TestRunner(), + routeFile = path.join(__dirname, 'config.json'); + +var fileOptions = { + router: { + "foo.com": "127.0.0.1:8101", + "bar.com": "127.0.0.1:8102" + } +}; + +var defaultOptions = { + router: { + "foo.com": "127.0.0.1:8091", + "bar.com": "127.0.0.1:8092" + } +}; + +function createTargetTest (host, proxyPort, port) { + var assertion = "should receive 'hello " + host + "'", + output = 'hello ' + host; + + var test = { + topic: function () { + var options = { + method: 'GET', + uri: 'http://localhost:' + proxyPort, + headers: { + host: host + } + }; + + if (port) runner.startTargetServer(port, output); + request(options, this.callback); + } + }; + + test[assertion] = function (err, res, body) { + assert.equal(body, output); + }; + + return test; +}; + +function createNoTargetTest (proxyPort) { + return { + topic: function () { + var options = { + method: 'GET', + uri: 'http://localhost:' + proxyPort, + headers: { + host: 'unknown.com' + } + }; + + request(options, this.callback); + }, + "should receive 404 response code": function (err, res, body) { + assert.equal(res.statusCode, 404); + } + }; +} + +vows.describe('proxy-table').addBatch({ + "When using server created by httpProxy.createServer()": { + "when passed a routing table": { + topic: function () { + this.server = runner.startProxyServerWithTable(8090, defaultOptions); + return null; + }, + "an incoming request to foo.com": createTargetTest('foo.com', 8090, 8091), + "an incoming request to bar.com": createTargetTest('bar.com', 8090, 8092), + "an incoming request to unknown.com": createNoTargetTest(8090) + }, + "when passed a routing file": { + topic: function () { + fs.writeFileSync(routeFile, JSON.stringify(fileOptions)); + this.server = runner.startProxyServerWithTable(8100, { + router: routeFile + }); + + return null; + }, + "an incoming request to foo.com": createTargetTest('foo.com', 8100, 8101), + "an incoming request to bar.com": createTargetTest('bar.com', 8100, 8102), + "an incoming request to unknown.com": createNoTargetTest(8100), + "an incoming request to dynamic.com": { + "after the file has been modified": { + topic: function () { + var that = this, + data = fs.readFileSync(routeFile), + config = JSON.parse(data); + + this.output = 'hello dynamic.com'; + config.router['dynamic.com'] = "127.0.0.1:8103" + fs.writeFileSync(routeFile, JSON.stringify(config)); + + this.server.on('updateRoutes', function () { + var options = { + method: 'GET', + uri: 'http://localhost:8100', + headers: { + host: 'dynamic.com' + } + }; + + runner.startTargetServer(8103, that.output); + request(options, that.callback); + }); + }, + "should receive 'hello dynamic.com'": function (err, res, body) { + assert.equal(body, this.output); + } + } + } + } + } +}).addBatch({ + "When using an instance of ProxyTable combined with HttpProxy directly": { + topic: function () { + this.server = runner.startProxyServerWithTableAndLatency(8110, 100, { + 'foo.com': 'localhost:8111', + 'bar.com': 'localhost:8112' + }); + return null; + }, + "an incoming request to foo.com": createTargetTest('foo.com', 8110, 8111), + "an incoming request to bar.com": createTargetTest('bar.com', 8110, 8112), + "an incoming request to unknown.com": createNoTargetTest(8110) + } +}).addBatch({ + "When the tests are over": { + topic: function () { + fs.unlinkSync(routeFile); + return runner.closeServers(); + }, + "the servers should clean up": function () { + assert.isTrue(true); + } + } +}).export(module); \ No newline at end of file