[Extensions Bindings] Add nativeMessaging support to runtime bindings

Add support for native messaging to native runtime bindings. This
includes adding handlers for connect and connectNative, as well as
updating the IPC message sender. Add unittests for the new handlers.

Bug: 653596
Change-Id: Icdf54ab625841220d226a6bf60d0999943ba0ebe
Reviewed-on: https://chromium-review.googlesource.com/710223
Reviewed-by: Istiaque Ahmed <[email protected]>
Reviewed-by: Jeremy Roman <[email protected]>
Commit-Queue: Devlin <[email protected]>
Cr-Commit-Position: refs/heads/master@{#510633}
diff --git a/extensions/renderer/runtime_hooks_delegate.cc b/extensions/renderer/runtime_hooks_delegate.cc
index 650c242..6fadf03 100644
--- a/extensions/renderer/runtime_hooks_delegate.cc
+++ b/extensions/renderer/runtime_hooks_delegate.cc
@@ -196,7 +196,9 @@
 constexpr char kGetManifest[] = "runtime.getManifest";
 constexpr char kGetURL[] = "runtime.getURL";
 constexpr char kConnect[] = "runtime.connect";
+constexpr char kConnectNative[] = "runtime.connectNative";
 constexpr char kSendMessage[] = "runtime.sendMessage";
+constexpr char kSendNativeMessage[] = "runtime.sendNativeMessage";
 
 constexpr char kSendMessageChannel[] = "chrome.runtime.sendMessage";
 
@@ -223,6 +225,8 @@
       {&RuntimeHooksDelegate::HandleConnect, kConnect},
       {&RuntimeHooksDelegate::HandleGetURL, kGetURL},
       {&RuntimeHooksDelegate::HandleGetManifest, kGetManifest},
+      {&RuntimeHooksDelegate::HandleConnectNative, kConnectNative},
+      {&RuntimeHooksDelegate::HandleSendNativeMessage, kSendNativeMessage},
   };
 
   ScriptContext* script_context =
@@ -327,7 +331,6 @@
   }
 
   v8::Local<v8::Value> v8_message = arguments[1];
-  DCHECK(!v8_message.IsEmpty());
   std::unique_ptr<Message> message =
       messaging_util::MessageFromV8(v8_context, v8_message);
   if (!message) {
@@ -348,6 +351,35 @@
   return RequestResult(RequestResult::HANDLED);
 }
 
+RequestResult RuntimeHooksDelegate::HandleSendNativeMessage(
+    ScriptContext* script_context,
+    const std::vector<v8::Local<v8::Value>>& arguments) {
+  DCHECK_EQ(3u, arguments.size());
+
+  std::string application_name = gin::V8ToString(arguments[0]);
+
+  v8::Local<v8::Value> v8_message = arguments[1];
+  DCHECK(!v8_message.IsEmpty());
+  std::unique_ptr<Message> message =
+      messaging_util::MessageFromV8(script_context->v8_context(), v8_message);
+  if (!message) {
+    RequestResult result(RequestResult::INVALID_INVOCATION);
+    result.error =
+        "Illegal argument to runtime.sendNativeMessage for 'message'.";
+    return result;
+  }
+
+  v8::Local<v8::Function> response_callback;
+  if (!arguments[2]->IsNull())
+    response_callback = arguments[2].As<v8::Function>();
+
+  messaging_service_->SendOneTimeMessage(
+      script_context, MessageTarget::ForNativeApp(application_name),
+      std::string(), false, *message, response_callback);
+
+  return RequestResult(RequestResult::HANDLED);
+}
+
 RequestResult RuntimeHooksDelegate::HandleConnect(
     ScriptContext* script_context,
     const std::vector<v8::Local<v8::Value>>& arguments) {
@@ -390,4 +422,20 @@
   return result;
 }
 
+RequestResult RuntimeHooksDelegate::HandleConnectNative(
+    ScriptContext* script_context,
+    const std::vector<v8::Local<v8::Value>>& arguments) {
+  DCHECK_EQ(1u, arguments.size());
+  DCHECK(arguments[0]->IsString());
+
+  std::string application_name = gin::V8ToString(arguments[0]);
+  gin::Handle<GinPort> port = messaging_service_->Connect(
+      script_context, MessageTarget::ForNativeApp(application_name),
+      std::string(), false);
+
+  RequestResult result(RequestResult::HANDLED);
+  result.return_value = port.ToV8();
+  return result;
+}
+
 }  // namespace extensions