Skip to content

Commit

Permalink
fix: skip set content-length when FormData value is stream (nodejs#2091)
Browse files Browse the repository at this point in the history
  • Loading branch information
fengmk2 authored and yume-chan committed May 2, 2023
1 parent 19eedaf commit 0a58f13
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 1 deletion.
10 changes: 9 additions & 1 deletion lib/fetch/body.js
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ function extractBody (object, keepalive = false) {
const blobParts = []
const rn = new Uint8Array([13, 10]) // '\r\n'
length = 0
let hasUnknownSizeValue = false

for (const [name, value] of object) {
if (typeof value === 'string') {
Expand All @@ -138,13 +139,20 @@ function extractBody (object, keepalive = false) {
value.type || 'application/octet-stream'
}\r\n\r\n`)
blobParts.push(chunk, value, rn)
length += chunk.byteLength + value.size + rn.byteLength
if (typeof value.size === 'number') {
length += chunk.byteLength + value.size + rn.byteLength
} else {
hasUnknownSizeValue = true
}
}
}

const chunk = enc.encode(`--${boundary}--`)
blobParts.push(chunk)
length += chunk.byteLength
if (hasUnknownSizeValue) {
length = null
}

// Set source to object.
source = object
Expand Down
41 changes: 41 additions & 0 deletions test/issue-2065.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ const { test, skip } = require('tap')
const { nodeMajor, nodeMinor } = require('../lib/core/util')
const { createServer } = require('http')
const { once } = require('events')
const { createReadStream } = require('fs')
const { File, FormData, request } = require('..')

if (nodeMajor < 16 || (nodeMajor === 16 && nodeMinor < 8)) {
Expand All @@ -28,3 +29,43 @@ test('undici.request with a FormData body should set content-length header', asy
body
})
})

test('undici.request with a FormData stream value should set transfer-encoding header', async (t) => {
const server = createServer((req, res) => {
t.equal(req.headers['transfer-encoding'], 'chunked')
res.end()
}).listen(0)

t.teardown(server.close.bind(server))
await once(server, 'listening')

class BlobFromStream {
#stream
#type
constructor (stream, type) {
this.#stream = stream
this.#type = type
}

stream () {
return this.#stream
}

get type () {
return this.#type
}

get [Symbol.toStringTag] () {
return 'Blob'
}
}

const body = new FormData()
const fileReadable = createReadStream(__filename)
body.set('file', new BlobFromStream(fileReadable, '.js'), 'streamfile')

await request(`http://localhost:${server.address().port}`, {
method: 'POST',
body
})
})

0 comments on commit 0a58f13

Please sign in to comment.