Title: [293676] trunk
Revision
293676
Author
you...@apple.com
Date
2022-05-02 12:46:33 -0700 (Mon, 02 May 2022)

Log Message

PWA in iOS use old assets after publish new servicerWorker/assets
https://bugs.webkit.org/show_bug.cgi?id=199110
<rdar://problem/51992077>

Reviewed by Chris Dumez.

Source/WebCore:

In case a service worker is updated, its state will be waiting until activated.
In case we suspend clients and network process, the newly installed service worker wil remain waiting.
We will wait for the service worker to get activated when network process gets unsuspended, which might not happen if the network process gets stopped by the OS.
To prevent this, we now update the service worker registration as soon as the service worker install job is finished.
The migration from waiting to activated upon network process crash is not ideal: in theory we should fire an activate event on the waiting service worker.
That said, this is still somehow allowed, as failing to activate (say if service worker process is crashing when handling the event) is allowed.

Covered by new API test.

* workers/service/server/SWServer.cpp:

Tools:

* TestWebKitAPI/Tests/WebKitCocoa/ServiceWorkerBasic.mm:
* TestWebKitAPI/cocoa/HTTPServer.h:
* TestWebKitAPI/cocoa/HTTPServer.mm:

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (293675 => 293676)


--- trunk/Source/WebCore/ChangeLog	2022-05-02 19:44:02 UTC (rev 293675)
+++ trunk/Source/WebCore/ChangeLog	2022-05-02 19:46:33 UTC (rev 293676)
@@ -1,3 +1,22 @@
+2022-05-02  Youenn Fablet  <you...@apple.com>
+
+        PWA in iOS use old assets after publish new servicerWorker/assets
+        https://bugs.webkit.org/show_bug.cgi?id=199110
+        <rdar://problem/51992077>
+
+        Reviewed by Chris Dumez.
+
+        In case a service worker is updated, its state will be waiting until activated.
+        In case we suspend clients and network process, the newly installed service worker wil remain waiting.
+        We will wait for the service worker to get activated when network process gets unsuspended, which might not happen if the network process gets stopped by the OS.
+        To prevent this, we now update the service worker registration as soon as the service worker install job is finished.
+        The migration from waiting to activated upon network process crash is not ideal: in theory we should fire an activate event on the waiting service worker.
+        That said, this is still somehow allowed, as failing to activate (say if service worker process is crashing when handling the event) is allowed.
+
+        Covered by new API test.
+
+        * workers/service/server/SWServer.cpp:
+
 2022-05-02  Ziran Sun  <z...@igalia.com>
 
         [selection] Set correct selection range for TEXTAREA when updating default value

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


--- trunk/Source/WebCore/workers/service/server/SWServer.cpp	2022-05-02 19:44:02 UTC (rev 293675)
+++ trunk/Source/WebCore/workers/service/server/SWServer.cpp	2022-05-02 19:46:33 UTC (rev 293676)
@@ -676,6 +676,9 @@
     if (!jobDataIdentifier)
         return;
 
+    if (wasSuccessful)
+        storeRegistrationForWorker(worker);
+
     if (auto* jobQueue = m_jobQueues.get(worker.registrationKey()))
         jobQueue->didFinishInstall(*jobDataIdentifier, worker, wasSuccessful);
 }
@@ -688,8 +691,6 @@
     if (!registration)
         return;
 
-    storeRegistrationForWorker(worker);
-
     registration->didFinishActivation(worker.identifier());
 }
 

Modified: trunk/Tools/ChangeLog (293675 => 293676)


--- trunk/Tools/ChangeLog	2022-05-02 19:44:02 UTC (rev 293675)
+++ trunk/Tools/ChangeLog	2022-05-02 19:46:33 UTC (rev 293676)
@@ -1,3 +1,15 @@
+2022-05-02  Youenn Fablet  <you...@apple.com>
+
+        PWA in iOS use old assets after publish new servicerWorker/assets
+        https://bugs.webkit.org/show_bug.cgi?id=199110
+        <rdar://problem/51992077>
+
+        Reviewed by Chris Dumez.
+
+        * TestWebKitAPI/Tests/WebKitCocoa/ServiceWorkerBasic.mm:
+        * TestWebKitAPI/cocoa/HTTPServer.h:
+        * TestWebKitAPI/cocoa/HTTPServer.mm:
+
 2022-05-02  Eric Carlson  <eric.carl...@apple.com>
 
         [Cocoa] Allow more mime types in captive portal mode

Modified: trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/ServiceWorkerBasic.mm (293675 => 293676)


--- trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/ServiceWorkerBasic.mm	2022-05-02 19:44:02 UTC (rev 293675)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/ServiceWorkerBasic.mm	2022-05-02 19:46:33 UTC (rev 293676)
@@ -3381,3 +3381,135 @@
     [webView evaluateJavaScript:[NSString stringWithFormat:@"openWindowToURL('%@?swap')", [[server.request() URL] absoluteString]] completionHandler: nil];
     EXPECT_WK_STREQ([webView _test_waitForAlert], "client");
 }
+
+#if WK_HAVE_C_SPI
+
+static constexpr auto serviceWorkerStorageTimingMainBytes = R"SWRESOURCE(
+<script>
+function log(msg)
+{
+    window.webkit.messageHandlers.sw.postMessage(msg);
+}
+
+navigator.serviceWorker.addEventListener("message", function(event) {
+    log("Message from worker: " + event.data);
+});
+
+let registration;
+try {
+navigator.serviceWorker.register('/sw.js').then(function(reg) {
+    registration = reg;
+    worker = reg.installing ? reg.installing : reg.active;
+    worker.postMessage("Hello from the web page");
+}).catch(function(error) {
+    log("Registration failed with: " + error);
+});
+} catch(e) {
+    log("Exception: " + e);
+}
+
+function storeRegistration()
+{
+    if (!window.internals) {
+        alert("no internals");
+        return;
+    }
+    internals.storeRegistrationsOnDisk().then(() => {
+        alert("ok");
+    }, () => {
+        alert("ko");
+    });
+}
+
+function waitForWaitingWorker(counter)
+{
+    try {
+        if (registration.waiting) {
+            alert("ok");
+            return;
+        }
+        if (!counter)
+            counter = 0;
+        else if (counter > 100) {
+            alert("ko");
+            return;
+        }
+        setTimeout(() => waitForWaitingWorker(++counter), 50);
+    } catch (e) {
+        alert("error: " + e);
+        return;
+    }
+}
+
+</script>
+)SWRESOURCE"_s;
+
+static constexpr auto serviceWorkerStorageTimingScriptBytesV1 = R"SWRESOURCE(
+self.addEventListener("message", (event) => {
+    event.source.postMessage("V1");
+});
+)SWRESOURCE"_s;
+
+static constexpr auto serviceWorkerStorageTimingScriptBytesV2 = R"SWRESOURCE(
+self.addEventListener("message", (event) => {
+    event.source.postMessage("V2");
+});
+)SWRESOURCE"_s;
+
+TEST(ServiceWorkers, ServiceWorkerStorageTiming)
+{
+    [WKWebsiteDataStore _allowWebsiteDataRecordsForAllOrigins];
+
+    // Start with a clean slate data store
+    [[WKWebsiteDataStore defaultDataStore] removeDataOfTypes:[WKWebsiteDataStore allWebsiteDataTypes] modifiedSince:[NSDate distantPast] completionHandler:^() {
+        done = true;
+    }];
+    TestWebKitAPI::Util::run(&done);
+    done = false;
+
+    auto messageHandler = adoptNS([[SWMessageHandlerWithExpectedMessage alloc] init]);
+
+    TestWebKitAPI::HTTPServer server({
+        { "/"_s, { { { "Cache-Control"_s, "no-cache"_s } }, serviceWorkerStorageTimingMainBytes } },
+        { "/sw.js"_s, { { { "Content-Type"_s, "application/_javascript_"_s } }, serviceWorkerStorageTimingScriptBytesV1 } },
+    });
+
+    auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
+    setConfigurationInjectedBundlePath(configuration.get());
+    [[configuration userContentController] addScriptMessageHandler:messageHandler.get() name:@"sw"];
+
+    done = false;
+    expectedMessage = "Message from worker: V1"_s;
+    auto webView1 = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration.get() addToWindow: YES]);
+    [webView1 loadRequest:server.request()];
+    TestWebKitAPI::Util::run(&done);
+
+    HashMap<String, String> sourceHeaders;
+    sourceHeaders.add("Cache-Control"_s, "no-cache"_s);
+    sourceHeaders.add("Content-Type"_s, "application/_javascript_"_s);
+    server.setResponse("/sw.js"_s, TestWebKitAPI::HTTPResponse { WTFMove(sourceHeaders), serviceWorkerStorageTimingScriptBytesV2 });
+
+    done = false;
+    expectedMessage = "Message from worker: V1"_s;
+    auto webView2 = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration.get()]);
+    [webView2 loadRequest:server.request()];
+    TestWebKitAPI::Util::run(&done);
+
+    // Let's wait for a V2 service worker.
+    [webView1 evaluateJavaScript:@"waitForWaitingWorker()" completionHandler: nil];
+    EXPECT_WK_STREQ([webView1 _test_waitForAlert], "ok");
+
+    // Let's ensure we store it on disk.
+    [webView1 evaluateJavaScript:@"storeRegistration()" completionHandler: nil];
+    EXPECT_WK_STREQ([webView1 _test_waitForAlert], "ok");
+
+    [[webView1 configuration].websiteDataStore _terminateNetworkProcess];
+
+    done = false;
+    expectedMessage = "Message from worker: V2"_s;
+    auto webView3 = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration.get()]);
+    [webView3 loadRequest:server.request()];
+    TestWebKitAPI::Util::run(&done);
+}
+
+#endif // WK_HAVE_C_SPI

Modified: trunk/Tools/TestWebKitAPI/cocoa/HTTPServer.h (293675 => 293676)


--- trunk/Tools/TestWebKitAPI/cocoa/HTTPServer.h	2022-05-02 19:44:02 UTC (rev 293675)
+++ trunk/Tools/TestWebKitAPI/cocoa/HTTPServer.h	2022-05-02 19:46:33 UTC (rev 293676)
@@ -57,6 +57,7 @@
     void cancel();
 
     void addResponse(String&& path, HTTPResponse&&);
+    void setResponse(String&& path, HTTPResponse&&);
 
     static void respondWithOK(Connection);
     static void respondWithChallengeThenOK(Connection);

Modified: trunk/Tools/TestWebKitAPI/cocoa/HTTPServer.mm (293675 => 293676)


--- trunk/Tools/TestWebKitAPI/cocoa/HTTPServer.mm	2022-05-02 19:44:02 UTC (rev 293675)
+++ trunk/Tools/TestWebKitAPI/cocoa/HTTPServer.mm	2022-05-02 19:46:33 UTC (rev 293676)
@@ -222,6 +222,12 @@
     m_requestData->requestMap.add(WTFMove(path), WTFMove(response));
 }
 
+void HTTPServer::setResponse(String&& path, HTTPResponse&& response)
+{
+    ASSERT(m_requestData->requestMap.contains(path));
+    m_requestData->requestMap.set(WTFMove(path), WTFMove(response));
+}
+
 void HTTPServer::respondWithChallengeThenOK(Connection connection)
 {
     connection.receiveHTTPRequest([connection] (Vector<char>&&) {
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to