Changeset 287915 in webkit


Ignore:
Timestamp:
Jan 12, 2022 1:44:27 AM (6 months ago)
Author:
youenn@apple.com
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):

Location:
trunk
Files:
9 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/imported/w3c/ChangeLog

    r287909 r287915  
     12022-01-12  Youenn Fablet  <youenn@apple.com>
     2
     3        New service worker API 'FetchEvent.handled' needs to be supported
     4        https://bugs.webkit.org/show_bug.cgi?id=208185
     5        <rdar://problem/59808975>
     6
     7        Reviewed by Chris Dumez.
     8
     9        * web-platform-tests/service-workers/service-worker/fetch-event-handled.https-expected.txt:
     10        * web-platform-tests/service-workers/service-worker/fetch-event-handled.https.html:
     11        * web-platform-tests/service-workers/service-worker/resources/fetch-event-handled-worker.js:
     12        (try.event.handled.then):
     13        (catch):
     14        (send_message_to_client): Deleted.
     15
    1162021-11-29 Simon Fraser  <simon.fraser@apple.com>
    217
  • trunk/LayoutTests/imported/w3c/web-platform-tests/service-workers/service-worker/fetch-event-handled.https-expected.txt

    r267647 r287915  
    1 
    2 
    3 Harness Error (TIMEOUT), message = null
    41
    52PASS global setup
    6 TIMEOUT FetchEvent.handled should resolve when respondWith() is not called for a navigation request Test timed out
    7 NOTRUN FetchEvent.handled should resolve when respondWith() is not called for a sub-resource request
    8 NOTRUN FetchEvent.handled should reject when respondWith() is not called and the event is canceled
    9 NOTRUN FetchEvent.handled should resolve when the promise provided to respondWith() is resolved
    10 NOTRUN FetchEvent.handled should reject when the promise provided to respondWith() is resolved to an invalid response
    11 NOTRUN FetchEvent.handled should reject when the promise provided to respondWith() is rejected
    12 NOTRUN global cleanup
     3PASS FetchEvent.handled should resolve when respondWith() is not called for a navigation request
     4PASS FetchEvent.handled should resolve when respondWith() is not called for a sub-resource request
     5PASS FetchEvent.handled should reject when respondWith() is not called and the event is canceled
     6PASS FetchEvent.handled should resolve when the promise provided to respondWith() is resolved
     7PASS FetchEvent.handled should reject when the promise provided to respondWith() is resolved to an invalid response
     8PASS FetchEvent.handled should reject when the promise provided to respondWith() is rejected
     9PASS global cleanup
    1310
  • trunk/LayoutTests/imported/w3c/web-platform-tests/service-workers/service-worker/fetch-event-handled.https.html

    r279389 r287915  
    1111const script = 'resources/fetch-event-handled-worker.js';
    1212const scope = 'resources/simple.html';
     13const channel = new MessageChannel();
    1314
    1415// Wait for a message from the service worker and removes the message handler.
    1516function wait_for_message_from_worker() {
    16   return new Promise((resolve) => {
    17     const handler = (event) => {
    18       frame.contentWindow.navigator.serviceWorker.removeEventListener(
    19           'message', handler);
    20       resolve(event.data);
    21     };
    22     frame.contentWindow.navigator.serviceWorker.addEventListener(
    23         'message', handler);
    24   });
     17  return new Promise((resolve) => channel.port2.onmessage = (event) => resolve(event.data));
    2518}
    2619
     
    3023      await service_worker_unregister_and_register(t, script, scope);
    3124  worker = registration.installing;
     25  if (!worker)
     26      worker = registration.active;
     27  worker.postMessage({port:channel.port1}, [channel.port1]);
    3228  await wait_for_state(t, worker, 'activated');
    3329}, 'global setup');
    3430
    3531promise_test(async (t) => {
    36   frame = await with_iframe(scope);
     32  const promise = with_iframe(scope);
    3733  const message = await wait_for_message_from_worker();
     34  frame = await promise;
    3835  assert_equals(message, 'RESOLVED');
    3936}, 'FetchEvent.handled should resolve when respondWith() is not called for a' +
  • trunk/LayoutTests/imported/w3c/web-platform-tests/service-workers/service-worker/resources/fetch-event-handled-worker.js

    r264043 r287915  
    22// REJECTED) to the test.
    33
    4 // Send a message to the client with the client id.
    5 function send_message_to_client(message, clientId) {
    6   clients.get(clientId).then((client) => {
    7     client.postMessage(message);
    8   });
    9 }
     4self.addEventListener('message', function(event) {
     5  self.port = event.data.port;
     6});
    107
    118self.addEventListener('fetch', function(event) {
    12   const clientId = (event.request.mode === 'navigate') ?
    13       event.resultingClientId : event.clientId;
    14 
    159  try {
    1610    event.handled.then(() => {
    17       send_message_to_client('RESOLVED', clientId);
     11      self.port.postMessage('RESOLVED');
    1812    }, () => {
    19       send_message_to_client('REJECTED', clientId);
     13      self.port.postMessage('REJECTED');
    2014    });
    2115  } catch (e) {
    22     send_message_to_client('FAILED', clientId);
     16    self.port.postMessage('FAILED');
    2317    return;
    2418  }
  • trunk/Source/WebCore/ChangeLog

    r287914 r287915  
     12022-01-12  Youenn Fablet  <youenn@apple.com>
     2
     3        New service worker API 'FetchEvent.handled' needs to be supported
     4        https://bugs.webkit.org/show_bug.cgi?id=208185
     5        <rdar://problem/59808975>
     6
     7        Reviewed by Chris Dumez.
     8
     9        Expose FetchEvent.handled and resolve/reject it as per specification.
     10
     11        Covered by test that we update to not rely on clientIds that we do not support very well.
     12
     13        * workers/service/FetchEvent.cpp:
     14        (WebCore::FetchEvent::createForTesting):
     15        (WebCore::retrieveHandledPromise):
     16        (WebCore::FetchEvent::FetchEvent):
     17        * workers/service/FetchEvent.h:
     18        * workers/service/FetchEvent.idl:
     19        * workers/service/context/ServiceWorkerFetch.cpp:
     20        (WebCore::ServiceWorkerFetch::processResponse):
     21        (WebCore::ServiceWorkerFetch::dispatchFetchEvent):
     22
    1232022-01-12  Frédéric Wang  <fwang@igalia.com>
    224
  • trunk/Source/WebCore/workers/service/FetchEvent.cpp

    r286419 r287915  
    4343    FetchEvent::Init init;
    4444    init.request = FetchRequest::create(context, { }, FetchHeaders::create(FetchHeaders::Guard::Immutable, { }), { }, { }, { });
    45     return FetchEvent::create("fetch", WTFMove(init), Event::IsTrusted::Yes);
     45    return FetchEvent::create(*context.globalObject(), "fetch", WTFMove(init), Event::IsTrusted::Yes);
    4646}
    4747
    48 FetchEvent::FetchEvent(const AtomString& type, Init&& initializer, IsTrusted isTrusted)
     48static inline Ref<DOMPromise> retrieveHandledPromise(JSC::JSGlobalObject& globalObject, RefPtr<DOMPromise>&& promise)
     49{
     50    if (promise)
     51        return promise.releaseNonNull();
     52
     53    JSC::JSLockHolder lock(globalObject.vm());
     54
     55    auto& jsDOMGlobalObject = *JSC::jsCast<JSDOMGlobalObject*>(&globalObject);
     56    auto deferredPromise = DeferredPromise::create(jsDOMGlobalObject);
     57    return DOMPromise::create(jsDOMGlobalObject, *JSC::jsCast<JSC::JSPromise*>(deferredPromise->promise()));
     58}
     59
     60FetchEvent::FetchEvent(JSC::JSGlobalObject& globalObject, const AtomString& type, Init&& initializer, IsTrusted isTrusted)
    4961    : ExtendableEvent(type, initializer, isTrusted)
    5062    , m_request(initializer.request.releaseNonNull())
     
    5264    , m_reservedClientId(WTFMove(initializer.reservedClientId))
    5365    , m_targetClientId(WTFMove(initializer.targetClientId))
     66    , m_handled(retrieveHandledPromise(globalObject, WTFMove(initializer.handled)))
    5467{
    5568}
  • trunk/Source/WebCore/workers/service/FetchEvent.h

    r286419 r287915  
    3434#include <wtf/Expected.h>
    3535
     36namespace JSC {
     37class JSGlobalObject;
     38}
     39
    3640namespace WebCore {
    3741
     42class DOMPromise;
    3843class FetchResponse;
    3944class ResourceError;
     
    4752        String reservedClientId;
    4853        String targetClientId;
     54        RefPtr<DOMPromise> handled;
    4955    };
    5056
    5157    WEBCORE_EXPORT static Ref<FetchEvent> createForTesting(ScriptExecutionContext&);
    5258
    53     static Ref<FetchEvent> create(const AtomString& type, Init&& initializer, IsTrusted isTrusted = IsTrusted::No)
     59    static Ref<FetchEvent> create(JSC::JSGlobalObject& globalObject, const AtomString& type, Init&& initializer, IsTrusted isTrusted = IsTrusted::No)
    5460    {
    55         return adoptRef(*new FetchEvent(type, WTFMove(initializer), isTrusted));
     61        return adoptRef(*new FetchEvent(globalObject, type, WTFMove(initializer), isTrusted));
    5662    }
    5763    ~FetchEvent();
     
    6874    const String& reservedClientId() const { return m_reservedClientId; }
    6975    const String& targetClientId() const { return m_targetClientId; }
     76    DOMPromise& handled() const { return m_handled.get(); }
    7077
    7178    bool respondWithEntered() const { return m_respondWithEntered; }
     
    7986
    8087private:
    81     WEBCORE_EXPORT FetchEvent(const AtomString&, Init&&, IsTrusted);
     88    WEBCORE_EXPORT FetchEvent(JSC::JSGlobalObject&, const AtomString&, Init&&, IsTrusted);
    8289
    8390    void promiseIsSettled();
     
    94101    bool m_respondWithError { false };
    95102    RefPtr<DOMPromise> m_respondPromise;
     103    Ref<DOMPromise> m_handled;
    96104
    97105    ResponseCallback m_onResponse;
  • trunk/Source/WebCore/workers/service/FetchEvent.idl

    r286419 r287915  
    3232    JSGenerateToNativeObject
    3333] interface FetchEvent : ExtendableEvent {
    34     constructor(DOMString type, FetchEventInit eventInitDict);
     34    [CallWith=GlobalObject] constructor(DOMString type, FetchEventInit eventInitDict);
    3535    [SameObject] readonly attribute FetchRequest request;
    3636    [CallWith=ScriptExecutionContext, EnabledBySetting=ServiceWorkerNavigationPreloadEnabled] readonly attribute Promise<any> preloadResponse;
     
    3838    readonly attribute DOMString reservedClientId;
    3939    readonly attribute DOMString targetClientId;
     40    readonly attribute Promise<undefined> handled;
    4041
    4142    undefined respondWith(Promise<FetchResponse> r);
     
    4748    DOMString reservedClientId = "";
    4849    DOMString targetClientId = "";
     50    Promise<undefined> handled;
    4951};
  • trunk/Source/WebCore/workers/service/context/ServiceWorkerFetch.cpp

    r287612 r287915  
    3434#include "FetchRequest.h"
    3535#include "FetchResponse.h"
     36#include "JSDOMPromise.h"
    3637#include "MIMETypeRegistry.h"
    3738#include "ResourceRequest.h"
     
    6566}
    6667
    67 static void processResponse(Ref<Client>&& client, Expected<Ref<FetchResponse>, std::optional<ResourceError>>&& result, FetchOptions::Mode mode, FetchOptions::Redirect redirect, const URL& requestURL, CertificateInfo&& certificateInfo)
     68static 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)
    6869{
    6970    if (!result.has_value()) {
     
    7172        if (!error) {
    7273            client->didNotHandle();
     74            promise.resolve();
    7375            return;
    7476        }
    7577        client->didFail(*error);
     78        promise.reject(Exception { ExceptionCode::NetworkError });
    7679        return;
    7780    }
     
    8184    if (!loadingError.isNull()) {
    8285        client->didFail(loadingError);
     86        promise.reject(Exception { ExceptionCode::NetworkError });
    8387        return;
    8488    }
     
    8791    if (auto error = validateResponse(resourceResponse, mode, redirect); !error.isNull()) {
    8892        client->didFail(error);
    89         return;
    90     }
     93        promise.reject(Exception { ExceptionCode::NetworkError });
     94        return;
     95    }
     96
     97    promise.resolve();
    9198
    9299    if (resourceResponse.isRedirection() && resourceResponse.httpHeaderFields().contains(HTTPHeaderName::Location)) {
     
    182189        init.clientId = clientId->toString();
    183190    init.cancelable = true;
    184     auto event = FetchEvent::create(eventNames().fetchEvent, WTFMove(init), Event::IsTrusted::Yes);
     191
     192    auto& jsDOMGlobalObject = *JSC::jsCast<JSDOMGlobalObject*>(globalScope.globalObject());
     193    JSC::JSLockHolder lock(jsDOMGlobalObject.vm());
     194
     195    auto* promise = JSC::JSPromise::create(jsDOMGlobalObject.vm(), jsDOMGlobalObject.promiseStructure());
     196    ASSERT(promise);
     197
     198    auto deferredPromise = DeferredPromise::create(jsDOMGlobalObject, *promise);
     199    init.handled = DOMPromise::create(jsDOMGlobalObject, *promise);
     200
     201    auto event = FetchEvent::create(*globalScope.globalObject(), eventNames().fetchEvent, WTFMove(init), Event::IsTrusted::Yes);
    185202
    186203    if (isServiceWorkerNavigationPreloadEnabled)
     
    189206    CertificateInfo certificateInfo = globalScope.certificateInfo();
    190207
    191     event->onResponse([client, mode, redirect, requestURL, certificateInfo = WTFMove(certificateInfo)] (auto&& result) mutable {
    192         processResponse(WTFMove(client), WTFMove(result), mode, redirect, requestURL, WTFMove(certificateInfo));
     208    event->onResponse([client, mode, redirect, requestURL, certificateInfo = WTFMove(certificateInfo), deferredPromise] (auto&& result) mutable {
     209        processResponse(WTFMove(client), WTFMove(result), mode, redirect, requestURL, WTFMove(certificateInfo), deferredPromise.get());
    193210    });
    194211
     
    199216            ResourceError error { errorDomainWebKitInternal, 0, requestURL, "Fetch event was canceled"_s, ResourceError::Type::General, ResourceError::IsSanitized::Yes };
    200217            client->didFail(error);
     218            deferredPromise->reject(Exception { NetworkError });
    201219            return;
    202220        }
    203221        client->didNotHandle();
     222        deferredPromise->resolve();
    204223    }
    205224
Note: See TracChangeset for help on using the changeset viewer.