Diff
Modified: trunk/LayoutTests/imported/w3c/ChangeLog (287914 => 287915)
--- trunk/LayoutTests/imported/w3c/ChangeLog 2022-01-12 08:51:26 UTC (rev 287914)
+++ trunk/LayoutTests/imported/w3c/ChangeLog 2022-01-12 09:44:27 UTC (rev 287915)
@@ -1,3 +1,18 @@
+2022-01-12 Youenn Fablet <you...@apple.com>
+
+ New service worker API 'FetchEvent.handled' needs to be supported
+ https://bugs.webkit.org/show_bug.cgi?id=208185
+ <rdar://problem/59808975>
+
+ Reviewed by Chris Dumez.
+
+ * web-platform-tests/service-workers/service-worker/fetch-event-handled.https-expected.txt:
+ * web-platform-tests/service-workers/service-worker/fetch-event-handled.https.html:
+ * web-platform-tests/service-workers/service-worker/resources/fetch-event-handled-worker.js:
+ (try.event.handled.then):
+ (catch):
+ (send_message_to_client): Deleted.
+
2021-11-29 Simon Fraser <simon.fra...@apple.com>
Serialize CSS <number> values with rounding, limited decimal precision, and no exponents per-spec
Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/service-workers/service-worker/fetch-event-handled.https-expected.txt (287914 => 287915)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/service-workers/service-worker/fetch-event-handled.https-expected.txt 2022-01-12 08:51:26 UTC (rev 287914)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/service-workers/service-worker/fetch-event-handled.https-expected.txt 2022-01-12 09:44:27 UTC (rev 287915)
@@ -1,13 +1,10 @@
-
-Harness Error (TIMEOUT), message = null
-
PASS global setup
-TIMEOUT FetchEvent.handled should resolve when respondWith() is not called for a navigation request Test timed out
-NOTRUN FetchEvent.handled should resolve when respondWith() is not called for a sub-resource request
-NOTRUN FetchEvent.handled should reject when respondWith() is not called and the event is canceled
-NOTRUN FetchEvent.handled should resolve when the promise provided to respondWith() is resolved
-NOTRUN FetchEvent.handled should reject when the promise provided to respondWith() is resolved to an invalid response
-NOTRUN FetchEvent.handled should reject when the promise provided to respondWith() is rejected
-NOTRUN global cleanup
+PASS FetchEvent.handled should resolve when respondWith() is not called for a navigation request
+PASS FetchEvent.handled should resolve when respondWith() is not called for a sub-resource request
+PASS FetchEvent.handled should reject when respondWith() is not called and the event is canceled
+PASS FetchEvent.handled should resolve when the promise provided to respondWith() is resolved
+PASS FetchEvent.handled should reject when the promise provided to respondWith() is resolved to an invalid response
+PASS FetchEvent.handled should reject when the promise provided to respondWith() is rejected
+PASS global cleanup
Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/service-workers/service-worker/fetch-event-handled.https.html (287914 => 287915)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/service-workers/service-worker/fetch-event-handled.https.html 2022-01-12 08:51:26 UTC (rev 287914)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/service-workers/service-worker/fetch-event-handled.https.html 2022-01-12 09:44:27 UTC (rev 287915)
@@ -10,18 +10,11 @@
let worker = null;
const script = 'resources/fetch-event-handled-worker.js';
const scope = 'resources/simple.html';
+const channel = new MessageChannel();
// Wait for a message from the service worker and removes the message handler.
function wait_for_message_from_worker() {
- return new Promise((resolve) => {
- const handler = (event) => {
- frame.contentWindow.navigator.serviceWorker.removeEventListener(
- 'message', handler);
- resolve(event.data);
- };
- frame.contentWindow.navigator.serviceWorker.addEventListener(
- 'message', handler);
- });
+ return new Promise((resolve) => channel.port2._onmessage_ = (event) => resolve(event.data));
}
// Global setup: this must be the first promise_test.
@@ -29,12 +22,16 @@
const registration =
await service_worker_unregister_and_register(t, script, scope);
worker = registration.installing;
+ if (!worker)
+ worker = registration.active;
+ worker.postMessage({port:channel.port1}, [channel.port1]);
await wait_for_state(t, worker, 'activated');
}, 'global setup');
promise_test(async (t) => {
- frame = await with_iframe(scope);
+ const promise = with_iframe(scope);
const message = await wait_for_message_from_worker();
+ frame = await promise;
assert_equals(message, 'RESOLVED');
}, 'FetchEvent.handled should resolve when respondWith() is not called for a' +
' navigation request');
Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/service-workers/service-worker/resources/fetch-event-handled-worker.js (287914 => 287915)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/service-workers/service-worker/resources/fetch-event-handled-worker.js 2022-01-12 08:51:26 UTC (rev 287914)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/service-workers/service-worker/resources/fetch-event-handled-worker.js 2022-01-12 09:44:27 UTC (rev 287915)
@@ -1,25 +1,19 @@
// This worker reports back the final state of FetchEvent.handled (RESOLVED or
// REJECTED) to the test.
-// Send a message to the client with the client id.
-function send_message_to_client(message, clientId) {
- clients.get(clientId).then((client) => {
- client.postMessage(message);
- });
-}
+self.addEventListener('message', function(event) {
+ self.port = event.data.port;
+});
self.addEventListener('fetch', function(event) {
- const clientId = (event.request.mode === 'navigate') ?
- event.resultingClientId : event.clientId;
-
try {
event.handled.then(() => {
- send_message_to_client('RESOLVED', clientId);
+ self.port.postMessage('RESOLVED');
}, () => {
- send_message_to_client('REJECTED', clientId);
+ self.port.postMessage('REJECTED');
});
} catch (e) {
- send_message_to_client('FAILED', clientId);
+ self.port.postMessage('FAILED');
return;
}
Modified: trunk/Source/WebCore/ChangeLog (287914 => 287915)
--- trunk/Source/WebCore/ChangeLog 2022-01-12 08:51:26 UTC (rev 287914)
+++ trunk/Source/WebCore/ChangeLog 2022-01-12 09:44:27 UTC (rev 287915)
@@ -1,3 +1,25 @@
+2022-01-12 Youenn Fablet <you...@apple.com>
+
+ New service worker API 'FetchEvent.handled' needs to be supported
+ https://bugs.webkit.org/show_bug.cgi?id=208185
+ <rdar://problem/59808975>
+
+ Reviewed by Chris Dumez.
+
+ Expose FetchEvent.handled and resolve/reject it as per specification.
+
+ Covered by test that we update to not rely on clientIds that we do not support very well.
+
+ * workers/service/FetchEvent.cpp:
+ (WebCore::FetchEvent::createForTesting):
+ (WebCore::retrieveHandledPromise):
+ (WebCore::FetchEvent::FetchEvent):
+ * workers/service/FetchEvent.h:
+ * workers/service/FetchEvent.idl:
+ * workers/service/context/ServiceWorkerFetch.cpp:
+ (WebCore::ServiceWorkerFetch::processResponse):
+ (WebCore::ServiceWorkerFetch::dispatchFetchEvent):
+
2022-01-12 Frédéric Wang <fw...@igalia.com>
Protect DocumentLoader when a reference to its members is used.
Modified: trunk/Source/WebCore/workers/service/FetchEvent.cpp (287914 => 287915)
--- trunk/Source/WebCore/workers/service/FetchEvent.cpp 2022-01-12 08:51:26 UTC (rev 287914)
+++ trunk/Source/WebCore/workers/service/FetchEvent.cpp 2022-01-12 09:44:27 UTC (rev 287915)
@@ -42,15 +42,28 @@
{
FetchEvent::Init init;
init.request = FetchRequest::create(context, { }, FetchHeaders::create(FetchHeaders::Guard::Immutable, { }), { }, { }, { });
- return FetchEvent::create("fetch", WTFMove(init), Event::IsTrusted::Yes);
+ return FetchEvent::create(*context.globalObject(), "fetch", WTFMove(init), Event::IsTrusted::Yes);
}
-FetchEvent::FetchEvent(const AtomString& type, Init&& initializer, IsTrusted isTrusted)
+static inline Ref<DOMPromise> retrieveHandledPromise(JSC::JSGlobalObject& globalObject, RefPtr<DOMPromise>&& promise)
+{
+ if (promise)
+ return promise.releaseNonNull();
+
+ JSC::JSLockHolder lock(globalObject.vm());
+
+ auto& jsDOMGlobalObject = *JSC::jsCast<JSDOMGlobalObject*>(&globalObject);
+ auto deferredPromise = DeferredPromise::create(jsDOMGlobalObject);
+ return DOMPromise::create(jsDOMGlobalObject, *JSC::jsCast<JSC::JSPromise*>(deferredPromise->promise()));
+}
+
+FetchEvent::FetchEvent(JSC::JSGlobalObject& globalObject, const AtomString& type, Init&& initializer, IsTrusted isTrusted)
: ExtendableEvent(type, initializer, isTrusted)
, m_request(initializer.request.releaseNonNull())
, m_clientId(WTFMove(initializer.clientId))
, m_reservedClientId(WTFMove(initializer.reservedClientId))
, m_targetClientId(WTFMove(initializer.targetClientId))
+ , m_handled(retrieveHandledPromise(globalObject, WTFMove(initializer.handled)))
{
}
Modified: trunk/Source/WebCore/workers/service/FetchEvent.h (287914 => 287915)
--- trunk/Source/WebCore/workers/service/FetchEvent.h 2022-01-12 08:51:26 UTC (rev 287914)
+++ trunk/Source/WebCore/workers/service/FetchEvent.h 2022-01-12 09:44:27 UTC (rev 287915)
@@ -33,8 +33,13 @@
#include <wtf/CompletionHandler.h>
#include <wtf/Expected.h>
+namespace JSC {
+class JSGlobalObject;
+}
+
namespace WebCore {
+class DOMPromise;
class FetchResponse;
class ResourceError;
@@ -46,13 +51,14 @@
String clientId;
String reservedClientId;
String targetClientId;
+ RefPtr<DOMPromise> handled;
};
WEBCORE_EXPORT static Ref<FetchEvent> createForTesting(ScriptExecutionContext&);
- static Ref<FetchEvent> create(const AtomString& type, Init&& initializer, IsTrusted isTrusted = IsTrusted::No)
+ static Ref<FetchEvent> create(JSC::JSGlobalObject& globalObject, const AtomString& type, Init&& initializer, IsTrusted isTrusted = IsTrusted::No)
{
- return adoptRef(*new FetchEvent(type, WTFMove(initializer), isTrusted));
+ return adoptRef(*new FetchEvent(globalObject, type, WTFMove(initializer), isTrusted));
}
~FetchEvent();
@@ -67,6 +73,7 @@
const String& clientId() const { return m_clientId; }
const String& reservedClientId() const { return m_reservedClientId; }
const String& targetClientId() const { return m_targetClientId; }
+ DOMPromise& handled() const { return m_handled.get(); }
bool respondWithEntered() const { return m_respondWithEntered; }
@@ -78,7 +85,7 @@
void setNavigationPreloadIdentifier(FetchIdentifier);
private:
- WEBCORE_EXPORT FetchEvent(const AtomString&, Init&&, IsTrusted);
+ WEBCORE_EXPORT FetchEvent(JSC::JSGlobalObject&, const AtomString&, Init&&, IsTrusted);
void promiseIsSettled();
void processResponse(Expected<Ref<FetchResponse>, std::optional<ResourceError>>&&);
@@ -93,6 +100,7 @@
bool m_waitToRespond { false };
bool m_respondWithError { false };
RefPtr<DOMPromise> m_respondPromise;
+ Ref<DOMPromise> m_handled;
ResponseCallback m_onResponse;
Modified: trunk/Source/WebCore/workers/service/FetchEvent.idl (287914 => 287915)
--- trunk/Source/WebCore/workers/service/FetchEvent.idl 2022-01-12 08:51:26 UTC (rev 287914)
+++ trunk/Source/WebCore/workers/service/FetchEvent.idl 2022-01-12 09:44:27 UTC (rev 287915)
@@ -31,12 +31,13 @@
Exposed=ServiceWorker,
JSGenerateToNativeObject
] interface FetchEvent : ExtendableEvent {
- constructor(DOMString type, FetchEventInit eventInitDict);
+ [CallWith=GlobalObject] constructor(DOMString type, FetchEventInit eventInitDict);
[SameObject] readonly attribute FetchRequest request;
[CallWith=ScriptExecutionContext, EnabledBySetting=ServiceWorkerNavigationPreloadEnabled] readonly attribute Promise<any> preloadResponse;
readonly attribute DOMString clientId;
readonly attribute DOMString reservedClientId;
readonly attribute DOMString targetClientId;
+ readonly attribute Promise<undefined> handled;
undefined respondWith(Promise<FetchResponse> r);
};
@@ -46,4 +47,5 @@
DOMString clientId = "";
DOMString reservedClientId = "";
DOMString targetClientId = "";
+ Promise<undefined> handled;
};
Modified: trunk/Source/WebCore/workers/service/context/ServiceWorkerFetch.cpp (287914 => 287915)
--- trunk/Source/WebCore/workers/service/context/ServiceWorkerFetch.cpp 2022-01-12 08:51:26 UTC (rev 287914)
+++ trunk/Source/WebCore/workers/service/context/ServiceWorkerFetch.cpp 2022-01-12 09:44:27 UTC (rev 287915)
@@ -33,6 +33,7 @@
#include "FetchEvent.h"
#include "FetchRequest.h"
#include "FetchResponse.h"
+#include "JSDOMPromise.h"
#include "MIMETypeRegistry.h"
#include "ResourceRequest.h"
#include "ScriptExecutionContextIdentifier.h"
@@ -64,15 +65,17 @@
return { };
}
-static void processResponse(Ref<Client>&& client, Expected<Ref<FetchResponse>, std::optional<ResourceError>>&& result, FetchOptions::Mode mode, FetchOptions::Redirect redirect, const URL& requestURL, CertificateInfo&& certificateInfo)
+static void processResponse(Ref<Client>&& client, Expected<Ref<FetchResponse>, std::optional<ResourceError>>&& result, FetchOptions::Mode mode, FetchOptions::Redirect redirect, const URL& requestURL, CertificateInfo&& certificateInfo, DeferredPromise& promise)
{
if (!result.has_value()) {
auto& error = result.error();
if (!error) {
client->didNotHandle();
+ promise.resolve();
return;
}
client->didFail(*error);
+ promise.reject(Exception { ExceptionCode::NetworkError });
return;
}
auto response = WTFMove(result.value());
@@ -80,6 +83,7 @@
auto loadingError = response->loadingError();
if (!loadingError.isNull()) {
client->didFail(loadingError);
+ promise.reject(Exception { ExceptionCode::NetworkError });
return;
}
@@ -86,9 +90,12 @@
auto resourceResponse = response->resourceResponse();
if (auto error = validateResponse(resourceResponse, mode, redirect); !error.isNull()) {
client->didFail(error);
+ promise.reject(Exception { ExceptionCode::NetworkError });
return;
}
+ promise.resolve();
+
if (resourceResponse.isRedirection() && resourceResponse.httpHeaderFields().contains(HTTPHeaderName::Location)) {
client->didReceiveRedirection(resourceResponse);
return;
@@ -181,15 +188,25 @@
} else if (clientId)
init.clientId = clientId->toString();
init.cancelable = true;
- auto event = FetchEvent::create(eventNames().fetchEvent, WTFMove(init), Event::IsTrusted::Yes);
+ auto& jsDOMGlobalObject = *JSC::jsCast<JSDOMGlobalObject*>(globalScope.globalObject());
+ JSC::JSLockHolder lock(jsDOMGlobalObject.vm());
+
+ auto* promise = JSC::JSPromise::create(jsDOMGlobalObject.vm(), jsDOMGlobalObject.promiseStructure());
+ ASSERT(promise);
+
+ auto deferredPromise = DeferredPromise::create(jsDOMGlobalObject, *promise);
+ init.handled = DOMPromise::create(jsDOMGlobalObject, *promise);
+
+ auto event = FetchEvent::create(*globalScope.globalObject(), eventNames().fetchEvent, WTFMove(init), Event::IsTrusted::Yes);
+
if (isServiceWorkerNavigationPreloadEnabled)
event->setNavigationPreloadIdentifier(fetchIdentifier);
CertificateInfo certificateInfo = globalScope.certificateInfo();
- event->onResponse([client, mode, redirect, requestURL, certificateInfo = WTFMove(certificateInfo)] (auto&& result) mutable {
- processResponse(WTFMove(client), WTFMove(result), mode, redirect, requestURL, WTFMove(certificateInfo));
+ event->onResponse([client, mode, redirect, requestURL, certificateInfo = WTFMove(certificateInfo), deferredPromise] (auto&& result) mutable {
+ processResponse(WTFMove(client), WTFMove(result), mode, redirect, requestURL, WTFMove(certificateInfo), deferredPromise.get());
});
globalScope.dispatchEvent(event);
@@ -198,9 +215,11 @@
if (event->defaultPrevented()) {
ResourceError error { errorDomainWebKitInternal, 0, requestURL, "Fetch event was canceled"_s, ResourceError::Type::General, ResourceError::IsSanitized::Yes };
client->didFail(error);
+ deferredPromise->reject(Exception { NetworkError });
return;
}
client->didNotHandle();
+ deferredPromise->resolve();
}
globalScope.updateExtendedEventsSet(event.ptr());