fix(core): Proxy all HTTP traffic instead of only axios (#20614)

This commit is contained in:
Elias Meire
2025-10-16 10:49:52 +03:00
committed by GitHub
parent fbb35d432c
commit f41b86402e
7 changed files with 460 additions and 187 deletions
+5 -3
View File
@@ -1,3 +1,5 @@
import { CLI_DIR, EDITOR_UI_DIST_DIR, inE2ETests } from '@/constants';
import type { ICredentialsOverwrite } from '@/interfaces';
import { inDevelopment, inProduction } from '@n8n/backend-common';
import { SecurityConfig } from '@n8n/config';
import { Time } from '@n8n/constants';
@@ -8,20 +10,18 @@ import express from 'express';
import { access as fsAccess } from 'fs/promises';
import helmet from 'helmet';
import isEmpty from 'lodash/isEmpty';
import { InstanceSettings } from 'n8n-core';
import { InstanceSettings, installGlobalProxyAgent } from 'n8n-core';
import { jsonParse } from 'n8n-workflow';
import { resolve } from 'path';
import { AbstractServer } from '@/abstract-server';
import { AuthService } from '@/auth/auth.service';
import config from '@/config';
import { CLI_DIR, EDITOR_UI_DIST_DIR, inE2ETests } from '@/constants';
import { ControllerRegistry } from '@/controller.registry';
import { CredentialsOverwrites } from '@/credentials-overwrites';
import { MessageEventBus } from '@/eventbus/message-event-bus/message-event-bus';
import { EventService } from '@/events/event.service';
import { LogStreamingEventRelay } from '@/events/relays/log-streaming.event-relay';
import type { ICredentialsOverwrite } from '@/interfaces';
import { isLdapEnabled } from '@/ldap.ee/helpers.ee';
import { LoadNodesAndCredentials } from '@/load-nodes-and-credentials';
import { handleMfaDisable, isMfaFeatureEnabled } from '@/mfa/helpers';
@@ -479,6 +479,8 @@ export class Server extends AbstractServer {
} else {
this.app.use('/', express.static(staticCacheDir, cacheOptions));
}
installGlobalProxyAgent();
}
protected setupPushServer(): void {
@@ -0,0 +1,254 @@
import http from 'http';
import https from 'https';
import type { AddressInfo } from 'net';
import nock from 'nock';
import { promisify } from 'util';
import { installGlobalProxyAgent, uninstallGlobalProxyAgent } from '../http-proxy';
interface TestResponse {
message: string;
timestamp: number;
}
interface ProxyRequest {
method: string;
url: string;
timestamp: number;
}
async function createMockProxyServer() {
const capturedRequests: ProxyRequest[] = [];
const server = http.createServer((req, res) => {
capturedRequests.push({
method: req.method ?? 'GET',
url: req.url ?? '',
timestamp: Date.now(),
});
res.setHeader('Content-Type', 'application/json');
res.end(JSON.stringify({ message: 'proxied', timestamp: Date.now() }));
});
server.on('connect', (req, clientSocket) => {
capturedRequests.push({
method: 'CONNECT',
url: req.url ?? '',
timestamp: Date.now(),
});
clientSocket.write('HTTP/1.1 200 Connection Established\r\n\r\n');
clientSocket.end();
});
await new Promise<void>((resolve, reject) => {
server.listen(0, '127.0.0.1', resolve);
server.on('error', reject);
});
const address = server.address() as AddressInfo;
return {
server,
port: address.port,
url: `http://127.0.0.1:${address.port}`,
capturedRequests,
clearRequests: () => (capturedRequests.length = 0),
};
}
async function makeRequest(url: string): Promise<TestResponse> {
return await new Promise((resolve, reject) => {
const urlObj = new URL(url);
const httpModule = urlObj.protocol === 'https:' ? https : http;
const req = httpModule.get(url, { timeout: 5000 }, (res) => {
let data = '';
res.on('data', (chunk) => (data += chunk));
res.on('end', () => {
try {
resolve(JSON.parse(data));
} catch (error) {
reject(error instanceof Error ? error : new Error(String(error)));
}
});
});
req.on('error', reject);
req.on('timeout', () => {
req.destroy();
reject(new Error('Request timeout'));
});
});
}
describe('HTTP Proxy Tests', () => {
let proxyServer: Awaited<ReturnType<typeof createMockProxyServer>>;
beforeAll(async () => {
proxyServer = await createMockProxyServer();
});
afterAll(async () => {
await promisify(proxyServer.server.close.bind(proxyServer.server))();
});
beforeEach(() => {
delete process.env.HTTP_PROXY;
delete process.env.HTTPS_PROXY;
delete process.env.NO_PROXY;
delete process.env.ALL_PROXY;
nock.cleanAll();
nock.restore();
});
afterEach(() => {
uninstallGlobalProxyAgent();
proxyServer.clearRequests();
nock.cleanAll();
});
test.each([
{
name: 'should use HTTP_PROXY for HTTP requests',
env: { HTTP_PROXY: true },
targetUrl: 'http://api.example.com:8080/test',
expectProxied: true,
},
{
name: 'should ignore HTTPS_PROXY for HTTP requests',
env: { HTTPS_PROXY: true },
targetUrl: 'http://api.example.com:8080/test',
expectProxied: false,
},
{
name: 'should use ALL_PROXY when specific proxy not set',
env: { ALL_PROXY: true },
targetUrl: 'http://api.example.com:8080/test',
expectProxied: true,
},
{
name: 'should prefer HTTP_PROXY over ALL_PROXY',
env: { HTTP_PROXY: true, ALL_PROXY: 'http://unused:8080' },
targetUrl: 'http://api.example.com:8080/test',
expectProxied: true,
},
{
name: 'should make direct requests when no proxy configured',
env: {},
targetUrl: 'http://api.example.com:8080/test',
expectProxied: false,
},
{
name: 'should bypass proxy for exact hostname match',
env: { HTTP_PROXY: true, NO_PROXY: 'api.example.com' },
targetUrl: 'http://api.example.com:8080/test',
expectProxied: false,
},
{
name: 'should bypass proxy for exact IP match',
env: { HTTP_PROXY: true, NO_PROXY: '192.168.1.100' },
targetUrl: 'http://192.168.1.100:8080/test',
expectProxied: false,
},
{
name: 'should proxy when hostname not in NO_PROXY',
env: { HTTP_PROXY: true, NO_PROXY: 'example.com' },
targetUrl: 'http://test.local:8080/api',
expectProxied: true,
},
{
name: 'should bypass proxy for wildcard subdomain patterns',
env: { HTTP_PROXY: true, NO_PROXY: '*.local' },
targetUrl: 'http://app.local:8080/api',
expectProxied: false,
},
{
name: 'should bypass proxy for nested wildcard patterns',
env: { HTTP_PROXY: true, NO_PROXY: '*.example.com' },
targetUrl: 'http://api.example.com:8080/data',
expectProxied: false,
},
{
name: 'should proxy when wildcard does not match',
env: { HTTP_PROXY: true, NO_PROXY: '*.example.com' },
targetUrl: 'http://test.local:8080/api',
expectProxied: true,
},
{
name: 'should handle multiple NO_PROXY patterns - match first',
env: { HTTP_PROXY: true, NO_PROXY: 'localhost,*.local,example.com' },
targetUrl: 'http://localhost:8080/test',
expectProxied: false,
},
{
name: 'should handle multiple NO_PROXY patterns - match middle',
env: { HTTP_PROXY: true, NO_PROXY: 'localhost,*.local,example.com' },
targetUrl: 'http://app.local:8080/api',
expectProxied: false,
},
{
name: 'should handle multiple NO_PROXY patterns - match last',
env: { HTTP_PROXY: true, NO_PROXY: 'localhost,*.local,example.com' },
targetUrl: 'http://example.com:8080/data',
expectProxied: false,
},
{
name: 'should proxy when none of multiple patterns match',
env: { HTTP_PROXY: true, NO_PROXY: 'localhost,*.example.com,test.org' },
targetUrl: 'http://app.local:8080/api',
expectProxied: true,
},
{
name: 'should respect NO_PROXY with ALL_PROXY',
env: { ALL_PROXY: true, NO_PROXY: '*.example.com' },
targetUrl: 'http://api.example.com:8080/test',
expectProxied: false,
},
{
name: 'should proxy when target not in NO_PROXY list',
env: { HTTP_PROXY: true, NO_PROXY: 'localhost,*.internal' },
targetUrl: 'http://api.example.com:8080/test',
expectProxied: true,
},
])('$name', async ({ env, targetUrl, expectProxied }) => {
if (env.HTTP_PROXY) process.env.HTTP_PROXY = proxyServer.url;
if (env.HTTPS_PROXY) process.env.HTTPS_PROXY = proxyServer.url;
if (env.ALL_PROXY === true) process.env.ALL_PROXY = proxyServer.url;
if (env.ALL_PROXY && env.ALL_PROXY !== true) process.env.ALL_PROXY = env.ALL_PROXY;
if (env.NO_PROXY) process.env.NO_PROXY = env.NO_PROXY;
installGlobalProxyAgent();
let scope: nock.Scope | undefined;
if (!expectProxied) {
scope = setupDirectRequestMock(targetUrl);
}
const response = await makeRequest(targetUrl);
if (expectProxied) {
expectProxiedResponse(response);
} else {
expectDirectResponse(response, scope);
}
});
function setupDirectRequestMock(targetUrl: string) {
if (!nock.isActive()) nock.activate();
const url = new URL(targetUrl);
return nock(`${url.protocol}//${url.host}`)
.get(url.pathname)
.reply(200, { message: 'direct', timestamp: Date.now() });
}
function expectProxiedResponse(response: TestResponse) {
expect(response.message).toBe('proxied');
expect(proxyServer.capturedRequests.length).toBeGreaterThan(0);
}
function expectDirectResponse(response: TestResponse, scope?: nock.Scope) {
expect(response.message).toBe('direct');
expect(proxyServer.capturedRequests).toHaveLength(0);
expect(scope?.isDone()).toBe(true);
}
});
@@ -1,8 +1,5 @@
import FormData from 'form-data';
import { Agent as HttpAgent } from 'http';
import { HttpProxyAgent } from 'http-proxy-agent';
import { Agent as HttpsAgent } from 'https';
import { HttpsProxyAgent } from 'https-proxy-agent';
import type { Agent as HttpsAgent } from 'https';
import { mock } from 'jest-mock-extended';
import type {
IHttpRequestMethods,
@@ -22,7 +19,6 @@ import {
applyPaginationRequestData,
convertN8nRequestToAxios,
createFormDataObject,
getAgentWithProxy,
httpRequest,
invokeAxios,
parseRequestObject,
@@ -870,90 +866,4 @@ describe('Request Helper Functions', () => {
scope.done();
});
});
describe('getAgentWithProxy', () => {
const baseUrlHttps = 'https://example.com';
const baseUrlHttp = 'http://example.com';
const proxyUrlHttps = 'http://proxy-for-https.com:8080/';
const proxyUrlHttp = 'http://proxy-for-http.com:8080/';
test('should return a regular HTTP agent when no proxy is set', async () => {
const { agent, protocol } = getAgentWithProxy({
targetUrl: baseUrlHttp,
});
expect(protocol).toEqual('http');
expect(agent).toBeInstanceOf(HttpAgent);
});
test('should return a regular HTTPS agent when no proxy is set', async () => {
const { agent, protocol } = getAgentWithProxy({
targetUrl: baseUrlHttps,
});
expect(protocol).toEqual('https');
expect(agent).toBeInstanceOf(HttpsAgent);
});
test('should use a proxyConfig object', async () => {
const { agent, protocol } = getAgentWithProxy({
targetUrl: baseUrlHttps,
proxyConfig: {
host: 'proxy-for-https.com',
port: 8080,
},
});
expect(protocol).toEqual('https');
expect((agent as HttpsProxyAgent<string>).proxy.href).toEqual(proxyUrlHttps);
});
test('should use a proxyConfig string', async () => {
const { agent, protocol } = getAgentWithProxy({
targetUrl: baseUrlHttps,
proxyConfig: proxyUrlHttps,
});
expect(agent).toBeInstanceOf(HttpsProxyAgent);
expect(protocol).toEqual('https');
expect((agent as HttpsProxyAgent<string>).proxy.href).toEqual(proxyUrlHttps);
});
describe('environment variables', () => {
let originalEnv: NodeJS.ProcessEnv;
beforeAll(() => {
originalEnv = { ...process.env };
process.env.HTTP_PROXY = proxyUrlHttp;
process.env.HTTPS_PROXY = proxyUrlHttps;
process.env.NO_PROXY = 'should-not-proxy.com';
});
afterAll(() => {
process.env = originalEnv;
});
test('should proxy http requests (HTTP_PROXY)', async () => {
const { agent, protocol } = getAgentWithProxy({
targetUrl: baseUrlHttp,
});
expect(protocol).toEqual('http');
expect(agent).toBeInstanceOf(HttpProxyAgent);
expect((agent as HttpsProxyAgent<string>).proxy.href).toEqual(proxyUrlHttp);
});
test('should proxy https requests (HTTPS_PROXY)', async () => {
const { agent, protocol } = getAgentWithProxy({
targetUrl: baseUrlHttps,
});
expect(protocol).toEqual('https');
expect(agent).toBeInstanceOf(HttpsProxyAgent);
expect((agent as HttpsProxyAgent<string>).proxy.href).toEqual(proxyUrlHttps);
});
test('should not proxy some hosts based on NO_PROXY', async () => {
const { agent, protocol } = getAgentWithProxy({
targetUrl: 'https://should-not-proxy.com/foo',
});
expect(protocol).toEqual('https');
expect(agent).toBeInstanceOf(HttpsAgent);
});
});
});
});
@@ -19,10 +19,8 @@ import type { AxiosError, AxiosHeaders, AxiosRequestConfig, AxiosResponse } from
import axios from 'axios';
import crypto, { createHmac } from 'crypto';
import FormData from 'form-data';
import { IncomingMessage, Agent as HttpAgent } from 'http';
import { HttpProxyAgent } from 'http-proxy-agent';
import { type AgentOptions, Agent as HttpsAgent } from 'https';
import { HttpsProxyAgent } from 'https-proxy-agent';
import { IncomingMessage } from 'http';
import { type AgentOptions } from 'https';
import get from 'lodash/get';
import isEmpty from 'lodash/isEmpty';
import merge from 'lodash/merge';
@@ -63,10 +61,10 @@ import type {
} from 'n8n-workflow';
import type { Token } from 'oauth-1.0a';
import clientOAuth1 from 'oauth-1.0a';
import proxyFromEnv from 'proxy-from-env';
import { stringify } from 'qs';
import { Readable } from 'stream';
import { createHttpProxyAgent, createHttpsProxyAgent } from '@/http-proxy';
import type { IResponseError } from '@/interfaces';
import { binaryToString } from './binary-helper-functions';
@@ -89,95 +87,63 @@ axios.defaults.proxy = false;
function validateUrl(url?: string): boolean {
if (!url) return false;
try {
new URL(url);
return true;
} catch (error) {
} catch {
return false;
}
}
function getUrlFromProxyConfig(proxyConfig: IHttpRequestOptions['proxy'] | string): string | null {
if (typeof proxyConfig === 'string') {
if (!validateUrl(proxyConfig)) {
return null;
}
return proxyConfig;
return validateUrl(proxyConfig) ? proxyConfig : null;
}
if (!proxyConfig?.host) {
return null;
}
if (!proxyConfig?.host) return null;
const { protocol, host, port, auth } = proxyConfig;
const safeProtocol = protocol?.endsWith(':') ? protocol.replace(':', '') : (protocol ?? 'http');
const safeProtocol = protocol?.endsWith(':') ? protocol.slice(0, -1) : (protocol ?? 'http');
try {
const url = new URL(`${safeProtocol}://${host}`);
if (port !== undefined) {
url.port = String(port);
}
if (port !== undefined) url.port = String(port);
if (auth?.username) {
url.username = auth.username;
url.password = auth.password ?? '';
}
return url.href;
} catch (error) {
} catch {
return null;
}
}
function getTargetUrlFromAxiosConfig(axiosConfig: AxiosRequestConfig): string {
const { url, baseURL } = axiosConfig;
function buildTargetUrl(url?: string, baseURL?: string): string | undefined {
if (!url) return undefined;
try {
return new URL(url ?? '', baseURL).href;
return baseURL ? new URL(url, baseURL).href : url;
} catch {
return '';
return undefined;
}
}
type AgentInfo = { protocol: 'http' | 'https'; agent: HttpAgent };
export function getAgentWithProxy({
agentOptions,
proxyConfig,
targetUrl,
}: {
agentOptions?: AgentOptions;
proxyConfig?: IHttpRequestOptions['proxy'] | string;
targetUrl: string;
}): AgentInfo {
// If no proxy is set in config, use HTTP_PROXY/HTTPS_PROXY/ALL_PROXY from env depending on target URL
// Also respect NO_PROXY to disable the proxy for certain hosts
const proxyUrl = getUrlFromProxyConfig(proxyConfig) ?? proxyFromEnv.getProxyForUrl(targetUrl);
const protocol = targetUrl.startsWith('https://') ? 'https' : 'http';
if (proxyUrl) {
const ProxyAgent = protocol === 'http' ? HttpProxyAgent : HttpsProxyAgent;
return { protocol, agent: new ProxyAgent(proxyUrl, agentOptions) };
}
const Agent = protocol === 'http' ? HttpAgent : HttpsAgent;
return { protocol, agent: new Agent(agentOptions) };
}
const applyAgentToAxiosConfig = (
function setAxiosAgents(
config: AxiosRequestConfig,
{ agent, protocol }: AgentInfo,
): AxiosRequestConfig => {
if (protocol === 'http') {
config.httpAgent = agent;
} else {
config.httpsAgent = agent;
}
agentOptions?: AgentOptions,
proxyConfig?: IHttpRequestOptions['proxy'] | string,
): void {
if (config.httpAgent || config.httpsAgent) return;
return config;
};
const customProxyUrl = getUrlFromProxyConfig(proxyConfig);
const targetUrl = buildTargetUrl(config.url, config.baseURL);
if (!targetUrl) return;
config.httpAgent = createHttpProxyAgent(customProxyUrl, targetUrl, agentOptions);
config.httpsAgent = createHttpsProxyAgent(customProxyUrl, targetUrl, agentOptions);
}
axios.interceptors.request.use((config) => {
// If no content-type is set by us, prevent axios from force-setting the content-type to `application/x-www-form-urlencoded`
@@ -185,13 +151,7 @@ axios.interceptors.request.use((config) => {
config.headers.setContentType(false, false);
}
if (!config.httpsAgent && !config.httpAgent) {
const agent = getAgentWithProxy({
targetUrl: getTargetUrlFromAxiosConfig(config),
});
applyAgentToAxiosConfig(config, agent);
}
setAxiosAgents(config);
return config;
});
@@ -230,22 +190,21 @@ const getBeforeRedirectFn =
(redirectedRequest: Record<string, any>) => {
const redirectAgentOptions = {
...agentOptions,
servername: redirectedRequest.hostname,
};
const redirectAgent = getAgentWithProxy({
agentOptions: redirectAgentOptions,
proxyConfig,
targetUrl: redirectedRequest.href,
});
const customProxyUrl = getUrlFromProxyConfig(proxyConfig);
redirectedRequest.agent = redirectAgent.agent;
if (redirectAgent.protocol === 'http') {
redirectedRequest.agents.http = redirectAgent.agent;
} else {
redirectedRequest.agents.https = redirectAgent.agent;
}
// Create both agents and set them
const targetUrl = redirectedRequest.href;
const httpAgent = createHttpProxyAgent(customProxyUrl, targetUrl, redirectAgentOptions);
const httpsAgent = createHttpsProxyAgent(customProxyUrl, targetUrl, redirectAgentOptions);
redirectedRequest.agent = redirectedRequest.href.startsWith('https://')
? httpsAgent
: httpAgent;
redirectedRequest.agents = { http: httpAgent, https: httpsAgent };
// Copy auth headers
if (axiosConfig.headers?.Authorization) {
redirectedRequest.headers.Authorization = axiosConfig.headers.Authorization;
}
@@ -613,13 +572,7 @@ export async function parseRequestObject(requestObject: IRequestOptions) {
axiosConfig.timeout = requestObject.timeout;
}
const agent = getAgentWithProxy({
agentOptions,
proxyConfig: requestObject.proxy,
targetUrl: getTargetUrlFromAxiosConfig(axiosConfig),
});
applyAgentToAxiosConfig(axiosConfig, agent);
setAxiosAgents(axiosConfig, agentOptions, requestObject.proxy);
axiosConfig.beforeRedirect = getBeforeRedirectFn(agentOptions, axiosConfig, requestObject.proxy);
@@ -799,12 +752,7 @@ export function convertN8nRequestToAxios(n8nRequest: IHttpRequestOptions): Axios
if (n8nRequest.skipSslCertificateValidation === true) {
agentOptions.rejectUnauthorized = false;
}
const agent = getAgentWithProxy({
agentOptions,
proxyConfig: proxy,
targetUrl: getTargetUrlFromAxiosConfig(axiosRequest),
});
applyAgentToAxiosConfig(axiosRequest, agent);
setAxiosAgents(axiosRequest, agentOptions, proxy);
axiosRequest.beforeRedirect = getBeforeRedirectFn(agentOptions, axiosRequest, n8nRequest.proxy);
+144
View File
@@ -0,0 +1,144 @@
import http from 'http';
import { HttpProxyAgent } from 'http-proxy-agent';
import https from 'https';
import { HttpsProxyAgent } from 'https-proxy-agent';
import { LoggerProxy } from 'n8n-workflow';
import proxyFromEnv from 'proxy-from-env';
type ProxyRequestParameters = Parameters<HttpProxyAgent<string>['addRequest']>;
type ProxyClientRequest = ProxyRequestParameters[0];
type ProxyRequestOptions = ProxyRequestParameters[1];
function buildTargetUrl(hostname: string, port: number, protocol: 'http' | 'https'): string {
const defaultPort = protocol === 'https' ? 443 : 80;
const portSuffix = port === defaultPort ? '' : `:${port}`;
return `${protocol}://${hostname}${portSuffix}`;
}
function extractHostInfo(
options: http.RequestOptions,
defaultPort: number,
): { hostname: string; port: number } {
const hostname = options.hostname ?? options.host ?? 'localhost';
const port =
typeof options.port === 'string' ? parseInt(options.port, 10) : (options.port ?? defaultPort);
return { hostname: String(hostname), port: Number(port) };
}
function getOrCreateProxyAgent<T extends HttpProxyAgent<string> | HttpsProxyAgent<string>>(
cache: Map<string, T>,
proxyUrl: string,
createAgent: (url: string) => T,
): T {
let proxyAgent = cache.get(proxyUrl);
if (!proxyAgent) {
proxyAgent = createAgent(proxyUrl);
cache.set(proxyUrl, proxyAgent);
}
return proxyAgent;
}
function createFallbackAgent<T extends http.Agent | https.Agent>(AgentClass: new () => T): T {
return new AgentClass();
}
/**
* Node.js is working on native HTTP proxy support (as of Node.js 24)
* When it is stable we can use it and remove this implementation
*
* https://nodejs.org/api/http.html#built-in-proxy-support
*/
class HttpProxyManager extends http.Agent {
private readonly proxyAgentCache = new Map<string, HttpProxyAgent<string>>();
private readonly fallbackAgent = createFallbackAgent(http.Agent);
addRequest(req: http.ClientRequest, options: http.RequestOptions) {
const { hostname, port } = extractHostInfo(options, 80);
const targetUrl = buildTargetUrl(hostname, port, 'http');
const proxyUrl = proxyFromEnv.getProxyForUrl(targetUrl);
if (proxyUrl) {
const proxyAgent = getOrCreateProxyAgent(
this.proxyAgentCache,
proxyUrl,
(url) => new HttpProxyAgent(url),
);
return proxyAgent.addRequest(req as ProxyClientRequest, options as ProxyRequestOptions);
}
return this.fallbackAgent.addRequest(req, options);
}
}
class HttpsProxyManager extends https.Agent {
private readonly proxyAgentCache = new Map<string, HttpsProxyAgent<string>>();
private readonly fallbackAgent = createFallbackAgent(https.Agent);
addRequest(req: http.ClientRequest, options: https.RequestOptions) {
const { hostname, port } = extractHostInfo(options, 443);
const targetUrl = buildTargetUrl(hostname, port, 'https');
const proxyUrl = proxyFromEnv.getProxyForUrl(targetUrl);
if (proxyUrl) {
const proxyAgent = getOrCreateProxyAgent(
this.proxyAgentCache,
proxyUrl,
(url) => new HttpsProxyAgent(url),
);
return proxyAgent.addRequest(req, options);
}
return this.fallbackAgent.addRequest(req, options);
}
}
export function createHttpProxyAgent(
customProxyUrl: string | null = null,
targetUrl: string,
options?: http.AgentOptions,
): http.Agent {
const proxyUrl = customProxyUrl ?? proxyFromEnv.getProxyForUrl(targetUrl);
if (proxyUrl) {
return new HttpProxyAgent(proxyUrl, options);
}
return new http.Agent(options);
}
export function createHttpsProxyAgent(
customProxyUrl: string | null = null,
targetUrl: string,
options?: https.AgentOptions,
): https.Agent {
const proxyUrl = customProxyUrl ?? proxyFromEnv.getProxyForUrl(targetUrl);
if (proxyUrl) {
return new HttpsProxyAgent(proxyUrl, options);
}
return new https.Agent(options);
}
function hasProxyEnvironmentVariables(): boolean {
return Boolean(process.env.HTTP_PROXY ?? process.env.HTTPS_PROXY ?? process.env.ALL_PROXY);
}
export function installGlobalProxyAgent(): void {
if (hasProxyEnvironmentVariables()) {
LoggerProxy.debug('Installing global HTTP proxy agents', {
HTTP_PROXY: process.env.HTTP_PROXY,
HTTPS_PROXY: process.env.HTTPS_PROXY,
NO_PROXY: process.env.NO_PROXY,
ALL_PROXY: process.env.ALL_PROXY,
});
http.globalAgent = new HttpProxyManager();
https.globalAgent = new HttpsProxyManager();
}
}
export function uninstallGlobalProxyAgent(): void {
http.globalAgent = new http.Agent();
https.globalAgent = new https.Agent();
}
+14
View File
@@ -0,0 +1,14 @@
import type http from 'http-proxy-agent';
import type https from 'https-proxy-agent';
declare module 'http' {
interface Agent {
addRequest(req: ClientRequest, options: http.HttpProxyAgentOptions): void;
}
}
declare module 'https' {
interface Agent {
addRequest(req: ClientRequest, options: https.HttpsProxyAgentOptions): void;
}
}
+1
View File
@@ -11,6 +11,7 @@ export * from './html-sandbox';
export * from './instance-settings';
export * from './nodes-loader';
export * from './utils';
export * from './http-proxy';
export { WorkflowHasIssuesError } from './errors/workflow-has-issues.error';
export type * from './interfaces';