1 // Copyright 2015 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 "extensions/browser/extension_user_script_loader.h"
10 #include "base/bind.h"
11 #include "base/bind_helpers.h"
12 #include "base/files/file_path.h"
13 #include "base/files/file_util.h"
14 #include "base/version.h"
15 #include "content/public/browser/browser_context.h"
16 #include "content/public/browser/browser_thread.h"
17 #include "content/public/browser/notification_service.h"
18 #include "content/public/browser/render_process_host.h"
19 #include "extensions/browser/component_extension_resource_manager.h"
20 #include "extensions/browser/content_verifier.h"
21 #include "extensions/browser/extension_registry.h"
22 #include "extensions/browser/extension_system.h"
23 #include "extensions/browser/extensions_browser_client.h"
24 #include "extensions/common/file_util.h"
25 #include "extensions/common/manifest_handlers/default_locale_handler.h"
26 #include "extensions/common/message_bundle.h"
27 #include "extensions/common/one_shot_event.h"
28 #include "ui/base/resource/resource_bundle.h"
30 using content::BrowserContext
;
32 namespace extensions
{
36 // Verifies file contents as they are read.
37 void VerifyContent(const scoped_refptr
<ContentVerifier
>& verifier
,
38 const std::string
& extension_id
,
39 const base::FilePath
& extension_root
,
40 const base::FilePath
& relative_path
,
41 const std::string
& content
) {
42 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
43 scoped_refptr
<ContentVerifyJob
> job(
44 verifier
->CreateJobFor(extension_id
, extension_root
, relative_path
));
47 job
->BytesRead(content
.size(), content
.data());
52 // Loads user scripts from the extension who owns these scripts.
53 bool ExtensionLoadScriptContent(
54 const HostID
& host_id
,
55 UserScript::File
* script_file
,
56 const UserScriptLoader::SubstitutionMap
* localization_messages
,
57 const scoped_refptr
<ContentVerifier
>& verifier
) {
60 const base::FilePath
& path
= ExtensionResource::GetFilePath(
61 script_file
->extension_root(), script_file
->relative_path(),
62 ExtensionResource::SYMLINKS_MUST_RESOLVE_WITHIN_ROOT
);
65 if (ExtensionsBrowserClient::Get()
66 ->GetComponentExtensionResourceManager()
67 ->IsComponentExtensionResource(script_file
->extension_root(),
68 script_file
->relative_path(),
70 const ResourceBundle
& rb
= ResourceBundle::GetSharedInstance();
71 content
= rb
.GetRawDataResource(resource_id
).as_string();
73 LOG(WARNING
) << "Failed to get file path to "
74 << script_file
->relative_path().value() << " from "
75 << script_file
->extension_root().value();
79 if (!base::ReadFileToString(path
, &content
)) {
80 LOG(WARNING
) << "Failed to load user script file: " << path
.value();
84 content::BrowserThread::PostTask(
85 content::BrowserThread::IO
, FROM_HERE
,
86 base::Bind(&VerifyContent
, verifier
, host_id
.id(),
87 script_file
->extension_root(),
88 script_file
->relative_path(), content
));
92 // Localize the content.
93 if (localization_messages
) {
95 MessageBundle::ReplaceMessagesWithExternalDictionary(*localization_messages
,
98 LOG(WARNING
) << "Failed to replace messages in script: " << error
;
101 // Remove BOM from the content.
102 std::string::size_type index
= content
.find(base::kUtf8ByteOrderMark
);
104 script_file
->set_content(content
.substr(strlen(base::kUtf8ByteOrderMark
)));
106 script_file
->set_content(content
);
113 ExtensionUserScriptLoader::ExtensionUserScriptLoader(
114 BrowserContext
* browser_context
,
115 const HostID
& host_id
,
116 bool listen_for_extension_system_loaded
)
120 ExtensionSystem::Get(browser_context
)->content_verifier()),
121 extension_registry_observer_(this),
122 weak_factory_(this) {
123 extension_registry_observer_
.Add(ExtensionRegistry::Get(browser_context
));
124 if (listen_for_extension_system_loaded
) {
125 ExtensionSystem::Get(browser_context
)
128 base::Bind(&ExtensionUserScriptLoader::OnExtensionSystemReady
,
129 weak_factory_
.GetWeakPtr()));
135 ExtensionUserScriptLoader::~ExtensionUserScriptLoader() {
138 void ExtensionUserScriptLoader::UpdateHostsInfo(
139 const std::set
<HostID
>& changed_hosts
) {
140 ExtensionRegistry
* registry
= ExtensionRegistry::Get(browser_context());
141 for (const HostID
& host_id
: changed_hosts
) {
142 const Extension
* extension
=
143 registry
->GetExtensionById(host_id
.id(), ExtensionRegistry::ENABLED
);
144 // |changed_hosts_| may include hosts that have been removed,
145 // which leads to the above lookup failing. In this case, just continue.
148 AddHostInfo(host_id
, ExtensionSet::ExtensionPathAndDefaultLocale(
150 LocaleInfo::GetDefaultLocale(extension
)));
154 UserScriptLoader::LoadUserScriptsContentFunction
155 ExtensionUserScriptLoader::GetLoadUserScriptsFunction() {
156 return base::Bind(&ExtensionLoadScriptContent
);
159 void ExtensionUserScriptLoader::OnExtensionUnloaded(
160 content::BrowserContext
* browser_context
,
161 const Extension
* extension
,
162 UnloadedExtensionInfo::Reason reason
) {
163 RemoveHostInfo(HostID(HostID::EXTENSIONS
, extension
->id()));
166 void ExtensionUserScriptLoader::OnExtensionSystemReady() {
170 } // namespace extensions