1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "chrome/renderer/extensions/dispatcher.h" 6 7 #include "base/callback.h" 8 #include "base/command_line.h" 9 #include "base/debug/alias.h" 10 #include "base/json/json_reader.h" 11 #include "base/memory/scoped_ptr.h" 12 #include "base/sha1.h" 13 #include "base/strings/string_number_conversions.h" 14 #include "base/strings/string_piece.h" 15 #include "base/strings/string_split.h" 16 #include "base/strings/string_util.h" 17 #include "chrome/common/chrome_switches.h" 18 #include "chrome/common/chrome_version_info.h" 19 #include "chrome/common/crash_keys.h" 20 #include "chrome/common/extensions/api/messaging/message.h" 21 #include "chrome/common/extensions/extension_messages.h" 22 #include "chrome/common/extensions/features/feature_channel.h" 23 #include "chrome/common/extensions/manifest_handlers/externally_connectable.h" 24 #include "chrome/common/extensions/message_bundle.h" 25 #include "chrome/common/url_constants.h" 26 #include "chrome/renderer/chrome_render_process_observer.h" 27 #include "chrome/renderer/extensions/api_activity_logger.h" 28 #include "chrome/renderer/extensions/api_definitions_natives.h" 29 #include "chrome/renderer/extensions/app_bindings.h" 30 #include "chrome/renderer/extensions/app_runtime_custom_bindings.h" 31 #include "chrome/renderer/extensions/app_window_custom_bindings.h" 32 #include "chrome/renderer/extensions/binding_generating_native_handler.h" 33 #include "chrome/renderer/extensions/blob_native_handler.h" 34 #include "chrome/renderer/extensions/chrome_v8_context.h" 35 #include "chrome/renderer/extensions/chrome_v8_extension.h" 36 #include "chrome/renderer/extensions/content_watcher.h" 37 #include "chrome/renderer/extensions/context_menus_custom_bindings.h" 38 #include "chrome/renderer/extensions/css_native_handler.h" 39 #include "chrome/renderer/extensions/document_custom_bindings.h" 40 #include "chrome/renderer/extensions/dom_activity_logger.h" 41 #include "chrome/renderer/extensions/event_bindings.h" 42 #include "chrome/renderer/extensions/extension_groups.h" 43 #include "chrome/renderer/extensions/extension_helper.h" 44 #include "chrome/renderer/extensions/file_browser_handler_custom_bindings.h" 45 #include "chrome/renderer/extensions/file_browser_private_custom_bindings.h" 46 #include "chrome/renderer/extensions/file_system_natives.h" 47 #include "chrome/renderer/extensions/i18n_custom_bindings.h" 48 #include "chrome/renderer/extensions/id_generator_custom_bindings.h" 49 #include "chrome/renderer/extensions/logging_native_handler.h" 50 #include "chrome/renderer/extensions/media_galleries_custom_bindings.h" 51 #include "chrome/renderer/extensions/messaging_bindings.h" 52 #include "chrome/renderer/extensions/module_system.h" 53 #include "chrome/renderer/extensions/object_backed_native_handler.h" 54 #include "chrome/renderer/extensions/page_actions_custom_bindings.h" 55 #include "chrome/renderer/extensions/page_capture_custom_bindings.h" 56 #include "chrome/renderer/extensions/pepper_request_natives.h" 57 #include "chrome/renderer/extensions/render_view_observer_natives.h" 58 #include "chrome/renderer/extensions/request_sender.h" 59 #include "chrome/renderer/extensions/runtime_custom_bindings.h" 60 #include "chrome/renderer/extensions/safe_builtins.h" 61 #include "chrome/renderer/extensions/send_request_natives.h" 62 #include "chrome/renderer/extensions/set_icon_natives.h" 63 #include "chrome/renderer/extensions/sync_file_system_custom_bindings.h" 64 #include "chrome/renderer/extensions/tab_finder.h" 65 #include "chrome/renderer/extensions/tabs_custom_bindings.h" 66 #include "chrome/renderer/extensions/user_script_slave.h" 67 #include "chrome/renderer/extensions/webstore_bindings.h" 68 #include "chrome/renderer/resource_bundle_source_map.h" 69 #include "content/public/renderer/render_thread.h" 70 #include "content/public/renderer/render_view.h" 71 #include "content/public/renderer/v8_value_converter.h" 72 #include "extensions/common/constants.h" 73 #include "extensions/common/extension.h" 74 #include "extensions/common/extension_api.h" 75 #include "extensions/common/extension_urls.h" 76 #include "extensions/common/features/feature.h" 77 #include "extensions/common/features/feature_provider.h" 78 #include "extensions/common/manifest.h" 79 #include "extensions/common/manifest_constants.h" 80 #include "extensions/common/manifest_handlers/background_info.h" 81 #include "extensions/common/manifest_handlers/sandboxed_page_info.h" 82 #include "extensions/common/permissions/permission_set.h" 83 #include "extensions/common/permissions/permissions_data.h" 84 #include "extensions/common/view_type.h" 85 #include "grit/common_resources.h" 86 #include "grit/renderer_resources.h" 87 #include "third_party/WebKit/public/platform/WebString.h" 88 #include "third_party/WebKit/public/platform/WebURLRequest.h" 89 #include "third_party/WebKit/public/web/WebCustomElement.h" 90 #include "third_party/WebKit/public/web/WebDataSource.h" 91 #include "third_party/WebKit/public/web/WebDocument.h" 92 #include "third_party/WebKit/public/web/WebFrame.h" 93 #include "third_party/WebKit/public/web/WebRuntimeFeatures.h" 94 #include "third_party/WebKit/public/web/WebScopedUserGesture.h" 95 #include "third_party/WebKit/public/web/WebSecurityPolicy.h" 96 #include "third_party/WebKit/public/web/WebUserGestureIndicator.h" 97 #include "third_party/WebKit/public/web/WebView.h" 98 #include "ui/base/layout.h" 99 #include "ui/base/resource/resource_bundle.h" 100 #include "v8/include/v8.h" 101 102 #if defined(ENABLE_WEBRTC) 103 #include "chrome/renderer/extensions/cast_streaming_native_handler.h" 104 #endif 105 106 using blink::WebDataSource; 107 using blink::WebDocument; 108 using blink::WebFrame; 109 using blink::WebScopedUserGesture; 110 using blink::WebSecurityPolicy; 111 using blink::WebString; 112 using blink::WebVector; 113 using blink::WebView; 114 using content::RenderThread; 115 using content::RenderView; 116 using content::UserMetricsAction; 117 118 namespace extensions { 119 120 namespace { 121 122 static const int64 kInitialExtensionIdleHandlerDelayMs = 5*1000; 123 static const int64 kMaxExtensionIdleHandlerDelayMs = 5*60*1000; 124 static const char kEventDispatchFunction[] = "dispatchEvent"; 125 static const char kOnSuspendEvent[] = "runtime.onSuspend"; 126 static const char kOnSuspendCanceledEvent[] = "runtime.onSuspendCanceled"; 127 128 // Returns the global value for "chrome" from |context|. If one doesn't exist 129 // creates a new object for it. 130 // 131 // Note that this isn't necessarily an object, since webpages can write, for 132 // example, "window.chrome = true". 133 v8::Handle<v8::Value> GetOrCreateChrome(ChromeV8Context* context) { 134 v8::Handle<v8::String> chrome_string( 135 v8::String::NewFromUtf8(context->isolate(), "chrome")); 136 v8::Handle<v8::Object> global(context->v8_context()->Global()); 137 v8::Handle<v8::Value> chrome(global->Get(chrome_string)); 138 if (chrome->IsUndefined()) { 139 chrome = v8::Object::New(); 140 global->Set(chrome_string, chrome); 141 } 142 return chrome; 143 } 144 145 // Returns |value| cast to an object if possible, else an empty handle. 146 v8::Handle<v8::Object> AsObjectOrEmpty(v8::Handle<v8::Value> value) { 147 return value->IsObject() ? value.As<v8::Object>() : v8::Handle<v8::Object>(); 148 } 149 150 class TestFeaturesNativeHandler : public ObjectBackedNativeHandler { 151 public: 152 explicit TestFeaturesNativeHandler(ChromeV8Context* context) 153 : ObjectBackedNativeHandler(context) { 154 RouteFunction("GetAPIFeatures", 155 base::Bind(&TestFeaturesNativeHandler::GetAPIFeatures, 156 base::Unretained(this))); 157 } 158 159 private: 160 void GetAPIFeatures(const v8::FunctionCallbackInfo<v8::Value>& args) { 161 base::Value* value = base::JSONReader::Read( 162 ResourceBundle::GetSharedInstance().GetRawDataResource( 163 IDR_EXTENSION_API_FEATURES).as_string()); 164 scoped_ptr<content::V8ValueConverter> converter( 165 content::V8ValueConverter::create()); 166 args.GetReturnValue().Set( 167 converter->ToV8Value(value, context()->v8_context())); 168 } 169 }; 170 171 class UserGesturesNativeHandler : public ObjectBackedNativeHandler { 172 public: 173 explicit UserGesturesNativeHandler(ChromeV8Context* context) 174 : ObjectBackedNativeHandler(context) { 175 RouteFunction("IsProcessingUserGesture", 176 base::Bind(&UserGesturesNativeHandler::IsProcessingUserGesture, 177 base::Unretained(this))); 178 RouteFunction("RunWithUserGesture", 179 base::Bind(&UserGesturesNativeHandler::RunWithUserGesture, 180 base::Unretained(this))); 181 RouteFunction("RunWithoutUserGesture", 182 base::Bind(&UserGesturesNativeHandler::RunWithoutUserGesture, 183 base::Unretained(this))); 184 } 185 186 private: 187 void IsProcessingUserGesture( 188 const v8::FunctionCallbackInfo<v8::Value>& args) { 189 args.GetReturnValue().Set(v8::Boolean::New( 190 args.GetIsolate(), 191 blink::WebUserGestureIndicator::isProcessingUserGesture())); 192 } 193 194 void RunWithUserGesture( 195 const v8::FunctionCallbackInfo<v8::Value>& args) { 196 blink::WebScopedUserGesture user_gesture; 197 CHECK_EQ(args.Length(), 1); 198 CHECK(args[0]->IsFunction()); 199 v8::Handle<v8::Value> no_args; 200 context()->CallFunction(v8::Handle<v8::Function>::Cast(args[0]), 201 0, &no_args); 202 } 203 204 void RunWithoutUserGesture( 205 const v8::FunctionCallbackInfo<v8::Value>& args) { 206 blink::WebUserGestureIndicator::consumeUserGesture(); 207 CHECK_EQ(args.Length(), 1); 208 CHECK(args[0]->IsFunction()); 209 v8::Handle<v8::Value> no_args; 210 context()->CallFunction(v8::Handle<v8::Function>::Cast(args[0]), 211 0, &no_args); 212 } 213 }; 214 215 class V8ContextNativeHandler : public ObjectBackedNativeHandler { 216 public: 217 V8ContextNativeHandler(ChromeV8Context* context, Dispatcher* dispatcher) 218 : ObjectBackedNativeHandler(context), 219 context_(context), 220 dispatcher_(dispatcher) { 221 RouteFunction("GetAvailability", 222 base::Bind(&V8ContextNativeHandler::GetAvailability, 223 base::Unretained(this))); 224 RouteFunction("GetModuleSystem", 225 base::Bind(&V8ContextNativeHandler::GetModuleSystem, 226 base::Unretained(this))); 227 } 228 229 private: 230 void GetAvailability(const v8::FunctionCallbackInfo<v8::Value>& args) { 231 CHECK_EQ(args.Length(), 1); 232 v8::Isolate* isolate = args.GetIsolate(); 233 std::string api_name = *v8::String::Utf8Value(args[0]->ToString()); 234 Feature::Availability availability = context_->GetAvailability(api_name); 235 236 v8::Handle<v8::Object> ret = v8::Object::New(); 237 ret->Set(v8::String::NewFromUtf8(isolate, "is_available"), 238 v8::Boolean::New(isolate, availability.is_available())); 239 ret->Set(v8::String::NewFromUtf8(isolate, "message"), 240 v8::String::NewFromUtf8(isolate, availability.message().c_str())); 241 ret->Set(v8::String::NewFromUtf8(isolate, "result"), 242 v8::Integer::New(availability.result())); 243 args.GetReturnValue().Set(ret); 244 } 245 246 void GetModuleSystem(const v8::FunctionCallbackInfo<v8::Value>& args) { 247 CHECK_EQ(args.Length(), 1); 248 CHECK(args[0]->IsObject()); 249 v8::Handle<v8::Context> v8_context = 250 v8::Handle<v8::Object>::Cast(args[0])->CreationContext(); 251 ChromeV8Context* context = dispatcher_->v8_context_set().GetByV8Context( 252 v8_context); 253 args.GetReturnValue().Set(context->module_system()->NewInstance()); 254 } 255 256 ChromeV8Context* context_; 257 Dispatcher* dispatcher_; 258 }; 259 260 class ChromeNativeHandler : public ObjectBackedNativeHandler { 261 public: 262 explicit ChromeNativeHandler(ChromeV8Context* context) 263 : ObjectBackedNativeHandler(context) { 264 RouteFunction("GetChrome", 265 base::Bind(&ChromeNativeHandler::GetChrome, base::Unretained(this))); 266 } 267 268 void GetChrome(const v8::FunctionCallbackInfo<v8::Value>& args) { 269 args.GetReturnValue().Set(GetOrCreateChrome(context())); 270 } 271 }; 272 273 class PrintNativeHandler : public ObjectBackedNativeHandler { 274 public: 275 explicit PrintNativeHandler(ChromeV8Context* context) 276 : ObjectBackedNativeHandler(context) { 277 RouteFunction("Print", 278 base::Bind(&PrintNativeHandler::Print, 279 base::Unretained(this))); 280 } 281 282 void Print(const v8::FunctionCallbackInfo<v8::Value>& args) { 283 if (args.Length() < 1) 284 return; 285 286 std::vector<std::string> components; 287 for (int i = 0; i < args.Length(); ++i) 288 components.push_back(*v8::String::Utf8Value(args[i]->ToString())); 289 290 LOG(ERROR) << JoinString(components, ','); 291 } 292 }; 293 294 class LazyBackgroundPageNativeHandler : public ChromeV8Extension { 295 public: 296 LazyBackgroundPageNativeHandler(Dispatcher* dispatcher, 297 ChromeV8Context* context) 298 : ChromeV8Extension(dispatcher, context) { 299 RouteFunction("IncrementKeepaliveCount", 300 base::Bind(&LazyBackgroundPageNativeHandler::IncrementKeepaliveCount, 301 base::Unretained(this))); 302 RouteFunction("DecrementKeepaliveCount", 303 base::Bind(&LazyBackgroundPageNativeHandler::DecrementKeepaliveCount, 304 base::Unretained(this))); 305 } 306 307 void IncrementKeepaliveCount( 308 const v8::FunctionCallbackInfo<v8::Value>& args) { 309 if (!context()) 310 return; 311 RenderView* render_view = context()->GetRenderView(); 312 if (IsContextLazyBackgroundPage(render_view, context()->extension())) { 313 render_view->Send(new ExtensionHostMsg_IncrementLazyKeepaliveCount( 314 render_view->GetRoutingID())); 315 } 316 } 317 318 void DecrementKeepaliveCount( 319 const v8::FunctionCallbackInfo<v8::Value>& args) { 320 if (!context()) 321 return; 322 RenderView* render_view = context()->GetRenderView(); 323 if (IsContextLazyBackgroundPage(render_view, context()->extension())) { 324 render_view->Send(new ExtensionHostMsg_DecrementLazyKeepaliveCount( 325 render_view->GetRoutingID())); 326 } 327 } 328 329 private: 330 bool IsContextLazyBackgroundPage(RenderView* render_view, 331 const Extension* extension) { 332 if (!render_view) 333 return false; 334 335 ExtensionHelper* helper = ExtensionHelper::Get(render_view); 336 return (extension && BackgroundInfo::HasLazyBackgroundPage(extension) && 337 helper->view_type() == VIEW_TYPE_EXTENSION_BACKGROUND_PAGE); 338 } 339 }; 340 341 class ProcessInfoNativeHandler : public ChromeV8Extension { 342 public: 343 ProcessInfoNativeHandler(Dispatcher* dispatcher, 344 ChromeV8Context* context, 345 const std::string& extension_id, 346 const std::string& context_type, 347 bool is_incognito_context, 348 int manifest_version, 349 bool send_request_disabled) 350 : ChromeV8Extension(dispatcher, context), 351 extension_id_(extension_id), 352 context_type_(context_type), 353 is_incognito_context_(is_incognito_context), 354 manifest_version_(manifest_version), 355 send_request_disabled_(send_request_disabled) { 356 RouteFunction("GetExtensionId", 357 base::Bind(&ProcessInfoNativeHandler::GetExtensionId, 358 base::Unretained(this))); 359 RouteFunction("GetContextType", 360 base::Bind(&ProcessInfoNativeHandler::GetContextType, 361 base::Unretained(this))); 362 RouteFunction("InIncognitoContext", 363 base::Bind(&ProcessInfoNativeHandler::InIncognitoContext, 364 base::Unretained(this))); 365 RouteFunction("GetManifestVersion", 366 base::Bind(&ProcessInfoNativeHandler::GetManifestVersion, 367 base::Unretained(this))); 368 RouteFunction("IsSendRequestDisabled", 369 base::Bind(&ProcessInfoNativeHandler::IsSendRequestDisabled, 370 base::Unretained(this))); 371 RouteFunction("HasSwitch", 372 base::Bind(&ProcessInfoNativeHandler::HasSwitch, 373 base::Unretained(this))); 374 } 375 376 private: 377 void GetExtensionId(const v8::FunctionCallbackInfo<v8::Value>& args) { 378 args.GetReturnValue() 379 .Set(v8::String::NewFromUtf8(args.GetIsolate(), extension_id_.c_str())); 380 } 381 382 void GetContextType(const v8::FunctionCallbackInfo<v8::Value>& args) { 383 args.GetReturnValue() 384 .Set(v8::String::NewFromUtf8(args.GetIsolate(), context_type_.c_str())); 385 } 386 387 void InIncognitoContext(const v8::FunctionCallbackInfo<v8::Value>& args) { 388 args.GetReturnValue().Set(is_incognito_context_); 389 } 390 391 void GetManifestVersion(const v8::FunctionCallbackInfo<v8::Value>& args) { 392 args.GetReturnValue().Set(static_cast<int32_t>(manifest_version_)); 393 } 394 395 void IsSendRequestDisabled(const v8::FunctionCallbackInfo<v8::Value>& args) { 396 if (send_request_disabled_) { 397 args.GetReturnValue().Set(v8::String::NewFromUtf8(args.GetIsolate(), 398 "sendRequest and onRequest are obsolete." 399 " Please use sendMessage and onMessage instead.")); 400 } 401 } 402 403 void HasSwitch(const v8::FunctionCallbackInfo<v8::Value>& args) { 404 CHECK(args.Length() == 1 && args[0]->IsString()); 405 bool has_switch = CommandLine::ForCurrentProcess()->HasSwitch( 406 *v8::String::Utf8Value(args[0])); 407 args.GetReturnValue().Set(v8::Boolean::New(args.GetIsolate(), has_switch)); 408 } 409 410 std::string extension_id_; 411 std::string context_type_; 412 bool is_incognito_context_; 413 int manifest_version_; 414 bool send_request_disabled_; 415 }; 416 417 void InstallAppBindings(ModuleSystem* module_system, 418 v8::Handle<v8::Object> chrome) { 419 module_system->SetLazyField(chrome, "app", "app", "chromeApp"); 420 } 421 422 void InstallWebstoreBindings(ModuleSystem* module_system, 423 v8::Handle<v8::Object> chrome) { 424 module_system->SetLazyField(chrome, "webstore", "webstore", "chromeWebstore"); 425 } 426 427 // Calls a method |method_name| in a module |module_name| belonging to the 428 // module system from |context|. Intended as a callback target from 429 // ChromeV8ContextSet::ForEach. 430 void CallModuleMethod(const std::string& module_name, 431 const std::string& method_name, 432 const base::ListValue* args, 433 ChromeV8Context* context) { 434 v8::HandleScope handle_scope(context->isolate()); 435 v8::Context::Scope context_scope(context->v8_context()); 436 437 scoped_ptr<content::V8ValueConverter> converter( 438 content::V8ValueConverter::create()); 439 440 std::vector<v8::Handle<v8::Value> > arguments; 441 for (base::ListValue::const_iterator it = args->begin(); it != args->end(); 442 ++it) { 443 arguments.push_back(converter->ToV8Value(*it, context->v8_context())); 444 } 445 446 context->module_system()->CallModuleMethod( 447 module_name, method_name, &arguments); 448 } 449 450 } // namespace 451 452 Dispatcher::Dispatcher() 453 : content_watcher_(new ContentWatcher()), 454 is_webkit_initialized_(false), 455 webrequest_adblock_(false), 456 webrequest_adblock_plus_(false), 457 webrequest_other_(false), 458 source_map_(&ResourceBundle::GetSharedInstance()), 459 v8_schema_registry_(new V8SchemaRegistry) { 460 const CommandLine& command_line = *(CommandLine::ForCurrentProcess()); 461 is_extension_process_ = 462 command_line.HasSwitch(switches::kExtensionProcess) || 463 command_line.HasSwitch(switches::kSingleProcess); 464 465 if (is_extension_process_) { 466 RenderThread::Get()->SetIdleNotificationDelayInMs( 467 kInitialExtensionIdleHandlerDelayMs); 468 } 469 470 RenderThread::Get()->RegisterExtension(SafeBuiltins::CreateV8Extension()); 471 472 user_script_slave_.reset(new UserScriptSlave(&extensions_)); 473 request_sender_.reset(new RequestSender(this)); 474 PopulateSourceMap(); 475 PopulateLazyBindingsMap(); 476 } 477 478 Dispatcher::~Dispatcher() { 479 } 480 481 bool Dispatcher::OnControlMessageReceived(const IPC::Message& message) { 482 bool handled = true; 483 IPC_BEGIN_MESSAGE_MAP(Dispatcher, message) 484 IPC_MESSAGE_HANDLER(ExtensionMsg_SetChannel, OnSetChannel) 485 IPC_MESSAGE_HANDLER(ExtensionMsg_MessageInvoke, OnMessageInvoke) 486 IPC_MESSAGE_HANDLER(ExtensionMsg_DispatchOnConnect, OnDispatchOnConnect) 487 IPC_MESSAGE_HANDLER(ExtensionMsg_DeliverMessage, OnDeliverMessage) 488 IPC_MESSAGE_HANDLER(ExtensionMsg_DispatchOnDisconnect, 489 OnDispatchOnDisconnect) 490 IPC_MESSAGE_HANDLER(ExtensionMsg_SetFunctionNames, OnSetFunctionNames) 491 IPC_MESSAGE_HANDLER(ExtensionMsg_SetSystemFont, OnSetSystemFont) 492 IPC_MESSAGE_HANDLER(ExtensionMsg_Loaded, OnLoaded) 493 IPC_MESSAGE_HANDLER(ExtensionMsg_Unloaded, OnUnloaded) 494 IPC_MESSAGE_HANDLER(ExtensionMsg_SetScriptingWhitelist, 495 OnSetScriptingWhitelist) 496 IPC_MESSAGE_HANDLER(ExtensionMsg_ActivateExtension, OnActivateExtension) 497 IPC_MESSAGE_HANDLER(ExtensionMsg_UpdatePermissions, OnUpdatePermissions) 498 IPC_MESSAGE_HANDLER(ExtensionMsg_UpdateTabSpecificPermissions, 499 OnUpdateTabSpecificPermissions) 500 IPC_MESSAGE_HANDLER(ExtensionMsg_ClearTabSpecificPermissions, 501 OnClearTabSpecificPermissions) 502 IPC_MESSAGE_HANDLER(ExtensionMsg_UpdateUserScripts, OnUpdateUserScripts) 503 IPC_MESSAGE_HANDLER(ExtensionMsg_UsingWebRequestAPI, OnUsingWebRequestAPI) 504 IPC_MESSAGE_HANDLER(ExtensionMsg_ShouldSuspend, OnShouldSuspend) 505 IPC_MESSAGE_HANDLER(ExtensionMsg_Suspend, OnSuspend) 506 IPC_MESSAGE_HANDLER(ExtensionMsg_CancelSuspend, OnCancelSuspend) 507 IPC_MESSAGE_FORWARD(ExtensionMsg_WatchPages, 508 content_watcher_.get(), ContentWatcher::OnWatchPages) 509 IPC_MESSAGE_UNHANDLED(handled = false) 510 IPC_END_MESSAGE_MAP() 511 512 return handled; 513 } 514 515 void Dispatcher::WebKitInitialized() { 516 // For extensions, we want to ensure we call the IdleHandler every so often, 517 // even if the extension keeps up activity. 518 if (is_extension_process_) { 519 forced_idle_timer_.Start(FROM_HERE, 520 base::TimeDelta::FromMilliseconds(kMaxExtensionIdleHandlerDelayMs), 521 RenderThread::Get(), &RenderThread::IdleHandler); 522 } 523 524 // Initialize host permissions for any extensions that were activated before 525 // WebKit was initialized. 526 for (std::set<std::string>::iterator iter = active_extension_ids_.begin(); 527 iter != active_extension_ids_.end(); ++iter) { 528 const Extension* extension = extensions_.GetByID(*iter); 529 CHECK(extension); 530 InitOriginPermissions(extension); 531 } 532 533 EnableCustomElementWhiteList(); 534 535 is_webkit_initialized_ = true; 536 } 537 538 void Dispatcher::IdleNotification() { 539 if (is_extension_process_) { 540 // Dampen the forced delay as well if the extension stays idle for long 541 // periods of time. 542 int64 forced_delay_ms = std::max( 543 RenderThread::Get()->GetIdleNotificationDelayInMs(), 544 kMaxExtensionIdleHandlerDelayMs); 545 forced_idle_timer_.Stop(); 546 forced_idle_timer_.Start(FROM_HERE, 547 base::TimeDelta::FromMilliseconds(forced_delay_ms), 548 RenderThread::Get(), &RenderThread::IdleHandler); 549 } 550 } 551 552 void Dispatcher::OnRenderProcessShutdown() { 553 v8_schema_registry_.reset(); 554 } 555 556 void Dispatcher::OnSetFunctionNames( 557 const std::vector<std::string>& names) { 558 function_names_.clear(); 559 for (size_t i = 0; i < names.size(); ++i) 560 function_names_.insert(names[i]); 561 } 562 563 void Dispatcher::OnSetSystemFont(const std::string& font_family, 564 const std::string& font_size) { 565 system_font_family_ = font_family; 566 system_font_size_ = font_size; 567 } 568 569 void Dispatcher::OnSetChannel(int channel) { 570 SetCurrentChannel(static_cast<chrome::VersionInfo::Channel>(channel)); 571 } 572 573 void Dispatcher::OnMessageInvoke(const std::string& extension_id, 574 const std::string& module_name, 575 const std::string& function_name, 576 const base::ListValue& args, 577 bool user_gesture) { 578 InvokeModuleSystemMethod( 579 NULL, extension_id, module_name, function_name, args, user_gesture); 580 } 581 582 void Dispatcher::OnDispatchOnConnect( 583 int target_port_id, 584 const std::string& channel_name, 585 const base::DictionaryValue& source_tab, 586 const ExtensionMsg_ExternalConnectionInfo& info, 587 const std::string& tls_channel_id) { 588 MessagingBindings::DispatchOnConnect( 589 v8_context_set_.GetAll(), 590 target_port_id, channel_name, source_tab, 591 info.source_id, info.target_id, info.source_url, 592 tls_channel_id, 593 NULL); // All render views. 594 } 595 596 void Dispatcher::OnDeliverMessage(int target_port_id, 597 const Message& message) { 598 MessagingBindings::DeliverMessage( 599 v8_context_set_.GetAll(), 600 target_port_id, 601 message, 602 NULL); // All render views. 603 } 604 605 void Dispatcher::OnDispatchOnDisconnect(int port_id, 606 const std::string& error_message) { 607 MessagingBindings::DispatchOnDisconnect( 608 v8_context_set_.GetAll(), 609 port_id, error_message, 610 NULL); // All render views. 611 } 612 613 void Dispatcher::OnLoaded( 614 const std::vector<ExtensionMsg_Loaded_Params>& loaded_extensions) { 615 std::vector<ExtensionMsg_Loaded_Params>::const_iterator i; 616 for (i = loaded_extensions.begin(); i != loaded_extensions.end(); ++i) { 617 std::string error; 618 scoped_refptr<const Extension> extension = i->ConvertToExtension(&error); 619 if (!extension.get()) { 620 extension_load_errors_[i->id] = error; 621 continue; 622 } 623 OnLoadedInternal(extension); 624 } 625 // Update the available bindings for all contexts. These may have changed if 626 // an externally_connectable extension was loaded that can connect to an 627 // open webpage. 628 AddOrRemoveBindings(""); 629 } 630 631 void Dispatcher::OnLoadedInternal(scoped_refptr<const Extension> extension) { 632 extensions_.Insert(extension); 633 } 634 635 void Dispatcher::OnUnloaded(const std::string& id) { 636 extensions_.Remove(id); 637 active_extension_ids_.erase(id); 638 639 // If the extension is later reloaded with a different set of permissions, 640 // we'd like it to get a new isolated world ID, so that it can pick up the 641 // changed origin whitelist. 642 user_script_slave_->RemoveIsolatedWorld(id); 643 644 // Invalidate all of the contexts that were removed. 645 // TODO(kalman): add an invalidation observer interface to ChromeV8Context. 646 ChromeV8ContextSet::ContextSet removed_contexts = 647 v8_context_set_.OnExtensionUnloaded(id); 648 for (ChromeV8ContextSet::ContextSet::iterator it = removed_contexts.begin(); 649 it != removed_contexts.end(); ++it) { 650 request_sender_->InvalidateSource(*it); 651 } 652 653 // Update the available bindings for the remaining contexts. These may have 654 // changed if an externally_connectable extension is unloaded and a webpage 655 // is no longer accessible. 656 AddOrRemoveBindings(""); 657 658 // Invalidates the messages map for the extension in case the extension is 659 // reloaded with a new messages map. 660 EraseL10nMessagesMap(id); 661 662 // We don't do anything with existing platform-app stylesheets. They will 663 // stay resident, but the URL pattern corresponding to the unloaded 664 // extension's URL just won't match anything anymore. 665 } 666 667 void Dispatcher::OnSetScriptingWhitelist( 668 const ExtensionsClient::ScriptingWhitelist& extension_ids) { 669 ExtensionsClient::Get()->SetScriptingWhitelist(extension_ids); 670 } 671 672 bool Dispatcher::IsExtensionActive( 673 const std::string& extension_id) const { 674 bool is_active = 675 active_extension_ids_.find(extension_id) != active_extension_ids_.end(); 676 if (is_active) 677 CHECK(extensions_.Contains(extension_id)); 678 return is_active; 679 } 680 681 v8::Handle<v8::Object> Dispatcher::GetOrCreateObject( 682 v8::Handle<v8::Object> object, 683 const std::string& field, 684 v8::Isolate* isolate) { 685 v8::Handle<v8::String> key = v8::String::NewFromUtf8(isolate, field.c_str()); 686 // If the object has a callback property, it is assumed it is an unavailable 687 // API, so it is safe to delete. This is checked before GetOrCreateObject is 688 // called. 689 if (object->HasRealNamedCallbackProperty(key)) { 690 object->Delete(key); 691 } else if (object->HasRealNamedProperty(key)) { 692 v8::Handle<v8::Value> value = object->Get(key); 693 CHECK(value->IsObject()); 694 return v8::Handle<v8::Object>::Cast(value); 695 } 696 697 v8::Handle<v8::Object> new_object = v8::Object::New(); 698 object->Set(key, new_object); 699 return new_object; 700 } 701 702 void Dispatcher::AddOrRemoveBindingsForContext(ChromeV8Context* context) { 703 v8::HandleScope handle_scope(context->isolate()); 704 v8::Context::Scope context_scope(context->v8_context()); 705 706 // TODO(kalman): Make the bindings registration have zero overhead then run 707 // the same code regardless of context type. 708 switch (context->context_type()) { 709 case Feature::UNSPECIFIED_CONTEXT: 710 case Feature::WEB_PAGE_CONTEXT: 711 case Feature::BLESSED_WEB_PAGE_CONTEXT: { 712 // Web page context; it's too expensive to run the full bindings code. 713 // Hard-code that the app and webstore APIs are available... 714 RegisterBinding("app", context); 715 RegisterBinding("webstore", context); 716 717 // ... and that the runtime API might be available if any extension can 718 // connect to it. 719 bool runtime_is_available = false; 720 for (ExtensionSet::const_iterator it = extensions_.begin(); 721 it != extensions_.end(); ++it) { 722 ExternallyConnectableInfo* info = 723 static_cast<ExternallyConnectableInfo*>((*it)->GetManifestData( 724 manifest_keys::kExternallyConnectable)); 725 if (info && info->matches.MatchesURL(context->GetURL())) { 726 runtime_is_available = true; 727 break; 728 } 729 } 730 if (runtime_is_available) 731 RegisterBinding("runtime", context); 732 break; 733 } 734 735 case Feature::BLESSED_EXTENSION_CONTEXT: 736 case Feature::UNBLESSED_EXTENSION_CONTEXT: 737 case Feature::CONTENT_SCRIPT_CONTEXT: { 738 // Extension context; iterate through all the APIs and bind the available 739 // ones. 740 FeatureProvider* api_feature_provider = FeatureProvider::GetAPIFeatures(); 741 const std::vector<std::string>& apis = 742 api_feature_provider->GetAllFeatureNames(); 743 for (std::vector<std::string>::const_iterator it = apis.begin(); 744 it != apis.end(); ++it) { 745 const std::string& api_name = *it; 746 Feature* feature = api_feature_provider->GetFeature(api_name); 747 DCHECK(feature); 748 749 // Internal APIs are included via require(api_name) from internal code 750 // rather than chrome[api_name]. 751 if (feature->IsInternal()) 752 continue; 753 754 // If this API name has parent features, then this must be a function or 755 // event, so we should not register. 756 bool parent_feature_available = false; 757 for (Feature* parent = api_feature_provider->GetParent(feature); 758 parent != NULL; parent = api_feature_provider->GetParent(parent)) { 759 if (context->IsAnyFeatureAvailableToContext(parent->name())) { 760 parent_feature_available = true; 761 break; 762 } 763 } 764 if (parent_feature_available) 765 continue; 766 767 if (context->IsAnyFeatureAvailableToContext(api_name)) 768 RegisterBinding(api_name, context); 769 } 770 break; 771 } 772 } 773 } 774 775 v8::Handle<v8::Object> Dispatcher::GetOrCreateBindObjectIfAvailable( 776 const std::string& api_name, 777 std::string* bind_name, 778 ChromeV8Context* context) { 779 std::vector<std::string> split; 780 base::SplitString(api_name, '.', &split); 781 782 v8::Handle<v8::Object> bind_object; 783 784 // Check if this API has an ancestor. If the API's ancestor is available and 785 // the API is not available, don't install the bindings for this API. If 786 // the API is available and its ancestor is not, delete the ancestor and 787 // install the bindings for the API. This is to prevent loading the ancestor 788 // API schema if it will not be needed. 789 // 790 // For example: 791 // If app is available and app.window is not, just install app. 792 // If app.window is available and app is not, delete app and install 793 // app.window on a new object so app does not have to be loaded. 794 FeatureProvider* api_feature_provider = FeatureProvider::GetAPIFeatures(); 795 std::string ancestor_name; 796 bool only_ancestor_available = false; 797 798 for (size_t i = 0; i < split.size() - 1; ++i) { 799 ancestor_name += (i ? ".": "") + split[i]; 800 if (api_feature_provider->GetFeature(ancestor_name) && 801 context->GetAvailability(ancestor_name).is_available() && 802 !context->GetAvailability(api_name).is_available()) { 803 only_ancestor_available = true; 804 break; 805 } 806 807 if (bind_object.IsEmpty()) { 808 bind_object = AsObjectOrEmpty(GetOrCreateChrome(context)); 809 if (bind_object.IsEmpty()) 810 return v8::Handle<v8::Object>(); 811 } 812 bind_object = GetOrCreateObject(bind_object, split[i], context->isolate()); 813 } 814 815 if (only_ancestor_available) 816 return v8::Handle<v8::Object>(); 817 818 if (bind_name) 819 *bind_name = split.back(); 820 821 return bind_object.IsEmpty() ? 822 AsObjectOrEmpty(GetOrCreateChrome(context)) : bind_object; 823 } 824 825 void Dispatcher::RegisterBinding(const std::string& api_name, 826 ChromeV8Context* context) { 827 std::string bind_name; 828 v8::Handle<v8::Object> bind_object = 829 GetOrCreateBindObjectIfAvailable(api_name, &bind_name, context); 830 831 // Empty if the bind object failed to be created, probably because the 832 // extension overrode chrome with a non-object, e.g. window.chrome = true. 833 if (bind_object.IsEmpty()) 834 return; 835 836 v8::Local<v8::String> v8_api_name = 837 v8::String::NewFromUtf8(context->isolate(), api_name.c_str()); 838 if (bind_object->HasRealNamedProperty(v8_api_name)) { 839 // The bind object may already have the property if the API has been 840 // registered before (or if the extension has put something there already, 841 // but, whatevs). 842 // 843 // In the former case, we need to re-register the bindings for the APIs 844 // which the extension now has permissions for (if any), but not touch any 845 // others so that we don't destroy state such as event listeners. 846 // 847 // TODO(kalman): Only register available APIs to make this all moot. 848 if (bind_object->HasRealNamedCallbackProperty(v8_api_name)) 849 return; // lazy binding still there, nothing to do 850 if (bind_object->Get(v8_api_name)->IsObject()) 851 return; // binding has already been fully installed 852 } 853 854 ModuleSystem* module_system = context->module_system(); 855 if (lazy_bindings_map_.find(api_name) != lazy_bindings_map_.end()) { 856 InstallBindings(module_system, context->v8_context(), api_name); 857 } else if (!source_map_.Contains(api_name)) { 858 module_system->RegisterNativeHandler( 859 api_name, 860 scoped_ptr<NativeHandler>(new BindingGeneratingNativeHandler( 861 module_system, 862 api_name, 863 "binding"))); 864 module_system->SetNativeLazyField(bind_object, 865 bind_name, 866 api_name, 867 "binding"); 868 } else { 869 module_system->SetLazyField(bind_object, 870 bind_name, 871 api_name, 872 "binding"); 873 } 874 } 875 876 // NOTE: please use the naming convention "foo_natives" for these. 877 void Dispatcher::RegisterNativeHandlers(ModuleSystem* module_system, 878 ChromeV8Context* context) { 879 module_system->RegisterNativeHandler("event_natives", 880 scoped_ptr<NativeHandler>(EventBindings::Create(this, context))); 881 module_system->RegisterNativeHandler("messaging_natives", 882 scoped_ptr<NativeHandler>(MessagingBindings::Get(this, context))); 883 module_system->RegisterNativeHandler("apiDefinitions", 884 scoped_ptr<NativeHandler>(new ApiDefinitionsNatives(this, context))); 885 module_system->RegisterNativeHandler("sendRequest", 886 scoped_ptr<NativeHandler>( 887 new SendRequestNatives(this, request_sender_.get(), context))); 888 module_system->RegisterNativeHandler("setIcon", 889 scoped_ptr<NativeHandler>( 890 new SetIconNatives(this, request_sender_.get(), context))); 891 module_system->RegisterNativeHandler("activityLogger", 892 scoped_ptr<NativeHandler>(new APIActivityLogger(this, context))); 893 module_system->RegisterNativeHandler("renderViewObserverNatives", 894 scoped_ptr<NativeHandler>(new RenderViewObserverNatives(this, context))); 895 896 // Natives used by multiple APIs. 897 module_system->RegisterNativeHandler("file_system_natives", 898 scoped_ptr<NativeHandler>(new FileSystemNatives(context))); 899 900 // Custom bindings. 901 module_system->RegisterNativeHandler("app", 902 scoped_ptr<NativeHandler>(new AppBindings(this, context))); 903 module_system->RegisterNativeHandler("app_runtime", 904 scoped_ptr<NativeHandler>( 905 new AppRuntimeCustomBindings(this, context))); 906 module_system->RegisterNativeHandler("app_window_natives", 907 scoped_ptr<NativeHandler>( 908 new AppWindowCustomBindings(this, context))); 909 module_system->RegisterNativeHandler("blob_natives", 910 scoped_ptr<NativeHandler>(new BlobNativeHandler(context))); 911 module_system->RegisterNativeHandler("context_menus", 912 scoped_ptr<NativeHandler>( 913 new ContextMenusCustomBindings(this, context))); 914 module_system->RegisterNativeHandler( 915 "css_natives", scoped_ptr<NativeHandler>(new CssNativeHandler(context))); 916 module_system->RegisterNativeHandler("document_natives", 917 scoped_ptr<NativeHandler>( 918 new DocumentCustomBindings(this, context))); 919 module_system->RegisterNativeHandler("sync_file_system", 920 scoped_ptr<NativeHandler>( 921 new SyncFileSystemCustomBindings(this, context))); 922 module_system->RegisterNativeHandler("file_browser_handler", 923 scoped_ptr<NativeHandler>(new FileBrowserHandlerCustomBindings( 924 this, context))); 925 module_system->RegisterNativeHandler("file_browser_private", 926 scoped_ptr<NativeHandler>(new FileBrowserPrivateCustomBindings( 927 this, context))); 928 module_system->RegisterNativeHandler("i18n", 929 scoped_ptr<NativeHandler>( 930 new I18NCustomBindings(this, context))); 931 module_system->RegisterNativeHandler( 932 "id_generator", 933 scoped_ptr<NativeHandler>(new IdGeneratorCustomBindings(this, context))); 934 module_system->RegisterNativeHandler("mediaGalleries", 935 scoped_ptr<NativeHandler>( 936 new MediaGalleriesCustomBindings(this, context))); 937 module_system->RegisterNativeHandler("page_actions", 938 scoped_ptr<NativeHandler>( 939 new PageActionsCustomBindings(this, context))); 940 module_system->RegisterNativeHandler("page_capture", 941 scoped_ptr<NativeHandler>( 942 new PageCaptureCustomBindings(this, context))); 943 module_system->RegisterNativeHandler( 944 "pepper_request_natives", 945 scoped_ptr<NativeHandler>(new PepperRequestNatives(context))); 946 module_system->RegisterNativeHandler("runtime", 947 scoped_ptr<NativeHandler>(new RuntimeCustomBindings(this, context))); 948 module_system->RegisterNativeHandler("tabs", 949 scoped_ptr<NativeHandler>(new TabsCustomBindings(this, context))); 950 module_system->RegisterNativeHandler("webstore", 951 scoped_ptr<NativeHandler>(new WebstoreBindings(this, context))); 952 #if defined(ENABLE_WEBRTC) 953 module_system->RegisterNativeHandler("cast_streaming_natives", 954 scoped_ptr<NativeHandler>(new CastStreamingNativeHandler(context))); 955 #endif 956 } 957 958 void Dispatcher::PopulateSourceMap() { 959 // Libraries. 960 source_map_.RegisterSource("entryIdManager", IDR_ENTRY_ID_MANAGER); 961 source_map_.RegisterSource(kEventBindings, IDR_EVENT_BINDINGS_JS); 962 source_map_.RegisterSource("imageUtil", IDR_IMAGE_UTIL_JS); 963 source_map_.RegisterSource("json_schema", IDR_JSON_SCHEMA_JS); 964 source_map_.RegisterSource("lastError", IDR_LAST_ERROR_JS); 965 source_map_.RegisterSource("messaging", IDR_MESSAGING_JS); 966 source_map_.RegisterSource("messaging_utils", IDR_MESSAGING_UTILS_JS); 967 source_map_.RegisterSource("pepper_request", IDR_PEPPER_REQUEST_JS); 968 source_map_.RegisterSource(kSchemaUtils, IDR_SCHEMA_UTILS_JS); 969 source_map_.RegisterSource("sendRequest", IDR_SEND_REQUEST_JS); 970 source_map_.RegisterSource("setIcon", IDR_SET_ICON_JS); 971 source_map_.RegisterSource("test", IDR_TEST_CUSTOM_BINDINGS_JS); 972 source_map_.RegisterSource("unload_event", IDR_UNLOAD_EVENT_JS); 973 source_map_.RegisterSource("utils", IDR_UTILS_JS); 974 975 // Custom bindings. 976 source_map_.RegisterSource("app", IDR_APP_CUSTOM_BINDINGS_JS); 977 source_map_.RegisterSource("app.runtime", IDR_APP_RUNTIME_CUSTOM_BINDINGS_JS); 978 source_map_.RegisterSource("app.window", IDR_APP_WINDOW_CUSTOM_BINDINGS_JS); 979 source_map_.RegisterSource("bluetooth", IDR_BLUETOOTH_CUSTOM_BINDINGS_JS); 980 source_map_.RegisterSource("browserAction", 981 IDR_BROWSER_ACTION_CUSTOM_BINDINGS_JS); 982 source_map_.RegisterSource("contextMenus", 983 IDR_CONTEXT_MENUS_CUSTOM_BINDINGS_JS); 984 source_map_.RegisterSource("declarativeContent", 985 IDR_DECLARATIVE_CONTENT_CUSTOM_BINDINGS_JS); 986 source_map_.RegisterSource("declarativeWebRequest", 987 IDR_DECLARATIVE_WEBREQUEST_CUSTOM_BINDINGS_JS); 988 source_map_.RegisterSource("desktopCapture", 989 IDR_DESKTOP_CAPTURE_CUSTOM_BINDINGS_JS); 990 source_map_.RegisterSource("downloads", 991 IDR_DOWNLOADS_CUSTOM_BINDINGS_JS); 992 source_map_.RegisterSource("experimental.offscreen", 993 IDR_EXPERIMENTAL_OFFSCREENTABS_CUSTOM_BINDINGS_JS); 994 source_map_.RegisterSource("extension", IDR_EXTENSION_CUSTOM_BINDINGS_JS); 995 source_map_.RegisterSource("feedbackPrivate", 996 IDR_FEEDBACK_PRIVATE_CUSTOM_BINDINGS_JS); 997 source_map_.RegisterSource("fileBrowserHandler", 998 IDR_FILE_BROWSER_HANDLER_CUSTOM_BINDINGS_JS); 999 source_map_.RegisterSource("fileBrowserPrivate", 1000 IDR_FILE_BROWSER_PRIVATE_CUSTOM_BINDINGS_JS); 1001 source_map_.RegisterSource("fileSystem", 1002 IDR_FILE_SYSTEM_CUSTOM_BINDINGS_JS); 1003 source_map_.RegisterSource("fileSystemProvider", 1004 IDR_FILE_SYSTEM_PROVIDER_CUSTOM_BINDINGS_JS); 1005 source_map_.RegisterSource("gcm", 1006 IDR_GCM_CUSTOM_BINDINGS_JS); 1007 source_map_.RegisterSource("i18n", IDR_I18N_CUSTOM_BINDINGS_JS); 1008 source_map_.RegisterSource("identity", IDR_IDENTITY_CUSTOM_BINDINGS_JS); 1009 source_map_.RegisterSource("imageWriterPrivate", 1010 IDR_IMAGE_WRITER_PRIVATE_CUSTOM_BINDINGS_JS); 1011 source_map_.RegisterSource("input.ime", IDR_INPUT_IME_CUSTOM_BINDINGS_JS); 1012 source_map_.RegisterSource("mediaGalleries", 1013 IDR_MEDIA_GALLERIES_CUSTOM_BINDINGS_JS); 1014 source_map_.RegisterSource("notifications", 1015 IDR_NOTIFICATIONS_CUSTOM_BINDINGS_JS); 1016 source_map_.RegisterSource("omnibox", IDR_OMNIBOX_CUSTOM_BINDINGS_JS); 1017 source_map_.RegisterSource("pageActions", 1018 IDR_PAGE_ACTIONS_CUSTOM_BINDINGS_JS); 1019 source_map_.RegisterSource("pageAction", IDR_PAGE_ACTION_CUSTOM_BINDINGS_JS); 1020 source_map_.RegisterSource("pageCapture", 1021 IDR_PAGE_CAPTURE_CUSTOM_BINDINGS_JS); 1022 source_map_.RegisterSource("permissions", IDR_PERMISSIONS_CUSTOM_BINDINGS_JS); 1023 source_map_.RegisterSource("runtime", IDR_RUNTIME_CUSTOM_BINDINGS_JS); 1024 source_map_.RegisterSource("syncFileSystem", 1025 IDR_SYNC_FILE_SYSTEM_CUSTOM_BINDINGS_JS); 1026 source_map_.RegisterSource("systemIndicator", 1027 IDR_SYSTEM_INDICATOR_CUSTOM_BINDINGS_JS); 1028 source_map_.RegisterSource("tabCapture", IDR_TAB_CAPTURE_CUSTOM_BINDINGS_JS); 1029 source_map_.RegisterSource("tabs", IDR_TABS_CUSTOM_BINDINGS_JS); 1030 source_map_.RegisterSource("tts", IDR_TTS_CUSTOM_BINDINGS_JS); 1031 source_map_.RegisterSource("ttsEngine", IDR_TTS_ENGINE_CUSTOM_BINDINGS_JS); 1032 source_map_.RegisterSource("webRequest", IDR_WEB_REQUEST_CUSTOM_BINDINGS_JS); 1033 source_map_.RegisterSource("webRequestInternal", 1034 IDR_WEB_REQUEST_INTERNAL_CUSTOM_BINDINGS_JS); 1035 #if defined(ENABLE_WEBRTC) 1036 source_map_.RegisterSource("cast.streaming.rtpStream", 1037 IDR_CAST_STREAMING_RTP_STREAM_CUSTOM_BINDINGS_JS); 1038 source_map_.RegisterSource("cast.streaming.session", 1039 IDR_CAST_STREAMING_SESSION_CUSTOM_BINDINGS_JS); 1040 source_map_.RegisterSource( 1041 "cast.streaming.udpTransport", 1042 IDR_CAST_STREAMING_UDP_TRANSPORT_CUSTOM_BINDINGS_JS); 1043 #endif 1044 source_map_.RegisterSource("webstore", IDR_WEBSTORE_CUSTOM_BINDINGS_JS); 1045 source_map_.RegisterSource("windowControls", IDR_WINDOW_CONTROLS_JS); 1046 source_map_.RegisterSource("binding", IDR_BINDING_JS); 1047 1048 // Custom types sources. 1049 source_map_.RegisterSource("ChromeSetting", IDR_CHROME_SETTING_JS); 1050 source_map_.RegisterSource("StorageArea", IDR_STORAGE_AREA_JS); 1051 source_map_.RegisterSource("ContentSetting", IDR_CONTENT_SETTING_JS); 1052 source_map_.RegisterSource("ChromeDirectSetting", 1053 IDR_CHROME_DIRECT_SETTING_JS); 1054 1055 // Platform app sources that are not API-specific.. 1056 source_map_.RegisterSource("tagWatcher", IDR_TAG_WATCHER_JS); 1057 // Note: webView not webview so that this doesn't interfere with the 1058 // chrome.webview API bindings. 1059 source_map_.RegisterSource("webView", IDR_WEB_VIEW_JS); 1060 source_map_.RegisterSource("webViewExperimental", 1061 IDR_WEB_VIEW_EXPERIMENTAL_JS); 1062 source_map_.RegisterSource("webViewRequest", 1063 IDR_WEB_VIEW_REQUEST_CUSTOM_BINDINGS_JS); 1064 source_map_.RegisterSource("denyWebView", IDR_WEB_VIEW_DENY_JS); 1065 source_map_.RegisterSource("adView", IDR_AD_VIEW_JS); 1066 source_map_.RegisterSource("denyAdView", IDR_AD_VIEW_DENY_JS); 1067 source_map_.RegisterSource("platformApp", IDR_PLATFORM_APP_JS); 1068 source_map_.RegisterSource("injectAppTitlebar", IDR_INJECT_APP_TITLEBAR_JS); 1069 } 1070 1071 void Dispatcher::PopulateLazyBindingsMap() { 1072 lazy_bindings_map_["app"] = InstallAppBindings; 1073 lazy_bindings_map_["webstore"] = InstallWebstoreBindings; 1074 } 1075 1076 void Dispatcher::InstallBindings(ModuleSystem* module_system, 1077 v8::Handle<v8::Context> v8_context, 1078 const std::string& api) { 1079 std::map<std::string, BindingInstaller>::const_iterator lazy_binding = 1080 lazy_bindings_map_.find(api); 1081 if (lazy_binding != lazy_bindings_map_.end()) { 1082 v8::Handle<v8::Object> global(v8_context->Global()); 1083 v8::Handle<v8::Object> chrome = 1084 global->Get(v8::String::NewFromUtf8(v8_context->GetIsolate(), "chrome")) 1085 ->ToObject(); 1086 (*lazy_binding->second)(module_system, chrome); 1087 } else { 1088 module_system->Require(api); 1089 } 1090 } 1091 1092 void Dispatcher::DidCreateScriptContext( 1093 WebFrame* frame, v8::Handle<v8::Context> v8_context, int extension_group, 1094 int world_id) { 1095 #if !defined(ENABLE_EXTENSIONS) 1096 return; 1097 #endif 1098 1099 std::string extension_id = GetExtensionID(frame, world_id); 1100 1101 const Extension* extension = extensions_.GetByID(extension_id); 1102 if (!extension && !extension_id.empty()) { 1103 // There are conditions where despite a context being associated with an 1104 // extension, no extension actually gets found. Ignore "invalid" because 1105 // CSP blocks extension page loading by switching the extension ID to 1106 // "invalid". This isn't interesting. 1107 if (extension_id != "invalid") { 1108 LOG(ERROR) << "Extension \"" << extension_id << "\" not found"; 1109 RenderThread::Get()->RecordAction( 1110 UserMetricsAction("ExtensionNotFound_ED")); 1111 } 1112 1113 extension_id = ""; 1114 } 1115 1116 Feature::Context context_type = ClassifyJavaScriptContext( 1117 extension, 1118 extension_group, 1119 UserScriptSlave::GetDataSourceURLForFrame(frame), 1120 frame->document().securityOrigin()); 1121 1122 ChromeV8Context* context = 1123 new ChromeV8Context(v8_context, frame, extension, context_type); 1124 v8_context_set_.Add(context); 1125 1126 { 1127 scoped_ptr<ModuleSystem> module_system(new ModuleSystem(context, 1128 &source_map_)); 1129 context->set_module_system(module_system.Pass()); 1130 } 1131 ModuleSystem* module_system = context->module_system(); 1132 1133 // Enable natives in startup. 1134 ModuleSystem::NativesEnabledScope natives_enabled_scope( 1135 module_system); 1136 1137 RegisterNativeHandlers(module_system, context); 1138 1139 module_system->RegisterNativeHandler("chrome", 1140 scoped_ptr<NativeHandler>(new ChromeNativeHandler(context))); 1141 module_system->RegisterNativeHandler("print", 1142 scoped_ptr<NativeHandler>(new PrintNativeHandler(context))); 1143 module_system->RegisterNativeHandler("lazy_background_page", 1144 scoped_ptr<NativeHandler>( 1145 new LazyBackgroundPageNativeHandler(this, context))); 1146 module_system->RegisterNativeHandler("logging", 1147 scoped_ptr<NativeHandler>(new LoggingNativeHandler(context))); 1148 module_system->RegisterNativeHandler("schema_registry", 1149 v8_schema_registry_->AsNativeHandler()); 1150 module_system->RegisterNativeHandler("v8_context", 1151 scoped_ptr<NativeHandler>(new V8ContextNativeHandler(context, this))); 1152 module_system->RegisterNativeHandler("test_features", 1153 scoped_ptr<NativeHandler>(new TestFeaturesNativeHandler(context))); 1154 module_system->RegisterNativeHandler("user_gestures", 1155 scoped_ptr<NativeHandler>(new UserGesturesNativeHandler(context))); 1156 1157 int manifest_version = extension ? extension->manifest_version() : 1; 1158 bool send_request_disabled = 1159 (extension && Manifest::IsUnpackedLocation(extension->location()) && 1160 BackgroundInfo::HasLazyBackgroundPage(extension)); 1161 module_system->RegisterNativeHandler("process", 1162 scoped_ptr<NativeHandler>(new ProcessInfoNativeHandler( 1163 this, context, context->GetExtensionID(), 1164 context->GetContextTypeDescription(), 1165 ChromeRenderProcessObserver::is_incognito_process(), 1166 manifest_version, send_request_disabled))); 1167 1168 // chrome.Event is part of the public API (although undocumented). Make it 1169 // lazily evalulate to Event from event_bindings.js. For extensions only 1170 // though, not all webpages! 1171 if (context->extension()) { 1172 v8::Handle<v8::Object> chrome = AsObjectOrEmpty(GetOrCreateChrome(context)); 1173 if (!chrome.IsEmpty()) 1174 module_system->SetLazyField(chrome, "Event", kEventBindings, "Event"); 1175 } 1176 1177 AddOrRemoveBindingsForContext(context); 1178 1179 bool is_within_platform_app = IsWithinPlatformApp(); 1180 // Inject custom JS into the platform app context. 1181 if (is_within_platform_app) { 1182 module_system->Require("platformApp"); 1183 } 1184 1185 if (context_type == Feature::BLESSED_EXTENSION_CONTEXT && 1186 is_within_platform_app && 1187 GetCurrentChannel() <= chrome::VersionInfo::CHANNEL_DEV && 1188 CommandLine::ForCurrentProcess()->HasSwitch( 1189 switches::kEnableAppWindowControls)) { 1190 module_system->Require("windowControls"); 1191 } 1192 1193 // Currently only platform apps and whitelisted component extensions support 1194 // the <webview> tag, because the "denyWebView" module will affect the 1195 // performance of DOM modifications (http://crbug.com/196453). 1196 // We used to limit WebView to |BLESSED_EXTENSION_CONTEXT| within platform 1197 // apps. An ext/app runs in a blessed extension context, if it is the active 1198 // extension in the current process, in other words, if it is loaded in a top 1199 // frame. To support webview in a non-frame extension, we have to allow 1200 // unblessed extension context as well. 1201 if (context_type == Feature::BLESSED_EXTENSION_CONTEXT || 1202 context_type == Feature::UNBLESSED_EXTENSION_CONTEXT) { 1203 // Note: setting up the WebView class here, not the chrome.webview API. 1204 // The API will be automatically set up when first used. 1205 if (extension->HasAPIPermission(APIPermission::kWebView)) { 1206 module_system->Require("webView"); 1207 bool includeExperimental = 1208 GetCurrentChannel() <= chrome::VersionInfo::CHANNEL_DEV; 1209 if (!includeExperimental) { 1210 // TODO(asargent) We need a whitelist for webview experimental. 1211 // crbug.com/264852 1212 std::string id_hash = base::SHA1HashString(extension->id()); 1213 std::string hexencoded_id_hash = base::HexEncode(id_hash.c_str(), 1214 id_hash.length()); 1215 if (hexencoded_id_hash == "8C3741E3AF0B93B6E8E0DDD499BB0B74839EA578" || 1216 hexencoded_id_hash == "E703483CEF33DEC18B4B6DD84B5C776FB9182BDB" || 1217 hexencoded_id_hash == "1A26E32DE447A17CBE5E9750CDBA78F58539B39C" || 1218 hexencoded_id_hash == "59048028102D7B4C681DBC7BC6CD980C3DC66DA3") 1219 includeExperimental = true; 1220 } 1221 if (includeExperimental) 1222 module_system->Require("webViewExperimental"); 1223 } else { 1224 module_system->Require("denyWebView"); 1225 } 1226 } 1227 1228 // Same comment as above for <adview> tag. 1229 if (context_type == Feature::BLESSED_EXTENSION_CONTEXT && 1230 is_within_platform_app) { 1231 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnableAdview)) { 1232 if (extension->HasAPIPermission(APIPermission::kAdView)) { 1233 module_system->Require("adView"); 1234 } else { 1235 module_system->Require("denyAdView"); 1236 } 1237 } 1238 } 1239 1240 VLOG(1) << "Num tracked contexts: " << v8_context_set_.size(); 1241 } 1242 1243 std::string Dispatcher::GetExtensionID(const WebFrame* frame, int world_id) { 1244 if (world_id != 0) { 1245 // Isolated worlds (content script). 1246 return user_script_slave_->GetExtensionIdForIsolatedWorld(world_id); 1247 } 1248 1249 // TODO(kalman): Delete this check. 1250 if (frame->document().securityOrigin().isUnique()) 1251 return std::string(); 1252 1253 // Extension pages (chrome-extension:// URLs). 1254 GURL frame_url = UserScriptSlave::GetDataSourceURLForFrame(frame); 1255 return extensions_.GetExtensionOrAppIDByURL(frame_url); 1256 } 1257 1258 bool Dispatcher::IsWithinPlatformApp() { 1259 for (std::set<std::string>::iterator iter = active_extension_ids_.begin(); 1260 iter != active_extension_ids_.end(); ++iter) { 1261 const Extension* extension = extensions_.GetByID(*iter); 1262 if (extension && extension->is_platform_app()) 1263 return true; 1264 } 1265 return false; 1266 } 1267 1268 void Dispatcher::WillReleaseScriptContext( 1269 WebFrame* frame, v8::Handle<v8::Context> v8_context, int world_id) { 1270 ChromeV8Context* context = v8_context_set_.GetByV8Context(v8_context); 1271 if (!context) 1272 return; 1273 1274 // If the V8 context has an OOM exception, javascript execution has been 1275 // stopped, so dispatching an onUnload event is pointless. 1276 if (!v8_context->HasOutOfMemoryException()) 1277 context->DispatchOnUnloadEvent(); 1278 // TODO(kalman): add an invalidation observer interface to ChromeV8Context. 1279 request_sender_->InvalidateSource(context); 1280 1281 v8_context_set_.Remove(context); 1282 VLOG(1) << "Num tracked contexts: " << v8_context_set_.size(); 1283 } 1284 1285 void Dispatcher::DidCreateDocumentElement(blink::WebFrame* frame) { 1286 if (IsWithinPlatformApp()) { 1287 // WebKit doesn't let us define an additional user agent stylesheet, so we 1288 // insert the default platform app stylesheet into all documents that are 1289 // loaded in each app. 1290 std::string stylesheet = 1291 ResourceBundle::GetSharedInstance(). 1292 GetRawDataResource(IDR_PLATFORM_APP_CSS).as_string(); 1293 ReplaceFirstSubstringAfterOffset(&stylesheet, 0, 1294 "$FONTFAMILY", system_font_family_); 1295 ReplaceFirstSubstringAfterOffset(&stylesheet, 0, 1296 "$FONTSIZE", system_font_size_); 1297 frame->document().insertUserStyleSheet( 1298 WebString::fromUTF8(stylesheet), WebDocument::UserStyleAuthorLevel); 1299 } 1300 1301 content_watcher_->DidCreateDocumentElement(frame); 1302 } 1303 1304 void Dispatcher::DidMatchCSS( 1305 blink::WebFrame* frame, 1306 const blink::WebVector<blink::WebString>& newly_matching_selectors, 1307 const blink::WebVector<blink::WebString>& stopped_matching_selectors) { 1308 content_watcher_->DidMatchCSS( 1309 frame, newly_matching_selectors, stopped_matching_selectors); 1310 } 1311 1312 1313 void Dispatcher::OnActivateExtension(const std::string& extension_id) { 1314 const Extension* extension = extensions_.GetByID(extension_id); 1315 if (!extension) { 1316 // Extension was activated but was never loaded. This probably means that 1317 // the renderer failed to load it (or the browser failed to tell us when it 1318 // did). Failures shouldn't happen, but instead of crashing there (which 1319 // executes on all renderers) be conservative and only crash in the renderer 1320 // of the extension which failed to load; this one. 1321 std::string& error = extension_load_errors_[extension_id]; 1322 char minidump[256]; 1323 base::debug::Alias(&minidump); 1324 base::snprintf(minidump, arraysize(minidump), 1325 "e::dispatcher:%s:%s", extension_id.c_str(), error.c_str()); 1326 CHECK(extension) << extension_id << " was never loaded: " << error; 1327 } 1328 1329 active_extension_ids_.insert(extension_id); 1330 1331 // This is called when starting a new extension page, so start the idle 1332 // handler ticking. 1333 RenderThread::Get()->ScheduleIdleHandler(kInitialExtensionIdleHandlerDelayMs); 1334 1335 UpdateActiveExtensions(); 1336 1337 if (is_webkit_initialized_) { 1338 InitOriginPermissions(extension); 1339 DOMActivityLogger::AttachToWorld(DOMActivityLogger::kMainWorldId, 1340 extension_id); 1341 } 1342 } 1343 1344 void Dispatcher::InitOriginPermissions(const Extension* extension) { 1345 // TODO(jstritar): We should try to remove this special case. Also, these 1346 // whitelist entries need to be updated when the kManagement permission 1347 // changes. 1348 if (extension->HasAPIPermission(APIPermission::kManagement)) { 1349 WebSecurityPolicy::addOriginAccessWhitelistEntry( 1350 extension->url(), 1351 WebString::fromUTF8(chrome::kChromeUIScheme), 1352 WebString::fromUTF8(chrome::kChromeUIExtensionIconHost), 1353 false); 1354 } 1355 1356 AddOrRemoveOriginPermissions( 1357 UpdatedExtensionPermissionsInfo::ADDED, 1358 extension, 1359 extension->GetActivePermissions()->explicit_hosts()); 1360 } 1361 1362 void Dispatcher::AddOrRemoveOriginPermissions( 1363 UpdatedExtensionPermissionsInfo::Reason reason, 1364 const Extension* extension, 1365 const URLPatternSet& origins) { 1366 for (URLPatternSet::const_iterator i = origins.begin(); 1367 i != origins.end(); ++i) { 1368 const char* schemes[] = { 1369 content::kHttpScheme, 1370 content::kHttpsScheme, 1371 chrome::kFileScheme, 1372 chrome::kChromeUIScheme, 1373 }; 1374 for (size_t j = 0; j < arraysize(schemes); ++j) { 1375 if (i->MatchesScheme(schemes[j])) { 1376 ((reason == UpdatedExtensionPermissionsInfo::REMOVED) ? 1377 WebSecurityPolicy::removeOriginAccessWhitelistEntry : 1378 WebSecurityPolicy::addOriginAccessWhitelistEntry)( 1379 extension->url(), 1380 WebString::fromUTF8(schemes[j]), 1381 WebString::fromUTF8(i->host()), 1382 i->match_subdomains()); 1383 } 1384 } 1385 } 1386 } 1387 1388 void Dispatcher::EnableCustomElementWhiteList() { 1389 blink::WebRuntimeFeatures::enableEmbedderCustomElements(true); 1390 blink::WebCustomElement::addEmbedderCustomElementName("webview"); 1391 // TODO(fsamuel): Add <adview> to the whitelist once it has been converted 1392 // into a custom element. 1393 blink::WebCustomElement::addEmbedderCustomElementName("browser-plugin"); 1394 } 1395 1396 void Dispatcher::AddOrRemoveBindings(const std::string& extension_id) { 1397 v8_context_set().ForEach( 1398 extension_id, 1399 NULL, // all render views 1400 base::Bind(&Dispatcher::AddOrRemoveBindingsForContext, 1401 base::Unretained(this))); 1402 } 1403 1404 void Dispatcher::OnUpdatePermissions( 1405 const ExtensionMsg_UpdatePermissions_Params& params) { 1406 int reason_id = params.reason_id; 1407 const std::string& extension_id = params.extension_id; 1408 const APIPermissionSet& apis = params.apis; 1409 const ManifestPermissionSet& manifest_permissions = 1410 params.manifest_permissions; 1411 const URLPatternSet& explicit_hosts = params.explicit_hosts; 1412 const URLPatternSet& scriptable_hosts = params.scriptable_hosts; 1413 1414 const Extension* extension = extensions_.GetByID(extension_id); 1415 if (!extension) 1416 return; 1417 1418 scoped_refptr<const PermissionSet> delta = 1419 new PermissionSet(apis, manifest_permissions, 1420 explicit_hosts, scriptable_hosts); 1421 scoped_refptr<const PermissionSet> old_active = 1422 extension->GetActivePermissions(); 1423 UpdatedExtensionPermissionsInfo::Reason reason = 1424 static_cast<UpdatedExtensionPermissionsInfo::Reason>(reason_id); 1425 1426 const PermissionSet* new_active = NULL; 1427 switch (reason) { 1428 case UpdatedExtensionPermissionsInfo::ADDED: 1429 new_active = PermissionSet::CreateUnion(old_active.get(), delta.get()); 1430 break; 1431 case UpdatedExtensionPermissionsInfo::REMOVED: 1432 new_active = 1433 PermissionSet::CreateDifference(old_active.get(), delta.get()); 1434 break; 1435 } 1436 1437 PermissionsData::SetActivePermissions(extension, new_active); 1438 AddOrRemoveOriginPermissions(reason, extension, explicit_hosts); 1439 AddOrRemoveBindings(extension->id()); 1440 } 1441 1442 void Dispatcher::OnUpdateTabSpecificPermissions( 1443 int page_id, 1444 int tab_id, 1445 const std::string& extension_id, 1446 const URLPatternSet& origin_set) { 1447 RenderView* view = TabFinder::Find(tab_id); 1448 1449 // For now, the message should only be sent to the render view that contains 1450 // the target tab. This may change. Either way, if this is the target tab it 1451 // gives us the chance to check against the page ID to avoid races. 1452 DCHECK(view); 1453 if (view && view->GetPageId() != page_id) 1454 return; 1455 1456 const Extension* extension = extensions_.GetByID(extension_id); 1457 if (!extension) 1458 return; 1459 1460 PermissionsData::UpdateTabSpecificPermissions( 1461 extension, 1462 tab_id, 1463 new PermissionSet(APIPermissionSet(), ManifestPermissionSet(), 1464 origin_set, URLPatternSet())); 1465 } 1466 1467 void Dispatcher::OnClearTabSpecificPermissions( 1468 int tab_id, 1469 const std::vector<std::string>& extension_ids) { 1470 for (std::vector<std::string>::const_iterator it = extension_ids.begin(); 1471 it != extension_ids.end(); ++it) { 1472 const Extension* extension = extensions_.GetByID(*it); 1473 if (extension) 1474 PermissionsData::ClearTabSpecificPermissions(extension, tab_id); 1475 } 1476 } 1477 1478 void Dispatcher::OnUpdateUserScripts( 1479 base::SharedMemoryHandle scripts) { 1480 DCHECK(base::SharedMemory::IsHandleValid(scripts)) << "Bad scripts handle"; 1481 user_script_slave_->UpdateScripts(scripts); 1482 UpdateActiveExtensions(); 1483 } 1484 1485 void Dispatcher::UpdateActiveExtensions() { 1486 // In single-process mode, the browser process reports the active extensions. 1487 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kSingleProcess)) 1488 return; 1489 1490 std::set<std::string> active_extensions = active_extension_ids_; 1491 user_script_slave_->GetActiveExtensions(&active_extensions); 1492 crash_keys::SetActiveExtensions(active_extensions); 1493 } 1494 1495 void Dispatcher::OnUsingWebRequestAPI( 1496 bool adblock, bool adblock_plus, bool other) { 1497 webrequest_adblock_ = adblock; 1498 webrequest_adblock_plus_ = adblock_plus; 1499 webrequest_other_ = other; 1500 } 1501 1502 void Dispatcher::OnShouldSuspend(const std::string& extension_id, 1503 int sequence_id) { 1504 RenderThread::Get()->Send( 1505 new ExtensionHostMsg_ShouldSuspendAck(extension_id, sequence_id)); 1506 } 1507 1508 void Dispatcher::OnSuspend(const std::string& extension_id) { 1509 // Dispatch the suspend event. This doesn't go through the standard event 1510 // dispatch machinery because it requires special handling. We need to let 1511 // the browser know when we are starting and stopping the event dispatch, so 1512 // that it still considers the extension idle despite any activity the suspend 1513 // event creates. 1514 DispatchEvent(extension_id, kOnSuspendEvent); 1515 RenderThread::Get()->Send(new ExtensionHostMsg_SuspendAck(extension_id)); 1516 } 1517 1518 void Dispatcher::OnCancelSuspend(const std::string& extension_id) { 1519 DispatchEvent(extension_id, kOnSuspendCanceledEvent); 1520 } 1521 1522 // TODO(kalman): This is checking for the wrong thing, it should be checking if 1523 // the frame's security origin is unique. The extension sandbox directive is 1524 // checked for in extensions/common/manifest_handlers/csp_info.cc. 1525 bool Dispatcher::IsSandboxedPage(const GURL& url) const { 1526 if (url.SchemeIs(kExtensionScheme)) { 1527 const Extension* extension = extensions_.GetByID(url.host()); 1528 if (extension) { 1529 return SandboxedPageInfo::IsSandboxedPage(extension, url.path()); 1530 } 1531 } 1532 return false; 1533 } 1534 1535 Feature::Context Dispatcher::ClassifyJavaScriptContext( 1536 const Extension* extension, 1537 int extension_group, 1538 const GURL& url, 1539 const blink::WebSecurityOrigin& origin) { 1540 DCHECK_GE(extension_group, 0); 1541 if (extension_group == EXTENSION_GROUP_CONTENT_SCRIPTS) { 1542 return extension ? // TODO(kalman): when does this happen? 1543 Feature::CONTENT_SCRIPT_CONTEXT : Feature::UNSPECIFIED_CONTEXT; 1544 } 1545 1546 // We have an explicit check for sandboxed pages before checking whether the 1547 // extension is active in this process because: 1548 // 1. Sandboxed pages run in the same process as regular extension pages, so 1549 // the extension is considered active. 1550 // 2. ScriptContext creation (which triggers bindings injection) happens 1551 // before the SecurityContext is updated with the sandbox flags (after 1552 // reading the CSP header), so the caller can't check if the context's 1553 // security origin is unique yet. 1554 if (IsSandboxedPage(url)) 1555 return Feature::WEB_PAGE_CONTEXT; 1556 1557 if (extension && IsExtensionActive(extension->id())) { 1558 // |extension| is active in this process, but it could be either a true 1559 // extension process or within the extent of a hosted app. In the latter 1560 // case this would usually be considered a (blessed) web page context, 1561 // unless the extension in question is a component extension, in which case 1562 // we cheat and call it blessed. 1563 return (extension->is_hosted_app() && 1564 extension->location() != Manifest::COMPONENT) ? 1565 Feature::BLESSED_WEB_PAGE_CONTEXT : Feature::BLESSED_EXTENSION_CONTEXT; 1566 } 1567 1568 // TODO(kalman): This isUnique() check is wrong, it should be performed as 1569 // part of IsSandboxedPage(). 1570 if (!origin.isUnique() && extensions_.ExtensionBindingsAllowed(url)) { 1571 if (!extension) // TODO(kalman): when does this happen? 1572 return Feature::UNSPECIFIED_CONTEXT; 1573 return extension->is_hosted_app() ? 1574 Feature::BLESSED_WEB_PAGE_CONTEXT : 1575 Feature::UNBLESSED_EXTENSION_CONTEXT; 1576 } 1577 1578 if (url.is_valid()) 1579 return Feature::WEB_PAGE_CONTEXT; 1580 1581 return Feature::UNSPECIFIED_CONTEXT; 1582 } 1583 1584 void Dispatcher::OnExtensionResponse(int request_id, 1585 bool success, 1586 const base::ListValue& response, 1587 const std::string& error) { 1588 request_sender_->HandleResponse(request_id, success, response, error); 1589 } 1590 1591 bool Dispatcher::CheckContextAccessToExtensionAPI( 1592 const std::string& function_name, ChromeV8Context* context) const { 1593 if (!context) { 1594 DLOG(ERROR) << "Not in a v8::Context"; 1595 return false; 1596 } 1597 1598 if (!context->extension()) { 1599 context->isolate()->ThrowException(v8::Exception::Error( 1600 v8::String::NewFromUtf8(context->isolate(), "Not in an extension."))); 1601 return false; 1602 } 1603 1604 // Theoretically we could end up with bindings being injected into sandboxed 1605 // frames, for example content scripts. Don't let them execute API functions. 1606 blink::WebFrame* frame = context->web_frame(); 1607 if (IsSandboxedPage(UserScriptSlave::GetDataSourceURLForFrame(frame))) { 1608 static const char kMessage[] = 1609 "%s cannot be used within a sandboxed frame."; 1610 std::string error_msg = base::StringPrintf(kMessage, function_name.c_str()); 1611 context->isolate()->ThrowException(v8::Exception::Error( 1612 v8::String::NewFromUtf8(context->isolate(), error_msg.c_str()))); 1613 return false; 1614 } 1615 1616 Feature::Availability availability = context->GetAvailability(function_name); 1617 if (!availability.is_available()) { 1618 context->isolate()->ThrowException( 1619 v8::Exception::Error(v8::String::NewFromUtf8( 1620 context->isolate(), availability.message().c_str()))); 1621 } 1622 1623 return availability.is_available(); 1624 } 1625 1626 void Dispatcher::DispatchEvent(const std::string& extension_id, 1627 const std::string& event_name) const { 1628 base::ListValue args; 1629 args.Set(0, new base::StringValue(event_name)); 1630 args.Set(1, new base::ListValue()); 1631 1632 // Needed for Windows compilation, since kEventBindings is declared extern. 1633 const char* local_event_bindings = kEventBindings; 1634 v8_context_set_.ForEach( 1635 extension_id, 1636 NULL, // all render views 1637 base::Bind(&CallModuleMethod, 1638 local_event_bindings, 1639 kEventDispatchFunction, 1640 &args)); 1641 } 1642 1643 void Dispatcher::InvokeModuleSystemMethod( 1644 content::RenderView* render_view, 1645 const std::string& extension_id, 1646 const std::string& module_name, 1647 const std::string& function_name, 1648 const base::ListValue& args, 1649 bool user_gesture) { 1650 scoped_ptr<WebScopedUserGesture> web_user_gesture; 1651 if (user_gesture) 1652 web_user_gesture.reset(new WebScopedUserGesture); 1653 1654 v8_context_set_.ForEach( 1655 extension_id, 1656 render_view, 1657 base::Bind(&CallModuleMethod, module_name, function_name, &args)); 1658 1659 // Reset the idle handler each time there's any activity like event or message 1660 // dispatch, for which Invoke is the chokepoint. 1661 if (is_extension_process_) { 1662 RenderThread::Get()->ScheduleIdleHandler( 1663 kInitialExtensionIdleHandlerDelayMs); 1664 } 1665 1666 // Tell the browser process when an event has been dispatched with a lazy 1667 // background page active. 1668 const Extension* extension = extensions_.GetByID(extension_id); 1669 if (extension && BackgroundInfo::HasLazyBackgroundPage(extension) && 1670 module_name == kEventBindings && 1671 function_name == kEventDispatchFunction) { 1672 RenderView* background_view = 1673 ExtensionHelper::GetBackgroundPage(extension_id); 1674 if (background_view) { 1675 background_view->Send(new ExtensionHostMsg_EventAck( 1676 background_view->GetRoutingID())); 1677 } 1678 } 1679 } 1680 1681 } // namespace extensions 1682