Handle Fetch should wait for the service worker's state to become activated
authorcdumez@apple.com <cdumez@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 19 Dec 2017 21:22:22 +0000 (21:22 +0000)
committercdumez@apple.com <cdumez@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 19 Dec 2017 21:22:22 +0000 (21:22 +0000)
https://bugs.webkit.org/show_bug.cgi?id=180959

Reviewed by Youenn Fablet.

LayoutTests/imported/w3c:

Rebaseline WPT test that is now passing.

* web-platform-tests/service-workers/service-worker/fetch-waits-for-activate.https-expected.txt:

Source/WebCore:

Handle Fetch should wait for the service worker's state to become activated when
it is currently activating.

Specification:
- https://w3c.github.io/ServiceWorker/#on-fetch-request-algorithm (Step 16)

No new tests, rebaselined existing test.

* workers/service/server/SWServerWorker.cpp:
(WebCore::SWServerWorker::~SWServerWorker):
(WebCore::SWServerWorker::whenActivated):
(WebCore::SWServerWorker::setState):
(WebCore::SWServerWorker::callWhenActivatedHandler):
* workers/service/server/SWServerWorker.h:

Source/WebKit:

Handle Fetch should wait for the service worker's state to become activated when
it is currently activating.

Specification:
- https://w3c.github.io/ServiceWorker/#on-fetch-request-algorithm (Step 16)

* StorageProcess/ServiceWorker/WebSWServerConnection.cpp:
(WebKit::WebSWServerConnection::startFetch):

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

LayoutTests/imported/w3c/ChangeLog
LayoutTests/imported/w3c/web-platform-tests/service-workers/service-worker/fetch-waits-for-activate.https-expected.txt
Source/WebCore/ChangeLog
Source/WebCore/workers/service/server/SWServer.h
Source/WebCore/workers/service/server/SWServerWorker.cpp
Source/WebCore/workers/service/server/SWServerWorker.h
Source/WebKit/ChangeLog
Source/WebKit/StorageProcess/ServiceWorker/WebSWServerConnection.cpp

index 17290c4..204df29 100644 (file)
@@ -1,3 +1,14 @@
+2017-12-19  Chris Dumez  <cdumez@apple.com>
+
+        Handle Fetch should wait for the service worker's state to become activated
+        https://bugs.webkit.org/show_bug.cgi?id=180959
+
+        Reviewed by Youenn Fablet.
+
+        Rebaseline WPT test that is now passing.
+
+        * web-platform-tests/service-workers/service-worker/fetch-waits-for-activate.https-expected.txt:
+
 2017-12-19  Youenn Fablet  <youenn@apple.com>
 
         Service Worker should not clean HTTP headers added by the application or by fetch specification before service worker interception
index 5463581..d7fbbb2 100644 (file)
@@ -1,4 +1,3 @@
 
-
-FAIL Fetch events should wait for the activate event to complete. assert_unreached: unexpected rejection: assert_equals: frame should not be loaded expected (undefined) undefined but got (object) Element node <iframe class="test-iframe" src="resources/fetch-waits-fo... Reached unreachable code
+PASS Fetch events should wait for the activate event to complete. 
 
index e0e9d1d..908039f 100644 (file)
@@ -1,3 +1,25 @@
+2017-12-19  Chris Dumez  <cdumez@apple.com>
+
+        Handle Fetch should wait for the service worker's state to become activated
+        https://bugs.webkit.org/show_bug.cgi?id=180959
+
+        Reviewed by Youenn Fablet.
+
+        Handle Fetch should wait for the service worker's state to become activated when
+        it is currently activating.
+
+        Specification:
+        - https://w3c.github.io/ServiceWorker/#on-fetch-request-algorithm (Step 16)
+
+        No new tests, rebaselined existing test.
+
+        * workers/service/server/SWServerWorker.cpp:
+        (WebCore::SWServerWorker::~SWServerWorker):
+        (WebCore::SWServerWorker::whenActivated):
+        (WebCore::SWServerWorker::setState):
+        (WebCore::SWServerWorker::callWhenActivatedHandler):
+        * workers/service/server/SWServerWorker.h:
+
 2017-12-19  Yusuke Suzuki  <utatane.tea@gmail.com>
 
         [YARR] Yarr should return ErrorCode instead of error messages (const char*)
