[Service Workers] Add proper implementation for 'updatefound' event
authorcdumez@apple.com <cdumez@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 6 Nov 2017 20:22:11 +0000 (20:22 +0000)
committercdumez@apple.com <cdumez@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 6 Nov 2017 20:22:11 +0000 (20:22 +0000)
https://bugs.webkit.org/show_bug.cgi?id=179302

Reviewed by Brady Eidson.

Source/WebCore:

Add proper implementation for 'updatefound' event instead of faking it.
The 'updatefound' event firing is now triggered from the StorageProcess,
during the install steps, instead of being fired on WebContent process
side in jobResolvedWithRegistration().

Specification:
- https://w3c.github.io/ServiceWorker/#install (step 7)

* workers/service/ServiceWorkerContainer.cpp:
(WebCore::ServiceWorkerContainer::scheduleJob):
(WebCore::ServiceWorkerContainer::fireUpdateFoundEvent):
(WebCore::ServiceWorkerContainer::jobResolvedWithRegistration):
(WebCore::ServiceWorkerContainer::jobDidFinish):
* workers/service/ServiceWorkerContainer.h:
* workers/service/server/SWClientConnection.cpp:
(WebCore::SWClientConnection::fireUpdateFoundEvent):
* workers/service/server/SWClientConnection.h:
* workers/service/server/SWServer.h:
* workers/service/server/SWServerJobQueue.cpp:
(WebCore::SWServerJobQueue::scriptContextStarted):
(WebCore::SWServerJobQueue::install):
* workers/service/server/SWServerJobQueue.h:
* workers/service/server/SWServerRegistration.cpp:
(WebCore::SWServerRegistration::fireUpdateFoundEvent):
* workers/service/server/SWServerRegistration.h:

Source/WebKit:

* StorageProcess/ServiceWorker/WebSWServerConnection.cpp:
(WebKit::WebSWServerConnection::fireUpdateFoundEvent):
* StorageProcess/ServiceWorker/WebSWServerConnection.h:
* WebProcess/Storage/WebSWClientConnection.messages.in:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@224506 268f45cc-cd09-0410-ab3c-d52691b4dbfc

14 files changed:
Source/WebCore/ChangeLog
Source/WebCore/workers/service/ServiceWorkerContainer.cpp
Source/WebCore/workers/service/ServiceWorkerContainer.h
Source/WebCore/workers/service/server/SWClientConnection.cpp
Source/WebCore/workers/service/server/SWClientConnection.h
Source/WebCore/workers/service/server/SWServer.h
Source/WebCore/workers/service/server/SWServerJobQueue.cpp
Source/WebCore/workers/service/server/SWServerJobQueue.h
Source/WebCore/workers/service/server/SWServerRegistration.cpp
Source/WebCore/workers/service/server/SWServerRegistration.h
Source/WebKit/ChangeLog
Source/WebKit/StorageProcess/ServiceWorker/WebSWServerConnection.cpp
Source/WebKit/StorageProcess/ServiceWorker/WebSWServerConnection.h
Source/WebKit/WebProcess/Storage/WebSWClientConnection.messages.in

index a15dc8e..c1e297c 100644 (file)
@@ -1,3 +1,36 @@
+2017-11-06  Chris Dumez  <cdumez@apple.com>
+
+        [Service Workers] Add proper implementation for 'updatefound' event
+        https://bugs.webkit.org/show_bug.cgi?id=179302
+
+        Reviewed by Brady Eidson.
+
+        Add proper implementation for 'updatefound' event instead of faking it.
+        The 'updatefound' event firing is now triggered from the StorageProcess,
+        during the install steps, instead of being fired on WebContent process
+        side in jobResolvedWithRegistration().
+
+        Specification:
+        - https://w3c.github.io/ServiceWorker/#install (step 7)
+
+        * workers/service/ServiceWorkerContainer.cpp:
+        (WebCore::ServiceWorkerContainer::scheduleJob):
+        (WebCore::ServiceWorkerContainer::fireUpdateFoundEvent):
+        (WebCore::ServiceWorkerContainer::jobResolvedWithRegistration):
+        (WebCore::ServiceWorkerContainer::jobDidFinish):
+        * workers/service/ServiceWorkerContainer.h:
+        * workers/service/server/SWClientConnection.cpp:
+        (WebCore::SWClientConnection::fireUpdateFoundEvent):
+        * workers/service/server/SWClientConnection.h:
+        * workers/service/server/SWServer.h:
+        * workers/service/server/SWServerJobQueue.cpp:
+        (WebCore::SWServerJobQueue::scriptContextStarted):
+        (WebCore::SWServerJobQueue::install):
+        * workers/service/server/SWServerJobQueue.h:
+        * workers/service/server/SWServerRegistration.cpp:
+        (WebCore::SWServerRegistration::fireUpdateFoundEvent):
+        * workers/service/server/SWServerRegistration.h:
+
 2017-11-06  Christopher Reid  <chris.reid@sony.com>
 
         Use enum classes within FileSystem
index 3903039..17b14bc 100644 (file)
@@ -263,22 +263,28 @@ void ServiceWorkerContainer::jobFailedWithException(ServiceWorkerJob& job, const
     jobDidFinish(job);
 }
 
-class FakeServiceWorkerInstallMicrotask final : public Microtask {
+class FireUpdateFoundEventMicrotask final : public Microtask {
     WTF_MAKE_FAST_ALLOCATED;
 public:
-    explicit FakeServiceWorkerInstallMicrotask(Ref<ServiceWorkerRegistration>&& registration)
-        : m_registration(WTFMove(registration))
+    explicit FireUpdateFoundEventMicrotask(Ref<ServiceWorkerContainer>&& container, Ref<ServiceWorkerRegistration>&& registration)
+        : m_container(WTFMove(container))
+        , m_registration(WTFMove(registration))
     {
     }
-
 private:
     Result run() final
     {
-        // FIXME: We currently resolve the promise at the end of the install instead of the beginning so we need to fake
-        // a few events to make it look like we are installing and activing the service worker.
-        callOnMainThread([registration = WTFMove(m_registration)] () mutable {
+        callOnMainThread([container = WTFMove(m_container), registration = WTFMove(m_registration)] () mutable {
+            if (container->isStopped())
+                return;
+
             registration->dispatchEvent(Event::create(eventNames().updatefoundEvent, false, false));
+
+            // FIXME: We currently fake a few events to make it look like we are installing and activating the service worker.
             callOnMainThread([registration = WTFMove(registration)] () mutable {
+                if (!registration->installing())
+                    return;
+
                 registration->setWaitingWorker(registration->installing());
                 registration->setInstallingWorker(nullptr);
                 registration->waiting()->setState(ServiceWorker::State::Installed);
@@ -295,9 +301,22 @@ private:
         return Result::Done;
     }
 
+    Ref<ServiceWorkerContainer> m_container;
     Ref<ServiceWorkerRegistration> m_registration;
 };
 
+void ServiceWorkerContainer::fireUpdateFoundEvent(const ServiceWorkerRegistrationKey& key)
+{
+    if (isStopped())
+        return;
+
+    auto* registration = m_registrations.get(key);
+    if (!registration)
+        return;
+
+    MicrotaskQueue::mainThreadQueue().append(std::make_unique<FireUpdateFoundEventMicrotask>(*this, *registration));
+}
+
 void ServiceWorkerContainer::jobResolvedWithRegistration(ServiceWorkerJob& job, ServiceWorkerRegistrationData&& data)
 {
     auto guard = WTF::makeScopeExit([this, &job] {
@@ -326,9 +345,6 @@ void ServiceWorkerContainer::jobResolvedWithRegistration(ServiceWorkerJob& job,
     registration->setInstallingWorker(activeServiceWorker);
 
     job.promise().resolve<IDLInterface<ServiceWorkerRegistration>>(*registration);
-
-    // Use a microtask because we need to make sure this is executed after the promise above is resolved.
-    MicrotaskQueue::mainThreadQueue().append(std::make_unique<FakeServiceWorkerInstallMicrotask>(registration.releaseNonNull()));
 }
 
 void ServiceWorkerContainer::jobResolvedWithUnregistrationResult(ServiceWorkerJob& job, bool unregistrationResult)
index 1e22600..83a0bf4 100644 (file)
@@ -66,6 +66,7 @@ public:
 
     void getRegistration(const String& clientURL, Ref<DeferredPromise>&&);
     void updateRegistration(const ServiceWorkerRegistrationKey&, ServiceWorkerRegistrationState, const std::optional<ServiceWorkerIdentifier>&);
+    void fireUpdateFoundEvent(const ServiceWorkerRegistrationKey&);
 
     using RegistrationsPromise = DOMPromiseDeferred<IDLSequence<IDLInterface<ServiceWorkerRegistration>>>;
     void getRegistrations(RegistrationsPromise&&);
@@ -78,6 +79,8 @@ public:
     void ref() final { refEventTarget(); }
     void deref() final { derefEventTarget(); }
 
+    bool isStopped() const { return m_isStopped; };
+
 private:
     void scheduleJob(Ref<ServiceWorkerJob>&&);
 
index 043604c..84d3c76 100644 (file)
@@ -147,6 +147,15 @@ void SWClientConnection::updateRegistrationState(const ServiceWorkerRegistration
     }
 }
 
+void SWClientConnection::fireUpdateFoundEvent(const ServiceWorkerRegistrationKey& key)
+{
+    // FIXME: We should iterate over all service worker clients, not only documents.
+    for (auto& document : Document::allDocuments()) {
+        if (auto* container = document->serviceWorkerContainer())
+            container->fireUpdateFoundEvent(key);
+    }
+}
+
 } // namespace WebCore
 
 #endif // ENABLE(SERVICE_WORKER)
index 57be04a..7940003 100644 (file)
@@ -67,6 +67,7 @@ protected:
     WEBCORE_EXPORT void startScriptFetchForServer(uint64_t jobIdentifier);
     WEBCORE_EXPORT void postMessageToServiceWorkerClient(uint64_t destinationScriptExecutionContextIdentifier, Ref<SerializedScriptValue>&& message, ServiceWorkerIdentifier source, const String& sourceOrigin);
     WEBCORE_EXPORT void updateRegistrationState(const ServiceWorkerRegistrationKey&, ServiceWorkerRegistrationState, std::optional<ServiceWorkerIdentifier>);
+    WEBCORE_EXPORT void fireUpdateFoundEvent(const ServiceWorkerRegistrationKey&);
 
 private:
     virtual void scheduleJobInServer(const ServiceWorkerJobData&) = 0;
index fd93633..11f9760 100644 (file)
@@ -64,6 +64,7 @@ public:
 
         // Messages to the client WebProcess
         virtual void updateRegistrationStateInClient(const ServiceWorkerRegistrationKey&, ServiceWorkerRegistrationState, std::optional<ServiceWorkerIdentifier>) = 0;
+        virtual void fireUpdateFoundEvent(const ServiceWorkerRegistrationKey&) = 0;
 
     protected:
         WEBCORE_EXPORT Connection(SWServer&, uint64_t identifier);
index 5e015fc..347ada9 100644 (file)
@@ -115,7 +115,20 @@ void SWServerJobQueue::scriptContextStarted(SWServer::Connection&, ServiceWorker
     ASSERT(registration);
     registration->setActiveServiceWorkerIdentifier(identifier);
 
-    m_server.resolveRegistrationJob(firstJob(), registration->data());
+    install(*registration);
+}
+
+// https://w3c.github.io/ServiceWorker/#install
+void SWServerJobQueue::install(SWServerRegistration& registration)
+{
+    // Invoke Resolve Job Promise with job and registration.
+    m_server.resolveRegistrationJob(firstJob(), registration.data());
+
+    // Queue a task to fire an event named updatefound at all the ServiceWorkerRegistration objects
+    // for all the service worker clients whose creation URL matches registration's scope url and
+    // all the service workers whose containing service worker registration is registration.
+    registration.fireUpdateFoundEvent(firstJob().connectionIdentifier());
+
     finishCurrentJob();
 }
 
index 6df8038..06fc7c8 100644 (file)
@@ -63,6 +63,7 @@ private:
 
     void tryClearRegistration(SWServerRegistration&);
     void clearRegistration(SWServerRegistration&);
+    void install(SWServerRegistration&);
 
     Deque<ServiceWorkerJobData> m_jobQueue;
 
index 10267cf..3366ba4 100644 (file)
@@ -83,6 +83,22 @@ void SWServerRegistration::updateRegistrationState(ServiceWorkerRegistrationStat
     }
 }
 
+void SWServerRegistration::fireUpdateFoundEvent(uint64_t connectionIdentifier)
+{
+    // No matter what, we send the event to the connection that scheduled the job. The client registration
+    // may not have gotten a chance to register itself yet.
+    if (auto* connection = m_server.getConnection(connectionIdentifier))
+        connection->fireUpdateFoundEvent(m_registrationKey);
+
+    for (auto& connectionIdentifierWithClients : m_clientRegistrationsByConnection.keys()) {
+        if (connectionIdentifierWithClients == connectionIdentifier)
+            continue;
+
+        if (auto* connection = m_server.getConnection(connectionIdentifierWithClients))
+            connection->fireUpdateFoundEvent(m_registrationKey);
+    }
+}
+
 ServiceWorkerRegistrationData SWServerRegistration::data() const
 {
     return { m_registrationKey, identifier(), m_activeServiceWorkerIdentifier, m_scopeURL, m_scriptURL, m_updateViaCache };
index 90cc2b8..b17a139 100644 (file)
@@ -58,6 +58,7 @@ public:
     void setActiveServiceWorkerIdentifier(ServiceWorkerIdentifier identifier) { m_activeServiceWorkerIdentifier = identifier; }
 
     void updateRegistrationState(ServiceWorkerRegistrationState, SWServerWorker*);
+    void fireUpdateFoundEvent(uint64_t connectionIdentifier);
 
     void addClientServiceWorkerRegistration(uint64_t connectionIdentifier, uint64_t clientRegistrationIdentifier);
     void removeClientServiceWorkerRegistration(uint64_t connectionIdentifier, uint64_t clientRegistrationIdentifier);
index f972d35..1fff2b3 100644 (file)
@@ -1,3 +1,15 @@
+2017-11-06  Chris Dumez  <cdumez@apple.com>
+
+        [Service Workers] Add proper implementation for 'updatefound' event
+        https://bugs.webkit.org/show_bug.cgi?id=179302
+
+        Reviewed by Brady Eidson.
+
+        * StorageProcess/ServiceWorker/WebSWServerConnection.cpp:
+        (WebKit::WebSWServerConnection::fireUpdateFoundEvent):
+        * StorageProcess/ServiceWorker/WebSWServerConnection.h:
+        * WebProcess/Storage/WebSWClientConnection.messages.in:
+
 2017-11-06  Christopher Reid  <chris.reid@sony.com>
 
         Use enum classes within FileSystem
index ce7dbe9..176e600 100644 (file)
@@ -101,6 +101,11 @@ void WebSWServerConnection::updateRegistrationStateInClient(const ServiceWorkerR
     send(Messages::WebSWClientConnection::UpdateRegistrationState(key, state, serviceWorkerIdentifier));
 }
 
+void WebSWServerConnection::fireUpdateFoundEvent(const ServiceWorkerRegistrationKey& key)
+{
+    send(Messages::WebSWClientConnection::FireUpdateFoundEvent(key));
+}
+
 void WebSWServerConnection::updateServiceWorkerContext(const ServiceWorkerContextData& data)
 {
     if (sendToContextProcess(Messages::WebSWContextManagerConnection::UpdateServiceWorker(identifier(), data)))
index 548dd9f..933939c 100644 (file)
@@ -66,6 +66,7 @@ private:
     void resolveUnregistrationJobInClient(uint64_t jobIdentifier, const WebCore::ServiceWorkerRegistrationKey&, bool unregistrationResult) final;
     void startScriptFetchInClient(uint64_t jobIdentifier) final;
     void updateRegistrationStateInClient(const WebCore::ServiceWorkerRegistrationKey&, WebCore::ServiceWorkerRegistrationState, std::optional<WebCore::ServiceWorkerIdentifier>) final;
+    void fireUpdateFoundEvent(const WebCore::ServiceWorkerRegistrationKey&) final;
 
     void startFetch(uint64_t fetchIdentifier, std::optional<WebCore::ServiceWorkerIdentifier>, const WebCore::ResourceRequest&, const WebCore::FetchOptions&);
 
index fcf0bfb..1c3acfc 100644 (file)
@@ -29,6 +29,7 @@ messages -> WebSWClientConnection {
     UnregistrationJobResolvedInServer(uint64_t identifier, bool unregistrationResult)
     StartScriptFetchForServer(uint64_t jobIdentifier)
     UpdateRegistrationState(WebCore::ServiceWorkerRegistrationKey key, enum WebCore::ServiceWorkerRegistrationState state, std::optional<WebCore::ServiceWorkerIdentifier> serviceWorkerIdentifier)
+    FireUpdateFoundEvent(WebCore::ServiceWorkerRegistrationKey key)
 
     SetSWOriginTableSharedMemory(WebKit::SharedMemory::Handle handle)
     PostMessageToServiceWorkerClient(uint64_t destinationScriptExecutionContextIdentifier, IPC::DataReference message, WebCore::ServiceWorkerIdentifier sourceServiceWorkerIdentifier, String sourceOrigin)