Skip to content

Commit 6698402

Browse files
committed
[Fetch API] Implement abortable fetch
https://bugs.webkit.org/show_bug.cgi?id=174980 <rdar://problem/46861402> Reviewed by Chris Dumez. LayoutTests/imported/w3c: 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: Source/WebCore: 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: LayoutTests: * TestExpectations: Enable abort tests. Canonical link: https://commits.webkit.org/207672@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@239644 268f45cc-cd09-0410-ab3c-d52691b4dbfc
1 parent fd1c016 commit 6698402

32 files changed

Lines changed: 420 additions & 165 deletions

LayoutTests/ChangeLog

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,13 @@
1+
2019-01-04 Youenn Fablet <[email protected]>
2+
3+
[Fetch API] Implement abortable fetch
4+
https://bugs.webkit.org/show_bug.cgi?id=174980
5+
<rdar://problem/46861402>
6+
7+
Reviewed by Chris Dumez.
8+
9+
* TestExpectations: Enable abort tests.
10+
111
2019-01-04 Brent Fulgham <[email protected]>
212

313
Parsed protocol of javascript URLs with embedded newlines and carriage returns do not match parsed protocol in Chrome and Firefox

LayoutTests/TestExpectations

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,6 @@ imported/w3c/web-platform-tests/service-workers/service-worker/worker-client-id.
211211
imported/w3c/web-platform-tests/cors/remote-origin.htm [ Skip ]
212212

213213
# Skip service worker tests that are timing out.
214-
imported/w3c/web-platform-tests/fetch/api/abort/general-serviceworker.https.html [ Skip ]
215214
imported/w3c/web-platform-tests/service-workers/service-worker/performance-timeline.https.html [ Skip ]
216215
imported/w3c/web-platform-tests/service-workers/service-worker/respond-with-body-accessed-response.https.html [ Skip ]
217216
imported/w3c/web-platform-tests/service-workers/service-worker/sandboxed-iframe-fetch-event.https.html [ Skip ]
@@ -383,10 +382,6 @@ webkit.org/b/189905 imported/w3c/web-platform-tests/resource-timing/resource_ini
383382
webkit.org/b/189910 imported/w3c/web-platform-tests/resource-timing/resource_timing_store_and_clear_during_callback.html [ Pass Failure ]
384383
webkit.org/b/190523 imported/w3c/web-platform-tests/resource-timing/resource_timing_cross_origin_redirect_chain.html [ Pass Failure ]
385384

386-
# The follow two tests change their output each run
387-
imported/w3c/web-platform-tests/fetch/api/abort/general.any.html [ Skip ]
388-
imported/w3c/web-platform-tests/fetch/api/abort/general.any.worker.html [ Skip ]
389-
390385
# These tests time out
391386
imported/w3c/web-platform-tests/fetch/api/request/destination/fetch-destination-no-load-event.https.html [ Skip ]
392387
imported/w3c/web-platform-tests/fetch/api/request/destination/fetch-destination.https.html [ Skip ]

LayoutTests/imported/w3c/ChangeLog

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,22 @@
1+
2019-01-04 Youenn Fablet <[email protected]>
2+
3+
[Fetch API] Implement abortable fetch
4+
https://bugs.webkit.org/show_bug.cgi?id=174980
5+
<rdar://problem/46861402>
6+
7+
Reviewed by Chris Dumez.
8+
9+
Fixed tests to run in WebKit CI.
10+
Also fixed a bug in a test where the fetch response body is not actually empty.
11+
12+
* web-platform-tests/fetch/api/abort/cache.https-expected.txt:
13+
* web-platform-tests/fetch/api/abort/general-serviceworker.https-expected.txt:
14+
* web-platform-tests/fetch/api/abort/general.any-expected.txt:
15+
* web-platform-tests/fetch/api/abort/general.any.js:
16+
* web-platform-tests/fetch/api/abort/general.any.worker-expected.txt:
17+
* web-platform-tests/fetch/api/abort/serviceworker-intercepted.https-expected.txt:
18+
* web-platform-tests/fetch/api/response/response-consume-stream-expected.txt:
19+
120
2019-01-02 Simon Fraser <[email protected]>
221

