Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support subpaths in proxies for Testacular #29

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Support subpaths in proxies
[changelog]
  • Loading branch information
shyamseshadri committed Aug 13, 2012
commit fe53715a6f153b2d615e08cbd02f4f21e5f5eab7
35 changes: 31 additions & 4 deletions lib/proxy.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,39 @@
var url = require('url');

var parseProxyConfig = function(proxies) {
var proxyConfig = {};
var endsWith = function(str, suffix) {
return str.substr(-suffix.length) === suffix;
}
if (!proxies) { return; }
Object.keys(proxies).forEach(function(proxyPath) {
var proxyUrl = proxies[proxyPath];
if (!endsWith(proxyPath, '/')) {
proxyPath = proxyPath + '/';
}
var proxyDetails = url.parse(proxyUrl);
if (!endsWith(proxyDetails.path, '/')) {
proxyDetails.path = proxyDetails.path + '/';
}
proxyConfig[proxyPath] = {
host: proxyDetails.hostname,
port: proxyDetails.port || '80',
baseProxyUrl: proxyDetails.path
};
});
return proxyConfig;
};

exports.parseProxyConfig = parseProxyConfig;

/**
* Returns a handler which understands the proxies and its redirects, along with the proxy to use
* @param proxy A http-proxy.RoutingProxy object with the proxyRequest method
* @param proxies a map of routes to proxy url
* @return {Function} handler function
*/
var createProxyHandler = function(proxy, proxies) {
var createProxyHandler = function(proxy, proxyConfig) {
var proxies = parseProxyConfig(proxyConfig);
var proxiesList = [];
if (proxies) {
proxiesList = Object.keys(proxies);
Expand All @@ -18,14 +45,14 @@ var createProxyHandler = function(proxy, proxies) {
if (proxies) {
for (var i = 0; i < proxiesList.length; i++) {
if (request.url.indexOf(proxiesList[i]) === 0) {
proxiedUrl = url.parse(proxies[proxiesList[i]]);
proxiedUrl = proxies[proxiesList[i]];
request.url = request.url.replace(proxiesList[i], proxiedUrl.baseProxyUrl);
break;
}
}
}
if (proxiedUrl) {
proxiedUrl.port = proxiedUrl.port || '80';
proxy.proxyRequest(request, response, {host: proxiedUrl.hostname, port: proxiedUrl.port});
proxy.proxyRequest(request, response, {host: proxiedUrl.host, port: proxiedUrl.port});
return true;
}
return false;
Expand Down
7 changes: 2 additions & 5 deletions lib/web-server.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ exports.createWebServer = function (fileList, baseFolder, proxies, urlRoot) {
var adapterFolder = path.normalize(__dirname + '/../adapter');

return http.createServer(createHandler(fileList, u.normalizeWinPath(staticFolder),
u.normalizeWinPath(adapterFolder), baseFolder,
new httpProxy.RoutingProxy(), proxies, urlRoot));
u.normalizeWinPath(adapterFolder), baseFolder,
new httpProxy.RoutingProxy(), proxies, urlRoot));
};

var createHandler = function(fileList, staticFolder, adapterFolder, baseFolder, proxyFn, proxies, urlRoot) {
Expand Down Expand Up @@ -150,6 +150,3 @@ var createSourceFileHandler = function(fileList, adapterFolder, baseFolder) {
}
}
};



31 changes: 27 additions & 4 deletions test/unit/proxy.spec.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ describe 'proxy unit tests', ->
fsMock = require('mocks').fs
httpMock = require('mocks').http
loadFile = require('mocks').loadFile
actualOptions = null
actualOptions = requestedUrl = null
# async helper
waitForFinishingResponse = ->
waitsFor (-> response._isFinished()), 'Finish response', 100
Expand All @@ -18,35 +18,58 @@ describe 'proxy unit tests', ->
mockProxy = {}
mockProxy.proxyRequest = (req, res, opt) ->
actualOptions = opt
requestedUrl = req.url
res.writeHead 200
res.end 'DONE'
response = null

beforeEach ->
actualOptions = {}
requestedUrl = ''
response = new httpMock.ServerResponse

it 'should proxy requests', ->
proxy = m.createProxyHandler(mockProxy, {'/proxy': 'http://localhost:9000'})
proxy = m.createProxyHandler mockProxy, {'/proxy': 'http://localhost:9000'}

expect(proxy new httpMock.ServerRequest('/proxy/test.html'), response).toBeTruthy()
waitForFinishingResponse()

runs ->
expect(requestedUrl).toEqual '/test.html'
expect(actualOptions).toEqual {host: 'localhost', port: '9000'}

it 'should support multiple proxies', ->
proxy = m.createProxyHandler(mockProxy, {'/proxy': 'http://localhost:9000', '/static': 'http://gstatic.com'})
proxy = m.createProxyHandler mockProxy, {'/proxy': 'http://localhost:9000', '/static': 'http://gstatic.com'}
expect(proxy new httpMock.ServerRequest('/static/test.html'), response).toBeTruthy()
waitForFinishingResponse()

runs ->
expect(requestedUrl).toEqual '/test.html'
expect(actualOptions).toEqual {host: 'gstatic.com', port: '80'}

it 'should handle nested proxies', ->
proxy = m.createProxyHandler(mockProxy, {'/sub': 'http://localhost:9000', '/sub/some': 'http://gstatic.com'})
proxy = m.createProxyHandler mockProxy, {'/sub': 'http://localhost:9000', '/sub/some': 'http://gstatic.com/something'}
expect(proxy new httpMock.ServerRequest('/sub/some/Test.html'), response).toBeTruthy()
waitForFinishingResponse()

runs ->
expect(requestedUrl).toEqual '/something/Test.html'
expect(actualOptions).toEqual {host: 'gstatic.com', port: '80'}

it 'should parse a simple proxy config', ->
proxy = {'/base/': 'http://localhost:8000'}
parsedProxyConfig = m.parseProxyConfig proxy
expect(parsedProxyConfig).toEqual({'/base/': {host: 'localhost', port: '8000', baseProxyUrl: '/'}})

it 'should handle proxy configs without trailing slash', ->
proxy = {'/base': 'http://internationalhost:8000'}
parsedProxyConfig = m.parseProxyConfig proxy
expect(parsedProxyConfig).toEqual({'/base/': {host: 'internationalhost', port: '8000', baseProxyUrl: '/'}})

it 'should handle proxy configs with paths', ->
proxy = {'/base': 'http://localhost:8000/proxy'}
parsedProxyConfig = m.parseProxyConfig proxy
expect(parsedProxyConfig).toEqual({'/base/': {host: 'localhost', port: '8000', baseProxyUrl: '/proxy/'}})

it 'should handle empty proxy config', ->
expect(m.parseProxyConfig {}).toEqual({})