Title: [268239] trunk
Revision
268239
Author
rn...@webkit.org
Date
2020-10-08 17:48:35 -0700 (Thu, 08 Oct 2020)

Log Message

Make it possible to send an arbitrary IPC message from _javascript_
https://bugs.webkit.org/show_bug.cgi?id=217423
<rdar://problem/69969351>

Reviewed by Geoffrey Garen.

Source/_javascript_Core:

Added a helper function to get uint64_t out of BigInt.

* runtime/JSBigInt.cpp:
(JSC::JSBigInt::toUint64Heap): Added.
* runtime/JSBigInt.h:
(JSC::JSBigInt::toUint64): Added.

Source/WebKit:

This patch introduces the _javascript_ API (window.IPC) to send IPC out of WebContent process.
The feature is compiled in under ASAN and Debug builds and can be enabled at runtime.

window.IPC has two methods: sendMessage and sendSyncMessage which sends an async and sync IPC respectively.
It takes the destination process name (UI, GPU, or Networking), the destination ID (e.g. WebPageProxy ID),
message ID, timeout for sendSyncMessage, and optionally IPC message arguments. The message arguments can be
passed in as a TypedArray or ArrayBuffer, or a _javascript_ array that recursively describes encoded objects.

Each object can be either a TypedArray or ArrayBuffer, which will be treated as encoded message, an array
which will be encoded as a Vector with each item within the array encoded recursively, or a dictionary which
describes a specific type.

When a specific type is described via a dictionary, "value" is encoed based on "type" as follows:
 - When "type" is "String", "value" is encoded as a WTF::String, treating null or undefined as a null string.
 - When "type" is "bool", "int8_t", "int16_t", "int32_t", "int64_t", "uint8_t", "uint16_t", "uint32_t",
   or "uint64_t", "value" (which can be BigInt or a number) is encoded as the respective C++ type.
 - When "type" is "RGBA", "value" is used as PackedColor::RGBA to construct WebCore::Color to be encoded.
 - When "type" is "IntRect" or "FloatRect", "x", "y", "width", and "height" are treated as respective values
   of IntRect or FloatRect C++ objects, and the constructed *Rect is encoded. 
 - When "type" is "FrameInfoData", the context object's WebFrame's FrameInfoData is encoded.

The list of IPC messages are exposed on window.IPC.messages, and VisitedLinkStore ID, WebPageProxy ID,
and frame identifiers are also exposed as static variables on window.IPC.

* Sources.txt:
* WebKit.xcodeproj/project.pbxproj:
* WebProcess/WebCoreSupport/WebFrameLoaderClient.cpp:
(WebKit::WebFrameLoaderClient::dispatchDidClearWindowObjectInWorld): Inject the API if enabled.
* WebProcess/WebPage/IPCTestingAPI.cpp: Added.
(WebKit::IPCTestingAPI::JSIPC::create): Added.
(WebKit::IPCTestingAPI::JSIPC::webFrame): Added.
(WebKit::IPCTestingAPI::JSIPC::JSIPC): Added.
(WebKit::IPCTestingAPI::JSIPC::wrapperClass): Added.
(WebKit::IPCTestingAPI::JSIPC::unwrap): Added.
(WebKit::IPCTestingAPI::JSIPC::toWrapped): Added.
(WebKit::IPCTestingAPI::JSIPC::initialize): Added.
(WebKit::IPCTestingAPI::JSIPC::finalize): Added.
(WebKit::IPCTestingAPI::JSIPC::staticFunctions): Added.
(WebKit::IPCTestingAPI::JSIPC::staticValues): Added.
(WebKit::IPCTestingAPI::convertToUint64): Added.
(WebKit::IPCTestingAPI::processTargetFromArgument): Added.
(WebKit::IPCTestingAPI::destinationIDFromArgument): Added.
(WebKit::IPCTestingAPI::messageIDFromArgument): Added.
(WebKit::IPCTestingAPI::encodeTypedArray): Added.
(WebKit::IPCTestingAPI::createTypeError): Added.
(WebKit::IPCTestingAPI::encodeRectType): Added.
(WebKit::IPCTestingAPI::encodeIntegralType): Added.
(WebKit::IPCTestingAPI::VectorEncodeHelper::encode const): Added.
(WebKit::IPCTestingAPI::encodeArgument): Added.
(WebKit::IPCTestingAPI::JSIPC::sendMessage): Added.
(WebKit::IPCTestingAPI::JSIPC::sendSyncMessage): Added.
(WebKit::IPCTestingAPI::JSIPC::visitedLinkStoreID): Added.
(WebKit::IPCTestingAPI::JSIPC::webPageProxyID): Added.
(WebKit::IPCTestingAPI::JSIPC::frameIdentifier): Added.
(WebKit::IPCTestingAPI::JSIPC::retrieveID): Added.
(WebKit::IPCTestingAPI::JSIPC::messages): Added.
(WebKit::IPCTestingAPI::inject):
* WebProcess/WebPage/IPCTestingAPI.h: Added.
* WebProcess/WebPage/WebFrame.h:
* WebProcess/WebPage/WebPage.cpp:
(WebKit::m_limitsNavigationsToAppBoundDomains):
(WebKit::WebPage::updatePreferences):
* WebProcess/WebPage/WebPage.h:
(WebKit::WebPage::ipcTestingAPIEnabled const):
(WebKit::WebPage::webPageProxyID const):
(WebKit::WebPage::visitedLinkTableID const):

Source/WTF:

Added a compile time flag (ENABLE_IPC_TESTING_API) and a runtime flag (IPCTestingAPIEnabled)
for the _javascript_ API to test IPC.

* Scripts/GeneratePreferences.rb:
(Preference::nameLower): Keep IPC uppercase.
* Scripts/Preferences/WebPreferencesInternal.yaml: Added IPCTestingAPIEnabled.
* wtf/PlatformEnable.h: Added ENABLE_IPC_TESTING_API.

Tools:

* TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
* TestWebKitAPI/Tests/WebKitCocoa/IPCTestingAPI.mm: Added.
(-[IPCTestingAPIDelegate webView:runJavaScriptAlertPanelWithMessage:initiatedByFrame:completionHandler:]):
(TEST):

Modified Paths

Added Paths

Diff

Modified: trunk/Source/_javascript_Core/ChangeLog (268238 => 268239)


--- trunk/Source/_javascript_Core/ChangeLog	2020-10-09 00:45:29 UTC (rev 268238)
+++ trunk/Source/_javascript_Core/ChangeLog	2020-10-09 00:48:35 UTC (rev 268239)
@@ -1,3 +1,18 @@
+2020-10-08  Ryosuke Niwa  <rn...@webkit.org>
+
+        Make it possible to send an arbitrary IPC message from _javascript_
+        https://bugs.webkit.org/show_bug.cgi?id=217423
+        <rdar://problem/69969351>
+
+        Reviewed by Geoffrey Garen.
+
+        Added a helper function to get uint64_t out of BigInt.
+
+        * runtime/JSBigInt.cpp:
+        (JSC::JSBigInt::toUint64Heap): Added.
+        * runtime/JSBigInt.h:
+        (JSC::JSBigInt::toUint64): Added.
+
 2020-10-07  Yusuke Suzuki  <ysuz...@apple.com>
 
         [JSC] Restrict more ptr-tagging and avoid using OperationPtrTag for JIT code

Modified: trunk/Source/_javascript_Core/runtime/JSBigInt.cpp (268238 => 268239)


--- trunk/Source/_javascript_Core/runtime/JSBigInt.cpp	2020-10-09 00:45:29 UTC (rev 268238)
+++ trunk/Source/_javascript_Core/runtime/JSBigInt.cpp	2020-10-09 00:48:35 UTC (rev 268239)
@@ -3049,6 +3049,29 @@
 }
 #endif
 
