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