Modified: trunk/Source/WebKit/ChangeLog (280384 => 280385)
--- trunk/Source/WebKit/ChangeLog 2021-07-28 15:55:25 UTC (rev 280384)
+++ trunk/Source/WebKit/ChangeLog 2021-07-28 15:57:49 UTC (rev 280385)
@@ -1,3 +1,26 @@
+2021-07-28 Alex Christensen <[email protected]>
+
+ WebSocket: Safari on iOS 15 beta 3 is sending invalid close frame
+ https://bugs.webkit.org/show_bug.cgi?id=228329
+
+ Reviewed by Youenn Fablet.
+
+ Our NSURLSession WebSocket implementation had two bugs:
+ 1. It was sending 1005 as the close code if none was specified.
+ It now sends no close code, which matches Chrome and Firefox.
+ 2. It was not sending a close code before the close reason when a WebSocket is closed due to navigation.
+ It now sends the close code in 2 bytes before the reason, which matches Chrome and Firefox.
+ Side note: our CFReadStream/CFWriteStream implementation sent neither the code nor the reason
+ in this case, which matches no other browser.
+
+ Covered by an API test.
+
+ * NetworkProcess/cocoa/WebSocketTaskCocoa.mm:
+ (WebKit::WebSocketTask::close):
+ * WebProcess/Network/WebSocketChannel.cpp:
+ (WebKit::WebSocketChannel::fail):
+ (WebKit::WebSocketChannel::disconnect):
+
2021-07-28 Philippe Normand <[email protected]>
[WPE][GTK] SVN_REVISION drifting away if bots don't re-run cmake
Modified: trunk/Source/WebKit/NetworkProcess/cocoa/WebSocketTaskCocoa.mm (280384 => 280385)
--- trunk/Source/WebKit/NetworkProcess/cocoa/WebSocketTaskCocoa.mm 2021-07-28 15:55:25 UTC (rev 280384)
+++ trunk/Source/WebKit/NetworkProcess/cocoa/WebSocketTaskCocoa.mm 2021-07-28 15:57:49 UTC (rev 280385)
@@ -140,9 +140,8 @@
void WebSocketTask::close(int32_t code, const String& reason)
{
- // FIXME: Should NSURLSession provide a way to call cancelWithCloseCode without any specific code.
if (code == WebCore::WebSocketChannel::CloseEventCodeNotSpecified)
- code = 1005;
+ code = NSURLSessionWebSocketCloseCodeInvalid;
auto utf8 = reason.utf8();
auto nsData = adoptNS([[NSData alloc] initWithBytes:utf8.data() length:utf8.length()]);
if ([m_task respondsToSelector:@selector(_sendCloseCode:reason:)]) {
Modified: trunk/Source/WebKit/WebProcess/Network/WebSocketChannel.cpp (280384 => 280385)
--- trunk/Source/WebKit/WebProcess/Network/WebSocketChannel.cpp 2021-07-28 15:55:25 UTC (rev 280384)
+++ trunk/Source/WebKit/WebProcess/Network/WebSocketChannel.cpp 2021-07-28 15:57:49 UTC (rev 280385)
@@ -224,7 +224,7 @@
if (m_isClosing)
return;
- MessageSender::send(Messages::NetworkSocketChannel::Close { 0, reason });
+ MessageSender::send(Messages::NetworkSocketChannel::Close { WebCore::WebSocketChannel::CloseEventCodeGoingAway, reason });
didClose(WebCore::WebSocketChannel::CloseEventCodeAbnormalClosure, { });
}
@@ -235,10 +235,9 @@
m_pendingTasks.clear();
m_messageQueue.clear();
-
m_inspector.didCloseWebSocket(m_document.get());
- MessageSender::send(Messages::NetworkSocketChannel::Close { 0, { } });
+ MessageSender::send(Messages::NetworkSocketChannel::Close { WebCore::WebSocketChannel::CloseEventCodeGoingAway, { } });
}
void WebSocketChannel::didConnect(String&& subprotocol, String&& extensions)
Modified: trunk/Tools/ChangeLog (280384 => 280385)
--- trunk/Tools/ChangeLog 2021-07-28 15:55:25 UTC (rev 280384)
+++ trunk/Tools/ChangeLog 2021-07-28 15:57:49 UTC (rev 280385)
@@ -1,3 +1,13 @@
+2021-07-28 Alex Christensen <[email protected]>
+
+ WebSocket: Safari on iOS 15 beta 3 is sending invalid close frame
+ https://bugs.webkit.org/show_bug.cgi?id=228329
+
+ Reviewed by Youenn Fablet.
+
+ * TestWebKitAPI/Tests/WebKitCocoa/WebSocket.mm:
+ (TestWebKitAPI::TEST):
+
2021-07-28 Philippe Normand <[email protected]>
[WPE][GTK] SVN_REVISION drifting away if bots don't re-run cmake
Modified: trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/WebSocket.mm (280384 => 280385)
--- trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/WebSocket.mm 2021-07-28 15:55:25 UTC (rev 280384)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/WebSocket.mm 2021-07-28 15:57:49 UTC (rev 280385)
@@ -127,4 +127,89 @@
EXPECT_EQ(originalNetworkProcessPID, configuration.get().websiteDataStore._networkProcessIdentifier);
}
+#if HAVE(NSURLSESSION_WEBSOCKET)
+TEST(WebSocket, CloseCode)
+{
+ bool receivedWebSocketClose { false };
+ Vector<uint8_t> closeData;
+ HTTPServer webSocketServer([&](Connection connection) {
+ connection.webSocketHandshake([&, connection] {
+ connection.receiveBytes([&, connection](Vector<uint8_t>&& v) {
+ // https://datatracker.ietf.org/doc/html/rfc6455#section-5.2
+ constexpr uint8_t connectionCloseOpcode { 0x08 };
+ constexpr uint8_t opcodeMask { 0x08 };
+ constexpr uint8_t maskMask { 0x80 };
+ constexpr uint8_t payloadLengthMask { 0x7F };
+ constexpr uint8_t headerSize { 6 };
+ ASSERT_GT(v.size(), 1u);
+ EXPECT_EQ(v[0] & opcodeMask, connectionCloseOpcode);
+ EXPECT_TRUE(v[1] & maskMask);
+ size_t length = v[1] & payloadLengthMask;
+ ASSERT_EQ(length, v.size() - headerSize);
+ std::array<uint8_t, 4> mask { v[2], v[3], v[4], v[5] };
+ for (size_t i = headerSize; i < v.size(); i++)
+ closeData.append(v[i] ^ mask[(i - headerSize) % 4]);
+ receivedWebSocketClose = true;
+ connection.receiveBytes([](Vector<uint8_t>&& v) {
+ EXPECT_EQ(v.size(), 0u);
+ });
+ });
+ });
+ });
+
+ auto htmlWithOnOpen = [&] (const char* onopen) {
+ return [NSString stringWithFormat:@""
+ "<script>"
+ " var ws = new WebSocket('ws://127.0.0.1:%d/');"
+ " ws._onopen_ = function() { %s };"
+ "</script>", webSocketServer.port(), onopen];
+ };
+
+ HTTPServer httpServer({
+ { "/navigateAway", { htmlWithOnOpen("window.location = '/navigationTarget'") }},
+ { "/navigationTarget", { "hi" } },
+ { "/closeCustomCode", { htmlWithOnOpen("ws.close(3000)") } },
+ { "/closeNoArguments", { htmlWithOnOpen("ws.close()") } },
+ { "/closeBothParameters", { htmlWithOnOpen("ws.close(3001, 'custom reason')") } },
+ });
+
+ auto appendString = [] (Vector<uint8_t>& vector, const char* string) {
+ auto length = strlen(string);
+ for (size_t i = 0; i < length; i++)
+ vector.append(string[i]);
+ };
+
+ auto webView = adoptNS([WKWebView new]);
+ [webView loadRequest:httpServer.request("/navigateAway")];
+ [webView _test_waitForDidFinishNavigation];
+ [webView _test_waitForDidFinishNavigation];
+ Util::run(&receivedWebSocketClose);
+ Vector<uint8_t> expected { 0x3, 0xe9 }; // NSURLSessionWebSocketCloseCodeGoingAway
+ appendString(expected, "WebSocket is closed due to suspension.");
+ EXPECT_EQ(closeData, expected);
+
+ receivedWebSocketClose = false;
+ closeData = { };
+ expected = { 0xb, 0xb8 }; // 3000
+ [webView loadRequest:httpServer.request("/closeCustomCode")];
+ Util::run(&receivedWebSocketClose);
+ EXPECT_EQ(closeData, expected);
+
+ receivedWebSocketClose = false;
+ closeData = { };
+ expected = { };
+ [webView loadRequest:httpServer.request("/closeNoArguments")];
+ Util::run(&receivedWebSocketClose);
+ EXPECT_EQ(closeData, expected);
+
+ receivedWebSocketClose = false;
+ closeData = { };
+ expected = { 0xb, 0xb9 }; // 3001
+ appendString(expected, "custom reason");
+ [webView loadRequest:httpServer.request("/closeBothParameters")];
+ Util::run(&receivedWebSocketClose);
+ EXPECT_EQ(closeData, expected);
}
+#endif // HAVE(NSURLSESSION_WEBSOCKET)
+
+}