+Optional<uint64_t> JSBigInt::toUint64Heap(JSBigInt* bigInt)
+{
+    auto length = bigInt->length();
+    if (!length)
+        return 0;
+    if (bigInt->sign())
+        return WTF::nullopt;
+
+    static_assert(sizeof(uint64_t) == sizeof(Digit) || sizeof(uint64_t) == sizeof(Digit) * 2, "Digit must be either 32-bit or 64-bit");
+    if (sizeof(uint64_t) == sizeof(Digit)) {
+        if (length > 1)
+            return WTF::nullopt;
+        return bigInt->digit(0);
+    }
+
+    if (length > 2)
+        return WTF::nullopt;
+    uint64_t result = bigInt->digit(0);
+    if (length == 1)
+        result += static_cast<uint64_t>(bigInt->digit(0)) << 32;
+    return result;
+}
+
 static ALWAYS_INLINE unsigned computeHash(JSBigInt::Digit* digits, unsigned length, bool sign)
 {
     Hasher hasher;

Modified: trunk/Source/_javascript_Core/runtime/JSBigInt.h (268238 => 268239)


--- trunk/Source/_javascript_Core/runtime/JSBigInt.h	2020-10-09 00:45:29 UTC (rev 268238)
+++ trunk/Source/_javascript_Core/runtime/JSBigInt.h	2020-10-09 00:48:35 UTC (rev 268239)
@@ -73,7 +73,7 @@
     static JSBigInt* tryCreateFrom(VM&, int32_t value);
     static JSBigInt* createFrom(JSGlobalObject*, uint32_t value);
     static JSBigInt* createFrom(JSGlobalObject*, int64_t value);
-    static JSBigInt* createFrom(JSGlobalObject*, uint64_t value);
+    JS_EXPORT_PRIVATE static JSBigInt* createFrom(JSGlobalObject*, uint64_t value);
     static JSBigInt* createFrom(JSGlobalObject*, bool value);
     static JSBigInt* createFrom(JSGlobalObject*, double value);
 
@@ -422,6 +422,20 @@
     static JSValue asUintN(JSGlobalObject*, uint64_t numberOfBits, int32_t bigIntAsInt32);
 #endif
 
+    static Optional<uint64_t> toUint64(JSValue bigInt)
+    {
+        ASSERT(bigInt.isBigInt());
+#if USE(BIGINT32)
+        if (bigInt.isBigInt32()) {
+            auto value = bigInt.bigInt32AsInt32();
+            if (value < 0)
+                return WTF::nullopt;
+            return value;
+        }
+#endif
+        return toUint64Heap(jsCast<JSBigInt*>(bigInt));
+    }
+
     Digit digit(unsigned);
     void setDigit(unsigned, Digit); // Use only when initializing.
     JS_EXPORT_PRIVATE JSBigInt* rightTrim(JSGlobalObject*);
@@ -576,6 +590,8 @@
     template <typename BigIntImpl>
     static ImplResult truncateAndSubFromPowerOfTwo(JSGlobalObject*, int32_t, BigIntImpl, bool resultSign);
 
+    JS_EXPORT_PRIVATE static Optional<uint64_t> toUint64Heap(JSBigInt*);
+
     inline static size_t offsetOfData()
     {
         return OBJECT_OFFSETOF(JSBigInt, m_data);

Modified: trunk/Source/WTF/ChangeLog (268238 => 268239)


--- trunk/Source/WTF/ChangeLog	2020-10-09 00:45:29 UTC (rev 268238)
+++ trunk/Source/WTF/ChangeLog	2020-10-09 00:48:35 UTC (rev 268239)
@@ -1,3 +1,19 @@
+2020-10-08  Ryosuke Niwa  <rn...@webkit.org>
+
+        Make it possible to send an arbitrary IPC message from _javascript_
+        https://bugs.webkit.org/show_bug.cgi?id=217423
+        <rdar://problem/69969351>
+
+        Reviewed by Geoffrey Garen.
+
+        Added a compile time flag (ENABLE_IPC_TESTING_API) and a runtime flag (IPCTestingAPIEnabled)
+        for the _javascript_ API to test IPC.
+
+        * Scripts/GeneratePreferences.rb:
+        (Preference::nameLower): Keep IPC uppercase.
+        * Scripts/Preferences/WebPreferencesInternal.yaml: Added IPCTestingAPIEnabled.
+        * wtf/PlatformEnable.h: Added ENABLE_IPC_TESTING_API.
+
 2020-10-08  Alex Christensen  <achristen...@webkit.org>
 
         REGRESSION (r267763): [ iOS wk2 ] http/tests/in-app-browser-privacy/non-app-bound-domain-does-not-get-app-bound-session.html is a constant failure

Modified: trunk/Source/WTF/Scripts/GeneratePreferences.rb (268238 => 268239)


--- trunk/Source/WTF/Scripts/GeneratePreferences.rb	2020-10-09 00:45:29 UTC (rev 268238)
+++ trunk/Source/WTF/Scripts/GeneratePreferences.rb	2020-10-09 00:48:35 UTC (rev 268239)
@@ -120,7 +120,7 @@
       @getter
     elsif @name.start_with?("VP")
       @name[0..1].downcase + @name[2..@name.length]
-    elsif @name.start_with?("CSS", "XSS", "FTP", "DOM", "DNS", "PDF", "ICE")
+    elsif @name.start_with?("CSS", "DOM", "DNS", "FTP", "ICE", "IPC", "PDF", "XSS")
       @name[0..2].downcase + @name[3..@name.length]
     elsif @name.start_with?("HTTP")
       @name[0..3].downcase + @name[4..@name.length]

Modified: trunk/Source/WTF/Scripts/Preferences/WebPreferencesInternal.yaml (268238 => 268239)


--- trunk/Source/WTF/Scripts/Preferences/WebPreferencesInternal.yaml	2020-10-09 00:45:29 UTC (rev 268238)
+++ trunk/Source/WTF/Scripts/Preferences/WebPreferencesInternal.yaml	2020-10-09 00:48:35 UTC (rev 268239)
@@ -279,6 +279,17 @@
     WebKit:
       default: true
 
+IPCTestingAPIEnabled:
+  type: bool
+  humanReadableName: "IPC Testing API"
+  humanReadableDescription: "Enable IPC Testing API for _javascript_"
+  webcoreBinding: none
+  condition: ENABLE(IPC_TESTING_API)
+  exposed: [ WebKit ]
+  defaultValue:
+    WebKit:
+      default: false
+
 InputTypeColorEnabled:
   type: bool
   humanReadableName: "Color Inputs"

Modified: trunk/Source/WTF/wtf/PlatformEnable.h (268238 => 268239)


--- trunk/Source/WTF/wtf/PlatformEnable.h	2020-10-09 00:45:29 UTC (rev 268238)
+++ trunk/Source/WTF/wtf/PlatformEnable.h	2020-10-09 00:48:35 UTC (rev 268239)
@@ -315,6 +315,13 @@
 #define ENABLE_INPUT_TYPE_WEEK 0
 #endif
 
+#if !defined(ENABLE_IPC_TESTING_API)
+/* Enable IPC testing on all ASAN builds and debug builds. */
+#if ASAN_ENABLED || !defined(NDEBUG)
+#define ENABLE_IPC_TESTING_API 1
+#endif
+#endif
+
 #if ENABLE(INPUT_TYPE_DATE) || ENABLE(INPUT_TYPE_DATETIMELOCAL) || ENABLE(INPUT_TYPE_MONTH) || ENABLE(INPUT_TYPE_TIME) || ENABLE(INPUT_TYPE_WEEK)
 #if !defined(ENABLE_DATE_AND_TIME_INPUT_TYPES)
 #define ENABLE_DATE_AND_TIME_INPUT_TYPES 1

Modified: trunk/Source/WebKit/ChangeLog (268238 => 268239)


--- trunk/Source/WebKit/ChangeLog	2020-10-09 00:45:29 UTC (rev 268238)
+++ trunk/Source/WebKit/ChangeLog	2020-10-09 00:48:35 UTC (rev 268239)
@@ -1,3 +1,78 @@
+2020-10-08  Ryosuke Niwa  <rn...@webkit.org>
+
+        Make it possible to send an arbitrary IPC message from _javascript_
+        https://bugs.webkit.org/show_bug.cgi?id=217423
+        <rdar://problem/69969351>
+
+        Reviewed by Geoffrey Garen.
+
+        This patch introduces the _javascript_ API (window.IPC) to send IPC out of WebContent process.
+        The feature is compiled in under ASAN and Debug builds and can be enabled at runtime.
+
+        window.IPC has two methods: sendMessage and sendSyncMessage which sends an async and sync IPC respectively.
+        It takes the destination process name (UI, GPU, or Networking), the destination ID (e.g. WebPageProxy ID),
+        message ID, timeout for sendSyncMessage, and optionally IPC message arguments. The message arguments can be
+        passed in as a TypedArray or ArrayBuffer, or a _javascript_ array that recursively describes encoded objects.
+
+        Each object can be either a TypedArray or ArrayBuffer, which will be treated as encoded message, an array
+        which will be encoded as a Vector with each item within the array encoded recursively, or a dictionary which
+        describes a specific type.
+
+        When a specific type is described via a dictionary, "value" is encoed based on "type" as follows:
+         - When "type" is "String", "value" is encoded as a WTF::String, treating null or undefined as a null string.
+         - When "type" is "bool", "int8_t", "int16_t", "int32_t", "int64_t", "uint8_t", "uint16_t", "uint32_t",
+           or "uint64_t", "value" (which can be BigInt or a number) is encoded as the respective C++ type.
+         - When "type" is "RGBA", "value" is used as PackedColor::RGBA to construct WebCore::Color to be encoded.
+         - When "type" is "IntRect" or "FloatRect", "x", "y", "width", and "height" are treated as respective values
+           of IntRect or FloatRect C++ objects, and the constructed *Rect is encoded. 
+         - When "type" is "FrameInfoData", the context object's WebFrame's FrameInfoData is encoded.
+
+        The list of IPC messages are exposed on window.IPC.messages, and VisitedLinkStore ID, WebPageProxy ID,
+        and frame identifiers are also exposed as static variables on window.IPC.
+
+        * Sources.txt:
+        * WebKit.xcodeproj/project.pbxproj:
+        * WebProcess/WebCoreSupport/WebFrameLoaderClient.cpp:
+        (WebKit::WebFrameLoaderClient::dispatchDidClearWindowObjectInWorld): Inject the API if enabled.
+        * WebProcess/WebPage/IPCTestingAPI.cpp: Added.
+        (WebKit::IPCTestingAPI::JSIPC::create): Added.
+        (WebKit::IPCTestingAPI::JSIPC::webFrame): Added.
+        (WebKit::IPCTestingAPI::JSIPC::JSIPC): Added.
+        (WebKit::IPCTestingAPI::JSIPC::wrapperClass): Added.
+        (WebKit::IPCTestingAPI::JSIPC::unwrap): Added.
+        (WebKit::IPCTestingAPI::JSIPC::toWrapped): Added.
+        (WebKit::IPCTestingAPI::JSIPC::initialize): Added.
+        (WebKit::IPCTestingAPI::JSIPC::finalize): Added.
+        (WebKit::IPCTestingAPI::JSIPC::staticFunctions): Added.
+        (WebKit::IPCTestingAPI::JSIPC::staticValues): Added.
+        (WebKit::IPCTestingAPI::convertToUint64): Added.
+        (WebKit::IPCTestingAPI::processTargetFromArgument): Added.
+        (WebKit::IPCTestingAPI::destinationIDFromArgument): Added.
+        (WebKit::IPCTestingAPI::messageIDFromArgument): Added.
+        (WebKit::IPCTestingAPI::encodeTypedArray): Added.
+        (WebKit::IPCTestingAPI::createTypeError): Added.
+        (WebKit::IPCTestingAPI::encodeRectType): Added.
+        (WebKit::IPCTestingAPI::encodeIntegralType): Added.
+        (WebKit::IPCTestingAPI::VectorEncodeHelper::encode const): Added.
+        (WebKit::IPCTestingAPI::encodeArgument): Added.
+        (WebKit::IPCTestingAPI::JSIPC::sendMessage): Added.
+        (WebKit::IPCTestingAPI::JSIPC::sendSyncMessage): Added.
+        (WebKit::IPCTestingAPI::JSIPC::visitedLinkStoreID): Added.
+        (WebKit::IPCTestingAPI::JSIPC::webPageProxyID): Added.
+        (WebKit::IPCTestingAPI::JSIPC::frameIdentifier): Added.
+        (WebKit::IPCTestingAPI::JSIPC::retrieveID): Added.
+        (WebKit::IPCTestingAPI::JSIPC::messages): Added.
+        (WebKit::IPCTestingAPI::inject):
+        * WebProcess/WebPage/IPCTestingAPI.h: Added.
+        * WebProcess/WebPage/WebFrame.h:
+        * WebProcess/WebPage/WebPage.cpp:
+        (WebKit::m_limitsNavigationsToAppBoundDomains):
+        (WebKit::WebPage::updatePreferences):
+        * WebProcess/WebPage/WebPage.h:
+        (WebKit::WebPage::ipcTestingAPIEnabled const):
+        (WebKit::WebPage::webPageProxyID const):
+        (WebKit::WebPage::visitedLinkTableID const):
+
 2020-10-08  Peng Liu  <peng.l...@apple.com>
 
         [Media in GPU Process] Cannot activate or deactivate an audio session

Modified: trunk/Source/WebKit/Sources.txt (268238 => 268239)


--- trunk/Source/WebKit/Sources.txt	2020-10-09 00:45:29 UTC (rev 268238)
+++ trunk/Source/WebKit/Sources.txt	2020-10-09 00:48:35 UTC (rev 268239)
@@ -652,6 +652,7 @@
 WebProcess/WebPage/DrawingArea.cpp
 WebProcess/WebPage/EventDispatcher.cpp
 WebProcess/WebPage/FindController.cpp
+WebProcess/WebPage/IPCTestingAPI.cpp
 WebProcess/WebPage/PageBanner.cpp
 WebProcess/WebPage/VisitedLinkTableController.cpp
 WebProcess/WebPage/WebBackForwardListProxy.cpp

Modified: trunk/Source/WebKit/WebKit.xcodeproj/project.pbxproj (268238 => 268239)


--- trunk/Source/WebKit/WebKit.xcodeproj/project.pbxproj	2020-10-09 00:45:29 UTC (rev 268238)
+++ trunk/Source/WebKit/WebKit.xcodeproj/project.pbxproj	2020-10-09 00:48:35 UTC (rev 268239)
@@ -4487,6 +4487,8 @@
 		9B02E0CD235EB967004044B2 /* _WKTextManipulationToken.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = _WKTextManipulationToken.h; sourceTree = "<group>"; };
 		9B02E0CE235EBB14004044B2 /* _WKTextManipulationToken.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = _WKTextManipulationToken.mm; sourceTree = "<group>"; };
 		9B02E0D0235EBCCA004044B2 /* _WKTextManipulationItem.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = _WKTextManipulationItem.mm; sourceTree = "<group>"; };
+		9B033E71252580F300501071 /* IPCTestingAPI.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IPCTestingAPI.h; sourceTree = "<group>"; };
+		9B033E72252580F300501071 /* IPCTestingAPI.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = IPCTestingAPI.cpp; sourceTree = "<group>"; };
 		9B1229CB23FF25F2008CA751 /* RemoteAudioDestinationManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RemoteAudioDestinationManager.h; sourceTree = "<group>"; };
 		9B1229CC23FF25F2008CA751 /* RemoteAudioDestinationManager.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = RemoteAudioDestinationManager.cpp; sourceTree = "<group>"; };
 		9B1229CF23FF2814008CA751 /* RemoteAudioDestinationManager.messages.in */ = {isa = PBXFileReference; lastKnownFileType = text; path = RemoteAudioDestinationManager.messages.in; sourceTree = "<group>"; };
@@ -8866,6 +8868,8 @@
 				1AA575FD1496B6F300A4EE06 /* EventDispatcher.messages.in */,
 				1A90C1F31264FD71003E44D4 /* FindController.cpp */,
 				1A90C1F21264FD71003E44D4 /* FindController.h */,
+				9B033E72252580F300501071 /* IPCTestingAPI.cpp */,
+				9B033E71252580F300501071 /* IPCTestingAPI.h */,
 				7C387433172F5615001BD88A /* PageBanner.cpp */,
 				7CF47FF917275C57008ACB91 /* PageBanner.h */,
 				2D819B99186275B3001F03D1 /* ViewGestureGeometryCollector.cpp */,

Modified: trunk/Source/WebKit/WebProcess/WebCoreSupport/WebFrameLoaderClient.cpp (268238 => 268239)


--- trunk/Source/WebKit/WebProcess/WebCoreSupport/WebFrameLoaderClient.cpp	2020-10-09 00:45:29 UTC (rev 268238)
+++ trunk/Source/WebKit/WebProcess/WebCoreSupport/WebFrameLoaderClient.cpp	2020-10-09 00:48:35 UTC (rev 268239)
@@ -32,6 +32,7 @@
 #include "FindController.h"
 #include "FormDataReference.h"
 #include "FrameInfoData.h"
+#include "IPCTestingAPI.h"
 #include "InjectedBundle.h"
 #include "InjectedBundleDOMWindowExtension.h"
 #include "InjectedBundleNavigationAction.h"
@@ -1743,6 +1744,11 @@
     if (!webPage)
         return;
 
+#if ENABLE(IPC_TESTING_API)
+    if (world.isNormal() && webPage->ipcTestingAPIEnabled())
+        IPCTestingAPI::inject(*webPage, m_frame.get(), world);
+#endif
+
     webPage->injectedBundleLoaderClient().didClearWindowObjectForFrame(*webPage, m_frame, world);
 
     WebAutomationSessionProxy* automationSessionProxy = WebProcess::singleton().automationSessionProxy();

Added: trunk/Source/WebKit/WebProcess/WebPage/IPCTestingAPI.cpp (0 => 268239)


--- trunk/Source/WebKit/WebProcess/WebPage/IPCTestingAPI.cpp	                        (rev 0)
+++ trunk/Source/WebKit/WebProcess/WebPage/IPCTestingAPI.cpp	2020-10-09 00:48:35 UTC (rev 268239)
@@ -0,0 +1,604 @@
+/*
+ * Copyright (C) 2020 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 "IPCTestingAPI.h"
+
+#if ENABLE(IPC_TESTING_API)
+
+#include "Encoder.h"
+#include "FrameInfoData.h"
+#include "GPUProcessConnection.h"
+#include "MessageNames.h"
+#include "NetworkProcessConnection.h"
+#include "WebCoreArgumentCoders.h"
+#include "WebFrame.h"
+#include "WebPage.h"
+#include "WebProcess.h"
+#include <_javascript_Core/APICast.h>
+#include <_javascript_Core/BuiltinNames.h>
+#include <_javascript_Core/JSBigInt.h>
+#include <_javascript_Core/JSClassRef.h>
+#include <_javascript_Core/JSLock.h>
+#include <_javascript_Core/JSObject.h>
+#include <_javascript_Core/JSValueRef.h>
+#include <_javascript_Core/_javascript_.h>
+#include <_javascript_Core/OpaqueJSString.h>
+#include <WebCore/DOMWrapperWorld.h>
+#include <WebCore/Frame.h>
+#include <WebCore/ScriptController.h>
+
+namespace WebKit {
+
+namespace IPCTestingAPI {
+
+class JSIPC : public RefCounted<JSIPC> {
+public:
+    static Ref<JSIPC> create(WebPage& webPage, WebFrame& webFrame)
+    {
+        return adoptRef(*new JSIPC(webPage, webFrame));
+    }
+
+    static JSClassRef wrapperClass();
+
+    WebFrame* webFrame() { return m_webFrame.get(); }
+
+private:
+    JSIPC(WebPage& webPage, WebFrame& webFrame)
+        : m_webPage(makeWeakPtr(webPage))
+        , m_webFrame(makeWeakPtr(webFrame))
+    { }
+
+    static JSIPC* unwrap(JSObjectRef);
+    static JSIPC* toWrapped(JSContextRef, JSValueRef);
+    static void initialize(JSContextRef, JSObjectRef);
+    static void finalize(JSObjectRef);
+    static const JSStaticFunction* staticFunctions();
+    static const JSStaticValue* staticValues();
+
+    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 visitedLinkStoreID(JSContextRef, JSObjectRef, JSStringRef, JSValueRef* exception);
+    static JSValueRef webPageProxyID(JSContextRef, JSObjectRef, JSStringRef, JSValueRef* exception);
+    static JSValueRef frameIdentifier(JSContextRef, JSObjectRef, JSStringRef, JSValueRef* exception);
+    static JSValueRef retrieveID(JSContextRef, JSObjectRef thisObject, JSValueRef* exception, const WTF::Function<uint64_t(JSIPC&)>&);
+
+    static JSValueRef messages(JSContextRef, JSObjectRef, JSStringRef, JSValueRef* exception);
+
+    WeakPtr<WebPage> m_webPage;
+    WeakPtr<WebFrame> m_webFrame;
+};
+
+JSClassRef JSIPC::wrapperClass()
+{
+    static JSClassRef jsClass;
+    if (!jsClass) {
+        JSClassDefinition definition = kJSClassDefinitionEmpty;
+        definition.className = "UIProcess";
+        definition.parentClass = 0;
+        definition.staticValues = staticValues();
+        definition.staticFunctions = staticFunctions();
+        definition.initialize = initialize;
+        definition.finalize = finalize;
+        jsClass = JSClassCreate(&definition);
+    }
+    return jsClass;
+}
+
+inline JSIPC* JSIPC::unwrap(JSObjectRef object)
+{
+    return static_cast<JSIPC*>(JSObjectGetPrivate(object));
+}
+
+JSIPC* JSIPC::toWrapped(JSContextRef context, JSValueRef value)
+{
+    if (!context || !value || !JSValueIsObjectOfClass(context, value, wrapperClass()))
+        return nullptr;
+    return unwrap(JSValueToObject(context, value, 0));
+}
+
+void JSIPC::initialize(JSContextRef, JSObjectRef object)
+{
+    unwrap(object)->ref();
+}
+
+void JSIPC::finalize(JSObjectRef object)
+{
+    unwrap(object)->deref();
+}
+
+const JSStaticFunction* JSIPC::staticFunctions()
+{
+    static const JSStaticFunction functions[] = {
+        { "sendMessage", sendMessage, kJSPropertyAttributeDontDelete | kJSPropertyAttributeReadOnly },
+        { "sendSyncMessage", sendSyncMessage, kJSPropertyAttributeDontDelete | kJSPropertyAttributeReadOnly },
+        { 0, 0, 0 }
+    };
+    return functions;
+}
+
+const JSStaticValue* JSIPC::staticValues()
+{
+    static const JSStaticValue values[] = {
+        { "visitedLinkStoreID", visitedLinkStoreID, 0, kJSPropertyAttributeDontDelete | kJSPropertyAttributeReadOnly },
+        { "webPageProxyID", webPageProxyID, 0, kJSPropertyAttributeDontDelete | kJSPropertyAttributeReadOnly },
+        { "frameIdentifier", frameIdentifier, 0, kJSPropertyAttributeDontDelete | kJSPropertyAttributeReadOnly },
+        { "messages", messages, 0, kJSPropertyAttributeDontDelete | kJSPropertyAttributeReadOnly },
+        { 0, 0, 0, 0 }
+    };
+    return values;
+}
+
+static Optional<uint64_t> convertToUint64(JSC::JSValue jsValue)
+{
+    if (jsValue.isNumber()) {
+        double value = jsValue.asNumber();
+        if (value < 0 || trunc(value) != value)
+            return WTF::nullopt;
+        return value;
+    }
+    if (jsValue.isBigInt())
+        return JSC::JSBigInt::toUint64(jsValue);
+    return WTF::nullopt;
+}
+
+static RefPtr<IPC::Connection> processTargetFromArgument(JSC::JSGlobalObject* globalObject, JSValueRef valueRef, JSValueRef* exception)
+{
+    auto scope = DECLARE_CATCH_SCOPE(globalObject->vm());
+    auto name = toJS(globalObject, valueRef).toWTFString(globalObject);
+    if (scope.exception())
+        return nullptr;
+
+    if (name == "UI")
+        return WebProcess::singleton().parentProcessConnection();
+#if ENABLE(GPU_PROCESS)
+    if (name == "GPU")
+        return &WebProcess::singleton().ensureGPUProcessConnection().connection();
+#endif
+    if (name == "Networking")
+        return &WebProcess::singleton().ensureNetworkProcessConnection().connection();
+
+    *exception = toRef(JSC::createTypeError(globalObject, "Target process must be UI, GPU, or Networking"_s));
+    return nullptr;
+}
+
+static Optional<uint64_t> destinationIDFromArgument(JSC::JSGlobalObject* globalObject, JSValueRef valueRef, JSValueRef* exception)
+{
+    auto jsValue = toJS(globalObject, valueRef);
+    auto result = convertToUint64(jsValue);
+    if (!result)
+        *exception = toRef(JSC::createTypeError(globalObject, "destinationID must be an integer"_s));
+    return result;
+}
+
+static Optional<uint64_t> messageIDFromArgument(JSC::JSGlobalObject* globalObject, JSValueRef valueRef, JSValueRef* exception)
+{
+    auto jsValue = toJS(globalObject, valueRef);
+    auto result = convertToUint64(jsValue);
+    if (!result)
+        *exception = toRef(JSC::createTypeError(globalObject, "messageID must be an integer"_s));
+    return result;
+}
+
+static bool encodeTypedArray(IPC::Encoder& encoder, JSContextRef context, JSValueRef valueRef, JSTypedArrayType type, JSValueRef* exception)
+{
+    ASSERT(type != kJSTypedArrayTypeNone);
+
+    auto objectRef = JSValueToObject(context, valueRef, exception);
+    if (!objectRef)
+        return false;
+
+    void* buffer;
+    if (type == kJSTypedArrayTypeArrayBuffer)
+        buffer = JSObjectGetArrayBufferBytesPtr(context, objectRef, exception);
+    else
+        buffer = JSObjectGetTypedArrayBytesPtr(context, objectRef, exception);
+    if (!buffer)
+        return false;
+
+    size_t bufferSize;
+    if (type == kJSTypedArrayTypeArrayBuffer)
+        bufferSize = JSObjectGetArrayBufferByteLength(context, objectRef, exception);
+    else
+        bufferSize = JSObjectGetTypedArrayByteLength(context, objectRef, exception);
+    if (!bufferSize)
+        return false;
+
+    encoder.encodeFixedLengthData(reinterpret_cast<const uint8_t*>(buffer), bufferSize, 1);
+    return true;
+}
+
+static JSValueRef createTypeError(JSContextRef context, const String& message)
+{
+    JSC::JSLockHolder lock(toJS(context)->vm());
+    return toRef(JSC::createTypeError(toJS(context), message));
+}
+
+template<typename RectType> bool encodeRectType(IPC::Encoder& encoder, JSC::JSGlobalObject* globalObject, JSC::JSObject* jsObject)
+{
+    auto& vm = globalObject->vm();
+    auto jsX = jsObject->get(globalObject, JSC::Identifier::fromString(vm, "x"_s));
+    if (!jsX.isNumber())
+        return false;
+    auto jsY = jsObject->get(globalObject, JSC::Identifier::fromString(vm, "y"_s));
+    if (!jsY.isNumber())
+        return false;
+    auto jsWidth = jsObject->get(globalObject, JSC::Identifier::fromString(vm, "width"_s));
+    if (!jsWidth.isNumber())
+        return false;
+    auto jsHeight = jsObject->get(globalObject, JSC::Identifier::fromString(vm, "height"_s));
+    if (!jsHeight.isNumber())
+        return false;
+    encoder << RectType(jsX.asNumber(), jsY.asNumber(), jsWidth.asNumber(), jsHeight.asNumber());
+    return true;
+}
+
+template<typename IntegralType> bool encodeIntegralType(IPC::Encoder& encoder, JSC::JSValue jsValue)
+{
+    if (jsValue.isBigInt()) {
+        // FIXME: Support negative BigInt.
+        auto result = JSC::JSBigInt::toUint64(jsValue);
+        if (!result)
+            return false;
+        encoder << static_cast<IntegralType>(*result);
+        return true;
+    }
+    if (!jsValue.isNumber())
+        return false;
+    double value = jsValue.asNumber();
+    encoder << static_cast<IntegralType>(value);
+    return true;
+}
+
+enum class ArrayMode { Tuple, Vector };
+static bool encodeArgument(IPC::Encoder&, JSIPC&, JSContextRef, JSValueRef, JSValueRef* exception, ArrayMode = ArrayMode::Tuple);
+
+struct VectorEncodeHelper {
+    Ref<JSIPC> jsIPC;
+    JSContextRef context;
+    JSValueRef valueRef;
+    JSValueRef* exception;
+    bool& success;
+
+    void encode(IPC::Encoder& encoder) const
+    {
+        if (!success)
+            return;
+        success = encodeArgument(encoder, jsIPC.get(), context, valueRef, exception, ArrayMode::Vector);
+    }
+};
+
+static bool encodeArgument(IPC::Encoder& encoder, JSIPC& jsIPC, JSContextRef context, JSValueRef valueRef, JSValueRef* exception, ArrayMode arrayMode)
+{
+    auto objectRef = JSValueToObject(context, valueRef, exception);
+    if (!objectRef)
+        return false;
+
+    if (auto type = JSValueGetTypedArrayType(context, objectRef, exception); type != kJSTypedArrayTypeNone)
+        return encodeTypedArray(encoder, context, objectRef, type, exception);
+
+    auto* globalObject = toJS(context);
+    auto& vm = globalObject->vm();
+    JSC::JSLockHolder lock(vm);
+    auto scope = DECLARE_CATCH_SCOPE(globalObject->vm());
+    auto* jsObject = toJS(globalObject, objectRef).getObject();
+    ASSERT(jsObject);
+    if (JSValueIsArray(context, objectRef)) {
+        auto jsLength = jsObject->get(globalObject, JSC::Identifier::fromString(vm, "length"_s));
+        if (scope.exception())
+            return false;
+        if (!jsLength.isNumber()) {
+            *exception = createTypeError(context, "Array length is not a number"_s);
+            return false;
+        }
+        auto length = jsLength.asNumber();
+
+        Vector<VectorEncodeHelper> vector;
+        bool success = true;
+        for (unsigned i = 0; i < length; ++i) {
+            auto itemRef = JSObjectGetPropertyAtIndex(context, objectRef, i, exception);
+            if (!itemRef)
+                return false;
+            vector.append(VectorEncodeHelper { jsIPC, context, itemRef, exception, success });
+        }
+        if (arrayMode == ArrayMode::Tuple) {
+            for (auto& item : vector)
+                item.encode(encoder);
+        } else
+            encoder << vector;
+        return success;
+    }
+
+    auto jsType = jsObject->get(globalObject, JSC::Identifier::fromString(vm, "type"_s));
+    if (scope.exception())
+        return false;
+
+    auto type = jsType.toWTFString(globalObject);
+    if (scope.exception())
+        return false;
+
+    if (type == "IntRect") {
+        if (!encodeRectType<WebCore::IntRect>(encoder, globalObject, jsObject)) {
+            *exception = createTypeError(context, "Failed to convert IntRect"_s);
+            return false;
+        }
+        return true;
+    }
+
+    if (type == "FloatRect") {
+        if (!encodeRectType<WebCore::FloatRect>(encoder, globalObject, jsObject)) {
+            *exception = createTypeError(context, "Failed to convert FloatRect"_s);
+            return false;
+        }
+        return true;
+    }
+
+    if (type == "FrameInfoData") {
+        auto webFrame = makeRefPtr(jsIPC.webFrame());
+        if (!webFrame) {
+            *exception = createTypeError(context, "Failed to get the frame"_s);
+            return false;
+        }
+        encoder << webFrame->info();
+        return true;
+    }
+
+    auto jsValue = jsObject->get(globalObject, JSC::Identifier::fromString(vm, "value"_s));
+    if (scope.exception())
+        return false;
+
+    if (type == "String") {
+        if (jsValue.isUndefinedOrNull()) {
+            encoder << String { };
+            return true;
+        }
+        auto string = jsValue.toWTFString(globalObject);
+        if (scope.exception())
+            return false;
+        encoder << string;
+        return true;
+    }
+
+    if (type == "RGBA") {
+        if (!jsValue.isNumber()) {
+            *exception = createTypeError(context, "RGBA value should be a number"_s);
+            return false;
+        }
+        uint32_t rgba = jsValue.asNumber();
+        encoder << WebCore::Color { WebCore::asSRGBA(WebCore::PackedColor::RGBA(rgba)) };
+        return true;
+    }
+
+    bool integralResult;
+    if (type == "bool")
+        integralResult = encodeIntegralType<bool>(encoder, jsValue);
+    else if (type == "int8_t")
+        integralResult = encodeIntegralType<int8_t>(encoder, jsValue);
+    else if (type == "int16_t")
+        integralResult = encodeIntegralType<int16_t>(encoder, jsValue);
+    else if (type == "int32_t")
+        integralResult = encodeIntegralType<int32_t>(encoder, jsValue);
+    else if (type == "int64_t")
+        integralResult = encodeIntegralType<int64_t>(encoder, jsValue);
+    else if (type == "uint8_t")
+        integralResult = encodeIntegralType<uint8_t>(encoder, jsValue);
+    else if (type == "uint16_t")
+        integralResult = encodeIntegralType<uint16_t>(encoder, jsValue);
+    else if (type == "uint32_t")
+        integralResult = encodeIntegralType<uint32_t>(encoder, jsValue);
+    else if (type == "uint64_t")
+        integralResult = encodeIntegralType<uint64_t>(encoder, jsValue);
+    else {
+        *exception = createTypeError(context, "Bad type name"_s);
+        return false;
+    }
+    if (!integralResult) {
+        *exception = createTypeError(context, "Failed to encode an integer"_s);
+        return false;
+    }
+    return true;
+}
+
+JSValueRef JSIPC::sendMessage(JSContextRef context, JSObjectRef, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+    auto* globalObject = toJS(context);
+    JSC::JSLockHolder lock(globalObject->vm());
+    auto jsIPC = makeRefPtr(toWrapped(context, thisObject));
+    if (!jsIPC) {
+        *exception = toRef(JSC::createTypeError(toJS(context), "Wrong type"_s));
+        return JSValueMakeUndefined(context);
+    }
+
+    if (argumentCount < 3) {
+        *exception = toRef(JSC::createTypeError(toJS(context), "Must specify the target process, desination 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);
+
+    auto destinationID = destinationIDFromArgument(globalObject, arguments[1], exception);
+    if (!destinationID)
+        return JSValueMakeUndefined(context);
+
+    auto messageID = messageIDFromArgument(globalObject, arguments[2], exception);
+    if (!messageID)
+        return JSValueMakeUndefined(context);
+
+    auto encoder = makeUnique<IPC::Encoder>(static_cast<IPC::MessageName>(static_cast<uint64_t>(*messageID)), *destinationID);
+
+    if (argumentCount > 3) {
+        if (!encodeArgument(*encoder, *jsIPC, context, arguments[3], exception))
+            return JSValueMakeUndefined(context);
+    }
+
+    // FIXME: Add the support for specifying IPC options.
+
+    connection->sendMessage(WTFMove(encoder), { });
+
+    return JSValueMakeUndefined(context);
+}
+
+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());
+    auto jsIPC = makeRefPtr(toWrapped(context, thisObject));
+    if (!jsIPC) {
+        *exception = toRef(JSC::createTypeError(toJS(context), "Wrong type"_s));
+        return JSValueMakeUndefined(context);
+    }
+
+    if (argumentCount < 4) {
+        *exception = toRef(JSC::createTypeError(toJS(context), "Must specify the target process, desination ID, message ID, and timeout as the first four arguments"_s));
+        return JSValueMakeUndefined(context);
+    }
+
+    auto connection = processTargetFromArgument(globalObject, arguments[0], exception);
+    if (!connection)
+        return JSValueMakeUndefined(context);
+
+    auto destinationID = destinationIDFromArgument(globalObject, arguments[1], exception);
+    if (!destinationID)
+        return JSValueMakeUndefined(context);
+
+    auto messageID = messageIDFromArgument(globalObject, arguments[2], exception);
+    if (!messageID)
+        return JSValueMakeUndefined(context);
+
+    Seconds timeout;
+    {
+        auto jsValue = toJS(globalObject, arguments[3]);
+        if (!jsValue.isNumber()) {
+            *exception = toRef(JSC::createTypeError(globalObject, "timeout must be a number"_s));
+            return JSValueMakeUndefined(context);
+        }
+        timeout = Seconds { jsValue.asNumber() };
+    }
+    
+    // FIXME: Support the options.
+
+    uint64_t syncRequestID = 0;
+    auto encoder = connection->createSyncMessageEncoder(static_cast<IPC::MessageName>(static_cast<uint64_t>(*messageID)), *destinationID, syncRequestID);
+
+    if (argumentCount > 4) {
+        if (!encodeArgument(*encoder, *jsIPC, context, arguments[4], exception))
+            return JSValueMakeUndefined(context);
+    }
+
+    auto replyDecoder = connection->sendSyncMessage(syncRequestID, WTFMove(encoder), timeout, { });
+    // FIXME: Decode the reply.
+
+    return JSValueMakeUndefined(context);
+}
+
+JSValueRef JSIPC::visitedLinkStoreID(JSContextRef context, JSObjectRef thisObject, JSStringRef, JSValueRef* exception)
+{
+    return retrieveID(context, thisObject, exception, [](JSIPC& wrapped) {
+        auto webPage = makeRef(*wrapped.m_webPage);
+        return webPage->visitedLinkTableID();
+    });
+}
+
+JSValueRef JSIPC::webPageProxyID(JSContextRef context, JSObjectRef thisObject, JSStringRef, JSValueRef* exception)
+{
+    return retrieveID(context, thisObject, exception, [](JSIPC& wrapped) {
+        return wrapped.m_webPage->webPageProxyID();
+    });
+}
+
+JSValueRef JSIPC::frameIdentifier(JSContextRef context, JSObjectRef thisObject, JSStringRef, JSValueRef* exception)
+{
+    return retrieveID(context, thisObject, exception, [](JSIPC& wrapped) {
+        return wrapped.m_webFrame->frameID().toUInt64();
+    });
+}
+
+JSValueRef JSIPC::retrieveID(JSContextRef context, JSObjectRef thisObject, JSValueRef* exception, const WTF::Function<uint64_t(JSIPC&)>& callback)
+{
+    auto* globalObject = toJS(context);
+    auto& vm = globalObject->vm();
+    JSC::JSLockHolder lock(vm);
+
+    RefPtr<JSIPC> wrapped = toWrapped(context, thisObject);
+    if (!wrapped) {
+        *exception = toRef(JSC::createTypeError(toJS(context), "Wrong type"_s));
+        return JSValueMakeUndefined(context);
+    }
+
+    auto id = callback(*wrapped);
+    JSC::JSCell* jsValue = JSC::JSBigInt::createFrom(globalObject, id);
+    return toRef(vm, jsValue);
+}
+
+JSValueRef JSIPC::messages(JSContextRef context, JSObjectRef thisObject, JSStringRef, JSValueRef* exception)
+{
+    auto* globalObject = toJS(context);
+    auto& vm = globalObject->vm();
+    JSC::JSLockHolder lock(vm);
+
+    auto* impl = toWrapped(context, thisObject);
+    if (!impl) {
+        *exception = toRef(JSC::createTypeError(toJS(context), "Wrong type"_s));
+        return JSValueMakeUndefined(context);
+    }
+
+    JSC::JSObject* messagesObject = constructEmptyObject(globalObject, globalObject->objectPrototype());
+    auto nameIdent = JSC::Identifier::fromString(vm, "name");
+    for (unsigned i = 0; i < static_cast<unsigned>(IPC::MessageName::Last); ++i) {
+        auto* messageName = description(static_cast<IPC::MessageName>(i));
+
+        JSC::JSObject* dictionary = constructEmptyObject(globalObject, globalObject->objectPrototype());
+        dictionary->putDirect(vm, nameIdent, JSC::JSValue(i));
+
+        // FIXME: Add argument names.
+
+        messagesObject->putDirect(vm, JSC::Identifier::fromString(vm, messageName), dictionary);
+    }
+
+    return toRef(vm, messagesObject);
+}
+
+void inject(WebPage& webPage, WebFrame& webFrame, WebCore::DOMWrapperWorld& world)
+{
+    auto* globalObject = webFrame.coreFrame()->script().globalObject(world);
+
+    auto& vm = globalObject->vm();
+    JSC::JSLockHolder lock(vm);
+    auto scope = DECLARE_CATCH_SCOPE(vm);
+    auto wrapped = JSIPC::create(webPage, webFrame);
+    JSObjectRef wrapperObject = JSObjectMake(toGlobalRef(globalObject), JSIPC::wrapperClass(), wrapped.ptr());
+    globalObject->putDirect(vm, JSC::Identifier::fromString(vm, "IPC"), toJS(globalObject, wrapperObject));
+
+    scope.clearException();
+}
+
+} // namespace IPCTestingAPI
+
+} // namespace WebKit
+
+#endif

Added: trunk/Source/WebKit/WebProcess/WebPage/IPCTestingAPI.h (0 => 268239)


--- trunk/Source/WebKit/WebProcess/WebPage/IPCTestingAPI.h	                        (rev 0)
+++ trunk/Source/WebKit/WebProcess/WebPage/IPCTestingAPI.h	2020-10-09 00:48:35 UTC (rev 268239)
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2020 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)
+
+namespace WebCore {
+
+class DOMWrapperWorld;
+class Frame;
+
+};
+
+namespace WebKit {
+
+class WebFrame;
+class WebPage;
+
+namespace IPCTestingAPI {
+
+void inject(WebPage&, WebFrame&, WebCore::DOMWrapperWorld&);
+
+}
+
+} // namespace WebKit
+
+#endif

Modified: trunk/Source/WebKit/WebProcess/WebPage/WebFrame.h (268238 => 268239)


--- trunk/Source/WebKit/WebProcess/WebPage/WebFrame.h	2020-10-09 00:45:29 UTC (rev 268238)
+++ trunk/Source/WebKit/WebProcess/WebPage/WebFrame.h	2020-10-09 00:48:35 UTC (rev 268239)
@@ -63,7 +63,7 @@
 struct FrameInfoData;
 struct WebsitePoliciesData;
 
-class WebFrame : public API::ObjectImpl<API::Object::Type::BundleFrame> {
+class WebFrame : public API::ObjectImpl<API::Object::Type::BundleFrame>, public CanMakeWeakPtr<WebFrame> {
 public:
     static Ref<WebFrame> create() { return adoptRef(*new WebFrame); }
     static Ref<WebFrame> createSubframe(WebPage*, const String& frameName, WebCore::HTMLFrameOwnerElement*);

Modified: trunk/Source/WebKit/WebProcess/WebPage/WebPage.cpp (268238 => 268239)


--- trunk/Source/WebKit/WebProcess/WebPage/WebPage.cpp	2020-10-09 00:45:29 UTC (rev 268238)
+++ trunk/Source/WebKit/WebProcess/WebPage/WebPage.cpp	2020-10-09 00:48:35 UTC (rev 268239)
@@ -789,6 +789,10 @@
         WebProcess::singleton().ensureGPUProcessConnection().updateParameters(parameters);
 #endif
 
+#if ENABLE(IPC_TESTING_API)
+    m_visitedLinkTableID = parameters.visitedLinkTableID;
+#endif
+
 #if ENABLE(VP9)
     if (parameters.shouldEnableVP9Decoder)
         WebProcess::singleton().enableVP9Decoder();
@@ -3784,6 +3788,10 @@
     WebProcess::singleton().supplement<RemoteMediaPlayerManager>()->updatePreferences(settings);
     WebProcess::singleton().setUseGPUProcessForMedia(settings.useGPUProcessForMediaEnabled());
 #endif
+
+#if ENABLE(IPC_TESTING_API)
+    m_ipcTestingAPIEnabled = store.getBoolValueForKey(WebPreferencesKey::ipcTestingAPIEnabledKey());
+#endif
 }
 
 #if ENABLE(DATA_DETECTION)

Modified: trunk/Source/WebKit/WebProcess/WebPage/WebPage.h (268238 => 268239)


--- trunk/Source/WebKit/WebProcess/WebPage/WebPage.h	2020-10-09 00:45:29 UTC (rev 268238)
+++ trunk/Source/WebKit/WebProcess/WebPage/WebPage.h	2020-10-09 00:48:35 UTC (rev 268239)
@@ -1339,6 +1339,12 @@
 
     void updateCORSDisablingPatterns(Vector<String>&&);
 
+#if ENABLE(IPC_TESTING_API)
+    bool ipcTestingAPIEnabled() const { return m_ipcTestingAPIEnabled; }
+    uint64_t webPageProxyID() const { return messageSenderDestinationID(); }
+    uint64_t visitedLinkTableID() const { return m_visitedLinkTableID; }
+#endif
+
     void getProcessDisplayName(CompletionHandler<void(String&&)>&&);
 
     WebCore::AllowsContentJavaScript allowsContentJavaScriptFromMostRecentNavigation() const { return m_allowsContentJavaScriptFromMostRecentNavigation; }
@@ -2171,6 +2177,11 @@
     bool m_canUseCredentialStorage { true };
 
     Vector<String> m_corsDisablingPatterns;
+
+#if ENABLE(IPC_TESTING_API)
+    bool m_ipcTestingAPIEnabled { false };
+    uint64_t m_visitedLinkTableID;
+#endif
 };
 
 #if !PLATFORM(IOS_FAMILY)

Modified: trunk/Tools/ChangeLog (268238 => 268239)


--- trunk/Tools/ChangeLog	2020-10-09 00:45:29 UTC (rev 268238)
+++ trunk/Tools/ChangeLog	2020-10-09 00:48:35 UTC (rev 268239)
@@ -1,3 +1,16 @@
+2020-10-08  Ryosuke Niwa  <rn...@webkit.org>
+
+        Make it possible to send an arbitrary IPC message from _javascript_
+        https://bugs.webkit.org/show_bug.cgi?id=217423
+        <rdar://problem/69969351>
+
+        Reviewed by Geoffrey Garen.
+
+        * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
+        * TestWebKitAPI/Tests/WebKitCocoa/IPCTestingAPI.mm: Added.
+        (-[IPCTestingAPIDelegate webView:runJavaScriptAlertPanelWithMessage:initiatedByFrame:completionHandler:]):
+        (TEST):
+
 2020-10-08  Sam Weinig  <wei...@apple.com>
 
         Refactor TestOptions code in WebKitTestRunner to make it easier to rationalize and extend

Modified: trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj (268238 => 268239)


--- trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj	2020-10-09 00:45:29 UTC (rev 268238)
+++ trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj	2020-10-09 00:48:35 UTC (rev 268239)
@@ -847,6 +847,7 @@
 		9B4F8FA7159D52DD002D9F94 /* HTMLCollectionNamedItem.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 9B4F8FA6159D52CA002D9F94 /* HTMLCollectionNamedItem.html */; };
 		9B59F12A2034086F009E63D5 /* mso-list-compat-mode.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 9B59F12920340854009E63D5 /* mso-list-compat-mode.html */; };
 		9B62630C1F8C25C8007EE29B /* copy-url.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 9B62630B1F8C2510007EE29B /* copy-url.html */; };
