Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: fix EnvHttpProxyAgent for the Node.js bundle #4064

Merged
merged 2 commits into from
Feb 26, 2025
Merged
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
3 changes: 3 additions & 0 deletions index-fetch.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
75 changes: 75 additions & 0 deletions test/env-http-proxy-agent-nodejs-bundle.js
Original file line number Diff line number Diff line change
@@ -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')
})
})
Loading