Title: [293567] trunk
Revision
293567
Author
commit-qu...@webkit.org
Date
2022-04-28 00:18:08 -0700 (Thu, 28 Apr 2022)

Log Message

IPC testing API should have the ability to test IPC::Connection send and receive through IPC::Connection
https://bugs.webkit.org/show_bug.cgi?id=239495

Patch by Kimmo Kinnunen <kkinnu...@apple.com> on 2022-04-28
Reviewed by Darin Adler.

Source/WebKit:

Add the testing interfaces to be able to send IPC::Connection instances
to other processes.
Add the testing interfaces to be able to send messages through arbitrary
IPC::Connection instances.

Test: ipc/create-connection-and-send-async.html

* CMakeLists.txt:
* DerivedSources-input.xcfilelist:
* DerivedSources-output.xcfilelist:
* DerivedSources.make:
* Platform/IPC/Connection.h:
(IPC::Connection::waitForMessageForTesting):
* Scripts/webkit/messages.py:
(types_that_cannot_be_forward_declared):
* Shared/IPCConnectionTester.cpp: Added.
(WebKit::asIdentifier):
(WebKit::IPCConnectionTester::create):
(WebKit::IPCConnectionTester::IPCConnectionTester):
(WebKit::IPCConnectionTester::initialize):
(WebKit::IPCConnectionTester::stopListeningForIPC):
(WebKit::IPCConnectionTester::sendAsyncMessages):
(WebKit::IPCConnectionTester::didClose):
(WebKit::IPCConnectionTester::didReceiveInvalidMessage):
(WebKit::IPCConnectionTester::asyncMessage):
(WebKit::IPCConnectionTester::syncMessage):
* Shared/IPCConnectionTester.h: Copied from Source/WebKit/Shared/IPCTester.h.
* Shared/IPCConnectionTester.messages.in: Copied from Source/WebKit/Shared/IPCTester.messages.in.
* Shared/IPCConnectionTesterIdentifier.h: Added.
* Shared/IPCTester.cpp:
(WebKit::IPCTester::createConnectionTester):
(WebKit::IPCTester::createConnectionTesterAndSendAsyncMessages):
(WebKit::IPCTester::releaseConnectionTester):
* Shared/IPCTester.h:
* Shared/IPCTester.messages.in:
* Sources.txt:
* WebKit.xcodeproj/project.pbxproj:
* WebProcess/WebPage/IPCTestingAPI.cpp:
(WebKit::IPCTestingAPI::JSIPCAttachment::create):
(WebKit::IPCTestingAPI::JSIPCAttachment::encode const):
(WebKit::IPCTestingAPI::JSIPCAttachment::JSIPCAttachment):
(WebKit::IPCTestingAPI::JSIPCConnection::create):
(WebKit::IPCTestingAPI::JSIPCConnection::JSIPCConnection):
(WebKit::IPCTestingAPI::createTypeError):
(WebKit::IPCTestingAPI::convertToUint64):
(WebKit::IPCTestingAPI::sendMessageWithJSArguments):
(WebKit::IPCTestingAPI::extractSyncIPCMessageInfo):
(WebKit::IPCTestingAPI::sendSyncMessageWithJSArguments):
(WebKit::IPCTestingAPI::waitForMessageWithJSArguments):
(WebKit::IPCTestingAPI::JSIPCSemaphore::createJSWrapper):
(WebKit::IPCTestingAPI::JSIPCSemaphore::wrapperClass):
(WebKit::IPCTestingAPI::JSIPCSemaphore::unwrap):
(WebKit::IPCTestingAPI::JSIPCSemaphore::toWrapped):
(WebKit::IPCTestingAPI::JSIPCSemaphore::initialize):
(WebKit::IPCTestingAPI::JSIPCSemaphore::finalize):
(WebKit::IPCTestingAPI::JSIPCSemaphore::staticFunctions):
(WebKit::IPCTestingAPI::JSIPCAttachment::createJSWrapper):
(WebKit::IPCTestingAPI::JSIPCAttachment::wrapperClass):
(WebKit::IPCTestingAPI::JSIPCAttachment::unwrap):
(WebKit::IPCTestingAPI::JSIPCAttachment::toWrapped):
(WebKit::IPCTestingAPI::JSIPCAttachment::initialize):
(WebKit::IPCTestingAPI::JSIPCAttachment::finalize):
(WebKit::IPCTestingAPI::JSIPCAttachment::staticFunctions):
(WebKit::IPCTestingAPI::JSIPCConnection::createJSWrapper):
(WebKit::IPCTestingAPI::JSIPCConnection::wrapperClass):
(WebKit::IPCTestingAPI::JSIPCConnection::unwrap):
(WebKit::IPCTestingAPI::JSIPCConnection::toWrapped):
(WebKit::IPCTestingAPI::JSIPCConnection::initialize):
(WebKit::IPCTestingAPI::JSIPCConnection::finalize):
(WebKit::IPCTestingAPI::JSIPCConnection::didReceiveMessage):
(WebKit::IPCTestingAPI::JSIPCConnection::didReceiveSyncMessage):
(WebKit::IPCTestingAPI::JSIPCConnection::didClose):
(WebKit::IPCTestingAPI::JSIPCConnection::didReceiveInvalidMessage):
(WebKit::IPCTestingAPI::JSIPCConnection::staticFunctions):
(WebKit::IPCTestingAPI::JSIPCConnection::open):
(WebKit::IPCTestingAPI::JSIPCConnection::invalidate):
(WebKit::IPCTestingAPI::JSIPCConnection::sendMessage):
(WebKit::IPCTestingAPI::JSIPCConnection::sendSyncMessage):
(WebKit::IPCTestingAPI::JSIPCConnection::waitForMessage):
(WebKit::IPCTestingAPI::JSIPCStreamClientConnection::prepareToSendOutOfStreamMessage):
(WebKit::IPCTestingAPI::JSIPC::staticFunctions):
(WebKit::IPCTestingAPI::encodeFrameInfoData):
(WebKit::IPCTestingAPI::encodeAttachment):
(WebKit::IPCTestingAPI::VectorEncodeHelper::encode const):
(WebKit::IPCTestingAPI::encodeArrayArgument):
(WebKit::IPCTestingAPI::encodeArgument):
(WebKit::IPCTestingAPI::JSIPC::sendMessage):
(WebKit::IPCTestingAPI::JSIPC::waitForMessage):
(WebKit::IPCTestingAPI::JSIPC::sendSyncMessage):
(WebKit::IPCTestingAPI::JSIPC::createConnectionPair):

Tools:

* TestWebKitAPI/Tests/WebKitCocoa/IPCTestingAPI.mm:
(TEST):
Change two tests to pass "IPC" object as the value of FrameInfoData. This way the argument encode functions
do not need to take the JSIPC argument.

LayoutTests:

* ipc/create-connection-and-send-async.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (293566 => 293567)


--- trunk/LayoutTests/ChangeLog	2022-04-28 05:36:41 UTC (rev 293566)
+++ trunk/LayoutTests/ChangeLog	2022-04-28 07:18:08 UTC (rev 293567)
@@ -1,3 +1,12 @@
+2022-04-28  Kimmo Kinnunen  <kkinnu...@apple.com>
+
+        IPC testing API should have the ability to test IPC::Connection send and receive through IPC::Connection
+        https://bugs.webkit.org/show_bug.cgi?id=239495
+
+        Reviewed by Darin Adler.
+
+        * ipc/create-connection-and-send-async.html: Added.
+
 2022-04-27  Patrick Angle  <pan...@apple.com>
 
         Web Inspector: [Flexbox] `<button>` and `<select>` elements are appearing in list of Flex containers

Added: trunk/LayoutTests/ipc/create-connection-and-send-async-expected.txt (0 => 293567)


--- trunk/LayoutTests/ipc/create-connection-and-send-async-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/ipc/create-connection-and-send-async-expected.txt	2022-04-28 07:18:08 UTC (rev 293567)
@@ -0,0 +1,4 @@
+
+PASS Sending async messages from the server immediately after opening a new connection works.
+PASS Sending async messages from the client immediately after opening the connection works.
+

Added: trunk/LayoutTests/ipc/create-connection-and-send-async.html (0 => 293567)


--- trunk/LayoutTests/ipc/create-connection-and-send-async.html	                        (rev 0)
+++ trunk/LayoutTests/ipc/create-connection-and-send-async.html	2022-04-28 07:18:08 UTC (rev 293567)
@@ -0,0 +1,72 @@
+<!doctype html><!-- webkit-test-runner [ IPCTestingAPIEnabled=true ] -->
+<title>Test that sending messages immediately after creating a new connection works.</title>
+<script src=""
+<script src=""
+<body>
+<script>
+const defaultTimeout = 1000;
+
+promise_test(async t => {
+    if (!window.IPC)
+        return;
+    const testerID = 447;
+    for (const processTarget of IPC.processTargets) {
+        // Test starts here.
+        const [connection, clientConnectionIdentifier] = IPC.createConnectionPair();
+        connection.open();
+        const msgs = [];
+        const numMessages = 10000;
+        for (let v = 0; v < numMessages; v++)
+            msgs.push([{ type: 'uint32_t', value: v + 1}]);
+        let msgName = IPC.messages.IPCConnectionTester_AsyncMessage.name;
+
+        IPC.sendMessage(processTarget, 0, IPC.messages.IPCTester_CreateConnectionTester.name, [
+            { type: 'uint64_t', value: testerID },
+            { type: 'Attachment', value: clientConnectionIdentifier },
+        ]);
+        try {
+            for (let msg of msgs)
+                connection.sendMessage(0, msgName, msg);
+            const reply = connection.sendSyncMessage(0, IPC.messages.IPCConnectionTester_SyncMessage.name, defaultTimeout, [{ type: 'uint32_t', value: 55 }]);
+            const firstResult = reply.arguments[0];
+            assert_equals(firstResult.type, "uint32_t", `for ${ processTarget }`);
+            assert_equals(firstResult.value, 55 + numMessages, `for ${ processTarget }`);
+        } finally {
+            connection.invalidate();
+            IPC.sendSyncMessage(processTarget, 0, IPC.messages.IPCTester_ReleaseConnectionTester.name, defaultTimeout, [{ type: 'uint64_t', value: testerID }]);
+        }
+    }
+}, "Sending async messages from the server immediately after opening a new connection works.");
+
+promise_test(async t => {
+    if (!window.IPC)
+        return;
+    const testerID = 448;
+    for (const processTarget of IPC.processTargets) {
+        // Test starts here.
+        const connectionCount = 5; // FIXME: should be 100, but waiting for messages is slow.
+        for (let i = 0; i < connectionCount; ++i) {
+            const [connection, clientConnectionIdentifier] = IPC.createConnectionPair();
+            connection.open();
+            const messageCount = 3; // FIXME: should be 10000, but waiting for messages is slow.
+            IPC.sendMessage(processTarget, 0, IPC.messages.IPCTester_CreateConnectionTesterAndSendAsyncMessages.name, [
+                { type: 'uint64_t', value: testerID },
+                { type: 'Attachment', value: clientConnectionIdentifier },
+                { type: 'uint32_t', value: messageCount },
+            ]);
+            try {
+                for (let v = 0; v < messageCount; v++) {
+                    const msg = connection.waitForMessage(0, IPC.messages.IPCConnectionTester_AsyncMessage.name, defaultTimeout);
+                    assert_equals(msg[0].type, "uint32_t", `for ${ processTarget }`);
+                    assert_equals(msg[0].value, v, `for ${ processTarget }`);
+
+                }
+            } finally {
+                connection.invalidate();
+                IPC.sendSyncMessage(processTarget, 0, IPC.messages.IPCTester_ReleaseConnectionTester.name, defaultTimeout, [{ type: 'uint64_t', value: testerID }]);
+            }
+        }
+    }
+}, "Sending async messages from the client immediately after opening the connection works.");
+</script>
+</body>
\ No newline at end of file

