- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / common / extensions / manifest_url_handler.cc
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.
4
5 #include "chrome/common/extensions/manifest_url_handler.h"
6
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/extensions/extension_file_util.h"
17 #include "chrome/common/extensions/permissions/permissions_data.h"
18 #include "chrome/common/url_constants.h"
19 #include "extensions/common/error_utils.h"
20 #include "extensions/common/manifest.h"
21 #include "extensions/common/manifest_constants.h"
22 #include "extensions/common/permissions/api_permission.h"
23 #include "extensions/common/permissions/api_permission_set.h"
24 #include "grit/generated_resources.h"
25 #include "ui/base/l10n/l10n_util.h"
26
27 #if defined(USE_AURA)
28 #include "ui/keyboard/keyboard_constants.h"
29 #endif
30
31 namespace extensions {
32
33 namespace keys = manifest_keys;
34 namespace errors = manifest_errors;
35
36 namespace {
37
38 const char kOverrideExtentUrlPatternFormat[] = "chrome://%s/*";
39
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();
45 }
46
47 }  // namespace
48
49 // static
50 const GURL& ManifestURL::GetDevToolsPage(const Extension* extension) {
51   return GetManifestURL(extension, keys::kDevToolsPage);
52 }
53
54 // static
55 const GURL ManifestURL::GetHomepageURL(const Extension* extension) {
56   const GURL& homepage_url = GetManifestURL(extension, keys::kHomepageURL);
57   if (homepage_url.is_valid())
58     return homepage_url;
59   return UpdatesFromGallery(extension) ?
60       GURL(extension_urls::GetWebstoreItemDetailURLPrefix() + extension->id()) :
61       GURL::EmptyGURL();
62 }
63
64 // static
65 const GURL& ManifestURL::GetUpdateURL(const Extension* extension) {
66   return GetManifestURL(extension, keys::kUpdateURL);
67 }
68
69 // static
70 bool ManifestURL::UpdatesFromGallery(const Extension* extension) {
71   return extension_urls::IsWebstoreUpdateUrl(GetUpdateURL(extension));
72 }
73
74 // static
75 const GURL& ManifestURL::GetOptionsPage(const Extension* extension) {
76   return GetManifestURL(extension, keys::kOptionsPage);
77 }
78
79 // static
80 const GURL ManifestURL::GetDetailsURL(const Extension* extension) {
81   return extension->from_webstore() ?
82       GURL(extension_urls::GetWebstoreItemDetailURLPrefix() + extension->id()) :
83       GURL::EmptyGURL();
84 }
85
86 URLOverrides::URLOverrides() {
87 }
88
89 URLOverrides::~URLOverrides() {
90 }
91
92 static base::LazyInstance<URLOverrides::URLOverrideMap> g_empty_url_overrides =
93     LAZY_INSTANCE_INITIALIZER;
94
95 // static
96 const URLOverrides::URLOverrideMap&
97     URLOverrides::GetChromeURLOverrides(const Extension* extension) {
98   URLOverrides* url_overrides = static_cast<URLOverrides*>(
99       extension->GetManifestData(keys::kChromeURLOverrides));
100   return url_overrides ?
101          url_overrides->chrome_url_overrides_ :
102          g_empty_url_overrides.Get();
103 }
104
105 DevToolsPageHandler::DevToolsPageHandler() {
106 }
107
108 DevToolsPageHandler::~DevToolsPageHandler() {
109 }
110
111 bool DevToolsPageHandler::Parse(Extension* extension, string16* error) {
112   scoped_ptr<ManifestURL> manifest_url(new ManifestURL);
113   std::string devtools_str;
114   if (!extension->manifest()->GetString(keys::kDevToolsPage, &devtools_str)) {
115     *error = ASCIIToUTF16(errors::kInvalidDevToolsPage);
116     return false;
117   }
118   manifest_url->url_ = extension->GetResourceURL(devtools_str);
119   extension->SetManifestData(keys::kDevToolsPage, manifest_url.release());
120   PermissionsData::GetInitialAPIPermissions(extension)->insert(
121       APIPermission::kDevtools);
122   return true;
123 }
124
125 const std::vector<std::string> DevToolsPageHandler::Keys() const {
126   return SingleKey(keys::kDevToolsPage);
127 }
128
129 HomepageURLHandler::HomepageURLHandler() {
130 }
131
132 HomepageURLHandler::~HomepageURLHandler() {
133 }
134
135 bool HomepageURLHandler::Parse(Extension* extension, string16* error) {
136   scoped_ptr<ManifestURL> manifest_url(new ManifestURL);
137   std::string homepage_url_str;
138   if (!extension->manifest()->GetString(keys::kHomepageURL,
139                                         &homepage_url_str)) {
140     *error = ErrorUtils::FormatErrorMessageUTF16(errors::kInvalidHomepageURL,
141                                                  std::string());
142     return false;
143   }
144   manifest_url->url_ = GURL(homepage_url_str);
145   if (!manifest_url->url_.is_valid() ||
146       !manifest_url->url_.SchemeIsHTTPOrHTTPS()) {
147     *error = ErrorUtils::FormatErrorMessageUTF16(
148         errors::kInvalidHomepageURL, homepage_url_str);
149     return false;
150   }
151   extension->SetManifestData(keys::kHomepageURL, manifest_url.release());
152   return true;
153 }
154
155 const std::vector<std::string> HomepageURLHandler::Keys() const {
156   return SingleKey(keys::kHomepageURL);
157 }
158
159 UpdateURLHandler::UpdateURLHandler() {
160 }
161
162 UpdateURLHandler::~UpdateURLHandler() {
163 }
164
165 bool UpdateURLHandler::Parse(Extension* extension, string16* error) {
166   scoped_ptr<ManifestURL> manifest_url(new ManifestURL);
167   std::string tmp_update_url;
168
169   if (!extension->manifest()->GetString(keys::kUpdateURL, &tmp_update_url)) {
170     *error = ErrorUtils::FormatErrorMessageUTF16(errors::kInvalidUpdateURL,
171                                                  std::string());
172     return false;
173   }
174
175   manifest_url->url_ = GURL(tmp_update_url);
176   if (!manifest_url->url_.is_valid() ||
177       manifest_url->url_.has_ref()) {
178     *error = ErrorUtils::FormatErrorMessageUTF16(
179         errors::kInvalidUpdateURL, tmp_update_url);
180     return false;
181   }
182
183   extension->SetManifestData(keys::kUpdateURL, manifest_url.release());
184   return true;
185 }
186
187 const std::vector<std::string> UpdateURLHandler::Keys() const {
188   return SingleKey(keys::kUpdateURL);
189 }
190
191 OptionsPageHandler::OptionsPageHandler() {
192 }
193
194 OptionsPageHandler::~OptionsPageHandler() {
195 }
196
197 bool OptionsPageHandler::Parse(Extension* extension, string16* error) {
198   scoped_ptr<ManifestURL> manifest_url(new ManifestURL);
199   std::string options_str;
200   if (!extension->manifest()->GetString(keys::kOptionsPage, &options_str)) {
201     *error = ASCIIToUTF16(errors::kInvalidOptionsPage);
202     return false;
203   }
204
205   if (extension->is_hosted_app()) {
206     // hosted apps require an absolute URL.
207     GURL options_url(options_str);
208     if (!options_url.is_valid() ||
209         !options_url.SchemeIsHTTPOrHTTPS()) {
210       *error = ASCIIToUTF16(errors::kInvalidOptionsPageInHostedApp);
211       return false;
212     }
213     manifest_url->url_ = options_url;
214   } else {
215     GURL absolute(options_str);
216     if (absolute.is_valid()) {
217       *error = ASCIIToUTF16(errors::kInvalidOptionsPageExpectUrlInPackage);
218       return false;
219     }
220     manifest_url->url_ = extension->GetResourceURL(options_str);
221     if (!manifest_url->url_.is_valid()) {
222       *error = ASCIIToUTF16(errors::kInvalidOptionsPage);
223       return false;
224     }
225   }
226
227   extension->SetManifestData(keys::kOptionsPage, manifest_url.release());
228   return true;
229 }
230
231 bool OptionsPageHandler::Validate(const Extension* extension,
232                                   std::string* error,
233                                   std::vector<InstallWarning>* warnings) const {
234   // Validate path to the options page.  Don't check the URL for hosted apps,
235   // because they are expected to refer to an external URL.
236   if (!extensions::ManifestURL::GetOptionsPage(extension).is_empty() &&
237       !extension->is_hosted_app()) {
238     const base::FilePath options_path =
239         extension_file_util::ExtensionURLToRelativeFilePath(
240             extensions::ManifestURL::GetOptionsPage(extension));
241     const base::FilePath path =
242         extension->GetResource(options_path).GetFilePath();
243     if (path.empty() || !base::PathExists(path)) {
244       *error =
245           l10n_util::GetStringFUTF8(
246               IDS_EXTENSION_LOAD_OPTIONS_PAGE_FAILED,
247               options_path.LossyDisplayName());
248       return false;
249     }
250   }
251   return true;
252 }
253
254 const std::vector<std::string> OptionsPageHandler::Keys() const {
255   return SingleKey(keys::kOptionsPage);
256 }
257
258 URLOverridesHandler::URLOverridesHandler() {
259 }
260
261 URLOverridesHandler::~URLOverridesHandler() {
262 }
263
264 bool URLOverridesHandler::Parse(Extension* extension, string16* error) {
265   const base::DictionaryValue* overrides = NULL;
266   if (!extension->manifest()->GetDictionary(keys::kChromeURLOverrides,
267                                             &overrides)) {
268     *error = ASCIIToUTF16(errors::kInvalidChromeURLOverrides);
269     return false;
270   }
271   scoped_ptr<URLOverrides> url_overrides(new URLOverrides);
272   // Validate that the overrides are all strings
273   for (base::DictionaryValue::Iterator iter(*overrides); !iter.IsAtEnd();
274          iter.Advance()) {
275     std::string page = iter.key();
276     std::string val;
277     // Restrict override pages to a list of supported URLs.
278     bool is_override = (page != chrome::kChromeUINewTabHost &&
279                         page != chrome::kChromeUIBookmarksHost &&
280                         page != chrome::kChromeUIHistoryHost);
281 #if defined(OS_CHROMEOS)
282     is_override = (is_override &&
283                    page != chrome::kChromeUIActivationMessageHost);
284 #endif
285 #if defined(OS_CHROMEOS)
286     is_override = (is_override && page != keyboard::kKeyboardWebUIHost);
287 #endif
288 #if defined(ENABLE_ENHANCED_BOOKMARKS)
289     is_override = (is_override &&
290                    !(extension->location() == Manifest::COMPONENT &&
291                      page ==  chrome::kChromeUIEnhancedBookmarksHost));
292 #endif
293
294     if (is_override || !iter.value().GetAsString(&val)) {
295       *error = ASCIIToUTF16(errors::kInvalidChromeURLOverrides);
296       return false;
297     }
298     // Replace the entry with a fully qualified chrome-extension:// URL.
299     url_overrides->chrome_url_overrides_[page] = extension->GetResourceURL(val);
300
301     // For component extensions, add override URL to extent patterns.
302     if (extension->is_legacy_packaged_app() &&
303         extension->location() == Manifest::COMPONENT) {
304       URLPattern pattern(URLPattern::SCHEME_CHROMEUI);
305       std::string url = base::StringPrintf(kOverrideExtentUrlPatternFormat,
306                                            page.c_str());
307       if (pattern.Parse(url) != URLPattern::PARSE_SUCCESS) {
308         *error = ErrorUtils::FormatErrorMessageUTF16(
309             errors::kInvalidURLPatternError, url);
310         return false;
311       }
312       extension->AddWebExtentPattern(pattern);
313     }
314   }
315
316   // An extension may override at most one page.
317   if (overrides->size() > 1) {
318     *error = ASCIIToUTF16(errors::kMultipleOverrides);
319     return false;
320   }
321   extension->SetManifestData(keys::kChromeURLOverrides,
322                              url_overrides.release());
323   return true;
324 }
325
326 const std::vector<std::string> URLOverridesHandler::Keys() const {
327   return SingleKey(keys::kChromeURLOverrides);
328 }
329
330 }  // namespace extensions