Title: [260303] trunk
Revision
260303
Author
[email protected]
Date
2020-04-17 17:54:41 -0700 (Fri, 17 Apr 2020)

Log Message

Enable service workers for app-bound domains
https://bugs.webkit.org/show_bug.cgi?id=210451
<rdar://problem/61479474>

Reviewed by Brent Fulgham.

Source/WebCore:

SWServer now retrieves the app-bound domains from the UI Process and
only continues with the load if the proper entitlement is present
or the load is coming from an app-bound domain.

* workers/service/server/SWServer.cpp:
(WebCore::SWServer::addRegistrationFromStore):
(WebCore::SWServer::SWServer):
(WebCore::SWServer::validateRegistrationDomain):
(WebCore::SWServer::scheduleJob):
* workers/service/server/SWServer.h:

Source/WebKit:

* NetworkProcess/NetworkConnectionToWebProcess.cpp:
(WebKit::NetworkConnectionToWebProcess::createFetchTask):
(WebKit::NetworkConnectionToWebProcess::scheduleResourceLoad):
(WebKit::NetworkConnectionToWebProcess::swConnection):
(WebKit::NetworkConnectionToWebProcess::isServiceWorkerAllowed const): Deleted.
* NetworkProcess/NetworkConnectionToWebProcess.h:
Removed ASSERTS and service worker entitlement checks which are now done along with app-bound
domain checks in SWServer.cpp.

* NetworkProcess/NetworkProcess.cpp:
(WebKit::NetworkProcess::initializeNetworkProcess):
(WebKit::NetworkProcess::addWebsiteDataStore):
Remove the check for parentProcessHasServiceWorkerEntitlement() before
adding a serviceWorkerSession. This doesn't do anything except add an
entry to a map, and simplifies the case where we need a session for
app-bound instances which should have service workers but have no entitlement.

Pass the entitlement and a new callback to request app-bound domains
from the UI Process to the SWServer. This will make sure the server
checks for the entitlement or list of app-bound domains before completing a load.

(WebKit::NetworkProcess::registerSWServerConnection):
Remove unnecessary ASSERT for entitlement.

* NetworkProcess/NetworkProcess.h:
* NetworkProcess/NetworkProcess.messages.in:
* NetworkProcess/ios/NetworkProcessIOS.mm:
(WebKit::NetworkProcess::parentProcessHasServiceWorkerEntitlement const):
(WebKit::NetworkProcess::disableServiceWorkerEntitlement):
(WebKit::NetworkProcess::clearServiceWorkerEntitlementOverride):
In order to test this thoroughly, TestWebKitAPI needed a way to
temporarily disable the service worker entitlement. This function
overrides the check for the entitlement if the bool is set, disabling
the entitlement.

* Shared/WebPageCreationParameters.cpp:
(WebKit::WebPageCreationParameters::encode const):
(WebKit::WebPageCreationParameters::decode):
* Shared/WebPageCreationParameters.h:
WebPage needs to know if it is app-bound when created so it can update
the service worker preferences key accordingly.

* Shared/WebPreferences.yaml:
* UIProcess/API/Cocoa/WKPreferences.mm:
(-[WKPreferences _serviceWorkerEntitlementDisabledForTesting]):
(-[WKPreferences _setServiceWorkerEntitlementDisabledForTesting:]):
* UIProcess/API/Cocoa/WKPreferencesPrivate.h:
Disable entitlement for testing.

* UIProcess/API/APIPageConfiguration.cpp:
(API::PageConfiguration::copy const):
* UIProcess/API/APIPageConfiguration.h:
(API::PageConfiguration::limitsNavigationsToAppBoundDomains const):
(API::PageConfiguration::setLimitsNavigationsToAppBoundDomains):
(API::PageConfiguration::limitsNavigationToAppBoundDomains const): Deleted.
(API::PageConfiguration::setLimitsNavigationToAppBoundDomains): Deleted.
(-[WKWebViewConfiguration limitsNavigationsToAppBoundDomains]):
(-[WKWebViewConfiguration setLimitsNavigationsToAppBoundDomains:]):
(-[WKWebViewConfiguration limitsNavigationToAppBoundDomains]): Deleted.
(-[WKWebViewConfiguration setLimitsNavigationToAppBoundDomains:]): Deleted.
* UIProcess/API/Cocoa/WKWebViewConfiguration.mm:
Inconsistent naming (Navigation vs Navigations).

* UIProcess/API/Cocoa/WKWebView.mm:
(-[WKWebView _setupPageConfiguration:]):
Check for entitlement or app-bound webview.

(-[WKWebView _serviceWorkersEnabled:]):
(-[WKWebView _clearServiceWorkerEntitlementOverride:]):
* UIProcess/API/Cocoa/WKWebViewPrivate.h:
Testing SPIs.

* UIProcess/Network/NetworkProcessProxy.cpp:
(WebKit::NetworkProcessProxy::getAppBoundDomains):
* UIProcess/Network/NetworkProcessProxy.h:
* UIProcess/Network/NetworkProcessProxy.messages.in:
Sends the app-bound domains to the Network Process.

* UIProcess/WebPageProxy.cpp:
(WebKit::m_limitsNavigationsToAppBoundDomains):
(WebKit::m_limitsNavigationToAppBoundDomains): Deleted.
Naming inconsistency.

(WebKit::WebPageProxy::disableServiceWorkerEntitlementInNetworkProcess):
(WebKit::WebPageProxy::clearServiceWorkerEntitlementOverride):
* UIProcess/WebPageProxy.h:
Disable entitlement for testing.

* WebProcess/WebPage/WebPage.cpp:
(WebKit::m_isNavigatingToAppBoundDomain):
Set this parameter in the constructor so it will be accurate when
updating preferences.

(WebKit::WebPage::updatePreferences):
* WebProcess/WebPage/WebPage.h:
(WebKit::WebPage::clearServiceWorkerEntitlementOverride):
* WebProcess/WebPage/WebPage.messages.in:
* WebProcess/WebPage/ios/WebPageIOS.mm:
(WebKit::WebPage::parentProcessHasServiceWorkerEntitlement const):
(WebKit::WebPage::disableServiceWorkerEntitlement):
(WebKit::WebPage::clearServiceWorkerEntitlementOverride):
Disable entitlement for testing.

Tools:

Adds 2 test cases to make sure service workers behave properly on
app bound domains, and that the APIs are not available on non-app
bound domains.

* TestWebKitAPI/Tests/WebKitCocoa/InAppBrowserPrivacy.mm:
(-[SWInAppBrowserPrivacyMessageHandler userContentController:didReceiveScriptMessage:]):

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (260302 => 260303)


--- trunk/Source/WebCore/ChangeLog	2020-04-17 23:40:39 UTC (rev 260302)
+++ trunk/Source/WebCore/ChangeLog	2020-04-18 00:54:41 UTC (rev 260303)
@@ -1,3 +1,22 @@
+2020-04-17  Kate Cheney  <[email protected]>
+
+        Enable service workers for app-bound domains
+        https://bugs.webkit.org/show_bug.cgi?id=210451
+        <rdar://problem/61479474>
+
+        Reviewed by Brent Fulgham.
+
+        SWServer now retrieves the app-bound domains from the UI Process and
+        only continues with the load if the proper entitlement is present
+        or the load is coming from an app-bound domain.
+
+        * workers/service/server/SWServer.cpp:
+        (WebCore::SWServer::addRegistrationFromStore):
+        (WebCore::SWServer::SWServer):
+        (WebCore::SWServer::validateRegistrationDomain):
+        (WebCore::SWServer::scheduleJob):
+        * workers/service/server/SWServer.h:
+
 2020-04-17  Dean Jackson  <[email protected]>
 
         [WebGL] Confirm there are no errors when setting up framebuffers

Modified: trunk/Source/WebCore/workers/service/server/SWServer.cpp (260302 => 260303)


--- trunk/Source/WebCore/workers/service/server/SWServer.cpp	2020-04-17 23:40:39 UTC (rev 260302)
+++ trunk/Source/WebCore/workers/service/server/SWServer.cpp	2020-04-18 00:54:41 UTC (rev 260303)
@@ -155,15 +155,21 @@
 {
     // Pages should not have been able to make a new registration to this key while the import was still taking place.
     ASSERT(!m_scopeToRegistrationMap.contains(data.registration.key));
+    
+    validateRegistrationDomain(WebCore::RegistrableDomain(data.scriptURL), [this, weakThis = makeWeakPtr(this), data = "" (bool isValid) mutable {
+        if (!weakThis)
+            return;
+        if (m_hasServiceWorkerEntitlement || isValid) {
+            auto registration = makeUnique<SWServerRegistration>(*this, data.registration.key, data.registration.updateViaCache, data.registration.scopeURL, data.scriptURL);
+            registration->setLastUpdateTime(data.registration.lastUpdateTime);
+            auto registrationPtr = registration.get();
+            addRegistration(WTFMove(registration));
 
-    auto registration = makeUnique<SWServerRegistration>(*this, data.registration.key, data.registration.updateViaCache, data.registration.scopeURL, data.scriptURL);
-    registration->setLastUpdateTime(data.registration.lastUpdateTime);
-    auto registrationPtr = registration.get();
-    addRegistration(WTFMove(registration));
-
-    auto worker = SWServerWorker::create(*this, *registrationPtr, data.scriptURL, data.script, data.contentSecurityPolicy, WTFMove(data.referrerPolicy), data.workerType, data.serviceWorkerIdentifier, WTFMove(data.scriptResourceMap));
-    registrationPtr->updateRegistrationState(ServiceWorkerRegistrationState::Active, worker.ptr());
-    worker->setState(ServiceWorkerState::Activated);
+            auto worker = SWServerWorker::create(*this, *registrationPtr, data.scriptURL, data.script, data.contentSecurityPolicy, WTFMove(data.referrerPolicy), data.workerType, data.serviceWorkerIdentifier, WTFMove(data.scriptResourceMap));
+            registrationPtr->updateRegistrationState(ServiceWorkerRegistrationState::Active, worker.ptr());
+            worker->setState(ServiceWorkerState::Activated);
+        }
+    });
 }
 
 void SWServer::addRegistration(std::unique_ptr<SWServerRegistration>&& registration)
@@ -305,12 +311,14 @@
     m_server.removeClientServiceWorkerRegistration(*this, identifier);
 }
 
-SWServer::SWServer(UniqueRef<SWOriginStore>&& originStore, bool processTerminationDelayEnabled, String&& registrationDatabaseDirectory, PAL::SessionID sessionID, SoftUpdateCallback&& softUpdateCallback, CreateContextConnectionCallback&& callback)
+SWServer::SWServer(UniqueRef<SWOriginStore>&& originStore, bool processTerminationDelayEnabled, String&& registrationDatabaseDirectory, PAL::SessionID sessionID, bool hasServiceWorkerEntitlement, SoftUpdateCallback&& softUpdateCallback, CreateContextConnectionCallback&& callback, AppBoundDomainsCallback&& appBoundDomainsCallback)
     : m_originStore(WTFMove(originStore))
     , m_sessionID(sessionID)
     , m_isProcessTerminationDelayEnabled(processTerminationDelayEnabled)
     , m_createContextConnectionCallback(WTFMove(callback))
     , m_softUpdateCallback(WTFMove(softUpdateCallback))
+    , m_appBoundDomainsCallback(WTFMove(appBoundDomainsCallback))
+    , m_hasServiceWorkerEntitlement(hasServiceWorkerEntitlement)
 {
     RELEASE_LOG_IF(registrationDatabaseDirectory.isEmpty() && !m_sessionID.isEphemeral(), ServiceWorker, "No path to store the service worker registrations");
     if (!m_sessionID.isEphemeral())
@@ -322,31 +330,53 @@
     allServers().add(this);
 }
 
+void SWServer::validateRegistrationDomain(WebCore::RegistrableDomain domain, CompletionHandler<void(bool)>&& completionHandler)
+{
+    if (m_hasServiceWorkerEntitlement || m_hasReceivedAppBoundDomains) {
+        completionHandler(m_appBoundDomains.contains(domain));
+        return;
+    }
+    
+    m_appBoundDomainsCallback([this, weakThis = makeWeakPtr(this), domain = WTFMove(domain), completionHandler = WTFMove(completionHandler)](auto&& appBoundDomains) mutable {
+        if (!weakThis)
+            return;
+        m_hasReceivedAppBoundDomains = true;
+        m_appBoundDomains = WTFMove(appBoundDomains);
+        completionHandler(m_appBoundDomains.contains(domain));
+    });
+}
+
 // https://w3c.github.io/ServiceWorker/#schedule-job-algorithm
 void SWServer::scheduleJob(ServiceWorkerJobData&& jobData)
 {
     ASSERT(m_connections.contains(jobData.connectionIdentifier()) || jobData.connectionIdentifier() == Process::identifier());
 
-    auto& jobQueue = *m_jobQueues.ensure(jobData.registrationKey(), [this, &jobData] {
-        return makeUnique<SWServerJobQueue>(*this, jobData.registrationKey());
-    }).iterator->value;
-
-    if (!jobQueue.size()) {
-        jobQueue.enqueueJob(WTFMove(jobData));
-        jobQueue.runNextJob();
-        return;
-    }
-    auto& lastJob = jobQueue.lastJob();
-    if (jobData.isEquivalent(lastJob)) {
-        // FIXME: Per the spec, check if this job is equivalent to the last job on the queue.
-        // If it is, stack it along with that job. For now, we just make sure to not call soft-update too often.
-        if (jobData.type == ServiceWorkerJobType::Update && jobData.connectionIdentifier() == Process::identifier())
+    validateRegistrationDomain(WebCore::RegistrableDomain(jobData.scriptURL), [this, weakThis = makeWeakPtr(this), jobData = WTFMove(jobData)] (bool isValid) mutable {
+        if (!weakThis)
             return;
-    }
+        if (m_hasServiceWorkerEntitlement || isValid) {
+            auto& jobQueue = *m_jobQueues.ensure(jobData.registrationKey(), [this, &jobData] {
+                return makeUnique<SWServerJobQueue>(*this, jobData.registrationKey());
+            }).iterator->value;
 
-    jobQueue.enqueueJob(WTFMove(jobData));
-    if (jobQueue.size() == 1)
-        jobQueue.runNextJob();
+            if (!jobQueue.size()) {
+                jobQueue.enqueueJob(WTFMove(jobData));
+                jobQueue.runNextJob();
+                return;
+            }
+            auto& lastJob = jobQueue.lastJob();
+            if (jobData.isEquivalent(lastJob)) {
+                // FIXME: Per the spec, check if this job is equivalent to the last job on the queue.
+                // If it is, stack it along with that job. For now, we just make sure to not call soft-update too often.
+                if (jobData.type == ServiceWorkerJobType::Update && jobData.connectionIdentifier() == Process::identifier())
+                    return;
+            }
+            jobQueue.enqueueJob(WTFMove(jobData));
+            if (jobQueue.size() == 1)
+                jobQueue.runNextJob();
+        } else
+            rejectJob(jobData, { TypeError, "Job rejected for non app-bound domain" });
+    });
 }
 
 void SWServer::scheduleUnregisterJob(ServiceWorkerJobDataIdentifier jobDataIdentifier, SWServerRegistration& registration, DocumentOrWorkerIdentifier contextIdentifier, URL&& clientCreationURL)

Modified: trunk/Source/WebCore/workers/service/server/SWServer.h (260302 => 260303)


--- trunk/Source/WebCore/workers/service/server/SWServer.h	2020-04-17 23:40:39 UTC (rev 260302)
+++ trunk/Source/WebCore/workers/service/server/SWServer.h	2020-04-18 00:54:41 UTC (rev 260303)
@@ -126,7 +126,8 @@
 
     using SoftUpdateCallback = Function<void(ServiceWorkerJobData&& jobData, bool shouldRefreshCache, ResourceRequest&&, CompletionHandler<void(const ServiceWorkerFetchResult&)>&&)>;
     using CreateContextConnectionCallback = Function<void(const WebCore::RegistrableDomain&, CompletionHandler<void()>&&)>;
-    WEBCORE_EXPORT SWServer(UniqueRef<SWOriginStore>&&, bool processTerminationDelayEnabled, String&& registrationDatabaseDirectory, PAL::SessionID, SoftUpdateCallback&&, CreateContextConnectionCallback&&);
+    using AppBoundDomainsCallback = Function<void(CompletionHandler<void(HashSet<WebCore::RegistrableDomain>&&)>&&)>;
+    WEBCORE_EXPORT SWServer(UniqueRef<SWOriginStore>&&, bool processTerminationDelayEnabled, String&& registrationDatabaseDirectory, PAL::SessionID, bool hasServiceWorkerEntitlement, SoftUpdateCallback&&, CreateContextConnectionCallback&&, AppBoundDomainsCallback&&);
 
     WEBCORE_EXPORT ~SWServer();
 
@@ -215,6 +216,8 @@
     static constexpr Seconds defaultTerminationDelay = 10_s;
 
 private:
+    void validateRegistrationDomain(WebCore::RegistrableDomain, CompletionHandler<void(bool)>&&);
+
     void scriptFetchFinished(const ServiceWorkerFetchResult&);
 
     void didResolveRegistrationPromise(Connection*, const ServiceWorkerRegistrationKey&);
@@ -269,6 +272,11 @@
     HashSet<WebCore::RegistrableDomain> m_pendingConnectionDomains;
     Vector<CompletionHandler<void()>> m_importCompletedCallbacks;
     SoftUpdateCallback m_softUpdateCallback;
+    AppBoundDomainsCallback m_appBoundDomainsCallback;
+    
+    HashSet<WebCore::RegistrableDomain> m_appBoundDomains;
+    bool m_hasServiceWorkerEntitlement { false };
+    bool m_hasReceivedAppBoundDomains { false };
 };
 
 } // namespace WebCore

Modified: trunk/Source/WebKit/ChangeLog (260302 => 260303)


--- trunk/Source/WebKit/ChangeLog	2020-04-17 23:40:39 UTC (rev 260302)
+++ trunk/Source/WebKit/ChangeLog	2020-04-18 00:54:41 UTC (rev 260303)
@@ -1,3 +1,114 @@
+2020-04-17  Kate Cheney  <[email protected]>
+
+        Enable service workers for app-bound domains
+        https://bugs.webkit.org/show_bug.cgi?id=210451
+        <rdar://problem/61479474>
+
+        Reviewed by Brent Fulgham.
+
+        * NetworkProcess/NetworkConnectionToWebProcess.cpp:
+        (WebKit::NetworkConnectionToWebProcess::createFetchTask):
+        (WebKit::NetworkConnectionToWebProcess::scheduleResourceLoad):
+        (WebKit::NetworkConnectionToWebProcess::swConnection):
+        (WebKit::NetworkConnectionToWebProcess::isServiceWorkerAllowed const): Deleted.
+        * NetworkProcess/NetworkConnectionToWebProcess.h:
+        Removed ASSERTS and service worker entitlement checks which are now done along with app-bound
+        domain checks in SWServer.cpp.
+
+        * NetworkProcess/NetworkProcess.cpp:
+        (WebKit::NetworkProcess::initializeNetworkProcess):
+        (WebKit::NetworkProcess::addWebsiteDataStore):
+        Remove the check for parentProcessHasServiceWorkerEntitlement() before
+        adding a serviceWorkerSession. This doesn't do anything except add an
+        entry to a map, and simplifies the case where we need a session for
+        app-bound instances which should have service workers but have no entitlement.
+
+        Pass the entitlement and a new callback to request app-bound domains
+        from the UI Process to the SWServer. This will make sure the server
+        checks for the entitlement or list of app-bound domains before completing a load.
+
+        (WebKit::NetworkProcess::registerSWServerConnection):
+        Remove unnecessary ASSERT for entitlement.
+
+        * NetworkProcess/NetworkProcess.h:
+        * NetworkProcess/NetworkProcess.messages.in:
+        * NetworkProcess/ios/NetworkProcessIOS.mm:
+        (WebKit::NetworkProcess::parentProcessHasServiceWorkerEntitlement const):
+        (WebKit::NetworkProcess::disableServiceWorkerEntitlement):
+        (WebKit::NetworkProcess::clearServiceWorkerEntitlementOverride):
+        In order to test this thoroughly, TestWebKitAPI needed a way to
+        temporarily disable the service worker entitlement. This function
+        overrides the check for the entitlement if the bool is set, disabling
+        the entitlement.
+
+        * Shared/WebPageCreationParameters.cpp:
+        (WebKit::WebPageCreationParameters::encode const):
+        (WebKit::WebPageCreationParameters::decode):
+        * Shared/WebPageCreationParameters.h:
+        WebPage needs to know if it is app-bound when created so it can update
+        the service worker preferences key accordingly.
+
+        * Shared/WebPreferences.yaml:
+        * UIProcess/API/Cocoa/WKPreferences.mm:
+        (-[WKPreferences _serviceWorkerEntitlementDisabledForTesting]):
+        (-[WKPreferences _setServiceWorkerEntitlementDisabledForTesting:]):
+        * UIProcess/API/Cocoa/WKPreferencesPrivate.h:
+        Disable entitlement for testing.
+
+        * UIProcess/API/APIPageConfiguration.cpp:
+        (API::PageConfiguration::copy const):
+        * UIProcess/API/APIPageConfiguration.h:
+        (API::PageConfiguration::limitsNavigationsToAppBoundDomains const):
+        (API::PageConfiguration::setLimitsNavigationsToAppBoundDomains):
+        (API::PageConfiguration::limitsNavigationToAppBoundDomains const): Deleted.
+        (API::PageConfiguration::setLimitsNavigationToAppBoundDomains): Deleted.
+        (-[WKWebViewConfiguration limitsNavigationsToAppBoundDomains]):
+        (-[WKWebViewConfiguration setLimitsNavigationsToAppBoundDomains:]):
+        (-[WKWebViewConfiguration limitsNavigationToAppBoundDomains]): Deleted.
+        (-[WKWebViewConfiguration setLimitsNavigationToAppBoundDomains:]): Deleted.
+        * UIProcess/API/Cocoa/WKWebViewConfiguration.mm:
+        Inconsistent naming (Navigation vs Navigations).
+
+        * UIProcess/API/Cocoa/WKWebView.mm:
+        (-[WKWebView _setupPageConfiguration:]):
+        Check for entitlement or app-bound webview.
+
+        (-[WKWebView _serviceWorkersEnabled:]):
+        (-[WKWebView _clearServiceWorkerEntitlementOverride:]):
+        * UIProcess/API/Cocoa/WKWebViewPrivate.h:
+        Testing SPIs.
+
+        * UIProcess/Network/NetworkProcessProxy.cpp:
+        (WebKit::NetworkProcessProxy::getAppBoundDomains):
+        * UIProcess/Network/NetworkProcessProxy.h:
+        * UIProcess/Network/NetworkProcessProxy.messages.in:
+        Sends the app-bound domains to the Network Process.
+
+        * UIProcess/WebPageProxy.cpp:
+        (WebKit::m_limitsNavigationsToAppBoundDomains):
+        (WebKit::m_limitsNavigationToAppBoundDomains): Deleted.
+        Naming inconsistency.
+
+        (WebKit::WebPageProxy::disableServiceWorkerEntitlementInNetworkProcess):
+        (WebKit::WebPageProxy::clearServiceWorkerEntitlementOverride):
+        * UIProcess/WebPageProxy.h:
+        Disable entitlement for testing.
+
+        * WebProcess/WebPage/WebPage.cpp:
+        (WebKit::m_isNavigatingToAppBoundDomain):
+        Set this parameter in the constructor so it will be accurate when
+        updating preferences.
+
+        (WebKit::WebPage::updatePreferences):
+        * WebProcess/WebPage/WebPage.h:
+        (WebKit::WebPage::clearServiceWorkerEntitlementOverride):
+        * WebProcess/WebPage/WebPage.messages.in:
+        * WebProcess/WebPage/ios/WebPageIOS.mm:
+        (WebKit::WebPage::parentProcessHasServiceWorkerEntitlement const):
+        (WebKit::WebPage::disableServiceWorkerEntitlement):
+        (WebKit::WebPage::clearServiceWorkerEntitlementOverride):
+        Disable entitlement for testing.
+
 2020-04-17  Alex Christensen  <[email protected]>
 
         NetworkSessionCocoa should request client certificate only once per host/port

Modified: trunk/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.cpp (260302 => 260303)


--- trunk/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.cpp	2020-04-17 23:40:39 UTC (rev 260302)
+++ trunk/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.cpp	2020-04-18 00:54:41 UTC (rev 260303)
@@ -121,8 +121,7 @@
     m_connection->open();
 
 #if ENABLE(SERVICE_WORKER)
-    if (networkProcess.parentProcessHasServiceWorkerEntitlement())
-        establishSWServerConnection();
+    establishSWServerConnection();
 #endif
 }
 
@@ -431,15 +430,8 @@
 }
 
 #if ENABLE(SERVICE_WORKER)
-bool NetworkConnectionToWebProcess::isServiceWorkerAllowed() const
-{
-    return m_networkProcess->parentProcessHasServiceWorkerEntitlement();
-}
-
 std::unique_ptr<ServiceWorkerFetchTask> NetworkConnectionToWebProcess::createFetchTask(NetworkResourceLoader& loader, const ResourceRequest& request)
 {
-    if (!isServiceWorkerAllowed())
-        return nullptr;
     return swConnection().createFetchTask(loader, request);
 }
 #endif
@@ -447,18 +439,15 @@
 void NetworkConnectionToWebProcess::scheduleResourceLoad(NetworkResourceLoadParameters&& loadParameters)
 {
 #if ENABLE(SERVICE_WORKER)
-    bool isServiceWorkerAllowed = this->isServiceWorkerAllowed();
-    if (isServiceWorkerAllowed) {
-        auto& server = m_networkProcess->swServerForSession(m_sessionID);
-        if (!server.isImportCompleted()) {
-            server.whenImportIsCompleted([this, protectedThis = makeRef(*this), loadParameters = WTFMove(loadParameters)]() mutable {
-                if (!m_networkProcess->webProcessConnection(webProcessIdentifier()))
-                    return;
-                ASSERT(m_networkProcess->swServerForSession(m_sessionID).isImportCompleted());
-                scheduleResourceLoad(WTFMove(loadParameters));
-            });
-            return;
-        }
+    auto& server = m_networkProcess->swServerForSession(m_sessionID);
+    if (!server.isImportCompleted()) {
+        server.whenImportIsCompleted([this, protectedThis = makeRef(*this), loadParameters = WTFMove(loadParameters)]() mutable {
+            if (!m_networkProcess->webProcessConnection(webProcessIdentifier()))
+                return;
+            ASSERT(m_networkProcess->swServerForSession(m_sessionID).isImportCompleted());
+            scheduleResourceLoad(WTFMove(loadParameters));
+        });
+        return;
     }
 #endif
     auto identifier = loadParameters.identifier;
@@ -469,12 +458,11 @@
     auto& loader = m_networkResourceLoaders.add(identifier, NetworkResourceLoader::create(WTFMove(loadParameters), *this)).iterator->value;
 
 #if ENABLE(SERVICE_WORKER)
-    if (isServiceWorkerAllowed) {
-        loader->startWithServiceWorker();
-        return;
-    }
+    loader->startWithServiceWorker();
+    return;
+#else
+    loader->start();
 #endif
-    loader->start();
 }
 
 void NetworkConnectionToWebProcess::performSynchronousLoad(NetworkResourceLoadParameters&& loadParameters, Messages::NetworkConnectionToWebProcess::PerformSynchronousLoad::DelayedReply&& reply)
@@ -1053,7 +1041,6 @@
 
 WebSWServerConnection& NetworkConnectionToWebProcess::swConnection()
 {
-    ASSERT(isServiceWorkerAllowed());
     if (!m_swConnection)
         establishSWServerConnection();
     return *m_swConnection;

Modified: trunk/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.h (260302 => 260303)


--- trunk/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.h	2020-04-17 23:40:39 UTC (rev 260302)
+++ trunk/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.h	2020-04-18 00:54:41 UTC (rev 260303)
@@ -236,7 +236,6 @@
     void establishSWContextConnection(WebCore::RegistrableDomain&&, CompletionHandler<void()>&&);
     void closeSWContextConnection();
     void unregisterSWConnection();
-    bool isServiceWorkerAllowed() const;
 #endif
 
     void createNewMessagePortChannel(const WebCore::MessagePortIdentifier& port1, const WebCore::MessagePortIdentifier& port2);

Modified: trunk/Source/WebKit/NetworkProcess/NetworkProcess.cpp (260302 => 260303)


--- trunk/Source/WebKit/NetworkProcess/NetworkProcess.cpp	2020-04-17 23:40:39 UTC (rev 260302)
+++ trunk/Source/WebKit/NetworkProcess/NetworkProcess.cpp	2020-04-18 00:54:41 UTC (rev 260303)
@@ -345,10 +345,8 @@
 #endif
 
 #if ENABLE(SERVICE_WORKER)
-    if (parentProcessHasServiceWorkerEntitlement()) {
-        bool serviceWorkerProcessTerminationDelayEnabled = true;
-        addServiceWorkerSession(PAL::SessionID::defaultSessionID(), serviceWorkerProcessTerminationDelayEnabled, WTFMove(parameters.serviceWorkerRegistrationDirectory), parameters.serviceWorkerRegistrationDirectoryExtensionHandle);
-    }
+    bool serviceWorkerProcessTerminationDelayEnabled = true;
+    addServiceWorkerSession(PAL::SessionID::defaultSessionID(), serviceWorkerProcessTerminationDelayEnabled, WTFMove(parameters.serviceWorkerRegistrationDirectory), parameters.serviceWorkerRegistrationDirectoryExtensionHandle);
 #endif
 
     m_storageManagerSet->add(sessionID, parameters.defaultDataStoreParameters.localStorageDirectory, parameters.defaultDataStoreParameters.localStorageDirectoryExtensionHandle);
@@ -438,8 +436,7 @@
 #endif
 
 #if ENABLE(SERVICE_WORKER)
-    if (parentProcessHasServiceWorkerEntitlement())
-        addServiceWorkerSession(sessionID, parameters.serviceWorkerProcessTerminationDelayEnabled, WTFMove(parameters.serviceWorkerRegistrationDirectory), parameters.serviceWorkerRegistrationDirectoryExtensionHandle);
+    addServiceWorkerSession(sessionID, parameters.serviceWorkerProcessTerminationDelayEnabled, WTFMove(parameters.serviceWorkerRegistrationDirectory), parameters.serviceWorkerRegistrationDirectoryExtensionHandle);
 #endif
 
     m_storageManagerSet->add(sessionID, parameters.localStorageDirectory, parameters.localStorageDirectoryExtensionHandle);
@@ -2455,11 +2452,13 @@
         // If there's not, then where did this PAL::SessionID come from?
         ASSERT(sessionID.isEphemeral() || !path.isEmpty());
 
-        return makeUnique<SWServer>(makeUniqueRef<WebSWOriginStore>(), info.processTerminationDelayEnabled, WTFMove(path), sessionID, [this, sessionID](auto&& jobData, bool shouldRefreshCache, auto&& request, auto&& completionHandler) mutable {
+        return makeUnique<SWServer>(makeUniqueRef<WebSWOriginStore>(), info.processTerminationDelayEnabled, WTFMove(path), sessionID, parentProcessHasServiceWorkerEntitlement(), [this, sessionID](auto&& jobData, bool shouldRefreshCache, auto&& request, auto&& completionHandler) mutable {
             ServiceWorkerSoftUpdateLoader::start(networkSession(sessionID), WTFMove(jobData), shouldRefreshCache, WTFMove(request), WTFMove(completionHandler));
         }, [this, sessionID](auto& registrableDomain, auto&& completionHandler) {
             ASSERT(!registrableDomain.isEmpty());
             parentProcessConnection()->sendWithAsyncReply(Messages::NetworkProcessProxy::EstablishWorkerContextConnectionToNetworkProcess { registrableDomain, sessionID }, WTFMove(completionHandler), 0);
+        }, [this, sessionID](auto&& completionHandler) {
+            parentProcessConnection()->sendWithAsyncReply(Messages::NetworkProcessProxy::GetAppBoundDomains { sessionID }, WTFMove(completionHandler), 0);
         });
     });
     return *result.iterator->value;
@@ -2475,7 +2474,6 @@
 
 void NetworkProcess::registerSWServerConnection(WebSWServerConnection& connection)
 {
-    ASSERT(parentProcessHasServiceWorkerEntitlement());
     auto* store = existingSWOriginStoreForSession(connection.sessionID());
     ASSERT(store);
     if (store)

Modified: trunk/Source/WebKit/NetworkProcess/NetworkProcess.h (260302 => 260303)


--- trunk/Source/WebKit/NetworkProcess/NetworkProcess.h	2020-04-17 23:40:39 UTC (rev 260302)
+++ trunk/Source/WebKit/NetworkProcess/NetworkProcess.h	2020-04-18 00:54:41 UTC (rev 260303)
@@ -306,6 +306,8 @@
 
 #if PLATFORM(IOS_FAMILY)
     bool parentProcessHasServiceWorkerEntitlement() const;
+    void disableServiceWorkerEntitlement();
+    void clearServiceWorkerEntitlementOverride(CompletionHandler<void()>&&);
 #else
     bool parentProcessHasServiceWorkerEntitlement() const { return true; }
 #endif

Modified: trunk/Source/WebKit/NetworkProcess/NetworkProcess.messages.in (260302 => 260303)


--- trunk/Source/WebKit/NetworkProcess/NetworkProcess.messages.in	2020-04-17 23:40:39 UTC (rev 260302)
+++ trunk/Source/WebKit/NetworkProcess/NetworkProcess.messages.in	2020-04-18 00:54:41 UTC (rev 260303)
@@ -172,4 +172,9 @@
     
     HasAppBoundSession(PAL::SessionID sessionID) -> (bool hasAppBoundSession) Async
     SetInAppBrowserPrivacyEnabled(PAL::SessionID sessionID, bool value) -> () Async
+
+#if PLATFORM(IOS_FAMILY)
+    DisableServiceWorkerEntitlement()
+    ClearServiceWorkerEntitlementOverride() -> () Async
+#endif
 }

Modified: trunk/Source/WebKit/NetworkProcess/ios/NetworkProcessIOS.mm (260302 => 260303)


--- trunk/Source/WebKit/NetworkProcess/ios/NetworkProcessIOS.mm	2020-04-17 23:40:39 UTC (rev 260302)
+++ trunk/Source/WebKit/NetworkProcess/ios/NetworkProcessIOS.mm	2020-04-18 00:54:41 UTC (rev 260303)
@@ -74,12 +74,28 @@
     notImplemented();
 }
 
+static bool disableServiceWorkerEntitlementTestingOverride;
+
 bool NetworkProcess::parentProcessHasServiceWorkerEntitlement() const
 {
+    if (disableServiceWorkerEntitlementTestingOverride)
+        return false;
+
     static bool hasEntitlement = WTF::hasEntitlement(parentProcessConnection()->xpcConnection(), "com.apple.developer.WebKit.ServiceWorkers");
     return hasEntitlement;
 }
 
+void NetworkProcess::disableServiceWorkerEntitlement()
+{
+    disableServiceWorkerEntitlementTestingOverride = true;
+}
+
+void NetworkProcess::clearServiceWorkerEntitlementOverride(CompletionHandler<void()>&& completionHandler)
+{
+    disableServiceWorkerEntitlementTestingOverride = false;
+    completionHandler();
+}
+
 } // namespace WebKit
 
 #endif // PLATFORM(IOS_FAMILY)

Modified: trunk/Source/WebKit/Shared/WebPageCreationParameters.cpp (260302 => 260303)


--- trunk/Source/WebKit/Shared/WebPageCreationParameters.cpp	2020-04-17 23:40:39 UTC (rev 260302)
+++ trunk/Source/WebKit/Shared/WebPageCreationParameters.cpp	2020-04-18 00:54:41 UTC (rev 260303)
@@ -146,6 +146,7 @@
     encoder << shouldCaptureDisplayInUIProcess;
     encoder << shouldRenderCanvasInGPUProcess;
     encoder << needsInAppBrowserPrivacyQuirks;
+    encoder << limitsNavigationsToAppBoundDomains;
 
 #if PLATFORM(GTK)
     encoder << themeName;
@@ -470,6 +471,9 @@
     if (!decoder.decode(parameters.needsInAppBrowserPrivacyQuirks))
         return WTF::nullopt;
     
+    if (!decoder.decode(parameters.limitsNavigationsToAppBoundDomains))
+        return WTF::nullopt;
+    
 #if PLATFORM(GTK)
     if (!decoder.decode(parameters.themeName))
         return WTF::nullopt;

Modified: trunk/Source/WebKit/Shared/WebPageCreationParameters.h (260302 => 260303)


--- trunk/Source/WebKit/Shared/WebPageCreationParameters.h	2020-04-17 23:40:39 UTC (rev 260302)
+++ trunk/Source/WebKit/Shared/WebPageCreationParameters.h	2020-04-18 00:54:41 UTC (rev 260303)
@@ -217,6 +217,7 @@
     bool shouldCaptureDisplayInUIProcess { false };
     bool shouldRenderCanvasInGPUProcess { false };
     bool needsInAppBrowserPrivacyQuirks { false };
+    bool limitsNavigationsToAppBoundDomains { false };
 
 #if PLATFORM(GTK)
     String themeName;

Modified: trunk/Source/WebKit/Shared/WebPreferences.yaml (260302 => 260303)


--- trunk/Source/WebKit/Shared/WebPreferences.yaml	2020-04-17 23:40:39 UTC (rev 260302)
+++ trunk/Source/WebKit/Shared/WebPreferences.yaml	2020-04-18 00:54:41 UTC (rev 260303)
@@ -1273,6 +1273,11 @@
     webcoreBinding: RuntimeEnabledFeatures
     category: debug
 
+ServiceWorkerEntitlementDisabledForTesting:
+    type: bool
+    defaultValue: false
+    webcoreBinding: none
+
 # For experimental features:
 # The type should be boolean.
 # You must provide a humanReadableName and humanReadableDescription for all experimental features. They

Modified: trunk/Source/WebKit/UIProcess/API/APIPageConfiguration.cpp (260302 => 260303)


--- trunk/Source/WebKit/UIProcess/API/APIPageConfiguration.cpp	2020-04-17 23:40:39 UTC (rev 260302)
+++ trunk/Source/WebKit/UIProcess/API/APIPageConfiguration.cpp	2020-04-18 00:54:41 UTC (rev 260303)
@@ -97,7 +97,7 @@
     copy->m_ignoresAppBoundDomains = this->m_ignoresAppBoundDomains;
     copy->m_loadsSubresources = this->m_loadsSubresources;
     copy->m_loadsFromNetwork = this->m_loadsFromNetwork;
-    copy->m_limitsNavigationToAppBoundDomains = this->m_limitsNavigationToAppBoundDomains;
+    copy->m_limitsNavigationsToAppBoundDomains = this->m_limitsNavigationsToAppBoundDomains;
 
     return copy;
 }

Modified: trunk/Source/WebKit/UIProcess/API/APIPageConfiguration.h (260302 => 260303)


--- trunk/Source/WebKit/UIProcess/API/APIPageConfiguration.h	2020-04-17 23:40:39 UTC (rev 260302)
+++ trunk/Source/WebKit/UIProcess/API/APIPageConfiguration.h	2020-04-18 00:54:41 UTC (rev 260303)
@@ -158,8 +158,8 @@
     bool loadsFromNetwork() const { return m_loadsFromNetwork; }
     void setLoadsFromNetwork(bool loads) { m_loadsFromNetwork = loads; }
 
-    bool limitsNavigationToAppBoundDomains() const { return m_limitsNavigationToAppBoundDomains; }
-    void setLimitsNavigationToAppBoundDomains(bool limits) { m_limitsNavigationToAppBoundDomains = limits; }
+    bool limitsNavigationsToAppBoundDomains() const { return m_limitsNavigationsToAppBoundDomains; }
+    void setLimitsNavigationsToAppBoundDomains(bool limits) { m_limitsNavigationsToAppBoundDomains = limits; }
 
 private:
 
@@ -204,7 +204,7 @@
     bool m_ignoresAppBoundDomains { false };
     bool m_loadsSubresources { true };
     bool m_loadsFromNetwork { true };
-    bool m_limitsNavigationToAppBoundDomains { false };
+    bool m_limitsNavigationsToAppBoundDomains { false };
 };
 
 } // namespace API

Modified: trunk/Source/WebKit/UIProcess/API/Cocoa/WKPreferences.mm (260302 => 260303)


--- trunk/Source/WebKit/UIProcess/API/Cocoa/WKPreferences.mm	2020-04-17 23:40:39 UTC (rev 260302)
+++ trunk/Source/WebKit/UIProcess/API/Cocoa/WKPreferences.mm	2020-04-18 00:54:41 UTC (rev 260303)
@@ -923,6 +923,16 @@
     return _preferences->isITPDatabaseEnabled();
 }
 
+- (BOOL)_serviceWorkerEntitlementDisabledForTesting
+{
+    return _preferences->serviceWorkerEntitlementDisabledForTesting();
+}
+
+- (void)_setServiceWorkerEntitlementDisabledForTesting:(BOOL)disable
+{
+    _preferences->setServiceWorkerEntitlementDisabledForTesting(disable);
+}
+
 #if PLATFORM(MAC)
 - (void)_setJavaEnabledForLocalFiles:(BOOL)enabled
 {

Modified: trunk/Source/WebKit/UIProcess/API/Cocoa/WKPreferencesPrivate.h (260302 => 260303)


--- trunk/Source/WebKit/UIProcess/API/Cocoa/WKPreferencesPrivate.h	2020-04-17 23:40:39 UTC (rev 260302)
+++ trunk/Source/WebKit/UIProcess/API/Cocoa/WKPreferencesPrivate.h	2020-04-18 00:54:41 UTC (rev 260303)
@@ -165,6 +165,7 @@
 @property (nonatomic, setter=_setAcceleratedCompositingEnabled:) BOOL _acceleratedCompositingEnabled WK_API_AVAILABLE(macos(10.13.4), ios(WK_IOS_TBA));
 @property (nonatomic, setter=_setRequestAnimationFrameEnabled:) BOOL _requestAnimationFrameEnabled WK_API_AVAILABLE(macos(WK_MAC_TBA), ios(WK_IOS_TBA));
 @property (nonatomic, readonly) BOOL _isITPDatabaseEnabled WK_API_AVAILABLE(macos(WK_MAC_TBA), ios(WK_IOS_TBA));
+@property (nonatomic, setter=_setServiceWorkerEntitlementDisabledForTesting:) BOOL _serviceWorkerEntitlementDisabledForTesting WK_API_AVAILABLE(macos(WK_MAC_TBA), ios(WK_IOS_TBA));
 
 #if !TARGET_OS_IPHONE
 @property (nonatomic, setter=_setWebGLEnabled:) BOOL _webGLEnabled WK_API_AVAILABLE(macos(10.13.4));

Modified: trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebView.mm (260302 => 260303)


--- trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebView.mm	2020-04-17 23:40:39 UTC (rev 260302)
+++ trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebView.mm	2020-04-18 00:54:41 UTC (rev 260303)
@@ -121,6 +121,7 @@
 #import <WebCore/MIMETypeRegistry.h>
 #import <WebCore/PlatformScreen.h>
 #import <WebCore/RuntimeApplicationChecks.h>
+#import <WebCore/RuntimeEnabledFeatures.h>
 #import <WebCore/SQLiteDatabaseTracker.h>
 #import <WebCore/Settings.h>
 #import <WebCore/SharedBuffer.h>
@@ -523,8 +524,9 @@
 #endif
 
 #if PLATFORM(IOS_FAMILY) && ENABLE(SERVICE_WORKER)
-    if (!WTF::processHasEntitlement("com.apple.developer.WebKit.ServiceWorkers"))
+    if ((!WTF::processHasEntitlement("com.apple.developer.WebKit.ServiceWorkers") || !![_configuration preferences]._serviceWorkerEntitlementDisabledForTesting) && ![_configuration limitsNavigationsToAppBoundDomains])
         pageConfiguration->preferences()->setServiceWorkersEnabled(false);
+    pageConfiguration->preferences()->setServiceWorkerEntitlementDisabledForTesting(!![_configuration preferences]._serviceWorkerEntitlementDisabledForTesting);
 #endif
 
     if (!linkedOnOrAfter(WebKit::SDKVersion::FirstWhereSiteSpecificQuirksAreEnabledByDefault))
@@ -2650,6 +2652,19 @@
     });
 }
 
+- (void)_serviceWorkersEnabled:(void(^)(BOOL))completionHandler
+{
+    auto enabled = [_configuration preferences]->_preferences.get()->serviceWorkersEnabled() || WebCore::RuntimeEnabledFeatures::sharedFeatures().serviceWorkerEnabled();
+    completionHandler(enabled);
+}
+
+- (void)_clearServiceWorkerEntitlementOverride:(void (^)(void))completionHandler
+{
+    _page->clearServiceWorkerEntitlementOverride([completionHandler = makeBlockPtr(completionHandler)] {
+        completionHandler();
+    });
+}
+
 - (id <_WKInputDelegate>)_inputDelegate
 {
     return _inputDelegate.getAutoreleased();

Modified: trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebViewConfiguration.mm (260302 => 260303)


--- trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebViewConfiguration.mm	2020-04-17 23:40:39 UTC (rev 260302)
+++ trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebViewConfiguration.mm	2020-04-18 00:54:41 UTC (rev 260303)
@@ -685,14 +685,14 @@
     _allowTopNavigationToDataURLs = allowTopNavigationToDataURLs;
 }
 
-- (BOOL)limitsNavigationToAppBoundDomains
+- (BOOL)limitsNavigationsToAppBoundDomains
 {
-    return _pageConfiguration->limitsNavigationToAppBoundDomains();
+    return _pageConfiguration->limitsNavigationsToAppBoundDomains();
 }
 
-- (void)setLimitsNavigationToAppBoundDomains:(BOOL)limitsToAppBoundDomains
+- (void)setLimitsNavigationsToAppBoundDomains:(BOOL)limitsToAppBoundDomains
 {
-    _pageConfiguration->setLimitsNavigationToAppBoundDomains(limitsToAppBoundDomains);
+    _pageConfiguration->setLimitsNavigationsToAppBoundDomains(limitsToAppBoundDomains);
 }
 
 - (BOOL)_convertsPositionStyleOnCopy

Modified: trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebViewPrivate.h (260302 => 260303)


--- trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebViewPrivate.h	2020-04-17 23:40:39 UTC (rev 260302)
+++ trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebViewPrivate.h	2020-04-18 00:54:41 UTC (rev 260303)
@@ -343,6 +343,8 @@
 
 - (void)_grantAccessToPreferenceService WK_API_AVAILABLE(macos(WK_MAC_TBA), ios(WK_IOS_TBA));
 
+- (void)_serviceWorkersEnabled:(void(^)(BOOL))completionHandler WK_API_AVAILABLE(macos(WK_MAC_TBA), ios(WK_IOS_TBA));
+- (void)_clearServiceWorkerEntitlementOverride:(void (^)(void))completionHandler WK_API_AVAILABLE(macos(WK_MAC_TBA), ios(WK_IOS_TBA));
 @end
 
 #if TARGET_OS_IPHONE

Modified: trunk/Source/WebKit/UIProcess/Network/NetworkProcessProxy.cpp (260302 => 260303)


--- trunk/Source/WebKit/UIProcess/Network/NetworkProcessProxy.cpp	2020-04-17 23:40:39 UTC (rev 260302)
+++ trunk/Source/WebKit/UIProcess/Network/NetworkProcessProxy.cpp	2020-04-18 00:54:41 UTC (rev 260303)
@@ -1481,6 +1481,21 @@
     sendWithAsyncReply(Messages::NetworkProcess::SetInAppBrowserPrivacyEnabled(sessionID, value), WTFMove(completionHandler));
 }
 
+void NetworkProcessProxy::getAppBoundDomains(PAL::SessionID sessionID, CompletionHandler<void(HashSet<WebCore::RegistrableDomain>&&)>&& completionHandler)
+{
+#if PLATFORM(IOS_FAMILY)
+    if (auto* store = websiteDataStoreFromSessionID(sessionID)) {
+        store->getAppBoundDomains([completionHandler = WTFMove(completionHandler)] (auto& appBoundDomains) mutable {
+            auto appBoundDomainsCopy = appBoundDomains;
+            completionHandler(WTFMove(appBoundDomainsCopy));
+        });
+        return;
+    }
+    completionHandler({ });
+#else
+    completionHandler({ });
+#endif
+}
 
 } // namespace WebKit
 

Modified: trunk/Source/WebKit/UIProcess/Network/NetworkProcessProxy.h (260302 => 260303)


--- trunk/Source/WebKit/UIProcess/Network/NetworkProcessProxy.h	2020-04-17 23:40:39 UTC (rev 260302)
+++ trunk/Source/WebKit/UIProcess/Network/NetworkProcessProxy.h	2020-04-18 00:54:41 UTC (rev 260303)
@@ -223,7 +223,8 @@
 
     void hasAppBoundSession(PAL::SessionID, CompletionHandler<void(bool)>&&);
     void setInAppBrowserPrivacyEnabled(PAL::SessionID, bool, CompletionHandler<void()>&&);
-    
+    void getAppBoundDomains(PAL::SessionID, CompletionHandler<void(HashSet<WebCore::RegistrableDomain>&&)>&&);
+
 private:
     // AuxiliaryProcessProxy
     ASCIILiteral processName() const final { return "Networking"_s; }

Modified: trunk/Source/WebKit/UIProcess/Network/NetworkProcessProxy.messages.in (260302 => 260303)


--- trunk/Source/WebKit/UIProcess/Network/NetworkProcessProxy.messages.in	2020-04-17 23:40:39 UTC (rev 260302)
+++ trunk/Source/WebKit/UIProcess/Network/NetworkProcessProxy.messages.in	2020-04-18 00:54:41 UTC (rev 260303)
@@ -67,6 +67,8 @@
 
     SetWebProcessHasUploads(WebCore::ProcessIdentifier processID, bool hasUpload)
 
+    GetAppBoundDomains(PAL::SessionID sessionID) -> (HashSet<WebCore::RegistrableDomain> appBoundDomains) Async
+
     RequestStorageSpace(PAL::SessionID sessionID, struct WebCore::ClientOrigin origin, uint64_t quota, uint64_t currentSize, uint64_t spaceRequired) -> (Optional<uint64_t> newQuota) Async
     
     ResourceLoadDidSendRequest(WebKit::WebPageProxyIdentifier pageIdentifier, struct WebKit::ResourceLoadInfo resourceLoadInfo, WebCore::ResourceRequest request, Optional<IPC::FormDataReference> httpBody)

Modified: trunk/Source/WebKit/UIProcess/WebPageProxy.cpp (260302 => 260303)


--- trunk/Source/WebKit/UIProcess/WebPageProxy.cpp	2020-04-17 23:40:39 UTC (rev 260302)
+++ trunk/Source/WebKit/UIProcess/WebPageProxy.cpp	2020-04-18 00:54:41 UTC (rev 260303)
@@ -179,6 +179,7 @@
 #include <WebCore/WindowFeatures.h>
 #include <WebCore/WritingDirection.h>
 #include <stdio.h>
+#include <wtf/CallbackAggregator.h>
 #include <wtf/NeverDestroyed.h>
 #include <wtf/Scope.h>
 #include <wtf/SystemTracing.h>
@@ -485,7 +486,7 @@
     , m_tryCloseTimeoutTimer(RunLoop::main(), this, &WebPageProxy::tryCloseTimedOut)
 #if PLATFORM(COCOA)
     , m_ignoresAppBoundDomains(m_configuration->ignoresAppBoundDomains() || WTF::processHasEntitlement("com.apple.private.applemediaservices"))
-    , m_limitsNavigationToAppBoundDomains(m_configuration->limitsNavigationToAppBoundDomains())
+    , m_limitsNavigationsToAppBoundDomains(m_configuration->limitsNavigationsToAppBoundDomains())
 #endif
 {
     RELEASE_LOG_IF_ALLOWED(Loading, "constructor:");
@@ -521,6 +522,9 @@
 
 #if PLATFORM(IOS_FAMILY)
     DeprecatedGlobalSettings::setDisableScreenSizeOverride(m_preferences->disableScreenSizeOverride());
+    
+    if (m_configuration->preferences()->serviceWorkerEntitlementDisabledForTesting())
+        disableServiceWorkerEntitlementInNetworkProcess();
 #endif
 
 #if PLATFORM(COCOA)
@@ -3156,6 +3160,34 @@
     completionHandler(m_isNavigatingToAppBoundDomain && (*m_isNavigatingToAppBoundDomain == NavigatingToAppBoundDomain::Yes));
 }
 
+void WebPageProxy::disableServiceWorkerEntitlementInNetworkProcess()
+{
+#if PLATFORM(IOS_FAMILY)
+    if (auto* networkProcess = m_process->processPool().networkProcess()) {
+        if (!networkProcess->canSendMessage())
+            return;
+        networkProcess->send(Messages::NetworkProcess::DisableServiceWorkerEntitlement(), 0);
+    }
+#endif
+}
+
+void WebPageProxy::clearServiceWorkerEntitlementOverride(CompletionHandler<void()>&& completionHandler)
+{
+#if PLATFORM(IOS_FAMILY)
+    auto callbackAggregator = CallbackAggregator::create(WTFMove(completionHandler));
+    sendWithAsyncReply(Messages::WebPage::ClearServiceWorkerEntitlementOverride(), [callbackAggregator = callbackAggregator.copyRef()] { });
+    if (auto* networkProcess = m_process->processPool().networkProcess()) {
+        if (!networkProcess->canSendMessage()) {
+            completionHandler();
+            return;
+        }
+        networkProcess->sendWithAsyncReply(Messages::NetworkProcess::ClearServiceWorkerEntitlementOverride(), [callbackAggregator = callbackAggregator.copyRef()] { });
+    }
+#else
+    completionHandler();
+#endif
+}
+
 void WebPageProxy::receivedNavigationPolicyDecision(PolicyAction policyAction, API::Navigation* navigation, ProcessSwapRequestedByClient processSwapRequestedByClient, WebFrameProxy& frame, RefPtr<API::WebsitePolicies>&& policies, Ref<PolicyDecisionSender>&& sender)
 {
     Ref<WebsiteDataStore> websiteDataStore = m_websiteDataStore.copyRef();
@@ -7804,6 +7836,7 @@
     parameters.shouldCaptureVideoInGPUProcess = preferences().captureVideoInGPUProcessEnabled();
     parameters.shouldRenderCanvasInGPUProcess = preferences().renderCanvasInGPUProcessEnabled();
     parameters.shouldCaptureDisplayInUIProcess = m_process->processPool().configuration().shouldCaptureDisplayInUIProcess();
+    parameters.limitsNavigationsToAppBoundDomains = m_limitsNavigationsToAppBoundDomains;
 
 #if PLATFORM(GTK)
     parameters.themeName = pageClient().themeName();

Modified: trunk/Source/WebKit/UIProcess/WebPageProxy.h (260302 => 260303)


--- trunk/Source/WebKit/UIProcess/WebPageProxy.h	2020-04-17 23:40:39 UTC (rev 260302)
+++ trunk/Source/WebKit/UIProcess/WebPageProxy.h	2020-04-18 00:54:41 UTC (rev 260303)
@@ -1729,6 +1729,9 @@
     void isNavigatingToAppBoundDomainTesting(CompletionHandler<void(bool)>&&);
     Optional<NavigatingToAppBoundDomain> isNavigatingToAppBoundDomain() const { return m_isNavigatingToAppBoundDomain; }
 
+    void disableServiceWorkerEntitlementInNetworkProcess();
+    void clearServiceWorkerEntitlementOverride(CompletionHandler<void()>&&);
+        
 #if PLATFORM(COCOA)
     void grantAccessToCurrentPasteboardData(const String& pasteboardName);
 #endif
@@ -2797,7 +2800,7 @@
     NavigatedAwayFromAppBoundDomain m_hasNavigatedAwayFromAppBoundDomain { NavigatedAwayFromAppBoundDomain::No };
     bool m_ignoresAppBoundDomains { false };
     bool m_userScriptsNotified { false };
-    bool m_limitsNavigationToAppBoundDomains { false };
+    bool m_limitsNavigationsToAppBoundDomains { false };
 
 #if ENABLE(ROUTING_ARBITRATION)
     std::unique_ptr<AudioSessionRoutingArbitratorProxy> m_routingArbitrator;

Modified: trunk/Source/WebKit/WebProcess/WebPage/WebPage.cpp (260302 => 260303)


--- trunk/Source/WebKit/WebProcess/WebPage/WebPage.cpp	2020-04-17 23:40:39 UTC (rev 260302)
+++ trunk/Source/WebKit/WebProcess/WebPage/WebPage.cpp	2020-04-18 00:54:41 UTC (rev 260303)
@@ -460,6 +460,7 @@
 #endif
     , m_overriddenMediaType(parameters.overriddenMediaType)
     , m_processDisplayName(parameters.processDisplayName)
+    , m_isNavigatingToAppBoundDomain(parameters.limitsNavigationsToAppBoundDomains ? NavigatingToAppBoundDomain::Yes : NavigatingToAppBoundDomain::No)
 {
     ASSERT(m_identifier);
 
@@ -3672,9 +3673,12 @@
 #endif
 
 #if ENABLE(SERVICE_WORKER)
+    if (store.getBoolValueForKey(WebPreferencesKey::serviceWorkerEntitlementDisabledForTestingKey()))
+        disableServiceWorkerEntitlement();
+
     if (store.getBoolValueForKey(WebPreferencesKey::serviceWorkersEnabledKey())) {
-        ASSERT(parentProcessHasServiceWorkerEntitlement());
-        if (!parentProcessHasServiceWorkerEntitlement())
+        ASSERT(parentProcessHasServiceWorkerEntitlement() || m_isNavigatingToAppBoundDomain);
+        if (!parentProcessHasServiceWorkerEntitlement() && !m_isNavigatingToAppBoundDomain)
             RuntimeEnabledFeatures::sharedFeatures().setServiceWorkerEnabled(false);
     }
 #endif

Modified: trunk/Source/WebKit/WebProcess/WebPage/WebPage.h (260302 => 260303)


--- trunk/Source/WebKit/WebProcess/WebPage/WebPage.h	2020-04-17 23:40:39 UTC (rev 260302)
+++ trunk/Source/WebKit/WebProcess/WebPage/WebPage.h	2020-04-18 00:54:41 UTC (rev 260303)
@@ -1523,8 +1523,12 @@
 
 #if PLATFORM(IOS_FAMILY)
     bool parentProcessHasServiceWorkerEntitlement() const;
+    void disableServiceWorkerEntitlement();
+    void clearServiceWorkerEntitlementOverride(CompletionHandler<void()>&&);
 #else
     bool parentProcessHasServiceWorkerEntitlement() const { return true; }
+    void disableServiceWorkerEntitlement() { }
+    void clearServiceWorkerEntitlementOverride(CompletionHandler<void()>&& completionHandler) { completionHandler(); }
 #endif
 
     void didReceivePolicyDecision(WebCore::FrameIdentifier, uint64_t listenerID, PolicyDecision&&);

Modified: trunk/Source/WebKit/WebProcess/WebPage/WebPage.messages.in (260302 => 260303)


--- trunk/Source/WebKit/WebProcess/WebPage/WebPage.messages.in	2020-04-17 23:40:39 UTC (rev 260302)
+++ trunk/Source/WebKit/WebProcess/WebPage/WebPage.messages.in	2020-04-18 00:54:41 UTC (rev 260303)
@@ -122,6 +122,7 @@
     InsertTextPlaceholder(WebCore::IntSize size) -> (Optional<WebCore::ElementContext> placeholder) Async
     RemoveTextPlaceholder(struct WebCore::ElementContext placeholder) -> () Async
     FocusTextInputContextAndPlaceCaret(struct WebCore::ElementContext context, WebCore::IntPoint point) -> (bool success) Async
+    ClearServiceWorkerEntitlementOverride() -> () Async
 #endif
 
     SetControlledByAutomation(bool controlled)

Modified: trunk/Source/WebKit/WebProcess/WebPage/ios/WebPageIOS.mm (260302 => 260303)


--- trunk/Source/WebKit/WebProcess/WebPage/ios/WebPageIOS.mm	2020-04-17 23:40:39 UTC (rev 260302)
+++ trunk/Source/WebKit/WebProcess/WebPage/ios/WebPageIOS.mm	2020-04-18 00:54:41 UTC (rev 260303)
@@ -488,12 +488,28 @@
     return sendResult && eventWasHandled;
 }
 
+static bool disableServiceWorkerEntitlementTestingOverride;
+
 bool WebPage::parentProcessHasServiceWorkerEntitlement() const
 {
+    if (disableServiceWorkerEntitlementTestingOverride)
+        return false;
+    
     static bool hasEntitlement = WTF::hasEntitlement(WebProcess::singleton().parentProcessConnection()->xpcConnection(), "com.apple.developer.WebKit.ServiceWorkers");
     return hasEntitlement;
 }
 
+void WebPage::disableServiceWorkerEntitlement()
+{
+    disableServiceWorkerEntitlementTestingOverride = true;
+}
+
+void WebPage::clearServiceWorkerEntitlementOverride(CompletionHandler<void()>&& completionHandler)
+{
+    disableServiceWorkerEntitlementTestingOverride = false;
+    completionHandler();
+}
+
 void WebPage::sendComplexTextInputToPlugin(uint64_t, const String&)
 {
     notImplemented();

Modified: trunk/Tools/ChangeLog (260302 => 260303)


--- trunk/Tools/ChangeLog	2020-04-17 23:40:39 UTC (rev 260302)
+++ trunk/Tools/ChangeLog	2020-04-18 00:54:41 UTC (rev 260303)
@@ -1,3 +1,18 @@
+2020-04-17  Kate Cheney  <[email protected]>
+
+        Enable service workers for app-bound domains
+        https://bugs.webkit.org/show_bug.cgi?id=210451
+        <rdar://problem/61479474>
+
+        Reviewed by Brent Fulgham.
+
+        Adds 2 test cases to make sure service workers behave properly on
+        app bound domains, and that the APIs are not available on non-app
+        bound domains.
+
+        * TestWebKitAPI/Tests/WebKitCocoa/InAppBrowserPrivacy.mm:
+        (-[SWInAppBrowserPrivacyMessageHandler userContentController:didReceiveScriptMessage:]):
+
 2020-04-17  Alex Christensen  <[email protected]>
 
         NetworkSessionCocoa should request client certificate only once per host/port

Modified: trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/InAppBrowserPrivacy.mm (260302 => 260303)


--- trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/InAppBrowserPrivacy.mm	2020-04-17 23:40:39 UTC (rev 260302)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/InAppBrowserPrivacy.mm	2020-04-18 00:54:41 UTC (rev 260303)
@@ -26,6 +26,7 @@
 #import "config.h"
 
 #import "PlatformUtilities.h"
+#import "ServiceWorkerTCPServer.h"
 #import "TestNavigationDelegate.h"
 #import "TestWKWebView.h"
 #import "WKWebViewConfigurationExtras.h"
@@ -743,6 +744,137 @@
     TestWebKitAPI::Util::run(&done);
 }
 
+@interface SWInAppBrowserPrivacyMessageHandler : NSObject <WKScriptMessageHandler>
+@end
+
+@implementation SWInAppBrowserPrivacyMessageHandler
+- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message
+{
+    EXPECT_WK_STREQ(@"Message from worker: ServiceWorker received: Hello from an app-bound domain", [message body]);
+    isDone = true;
+}
+@end
+
+static const char* mainBytes = R"SWRESOURCE(
+<script>
+
+function log(msg)
+{
+    window.webkit.messageHandlers.sw.postMessage(msg);
+}
+
+navigator.serviceWorker.addEventListener("message", function(event) {
+    log("Message from worker: " + event.data);
+});
+
+try {
+
+navigator.serviceWorker.register('/sw.js').then(function(reg) {
+    worker = reg.installing ? reg.installing : reg.active;
+    worker.postMessage("Hello from an app-bound domain");
+}).catch(function(error) {
+    log("Registration failed with: " + error);
+});
+} catch(e) {
+    log("Exception: " + e);
+}
+
+</script>
+)SWRESOURCE";
+
+static const char* scriptBytes = R"SWRESOURCE(
+
+self.addEventListener("message", (event) => {
+    event.source.postMessage("ServiceWorker received: " + event.data);
+});
+
+)SWRESOURCE";
+
+TEST(InAppBrowserPrivacy, AppBoundDomainAllowsServiceWorkers)
+{
+    initializeInAppBrowserPrivacyTestSettings();
+    isDone = false;
+
+    auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
+    auto messageHandler = adoptNS([[SWInAppBrowserPrivacyMessageHandler alloc] init]);
+    [[configuration userContentController] addScriptMessageHandler:messageHandler.get() name:@"sw"];
+    [configuration preferences]._serviceWorkerEntitlementDisabledForTesting = YES;
+    [configuration setLimitsNavigationsToAppBoundDomains:YES];
+
+    auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration.get()]);
+
+    ServiceWorkerTCPServer server1({
+        { "text/html", mainBytes },
+        { "application/_javascript_", scriptBytes},
+    });
+
+    [WKWebsiteDataStore _allowWebsiteDataRecordsForAllOrigins];
+
+    // Start with a clean slate data store
+    [[WKWebsiteDataStore defaultDataStore] removeDataOfTypes:[WKWebsiteDataStore allWebsiteDataTypes] modifiedSince:[NSDate distantPast] completionHandler:^() {
+        isDone = true;
+    }];
+    TestWebKitAPI::Util::run(&isDone);
+    isDone = false;
+    
+    // Expect the service worker load to complete successfully.
+    [webView loadRequest:server1.requestWithLocalhost()];
+    TestWebKitAPI::Util::run(&isDone);
+    isDone = false;
+
+    [[WKWebsiteDataStore defaultDataStore] fetchDataRecordsOfTypes:[NSSet setWithObject:WKWebsiteDataTypeServiceWorkerRegistrations] completionHandler:^(NSArray<WKWebsiteDataRecord *> *websiteDataRecords) {
+        EXPECT_EQ(1u, [websiteDataRecords count]);
+        EXPECT_WK_STREQ(websiteDataRecords[0].displayName, "localhost");
+        isDone = true;
+    }];
+
+    TestWebKitAPI::Util::run(&isDone);
+    isDone = false;
+
+    // Reset service worker entitlement.
+    [webView _clearServiceWorkerEntitlementOverride:^(void) {
+        cleanUpInAppBrowserPrivacyTestSettings();
+        isDone = true;
+    }];
+    TestWebKitAPI::Util::run(&isDone);
+    isDone = false;
+}
+
+TEST(InAppBrowserPrivacy, NonAppBoundDomainDoesNotAllowServiceWorkers)
+{
+    initializeInAppBrowserPrivacyTestSettings();
+    isDone = false;
+
+    auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
+    auto schemeHandler = adoptNS([[InAppBrowserSchemeHandler alloc] init]);
+    [configuration setURLSchemeHandler:schemeHandler.get() forURLScheme:@"in-app-browser"];
+    // Disable entitlement which allows service workers.
+    [configuration preferences]._serviceWorkerEntitlementDisabledForTesting = YES;
+
+    auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration.get()]);
+
+    // Load a non-app bound domain.
+    NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"in-app-browser:///in-app-browser-privacy-test-user-style-sheets"]];
+    [webView loadRequest:request];
+    [webView _test_waitForDidFinishNavigation];
+    
+    // Expect that service workers are disabled for this webView.
+    isDone = false;
+    [webView _serviceWorkersEnabled:^(BOOL enabled) {
+        EXPECT_FALSE(enabled);
+        isDone = true;
+    }];
+    TestWebKitAPI::Util::run(&isDone);
+    
+    // Reset service worker entitlement.
+    [webView _clearServiceWorkerEntitlementOverride:^(void) {
+        cleanUpInAppBrowserPrivacyTestSettings();
+        isDone = true;
+    }];
+    TestWebKitAPI::Util::run(&isDone);
+    isDone = false;
+}
+
 #endif // USE(APPLE_INTERNAL_SDK)
 
 #endif // PLATFORM(IOS_FAMILY)
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to