| 'use strict' |
| |
| var url = require('url') |
| , tunnel = require('tunnel-agent') |
| |
| var defaultProxyHeaderWhiteList = [ |
| 'accept', |
| 'accept-charset', |
| 'accept-encoding', |
| 'accept-language', |
| 'accept-ranges', |
| 'cache-control', |
| 'content-encoding', |
| 'content-language', |
| 'content-location', |
| 'content-md5', |
| 'content-range', |
| 'content-type', |
| 'connection', |
| 'date', |
| 'expect', |
| 'max-forwards', |
| 'pragma', |
| 'referer', |
| 'te', |
| 'user-agent', |
| 'via' |
| ] |
| |
| var defaultProxyHeaderExclusiveList = [ |
| 'proxy-authorization' |
| ] |
| |
| function constructProxyHost(uriObject) { |
| var port = uriObject.port |
| , protocol = uriObject.protocol |
| , proxyHost = uriObject.hostname + ':' |
| |
| if (port) { |
| proxyHost += port |
| } else if (protocol === 'https:') { |
| proxyHost += '443' |
| } else { |
| proxyHost += '80' |
| } |
| |
| return proxyHost |
| } |
| |
| function constructProxyHeaderWhiteList(headers, proxyHeaderWhiteList) { |
| var whiteList = proxyHeaderWhiteList |
| .reduce(function (set, header) { |
| set[header.toLowerCase()] = true |
| return set |
| }, {}) |
| |
| return Object.keys(headers) |
| .filter(function (header) { |
| return whiteList[header.toLowerCase()] |
| }) |
| .reduce(function (set, header) { |
| set[header] = headers[header] |
| return set |
| }, {}) |
| } |
| |
| function constructTunnelOptions (request, proxyHeaders) { |
| var proxy = request.proxy |
| |
| var tunnelOptions = { |
| proxy : { |
| host : proxy.hostname, |
| port : +proxy.port, |
| proxyAuth : proxy.auth, |
| headers : proxyHeaders |
| }, |
| headers : request.headers, |
| ca : request.ca, |
| cert : request.cert, |
| key : request.key, |
| passphrase : request.passphrase, |
| pfx : request.pfx, |
| ciphers : request.ciphers, |
| rejectUnauthorized : request.rejectUnauthorized, |
| secureOptions : request.secureOptions, |
| secureProtocol : request.secureProtocol |
| } |
| |
| return tunnelOptions |
| } |
| |
| function constructTunnelFnName(uri, proxy) { |
| var uriProtocol = (uri.protocol === 'https:' ? 'https' : 'http') |
| var proxyProtocol = (proxy.protocol === 'https:' ? 'Https' : 'Http') |
| return [uriProtocol, proxyProtocol].join('Over') |
| } |
| |
| function getTunnelFn(request) { |
| var uri = request.uri |
| var proxy = request.proxy |
| var tunnelFnName = constructTunnelFnName(uri, proxy) |
| return tunnel[tunnelFnName] |
| } |
| |
| |
| function Tunnel (request) { |
| this.request = request |
| this.proxyHeaderWhiteList = defaultProxyHeaderWhiteList |
| this.proxyHeaderExclusiveList = [] |
| if (typeof request.tunnel !== 'undefined') { |
| this.tunnelOverride = request.tunnel |
| } |
| } |
| |
| Tunnel.prototype.isEnabled = function () { |
| var self = this |
| , request = self.request |
| // Tunnel HTTPS by default. Allow the user to override this setting. |
| |
| // If self.tunnelOverride is set (the user specified a value), use it. |
| if (typeof self.tunnelOverride !== 'undefined') { |
| return self.tunnelOverride |
| } |
| |
| // If the destination is HTTPS, tunnel. |
| if (request.uri.protocol === 'https:') { |
| return true |
| } |
| |
| // Otherwise, do not use tunnel. |
| return false |
| } |
| |
| Tunnel.prototype.setup = function (options) { |
| var self = this |
| , request = self.request |
| |
| options = options || {} |
| |
| if (typeof request.proxy === 'string') { |
| request.proxy = url.parse(request.proxy) |
| } |
| |
| if (!request.proxy || !request.tunnel) { |
| return false |
| } |
| |
| // Setup Proxy Header Exclusive List and White List |
| if (options.proxyHeaderWhiteList) { |
| self.proxyHeaderWhiteList = options.proxyHeaderWhiteList |
| } |
| if (options.proxyHeaderExclusiveList) { |
| self.proxyHeaderExclusiveList = options.proxyHeaderExclusiveList |
| } |
| |
| var proxyHeaderExclusiveList = self.proxyHeaderExclusiveList.concat(defaultProxyHeaderExclusiveList) |
| var proxyHeaderWhiteList = self.proxyHeaderWhiteList.concat(proxyHeaderExclusiveList) |
| |
| // Setup Proxy Headers and Proxy Headers Host |
| // Only send the Proxy White Listed Header names |
| var proxyHeaders = constructProxyHeaderWhiteList(request.headers, proxyHeaderWhiteList) |
| proxyHeaders.host = constructProxyHost(request.uri) |
| |
| proxyHeaderExclusiveList.forEach(request.removeHeader, request) |
| |
| // Set Agent from Tunnel Data |
| var tunnelFn = getTunnelFn(request) |
| var tunnelOptions = constructTunnelOptions(request, proxyHeaders) |
| request.agent = tunnelFn(tunnelOptions) |
| |
| return true |
| } |
| |
| Tunnel.defaultProxyHeaderWhiteList = defaultProxyHeaderWhiteList |
| Tunnel.defaultProxyHeaderExclusiveList = defaultProxyHeaderExclusiveList |
| exports.Tunnel = Tunnel |