d37c75f08d5fcc24f7b6904b6258841a6b9fe85d
[platform/framework/web/crosswalk.git] / src / xwalk / application / common / application_data.cc
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.
4
5 #include "xwalk/application/common/application_data.h"
6
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"
35
36 #if defined(OS_TIZEN)
37 #include "xwalk/tizen/appcore_context.h"
38 #endif
39
40 namespace keys = xwalk::application_manifest_keys;
41 namespace widget_keys = xwalk::application_widget_keys;
42 namespace errors = xwalk::application_manifest_errors;
43
44 namespace xwalk {
45 namespace application {
46
47 // static
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);
55   base::string16 error;
56   scoped_ptr<xwalk::application::Manifest> manifest(
57       new xwalk::application::Manifest(source_type,
58                  scoped_ptr<base::DictionaryValue>(manifest_data.DeepCopy())));
59
60   if (!InitApplicationID(manifest.get(), path, explicit_id, &error)) {
61     *error_message = base::UTF16ToUTF8(error);
62     return NULL;
63   }
64
65   std::vector<InstallWarning> install_warnings;
66   if (!manifest->ValidateManifest(error_message, &install_warnings)) {
67     return NULL;
68   }
69
70   scoped_refptr<ApplicationData> application = new ApplicationData(path,
71                                                            manifest.Pass());
72   application->install_warnings_.swap(install_warnings);
73
74   if (!application->Init(&error)) {
75     *error_message = base::UTF16ToUTF8(error);
76     return NULL;
77   }
78
79   return application;
80 }
81
82 // static
83 bool ApplicationData::IsIDValid(const std::string& id) {
84   std::string temp = StringToLowerASCII(id);
85
86 #if defined(OS_TIZEN)
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');
92       if (!valid)
93         return false;
94     }
95
96     return true;
97   }
98 #endif
99
100   // Verify that the id is legal.
101   if (temp.size() != (kIdSize * 2))
102     return false;
103
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')
108       return false;
109
110   return true;
111 }
112
113 // static
114 GURL ApplicationData::GetBaseURLFromApplicationId(
115     const std::string& application_id) {
116   return GURL(std::string(xwalk::application::kApplicationScheme) +
117               content::kStandardSchemeSeparator + application_id + "/");
118 }
119
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();
126   return NULL;
127 }
128
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);
133 }
134
135 Manifest::SourceType ApplicationData::GetSourceType() const {
136   return manifest_->GetSourceType();
137 }
138
139 const std::string& ApplicationData::ID() const {
140   return manifest_->GetApplicationID();
141 }
142
143 const std::string ApplicationData::VersionString() const {
144   return Version()->GetString();
145 }
146
147 bool ApplicationData::IsPlatformApp() const {
148   return manifest_->IsPackaged();
149 }
150
151 bool ApplicationData::IsHostedApp() const {
152   return GetManifest()->IsHosted();
153 }
154
155 Manifest::PackageType ApplicationData::GetPackageType() const {
156   return manifest_->GetPackageType();
157 }
158
159 bool ApplicationData::HasMainDocument() const {
160   MainDocumentInfo* main_info = ToMainDocumentInfo(
161       GetManifestData(application_manifest_keys::kAppMainKey));
162
163   return main_info != NULL;
164 }
165
166 // static
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";
176       return false;
177     }
178   }
179
180   if (!application_id.empty()) {
181     manifest->SetApplicationID(application_id);
182     return true;
183   }
184 #endif
185
186   if (!explicit_id.empty()) {
187     manifest->SetApplicationID(explicit_id);
188     return true;
189   }
190
191   application_id = GenerateIdForPath(path);
192   if (application_id.empty()) {
193     NOTREACHED() << "Could not create ID from path.";
194     return false;
195   }
196   manifest->SetApplicationID(application_id);
197   return true;
198 }
199
200 ApplicationData::ApplicationData(const base::FilePath& path,
201                      scoped_ptr<xwalk::application::Manifest> manifest)
202     : manifest_version_(0),
203       is_dirty_(false),
204       manifest_(manifest.release()),
205       finished_parsing_manifest_(false) {
206   DCHECK(path.empty() || path.IsAbsolute());
207   path_ = path;
208 }
209
210 ApplicationData::~ApplicationData() {
211 }
212
213 // static
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());
218
219   std::string path = relative_path;
220
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);
226
227   GURL ret_val = GURL(application_url.spec() + path);
228   DCHECK(StartsWithASCII(ret_val.spec(), application_url.spec(), false));
229
230   return ret_val;
231 }
232
233 Manifest::Type ApplicationData::GetType() const {
234   return manifest_->GetType();
235 }
236
237 bool ApplicationData::Init(base::string16* error) {
238   DCHECK(error);
239
240   if (!LoadName(error))
241     return false;
242   if (!LoadVersion(error))
243       return false;
244   if (!LoadDescription(error))
245       return false;
246   if (!LoadManifestVersion(error))
247     return false;
248
249   application_url_ = ApplicationData::GetBaseURLFromApplicationId(ID());
250
251   ManifestHandlerRegistry* registry =
252       ManifestHandlerRegistry::GetInstance(GetPackageType());
253   if (!registry->ParseAppManifest(this, error))
254     return false;
255
256   finished_parsing_manifest_ = true;
257 #if defined(OS_TIZEN)
258   appcore_context_ = tizen::AppcoreContext::Create();
259 #endif
260   return true;
261 }
262
263 bool ApplicationData::LoadName(base::string16* error) {
264   DCHECK(error);
265   base::string16 localized_name;
266   std::string name_key(GetNameKey(GetPackageType()));
267
268   if (!manifest_->GetString(name_key, &localized_name)) {
269     *error = base::ASCIIToUTF16(errors::kInvalidName);
270     return false;
271   }
272   non_localized_name_ = base::UTF16ToUTF8(localized_name);
273   base::i18n::AdjustStringForLocaleDirection(&localized_name);
274   name_ = base::UTF16ToUTF8(localized_name);
275   return true;
276 }
277
278 bool ApplicationData::LoadVersion(base::string16* error) {
279   DCHECK(error);
280   std::string version_str;
281   std::string version_key(GetVersionKey(GetPackageType()));
282
283   if (!manifest_->GetString(version_key, &version_str)) {
284     *error = base::ASCIIToUTF16(errors::kInvalidVersion);
285     return false;
286   }
287   version_.reset(new base::Version(version_str));
288   if (!version_->IsValid() || version_->components().size() > 4) {
289     *error = base::ASCIIToUTF16(errors::kInvalidVersion);
290     return false;
291   }
292   return true;
293 }
294
295 bool ApplicationData::LoadDescription(base::string16* error) {
296   DCHECK(error);
297   if (manifest_->HasKey(keys::kDescriptionKey) &&
298       !manifest_->GetString(keys::kDescriptionKey, &description_)) {
299     *error = base::ASCIIToUTF16(errors::kInvalidDescription);
300     return false;
301   }
302   return true;
303 }
304
305 bool ApplicationData::LoadManifestVersion(base::string16* error) {
306   DCHECK(error);
307   // Get the original value out of the dictionary so that we can validate it
308   // more strictly.
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);
314       return false;
315     }
316   }
317
318   manifest_version_ = manifest_->GetManifestVersion();
319   return true;
320 }
321
322 void ApplicationData::SetEvents(const std::set<std::string>& events) {
323   events_ = events;
324   is_dirty_ = true;
325 }
326
327 const std::set<std::string>& ApplicationData::GetEvents() const {
328   return events_;
329 }
330
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;
337   return iter->second;
338 }
339
340 bool ApplicationData::SetPermission(const std::string& permission_name,
341                                     StoredPermission perm) {
342   if (perm != UNDEFINED_STORED_PERM) {
343     permission_map_[permission_name] = perm;
344     is_dirty_ = true;
345     return true;
346   }
347   return false;
348 }
349
350 void ApplicationData::ClearPermissions() {
351   permission_map_.clear();
352 }
353
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();
360   }
361   return permissions;
362 }
363
364 }   // namespace application
365 }   // namespace xwalk