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.
5 #include "chrome/renderer/extensions/dispatcher.h"
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/extension_api.h"
21 #include "chrome/common/extensions/api/messaging/message.h"
22 #include "chrome/common/extensions/background_info.h"
23 #include "chrome/common/extensions/extension.h"
24 #include "chrome/common/extensions/extension_messages.h"
25 #include "chrome/common/extensions/features/feature_channel.h"
26 #include "chrome/common/extensions/manifest_handlers/externally_connectable.h"
27 #include "chrome/common/extensions/manifest_handlers/sandboxed_page_info.h"
28 #include "chrome/common/extensions/message_bundle.h"
29 #include "chrome/common/extensions/permissions/permissions_data.h"
30 #include "chrome/common/url_constants.h"
31 #include "chrome/renderer/chrome_render_process_observer.h"
32 #include "chrome/renderer/extensions/api_activity_logger.h"
33 #include "chrome/renderer/extensions/api_definitions_natives.h"
34 #include "chrome/renderer/extensions/app_bindings.h"
35 #include "chrome/renderer/extensions/app_runtime_custom_bindings.h"
36 #include "chrome/renderer/extensions/app_window_custom_bindings.h"
37 #include "chrome/renderer/extensions/binding_generating_native_handler.h"
38 #include "chrome/renderer/extensions/chrome_v8_context.h"
39 #include "chrome/renderer/extensions/chrome_v8_extension.h"
40 #include "chrome/renderer/extensions/content_watcher.h"
41 #include "chrome/renderer/extensions/context_menus_custom_bindings.h"
42 #include "chrome/renderer/extensions/css_native_handler.h"
43 #include "chrome/renderer/extensions/document_custom_bindings.h"
44 #include "chrome/renderer/extensions/dom_activity_logger.h"
45 #include "chrome/renderer/extensions/event_bindings.h"
46 #include "chrome/renderer/extensions/extension_custom_bindings.h"
47 #include "chrome/renderer/extensions/extension_groups.h"
48 #include "chrome/renderer/extensions/extension_helper.h"
49 #include "chrome/renderer/extensions/feedback_private_custom_bindings.h"
50 #include "chrome/renderer/extensions/file_browser_handler_custom_bindings.h"
51 #include "chrome/renderer/extensions/file_browser_private_custom_bindings.h"
52 #include "chrome/renderer/extensions/file_system_natives.h"
53 #include "chrome/renderer/extensions/i18n_custom_bindings.h"
54 #include "chrome/renderer/extensions/id_generator_custom_bindings.h"
55 #include "chrome/renderer/extensions/logging_native_handler.h"
56 #include "chrome/renderer/extensions/media_galleries_custom_bindings.h"
57 #include "chrome/renderer/extensions/messaging_bindings.h"
58 #include "chrome/renderer/extensions/module_system.h"
59 #include "chrome/renderer/extensions/object_backed_native_handler.h"
60 #include "chrome/renderer/extensions/page_actions_custom_bindings.h"
61 #include "chrome/renderer/extensions/page_capture_custom_bindings.h"
62 #include "chrome/renderer/extensions/render_view_observer_natives.h"
63 #include "chrome/renderer/extensions/request_sender.h"
64 #include "chrome/renderer/extensions/runtime_custom_bindings.h"
65 #include "chrome/renderer/extensions/safe_builtins.h"
66 #include "chrome/renderer/extensions/send_request_natives.h"
67 #include "chrome/renderer/extensions/set_icon_natives.h"
68 #include "chrome/renderer/extensions/sync_file_system_custom_bindings.h"
69 #include "chrome/renderer/extensions/tab_finder.h"
70 #include "chrome/renderer/extensions/tabs_custom_bindings.h"
71 #include "chrome/renderer/extensions/user_script_slave.h"
72 #include "chrome/renderer/extensions/webrtc_native_handler.h"
73 #include "chrome/renderer/extensions/webstore_bindings.h"
74 #include "chrome/renderer/resource_bundle_source_map.h"
75 #include "content/public/renderer/render_thread.h"
76 #include "content/public/renderer/render_view.h"
77 #include "content/public/renderer/v8_value_converter.h"
78 #include "extensions/common/constants.h"
79 #include "extensions/common/extension_urls.h"
80 #include "extensions/common/features/feature.h"
81 #include "extensions/common/features/feature_provider.h"
82 #include "extensions/common/manifest.h"
83 #include "extensions/common/manifest_constants.h"
84 #include "extensions/common/permissions/permission_set.h"
85 #include "extensions/common/view_type.h"
86 #include "grit/common_resources.h"
87 #include "grit/renderer_resources.h"
88 #include "third_party/WebKit/public/platform/WebString.h"
89 #include "third_party/WebKit/public/platform/WebURLRequest.h"
90 #include "third_party/WebKit/public/web/WebCustomElement.h"
91 #include "third_party/WebKit/public/web/WebDataSource.h"
92 #include "third_party/WebKit/public/web/WebDocument.h"
93 #include "third_party/WebKit/public/web/WebFrame.h"
94 #include "third_party/WebKit/public/web/WebRuntimeFeatures.h"
95 #include "third_party/WebKit/public/web/WebScopedUserGesture.h"
96 #include "third_party/WebKit/public/web/WebSecurityPolicy.h"
97 #include "third_party/WebKit/public/web/WebUserGestureIndicator.h"
98 #include "third_party/WebKit/public/web/WebView.h"
99 #include "ui/base/layout.h"
100 #include "ui/base/resource/resource_bundle.h"
101 #include "v8/include/v8.h"
103 using WebKit::WebDataSource;
104 using WebKit::WebDocument;
105 using WebKit::WebFrame;
106 using WebKit::WebScopedUserGesture;
107 using WebKit::WebSecurityPolicy;
108 using WebKit::WebString;
109 using WebKit::WebVector;
110 using WebKit::WebView;
111 using content::RenderThread;
112 using content::RenderView;
114 namespace extensions {
118 static const int64 kInitialExtensionIdleHandlerDelayMs = 5*1000;
119 static const int64 kMaxExtensionIdleHandlerDelayMs = 5*60*1000;
120 static const char kEventDispatchFunction[] = "dispatchEvent";
121 static const char kOnSuspendEvent[] = "runtime.onSuspend";
122 static const char kOnSuspendCanceledEvent[] = "runtime.onSuspendCanceled";
124 // Returns the global value for "chrome" from |context|. If one doesn't exist
125 // creates a new object for it.
127 // Note that this isn't necessarily an object, since webpages can write, for
128 // example, "window.chrome = true".
129 v8::Handle<v8::Value> GetOrCreateChrome(ChromeV8Context* context) {
130 v8::Handle<v8::String> chrome_string(v8::String::New("chrome"));
131 v8::Handle<v8::Object> global(context->v8_context()->Global());
132 v8::Handle<v8::Value> chrome(global->Get(chrome_string));
133 if (chrome->IsUndefined()) {
134 chrome = v8::Object::New();
135 global->Set(chrome_string, chrome);
140 // Returns |value| cast to an object if possible, else an empty handle.
141 v8::Handle<v8::Object> AsObjectOrEmpty(v8::Handle<v8::Value> value) {
142 return value->IsObject() ? value.As<v8::Object>() : v8::Handle<v8::Object>();
145 class TestFeaturesNativeHandler : public ObjectBackedNativeHandler {
147 explicit TestFeaturesNativeHandler(ChromeV8Context* context)
148 : ObjectBackedNativeHandler(context) {
149 RouteFunction("GetAPIFeatures",
150 base::Bind(&TestFeaturesNativeHandler::GetAPIFeatures,
151 base::Unretained(this)));
155 void GetAPIFeatures(const v8::FunctionCallbackInfo<v8::Value>& args) {
156 base::Value* value = base::JSONReader::Read(
157 ResourceBundle::GetSharedInstance().GetRawDataResource(
158 IDR_EXTENSION_API_FEATURES).as_string());
159 scoped_ptr<content::V8ValueConverter> converter(
160 content::V8ValueConverter::create());
161 args.GetReturnValue().Set(
162 converter->ToV8Value(value, context()->v8_context()));
166 class UserGesturesNativeHandler : public ObjectBackedNativeHandler {
168 explicit UserGesturesNativeHandler(ChromeV8Context* context)
169 : ObjectBackedNativeHandler(context) {
170 RouteFunction("IsProcessingUserGesture",
171 base::Bind(&UserGesturesNativeHandler::IsProcessingUserGesture,
172 base::Unretained(this)));
173 RouteFunction("RunWithUserGesture",
174 base::Bind(&UserGesturesNativeHandler::RunWithUserGesture,
175 base::Unretained(this)));
176 RouteFunction("RunWithoutUserGesture",
177 base::Bind(&UserGesturesNativeHandler::RunWithoutUserGesture,
178 base::Unretained(this)));
182 void IsProcessingUserGesture(
183 const v8::FunctionCallbackInfo<v8::Value>& args) {
184 args.GetReturnValue().Set(v8::Boolean::New(
185 WebKit::WebUserGestureIndicator::isProcessingUserGesture()));
188 void RunWithUserGesture(
189 const v8::FunctionCallbackInfo<v8::Value>& args) {
190 WebKit::WebScopedUserGesture user_gesture;
191 CHECK_EQ(args.Length(), 1);
192 CHECK(args[0]->IsFunction());
193 v8::Handle<v8::Value> no_args;
194 context()->CallFunction(v8::Handle<v8::Function>::Cast(args[0]),
198 void RunWithoutUserGesture(
199 const v8::FunctionCallbackInfo<v8::Value>& args) {
200 WebKit::WebUserGestureIndicator::consumeUserGesture();
201 CHECK_EQ(args.Length(), 1);
202 CHECK(args[0]->IsFunction());
203 v8::Handle<v8::Value> no_args;
204 context()->CallFunction(v8::Handle<v8::Function>::Cast(args[0]),
209 class V8ContextNativeHandler : public ObjectBackedNativeHandler {
211 V8ContextNativeHandler(ChromeV8Context* context, Dispatcher* dispatcher)
212 : ObjectBackedNativeHandler(context),
214 dispatcher_(dispatcher) {
215 RouteFunction("GetAvailability",
216 base::Bind(&V8ContextNativeHandler::GetAvailability,
217 base::Unretained(this)));
218 RouteFunction("GetModuleSystem",
219 base::Bind(&V8ContextNativeHandler::GetModuleSystem,
220 base::Unretained(this)));
224 void GetAvailability(const v8::FunctionCallbackInfo<v8::Value>& args) {
225 CHECK_EQ(args.Length(), 1);
226 std::string api_name = *v8::String::AsciiValue(args[0]->ToString());
227 Feature::Availability availability = context_->GetAvailability(api_name);
229 v8::Handle<v8::Object> ret = v8::Object::New();
230 ret->Set(v8::String::New("is_available"),
231 v8::Boolean::New(availability.is_available()));
232 ret->Set(v8::String::New("message"),
233 v8::String::New(availability.message().c_str()));
234 ret->Set(v8::String::New("result"),
235 v8::Integer::New(availability.result()));
236 args.GetReturnValue().Set(ret);
239 void GetModuleSystem(const v8::FunctionCallbackInfo<v8::Value>& args) {
240 CHECK_EQ(args.Length(), 1);
241 CHECK(args[0]->IsObject());
242 v8::Handle<v8::Context> v8_context =
243 v8::Handle<v8::Object>::Cast(args[0])->CreationContext();
244 ChromeV8Context* context = dispatcher_->v8_context_set().GetByV8Context(
246 args.GetReturnValue().Set(context->module_system()->NewInstance());
249 ChromeV8Context* context_;
250 Dispatcher* dispatcher_;
253 class ChromeNativeHandler : public ObjectBackedNativeHandler {
255 explicit ChromeNativeHandler(ChromeV8Context* context)
256 : ObjectBackedNativeHandler(context) {
257 RouteFunction("GetChrome",
258 base::Bind(&ChromeNativeHandler::GetChrome, base::Unretained(this)));
261 void GetChrome(const v8::FunctionCallbackInfo<v8::Value>& args) {
262 args.GetReturnValue().Set(GetOrCreateChrome(context()));
266 class PrintNativeHandler : public ObjectBackedNativeHandler {
268 explicit PrintNativeHandler(ChromeV8Context* context)
269 : ObjectBackedNativeHandler(context) {
270 RouteFunction("Print",
271 base::Bind(&PrintNativeHandler::Print,
272 base::Unretained(this)));
275 void Print(const v8::FunctionCallbackInfo<v8::Value>& args) {
276 if (args.Length() < 1)
279 std::vector<std::string> components;
280 for (int i = 0; i < args.Length(); ++i)
281 components.push_back(*v8::String::Utf8Value(args[i]->ToString()));
283 LOG(ERROR) << JoinString(components, ',');
287 class LazyBackgroundPageNativeHandler : public ChromeV8Extension {
289 LazyBackgroundPageNativeHandler(Dispatcher* dispatcher,
290 ChromeV8Context* context)
291 : ChromeV8Extension(dispatcher, context) {
292 RouteFunction("IncrementKeepaliveCount",
293 base::Bind(&LazyBackgroundPageNativeHandler::IncrementKeepaliveCount,
294 base::Unretained(this)));
295 RouteFunction("DecrementKeepaliveCount",
296 base::Bind(&LazyBackgroundPageNativeHandler::DecrementKeepaliveCount,
297 base::Unretained(this)));
300 void IncrementKeepaliveCount(
301 const v8::FunctionCallbackInfo<v8::Value>& args) {
304 RenderView* render_view = context()->GetRenderView();
305 if (IsContextLazyBackgroundPage(render_view, context()->extension())) {
306 render_view->Send(new ExtensionHostMsg_IncrementLazyKeepaliveCount(
307 render_view->GetRoutingID()));
311 void DecrementKeepaliveCount(
312 const v8::FunctionCallbackInfo<v8::Value>& args) {
315 RenderView* render_view = context()->GetRenderView();
316 if (IsContextLazyBackgroundPage(render_view, context()->extension())) {
317 render_view->Send(new ExtensionHostMsg_DecrementLazyKeepaliveCount(
318 render_view->GetRoutingID()));
323 bool IsContextLazyBackgroundPage(RenderView* render_view,
324 const Extension* extension) {
328 ExtensionHelper* helper = ExtensionHelper::Get(render_view);
329 return (extension && BackgroundInfo::HasLazyBackgroundPage(extension) &&
330 helper->view_type() == VIEW_TYPE_EXTENSION_BACKGROUND_PAGE);
334 class ProcessInfoNativeHandler : public ChromeV8Extension {
336 ProcessInfoNativeHandler(Dispatcher* dispatcher,
337 ChromeV8Context* context,
338 const std::string& extension_id,
339 const std::string& context_type,
340 bool is_incognito_context,
341 int manifest_version,
342 bool send_request_disabled)
343 : ChromeV8Extension(dispatcher, context),
344 extension_id_(extension_id),
345 context_type_(context_type),
346 is_incognito_context_(is_incognito_context),
347 manifest_version_(manifest_version),
348 send_request_disabled_(send_request_disabled) {
349 RouteFunction("GetExtensionId",
350 base::Bind(&ProcessInfoNativeHandler::GetExtensionId,
351 base::Unretained(this)));
352 RouteFunction("GetContextType",
353 base::Bind(&ProcessInfoNativeHandler::GetContextType,
354 base::Unretained(this)));
355 RouteFunction("InIncognitoContext",
356 base::Bind(&ProcessInfoNativeHandler::InIncognitoContext,
357 base::Unretained(this)));
358 RouteFunction("GetManifestVersion",
359 base::Bind(&ProcessInfoNativeHandler::GetManifestVersion,
360 base::Unretained(this)));
361 RouteFunction("IsSendRequestDisabled",
362 base::Bind(&ProcessInfoNativeHandler::IsSendRequestDisabled,
363 base::Unretained(this)));
364 RouteFunction("HasSwitch",
365 base::Bind(&ProcessInfoNativeHandler::HasSwitch,
366 base::Unretained(this)));
370 void GetExtensionId(const v8::FunctionCallbackInfo<v8::Value>& args) {
371 args.GetReturnValue().Set(v8::String::New(extension_id_.c_str()));
374 void GetContextType(const v8::FunctionCallbackInfo<v8::Value>& args) {
375 args.GetReturnValue().Set(v8::String::New(context_type_.c_str()));
378 void InIncognitoContext(const v8::FunctionCallbackInfo<v8::Value>& args) {
379 args.GetReturnValue().Set(is_incognito_context_);
382 void GetManifestVersion(const v8::FunctionCallbackInfo<v8::Value>& args) {
383 args.GetReturnValue().Set(static_cast<int32_t>(manifest_version_));
386 void IsSendRequestDisabled(const v8::FunctionCallbackInfo<v8::Value>& args) {
387 if (send_request_disabled_) {
388 args.GetReturnValue().Set(v8::String::New(
389 "sendRequest and onRequest are obsolete."
390 " Please use sendMessage and onMessage instead."));
394 void HasSwitch(const v8::FunctionCallbackInfo<v8::Value>& args) {
395 CHECK(args.Length() == 1 && args[0]->IsString());
396 bool has_switch = CommandLine::ForCurrentProcess()->HasSwitch(
397 *v8::String::AsciiValue(args[0]));
398 args.GetReturnValue().Set(v8::Boolean::New(has_switch));
401 std::string extension_id_;
402 std::string context_type_;
403 bool is_incognito_context_;
404 int manifest_version_;
405 bool send_request_disabled_;
408 void InstallAppBindings(ModuleSystem* module_system,
409 v8::Handle<v8::Object> chrome) {
410 module_system->SetLazyField(chrome, "app", "app", "chromeApp");
413 void InstallWebstoreBindings(ModuleSystem* module_system,
414 v8::Handle<v8::Object> chrome) {
415 module_system->SetLazyField(chrome, "webstore", "webstore", "chromeWebstore");
418 // Calls a method |method_name| in a module |module_name| belonging to the
419 // module system from |context|. Intended as a callback target from
420 // ChromeV8ContextSet::ForEach.
421 void CallModuleMethod(const std::string& module_name,
422 const std::string& method_name,
423 const base::ListValue* args,
424 ChromeV8Context* context) {
425 v8::HandleScope handle_scope(context->isolate());
426 v8::Context::Scope context_scope(context->v8_context());
428 scoped_ptr<content::V8ValueConverter> converter(
429 content::V8ValueConverter::create());
431 std::vector<v8::Handle<v8::Value> > arguments;
432 for (base::ListValue::const_iterator it = args->begin(); it != args->end();
434 arguments.push_back(converter->ToV8Value(*it, context->v8_context()));
437 context->module_system()->CallModuleMethod(
438 module_name, method_name, &arguments);
443 Dispatcher::Dispatcher()
444 : content_watcher_(new ContentWatcher()),
445 is_webkit_initialized_(false),
446 webrequest_adblock_(false),
447 webrequest_adblock_plus_(false),
448 webrequest_other_(false),
449 source_map_(&ResourceBundle::GetSharedInstance()),
450 v8_schema_registry_(new V8SchemaRegistry) {
451 const CommandLine& command_line = *(CommandLine::ForCurrentProcess());
452 is_extension_process_ =
453 command_line.HasSwitch(switches::kExtensionProcess) ||
454 command_line.HasSwitch(switches::kSingleProcess);
456 if (is_extension_process_) {
457 RenderThread::Get()->SetIdleNotificationDelayInMs(
458 kInitialExtensionIdleHandlerDelayMs);
461 RenderThread::Get()->RegisterExtension(SafeBuiltins::CreateV8Extension());
463 user_script_slave_.reset(new UserScriptSlave(&extensions_));
464 request_sender_.reset(new RequestSender(this));
466 PopulateLazyBindingsMap();
469 Dispatcher::~Dispatcher() {
472 bool Dispatcher::OnControlMessageReceived(const IPC::Message& message) {
474 IPC_BEGIN_MESSAGE_MAP(Dispatcher, message)
475 IPC_MESSAGE_HANDLER(ExtensionMsg_SetChannel, OnSetChannel)
476 IPC_MESSAGE_HANDLER(ExtensionMsg_MessageInvoke, OnMessageInvoke)
477 IPC_MESSAGE_HANDLER(ExtensionMsg_DispatchOnConnect, OnDispatchOnConnect)
478 IPC_MESSAGE_HANDLER(ExtensionMsg_DeliverMessage, OnDeliverMessage)
479 IPC_MESSAGE_HANDLER(ExtensionMsg_DispatchOnDisconnect,
480 OnDispatchOnDisconnect)
481 IPC_MESSAGE_HANDLER(ExtensionMsg_SetFunctionNames, OnSetFunctionNames)
482 IPC_MESSAGE_HANDLER(ExtensionMsg_SetSystemFont, OnSetSystemFont)
483 IPC_MESSAGE_HANDLER(ExtensionMsg_Loaded, OnLoaded)
484 IPC_MESSAGE_HANDLER(ExtensionMsg_Unloaded, OnUnloaded)
485 IPC_MESSAGE_HANDLER(ExtensionMsg_SetScriptingWhitelist,
486 OnSetScriptingWhitelist)
487 IPC_MESSAGE_HANDLER(ExtensionMsg_ActivateExtension, OnActivateExtension)
488 IPC_MESSAGE_HANDLER(ExtensionMsg_UpdatePermissions, OnUpdatePermissions)
489 IPC_MESSAGE_HANDLER(ExtensionMsg_UpdateTabSpecificPermissions,
490 OnUpdateTabSpecificPermissions)
491 IPC_MESSAGE_HANDLER(ExtensionMsg_ClearTabSpecificPermissions,
492 OnClearTabSpecificPermissions)
493 IPC_MESSAGE_HANDLER(ExtensionMsg_UpdateUserScripts, OnUpdateUserScripts)
494 IPC_MESSAGE_HANDLER(ExtensionMsg_UsingWebRequestAPI, OnUsingWebRequestAPI)
495 IPC_MESSAGE_HANDLER(ExtensionMsg_ShouldSuspend, OnShouldSuspend)
496 IPC_MESSAGE_HANDLER(ExtensionMsg_Suspend, OnSuspend)
497 IPC_MESSAGE_HANDLER(ExtensionMsg_CancelSuspend, OnCancelSuspend)
498 IPC_MESSAGE_FORWARD(ExtensionMsg_WatchPages,
499 content_watcher_.get(), ContentWatcher::OnWatchPages)
500 IPC_MESSAGE_UNHANDLED(handled = false)
501 IPC_END_MESSAGE_MAP()
506 void Dispatcher::WebKitInitialized() {
507 // For extensions, we want to ensure we call the IdleHandler every so often,
508 // even if the extension keeps up activity.
509 if (is_extension_process_) {
510 forced_idle_timer_.Start(FROM_HERE,
511 base::TimeDelta::FromMilliseconds(kMaxExtensionIdleHandlerDelayMs),
512 RenderThread::Get(), &RenderThread::IdleHandler);
515 // Initialize host permissions for any extensions that were activated before
516 // WebKit was initialized.
517 for (std::set<std::string>::iterator iter = active_extension_ids_.begin();
518 iter != active_extension_ids_.end(); ++iter) {
519 const Extension* extension = extensions_.GetByID(*iter);
521 InitOriginPermissions(extension);
524 EnableCustomElementWhiteList();
526 is_webkit_initialized_ = true;
529 void Dispatcher::IdleNotification() {
530 if (is_extension_process_) {
531 // Dampen the forced delay as well if the extension stays idle for long
533 int64 forced_delay_ms = std::max(
534 RenderThread::Get()->GetIdleNotificationDelayInMs(),
535 kMaxExtensionIdleHandlerDelayMs);
536 forced_idle_timer_.Stop();
537 forced_idle_timer_.Start(FROM_HERE,
538 base::TimeDelta::FromMilliseconds(forced_delay_ms),
539 RenderThread::Get(), &RenderThread::IdleHandler);
543 void Dispatcher::OnRenderProcessShutdown() {
544 v8_schema_registry_.reset();
547 void Dispatcher::OnSetFunctionNames(
548 const std::vector<std::string>& names) {
549 function_names_.clear();
550 for (size_t i = 0; i < names.size(); ++i)
551 function_names_.insert(names[i]);
554 void Dispatcher::OnSetSystemFont(const std::string& font_family,
555 const std::string& font_size) {
556 system_font_family_ = font_family;
557 system_font_size_ = font_size;
560 void Dispatcher::OnSetChannel(int channel) {
561 SetCurrentChannel(static_cast<chrome::VersionInfo::Channel>(channel));
564 void Dispatcher::OnMessageInvoke(const std::string& extension_id,
565 const std::string& module_name,
566 const std::string& function_name,
567 const base::ListValue& args,
569 InvokeModuleSystemMethod(
570 NULL, extension_id, module_name, function_name, args, user_gesture);
573 void Dispatcher::OnDispatchOnConnect(
575 const std::string& channel_name,
576 const base::DictionaryValue& source_tab,
577 const ExtensionMsg_ExternalConnectionInfo& info,
578 const std::string& tls_channel_id) {
579 MessagingBindings::DispatchOnConnect(
580 v8_context_set_.GetAll(),
581 target_port_id, channel_name, source_tab,
582 info.source_id, info.target_id, info.source_url,
584 NULL); // All render views.
587 void Dispatcher::OnDeliverMessage(int target_port_id,
588 const Message& message) {
589 MessagingBindings::DeliverMessage(
590 v8_context_set_.GetAll(),
593 NULL); // All render views.
596 void Dispatcher::OnDispatchOnDisconnect(int port_id,
597 const std::string& error_message) {
598 MessagingBindings::DispatchOnDisconnect(
599 v8_context_set_.GetAll(),
600 port_id, error_message,
601 NULL); // All render views.
604 void Dispatcher::OnLoaded(
605 const std::vector<ExtensionMsg_Loaded_Params>& loaded_extensions) {
606 std::vector<ExtensionMsg_Loaded_Params>::const_iterator i;
607 for (i = loaded_extensions.begin(); i != loaded_extensions.end(); ++i) {
609 scoped_refptr<const Extension> extension = i->ConvertToExtension(&error);
610 if (!extension.get()) {
611 extension_load_errors_[i->id] = error;
614 OnLoadedInternal(extension);
616 // Update the available bindings for all contexts. These may have changed if
617 // an externally_connectable extension was loaded that can connect to an
619 AddOrRemoveBindings("");
622 void Dispatcher::OnLoadedInternal(scoped_refptr<const Extension> extension) {
623 extensions_.Insert(extension);
626 void Dispatcher::OnUnloaded(const std::string& id) {
627 extensions_.Remove(id);
628 active_extension_ids_.erase(id);
630 // If the extension is later reloaded with a different set of permissions,
631 // we'd like it to get a new isolated world ID, so that it can pick up the
632 // changed origin whitelist.
633 user_script_slave_->RemoveIsolatedWorld(id);
635 // Invalidate all of the contexts that were removed.
636 // TODO(kalman): add an invalidation observer interface to ChromeV8Context.
637 ChromeV8ContextSet::ContextSet removed_contexts =
638 v8_context_set_.OnExtensionUnloaded(id);
639 for (ChromeV8ContextSet::ContextSet::iterator it = removed_contexts.begin();
640 it != removed_contexts.end(); ++it) {
641 request_sender_->InvalidateSource(*it);
644 // Update the available bindings for the remaining contexts. These may have
645 // changed if an externally_connectable extension is unloaded and a webpage
646 // is no longer accessible.
647 AddOrRemoveBindings("");
649 // Invalidates the messages map for the extension in case the extension is
650 // reloaded with a new messages map.
651 EraseL10nMessagesMap(id);
653 // We don't do anything with existing platform-app stylesheets. They will
654 // stay resident, but the URL pattern corresponding to the unloaded
655 // extension's URL just won't match anything anymore.
658 void Dispatcher::OnSetScriptingWhitelist(
659 const ExtensionsClient::ScriptingWhitelist& extension_ids) {
660 ExtensionsClient::Get()->SetScriptingWhitelist(extension_ids);
663 bool Dispatcher::IsExtensionActive(
664 const std::string& extension_id) const {
666 active_extension_ids_.find(extension_id) != active_extension_ids_.end();
668 CHECK(extensions_.Contains(extension_id));
672 v8::Handle<v8::Object> Dispatcher::GetOrCreateObject(
673 v8::Handle<v8::Object> object,
674 const std::string& field) {
675 v8::Handle<v8::String> key = v8::String::New(field.c_str());
676 // If the object has a callback property, it is assumed it is an unavailable
677 // API, so it is safe to delete. This is checked before GetOrCreateObject is
679 if (object->HasRealNamedCallbackProperty(key)) {
681 } else if (object->HasRealNamedProperty(key)) {
682 v8::Handle<v8::Value> value = object->Get(key);
683 CHECK(value->IsObject());
684 return v8::Handle<v8::Object>::Cast(value);
687 v8::Handle<v8::Object> new_object = v8::Object::New();
688 object->Set(key, new_object);
692 void Dispatcher::AddOrRemoveBindingsForContext(ChromeV8Context* context) {
693 v8::HandleScope handle_scope(context->isolate());
694 v8::Context::Scope context_scope(context->v8_context());
696 // TODO(kalman): Make the bindings registration have zero overhead then run
697 // the same code regardless of context type.
698 switch (context->context_type()) {
699 case Feature::UNSPECIFIED_CONTEXT:
700 case Feature::WEB_PAGE_CONTEXT: {
701 // Web page context; it's too expensive to run the full bindings code.
702 // Hard-code that the app and webstore APIs are available...
703 RegisterBinding("app", context);
704 RegisterBinding("webstore", context);
706 // ... and that the runtime API might be available if any extension can
708 bool runtime_is_available = false;
709 for (ExtensionSet::const_iterator it = extensions_.begin();
710 it != extensions_.end(); ++it) {
711 ExternallyConnectableInfo* info =
712 static_cast<ExternallyConnectableInfo*>((*it)->GetManifestData(
713 manifest_keys::kExternallyConnectable));
714 if (info && info->matches.MatchesURL(context->GetURL())) {
715 runtime_is_available = true;
719 if (runtime_is_available)
720 RegisterBinding("runtime", context);
724 case Feature::BLESSED_EXTENSION_CONTEXT:
725 case Feature::UNBLESSED_EXTENSION_CONTEXT:
726 case Feature::CONTENT_SCRIPT_CONTEXT: {
727 // Extension context; iterate through all the APIs and bind the available
729 FeatureProvider* api_feature_provider = FeatureProvider::GetAPIFeatures();
730 const std::vector<std::string>& apis =
731 api_feature_provider->GetAllFeatureNames();
732 for (std::vector<std::string>::const_iterator it = apis.begin();
733 it != apis.end(); ++it) {
734 const std::string& api_name = *it;
735 Feature* feature = api_feature_provider->GetFeature(api_name);
738 // Internal APIs are included via require(api_name) from internal code
739 // rather than chrome[api_name].
740 if (feature->IsInternal())
743 // If this API name has parent features, then this must be a function or
744 // event, so we should not register.
745 bool parent_feature_available = false;
746 for (Feature* parent = api_feature_provider->GetParent(feature);
747 parent != NULL; parent = api_feature_provider->GetParent(parent)) {
748 if (context->IsAnyFeatureAvailableToContext(parent->name())) {
749 parent_feature_available = true;
753 if (parent_feature_available)
756 if (context->IsAnyFeatureAvailableToContext(api_name))
757 RegisterBinding(api_name, context);
764 v8::Handle<v8::Object> Dispatcher::GetOrCreateBindObjectIfAvailable(
765 const std::string& api_name,
766 std::string* bind_name,
767 ChromeV8Context* context) {
768 std::vector<std::string> split;
769 base::SplitString(api_name, '.', &split);
771 v8::Handle<v8::Object> bind_object;
773 // Check if this API has an ancestor. If the API's ancestor is available and
774 // the API is not available, don't install the bindings for this API. If
775 // the API is available and its ancestor is not, delete the ancestor and
776 // install the bindings for the API. This is to prevent loading the ancestor
777 // API schema if it will not be needed.
780 // If app is available and app.window is not, just install app.
781 // If app.window is available and app is not, delete app and install
782 // app.window on a new object so app does not have to be loaded.
783 FeatureProvider* api_feature_provider = FeatureProvider::GetAPIFeatures();
784 std::string ancestor_name;
785 bool only_ancestor_available = false;
787 for (size_t i = 0; i < split.size() - 1; ++i) {
788 ancestor_name += (i ? ".": "") + split[i];
789 if (api_feature_provider->GetFeature(ancestor_name) &&
790 context->GetAvailability(ancestor_name).is_available() &&
791 !context->GetAvailability(api_name).is_available()) {
792 only_ancestor_available = true;
796 if (bind_object.IsEmpty()) {
797 bind_object = AsObjectOrEmpty(GetOrCreateChrome(context));
798 if (bind_object.IsEmpty())
799 return v8::Handle<v8::Object>();
801 bind_object = GetOrCreateObject(bind_object, split[i]);
804 if (only_ancestor_available)
805 return v8::Handle<v8::Object>();
808 *bind_name = split.back();
810 return bind_object.IsEmpty() ?
811 AsObjectOrEmpty(GetOrCreateChrome(context)) : bind_object;
814 void Dispatcher::RegisterBinding(const std::string& api_name,
815 ChromeV8Context* context) {
816 std::string bind_name;
817 v8::Handle<v8::Object> bind_object =
818 GetOrCreateBindObjectIfAvailable(api_name, &bind_name, context);
820 // Empty if the bind object failed to be created, probably because the
821 // extension overrode chrome with a non-object, e.g. window.chrome = true.
822 if (bind_object.IsEmpty())
825 v8::Local<v8::String> v8_api_name = v8::String::New(api_name.c_str());
826 if (bind_object->HasRealNamedProperty(v8_api_name)) {
827 // The bind object may already have the property if the API has been
828 // registered before (or if the extension has put something there already,
831 // In the former case, we need to re-register the bindings for the APIs
832 // which the extension now has permissions for (if any), but not touch any
833 // others so that we don't destroy state such as event listeners.
835 // TODO(kalman): Only register available APIs to make this all moot.
836 if (bind_object->HasRealNamedCallbackProperty(v8_api_name))
837 return; // lazy binding still there, nothing to do
838 if (bind_object->Get(v8_api_name)->IsObject())
839 return; // binding has already been fully installed
842 ModuleSystem* module_system = context->module_system();
843 if (lazy_bindings_map_.find(api_name) != lazy_bindings_map_.end()) {
844 InstallBindings(module_system, context->v8_context(), api_name);
845 } else if (!source_map_.Contains(api_name)) {
846 module_system->RegisterNativeHandler(
848 scoped_ptr<NativeHandler>(new BindingGeneratingNativeHandler(
852 module_system->SetNativeLazyField(bind_object,
857 module_system->SetLazyField(bind_object,
864 // NOTE: please use the naming convention "foo_natives" for these.
865 void Dispatcher::RegisterNativeHandlers(ModuleSystem* module_system,
866 ChromeV8Context* context) {
867 module_system->RegisterNativeHandler("event_natives",
868 scoped_ptr<NativeHandler>(EventBindings::Create(this, context)));
869 module_system->RegisterNativeHandler("messaging_natives",
870 scoped_ptr<NativeHandler>(MessagingBindings::Get(this, context)));
871 module_system->RegisterNativeHandler("apiDefinitions",
872 scoped_ptr<NativeHandler>(new ApiDefinitionsNatives(this, context)));
873 module_system->RegisterNativeHandler("sendRequest",
874 scoped_ptr<NativeHandler>(
875 new SendRequestNatives(this, request_sender_.get(), context)));
876 module_system->RegisterNativeHandler("setIcon",
877 scoped_ptr<NativeHandler>(
878 new SetIconNatives(this, request_sender_.get(), context)));
879 module_system->RegisterNativeHandler("activityLogger",
880 scoped_ptr<NativeHandler>(new APIActivityLogger(this, context)));
881 module_system->RegisterNativeHandler("renderViewObserverNatives",
882 scoped_ptr<NativeHandler>(new RenderViewObserverNatives(this, context)));
884 // Natives used by multiple APIs.
885 module_system->RegisterNativeHandler("file_system_natives",
886 scoped_ptr<NativeHandler>(new FileSystemNatives(context)));
889 module_system->RegisterNativeHandler("app",
890 scoped_ptr<NativeHandler>(new AppBindings(this, context)));
891 module_system->RegisterNativeHandler("app_runtime",
892 scoped_ptr<NativeHandler>(
893 new AppRuntimeCustomBindings(this, context)));
894 module_system->RegisterNativeHandler("app_window_natives",
895 scoped_ptr<NativeHandler>(
896 new AppWindowCustomBindings(this, context)));
897 module_system->RegisterNativeHandler("context_menus",
898 scoped_ptr<NativeHandler>(
899 new ContextMenusCustomBindings(this, context)));
900 module_system->RegisterNativeHandler(
901 "css_natives", scoped_ptr<NativeHandler>(new CssNativeHandler(context)));
902 module_system->RegisterNativeHandler("document_natives",
903 scoped_ptr<NativeHandler>(
904 new DocumentCustomBindings(this, context)));
905 module_system->RegisterNativeHandler("extension",
906 scoped_ptr<NativeHandler>(
907 new ExtensionCustomBindings(this, context)));
908 module_system->RegisterNativeHandler("sync_file_system",
909 scoped_ptr<NativeHandler>(
910 new SyncFileSystemCustomBindings(this, context)));
911 module_system->RegisterNativeHandler("feedback_private",
912 scoped_ptr<NativeHandler>(new FeedbackPrivateCustomBindings(
914 module_system->RegisterNativeHandler("file_browser_handler",
915 scoped_ptr<NativeHandler>(new FileBrowserHandlerCustomBindings(
917 module_system->RegisterNativeHandler("file_browser_private",
918 scoped_ptr<NativeHandler>(new FileBrowserPrivateCustomBindings(
920 module_system->RegisterNativeHandler("i18n",
921 scoped_ptr<NativeHandler>(
922 new I18NCustomBindings(this, context)));
923 module_system->RegisterNativeHandler(
925 scoped_ptr<NativeHandler>(new IdGeneratorCustomBindings(this, context)));
926 module_system->RegisterNativeHandler("mediaGalleries",
927 scoped_ptr<NativeHandler>(
928 new MediaGalleriesCustomBindings(this, context)));
929 module_system->RegisterNativeHandler("page_actions",
930 scoped_ptr<NativeHandler>(
931 new PageActionsCustomBindings(this, context)));
932 module_system->RegisterNativeHandler("page_capture",
933 scoped_ptr<NativeHandler>(
934 new PageCaptureCustomBindings(this, context)));
935 module_system->RegisterNativeHandler("runtime",
936 scoped_ptr<NativeHandler>(new RuntimeCustomBindings(this, context)));
937 module_system->RegisterNativeHandler("tabs",
938 scoped_ptr<NativeHandler>(new TabsCustomBindings(this, context)));
939 module_system->RegisterNativeHandler("webstore",
940 scoped_ptr<NativeHandler>(new WebstoreBindings(this, context)));
941 module_system->RegisterNativeHandler("webrtc_natives",
942 scoped_ptr<NativeHandler>(new WebRtcNativeHandler(context)));
945 void Dispatcher::PopulateSourceMap() {
947 source_map_.RegisterSource("entryIdManager", IDR_ENTRY_ID_MANAGER);
948 source_map_.RegisterSource(kEventBindings, IDR_EVENT_BINDINGS_JS);
949 source_map_.RegisterSource("imageUtil", IDR_IMAGE_UTIL_JS);
950 source_map_.RegisterSource("json_schema", IDR_JSON_SCHEMA_JS);
951 source_map_.RegisterSource("lastError", IDR_LAST_ERROR_JS);
952 source_map_.RegisterSource("messaging", IDR_MESSAGING_JS);
953 source_map_.RegisterSource("messaging_utils", IDR_MESSAGING_UTILS_JS);
954 source_map_.RegisterSource(kSchemaUtils, IDR_SCHEMA_UTILS_JS);
955 source_map_.RegisterSource("sendRequest", IDR_SEND_REQUEST_JS);
956 source_map_.RegisterSource("setIcon", IDR_SET_ICON_JS);
957 source_map_.RegisterSource("test", IDR_TEST_CUSTOM_BINDINGS_JS);
958 source_map_.RegisterSource("unload_event", IDR_UNLOAD_EVENT_JS);
959 source_map_.RegisterSource("utils", IDR_UTILS_JS);
962 source_map_.RegisterSource("app", IDR_APP_CUSTOM_BINDINGS_JS);
963 source_map_.RegisterSource("app.runtime", IDR_APP_RUNTIME_CUSTOM_BINDINGS_JS);
964 source_map_.RegisterSource("app.window", IDR_APP_WINDOW_CUSTOM_BINDINGS_JS);
965 source_map_.RegisterSource("bluetooth", IDR_BLUETOOTH_CUSTOM_BINDINGS_JS);
966 source_map_.RegisterSource("browserAction",
967 IDR_BROWSER_ACTION_CUSTOM_BINDINGS_JS);
968 source_map_.RegisterSource("contextMenus",
969 IDR_CONTEXT_MENUS_CUSTOM_BINDINGS_JS);
970 source_map_.RegisterSource("declarativeContent",
971 IDR_DECLARATIVE_CONTENT_CUSTOM_BINDINGS_JS);
972 source_map_.RegisterSource("declarativeWebRequest",
973 IDR_DECLARATIVE_WEBREQUEST_CUSTOM_BINDINGS_JS);
974 source_map_.RegisterSource("desktopCapture",
975 IDR_DESKTOP_CAPTURE_CUSTOM_BINDINGS_JS);
976 source_map_.RegisterSource("downloads",
977 IDR_DOWNLOADS_CUSTOM_BINDINGS_JS);
978 source_map_.RegisterSource("experimental.offscreen",
979 IDR_EXPERIMENTAL_OFFSCREENTABS_CUSTOM_BINDINGS_JS);
980 source_map_.RegisterSource("extension", IDR_EXTENSION_CUSTOM_BINDINGS_JS);
981 source_map_.RegisterSource("feedbackPrivate",
982 IDR_FEEDBACK_PRIVATE_CUSTOM_BINDINGS_JS);
983 source_map_.RegisterSource("fileBrowserHandler",
984 IDR_FILE_BROWSER_HANDLER_CUSTOM_BINDINGS_JS);
985 source_map_.RegisterSource("fileBrowserPrivate",
986 IDR_FILE_BROWSER_PRIVATE_CUSTOM_BINDINGS_JS);
987 source_map_.RegisterSource("fileSystem",
988 IDR_FILE_SYSTEM_CUSTOM_BINDINGS_JS);
989 source_map_.RegisterSource("i18n", IDR_I18N_CUSTOM_BINDINGS_JS);
990 source_map_.RegisterSource("input.ime", IDR_INPUT_IME_CUSTOM_BINDINGS_JS);
991 source_map_.RegisterSource("mediaGalleries",
992 IDR_MEDIA_GALLERIES_CUSTOM_BINDINGS_JS);
993 source_map_.RegisterSource("notifications",
994 IDR_NOTIFICATIONS_CUSTOM_BINDINGS_JS);
995 source_map_.RegisterSource("omnibox", IDR_OMNIBOX_CUSTOM_BINDINGS_JS);
996 source_map_.RegisterSource("pageActions",
997 IDR_PAGE_ACTIONS_CUSTOM_BINDINGS_JS);
998 source_map_.RegisterSource("pageAction", IDR_PAGE_ACTION_CUSTOM_BINDINGS_JS);
999 source_map_.RegisterSource("pageCapture",
1000 IDR_PAGE_CAPTURE_CUSTOM_BINDINGS_JS);
1001 source_map_.RegisterSource("permissions", IDR_PERMISSIONS_CUSTOM_BINDINGS_JS);
1002 source_map_.RegisterSource("runtime", IDR_RUNTIME_CUSTOM_BINDINGS_JS);
1003 source_map_.RegisterSource("syncFileSystem",
1004 IDR_SYNC_FILE_SYSTEM_CUSTOM_BINDINGS_JS);
1005 source_map_.RegisterSource("systemIndicator",
1006 IDR_SYSTEM_INDICATOR_CUSTOM_BINDINGS_JS);
1007 source_map_.RegisterSource("tabCapture", IDR_TAB_CAPTURE_CUSTOM_BINDINGS_JS);
1008 source_map_.RegisterSource("tabs", IDR_TABS_CUSTOM_BINDINGS_JS);
1009 source_map_.RegisterSource("tts", IDR_TTS_CUSTOM_BINDINGS_JS);
1010 source_map_.RegisterSource("ttsEngine", IDR_TTS_ENGINE_CUSTOM_BINDINGS_JS);
1011 source_map_.RegisterSource("webRequest", IDR_WEB_REQUEST_CUSTOM_BINDINGS_JS);
1012 source_map_.RegisterSource("webRequestInternal",
1013 IDR_WEB_REQUEST_INTERNAL_CUSTOM_BINDINGS_JS);
1014 source_map_.RegisterSource("webrtc.castSendTransport",
1015 IDR_WEBRTC_CAST_SEND_TRANSPORT_CUSTOM_BINDINGS_JS);
1016 source_map_.RegisterSource("webrtc.castUdpTransport",
1017 IDR_WEBRTC_CAST_UDP_TRANSPORT_CUSTOM_BINDINGS_JS);
1018 source_map_.RegisterSource("webstore", IDR_WEBSTORE_CUSTOM_BINDINGS_JS);
1019 source_map_.RegisterSource("windowControls", IDR_WINDOW_CONTROLS_JS);
1020 source_map_.RegisterSource("binding", IDR_BINDING_JS);
1022 // Custom types sources.
1023 source_map_.RegisterSource("ChromeSetting", IDR_CHROME_SETTING_JS);
1024 source_map_.RegisterSource("StorageArea", IDR_STORAGE_AREA_JS);
1025 source_map_.RegisterSource("ContentSetting", IDR_CONTENT_SETTING_JS);
1026 source_map_.RegisterSource("ChromeDirectSetting",
1027 IDR_CHROME_DIRECT_SETTING_JS);
1029 // Platform app sources that are not API-specific..
1030 source_map_.RegisterSource("tagWatcher", IDR_TAG_WATCHER_JS);
1031 // Note: webView not webview so that this doesn't interfere with the
1032 // chrome.webview API bindings.
1033 source_map_.RegisterSource("webView", IDR_WEB_VIEW_JS);
1034 source_map_.RegisterSource("webViewExperimental",
1035 IDR_WEB_VIEW_EXPERIMENTAL_JS);
1036 source_map_.RegisterSource("denyWebView", IDR_WEB_VIEW_DENY_JS);
1037 source_map_.RegisterSource("adView", IDR_AD_VIEW_JS);
1038 source_map_.RegisterSource("denyAdView", IDR_AD_VIEW_DENY_JS);
1039 source_map_.RegisterSource("platformApp", IDR_PLATFORM_APP_JS);
1040 source_map_.RegisterSource("injectAppTitlebar", IDR_INJECT_APP_TITLEBAR_JS);
1042 #if defined OS_CHROMEOS
1043 source_map_.RegisterSource("wallpaper", IDR_WALLPAPER_CUSTOM_BINDINGS_JS);
1047 void Dispatcher::PopulateLazyBindingsMap() {
1048 lazy_bindings_map_["app"] = InstallAppBindings;
1049 lazy_bindings_map_["webstore"] = InstallWebstoreBindings;
1052 void Dispatcher::InstallBindings(ModuleSystem* module_system,
1053 v8::Handle<v8::Context> v8_context,
1054 const std::string& api) {
1055 std::map<std::string, BindingInstaller>::const_iterator lazy_binding =
1056 lazy_bindings_map_.find(api);
1057 if (lazy_binding != lazy_bindings_map_.end()) {
1058 v8::Handle<v8::Object> global(v8_context->Global());
1059 v8::Handle<v8::Object> chrome =
1060 global->Get(v8::String::New("chrome"))->ToObject();
1061 (*lazy_binding->second)(module_system, chrome);
1063 module_system->Require(api);
1067 void Dispatcher::DidCreateScriptContext(
1068 WebFrame* frame, v8::Handle<v8::Context> v8_context, int extension_group,
1070 #if !defined(ENABLE_EXTENSIONS)
1074 std::string extension_id = GetExtensionID(frame, world_id);
1076 const Extension* extension = extensions_.GetByID(extension_id);
1077 if (!extension && !extension_id.empty()) {
1078 // There are conditions where despite a context being associated with an
1079 // extension, no extension actually gets found. Ignore "invalid" because
1080 // CSP blocks extension page loading by switching the extension ID to
1081 // "invalid". This isn't interesting.
1082 if (extension_id != "invalid") {
1083 LOG(ERROR) << "Extension \"" << extension_id << "\" not found";
1084 RenderThread::Get()->RecordUserMetrics("ExtensionNotFound_ED");
1090 Feature::Context context_type = ClassifyJavaScriptContext(
1091 extension_id, extension_group,
1092 UserScriptSlave::GetDataSourceURLForFrame(frame),
1093 frame->document().securityOrigin());
1095 ChromeV8Context* context =
1096 new ChromeV8Context(v8_context, frame, extension, context_type);
1097 v8_context_set_.Add(context);
1100 scoped_ptr<ModuleSystem> module_system(new ModuleSystem(context,
1102 context->set_module_system(module_system.Pass());
1104 ModuleSystem* module_system = context->module_system();
1106 // Enable natives in startup.
1107 ModuleSystem::NativesEnabledScope natives_enabled_scope(
1110 RegisterNativeHandlers(module_system, context);
1112 module_system->RegisterNativeHandler("chrome",
1113 scoped_ptr<NativeHandler>(new ChromeNativeHandler(context)));
1114 module_system->RegisterNativeHandler("print",
1115 scoped_ptr<NativeHandler>(new PrintNativeHandler(context)));
1116 module_system->RegisterNativeHandler("lazy_background_page",
1117 scoped_ptr<NativeHandler>(
1118 new LazyBackgroundPageNativeHandler(this, context)));
1119 module_system->RegisterNativeHandler("logging",
1120 scoped_ptr<NativeHandler>(new LoggingNativeHandler(context)));
1121 module_system->RegisterNativeHandler("schema_registry",
1122 v8_schema_registry_->AsNativeHandler());
1123 module_system->RegisterNativeHandler("v8_context",
1124 scoped_ptr<NativeHandler>(new V8ContextNativeHandler(context, this)));
1125 module_system->RegisterNativeHandler("test_features",
1126 scoped_ptr<NativeHandler>(new TestFeaturesNativeHandler(context)));
1127 module_system->RegisterNativeHandler("user_gestures",
1128 scoped_ptr<NativeHandler>(new UserGesturesNativeHandler(context)));
1130 int manifest_version = extension ? extension->manifest_version() : 1;
1131 bool send_request_disabled =
1132 (extension && Manifest::IsUnpackedLocation(extension->location()) &&
1133 BackgroundInfo::HasLazyBackgroundPage(extension));
1134 module_system->RegisterNativeHandler("process",
1135 scoped_ptr<NativeHandler>(new ProcessInfoNativeHandler(
1136 this, context, context->GetExtensionID(),
1137 context->GetContextTypeDescription(),
1138 ChromeRenderProcessObserver::is_incognito_process(),
1139 manifest_version, send_request_disabled)));
1141 // chrome.Event is part of the public API (although undocumented). Make it
1142 // lazily evalulate to Event from event_bindings.js. For extensions only
1143 // though, not all webpages!
1144 if (context->extension()) {
1145 v8::Handle<v8::Object> chrome = AsObjectOrEmpty(GetOrCreateChrome(context));
1146 if (!chrome.IsEmpty())
1147 module_system->SetLazyField(chrome, "Event", kEventBindings, "Event");
1150 AddOrRemoveBindingsForContext(context);
1152 bool is_within_platform_app = IsWithinPlatformApp();
1153 // Inject custom JS into the platform app context.
1154 if (is_within_platform_app) {
1155 module_system->Require("platformApp");
1158 if (context_type == Feature::BLESSED_EXTENSION_CONTEXT &&
1159 is_within_platform_app &&
1160 GetCurrentChannel() <= chrome::VersionInfo::CHANNEL_DEV &&
1161 CommandLine::ForCurrentProcess()->HasSwitch(
1162 switches::kEnableAppWindowControls)) {
1163 module_system->Require("windowControls");
1166 // Currently only platform apps and whitelisted component extensions support
1167 // the <webview> tag, because the "denyWebView" module will affect the
1168 // performance of DOM modifications (http://crbug.com/196453).
1169 // We used to limit WebView to |BLESSED_EXTENSION_CONTEXT| within platform
1170 // apps. An ext/app runs in a blessed extension context, if it is the active
1171 // extension in the current process, in other words, if it is loaded in a top
1172 // frame. To support webview in a non-frame extension, we have to allow
1173 // unblessed extension context as well.
1174 if (context_type == Feature::BLESSED_EXTENSION_CONTEXT ||
1175 context_type == Feature::UNBLESSED_EXTENSION_CONTEXT) {
1176 // Note: setting up the WebView class here, not the chrome.webview API.
1177 // The API will be automatically set up when first used.
1178 if (extension->HasAPIPermission(APIPermission::kWebView)) {
1179 module_system->Require("webView");
1180 bool includeExperimental =
1181 GetCurrentChannel() <= chrome::VersionInfo::CHANNEL_DEV;
1182 if (!includeExperimental) {
1183 // TODO(asargent) We need a whitelist for webview experimental.
1185 std::string id_hash = base::SHA1HashString(extension->id());
1186 std::string hexencoded_id_hash = base::HexEncode(id_hash.c_str(),
1188 if (hexencoded_id_hash == "8C3741E3AF0B93B6E8E0DDD499BB0B74839EA578" ||
1189 hexencoded_id_hash == "E703483CEF33DEC18B4B6DD84B5C776FB9182BDB" ||
1190 hexencoded_id_hash == "1A26E32DE447A17CBE5E9750CDBA78F58539B39C" ||
1191 hexencoded_id_hash == "59048028102D7B4C681DBC7BC6CD980C3DC66DA3")
1192 includeExperimental = true;
1194 if (includeExperimental)
1195 module_system->Require("webViewExperimental");
1197 module_system->Require("denyWebView");
1201 // Same comment as above for <adview> tag.
1202 if (context_type == Feature::BLESSED_EXTENSION_CONTEXT &&
1203 is_within_platform_app) {
1204 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnableAdview)) {
1205 if (extension->HasAPIPermission(APIPermission::kAdView)) {
1206 module_system->Require("adView");
1208 module_system->Require("denyAdView");
1213 VLOG(1) << "Num tracked contexts: " << v8_context_set_.size();
1216 std::string Dispatcher::GetExtensionID(const WebFrame* frame, int world_id) {
1217 if (world_id != 0) {
1218 // Isolated worlds (content script).
1219 return user_script_slave_->GetExtensionIdForIsolatedWorld(world_id);
1222 // TODO(kalman): Delete this check.
1223 if (frame->document().securityOrigin().isUnique())
1224 return std::string();
1226 // Extension pages (chrome-extension:// URLs).
1227 GURL frame_url = UserScriptSlave::GetDataSourceURLForFrame(frame);
1228 return extensions_.GetExtensionOrAppIDByURL(frame_url);
1231 bool Dispatcher::IsWithinPlatformApp() {
1232 for (std::set<std::string>::iterator iter = active_extension_ids_.begin();
1233 iter != active_extension_ids_.end(); ++iter) {
1234 const Extension* extension = extensions_.GetByID(*iter);
1235 if (extension && extension->is_platform_app())
1241 void Dispatcher::WillReleaseScriptContext(
1242 WebFrame* frame, v8::Handle<v8::Context> v8_context, int world_id) {
1243 ChromeV8Context* context = v8_context_set_.GetByV8Context(v8_context);
1247 context->DispatchOnUnloadEvent();
1248 // TODO(kalman): add an invalidation observer interface to ChromeV8Context.
1249 request_sender_->InvalidateSource(context);
1251 v8_context_set_.Remove(context);
1252 VLOG(1) << "Num tracked contexts: " << v8_context_set_.size();
1255 void Dispatcher::DidCreateDocumentElement(WebKit::WebFrame* frame) {
1256 if (IsWithinPlatformApp()) {
1257 // WebKit doesn't let us define an additional user agent stylesheet, so we
1258 // insert the default platform app stylesheet into all documents that are
1259 // loaded in each app.
1260 std::string stylesheet =
1261 ResourceBundle::GetSharedInstance().
1262 GetRawDataResource(IDR_PLATFORM_APP_CSS).as_string();
1263 ReplaceFirstSubstringAfterOffset(&stylesheet, 0,
1264 "$FONTFAMILY", system_font_family_);
1265 ReplaceFirstSubstringAfterOffset(&stylesheet, 0,
1266 "$FONTSIZE", system_font_size_);
1267 frame->document().insertUserStyleSheet(
1268 WebString::fromUTF8(stylesheet), WebDocument::UserStyleUserLevel);
1271 content_watcher_->DidCreateDocumentElement(frame);
1274 void Dispatcher::DidMatchCSS(
1275 WebKit::WebFrame* frame,
1276 const WebKit::WebVector<WebKit::WebString>& newly_matching_selectors,
1277 const WebKit::WebVector<WebKit::WebString>& stopped_matching_selectors) {
1278 content_watcher_->DidMatchCSS(
1279 frame, newly_matching_selectors, stopped_matching_selectors);
1283 void Dispatcher::OnActivateExtension(const std::string& extension_id) {
1284 const Extension* extension = extensions_.GetByID(extension_id);
1286 // Extension was activated but was never loaded. This probably means that
1287 // the renderer failed to load it (or the browser failed to tell us when it
1288 // did). Failures shouldn't happen, but instead of crashing there (which
1289 // executes on all renderers) be conservative and only crash in the renderer
1290 // of the extension which failed to load; this one.
1291 std::string& error = extension_load_errors_[extension_id];
1293 base::debug::Alias(&minidump);
1294 base::snprintf(minidump, arraysize(minidump),
1295 "e::dispatcher:%s:%s", extension_id.c_str(), error.c_str());
1296 CHECK(extension) << extension_id << " was never loaded: " << error;
1299 active_extension_ids_.insert(extension_id);
1301 // This is called when starting a new extension page, so start the idle
1303 RenderThread::Get()->ScheduleIdleHandler(kInitialExtensionIdleHandlerDelayMs);
1305 UpdateActiveExtensions();
1307 if (is_webkit_initialized_) {
1308 InitOriginPermissions(extension);
1309 DOMActivityLogger::AttachToWorld(DOMActivityLogger::kMainWorldId,
1314 void Dispatcher::InitOriginPermissions(const Extension* extension) {
1315 // TODO(jstritar): We should try to remove this special case. Also, these
1316 // whitelist entries need to be updated when the kManagement permission
1318 if (extension->HasAPIPermission(APIPermission::kManagement)) {
1319 WebSecurityPolicy::addOriginAccessWhitelistEntry(
1321 WebString::fromUTF8(chrome::kChromeUIScheme),
1322 WebString::fromUTF8(chrome::kChromeUIExtensionIconHost),
1326 AddOrRemoveOriginPermissions(
1327 UpdatedExtensionPermissionsInfo::ADDED,
1329 extension->GetActivePermissions()->explicit_hosts());
1332 void Dispatcher::AddOrRemoveOriginPermissions(
1333 UpdatedExtensionPermissionsInfo::Reason reason,
1334 const Extension* extension,
1335 const URLPatternSet& origins) {
1336 for (URLPatternSet::const_iterator i = origins.begin();
1337 i != origins.end(); ++i) {
1338 const char* schemes[] = {
1339 content::kHttpScheme,
1340 content::kHttpsScheme,
1341 chrome::kFileScheme,
1342 chrome::kChromeUIScheme,
1344 for (size_t j = 0; j < arraysize(schemes); ++j) {
1345 if (i->MatchesScheme(schemes[j])) {
1346 ((reason == UpdatedExtensionPermissionsInfo::REMOVED) ?
1347 WebSecurityPolicy::removeOriginAccessWhitelistEntry :
1348 WebSecurityPolicy::addOriginAccessWhitelistEntry)(
1350 WebString::fromUTF8(schemes[j]),
1351 WebString::fromUTF8(i->host()),
1352 i->match_subdomains());
1358 void Dispatcher::EnableCustomElementWhiteList() {
1359 WebKit::WebRuntimeFeatures::enableEmbedderCustomElements(true);
1360 WebKit::WebCustomElement::addEmbedderCustomElementName("webview");
1361 // TODO(fsamuel): Add <adview> to the whitelist once it has been converted
1362 // into a custom element.
1363 WebKit::WebCustomElement::addEmbedderCustomElementName("browser-plugin");
1366 void Dispatcher::AddOrRemoveBindings(const std::string& extension_id) {
1367 v8_context_set().ForEach(
1369 NULL, // all render views
1370 base::Bind(&Dispatcher::AddOrRemoveBindingsForContext,
1371 base::Unretained(this)));
1374 void Dispatcher::OnUpdatePermissions(int reason_id,
1375 const std::string& extension_id,
1376 const APIPermissionSet& apis,
1377 const URLPatternSet& explicit_hosts,
1378 const URLPatternSet& scriptable_hosts) {
1379 const Extension* extension = extensions_.GetByID(extension_id);
1383 scoped_refptr<const PermissionSet> delta =
1384 new PermissionSet(apis, explicit_hosts, scriptable_hosts);
1385 scoped_refptr<const PermissionSet> old_active =
1386 extension->GetActivePermissions();
1387 UpdatedExtensionPermissionsInfo::Reason reason =
1388 static_cast<UpdatedExtensionPermissionsInfo::Reason>(reason_id);
1390 const PermissionSet* new_active = NULL;
1392 case UpdatedExtensionPermissionsInfo::ADDED:
1393 new_active = PermissionSet::CreateUnion(old_active.get(), delta.get());
1395 case UpdatedExtensionPermissionsInfo::REMOVED:
1397 PermissionSet::CreateDifference(old_active.get(), delta.get());
1401 PermissionsData::SetActivePermissions(extension, new_active);
1402 AddOrRemoveOriginPermissions(reason, extension, explicit_hosts);
1403 AddOrRemoveBindings(extension->id());
1406 void Dispatcher::OnUpdateTabSpecificPermissions(
1409 const std::string& extension_id,
1410 const URLPatternSet& origin_set) {
1411 RenderView* view = TabFinder::Find(tab_id);
1413 // For now, the message should only be sent to the render view that contains
1414 // the target tab. This may change. Either way, if this is the target tab it
1415 // gives us the chance to check against the page ID to avoid races.
1417 if (view && view->GetPageId() != page_id)
1420 const Extension* extension = extensions_.GetByID(extension_id);
1424 PermissionsData::UpdateTabSpecificPermissions(
1427 new PermissionSet(APIPermissionSet(), origin_set, URLPatternSet()));
1430 void Dispatcher::OnClearTabSpecificPermissions(
1432 const std::vector<std::string>& extension_ids) {
1433 for (std::vector<std::string>::const_iterator it = extension_ids.begin();
1434 it != extension_ids.end(); ++it) {
1435 const Extension* extension = extensions_.GetByID(*it);
1437 PermissionsData::ClearTabSpecificPermissions(extension, tab_id);
1441 void Dispatcher::OnUpdateUserScripts(
1442 base::SharedMemoryHandle scripts) {
1443 DCHECK(base::SharedMemory::IsHandleValid(scripts)) << "Bad scripts handle";
1444 user_script_slave_->UpdateScripts(scripts);
1445 UpdateActiveExtensions();
1448 void Dispatcher::UpdateActiveExtensions() {
1449 // In single-process mode, the browser process reports the active extensions.
1450 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kSingleProcess))
1453 std::set<std::string> active_extensions = active_extension_ids_;
1454 user_script_slave_->GetActiveExtensions(&active_extensions);
1455 crash_keys::SetActiveExtensions(active_extensions);
1458 void Dispatcher::OnUsingWebRequestAPI(
1459 bool adblock, bool adblock_plus, bool other) {
1460 webrequest_adblock_ = adblock;
1461 webrequest_adblock_plus_ = adblock_plus;
1462 webrequest_other_ = other;
1465 void Dispatcher::OnShouldSuspend(const std::string& extension_id,
1467 RenderThread::Get()->Send(
1468 new ExtensionHostMsg_ShouldSuspendAck(extension_id, sequence_id));
1471 void Dispatcher::OnSuspend(const std::string& extension_id) {
1472 // Dispatch the suspend event. This doesn't go through the standard event
1473 // dispatch machinery because it requires special handling. We need to let
1474 // the browser know when we are starting and stopping the event dispatch, so
1475 // that it still considers the extension idle despite any activity the suspend
1477 DispatchEvent(extension_id, kOnSuspendEvent);
1478 RenderThread::Get()->Send(new ExtensionHostMsg_SuspendAck(extension_id));
1481 void Dispatcher::OnCancelSuspend(const std::string& extension_id) {
1482 DispatchEvent(extension_id, kOnSuspendCanceledEvent);
1485 // TODO(kalman): This is checking for the wrong thing, it should be checking if
1486 // the frame's security origin is unique. The extension sandbox directive is
1487 // checked for in chrome/common/extensions/csp_handler.cc.
1488 bool Dispatcher::IsSandboxedPage(const GURL& url) const {
1489 if (url.SchemeIs(kExtensionScheme)) {
1490 const Extension* extension = extensions_.GetByID(url.host());
1492 return SandboxedPageInfo::IsSandboxedPage(extension, url.path());
1498 Feature::Context Dispatcher::ClassifyJavaScriptContext(
1499 const std::string& extension_id,
1500 int extension_group,
1502 const WebKit::WebSecurityOrigin& origin) {
1503 DCHECK_GE(extension_group, 0);
1504 if (extension_group == EXTENSION_GROUP_CONTENT_SCRIPTS) {
1505 return extensions_.Contains(extension_id) ?
1506 Feature::CONTENT_SCRIPT_CONTEXT : Feature::UNSPECIFIED_CONTEXT;
1509 // We have an explicit check for sandboxed pages before checking whether the
1510 // extension is active in this process because:
1511 // 1. Sandboxed pages run in the same process as regular extension pages, so
1512 // the extension is considered active.
1513 // 2. ScriptContext creation (which triggers bindings injection) happens
1514 // before the SecurityContext is updated with the sandbox flags (after
1515 // reading the CSP header), so the caller can't check if the context's
1516 // security origin is unique yet.
1517 if (IsSandboxedPage(url))
1518 return Feature::WEB_PAGE_CONTEXT;
1520 if (IsExtensionActive(extension_id))
1521 return Feature::BLESSED_EXTENSION_CONTEXT;
1523 // TODO(kalman): This isUnique() check is wrong, it should be performed as
1524 // part of IsSandboxedPage().
1525 if (!origin.isUnique() && extensions_.ExtensionBindingsAllowed(url)) {
1526 return extensions_.Contains(extension_id) ?
1527 Feature::UNBLESSED_EXTENSION_CONTEXT : Feature::UNSPECIFIED_CONTEXT;
1531 return Feature::WEB_PAGE_CONTEXT;
1533 return Feature::UNSPECIFIED_CONTEXT;
1536 void Dispatcher::OnExtensionResponse(int request_id,
1538 const base::ListValue& response,
1539 const std::string& error) {
1540 request_sender_->HandleResponse(request_id, success, response, error);
1543 bool Dispatcher::CheckContextAccessToExtensionAPI(
1544 const std::string& function_name, ChromeV8Context* context) const {
1546 DLOG(ERROR) << "Not in a v8::Context";
1550 if (!context->extension()) {
1552 v8::Exception::Error(v8::String::New("Not in an extension.")));
1556 // Theoretically we could end up with bindings being injected into sandboxed
1557 // frames, for example content scripts. Don't let them execute API functions.
1558 WebKit::WebFrame* frame = context->web_frame();
1559 if (IsSandboxedPage(UserScriptSlave::GetDataSourceURLForFrame(frame))) {
1560 static const char kMessage[] =
1561 "%s cannot be used within a sandboxed frame.";
1562 std::string error_msg = base::StringPrintf(kMessage, function_name.c_str());
1564 v8::Exception::Error(v8::String::New(error_msg.c_str())));
1568 Feature::Availability availability = context->GetAvailability(function_name);
1569 if (!availability.is_available()) {
1570 v8::ThrowException(v8::Exception::Error(
1571 v8::String::New(availability.message().c_str())));
1574 return availability.is_available();
1577 void Dispatcher::DispatchEvent(const std::string& extension_id,
1578 const std::string& event_name) const {
1579 base::ListValue args;
1580 args.Set(0, new base::StringValue(event_name));
1581 args.Set(1, new base::ListValue());
1583 // Needed for Windows compilation, since kEventBindings is declared extern.
1584 const char* local_event_bindings = kEventBindings;
1585 v8_context_set_.ForEach(
1587 NULL, // all render views
1588 base::Bind(&CallModuleMethod,
1589 local_event_bindings,
1590 kEventDispatchFunction,
1594 void Dispatcher::InvokeModuleSystemMethod(
1595 content::RenderView* render_view,
1596 const std::string& extension_id,
1597 const std::string& module_name,
1598 const std::string& function_name,
1599 const base::ListValue& args,
1600 bool user_gesture) {
1601 scoped_ptr<WebScopedUserGesture> web_user_gesture;
1603 web_user_gesture.reset(new WebScopedUserGesture);
1605 v8_context_set_.ForEach(
1608 base::Bind(&CallModuleMethod, module_name, function_name, &args));
1610 // Reset the idle handler each time there's any activity like event or message
1611 // dispatch, for which Invoke is the chokepoint.
1612 if (is_extension_process_) {
1613 RenderThread::Get()->ScheduleIdleHandler(
1614 kInitialExtensionIdleHandlerDelayMs);
1617 // Tell the browser process when an event has been dispatched with a lazy
1618 // background page active.
1619 const Extension* extension = extensions_.GetByID(extension_id);
1620 if (extension && BackgroundInfo::HasLazyBackgroundPage(extension) &&
1621 module_name == kEventBindings &&
1622 function_name == kEventDispatchFunction) {
1623 RenderView* background_view =
1624 ExtensionHelper::GetBackgroundPage(extension_id);
1625 if (background_view) {
1626 background_view->Send(new ExtensionHostMsg_EventAck(
1627 background_view->GetRoutingID()));
1632 } // namespace extensions