OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "extensions/renderer/messaging_bindings.h" | 5 #include "extensions/renderer/messaging_bindings.h" |
6 | 6 |
7 #include <map> | 7 #include <map> |
8 #include <string> | 8 #include <string> |
9 | 9 |
10 #include "base/basictypes.h" | 10 #include "base/basictypes.h" |
(...skipping 219 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
230 CHECK(args.Length() == 2 && args[0]->IsObject() && args[1]->IsFunction()); | 230 CHECK(args.Length() == 2 && args[0]->IsObject() && args[1]->IsFunction()); |
231 GCCallback::Bind(args[0].As<v8::Object>(), | 231 GCCallback::Bind(args[0].As<v8::Object>(), |
232 args[1].As<v8::Function>(), | 232 args[1].As<v8::Function>(), |
233 args.GetIsolate()); | 233 args.GetIsolate()); |
234 } | 234 } |
235 | 235 |
236 // Dispatcher handle. Not owned. | 236 // Dispatcher handle. Not owned. |
237 Dispatcher* dispatcher_; | 237 Dispatcher* dispatcher_; |
238 }; | 238 }; |
239 | 239 |
| 240 void DispatchOnConnectToScriptContext( |
| 241 int target_port_id, |
| 242 const std::string& channel_name, |
| 243 const base::DictionaryValue* source_tab, |
| 244 const ExtensionMsg_ExternalConnectionInfo& info, |
| 245 const std::string& tls_channel_id, |
| 246 bool* port_created, |
| 247 ScriptContext* script_context) { |
| 248 v8::Isolate* isolate = script_context->isolate(); |
| 249 v8::HandleScope handle_scope(isolate); |
| 250 |
| 251 scoped_ptr<V8ValueConverter> converter(V8ValueConverter::create()); |
| 252 |
| 253 const std::string& source_url_spec = info.source_url.spec(); |
| 254 std::string target_extension_id = script_context->GetExtensionID(); |
| 255 const Extension* extension = script_context->extension(); |
| 256 |
| 257 v8::Handle<v8::Value> tab = v8::Null(isolate); |
| 258 v8::Handle<v8::Value> tls_channel_id_value = v8::Undefined(isolate); |
| 259 |
| 260 if (extension) { |
| 261 if (!source_tab->empty() && !extension->is_platform_app()) |
| 262 tab = converter->ToV8Value(source_tab, script_context->v8_context()); |
| 263 |
| 264 ExternallyConnectableInfo* externally_connectable = |
| 265 ExternallyConnectableInfo::Get(extension); |
| 266 if (externally_connectable && |
| 267 externally_connectable->accepts_tls_channel_id) { |
| 268 tls_channel_id_value = v8::String::NewFromUtf8(isolate, |
| 269 tls_channel_id.c_str(), |
| 270 v8::String::kNormalString, |
| 271 tls_channel_id.size()); |
| 272 } |
| 273 } |
| 274 |
| 275 v8::Handle<v8::Value> arguments[] = { |
| 276 // portId |
| 277 v8::Integer::New(isolate, target_port_id), |
| 278 // channelName |
| 279 v8::String::NewFromUtf8(isolate, |
| 280 channel_name.c_str(), |
| 281 v8::String::kNormalString, |
| 282 channel_name.size()), |
| 283 // sourceTab |
| 284 tab, |
| 285 // sourceExtensionId |
| 286 v8::String::NewFromUtf8(isolate, |
| 287 info.source_id.c_str(), |
| 288 v8::String::kNormalString, |
| 289 info.source_id.size()), |
| 290 // targetExtensionId |
| 291 v8::String::NewFromUtf8(isolate, |
| 292 target_extension_id.c_str(), |
| 293 v8::String::kNormalString, |
| 294 target_extension_id.size()), |
| 295 // sourceUrl |
| 296 v8::String::NewFromUtf8(isolate, |
| 297 source_url_spec.c_str(), |
| 298 v8::String::kNormalString, |
| 299 source_url_spec.size()), |
| 300 // tlsChannelId |
| 301 tls_channel_id_value, |
| 302 }; |
| 303 |
| 304 v8::Handle<v8::Value> retval = |
| 305 script_context->module_system()->CallModuleMethod( |
| 306 "messaging", "dispatchOnConnect", arraysize(arguments), arguments); |
| 307 |
| 308 if (!retval.IsEmpty()) { |
| 309 CHECK(retval->IsBoolean()); |
| 310 *port_created |= retval->BooleanValue(); |
| 311 } else { |
| 312 LOG(ERROR) << "Empty return value from dispatchOnConnect."; |
| 313 } |
| 314 } |
| 315 |
| 316 void DeliverMessageToScriptContext(const std::string& message_data, |
| 317 int target_port_id, |
| 318 ScriptContext* script_context) { |
| 319 v8::Isolate* isolate = v8::Isolate::GetCurrent(); |
| 320 v8::HandleScope handle_scope(isolate); |
| 321 |
| 322 // Check to see whether the context has this port before bothering to create |
| 323 // the message. |
| 324 v8::Handle<v8::Value> port_id_handle = |
| 325 v8::Integer::New(isolate, target_port_id); |
| 326 v8::Handle<v8::Value> has_port = |
| 327 script_context->module_system()->CallModuleMethod( |
| 328 "messaging", "hasPort", 1, &port_id_handle); |
| 329 |
| 330 CHECK(!has_port.IsEmpty()); |
| 331 if (!has_port->BooleanValue()) |
| 332 return; |
| 333 |
| 334 std::vector<v8::Handle<v8::Value> > arguments; |
| 335 arguments.push_back(v8::String::NewFromUtf8(isolate, |
| 336 message_data.c_str(), |
| 337 v8::String::kNormalString, |
| 338 message_data.size())); |
| 339 arguments.push_back(port_id_handle); |
| 340 script_context->module_system()->CallModuleMethod( |
| 341 "messaging", "dispatchOnMessage", &arguments); |
| 342 } |
| 343 |
| 344 void DispatchOnDisconnectToScriptContext(int port_id, |
| 345 const std::string& error_message, |
| 346 ScriptContext* script_context) { |
| 347 v8::Isolate* isolate = script_context->isolate(); |
| 348 v8::HandleScope handle_scope(isolate); |
| 349 |
| 350 std::vector<v8::Handle<v8::Value> > arguments; |
| 351 arguments.push_back(v8::Integer::New(isolate, port_id)); |
| 352 if (!error_message.empty()) { |
| 353 arguments.push_back( |
| 354 v8::String::NewFromUtf8(isolate, error_message.c_str())); |
| 355 } else { |
| 356 arguments.push_back(v8::Null(isolate)); |
| 357 } |
| 358 |
| 359 script_context->module_system()->CallModuleMethod( |
| 360 "messaging", "dispatchOnDisconnect", &arguments); |
| 361 } |
| 362 |
240 } // namespace | 363 } // namespace |
241 | 364 |
242 ObjectBackedNativeHandler* MessagingBindings::Get(Dispatcher* dispatcher, | 365 ObjectBackedNativeHandler* MessagingBindings::Get(Dispatcher* dispatcher, |
243 ScriptContext* context) { | 366 ScriptContext* context) { |
244 return new ExtensionImpl(dispatcher, context); | 367 return new ExtensionImpl(dispatcher, context); |
245 } | 368 } |
246 | 369 |
247 // static | 370 // static |
248 void MessagingBindings::DispatchOnConnect( | 371 void MessagingBindings::DispatchOnConnect( |
249 const ScriptContextSet::ContextSet& contexts, | 372 const ScriptContextSet& context_set, |
250 int target_port_id, | 373 int target_port_id, |
251 const std::string& channel_name, | 374 const std::string& channel_name, |
252 const base::DictionaryValue& source_tab, | 375 const base::DictionaryValue& source_tab, |
253 const std::string& source_extension_id, | 376 const ExtensionMsg_ExternalConnectionInfo& info, |
254 const std::string& target_extension_id, | |
255 const GURL& source_url, | |
256 const std::string& tls_channel_id, | 377 const std::string& tls_channel_id, |
257 content::RenderView* restrict_to_render_view) { | 378 content::RenderView* restrict_to_render_view) { |
258 v8::Isolate* isolate = v8::Isolate::GetCurrent(); | |
259 v8::HandleScope handle_scope(isolate); | |
260 | |
261 scoped_ptr<V8ValueConverter> converter(V8ValueConverter::create()); | |
262 | |
263 bool port_created = false; | 379 bool port_created = false; |
264 std::string source_url_spec = source_url.spec(); | 380 context_set.ForEach(info.target_id, |
265 | 381 restrict_to_render_view, |
266 // TODO(kalman): pass in the full ScriptContextSet; call ForEach. | 382 base::Bind(&DispatchOnConnectToScriptContext, |
267 for (ScriptContextSet::ContextSet::const_iterator it = contexts.begin(); | 383 target_port_id, |
268 it != contexts.end(); | 384 channel_name, |
269 ++it) { | 385 &source_tab, |
270 if (restrict_to_render_view && | 386 info, |
271 restrict_to_render_view != (*it)->GetRenderView()) { | 387 tls_channel_id, |
272 continue; | 388 &port_created)); |
273 } | |
274 | |
275 // TODO(kalman): remove when ContextSet::ForEach is available. | |
276 if ((*it)->v8_context().IsEmpty()) | |
277 continue; | |
278 | |
279 v8::Handle<v8::Value> tab = v8::Null(isolate); | |
280 v8::Handle<v8::Value> tls_channel_id_value = v8::Undefined(isolate); | |
281 const Extension* extension = (*it)->extension(); | |
282 if (extension) { | |
283 if (!source_tab.empty() && !extension->is_platform_app()) | |
284 tab = converter->ToV8Value(&source_tab, (*it)->v8_context()); | |
285 | |
286 ExternallyConnectableInfo* externally_connectable = | |
287 ExternallyConnectableInfo::Get(extension); | |
288 if (externally_connectable && | |
289 externally_connectable->accepts_tls_channel_id) { | |
290 tls_channel_id_value = | |
291 v8::String::NewFromUtf8(isolate, | |
292 tls_channel_id.c_str(), | |
293 v8::String::kNormalString, | |
294 tls_channel_id.size()); | |
295 } | |
296 } | |
297 | |
298 v8::Handle<v8::Value> arguments[] = { | |
299 // portId | |
300 v8::Integer::New(isolate, target_port_id), | |
301 // channelName | |
302 v8::String::NewFromUtf8(isolate, | |
303 channel_name.c_str(), | |
304 v8::String::kNormalString, | |
305 channel_name.size()), | |
306 // sourceTab | |
307 tab, | |
308 // sourceExtensionId | |
309 v8::String::NewFromUtf8(isolate, | |
310 source_extension_id.c_str(), | |
311 v8::String::kNormalString, | |
312 source_extension_id.size()), | |
313 // targetExtensionId | |
314 v8::String::NewFromUtf8(isolate, | |
315 target_extension_id.c_str(), | |
316 v8::String::kNormalString, | |
317 target_extension_id.size()), | |
318 // sourceUrl | |
319 v8::String::NewFromUtf8(isolate, | |
320 source_url_spec.c_str(), | |
321 v8::String::kNormalString, | |
322 source_url_spec.size()), | |
323 // tlsChannelId | |
324 tls_channel_id_value, | |
325 }; | |
326 | |
327 v8::Handle<v8::Value> retval = (*it)->module_system()->CallModuleMethod( | |
328 "messaging", "dispatchOnConnect", arraysize(arguments), arguments); | |
329 | |
330 if (retval.IsEmpty()) { | |
331 LOG(ERROR) << "Empty return value from dispatchOnConnect."; | |
332 continue; | |
333 } | |
334 | |
335 CHECK(retval->IsBoolean()); | |
336 port_created |= retval->BooleanValue(); | |
337 } | |
338 | 389 |
339 // If we didn't create a port, notify the other end of the channel (treat it | 390 // If we didn't create a port, notify the other end of the channel (treat it |
340 // as a disconnect). | 391 // as a disconnect). |
341 if (!port_created) { | 392 if (!port_created) { |
342 content::RenderThread::Get()->Send(new ExtensionHostMsg_CloseChannel( | 393 content::RenderThread::Get()->Send(new ExtensionHostMsg_CloseChannel( |
343 target_port_id, kReceivingEndDoesntExistError)); | 394 target_port_id, kReceivingEndDoesntExistError)); |
344 } | 395 } |
345 } | 396 } |
346 | 397 |
347 // static | 398 // static |
348 void MessagingBindings::DeliverMessage( | 399 void MessagingBindings::DeliverMessage( |
349 const ScriptContextSet::ContextSet& contexts, | 400 const ScriptContextSet& context_set, |
350 int target_port_id, | 401 int target_port_id, |
351 const Message& message, | 402 const Message& message, |
352 content::RenderView* restrict_to_render_view) { | 403 content::RenderView* restrict_to_render_view) { |
353 scoped_ptr<blink::WebScopedUserGesture> web_user_gesture; | 404 scoped_ptr<blink::WebScopedUserGesture> web_user_gesture; |
354 scoped_ptr<blink::WebScopedWindowFocusAllowedIndicator> allow_window_focus; | 405 scoped_ptr<blink::WebScopedWindowFocusAllowedIndicator> allow_window_focus; |
355 if (message.user_gesture) { | 406 if (message.user_gesture) { |
356 web_user_gesture.reset(new blink::WebScopedUserGesture); | 407 web_user_gesture.reset(new blink::WebScopedUserGesture); |
357 allow_window_focus.reset(new blink::WebScopedWindowFocusAllowedIndicator); | 408 allow_window_focus.reset(new blink::WebScopedWindowFocusAllowedIndicator); |
358 } | 409 } |
359 | 410 |
360 v8::Isolate* isolate = v8::Isolate::GetCurrent(); | 411 context_set.ForEach( |
361 v8::HandleScope handle_scope(isolate); | 412 restrict_to_render_view, |
362 | 413 base::Bind(&DeliverMessageToScriptContext, message.data, target_port_id)); |
363 // TODO(kalman): pass in the full ScriptContextSet; call ForEach. | |
364 for (ScriptContextSet::ContextSet::const_iterator it = contexts.begin(); | |
365 it != contexts.end(); | |
366 ++it) { | |
367 if (restrict_to_render_view && | |
368 restrict_to_render_view != (*it)->GetRenderView()) { | |
369 continue; | |
370 } | |
371 | |
372 // TODO(kalman): remove when ContextSet::ForEach is available. | |
373 if ((*it)->v8_context().IsEmpty()) | |
374 continue; | |
375 | |
376 // Check to see whether the context has this port before bothering to create | |
377 // the message. | |
378 v8::Handle<v8::Value> port_id_handle = | |
379 v8::Integer::New(isolate, target_port_id); | |
380 v8::Handle<v8::Value> has_port = (*it)->module_system()->CallModuleMethod( | |
381 "messaging", "hasPort", 1, &port_id_handle); | |
382 | |
383 CHECK(!has_port.IsEmpty()); | |
384 if (!has_port->BooleanValue()) | |
385 continue; | |
386 | |
387 std::vector<v8::Handle<v8::Value> > arguments; | |
388 arguments.push_back(v8::String::NewFromUtf8(isolate, | |
389 message.data.c_str(), | |
390 v8::String::kNormalString, | |
391 message.data.size())); | |
392 arguments.push_back(port_id_handle); | |
393 (*it)->module_system()->CallModuleMethod( | |
394 "messaging", "dispatchOnMessage", &arguments); | |
395 } | |
396 } | 414 } |
397 | 415 |
398 // static | 416 // static |
399 void MessagingBindings::DispatchOnDisconnect( | 417 void MessagingBindings::DispatchOnDisconnect( |
400 const ScriptContextSet::ContextSet& contexts, | 418 const ScriptContextSet& context_set, |
401 int port_id, | 419 int port_id, |
402 const std::string& error_message, | 420 const std::string& error_message, |
403 content::RenderView* restrict_to_render_view) { | 421 content::RenderView* restrict_to_render_view) { |
404 v8::Isolate* isolate = v8::Isolate::GetCurrent(); | 422 context_set.ForEach( |
405 v8::HandleScope handle_scope(isolate); | 423 restrict_to_render_view, |
406 | 424 base::Bind(&DispatchOnDisconnectToScriptContext, port_id, error_message)); |
407 // TODO(kalman): pass in the full ScriptContextSet; call ForEach. | |
408 for (ScriptContextSet::ContextSet::const_iterator it = contexts.begin(); | |
409 it != contexts.end(); | |
410 ++it) { | |
411 if (restrict_to_render_view && | |
412 restrict_to_render_view != (*it)->GetRenderView()) { | |
413 continue; | |
414 } | |
415 | |
416 // TODO(kalman): remove when ContextSet::ForEach is available. | |
417 if ((*it)->v8_context().IsEmpty()) | |
418 continue; | |
419 | |
420 std::vector<v8::Handle<v8::Value> > arguments; | |
421 arguments.push_back(v8::Integer::New(isolate, port_id)); | |
422 if (!error_message.empty()) { | |
423 arguments.push_back( | |
424 v8::String::NewFromUtf8(isolate, error_message.c_str())); | |
425 } else { | |
426 arguments.push_back(v8::Null(isolate)); | |
427 } | |
428 (*it)->module_system()->CallModuleMethod( | |
429 "messaging", "dispatchOnDisconnect", &arguments); | |
430 } | |
431 } | 425 } |
432 | 426 |
433 } // namespace extensions | 427 } // namespace extensions |
OLD | NEW |