Changeset 292459 in webkit


Ignore:
Timestamp:
Apr 6, 2022 4:17:25 AM (4 months ago)
Author:
youenn@apple.com
Message:

Implement ServiceWorkerWindowClient.navigate
https://bugs.webkit.org/show_bug.cgi?id=238738

Reviewed by Chris Dumez.

LayoutTests/imported/w3c:

  • web-platform-tests/service-workers/service-worker/windowclient-navigate.https-expected.txt:

Source/WebCore:

Introduce a routine to navigate a Document.
Send FrameIdentifier as part of ServiceWorkerClientData.
Implement ServiceWorkerWindowClient::navigate by sending IPC to network process.

Test: http/wpt/service-workers/navigate-iframes-window-client.https.html

  • dom/Document.cpp:
  • dom/Document.h:
  • loader/FrameLoader.cpp:
  • workers/service/ServiceWorkerClientData.cpp:
  • workers/service/ServiceWorkerClientData.h:
  • workers/service/ServiceWorkerWindowClient.cpp:
  • workers/service/context/SWContextManager.h:
  • workers/service/server/SWServer.cpp:
  • workers/service/server/SWServer.h:
  • workers/service/server/SWServerWorker.cpp:
  • workers/service/server/SWServerWorker.h:

Source/WebKit:

When receiving a request to navigate a client, send message to UIProcess.
UIProcess locates the WebFrameProxy which will send an IPC message to the WebProcess to do navigation.
We keep track of the navigation within WebFrameProxy.
In case of process swapping, we make sure to transfer the WebFrameProxy callback.
In case of policy decision to stop loads, we resolve the promise with an empty client.
A follow-up patch may reject the promise once the expected behavior will be clarified.

  • NetworkProcess/ServiceWorker/WebSWServerConnection.cpp:
  • NetworkProcess/ServiceWorker/WebSWServerConnection.h:
  • NetworkProcess/ServiceWorker/WebSWServerToContextConnection.cpp:
  • NetworkProcess/ServiceWorker/WebSWServerToContextConnection.h:
  • NetworkProcess/ServiceWorker/WebSWServerToContextConnection.messages.in:
  • UIProcess/Network/NetworkProcessProxy.cpp:
  • UIProcess/Network/NetworkProcessProxy.h:
  • UIProcess/Network/NetworkProcessProxy.messages.in:
  • UIProcess/ProvisionalPageProxy.cpp:
  • UIProcess/WebFrameProxy.cpp:
  • UIProcess/WebFrameProxy.h:
  • UIProcess/WebPageProxy.cpp:
  • WebProcess/Storage/WebSWContextManagerConnection.cpp:
  • WebProcess/Storage/WebSWContextManagerConnection.h:
  • WebProcess/WebCoreSupport/WebFrameLoaderClient.cpp:
  • WebProcess/WebPage/WebPage.cpp:
  • WebProcess/WebPage/WebPage.h:
  • WebProcess/WebPage/WebPage.messages.in:

Tools:

  • TestWebKitAPI/Tests/WebKitCocoa/ServiceWorkerBasic.mm:

LayoutTests:

  • http/wpt/service-workers/navigate-iframes-window-client.https-expected.txt: Added.
  • http/wpt/service-workers/navigate-iframes-window-client.https.html: Added.
  • http/wpt/service-workers/navigate-window-client-worker.js: Added.
  • platform/glib/TestExpectations:
  • platform/glib/imported/w3c/web-platform-tests/service-workers/service-worker/windowclient-navigate.https-expected.txt: Removed.
  • platform/mac-wk2/TestExpectations:
Location:
trunk
Files:
3 added
1 deleted
35 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r292449 r292459  
     12022-04-06  Youenn Fablet  <youenn@apple.com>
     2
     3        Implement ServiceWorkerWindowClient.navigate
     4        https://bugs.webkit.org/show_bug.cgi?id=238738
     5
     6        Reviewed by Chris Dumez.
     7
     8        * http/wpt/service-workers/navigate-iframes-window-client.https-expected.txt: Added.
     9        * http/wpt/service-workers/navigate-iframes-window-client.https.html: Added.
     10        * http/wpt/service-workers/navigate-window-client-worker.js: Added.
     11        * platform/glib/TestExpectations:
     12        * platform/glib/imported/w3c/web-platform-tests/service-workers/service-worker/windowclient-navigate.https-expected.txt: Removed.
     13        * platform/mac-wk2/TestExpectations:
     14
    1152022-04-05  Ada Chan  <adachan@apple.com>
    216
  • trunk/LayoutTests/imported/w3c/ChangeLog

    r292432 r292459  
     12022-04-06  Youenn Fablet  <youenn@apple.com>
     2
     3        Implement ServiceWorkerWindowClient.navigate
     4        https://bugs.webkit.org/show_bug.cgi?id=238738
     5
     6        Reviewed by Chris Dumez.
     7
     8        * web-platform-tests/service-workers/service-worker/windowclient-navigate.https-expected.txt:
     9
    1102022-04-05  Matt Woodrow  <mattwoodrow@apple.com>
    211
  • trunk/LayoutTests/imported/w3c/web-platform-tests/service-workers/service-worker/windowclient-navigate.https-expected.txt

    r289558 r292459  
    1111PASS invalid url (about:blank)
    1212PASS navigate on a top-level window client
    13 FAIL normal worker side promise_test: Unhandled rejection with value: object "NotSupportedError: windowClient.navigate() is not yet supported"
    14 FAIL blank url worker side promise_test: Unhandled rejection with value: object "NotSupportedError: windowClient.navigate() is not yet supported"
    15 FAIL in scope but not controlled test on installing worker worker side promise_rejects_js: function "function () { throw e }" threw object "NotSupportedError: windowClient.navigate() is not yet supported" ("NotSupportedError") expected instance of function "function TypeError() {
    16     [native code]
    17 }" ("TypeError")
    18 FAIL in scope but not controlled test on active worker worker side promise_rejects_js: function "function () { throw e }" threw object "NotSupportedError: windowClient.navigate() is not yet supported" ("NotSupportedError") expected instance of function "function TypeError() {
    19     [native code]
    20 }" ("TypeError")
    21 FAIL out of scope worker side promise_rejects_js: function "function () { throw e }" threw object "NotSupportedError: windowClient.navigate() is not yet supported" ("NotSupportedError") expected instance of function "function TypeError() {
    22     [native code]
    23 }" ("TypeError")
    24 FAIL cross orgin url worker side promise_test: Unhandled rejection with value: object "NotSupportedError: windowClient.navigate() is not yet supported"
    25 FAIL invalid url (http://[example.com]) worker side promise_rejects_js: function "function () { throw e }" threw object "NotSupportedError: windowClient.navigate() is not yet supported" ("NotSupportedError") expected instance of function "function TypeError() {
    26     [native code]
    27 }" ("TypeError")
    28 FAIL invalid url (view-source://example.com) worker side promise_rejects_js: function "function () { throw e }" threw object "NotSupportedError: windowClient.navigate() is not yet supported" ("NotSupportedError") expected instance of function "function TypeError() {
    29     [native code]
    30 }" ("TypeError")
    31 FAIL invalid url (file:///) worker side promise_rejects_js: function "function () { throw e }" threw object "NotSupportedError: windowClient.navigate() is not yet supported" ("NotSupportedError") expected instance of function "function TypeError() {
    32     [native code]
    33 }" ("TypeError")
    34 FAIL invalid url (about:blank) worker side promise_rejects_js: function "function () { throw e }" threw object "NotSupportedError: windowClient.navigate() is not yet supported" ("NotSupportedError") expected instance of function "function TypeError() {
    35     [native code]
    36 }" ("TypeError")
     13PASS normal worker side
     14PASS blank url worker side
     15PASS in scope but not controlled test on installing worker worker side
     16PASS in scope but not controlled test on active worker worker side
     17PASS out of scope worker side
     18PASS cross orgin url worker side
     19PASS invalid url (http://[example.com]) worker side
     20PASS invalid url (view-source://example.com) worker side
     21FAIL invalid url (file:///) worker side assert_equals: expected (string) "TypeError" but got (object) null
     22PASS invalid url (about:blank) worker side
    3723FAIL navigate on a top-level window client worker side assert_equals: expected "top-level" but got "auxiliary"
    3824
  • trunk/LayoutTests/platform/glib/TestExpectations

    r292086 r292459  
    11941194webkit.org/b/201981 http/wpt/service-workers/server-trust-evaluation.https.html [ Failure ]
    11951195webkit.org/b/201981 imported/w3c/web-platform-tests/service-workers/service-worker/fetch-canvas-tainting-image-cache.https.html [ Failure Pass ]
     1196
     1197webkit.org/b/238738 http/wpt/service-workers/navigate-iframes-window-client.https.html [ Failure ]
     1198webkit.org/b/238738238738 imported/w3c/web-platform-tests/service-workers/service-worker/windowclient-navigate.https.html [ Failure ]
    11961199
    11971200webkit.org/b/208369 http/tests/workers/service/basic-timeout.https.html [ Failure Timeout Pass ]
  • trunk/LayoutTests/platform/mac-wk2/TestExpectations

    r292274 r292459  
    925925webkit.org/b/230412 imported/w3c/web-platform-tests/service-workers/service-worker/clients-matchall-client-types.https.html [ Pass Failure ]
    926926
    927 webkit.org/b/179352 imported/w3c/web-platform-tests/service-workers/service-worker/windowclient-navigate.https.html [ Pass Failure Slow ]
     927webkit.org/b/179352 imported/w3c/web-platform-tests/service-workers/service-worker/windowclient-navigate.https.html [ Slow ]
    928928
    929929webkit.org/b/183164 fast/dom/Window/window-focus-self.html [ Pass Failure ]
  • trunk/Source/WebCore/ChangeLog

    r292456 r292459  
     12022-04-06  Youenn Fablet  <youenn@apple.com>
     2
     3        Implement ServiceWorkerWindowClient.navigate
     4        https://bugs.webkit.org/show_bug.cgi?id=238738
     5
     6        Reviewed by Chris Dumez.
     7
     8        Introduce a routine to navigate a Document.
     9        Send FrameIdentifier as part of ServiceWorkerClientData.
     10        Implement ServiceWorkerWindowClient::navigate by sending IPC to network process.
     11
     12        Test: http/wpt/service-workers/navigate-iframes-window-client.https.html
     13
     14        * dom/Document.cpp:
     15        * dom/Document.h:
     16        * loader/FrameLoader.cpp:
     17        * workers/service/ServiceWorkerClientData.cpp:
     18        * workers/service/ServiceWorkerClientData.h:
     19        * workers/service/ServiceWorkerWindowClient.cpp:
     20        * workers/service/context/SWContextManager.h:
     21        * workers/service/server/SWServer.cpp:
     22        * workers/service/server/SWServer.h:
     23        * workers/service/server/SWServerWorker.cpp:
     24        * workers/service/server/SWServerWorker.h:
     25
    1262022-04-06  Youenn Fablet  <youenn@apple.com>
    227
  • trunk/Source/WebCore/dom/Document.cpp

    r292277 r292459  
    84158415std::optional<FrameIdentifier> Document::frameID() const
    84168416{
    8417     return m_frame->loader().frameID();
     8417    return m_frame ? m_frame->loader().frameID() : std::nullopt;
    84188418}
    84198419
     
    87818781    m_serviceWorkerConnection->registerServiceWorkerClient(topOrigin(), ServiceWorkerClientData::from(*this), controllingServiceWorkerRegistrationIdentifier, userAgent(url()));
    87828782}
     8783
     8784void Document::navigateFromServiceWorker(const URL& url, CompletionHandler<void(bool)>&& callback)
     8785{
     8786    if (activeDOMObjectsAreSuspended() || activeDOMObjectsAreStopped()) {
     8787        callback(false);
     8788        return;
     8789    }
     8790    eventLoop().queueTask(TaskSource::DOMManipulation, [weakThis = WeakPtr { *this }, url, callback = WTFMove(callback)]() mutable {
     8791        auto* frame = weakThis ? weakThis->frame() : nullptr;
     8792        if (!frame) {
     8793            callback(false);
     8794            return;
     8795        }
     8796        frame->navigationScheduler().scheduleLocationChange(*weakThis, weakThis->securityOrigin(), url, frame->loader().outgoingReferrer(), LockHistory::Yes, LockBackForwardList::No, [callback = WTFMove(callback)]() mutable {
     8797            callback(true);
     8798        });
     8799    });
     8800}
    87838801#endif
    87848802
  • trunk/Source/WebCore/dom/Document.h

    r292400 r292459  
    15701570    void setServiceWorkerConnection(SWClientConnection*);
    15711571    void updateServiceWorkerClientData();
     1572    WEBCORE_EXPORT void navigateFromServiceWorker(const URL&, CompletionHandler<void(bool)>&&);
    15721573#endif
    15731574
  • trunk/Source/WebCore/workers/service/ServiceWorkerClientData.cpp

    r292105 r292459  
    6060ServiceWorkerClientData ServiceWorkerClientData::isolatedCopy() const &
    6161{
    62     return { identifier, type, frameType, url.isolatedCopy(), pageIdentifier, lastNavigationWasAppInitiated, isVisible, isFocused, focusOrder, crossThreadCopy(ancestorOrigins) };
     62    return { identifier, type, frameType, url.isolatedCopy(), pageIdentifier, frameIdentifier, lastNavigationWasAppInitiated, isVisible, isFocused, focusOrder, crossThreadCopy(ancestorOrigins) };
    6363}
    6464
    6565ServiceWorkerClientData ServiceWorkerClientData::isolatedCopy() &&
    6666{
    67     return { identifier, type, frameType, WTFMove(url).isolatedCopy(), pageIdentifier, lastNavigationWasAppInitiated, isVisible, isFocused, focusOrder, crossThreadCopy(WTFMove(ancestorOrigins)) };
     67    return { identifier, type, frameType, WTFMove(url).isolatedCopy(), pageIdentifier, frameIdentifier, lastNavigationWasAppInitiated, isVisible, isFocused, focusOrder, crossThreadCopy(WTFMove(ancestorOrigins)) };
    6868}
    6969
     
    8888        document.creationURL(),
    8989        document.pageID(),
     90        document.frameID(),
    9091        lastNavigationWasAppInitiated,
    9192        !document.hidden(),
  • trunk/Source/WebCore/workers/service/ServiceWorkerClientData.h

    r292105 r292459  
    2828#if ENABLE(SERVICE_WORKER)
    2929
     30#include "FrameIdentifier.h"
    3031#include "PageIdentifier.h"
    3132#include "ProcessQualified.h"
     
    5051    URL url;
    5152    std::optional<PageIdentifier> pageIdentifier;
     53    std::optional<FrameIdentifier> frameIdentifier;
    5254    LastNavigationWasAppInitiated lastNavigationWasAppInitiated;
    5355    bool isVisible { false };
     
    6870void ServiceWorkerClientData::encode(Encoder& encoder) const
    6971{
    70     encoder << identifier << type << frameType << url << pageIdentifier << lastNavigationWasAppInitiated << isVisible << isFocused << focusOrder << ancestorOrigins;
     72    encoder << identifier << type << frameType << url << pageIdentifier << frameIdentifier << lastNavigationWasAppInitiated << isVisible << isFocused << focusOrder << ancestorOrigins;
    7173}
    7274
     
    99101        return std::nullopt;
    100102
     103    std::optional<std::optional<FrameIdentifier>> frameIdentifier;
     104    decoder >> frameIdentifier;
     105    if (!frameIdentifier)
     106        return std::nullopt;
     107
    101108    std::optional<LastNavigationWasAppInitiated> lastNavigationWasAppInitiated;
    102109    decoder >> lastNavigationWasAppInitiated;
     
    124131        return std::nullopt;
    125132
    126     return { { WTFMove(*identifier), WTFMove(*type), WTFMove(*frameType), WTFMove(*url), WTFMove(*pageIdentifier), WTFMove(*lastNavigationWasAppInitiated), WTFMove(*isVisible), WTFMove(*isFocused), WTFMove(*focusOrder), WTFMove(*ancestorOrigins) } };
     133    return { { WTFMove(*identifier), WTFMove(*type), WTFMove(*frameType), WTFMove(*url), WTFMove(*pageIdentifier), WTFMove(*frameIdentifier), WTFMove(*lastNavigationWasAppInitiated), WTFMove(*isVisible), WTFMove(*isFocused), WTFMove(*focusOrder), WTFMove(*ancestorOrigins) } };
    127134}
    128135
  • trunk/Source/WebCore/workers/service/ServiceWorkerWindowClient.cpp

    r291960 r292459  
    7272}
    7373
    74 void ServiceWorkerWindowClient::navigate(ScriptExecutionContext&, const String& url, Ref<DeferredPromise>&& promise)
     74void ServiceWorkerWindowClient::navigate(ScriptExecutionContext& context, const String& urlString, Ref<DeferredPromise>&& promise)
    7575{
    76     UNUSED_PARAM(url);
    77     promise->reject(Exception { NotSupportedError, "windowClient.navigate() is not yet supported"_s });
     76    auto url = context.completeURL(urlString);
     77
     78    if (!url.isValid()) {
     79        promise->reject(Exception { TypeError, makeString("URL string ", urlString, " cannot successfully be parsed") });
     80        return;
     81    }
     82
     83    if (url.protocolIsAbout()) {
     84        promise->reject(Exception { TypeError, makeString("ServiceWorkerClients.navigate() cannot be called with URL ", url.string()) });
     85        return;
     86    }
     87
     88    // We implement step 4 (checking of client's active service worker) in network process as we cannot do it synchronously.
     89    auto& serviceWorkerContext = downcast<ServiceWorkerGlobalScope>(context);
     90    auto promiseIdentifier = serviceWorkerContext.clients().addPendingPromise(WTFMove(promise));
     91    callOnMainThread([clientIdentifier = identifier(), promiseIdentifier, serviceWorkerIdentifier = serviceWorkerContext.thread().identifier(), url = WTFMove(url).isolatedCopy()]() mutable {
     92        SWContextManager::singleton().connection()->navigate(clientIdentifier, serviceWorkerIdentifier, url, [promiseIdentifier, serviceWorkerIdentifier](auto result) mutable {
     93            SWContextManager::singleton().postTaskToServiceWorker(serviceWorkerIdentifier, [promiseIdentifier, result = crossThreadCopy(WTFMove(result))](auto& serviceWorkerContext) mutable {
     94                auto promise = serviceWorkerContext.clients().takePendingPromise(promiseIdentifier);
     95                if (!promise)
     96                    return;
     97
     98                if (result.hasException()) {
     99                    promise->reject(result.releaseException());
     100                    return;
     101                }
     102                auto clientData = result.releaseReturnValue();
     103                if (!clientData) {
     104                    promise->resolveWithJSValue(JSC::jsNull());
     105                    return;
     106                }
     107#if ASSERT_ENABLED
     108                auto originData = SecurityOriginData::fromURL(clientData->url);
     109                ClientOrigin clientOrigin { originData, originData };
     110#endif
     111                ASSERT(serviceWorkerContext.clientOrigin() == clientOrigin);
     112                promise->template resolve<IDLInterface<ServiceWorkerWindowClient>>(ServiceWorkerWindowClient::create(serviceWorkerContext, WTFMove(*clientData)));
     113            });
     114        });
     115    });
    78116}
    79117
  • trunk/Source/WebCore/workers/service/context/SWContextManager.h

    r292456 r292459  
    7373        virtual void openWindow(ServiceWorkerIdentifier, const URL&, OpenWindowCallback&&) = 0;
    7474
     75        using NavigateCallback = CompletionHandler<void(ExceptionOr<std::optional<WebCore::ServiceWorkerClientData>>&&)>;
     76        virtual void navigate(ScriptExecutionContextIdentifier, ServiceWorkerIdentifier, const URL&, NavigateCallback&&) = 0;
     77
    7578        virtual void didFailHeartBeatCheck(ServiceWorkerIdentifier) = 0;
    7679        virtual void setAsInspected(ServiceWorkerIdentifier, bool) = 0;
  • trunk/Source/WebCore/workers/service/server/SWServer.cpp

    r292456 r292459  
    10921092}
    10931093
     1094std::optional<ServiceWorkerRegistrationIdentifier> SWServer::clientIdentifierToControllingRegistration(ScriptExecutionContextIdentifier clientIdentifier) const
     1095{
     1096    auto registrationIterator = m_clientToControllingRegistration.find(clientIdentifier);
     1097    if (registrationIterator == m_clientToControllingRegistration.end())
     1098        return { };
     1099    return registrationIterator->value;
     1100}
     1101
    10941102SWServer::ShouldDelayRemoval SWServer::removeContextConnectionIfPossible(const RegistrableDomain& domain)
    10951103{
  • trunk/Source/WebCore/workers/service/server/SWServer.h

    r292456 r292459  
    243243    ShouldDelayRemoval removeContextConnectionIfPossible(const RegistrableDomain&);
    244244
     245    std::optional<ServiceWorkerRegistrationIdentifier> clientIdentifierToControllingRegistration(ScriptExecutionContextIdentifier) const;
     246    WEBCORE_EXPORT void forEachClientForOrigin(const ClientOrigin&, const Function<void(ServiceWorkerClientData&)>&);
     247
    245248private:
    246249    void validateRegistrationDomain(WebCore::RegistrableDomain, ServiceWorkerJobType, CompletionHandler<void(bool)>&&);
     
    262265
    263266    SWServerRegistration* registrationFromServiceWorkerIdentifier(ServiceWorkerIdentifier);
    264     void forEachClientForOrigin(const ClientOrigin&, const Function<void(ServiceWorkerClientData&)>&);
    265267
    266268    void performGetOriginsWithRegistrationsCallbacks();
  • trunk/Source/WebCore/workers/service/server/SWServerWorker.cpp

    r292110 r292459  
    420420}
    421421
     422bool SWServerWorker::isClientActiveServiceWorker(ScriptExecutionContextIdentifier clientIdentifier) const
     423{
     424    if (!m_server)
     425        return false;
     426    auto registrationIdentifier = m_server->clientIdentifierToControllingRegistration(clientIdentifier);
     427    return registrationIdentifier == m_data.registrationIdentifier;
     428}
     429
    422430} // namespace WebCore
    423431
  • trunk/Source/WebCore/workers/service/server/SWServerWorker.h

    r292110 r292459  
    142142    bool shouldContinue() const { return !!m_functionalEventCounter || m_isInspected; }
    143143
     144    WEBCORE_EXPORT bool isClientActiveServiceWorker(ScriptExecutionContextIdentifier) const;
     145
    144146private:
    145147    SWServerWorker(SWServer&, SWServerRegistration&, const URL&, const ScriptBuffer&, const CertificateInfo&, const ContentSecurityPolicyResponseHeaders&, const CrossOriginEmbedderPolicy&, String&& referrerPolicy, WorkerType, ServiceWorkerIdentifier, HashMap<URL, ServiceWorkerContextData::ImportedScript>&&);
  • trunk/Source/WebKit/ChangeLog

    r292458 r292459  
     12022-04-06  Youenn Fablet  <youenn@apple.com>
     2
     3        Implement ServiceWorkerWindowClient.navigate
     4        https://bugs.webkit.org/show_bug.cgi?id=238738
     5
     6        Reviewed by Chris Dumez.
     7
     8        When receiving a request to navigate a client, send message to UIProcess.
     9        UIProcess locates the WebFrameProxy which will send an IPC message to the WebProcess to do navigation.
     10        We keep track of the navigation within WebFrameProxy.
     11        In case of process swapping, we make sure to transfer the WebFrameProxy callback.
     12        In case of policy decision to stop loads, we resolve the promise with an empty client.
     13        A follow-up patch may reject the promise once the expected behavior will be clarified.
     14
     15        * NetworkProcess/ServiceWorker/WebSWServerConnection.cpp:
     16        * NetworkProcess/ServiceWorker/WebSWServerConnection.h:
     17        * NetworkProcess/ServiceWorker/WebSWServerToContextConnection.cpp:
     18        * NetworkProcess/ServiceWorker/WebSWServerToContextConnection.h:
     19        * NetworkProcess/ServiceWorker/WebSWServerToContextConnection.messages.in:
     20        * UIProcess/Network/NetworkProcessProxy.cpp:
     21        * UIProcess/Network/NetworkProcessProxy.h:
     22        * UIProcess/Network/NetworkProcessProxy.messages.in:
     23        * UIProcess/ProvisionalPageProxy.cpp:
     24        * UIProcess/WebFrameProxy.cpp:
     25        * UIProcess/WebFrameProxy.h:
     26        * UIProcess/WebPageProxy.cpp:
     27        * WebProcess/Storage/WebSWContextManagerConnection.cpp:
     28        * WebProcess/Storage/WebSWContextManagerConnection.h:
     29        * WebProcess/WebCoreSupport/WebFrameLoaderClient.cpp:
     30        * WebProcess/WebPage/WebPage.cpp:
     31        * WebProcess/WebPage/WebPage.h:
     32        * WebProcess/WebPage/WebPage.messages.in:
     33
    1342022-04-06  Zan Dobersek  <zdobersek@igalia.com>
    235
  • trunk/Source/WebKit/NetworkProcess/ServiceWorker/WebSWServerConnection.cpp

    r292105 r292459  
    165165}
    166166
    167 void WebSWServerConnection::controlClient(const Vector<RefPtr<SecurityOrigin>>& frameAncestorOrigins, ScriptExecutionContextIdentifier clientIdentifier, SWServerRegistration& registration, const ResourceRequest& request)
    168 {
     167void WebSWServerConnection::controlClient(const NetworkResourceLoadParameters& parameters, SWServerRegistration& registration, const ResourceRequest& request)
     168{
     169    auto clientIdentifier = *parameters.options.clientIdentifier;
    169170    // As per step 12 of https://w3c.github.io/ServiceWorker/#on-fetch-request-algorithm, the active service worker should be controlling the document.
    170     // We register a temporary service worker client using the identifier provided by DocumentLoader and notify DocumentLoader about it.
    171     // If notification is successful, DocumentLoader will unregister the temporary service worker client just after the document is created and registered as a client.
     171    // We register the service worker client using the identifier provided by DocumentLoader and notify DocumentLoader about it.
     172    // If notification is successful, DocumentLoader is responsible to unregister the service worker client as needed.
    172173    sendWithAsyncReply(Messages::WebSWClientConnection::SetDocumentIsControlled { clientIdentifier, registration.data() }, [weakThis = WeakPtr { *this }, this, clientIdentifier](bool isSuccess) {
    173174        if (!weakThis || isSuccess)
     
    176177    });
    177178
    178     auto ancestorOrigins = map(frameAncestorOrigins, [](auto& origin) { return origin->toString(); });
    179     ServiceWorkerClientData data { clientIdentifier, ServiceWorkerClientType::Window, ServiceWorkerClientFrameType::None, request.url(), { }, request.isAppInitiated() ? WebCore::LastNavigationWasAppInitiated::Yes : WebCore::LastNavigationWasAppInitiated::No, false, false, 0, WTFMove(ancestorOrigins) };
     179    auto ancestorOrigins = map(parameters.frameAncestorOrigins, [](auto& origin) { return origin->toString(); });
     180    ServiceWorkerClientData data { clientIdentifier, ServiceWorkerClientType::Window, ServiceWorkerClientFrameType::None, request.url(), parameters.webPageID, parameters.webFrameID, request.isAppInitiated() ? WebCore::LastNavigationWasAppInitiated::Yes : WebCore::LastNavigationWasAppInitiated::No, false, false, 0, WTFMove(ancestorOrigins) };
    180181    registerServiceWorkerClient(SecurityOriginData { registration.key().topOrigin() }, WTFMove(data), registration.identifier(), request.httpUserAgent());
    181182}
     
    202203
    203204        serviceWorkerRegistrationIdentifier = registration->identifier();
    204         controlClient(loader.parameters().frameAncestorOrigins, *loader.parameters().options.clientIdentifier, *registration, request);
     205        controlClient(loader.parameters(), *registration, request);
    205206        loader.setResultingClientIdentifier(loader.parameters().options.clientIdentifier->toString());
    206207    } else {
  • trunk/Source/WebKit/NetworkProcess/ServiceWorker/WebSWServerConnection.h

    r292105 r292459  
    6262
    6363class NetworkProcess;
     64class NetworkResourceLoadParameters;
    6465class NetworkResourceLoader;
    6566class ServiceWorkerFetchTask;
     
    8485    void fetchTaskTimedOut(WebCore::ServiceWorkerIdentifier);
    8586
    86     void focusServiceWorkerClient(WebCore::ScriptExecutionContextIdentifier, CompletionHandler<void(std::optional<WebCore::ServiceWorkerClientData>&&)>&&);
    87 
    8887private:
    8988    // Implement SWServer::Connection (Messages to the client WebProcess)
     
    9897    void setRegistrationUpdateViaCache(WebCore::ServiceWorkerRegistrationIdentifier, WebCore::ServiceWorkerUpdateViaCache) final;
    9998    void notifyClientsOfControllerChange(const HashSet<WebCore::ScriptExecutionContextIdentifier>& contextIdentifiers, const WebCore::ServiceWorkerData& newController);
     99    void focusServiceWorkerClient(WebCore::ScriptExecutionContextIdentifier, CompletionHandler<void(std::optional<WebCore::ServiceWorkerClientData>&&)>&&) final;
    100100
    101101    void scheduleJobInServer(WebCore::ServiceWorkerJobData&&);
     
    130130
    131131    void postMessageToServiceWorker(WebCore::ServiceWorkerIdentifier destination, WebCore::MessageWithMessagePorts&&, const WebCore::ServiceWorkerOrClientIdentifier& source);
    132     void controlClient(const Vector<RefPtr<WebCore::SecurityOrigin>>&, WebCore::ScriptExecutionContextIdentifier, WebCore::SWServerRegistration&, const WebCore::ResourceRequest&);
     132    void controlClient(const NetworkResourceLoadParameters&, WebCore::SWServerRegistration&, const WebCore::ResourceRequest&);
    133133
    134134    using ExceptionOrVoidCallback = CompletionHandler<void(std::optional<WebCore::ExceptionData>&&)>;
  • trunk/Source/WebKit/NetworkProcess/ServiceWorker/WebSWServerToContextConnection.cpp

    r292456 r292459  
    274274}
    275275
     276void WebSWServerToContextConnection::navigate(ScriptExecutionContextIdentifier clientIdentifier, ServiceWorkerIdentifier serviceWorkerIdentifier, const URL& url, CompletionHandler<void(Expected<std::optional<ServiceWorkerClientData>, ExceptionData>&&)>&& callback)
     277{
     278    auto* worker = SWServerWorker::existingWorkerForIdentifier(serviceWorkerIdentifier);
     279    if (!worker) {
     280        callback(makeUnexpected(ExceptionData { TypeError, "no service worker"_s }));
     281        return;
     282    }
     283
     284    if (!worker->isClientActiveServiceWorker(clientIdentifier)) {
     285        callback(makeUnexpected(ExceptionData { TypeError, "service worker is not the client active service worker"_s }));
     286        return;
     287    }
     288
     289    auto data = worker->findClientByIdentifier(clientIdentifier);
     290    if (!data || !data->pageIdentifier || !data->frameIdentifier) {
     291        callback(makeUnexpected(ExceptionData { TypeError, "cannot navigate service worker client"_s }));
     292        return;
     293    }
     294
     295    auto frameIdentifier = *data->frameIdentifier;
     296    m_connection.networkProcess().parentProcessConnection()->sendWithAsyncReply(Messages::NetworkProcessProxy::NavigateServiceWorkerClient { frameIdentifier, clientIdentifier, url }, [weakThis = WeakPtr { *this }, frameIdentifier, url, clientOrigin = worker->origin(), callback = WTFMove(callback)](auto pageIdentifier) mutable {
     297        if (!weakThis || !weakThis->server()) {
     298            callback(makeUnexpected(ExceptionData { TypeError, "service worker is gone"_s }));
     299            return;
     300        }
     301
     302        if (!pageIdentifier) {
     303            callback(makeUnexpected(ExceptionData { TypeError, "navigate failed"_s }));
     304            return;
     305        }
     306
     307        std::optional<ServiceWorkerClientData> clientData;
     308        weakThis->server()->forEachClientForOrigin(clientOrigin, [pageIdentifier, frameIdentifier, url, &clientData](auto& data) {
     309            if (!clientData && data.pageIdentifier && *data.pageIdentifier == *pageIdentifier && data.frameIdentifier && *data.frameIdentifier == frameIdentifier && equalIgnoringFragmentIdentifier(data.url, url))
     310                clientData = data;
     311        });
     312        callback(WTFMove(clientData));
     313    }, 0);
     314}
     315
    276316} // namespace WebKit
    277317
  • trunk/Source/WebKit/NetworkProcess/ServiceWorker/WebSWServerToContextConnection.h

    r292456 r292459  
    101101    void close() final;
    102102    void focus(WebCore::ScriptExecutionContextIdentifier, CompletionHandler<void(std::optional<WebCore::ServiceWorkerClientData>&&)>&&);
     103    void navigate(WebCore::ScriptExecutionContextIdentifier, WebCore::ServiceWorkerIdentifier, const URL&, CompletionHandler<void(Expected<std::optional<WebCore::ServiceWorkerClientData>, WebCore::ExceptionData>&&)>&&);
    103104
    104105    void connectionIsNoLongerNeeded() final;
  • trunk/Source/WebKit/NetworkProcess/ServiceWorker/WebSWServerToContextConnection.messages.in

    r292456 r292459  
    3737    Claim(WebCore::ServiceWorkerIdentifier serviceWorkerIdentifier) -> (std::optional<WebCore::ExceptionData> result)
    3838    Focus(WebCore::ScriptExecutionContextIdentifier serviceWorkerClientIdentifier) -> (std::optional<WebCore::ServiceWorkerClientData> result)
     39    Navigate(WebCore::ScriptExecutionContextIdentifier clientIdentifier, WebCore::ServiceWorkerIdentifier serviceWorkerIdentifier, URL url) -> (Expected<std::optional<WebCore::ServiceWorkerClientData>, WebCore::ExceptionData> result)
    3940    SetScriptResource(WebCore::ServiceWorkerIdentifier identifier, URL scriptURL, WebCore::ServiceWorkerContextData::ImportedScript script)
    4041    PostMessageToServiceWorkerClient(WebCore::ScriptExecutionContextIdentifier destination, struct WebCore::MessageWithMessagePorts message, WebCore::ServiceWorkerIdentifier source, String sourceOrigin)
  • trunk/Source/WebKit/UIProcess/Network/NetworkProcessProxy.cpp

    r292426 r292459  
    18061806}
    18071807
     1808void NetworkProcessProxy::navigateServiceWorkerClient(WebCore::FrameIdentifier frameIdentifier, WebCore::ScriptExecutionContextIdentifier documentIdentifier, const URL& url, CompletionHandler<void(std::optional<WebCore::PageIdentifier>)>&& callback)
     1809{
     1810    auto* process = WebProcessProxy::processForIdentifier(documentIdentifier.processIdentifier());
     1811    auto* frame = process ? process->webFrame(frameIdentifier) : nullptr;
     1812    if (!frame) {
     1813        callback({ });
     1814        return;
     1815    }
     1816    frame->navigateServiceWorkerClient(documentIdentifier, url, WTFMove(callback));
     1817}
     1818
    18081819void NetworkProcessProxy::applicationDidEnterBackground()
    18091820{
  • trunk/Source/WebKit/UIProcess/Network/NetworkProcessProxy.h

    r292110 r292459  
    305305    void openWindowFromServiceWorker(PAL::SessionID, const String& urlString, const WebCore::SecurityOriginData& serviceWorkerOrigin, CompletionHandler<void(std::optional<WebCore::PageIdentifier>&&)>&&);
    306306
     307    void navigateServiceWorkerClient(WebCore::FrameIdentifier, WebCore::ScriptExecutionContextIdentifier, const URL&, CompletionHandler<void(std::optional<WebCore::PageIdentifier>)>&&);
     308
    307309private:
    308310    explicit NetworkProcessProxy();
  • trunk/Source/WebKit/UIProcess/Network/NetworkProcessProxy.messages.in

    r291979 r292459  
    9494
    9595    OpenWindowFromServiceWorker(PAL::SessionID sessionID, String urlString, struct WebCore::SecurityOriginData serviceWorkerOrigin) -> (std::optional<WebCore::PageIdentifier> newPage)
     96    NavigateServiceWorkerClient(WebCore::FrameIdentifier frameIdentifier, WebCore::ScriptExecutionContextIdentifier documentIdentifier, URL url) -> (std::optional<WebCore::PageIdentifier> page)
    9697}
    9798
  • trunk/Source/WebKit/UIProcess/ProvisionalPageProxy.cpp

    r290563 r292459  
    239239    // Restore the main frame's committed URL as some clients may rely on it until the next load is committed.
    240240    RefPtr previousMainFrame = m_page.mainFrame();
    241     if (previousMainFrame)
     241    if (previousMainFrame) {
    242242        m_mainFrame->frameLoadState().setURL(previousMainFrame->url());
     243        previousMainFrame->transferNavigationCallbackToFrame(*m_mainFrame);
     244    }
    243245
    244246    // Normally, notification of a server redirect comes from the WebContent process.
  • trunk/Source/WebKit/UIProcess/WebFrameProxy.cpp

    r284142 r292459  
    5959    WebPasteboardProxy::singleton().didDestroyFrame(this);
    6060#endif
     61
     62    if (m_navigateCallback)
     63        m_navigateCallback({ });
    6164}
    6265
     
    6972        m_activeListener = nullptr;
    7073    }
     74
     75    if (m_navigateCallback)
     76        m_navigateCallback({ });
    7177}
    7278
     
    7985}
    8086
     87std::optional<PageIdentifier> WebFrameProxy::pageIdentifier() const
     88{
     89    if (!m_page)
     90        return { };
     91    return m_page->webPageID();
     92}
     93
     94void WebFrameProxy::navigateServiceWorkerClient(WebCore::ScriptExecutionContextIdentifier documentIdentifier, const URL& url, CompletionHandler<void(std::optional<PageIdentifier>)>&& callback)
     95{
     96    if (!m_page) {
     97        callback({ });
     98        return;
     99    }
     100
     101    m_page->sendWithAsyncReply(Messages::WebPage::NavigateServiceWorkerClient { documentIdentifier, url }, [this, protectedThis = Ref { *this }, url, callback = WTFMove(callback)](bool result) mutable {
     102        if (!result) {
     103            callback({ });
     104            return;
     105        }
     106
     107        if (!m_activeListener) {
     108            callback(pageIdentifier());
     109            return;
     110        }
     111
     112        if (m_navigateCallback)
     113            m_navigateCallback({ });
     114
     115        m_navigateCallback = WTFMove(callback);
     116    });
     117}
     118
    81119void WebFrameProxy::loadURL(const URL& url, const String& referrer)
    82120{
     
    96134}
    97135
    98 void WebFrameProxy::stopLoading() const
     136void WebFrameProxy::stopLoading()
    99137{
    100138    if (!m_page)
     
    105143
    106144    m_page->send(Messages::WebPage::StopLoadingFrame(m_frameID));
     145
     146    if (m_navigateCallback)
     147        m_navigateCallback({ });
    107148}
    108149   
     
    161202{
    162203    m_frameLoadState.didFailProvisionalLoad();
     204
     205    if (m_navigateCallback)
     206        m_navigateCallback({ });
    163207}
    164208
     
    176220{
    177221    m_frameLoadState.didFinishLoad();
     222
     223    if (m_navigateCallback)
     224        m_navigateCallback(pageIdentifier());
    178225}
    179226
     
    181228{
    182229    m_frameLoadState.didFailLoad();
     230
     231    if (m_navigateCallback)
     232        m_navigateCallback({ });
    183233}
    184234
     
    198248        m_activeListener->ignore();
    199249    m_activeListener = WebFramePolicyListenerProxy::create([this, protectedThis = Ref { *this }, completionHandler = WTFMove(completionHandler)] (PolicyAction action, API::WebsitePolicies* policies, ProcessSwapRequestedByClient processSwapRequestedByClient, RefPtr<SafeBrowsingWarning>&& safeBrowsingWarning, std::optional<NavigatingToAppBoundDomain> isNavigatingToAppBoundDomain) mutable {
     250        if (action != PolicyAction::Use && m_navigateCallback)
     251            m_navigateCallback(pageIdentifier());
     252
    200253        completionHandler(action, policies, processSwapRequestedByClient, WTFMove(safeBrowsingWarning), isNavigatingToAppBoundDomain);
    201254        m_activeListener = nullptr;
  • trunk/Source/WebKit/UIProcess/WebFrameProxy.h

    r282889 r292459  
    7878    FrameLoadState& frameLoadState() { return m_frameLoadState; }
    7979
     80    void navigateServiceWorkerClient(WebCore::ScriptExecutionContextIdentifier, const URL&, CompletionHandler<void(std::optional<WebCore::PageIdentifier>)>&&);
     81
    8082    void loadURL(const URL&, const String& referrer = String());
    8183    // Sub frames only. For main frames, use WebPageProxy::loadData.
    8284    void loadData(const IPC::DataReference&, const String& MIMEType, const String& encodingName, const URL& baseURL);
    83     void stopLoading() const;
     85    void stopLoading();
    8486
    8587    const URL& url() const { return m_frameLoadState.url(); }
     
    129131#endif
    130132
     133    void transferNavigationCallbackToFrame(WebFrameProxy& frame) { frame.m_navigateCallback = WTFMove(m_navigateCallback); }
     134
    131135private:
    132136    WebFrameProxy(WebPageProxy&, WebCore::FrameIdentifier);
     137
     138    std::optional<WebCore::PageIdentifier> pageIdentifier() const;
    133139
    134140    WeakPtr<WebPageProxy> m_page;
     
    145151    WebCore::ContentFilterUnblockHandler m_contentFilterUnblockHandler;
    146152#endif
     153    CompletionHandler<void(std::optional<WebCore::PageIdentifier>)> m_navigateCallback;
    147154};
    148155
  • trunk/Source/WebKit/WebProcess/Storage/WebSWContextManagerConnection.cpp

    r292456 r292459  
    356356}
    357357
     358void WebSWContextManagerConnection::navigate(ScriptExecutionContextIdentifier clientIdentifier, ServiceWorkerIdentifier serviceWorkerIdentifier, const URL& url, NavigateCallback&& callback)
     359{
     360    m_connectionToNetworkProcess->sendWithAsyncReply(Messages::WebSWServerToContextConnection::Navigate { clientIdentifier, serviceWorkerIdentifier, url }, [callback = WTFMove(callback)](auto&& result) mutable {
     361        if (!result.has_value()) {
     362            callback(WTFMove(result).error().toException());
     363            return;
     364        }
     365        callback(WTFMove(result).value());
     366    });
     367}
     368
    358369void WebSWContextManagerConnection::focus(ScriptExecutionContextIdentifier clientIdentifier, CompletionHandler<void(std::optional<WebCore::ServiceWorkerClientData>&&)>&& callback)
    359370{
  • trunk/Source/WebKit/WebProcess/Storage/WebSWContextManagerConnection.h

    r292456 r292459  
    8383    void claim(WebCore::ServiceWorkerIdentifier, CompletionHandler<void(WebCore::ExceptionOr<void>&&)>&&) final;
    8484    void focus(WebCore::ScriptExecutionContextIdentifier, CompletionHandler<void(std::optional<WebCore::ServiceWorkerClientData>&&)>&&) final;
     85    void navigate(WebCore::ScriptExecutionContextIdentifier, WebCore::ServiceWorkerIdentifier, const URL&, NavigateCallback&&) final;
    8586    void skipWaiting(WebCore::ServiceWorkerIdentifier, CompletionHandler<void()>&&) final;
    8687    void setScriptResource(WebCore::ServiceWorkerIdentifier, const URL&, const WebCore::ServiceWorkerContextData::ImportedScript&) final;
  • trunk/Source/WebKit/WebProcess/WebPage/WebPage.cpp

    r292408 r292459  
    64406440}
    64416441
     6442void WebPage::navigateServiceWorkerClient(ScriptExecutionContextIdentifier documentIdentifier, const URL& url, CompletionHandler<void(bool)>&& callback)
     6443{
     6444#if ENABLE(SERVICE_WORKER)
     6445    RefPtr document = Document::allDocumentsMap().get(documentIdentifier);
     6446    if (!document) {
     6447        callback(false);
     6448        return;
     6449    }
     6450    document->navigateFromServiceWorker(url, WTFMove(callback));
     6451#else
     6452    UNUSED_PARAM(documentIdentifier);
     6453    UNUSED_PARAM(url);
     6454    callback(false);
     6455#endif
     6456}
     6457
    64426458void WebPage::setAlwaysShowsHorizontalScroller(bool alwaysShowsHorizontalScroller)
    64436459{
  • trunk/Source/WebKit/WebProcess/WebPage/WebPage.h

    r292458 r292459  
    946946
    947947    void interactionRegions(WebCore::FloatRect rectInContentCoordinates, CompletionHandler<void(Vector<WebCore::InteractionRegion>)>&&);
     948    void navigateServiceWorkerClient(WebCore::ScriptExecutionContextIdentifier, const URL&, CompletionHandler<void(bool)>&&);
    948949
    949950#if PLATFORM(COCOA)
  • trunk/Source/WebKit/WebProcess/WebPage/WebPage.messages.in

    r292264 r292459  
    684684
    685685    InteractionRegions(WebCore::FloatRect rectInContentCoordinates) -> (Vector<WebCore::InteractionRegion> regions)
     686
     687    NavigateServiceWorkerClient(WebCore::ScriptExecutionContextIdentifier documentIdentifier, URL url) -> (bool result)
    686688}
  • trunk/Tools/ChangeLog

    r292456 r292459  
     12022-04-06  Youenn Fablet  <youenn@apple.com>
     2
     3        Implement ServiceWorkerWindowClient.navigate
     4        https://bugs.webkit.org/show_bug.cgi?id=238738
     5
     6        Reviewed by Chris Dumez.
     7
     8        * TestWebKitAPI/Tests/WebKitCocoa/ServiceWorkerBasic.mm:
     9
    1102022-04-06  Youenn Fablet  <youenn@apple.com>
    211
  • trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/ServiceWorkerBasic.mm

    r292456 r292459  
    30483048    TestWebKitAPI::Util::run(&done);
    30493049}
     3050
     3051static constexpr auto ServiceWorkerWindowClientNavigateMain =
     3052"<div>test page</div>"
     3053"<script>"
     3054"let worker;"
     3055"async function registerServiceWorker() {"
     3056"    try {"
     3057"        const registration = await navigator.serviceWorker.register('/sw.js');"
     3058"        if (registration.active) {"
     3059"            worker = registration.active;"
     3060"            alert('already active');"
     3061"            return;"
     3062"        }"
     3063"        worker = registration.installing;"
     3064"        worker.addEventListener('statechange', () => {"
     3065"            if (worker.state == 'activated')"
     3066"                alert('successfully registered');"
     3067"        });"
     3068"    } catch(e) {"
     3069"        alert('Exception: ' + e);"
     3070"    }"
     3071"}"
     3072"window.onload = registerServiceWorker;"
     3073""
     3074"function navigateOtherClientToURL(url) {"
     3075"    worker.postMessage({navigateOtherClientToURL: url});"
     3076"    navigator.serviceWorker.onmessage = (event) => {"
     3077"        alert(event.data);"
     3078"    };"
     3079"}"
     3080"</script>"_s;
     3081
     3082static constexpr auto ServiceWorkerWindowClientNavigateJS =
     3083"self.addEventListener('message', async (event) => {"
     3084"   if (event.data && event.data.navigateOtherClientToURL) {"
     3085"       let otherClient;"
     3086"       let currentClients = await self.clients.matchAll();"
     3087"       for (let client of currentClients) {"
     3088"           if (client.id !== event.source.id)"
     3089"               otherClient = client;"
     3090"       }"
     3091"       if (!otherClient) {"
     3092"           event.source.postMessage('failed, no other client, client number = ' + currentClients.length);"
     3093"           return;"
     3094"       }"
     3095"       await otherClient.navigate(event.data.navigateOtherClientToURL).then((client) => {"
     3096"           event.source.postMessage(client ? 'client' : 'none');"
     3097"       }, (e) => {"
     3098"           event.source.postMessage('failed');"
     3099"       });"
     3100"       return;"
     3101"   }"
     3102"});"_s;
     3103
     3104
     3105@interface ServiceWorkerPSONNavigationDelegate : NSObject <WKNavigationDelegatePrivate> {
     3106    @public void (^decidePolicyForNavigationAction)(WKNavigationAction *, void (^)(WKNavigationActionPolicy));
     3107    @public void (^didStartProvisionalNavigationHandler)();
     3108    @public void (^didCommitNavigationHandler)();
     3109}
     3110@end
     3111
     3112@implementation ServiceWorkerPSONNavigationDelegate
     3113
     3114- (instancetype) init
     3115{
     3116    self = [super init];
     3117    return self;
     3118}
     3119
     3120- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
     3121{
     3122    decisionHandler(WKNavigationActionPolicyAllow);
     3123}
     3124
     3125- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler
     3126{
     3127    decisionHandler(WKNavigationResponsePolicyAllow);
     3128}
     3129
     3130@end
     3131
     3132TEST(ServiceWorker, WindowClientNavigate)
     3133{
     3134    [WKWebsiteDataStore _allowWebsiteDataRecordsForAllOrigins];
     3135
     3136    // Start with a clean slate data store
     3137    [[WKWebsiteDataStore defaultDataStore] removeDataOfTypes:[WKWebsiteDataStore allWebsiteDataTypes] modifiedSince:[NSDate distantPast] completionHandler:^() {
     3138        done = true;
     3139    }];
     3140    TestWebKitAPI::Util::run(&done);
     3141    done = false;
     3142
     3143    auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
     3144    for (_WKExperimentalFeature *feature in [WKPreferences _experimentalFeatures]) {
     3145        if ([feature.key isEqualToString:@"CrossOriginOpenerPolicyEnabled"])
     3146            [[configuration preferences] _setEnabled:YES forExperimentalFeature:feature];
     3147        else if ([feature.key isEqualToString:@"CrossOriginEmbedderPolicyEnabled"])
     3148            [[configuration preferences] _setEnabled:YES forExperimentalFeature:feature];
     3149    }
     3150
     3151    auto webView1 = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 300, 300) configuration:configuration.get() addToWindow:YES]);
     3152    auto webView2 = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 300, 300) configuration:configuration.get() addToWindow:YES]);
     3153
     3154    TestWebKitAPI::HTTPServer server({
     3155        { "/"_s, { ServiceWorkerWindowClientNavigateMain } },
     3156        { "/?test"_s, { ServiceWorkerWindowClientNavigateMain } },
     3157        { "/?swap"_s, { {{ "Content-Type"_s, "application/html"_s }, { "Cross-Origin-Opener-Policy"_s, "same-origin"_s } }, ServiceWorkerWindowClientNavigateMain } },
     3158        { "/sw.js"_s, { {{ "Content-Type"_s, "application/javascript"_s }}, ServiceWorkerWindowClientNavigateJS } }
     3159    }, TestWebKitAPI::HTTPServer::Protocol::Http, nullptr, nullptr, 8091);
     3160
     3161    [webView1 loadRequest:server.request()];
     3162    EXPECT_WK_STREQ([webView1 _test_waitForAlert], "successfully registered");
     3163    [webView2 loadRequest:server.request()];
     3164    EXPECT_WK_STREQ([webView2 _test_waitForAlert], "already active");
     3165
     3166    auto navigationDelegate = adoptNS([[ServiceWorkerPSONNavigationDelegate alloc] init]);
     3167    [webView2 setNavigationDelegate:navigationDelegate.get()];
     3168
     3169    auto *baseURL = [[server.request() URL] absoluteString];
     3170
     3171    [webView1 evaluateJavaScript:[NSString stringWithFormat:@"navigateOtherClientToURL('%@')", baseURL] completionHandler: nil];
     3172    EXPECT_WK_STREQ([webView1 _test_waitForAlert], "client");
     3173
     3174    [webView1 evaluateJavaScript:[NSString stringWithFormat:@"navigateOtherClientToURL('%@#test')", baseURL] completionHandler: nil];
     3175    EXPECT_WK_STREQ([webView1 _test_waitForAlert], "client");
     3176
     3177    [webView1 evaluateJavaScript:[NSString stringWithFormat:@"navigateOtherClientToURL('%@?test')", baseURL] completionHandler: nil];
     3178    EXPECT_WK_STREQ([webView1 _test_waitForAlert], "client");
     3179
     3180    [webView1 evaluateJavaScript:[NSString stringWithFormat:@"navigateOtherClientToURL('%@?swap')", baseURL] completionHandler: nil];
     3181    EXPECT_WK_STREQ([webView1 _test_waitForAlert], "client");
     3182}
     3183
     3184TEST(ServiceWorker, WindowClientNavigateCrossOrigin)
     3185{
     3186    [WKWebsiteDataStore _allowWebsiteDataRecordsForAllOrigins];
     3187
     3188    // Start with a clean slate data store
     3189    [[WKWebsiteDataStore defaultDataStore] removeDataOfTypes:[WKWebsiteDataStore allWebsiteDataTypes] modifiedSince:[NSDate distantPast] completionHandler:^() {
     3190        done = true;
     3191    }];
     3192    TestWebKitAPI::Util::run(&done);
     3193    done = false;
     3194
     3195    auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
     3196
     3197    auto webView1 = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 300, 300) configuration:configuration.get() addToWindow:YES]);
     3198    auto webView2 = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 300, 300) configuration:configuration.get() addToWindow:YES]);
     3199
     3200    TestWebKitAPI::HTTPServer server1({
     3201        { "/"_s, { ServiceWorkerWindowClientNavigateMain } },
     3202        { "/?test"_s, { ServiceWorkerWindowClientNavigateMain } },
     3203        { "/?swap"_s, { {{ "Content-Type"_s, "application/html"_s }, { "Cross-Origin-Opener-Policy"_s, "same-origin"_s } }, ServiceWorkerWindowClientNavigateMain } },
     3204        { "/sw.js"_s, { {{ "Content-Type"_s, "application/javascript"_s }}, ServiceWorkerWindowClientNavigateJS } }
     3205    }, TestWebKitAPI::HTTPServer::Protocol::Http, nullptr, nullptr, 8091);
     3206
     3207    TestWebKitAPI::HTTPServer server2({
     3208        { "/"_s, { ServiceWorkerWindowClientNavigateMain } },
     3209        { "/sw.js"_s, { {{ "Content-Type"_s, "application/javascript"_s }}, ServiceWorkerWindowClientNavigateJS } }
     3210    }, TestWebKitAPI::HTTPServer::Protocol::Http, nullptr, nullptr, 9091);
     3211
     3212    [webView1 loadRequest:server1.request()];
     3213    EXPECT_WK_STREQ([webView1 _test_waitForAlert], "successfully registered");
     3214    [webView2 loadRequest:server1.request()];
     3215    EXPECT_WK_STREQ([webView2 _test_waitForAlert], "already active");
     3216    [webView1 evaluateJavaScript:[NSString stringWithFormat:@"navigateOtherClientToURL('%@')", [[server2.request() URL] absoluteString]] completionHandler: nil];
     3217    EXPECT_WK_STREQ([webView1 _test_waitForAlert], "none");
     3218}
Note: See TracChangeset for help on using the changeset viewer.