diff --git a/README.md b/README.md index 3aa0132..2b7f992 100644 --- a/README.md +++ b/README.md @@ -303,9 +303,15 @@ These are the available config options for making requests. Only the `url` is re httpsAgent: new https.Agent({ keepAlive: true }), // 'proxy' defines the hostname and port of the proxy server + // `auth` indicates that HTTP Basic auth should be used to connect to the proxy, and supplies credentials. + // This will set an `Proxy-Authorization` header, overwriting any existing `Proxy-Authorization` custom headers you have set using `headers`. proxy: { host: '127.0.0.1', - port: 9000 + port: 9000, + auth: : { + username: 'mikeymike', + password: 'rapunz3l' + } }, // `cancelToken` specifies a cancel token that can be used to cancel the request diff --git a/lib/adapters/http.js b/lib/adapters/http.js index d6908b3..8a2fc57 100644 --- a/lib/adapters/http.js +++ b/lib/adapters/http.js @@ -91,15 +91,29 @@ module.exports = function httpAdapter(config) { host: parsedProxyUrl.hostname, port: parsedProxyUrl.port }; + + if (parsedProxyUrl.auth) { + var proxyUrlAuth = parsedProxyUrl.auth.split(':'); + proxy.auth = { + username: proxyUrlAuth[0], + password: proxyUrlAuth[1] + }; + } } } if (proxy) { - options.host = proxy.host; options.hostname = proxy.host; + options.host = proxy.host; options.headers.host = parsed.hostname + (parsed.port ? ':' + parsed.port : ''); options.port = proxy.port; options.path = protocol + '//' + parsed.hostname + (parsed.port ? ':' + parsed.port : '') + options.path; + + // Basic proxy authorization + if (proxy.auth) { + var base64 = new Buffer(proxy.auth.username + ':' + proxy.auth.password, 'utf8').toString('base64'); + options.headers['Proxy-Authorization'] = 'Basic ' + base64; + } } var transport; diff --git a/test/unit/adapters/http.js b/test/unit/adapters/http.js index 1e41a63..131bce0 100644 --- a/test/unit/adapters/http.js +++ b/test/unit/adapters/http.js @@ -248,7 +248,7 @@ module.exports = { }); }, - testProxy: function(test) { + testHTTPProxy: function(test) { server = http.createServer(function(req, res) { res.setHeader('Content-Type', 'text/html; charset=UTF-8'); res.end('12345'); @@ -322,6 +322,131 @@ module.exports = { }); }, + testHTTPProxyAuth: function(test) { + server = http.createServer(function(req, res) { + res.end(); + }).listen(4444, function() { + proxy = http.createServer(function(request, response) { + var parsed = url.parse(request.url); + var opts = { + host: parsed.hostname, + port: parsed.port, + path: parsed.path + }; + var proxyAuth = request.headers['proxy-authorization']; + + http.get(opts, function(res) { + var body = ''; + res.on('data', function(data) { + body += data; + }); + res.on('end', function() { + response.setHeader('Content-Type', 'text/html; charset=UTF-8'); + response.end(proxyAuth); + }); + }); + + }).listen(4000, function() { + axios.get('http://localhost:4444/', { + proxy: { + host: 'localhost', + port: 4000, + auth: { + username: 'user', + password: 'pass' + } + } + }).then(function(res) { + var base64 = new Buffer('user:pass', 'utf8').toString('base64'); + test.equal(res.data, 'Basic ' + base64, 'should authenticate to the proxy'); + test.done(); + }); + }); + }); + }, + + testHTTPProxyAuthFromEnv: function(test) { + server = http.createServer(function(req, res) { + res.end(); + }).listen(4444, function() { + proxy = http.createServer(function(request, response) { + var parsed = url.parse(request.url); + var opts = { + host: parsed.hostname, + port: parsed.port, + path: parsed.path + }; + var proxyAuth = request.headers['proxy-authorization']; + + http.get(opts, function(res) { + var body = ''; + res.on('data', function(data) { + body += data; + }); + res.on('end', function() { + response.setHeader('Content-Type', 'text/html; charset=UTF-8'); + response.end(proxyAuth); + }); + }); + + }).listen(4000, function() { + process.env.http_proxy = 'http://user:pass@localhost:4000/'; + + axios.get('http://localhost:4444/').then(function(res) { + var base64 = new Buffer('user:pass', 'utf8').toString('base64'); + test.equal(res.data, 'Basic ' + base64, 'should authenticate to the proxy set by process.env.http_proxy'); + test.done(); + }); + }); + }); + }, + + testHTTPProxyAuthWithHeader: function (test) { + server = http.createServer(function(req, res) { + res.end(); + }).listen(4444, function() { + proxy = http.createServer(function(request, response) { + var parsed = url.parse(request.url); + var opts = { + host: parsed.hostname, + port: parsed.port, + path: parsed.path + }; + var proxyAuth = request.headers['proxy-authorization']; + + http.get(opts, function(res) { + var body = ''; + res.on('data', function(data) { + body += data; + }); + res.on('end', function() { + response.setHeader('Content-Type', 'text/html; charset=UTF-8'); + response.end(proxyAuth); + }); + }); + + }).listen(4000, function() { + axios.get('http://localhost:4444/', { + proxy: { + host: 'localhost', + port: 4000, + auth: { + username: 'user', + password: 'pass' + } + }, + headers: { + 'Proxy-Authorization': 'Basic abc123' + } + }).then(function(res) { + var base64 = new Buffer('user:pass', 'utf8').toString('base64'); + test.equal(res.data, 'Basic ' + base64, 'should authenticate to the proxy'); + test.done(); + }); + }); + }); + }, + testCancel: function(test) { var source = axios.CancelToken.source(); server = http.createServer(function (req, res) {