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 "webkit/browser/fileapi/file_system_url.h"
6
7 #include <sstream>
8
9 #include "base/logging.h"
10 #include "base/strings/string_util.h"
11 #include "net/base/escape.h"
12 #include "webkit/common/fileapi/file_system_types.h"
13 #include "webkit/common/fileapi/file_system_util.h"
14
15 namespace fileapi {
16
17 namespace {
18
19 } // namespace
20
FileSystemURL()21 FileSystemURL::FileSystemURL()
22 : is_valid_(false),
23 mount_type_(kFileSystemTypeUnknown),
24 type_(kFileSystemTypeUnknown),
25 mount_option_(COPY_SYNC_OPTION_NO_SYNC) {
26 }
27
28 // static
CreateForTest(const GURL & url)29 FileSystemURL FileSystemURL::CreateForTest(const GURL& url) {
30 return FileSystemURL(url);
31 }
32
CreateForTest(const GURL & origin,FileSystemType mount_type,const base::FilePath & virtual_path)33 FileSystemURL FileSystemURL::CreateForTest(const GURL& origin,
34 FileSystemType mount_type,
35 const base::FilePath& virtual_path) {
36 return FileSystemURL(origin, mount_type, virtual_path);
37 }
38
39 // static
ParseFileSystemSchemeURL(const GURL & url,GURL * origin_url,FileSystemType * mount_type,base::FilePath * virtual_path)40 bool FileSystemURL::ParseFileSystemSchemeURL(
41 const GURL& url,
42 GURL* origin_url,
43 FileSystemType* mount_type,
44 base::FilePath* virtual_path) {
45 GURL origin;
46 FileSystemType file_system_type = kFileSystemTypeUnknown;
47
48 if (!url.is_valid() || !url.SchemeIsFileSystem())
49 return false;
50
51 const struct {
52 FileSystemType type;
53 const char* dir;
54 } kValidTypes[] = {
55 { kFileSystemTypePersistent, kPersistentDir },
56 { kFileSystemTypeTemporary, kTemporaryDir },
57 { kFileSystemTypeIsolated, kIsolatedDir },
58 { kFileSystemTypeExternal, kExternalDir },
59 { kFileSystemTypeTest, kTestDir },
60 };
61
62 // A path of the inner_url contains only mount type part (e.g. "/temporary").
63 DCHECK(url.inner_url());
64 std::string inner_path = url.inner_url()->path();
65 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kValidTypes); ++i) {
66 if (inner_path == kValidTypes[i].dir) {
67 file_system_type = kValidTypes[i].type;
68 break;
69 }
70 }
71
72 if (file_system_type == kFileSystemTypeUnknown)
73 return false;
74
75 std::string path = net::UnescapeURLComponent(url.path(),
76 net::UnescapeRule::SPACES | net::UnescapeRule::URL_SPECIAL_CHARS |
77 net::UnescapeRule::CONTROL_CHARS);
78
79 // Ensure the path is relative.
80 while (!path.empty() && path[0] == '/')
81 path.erase(0, 1);
82
83 base::FilePath converted_path = base::FilePath::FromUTF8Unsafe(path);
84
85 // All parent references should have been resolved in the renderer.
86 if (converted_path.ReferencesParent())
87 return false;
88
89 if (origin_url)
90 *origin_url = url.GetOrigin();
91 if (mount_type)
92 *mount_type = file_system_type;
93 if (virtual_path)
94 *virtual_path = converted_path.NormalizePathSeparators().
95 StripTrailingSeparators();
96
97 return true;
98 }
99
FileSystemURL(const GURL & url)100 FileSystemURL::FileSystemURL(const GURL& url)
101 : mount_type_(kFileSystemTypeUnknown),
102 type_(kFileSystemTypeUnknown),
103 mount_option_(COPY_SYNC_OPTION_NO_SYNC) {
104 is_valid_ = ParseFileSystemSchemeURL(url, &origin_, &mount_type_,
105 &virtual_path_);
106 path_ = virtual_path_;
107 type_ = mount_type_;
108 }
109
FileSystemURL(const GURL & origin,FileSystemType mount_type,const base::FilePath & virtual_path)110 FileSystemURL::FileSystemURL(const GURL& origin,
111 FileSystemType mount_type,
112 const base::FilePath& virtual_path)
113 : is_valid_(true),
114 origin_(origin),
115 mount_type_(mount_type),
116 virtual_path_(virtual_path.NormalizePathSeparators()),
117 type_(mount_type),
118 path_(virtual_path.NormalizePathSeparators()),
119 mount_option_(COPY_SYNC_OPTION_NO_SYNC) {
120 }
121
FileSystemURL(const GURL & origin,FileSystemType mount_type,const base::FilePath & virtual_path,const std::string & mount_filesystem_id,FileSystemType cracked_type,const base::FilePath & cracked_path,const std::string & filesystem_id,const FileSystemMountOption & mount_option)122 FileSystemURL::FileSystemURL(const GURL& origin,
123 FileSystemType mount_type,
124 const base::FilePath& virtual_path,
125 const std::string& mount_filesystem_id,
126 FileSystemType cracked_type,
127 const base::FilePath& cracked_path,
128 const std::string& filesystem_id,
129 const FileSystemMountOption& mount_option)
130 : is_valid_(true),
131 origin_(origin),
132 mount_type_(mount_type),
133 virtual_path_(virtual_path.NormalizePathSeparators()),
134 mount_filesystem_id_(mount_filesystem_id),
135 type_(cracked_type),
136 path_(cracked_path.NormalizePathSeparators()),
137 filesystem_id_(filesystem_id),
138 mount_option_(mount_option) {
139 }
140
~FileSystemURL()141 FileSystemURL::~FileSystemURL() {}
142
ToGURL() const143 GURL FileSystemURL::ToGURL() const {
144 if (!is_valid_)
145 return GURL();
146
147 std::string url = GetFileSystemRootURI(origin_, mount_type_).spec();
148 if (url.empty())
149 return GURL();
150
151 url.append(virtual_path_.AsUTF8Unsafe());
152
153 // Build nested GURL.
154 return GURL(url);
155 }
156
DebugString() const157 std::string FileSystemURL::DebugString() const {
158 if (!is_valid_)
159 return "invalid filesystem: URL";
160 std::ostringstream ss;
161 ss << GetFileSystemRootURI(origin_, mount_type_);
162
163 // filesystem_id_ will be non empty for (and only for) cracked URLs.
164 if (!filesystem_id_.empty()) {
165 ss << virtual_path_.value();
166 ss << " (";
167 ss << GetFileSystemTypeString(type_) << "@" << filesystem_id_ << ":";
168 ss << path_.value();
169 ss << ")";
170 } else {
171 ss << path_.value();
172 }
173 return ss.str();
174 }
175
IsParent(const FileSystemURL & child) const176 bool FileSystemURL::IsParent(const FileSystemURL& child) const {
177 return IsInSameFileSystem(child) &&
178 path().IsParent(child.path());
179 }
180
IsInSameFileSystem(const FileSystemURL & other) const181 bool FileSystemURL::IsInSameFileSystem(const FileSystemURL& other) const {
182 return origin() == other.origin() &&
183 type() == other.type() &&
184 filesystem_id() == other.filesystem_id();
185 }
186
operator ==(const FileSystemURL & that) const187 bool FileSystemURL::operator==(const FileSystemURL& that) const {
188 return origin_ == that.origin_ &&
189 type_ == that.type_ &&
190 path_ == that.path_ &&
191 filesystem_id_ == that.filesystem_id_ &&
192 is_valid_ == that.is_valid_;
193 }
194
operator ()(const FileSystemURL & lhs,const FileSystemURL & rhs) const195 bool FileSystemURL::Comparator::operator()(const FileSystemURL& lhs,
196 const FileSystemURL& rhs) const {
197 DCHECK(lhs.is_valid_ && rhs.is_valid_);
198 if (lhs.origin_ != rhs.origin_)
199 return lhs.origin_ < rhs.origin_;
200 if (lhs.type_ != rhs.type_)
201 return lhs.type_ < rhs.type_;
202 if (lhs.filesystem_id_ != rhs.filesystem_id_)
203 return lhs.filesystem_id_ < rhs.filesystem_id_;
204 return lhs.path_ < rhs.path_;
205 }
206
207 } // namespace fileapi
208