| 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" |
| 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 "content/public/renderer/render_frame.h" |
| 16 #include "content/public/renderer/render_thread.h" | 17 #include "content/public/renderer/render_thread.h" |
| 17 #include "content/public/renderer/render_view.h" | |
| 18 #include "content/public/renderer/v8_value_converter.h" | 18 #include "content/public/renderer/v8_value_converter.h" |
| 19 #include "extensions/common/api/messaging/message.h" | 19 #include "extensions/common/api/messaging/message.h" |
| 20 #include "extensions/common/extension_messages.h" | 20 #include "extensions/common/extension_messages.h" |
| 21 #include "extensions/common/manifest_handlers/externally_connectable.h" | 21 #include "extensions/common/manifest_handlers/externally_connectable.h" |
| 22 #include "extensions/renderer/dispatcher.h" | 22 #include "extensions/renderer/dispatcher.h" |
| 23 #include "extensions/renderer/event_bindings.h" | 23 #include "extensions/renderer/event_bindings.h" |
| 24 #include "extensions/renderer/object_backed_native_handler.h" | 24 #include "extensions/renderer/object_backed_native_handler.h" |
| 25 #include "extensions/renderer/scoped_persistent.h" | 25 #include "extensions/renderer/scoped_persistent.h" |
| 26 #include "extensions/renderer/script_context.h" | 26 #include "extensions/renderer/script_context.h" |
| 27 #include "extensions/renderer/script_context_set.h" | 27 #include "extensions/renderer/script_context_set.h" |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 99 ~ExtensionImpl() override {} | 99 ~ExtensionImpl() override {} |
| 100 | 100 |
| 101 private: | 101 private: |
| 102 void ClearPortDataAndNotifyDispatcher(int port_id) { | 102 void ClearPortDataAndNotifyDispatcher(int port_id) { |
| 103 ClearPortData(port_id); | 103 ClearPortData(port_id); |
| 104 dispatcher_->ClearPortData(port_id); | 104 dispatcher_->ClearPortData(port_id); |
| 105 } | 105 } |
| 106 | 106 |
| 107 // Sends a message along the given channel. | 107 // Sends a message along the given channel. |
| 108 void PostMessage(const v8::FunctionCallbackInfo<v8::Value>& args) { | 108 void PostMessage(const v8::FunctionCallbackInfo<v8::Value>& args) { |
| 109 content::RenderView* renderview = context()->GetRenderView(); | 109 content::RenderFrame* renderframe = context()->GetRenderFrame(); |
| 110 if (!renderview) | 110 if (!renderframe) |
| 111 return; | 111 return; |
| 112 | 112 |
| 113 // Arguments are (int32 port_id, string message). | 113 // Arguments are (int32 port_id, string message). |
| 114 CHECK(args.Length() == 2 && args[0]->IsInt32() && args[1]->IsString()); | 114 CHECK(args.Length() == 2 && args[0]->IsInt32() && 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)) { |
| 118 args.GetIsolate()->ThrowException(v8::Exception::Error( | 118 args.GetIsolate()->ThrowException(v8::Exception::Error( |
| 119 v8::String::NewFromUtf8(args.GetIsolate(), kPortClosedError))); | 119 v8::String::NewFromUtf8(args.GetIsolate(), kPortClosedError))); |
| 120 return; | 120 return; |
| 121 } | 121 } |
| 122 | 122 |
| 123 renderview->Send(new ExtensionHostMsg_PostMessage( | 123 renderframe->Send(new ExtensionHostMsg_PostMessage( |
| 124 renderview->GetRoutingID(), port_id, | 124 renderframe->GetRoutingID(), port_id, |
| 125 Message(*v8::String::Utf8Value(args[1]), | 125 Message(*v8::String::Utf8Value(args[1]), |
| 126 blink::WebUserGestureIndicator::isProcessingUserGesture()))); | 126 blink::WebUserGestureIndicator::isProcessingUserGesture()))); |
| 127 } | 127 } |
| 128 | 128 |
| 129 // Forcefully disconnects a port. | 129 // Forcefully disconnects a port. |
| 130 void CloseChannel(const v8::FunctionCallbackInfo<v8::Value>& args) { | 130 void CloseChannel(const v8::FunctionCallbackInfo<v8::Value>& args) { |
| 131 // Arguments are (int32 port_id, boolean notify_browser). | 131 // Arguments are (int32 port_id, boolean notify_browser). |
| 132 CHECK_EQ(2, args.Length()); | 132 CHECK_EQ(2, args.Length()); |
| 133 CHECK(args[0]->IsInt32()); | 133 CHECK(args[0]->IsInt32()); |
| 134 CHECK(args[1]->IsBoolean()); | 134 CHECK(args[1]->IsBoolean()); |
| 135 | 135 |
| 136 int port_id = args[0]->Int32Value(); | 136 int port_id = args[0]->Int32Value(); |
| 137 if (!HasPortData(port_id)) | 137 if (!HasPortData(port_id)) |
| 138 return; | 138 return; |
| 139 | 139 |
| 140 // Send via the RenderThread because the RenderView might be closing. | 140 // Send via the RenderThread because the RenderFrame might be closing. |
| 141 bool notify_browser = args[1]->BooleanValue(); | 141 bool notify_browser = args[1]->BooleanValue(); |
| 142 if (notify_browser) { | 142 if (notify_browser) { |
| 143 content::RenderThread::Get()->Send( | 143 content::RenderThread::Get()->Send( |
| 144 new ExtensionHostMsg_CloseChannel(port_id, std::string())); | 144 new ExtensionHostMsg_CloseChannel(port_id, std::string())); |
| 145 } | 145 } |
| 146 | 146 |
| 147 ClearPortDataAndNotifyDispatcher(port_id); | 147 ClearPortDataAndNotifyDispatcher(port_id); |
| 148 } | 148 } |
| 149 | 149 |
| 150 // A new port has been created for a context. This occurs both when script | 150 // A new port has been created for a context. This occurs both when script |
| (...skipping 10 matching lines...) Expand all Loading... |
| 161 // The frame a port lived in has been destroyed. When there are no more | 161 // The frame a port lived in has been destroyed. When there are no more |
| 162 // frames with a reference to a given port, we will disconnect it and notify | 162 // frames with a reference to a given port, we will disconnect it and notify |
| 163 // the other end of the channel. | 163 // the other end of the channel. |
| 164 void PortRelease(const v8::FunctionCallbackInfo<v8::Value>& args) { | 164 void PortRelease(const v8::FunctionCallbackInfo<v8::Value>& args) { |
| 165 // Arguments are (int32 port_id). | 165 // Arguments are (int32 port_id). |
| 166 CHECK_EQ(1, args.Length()); | 166 CHECK_EQ(1, args.Length()); |
| 167 CHECK(args[0]->IsInt32()); | 167 CHECK(args[0]->IsInt32()); |
| 168 | 168 |
| 169 int port_id = args[0]->Int32Value(); | 169 int port_id = args[0]->Int32Value(); |
| 170 if (HasPortData(port_id) && --GetPortData(port_id).ref_count == 0) { | 170 if (HasPortData(port_id) && --GetPortData(port_id).ref_count == 0) { |
| 171 // Send via the RenderThread because the RenderView might be closing. | 171 // Send via the RenderThread because the RenderFrame might be closing. |
| 172 content::RenderThread::Get()->Send( | 172 content::RenderThread::Get()->Send( |
| 173 new ExtensionHostMsg_CloseChannel(port_id, std::string())); | 173 new ExtensionHostMsg_CloseChannel(port_id, std::string())); |
| 174 ClearPortDataAndNotifyDispatcher(port_id); | 174 ClearPortDataAndNotifyDispatcher(port_id); |
| 175 } | 175 } |
| 176 } | 176 } |
| 177 | 177 |
| 178 // Holds a |callback| to run sometime after |object| is GC'ed. |callback| will | 178 // Holds a |callback| to run sometime after |object| is GC'ed. |callback| will |
| 179 // not be executed re-entrantly to avoid running JS in an unexpected state. | 179 // not be executed re-entrantly to avoid running JS in an unexpected state. |
| 180 class GCCallback { | 180 class GCCallback { |
| 181 public: | 181 public: |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 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( | 240 void DispatchOnConnectToScriptContext( |
| 241 int target_port_id, | 241 int target_port_id, |
| 242 const std::string& channel_name, | 242 const std::string& channel_name, |
| 243 const base::DictionaryValue* source_tab, | 243 const ExtensionMsg_TabConnectionInfo* source, |
| 244 const ExtensionMsg_ExternalConnectionInfo& info, | 244 const ExtensionMsg_ExternalConnectionInfo& info, |
| 245 const std::string& tls_channel_id, | 245 const std::string& tls_channel_id, |
| 246 bool* port_created, | 246 bool* port_created, |
| 247 ScriptContext* script_context) { | 247 ScriptContext* script_context) { |
| 248 v8::Isolate* isolate = script_context->isolate(); | 248 v8::Isolate* isolate = script_context->isolate(); |
| 249 v8::HandleScope handle_scope(isolate); | 249 v8::HandleScope handle_scope(isolate); |
| 250 | 250 |
| 251 scoped_ptr<V8ValueConverter> converter(V8ValueConverter::create()); | 251 scoped_ptr<V8ValueConverter> converter(V8ValueConverter::create()); |
| 252 | 252 |
| 253 const std::string& source_url_spec = info.source_url.spec(); | 253 const std::string& source_url_spec = info.source_url.spec(); |
| 254 std::string target_extension_id = script_context->GetExtensionID(); | 254 std::string target_extension_id = script_context->GetExtensionID(); |
| 255 const Extension* extension = script_context->extension(); | 255 const Extension* extension = script_context->extension(); |
| 256 | 256 |
| 257 v8::Handle<v8::Value> tab = v8::Null(isolate); | 257 v8::Handle<v8::Value> tab = v8::Null(isolate); |
| 258 v8::Handle<v8::Value> tls_channel_id_value = v8::Undefined(isolate); | 258 v8::Handle<v8::Value> tls_channel_id_value = v8::Undefined(isolate); |
| 259 | 259 |
| 260 if (extension) { | 260 if (extension) { |
| 261 if (!source_tab->empty() && !extension->is_platform_app()) | 261 if (!source->tab.empty() && !extension->is_platform_app()) |
| 262 tab = converter->ToV8Value(source_tab, script_context->v8_context()); | 262 tab = converter->ToV8Value(&source->tab, script_context->v8_context()); |
| 263 | 263 |
| 264 ExternallyConnectableInfo* externally_connectable = | 264 ExternallyConnectableInfo* externally_connectable = |
| 265 ExternallyConnectableInfo::Get(extension); | 265 ExternallyConnectableInfo::Get(extension); |
| 266 if (externally_connectable && | 266 if (externally_connectable && |
| 267 externally_connectable->accepts_tls_channel_id) { | 267 externally_connectable->accepts_tls_channel_id) { |
| 268 tls_channel_id_value = v8::String::NewFromUtf8(isolate, | 268 tls_channel_id_value = v8::String::NewFromUtf8(isolate, |
| 269 tls_channel_id.c_str(), | 269 tls_channel_id.c_str(), |
| 270 v8::String::kNormalString, | 270 v8::String::kNormalString, |
| 271 tls_channel_id.size()); | 271 tls_channel_id.size()); |
| 272 } | 272 } |
| 273 } | 273 } |
| 274 | 274 |
| 275 v8::Handle<v8::Value> arguments[] = { | 275 v8::Handle<v8::Value> arguments[] = { |
| 276 // portId | 276 // portId |
| 277 v8::Integer::New(isolate, target_port_id), | 277 v8::Integer::New(isolate, target_port_id), |
| 278 // channelName | 278 // channelName |
| 279 v8::String::NewFromUtf8(isolate, | 279 v8::String::NewFromUtf8(isolate, |
| 280 channel_name.c_str(), | 280 channel_name.c_str(), |
| 281 v8::String::kNormalString, | 281 v8::String::kNormalString, |
| 282 channel_name.size()), | 282 channel_name.size()), |
| 283 // sourceTab | 283 // sourceTab |
| 284 tab, | 284 tab, |
| 285 // source_frame_id |
| 286 v8::Integer::New(isolate, source->frame_id), |
| 285 // sourceExtensionId | 287 // sourceExtensionId |
| 286 v8::String::NewFromUtf8(isolate, | 288 v8::String::NewFromUtf8(isolate, |
| 287 info.source_id.c_str(), | 289 info.source_id.c_str(), |
| 288 v8::String::kNormalString, | 290 v8::String::kNormalString, |
| 289 info.source_id.size()), | 291 info.source_id.size()), |
| 290 // targetExtensionId | 292 // targetExtensionId |
| 291 v8::String::NewFromUtf8(isolate, | 293 v8::String::NewFromUtf8(isolate, |
| 292 target_extension_id.c_str(), | 294 target_extension_id.c_str(), |
| 293 v8::String::kNormalString, | 295 v8::String::kNormalString, |
| 294 target_extension_id.size()), | 296 target_extension_id.size()), |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 365 ObjectBackedNativeHandler* MessagingBindings::Get(Dispatcher* dispatcher, | 367 ObjectBackedNativeHandler* MessagingBindings::Get(Dispatcher* dispatcher, |
| 366 ScriptContext* context) { | 368 ScriptContext* context) { |
| 367 return new ExtensionImpl(dispatcher, context); | 369 return new ExtensionImpl(dispatcher, context); |
| 368 } | 370 } |
| 369 | 371 |
| 370 // static | 372 // static |
| 371 void MessagingBindings::DispatchOnConnect( | 373 void MessagingBindings::DispatchOnConnect( |
| 372 const ScriptContextSet& context_set, | 374 const ScriptContextSet& context_set, |
| 373 int target_port_id, | 375 int target_port_id, |
| 374 const std::string& channel_name, | 376 const std::string& channel_name, |
| 375 const base::DictionaryValue& source_tab, | 377 const ExtensionMsg_TabConnectionInfo& source, |
| 376 const ExtensionMsg_ExternalConnectionInfo& info, | 378 const ExtensionMsg_ExternalConnectionInfo& info, |
| 377 const std::string& tls_channel_id, | 379 const std::string& tls_channel_id, |
| 378 content::RenderView* restrict_to_render_view) { | 380 content::RenderFrame* restrict_to_render_frame) { |
| 381 // TODO(robwu): ScriptContextSet.ForEach should accept RenderFrame*. |
| 382 content::RenderView* restrict_to_render_view = |
| 383 restrict_to_render_frame ? restrict_to_render_frame->GetRenderView() |
| 384 : NULL; |
| 379 bool port_created = false; | 385 bool port_created = false; |
| 380 context_set.ForEach(info.target_id, | 386 context_set.ForEach( |
| 381 restrict_to_render_view, | 387 info.target_id, restrict_to_render_view, |
| 382 base::Bind(&DispatchOnConnectToScriptContext, | 388 base::Bind(&DispatchOnConnectToScriptContext, target_port_id, |
| 383 target_port_id, | 389 channel_name, &source, info, tls_channel_id, &port_created)); |
| 384 channel_name, | |
| 385 &source_tab, | |
| 386 info, | |
| 387 tls_channel_id, | |
| 388 &port_created)); | |
| 389 | 390 |
| 390 // If we didn't create a port, notify the other end of the channel (treat it | 391 // If we didn't create a port, notify the other end of the channel (treat it |
| 391 // as a disconnect). | 392 // as a disconnect). |
| 392 if (!port_created) { | 393 if (!port_created) { |
| 393 content::RenderThread::Get()->Send(new ExtensionHostMsg_CloseChannel( | 394 content::RenderThread::Get()->Send(new ExtensionHostMsg_CloseChannel( |
| 394 target_port_id, kReceivingEndDoesntExistError)); | 395 target_port_id, kReceivingEndDoesntExistError)); |
| 395 } | 396 } |
| 396 } | 397 } |
| 397 | 398 |
| 398 // static | 399 // static |
| 399 void MessagingBindings::DeliverMessage( | 400 void MessagingBindings::DeliverMessage( |
| 400 const ScriptContextSet& context_set, | 401 const ScriptContextSet& context_set, |
| 401 int target_port_id, | 402 int target_port_id, |
| 402 const Message& message, | 403 const Message& message, |
| 403 content::RenderView* restrict_to_render_view) { | 404 content::RenderFrame* restrict_to_render_frame) { |
| 404 scoped_ptr<blink::WebScopedUserGesture> web_user_gesture; | 405 scoped_ptr<blink::WebScopedUserGesture> web_user_gesture; |
| 405 scoped_ptr<blink::WebScopedWindowFocusAllowedIndicator> allow_window_focus; | 406 scoped_ptr<blink::WebScopedWindowFocusAllowedIndicator> allow_window_focus; |
| 406 if (message.user_gesture) { | 407 if (message.user_gesture) { |
| 407 web_user_gesture.reset(new blink::WebScopedUserGesture); | 408 web_user_gesture.reset(new blink::WebScopedUserGesture); |
| 408 allow_window_focus.reset(new blink::WebScopedWindowFocusAllowedIndicator); | 409 allow_window_focus.reset(new blink::WebScopedWindowFocusAllowedIndicator); |
| 409 } | 410 } |
| 410 | 411 |
| 412 // TODO(robwu): ScriptContextSet.ForEach should accept RenderFrame*. |
| 413 content::RenderView* restrict_to_render_view = |
| 414 restrict_to_render_frame ? restrict_to_render_frame->GetRenderView() |
| 415 : NULL; |
| 411 context_set.ForEach( | 416 context_set.ForEach( |
| 412 restrict_to_render_view, | 417 restrict_to_render_view, |
| 413 base::Bind(&DeliverMessageToScriptContext, message.data, target_port_id)); | 418 base::Bind(&DeliverMessageToScriptContext, message.data, target_port_id)); |
| 414 } | 419 } |
| 415 | 420 |
| 416 // static | 421 // static |
| 417 void MessagingBindings::DispatchOnDisconnect( | 422 void MessagingBindings::DispatchOnDisconnect( |
| 418 const ScriptContextSet& context_set, | 423 const ScriptContextSet& context_set, |
| 419 int port_id, | 424 int port_id, |
| 420 const std::string& error_message, | 425 const std::string& error_message, |
| 421 content::RenderView* restrict_to_render_view) { | 426 content::RenderFrame* restrict_to_render_frame) { |
| 427 // TODO(robwu): ScriptContextSet.ForEach should accept RenderFrame*. |
| 428 content::RenderView* restrict_to_render_view = |
| 429 restrict_to_render_frame ? restrict_to_render_frame->GetRenderView() |
| 430 : NULL; |
| 422 context_set.ForEach( | 431 context_set.ForEach( |
| 423 restrict_to_render_view, | 432 restrict_to_render_view, |
| 424 base::Bind(&DispatchOnDisconnectToScriptContext, port_id, error_message)); | 433 base::Bind(&DispatchOnDisconnectToScriptContext, port_id, error_message)); |
| 425 } | 434 } |
| 426 | 435 |
| 427 } // namespace extensions | 436 } // namespace extensions |
| OLD | NEW |