Modified: trunk/Source/WebKit/CMakeLists.txt (293566 => 293567)


--- trunk/Source/WebKit/CMakeLists.txt	2022-04-28 05:36:41 UTC (rev 293566)
+++ trunk/Source/WebKit/CMakeLists.txt	2022-04-28 07:18:08 UTC (rev 293567)
@@ -215,6 +215,7 @@
     NetworkProcess/webrtc/RTCDataChannelRemoteManagerProxy
 
     Shared/AuxiliaryProcess
+    Shared/IPCConnectionTester
     Shared/IPCStreamTester
     Shared/IPCStreamTesterProxy
     Shared/IPCTester

Modified: trunk/Source/WebKit/ChangeLog (293566 => 293567)


--- trunk/Source/WebKit/ChangeLog	2022-04-28 05:36:41 UTC (rev 293566)
+++ trunk/Source/WebKit/ChangeLog	2022-04-28 07:18:08 UTC (rev 293567)
@@ -1,3 +1,101 @@
+2022-04-28  Kimmo Kinnunen  <kkinnu...@apple.com>
+
+        IPC testing API should have the ability to test IPC::Connection send and receive through IPC::Connection
+        https://bugs.webkit.org/show_bug.cgi?id=239495
+
+        Reviewed by Darin Adler.
+
+        Add the testing interfaces to be able to send IPC::Connection instances
+        to other processes.
+        Add the testing interfaces to be able to send messages through arbitrary
+        IPC::Connection instances.
+
+        Test: ipc/create-connection-and-send-async.html
+
+        * CMakeLists.txt:
+        * DerivedSources-input.xcfilelist:
+        * DerivedSources-output.xcfilelist:
+        * DerivedSources.make:
+        * Platform/IPC/Connection.h:
+        (IPC::Connection::waitForMessageForTesting):
+        * Scripts/webkit/messages.py:
+        (types_that_cannot_be_forward_declared):
+        * Shared/IPCConnectionTester.cpp: Added.
+        (WebKit::asIdentifier):
+        (WebKit::IPCConnectionTester::create):
+        (WebKit::IPCConnectionTester::IPCConnectionTester):
+        (WebKit::IPCConnectionTester::initialize):
+        (WebKit::IPCConnectionTester::stopListeningForIPC):
+        (WebKit::IPCConnectionTester::sendAsyncMessages):
+        (WebKit::IPCConnectionTester::didClose):
+        (WebKit::IPCConnectionTester::didReceiveInvalidMessage):
+        (WebKit::IPCConnectionTester::asyncMessage):
+        (WebKit::IPCConnectionTester::syncMessage):
+        * Shared/IPCConnectionTester.h: Copied from Source/WebKit/Shared/IPCTester.h.
+        * Shared/IPCConnectionTester.messages.in: Copied from Source/WebKit/Shared/IPCTester.messages.in.
+        * Shared/IPCConnectionTesterIdentifier.h: Added.
+        * Shared/IPCTester.cpp:
+        (WebKit::IPCTester::createConnectionTester):
+        (WebKit::IPCTester::createConnectionTesterAndSendAsyncMessages):
+        (WebKit::IPCTester::releaseConnectionTester):
+        * Shared/IPCTester.h:
+        * Shared/IPCTester.messages.in:
+        * Sources.txt:
+        * WebKit.xcodeproj/project.pbxproj:
+        * WebProcess/WebPage/IPCTestingAPI.cpp:
+        (WebKit::IPCTestingAPI::JSIPCAttachment::create):
+        (WebKit::IPCTestingAPI::JSIPCAttachment::encode const):
+        (WebKit::IPCTestingAPI::JSIPCAttachment::JSIPCAttachment):
+        (WebKit::IPCTestingAPI::JSIPCConnection::create):
+        (WebKit::IPCTestingAPI::JSIPCConnection::JSIPCConnection):
+        (WebKit::IPCTestingAPI::createTypeError):
+        (WebKit::IPCTestingAPI::convertToUint64):
+        (WebKit::IPCTestingAPI::sendMessageWithJSArguments):
+        (WebKit::IPCTestingAPI::extractSyncIPCMessageInfo):
+        (WebKit::IPCTestingAPI::sendSyncMessageWithJSArguments):
+        (WebKit::IPCTestingAPI::waitForMessageWithJSArguments):
+        (WebKit::IPCTestingAPI::JSIPCSemaphore::createJSWrapper):
+        (WebKit::IPCTestingAPI::JSIPCSemaphore::wrapperClass):
+        (WebKit::IPCTestingAPI::JSIPCSemaphore::unwrap):
+        (WebKit::IPCTestingAPI::JSIPCSemaphore::toWrapped):
+        (WebKit::IPCTestingAPI::JSIPCSemaphore::initialize):
+        (WebKit::IPCTestingAPI::JSIPCSemaphore::finalize):
+        (WebKit::IPCTestingAPI::JSIPCSemaphore::staticFunctions):
+        (WebKit::IPCTestingAPI::JSIPCAttachment::createJSWrapper):
+        (WebKit::IPCTestingAPI::JSIPCAttachment::wrapperClass):
+        (WebKit::IPCTestingAPI::JSIPCAttachment::unwrap):
+        (WebKit::IPCTestingAPI::JSIPCAttachment::toWrapped):
+        (WebKit::IPCTestingAPI::JSIPCAttachment::initialize):
+        (WebKit::IPCTestingAPI::JSIPCAttachment::finalize):
+        (WebKit::IPCTestingAPI::JSIPCAttachment::staticFunctions):
+        (WebKit::IPCTestingAPI::JSIPCConnection::createJSWrapper):
+        (WebKit::IPCTestingAPI::JSIPCConnection::wrapperClass):
+        (WebKit::IPCTestingAPI::JSIPCConnection::unwrap):
+        (WebKit::IPCTestingAPI::JSIPCConnection::toWrapped):
+        (WebKit::IPCTestingAPI::JSIPCConnection::initialize):
+        (WebKit::IPCTestingAPI::JSIPCConnection::finalize):
+        (WebKit::IPCTestingAPI::JSIPCConnection::didReceiveMessage):
+        (WebKit::IPCTestingAPI::JSIPCConnection::didReceiveSyncMessage):
+        (WebKit::IPCTestingAPI::JSIPCConnection::didClose):
+        (WebKit::IPCTestingAPI::JSIPCConnection::didReceiveInvalidMessage):
+        (WebKit::IPCTestingAPI::JSIPCConnection::staticFunctions):
+        (WebKit::IPCTestingAPI::JSIPCConnection::open):
+        (WebKit::IPCTestingAPI::JSIPCConnection::invalidate):
+        (WebKit::IPCTestingAPI::JSIPCConnection::sendMessage):
+        (WebKit::IPCTestingAPI::JSIPCConnection::sendSyncMessage):
+        (WebKit::IPCTestingAPI::JSIPCConnection::waitForMessage):
+        (WebKit::IPCTestingAPI::JSIPCStreamClientConnection::prepareToSendOutOfStreamMessage):
+        (WebKit::IPCTestingAPI::JSIPC::staticFunctions):
+        (WebKit::IPCTestingAPI::encodeFrameInfoData):
+        (WebKit::IPCTestingAPI::encodeAttachment):
+        (WebKit::IPCTestingAPI::VectorEncodeHelper::encode const):
+        (WebKit::IPCTestingAPI::encodeArrayArgument):
+        (WebKit::IPCTestingAPI::encodeArgument):
+        (WebKit::IPCTestingAPI::JSIPC::sendMessage):
+        (WebKit::IPCTestingAPI::JSIPC::waitForMessage):
+        (WebKit::IPCTestingAPI::JSIPC::sendSyncMessage):
+        (WebKit::IPCTestingAPI::JSIPC::createConnectionPair):
+
 2022-04-27  Wenson Hsieh  <wenson_hs...@apple.com>
 
         [iOS] Add a mechanism to override desktop-class browsing state in multitasking mode

Modified: trunk/Source/WebKit/DerivedSources-input.xcfilelist (293566 => 293567)


--- trunk/Source/WebKit/DerivedSources-input.xcfilelist	2022-04-28 05:36:41 UTC (rev 293566)
+++ trunk/Source/WebKit/DerivedSources-input.xcfilelist	2022-04-28 07:18:08 UTC (rev 293567)
@@ -129,6 +129,7 @@
 $(PROJECT_DIR)/Shared/Authentication/AuthenticationManager.messages.in
 $(PROJECT_DIR)/Shared/AuxiliaryProcess.messages.in
 $(PROJECT_DIR)/Shared/HTTPSUpgrade/HTTPSUpgradeList.txt
+$(PROJECT_DIR)/Shared/IPCConnectionTester.messages.in
 $(PROJECT_DIR)/Shared/IPCStreamTester.messages.in
 $(PROJECT_DIR)/Shared/IPCStreamTesterProxy.messages.in
 $(PROJECT_DIR)/Shared/IPCTester.messages.in

Modified: trunk/Source/WebKit/DerivedSources-output.xcfilelist (293566 => 293567)


--- trunk/Source/WebKit/DerivedSources-output.xcfilelist	2022-04-28 05:36:41 UTC (rev 293566)
+++ trunk/Source/WebKit/DerivedSources-output.xcfilelist	2022-04-28 07:18:08 UTC (rev 293567)
@@ -46,6 +46,9 @@
 $(BUILT_PRODUCTS_DIR)/DerivedSources/WebKit/GPUProcessProxyMessageReceiver.cpp
 $(BUILT_PRODUCTS_DIR)/DerivedSources/WebKit/GPUProcessProxyMessages.h
 $(BUILT_PRODUCTS_DIR)/DerivedSources/WebKit/GPUProcessProxyMessagesReplies.h
