Upstream version 6.35.131.0
[platform/framework/web/crosswalk.git] / src / xwalk / application / common / application_resource.cc
1 // Copyright (c) 2012 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_resource.h"
6
7 #include <vector>
8
9 #include "base/file_util.h"
10 #include "base/logging.h"
11 #include "base/threading/thread_restrictions.h"
12
13 namespace xwalk {
14 namespace application {
15 namespace {
16 const base::FilePath::StringType WGT_LOCALE_DIRECTORY =
17     FILE_PATH_LITERAL("locales");
18 }  // namespace
19
20 ApplicationResource::ApplicationResource() : follow_symlinks_anywhere_(false) {
21 }
22
23 ApplicationResource::ApplicationResource(const std::string& application_id,
24                                      const base::FilePath& application_root,
25                                      const base::FilePath& relative_path)
26     : application_id_(application_id),
27       application_root_(application_root),
28       relative_path_(relative_path),
29       follow_symlinks_anywhere_(false) {
30 }
31
32 ApplicationResource::~ApplicationResource() {}
33
34 void ApplicationResource::set_follow_symlinks_anywhere() {
35   follow_symlinks_anywhere_ = true;
36 }
37
38 const base::FilePath& ApplicationResource::GetFilePath() const {
39   if (application_root_.empty() || relative_path_.empty()) {
40     DCHECK(full_resource_path_.empty());
41     return full_resource_path_;
42   }
43
44   // We've already checked, just return last value.
45   if (!full_resource_path_.empty())
46     return full_resource_path_;
47
48   for (std::list<std::string>::const_iterator it = locales_.begin();
49        it != locales_.end(); ++it) {
50     full_resource_path_ = GetFilePath(
51         application_root_,
52         base::FilePath(WGT_LOCALE_DIRECTORY)
53         .AppendASCII(*it).Append(relative_path_),
54         follow_symlinks_anywhere_ ?
55         FOLLOW_SYMLINKS_ANYWHERE : SYMLINKS_MUST_RESOLVE_WITHIN_ROOT);
56     if (!full_resource_path_.empty())
57       return full_resource_path_;
58   }
59   full_resource_path_ = GetFilePath(
60       application_root_, relative_path_,
61       follow_symlinks_anywhere_ ?
62           FOLLOW_SYMLINKS_ANYWHERE : SYMLINKS_MUST_RESOLVE_WITHIN_ROOT);
63   return full_resource_path_;
64 }
65
66 // static
67 base::FilePath ApplicationResource::GetFilePath(
68     const base::FilePath& application_root,
69     const base::FilePath& relative_path,
70     SymlinkPolicy symlink_policy) {
71   // We need to resolve the parent references in the application_root
72   // path on its own because IsParent doesn't like parent references.
73   base::FilePath clean_application_root(
74       base::MakeAbsoluteFilePath(application_root));
75   if (clean_application_root.empty())
76     return base::FilePath();
77
78   base::FilePath full_path = clean_application_root.Append(relative_path);
79
80   // If we are allowing the file to be a symlink outside of the root, then the
81   // path before resolving the symlink must still be within it.
82   if (symlink_policy == FOLLOW_SYMLINKS_ANYWHERE) {
83     std::vector<base::FilePath::StringType> components;
84     relative_path.GetComponents(&components);
85     int depth = 0;
86
87     for (std::vector<base::FilePath::StringType>::const_iterator
88          i = components.begin(); i != components.end(); i++) {
89       if (*i == base::FilePath::kParentDirectory) {
90         depth--;
91       } else if (*i != base::FilePath::kCurrentDirectory) {
92         depth++;
93       }
94       if (depth < 0) {
95         return base::FilePath();
96       }
97     }
98   }
99
100   // We must resolve the absolute path of the combined path when
101   // the relative path contains references to a parent folder (i.e., '..').
102   // We also check if the path exists because the posix version of
103   // MakeAbsoluteFilePath will fail if the path doesn't exist, and we want the
104   // same behavior on Windows... So until the posix and Windows version of
105   // MakeAbsoluteFilePath are unified, we need an extra call to PathExists,
106   // unfortunately.
107   // TODO(mad): Fix this once MakeAbsoluteFilePath is unified.
108   full_path = base::MakeAbsoluteFilePath(full_path);
109   if (base::PathExists(full_path) &&
110       (symlink_policy == FOLLOW_SYMLINKS_ANYWHERE ||
111        clean_application_root.IsParent(full_path))) {
112     return full_path;
113   }
114
115   return base::FilePath();
116 }
117
118 // Unit-testing helpers.
119 base::FilePath::StringType ApplicationResource::NormalizeSeperators(
120     const base::FilePath::StringType& path) const {
121 #if defined(FILE_PATH_USES_WIN_SEPARATORS)
122   base::FilePath::StringType win_path = path;
123   for (size_t i = 0; i < win_path.length(); i++) {
124     if (base::FilePath::IsSeparator(win_path[i]))
125       win_path[i] = base::FilePath::kSeparators[0];
126   }
127   return win_path;
128 #else
129   return path;
130 #endif  // FILE_PATH_USES_WIN_SEPARATORS
131 }
132
133 bool ApplicationResource::ComparePathWithDefault(
134     const base::FilePath& path) const {
135   // Make sure we have a cached value to test against...
136   if (full_resource_path_.empty())
137     GetFilePath();
138   if (NormalizeSeperators(path.value()) ==
139     NormalizeSeperators(full_resource_path_.value())) {
140     return true;
141   } else {
142     return false;
143   }
144 }
145
146 }  // namespace application
147 }  // namespace xwalk