179 lines
4.5 KiB
JavaScript
179 lines
4.5 KiB
JavaScript
|
'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-length',
|
||
|
'content-location',
|
||
|
'content-md5',
|
||
|
'content-range',
|
||
|
'content-type',
|
||
|
'connection',
|
||
|
'date',
|
||
|
'expect',
|
||
|
'max-forwards',
|
||
|
'pragma',
|
||
|
'referer',
|
||
|
'te',
|
||
|
'transfer-encoding',
|
||
|
'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
|