Upstream version 9.38.198.0
[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/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"
36
37 namespace keys = xwalk::application_manifest_keys;
38 namespace widget_keys = xwalk::application_widget_keys;
39 namespace errors = xwalk::application_manifest_errors;
40
41 namespace xwalk {
42 namespace application {
43
44 // static
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);
52   base::string16 error;
53   scoped_ptr<xwalk::application::Manifest> manifest(
54       new xwalk::application::Manifest(source_type,
55                  scoped_ptr<base::DictionaryValue>(manifest_data.DeepCopy())));
56
57   if (!manifest->ValidateManifest(error_message))
58     return NULL;
59
60   scoped_refptr<ApplicationData> application = new ApplicationData(path,
61                                                            manifest.Pass());
62   if (!application->Init(explicit_id, &error)) {
63     *error_message = base::UTF16ToUTF8(error);
64     return NULL;
65   }
66
67   return application;
68 }
69
70 // static
71 scoped_refptr<ApplicationData> ApplicationData::Create(
72     const GURL& url,
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);
77
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);
87
88   return application_data;
89 }
90
91 // static
92 GURL ApplicationData::GetBaseURLFromApplicationId(
93     const std::string& application_id) {
94   return GURL(std::string(xwalk::application::kApplicationScheme) +
95               url::kStandardSchemeSeparator + application_id + "/");
96 }
97
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();
104   return NULL;
105 }
106
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);
111 }
112
113 Manifest::SourceType ApplicationData::GetSourceType() const {
114   return manifest_->GetSourceType();
115 }
116
117 const std::string& ApplicationData::ID() const {
118   return manifest_->GetApplicationID();
119 }
120
121 #if defined(OS_TIZEN)
122 std::string ApplicationData::GetPackageID() const {
123   return AppIdToPkgId(manifest_->GetApplicationID());
124 }
125 #endif
126
127 const std::string ApplicationData::VersionString() const {
128   if (!version_->components().empty())
129     return Version()->GetString();
130
131   return "";
132 }
133
134 bool ApplicationData::IsPlatformApp() const {
135   return manifest_->IsPackaged();
136 }
137
138 bool ApplicationData::IsHostedApp() const {
139   return GetManifest()->IsHosted();
140 }
141
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());
148   path_ = path;
149   if (manifest_->HasPath(widget_keys::kWidgetKey))
150     package_type_ = Package::WGT;
151   else
152     package_type_ = Package::XPK;
153 }
154
155 ApplicationData::~ApplicationData() {
156 }
157
158 // static
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());
163
164   std::string path = relative_path;
165
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);
171
172   GURL ret_val = GURL(application_url.spec() + path);
173   DCHECK(StartsWithASCII(ret_val.spec(), application_url.spec(), false));
174
175   return ret_val;
176 }
177
178 Manifest::Type ApplicationData::GetType() const {
179   return manifest_->GetType();
180 }
181
182 bool ApplicationData::Init(const std::string& explicit_id,
183                            base::string16* error) {
184   DCHECK(error);
185   ManifestHandlerRegistry* registry =
186       ManifestHandlerRegistry::GetInstance(GetPackageType());
187   if (!registry->ParseAppManifest(this, error))
188     return false;
189
190   if (!LoadID(explicit_id, error))
191     return false;
192   if (!LoadName(error))
193     return false;
194   if (!LoadVersion(error))
195     return false;
196   if (!LoadDescription(error))
197     return false;
198
199   application_url_ = ApplicationData::GetBaseURLFromApplicationId(ID());
200
201   finished_parsing_manifest_ = true;
202   return true;
203 }
204
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";
218       return false;
219     }
220   }
221
222   if (!application_id.empty()) {
223     manifest_->SetApplicationID(application_id);
224     return true;
225   }
226 #endif
227
228   if (!explicit_id.empty()) {
229     manifest_->SetApplicationID(explicit_id);
230     return true;
231   }
232
233   application_id = GenerateIdForPath(path_);
234   if (application_id.empty()) {
235     NOTREACHED() << "Could not create ID from path.";
236     return false;
237   }
238   manifest_->SetApplicationID(application_id);
239   return true;
240 }
241
242 bool ApplicationData::LoadName(base::string16* error) {
243   DCHECK(error);
244   base::string16 localized_name;
245   std::string name_key(GetNameKey(GetPackageType()));
246
247   if (!manifest_->GetString(name_key, &localized_name) &&
248       package_type_ == Package::XPK) {
249     *error = base::ASCIIToUTF16(errors::kInvalidName);
250     return false;
251   }
252   non_localized_name_ = base::UTF16ToUTF8(localized_name);
253   base::i18n::AdjustStringForLocaleDirection(&localized_name);
254   name_ = base::UTF16ToUTF8(localized_name);
255   return true;
256 }
257
258 bool ApplicationData::LoadVersion(base::string16* error) {
259   DCHECK(error);
260   std::string version_str;
261
262   version_.reset(new base::Version());
263
264   if (package_type_ == Package::WGT) {
265     bool ok = manifest_->GetString(widget_keys::kVersionKey, &version_str);
266     if (!ok) {
267       *error = base::ASCIIToUTF16(errors::kInvalidVersion);
268       return true;
269     }
270
271     version_.reset(new base::Version(version_str));
272     return true;
273   }
274
275   // W3C Manifest (XPK and hosted):
276
277   bool hasDeprecatedKey = manifest_->HasKey(keys::kDeprecatedVersionKey);
278   bool hasKey = manifest_->HasKey(keys::kXWalkVersionKey);
279
280   if (!hasKey && !hasDeprecatedKey) {
281     // xwalk_version is optional.
282     return true;
283   }
284
285   bool ok = false;
286   if (hasKey) {
287     if (hasDeprecatedKey) {
288       LOG(WARNING) << "Deprecated key '" << keys::kDeprecatedVersionKey
289           << "' found in addition to '" << keys::kXWalkVersionKey
290           << "'. Consider removing.";
291     }
292     ok = manifest_->GetString(keys::kXWalkVersionKey, &version_str);
293   }
294
295   if (!hasKey && hasDeprecatedKey) {
296     LOG(WARNING) << "Deprecated key '" << keys::kDeprecatedVersionKey
297         << "' found. Please migrate to using '" << keys::kXWalkVersionKey
298         << "' instead.";
299     ok = manifest_->GetString(keys::kDeprecatedVersionKey, &version_str);
300   }
301
302   version_.reset(new base::Version(version_str));
303
304   if (!ok || !version_->IsValid() || version_->components().size() > 4) {
305     *error = base::ASCIIToUTF16(errors::kInvalidVersion);
306     version_.reset(new base::Version());
307     return false;
308   }
309
310   return ok;
311 }
312
313 bool ApplicationData::LoadDescription(base::string16* error) {
314   DCHECK(error);
315   // FIXME: Better to assert on use from Widget.
316   if (package_type_ != Package::XPK)
317     return true;  // No error.
318
319   bool hasDeprecatedKey = manifest_->HasKey(keys::kDeprecatedDescriptionKey);
320   bool hasKey = manifest_->HasKey(keys::kXWalkDescriptionKey);
321
322   if (hasKey) {
323     if (hasDeprecatedKey) {
324       LOG(WARNING) << "Deprecated key '" << keys::kDeprecatedDescriptionKey
325           << "' found in addition to '" << keys::kXWalkDescriptionKey
326           << "'. Consider removing.";
327     }
328     bool ok = manifest_->GetString(keys::kXWalkDescriptionKey, &description_);
329     if (!ok)
330       *error = base::ASCIIToUTF16(errors::kInvalidDescription);
331     return ok;
332   }
333
334   if (hasDeprecatedKey) {
335     LOG(WARNING) << "Deprecated key '" << keys::kDeprecatedDescriptionKey
336         << "' found. Please migrate to using '" << keys::kXWalkDescriptionKey
337         << "' instead.";
338     bool ok = manifest_->GetString(
339         keys::kDeprecatedDescriptionKey, &description_);
340     if (!ok)
341       *error = base::ASCIIToUTF16(errors::kInvalidDescription);
342     return ok;
343   }
344
345   // No error but also no description found.
346   return true;
347 }
348
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;
355   return iter->second;
356 }
357
358 bool ApplicationData::SetPermission(const std::string& permission_name,
359                                     StoredPermission perm) {
360   if (perm != UNDEFINED_STORED_PERM) {
361     permission_map_[permission_name] = perm;
362     return true;
363   }
364   return false;
365 }
366
367 void ApplicationData::ClearPermissions() {
368   permission_map_.clear();
369 }
370
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();
377   }
378   return permissions;
379 }
380
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);
386 #else
387   return manifest_->HasPath(GetCSPKey(package_type_));
388 #endif
389 }
390
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))
396     return false;
397   if (!LoadDescription(error))
398     return false;
399
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);
411   }
412   return true;
413 }
414
415 }   // namespace application
416 }   // namespace xwalk