Skip to content

Commit 23a3410

Browse files
authored
lib: allow byob reader for 'blob.stream()'
Fixes: #47993 PR-URL: #49713 Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
1 parent 9718a94 commit 23a3410

File tree

3 files changed

+52
-11
lines changed

3 files changed

+52
-11
lines changed

lib/internal/blob.js

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,7 @@ class Blob {
320320

321321
const reader = this[kHandle].getReader();
322322
return new lazyReadableStream({
323+
type: 'bytes',
323324
start(c) {
324325
// There really should only be one read at a time so using an
325326
// array here is purely defensive.
@@ -339,6 +340,9 @@ class Blob {
339340
if (status === 0) {
340341
// EOS
341342
c.close();
343+
// This is to signal the end for byob readers
344+
// see https://streams.spec.whatwg.org/#example-rbs-pull
345+
c.byobRequest?.respond(0);
342346
const pending = this.pendingPulls.shift();
343347
pending.resolve();
344348
return;
@@ -352,13 +356,15 @@ class Blob {
352356
pending.reject(error);
353357
return;
354358
}
355-
if (buffer !== undefined) {
359+
// ReadableByteStreamController.enqueue errors if we submit a 0-length
360+
// buffer. We need to check for that here.
361+
if (buffer !== undefined && buffer.byteLength !== 0) {
356362
c.enqueue(new Uint8Array(buffer));
357363
}
358364
// We keep reading until we either reach EOS, some error, or we
359365
// hit the flow rate of the stream (c.desiredSize).
360366
queueMicrotask(() => {
361-
if (c.desiredSize <= 0) {
367+
if (c.desiredSize < 0) {
362368
// A manual backpressure check.
363369
if (this.pendingPulls.length !== 0) {
364370
// A case of waiting pull finished (= not yet canceled)

test/parallel/test-blob.js

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -331,12 +331,54 @@ assert.throws(() => new Blob({}), {
331331
const b = new Blob(Array(10).fill('hello'));
332332
const stream = b.stream();
333333
const reader = stream.getReader();
334-
assert.strictEqual(stream[kState].controller.desiredSize, 1);
334+
assert.strictEqual(stream[kState].controller.desiredSize, 0);
335335
const { value, done } = await reader.read();
336336
assert.strictEqual(value.byteLength, 5);
337337
assert(!done);
338338
setTimeout(() => {
339-
assert.strictEqual(stream[kState].controller.desiredSize, 0);
339+
// The blob stream is now a byte stream hence after the first read,
340+
// it should pull in the next 'hello' which is 5 bytes hence -5.
341+
assert.strictEqual(stream[kState].controller.desiredSize, -5);
342+
}, 0);
343+
})().then(common.mustCall());
344+
345+
(async () => {
346+
const blob = new Blob(['hello', 'world']);
347+
const stream = blob.stream();
348+
const reader = stream.getReader({ mode: 'byob' });
349+
const decoder = new TextDecoder();
350+
const chunks = [];
351+
while (true) {
352+
const { value, done } = await reader.read(new Uint8Array(100));
353+
if (done) break;
354+
chunks.push(decoder.decode(value, { stream: true }));
355+
}
356+
assert.strictEqual(chunks.join(''), 'helloworld');
357+
})().then(common.mustCall());
358+
359+
(async () => {
360+
const b = new Blob(Array(10).fill('hello'));
361+
const stream = b.stream();
362+
const reader = stream.getReader({ mode: 'byob' });
363+
assert.strictEqual(stream[kState].controller.desiredSize, 0);
364+
const { value, done } = await reader.read(new Uint8Array(100));
365+
assert.strictEqual(value.byteLength, 5);
366+
assert(!done);
367+
setTimeout(() => {
368+
assert.strictEqual(stream[kState].controller.desiredSize, -5);
369+
}, 0);
370+
})().then(common.mustCall());
371+
372+
(async () => {
373+
const b = new Blob(Array(10).fill('hello'));
374+
const stream = b.stream();
375+
const reader = stream.getReader({ mode: 'byob' });
376+
assert.strictEqual(stream[kState].controller.desiredSize, 0);
377+
const { value, done } = await reader.read(new Uint8Array(2));
378+
assert.strictEqual(value.byteLength, 2);
379+
assert(!done);
380+
setTimeout(() => {
381+
assert.strictEqual(stream[kState].controller.desiredSize, -3);
340382
}, 0);
341383
})().then(common.mustCall());
342384

test/wpt/status/FileAPI/blob.json

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -44,12 +44,5 @@
4444
},
4545
"Blob-slice.any.js": {
4646
"skip": "Depends on File API"
47-
},
48-
"Blob-stream.any.js": {
49-
"fail": {
50-
"expected": [
51-
"Reading Blob.stream() with BYOB reader"
52-
]
53-
}
5447
}
5548
}

0 commit comments

Comments
 (0)