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
{
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
);
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
{
145 explicit TestFeaturesNativeHandler(ChromeV8Context
* context
)
146 : ObjectBackedNativeHandler(context
) {
147 RouteFunction("GetAPIFeatures",
148 base::Bind(&TestFeaturesNativeHandler::GetAPIFeatures
,
149 base::Unretained(this)));
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
{
166 V8ContextNativeHandler(ChromeV8Context
* context
, Dispatcher
* dispatcher
)
167 : ObjectBackedNativeHandler(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)));
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(
201 args
.GetReturnValue().Set(context
->module_system()->NewInstance());
204 ChromeV8Context
* context_
;
205 Dispatcher
* dispatcher_
;
208 class ChromeNativeHandler
: public ObjectBackedNativeHandler
{
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
{
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)
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
{
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
) {
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
) {
270 RenderView
* render_view
= context()->GetRenderView();
271 if (IsContextLazyBackgroundPage(render_view
, context()->extension())) {
272 render_view
->Send(new ExtensionHostMsg_DecrementLazyKeepaliveCount(
273 render_view
->GetRoutingID()));
278 bool IsContextLazyBackgroundPage(RenderView
* render_view
,
279 const Extension
* extension
) {
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
{
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)));
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();
389 arguments
.push_back(converter
->ToV8Value(*it
, context
->v8_context()));
392 context
->module_system()->CallModuleMethod(
393 module_name
, method_name
, &arguments
);
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));
421 PopulateLazyBindingsMap();
424 Dispatcher::~Dispatcher() {
427 bool Dispatcher::OnControlMessageReceived(const IPC::Message
& message
) {
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()
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
);
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
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
,
524 InvokeModuleSystemMethod(
525 NULL
, extension_id
, module_name
, function_name
, args
, user_gesture
);
528 void Dispatcher::OnDispatchOnConnect(
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(),
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
) {
562 scoped_refptr
<const Extension
> extension
= i
->ConvertToExtension(&error
);
563 if (!extension
.get()) {
564 extension_load_errors_
[i
->id
] = error
;
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
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 {
619 active_extension_ids_
.find(extension_id
) != active_extension_ids_
.end();
621 CHECK(extensions_
.Contains(extension_id
));
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
632 if (object
->HasRealNamedCallbackProperty(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
);
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
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;
672 if (runtime_is_available
)
673 RegisterBinding("runtime", context
);
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
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
);
691 // Internal APIs are included via require(api_name) from internal code
692 // rather than chrome[api_name].
693 if (feature
->IsInternal())
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;
706 if (parent_feature_available
)
709 if (context
->IsAnyFeatureAvailableToContext(api_name
))
710 RegisterBinding(api_name
, context
);
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.
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;
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
>();
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())
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,
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(
801 scoped_ptr
<NativeHandler
>(new BindingGeneratingNativeHandler(
805 module_system
->SetNativeLazyField(bind_object
,
810 module_system
->SetLazyField(bind_object
,
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
)));
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(
867 module_system
->RegisterNativeHandler("file_browser_handler",
868 scoped_ptr
<NativeHandler
>(new FileBrowserHandlerCustomBindings(
870 module_system
->RegisterNativeHandler("file_browser_private",
871 scoped_ptr
<NativeHandler
>(new FileBrowserPrivateCustomBindings(
873 module_system
->RegisterNativeHandler("i18n",
874 scoped_ptr
<NativeHandler
>(
875 new I18NCustomBindings(this, context
)));
876 module_system
->RegisterNativeHandler(
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() {
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
);
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
);
1008 module_system
->Require(api
);
1012 void Dispatcher::DidCreateScriptContext(
1013 WebFrame
* frame
, v8::Handle
<v8::Context
> v8_context
, int extension_group
,
1015 #if !defined(ENABLE_EXTENSIONS)
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");
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
,
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(
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.
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.
1132 std::string id_hash
= base::SHA1HashString(extension
->id());
1133 std::string hexencoded_id_hash
= base::HexEncode(id_hash
.c_str(),
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");
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");
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())
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
);
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
);
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
];
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
1250 RenderThread::Get()->ScheduleIdleHandler(kInitialExtensionIdleHandlerDelayMs
);
1252 UpdateActiveExtensions();
1254 if (is_webkit_initialized_
) {
1255 InitOriginPermissions(extension
);
1256 DOMActivityLogger::AttachToWorld(DOMActivityLogger::kMainWorldId
,
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
1265 if (extension
->HasAPIPermission(APIPermission::kManagement
)) {
1266 WebSecurityPolicy::addOriginAccessWhitelistEntry(
1268 WebString::fromUTF8(chrome::kChromeUIScheme
),
1269 WebString::fromUTF8(chrome::kChromeUIExtensionIconHost
),
1273 AddOrRemoveOriginPermissions(
1274 UpdatedExtensionPermissionsInfo::ADDED
,
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
)(
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(
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
);
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
;
1339 case UpdatedExtensionPermissionsInfo::ADDED
:
1340 new_active
= PermissionSet::CreateUnion(old_active
.get(), delta
.get());
1342 case UpdatedExtensionPermissionsInfo::REMOVED
:
1344 PermissionSet::CreateDifference(old_active
.get(), delta
.get());
1348 PermissionsData::SetActivePermissions(extension
, new_active
);
1349 AddOrRemoveOriginPermissions(reason
, extension
, explicit_hosts
);
1350 AddOrRemoveBindings(extension
->id());
1353 void Dispatcher::OnUpdateTabSpecificPermissions(
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.
1364 if (view
&& view
->GetPageId() != page_id
)
1367 const Extension
* extension
= extensions_
.GetByID(extension_id
);
1371 PermissionsData::UpdateTabSpecificPermissions(
1374 new PermissionSet(APIPermissionSet(), origin_set
, URLPatternSet()));
1377 void Dispatcher::OnClearTabSpecificPermissions(
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
);
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
))
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
,
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
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());
1439 return SandboxedPageInfo::IsSandboxedPage(extension
, url
.path());
1445 Feature::Context
Dispatcher::ClassifyJavaScriptContext(
1446 const std::string
& extension_id
,
1447 int extension_group
,
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
;
1478 return Feature::WEB_PAGE_CONTEXT
;
1480 return Feature::UNSPECIFIED_CONTEXT
;
1483 void Dispatcher::OnExtensionResponse(int request_id
,
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 {
1493 DLOG(ERROR
) << "Not in a v8::Context";
1497 if (!context
->extension()) {
1499 v8::Exception::Error(v8::String::New("Not in an extension.")));
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());
1511 v8::Exception::Error(v8::String::New(error_msg
.c_str())));
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(
1534 NULL
, // all render views
1535 base::Bind(&CallModuleMethod
,
1536 local_event_bindings
,
1537 kEventDispatchFunction
,
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
;
1550 web_user_gesture
.reset(new WebScopedUserGesture
);
1552 v8_context_set_
.ForEach(
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