Changeset 268431 in webkit


Ignore:
Timestamp:
Oct 13, 2020 4:20:54 PM (4 years ago)
Author:
rniwa@webkit.org
Message:

IPC testing JS API should expose a reply and describe the list of arguments for each message
https://bugs.webkit.org/show_bug.cgi?id=217565

Reviewed by Geoffrey Garen.

Source/WebKit:

This patch makes IPC.sendMessage and IPC.sendSyncMessage decode the reply. IPC.sendSyncMessage now returns
a dictionary with two keys: "buffer" and "arguments", the first of which returns ArrayBuffer of the decoded
message reply and the second of which is an array of decoded arguments where there was an appropriate JS
binding code existed for the argument type. IPC.sendMessage now returns a Promise which can either resolve
with the same dictionary as IPC.sendSyncMessage or reject when the decoding fails.

In addition, this patch exposes a dictionary describing each IPC message argument's type and parameter name.

In order to add these two functionalities, this patch adds a new step in generate-message-receiver.py to
generate MessageArgumentDescriptions.cpp, which contains functions which know how to decode arguments of
any IPC message and create a JS dictionary describing it as well as functions that return descriptions of
arguments or reply arguments.

Finally, this patch adds encoders for a few types found to be very common after r268239 had been landed.

Tests: TestWebKitAPI.IPCTestingAPI.DecodesReplyArgumentsForPrompt

TestWebKitAPI.IPCTestingAPI.DecodesReplyArgumentsForAsyncMessage
TestWebKitAPI.IPCTestingAPI.DescribesArguments

  • CMakeLists.txt:
  • DerivedSources-output.xcfilelist:
  • DerivedSources.make:
  • Platform/IPC/Decoder.h:

(IPC::Decoder::buffer const):

  • Platform/IPC/JSIPCBinding.h: Added.

(jsValueForDecodedArgumentValue): Added. A template function to construct a JS value for a given C++ value.
(jsValueForDecodedNumericArgumentValue): Added. A helper for constructing a JS value for numeric values.
(jsValueForDecodedArgumentRect): Added. Ditto for IntRect and FloatRect.
(DecodedArgumentJSValueConverter): Added. A helper class to construct JS values for a tuple of values using
partial template specializations.
(DecodedArgumentJSValueConverter::convert): Added.
(jsValueForArgumentTuple): Added. A helper to construct a JS array for the decoded IPC arguments.
(jsValueForDecodedArguments): Added.

  • Platform/IPC/MessageArgumentDescriptions.h: Added.

(IPC::ArgumentDescription): Added.

  • Scripts/generate-message-receiver.py:

(main): Generate MessageArgumentDescriptions.cpp.

  • Scripts/webkit/messages.py:

(headers_for_type): Removed the special case for PaymentMethodUpdate now that it's in its own header. Also
added made webrtc::WebKitEncodedFrameInfo include LibWebRTCEnumTraits.h as it uses webrtc::VideoFrameType.
(collect_header_conditions_for_receiver): Extracted from generate_message_handler.
(generate_header_includes_from_conditions): Ditto.
(generate_message_handler):
(generate_js_value_conversion_function): Added.
(generate_js_argument_descriptions): Added.
(generate_message_argument_description_implementation): Added.

  • Shared/ApplePay/ApplePayPaymentSetupFeaturesWebKit.h: Fixed a bug that we were not forward declaring NSArray.
  • SourcesCocoa.txt: Added MessageArgumentDescriptions.cpp as a non-unified cpp file as its size is around 1MB.
  • WebKit.xcodeproj/project.pbxproj:
  • WebProcess/WebPage/IPCTestingAPI.cpp:

(WebKit::IPCTestingAPI::JSIPC::staticValues): Added the session ID and page ID as static variables.
(WebKit::IPCTestingAPI::encodePointType): Added.
(WebKit::IPCTestingAPI::encodeRectType): Fixed the bug was that this code wasn't checking for any exceptions.
(WebKit::IPCTestingAPI::encodeNumericType): Renamed from encodeIntegralType since this function is now used
to encode double and float, not just integral types.
(WebKit::IPCTestingAPI::encodeArgument): Added the support for IntPoint, FloatPoint, URL, RegistrableDomain,
double, and float all of which turned out to be in the top 20 most common types.
(WebKit::IPCTestingAPI::jsResultFromReplyDecoder): Added.
(WebKit::IPCTestingAPI::JSIPC::sendMessage): Added the code to return Promise when there is a reply and resolve
it with the JS object describing the decoded argument. We use messageReplyArgumentDescriptions to figure out
whether there is a reply or not.
(WebKit::IPCTestingAPI::JSIPC::sendSyncMessage): Decode the reply and return a JS object which describes it.
(WebKit::IPCTestingAPI::JSIPC::frameID): Renamed from frameIdentifier to be consistent.
(WebKit::IPCTestingAPI::JSIPC::pageID): Added.
(WebKit::IPCTestingAPI::JSIPC::sessionID): Added.
(WebKit::IPCTestingAPI::createJSArrayForArgumentDescriptions): Added.
(WebKit::IPCTestingAPI::JSIPC::messages): Added the code to generate descriptions for arguments.

Tools:

Added tests for decoding replies for sync and async messages and one for argument descriptions.

  • TestWebKitAPI/Tests/WebKitCocoa/IPCTestingAPI.mm:

(-[IPCTestingAPIDelegate webView:runJavaScriptTextInputPanelWithPrompt:defaultText:initiatedByFrame:completionHandler:]):
(-[IPCTestingAPIDelegate _webView:webContentProcessDidTerminateWithReason:]):
(IPCTestingAPI.DecodesReplyArgumentsForPrompt):
(IPCTestingAPI.DecodesReplyArgumentsForAsyncMessage):
(IPCTestingAPI.DescribesArguments):