+$(BUILT_PRODUCTS_DIR)/DerivedSources/WebKit/IPCConnectionTesterMessageReceiver.cpp
+$(BUILT_PRODUCTS_DIR)/DerivedSources/WebKit/IPCConnectionTesterMessages.h
+$(BUILT_PRODUCTS_DIR)/DerivedSources/WebKit/IPCConnectionTesterMessagesReplies.h
 $(BUILT_PRODUCTS_DIR)/DerivedSources/WebKit/IPCStreamTesterMessageReceiver.cpp
 $(BUILT_PRODUCTS_DIR)/DerivedSources/WebKit/IPCStreamTesterMessages.h
 $(BUILT_PRODUCTS_DIR)/DerivedSources/WebKit/IPCStreamTesterMessagesReplies.h

Modified: trunk/Source/WebKit/DerivedSources.make (293566 => 293567)


--- trunk/Source/WebKit/DerivedSources.make	2022-04-28 05:36:41 UTC (rev 293566)
+++ trunk/Source/WebKit/DerivedSources.make	2022-04-28 07:18:08 UTC (rev 293567)
@@ -149,6 +149,7 @@
 	Shared/Authentication/AuthenticationManager \
 	Shared/Notifications/NotificationManagerMessageHandler \
 	Shared/WebConnection \
+	Shared/IPCConnectionTester \
 	Shared/IPCStreamTester \
 	Shared/IPCStreamTesterProxy \
 	Shared/IPCTester \

Modified: trunk/Source/WebKit/Platform/IPC/Connection.h (293566 => 293567)


--- trunk/Source/WebKit/Platform/IPC/Connection.h	2022-04-28 05:36:41 UTC (rev 293566)
+++ trunk/Source/WebKit/Platform/IPC/Connection.h	2022-04-28 07:18:08 UTC (rev 293567)
@@ -57,11 +57,6 @@
 #include <wtf/glib/GSocketMonitor.h>
 #endif
 
-namespace WebKit {
-namespace IPCTestingAPI {
-class JSIPC;
-}
-}
 
 namespace IPC {
 
@@ -333,6 +328,7 @@
     void setIgnoreInvalidMessageForTesting() { m_ignoreInvalidMessageForTesting = true; }
     bool ignoreInvalidMessageForTesting() const { return m_ignoreInvalidMessageForTesting; }
     void dispatchIncomingMessageForTesting(std::unique_ptr<Decoder>&&);
+    std::unique_ptr<Decoder> waitForMessageForTesting(MessageName, uint64_t destinationID, Timeout, OptionSet<WaitForOption>);
 #endif
 
     void dispatchMessageReceiverMessage(MessageReceiver&, std::unique_ptr<Decoder>&&);
@@ -524,7 +520,6 @@
     HANDLE m_connectionPipe { INVALID_HANDLE_VALUE };
 #endif
     friend class StreamClientConnection;
-    friend class WebKit::IPCTestingAPI::JSIPC;
 };
 
 template<typename T>
@@ -657,6 +652,14 @@
     return true;
 }
 
+#if ENABLE(IPC_TESTING_API)
+inline std::unique_ptr<Decoder> Connection::waitForMessageForTesting(MessageName messageName, uint64_t destinationID, Timeout timeout, OptionSet<WaitForOption> options)
+{
+    return waitForMessage(messageName, destinationID, timeout, options);
+}
+#endif
+
+
 class UnboundedSynchronousIPCScope {
 public:
     UnboundedSynchronousIPCScope()

Modified: trunk/Source/WebKit/Scripts/webkit/messages.py (293566 => 293567)


--- trunk/Source/WebKit/Scripts/webkit/messages.py	2022-04-28 05:36:41 UTC (rev 293566)
+++ trunk/Source/WebKit/Scripts/webkit/messages.py	2022-04-28 07:18:08 UTC (rev 293567)
@@ -324,6 +324,7 @@
         'WebKit::GeolocationIdentifier',
         'WebKit::GraphicsContextGLIdentifier',
         'WebKit::ImageBufferBackendHandle',
+        'WebKit::IPCConnectionTesterIdentifier',
         'WebKit::IPCStreamTesterIdentifier',
         'WebKit::LayerHostingContextID',
         'WebKit::LegacyCustomProtocolID',

Added: trunk/Source/WebKit/Shared/IPCConnectionTester.cpp (0 => 293567)


--- trunk/Source/WebKit/Shared/IPCConnectionTester.cpp	                        (rev 0)
+++ trunk/Source/WebKit/Shared/IPCConnectionTester.cpp	2022-04-28 07:18:08 UTC (rev 293567)
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2022 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "IPCConnectionTester.h"
+
+#if ENABLE(IPC_TESTING_API)
+#include "IPCConnectionTesterMessages.h"
+#include "IPCTester.h"
+
+namespace WebKit {
+
+// FIXME(https://webkit.org/b/239487): These ifdefs are error prone, duplicated and the lack of move semantics causes leaks.
+static IPC::Connection::Identifier asIdentifier(IPC::Attachment&& connectionIdentifier)
+{
+#if USE(UNIX_DOMAIN_SOCKETS)
+    return { connectionIdentifier.release().release() };
+#elif OS(DARWIN)
+    return { connectionIdentifier.port() };
+#elif OS(WINDOWS)
+    return { connectionIdentifier.handle() };
+#else
+    notImplemented();
+    return { };
+#endif
+}
+
+Ref<IPCConnectionTester> IPCConnectionTester::create(IPC::Connection& connection, IPCConnectionTesterIdentifier identifier, IPC::Attachment&& testedConnectionIdentifier)
+{
+    auto tester = adoptRef(*new IPCConnectionTester(connection, identifier, WTFMove(testedConnectionIdentifier)));
+    tester->initialize();
+    return tester;
+}
+
+IPCConnectionTester::IPCConnectionTester(Ref<IPC::Connection>&& connection, IPCConnectionTesterIdentifier identifier, IPC::Attachment&& testedConnectionIdentifier)
+    : m_connection(WTFMove(connection))
+    , m_testedConnection(IPC::Connection::createClientConnection(asIdentifier(WTFMove(testedConnectionIdentifier)), *this))
+    , m_identifier(identifier)
+{
+}
+
+IPCConnectionTester::~IPCConnectionTester() = default;
+
+void IPCConnectionTester::initialize()
+{
+    m_testedConnection->open();
+}
+
+void IPCConnectionTester::stopListeningForIPC(Ref<IPCConnectionTester>&& refFromConnection)
+{
+    m_testedConnection->invalidate();
+}
+
+void IPCConnectionTester::sendAsyncMessages(uint32_t messageCount)
+{
+    for (uint32_t i = 0; i < messageCount; ++i)
+        m_testedConnection->send(Messages::IPCConnectionTester::AsyncMessage(i), 0);
+}
+
+void IPCConnectionTester::didClose(IPC::Connection&)
+{
+}
+
+void IPCConnectionTester::didReceiveInvalidMessage(IPC::Connection&, IPC::MessageName)
+{
+    ASSERT_NOT_REACHED();
+}
+
+void IPCConnectionTester::asyncMessage(uint32_t value)
+{
+    if (m_previousAsyncMessageValue != value - 1) {
+        ASSERT_IS_TESTING_IPC();
+        return;
+    }
+    m_previousAsyncMessageValue = value;
+}
+
+void IPCConnectionTester::syncMessage(uint32_t value, CompletionHandler<void(uint32_t)>&& completionHandler)
+{
+    completionHandler(value + m_previousAsyncMessageValue);
+}
+
+}
+
+#endif

Added: trunk/Source/WebKit/Shared/IPCConnectionTester.h (0 => 293567)


--- trunk/Source/WebKit/Shared/IPCConnectionTester.h	                        (rev 0)
+++ trunk/Source/WebKit/Shared/IPCConnectionTester.h	2022-04-28 07:18:08 UTC (rev 293567)
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2022 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(IPC_TESTING_API)
+
+#include "Connection.h"
+#include "IPCConnectionTesterIdentifier.h"
+#include "MessageReceiver.h"
+#include <optional>
+#include <wtf/HashMap.h>
+
+namespace IPC {
+class Connection;
+}
+
+namespace WebKit {
+
+// Interface to test various IPC::Connection related activities.
+class IPCConnectionTester final : public RefCounted<IPCConnectionTester>, private IPC::Connection::Client {
+public:
+    ~IPCConnectionTester();
+    static Ref<IPCConnectionTester> create(IPC::Connection&, IPCConnectionTesterIdentifier, IPC::Attachment&& testedConnectionIdentifier);
+    void stopListeningForIPC(Ref<IPCConnectionTester>&& refFromConnection);
+
+    void sendAsyncMessages(uint32_t messageCount);
+private:
+    IPCConnectionTester(Ref<IPC::Connection>&&, IPCConnectionTesterIdentifier, IPC::Attachment&& testedConnectionIdentifier);
+    void initialize();
+
+    // IPC::Connection::Client overrides.
+    void didReceiveMessage(IPC::Connection&, IPC::Decoder&) final;
+    bool didReceiveSyncMessage(IPC::Connection&, IPC::Decoder&, UniqueRef<IPC::Encoder>&) final;
+    void didClose(IPC::Connection&) final;
+    void didReceiveInvalidMessage(IPC::Connection&, IPC::MessageName) final;
+
+    // Messages.
+    void asyncMessage(uint32_t value);
+    void syncMessage(uint32_t value, CompletionHandler<void(uint32_t sameValue)>&&);
+
+    const Ref<IPC::Connection> m_connection;
+    const Ref<IPC::Connection> m_testedConnection;
+    const IPCConnectionTesterIdentifier m_identifier;
+    uint32_t m_previousAsyncMessageValue { 0 };
+};
+
+}
+
+#endif

Copied: trunk/Source/WebKit/Shared/IPCConnectionTester.messages.in (from rev 293566, trunk/Source/WebKit/Shared/IPCTester.messages.in) (0 => 293567)


--- trunk/Source/WebKit/Shared/IPCConnectionTester.messages.in	                        (rev 0)
+++ trunk/Source/WebKit/Shared/IPCConnectionTester.messages.in	2022-04-28 07:18:08 UTC (rev 293567)
@@ -0,0 +1,30 @@
+# Copyright (C) 2022 Apple Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1.  Redistributions of source code must retain the above copyright
+#     notice, this list of conditions and the following disclaimer.
+# 2.  Redistributions in binary form must reproduce the above copyright
+#     notice, this list of conditions and the following disclaimer in the
+#     documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR
+# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#if ENABLE(IPC_TESTING_API)
+
+messages -> IPCConnectionTester NotRefCounted {
+    AsyncMessage(uint32_t value)
+    SyncMessage(uint32_t value) -> (uint32_t sameValue) Synchronous
+}
+
+#endif

Added: trunk/Source/WebKit/Shared/IPCConnectionTesterIdentifier.h (0 => 293567)


--- trunk/Source/WebKit/Shared/IPCConnectionTesterIdentifier.h	                        (rev 0)
+++ trunk/Source/WebKit/Shared/IPCConnectionTesterIdentifier.h	2022-04-28 07:18:08 UTC (rev 293567)
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(IPC_TESTING_API)
+
+#include <wtf/ObjectIdentifier.h>
+
+namespace WebKit {
+
+enum IPCConnectionTesterIdentifierType { };
+using IPCConnectionTesterIdentifier = ObjectIdentifier<IPCConnectionTesterIdentifierType>;
+
+}
+
+#endif

Modified: trunk/Source/WebKit/Shared/IPCTester.cpp (293566 => 293567)


--- trunk/Source/WebKit/Shared/IPCTester.cpp	2022-04-28 05:36:41 UTC (rev 293566)
+++ trunk/Source/WebKit/Shared/IPCTester.cpp	2022-04-28 07:18:08 UTC (rev 293567)
@@ -29,6 +29,7 @@
 #if ENABLE(IPC_TESTING_API)
 #include "Connection.h"
 #include "Decoder.h"
+#include "IPCConnectionTester.h"
 #include "IPCStreamTester.h"
 #include "IPCTesterMessages.h"
 
@@ -168,6 +169,32 @@
     }
 }
 
