3 var url = require('url')
4 , tunnel = require('tunnel-agent')
6 var defaultProxyHeaderWhiteList = [
30 var defaultProxyHeaderExclusiveList = [
34 function constructProxyHost(uriObject) {
35 var port = uriObject.port
36 , protocol = uriObject.protocol
37 , proxyHost = uriObject.hostname + ':'
41 } else if (protocol === 'https:') {
50 function constructProxyHeaderWhiteList(headers, proxyHeaderWhiteList) {
51 var whiteList = proxyHeaderWhiteList
52 .reduce(function (set, header) {
53 set[header.toLowerCase()] = true
57 return Object.keys(headers)
58 .filter(function (header) {
59 return whiteList[header.toLowerCase()]
61 .reduce(function (set, header) {
62 set[header] = headers[header]
67 function constructTunnelOptions (request, proxyHeaders) {
68 var proxy = request.proxy
72 host : proxy.hostname,
74 proxyAuth : proxy.auth,
75 headers : proxyHeaders
77 headers : request.headers,
81 passphrase : request.passphrase,
83 ciphers : request.ciphers,
84 rejectUnauthorized : request.rejectUnauthorized,
85 secureOptions : request.secureOptions,
86 secureProtocol : request.secureProtocol
92 function constructTunnelFnName(uri, proxy) {
93 var uriProtocol = (uri.protocol === 'https:' ? 'https' : 'http')
94 var proxyProtocol = (proxy.protocol === 'https:' ? 'Https' : 'Http')
95 return [uriProtocol, proxyProtocol].join('Over')
98 function getTunnelFn(request) {
100 var proxy = request.proxy
101 var tunnelFnName = constructTunnelFnName(uri, proxy)
102 return tunnel[tunnelFnName]
106 function Tunnel (request) {
107 this.request = request
108 this.proxyHeaderWhiteList = defaultProxyHeaderWhiteList
109 this.proxyHeaderExclusiveList = []
110 if (typeof request.tunnel !== 'undefined') {
111 this.tunnelOverride = request.tunnel
115 Tunnel.prototype.isEnabled = function () {
117 , request = self.request
118 // Tunnel HTTPS by default. Allow the user to override this setting.
120 // If self.tunnelOverride is set (the user specified a value), use it.
121 if (typeof self.tunnelOverride !== 'undefined') {
122 return self.tunnelOverride
125 // If the destination is HTTPS, tunnel.
126 if (request.uri.protocol === 'https:') {
130 // Otherwise, do not use tunnel.
134 Tunnel.prototype.setup = function (options) {
136 , request = self.request
138 options = options || {}
140 if (typeof request.proxy === 'string') {
141 request.proxy = url.parse(request.proxy)
144 if (!request.proxy || !request.tunnel) {
148 // Setup Proxy Header Exclusive List and White List
149 if (options.proxyHeaderWhiteList) {
150 self.proxyHeaderWhiteList = options.proxyHeaderWhiteList
152 if (options.proxyHeaderExclusiveList) {
153 self.proxyHeaderExclusiveList = options.proxyHeaderExclusiveList
156 var proxyHeaderExclusiveList = self.proxyHeaderExclusiveList.concat(defaultProxyHeaderExclusiveList)
157 var proxyHeaderWhiteList = self.proxyHeaderWhiteList.concat(proxyHeaderExclusiveList)
159 // Setup Proxy Headers and Proxy Headers Host
160 // Only send the Proxy White Listed Header names
161 var proxyHeaders = constructProxyHeaderWhiteList(request.headers, proxyHeaderWhiteList)
162 proxyHeaders.host = constructProxyHost(request.uri)
164 proxyHeaderExclusiveList.forEach(request.removeHeader, request)
166 // Set Agent from Tunnel Data
167 var tunnelFn = getTunnelFn(request)
168 var tunnelOptions = constructTunnelOptions(request, proxyHeaders)
169 request.agent = tunnelFn(tunnelOptions)
174 Tunnel.defaultProxyHeaderWhiteList = defaultProxyHeaderWhiteList
175 Tunnel.defaultProxyHeaderExclusiveList = defaultProxyHeaderExclusiveList
176 exports.Tunnel = Tunnel