dispatcher.cc revision 010d83a9304c5a91596085d917d248abff47903a
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 3// found in the LICENSE file. 4 5#include "extensions/renderer/dispatcher.h" 6 7#include "base/callback.h" 8#include "base/command_line.h" 9#include "base/debug/alias.h" 10#include "base/memory/scoped_ptr.h" 11#include "base/metrics/user_metrics_action.h" 12#include "base/strings/string_piece.h" 13#include "base/strings/string_split.h" 14#include "base/strings/string_util.h" 15#include "base/values.h" 16#include "content/public/common/content_switches.h" 17#include "content/public/common/url_constants.h" 18#include "content/public/renderer/render_thread.h" 19#include "content/public/renderer/render_view.h" 20#include "content/public/renderer/v8_value_converter.h" 21#include "extensions/common/api/messaging/message.h" 22#include "extensions/common/constants.h" 23#include "extensions/common/extension.h" 24#include "extensions/common/extension_api.h" 25#include "extensions/common/extension_messages.h" 26#include "extensions/common/extension_urls.h" 27#include "extensions/common/features/feature.h" 28#include "extensions/common/features/feature_provider.h" 29#include "extensions/common/manifest.h" 30#include "extensions/common/manifest_constants.h" 31#include "extensions/common/manifest_handlers/background_info.h" 32#include "extensions/common/manifest_handlers/externally_connectable.h" 33#include "extensions/common/manifest_handlers/sandboxed_page_info.h" 34#include "extensions/common/message_bundle.h" 35#include "extensions/common/permissions/permission_set.h" 36#include "extensions/common/permissions/permissions_data.h" 37#include "extensions/common/switches.h" 38#include "extensions/common/view_type.h" 39#include "extensions/renderer/api_activity_logger.h" 40#include "extensions/renderer/api_definitions_natives.h" 41#include "extensions/renderer/app_runtime_custom_bindings.h" 42#include "extensions/renderer/binding_generating_native_handler.h" 43#include "extensions/renderer/blob_native_handler.h" 44#include "extensions/renderer/content_watcher.h" 45#include "extensions/renderer/context_menus_custom_bindings.h" 46#include "extensions/renderer/css_native_handler.h" 47#include "extensions/renderer/dispatcher_delegate.h" 48#include "extensions/renderer/document_custom_bindings.h" 49#include "extensions/renderer/dom_activity_logger.h" 50#include "extensions/renderer/event_bindings.h" 51#include "extensions/renderer/extension_groups.h" 52#include "extensions/renderer/extension_helper.h" 53#include "extensions/renderer/extensions_renderer_client.h" 54#include "extensions/renderer/file_system_natives.h" 55#include "extensions/renderer/i18n_custom_bindings.h" 56#include "extensions/renderer/id_generator_custom_bindings.h" 57#include "extensions/renderer/lazy_background_page_native_handler.h" 58#include "extensions/renderer/logging_native_handler.h" 59#include "extensions/renderer/messaging_bindings.h" 60#include "extensions/renderer/module_system.h" 61#include "extensions/renderer/print_native_handler.h" 62#include "extensions/renderer/process_info_native_handler.h" 63#include "extensions/renderer/render_view_observer_natives.h" 64#include "extensions/renderer/request_sender.h" 65#include "extensions/renderer/runtime_custom_bindings.h" 66#include "extensions/renderer/safe_builtins.h" 67#include "extensions/renderer/script_context.h" 68#include "extensions/renderer/script_context_set.h" 69#include "extensions/renderer/send_request_natives.h" 70#include "extensions/renderer/set_icon_natives.h" 71#include "extensions/renderer/test_features_native_handler.h" 72#include "extensions/renderer/user_gestures_native_handler.h" 73#include "extensions/renderer/user_script_slave.h" 74#include "extensions/renderer/utils_native_handler.h" 75#include "extensions/renderer/v8_context_native_handler.h" 76#include "grit/common_resources.h" 77#include "grit/renderer_resources.h" 78#include "third_party/WebKit/public/platform/WebString.h" 79#include "third_party/WebKit/public/platform/WebURLRequest.h" 80#include "third_party/WebKit/public/web/WebCustomElement.h" 81#include "third_party/WebKit/public/web/WebDataSource.h" 82#include "third_party/WebKit/public/web/WebDocument.h" 83#include "third_party/WebKit/public/web/WebFrame.h" 84#include "third_party/WebKit/public/web/WebRuntimeFeatures.h" 85#include "third_party/WebKit/public/web/WebScopedUserGesture.h" 86#include "third_party/WebKit/public/web/WebSecurityPolicy.h" 87#include "third_party/WebKit/public/web/WebView.h" 88#include "ui/base/layout.h" 89#include "ui/base/resource/resource_bundle.h" 90#include "v8/include/v8.h" 91 92using base::UserMetricsAction; 93using blink::WebDataSource; 94using blink::WebDocument; 95using blink::WebFrame; 96using blink::WebScopedUserGesture; 97using blink::WebSecurityPolicy; 98using blink::WebString; 99using blink::WebVector; 100using blink::WebView; 101using content::RenderThread; 102using content::RenderView; 103 104namespace extensions { 105 106namespace { 107 108static const int64 kInitialExtensionIdleHandlerDelayMs = 5 * 1000; 109static const int64 kMaxExtensionIdleHandlerDelayMs = 5 * 60 * 1000; 110static const char kEventDispatchFunction[] = "dispatchEvent"; 111static const char kOnSuspendEvent[] = "runtime.onSuspend"; 112static const char kOnSuspendCanceledEvent[] = "runtime.onSuspendCanceled"; 113 114// Returns the global value for "chrome" from |context|. If one doesn't exist 115// creates a new object for it. 116// 117// Note that this isn't necessarily an object, since webpages can write, for 118// example, "window.chrome = true". 119v8::Handle<v8::Value> GetOrCreateChrome(ScriptContext* context) { 120 v8::Handle<v8::String> chrome_string( 121 v8::String::NewFromUtf8(context->isolate(), "chrome")); 122 v8::Handle<v8::Object> global(context->v8_context()->Global()); 123 v8::Handle<v8::Value> chrome(global->Get(chrome_string)); 124 if (chrome->IsUndefined()) { 125 chrome = v8::Object::New(context->isolate()); 126 global->Set(chrome_string, chrome); 127 } 128 return chrome; 129} 130 131// Returns |value| cast to an object if possible, else an empty handle. 132v8::Handle<v8::Object> AsObjectOrEmpty(v8::Handle<v8::Value> value) { 133 return value->IsObject() ? value.As<v8::Object>() : v8::Handle<v8::Object>(); 134} 135 136// Calls a method |method_name| in a module |module_name| belonging to the 137// module system from |context|. Intended as a callback target from 138// ScriptContextSet::ForEach. 139void CallModuleMethod(const std::string& module_name, 140 const std::string& method_name, 141 const base::ListValue* args, 142 ScriptContext* context) { 143 v8::HandleScope handle_scope(context->isolate()); 144 v8::Context::Scope context_scope(context->v8_context()); 145 146 scoped_ptr<content::V8ValueConverter> converter( 147 content::V8ValueConverter::create()); 148 149 std::vector<v8::Handle<v8::Value> > arguments; 150 for (base::ListValue::const_iterator it = args->begin(); it != args->end(); 151 ++it) { 152 arguments.push_back(converter->ToV8Value(*it, context->v8_context())); 153 } 154 155 context->module_system()->CallModuleMethod( 156 module_name, method_name, &arguments); 157} 158 159// This handles the "chrome." root API object in script contexts. 160class ChromeNativeHandler : public ObjectBackedNativeHandler { 161 public: 162 explicit ChromeNativeHandler(ScriptContext* context) 163 : ObjectBackedNativeHandler(context) { 164 RouteFunction( 165 "GetChrome", 166 base::Bind(&ChromeNativeHandler::GetChrome, base::Unretained(this))); 167 } 168 169 void GetChrome(const v8::FunctionCallbackInfo<v8::Value>& args) { 170 args.GetReturnValue().Set(GetOrCreateChrome(context())); 171 } 172}; 173 174} // namespace 175 176Dispatcher::Dispatcher(DispatcherDelegate* delegate) 177 : delegate_(delegate), 178 content_watcher_(new ContentWatcher()), 179 source_map_(&ResourceBundle::GetSharedInstance()), 180 v8_schema_registry_(new V8SchemaRegistry), 181 is_webkit_initialized_(false) { 182 const CommandLine& command_line = *(CommandLine::ForCurrentProcess()); 183 is_extension_process_ = 184 command_line.HasSwitch(extensions::switches::kExtensionProcess) || 185 command_line.HasSwitch(::switches::kSingleProcess); 186 187 if (is_extension_process_) { 188 RenderThread::Get()->SetIdleNotificationDelayInMs( 189 kInitialExtensionIdleHandlerDelayMs); 190 } 191 192 RenderThread::Get()->RegisterExtension(SafeBuiltins::CreateV8Extension()); 193 194 user_script_slave_.reset(new UserScriptSlave(&extensions_)); 195 request_sender_.reset(new RequestSender(this)); 196 PopulateSourceMap(); 197} 198 199Dispatcher::~Dispatcher() { 200} 201 202bool Dispatcher::IsExtensionActive(const std::string& extension_id) const { 203 bool is_active = 204 active_extension_ids_.find(extension_id) != active_extension_ids_.end(); 205 if (is_active) 206 CHECK(extensions_.Contains(extension_id)); 207 return is_active; 208} 209 210std::string Dispatcher::GetExtensionID(const WebFrame* frame, int world_id) { 211 if (world_id != 0) { 212 // Isolated worlds (content script). 213 return user_script_slave_->GetExtensionIdForIsolatedWorld(world_id); 214 } 215 216 // TODO(kalman): Delete this check. 217 if (frame->document().securityOrigin().isUnique()) 218 return std::string(); 219 220 // Extension pages (chrome-extension:// URLs). 221 GURL frame_url = ScriptContext::GetDataSourceURLForFrame(frame); 222 return extensions_.GetExtensionOrAppIDByURL(frame_url); 223} 224 225void Dispatcher::DidCreateScriptContext( 226 WebFrame* frame, 227 const v8::Handle<v8::Context>& v8_context, 228 int extension_group, 229 int world_id) { 230#if !defined(ENABLE_EXTENSIONS) 231 return; 232#endif 233 234 std::string extension_id = GetExtensionID(frame, world_id); 235 236 const Extension* extension = extensions_.GetByID(extension_id); 237 if (!extension && !extension_id.empty()) { 238 // There are conditions where despite a context being associated with an 239 // extension, no extension actually gets found. Ignore "invalid" because 240 // CSP blocks extension page loading by switching the extension ID to 241 // "invalid". This isn't interesting. 242 if (extension_id != "invalid") { 243 LOG(ERROR) << "Extension \"" << extension_id << "\" not found"; 244 RenderThread::Get()->RecordAction( 245 UserMetricsAction("ExtensionNotFound_ED")); 246 } 247 248 extension_id = ""; 249 } 250 251 Feature::Context context_type = 252 ClassifyJavaScriptContext(extension, 253 extension_group, 254 ScriptContext::GetDataSourceURLForFrame(frame), 255 frame->document().securityOrigin()); 256 257 ScriptContext* context = 258 delegate_->CreateScriptContext(v8_context, frame, extension, context_type) 259 .release(); 260 script_context_set_.Add(context); 261 262 if (extension) { 263 InitOriginPermissions(extension, context_type); 264 } 265 266 { 267 scoped_ptr<ModuleSystem> module_system( 268 new ModuleSystem(context, &source_map_)); 269 context->set_module_system(module_system.Pass()); 270 } 271 ModuleSystem* module_system = context->module_system(); 272 273 // Enable natives in startup. 274 ModuleSystem::NativesEnabledScope natives_enabled_scope(module_system); 275 276 RegisterNativeHandlers(module_system, context); 277 278 // chrome.Event is part of the public API (although undocumented). Make it 279 // lazily evalulate to Event from event_bindings.js. For extensions only 280 // though, not all webpages! 281 if (context->extension()) { 282 v8::Handle<v8::Object> chrome = AsObjectOrEmpty(GetOrCreateChrome(context)); 283 if (!chrome.IsEmpty()) 284 module_system->SetLazyField(chrome, "Event", kEventBindings, "Event"); 285 } 286 287 UpdateBindingsForContext(context); 288 289 bool is_within_platform_app = IsWithinPlatformApp(); 290 // Inject custom JS into the platform app context. 291 if (is_within_platform_app) { 292 module_system->Require("platformApp"); 293 } 294 295 delegate_->RequireAdditionalModules( 296 module_system, extension, context_type, is_within_platform_app); 297 298 VLOG(1) << "Num tracked contexts: " << script_context_set_.size(); 299} 300 301void Dispatcher::WillReleaseScriptContext( 302 WebFrame* frame, 303 const v8::Handle<v8::Context>& v8_context, 304 int world_id) { 305 ScriptContext* context = script_context_set_.GetByV8Context(v8_context); 306 if (!context) 307 return; 308 309 context->DispatchOnUnloadEvent(); 310 // TODO(kalman): add an invalidation observer interface to ScriptContext. 311 request_sender_->InvalidateSource(context); 312 313 script_context_set_.Remove(context); 314 VLOG(1) << "Num tracked contexts: " << script_context_set_.size(); 315} 316 317void Dispatcher::DidCreateDocumentElement(blink::WebFrame* frame) { 318 if (IsWithinPlatformApp()) { 319 // WebKit doesn't let us define an additional user agent stylesheet, so we 320 // insert the default platform app stylesheet into all documents that are 321 // loaded in each app. 322 std::string stylesheet = ResourceBundle::GetSharedInstance() 323 .GetRawDataResource(IDR_PLATFORM_APP_CSS) 324 .as_string(); 325 ReplaceFirstSubstringAfterOffset( 326 &stylesheet, 0, "$FONTFAMILY", system_font_family_); 327 ReplaceFirstSubstringAfterOffset( 328 &stylesheet, 0, "$FONTSIZE", system_font_size_); 329 frame->document().insertStyleSheet(WebString::fromUTF8(stylesheet)); 330 } 331 332 content_watcher_->DidCreateDocumentElement(frame); 333} 334 335void Dispatcher::DidMatchCSS( 336 blink::WebFrame* frame, 337 const blink::WebVector<blink::WebString>& newly_matching_selectors, 338 const blink::WebVector<blink::WebString>& stopped_matching_selectors) { 339 content_watcher_->DidMatchCSS( 340 frame, newly_matching_selectors, stopped_matching_selectors); 341} 342 343void Dispatcher::OnExtensionResponse(int request_id, 344 bool success, 345 const base::ListValue& response, 346 const std::string& error) { 347 request_sender_->HandleResponse(request_id, success, response, error); 348} 349 350bool Dispatcher::CheckContextAccessToExtensionAPI( 351 const std::string& function_name, 352 ScriptContext* context) const { 353 if (!context) { 354 DLOG(ERROR) << "Not in a v8::Context"; 355 return false; 356 } 357 358 if (!context->extension()) { 359 context->isolate()->ThrowException(v8::Exception::Error( 360 v8::String::NewFromUtf8(context->isolate(), "Not in an extension."))); 361 return false; 362 } 363 364 // Theoretically we could end up with bindings being injected into sandboxed 365 // frames, for example content scripts. Don't let them execute API functions. 366 blink::WebFrame* frame = context->web_frame(); 367 if (IsSandboxedPage(ScriptContext::GetDataSourceURLForFrame(frame))) { 368 static const char kMessage[] = 369 "%s cannot be used within a sandboxed frame."; 370 std::string error_msg = base::StringPrintf(kMessage, function_name.c_str()); 371 context->isolate()->ThrowException(v8::Exception::Error( 372 v8::String::NewFromUtf8(context->isolate(), error_msg.c_str()))); 373 return false; 374 } 375 376 Feature::Availability availability = context->GetAvailability(function_name); 377 if (!availability.is_available()) { 378 context->isolate()->ThrowException( 379 v8::Exception::Error(v8::String::NewFromUtf8( 380 context->isolate(), availability.message().c_str()))); 381 } 382 383 return availability.is_available(); 384} 385 386void Dispatcher::DispatchEvent(const std::string& extension_id, 387 const std::string& event_name) const { 388 base::ListValue args; 389 args.Set(0, new base::StringValue(event_name)); 390 args.Set(1, new base::ListValue()); 391 392 // Needed for Windows compilation, since kEventBindings is declared extern. 393 const char* local_event_bindings = kEventBindings; 394 script_context_set_.ForEach(extension_id, 395 NULL, // all render views 396 base::Bind(&CallModuleMethod, 397 local_event_bindings, 398 kEventDispatchFunction, 399 &args)); 400} 401 402void Dispatcher::InvokeModuleSystemMethod(content::RenderView* render_view, 403 const std::string& extension_id, 404 const std::string& module_name, 405 const std::string& function_name, 406 const base::ListValue& args, 407 bool user_gesture) { 408 scoped_ptr<WebScopedUserGesture> web_user_gesture; 409 if (user_gesture) 410 web_user_gesture.reset(new WebScopedUserGesture); 411 412 script_context_set_.ForEach( 413 extension_id, 414 render_view, 415 base::Bind(&CallModuleMethod, module_name, function_name, &args)); 416 417 // Reset the idle handler each time there's any activity like event or message 418 // dispatch, for which Invoke is the chokepoint. 419 if (is_extension_process_) { 420 RenderThread::Get()->ScheduleIdleHandler( 421 kInitialExtensionIdleHandlerDelayMs); 422 } 423 424 // Tell the browser process when an event has been dispatched with a lazy 425 // background page active. 426 const Extension* extension = extensions_.GetByID(extension_id); 427 if (extension && BackgroundInfo::HasLazyBackgroundPage(extension) && 428 module_name == kEventBindings && 429 function_name == kEventDispatchFunction) { 430 RenderView* background_view = 431 ExtensionHelper::GetBackgroundPage(extension_id); 432 if (background_view) { 433 background_view->Send( 434 new ExtensionHostMsg_EventAck(background_view->GetRoutingID())); 435 } 436 } 437} 438 439void Dispatcher::ClearPortData(int port_id) { 440 // Only the target port side has entries in |port_to_tab_id_map_|. If 441 // |port_id| is a source port, std::map::erase() will just silently fail 442 // here as a no-op. 443 port_to_tab_id_map_.erase(port_id); 444} 445 446bool Dispatcher::OnControlMessageReceived(const IPC::Message& message) { 447 bool handled = true; 448 IPC_BEGIN_MESSAGE_MAP(Dispatcher, message) 449 IPC_MESSAGE_HANDLER(ExtensionMsg_ActivateExtension, OnActivateExtension) 450 IPC_MESSAGE_HANDLER(ExtensionMsg_CancelSuspend, OnCancelSuspend) 451 IPC_MESSAGE_HANDLER(ExtensionMsg_ClearTabSpecificPermissions, 452 OnClearTabSpecificPermissions) 453 IPC_MESSAGE_HANDLER(ExtensionMsg_DeliverMessage, OnDeliverMessage) 454 IPC_MESSAGE_HANDLER(ExtensionMsg_DispatchOnConnect, OnDispatchOnConnect) 455 IPC_MESSAGE_HANDLER(ExtensionMsg_DispatchOnDisconnect, OnDispatchOnDisconnect) 456 IPC_MESSAGE_HANDLER(ExtensionMsg_Loaded, OnLoaded) 457 IPC_MESSAGE_HANDLER(ExtensionMsg_MessageInvoke, OnMessageInvoke) 458 IPC_MESSAGE_HANDLER(ExtensionMsg_SetChannel, OnSetChannel) 459 IPC_MESSAGE_HANDLER(ExtensionMsg_SetFunctionNames, OnSetFunctionNames) 460 IPC_MESSAGE_HANDLER(ExtensionMsg_SetScriptingWhitelist, 461 OnSetScriptingWhitelist) 462 IPC_MESSAGE_HANDLER(ExtensionMsg_SetSystemFont, OnSetSystemFont) 463 IPC_MESSAGE_HANDLER(ExtensionMsg_ShouldSuspend, OnShouldSuspend) 464 IPC_MESSAGE_HANDLER(ExtensionMsg_Suspend, OnSuspend) 465 IPC_MESSAGE_HANDLER(ExtensionMsg_Unloaded, OnUnloaded) 466 IPC_MESSAGE_HANDLER(ExtensionMsg_UpdatePermissions, OnUpdatePermissions) 467 IPC_MESSAGE_HANDLER(ExtensionMsg_UpdateTabSpecificPermissions, 468 OnUpdateTabSpecificPermissions) 469 IPC_MESSAGE_HANDLER(ExtensionMsg_UpdateUserScripts, OnUpdateUserScripts) 470 IPC_MESSAGE_HANDLER(ExtensionMsg_UsingWebRequestAPI, OnUsingWebRequestAPI) 471 IPC_MESSAGE_FORWARD(ExtensionMsg_WatchPages, 472 content_watcher_.get(), 473 ContentWatcher::OnWatchPages) 474 IPC_MESSAGE_UNHANDLED(handled = false) 475 IPC_END_MESSAGE_MAP() 476 477 return handled; 478} 479 480void Dispatcher::WebKitInitialized() { 481 // For extensions, we want to ensure we call the IdleHandler every so often, 482 // even if the extension keeps up activity. 483 if (is_extension_process_) { 484 forced_idle_timer_.reset(new base::RepeatingTimer<content::RenderThread>); 485 forced_idle_timer_->Start( 486 FROM_HERE, 487 base::TimeDelta::FromMilliseconds(kMaxExtensionIdleHandlerDelayMs), 488 RenderThread::Get(), 489 &RenderThread::IdleHandler); 490 } 491 492 // Initialize host permissions for any extensions that were activated before 493 // WebKit was initialized. 494 for (std::set<std::string>::iterator iter = active_extension_ids_.begin(); 495 iter != active_extension_ids_.end(); 496 ++iter) { 497 const Extension* extension = extensions_.GetByID(*iter); 498 CHECK(extension); 499 } 500 501 EnableCustomElementWhiteList(); 502 503 is_webkit_initialized_ = true; 504} 505 506void Dispatcher::IdleNotification() { 507 if (is_extension_process_) { 508 // Dampen the forced delay as well if the extension stays idle for long 509 // periods of time. 510 int64 forced_delay_ms = 511 std::max(RenderThread::Get()->GetIdleNotificationDelayInMs(), 512 kMaxExtensionIdleHandlerDelayMs); 513 forced_idle_timer_->Stop(); 514 forced_idle_timer_->Start( 515 FROM_HERE, 516 base::TimeDelta::FromMilliseconds(forced_delay_ms), 517 RenderThread::Get(), 518 &RenderThread::IdleHandler); 519 } 520} 521 522void Dispatcher::OnRenderProcessShutdown() { 523 v8_schema_registry_.reset(); 524 forced_idle_timer_.reset(); 525} 526 527void Dispatcher::OnActivateExtension(const std::string& extension_id) { 528 const Extension* extension = extensions_.GetByID(extension_id); 529 if (!extension) { 530 // Extension was activated but was never loaded. This probably means that 531 // the renderer failed to load it (or the browser failed to tell us when it 532 // did). Failures shouldn't happen, but instead of crashing there (which 533 // executes on all renderers) be conservative and only crash in the renderer 534 // of the extension which failed to load; this one. 535 std::string& error = extension_load_errors_[extension_id]; 536 char minidump[256]; 537 base::debug::Alias(&minidump); 538 base::snprintf(minidump, 539 arraysize(minidump), 540 "e::dispatcher:%s:%s", 541 extension_id.c_str(), 542 error.c_str()); 543 CHECK(extension) << extension_id << " was never loaded: " << error; 544 } 545 546 active_extension_ids_.insert(extension_id); 547 548 // This is called when starting a new extension page, so start the idle 549 // handler ticking. 550 RenderThread::Get()->ScheduleIdleHandler(kInitialExtensionIdleHandlerDelayMs); 551 552 if (is_webkit_initialized_) { 553 extensions::DOMActivityLogger::AttachToWorld( 554 extensions::DOMActivityLogger::kMainWorldId, extension_id); 555 } 556 557 UpdateActiveExtensions(); 558} 559 560void Dispatcher::OnCancelSuspend(const std::string& extension_id) { 561 DispatchEvent(extension_id, kOnSuspendCanceledEvent); 562} 563 564void Dispatcher::OnClearTabSpecificPermissions( 565 int tab_id, 566 const std::vector<std::string>& extension_ids) { 567 delegate_->ClearTabSpecificPermissions(this, tab_id, extension_ids); 568} 569 570void Dispatcher::OnDeliverMessage(int target_port_id, const Message& message) { 571 scoped_ptr<RequestSender::ScopedTabID> scoped_tab_id; 572 std::map<int, int>::const_iterator it = 573 port_to_tab_id_map_.find(target_port_id); 574 if (it != port_to_tab_id_map_.end()) { 575 scoped_tab_id.reset( 576 new RequestSender::ScopedTabID(request_sender(), it->second)); 577 } 578 579 MessagingBindings::DeliverMessage(script_context_set_.GetAll(), 580 target_port_id, 581 message, 582 NULL); // All render views. 583} 584 585void Dispatcher::OnDispatchOnConnect( 586 int target_port_id, 587 const std::string& channel_name, 588 const base::DictionaryValue& source_tab, 589 const ExtensionMsg_ExternalConnectionInfo& info, 590 const std::string& tls_channel_id) { 591 DCHECK(!ContainsKey(port_to_tab_id_map_, target_port_id)); 592 DCHECK_EQ(1, target_port_id % 2); // target renderer ports have odd IDs. 593 int sender_tab_id = -1; 594 source_tab.GetInteger("id", &sender_tab_id); 595 port_to_tab_id_map_[target_port_id] = sender_tab_id; 596 597 MessagingBindings::DispatchOnConnect(script_context_set_.GetAll(), 598 target_port_id, 599 channel_name, 600 source_tab, 601 info.source_id, 602 info.target_id, 603 info.source_url, 604 tls_channel_id, 605 NULL); // All render views. 606} 607 608void Dispatcher::OnDispatchOnDisconnect(int port_id, 609 const std::string& error_message) { 610 MessagingBindings::DispatchOnDisconnect(script_context_set_.GetAll(), 611 port_id, 612 error_message, 613 NULL); // All render views. 614} 615 616void Dispatcher::OnLoaded( 617 const std::vector<ExtensionMsg_Loaded_Params>& loaded_extensions) { 618 std::vector<ExtensionMsg_Loaded_Params>::const_iterator i; 619 for (i = loaded_extensions.begin(); i != loaded_extensions.end(); ++i) { 620 std::string error; 621 scoped_refptr<const Extension> extension = i->ConvertToExtension(&error); 622 if (!extension.get()) { 623 extension_load_errors_[i->id] = error; 624 continue; 625 } 626 OnLoadedInternal(extension); 627 } 628 // Update the available bindings for all contexts. These may have changed if 629 // an externally_connectable extension was loaded that can connect to an 630 // open webpage. 631 UpdateBindings(""); 632} 633 634void Dispatcher::OnLoadedInternal(scoped_refptr<const Extension> extension) { 635 extensions_.Insert(extension); 636} 637 638void Dispatcher::OnMessageInvoke(const std::string& extension_id, 639 const std::string& module_name, 640 const std::string& function_name, 641 const base::ListValue& args, 642 bool user_gesture) { 643 InvokeModuleSystemMethod( 644 NULL, extension_id, module_name, function_name, args, user_gesture); 645} 646 647void Dispatcher::OnSetChannel(int channel) { 648 delegate_->SetChannel(channel); 649} 650 651void Dispatcher::OnSetFunctionNames(const std::vector<std::string>& names) { 652 function_names_.clear(); 653 for (size_t i = 0; i < names.size(); ++i) 654 function_names_.insert(names[i]); 655} 656 657void Dispatcher::OnSetScriptingWhitelist( 658 const ExtensionsClient::ScriptingWhitelist& extension_ids) { 659 ExtensionsClient::Get()->SetScriptingWhitelist(extension_ids); 660} 661 662void Dispatcher::OnSetSystemFont(const std::string& font_family, 663 const std::string& font_size) { 664 system_font_family_ = font_family; 665 system_font_size_ = font_size; 666} 667 668void Dispatcher::OnShouldSuspend(const std::string& extension_id, 669 int sequence_id) { 670 RenderThread::Get()->Send( 671 new ExtensionHostMsg_ShouldSuspendAck(extension_id, sequence_id)); 672} 673 674void Dispatcher::OnSuspend(const std::string& extension_id) { 675 // Dispatch the suspend event. This doesn't go through the standard event 676 // dispatch machinery because it requires special handling. We need to let 677 // the browser know when we are starting and stopping the event dispatch, so 678 // that it still considers the extension idle despite any activity the suspend 679 // event creates. 680 DispatchEvent(extension_id, kOnSuspendEvent); 681 RenderThread::Get()->Send(new ExtensionHostMsg_SuspendAck(extension_id)); 682} 683 684void Dispatcher::OnUnloaded(const std::string& id) { 685 extensions_.Remove(id); 686 active_extension_ids_.erase(id); 687 688 // If the extension is later reloaded with a different set of permissions, 689 // we'd like it to get a new isolated world ID, so that it can pick up the 690 // changed origin whitelist. 691 user_script_slave_->RemoveIsolatedWorld(id); 692 693 // Invalidate all of the contexts that were removed. 694 // TODO(kalman): add an invalidation observer interface to ScriptContext. 695 ScriptContextSet::ContextSet removed_contexts = 696 script_context_set_.OnExtensionUnloaded(id); 697 for (ScriptContextSet::ContextSet::iterator it = removed_contexts.begin(); 698 it != removed_contexts.end(); 699 ++it) { 700 request_sender_->InvalidateSource(*it); 701 } 702 703 // Update the available bindings for the remaining contexts. These may have 704 // changed if an externally_connectable extension is unloaded and a webpage 705 // is no longer accessible. 706 UpdateBindings(""); 707 708 // Invalidates the messages map for the extension in case the extension is 709 // reloaded with a new messages map. 710 EraseL10nMessagesMap(id); 711 712 // We don't do anything with existing platform-app stylesheets. They will 713 // stay resident, but the URL pattern corresponding to the unloaded 714 // extension's URL just won't match anything anymore. 715} 716 717void Dispatcher::OnUpdatePermissions( 718 const ExtensionMsg_UpdatePermissions_Params& params) { 719 int reason_id = params.reason_id; 720 const std::string& extension_id = params.extension_id; 721 const APIPermissionSet& apis = params.apis; 722 const ManifestPermissionSet& manifest_permissions = 723 params.manifest_permissions; 724 const URLPatternSet& explicit_hosts = params.explicit_hosts; 725 const URLPatternSet& scriptable_hosts = params.scriptable_hosts; 726 727 const Extension* extension = extensions_.GetByID(extension_id); 728 if (!extension) 729 return; 730 731 scoped_refptr<const PermissionSet> delta = new PermissionSet( 732 apis, manifest_permissions, explicit_hosts, scriptable_hosts); 733 scoped_refptr<const PermissionSet> old_active = 734 extension->GetActivePermissions(); 735 UpdatedExtensionPermissionsInfo::Reason reason = 736 static_cast<UpdatedExtensionPermissionsInfo::Reason>(reason_id); 737 738 const PermissionSet* new_active = NULL; 739 switch (reason) { 740 case UpdatedExtensionPermissionsInfo::ADDED: 741 new_active = PermissionSet::CreateUnion(old_active.get(), delta.get()); 742 break; 743 case UpdatedExtensionPermissionsInfo::REMOVED: 744 new_active = 745 PermissionSet::CreateDifference(old_active.get(), delta.get()); 746 break; 747 } 748 749 PermissionsData::SetActivePermissions(extension, new_active); 750 UpdateOriginPermissions(reason, extension, explicit_hosts); 751 UpdateBindings(extension->id()); 752} 753 754void Dispatcher::OnUpdateTabSpecificPermissions( 755 int page_id, 756 int tab_id, 757 const std::string& extension_id, 758 const URLPatternSet& origin_set) { 759 delegate_->UpdateTabSpecificPermissions( 760 this, page_id, tab_id, extension_id, origin_set); 761} 762 763void Dispatcher::OnUpdateUserScripts(base::SharedMemoryHandle scripts) { 764 DCHECK(base::SharedMemory::IsHandleValid(scripts)) << "Bad scripts handle"; 765 user_script_slave_->UpdateScripts(scripts); 766 UpdateActiveExtensions(); 767} 768 769void Dispatcher::OnUsingWebRequestAPI(bool adblock, 770 bool adblock_plus, 771 bool other_webrequest) { 772 delegate_->HandleWebRequestAPIUsage(adblock, adblock_plus, other_webrequest); 773} 774 775void Dispatcher::UpdateActiveExtensions() { 776 std::set<std::string> active_extensions = active_extension_ids_; 777 user_script_slave_->GetActiveExtensions(&active_extensions); 778 delegate_->OnActiveExtensionsUpdated(active_extensions); 779} 780 781void Dispatcher::InitOriginPermissions(const Extension* extension, 782 Feature::Context context_type) { 783 delegate_->InitOriginPermissions(extension, context_type); 784 UpdateOriginPermissions( 785 UpdatedExtensionPermissionsInfo::ADDED, 786 extension, 787 PermissionsData::GetEffectiveHostPermissions(extension)); 788} 789 790void Dispatcher::UpdateOriginPermissions( 791 UpdatedExtensionPermissionsInfo::Reason reason, 792 const Extension* extension, 793 const URLPatternSet& origins) { 794 for (URLPatternSet::const_iterator i = origins.begin(); i != origins.end(); 795 ++i) { 796 const char* schemes[] = { 797 url::kHttpScheme, 798 url::kHttpsScheme, 799 content::kFileScheme, 800 content::kChromeUIScheme, 801 content::kFtpScheme, 802 }; 803 for (size_t j = 0; j < arraysize(schemes); ++j) { 804 if (i->MatchesScheme(schemes[j])) { 805 ((reason == UpdatedExtensionPermissionsInfo::REMOVED) 806 ? WebSecurityPolicy::removeOriginAccessWhitelistEntry 807 : WebSecurityPolicy::addOriginAccessWhitelistEntry)( 808 extension->url(), 809 WebString::fromUTF8(schemes[j]), 810 WebString::fromUTF8(i->host()), 811 i->match_subdomains()); 812 } 813 } 814 } 815} 816 817void Dispatcher::EnableCustomElementWhiteList() { 818 blink::WebCustomElement::addEmbedderCustomElementName("webview"); 819 // TODO(fsamuel): Add <adview> to the whitelist once it has been converted 820 // into a custom element. 821 blink::WebCustomElement::addEmbedderCustomElementName("browser-plugin"); 822} 823 824void Dispatcher::UpdateBindings(const std::string& extension_id) { 825 script_context_set().ForEach(extension_id, 826 NULL, // all render views 827 base::Bind(&Dispatcher::UpdateBindingsForContext, 828 base::Unretained(this))); 829} 830 831void Dispatcher::UpdateBindingsForContext(ScriptContext* context) { 832 v8::HandleScope handle_scope(context->isolate()); 833 v8::Context::Scope context_scope(context->v8_context()); 834 835 // TODO(kalman): Make the bindings registration have zero overhead then run 836 // the same code regardless of context type. 837 switch (context->context_type()) { 838 case Feature::UNSPECIFIED_CONTEXT: 839 case Feature::WEB_PAGE_CONTEXT: 840 case Feature::BLESSED_WEB_PAGE_CONTEXT: { 841 // Web page context; it's too expensive to run the full bindings code. 842 // Hard-code that the app and webstore APIs are available... 843 RegisterBinding("app", context); 844 RegisterBinding("webstore", context); 845 846 // ... and that the runtime API might be available if any extension can 847 // connect to it. 848 bool runtime_is_available = false; 849 for (ExtensionSet::const_iterator it = extensions_.begin(); 850 it != extensions_.end(); 851 ++it) { 852 ExternallyConnectableInfo* info = 853 static_cast<ExternallyConnectableInfo*>( 854 (*it)->GetManifestData(manifest_keys::kExternallyConnectable)); 855 if (info && info->matches.MatchesURL(context->GetURL())) { 856 runtime_is_available = true; 857 break; 858 } 859 } 860 if (runtime_is_available) 861 RegisterBinding("runtime", context); 862 break; 863 } 864 865 case Feature::BLESSED_EXTENSION_CONTEXT: 866 case Feature::UNBLESSED_EXTENSION_CONTEXT: 867 case Feature::CONTENT_SCRIPT_CONTEXT: { 868 // Extension context; iterate through all the APIs and bind the available 869 // ones. 870 FeatureProvider* api_feature_provider = FeatureProvider::GetAPIFeatures(); 871 const std::vector<std::string>& apis = 872 api_feature_provider->GetAllFeatureNames(); 873 for (std::vector<std::string>::const_iterator it = apis.begin(); 874 it != apis.end(); 875 ++it) { 876 const std::string& api_name = *it; 877 Feature* feature = api_feature_provider->GetFeature(api_name); 878 DCHECK(feature); 879 880 // Internal APIs are included via require(api_name) from internal code 881 // rather than chrome[api_name]. 882 if (feature->IsInternal()) 883 continue; 884 885 // If this API has a parent feature (and isn't marked 'noparent'), 886 // then this must be a function or event, so we should not register. 887 if (api_feature_provider->GetParent(feature) != NULL) 888 continue; 889 890 if (context->IsAnyFeatureAvailableToContext(*feature)) 891 RegisterBinding(api_name, context); 892 } 893 if (CommandLine::ForCurrentProcess()->HasSwitch(::switches::kTestType)) { 894 RegisterBinding("test", context); 895 } 896 break; 897 } 898 } 899} 900 901void Dispatcher::RegisterBinding(const std::string& api_name, 902 ScriptContext* context) { 903 std::string bind_name; 904 v8::Handle<v8::Object> bind_object = 905 GetOrCreateBindObjectIfAvailable(api_name, &bind_name, context); 906 907 // Empty if the bind object failed to be created, probably because the 908 // extension overrode chrome with a non-object, e.g. window.chrome = true. 909 if (bind_object.IsEmpty()) 910 return; 911 912 v8::Local<v8::String> v8_api_name = 913 v8::String::NewFromUtf8(context->isolate(), api_name.c_str()); 914 if (bind_object->HasRealNamedProperty(v8_api_name)) { 915 // The bind object may already have the property if the API has been 916 // registered before (or if the extension has put something there already, 917 // but, whatevs). 918 // 919 // In the former case, we need to re-register the bindings for the APIs 920 // which the extension now has permissions for (if any), but not touch any 921 // others so that we don't destroy state such as event listeners. 922 // 923 // TODO(kalman): Only register available APIs to make this all moot. 924 if (bind_object->HasRealNamedCallbackProperty(v8_api_name)) 925 return; // lazy binding still there, nothing to do 926 if (bind_object->Get(v8_api_name)->IsObject()) 927 return; // binding has already been fully installed 928 } 929 930 ModuleSystem* module_system = context->module_system(); 931 if (!source_map_.Contains(api_name)) { 932 module_system->RegisterNativeHandler( 933 api_name, 934 scoped_ptr<NativeHandler>(new BindingGeneratingNativeHandler( 935 module_system, api_name, "binding"))); 936 module_system->SetNativeLazyField( 937 bind_object, bind_name, api_name, "binding"); 938 } else { 939 module_system->SetLazyField(bind_object, bind_name, api_name, "binding"); 940 } 941} 942 943// NOTE: please use the naming convention "foo_natives" for these. 944void Dispatcher::RegisterNativeHandlers(ModuleSystem* module_system, 945 ScriptContext* context) { 946 module_system->RegisterNativeHandler( 947 "chrome", scoped_ptr<NativeHandler>(new ChromeNativeHandler(context))); 948 module_system->RegisterNativeHandler( 949 "lazy_background_page", 950 scoped_ptr<NativeHandler>(new LazyBackgroundPageNativeHandler(context))); 951 module_system->RegisterNativeHandler( 952 "logging", scoped_ptr<NativeHandler>(new LoggingNativeHandler(context))); 953 module_system->RegisterNativeHandler("schema_registry", 954 v8_schema_registry_->AsNativeHandler()); 955 module_system->RegisterNativeHandler( 956 "print", scoped_ptr<NativeHandler>(new PrintNativeHandler(context))); 957 module_system->RegisterNativeHandler( 958 "test_features", 959 scoped_ptr<NativeHandler>(new TestFeaturesNativeHandler(context))); 960 module_system->RegisterNativeHandler( 961 "user_gestures", 962 scoped_ptr<NativeHandler>(new UserGesturesNativeHandler(context))); 963 module_system->RegisterNativeHandler( 964 "utils", scoped_ptr<NativeHandler>(new UtilsNativeHandler(context))); 965 module_system->RegisterNativeHandler( 966 "v8_context", 967 scoped_ptr<NativeHandler>(new V8ContextNativeHandler(context, this))); 968 969 const Extension* extension = context->extension(); 970 int manifest_version = extension ? extension->manifest_version() : 1; 971 bool send_request_disabled = 972 (extension && Manifest::IsUnpackedLocation(extension->location()) && 973 BackgroundInfo::HasLazyBackgroundPage(extension)); 974 module_system->RegisterNativeHandler( 975 "process", 976 scoped_ptr<NativeHandler>(new ProcessInfoNativeHandler( 977 context, 978 context->GetExtensionID(), 979 context->GetContextTypeDescription(), 980 ExtensionsRendererClient::Get()->IsIncognitoProcess(), 981 manifest_version, 982 send_request_disabled))); 983 984 module_system->RegisterNativeHandler( 985 "event_natives", 986 scoped_ptr<NativeHandler>(new EventBindings(this, context))); 987 module_system->RegisterNativeHandler( 988 "messaging_natives", 989 scoped_ptr<NativeHandler>(MessagingBindings::Get(this, context))); 990 module_system->RegisterNativeHandler( 991 "apiDefinitions", 992 scoped_ptr<NativeHandler>(new ApiDefinitionsNatives(this, context))); 993 module_system->RegisterNativeHandler( 994 "sendRequest", 995 scoped_ptr<NativeHandler>( 996 new SendRequestNatives(request_sender_.get(), context))); 997 module_system->RegisterNativeHandler( 998 "setIcon", 999 scoped_ptr<NativeHandler>( 1000 new SetIconNatives(request_sender_.get(), context))); 1001 module_system->RegisterNativeHandler( 1002 "activityLogger", 1003 scoped_ptr<NativeHandler>(new APIActivityLogger(context))); 1004 module_system->RegisterNativeHandler( 1005 "renderViewObserverNatives", 1006 scoped_ptr<NativeHandler>(new RenderViewObserverNatives(context))); 1007 1008 // Natives used by multiple APIs. 1009 module_system->RegisterNativeHandler( 1010 "file_system_natives", 1011 scoped_ptr<NativeHandler>(new FileSystemNatives(context))); 1012 1013 // Custom bindings. 1014 module_system->RegisterNativeHandler( 1015 "app_runtime", 1016 scoped_ptr<NativeHandler>(new AppRuntimeCustomBindings(context))); 1017 module_system->RegisterNativeHandler( 1018 "blob_natives", 1019 scoped_ptr<NativeHandler>(new BlobNativeHandler(context))); 1020 module_system->RegisterNativeHandler( 1021 "context_menus", 1022 scoped_ptr<NativeHandler>(new ContextMenusCustomBindings(context))); 1023 module_system->RegisterNativeHandler( 1024 "css_natives", scoped_ptr<NativeHandler>(new CssNativeHandler(context))); 1025 module_system->RegisterNativeHandler( 1026 "document_natives", 1027 scoped_ptr<NativeHandler>(new DocumentCustomBindings(context))); 1028 module_system->RegisterNativeHandler( 1029 "i18n", scoped_ptr<NativeHandler>(new I18NCustomBindings(context))); 1030 module_system->RegisterNativeHandler( 1031 "id_generator", 1032 scoped_ptr<NativeHandler>(new IdGeneratorCustomBindings(context))); 1033 module_system->RegisterNativeHandler( 1034 "runtime", scoped_ptr<NativeHandler>(new RuntimeCustomBindings(context))); 1035 1036 delegate_->RegisterNativeHandlers(this, module_system, context); 1037} 1038 1039void Dispatcher::PopulateSourceMap() { 1040 // Libraries. 1041 source_map_.RegisterSource("entryIdManager", IDR_ENTRY_ID_MANAGER); 1042 source_map_.RegisterSource(kEventBindings, IDR_EVENT_BINDINGS_JS); 1043 source_map_.RegisterSource("imageUtil", IDR_IMAGE_UTIL_JS); 1044 source_map_.RegisterSource("json_schema", IDR_JSON_SCHEMA_JS); 1045 source_map_.RegisterSource("lastError", IDR_LAST_ERROR_JS); 1046 source_map_.RegisterSource("messaging", IDR_MESSAGING_JS); 1047 source_map_.RegisterSource("messaging_utils", IDR_MESSAGING_UTILS_JS); 1048 source_map_.RegisterSource(kSchemaUtils, IDR_SCHEMA_UTILS_JS); 1049 source_map_.RegisterSource("sendRequest", IDR_SEND_REQUEST_JS); 1050 source_map_.RegisterSource("setIcon", IDR_SET_ICON_JS); 1051 source_map_.RegisterSource("test", IDR_TEST_CUSTOM_BINDINGS_JS); 1052 source_map_.RegisterSource("uncaught_exception_handler", 1053 IDR_UNCAUGHT_EXCEPTION_HANDLER_JS); 1054 source_map_.RegisterSource("unload_event", IDR_UNLOAD_EVENT_JS); 1055 source_map_.RegisterSource("utils", IDR_UTILS_JS); 1056 1057 // Custom bindings. 1058 source_map_.RegisterSource("app.runtime", IDR_APP_RUNTIME_CUSTOM_BINDINGS_JS); 1059 source_map_.RegisterSource("contextMenus", 1060 IDR_CONTEXT_MENUS_CUSTOM_BINDINGS_JS); 1061 source_map_.RegisterSource("extension", IDR_EXTENSION_CUSTOM_BINDINGS_JS); 1062 source_map_.RegisterSource("i18n", IDR_I18N_CUSTOM_BINDINGS_JS); 1063 source_map_.RegisterSource("permissions", IDR_PERMISSIONS_CUSTOM_BINDINGS_JS); 1064 source_map_.RegisterSource("runtime", IDR_RUNTIME_CUSTOM_BINDINGS_JS); 1065 source_map_.RegisterSource("binding", IDR_BINDING_JS); 1066 1067 // Custom types sources. 1068 source_map_.RegisterSource("StorageArea", IDR_STORAGE_AREA_JS); 1069 1070 // Platform app sources that are not API-specific.. 1071 source_map_.RegisterSource("platformApp", IDR_PLATFORM_APP_JS); 1072 1073 delegate_->PopulateSourceMap(&source_map_); 1074} 1075 1076bool Dispatcher::IsWithinPlatformApp() { 1077 for (std::set<std::string>::iterator iter = active_extension_ids_.begin(); 1078 iter != active_extension_ids_.end(); 1079 ++iter) { 1080 const Extension* extension = extensions_.GetByID(*iter); 1081 if (extension && extension->is_platform_app()) 1082 return true; 1083 } 1084 return false; 1085} 1086 1087// TODO(kalman): This is checking for the wrong thing, it should be checking if 1088// the frame's security origin is unique. The extension sandbox directive is 1089// checked for in extensions/common/manifest_handlers/csp_info.cc. 1090bool Dispatcher::IsSandboxedPage(const GURL& url) const { 1091 if (url.SchemeIs(kExtensionScheme)) { 1092 const Extension* extension = extensions_.GetByID(url.host()); 1093 if (extension) { 1094 return SandboxedPageInfo::IsSandboxedPage(extension, url.path()); 1095 } 1096 } 1097 return false; 1098} 1099 1100Feature::Context Dispatcher::ClassifyJavaScriptContext( 1101 const Extension* extension, 1102 int extension_group, 1103 const GURL& url, 1104 const blink::WebSecurityOrigin& origin) { 1105 DCHECK_GE(extension_group, 0); 1106 if (extension_group == EXTENSION_GROUP_CONTENT_SCRIPTS) { 1107 return extension ? // TODO(kalman): when does this happen? 1108 Feature::CONTENT_SCRIPT_CONTEXT 1109 : Feature::UNSPECIFIED_CONTEXT; 1110 } 1111 1112 // We have an explicit check for sandboxed pages before checking whether the 1113 // extension is active in this process because: 1114 // 1. Sandboxed pages run in the same process as regular extension pages, so 1115 // the extension is considered active. 1116 // 2. ScriptContext creation (which triggers bindings injection) happens 1117 // before the SecurityContext is updated with the sandbox flags (after 1118 // reading the CSP header), so the caller can't check if the context's 1119 // security origin is unique yet. 1120 if (IsSandboxedPage(url)) 1121 return Feature::WEB_PAGE_CONTEXT; 1122 1123 if (extension && IsExtensionActive(extension->id())) { 1124 // |extension| is active in this process, but it could be either a true 1125 // extension process or within the extent of a hosted app. In the latter 1126 // case this would usually be considered a (blessed) web page context, 1127 // unless the extension in question is a component extension, in which case 1128 // we cheat and call it blessed. 1129 return (extension->is_hosted_app() && 1130 extension->location() != Manifest::COMPONENT) 1131 ? Feature::BLESSED_WEB_PAGE_CONTEXT 1132 : Feature::BLESSED_EXTENSION_CONTEXT; 1133 } 1134 1135 // TODO(kalman): This isUnique() check is wrong, it should be performed as 1136 // part of IsSandboxedPage(). 1137 if (!origin.isUnique() && extensions_.ExtensionBindingsAllowed(url)) { 1138 if (!extension) // TODO(kalman): when does this happen? 1139 return Feature::UNSPECIFIED_CONTEXT; 1140 return extension->is_hosted_app() ? Feature::BLESSED_WEB_PAGE_CONTEXT 1141 : Feature::UNBLESSED_EXTENSION_CONTEXT; 1142 } 1143 1144 if (url.is_valid()) 1145 return Feature::WEB_PAGE_CONTEXT; 1146 1147 return Feature::UNSPECIFIED_CONTEXT; 1148} 1149 1150v8::Handle<v8::Object> Dispatcher::GetOrCreateObject( 1151 const v8::Handle<v8::Object>& object, 1152 const std::string& field, 1153 v8::Isolate* isolate) { 1154 v8::Handle<v8::String> key = v8::String::NewFromUtf8(isolate, field.c_str()); 1155 // If the object has a callback property, it is assumed it is an unavailable 1156 // API, so it is safe to delete. This is checked before GetOrCreateObject is 1157 // called. 1158 if (object->HasRealNamedCallbackProperty(key)) { 1159 object->Delete(key); 1160 } else if (object->HasRealNamedProperty(key)) { 1161 v8::Handle<v8::Value> value = object->Get(key); 1162 CHECK(value->IsObject()); 1163 return v8::Handle<v8::Object>::Cast(value); 1164 } 1165 1166 v8::Handle<v8::Object> new_object = v8::Object::New(isolate); 1167 object->Set(key, new_object); 1168 return new_object; 1169} 1170 1171v8::Handle<v8::Object> Dispatcher::GetOrCreateBindObjectIfAvailable( 1172 const std::string& api_name, 1173 std::string* bind_name, 1174 ScriptContext* context) { 1175 std::vector<std::string> split; 1176 base::SplitString(api_name, '.', &split); 1177 1178 v8::Handle<v8::Object> bind_object; 1179 1180 // Check if this API has an ancestor. If the API's ancestor is available and 1181 // the API is not available, don't install the bindings for this API. If 1182 // the API is available and its ancestor is not, delete the ancestor and 1183 // install the bindings for the API. This is to prevent loading the ancestor 1184 // API schema if it will not be needed. 1185 // 1186 // For example: 1187 // If app is available and app.window is not, just install app. 1188 // If app.window is available and app is not, delete app and install 1189 // app.window on a new object so app does not have to be loaded. 1190 FeatureProvider* api_feature_provider = FeatureProvider::GetAPIFeatures(); 1191 std::string ancestor_name; 1192 bool only_ancestor_available = false; 1193 1194 for (size_t i = 0; i < split.size() - 1; ++i) { 1195 ancestor_name += (i ? "." : "") + split[i]; 1196 if (api_feature_provider->GetFeature(ancestor_name) && 1197 context->GetAvailability(ancestor_name).is_available() && 1198 !context->GetAvailability(api_name).is_available()) { 1199 only_ancestor_available = true; 1200 break; 1201 } 1202 1203 if (bind_object.IsEmpty()) { 1204 bind_object = AsObjectOrEmpty(GetOrCreateChrome(context)); 1205 if (bind_object.IsEmpty()) 1206 return v8::Handle<v8::Object>(); 1207 } 1208 bind_object = GetOrCreateObject(bind_object, split[i], context->isolate()); 1209 } 1210 1211 if (only_ancestor_available) 1212 return v8::Handle<v8::Object>(); 1213 1214 if (bind_name) 1215 *bind_name = split.back(); 1216 1217 return bind_object.IsEmpty() ? AsObjectOrEmpty(GetOrCreateChrome(context)) 1218 : bind_object; 1219} 1220 1221} // namespace extensions 1222