OLD | NEW |
---|---|
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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/event_bindings.h" | 5 #include "chrome/renderer/extensions/event_bindings.h" |
6 | 6 |
7 #include <vector> | 7 #include <vector> |
8 | 8 |
9 #include "base/basictypes.h" | 9 #include "base/basictypes.h" |
10 #include "base/lazy_instance.h" | 10 #include "base/lazy_instance.h" |
(...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
182 WebKit::WebString::fromUTF8(file_full_path.c_str()), | 182 WebKit::WebString::fromUTF8(file_full_path.c_str()), |
183 is_directory); | 183 is_directory); |
184 #else | 184 #else |
185 return v8::Undefined(); | 185 return v8::Undefined(); |
186 #endif | 186 #endif |
187 } | 187 } |
188 }; | 188 }; |
189 | 189 |
190 // Returns true if the extension running in the given |context| has sufficient | 190 // Returns true if the extension running in the given |context| has sufficient |
191 // permissions to access the data. | 191 // permissions to access the data. |
192 static bool HasSufficientPermissions(ContextInfo* context, | 192 static bool HasSufficientPermissions(RenderView* render_view, |
193 const GURL& event_url) { | 193 const GURL& event_url) { |
194 v8::Context::Scope context_scope(context->context); | |
195 | |
196 // During unit tests, we might be invoked without a v8 context. In these | 194 // During unit tests, we might be invoked without a v8 context. In these |
197 // cases, we only allow empty event_urls and short-circuit before retrieving | 195 // cases, we only allow empty event_urls and short-circuit before retrieving |
198 // the render view from the current context. | 196 // the render view from the current context. |
199 if (!event_url.is_valid()) | 197 if (!event_url.is_valid()) |
200 return true; | 198 return true; |
201 | 199 |
202 RenderView* renderview = bindings_utils::GetRenderViewForCurrentContext(); | 200 WebDocument document = render_view->webview()->mainFrame()->document(); |
203 if (!renderview) | |
204 return false; | |
205 | |
206 WebDocument document = renderview->webview()->mainFrame()->document(); | |
207 return GURL(document.url()).SchemeIs(chrome::kExtensionScheme) && | 201 return GURL(document.url()).SchemeIs(chrome::kExtensionScheme) && |
208 document.securityOrigin().canRequest(event_url); | 202 document.securityOrigin().canRequest(event_url); |
209 } | 203 } |
210 | 204 |
211 } // namespace | 205 } // namespace |
212 | 206 |
213 const char* EventBindings::kName = "chrome/EventBindings"; | 207 const char* EventBindings::kName = "chrome/EventBindings"; |
214 const char* EventBindings::kTestingExtensionId = | 208 const char* EventBindings::kTestingExtensionId = |
215 "oooooooooooooooooooooooooooooooo"; | 209 "oooooooooooooooooooooooooooooooo"; |
216 | 210 |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
291 v8::Handle<v8::Context> context, | 285 v8::Handle<v8::Context> context, |
292 ExtensionDispatcher* extension_dispatcher, | 286 ExtensionDispatcher* extension_dispatcher, |
293 int isolated_world_id) { | 287 int isolated_world_id) { |
294 if (!bindings_registered) | 288 if (!bindings_registered) |
295 return; | 289 return; |
296 | 290 |
297 bool content_script = isolated_world_id != 0; | 291 bool content_script = isolated_world_id != 0; |
298 ContextList& contexts = GetContexts(); | 292 ContextList& contexts = GetContexts(); |
299 | 293 |
300 v8::Persistent<v8::Context> persistent_context; | 294 v8::Persistent<v8::Context> persistent_context; |
295 v8::Persistent<v8::Context> main_world_context; | |
301 std::string extension_id; | 296 std::string extension_id; |
302 | 297 |
303 if (content_script) { | 298 if (content_script) { |
304 // Content script contexts can get GCed before their frame goes away, so | 299 // Content script contexts can get GCed before their frame goes away, so |
305 // set up a GC callback. | 300 // set up a GC callback. |
306 persistent_context = v8::Persistent<v8::Context>::New(context); | 301 persistent_context = v8::Persistent<v8::Context>::New(context); |
307 persistent_context.MakeWeak(NULL, &ContextWeakReferenceCallback); | 302 persistent_context.MakeWeak(NULL, &ContextWeakReferenceCallback); |
303 | |
304 main_world_context = v8::Persistent<v8::Context>::New( | |
305 frame->mainWorldScriptContext()); | |
306 main_world_context.MakeWeak(NULL, NULL); | |
307 | |
308 extension_id = | 308 extension_id = |
309 extension_dispatcher->user_script_slave()-> | 309 extension_dispatcher->user_script_slave()-> |
310 GetExtensionIdForIsolatedWorld(isolated_world_id); | 310 GetExtensionIdForIsolatedWorld(isolated_world_id); |
311 } else { | 311 } else { |
312 // Figure out the frame's URL. If the frame is loading, use its provisional | 312 // Figure out the frame's URL. If the frame is loading, use its provisional |
313 // URL, since we get this notification before commit. | 313 // URL, since we get this notification before commit. |
314 WebDataSource* ds = frame->provisionalDataSource(); | 314 WebDataSource* ds = frame->provisionalDataSource(); |
315 if (!ds) | 315 if (!ds) |
316 ds = frame->dataSource(); | 316 ds = frame->dataSource(); |
317 GURL url = ds->request().url(); | 317 GURL url = ds->request().url(); |
(...skipping 11 matching lines...) Expand all Loading... | |
329 | 329 |
330 // For tests, we want the dispatchOnLoad to actually setup our bindings, | 330 // For tests, we want the dispatchOnLoad to actually setup our bindings, |
331 // so we give a fake extension id; | 331 // so we give a fake extension id; |
332 extension_id = kTestingExtensionId; | 332 extension_id = kTestingExtensionId; |
333 } | 333 } |
334 | 334 |
335 persistent_context = v8::Persistent<v8::Context>::New(context); | 335 persistent_context = v8::Persistent<v8::Context>::New(context); |
336 } | 336 } |
337 | 337 |
338 contexts.push_back(linked_ptr<ContextInfo>( | 338 contexts.push_back(linked_ptr<ContextInfo>( |
339 new ContextInfo(persistent_context, extension_id, frame))); | 339 new ContextInfo(persistent_context, main_world_context, extension_id))); |
340 | 340 |
341 // Content scripts get initialized in user_script_slave.cc. | 341 // Content scripts get initialized in user_script_slave.cc. |
342 if (!content_script) { | 342 if (!content_script) { |
343 v8::HandleScope handle_scope; | 343 v8::HandleScope handle_scope; |
344 v8::Handle<v8::Value> argv[1]; | 344 v8::Handle<v8::Value> argv[1]; |
345 argv[0] = v8::String::New(extension_id.c_str()); | 345 argv[0] = v8::String::New(extension_id.c_str()); |
346 CallFunctionInContext(context, "dispatchOnLoad", arraysize(argv), argv); | 346 CallFunctionInContext(context, "dispatchOnLoad", arraysize(argv), argv); |
347 } | 347 } |
348 } | 348 } |
349 | 349 |
350 // static | 350 // static |
351 void EventBindings::HandleContextDestroyed(WebFrame* frame) { | 351 void EventBindings::HandleContextDestroyed(WebFrame* frame) { |
352 if (!bindings_registered) | 352 if (!bindings_registered) |
353 return; | 353 return; |
354 | 354 |
355 v8::HandleScope handle_scope; | 355 v8::HandleScope handle_scope; |
356 v8::Local<v8::Context> context = frame->mainWorldScriptContext(); | 356 v8::Local<v8::Context> context = frame->mainWorldScriptContext(); |
357 if (!context.IsEmpty()) { | 357 |
358 ContextList::iterator context_iter = bindings_utils::FindContext(context); | 358 if (context.IsEmpty()) { |
359 if (context_iter != GetContexts().end()) | 359 NOTREACHED(); |
Aaron Boodman
2011/08/24 02:58:16
According to the code upstream, this should not ha
| |
360 UnregisterContext(context_iter, false); | 360 return; |
361 } | 361 } |
362 | 362 |
363 // Unload any content script contexts for this frame. Note that the frame | 363 ContextList::iterator context_iter = bindings_utils::FindContext(context); |
364 // itself might not be registered, but can still be a parent frame. | 364 if (context_iter != GetContexts().end()) |
365 UnregisterContext(context_iter, false); | |
366 | |
367 // Unload any associated content script contexts. Note that the main world | |
368 // context itself might not be registered, but can still be associated with a | |
369 // content script that is. | |
365 for (ContextList::iterator it = GetContexts().begin(); | 370 for (ContextList::iterator it = GetContexts().begin(); |
366 it != GetContexts().end(); ) { | 371 it != GetContexts().end(); ) { |
367 if ((*it)->frame == frame) { | 372 if ((*it)->main_world_context == context) { |
368 UnregisterContext(it, false); | 373 UnregisterContext(it, false); |
369 // UnregisterContext will remove |it| from the list, but may also | 374 // UnregisterContext will remove |it| from the list, but may also |
370 // modify the rest of the list as a result of calling into javascript. | 375 // modify the rest of the list as a result of calling into javascript. |
371 it = GetContexts().begin(); | 376 it = GetContexts().begin(); |
372 } else { | 377 } else { |
373 ++it; | 378 ++it; |
374 } | 379 } |
375 } | 380 } |
376 } | 381 } |
377 | 382 |
378 // static | 383 // static |
379 void EventBindings::CallFunction(const std::string& extension_id, | 384 void EventBindings::CallFunction(const std::string& extension_id, |
380 const std::string& function_name, | 385 const std::string& function_name, |
381 const ListValue& arguments, | 386 const ListValue& arguments, |
382 RenderView* render_view, | 387 RenderView* render_view, |
383 const GURL& event_url) { | 388 const GURL& event_url) { |
384 v8::HandleScope handle_scope; | 389 v8::HandleScope handle_scope; |
385 | 390 |
386 // We copy the context list, because calling into javascript may modify it | 391 // We copy the context list, because calling into javascript may modify it |
387 // out from under us. We also guard against deleted contexts by checking if | 392 // out from under us. We also guard against deleted contexts by checking if |
388 // they have been cleared first. | 393 // they have been cleared first. |
389 ContextList contexts = GetContexts(); | 394 ContextList contexts = GetContexts(); |
390 | 395 |
391 V8ValueConverter converter; | 396 V8ValueConverter converter; |
392 for (ContextList::iterator it = contexts.begin(); | 397 for (ContextList::iterator it = contexts.begin(); |
393 it != contexts.end(); ++it) { | 398 it != contexts.end(); ++it) { |
394 if (render_view) { | 399 if ((*it)->context.IsEmpty()) |
395 RenderView* context_render_view = | 400 continue; |
396 RenderView::FromWebView((*it)->frame->view()); | |
397 if (render_view != context_render_view) | |
398 continue; | |
399 } | |
400 | 401 |
401 if (!extension_id.empty() && extension_id != (*it)->extension_id) | 402 if (!extension_id.empty() && extension_id != (*it)->extension_id) |
402 continue; | 403 continue; |
403 | 404 |
404 if ((*it)->context.IsEmpty()) | 405 WebFrame* context_frame = WebFrame::frameForContext((*it)->context); |
Aaron Boodman
2011/08/24 02:58:16
It will return NULL if the context is detached fro
| |
406 if (!context_frame || !context_frame->view()) | |
405 continue; | 407 continue; |
406 | 408 |
407 if (!HasSufficientPermissions(it->get(), event_url)) | 409 RenderView* context_render_view = |
410 RenderView::FromWebView(context_frame->view()); | |
411 if (!context_render_view) | |
412 continue; | |
413 | |
414 if (render_view && render_view != context_render_view) | |
415 continue; | |
416 | |
417 if (!HasSufficientPermissions(render_view, event_url)) | |
408 continue; | 418 continue; |
409 | 419 |
410 v8::Local<v8::Context> context(*((*it)->context)); | 420 v8::Local<v8::Context> context(*((*it)->context)); |
411 std::vector<v8::Handle<v8::Value> > v8_arguments; | 421 std::vector<v8::Handle<v8::Value> > v8_arguments; |
412 for (size_t i = 0; i < arguments.GetSize(); ++i) { | 422 for (size_t i = 0; i < arguments.GetSize(); ++i) { |
413 Value* item = NULL; | 423 Value* item = NULL; |
414 CHECK(arguments.Get(i, &item)); | 424 CHECK(arguments.Get(i, &item)); |
415 v8_arguments.push_back(converter.ToV8Value(item, context)); | 425 v8_arguments.push_back(converter.ToV8Value(item, context)); |
416 } | 426 } |
417 | 427 |
418 v8::Handle<v8::Value> retval = CallFunctionInContext( | 428 v8::Handle<v8::Value> retval = CallFunctionInContext( |
419 context, function_name, v8_arguments.size(), &v8_arguments[0]); | 429 context, function_name, v8_arguments.size(), &v8_arguments[0]); |
420 // In debug, the js will validate the event parameters and return a | 430 // In debug, the js will validate the event parameters and return a |
421 // string if a validation error has occured. | 431 // string if a validation error has occured. |
422 // TODO(rafaelw): Consider only doing this check if function_name == | 432 // TODO(rafaelw): Consider only doing this check if function_name == |
423 // "Event.dispatchJSON". | 433 // "Event.dispatchJSON". |
424 #ifndef NDEBUG | 434 #ifndef NDEBUG |
425 if (!retval.IsEmpty() && !retval->IsUndefined()) { | 435 if (!retval.IsEmpty() && !retval->IsUndefined()) { |
426 std::string error = *v8::String::AsciiValue(retval); | 436 std::string error = *v8::String::AsciiValue(retval); |
427 DCHECK(false) << error; | 437 DCHECK(false) << error; |
428 } | 438 } |
429 #endif | 439 #endif |
430 } | 440 } |
431 } | 441 } |
OLD | NEW |