Skip to content

Commit 3a6e724

Browse files
KhafraDevtargos
authored andcommitted
buffer: extract Blob's .arrayBuffer() & webidl changes
- Extracts Blob.prototype.arrayBuffer so it cannot be overridden in .text(), etc. - Make .bytes() enumerable. I guess the WPT runner is not running the idlharness tests? - Make .text() return a Promise, rather than being explicitly async. This is a non-documented part of the webidl spec. Refs: #49936 - Have .text(), .arrayBuffer(), and .bytes() reject for an invalid this instead of throwing. Fix the tests regarding this. PR-URL: #53372 Refs: #49936 Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com> Reviewed-By: Vinícius Lourenço Claro Cardoso <contact@viniciusl.com.br>
1 parent fb8470a commit 3a6e724

File tree

2 files changed

+56
-32
lines changed

2 files changed

+56
-32
lines changed

lib/internal/blob.js

+37-30
Original file line numberDiff line numberDiff line change
@@ -273,54 +273,32 @@ class Blob {
273273
if (!isBlob(this))
274274
return PromiseReject(new ERR_INVALID_THIS('Blob'));
275275

276-
const { promise, resolve, reject } = createDeferredPromise();
277-
const reader = this[kHandle].getReader();
278-
const buffers = [];
279-
const readNext = () => {
280-
reader.pull((status, buffer) => {
281-
if (status === 0) {
282-
// EOS, concat & resolve
283-
// buffer should be undefined here
284-
resolve(concat(buffers));
285-
return;
286-
} else if (status < 0) {
287-
// The read could fail for many different reasons when reading
288-
// from a non-memory resident blob part (e.g. file-backed blob).
289-
// The error details the system error code.
290-
const error = lazyDOMException('The blob could not be read', 'NotReadableError');
291-
reject(error);
292-
return;
293-
}
294-
if (buffer !== undefined)
295-
buffers.push(buffer);
296-
queueMicrotask(() => readNext());
297-
});
298-
};
299-
readNext();
300-
return promise;
276+
return arrayBuffer(this);
301277
}
302278

303279
/**
304280
* @returns {Promise<string>}
305281
*/
306-
async text() {
282+
text() {
307283
if (!isBlob(this))
308-
throw new ERR_INVALID_THIS('Blob');
284+
return PromiseReject(new ERR_INVALID_THIS('Blob'));
309285

310286
dec ??= new TextDecoder();
311287

312-
return dec.decode(await this.arrayBuffer());
288+
return PromisePrototypeThen(
289+
arrayBuffer(this),
290+
(buffer) => dec.decode(buffer));
313291
}
314292

315293
/**
316294
* @returns {Promise<Uint8Array>}
317295
*/
318296
bytes() {
319297
if (!isBlob(this))
320-
throw new ERR_INVALID_THIS('Blob');
298+
return PromiseReject(new ERR_INVALID_THIS('Blob'));
321299

322300
return PromisePrototypeThen(
323-
this.arrayBuffer(),
301+
arrayBuffer(this),
324302
(buffer) => new Uint8Array(buffer));
325303
}
326304

@@ -439,6 +417,7 @@ ObjectDefineProperties(Blob.prototype, {
439417
stream: kEnumerableProperty,
440418
text: kEnumerableProperty,
441419
arrayBuffer: kEnumerableProperty,
420+
bytes: kEnumerableProperty,
442421
});
443422

444423
function resolveObjectURL(url) {
@@ -490,6 +469,34 @@ function createBlobFromFilePath(path, options) {
490469
return res;
491470
}
492471

472+
function arrayBuffer(blob) {
473+
const { promise, resolve, reject } = createDeferredPromise();
474+
const reader = blob[kHandle].getReader();
475+
const buffers = [];
476+
const readNext = () => {
477+
reader.pull((status, buffer) => {
478+
if (status === 0) {
479+
// EOS, concat & resolve
480+
// buffer should be undefined here
481+
resolve(concat(buffers));
482+
return;
483+
} else if (status < 0) {
484+
// The read could fail for many different reasons when reading
485+
// from a non-memory resident blob part (e.g. file-backed blob).
486+
// The error details the system error code.
487+
const error = lazyDOMException('The blob could not be read', 'NotReadableError');
488+
reject(error);
489+
return;
490+
}
491+
if (buffer !== undefined)
492+
buffers.push(buffer);
493+
queueMicrotask(() => readNext());
494+
});
495+
};
496+
readNext();
497+
return promise;
498+
}
499+
493500
module.exports = {
494501
Blob,
495502
createBlob,

test/parallel/test-blob.js

+19-2
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,7 @@ assert.throws(() => new Blob({}), {
197197
'stream',
198198
'text',
199199
'arrayBuffer',
200+
'bytes',
200201
];
201202

202203
for (const prop of enumerable) {
@@ -409,10 +410,13 @@ assert.throws(() => new Blob({}), {
409410
}
410411

411412
(async () => {
412-
await assert.rejects(async () => Blob.prototype.arrayBuffer.call(), {
413+
await assert.rejects(() => Blob.prototype.arrayBuffer.call(), {
413414
code: 'ERR_INVALID_THIS',
414415
});
415-
await assert.rejects(async () => Blob.prototype.text.call(), {
416+
await assert.rejects(() => Blob.prototype.text.call(), {
417+
code: 'ERR_INVALID_THIS',
418+
});
419+
await assert.rejects(() => Blob.prototype.bytes.call(), {
416420
code: 'ERR_INVALID_THIS',
417421
});
418422
})().then(common.mustCall());
@@ -490,3 +494,16 @@ assert.throws(() => new Blob({}), {
490494
assert.ok(structuredClone(blob).size === blob.size);
491495
assert.ok((await structuredClone(blob).text()) === (await blob.text()));
492496
})().then(common.mustCall());
497+
498+
(async () => {
499+
const blob = new Blob(['hello']);
500+
const { arrayBuffer } = Blob.prototype;
501+
502+
Blob.prototype.arrayBuffer = common.mustNotCall();
503+
504+
try {
505+
assert.strictEqual(await blob.text(), 'hello');
506+
} finally {
507+
Blob.prototype.arrayBuffer = arrayBuffer;
508+
}
509+
})().then(common.mustCall());

0 commit comments

Comments
 (0)