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

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

Issue 145463002: Extensions: Send the tab id to platform apps. (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: fix null pointer deref Created 6 years, 10 months 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 | Annotate | Revision Log
« no previous file with comments | « chrome/renderer/extensions/dispatcher.cc ('k') | chrome/renderer/extensions/request_sender.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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"
(...skipping 29 matching lines...) Expand all
40 // var port = runtime.connect(); 40 // var port = runtime.connect();
41 // port.postMessage('Can you hear me now?'); 41 // port.postMessage('Can you hear me now?');
42 // port.onmessage.addListener(function(msg, port) { 42 // port.onmessage.addListener(function(msg, port) {
43 // alert('response=' + msg); 43 // alert('response=' + msg);
44 // port.postMessage('I got your reponse'); 44 // port.postMessage('I got your reponse');
45 // }); 45 // });
46 46
47 using content::RenderThread; 47 using content::RenderThread;
48 using content::V8ValueConverter; 48 using content::V8ValueConverter;
49 49
50 namespace extensions {
51
50 namespace { 52 namespace {
51 53
52 struct ExtensionData { 54 struct ExtensionData {
53 struct PortData { 55 struct PortData {
54 int ref_count; // how many contexts have a handle to this port 56 int ref_count; // how many contexts have a handle to this port
55 PortData() : ref_count(0) {} 57 PortData() : ref_count(0) {}
56 }; 58 };
57 std::map<int, PortData> ports; // port ID -> data 59 std::map<int, PortData> ports; // port ID -> data
58 }; 60 };
59 61
60 static base::LazyInstance<ExtensionData> g_extension_data = 62 base::LazyInstance<ExtensionData> g_extension_data =
61 LAZY_INSTANCE_INITIALIZER; 63 LAZY_INSTANCE_INITIALIZER;
62 64
63 static bool HasPortData(int port_id) { 65 bool HasPortData(int port_id) {
64 return g_extension_data.Get().ports.find(port_id) != 66 return g_extension_data.Get().ports.find(port_id) !=
65 g_extension_data.Get().ports.end(); 67 g_extension_data.Get().ports.end();
66 } 68 }
67 69
68 static ExtensionData::PortData& GetPortData(int port_id) { 70 ExtensionData::PortData& GetPortData(int port_id) {
69 return g_extension_data.Get().ports[port_id]; 71 return g_extension_data.Get().ports[port_id];
70 } 72 }
71 73
72 static void ClearPortData(int port_id) { 74 void ClearPortData(int port_id) {
73 g_extension_data.Get().ports.erase(port_id); 75 g_extension_data.Get().ports.erase(port_id);
74 } 76 }
75 77
76 const char kPortClosedError[] = "Attempting to use a disconnected port object"; 78 const char kPortClosedError[] = "Attempting to use a disconnected port object";
77 const char kReceivingEndDoesntExistError[] = 79 const char kReceivingEndDoesntExistError[] =
78 "Could not establish connection. Receiving end does not exist."; 80 "Could not establish connection. Receiving end does not exist.";
79 81
80 class ExtensionImpl : public extensions::ChromeV8Extension { 82 class ExtensionImpl : public ChromeV8Extension {
81 public: 83 public:
82 explicit ExtensionImpl(extensions::Dispatcher* dispatcher, 84 ExtensionImpl(Dispatcher* dispatcher, ChromeV8Context* context)
83 extensions::ChromeV8Context* context) 85 : ChromeV8Extension(dispatcher, context) {
84 : extensions::ChromeV8Extension(dispatcher, context) {
85 RouteFunction("CloseChannel", 86 RouteFunction("CloseChannel",
86 base::Bind(&ExtensionImpl::CloseChannel, base::Unretained(this))); 87 base::Bind(&ExtensionImpl::CloseChannel, base::Unretained(this)));
87 RouteFunction("PortAddRef", 88 RouteFunction("PortAddRef",
88 base::Bind(&ExtensionImpl::PortAddRef, base::Unretained(this))); 89 base::Bind(&ExtensionImpl::PortAddRef, base::Unretained(this)));
89 RouteFunction("PortRelease", 90 RouteFunction("PortRelease",
90 base::Bind(&ExtensionImpl::PortRelease, base::Unretained(this))); 91 base::Bind(&ExtensionImpl::PortRelease, base::Unretained(this)));
91 RouteFunction("PostMessage", 92 RouteFunction("PostMessage",
92 base::Bind(&ExtensionImpl::PostMessage, base::Unretained(this))); 93 base::Bind(&ExtensionImpl::PostMessage, base::Unretained(this)));
93 // TODO(fsamuel, kalman): Move BindToGC out of messaging natives. 94 // TODO(fsamuel, kalman): Move BindToGC out of messaging natives.
94 RouteFunction("BindToGC", 95 RouteFunction("BindToGC",
95 base::Bind(&ExtensionImpl::BindToGC, base::Unretained(this))); 96 base::Bind(&ExtensionImpl::BindToGC, base::Unretained(this)));
96 } 97 }
97 98
98 virtual ~ExtensionImpl() {} 99 virtual ~ExtensionImpl() {}
99 100
101 void ClearPortDataAndNotifyDispatcher(int port_id) {
102 ClearPortData(port_id);
103 dispatcher()->ClearPortData(port_id);
104 }
105
100 // Sends a message along the given channel. 106 // Sends a message along the given channel.
101 void PostMessage(const v8::FunctionCallbackInfo<v8::Value>& args) { 107 void PostMessage(const v8::FunctionCallbackInfo<v8::Value>& args) {
102 content::RenderView* renderview = GetRenderView(); 108 content::RenderView* renderview = GetRenderView();
103 if (!renderview) 109 if (!renderview)
104 return; 110 return;
105 111
106 // Arguments are (int32 port_id, string message). 112 // Arguments are (int32 port_id, string message).
107 CHECK(args.Length() == 2 && 113 CHECK(args.Length() == 2 &&
108 args[0]->IsInt32() && 114 args[0]->IsInt32() &&
109 args[1]->IsString()); 115 args[1]->IsString());
110 116
111 int port_id = args[0]->Int32Value(); 117 int port_id = args[0]->Int32Value();
112 if (!HasPortData(port_id)) { 118 if (!HasPortData(port_id)) {
113 args.GetIsolate()->ThrowException(v8::Exception::Error( 119 args.GetIsolate()->ThrowException(v8::Exception::Error(
114 v8::String::NewFromUtf8(args.GetIsolate(), kPortClosedError))); 120 v8::String::NewFromUtf8(args.GetIsolate(), kPortClosedError)));
115 return; 121 return;
116 } 122 }
117 123
118 renderview->Send(new ExtensionHostMsg_PostMessage( 124 renderview->Send(new ExtensionHostMsg_PostMessage(
119 renderview->GetRoutingID(), port_id, 125 renderview->GetRoutingID(), port_id,
120 extensions::Message( 126 Message(*v8::String::Utf8Value(args[1]),
121 *v8::String::Utf8Value(args[1]), 127 blink::WebUserGestureIndicator::isProcessingUserGesture())));
122 blink::WebUserGestureIndicator::isProcessingUserGesture())));
123 } 128 }
124 129
125 // Forcefully disconnects a port. 130 // Forcefully disconnects a port.
126 void CloseChannel(const v8::FunctionCallbackInfo<v8::Value>& args) { 131 void CloseChannel(const v8::FunctionCallbackInfo<v8::Value>& args) {
127 // Arguments are (int32 port_id, boolean notify_browser). 132 // Arguments are (int32 port_id, boolean notify_browser).
128 CHECK_EQ(2, args.Length()); 133 CHECK_EQ(2, args.Length());
129 CHECK(args[0]->IsInt32()); 134 CHECK(args[0]->IsInt32());
130 CHECK(args[1]->IsBoolean()); 135 CHECK(args[1]->IsBoolean());
131 136
132 int port_id = args[0]->Int32Value(); 137 int port_id = args[0]->Int32Value();
133 if (!HasPortData(port_id)) 138 if (!HasPortData(port_id))
134 return; 139 return;
135 140
136 // Send via the RenderThread because the RenderView might be closing. 141 // Send via the RenderThread because the RenderView might be closing.
137 bool notify_browser = args[1]->BooleanValue(); 142 bool notify_browser = args[1]->BooleanValue();
138 if (notify_browser) { 143 if (notify_browser) {
139 content::RenderThread::Get()->Send( 144 content::RenderThread::Get()->Send(
140 new ExtensionHostMsg_CloseChannel(port_id, std::string())); 145 new ExtensionHostMsg_CloseChannel(port_id, std::string()));
141 } 146 }
142 147
143 ClearPortData(port_id); 148 ClearPortDataAndNotifyDispatcher(port_id);
144 } 149 }
145 150
146 // A new port has been created for a context. This occurs both when script 151 // A new port has been created for a context. This occurs both when script
147 // opens a connection, and when a connection is opened to this script. 152 // opens a connection, and when a connection is opened to this script.
148 void PortAddRef(const v8::FunctionCallbackInfo<v8::Value>& args) { 153 void PortAddRef(const v8::FunctionCallbackInfo<v8::Value>& args) {
149 // Arguments are (int32 port_id). 154 // Arguments are (int32 port_id).
150 CHECK_EQ(1, args.Length()); 155 CHECK_EQ(1, args.Length());
151 CHECK(args[0]->IsInt32()); 156 CHECK(args[0]->IsInt32());
152 157
153 int port_id = args[0]->Int32Value(); 158 int port_id = args[0]->Int32Value();
154 ++GetPortData(port_id).ref_count; 159 ++GetPortData(port_id).ref_count;
155 } 160 }
156 161
157 // The frame a port lived in has been destroyed. When there are no more 162 // The frame a port lived in has been destroyed. When there are no more
158 // frames with a reference to a given port, we will disconnect it and notify 163 // frames with a reference to a given port, we will disconnect it and notify
159 // the other end of the channel. 164 // the other end of the channel.
160 void PortRelease(const v8::FunctionCallbackInfo<v8::Value>& args) { 165 void PortRelease(const v8::FunctionCallbackInfo<v8::Value>& args) {
161 // Arguments are (int32 port_id). 166 // Arguments are (int32 port_id).
162 CHECK_EQ(1, args.Length()); 167 CHECK_EQ(1, args.Length());
163 CHECK(args[0]->IsInt32()); 168 CHECK(args[0]->IsInt32());
164 169
165 int port_id = args[0]->Int32Value(); 170 int port_id = args[0]->Int32Value();
166 if (HasPortData(port_id) && --GetPortData(port_id).ref_count == 0) { 171 if (HasPortData(port_id) && --GetPortData(port_id).ref_count == 0) {
167 // Send via the RenderThread because the RenderView might be closing. 172 // Send via the RenderThread because the RenderView might be closing.
168 content::RenderThread::Get()->Send( 173 content::RenderThread::Get()->Send(
169 new ExtensionHostMsg_CloseChannel(port_id, std::string())); 174 new ExtensionHostMsg_CloseChannel(port_id, std::string()));
170 ClearPortData(port_id); 175 ClearPortDataAndNotifyDispatcher(port_id);
171 } 176 }
172 } 177 }
173 178
174 // Holds a |callback| to run sometime after |object| is GC'ed. |callback| will 179 // Holds a |callback| to run sometime after |object| is GC'ed. |callback| will
175 // not be executed re-entrantly to avoid running JS in an unexpected state. 180 // not be executed re-entrantly to avoid running JS in an unexpected state.
176 class GCCallback { 181 class GCCallback {
177 public: 182 public:
178 static void Bind(v8::Handle<v8::Object> object, 183 static void Bind(v8::Handle<v8::Object> object,
179 v8::Handle<v8::Function> callback, 184 v8::Handle<v8::Function> callback,
180 v8::Isolate* isolate) { 185 v8::Isolate* isolate) {
(...skipping 22 matching lines...) Expand all
203 v8::HandleScope handle_scope(isolate_); 208 v8::HandleScope handle_scope(isolate_);
204 v8::Handle<v8::Function> callback = callback_.NewHandle(isolate_); 209 v8::Handle<v8::Function> callback = callback_.NewHandle(isolate_);
205 v8::Handle<v8::Context> context = callback->CreationContext(); 210 v8::Handle<v8::Context> context = callback->CreationContext();
206 if (context.IsEmpty()) 211 if (context.IsEmpty())
207 return; 212 return;
208 v8::Context::Scope context_scope(context); 213 v8::Context::Scope context_scope(context);
209 blink::WebScopedMicrotaskSuppression suppression; 214 blink::WebScopedMicrotaskSuppression suppression;
210 callback->Call(context->Global(), 0, NULL); 215 callback->Call(context->Global(), 0, NULL);
211 } 216 }
212 217
213 extensions::ScopedPersistent<v8::Object> object_; 218 ScopedPersistent<v8::Object> object_;
214 extensions::ScopedPersistent<v8::Function> callback_; 219 ScopedPersistent<v8::Function> callback_;
215 v8::Isolate* isolate_; 220 v8::Isolate* isolate_;
216 221
217 DISALLOW_COPY_AND_ASSIGN(GCCallback); 222 DISALLOW_COPY_AND_ASSIGN(GCCallback);
218 }; 223 };
219 224
220 // void BindToGC(object, callback) 225 // void BindToGC(object, callback)
221 // 226 //
222 // Binds |callback| to be invoked *sometime after* |object| is garbage 227 // Binds |callback| to be invoked *sometime after* |object| is garbage
223 // collected. We don't call the method re-entrantly so as to avoid executing 228 // collected. We don't call the method re-entrantly so as to avoid executing
224 // JS in some bizarro undefined mid-GC state. 229 // JS in some bizarro undefined mid-GC state.
225 void BindToGC(const v8::FunctionCallbackInfo<v8::Value>& args) { 230 void BindToGC(const v8::FunctionCallbackInfo<v8::Value>& args) {
226 CHECK(args.Length() == 2 && args[0]->IsObject() && args[1]->IsFunction()); 231 CHECK(args.Length() == 2 && args[0]->IsObject() && args[1]->IsFunction());
227 GCCallback::Bind(args[0].As<v8::Object>(), 232 GCCallback::Bind(args[0].As<v8::Object>(),
228 args[1].As<v8::Function>(), 233 args[1].As<v8::Function>(),
229 args.GetIsolate()); 234 args.GetIsolate());
230 } 235 }
231 }; 236 };
232 237
233 } // namespace 238 } // namespace
234 239
235 namespace extensions {
236
237 ChromeV8Extension* MessagingBindings::Get( 240 ChromeV8Extension* MessagingBindings::Get(
238 Dispatcher* dispatcher, 241 Dispatcher* dispatcher,
239 ChromeV8Context* context) { 242 ChromeV8Context* context) {
240 return new ExtensionImpl(dispatcher, context); 243 return new ExtensionImpl(dispatcher, context);
241 } 244 }
242 245
243 // static 246 // static
244 void MessagingBindings::DispatchOnConnect( 247 void MessagingBindings::DispatchOnConnect(
245 const ChromeV8ContextSet::ContextSet& contexts, 248 const ChromeV8ContextSet::ContextSet& contexts,
246 int target_port_id, 249 int target_port_id,
(...skipping 18 matching lines...) Expand all
265 if (restrict_to_render_view && 268 if (restrict_to_render_view &&
266 restrict_to_render_view != (*it)->GetRenderView()) { 269 restrict_to_render_view != (*it)->GetRenderView()) {
267 continue; 270 continue;
268 } 271 }
269 272
270 // TODO(kalman): remove when ContextSet::ForEach is available. 273 // TODO(kalman): remove when ContextSet::ForEach is available.
271 if ((*it)->v8_context().IsEmpty()) 274 if ((*it)->v8_context().IsEmpty())
272 continue; 275 continue;
273 276
274 v8::Handle<v8::Value> tab = v8::Null(isolate); 277 v8::Handle<v8::Value> tab = v8::Null(isolate);
275 if (!source_tab.empty()) 278 v8::Handle<v8::Value> tls_channel_id_value = v8::Undefined(isolate);
276 tab = converter->ToV8Value(&source_tab, (*it)->v8_context()); 279 const Extension* extension = (*it)->extension();
280 if (extension) {
281 if (!source_tab.empty() && !extension->is_platform_app())
282 tab = converter->ToV8Value(&source_tab, (*it)->v8_context());
277 283
278 v8::Handle<v8::Value> tls_channel_id_value = v8::Undefined(isolate);
279 if ((*it)->extension()) {
280 ExternallyConnectableInfo* externally_connectable = 284 ExternallyConnectableInfo* externally_connectable =
281 ExternallyConnectableInfo::Get((*it)->extension()); 285 ExternallyConnectableInfo::Get(extension);
282 if (externally_connectable && 286 if (externally_connectable &&
283 externally_connectable->accepts_tls_channel_id) { 287 externally_connectable->accepts_tls_channel_id) {
284 tls_channel_id_value = 288 tls_channel_id_value =
285 v8::String::NewFromUtf8(isolate, 289 v8::String::NewFromUtf8(isolate,
286 tls_channel_id.c_str(), 290 tls_channel_id.c_str(),
287 v8::String::kNormalString, 291 v8::String::kNormalString,
288 tls_channel_id.size()); 292 tls_channel_id.size());
289 } 293 }
290 } 294 }
291 295
292 v8::Handle<v8::Value> arguments[] = { 296 v8::Handle<v8::Value> arguments[] = {
297 // portId
293 v8::Integer::New(isolate, target_port_id), 298 v8::Integer::New(isolate, target_port_id),
299 // channelName
294 v8::String::NewFromUtf8(isolate, 300 v8::String::NewFromUtf8(isolate,
295 channel_name.c_str(), 301 channel_name.c_str(),
296 v8::String::kNormalString, 302 v8::String::kNormalString,
297 channel_name.size()), 303 channel_name.size()),
298 tab, v8::String::NewFromUtf8(isolate, 304 // sourceTab
299 source_extension_id.c_str(), 305 tab,
300 v8::String::kNormalString, 306 // sourceExtensionId
301 source_extension_id.size()), 307 v8::String::NewFromUtf8(isolate,
308 source_extension_id.c_str(),
309 v8::String::kNormalString,
310 source_extension_id.size()),
311 // targetExtensionId
302 v8::String::NewFromUtf8(isolate, 312 v8::String::NewFromUtf8(isolate,
303 target_extension_id.c_str(), 313 target_extension_id.c_str(),
304 v8::String::kNormalString, 314 v8::String::kNormalString,
305 target_extension_id.size()), 315 target_extension_id.size()),
316 // sourceUrl
306 v8::String::NewFromUtf8(isolate, 317 v8::String::NewFromUtf8(isolate,
307 source_url_spec.c_str(), 318 source_url_spec.c_str(),
308 v8::String::kNormalString, 319 v8::String::kNormalString,
309 source_url_spec.size()), 320 source_url_spec.size()),
321 // tlsChannelId
310 tls_channel_id_value, 322 tls_channel_id_value,
311 }; 323 };
312 324
313 v8::Handle<v8::Value> retval = (*it)->module_system()->CallModuleMethod( 325 v8::Handle<v8::Value> retval = (*it)->module_system()->CallModuleMethod(
314 "messaging", 326 "messaging",
315 "dispatchOnConnect", 327 "dispatchOnConnect",
316 arraysize(arguments), arguments); 328 arraysize(arguments), arguments);
317 329
318 if (retval.IsEmpty()) { 330 if (retval.IsEmpty()) {
319 LOG(ERROR) << "Empty return value from dispatchOnConnect."; 331 LOG(ERROR) << "Empty return value from dispatchOnConnect.";
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after
415 } else { 427 } else {
416 arguments.push_back(v8::Null(isolate)); 428 arguments.push_back(v8::Null(isolate));
417 } 429 }
418 (*it)->module_system()->CallModuleMethod("messaging", 430 (*it)->module_system()->CallModuleMethod("messaging",
419 "dispatchOnDisconnect", 431 "dispatchOnDisconnect",
420 &arguments); 432 &arguments);
421 } 433 }
422 } 434 }
423 435
424 } // namespace extensions 436 } // namespace extensions
OLDNEW
« no previous file with comments | « chrome/renderer/extensions/dispatcher.cc ('k') | chrome/renderer/extensions/request_sender.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698