Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 "chrome/renderer/extensions/messaging_bindings.h" | 5 #include "chrome/renderer/extensions/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" |
| 11 #include "base/bind.h" | 11 #include "base/bind.h" |
| 12 #include "base/bind_helpers.h" | 12 #include "base/bind_helpers.h" |
| 13 #include "base/lazy_instance.h" | 13 #include "base/lazy_instance.h" |
| 14 #include "base/message_loop/message_loop.h" | 14 #include "base/message_loop/message_loop.h" |
| 15 #include "base/values.h" | 15 #include "base/values.h" |
| 16 #include "chrome/common/extensions/manifest_handlers/externally_connectable.h" | 16 #include "chrome/common/extensions/manifest_handlers/externally_connectable.h" |
| 17 #include "chrome/common/url_constants.h" | 17 #include "chrome/common/url_constants.h" |
| 18 #include "chrome/renderer/extensions/chrome_v8_context.h" | |
| 19 #include "chrome/renderer/extensions/chrome_v8_context_set.h" | |
| 20 #include "chrome/renderer/extensions/chrome_v8_extension.h" | |
| 21 #include "chrome/renderer/extensions/dispatcher.h" | 18 #include "chrome/renderer/extensions/dispatcher.h" |
| 22 #include "content/public/renderer/render_thread.h" | 19 #include "content/public/renderer/render_thread.h" |
| 23 #include "content/public/renderer/render_view.h" | 20 #include "content/public/renderer/render_view.h" |
| 24 #include "content/public/renderer/v8_value_converter.h" | 21 #include "content/public/renderer/v8_value_converter.h" |
| 25 #include "extensions/common/api/messaging/message.h" | 22 #include "extensions/common/api/messaging/message.h" |
| 26 #include "extensions/common/extension_messages.h" | 23 #include "extensions/common/extension_messages.h" |
| 27 #include "extensions/renderer/event_bindings.h" | 24 #include "extensions/renderer/event_bindings.h" |
| 25 #include "extensions/renderer/object_backed_native_handler.h" | |
| 28 #include "extensions/renderer/scoped_persistent.h" | 26 #include "extensions/renderer/scoped_persistent.h" |
| 29 #include "grit/renderer_resources.h" | 27 #include "extensions/renderer/script_context.h" |
| 28 #include "extensions/renderer/script_context_set.h" | |
| 30 #include "third_party/WebKit/public/web/WebScopedMicrotaskSuppression.h" | 29 #include "third_party/WebKit/public/web/WebScopedMicrotaskSuppression.h" |
| 31 #include "third_party/WebKit/public/web/WebScopedUserGesture.h" | 30 #include "third_party/WebKit/public/web/WebScopedUserGesture.h" |
| 32 #include "third_party/WebKit/public/web/WebScopedWindowFocusAllowedIndicator.h" | 31 #include "third_party/WebKit/public/web/WebScopedWindowFocusAllowedIndicator.h" |
| 33 #include "third_party/WebKit/public/web/WebUserGestureIndicator.h" | 32 #include "third_party/WebKit/public/web/WebUserGestureIndicator.h" |
| 34 #include "v8/include/v8.h" | 33 #include "v8/include/v8.h" |
| 35 | 34 |
| 36 // Message passing API example (in a content script): | 35 // Message passing API example (in a content script): |
| 37 // var extension = | 36 // var extension = |
| 38 // new chrome.Extension('00123456789abcdef0123456789abcdef0123456'); | 37 // new chrome.Extension('00123456789abcdef0123456789abcdef0123456'); |
| 39 // var port = runtime.connect(); | 38 // var port = runtime.connect(); |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 71 } | 70 } |
| 72 | 71 |
| 73 void ClearPortData(int port_id) { | 72 void ClearPortData(int port_id) { |
| 74 g_extension_data.Get().ports.erase(port_id); | 73 g_extension_data.Get().ports.erase(port_id); |
| 75 } | 74 } |
| 76 | 75 |
| 77 const char kPortClosedError[] = "Attempting to use a disconnected port object"; | 76 const char kPortClosedError[] = "Attempting to use a disconnected port object"; |
| 78 const char kReceivingEndDoesntExistError[] = | 77 const char kReceivingEndDoesntExistError[] = |
| 79 "Could not establish connection. Receiving end does not exist."; | 78 "Could not establish connection. Receiving end does not exist."; |
| 80 | 79 |
| 81 class ExtensionImpl : public ChromeV8Extension { | 80 class ExtensionImpl : public ObjectBackedNativeHandler { |
| 82 public: | 81 public: |
| 83 ExtensionImpl(Dispatcher* dispatcher, ChromeV8Context* context) | 82 ExtensionImpl(Dispatcher* dispatcher, ScriptContext* context) |
| 84 : ChromeV8Extension(dispatcher, context) { | 83 : ObjectBackedNativeHandler(context), dispatcher_(dispatcher) { |
| 85 RouteFunction("CloseChannel", | 84 RouteFunction("CloseChannel", |
| 86 base::Bind(&ExtensionImpl::CloseChannel, base::Unretained(this))); | 85 base::Bind(&ExtensionImpl::CloseChannel, base::Unretained(this))); |
| 87 RouteFunction("PortAddRef", | 86 RouteFunction("PortAddRef", |
| 88 base::Bind(&ExtensionImpl::PortAddRef, base::Unretained(this))); | 87 base::Bind(&ExtensionImpl::PortAddRef, base::Unretained(this))); |
| 89 RouteFunction("PortRelease", | 88 RouteFunction("PortRelease", |
| 90 base::Bind(&ExtensionImpl::PortRelease, base::Unretained(this))); | 89 base::Bind(&ExtensionImpl::PortRelease, base::Unretained(this))); |
| 91 RouteFunction("PostMessage", | 90 RouteFunction("PostMessage", |
| 92 base::Bind(&ExtensionImpl::PostMessage, base::Unretained(this))); | 91 base::Bind(&ExtensionImpl::PostMessage, base::Unretained(this))); |
| 93 // TODO(fsamuel, kalman): Move BindToGC out of messaging natives. | 92 // TODO(fsamuel, kalman): Move BindToGC out of messaging natives. |
| 94 RouteFunction("BindToGC", | 93 RouteFunction("BindToGC", |
| 95 base::Bind(&ExtensionImpl::BindToGC, base::Unretained(this))); | 94 base::Bind(&ExtensionImpl::BindToGC, base::Unretained(this))); |
| 96 } | 95 } |
| 97 | 96 |
| 98 virtual ~ExtensionImpl() {} | 97 virtual ~ExtensionImpl() {} |
| 99 | 98 |
| 99 private: | |
| 100 void ClearPortDataAndNotifyDispatcher(int port_id) { | 100 void ClearPortDataAndNotifyDispatcher(int port_id) { |
| 101 ClearPortData(port_id); | 101 ClearPortData(port_id); |
| 102 dispatcher()->ClearPortData(port_id); | 102 dispatcher_->ClearPortData(port_id); |
|
not at google - send to devlin
2014/04/17 15:11:10
why does Dispatcher know anything about ports..? w
| |
| 103 } | 103 } |
| 104 | 104 |
| 105 // Sends a message along the given channel. | 105 // Sends a message along the given channel. |
| 106 void PostMessage(const v8::FunctionCallbackInfo<v8::Value>& args) { | 106 void PostMessage(const v8::FunctionCallbackInfo<v8::Value>& args) { |
| 107 content::RenderView* renderview = GetRenderView(); | 107 content::RenderView* renderview = context()->GetRenderView(); |
| 108 if (!renderview) | 108 if (!renderview) |
| 109 return; | 109 return; |
| 110 | 110 |
| 111 // Arguments are (int32 port_id, string message). | 111 // Arguments are (int32 port_id, string message). |
| 112 CHECK(args.Length() == 2 && | 112 CHECK(args.Length() == 2 && |
| 113 args[0]->IsInt32() && | 113 args[0]->IsInt32() && |
| 114 args[1]->IsString()); | 114 args[1]->IsString()); |
| 115 | 115 |
| 116 int port_id = args[0]->Int32Value(); | 116 int port_id = args[0]->Int32Value(); |
| 117 if (!HasPortData(port_id)) { | 117 if (!HasPortData(port_id)) { |
| (...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 225 // | 225 // |
| 226 // Binds |callback| to be invoked *sometime after* |object| is garbage | 226 // Binds |callback| to be invoked *sometime after* |object| is garbage |
| 227 // collected. We don't call the method re-entrantly so as to avoid executing | 227 // collected. We don't call the method re-entrantly so as to avoid executing |
| 228 // JS in some bizarro undefined mid-GC state. | 228 // JS in some bizarro undefined mid-GC state. |
| 229 void BindToGC(const v8::FunctionCallbackInfo<v8::Value>& args) { | 229 void BindToGC(const v8::FunctionCallbackInfo<v8::Value>& args) { |
| 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 | |
| 236 // Dispatcher handle. Not owned. | |
| 237 Dispatcher* dispatcher_; | |
| 235 }; | 238 }; |
| 236 | 239 |
| 237 } // namespace | 240 } // namespace |
| 238 | 241 |
| 239 ChromeV8Extension* MessagingBindings::Get( | 242 ObjectBackedNativeHandler* MessagingBindings::Get(Dispatcher* dispatcher, |
| 240 Dispatcher* dispatcher, | 243 ScriptContext* context) { |
| 241 ChromeV8Context* context) { | |
| 242 return new ExtensionImpl(dispatcher, context); | 244 return new ExtensionImpl(dispatcher, context); |
| 243 } | 245 } |
| 244 | 246 |
| 245 // static | 247 // static |
| 246 void MessagingBindings::DispatchOnConnect( | 248 void MessagingBindings::DispatchOnConnect( |
| 247 const ChromeV8ContextSet::ContextSet& contexts, | 249 const ScriptContextSet::ContextSet& contexts, |
| 248 int target_port_id, | 250 int target_port_id, |
| 249 const std::string& channel_name, | 251 const std::string& channel_name, |
| 250 const base::DictionaryValue& source_tab, | 252 const base::DictionaryValue& source_tab, |
| 251 const std::string& source_extension_id, | 253 const std::string& source_extension_id, |
| 252 const std::string& target_extension_id, | 254 const std::string& target_extension_id, |
| 253 const GURL& source_url, | 255 const GURL& source_url, |
| 254 const std::string& tls_channel_id, | 256 const std::string& tls_channel_id, |
| 255 content::RenderView* restrict_to_render_view) { | 257 content::RenderView* restrict_to_render_view) { |
| 256 v8::Isolate* isolate = v8::Isolate::GetCurrent(); | 258 v8::Isolate* isolate = v8::Isolate::GetCurrent(); |
| 257 v8::HandleScope handle_scope(isolate); | 259 v8::HandleScope handle_scope(isolate); |
| 258 | 260 |
| 259 scoped_ptr<V8ValueConverter> converter(V8ValueConverter::create()); | 261 scoped_ptr<V8ValueConverter> converter(V8ValueConverter::create()); |
| 260 | 262 |
| 261 bool port_created = false; | 263 bool port_created = false; |
| 262 std::string source_url_spec = source_url.spec(); | 264 std::string source_url_spec = source_url.spec(); |
| 263 | 265 |
| 264 // TODO(kalman): pass in the full ChromeV8ContextSet; call ForEach. | 266 // TODO(kalman): pass in the full ScriptContextSet; call ForEach. |
| 265 for (ChromeV8ContextSet::ContextSet::const_iterator it = contexts.begin(); | 267 for (ScriptContextSet::ContextSet::const_iterator it = contexts.begin(); |
| 266 it != contexts.end(); ++it) { | 268 it != contexts.end(); |
| 269 ++it) { | |
| 267 if (restrict_to_render_view && | 270 if (restrict_to_render_view && |
| 268 restrict_to_render_view != (*it)->GetRenderView()) { | 271 restrict_to_render_view != (*it)->GetRenderView()) { |
| 269 continue; | 272 continue; |
| 270 } | 273 } |
| 271 | 274 |
| 272 // TODO(kalman): remove when ContextSet::ForEach is available. | 275 // TODO(kalman): remove when ContextSet::ForEach is available. |
| 273 if ((*it)->v8_context().IsEmpty()) | 276 if ((*it)->v8_context().IsEmpty()) |
| 274 continue; | 277 continue; |
| 275 | 278 |
| 276 v8::Handle<v8::Value> tab = v8::Null(isolate); | 279 v8::Handle<v8::Value> tab = v8::Null(isolate); |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 339 // as a disconnect). | 342 // as a disconnect). |
| 340 if (!port_created) { | 343 if (!port_created) { |
| 341 content::RenderThread::Get()->Send( | 344 content::RenderThread::Get()->Send( |
| 342 new ExtensionHostMsg_CloseChannel( | 345 new ExtensionHostMsg_CloseChannel( |
| 343 target_port_id, kReceivingEndDoesntExistError)); | 346 target_port_id, kReceivingEndDoesntExistError)); |
| 344 } | 347 } |
| 345 } | 348 } |
| 346 | 349 |
| 347 // static | 350 // static |
| 348 void MessagingBindings::DeliverMessage( | 351 void MessagingBindings::DeliverMessage( |
| 349 const ChromeV8ContextSet::ContextSet& contexts, | 352 const ScriptContextSet::ContextSet& contexts, |
| 350 int target_port_id, | 353 int target_port_id, |
| 351 const Message& message, | 354 const Message& message, |
| 352 content::RenderView* restrict_to_render_view) { | 355 content::RenderView* restrict_to_render_view) { |
| 353 scoped_ptr<blink::WebScopedUserGesture> web_user_gesture; | 356 scoped_ptr<blink::WebScopedUserGesture> web_user_gesture; |
| 354 scoped_ptr<blink::WebScopedWindowFocusAllowedIndicator> allow_window_focus; | 357 scoped_ptr<blink::WebScopedWindowFocusAllowedIndicator> allow_window_focus; |
| 355 if (message.user_gesture) { | 358 if (message.user_gesture) { |
| 356 web_user_gesture.reset(new blink::WebScopedUserGesture); | 359 web_user_gesture.reset(new blink::WebScopedUserGesture); |
| 357 allow_window_focus.reset(new blink::WebScopedWindowFocusAllowedIndicator); | 360 allow_window_focus.reset(new blink::WebScopedWindowFocusAllowedIndicator); |
| 358 } | 361 } |
| 359 | 362 |
| 360 v8::Isolate* isolate = v8::Isolate::GetCurrent(); | 363 v8::Isolate* isolate = v8::Isolate::GetCurrent(); |
| 361 v8::HandleScope handle_scope(isolate); | 364 v8::HandleScope handle_scope(isolate); |
| 362 | 365 |
| 363 // TODO(kalman): pass in the full ChromeV8ContextSet; call ForEach. | 366 // TODO(kalman): pass in the full ScriptContextSet; call ForEach. |
| 364 for (ChromeV8ContextSet::ContextSet::const_iterator it = contexts.begin(); | 367 for (ScriptContextSet::ContextSet::const_iterator it = contexts.begin(); |
| 365 it != contexts.end(); ++it) { | 368 it != contexts.end(); |
| 369 ++it) { | |
| 366 if (restrict_to_render_view && | 370 if (restrict_to_render_view && |
| 367 restrict_to_render_view != (*it)->GetRenderView()) { | 371 restrict_to_render_view != (*it)->GetRenderView()) { |
| 368 continue; | 372 continue; |
| 369 } | 373 } |
| 370 | 374 |
| 371 // TODO(kalman): remove when ContextSet::ForEach is available. | 375 // TODO(kalman): remove when ContextSet::ForEach is available. |
| 372 if ((*it)->v8_context().IsEmpty()) | 376 if ((*it)->v8_context().IsEmpty()) |
| 373 continue; | 377 continue; |
| 374 | 378 |
| 375 // Check to see whether the context has this port before bothering to create | 379 // Check to see whether the context has this port before bothering to create |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 392 message.data.size())); | 396 message.data.size())); |
| 393 arguments.push_back(port_id_handle); | 397 arguments.push_back(port_id_handle); |
| 394 (*it)->module_system()->CallModuleMethod("messaging", | 398 (*it)->module_system()->CallModuleMethod("messaging", |
| 395 "dispatchOnMessage", | 399 "dispatchOnMessage", |
| 396 &arguments); | 400 &arguments); |
| 397 } | 401 } |
| 398 } | 402 } |
| 399 | 403 |
| 400 // static | 404 // static |
| 401 void MessagingBindings::DispatchOnDisconnect( | 405 void MessagingBindings::DispatchOnDisconnect( |
| 402 const ChromeV8ContextSet::ContextSet& contexts, | 406 const ScriptContextSet::ContextSet& contexts, |
| 403 int port_id, | 407 int port_id, |
| 404 const std::string& error_message, | 408 const std::string& error_message, |
| 405 content::RenderView* restrict_to_render_view) { | 409 content::RenderView* restrict_to_render_view) { |
| 406 v8::Isolate* isolate = v8::Isolate::GetCurrent(); | 410 v8::Isolate* isolate = v8::Isolate::GetCurrent(); |
| 407 v8::HandleScope handle_scope(isolate); | 411 v8::HandleScope handle_scope(isolate); |
| 408 | 412 |
| 409 // TODO(kalman): pass in the full ChromeV8ContextSet; call ForEach. | 413 // TODO(kalman): pass in the full ScriptContextSet; call ForEach. |
| 410 for (ChromeV8ContextSet::ContextSet::const_iterator it = contexts.begin(); | 414 for (ScriptContextSet::ContextSet::const_iterator it = contexts.begin(); |
| 411 it != contexts.end(); ++it) { | 415 it != contexts.end(); |
| 416 ++it) { | |
| 412 if (restrict_to_render_view && | 417 if (restrict_to_render_view && |
| 413 restrict_to_render_view != (*it)->GetRenderView()) { | 418 restrict_to_render_view != (*it)->GetRenderView()) { |
| 414 continue; | 419 continue; |
| 415 } | 420 } |
| 416 | 421 |
| 417 // TODO(kalman): remove when ContextSet::ForEach is available. | 422 // TODO(kalman): remove when ContextSet::ForEach is available. |
| 418 if ((*it)->v8_context().IsEmpty()) | 423 if ((*it)->v8_context().IsEmpty()) |
| 419 continue; | 424 continue; |
| 420 | 425 |
| 421 std::vector<v8::Handle<v8::Value> > arguments; | 426 std::vector<v8::Handle<v8::Value> > arguments; |
| 422 arguments.push_back(v8::Integer::New(isolate, port_id)); | 427 arguments.push_back(v8::Integer::New(isolate, port_id)); |
| 423 if (!error_message.empty()) { | 428 if (!error_message.empty()) { |
| 424 arguments.push_back( | 429 arguments.push_back( |
| 425 v8::String::NewFromUtf8(isolate, error_message.c_str())); | 430 v8::String::NewFromUtf8(isolate, error_message.c_str())); |
| 426 } else { | 431 } else { |
| 427 arguments.push_back(v8::Null(isolate)); | 432 arguments.push_back(v8::Null(isolate)); |
| 428 } | 433 } |
| 429 (*it)->module_system()->CallModuleMethod("messaging", | 434 (*it)->module_system()->CallModuleMethod("messaging", |
| 430 "dispatchOnDisconnect", | 435 "dispatchOnDisconnect", |
| 431 &arguments); | 436 &arguments); |
| 432 } | 437 } |
| 433 } | 438 } |
| 434 | 439 |
| 435 } // namespace extensions | 440 } // namespace extensions |
| OLD | NEW |