(opts)
| 96 | |
| 97 | class ProxyAgent extends DispatcherBase { |
| 98 | constructor (opts) { |
| 99 | if (!opts || (typeof opts === 'object' && !(opts instanceof URL) && !opts.uri)) { |
| 100 | throw new InvalidArgumentError('Proxy uri is mandatory') |
| 101 | } |
| 102 | |
| 103 | const { clientFactory = defaultFactory } = opts |
| 104 | if (typeof clientFactory !== 'function') { |
| 105 | throw new InvalidArgumentError('Proxy opts.clientFactory must be a function.') |
| 106 | } |
| 107 | |
| 108 | const { proxyTunnel = true, connectTimeout } = opts |
| 109 | |
| 110 | super() |
| 111 | |
| 112 | const url = this.#getUrl(opts) |
| 113 | const { href, origin, port, protocol, username, password, hostname: proxyHostname } = url |
| 114 | |
| 115 | this[kProxy] = { uri: href, protocol } |
| 116 | this[kRequestTls] = opts.requestTls |
| 117 | this[kProxyTls] = opts.proxyTls |
| 118 | this[kProxyHeaders] = opts.headers || {} |
| 119 | this[kTunnelProxy] = proxyTunnel |
| 120 | |
| 121 | if (opts.auth && opts.token) { |
| 122 | throw new InvalidArgumentError('opts.auth cannot be used in combination with opts.token') |
| 123 | } else if (opts.auth) { |
| 124 | /* @deprecated in favour of opts.token */ |
| 125 | this[kProxyHeaders]['proxy-authorization'] = `Basic ${opts.auth}` |
| 126 | } else if (opts.token) { |
| 127 | this[kProxyHeaders]['proxy-authorization'] = opts.token |
| 128 | } else if (username && password) { |
| 129 | this[kProxyHeaders]['proxy-authorization'] = `Basic ${Buffer.from(`${decodeURIComponent(username)}:${decodeURIComponent(password)}`).toString('base64')}` |
| 130 | } else if (username) { |
| 131 | this[kProxyHeaders]['proxy-authorization'] = `Basic ${Buffer.from(`${decodeURIComponent(username)}:`).toString('base64')}` |
| 132 | } |
| 133 | |
| 134 | const connect = buildConnector({ timeout: connectTimeout, ...opts.proxyTls }) |
| 135 | this[kConnectEndpoint] = buildConnector({ timeout: connectTimeout, ...opts.requestTls }) |
| 136 | this[kConnectEndpointHTTP1] = buildConnector({ timeout: connectTimeout, ...opts.requestTls, allowH2: false }) |
| 137 | |
| 138 | const agentFactory = opts.factory || defaultAgentFactory |
| 139 | const factory = (origin, options) => { |
| 140 | const { protocol } = new URL(origin) |
| 141 | |
| 142 | // Handle SOCKS5 proxy |
| 143 | if (this[kProxy].protocol === 'socks5:' || this[kProxy].protocol === 'socks:') { |
| 144 | return new Socks5ProxyAgent(this[kProxy].uri, { |
| 145 | headers: this[kProxyHeaders], |
| 146 | connect, |
| 147 | factory: agentFactory, |
| 148 | username: opts.username || username, |
| 149 | password: opts.password || password, |
| 150 | proxyTls: opts.proxyTls, |
| 151 | requestTls: opts.requestTls |
| 152 | }) |
| 153 | } |
| 154 | |
| 155 | if (!this[kTunnelProxy] && protocol === 'http:' && this[kProxy].protocol === 'http:') { |
nothing calls this directly
no test coverage detected