@@ -15,12 +15,12 @@ const { FormData } = require('./formdata')
1515const { kState } = require ( './symbols' )
1616const { webidl } = require ( './webidl' )
1717const { Blob, File : NativeFile } = require ( 'node:buffer' )
18- const { kBodyUsed } = require ( '../core/symbols' )
1918const assert = require ( 'node:assert' )
2019const { isErrored } = require ( '../core/util' )
21- const { isUint8Array , isArrayBuffer } = require ( 'util/types' )
20+ const { isArrayBuffer } = require ( 'util/types' )
2221const { File : UndiciFile } = require ( './file' )
2322const { serializeAMimeType } = require ( './dataURL' )
23+ const { Readable } = require ( 'node:stream' )
2424
2525/** @type {globalThis['File'] } */
2626const File = NativeFile ?? UndiciFile
@@ -291,29 +291,6 @@ function cloneBody (body) {
291291 }
292292}
293293
294- async function * consumeBody ( body ) {
295- if ( body ) {
296- if ( isUint8Array ( body ) ) {
297- yield body
298- } else {
299- const stream = body . stream
300-
301- if ( util . isDisturbed ( stream ) ) {
302- throw new TypeError ( 'The body has already been consumed.' )
303- }
304-
305- if ( stream . locked ) {
306- throw new TypeError ( 'The stream is locked.' )
307- }
308-
309- // Compat.
310- stream [ kBodyUsed ] = true
311-
312- yield * stream
313- }
314- }
315- }
316-
317294function throwIfAborted ( state ) {
318295 if ( state . aborted ) {
319296 throw new DOMException ( 'The operation was aborted.' , 'AbortError' )
@@ -328,7 +305,7 @@ function bodyMixinMethods (instance) {
328305 // given a byte sequence bytes: return a Blob whose
329306 // contents are bytes and whose type attribute is this’s
330307 // MIME type.
331- return specConsumeBody ( this , ( bytes ) => {
308+ return consumeBody ( this , ( bytes ) => {
332309 let mimeType = bodyMimeType ( this )
333310
334311 if ( mimeType === null ) {
@@ -348,21 +325,21 @@ function bodyMixinMethods (instance) {
348325 // of running consume body with this and the following step
349326 // given a byte sequence bytes: return a new ArrayBuffer
350327 // whose contents are bytes.
351- return specConsumeBody ( this , ( bytes ) => {
328+ return consumeBody ( this , ( bytes ) => {
352329 return new Uint8Array ( bytes ) . buffer
353330 } , instance )
354331 } ,
355332
356333 text ( ) {
357334 // The text() method steps are to return the result of running
358335 // consume body with this and UTF-8 decode.
359- return specConsumeBody ( this , utf8DecodeBytes , instance )
336+ return consumeBody ( this , utf8DecodeBytes , instance )
360337 } ,
361338
362339 json ( ) {
363340 // The json() method steps are to return the result of running
364341 // consume body with this and parse JSON from bytes.
365- return specConsumeBody ( this , parseJSONFromBytes , instance )
342+ return consumeBody ( this , parseJSONFromBytes , instance )
366343 } ,
367344
368345 async formData ( ) {
@@ -375,16 +352,15 @@ function bodyMixinMethods (instance) {
375352
376353 // If mimeType’s essence is "multipart/form-data", then:
377354 if ( mimeType !== null && mimeType . essence === 'multipart/form-data' ) {
378- const headers = { }
379- for ( const [ key , value ] of this . headers ) headers [ key ] = value
380-
381355 const responseFormData = new FormData ( )
382356
383357 let busboy
384358
385359 try {
386360 busboy = new Busboy ( {
387- headers,
361+ headers : {
362+ 'content-type' : serializeAMimeType ( mimeType )
363+ } ,
388364 preservePath : true
389365 } )
390366 } catch ( err ) {
@@ -427,8 +403,10 @@ function bodyMixinMethods (instance) {
427403 busboy . on ( 'error' , ( err ) => reject ( new TypeError ( err ) ) )
428404 } )
429405
430- if ( this . body !== null ) for await ( const chunk of consumeBody ( this [ kState ] . body ) ) busboy . write ( chunk )
431- busboy . end ( )
406+ if ( this . body !== null ) {
407+ Readable . from ( this [ kState ] . body . stream ) . pipe ( busboy )
408+ }
409+
432410 await busboyResolve
433411
434412 return responseFormData
@@ -442,20 +420,17 @@ function bodyMixinMethods (instance) {
442420 // application/x-www-form-urlencoded parser will keep the BOM.
443421 // https://url.spec.whatwg.org/#concept-urlencoded-parser
444422 // Note that streaming decoder is stateful and cannot be reused
445- const streamingDecoder = new TextDecoder ( 'utf-8' , { ignoreBOM : true } )
423+ const stream = this [ kState ] . body . stream . pipeThrough ( new TextDecoderStream ( 'utf-8' , { ignoreBOM : true } ) )
446424
447- for await ( const chunk of consumeBody ( this [ kState ] . body ) ) {
448- if ( ! isUint8Array ( chunk ) ) {
449- throw new TypeError ( 'Expected Uint8Array chunk' )
450- }
451- text += streamingDecoder . decode ( chunk , { stream : true } )
425+ for await ( const chunk of stream ) {
426+ text += chunk
452427 }
453- text += streamingDecoder . decode ( )
428+
454429 entries = new URLSearchParams ( text )
455430 } catch ( err ) {
456431 // istanbul ignore next: Unclear when new URLSearchParams can fail on a string.
457432 // 2. If entries is failure, then throw a TypeError.
458- throw new TypeError ( undefined , { cause : err } )
433+ throw new TypeError ( err )
459434 }
460435
461436 // 3. Return a new FormData object whose entries are entries.
@@ -493,7 +468,7 @@ function mixinBody (prototype) {
493468 * @param {(value: unknown) => unknown } convertBytesToJSValue
494469 * @param {Response|Request } instance
495470 */
496- async function specConsumeBody ( object , convertBytesToJSValue , instance ) {
471+ async function consumeBody ( object , convertBytesToJSValue , instance ) {
497472 webidl . brandCheck ( object , instance )
498473
499474 throwIfAborted ( object [ kState ] )
0 commit comments