Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / chrome / common / extensions / manifest_handlers / app_launch_info.cc
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.
4
5 #include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
6
7 #include "base/command_line.h"
8 #include "base/lazy_instance.h"
9 #include "base/memory/scoped_ptr.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "base/values.h"
12 #include "chrome/common/chrome_switches.h"
13 #include "chrome/common/extensions/extension_constants.h"
14 #include "chrome/common/url_constants.h"
15 #include "components/cloud_devices/common/cloud_devices_urls.h"
16 #include "extensions/common/error_utils.h"
17 #include "extensions/common/manifest_constants.h"
18
19 namespace extensions {
20
21 namespace keys = manifest_keys;
22 namespace values = manifest_values;
23 namespace errors = manifest_errors;
24
25 namespace {
26
27 bool ReadLaunchDimension(const extensions::Manifest* manifest,
28                          const char* key,
29                          int* target,
30                          bool is_valid_container,
31                          base::string16* error) {
32   const base::Value* temp = NULL;
33   if (manifest->Get(key, &temp)) {
34     if (!is_valid_container) {
35       *error = ErrorUtils::FormatErrorMessageUTF16(
36           errors::kInvalidLaunchValueContainer,
37           key);
38       return false;
39     }
40     if (!temp->GetAsInteger(target) || *target < 0) {
41       *target = 0;
42       *error = ErrorUtils::FormatErrorMessageUTF16(
43           errors::kInvalidLaunchValue,
44           key);
45       return false;
46     }
47   }
48   return true;
49 }
50
51 static base::LazyInstance<AppLaunchInfo> g_empty_app_launch_info =
52     LAZY_INSTANCE_INITIALIZER;
53
54 const AppLaunchInfo& GetAppLaunchInfo(const Extension* extension) {
55   AppLaunchInfo* info = static_cast<AppLaunchInfo*>(
56       extension->GetManifestData(keys::kLaunch));
57   return info ? *info : g_empty_app_launch_info.Get();
58 }
59
60 }  // namespace
61
62 AppLaunchInfo::AppLaunchInfo()
63     : launch_container_(LAUNCH_CONTAINER_TAB),
64       launch_width_(0),
65       launch_height_(0) {
66 }
67
68 AppLaunchInfo::~AppLaunchInfo() {
69 }
70
71 // static
72 const std::string& AppLaunchInfo::GetLaunchLocalPath(
73     const Extension* extension) {
74   return GetAppLaunchInfo(extension).launch_local_path_;
75 }
76
77 // static
78 const GURL& AppLaunchInfo::GetLaunchWebURL(
79     const Extension* extension) {
80   return GetAppLaunchInfo(extension).launch_web_url_;
81 }
82
83 // static
84 extensions::LaunchContainer AppLaunchInfo::GetLaunchContainer(
85     const Extension* extension) {
86   return GetAppLaunchInfo(extension).launch_container_;
87 }
88
89 // static
90 int AppLaunchInfo::GetLaunchWidth(const Extension* extension) {
91   return GetAppLaunchInfo(extension).launch_width_;
92 }
93
94 // static
95 int AppLaunchInfo::GetLaunchHeight(const Extension* extension) {
96   return GetAppLaunchInfo(extension).launch_height_;
97 }
98
99 // static
100 GURL AppLaunchInfo::GetFullLaunchURL(const Extension* extension) {
101   const AppLaunchInfo& info = GetAppLaunchInfo(extension);
102   if (info.launch_local_path_.empty())
103     return info.launch_web_url_;
104   else
105     return extension->url().Resolve(info.launch_local_path_);
106 }
107
108 bool AppLaunchInfo::Parse(Extension* extension, base::string16* error) {
109   if (!LoadLaunchURL(extension, error) ||
110       !LoadLaunchContainer(extension, error))
111     return false;
112   return true;
113 }
114
115 bool AppLaunchInfo::LoadLaunchURL(Extension* extension, base::string16* error) {
116   const base::Value* temp = NULL;
117
118   // Launch URL can be either local (to chrome-extension:// root) or an absolute
119   // web URL.
120   if (extension->manifest()->Get(keys::kLaunchLocalPath, &temp)) {
121     if (extension->manifest()->Get(keys::kLaunchWebURL, NULL)) {
122       *error = base::ASCIIToUTF16(errors::kLaunchPathAndURLAreExclusive);
123       return false;
124     }
125
126     if (extension->manifest()->Get(keys::kWebURLs, NULL)) {
127       *error = base::ASCIIToUTF16(errors::kLaunchPathAndExtentAreExclusive);
128       return false;
129     }
130
131     std::string launch_path;
132     if (!temp->GetAsString(&launch_path)) {
133       *error = ErrorUtils::FormatErrorMessageUTF16(
134           errors::kInvalidLaunchValue,
135           keys::kLaunchLocalPath);
136       return false;
137     }
138
139     // Ensure the launch path is a valid relative URL.
140     GURL resolved = extension->url().Resolve(launch_path);
141     if (!resolved.is_valid() || resolved.GetOrigin() != extension->url()) {
142       *error = ErrorUtils::FormatErrorMessageUTF16(
143           errors::kInvalidLaunchValue,
144           keys::kLaunchLocalPath);
145       return false;
146     }
147
148     launch_local_path_ = launch_path;
149   } else if (extension->manifest()->Get(keys::kLaunchWebURL, &temp)) {
150     std::string launch_url;
151     if (!temp->GetAsString(&launch_url)) {
152       *error = ErrorUtils::FormatErrorMessageUTF16(
153           errors::kInvalidLaunchValue,
154           keys::kLaunchWebURL);
155       return false;
156     }
157
158     // Ensure the launch web URL is a valid absolute URL and web extent scheme.
159     GURL url(launch_url);
160     URLPattern pattern(Extension::kValidWebExtentSchemes);
161     if (!url.is_valid() || !pattern.SetScheme(url.scheme())) {
162       *error = ErrorUtils::FormatErrorMessageUTF16(
163           errors::kInvalidLaunchValue,
164           keys::kLaunchWebURL);
165       return false;
166     }
167
168     launch_web_url_ = url;
169   } else if (extension->is_legacy_packaged_app()) {
170     *error = base::ASCIIToUTF16(errors::kLaunchURLRequired);
171     return false;
172   }
173
174   // For the Chrome component app, override launch url to new tab.
175   if (extension->id() == extension_misc::kChromeAppId) {
176     launch_web_url_ = GURL(chrome::kChromeUINewTabURL);
177     return true;
178   }
179
180   // If there is no extent, we default the extent based on the launch URL.
181   if (extension->web_extent().is_empty() && !launch_web_url_.is_empty()) {
182     URLPattern pattern(Extension::kValidWebExtentSchemes);
183     if (!pattern.SetScheme("*")) {
184       *error = ErrorUtils::FormatErrorMessageUTF16(
185           errors::kInvalidLaunchValue,
186           keys::kLaunchWebURL);
187       return false;
188     }
189     pattern.SetHost(launch_web_url_.host());
190     pattern.SetPath("/*");
191     extension->AddWebExtentPattern(pattern);
192   }
193
194   // In order for the --apps-gallery-url switch to work with the gallery
195   // process isolation, we must insert any provided value into the component
196   // app's launch url and web extent.
197   if (extension->id() == extension_misc::kWebStoreAppId) {
198     std::string gallery_url_str = CommandLine::ForCurrentProcess()->
199         GetSwitchValueASCII(switches::kAppsGalleryURL);
200
201     // Empty string means option was not used.
202     if (!gallery_url_str.empty()) {
203       GURL gallery_url(gallery_url_str);
204       OverrideLaunchURL(extension, gallery_url);
205     }
206   } else if (extension->id() == extension_misc::kCloudPrintAppId) {
207     // In order for the --cloud-print-service switch to work, we must update
208     // the launch URL and web extent.
209     GURL url =
210         cloud_devices::GetCloudPrintRelativeURL("enable_chrome_connector");
211     if (!url.is_empty()) {
212       OverrideLaunchURL(extension, url);
213     }
214   }
215
216   return true;
217 }
218
219 bool AppLaunchInfo::LoadLaunchContainer(Extension* extension,
220                                         base::string16* error) {
221   const base::Value* tmp_launcher_container = NULL;
222   if (!extension->manifest()->Get(keys::kLaunchContainer,
223                                   &tmp_launcher_container))
224     return true;
225
226   std::string launch_container_string;
227   if (!tmp_launcher_container->GetAsString(&launch_container_string)) {
228     *error = base::ASCIIToUTF16(errors::kInvalidLaunchContainer);
229     return false;
230   }
231
232   if (launch_container_string == values::kLaunchContainerPanel) {
233     launch_container_ = LAUNCH_CONTAINER_PANEL;
234   } else if (launch_container_string == values::kLaunchContainerTab) {
235     launch_container_ = LAUNCH_CONTAINER_TAB;
236   } else {
237     *error = base::ASCIIToUTF16(errors::kInvalidLaunchContainer);
238     return false;
239   }
240
241   bool can_specify_initial_size = launch_container_ == LAUNCH_CONTAINER_PANEL;
242
243   // Validate the container width if present.
244   if (!ReadLaunchDimension(extension->manifest(),
245                            keys::kLaunchWidth,
246                            &launch_width_,
247                            can_specify_initial_size,
248                            error)) {
249     return false;
250   }
251
252   // Validate container height if present.
253   if (!ReadLaunchDimension(extension->manifest(),
254                            keys::kLaunchHeight,
255                            &launch_height_,
256                            can_specify_initial_size,
257                            error)) {
258     return false;
259   }
260
261   return true;
262 }
263
264 void AppLaunchInfo::OverrideLaunchURL(Extension* extension,
265                                       GURL override_url) {
266   if (!override_url.is_valid()) {
267     DLOG(WARNING) << "Invalid override url given for " << extension->name();
268     return;
269   }
270   if (override_url.has_port()) {
271     DLOG(WARNING) << "Override URL passed for " << extension->name()
272                   << " should not contain a port.  Removing it.";
273
274     GURL::Replacements remove_port;
275     remove_port.ClearPort();
276     override_url = override_url.ReplaceComponents(remove_port);
277   }
278
279   launch_web_url_ = override_url;
280
281   URLPattern pattern(Extension::kValidWebExtentSchemes);
282   URLPattern::ParseResult result = pattern.Parse(override_url.spec());
283   DCHECK_EQ(result, URLPattern::PARSE_SUCCESS);
284   pattern.SetPath(pattern.path() + '*');
285   extension->AddWebExtentPattern(pattern);
286 }
287
288 AppLaunchManifestHandler::AppLaunchManifestHandler() {
289 }
290
291 AppLaunchManifestHandler::~AppLaunchManifestHandler() {
292 }
293
294 bool AppLaunchManifestHandler::Parse(Extension* extension,
295                                      base::string16* error) {
296   scoped_ptr<AppLaunchInfo> info(new AppLaunchInfo);
297   if (!info->Parse(extension, error))
298     return false;
299   extension->SetManifestData(keys::kLaunch, info.release());
300   return true;
301 }
302
303 bool AppLaunchManifestHandler::AlwaysParseForType(Manifest::Type type) const {
304   return type == Manifest::TYPE_LEGACY_PACKAGED_APP;
305 }
306
307 const std::vector<std::string> AppLaunchManifestHandler::Keys() const {
308   static const char* keys[] = {
309     keys::kLaunchLocalPath,
310     keys::kLaunchWebURL,
311     keys::kLaunchContainer,
312     keys::kLaunchHeight,
313     keys::kLaunchWidth
314   };
315   return std::vector<std::string>(keys, keys + arraysize(keys));
316 }
317
318 }  // namespace extensions