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/files/file_path.h"
11 #include "base/files/file_util.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, const std::string& explicit_id,
47 SourceType source_type, scoped_ptr<Manifest> manifest,
48 std::string* error_message) {
49 DCHECK(error_message);
51 if (!manifest->ValidateManifest(error_message))
54 scoped_refptr<ApplicationData> app_data =
55 new ApplicationData(path, source_type, manifest.Pass());
56 if (!app_data->Init(explicit_id, &error)) {
57 *error_message = base::UTF16ToUTF8(error);
61 ManifestHandlerRegistry* registry =
62 ManifestHandlerRegistry::GetInstance(app_data->manifest_type());
64 if (!registry->ValidateAppManifest(app_data, error_message))
71 GURL ApplicationData::GetBaseURLFromApplicationId(
72 const std::string& application_id) {
73 return GURL(std::string(kApplicationScheme) +
74 url::kStandardSchemeSeparator + application_id + "/");
77 ApplicationData::ManifestData* ApplicationData::GetManifestData(
78 const std::string& key) const {
79 DCHECK(finished_parsing_manifest_ || thread_checker_.CalledOnValidThread());
80 ManifestDataMap::const_iterator iter = manifest_data_.find(key);
81 if (iter != manifest_data_.end())
82 return iter->second.get();
86 void ApplicationData::SetManifestData(const std::string& key,
87 ApplicationData::ManifestData* data) {
88 DCHECK(!finished_parsing_manifest_ && thread_checker_.CalledOnValidThread());
89 manifest_data_[key] = linked_ptr<ManifestData>(data);
93 std::string ApplicationData::GetPackageID() const {
94 return AppIdToPkgId(application_id_);
98 const std::string ApplicationData::VersionString() const {
99 if (!version_->components().empty())
100 return Version()->GetString();
105 bool ApplicationData::IsHostedApp() const {
106 bool hosted = source_type_ == EXTERNAL_URL;
107 #if defined(OS_TIZEN)
108 if (manifest_->HasPath(widget_keys::kContentNamespace)) {
110 if (manifest_->GetString(widget_keys::kContentNamespace, &ns) &&
111 ns == widget_keys::kTizenNamespacePrefix)
118 ApplicationData::ApplicationData(const base::FilePath& path,
119 SourceType source_type, scoped_ptr<Manifest> manifest)
120 : manifest_version_(0),
122 manifest_(manifest.release()),
123 finished_parsing_manifest_(false),
124 source_type_(source_type) {
125 DCHECK(path_.empty() || path_.IsAbsolute());
128 ApplicationData::~ApplicationData() {
132 GURL ApplicationData::GetResourceURL(const GURL& application_url,
133 const std::string& relative_path) {
134 DCHECK(application_url.SchemeIs(kApplicationScheme));
135 DCHECK_EQ("/", application_url.path());
137 std::string path = relative_path;
139 // If the relative path starts with "/", it is "absolute" relative to the
140 // application base directory, but application_url is already specified to
141 // refer to that base directory, so strip the leading "/" if present.
142 if (relative_path.size() > 0 && relative_path[0] == '/')
143 path = relative_path.substr(1);
145 GURL ret_val = GURL(application_url.spec() + path);
146 DCHECK(StartsWithASCII(ret_val.spec(), application_url.spec(), false));
151 GURL ApplicationData::GetResourceURL(const std::string& relative_path) const {
153 if (!base::PathExists(path_.Append(base::UTF8ToWide(relative_path)))) {
155 if (!base::PathExists(path_.Append(relative_path))) {
157 LOG(ERROR) << "The path does not exist in the application directory: "
162 return GetResourceURL(URL(), relative_path);
165 bool ApplicationData::Init(const std::string& explicit_id,
166 base::string16* error) {
168 ManifestHandlerRegistry* registry =
169 ManifestHandlerRegistry::GetInstance(manifest_type());
170 if (!registry->ParseAppManifest(this, error))
173 if (!LoadID(explicit_id, error))
175 if (!LoadName(error))
177 if (!LoadVersion(error))
179 if (!LoadDescription(error))
182 application_url_ = ApplicationData::GetBaseURLFromApplicationId(ID());
184 finished_parsing_manifest_ = true;
188 bool ApplicationData::LoadID(const std::string& explicit_id,
189 base::string16* error) {
190 std::string application_id;
191 #if defined(OS_TIZEN)
192 if (manifest_type() == Manifest::TYPE_WIDGET) {
193 const TizenApplicationInfo* tizen_app_info =
194 static_cast<TizenApplicationInfo*>(GetManifestData(
195 widget_keys::kTizenApplicationKey));
196 CHECK(tizen_app_info);
197 application_id = tizen_app_info->id();
198 } else if (manifest_->HasKey(keys::kTizenAppIdKey)) {
199 if (!manifest_->GetString(keys::kTizenAppIdKey, &application_id)) {
200 NOTREACHED() << "Could not get Tizen application key";
205 if (!application_id.empty()) {
206 application_id_ = application_id;
211 if (!explicit_id.empty()) {
212 application_id_ = explicit_id;
216 application_id = GenerateIdForPath(path_);
217 if (application_id.empty()) {
218 NOTREACHED() << "Could not create ID from path.";
221 application_id_ = application_id;
225 bool ApplicationData::LoadName(base::string16* error) {
227 base::string16 localized_name;
228 std::string name_key(GetNameKey(manifest_type()));
230 if (!manifest_->GetString(name_key, &localized_name) &&
231 manifest_type() == Manifest::TYPE_MANIFEST) {
232 *error = base::ASCIIToUTF16(errors::kInvalidName);
235 non_localized_name_ = base::UTF16ToUTF8(localized_name);
236 base::i18n::AdjustStringForLocaleDirection(&localized_name);
237 name_ = base::UTF16ToUTF8(localized_name);
241 bool ApplicationData::LoadVersion(base::string16* error) {
243 std::string version_str;
245 version_.reset(new base::Version());
247 if (manifest_type() == Manifest::TYPE_WIDGET) {
248 bool ok = manifest_->GetString(widget_keys::kVersionKey, &version_str);
250 *error = base::ASCIIToUTF16(errors::kInvalidVersion);
254 version_.reset(new base::Version(version_str));
258 // W3C Manifest (XPK and hosted):
260 bool hasDeprecatedKey = manifest_->HasKey(keys::kDeprecatedVersionKey);
261 bool hasKey = manifest_->HasKey(keys::kXWalkVersionKey);
263 if (!hasKey && !hasDeprecatedKey) {
264 // xwalk_version is optional.
270 if (hasDeprecatedKey) {
271 LOG(WARNING) << "Deprecated key '" << keys::kDeprecatedVersionKey
272 << "' found in addition to '" << keys::kXWalkVersionKey
273 << "'. Consider removing.";
275 ok = manifest_->GetString(keys::kXWalkVersionKey, &version_str);
278 if (!hasKey && hasDeprecatedKey) {
279 LOG(WARNING) << "Deprecated key '" << keys::kDeprecatedVersionKey
280 << "' found. Please migrate to using '" << keys::kXWalkVersionKey
282 ok = manifest_->GetString(keys::kDeprecatedVersionKey, &version_str);
285 version_.reset(new base::Version(version_str));
287 if (!ok || !version_->IsValid() || version_->components().size() > 4) {
288 *error = base::ASCIIToUTF16(errors::kInvalidVersion);
289 version_.reset(new base::Version());
296 bool ApplicationData::LoadDescription(base::string16* error) {
298 // FIXME: Better to assert on use from Widget.
299 if (manifest_type() != Manifest::TYPE_MANIFEST)
300 return true; // No error.
302 bool hasDeprecatedKey = manifest_->HasKey(keys::kDeprecatedDescriptionKey);
303 bool hasKey = manifest_->HasKey(keys::kXWalkDescriptionKey);
306 if (hasDeprecatedKey) {
307 LOG(WARNING) << "Deprecated key '" << keys::kDeprecatedDescriptionKey
308 << "' found in addition to '" << keys::kXWalkDescriptionKey
309 << "'. Consider removing.";
311 bool ok = manifest_->GetString(keys::kXWalkDescriptionKey, &description_);
313 *error = base::ASCIIToUTF16(errors::kInvalidDescription);
317 if (hasDeprecatedKey) {
318 LOG(WARNING) << "Deprecated key '" << keys::kDeprecatedDescriptionKey
319 << "' found. Please migrate to using '" << keys::kXWalkDescriptionKey
321 bool ok = manifest_->GetString(
322 keys::kDeprecatedDescriptionKey, &description_);
324 *error = base::ASCIIToUTF16(errors::kInvalidDescription);
328 // No error but also no description found.
332 StoredPermission ApplicationData::GetPermission(
333 const std::string& permission_name) const {
334 StoredPermissionMap::const_iterator iter =
335 permission_map_.find(permission_name);
336 if (iter == permission_map_.end())
337 return UNDEFINED_STORED_PERM;
341 bool ApplicationData::SetPermission(const std::string& permission_name,
342 StoredPermission perm) {
343 if (perm != UNDEFINED_STORED_PERM) {
344 permission_map_[permission_name] = perm;
350 void ApplicationData::ClearPermissions() {
351 permission_map_.clear();
354 PermissionSet ApplicationData::GetManifestPermissions() const {
355 PermissionSet permissions;
356 if (manifest_->value()->HasKey(keys::kPermissionsKey)) {
357 const PermissionsInfo* perm_info = static_cast<PermissionsInfo*>(
358 GetManifestData(keys::kPermissionsKey));
359 permissions = perm_info->GetAPIPermissions();
364 bool ApplicationData::HasCSPDefined() const {
365 #if defined(OS_TIZEN)
366 return manifest_->HasPath(GetCSPKey(manifest_type())) ||
367 manifest_->HasPath(widget_keys::kCSPReportOnlyKey) ||
368 manifest_->HasPath(widget_keys::kAllowNavigationKey);
370 return manifest_->HasPath(GetCSPKey(manifest_type()));
374 bool ApplicationData::SetApplicationLocale(const std::string& locale,
375 base::string16* error) {
376 DCHECK(thread_checker_.CalledOnValidThread());
377 manifest_->SetSystemLocale(locale);
378 if (!LoadName(error))
380 if (!LoadDescription(error))
383 // Only update when the package is wgt and we have parsed the widget handler,
384 // otherwise we can not get widget_info.
385 if (WidgetInfo* widget_info = static_cast<WidgetInfo*>(
386 GetManifestData(widget_keys::kWidgetKey))) {
387 std::string string_value;
388 if (manifest_->GetString(widget_keys::kNameKey, &string_value))
389 widget_info->SetName(string_value);
390 if (manifest_->GetString(widget_keys::kShortNameKey, &string_value))
391 widget_info->SetShortName(string_value);
392 if (manifest_->GetString(widget_keys::kDescriptionKey, &string_value))
393 widget_info->SetDescription(string_value);
398 } // namespace application