Skip to content
This repository has been archived by the owner on May 24, 2023. It is now read-only.

Commit

Permalink
added proxy test, fixed proxy middleware issues
Browse files Browse the repository at this point in the history
  • Loading branch information
matz3 committed Nov 15, 2014
1 parent 1375db7 commit 483e137
Show file tree
Hide file tree
Showing 4 changed files with 148 additions and 39 deletions.
18 changes: 15 additions & 3 deletions Gruntfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,28 @@ module.exports = function(grunt) {
eslint: {
all: [
'Gruntfile.js',
'lib/*.js'
'lib/*.js',
'<%= mochaTest.all.src %>'
]
},

// Unit tests.
mochaTest: {
all: {
src: ['test/*_test.js']
}
}

});

// These plugins provide necessary tasks.
grunt.loadNpmTasks('grunt-eslint');
grunt.loadNpmTasks('grunt-mocha-test');

// Run mocha unit tests
grunt.registerTask('test', ['mochaTest']);

// By default: lint.
grunt.registerTask('default', [ 'eslint']);
// By default: lint and test
grunt.registerTask('default', ['eslint', 'test']);

};
98 changes: 66 additions & 32 deletions lib/proxy.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,55 +14,89 @@

'use strict';

var url = require('url');
var httpProxy = require('http-proxy');
var Promise = require('es6-promise').Promise;
var npmconf = require('npmconf');

module.exports = function() {
var env = {
no_proxy: process.env.NO_PROXY || process.env.no_proxy,
http_proxy: process.env.HTTP_PROXY || process.env.http_proxy,
https_proxy: process.env.HTTPS_PROXY || process.env.https_proxy
};

var urlPattern = /^\/(http|https)\/([^/]+)\/?(.*)/;
var proxy = httpProxy.createProxyServer({});
// inspired by https://github.com/request/request/blob/33cd9e297a00c5540e55778a24a706effc35434c/request.js#L169
function getProxyUri(uri) {

var loadConf = new Promise(function(resolve, reject) {
npmconf.load(function(err, conf) {
if (err) {
reject(err);
} else {
resolve(conf);
if (uri.protocol === 'https:' && env.https_proxy || uri.protocol === 'http:' && env.http_proxy) {

if (env.no_proxy) {
var canonicalHost = uri.host.replace(/^\.*/, '.');
var port = uri.port || (uri.protocol === 'https:' ? '443' : '80');

var patterns = env.no_proxy.split(',');
for (var i = patterns.length - 1; i >= 0; i--) {
var pattern = patterns[i].trim().toLowerCase();

// don't use a proxy at all
if (pattern === '*') {
return null;
}

pattern = pattern.replace(/^\.*/, '.');

// add port if no specified
if (pattern.indexOf(':') === -1) {
pattern += ':' + port;
}

// if host ends with pattern, no proxy should be used
if (canonicalHost.indexOf(pattern) === canonicalHost.length - pattern.length) {
return null;
}
}
});
});
}

if (uri.protocol === 'https:' && env.https_proxy) {
return env.https_proxy;
} else if (uri.protocol === 'http:' && env.http_proxy) {
return env.http_proxy;
}
}

return null;
}

module.exports = function() {

var urlPattern = /^\/(http|https)\/(.*)/;
var proxy = httpProxy.createProxyServer({});

return function(req, res, next) {

// parse the request url
var parts = urlPattern.exec(req.url);
if (!parts) {
return next();
}

var protocol = parts[1];
var host = parts[2];
var urlPath = '/' + parts[3] || '';

req.url = urlPath;
req.headers.host = host;
// parse target url
var uri = url.parse(parts[1] + '://' + parts[2]);

loadConf.then(function(conf) {
// change original request url to target url
req.url = uri.path;

var proxyForRequest;
if (protocol === 'https') {
proxyForRequest = conf.get('https-proxy');
}
proxyForRequest = proxyForRequest || conf.get('http-proxy') || conf.get('proxy');
// change original host to target host
req.headers.host = uri.host;

proxy.proxyRequest(req, res, {
target: proxyForRequest ? proxyForRequest : protocol + '://' + host
}, function(err) {
if (err) {
next(err);
}
});
// get proxy for uri (if defined in env vars)
var targetUri = getProxyUri(uri) || uri.protocol + '//' + uri.host;

// proxy the request
proxy.proxyRequest(req, res, {
target: targetUri
}, function(err) {
if (err) {
next(err);
}
});

};
Expand Down
9 changes: 5 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,14 @@
},
"dependencies": {
"async": "^0.9.0",
"es6-promise": "^2.0.0",
"http-proxy": "^1.5.3",
"less-openui5": "^0.1.1",
"npmconf": "^2.1.1"
"less-openui5": "^0.1.1"
},
"devDependencies": {
"connect": "^3.3.3",
"grunt": "~0.4.5",
"grunt-eslint": "^1.1.0"
"grunt-eslint": "^1.1.0",
"grunt-mocha-test": "^0.12.3",
"mocha": "^2.0.1"
}
}
62 changes: 62 additions & 0 deletions test/proxy_test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// Copyright 2014 SAP SE.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http: //www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
// either express or implied. See the License for the specific
// language governing permissions and limitations under the License.

/*eslint-env mocha */
'use strict';

var http = require('http');
var assert = require('assert');
var connect = require('connect');
var proxy = require('../').proxy;

describe('proxy middleware should proxy generic requests', function () {
it('should proxy from one server to the other', function (done) {
var sExpectedResponse = 'All ok!',
sExpectedPath = '/foo/bar',
iExpectedStatusCode = 200,
oAppToBeProxied = connect(),
sActualResponse = '',
sActualPath,
iActualStatusCode;

oAppToBeProxied.use(function (oRequest, oResponse) {
sActualPath = oRequest.url;
oResponse.end(sExpectedResponse);
});

var oServerToBeProxied = http.createServer(oAppToBeProxied);
oServerToBeProxied.listen(8080);

var oProxyApp = connect();
oProxyApp.use(proxy());
var oProxyServer = http.createServer(oProxyApp);
oProxyServer.listen(9000);

http.get('http://localhost:9000/http/localhost:8080' + sExpectedPath, function (oResponse) {
oResponse.on('data', function(oData) {
sActualResponse += oData;
});
iActualStatusCode = oResponse.statusCode;
oResponse.on('end', function () {
assert.equal(sActualPath, sExpectedPath);
assert.equal(sActualResponse, sExpectedResponse);
assert.equal(iActualStatusCode, iExpectedStatusCode);

oServerToBeProxied.close();
oProxyServer.close();
done();
});
});
});
});

0 comments on commit 483e137

Please sign in to comment.