| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 660d573 commit bedaaa1
7 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -3629,6 +3629,21 @@ If `value` equals `'0'`, certificate validation is disabled for TLS connections. | |||
| 3629 | 3629 | This makes TLS, and HTTPS by extension, insecure. The use of this environment | |
| 3630 | 3630 | variable is strongly discouraged. | |
| 3631 | 3631 | ||
| 3632 | + ### `NODE_USE_ENV_PROXY=1` | ||
| 3633 | + | ||
| 3634 | + <!-- YAML | ||
| 3635 | + added: REPLACEME | ||
| 3636 | + --> | ||
| 3637 | + | ||
| 3638 | + > Stability: 1.1 - Active Development | ||
| 3639 | + | ||
| 3640 | + When enabled, Node.js parses the `HTTP_PROXY`, `HTTPS_PROXY` and `NO_PROXY` | ||
| 3641 | + environment variables during startup, and tunnels requests over the | ||
| 3642 | + specified proxy. | ||
| 3643 | + | ||
| 3644 | + This currently only affects requests sent over `fetch()`. Support for other | ||
| 3645 | + built-in `http` and `https` methods is under way. | ||
| 3646 | + | ||
| 3632 | 3647 | ### `NODE_USE_SYSTEM_CA=1` | |
| 3633 | 3648 | ||
| 3634 | 3649 | <!-- YAML | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -842,6 +842,19 @@ When set to | |||
| 842 | 842 | .Ar 0 , | |
| 843 | 843 | TLS certificate validation is disabled. | |
| 844 | 844 | . | |
| 845 | + .It Ev NODE_USE_ENV_PROXY | ||
| 846 | + When enabled, Node.js parses the | ||
| 847 | + .Ar HTTP_PROXY | ||
| 848 | + , | ||
| 849 | + .Ar HTTPS_PROXY | ||
| 850 | + and | ||
| 851 | + .Ar NO_PROXY | ||
| 852 | + environment variables during startup, and tunnels requests over the specified proxy. | ||
| 853 | + .Pp | ||
| 854 | + This currently only affects requests sent over | ||
| 855 | + .Ar fetch() . | ||
| 856 | + Support for other built-in http and https methods is under way. | ||
| 857 | + . | ||
| 845 | 858 | .It Ev NODE_USE_SYSTEM_CA | |
| 846 | 859 | Similar to | |
| 847 | 860 | .Fl -use-system-ca . | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -127,6 +127,7 @@ function prepareExecution(options) { | |||
| 127 | 127 | initializeConfigFileSupport(); | |
| 128 | 128 | ||
| 129 | 129 | require('internal/dns/utils').initializeDns(); | |
| 130 | + setupHttpProxy(); | ||
| 130 | 131 | ||
| 131 | 132 | setupSymbolDisposePolyfill(); | |
| 132 | 133 | ||
@@ -189,6 +190,21 @@ function setupSymbolDisposePolyfill() { | |||
| 189 | 190 | } | |
| 190 | 191 | } | |
| 191 | 192 | ||
| 193 | + function setupHttpProxy() { | ||
| 194 | + if (process.env.NODE_USE_ENV_PROXY && | ||
| 195 | + (process.env.HTTP_PROXY || process.env.HTTPS_PROXY || | ||
| 196 | + process.env.http_proxy || process.env.https_proxy)) { | ||
| 197 | + const { setGlobalDispatcher, EnvHttpProxyAgent } = require('internal/deps/undici/undici'); | ||
| 198 | + const envHttpProxyAgent = new EnvHttpProxyAgent(); | ||
| 199 | + setGlobalDispatcher(envHttpProxyAgent); | ||
| 200 | + // TODO(joyeecheung): This currently only affects fetch. Implement handling in the | ||
| 201 | + // http/https Agent constructor too. | ||
| 202 | + // TODO(joyeecheung): This is currently guarded with NODE_USE_ENV_PROXY. Investigate whether | ||
| 203 | + // it's possible to enable it by default without stepping on other existing libraries that | ||
| 204 | + // sets the global dispatcher or monkey patches the global agent. | ||
| 205 | + } | ||
| 206 | + } | ||
| 207 | + | ||
| 192 | 208 | function setupUserModules(forceDefaultLoader = false) { | |
| 193 | 209 | initializeCJSLoader(); | |
| 194 | 210 | initializeESMLoader(forceDefaultLoader); | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,100 @@ | |||
| 1 | + 'use strict'; | ||
| 2 | + | ||
| 3 | + const net = require('net'); | ||
| 4 | + const http = require('http'); | ||
| 5 | + const assert = require('assert'); | ||
| 6 | + | ||
| 7 | + function logRequest(logs, req) { | ||
| 8 | + logs.push({ | ||
| 9 | + method: req.method, | ||
| 10 | + url: req.url, | ||
| 11 | + headers: { ...req.headers }, | ||
| 12 | + }); | ||
| 13 | + } | ||
| 14 | + | ||
| 15 | + // This creates a minimal proxy server that logs the requests it gets | ||
| 16 | + // to an array before performing proxying. | ||
| 17 | + exports.createProxyServer = function() { | ||
| 18 | + const logs = []; | ||
| 19 | + | ||
| 20 | + const proxy = http.createServer(); | ||
| 21 | + proxy.on('request', (req, res) => { | ||
| 22 | + logRequest(logs, req); | ||
| 23 | + const [hostname, port] = req.headers.host.split(':'); | ||
| 24 | + const targetPort = port || 80; | ||
| 25 | + | ||
| 26 | + const options = { | ||
| 27 | + hostname: hostname, | ||
| 28 | + port: targetPort, | ||
| 29 | + path: req.url, | ||
| 30 | + method: req.method, | ||
| 31 | + headers: req.headers, | ||
| 32 | + }; | ||
| 33 | + | ||
| 34 | + const proxyReq = http.request(options, (proxyRes) => { | ||
| 35 | + res.writeHead(proxyRes.statusCode, proxyRes.headers); | ||
| 36 | + proxyRes.pipe(res, { end: true }); | ||
| 37 | + }); | ||
| 38 | + | ||
| 39 | + proxyReq.on('error', (err) => { | ||
| 40 | + logs.push({ error: err, source: 'proxy request' }); | ||
| 41 | + res.writeHead(500); | ||
| 42 | + res.end('Proxy error: ' + err.message); | ||
| 43 | + }); | ||
| 44 | + | ||
| 45 | + req.pipe(proxyReq, { end: true }); | ||
| 46 | + }); | ||
| 47 | + | ||
| 48 | + proxy.on('connect', (req, res, head) => { | ||
| 49 | + logRequest(logs, req); | ||
| 50 | + | ||
| 51 | + const [hostname, port] = req.url.split(':'); | ||
| 52 | + const proxyReq = net.connect(port, hostname, () => { | ||
| 53 | + res.write( | ||
| 54 | + 'HTTP/1.1 200 Connection Established\r\n' + | ||
| 55 | + 'Proxy-agent: Node.js-Proxy\r\n' + | ||
| 56 | + '\r\n', | ||
| 57 | + ); | ||
| 58 | + proxyReq.write(head); | ||
| 59 | + res.pipe(proxyReq); | ||
| 60 | + proxyReq.pipe(res); | ||
| 61 | + }); | ||
| 62 | + | ||
| 63 | + proxyReq.on('error', (err) => { | ||
| 64 | + logs.push({ error: err, source: 'proxy request' }); | ||
| 65 | + res.write('HTTP/1.1 500 Connection Error\r\n\r\n'); | ||
| 66 | + res.end('Proxy error: ' + err.message); | ||
| 67 | + }); | ||
| 68 | + }); | ||
| 69 | + | ||
| 70 | + proxy.on('error', (err) => { | ||
| 71 | + logs.push({ error: err, source: 'proxy server' }); | ||
| 72 | + }); | ||
| 73 | + | ||
| 74 | + return { proxy, logs }; | ||
| 75 | + }; | ||
| 76 | + | ||
| 77 | + exports.checkProxiedRequest = async function(envExtension, expectation) { | ||
| 78 | + const { spawnPromisified } = require('./'); | ||
| 79 | + const fixtures = require('./fixtures'); | ||
| 80 | + const { code, signal, stdout, stderr } = await spawnPromisified( | ||
| 81 | + process.execPath, | ||
| 82 | + ['--no-warnings', fixtures.path('fetch-and-log.mjs')], { | ||
| 83 | + env: { | ||
| 84 | + ...process.env, | ||
| 85 | + ...envExtension, | ||
| 86 | + }, | ||
| 87 | + }); | ||
| 88 | + | ||
| 89 | + assert.deepStrictEqual({ | ||
| 90 | + stderr: stderr.trim(), | ||
| 91 | + stdout: stdout.trim(), | ||
| 92 | + code, | ||
| 93 | + signal, | ||
| 94 | + }, { | ||
| 95 | + stderr: '', | ||
| 96 | + code: 0, | ||
| 97 | + signal: null, | ||
| 98 | + ...expectation, | ||
| 99 | + }); | ||
| 100 | + }; | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,3 @@ | |||
| 1 | + const response = await fetch(process.env.FETCH_URL); | ||
| 2 | + const body = await response.text(); | ||
| 3 | + console.log(body); | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,61 @@ | |||
| 1 | + 'use strict'; | ||
| 2 | + | ||
| 3 | + const common = require('../common'); | ||
| 4 | + const assert = require('assert'); | ||
| 5 | + const { once } = require('events'); | ||
| 6 | + const http = require('http'); | ||
| 7 | + const { createProxyServer, checkProxiedRequest } = require('../common/proxy-server'); | ||
| 8 | + | ||
| 9 | + (async () => { | ||
| 10 | + // Start a server to process the final request. | ||
| 11 | + const server = http.createServer(common.mustCall((req, res) => { | ||
| 12 | + res.end('Hello world'); | ||
| 13 | + }, 2)); | ||
| 14 | + server.on('error', common.mustNotCall((err) => { console.error('Server error', err); })); | ||
| 15 | + server.listen(0); | ||
| 16 | + await once(server, 'listening'); | ||
| 17 | + | ||
| 18 | + // Start a minimal proxy server. | ||
| 19 | + const { proxy, logs } = createProxyServer(); | ||
| 20 | + proxy.listen(0); | ||
| 21 | + await once(proxy, 'listening'); | ||
| 22 | + | ||
| 23 | + const serverHost = `localhost:${server.address().port}`; | ||
| 24 | + | ||
| 25 | + // FIXME(undici:4083): undici currently always tunnels the request over | ||
| 26 | + // CONNECT, no matter it's HTTP traffic or not, which is different from e.g. | ||
| 27 | + // how curl behaves. | ||
| 28 | + const expectedLogs = [{ | ||
| 29 | + method: 'CONNECT', | ||
| 30 | + url: serverHost, | ||
| 31 | + headers: { | ||
| 32 | + // FIXME(undici:4086): this should be keep-alive. | ||
| 33 | + connection: 'close', | ||
| 34 | + host: serverHost | ||
| 35 | + } | ||
| 36 | + }]; | ||
| 37 | + | ||
| 38 | + // Check upper-cased HTTPS_PROXY environment variable. | ||
| 39 | + await checkProxiedRequest({ | ||
| 40 | + NODE_USE_ENV_PROXY: 1, | ||
| 41 | + FETCH_URL: `http://${serverHost}/test`, | ||
| 42 | + HTTP_PROXY: `http://localhost:${proxy.address().port}`, | ||
| 43 | + }, { | ||
| 44 | + stdout: 'Hello world', | ||
| 45 | + }); | ||
| 46 | + assert.deepStrictEqual(logs, expectedLogs); | ||
| 47 | + | ||
| 48 | + // Check lower-cased https_proxy environment variable. | ||
| 49 | + logs.splice(0, logs.length); | ||
| 50 | + await checkProxiedRequest({ | ||
| 51 | + NODE_USE_ENV_PROXY: 1, | ||
| 52 | + FETCH_URL: `http://${serverHost}/test`, | ||
| 53 | + http_proxy: `http://localhost:${proxy.address().port}`, | ||
| 54 | + }, { | ||
| 55 | + stdout: 'Hello world', | ||
| 56 | + }); | ||
| 57 | + assert.deepStrictEqual(logs, expectedLogs); | ||
| 58 | + | ||
| 59 | + proxy.close(); | ||
| 60 | + server.close(); | ||
| 61 | + })().then(common.mustCall()); | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,67 @@ | |||
| 1 | + 'use strict'; | ||
| 2 | + | ||
| 3 | + const common = require('../common'); | ||
| 4 | + if (!common.hasCrypto) | ||
| 5 | + common.skip('missing crypto'); | ||
| 6 | + | ||
| 7 | + const fixtures = require('../common/fixtures'); | ||
| 8 | + const assert = require('assert'); | ||
| 9 | + const https = require('https'); | ||
| 10 | + const { once } = require('events'); | ||
| 11 | + const { createProxyServer, checkProxiedRequest } = require('../common/proxy-server'); | ||
| 12 | + | ||
| 13 | + (async () => { | ||
| 14 | + // Start a server to process the final request. | ||
| 15 | + const server = https.createServer({ | ||
| 16 | + cert: fixtures.readKey('agent8-cert.pem'), | ||
| 17 | + key: fixtures.readKey('agent8-key.pem'), | ||
| 18 | + }, common.mustCall((req, res) => { | ||
| 19 | + res.end('Hello world'); | ||
| 20 | + }, 2)); | ||
| 21 | + server.on('error', common.mustNotCall((err) => { console.error('Server error', err); })); | ||
| 22 | + server.listen(0); | ||
| 23 | + await once(server, 'listening'); | ||
| 24 | + | ||
| 25 | + // Start a minimal proxy server. | ||
| 26 | + const { proxy, logs } = createProxyServer(); | ||
| 27 | + proxy.listen(0); | ||
| 28 | + await once(proxy, 'listening'); | ||
| 29 | + | ||
| 30 | + const serverHost = `localhost:${server.address().port}`; | ||
| 31 | + | ||
| 32 | + const expectedLogs = [{ | ||
| 33 | + method: 'CONNECT', | ||
| 34 | + url: serverHost, | ||
| 35 | + headers: { | ||
| 36 | + // FIXME(undici:4086): this should be keep-alive. | ||
| 37 | + connection: 'close', | ||
| 38 | + host: serverHost | ||
| 39 | + } | ||
| 40 | + }]; | ||
| 41 | + | ||
| 42 | + // Check upper-cased HTTPS_PROXY environment variable. | ||
| 43 | + await checkProxiedRequest({ | ||
| 44 | + NODE_USE_ENV_PROXY: 1, | ||
| 45 | + FETCH_URL: `https://${serverHost}/test`, | ||
| 46 | + HTTPS_PROXY: `http://localhost:${proxy.address().port}`, | ||
| 47 | + NODE_EXTRA_CA_CERTS: fixtures.path('keys', 'fake-startcom-root-cert.pem'), | ||
| 48 | + }, { | ||
| 49 | + stdout: 'Hello world', | ||
| 50 | + }); | ||
| 51 | + assert.deepStrictEqual(logs, expectedLogs); | ||
| 52 | + | ||
| 53 | + // Check lower-cased https_proxy environment variable. | ||
| 54 | + logs.splice(0, logs.length); | ||
| 55 | + await checkProxiedRequest({ | ||
| 56 | + NODE_USE_ENV_PROXY: 1, | ||
| 57 | + FETCH_URL: `https://${serverHost}/test`, | ||
| 58 | + https_proxy: `http://localhost:${proxy.address().port}`, | ||
| 59 | + NODE_EXTRA_CA_CERTS: fixtures.path('keys', 'fake-startcom-root-cert.pem'), | ||
| 60 | + }, { | ||
| 61 | + stdout: 'Hello world', | ||
| 62 | + }); | ||
| 63 | + assert.deepStrictEqual(logs, expectedLogs); | ||
| 64 | + | ||
| 65 | + proxy.close(); | ||
| 66 | + server.close(); | ||
| 67 | + })().then(common.mustCall()); | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments