Changeset 291979 in webkit


Ignore:
Timestamp:
Mar 28, 2022 11:14:19 AM (4 months ago)
Author:
beidson@apple.com
Message:

Support ServiceWorkerClients.openWindow.
<rdar://90616651> and https://bugs.webkit.org/show_bug.cgi?id=238400

Reviewed by Youenn Fablet.
Source/WebCore:

Test: http/tests/workers/service/openwindow-from-notification-click.html

  • dom/Document.cpp:

(WebCore::Document::pageID const):

  • page/ClientOrigin.h:

(WebCore::ClientOrigin::loggingString const):

  • workers/service/ServiceWorkerClientData.cpp:

(WebCore::ServiceWorkerClientData::isolatedCopy const):
(WebCore::ServiceWorkerClientData::isolatedCopy):
(WebCore::ServiceWorkerClientData::from):

  • workers/service/ServiceWorkerClientData.h:

(WebCore::ServiceWorkerClientData::encode const):
(WebCore::ServiceWorkerClientData::decode):

  • workers/service/ServiceWorkerClients.cpp:

(WebCore::matchWindowWithPageIdentifier):
(WebCore::ServiceWorkerClients::openWindow):

  • workers/service/context/SWContextManager.h:
  • workers/service/server/SWServerToContextConnection.h:
  • workers/service/server/SWServerWorker.h:

Source/WebKit:

This API asks the browser to asynchronously open a new tab to a URL then resolve
a promise with the new WindowClient representing that tab.

From a WebCore/WebKit standpoint, implementing this was mostly straightforward.
1 - A plumbing exercise (thread hopping and IPC'ing the message and its reply around)
2 - Implmenting a new delegate method for the hosting app to create the requested WKWebView

The delegate method was interesting. Normally this is the type of thing that'd go to the
WKUIDelegate but that requires there to be a WKWebView, and service workers can be running
without any web views.

Fortunately we already had a WKWebsiteDataStore delegate SPI, and service workers *do* always
have an associated website data store they're running under.

Once the app gives the new web view back to WebKit, we record its PageIdentifier in the reply.

Once the reply makes its way all the way back to the ServiceWorker process and on the
ServiceWorker thread, we do a client match and cross check with that PageIdentifier to make
sure we're resolving the promise with the correct WindowClient.

If there's no matched clients, then the view is either already gone or it has navigated away
to a non-applicable URL.

Same if there are matched clients, but they don't match the specified PageIdentifier.

A straight forward layouttest completes the task.

  • NetworkProcess/ServiceWorker/WebSWServerConnection.cpp:

(WebKit::WebSWServerConnection::controlClient):

  • NetworkProcess/ServiceWorker/WebSWServerToContextConnection.cpp:

(WebKit::WebSWServerToContextConnection::openWindow):

  • NetworkProcess/ServiceWorker/WebSWServerToContextConnection.h:
  • NetworkProcess/ServiceWorker/WebSWServerToContextConnection.messages.in:
  • UIProcess/API/Cocoa/WKWebsiteDataStore.mm:

(-[WKWebsiteDataStore set_delegate:]):

  • UIProcess/API/Cocoa/_WKWebsiteDataStoreDelegate.h:
  • UIProcess/Network/NetworkProcessProxy.cpp:

(WebKit::NetworkProcessProxy::openWindowFromServiceWorker):

  • UIProcess/Network/NetworkProcessProxy.h:
  • UIProcess/Network/NetworkProcessProxy.messages.in:
  • UIProcess/WebPageProxy.cpp:

(WebKit::WebPageProxy::didFailProvisionalLoadForFrameShared):
(WebKit::WebPageProxy::callLoadCompletionHandlersIfNecessary):
(WebKit::WebPageProxy::didFinishLoadForFrame):
(WebKit::WebPageProxy::didFailLoadForFrame):
(WebKit::WebPageProxy::resetState):
(WebKit::WebPageProxy::callServiceWorkerLaunchCompletionHandlerIfNecessary): Deleted.

  • UIProcess/WebPageProxy.h:
  • UIProcess/WebsiteData/WebsiteDataStore.cpp:

(WebKit::WebsiteDataStore::openWindowFromServiceWorker):

  • UIProcess/WebsiteData/WebsiteDataStore.h:
  • UIProcess/WebsiteData/WebsiteDataStoreClient.h:

(WebKit::WebsiteDataStoreClient::openWindowFromServiceWorker):

  • WebProcess/Notifications/WebNotificationManager.cpp:

(WebKit::WebNotificationManager::show):
(WebKit::WebNotificationManager::didShowNotification):
(WebKit::WebNotificationManager::didClickNotification):

  • WebProcess/Storage/WebSWContextManagerConnection.cpp:

(WebKit::WebSWContextManagerConnection::openWindow):

  • WebProcess/Storage/WebSWContextManagerConnection.h:

Source/WTF:

  • wtf/HashTable.h:

(WTF::KeyTraits>::inlineLookup): Relax this value size requirement for now.
The required refactoring is best left as a seperate task with a seperate patch.

Tools:

Implement the new delegate to create the new view.

  • WebKitTestRunner/TestController.cpp:

(WTR::TestController::createOtherPage):
(WTR::TestController::createOtherPlatformWebView):

  • WebKitTestRunner/TestController.h:
  • WebKitTestRunner/cocoa/TestControllerCocoa.mm:

(WTR::TestController::platformCreateOtherPage):

  • WebKitTestRunner/cocoa/TestWebsiteDataStoreDelegate.mm:

(-[TestWebsiteDataStoreDelegate websiteDataStore:openWindow:fromServiceWorkerOrigin:completionHandler:]):

LayoutTests:

WKTR knows how to openWindow() now.

So test:

  • The success case
  • Failure due to a disallowed URL
  • Failure due to a lack of a related user gesture.
  • http/tests/workers/service/openwindow-from-notification-click-expected.txt: Added.
  • http/tests/workers/service/openwindow-from-notification-click.html: Added.
  • http/tests/workers/service/resources/openwindow-client.html: Added.
  • http/tests/workers/service/resources/shownotification-openwindow-worker.js: Added.

(async const):
(let.messageClients):
(clients.openWindow.string_appeared_here.then.async client):
(catch.async error):
(async event):
(async tryShow):
(async getNotes):

  • platform/gtk/TestExpectations:
Location:
trunk
Files:
4 added
36 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r291962 r291979  
     12022-03-28  Brady Eidson  <beidson@apple.com>
     2
     3        Support ServiceWorkerClients.openWindow.
     4        <rdar://90616651> and https://bugs.webkit.org/show_bug.cgi?id=238400
     5
     6        Reviewed by Youenn Fablet.
     7
     8        WKTR knows how to openWindow() now.
     9       
     10        So test:
     11        - The success case
     12        - Failure due to a disallowed URL
     13        - Failure due to a lack of a related user gesture.
     14       
     15        * http/tests/workers/service/openwindow-from-notification-click-expected.txt: Added.
     16        * http/tests/workers/service/openwindow-from-notification-click.html: Added.
     17        * http/tests/workers/service/resources/openwindow-client.html: Added.
     18        * http/tests/workers/service/resources/shownotification-openwindow-worker.js: Added.
     19        (async const):
     20        (let.messageClients):
     21        (clients.openWindow.string_appeared_here.then.async client):
     22        (catch.async error):
     23        (async event):
     24        (async tryShow):
     25        (async getNotes):
     26        * platform/gtk/TestExpectations:
     27
    1282022-03-28  Ziran Sun  <zsun@igalia.com>
    229
  • trunk/LayoutTests/platform/gtk/TestExpectations

    r291950 r291979  
    718718webkit.org/b/175419 imported/w3c/web-platform-tests/service-workers/cache-storage/serviceworker/credentials.https.html [ Skip ]
    719719webkit.org/b/175419 [ Release ] http/tests/workers/service/postmessage-after-terminate.https.html [ Pass Failure Timeout ]
     720webkit.org/b/175419 http/tests/workers/service/openwindow-from-notification-click.html [ Skip ]
    720721
    721722# FIXME: This can't be the right bug number.
  • trunk/Source/WTF/ChangeLog

    r291972 r291979  
     12022-03-28  Brady Eidson  <beidson@apple.com>
     2
     3        Support ServiceWorkerClients.openWindow.
     4        <rdar://90616651> and https://bugs.webkit.org/show_bug.cgi?id=238400
     5
     6        Reviewed by Youenn Fablet.
     7
     8        * wtf/HashTable.h:
     9        (WTF::KeyTraits>::inlineLookup): Relax this value size requirement for now.
     10        The required refactoring is best left as a seperate task with a seperate patch.
     11
    1122022-03-28  Chris Dumez  <cdumez@apple.com>
    213
  • trunk/Source/WTF/wtf/HashTable.h

    r284167 r291979  
    682682    ALWAYS_INLINE auto HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::inlineLookup(const T& key) -> ValueType*
    683683    {
    684         static_assert(sizeof(Value) <= 128, "Your HashTable types are too big to efficiently move when rehashing.  Consider using UniqueRef instead");
     684        static_assert(sizeof(Value) <= 150, "Your HashTable types are too big to efficiently move when rehashing.  Consider using UniqueRef instead");
    685685        checkKey<HashTranslator>(key);
    686686
  • trunk/Source/WebCore/ChangeLog

    r291978 r291979  
     12022-03-28  Brady Eidson  <beidson@apple.com>
     2
     3        Support ServiceWorkerClients.openWindow.
     4        <rdar://90616651> and https://bugs.webkit.org/show_bug.cgi?id=238400
     5
     6        Reviewed by Youenn Fablet.
     7
     8        Test: http/tests/workers/service/openwindow-from-notification-click.html
     9
     10        * dom/Document.cpp:
     11        (WebCore::Document::pageID const):
     12       
     13        * page/ClientOrigin.h:
     14        (WebCore::ClientOrigin::loggingString const):
     15       
     16        * workers/service/ServiceWorkerClientData.cpp:
     17        (WebCore::ServiceWorkerClientData::isolatedCopy const):
     18        (WebCore::ServiceWorkerClientData::isolatedCopy):
     19        (WebCore::ServiceWorkerClientData::from):
     20       
     21        * workers/service/ServiceWorkerClientData.h:
     22        (WebCore::ServiceWorkerClientData::encode const):
     23        (WebCore::ServiceWorkerClientData::decode):
     24       
     25        * workers/service/ServiceWorkerClients.cpp:
     26        (WebCore::matchWindowWithPageIdentifier):
     27        (WebCore::ServiceWorkerClients::openWindow):
     28       
     29        * workers/service/context/SWContextManager.h:
     30        * workers/service/server/SWServerToContextConnection.h:
     31        * workers/service/server/SWServerWorker.h:
     32
    1332022-03-28  Ian Anderson  <iana@apple.com>
    234
  • trunk/Source/WebCore/dom/Document.cpp

    r291888 r291979  
    84098409std::optional<PageIdentifier> Document::pageID() const
    84108410{
    8411     return m_frame->loader().pageID();
     8411    return m_frame ? m_frame->loader().pageID() : std::nullopt;
    84128412}
    84138413
  • trunk/Source/WebCore/page/ClientOrigin.h

    r290901 r291979  
    5151    SecurityOriginData topOrigin;
    5252    SecurityOriginData clientOrigin;
     53
     54    String loggingString() const { return makeString(topOrigin.toString(), "-", clientOrigin.toString()); }
    5355};
    5456
  • trunk/Source/WebCore/workers/service/ServiceWorkerClientData.cpp

    r291888 r291979  
    5959ServiceWorkerClientData ServiceWorkerClientData::isolatedCopy() const &
    6060{
    61     return { identifier, type, frameType, url.isolatedCopy(), lastNavigationWasAppInitiated, isVisible, isFocused, focusOrder };
     61    return { identifier, type, frameType, url.isolatedCopy(), pageIdentifier, lastNavigationWasAppInitiated, isVisible, isFocused, focusOrder };
    6262}
    6363
    6464ServiceWorkerClientData ServiceWorkerClientData::isolatedCopy() &&
    6565{
    66     return { identifier, type, frameType, WTFMove(url).isolatedCopy(), lastNavigationWasAppInitiated, isVisible, isFocused, focusOrder };
     66    return { identifier, type, frameType, WTFMove(url).isolatedCopy(), pageIdentifier, lastNavigationWasAppInitiated, isVisible, isFocused, focusOrder };
    6767}
    6868
     
    7979        isDocument ? ServiceWorkerClientType::Window : ServiceWorkerClientType::Worker,
    8080        toServiceWorkerClientFrameType(context),
    81         document.creationURL(), lastNavigationWasAppInitiated,
     81        document.creationURL(),
     82        document.pageID(),
     83        lastNavigationWasAppInitiated,
    8284        !document.hidden(),
    8385        document.hasFocus(),
  • trunk/Source/WebCore/workers/service/ServiceWorkerClientData.h

    r291938 r291979  
    2828#if ENABLE(SERVICE_WORKER)
    2929
     30#include "PageIdentifier.h"
    3031#include "ProcessQualified.h"
    3132#include "ScriptExecutionContextIdentifier.h"
     
    4647    ServiceWorkerClientFrameType frameType;
    4748    URL url;
     49    std::optional<PageIdentifier> pageIdentifier;
    4850    LastNavigationWasAppInitiated lastNavigationWasAppInitiated;
    4951    bool isVisible { false };
     
    6365void ServiceWorkerClientData::encode(Encoder& encoder) const
    6466{
    65     encoder << identifier << type << frameType << url << lastNavigationWasAppInitiated << isVisible << isFocused << focusOrder;
     67    encoder << identifier << type << frameType << url << pageIdentifier << lastNavigationWasAppInitiated << isVisible << isFocused << focusOrder;
    6668}
    6769
     
    8991        return std::nullopt;
    9092
     93    std::optional<std::optional<PageIdentifier>> pageIdentifier;
     94    decoder >> pageIdentifier;
     95    if (!pageIdentifier)
     96        return std::nullopt;
     97
    9198    std::optional<LastNavigationWasAppInitiated> lastNavigationWasAppInitiated;
    9299    decoder >> lastNavigationWasAppInitiated;
     
    109116        return std::nullopt;
    110117
    111     return { { WTFMove(*identifier), WTFMove(*type), WTFMove(*frameType), WTFMove(*url), WTFMove(*lastNavigationWasAppInitiated), WTFMove(*isVisible), WTFMove(*isFocused), WTFMove(*focusOrder) } };
     118    return { { WTFMove(*identifier), WTFMove(*type), WTFMove(*frameType), WTFMove(*url), WTFMove(*pageIdentifier), WTFMove(*lastNavigationWasAppInitiated), WTFMove(*isVisible), WTFMove(*isFocused), WTFMove(*focusOrder) } };
    112119}
    113120
  • trunk/Source/WebCore/workers/service/ServiceWorkerClients.cpp

    r291938 r291979  
    9191}
    9292
    93 void ServiceWorkerClients::openWindow(ScriptExecutionContext&, const String& url, Ref<DeferredPromise>&& promise)
     93static void matchWindowWithPageIdentifier(ServiceWorkerIdentifier serviceWorkerIdentifier, PageIdentifier pageIdentifier, CompletionHandler<void(ServiceWorkerGlobalScope&, std::optional<ServiceWorkerClientData>)>&& callback)
    9494{
    95     UNUSED_PARAM(url);
    96     promise->reject(Exception { NotSupportedError, "clients.openWindow() is not yet supported"_s });
     95    callOnMainThread([serviceWorkerIdentifier, pageIdentifier, callback = WTFMove(callback)] () mutable {
     96        auto connection = SWContextManager::singleton().connection();
     97        auto options = ServiceWorkerClientQueryOptions { true, ServiceWorkerClientType::Window };
     98        connection->matchAll(serviceWorkerIdentifier, options, [serviceWorkerIdentifier, pageIdentifier, callback = WTFMove(callback)] (Vector<ServiceWorkerClientData>&& clientsData) mutable {
     99            SWContextManager::singleton().postTaskToServiceWorker(serviceWorkerIdentifier, [pageIdentifier, callback = WTFMove(callback), clientsData = crossThreadCopy(WTFMove(clientsData))] (auto& scope) mutable {
     100                for (auto& data : clientsData) {
     101                    if (data.pageIdentifier == pageIdentifier) {
     102                        callback(scope, data);
     103                        return;
     104                    }
     105                }
     106
     107                callback(scope, std::nullopt);
     108            });
     109        });
     110    });
     111}
     112
     113void ServiceWorkerClients::openWindow(ScriptExecutionContext& context, const String& urlString, Ref<DeferredPromise>&& promise)
     114{
     115    LOG(ServiceWorker, "WebProcess %i service worker calling openWindow to URL %s", getpid(), urlString.utf8().data());
     116
     117    auto serviceWorkerIdentifier = downcast<ServiceWorkerGlobalScope>(context).thread().identifier();
     118    auto url = context.completeURL(urlString);
     119
     120    if (context.settingsValues().serviceWorkersUserGestureEnabled && !downcast<ServiceWorkerGlobalScope>(context).isProcessingUserGesture()) {
     121        promise->reject(Exception { InvalidAccessError, "ServiceWorkerClients.openWindow() requires a user gesture"_s });
     122        return;
     123    }
     124
     125    if (!url.isValid()) {
     126        promise->reject(Exception { TypeError, makeString("URL string ", urlString, " cannot successfully be parsed"_s) });
     127        return;
     128    }
     129
     130    if (url.protocolIsAbout()) {
     131        promise->reject(Exception { TypeError, makeString("ServiceWorkerClients.openWindow() cannot be called with URL "_s, url.string()) });
     132        return;
     133    }
     134
     135    callOnMainThread([promiseIdentifier = addPendingPromise(WTFMove(promise)), serviceWorkerIdentifier, url = url.isolatedCopy()] () mutable {
     136        auto connection = SWContextManager::singleton().connection();
     137        connection->openWindow(serviceWorkerIdentifier, url.string(), [promiseIdentifier, serviceWorkerIdentifier] (std::optional<PageIdentifier>&& pageIdentifier) mutable {
     138            SWContextManager::singleton().postTaskToServiceWorker(serviceWorkerIdentifier, [promiseIdentifier, pageIdentifier = WTFMove(pageIdentifier), serviceWorkerIdentifier] (ServiceWorkerGlobalScope& scope) mutable {
     139                LOG(ServiceWorker, "WebProcess %i finished ServiceWorkerClients::openWindow call. Resulting page identifier is %s", getpid(), pageIdentifier ? pageIdentifier->loggingString().utf8().data() : "<NONE>");
     140
     141                if (!pageIdentifier) {
     142                    if (auto promise = scope.clients().takePendingPromise(promiseIdentifier))
     143                        promise->resolveWithJSValue(JSC::jsNull());
     144                    return;
     145                }
     146
     147                matchWindowWithPageIdentifier(serviceWorkerIdentifier, *pageIdentifier, [promiseIdentifier] (auto& scope, std::optional<ServiceWorkerClientData> clientData) mutable {
     148                    auto promise = scope.clients().takePendingPromise(promiseIdentifier);
     149                    if (!promise)
     150                        return;
     151
     152                    if (!clientData) {
     153                        promise->resolveWithJSValue(JSC::jsNull());
     154                        return;
     155                    }
     156
     157                    auto client = ServiceWorkerClient::create(scope, WTFMove(*clientData));
     158                    promise->template resolve<IDLInterface<ServiceWorkerClient>>(WTFMove(client));
     159                });
     160            });
     161        });
     162    });
    97163}
    98164
  • trunk/Source/WebCore/workers/service/context/SWContextManager.h

    r291938 r291979  
    6868        virtual void matchAll(ServiceWorkerIdentifier, const ServiceWorkerClientQueryOptions&, ServiceWorkerClientsMatchAllCallback&&) = 0;
    6969        virtual void claim(ServiceWorkerIdentifier, CompletionHandler<void(ExceptionOr<void>&&)>&&) = 0;
    70 
    7170        virtual void focus(ScriptExecutionContextIdentifier, CompletionHandler<void(std::optional<WebCore::ServiceWorkerClientData>&&)>&&) = 0;
     71        virtual void openWindow(ServiceWorkerIdentifier, const String& url, CompletionHandler<void(std::optional<PageIdentifier>&&)>&&) = 0;
    7272
    7373        virtual void didFailHeartBeatCheck(ServiceWorkerIdentifier) = 0;
  • trunk/Source/WebCore/workers/service/server/SWServerToContextConnection.h

    r291467 r291979  
    8383    WEBCORE_EXPORT void findClientByVisibleIdentifier(ServiceWorkerIdentifier, const String& clientIdentifier, CompletionHandler<void(std::optional<WebCore::ServiceWorkerClientData>&&)>&&);
    8484
     85    virtual void openWindow(ServiceWorkerIdentifier, const String& urlString, CompletionHandler<void(std::optional<WebCore::PageIdentifier>&&)>&&) = 0;
     86
    8587    const RegistrableDomain& registrableDomain() const { return m_registrableDomain; }
    8688    std::optional<ScriptExecutionContextIdentifier> serviceWorkerPageIdentifier() const { return m_serviceWorkerPageIdentifier; }
  • trunk/Source/WebCore/workers/service/server/SWServerWorker.h

    r291467 r291979  
    118118    ServiceWorkerContextData contextData() const;
    119119
    120     const ClientOrigin& origin() const;
     120    WEBCORE_EXPORT const ClientOrigin& origin() const;
    121121    const RegistrableDomain& registrableDomain() const { return m_registrableDomain; }
    122122    WEBCORE_EXPORT std::optional<ScriptExecutionContextIdentifier> serviceWorkerPageIdentifier() const;
  • trunk/Source/WebKit/ChangeLog

    r291967 r291979  
     12022-03-28  Brady Eidson  <beidson@apple.com>
     2
     3        Support ServiceWorkerClients.openWindow.
     4        <rdar://90616651> and https://bugs.webkit.org/show_bug.cgi?id=238400
     5
     6        Reviewed by Youenn Fablet.
     7       
     8        This API asks the browser to asynchronously open a new tab to a URL then resolve
     9        a promise with the new WindowClient representing that tab.
     10           
     11        From a WebCore/WebKit standpoint, implementing this was mostly straightforward.
     12        1 - A plumbing exercise (thread hopping and IPC'ing the message and its reply around)
     13        2 - Implmenting a new delegate method for the hosting app to create the requested WKWebView
     14       
     15        The delegate method was interesting. Normally this is the type of thing that'd go to the
     16        WKUIDelegate but that requires there to be a WKWebView, and service workers can be running
     17        without any web views.
     18       
     19        Fortunately we already had a WKWebsiteDataStore delegate SPI, and service workers *do* always
     20        have an associated website data store they're running under.
     21       
     22        Once the app gives the new web view back to WebKit, we record its PageIdentifier in the reply.
     23       
     24        Once the reply makes its way all the way back to the ServiceWorker process and on the
     25        ServiceWorker thread, we do a client match and cross check with that PageIdentifier to make
     26        sure we're resolving the promise with the correct WindowClient.
     27       
     28        If there's no matched clients, then the view is either already gone or it has navigated away
     29        to a non-applicable URL.
     30       
     31        Same if there are matched clients, but they don't match the specified PageIdentifier.
     32
     33        A straight forward layouttest completes the task.
     34       
     35        * NetworkProcess/ServiceWorker/WebSWServerConnection.cpp:
     36        (WebKit::WebSWServerConnection::controlClient):
     37       
     38        * NetworkProcess/ServiceWorker/WebSWServerToContextConnection.cpp:
     39        (WebKit::WebSWServerToContextConnection::openWindow):
     40        * NetworkProcess/ServiceWorker/WebSWServerToContextConnection.h:
     41        * NetworkProcess/ServiceWorker/WebSWServerToContextConnection.messages.in:
     42       
     43        * UIProcess/API/Cocoa/WKWebsiteDataStore.mm:
     44        (-[WKWebsiteDataStore set_delegate:]):
     45        * UIProcess/API/Cocoa/_WKWebsiteDataStoreDelegate.h:
     46       
     47        * UIProcess/Network/NetworkProcessProxy.cpp:
     48        (WebKit::NetworkProcessProxy::openWindowFromServiceWorker):
     49        * UIProcess/Network/NetworkProcessProxy.h:
     50        * UIProcess/Network/NetworkProcessProxy.messages.in:
     51
     52        * UIProcess/WebPageProxy.cpp:
     53        (WebKit::WebPageProxy::didFailProvisionalLoadForFrameShared):
     54        (WebKit::WebPageProxy::callLoadCompletionHandlersIfNecessary):
     55        (WebKit::WebPageProxy::didFinishLoadForFrame):
     56        (WebKit::WebPageProxy::didFailLoadForFrame):
     57        (WebKit::WebPageProxy::resetState):
     58        (WebKit::WebPageProxy::callServiceWorkerLaunchCompletionHandlerIfNecessary): Deleted.
     59        * UIProcess/WebPageProxy.h:
     60
     61        * UIProcess/WebsiteData/WebsiteDataStore.cpp:
     62        (WebKit::WebsiteDataStore::openWindowFromServiceWorker):
     63        * UIProcess/WebsiteData/WebsiteDataStore.h:
     64
     65        * UIProcess/WebsiteData/WebsiteDataStoreClient.h:
     66        (WebKit::WebsiteDataStoreClient::openWindowFromServiceWorker):
     67
     68        * WebProcess/Notifications/WebNotificationManager.cpp:
     69        (WebKit::WebNotificationManager::show):
     70        (WebKit::WebNotificationManager::didShowNotification):
     71        (WebKit::WebNotificationManager::didClickNotification):
     72
     73        * WebProcess/Storage/WebSWContextManagerConnection.cpp:
     74        (WebKit::WebSWContextManagerConnection::openWindow):
     75        * WebProcess/Storage/WebSWContextManagerConnection.h:
     76
    1772022-03-28  Youenn Fablet  <youenn@apple.com>
    278
  • trunk/Source/WebKit/NetworkProcess/ServiceWorker/WebSWServerConnection.cpp

    r291938 r291979  
    176176    });
    177177
    178     ServiceWorkerClientData data { clientIdentifier, ServiceWorkerClientType::Window, ServiceWorkerClientFrameType::None, request.url(), request.isAppInitiated() ? WebCore::LastNavigationWasAppInitiated::Yes : WebCore::LastNavigationWasAppInitiated::No };
     178    ServiceWorkerClientData data { clientIdentifier, ServiceWorkerClientType::Window, ServiceWorkerClientFrameType::None, request.url(), { }, request.isAppInitiated() ? WebCore::LastNavigationWasAppInitiated::Yes : WebCore::LastNavigationWasAppInitiated::No };
    179179    registerServiceWorkerClient(SecurityOriginData { registration.key().topOrigin() }, WTFMove(data), registration.identifier(), request.httpUserAgent());
    180180}
  • trunk/Source/WebKit/NetworkProcess/ServiceWorker/WebSWServerToContextConnection.cpp

    r291938 r291979  
    158158}
    159159
     160void WebSWServerToContextConnection::openWindow(WebCore::ServiceWorkerIdentifier identifier, const String& urlString, CompletionHandler<void(std::optional<WebCore::PageIdentifier>&&)>&& callback)
     161{
     162    auto* server = this->server();
     163    if (!server) {
     164        callback(std::nullopt);
     165        return;
     166    }
     167
     168    auto* worker = server->workerByID(identifier);
     169    if (!worker) {
     170        callback(std::nullopt);
     171        return;
     172    }
     173
     174    auto innerCallback = [callback = WTFMove(callback)](std::optional<WebCore::PageIdentifier>&& pageIdentifier) mutable {
     175        callback(WTFMove(pageIdentifier));
     176    };
     177
     178    m_connection.networkProcess().parentProcessConnection()->sendWithAsyncReply(Messages::NetworkProcessProxy::OpenWindowFromServiceWorker { server->sessionID(), urlString, worker->origin().clientOrigin }, WTFMove(innerCallback));
     179}
     180
    160181void WebSWServerToContextConnection::matchAllCompleted(uint64_t requestIdentifier, const Vector<ServiceWorkerClientData>& clientsData)
    161182{
  • trunk/Source/WebKit/NetworkProcess/ServiceWorker/WebSWServerToContextConnection.h

    r291938 r291979  
    103103    void connectionIsNoLongerNeeded() final;
    104104    void terminateDueToUnresponsiveness() final;
     105    void openWindow(WebCore::ServiceWorkerIdentifier, const String& urlString, CompletionHandler<void(std::optional<WebCore::PageIdentifier>&&)>&&) final;
    105106
    106107    void connectionClosed();
  • trunk/Source/WebKit/NetworkProcess/ServiceWorker/WebSWServerToContextConnection.messages.in

    r291938 r291979  
    4141    DidFailHeartBeatCheck(WebCore::ServiceWorkerIdentifier identifier)
    4242    SetAsInspected(WebCore::ServiceWorkerIdentifier identifier, bool isInspected)
     43
     44    OpenWindow(WebCore::ServiceWorkerIdentifier identifier, String urlString) -> (std::optional<WebCore::PageIdentifier> newClientData)
    4345}
    4446
  • trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataStore.mm

    r291851 r291979  
    4949#import <WebCore/Credential.h>
    5050#import <WebCore/RegistrationDatabase.h>
     51#import <WebCore/ServiceWorkerClientData.h>
    5152#import <WebCore/WebCoreObjCExtras.h>
    5253#import <wtf/BlockPtr.h>
     
    5758class WebsiteDataStoreClient final : public WebKit::WebsiteDataStoreClient {
    5859public:
    59     explicit WebsiteDataStoreClient(id <_WKWebsiteDataStoreDelegate> delegate)
    60         : m_delegate(delegate)
     60    explicit WebsiteDataStoreClient(WKWebsiteDataStore *dataStore, id<_WKWebsiteDataStoreDelegate> delegate)
     61        : m_dataStore(dataStore)
     62        , m_delegate(delegate)
    6163        , m_hasRequestStorageSpaceSelector([m_delegate.get() respondsToSelector:@selector(requestStorageSpace: frameOrigin: quota: currentSize: spaceRequired: decisionHandler:)])
    6264        , m_hasAuthenticationChallengeSelector([m_delegate.get() respondsToSelector:@selector(didReceiveAuthenticationChallenge: completionHandler:)])
     65        , m_hasOpenWindowSelector([m_delegate.get() respondsToSelector:@selector(websiteDataStore:openWindow:fromServiceWorkerOrigin:completionHandler:)])
    6366    {
    6467    }
     
    105108    }
    106109
     110    void openWindowFromServiceWorker(const String& url, const WebCore::SecurityOriginData& serviceWorkerOrigin, CompletionHandler<void(WebKit::WebPageProxy*)>&& callback)
     111    {
     112        if (!m_hasOpenWindowSelector || !m_delegate || !m_dataStore) {
     113            callback({ });
     114            return;
     115        }
     116
     117        auto checker = WebKit::CompletionHandlerCallChecker::create(m_delegate.getAutoreleased(), @selector(websiteDataStore:openWindow:fromServiceWorkerOrigin:completionHandler:));
     118        auto completionHandler = makeBlockPtr([callback = WTFMove(callback), checker = WTFMove(checker)](WKWebView *newWebView) mutable {
     119            if (checker->completionHandlerHasBeenCalled())
     120                return;
     121            checker->didCallCompletionHandler();
     122
     123            callback(newWebView._page.get());
     124        });
     125
     126        auto nsURL = (NSURL *)URL { url };
     127        auto apiOrigin = API::SecurityOrigin::create(serviceWorkerOrigin);
     128        [m_delegate.getAutoreleased() websiteDataStore:m_dataStore.getAutoreleased() openWindow:nsURL fromServiceWorkerOrigin:wrapper(apiOrigin.get()) completionHandler:completionHandler.get()];
     129    }
     130
     131    WeakObjCPtr<WKWebsiteDataStore> m_dataStore;
    107132    WeakObjCPtr<id <_WKWebsiteDataStoreDelegate> > m_delegate;
    108133    bool m_hasRequestStorageSpaceSelector { false };
    109134    bool m_hasAuthenticationChallengeSelector { false };
     135    bool m_hasOpenWindowSelector { false };
    110136};
    111137
     
    653679{
    654680    _delegate = delegate;
    655     _websiteDataStore->setClient(makeUniqueRef<WebsiteDataStoreClient>(delegate));
     681    _websiteDataStore->setClient(makeUniqueRef<WebsiteDataStoreClient>(self, delegate));
    656682}
    657683
  • trunk/Source/WebKit/UIProcess/API/Cocoa/_WKWebsiteDataStoreDelegate.h

    r260366 r291979  
    2727#import <WebKit/WKFoundation.h>
    2828
     29@class WKSecurityOrigin;
     30@class WKWebsiteDataStore;
     31@class WKWebView;
     32
    2933WK_API_AVAILABLE(macos(10.15), ios(13.0))
    3034@protocol _WKWebsiteDataStoreDelegate <NSObject>
     
    3337- (void)requestStorageSpace:(NSURL *)mainFrameURL frameOrigin:(NSURL *)frameURL quota:(NSUInteger)quota currentSize:(NSUInteger)currentSize spaceRequired:(NSUInteger)spaceRequired decisionHandler:(void (^)(unsigned long long quota))decisionHandler;
    3438- (void)didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler;
    35 
     39- (void)websiteDataStore:(WKWebsiteDataStore *)dataStore openWindow:(NSURL *)url fromServiceWorkerOrigin:(WKSecurityOrigin *)serviceWorkerOrigin completionHandler:(void (^)(WKWebView *newWebView))completionHandler;
    3640@end
  • trunk/Source/WebKit/UIProcess/Network/NetworkProcessProxy.cpp

    r291851 r291979  
    17991799}
    18001800
     1801void NetworkProcessProxy::openWindowFromServiceWorker(PAL::SessionID sessionID, const String& urlString, const WebCore::SecurityOriginData& serviceWorkerOrigin, CompletionHandler<void(std::optional<WebCore::PageIdentifier>&&)>&& callback)
     1802{
     1803    if (auto* store = websiteDataStoreFromSessionID(sessionID)) {
     1804        store->openWindowFromServiceWorker(urlString, serviceWorkerOrigin, WTFMove(callback));
     1805        return;
     1806    }
     1807
     1808    callback(std::nullopt);
     1809}
     1810
    18011811} // namespace WebKit
    18021812
  • trunk/Source/WebKit/UIProcess/Network/NetworkProcessProxy.h

    r291851 r291979  
    300300    void terminateRemoteWorkerContextConnectionWhenPossible(RemoteWorkerType, PAL::SessionID, const WebCore::RegistrableDomain&, WebCore::ProcessIdentifier);
    301301
     302    void openWindowFromServiceWorker(PAL::SessionID, const String& urlString, const WebCore::SecurityOriginData& serviceWorkerOrigin, CompletionHandler<void(std::optional<WebCore::PageIdentifier>&&)>&&);
     303
    302304private:
    303305    explicit NetworkProcessProxy();
  • trunk/Source/WebKit/UIProcess/Network/NetworkProcessProxy.messages.in

    r291630 r291979  
    9292    DataTaskDidReceiveData(WebKit::DataTaskIdentifier identifier, IPC::DataReference data)
    9393    DataTaskDidCompleteWithError(WebKit::DataTaskIdentifier identifier, WebCore::ResourceError error)
     94
     95    OpenWindowFromServiceWorker(PAL::SessionID sessionID, String urlString, struct WebCore::SecurityOriginData serviceWorkerOrigin) -> (std::optional<WebCore::PageIdentifier> newPage)
    9496}
    9597
  • trunk/Source/WebKit/UIProcess/WebPageProxy.cpp

    r291938 r291979  
    48714871            navigation->setClientNavigationActivity(nullptr);
    48724872
    4873         callServiceWorkerLaunchCompletionHandlerIfNecessary();
     4873        callLoadCompletionHandlersIfNecessary(false);
    48744874    }
    48754875
     
    49064906#endif
    49074907
    4908 void WebPageProxy::callServiceWorkerLaunchCompletionHandlerIfNecessary()
     4908void WebPageProxy::callLoadCompletionHandlersIfNecessary(bool success)
    49094909{
    49104910#if ENABLE(SERVICE_WORKER)
    4911     if (m_isServiceWorkerPage && m_serviceWorkerLaunchCompletionHandler)
     4911    if (m_isServiceWorkerPage && m_serviceWorkerLaunchCompletionHandler && !success)
    49124912        m_serviceWorkerLaunchCompletionHandler(false);
    49134913#endif
     4914
     4915    if (m_serviceWorkerOpenWindowCompletionCallback)
     4916        m_serviceWorkerOpenWindowCompletionCallback(success);
    49144917}
    49154918
     
    51355138
    51365139        notifyProcessPoolToPrewarm();
     5140
     5141        callLoadCompletionHandlersIfNecessary(true);
    51375142    }
    51385143
     
    51835188            navigation->setClientNavigationActivity(nullptr);
    51845189
    5185         callServiceWorkerLaunchCompletionHandlerIfNecessary();
     5190        callLoadCompletionHandlersIfNecessary(false);
    51865191    }
    51875192}
     
    80198024
    80208025    if (resetStateReason != ResetStateReason::NavigationSwap)
    8021         callServiceWorkerLaunchCompletionHandlerIfNecessary();
     8026        callLoadCompletionHandlersIfNecessary(false);
    80228027
    80238028    if (m_openPanelResultListener) {
  • trunk/Source/WebKit/UIProcess/WebPageProxy.h

    r291938 r291979  
    20822082    void interactableRegionsInRootViewCoordinates(WebCore::FloatRect, CompletionHandler<void(Vector<WebCore::FloatRect>)>&&);
    20832083
     2084#if ENABLE(SERVICE_WORKER)
     2085    void setServiceWorkerOpenWindowCompletionCallback(CompletionHandler<void(bool)>&& completionCallback)
     2086    {
     2087        ASSERT(!m_serviceWorkerOpenWindowCompletionCallback);
     2088        m_serviceWorkerOpenWindowCompletionCallback = WTFMove(completionCallback);
     2089    }
     2090#endif
     2091
    20842092private:
    20852093    WebPageProxy(PageClient&, WebProcessProxy&, Ref<API::PageConfiguration>&&);
     
    26082616    void didFinishServiceWorkerPageRegistration(bool success);
    26092617#endif
    2610     void callServiceWorkerLaunchCompletionHandlerIfNecessary();
     2618    void callLoadCompletionHandlersIfNecessary(bool success);
    26112619
    26122620#if PLATFORM(IOS_FAMILY)
     
    31203128    bool m_isServiceWorkerPage { false };
    31213129    CompletionHandler<void(bool)> m_serviceWorkerLaunchCompletionHandler;
     3130    CompletionHandler<void(bool)> m_serviceWorkerOpenWindowCompletionCallback;
    31223131#endif
    31233132
  • trunk/Source/WebKit/UIProcess/WebsiteData/WebsiteDataStore.cpp

    r291851 r291979  
    20882088}
    20892089
    2090 }
     2090void WebsiteDataStore::openWindowFromServiceWorker(const String& urlString, const WebCore::SecurityOriginData& serviceWorkerOrigin, CompletionHandler<void(std::optional<WebCore::PageIdentifier>)>&& callback)
     2091{
     2092    auto innerCallback = [callback = WTFMove(callback)] (WebPageProxy* newPage) mutable {
     2093        if (!newPage) {
     2094            callback(std::nullopt);
     2095            return;
     2096        }
     2097
     2098        if (!newPage->pageLoadState().isLoading()) {
     2099            RELEASE_LOG(Loading, "The WKWebView provided in response to a ServiceWorker openWindow request was not in the loading state");
     2100            callback(std::nullopt);
     2101            return;
     2102        }
     2103
     2104        auto innerCallback = [pageID = newPage->identifier(), callback = WTFMove(callback)] (bool success) mutable {
     2105            auto* newPage = WebProcessProxy::webPage(pageID);
     2106            if (!newPage || !success) {
     2107                callback(std::nullopt);
     2108                return;
     2109            }
     2110
     2111            callback(newPage->webPageID());
     2112        };
     2113
     2114        newPage->setServiceWorkerOpenWindowCompletionCallback(WTFMove(innerCallback));
     2115    };
     2116
     2117    m_client->openWindowFromServiceWorker(urlString, serviceWorkerOrigin, WTFMove(innerCallback));
     2118}
     2119
     2120}
  • trunk/Source/WebKit/UIProcess/WebsiteData/WebsiteDataStore.h

    r291851 r291979  
    380380    void didDestroyServiceWorkerNotification(const UUID& notificationID);
    381381
     382    void openWindowFromServiceWorker(const String& urlString, const WebCore::SecurityOriginData& serviceWorkerOrigin, CompletionHandler<void(std::optional<WebCore::PageIdentifier>)>&&);
     383
    382384private:
    383385    enum class ForceReinitialization : bool { No, Yes };
  • trunk/Source/WebKit/UIProcess/WebsiteData/WebsiteDataStoreClient.h

    r278253 r291979  
    3737namespace WebKit {
    3838
     39class WebPageProxy;
     40
    3941class WebsiteDataStoreClient {
    4042    WTF_MAKE_FAST_ALLOCATED;
     
    5153        challenge->listener().completeChallenge(AuthenticationChallengeDisposition::PerformDefaultHandling);
    5254    }
     55
     56    virtual void openWindowFromServiceWorker(const String&, const WebCore::SecurityOriginData&, CompletionHandler<void(WebPageProxy*)>&& completionHandler)
     57    {
     58        completionHandler(nullptr);
     59    }
    5360};
    5461
  • trunk/Source/WebKit/WebProcess/Notifications/WebNotificationManager.cpp

    r289721 r291979  
    151151bool WebNotificationManager::show(Notification& notification, WebPage* page)
    152152{
     153    LOG(Notifications, "WebProcess %i going to show notification %s", getpid(), notification.identifier().toString().utf8().data());
     154
    153155    ASSERT(isMainRunLoop());
    154156#if ENABLE(NOTIFICATIONS)
     
    209211    ASSERT(isMainRunLoop());
    210212
     213    LOG(Notifications, "WebProcess %i DID SHOW notification %s", getpid(), notificationID.toString().utf8().data());
     214
    211215#if ENABLE(NOTIFICATIONS)
    212216    RefPtr<Notification> notification = m_notificationIDMap.get(notificationID);
     
    224228    ASSERT(isMainRunLoop());
    225229
     230    LOG(Notifications, "WebProcess %i DID CLICK notification %s", getpid(), notificationID.toString().utf8().data());
     231
    226232#if ENABLE(NOTIFICATIONS)
    227233    RefPtr<Notification> notification = m_notificationIDMap.get(notificationID);
    228234    if (!notification)
    229235        return;
     236
     237    LOG(Notifications, "WebProcess %i handling click event for notification %s", getpid(), notificationID.toString().utf8().data());
    230238
    231239    // Indicate that this event is being dispatched in reaction to a user's interaction with a platform notification.
  • trunk/Source/WebKit/WebProcess/Storage/WebSWContextManagerConnection.cpp

    r291938 r291979  
    333333}
    334334
     335void WebSWContextManagerConnection::openWindow(WebCore::ServiceWorkerIdentifier serviceWorkerIdentifier, const String& url, CompletionHandler<void(std::optional<WebCore::PageIdentifier>&&)>&& callback)
     336{
     337    m_connectionToNetworkProcess->sendWithAsyncReply(Messages::WebSWServerToContextConnection::OpenWindow { serviceWorkerIdentifier, url }, WTFMove(callback));
     338}
     339
    335340void WebSWContextManagerConnection::claim(ServiceWorkerIdentifier serviceWorkerIdentifier, CompletionHandler<void(ExceptionOr<void>&&)>&& callback)
    336341{
  • trunk/Source/WebKit/WebProcess/Storage/WebSWContextManagerConnection.h

    r291938 r291979  
    8888    void didFailHeartBeatCheck(WebCore::ServiceWorkerIdentifier) final;
    8989    void setAsInspected(WebCore::ServiceWorkerIdentifier, bool) final;
     90    void openWindow(WebCore::ServiceWorkerIdentifier, const String& url, CompletionHandler<void(std::optional<WebCore::PageIdentifier>&&)>&&) final;
    9091
    9192    // IPC messages.
  • trunk/Tools/ChangeLog

    r291966 r291979  
     12022-03-28  Brady Eidson  <beidson@apple.com>
     2
     3        Support ServiceWorkerClients.openWindow.
     4        <rdar://90616651> and https://bugs.webkit.org/show_bug.cgi?id=238400
     5
     6        Reviewed by Youenn Fablet.
     7
     8        Implement the new delegate to create the new view.
     9       
     10        * WebKitTestRunner/TestController.cpp:
     11        (WTR::TestController::createOtherPage):
     12        (WTR::TestController::createOtherPlatformWebView):
     13        * WebKitTestRunner/TestController.h:
     14       
     15        * WebKitTestRunner/cocoa/TestControllerCocoa.mm:
     16        (WTR::TestController::platformCreateOtherPage):
     17        * WebKitTestRunner/cocoa/TestWebsiteDataStoreDelegate.mm:
     18        (-[TestWebsiteDataStoreDelegate websiteDataStore:openWindow:fromServiceWorkerOrigin:completionHandler:]):
     19
    1202022-03-28  Noam Rosenthal  <noam@webkit.org>
    221
  • trunk/Tools/WebKitTestRunner/TestController.cpp

    r291737 r291979  
    382382WKPageRef TestController::createOtherPage(PlatformWebView* parentView, WKPageConfigurationRef configuration, WKNavigationActionRef navigationAction, WKWindowFeaturesRef windowFeatures)
    383383{
     384    auto* platformWebView = createOtherPlatformWebView(parentView, configuration, navigationAction, windowFeatures);
     385    if (!platformWebView)
     386        return nullptr;
     387
     388    auto* page = platformWebView->page();
     389    WKRetain(page);
     390    return page;
     391}
     392
     393PlatformWebView* TestController::createOtherPlatformWebView(PlatformWebView* parentView, WKPageConfigurationRef configuration, WKNavigationActionRef, WKWindowFeaturesRef)
     394{
    384395    m_currentInvocation->willCreateNewPage();
    385396
     
    390401    m_createdOtherPage = true;
    391402
    392     auto view = platformCreateOtherPage(parentView, configuration, parentView->options());
     403    auto options = parentView ? parentView->options() : m_mainWebView->options();
     404    auto view = platformCreateOtherPage(parentView, configuration, options);
    393405    WKPageRef newPage = view->page();
    394406
     
    510522    TestController::singleton().updateWindowScaleForTest(view.ptr(), *TestController::singleton().m_currentInvocation);
    511523
     524    PlatformWebView* viewToReturn = view.ptr();
    512525    m_auxiliaryWebViews.append(WTFMove(view));
    513     WKRetain(newPage);
    514     return newPage;
     526    return viewToReturn;
    515527}
    516528
  • trunk/Tools/WebKitTestRunner/TestController.h

    r291737 r291979  
    379379    bool denyNotificationPermissionOnPrompt(WKStringRef origin);
    380380
     381    PlatformWebView* createOtherPlatformWebView(PlatformWebView* parentView, WKPageConfigurationRef, WKNavigationActionRef, WKWindowFeaturesRef);
     382
    381383private:
    382384    WKRetainPtr<WKPageConfigurationRef> generatePageConfiguration(const TestOptions&);
  • trunk/Tools/WebKitTestRunner/cocoa/TestControllerCocoa.mm

    r290098 r291979  
    215215{
    216216    auto newConfiguration = adoptNS([globalWebViewConfiguration() copy]);
    217     [newConfiguration _setRelatedWebView:static_cast<WKWebView*>(parentView->platformView())];
     217    if (parentView)
     218        [newConfiguration _setRelatedWebView:static_cast<WKWebView*>(parentView->platformView())];
    218219    if ([newConfiguration _relatedWebView])
    219220        [newConfiguration setWebsiteDataStore:[newConfiguration _relatedWebView].configuration.websiteDataStore];
  • trunk/Tools/WebKitTestRunner/cocoa/TestWebsiteDataStoreDelegate.mm

    r249096 r291979  
    2626#import "config.h"
    2727#import "TestWebsiteDataStoreDelegate.h"
     28
     29#import "PlatformWebView.h"
     30#import "TestController.h"
     31#import "TestRunnerWKWebView.h"
     32#import <WebKit/WKWebView.h>
     33#import <wtf/UniqueRef.h>
    2834
    2935@implementation TestWebsiteDataStoreDelegate { }
     
    6268}
    6369
     70- (void)websiteDataStore:(WKWebsiteDataStore *)dataStore openWindow:(NSURL *)url fromServiceWorkerOrigin:(WKSecurityOrigin *)serviceWorkerOrigin completionHandler:(void (^)(WKWebView *newWebView))completionHandler
     71{
     72    auto* newView = WTR::TestController::singleton().createOtherPlatformWebView(nullptr, nullptr, nullptr, nullptr);
     73    WKWebView *webView = newView->platformView();
     74
     75    ASSERT(webView.configuration.websiteDataStore == dataStore);
     76
     77    [webView loadRequest:[NSURLRequest requestWithURL:url]];
     78    completionHandler(webView);
     79}
     80
    6481@end
Note: See TracChangeset for help on using the changeset viewer.