Skip to content

Commit e3675bd

Browse files
authored
fix(core): Fix HTTP proxy support in all nodes and other axios requests (#16092)
1 parent cd6e510 commit e3675bd

File tree

6 files changed

+325
-140
lines changed

6 files changed

+325
-140
lines changed

packages/@n8n/nodes-langchain/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@
195195
"form-data": "catalog:",
196196
"generate-schema": "2.6.0",
197197
"html-to-text": "9.0.5",
198-
"https-proxy-agent": "^7.0.6",
198+
"https-proxy-agent": "catalog:",
199199
"jsdom": "23.0.1",
200200
"langchain": "0.3.11",
201201
"lodash": "catalog:",

packages/core/package.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
"@types/jsonwebtoken": "catalog:",
3333
"@types/lodash": "catalog:",
3434
"@types/mime-types": "^2.1.0",
35+
"@types/proxy-from-env": "^1.0.4",
3536
"@types/uuid": "catalog:",
3637
"@types/xml2js": "catalog:"
3738
},
@@ -52,6 +53,8 @@
5253
"fast-glob": "catalog:",
5354
"file-type": "16.5.4",
5455
"form-data": "catalog:",
56+
"http-proxy-agent": "catalog:",
57+
"https-proxy-agent": "catalog:",
5558
"iconv-lite": "catalog:",
5659
"jsonwebtoken": "catalog:",
5760
"lodash": "catalog:",
@@ -63,6 +66,7 @@
6366
"p-cancelable": "2.1.1",
6467
"picocolors": "catalog:",
6568
"pretty-bytes": "5.6.0",
69+
"proxy-from-env": "^1.1.0",
6670
"qs": "6.11.0",
6771
"ssh2": "1.15.0",
6872
"uuid": "catalog:",

packages/core/src/execution-engine/node-execution-context/utils/__tests__/request-helper-functions.test.ts

