diff --git a/src/Commands/RunRepeater.ts b/src/Commands/RunRepeater.ts index a31ee853..45fc33db 100644 --- a/src/Commands/RunRepeater.ts +++ b/src/Commands/RunRepeater.ts @@ -135,17 +135,19 @@ export class RunRepeater implements CommandModule { requiresArg: true, array: true, describe: - 'Comma-separated list of domains that should be routed through the proxy. This option is only applicable when using the --proxy option' + 'Space-separated list of domains that should be routed through the proxy. This option is only applicable when using the --proxy option' + }) + .option('proxy-domains-bypass', { + requiresArg: true, + array: true, + describe: + 'Space-separated list of domains that should not be routed through the proxy. This option is only applicable when using the --proxy option' }) .conflicts({ daemon: 'remove-daemon', - ntlm: [ - 'proxy', - 'proxy-bright', - 'proxy-target', - 'experimental-connection-reuse' - ] + ntlm: ['proxy', 'experimental-connection-reuse'] }) + .conflicts('proxy-domains', 'proxy-domains-bypass') .env('REPEATER') .middleware((args: Arguments) => { if (Object.hasOwnProperty.call(args, '')) { @@ -196,7 +198,8 @@ export class RunRepeater implements CommandModule { { type: 'application/ld+json', allowTruncation: false }, { type: 'application/graphql', allowTruncation: false } ], - proxyDomains: args.proxyDomains as string[] + proxyDomains: args.proxyDomains as string[], + proxyDomainsBypass: args.proxyDomainsBypass as string[] } }) .register( diff --git a/src/RequestExecutor/HttpRequestExecutor.ts b/src/RequestExecutor/HttpRequestExecutor.ts index 408da629..b4534fd7 100644 --- a/src/RequestExecutor/HttpRequestExecutor.ts +++ b/src/RequestExecutor/HttpRequestExecutor.ts @@ -40,6 +40,7 @@ export class HttpRequestExecutor implements RequestExecutor { private readonly httpAgent?: http.Agent; private readonly httpsAgent?: https.Agent; private readonly proxyDomains?: RegExp[]; + private readonly proxyDomainsBypass?: RegExp[]; get protocol(): Protocol { return Protocol.HTTP; @@ -67,11 +68,23 @@ export class HttpRequestExecutor implements RequestExecutor { this.httpAgent = new http.Agent(agentOptions); } + if (this.options.proxyDomains && this.options.proxyDomainsBypass) { + throw new Error( + 'cannot use both proxyDomains and proxyDomainsBypass at the same time' + ); + } + if (this.options.proxyDomains) { this.proxyDomains = this.options.proxyDomains.map((domain) => Helpers.wildcardToRegExp(domain) ); } + + if (this.options.proxyDomainsBypass) { + this.proxyDomainsBypass = this.options.proxyDomainsBypass.map((domain) => + Helpers.wildcardToRegExp(domain) + ); + } } public async execute(options: Request): Promise { @@ -197,12 +210,27 @@ export class HttpRequestExecutor implements RequestExecutor { } private getRequestAgent(options: Request) { + // do not use proxy for domains that are not in the list if ( this.proxyDomains && !this.proxyDomains.some((domain) => domain.test(parseUrl(options.url).hostname) ) ) { + logger.debug("Not using proxy for URL '%s'", options.url); + + return options.secureEndpoint ? this.httpsAgent : this.httpAgent; + } + + // do not use proxy for domains that are in the bypass list + if ( + this.proxyDomainsBypass && + this.proxyDomainsBypass.some((domain) => + domain.test(parseUrl(options.url).hostname) + ) + ) { + logger.debug("Bypassing proxy for URL '%s'", options.url); + return options.secureEndpoint ? this.httpsAgent : this.httpAgent; } diff --git a/src/RequestExecutor/RequestExecutorOptions.ts b/src/RequestExecutor/RequestExecutorOptions.ts index 374013df..9579324c 100644 --- a/src/RequestExecutor/RequestExecutorOptions.ts +++ b/src/RequestExecutor/RequestExecutorOptions.ts @@ -15,6 +15,7 @@ export interface RequestExecutorOptions { maxContentLength?: number; reuseConnection?: boolean; proxyDomains?: string[]; + proxyDomainsBypass?: string[]; } export const RequestExecutorOptions: unique symbol = Symbol(