Diff
Modified: trunk/LayoutTests/ChangeLog (239643 => 239644)
--- trunk/LayoutTests/ChangeLog 2019-01-04 23:53:22 UTC (rev 239643)
+++ trunk/LayoutTests/ChangeLog 2019-01-05 00:01:43 UTC (rev 239644)
@@ -1,3 +1,13 @@
+2019-01-04 Youenn Fablet <[email protected]>
+
+ [Fetch API] Implement abortable fetch
+ https://bugs.webkit.org/show_bug.cgi?id=174980
+ <rdar://problem/46861402>
+
+ Reviewed by Chris Dumez.
+
+ * TestExpectations: Enable abort tests.
+
2019-01-04 Brent Fulgham <[email protected]>
Parsed protocol of _javascript_ URLs with embedded newlines and carriage returns do not match parsed protocol in Chrome and Firefox
Modified: trunk/LayoutTests/TestExpectations (239643 => 239644)
--- trunk/LayoutTests/TestExpectations 2019-01-04 23:53:22 UTC (rev 239643)
+++ trunk/LayoutTests/TestExpectations 2019-01-05 00:01:43 UTC (rev 239644)
@@ -211,7 +211,6 @@
imported/w3c/web-platform-tests/cors/remote-origin.htm [ Skip ]
# Skip service worker tests that are timing out.
-imported/w3c/web-platform-tests/fetch/api/abort/general-serviceworker.https.html [ Skip ]
imported/w3c/web-platform-tests/service-workers/service-worker/performance-timeline.https.html [ Skip ]
imported/w3c/web-platform-tests/service-workers/service-worker/respond-with-body-accessed-response.https.html [ Skip ]
imported/w3c/web-platform-tests/service-workers/service-worker/sandboxed-iframe-fetch-event.https.html [ Skip ]
@@ -383,10 +382,6 @@
webkit.org/b/189910 imported/w3c/web-platform-tests/resource-timing/resource_timing_store_and_clear_during_callback.html [ Pass Failure ]
webkit.org/b/190523 imported/w3c/web-platform-tests/resource-timing/resource_timing_cross_origin_redirect_chain.html [ Pass Failure ]
-# The follow two tests change their output each run
-imported/w3c/web-platform-tests/fetch/api/abort/general.any.html [ Skip ]
-imported/w3c/web-platform-tests/fetch/api/abort/general.any.worker.html [ Skip ]
-
# These tests time out
imported/w3c/web-platform-tests/fetch/api/request/destination/fetch-destination-no-load-event.https.html [ Skip ]
imported/w3c/web-platform-tests/fetch/api/request/destination/fetch-destination.https.html [ Skip ]
Modified: trunk/LayoutTests/imported/w3c/ChangeLog (239643 => 239644)
--- trunk/LayoutTests/imported/w3c/ChangeLog 2019-01-04 23:53:22 UTC (rev 239643)
+++ trunk/LayoutTests/imported/w3c/ChangeLog 2019-01-05 00:01:43 UTC (rev 239644)
@@ -1,3 +1,22 @@
+2019-01-04 Youenn Fablet <[email protected]>
+
+ [Fetch API] Implement abortable fetch
+ https://bugs.webkit.org/show_bug.cgi?id=174980
+ <rdar://problem/46861402>
+
+ Reviewed by Chris Dumez.
+
+ Fixed tests to run in WebKit CI.
+ Also fixed a bug in a test where the fetch response body is not actually empty.
+
+ * web-platform-tests/fetch/api/abort/cache.https-expected.txt:
+ * web-platform-tests/fetch/api/abort/general-serviceworker.https-expected.txt:
+ * web-platform-tests/fetch/api/abort/general.any-expected.txt:
+ * web-platform-tests/fetch/api/abort/general.any.js:
+ * web-platform-tests/fetch/api/abort/general.any.worker-expected.txt:
+ * web-platform-tests/fetch/api/abort/serviceworker-intercepted.https-expected.txt:
+ * web-platform-tests/fetch/api/response/response-consume-stream-expected.txt:
+
2019-01-02 Simon Fraser <[email protected]>
Support css-color-4 rgb functions
Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/abort/cache.https-expected.txt (239643 => 239644)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/abort/cache.https-expected.txt 2019-01-04 23:53:22 UTC (rev 239643)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/abort/cache.https-expected.txt 2019-01-05 00:01:43 UTC (rev 239644)
@@ -1,4 +1,4 @@
-FAIL Signals are not stored in the cache API promise_test: Unhandled rejection with value: object "TypeError: undefined is not an object (evaluating 'cachedRequest.signal.aborted')"
-FAIL Signals are not stored in the cache API, even if they're already aborted promise_test: Unhandled rejection with value: object "TypeError: undefined is not an object (evaluating 'cachedRequest.signal.aborted')"
+PASS Signals are not stored in the cache API
+PASS Signals are not stored in the cache API, even if they're already aborted
Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/abort/general-serviceworker.https-expected.txt (239643 => 239644)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/abort/general-serviceworker.https-expected.txt 2019-01-04 23:53:22 UTC (rev 239643)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/abort/general-serviceworker.https-expected.txt 2019-01-05 00:01:43 UTC (rev 239644)
@@ -1,8 +1,6 @@
-Harness Error (TIMEOUT), message = null
-
-FAIL Aborting rejects with AbortError assert_unreached: Should have rejected: undefined Reached unreachable code
-FAIL Aborting rejects with AbortError - no-cors assert_throws: function "function () { throw e }" threw object "TypeError: A server with the specified hostname could not be found." that is not a DOMException AbortError: property "code" is equal to undefined, expected 20
+PASS Aborting rejects with AbortError
+PASS Aborting rejects with AbortError - no-cors
PASS TypeError from request constructor takes priority - RequestInit's window is not null
PASS TypeError from request constructor takes priority - Input URL is not valid
PASS TypeError from request constructor takes priority - Input URL has credentials
@@ -19,34 +17,34 @@
PASS TypeError from request constructor takes priority - Bad credentials init parameter value
PASS TypeError from request constructor takes priority - Bad cache init parameter value
PASS TypeError from request constructor takes priority - Bad redirect init parameter value
-FAIL Request objects have a signal property assert_true: Signal member is present & truthy expected true got false
-FAIL Signal on request object assert_true: Signal member is present & truthy expected true got false
-FAIL Signal on request object created from request object assert_unreached: Should have rejected: undefined Reached unreachable code
-FAIL Signal on request object created from request object, with signal on second request assert_unreached: Should have rejected: undefined Reached unreachable code
-FAIL Signal on request object created from request object, with signal on second request overriding another assert_unreached: Should have rejected: undefined Reached unreachable code
-FAIL Signal retained after unrelated properties are overridden by fetch assert_unreached: Should have rejected: undefined Reached unreachable code
+PASS Request objects have a signal property
+PASS Signal on request object
+PASS Signal on request object created from request object
+PASS Signal on request object created from request object, with signal on second request
+PASS Signal on request object created from request object, with signal on second request overriding another
+PASS Signal retained after unrelated properties are overridden by fetch
PASS Signal removed by setting to null
-FAIL Already aborted signal rejects immediately assert_unreached: Fetch must not resolve Reached unreachable code
+PASS Already aborted signal rejects immediately
PASS Request is still 'used' if signal is aborted before fetching
-FAIL response.arrayBuffer() rejects if already aborted assert_unreached: Should have rejected: undefined Reached unreachable code
-FAIL response.blob() rejects if already aborted assert_unreached: Should have rejected: undefined Reached unreachable code
-FAIL response.formData() rejects if already aborted assert_throws: function "function () { throw e }" threw object "NotSupportedError: The operation is not supported." that is not a DOMException AbortError: property "code" is equal to 9, expected 20
-FAIL response.json() rejects if already aborted assert_unreached: Should have rejected: undefined Reached unreachable code
-FAIL response.text() rejects if already aborted assert_unreached: Should have rejected: undefined Reached unreachable code
-FAIL Already aborted signal does not make request assert_equals: Request hasn't been made to the server expected (object) null but got (string) "open"
-FAIL Already aborted signal can be used for many fetches assert_unreached: Should have rejected: undefined Reached unreachable code
-FAIL Signal can be used to abort other fetches, even if another fetch succeeded before aborting assert_unreached: Should have rejected: undefined Reached unreachable code
-FAIL Underlying connection is closed when aborting after receiving response promise_test: Unhandled rejection with value: object "Error: Timed out"
-FAIL Underlying connection is closed when aborting after receiving response - no-cors promise_test: Unhandled rejection with value: object "TypeError: A server with the specified hostname could not be found."
-TIMEOUT Fetch aborted & connection closed when aborted after calling response.arrayBuffer() Test timed out
-NOTRUN Fetch aborted & connection closed when aborted after calling response.blob()
-NOTRUN Fetch aborted & connection closed when aborted after calling response.formData()
-NOTRUN Fetch aborted & connection closed when aborted after calling response.json()
-NOTRUN Fetch aborted & connection closed when aborted after calling response.text()
-NOTRUN Stream errors once aborted. Underlying connection closed.
-NOTRUN Stream errors once aborted, after reading. Underlying connection closed.
-NOTRUN Stream will not error if body is empty. It's closed with an empty queue before it errors.
-NOTRUN Readable stream synchronously cancels with AbortError if aborted before reading
-FAIL Signal state is cloned undefined is not an object (evaluating 'request.signal.aborted')
-FAIL Clone aborts with original controller undefined is not an object (evaluating 'request.signal.addEventListener')
+PASS response.arrayBuffer() rejects if already aborted
+PASS response.blob() rejects if already aborted
+PASS response.formData() rejects if already aborted
+PASS response.json() rejects if already aborted
+PASS response.text() rejects if already aborted
+PASS Already aborted signal does not make request
+PASS Already aborted signal can be used for many fetches
+PASS Signal can be used to abort other fetches, even if another fetch succeeded before aborting
+PASS Underlying connection is closed when aborting after receiving response
+PASS Underlying connection is closed when aborting after receiving response - no-cors
+PASS Fetch aborted & connection closed when aborted after calling response.arrayBuffer()
+PASS Fetch aborted & connection closed when aborted after calling response.blob()
+FAIL Fetch aborted & connection closed when aborted after calling response.formData() assert_throws: function "function () { throw e }" threw object "NotSupportedError: The operation is not supported." that is not a DOMException AbortError: property "code" is equal to 9, expected 20
+PASS Fetch aborted & connection closed when aborted after calling response.json()
+PASS Fetch aborted & connection closed when aborted after calling response.text()
+PASS Stream errors once aborted. Underlying connection closed.
+PASS Stream errors once aborted, after reading. Underlying connection closed.
+PASS Stream will not error if body is empty. It's closed with an empty queue before it errors.
+FAIL Readable stream synchronously cancels with AbortError if aborted before reading assert_true: Cancel called sync expected true got false
+PASS Signal state is cloned
+PASS Clone aborts with original controller
Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/abort/general.any-expected.txt (239643 => 239644)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/abort/general.any-expected.txt 2019-01-04 23:53:22 UTC (rev 239643)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/abort/general.any-expected.txt 2019-01-05 00:01:43 UTC (rev 239644)
@@ -1,12 +1,7 @@
-Blocked access to external URL http://www1.localhost:8800/fetch/api/resources/data.json
-CONSOLE MESSAGE: line 36: Fetch API cannot load http://www1.localhost:8800/fetch/api/resources/data.json due to access control checks.
-Blocked access to external URL http://www1.localhost:8800/fetch/api/resources/infinite-slow-response.py?stateKey=28d5c068-417e-4c81-a0cd-9b8c22aed3c1&abortKey=ef9a1b5a-7afd-4734-b145-f033788c0e6b
-CONSOLE MESSAGE: line 318: Fetch API cannot load http://www1.localhost:8800/fetch/api/resources/infinite-slow-response.py?stateKey=28d5c068-417e-4c81-a0cd-9b8c22aed3c1&abortKey=ef9a1b5a-7afd-4734-b145-f033788c0e6b due to access control checks.
+CONSOLE MESSAGE: Unhandled Promise Rejection: AbortError: Request signal is aborted
-Harness Error (TIMEOUT), message = null
-
-FAIL Aborting rejects with AbortError assert_unreached: Should have rejected: undefined Reached unreachable code
-FAIL Aborting rejects with AbortError - no-cors assert_throws: function "function () { throw e }" threw object "TypeError: Type error" that is not a DOMException AbortError: property "code" is equal to undefined, expected 20
+PASS Aborting rejects with AbortError
+PASS Aborting rejects with AbortError - no-cors
PASS TypeError from request constructor takes priority - RequestInit's window is not null
PASS TypeError from request constructor takes priority - Input URL is not valid
PASS TypeError from request constructor takes priority - Input URL has credentials
@@ -15,7 +10,6 @@
PASS TypeError from request constructor takes priority - RequestInit's method is invalid
PASS TypeError from request constructor takes priority - RequestInit's method is forbidden
PASS TypeError from request constructor takes priority - RequestInit's mode is no-cors and method is not simple
-PASS TypeError from request constructor takes priority - RequestInit's mode is no-cors and integrity is not empty
PASS TypeError from request constructor takes priority - RequestInit's cache mode is only-if-cached and mode is not same-origin
PASS TypeError from request constructor takes priority - Request with cache mode: only-if-cached and fetch mode cors
PASS TypeError from request constructor takes priority - Request with cache mode: only-if-cached and fetch mode no-cors
@@ -24,34 +18,34 @@
PASS TypeError from request constructor takes priority - Bad credentials init parameter value
PASS TypeError from request constructor takes priority - Bad cache init parameter value
PASS TypeError from request constructor takes priority - Bad redirect init parameter value
-FAIL Request objects have a signal property assert_true: Signal member is present & truthy expected true got false
-FAIL Signal on request object assert_true: Signal member is present & truthy expected true got false
-FAIL Signal on request object created from request object assert_unreached: Should have rejected: undefined Reached unreachable code
-FAIL Signal on request object created from request object, with signal on second request assert_unreached: Should have rejected: undefined Reached unreachable code
-FAIL Signal on request object created from request object, with signal on second request overriding another assert_unreached: Should have rejected: undefined Reached unreachable code
-FAIL Signal retained after unrelated properties are overridden by fetch assert_unreached: Should have rejected: undefined Reached unreachable code
+PASS Request objects have a signal property
+PASS Signal on request object
+PASS Signal on request object created from request object
+PASS Signal on request object created from request object, with signal on second request
+PASS Signal on request object created from request object, with signal on second request overriding another
+PASS Signal retained after unrelated properties are overridden by fetch
PASS Signal removed by setting to null
-FAIL Already aborted signal rejects immediately assert_unreached: Fetch must not resolve Reached unreachable code
+PASS Already aborted signal rejects immediately
PASS Request is still 'used' if signal is aborted before fetching
-FAIL response.arrayBuffer() rejects if already aborted assert_unreached: Should have rejected: undefined Reached unreachable code
-FAIL response.blob() rejects if already aborted assert_unreached: Should have rejected: undefined Reached unreachable code
-FAIL response.formData() rejects if already aborted assert_throws: function "function () { throw e }" threw object "NotSupportedError: The operation is not supported." that is not a DOMException AbortError: property "code" is equal to 9, expected 20
-FAIL response.json() rejects if already aborted assert_unreached: Should have rejected: undefined Reached unreachable code
-FAIL response.text() rejects if already aborted assert_unreached: Should have rejected: undefined Reached unreachable code
-FAIL Already aborted signal does not make request assert_equals: Request hasn't been made to the server expected (object) null but got (string) "open"
-FAIL Already aborted signal can be used for many fetches assert_unreached: Should have rejected: undefined Reached unreachable code
-FAIL Signal can be used to abort other fetches, even if another fetch succeeded before aborting assert_unreached: Should have rejected: undefined Reached unreachable code
-FAIL Underlying connection is closed when aborting after receiving response promise_test: Unhandled rejection with value: object "Error: Timed out"
-FAIL Underlying connection is closed when aborting after receiving response - no-cors promise_test: Unhandled rejection with value: object "TypeError: Type error"
-TIMEOUT Fetch aborted & connection closed when aborted after calling response.arrayBuffer() Test timed out
-NOTRUN Fetch aborted & connection closed when aborted after calling response.blob()
-NOTRUN Fetch aborted & connection closed when aborted after calling response.formData()
-NOTRUN Fetch aborted & connection closed when aborted after calling response.json()
-NOTRUN Fetch aborted & connection closed when aborted after calling response.text()
-NOTRUN Stream errors once aborted. Underlying connection closed.
-NOTRUN Stream errors once aborted, after reading. Underlying connection closed.
-NOTRUN Stream will not error if body is empty. It's closed with an empty queue before it errors.
-NOTRUN Readable stream synchronously cancels with AbortError if aborted before reading
-FAIL Signal state is cloned undefined is not an object (evaluating 'request.signal.aborted')
-FAIL Clone aborts with original controller undefined is not an object (evaluating 'request.signal.addEventListener')
+PASS response.arrayBuffer() rejects if already aborted
+PASS response.blob() rejects if already aborted
+PASS response.formData() rejects if already aborted
+PASS response.json() rejects if already aborted
+PASS response.text() rejects if already aborted
+PASS Already aborted signal does not make request
+PASS Already aborted signal can be used for many fetches
+PASS Signal can be used to abort other fetches, even if another fetch succeeded before aborting
+PASS Underlying connection is closed when aborting after receiving response
+PASS Underlying connection is closed when aborting after receiving response - no-cors
+PASS Fetch aborted & connection closed when aborted after calling response.arrayBuffer()
+PASS Fetch aborted & connection closed when aborted after calling response.blob()
+FAIL Fetch aborted & connection closed when aborted after calling response.formData() assert_throws: function "function () { throw e }" threw object "NotSupportedError: The operation is not supported." that is not a DOMException AbortError: property "code" is equal to 9, expected 20
+PASS Fetch aborted & connection closed when aborted after calling response.json()
+PASS Fetch aborted & connection closed when aborted after calling response.text()
+PASS Stream errors once aborted. Underlying connection closed.
+PASS Stream errors once aborted, after reading. Underlying connection closed.
+PASS Stream will not error if body is empty. It's closed with an empty queue before it errors.
+FAIL Readable stream synchronously cancels with AbortError if aborted before reading assert_true: Cancel called sync expected true got false
+PASS Signal state is cloned
+PASS Clone aborts with original controller
Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/abort/general.any.js (239643 => 239644)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/abort/general.any.js 2019-01-04 23:53:22 UTC (rev 239643)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/abort/general.any.js 2019-01-05 00:01:43 UTC (rev 239644)
@@ -1,4 +1,5 @@
// META: script=/common/utils.js
+// META: script=/common/get-host-info.sub.js
// META: script=../request/request-error.js
const BODY_METHODS = ['arrayBuffer', 'blob', 'formData', 'json', 'text'];
@@ -15,6 +16,9 @@
);
}
+const hostInfo = get_host_info();
+const urlHostname = hostInfo.REMOTE_HOST;
+
promise_test(async t => {
const controller = new AbortController();
const signal = controller.signal;
@@ -31,7 +35,7 @@
controller.abort();
const url = "" URL('../resources/data.json', location);
- url.hostname = 'www1.' + url.hostname;
+ url.hostname = urlHostname;
const fetchPromise = fetch(url, {
signal,
@@ -314,7 +318,7 @@
requestAbortKeys.push(abortKey);
const url = "" URL(`../resources/infinite-slow-response.py?stateKey=${stateKey}&abortKey=${abortKey}`, location);
- url.hostname = 'www1.' + url.hostname;
+ url.hostname = urlHostname;
await fetch(url, {
signal,
@@ -322,7 +326,7 @@
});
const stashTakeURL = new URL(`../resources/stash-take.py?key=${stateKey}`, location);
- stashTakeURL.hostname = 'www1.' + stashTakeURL.hostname;
+ stashTakeURL.hostname = urlHostname;
const beforeAbortResult = await fetch(stashTakeURL).then(r => r.json());
assert_equals(beforeAbortResult, "open", "Connection is open");
@@ -440,7 +444,7 @@
const controller = new AbortController();
const signal = controller.signal;
- const response = await fetch(`../resources/empty.txt`, { signal });
+ const response = await fetch(`../resources/method.py`, { signal });
// Read whole response to ensure close signal has sent.
await response.clone().text();
Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/abort/general.any.worker-expected.txt (239643 => 239644)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/abort/general.any.worker-expected.txt 2019-01-04 23:53:22 UTC (rev 239643)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/abort/general.any.worker-expected.txt 2019-01-05 00:01:43 UTC (rev 239644)
@@ -1,10 +1,6 @@
-Blocked access to external URL http://www1.localhost:8800/fetch/api/resources/data.json
-Blocked access to external URL http://www1.localhost:8800/fetch/api/resources/infinite-slow-response.py?stateKey=7471d98e-1bdb-4254-a315-9489c98b8f59&abortKey=4c631f17-2786-4b07-84f4-0a5760d28f1e
-Harness Error (TIMEOUT), message = null
-
-FAIL Aborting rejects with AbortError assert_unreached: Should have rejected: undefined Reached unreachable code
-FAIL Aborting rejects with AbortError - no-cors assert_throws: function "function () { throw e }" threw object "TypeError: Type error" that is not a DOMException AbortError: property "code" is equal to undefined, expected 20
+PASS Aborting rejects with AbortError
+PASS Aborting rejects with AbortError - no-cors
PASS TypeError from request constructor takes priority - RequestInit's window is not null
PASS TypeError from request constructor takes priority - Input URL is not valid
PASS TypeError from request constructor takes priority - Input URL has credentials
@@ -13,7 +9,6 @@
PASS TypeError from request constructor takes priority - RequestInit's method is invalid
PASS TypeError from request constructor takes priority - RequestInit's method is forbidden
PASS TypeError from request constructor takes priority - RequestInit's mode is no-cors and method is not simple
-PASS TypeError from request constructor takes priority - RequestInit's mode is no-cors and integrity is not empty
PASS TypeError from request constructor takes priority - RequestInit's cache mode is only-if-cached and mode is not same-origin
PASS TypeError from request constructor takes priority - Request with cache mode: only-if-cached and fetch mode cors
PASS TypeError from request constructor takes priority - Request with cache mode: only-if-cached and fetch mode no-cors
@@ -22,34 +17,34 @@
PASS TypeError from request constructor takes priority - Bad credentials init parameter value
PASS TypeError from request constructor takes priority - Bad cache init parameter value
PASS TypeError from request constructor takes priority - Bad redirect init parameter value
-FAIL Request objects have a signal property assert_true: Signal member is present & truthy expected true got false
-FAIL Signal on request object assert_true: Signal member is present & truthy expected true got false
-FAIL Signal on request object created from request object assert_unreached: Should have rejected: undefined Reached unreachable code
-FAIL Signal on request object created from request object, with signal on second request assert_unreached: Should have rejected: undefined Reached unreachable code
-FAIL Signal on request object created from request object, with signal on second request overriding another assert_unreached: Should have rejected: undefined Reached unreachable code
-FAIL Signal retained after unrelated properties are overridden by fetch assert_unreached: Should have rejected: undefined Reached unreachable code
+PASS Request objects have a signal property
+PASS Signal on request object
+PASS Signal on request object created from request object
+PASS Signal on request object created from request object, with signal on second request
+PASS Signal on request object created from request object, with signal on second request overriding another
+PASS Signal retained after unrelated properties are overridden by fetch
PASS Signal removed by setting to null
-FAIL Already aborted signal rejects immediately assert_unreached: Fetch must not resolve Reached unreachable code
+PASS Already aborted signal rejects immediately
PASS Request is still 'used' if signal is aborted before fetching
-FAIL response.arrayBuffer() rejects if already aborted assert_unreached: Should have rejected: undefined Reached unreachable code
-FAIL response.blob() rejects if already aborted assert_unreached: Should have rejected: undefined Reached unreachable code
-FAIL response.formData() rejects if already aborted assert_throws: function "function () { throw e }" threw object "NotSupportedError: The operation is not supported." that is not a DOMException AbortError: property "code" is equal to 9, expected 20
-FAIL response.json() rejects if already aborted assert_unreached: Should have rejected: undefined Reached unreachable code
-FAIL response.text() rejects if already aborted assert_unreached: Should have rejected: undefined Reached unreachable code
-FAIL Already aborted signal does not make request assert_equals: Request hasn't been made to the server expected (object) null but got (string) "open"
-FAIL Already aborted signal can be used for many fetches assert_unreached: Should have rejected: undefined Reached unreachable code
-FAIL Signal can be used to abort other fetches, even if another fetch succeeded before aborting assert_unreached: Should have rejected: undefined Reached unreachable code
-FAIL Underlying connection is closed when aborting after receiving response promise_test: Unhandled rejection with value: object "Error: Timed out"
-FAIL Underlying connection is closed when aborting after receiving response - no-cors promise_test: Unhandled rejection with value: object "TypeError: Type error"
-TIMEOUT Fetch aborted & connection closed when aborted after calling response.arrayBuffer() Test timed out
-NOTRUN Fetch aborted & connection closed when aborted after calling response.blob()
-NOTRUN Fetch aborted & connection closed when aborted after calling response.formData()
-NOTRUN Fetch aborted & connection closed when aborted after calling response.json()
-NOTRUN Fetch aborted & connection closed when aborted after calling response.text()
-NOTRUN Stream errors once aborted. Underlying connection closed.
-NOTRUN Stream errors once aborted, after reading. Underlying connection closed.
-NOTRUN Stream will not error if body is empty. It's closed with an empty queue before it errors.
-NOTRUN Readable stream synchronously cancels with AbortError if aborted before reading
-FAIL Signal state is cloned undefined is not an object (evaluating 'request.signal.aborted')
-FAIL Clone aborts with original controller undefined is not an object (evaluating 'request.signal.addEventListener')
+PASS response.arrayBuffer() rejects if already aborted
+PASS response.blob() rejects if already aborted
+PASS response.formData() rejects if already aborted
+PASS response.json() rejects if already aborted
+PASS response.text() rejects if already aborted
+PASS Already aborted signal does not make request
+PASS Already aborted signal can be used for many fetches
+PASS Signal can be used to abort other fetches, even if another fetch succeeded before aborting
+PASS Underlying connection is closed when aborting after receiving response
+PASS Underlying connection is closed when aborting after receiving response - no-cors
+PASS Fetch aborted & connection closed when aborted after calling response.arrayBuffer()
+PASS Fetch aborted & connection closed when aborted after calling response.blob()
+FAIL Fetch aborted & connection closed when aborted after calling response.formData() assert_throws: function "function () { throw e }" threw object "NotSupportedError: The operation is not supported." that is not a DOMException AbortError: property "code" is equal to 9, expected 20
+PASS Fetch aborted & connection closed when aborted after calling response.json()
+PASS Fetch aborted & connection closed when aborted after calling response.text()
+PASS Stream errors once aborted. Underlying connection closed.
+PASS Stream errors once aborted, after reading. Underlying connection closed.
+PASS Stream will not error if body is empty. It's closed with an empty queue before it errors.
+FAIL Readable stream synchronously cancels with AbortError if aborted before reading assert_true: Cancel called sync expected true got false
+PASS Signal state is cloned
+PASS Clone aborts with original controller
Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/abort/serviceworker-intercepted.https-expected.txt (239643 => 239644)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/abort/serviceworker-intercepted.https-expected.txt 2019-01-04 23:53:22 UTC (rev 239643)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/abort/serviceworker-intercepted.https-expected.txt 2019-01-05 00:01:43 UTC (rev 239644)
@@ -1,9 +1,10 @@
-FAIL Already aborted request does not land in service worker assert_unreached: Should have rejected: undefined Reached unreachable code
-FAIL response.arrayBuffer() rejects if already aborted promise_test: Unhandled rejection with value: object "Error: wait_for_state must be passed a ServiceWorker"
-FAIL response.blob() rejects if already aborted promise_test: Unhandled rejection with value: object "Error: wait_for_state must be passed a ServiceWorker"
-FAIL response.formData() rejects if already aborted promise_test: Unhandled rejection with value: object "Error: wait_for_state must be passed a ServiceWorker"
-FAIL response.json() rejects if already aborted promise_test: Unhandled rejection with value: object "Error: wait_for_state must be passed a ServiceWorker"
-FAIL response.text() rejects if already aborted promise_test: Unhandled rejection with value: object "Error: wait_for_state must be passed a ServiceWorker"
-FAIL Stream errors once aborted. promise_test: Unhandled rejection with value: object "Error: wait_for_state must be passed a ServiceWorker"
+PASS Already aborted request does not land in service worker
+PASS response.arrayBuffer() rejects if already aborted
+PASS response.blob() rejects if already aborted
+PASS response.formData() rejects if already aborted
+PASS response.json() rejects if already aborted
+PASS response.text() rejects if already aborted
+FAIL Stream errors once aborted. assert_unreached: Should have rejected: undefined Reached unreachable code
+
Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/response/response-consume-stream-expected.txt (239643 => 239644)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/response/response-consume-stream-expected.txt 2019-01-04 23:53:22 UTC (rev 239643)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/api/response/response-consume-stream-expected.txt 2019-01-05 00:01:43 UTC (rev 239644)
@@ -5,7 +5,7 @@
PASS Read text response's body as readableStream
PASS Read URLSearchParams response's body as readableStream
PASS Read array buffer response's body as readableStream
-FAIL Read form data response's body as readableStream promise_test: Unhandled rejection with value: object "TypeError: not implemented"
+FAIL Read form data response's body as readableStream promise_test: Unhandled rejection with value: object "NotSupportedError: Not implemented"
PASS Getting an error Response stream
PASS Getting a redirect Response stream
Modified: trunk/LayoutTests/platform/ios-simulator/TestExpectations (239643 => 239644)
--- trunk/LayoutTests/platform/ios-simulator/TestExpectations 2019-01-04 23:53:22 UTC (rev 239643)
+++ trunk/LayoutTests/platform/ios-simulator/TestExpectations 2019-01-05 00:01:43 UTC (rev 239644)
@@ -67,6 +67,7 @@
# This test requires Skia, which isn't available on iOS.
webkit.org/b/174079 fast/text/variations/skia-postscript-name.html [ ImageOnlyFailure ]
+imported/w3c/web-platform-tests/fetch/api/abort/general-serviceworker.https.html [ Pass Failure ]
imported/w3c/web-platform-tests/2dcontext/transformations/canvas_transformations_reset_001.html [ ImageOnlyFailure ]
imported/w3c/web-platform-tests/html/browsers/browsing-the-web/history-traversal/persisted-user-state-restoration/scroll-restoration-fragment-scrolling-cross-origin.html [ Failure ]
imported/w3c/web-platform-tests/webrtc/RTCPeerConnection-setLocalDescription-offer.html [ Failure ]
Modified: trunk/Source/WebCore/ChangeLog (239643 => 239644)
--- trunk/Source/WebCore/ChangeLog 2019-01-04 23:53:22 UTC (rev 239643)
+++ trunk/Source/WebCore/ChangeLog 2019-01-05 00:01:43 UTC (rev 239644)
@@ -1,3 +1,73 @@
+2019-01-04 Youenn Fablet <[email protected]>
+
+ [Fetch API] Implement abortable fetch
+ https://bugs.webkit.org/show_bug.cgi?id=174980
+ <rdar://problem/46861402>
+
+ Reviewed by Chris Dumez.
+
+ Add an AbortSignal to FetchRequest.
+
+ Add support for AbortSignal algorithm.
+ The fetch request signal is added an algorithm to abort the fetch.
+ Update clone algorithm to let signal of the cloned request be following the origin request.
+
+ Update ReadableStream error handling to return an exception instead of a string.
+ This allows passing an AbortError instead of a TypeError as previously done.
+
+ Update FetchBodyOwner to store a loading error either as an exception or as a resource error.
+ The latter is used for passing the error from service worker back to the page.
+ The former is used to pass it to ReadableStream or body accessors.
+
+ Covered by enabled tests.
+
+ * Modules/cache/DOMCache.cpp:
+ (WebCore::DOMCache::put):
+ * Modules/fetch/FetchBody.cpp:
+ (WebCore::FetchBody::consumeAsStream):
+ (WebCore::FetchBody::loadingFailed):
+ * Modules/fetch/FetchBody.h:
+ * Modules/fetch/FetchBodyConsumer.cpp:
+ (WebCore::FetchBodyConsumer::loadingFailed):
+ * Modules/fetch/FetchBodyConsumer.h:
+ * Modules/fetch/FetchBodyOwner.cpp:
+ (WebCore::FetchBodyOwner::arrayBuffer):
+ (WebCore::FetchBodyOwner::blob):
+ (WebCore::FetchBodyOwner::cloneBody):
+ (WebCore::FetchBodyOwner::formData):
+ (WebCore::FetchBodyOwner::json):
+ (WebCore::FetchBodyOwner::text):
+ (WebCore::FetchBodyOwner::loadBlob):
+ (WebCore::FetchBodyOwner::blobLoadingFailed):
+ (WebCore::FetchBodyOwner::consumeBodyAsStream):
+ (WebCore::FetchBodyOwner::setLoadingError):
+ * Modules/fetch/FetchBodyOwner.h:
+ (WebCore::FetchBodyOwner::loadingError const):
+ (WebCore::FetchBodyOwner::loadingException const):
+ * Modules/fetch/FetchBodySource.cpp:
+ (WebCore::FetchBodySource::error):
+ * Modules/fetch/FetchBodySource.h:
+ * Modules/fetch/FetchRequest.cpp:
+ (WebCore::FetchRequest::initializeWith):
+ (WebCore::FetchRequest::clone):
+ * Modules/fetch/FetchRequest.h:
+ (WebCore::FetchRequest::FetchRequest):
+ * Modules/fetch/FetchRequest.idl:
+ * Modules/fetch/FetchRequestInit.h:
+ (WebCore::FetchRequestInit::hasMembers const):
+ * Modules/fetch/FetchRequestInit.idl:
+ * Modules/fetch/FetchResponse.cpp:
+ (WebCore::FetchResponse::clone):
+ (WebCore::FetchResponse::fetch):
+ (WebCore::FetchResponse::BodyLoader::didFail):
+ * Modules/fetch/FetchResponse.h:
+ * bindings/js/ReadableStreamDefaultController.h:
+ (WebCore::ReadableStreamDefaultController::error):
+ * dom/AbortSignal.cpp:
+ (WebCore::AbortSignal::abort):
+ (WebCore::AbortSignal::follow):
+ * dom/AbortSignal.h:
+
2019-01-04 Brent Fulgham <[email protected]>
Parsed protocol of _javascript_ URLs with embedded newlines and carriage returns do not match parsed protocol in Chrome and Firefox
Modified: trunk/Source/WebCore/Modules/cache/DOMCache.cpp (239643 => 239644)
--- trunk/Source/WebCore/Modules/cache/DOMCache.cpp 2019-01-04 23:53:22 UTC (rev 239643)
+++ trunk/Source/WebCore/Modules/cache/DOMCache.cpp 2019-01-05 00:01:43 UTC (rev 239644)
@@ -321,8 +321,8 @@
}
auto request = requestOrException.releaseReturnValue();
- if (response->loadingError()) {
- promise.reject(Exception { TypeError, response->loadingError()->localizedDescription() });
+ if (auto exception = response->loadingException()) {
+ promise.reject(*exception);
return;
}
Modified: trunk/Source/WebCore/Modules/fetch/FetchBody.cpp (239643 => 239644)
--- trunk/Source/WebCore/Modules/fetch/FetchBody.cpp 2019-01-04 23:53:22 UTC (rev 239643)
+++ trunk/Source/WebCore/Modules/fetch/FetchBody.cpp 2019-01-05 00:01:43 UTC (rev 239644)
@@ -186,7 +186,7 @@
owner.loadBlob(blobBody(), nullptr);
m_data = nullptr;
} else if (isFormData())
- source.error("not implemented"_s);
+ source.error(Exception { NotSupportedError, "Not implemented"_s });
else if (m_consumer.hasData())
closeStream = source.enqueue(m_consumer.takeAsArrayBuffer());
else
@@ -224,9 +224,9 @@
m_data = nullptr;
}
-void FetchBody::loadingFailed()
+void FetchBody::loadingFailed(const Exception& exception)
{
- m_consumer.loadingFailed();
+ m_consumer.loadingFailed(exception);
}
void FetchBody::loadingSucceeded()
Modified: trunk/Source/WebCore/Modules/fetch/FetchBody.h (239643 => 239644)
--- trunk/Source/WebCore/Modules/fetch/FetchBody.h 2019-01-04 23:53:22 UTC (rev 239643)
+++ trunk/Source/WebCore/Modules/fetch/FetchBody.h 2019-01-05 00:01:43 UTC (rev 239644)
@@ -60,7 +60,7 @@
WEBCORE_EXPORT static Optional<FetchBody> fromFormData(FormData&);
- void loadingFailed();
+ void loadingFailed(const Exception&);
void loadingSucceeded();
RefPtr<FormData> bodyAsFormData(ScriptExecutionContext&) const;
Modified: trunk/Source/WebCore/Modules/fetch/FetchBodyConsumer.cpp (239643 => 239644)
--- trunk/Source/WebCore/Modules/fetch/FetchBodyConsumer.cpp 2019-01-04 23:53:22 UTC (rev 239643)
+++ trunk/Source/WebCore/Modules/fetch/FetchBodyConsumer.cpp 2019-01-05 00:01:43 UTC (rev 239644)
@@ -212,15 +212,15 @@
}
}
-void FetchBodyConsumer::loadingFailed()
+void FetchBodyConsumer::loadingFailed(const Exception& exception)
{
m_isLoading = false;
if (m_consumePromise) {
- m_consumePromise->reject();
+ m_consumePromise->reject(exception);
m_consumePromise = nullptr;
}
if (m_source) {
- m_source->error("Loading failed"_s);
+ m_source->error(exception);
m_source = nullptr;
}
}
Modified: trunk/Source/WebCore/Modules/fetch/FetchBodyConsumer.h (239643 => 239644)
--- trunk/Source/WebCore/Modules/fetch/FetchBodyConsumer.h 2019-01-04 23:53:22 UTC (rev 239643)
+++ trunk/Source/WebCore/Modules/fetch/FetchBodyConsumer.h 2019-01-05 00:01:43 UTC (rev 239644)
@@ -66,7 +66,7 @@
void resolve(Ref<DeferredPromise>&&, ReadableStream*);
void resolveWithData(Ref<DeferredPromise>&&, const unsigned char*, unsigned);
- void loadingFailed();
+ void loadingFailed(const Exception&);
void loadingSucceeded();
void setConsumePromise(Ref<DeferredPromise>&&);
Modified: trunk/Source/WebCore/Modules/fetch/FetchBodyOwner.cpp (239643 => 239644)
--- trunk/Source/WebCore/Modules/fetch/FetchBodyOwner.cpp 2019-01-04 23:53:22 UTC (rev 239643)
+++ trunk/Source/WebCore/Modules/fetch/FetchBodyOwner.cpp 2019-01-05 00:01:43 UTC (rev 239644)
@@ -99,6 +99,11 @@
void FetchBodyOwner::arrayBuffer(Ref<DeferredPromise>&& promise)
{
+ if (auto exception = loadingException()) {
+ promise->reject(*exception);
+ return;
+ }
+
if (isBodyNullOrOpaque()) {
fulfillPromiseWithArrayBuffer(WTFMove(promise), nullptr, 0);
return;
@@ -113,6 +118,11 @@
void FetchBodyOwner::blob(Ref<DeferredPromise>&& promise)
{
+ if (auto exception = loadingException()) {
+ promise->reject(*exception);
+ return;
+ }
+
if (isBodyNullOrOpaque()) {
promise->resolve<IDLInterface<Blob>>(Blob::create(Vector<uint8_t> { }, Blob::normalizedContentType(extractMIMETypeFromMediaType(m_contentType))));
return;
@@ -127,6 +137,8 @@
void FetchBodyOwner::cloneBody(FetchBodyOwner& owner)
{
+ m_loadingError = owner.m_loadingError;
+
m_contentType = owner.m_contentType;
if (owner.isBodyNull())
return;
@@ -161,6 +173,11 @@
void FetchBodyOwner::formData(Ref<DeferredPromise>&& promise)
{
+ if (auto exception = loadingException()) {
+ promise->reject(*exception);
+ return;
+ }
+
if (isBodyNullOrOpaque()) {
promise->reject();
return;
@@ -175,6 +192,11 @@
void FetchBodyOwner::json(Ref<DeferredPromise>&& promise)
{
+ if (auto exception = loadingException()) {
+ promise->reject(*exception);
+ return;
+ }
+
if (isBodyNullOrOpaque()) {
promise->reject(SyntaxError);
return;
@@ -189,6 +211,11 @@
void FetchBodyOwner::text(Ref<DeferredPromise>&& promise)
{
+ if (auto exception = loadingException()) {
+ promise->reject(*exception);
+ return;
+ }
+
if (isBodyNullOrOpaque()) {
promise->resolve<IDLDOMString>({ });
return;
@@ -208,7 +235,7 @@
ASSERT(!isBodyNull());
if (!scriptExecutionContext()) {
- m_body->loadingFailed();
+ m_body->loadingFailed(Exception { TypeError, "Blob loading failed"_s});
return;
}
@@ -217,7 +244,7 @@
m_blobLoader->loader->start(*scriptExecutionContext(), blob);
if (!m_blobLoader->loader->isStarted()) {
- m_body->loadingFailed();
+ m_body->loadingFailed(Exception { TypeError, "Blob loading failed"_s});
m_blobLoader = WTF::nullopt;
return;
}
@@ -251,11 +278,11 @@
#if ENABLE(STREAMS_API)
if (m_readableStreamSource) {
if (!m_readableStreamSource->isCancelling())
- m_readableStreamSource->error("Blob loading failed"_s);
+ m_readableStreamSource->error(Exception { TypeError, "Blob loading failed"_s});
m_readableStreamSource = nullptr;
} else
#endif
- m_body->loadingFailed();
+ m_body->loadingFailed(Exception { TypeError, "Blob loading failed"_s});
finishBlobLoading();
}
@@ -318,9 +345,8 @@
{
ASSERT(m_readableStreamSource);
- if (m_loadingError) {
- auto errorMessage = m_loadingError->localizedDescription();
- m_readableStreamSource->error(errorMessage.isEmpty() ? "Loading failed"_s : errorMessage);
+ if (auto exception = loadingException()) {
+ m_readableStreamSource->error(*exception);
return;
}
@@ -329,4 +355,53 @@
m_readableStreamSource = nullptr;
}
+ResourceError FetchBodyOwner::loadingError() const
+{
+ return WTF::switchOn(m_loadingError, [](const ResourceError& error) {
+ return ResourceError { error };
+ }, [](const Exception& exception) {
+ return ResourceError { errorDomainWebKitInternal, 0, { }, exception.message() };
+ }, [](auto&&) {
+ return ResourceError { };
+ });
+}
+
+Optional<Exception> FetchBodyOwner::loadingException() const
+{
+ return WTF::switchOn(m_loadingError, [](const ResourceError& error) {
+ return Exception { TypeError, error.localizedDescription().isEmpty() ? "Loading failed"_s : error.localizedDescription() };
+ }, [](const Exception& exception) {
+ return Exception { exception };
+ }, [](auto&&) -> Optional<Exception> {
+ return WTF::nullopt;
+ });
+}
+
+bool FetchBodyOwner::hasLoadingError() const
+{
+ return WTF::switchOn(m_loadingError, [](const ResourceError&) {
+ return true;
+ }, [](const Exception&) {
+ return true;
+ }, [](auto&&) {
+ return false;
+ });
+}
+
+void FetchBodyOwner::setLoadingError(Exception&& exception)
+{
+ if (hasLoadingError())
+ return;
+
+ m_loadingError = WTFMove(exception);
+}
+
+void FetchBodyOwner::setLoadingError(ResourceError&& error)
+{
+ if (hasLoadingError())
+ return;
+
+ m_loadingError = WTFMove(error);
+}
+
} // namespace WebCore
Modified: trunk/Source/WebCore/Modules/fetch/FetchBodyOwner.h (239643 => 239644)
--- trunk/Source/WebCore/Modules/fetch/FetchBodyOwner.h 2019-01-04 23:53:22 UTC (rev 239643)
+++ trunk/Source/WebCore/Modules/fetch/FetchBodyOwner.h 2019-01-05 00:01:43 UTC (rev 239644)
@@ -66,6 +66,10 @@
virtual void cancel() { }
#endif
+ bool hasLoadingError() const;
+ ResourceError loadingError() const;
+ Optional<Exception> loadingException() const;
+
protected:
const FetchBody& body() const { return *m_body; }
FetchBody& body() { return *m_body; }
@@ -88,6 +92,9 @@
void setBodyAsOpaque() { m_isBodyOpaque = true; }
bool isBodyOpaque() const { return m_isBodyOpaque; }
+ void setLoadingError(Exception&&);
+ void setLoadingError(ResourceError&&);
+
private:
// Blob loading routines
void blobChunk(const char*, size_t);
@@ -116,11 +123,12 @@
RefPtr<FetchBodySource> m_readableStreamSource;
#endif
Ref<FetchHeaders> m_headers;
- Optional<ResourceError> m_loadingError;
private:
Optional<BlobLoader> m_blobLoader;
bool m_isBodyOpaque { false };
+
+ Variant<std::nullptr_t, Exception, ResourceError> m_loadingError;
};
} // namespace WebCore
Modified: trunk/Source/WebCore/Modules/fetch/FetchBodySource.cpp (239643 => 239644)
--- trunk/Source/WebCore/Modules/fetch/FetchBodySource.cpp 2019-01-04 23:53:22 UTC (rev 239643)
+++ trunk/Source/WebCore/Modules/fetch/FetchBodySource.cpp 2019-01-05 00:01:43 UTC (rev 239644)
@@ -88,7 +88,7 @@
m_bodyOwner = nullptr;
}
-void FetchBodySource::error(const String& value)
+void FetchBodySource::error(const Exception& value)
{
controller().error(value);
clean();
Modified: trunk/Source/WebCore/Modules/fetch/FetchBodySource.h (239643 => 239644)
--- trunk/Source/WebCore/Modules/fetch/FetchBodySource.h 2019-01-04 23:53:22 UTC (rev 239643)
+++ trunk/Source/WebCore/Modules/fetch/FetchBodySource.h 2019-01-05 00:01:43 UTC (rev 239644)
@@ -44,7 +44,7 @@
bool enqueue(RefPtr<JSC::ArrayBuffer>&& chunk) { return controller().enqueue(WTFMove(chunk)); }
void close();
- void error(const String&);
+ void error(const Exception&);
bool isCancelling() const { return m_isCancelling; }
Modified: trunk/Source/WebCore/Modules/fetch/FetchRequest.cpp (239643 => 239644)
--- trunk/Source/WebCore/Modules/fetch/FetchRequest.cpp 2019-01-04 23:53:22 UTC (rev 239643)
+++ trunk/Source/WebCore/Modules/fetch/FetchRequest.cpp 2019-01-05 00:01:43 UTC (rev 239644)
@@ -159,6 +159,9 @@
if (optionsResult.hasException())
return optionsResult.releaseException();
+ if (init.signal && init.signal.value())
+ m_signal->follow(*init.signal.value());
+
if (init.headers) {
auto fillResult = m_headers->fill(*init.headers);
if (fillResult.hasException())
@@ -188,6 +191,12 @@
if (optionsResult.hasException())
return optionsResult.releaseException();
+ if (init.signal) {
+ if (init.signal.value())
+ m_signal->follow(*init.signal.value());
+ } else
+ m_signal->follow(input.m_signal);
+
if (init.headers) {
auto fillResult = m_headers->fill(*init.headers);
if (fillResult.hasException())
@@ -293,6 +302,7 @@
auto clone = adoptRef(*new FetchRequest(context, WTF::nullopt, FetchHeaders::create(m_headers.get()), ResourceRequest { m_request }, FetchOptions { m_options}, String { m_referrer }));
clone->cloneBody(*this);
+ clone->m_signal->follow(m_signal);
return WTFMove(clone);
}
Modified: trunk/Source/WebCore/Modules/fetch/FetchRequest.h (239643 => 239644)
--- trunk/Source/WebCore/Modules/fetch/FetchRequest.h 2019-01-04 23:53:22 UTC (rev 239643)
+++ trunk/Source/WebCore/Modules/fetch/FetchRequest.h 2019-01-05 00:01:43 UTC (rev 239644)
@@ -28,6 +28,7 @@
#pragma once
+#include "AbortSignal.h"
#include "ExceptionOr.h"
#include "FetchBodyOwner.h"
#include "FetchOptions.h"
@@ -68,6 +69,7 @@
Cache cache() const { return m_options.cache; }
Redirect redirect() const { return m_options.redirect; }
bool keepalive() const { return m_options.keepAlive; };
+ AbortSignal& signal() { return m_signal.get(); }
const String& integrity() const { return m_options.integrity; }
@@ -96,6 +98,7 @@
FetchOptions m_options;
String m_referrer;
mutable String m_requestURL;
+ Ref<AbortSignal> m_signal;
};
inline FetchRequest::FetchRequest(ScriptExecutionContext& context, Optional<FetchBody>&& body, Ref<FetchHeaders>&& headers, ResourceRequest&& request, FetchOptions&& options, String&& referrer)
@@ -103,6 +106,7 @@
, m_request(WTFMove(request))
, m_options(WTFMove(options))
, m_referrer(WTFMove(referrer))
+ , m_signal(AbortSignal::create(context))
{
updateContentType();
}
Modified: trunk/Source/WebCore/Modules/fetch/FetchRequest.idl (239643 => 239644)
--- trunk/Source/WebCore/Modules/fetch/FetchRequest.idl 2019-01-04 23:53:22 UTC (rev 239643)
+++ trunk/Source/WebCore/Modules/fetch/FetchRequest.idl 2019-01-05 00:01:43 UTC (rev 239644)
@@ -55,6 +55,7 @@
readonly attribute FetchRequestRedirect redirect;
readonly attribute DOMString integrity;
[EnabledAtRuntime=FetchAPIKeepAlive] readonly attribute boolean keepalive;
+ readonly attribute AbortSignal signal;
[CallWith=ScriptExecutionContext, MayThrowException, NewObject] FetchRequest clone();
};
Modified: trunk/Source/WebCore/Modules/fetch/FetchRequestInit.h (239643 => 239644)
--- trunk/Source/WebCore/Modules/fetch/FetchRequestInit.h 2019-01-04 23:53:22 UTC (rev 239643)
+++ trunk/Source/WebCore/Modules/fetch/FetchRequestInit.h 2019-01-05 00:01:43 UTC (rev 239644)
@@ -25,6 +25,7 @@
#pragma once
+#include "AbortSignal.h"
#include "FetchBody.h"
#include "FetchHeaders.h"
#include "FetchOptions.h"
@@ -46,9 +47,10 @@
Optional<FetchOptions::Redirect> redirect;
String integrity;
Optional<bool> keepalive;
+ Optional<AbortSignal*> signal;
JSC::JSValue window;
- bool hasMembers() const { return !method.isEmpty() || headers || body || !referrer.isEmpty() || referrerPolicy || mode || credentials || cache || redirect || !integrity.isEmpty() || keepalive || !window.isUndefined(); }
+ bool hasMembers() const { return !method.isEmpty() || headers || body || !referrer.isEmpty() || referrerPolicy || mode || credentials || cache || redirect || !integrity.isEmpty() || keepalive || !window.isUndefined() || signal; }
};
}
Modified: trunk/Source/WebCore/Modules/fetch/FetchRequestInit.idl (239643 => 239644)
--- trunk/Source/WebCore/Modules/fetch/FetchRequestInit.idl 2019-01-04 23:53:22 UTC (rev 239643)
+++ trunk/Source/WebCore/Modules/fetch/FetchRequestInit.idl 2019-01-05 00:01:43 UTC (rev 239644)
@@ -39,5 +39,6 @@
FetchRequestRedirect redirect;
DOMString integrity;
boolean keepalive;
+ AbortSignal? signal;
any window; // can only be set to null
};
Modified: trunk/Source/WebCore/Modules/fetch/FetchResponse.cpp (239643 => 239644)
--- trunk/Source/WebCore/Modules/fetch/FetchResponse.cpp 2019-01-04 23:53:22 UTC (rev 239643)
+++ trunk/Source/WebCore/Modules/fetch/FetchResponse.cpp 2019-01-05 00:01:43 UTC (rev 239644)
@@ -179,7 +179,6 @@
m_internalResponse.setHTTPHeaderFields(HTTPHeaderMap { headers().internalHeaders() });
auto clone = FetchResponse::create(context, WTF::nullopt, headers().guard(), ResourceResponse { m_internalResponse });
- clone->m_loadingError = m_loadingError;
clone->cloneBody(*this);
clone->m_opaqueLoadIdentifier = m_opaqueLoadIdentifier;
clone->m_bodySizeWithPadding = m_bodySizeWithPadding;
@@ -186,11 +185,48 @@
return WTFMove(clone);
}
+void FetchResponse::addAbortSteps(Ref<AbortSignal>&& signal)
+{
+ m_abortSignal = WTFMove(signal);
+ m_abortSignal->addAlgorithm([this, weakThis = makeWeakPtr(this)] {
+ // FIXME: Cancel request body if it is a stream.
+ if (!weakThis)
+ return;
+
+ m_abortSignal = nullptr;
+
+ setLoadingError(Exception { AbortError, "Fetch is aborted"_s });
+
+ if (m_bodyLoader) {
+ if (auto callback = m_bodyLoader->takeNotificationCallback())
+ callback(Exception { AbortError, "Fetch is aborted"_s });
+ }
+
+ if (m_readableStreamSource) {
+ if (!m_readableStreamSource->isCancelling())
+ m_readableStreamSource->error(*loadingException());
+ m_readableStreamSource = nullptr;
+ }
+ if (m_body)
+ m_body->loadingFailed(*loadingException());
+
+ if (m_bodyLoader) {
+ m_bodyLoader->stop();
+ m_bodyLoader = WTF::nullopt;
+ }
+ });
+}
+
void FetchResponse::fetch(ScriptExecutionContext& context, FetchRequest& request, NotificationCallback&& responseCallback)
{
+ if (request.signal().aborted()) {
+ responseCallback(Exception { AbortError, "Request signal is aborted"_s });
+ // FIXME: Cancel request body if it is a stream.
+ return;
+ }
+
if (request.hasReadableStreamBody()) {
- if (responseCallback)
- responseCallback(Exception { NotSupportedError, "ReadableStream uploading is not supported" });
+ responseCallback(Exception { NotSupportedError, "ReadableStream uploading is not supported"_s });
return;
}
auto response = adoptRef(*new FetchResponse(context, FetchBody { }, FetchHeaders::create(FetchHeaders::Guard::Immutable), { }));
@@ -197,6 +233,8 @@
response->body().consumer().setAsLoading();
+ response->addAbortSteps(request.signal());
+
response->m_bodyLoader.emplace(response.get(), WTFMove(responseCallback));
if (!response->m_bodyLoader->start(context, request))
response->m_bodyLoader = WTF::nullopt;
@@ -245,7 +283,7 @@
{
ASSERT(m_response.hasPendingActivity());
- m_response.m_loadingError = error;
+ m_response.setLoadingError(ResourceError { error });
if (auto responseCallback = WTFMove(m_responseCallback))
responseCallback(Exception { TypeError, error.localizedDescription() });
@@ -256,7 +294,7 @@
#if ENABLE(STREAMS_API)
if (m_response.m_readableStreamSource) {
if (!m_response.m_readableStreamSource->isCancelling())
- m_response.m_readableStreamSource->error(makeString("Loading failed: "_s, error.localizedDescription()));
+ m_response.m_readableStreamSource->error(*m_response.loadingException());
m_response.m_readableStreamSource = nullptr;
}
#endif
Modified: trunk/Source/WebCore/Modules/fetch/FetchResponse.h (239643 => 239644)
--- trunk/Source/WebCore/Modules/fetch/FetchResponse.h 2019-01-04 23:53:22 UTC (rev 239643)
+++ trunk/Source/WebCore/Modules/fetch/FetchResponse.h 2019-01-05 00:01:43 UTC (rev 239644)
@@ -33,6 +33,7 @@
#include "ReadableStreamSink.h"
#include "ResourceResponse.h"
#include <_javascript_Core/TypedArrays.h>
+#include <wtf/WeakPtr.h>
namespace JSC {
class ExecState;
@@ -41,11 +42,12 @@
namespace WebCore {
+class AbortSignal;
class FetchRequest;
struct ReadableStreamChunk;
class ReadableStreamSource;
-class FetchResponse final : public FetchBodyOwner {
+class FetchResponse final : public FetchBodyOwner, public CanMakeWeakPtr<FetchResponse> {
public:
using Type = ResourceResponse::Type;
@@ -107,8 +109,6 @@
void initializeOpaqueLoadIdentifierForTesting() { m_opaqueLoadIdentifier = 1; }
- const Optional<ResourceError>& loadingError() const { return m_loadingError; }
-
const HTTPHeaderMap& internalResponseHeaders() const { return m_internalResponse.httpHeaderFields(); }
private:
@@ -124,6 +124,8 @@
void closeStream();
#endif
+ void addAbortSteps(Ref<AbortSignal>&&);
+
class BodyLoader final : public FetchLoaderClient {
public:
BodyLoader(FetchResponse&, NotificationCallback&&);
@@ -137,6 +139,7 @@
#if ENABLE(STREAMS_API)
RefPtr<SharedBuffer> startStreaming();
#endif
+ NotificationCallback takeNotificationCallback() { return WTFMove(m_responseCallback); }
private:
// FetchLoaderClient API
@@ -158,6 +161,7 @@
// Opaque responses will padd their body size when used with Cache API.
uint64_t m_bodySizeWithPadding { 0 };
uint64_t m_opaqueLoadIdentifier { 0 };
+ RefPtr<AbortSignal> m_abortSignal;
};
} // namespace WebCore
Modified: trunk/Source/WebCore/bindings/js/ReadableStreamDefaultController.h (239643 => 239644)
--- trunk/Source/WebCore/bindings/js/ReadableStreamDefaultController.h 2019-01-04 23:53:22 UTC (rev 239643)
+++ trunk/Source/WebCore/bindings/js/ReadableStreamDefaultController.h 2019-01-05 00:01:43 UTC (rev 239644)
@@ -49,8 +49,7 @@
bool enqueue(RefPtr<JSC::ArrayBuffer>&&);
- template<class ResolveResultType>
- void error(const ResolveResultType&);
+ void error(const Exception&);
void close() { invoke(*globalObject().globalExec(), jsController(), "close", JSC::jsUndefined()); }
@@ -104,12 +103,11 @@
return true;
}
-template<>
-inline void ReadableStreamDefaultController::error<String>(const String& errorMessage)
+inline void ReadableStreamDefaultController::error(const Exception& exception)
{
JSC::ExecState& state = globalExec();
JSC::JSLockHolder locker(&state);
- error(state, JSC::createTypeError(&state, errorMessage));
+ error(state, createDOMException(&state, exception.code(), exception.message()));
}
} // namespace WebCore
Modified: trunk/Source/WebCore/dom/AbortSignal.cpp (239643 => 239644)
--- trunk/Source/WebCore/dom/AbortSignal.cpp 2019-01-04 23:53:22 UTC (rev 239643)
+++ trunk/Source/WebCore/dom/AbortSignal.cpp 2019-01-05 00:01:43 UTC (rev 239644)
@@ -37,7 +37,6 @@
return adoptRef(*new AbortSignal(context));
}
-
AbortSignal::AbortSignal(ScriptExecutionContext& context)
: ContextDestructionObserver(&context)
{
@@ -52,13 +51,32 @@
// 2. Set signal’s aborted flag.
m_aborted = true;
-
- // 3. For each algorithm in signal's abort algorithms: run algorithm.
- // 4. Empty signal's abort algorithms.
- // FIXME: Add support for 'abort algorithms' - https://dom.spec.whatwg.org/#abortsignal-abort-algorithms
+ auto protectedThis = makeRef(*this);
+ auto algorithms = WTFMove(m_algorithms);
+ for (auto& algorithm : algorithms)
+ algorithm();
+
// 5. Fire an event named abort at signal.
dispatchEvent(Event::create(eventNames().abortEvent, Event::CanBubble::No, Event::IsCancelable::No));
}
+// https://dom.spec.whatwg.org/#abortsignal-follow
+void AbortSignal::follow(AbortSignal& signal)
+{
+ if (aborted())
+ return;
+
+ if (signal.aborted()) {
+ abort();
+ return;
+ }
+
+ signal.addAlgorithm([weakThis = makeWeakPtr(this)] {
+ if (!weakThis)
+ return;
+ weakThis->abort();
+ });
}
+
+}
Modified: trunk/Source/WebCore/dom/AbortSignal.h (239643 => 239644)
--- trunk/Source/WebCore/dom/AbortSignal.h 2019-01-04 23:53:22 UTC (rev 239643)
+++ trunk/Source/WebCore/dom/AbortSignal.h 2019-01-05 00:01:43 UTC (rev 239644)
@@ -27,14 +27,16 @@
#include "ContextDestructionObserver.h"
#include "EventTarget.h"
+#include <wtf/Function.h>
#include <wtf/Ref.h>
#include <wtf/RefCounted.h>
+#include <wtf/WeakPtr.h>
namespace WebCore {
class ScriptExecutionContext;
-class AbortSignal final : public RefCounted<AbortSignal>, public EventTargetWithInlineData, private ContextDestructionObserver {
+class AbortSignal final : public RefCounted<AbortSignal>, public EventTargetWithInlineData, public CanMakeWeakPtr<AbortSignal>, private ContextDestructionObserver {
public:
static Ref<AbortSignal> create(ScriptExecutionContext&);
@@ -45,6 +47,11 @@
using RefCounted::ref;
using RefCounted::deref;
+ using Algorithm = WTF::Function<void()>;
+ void addAlgorithm(Algorithm&& algorithm) { m_algorithms.append(WTFMove(algorithm)); }
+
+ void follow(AbortSignal&);
+
private:
explicit AbortSignal(ScriptExecutionContext&);
@@ -54,6 +61,7 @@
void derefEventTarget() final { deref(); }
bool m_aborted { false };
+ Vector<Algorithm> m_algorithms;
};
}
Modified: trunk/Source/WebCore/workers/service/context/ServiceWorkerFetch.cpp (239643 => 239644)
--- trunk/Source/WebCore/workers/service/context/ServiceWorkerFetch.cpp 2019-01-04 23:53:22 UTC (rev 239643)
+++ trunk/Source/WebCore/workers/service/context/ServiceWorkerFetch.cpp 2019-01-05 00:01:43 UTC (rev 239644)
@@ -53,8 +53,9 @@
client->didReceiveResponse(response->resourceResponse());
- if (response->loadingError()) {
- client->didFail(*response->loadingError());
+ auto loadingError = response->loadingError();
+ if (!loadingError.isNull()) {
+ client->didFail(loadingError);
return;
}