+void IPCTester::createConnectionTester(IPC::Connection& connection, IPCConnectionTesterIdentifier identifier, IPC::Attachment&& testedConnectionIdentifier)
+{
+    auto addResult = m_connectionTesters.ensure(identifier, [&] {
+        return IPC::ScopedActiveMessageReceiveQueue<IPCConnectionTester> { IPCConnectionTester::create(connection, identifier, WTFMove(testedConnectionIdentifier)) };
+    });
+    ASSERT_UNUSED(addResult, addResult.isNewEntry || isTestingIPC());
+}
+
+void IPCTester::createConnectionTesterAndSendAsyncMessages(IPC::Connection& connection, IPCConnectionTesterIdentifier identifier, IPC::Attachment&& testedConnectionIdentifier, uint32_t messageCount)
+{
+    auto addResult = m_connectionTesters.ensure(identifier, [&] {
+        return IPC::ScopedActiveMessageReceiveQueue<IPCConnectionTester> { IPCConnectionTester::create(connection, identifier, WTFMove(testedConnectionIdentifier)) };
+    });
+    if (!addResult.isNewEntry) {
+        ASSERT_IS_TESTING_IPC();
+        return;
+    }
+    addResult.iterator->value->sendAsyncMessages(messageCount);
+}
+
+void IPCTester::releaseConnectionTester(IPCConnectionTesterIdentifier identifier, CompletionHandler<void()>&& completionHandler)
+{
+    m_connectionTesters.remove(identifier);
+    completionHandler();
+}
+
 void IPCTester::stopIfNeeded()
 {
     if (m_testQueue) {

Modified: trunk/Source/WebKit/Shared/IPCTester.h (293566 => 293567)


--- trunk/Source/WebKit/Shared/IPCTester.h	2022-04-28 05:36:41 UTC (rev 293566)
+++ trunk/Source/WebKit/Shared/IPCTester.h	2022-04-28 07:18:08 UTC (rev 293567)
@@ -28,6 +28,7 @@
 
 #if ENABLE(IPC_TESTING_API)
 
+#include "IPCConnectionTesterIdentifier.h"
 #include "IPCStreamTesterIdentifier.h"
 #include "MessageReceiver.h"
 #include "ScopedActiveMessageReceiveQueue.h"
@@ -52,6 +53,7 @@
 // and exposes bugs underneath.
 bool isTestingIPC();
 
+class IPCConnectionTester;
 class IPCStreamTester;
 
 // Main test interface for initiating various IPC test activities.
@@ -69,6 +71,9 @@
     void stopMessageTesting(CompletionHandler<void()>);
     void createStreamTester(IPC::Connection&, IPCStreamTesterIdentifier, IPC::StreamConnectionBuffer&&);
     void releaseStreamTester(IPCStreamTesterIdentifier, CompletionHandler<void()>&&);
+    void createConnectionTester(IPC::Connection&, IPCConnectionTesterIdentifier, IPC::Attachment&&);
+    void createConnectionTesterAndSendAsyncMessages(IPC::Connection&, IPCConnectionTesterIdentifier, IPC::Attachment&&, uint32_t messageCount);
+    void releaseConnectionTester(IPCConnectionTesterIdentifier, CompletionHandler<void()>&&);
     void sendSameSemaphoreBack(IPC::Connection&, IPC::Semaphore&&);
     void sendSemaphoreBackAndSignalProtocol(IPC::Connection&, IPC::Semaphore&&);
 
@@ -79,6 +84,9 @@
 
     using StreamTesterMap = HashMap<IPCStreamTesterIdentifier, IPC::ScopedActiveMessageReceiveQueue<IPCStreamTester>>;
     StreamTesterMap m_streamTesters;
+
+    using ConnectionTesterMap = HashMap<IPCConnectionTesterIdentifier, IPC::ScopedActiveMessageReceiveQueue<IPCConnectionTester>>;
+    ConnectionTesterMap m_connectionTesters;
 };
 
 #else

Modified: trunk/Source/WebKit/Shared/IPCTester.messages.in (293566 => 293567)


--- trunk/Source/WebKit/Shared/IPCTester.messages.in	2022-04-28 05:36:41 UTC (rev 293566)
+++ trunk/Source/WebKit/Shared/IPCTester.messages.in	2022-04-28 07:18:08 UTC (rev 293567)
@@ -27,6 +27,9 @@
     StopMessageTesting() -> () Synchronous
     CreateStreamTester(WebKit::IPCStreamTesterIdentifier identifier, IPC::StreamConnectionBuffer stream) WantsConnection
     ReleaseStreamTester(WebKit::IPCStreamTesterIdentifier identifier) -> () Synchronous
+    CreateConnectionTester(WebKit::IPCConnectionTesterIdentifier ideœntifier, IPC::Attachment connection) WantsConnection
+    CreateConnectionTesterAndSendAsyncMessages(WebKit::IPCConnectionTesterIdentifier identifier, IPC::Attachment connection, uint32_t messageCount) WantsConnection
+    ReleaseConnectionTester(WebKit::IPCConnectionTesterIdentifier identifier) -> () Synchronous
 
     SendSameSemaphoreBack(IPC::Semaphore semaphore) WantsConnection
     SendSemaphoreBackAndSignalProtocol(IPC::Semaphore semaphore) WantsConnection

Modified: trunk/Source/WebKit/Sources.txt (293566 => 293567)


--- trunk/Source/WebKit/Sources.txt	2022-04-28 05:36:41 UTC (rev 293566)
+++ trunk/Source/WebKit/Sources.txt	2022-04-28 07:18:08 UTC (rev 293567)
@@ -227,6 +227,7 @@
 Shared/FontInfo.cpp
 Shared/FrameInfoData.cpp
 Shared/InspectorExtensionTypes.cpp
+Shared/IPCConnectionTester.cpp
 Shared/IPCStreamTester.cpp
 Shared/IPCTester.cpp
 Shared/LayerTreeContext.cpp
@@ -868,6 +869,7 @@
 
 WebProcess/XR/PlatformXRSystemProxy.cpp
 
+IPCConnectionTesterMessageReceiver.cpp
 IPCStreamTesterMessageReceiver.cpp
 IPCStreamTesterProxyMessageReceiver.cpp
 IPCTesterMessageReceiver.cpp

Modified: trunk/Source/WebKit/WebKit.xcodeproj/project.pbxproj (293566 => 293567)


--- trunk/Source/WebKit/WebKit.xcodeproj/project.pbxproj	2022-04-28 05:36:41 UTC (rev 293566)
+++ trunk/Source/WebKit/WebKit.xcodeproj/project.pbxproj	2022-04-28 07:18:08 UTC (rev 293567)
@@ -1351,6 +1351,8 @@
 		7B73124125CC8525003B2796 /* StreamServerConnection.h in Headers */ = {isa = PBXBuildFile; fileRef = 7B73123825CC8524003B2796 /* StreamServerConnection.h */; };
 		7B73124225CC8525003B2796 /* StreamConnectionEncoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 7B73123925CC8525003B2796 /* StreamConnectionEncoder.h */; };
 		7BAB111025DD02B3008FC479 /* ScopedActiveMessageReceiveQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 7BAB110F25DD02B2008FC479 /* ScopedActiveMessageReceiveQueue.h */; };
+		7BBA63DF280E93D200B04823 /* IPCConnectionTesterIdentifier.h in Headers */ = {isa = PBXBuildFile; fileRef = 7BBA63DC280E93B500B04823 /* IPCConnectionTesterIdentifier.h */; };
+		7BBA63E0280E93D600B04823 /* IPCConnectionTester.h in Headers */ = {isa = PBXBuildFile; fileRef = 7BBA63DE280E93B600B04823 /* IPCConnectionTester.h */; };
 		7BCF70DE2615D06E00E4FB70 /* ScopedRenderingResourcesRequestCocoa.mm in Sources */ = {isa = PBXBuildFile; fileRef = 7BCF70CB2614935E00E4FB70 /* ScopedRenderingResourcesRequestCocoa.mm */; };
 		7BE37F9327C7CA51007A6CD3 /* IPCStreamTesterIdentifier.h in Headers */ = {isa = PBXBuildFile; fileRef = 7BE37F9227C7C518007A6CD3 /* IPCStreamTesterIdentifier.h */; };
 		7BE9326327F5C75A00D5FEFB /* ReceiverMatcher.h in Headers */ = {isa = PBXBuildFile; fileRef = 7BE9326227F5C75A00D5FEFB /* ReceiverMatcher.h */; };
@@ -5535,6 +5537,9 @@
 		7B90416A254AFEA7006EEB8C /* RemoteGraphicsContextGL.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RemoteGraphicsContextGL.h; sourceTree = "<group>"; };
 		7B90416D2550108C006EEB8C /* RemoteGraphicsContextGLFunctionsGenerated.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RemoteGraphicsContextGLFunctionsGenerated.h; sourceTree = "<group>"; };
 		7BAB110F25DD02B2008FC479 /* ScopedActiveMessageReceiveQueue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ScopedActiveMessageReceiveQueue.h; sourceTree = "<group>"; };
+		7BBA63DC280E93B500B04823 /* IPCConnectionTesterIdentifier.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IPCConnectionTesterIdentifier.h; sourceTree = "<group>"; };
+		7BBA63DD280E93B600B04823 /* IPCConnectionTester.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = IPCConnectionTester.cpp; sourceTree = "<group>"; };
+		7BBA63DE280E93B600B04823 /* IPCConnectionTester.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IPCConnectionTester.h; sourceTree = "<group>"; };
 		7BCF70CA2614935E00E4FB70 /* ScopedRenderingResourcesRequest.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = ScopedRenderingResourcesRequest.cpp; sourceTree = "<group>"; };
 		7BCF70CB2614935E00E4FB70 /* ScopedRenderingResourcesRequestCocoa.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = ScopedRenderingResourcesRequestCocoa.mm; sourceTree = "<group>"; };
 		7BCF70CC2614935F00E4FB70 /* ScopedWebGLRenderingResourcesRequest.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = ScopedWebGLRenderingResourcesRequest.cpp; sourceTree = "<group>"; };
@@ -7939,6 +7944,9 @@
 				BCCF6B2312C93E7A008F9C35 /* ImageOptions.h */,
 				999B7ED82550E4A800F450A4 /* InspectorExtensionTypes.cpp */,
 				99BE3B1625433B9400C6551C /* InspectorExtensionTypes.h */,
