Correctly reject in-progress body methods with AbortError
Prior to this change, response body methods such as
response.body.arrayBuffer() would reject with a TypeError if the fetch
was aborted. This change makes them correctly reject with an AbortError
instead.
This implements stage #3 of the "Body Cancellation" section of the
design doc:
https://docs.google.com/document/d/1OuoCG2uiijbAwbCw9jaS7tHEO0LBO_4gMNio1ox0qlY/edit#heading=h.fvc7d7q07oio
Bug: 817687
Change-Id: Ifde322d9c22485a8ba9d14fd4ffca65c4fb4745a
Reviewed-on: https://chromium-review.googlesource.com/954765
Commit-Queue: Adam Rice <ricea@chromium.org>
Reviewed-by: Matt Falkenhagen <falken@chromium.org>
Reviewed-by: Yutaka Hirano <yhirano@chromium.org>
Cr-Commit-Position: refs/heads/master@{#544335}
diff --git a/lint.whitelist b/lint.whitelist
index 42c7d48..958adb2 100644
--- a/lint.whitelist
+++ b/lint.whitelist
@@ -197,6 +197,7 @@
SET TIMEOUT: screen-orientation/onchange-event.html
SET TIMEOUT: screen-orientation/resources/sandboxed-iframe-locking.html
SET TIMEOUT: secure-contexts/basic-popup-and-iframe-tests.https.js
+SET TIMEOUT: service-workers/cache-storage/script-tests/cache-abort.js
SET TIMEOUT: service-workers/service-worker/activation.https.html
SET TIMEOUT: service-workers/service-worker/fetch-frame-resource.https.html
SET TIMEOUT: service-workers/service-worker/fetch-request-redirect.https.html
diff --git a/service-workers/cache-storage/script-tests/cache-abort.js b/service-workers/cache-storage/script-tests/cache-abort.js
new file mode 100644
index 0000000..ec4130f
--- /dev/null
+++ b/service-workers/cache-storage/script-tests/cache-abort.js
@@ -0,0 +1,81 @@
+if (self.importScripts) {
+ importScripts('/resources/testharness.js');
+ importScripts('../resources/test-helpers.js');
+ importScripts('/common/utils.js');
+}
+
+// We perform the same tests on put, add, addAll. Parameterise the tests to
+// reduce repetition.
+const methodsToTest = {
+ put: async (cache, request) => {
+ const response = await fetch(request);
+ return cache.put(request, response);
+ },
+ add: async (cache, request) => cache.add(request),
+ addAll: async (cache, request) => cache.addAll([request]),
+};
+
+for (const method in methodsToTest) {
+ const perform = methodsToTest[method];
+
+ cache_test(async (cache, test) => {
+ const controller = new AbortController();
+ const signal = controller.signal;
+ controller.abort();
+ const request = new Request('../resources/simple.txt', { signal });
+ return promise_rejects(test, 'AbortError', perform(cache, request),
+ `${method} should reject`);
+ }, `${method}() on an already-aborted request should reject with AbortError`);
+
+ cache_test(async (cache, test) => {
+ const controller = new AbortController();
+ const signal = controller.signal;
+ const request = new Request('../resources/simple.txt', { signal });
+ const promise = perform(cache, request);
+ controller.abort();
+ return promise_rejects(test, 'AbortError', promise,
+ `${method} should reject`);
+ }, `${method}() synchronously followed by abort should reject with ` +
+ `AbortError`);
+
+ cache_test(async (cache, test) => {
+ const controller = new AbortController();
+ const signal = controller.signal;
+ const stateKey = token();
+ const abortKey = token();
+ const request = new Request(
+ `../../../fetch/api/resources/infinite-slow-response.py?stateKey=${stateKey}&abortKey=${abortKey}`,
+ { signal });
+
+ const promise = perform(cache, request);
+
+ // Wait for the server to start sending the response body.
+ let opened = false;
+ do {
+ // Normally only one fetch to 'stash-take' is needed, but the fetches
+ // will be served in reverse order sometimes
+ // (i.e., 'stash-take' gets served before 'infinite-slow-response').
+
+ const response =
+ await fetch(`../../../fetch/api/resources/stash-take.py?key=${stateKey}`);
+ const body = await response.json();
+ if (body === 'open') opened = true;
+ } while (!opened);
+
+ // Sadly the above loop cannot guarantee that the browser has started
+ // processing the response body. This delay is needed to make the test
+ // failures non-flaky in Chrome version 66. My deepest apologies.
+ await new Promise(resolve => setTimeout(resolve, 250));
+
+ controller.abort();
+
+ await promise_rejects(test, 'AbortError', promise,
+ `${method} should reject`);
+
+ // infinite-slow-response.py doesn't know when to stop.
+ return fetch(`../../../fetch/api/resources/stash-put.py?key=${abortKey}`);
+ }, `${method}() followed by abort after headers received should reject ` +
+ `with AbortError`);
+}
+
+done();
diff --git a/service-workers/cache-storage/serviceworker/cache-abort.https.html b/service-workers/cache-storage/serviceworker/cache-abort.https.html
new file mode 100644
index 0000000..b4f203b
--- /dev/null
+++ b/service-workers/cache-storage/serviceworker/cache-abort.https.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<title>Cache Storage: Abort</title>
+<link rel="help" href="https://fetch.spec.whatwg.org/#request-signal">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../service-worker/resources/test-helpers.sub.js"></script>
+<script>
+service_worker_test('../script-tests/cache-abort.js');
+</script>
diff --git a/service-workers/cache-storage/window/cache-abort.https.html b/service-workers/cache-storage/window/cache-abort.https.html
new file mode 100644
index 0000000..935023d
--- /dev/null
+++ b/service-workers/cache-storage/window/cache-abort.https.html
@@ -0,0 +1,8 @@
+<!DOCTYPE html>
+<title>Cache Storage: Abort</title>
+<link rel="help" href="https://fetch.spec.whatwg.org/#request-signal">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../resources/test-helpers.js"></script>
+<script src="/common/utils.js"></script>
+<script src="../script-tests/cache-abort.js"></script>
diff --git a/service-workers/cache-storage/worker/cache-abort.https.html b/service-workers/cache-storage/worker/cache-abort.https.html
new file mode 100644
index 0000000..ccd7191
--- /dev/null
+++ b/service-workers/cache-storage/worker/cache-abort.https.html
@@ -0,0 +1,8 @@
+<!DOCTYPE html>
+<title>>Cache Storage: Abort</title>
+<link rel="help" href="https://fetch.spec.whatwg.org/#request-signal">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+fetch_tests_from_worker(new Worker('../script-tests/cache-abort.js'));
+</script>