@@ -99,7 +99,7 @@ function extractBody (object, keepalive = false) {
99
99
// Set source to a copy of the bytes held by object.
100
100
source = new Uint8Array ( object . buffer . slice ( object . byteOffset , object . byteOffset + object . byteLength ) )
101
101
} else if ( util . isFormDataLike ( object ) ) {
102
- const boundary = ' ----formdata-undici-' + Math . random ( )
102
+ const boundary = ` ----formdata-undici-${ Math . random ( ) } ` . replace ( '.' , '' ) . slice ( 0 , 32 )
103
103
const prefix = `--${ boundary } \r\nContent-Disposition: form-data`
104
104
105
105
/*! formdata-polyfill. MIT License. Jimmy Wärting <https://jimmy.warting.se/opensource> */
@@ -109,68 +109,49 @@ function extractBody (object, keepalive = false) {
109
109
110
110
// Set action to this step: run the multipart/form-data
111
111
// encoding algorithm, with object’s entry list and UTF-8.
112
- action = async function * ( object ) {
113
- const enc = new TextEncoder ( )
114
-
115
- for ( const [ name , value ] of object ) {
116
- if ( typeof value === 'string' ) {
117
- yield enc . encode (
118
- prefix +
119
- `; name="${ escape ( normalizeLinefeeds ( name ) ) } "` +
120
- `\r\n\r\n${ normalizeLinefeeds ( value ) } \r\n`
121
- )
122
- } else {
123
- yield enc . encode (
124
- prefix +
125
- `; name="${ escape ( normalizeLinefeeds ( name ) ) } "` +
126
- ( value . name ? `; filename="${ escape ( value . name ) } "` : '' ) +
127
- '\r\n' +
128
- `Content-Type: ${
129
- value . type || 'application/octet-stream'
130
- } \r\n\r\n`
131
- )
132
-
133
- yield * value . stream ( )
134
-
135
- // '\r\n' encoded
136
- yield new Uint8Array ( [ 13 , 10 ] )
137
- }
112
+ // - This ensures that the body is immutable and can't be changed afterwords
113
+ // - That the content-length is calculated in advance.
114
+ // - And that all parts are pre-encoded and ready to be sent.
115
+
116
+ const enc = new TextEncoder ( )
117
+ const blobParts = [ ]
118
+ const rn = new Uint8Array ( [ 13 , 10 ] ) // '\r\n'
119
+ length = 0
120
+
121
+ for ( const [ name , value ] of object ) {
122
+ if ( typeof value === 'string' ) {
123
+ const chunk = enc . encode ( prefix +
124
+ `; name="${ escape ( normalizeLinefeeds ( name ) ) } "` +
125
+ `\r\n\r\n${ normalizeLinefeeds ( value ) } \r\n` )
126
+ blobParts . push ( chunk )
127
+ length += chunk . byteLength
128
+ } else {
129
+ const chunk = enc . encode ( `${ prefix } ; name="${ escape ( normalizeLinefeeds ( name ) ) } "` +
130
+ ( value . name ? `; filename="${ escape ( value . name ) } "` : '' ) + '\r\n' +
131
+ `Content-Type: ${
132
+ value . type || 'application/octet-stream'
133
+ } \r\n\r\n`)
134
+ blobParts . push ( chunk , value , rn )
135
+ length += chunk . byteLength + value . size + rn . byteLength
138
136
}
139
-
140
- yield enc . encode ( `--${ boundary } --` )
141
137
}
142
138
139
+ const chunk = enc . encode ( `--${ boundary } --` )
140
+ blobParts . push ( chunk )
141
+ length += chunk . byteLength
142
+
143
143
// Set source to object.
144
144
source = object
145
145
146
- // Set length to unclear, see html/6424 for improving this.
147
- length = ( ( ) => {
148
- const prefixLength = prefix . length
149
- const boundaryLength = boundary . length
150
- let bodyLength = 0
151
-
152
- for ( const [ name , value ] of object ) {
153
- if ( typeof value === 'string' ) {
154
- bodyLength +=
155
- prefixLength +
156
- Buffer . byteLength ( `; name="${ escape ( normalizeLinefeeds ( name ) ) } "\r\n\r\n${ normalizeLinefeeds ( value ) } \r\n` )
146
+ action = async function * ( ) {
147
+ for ( const part of blobParts ) {
148
+ if ( part . stream ) {
149
+ yield * part . stream ( )
157
150
} else {
158
- bodyLength +=
159
- prefixLength +
160
- Buffer . byteLength ( `; name="${ escape ( normalizeLinefeeds ( name ) ) } "` + ( value . name ? `; filename="${ escape ( value . name ) } "` : '' ) ) +
161
- 2 + // \r\n
162
- `Content-Type: ${
163
- value . type || 'application/octet-stream'
164
- } \r\n\r\n`. length
165
-
166
- // value is a Blob or File, and \r\n
167
- bodyLength += value . size + 2
151
+ yield part
168
152
}
169
153
}
170
-
171
- bodyLength += boundaryLength + 4 // --boundary--
172
- return bodyLength
173
- } ) ( )
154
+ }
174
155
175
156
// Set type to `multipart/form-data; boundary=`,
176
157
// followed by the multipart/form-data boundary string generated
0 commit comments