Title: [287915] trunk
Revision
287915
Author
you...@apple.com
Date
2022-01-12 01:44:27 -0800 (Wed, 12 Jan 2022)

Log Message

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.

LayoutTests/imported/w3c:

* 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.

Source/WebCore:

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):

Modified Paths

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());
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to