Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

simplify formData body parsing #2735

Merged
merged 3 commits into from
Feb 12, 2024
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 11 additions & 35 deletions lib/fetch/body.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@ const { FormData } = require('./formdata')
const { kState } = require('./symbols')
const { webidl } = require('./webidl')
const { Blob, File: NativeFile } = require('node:buffer')
const { kBodyUsed } = require('../core/symbols')
const assert = require('node:assert')
const { isErrored } = require('../core/util')
const { isUint8Array, isArrayBuffer } = require('util/types')
const { isArrayBuffer } = require('util/types')
const { File: UndiciFile } = require('./file')
const { serializeAMimeType } = require('./dataURL')
const { Readable } = require('node:stream')

/** @type {globalThis['File']} */
const File = NativeFile ?? UndiciFile
Expand Down Expand Up @@ -291,29 +291,6 @@ function cloneBody (body) {
}
}

async function * consumeBody (body) {
if (body) {
if (isUint8Array(body)) {
yield body
} else {
const stream = body.stream

if (util.isDisturbed(stream)) {
throw new TypeError('The body has already been consumed.')
}

if (stream.locked) {
throw new TypeError('The stream is locked.')
}

// Compat.
stream[kBodyUsed] = true

yield * stream
}
}
}

function throwIfAborted (state) {
if (state.aborted) {
throw new DOMException('The operation was aborted.', 'AbortError')
Expand Down Expand Up @@ -427,8 +404,10 @@ function bodyMixinMethods (instance) {
busboy.on('error', (err) => reject(new TypeError(err)))
})

if (this.body !== null) for await (const chunk of consumeBody(this[kState].body)) busboy.write(chunk)
busboy.end()
if (this.body !== null) {
Readable.from(this[kState].body.stream).pipe(busboy)
}

await busboyResolve

return responseFormData
Expand All @@ -442,20 +421,17 @@ function bodyMixinMethods (instance) {
// application/x-www-form-urlencoded parser will keep the BOM.
// https://url.spec.whatwg.org/#concept-urlencoded-parser
// Note that streaming decoder is stateful and cannot be reused
const streamingDecoder = new TextDecoder('utf-8', { ignoreBOM: true })
const stream = this[kState].body.stream.pipeThrough(new TextDecoderStream('utf-8', { ignoreBOM: true }))

for await (const chunk of consumeBody(this[kState].body)) {
if (!isUint8Array(chunk)) {
throw new TypeError('Expected Uint8Array chunk')
}
text += streamingDecoder.decode(chunk, { stream: true })
for await (const chunk of stream) {
text += chunk
}
text += streamingDecoder.decode()

entries = new URLSearchParams(text)
} catch (err) {
// istanbul ignore next: Unclear when new URLSearchParams can fail on a string.
// 2. If entries is failure, then throw a TypeError.
throw new TypeError(undefined, { cause: err })
throw new TypeError(err)
}

// 3. Return a new FormData object whose entries are entries.
Expand Down
Loading