Repository: WebKit/WebKit
Pull request #42797: [Cocoa] Ensure network load happens after setCookies requests are handled
Author: login: szewai
Labels: name: New Bugs
description: Unclassified bugs are placed in this component until the correct component can be determined.
Created: 2025-03-21T06:32:16Z | Merged: 2025-03-22T01:11:58Z

#### db0157e0a926e23c71e70d75e105255bb29e523d
<pre>
[Cocoa] Ensure network load happens after setCookies requests are handled
<a href="https://bugs.webkit.org/show_bug.cgi?id=290158">https://bugs.webkit.org/show_bug.cgi?id=290158</a>

Reviewed by Chris Dumez.

If loadRequest is invoked after setCookie, client may expect the cookies to be used for requests. This patch implements
that by introducing cookies version. When setCookie is invoked, cookies version will be incremented. When a load request
is created in UI process, it will record the current cookies version as &quot;required cookies version&quot;, meaning the related
network tasks should be started in network process after network process has handled setCookies requests with lower
cookies version.

API test: WKHTTPCookieStore.CookiesSetBeforeLoad

* Source/WebCore/loader/FrameLoader.h:
* Source/WebCore/platform/network/NetworkStorageSession.cpp:
(WebCore::NetworkStorageSession::setCookiesVersion):
(WebCore::NetworkStorageSession::addCookiesVersionChangeCallback):
* Source/WebCore/platform/network/NetworkStorageSession.h:
(WebCore::NetworkStorageSession::cookiesVersion const):
* Source/WebKit/NetworkProcess/Cookies/WebCookieManager.cpp:
(WebKit::WebCookieManager::setCookie):
* Source/WebKit/NetworkProcess/Cookies/WebCookieManager.h:
* Source/WebKit/NetworkProcess/Cookies/WebCookieManager.messages.in:
* Source/WebKit/NetworkProcess/NetworkLoadParameters.h:
(WebKit::NetworkLoadParameters::NetworkLoadParameters):
* Source/WebKit/NetworkProcess/NetworkProcess.cpp:
(WebKit::NetworkProcess::preconnectTo):
* Source/WebKit/NetworkProcess/NetworkProcess.h:
* Source/WebKit/NetworkProcess/NetworkProcess.messages.in:
* Source/WebKit/NetworkProcess/NetworkResourceLoadParameters.serialization.in:
* Source/WebKit/NetworkProcess/cocoa/NetworkDataTaskCocoa.h:
* Source/WebKit/NetworkProcess/cocoa/NetworkDataTaskCocoa.mm:
(WebKit::NetworkDataTaskCocoa::NetworkDataTaskCocoa):
(WebKit::NetworkDataTaskCocoa::resume):
* Source/WebKit/Shared/LoadParameters.h:
* Source/WebKit/Shared/LoadParameters.serialization.in:
* Source/WebKit/UIProcess/API/APIHTTPCookieStore.cpp:
(API::HTTPCookieStore::setCookies):
* Source/WebKit/UIProcess/API/Cocoa/WKHTTPCookieStore.mm:
(makeVectorElement):
(-[WKHTTPCookieStore _setCookies:completionHandler:]):
* Source/WebKit/UIProcess/API/Cocoa/WKHTTPCookieStorePrivate.h:
* Source/WebKit/UIProcess/Network/NetworkProcessProxy.cpp:
(WebKit::NetworkProcessProxy::preconnectTo):
(WebKit::NetworkProcessProxy::setCookies):
* Source/WebKit/UIProcess/Network/NetworkProcessProxy.h:
* Source/WebKit/UIProcess/WebPageProxy.cpp:
(WebKit::WebPageProxy::loadRequestWithNavigationShared):
* Source/WebKit/WebProcess/Network/WebLoaderStrategy.cpp:
(WebKit::WebLoaderStrategy::scheduleLoadFromNetworkProcess):
* Source/WebKit/WebProcess/WebPage/WebPage.cpp:
(WebKit::WebPage::loadRequest):
* Tools/TestWebKitAPI/Tests/WebKitCocoa/WKHTTPCookieStore.mm:
(TEST(WKHTTPCookieStore, CookiesSetBeforeLoad)):
* Tools/TestWebKitAPI/cocoa/HTTPServer.h:
* Tools/TestWebKitAPI/cocoa/HTTPServer.mm:
(TestWebKitAPI::HTTPServer::lastRequestCookies const):
(TestWebKitAPI::HTTPServer::parseCookies):
(TestWebKitAPI::HTTPServer::respondToRequests):

Canonical link: <a href="https://commits.webkit.org/292525@main">https://commits.webkit.org/292525@main</a>
</pre>
<!--EWS-Status-Bubble-Start-->
https://github.com/WebKit/WebKit/commit/dfc22f47b497920a1899c3f5244fa37a21fc6df6

| Misc | iOS, visionOS, tvOS & watchOS  | macOS  | Linux |  Windows |
| ----- | ---------------------- | ------- |  ----- |  --------- |
| [✅ 🧪 style](https://ews-build.webkit.org/#/builders/38/builds/96259 "Passed style check") | [✅ 🛠 ios](https://ews-build.webkit.org/#/builders/131/builds/15873 "Built successfully") | [✅ 🛠 mac](https://ews-build.webkit.org/#/builders/138/builds/5842 "Built successfully") | [✅ 🛠 wpe](https://ews-build.webkit.org/#/builders/5/builds/101326 "Built successfully") | [✅ 🛠 win](https://ews-build.webkit.org/#/builders/59/builds/46778 "Built successfully") 
| [✅ 🧪 bindings](https://ews-build.webkit.org/#/builders/9/builds/98304 "Passed tests") | [✅ 🛠 ios-sim](https://ews-build.webkit.org/#/builders/130/builds/16169 "Built successfully") | [✅ 🛠 mac-AS-debug](https://ews-build.webkit.org/#/builders/123/builds/24306 "Built successfully") | [✅ 🧪 wpe-wk2](https://ews-build.webkit.org/#/builders/34/builds/73376 "Passed tests") | [✅ 🧪 win-tests](https://ews-build.webkit.org/#/builders/60/builds/30605 "Passed tests") 
| [✅ 🧪 webkitperl](https://ews-build.webkit.org/#/builders/11/builds/99262 "Passed tests") | [✅ 🧪 ios-wk2](https://ews-build.webkit.org/#/builders/132/builds/12133 "Passed tests") | [✅ 🧪 api-mac](https://ews-build.webkit.org/#/builders/18/builds/86957 "Passed tests") | [✅ 🧪 api-wpe](https://ews-build.webkit.org/#/builders/41/builds/53713 "Passed tests") | 
| | [✅ 🧪 ios-wk2-wpt](https://ews-build.webkit.org/#/builders/133/builds/11884 "Passed tests") | [✅ 🧪 mac-wk1](https://ews-build.webkit.org/#/builders/135/builds/4719 "Passed tests") | [✅ 🛠 wpe-cairo](https://ews-build.webkit.org/#/builders/65/builds/46105 "Built successfully") | 
| | [✅ 🧪 api-ios](https://ews-build.webkit.org/#/builders/13/builds/82002 "Passed tests") | [✅ 🧪 mac-wk2](https://ews-build.webkit.org/#/builders/136/builds/4817 "Passed tests") | [✅ 🛠 gtk](https://ews-build.webkit.org/#/builders/2/builds/103354 "Built successfully") | 
| | [✅ 🛠 vision](https://ews-build.webkit.org/#/builders/128/builds/23326 "Built successfully") | [✅ 🧪 mac-AS-debug-wk2](https://ews-build.webkit.org/#/builders/122/builds/16984 "Passed tests") | [✅ 🧪 gtk-wk2](https://ews-build.webkit.org/#/builders/1/builds/82418 "Passed tests") | 
| | [✅ 🛠 vision-sim](https://ews-build.webkit.org/#/builders/121/builds/23577 "Built successfully") | [✅ 🧪 mac-wk2-stress](https://ews-build.webkit.org/#/builders/8/builds/82977 "Passed tests") | [✅ 🧪 api-gtk](https://ews-build.webkit.org/#/builders/21/builds/81793 "Passed tests") | 
| [✅ 🛠 🧪 merge](https://ews-build.webkit.org/#/builders/19/builds/20539 "Built successfully and passed tests") | [✅ 🧪 vision-wk2](https://ews-build.webkit.org/#/builders/126/builds/26426 "Passed tests") | [✅ 🧪 mac-intel-wk2](https://ews-build.webkit.org/#/builders/137/builds/3858 "Passed tests") | [✅ 🛠 playstation](https://ews-build.webkit.org/#/builders/134/builds/16700 "Built successfully") | 
| | [✅ 🛠 tv](https://ews-build.webkit.org/#/builders/127/builds/23289 "Built successfully") | [  ~~🛠 mac-safer-cpp~~](https://ews-build.webkit.org/#/builders/120/builds/28444 "The change is no longer eligible for processing. Pull Request was already closed when EWS attempted to process it.") | | 
| | [✅ 🛠 tv-sim](https://ews-build.webkit.org/#/builders/125/builds/22948 "Built successfully") | | | 
| | [✅ 🛠 watch](https://ews-build.webkit.org/#/builders/129/builds/26428 "Built successfully") | | | 
| | [✅ 🛠 watch-sim](https://ews-build.webkit.org/#/builders/124/builds/24689 "Built successfully") | | | 
<!--EWS-Status-Bubble-End-->


Diff:
diff --git a/Source/WebCore/loader/FrameLoader.h b/Source/WebCore/loader/FrameLoader.h
index 4d57651c3ca5..cc02b89ac204 100644
--- a/Source/WebCore/loader/FrameLoader.h
+++ b/Source/WebCore/loader/FrameLoader.h
@@ -358,6 +358,9 @@ class FrameLoader final : public CanMakeWeakPtr<FrameLoader> {
 
     void updateURLAndHistory(const URL&, RefPtr<SerializedScriptValue>&& stateObject, NavigationHistoryBehavior = NavigationHistoryBehavior::Replace);
 
+    void setRequiredCookiesVersion(uint64_t version) { m_requiredCookiesVersion = version; }
+    uint64_t requiredCookiesVersion() const { return m_requiredCookiesVersion; }
+
 private:
     enum FormSubmissionCacheLoadPolicy {
         MayAttemptCacheOnlyLoadForFormSubmissionItem,
@@ -543,6 +546,7 @@ class FrameLoader final : public CanMakeWeakPtr<FrameLoader> {
 
     bool m_errorOccurredInLoading { false };
     bool m_doNotAbortNavigationAPI { false };
+    uint64_t m_requiredCookiesVersion { 0 };
 };
 
 // This function is called by createWindow() in JSDOMWindowBase.cpp, for example, for
diff --git a/Source/WebCore/platform/network/NetworkStorageSession.cpp b/Source/WebCore/platform/network/NetworkStorageSession.cpp
index 7395dd5c4618..d7adbcb625a2 100644
--- a/Source/WebCore/platform/network/NetworkStorageSession.cpp
+++ b/Source/WebCore/platform/network/NetworkStorageSession.cpp
@@ -633,4 +633,19 @@ void NetworkStorageSession::cookieEnabledStateMayHaveChanged()
         observer->cookieEnabledStateMayHaveChanged();
 }
 
+void NetworkStorageSession::setCookiesVersion(uint64_t version)
+{
+    m_cookiesVersion = version;
+    for (auto&& callback : m_cookiesVersionChangeCallbacks.take(version))
+        callback();
+}
+
+void NetworkStorageSession::addCookiesVersionChangeCallback(uint64_t version, CompletionHandler<void()>&& completionHandler)
+{
+    auto iterator = m_cookiesVersionChangeCallbacks.ensure(version, [] {
+        return Vector<CompletionHandler<void()>> { };
+    }).iterator;
+    iterator->value.append(WTFMove(completionHandler));
+}
+
 }
diff --git a/Source/WebCore/platform/network/NetworkStorageSession.h b/Source/WebCore/platform/network/NetworkStorageSession.h
index 6a0197e3f456..75ad8d78d5ab 100644
--- a/Source/WebCore/platform/network/NetworkStorageSession.h
+++ b/Source/WebCore/platform/network/NetworkStorageSession.h
@@ -301,6 +301,10 @@ class NetworkStorageSession
     WEBCORE_EXPORT void resetManagedDomains();
 #endif
 
+    uint64_t cookiesVersion() const { return m_cookiesVersion; }
+    WEBCORE_EXPORT void setCookiesVersion(uint64_t);
+    WEBCORE_EXPORT void addCookiesVersionChangeCallback(uint64_t version, CompletionHandler<void()>&&);
+
 private:
 #if PLATFORM(COCOA)
     enum IncludeHTTPOnlyOrNot { DoNotIncludeHTTPOnly, IncludeHTTPOnly };
@@ -388,6 +392,9 @@ class NetworkStorageSession
 private:
     mutable std::unique_ptr<CookieStorageObserver> m_cookieStorageObserver;
 #endif
+    uint64_t m_cookiesVersion { 0 };
+    HashMap<uint64_t, Vector<CompletionHandler<void()>>> m_cookiesVersionChangeCallbacks;
+
     static bool m_processMayUseCookieAPI;
 };
 
diff --git a/Source/WebKit/NetworkProcess/Cookies/WebCookieManager.cpp b/Source/WebKit/NetworkProcess/Cookies/WebCookieManager.cpp
index fd787044cfd8..6faa168c4f3b 100644
--- a/Source/WebKit/NetworkProcess/Cookies/WebCookieManager.cpp
+++ b/Source/WebKit/NetworkProcess/Cookies/WebCookieManager.cpp
@@ -131,11 +131,12 @@ void WebCookieManager::getCookies(PAL::SessionID sessionID, const URL& url, Comp
     completionHandler(WTFMove(cookies));
 }
 
-void WebCookieManager::setCookie(PAL::SessionID sessionID, const Vector<Cookie>& cookies, CompletionHandler<void()>&& completionHandler)
+void WebCookieManager::setCookie(PAL::SessionID sessionID, const Vector<Cookie>& cookies, uint64_t cookiesVersion, CompletionHandler<void()>&& completionHandler)
 {
     if (auto* storageSession = protectedProcess()->storageSession(sessionID)) {
         for (auto& cookie : cookies)
             storageSession->setCookie(cookie);
+        storageSession->setCookiesVersion(cookiesVersion);
     }
     completionHandler();
 }
diff --git a/Source/WebKit/NetworkProcess/Cookies/WebCookieManager.h b/Source/WebKit/NetworkProcess/Cookies/WebCookieManager.h
index 3c980e3db2aa..d12e3caee99d 100644
--- a/Source/WebKit/NetworkProcess/Cookies/WebCookieManager.h
+++ b/Source/WebKit/NetworkProcess/Cookies/WebCookieManager.h
@@ -83,7 +83,7 @@ class WebCookieManager : public NetworkProcessSupplement, public IPC::MessageRec
     void deleteAllCookies(PAL::SessionID, CompletionHandler<void()>&&);
     void deleteAllCookiesModifiedSince(PAL::SessionID, WallTime, CompletionHandler<void()>&&);
 
-    void setCookie(PAL::SessionID, const Vector<WebCore::Cookie>&, CompletionHandler<void()>&&);
+    void setCookie(PAL::SessionID, const Vector<WebCore::Cookie>&, uint64_t cookiesVersion, CompletionHandler<void()>&&);
     void setCookies(PAL::SessionID, const Vector<WebCore::Cookie>&, const URL&, const URL& mainDocumentURL, CompletionHandler<void()>&&);
     void getAllCookies(PAL::SessionID, CompletionHandler<void(Vector<WebCore::Cookie>&&)>&&);
     void getCookies(PAL::SessionID, const URL&, CompletionHandler<void(Vector<WebCore::Cookie>&&)>&&);
diff --git a/Source/WebKit/NetworkProcess/Cookies/WebCookieManager.messages.in b/Source/WebKit/NetworkProcess/Cookies/WebCookieManager.messages.in
index c462e59fbb5e..2689d3fbfea8 100644
--- a/Source/WebKit/NetworkProcess/Cookies/WebCookieManager.messages.in
+++ b/Source/WebKit/NetworkProcess/Cookies/WebCookieManager.messages.in
@@ -33,7 +33,7 @@ messages -> WebCookieManager {
     void DeleteCookiesForHostnames(PAL::SessionID sessionID, Vector<String> hostnames) -> ()
     void DeleteAllCookies(PAL::SessionID sessionID) -> ()
 
-    void SetCookie(PAL::SessionID sessionID, Vector<WebCore::Cookie> cookie) -> ()
+    void SetCookie(PAL::SessionID sessionID, Vector<WebCore::Cookie> cookie, uint64_t cookiesVersion) -> ()
     void SetCookies(PAL::SessionID sessionID, Vector<WebCore::Cookie> cookies, URL url, URL mainDocumentURL) -> ()
     void GetAllCookies(PAL::SessionID sessionID) -> (Vector<WebCore::Cookie> cookies)
     void GetCookies(PAL::SessionID sessionID, URL url) -> (Vector<WebCore::Cookie> cookies)
diff --git a/Source/WebKit/NetworkProcess/NetworkLoadParameters.h b/Source/WebKit/NetworkProcess/NetworkLoadParameters.h
index e179b790b84e..762af0932a17 100644
--- a/Source/WebKit/NetworkProcess/NetworkLoadParameters.h
+++ b/Source/WebKit/NetworkProcess/NetworkLoadParameters.h
@@ -44,7 +44,7 @@ enum class PreconnectOnly : bool { No, Yes };
 class NetworkLoadParameters {
 public:
     NetworkLoadParameters() = default;
-    NetworkLoadParameters(Markable<WebPageProxyIdentifier> webPageProxyID, Markable<WebCore::PageIdentifier> webPageID, Markable<WebCore::FrameIdentifier> webFrameID, RefPtr<WebCore::SecurityOrigin>&& topOrigin, RefPtr<WebCore::SecurityOrigin>&& sourceOrigin, WTF::ProcessID parentPID, WebCore::ResourceRequest&& request, WebCore::ContentSniffingPolicy contentSniffingPolicy, WebCore::ContentEncodingSniffingPolicy contentEncodingSniffingPolicy, WebCore::StoredCredentialsPolicy storedCredentialsPolicy, WebCore::ClientCredentialPolicy clientCredentialPolicy, bool shouldClearReferrerOnHTTPSToHTTPRedirect, bool needsCertificateInfo, bool isMainFrameNavigation, std::optional<NavigationActionData>&& mainResourceNavigationDataForAnyFrame, PreconnectOnly shouldPreconnectOnly, std::optional<NavigatingToAppBoundDomain> isNavigatingToAppBoundDomain, bool hadMainFrameMainResourcePrivateRelayed, bool allowPrivacyProxy, OptionSet<WebCore::AdvancedPrivacyProtections> advancedPrivacyProtections)
+    NetworkLoadParameters(Markable<WebPageProxyIdentifier> webPageProxyID, Markable<WebCore::PageIdentifier> webPageID, Markable<WebCore::FrameIdentifier> webFrameID, RefPtr<WebCore::SecurityOrigin>&& topOrigin, RefPtr<WebCore::SecurityOrigin>&& sourceOrigin, WTF::ProcessID parentPID, WebCore::ResourceRequest&& request, WebCore::ContentSniffingPolicy contentSniffingPolicy, WebCore::ContentEncodingSniffingPolicy contentEncodingSniffingPolicy, WebCore::StoredCredentialsPolicy storedCredentialsPolicy, WebCore::ClientCredentialPolicy clientCredentialPolicy, bool shouldClearReferrerOnHTTPSToHTTPRedirect, bool needsCertificateInfo, bool isMainFrameNavigation, std::optional<NavigationActionData>&& mainResourceNavigationDataForAnyFrame, PreconnectOnly shouldPreconnectOnly, std::optional<NavigatingToAppBoundDomain> isNavigatingToAppBoundDomain, bool hadMainFrameMainResourcePrivateRelayed, bool allowPrivacyProxy, OptionSet<WebCore::AdvancedPrivacyProtections> advancedPrivacyProtections, uint64_t requiredCookiesVersion)
         : webPageProxyID(webPageProxyID)
         , webPageID(webPageID)
         , webFrameID(webFrameID)
@@ -65,6 +65,7 @@ class NetworkLoadParameters {
         , hadMainFrameMainResourcePrivateRelayed(hadMainFrameMainResourcePrivateRelayed)
         , allowPrivacyProxy(allowPrivacyProxy)
         , advancedPrivacyProtections(advancedPrivacyProtections)
+        , requiredCookiesVersion(requiredCookiesVersion)
     {
     }
     
@@ -95,6 +96,7 @@ class NetworkLoadParameters {
     OptionSet<WebCore::AdvancedPrivacyProtections> advancedPrivacyProtections;
 
     RefPtr<WebCore::SecurityOrigin> protectedSourceOrigin() const { return sourceOrigin; }
+    uint64_t requiredCookiesVersion { 0 };
 };
 
 } // namespace WebKit
diff --git a/Source/WebKit/NetworkProcess/NetworkProcess.cpp b/Source/WebKit/NetworkProcess/NetworkProcess.cpp
index 11b46b82eaac..42fc33c1eb09 100644
--- a/Source/WebKit/NetworkProcess/NetworkProcess.cpp
+++ b/Source/WebKit/NetworkProcess/NetworkProcess.cpp
@@ -1503,7 +1503,7 @@ void NetworkProcess::setOptInCookiePartitioningEnabled(PAL::SessionID sessionID,
 }
 #endif
 
-void NetworkProcess::preconnectTo(PAL::SessionID sessionID, WebPageProxyIdentifier webPageProxyID, WebCore::PageIdentifier webPageID, WebCore::ResourceRequest&& request, WebCore::StoredCredentialsPolicy storedCredentialsPolicy, std::optional<NavigatingToAppBoundDomain> isNavigatingToAppBoundDomain)
+void NetworkProcess::preconnectTo(PAL::SessionID sessionID, WebPageProxyIdentifier webPageProxyID, WebCore::PageIdentifier webPageID, WebCore::ResourceRequest&& request, WebCore::StoredCredentialsPolicy storedCredentialsPolicy, std::optional<NavigatingToAppBoundDomain> isNavigatingToAppBoundDomain, uint64_t requiredCookiesVersion)
 {
     auto url = request.url();
     auto userAgent = request.httpUserAgent();
@@ -1527,6 +1527,7 @@ void NetworkProcess::preconnectTo(PAL::SessionID sessionID, WebPageProxyIdentifi
     parameters.isNavigatingToAppBoundDomain = isNavigatingToAppBoundDomain;
     parameters.storedCredentialsPolicy = storedCredentialsPolicy;
     parameters.shouldPreconnectOnly = PreconnectOnly::Yes;
+    parameters.requiredCookiesVersion = requiredCookiesVersion;
 
     NetworkLoadParameters parametersForAdditionalPreconnect = parameters;
 
diff --git a/Source/WebKit/NetworkProcess/NetworkProcess.h b/Source/WebKit/NetworkProcess/NetworkProcess.h
index 5be69103ecc2..f92ed4b7687b 100644
--- a/Source/WebKit/NetworkProcess/NetworkProcess.h
+++ b/Source/WebKit/NetworkProcess/NetworkProcess.h
@@ -320,7 +320,7 @@ class NetworkProcess final : public AuxiliaryProcess, private DownloadManager::C
     void setOptInCookiePartitioningEnabled(PAL::SessionID, bool) const;
 #endif
 
-    void preconnectTo(PAL::SessionID, WebPageProxyIdentifier, WebCore::PageIdentifier, WebCore::ResourceRequest&&, WebCore::StoredCredentialsPolicy, std::optional<NavigatingToAppBoundDomain>);
+    void preconnectTo(PAL::SessionID, WebPageProxyIdentifier, WebCore::PageIdentifier, WebCore::ResourceRequest&&, WebCore::StoredCredentialsPolicy, std::optional<NavigatingToAppBoundDomain>, uint64_t requiredCookiesVersion);
 
     void setSessionIsControlledByAutomation(PAL::SessionID, bool);
     bool sessionIsControlledByAutomation(PAL::SessionID) const;
diff --git a/Source/WebKit/NetworkProcess/NetworkProcess.messages.in b/Source/WebKit/NetworkProcess/NetworkProcess.messages.in
index 24124fdb6ad7..142db1199485 100644
--- a/Source/WebKit/NetworkProcess/NetworkProcess.messages.in
+++ b/Source/WebKit/NetworkProcess/NetworkProcess.messages.in
@@ -86,7 +86,7 @@ messages -> NetworkProcess : AuxiliaryProcess WantsAsyncDispatchMessage {
 
     NotifyMediaStreamingActivity(bool activity)
 
-    PreconnectTo(PAL::SessionID sessionID, WebKit::WebPageProxyIdentifier webPageProxyID, WebCore::PageIdentifier webPageID, WebCore::ResourceRequest request, enum:uint8_t WebCore::StoredCredentialsPolicy storedCredentialsPolicy, std::optional<WebKit::NavigatingToAppBoundDomain> isNavigatingToAppBoundDomain);
+    PreconnectTo(PAL::SessionID sessionID, WebKit::WebPageProxyIdentifier webPageProxyID, WebCore::PageIdentifier webPageID, WebCore::ResourceRequest request, enum:uint8_t WebCore::StoredCredentialsPolicy storedCredentialsPolicy, std::optional<WebKit::NavigatingToAppBoundDomain> isNavigatingToAppBoundDomain, uint64_t requiredCookiesVersion);
 
     SetInspectionForServiceWorkersAllowed(PAL::SessionID sessionID, bool inspectable)
 
diff --git a/Source/WebKit/NetworkProcess/NetworkResourceLoadParameters.serialization.in b/Source/WebKit/NetworkProcess/NetworkResourceLoadParameters.serialization.in
index 76d0ca251908..61be6a1597fb 100644
--- a/Source/WebKit/NetworkProcess/NetworkResourceLoadParameters.serialization.in
+++ b/Source/WebKit/NetworkProcess/NetworkResourceLoadParameters.serialization.in
@@ -53,6 +53,7 @@ class WebKit::NetworkLoadParameters {
     bool hadMainFrameMainResourcePrivateRelayed;
     bool allowPrivacyProxy;
     OptionSet<WebCore::AdvancedPrivacyProtections> advancedPrivacyProtections;
+    uint64_t requiredCookiesVersion;
 }
 
 class WebKit::NetworkResourceLoadParameters : WebKit::NetworkLoadParameters {
diff --git a/Source/WebKit/NetworkProcess/cocoa/NetworkDataTaskCocoa.h b/Source/WebKit/NetworkProcess/cocoa/NetworkDataTaskCocoa.h
index 0ab295a406e4..7d74909298c8 100644
--- a/Source/WebKit/NetworkProcess/cocoa/NetworkDataTaskCocoa.h
+++ b/Source/WebKit/NetworkProcess/cocoa/NetworkDataTaskCocoa.h
@@ -117,6 +117,7 @@ class NetworkDataTaskCocoa final : public NetworkDataTask, public NetworkTaskCoc
 
     bool m_isForMainResourceNavigationForAnyFrame { false };
     RefPtr<WebCore::SecurityOrigin> m_sourceOrigin;
+    uint64_t m_requiredCookiesVersion { 0 };
 };
 
 WebCore::Credential serverTrustCredential(const WebCore::AuthenticationChallenge&);
diff --git a/Source/WebKit/NetworkProcess/cocoa/NetworkDataTaskCocoa.mm b/Source/WebKit/NetworkProcess/cocoa/NetworkDataTaskCocoa.mm
index dbb40883a41a..d72cc9356842 100644
--- a/Source/WebKit/NetworkProcess/cocoa/NetworkDataTaskCocoa.mm
+++ b/Source/WebKit/NetworkProcess/cocoa/NetworkDataTaskCocoa.mm
@@ -191,6 +191,7 @@ static float toNSURLSessionTaskPriority(WebCore::ResourceLoadPriority priority)
     , m_webPageProxyID(parameters.webPageProxyID)
     , m_isForMainResourceNavigationForAnyFrame(!!parameters.mainResourceNavigationDataForAnyFrame)
     , m_sourceOrigin(parameters.sourceOrigin)
+    , m_requiredCookiesVersion(parameters.requiredCookiesVersion)
 {
     auto request = parameters.request;
     auto url = request.url();
@@ -593,6 +594,20 @@ static float toNSURLSessionTaskPriority(WebCore::ResourceLoadPriority priority)
     if (m_failureScheduled)
         return;
 
+    if (CheckedPtr session = m_session.get()) {
+        CheckedPtr storageSession = session->networkStorageSession();
+        if (storageSession && storageSession->cookiesVersion() < m_requiredCookiesVersion) {
+            RELEASE_LOG(Loading, "%p - NetworkDataTaskCocoa::resume: task is delayed because cookies version (%" PRIu64 ") is lower than required (%" PRIu64 ")", this, storageSession->cookiesVersion(), m_requiredCookiesVersion);
+            storageSession->addCookiesVersionChangeCallback(m_requiredCookiesVersion, [weakThis = ThreadSafeWeakPtr { *this }] {
+                if (auto protectedThis = weakThis.get()) {
+                    RELEASE_LOG(Loading, "%p - NetworkDataTaskCocoa::resume: task delayed by cookies version is started", protectedThis.get());
+                    protectedThis->resume();
+                }
+            });
+            return;
+        }
+    }
+
     auto& cocoaSession = static_cast<NetworkSessionCocoa&>(*m_session);
     if (cocoaSession.deviceManagementRestrictionsEnabled() && m_isForMainResourceNavigationForAnyFrame) {
         auto didDetermineDeviceRestrictionPolicyForURL = makeBlockPtr([protectedThis = Ref { *this }](BOOL isBlocked) mutable {
diff --git a/Source/WebKit/Shared/LoadParameters.h b/Source/WebKit/Shared/LoadParameters.h
index 5d570ced429d..3a1a0b04788f 100644
--- a/Source/WebKit/Shared/LoadParameters.h
+++ b/Source/WebKit/Shared/LoadParameters.h
@@ -90,6 +90,7 @@ struct LoadParameters {
     bool isHandledByAboutSchemeHandler { false };
 
     std::optional<OptionSet<WebCore::AdvancedPrivacyProtections>> advancedPrivacyProtections;
+    uint64_t requiredCookiesVersion { 0 };
 };
 
 } // namespace WebKit
diff --git a/Source/WebKit/Shared/LoadParameters.serialization.in b/Source/WebKit/Shared/LoadParameters.serialization.in
index 1a796251628e..eb57c68fedb6 100644
--- a/Source/WebKit/Shared/LoadParameters.serialization.in
+++ b/Source/WebKit/Shared/LoadParameters.serialization.in
@@ -58,4 +58,5 @@ enum class WebCore::LockBackForwardList : bool;
     bool isHandledByAboutSchemeHandler;
 
     std::optional<OptionSet<WebCore::AdvancedPrivacyProtections>> advancedPrivacyProtections;
+    uint64_t requiredCookiesVersion;
 };
diff --git a/Source/WebKit/UIProcess/API/APIHTTPCookieStore.cpp b/Source/WebKit/UIProcess/API/APIHTTPCookieStore.cpp
index 42ab9489eaae..a46c2448337d 100644
--- a/Source/WebKit/UIProcess/API/APIHTTPCookieStore.cpp
+++ b/Source/WebKit/UIProcess/API/APIHTTPCookieStore.cpp
@@ -102,7 +102,7 @@ void HTTPCookieStore::setCookies(Vector<WebCore::Cookie>&& cookies, CompletionHa
 {
     filterAppBoundCookies(WTFMove(cookies), [this, protectedThis = Ref { *this }, completionHandler = WTFMove(completionHandler)] (auto&& appBoundCookies) mutable {
         if (RefPtr networkProcess = networkProcessLaunchingIfNecessary())
-            networkProcess->sendWithAsyncReply(Messages::WebCookieManager::SetCookie(m_sessionID, appBoundCookies), WTFMove(completionHandler));
+            networkProcess->setCookies(m_sessionID, WTFMove(appBoundCookies), WTFMove(completionHandler));
         else
             completionHandler();
     });
diff --git a/Source/WebKit/UIProcess/API/Cocoa/WKHTTPCookieStore.mm b/Source/WebKit/UIProcess/API/Cocoa/WKHTTPCookieStore.mm
index 555a4e2895ed..1a47a2f6583a 100644
--- a/Source/WebKit/UIProcess/API/Cocoa/WKHTTPCookieStore.mm
+++ b/Source/WebKit/UIProcess/API/Cocoa/WKHTTPCookieStore.mm
@@ -205,4 +205,23 @@ - (void)_flushCookiesToDiskWithCompletionHandler:(void(^)(void))completionHandle
     });
 }
 
+#if !TARGET_OS_IPHONE
+
+static std::optional<WebCore::Cookie> makeVectorElement(const WebCore::Cookie*, id arrayElement)
+{
+    if (NSHTTPCookie *nsCookie = dynamic_objc_cast<NSHTTPCookie>(arrayElement))
+        return WebCore::Cookie { nsCookie };
+
+    return std::nullopt;
+}
+
+- (void)_setCookies:(NSArray<NSHTTPCookie *> *)cookies completionHandler:(void (^)(void))completionHandler
+{
+    _cookieStore->setCookies(makeVector<WebCore::Cookie>(cookies), [completionHandler = makeBlockPtr(completionHandler)]() {
+        completionHandler();
+    });
+}
+
+#endif
+
 @end
diff --git a/Source/WebKit/UIProcess/API/Cocoa/WKHTTPCookieStorePrivate.h b/Source/WebKit/UIProcess/API/Cocoa/WKHTTPCookieStorePrivate.h
index 43b53f0041cf..1211e001f44c 100644
--- a/Source/WebKit/UIProcess/API/Cocoa/WKHTTPCookieStorePrivate.h
+++ b/Source/WebKit/UIProcess/API/Cocoa/WKHTTPCookieStorePrivate.h
@@ -29,4 +29,9 @@
 - (void)_getCookiesForURL:(NSURL *)url completionHandler:(void (^)(NSArray<NSHTTPCookie *> *))completionHandler WK_API_AVAILABLE(macos(11.0), ios(14.0));
 - (void)_setCookieAcceptPolicy:(NSHTTPCookieAcceptPolicy)policy completionHandler:(void (^)(void))completionHandler WK_API_AVAILABLE(macos(12.0), ios(15.0));
 - (void)_flushCookiesToDiskWithCompletionHandler:(void(^)(void))completionHandler WK_API_AVAILABLE(macos(12.0), ios(15.0));
+
+#if !TARGET_OS_IPHONE
+// FIXME: Promote this to API (rdar://147591774).
+- (void)_setCookies:(NSArray<NSHTTPCookie *> *)cookies completionHandler:(void(^)(void))completionHandler WK_API_AVAILABLE(macos(WK_MAC_TBA));
+#endif
 @end
diff --git a/Source/WebKit/UIProcess/Network/NetworkProcessProxy.cpp b/Source/WebKit/UIProcess/Network/NetworkProcessProxy.cpp
index 60128fbc8d24..6fca418cbd26 100644
--- a/Source/WebKit/UIProcess/Network/NetworkProcessProxy.cpp
+++ b/Source/WebKit/UIProcess/Network/NetworkProcessProxy.cpp
@@ -60,6 +60,7 @@
 #include "StorageAccessStatus.h"
 #include "ViewSnapshotStore.h"
 #include "WebCompiledContentRuleList.h"
+#include "WebCookieManagerMessages.h"
 #include "WebFrameProxy.h"
 #include "WebNotificationManagerProxy.h"
 #include "WebPageMessages.h"
@@ -1670,7 +1671,7 @@ void NetworkProcessProxy::preconnectTo(PAL::SessionID sessionID, WebPageProxyIde
 {
     if (!request.url().isValid() || !request.url().protocolIsInHTTPFamily())
         return;
-    send(Messages::NetworkProcess::PreconnectTo(sessionID, webPageProxyID, webPageID, WTFMove(request), storedCredentialsPolicy, isNavigatingToAppBoundDomain), 0);
+    send(Messages::NetworkProcess::PreconnectTo(sessionID, webPageProxyID, webPageID, WTFMove(request), storedCredentialsPolicy, isNavigatingToAppBoundDomain, m_cookiesVersion), 0);
 }
 
 static bool anyProcessPoolHasForegroundWebProcesses()
@@ -1978,6 +1979,11 @@ void NetworkProcessProxy::addAllowedFirstPartyForCookies(WebProcessProxy& webPro
         completionHandler();
 }
 
+void NetworkProcessProxy::setCookies(PAL::SessionID sessionID, Vector<WebCore::Cookie>&& cookies, CompletionHandler<void()>&& completionHandler)
+{
+    sendWithAsyncReply(Messages::WebCookieManager::SetCookie(sessionID, WTFMove(cookies), ++m_cookiesVersion), WTFMove(completionHandler));
+}
+
 #if USE(RUNNINGBOARD)
 void NetworkProcessProxy::wakeUpWebProcessForIPC(WebCore::ProcessIdentifier processIdentifier)
 {
diff --git a/Source/WebKit/UIProcess/Network/NetworkProcessProxy.h b/Source/WebKit/UIProcess/Network/NetworkProcessProxy.h
index 4857537c69a6..6c7f35c5045b 100644
--- a/Source/WebKit/UIProcess/Network/NetworkProcessProxy.h
+++ b/Source/WebKit/UIProcess/Network/NetworkProcessProxy.h
@@ -141,6 +141,7 @@ class NetworkProcessProxy final : public AuxiliaryProcessProxy {
     void dataTaskWithRequest(WebPageProxy&, PAL::SessionID, WebCore::ResourceRequest&&, const std::optional<WebCore::SecurityOriginData>& topOrigin, bool shouldRunAtForegroundPriority, CompletionHandler<void(API::DataTask&)>&&);
 
     void addAllowedFirstPartyForCookies(WebProcessProxy&, const WebCore::RegistrableDomain& firstPartyForCookies, LoadedWebArchive, CompletionHandler<void()>&&);
+    void setCookies(PAL::SessionID, Vector<WebCore::Cookie>&&, CompletionHandler<void()>&&);
 
     void fetchWebsiteData(PAL::SessionID, OptionSet<WebsiteDataType>, OptionSet<WebsiteDataFetchOption>, CompletionHandler<void(WebsiteData)>&&);
     void deleteWebsiteData(PAL::SessionID, OptionSet<WebsiteDataType>, WallTime modifiedSince, const HashSet<WebCore::ProcessIdentifier>&, CompletionHandler<void()>&&);
@@ -348,6 +349,8 @@ class NetworkProcessProxy final : public AuxiliaryProcessProxy {
     void resetResourceMonitorThrottlerForTesting(PAL::SessionID, CompletionHandler<void()>&&);
 #endif
 
+    uint64_t cookiesVersion() const { return m_cookiesVersion; }
+
 private:
     explicit NetworkProcessProxy();
 
@@ -487,6 +490,8 @@ class NetworkProcessProxy final : public AuxiliaryProcessProxy {
     RetainPtr<id> m_backgroundObserver;
     RetainPtr<id> m_foregroundObserver;
 #endif
+
+    uint64_t m_cookiesVersion { 0 };
 };
 
 } // namespace WebKit
diff --git a/Source/WebKit/UIProcess/WebPageProxy.cpp b/Source/WebKit/UIProcess/WebPageProxy.cpp
index e732d41f9172..2c395196179d 100644
--- a/Source/WebKit/UIProcess/WebPageProxy.cpp
+++ b/Source/WebKit/UIProcess/WebPageProxy.cpp
@@ -2102,6 +2102,8 @@ void WebPageProxy::loadRequestWithNavigationShared(Ref<WebProcessProxy>&& proces
     loadParameters.isRequestFromClientOrUserInput = navigation.isRequestFromClientOrUserInput();
     loadParameters.isPerformingHTTPFallback = isPerformingHTTPFallback == IsPerformingHTTPFallback::Yes;
     loadParameters.isHandledByAboutSchemeHandler = protectedAboutSchemeHandler()->canHandleURL(url);
+    if (RefPtr networkProcess = protectedWebsiteDataStore()->networkProcessIfExists())
+        loadParameters.requiredCookiesVersion = networkProcess->cookiesVersion();
 
 #if ENABLE(CONTENT_EXTENSIONS)
     if (protectedPreferences()->iFrameResourceMonitoringEnabled())
diff --git a/Source/WebKit/WebProcess/Network/WebLoaderStrategy.cpp b/Source/WebKit/WebProcess/Network/WebLoaderStrategy.cpp
index 50fb18c5d139..219a04317cbf 100644
--- a/Source/WebKit/WebProcess/Network/WebLoaderStrategy.cpp
+++ b/Source/WebKit/WebProcess/Network/WebLoaderStrategy.cpp
@@ -549,6 +549,9 @@ void WebLoaderStrategy::scheduleLoadFromNetworkProcess(ResourceLoader& resourceL
         loadParameters.frameAncestorOrigins = WTFMove(frameAncestorOrigins);
     }
 
+    if (RefPtr frameLoader = resourceLoader.frameLoader())
+        loadParameters.requiredCookiesVersion = frameLoader->requiredCookiesVersion();
+
     ASSERT((loadParameters.webPageID && loadParameters.webFrameID) || loadParameters.clientCredentialPolicy == ClientCredentialPolicy::CannotAskClientForCredentials);
 
     std::optional<NetworkResourceLoadIdentifier> existingNetworkResourceLoadIdentifierToResume;
diff --git a/Source/WebKit/WebProcess/WebPage/WebPage.cpp b/Source/WebKit/WebProcess/WebPage/WebPage.cpp
index d9d2ad879036..1ea1063ab02b 100644
--- a/Source/WebKit/WebProcess/WebPage/WebPage.cpp
+++ b/Source/WebKit/WebProcess/WebPage/WebPage.cpp
@@ -2157,7 +2157,7 @@ void WebPage::loadRequest(LoadParameters&& loadParameters)
         localFrame->setOwnerPermissionsPolicy(WTFMove(*onwerPermissionsPolicy));
 
     localFrame->loader().setHTTPFallbackInProgress(loadParameters.isPerformingHTTPFallback);
-
+    localFrame->loader().setRequiredCookiesVersion(loadParameters.requiredCookiesVersion);
     localFrame->loader().load(WTFMove(frameLoadRequest));
 
     ASSERT(!m_pendingNavigationID);
diff --git a/Tools/TestWebKitAPI/Tests/WebKitCocoa/WKHTTPCookieStore.mm b/Tools/TestWebKitAPI/Tests/WebKitCocoa/WKHTTPCookieStore.mm
index fe119b5b1a76..18c747781bd6 100644
--- a/Tools/TestWebKitAPI/Tests/WebKitCocoa/WKHTTPCookieStore.mm
+++ b/Tools/TestWebKitAPI/Tests/WebKitCocoa/WKHTTPCookieStore.mm
@@ -1069,3 +1069,36 @@ HTTPServer server(TestWebKitAPI::HTTPServer::UseCoroutines::Yes, [&] (Connection
     [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:[NSString stringWithFormat:@"http://127.0.0.1:%d/ninja", serverPort]]]];
     Util::run(&receivedWebSocket);
 }
+
+TEST(WKHTTPCookieStore, CookiesSetBeforeLoad)
+{
+    TestWebKitAPI::HTTPServer server({
+        { "/"_s, { { { "Content-Type"_s, "text/html"_s } }, ""_s } }
+    }, TestWebKitAPI::HTTPServer::Protocol::Http);
+
+    RetainPtr<NSHTTPCookie> sessionCookie = [NSHTTPCookie cookieWithProperties:@{
+        NSHTTPCookiePath: @"/",
+        NSHTTPCookieName: @"SessionCookieName",
+        NSHTTPCookieValue: @"CookieValue",
+        NSHTTPCookieDomain: @"127.0.0.1",
+    }];
+
+    RetainPtr<NSHTTPCookie> persistentCookie = [NSHTTPCookie cookieWithProperties:@{
+        NSHTTPCookiePath: @"/",
+        NSHTTPCookieName: @"PersistentCookieName",
+        NSHTTPCookieValue: @"CookieValue",
+        NSHTTPCookieDomain: @"127.0.0.1",
+        NSHTTPCookieExpires: [NSDate distantFuture],
+    }];
+
+    RetainPtr configuration = adoptNS([WKWebViewConfiguration new]);
+    configuration.get().websiteDataStore = [WKWebsiteDataStore nonPersistentDataStore];
+    RetainPtr webView = adoptNS([[WKWebView alloc] initWithFrame:CGRectZero configuration:configuration.get()]);
+
+    [configuration.get().websiteDataStore.httpCookieStore setCookie:sessionCookie.get() completionHandler:^{ }];
+    [configuration.get().websiteDataStore.httpCookieStore setCookie:persistentCookie.get() completionHandler:^{ }];
+    [webView loadRequest:server.request()];
+    [webView _test_waitForDidFinishNavigation];
+
+    EXPECT_WK_STREQ(server.lastRequestCookies(), "PersistentCookieName=CookieValue; SessionCookieName=CookieValue");
+}
diff --git a/Tools/TestWebKitAPI/cocoa/HTTPServer.h b/Tools/TestWebKitAPI/cocoa/HTTPServer.h
index af32c09733c6..a31d50873958 100644
--- a/Tools/TestWebKitAPI/cocoa/HTTPServer.h
+++ b/Tools/TestWebKitAPI/cocoa/HTTPServer.h
@@ -59,6 +59,7 @@ class HTTPServer {
     WKWebViewConfiguration *httpsProxyConfiguration() const;
     size_t totalConnections() const;
     size_t totalRequests() const;
+    String lastRequestCookies() const;
     void cancel();
     void terminateAllConnections(CompletionHandler<void()>&&);
 
@@ -67,6 +68,7 @@ class HTTPServer {
 
     static void respondWithOK(Connection);
     static void respondWithChallengeThenOK(Connection);
+    static String parseCookies(const Vector<char>& request);
     static String parsePath(const Vector<char>& request);
     static String parseBody(const Vector<char>&);
     static Vector<uint8_t> testPrivateKey();
diff --git a/Tools/TestWebKitAPI/cocoa/HTTPServer.mm b/Tools/TestWebKitAPI/cocoa/HTTPServer.mm
index 8b50fa6907ce..7f71f90194d0 100644
--- a/Tools/TestWebKitAPI/cocoa/HTTPServer.mm
+++ b/Tools/TestWebKitAPI/cocoa/HTTPServer.mm
@@ -56,6 +56,7 @@
     HashMap<String, HTTPResponse> requestMap;
     Vector<Connection> connections;
     Vector<CoroutineHandle<ConnectionTask::promise_type>> coroutineHandles;
+    String lastRequestCookies;
 };
 
 static RetainPtr<nw_protocol_definition_t> proxyDefinition(HTTPServer::Protocol protocol)
@@ -307,6 +308,11 @@ static void startListening(nw_listener_t listener)
     return m_requestData->requestCount;
 }
 
+String HTTPServer::lastRequestCookies() const
+{
+    return m_requestData->lastRequestCookies;
+}
+
 static ASCIILiteral statusText(unsigned statusCode)
 {
     switch (statusCode) {
@@ -375,6 +381,25 @@ static ASCIILiteral statusText(unsigned statusCode)
     return request.subspan(pathPrefixLength, pathLength);
 }
 
+String HTTPServer::parseCookies(const Vector<char>& characters)
+{
+    if (!characters.size())
+        return { };
+
+    String request { characters.span() };
+    ASCIILiteral cookiePrefix = "Cookie: "_s;
+    size_t cookieStringStart = request.find(cookiePrefix);
+    if (cookieStringStart == notFound)
+        return { };
+    cookieStringStart += cookiePrefix.length();
+
+    size_t cookieStringEnd = request.find("\r\n"_s, cookieStringStart);
+    if (cookieStringEnd == notFound)
+        return { };
+
+    return request.substring(cookieStringStart, cookieStringEnd - cookieStringStart);
+}
+
 String HTTPServer::parseBody(const Vector<char>& request)
 {
     const char* headerEndBytes = "\r\n\r\n";
@@ -406,7 +431,9 @@ static bool isConditionalRequest(std::span<const char> request)
     connection.receiveHTTPRequest([connection, requestData] (Vector<char>&& request) mutable {
         if (!request.size())
             return;
+
         requestData->requestCount++;
+        requestData->lastRequestCookies = parseCookies(request);
 
         auto path = parsePath(request);
         ASSERT_WITH_MESSAGE(requestData->requestMap.contains(path), "This HTTPServer does not know how to respond to a request for %s", path.utf8().data());


Reviews:
user: login: cdumez
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-21T16:45:08Z
user: login: cdumez
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-21T16:53:23Z
user: login: szewai
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-21T17:25:50Z
user: login: cdumez
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-21T17:32:18Z
user: login: szewai
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-21T17:42:07Z
user: login: cdumez
body: LGTM
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-03-21T18:30:55Z

Review comments:
diff_hunk: @@ -593,6 +594,19 @@ static float toNSURLSessionTaskPriority(WebCore::ResourceLoadPriority priority)
     if (m_failureScheduled)
         return;
 
+    CheckedPtr session = m_session.get();
+    if (session) {
path: Source/WebKit/NetworkProcess/cocoa/NetworkDataTaskCocoa.mm
user: login: cdumez
body: `if (CheckedPtr session = m_session.get())`
created_at: 2025-03-21T16:38:52Z
author_association: CONTRIBUTOR
diff_hunk: @@ -593,6 +594,19 @@ static float toNSURLSessionTaskPriority(WebCore::ResourceLoadPriority priority)
     if (m_failureScheduled)
         return;
 
+    CheckedPtr session = m_session.get();
+    if (session) {
+        CheckedPtr storageSession = session->networkStorageSession();
+        if (storageSession && storageSession->cookiesVersion() < m_requiredCookiesVersion) {
+            RELEASE_LOG(Loading, "NetworkDataTaskCocoa::resume is delayed because cookies version is too low");
+            storageSession->setCookiesVersionChangeCallback(m_requiredCookiesVersion, [weakThis = ThreadSafeWeakPtr { *this }] {
path: Source/WebKit/NetworkProcess/cocoa/NetworkDataTaskCocoa.mm
user: login: cdumez
body: This should be called `addCookiesVersionChangeCallback` since it doesn't overwrite.
created_at: 2025-03-21T16:39:26Z
author_association: CONTRIBUTOR
diff_hunk: @@ -593,6 +594,19 @@ static float toNSURLSessionTaskPriority(WebCore::ResourceLoadPriority priority)
     if (m_failureScheduled)
         return;
 
+    CheckedPtr session = m_session.get();
+    if (session) {
+        CheckedPtr storageSession = session->networkStorageSession();
+        if (storageSession && storageSession->cookiesVersion() < m_requiredCookiesVersion) {
+            RELEASE_LOG(Loading, "NetworkDataTaskCocoa::resume is delayed because cookies version is too low");
+            storageSession->setCookiesVersionChangeCallback(m_requiredCookiesVersion, [weakThis = ThreadSafeWeakPtr { *this }] {
path: Source/WebKit/NetworkProcess/cocoa/NetworkDataTaskCocoa.mm
user: login: cdumez
body: Please add RELEASE_LOGGING so we can have a chance to debug things in sysdiagnoses if this misbehaves. In case of bug, this could easily cause unexplained load hangs.
created_at: 2025-03-21T16:40:26Z
author_association: CONTRIBUTOR
diff_hunk: @@ -205,4 +205,19 @@ - (void)_flushCookiesToDiskWithCompletionHandler:(void(^)(void))completionHandle
     });
 }
 
+- (void)_setCookies:(NSArray<NSHTTPCookie *> *)cookies completionHandler:(void (^)(void))completionHandler
+{
+    Vector<WebCore::Cookie> cookiesVector;
+    cookiesVector.reserveInitialCapacity(cookies.count);
+    for (NSHTTPCookie * cookie in cookies)
+        cookiesVector.append({ cookie });
path: Source/WebKit/UIProcess/API/Cocoa/WKHTTPCookieStore.mm
user: login: cdumez
body: We should likely use `makeVector()` from VectorCocoa.h
created_at: 2025-03-21T16:43:00Z
author_association: CONTRIBUTOR
diff_hunk: @@ -205,4 +205,19 @@ - (void)_flushCookiesToDiskWithCompletionHandler:(void(^)(void))completionHandle
     });
 }
 
+- (void)_setCookies:(NSArray<NSHTTPCookie *> *)cookies completionHandler:(void (^)(void))completionHandler
+{
+    Vector<WebCore::Cookie> cookiesVector;
+    cookiesVector.reserveInitialCapacity(cookies.count);
+    for (NSHTTPCookie * cookie in cookies)
+        cookiesVector.append({ cookie });
+
+    _cookieStore->setCookies(WTFMove(cookiesVector), [handler = adoptNS([completionHandler copy])]() {
path: Source/WebKit/UIProcess/API/Cocoa/WKHTTPCookieStore.mm
user: login: cdumez
body: Can we use WTF::BlockPtr instead of `[x copy]`?
created_at: 2025-03-21T16:43:43Z
author_association: CONTRIBUTOR
diff_hunk: @@ -29,4 +29,5 @@
 - (void)_getCookiesForURL:(NSURL *)url completionHandler:(void (^)(NSArray<NSHTTPCookie *> *))completionHandler WK_API_AVAILABLE(macos(11.0), ios(14.0));
 - (void)_setCookieAcceptPolicy:(NSHTTPCookieAcceptPolicy)policy completionHandler:(void (^)(void))completionHandler WK_API_AVAILABLE(macos(12.0), ios(15.0));
 - (void)_flushCookiesToDiskWithCompletionHandler:(void(^)(void))completionHandler WK_API_AVAILABLE(macos(12.0), ios(15.0));
+- (void)_setCookies:(NSArray<NSHTTPCookie *> *)cookies completionHandler:(void(^)(void))completionHandler WK_API_AVAILABLE(macos(WK_MAC_TBA), ios(WK_IOS_TBA), visionos(WK_XROS_TBA));
path: Source/WebKit/UIProcess/API/Cocoa/WKHTTPCookieStorePrivate.h
user: login: cdumez
body: I recommend we make this only available on macOS.
created_at: 2025-03-21T16:44:20Z
author_association: CONTRIBUTOR
diff_hunk: @@ -29,4 +29,5 @@
 - (void)_getCookiesForURL:(NSURL *)url completionHandler:(void (^)(NSArray<NSHTTPCookie *> *))completionHandler WK_API_AVAILABLE(macos(11.0), ios(14.0));
 - (void)_setCookieAcceptPolicy:(NSHTTPCookieAcceptPolicy)policy completionHandler:(void (^)(void))completionHandler WK_API_AVAILABLE(macos(12.0), ios(15.0));
 - (void)_flushCookiesToDiskWithCompletionHandler:(void(^)(void))completionHandler WK_API_AVAILABLE(macos(12.0), ios(15.0));
+- (void)_setCookies:(NSArray<NSHTTPCookie *> *)cookies completionHandler:(void(^)(void))completionHandler WK_API_AVAILABLE(macos(WK_MAC_TBA), ios(WK_IOS_TBA), visionos(WK_XROS_TBA));
path: Source/WebKit/UIProcess/API/Cocoa/WKHTTPCookieStorePrivate.h
user: login: cdumez
body: Also, please file a radar about making it API and add the radar in a code comment.
created_at: 2025-03-21T16:53:23Z
author_association: CONTRIBUTOR
diff_hunk: @@ -593,6 +594,19 @@ static float toNSURLSessionTaskPriority(WebCore::ResourceLoadPriority priority)
     if (m_failureScheduled)
         return;
 
+    CheckedPtr session = m_session.get();
+    if (session) {
+        CheckedPtr storageSession = session->networkStorageSession();
+        if (storageSession && storageSession->cookiesVersion() < m_requiredCookiesVersion) {
+            RELEASE_LOG(Loading, "NetworkDataTaskCocoa::resume is delayed because cookies version is too low");
+            storageSession->setCookiesVersionChangeCallback(m_requiredCookiesVersion, [weakThis = ThreadSafeWeakPtr { *this }] {
path: Source/WebKit/NetworkProcess/cocoa/NetworkDataTaskCocoa.mm
user: login: szewai
body: hmm this has `RELEASE_LOG(Loading,`, or did you suggest logging more information?
created_at: 2025-03-21T17:25:50Z
author_association: CONTRIBUTOR
diff_hunk: @@ -593,6 +594,19 @@ static float toNSURLSessionTaskPriority(WebCore::ResourceLoadPriority priority)
     if (m_failureScheduled)
         return;
 
+    CheckedPtr session = m_session.get();
+    if (session) {
+        CheckedPtr storageSession = session->networkStorageSession();
+        if (storageSession && storageSession->cookiesVersion() < m_requiredCookiesVersion) {
+            RELEASE_LOG(Loading, "NetworkDataTaskCocoa::resume is delayed because cookies version is too low");
+            storageSession->setCookiesVersionChangeCallback(m_requiredCookiesVersion, [weakThis = ThreadSafeWeakPtr { *this }] {
path: Source/WebKit/NetworkProcess/cocoa/NetworkDataTaskCocoa.mm
user: login: cdumez
body: Do we have logging when the load is actually unblocked by the cookie version upgrading?
created_at: 2025-03-21T17:32:18Z
author_association: CONTRIBUTOR
diff_hunk: @@ -593,6 +594,19 @@ static float toNSURLSessionTaskPriority(WebCore::ResourceLoadPriority priority)
     if (m_failureScheduled)
         return;
 
+    CheckedPtr session = m_session.get();
+    if (session) {
+        CheckedPtr storageSession = session->networkStorageSession();
+        if (storageSession && storageSession->cookiesVersion() < m_requiredCookiesVersion) {
+            RELEASE_LOG(Loading, "NetworkDataTaskCocoa::resume is delayed because cookies version is too low");
+            storageSession->setCookiesVersionChangeCallback(m_requiredCookiesVersion, [weakThis = ThreadSafeWeakPtr { *this }] {
path: Source/WebKit/NetworkProcess/cocoa/NetworkDataTaskCocoa.mm
user: login: szewai
body: oh you mean in the callback, ok will add
created_at: 2025-03-21T17:42:07Z
author_association: CONTRIBUTOR
diff_hunk: @@ -593,6 +594,20 @@ static float toNSURLSessionTaskPriority(WebCore::ResourceLoadPriority priority)
     if (m_failureScheduled)
         return;
 
+    if (CheckedPtr session = m_session.get()) {
+        CheckedPtr storageSession = session->networkStorageSession();
+        if (storageSession && storageSession->cookiesVersion() < m_requiredCookiesVersion) {
+            RELEASE_LOG(Loading, "%p - NetworkDataTaskCocoa::resume is delayed because cookies version (%" PRIu64 ") is lower than required (%" PRIu64 ")", this, storageSession->cookiesVersion(), m_requiredCookiesVersion);
+            storageSession->addCookiesVersionChangeCallback(m_requiredCookiesVersion, [weakThis = ThreadSafeWeakPtr { *this }] {
+                if (auto protectedThis = weakThis.get()) {
+                    RELEASE_LOG(Loading, "%p - NetworkDataTaskCocoa::resume delayed task is started", protectedThis.get());
path: Source/WebKit/NetworkProcess/cocoa/NetworkDataTaskCocoa.mm
user: login: cdumez
body: This should mention cookies. from the logs, it will not be clear why the load is resuming now.
created_at: 2025-03-21T18:24:57Z
author_association: CONTRIBUTOR
diff_hunk: @@ -205,4 +205,20 @@ - (void)_flushCookiesToDiskWithCompletionHandler:(void(^)(void))completionHandle
     });
 }
 
+static std::optional<WebCore::Cookie> makeVectorElement(const WebCore::Cookie*, id arrayElement)
+{
+    if (![arrayElement isKindOfClass:[NSHTTPCookie class]])
path: Source/WebKit/UIProcess/API/Cocoa/WKHTTPCookieStore.mm
user: login: cdumez
body: Seems like we should use `dynamic_objc_cast`
created_at: 2025-03-21T18:28:16Z
author_association: CONTRIBUTOR
diff_hunk: @@ -29,4 +29,7 @@
 - (void)_getCookiesForURL:(NSURL *)url completionHandler:(void (^)(NSArray<NSHTTPCookie *> *))completionHandler WK_API_AVAILABLE(macos(11.0), ios(14.0));
 - (void)_setCookieAcceptPolicy:(NSHTTPCookieAcceptPolicy)policy completionHandler:(void (^)(void))completionHandler WK_API_AVAILABLE(macos(12.0), ios(15.0));
 - (void)_flushCookiesToDiskWithCompletionHandler:(void(^)(void))completionHandler WK_API_AVAILABLE(macos(12.0), ios(15.0));
+
+// rdar://147591774
+- (void)_setCookies:(NSArray<NSHTTPCookie *> *)cookies completionHandler:(void(^)(void))completionHandler WK_API_AVAILABLE(macos(WK_MAC_TBA));
path: Source/WebKit/UIProcess/API/Cocoa/WKHTTPCookieStorePrivate.h
user: login: cdumez
body: We're missing the `#if !TARGET_OS_IPHONE` to guard this.
created_at: 2025-03-21T18:30:02Z
author_association: CONTRIBUTOR
diff_hunk: @@ -29,4 +29,7 @@
 - (void)_getCookiesForURL:(NSURL *)url completionHandler:(void (^)(NSArray<NSHTTPCookie *> *))completionHandler WK_API_AVAILABLE(macos(11.0), ios(14.0));
 - (void)_setCookieAcceptPolicy:(NSHTTPCookieAcceptPolicy)policy completionHandler:(void (^)(void))completionHandler WK_API_AVAILABLE(macos(12.0), ios(15.0));
 - (void)_flushCookiesToDiskWithCompletionHandler:(void(^)(void))completionHandler WK_API_AVAILABLE(macos(12.0), ios(15.0));
+
+// rdar://147591774
path: Source/WebKit/UIProcess/API/Cocoa/WKHTTPCookieStorePrivate.h
user: login: cdumez
body: `// FIXME: Promote this to API (rdar://147591774).`
created_at: 2025-03-21T18:30:28Z
author_association: CONTRIBUTOR

PR comments:
user: login: webkit-early-warning-system
created_at: 2025-03-21T06:32:25Z
body: EWS run on previous version of this PR (hash https://github.com/WebKit/WebKit/commit/77e1de4685f0c14f864ed1bc3f8e02ea08a393fc)<details>

| Misc | iOS, visionOS, tvOS & watchOS  | macOS  | Linux |  Windows |
| ----- | ---------------------- | ------- |  ----- |  --------- |
| [✅ 🧪 style](https://ews-build.webkit.org/#/builders/38/builds/96161 "Passed style check") | [✅ 🛠 ios](https://ews-build.webkit.org/#/builders/131/builds/15775 "Built successfully") | [✅ 🛠 mac](https://ews-build.webkit.org/#/builders/138/builds/5736 "Built successfully") | [✅ 🛠 wpe](https://ews-build.webkit.org/#/builders/5/builds/101226 "Built successfully") | [✅ 🛠 win](https://ews-build.webkit.org/#/builders/59/builds/46686 "Built successfully") 
| [✅ 🧪 bindings](https://ews-build.webkit.org/#/builders/9/builds/98206 "Passed tests") | [✅ 🛠 ios-sim](https://ews-build.webkit.org/#/builders/130/builds/16070 "Built successfully") | [✅ 🛠 mac-AS-debug](https://ews-build.webkit.org/#/builders/123/builds/24208 "Built successfully") | [✅ 🧪 wpe-wk2](https://ews-build.webkit.org/#/builders/34/builds/73310 "Passed tests") | [✅ 🧪 win-tests](https://ews-build.webkit.org/#/builders/60/builds/30545 "Passed tests") 
| [✅ 🧪 webkitperl](https://ews-build.webkit.org/#/builders/11/builds/99164 "Passed tests") | [✅ 🧪 ios-wk2](https://ews-build.webkit.org/#/builders/132/builds/12043 "Passed tests") | [✅ 🧪 api-mac](https://ews-build.webkit.org/#/builders/18/builds/86863 "Passed tests") | [✅ 🧪 api-wpe](https://ews-build.webkit.org/#/builders/41/builds/53647 "Passed tests") | 
| | [✅ 🧪 ios-wk2-wpt](https://ews-build.webkit.org/#/builders/133/builds/11794 "Passed tests") | [✅ 🧪 mac-wk1](https://ews-build.webkit.org/#/builders/135/builds/4624 "Passed tests") | [✅ 🛠 wpe-cairo](https://ews-build.webkit.org/#/builders/65/builds/46005 "Built successfully") | 
| | [✅ 🧪 api-ios](https://ews-build.webkit.org/#/builders/13/builds/81923 "Passed tests") | [✅ 🧪 mac-wk2](https://ews-build.webkit.org/#/builders/136/builds/4721 "Passed tests") | [✅ 🛠 gtk](https://ews-build.webkit.org/#/builders/2/builds/103251 "Built successfully") | 
| | [✅ 🛠 vision](https://ews-build.webkit.org/#/builders/128/builds/23228 "Built successfully") | [✅ 🧪 mac-AS-debug-wk2](https://ews-build.webkit.org/#/builders/122/builds/16917 "Passed tests") | [❌ 🧪 gtk-wk2](https://ews-build.webkit.org/#/builders/1/builds/82345 "Found 1 new test failure: imported/w3c/web-platform-tests/css/css-view-transitions/active-view-transition-type-on-non-root.html (failure)") | 
| | [✅ 🛠 vision-sim](https://ews-build.webkit.org/#/builders/121/builds/23479 "Built successfully") | [✅ 🧪 mac-wk2-stress](https://ews-build.webkit.org/#/builders/8/builds/82883 "Passed tests") | [✅ 🧪 api-gtk](https://ews-build.webkit.org/#/builders/21/builds/81721 "Passed tests") | 
| | [✅ 🧪 vision-wk2](https://ews-build.webkit.org/#/builders/126/builds/26336 "Passed tests") | [✅ 🧪 mac-intel-wk2](https://ews-build.webkit.org/#/builders/137/builds/3765 "Passed tests") | [✅ 🛠 playstation](https://ews-build.webkit.org/#/builders/134/builds/16591 "Built successfully") | 
| | [✅ 🛠 tv](https://ews-build.webkit.org/#/builders/127/builds/23191 "Built successfully") | [  ~~🛠 mac-safer-cpp~~](https://ews-build.webkit.org/#/builders/120/builds/28346 "The change is no longer eligible for processing. Commit was outdated when EWS attempted to process it.") | | 
| | [✅ 🛠 tv-sim](https://ews-build.webkit.org/#/builders/125/builds/22850 "Built successfully") | | | 
| | [✅ 🛠 watch](https://ews-build.webkit.org/#/builders/129/builds/26330 "Built successfully") | | | 
| | [✅ 🛠 watch-sim](https://ews-build.webkit.org/#/builders/124/builds/24591 "Built successfully") | | | </details>
author_association: COLLABORATOR
user: login: webkit-early-warning-system
created_at: 2025-03-21T18:00:57Z
body: EWS run on previous version of this PR (hash https://github.com/WebKit/WebKit/commit/10ae2674cdcc118b8e69e76534ac8a7e30d993cc)<details>

| Misc | iOS, visionOS, tvOS & watchOS  | macOS  | Linux |  Windows |
| ----- | ---------------------- | ------- |  ----- |  --------- |
| [✅ 🧪 style](https://ews-build.webkit.org/#/builders/38/builds/96232 "Passed style check") | [✅ 🛠 ios](https://ews-build.webkit.org/#/builders/131/builds/15846 "Built successfully") | [✅ 🛠 mac](https://ews-build.webkit.org/#/builders/138/builds/5814 "Built successfully") | [✅ 🛠 wpe](https://ews-build.webkit.org/#/builders/5/builds/101299 "Built successfully") | [✅ 🛠 win](https://ews-build.webkit.org/#/builders/59/builds/46751 "Built successfully") 
| [✅ 🧪 bindings](https://ews-build.webkit.org/#/builders/9/builds/98277 "Passed tests") | [✅ 🛠 ios-sim](https://ews-build.webkit.org/#/builders/130/builds/16142 "Built successfully") | [✅ 🛠 mac-AS-debug](https://ews-build.webkit.org/#/builders/123/builds/24279 "Built successfully") | [  ~~🧪 wpe-wk2~~](https://ews-build.webkit.org/#/builders/34/builds/73363 "The change is no longer eligible for processing. Commit was outdated when EWS attempted to process it.") | [  ~~🧪 win-tests~~](https://ews-build.webkit.org/#/builders/60/builds/30595 "The change is no longer eligible for processing. Commit was outdated when EWS attempted to process it.") 
| [✅ 🧪 webkitperl](https://ews-build.webkit.org/#/builders/11/builds/99235 "Passed tests") | [  ~~🧪 ios-wk2~~](https://ews-build.webkit.org/#/builders/132/builds/12118 "The change is no longer eligible for processing. Commit was outdated when EWS attempted to process it.") | [✅ 🧪 api-mac](https://ews-build.webkit.org/#/builders/18/builds/86942 "Passed tests") | [✅ 🧪 api-wpe](https://ews-build.webkit.org/#/builders/41/builds/53702 "Passed tests") | 
| | [✅ 🧪 ios-wk2-wpt](https://ews-build.webkit.org/#/builders/133/builds/11870 "Passed tests") | [✅ 🧪 mac-wk1](https://ews-build.webkit.org/#/builders/135/builds/4703 "Passed tests") | [✅ 🛠 wpe-cairo](https://ews-build.webkit.org/#/builders/65/builds/46085 "Built successfully") | 
| | [⏳ 🧪 api-ios](https://ews-build.webkit.org/#/builders/API-Tests-iOS-Simulator-EWS "Waiting to run tests") | [✅ 🧪 mac-wk2](https://ews-build.webkit.org/#/builders/136/builds/4800 "Passed tests") | [✅ 🛠 gtk](https://ews-build.webkit.org/#/builders/2/builds/103333 "Built successfully") | 
| | [✅ 🛠 vision](https://ews-build.webkit.org/#/builders/128/builds/23299 "Built successfully") | [  ~~🧪 mac-AS-debug-wk2~~](https://ews-build.webkit.org/#/builders/122/builds/16968 "The change is no longer eligible for processing. Commit was outdated when EWS attempted to process it.") | [  ~~🧪 gtk-wk2~~](https://ews-build.webkit.org/#/builders/1/builds/82409 "The change is no longer eligible for processing. Commit was outdated when EWS attempted to process it.") | 
| | [✅ 🛠 vision-sim](https://ews-build.webkit.org/#/builders/121/builds/23550 "Built successfully") | [  ~~🧪 mac-wk2-stress~~](https://ews-build.webkit.org/#/builders/8/builds/82961 "The change is no longer eligible for processing. Commit was outdated when EWS attempted to process it.") | [✅ 🧪 api-gtk](https://ews-build.webkit.org/#/builders/21/builds/81785 "Passed tests") | 
| | [✅ 🧪 vision-wk2](https://ews-build.webkit.org/#/builders/126/builds/26400 "Passed tests") | [⏳ 🧪 mac-intel-wk2](https://ews-build.webkit.org/#/builders/macOS-Sonoma-Release-WK2-Intel-Tests-EWS "Waiting to run tests") | [✅ 🛠 playstation](https://ews-build.webkit.org/#/builders/134/builds/16673 "Built successfully") | 
| | [✅ 🛠 tv](https://ews-build.webkit.org/#/builders/127/builds/23262 "Built successfully") | [  ~~🛠 mac-safer-cpp~~](https://ews-build.webkit.org/#/builders/120/builds/28417 "The change is no longer eligible for processing. Commit was outdated when EWS attempted to process it.") | | 
| | [✅ 🛠 tv-sim](https://ews-build.webkit.org/#/builders/125/builds/22921 "Built successfully") | | | 
| | [✅ 🛠 watch](https://ews-build.webkit.org/#/builders/129/builds/26401 "Built successfully") | | | 
| | [✅ 🛠 watch-sim](https://ews-build.webkit.org/#/builders/124/builds/24662 "Built successfully") | | | </details>
author_association: COLLABORATOR
user: login: webkit-early-warning-system
created_at: 2025-03-21T20:03:13Z
body: EWS run on current version of this PR (hash https://github.com/WebKit/WebKit/commit/dfc22f47b497920a1899c3f5244fa37a21fc6df6)<details>

| Misc | iOS, visionOS, tvOS & watchOS  | macOS  | Linux |  Windows |
| ----- | ---------------------- | ------- |  ----- |  --------- |
| [✅ 🧪 style](https://ews-build.webkit.org/#/builders/38/builds/96259 "Passed style check") | [✅ 🛠 ios](https://ews-build.webkit.org/#/builders/131/builds/15873 "Built successfully") | [✅ 🛠 mac](https://ews-build.webkit.org/#/builders/138/builds/5842 "Built successfully") | [✅ 🛠 wpe](https://ews-build.webkit.org/#/builders/5/builds/101326 "Built successfully") | [✅ 🛠 win](https://ews-build.webkit.org/#/builders/59/builds/46778 "Built successfully") 
| [✅ 🧪 bindings](https://ews-build.webkit.org/#/builders/9/builds/98304 "Passed tests") | [✅ 🛠 ios-sim](https://ews-build.webkit.org/#/builders/130/builds/16169 "Built successfully") | [✅ 🛠 mac-AS-debug](https://ews-build.webkit.org/#/builders/123/builds/24306 "Built successfully") | [✅ 🧪 wpe-wk2](https://ews-build.webkit.org/#/builders/34/builds/73376 "Passed tests") | [✅ 🧪 win-tests](https://ews-build.webkit.org/#/builders/60/builds/30605 "Passed tests") 
| [✅ 🧪 webkitperl](https://ews-build.webkit.org/#/builders/11/builds/99262 "Passed tests") | [✅ 🧪 ios-wk2](https://ews-build.webkit.org/#/builders/132/builds/12133 "Passed tests") | [✅ 🧪 api-mac](https://ews-build.webkit.org/#/builders/18/builds/86957 "Passed tests") | [✅ 🧪 api-wpe](https://ews-build.webkit.org/#/builders/41/builds/53713 "Passed tests") | 
| | [✅ 🧪 ios-wk2-wpt](https://ews-build.webkit.org/#/builders/133/builds/11884 "Passed tests") | [✅ 🧪 mac-wk1](https://ews-build.webkit.org/#/builders/135/builds/4719 "Passed tests") | [✅ 🛠 wpe-cairo](https://ews-build.webkit.org/#/builders/65/builds/46105 "Built successfully") | 
| | [✅ 🧪 api-ios](https://ews-build.webkit.org/#/builders/13/builds/82002 "Passed tests") | [✅ 🧪 mac-wk2](https://ews-build.webkit.org/#/builders/136/builds/4817 "Passed tests") | [✅ 🛠 gtk](https://ews-build.webkit.org/#/builders/2/builds/103354 "Built successfully") | 
| | [✅ 🛠 vision](https://ews-build.webkit.org/#/builders/128/builds/23326 "Built successfully") | [✅ 🧪 mac-AS-debug-wk2](https://ews-build.webkit.org/#/builders/122/builds/16984 "Passed tests") | [✅ 🧪 gtk-wk2](https://ews-build.webkit.org/#/builders/1/builds/82418 "Passed tests") | 
| | [✅ 🛠 vision-sim](https://ews-build.webkit.org/#/builders/121/builds/23577 "Built successfully") | [✅ 🧪 mac-wk2-stress](https://ews-build.webkit.org/#/builders/8/builds/82977 "Passed tests") | [✅ 🧪 api-gtk](https://ews-build.webkit.org/#/builders/21/builds/81793 "Passed tests") | 
| [✅ 🛠 🧪 merge](https://ews-build.webkit.org/#/builders/19/builds/20539 "Built successfully and passed tests") | [✅ 🧪 vision-wk2](https://ews-build.webkit.org/#/builders/126/builds/26426 "Passed tests") | [✅ 🧪 mac-intel-wk2](https://ews-build.webkit.org/#/builders/137/builds/3858 "Passed tests") | [✅ 🛠 playstation](https://ews-build.webkit.org/#/builders/134/builds/16700 "Built successfully") | 
| | [✅ 🛠 tv](https://ews-build.webkit.org/#/builders/127/builds/23289 "Built successfully") | [  ~~🛠 mac-safer-cpp~~](https://ews-build.webkit.org/#/builders/120/builds/28444 "The change is no longer eligible for processing. Pull Request was already closed when EWS attempted to process it.") | | 
| | [✅ 🛠 tv-sim](https://ews-build.webkit.org/#/builders/125/builds/22948 "Built successfully") | | | 
| | [✅ 🛠 watch](https://ews-build.webkit.org/#/builders/129/builds/26428 "Built successfully") | | | 
| | [✅ 🛠 watch-sim](https://ews-build.webkit.org/#/builders/124/builds/24689 "Built successfully") | | | </details>
author_association: COLLABORATOR
user: login: webkit-ews-buildbot
created_at: 2025-03-22T00:52:23Z
body: 

Safe-Merge-Queue: Build [#52162](https://ews-build.webkit.org/#/builders/40/builds/52162).
author_association: COLLABORATOR
user: login: webkit-commit-queue
created_at: 2025-03-22T01:11:58Z
body: Committed 292525@main (db0157e0a926): <https://commits.webkit.org/292525@main>

Reviewed commits have been landed. Closing PR #42797 and removing active labels.
author_association: COLLABORATOR