Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(66)

Side by Side Diff: extensions/renderer/messaging_bindings.cc

Issue 1413543005: Use FrameTreeNode ID as frameId in extension APIs (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Improve port lifetime management, add tests Created 5 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698