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