(
req: IncomingMessage,
res: ServerResponse,
targetUrl: string
)
| 292 | } |
| 293 | |
| 294 | async function proxyHttp( |
| 295 | req: IncomingMessage, |
| 296 | res: ServerResponse, |
| 297 | targetUrl: string |
| 298 | ): Promise<void> { |
| 299 | const method = (req.method || 'GET').toUpperCase() |
| 300 | const body = |
| 301 | method === 'GET' || method === 'HEAD' ? undefined : await readBody(req, 20 * 1024 * 1024) |
| 302 | |
| 303 | // Drop hop-by-hop headers; keep the rest. |
| 304 | const headers: Record<string, string> = {} |
| 305 | for (const [k, v] of Object.entries(req.headers)) { |
| 306 | if (!v) continue |
| 307 | const key = k.toLowerCase() |
| 308 | if ( |
| 309 | key === 'host' || |
| 310 | key === 'connection' || |
| 311 | key === 'upgrade' || |
| 312 | key === 'proxy-connection' || |
| 313 | key === 'keep-alive' || |
| 314 | key === 'transfer-encoding' || |
| 315 | key === 'content-length' || |
| 316 | key === 'te' || |
| 317 | key === 'trailer' |
| 318 | ) { |
| 319 | continue |
| 320 | } |
| 321 | if (Array.isArray(v)) headers[k] = v.join(', ') |
| 322 | else headers[k] = String(v) |
| 323 | } |
| 324 | |
| 325 | const upstream = await fetch(targetUrl, { |
| 326 | method, |
| 327 | headers, |
| 328 | body, |
| 329 | redirect: 'manual', |
| 330 | }) |
| 331 | |
| 332 | res.statusCode = upstream.status |
| 333 | upstream.headers.forEach((value, key) => { |
| 334 | const lk = key.toLowerCase() |
| 335 | if (lk === 'transfer-encoding') return |
| 336 | res.setHeader(key, value) |
| 337 | }) |
| 338 | |
| 339 | if (!upstream.body) { |
| 340 | res.end() |
| 341 | return |
| 342 | } |
| 343 | |
| 344 | const nodeStream = Readable.fromWeb(upstream.body as any) |
| 345 | await new Promise<void>((resolve) => { |
| 346 | nodeStream.on('error', () => resolve()) |
| 347 | res.on('close', () => resolve()) |
| 348 | nodeStream.pipe(res) |
| 349 | nodeStream.on('end', () => resolve()) |
| 350 | }) |
| 351 | } |
no test coverage detected