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);
}
+
+}