[email protected] | e689367 | 2014-05-01 17:29:13 | [diff] [blame] | 1 | // Copyright 2014 The Chromium Authors. All rights reserved. |
[email protected] | 0aa477bd | 2009-03-23 22:21:43 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
[email protected] | e689367 | 2014-05-01 17:29:13 | [diff] [blame] | 5 | #include "extensions/renderer/messaging_bindings.h" |
[email protected] | 0aa477bd | 2009-03-23 22:21:43 | [diff] [blame] | 6 | |
avi | 2d124c0 | 2015-12-23 06:36:42 | [diff] [blame] | 7 | #include <stdint.h> |
| 8 | |
[email protected] | a672cb9 | 2009-12-29 00:28:43 | [diff] [blame] | 9 | #include <map> |
| 10 | #include <string> |
| 11 | |
[email protected] | 09e9d64 | 2013-03-14 17:00:10 | [diff] [blame] | 12 | #include "base/bind.h" |
[email protected] | 204d8ee | 2013-07-24 07:43:06 | [diff] [blame] | 13 | #include "base/bind_helpers.h" |
kalman | 70c00e24 | 2015-05-15 23:42:27 | [diff] [blame] | 14 | #include "base/callback.h" |
[email protected] | 204d8ee | 2013-07-24 07:43:06 | [diff] [blame] | 15 | #include "base/message_loop/message_loop.h" |
[email protected] | 686914f | 2013-04-25 04:54:58 | [diff] [blame] | 16 | #include "base/values.h" |
mek | 87e0ab5 | 2015-02-13 01:18:26 | [diff] [blame] | 17 | #include "content/public/child/v8_value_converter.h" |
vrk | 85dfc5c | 2015-01-10 00:05:32 | [diff] [blame] | 18 | #include "content/public/common/child_process_host.h" |
rob | 248d6a8 | 2014-11-21 02:04:48 | [diff] [blame] | 19 | #include "content/public/renderer/render_frame.h" |
[email protected] | 52647690 | 2011-10-06 20:34:06 | [diff] [blame] | 20 | #include "content/public/renderer/render_thread.h" |
[email protected] | 91add6a | 2014-03-21 11:48:22 | [diff] [blame] | 21 | #include "extensions/common/api/messaging/message.h" |
[email protected] | fb820c0 | 2014-03-13 15:07:08 | [diff] [blame] | 22 | #include "extensions/common/extension_messages.h" |
thestig | da556af | 2014-11-01 00:51:31 | [diff] [blame] | 23 | #include "extensions/common/manifest_handlers/externally_connectable.h" |
rdevlin.cronin | b05a80f | 2015-10-06 00:58:18 | [diff] [blame] | 24 | #include "extensions/renderer/extension_frame_helper.h" |
kalman | 32d7af2 | 2015-07-24 05:10:59 | [diff] [blame] | 25 | #include "extensions/renderer/gc_callback.h" |
[email protected] | bcd9580f | 2014-04-17 19:17:59 | [diff] [blame] | 26 | #include "extensions/renderer/script_context.h" |
| 27 | #include "extensions/renderer/script_context_set.h" |
bashi | 7b0e3c9 | 2015-06-23 05:19:56 | [diff] [blame] | 28 | #include "extensions/renderer/v8_helpers.h" |
mlamouri | 9b4c024 | 2015-04-21 10:43:54 | [diff] [blame] | 29 | #include "third_party/WebKit/public/web/WebDocument.h" |
rob | 4ae97b7 | 2014-12-10 00:16:04 | [diff] [blame] | 30 | #include "third_party/WebKit/public/web/WebLocalFrame.h" |
[email protected] | 8865fea | 2013-10-23 01:17:26 | [diff] [blame] | 31 | #include "third_party/WebKit/public/web/WebScopedUserGesture.h" |
[email protected] | 2d76a39 | 2013-12-23 08:43:40 | [diff] [blame] | 32 | #include "third_party/WebKit/public/web/WebScopedWindowFocusAllowedIndicator.h" |
[email protected] | 8865fea | 2013-10-23 01:17:26 | [diff] [blame] | 33 | #include "third_party/WebKit/public/web/WebUserGestureIndicator.h" |
[email protected] | 82fc0f5 | 2011-09-06 23:39:22 | [diff] [blame] | 34 | #include "v8/include/v8.h" |
[email protected] | 0aa477bd | 2009-03-23 22:21:43 | [diff] [blame] | 35 | |
[email protected] | 0aa477bd | 2009-03-23 22:21:43 | [diff] [blame] | 36 | // Message passing API example (in a content script): |
| 37 | // var extension = |
[email protected] | 28c47ee9 | 2009-05-05 18:25:01 | [diff] [blame] | 38 | // new chrome.Extension('00123456789abcdef0123456789abcdef0123456'); |
[email protected] | 754ea8b7 | 2013-01-08 15:10:31 | [diff] [blame] | 39 | // var port = runtime.connect(); |
[email protected] | a40caa97 | 2009-04-08 18:35:34 | [diff] [blame] | 40 | // port.postMessage('Can you hear me now?'); |
| 41 | // port.onmessage.addListener(function(msg, port) { |
[email protected] | 75e5a87 | 2009-04-02 23:56:11 | [diff] [blame] | 42 | // alert('response=' + msg); |
| 43 | // port.postMessage('I got your reponse'); |
[email protected] | a40caa97 | 2009-04-08 18:35:34 | [diff] [blame] | 44 | // }); |
[email protected] | 75e5a87 | 2009-04-02 23:56:11 | [diff] [blame] | 45 | |
[email protected] | eb7ef5f | 2014-02-06 09:59:19 | [diff] [blame] | 46 | namespace extensions { |
| 47 | |
bashi | 7b0e3c9 | 2015-06-23 05:19:56 | [diff] [blame] | 48 | using v8_helpers::ToV8String; |
kalman | 33076cb | 2015-08-11 19:12:07 | [diff] [blame] | 49 | using v8_helpers::IsEmptyOrUndefied; |
bashi | 7b0e3c9 | 2015-06-23 05:19:56 | [diff] [blame] | 50 | |
[email protected] | 75e5a87 | 2009-04-02 23:56:11 | [diff] [blame] | 51 | namespace { |
| 52 | |
rob | d1db9f6 | 2016-05-25 11:03:10 | [diff] [blame] | 53 | void HasMessagePort(int port_id, |
| 54 | bool* has_port, |
| 55 | ScriptContext* script_context) { |
| 56 | if (*has_port) |
| 57 | return; // Stop checking if the port was found. |
| 58 | |
| 59 | v8::Isolate* isolate = script_context->isolate(); |
| 60 | v8::HandleScope handle_scope(isolate); |
| 61 | |
| 62 | v8::Local<v8::Value> port_id_handle = v8::Integer::New(isolate, port_id); |
| 63 | v8::Local<v8::Value> v8_has_port = |
| 64 | script_context->module_system()->CallModuleMethod("messaging", "hasPort", |
| 65 | 1, &port_id_handle); |
| 66 | if (IsEmptyOrUndefied(v8_has_port)) |
| 67 | return; |
| 68 | CHECK(v8_has_port->IsBoolean()); |
| 69 | if (!v8_has_port.As<v8::Boolean>()->Value()) |
| 70 | return; |
| 71 | *has_port = true; |
| 72 | } |
| 73 | |
[email protected] | 800f987 | 2014-06-12 04:12:51 | [diff] [blame] | 74 | void DispatchOnConnectToScriptContext( |
| 75 | int target_port_id, |
| 76 | const std::string& channel_name, |
rob | 248d6a8 | 2014-11-21 02:04:48 | [diff] [blame] | 77 | const ExtensionMsg_TabConnectionInfo* source, |
[email protected] | 800f987 | 2014-06-12 04:12:51 | [diff] [blame] | 78 | const ExtensionMsg_ExternalConnectionInfo& info, |
| 79 | const std::string& tls_channel_id, |
kalman | 62b5911d | 2015-04-04 02:33:09 | [diff] [blame] | 80 | bool* port_created, |
[email protected] | 800f987 | 2014-06-12 04:12:51 | [diff] [blame] | 81 | ScriptContext* script_context) { |
[email protected] | 800f987 | 2014-06-12 04:12:51 | [diff] [blame] | 82 | v8::Isolate* isolate = script_context->isolate(); |
| 83 | v8::HandleScope handle_scope(isolate); |
| 84 | |
rdevlin.cronin | 4012b3b | 2016-08-31 18:36:47 | [diff] [blame^] | 85 | std::unique_ptr<content::V8ValueConverter> converter( |
| 86 | content::V8ValueConverter::create()); |
[email protected] | 800f987 | 2014-06-12 04:12:51 | [diff] [blame] | 87 | |
| 88 | const std::string& source_url_spec = info.source_url.spec(); |
| 89 | std::string target_extension_id = script_context->GetExtensionID(); |
| 90 | const Extension* extension = script_context->extension(); |
| 91 | |
tfarina | f85316f | 2015-04-29 17:03:40 | [diff] [blame] | 92 | v8::Local<v8::Value> tab = v8::Null(isolate); |
| 93 | v8::Local<v8::Value> tls_channel_id_value = v8::Undefined(isolate); |
| 94 | v8::Local<v8::Value> guest_process_id = v8::Undefined(isolate); |
lazyboy | 0b46a97 | 2015-06-16 02:54:41 | [diff] [blame] | 95 | v8::Local<v8::Value> guest_render_frame_routing_id = v8::Undefined(isolate); |
[email protected] | 800f987 | 2014-06-12 04:12:51 | [diff] [blame] | 96 | |
| 97 | if (extension) { |
rob | 248d6a8 | 2014-11-21 02:04:48 | [diff] [blame] | 98 | if (!source->tab.empty() && !extension->is_platform_app()) |
| 99 | tab = converter->ToV8Value(&source->tab, script_context->v8_context()); |
[email protected] | 800f987 | 2014-06-12 04:12:51 | [diff] [blame] | 100 | |
| 101 | ExternallyConnectableInfo* externally_connectable = |
| 102 | ExternallyConnectableInfo::Get(extension); |
| 103 | if (externally_connectable && |
| 104 | externally_connectable->accepts_tls_channel_id) { |
bashi | 7b0e3c9 | 2015-06-23 05:19:56 | [diff] [blame] | 105 | v8::Local<v8::String> v8_tls_channel_id; |
| 106 | if (ToV8String(isolate, tls_channel_id.c_str(), &v8_tls_channel_id)) |
| 107 | tls_channel_id_value = v8_tls_channel_id; |
[email protected] | 800f987 | 2014-06-12 04:12:51 | [diff] [blame] | 108 | } |
vrk | 85dfc5c | 2015-01-10 00:05:32 | [diff] [blame] | 109 | |
lazyboy | 0b46a97 | 2015-06-16 02:54:41 | [diff] [blame] | 110 | if (info.guest_process_id != content::ChildProcessHost::kInvalidUniqueID) { |
vrk | 85dfc5c | 2015-01-10 00:05:32 | [diff] [blame] | 111 | guest_process_id = v8::Integer::New(isolate, info.guest_process_id); |
lazyboy | 0b46a97 | 2015-06-16 02:54:41 | [diff] [blame] | 112 | guest_render_frame_routing_id = |
| 113 | v8::Integer::New(isolate, info.guest_render_frame_routing_id); |
| 114 | } |
[email protected] | 800f987 | 2014-06-12 04:12:51 | [diff] [blame] | 115 | } |
| 116 | |
bashi | 7b0e3c9 | 2015-06-23 05:19:56 | [diff] [blame] | 117 | v8::Local<v8::String> v8_channel_name; |
| 118 | v8::Local<v8::String> v8_source_id; |
| 119 | v8::Local<v8::String> v8_target_extension_id; |
| 120 | v8::Local<v8::String> v8_source_url_spec; |
| 121 | if (!ToV8String(isolate, channel_name.c_str(), &v8_channel_name) || |
| 122 | !ToV8String(isolate, info.source_id.c_str(), &v8_source_id) || |
| 123 | !ToV8String(isolate, target_extension_id.c_str(), |
| 124 | &v8_target_extension_id) || |
| 125 | !ToV8String(isolate, source_url_spec.c_str(), &v8_source_url_spec)) { |
| 126 | NOTREACHED() << "dispatchOnConnect() passed non-string argument"; |
| 127 | return; |
| 128 | } |
| 129 | |
tfarina | f85316f | 2015-04-29 17:03:40 | [diff] [blame] | 130 | v8::Local<v8::Value> arguments[] = { |
[email protected] | 800f987 | 2014-06-12 04:12:51 | [diff] [blame] | 131 | // portId |
| 132 | v8::Integer::New(isolate, target_port_id), |
| 133 | // channelName |
bashi | 7b0e3c9 | 2015-06-23 05:19:56 | [diff] [blame] | 134 | v8_channel_name, |
[email protected] | 800f987 | 2014-06-12 04:12:51 | [diff] [blame] | 135 | // sourceTab |
| 136 | tab, |
rob | 248d6a8 | 2014-11-21 02:04:48 | [diff] [blame] | 137 | // source_frame_id |
| 138 | v8::Integer::New(isolate, source->frame_id), |
vrk | 85dfc5c | 2015-01-10 00:05:32 | [diff] [blame] | 139 | // guestProcessId |
| 140 | guest_process_id, |
lazyboy | 0b46a97 | 2015-06-16 02:54:41 | [diff] [blame] | 141 | // guestRenderFrameRoutingId |
| 142 | guest_render_frame_routing_id, |
[email protected] | 800f987 | 2014-06-12 04:12:51 | [diff] [blame] | 143 | // sourceExtensionId |
bashi | 7b0e3c9 | 2015-06-23 05:19:56 | [diff] [blame] | 144 | v8_source_id, |
[email protected] | 800f987 | 2014-06-12 04:12:51 | [diff] [blame] | 145 | // targetExtensionId |
bashi | 7b0e3c9 | 2015-06-23 05:19:56 | [diff] [blame] | 146 | v8_target_extension_id, |
[email protected] | 800f987 | 2014-06-12 04:12:51 | [diff] [blame] | 147 | // sourceUrl |
bashi | 7b0e3c9 | 2015-06-23 05:19:56 | [diff] [blame] | 148 | v8_source_url_spec, |
[email protected] | 800f987 | 2014-06-12 04:12:51 | [diff] [blame] | 149 | // tlsChannelId |
| 150 | tls_channel_id_value, |
| 151 | }; |
| 152 | |
tfarina | f85316f | 2015-04-29 17:03:40 | [diff] [blame] | 153 | v8::Local<v8::Value> retval = |
[email protected] | 800f987 | 2014-06-12 04:12:51 | [diff] [blame] | 154 | script_context->module_system()->CallModuleMethod( |
| 155 | "messaging", "dispatchOnConnect", arraysize(arguments), arguments); |
| 156 | |
kalman | 33076cb | 2015-08-11 19:12:07 | [diff] [blame] | 157 | if (!IsEmptyOrUndefied(retval)) { |
[email protected] | 800f987 | 2014-06-12 04:12:51 | [diff] [blame] | 158 | CHECK(retval->IsBoolean()); |
bashi | 7b0e3c9 | 2015-06-23 05:19:56 | [diff] [blame] | 159 | *port_created |= retval.As<v8::Boolean>()->Value(); |
[email protected] | 800f987 | 2014-06-12 04:12:51 | [diff] [blame] | 160 | } else { |
| 161 | LOG(ERROR) << "Empty return value from dispatchOnConnect."; |
| 162 | } |
| 163 | } |
| 164 | |
mlamouri | 9b4c024 | 2015-04-21 10:43:54 | [diff] [blame] | 165 | void DeliverMessageToScriptContext(const Message& message, |
[email protected] | 800f987 | 2014-06-12 04:12:51 | [diff] [blame] | 166 | int target_port_id, |
| 167 | ScriptContext* script_context) { |
kalman | fb6f10ac | 2014-11-06 23:55:35 | [diff] [blame] | 168 | v8::Isolate* isolate = script_context->isolate(); |
[email protected] | 800f987 | 2014-06-12 04:12:51 | [diff] [blame] | 169 | v8::HandleScope handle_scope(isolate); |
| 170 | |
| 171 | // Check to see whether the context has this port before bothering to create |
| 172 | // the message. |
tfarina | f85316f | 2015-04-29 17:03:40 | [diff] [blame] | 173 | v8::Local<v8::Value> port_id_handle = |
[email protected] | 800f987 | 2014-06-12 04:12:51 | [diff] [blame] | 174 | v8::Integer::New(isolate, target_port_id); |
tfarina | f85316f | 2015-04-29 17:03:40 | [diff] [blame] | 175 | v8::Local<v8::Value> has_port = |
| 176 | script_context->module_system()->CallModuleMethod("messaging", "hasPort", |
| 177 | 1, &port_id_handle); |
bashi | 5794de27 | 2015-07-15 00:07:14 | [diff] [blame] | 178 | // Could be empty/undefined if an exception was thrown. |
| 179 | // TODO(kalman): Should this be built into CallModuleMethod? |
kalman | 33076cb | 2015-08-11 19:12:07 | [diff] [blame] | 180 | if (IsEmptyOrUndefied(has_port)) |
bashi | 5794de27 | 2015-07-15 00:07:14 | [diff] [blame] | 181 | return; |
| 182 | CHECK(has_port->IsBoolean()); |
bashi | 7b0e3c9 | 2015-06-23 05:19:56 | [diff] [blame] | 183 | if (!has_port.As<v8::Boolean>()->Value()) |
[email protected] | 800f987 | 2014-06-12 04:12:51 | [diff] [blame] | 184 | return; |
| 185 | |
bashi | 7b0e3c9 | 2015-06-23 05:19:56 | [diff] [blame] | 186 | v8::Local<v8::String> v8_data; |
| 187 | if (!ToV8String(isolate, message.data.c_str(), &v8_data)) |
| 188 | return; |
tfarina | f85316f | 2015-04-29 17:03:40 | [diff] [blame] | 189 | std::vector<v8::Local<v8::Value>> arguments; |
bashi | 7b0e3c9 | 2015-06-23 05:19:56 | [diff] [blame] | 190 | arguments.push_back(v8_data); |
[email protected] | 800f987 | 2014-06-12 04:12:51 | [diff] [blame] | 191 | arguments.push_back(port_id_handle); |
mlamouri | 9b4c024 | 2015-04-21 10:43:54 | [diff] [blame] | 192 | |
dcheng | f6f8066 | 2016-04-20 20:26:04 | [diff] [blame] | 193 | std::unique_ptr<blink::WebScopedUserGesture> web_user_gesture; |
| 194 | std::unique_ptr<blink::WebScopedWindowFocusAllowedIndicator> |
| 195 | allow_window_focus; |
mlamouri | 9b4c024 | 2015-04-21 10:43:54 | [diff] [blame] | 196 | if (message.user_gesture) { |
| 197 | web_user_gesture.reset(new blink::WebScopedUserGesture); |
| 198 | |
| 199 | if (script_context->web_frame()) { |
| 200 | blink::WebDocument document = script_context->web_frame()->document(); |
| 201 | allow_window_focus.reset(new blink::WebScopedWindowFocusAllowedIndicator( |
| 202 | &document)); |
| 203 | } |
| 204 | } |
| 205 | |
[email protected] | 800f987 | 2014-06-12 04:12:51 | [diff] [blame] | 206 | script_context->module_system()->CallModuleMethod( |
| 207 | "messaging", "dispatchOnMessage", &arguments); |
| 208 | } |
| 209 | |
| 210 | void DispatchOnDisconnectToScriptContext(int port_id, |
| 211 | const std::string& error_message, |
| 212 | ScriptContext* script_context) { |
| 213 | v8::Isolate* isolate = script_context->isolate(); |
| 214 | v8::HandleScope handle_scope(isolate); |
| 215 | |
tfarina | f85316f | 2015-04-29 17:03:40 | [diff] [blame] | 216 | std::vector<v8::Local<v8::Value>> arguments; |
[email protected] | 800f987 | 2014-06-12 04:12:51 | [diff] [blame] | 217 | arguments.push_back(v8::Integer::New(isolate, port_id)); |
bashi | 7b0e3c9 | 2015-06-23 05:19:56 | [diff] [blame] | 218 | v8::Local<v8::String> v8_error_message; |
| 219 | if (!error_message.empty()) |
| 220 | ToV8String(isolate, error_message.c_str(), &v8_error_message); |
| 221 | if (!v8_error_message.IsEmpty()) { |
| 222 | arguments.push_back(v8_error_message); |
[email protected] | 800f987 | 2014-06-12 04:12:51 | [diff] [blame] | 223 | } else { |
| 224 | arguments.push_back(v8::Null(isolate)); |
| 225 | } |
| 226 | |
| 227 | script_context->module_system()->CallModuleMethod( |
| 228 | "messaging", "dispatchOnDisconnect", &arguments); |
| 229 | } |
| 230 | |
[email protected] | 0aa477bd | 2009-03-23 22:21:43 | [diff] [blame] | 231 | } // namespace |
| 232 | |
rdevlin.cronin | 4012b3b | 2016-08-31 18:36:47 | [diff] [blame^] | 233 | MessagingBindings::MessagingBindings(ScriptContext* context) |
| 234 | : ObjectBackedNativeHandler(context), weak_ptr_factory_(this) { |
| 235 | RouteFunction("CloseChannel", base::Bind(&MessagingBindings::CloseChannel, |
| 236 | base::Unretained(this))); |
| 237 | RouteFunction("PostMessage", base::Bind(&MessagingBindings::PostMessage, |
| 238 | base::Unretained(this))); |
| 239 | // TODO(fsamuel, kalman): Move BindToGC out of messaging natives. |
| 240 | RouteFunction("BindToGC", base::Bind(&MessagingBindings::BindToGC, |
| 241 | base::Unretained(this))); |
rob | d1db9f6 | 2016-05-25 11:03:10 | [diff] [blame] | 242 | } |
| 243 | |
rdevlin.cronin | 4012b3b | 2016-08-31 18:36:47 | [diff] [blame^] | 244 | MessagingBindings::~MessagingBindings() {} |
| 245 | |
| 246 | // static |
rob | d1db9f6 | 2016-05-25 11:03:10 | [diff] [blame] | 247 | void MessagingBindings::ValidateMessagePort( |
| 248 | const ScriptContextSet& context_set, |
| 249 | int port_id, |
| 250 | content::RenderFrame* render_frame) { |
| 251 | int routing_id = render_frame->GetRoutingID(); |
| 252 | |
| 253 | bool has_port = false; |
| 254 | context_set.ForEach(render_frame, |
| 255 | base::Bind(&HasMessagePort, port_id, &has_port)); |
| 256 | // Note: HasMessagePort invokes a JavaScript function. If the runtime of the |
| 257 | // extension bindings in JS have been compromised, then |render_frame| may be |
| 258 | // invalid at this point. |
| 259 | |
| 260 | // A reply is only sent if the port is missing, because the port is assumed to |
| 261 | // exist unless stated otherwise. |
| 262 | if (!has_port) { |
| 263 | content::RenderThread::Get()->Send( |
| 264 | new ExtensionHostMsg_CloseMessagePort(routing_id, port_id, false)); |
| 265 | } |
[email protected] | 0aa477bd | 2009-03-23 22:21:43 | [diff] [blame] | 266 | } |
[email protected] | b2e86ec1 | 2011-09-15 01:59:06 | [diff] [blame] | 267 | |
[email protected] | f9db247 | 2012-04-02 20:42:45 | [diff] [blame] | 268 | // static |
[email protected] | d710efe | 2013-07-30 22:25:48 | [diff] [blame] | 269 | void MessagingBindings::DispatchOnConnect( |
[email protected] | 800f987 | 2014-06-12 04:12:51 | [diff] [blame] | 270 | const ScriptContextSet& context_set, |
[email protected] | f9db247 | 2012-04-02 20:42:45 | [diff] [blame] | 271 | int target_port_id, |
| 272 | const std::string& channel_name, |
rob | 248d6a8 | 2014-11-21 02:04:48 | [diff] [blame] | 273 | const ExtensionMsg_TabConnectionInfo& source, |
[email protected] | 800f987 | 2014-06-12 04:12:51 | [diff] [blame] | 274 | const ExtensionMsg_ExternalConnectionInfo& info, |
[email protected] | 8ad95b7 | 2013-10-16 02:54:11 | [diff] [blame] | 275 | const std::string& tls_channel_id, |
rob | 248d6a8 | 2014-11-21 02:04:48 | [diff] [blame] | 276 | content::RenderFrame* restrict_to_render_frame) { |
rob | 02aac0f | 2016-05-02 17:07:47 | [diff] [blame] | 277 | int routing_id = restrict_to_render_frame |
| 278 | ? restrict_to_render_frame->GetRoutingID() |
| 279 | : MSG_ROUTING_NONE; |
kalman | 62b5911d | 2015-04-04 02:33:09 | [diff] [blame] | 280 | bool port_created = false; |
| 281 | context_set.ForEach( |
rdevlin.cronin | c5d9a0ea | 2015-06-23 21:29:10 | [diff] [blame] | 282 | info.target_id, restrict_to_render_frame, |
rob | 248d6a8 | 2014-11-21 02:04:48 | [diff] [blame] | 283 | base::Bind(&DispatchOnConnectToScriptContext, target_port_id, |
kalman | 62b5911d | 2015-04-04 02:33:09 | [diff] [blame] | 284 | channel_name, &source, info, tls_channel_id, &port_created)); |
rob | 02aac0f | 2016-05-02 17:07:47 | [diff] [blame] | 285 | // Note: |restrict_to_render_frame| may have been deleted at this point! |
kalman | 62b5911d | 2015-04-04 02:33:09 | [diff] [blame] | 286 | |
rob | 3e2a073 | 2016-01-06 21:22:09 | [diff] [blame] | 287 | if (port_created) { |
| 288 | content::RenderThread::Get()->Send( |
| 289 | new ExtensionHostMsg_OpenMessagePort(routing_id, target_port_id)); |
| 290 | } else { |
| 291 | content::RenderThread::Get()->Send(new ExtensionHostMsg_CloseMessagePort( |
| 292 | routing_id, target_port_id, false)); |
kalman | 62b5911d | 2015-04-04 02:33:09 | [diff] [blame] | 293 | } |
[email protected] | f9db247 | 2012-04-02 20:42:45 | [diff] [blame] | 294 | } |
| 295 | |
| 296 | // static |
[email protected] | d710efe | 2013-07-30 22:25:48 | [diff] [blame] | 297 | void MessagingBindings::DeliverMessage( |
[email protected] | 800f987 | 2014-06-12 04:12:51 | [diff] [blame] | 298 | const ScriptContextSet& context_set, |
[email protected] | b2e86ec1 | 2011-09-15 01:59:06 | [diff] [blame] | 299 | int target_port_id, |
[email protected] | 8865fea | 2013-10-23 01:17:26 | [diff] [blame] | 300 | const Message& message, |
rob | 248d6a8 | 2014-11-21 02:04:48 | [diff] [blame] | 301 | content::RenderFrame* restrict_to_render_frame) { |
kalman | 62b5911d | 2015-04-04 02:33:09 | [diff] [blame] | 302 | context_set.ForEach( |
rdevlin.cronin | c5d9a0ea | 2015-06-23 21:29:10 | [diff] [blame] | 303 | restrict_to_render_frame, |
mlamouri | 9b4c024 | 2015-04-21 10:43:54 | [diff] [blame] | 304 | base::Bind(&DeliverMessageToScriptContext, message, target_port_id)); |
[email protected] | b2e86ec1 | 2011-09-15 01:59:06 | [diff] [blame] | 305 | } |
[email protected] | 83820d4 | 2011-11-12 22:03:11 | [diff] [blame] | 306 | |
[email protected] | f9db247 | 2012-04-02 20:42:45 | [diff] [blame] | 307 | // static |
[email protected] | d710efe | 2013-07-30 22:25:48 | [diff] [blame] | 308 | void MessagingBindings::DispatchOnDisconnect( |
[email protected] | 800f987 | 2014-06-12 04:12:51 | [diff] [blame] | 309 | const ScriptContextSet& context_set, |
[email protected] | f9db247 | 2012-04-02 20:42:45 | [diff] [blame] | 310 | int port_id, |
[email protected] | d6b3961 | 2013-03-08 02:33:13 | [diff] [blame] | 311 | const std::string& error_message, |
rob | 248d6a8 | 2014-11-21 02:04:48 | [diff] [blame] | 312 | content::RenderFrame* restrict_to_render_frame) { |
kalman | 62b5911d | 2015-04-04 02:33:09 | [diff] [blame] | 313 | context_set.ForEach( |
rdevlin.cronin | c5d9a0ea | 2015-06-23 21:29:10 | [diff] [blame] | 314 | restrict_to_render_frame, |
[email protected] | 800f987 | 2014-06-12 04:12:51 | [diff] [blame] | 315 | base::Bind(&DispatchOnDisconnectToScriptContext, port_id, error_message)); |
[email protected] | f9db247 | 2012-04-02 20:42:45 | [diff] [blame] | 316 | } |
| 317 | |
rdevlin.cronin | 4012b3b | 2016-08-31 18:36:47 | [diff] [blame^] | 318 | void MessagingBindings::PostMessage( |
| 319 | const v8::FunctionCallbackInfo<v8::Value>& args) { |
| 320 | // Arguments are (int32_t port_id, string message). |
| 321 | CHECK(args.Length() == 2 && args[0]->IsInt32() && args[1]->IsString()); |
| 322 | |
| 323 | int port_id = args[0].As<v8::Int32>()->Value(); |
| 324 | |
| 325 | content::RenderFrame* render_frame = context()->GetRenderFrame(); |
| 326 | if (render_frame) { |
| 327 | render_frame->Send(new ExtensionHostMsg_PostMessage( |
| 328 | render_frame->GetRoutingID(), port_id, |
| 329 | Message(*v8::String::Utf8Value(args[1]), |
| 330 | blink::WebUserGestureIndicator::isProcessingUserGesture()))); |
| 331 | } |
| 332 | } |
| 333 | |
| 334 | void MessagingBindings::CloseChannel( |
| 335 | const v8::FunctionCallbackInfo<v8::Value>& args) { |
| 336 | // Arguments are (int32_t port_id, bool force_close). |
| 337 | CHECK_EQ(2, args.Length()); |
| 338 | CHECK(args[0]->IsInt32()); |
| 339 | CHECK(args[1]->IsBoolean()); |
| 340 | |
| 341 | int port_id = args[0].As<v8::Int32>()->Value(); |
| 342 | bool force_close = args[1].As<v8::Boolean>()->Value(); |
| 343 | ClosePort(port_id, force_close); |
| 344 | } |
| 345 | |
| 346 | void MessagingBindings::BindToGC( |
| 347 | const v8::FunctionCallbackInfo<v8::Value>& args) { |
| 348 | CHECK(args.Length() == 3 && args[0]->IsObject() && args[1]->IsFunction() && |
| 349 | args[2]->IsInt32()); |
| 350 | int port_id = args[2].As<v8::Int32>()->Value(); |
| 351 | base::Closure fallback = base::Bind(&base::DoNothing); |
| 352 | if (port_id >= 0) { |
| 353 | // TODO(robwu): Falling back to closing the port shouldn't be needed. If |
| 354 | // the script context is destroyed, then the frame has navigated. But that |
| 355 | // is already detected by the browser, so this logic is redundant. Remove |
| 356 | // this fallback (and move BindToGC out of messaging because it is also |
| 357 | // used in other places that have nothing to do with messaging...). |
| 358 | fallback = base::Bind(&MessagingBindings::ClosePort, |
| 359 | weak_ptr_factory_.GetWeakPtr(), port_id, |
| 360 | false /* force_close */); |
| 361 | } |
| 362 | // Destroys itself when the object is GC'd or context is invalidated. |
| 363 | new GCCallback(context(), args[0].As<v8::Object>(), |
| 364 | args[1].As<v8::Function>(), fallback); |
| 365 | } |
| 366 | |
| 367 | void MessagingBindings::ClosePort(int port_id, bool force_close) { |
| 368 | // TODO(robwu): Merge this logic with CloseChannel once the TODO in BindToGC |
| 369 | // has been addressed. |
| 370 | content::RenderFrame* render_frame = context()->GetRenderFrame(); |
| 371 | if (render_frame) { |
| 372 | render_frame->Send(new ExtensionHostMsg_CloseMessagePort( |
| 373 | render_frame->GetRoutingID(), port_id, force_close)); |
| 374 | } |
| 375 | } |
| 376 | |
[email protected] | 8fe74bf | 2012-08-07 21:08:42 | [diff] [blame] | 377 | } // namespace extensions |