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