UNPKG

@applitools/execution-grid-tunnel

Version:

Allows user to run tests with exection-grid and navigate to private hosts and ips

145 lines (129 loc) 4.36 kB
const {createSocks5ProxyServer, EVENTS} = require('@applitools/eg-socks5-proxy-server') const {parsePacDirectives} = require('./parse-pac-directives') module.exports = async function ({port, logger, findProxyForURL}) { const socks5Proxy = createSocks5ProxyServer() socks5Proxy.on( EVENTS.REMOTE_CONNECTION_TIMEOUT_ERROR, ({originInfo, destinationInfo: {address, port}}) => logger.error({ action: 'remote-connection-timeout-error', address, port, originInfo, }), ) socks5Proxy.on(EVENTS.ORIGIN_SOCKET_ERROR, ({err}) => logger.warn({ action: 'origin-socket-error', error: err, }), ) socks5Proxy.on( EVENTS.REMOTE_SOCKET_ERROR, ({err, destination, args, originInfo, destinationInfo: {address, port}}) => logger.warn({ action: 'remote-socket-error', error: err, address, port, }), ) socks5Proxy.on(EVENTS.ACCEPT_NEW_REQUEST, ({destinationInfo: {address, port}}) => logger.info({ action: 'socks5-accept-new-request', address, port, }), ) socks5Proxy.on(EVENTS.CONNECTED_TO_REMOTE_ADDRESS, ({destinationInfo: {address, port}}) => logger.info({ action: 'connected-to-remote-address', address, port, }), ) // HTTP CONNECT upstream path lifecycle (client-side PAC routing). These // events come from @applitools/eg-socks5-proxy-server ≥ 1.1.0 when a // resolver is registered via `setHttpProxyResolver(...)` below. Subscribing // unconditionally is safe — they never fire when no resolver is set, so // existing DIRECT-only / SOCKS5-chain consumers see no new log lines. socks5Proxy.on(EVENTS.CONNECTED_TO_HTTP_PROXY, ({destinationInfo, proxyInfo}) => logger.info({ action: 'connected-to-http-proxy', address: destinationInfo && destinationInfo.address, port: destinationInfo && destinationInfo.port, proxyInfo, }), ) socks5Proxy.on( EVENTS.HTTP_PROXY_CONNECT_RESPONDED, ({destinationInfo, proxyInfo, statusCode}) => { const isOk = statusCode >= 200 && statusCode < 300 logger[isOk ? 'info' : 'warn']({ action: 'http-proxy-connect-responded', address: destinationInfo && destinationInfo.address, port: destinationInfo && destinationInfo.port, proxyInfo, statusCode, }) }, ) socks5Proxy.on( EVENTS.HTTP_PROXY_CONNECT_FAILED, ({destinationInfo, proxyInfo, rfc1928Reply, error}) => logger.warn({ action: 'http-proxy-connect-failed', address: destinationInfo && destinationInfo.address, port: destinationInfo && destinationInfo.port, proxyInfo, rfc1928Reply, error, }), ) await socks5Proxy.listenAsync(port) // Per-request PAC routing adapter — only wired when a compiled // `findProxyForURL` was supplied by the caller (i.e. `pacFile` / `pacScript` // / `pacUrl` was set on `startEgTunnelService`). When unset, the SOCKS5 // server runs in its existing DIRECT-only mode — zero new code path. // // Runtime PAC errors (eval throws, directive parse failures) do NOT crash // the service or the request — they log and fall through to DIRECT. if (findProxyForURL) { socks5Proxy.setHttpProxyResolver(async ({destinationInfo}) => { const address = destinationInfo.address const port = destinationInfo.port let directive try { directive = await findProxyForURL( `http://${address}:${port}/`, address, ) } catch (err) { logger.warn({ action: 'pac-eval-failed', error: err, address, port, }) return null } return parsePacDirectives(directive, {logger, address, port}) }) } const checkConnectionsLeakInterval = setInterval( () => socks5Proxy.getConnections((error, count) => { if (error) return if (count < socks5Proxy.destinationSockets.length) { logger.warn({ action: 'socks5-connections-leak', expectedSockets: count, actualSockets: socks5Proxy.destinationSockets.length, }) } }), 10000, ) socks5Proxy.on('close', () => clearInterval(checkConnectionsLeakInterval)) return socks5Proxy }