+				7BBA63DD280E93B600B04823 /* IPCConnectionTester.cpp */,
+				7BBA63DE280E93B600B04823 /* IPCConnectionTester.h */,
+				7BBA63DC280E93B500B04823 /* IPCConnectionTesterIdentifier.h */,
 				7BE37F9527C7CD90007A6CD3 /* IPCStreamTester.cpp */,
 				7BE37F9427C7CD51007A6CD3 /* IPCStreamTester.h */,
 				7BE37F9227C7C518007A6CD3 /* IPCStreamTesterIdentifier.h */,
@@ -14337,6 +14345,8 @@
 				51E9049C27BCB9D400929E7E /* InstallCoordinationSPI.h in Headers */,
 				C5BCE5DF1C50766A00CDE3FA /* InteractionInformationAtPosition.h in Headers */,
 				2D4D2C811DF60BF3002EB10C /* InteractionInformationRequest.h in Headers */,
+				7BBA63E0280E93D600B04823 /* IPCConnectionTester.h in Headers */,
+				7BBA63DF280E93D200B04823 /* IPCConnectionTesterIdentifier.h in Headers */,
 				A31F60A425CC7DB900AF14F4 /* IPCSemaphore.h in Headers */,
 				7BE37F9327C7CA51007A6CD3 /* IPCStreamTesterIdentifier.h in Headers */,
 				9B47908F253151CC00EC11AB /* JSIPCBinding.h in Headers */,

Modified: trunk/Source/WebKit/WebProcess/WebPage/IPCTestingAPI.cpp (293566 => 293567)


