Skip to content

Commit 18c0d95

Browse files
committed
http: support http proxy for fetch under NODE_USE_ENV_PROXY
1 parent 52ac448 commit 18c0d95

File tree

4 files changed

+102
-0
lines changed

4 files changed

+102
-0
lines changed

lib/internal/process/pre_execution.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ function prepareExecution(options) {
119119
initializeConfigFileSupport();
120120

121121
require('internal/dns/utils').initializeDns();
122+
setupHttpProxy();
122123

123124
if (isMainThread) {
124125
assert(internalBinding('worker').isMainThread);
@@ -154,6 +155,17 @@ function prepareExecution(options) {
154155
return mainEntry;
155156
}
156157

158+
function setupHttpProxy() {
159+
if (process.env.NODE_USE_ENV_PROXY &&
160+
(process.env.HTTP_PROXY || process.env.HTTPS_PROXY)) {
161+
const { setGlobalDispatcher, EnvHttpProxyAgent } = require('internal/deps/undici/undici');
162+
const envHttpProxyAgent = new EnvHttpProxyAgent();
163+
setGlobalDispatcher(envHttpProxyAgent);
164+
// TODO(joyeecheung): handle http/https global agents and perhaps Agent constructor
165+
// behaviors.
166+
}
167+
}
168+
157169
function setupUserModules(forceDefaultLoader = false) {
158170
initializeCJSLoader();
159171
initializeESMLoader(forceDefaultLoader);

test/fixtures/fetch-and-log.mjs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
const address = process.env.SERVER_ADDRESS;
2+
const response = await fetch(address);
3+
const body = await response.text();
4+
console.log(body);

test/fixtures/proxy-handler.js

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
const net = require('net');
2+
3+
exports.onConnect = function (req, clientSocket, head) {
4+
const [hostname, port] = req.url.split(':');
5+
6+
const serverSocket = net.connect(port, hostname, () => {
7+
clientSocket.write(
8+
'HTTP/1.1 200 Connection Established\r\n' +
9+
'Proxy-agent: Node.js-Proxy\r\n' +
10+
'\r\n'
11+
);
12+
serverSocket.write(head);
13+
clientSocket.pipe(serverSocket);
14+
serverSocket.pipe(clientSocket);
15+
});
16+
17+
serverSocket.on('error', (err) => {
18+
console.error('Error on CONNECT tunnel:', err.message);
19+
clientSocket.write('HTTP/1.1 500 Connection Error\r\n\r\n');
20+
clientSocket.end();
21+
});
22+
};
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
'use strict';
2+
3+
const common = require('../common');
4+
const fixtures = require('../common/fixtures');
5+
const assert = require('assert');
6+
const { spawn } = require('child_process');
7+
const http = require('http');
8+
const { onConnect } = require('../fixtures/proxy-handler');
9+
10+
// Start a server to process the final request.
11+
const server = http.createServer((req, res) => {
12+
res.end('Hello world');
13+
});
14+
server.on('error', (err) => { console.log('Server error', err); });
15+
16+
server.listen(0, common.mustCall(() => {
17+
// Start a proxy server to tunnel the request.
18+
const proxy = http.createServer();
19+
// If the request does not go through the proxy server, common.mustCall fails.
20+
proxy.on('connect', common.mustCall((req, clientSocket, head) => {
21+
console.log('Proxying CONNECT', req.url, req.headers);
22+
assert.strictEqual(req.url, `localhost:${server.address().port}`);
23+
onConnect(req, clientSocket, head);
24+
}));
25+
proxy.on('error', (err) => { console.log('Proxy error', err); });
26+
27+
proxy.listen(0, common.mustCall(() => {
28+
const proxyAddress = `http://localhost:${proxy.address().port}`;
29+
const serverAddress = `http://localhost:${server.address().port}`;
30+
const child = spawn(process.execPath,
31+
[fixtures.path('fetch-and-log.mjs')],
32+
{
33+
env: {
34+
...process.env,
35+
HTTP_PROXY: proxyAddress,
36+
NODE_USE_ENV_PROXY: true,
37+
SERVER_ADDRESS: serverAddress,
38+
},
39+
});
40+
41+
const stderr = [];
42+
const stdout = [];
43+
child.stderr.on('data', (chunk) => {
44+
stderr.push(chunk);
45+
});
46+
child.stdout.on('data', (chunk) => {
47+
stdout.push(chunk);
48+
});
49+
50+
child.on('exit', common.mustCall(function(code, signal) {
51+
proxy.close();
52+
server.close();
53+
54+
console.log('--- stderr ---');
55+
console.log(Buffer.concat(stderr).toString());
56+
console.log('--- stdout ---');
57+
const stdoutStr = Buffer.concat(stdout).toString();
58+
console.log(stdoutStr);
59+
assert.strictEqual(stdoutStr.trim(), 'Hello world');
60+
assert.strictEqual(code, 0);
61+
assert.strictEqual(signal, null);
62+
}));
63+
}));
64+
}));

0 commit comments

Comments
 (0)