Diff
Modified: trunk/Source/WebCore/ChangeLog (292455 => 292456)
--- trunk/Source/WebCore/ChangeLog 2022-04-06 09:16:42 UTC (rev 292455)
+++ trunk/Source/WebCore/ChangeLog 2022-04-06 10:05:05 UTC (rev 292456)
@@ -1,3 +1,23 @@
+2022-04-06 Youenn Fablet <you...@apple.com>
+
+ ServiceWorkerClients.openWindow should not need to get all clients asynchronously to resolve its promise
+ https://bugs.webkit.org/show_bug.cgi?id=238503
+
+ Reviewed by Chris Dumez.
+
+ Move matching client in openWindow in network process as an optimization.
+ This also prevents some race conditions where the opened page could quickly navigate to another page.
+ Also have a code path that rejects the openWindow promise, and trigger that code path in case of internal error.
+
+ Covered by existing and API test.
+
+ * workers/WorkerGlobalScope.h:
+ * workers/service/ServiceWorkerClients.cpp:
+ * workers/service/context/SWContextManager.h:
+ * workers/service/server/SWServer.cpp:
+ * workers/service/server/SWServer.h:
+ * workers/service/server/SWServerToContextConnection.h:
+
2022-04-06 Antti Koivisto <an...@apple.com>
Remove some @apply leftover code
Modified: trunk/Source/WebCore/workers/WorkerGlobalScope.h (292455 => 292456)
--- trunk/Source/WebCore/workers/WorkerGlobalScope.h 2022-04-06 09:16:42 UTC (rev 292455)
+++ trunk/Source/WebCore/workers/WorkerGlobalScope.h 2022-04-06 10:05:05 UTC (rev 292456)
@@ -28,6 +28,7 @@
#include "Base64Utilities.h"
#include "CacheStorageConnection.h"
+#include "ClientOrigin.h"
#include "ImageBitmap.h"
#include "ScriptExecutionContext.h"
#include "Supplementable.h"
@@ -156,6 +157,8 @@
void setMainScriptSourceProvider(ScriptBufferSourceProvider&);
void addImportedScriptSourceProvider(const URL&, ScriptBufferSourceProvider&);
+ ClientOrigin clientOrigin() const { return { topOrigin().data(), securityOrigin()->data() }; }
+
protected:
WorkerGlobalScope(WorkerThreadType, const WorkerParameters&, Ref<SecurityOrigin>&&, WorkerThread&, Ref<SecurityOrigin>&& topOrigin, IDBClient::IDBConnectionProxy*, SocketProvider*);
Modified: trunk/Source/WebCore/workers/service/ServiceWorkerClients.cpp (292455 => 292456)
--- trunk/Source/WebCore/workers/service/ServiceWorkerClients.cpp 2022-04-06 09:16:42 UTC (rev 292455)
+++ trunk/Source/WebCore/workers/service/ServiceWorkerClients.cpp 2022-04-06 10:05:05 UTC (rev 292456)
@@ -90,38 +90,16 @@
});
}
-static void matchWindowWithPageIdentifier(ServiceWorkerIdentifier serviceWorkerIdentifier, PageIdentifier pageIdentifier, CompletionHandler<void(ServiceWorkerGlobalScope&, std::optional<ServiceWorkerClientData>)>&& callback)
-{
- callOnMainThread([serviceWorkerIdentifier, pageIdentifier, callback = WTFMove(callback)] () mutable {
- auto connection = SWContextManager::singleton().connection();
- auto options = ServiceWorkerClientQueryOptions { true, ServiceWorkerClientType::Window };
- connection->matchAll(serviceWorkerIdentifier, options, [serviceWorkerIdentifier, pageIdentifier, callback = WTFMove(callback)] (Vector<ServiceWorkerClientData>&& clientsData) mutable {
- SWContextManager::singleton().postTaskToServiceWorker(serviceWorkerIdentifier, [pageIdentifier, callback = WTFMove(callback), clientsData = crossThreadCopy(WTFMove(clientsData))] (auto& scope) mutable {
- for (auto& data : clientsData) {
- if (data.pageIdentifier == pageIdentifier) {
- callback(scope, data);
- return;
- }
- }
-
- callback(scope, std::nullopt);
- });
- });
- });
-}
-
void ServiceWorkerClients::openWindow(ScriptExecutionContext& context, const String& urlString, Ref<DeferredPromise>&& promise)
{
LOG(ServiceWorker, "WebProcess %i service worker calling openWindow to URL %s", getpid(), urlString.utf8().data());
- auto serviceWorkerIdentifier = downcast<ServiceWorkerGlobalScope>(context).thread().identifier();
- auto url = ""
-
if (context.settingsValues().serviceWorkersUserGestureEnabled && !downcast<ServiceWorkerGlobalScope>(context).isProcessingUserGesture()) {
promise->reject(Exception { InvalidAccessError, "ServiceWorkerClients.openWindow() requires a user gesture"_s });
return;
}
+ auto url = ""
if (!url.isValid()) {
promise->reject(Exception { TypeError, makeString("URL string ", urlString, " cannot successfully be parsed"_s) });
return;
@@ -132,31 +110,34 @@
return;
}
+ auto serviceWorkerIdentifier = downcast<ServiceWorkerGlobalScope>(context).thread().identifier();
callOnMainThread([promiseIdentifier = addPendingPromise(WTFMove(promise)), serviceWorkerIdentifier, url = "" () mutable {
auto connection = SWContextManager::singleton().connection();
- connection->openWindow(serviceWorkerIdentifier, url.string(), [promiseIdentifier, serviceWorkerIdentifier] (std::optional<PageIdentifier>&& pageIdentifier) mutable {
- SWContextManager::singleton().postTaskToServiceWorker(serviceWorkerIdentifier, [promiseIdentifier, pageIdentifier = WTFMove(pageIdentifier), serviceWorkerIdentifier] (ServiceWorkerGlobalScope& scope) mutable {
- LOG(ServiceWorker, "WebProcess %i finished ServiceWorkerClients::openWindow call. Resulting page identifier is %s", getpid(), pageIdentifier ? pageIdentifier->loggingString().utf8().data() : "<NONE>");
+ connection->openWindow(serviceWorkerIdentifier, url, [promiseIdentifier, serviceWorkerIdentifier] (auto&& result) mutable {
+ SWContextManager::singleton().postTaskToServiceWorker(serviceWorkerIdentifier, [promiseIdentifier, result = crossThreadCopy(WTFMove(result))] (ServiceWorkerGlobalScope& scope) mutable {
+ LOG(ServiceWorker, "WebProcess %i finished ServiceWorkerClients::openWindow call result is %d.", getpid(), !result.hasException());
- if (!pageIdentifier) {
- if (auto promise = scope.clients().takePendingPromise(promiseIdentifier))
- promise->resolveWithJSValue(JSC::jsNull());
+ auto promise = scope.clients().takePendingPromise(promiseIdentifier);
+ if (!promise)
return;
+
+ if (result.hasException()) {
+ promise->reject(result.releaseException());
+ return;
}
- matchWindowWithPageIdentifier(serviceWorkerIdentifier, *pageIdentifier, [promiseIdentifier] (auto& scope, std::optional<ServiceWorkerClientData> clientData) mutable {
- auto promise = scope.clients().takePendingPromise(promiseIdentifier);
- if (!promise)
- return;
+ auto clientData = result.releaseReturnValue();
+ if (!clientData) {
+ promise->resolveWithJSValue(JSC::jsNull());
+ return;
+ }
- if (!clientData) {
- promise->resolveWithJSValue(JSC::jsNull());
- return;
- }
-
- auto client = ServiceWorkerClient::create(scope, WTFMove(*clientData));
- promise->template resolve<IDLInterface<ServiceWorkerClient>>(WTFMove(client));
- });
+#if ASSERT_ENABLED
+ auto originData = SecurityOriginData::fromURL(clientData->url);
+ ClientOrigin clientOrigin { originData, originData };
+#endif
+ ASSERT(scope.clientOrigin() == clientOrigin);
+ promise->template resolve<IDLInterface<ServiceWorkerClient>>(ServiceWorkerClient::create(scope, WTFMove(*clientData)));
});
});
});
Modified: trunk/Source/WebCore/workers/service/context/SWContextManager.h (292455 => 292456)
--- trunk/Source/WebCore/workers/service/context/SWContextManager.h 2022-04-06 09:16:42 UTC (rev 292455)
+++ trunk/Source/WebCore/workers/service/context/SWContextManager.h 2022-04-06 10:05:05 UTC (rev 292456)
@@ -67,9 +67,11 @@
virtual void findClientByVisibleIdentifier(ServiceWorkerIdentifier, const String&, FindClientByIdentifierCallback&&) = 0;
virtual void matchAll(ServiceWorkerIdentifier, const ServiceWorkerClientQueryOptions&, ServiceWorkerClientsMatchAllCallback&&) = 0;
virtual void claim(ServiceWorkerIdentifier, CompletionHandler<void(ExceptionOr<void>&&)>&&) = 0;
- virtual void focus(ScriptExecutionContextIdentifier, CompletionHandler<void(std::optional<WebCore::ServiceWorkerClientData>&&)>&&) = 0;
- virtual void openWindow(ServiceWorkerIdentifier, const String& url, CompletionHandler<void(std::optional<PageIdentifier>&&)>&&) = 0;
+ virtual void focus(ScriptExecutionContextIdentifier, CompletionHandler<void(std::optional<ServiceWorkerClientData>&&)>&&) = 0;
+ using OpenWindowCallback = CompletionHandler<void(ExceptionOr<std::optional<ServiceWorkerClientData>>&&)>;
+ virtual void openWindow(ServiceWorkerIdentifier, const URL&, OpenWindowCallback&&) = 0;
+
virtual void didFailHeartBeatCheck(ServiceWorkerIdentifier) = 0;
virtual void setAsInspected(ServiceWorkerIdentifier, bool) = 0;
Modified: trunk/Source/WebCore/workers/service/server/SWServer.cpp (292455 => 292456)
--- trunk/Source/WebCore/workers/service/server/SWServer.cpp 2022-04-06 09:16:42 UTC (rev 292455)
+++ trunk/Source/WebCore/workers/service/server/SWServer.cpp 2022-04-06 10:05:05 UTC (rev 292456)
@@ -112,6 +112,20 @@
return clientIterator->value;
}
+std::optional<ServiceWorkerClientData> SWServer::topLevelServiceWorkerClientFromPageIdentifier(const ClientOrigin& clientOrigin, PageIdentifier pageIdentifier) const
+{
+ auto iterator = m_clientIdentifiersPerOrigin.find(clientOrigin);
+ if (iterator == m_clientIdentifiersPerOrigin.end())
+ return { };
+
+ for (auto clientIdentifier : iterator->value.identifiers) {
+ auto clientIterator = m_clientsById.find(clientIdentifier);
+ if (clientIterator->value->frameType == ServiceWorkerClientFrameType::TopLevel && clientIterator->value->pageIdentifier == pageIdentifier)
+ return clientIterator->value;
+ }
+ return { };
+}
+
String SWServer::serviceWorkerClientUserAgent(const ClientOrigin& clientOrigin) const
{
auto iterator = m_clientIdentifiersPerOrigin.find(clientOrigin);
Modified: trunk/Source/WebCore/workers/service/server/SWServer.h (292455 => 292456)
--- trunk/Source/WebCore/workers/service/server/SWServer.h 2022-04-06 09:16:42 UTC (rev 292455)
+++ trunk/Source/WebCore/workers/service/server/SWServer.h 2022-04-06 10:05:05 UTC (rev 292456)
@@ -29,6 +29,7 @@
#include "ClientOrigin.h"
#include "ExceptionOr.h"
+#include "PageIdentifier.h"
#include "SWServerWorker.h"
#include "ScriptExecutionContextIdentifier.h"
#include "SecurityOriginData.h"
@@ -161,6 +162,7 @@
WEBCORE_EXPORT SWServerWorker* workerByID(ServiceWorkerIdentifier) const;
WEBCORE_EXPORT std::optional<ServiceWorkerClientData> serviceWorkerClientWithOriginByID(const ClientOrigin&, const ScriptExecutionContextIdentifier&) const;
+ WEBCORE_EXPORT std::optional<ServiceWorkerClientData> topLevelServiceWorkerClientFromPageIdentifier(const ClientOrigin&, PageIdentifier) const;
String serviceWorkerClientUserAgent(const ClientOrigin&) const;
WEBCORE_EXPORT SWServerWorker* activeWorkerFromRegistrationID(ServiceWorkerRegistrationIdentifier);
Modified: trunk/Source/WebCore/workers/service/server/SWServerToContextConnection.h (292455 => 292456)
--- trunk/Source/WebCore/workers/service/server/SWServerToContextConnection.h 2022-04-06 09:16:42 UTC (rev 292455)
+++ trunk/Source/WebCore/workers/service/server/SWServerToContextConnection.h 2022-04-06 10:05:05 UTC (rev 292456)
@@ -86,7 +86,8 @@
WEBCORE_EXPORT void setAsInspected(ServiceWorkerIdentifier, bool);
WEBCORE_EXPORT void findClientByVisibleIdentifier(ServiceWorkerIdentifier, const String& clientIdentifier, CompletionHandler<void(std::optional<WebCore::ServiceWorkerClientData>&&)>&&);
- virtual void openWindow(ServiceWorkerIdentifier, const String& urlString, CompletionHandler<void(std::optional<WebCore::PageIdentifier>&&)>&&) = 0;
+ using OpenWindowCallback = CompletionHandler<void(Expected<std::optional<ServiceWorkerClientData>, ExceptionData>&&)>;
+ virtual void openWindow(ServiceWorkerIdentifier, const URL&, OpenWindowCallback&&) = 0;
const RegistrableDomain& registrableDomain() const { return m_registrableDomain; }
std::optional<ScriptExecutionContextIdentifier> serviceWorkerPageIdentifier() const { return m_serviceWorkerPageIdentifier; }
Modified: trunk/Source/WebKit/ChangeLog (292455 => 292456)
--- trunk/Source/WebKit/ChangeLog 2022-04-06 09:16:42 UTC (rev 292455)
+++ trunk/Source/WebKit/ChangeLog 2022-04-06 10:05:05 UTC (rev 292456)
@@ -1,5 +1,21 @@
2022-04-06 Youenn Fablet <you...@apple.com>
+ ServiceWorkerClients.openWindow should not need to get all clients asynchronously to resolve its promise
+ https://bugs.webkit.org/show_bug.cgi?id=238503
+
+ Reviewed by Chris Dumez.
+
+ Add logic to get the client from its page ID.
+ In case of internal error case, trigger promise rejection instead of promise resolution with null.
+
+ * NetworkProcess/ServiceWorker/WebSWServerToContextConnection.cpp:
+ * NetworkProcess/ServiceWorker/WebSWServerToContextConnection.h:
+ * NetworkProcess/ServiceWorker/WebSWServerToContextConnection.messages.in:
+ * WebProcess/Storage/WebSWContextManagerConnection.cpp:
+ * WebProcess/Storage/WebSWContextManagerConnection.h:
+
+2022-04-06 Youenn Fablet <you...@apple.com>
+
Remove Notification::m_relatedNotificationIdentifier
https://bugs.webkit.org/show_bug.cgi?id=238603
Modified: trunk/Source/WebKit/NetworkProcess/ServiceWorker/WebSWServerToContextConnection.cpp (292455 => 292456)
--- trunk/Source/WebKit/NetworkProcess/ServiceWorker/WebSWServerToContextConnection.cpp 2022-04-06 09:16:42 UTC (rev 292455)
+++ trunk/Source/WebKit/NetworkProcess/ServiceWorker/WebSWServerToContextConnection.cpp 2022-04-06 10:05:05 UTC (rev 292456)
@@ -170,25 +170,36 @@
m_connection.networkProcess().parentProcessConnection()->send(Messages::NetworkProcessProxy::TerminateUnresponsiveServiceWorkerProcesses { webProcessIdentifier() }, 0);
}
-void WebSWServerToContextConnection::openWindow(WebCore::ServiceWorkerIdentifier identifier, const String& urlString, CompletionHandler<void(std::optional<WebCore::PageIdentifier>&&)>&& callback)
+void WebSWServerToContextConnection::openWindow(WebCore::ServiceWorkerIdentifier identifier, const URL& url, OpenWindowCallback&& callback)
{
auto* server = this->server();
if (!server) {
- callback(std::nullopt);
+ callback(makeUnexpected(ExceptionData { TypeError, "No SWServer"_s }));
return;
}
auto* worker = server->workerByID(identifier);
if (!worker) {
- callback(std::nullopt);
+ callback(makeUnexpected(ExceptionData { TypeError, "No remaining service worker"_s }));
return;
}
- auto innerCallback = [callback = WTFMove(callback)](std::optional<WebCore::PageIdentifier>&& pageIdentifier) mutable {
- callback(WTFMove(pageIdentifier));
+ auto innerCallback = [callback = WTFMove(callback), server = WeakPtr { *server }, origin = worker->origin()](std::optional<WebCore::PageIdentifier>&& pageIdentifier) mutable {
+ if (!pageIdentifier) {
+ // FIXME: validate whether we should reject or resolve with null, https://github.com/w3c/ServiceWorker/issues/1639
+ callback({ });
+ return;
+ }
+
+ if (!server) {
+ callback(makeUnexpected(ExceptionData { TypeError, "No SWServer"_s }));
+ return;
+ }
+
+ callback(server->topLevelServiceWorkerClientFromPageIdentifier(origin, *pageIdentifier));
};
- m_connection.networkProcess().parentProcessConnection()->sendWithAsyncReply(Messages::NetworkProcessProxy::OpenWindowFromServiceWorker { server->sessionID(), urlString, worker->origin().clientOrigin }, WTFMove(innerCallback));
+ m_connection.networkProcess().parentProcessConnection()->sendWithAsyncReply(Messages::NetworkProcessProxy::OpenWindowFromServiceWorker { m_connection.sessionID(), url.string(), worker->origin().clientOrigin }, WTFMove(innerCallback));
}
void WebSWServerToContextConnection::matchAllCompleted(uint64_t requestIdentifier, const Vector<ServiceWorkerClientData>& clientsData)
Modified: trunk/Source/WebKit/NetworkProcess/ServiceWorker/WebSWServerToContextConnection.h (292455 => 292456)
--- trunk/Source/WebKit/NetworkProcess/ServiceWorker/WebSWServerToContextConnection.h 2022-04-06 09:16:42 UTC (rev 292455)
+++ trunk/Source/WebKit/NetworkProcess/ServiceWorker/WebSWServerToContextConnection.h 2022-04-06 10:05:05 UTC (rev 292456)
@@ -103,7 +103,7 @@
void connectionIsNoLongerNeeded() final;
void terminateDueToUnresponsiveness() final;
- void openWindow(WebCore::ServiceWorkerIdentifier, const String& urlString, CompletionHandler<void(std::optional<WebCore::PageIdentifier>&&)>&&) final;
+ void openWindow(WebCore::ServiceWorkerIdentifier, const URL&, OpenWindowCallback&&) final;
void connectionClosed();
Modified: trunk/Source/WebKit/NetworkProcess/ServiceWorker/WebSWServerToContextConnection.messages.in (292455 => 292456)
--- trunk/Source/WebKit/NetworkProcess/ServiceWorker/WebSWServerToContextConnection.messages.in 2022-04-06 09:16:42 UTC (rev 292455)
+++ trunk/Source/WebKit/NetworkProcess/ServiceWorker/WebSWServerToContextConnection.messages.in 2022-04-06 10:05:05 UTC (rev 292456)
@@ -41,7 +41,7 @@
DidFailHeartBeatCheck(WebCore::ServiceWorkerIdentifier identifier)
SetAsInspected(WebCore::ServiceWorkerIdentifier identifier, bool isInspected)
- OpenWindow(WebCore::ServiceWorkerIdentifier identifier, String urlString) -> (std::optional<WebCore::PageIdentifier> newClientData)
+ OpenWindow(WebCore::ServiceWorkerIdentifier identifier, URL url) -> (Expected<std::optional<WebCore::ServiceWorkerClientData>, WebCore::ExceptionData> newClientData)
}
#endif // ENABLE(SERVICE_WORKER)
Modified: trunk/Source/WebKit/WebProcess/Storage/WebSWContextManagerConnection.cpp (292455 => 292456)
--- trunk/Source/WebKit/WebProcess/Storage/WebSWContextManagerConnection.cpp 2022-04-06 09:16:42 UTC (rev 292455)
+++ trunk/Source/WebKit/WebProcess/Storage/WebSWContextManagerConnection.cpp 2022-04-06 10:05:05 UTC (rev 292456)
@@ -337,9 +337,15 @@
callback(WTFMove(clientsData));
}
-void WebSWContextManagerConnection::openWindow(WebCore::ServiceWorkerIdentifier serviceWorkerIdentifier, const String& url, CompletionHandler<void(std::optional<WebCore::PageIdentifier>&&)>&& callback)
+void WebSWContextManagerConnection::openWindow(WebCore::ServiceWorkerIdentifier serviceWorkerIdentifier, const URL& url, OpenWindowCallback&& callback)
{
- m_connectionToNetworkProcess->sendWithAsyncReply(Messages::WebSWServerToContextConnection::OpenWindow { serviceWorkerIdentifier, url }, WTFMove(callback));
+ m_connectionToNetworkProcess->sendWithAsyncReply(Messages::WebSWServerToContextConnection::OpenWindow { serviceWorkerIdentifier, url }, [callback = WTFMove(callback)] (auto&& result) mutable {
+ if (!result.has_value()) {
+ callback(result.error().toException());
+ return;
+ }
+ callback(WTFMove(result.value()));
+ });
}
void WebSWContextManagerConnection::claim(ServiceWorkerIdentifier serviceWorkerIdentifier, CompletionHandler<void(ExceptionOr<void>&&)>&& callback)
Modified: trunk/Source/WebKit/WebProcess/Storage/WebSWContextManagerConnection.h (292455 => 292456)
--- trunk/Source/WebKit/WebProcess/Storage/WebSWContextManagerConnection.h 2022-04-06 09:16:42 UTC (rev 292455)
+++ trunk/Source/WebKit/WebProcess/Storage/WebSWContextManagerConnection.h 2022-04-06 10:05:05 UTC (rev 292456)
@@ -87,7 +87,7 @@
bool isThrottleable() const final;
void didFailHeartBeatCheck(WebCore::ServiceWorkerIdentifier) final;
void setAsInspected(WebCore::ServiceWorkerIdentifier, bool) final;
- void openWindow(WebCore::ServiceWorkerIdentifier, const String& url, CompletionHandler<void(std::optional<WebCore::PageIdentifier>&&)>&&) final;
+ void openWindow(WebCore::ServiceWorkerIdentifier, const URL&, OpenWindowCallback&&) final;
// IPC messages.
void serviceWorkerStarted(std::optional<WebCore::ServiceWorkerJobDataIdentifier>, WebCore::ServiceWorkerIdentifier, bool doesHandleFetch) final;
Modified: trunk/Tools/ChangeLog (292455 => 292456)
--- trunk/Tools/ChangeLog 2022-04-06 09:16:42 UTC (rev 292455)
+++ trunk/Tools/ChangeLog 2022-04-06 10:05:05 UTC (rev 292456)
@@ -1,3 +1,12 @@
+2022-04-06 Youenn Fablet <you...@apple.com>
+
+ ServiceWorkerClients.openWindow should not need to get all clients asynchronously to resolve its promise
+ https://bugs.webkit.org/show_bug.cgi?id=238503
+
+ Reviewed by Chris Dumez.
+
+ * TestWebKitAPI/Tests/WebKitCocoa/ServiceWorkerBasic.mm:
+
2022-04-06 Lauro Moura <lmo...@igalia.com>
[Flatpak SDK][AT-SPI] Use xdg-dbus-proxy to expose the a11y bus
Modified: trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/ServiceWorkerBasic.mm (292455 => 292456)
--- trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/ServiceWorkerBasic.mm 2022-04-06 09:16:42 UTC (rev 292455)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/ServiceWorkerBasic.mm 2022-04-06 10:05:05 UTC (rev 292456)
@@ -2966,3 +2966,84 @@
[webView evaluateJavaScript:@"focusClient()" completionHandler: nil];
TestWebKitAPI::Util::run(&done);
}
+
+static constexpr auto ServiceWorkerWindowClientOpenWindowMain =
+"<div id='log'>test page</div>"
+"<script>"
+"let worker;"
+"async function test() {"
+" log.innerHTML = 'test';"
+" try {"
+" const registration = await navigator.serviceWorker.register('/sw.js');"
+" log.innerHTML = 'registered';"
+" if (registration.active) {"
+" worker = registration.active;"
+" alert('already active');"
+" return;"
+" }"
+" worker = registration.installing;"
+" worker.addEventListener('statechange', () => {"
+" log.innerHTML = 'worker.state=' + worker.state;"
+" if (worker.state == 'activated')"
+" alert('successfully registered');"
+" });"
+" } catch(e) {"
+" alert('Exception: ' + e);"
+" }"
+"}"
+"window._onload_ = test;"
+""
+"function openWindowClient() {"
+" log.innerHTML = 'openWindowClient';"
+" worker.postMessage('start');"
+" navigator.serviceWorker._onmessage_ = (event) => {"
+" window.webkit.messageHandlers.sw.postMessage(event.data);"
+" }"
+"}"
+"</script>"_s;
+static constexpr auto ServiceWorkerWindowClientOpenWindowJS =
+"self.addEventListener('message', (event) => {"
+" self.clients.openWindow('/sw.js').then((client) => {"
+" event.source.postMessage(client ? 'opened with client' : 'opened without client');"
+" }, (error) => {"
+" event.source.postMessage('not opened');"
+" });"
+"});"_s;
+
+TEST(ServiceWorker, openWindowWithoutDelegate)
+{
+ [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 configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
+ auto preferences = [configuration preferences];
+
+ for (_WKInternalDebugFeature *feature in [WKPreferences _internalDebugFeatures]) {
+ if ([feature.key isEqualToString:@"ServiceWorkersUserGestureEnabled"])
+ [preferences _setEnabled:NO forInternalDebugFeature:feature];
+ }
+
+ auto messageHandler = adoptNS([[SWMessageHandlerWithExpectedMessage alloc] init]);
+ [[configuration userContentController] addScriptMessageHandler:messageHandler.get() name:@"sw"];
+
+ auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 300, 300) configuration:configuration.get() addToWindow:YES]);
+
+ TestWebKitAPI::HTTPServer server({
+ { "/"_s, { ServiceWorkerWindowClientOpenWindowMain } },
+ { "/sw.js"_s, { {{ "Content-Type"_s, "application/_javascript_"_s }}, ServiceWorkerWindowClientOpenWindowJS } }
+ });
+
+ [webView loadRequest:server.request()];
+ EXPECT_WK_STREQ([webView _test_waitForAlert], "successfully registered");
+
+ done = false;
+ expectedMessage = "opened without client"_s;
+ [webView evaluateJavaScript:@"openWindowClient()" completionHandler: nil];
+ TestWebKitAPI::Util::run(&done);
+}