Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion lib/_http_agent.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ const {
NumberIsFinite,
NumberParseInt,
ObjectKeys,
ObjectPrototypeHasOwnProperty,
ObjectSetPrototypeOf,
ObjectValues,
Symbol,
Expand Down Expand Up @@ -184,7 +185,9 @@ function Agent(options) {
this.options.agentKeepAliveTimeoutBuffer :
1000;

const proxyEnv = this.options.proxyEnv;
const proxyEnv = ObjectPrototypeHasOwnProperty(this.options, 'proxyEnv') ?
this.options.proxyEnv :
(getOptionValue('--use-env-proxy') ? process.env : undefined);
if (typeof proxyEnv === 'object' && proxyEnv !== null) {
this[kProxyConfig] = parseProxyConfigFromEnv(proxyEnv, this.protocol, this.keepAlive);
debug(`new ${this.protocol} agent with proxy config`, this[kProxyConfig]);
Expand Down
75 changes: 75 additions & 0 deletions test/client-proxy/test-use-env-proxy-agent.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// This tests that when Node.js is configured to use the environment proxy
// (via --use-env-proxy or NODE_USE_ENV_PROXY), a custom agent created without
// a `proxyEnv` option falls back to process.env and goes through the proxy,
// while an agent created with an explicit `proxyEnv: null` bypasses it.

import * as common from '../common/index.mjs';
import assert from 'node:assert';
import http from 'node:http';
import { once } from 'events';
import fixtures from '../common/fixtures.js';
import { createProxyServer } from '../common/proxy-server.js';

// Start a minimal proxy server.
const { proxy, logs } = createProxyServer();
proxy.listen(0);
await once(proxy, 'listening');

delete process.env.NODE_USE_ENV_PROXY; // Ensure the environment variable is not set.

// Start a HTTP server to process the final request.
const server = http.createServer(common.mustCall((req, res) => {
res.end('Hello world');
}, 2));
server.on('error', common.mustNotCall((err) => { console.error('Server error', err); }));
server.listen(0);
await once(server, 'listening');

const serverHost = `localhost:${server.address().port}`;
const requestUrl = `http://${serverHost}/test`;
const script = fixtures.path('agent-request-and-log.js');

function runAgentRequest(env, cliArgs = []) {
return common.spawnPromisified(process.execPath, [...cliArgs, script], {
env: {
...process.env,
REQUEST_URL: requestUrl,
HTTP_PROXY: `http://localhost:${proxy.address().port}`,
...env,
},
});
}

// A plain agent without a `proxyEnv` option should use the environment proxy
// when Node.js is started with --use-env-proxy.
{
const { code, signal, stderr, stdout } = await runAgentRequest({}, ['--use-env-proxy']);
assert.strictEqual(stderr.trim(), '');
assert.match(stdout, /Hello world/);
assert.strictEqual(code, 0);
assert.strictEqual(signal, null);
// The request should go through the proxy.
assert.strictEqual(logs.length, 1);
assert.strictEqual(logs[0].method, 'GET');
assert.strictEqual(logs[0].url, requestUrl);
}

// An agent created with an explicit `proxyEnv: null` should bypass the proxy
// even when Node.js is configured to use the environment proxy. The same must
// hold whether the proxy is enabled via NODE_USE_ENV_PROXY or --use-env-proxy.
{
logs.splice(0, logs.length);
const { code, signal, stderr, stdout } = await runAgentRequest({
NODE_USE_ENV_PROXY: '1',
PROXY_ENV_NULL: '1',
});
assert.strictEqual(stderr.trim(), '');
assert.match(stdout, /Hello world/);
assert.strictEqual(code, 0);
assert.strictEqual(signal, null);
// The request should reach the server directly, so the proxy sees nothing.
assert.strictEqual(logs.length, 0);
}

server.close();
proxy.close();
28 changes: 28 additions & 0 deletions test/fixtures/agent-request-and-log.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
'use strict';

// A minimal fixture that issues a single HTTP GET request using a
// user-provided agent. It is used to exercise how an agent picks up the
// environment proxy configuration when Node.js is started with
// --use-env-proxy or NODE_USE_ENV_PROXY.
//
// When PROXY_ENV_NULL is set, the agent is created with an explicit
// `proxyEnv: null`, which should disable proxying even when Node.js is
// configured to use the environment proxy. Otherwise a plain agent is
// created without any `proxyEnv` option, which should fall back to
// process.env when the environment proxy is enabled.

const http = require('http');

const url = process.env.REQUEST_URL;

const agent = process.env.PROXY_ENV_NULL ?
new http.Agent({ proxyEnv: null }) :
new http.Agent();

const req = http.get(url, { agent }, (res) => {
res.pipe(process.stdout);
});

req.on('error', (e) => {
console.error('Request Error', e);
});