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/common/extensions/manifest_url_handler.h"
7 #include "base/file_util.h"
8 #include "base/lazy_instance.h"
9 #include "base/memory/scoped_ptr.h"
10 #include "base/strings/string_util.h"
11 #include "base/strings/stringprintf.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "base/values.h"
14 #include "chrome/common/chrome_constants.h"
15 #include "chrome/common/extensions/extension_constants.h"
16 #include "chrome/common/url_constants.h"
17 #include "extensions/common/error_utils.h"
18 #include "extensions/common/file_util.h"
19 #include "extensions/common/manifest.h"
20 #include "extensions/common/manifest_constants.h"
21 #include "extensions/common/permissions/api_permission.h"
22 #include "extensions/common/permissions/api_permission_set.h"
23 #include "extensions/common/permissions/permissions_data.h"
24 #include "grit/generated_resources.h"
25 #include "ui/base/l10n/l10n_util.h"
28 #include "ui/keyboard/keyboard_constants.h"
31 namespace extensions
{
33 namespace keys
= manifest_keys
;
34 namespace errors
= manifest_errors
;
38 const char kOverrideExtentUrlPatternFormat
[] = "chrome://%s/*";
40 const GURL
& GetManifestURL(const Extension
* extension
,
41 const std::string
& key
) {
42 ManifestURL
* manifest_url
=
43 static_cast<ManifestURL
*>(extension
->GetManifestData(key
));
44 return manifest_url
? manifest_url
->url_
: GURL::EmptyGURL();
50 const GURL
& ManifestURL::GetDevToolsPage(const Extension
* extension
) {
51 return GetManifestURL(extension
, keys::kDevToolsPage
);
55 const GURL
ManifestURL::GetHomepageURL(const Extension
* extension
) {
56 const GURL
& homepage_url
= GetManifestURL(extension
, keys::kHomepageURL
);
57 if (homepage_url
.is_valid())
59 return UpdatesFromGallery(extension
) ?
60 GURL(extension_urls::GetWebstoreItemDetailURLPrefix() + extension
->id()) :
65 const GURL
& ManifestURL::GetUpdateURL(const Extension
* extension
) {
66 return GetManifestURL(extension
, keys::kUpdateURL
);
70 bool ManifestURL::UpdatesFromGallery(const Extension
* extension
) {
71 return extension_urls::IsWebstoreUpdateUrl(GetUpdateURL(extension
));
75 bool ManifestURL::UpdatesFromGallery(const base::DictionaryValue
* manifest
) {
77 if (!manifest
->GetString(keys::kUpdateURL
, &url
))
79 return extension_urls::IsWebstoreUpdateUrl(GURL(url
));
83 const GURL
& ManifestURL::GetOptionsPage(const Extension
* extension
) {
84 return GetManifestURL(extension
, keys::kOptionsPage
);
88 const GURL
ManifestURL::GetDetailsURL(const Extension
* extension
) {
89 return extension
->from_webstore() ?
90 GURL(extension_urls::GetWebstoreItemDetailURLPrefix() + extension
->id()) :
94 URLOverrides::URLOverrides() {
97 URLOverrides::~URLOverrides() {
100 static base::LazyInstance
<URLOverrides::URLOverrideMap
> g_empty_url_overrides
=
101 LAZY_INSTANCE_INITIALIZER
;
104 const URLOverrides::URLOverrideMap
&
105 URLOverrides::GetChromeURLOverrides(const Extension
* extension
) {
106 URLOverrides
* url_overrides
= static_cast<URLOverrides
*>(
107 extension
->GetManifestData(keys::kChromeURLOverrides
));
108 return url_overrides
?
109 url_overrides
->chrome_url_overrides_
:
110 g_empty_url_overrides
.Get();
113 DevToolsPageHandler::DevToolsPageHandler() {
116 DevToolsPageHandler::~DevToolsPageHandler() {
119 bool DevToolsPageHandler::Parse(Extension
* extension
, base::string16
* error
) {
120 scoped_ptr
<ManifestURL
> manifest_url(new ManifestURL
);
121 std::string devtools_str
;
122 if (!extension
->manifest()->GetString(keys::kDevToolsPage
, &devtools_str
)) {
123 *error
= base::ASCIIToUTF16(errors::kInvalidDevToolsPage
);
126 manifest_url
->url_
= extension
->GetResourceURL(devtools_str
);
127 extension
->SetManifestData(keys::kDevToolsPage
, manifest_url
.release());
128 PermissionsData::GetInitialAPIPermissions(extension
)->insert(
129 APIPermission::kDevtools
);
133 const std::vector
<std::string
> DevToolsPageHandler::Keys() const {
134 return SingleKey(keys::kDevToolsPage
);
137 HomepageURLHandler::HomepageURLHandler() {
140 HomepageURLHandler::~HomepageURLHandler() {
143 bool HomepageURLHandler::Parse(Extension
* extension
, base::string16
* error
) {
144 scoped_ptr
<ManifestURL
> manifest_url(new ManifestURL
);
145 std::string homepage_url_str
;
146 if (!extension
->manifest()->GetString(keys::kHomepageURL
,
147 &homepage_url_str
)) {
148 *error
= ErrorUtils::FormatErrorMessageUTF16(errors::kInvalidHomepageURL
,
152 manifest_url
->url_
= GURL(homepage_url_str
);
153 if (!manifest_url
->url_
.is_valid() ||
154 !manifest_url
->url_
.SchemeIsHTTPOrHTTPS()) {
155 *error
= ErrorUtils::FormatErrorMessageUTF16(
156 errors::kInvalidHomepageURL
, homepage_url_str
);
159 extension
->SetManifestData(keys::kHomepageURL
, manifest_url
.release());
163 const std::vector
<std::string
> HomepageURLHandler::Keys() const {
164 return SingleKey(keys::kHomepageURL
);
167 UpdateURLHandler::UpdateURLHandler() {
170 UpdateURLHandler::~UpdateURLHandler() {
173 bool UpdateURLHandler::Parse(Extension
* extension
, base::string16
* error
) {
174 scoped_ptr
<ManifestURL
> manifest_url(new ManifestURL
);
175 std::string tmp_update_url
;
177 if (!extension
->manifest()->GetString(keys::kUpdateURL
, &tmp_update_url
)) {
178 *error
= ErrorUtils::FormatErrorMessageUTF16(errors::kInvalidUpdateURL
,
183 manifest_url
->url_
= GURL(tmp_update_url
);
184 if (!manifest_url
->url_
.is_valid() ||
185 manifest_url
->url_
.has_ref()) {
186 *error
= ErrorUtils::FormatErrorMessageUTF16(
187 errors::kInvalidUpdateURL
, tmp_update_url
);
191 extension
->SetManifestData(keys::kUpdateURL
, manifest_url
.release());
195 const std::vector
<std::string
> UpdateURLHandler::Keys() const {
196 return SingleKey(keys::kUpdateURL
);
199 OptionsPageHandler::OptionsPageHandler() {
202 OptionsPageHandler::~OptionsPageHandler() {
205 bool OptionsPageHandler::Parse(Extension
* extension
, base::string16
* error
) {
206 scoped_ptr
<ManifestURL
> manifest_url(new ManifestURL
);
207 std::string options_str
;
208 if (!extension
->manifest()->GetString(keys::kOptionsPage
, &options_str
)) {
209 *error
= base::ASCIIToUTF16(errors::kInvalidOptionsPage
);
213 if (extension
->is_hosted_app()) {
214 // hosted apps require an absolute URL.
215 GURL
options_url(options_str
);
216 if (!options_url
.is_valid() ||
217 !options_url
.SchemeIsHTTPOrHTTPS()) {
218 *error
= base::ASCIIToUTF16(errors::kInvalidOptionsPageInHostedApp
);
221 manifest_url
->url_
= options_url
;
223 GURL
absolute(options_str
);
224 if (absolute
.is_valid()) {
226 base::ASCIIToUTF16(errors::kInvalidOptionsPageExpectUrlInPackage
);
229 manifest_url
->url_
= extension
->GetResourceURL(options_str
);
230 if (!manifest_url
->url_
.is_valid()) {
231 *error
= base::ASCIIToUTF16(errors::kInvalidOptionsPage
);
236 extension
->SetManifestData(keys::kOptionsPage
, manifest_url
.release());
240 bool OptionsPageHandler::Validate(const Extension
* extension
,
242 std::vector
<InstallWarning
>* warnings
) const {
243 // Validate path to the options page. Don't check the URL for hosted apps,
244 // because they are expected to refer to an external URL.
245 if (!extensions::ManifestURL::GetOptionsPage(extension
).is_empty() &&
246 !extension
->is_hosted_app()) {
247 const base::FilePath options_path
=
248 extensions::file_util::ExtensionURLToRelativeFilePath(
249 extensions::ManifestURL::GetOptionsPage(extension
));
250 const base::FilePath path
=
251 extension
->GetResource(options_path
).GetFilePath();
252 if (path
.empty() || !base::PathExists(path
)) {
254 l10n_util::GetStringFUTF8(
255 IDS_EXTENSION_LOAD_OPTIONS_PAGE_FAILED
,
256 options_path
.LossyDisplayName());
263 const std::vector
<std::string
> OptionsPageHandler::Keys() const {
264 return SingleKey(keys::kOptionsPage
);
267 URLOverridesHandler::URLOverridesHandler() {
270 URLOverridesHandler::~URLOverridesHandler() {
273 bool URLOverridesHandler::Parse(Extension
* extension
, base::string16
* error
) {
274 const base::DictionaryValue
* overrides
= NULL
;
275 if (!extension
->manifest()->GetDictionary(keys::kChromeURLOverrides
,
277 *error
= base::ASCIIToUTF16(errors::kInvalidChromeURLOverrides
);
280 scoped_ptr
<URLOverrides
> url_overrides(new URLOverrides
);
281 // Validate that the overrides are all strings
282 for (base::DictionaryValue::Iterator
iter(*overrides
); !iter
.IsAtEnd();
284 std::string page
= iter
.key();
286 // Restrict override pages to a list of supported URLs.
287 bool is_override
= (page
!= chrome::kChromeUINewTabHost
&&
288 page
!= chrome::kChromeUIBookmarksHost
&&
289 page
!= chrome::kChromeUIHistoryHost
);
290 #if defined(OS_CHROMEOS)
291 is_override
= (is_override
&&
292 page
!= chrome::kChromeUIActivationMessageHost
);
294 #if defined(OS_CHROMEOS)
295 is_override
= (is_override
&& page
!= keyboard::kKeyboardHost
);
298 if (is_override
|| !iter
.value().GetAsString(&val
)) {
299 *error
= base::ASCIIToUTF16(errors::kInvalidChromeURLOverrides
);
302 // Replace the entry with a fully qualified chrome-extension:// URL.
303 url_overrides
->chrome_url_overrides_
[page
] = extension
->GetResourceURL(val
);
305 // For component extensions, add override URL to extent patterns.
306 if (extension
->is_legacy_packaged_app() &&
307 extension
->location() == Manifest::COMPONENT
) {
308 URLPattern
pattern(URLPattern::SCHEME_CHROMEUI
);
309 std::string url
= base::StringPrintf(kOverrideExtentUrlPatternFormat
,
311 if (pattern
.Parse(url
) != URLPattern::PARSE_SUCCESS
) {
312 *error
= ErrorUtils::FormatErrorMessageUTF16(
313 errors::kInvalidURLPatternError
, url
);
316 extension
->AddWebExtentPattern(pattern
);
320 // An extension may override at most one page.
321 if (overrides
->size() > 1) {
322 *error
= base::ASCIIToUTF16(errors::kMultipleOverrides
);
325 extension
->SetManifestData(keys::kChromeURLOverrides
,
326 url_overrides
.release());
330 const std::vector
<std::string
> URLOverridesHandler::Keys() const {
331 return SingleKey(keys::kChromeURLOverrides
);
334 } // namespace extensions