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/permission_policy_manager.h"
32 #include "content/public/common/url_constants.h"
33 #include "url/url_util.h"
34 #include "ui/base/l10n/l10n_util.h"
36 namespace keys = xwalk::application_manifest_keys;
37 namespace widget_keys = xwalk::application_widget_keys;
38 namespace errors = xwalk::application_manifest_errors;
41 namespace application {
44 scoped_refptr<ApplicationData> ApplicationData::Create(
45 const base::FilePath& path,
46 Manifest::SourceType source_type,
47 const base::DictionaryValue& manifest_data,
48 const std::string& explicit_id,
49 std::string* error_message) {
50 DCHECK(error_message);
52 scoped_ptr<xwalk::application::Manifest> manifest(
53 new xwalk::application::Manifest(source_type,
54 scoped_ptr<base::DictionaryValue>(manifest_data.DeepCopy())));
56 if (!InitApplicationID(manifest.get(), path, explicit_id, &error)) {
57 *error_message = base::UTF16ToUTF8(error);
61 std::vector<InstallWarning> install_warnings;
62 if (!manifest->ValidateManifest(error_message, &install_warnings)) {
66 scoped_refptr<ApplicationData> application = new ApplicationData(path,
68 application->install_warnings_.swap(install_warnings);
70 if (!application->Init(&error)) {
71 *error_message = base::UTF16ToUTF8(error);
79 bool ApplicationData::IsIDValid(const std::string& id) {
80 std::string temp = StringToLowerASCII(id);
83 // An ID with 10 characters is most likely a legacy Tizen ID.
84 if (temp.size() == kLegacyTizenIdSize) {
85 for (size_t i = 0; i < kLegacyTizenIdSize; ++i) {
86 const char c = temp[i];
87 const bool valid = (c >= '0' && c <= '9') || (c >= 'a' && c <= 'z');
96 // Verify that the id is legal.
97 if (temp.size() != (kIdSize * 2))
100 // We only support lowercase IDs, because IDs can be used as URL components
101 // (where GURL will lowercase it).
102 for (size_t i = 0; i < temp.size(); ++i)
103 if (temp[i] < 'a' || temp[i] > 'p')
110 GURL ApplicationData::GetBaseURLFromApplicationId(
111 const std::string& application_id) {
112 return GURL(std::string(xwalk::application::kApplicationScheme) +
113 content::kStandardSchemeSeparator + application_id + "/");
116 ApplicationData::ManifestData* ApplicationData::GetManifestData(
117 const std::string& key) const {
118 DCHECK(finished_parsing_manifest_ || thread_checker_.CalledOnValidThread());
119 ManifestDataMap::const_iterator iter = manifest_data_.find(key);
120 if (iter != manifest_data_.end())
121 return iter->second.get();
125 void ApplicationData::SetManifestData(const std::string& key,
126 ApplicationData::ManifestData* data) {
127 DCHECK(!finished_parsing_manifest_ && thread_checker_.CalledOnValidThread());
128 manifest_data_[key] = linked_ptr<ManifestData>(data);
131 Manifest::SourceType ApplicationData::GetSourceType() const {
132 return manifest_->GetSourceType();
135 const std::string& ApplicationData::ID() const {
136 return manifest_->GetApplicationID();
139 const std::string ApplicationData::VersionString() const {
140 if (!version_->components().empty())
141 return Version()->GetString();
146 bool ApplicationData::IsPlatformApp() const {
147 return manifest_->IsPackaged();
150 bool ApplicationData::IsHostedApp() const {
151 return GetManifest()->IsHosted();
155 bool ApplicationData::InitApplicationID(xwalk::application::Manifest* manifest,
156 const base::FilePath& path,
157 const std::string& explicit_id,
158 base::string16* error) {
159 std::string application_id;
160 #if defined(OS_TIZEN)
161 if (manifest->HasKey(keys::kTizenAppIdKey)) {
162 if (!manifest->GetString(keys::kTizenAppIdKey, &application_id)) {
163 NOTREACHED() << "Could not get Tizen application key";
168 if (!application_id.empty()) {
169 manifest->SetApplicationID(application_id);
174 if (!explicit_id.empty()) {
175 manifest->SetApplicationID(explicit_id);
179 application_id = GenerateIdForPath(path);
180 if (application_id.empty()) {
181 NOTREACHED() << "Could not create ID from path.";
184 manifest->SetApplicationID(application_id);
188 ApplicationData::ApplicationData(const base::FilePath& path,
189 scoped_ptr<xwalk::application::Manifest> manifest)
190 : manifest_version_(0),
192 manifest_(manifest.release()),
193 finished_parsing_manifest_(false) {
194 DCHECK(path.empty() || path.IsAbsolute());
196 if (manifest_->HasPath(widget_keys::kWidgetKey))
197 package_type_ = Package::WGT;
199 package_type_ = Package::XPK;
202 ApplicationData::~ApplicationData() {
206 GURL ApplicationData::GetResourceURL(const GURL& application_url,
207 const std::string& relative_path) {
208 DCHECK(application_url.SchemeIs(xwalk::application::kApplicationScheme));
209 DCHECK_EQ("/", application_url.path());
211 std::string path = relative_path;
213 // If the relative path starts with "/", it is "absolute" relative to the
214 // application base directory, but application_url is already specified to
215 // refer to that base directory, so strip the leading "/" if present.
216 if (relative_path.size() > 0 && relative_path[0] == '/')
217 path = relative_path.substr(1);
219 GURL ret_val = GURL(application_url.spec() + path);
220 DCHECK(StartsWithASCII(ret_val.spec(), application_url.spec(), false));
225 Manifest::Type ApplicationData::GetType() const {
226 return manifest_->GetType();
229 bool ApplicationData::Init(base::string16* error) {
232 if (!LoadName(error))
234 if (!LoadVersion(error))
236 if (!LoadDescription(error))
238 if (!LoadManifestVersion(error))
241 application_url_ = ApplicationData::GetBaseURLFromApplicationId(ID());
243 ManifestHandlerRegistry* registry =
244 ManifestHandlerRegistry::GetInstance(GetPackageType());
245 if (!registry->ParseAppManifest(this, error))
248 finished_parsing_manifest_ = true;
252 bool ApplicationData::LoadName(base::string16* error) {
254 base::string16 localized_name;
255 std::string name_key(GetNameKey(GetPackageType()));
257 if (!manifest_->GetString(name_key, &localized_name) &&
258 package_type_ == Package::XPK) {
259 *error = base::ASCIIToUTF16(errors::kInvalidName);
262 non_localized_name_ = base::UTF16ToUTF8(localized_name);
263 base::i18n::AdjustStringForLocaleDirection(&localized_name);
264 name_ = base::UTF16ToUTF8(localized_name);
268 bool ApplicationData::LoadVersion(base::string16* error) {
270 std::string version_str;
271 std::string version_key(GetVersionKey(GetPackageType()));
273 if (!manifest_->GetString(version_key, &version_str) &&
274 package_type_ == Package::XPK) {
275 *error = base::ASCIIToUTF16(errors::kInvalidVersion);
278 version_.reset(new base::Version(version_str));
279 if (package_type_ == Package::XPK &&
280 (!version_->IsValid() || version_->components().size() > 4)) {
281 *error = base::ASCIIToUTF16(errors::kInvalidVersion);
287 bool ApplicationData::LoadDescription(base::string16* error) {
289 if (manifest_->HasKey(keys::kDescriptionKey) &&
290 !manifest_->GetString(keys::kDescriptionKey, &description_) &&
291 package_type_ == Package::XPK) {
292 *error = base::ASCIIToUTF16(errors::kInvalidDescription);
298 bool ApplicationData::LoadManifestVersion(base::string16* error) {
300 // Get the original value out of the dictionary so that we can validate it
302 if (manifest_->value()->HasKey(keys::kManifestVersionKey)) {
303 int manifest_version = 1;
304 if (!manifest_->GetInteger(keys::kManifestVersionKey, &manifest_version) ||
305 manifest_version < 1) {
306 if (package_type_ == Package::XPK) {
307 *error = base::ASCIIToUTF16(errors::kInvalidManifestVersion);
313 manifest_version_ = manifest_->GetManifestVersion();
317 StoredPermission ApplicationData::GetPermission(
318 const std::string& permission_name) const {
319 StoredPermissionMap::const_iterator iter =
320 permission_map_.find(permission_name);
321 if (iter == permission_map_.end())
322 return UNDEFINED_STORED_PERM;
326 bool ApplicationData::SetPermission(const std::string& permission_name,
327 StoredPermission perm) {
328 if (perm != UNDEFINED_STORED_PERM) {
329 permission_map_[permission_name] = perm;
336 void ApplicationData::ClearPermissions() {
337 permission_map_.clear();
340 PermissionSet ApplicationData::GetManifestPermissions() const {
341 PermissionSet permissions;
342 if (manifest_->value()->HasKey(keys::kPermissionsKey)) {
343 const PermissionsInfo* perm_info = static_cast<PermissionsInfo*>(
344 GetManifestData(keys::kPermissionsKey));
345 permissions = perm_info->GetAPIPermissions();
350 bool ApplicationData::HasCSPDefined() const {
351 #if defined(OS_TIZEN)
352 return manifest_->HasPath(GetCSPKey(package_type_)) ||
353 manifest_->HasPath(widget_keys::kCSPReportOnlyKey) ||
354 manifest_->HasPath(widget_keys::kAllowNavigationKey);
356 return manifest_->HasPath(GetCSPKey(package_type_));
360 bool ApplicationData::SetApplicationLocale(const std::string& locale,
361 base::string16* error) {
362 DCHECK(thread_checker_.CalledOnValidThread());
363 manifest_->SetSystemLocale(locale);
364 if (!LoadName(error))
366 if (!LoadDescription(error))
369 // Only update when the package is wgt and we have parsed the widget handler,
370 // otherwise we can not get widget_info.
371 if (WidgetInfo* widget_info = static_cast<WidgetInfo*>(
372 GetManifestData(widget_keys::kWidgetKey))) {
373 std::string string_value;
374 if (manifest_->GetString(widget_keys::kNameKey, &string_value))
375 widget_info->SetName(string_value);
376 if (manifest_->GetString(widget_keys::kShortNameKey, &string_value))
377 widget_info->SetShortName(string_value);
378 if (manifest_->GetString(widget_keys::kDescriptionKey, &string_value))
379 widget_info->SetDescription(string_value);
384 } // namespace application