1 | 'use strict'
|
---|
2 |
|
---|
3 | var url = require('url')
|
---|
4 | var tunnel = require('tunnel-agent')
|
---|
5 |
|
---|
6 | var 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 |
|
---|
30 | var defaultProxyHeaderExclusiveList = [
|
---|
31 | 'proxy-authorization'
|
---|
32 | ]
|
---|
33 |
|
---|
34 | function 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 |
|
---|
50 | function 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 |
|
---|
67 | function 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 |
|
---|
92 | function 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 |
|
---|
98 | function 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 | function 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 |
|
---|
114 | Tunnel.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 |
|
---|
133 | Tunnel.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 |
|
---|
173 | Tunnel.defaultProxyHeaderWhiteList = defaultProxyHeaderWhiteList
|
---|
174 | Tunnel.defaultProxyHeaderExclusiveList = defaultProxyHeaderExclusiveList
|
---|
175 | exports.Tunnel = Tunnel
|
---|