| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent b935c91 commit a516f87
2 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -17,7 +17,7 @@ const debug = debuglog('undici:socks5-proxy') | |||
| 17 | 17 | const kProxyUrl = Symbol('proxy url') | |
| 18 | 18 | const kProxyHeaders = Symbol('proxy headers') | |
| 19 | 19 | const kProxyAuth = Symbol('proxy auth') | |
| 20 | - const kPool = Symbol('pool') | ||
| 20 | + const kPools = Symbol('pools') | ||
| 21 | 21 | const kConnector = Symbol('connector') | |
| 22 | 22 | ||
| 23 | 23 | // Static flag to ensure warning is only emitted once per process | |
@@ -65,8 +65,8 @@ class Socks5ProxyAgent extends DispatcherBase { | |||
| 65 | 65 | servername: options.proxyTls?.servername || url.hostname | |
| 66 | 66 | }) | |
| 67 | 67 | ||
| 68 | - // Pool for the actual HTTP connections (with SOCKS5 tunnel connect function) | ||
| 69 | - this[kPool] = null | ||
| 68 | + // Pools for the actual HTTP connections (with SOCKS5 tunnel connect function), keyed by origin | ||
| 69 | + this[kPools] = new Map() | ||
| 70 | 70 | } | |
| 71 | 71 | ||
| 72 | 72 | /** | |
@@ -183,9 +183,11 @@ class Socks5ProxyAgent extends DispatcherBase { | |||
| 183 | 183 | debug('dispatching request to', origin, 'via SOCKS5') | |
| 184 | 184 | ||
| 185 | 185 | try { | |
| 186 | - // Create Pool with custom connect function if we don't have one yet | ||
| 187 | - if (!this[kPool] || this[kPool].destroyed || this[kPool].closed) { | ||
| 188 | - this[kPool] = new Pool(origin, { | ||
| 186 | + const originKey = String(origin) | ||
| 187 | + let pool = this[kPools].get(originKey) | ||
| 188 | + // Create a Pool per origin so requests are not routed to the wrong host | ||
| 189 | + if (!pool || pool.destroyed || pool.closed) { | ||
| 190 | + pool = new Pool(origin, { | ||
| 189 | 191 | pipelining: opts.pipelining, | |
| 190 | 192 | connections: opts.connections, | |
| 191 | 193 | connect: async (connectOpts, callback) => { | |
@@ -225,10 +227,11 @@ class Socks5ProxyAgent extends DispatcherBase { | |||
| 225 | 227 | } | |
| 226 | 228 | } | |
| 227 | 229 | }) | |
| 230 | + this[kPools].set(originKey, pool) | ||
| 228 | 231 | } | |
| 229 | 232 | ||
| 230 | - // Dispatch the request through the pool | ||
| 231 | - return this[kPool][kDispatch](opts, handler) | ||
| 233 | + // Dispatch the request through the per-origin pool | ||
| 234 | + return pool[kDispatch](opts, handler) | ||
| 232 | 235 | } catch (err) { | |
| 233 | 236 | debug('dispatch error:', err) | |
| 234 | 237 | if (typeof handler.onError === 'function') { | |
@@ -240,15 +243,21 @@ class Socks5ProxyAgent extends DispatcherBase { | |||
| 240 | 243 | } | |
| 241 | 244 | ||
| 242 | 245 | async [kClose] () { | |
| 243 | - if (this[kPool]) { | ||
| 244 | - await this[kPool].close() | ||
| 246 | + const closePromises = [] | ||
| 247 | + for (const pool of this[kPools].values()) { | ||
| 248 | + closePromises.push(pool.close()) | ||
| 245 | 249 | } | |
| 250 | + this[kPools].clear() | ||
| 251 | + await Promise.all(closePromises) | ||
| 246 | 252 | } | |
| 247 | 253 | ||
| 248 | 254 | async [kDestroy] (err) { | |
| 249 | - if (this[kPool]) { | ||
| 250 | - await this[kPool].destroy(err) | ||
| 255 | + const destroyPromises = [] | ||
| 256 | + for (const pool of this[kPools].values()) { | ||
| 257 | + destroyPromises.push(pool.destroy(err)) | ||
| 251 | 258 | } | |
| 259 | + this[kPools].clear() | ||
| 260 | + await Promise.all(destroyPromises) | ||
| 252 | 261 | } | |
| 253 | 262 | } | |
| 254 | 263 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -225,6 +225,48 @@ test('Socks5ProxyAgent - multiple requests through same proxy', async (t) => { | |||
| 225 | 225 | await p.completed | |
| 226 | 226 | }) | |
| 227 | 227 | ||
| 228 | + test('Socks5ProxyAgent - requests to different origins are routed correctly', async (t) => { | ||
| 229 | + const p = tspl(t, { plan: 4 }) | ||
| 230 | + | ||
| 231 | + // Create two distinct target servers | ||
| 232 | + const serverA = createServer((req, res) => { | ||
| 233 | + res.writeHead(200, { 'content-type': 'application/json' }) | ||
| 234 | + res.end(JSON.stringify({ server: 'A', path: req.url })) | ||
| 235 | + }) | ||
| 236 | + const serverB = createServer((req, res) => { | ||
| 237 | + res.writeHead(200, { 'content-type': 'application/json' }) | ||
| 238 | + res.end(JSON.stringify({ server: 'B', path: req.url })) | ||
| 239 | + }) | ||
| 240 | + | ||
| 241 | + await new Promise((resolve) => serverA.listen(0, '127.0.0.1', resolve)) | ||
| 242 | + await new Promise((resolve) => serverB.listen(0, '127.0.0.1', resolve)) | ||
| 243 | + const portA = serverA.address().port | ||
| 244 | + const portB = serverB.address().port | ||
| 245 | + | ||
| 246 | + const socksServer = new TestSocks5Server() | ||
| 247 | + const socksAddress = await socksServer.listen() | ||
| 248 | + | ||
| 249 | + try { | ||
| 250 | + const proxyWrapper = new Socks5ProxyAgent(`socks5://127.0.0.1:${socksAddress.port}`) | ||
| 251 | + | ||
| 252 | + // First request goes to server A — establishes a pool | ||
| 253 | + const respA = await request(`http://127.0.0.1:${portA}/a`, { dispatcher: proxyWrapper }) | ||
| 254 | + p.equal(respA.statusCode, 200) | ||
| 255 | + p.deepEqual(await respA.body.json(), { server: 'A', path: '/a' }) | ||
| 256 | + | ||
| 257 | + // Second request goes to server B — must NOT reuse the pool from origin A | ||
| 258 | + const respB = await request(`http://127.0.0.1:${portB}/b`, { dispatcher: proxyWrapper }) | ||
| 259 | + p.equal(respB.statusCode, 200) | ||
| 260 | + p.deepEqual(await respB.body.json(), { server: 'B', path: '/b' }, 'request to origin B must reach server B, not server A') | ||
| 261 | + } finally { | ||
| 262 | + await socksServer.close() | ||
| 263 | + serverA.close() | ||
| 264 | + serverB.close() | ||
| 265 | + } | ||
| 266 | + | ||
| 267 | + await p.completed | ||
| 268 | + }) | ||
| 269 | + | ||
| 228 | 270 | test('Socks5ProxyAgent - connection failure', async (t) => { | |
| 229 | 271 | const p = tspl(t, { plan: 1 }) | |
| 230 | 272 | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments