Title: [279340] trunk
Revision
279340
Author
commit-qu...@webkit.org
Date
2021-06-28 09:39:19 -0700 (Mon, 28 Jun 2021)

Log Message

RELEASE_ASSERT hit in NetworkSessionCocoa::removeWebSocketTask when using WKWebViewConfiguration._attributedBundleIdentifier
https://bugs.webkit.org/show_bug.cgi?id=227420
<rdar://79609212>

Patch by Alex Christensen <achristen...@webkit.org> on 2021-06-28
Reviewed by Brady Eidson.

Source/WebKit:

WKWebViewConfiguration._attributedBundleIdentifier makes us use a SessionSet per WKWebView.
When the WKWebView is destroyed with an open WebSocket, there's a race condition between the
NetworkSessionCocoa::removeWebPageNetworkParameters message coming from the UI process and the
NetworkConnectionToWebProcess::didClose message coming from the closing of the web process, which
calls NetworkSessionCocoa::removeWebSocketTask which currently expects the WebSocketTask to still
be there.  Instead, keep a WeakPtr<SessionSet> and don't remove it if the SessionSet's map is gone.

I wrote an API test that hits this condition sometimes when HAVE_NSURLSESSION_WEBSOCKET is true.

* NetworkProcess/NetworkSession.h:
(WebKit::NetworkSession::removeWebSocketTask):
* NetworkProcess/NetworkSocketChannel.cpp:
(WebKit::NetworkSocketChannel::~NetworkSocketChannel):
* NetworkProcess/cocoa/NetworkSessionCocoa.h:
(WebKit::SessionSet::create):
* NetworkProcess/cocoa/NetworkSessionCocoa.mm:
(WebKit::NetworkSessionCocoa::sessionSetForPage):
(WebKit::NetworkSessionCocoa::sessionSetForPage const):
(WebKit::SessionSet::initializeEphemeralStatelessSessionIfNeeded):
(WebKit::SessionSet::isolatedSession):
(WebKit::NetworkSessionCocoa::createWebSocketTask):
(WebKit::NetworkSessionCocoa::addWebSocketTask):
(WebKit::NetworkSessionCocoa::removeWebSocketTask):
(WebKit::NetworkSessionCocoa::SessionSet::initializeEphemeralStatelessSessionIfNeeded): Deleted.
(WebKit::NetworkSessionCocoa::SessionSet::isolatedSession): Deleted.
* NetworkProcess/cocoa/WebSocketTaskCocoa.h:
(WebKit::WebSocketTask::sessionSet):
* NetworkProcess/cocoa/WebSocketTaskCocoa.mm:
(WebKit::WebSocketTask::WebSocketTask):

Tools:

* TestWebKitAPI/Tests/WebKitCocoa/WebSocket.mm:
(TestWebKitAPI::TEST):

Modified Paths

Diff

Modified: trunk/Source/WebKit/ChangeLog (279339 => 279340)


--- trunk/Source/WebKit/ChangeLog	2021-06-28 15:34:32 UTC (rev 279339)
+++ trunk/Source/WebKit/ChangeLog	2021-06-28 16:39:19 UTC (rev 279340)
@@ -1,3 +1,41 @@
+2021-06-28  Alex Christensen  <achristen...@webkit.org>
+
+        RELEASE_ASSERT hit in NetworkSessionCocoa::removeWebSocketTask when using WKWebViewConfiguration._attributedBundleIdentifier
+        https://bugs.webkit.org/show_bug.cgi?id=227420
+        <rdar://79609212>
+
+        Reviewed by Brady Eidson.
+
+        WKWebViewConfiguration._attributedBundleIdentifier makes us use a SessionSet per WKWebView.
+        When the WKWebView is destroyed with an open WebSocket, there's a race condition between the
+        NetworkSessionCocoa::removeWebPageNetworkParameters message coming from the UI process and the
+        NetworkConnectionToWebProcess::didClose message coming from the closing of the web process, which
+        calls NetworkSessionCocoa::removeWebSocketTask which currently expects the WebSocketTask to still
+        be there.  Instead, keep a WeakPtr<SessionSet> and don't remove it if the SessionSet's map is gone.
+
+        I wrote an API test that hits this condition sometimes when HAVE_NSURLSESSION_WEBSOCKET is true.
+
+        * NetworkProcess/NetworkSession.h:
+        (WebKit::NetworkSession::removeWebSocketTask):
+        * NetworkProcess/NetworkSocketChannel.cpp:
+        (WebKit::NetworkSocketChannel::~NetworkSocketChannel):
+        * NetworkProcess/cocoa/NetworkSessionCocoa.h:
+        (WebKit::SessionSet::create):
+        * NetworkProcess/cocoa/NetworkSessionCocoa.mm:
+        (WebKit::NetworkSessionCocoa::sessionSetForPage):
+        (WebKit::NetworkSessionCocoa::sessionSetForPage const):
+        (WebKit::SessionSet::initializeEphemeralStatelessSessionIfNeeded):
+        (WebKit::SessionSet::isolatedSession):
+        (WebKit::NetworkSessionCocoa::createWebSocketTask):
+        (WebKit::NetworkSessionCocoa::addWebSocketTask):
+        (WebKit::NetworkSessionCocoa::removeWebSocketTask):
+        (WebKit::NetworkSessionCocoa::SessionSet::initializeEphemeralStatelessSessionIfNeeded): Deleted.
+        (WebKit::NetworkSessionCocoa::SessionSet::isolatedSession): Deleted.
+        * NetworkProcess/cocoa/WebSocketTaskCocoa.h:
+        (WebKit::WebSocketTask::sessionSet):
+        * NetworkProcess/cocoa/WebSocketTaskCocoa.mm:
+        (WebKit::WebSocketTask::WebSocketTask):
+
 2021-06-28  Jean-Yves Avenard  <j...@apple.com>
 
         Not all uses of AudioToolbox framework use soft linking

Modified: trunk/Source/WebKit/NetworkProcess/NetworkSession.h (279339 => 279340)


--- trunk/Source/WebKit/NetworkProcess/NetworkSession.h	2021-06-28 15:34:32 UTC (rev 279339)
+++ trunk/Source/WebKit/NetworkProcess/NetworkSession.h	2021-06-28 16:39:19 UTC (rev 279340)
@@ -53,16 +53,17 @@
 
 namespace WebKit {
 
-class PrivateClickMeasurementManager;
 class NetworkDataTask;
 class NetworkLoadScheduler;
 class NetworkProcess;
 class NetworkResourceLoader;
 class NetworkSocketChannel;
+class PrivateClickMeasurementManager;
 class WebPageNetworkParameters;
 class WebResourceLoadStatisticsStore;
 class WebSocketTask;
 struct NetworkSessionCreationParameters;
+struct SessionSet;
 
 enum class WebsiteDataType : uint32_t;
 
@@ -142,7 +143,7 @@
     void clearPrefetchCache() { m_prefetchCache.clear(); }
 
     virtual std::unique_ptr<WebSocketTask> createWebSocketTask(WebPageProxyIdentifier, NetworkSocketChannel&, const WebCore::ResourceRequest&, const String& protocol);
-    virtual void removeWebSocketTask(WebPageProxyIdentifier, WebSocketTask&) { }
+    virtual void removeWebSocketTask(SessionSet&, WebSocketTask&) { }
     virtual void addWebSocketTask(WebPageProxyIdentifier, WebSocketTask&) { }
 
     WebCore::BlobRegistryImpl& blobRegistry() { return m_blobRegistry; }

Modified: trunk/Source/WebKit/NetworkProcess/NetworkSocketChannel.cpp (279339 => 279340)


--- trunk/Source/WebKit/NetworkProcess/NetworkSocketChannel.cpp	2021-06-28 15:34:32 UTC (rev 279339)
+++ trunk/Source/WebKit/NetworkProcess/NetworkSocketChannel.cpp	2021-06-28 16:39:19 UTC (rev 279340)
@@ -65,11 +65,11 @@
 
 NetworkSocketChannel::~NetworkSocketChannel()
 {
-    if (m_session)
-        m_session->removeWebSocketTask(m_webPageProxyID, *m_socket);
-
-    if (m_socket)
+    if (m_socket) {
+        if (m_session && m_socket->sessionSet())
+            m_session->removeWebSocketTask(*m_socket->sessionSet(), *m_socket);
         m_socket->cancel();
+    }
 }
 
 void NetworkSocketChannel::sendString(const IPC::DataReference& message, CompletionHandler<void()>&& callback)

Modified: trunk/Source/WebKit/NetworkProcess/WebSocketTask.h (279339 => 279340)


--- trunk/Source/WebKit/NetworkProcess/WebSocketTask.h	2021-06-28 15:34:32 UTC (rev 279339)
+++ trunk/Source/WebKit/NetworkProcess/WebSocketTask.h	2021-06-28 16:39:19 UTC (rev 279340)
@@ -31,9 +31,10 @@
 #include "WebSocketTaskSoup.h"
 #else
 
-
 namespace WebKit {
 
+struct SessionSet;
+
 class WebSocketTask {
     WTF_MAKE_FAST_ALLOCATED;
 public:
@@ -45,6 +46,8 @@
 
     void cancel() { }
     void resume() { }
+    
+    SessionSet* sessionSet() { return nullptr; }
 };
 
 } // namespace WebKit

Modified: trunk/Source/WebKit/NetworkProcess/cocoa/NetworkSessionCocoa.h (279339 => 279340)


--- trunk/Source/WebKit/NetworkProcess/cocoa/NetworkSessionCocoa.h	2021-06-28 15:34:32 UTC (rev 279339)
+++ trunk/Source/WebKit/NetworkProcess/cocoa/NetworkSessionCocoa.h	2021-06-28 16:39:19 UTC (rev 279340)
@@ -64,6 +64,36 @@
 #endif
 };
 
+struct IsolatedSession {
+    WTF_MAKE_FAST_ALLOCATED;
+public:
+    SessionWrapper sessionWithCredentialStorage;
+    SessionWrapper sessionWithoutCredentialStorage;
+    WallTime lastUsed;
+};
+
+struct SessionSet : public RefCounted<SessionSet>, public CanMakeWeakPtr<SessionSet> {
+public:
+    static Ref<SessionSet> create()
+    {
+        return adoptRef(*new SessionSet);
+    }
+
+    SessionWrapper& isolatedSession(WebCore::StoredCredentialsPolicy, const WebCore::RegistrableDomain, NavigatingToAppBoundDomain, NetworkSessionCocoa&);
+    SessionWrapper& initializeEphemeralStatelessSessionIfNeeded(NavigatingToAppBoundDomain, NetworkSessionCocoa&);
+
+    HashMap<WebCore::RegistrableDomain, std::unique_ptr<IsolatedSession>> isolatedSessions;
+    std::unique_ptr<IsolatedSession> appBoundSession;
+
+    SessionWrapper sessionWithCredentialStorage;
+    SessionWrapper sessionWithoutCredentialStorage;
+    SessionWrapper ephemeralStatelessSession;
+
+private:
+
+    SessionSet() = default;
+};
+
 class NetworkSessionCocoa final : public NetworkSession {
 public:
     static std::unique_ptr<NetworkSession> create(NetworkProcess&, NetworkSessionCreationParameters&&);
@@ -125,7 +155,7 @@
 #if HAVE(NSURLSESSION_WEBSOCKET)
     std::unique_ptr<WebSocketTask> createWebSocketTask(WebPageProxyIdentifier, NetworkSocketChannel&, const WebCore::ResourceRequest&, const String& protocol) final;
     void addWebSocketTask(WebPageProxyIdentifier, WebSocketTask&) final;
-    void removeWebSocketTask(WebPageProxyIdentifier, WebSocketTask&) final;
+    void removeWebSocketTask(SessionSet&, WebSocketTask&) final;
 #endif
 
     void addWebPageNetworkParameters(WebPageProxyIdentifier, WebPageNetworkParameters&&) final;
@@ -132,35 +162,6 @@
     void removeWebPageNetworkParameters(WebPageProxyIdentifier) final;
     size_t countNonDefaultSessionSets() const final;
 
-    struct IsolatedSession {
-        WTF_MAKE_FAST_ALLOCATED;
-    public:
-        SessionWrapper sessionWithCredentialStorage;
-        SessionWrapper sessionWithoutCredentialStorage;
-        WallTime lastUsed;
-    };
-
-    struct SessionSet : public RefCounted<SessionSet>, public CanMakeWeakPtr<SessionSet> {
-    public:
-        static Ref<SessionSet> create()
-        {
-            return adoptRef(*new SessionSet);
-        }
-    
-        SessionWrapper& isolatedSession(WebCore::StoredCredentialsPolicy, const WebCore::RegistrableDomain, NavigatingToAppBoundDomain, NetworkSessionCocoa&);
-        SessionWrapper& initializeEphemeralStatelessSessionIfNeeded(NavigatingToAppBoundDomain, NetworkSessionCocoa&);
-
-        HashMap<WebCore::RegistrableDomain, std::unique_ptr<IsolatedSession>> isolatedSessions;
-        std::unique_ptr<IsolatedSession> appBoundSession;
-
-        SessionWrapper sessionWithCredentialStorage;
-        SessionWrapper sessionWithoutCredentialStorage;
-        SessionWrapper ephemeralStatelessSession;
-
-    private:
-        SessionSet() = default;
-    };
-
     Ref<SessionSet> m_defaultSessionSet;
     HashMap<WebPageProxyIdentifier, Ref<SessionSet>> m_perPageSessionSets;
     HashMap<WebPageNetworkParameters, WeakPtr<SessionSet>> m_perParametersSessionSets;

Modified: trunk/Source/WebKit/NetworkProcess/cocoa/NetworkSessionCocoa.mm (279339 => 279340)


--- trunk/Source/WebKit/NetworkProcess/cocoa/NetworkSessionCocoa.mm	2021-06-28 15:34:32 UTC (rev 279339)
+++ trunk/Source/WebKit/NetworkProcess/cocoa/NetworkSessionCocoa.mm	2021-06-28 16:39:19 UTC (rev 279340)
@@ -1347,13 +1347,13 @@
     sessionSet.sessionWithoutCredentialStorage.initialize(configuration, *this, WebCore::StoredCredentialsPolicy::DoNotUse, NavigatingToAppBoundDomain::No);
 }
 
-NetworkSessionCocoa::SessionSet& NetworkSessionCocoa::sessionSetForPage(WebPageProxyIdentifier webPageProxyID)
+SessionSet& NetworkSessionCocoa::sessionSetForPage(WebPageProxyIdentifier webPageProxyID)
 {
     SessionSet* sessionSet = webPageProxyID ? m_perPageSessionSets.get(webPageProxyID) : nullptr;
     return sessionSet ? *sessionSet : m_defaultSessionSet.get();
 }
 
-const NetworkSessionCocoa::SessionSet& NetworkSessionCocoa::sessionSetForPage(WebPageProxyIdentifier webPageProxyID) const
+const SessionSet& NetworkSessionCocoa::sessionSetForPage(WebPageProxyIdentifier webPageProxyID) const
 {
     SessionSet* sessionSet = webPageProxyID ? m_perPageSessionSets.get(webPageProxyID) : nullptr;
     return sessionSet ? *sessionSet : m_defaultSessionSet.get();
@@ -1364,7 +1364,7 @@
     return sessionSetForPage(webPageProxyID).initializeEphemeralStatelessSessionIfNeeded(isNavigatingToAppBoundDomain, *this);
 }
 
-SessionWrapper& NetworkSessionCocoa::SessionSet::initializeEphemeralStatelessSessionIfNeeded(NavigatingToAppBoundDomain isNavigatingToAppBoundDomain, NetworkSessionCocoa& session)
+SessionWrapper& SessionSet::initializeEphemeralStatelessSessionIfNeeded(NavigatingToAppBoundDomain isNavigatingToAppBoundDomain, NetworkSessionCocoa& session)
 {
     if (ephemeralStatelessSession.session)
         return ephemeralStatelessSession;
@@ -1471,7 +1471,7 @@
     return sessionSetForPage(webPageProxyID).isolatedSession(storedCredentialsPolicy, firstPartyDomain, isNavigatingToAppBoundDomain, *this);
 }
 
-SessionWrapper& NetworkSessionCocoa::SessionSet::isolatedSession(WebCore::StoredCredentialsPolicy storedCredentialsPolicy, const WebCore::RegistrableDomain firstPartyDomain, NavigatingToAppBoundDomain isNavigatingToAppBoundDomain, NetworkSessionCocoa& session)
+SessionWrapper& SessionSet::isolatedSession(WebCore::StoredCredentialsPolicy storedCredentialsPolicy, const WebCore::RegistrableDomain firstPartyDomain, NavigatingToAppBoundDomain isNavigatingToAppBoundDomain, NetworkSessionCocoa& session)
 {
     auto& entry = isolatedSessions.ensure(firstPartyDomain, [this, &session, isNavigatingToAppBoundDomain] {
         auto newEntry = makeUnique<IsolatedSession>();
@@ -1692,21 +1692,22 @@
     // rdar://problem/68057031: explicitly disable sniffing for WebSocket handshakes.
     [nsRequest _setProperty:@NO forKey:(NSString *)_kCFURLConnectionPropertyShouldSniff];
 
-    RetainPtr<NSURLSessionWebSocketTask> task = [sessionSetForPage(webPageProxyID).sessionWithCredentialStorage.session webSocketTaskWithRequest:nsRequest.get()];
+    auto& sessionSet = sessionSetForPage(webPageProxyID);
+    RetainPtr<NSURLSessionWebSocketTask> task = [sessionSet.sessionWithCredentialStorage.session webSocketTaskWithRequest:nsRequest.get()];
     task.get().maximumMessageSize = 0;
-    return makeUnique<WebSocketTask>(channel, webPageProxyID, request, WTFMove(task));
+    return makeUnique<WebSocketTask>(channel, webPageProxyID, makeWeakPtr(sessionSet), request, WTFMove(task));
 }
 
 void NetworkSessionCocoa::addWebSocketTask(WebPageProxyIdentifier webPageProxyID, WebSocketTask& task)
 {
-    RELEASE_ASSERT(!sessionSetForPage(webPageProxyID).sessionWithCredentialStorage.webSocketDataTaskMap.contains(task.identifier()));
-    sessionSetForPage(webPageProxyID).sessionWithCredentialStorage.webSocketDataTaskMap.add(task.identifier(), &task);
+    auto addResult = sessionSetForPage(webPageProxyID).sessionWithCredentialStorage.webSocketDataTaskMap.add(task.identifier(), &task);
+    RELEASE_ASSERT(addResult.isNewEntry);
 }
 
-void NetworkSessionCocoa::removeWebSocketTask(WebPageProxyIdentifier webPageProxyID, WebSocketTask& task)
+void NetworkSessionCocoa::removeWebSocketTask(SessionSet& sessionSet, WebSocketTask& task)
 {
-    RELEASE_ASSERT(sessionSetForPage(webPageProxyID).sessionWithCredentialStorage.webSocketDataTaskMap.contains(task.identifier()));
-    sessionSetForPage(webPageProxyID).sessionWithCredentialStorage.webSocketDataTaskMap.remove(task.identifier());
+    bool contained = sessionSet.sessionWithCredentialStorage.webSocketDataTaskMap.remove(task.identifier());
+    RELEASE_ASSERT(contained);
 }
 
 #endif // HAVE(NSURLSESSION_WEBSOCKET)

Modified: trunk/Source/WebKit/NetworkProcess/cocoa/WebSocketTaskCocoa.h (279339 => 279340)


--- trunk/Source/WebKit/NetworkProcess/cocoa/WebSocketTaskCocoa.h	2021-06-28 15:34:32 UTC (rev 279339)
+++ trunk/Source/WebKit/NetworkProcess/cocoa/WebSocketTaskCocoa.h	2021-06-28 16:39:19 UTC (rev 279340)
@@ -42,11 +42,12 @@
 class NetworkSession;
 class NetworkSessionCocoa;
 class NetworkSocketChannel;
+struct SessionSet;
 
 class WebSocketTask : public CanMakeWeakPtr<WebSocketTask> {
     WTF_MAKE_FAST_ALLOCATED;
 public:
-    WebSocketTask(NetworkSocketChannel&, WebPageProxyIdentifier, const WebCore::ResourceRequest&, RetainPtr<NSURLSessionWebSocketTask>&&);
+    WebSocketTask(NetworkSocketChannel&, WebPageProxyIdentifier, WeakPtr<SessionSet>&&, const WebCore::ResourceRequest&, RetainPtr<NSURLSessionWebSocketTask>&&);
     ~WebSocketTask();
 
     void sendString(const IPC::DataReference&, CompletionHandler<void()>&&);
@@ -63,6 +64,7 @@
     TaskIdentifier identifier() const;
 
     NetworkSessionCocoa* networkSession();
+    SessionSet* sessionSet() { return m_sessionSet.get(); }
 
     WebPageProxyIdentifier pageID() const { return m_pageID; }
     String partition() const { return m_partition; }
@@ -75,6 +77,7 @@
     bool m_receivedDidClose { false };
     bool m_receivedDidConnect { false };
     WebPageProxyIdentifier m_pageID;
+    WeakPtr<SessionSet> m_sessionSet;
     String m_partition;
 };
 

Modified: trunk/Source/WebKit/NetworkProcess/cocoa/WebSocketTaskCocoa.mm (279339 => 279340)


--- trunk/Source/WebKit/NetworkProcess/cocoa/WebSocketTaskCocoa.mm	2021-06-28 15:34:32 UTC (rev 279339)
+++ trunk/Source/WebKit/NetworkProcess/cocoa/WebSocketTaskCocoa.mm	2021-06-28 16:39:19 UTC (rev 279340)
@@ -40,10 +40,11 @@
 
 using namespace WebCore;
 
-WebSocketTask::WebSocketTask(NetworkSocketChannel& channel, WebPageProxyIdentifier webPageProxyID, const WebCore::ResourceRequest& request, RetainPtr<NSURLSessionWebSocketTask>&& task)
+WebSocketTask::WebSocketTask(NetworkSocketChannel& channel, WebPageProxyIdentifier pageID, WeakPtr<SessionSet>&& sessionSet, const WebCore::ResourceRequest& request, RetainPtr<NSURLSessionWebSocketTask>&& task)
     : m_channel(channel)
     , m_task(WTFMove(task))
-    , m_pageID(webPageProxyID)
+    , m_pageID(pageID)
+    , m_sessionSet(WTFMove(sessionSet))
     , m_partition(request.cachePartition())
 {
     readNextMessage();

Modified: trunk/Source/WebKit/NetworkProcess/soup/WebSocketTaskSoup.h (279339 => 279340)


--- trunk/Source/WebKit/NetworkProcess/soup/WebSocketTaskSoup.h	2021-06-28 15:34:32 UTC (rev 279339)
+++ trunk/Source/WebKit/NetworkProcess/soup/WebSocketTaskSoup.h	2021-06-28 16:39:19 UTC (rev 279340)
@@ -33,6 +33,7 @@
 
 namespace WebKit {
 class NetworkSocketChannel;
+struct SessionSet;
 
 class WebSocketTask {
     WTF_MAKE_FAST_ALLOCATED;
@@ -47,6 +48,8 @@
     void cancel();
     void resume();
 
+    SessionSet* sessionSet() { return nullptr; }
+
 private:
     void didConnect(GRefPtr<SoupWebsocketConnection>&&);
     void didFail(const String&);

Modified: trunk/Tools/ChangeLog (279339 => 279340)


--- trunk/Tools/ChangeLog	2021-06-28 15:34:32 UTC (rev 279339)
+++ trunk/Tools/ChangeLog	2021-06-28 16:39:19 UTC (rev 279340)
@@ -1,3 +1,14 @@
+2021-06-28  Alex Christensen  <achristen...@webkit.org>
+
+        RELEASE_ASSERT hit in NetworkSessionCocoa::removeWebSocketTask when using WKWebViewConfiguration._attributedBundleIdentifier
+        https://bugs.webkit.org/show_bug.cgi?id=227420
+        <rdar://79609212>
+
+        Reviewed by Brady Eidson.
+
+        * TestWebKitAPI/Tests/WebKitCocoa/WebSocket.mm:
+        (TestWebKitAPI::TEST):
+
 2021-06-28  Sam Weinig  <wei...@apple.com>
 
         Add helpers to create Spans from CFDataRef and NSData

Modified: trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/WebSocket.mm (279339 => 279340)


--- trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/WebSocket.mm	2021-06-28 15:34:32 UTC (rev 279339)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/WebSocket.mm	2021-06-28 16:39:19 UTC (rev 279340)
@@ -28,7 +28,10 @@
 #import "HTTPServer.h"
 #import "PlatformUtilities.h"
 #import "TestUIDelegate.h"
+#import <WebKit/WKWebViewConfigurationPrivate.h>
+#import <WebKit/WKWebsiteDataStorePrivate.h>
 #import <wtf/RetainPtr.h>
+#import <wtf/WeakObjCPtr.h>
 
 namespace TestWebKitAPI {
 
@@ -83,4 +86,45 @@
     EXPECT_WK_STREQ([webView _test_waitForAlert], "PASS");
 }
 
+TEST(WebSocket, PageWithAttributedBundleIdentifierDestroyed)
+{
+    HTTPServer server([](Connection connection) {
+        connection.webSocketHandshake();
+    });
+
+    NSString *html = [NSString stringWithFormat:@""
+    "<script>"
+    "    var ws = new WebSocket('ws://127.0.0.1:%d/');"
+    "    ws._onopen_ = function() { alert('opened successfully'); };"
+    "    ws._onerror_ = function(error) { alert('FAIL - error ' + error.message); }"
+    "</script>", server.port()];
+
+    pid_t originalNetworkProcessPID { 0 };
+    auto configuration = adoptNS([WKWebViewConfiguration new]);
+    __block size_t webSocketsConnected { 0 };
+    auto delegate = adoptNS([TestUIDelegate new]);
+    delegate.get().runJavaScriptAlertPanelWithMessage = ^(WKWebView *, NSString *message, WKFrameInfo *, void (^completionHandler)(void)) {
+        EXPECT_WK_STREQ(message, "opened successfully");
+        webSocketsConnected++;
+        completionHandler();
+    };
+    constexpr size_t viewCount = 20;
+
+    @autoreleasepool {
+        std::array<RetainPtr<WKWebView>, viewCount> views;
+        for (size_t i = 0; i < viewCount; i++) {
+            configuration.get()._attributedBundleIdentifier = [NSString stringWithFormat:@"test.bundle.identifier.%zu", i];
+            views[i] = adoptNS([[WKWebView alloc] initWithFrame:CGRectMake(0, 0, 100, 100) configuration:configuration.get()]);
+            views[i].get().UIDelegate = delegate.get();
+            [views[i] loadHTMLString:html baseURL:nil];
+        }
+        while (webSocketsConnected < viewCount)
+            Util::spinRunLoop();
+        originalNetworkProcessPID = configuration.get().websiteDataStore._networkProcessIdentifier;
+    }
+
+    Util::spinRunLoop(viewCount * 3);
+    EXPECT_EQ(originalNetworkProcessPID, configuration.get().websiteDataStore._networkProcessIdentifier);
 }
+
+}
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to