322
Support css-color-4 rgb functions
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11

2-
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')"
3-
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')"
2+
PASS Signals are not stored in the cache API
3+
PASS Signals are not stored in the cache API, even if they're already aborted
44

Lines changed: 30 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11

2-
Harness Error (TIMEOUT), message = null
3-
4-
FAIL Aborting rejects with AbortError assert_unreached: Should have rejected: undefined Reached unreachable code
5-
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
2+
PASS Aborting rejects with AbortError
3+
PASS Aborting rejects with AbortError - no-cors
64
PASS TypeError from request constructor takes priority - RequestInit's window is not null
75
PASS TypeError from request constructor takes priority - Input URL is not valid
86
PASS TypeError from request constructor takes priority - Input URL has credentials
@@ -19,34 +17,34 @@ PASS TypeError from request constructor takes priority - Bad mode init parameter
1917
PASS TypeError from request constructor takes priority - Bad credentials init parameter value
2018
PASS TypeError from request constructor takes priority - Bad cache init parameter value
2119
PASS TypeError from request constructor takes priority - Bad redirect init parameter value
22-
FAIL Request objects have a signal property assert_true: Signal member is present & truthy expected true got false
23-
FAIL Signal on request object assert_true: Signal member is present & truthy expected true got false
24-
FAIL Signal on request object created from request object assert_unreached: Should have rejected: undefined Reached unreachable code
25-
FAIL Signal on request object created from request object, with signal on second request assert_unreached: Should have rejected: undefined Reached unreachable code
26-
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
27-
FAIL Signal retained after unrelated properties are overridden by fetch assert_unreached: Should have rejected: undefined Reached unreachable code
20+
PASS Request objects have a signal property
21+
PASS Signal on request object
22+
PASS Signal on request object created from request object
23+
PASS Signal on request object created from request object, with signal on second request
24+
PASS Signal on request object created from request object, with signal on second request overriding another
25+
PASS Signal retained after unrelated properties are overridden by fetch
2826
PASS Signal removed by setting to null
29-
FAIL Already aborted signal rejects immediately assert_unreached: Fetch must not resolve Reached unreachable code
27+
PASS Already aborted signal rejects immediately
3028
PASS Request is still 'used' if signal is aborted before fetching
31-
FAIL response.arrayBuffer() rejects if already aborted assert_unreached: Should have rejected: undefined Reached unreachable code
32-
FAIL response.blob() rejects if already aborted assert_unreached: Should have rejected: undefined Reached unreachable code
33-
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
34-
FAIL response.json() rejects if already aborted assert_unreached: Should have rejected: undefined Reached unreachable code
35-
FAIL response.text() rejects if already aborted assert_unreached: Should have rejected: undefined Reached unreachable code
36-
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"
37-
FAIL Already aborted signal can be used for many fetches assert_unreached: Should have rejected: undefined Reached unreachable code
38-
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
39-
FAIL Underlying connection is closed when aborting after receiving response promise_test: Unhandled rejection with value: object "Error: Timed out"
40-
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."
41-
TIMEOUT Fetch aborted & connection closed when aborted after calling response.arrayBuffer() Test timed out
42-
NOTRUN Fetch aborted & connection closed when aborted after calling response.blob()
43-
NOTRUN Fetch aborted & connection closed when aborted after calling response.formData()
44-
NOTRUN Fetch aborted & connection closed when aborted after calling response.json()
45-
NOTRUN Fetch aborted & connection closed when aborted after calling response.text()
46-
NOTRUN Stream errors once aborted. Underlying connection closed.
47-
NOTRUN Stream errors once aborted, after reading. Underlying connection closed.
48-
NOTRUN Stream will not error if body is empty. It's closed with an empty queue before it errors.
49-
NOTRUN Readable stream synchronously cancels with AbortError if aborted before reading
50-
FAIL Signal state is cloned undefined is not an object (evaluating 'request.signal.aborted')
51-
FAIL Clone aborts with original controller undefined is not an object (evaluating 'request.signal.addEventListener')
29+
PASS response.arrayBuffer() rejects if already aborted
30+
PASS response.blob() rejects if already aborted
31+
PASS response.formData() rejects if already aborted
32+
PASS response.json() rejects if already aborted
33+
PASS response.text() rejects if already aborted
34+
PASS Already aborted signal does not make request
35+
PASS Already aborted signal can be used for many fetches
36+
PASS Signal can be used to abort other fetches, even if another fetch succeeded before aborting
37+
PASS Underlying connection is closed when aborting after receiving response
38+
PASS Underlying connection is closed when aborting after receiving response - no-cors
39+
PASS Fetch aborted & connection closed when aborted after calling response.arrayBuffer()
40+
PASS Fetch aborted & connection closed when aborted after calling response.blob()
41+
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
42+
PASS Fetch aborted & connection closed when aborted after calling response.json()
43+
PASS Fetch aborted & connection closed when aborted after calling response.text()
44+
PASS Stream errors once aborted. Underlying connection closed.
45+
PASS Stream errors once aborted, after reading. Underlying connection closed.
46+
PASS Stream will not error if body is empty. It's closed with an empty queue before it errors.
47+
FAIL Readable stream synchronously cancels with AbortError if aborted before reading assert_true: Cancel called sync expected true got false
48+
PASS Signal state is cloned
49+
PASS Clone aborts with original controller
5250