+		9B6D9FF9252EFDE500A51640 /* IPCTestingAPI.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9B6D9FF8252EFDE500A51640 /* IPCTestingAPI.mm */; };
 		9B7A37C41F8AEBA5004AA228 /* CopyURL.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9B7A37C21F8AEBA5004AA228 /* CopyURL.mm */; };
 		9B7D740F1F8378770006C432 /* paste-rtfd.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 9B7D740E1F8377E60006C432 /* paste-rtfd.html */; };
 		9B9332CE2320C745002D50E8 /* cocoa-writer-markup-with-lists.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 9B9332CD2320C73E002D50E8 /* cocoa-writer-markup-with-lists.html */; };
@@ -2459,6 +2460,7 @@
 		9B4F8FA6159D52CA002D9F94 /* HTMLCollectionNamedItem.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = HTMLCollectionNamedItem.html; sourceTree = "<group>"; };
 		9B59F12920340854009E63D5 /* mso-list-compat-mode.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = "mso-list-compat-mode.html"; sourceTree = "<group>"; };
 		9B62630B1F8C2510007EE29B /* copy-url.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = "copy-url.html"; sourceTree = "<group>"; };
+		9B6D9FF8252EFDE500A51640 /* IPCTestingAPI.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = IPCTestingAPI.mm; sourceTree = "<group>"; };
 		9B79164F1BD89D0D00D50B8F /* FirstResponderScrollingPosition.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FirstResponderScrollingPosition.mm; sourceTree = "<group>"; };
 		9B7A37C21F8AEBA5004AA228 /* CopyURL.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = CopyURL.mm; sourceTree = "<group>"; };
 		9B7D740E1F8377E60006C432 /* paste-rtfd.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = "paste-rtfd.html"; sourceTree = "<group>"; };
@@ -3270,6 +3272,7 @@
 				CED73D35246F204C00DAE327 /* InsertTextAlternatives.mm */,
 				2DB0232E1E4E871800707123 /* InteractionDeadlockAfterCrash.mm */,
 				2D116E1223E0CB3900208900 /* iOSMouseSupport.mm */,
