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 |