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