Skip to content

Commit b6af4e6

Browse files
authored
fix(body mixin): only allow Uint8Array chunks (#1550)
1 parent 6c9e634 commit b6af4e6

File tree

2 files changed

+82
-0
lines changed

2 files changed

+82
-0
lines changed

lib/fetch/body.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,10 @@ function bodyMixinMethods (instance) {
291291
const chunks = []
292292

293293
for await (const chunk of consumeBody(this[kState].body)) {
294+
if (!isUint8Array(chunk)) {
295+
throw new TypeError('Expected Uint8Array chunk')
296+
}
297+
294298
// Assemble one final large blob with Uint8Array's can exhaust memory.
295299
// That's why we create create multiple blob's and using references
296300
chunks.push(new Blob([chunk]))
@@ -314,6 +318,10 @@ function bodyMixinMethods (instance) {
314318
let offset = 0
315319

316320
for await (const chunk of consumeBody(this[kState].body)) {
321+
if (!isUint8Array(chunk)) {
322+
throw new TypeError('Expected Uint8Array chunk')
323+
}
324+
317325
buffer.set(chunk, offset)
318326
offset += chunk.length
319327
}
@@ -331,6 +339,10 @@ function bodyMixinMethods (instance) {
331339
let size = 0
332340

333341
for await (const chunk of consumeBody(this[kState].body)) {
342+
if (!isUint8Array(chunk)) {
343+
throw new TypeError('Expected Uint8Array chunk')
344+
}
345+
334346
chunks.push(chunk)
335347
size += chunk.byteLength
336348
}
@@ -355,6 +367,10 @@ function bodyMixinMethods (instance) {
355367
const textDecoder = new TextDecoder()
356368

357369
for await (const chunk of consumeBody(this[kState].body)) {
370+
if (!isUint8Array(chunk)) {
371+
throw new TypeError('Expected Uint8Array chunk')
372+
}
373+
358374
result += textDecoder.decode(chunk, { stream: true })
359375
}
360376

test/fetch/response.js

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ const { test } = require('tap')
44
const {
55
Response
66
} = require('../../')
7+
const { ReadableStream } = require('stream/web')
78

89
test('arg validation', async (t) => {
910
// constructor
@@ -164,3 +165,68 @@ test('Modifying headers using Headers.prototype.set', (t) => {
164165

165166
t.end()
166167
})
168+
169+
// https://github.com/nodejs/node/issues/43838
170+
test('constructing a Response with a ReadableStream body', async (t) => {
171+
const text = '{"foo":"bar"}'
172+
const uint8 = new TextEncoder().encode(text)
173+
174+
t.test('Readable stream with Uint8Array chunks', async (t) => {
175+
const readable = new ReadableStream({
176+
start (controller) {
177+
controller.enqueue(uint8)
178+
controller.close()
179+
}
180+
})
181+
182+
const response1 = new Response(readable)
183+
const response2 = response1.clone()
184+
const response3 = response1.clone()
185+
186+
t.equal(await response1.text(), text)
187+
t.same(await response2.arrayBuffer(), uint8.buffer)
188+
t.same(await response3.json(), JSON.parse(text))
189+
190+
t.end()
191+
})
192+
193+
t.test('Readable stream with non-Uint8Array chunks', async (t) => {
194+
const readable = new ReadableStream({
195+
start (controller) {
196+
controller.enqueue(text) // string
197+
controller.close()
198+
}
199+
})
200+
201+
const response = new Response(readable)
202+
203+
await t.rejects(response.text(), TypeError)
204+
205+
t.end()
206+
})
207+
208+
t.test('Readable with ArrayBuffer chunk still throws', async (t) => {
209+
const readable = new ReadableStream({
210+
start (controller) {
211+
controller.enqueue(uint8.buffer)
212+
controller.close()
213+
}
214+
})
215+
216+
const response1 = new Response(readable)
217+
const response2 = response1.clone()
218+
const response3 = response1.clone()
219+
// const response4 = response1.clone()
220+
221+
await t.rejects(response1.arrayBuffer(), TypeError)
222+
await t.rejects(response2.text(), TypeError)
223+
await t.rejects(response3.json(), TypeError)
224+
// TODO: on Node v16.8.0, this throws a TypeError
225+
// because the body is detected as disturbed.
226+
// await t.rejects(response4.blob(), TypeError)
227+
228+
t.end()
229+
})
230+
231+
t.end()
232+
})

0 commit comments

Comments
 (0)