index 481bde6..f76cb94 100644 (file)
@@ -46,6 +46,7 @@
 #include <wtf/ThreadSafeRefCounted.h>
 #include <wtf/Threading.h>
 #include <wtf/UniqueRef.h>
+#include <wtf/WeakPtr.h>
 
 namespace WebCore {
 
@@ -74,6 +75,8 @@ public:
         using Identifier = SWServerConnectionIdentifier;
         Identifier identifier() const { return m_identifier; }
 
+        auto& weakPtrFactory() { return m_weakFactory; }
+
         WEBCORE_EXPORT void didResolveRegistrationPromise(const ServiceWorkerRegistrationKey&);
         SWServerRegistration* doRegistrationMatching(const SecurityOriginData& topOrigin, const URL& clientURL) { return m_server.doRegistrationMatching(topOrigin, clientURL); }
         void resolveRegistrationReadyRequests(SWServerRegistration&);
@@ -113,6 +116,7 @@ public:
 
         SWServer& m_server;
         Identifier m_identifier;
+        WeakPtrFactory<Connection> m_weakFactory;
         Vector<RegistrationReadyRequest> m_registrationReadyRequests;
     };
 
index 1a575be..f8ee2de 100644 (file)
@@ -58,6 +58,8 @@ SWServerWorker::SWServerWorker(SWServer& server, SWServerRegistration& registrat
 
 SWServerWorker::~SWServerWorker()
 {
+    callWhenActivatedHandler(false);
+
     auto taken = allWorkers().take(identifier());
     ASSERT_UNUSED(taken, taken == this);
 }
@@ -152,6 +154,30 @@ void SWServerWorker::setHasPendingEvents(bool hasPendingEvents)
     registration->tryActivate();
 }
 
+void SWServerWorker::whenActivated(WTF::Function<void(bool)>&& handler)
+{
+    if (state() == ServiceWorkerState::Activated) {
+        handler(true);
+        return;
+    }
+    m_whenActivatedHandlers.append(WTFMove(handler));
+}
+
+void SWServerWorker::setState(ServiceWorkerState state)
+{
+    m_data.state = state;
+
+    if (state == ServiceWorkerState::Activated || state == ServiceWorkerState::Redundant)
+        callWhenActivatedHandler(state == ServiceWorkerState::Activated);
+}
+
+void SWServerWorker::callWhenActivatedHandler(bool success)
+{
+    auto whenActivatedHandlers = WTFMove(m_whenActivatedHandlers);
+    for (auto& handler : whenActivatedHandlers)
+        handler(success);
+}
+
 } // namespace WebCore
 
 #endif // ENABLE(SERVICE_WORKER)
index e1275c0..38c1129 100644 (file)
@@ -59,6 +59,8 @@ public:
 
     void terminate();
 
+    WEBCORE_EXPORT void whenActivated(WTF::Function<void(bool)>&&);
+
     enum class State {
         Running,
         Terminating,
@@ -78,7 +80,7 @@ public:
     SWServerToContextConnectionIdentifier contextConnectionIdentifier() const { return m_contextConnectionIdentifier; }
 
     ServiceWorkerState state() const { return m_data.state; }
-    void setState(ServiceWorkerState state) { m_data.state = state; }
+    void setState(ServiceWorkerState);
 
     bool hasPendingEvents() const { return m_hasPendingEvents; }
     void setHasPendingEvents(bool);
@@ -104,6 +106,8 @@ public:
 private:
     SWServerWorker(SWServer&, SWServerRegistration&, SWServerToContextConnectionIdentifier, const URL&, const String& script, WorkerType, ServiceWorkerIdentifier);
 
+    void callWhenActivatedHandler(bool success);
+
     SWServer& m_server;
     ServiceWorkerRegistrationKey m_registrationKey;
     SWServerToContextConnectionIdentifier m_contextConnectionIdentifier;
@@ -113,6 +117,7 @@ private:
     State m_state { State::NotRunning };
     mutable std::optional<ClientOrigin> m_origin;
     bool m_isSkipWaitingFlagSet { false };
+    Vector<WTF::Function<void(bool)>> m_whenActivatedHandlers;
 };
 
 } // namespace WebCore
index 72acb71..48229ae 100644 (file)
@@ -1,3 +1,19 @@
+2017-12-19  Chris Dumez  <cdumez@apple.com>
+
+        Handle Fetch should wait for the service worker's state to become activated
+        https://bugs.webkit.org/show_bug.cgi?id=180959
+
+        Reviewed by Youenn Fablet.
+
+        Handle Fetch should wait for the service worker's state to become activated when
+        it is currently activating.
+
+        Specification:
+        - https://w3c.github.io/ServiceWorker/#on-fetch-request-algorithm (Step 16)
+
+        * StorageProcess/ServiceWorker/WebSWServerConnection.cpp:
+        (WebKit::WebSWServerConnection::startFetch):
+
 2017-12-19  Youenn Fablet  <youenn@apple.com>
 
         Service Worker should not clean HTTP headers added by the application or by fetch specification before service worker interception
index 6dde72d..f3a2224 100644 (file)
@@ -128,13 +128,36 @@ void WebSWServerConnection::updateWorkerStateInClient(ServiceWorkerIdentifier wo
 
 void WebSWServerConnection::startFetch(uint64_t fetchIdentifier, ServiceWorkerIdentifier serviceWorkerIdentifier, ResourceRequest&& request, FetchOptions&& options, IPC::FormDataReference&& formData, String&& referrer)
 {
-    // It's possible this specific worker cannot be re-run (e.g. its registration has been removed)
-    server().runServiceWorkerIfNecessary(serviceWorkerIdentifier, [contentConnection = m_contentConnection.copyRef(), connectionIdentifier = identifier(), fetchIdentifier, serviceWorkerIdentifier = serviceWorkerIdentifier, request = WTFMove(request), options = WTFMove(options), formData = WTFMove(formData), referrer = WTFMove(referrer)](bool success, auto& contextConnection) {
-        if (success)
-            sendToContextProcess(contextConnection, Messages::WebSWContextManagerConnection::StartFetch { connectionIdentifier, fetchIdentifier, serviceWorkerIdentifier, request, options, formData, referrer });
-        else
-            contentConnection->send(Messages::ServiceWorkerClientFetch::DidNotHandle { }, fetchIdentifier);
-    });
+    auto* worker = server().workerByID(serviceWorkerIdentifier);
+    if (!worker) {
+        m_contentConnection->send(Messages::ServiceWorkerClientFetch::DidNotHandle { }, fetchIdentifier);
+        return;
+    }
+
+    auto runServerWorkerAndStartFetch = [weakThis = makeWeakPtr(this), this, fetchIdentifier, serviceWorkerIdentifier, request = WTFMove(request), options = WTFMove(options), formData = WTFMove(formData), referrer = WTFMove(referrer)](bool success) mutable {
+        if (!weakThis)
+            return;
+
+        if (!success) {
+            m_contentConnection->send(Messages::ServiceWorkerClientFetch::DidNotHandle { }, fetchIdentifier);
+            return;
+        }
+
+        server().runServiceWorkerIfNecessary(serviceWorkerIdentifier, [weakThis = WTFMove(weakThis), this, fetchIdentifier, serviceWorkerIdentifier, request = WTFMove(request), options = WTFMove(options), formData = WTFMove(formData), referrer = WTFMove(referrer)](bool success, auto& contextConnection) {
+            if (!weakThis)
+                return;
+
+            if (success)
+                sendToContextProcess(contextConnection, Messages::WebSWContextManagerConnection::StartFetch { identifier(), fetchIdentifier, serviceWorkerIdentifier, request, options, formData, referrer });
+            else
+                m_contentConnection->send(Messages::ServiceWorkerClientFetch::DidNotHandle { }, fetchIdentifier);
+        });
+    };
+
+    if (worker->state() == ServiceWorkerState::Activating)
+        worker->whenActivated(WTFMove(runServerWorkerAndStartFetch));
+    else
+        runServerWorkerAndStartFetch(true);
 }
 
 void WebSWServerConnection::postMessageToServiceWorker(ServiceWorkerIdentifier destinationIdentifier, IPC::DataReference&& message, const ServiceWorkerOrClientIdentifier& sourceIdentifier)