tunnel.js (4416B)
1 'use strict' 2 3 var url = require('url') 4 var tunnel = require('tunnel-agent') 5 6 var defaultProxyHeaderWhiteList = [ 7 'accept', 8 'accept-charset', 9 'accept-encoding', 10 'accept-language', 11 'accept-ranges', 12 'cache-control', 13 'content-encoding', 14 'content-language', 15 'content-location', 16 'content-md5', 17 'content-range', 18 'content-type', 19 'connection', 20 'date', 21 'expect', 22 'max-forwards', 23 'pragma', 24 'referer', 25 'te', 26 'user-agent', 27 'via' 28 ] 29 30 var defaultProxyHeaderExclusiveList = [ 31 'proxy-authorization' 32 ] 33 34 function constructProxyHost (uriObject) { 35 var port = uriObject.port 36 var protocol = uriObject.protocol 37 var proxyHost = uriObject.hostname + ':' 38 39 if (port) { 40 proxyHost += port 41 } else if (protocol === 'https:') { 42 proxyHost += '443' 43 } else { 44 proxyHost += '80' 45 } 46 47 return proxyHost 48 } 49 50 function constructProxyHeaderWhiteList (headers, proxyHeaderWhiteList) { 51 var whiteList = proxyHeaderWhiteList 52 .reduce(function (set, header) { 53 set[header.toLowerCase()] = true 54 return set 55 }, {}) 56 57 return Object.keys(headers) 58 .filter(function (header) { 59 return whiteList[header.toLowerCase()] 60 }) 61 .reduce(function (set, header) { 62 set[header] = headers[header] 63 return set 64 }, {}) 65 } 66 67 function constructTunnelOptions (request, proxyHeaders) { 68 var proxy = request.proxy 69 70 var tunnelOptions = { 71 proxy: { 72 host: proxy.hostname, 73 port: +proxy.port, 74 proxyAuth: proxy.auth, 75 headers: proxyHeaders 76 }, 77 headers: request.headers, 78 ca: request.ca, 79 cert: request.cert, 80 key: request.key, 81 passphrase: request.passphrase, 82 pfx: request.pfx, 83 ciphers: request.ciphers, 84 rejectUnauthorized: request.rejectUnauthorized, 85 secureOptions: request.secureOptions, 86 secureProtocol: request.secureProtocol 87 } 88 89 return tunnelOptions 90 } 91 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') 96 } 97 98 function getTunnelFn (request) { 99 var uri = request.uri 100 var proxy = request.proxy 101 var tunnelFnName = constructTunnelFnName(uri, proxy) 102 return tunnel[tunnelFnName] 103 } 104 105 function Tunnel (request) { 106 this.request = request 107 this.proxyHeaderWhiteList = defaultProxyHeaderWhiteList 108 this.proxyHeaderExclusiveList = [] 109 if (typeof request.tunnel !== 'undefined') { 110 this.tunnelOverride = request.tunnel 111 } 112 } 113 114 Tunnel.prototype.isEnabled = function () { 115 var self = this 116 var request = self.request 117 // Tunnel HTTPS by default. Allow the user to override this setting. 118 119 // If self.tunnelOverride is set (the user specified a value), use it. 120 if (typeof self.tunnelOverride !== 'undefined') { 121 return self.tunnelOverride 122 } 123 124 // If the destination is HTTPS, tunnel. 125 if (request.uri.protocol === 'https:') { 126 return true 127 } 128 129 // Otherwise, do not use tunnel. 130 return false 131 } 132 133 Tunnel.prototype.setup = function (options) { 134 var self = this 135 var request = self.request 136 137 options = options || {} 138 139 if (typeof request.proxy === 'string') { 140 request.proxy = url.parse(request.proxy) 141 } 142 143 if (!request.proxy || !request.tunnel) { 144 return false 145 } 146 147 // Setup Proxy Header Exclusive List and White List 148 if (options.proxyHeaderWhiteList) { 149 self.proxyHeaderWhiteList = options.proxyHeaderWhiteList 150 } 151 if (options.proxyHeaderExclusiveList) { 152 self.proxyHeaderExclusiveList = options.proxyHeaderExclusiveList 153 } 154 155 var proxyHeaderExclusiveList = self.proxyHeaderExclusiveList.concat(defaultProxyHeaderExclusiveList) 156 var proxyHeaderWhiteList = self.proxyHeaderWhiteList.concat(proxyHeaderExclusiveList) 157 158 // Setup Proxy Headers and Proxy Headers Host 159 // Only send the Proxy White Listed Header names 160 var proxyHeaders = constructProxyHeaderWhiteList(request.headers, proxyHeaderWhiteList) 161 proxyHeaders.host = constructProxyHost(request.uri) 162 163 proxyHeaderExclusiveList.forEach(request.removeHeader, request) 164 165 // Set Agent from Tunnel Data 166 var tunnelFn = getTunnelFn(request) 167 var tunnelOptions = constructTunnelOptions(request, proxyHeaders) 168 request.agent = tunnelFn(tunnelOptions) 169 170 return true 171 } 172 173 Tunnel.defaultProxyHeaderWhiteList = defaultProxyHeaderWhiteList 174 Tunnel.defaultProxyHeaderExclusiveList = defaultProxyHeaderExclusiveList 175 exports.Tunnel = Tunnel