diff options
Diffstat (limited to 'node_modules/global-agent/src/classes')
| -rw-r--r-- | node_modules/global-agent/src/classes/Agent.js | 212 | ||||
| -rw-r--r-- | node_modules/global-agent/src/classes/HttpProxyAgent.js | 30 | ||||
| -rw-r--r-- | node_modules/global-agent/src/classes/HttpsProxyAgent.js | 54 | ||||
| -rw-r--r-- | node_modules/global-agent/src/classes/index.js | 5 | 
4 files changed, 301 insertions, 0 deletions
| diff --git a/node_modules/global-agent/src/classes/Agent.js b/node_modules/global-agent/src/classes/Agent.js new file mode 100644 index 0000000..801dd1f --- /dev/null +++ b/node_modules/global-agent/src/classes/Agent.js @@ -0,0 +1,212 @@ +// @flow + +import { +  serializeError, +} from 'serialize-error'; +import { +  boolean, +} from 'boolean'; +import Logger from '../Logger'; +import type { +  AgentType, +  GetUrlProxyMethodType, +  IsProxyConfiguredMethodType, +  MustUrlUseProxyMethodType, +  ProtocolType, +} from '../types'; + +const log = Logger.child({ +  namespace: 'Agent', +}); + +let requestId = 0; + +class Agent { +  defaultPort: number; + +  protocol: ProtocolType; + +  fallbackAgent: AgentType; + +  isProxyConfigured: IsProxyConfiguredMethodType; + +  mustUrlUseProxy: MustUrlUseProxyMethodType; + +  getUrlProxy: GetUrlProxyMethodType; + +  socketConnectionTimeout: number; + +  constructor ( +    isProxyConfigured: IsProxyConfiguredMethodType, +    mustUrlUseProxy: MustUrlUseProxyMethodType, +    getUrlProxy: GetUrlProxyMethodType, +    fallbackAgent: AgentType, +    socketConnectionTimeout: number, +  ) { +    this.fallbackAgent = fallbackAgent; +    this.isProxyConfigured = isProxyConfigured; +    this.mustUrlUseProxy = mustUrlUseProxy; +    this.getUrlProxy = getUrlProxy; +    this.socketConnectionTimeout = socketConnectionTimeout; +  } + +  addRequest (request: *, configuration: *) { +    let requestUrl; + +    // It is possible that addRequest was constructed for a proxied request already, e.g. +    // "request" package does this when it detects that a proxy should be used +    // https://github.com/request/request/blob/212570b6971a732b8dd9f3c73354bcdda158a737/request.js#L402 +    // https://gist.github.com/gajus/e2074cd3b747864ffeaabbd530d30218 +    if (request.path.startsWith('http://') || request.path.startsWith('https://')) { +      requestUrl = request.path; +    } else { +      requestUrl = this.protocol + '//' + (configuration.hostname || configuration.host) + (configuration.port === 80 || configuration.port === 443 ? '' : ':' + configuration.port) + request.path; +    } + +    if (!this.isProxyConfigured()) { +      log.trace({ +        destination: requestUrl, +      }, 'not proxying request; GLOBAL_AGENT.HTTP_PROXY is not configured'); + +      // $FlowFixMe It appears that Flow is missing the method description. +      this.fallbackAgent.addRequest(request, configuration); + +      return; +    } + +    if (!this.mustUrlUseProxy(requestUrl)) { +      log.trace({ +        destination: requestUrl, +      }, 'not proxying request; url matches GLOBAL_AGENT.NO_PROXY'); + +      // $FlowFixMe It appears that Flow is missing the method description. +      this.fallbackAgent.addRequest(request, configuration); + +      return; +    } + +    const currentRequestId = requestId++; + +    const proxy = this.getUrlProxy(requestUrl); + +    if (this.protocol === 'http:') { +      request.path = requestUrl; + +      if (proxy.authorization) { +        request.setHeader('proxy-authorization', 'Basic ' + Buffer.from(proxy.authorization).toString('base64')); +      } +    } + +    log.trace({ +      destination: requestUrl, +      proxy: 'http://' + proxy.hostname + ':' + proxy.port, +      requestId: currentRequestId, +    }, 'proxying request'); + +    request.on('error', (error) => { +      log.error({ +        error: serializeError(error), +      }, 'request error'); +    }); + +    request.once('response', (response) => { +      log.trace({ +        headers: response.headers, +        requestId: currentRequestId, +        statusCode: response.statusCode, +      }, 'proxying response'); +    }); + +    request.shouldKeepAlive = false; + +    const connectionConfiguration = { +      host: configuration.hostname || configuration.host, +      port: configuration.port || 80, +      proxy, +      tls: {}, +    }; + +    // add optional tls options for https requests. +    // @see https://nodejs.org/docs/latest-v12.x/api/https.html#https_https_request_url_options_callback : +    // > The following additional options from tls.connect() +    // >   - https://nodejs.org/docs/latest-v12.x/api/tls.html#tls_tls_connect_options_callback - +    // > are also accepted: +    // >   ca, cert, ciphers, clientCertEngine, crl, dhparam, ecdhCurve, honorCipherOrder, +    // >   key, passphrase, pfx, rejectUnauthorized, secureOptions, secureProtocol, servername, sessionIdContext. +    if (this.protocol === 'https:') { +      connectionConfiguration.tls = { +        ca: configuration.ca, +        cert: configuration.cert, +        ciphers: configuration.ciphers, +        clientCertEngine: configuration.clientCertEngine, +        crl: configuration.crl, +        dhparam: configuration.dhparam, +        ecdhCurve: configuration.ecdhCurve, +        honorCipherOrder: configuration.honorCipherOrder, +        key: configuration.key, +        passphrase: configuration.passphrase, +        pfx: configuration.pfx, +        rejectUnauthorized: configuration.rejectUnauthorized, +        secureOptions: configuration.secureOptions, +        secureProtocol: configuration.secureProtocol, +        servername: configuration.servername || connectionConfiguration.host, +        sessionIdContext: configuration.sessionIdContext, +      }; + +      // This is not ideal because there is no way to override this setting using `tls` configuration if `NODE_TLS_REJECT_UNAUTHORIZED=0`. +      // However, popular HTTP clients (such as https://github.com/sindresorhus/got) come with pre-configured value for `rejectUnauthorized`, +      // which makes it impossible to override that value globally and respect `rejectUnauthorized` for specific requests only. +      // +      // eslint-disable-next-line no-process-env +      if (typeof process.env.NODE_TLS_REJECT_UNAUTHORIZED === 'string' && boolean(process.env.NODE_TLS_REJECT_UNAUTHORIZED) === false) { +        connectionConfiguration.tls.rejectUnauthorized = false; +      } +    } + +    // $FlowFixMe It appears that Flow is missing the method description. +    this.createConnection(connectionConfiguration, (error, socket) => { +      log.trace({ +        target: connectionConfiguration, +      }, 'connecting'); + +      // @see https://github.com/nodejs/node/issues/5757#issuecomment-305969057 +      if (socket) { +        socket.setTimeout(this.socketConnectionTimeout, () => { +          socket.destroy(); +        }); + +        socket.once('connect', () => { +          log.trace({ +            target: connectionConfiguration, +          }, 'connected'); + +          socket.setTimeout(0); +        }); + +        socket.once('secureConnect', () => { +          log.trace({ +            target: connectionConfiguration, +          }, 'connected (secure)'); + +          socket.setTimeout(0); +        }); +      } + +      if (error) { +        request.emit('error', error); +      } else { +        log.debug('created socket'); + +        socket.on('error', (socketError) => { +          log.error({ +            error: serializeError(socketError), +          }, 'socket error'); +        }); + +        request.onSocket(socket); +      } +    }); +  } +} + +export default Agent; diff --git a/node_modules/global-agent/src/classes/HttpProxyAgent.js b/node_modules/global-agent/src/classes/HttpProxyAgent.js new file mode 100644 index 0000000..8b9b471 --- /dev/null +++ b/node_modules/global-agent/src/classes/HttpProxyAgent.js @@ -0,0 +1,30 @@ +// @flow + +import net from 'net'; +import type { +  ConnectionCallbackType, +  ConnectionConfigurationType, +} from '../types'; +import Agent from './Agent'; + +class HttpProxyAgent extends Agent { +  // @see https://github.com/sindresorhus/eslint-plugin-unicorn/issues/169#issuecomment-486980290 +  // eslint-disable-next-line unicorn/prevent-abbreviations +  constructor (...args: *) { +    super(...args); + +    this.protocol = 'http:'; +    this.defaultPort = 80; +  } + +  createConnection (configuration: ConnectionConfigurationType, callback: ConnectionCallbackType) { +    const socket = net.connect( +      configuration.proxy.port, +      configuration.proxy.hostname, +    ); + +    callback(null, socket); +  } +} + +export default HttpProxyAgent; diff --git a/node_modules/global-agent/src/classes/HttpsProxyAgent.js b/node_modules/global-agent/src/classes/HttpsProxyAgent.js new file mode 100644 index 0000000..24d724f --- /dev/null +++ b/node_modules/global-agent/src/classes/HttpsProxyAgent.js @@ -0,0 +1,54 @@ +// @flow + +import net from 'net'; +import tls from 'tls'; +import type { +  ConnectionCallbackType, +  ConnectionConfigurationType, +} from '../types'; +import Agent from './Agent'; + +class HttpsProxyAgent extends Agent { +  // eslint-disable-next-line unicorn/prevent-abbreviations +  constructor (...args: *) { +    super(...args); + +    this.protocol = 'https:'; +    this.defaultPort = 443; +  } + +  createConnection (configuration: ConnectionConfigurationType, callback: ConnectionCallbackType) { +    const socket = net.connect( +      configuration.proxy.port, +      configuration.proxy.hostname, +    ); + +    socket.on('error', (error) => { +      callback(error); +    }); + +    socket.once('data', () => { +      const secureSocket = tls.connect({ +        ...configuration.tls, +        socket, +      }); + +      callback(null, secureSocket); +    }); + +    let connectMessage = ''; + +    connectMessage += 'CONNECT ' + configuration.host + ':' + configuration.port + ' HTTP/1.1\r\n'; +    connectMessage += 'Host: ' + configuration.host + ':' + configuration.port + '\r\n'; + +    if (configuration.proxy.authorization) { +      connectMessage += 'Proxy-Authorization: Basic ' + Buffer.from(configuration.proxy.authorization).toString('base64') + '\r\n'; +    } + +    connectMessage += '\r\n'; + +    socket.write(connectMessage); +  } +} + +export default HttpsProxyAgent; diff --git a/node_modules/global-agent/src/classes/index.js b/node_modules/global-agent/src/classes/index.js new file mode 100644 index 0000000..9e8418a --- /dev/null +++ b/node_modules/global-agent/src/classes/index.js @@ -0,0 +1,5 @@ +// @flow + +export {default as Agent} from './Agent'; +export {default as HttpProxyAgent} from './HttpProxyAgent'; +export {default as HttpsProxyAgent} from './HttpsProxyAgent'; | 
