From a217002369c403f5a84a870520294435632ef6eb Mon Sep 17 00:00:00 2001 From: Joyee Cheung Date: Wed, 26 Feb 2025 23:00:49 +0800 Subject: [PATCH] fix: fix EnvHttpProxyAgent for the Node.js bundle (#4064) * fix: fix EnvHttpProxyAgent for the Node.js bundle The Dispatcher needs some methods from lib/api for EnvHttpProxyAgent, otherwise it's incomplete. * fixup! fix: fix EnvHttpProxyAgent for the Node.js bundle --- index-fetch.js | 3 + test/env-http-proxy-agent-nodejs-bundle.js | 75 ++++++++++++++++++++++ 2 files changed, 78 insertions(+) create mode 100644 test/env-http-proxy-agent-nodejs-bundle.js diff --git a/index-fetch.js b/index-fetch.js index 01df32d2fb4..711d7e8a1e4 100644 --- a/index-fetch.js +++ b/index-fetch.js @@ -26,6 +26,9 @@ module.exports.createFastMessageEvent = createFastMessageEvent module.exports.EventSource = require('./lib/web/eventsource/eventsource').EventSource +const api = require('./lib/api') +const Dispatcher = require('./lib/dispatcher/dispatcher') +Object.assign(Dispatcher.prototype, api) // Expose the fetch implementation to be enabled in Node.js core via a flag module.exports.EnvHttpProxyAgent = EnvHttpProxyAgent module.exports.getGlobalDispatcher = getGlobalDispatcher diff --git a/test/env-http-proxy-agent-nodejs-bundle.js b/test/env-http-proxy-agent-nodejs-bundle.js new file mode 100644 index 00000000000..43746a318a5 --- /dev/null +++ b/test/env-http-proxy-agent-nodejs-bundle.js @@ -0,0 +1,75 @@ +'use strict' + +const { tspl } = require('@matteo.collina/tspl') +const { describe, test, after, before } = require('node:test') +const { EnvHttpProxyAgent, setGlobalDispatcher } = require('../index-fetch') +const http = require('node:http') +const net = require('node:net') +const { once } = require('node:events') + +const env = { ...process.env } + +describe('EnvHttpProxyAgent and setGlobalDispatcher', () => { + before(() => { + ['HTTP_PROXY', 'http_proxy', 'HTTPS_PROXY', 'https_proxy', 'NO_PROXY', 'no_proxy'].forEach((varname) => { + delete process.env[varname] + }) + }) + + after(() => { + process.env = { ...env } + }) + + test('should work together from the Node.js bundle', async (t) => { + const { strictEqual } = tspl(t, { plan: 3 }) + + // Instead of using mocks, start a real server and a minimal proxy server + // in order to exercise the actual paths in EnvHttpProxyAgent from the + // Node.js bundle. + const server = http.createServer((req, res) => { res.end('Hello world') }) + server.on('error', err => { console.log('Server error', err) }) + server.listen(0) + await once(server, 'listening') + t.after(() => { server.close() }) + + const proxy = http.createServer() + proxy.on('connect', (req, clientSocket, head) => { + // Check that the proxy is actually used to tunnel the request sent below. + const [hostname, port] = req.url.split(':') + strictEqual(hostname, 'localhost') + strictEqual(port, server.address().port.toString()) + + const serverSocket = net.connect(port, hostname, () => { + clientSocket.write( + 'HTTP/1.1 200 Connection Established\r\n' + + 'Proxy-agent: Node.js-Proxy\r\n' + + '\r\n' + ) + serverSocket.write(head) + clientSocket.pipe(serverSocket) + serverSocket.pipe(clientSocket) + }) + + serverSocket.on('error', () => { + clientSocket.write('HTTP/1.1 500 Connection Error\r\n\r\n') + clientSocket.end() + }) + }) + + proxy.on('error', (err) => { console.log('Proxy error', err) }) + + proxy.listen(0) + await once(proxy, 'listening') + t.after(() => { proxy.close() }) + + // Use setGlobalDispatcher and EnvHttpProxyAgent from Node.js + // and make sure that they work together. + const proxyAddress = `http://localhost:${proxy.address().port}` + const serverAddress = `http://localhost:${server.address().port}` + process.env.http_proxy = proxyAddress + setGlobalDispatcher(new EnvHttpProxyAgent()) + + const res = await fetch(serverAddress) + strictEqual(await res.text(), 'Hello world') + }) +})