summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreu Botella <abb@randomunok.com>2021-07-14 12:08:42 +0200
committerGitHub <noreply@github.com>2021-07-14 12:08:42 +0200
commit5b771e7e83b32402f06873e684efb2381971e0f6 (patch)
treebe1c3cab01d9edb71900afbfde4b2f983fc38c63
parent56635d3b528347bd37719cd111e55f7d1abace72 (diff)
fix(extensions/web): aborting a FileReader should not affect later reads (#11381)
Currently, calling the `abort()` method on a `FileReader` object aborts any current read operation, but it also prevents any read operation started at some later point from starting. The File API instead specifies that calling `abort()` should reset the `FileReader`'s state and result, as well as removing any queued tasks from the current operation that haven't yet run.
-rw-r--r--extensions/web/10_filereader.js26
-rw-r--r--tools/wpt/expectation.json2
2 files changed, 18 insertions, 10 deletions
diff --git a/extensions/web/10_filereader.js b/extensions/web/10_filereader.js
index 9fdf8862f..ad10e2831 100644
--- a/extensions/web/10_filereader.js
+++ b/extensions/web/10_filereader.js
@@ -52,8 +52,8 @@
[result] = null;
/** @type {null | DOMException} */
[error] = null;
-
- [aborted] = false;
+ /** @type {null | {aborted: boolean}} */
+ [aborted] = null;
/**
* @param {Blob} blob
@@ -74,6 +74,12 @@
// 4. Set fr’s error to null.
this[error] = null;
+ // We set this[aborted] to a new object, and keep track of it in a
+ // separate variable, so if a new read operation starts while there are
+ // remaining tasks from a previous aborted operation, the new operation
+ // will run while the tasks from the previous one are still aborted.
+ const abortedState = this[aborted] = { aborted: false };
+
// 5. Let stream be the result of calling get stream on blob.
const stream /*: ReadableStream<ArrayBufferView>*/ = blob.stream();
@@ -92,17 +98,17 @@
// 10 in parallel while true
(async () => {
- while (!this[aborted]) {
+ while (!abortedState.aborted) {
// 1. Wait for chunkPromise to be fulfilled or rejected.
try {
const chunk = await chunkPromise;
- if (this[aborted]) return;
+ if (abortedState.aborted) return;
// 2. If chunkPromise is fulfilled, and isFirstChunk is true, queue a task to fire a progress event called loadstart at fr.
if (isFirstChunk) {
// TODO(lucacasonato): this is wrong, should be HTML "queue a task"
queueMicrotask(() => {
- if (this[aborted]) return;
+ if (abortedState.aborted) return;
// fire a progress event for loadstart
const ev = new ProgressEvent("loadstart", {});
this.dispatchEvent(ev);
@@ -128,7 +134,7 @@
});
// TODO(lucacasonato): this is wrong, should be HTML "queue a task"
queueMicrotask(() => {
- if (this[aborted]) return;
+ if (abortedState.aborted) return;
this.dispatchEvent(ev);
});
}
@@ -138,7 +144,7 @@
else if (chunk.done === true) {
// TODO(lucacasonato): this is wrong, should be HTML "queue a task"
queueMicrotask(() => {
- if (this[aborted]) return;
+ if (abortedState.aborted) return;
// 1. Set fr’s state to "done".
this[state] = "done";
// 2. Let result be the result of package data given bytes, type, blob’s type, and encodingName.
@@ -232,7 +238,7 @@
} catch (err) {
// TODO(lucacasonato): this is wrong, should be HTML "queue a task"
queueMicrotask(() => {
- if (this[aborted]) return;
+ if (abortedState.aborted) return;
// chunkPromise rejected
this[state] = "done";
@@ -303,7 +309,9 @@
}
// If there are any tasks from the context object on the file reading task source in an affiliated task queue, then remove those tasks from that task queue.
// Terminate the algorithm for the read method being processed.
- this[aborted] = true;
+ if (this[aborted] !== null) {
+ this[aborted].aborted = true;
+ }
// Fire a progress event called abort at the context object.
const ev = new ProgressEvent("abort", {});
diff --git a/tools/wpt/expectation.json b/tools/wpt/expectation.json
index 4124efe7c..0fb126066 100644
--- a/tools/wpt/expectation.json
+++ b/tools/wpt/expectation.json
@@ -2794,7 +2794,7 @@
"reading-data-section": {
"Determining-Encoding.any.html": true,
"FileReader-event-handler-attributes.any.html": true,
- "FileReader-multiple-reads.any.html": false,
+ "FileReader-multiple-reads.any.html": true,
"filereader_abort.any.html": true,
"filereader_error.any.html": true,
"filereader_events.any.html": false,