+				9B6D9FF8252EFDE500A51640 /* IPCTestingAPI.mm */,
 				5C69BDD41F82A7EB000F4F4B /* _javascript_DuringNavigation.mm */,
 				5C0160C021A132320077FA32 /* JITEnabled.mm */,
 				C25CCA051E51380B0026CB8A /* LineBreaking.mm */,
@@ -5226,6 +5229,7 @@
 				7A909A821D877480007E10F8 /* IntRectTests.cpp in Sources */,
 				7A909A831D877480007E10F8 /* IntSizeTests.cpp in Sources */,
 				2D116E1323E0CB3A00208900 /* iOSMouseSupport.mm in Sources */,
+				9B6D9FF9252EFDE500A51640 /* IPCTestingAPI.mm in Sources */,
 				5C0BF8931DD599BD00B00328 /* IsNavigationActionTrusted.mm in Sources */,
 				CD5FF49F2162E943004BD86F /* ISOBox.cpp in Sources */,
 				5C69BDD51F82A7EF000F4F4B /* _javascript_DuringNavigation.mm in Sources */,

Added: trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/IPCTestingAPI.mm (0 => 268239)


--- trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/IPCTestingAPI.mm	                        (rev 0)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/IPCTestingAPI.mm	2020-10-09 00:48:35 UTC (rev 268239)
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#import "config.h"
+
+#import "TestWKWebView.h"
+#import "Utilities.h"
+#import <WebKit/WKNavigationDelegatePrivate.h>
+#import <WebKit/WKPreferencesPrivate.h>
+#import <WebKit/WKWebView.h>
+#import <WebKit/_WKInternalDebugFeature.h>
+#import <wtf/RetainPtr.h>
+
+static bool done = false;
+static RetainPtr<NSString> alertMessage;
+
+@interface IPCTestingAPIDelegate : NSObject <WKUIDelegate>
+@end
+    
+@implementation IPCTestingAPIDelegate
+
+- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler
+{
+    alertMessage = message;
+    done = true;
+    completionHandler();
+}
+
+@end
+
+TEST(IPCTestingAPI, IsDisabledByDefault)
+{
+    auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 400, 400)]);
+
+    auto delegate = adoptNS([[IPCTestingAPIDelegate alloc] init]);
+    [webView setUIDelegate:delegate.get()];
+
+    done = false;
+    [webView synchronouslyLoadHTMLString:@"<!DOCTYPE html><script>alert(typeof(IPC));</script>"];
+    TestWebKitAPI::Util::run(&done);
+    EXPECT_STREQ([alertMessage UTF8String], "undefined");
+}
+
+#if ENABLE(IPC_TESTING_API)
+
+TEST(IPCTestingAPI, CanSendAlert)
+{
+    RetainPtr<WKWebViewConfiguration> configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
+    for (_WKInternalDebugFeature *feature in [WKPreferences _internalDebugFeatures]) {
+        if ([feature.key isEqualToString:@"IPCTestingAPIEnabled"]) {
+            [[configuration preferences] _setEnabled:YES forInternalDebugFeature:feature];
+            break;
+        }
+    }
+    RetainPtr<TestWKWebView> webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 300, 300) configuration:configuration.get()]);
+
+    auto delegate = adoptNS([[IPCTestingAPIDelegate alloc] init]);
+    [webView setUIDelegate:delegate.get()];
+
+    done = false;
+    [webView synchronouslyLoadHTMLString:@"<!DOCTYPE html><script>IPC.sendSyncMessage('UI', IPC.webPageProxyID, IPC.messages.WebPageProxy_RunJavaScriptAlert.name, 100,"
+        "[{type: 'uint64_t', value: IPC.frameIdentifier}, {type: 'FrameInfoData'}, {'type': 'String', 'value': 'hi'}]);</script>"];
+    TestWebKitAPI::Util::run(&done);
+
+    EXPECT_STREQ([alertMessage UTF8String], "hi");
+}
+
+#endif
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to