Add cast transport API skeleton.
[chromium-blink-merge.git] / chrome / renderer / extensions / dispatcher.cc
bloba4f98f63ac492691153e057e62256c7e55375fcb
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/background_info.h"
22 #include "chrome/common/extensions/extension.h"
23 #include "chrome/common/extensions/extension_constants.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/permission_set.h"
30 #include "chrome/common/extensions/permissions/permissions_data.h"
31 #include "chrome/common/url_constants.h"
32 #include "chrome/renderer/chrome_render_process_observer.h"
33 #include "chrome/renderer/extensions/api_activity_logger.h"
34 #include "chrome/renderer/extensions/api_definitions_natives.h"
35 #include "chrome/renderer/extensions/app_bindings.h"
36 #include "chrome/renderer/extensions/app_runtime_custom_bindings.h"
37 #include "chrome/renderer/extensions/app_window_custom_bindings.h"
38 #include "chrome/renderer/extensions/binding_generating_native_handler.h"
39 #include "chrome/renderer/extensions/chrome_v8_context.h"
40 #include "chrome/renderer/extensions/chrome_v8_extension.h"
41 #include "chrome/renderer/extensions/content_watcher.h"
42 #include "chrome/renderer/extensions/context_menus_custom_bindings.h"
43 #include "chrome/renderer/extensions/css_native_handler.h"
44 #include "chrome/renderer/extensions/document_custom_bindings.h"
45 #include "chrome/renderer/extensions/dom_activity_logger.h"
46 #include "chrome/renderer/extensions/event_bindings.h"
47 #include "chrome/renderer/extensions/extension_custom_bindings.h"
48 #include "chrome/renderer/extensions/extension_groups.h"
49 #include "chrome/renderer/extensions/extension_helper.h"
50 #include "chrome/renderer/extensions/feedback_private_custom_bindings.h"
51 #include "chrome/renderer/extensions/file_browser_handler_custom_bindings.h"
52 #include "chrome/renderer/extensions/file_browser_private_custom_bindings.h"
53 #include "chrome/renderer/extensions/file_system_natives.h"
54 #include "chrome/renderer/extensions/i18n_custom_bindings.h"
55 #include "chrome/renderer/extensions/id_generator_custom_bindings.h"
56 #include "chrome/renderer/extensions/logging_native_handler.h"
57 #include "chrome/renderer/extensions/media_galleries_custom_bindings.h"
58 #include "chrome/renderer/extensions/messaging_bindings.h"
59 #include "chrome/renderer/extensions/module_system.h"
60 #include "chrome/renderer/extensions/object_backed_native_handler.h"
61 #include "chrome/renderer/extensions/page_actions_custom_bindings.h"
62 #include "chrome/renderer/extensions/page_capture_custom_bindings.h"
63 #include "chrome/renderer/extensions/render_view_observer_natives.h"
64 #include "chrome/renderer/extensions/request_sender.h"
65 #include "chrome/renderer/extensions/runtime_custom_bindings.h"
66 #include "chrome/renderer/extensions/safe_builtins.h"
67 #include "chrome/renderer/extensions/send_request_natives.h"
68 #include "chrome/renderer/extensions/set_icon_natives.h"
69 #include "chrome/renderer/extensions/sync_file_system_custom_bindings.h"
70 #include "chrome/renderer/extensions/tab_finder.h"
71 #include "chrome/renderer/extensions/tabs_custom_bindings.h"
72 #include "chrome/renderer/extensions/user_script_slave.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/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/WebView.h"
97 #include "ui/base/layout.h"
98 #include "ui/base/resource/resource_bundle.h"
99 #include "v8/include/v8.h"
101 using WebKit::WebDataSource;
102 using WebKit::WebDocument;
103 using WebKit::WebFrame;
104 using WebKit::WebScopedUserGesture;
105 using WebKit::WebSecurityPolicy;
106 using WebKit::WebString;
107 using WebKit::WebVector;
108 using WebKit::WebView;
109 using content::RenderThread;
110 using content::RenderView;
112 namespace extensions {
114 namespace {
116 static const int64 kInitialExtensionIdleHandlerDelayMs = 5*1000;
117 static const int64 kMaxExtensionIdleHandlerDelayMs = 5*60*1000;
118 static const char kEventDispatchFunction[] = "dispatchEvent";
119 static const char kOnSuspendEvent[] = "runtime.onSuspend";
120 static const char kOnSuspendCanceledEvent[] = "runtime.onSuspendCanceled";
122 // Returns the global value for "chrome" from |context|. If one doesn't exist
123 // creates a new object for it.
125 // Note that this isn't necessarily an object, since webpages can write, for
126 // example, "window.chrome = true".
127 v8::Handle<v8::Value> GetOrCreateChrome(ChromeV8Context* context) {
128 v8::Handle<v8::String> chrome_string(v8::String::New("chrome"));
129 v8::Handle<v8::Object> global(context->v8_context()->Global());
130 v8::Handle<v8::Value> chrome(global->Get(chrome_string));
131 if (chrome->IsUndefined()) {
132 chrome = v8::Object::New();
133 global->Set(chrome_string, chrome);
135 return chrome;
138 // Returns |value| cast to an object if possible, else an empty handle.
139 v8::Handle<v8::Object> AsObjectOrEmpty(v8::Handle<v8::Value> value) {
140 return value->IsObject() ? value.As<v8::Object>() : v8::Handle<v8::Object>();
143 class TestFeaturesNativeHandler : public ObjectBackedNativeHandler {
144 public:
145 explicit TestFeaturesNativeHandler(ChromeV8Context* context)
146 : ObjectBackedNativeHandler(context) {
147 RouteFunction("GetAPIFeatures",
148 base::Bind(&TestFeaturesNativeHandler::GetAPIFeatures,
149 base::Unretained(this)));
152 private:
153 void GetAPIFeatures(const v8::FunctionCallbackInfo<v8::Value>& args) {
154 base::Value* value = base::JSONReader::Read(
155 ResourceBundle::GetSharedInstance().GetRawDataResource(
156 IDR_EXTENSION_API_FEATURES).as_string());
157 scoped_ptr<content::V8ValueConverter> converter(
158 content::V8ValueConverter::create());
159 args.GetReturnValue().Set(
160 converter->ToV8Value(value, context()->v8_context()));
164 class V8ContextNativeHandler : public ObjectBackedNativeHandler {
165 public:
166 V8ContextNativeHandler(ChromeV8Context* context, Dispatcher* dispatcher)
167 : ObjectBackedNativeHandler(context),
168 context_(context),
169 dispatcher_(dispatcher) {
170 RouteFunction("GetAvailability",
171 base::Bind(&V8ContextNativeHandler::GetAvailability,
172 base::Unretained(this)));
173 RouteFunction("GetModuleSystem",
174 base::Bind(&V8ContextNativeHandler::GetModuleSystem,
175 base::Unretained(this)));
178 private:
179 void GetAvailability(const v8::FunctionCallbackInfo<v8::Value>& args) {
180 CHECK_EQ(args.Length(), 1);
181 std::string api_name = *v8::String::AsciiValue(args[0]->ToString());
182 Feature::Availability availability = context_->GetAvailability(api_name);
184 v8::Handle<v8::Object> ret = v8::Object::New();
185 ret->Set(v8::String::New("is_available"),
186 v8::Boolean::New(availability.is_available()));
187 ret->Set(v8::String::New("message"),
188 v8::String::New(availability.message().c_str()));
189 ret->Set(v8::String::New("result"),
190 v8::Integer::New(availability.result()));
191 args.GetReturnValue().Set(ret);
194 void GetModuleSystem(const v8::FunctionCallbackInfo<v8::Value>& args) {
195 CHECK_EQ(args.Length(), 1);
196 CHECK(args[0]->IsObject());
197 v8::Handle<v8::Context> v8_context =
198 v8::Handle<v8::Object>::Cast(args[0])->CreationContext();
199 ChromeV8Context* context = dispatcher_->v8_context_set().GetByV8Context(
200 v8_context);
201 args.GetReturnValue().Set(context->module_system()->NewInstance());
204 ChromeV8Context* context_;
205 Dispatcher* dispatcher_;
208 class ChromeNativeHandler : public ObjectBackedNativeHandler {
209 public:
210 explicit ChromeNativeHandler(ChromeV8Context* context)
211 : ObjectBackedNativeHandler(context) {
212 RouteFunction("GetChrome",
213 base::Bind(&ChromeNativeHandler::GetChrome, base::Unretained(this)));
216 void GetChrome(const v8::FunctionCallbackInfo<v8::Value>& args) {
217 args.GetReturnValue().Set(GetOrCreateChrome(context()));
221 class PrintNativeHandler : public ObjectBackedNativeHandler {
222 public:
223 explicit PrintNativeHandler(ChromeV8Context* context)
224 : ObjectBackedNativeHandler(context) {
225 RouteFunction("Print",
226 base::Bind(&PrintNativeHandler::Print,
227 base::Unretained(this)));
230 void Print(const v8::FunctionCallbackInfo<v8::Value>& args) {
231 if (args.Length() < 1)
232 return;
234 std::vector<std::string> components;
235 for (int i = 0; i < args.Length(); ++i)
236 components.push_back(*v8::String::Utf8Value(args[i]->ToString()));
238 LOG(ERROR) << JoinString(components, ',');
242 class LazyBackgroundPageNativeHandler : public ChromeV8Extension {
243 public:
244 LazyBackgroundPageNativeHandler(Dispatcher* dispatcher,
245 ChromeV8Context* context)
246 : ChromeV8Extension(dispatcher, context) {
247 RouteFunction("IncrementKeepaliveCount",
248 base::Bind(&LazyBackgroundPageNativeHandler::IncrementKeepaliveCount,
249 base::Unretained(this)));
250 RouteFunction("DecrementKeepaliveCount",
251 base::Bind(&LazyBackgroundPageNativeHandler::DecrementKeepaliveCount,
252 base::Unretained(this)));
255 void IncrementKeepaliveCount(
256 const v8::FunctionCallbackInfo<v8::Value>& args) {
257 if (!context())
258 return;
259 RenderView* render_view = context()->GetRenderView();
260 if (IsContextLazyBackgroundPage(render_view, context()->extension())) {
261 render_view->Send(new ExtensionHostMsg_IncrementLazyKeepaliveCount(
262 render_view->GetRoutingID()));
266 void DecrementKeepaliveCount(
267 const v8::FunctionCallbackInfo<v8::Value>& args) {
268 if (!context())
269 return;
270 RenderView* render_view = context()->GetRenderView();
271 if (IsContextLazyBackgroundPage(render_view, context()->extension())) {
272 render_view->Send(new ExtensionHostMsg_DecrementLazyKeepaliveCount(
273 render_view->GetRoutingID()));
277 private:
278 bool IsContextLazyBackgroundPage(RenderView* render_view,
279 const Extension* extension) {
280 if (!render_view)
281 return false;
283 ExtensionHelper* helper = ExtensionHelper::Get(render_view);
284 return (extension && BackgroundInfo::HasLazyBackgroundPage(extension) &&
285 helper->view_type() == VIEW_TYPE_EXTENSION_BACKGROUND_PAGE);
289 class ProcessInfoNativeHandler : public ChromeV8Extension {
290 public:
291 ProcessInfoNativeHandler(Dispatcher* dispatcher,
292 ChromeV8Context* context,
293 const std::string& extension_id,
294 const std::string& context_type,
295 bool is_incognito_context,
296 int manifest_version,
297 bool send_request_disabled)
298 : ChromeV8Extension(dispatcher, context),
299 extension_id_(extension_id),
300 context_type_(context_type),
301 is_incognito_context_(is_incognito_context),
302 manifest_version_(manifest_version),
303 send_request_disabled_(send_request_disabled) {
304 RouteFunction("GetExtensionId",
305 base::Bind(&ProcessInfoNativeHandler::GetExtensionId,
306 base::Unretained(this)));
307 RouteFunction("GetContextType",
308 base::Bind(&ProcessInfoNativeHandler::GetContextType,
309 base::Unretained(this)));
310 RouteFunction("InIncognitoContext",
311 base::Bind(&ProcessInfoNativeHandler::InIncognitoContext,
312 base::Unretained(this)));
313 RouteFunction("GetManifestVersion",
314 base::Bind(&ProcessInfoNativeHandler::GetManifestVersion,
315 base::Unretained(this)));
316 RouteFunction("IsSendRequestDisabled",
317 base::Bind(&ProcessInfoNativeHandler::IsSendRequestDisabled,
318 base::Unretained(this)));
319 RouteFunction("HasSwitch",
320 base::Bind(&ProcessInfoNativeHandler::HasSwitch,
321 base::Unretained(this)));
324 private:
325 void GetExtensionId(const v8::FunctionCallbackInfo<v8::Value>& args) {
326 args.GetReturnValue().Set(v8::String::New(extension_id_.c_str()));
329 void GetContextType(const v8::FunctionCallbackInfo<v8::Value>& args) {
330 args.GetReturnValue().Set(v8::String::New(context_type_.c_str()));
333 void InIncognitoContext(const v8::FunctionCallbackInfo<v8::Value>& args) {
334 args.GetReturnValue().Set(is_incognito_context_);
337 void GetManifestVersion(const v8::FunctionCallbackInfo<v8::Value>& args) {
338 args.GetReturnValue().Set(static_cast<int32_t>(manifest_version_));
341 void IsSendRequestDisabled(const v8::FunctionCallbackInfo<v8::Value>& args) {
342 if (send_request_disabled_) {
343 args.GetReturnValue().Set(v8::String::New(
344 "sendRequest and onRequest are obsolete."
345 " Please use sendMessage and onMessage instead."));
349 void HasSwitch(const v8::FunctionCallbackInfo<v8::Value>& args) {
350 CHECK(args.Length() == 1 && args[0]->IsString());
351 bool has_switch = CommandLine::ForCurrentProcess()->HasSwitch(
352 *v8::String::AsciiValue(args[0]));
353 args.GetReturnValue().Set(v8::Boolean::New(has_switch));
356 std::string extension_id_;
357 std::string context_type_;
358 bool is_incognito_context_;
359 int manifest_version_;
360 bool send_request_disabled_;
363 void InstallAppBindings(ModuleSystem* module_system,
364 v8::Handle<v8::Object> chrome) {
365 module_system->SetLazyField(chrome, "app", "app", "chromeApp");
368 void InstallWebstoreBindings(ModuleSystem* module_system,
369 v8::Handle<v8::Object> chrome) {
370 module_system->SetLazyField(chrome, "webstore", "webstore", "chromeWebstore");
373 // Calls a method |method_name| in a module |module_name| belonging to the
374 // module system from |context|. Intended as a callback target from
375 // ChromeV8ContextSet::ForEach.
376 void CallModuleMethod(const std::string& module_name,
377 const std::string& method_name,
378 const base::ListValue* args,
379 ChromeV8Context* context) {
380 v8::HandleScope handle_scope(context->isolate());
381 v8::Context::Scope context_scope(context->v8_context());
383 scoped_ptr<content::V8ValueConverter> converter(
384 content::V8ValueConverter::create());
386 std::vector<v8::Handle<v8::Value> > arguments;
387 for (base::ListValue::const_iterator it = args->begin(); it != args->end();
388 ++it) {
389 arguments.push_back(converter->ToV8Value(*it, context->v8_context()));
392 context->module_system()->CallModuleMethod(
393 module_name, method_name, &arguments);
396 } // namespace
398 Dispatcher::Dispatcher()
399 : content_watcher_(new ContentWatcher()),
400 is_webkit_initialized_(false),
401 webrequest_adblock_(false),
402 webrequest_adblock_plus_(false),
403 webrequest_other_(false),
404 source_map_(&ResourceBundle::GetSharedInstance()),
405 v8_schema_registry_(new V8SchemaRegistry) {
406 const CommandLine& command_line = *(CommandLine::ForCurrentProcess());
407 is_extension_process_ =
408 command_line.HasSwitch(switches::kExtensionProcess) ||
409 command_line.HasSwitch(switches::kSingleProcess);
411 if (is_extension_process_) {
412 RenderThread::Get()->SetIdleNotificationDelayInMs(
413 kInitialExtensionIdleHandlerDelayMs);
416 RenderThread::Get()->RegisterExtension(SafeBuiltins::CreateV8Extension());
418 user_script_slave_.reset(new UserScriptSlave(&extensions_));
419 request_sender_.reset(new RequestSender(this));
420 PopulateSourceMap();
421 PopulateLazyBindingsMap();
424 Dispatcher::~Dispatcher() {
427 bool Dispatcher::OnControlMessageReceived(const IPC::Message& message) {
428 bool handled = true;
429 IPC_BEGIN_MESSAGE_MAP(Dispatcher, message)
430 IPC_MESSAGE_HANDLER(ExtensionMsg_SetChannel, OnSetChannel)
431 IPC_MESSAGE_HANDLER(ExtensionMsg_MessageInvoke, OnMessageInvoke)
432 IPC_MESSAGE_HANDLER(ExtensionMsg_DispatchOnConnect, OnDispatchOnConnect)
433 IPC_MESSAGE_HANDLER(ExtensionMsg_DeliverMessage, OnDeliverMessage)
434 IPC_MESSAGE_HANDLER(ExtensionMsg_DispatchOnDisconnect,
435 OnDispatchOnDisconnect)
436 IPC_MESSAGE_HANDLER(ExtensionMsg_SetFunctionNames, OnSetFunctionNames)
437 IPC_MESSAGE_HANDLER(ExtensionMsg_SetSystemFont, OnSetSystemFont)
438 IPC_MESSAGE_HANDLER(ExtensionMsg_Loaded, OnLoaded)
439 IPC_MESSAGE_HANDLER(ExtensionMsg_Unloaded, OnUnloaded)
440 IPC_MESSAGE_HANDLER(ExtensionMsg_SetScriptingWhitelist,
441 OnSetScriptingWhitelist)
442 IPC_MESSAGE_HANDLER(ExtensionMsg_ActivateExtension, OnActivateExtension)
443 IPC_MESSAGE_HANDLER(ExtensionMsg_UpdatePermissions, OnUpdatePermissions)
444 IPC_MESSAGE_HANDLER(ExtensionMsg_UpdateTabSpecificPermissions,
445 OnUpdateTabSpecificPermissions)
446 IPC_MESSAGE_HANDLER(ExtensionMsg_ClearTabSpecificPermissions,
447 OnClearTabSpecificPermissions)
448 IPC_MESSAGE_HANDLER(ExtensionMsg_UpdateUserScripts, OnUpdateUserScripts)
449 IPC_MESSAGE_HANDLER(ExtensionMsg_UsingWebRequestAPI, OnUsingWebRequestAPI)
450 IPC_MESSAGE_HANDLER(ExtensionMsg_ShouldSuspend, OnShouldSuspend)
451 IPC_MESSAGE_HANDLER(ExtensionMsg_Suspend, OnSuspend)
452 IPC_MESSAGE_HANDLER(ExtensionMsg_CancelSuspend, OnCancelSuspend)
453 IPC_MESSAGE_FORWARD(ExtensionMsg_WatchPages,
454 content_watcher_.get(), ContentWatcher::OnWatchPages)
455 IPC_MESSAGE_UNHANDLED(handled = false)
456 IPC_END_MESSAGE_MAP()
458 return handled;
461 void Dispatcher::WebKitInitialized() {
462 // For extensions, we want to ensure we call the IdleHandler every so often,
463 // even if the extension keeps up activity.
464 if (is_extension_process_) {
465 forced_idle_timer_.Start(FROM_HERE,
466 base::TimeDelta::FromMilliseconds(kMaxExtensionIdleHandlerDelayMs),
467 RenderThread::Get(), &RenderThread::IdleHandler);
470 // Initialize host permissions for any extensions that were activated before
471 // WebKit was initialized.
472 for (std::set<std::string>::iterator iter = active_extension_ids_.begin();
473 iter != active_extension_ids_.end(); ++iter) {
474 const Extension* extension = extensions_.GetByID(*iter);
475 CHECK(extension);
476 InitOriginPermissions(extension);
479 EnableCustomElementWhiteList();
481 is_webkit_initialized_ = true;
484 void Dispatcher::IdleNotification() {
485 if (is_extension_process_) {
486 // Dampen the forced delay as well if the extension stays idle for long
487 // periods of time.
488 int64 forced_delay_ms = std::max(
489 RenderThread::Get()->GetIdleNotificationDelayInMs(),
490 kMaxExtensionIdleHandlerDelayMs);
491 forced_idle_timer_.Stop();
492 forced_idle_timer_.Start(FROM_HERE,
493 base::TimeDelta::FromMilliseconds(forced_delay_ms),
494 RenderThread::Get(), &RenderThread::IdleHandler);
498 void Dispatcher::OnRenderProcessShutdown() {
499 v8_schema_registry_.reset();
502 void Dispatcher::OnSetFunctionNames(
503 const std::vector<std::string>& names) {
504 function_names_.clear();
505 for (size_t i = 0; i < names.size(); ++i)
506 function_names_.insert(names[i]);
509 void Dispatcher::OnSetSystemFont(const std::string& font_family,
510 const std::string& font_size) {
511 system_font_family_ = font_family;
512 system_font_size_ = font_size;
515 void Dispatcher::OnSetChannel(int channel) {
516 SetCurrentChannel(static_cast<chrome::VersionInfo::Channel>(channel));
519 void Dispatcher::OnMessageInvoke(const std::string& extension_id,
520 const std::string& module_name,
521 const std::string& function_name,
522 const base::ListValue& args,
523 bool user_gesture) {
524 InvokeModuleSystemMethod(
525 NULL, extension_id, module_name, function_name, args, user_gesture);
528 void Dispatcher::OnDispatchOnConnect(
529 int target_port_id,
530 const std::string& channel_name,
531 const base::DictionaryValue& source_tab,
532 const ExtensionMsg_ExternalConnectionInfo& info) {
533 MessagingBindings::DispatchOnConnect(
534 v8_context_set_.GetAll(),
535 target_port_id, channel_name, source_tab,
536 info.source_id, info.target_id, info.source_url,
537 NULL); // All render views.
540 void Dispatcher::OnDeliverMessage(int target_port_id,
541 const std::string& message) {
542 MessagingBindings::DeliverMessage(
543 v8_context_set_.GetAll(),
544 target_port_id,
545 message,
546 NULL); // All render views.
549 void Dispatcher::OnDispatchOnDisconnect(int port_id,
550 const std::string& error_message) {
551 MessagingBindings::DispatchOnDisconnect(
552 v8_context_set_.GetAll(),
553 port_id, error_message,
554 NULL); // All render views.
557 void Dispatcher::OnLoaded(
558 const std::vector<ExtensionMsg_Loaded_Params>& loaded_extensions) {
559 std::vector<ExtensionMsg_Loaded_Params>::const_iterator i;
560 for (i = loaded_extensions.begin(); i != loaded_extensions.end(); ++i) {
561 std::string error;
562 scoped_refptr<const Extension> extension = i->ConvertToExtension(&error);
563 if (!extension.get()) {
564 extension_load_errors_[i->id] = error;
565 continue;
567 OnLoadedInternal(extension);
569 // Update the available bindings for all contexts. These may have changed if
570 // an externally_connectable extension was loaded that can connect to an
571 // open webpage.
572 AddOrRemoveBindings("");
575 void Dispatcher::OnLoadedInternal(scoped_refptr<const Extension> extension) {
576 extensions_.Insert(extension);
579 void Dispatcher::OnUnloaded(const std::string& id) {
580 extensions_.Remove(id);
581 active_extension_ids_.erase(id);
583 // If the extension is later reloaded with a different set of permissions,
584 // we'd like it to get a new isolated world ID, so that it can pick up the
585 // changed origin whitelist.
586 user_script_slave_->RemoveIsolatedWorld(id);
588 // Invalidate all of the contexts that were removed.
589 // TODO(kalman): add an invalidation observer interface to ChromeV8Context.
590 ChromeV8ContextSet::ContextSet removed_contexts =
591 v8_context_set_.OnExtensionUnloaded(id);
592 for (ChromeV8ContextSet::ContextSet::iterator it = removed_contexts.begin();
593 it != removed_contexts.end(); ++it) {
594 request_sender_->InvalidateSource(*it);
597 // Update the available bindings for the remaining contexts. These may have
598 // changed if an externally_connectable extension is unloaded and a webpage
599 // is no longer accessible.
600 AddOrRemoveBindings("");
602 // Invalidates the messages map for the extension in case the extension is
603 // reloaded with a new messages map.
604 EraseL10nMessagesMap(id);
606 // We don't do anything with existing platform-app stylesheets. They will
607 // stay resident, but the URL pattern corresponding to the unloaded
608 // extension's URL just won't match anything anymore.
611 void Dispatcher::OnSetScriptingWhitelist(
612 const Extension::ScriptingWhitelist& extension_ids) {
613 Extension::SetScriptingWhitelist(extension_ids);
616 bool Dispatcher::IsExtensionActive(
617 const std::string& extension_id) const {
618 bool is_active =
619 active_extension_ids_.find(extension_id) != active_extension_ids_.end();
620 if (is_active)
621 CHECK(extensions_.Contains(extension_id));
622 return is_active;
625 v8::Handle<v8::Object> Dispatcher::GetOrCreateObject(
626 v8::Handle<v8::Object> object,
627 const std::string& field) {
628 v8::Handle<v8::String> key = v8::String::New(field.c_str());
629 // If the object has a callback property, it is assumed it is an unavailable
630 // API, so it is safe to delete. This is checked before GetOrCreateObject is
631 // called.
632 if (object->HasRealNamedCallbackProperty(key)) {
633 object->Delete(key);
634 } else if (object->HasRealNamedProperty(key)) {
635 v8::Handle<v8::Value> value = object->Get(key);
636 CHECK(value->IsObject());
637 return v8::Handle<v8::Object>::Cast(value);
640 v8::Handle<v8::Object> new_object = v8::Object::New();
641 object->Set(key, new_object);
642 return new_object;
645 void Dispatcher::AddOrRemoveBindingsForContext(ChromeV8Context* context) {
646 v8::HandleScope handle_scope(context->isolate());
647 v8::Context::Scope context_scope(context->v8_context());
649 // TODO(kalman): Make the bindings registration have zero overhead then run
650 // the same code regardless of context type.
651 switch (context->context_type()) {
652 case Feature::UNSPECIFIED_CONTEXT:
653 case Feature::WEB_PAGE_CONTEXT: {
654 // Web page context; it's too expensive to run the full bindings code.
655 // Hard-code that the app and webstore APIs are available...
656 RegisterBinding("app", context);
657 RegisterBinding("webstore", context);
659 // ... and that the runtime API might be available if any extension can
660 // connect to it.
661 bool runtime_is_available = false;
662 for (ExtensionSet::const_iterator it = extensions_.begin();
663 it != extensions_.end(); ++it) {
664 ExternallyConnectableInfo* info =
665 static_cast<ExternallyConnectableInfo*>((*it)->GetManifestData(
666 manifest_keys::kExternallyConnectable));
667 if (info && info->matches.MatchesURL(context->GetURL())) {
668 runtime_is_available = true;
669 break;
672 if (runtime_is_available)
673 RegisterBinding("runtime", context);
674 break;
677 case Feature::BLESSED_EXTENSION_CONTEXT:
678 case Feature::UNBLESSED_EXTENSION_CONTEXT:
679 case Feature::CONTENT_SCRIPT_CONTEXT: {
680 // Extension context; iterate through all the APIs and bind the available
681 // ones.
682 FeatureProvider* api_feature_provider = FeatureProvider::GetAPIFeatures();
683 const std::vector<std::string>& apis =
684 api_feature_provider->GetAllFeatureNames();
685 for (std::vector<std::string>::const_iterator it = apis.begin();
686 it != apis.end(); ++it) {
687 const std::string& api_name = *it;
688 Feature* feature = api_feature_provider->GetFeature(api_name);
689 DCHECK(feature);
691 // Internal APIs are included via require(api_name) from internal code
692 // rather than chrome[api_name].
693 if (feature->IsInternal())
694 continue;
696 // If this API name has parent features, then this must be a function or
697 // event, so we should not register.
698 bool parent_feature_available = false;
699 for (Feature* parent = api_feature_provider->GetParent(feature);
700 parent != NULL; parent = api_feature_provider->GetParent(parent)) {
701 if (context->IsAnyFeatureAvailableToContext(parent->name())) {
702 parent_feature_available = true;
703 break;
706 if (parent_feature_available)
707 continue;
709 if (context->IsAnyFeatureAvailableToContext(api_name))
710 RegisterBinding(api_name, context);
712 break;
717 v8::Handle<v8::Object> Dispatcher::GetOrCreateBindObjectIfAvailable(
718 const std::string& api_name,
719 std::string* bind_name,
720 ChromeV8Context* context) {
721 std::vector<std::string> split;
722 base::SplitString(api_name, '.', &split);
724 v8::Handle<v8::Object> bind_object;
726 // Check if this API has an ancestor. If the API's ancestor is available and
727 // the API is not available, don't install the bindings for this API. If
728 // the API is available and its ancestor is not, delete the ancestor and
729 // install the bindings for the API. This is to prevent loading the ancestor
730 // API schema if it will not be needed.
732 // For example:
733 // If app is available and app.window is not, just install app.
734 // If app.window is available and app is not, delete app and install
735 // app.window on a new object so app does not have to be loaded.
736 FeatureProvider* api_feature_provider = FeatureProvider::GetAPIFeatures();
737 std::string ancestor_name;
738 bool only_ancestor_available = false;
740 for (size_t i = 0; i < split.size() - 1; ++i) {
741 ancestor_name += (i ? ".": "") + split[i];
742 if (api_feature_provider->GetFeature(ancestor_name) &&
743 context->GetAvailability(ancestor_name).is_available() &&
744 !context->GetAvailability(api_name).is_available()) {
745 only_ancestor_available = true;
746 break;
749 if (bind_object.IsEmpty()) {
750 bind_object = AsObjectOrEmpty(GetOrCreateChrome(context));
751 if (bind_object.IsEmpty())
752 return v8::Handle<v8::Object>();
754 bind_object = GetOrCreateObject(bind_object, split[i]);
757 if (only_ancestor_available)
758 return v8::Handle<v8::Object>();
760 if (bind_name)
761 *bind_name = split.back();
763 return bind_object.IsEmpty() ?
764 AsObjectOrEmpty(GetOrCreateChrome(context)) : bind_object;
767 void Dispatcher::RegisterBinding(const std::string& api_name,
768 ChromeV8Context* context) {
769 std::string bind_name;
770 v8::Handle<v8::Object> bind_object =
771 GetOrCreateBindObjectIfAvailable(api_name, &bind_name, context);
773 // Empty if the bind object failed to be created, probably because the
774 // extension overrode chrome with a non-object, e.g. window.chrome = true.
775 if (bind_object.IsEmpty())
776 return;
778 v8::Local<v8::String> v8_api_name = v8::String::New(api_name.c_str());
779 if (bind_object->HasRealNamedProperty(v8_api_name)) {
780 // The bind object may already have the property if the API has been
781 // registered before (or if the extension has put something there already,
782 // but, whatevs).
784 // In the former case, we need to re-register the bindings for the APIs
785 // which the extension now has permissions for (if any), but not touch any
786 // others so that we don't destroy state such as event listeners.
788 // TODO(kalman): Only register available APIs to make this all moot.
789 if (bind_object->HasRealNamedCallbackProperty(v8_api_name))
790 return; // lazy binding still there, nothing to do
791 if (bind_object->Get(v8_api_name)->IsObject())
792 return; // binding has already been fully installed
795 ModuleSystem* module_system = context->module_system();
796 if (lazy_bindings_map_.find(api_name) != lazy_bindings_map_.end()) {
797 InstallBindings(module_system, context->v8_context(), api_name);
798 } else if (!source_map_.Contains(api_name)) {
799 module_system->RegisterNativeHandler(
800 api_name,
801 scoped_ptr<NativeHandler>(new BindingGeneratingNativeHandler(
802 module_system,
803 api_name,
804 "binding")));
805 module_system->SetNativeLazyField(bind_object,
806 bind_name,
807 api_name,
808 "binding");
809 } else {
810 module_system->SetLazyField(bind_object,
811 bind_name,
812 api_name,
813 "binding");
817 // NOTE: please use the naming convention "foo_natives" for these.
818 void Dispatcher::RegisterNativeHandlers(ModuleSystem* module_system,
819 ChromeV8Context* context) {
820 module_system->RegisterNativeHandler("event_natives",
821 scoped_ptr<NativeHandler>(EventBindings::Create(this, context)));
822 module_system->RegisterNativeHandler("messaging_natives",
823 scoped_ptr<NativeHandler>(MessagingBindings::Get(this, context)));
824 module_system->RegisterNativeHandler("apiDefinitions",
825 scoped_ptr<NativeHandler>(new ApiDefinitionsNatives(this, context)));
826 module_system->RegisterNativeHandler("sendRequest",
827 scoped_ptr<NativeHandler>(
828 new SendRequestNatives(this, request_sender_.get(), context)));
829 module_system->RegisterNativeHandler("setIcon",
830 scoped_ptr<NativeHandler>(
831 new SetIconNatives(this, request_sender_.get(), context)));
832 module_system->RegisterNativeHandler("activityLogger",
833 scoped_ptr<NativeHandler>(new APIActivityLogger(this, context)));
834 module_system->RegisterNativeHandler("renderViewObserverNatives",
835 scoped_ptr<NativeHandler>(new RenderViewObserverNatives(this, context)));
837 // Natives used by multiple APIs.
838 module_system->RegisterNativeHandler("file_system_natives",
839 scoped_ptr<NativeHandler>(new FileSystemNatives(context)));
841 // Custom bindings.
842 module_system->RegisterNativeHandler("app",
843 scoped_ptr<NativeHandler>(new AppBindings(this, context)));
844 module_system->RegisterNativeHandler("app_runtime",
845 scoped_ptr<NativeHandler>(
846 new AppRuntimeCustomBindings(this, context)));
847 module_system->RegisterNativeHandler("app_window_natives",
848 scoped_ptr<NativeHandler>(
849 new AppWindowCustomBindings(this, context)));
850 module_system->RegisterNativeHandler("context_menus",
851 scoped_ptr<NativeHandler>(
852 new ContextMenusCustomBindings(this, context)));
853 module_system->RegisterNativeHandler(
854 "css_natives", scoped_ptr<NativeHandler>(new CssNativeHandler(context)));
855 module_system->RegisterNativeHandler("document_natives",
856 scoped_ptr<NativeHandler>(
857 new DocumentCustomBindings(this, context)));
858 module_system->RegisterNativeHandler("extension",
859 scoped_ptr<NativeHandler>(
860 new ExtensionCustomBindings(this, context)));
861 module_system->RegisterNativeHandler("sync_file_system",
862 scoped_ptr<NativeHandler>(
863 new SyncFileSystemCustomBindings(this, context)));
864 module_system->RegisterNativeHandler("feedback_private",
865 scoped_ptr<NativeHandler>(new FeedbackPrivateCustomBindings(
866 this, context)));
867 module_system->RegisterNativeHandler("file_browser_handler",
868 scoped_ptr<NativeHandler>(new FileBrowserHandlerCustomBindings(
869 this, context)));
870 module_system->RegisterNativeHandler("file_browser_private",
871 scoped_ptr<NativeHandler>(new FileBrowserPrivateCustomBindings(
872 this, context)));
873 module_system->RegisterNativeHandler("i18n",
874 scoped_ptr<NativeHandler>(
875 new I18NCustomBindings(this, context)));
876 module_system->RegisterNativeHandler(
877 "id_generator",
878 scoped_ptr<NativeHandler>(new IdGeneratorCustomBindings(this, context)));
879 module_system->RegisterNativeHandler("mediaGalleries",
880 scoped_ptr<NativeHandler>(
881 new MediaGalleriesCustomBindings(this, context)));
882 module_system->RegisterNativeHandler("page_actions",
883 scoped_ptr<NativeHandler>(
884 new PageActionsCustomBindings(this, context)));
885 module_system->RegisterNativeHandler("page_capture",
886 scoped_ptr<NativeHandler>(
887 new PageCaptureCustomBindings(this, context)));
888 module_system->RegisterNativeHandler("runtime",
889 scoped_ptr<NativeHandler>(new RuntimeCustomBindings(this, context)));
890 module_system->RegisterNativeHandler("tabs",
891 scoped_ptr<NativeHandler>(new TabsCustomBindings(this, context)));
892 module_system->RegisterNativeHandler("webstore",
893 scoped_ptr<NativeHandler>(new WebstoreBindings(this, context)));
896 void Dispatcher::PopulateSourceMap() {
897 // Libraries.
898 source_map_.RegisterSource("entryIdManager", IDR_ENTRY_ID_MANAGER);
899 source_map_.RegisterSource(kEventBindings, IDR_EVENT_BINDINGS_JS);
900 source_map_.RegisterSource("imageUtil", IDR_IMAGE_UTIL_JS);
901 source_map_.RegisterSource("json_schema", IDR_JSON_SCHEMA_JS);
902 source_map_.RegisterSource("lastError", IDR_LAST_ERROR_JS);
903 source_map_.RegisterSource("messaging", IDR_MESSAGING_JS);
904 source_map_.RegisterSource("messaging_utils", IDR_MESSAGING_UTILS_JS);
905 source_map_.RegisterSource(kSchemaUtils, IDR_SCHEMA_UTILS_JS);
906 source_map_.RegisterSource("sendRequest", IDR_SEND_REQUEST_JS);
907 source_map_.RegisterSource("setIcon", IDR_SET_ICON_JS);
908 source_map_.RegisterSource("test", IDR_TEST_CUSTOM_BINDINGS_JS);
909 source_map_.RegisterSource("unload_event", IDR_UNLOAD_EVENT_JS);
910 source_map_.RegisterSource("utils", IDR_UTILS_JS);
912 // Custom bindings.
913 source_map_.RegisterSource("app", IDR_APP_CUSTOM_BINDINGS_JS);
914 source_map_.RegisterSource("app.runtime", IDR_APP_RUNTIME_CUSTOM_BINDINGS_JS);
915 source_map_.RegisterSource("app.window", IDR_APP_WINDOW_CUSTOM_BINDINGS_JS);
916 source_map_.RegisterSource("bluetooth", IDR_BLUETOOTH_CUSTOM_BINDINGS_JS);
917 source_map_.RegisterSource("browserAction",
918 IDR_BROWSER_ACTION_CUSTOM_BINDINGS_JS);
919 source_map_.RegisterSource("contextMenus",
920 IDR_CONTEXT_MENUS_CUSTOM_BINDINGS_JS);
921 source_map_.RegisterSource("declarativeContent",
922 IDR_DECLARATIVE_CONTENT_CUSTOM_BINDINGS_JS);
923 source_map_.RegisterSource("declarativeWebRequest",
924 IDR_DECLARATIVE_WEBREQUEST_CUSTOM_BINDINGS_JS);
925 source_map_.RegisterSource("downloads",
926 IDR_DOWNLOADS_CUSTOM_BINDINGS_JS);
927 source_map_.RegisterSource("experimental.offscreen",
928 IDR_EXPERIMENTAL_OFFSCREENTABS_CUSTOM_BINDINGS_JS);
929 source_map_.RegisterSource("extension", IDR_EXTENSION_CUSTOM_BINDINGS_JS);
930 source_map_.RegisterSource("feedbackPrivate",
931 IDR_FEEDBACK_PRIVATE_CUSTOM_BINDINGS_JS);
932 source_map_.RegisterSource("fileBrowserHandler",
933 IDR_FILE_BROWSER_HANDLER_CUSTOM_BINDINGS_JS);
934 source_map_.RegisterSource("fileBrowserPrivate",
935 IDR_FILE_BROWSER_PRIVATE_CUSTOM_BINDINGS_JS);
936 source_map_.RegisterSource("fileSystem",
937 IDR_FILE_SYSTEM_CUSTOM_BINDINGS_JS);
938 source_map_.RegisterSource("i18n", IDR_I18N_CUSTOM_BINDINGS_JS);
939 source_map_.RegisterSource("input.ime", IDR_INPUT_IME_CUSTOM_BINDINGS_JS);
940 source_map_.RegisterSource("mediaGalleries",
941 IDR_MEDIA_GALLERIES_CUSTOM_BINDINGS_JS);
942 source_map_.RegisterSource("notifications",
943 IDR_NOTIFICATIONS_CUSTOM_BINDINGS_JS);
944 source_map_.RegisterSource("omnibox", IDR_OMNIBOX_CUSTOM_BINDINGS_JS);
945 source_map_.RegisterSource("pageActions",
946 IDR_PAGE_ACTIONS_CUSTOM_BINDINGS_JS);
947 source_map_.RegisterSource("pageAction", IDR_PAGE_ACTION_CUSTOM_BINDINGS_JS);
948 source_map_.RegisterSource("pageCapture",
949 IDR_PAGE_CAPTURE_CUSTOM_BINDINGS_JS);
950 source_map_.RegisterSource("permissions", IDR_PERMISSIONS_CUSTOM_BINDINGS_JS);
951 source_map_.RegisterSource("runtime", IDR_RUNTIME_CUSTOM_BINDINGS_JS);
952 source_map_.RegisterSource("syncFileSystem",
953 IDR_SYNC_FILE_SYSTEM_CUSTOM_BINDINGS_JS);
954 source_map_.RegisterSource("systemIndicator",
955 IDR_SYSTEM_INDICATOR_CUSTOM_BINDINGS_JS);
956 source_map_.RegisterSource("tabCapture", IDR_TAB_CAPTURE_CUSTOM_BINDINGS_JS);
957 source_map_.RegisterSource("tabs", IDR_TABS_CUSTOM_BINDINGS_JS);
958 source_map_.RegisterSource("tts", IDR_TTS_CUSTOM_BINDINGS_JS);
959 source_map_.RegisterSource("ttsEngine", IDR_TTS_ENGINE_CUSTOM_BINDINGS_JS);
960 source_map_.RegisterSource("webRequest", IDR_WEB_REQUEST_CUSTOM_BINDINGS_JS);
961 source_map_.RegisterSource("webRequestInternal",
962 IDR_WEB_REQUEST_INTERNAL_CUSTOM_BINDINGS_JS);
963 source_map_.RegisterSource("webrtc.castSendTransport",
964 IDR_WEBRTC_CAST_SEND_TRANSPORT_CUSTOM_BINDINGS_JS);
965 source_map_.RegisterSource("webrtc.udpTransport",
966 IDR_WEBRTC_UDP_TRANSPORT_CUSTOM_BINDINGS_JS);
967 source_map_.RegisterSource("webstore", IDR_WEBSTORE_CUSTOM_BINDINGS_JS);
968 source_map_.RegisterSource("windowControls", IDR_WINDOW_CONTROLS_JS);
969 source_map_.RegisterSource("binding", IDR_BINDING_JS);
971 // Custom types sources.
972 source_map_.RegisterSource("ChromeSetting", IDR_CHROME_SETTING_JS);
973 source_map_.RegisterSource("StorageArea", IDR_STORAGE_AREA_JS);
974 source_map_.RegisterSource("ContentSetting", IDR_CONTENT_SETTING_JS);
975 source_map_.RegisterSource("ChromeDirectSetting",
976 IDR_CHROME_DIRECT_SETTING_JS);
978 // Platform app sources that are not API-specific..
979 source_map_.RegisterSource("tagWatcher", IDR_TAG_WATCHER_JS);
980 // Note: webView not webview so that this doesn't interfere with the
981 // chrome.webview API bindings.
982 source_map_.RegisterSource("webView", IDR_WEB_VIEW_JS);
983 source_map_.RegisterSource("webViewExperimental",
984 IDR_WEB_VIEW_EXPERIMENTAL_JS);
985 source_map_.RegisterSource("denyWebView", IDR_WEB_VIEW_DENY_JS);
986 source_map_.RegisterSource("adView", IDR_AD_VIEW_JS);
987 source_map_.RegisterSource("denyAdView", IDR_AD_VIEW_DENY_JS);
988 source_map_.RegisterSource("platformApp", IDR_PLATFORM_APP_JS);
989 source_map_.RegisterSource("injectAppTitlebar", IDR_INJECT_APP_TITLEBAR_JS);
992 void Dispatcher::PopulateLazyBindingsMap() {
993 lazy_bindings_map_["app"] = InstallAppBindings;
994 lazy_bindings_map_["webstore"] = InstallWebstoreBindings;
997 void Dispatcher::InstallBindings(ModuleSystem* module_system,
998 v8::Handle<v8::Context> v8_context,
999 const std::string& api) {
1000 std::map<std::string, BindingInstaller>::const_iterator lazy_binding =
1001 lazy_bindings_map_.find(api);
1002 if (lazy_binding != lazy_bindings_map_.end()) {
1003 v8::Handle<v8::Object> global(v8_context->Global());
1004 v8::Handle<v8::Object> chrome =
1005 global->Get(v8::String::New("chrome"))->ToObject();
1006 (*lazy_binding->second)(module_system, chrome);
1007 } else {
1008 module_system->Require(api);
1012 void Dispatcher::DidCreateScriptContext(
1013 WebFrame* frame, v8::Handle<v8::Context> v8_context, int extension_group,
1014 int world_id) {
1015 #if !defined(ENABLE_EXTENSIONS)
1016 return;
1017 #endif
1019 std::string extension_id = GetExtensionID(frame, world_id);
1021 const Extension* extension = extensions_.GetByID(extension_id);
1022 if (!extension && !extension_id.empty()) {
1023 // There are conditions where despite a context being associated with an
1024 // extension, no extension actually gets found. Ignore "invalid" because
1025 // CSP blocks extension page loading by switching the extension ID to
1026 // "invalid". This isn't interesting.
1027 if (extension_id != "invalid") {
1028 LOG(ERROR) << "Extension \"" << extension_id << "\" not found";
1029 RenderThread::Get()->RecordUserMetrics("ExtensionNotFound_ED");
1032 extension_id = "";
1035 Feature::Context context_type = ClassifyJavaScriptContext(
1036 extension_id, extension_group,
1037 UserScriptSlave::GetDataSourceURLForFrame(frame),
1038 frame->document().securityOrigin());
1040 ChromeV8Context* context =
1041 new ChromeV8Context(v8_context, frame, extension, context_type);
1042 v8_context_set_.Add(context);
1045 scoped_ptr<ModuleSystem> module_system(new ModuleSystem(context,
1046 &source_map_));
1047 context->set_module_system(module_system.Pass());
1049 ModuleSystem* module_system = context->module_system();
1051 // Enable natives in startup.
1052 ModuleSystem::NativesEnabledScope natives_enabled_scope(
1053 module_system);
1055 RegisterNativeHandlers(module_system, context);
1057 module_system->RegisterNativeHandler("chrome",
1058 scoped_ptr<NativeHandler>(new ChromeNativeHandler(context)));
1059 module_system->RegisterNativeHandler("print",
1060 scoped_ptr<NativeHandler>(new PrintNativeHandler(context)));
1061 module_system->RegisterNativeHandler("lazy_background_page",
1062 scoped_ptr<NativeHandler>(
1063 new LazyBackgroundPageNativeHandler(this, context)));
1064 module_system->RegisterNativeHandler("logging",
1065 scoped_ptr<NativeHandler>(new LoggingNativeHandler(context)));
1066 module_system->RegisterNativeHandler("schema_registry",
1067 v8_schema_registry_->AsNativeHandler());
1068 module_system->RegisterNativeHandler("v8_context",
1069 scoped_ptr<NativeHandler>(new V8ContextNativeHandler(context, this)));
1070 module_system->RegisterNativeHandler("test_features",
1071 scoped_ptr<NativeHandler>(new TestFeaturesNativeHandler(context)));
1073 int manifest_version = extension ? extension->manifest_version() : 1;
1074 bool send_request_disabled =
1075 (extension && Manifest::IsUnpackedLocation(extension->location()) &&
1076 BackgroundInfo::HasLazyBackgroundPage(extension));
1077 module_system->RegisterNativeHandler("process",
1078 scoped_ptr<NativeHandler>(new ProcessInfoNativeHandler(
1079 this, context, context->GetExtensionID(),
1080 context->GetContextTypeDescription(),
1081 ChromeRenderProcessObserver::is_incognito_process(),
1082 manifest_version, send_request_disabled)));
1084 // chrome.Event is part of the public API (although undocumented). Make it
1085 // lazily evalulate to Event from event_bindings.js. For extensions only
1086 // though, not all webpages!
1087 if (context->extension()) {
1088 v8::Handle<v8::Object> chrome = AsObjectOrEmpty(GetOrCreateChrome(context));
1089 if (!chrome.IsEmpty())
1090 module_system->SetLazyField(chrome, "Event", kEventBindings, "Event");
1093 AddOrRemoveBindingsForContext(context);
1095 bool is_within_platform_app = IsWithinPlatformApp();
1096 // Inject custom JS into the platform app context.
1097 if (is_within_platform_app) {
1098 module_system->Require("platformApp");
1101 if (context_type == Feature::BLESSED_EXTENSION_CONTEXT &&
1102 is_within_platform_app &&
1103 GetCurrentChannel() <= chrome::VersionInfo::CHANNEL_DEV &&
1104 CommandLine::ForCurrentProcess()->HasSwitch(
1105 switches::kEnableAppWindowControls)) {
1106 module_system->Require("windowControls");
1109 // Currently only platform apps and whitelisted component extensions support
1110 // the <webview> tag, because the "denyWebView" module will affect the
1111 // performance of DOM modifications (http://crbug.com/196453).
1112 // We used to limit WebView to |BLESSED_EXTENSION_CONTEXT| within platform
1113 // apps. An ext/app runs in a blessed extension context, if it is the active
1114 // extension in the current process, in other words, if it is loaded in a top
1115 // frame. To support webview in a non-frame extension, we have to allow
1116 // unblessed extension context as well.
1117 if (context_type == Feature::BLESSED_EXTENSION_CONTEXT ||
1118 context_type == Feature::UNBLESSED_EXTENSION_CONTEXT) {
1119 // Note: setting up the WebView class here, not the chrome.webview API.
1120 // The API will be automatically set up when first used.
1121 if (extension->HasAPIPermission(APIPermission::kWebView)) {
1122 module_system->Require("webView");
1123 // TODO(mtomasz): Remove the Files app from the whitelist in M-31.
1124 // crbug.com/297936
1125 bool includeExperimental =
1126 GetCurrentChannel() <= chrome::VersionInfo::CHANNEL_DEV ||
1127 extension->id() == extension_misc::kIdentityApiUiAppId ||
1128 extension->id() == "hhaomjibdihmijegdhdafkllkbggdgoj"; // Files App.
1129 if (!includeExperimental) {
1130 // TODO(asargent) We need a whitelist for webview experimental.
1131 // crbug.com/264852
1132 std::string id_hash = base::SHA1HashString(extension->id());
1133 std::string hexencoded_id_hash = base::HexEncode(id_hash.c_str(),
1134 id_hash.length());
1135 if (hexencoded_id_hash == "8C3741E3AF0B93B6E8E0DDD499BB0B74839EA578" ||
1136 hexencoded_id_hash == "E703483CEF33DEC18B4B6DD84B5C776FB9182BDB" ||
1137 hexencoded_id_hash == "1A26E32DE447A17CBE5E9750CDBA78F58539B39C" ||
1138 hexencoded_id_hash == "59048028102D7B4C681DBC7BC6CD980C3DC66DA3")
1139 includeExperimental = true;
1141 if (includeExperimental)
1142 module_system->Require("webViewExperimental");
1143 } else {
1144 module_system->Require("denyWebView");
1148 // Same comment as above for <adview> tag.
1149 if (context_type == Feature::BLESSED_EXTENSION_CONTEXT &&
1150 is_within_platform_app) {
1151 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnableAdview)) {
1152 if (extension->HasAPIPermission(APIPermission::kAdView)) {
1153 module_system->Require("adView");
1154 } else {
1155 module_system->Require("denyAdView");
1160 VLOG(1) << "Num tracked contexts: " << v8_context_set_.size();
1163 std::string Dispatcher::GetExtensionID(const WebFrame* frame, int world_id) {
1164 if (world_id != 0) {
1165 // Isolated worlds (content script).
1166 return user_script_slave_->GetExtensionIdForIsolatedWorld(world_id);
1169 // TODO(kalman): Delete this check.
1170 if (frame->document().securityOrigin().isUnique())
1171 return std::string();
1173 // Extension pages (chrome-extension:// URLs).
1174 GURL frame_url = UserScriptSlave::GetDataSourceURLForFrame(frame);
1175 return extensions_.GetExtensionOrAppIDByURL(frame_url);
1178 bool Dispatcher::IsWithinPlatformApp() {
1179 for (std::set<std::string>::iterator iter = active_extension_ids_.begin();
1180 iter != active_extension_ids_.end(); ++iter) {
1181 const Extension* extension = extensions_.GetByID(*iter);
1182 if (extension && extension->is_platform_app())
1183 return true;
1185 return false;
1188 void Dispatcher::WillReleaseScriptContext(
1189 WebFrame* frame, v8::Handle<v8::Context> v8_context, int world_id) {
1190 ChromeV8Context* context = v8_context_set_.GetByV8Context(v8_context);
1191 if (!context)
1192 return;
1194 context->DispatchOnUnloadEvent();
1195 // TODO(kalman): add an invalidation observer interface to ChromeV8Context.
1196 request_sender_->InvalidateSource(context);
1198 v8_context_set_.Remove(context);
1199 VLOG(1) << "Num tracked contexts: " << v8_context_set_.size();
1202 void Dispatcher::DidCreateDocumentElement(WebKit::WebFrame* frame) {
1203 if (IsWithinPlatformApp()) {
1204 // WebKit doesn't let us define an additional user agent stylesheet, so we
1205 // insert the default platform app stylesheet into all documents that are
1206 // loaded in each app.
1207 std::string stylesheet =
1208 ResourceBundle::GetSharedInstance().
1209 GetRawDataResource(IDR_PLATFORM_APP_CSS).as_string();
1210 ReplaceFirstSubstringAfterOffset(&stylesheet, 0,
1211 "$FONTFAMILY", system_font_family_);
1212 ReplaceFirstSubstringAfterOffset(&stylesheet, 0,
1213 "$FONTSIZE", system_font_size_);
1214 frame->document().insertUserStyleSheet(
1215 WebString::fromUTF8(stylesheet), WebDocument::UserStyleUserLevel);
1218 content_watcher_->DidCreateDocumentElement(frame);
1221 void Dispatcher::DidMatchCSS(
1222 WebKit::WebFrame* frame,
1223 const WebKit::WebVector<WebKit::WebString>& newly_matching_selectors,
1224 const WebKit::WebVector<WebKit::WebString>& stopped_matching_selectors) {
1225 content_watcher_->DidMatchCSS(
1226 frame, newly_matching_selectors, stopped_matching_selectors);
1230 void Dispatcher::OnActivateExtension(const std::string& extension_id) {
1231 const Extension* extension = extensions_.GetByID(extension_id);
1232 if (!extension) {
1233 // Extension was activated but was never loaded. This probably means that
1234 // the renderer failed to load it (or the browser failed to tell us when it
1235 // did). Failures shouldn't happen, but instead of crashing there (which
1236 // executes on all renderers) be conservative and only crash in the renderer
1237 // of the extension which failed to load; this one.
1238 std::string& error = extension_load_errors_[extension_id];
1239 char minidump[256];
1240 base::debug::Alias(&minidump);
1241 base::snprintf(minidump, arraysize(minidump),
1242 "e::dispatcher:%s:%s", extension_id.c_str(), error.c_str());
1243 CHECK(extension) << extension_id << " was never loaded: " << error;
1246 active_extension_ids_.insert(extension_id);
1248 // This is called when starting a new extension page, so start the idle
1249 // handler ticking.
1250 RenderThread::Get()->ScheduleIdleHandler(kInitialExtensionIdleHandlerDelayMs);
1252 UpdateActiveExtensions();
1254 if (is_webkit_initialized_) {
1255 InitOriginPermissions(extension);
1256 DOMActivityLogger::AttachToWorld(DOMActivityLogger::kMainWorldId,
1257 extension_id);
1261 void Dispatcher::InitOriginPermissions(const Extension* extension) {
1262 // TODO(jstritar): We should try to remove this special case. Also, these
1263 // whitelist entries need to be updated when the kManagement permission
1264 // changes.
1265 if (extension->HasAPIPermission(APIPermission::kManagement)) {
1266 WebSecurityPolicy::addOriginAccessWhitelistEntry(
1267 extension->url(),
1268 WebString::fromUTF8(chrome::kChromeUIScheme),
1269 WebString::fromUTF8(chrome::kChromeUIExtensionIconHost),
1270 false);
1273 AddOrRemoveOriginPermissions(
1274 UpdatedExtensionPermissionsInfo::ADDED,
1275 extension,
1276 extension->GetActivePermissions()->explicit_hosts());
1279 void Dispatcher::AddOrRemoveOriginPermissions(
1280 UpdatedExtensionPermissionsInfo::Reason reason,
1281 const Extension* extension,
1282 const URLPatternSet& origins) {
1283 for (URLPatternSet::const_iterator i = origins.begin();
1284 i != origins.end(); ++i) {
1285 const char* schemes[] = {
1286 content::kHttpScheme,
1287 content::kHttpsScheme,
1288 chrome::kFileScheme,
1289 chrome::kChromeUIScheme,
1291 for (size_t j = 0; j < arraysize(schemes); ++j) {
1292 if (i->MatchesScheme(schemes[j])) {
1293 ((reason == UpdatedExtensionPermissionsInfo::REMOVED) ?
1294 WebSecurityPolicy::removeOriginAccessWhitelistEntry :
1295 WebSecurityPolicy::addOriginAccessWhitelistEntry)(
1296 extension->url(),
1297 WebString::fromUTF8(schemes[j]),
1298 WebString::fromUTF8(i->host()),
1299 i->match_subdomains());
1305 void Dispatcher::EnableCustomElementWhiteList() {
1306 WebKit::WebRuntimeFeatures::enableEmbedderCustomElements(true);
1307 WebKit::WebCustomElement::addEmbedderCustomElementName("webview");
1308 // TODO(fsamuel): Add <adview> to the whitelist once it has been converted
1309 // into a custom element.
1310 WebKit::WebCustomElement::addEmbedderCustomElementName("browser-plugin");
1313 void Dispatcher::AddOrRemoveBindings(const std::string& extension_id) {
1314 v8_context_set().ForEach(
1315 extension_id,
1316 NULL, // all render views
1317 base::Bind(&Dispatcher::AddOrRemoveBindingsForContext,
1318 base::Unretained(this)));
1321 void Dispatcher::OnUpdatePermissions(int reason_id,
1322 const std::string& extension_id,
1323 const APIPermissionSet& apis,
1324 const URLPatternSet& explicit_hosts,
1325 const URLPatternSet& scriptable_hosts) {
1326 const Extension* extension = extensions_.GetByID(extension_id);
1327 if (!extension)
1328 return;
1330 scoped_refptr<const PermissionSet> delta =
1331 new PermissionSet(apis, explicit_hosts, scriptable_hosts);
1332 scoped_refptr<const PermissionSet> old_active =
1333 extension->GetActivePermissions();
1334 UpdatedExtensionPermissionsInfo::Reason reason =
1335 static_cast<UpdatedExtensionPermissionsInfo::Reason>(reason_id);
1337 const PermissionSet* new_active = NULL;
1338 switch (reason) {
1339 case UpdatedExtensionPermissionsInfo::ADDED:
1340 new_active = PermissionSet::CreateUnion(old_active.get(), delta.get());
1341 break;
1342 case UpdatedExtensionPermissionsInfo::REMOVED:
1343 new_active =
1344 PermissionSet::CreateDifference(old_active.get(), delta.get());
1345 break;
1348 PermissionsData::SetActivePermissions(extension, new_active);
1349 AddOrRemoveOriginPermissions(reason, extension, explicit_hosts);
1350 AddOrRemoveBindings(extension->id());
1353 void Dispatcher::OnUpdateTabSpecificPermissions(
1354 int page_id,
1355 int tab_id,
1356 const std::string& extension_id,
1357 const URLPatternSet& origin_set) {
1358 RenderView* view = TabFinder::Find(tab_id);
1360 // For now, the message should only be sent to the render view that contains
1361 // the target tab. This may change. Either way, if this is the target tab it
1362 // gives us the chance to check against the page ID to avoid races.
1363 DCHECK(view);
1364 if (view && view->GetPageId() != page_id)
1365 return;
1367 const Extension* extension = extensions_.GetByID(extension_id);
1368 if (!extension)
1369 return;
1371 PermissionsData::UpdateTabSpecificPermissions(
1372 extension,
1373 tab_id,
1374 new PermissionSet(APIPermissionSet(), origin_set, URLPatternSet()));
1377 void Dispatcher::OnClearTabSpecificPermissions(
1378 int tab_id,
1379 const std::vector<std::string>& extension_ids) {
1380 for (std::vector<std::string>::const_iterator it = extension_ids.begin();
1381 it != extension_ids.end(); ++it) {
1382 const Extension* extension = extensions_.GetByID(*it);
1383 if (extension)
1384 PermissionsData::ClearTabSpecificPermissions(extension, tab_id);
1388 void Dispatcher::OnUpdateUserScripts(
1389 base::SharedMemoryHandle scripts) {
1390 DCHECK(base::SharedMemory::IsHandleValid(scripts)) << "Bad scripts handle";
1391 user_script_slave_->UpdateScripts(scripts);
1392 UpdateActiveExtensions();
1395 void Dispatcher::UpdateActiveExtensions() {
1396 // In single-process mode, the browser process reports the active extensions.
1397 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kSingleProcess))
1398 return;
1400 std::set<std::string> active_extensions = active_extension_ids_;
1401 user_script_slave_->GetActiveExtensions(&active_extensions);
1402 crash_keys::SetActiveExtensions(active_extensions);
1405 void Dispatcher::OnUsingWebRequestAPI(
1406 bool adblock, bool adblock_plus, bool other) {
1407 webrequest_adblock_ = adblock;
1408 webrequest_adblock_plus_ = adblock_plus;
1409 webrequest_other_ = other;
1412 void Dispatcher::OnShouldSuspend(const std::string& extension_id,
1413 int sequence_id) {
1414 RenderThread::Get()->Send(
1415 new ExtensionHostMsg_ShouldSuspendAck(extension_id, sequence_id));
1418 void Dispatcher::OnSuspend(const std::string& extension_id) {
1419 // Dispatch the suspend event. This doesn't go through the standard event
1420 // dispatch machinery because it requires special handling. We need to let
1421 // the browser know when we are starting and stopping the event dispatch, so
1422 // that it still considers the extension idle despite any activity the suspend
1423 // event creates.
1424 DispatchEvent(extension_id, kOnSuspendEvent);
1425 RenderThread::Get()->Send(new ExtensionHostMsg_SuspendAck(extension_id));
1428 void Dispatcher::OnCancelSuspend(const std::string& extension_id) {
1429 DispatchEvent(extension_id, kOnSuspendCanceledEvent);
1432 // TODO(kalman): This is checking for the wrong thing, it should be checking if
1433 // the frame's security origin is unique. The extension sandbox directive is
1434 // checked for in chrome/common/extensions/csp_handler.cc.
1435 bool Dispatcher::IsSandboxedPage(const GURL& url) const {
1436 if (url.SchemeIs(kExtensionScheme)) {
1437 const Extension* extension = extensions_.GetByID(url.host());
1438 if (extension) {
1439 return SandboxedPageInfo::IsSandboxedPage(extension, url.path());
1442 return false;
1445 Feature::Context Dispatcher::ClassifyJavaScriptContext(
1446 const std::string& extension_id,
1447 int extension_group,
1448 const GURL& url,
1449 const WebKit::WebSecurityOrigin& origin) {
1450 DCHECK_GE(extension_group, 0);
1451 if (extension_group == EXTENSION_GROUP_CONTENT_SCRIPTS) {
1452 return extensions_.Contains(extension_id) ?
1453 Feature::CONTENT_SCRIPT_CONTEXT : Feature::UNSPECIFIED_CONTEXT;
1456 // We have an explicit check for sandboxed pages before checking whether the
1457 // extension is active in this process because:
1458 // 1. Sandboxed pages run in the same process as regular extension pages, so
1459 // the extension is considered active.
1460 // 2. ScriptContext creation (which triggers bindings injection) happens
1461 // before the SecurityContext is updated with the sandbox flags (after
1462 // reading the CSP header), so the caller can't check if the context's
1463 // security origin is unique yet.
1464 if (IsSandboxedPage(url))
1465 return Feature::WEB_PAGE_CONTEXT;
1467 if (IsExtensionActive(extension_id))
1468 return Feature::BLESSED_EXTENSION_CONTEXT;
1470 // TODO(kalman): This isUnique() check is wrong, it should be performed as
1471 // part of IsSandboxedPage().
1472 if (!origin.isUnique() && extensions_.ExtensionBindingsAllowed(url)) {
1473 return extensions_.Contains(extension_id) ?
1474 Feature::UNBLESSED_EXTENSION_CONTEXT : Feature::UNSPECIFIED_CONTEXT;
1477 if (url.is_valid())
1478 return Feature::WEB_PAGE_CONTEXT;
1480 return Feature::UNSPECIFIED_CONTEXT;
1483 void Dispatcher::OnExtensionResponse(int request_id,
1484 bool success,
1485 const base::ListValue& response,
1486 const std::string& error) {
1487 request_sender_->HandleResponse(request_id, success, response, error);
1490 bool Dispatcher::CheckContextAccessToExtensionAPI(
1491 const std::string& function_name, ChromeV8Context* context) const {
1492 if (!context) {
1493 DLOG(ERROR) << "Not in a v8::Context";
1494 return false;
1497 if (!context->extension()) {
1498 v8::ThrowException(
1499 v8::Exception::Error(v8::String::New("Not in an extension.")));
1500 return false;
1503 // Theoretically we could end up with bindings being injected into sandboxed
1504 // frames, for example content scripts. Don't let them execute API functions.
1505 WebKit::WebFrame* frame = context->web_frame();
1506 if (IsSandboxedPage(UserScriptSlave::GetDataSourceURLForFrame(frame))) {
1507 static const char kMessage[] =
1508 "%s cannot be used within a sandboxed frame.";
1509 std::string error_msg = base::StringPrintf(kMessage, function_name.c_str());
1510 v8::ThrowException(
1511 v8::Exception::Error(v8::String::New(error_msg.c_str())));
1512 return false;
1515 Feature::Availability availability = context->GetAvailability(function_name);
1516 if (!availability.is_available()) {
1517 v8::ThrowException(v8::Exception::Error(
1518 v8::String::New(availability.message().c_str())));
1521 return availability.is_available();
1524 void Dispatcher::DispatchEvent(const std::string& extension_id,
1525 const std::string& event_name) const {
1526 base::ListValue args;
1527 args.Set(0, new base::StringValue(event_name));
1528 args.Set(1, new base::ListValue());
1530 // Needed for Windows compilation, since kEventBindings is declared extern.
1531 const char* local_event_bindings = kEventBindings;
1532 v8_context_set_.ForEach(
1533 extension_id,
1534 NULL, // all render views
1535 base::Bind(&CallModuleMethod,
1536 local_event_bindings,
1537 kEventDispatchFunction,
1538 &args));
1541 void Dispatcher::InvokeModuleSystemMethod(
1542 content::RenderView* render_view,
1543 const std::string& extension_id,
1544 const std::string& module_name,
1545 const std::string& function_name,
1546 const base::ListValue& args,
1547 bool user_gesture) {
1548 scoped_ptr<WebScopedUserGesture> web_user_gesture;
1549 if (user_gesture)
1550 web_user_gesture.reset(new WebScopedUserGesture);
1552 v8_context_set_.ForEach(
1553 extension_id,
1554 render_view,
1555 base::Bind(&CallModuleMethod, module_name, function_name, &args));
1557 // Reset the idle handler each time there's any activity like event or message
1558 // dispatch, for which Invoke is the chokepoint.
1559 if (is_extension_process_) {
1560 RenderThread::Get()->ScheduleIdleHandler(
1561 kInitialExtensionIdleHandlerDelayMs);
1564 // Tell the browser process when an event has been dispatched with a lazy
1565 // background page active.
1566 const Extension* extension = extensions_.GetByID(extension_id);
1567 if (extension && BackgroundInfo::HasLazyBackgroundPage(extension) &&
1568 module_name == kEventBindings &&
1569 function_name == kEventDispatchFunction) {
1570 RenderView* background_view =
1571 ExtensionHelper::GetBackgroundPage(extension_id);
1572 if (background_view) {
1573 background_view->Send(new ExtensionHostMsg_EventAck(
1574 background_view->GetRoutingID()));
1579 } // namespace extensions