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/main_document_handler.h"
30 #include "xwalk/application/common/manifest_handlers/permissions_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"
37 #include "xwalk/tizen/appcore_context.h"
40 namespace keys = xwalk::application_manifest_keys;
41 namespace widget_keys = xwalk::application_widget_keys;
42 namespace errors = xwalk::application_manifest_errors;
45 namespace application {
48 scoped_refptr<ApplicationData> ApplicationData::Create(
49 const base::FilePath& path,
50 Manifest::SourceType source_type,
51 const base::DictionaryValue& manifest_data,
52 const std::string& explicit_id,
53 std::string* error_message) {
54 DCHECK(error_message);
56 scoped_ptr<xwalk::application::Manifest> manifest(
57 new xwalk::application::Manifest(source_type,
58 scoped_ptr<base::DictionaryValue>(manifest_data.DeepCopy())));
60 if (!InitApplicationID(manifest.get(), path, explicit_id, &error)) {
61 *error_message = base::UTF16ToUTF8(error);
65 std::vector<InstallWarning> install_warnings;
66 if (!manifest->ValidateManifest(error_message, &install_warnings)) {
70 scoped_refptr<ApplicationData> application = new ApplicationData(path,
72 application->install_warnings_.swap(install_warnings);
74 if (!application->Init(&error)) {
75 *error_message = base::UTF16ToUTF8(error);
83 bool ApplicationData::IsIDValid(const std::string& id) {
84 std::string temp = StringToLowerASCII(id);
87 // An ID with 10 characters is most likely a legacy Tizen ID.
88 if (temp.size() == kLegacyTizenIdSize) {
89 for (size_t i = 0; i < kLegacyTizenIdSize; ++i) {
90 const char c = temp[i];
91 const bool valid = (c >= '0' && c <= '9') || (c >= 'a' && c <= 'z');
100 // Verify that the id is legal.
101 if (temp.size() != (kIdSize * 2))
104 // We only support lowercase IDs, because IDs can be used as URL components
105 // (where GURL will lowercase it).
106 for (size_t i = 0; i < temp.size(); ++i)
107 if (temp[i] < 'a' || temp[i] > 'p')
114 GURL ApplicationData::GetBaseURLFromApplicationId(
115 const std::string& application_id) {
116 return GURL(std::string(xwalk::application::kApplicationScheme) +
117 content::kStandardSchemeSeparator + application_id + "/");
120 ApplicationData::ManifestData* ApplicationData::GetManifestData(
121 const std::string& key) const {
122 DCHECK(finished_parsing_manifest_ || thread_checker_.CalledOnValidThread());
123 ManifestDataMap::const_iterator iter = manifest_data_.find(key);
124 if (iter != manifest_data_.end())
125 return iter->second.get();
129 void ApplicationData::SetManifestData(const std::string& key,
130 ApplicationData::ManifestData* data) {
131 DCHECK(!finished_parsing_manifest_ && thread_checker_.CalledOnValidThread());
132 manifest_data_[key] = linked_ptr<ManifestData>(data);
135 Manifest::SourceType ApplicationData::GetSourceType() const {
136 return manifest_->GetSourceType();
139 const std::string& ApplicationData::ID() const {
140 return manifest_->GetApplicationID();
143 const std::string ApplicationData::VersionString() const {
144 return Version()->GetString();
147 bool ApplicationData::IsPlatformApp() const {
148 return manifest_->IsPackaged();
151 bool ApplicationData::IsHostedApp() const {
152 return GetManifest()->IsHosted();
155 Manifest::PackageType ApplicationData::GetPackageType() const {
156 return manifest_->GetPackageType();
159 bool ApplicationData::HasMainDocument() const {
160 MainDocumentInfo* main_info = ToMainDocumentInfo(
161 GetManifestData(application_manifest_keys::kAppMainKey));
163 return main_info != NULL;
167 bool ApplicationData::InitApplicationID(xwalk::application::Manifest* manifest,
168 const base::FilePath& path,
169 const std::string& explicit_id,
170 base::string16* error) {
171 std::string application_id;
172 #if defined(OS_TIZEN)
173 if (manifest->HasKey(keys::kTizenAppIdKey)) {
174 if (!manifest->GetString(keys::kTizenAppIdKey, &application_id)) {
175 NOTREACHED() << "Could not get Tizen application key";
180 if (!application_id.empty()) {
181 manifest->SetApplicationID(application_id);
186 if (!explicit_id.empty()) {
187 manifest->SetApplicationID(explicit_id);
191 application_id = GenerateIdForPath(path);
192 if (application_id.empty()) {
193 NOTREACHED() << "Could not create ID from path.";
196 manifest->SetApplicationID(application_id);
200 ApplicationData::ApplicationData(const base::FilePath& path,
201 scoped_ptr<xwalk::application::Manifest> manifest)
202 : manifest_version_(0),
204 manifest_(manifest.release()),
205 finished_parsing_manifest_(false) {
206 DCHECK(path.empty() || path.IsAbsolute());
210 ApplicationData::~ApplicationData() {
214 GURL ApplicationData::GetResourceURL(const GURL& application_url,
215 const std::string& relative_path) {
216 DCHECK(application_url.SchemeIs(xwalk::application::kApplicationScheme));
217 DCHECK_EQ("/", application_url.path());
219 std::string path = relative_path;
221 // If the relative path starts with "/", it is "absolute" relative to the
222 // application base directory, but application_url is already specified to
223 // refer to that base directory, so strip the leading "/" if present.
224 if (relative_path.size() > 0 && relative_path[0] == '/')
225 path = relative_path.substr(1);
227 GURL ret_val = GURL(application_url.spec() + path);
228 DCHECK(StartsWithASCII(ret_val.spec(), application_url.spec(), false));
233 Manifest::Type ApplicationData::GetType() const {
234 return manifest_->GetType();
237 bool ApplicationData::Init(base::string16* error) {
240 if (!LoadName(error))
242 if (!LoadVersion(error))
244 if (!LoadDescription(error))
246 if (!LoadManifestVersion(error))
249 application_url_ = ApplicationData::GetBaseURLFromApplicationId(ID());
251 ManifestHandlerRegistry* registry =
252 ManifestHandlerRegistry::GetInstance(GetPackageType());
253 if (!registry->ParseAppManifest(this, error))
256 finished_parsing_manifest_ = true;
257 #if defined(OS_TIZEN)
258 appcore_context_ = tizen::AppcoreContext::Create();
263 bool ApplicationData::LoadName(base::string16* error) {
265 base::string16 localized_name;
266 std::string name_key(GetNameKey(GetPackageType()));
268 if (!manifest_->GetString(name_key, &localized_name)) {
269 *error = base::ASCIIToUTF16(errors::kInvalidName);
272 non_localized_name_ = base::UTF16ToUTF8(localized_name);
273 base::i18n::AdjustStringForLocaleDirection(&localized_name);
274 name_ = base::UTF16ToUTF8(localized_name);
278 bool ApplicationData::LoadVersion(base::string16* error) {
280 std::string version_str;
281 std::string version_key(GetVersionKey(GetPackageType()));
283 if (!manifest_->GetString(version_key, &version_str)) {
284 *error = base::ASCIIToUTF16(errors::kInvalidVersion);
287 version_.reset(new base::Version(version_str));
288 if (!version_->IsValid() || version_->components().size() > 4) {
289 *error = base::ASCIIToUTF16(errors::kInvalidVersion);
295 bool ApplicationData::LoadDescription(base::string16* error) {
297 if (manifest_->HasKey(keys::kDescriptionKey) &&
298 !manifest_->GetString(keys::kDescriptionKey, &description_)) {
299 *error = base::ASCIIToUTF16(errors::kInvalidDescription);
305 bool ApplicationData::LoadManifestVersion(base::string16* error) {
307 // Get the original value out of the dictionary so that we can validate it
309 if (manifest_->value()->HasKey(keys::kManifestVersionKey)) {
310 int manifest_version = 1;
311 if (!manifest_->GetInteger(keys::kManifestVersionKey, &manifest_version) ||
312 manifest_version < 1) {
313 *error = base::ASCIIToUTF16(errors::kInvalidManifestVersion);
318 manifest_version_ = manifest_->GetManifestVersion();
322 void ApplicationData::SetEvents(const std::set<std::string>& events) {
327 const std::set<std::string>& ApplicationData::GetEvents() const {
331 StoredPermission ApplicationData::GetPermission(
332 std::string& permission_name) const {
333 StoredPermissionMap::const_iterator iter =
334 permission_map_.find(permission_name);
335 if (iter == permission_map_.end())
336 return UNDEFINED_STORED_PERM;
340 bool ApplicationData::SetPermission(const std::string& permission_name,
341 StoredPermission perm) {
342 if (perm != UNDEFINED_STORED_PERM) {
343 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 } // namespace application