Chromium Code Reviews| 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 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 121 private: | 121 private: |
| 122 // Maps ScriptContexts to the port IDs that have a reference to it. | 122 // Maps ScriptContexts to the port IDs that have a reference to it. |
| 123 std::map<ScriptContext*, std::set<int>> contexts_to_ports_; | 123 std::map<ScriptContext*, std::set<int>> contexts_to_ports_; |
| 124 | 124 |
| 125 DISALLOW_COPY_AND_ASSIGN(PortTracker); | 125 DISALLOW_COPY_AND_ASSIGN(PortTracker); |
| 126 }; | 126 }; |
| 127 | 127 |
| 128 base::LazyInstance<PortTracker> g_port_tracker = LAZY_INSTANCE_INITIALIZER; | 128 base::LazyInstance<PortTracker> g_port_tracker = LAZY_INSTANCE_INITIALIZER; |
| 129 | 129 |
| 130 const char kPortClosedError[] = "Attempting to use a disconnected port object"; | 130 const char kPortClosedError[] = "Attempting to use a disconnected port object"; |
| 131 const char kReceivingEndDoesntExistError[] = | |
| 132 "Could not establish connection. Receiving end does not exist."; | |
| 133 | 131 |
| 134 class ExtensionImpl : public ObjectBackedNativeHandler { | 132 class ExtensionImpl : public ObjectBackedNativeHandler { |
| 135 public: | 133 public: |
| 136 ExtensionImpl(Dispatcher* dispatcher, ScriptContext* context) | 134 ExtensionImpl(Dispatcher* dispatcher, ScriptContext* context) |
| 137 : ObjectBackedNativeHandler(context), | 135 : ObjectBackedNativeHandler(context), |
| 138 dispatcher_(dispatcher), | 136 dispatcher_(dispatcher), |
| 139 weak_ptr_factory_(this) { | 137 weak_ptr_factory_(this) { |
| 140 RouteFunction( | 138 RouteFunction( |
| 141 "CloseChannel", | 139 "CloseChannel", |
| 142 base::Bind(&ExtensionImpl::CloseChannel, base::Unretained(this))); | 140 base::Bind(&ExtensionImpl::CloseChannel, base::Unretained(this))); |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 200 CHECK_EQ(2, args.Length()); | 198 CHECK_EQ(2, args.Length()); |
| 201 CHECK(args[0]->IsInt32()); | 199 CHECK(args[0]->IsInt32()); |
| 202 CHECK(args[1]->IsBoolean()); | 200 CHECK(args[1]->IsBoolean()); |
| 203 | 201 |
| 204 int port_id = args[0].As<v8::Int32>()->Value(); | 202 int port_id = args[0].As<v8::Int32>()->Value(); |
| 205 if (!g_port_tracker.Get().HasPort(port_id)) | 203 if (!g_port_tracker.Get().HasPort(port_id)) |
| 206 return; | 204 return; |
| 207 | 205 |
| 208 // Send via the RenderThread because the RenderFrame might be closing. | 206 // Send via the RenderThread because the RenderFrame might be closing. |
| 209 bool notify_browser = args[1].As<v8::Boolean>()->Value(); | 207 bool notify_browser = args[1].As<v8::Boolean>()->Value(); |
| 210 if (notify_browser) { | 208 content::RenderFrame* renderframe = context()->GetRenderFrame(); |
|
Devlin
2015/10/30 01:49:39
nit: I think render_frame is more common.
robwu
2015/11/02 19:08:34
Indeed, but this file only uses |renderframe| (2x
| |
| 211 content::RenderThread::Get()->Send( | 209 if (notify_browser && renderframe) |
| 212 new ExtensionHostMsg_CloseChannel(port_id, std::string())); | 210 renderframe->Send(new ExtensionHostMsg_CloseMessagePort( |
| 213 } | 211 renderframe->GetRoutingID(), port_id, true)); |
| 214 | 212 |
| 215 ClearPortDataAndNotifyDispatcher(port_id); | 213 ClearPortDataAndNotifyDispatcher(port_id); |
| 216 } | 214 } |
| 217 | 215 |
| 218 // A new port has been created for a context. This occurs both when script | 216 // A new port has been created for a context. This occurs both when script |
| 219 // opens a connection, and when a connection is opened to this script. | 217 // opens a connection, and when a connection is opened to this script. |
| 220 void PortAddRef(const v8::FunctionCallbackInfo<v8::Value>& args) { | 218 void PortAddRef(const v8::FunctionCallbackInfo<v8::Value>& args) { |
| 221 // Arguments are (int32 port_id). | 219 // Arguments are (int32 port_id). |
| 222 CHECK_EQ(1, args.Length()); | 220 CHECK_EQ(1, args.Length()); |
| 223 CHECK(args[0]->IsInt32()); | 221 CHECK(args[0]->IsInt32()); |
| 224 | 222 |
| 225 int port_id = args[0].As<v8::Int32>()->Value(); | 223 int port_id = args[0].As<v8::Int32>()->Value(); |
| 226 g_port_tracker.Get().AddReference(context(), port_id); | 224 g_port_tracker.Get().AddReference(context(), port_id); |
| 227 } | 225 } |
| 228 | 226 |
| 229 // The frame a port lived in has been destroyed. When there are no more | 227 // The frame a port lived in has been destroyed. When there are no more |
| 230 // frames with a reference to a given port, we will disconnect it and notify | 228 // frames with a reference to a given port, we will disconnect it and notify |
| 231 // the other end of the channel. | 229 // the other end of the channel. |
| 232 void PortRelease(const v8::FunctionCallbackInfo<v8::Value>& args) { | 230 void PortRelease(const v8::FunctionCallbackInfo<v8::Value>& args) { |
| 233 // Arguments are (int32 port_id). | 231 // Arguments are (int32 port_id). |
| 234 CHECK(args.Length() == 1 && args[0]->IsInt32()); | 232 CHECK(args.Length() == 1 && args[0]->IsInt32()); |
| 235 ReleasePort(args[0].As<v8::Int32>()->Value()); | 233 ReleasePort(args[0].As<v8::Int32>()->Value()); |
| 236 } | 234 } |
| 237 | 235 |
| 238 // Releases the reference to |port_id| for this context, and clears all port | 236 // Releases the reference to |port_id| for this context, and clears all port |
| 239 // data if there are no more references. | 237 // data if there are no more references. |
| 240 void ReleasePort(int port_id) { | 238 void ReleasePort(int port_id) { |
| 239 content::RenderFrame* renderframe = context()->GetRenderFrame(); | |
| 241 if (g_port_tracker.Get().RemoveReference(context(), port_id) && | 240 if (g_port_tracker.Get().RemoveReference(context(), port_id) && |
| 242 !g_port_tracker.Get().HasPort(port_id)) { | 241 !g_port_tracker.Get().HasPort(port_id) && renderframe) { |
| 243 // Send via the RenderThread because the RenderFrame might be closing. | 242 renderframe->Send(new ExtensionHostMsg_CloseMessagePort( |
| 244 content::RenderThread::Get()->Send( | 243 renderframe->GetRoutingID(), port_id, false)); |
| 245 new ExtensionHostMsg_CloseChannel(port_id, std::string())); | |
| 246 ClearPortDataAndNotifyDispatcher(port_id); | |
| 247 } | 244 } |
| 248 } | 245 } |
| 249 | 246 |
| 250 // void BindToGC(object, callback, port_id) | 247 // void BindToGC(object, callback, port_id) |
| 251 // | 248 // |
| 252 // Binds |callback| to be invoked *sometime after* |object| is garbage | 249 // Binds |callback| to be invoked *sometime after* |object| is garbage |
| 253 // collected. We don't call the method re-entrantly so as to avoid executing | 250 // collected. We don't call the method re-entrantly so as to avoid executing |
| 254 // JS in some bizarro undefined mid-GC state, nor do we then call into the | 251 // JS in some bizarro undefined mid-GC state, nor do we then call into the |
| 255 // script context if it's been invalidated. | 252 // script context if it's been invalidated. |
| 256 // | 253 // |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 277 }; | 274 }; |
| 278 | 275 |
| 279 void DispatchOnConnectToScriptContext( | 276 void DispatchOnConnectToScriptContext( |
| 280 int target_port_id, | 277 int target_port_id, |
| 281 const std::string& channel_name, | 278 const std::string& channel_name, |
| 282 const ExtensionMsg_TabConnectionInfo* source, | 279 const ExtensionMsg_TabConnectionInfo* source, |
| 283 const ExtensionMsg_ExternalConnectionInfo& info, | 280 const ExtensionMsg_ExternalConnectionInfo& info, |
| 284 const std::string& tls_channel_id, | 281 const std::string& tls_channel_id, |
| 285 bool* port_created, | 282 bool* port_created, |
| 286 ScriptContext* script_context) { | 283 ScriptContext* script_context) { |
| 287 // Only dispatch the events if this is the requested target frame (0 = main | |
| 288 // frame; positive = child frame). | |
| 289 content::RenderFrame* renderframe = script_context->GetRenderFrame(); | |
| 290 if (info.target_frame_id == 0 && renderframe->GetWebFrame()->parent() != NULL) | |
| 291 return; | |
| 292 if (info.target_frame_id > 0 && | |
| 293 renderframe->GetRoutingID() != info.target_frame_id) | |
| 294 return; | |
| 295 | |
| 296 // Bandaid fix for crbug.com/520303. | |
| 297 // TODO(rdevlin.cronin): Fix this properly by routing messages to the correct | |
| 298 // RenderFrame from the browser (same with |target_frame_id| in fact). | |
| 299 if (info.target_tab_id != -1 && | |
| 300 info.target_tab_id != ExtensionFrameHelper::Get(renderframe)->tab_id()) { | |
| 301 return; | |
| 302 } | |
| 303 | |
| 304 v8::Isolate* isolate = script_context->isolate(); | 284 v8::Isolate* isolate = script_context->isolate(); |
| 305 v8::HandleScope handle_scope(isolate); | 285 v8::HandleScope handle_scope(isolate); |
| 306 | 286 |
| 307 scoped_ptr<V8ValueConverter> converter(V8ValueConverter::create()); | 287 scoped_ptr<V8ValueConverter> converter(V8ValueConverter::create()); |
| 308 | 288 |
| 309 const std::string& source_url_spec = info.source_url.spec(); | 289 const std::string& source_url_spec = info.source_url.spec(); |
| 310 std::string target_extension_id = script_context->GetExtensionID(); | 290 std::string target_extension_id = script_context->GetExtensionID(); |
| 311 const Extension* extension = script_context->extension(); | 291 const Extension* extension = script_context->extension(); |
| 312 | 292 |
| 313 v8::Local<v8::Value> tab = v8::Null(isolate); | 293 v8::Local<v8::Value> tab = v8::Null(isolate); |
| (...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 463 const ExtensionMsg_TabConnectionInfo& source, | 443 const ExtensionMsg_TabConnectionInfo& source, |
| 464 const ExtensionMsg_ExternalConnectionInfo& info, | 444 const ExtensionMsg_ExternalConnectionInfo& info, |
| 465 const std::string& tls_channel_id, | 445 const std::string& tls_channel_id, |
| 466 content::RenderFrame* restrict_to_render_frame) { | 446 content::RenderFrame* restrict_to_render_frame) { |
| 467 bool port_created = false; | 447 bool port_created = false; |
| 468 context_set.ForEach( | 448 context_set.ForEach( |
| 469 info.target_id, restrict_to_render_frame, | 449 info.target_id, restrict_to_render_frame, |
| 470 base::Bind(&DispatchOnConnectToScriptContext, target_port_id, | 450 base::Bind(&DispatchOnConnectToScriptContext, target_port_id, |
| 471 channel_name, &source, info, tls_channel_id, &port_created)); | 451 channel_name, &source, info, tls_channel_id, &port_created)); |
| 472 | 452 |
| 473 // If we didn't create a port, notify the other end of the channel (treat it | 453 int routing_id = restrict_to_render_frame ? |
| 474 // as a disconnect). | 454 restrict_to_render_frame->GetRoutingID() : MSG_ROUTING_NONE; |
| 475 if (!port_created) { | 455 if (port_created) { |
| 476 content::RenderThread::Get()->Send(new ExtensionHostMsg_CloseChannel( | 456 content::RenderThread::Get()->Send(new ExtensionHostMsg_OpenMessagePort( |
| 477 target_port_id, kReceivingEndDoesntExistError)); | 457 routing_id, target_port_id)); |
| 458 } else { | |
| 459 content::RenderThread::Get()->Send(new ExtensionHostMsg_CloseMessagePort( | |
| 460 routing_id, target_port_id, false)); | |
| 478 } | 461 } |
| 479 } | 462 } |
| 480 | 463 |
| 481 // static | 464 // static |
| 482 void MessagingBindings::DeliverMessage( | 465 void MessagingBindings::DeliverMessage( |
| 483 const ScriptContextSet& context_set, | 466 const ScriptContextSet& context_set, |
| 484 int target_port_id, | 467 int target_port_id, |
| 485 const Message& message, | 468 const Message& message, |
| 486 content::RenderFrame* restrict_to_render_frame) { | 469 content::RenderFrame* restrict_to_render_frame) { |
| 487 context_set.ForEach( | 470 context_set.ForEach( |
| 488 restrict_to_render_frame, | 471 restrict_to_render_frame, |
| 489 base::Bind(&DeliverMessageToScriptContext, message, target_port_id)); | 472 base::Bind(&DeliverMessageToScriptContext, message, target_port_id)); |
| 490 } | 473 } |
| 491 | 474 |
| 492 // static | 475 // static |
| 493 void MessagingBindings::DispatchOnDisconnect( | 476 void MessagingBindings::DispatchOnDisconnect( |
| 494 const ScriptContextSet& context_set, | 477 const ScriptContextSet& context_set, |
| 495 int port_id, | 478 int port_id, |
| 496 const std::string& error_message, | 479 const std::string& error_message, |
| 497 content::RenderFrame* restrict_to_render_frame) { | 480 content::RenderFrame* restrict_to_render_frame) { |
| 498 context_set.ForEach( | 481 context_set.ForEach( |
| 499 restrict_to_render_frame, | 482 restrict_to_render_frame, |
| 500 base::Bind(&DispatchOnDisconnectToScriptContext, port_id, error_message)); | 483 base::Bind(&DispatchOnDisconnectToScriptContext, port_id, error_message)); |
| 501 } | 484 } |
| 502 | 485 |
| 503 } // namespace extensions | 486 } // namespace extensions |
| OLD | NEW |