UNPKG

4.42 kBJavaScriptView Raw
1'use strict'
2
3var url = require('url')
4var tunnel = require('tunnel-agent')
5
6var 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
30var defaultProxyHeaderExclusiveList = [
31 'proxy-authorization'
32]
33
34function 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
50function 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
67function 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
92function 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
98function getTunnelFn (request) {
99 var uri = request.uri
100 var proxy = request.proxy
101 var tunnelFnName = constructTunnelFnName(uri, proxy)
102 return tunnel[tunnelFnName]
103}
104
105function 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
114Tunnel.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
133Tunnel.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
173Tunnel.defaultProxyHeaderWhiteList = defaultProxyHeaderWhiteList
174Tunnel.defaultProxyHeaderExclusiveList = defaultProxyHeaderExclusiveList
175exports.Tunnel = Tunnel