You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					176 lines
				
				4.3 KiB
			
		
		
			
		
	
	
					176 lines
				
				4.3 KiB
			| 
											3 years ago
										 | 'use strict' | ||
|  | 
 | ||
|  | var url = require('url') | ||
|  | var 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 | ||
|  |   var protocol = uriObject.protocol | ||
|  |   var 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 | ||
|  |   var 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 | ||
|  |   var 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 |