- 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>&&) {