Diff
Modified: trunk/Source/WebCore/ChangeLog (283795 => 283796)
--- trunk/Source/WebCore/ChangeLog 2021-10-08 08:25:52 UTC (rev 283795)
+++ trunk/Source/WebCore/ChangeLog 2021-10-08 10:02:49 UTC (rev 283796)
@@ -1,3 +1,16 @@
+2021-10-08 Youenn Fablet <[email protected]>
+
+ Add support for processing push events without service worker clients
+ https://bugs.webkit.org/show_bug.cgi?id=231285
+
+ Reviewed by Chris Dumez.
+
+ Covered by API test.
+
+ * workers/service/server/SWServer.cpp:
+ Add a timer to terminate service worker if a push message is not processed with a given number of seconds.
+ The timer value is the default termination delay or 1 second for testing.
+
2021-10-08 Myles C. Maxfield <[email protected]>
font-families inside @font-palette-values need to be case insensitive
Modified: trunk/Source/WebCore/workers/service/server/SWServer.cpp (283795 => 283796)
--- trunk/Source/WebCore/workers/service/server/SWServer.cpp 2021-10-08 08:25:52 UTC (rev 283795)
+++ trunk/Source/WebCore/workers/service/server/SWServer.cpp 2021-10-08 10:02:49 UTC (rev 283796)
@@ -1214,12 +1214,24 @@
return;
}
- fireFunctionalEvent(*registration, [serviceWorkerIdentifier = worker->identifier(), data = "" callback = WTFMove(callback)](auto&& connectionOrStatus) mutable {
+ fireFunctionalEvent(*registration, [worker = Ref { *worker }, weakThis = WTFMove(weakThis), data = "" callback = WTFMove(callback)](auto&& connectionOrStatus) mutable {
if (!connectionOrStatus.has_value()) {
callback(connectionOrStatus.error() == ShouldSkipEvent::Yes);
return;
}
- connectionOrStatus.value()->firePushEvent(serviceWorkerIdentifier, data, WTFMove(callback));
+
+ auto serviceWorkerIdentifier = worker->identifier();
+ auto terminateWorkerTimer = makeUnique<Timer>([worker = WTFMove(worker)] {
+ RELEASE_LOG_ERROR(ServiceWorker, "Terminating service worker as processing push event took too much time");
+ worker->terminate();
+ });
+ terminateWorkerTimer->startOneShot(weakThis && weakThis->m_isProcessTerminationDelayEnabled ? defaultTerminationDelay : 2_s);
+ connectionOrStatus.value()->firePushEvent(serviceWorkerIdentifier, data, [callback = WTFMove(callback), terminateWorkerTimer = WTFMove(terminateWorkerTimer)](bool succeeded) mutable {
+ if (terminateWorkerTimer->isActive())
+ terminateWorkerTimer->stop();
+
+ callback(succeeded);
+ });
});
});
}
Modified: trunk/Source/WebKit/ChangeLog (283795 => 283796)
--- trunk/Source/WebKit/ChangeLog 2021-10-08 08:25:52 UTC (rev 283795)
+++ trunk/Source/WebKit/ChangeLog 2021-10-08 10:02:49 UTC (rev 283796)
@@ -1,3 +1,25 @@
+2021-10-08 Youenn Fablet <[email protected]>
+
+ Add support for processing push events without service worker clients
+ https://bugs.webkit.org/show_bug.cgi?id=231285
+
+ Reviewed by Chris Dumez.
+
+ When firing a push event, ask UIProcess to take a background assertion for the process running the service worker.
+ We use a counter based approach to take/dispose of the backgorund assertion.
+
+ * NetworkProcess/ServiceWorker/WebSWServerToContextConnection.cpp:
+ * NetworkProcess/ServiceWorker/WebSWServerToContextConnection.h:
+ * UIProcess/API/Cocoa/WKWebsiteDataStore.mm:
+ * UIProcess/API/Cocoa/WKWebsiteDataStorePrivate.h:
+ * UIProcess/Network/NetworkProcessProxy.cpp:
+ * UIProcess/Network/NetworkProcessProxy.h:
+ * UIProcess/Network/NetworkProcessProxy.messages.in:
+ * UIProcess/WebProcessProxy.cpp:
+ * UIProcess/WebProcessProxy.h:
+ * UIProcess/WebsiteData/WebsiteDataStore.cpp:
+ * UIProcess/WebsiteData/WebsiteDataStore.h:
+
2021-10-07 Simon Fraser <[email protected]>
Plumb "animated scroll did end" back from the scrolling tree
Modified: trunk/Source/WebKit/NetworkProcess/ServiceWorker/WebSWServerToContextConnection.cpp (283795 => 283796)
--- trunk/Source/WebKit/NetworkProcess/ServiceWorker/WebSWServerToContextConnection.cpp 2021-10-08 08:25:52 UTC (rev 283795)
+++ trunk/Source/WebKit/NetworkProcess/ServiceWorker/WebSWServerToContextConnection.cpp 2021-10-08 10:02:49 UTC (rev 283796)
@@ -109,10 +109,17 @@
void WebSWServerToContextConnection::firePushEvent(WebCore::ServiceWorkerIdentifier serviceWorkerIdentifier, const std::optional<Vector<uint8_t>>& data, CompletionHandler<void(bool)>&& callback)
{
+ if (!m_processingPushEventsCount++)
+ m_connection.networkProcess().parentProcessConnection()->send(Messages::NetworkProcessProxy::StartServiceWorkerBackgroundProcessing { webProcessIdentifier() }, 0);
+
std::optional<IPC::DataReference> ipcData;
if (data)
ipcData = IPC::DataReference { data->data(), data->size() };
- sendWithAsyncReply(Messages::WebSWContextManagerConnection::FirePushEvent(serviceWorkerIdentifier, ipcData), WTFMove(callback));
+ sendWithAsyncReply(Messages::WebSWContextManagerConnection::FirePushEvent(serviceWorkerIdentifier, ipcData), [weakThis = makeWeakPtr(this), callback = WTFMove(callback)](bool wasProcessed) mutable {
+ if (weakThis && !--weakThis->m_processingPushEventsCount)
+ weakThis->m_connection.networkProcess().parentProcessConnection()->send(Messages::NetworkProcessProxy::EndServiceWorkerBackgroundProcessing { weakThis->webProcessIdentifier() }, 0);
+ callback(wasProcessed);
+ });
}
void WebSWServerToContextConnection::terminateWorker(ServiceWorkerIdentifier serviceWorkerIdentifier)
Modified: trunk/Source/WebKit/NetworkProcess/ServiceWorker/WebSWServerToContextConnection.h (283795 => 283796)
--- trunk/Source/WebKit/NetworkProcess/ServiceWorker/WebSWServerToContextConnection.h 2021-10-08 08:25:52 UTC (rev 283795)
+++ trunk/Source/WebKit/NetworkProcess/ServiceWorker/WebSWServerToContextConnection.h 2021-10-08 10:02:49 UTC (rev 283796)
@@ -105,6 +105,7 @@
HashMap<WebCore::FetchIdentifier, WeakPtr<ServiceWorkerFetchTask>> m_ongoingFetches;
bool m_isThrottleable { true };
WebPageProxyIdentifier m_webPageProxyID;
+ size_t m_processingPushEventsCount { 0 };
}; // class WebSWServerToContextConnection
} // namespace WebKit
Modified: trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataStore.mm (283795 => 283796)
--- trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataStore.mm 2021-10-08 08:25:52 UTC (rev 283795)
+++ trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataStore.mm 2021-10-08 10:02:49 UTC (rev 283796)
@@ -753,6 +753,11 @@
});
}
+-(bool)_hasServiceWorkerBackgroundActivityForTesting
+{
+ return _websiteDataStore->hasServiceWorkerBackgroundActivityForTesting();
+}
+
-(void)_processPushMessage:(NSData*) message registration:(NSURL *)registration completionHandler:(void(^)(bool wasProcessed))completionHandler
{
#if ENABLE(SERVICE_WORKER)
Modified: trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataStorePrivate.h (283795 => 283796)
--- trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataStorePrivate.h 2021-10-08 08:25:52 UTC (rev 283795)
+++ trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataStorePrivate.h 2021-10-08 10:02:49 UTC (rev 283796)
@@ -106,6 +106,7 @@
+ (BOOL)_defaultNetworkProcessExists WK_API_AVAILABLE(macos(12.0), ios(15.0));
- (void)_countNonDefaultSessionSets:(void(^)(size_t))completionHandler;
+-(bool)_hasServiceWorkerBackgroundActivityForTesting WK_API_AVAILABLE(macos(WK_MAC_TBA), ios(WK_IOS_TBA));
-(void)_processPushMessage:(NSData*)data registration:(NSURL *)registration completionHandler:(void(^)(bool))completionHandler WK_API_AVAILABLE(macos(WK_MAC_TBA), ios(WK_IOS_TBA));
@end
Modified: trunk/Source/WebKit/UIProcess/Network/NetworkProcessProxy.cpp (283795 => 283796)
--- trunk/Source/WebKit/UIProcess/Network/NetworkProcessProxy.cpp 2021-10-08 08:25:52 UTC (rev 283795)
+++ trunk/Source/WebKit/UIProcess/Network/NetworkProcessProxy.cpp 2021-10-08 10:02:49 UTC (rev 283796)
@@ -1400,6 +1400,18 @@
serviceWorkerProcess->unregisterServiceWorkerClientProcess(*webProcess);
}
+
+void NetworkProcessProxy::startServiceWorkerBackgroundProcessing(WebCore::ProcessIdentifier serviceWorkerProcessIdentifier)
+{
+ if (auto* serviceWorkerProcess = WebProcessProxy::processForIdentifier(serviceWorkerProcessIdentifier))
+ serviceWorkerProcess->startServiceWorkerBackgroundProcessing();
+}
+
+void NetworkProcessProxy::endServiceWorkerBackgroundProcessing(WebCore::ProcessIdentifier serviceWorkerProcessIdentifier)
+{
+ if (auto* serviceWorkerProcess = WebProcessProxy::processForIdentifier(serviceWorkerProcessIdentifier))
+ serviceWorkerProcess->endServiceWorkerBackgroundProcessing();
+}
#endif
void NetworkProcessProxy::requestStorageSpace(PAL::SessionID sessionID, const WebCore::ClientOrigin& origin, uint64_t currentQuota, uint64_t currentSize, uint64_t spaceRequired, CompletionHandler<void(std::optional<uint64_t> quota)>&& completionHandler)
Modified: trunk/Source/WebKit/UIProcess/Network/NetworkProcessProxy.h (283795 => 283796)
--- trunk/Source/WebKit/UIProcess/Network/NetworkProcessProxy.h 2021-10-08 08:25:52 UTC (rev 283795)
+++ trunk/Source/WebKit/UIProcess/Network/NetworkProcessProxy.h 2021-10-08 10:02:49 UTC (rev 283796)
@@ -323,6 +323,8 @@
void workerContextConnectionNoLongerNeeded(WebCore::ProcessIdentifier);
void registerServiceWorkerClientProcess(WebCore::ProcessIdentifier webProcessIdentifier, WebCore::ProcessIdentifier serviceWorkerProcessIdentifier);
void unregisterServiceWorkerClientProcess(WebCore::ProcessIdentifier webProcessIdentifier, WebCore::ProcessIdentifier serviceWorkerProcessIdentifier);
+ void startServiceWorkerBackgroundProcessing(WebCore::ProcessIdentifier serviceWorkerProcessIdentifier);
+ void endServiceWorkerBackgroundProcessing(WebCore::ProcessIdentifier serviceWorkerProcessIdentifier);
#endif
void terminateWebProcess(WebCore::ProcessIdentifier);
Modified: trunk/Source/WebKit/UIProcess/Network/NetworkProcessProxy.messages.in (283795 => 283796)
--- trunk/Source/WebKit/UIProcess/Network/NetworkProcessProxy.messages.in 2021-10-08 08:25:52 UTC (rev 283795)
+++ trunk/Source/WebKit/UIProcess/Network/NetworkProcessProxy.messages.in 2021-10-08 10:02:49 UTC (rev 283796)
@@ -57,6 +57,8 @@
WorkerContextConnectionNoLongerNeeded(WebCore::ProcessIdentifier identifier)
RegisterServiceWorkerClientProcess(WebCore::ProcessIdentifier webProcessIdentifier, WebCore::ProcessIdentifier serviceWorkerProcessIdentifier)
UnregisterServiceWorkerClientProcess(WebCore::ProcessIdentifier webProcessIdentifier, WebCore::ProcessIdentifier serviceWorkerProcessIdentifier)
+ StartServiceWorkerBackgroundProcessing(WebCore::ProcessIdentifier serviceWorkerProcessIdentifier)
+ EndServiceWorkerBackgroundProcessing(WebCore::ProcessIdentifier serviceWorkerProcessIdentifier)
#endif
SetWebProcessHasUploads(WebCore::ProcessIdentifier processID, bool hasUpload)
Modified: trunk/Source/WebKit/UIProcess/WebProcessProxy.cpp (283795 => 283796)
--- trunk/Source/WebKit/UIProcess/WebProcessProxy.cpp 2021-10-08 08:25:52 UTC (rev 283795)
+++ trunk/Source/WebKit/UIProcess/WebProcessProxy.cpp 2021-10-08 10:02:49 UTC (rev 283796)
@@ -1938,6 +1938,14 @@
m_serviceWorkerInformation->activity = m_throttler.backgroundActivity("Service Worker for background view(s)"_s);
return;
}
+
+ if (m_hasServiceWorkerBackgroundProcessing) {
+ WEBPROCESSPROXY_RELEASE_LOG(ProcessSuspension, "Service Worker for background processing");
+ if (!ProcessThrottler::isValidBackgroundActivity(m_serviceWorkerInformation->activity))
+ m_serviceWorkerInformation->activity = m_throttler.backgroundActivity("Service Worker for background processing"_s);
+ return;
+ }
+
m_serviceWorkerInformation->activity = nullptr;
}
@@ -1970,6 +1978,26 @@
{
return m_serviceWorkerInformation ? ProcessThrottler::isValidBackgroundActivity(m_serviceWorkerInformation->activity) : false;
}
+
+void WebProcessProxy::startServiceWorkerBackgroundProcessing()
+{
+ if (!m_serviceWorkerInformation)
+ return;
+
+ WEBPROCESSPROXY_RELEASE_LOG(ProcessSuspension, "startServiceWorkerBackgroundProcessing");
+ m_hasServiceWorkerBackgroundProcessing = true;
+ updateServiceWorkerProcessAssertion();
+}
+
+void WebProcessProxy::endServiceWorkerBackgroundProcessing()
+{
+ if (!m_serviceWorkerInformation)
+ return;
+
+ WEBPROCESSPROXY_RELEASE_LOG(ProcessSuspension, "endServiceWorkerBackgroundProcessing");
+ m_hasServiceWorkerBackgroundProcessing = false;
+ updateServiceWorkerProcessAssertion();
+}
#endif // ENABLE(SERVICE_WORKER)
void WebProcessProxy::disableServiceWorkers()
Modified: trunk/Source/WebKit/UIProcess/WebProcessProxy.h (283795 => 283796)
--- trunk/Source/WebKit/UIProcess/WebProcessProxy.h 2021-10-08 08:25:52 UTC (rev 283795)
+++ trunk/Source/WebKit/UIProcess/WebProcessProxy.h 2021-10-08 10:02:49 UTC (rev 283796)
@@ -366,6 +366,8 @@
void unregisterServiceWorkerClientProcess(WebProcessProxy&);
bool hasServiceWorkerForegroundActivityForTesting() const;
bool hasServiceWorkerBackgroundActivityForTesting() const;
+ void startServiceWorkerBackgroundProcessing();
+ void endServiceWorkerBackgroundProcessing();
#endif
void setAssertionTypeForTesting(ProcessAssertionType type) { didSetAssertionType(type); }
@@ -657,6 +659,7 @@
WeakHashSet<WebProcessProxy> clientProcesses;
};
std::optional<ServiceWorkerInformation> m_serviceWorkerInformation;
+ bool m_hasServiceWorkerBackgroundProcessing { false };
HashMap<WebCore::SleepDisablerIdentifier, std::unique_ptr<WebCore::SleepDisabler>> m_sleepDisablers;
Modified: trunk/Source/WebKit/UIProcess/WebsiteData/WebsiteDataStore.cpp (283795 => 283796)
--- trunk/Source/WebKit/UIProcess/WebsiteData/WebsiteDataStore.cpp 2021-10-08 08:25:52 UTC (rev 283795)
+++ trunk/Source/WebKit/UIProcess/WebsiteData/WebsiteDataStore.cpp 2021-10-08 10:02:49 UTC (rev 283796)
@@ -1007,6 +1007,11 @@
networkProcess().sendSync(Messages::NetworkProcess::ResetServiceWorkerFetchTimeoutForTesting(), Messages::NetworkProcess::ResetServiceWorkerFetchTimeoutForTesting::Reply(), 0);
}
+bool WebsiteDataStore::hasServiceWorkerBackgroundActivityForTesting() const
+{
+ return WTF::anyOf(WebProcessPool::allProcessPools(), [](auto& pool) { return pool->hasServiceWorkerBackgroundActivityForTesting(); });
+}
+
#if ENABLE(INTELLIGENT_TRACKING_PREVENTION)
void WebsiteDataStore::setMaxStatisticsEntries(size_t maximumEntryCount, CompletionHandler<void()>&& completionHandler)
{
Modified: trunk/Source/WebKit/UIProcess/WebsiteData/WebsiteDataStore.h (283795 => 283796)
--- trunk/Source/WebKit/UIProcess/WebsiteData/WebsiteDataStore.h 2021-10-08 08:25:52 UTC (rev 283795)
+++ trunk/Source/WebKit/UIProcess/WebsiteData/WebsiteDataStore.h 2021-10-08 10:02:49 UTC (rev 283796)
@@ -173,6 +173,7 @@
void setCacheModelSynchronouslyForTesting(CacheModel);
void setServiceWorkerTimeoutForTesting(Seconds);
void resetServiceWorkerTimeoutForTesting();
+ bool hasServiceWorkerBackgroundActivityForTesting() const;
#if ENABLE(INTELLIGENT_TRACKING_PREVENTION)
void fetchDataForRegistrableDomains(OptionSet<WebsiteDataType>, OptionSet<WebsiteDataFetchOption>, Vector<WebCore::RegistrableDomain>&&, CompletionHandler<void(Vector<WebsiteDataRecord>&&, HashSet<WebCore::RegistrableDomain>&&)>&&);
Modified: trunk/Tools/ChangeLog (283795 => 283796)
--- trunk/Tools/ChangeLog 2021-10-08 08:25:52 UTC (rev 283795)
+++ trunk/Tools/ChangeLog 2021-10-08 10:02:49 UTC (rev 283796)
@@ -1,3 +1,12 @@
+2021-10-08 Youenn Fablet <[email protected]>
+
+ Add support for processing push events without service worker clients
+ https://bugs.webkit.org/show_bug.cgi?id=231285
+
+ Reviewed by Chris Dumez.
+
+ * TestWebKitAPI/Tests/WebKitCocoa/PushAPI.mm:
+
2021-10-07 Jonathan Bedard <[email protected]>
[webkitscmpy] Library should own contributors.json loading
Modified: trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/PushAPI.mm (283795 => 283796)
--- trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/PushAPI.mm 2021-10-08 08:25:52 UTC (rev 283795)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/PushAPI.mm 2021-10-08 10:02:49 UTC (rev 283796)
@@ -29,7 +29,9 @@
#import "PlatformUtilities.h"
#import "Test.h"
#import "TestWKWebView.h"
+#import <WebKit/WKWebViewPrivate.h>
#import <WebKit/WKWebsiteDataStorePrivate.h>
+#import <WebKit/_WKWebsiteDataStoreConfiguration.h>
static bool done;
static String expectedMessage;
@@ -105,6 +107,18 @@
static bool pushMessageProcessed = false;
static bool pushMessageSuccessful = false;
+
+static bool waitUntilEvaluatesToTrue(const Function<bool()>& f)
+{
+ unsigned timeout = 0;
+ do {
+ if (f())
+ return true;
+ TestWebKitAPI::Util::sleep(0.1);
+ } while (++timeout < 100);
+ return false;
+}
+
TEST(PushAPI, firePushEvent)
{
TestWebKitAPI::HTTPServer server({
@@ -157,3 +171,177 @@
clearWebsiteDataStore([configuration websiteDataStore]);
}
+
+static const char* waitOneSecondScriptBytes = R"SWRESOURCE(
+let port;
+self.addEventListener("message", (event) => {
+ port = event.data.port;
+ port.postMessage("Ready");
+});
+self.addEventListener("push", (event) => {
+ if (!event.data)
+ return;
+ const value = event.data.text();
+ if (value === 'Sweet Potatoes')
+ event.waitUntil(new Promise(resolve => setTimeout(resolve, 1000)));
+ else if (value === 'Rotten Potatoes')
+ event.waitUntil(new Promise((resolve, reject) => setTimeout(reject, 1000)));
+ else if (value === 'Timeless Potatoes')
+ event.waitUntil(new Promise(resolve => { }));
+});
+)SWRESOURCE";
+
+static void terminateNetworkProcessWhileRegistrationIsStored(WKWebViewConfiguration *configuration)
+{
+ auto path = configuration.websiteDataStore._configuration._serviceWorkerRegistrationDirectory.path;
+ NSURL* directory = [NSURL fileURLWithPath:path isDirectory:YES];
+ NSURL *swDBPath = [directory URLByAppendingPathComponent:@"ServiceWorkerRegistrations-7.sqlite3"];
+ unsigned timeout = 0;
+ while (![[NSFileManager defaultManager] fileExistsAtPath:swDBPath.path] && ++timeout < 100)
+ TestWebKitAPI::Util::sleep(0.1);
+ // Let's close the SQL database.
+ [configuration.websiteDataStore _sendNetworkProcessWillSuspendImminently];
+ [configuration.websiteDataStore _terminateNetworkProcess];
+}
+
+TEST(PushAPI, firePushEventWithNoPagesSuccessful)
+{
+ TestWebKitAPI::HTTPServer server({
+ { "/", { mainBytes } },
+ { "/sw.js", { {{ "Content-Type", "application/_javascript_" }}, waitOneSecondScriptBytes } }
+ }, TestWebKitAPI::HTTPServer::Protocol::Http);
+
+ [WKWebsiteDataStore _allowWebsiteDataRecordsForAllOrigins];
+
+ auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
+ clearWebsiteDataStore([configuration websiteDataStore]);
+
+ auto messageHandler = adoptNS([[PushAPIMessageHandlerWithExpectedMessage alloc] init]);
+ [[configuration userContentController] addScriptMessageHandler:messageHandler.get() name:@"sw"];
+
+ expectedMessage = "Ready";
+ auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration.get()]);
+ [webView loadRequest:server.request()];
+
+ TestWebKitAPI::Util::run(&done);
+
+ [webView _close];
+ webView = nullptr;
+
+ terminateNetworkProcessWhileRegistrationIsStored(configuration.get());
+
+ // Push event for service worker without any related page, should succeed.
+ pushMessageProcessed = false;
+ pushMessageSuccessful = false;
+ NSString *message = @"Sweet Potatoes";
+ [[configuration websiteDataStore] _processPushMessage:[message dataUsingEncoding:NSUTF8StringEncoding] registration:[server.request() URL] completionHandler:^(bool result) {
+ pushMessageSuccessful = result;
+ pushMessageProcessed = true;
+ }];
+
+ EXPECT_TRUE(waitUntilEvaluatesToTrue([&] { return [[configuration websiteDataStore] _hasServiceWorkerBackgroundActivityForTesting]; }));
+
+ TestWebKitAPI::Util::run(&pushMessageProcessed);
+ EXPECT_TRUE(pushMessageSuccessful);
+
+ EXPECT_TRUE(waitUntilEvaluatesToTrue([&] { return ![[configuration websiteDataStore] _hasServiceWorkerBackgroundActivityForTesting]; }));
+
+ clearWebsiteDataStore([configuration websiteDataStore]);
+}
+
+TEST(PushAPI, firePushEventWithNoPagesFail)
+{
+ TestWebKitAPI::HTTPServer server({
+ { "/", { mainBytes } },
+ { "/sw.js", { {{ "Content-Type", "application/_javascript_" }}, waitOneSecondScriptBytes } }
+ }, TestWebKitAPI::HTTPServer::Protocol::Http);
+
+ [WKWebsiteDataStore _allowWebsiteDataRecordsForAllOrigins];
+
+ auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
+ clearWebsiteDataStore([configuration websiteDataStore]);
+
+ auto messageHandler = adoptNS([[PushAPIMessageHandlerWithExpectedMessage alloc] init]);
+ [[configuration userContentController] addScriptMessageHandler:messageHandler.get() name:@"sw"];
+
+ expectedMessage = "Ready";
+ auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration.get()]);
+ [webView loadRequest:server.request()];
+
+ TestWebKitAPI::Util::run(&done);
+
+ [webView _close];
+ webView = nullptr;
+
+ terminateNetworkProcessWhileRegistrationIsStored(configuration.get());
+
+ // Push event for service worker without any related page, should fail.
+ pushMessageProcessed = false;
+ pushMessageSuccessful = false;
+ NSString *message = @"Rotten Potatoes";
+ [[configuration websiteDataStore] _processPushMessage:[message dataUsingEncoding:NSUTF8StringEncoding] registration:[server.request() URL] completionHandler:^(bool result) {
+ pushMessageSuccessful = result;
+ pushMessageProcessed = true;
+ }];
+
+ EXPECT_TRUE(waitUntilEvaluatesToTrue([&] { return [[configuration websiteDataStore] _hasServiceWorkerBackgroundActivityForTesting]; }));
+
+ TestWebKitAPI::Util::run(&pushMessageProcessed);
+ EXPECT_FALSE(pushMessageSuccessful);
+ EXPECT_TRUE(waitUntilEvaluatesToTrue([&] { return ![[configuration websiteDataStore] _hasServiceWorkerBackgroundActivityForTesting]; }));
+
+ clearWebsiteDataStore([configuration websiteDataStore]);
+}
+
+TEST(PushAPI, firePushEventWithNoPagesTimeout)
+{
+ TestWebKitAPI::HTTPServer server({
+ { "/", { mainBytes } },
+ { "/sw.js", { {{ "Content-Type", "application/_javascript_" }}, waitOneSecondScriptBytes } }
+ }, TestWebKitAPI::HTTPServer::Protocol::Http);
+
+ [WKWebsiteDataStore _allowWebsiteDataRecordsForAllOrigins];
+
+ // Disable service worker delay for the purpose of testing, push event should timeout after 1 second.
+ auto dataStoreConfiguration = adoptNS([[_WKWebsiteDataStoreConfiguration alloc] init]);
+ auto dataStore = adoptNS([[WKWebsiteDataStore alloc] _initWithConfiguration:dataStoreConfiguration.get()]);
+
+ auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
+ configuration.get().websiteDataStore = dataStore.get();
+ clearWebsiteDataStore([configuration websiteDataStore]);
+
+ auto messageHandler = adoptNS([[PushAPIMessageHandlerWithExpectedMessage alloc] init]);
+ [[configuration userContentController] addScriptMessageHandler:messageHandler.get() name:@"sw"];
+
+ expectedMessage = "Ready";
+ auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration.get()]);
+ [webView loadRequest:server.request()];
+
+ TestWebKitAPI::Util::run(&done);
+
+ [webView _close];
+ webView = nullptr;
+
+ [dataStoreConfiguration setServiceWorkerProcessTerminationDelayEnabled:NO];
+ dataStore = adoptNS([[WKWebsiteDataStore alloc] _initWithConfiguration:dataStoreConfiguration.get()]);
+ configuration.get().websiteDataStore = dataStore.get();
+
+ terminateNetworkProcessWhileRegistrationIsStored(configuration.get());
+
+ // Push event for service worker without any related page, should timeout so fail.
+ pushMessageProcessed = false;
+ pushMessageSuccessful = false;
+ NSString *message = @"Timeless Potatoes";
+ [[configuration websiteDataStore] _processPushMessage:[message dataUsingEncoding:NSUTF8StringEncoding] registration:[server.request() URL] completionHandler:^(bool result) {
+ pushMessageSuccessful = result;
+ pushMessageProcessed = true;
+ }];
+
+ EXPECT_TRUE(waitUntilEvaluatesToTrue([&] { return [[configuration websiteDataStore] _hasServiceWorkerBackgroundActivityForTesting]; }));
+
+ TestWebKitAPI::Util::run(&pushMessageProcessed);
+ EXPECT_FALSE(pushMessageSuccessful);
+ EXPECT_TRUE(waitUntilEvaluatesToTrue([&] { return ![[configuration websiteDataStore] _hasServiceWorkerBackgroundActivityForTesting]; }));
+
+ clearWebsiteDataStore([configuration websiteDataStore]);
+}