diff --git a/lib/node-http-proxy/proxy-table.js b/lib/node-http-proxy/proxy-table.js index 407ba47..84b17a3 100644 --- a/lib/node-http-proxy/proxy-table.js +++ b/lib/node-http-proxy/proxy-table.js @@ -84,6 +84,35 @@ var ProxyTable = exports.ProxyTable = function (options) { // util.inherits(ProxyTable, events.EventEmitter); +// +// ### function addRoute (route, target) +// #### @route {String} String containing route coming in +// #### @target {String} String containing the target +// Adds a host-based route to this instance. +// +ProxyTable.prototype.addRoute = function (route, target) { + if (!this.router) { + throw new Error('Cannot update ProxyTable routes without router.'); + } + + this.router[route] = target; + this.setRoutes(this.router); +}; + +// +// ### function removeRoute (route) +// #### @route {String} String containing route to remove +// Removes a host-based route from this instance. +// +ProxyTable.prototype.removeRoute = function (route) { + if (!this.router) { + throw new Error('Cannot update ProxyTable routes without router.'); + } + + delete this.router[route]; + this.setRoutes(this.router); +}; + // // ### function setRoutes (router) // #### @router {Object} Object containing the host based routes diff --git a/lib/node-http-proxy/routing-proxy.js b/lib/node-http-proxy/routing-proxy.js index b9b8a17..98c7a79 100644 --- a/lib/node-http-proxy/routing-proxy.js +++ b/lib/node-http-proxy/routing-proxy.js @@ -276,6 +276,29 @@ RoutingProxy.prototype.proxyWebSocketRequest = function (req, socket, head, opti proxy.proxyWebSocketRequest(req, socket, head, options.buffer); }; +// +// ### function addHost (host, target) +// #### @host {String} Host to add to proxyTable +// #### @target {String} Target to add to proxyTable +// Adds a host to proxyTable +// +RoutingProxy.prototype.addHost = function (host, target) { + if (this.proxyTable) { + this.proxyTable.addRoute(host, target); + } +}; + +// +// ### function removeHost (host) +// #### @host {String} Host to remove from proxyTable +// Removes a host to proxyTable +// +RoutingProxy.prototype.removeHost = function (host) { + if (this.proxyTable) { + this.proxyTable.removeRoute(host); + } +}; + // // ### @private function _getKey (options) // #### @options {Object} Options to extract the key from diff --git a/test/http/routing-table-test.js b/test/http/routing-table-test.js index 679c286..f3dcf31 100644 --- a/test/http/routing-table-test.js +++ b/test/http/routing-table-test.js @@ -12,7 +12,7 @@ var assert = require('assert'), request = require('request'), vows = require('vows'), macros = require('../macros'), - helpers = require('../helpers/index'); + helpers = require('../helpers'); var routeFile = path.join(__dirname, 'config.json'); @@ -25,6 +25,16 @@ vows.describe(helpers.describe('routing-table')).addBatch({ "latency.com": "127.0.0.1:{PORT}" } }), + "addHost() / removeHost()": macros.http.assertDynamicProxy({ + hostnameOnly: true, + routes: { + "static.com": "127.0.0.1:{PORT}", + "removed.com": "127.0.0.1:{PORT}" + } + }, { + add: [{ host: 'dynamic1.com', target: '127.0.0.1:' }], + drop: ['removed.com'] + }), "using RegExp": macros.http.assertProxiedToRoutes({ routes: { "foo.com": "127.0.0.1:{PORT}", diff --git a/test/macros/http.js b/test/macros/http.js index 108fa98..9f78f82 100644 --- a/test/macros/http.js +++ b/test/macros/http.js @@ -243,7 +243,7 @@ exports.assertProxiedToRoutes = function (options, nested) { // Parse locations from routes for making assertion requests. // var locations = helpers.http.parseRoutes(options), - port = helpers.nextPort, + port = options.pport || helpers.nextPort, protocol = helpers.protocols.proxy, context, proxy; @@ -365,3 +365,83 @@ exports.assertProxiedToRoutes = function (options, nested) { return context; }; + +// +// ### function assertDynamicProxy (static, dynamic) +// Asserts that after the `static` routes have been tested +// and the `dynamic` routes are added / removed the appropriate +// proxy responses are received. +// +exports.assertDynamicProxy = function (static, dynamic) { + var proxyPort = helpers.nextPort, + protocol = helpers.protocols.proxy, + context; + + if (dynamic.add) { + dynamic.add = dynamic.add.map(function (dyn) { + dyn.port = helpers.nextPort; + dyn.target = dyn.target + dyn.port; + return dyn; + }); + } + + context = { + topic: function () { + var that = this; + + setTimeout(function () { + if (dynamic.drop) { + dynamic.drop.forEach(function (dropHost) { + that.proxyServer.proxy.removeHost(dropHost); + }); + } + + if (dynamic.add) { + async.forEachSeries(dynamic.add, function addOne (dyn, next) { + that.proxyServer.proxy.addHost(dyn.host, dyn.target); + helpers.http.createServer({ + port: dyn.port, + output: 'hello ' + dyn.host + }, next); + }, that.callback); + } + else { + that.callback(); + } + }, 200); + } + }; + + if (dynamic.drop) { + dynamic.drop.forEach(function (dropHost) { + context[dropHost] = exports.assertRequest({ + assert: { statusCode: 404 }, + request: { + uri: protocol + '://127.0.0.1:' + proxyPort, + headers: { + host: dropHost + } + } + }); + }); + } + + if (dynamic.add) { + dynamic.add.forEach(function (dyn) { + context[dyn.host] = exports.assertRequest({ + assert: { body: 'hello ' + dyn.host }, + request: { + uri: protocol + '://127.0.0.1:' + proxyPort, + headers: { + host: dyn.host + } + } + }); + }); + } + + static.pport = proxyPort; + return exports.assertProxiedToRoutes(static, { + "once the server has started": context + }); +}; \ No newline at end of file