Lines changed: 90 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import FormData from 'form-data';
2-
import type { Agent } from 'https';
2+
import { HttpProxyAgent } from 'http-proxy-agent';
3+
import { Agent } from 'https';
4+
import { HttpsProxyAgent } from 'https-proxy-agent';
35
import { mock } from 'jest-mock-extended';
46
import type {
57
IHttpRequestMethods,
@@ -19,6 +21,7 @@ import {
1921
applyPaginationRequestData,
2022
convertN8nRequestToAxios,
2123
createFormDataObject,
24+
getAgentWithProxy,
2225
httpRequest,
2326
invokeAxios,
2427
parseRequestObject,
@@ -28,7 +31,7 @@ import {
2831

2932
describe('Request Helper Functions', () => {
3033
describe('proxyRequestToAxios', () => {
31-
const baseUrl = 'http://example.de';
34+
const baseUrl = 'https://example.de';
3235
const workflow = mock<Workflow>();
3336
const hooks = mock<ExecutionLifecycleHooks>();
3437
const additionalData = mock<IWorkflowExecuteAdditionalData>({ hooks });
@@ -66,7 +69,7 @@ describe('Request Helper Functions', () => {
6669
expect(error.options).toMatchObject({
6770
headers: { Accept: '*/*' },
6871
method: 'get',
69-
url: 'http://example.de/test',
72+
url: 'https://example.de/test',
7073
});
7174
expect(error.config).toBeUndefined();
7275
expect(error.message).toEqual('403 - "Forbidden"');
@@ -165,7 +168,7 @@ describe('Request Helper Functions', () => {
165168
});
166169

167170
describe('invokeAxios', () => {
168-
const baseUrl = 'http://example.de';
171+
const baseUrl = 'https://example.de';
169172

170173
beforeEach(() => {
171174
nock.cleanAll();
@@ -346,7 +349,11 @@ describe('Request Helper Functions', () => {
346349
const axiosOptions = await parseRequestObject(requestObject);
347350
expect(axiosOptions.beforeRedirect).toBeDefined;
348351
// eslint-disable-next-line @typescript-eslint/no-explicit-any
349-
const redirectOptions: Record<string, any> = { agents: {}, hostname: 'example.de' };
352+
const redirectOptions: Record<string, any> = {
353+
agents: {},
354+
hostname: 'example.de',
355+
href: requestObject.uri,
356+
};
350357
axiosOptions.beforeRedirect!(redirectOptions, mock());
351358
expect(redirectOptions.agent).toEqual(redirectOptions.agents.https);
352359
expect((redirectOptions.agent as Agent).options).toEqual({
@@ -862,4 +869,82 @@ describe('Request Helper Functions', () => {
862869
scope.done();
863870
});
864871
});
872+
873+
describe('getAgentWithProxy', () => {
874+
const baseUrlHttps = 'https://example.com';
875+
const baseUrlHttp = 'http://example.com';
876+
const proxyUrlHttps = 'http://proxy-for-https.com:8080/';
877+
const proxyUrlHttp = 'http://proxy-for-http.com:8080/';
878+
879+
test('should return a regular agent when no proxy is set', async () => {
880+
const { agent, protocol } = getAgentWithProxy({
881+
targetUrl: baseUrlHttps,
882+
});
883+
expect(protocol).toEqual('https');
884+
expect(agent).toBeInstanceOf(Agent);
885+
});
886+
887+
test('should use a proxyConfig object', async () => {
888+
const { agent, protocol } = getAgentWithProxy({
889+
targetUrl: baseUrlHttps,
890+
proxyConfig: {
891+
host: 'proxy-for-https.com',
892+
port: 8080,
893+
},
894+
});
895+
expect(protocol).toEqual('https');
896+
expect((agent as HttpsProxyAgent<string>).proxy.href).toEqual(proxyUrlHttps);
897+
});
898+
899+
test('should use a proxyConfig string', async () => {
900+
const { agent, protocol } = getAgentWithProxy({
901+
targetUrl: baseUrlHttps,
902+
proxyConfig: proxyUrlHttps,
903+
});
904+
expect(agent).toBeInstanceOf(HttpsProxyAgent);
905+
expect(protocol).toEqual('https');
906+
expect((agent as HttpsProxyAgent<string>).proxy.href).toEqual(proxyUrlHttps);
907+
});
908+
909+
describe('environment variables', () => {
910+
let originalEnv: NodeJS.ProcessEnv;
911+
912+
beforeAll(() => {
913+
originalEnv = { ...process.env };
914+
process.env.HTTP_PROXY = proxyUrlHttp;
915+
process.env.HTTPS_PROXY = proxyUrlHttps;
916+
process.env.NO_PROXY = 'should-not-proxy.com';
917+
});
918+
919+
afterAll(() => {
920+
process.env = originalEnv;
921+
});
922+
923+
test('should proxy http requests (HTTP_PROXY)', async () => {
924+
const { agent, protocol } = getAgentWithProxy({
925+
targetUrl: baseUrlHttp,
926+
});
927+
expect(protocol).toEqual('http');
928+
expect(agent).toBeInstanceOf(HttpProxyAgent);
929+
expect((agent as HttpsProxyAgent<string>).proxy.href).toEqual(proxyUrlHttp);
930+
});
931+
932+
test('should proxy https requests (HTTPS_PROXY)', async () => {
933+
const { agent, protocol } = getAgentWithProxy({
934+
targetUrl: baseUrlHttps,
935+
});
936+
expect(protocol).toEqual('https');
937+
expect(agent).toBeInstanceOf(HttpsProxyAgent);
938+
expect((agent as HttpsProxyAgent<string>).proxy.href).toEqual(proxyUrlHttps);
939+
});
940+
941+
test('should not proxy some hosts based on NO_PROXY', async () => {
942+
const { agent, protocol } = getAgentWithProxy({
943+
targetUrl: 'https://should-not-proxy.com/foo',
944+
});
945+
expect(protocol).toEqual('https');
946+
expect(agent).toBeInstanceOf(Agent);
947+
});
948+
});
949+
});
865950
});

0 commit comments

Comments
 (0)