UNPKG

4.54 kBJavaScriptView Raw
1'use strict'
2
3var url = require('url')
4 , 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 , protocol = uriObject.protocol
37 , 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
105
106function Tunnel (request) {
107 this.request = request
108 this.proxyHeaderWhiteList = defaultProxyHeaderWhiteList
109 this.proxyHeaderExclusiveList = []
110 if (typeof request.tunnel !== 'undefined') {
111 this.tunnelOverride = request.tunnel
112 }
113}
114
115Tunnel.prototype.isEnabled = function () {
116 var self = this
117 , request = self.request
118 // Tunnel HTTPS by default. Allow the user to override this setting.
119
120 // If self.tunnelOverride is set (the user specified a value), use it.
121 if (typeof self.tunnelOverride !== 'undefined') {
122 return self.tunnelOverride
123 }
124
125 // If the destination is HTTPS, tunnel.
126 if (request.uri.protocol === 'https:') {
127 return true
128 }
129
130 // Otherwise, do not use tunnel.
131 return false
132}
133
134Tunnel.prototype.setup = function (options) {
135 var self = this
136 , request = self.request
137
138 options = options || {}
139
140 if (typeof request.proxy === 'string') {
141 request.proxy = url.parse(request.proxy)
142 }
143
144 if (!request.proxy || !request.tunnel) {
145 return false
146 }
147
148 // Setup Proxy Header Exclusive List and White List
149 if (options.proxyHeaderWhiteList) {
150 self.proxyHeaderWhiteList = options.proxyHeaderWhiteList
151 }
152 if (options.proxyHeaderExclusiveList) {
153 self.proxyHeaderExclusiveList = options.proxyHeaderExclusiveList
154 }
155
156 var proxyHeaderExclusiveList = self.proxyHeaderExclusiveList.concat(defaultProxyHeaderExclusiveList)
157 var proxyHeaderWhiteList = self.proxyHeaderWhiteList.concat(proxyHeaderExclusiveList)
158
159 // Setup Proxy Headers and Proxy Headers Host
160 // Only send the Proxy White Listed Header names
161 var proxyHeaders = constructProxyHeaderWhiteList(request.headers, proxyHeaderWhiteList)
162 proxyHeaders.host = constructProxyHost(request.uri)
163
164 proxyHeaderExclusiveList.forEach(request.removeHeader, request)
165
166 // Set Agent from Tunnel Data
167 var tunnelFn = getTunnelFn(request)
168 var tunnelOptions = constructTunnelOptions(request, proxyHeaders)
169 request.agent = tunnelFn(tunnelOptions)
170
171 return true
172}
173
174Tunnel.defaultProxyHeaderWhiteList = defaultProxyHeaderWhiteList
175Tunnel.defaultProxyHeaderExclusiveList = defaultProxyHeaderExclusiveList
176exports.Tunnel = Tunnel