Skip to content

Commit

Permalink
fix: fix EnvHttpProxyAgent for the Node.js bundle (#4064)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
joyeecheung authored Feb 26, 2025
1 parent 782f06b commit a217002
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 0 deletions.
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')
})
})

0 comments on commit a217002

Please sign in to comment.