Lines changed: 31 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,7 @@
1-
Blocked access to external URL http://www1.localhost:8800/fetch/api/resources/data.json
2-
CONSOLE MESSAGE: line 36: Fetch API cannot load http://www1.localhost:8800/fetch/api/resources/data.json due to access control checks.
3-
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
4-
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.
1+
CONSOLE MESSAGE: Unhandled Promise Rejection: AbortError: Request signal is aborted
52

6-
Harness Error (TIMEOUT), message = null
7-
8-
FAIL Aborting rejects with AbortError assert_unreached: Should have rejected: undefined Reached unreachable code
9-
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
3+
PASS Aborting rejects with AbortError
4+
PASS Aborting rejects with AbortError - no-cors
105
PASS TypeError from request constructor takes priority - RequestInit's window is not null
116
PASS TypeError from request constructor takes priority - Input URL is not valid
127
PASS TypeError from request constructor takes priority - Input URL has credentials
@@ -15,7 +10,6 @@ PASS TypeError from request constructor takes priority - RequestInit's referrer
1510
PASS TypeError from request constructor takes priority - RequestInit's method is invalid
1611
PASS TypeError from request constructor takes priority - RequestInit's method is forbidden
1712
PASS TypeError from request constructor takes priority - RequestInit's mode is no-cors and method is not simple
18-
PASS TypeError from request constructor takes priority - RequestInit's mode is no-cors and integrity is not empty
1913
PASS TypeError from request constructor takes priority - RequestInit's cache mode is only-if-cached and mode is not same-origin
2014
PASS TypeError from request constructor takes priority - Request with cache mode: only-if-cached and fetch mode cors
2115
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 mode init parameter
2418
PASS TypeError from request constructor takes priority - Bad credentials init parameter value
2519
PASS TypeError from request constructor takes priority - Bad cache init parameter value
2620
PASS TypeError from request constructor takes priority - Bad redirect init parameter value
27-
FAIL Request objects have a signal property assert_true: Signal member is present & truthy expected true got false
28-
FAIL Signal on request object assert_true: Signal member is present & truthy expected true got false
29-
FAIL Signal on request object created from request object assert_unreached: Should have rejected: undefined Reached unreachable code
30-
FAIL Signal on request object created from request object, with signal on second request assert_unreached: Should have rejected: undefined Reached unreachable code
31-
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
32-
FAIL Signal retained after unrelated properties are overridden by fetch assert_unreached: Should have rejected: undefined Reached unreachable code
21+
PASS Request objects have a signal property
22+
PASS Signal on request object
23+
PASS Signal on request object created from request object
24+
PASS Signal on request object created from request object, with signal on second request
25+
PASS Signal on request object created from request object, with signal on second request overriding another
26+
PASS Signal retained after unrelated properties are overridden by fetch
3327
PASS Signal removed by setting to null
34-
FAIL Already aborted signal rejects immediately assert_unreached: Fetch must not resolve Reached unreachable code
28+
PASS Already aborted signal rejects immediately
3529
PASS Request is still 'used' if signal is aborted before fetching
36-
FAIL response.arrayBuffer() rejects if already aborted assert_unreached: Should have rejected: undefined Reached unreachable code
37-
FAIL response.blob() rejects if already aborted assert_unreached: Should have rejected: undefined Reached unreachable code
38-
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
39-
FAIL response.json() rejects if already aborted assert_unreached: Should have rejected: undefined Reached unreachable code
40-
FAIL response.text() rejects if already aborted assert_unreached: Should have rejected: undefined Reached unreachable code
41-
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"
42-
FAIL Already aborted signal can be used for many fetches assert_unreached: Should have rejected: undefined Reached unreachable code
43-
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
44-
FAIL Underlying connection is closed when aborting after receiving response promise_test: Unhandled rejection with value: object "Error: Timed out"
45-
FAIL Underlying connection is closed when aborting after receiving response - no-cors promise_test: Unhandled rejection with value: object "TypeError: Type error"
46-
TIMEOUT Fetch aborted & connection closed when aborted after calling response.arrayBuffer() Test timed out
47-
NOTRUN Fetch aborted & connection closed when aborted after calling response.blob()
48-
NOTRUN Fetch aborted & connection closed when aborted after calling response.formData()
49-
NOTRUN Fetch aborted & connection closed when aborted after calling response.json()
50-
NOTRUN Fetch aborted & connection closed when aborted after calling response.text()
51-
NOTRUN Stream errors once aborted. Underlying connection closed.
52-
NOTRUN Stream errors once aborted, after reading. Underlying connection closed.
53-
NOTRUN Stream will not error if body is empty. It's closed with an empty queue before it errors.
54-
NOTRUN Readable stream synchronously cancels with AbortError if aborted before reading
55-
FAIL Signal state is cloned undefined is not an object (evaluating 'request.signal.aborted')
56-
FAIL Clone aborts with original controller undefined is not an object (evaluating 'request.signal.addEventListener')
30+
PASS response.arrayBuffer() rejects if already aborted
31+
PASS response.blob() rejects if already aborted
32+
PASS response.formData() rejects if already aborted
33+
PASS response.json() rejects if already aborted
34+
PASS response.text() rejects if already aborted
35+
PASS Already aborted signal does not make request
36+
PASS Already aborted signal can be used for many fetches
37+
PASS Signal can be used to abort other fetches, even if another fetch succeeded before aborting
38+
PASS Underlying connection is closed when aborting after receiving response
39+
PASS Underlying connection is closed when aborting after receiving response - no-cors
40+
PASS Fetch aborted & connection closed when aborted after calling response.arrayBuffer()
41+
PASS Fetch aborted & connection closed when aborted after calling response.blob()
42+
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
43+
PASS Fetch aborted & connection closed when aborted after calling response.json()
44+
PASS Fetch aborted & connection closed when aborted after calling response.text()
45+
PASS Stream errors once aborted. Underlying connection closed.
46+
PASS Stream errors once aborted, after reading. Underlying connection closed.
47+
PASS Stream will not error if body is empty. It's closed with an empty queue before it errors.
48+
FAIL Readable stream synchronously cancels with AbortError if aborted before reading assert_true: Cancel called sync expected true got false
49+
PASS Signal state is cloned
50+
PASS Clone aborts with original controller
5751

0 commit comments

Comments
 (0)