1 // Copyright (c) 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 "xwalk/application/common/application_data.h"
7 #include "base/base64.h"
8 #include "base/basictypes.h"
9 #include "base/command_line.h"
10 #include "base/file_util.h"
11 #include "base/files/file_path.h"
12 #include "base/i18n/rtl.h"
13 #include "base/logging.h"
14 #include "base/memory/singleton.h"
15 #include "base/stl_util.h"
16 #include "base/strings/string16.h"
17 #include "base/strings/string_util.h"
18 #include "base/strings/stringprintf.h"
19 #include "base/strings/string_number_conversions.h"
20 #include "base/strings/string_piece.h"
21 #include "base/strings/utf_string_conversions.h"
22 #include "base/values.h"
23 #include "base/version.h"
24 #include "xwalk/application/common/application_manifest_constants.h"
25 #include "xwalk/application/common/id_util.h"
26 #include "xwalk/application/common/constants.h"
27 #include "xwalk/application/common/manifest.h"
28 #include "xwalk/application/common/manifest_handler.h"
29 #include "xwalk/application/common/manifest_handlers/permissions_handler.h"
30 #include "xwalk/application/common/manifest_handlers/widget_handler.h"
31 #include "xwalk/application/common/manifest_handlers/tizen_application_handler.h"
32 #include "xwalk/application/common/permission_policy_manager.h"
33 #include "content/public/common/url_constants.h"
34 #include "url/url_util.h"
35 #include "ui/base/l10n/l10n_util.h"
37 namespace keys = xwalk::application_manifest_keys;
38 namespace widget_keys = xwalk::application_widget_keys;
39 namespace errors = xwalk::application_manifest_errors;
42 namespace application {
45 scoped_refptr<ApplicationData> ApplicationData::Create(
46 const base::FilePath& path,
47 Manifest::SourceType source_type,
48 const base::DictionaryValue& manifest_data,
49 const std::string& explicit_id,
50 std::string* error_message) {
51 DCHECK(error_message);
53 scoped_ptr<xwalk::application::Manifest> manifest(
54 new xwalk::application::Manifest(source_type,
55 scoped_ptr<base::DictionaryValue>(manifest_data.DeepCopy())));
57 if (!manifest->ValidateManifest(error_message))
60 scoped_refptr<ApplicationData> application = new ApplicationData(path,
62 if (!application->Init(explicit_id, &error)) {
63 *error_message = base::UTF16ToUTF8(error);
71 scoped_refptr<ApplicationData> ApplicationData::Create(
73 std::string* error_message) {
74 const std::string& url_spec = url.spec();
75 DCHECK(!url_spec.empty());
76 const std::string& app_id = GenerateId(url_spec);
78 base::DictionaryValue manifest;
79 // FIXME: define permissions!
80 manifest.SetString(application_manifest_keys::kStartURLKey, url_spec);
81 // FIXME: Why use URL as name?
82 manifest.SetString(application_manifest_keys::kNameKey, url_spec);
83 manifest.SetString(application_manifest_keys::kXWalkVersionKey, "0");
84 scoped_refptr<ApplicationData> application_data =
85 ApplicationData::Create(base::FilePath(), Manifest::COMMAND_LINE,
86 manifest, app_id, error_message);
88 return application_data;
92 GURL ApplicationData::GetBaseURLFromApplicationId(
93 const std::string& application_id) {
94 return GURL(std::string(xwalk::application::kApplicationScheme) +
95 url::kStandardSchemeSeparator + application_id + "/");
98 ApplicationData::ManifestData* ApplicationData::GetManifestData(
99 const std::string& key) const {
100 DCHECK(finished_parsing_manifest_ || thread_checker_.CalledOnValidThread());
101 ManifestDataMap::const_iterator iter = manifest_data_.find(key);
102 if (iter != manifest_data_.end())
103 return iter->second.get();
107 void ApplicationData::SetManifestData(const std::string& key,
108 ApplicationData::ManifestData* data) {
109 DCHECK(!finished_parsing_manifest_ && thread_checker_.CalledOnValidThread());
110 manifest_data_[key] = linked_ptr<ManifestData>(data);
113 Manifest::SourceType ApplicationData::GetSourceType() const {
114 return manifest_->GetSourceType();
117 const std::string& ApplicationData::ID() const {
118 return manifest_->GetApplicationID();
121 #if defined(OS_TIZEN)
122 std::string ApplicationData::GetPackageID() const {
123 return AppIdToPkgId(manifest_->GetApplicationID());
127 const std::string ApplicationData::VersionString() const {
128 if (!version_->components().empty())
129 return Version()->GetString();
134 bool ApplicationData::IsPlatformApp() const {
135 return manifest_->IsPackaged();
138 bool ApplicationData::IsHostedApp() const {
139 return GetManifest()->IsHosted();
142 ApplicationData::ApplicationData(const base::FilePath& path,
143 scoped_ptr<xwalk::application::Manifest> manifest)
144 : manifest_version_(0),
145 manifest_(manifest.release()),
146 finished_parsing_manifest_(false) {
147 DCHECK(path.empty() || path.IsAbsolute());
149 if (manifest_->HasPath(widget_keys::kWidgetKey))
150 package_type_ = Package::WGT;
152 package_type_ = Package::XPK;
155 ApplicationData::~ApplicationData() {
159 GURL ApplicationData::GetResourceURL(const GURL& application_url,
160 const std::string& relative_path) {
161 DCHECK(application_url.SchemeIs(xwalk::application::kApplicationScheme));
162 DCHECK_EQ("/", application_url.path());
164 std::string path = relative_path;
166 // If the relative path starts with "/", it is "absolute" relative to the
167 // application base directory, but application_url is already specified to
168 // refer to that base directory, so strip the leading "/" if present.
169 if (relative_path.size() > 0 && relative_path[0] == '/')
170 path = relative_path.substr(1);
172 GURL ret_val = GURL(application_url.spec() + path);
173 DCHECK(StartsWithASCII(ret_val.spec(), application_url.spec(), false));
178 Manifest::Type ApplicationData::GetType() const {
179 return manifest_->GetType();
182 bool ApplicationData::Init(const std::string& explicit_id,
183 base::string16* error) {
185 ManifestHandlerRegistry* registry =
186 ManifestHandlerRegistry::GetInstance(GetPackageType());
187 if (!registry->ParseAppManifest(this, error))
190 if (!LoadID(explicit_id, error))
192 if (!LoadName(error))
194 if (!LoadVersion(error))
196 if (!LoadDescription(error))
199 application_url_ = ApplicationData::GetBaseURLFromApplicationId(ID());
201 finished_parsing_manifest_ = true;
205 bool ApplicationData::LoadID(const std::string& explicit_id,
206 base::string16* error) {
207 std::string application_id;
208 #if defined(OS_TIZEN)
209 if (GetPackageType() == Package::WGT) {
210 const TizenApplicationInfo* tizen_app_info =
211 static_cast<TizenApplicationInfo*>(GetManifestData(
212 widget_keys::kTizenApplicationKey));
213 CHECK(tizen_app_info);
214 application_id = tizen_app_info->id();
215 } else if (manifest_->HasKey(keys::kTizenAppIdKey)) {
216 if (!manifest_->GetString(keys::kTizenAppIdKey, &application_id)) {
217 NOTREACHED() << "Could not get Tizen application key";
222 if (!application_id.empty()) {
223 manifest_->SetApplicationID(application_id);
228 if (!explicit_id.empty()) {
229 manifest_->SetApplicationID(explicit_id);
233 application_id = GenerateIdForPath(path_);
234 if (application_id.empty()) {
235 NOTREACHED() << "Could not create ID from path.";
238 manifest_->SetApplicationID(application_id);
242 bool ApplicationData::LoadName(base::string16* error) {
244 base::string16 localized_name;
245 std::string name_key(GetNameKey(GetPackageType()));
247 if (!manifest_->GetString(name_key, &localized_name) &&
248 package_type_ == Package::XPK) {
249 *error = base::ASCIIToUTF16(errors::kInvalidName);
252 non_localized_name_ = base::UTF16ToUTF8(localized_name);
253 base::i18n::AdjustStringForLocaleDirection(&localized_name);
254 name_ = base::UTF16ToUTF8(localized_name);
258 bool ApplicationData::LoadVersion(base::string16* error) {
260 std::string version_str;
262 version_.reset(new base::Version());
264 if (package_type_ == Package::WGT) {
265 bool ok = manifest_->GetString(widget_keys::kVersionKey, &version_str);
267 *error = base::ASCIIToUTF16(errors::kInvalidVersion);
271 version_.reset(new base::Version(version_str));
275 // W3C Manifest (XPK and hosted):
277 bool hasDeprecatedKey = manifest_->HasKey(keys::kDeprecatedVersionKey);
278 bool hasKey = manifest_->HasKey(keys::kXWalkVersionKey);
280 if (!hasKey && !hasDeprecatedKey) {
281 // xwalk_version is optional.
287 if (hasDeprecatedKey) {
288 LOG(WARNING) << "Deprecated key '" << keys::kDeprecatedVersionKey
289 << "' found in addition to '" << keys::kXWalkVersionKey
290 << "'. Consider removing.";
292 ok = manifest_->GetString(keys::kXWalkVersionKey, &version_str);
295 if (!hasKey && hasDeprecatedKey) {
296 LOG(WARNING) << "Deprecated key '" << keys::kDeprecatedVersionKey
297 << "' found. Please migrate to using '" << keys::kXWalkVersionKey
299 ok = manifest_->GetString(keys::kDeprecatedVersionKey, &version_str);
302 version_.reset(new base::Version(version_str));
304 if (!ok || !version_->IsValid() || version_->components().size() > 4) {
305 *error = base::ASCIIToUTF16(errors::kInvalidVersion);
306 version_.reset(new base::Version());
313 bool ApplicationData::LoadDescription(base::string16* error) {
315 // FIXME: Better to assert on use from Widget.
316 if (package_type_ != Package::XPK)
317 return true; // No error.
319 bool hasDeprecatedKey = manifest_->HasKey(keys::kDeprecatedDescriptionKey);
320 bool hasKey = manifest_->HasKey(keys::kXWalkDescriptionKey);
323 if (hasDeprecatedKey) {
324 LOG(WARNING) << "Deprecated key '" << keys::kDeprecatedDescriptionKey
325 << "' found in addition to '" << keys::kXWalkDescriptionKey
326 << "'. Consider removing.";
328 bool ok = manifest_->GetString(keys::kXWalkDescriptionKey, &description_);
330 *error = base::ASCIIToUTF16(errors::kInvalidDescription);
334 if (hasDeprecatedKey) {
335 LOG(WARNING) << "Deprecated key '" << keys::kDeprecatedDescriptionKey
336 << "' found. Please migrate to using '" << keys::kXWalkDescriptionKey
338 bool ok = manifest_->GetString(
339 keys::kDeprecatedDescriptionKey, &description_);
341 *error = base::ASCIIToUTF16(errors::kInvalidDescription);
345 // No error but also no description found.
349 StoredPermission ApplicationData::GetPermission(
350 const std::string& permission_name) const {
351 StoredPermissionMap::const_iterator iter =
352 permission_map_.find(permission_name);
353 if (iter == permission_map_.end())
354 return UNDEFINED_STORED_PERM;
358 bool ApplicationData::SetPermission(const std::string& permission_name,
359 StoredPermission perm) {
360 if (perm != UNDEFINED_STORED_PERM) {
361 permission_map_[permission_name] = perm;
367 void ApplicationData::ClearPermissions() {
368 permission_map_.clear();
371 PermissionSet ApplicationData::GetManifestPermissions() const {
372 PermissionSet permissions;
373 if (manifest_->value()->HasKey(keys::kPermissionsKey)) {
374 const PermissionsInfo* perm_info = static_cast<PermissionsInfo*>(
375 GetManifestData(keys::kPermissionsKey));
376 permissions = perm_info->GetAPIPermissions();
381 bool ApplicationData::HasCSPDefined() const {
382 #if defined(OS_TIZEN)
383 return manifest_->HasPath(GetCSPKey(package_type_)) ||
384 manifest_->HasPath(widget_keys::kCSPReportOnlyKey) ||
385 manifest_->HasPath(widget_keys::kAllowNavigationKey);
387 return manifest_->HasPath(GetCSPKey(package_type_));
391 bool ApplicationData::SetApplicationLocale(const std::string& locale,
392 base::string16* error) {
393 DCHECK(thread_checker_.CalledOnValidThread());
394 manifest_->SetSystemLocale(locale);
395 if (!LoadName(error))
397 if (!LoadDescription(error))
400 // Only update when the package is wgt and we have parsed the widget handler,
401 // otherwise we can not get widget_info.
402 if (WidgetInfo* widget_info = static_cast<WidgetInfo*>(
403 GetManifestData(widget_keys::kWidgetKey))) {
404 std::string string_value;
405 if (manifest_->GetString(widget_keys::kNameKey, &string_value))
406 widget_info->SetName(string_value);
407 if (manifest_->GetString(widget_keys::kShortNameKey, &string_value))
408 widget_info->SetShortName(string_value);
409 if (manifest_->GetString(widget_keys::kDescriptionKey, &string_value))
410 widget_info->SetDescription(string_value);
415 } // namespace application