176 lines
		
	
	
		
			4.3 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			176 lines
		
	
	
		
			4.3 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| '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
 | 