--- trunk/Source/WebKit/WebProcess/WebPage/IPCTestingAPI.cpp	2022-04-28 05:36:41 UTC (rev 293566)
+++ trunk/Source/WebKit/WebProcess/WebPage/IPCTestingAPI.cpp	2022-04-28 07:18:08 UTC (rev 293567)
@@ -61,6 +61,8 @@
 
 namespace IPCTestingAPI {
 
+class JSIPC;
+
 static constexpr auto processTargetNameUI = "UI"_s;
 #if ENABLE(GPU_PROCESS)
 static constexpr auto processTargetNameGPU = "GPU"_s;
@@ -70,7 +72,7 @@
 static std::optional<uint64_t> destinationIDFromArgument(JSC::JSGlobalObject*, JSValueRef, JSValueRef*);
 static std::optional<uint64_t> messageIDFromArgument(JSC::JSGlobalObject*, JSValueRef, JSValueRef*);
 static JSC::JSObject* jsResultFromReplyDecoder(JSC::JSGlobalObject*, IPC::MessageName, IPC::Decoder&);
-static bool encodeArgument(IPC::Encoder&, JSIPC&, JSContextRef, JSValueRef, JSValueRef* exception);
+static bool encodeArgument(IPC::Encoder&, JSContextRef, JSValueRef, JSValueRef* exception);
 
 class JSIPCSemaphore : public RefCounted<JSIPCSemaphore> {
 public:
@@ -106,6 +108,71 @@
     IPC::Semaphore m_semaphore;
 };
 
+class JSIPCAttachment : public RefCounted<JSIPCAttachment> {
+public:
+    static Ref<JSIPCAttachment> create(IPC::Attachment&& attachment)
+    {
+        return adoptRef(*new JSIPCAttachment(WTFMove(attachment)));
+    }
+
+    JSObjectRef createJSWrapper(JSContextRef);
+    static JSIPCAttachment* toWrapped(JSContextRef, JSValueRef);
+
+    void encode(IPC::Encoder& encoder) const { m_attachment.encode(encoder); }
+
+private:
+    JSIPCAttachment(IPC::Attachment&& attachment)
+        : m_attachment(WTFMove(attachment))
+    { }
+
+    static JSClassRef wrapperClass();
+    static JSIPCAttachment* unwrap(JSObjectRef);
+    static void initialize(JSContextRef, JSObjectRef);
+    static void finalize(JSObjectRef);
+
+    static const JSStaticFunction* staticFunctions();
+
+    IPC::Attachment m_attachment;
+};
+
+class JSIPCConnection : public RefCounted<JSIPCConnection>, private IPC::Connection::Client {
+public:
+    static Ref<JSIPCConnection> create(IPC::Connection::Identifier&& testedConnectionIdentifier)
+    {
+        return adoptRef(*new JSIPCConnection(WTFMove(testedConnectionIdentifier)));
+    }
+
+    JSObjectRef createJSWrapper(JSContextRef);
+    static JSIPCConnection* toWrapped(JSContextRef, JSValueRef);
+
+private:
+    JSIPCConnection(IPC::Connection::Identifier&& testedConnectionIdentifier)
+        : m_testedConnection { IPC::Connection::createServerConnection(testedConnectionIdentifier, *this) }
+    {
+    }
+
+    // IPC::Connection::Client overrides.
+    void didReceiveMessage(IPC::Connection&, IPC::Decoder&) final;
+    bool didReceiveSyncMessage(IPC::Connection&, IPC::Decoder&, UniqueRef<IPC::Encoder>&) final;
+    void didClose(IPC::Connection&) final;
+    void didReceiveInvalidMessage(IPC::Connection&, IPC::MessageName) final;
+
+    static JSClassRef wrapperClass();
+    static JSIPCConnection* unwrap(JSObjectRef);
+    static void initialize(JSContextRef, JSObjectRef);
+    static void finalize(JSObjectRef);
+
+
+    static const JSStaticFunction* staticFunctions();
+    static JSValueRef open(JSContextRef, JSObjectRef, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception);
+    static JSValueRef invalidate(JSContextRef, JSObjectRef, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception);
+    static JSValueRef sendMessage(JSContextRef, JSObjectRef, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception);
+    static JSValueRef sendSyncMessage(JSContextRef, JSObjectRef, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception);
+    static JSValueRef waitForMessage(JSContextRef, JSObjectRef, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception);
+
+    Ref<IPC::Connection> m_testedConnection;
+};
+
 class JSIPCStreamClientConnection : public RefCounted<JSIPCStreamClientConnection>, public CanMakeWeakPtr<JSIPCStreamClientConnection> {
 public:
     static Ref<JSIPCStreamClientConnection> create(JSIPC& jsIPC, IPC::Connection& connection, size_t bufferSize)
@@ -220,8 +287,6 @@
     Ref<SharedMemory> m_sharedMemory;
 };
 
-class JSIPC;
-
 class JSMessageListener final : public IPC::Connection::MessageObserver {
     WTF_MAKE_FAST_ALLOCATED;
 public:
@@ -246,7 +311,7 @@
     {
         return adoptRef(*new JSIPC(webPage, webFrame));
     }
-
+    static JSIPC* toWrapped(JSContextRef, JSValueRef);
     static JSClassRef wrapperClass();
 
     WebFrame* webFrame() { return m_webFrame.get(); }
@@ -258,7 +323,6 @@
     { }
 
     static JSIPC* unwrap(JSObjectRef);
-    static JSIPC* toWrapped(JSContextRef, JSValueRef);
     static void initialize(JSContextRef, JSObjectRef);
     static void finalize(JSObjectRef);
     static const JSStaticFunction* staticFunctions();
@@ -272,6 +336,8 @@
     static JSValueRef sendSyncMessage(JSContextRef, JSObjectRef, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception);
     static JSValueRef waitForMessage(JSContextRef, JSObjectRef, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception);
 
+    static JSValueRef createConnectionPair(JSContextRef, JSObjectRef, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception);
+
     static JSValueRef createStreamClientConnection(JSContextRef, JSObjectRef, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception);
     static JSValueRef createSemaphore(JSContextRef, JSObjectRef, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception);
     static JSValueRef createSharedMemory(JSContextRef, JSObjectRef, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception);
@@ -311,6 +377,166 @@
     return std::nullopt;
 }
 
+
+static JSValueRef sendMessageWithJSArguments(IPC::Connection& connection, JSContextRef context, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+    auto* globalObject = toJS(context);
+    JSC::JSLockHolder lock(globalObject->vm());
+
+    auto destinationID = destinationIDFromArgument(globalObject, arguments[0], exception);
+    if (!destinationID)
+        return JSValueMakeUndefined(context);
+
+    auto messageID = messageIDFromArgument(globalObject, arguments[1], exception);
+    if (!messageID)
+        return JSValueMakeUndefined(context);
+
+    auto messageName = static_cast<IPC::MessageName>(*messageID);
+    auto encoder = makeUniqueRef<IPC::Encoder>(messageName, *destinationID);
+
+    JSValueRef returnValue = JSValueMakeUndefined(context);
+
+    bool hasReply = !!messageReplyArgumentDescriptions(messageName);
+    if (hasReply) {
+        uint64_t listenerID = IPC::nextAsyncReplyHandlerID();
+        encoder.get() << listenerID;
+
+        JSObjectRef resolve;
+        JSObjectRef reject;
+ALLOW_NEW_API_WITHOUT_GUARDS_BEGIN
+        returnValue = JSObjectMakeDeferredPromise(context, &resolve, &reject, exception); // NOLINT
+ALLOW_NEW_API_WITHOUT_GUARDS_END
+        if (!returnValue)  // NOLINT
+            return JSValueMakeUndefined(context);
+
+        JSGlobalContextRetain(JSContextGetGlobalContext(context));
+        JSValueProtect(context, resolve);
+        JSValueProtect(context, reject);
+        IPC::addAsyncReplyHandler(connection, listenerID, [messageName, context, resolve, reject](IPC::Decoder* replyDecoder) {
+            auto* globalObject = toJS(context);
+            auto& vm = globalObject->vm();
+            JSC::JSLockHolder lock(vm);
+
+            auto scope = DECLARE_CATCH_SCOPE(vm);
+            auto* jsResult = jsResultFromReplyDecoder(globalObject, messageName, *replyDecoder);
+            if (auto* exception = scope.exception()) {
+                scope.clearException();
+                JSValueRef arguments[] = { toRef(globalObject, exception) };
+                JSObjectCallAsFunction(context, reject, reject, 1, arguments, nullptr);
+            } else {
+                JSValueRef arguments[] = { toRef(globalObject, jsResult) };
+                JSObjectCallAsFunction(context, resolve, resolve, 1, arguments, nullptr);
+            }
+
+            JSValueUnprotect(context, reject);
+            JSValueUnprotect(context, resolve);
+            JSGlobalContextRelease(JSContextGetGlobalContext(context));
+        });
+    }
+
+    if (argumentCount > 2) {
+        if (!encodeArgument(encoder.get(), context, arguments[2], exception))
+            return JSValueMakeUndefined(context);
+    }
+
+    // FIXME: Add the support for specifying IPC options.
+
+    connection.sendMessage(WTFMove(encoder), { });
+    return returnValue;
+}
+
+namespace {
+
+struct SyncIPCMessageInfo {
+    uint64_t destinationID;
+    IPC::MessageName messageName;
+    IPC::Timeout timeout;
+};
+
+}
+
+static std::optional<SyncIPCMessageInfo> extractSyncIPCMessageInfo(JSContextRef context, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+    ASSERT(argumentCount >= 2);
+    auto* globalObject = toJS(context);
+    auto destinationID = destinationIDFromArgument(globalObject, arguments[0], exception);
+    if (!destinationID)
+        return std::nullopt;
+
+    auto messageID = messageIDFromArgument(globalObject, arguments[1], exception);
+    if (!messageID)
+        return std::nullopt;
+
+    Seconds timeoutDuration;
+    {
+        auto jsValue = toJS(globalObject, arguments[2]);
+        if (!jsValue.isNumber()) {
+            *exception = createTypeError(context, "Timeout must be a number"_s);
+            return std::nullopt;
+        }
+        timeoutDuration = Seconds { jsValue.asNumber() };
+    }
+
+    return { { *destinationID, static_cast<IPC::MessageName>(*messageID), { timeoutDuration } } };
+}
+
+static JSValueRef sendSyncMessageWithJSArguments(IPC::Connection& connection, JSContextRef context, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+    auto* globalObject = toJS(context);
+    JSC::JSLockHolder lock(globalObject->vm());
+    auto info = extractSyncIPCMessageInfo(context, argumentCount, arguments, exception);
+    if (!info)
+        return JSValueMakeUndefined(context);
+
+    auto [destinationID, messageName, timeout] = *info;
+
+    // FIXME: Support the options.
+
+    IPC::Connection::SyncRequestID syncRequestID;
+    auto encoder = connection.createSyncMessageEncoder(messageName, destinationID, syncRequestID);
+
+    if (argumentCount > 3) {
+        if (!encodeArgument(encoder.get(), context, arguments[3], exception))
+            return JSValueMakeUndefined(context);
+    }
+
+    if (auto replyDecoder = connection.sendSyncMessage(syncRequestID, WTFMove(encoder), timeout, { })) {
+        auto scope = DECLARE_CATCH_SCOPE(globalObject->vm());
+        auto* jsResult = jsResultFromReplyDecoder(globalObject, messageName, *replyDecoder);
+        if (scope.exception()) {
+            *exception = toRef(globalObject, scope.exception());
+            scope.clearException();
+            return JSValueMakeUndefined(context);
+        }
+        return toRef(globalObject, jsResult);
+    }
+
+    return JSValueMakeUndefined(context);
+}
+
+static JSValueRef waitForMessageWithJSArguments(IPC::Connection& connection, JSContextRef context, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+    auto* globalObject = toJS(context);
+    JSC::JSLockHolder lock(globalObject->vm());
+
+    auto info = extractSyncIPCMessageInfo(context, argumentCount, arguments, exception);
+    if (!info)
+        return JSValueMakeUndefined(context);
+
+    auto [destinationID, messageName, timeout] = *info;
+    if (auto decoder = connection.waitForMessageForTesting(messageName, destinationID, timeout, { })) {
+        auto scope = DECLARE_CATCH_SCOPE(globalObject->vm());
+        auto jsResult = jsValueForArguments(globalObject, messageName, *decoder);
+        if (scope.exception()) {
+            *exception = toRef(globalObject, scope.exception());
+            scope.clearException();
+            return JSValueMakeUndefined(context);
+        }
+        return jsResult ? toRef(globalObject, *jsResult) : JSValueMakeUndefined(context);
+    }
+    return JSValueMakeUndefined(context);
+}
+
 JSObjectRef JSIPCSemaphore::createJSWrapper(JSContextRef context)
 {
     auto* globalObject = toJS(context);
@@ -370,6 +596,210 @@
     return functions;
 }
 
+
+JSObjectRef JSIPCAttachment::createJSWrapper(JSContextRef context)
+{
+    auto* globalObject = toJS(context);
+    auto& vm = globalObject->vm();
+    JSC::JSLockHolder lock(vm);
+    auto scope = DECLARE_CATCH_SCOPE(vm);
+    JSObjectRef wrapperObject = JSObjectMake(toGlobalRef(globalObject), wrapperClass(), this);
+    scope.clearException();
+    return wrapperObject;
+}
+
+JSClassRef JSIPCAttachment::wrapperClass()
+{
+    static JSClassRef jsClass;
+    if (!jsClass) {
+        JSClassDefinition definition = kJSClassDefinitionEmpty;
+        definition.className = "Attachment";
+        definition.parentClass = nullptr;
+        definition.staticValues = nullptr;
+        definition.staticFunctions = staticFunctions();
+        definition.initialize = initialize;
+        definition.finalize = finalize;
+        jsClass = JSClassCreate(&definition);
+    }
+    return jsClass;
+}
+
+inline JSIPCAttachment* JSIPCAttachment::unwrap(JSObjectRef object)
+{
+    return static_cast<JSIPCAttachment*>(JSObjectGetPrivate(object));
+}
+
+JSIPCAttachment* JSIPCAttachment::toWrapped(JSContextRef context, JSValueRef value)
+{
+    if (!context || !value || !JSValueIsObjectOfClass(context, value, wrapperClass()))
+        return nullptr;
+    return unwrap(JSValueToObject(context, value, nullptr));
+}
+
+void JSIPCAttachment::initialize(JSContextRef, JSObjectRef object)
+{
+    unwrap(object)->ref();
+}
+
+void JSIPCAttachment::finalize(JSObjectRef object)
+{
+    unwrap(object)->deref();
+}
+
+const JSStaticFunction* JSIPCAttachment::staticFunctions()
+{
+    static const JSStaticFunction functions[] = {
+        { 0, 0, 0 }
+    };
+    return functions;
+}
+
+JSObjectRef JSIPCConnection::createJSWrapper(JSContextRef context)
+{
+    auto* globalObject = toJS(context);
+    auto& vm = globalObject->vm();
+    JSC::JSLockHolder lock(vm);
+    auto scope = DECLARE_CATCH_SCOPE(vm);
+    JSObjectRef wrapperObject = JSObjectMake(toGlobalRef(globalObject), wrapperClass(), this);
+    scope.clearException();
+    return wrapperObject;
+}
+
+JSClassRef JSIPCConnection::wrapperClass()
+{
+    static JSClassRef jsClass;
+    if (!jsClass) {
+        JSClassDefinition definition = kJSClassDefinitionEmpty;
+        definition.className = "Connection";
+        definition.parentClass = nullptr;
+        definition.staticValues = nullptr;
+        definition.staticFunctions = staticFunctions();
+        definition.initialize = initialize;
+        definition.finalize = finalize;
+        jsClass = JSClassCreate(&definition);
+    }
+    return jsClass;
+}
+
+inline JSIPCConnection* JSIPCConnection::unwrap(JSObjectRef object)
+{
+    return static_cast<JSIPCConnection*>(JSObjectGetPrivate(object));
+}
+
+JSIPCConnection* JSIPCConnection::toWrapped(JSContextRef context, JSValueRef value)
+{
+    if (!context || !value || !JSValueIsObjectOfClass(context, value, wrapperClass()))
+        return nullptr;
+    return unwrap(JSValueToObject(context, value, nullptr));
+}
+
+void JSIPCConnection::initialize(JSContextRef, JSObjectRef object)
+{
+    unwrap(object)->ref();
+}
+
+void JSIPCConnection::finalize(JSObjectRef object)
+{
+    unwrap(object)->deref();
+}
+
+void JSIPCConnection::didReceiveMessage(IPC::Connection&, IPC::Decoder&)
+{
+    ASSERT_NOT_REACHED();
+}
+
+bool JSIPCConnection::didReceiveSyncMessage(IPC::Connection&, IPC::Decoder&, UniqueRef<IPC::Encoder>&)
+{
+    ASSERT_NOT_REACHED();
+}
+
+void JSIPCConnection::didClose(IPC::Connection&)
+{
+}
+
+void JSIPCConnection::didReceiveInvalidMessage(IPC::Connection&, IPC::MessageName)
+{
+    ASSERT_NOT_REACHED();
+}
+
+
+const JSStaticFunction* JSIPCConnection::staticFunctions()
+{
+    static const JSStaticFunction functions[] = {
+        { "open", open, kJSPropertyAttributeDontDelete | kJSPropertyAttributeReadOnly },
+        { "invalidate", invalidate, kJSPropertyAttributeDontDelete | kJSPropertyAttributeReadOnly },
+        { "sendMessage", sendMessage, kJSPropertyAttributeDontDelete | kJSPropertyAttributeReadOnly },
+        { "sendSyncMessage", sendSyncMessage, kJSPropertyAttributeDontDelete | kJSPropertyAttributeReadOnly },
+        { "waitForMessage", waitForMessage, kJSPropertyAttributeDontDelete | kJSPropertyAttributeReadOnly },
+        { 0, 0, 0 }
+    };
+    return functions;
+}
+
+JSValueRef JSIPCConnection::open(JSContextRef context, JSObjectRef, JSObjectRef thisObject, size_t, const JSValueRef[], JSValueRef* exception)
+{
+    RefPtr self = toWrapped(context, thisObject);
+    if (!self) {
+        *exception = createTypeError(context, "Wrong type"_s);
+        return JSValueMakeUndefined(context);
+    }
+    self->m_testedConnection->open();
+    return JSValueMakeUndefined(context);
+}
+
+JSValueRef JSIPCConnection::invalidate(JSContextRef context, JSObjectRef, JSObjectRef thisObject, size_t, const JSValueRef[], JSValueRef* exception)
+{
+    RefPtr self = toWrapped(context, thisObject);
+    if (!self) {
+        *exception = createTypeError(context, "Wrong type"_s);
+        return JSValueMakeUndefined(context);
+    }
+    self->m_testedConnection->invalidate();
+    return JSValueMakeUndefined(context);
+}
+
+JSValueRef JSIPCConnection::sendMessage(JSContextRef context, JSObjectRef, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+    RefPtr self = toWrapped(context, thisObject);
+    if (!self) {
+        *exception = createTypeError(context, "Wrong type"_s);
+        return JSValueMakeUndefined(context);
+    }
+    if (argumentCount < 2) {
+        *exception = createTypeError(context, "Must specify the destination ID and message ID as the first two arguments"_s);
+        return JSValueMakeUndefined(context);
+    }
+    return sendMessageWithJSArguments(self->m_testedConnection, context, argumentCount, arguments, exception);
+}
+
+JSValueRef JSIPCConnection::sendSyncMessage(JSContextRef context, JSObjectRef, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+    RefPtr self = toWrapped(context, thisObject);
+    if (!self) {
+        *exception = createTypeError(context, "Wrong type"_s);
+        return JSValueMakeUndefined(context);
+    }
+    if (argumentCount < 2) {
+        *exception = createTypeError(context, "Must specify the destination ID and message ID as the first two arguments"_s);
+        return JSValueMakeUndefined(context);
+    }
+    return sendSyncMessageWithJSArguments(self->m_testedConnection, context, argumentCount, arguments, exception);
+}
+
+JSValueRef JSIPCConnection::waitForMessage(JSContextRef context, JSObjectRef, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+    RefPtr self = toWrapped(context, thisObject);
+    if (!self) {
+        *exception = createTypeError(context, "Wrong type"_s);
+        return JSValueMakeUndefined(context);
+    }
+    if (argumentCount < 2) {
+        *exception = createTypeError(context, "Must specify the destination ID and message ID as the first two arguments"_s);
+        return JSValueMakeUndefined(context);
+    }
+    return waitForMessageWithJSArguments(self->m_testedConnection, context, argumentCount, arguments, exception);
+}
+
 JSObjectRef JSIPCStreamClientConnection::createJSWrapper(JSContextRef context)
 {
     auto* globalObject = toJS(context);
@@ -508,7 +938,7 @@
 {
     // FIXME: Add support for sending in-stream IPC messages when appropriate.
     if (argumentCount > 3) {
-        if (!encodeArgument(encoder, jsIPC, context, arguments[3], exception))
+        if (!encodeArgument(encoder, context, arguments[3], exception))
             return false;
     }
 
@@ -1118,6 +1548,7 @@
         { "sendMessage", sendMessage, kJSPropertyAttributeDontDelete | kJSPropertyAttributeReadOnly },
         { "sendSyncMessage", sendSyncMessage, kJSPropertyAttributeDontDelete | kJSPropertyAttributeReadOnly },
         { "waitForMessage", waitForMessage, kJSPropertyAttributeDontDelete | kJSPropertyAttributeReadOnly },
+        { "createConnectionPair", createConnectionPair, kJSPropertyAttributeDontDelete | kJSPropertyAttributeReadOnly },
         { "createStreamClientConnection", createStreamClientConnection, kJSPropertyAttributeDontDelete | kJSPropertyAttributeReadOnly },
         { "createSemaphore", createSemaphore, kJSPropertyAttributeDontDelete | kJSPropertyAttributeReadOnly },
         { "createSharedMemory", createSharedMemory, kJSPropertyAttributeDontDelete | kJSPropertyAttributeReadOnly },
@@ -1356,6 +1787,21 @@
     return true;
 }
 
+static bool encodeFrameInfoData(IPC::Encoder& encoder, JSC::JSGlobalObject* globalObject, JSC::JSObject* jsObject, JSC::CatchScope& scope)
+{
+    auto jsIPCValue = jsObject->get(globalObject, JSC::Identifier::fromString(globalObject->vm(), "value"_s));
+    if (scope.exception())
+        return false;
+    RefPtr jsIPC = JSIPC::toWrapped(toRef(globalObject), toRef(jsIPCValue));
+    if (!jsIPC)
+        return false;
+    RefPtr webFrame = jsIPC->webFrame();
+    if (!webFrame)
+        return false;
+    encoder << webFrame->info();
+    return true;
+}
+
 static bool encodeStreamConnectionBuffer(IPC::Encoder& encoder, JSC::JSGlobalObject* globalObject, JSC::JSValue jsValue, JSC::CatchScope& scope)
 {
     RefPtr jsIPCStreamConnectionBuffer = JSIPCStreamConnectionBuffer::toWrapped(toRef(globalObject), toRef(jsValue));
@@ -1376,8 +1822,17 @@
     return true;
 }
 
+static bool encodeAttachment(IPC::Encoder& encoder, JSC::JSGlobalObject* globalObject, JSC::JSValue jsValue, JSC::CatchScope& scope)
+{
+    RefPtr jsIPCAttachment = JSIPCAttachment::toWrapped(toRef(globalObject), toRef(jsValue));
+    if (!jsIPCAttachment)
+        return false;
+
+    jsIPCAttachment->encode(encoder);
+    return true;
+}
+
 struct VectorEncodeHelper {
-    Ref<JSIPC> jsIPC;
     JSContextRef context;
     JSValueRef valueRef;
     JSValueRef* exception;
@@ -1387,12 +1842,12 @@
     {
         if (!success)
             return;
-        success = encodeArgument(encoder, jsIPC.get(), context, valueRef, exception);
+        success = encodeArgument(encoder, context, valueRef, exception);
     }
 };
 
 enum class ArrayMode { Tuple, Vector };
-static bool encodeArrayArgument(IPC::Encoder& encoder, JSIPC& jsIPC, ArrayMode arrayMode, JSContextRef context, JSValueRef valueRef, JSValueRef* exception)
+static bool encodeArrayArgument(IPC::Encoder& encoder, ArrayMode arrayMode, JSContextRef context, JSValueRef valueRef, JSValueRef* exception)
 {
     auto objectRef = JSValueToObject(context, valueRef, exception);
     ASSERT(objectRef);
@@ -1418,7 +1873,7 @@
         auto itemRef = JSObjectGetPropertyAtIndex(context, objectRef, i, exception);
         if (!itemRef)
             return false;
-        vector.append(VectorEncodeHelper { jsIPC, context, itemRef, exception, success });
+        vector.append(VectorEncodeHelper { context, itemRef, exception, success });
     }
     if (arrayMode == ArrayMode::Tuple) {
         for (auto& item : vector)
@@ -1428,7 +1883,7 @@
     return success;
 }
 
-static bool encodeArgument(IPC::Encoder& encoder, JSIPC& jsIPC, JSContextRef context, JSValueRef valueRef, JSValueRef* exception)
+static bool encodeArgument(IPC::Encoder& encoder, JSContextRef context, JSValueRef valueRef, JSValueRef* exception)
 {
     auto objectRef = JSValueToObject(context, valueRef, exception);
     if (!objectRef)
@@ -1438,7 +1893,7 @@
         return encodeTypedArray(encoder, context, objectRef, type, exception);
 
     if (JSValueIsArray(context, objectRef))
-        return encodeArrayArgument(encoder, jsIPC, ArrayMode::Tuple, context, objectRef, exception);
+        return encodeArrayArgument(encoder, ArrayMode::Tuple, context, objectRef, exception);
 
     auto* globalObject = toJS(context);
     auto& vm = globalObject->vm();
@@ -1505,12 +1960,10 @@
     }
 
     if (type == "FrameInfoData") {
-        RefPtr webFrame = jsIPC.webFrame();
-        if (!webFrame) {
+        if (!encodeFrameInfoData(encoder, globalObject, jsObject, scope)) {
             *exception = createTypeError(context, "Failed to get the frame"_s);
             return false;
         }
-        encoder << webFrame->info();
         return true;
     }
 
@@ -1534,12 +1987,20 @@
         return true;
     }
 
+    if (type == "Attachment") {
+        if (!encodeAttachment(encoder, globalObject, jsValue, scope)) {
+            *exception = createTypeError(context, "Failed to convert Attachment"_s);
+            return false;
+        }
+        return true;
+    }
+
     if (type == "Vector") {
         if (!jsValue.inherits<JSC::JSArray>()) {
             *exception = createTypeError(context, "Vector value must be an array"_s);
             return false;
         }
-        return encodeArrayArgument(encoder, jsIPC, ArrayMode::Vector, context, toRef(globalObject, jsValue), exception);
+        return encodeArrayArgument(encoder, ArrayMode::Vector, context, toRef(globalObject, jsValue), exception);
     }
 
     if (type == "String") {
@@ -1670,185 +2131,78 @@
         *exception = createTypeError(context, "Wrong type"_s);
         return JSValueMakeUndefined(context);
     }
-
     if (argumentCount < 3) {
         *exception = createTypeError(context, "Must specify the target process, destination ID, and message ID as the first three arguments"_s);
         return JSValueMakeUndefined(context);
     }
-
     auto connection = processTargetFromArgument(globalObject, arguments[0], exception);
     if (!connection)
         return JSValueMakeUndefined(context);
+    return sendMessageWithJSArguments(*connection, context, argumentCount - 1, arguments + 1, exception);
+}
 
-    auto destinationID = destinationIDFromArgument(globalObject, arguments[1], exception);
-    if (!destinationID)
+JSValueRef JSIPC::waitForMessage(JSContextRef context, JSObjectRef, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+    RefPtr jsIPC = toWrapped(context, thisObject);
+    if (!jsIPC) {
+        *exception = createTypeError(context, "Wrong type"_s);
         return JSValueMakeUndefined(context);
-
-    auto messageID = messageIDFromArgument(globalObject, arguments[2], exception);
-    if (!messageID)
-        return JSValueMakeUndefined(context);
-
-    auto messageName = static_cast<IPC::MessageName>(*messageID);
-    auto encoder = makeUniqueRef<IPC::Encoder>(messageName, *destinationID);
-
-    JSValueRef returnValue = JSValueMakeUndefined(context);
-
-    bool hasReply = !!messageReplyArgumentDescriptions(messageName);
-    if (hasReply) {
-        uint64_t listenerID = IPC::nextAsyncReplyHandlerID();
-        encoder.get() << listenerID;
-
-        JSObjectRef resolve;
-        JSObjectRef reject;
-ALLOW_NEW_API_WITHOUT_GUARDS_BEGIN
-        returnValue = JSObjectMakeDeferredPromise(context, &resolve, &reject, exception);
-ALLOW_NEW_API_WITHOUT_GUARDS_END
-        if (!returnValue)
-            return JSValueMakeUndefined(context);
-
-        JSGlobalContextRetain(JSContextGetGlobalContext(context));
-        JSValueProtect(context, resolve);
-        JSValueProtect(context, reject);
-        IPC::addAsyncReplyHandler(*connection, listenerID, [messageName, context, resolve, reject](IPC::Decoder* replyDecoder) {
-            auto* globalObject = toJS(context);
-            auto& vm = globalObject->vm();
-            JSC::JSLockHolder lock(vm);
-
-            auto scope = DECLARE_CATCH_SCOPE(vm);
-            auto* jsResult = jsResultFromReplyDecoder(globalObject, messageName, *replyDecoder);
-            if (auto* exception = scope.exception()) {
-                scope.clearException();
-                JSValueRef arguments[] = { toRef(globalObject, exception) };
-                JSObjectCallAsFunction(context, reject, reject, 1, arguments, nullptr);
-            } else {
-                JSValueRef arguments[] = { toRef(globalObject, jsResult) };
-                JSObjectCallAsFunction(context, resolve, resolve, 1, arguments, nullptr);
-            }
-
-            JSValueUnprotect(context, reject);
-            JSValueUnprotect(context, resolve);
-            JSGlobalContextRelease(JSContextGetGlobalContext(context));
-        });
     }
-
-    if (argumentCount > 3) {
-        if (!encodeArgument(encoder.get(), *jsIPC, context, arguments[3], exception))
-            return JSValueMakeUndefined(context);
-    }
-
-    // FIXME: Add the support for specifying IPC options.
-
-    connection->sendMessage(WTFMove(encoder), { });
-
-    return returnValue;
-}
-
-struct SyncIPCMessageInfo {
-    Ref<IPC::Connection> connection;
-    uint64_t destinationID;
-    IPC::MessageName messageName;
-    IPC::Timeout timeout;
-};
-
-static std::optional<SyncIPCMessageInfo> extractSyncIPCMessageInfo(JSContextRef context, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
-{
-    if (argumentCount < 4) {
+    if (argumentCount < 3) {
         *exception = createTypeError(context, "Must specify the target process, destination ID, and message ID as the first three arguments"_s);
-        return std::nullopt;
+        return JSValueMakeUndefined(context);
     }
-
     auto* globalObject = toJS(context);
+    JSC::JSLockHolder lock(globalObject->vm());
     auto connection = processTargetFromArgument(globalObject, arguments[0], exception);
     if (!connection)
-        return std::nullopt;
-
-    auto destinationID = destinationIDFromArgument(globalObject, arguments[1], exception);
-    if (!destinationID)
-        return std::nullopt;
-
-    auto messageID = messageIDFromArgument(globalObject, arguments[2], exception);
-    if (!messageID)
-        return std::nullopt;
-
-    Seconds timeoutDuration;
-    {
-        auto jsValue = toJS(globalObject, arguments[3]);
-        if (!jsValue.isNumber()) {
-            *exception = createTypeError(context, "Timeout must be a number"_s);
-            return std::nullopt;
-        }
-        timeoutDuration = Seconds { jsValue.asNumber() };
-    }
-
-    return { { connection.releaseNonNull(), *destinationID, static_cast<IPC::MessageName>(*messageID), { timeoutDuration } } };
+        return JSValueMakeUndefined(context);
+    return waitForMessageWithJSArguments(*connection, context, argumentCount - 1, arguments + 1, exception);
 }
 
-JSValueRef JSIPC::waitForMessage(JSContextRef context, JSObjectRef, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+JSValueRef JSIPC::sendSyncMessage(JSContextRef context, JSObjectRef, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
 {
-    auto* globalObject = toJS(context);
-    JSC::JSLockHolder lock(globalObject->vm());
     RefPtr jsIPC = toWrapped(context, thisObject);
     if (!jsIPC) {
         *exception = createTypeError(context, "Wrong type"_s);
         return JSValueMakeUndefined(context);
     }
-
-    auto info = extractSyncIPCMessageInfo(context, argumentCount, arguments, exception);
-    if (!info)
+    if (argumentCount < 3) {
+        *exception = createTypeError(context, "Must specify the target process, destination ID, and message ID as the first three arguments"_s);
         return JSValueMakeUndefined(context);
-
-    auto [connection, destinationID, messageName, timeout] = *info;
-    if (auto decoder = connection->waitForMessage(messageName, destinationID, timeout, { })) {
-        auto scope = DECLARE_CATCH_SCOPE(globalObject->vm());
-        auto jsResult = jsValueForArguments(globalObject, messageName, *decoder);
-        if (scope.exception()) {
-            *exception = toRef(globalObject, scope.exception());
-            scope.clearException();
-            return JSValueMakeUndefined(context);
-        }
-        return jsResult ? toRef(globalObject, *jsResult) : JSValueMakeUndefined(context);
     }
-    return JSValueMakeUndefined(context);
+    auto* globalObject = toJS(context);
+    JSC::JSLockHolder lock(globalObject->vm());
+    auto connection = processTargetFromArgument(globalObject, arguments[0], exception);
+    if (!connection)
+        return JSValueMakeUndefined(context);
+    return sendSyncMessageWithJSArguments(*connection, context, argumentCount - 1, arguments + 1, exception);
 }
 
-JSValueRef JSIPC::sendSyncMessage(JSContextRef context, JSObjectRef, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+JSValueRef JSIPC::createConnectionPair(JSContextRef context, JSObjectRef, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
 {
-    auto* globalObject = toJS(context);
-    JSC::JSLockHolder lock(globalObject->vm());
     RefPtr jsIPC = toWrapped(context, thisObject);
     if (!jsIPC) {
         *exception = createTypeError(context, "Wrong type"_s);
         return JSValueMakeUndefined(context);
     }
-
-    auto info = extractSyncIPCMessageInfo(context, argumentCount, arguments, exception);
-    if (!info)
+    auto connectionIdentifiers = IPC::Connection::createConnectionIdentifierPair();
+    if (!connectionIdentifiers)
         return JSValueMakeUndefined(context);
-
-    auto [connection, destinationID, messageName, timeout] = *info;
-
-    // FIXME: Support the options.
-
-    IPC::Connection::SyncRequestID syncRequestID;
-    auto encoder = connection->createSyncMessageEncoder(messageName, destinationID, syncRequestID);
-
-    if (argumentCount > 4) {
-        if (!encodeArgument(encoder.get(), *jsIPC, context, arguments[4], exception))
-            return JSValueMakeUndefined(context);
-    }
-
-    if (auto replyDecoder = connection->sendSyncMessage(syncRequestID, WTFMove(encoder), timeout, { })) {
-        auto scope = DECLARE_CATCH_SCOPE(globalObject->vm());
-        auto* jsResult = jsResultFromReplyDecoder(globalObject, messageName, *replyDecoder);
-        if (scope.exception()) {
-            *exception = toRef(globalObject, scope.exception());
-            scope.clearException();
-            return JSValueMakeUndefined(context);
-        }
-        return toRef(globalObject, jsResult);
-    }
-
-    return JSValueMakeUndefined(context);
+    auto* globalObject = toJS(context);
+    JSC::JSLockHolder lock(globalObject->vm());
+    auto& vm = globalObject->vm();
+    auto scope = DECLARE_CATCH_SCOPE(vm);
+    JSC::JSObject* connectionPairObject = JSC::constructEmptyArray(globalObject, nullptr);
+    RETURN_IF_EXCEPTION(scope, JSValueMakeUndefined(context));
+    int index = 0;
+    auto jsValue = toJS(globalObject, JSIPCConnection::create(WTFMove(connectionIdentifiers->server))->createJSWrapper(context));
+    connectionPairObject->putDirectIndex(globalObject, index++, jsValue);
+    RETURN_IF_EXCEPTION(scope, JSValueMakeUndefined(context));
+    jsValue = toJS(globalObject, JSIPCAttachment::create(WTFMove(connectionIdentifiers->client))->createJSWrapper(context));
+    connectionPairObject->putDirectIndex(globalObject, index++, jsValue);
+    RETURN_IF_EXCEPTION(scope, JSValueMakeUndefined(context));
+    return toRef(vm, connectionPairObject);
 }
 
 JSValueRef JSIPC::createStreamClientConnection(JSContextRef context, JSObjectRef, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)

Modified: trunk/Tools/ChangeLog (293566 => 293567)


--- trunk/Tools/ChangeLog	2022-04-28 05:36:41 UTC (rev 293566)
+++ trunk/Tools/ChangeLog	2022-04-28 07:18:08 UTC (rev 293567)
@@ -1,3 +1,15 @@
+2022-04-28  Kimmo Kinnunen  <kkinnu...@apple.com>
+
+        IPC testing API should have the ability to test IPC::Connection send and receive through IPC::Connection
+        https://bugs.webkit.org/show_bug.cgi?id=239495
+
+        Reviewed by Darin Adler.
+
+        * TestWebKitAPI/Tests/WebKitCocoa/IPCTestingAPI.mm:
+        (TEST):
+        Change two tests to pass "IPC" object as the value of FrameInfoData. This way the argument encode functions
+        do not need to take the JSIPC argument.
+
 2022-04-27  Sihui Liu  <sihui_...@apple.com>
 
         [ iOS ] TestWebKitAPI.IndexedDB.IndexedDBSuspendImminently is a constant timeout

Modified: trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/IPCTestingAPI.mm (293566 => 293567)


--- trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/IPCTestingAPI.mm	2022-04-28 05:36:41 UTC (rev 293566)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/IPCTestingAPI.mm	2022-04-28 07:18:08 UTC (rev 293567)
@@ -177,7 +177,7 @@
 
     done = false;
     [webView synchronouslyLoadHTMLString:@"<!DOCTYPE html><script>IPC.sendSyncMessage('UI', IPC.webPageProxyID, IPC.messages.WebPageProxy_RunJavaScriptAlert.name, 100,"
-        "[{type: 'uint64_t', value: IPC.frameID}, {type: 'FrameInfoData'}, {'type': 'String', 'value': 'hi'}]);</script>"];
+        "[{type: 'uint64_t', value: IPC.frameID}, {type: 'FrameInfoData', value: IPC}, {'type': 'String', 'value': 'hi'}]);</script>"];
     TestWebKitAPI::Util::run(&done);
 
     EXPECT_STREQ([alertMessage UTF8String], "hi");
@@ -345,7 +345,7 @@
     done = false;
     promptResult = @"foo";
     [webView synchronouslyLoadHTMLString:@"<!DOCTYPE html><script>result = IPC.sendSyncMessage('UI', IPC.webPageProxyID, IPC.messages.WebPageProxy_RunJavaScriptPrompt.name, 100,"
-        "[{type: 'uint64_t', value: IPC.frameID}, {type: 'FrameInfoData'}, {'type': 'String', 'value': 'hi'}, {'type': 'String', 'value': 'bar'}]);</script>"];
+        "[{type: 'uint64_t', value: IPC.frameID}, {type: 'FrameInfoData', value: IPC}, {'type': 'String', 'value': 'hi'}, {'type': 'String', 'value': 'bar'}]);</script>"];
     TestWebKitAPI::Util::run(&done);
 
     EXPECT_STREQ([promptDefault UTF8String], "bar");
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to