From d96932b8dd492bfa4401d47e3ae3c1dd80dfc1e2 Mon Sep 17 00:00:00 2001 From: Mikkel Garcia <mikkel@255bits.com> Date: Tue, 5 Mar 2013 17:08:44 -0700 Subject: [PATCH 1/3] pathnameOnly flag added. Ignores hostname and applies routing table to the paths being requested. --- lib/node-http-proxy/proxy-table.js | 23 +++++++++++++++++++++-- test/http/routing-table-test.js | 8 ++++++++ test/macros/http.js | 1 + 3 files changed, 30 insertions(+), 2 deletions(-) diff --git a/lib/node-http-proxy/proxy-table.js b/lib/node-http-proxy/proxy-table.js index b12b577..87184e8 100644 --- a/lib/node-http-proxy/proxy-table.js +++ b/lib/node-http-proxy/proxy-table.js @@ -34,6 +34,7 @@ var util = require('util'), // #### @router {Object} Object containing the host based routes // #### @silent {Boolean} Value indicating whether we should suppress logs // #### @hostnameOnly {Boolean} Value indicating if we should route based on __hostname string only__ +// #### @pathnameOnly {Boolean} Value indicating if we should route based on only the pathname. __This causes hostnames to be ignored.__. Using this along with hostnameOnly wont work at all. // Constructor function for the ProxyTable responsible for getting // locations of proxy targets based on ServerRequest headers; specifically // the HTTP host header. @@ -43,6 +44,7 @@ var ProxyTable = exports.ProxyTable = function (options) { this.silent = options.silent || options.silent !== true; this.target = options.target || {}; + this.pathnameOnly = options.pathnameOnly === true; this.hostnameOnly = options.hostnameOnly === true; if (typeof options.router === 'object') { @@ -164,8 +166,9 @@ ProxyTable.prototype.getProxyLocation = function (req) { return null; } - var target = req.headers.host.split(':')[0]; + var targetHost = req.headers.host.split(':')[0]; if (this.hostnameOnly === true) { + var target = targetHost; if (this.router.hasOwnProperty(target)) { var location = this.router[target].split(':'), host = location[0], @@ -177,8 +180,24 @@ ProxyTable.prototype.getProxyLocation = function (req) { }; } } + else if (this.pathnameOnly === true) { + var target = req.url; + for (var i in this.routes) { + var route = this.routes[i]; + if (target.match(route.source.regexp)) { + req.url = url.format(target.replace(route.source.regexp, '')); + return { + protocol: route.target.url.protocol.replace(':', ''), + host: route.target.url.hostname, + port: route.target.url.port + || (this.target.https ? 443 : 80) + }; + } + } + + } else { - target += req.url; + var target = targetHost + req.url; for (var i in this.routes) { var route = this.routes[i]; if (target.match(route.source.regexp)) { diff --git a/test/http/routing-table-test.js b/test/http/routing-table-test.js index f758bba..679c286 100644 --- a/test/http/routing-table-test.js +++ b/test/http/routing-table-test.js @@ -43,6 +43,14 @@ vows.describe(helpers.describe('routing-table')).addBatch({ "bar.com": "127.0.0.1:{PORT}" } }), + "using pathnameOnly": macros.http.assertProxiedToRoutes({ + pathnameOnly: true, + routes: { + "/foo": "127.0.0.1:{PORT}", + "/bar": "127.0.0.1:{PORT}", + "/pizza": "127.0.0.1:{PORT}" + } + }), "using a routing file": macros.http.assertProxiedToRoutes({ filename: routeFile, routes: { diff --git a/test/macros/http.js b/test/macros/http.js index 767b7db..cf62ce9 100644 --- a/test/macros/http.js +++ b/test/macros/http.js @@ -220,6 +220,7 @@ exports.assertProxiedToRoutes = function (options, nested) { // proxy = { hostnameOnly: options.hostnameOnly, + pathnameOnly: options.pathnameOnly, router: options.routes }; } -- GitLab From cbf39f502e742bce6f8e5a7663603e788855e2f2 Mon Sep 17 00:00:00 2001 From: Mikkel Garcia <mikkel@255bits.com> Date: Tue, 5 Mar 2013 17:32:49 -0700 Subject: [PATCH 2/3] pathnameOnly option documented in the Readme.md --- README.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/README.md b/README.md index fdedc3a..9dcce5c 100644 --- a/README.md +++ b/README.md @@ -202,6 +202,24 @@ var options = { Notice here that I have not included paths on the individual domains because this is not possible when using only the HTTP 'Host' header. Care to learn more? See [RFC2616: HTTP/1.1, Section 14.23, "Host"][4]. +### Proxy requests using a 'Pathname Only' ProxyTable + +If you dont care about forwarding to different hosts, you can redirect based on the request path. + +``` js +var options = { + pathnameOnly: true, + router: { + '/wiki': '127.0.0.1:8001', + '/blog': '127.0.0.1:8002', + '/api': '127.0.0.1:8003' + } +} +``` + +This comes in handy if you are running separate services or applications on separate paths. Note, using this option disables routing by hostname entirely. + + ### Proxy requests with an additional forward proxy Sometimes in addition to a reverse proxy, you may want your front-facing server to forward traffic to another location. For example, if you wanted to load test your staging environment. This is possible when using node-http-proxy using similar JSON-based configuration to a proxy table: -- GitLab From 189950ec36c2c07575dab076b3c8c949486176ab Mon Sep 17 00:00:00 2001 From: Mikkel Garcia <mikkel@255bits.com> Date: Tue, 5 Mar 2013 17:57:03 -0700 Subject: [PATCH 3/3] [doc] added comments to pathnameOnly block. --- lib/node-http-proxy/proxy-table.js | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/lib/node-http-proxy/proxy-table.js b/lib/node-http-proxy/proxy-table.js index 87184e8..407ba47 100644 --- a/lib/node-http-proxy/proxy-table.js +++ b/lib/node-http-proxy/proxy-table.js @@ -183,16 +183,25 @@ ProxyTable.prototype.getProxyLocation = function (req) { else if (this.pathnameOnly === true) { var target = req.url; for (var i in this.routes) { - var route = this.routes[i]; - if (target.match(route.source.regexp)) { - req.url = url.format(target.replace(route.source.regexp, '')); - return { - protocol: route.target.url.protocol.replace(':', ''), - host: route.target.url.hostname, - port: route.target.url.port - || (this.target.https ? 443 : 80) - }; - } + var route = this.routes[i]; + // + // If we are matching pathname only, we remove the matched pattern. + // + // IE /wiki/heartbeat + // is redirected to + // /heartbeat + // + // for the route "/wiki" : "127.0.0.1:8020" + // + if (target.match(route.source.regexp)) { + req.url = url.format(target.replace(route.source.regexp, '')); + return { + protocol: route.target.url.protocol.replace(':', ''), + host: route.target.url.hostname, + port: route.target.url.port + || (this.target.https ? 443 : 80) + }; + } } } -- GitLab