-
-
Notifications
You must be signed in to change notification settings - Fork 676
Open
Labels
bugSomething isn't workingSomething isn't working
Description
Bug description
fetch() with Web Streams hangs indefinitely on Windows when reading responses from a file server over named pipes through a proxy. The issue occurs when calling reader.read() on the response body's ReadableStream.
After reading several chunks (typically 4-5 chunks, ~131KB to 2MB of data), reader.read() hangs indefinitely and never resolves. The issue appears to be a deadlock between undici's Web Streams implementation and Windows named pipe buffering.
(It might also be a mistake on my end!)
Reproducible by
Reproduction script
#!/usr/bin/env node
import { createReadStream } from 'node:fs'
import { mkdir, rm, stat, writeFile } from 'node:fs/promises'
import { createServer } from 'node:http'
import { platform } from 'node:os'
import { dirname, join } from 'node:path'
import { fileURLToPath } from 'node:url'
import { Agent, fetch } from 'undici'
const __dirname = dirname(fileURLToPath(import.meta.url))
const TEST_DIR = join(__dirname, '.test')
const TEST_FILE = join(TEST_DIR, 'data.txt')
const isWindows = platform() === 'win32'
const socketPath = isWindows
? `\\\\.\\pipe\\test-${Date.now()}.sock`
: `/tmp/test-${Date.now()}.sock`
const PORT = 3333
// Create ~2MB test file
async function createTestFile() {
await mkdir(TEST_DIR, { recursive: true })
const content = 'x'.repeat(2_000_000) // 2MB
await writeFile(TEST_FILE, content)
console.log(`Created ${content.length} byte test file\n`)
}
// Server that streams a file
const fileServer = createServer(async (req, res) => {
const stats = await stat(TEST_FILE)
res.writeHead(200, {
'Content-Type': 'text/plain',
'Content-Length': stats.size,
})
createReadStream(TEST_FILE).pipe(res)
})
const proxyUndici = createServer(async (req, res) => {
console.log('[Proxy] Received request, fetching from file server via undici...')
const agent = new Agent({ connect: { socketPath } })
const response = await fetch('http://localhost/', { dispatcher: agent })
console.log(`[Proxy] Got response: ${response.status} ${response.statusText}`)
console.log(`[Proxy] Headers:`, Object.fromEntries(response.headers))
res.writeHead(response.status, Object.fromEntries(response.headers))
const reader = response.body.getReader()
let chunks = 0
let totalBytes = 0
console.log('[Proxy] Starting to read body via Web Streams...')
while (true) {
console.log(`[Proxy] Reading chunk ${chunks + 1}...`)
const result = await Promise.race([
reader.read(),
new Promise(resolve => setTimeout(() => resolve({ timeout: true }), 5000)),
])
if (result.timeout) {
console.error(`[Proxy] HUNG at chunk ${chunks + 1} after ${totalBytes} bytes - this is the bug!`)
reader.releaseLock()
break
}
const { done, value } = result
if (done) {
console.log(`[Proxy] Done reading. Total: ${chunks} chunks, ${totalBytes} bytes`)
break
}
chunks++
totalBytes += value.length
console.log(`[Proxy] Chunk ${chunks}: ${value.length} bytes (total: ${totalBytes} bytes)`)
res.write(value)
}
res.end()
console.log('[Proxy] Response ended')
})
// Clean up socket file on Unix
async function cleanupSocket() {
if (!isWindows) {
try {
await rm(socketPath, { force: true })
}
catch {}
}
}
async function main() {
await cleanupSocket()
await createTestFile()
// Start file server on named pipe
await new Promise(resolve => fileServer.listen({ path: socketPath }, resolve))
console.log('File server listening on pipe\n')
console.log('Starting undici proxy...\n')
await new Promise(resolve => proxyUndici.listen(PORT, resolve))
console.log('[Client] Fetching from proxy...')
const res = await fetch(`http://localhost:${PORT}/`)
console.log(`[Client] Got response, reading body...`)
const text = await res.text()
console.log(`[Client] Success: ${text.length} bytes received\n`)
proxyUndici.close()
fileServer.close()
await cleanupSocket()
await rm(TEST_DIR, { recursive: true, force: true })
}
main().catch(console.error)pi0 and mcollinametcoder95
Metadata
Metadata
Assignees
Labels
bugSomething isn't workingSomething isn't working