Commit 8981b0bd authored by Rayan Kanso's avatar Rayan Kanso Committed by Commit Bot

[Background Fetch] Throw DOMException for responseReady on abort.

According to the spec, responseReady in BackgroundFetchRecord should
throw an AbortError DOMException if the fetch was abandoned.

https://wicg.github.io/background-fetch/#create-record-objects (2.4.3)

Change-Id: Ieadf278acd061e05b8822014d0934f050fcac702
Reviewed-on: https://chromium-review.googlesource.com/c/1283692
Commit-Queue: Rayan Kanso <rayankans@chromium.org>
Reviewed-by: default avatarPeter Beverloo <peter@chromium.org>
Cr-Commit-Position: refs/heads/master@{#600769}
parent ac0b91e2
...@@ -59,4 +59,16 @@ backgroundFetchTest(async (test, backgroundFetch) => { ...@@ -59,4 +59,16 @@ backgroundFetchTest(async (test, backgroundFetch) => {
}; };
}); });
}, 'Calling BackgroundFetchRegistration.abort sets the correct fields and responses are still available'); }, 'Calling BackgroundFetchRegistration.abort sets the correct fields and responses are still available');
\ No newline at end of file
backgroundFetchTest(async (test, backgroundFetch) => {
const registration = await backgroundFetch.fetch(
uniqueId(), '/serviceworker/resources/slow-response.php');
assert_true(await registration.abort());
const {results} = await getMessageFromServiceWorker();
assert_equals(results.length, 1);
assert_false(results[0].response);
assert_equals(results[0].name, 'AbortError');
}, 'An aborted fetch throws a DOM exception when accessing an incomplete record', 'sw-abort.js');
\ No newline at end of file
importScripts('sw-helpers.js');
async function getFetchResult(record) {
try {
await record.responseReady;
} catch (e) {
return {
response: false,
name: e.name,
};
}
return {
response: true,
};
}
self.addEventListener('backgroundfetchabort', event => {
event.waitUntil(
event.registration.matchAll()
.then(records =>
Promise.all(records.map(record => getFetchResult(record))))
.then(results => sendMessageToDocument({results})));
});
...@@ -10,8 +10,9 @@ ...@@ -10,8 +10,9 @@
namespace blink { namespace blink {
BackgroundFetchRecord::BackgroundFetchRecord(Request* request, BackgroundFetchRecord::BackgroundFetchRecord(Request* request,
Response* response) Response* response,
: request_(request), response_(response) { bool aborted)
: request_(request), response_(response), aborted_(aborted) {
DCHECK(request_); DCHECK(request_);
} }
...@@ -23,15 +24,25 @@ ScriptPromise BackgroundFetchRecord::responseReady(ScriptState* script_state) { ...@@ -23,15 +24,25 @@ ScriptPromise BackgroundFetchRecord::responseReady(ScriptState* script_state) {
new ResponseReadyProperty(ExecutionContext::From(script_state), this, new ResponseReadyProperty(ExecutionContext::From(script_state), this,
ResponseReadyProperty::kResponseReady); ResponseReadyProperty::kResponseReady);
} }
if (!response_) {
return ScriptPromise::Reject( if (response_) {
DCHECK(response_);
response_ready_property_->Resolve(response_);
return response_ready_property_->Promise(script_state->World());
}
if (aborted_) {
return ScriptPromise::RejectWithDOMException(
script_state, script_state,
V8ThrowException::CreateTypeError(script_state->GetIsolate(), DOMException::Create(
"The response is not available.")); DOMExceptionCode::kAbortError,
"The fetch was aborted before the record was processed."));
} }
DCHECK(response_);
response_ready_property_->Resolve(response_); return ScriptPromise::Reject(
return response_ready_property_->Promise(script_state->World()); script_state,
V8ThrowException::CreateTypeError(script_state->GetIsolate(),
"The response is not available."));
} }
Request* BackgroundFetchRecord::request() const { Request* BackgroundFetchRecord::request() const {
......
...@@ -21,8 +21,7 @@ class MODULES_EXPORT BackgroundFetchRecord final : public ScriptWrappable { ...@@ -21,8 +21,7 @@ class MODULES_EXPORT BackgroundFetchRecord final : public ScriptWrappable {
DEFINE_WRAPPERTYPEINFO(); DEFINE_WRAPPERTYPEINFO();
public: public:
explicit BackgroundFetchRecord(Request* request, BackgroundFetchRecord(Request* request, Response* response, bool aborted);
Response* response = nullptr);
~BackgroundFetchRecord() override; ~BackgroundFetchRecord() override;
Request* request() const; Request* request() const;
...@@ -38,6 +37,9 @@ class MODULES_EXPORT BackgroundFetchRecord final : public ScriptWrappable { ...@@ -38,6 +37,9 @@ class MODULES_EXPORT BackgroundFetchRecord final : public ScriptWrappable {
Member<Request> request_; Member<Request> request_;
Member<Response> response_; Member<Response> response_;
Member<ResponseReadyProperty> response_ready_property_; Member<ResponseReadyProperty> response_ready_property_;
// Whether this record belongs to a fetch that was aborted.
bool aborted_;
}; };
} // namespace blink } // namespace blink
......
...@@ -238,11 +238,19 @@ void BackgroundFetchRegistration::DidGetMatchingRequests( ...@@ -238,11 +238,19 @@ void BackgroundFetchRegistration::DidGetMatchingRequests(
HeapVector<Member<BackgroundFetchRecord>> to_return; HeapVector<Member<BackgroundFetchRecord>> to_return;
to_return.ReserveInitialCapacity(settled_fetches.size()); to_return.ReserveInitialCapacity(settled_fetches.size());
for (const auto& fetch : settled_fetches) { for (const auto& fetch : settled_fetches) {
BackgroundFetchRecord* record = new BackgroundFetchRecord( Request* request = Request::Create(script_state, fetch->request);
Request::Create(script_state, fetch->request),
fetch->response ? Response::Create(script_state, *fetch->response) Response* response = fetch->response
: nullptr); ? Response::Create(script_state, *fetch->response)
to_return.push_back(record); : nullptr;
bool aborted =
failure_reason_ ==
mojom::BackgroundFetchFailureReason::CANCELLED_FROM_UI ||
failure_reason_ ==
mojom::BackgroundFetchFailureReason::CANCELLED_BY_DEVELOPER;
to_return.push_back(new BackgroundFetchRecord(request, response, aborted));
} }
if (!return_all) { if (!return_all) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment