Move service worker registration matching for navigation loads to network process
https://bugs.webkit.org/show_bug.cgi?id=203144

Patch by youenn fablet <youenn@apple.com> on 2019-10-21
Reviewed by Chris Dumez.

Source/WebCore:

For regular loads, we no longer match service worker registration explicitly.
This is now done by NetworkResourceLoader explicitly.
We still need to explicitely match registrations in those two cases:
- There is an app cache resource that can be used. We will use it only if there is no registration.
- There is a resource from the meory cache that can be used. We will match the registration to make sure 
the document is controlled by the right service worker. The load will still be served from the memory cache.

Since DocumentLoader is no longer matching registration, we need a way from NetworkProcess to inform that there is 
a matching registration and that the document is controlled.
For that purpose, DocumentLoader is adding itself in a global map with the temporary document identifier as the key.
Adding to the map happens when loading the main resource and removal from the map happens when destroying the DocumentLoader.
For this to happen properly, the temporary document identifier is kept the same for the lifetime of the DocumentLoader.

Registration matching was postponed until service worker registration is done.
Since we no longer do registration matching in WebProcess, we need to wait in NetworkProcess for that to happen.
We introduce a way for SWServer to notify when import is completed for that purpose.

Covered by existing tests.

* loader/DocumentLoader.cpp:
(WebCore::DocumentLoader::fromTemporaryDocumentIdentifier):
(WebCore::DocumentLoader::~DocumentLoader):
(WebCore::DocumentLoader::setControllingServiceWorkerRegistration):
(WebCore::DocumentLoader::redirectReceived):
(WebCore::DocumentLoader::responseReceived):
(WebCore::DocumentLoader::startLoadingMainResource):
(WebCore::DocumentLoader::unregisterTemporaryServiceWorkerClient):
(WebCore::DocumentLoader::loadMainResource):
* loader/DocumentLoader.h:
* loader/appcache/ApplicationCacheHost.cpp:
(WebCore::ApplicationCacheHost::canLoadMainResource):
* loader/appcache/ApplicationCacheHost.h:
* workers/service/server/SWServer.cpp:
(WebCore::SWServer::~SWServer):
(WebCore::SWServer::registrationStoreImportComplete):
(WebCore::SWServer::whenImportIsCompleted):
(WebCore::SWServer::doRegistrationMatching):
* workers/service/server/SWServer.h:
(WebCore::SWServer::isImportCompleted const):

Source/WebKit:

Create a WebSWServerConnection whenever receiving a load request in NetworkProcess.
This connection is used to check for service worker registration in case of navigation loads.
Similarly, we create a WebSWClientConnection whenever WebProcess needs it, including when receiving WebSWClientConnection messages from NetworkProcess.
This for instance happens when service worker registration import is complete to fill the shared registration origin store.

Delay loads until SWServer has finished importing its registrations.
This is needed since we might otherwise not intercept loads that could be intercepted.
Waiting for importing registrations was previously ensured by WebProcess getting a matching registration in DocumentLoader.

NetworkResourceLoader is now checking for service worker interception in case of redirections for navigations.
This is needed as redirections could end up using a new registration.

* NetworkProcess/NetworkConnectionToWebProcess.cpp:
(WebKit::NetworkConnectionToWebProcess::NetworkConnectionToWebProcess):
(WebKit::NetworkConnectionToWebProcess::scheduleResourceLoad):
(WebKit::NetworkConnectionToWebProcess::establishSWServerConnection):
(WebKit::NetworkConnectionToWebProcess::swConnection):
* NetworkProcess/NetworkConnectionToWebProcess.h:
* NetworkProcess/NetworkConnectionToWebProcess.messages.in:
* NetworkProcess/NetworkResourceLoader.cpp:
(WebKit::NetworkResourceLoader::continueWillSendRequest):
(WebKit::NetworkResourceLoader::startWithServiceWorker):
(WebKit::NetworkResourceLoader::serviceWorkerDidNotHandle):
* NetworkProcess/NetworkResourceLoader.h:
* NetworkProcess/ServiceWorker/ServiceWorkerFetchTask.cpp:
(WebKit::ServiceWorkerFetchTask::ServiceWorkerFetchTask):
(WebKit::ServiceWorkerFetchTask::start):
(WebKit::ServiceWorkerFetchTask::startFetch):
(WebKit::ServiceWorkerFetchTask::continueFetchTaskWith):
* NetworkProcess/ServiceWorker/ServiceWorkerFetchTask.h:
(WebKit::ServiceWorkerFetchTask::takeRequest):
* NetworkProcess/ServiceWorker/WebSWServerConnection.cpp:
(WebKit::WebSWServerConnection::controlClient):
(WebKit::WebSWServerConnection::createFetchTask):
* NetworkProcess/ServiceWorker/WebSWServerConnection.h:
* WebProcess/Network/NetworkProcessConnection.cpp:
(WebKit::NetworkProcessConnection::didReceiveMessage):
* WebProcess/Network/WebLoaderStrategy.cpp:
(WebKit::WebLoaderStrategy::scheduleLoad):
* WebProcess/Storage/WebSWClientConnection.cpp:
(WebKit::WebSWClientConnection::WebSWClientConnection):
(WebKit::WebSWClientConnection::registrationReady):
(WebKit::WebSWClientConnection::documentIsControlled):
* WebProcess/Storage/WebSWClientConnection.h:
* WebProcess/Storage/WebSWClientConnection.messages.in:

Tools:

* TestWebKitAPI/Tests/WebKitCocoa/ServiceWorkerBasic.mm:
We are now creating a WebSWClientConnection whenever receiving a WebSWClientConnection message
from NetworkProcess. It is free to do so given it no longer requires sending some IPC.
Update the tests accordingly.
A future patch will remove the service worker registration bit feature and corresponding test.



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@251409 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog
index fb6caa9..5c33d49 100644
--- a/Source/WebCore/ChangeLog
+++ b/Source/WebCore/ChangeLog
@@ -1,3 +1,50 @@
+2019-10-21  youenn fablet  <youenn@apple.com>
+
+        Move service worker registration matching for navigation loads to network process
+        https://bugs.webkit.org/show_bug.cgi?id=203144
+
+        Reviewed by Chris Dumez.
+
+        For regular loads, we no longer match service worker registration explicitly.
+        This is now done by NetworkResourceLoader explicitly.
+        We still need to explicitely match registrations in those two cases:
+        - There is an app cache resource that can be used. We will use it only if there is no registration.
+        - There is a resource from the meory cache that can be used. We will match the registration to make sure 
+        the document is controlled by the right service worker. The load will still be served from the memory cache.
+
+        Since DocumentLoader is no longer matching registration, we need a way from NetworkProcess to inform that there is 
+        a matching registration and that the document is controlled.
+        For that purpose, DocumentLoader is adding itself in a global map with the temporary document identifier as the key.
+        Adding to the map happens when loading the main resource and removal from the map happens when destroying the DocumentLoader.
+        For this to happen properly, the temporary document identifier is kept the same for the lifetime of the DocumentLoader.
+
+        Registration matching was postponed until service worker registration is done.
+        Since we no longer do registration matching in WebProcess, we need to wait in NetworkProcess for that to happen.
+        We introduce a way for SWServer to notify when import is completed for that purpose.
+
+        Covered by existing tests.
+
+        * loader/DocumentLoader.cpp:
+        (WebCore::DocumentLoader::fromTemporaryDocumentIdentifier):
+        (WebCore::DocumentLoader::~DocumentLoader):
+        (WebCore::DocumentLoader::setControllingServiceWorkerRegistration):
+        (WebCore::DocumentLoader::redirectReceived):
+        (WebCore::DocumentLoader::responseReceived):
+        (WebCore::DocumentLoader::startLoadingMainResource):
+        (WebCore::DocumentLoader::unregisterTemporaryServiceWorkerClient):
+        (WebCore::DocumentLoader::loadMainResource):
+        * loader/DocumentLoader.h:
+        * loader/appcache/ApplicationCacheHost.cpp:
+        (WebCore::ApplicationCacheHost::canLoadMainResource):
+        * loader/appcache/ApplicationCacheHost.h:
+        * workers/service/server/SWServer.cpp:
+        (WebCore::SWServer::~SWServer):
+        (WebCore::SWServer::registrationStoreImportComplete):
+        (WebCore::SWServer::whenImportIsCompleted):
+        (WebCore::SWServer::doRegistrationMatching):
+        * workers/service/server/SWServer.h:
+        (WebCore::SWServer::isImportCompleted const):
+
 2019-10-21  Sihui Liu  <sihui_liu@apple.com>
 
         Remove IDBBackingStoreTemporaryFileHandler
diff --git a/Source/WebCore/loader/DocumentLoader.cpp b/Source/WebCore/loader/DocumentLoader.cpp
index 5fe307d..ec1858d 100644
--- a/Source/WebCore/loader/DocumentLoader.cpp
+++ b/Source/WebCore/loader/DocumentLoader.cpp
@@ -125,6 +125,17 @@
         loader->setDefersLoading(defers);
 }
 
+static HashMap<DocumentIdentifier, DocumentLoader*>& temporaryIdentifierToLoaderMap()
+{
+    static NeverDestroyed<HashMap<DocumentIdentifier, DocumentLoader*>> map;
+    return map.get();
+}
+
+DocumentLoader* DocumentLoader::fromTemporaryDocumentIdentifier(DocumentIdentifier identifier)
+{
+    return temporaryIdentifierToLoaderMap().get(identifier);
+}
+
 DocumentLoader::DocumentLoader(const ResourceRequest& request, const SubstituteData& substituteData)
     : FrameDestructionObserver(nullptr)
     , m_cachedResourceLoader(CachedResourceLoader::create(this))
@@ -161,6 +172,13 @@
 
     m_cachedResourceLoader->clearDocumentLoader();
     clearMainResource();
+
+#if ENABLE(SERVICE_WORKER)
+    if (m_temporaryServiceWorkerClient) {
+        ASSERT(temporaryIdentifierToLoaderMap().contains(*m_temporaryServiceWorkerClient));
+        temporaryIdentifierToLoaderMap().remove(*m_temporaryServiceWorkerClient);
+    }
+#endif
 }
 
 RefPtr<SharedBuffer> DocumentLoader::mainResourceData() const
@@ -468,6 +486,16 @@
 }
 
 #if ENABLE(SERVICE_WORKER)
+bool DocumentLoader::setControllingServiceWorkerRegistration(ServiceWorkerRegistrationData&& data)
+{
+    if (!m_loadingMainResource)
+        return false;
+
+    ASSERT(!m_gotFirstByte);
+    m_serviceWorkerRegistrationData = WTFMove(data);
+    return true;
+}
+
 void DocumentLoader::matchRegistration(const URL& url, SWClientConnection::RegistrationCallback&& callback)
 {
     auto shouldTryLoadingThroughServiceWorker = !frameLoader()->isReloadingFromOrigin() && m_frame->page() && RuntimeEnabledFeatures::sharedFeatures().serviceWorkerEnabled() && LegacySchemeRegistry::canServiceWorkersHandleURLScheme(url.protocol().toStringWithoutCopying());
@@ -501,38 +529,34 @@
 {
     ASSERT_UNUSED(resource, &resource == m_mainResource);
 #if ENABLE(SERVICE_WORKER)
-    bool isRedirectionFromServiceWorker = redirectResponse.source() == ResourceResponse::Source::ServiceWorker;
-    willSendRequest(WTFMove(request), redirectResponse, [isRedirectionFromServiceWorker, completionHandler = WTFMove(completionHandler), protectedThis = makeRef(*this), this] (auto&& request) mutable {
+    if (m_serviceWorkerRegistrationData) {
+        m_serviceWorkerRegistrationData = { };
+        unregisterTemporaryServiceWorkerClient();
+    }
+    willSendRequest(WTFMove(request), redirectResponse, [completionHandler = WTFMove(completionHandler), protectedThis = makeRef(*this), this] (auto&& request) mutable {
         ASSERT(!m_substituteData.isValid());
         if (request.isNull() || !m_mainDocumentError.isNull() || !m_frame) {
             completionHandler({ });
             return;
         }
 
-        auto url = request.url();
-        this->matchRegistration(url, [request = WTFMove(request), isRedirectionFromServiceWorker, completionHandler = WTFMove(completionHandler), protectedThis = WTFMove(protectedThis), this] (auto&& registrationData) mutable {
-            if (!m_mainDocumentError.isNull() || !m_frame) {
-                completionHandler({ });
-                return;
-            }
-
-            if (!registrationData && this->tryLoadingRedirectRequestFromApplicationCache(request)) {
-                completionHandler({ });
-                return;
-            }
-
-            bool shouldContinueLoad = areRegistrationsEqual(m_serviceWorkerRegistrationData, registrationData)
-                && isRedirectionFromServiceWorker == !!registrationData;
-
-            if (shouldContinueLoad) {
+        if (m_applicationCacheHost->canLoadMainResource(request)) {
+            auto url = request.url();
+            // Let's check service worker registration to see whether loading from network or not.
+            this->matchRegistration(url, [request = WTFMove(request), completionHandler = WTFMove(completionHandler), protectedThis = WTFMove(protectedThis), this](auto&& registrationData) mutable {
+                if (!m_mainDocumentError.isNull() || !m_frame) {
+                    completionHandler({ });
+                    return;
+                }
+                if (!registrationData && this->tryLoadingRedirectRequestFromApplicationCache(request)) {
+                    completionHandler({ });
+                    return;
+                }
                 completionHandler(WTFMove(request));
-                return;
-            }
-
-            this->restartLoadingDueToServiceWorkerRegistrationChange(WTFMove(request), WTFMove(registrationData));
-            completionHandler({ });
+            });
             return;
-        });
+        }
+        completionHandler(WTFMove(request));
     });
 #else
     willSendRequest(WTFMove(request), redirectResponse, WTFMove(completionHandler));
@@ -695,20 +719,6 @@
     return true;
 }
 
-#if ENABLE(SERVICE_WORKER)
-void DocumentLoader::restartLoadingDueToServiceWorkerRegistrationChange(ResourceRequest&& request, Optional<ServiceWorkerRegistrationData>&& registrationData)
-{
-    clearMainResource();
-
-    ASSERT(!isCommitted());
-    m_serviceWorkerRegistrationData = WTFMove(registrationData);
-    loadMainResource(WTFMove(request));
-
-    if (m_mainResource)
-        frameLoader()->client().dispatchDidReceiveServerRedirectForProvisionalLoad();
-}
-#endif
-
 void DocumentLoader::stopLoadingAfterXFrameOptionsOrContentSecurityPolicyDenied(unsigned long identifier, const ResourceResponse& response)
 {
     Ref<DocumentLoader> protectedThis { *this };
@@ -725,6 +735,19 @@
 void DocumentLoader::responseReceived(CachedResource& resource, const ResourceResponse& response, CompletionHandler<void()>&& completionHandler)
 {
     ASSERT_UNUSED(resource, m_mainResource == &resource);
+#if ENABLE(SERVICE_WORKER)
+    if (RuntimeEnabledFeatures::sharedFeatures().serviceWorkerEnabled() && response.source() == ResourceResponse::Source::MemoryCache) {
+        matchRegistration(response.url(), [this, protectedThis = makeRef(*this), response, completionHandler = WTFMove(completionHandler)](auto&& registrationData) mutable {
+            if (!m_mainDocumentError.isNull() || !m_frame) {
+                completionHandler();
+                return;
+            }
+            m_serviceWorkerRegistrationData = WTFMove(registrationData);
+            responseReceived(response, WTFMove(completionHandler));
+        });
+        return;
+    }
+#endif
     responseReceived(response, WTFMove(completionHandler));
 }
 
@@ -1754,6 +1777,7 @@
 
     willSendRequest(ResourceRequest(m_request), ResourceResponse(), [this, protectedThis = WTFMove(protectedThis)] (ResourceRequest&& request) mutable {
         m_request = request;
+        // FIXME: Implement local URL interception by getting the service worker of the parent.
 
         // willSendRequest() may lead to our Frame being detached or cancelling the load via nulling the ResourceRequest.
         if (!m_frame || m_request.isNull()) {
@@ -1768,79 +1792,53 @@
         RELEASE_LOG_IF_ALLOWED("startLoadingMainResource: Starting load (frame = %p, main = %d)", m_frame, m_frame->isMainFrame());
 
 #if ENABLE(SERVICE_WORKER)
-        // FIXME: Implement local URL interception by getting the service worker of the parent.
-        auto url = request.url();
-        matchRegistration(url, [request = WTFMove(request), protectedThis = WTFMove(protectedThis), this] (auto&& registrationData) mutable {
-            if (!m_mainDocumentError.isNull() || !m_frame) {
-                RELEASE_LOG_IF_ALLOWED("startLoadingMainResource callback: Load canceled because of main document error (frame = %p, main = %d)", m_frame, m_frame ? m_frame->isMainFrame() : false);
-                return;
-            }
+        if (m_applicationCacheHost->canLoadMainResource(request) || m_substituteData.isValid()) {
+            auto url = request.url();
+            matchRegistration(url, [request = WTFMove(request), protectedThis = WTFMove(protectedThis), this] (auto&& registrationData) mutable {
+                if (!m_mainDocumentError.isNull() || !m_frame) {
+                    RELEASE_LOG_IF_ALLOWED("startLoadingMainResource callback: Load canceled because of main document error (frame = %p, main = %d)", m_frame, m_frame ? m_frame->isMainFrame() : false);
+                    return;
+                }
 
-            m_serviceWorkerRegistrationData = WTFMove(registrationData);
+                m_serviceWorkerRegistrationData = WTFMove(registrationData);
+                // Prefer existing substitute data (from WKWebView.loadData etc) over service worker fetch.
+                if (this->tryLoadingSubstituteData()) {
+                    RELEASE_LOG_IF_ALLOWED("startLoadingMainResource callback: Load canceled because of substitute data (frame = %p, main = %d)", m_frame, m_frame ? m_frame->isMainFrame() : false);
+                    return;
+                }
 
-            // Prefer existing substitute data (from WKWebView.loadData etc) over service worker fetch.
-            if (this->tryLoadingSubstituteData()) {
-                RELEASE_LOG_IF_ALLOWED("startLoadingMainResource callback: Load canceled because of substitute data (frame = %p, main = %d)", m_frame, m_frame ? m_frame->isMainFrame() : false);
-                return;
-            }
-            // Try app cache only if there is no service worker.
-            if (!m_serviceWorkerRegistrationData && this->tryLoadingRequestFromApplicationCache()) {
-                RELEASE_LOG_IF_ALLOWED("startLoadingMainResource callback: Loaded from Application Cache (frame = %p, main = %d)", m_frame, m_frame->isMainFrame());
-                return;
-            }
-            this->loadMainResource(WTFMove(request));
-        });
+                if (!m_serviceWorkerRegistrationData && this->tryLoadingRequestFromApplicationCache()) {
+                    RELEASE_LOG_IF_ALLOWED("startLoadingMainResource callback: Loaded from Application Cache (frame = %p, main = %d)", m_frame, m_frame->isMainFrame());
+                    return;
+                }
+                this->loadMainResource(WTFMove(request));
+            });
+            return;
+        }
 #else
         if (tryLoadingRequestFromApplicationCache()) {
             RELEASE_LOG_IF_ALLOWED("startLoadingMainResource: Loaded from Application Cache (frame = %p, main = %d)", m_frame, m_frame->isMainFrame());
             return;
         }
+#endif
         loadMainResource(WTFMove(request));
-#endif
     });
 }
 
-void DocumentLoader::registerTemporaryServiceWorkerClient(const URL& url)
-{
-#if ENABLE(SERVICE_WORKER)
-    ASSERT(!m_temporaryServiceWorkerClient);
-
-    if (!m_serviceWorkerRegistrationData)
-        return;
-
-    m_temporaryServiceWorkerClient = DocumentIdentifier::generate();
-
-    auto& serviceWorkerConnection = ServiceWorkerProvider::singleton().serviceWorkerConnection();
-
-    // FIXME: Compute ServiceWorkerClientFrameType appropriately.
-    ServiceWorkerClientData data { { serviceWorkerConnection.serverConnectionIdentifier(), *m_temporaryServiceWorkerClient }, ServiceWorkerClientType::Window, ServiceWorkerClientFrameType::None, url };
-
-    RefPtr<SecurityOrigin> topOrigin;
-    if (m_frame->isMainFrame())
-        topOrigin = SecurityOrigin::create(url);
-    else
-        topOrigin = &m_frame->mainFrame().document()->topOrigin();
-    serviceWorkerConnection.registerServiceWorkerClient(*topOrigin, WTFMove(data), m_serviceWorkerRegistrationData->identifier, m_frame->loader().userAgent(url));
-#else
-    UNUSED_PARAM(url);
-#endif
-}
-
 void DocumentLoader::unregisterTemporaryServiceWorkerClient()
 {
 #if ENABLE(SERVICE_WORKER)
-    if (!m_temporaryServiceWorkerClient)
+    if (!m_temporaryServiceWorkerClient || !RuntimeEnabledFeatures::sharedFeatures().serviceWorkerEnabled())
         return;
 
     auto& serviceWorkerConnection = ServiceWorkerProvider::singleton().serviceWorkerConnection();
     serviceWorkerConnection.unregisterServiceWorkerClient(*m_temporaryServiceWorkerClient);
-    m_temporaryServiceWorkerClient = WTF::nullopt;
 #endif
 }
 
 void DocumentLoader::loadMainResource(ResourceRequest&& request)
 {
-    static NeverDestroyed<ResourceLoaderOptions> mainResourceLoadOptions(
+    ResourceLoaderOptions mainResourceLoadOptions(
         SendCallbackPolicy::SendCallbacks,
         ContentSniffingPolicy::SniffContent,
         DataBufferingPolicy::BufferData,
@@ -1853,6 +1851,15 @@
         ContentSecurityPolicyImposition::SkipPolicyCheck,
         DefersLoadingPolicy::AllowDefersLoading,
         CachingPolicy::AllowCaching);
+#if ENABLE(SERVICE_WORKER)
+    if (!m_temporaryServiceWorkerClient) {
+        // The main navigation load will trigger the registration of the temp client.
+        m_temporaryServiceWorkerClient = DocumentIdentifier::generate();
+        ASSERT(!temporaryIdentifierToLoaderMap().contains(*m_temporaryServiceWorkerClient));
+        temporaryIdentifierToLoaderMap().add(*m_temporaryServiceWorkerClient, this);
+    }
+    mainResourceLoadOptions.clientIdentifier = m_temporaryServiceWorkerClient;
+#endif
     CachedResourceRequest mainResourceRequest(WTFMove(request), mainResourceLoadOptions);
     if (!m_frame->isMainFrame() && m_frame->document()) {
         // If we are loading the main resource of a subframe, use the cache partition of the main document.
@@ -1863,15 +1870,6 @@
         mainResourceRequest.setDomainForCachePartition(origin->domainForCachePartition());
     }
 
-#if ENABLE(SERVICE_WORKER)
-    mainResourceRequest.setNavigationServiceWorkerRegistrationData(m_serviceWorkerRegistrationData);
-    if (mainResourceRequest.options().serviceWorkersMode != ServiceWorkersMode::None) {
-        // As per step 12 of https://w3c.github.io/ServiceWorker/#on-fetch-request-algorithm, the active service worker should be controlling the document.
-        // Since we did not yet create the document, we register a temporary service worker client instead.
-        registerTemporaryServiceWorkerClient(mainResourceRequest.resourceRequest().url());
-    }
-#endif
-
     m_mainResource = m_cachedResourceLoader->requestMainResource(WTFMove(mainResourceRequest)).value_or(nullptr);
 
     if (!m_mainResource) {
diff --git a/Source/WebCore/loader/DocumentLoader.h b/Source/WebCore/loader/DocumentLoader.h
index 9f38f9e..74c6d4f 100644
--- a/Source/WebCore/loader/DocumentLoader.h
+++ b/Source/WebCore/loader/DocumentLoader.h
@@ -149,6 +149,9 @@
     {
         return adoptRef(*new DocumentLoader(request, data));
     }
+
+    WEBCORE_EXPORT static DocumentLoader* fromTemporaryDocumentIdentifier(DocumentIdentifier);
+
     WEBCORE_EXPORT virtual ~DocumentLoader();
 
     void attachToFrame(Frame&);
@@ -392,6 +395,10 @@
     void setAllowContentChangeObserverQuirk(bool allow) { m_allowContentChangeObserverQuirk = allow; }
     bool allowContentChangeObserverQuirk() const { return m_allowContentChangeObserverQuirk; }
 
+#if ENABLE(SERVICE_WORKER)
+    WEBCORE_EXPORT bool setControllingServiceWorkerRegistration(ServiceWorkerRegistrationData&&);
+#endif
+
 protected:
     WEBCORE_EXPORT DocumentLoader(const ResourceRequest&, const SubstituteData&);
 
@@ -405,7 +412,6 @@
 #if ENABLE(SERVICE_WORKER)
     void matchRegistration(const URL&, CompletionHandler<void(Optional<ServiceWorkerRegistrationData>&&)>&&);
 #endif
-    void registerTemporaryServiceWorkerClient(const URL&);
     void unregisterTemporaryServiceWorkerClient();
 
     void loadMainResource(ResourceRequest&&);
@@ -447,9 +453,6 @@
     bool tryLoadingRequestFromApplicationCache();
     bool tryLoadingSubstituteData();
     bool tryLoadingRedirectRequestFromApplicationCache(const ResourceRequest&);
-#if ENABLE(SERVICE_WORKER)
-    void restartLoadingDueToServiceWorkerRegistrationChange(ResourceRequest&&, Optional<ServiceWorkerRegistrationData>&&);
-#endif
     void continueAfterContentPolicy(PolicyAction);
 
     void stopLoadingForPolicyChange();
diff --git a/Source/WebCore/loader/appcache/ApplicationCacheHost.cpp b/Source/WebCore/loader/appcache/ApplicationCacheHost.cpp
index 899cba4..323db46 100644
--- a/Source/WebCore/loader/appcache/ApplicationCacheHost.cpp
+++ b/Source/WebCore/loader/appcache/ApplicationCacheHost.cpp
@@ -80,6 +80,13 @@
     ApplicationCacheGroup::selectCache(*m_documentLoader.frame(), manifestURL);
 }
 
+bool ApplicationCacheHost::canLoadMainResource(const ResourceRequest& request)
+{
+    if (!isApplicationCacheEnabled() || isApplicationCacheBlockedForRequest(request))
+        return false;
+    return !!ApplicationCacheGroup::cacheForMainRequest(request, &m_documentLoader);
+}
+
 void ApplicationCacheHost::maybeLoadMainResource(const ResourceRequest& request, SubstituteData& substituteData)
 {
     // Check if this request should be loaded from the application cache
diff --git a/Source/WebCore/loader/appcache/ApplicationCacheHost.h b/Source/WebCore/loader/appcache/ApplicationCacheHost.h
index 5b2aa1c..54ea550 100644
--- a/Source/WebCore/loader/appcache/ApplicationCacheHost.h
+++ b/Source/WebCore/loader/appcache/ApplicationCacheHost.h
@@ -90,6 +90,8 @@
     void selectCacheWithoutManifest();
     void selectCacheWithManifest(const URL& manifestURL);
 
+    bool canLoadMainResource(const ResourceRequest&);
+
     void maybeLoadMainResource(const ResourceRequest&, SubstituteData&);
     void maybeLoadMainResourceForRedirect(const ResourceRequest&, SubstituteData&);
     bool maybeLoadFallbackForMainResponse(const ResourceRequest&, const ResourceResponse&);
diff --git a/Source/WebCore/workers/service/server/SWServer.cpp b/Source/WebCore/workers/service/server/SWServer.cpp
index 1ca8dec..dbe9a30 100644
--- a/Source/WebCore/workers/service/server/SWServer.cpp
+++ b/Source/WebCore/workers/service/server/SWServer.cpp
@@ -69,6 +69,9 @@
     auto connections = WTFMove(m_connections);
     connections.clear();
 
+    for (auto& callback : std::exchange(m_importCompletedCallbacks, { }))
+        callback();
+
     Vector<SWServerWorker*> runningWorkers;
     for (auto& worker : m_runningOrTerminatingWorkers.values()) {
         if (worker->isRunning())
@@ -131,8 +134,18 @@
         callback();
 
     performGetOriginsWithRegistrationsCallbacks();
+
+    for (auto& callback : std::exchange(m_importCompletedCallbacks, { }))
+        callback();
 }
 
+void SWServer::whenImportIsCompleted(CompletionHandler<void()>&& callback)
+{
+    ASSERT(!m_importCompleted);
+    m_importCompletedCallbacks.append(WTFMove(callback));
+}
+
+
 void SWServer::registrationStoreDatabaseFailedToOpen()
 {
     if (!m_importCompleted)
@@ -757,6 +770,7 @@
 
 SWServerRegistration* SWServer::doRegistrationMatching(const SecurityOriginData& topOrigin, const URL& clientURL)
 {
+    ASSERT(isImportCompleted());
     SWServerRegistration* selectedRegistration = nullptr;
     for (auto& pair : m_scopeToRegistrationMap) {
         if (!pair.key.isMatching(topOrigin, clientURL))
diff --git a/Source/WebCore/workers/service/server/SWServer.h b/Source/WebCore/workers/service/server/SWServer.h
index 4c72458..d627277 100644
--- a/Source/WebCore/workers/service/server/SWServer.h
+++ b/Source/WebCore/workers/service/server/SWServer.h
@@ -203,6 +203,9 @@
     SWServerToContextConnection* contextConnectionForRegistrableDomain(const RegistrableDomain& domain) { return m_contextConnections.get(domain); }
     WEBCORE_EXPORT void createContextConnection(const RegistrableDomain&);
 
+    bool isImportCompleted() const { return m_importCompleted; }
+    WEBCORE_EXPORT void whenImportIsCompleted(CompletionHandler<void()>&&);
+
 private:
     void scriptFetchFinished(Connection&, const ServiceWorkerFetchResult&);
 
@@ -262,6 +265,7 @@
 
     CreateContextConnectionCallback m_createContextConnectionCallback;
     HashSet<WebCore::RegistrableDomain> m_pendingConnectionDomains;
+    Vector<CompletionHandler<void()>> m_importCompletedCallbacks;
 };
 
 } // namespace WebCore
diff --git a/Source/WebKit/ChangeLog b/Source/WebKit/ChangeLog
index 5997fbe..ad2a45f 100644
--- a/Source/WebKit/ChangeLog
+++ b/Source/WebKit/ChangeLog
@@ -1,3 +1,56 @@
+2019-10-21  youenn fablet  <youenn@apple.com>
+
+        Move service worker registration matching for navigation loads to network process
+        https://bugs.webkit.org/show_bug.cgi?id=203144
+
+        Reviewed by Chris Dumez.
+
+        Create a WebSWServerConnection whenever receiving a load request in NetworkProcess.
+        This connection is used to check for service worker registration in case of navigation loads.
+        Similarly, we create a WebSWClientConnection whenever WebProcess needs it, including when receiving WebSWClientConnection messages from NetworkProcess.
+        This for instance happens when service worker registration import is complete to fill the shared registration origin store.
+
+        Delay loads until SWServer has finished importing its registrations.
+        This is needed since we might otherwise not intercept loads that could be intercepted.
+        Waiting for importing registrations was previously ensured by WebProcess getting a matching registration in DocumentLoader.
+
+        NetworkResourceLoader is now checking for service worker interception in case of redirections for navigations.
+        This is needed as redirections could end up using a new registration.
+
+        * NetworkProcess/NetworkConnectionToWebProcess.cpp:
+        (WebKit::NetworkConnectionToWebProcess::NetworkConnectionToWebProcess):
+        (WebKit::NetworkConnectionToWebProcess::scheduleResourceLoad):
+        (WebKit::NetworkConnectionToWebProcess::establishSWServerConnection):
+        (WebKit::NetworkConnectionToWebProcess::swConnection):
+        * NetworkProcess/NetworkConnectionToWebProcess.h:
+        * NetworkProcess/NetworkConnectionToWebProcess.messages.in:
+        * NetworkProcess/NetworkResourceLoader.cpp:
+        (WebKit::NetworkResourceLoader::continueWillSendRequest):
+        (WebKit::NetworkResourceLoader::startWithServiceWorker):
+        (WebKit::NetworkResourceLoader::serviceWorkerDidNotHandle):
+        * NetworkProcess/NetworkResourceLoader.h:
+        * NetworkProcess/ServiceWorker/ServiceWorkerFetchTask.cpp:
+        (WebKit::ServiceWorkerFetchTask::ServiceWorkerFetchTask):
+        (WebKit::ServiceWorkerFetchTask::start):
+        (WebKit::ServiceWorkerFetchTask::startFetch):
+        (WebKit::ServiceWorkerFetchTask::continueFetchTaskWith):
+        * NetworkProcess/ServiceWorker/ServiceWorkerFetchTask.h:
+        (WebKit::ServiceWorkerFetchTask::takeRequest):
+        * NetworkProcess/ServiceWorker/WebSWServerConnection.cpp:
+        (WebKit::WebSWServerConnection::controlClient):
+        (WebKit::WebSWServerConnection::createFetchTask):
+        * NetworkProcess/ServiceWorker/WebSWServerConnection.h:
+        * WebProcess/Network/NetworkProcessConnection.cpp:
+        (WebKit::NetworkProcessConnection::didReceiveMessage):
+        * WebProcess/Network/WebLoaderStrategy.cpp:
+        (WebKit::WebLoaderStrategy::scheduleLoad):
+        * WebProcess/Storage/WebSWClientConnection.cpp:
+        (WebKit::WebSWClientConnection::WebSWClientConnection):
+        (WebKit::WebSWClientConnection::registrationReady):
+        (WebKit::WebSWClientConnection::documentIsControlled):
+        * WebProcess/Storage/WebSWClientConnection.h:
+        * WebProcess/Storage/WebSWClientConnection.messages.in:
+
 2019-10-21  Sihui Liu  <sihui_liu@apple.com>
 
         Remove IDBBackingStoreTemporaryFileHandler
diff --git a/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.cpp b/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.cpp
index c8a0766..c357aa6 100644
--- a/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.cpp
+++ b/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.cpp
@@ -101,6 +101,10 @@
     // reply from the Network process, which would be unsafe.
     m_connection->setOnlySendMessagesAsDispatchWhenWaitingForSyncReplyWhenProcessingSuchAMessage(true);
     m_connection->open();
+
+#if ENABLE(SERVICE_WORKER)
+    establishSWServerConnection();
+#endif
 }
 
 NetworkConnectionToWebProcess::~NetworkConnectionToWebProcess()
@@ -400,6 +404,18 @@
 
 void NetworkConnectionToWebProcess::scheduleResourceLoad(NetworkResourceLoadParameters&& loadParameters)
 {
+#if ENABLE(SERVICE_WORKER)
+    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;
     RELEASE_ASSERT(identifier);
     RELEASE_ASSERT(RunLoop::isMain());
@@ -408,7 +424,7 @@
     auto& loader = m_networkResourceLoaders.add(identifier, NetworkResourceLoader::create(WTFMove(loadParameters), *this)).iterator->value;
 
 #if ENABLE(SERVICE_WORKER)
-    loader->startWithServiceWorker(m_swConnection.get());
+    loader->startWithServiceWorker();
 #else
     loader->start();
 #endif
@@ -879,10 +895,12 @@
 
 void NetworkConnectionToWebProcess::establishSWServerConnection()
 {
+    if (m_swConnection)
+        return;
+
     auto& server = m_networkProcess->swServerForSession(m_sessionID);
     auto connection = makeUnique<WebSWServerConnection>(m_networkProcess, server, m_connection.get(), m_webProcessIdentifier);
 
-    ASSERT(!m_swConnection);
     m_swConnection = makeWeakPtr(*connection);
     server.addConnection(WTFMove(connection));
 }
@@ -905,6 +923,13 @@
 
     m_swContextConnection = nullptr;
 }
+
+WebSWServerConnection& NetworkConnectionToWebProcess::swConnection()
+{
+    if (!m_swConnection)
+        establishSWServerConnection();
+    return *m_swConnection;
+}
 #endif
 
 void NetworkConnectionToWebProcess::createNewMessagePortChannel(const MessagePortIdentifier& port1, const MessagePortIdentifier& port2)
diff --git a/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.h b/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.h
index 64e6d71..a02a1c3 100644
--- a/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.h
+++ b/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.h
@@ -157,6 +157,7 @@
 
 #if ENABLE(SERVICE_WORKER)
     void serverToContextConnectionNoLongerNeeded();
+    WebSWServerConnection& swConnection();
 #endif
 
 private:
diff --git a/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.messages.in b/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.messages.in
index 3bcd0eb..bcebab9 100644
--- a/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.messages.in
+++ b/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.messages.in
@@ -79,7 +79,6 @@
 #endif
 
 #if ENABLE(SERVICE_WORKER)
-    EstablishSWServerConnection()
     EstablishSWContextConnection(WebCore::RegistrableDomain domain)
     CloseSWContextConnection()
 #endif
diff --git a/Source/WebKit/NetworkProcess/NetworkResourceLoader.cpp b/Source/WebKit/NetworkProcess/NetworkResourceLoader.cpp
index d334db6..4e3c01e 100644
--- a/Source/WebKit/NetworkProcess/NetworkResourceLoader.cpp
+++ b/Source/WebKit/NetworkProcess/NetworkResourceLoader.cpp
@@ -761,11 +761,21 @@
 void NetworkResourceLoader::continueWillSendRequest(ResourceRequest&& newRequest, bool isAllowedToAskUserForCredentials)
 {
 #if ENABLE(SERVICE_WORKER)
+    if (parameters().options.mode == FetchOptions::Mode::Navigate) {
+        if (auto serviceWorkerFetchTask = m_connection->swConnection().createFetchTask(*this, newRequest)) {
+            m_networkLoad = nullptr;
+            m_serviceWorkerFetchTask = WTFMove(serviceWorkerFetchTask);
+            return;
+        }
+        m_shouldRestartLoad = !!m_serviceWorkerFetchTask;
+        m_serviceWorkerFetchTask = nullptr;
+    }
     if (m_serviceWorkerFetchTask) {
         m_serviceWorkerFetchTask->continueFetchTaskWith(WTFMove(newRequest));
         return;
     }
 #endif
+
     if (m_shouldRestartLoad) {
         m_shouldRestartLoad = false;
 
@@ -1223,10 +1233,10 @@
 }
 
 #if ENABLE(SERVICE_WORKER)
-void NetworkResourceLoader::startWithServiceWorker(WebSWServerConnection* swConnection)
+void NetworkResourceLoader::startWithServiceWorker()
 {
     ASSERT(!m_serviceWorkerFetchTask);
-    m_serviceWorkerFetchTask = swConnection ? swConnection->createFetchTask(*this) : nullptr;
+    m_serviceWorkerFetchTask = m_connection->swConnection().createFetchTask(*this, originalRequest());
     if (m_serviceWorkerFetchTask)
         return;
 
@@ -1241,7 +1251,15 @@
         return;
     }
 
-    m_serviceWorkerFetchTask = nullptr;
+    if (m_serviceWorkerFetchTask) {
+        auto newRequest = m_serviceWorkerFetchTask->takeRequest();
+        m_serviceWorkerFetchTask = nullptr;
+
+        if (m_networkLoad)
+            m_networkLoad->updateRequestAfterRedirection(newRequest);
+        restartNetworkLoad(WTFMove(newRequest));
+        return;
+    }
     start();
 }
 #endif
diff --git a/Source/WebKit/NetworkProcess/NetworkResourceLoader.h b/Source/WebKit/NetworkProcess/NetworkResourceLoader.h
index 71f81bb..8d179e3 100644
--- a/Source/WebKit/NetworkProcess/NetworkResourceLoader.h
+++ b/Source/WebKit/NetworkProcess/NetworkResourceLoader.h
@@ -126,7 +126,7 @@
     bool isKeptAlive() const { return m_isKeptAlive; }
 
 #if ENABLE(SERVICE_WORKER)
-    void startWithServiceWorker(WebSWServerConnection*);
+    void startWithServiceWorker();
     void serviceWorkerDidNotHandle();
 #endif
 
diff --git a/Source/WebKit/NetworkProcess/ServiceWorker/ServiceWorkerFetchTask.cpp b/Source/WebKit/NetworkProcess/ServiceWorker/ServiceWorkerFetchTask.cpp
index d457e21..7f95d0b 100644
--- a/Source/WebKit/NetworkProcess/ServiceWorker/ServiceWorkerFetchTask.cpp
+++ b/Source/WebKit/NetworkProcess/ServiceWorker/ServiceWorkerFetchTask.cpp
@@ -38,6 +38,7 @@
 #include "WebCoreArgumentCoders.h"
 #include "WebResourceLoaderMessages.h"
 #include "WebSWContextManagerConnectionMessages.h"
+#include "WebSWServerConnection.h"
 #include "WebSWServerToContextConnection.h"
 #include <WebCore/CrossOriginAccessControl.h>
 
@@ -48,12 +49,13 @@
 
 namespace WebKit {
 
-ServiceWorkerFetchTask::ServiceWorkerFetchTask(PAL::SessionID sessionID, NetworkResourceLoader& loader, SWServerConnectionIdentifier serverConnectionIdentifier, ServiceWorkerIdentifier serviceWorkerIdentifier)
+ServiceWorkerFetchTask::ServiceWorkerFetchTask(PAL::SessionID sessionID, NetworkResourceLoader& loader, ResourceRequest&& request, SWServerConnectionIdentifier serverConnectionIdentifier, ServiceWorkerIdentifier serviceWorkerIdentifier, ServiceWorkerRegistrationIdentifier serviceWorkerRegistrationIdentifier)
     : m_sessionID(sessionID)
     , m_loader(loader)
     , m_fetchIdentifier(WebCore::FetchIdentifier::generate())
     , m_serverConnectionIdentifier(serverConnectionIdentifier)
     , m_serviceWorkerIdentifier(serviceWorkerIdentifier)
+    , m_currentRequest(WTFMove(request))
     , m_timeoutTimer(*this, &ServiceWorkerFetchTask::timeoutTimerFired)
 {
     m_timeoutTimer.startOneShot(loader.connectionToWebProcess().networkProcess().serviceWorkerFetchTimeout());
@@ -80,20 +82,19 @@
     m_serviceWorkerConnection = makeWeakPtr(serviceWorkerConnection);
     serviceWorkerConnection.registerFetch(*this);
 
-    startFetch(ResourceRequest { m_loader.originalRequest() }, serviceWorkerConnection);
+    startFetch();
 }
 
-void ServiceWorkerFetchTask::startFetch(ResourceRequest&& request, WebSWServerToContextConnection& serviceWorkerConnection)
+void ServiceWorkerFetchTask::startFetch()
 {
-    m_currentRequest = WTFMove(request);
-
     auto& options = m_loader.parameters().options;
     auto referrer = m_currentRequest.httpReferrer();
 
     // We are intercepting fetch calls after going through the HTTP layer, which may add some specific headers.
-    cleanHTTPRequestHeadersForAccessControl(m_currentRequest, m_loader.parameters().httpHeadersToKeep);
+    auto request = m_currentRequest;
+    cleanHTTPRequestHeadersForAccessControl(request, m_loader.parameters().httpHeadersToKeep);
 
-    bool isSent = sendToServiceWorker(Messages::WebSWContextManagerConnection::StartFetch { m_serverConnectionIdentifier, m_serviceWorkerIdentifier, m_fetchIdentifier, m_currentRequest, options, IPC::FormDataReference { m_currentRequest.httpBody() }, referrer });
+    bool isSent = sendToServiceWorker(Messages::WebSWContextManagerConnection::StartFetch { m_serverConnectionIdentifier, m_serviceWorkerIdentifier, m_fetchIdentifier, request, options, IPC::FormDataReference { m_currentRequest.httpBody() }, referrer });
     ASSERT_UNUSED(isSent, isSent);
 }
 
@@ -169,7 +170,8 @@
         m_loader.serviceWorkerDidNotHandle();
         return;
     }
-    startFetch(WTFMove(request), *m_serviceWorkerConnection);
+    m_currentRequest = WTFMove(request);
+    startFetch();
 }
 
 void ServiceWorkerFetchTask::timeoutTimerFired()
diff --git a/Source/WebKit/NetworkProcess/ServiceWorker/ServiceWorkerFetchTask.h b/Source/WebKit/NetworkProcess/ServiceWorker/ServiceWorkerFetchTask.h
index bdfd5e6..da5668e 100644
--- a/Source/WebKit/NetworkProcess/ServiceWorker/ServiceWorkerFetchTask.h
+++ b/Source/WebKit/NetworkProcess/ServiceWorker/ServiceWorkerFetchTask.h
@@ -29,6 +29,7 @@
 
 #include <WebCore/FetchIdentifier.h>
 #include <WebCore/ResourceRequest.h>
+#include <WebCore/ServiceWorkerClientIdentifier.h>
 #include <WebCore/ServiceWorkerTypes.h>
 #include <WebCore/Timer.h>
 #include <pal/SessionID.h>
@@ -52,13 +53,10 @@
 class NetworkResourceLoader;
 class WebSWServerToContextConnection;
 
-class NetworkResourceLoader;
-class WebSWServerToContextConnection;
-
 class ServiceWorkerFetchTask : public CanMakeWeakPtr<ServiceWorkerFetchTask> {
     WTF_MAKE_FAST_ALLOCATED;
 public:
-    ServiceWorkerFetchTask(PAL::SessionID, NetworkResourceLoader&, WebCore::SWServerConnectionIdentifier, WebCore::ServiceWorkerIdentifier);
+    ServiceWorkerFetchTask(PAL::SessionID, NetworkResourceLoader&, WebCore::ResourceRequest&&, WebCore::SWServerConnectionIdentifier, WebCore::ServiceWorkerIdentifier, WebCore::ServiceWorkerRegistrationIdentifier);
     ~ServiceWorkerFetchTask();
 
     void start(WebSWServerToContextConnection&);
@@ -74,6 +72,7 @@
 
     void didNotHandle();
 
+    WebCore::ResourceRequest takeRequest() { return WTFMove(m_currentRequest); }
     bool wasHandled() const { return m_wasHandled; }
 
 private:
@@ -84,7 +83,7 @@
     void didFinish();
     void didFail(const WebCore::ResourceError&);
 
-    void startFetch(WebCore::ResourceRequest&&, WebSWServerToContextConnection&);
+    void startFetch();
 
     void timeoutTimerFired();
 
diff --git a/Source/WebKit/NetworkProcess/ServiceWorker/WebSWServerConnection.cpp b/Source/WebKit/NetworkProcess/ServiceWorker/WebSWServerConnection.cpp
index a190864..77d04e4 100644
--- a/Source/WebKit/NetworkProcess/ServiceWorker/WebSWServerConnection.cpp
+++ b/Source/WebKit/NetworkProcess/ServiceWorker/WebSWServerConnection.cpp
@@ -128,23 +128,51 @@
     send(Messages::WebSWClientConnection::UpdateWorkerState(worker, state));
 }
 
-std::unique_ptr<ServiceWorkerFetchTask> WebSWServerConnection::createFetchTask(NetworkResourceLoader& loader)
+void WebSWServerConnection::controlClient(ServiceWorkerClientIdentifier clientIdentifier, SWServerRegistration& registration, const ResourceRequest& request)
 {
-    if (!loader.parameters().serviceWorkerRegistrationIdentifier)
-        return nullptr;
+    // As per step 12 of https://w3c.github.io/ServiceWorker/#on-fetch-request-algorithm, the active service worker should be controlling the document.
+    // We register a temporary service worker client using the identifier provided by DocumentLoader and notify DocumentLoader about it.
+    // If notification is successful, DocumentLoader will unregister the temporary service worker client just after the document is created and registered as a client.
+    sendWithAsyncReply(Messages::WebSWClientConnection::SetDocumentIsControlled { clientIdentifier.contextIdentifier, registration.data() }, [weakThis = makeWeakPtr(this), this, clientIdentifier](bool isSuccess) {
+        if (!weakThis || isSuccess)
+            return;
+        unregisterServiceWorkerClient(clientIdentifier);
+    });
 
+    ServiceWorkerClientData data { clientIdentifier, ServiceWorkerClientType::Window, ServiceWorkerClientFrameType::None, request.url() };
+    registerServiceWorkerClient(SecurityOriginData { registration.key().topOrigin() }, WTFMove(data), registration.identifier(), request.httpUserAgent());
+}
+
+std::unique_ptr<ServiceWorkerFetchTask> WebSWServerConnection::createFetchTask(NetworkResourceLoader& loader, const ResourceRequest& request)
+{
     if (loader.parameters().serviceWorkersMode == ServiceWorkersMode::None)
         return nullptr;
 
-    if (isPotentialNavigationOrSubresourceRequest(loader.parameters().options.destination))
-        return nullptr;
-
     if (!server().canHandleScheme(loader.originalRequest().url().protocol()))
         return nullptr;
 
-    auto* worker = server().activeWorkerFromRegistrationID(*loader.parameters().serviceWorkerRegistrationIdentifier);
+    Optional<ServiceWorkerRegistrationIdentifier> serviceWorkerRegistrationIdentifier;
+    if (loader.parameters().options.mode == FetchOptions::Mode::Navigate) {
+        auto topOrigin = loader.parameters().isMainFrameNavigation ? SecurityOriginData::fromURL(request.url()) : loader.parameters().topOrigin->data();
+        auto* registration = doRegistrationMatching(topOrigin, request.url());
+        if (!registration)
+            return nullptr;
+
+        serviceWorkerRegistrationIdentifier = registration->identifier();
+        controlClient(ServiceWorkerClientIdentifier { loader.connectionToWebProcess().webProcessIdentifier(), *loader.parameters().options.clientIdentifier }, *registration, request);
+    } else {
+        if (!loader.parameters().serviceWorkerRegistrationIdentifier)
+            return nullptr;
+
+        if (isPotentialNavigationOrSubresourceRequest(loader.parameters().options.destination))
+            return nullptr;
+
+        serviceWorkerRegistrationIdentifier = *loader.parameters().serviceWorkerRegistrationIdentifier;
+    }
+
+    auto* worker = server().activeWorkerFromRegistrationID(*serviceWorkerRegistrationIdentifier);
     if (!worker) {
-        SWSERVERCONNECTION_RELEASE_LOG_ERROR_IF_ALLOWED("startFetch: DidNotHandle because no active worker %s", loader.parameters().serviceWorkerRegistrationIdentifier->loggingString().utf8().data());
+        SWSERVERCONNECTION_RELEASE_LOG_ERROR_IF_ALLOWED("startFetch: DidNotHandle because no active worker %s", serviceWorkerRegistrationIdentifier->loggingString().utf8().data());
         return nullptr;
     }
 
@@ -155,7 +183,7 @@
         return nullptr;
     }
 
-    auto task = makeUnique<ServiceWorkerFetchTask>(sessionID(), loader, identifier(), worker->identifier());
+    auto task = makeUnique<ServiceWorkerFetchTask>(sessionID(), loader, ResourceRequest { request }, identifier(), worker->identifier(), *serviceWorkerRegistrationIdentifier);
     startFetch(*task, *worker);
     return task;
 }
diff --git a/Source/WebKit/NetworkProcess/ServiceWorker/WebSWServerConnection.h b/Source/WebKit/NetworkProcess/ServiceWorker/WebSWServerConnection.h
index 4ed201e..fc0ba3a 100644
--- a/Source/WebKit/NetworkProcess/ServiceWorker/WebSWServerConnection.h
+++ b/Source/WebKit/NetworkProcess/ServiceWorker/WebSWServerConnection.h
@@ -68,7 +68,7 @@
     
     PAL::SessionID sessionID() const;
 
-    std::unique_ptr<ServiceWorkerFetchTask> createFetchTask(NetworkResourceLoader&);
+    std::unique_ptr<ServiceWorkerFetchTask> createFetchTask(NetworkResourceLoader&, const WebCore::ResourceRequest&);
 
 private:
     // Implement SWServer::Connection (Messages to the client WebProcess)
@@ -86,8 +86,6 @@
 
     void scheduleJobInServer(WebCore::ServiceWorkerJobData&&);
 
-    bool handleFetch(NetworkResourceLoader&);
-
     void startFetch(ServiceWorkerFetchTask&, WebCore::SWServerWorker&);
 
     void matchRegistration(uint64_t registrationMatchRequestIdentifier, const WebCore::SecurityOriginData& topOrigin, const URL& clientURL);
@@ -108,6 +106,7 @@
     void updateThrottleState();
 
     void postMessageToServiceWorker(WebCore::ServiceWorkerIdentifier destination, WebCore::MessageWithMessagePorts&&, const WebCore::ServiceWorkerOrClientIdentifier& source);
+    void controlClient(WebCore::ServiceWorkerClientIdentifier, WebCore::SWServerRegistration&, const WebCore::ResourceRequest&);
 
     IPC::Connection* messageSenderConnection() const final { return m_contentConnection.ptr(); }
     uint64_t messageSenderDestinationID() const final { return 0; }
diff --git a/Source/WebKit/WebProcess/Network/NetworkProcessConnection.cpp b/Source/WebKit/WebProcess/Network/NetworkProcessConnection.cpp
index 40c3b4b..fd00d78 100644
--- a/Source/WebKit/WebProcess/Network/NetworkProcessConnection.cpp
+++ b/Source/WebKit/WebProcess/Network/NetworkProcessConnection.cpp
@@ -137,8 +137,7 @@
 
 #if ENABLE(SERVICE_WORKER)
     if (decoder.messageReceiverName() == Messages::WebSWClientConnection::messageReceiverName()) {
-        if (m_swConnection)
-            m_swConnection->didReceiveMessage(connection, decoder);
+        serviceWorkerConnection().didReceiveMessage(connection, decoder);
         return;
     }
     if (decoder.messageReceiverName() == Messages::WebSWContextManagerConnection::messageReceiverName()) {
diff --git a/Source/WebKit/WebProcess/Network/WebLoaderStrategy.cpp b/Source/WebKit/WebProcess/Network/WebLoaderStrategy.cpp
index a9fc04d..4688fec 100644
--- a/Source/WebKit/WebProcess/Network/WebLoaderStrategy.cpp
+++ b/Source/WebKit/WebProcess/Network/WebLoaderStrategy.cpp
@@ -220,7 +220,8 @@
     if (data)
         url.string();
 
-    if ((resourceLoader.options().serviceWorkerRegistrationIdentifier && resourceLoader.options().serviceWorkersMode != ServiceWorkersMode::None) || !tryLoadingUsingURLSchemeHandler(resourceLoader)) {
+    bool canbeLoadedThroughServiceWorkers = resourceLoader.options().serviceWorkersMode != ServiceWorkersMode::None && (resourceLoader.options().serviceWorkerRegistrationIdentifier || resourceLoader.options().mode == FetchOptions::Mode::Navigate);
+    if (canbeLoadedThroughServiceWorkers || !tryLoadingUsingURLSchemeHandler(resourceLoader)) {
 #else
     if (!tryLoadingUsingURLSchemeHandler(resourceLoader)) {
 #endif
@@ -287,7 +288,7 @@
 
 #if ENABLE(SERVICE_WORKER)
     // In case of URL scheme handler, we will try to load on service workers and if unhandled, fallback to URL scheme handler.
-    if (resourceLoader.options().serviceWorkersMode == ServiceWorkersMode::All && webPage &&  webPage->urlSchemeHandlerForScheme(resourceLoader.request().url().protocol().toStringWithoutCopying()))
+    if (webPage && webPage->urlSchemeHandlerForScheme(resourceLoader.request().url().protocol().toStringWithoutCopying()))
         loadParameters.serviceWorkersMode = ServiceWorkersMode::Only;
     else
         loadParameters.serviceWorkersMode = resourceLoader.options().serviceWorkersMode;
diff --git a/Source/WebKit/WebProcess/Storage/WebSWClientConnection.cpp b/Source/WebKit/WebProcess/Storage/WebSWClientConnection.cpp
index 444183b..9c63a02 100644
--- a/Source/WebKit/WebProcess/Storage/WebSWClientConnection.cpp
+++ b/Source/WebKit/WebProcess/Storage/WebSWClientConnection.cpp
@@ -40,6 +40,7 @@
 #include "WebSWOriginTable.h"
 #include "WebSWServerConnectionMessages.h"
 #include <WebCore/Document.h>
+#include <WebCore/DocumentLoader.h>
 #include <WebCore/ProcessIdentifier.h>
 #include <WebCore/SecurityOrigin.h>
 #include <WebCore/SerializedScriptValue.h>
@@ -58,7 +59,6 @@
     : m_identifier(Process::identifier())
     , m_swOriginTable(makeUniqueRef<WebSWOriginTable>())
 {
-    send(Messages::NetworkConnectionToWebProcess::EstablishSWServerConnection { });
 }
 
 WebSWClientConnection::~WebSWClientConnection()
@@ -181,13 +181,20 @@
     send(Messages::WebSWServerConnection::WhenRegistrationReady(callbackID, topOrigin, clientURL));
 }
 
-void WebSWClientConnection::registrationReady(uint64_t callbackID, WebCore::ServiceWorkerRegistrationData&& registrationData)
+void WebSWClientConnection::registrationReady(uint64_t callbackID, ServiceWorkerRegistrationData&& registrationData)
 {
     ASSERT(registrationData.activeWorker);
     if (auto callback = m_ongoingRegistrationReadyTasks.take(callbackID))
         callback(WTFMove(registrationData));
 }
 
+void WebSWClientConnection::setDocumentIsControlled(DocumentIdentifier documentIdentifier, ServiceWorkerRegistrationData&& data, CompletionHandler<void(bool)>&& completionHandler)
+{
+    auto* documentLoader = DocumentLoader::fromTemporaryDocumentIdentifier(documentIdentifier);
+    bool result = documentLoader ? documentLoader->setControllingServiceWorkerRegistration(WTFMove(data)) : false;
+    completionHandler(result);
+}
+
 void WebSWClientConnection::getRegistrations(SecurityOriginData&& topOrigin, const URL& clientURL, GetRegistrationsCallback&& callback)
 {
     ASSERT(isMainThread());
diff --git a/Source/WebKit/WebProcess/Storage/WebSWClientConnection.h b/Source/WebKit/WebProcess/Storage/WebSWClientConnection.h
index 9e445f5..75a3dc6 100644
--- a/Source/WebKit/WebProcess/Storage/WebSWClientConnection.h
+++ b/Source/WebKit/WebProcess/Storage/WebSWClientConnection.h
@@ -79,6 +79,8 @@
     void whenRegistrationReady(const WebCore::SecurityOriginData& topOrigin, const URL& clientURL, WhenRegistrationReadyCallback&&) final;
     void registrationReady(uint64_t callbackID, WebCore::ServiceWorkerRegistrationData&&);
 
+    void setDocumentIsControlled(WebCore::DocumentIdentifier, WebCore::ServiceWorkerRegistrationData&&, CompletionHandler<void(bool)>&&);
+
     void getRegistrations(WebCore::SecurityOriginData&& topOrigin, const URL& clientURL, GetRegistrationsCallback&&) final;
 
     void didResolveRegistrationPromise(const WebCore::ServiceWorkerRegistrationKey&) final;
diff --git a/Source/WebKit/WebProcess/Storage/WebSWClientConnection.messages.in b/Source/WebKit/WebProcess/Storage/WebSWClientConnection.messages.in
index 5a4ace4..9406971 100644
--- a/Source/WebKit/WebProcess/Storage/WebSWClientConnection.messages.in
+++ b/Source/WebKit/WebProcess/Storage/WebSWClientConnection.messages.in
@@ -42,6 +42,8 @@
     DidMatchRegistration(uint64_t matchRequestIdentifier, Optional<WebCore::ServiceWorkerRegistrationData> data)
     DidGetRegistrations(uint64_t matchRequestIdentifier, Vector<WebCore::ServiceWorkerRegistrationData> registrations)
     RegistrationReady(uint64_t registrationReadyRequestIdentifier, struct WebCore::ServiceWorkerRegistrationData data)
+
+    SetDocumentIsControlled(WebCore::DocumentIdentifier temporaryDocumentIdentifier, struct WebCore::ServiceWorkerRegistrationData data) -> (bool isSuccess) Async
 }
 
 #endif // ENABLE(SERVICE_WORKER)
diff --git a/Tools/ChangeLog b/Tools/ChangeLog
index 2854bac..43f9ab3 100644
--- a/Tools/ChangeLog
+++ b/Tools/ChangeLog
@@ -1,3 +1,16 @@
+2019-10-21  youenn fablet  <youenn@apple.com>
+
+        Move service worker registration matching for navigation loads to network process
+        https://bugs.webkit.org/show_bug.cgi?id=203144
+
+        Reviewed by Chris Dumez.
+
+        * TestWebKitAPI/Tests/WebKitCocoa/ServiceWorkerBasic.mm:
+        We are now creating a WebSWClientConnection whenever receiving a WebSWClientConnection message
+        from NetworkProcess. It is free to do so given it no longer requires sending some IPC.
+        Update the tests accordingly.
+        A future patch will remove the service worker registration bit feature and corresponding test.
+
 2019-10-21  Simon Fraser  <simon.fraser@apple.com>
 
         TestWebKitAPI.ScrollViewScrollabilityTests.ScrollableWithOverflowHiddenAndInputView is failing on iPad simulator
diff --git a/Tools/TestWebKitAPI/Tests/WebKitCocoa/ServiceWorkerBasic.mm b/Tools/TestWebKitAPI/Tests/WebKitCocoa/ServiceWorkerBasic.mm
index 13f949b..dd8f0bb 100644
--- a/Tools/TestWebKitAPI/Tests/WebKitCocoa/ServiceWorkerBasic.mm
+++ b/Tools/TestWebKitAPI/Tests/WebKitCocoa/ServiceWorkerBasic.mm
@@ -864,13 +864,6 @@
 }
 @end
 
-static const char* regularPageWithoutConnectionBytes = R"SWRESOURCE(
-<script>
-var result = window.internals.hasServiceWorkerConnection() ? "FAIL" : "PASS";
-window.webkit.messageHandlers.regularPage.postMessage(result);
-</script>
-)SWRESOURCE";
-
 static const char* regularPageWithConnectionBytes = R"SWRESOURCE(
 <script>
 var result = window.internals.hasServiceWorkerConnection() ? "PASS" : "FAIL";
@@ -907,7 +900,7 @@
     [[configuration userContentController] addScriptMessageHandler:regularPageMessageHandler.get() name:@"regularPage"];
 
     ServiceWorkerTCPServer server({
-        { "text/html", regularPageWithoutConnectionBytes },
+        { "text/html", regularPageWithConnectionBytes },
         { "text/html", mainBytes },
         { "application/javascript", scriptBytes },
         { "text/html", regularPageWithConnectionBytes },
@@ -1090,7 +1083,7 @@
         { "text/html", mainBytesWithScope },
         { "application/javascript", scriptBytes },
     }, {
-        { "text/html", regularPageWithoutConnectionBytes },
+        { "text/html", regularPageWithConnectionBytes },
     }, {
         { "text/html", regularPageWithConnectionBytes }
     });