Location:
trunk
Files:
2 added
13 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebKit/CMakeLists.txt

    r268342 r268431  
    429429    add_custom_command(
    430430        OUTPUT
     431            ${WebKit_DERIVED_SOURCES_DIR}/MessageArgumentDescriptions.cpp
    431432            ${WebKit_DERIVED_SOURCES_DIR}/MessageNames.cpp
    432433            ${WebKit_DERIVED_SOURCES_DIR}/MessageNames.h
  • trunk/Source/WebKit/ChangeLog

    r268428 r268431  
     12020-10-12  Ryosuke Niwa  <rniwa@webkit.org>
     2
     3        IPC testing JS API should expose a reply and describe the list of arguments for each message
     4        https://bugs.webkit.org/show_bug.cgi?id=217565
     5
     6        Reviewed by Geoffrey Garen.
     7
     8        This patch makes IPC.sendMessage and IPC.sendSyncMessage decode the reply. IPC.sendSyncMessage now returns
     9        a dictionary with two keys: "buffer" and "arguments", the first of which returns ArrayBuffer of the decoded
     10        message reply and the second of which is an array of decoded arguments where there was an appropriate JS
     11        binding code existed for the argument type. IPC.sendMessage now returns a Promise which can either resolve
     12        with the same dictionary as IPC.sendSyncMessage or reject when the decoding fails.
     13
     14        In addition, this patch exposes a dictionary describing each IPC message argument's type and parameter name.
     15
     16        In order to add these two functionalities, this patch adds a new step in generate-message-receiver.py to
     17        generate MessageArgumentDescriptions.cpp, which contains functions which know how to decode arguments of
     18        any IPC message and create a JS dictionary describing it as well as functions that return descriptions of
     19        arguments or reply arguments.
     20
     21        Finally, this patch adds encoders for a few types found to be very common after r268239 had been landed.
     22
     23        Tests: TestWebKitAPI.IPCTestingAPI.DecodesReplyArgumentsForPrompt
     24               TestWebKitAPI.IPCTestingAPI.DecodesReplyArgumentsForAsyncMessage
     25               TestWebKitAPI.IPCTestingAPI.DescribesArguments
     26
     27        * CMakeLists.txt:
     28        * DerivedSources-output.xcfilelist:
     29        * DerivedSources.make:
     30        * Platform/IPC/Decoder.h:
     31        (IPC::Decoder::buffer const):
     32        * Platform/IPC/JSIPCBinding.h: Added.
     33        (jsValueForDecodedArgumentValue): Added. A template function to construct a JS value for a given C++ value.
     34        (jsValueForDecodedNumericArgumentValue): Added. A helper for constructing a JS value for numeric values.
     35        (jsValueForDecodedArgumentRect): Added. Ditto for IntRect and FloatRect.
     36        (DecodedArgumentJSValueConverter): Added. A helper class to construct JS values for a tuple of values using
     37        partial template specializations.
     38        (DecodedArgumentJSValueConverter::convert): Added.
     39        (jsValueForArgumentTuple): Added. A helper to construct a JS array for the decoded IPC arguments.
     40        (jsValueForDecodedArguments): Added.
     41        * Platform/IPC/MessageArgumentDescriptions.h: Added.
     42        (IPC::ArgumentDescription): Added.
     43        * Scripts/generate-message-receiver.py:
     44        (main): Generate MessageArgumentDescriptions.cpp.
     45        * Scripts/webkit/messages.py:
     46        (headers_for_type): Removed the special case for PaymentMethodUpdate now that it's in its own header. Also
     47        added made webrtc::WebKitEncodedFrameInfo include LibWebRTCEnumTraits.h as it uses webrtc::VideoFrameType.
     48        (collect_header_conditions_for_receiver): Extracted from generate_message_handler.
     49        (generate_header_includes_from_conditions): Ditto.
     50        (generate_message_handler):
     51        (generate_js_value_conversion_function): Added.
     52        (generate_js_argument_descriptions): Added.
     53        (generate_message_argument_description_implementation): Added.
     54        * Shared/ApplePay/ApplePayPaymentSetupFeaturesWebKit.h: Fixed a bug that we were not forward declaring NSArray.
     55        * SourcesCocoa.txt: Added MessageArgumentDescriptions.cpp as a non-unified cpp file as its size is around 1MB.
     56        * WebKit.xcodeproj/project.pbxproj:
     57        * WebProcess/WebPage/IPCTestingAPI.cpp:
     58        (WebKit::IPCTestingAPI::JSIPC::staticValues): Added the session ID and page ID as static variables.
     59        (WebKit::IPCTestingAPI::encodePointType): Added.
     60        (WebKit::IPCTestingAPI::encodeRectType): Fixed the bug was that this code wasn't checking for any exceptions.
     61        (WebKit::IPCTestingAPI::encodeNumericType): Renamed from encodeIntegralType since this function is now used
     62        to encode double and float, not just integral types.
     63        (WebKit::IPCTestingAPI::encodeArgument): Added the support for IntPoint, FloatPoint, URL, RegistrableDomain,
     64        double, and float all of which turned out to be in the top 20 most common types.
     65        (WebKit::IPCTestingAPI::jsResultFromReplyDecoder): Added.
     66        (WebKit::IPCTestingAPI::JSIPC::sendMessage): Added the code to return Promise when there is a reply and resolve
     67        it with the JS object describing the decoded argument. We use messageReplyArgumentDescriptions to figure out
     68        whether there is a reply or not.
     69        (WebKit::IPCTestingAPI::JSIPC::sendSyncMessage): Decode the reply and return a JS object which describes it.
     70        (WebKit::IPCTestingAPI::JSIPC::frameID): Renamed from frameIdentifier to be consistent.
     71        (WebKit::IPCTestingAPI::JSIPC::pageID): Added.
     72        (WebKit::IPCTestingAPI::JSIPC::sessionID): Added.
     73        (WebKit::IPCTestingAPI::createJSArrayForArgumentDescriptions): Added.
     74        (WebKit::IPCTestingAPI::JSIPC::messages): Added the code to generate descriptions for arguments.
     75
    1762020-10-13  Ellie Epskamp-Hunt  <eepskamphunt@apple.com>
    277
  • trunk/Source/WebKit/DerivedSources-output.xcfilelist

    r268342 r268431  
    6969$(BUILT_PRODUCTS_DIR)/DerivedSources/WebKit2/MediaPlayerPrivateRemoteMessages.h
    7070$(BUILT_PRODUCTS_DIR)/DerivedSources/WebKit2/MediaPlayerPrivateRemoteMessagesReplies.h
     71$(BUILT_PRODUCTS_DIR)/DerivedSources/WebKit2/MessageArgumentDescriptions.cpp
    7172$(BUILT_PRODUCTS_DIR)/DerivedSources/WebKit2/MessageNames.cpp
    7273$(BUILT_PRODUCTS_DIR)/DerivedSources/WebKit2/MessageNames.h
  • trunk/Source/WebKit/DerivedSources.make

    r268342 r268431  
    258258MESSAGE_REPLIES_FILES := $(addsuffix MessagesReplies.h,$(notdir $(MESSAGE_RECEIVERS)))
    259259
    260 GENERATED_MESSAGES_FILES := $(MESSAGE_RECEIVER_FILES) $(MESSAGES_FILES) $(MESSAGE_REPLIES_FILES) MessageNames.h MessageNames.cpp
     260GENERATED_MESSAGES_FILES := $(MESSAGE_RECEIVER_FILES) $(MESSAGES_FILES) $(MESSAGE_REPLIES_FILES) MessageNames.h MessageNames.cpp MessageArgumentDescriptions.cpp
    261261GENERATED_MESSAGES_FILES_AS_PATTERNS := $(subst .,%,$(GENERATED_MESSAGES_FILES))
    262262
  • trunk/Source/WebKit/Platform/IPC/Decoder.h

    r263208 r268431  
    7373    static std::unique_ptr<Decoder> unwrapForTesting(Decoder&);
    7474
     75    const uint8_t* buffer() const { return m_buffer; }
    7576    size_t length() const { return m_bufferEnd - m_buffer; }
    7677
  • trunk/Source/WebKit/Scripts/generate-message-receiver.py

    r261461 r268431  
    3535    first_arg = True
    3636    second_arg = False
     37    receiver_header_files = []
    3738    for parameter in argv:
    3839        if first_arg:
     
    5455            implementation_output.write(webkit.messages.generate_message_handler(receiver))
    5556
    56         with open('%sMessages.h' % receiver_name, "w+") as header_output:
     57        receiver_message_header = '%sMessages.h' % receiver_name
     58        receiver_header_files.append(receiver_message_header)
     59        with open(receiver_message_header, "w+") as header_output:
    5760            header_output.write(webkit.messages.generate_messages_header(receiver))
    5861
     
    6669        message_names_implementation_output.write(webkit.messages.generate_message_names_implementation(receivers))
    6770
     71    with open('MessageArgumentDescriptions.cpp', "w+") as message_descriptions_implementation_output:
     72        message_descriptions_implementation_output.write(webkit.messages.generate_message_argument_description_implementation(receivers, receiver_header_files))
     73
    6874    return 0
    6975
  • trunk/Source/WebKit/Scripts/webkit/messages.py

    r268372 r268431  
    624624        'WebCore::PasteboardWebContent': ['<WebCore/Pasteboard.h>'],
    625625        'WebCore::PaymentAuthorizationResult': ['<WebCore/ApplePaySessionPaymentRequest.h>'],
    626         'WebCore::PaymentMethodUpdate': ['<WebCore/ApplePaySessionPaymentRequest.h>'],
    627626        'WebCore::PlatformTextTrackData': ['<WebCore/PlatformTextTrack.h>'],
    628627        'WebCore::PluginInfo': ['<WebCore/PluginData.h>'],
     
    688687        'struct WebKit::WebUserStyleSheetData': ['"WebUserContentControllerDataTypes.h"'],
    689688        'struct WebKit::WebScriptMessageHandlerData': ['"WebUserContentControllerDataTypes.h"'],
    690         'webrtc::WebKitEncodedFrameInfo': ['<webrtc/sdk/WebKit/WebKitEncoder.h>'],
     689        'webrtc::WebKitEncodedFrameInfo': ['<webrtc/sdk/WebKit/WebKitEncoder.h>', '<WebCore/LibWebRTCEnumTraits.h>'],
    691690        'webrtc::WebKitRTPFragmentationHeader': ['<webrtc/sdk/WebKit/WebKitEncoder.h>'],
    692691    }
     
    715714
    716715
    717 def generate_message_handler(receiver):
    718     header_conditions = {
    719         '"%s"' % messages_header_filename(receiver): [None],
    720         '"HandleMessage.h"': [None],
    721         '"Decoder.h"': [None],
    722     }
    723 
     716def collect_header_conditions_for_receiver(receiver, header_conditions):
    724717    type_conditions = {}
    725718    for parameter in receiver.iterparameters():
     
    764757                    header_conditions[header].append(message.condition)
    765758
    766     result = []
    767 
    768     result.append(_license_header)
    769     result.append('#include "config.h"\n')
    770     result.append('\n')
    771 
    772     if receiver.condition:
    773         result.append('#if %s\n\n' % receiver.condition)
    774 
    775     result.append('#include "%s.h"\n\n' % receiver.name)
     759    return header_conditions
     760
     761
     762def generate_header_includes_from_conditions(header_conditions):
     763    result = []
    776764    for header in sorted(header_conditions):
    777765        if header_conditions[header] and not None in header_conditions[header]:
     
    781769        else:
    782770            result += ['#include %s\n' % header]
     771    return result
     772
     773
     774def generate_message_handler(receiver):
     775    header_conditions = {
     776        '"%s"' % messages_header_filename(receiver): [None],
     777        '"HandleMessage.h"': [None],
     778        '"Decoder.h"': [None],
     779    }
     780
     781    collect_header_conditions_for_receiver(receiver, header_conditions)
     782
     783    result = []
     784
     785    result.append(_license_header)
     786    result.append('#include "config.h"\n')
     787    result.append('\n')
     788
     789    if receiver.condition:
     790        result.append('#if %s\n\n' % receiver.condition)
     791
     792    result.append('#include "%s.h"\n\n' % receiver.name)
     793    result += generate_header_includes_from_conditions(header_conditions)
    783794    result.append('\n')
    784795
     
    10451056    result.append('} // namespace IPC\n')
    10461057    return ''.join(result)
     1058
     1059
     1060def generate_js_value_conversion_function(result, receivers, function_name, argument_type, predicate=lambda message: True):
     1061    result.append('Optional<JSC::JSValue> %s(JSC::JSGlobalObject* globalObject, MessageName name, Decoder& decoder)\n' % function_name)
     1062    result.append('{\n')
     1063    result.append('    switch (name) {\n')
     1064    for receiver in receivers:
     1065        if receiver.condition:
     1066            result.append('#if %s\n' % receiver.condition)
     1067        prevision_message_condition = None
     1068        for message in receiver.messages:
     1069            if not predicate(message):
     1070                continue
     1071            if prevision_message_condition != message.condition:
     1072                if prevision_message_condition:
     1073                    result.append('#endif\n')
     1074                if message.condition:
     1075                    result.append('#if %s\n' % message.condition)
     1076            prevision_message_condition = message.condition
     1077            result.append('    case MessageName::%s_%s:\n' % (receiver.name, message.name))
     1078            result.append('        return jsValueForDecodedArguments<Messages::%s::%s::%s>(globalObject, decoder);\n' % (receiver.name, message.name, argument_type))
     1079        if prevision_message_condition:
     1080            result.append('#endif\n')
     1081        if receiver.condition:
     1082            result.append('#endif\n')
     1083    result.append('    default:\n')
     1084    result.append('        break;\n')
     1085    result.append('    }\n')
     1086    result.append('    return WTF::nullopt;\n')
     1087    result.append('}\n')
     1088
     1089
     1090def generate_js_argument_descriptions(receivers, function_name, arguments_from_message):
     1091    result = []
     1092    result.append('Optional<Vector<ArgumentDescription>> %s(MessageName name)\n' % function_name)
     1093    result.append('{\n')
     1094    result.append('    switch (name) {\n')
     1095    for receiver in receivers:
     1096        if receiver.condition:
     1097            result.append('#if %s\n' % receiver.condition)
     1098        prevision_message_condition = None
     1099        for message in receiver.messages:
     1100            argument_list = arguments_from_message(message)
     1101            if argument_list is None:
     1102                continue
     1103            if prevision_message_condition != message.condition:
     1104                if prevision_message_condition:
     1105                    result.append('#endif\n')
     1106                if message.condition:
     1107                    result.append('#if %s\n' % message.condition)
     1108            prevision_message_condition = message.condition
     1109            result.append('    case MessageName::%s_%s:\n' % (receiver.name, message.name))
     1110
     1111            if not len(argument_list):
     1112                result.append('        return Vector<ArgumentDescription> { };\n')
     1113                continue
     1114
     1115            result.append('        return Vector<ArgumentDescription> {\n')
     1116            for argument in argument_list:
     1117                argument_type = argument.type
     1118                enum_type = None
     1119                is_optional = False
     1120                if argument.kind.startswith('enum:'):
     1121                    enum_type = '"%s"' % argument_type
     1122                    argument_type = argument.kind[5:]
     1123                if argument_type.startswith('Optional<') and argument_type.endswith('>'):
     1124                    argument_type = argument_type[9:-1]
     1125                    is_optional = True
     1126                result.append('            {"%s", "%s", %s, %s},\n' % (argument.name, argument_type, enum_type or 'nullptr', 'true' if is_optional else 'false'))
     1127            result.append('        };\n')
     1128        if prevision_message_condition:
     1129            result.append('#endif\n')
     1130        if receiver.condition:
     1131            result.append('#endif\n')
     1132    result.append('    default:\n')
     1133    result.append('        break;\n')
     1134    result.append('    }\n')
     1135    result.append('    return WTF::nullopt;\n')
     1136    result.append('}\n')
     1137    return result
     1138
     1139
     1140def generate_message_argument_description_implementation(receivers, receiver_headers):
     1141    header_conditions = {
     1142        '"JSIPCBinding.h"': [None]
     1143    }
     1144    for receiver in receivers:
     1145        header_conditions['"%s"' % messages_header_filename(receiver)] = [None]
     1146        collect_header_conditions_for_receiver(receiver, header_conditions)
     1147
     1148    result = []
     1149    result.append(_license_header)
     1150    result.append('#include "config.h"\n')
     1151    result.append('#include "MessageArgumentDescriptions.h"\n')
     1152    result.append('\n')
     1153    result.append('#if ENABLE(IPC_TESTING_API)\n')
     1154    result.append('\n')
     1155    result += generate_header_includes_from_conditions(header_conditions)
     1156    result.append('\n')
     1157
     1158    for header in receiver_headers:
     1159        result.append('#include "%s"\n' % (header))
     1160
     1161    result.append('\n')
     1162    result.append('namespace IPC {\n')
     1163    result.append('\n')
     1164
     1165    generate_js_value_conversion_function(result, receivers, 'jsValueForArguments', 'Arguments')
     1166
     1167    result.append('\n')
     1168
     1169    generate_js_value_conversion_function(result, receivers, 'jsValueForReplyArguments', 'ReplyArguments', lambda message: message.reply_parameters is not None and (message.has_attribute(SYNCHRONOUS_ATTRIBUTE) or message.has_attribute(ASYNC_ATTRIBUTE)))
     1170
     1171    result.append('\n')
     1172
     1173    result += generate_js_argument_descriptions(receivers, 'messageArgumentDescriptions', lambda message: message.parameters)
     1174
     1175    result.append('\n')
     1176
     1177    result += generate_js_argument_descriptions(receivers, 'messageReplyArgumentDescriptions', lambda message: message.reply_parameters if message.has_attribute(SYNCHRONOUS_ATTRIBUTE) or message.has_attribute(ASYNC_ATTRIBUTE) else None)
     1178
     1179    result.append('\n')
     1180
     1181    result.append('} // namespace WebKit\n')
     1182    result.append('\n')
     1183    result.append('#endif\n')
     1184    return ''.join(result)
  • trunk/Source/WebKit/Shared/ApplePay/ApplePayPaymentSetupFeaturesWebKit.h

    r262714 r268431  
    2828#if ENABLE(APPLE_PAY)
    2929
     30OBJC_CLASS NSArray;
    3031OBJC_CLASS PKPaymentSetupFeature;
    3132
  • trunk/Source/WebKit/SourcesCocoa.txt

    r268384 r268431  
    660660LibWebRTCCodecsProxyMessageReceiver.cpp
    661661LibWebRTCCodecsMessageReceiver.cpp
     662MessageArgumentDescriptions.cpp @no-unify
    662663MessageNames.cpp
    663664RemoteAudioDestinationManagerMessageReceiver.cpp
  • trunk/Source/WebKit/WebKit.xcodeproj/project.pbxproj

    r268384 r268431  
    14251425                9B1229CE23FF25F2008CA751 /* RemoteAudioDestinationManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9B1229CC23FF25F2008CA751 /* RemoteAudioDestinationManager.cpp */; };
    14261426                9B1229D223FF2BCC008CA751 /* RemoteAudioDestinationIdentifier.h in Headers */ = {isa = PBXBuildFile; fileRef = 9B1229D023FF2A5E008CA751 /* RemoteAudioDestinationIdentifier.h */; };
     1427                9B47908D25314D8300EC11AB /* MessageArgumentDescriptions.h in Headers */ = {isa = PBXBuildFile; fileRef = 9B47908C25314D8300EC11AB /* MessageArgumentDescriptions.h */; };
     1428                9B47908F253151CC00EC11AB /* JSIPCBinding.h in Headers */ = {isa = PBXBuildFile; fileRef = 9B47908E253151CC00EC11AB /* JSIPCBinding.h */; };
     1429                9B4790912531563200EC11AB /* MessageArgumentDescriptions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9B4790902531563200EC11AB /* MessageArgumentDescriptions.cpp */; };
    14271430                9B5499AD2362A6F900DF8BA5 /* _WKTextManipulationConfiguration.h in Headers */ = {isa = PBXBuildFile; fileRef = 9B5499AC2362A6F600DF8BA5 /* _WKTextManipulationConfiguration.h */; settings = {ATTRIBUTES = (Private, ); }; };
    14281431                9B5499B22362A7EC00DF8BA5 /* _WKTextManipulationExclusionRule.h in Headers */ = {isa = PBXBuildFile; fileRef = 9B5499B02362A7EC00DF8BA5 /* _WKTextManipulationExclusionRule.h */; settings = {ATTRIBUTES = (Private, ); }; };
     
    45304533                9B1229CF23FF2814008CA751 /* RemoteAudioDestinationManager.messages.in */ = {isa = PBXFileReference; lastKnownFileType = text; path = RemoteAudioDestinationManager.messages.in; sourceTree = "<group>"; };
    45314534                9B1229D023FF2A5E008CA751 /* RemoteAudioDestinationIdentifier.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RemoteAudioDestinationIdentifier.h; sourceTree = "<group>"; };
     4535                9B47908C25314D8300EC11AB /* MessageArgumentDescriptions.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MessageArgumentDescriptions.h; sourceTree = "<group>"; };
     4536                9B47908E253151CC00EC11AB /* JSIPCBinding.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = JSIPCBinding.h; sourceTree = "<group>"; };
     4537                9B4790902531563200EC11AB /* MessageArgumentDescriptions.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = MessageArgumentDescriptions.cpp; path = MessageArgumentDescriptions.cpp; sourceTree = "<group>"; };
    45324538                9B5499AC2362A6F600DF8BA5 /* _WKTextManipulationConfiguration.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = _WKTextManipulationConfiguration.h; sourceTree = "<group>"; };
    45334539                9B5499AE2362A7A700DF8BA5 /* _WKTextManipulationConfiguration.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = _WKTextManipulationConfiguration.mm; sourceTree = "<group>"; };
     
    64646470                                C0CE72AC1247E78D00BC0EC4 /* HandleMessage.h */,
    64656471                                1C9AF36124134D2300D3EC02 /* ImageDataReference.h */,
     6472                                9B47908E253151CC00EC11AB /* JSIPCBinding.h */,
     6473                                9B47908C25314D8300EC11AB /* MessageArgumentDescriptions.h */,
    64666474                                1AC4C82816B876A90069DCCD /* MessageFlags.h */,
    64676475                                1A3EED11161A53D600AEB4F5 /* MessageReceiver.h */,
     
    1008910097                                07E19EF923D401F00094FFB4 /* MediaPlayerPrivateRemoteMessages.h */,
    1009010098                                07E19EFA23D401F00094FFB4 /* MediaPlayerPrivateRemoteMessagesReplies.h */,
     10099                                9B4790902531563200EC11AB /* MessageArgumentDescriptions.cpp */,
    1009110100                                51DD9F2616367DA2001578E9 /* NetworkConnectionToWebProcessMessageReceiver.cpp */,
    1009210101                                51DD9F2716367DA2001578E9 /* NetworkConnectionToWebProcessMessages.h */,
     
    1094210951                                C5BCE5DF1C50766A00CDE3FA /* InteractionInformationAtPosition.h in Headers */,
    1094310952                                2D4D2C811DF60BF3002EB10C /* InteractionInformationRequest.h in Headers */,
     10953                                9B47908F253151CC00EC11AB /* JSIPCBinding.h in Headers */,
    1094410954                                1AE49A4911FFA8CE0048B464 /* JSNPMethod.h in Headers */,
    1094510955                                1AE4987811FF7FAA0048B464 /* JSNPObject.h in Headers */,
     
    1097810988                                07E19EFD23D401F10094FFB4 /* MediaPlayerPrivateRemoteMessagesReplies.h in Headers */,
    1097910989                                51933DEF1965EB31008AC3EA /* MenuUtilities.h in Headers */,
     10990                                9B47908D25314D8300EC11AB /* MessageArgumentDescriptions.h in Headers */,
    1098010991                                1AC4C82916B876A90069DCCD /* MessageFlags.h in Headers */,
    1098110992                                1A3EED12161A53D600AEB4F5 /* MessageReceiver.h in Headers */,
     
    1284912860                                2D92A779212B6A6100F493FD /* Logging.cpp in Sources */,
    1285012861                                07E19EFB23D401F10094FFB4 /* MediaPlayerPrivateRemoteMessageReceiver.cpp in Sources */,
     12862                                9B4790912531563200EC11AB /* MessageArgumentDescriptions.cpp in Sources */,
    1285112863                                2D92A781212B6A7100F493FD /* MessageReceiverMap.cpp in Sources */,
    1285212864                                2D92A782212B6A7100F493FD /* MessageSender.cpp in Sources */,
  • trunk/Source/WebKit/WebProcess/WebPage/IPCTestingAPI.cpp

    r268239 r268431  
    3232#include "FrameInfoData.h"
    3333#include "GPUProcessConnection.h"
    34 #include "MessageNames.h"
     34#include "MessageArgumentDescriptions.h"
    3535#include "NetworkProcessConnection.h"
    3636#include "WebCoreArgumentCoders.h"
     
    8484    static JSValueRef visitedLinkStoreID(JSContextRef, JSObjectRef, JSStringRef, JSValueRef* exception);
    8585    static JSValueRef webPageProxyID(JSContextRef, JSObjectRef, JSStringRef, JSValueRef* exception);
    86     static JSValueRef frameIdentifier(JSContextRef, JSObjectRef, JSStringRef, JSValueRef* exception);
     86    static JSValueRef sessionID(JSContextRef, JSObjectRef, JSStringRef, JSValueRef* exception);
     87    static JSValueRef pageID(JSContextRef, JSObjectRef, JSStringRef, JSValueRef* exception);
     88    static JSValueRef frameID(JSContextRef, JSObjectRef, JSStringRef, JSValueRef* exception);
    8789    static JSValueRef retrieveID(JSContextRef, JSObjectRef thisObject, JSValueRef* exception, const WTF::Function<uint64_t(JSIPC&)>&);
    8890
     
    145147    static const JSStaticValue values[] = {
    146148        { "visitedLinkStoreID", visitedLinkStoreID, 0, kJSPropertyAttributeDontDelete | kJSPropertyAttributeReadOnly },
     149        { "frameID", frameID, 0, kJSPropertyAttributeDontDelete | kJSPropertyAttributeReadOnly },
     150        { "pageID", pageID, 0, kJSPropertyAttributeDontDelete | kJSPropertyAttributeReadOnly },
     151        { "sessionID", sessionID, 0, kJSPropertyAttributeDontDelete | kJSPropertyAttributeReadOnly },
    147152        { "webPageProxyID", webPageProxyID, 0, kJSPropertyAttributeDontDelete | kJSPropertyAttributeReadOnly },
    148         { "frameIdentifier", frameIdentifier, 0, kJSPropertyAttributeDontDelete | kJSPropertyAttributeReadOnly },
    149153        { "messages", messages, 0, kJSPropertyAttributeDontDelete | kJSPropertyAttributeReadOnly },
    150154        { 0, 0, 0, 0 }
     
    238242}
    239243
    240 template<typename RectType> bool encodeRectType(IPC::Encoder& encoder, JSC::JSGlobalObject* globalObject, JSC::JSObject* jsObject)
     244template<typename PointType> bool encodePointType(IPC::Encoder& encoder, JSC::JSGlobalObject* globalObject, JSC::JSObject* jsObject, JSC::CatchScope& scope)
    241245{
    242246    auto& vm = globalObject->vm();
    243247    auto jsX = jsObject->get(globalObject, JSC::Identifier::fromString(vm, "x"_s));
    244     if (!jsX.isNumber())
     248    if (scope.exception() || !jsX.isNumber())
    245249        return false;
    246250    auto jsY = jsObject->get(globalObject, JSC::Identifier::fromString(vm, "y"_s));
    247     if (!jsY.isNumber())
     251    if (scope.exception() || !jsY.isNumber())
     252        return false;
     253    encoder << PointType(jsX.asNumber(), jsY.asNumber());
     254    return true;
     255}
     256
     257template<typename RectType> bool encodeRectType(IPC::Encoder& encoder, JSC::JSGlobalObject* globalObject, JSC::JSObject* jsObject, JSC::CatchScope& scope)
     258{
     259    auto& vm = globalObject->vm();
     260    auto jsX = jsObject->get(globalObject, JSC::Identifier::fromString(vm, "x"_s));
     261    if (scope.exception() || !jsX.isNumber())
     262        return false;
     263    auto jsY = jsObject->get(globalObject, JSC::Identifier::fromString(vm, "y"_s));
     264    if (scope.exception() || !jsY.isNumber())
    248265        return false;
    249266    auto jsWidth = jsObject->get(globalObject, JSC::Identifier::fromString(vm, "width"_s));
    250     if (!jsWidth.isNumber())
     267    if (scope.exception() || !jsWidth.isNumber())
    251268        return false;
    252269    auto jsHeight = jsObject->get(globalObject, JSC::Identifier::fromString(vm, "height"_s));
    253     if (!jsHeight.isNumber())
     270    if (scope.exception() || !jsHeight.isNumber())
    254271        return false;
    255272    encoder << RectType(jsX.asNumber(), jsY.asNumber(), jsWidth.asNumber(), jsHeight.asNumber());
     
    257274}
    258275
    259 template<typename IntegralType> bool encodeIntegralType(IPC::Encoder& encoder, JSC::JSValue jsValue)
     276template<typename IntegralType> bool encodeNumericType(IPC::Encoder& encoder, JSC::JSValue jsValue)
    260277{
    261278    if (jsValue.isBigInt()) {
     
    341358        return false;
    342359
     360    if (type == "IntPoint") {
     361        if (!encodePointType<WebCore::IntPoint>(encoder, globalObject, jsObject, scope)) {
     362            *exception = createTypeError(context, "Failed to convert IntPoint"_s);
     363            return false;
     364        }
     365        return true;
     366    }
     367
     368    if (type == "FloatPoint") {
     369        if (!encodePointType<WebCore::IntPoint>(encoder, globalObject, jsObject, scope)) {
     370            *exception = createTypeError(context, "Failed to convert FloatPoint"_s);
     371            return false;
     372        }
     373        return true;
     374    }
     375
    343376    if (type == "IntRect") {
    344         if (!encodeRectType<WebCore::IntRect>(encoder, globalObject, jsObject)) {
     377        if (!encodeRectType<WebCore::IntRect>(encoder, globalObject, jsObject, scope)) {
    345378            *exception = createTypeError(context, "Failed to convert IntRect"_s);
    346379            return false;
     
    350383
    351384    if (type == "FloatRect") {
    352         if (!encodeRectType<WebCore::FloatRect>(encoder, globalObject, jsObject)) {
     385        if (!encodeRectType<WebCore::FloatRect>(encoder, globalObject, jsObject, scope)) {
    353386            *exception = createTypeError(context, "Failed to convert FloatRect"_s);
    354387            return false;
     
    383416    }
    384417
     418    if (type == "URL") {
     419        if (jsValue.isUndefinedOrNull()) {
     420            encoder << URL { };
     421            return true;
     422        }
     423        auto string = jsValue.toWTFString(globalObject);
     424        if (scope.exception())
     425            return false;
     426        encoder << URL { URL { }, string };
     427        return true;
     428    }
     429
     430    if (type == "RegistrableDomain") {
     431        if (jsValue.isUndefinedOrNull()) {
     432            encoder << RegistrableDomain { };
     433            return true;
     434        }
     435        auto string = jsValue.toWTFString(globalObject);
     436        if (scope.exception())
     437            return false;
     438        encoder << RegistrableDomain { URL { URL { }, string } };
     439        return true;
     440    }
     441
    385442    if (type == "RGBA") {
    386443        if (!jsValue.isNumber()) {
     
    393450    }
    394451
    395     bool integralResult;
     452    bool numericResult;
    396453    if (type == "bool")
    397         integralResult = encodeIntegralType<bool>(encoder, jsValue);
     454        numericResult = encodeNumericType<bool>(encoder, jsValue);
     455    else if (type == "double")
     456        numericResult = encodeNumericType<double>(encoder, jsValue);
     457    else if (type == "float")
     458        numericResult = encodeNumericType<float>(encoder, jsValue);
    398459    else if (type == "int8_t")
    399         integralResult = encodeIntegralType<int8_t>(encoder, jsValue);
     460        numericResult = encodeNumericType<int8_t>(encoder, jsValue);
    400461    else if (type == "int16_t")
    401         integralResult = encodeIntegralType<int16_t>(encoder, jsValue);
     462        numericResult = encodeNumericType<int16_t>(encoder, jsValue);
    402463    else if (type == "int32_t")
    403         integralResult = encodeIntegralType<int32_t>(encoder, jsValue);
     464        numericResult = encodeNumericType<int32_t>(encoder, jsValue);
    404465    else if (type == "int64_t")
    405         integralResult = encodeIntegralType<int64_t>(encoder, jsValue);
     466        numericResult = encodeNumericType<int64_t>(encoder, jsValue);
    406467    else if (type == "uint8_t")
    407         integralResult = encodeIntegralType<uint8_t>(encoder, jsValue);
     468        numericResult = encodeNumericType<uint8_t>(encoder, jsValue);
    408469    else if (type == "uint16_t")
    409         integralResult = encodeIntegralType<uint16_t>(encoder, jsValue);
     470        numericResult = encodeNumericType<uint16_t>(encoder, jsValue);
    410471    else if (type == "uint32_t")
    411         integralResult = encodeIntegralType<uint32_t>(encoder, jsValue);
     472        numericResult = encodeNumericType<uint32_t>(encoder, jsValue);
    412473    else if (type == "uint64_t")
    413         integralResult = encodeIntegralType<uint64_t>(encoder, jsValue);
     474        numericResult = encodeNumericType<uint64_t>(encoder, jsValue);
    414475    else {
    415476        *exception = createTypeError(context, "Bad type name"_s);
    416477        return false;
    417478    }
    418     if (!integralResult) {
    419         *exception = createTypeError(context, "Failed to encode an integer"_s);
     479    if (!numericResult) {
     480        *exception = createTypeError(context, "Failed to encode a number"_s);
    420481        return false;
    421482    }
    422483    return true;
     484}
     485
     486
     487static JSC::JSObject* jsResultFromReplyDecoder(JSC::JSGlobalObject* globalObject, IPC::MessageName messageName, IPC::Decoder& decoder)
     488{
     489    auto& vm = globalObject->vm();
     490    auto scope = DECLARE_THROW_SCOPE(vm);
     491
     492    auto arrayBuffer = JSC::ArrayBuffer::create(decoder.buffer(), decoder.length());
     493    JSC::JSArrayBuffer* jsArrayBuffer = nullptr;
     494    if (auto* structure = globalObject->arrayBufferStructure(arrayBuffer->sharingMode()))
     495        jsArrayBuffer = JSC::JSArrayBuffer::create(vm, structure, WTFMove(arrayBuffer));
     496    if (!jsArrayBuffer) {
     497        throwException(globalObject, scope, JSC::createTypeError(globalObject, "Failed to create the array buffer for the reply"_s));
     498        return nullptr;
     499    }
     500
     501    auto jsReplyArguments = jsValueForReplyArguments(globalObject, messageName, decoder);
     502    if (!jsReplyArguments) {
     503        throwException(globalObject, scope, JSC::createTypeError(globalObject, "Failed to decode the reply"_s));
     504        return nullptr;
     505    }
     506
     507    if (jsReplyArguments->isEmpty()) {
     508        throwException(globalObject, scope, JSC::createTypeError(globalObject, "Failed to convert the reply to an JS array"_s));
     509        return nullptr;
     510    }
     511
     512    auto catchScope = DECLARE_CATCH_SCOPE(vm);
     513    JSC::JSObject* jsResult = constructEmptyObject(globalObject, globalObject->objectPrototype());
     514    RETURN_IF_EXCEPTION(catchScope, nullptr);
     515
     516    jsResult->putDirect(vm, vm.propertyNames->arguments, *jsReplyArguments);
     517    RETURN_IF_EXCEPTION(catchScope, nullptr);
     518
     519    jsResult->putDirect(vm, JSC::Identifier::fromString(vm, "buffer"), jsArrayBuffer);
     520    RETURN_IF_EXCEPTION(catchScope, nullptr);
     521
     522    return jsResult;
    423523}
    424524
     
    429529    auto jsIPC = makeRefPtr(toWrapped(context, thisObject));
    430530    if (!jsIPC) {
    431         *exception = toRef(JSC::createTypeError(toJS(context), "Wrong type"_s));
     531        *exception = createTypeError(context, "Wrong type"_s);
    432532        return JSValueMakeUndefined(context);
    433533    }
    434534
    435535    if (argumentCount < 3) {
    436         *exception = toRef(JSC::createTypeError(toJS(context), "Must specify the target process, desination ID, and message ID as the first three arguments"_s));
     536        *exception = createTypeError(context, "Must specify the target process, desination ID, and message ID as the first three arguments"_s);
    437537        return JSValueMakeUndefined(context);
    438538    }
     
    450550        return JSValueMakeUndefined(context);
    451551
    452     auto encoder = makeUnique<IPC::Encoder>(static_cast<IPC::MessageName>(static_cast<uint64_t>(*messageID)), *destinationID);
     552    auto messageName = static_cast<IPC::MessageName>(*messageID);
     553    auto encoder = makeUnique<IPC::Encoder>(messageName, *destinationID);
     554
     555    JSValueRef returnValue = JSValueMakeUndefined(context);
     556
     557    bool hasReply = !!messageReplyArgumentDescriptions(messageName);
     558    if (hasReply) {
     559        uint64_t listenerID = IPC::nextAsyncReplyHandlerID();
     560        encoder->encode(listenerID);
     561
     562        JSObjectRef resolve;
     563        JSObjectRef reject;
     564ALLOW_NEW_API_WITHOUT_GUARDS_BEGIN
     565        returnValue = JSObjectMakeDeferredPromise(context, &resolve, &reject, exception);
     566ALLOW_NEW_API_WITHOUT_GUARDS_END
     567        if (!returnValue)
     568            return JSValueMakeUndefined(context);
     569
     570        JSGlobalContextRetain(JSContextGetGlobalContext(context));
     571        JSValueProtect(context, resolve);
     572        JSValueProtect(context, reject);
     573        IPC::addAsyncReplyHandler(*connection, listenerID, [messageName, context, resolve, reject](IPC::Decoder* replyDecoder) {
     574            auto* globalObject = toJS(context);
     575            auto& vm = globalObject->vm();
     576            JSC::JSLockHolder lock(vm);
     577
     578            auto scope = DECLARE_CATCH_SCOPE(vm);
     579            auto* jsResult = jsResultFromReplyDecoder(globalObject, messageName, *replyDecoder);
     580            if (auto* exception = scope.exception()) {
     581                scope.clearException();
     582                JSValueRef arguments[] = { toRef(globalObject, exception) };
     583                JSObjectCallAsFunction(context, reject, reject, 1, arguments, nullptr);
     584            } else {
     585                JSValueRef arguments[] = { toRef(globalObject, jsResult) };
     586                JSObjectCallAsFunction(context, resolve, resolve, 1, arguments, nullptr);
     587            }
     588
     589            JSValueUnprotect(context, reject);
     590            JSValueUnprotect(context, resolve);
     591            JSGlobalContextRelease(JSContextGetGlobalContext(context));
     592        });
     593    }
    453594
    454595    if (argumentCount > 3) {
     
    461602    connection->sendMessage(WTFMove(encoder), { });
    462603
    463     return JSValueMakeUndefined(context);
     604    return returnValue;
    464605}
    465606
     
    470611    auto jsIPC = makeRefPtr(toWrapped(context, thisObject));
    471612    if (!jsIPC) {
    472         *exception = toRef(JSC::createTypeError(toJS(context), "Wrong type"_s));
     613        *exception = createTypeError(context, "Wrong type"_s);
    473614        return JSValueMakeUndefined(context);
    474615    }
    475616
    476617    if (argumentCount < 4) {
    477         *exception = toRef(JSC::createTypeError(toJS(context), "Must specify the target process, desination ID, message ID, and timeout as the first four arguments"_s));
     618        *exception = createTypeError(context, "Must specify the target process, desination ID, and message ID as the first three arguments"_s);
    478619        return JSValueMakeUndefined(context);
    479620    }
     
    495636        auto jsValue = toJS(globalObject, arguments[3]);
    496637        if (!jsValue.isNumber()) {
    497             *exception = toRef(JSC::createTypeError(globalObject, "timeout must be a number"_s));
     638            *exception = createTypeError(context, "Timeout must be a number"_s);
    498639            return JSValueMakeUndefined(context);
    499640        }
    500641        timeout = Seconds { jsValue.asNumber() };
    501642    }
    502    
     643
    503644    // FIXME: Support the options.
    504645
    505646    uint64_t syncRequestID = 0;
    506     auto encoder = connection->createSyncMessageEncoder(static_cast<IPC::MessageName>(static_cast<uint64_t>(*messageID)), *destinationID, syncRequestID);
     647    auto messageName = static_cast<IPC::MessageName>(*messageID);
     648    auto encoder = connection->createSyncMessageEncoder(messageName, *destinationID, syncRequestID);
    507649
    508650    if (argumentCount > 4) {
     
    511653    }
    512654
    513     auto replyDecoder = connection->sendSyncMessage(syncRequestID, WTFMove(encoder), timeout, { });
    514     // FIXME: Decode the reply.
     655    if (auto replyDecoder = connection->sendSyncMessage(syncRequestID, WTFMove(encoder), timeout, { })) {
     656        auto scope = DECLARE_CATCH_SCOPE(globalObject->vm());
     657        auto* jsResult = jsResultFromReplyDecoder(globalObject, messageName, *replyDecoder);
     658        if (scope.exception()) {
     659            *exception = toRef(globalObject, scope.exception());
     660            scope.clearException();
     661            return JSValueMakeUndefined(context);
     662        }
     663        return toRef(globalObject, jsResult);
     664    }
    515665
    516666    return JSValueMakeUndefined(context);
     
    525675}
    526676
     677JSValueRef JSIPC::frameID(JSContextRef context, JSObjectRef thisObject, JSStringRef, JSValueRef* exception)
     678{
     679    return retrieveID(context, thisObject, exception, [](JSIPC& wrapped) {
     680        return wrapped.m_webFrame->frameID().toUInt64();
     681    });
     682}
     683
     684JSValueRef JSIPC::pageID(JSContextRef context, JSObjectRef thisObject, JSStringRef, JSValueRef* exception)
     685{
     686    return retrieveID(context, thisObject, exception, [](JSIPC& wrapped) {
     687        return wrapped.m_webPage->identifier().toUInt64();
     688    });
     689}
     690
     691JSValueRef JSIPC::sessionID(JSContextRef context, JSObjectRef thisObject, JSStringRef, JSValueRef* exception)
     692{
     693    return retrieveID(context, thisObject, exception, [](JSIPC& wrapped) {
     694        return wrapped.m_webPage->sessionID().toUInt64();
     695    });
     696}
     697
    527698JSValueRef JSIPC::webPageProxyID(JSContextRef context, JSObjectRef thisObject, JSStringRef, JSValueRef* exception)
    528699{
     
    532703}
    533704
    534 JSValueRef JSIPC::frameIdentifier(JSContextRef context, JSObjectRef thisObject, JSStringRef, JSValueRef* exception)
    535 {
    536     return retrieveID(context, thisObject, exception, [](JSIPC& wrapped) {
    537         return wrapped.m_webFrame->frameID().toUInt64();
    538     });
    539 }
    540 
    541705JSValueRef JSIPC::retrieveID(JSContextRef context, JSObjectRef thisObject, JSValueRef* exception, const WTF::Function<uint64_t(JSIPC&)>& callback)
    542706{
     
    556720}
    557721
     722static JSC::JSValue createJSArrayForArgumentDescriptions(JSC::JSGlobalObject* globalObject, Optional<Vector<IPC::ArgumentDescription>>&& argumentDescriptions)
     723{
     724    if (!argumentDescriptions)
     725        return JSC::jsNull();
     726
     727    auto& vm = globalObject->vm();
     728    auto scope = DECLARE_CATCH_SCOPE(vm);
     729    JSC::JSObject* argumentsArray = JSC::constructEmptyArray(globalObject, nullptr);
     730    RETURN_IF_EXCEPTION(scope, JSC::jsTDZValue());
     731
     732    for (unsigned argumentIndex = 0; argumentIndex < argumentDescriptions->size(); ++argumentIndex) {
     733        auto& description = argumentDescriptions->at(argumentIndex);
     734        JSC::JSObject* jsDescriptions = constructEmptyObject(globalObject, globalObject->objectPrototype());
     735        RETURN_IF_EXCEPTION(scope, JSC::jsTDZValue());
     736
     737        argumentsArray->putDirectIndex(globalObject, argumentIndex, jsDescriptions);
     738        RETURN_IF_EXCEPTION(scope, JSC::jsTDZValue());
     739
     740        jsDescriptions->putDirect(vm, JSC::Identifier::fromString(vm, "name"), JSC::jsString(vm, String(description.name)));
     741        RETURN_IF_EXCEPTION(scope, JSC::jsTDZValue());
     742
     743        jsDescriptions->putDirect(vm, JSC::Identifier::fromString(vm, "type"), JSC::jsString(vm, String(description.type)));
     744        RETURN_IF_EXCEPTION(scope, JSC::jsTDZValue());
     745
     746        jsDescriptions->putDirect(vm, JSC::Identifier::fromString(vm, "optional"), JSC::jsBoolean(description.isOptional));
     747        RETURN_IF_EXCEPTION(scope, JSC::jsTDZValue());
     748
     749        if (description.enumName) {
     750            jsDescriptions->putDirect(vm, JSC::Identifier::fromString(vm, "enum"), JSC::jsString(vm, String(description.enumName)));
     751            RETURN_IF_EXCEPTION(scope, JSC::jsTDZValue());
     752        }
     753    }
     754    return argumentsArray;
     755}
     756
    558757JSValueRef JSIPC::messages(JSContextRef context, JSObjectRef thisObject, JSStringRef, JSValueRef* exception)
    559758{
     
    568767    }
    569768
     769    auto scope = DECLARE_CATCH_SCOPE(vm);
    570770    JSC::JSObject* messagesObject = constructEmptyObject(globalObject, globalObject->objectPrototype());
     771    RETURN_IF_EXCEPTION(scope, JSValueMakeUndefined(context));
     772
    571773    auto nameIdent = JSC::Identifier::fromString(vm, "name");
     774    auto replyArgumentsIdent = JSC::Identifier::fromString(vm, "replyArguments");
    572775    for (unsigned i = 0; i < static_cast<unsigned>(IPC::MessageName::Last); ++i) {
    573         auto* messageName = description(static_cast<IPC::MessageName>(i));
     776        auto name = static_cast<IPC::MessageName>(i);
    574777
    575778        JSC::JSObject* dictionary = constructEmptyObject(globalObject, globalObject->objectPrototype());
     779        RETURN_IF_EXCEPTION(scope, JSValueMakeUndefined(context));
     780
    576781        dictionary->putDirect(vm, nameIdent, JSC::JSValue(i));
    577 
    578         // FIXME: Add argument names.
    579 
    580         messagesObject->putDirect(vm, JSC::Identifier::fromString(vm, messageName), dictionary);
     782        RETURN_IF_EXCEPTION(scope, JSValueMakeUndefined(context));
     783
     784        auto argumentDescriptions = createJSArrayForArgumentDescriptions(globalObject, IPC::messageArgumentDescriptions(name));
     785        if (argumentDescriptions.isEmpty())
     786            return JSValueMakeUndefined(context);
     787        dictionary->putDirect(vm, vm.propertyNames->arguments, argumentDescriptions);           
     788        RETURN_IF_EXCEPTION(scope, JSValueMakeUndefined(context));
     789
     790        auto replyArgumentDescriptions = createJSArrayForArgumentDescriptions(globalObject, IPC::messageReplyArgumentDescriptions(name));
     791        if (replyArgumentDescriptions.isEmpty())
     792            return JSValueMakeUndefined(context);
     793        dictionary->putDirect(vm, replyArgumentsIdent, replyArgumentDescriptions);           
     794        RETURN_IF_EXCEPTION(scope, JSValueMakeUndefined(context));
     795
     796        messagesObject->putDirect(vm, JSC::Identifier::fromString(vm, description(name)), dictionary);
     797        RETURN_IF_EXCEPTION(scope, JSValueMakeUndefined(context));
    581798    }
    582799
  • trunk/Tools/ChangeLog

    r268429 r268431  
     12020-10-12  Ryosuke Niwa  <rniwa@webkit.org>
     2
     3        IPC testing JS API should expose a reply and describe the list of arguments for each message
     4        https://bugs.webkit.org/show_bug.cgi?id=217565
     5
     6        Reviewed by Geoffrey Garen.
     7
     8        Added tests for decoding replies for sync and async messages and one for argument descriptions.
     9
     10        * TestWebKitAPI/Tests/WebKitCocoa/IPCTestingAPI.mm:
     11        (-[IPCTestingAPIDelegate webView:runJavaScriptTextInputPanelWithPrompt:defaultText:initiatedByFrame:completionHandler:]):
     12        (-[IPCTestingAPIDelegate _webView:webContentProcessDidTerminateWithReason:]):
     13        (IPCTestingAPI.DecodesReplyArgumentsForPrompt):
     14        (IPCTestingAPI.DecodesReplyArgumentsForAsyncMessage):
     15        (IPCTestingAPI.DescribesArguments):
     16
    1172020-10-13  Aakash Jain  <aakash_jain@apple.com>
    218
  • trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/IPCTestingAPI.mm

    r268239 r268431  
    3535
    3636static bool done = false;
     37static bool didCrash = false;
    3738static RetainPtr<NSString> alertMessage;
     39static RetainPtr<NSString> promptDefault;
     40static RetainPtr<NSString> promptResult;
    3841
    39 @interface IPCTestingAPIDelegate : NSObject <WKUIDelegate>
     42@interface IPCTestingAPIDelegate : NSObject <WKUIDelegate, WKNavigationDelegate>
    4043@end
    4144   
     
    4750    done = true;
    4851    completionHandler();
     52}
     53
     54- (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * _Nullable))completionHandler
     55{
     56    promptDefault = defaultText;
     57    done = true;
     58    completionHandler(promptResult.get());
     59}
     60
     61- (void)_webView:(WKWebView *)webView webContentProcessDidTerminateWithReason:(_WKProcessTerminationReason)reason
     62{
     63    didCrash = false;
     64    done = true;
    4965}
    5066
     
    88104}
    89105
     106TEST(IPCTestingAPI, DecodesReplyArgumentsForPrompt)
     107{
     108    RetainPtr<WKWebViewConfiguration> configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
     109    for (_WKInternalDebugFeature *feature in [WKPreferences _internalDebugFeatures]) {
     110        if ([feature.key isEqualToString:@"IPCTestingAPIEnabled"]) {
     111            [[configuration preferences] _setEnabled:YES forInternalDebugFeature:feature];
     112            break;
     113        }
     114    }
     115    RetainPtr<TestWKWebView> webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 300, 300) configuration:configuration.get()]);
     116
     117    auto delegate = adoptNS([[IPCTestingAPIDelegate alloc] init]);
     118    [webView setUIDelegate:delegate.get()];
     119
     120    done = false;
     121    promptResult = @"foo";
     122    [webView synchronouslyLoadHTMLString:@"<!DOCTYPE html><script>result = IPC.sendSyncMessage('UI', IPC.webPageProxyID, IPC.messages.WebPageProxy_RunJavaScriptPrompt.name, 100,"
     123        "[{type: 'uint64_t', value: IPC.frameIdentifier}, {type: 'FrameInfoData'}, {'type': 'String', 'value': 'hi'}, {'type': 'String', 'value': 'bar'}]);</script>"];
     124    TestWebKitAPI::Util::run(&done);
     125
     126    EXPECT_STREQ([promptDefault UTF8String], "bar");
     127    EXPECT_STREQ([[webView stringByEvaluatingJavaScript:@"JSON.stringify(result.arguments)"] UTF8String], "[{\"type\":\"String\",\"value\":\"foo\"}]");
     128}
     129
     130#if ENABLE(RESOURCE_LOAD_STATISTICS)
     131TEST(IPCTestingAPI, DecodesReplyArgumentsForAsyncMessage)
     132{
     133    RetainPtr<WKWebViewConfiguration> configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
     134    for (_WKInternalDebugFeature *feature in [WKPreferences _internalDebugFeatures]) {
     135        if ([feature.key isEqualToString:@"IPCTestingAPIEnabled"]) {
     136            [[configuration preferences] _setEnabled:YES forInternalDebugFeature:feature];
     137            break;
     138        }
     139    }
     140    RetainPtr<TestWKWebView> webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 300, 300) configuration:configuration.get()]);
     141
     142    auto delegate = adoptNS([[IPCTestingAPIDelegate alloc] init]);
     143    [webView setUIDelegate:delegate.get()];
     144
     145    done = false;
     146    promptResult = @"foo";
     147    [webView synchronouslyLoadHTMLString:@"<!DOCTYPE html><script>IPC.sendMessage(\"Networking\", 0, IPC.messages.NetworkConnectionToWebProcess_HasStorageAccess.name,"
     148        "[{type: 'RegistrableDomain', value: 'https://ipctestingapi.com'}, {type: 'RegistrableDomain', value: 'https://webkit.org'}, {type: 'uint64_t', value: IPC.frameIdentifier},"
     149        "{type: 'uint64_t', value: IPC.pageIdentifier}]).then((result) => alert(JSON.stringify(result.arguments)));</script>"];
     150    TestWebKitAPI::Util::run(&done);
     151
     152    EXPECT_STREQ([alertMessage UTF8String], "[{\"type\":\"bool\",\"value\":false}]");
     153}
    90154#endif
     155
     156TEST(IPCTestingAPI, DescribesArguments)
     157{
     158    RetainPtr<WKWebViewConfiguration> configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
     159    for (_WKInternalDebugFeature *feature in [WKPreferences _internalDebugFeatures]) {
     160        if ([feature.key isEqualToString:@"IPCTestingAPIEnabled"]) {
     161            [[configuration preferences] _setEnabled:YES forInternalDebugFeature:feature];
     162            break;
     163        }
     164    }
     165    RetainPtr<TestWKWebView> webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 300, 300) configuration:configuration.get()]);
     166
     167    auto delegate = adoptNS([[IPCTestingAPIDelegate alloc] init]);
     168    [webView setUIDelegate:delegate.get()];
     169
     170    done = false;
     171    [webView synchronouslyLoadHTMLString:@"<!DOCTYPE html><script>window.args = IPC.messages.WebPageProxy_RunJavaScriptAlert.arguments; alert('ok')</script>"];
     172    TestWebKitAPI::Util::run(&done);
     173
     174    EXPECT_STREQ([[webView stringByEvaluatingJavaScript:@"args.length"] UTF8String], "3");
     175    EXPECT_STREQ([[webView stringByEvaluatingJavaScript:@"args[0].type"] UTF8String], "WebCore::FrameIdentifier");
     176    EXPECT_STREQ([[webView stringByEvaluatingJavaScript:@"args[1].type"] UTF8String], "WebKit::FrameInfoData");
     177    EXPECT_STREQ([[webView stringByEvaluatingJavaScript:@"args[2].name"] UTF8String], "message");
     178    EXPECT_STREQ([[webView stringByEvaluatingJavaScript:@"args[2].type"] UTF8String], "String");
     179}
     180
     181#endif
Note: See TracChangeset for help on using the changeset viewer.