1 // Copyright 2013 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/common/manifest_handlers/background_info.h"
7 #include "base/command_line.h"
8 #include "base/files/file_util.h"
9 #include "base/lazy_instance.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "extensions/common/constants.h"
14 #include "extensions/common/error_utils.h"
15 #include "extensions/common/file_util.h"
16 #include "extensions/common/manifest_constants.h"
17 #include "extensions/common/manifest_handlers/permissions_parser.h"
18 #include "extensions/common/permissions/api_permission_set.h"
19 #include "extensions/common/switches.h"
20 #include "grit/extensions_strings.h"
21 #include "ui/base/l10n/l10n_util.h"
23 using base::ASCIIToUTF16
;
24 using base::DictionaryValue
;
26 namespace extensions
{
28 namespace keys
= manifest_keys
;
29 namespace values
= manifest_values
;
30 namespace errors
= manifest_errors
;
34 const char kBackground
[] = "background";
36 static base::LazyInstance
<BackgroundInfo
> g_empty_background_info
=
37 LAZY_INSTANCE_INITIALIZER
;
39 const BackgroundInfo
& GetBackgroundInfo(const Extension
* extension
) {
40 BackgroundInfo
* info
= static_cast<BackgroundInfo
*>(
41 extension
->GetManifestData(kBackground
));
43 return g_empty_background_info
.Get();
49 BackgroundInfo::BackgroundInfo()
50 : is_persistent_(true),
51 allow_js_access_(true) {
54 BackgroundInfo::~BackgroundInfo() {
58 GURL
BackgroundInfo::GetBackgroundURL(const Extension
* extension
) {
59 const BackgroundInfo
& info
= GetBackgroundInfo(extension
);
60 if (info
.background_scripts_
.empty())
61 return info
.background_url_
;
62 return extension
->GetResourceURL(kGeneratedBackgroundPageFilename
);
66 const std::vector
<std::string
>& BackgroundInfo::GetBackgroundScripts(
67 const Extension
* extension
) {
68 return GetBackgroundInfo(extension
).background_scripts_
;
72 bool BackgroundInfo::HasBackgroundPage(const Extension
* extension
) {
73 return GetBackgroundInfo(extension
).has_background_page();
77 bool BackgroundInfo::HasPersistentBackgroundPage(const Extension
* extension
) {
78 return GetBackgroundInfo(extension
).has_persistent_background_page();
82 bool BackgroundInfo::HasLazyBackgroundPage(const Extension
* extension
) {
83 return GetBackgroundInfo(extension
).has_lazy_background_page();
87 bool BackgroundInfo::HasGeneratedBackgroundPage(const Extension
* extension
) {
88 const BackgroundInfo
& info
= GetBackgroundInfo(extension
);
89 return !info
.background_scripts_
.empty();
93 bool BackgroundInfo::AllowJSAccess(const Extension
* extension
) {
94 return GetBackgroundInfo(extension
).allow_js_access_
;
97 bool BackgroundInfo::Parse(const Extension
* extension
, base::string16
* error
) {
98 const std::string
& bg_scripts_key
= extension
->is_platform_app() ?
99 keys::kPlatformAppBackgroundScripts
: keys::kBackgroundScripts
;
100 if (!LoadBackgroundScripts(extension
, bg_scripts_key
, error
) ||
101 !LoadBackgroundPage(extension
, error
) ||
102 !LoadBackgroundPersistent(extension
, error
) ||
103 !LoadAllowJSAccess(extension
, error
)) {
107 int background_solution_sum
= (background_url_
.is_valid() ? 1 : 0) +
108 (!background_scripts_
.empty() ? 1 : 0);
109 if (background_solution_sum
> 1) {
110 *error
= ASCIIToUTF16(errors::kInvalidBackgroundCombination
);
117 bool BackgroundInfo::LoadBackgroundScripts(const Extension
* extension
,
118 const std::string
& key
,
119 base::string16
* error
) {
120 const base::Value
* background_scripts_value
= NULL
;
121 if (!extension
->manifest()->Get(key
, &background_scripts_value
))
124 CHECK(background_scripts_value
);
125 if (background_scripts_value
->GetType() != base::Value::TYPE_LIST
) {
126 *error
= ASCIIToUTF16(errors::kInvalidBackgroundScripts
);
130 const base::ListValue
* background_scripts
= NULL
;
131 background_scripts_value
->GetAsList(&background_scripts
);
132 for (size_t i
= 0; i
< background_scripts
->GetSize(); ++i
) {
134 if (!background_scripts
->GetString(i
, &script
)) {
135 *error
= ErrorUtils::FormatErrorMessageUTF16(
136 errors::kInvalidBackgroundScript
, base::IntToString(i
));
139 background_scripts_
.push_back(script
);
145 bool BackgroundInfo::LoadBackgroundPage(const Extension
* extension
,
146 const std::string
& key
,
147 base::string16
* error
) {
148 const base::Value
* background_page_value
= NULL
;
149 if (!extension
->manifest()->Get(key
, &background_page_value
))
152 std::string background_str
;
153 if (!background_page_value
->GetAsString(&background_str
)) {
154 *error
= ASCIIToUTF16(errors::kInvalidBackground
);
158 if (extension
->is_hosted_app()) {
159 background_url_
= GURL(background_str
);
161 if (!PermissionsParser::HasAPIPermission(extension
,
162 APIPermission::kBackground
)) {
163 *error
= ASCIIToUTF16(errors::kBackgroundPermissionNeeded
);
166 // Hosted apps require an absolute URL.
167 if (!background_url_
.is_valid()) {
168 *error
= ASCIIToUTF16(errors::kInvalidBackgroundInHostedApp
);
172 if (!(background_url_
.SchemeIs("https") ||
173 (base::CommandLine::ForCurrentProcess()->HasSwitch(
174 switches::kAllowHTTPBackgroundPage
) &&
175 background_url_
.SchemeIs("http")))) {
176 *error
= ASCIIToUTF16(errors::kInvalidBackgroundInHostedApp
);
180 background_url_
= extension
->GetResourceURL(background_str
);
186 bool BackgroundInfo::LoadBackgroundPage(const Extension
* extension
,
187 base::string16
* error
) {
188 if (extension
->is_platform_app()) {
189 return LoadBackgroundPage(
190 extension
, keys::kPlatformAppBackgroundPage
, error
);
193 if (!LoadBackgroundPage(extension
, keys::kBackgroundPage
, error
))
195 if (background_url_
.is_empty())
196 return LoadBackgroundPage(extension
, keys::kBackgroundPageLegacy
, error
);
200 bool BackgroundInfo::LoadBackgroundPersistent(const Extension
* extension
,
201 base::string16
* error
) {
202 if (extension
->is_platform_app()) {
203 is_persistent_
= false;
207 const base::Value
* background_persistent
= NULL
;
208 if (!extension
->manifest()->Get(keys::kBackgroundPersistent
,
209 &background_persistent
))
212 if (!background_persistent
->GetAsBoolean(&is_persistent_
)) {
213 *error
= ASCIIToUTF16(errors::kInvalidBackgroundPersistent
);
217 if (!has_background_page()) {
218 *error
= ASCIIToUTF16(errors::kInvalidBackgroundPersistentNoPage
);
225 bool BackgroundInfo::LoadAllowJSAccess(const Extension
* extension
,
226 base::string16
* error
) {
227 const base::Value
* allow_js_access
= NULL
;
228 if (!extension
->manifest()->Get(keys::kBackgroundAllowJsAccess
,
232 if (!allow_js_access
->IsType(base::Value::TYPE_BOOLEAN
) ||
233 !allow_js_access
->GetAsBoolean(&allow_js_access_
)) {
234 *error
= ASCIIToUTF16(errors::kInvalidBackgroundAllowJsAccess
);
241 BackgroundManifestHandler::BackgroundManifestHandler() {
244 BackgroundManifestHandler::~BackgroundManifestHandler() {
247 bool BackgroundManifestHandler::Parse(Extension
* extension
,
248 base::string16
* error
) {
249 scoped_ptr
<BackgroundInfo
> info(new BackgroundInfo
);
250 if (!info
->Parse(extension
, error
))
253 // Platform apps must have background pages.
254 if (extension
->is_platform_app() && !info
->has_background_page()) {
255 *error
= ASCIIToUTF16(errors::kBackgroundRequiredForPlatformApps
);
258 // Lazy background pages are incompatible with the webRequest API.
259 if (info
->has_lazy_background_page() &&
260 PermissionsParser::HasAPIPermission(extension
,
261 APIPermission::kWebRequest
)) {
262 *error
= ASCIIToUTF16(errors::kWebRequestConflictsWithLazyBackground
);
266 extension
->SetManifestData(kBackground
, info
.release());
270 bool BackgroundManifestHandler::Validate(
271 const Extension
* extension
,
273 std::vector
<InstallWarning
>* warnings
) const {
274 // Validate that background scripts exist.
275 const std::vector
<std::string
>& background_scripts
=
276 BackgroundInfo::GetBackgroundScripts(extension
);
277 for (size_t i
= 0; i
< background_scripts
.size(); ++i
) {
278 if (!base::PathExists(
279 extension
->GetResource(background_scripts
[i
]).GetFilePath())) {
280 *error
= l10n_util::GetStringFUTF8(
281 IDS_EXTENSION_LOAD_BACKGROUND_SCRIPT_FAILED
,
282 base::UTF8ToUTF16(background_scripts
[i
]));
287 // Validate background page location, except for hosted apps, which should use
288 // an external URL. Background page for hosted apps are verified when the
289 // extension is created (in Extension::InitFromValue)
290 if (BackgroundInfo::HasBackgroundPage(extension
) &&
291 !extension
->is_hosted_app() && background_scripts
.empty()) {
292 base::FilePath page_path
= file_util::ExtensionURLToRelativeFilePath(
293 BackgroundInfo::GetBackgroundURL(extension
));
294 const base::FilePath path
= extension
->GetResource(page_path
).GetFilePath();
295 if (path
.empty() || !base::PathExists(path
)) {
297 l10n_util::GetStringFUTF8(
298 IDS_EXTENSION_LOAD_BACKGROUND_PAGE_FAILED
,
299 page_path
.LossyDisplayName());
306 bool BackgroundManifestHandler::AlwaysParseForType(Manifest::Type type
) const {
307 return type
== Manifest::TYPE_PLATFORM_APP
;
310 const std::vector
<std::string
> BackgroundManifestHandler::Keys() const {
311 static const char* keys
[] = {
312 keys::kBackgroundAllowJsAccess
, keys::kBackgroundPage
,
313 keys::kBackgroundPageLegacy
, keys::kBackgroundPersistent
,
314 keys::kBackgroundScripts
, keys::kPlatformAppBackgroundPage
,
315 keys::kPlatformAppBackgroundScripts
};
316 return std::vector
<std::string
>(keys
, keys
+ arraysize(keys
));
319 } // namespace extensions