Upstream version 9.38.204.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     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<Manifest> manifest(new Manifest(
54       scoped_ptr<base::DictionaryValue>(manifest_data.DeepCopy())));
55
56   if (!manifest->ValidateManifest(error_message))
57     return NULL;
58
59   scoped_refptr<ApplicationData> app_data =
60       new ApplicationData(path, source_type, manifest.Pass());
61   if (!app_data->Init(explicit_id, &error)) {
62     *error_message = base::UTF16ToUTF8(error);
63     return NULL;
64   }
65
66   return app_data;
67 }
68
69 // static
70 GURL ApplicationData::GetBaseURLFromApplicationId(
71     const std::string& application_id) {
72   return GURL(std::string(xwalk::application::kApplicationScheme) +
73               url::kStandardSchemeSeparator + application_id + "/");
74 }
75
76 ApplicationData::ManifestData* ApplicationData::GetManifestData(
77         const std::string& key) const {
78   DCHECK(finished_parsing_manifest_ || thread_checker_.CalledOnValidThread());
79   ManifestDataMap::const_iterator iter = manifest_data_.find(key);
80   if (iter != manifest_data_.end())
81     return iter->second.get();
82   return NULL;
83 }
84
85 void ApplicationData::SetManifestData(const std::string& key,
86                                       ApplicationData::ManifestData* data) {
87   DCHECK(!finished_parsing_manifest_ && thread_checker_.CalledOnValidThread());
88   manifest_data_[key] = linked_ptr<ManifestData>(data);
89 }
90
91 const std::string& ApplicationData::ID() const {
92   return manifest_->GetApplicationID();
93 }
94
95 #if defined(OS_TIZEN)
96 std::string ApplicationData::GetPackageID() const {
97   return AppIdToPkgId(manifest_->GetApplicationID());
98 }
99 #endif
100
101 const std::string ApplicationData::VersionString() const {
102   if (!version_->components().empty())
103     return Version()->GetString();
104
105   return "";
106 }
107
108 bool ApplicationData::IsHostedApp() const {
109   return GetManifest()->IsHosted();
110 }
111
112 ApplicationData::ApplicationData(const base::FilePath& path,
113     SourceType source_type, scoped_ptr<Manifest> manifest)
114     : manifest_version_(0),
115       manifest_(manifest.release()),
116       finished_parsing_manifest_(false),
117       source_type_(source_type) {
118   DCHECK(path.empty() || path.IsAbsolute());
119   path_ = path;
120   if (manifest_->HasPath(widget_keys::kWidgetKey))
121     package_type_ = Package::WGT;
122   else
123     package_type_ = Package::XPK;
124 }
125
126 ApplicationData::~ApplicationData() {
127 }
128
129 // static
130 GURL ApplicationData::GetResourceURL(const GURL& application_url,
131                                const std::string& relative_path) {
132   DCHECK(application_url.SchemeIs(kApplicationScheme));
133   DCHECK_EQ("/", application_url.path());
134
135   std::string path = relative_path;
136
137   // If the relative path starts with "/", it is "absolute" relative to the
138   // application base directory, but application_url is already specified to
139   // refer to that base directory, so strip the leading "/" if present.
140   if (relative_path.size() > 0 && relative_path[0] == '/')
141     path = relative_path.substr(1);
142
143   GURL ret_val = GURL(application_url.spec() + path);
144   DCHECK(StartsWithASCII(ret_val.spec(), application_url.spec(), false));
145
146   return ret_val;
147 }
148
149 Manifest::Type ApplicationData::GetType() const {
150   return manifest_->GetType();
151 }
152
153 bool ApplicationData::Init(const std::string& explicit_id,
154                            base::string16* error) {
155   DCHECK(error);
156   ManifestHandlerRegistry* registry =
157       ManifestHandlerRegistry::GetInstance(GetPackageType());
158   if (!registry->ParseAppManifest(this, error))
159     return false;
160
161   if (!LoadID(explicit_id, error))
162     return false;
163   if (!LoadName(error))
164     return false;
165   if (!LoadVersion(error))
166     return false;
167   if (!LoadDescription(error))
168     return false;
169
170   application_url_ = ApplicationData::GetBaseURLFromApplicationId(ID());
171
172   finished_parsing_manifest_ = true;
173   return true;
174 }
175
176 bool ApplicationData::LoadID(const std::string& explicit_id,
177                              base::string16* error) {
178   std::string application_id;
179 #if defined(OS_TIZEN)
180   if (GetPackageType() == Package::WGT) {
181     const TizenApplicationInfo* tizen_app_info =
182         static_cast<TizenApplicationInfo*>(GetManifestData(
183             widget_keys::kTizenApplicationKey));
184     CHECK(tizen_app_info);
185     application_id = tizen_app_info->id();
186   } else if (manifest_->HasKey(keys::kTizenAppIdKey)) {
187     if (!manifest_->GetString(keys::kTizenAppIdKey, &application_id)) {
188       NOTREACHED() << "Could not get Tizen application key";
189       return false;
190     }
191   }
192
193   if (!application_id.empty()) {
194     manifest_->SetApplicationID(application_id);
195     return true;
196   }
197 #endif
198
199   if (!explicit_id.empty()) {
200     manifest_->SetApplicationID(explicit_id);
201     return true;
202   }
203
204   application_id = GenerateIdForPath(path_);
205   if (application_id.empty()) {
206     NOTREACHED() << "Could not create ID from path.";
207     return false;
208   }
209   manifest_->SetApplicationID(application_id);
210   return true;
211 }
212
213 bool ApplicationData::LoadName(base::string16* error) {
214   DCHECK(error);
215   base::string16 localized_name;
216   std::string name_key(GetNameKey(GetPackageType()));
217
218   if (!manifest_->GetString(name_key, &localized_name) &&
219       package_type_ == Package::XPK) {
220     *error = base::ASCIIToUTF16(errors::kInvalidName);
221     return false;
222   }
223   non_localized_name_ = base::UTF16ToUTF8(localized_name);
224   base::i18n::AdjustStringForLocaleDirection(&localized_name);
225   name_ = base::UTF16ToUTF8(localized_name);
226   return true;
227 }
228
229 bool ApplicationData::LoadVersion(base::string16* error) {
230   DCHECK(error);
231   std::string version_str;
232
233   version_.reset(new base::Version());
234
235   if (package_type_ == Package::WGT) {
236     bool ok = manifest_->GetString(widget_keys::kVersionKey, &version_str);
237     if (!ok) {
238       *error = base::ASCIIToUTF16(errors::kInvalidVersion);
239       return true;
240     }
241
242     version_.reset(new base::Version(version_str));
243     return true;
244   }
245
246   // W3C Manifest (XPK and hosted):
247
248   bool hasDeprecatedKey = manifest_->HasKey(keys::kDeprecatedVersionKey);
249   bool hasKey = manifest_->HasKey(keys::kXWalkVersionKey);
250
251   if (!hasKey && !hasDeprecatedKey) {
252     // xwalk_version is optional.
253     return true;
254   }
255
256   bool ok = false;
257   if (hasKey) {
258     if (hasDeprecatedKey) {
259       LOG(WARNING) << "Deprecated key '" << keys::kDeprecatedVersionKey
260           << "' found in addition to '" << keys::kXWalkVersionKey
261           << "'. Consider removing.";
262     }
263     ok = manifest_->GetString(keys::kXWalkVersionKey, &version_str);
264   }
265
266   if (!hasKey && hasDeprecatedKey) {
267     LOG(WARNING) << "Deprecated key '" << keys::kDeprecatedVersionKey
268         << "' found. Please migrate to using '" << keys::kXWalkVersionKey
269         << "' instead.";
270     ok = manifest_->GetString(keys::kDeprecatedVersionKey, &version_str);
271   }
272
273   version_.reset(new base::Version(version_str));
274
275   if (!ok || !version_->IsValid() || version_->components().size() > 4) {
276     *error = base::ASCIIToUTF16(errors::kInvalidVersion);
277     version_.reset(new base::Version());
278     return false;
279   }
280
281   return ok;
282 }
283
284 bool ApplicationData::LoadDescription(base::string16* error) {
285   DCHECK(error);
286   // FIXME: Better to assert on use from Widget.
287   if (package_type_ != Package::XPK)
288     return true;  // No error.
289
290   bool hasDeprecatedKey = manifest_->HasKey(keys::kDeprecatedDescriptionKey);
291   bool hasKey = manifest_->HasKey(keys::kXWalkDescriptionKey);
292
293   if (hasKey) {
294     if (hasDeprecatedKey) {
295       LOG(WARNING) << "Deprecated key '" << keys::kDeprecatedDescriptionKey
296           << "' found in addition to '" << keys::kXWalkDescriptionKey
297           << "'. Consider removing.";
298     }
299     bool ok = manifest_->GetString(keys::kXWalkDescriptionKey, &description_);
300     if (!ok)
301       *error = base::ASCIIToUTF16(errors::kInvalidDescription);
302     return ok;
303   }
304
305   if (hasDeprecatedKey) {
306     LOG(WARNING) << "Deprecated key '" << keys::kDeprecatedDescriptionKey
307         << "' found. Please migrate to using '" << keys::kXWalkDescriptionKey
308         << "' instead.";
309     bool ok = manifest_->GetString(
310         keys::kDeprecatedDescriptionKey, &description_);
311     if (!ok)
312       *error = base::ASCIIToUTF16(errors::kInvalidDescription);
313     return ok;
314   }
315
316   // No error but also no description found.
317   return true;
318 }
319
320 StoredPermission ApplicationData::GetPermission(
321     const std::string& permission_name) const {
322   StoredPermissionMap::const_iterator iter =
323       permission_map_.find(permission_name);
324   if (iter == permission_map_.end())
325     return UNDEFINED_STORED_PERM;
326   return iter->second;
327 }
328
329 bool ApplicationData::SetPermission(const std::string& permission_name,
330                                     StoredPermission perm) {
331   if (perm != UNDEFINED_STORED_PERM) {
332     permission_map_[permission_name] = perm;
333     return true;
334   }
335   return false;
336 }
337
338 void ApplicationData::ClearPermissions() {
339   permission_map_.clear();
340 }
341
342 PermissionSet ApplicationData::GetManifestPermissions() const {
343   PermissionSet permissions;
344   if (manifest_->value()->HasKey(keys::kPermissionsKey)) {
345     const PermissionsInfo* perm_info = static_cast<PermissionsInfo*>(
346                            GetManifestData(keys::kPermissionsKey));
347     permissions = perm_info->GetAPIPermissions();
348   }
349   return permissions;
350 }
351
352 bool ApplicationData::HasCSPDefined() const {
353 #if defined(OS_TIZEN)
354   return  manifest_->HasPath(GetCSPKey(package_type_)) ||
355           manifest_->HasPath(widget_keys::kCSPReportOnlyKey) ||
356           manifest_->HasPath(widget_keys::kAllowNavigationKey);
357 #else
358   return manifest_->HasPath(GetCSPKey(package_type_));
359 #endif
360 }
361
362 bool ApplicationData::SetApplicationLocale(const std::string& locale,
363                                            base::string16* error) {
364   DCHECK(thread_checker_.CalledOnValidThread());
365   manifest_->SetSystemLocale(locale);
366   if (!LoadName(error))
367     return false;
368   if (!LoadDescription(error))
369     return false;
370
371   // Only update when the package is wgt and we have parsed the widget handler,
372   // otherwise we can not get widget_info.
373   if (WidgetInfo* widget_info = static_cast<WidgetInfo*>(
374           GetManifestData(widget_keys::kWidgetKey))) {
375     std::string string_value;
376     if (manifest_->GetString(widget_keys::kNameKey, &string_value))
377       widget_info->SetName(string_value);
378     if (manifest_->GetString(widget_keys::kShortNameKey, &string_value))
379       widget_info->SetShortName(string_value);
380     if (manifest_->GetString(widget_keys::kDescriptionKey, &string_value))
381       widget_info->SetDescription(string_value);
382   }
383   return true;
384 }
385
386 }   // namespace application
387 }   // namespace xwalk