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