Fix sort order of unlaunched apps on app list start page.
[chromium-blink-merge.git] / extensions / common / manifest_handlers / background_info.cc
blob3d575682f504317e7e9b01612af2664e3743da39
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;
32 namespace {
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));
42 if (!info)
43 return g_empty_background_info.Get();
44 return *info;
47 } // namespace
49 BackgroundInfo::BackgroundInfo()
50 : is_persistent_(true),
51 allow_js_access_(true) {
54 BackgroundInfo::~BackgroundInfo() {
57 // static
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);
65 // static
66 const std::vector<std::string>& BackgroundInfo::GetBackgroundScripts(
67 const Extension* extension) {
68 return GetBackgroundInfo(extension).background_scripts_;
71 // static
72 bool BackgroundInfo::HasBackgroundPage(const Extension* extension) {
73 return GetBackgroundInfo(extension).has_background_page();
76 // static
77 bool BackgroundInfo::HasPersistentBackgroundPage(const Extension* extension) {
78 return GetBackgroundInfo(extension).has_persistent_background_page();
81 // static
82 bool BackgroundInfo::HasLazyBackgroundPage(const Extension* extension) {
83 return GetBackgroundInfo(extension).has_lazy_background_page();
86 // static
87 bool BackgroundInfo::HasGeneratedBackgroundPage(const Extension* extension) {
88 const BackgroundInfo& info = GetBackgroundInfo(extension);
89 return !info.background_scripts_.empty();
92 // static
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)) {
104 return false;
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);
111 return false;
114 return true;
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))
122 return true;
124 CHECK(background_scripts_value);
125 if (background_scripts_value->GetType() != base::Value::TYPE_LIST) {
126 *error = ASCIIToUTF16(errors::kInvalidBackgroundScripts);
127 return false;
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) {
133 std::string script;
134 if (!background_scripts->GetString(i, &script)) {
135 *error = ErrorUtils::FormatErrorMessageUTF16(
136 errors::kInvalidBackgroundScript, base::IntToString(i));
137 return false;
139 background_scripts_.push_back(script);
142 return true;
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))
150 return true;
152 std::string background_str;
153 if (!background_page_value->GetAsString(&background_str)) {
154 *error = ASCIIToUTF16(errors::kInvalidBackground);
155 return false;
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);
164 return false;
166 // Hosted apps require an absolute URL.
167 if (!background_url_.is_valid()) {
168 *error = ASCIIToUTF16(errors::kInvalidBackgroundInHostedApp);
169 return false;
172 if (!(background_url_.SchemeIs("https") ||
173 (base::CommandLine::ForCurrentProcess()->HasSwitch(
174 switches::kAllowHTTPBackgroundPage) &&
175 background_url_.SchemeIs("http")))) {
176 *error = ASCIIToUTF16(errors::kInvalidBackgroundInHostedApp);
177 return false;
179 } else {
180 background_url_ = extension->GetResourceURL(background_str);
183 return true;
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))
194 return false;
195 if (background_url_.is_empty())
196 return LoadBackgroundPage(extension, keys::kBackgroundPageLegacy, error);
197 return true;
200 bool BackgroundInfo::LoadBackgroundPersistent(const Extension* extension,
201 base::string16* error) {
202 if (extension->is_platform_app()) {
203 is_persistent_ = false;
204 return true;
207 const base::Value* background_persistent = NULL;
208 if (!extension->manifest()->Get(keys::kBackgroundPersistent,
209 &background_persistent))
210 return true;
212 if (!background_persistent->GetAsBoolean(&is_persistent_)) {
213 *error = ASCIIToUTF16(errors::kInvalidBackgroundPersistent);
214 return false;
217 if (!has_background_page()) {
218 *error = ASCIIToUTF16(errors::kInvalidBackgroundPersistentNoPage);
219 return false;
222 return true;
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,
229 &allow_js_access))
230 return true;
232 if (!allow_js_access->IsType(base::Value::TYPE_BOOLEAN) ||
233 !allow_js_access->GetAsBoolean(&allow_js_access_)) {
234 *error = ASCIIToUTF16(errors::kInvalidBackgroundAllowJsAccess);
235 return false;
238 return true;
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))
251 return false;
253 // Platform apps must have background pages.
254 if (extension->is_platform_app() && !info->has_background_page()) {
255 *error = ASCIIToUTF16(errors::kBackgroundRequiredForPlatformApps);
256 return false;
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);
263 return false;
266 extension->SetManifestData(kBackground, info.release());
267 return true;
270 bool BackgroundManifestHandler::Validate(
271 const Extension* extension,
272 std::string* error,
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]));
283 return false;
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)) {
296 *error =
297 l10n_util::GetStringFUTF8(
298 IDS_EXTENSION_LOAD_BACKGROUND_PAGE_FAILED,
299 page_path.LossyDisplayName());
300 return false;
303 return true;
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