1 // Copyright 2014 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.
7 #include "base/basictypes.h"
8 #include "base/logging.h"
9 #include "storage/browser/fileapi/file_system_url.h"
10 #include "storage/browser/fileapi/isolated_context.h"
11 #include "testing/gtest/include/gtest/gtest.h"
13 #define FPL(x) FILE_PATH_LITERAL(x)
15 #if defined(FILE_PATH_USES_DRIVE_LETTERS)
16 #define DRIVE FPL("C:")
21 using storage::FileSystemMountOption
;
22 using storage::FileSystemURL
;
23 using storage::IsolatedContext
;
24 using storage::kFileSystemTypeDragged
;
25 using storage::kFileSystemTypeIsolated
;
26 using storage::kFileSystemTypeNativeLocal
;
30 typedef IsolatedContext::MountPointInfo FileInfo
;
34 const base::FilePath kTestPaths
[] = {
35 base::FilePath(DRIVE
FPL("/a/b.txt")),
36 base::FilePath(DRIVE
FPL("/c/d/e")),
37 base::FilePath(DRIVE
FPL("/h/")),
38 base::FilePath(DRIVE
FPL("/")),
39 #if defined(FILE_PATH_USES_WIN_SEPARATORS)
40 base::FilePath(DRIVE
FPL("\\foo\\bar")),
41 base::FilePath(DRIVE
FPL("\\")),
43 // For duplicated base name test.
44 base::FilePath(DRIVE
FPL("/")),
45 base::FilePath(DRIVE
FPL("/f/e")),
46 base::FilePath(DRIVE
FPL("/f/b.txt")),
51 class IsolatedContextTest
: public testing::Test
{
53 IsolatedContextTest() {
54 for (size_t i
= 0; i
< arraysize(kTestPaths
); ++i
)
55 fileset_
.insert(kTestPaths
[i
].NormalizePathSeparators());
58 void SetUp() override
{
59 IsolatedContext::FileInfoSet files
;
60 for (size_t i
= 0; i
< arraysize(kTestPaths
); ++i
) {
63 files
.AddPath(kTestPaths
[i
].NormalizePathSeparators(), &name
));
64 names_
.push_back(name
);
66 id_
= IsolatedContext::GetInstance()->RegisterDraggedFileSystem(files
);
67 IsolatedContext::GetInstance()->AddReference(id_
);
68 ASSERT_FALSE(id_
.empty());
71 void TearDown() override
{
72 IsolatedContext::GetInstance()->RemoveReference(id_
);
75 IsolatedContext
* isolated_context() const {
76 return IsolatedContext::GetInstance();
81 std::multiset
<base::FilePath
> fileset_
;
82 std::vector
<std::string
> names_
;
85 DISALLOW_COPY_AND_ASSIGN(IsolatedContextTest
);
88 TEST_F(IsolatedContextTest
, RegisterAndRevokeTest
) {
89 // See if the returned top-level entries match with what we registered.
90 std::vector
<FileInfo
> toplevels
;
91 ASSERT_TRUE(isolated_context()->GetDraggedFileInfo(id_
, &toplevels
));
92 ASSERT_EQ(fileset_
.size(), toplevels
.size());
93 for (size_t i
= 0; i
< toplevels
.size(); ++i
) {
94 ASSERT_TRUE(fileset_
.find(toplevels
[i
].path
) != fileset_
.end());
97 // See if the name of each registered kTestPaths (that is what we
98 // register in SetUp() by RegisterDraggedFileSystem) is properly cracked as
99 // a valid virtual path in the isolated filesystem.
100 for (size_t i
= 0; i
< arraysize(kTestPaths
); ++i
) {
101 base::FilePath virtual_path
= isolated_context()->CreateVirtualRootPath(id_
)
102 .AppendASCII(names_
[i
]);
103 std::string cracked_id
;
104 base::FilePath cracked_path
;
105 std::string cracked_inner_id
;
106 storage::FileSystemType cracked_type
;
107 FileSystemMountOption cracked_option
;
108 ASSERT_TRUE(isolated_context()->CrackVirtualPath(
109 virtual_path
, &cracked_id
, &cracked_type
, &cracked_inner_id
,
110 &cracked_path
, &cracked_option
));
111 ASSERT_EQ(kTestPaths
[i
].NormalizePathSeparators().value(),
112 cracked_path
.value());
113 ASSERT_EQ(id_
, cracked_id
);
114 ASSERT_EQ(kFileSystemTypeDragged
, cracked_type
);
115 EXPECT_TRUE(cracked_inner_id
.empty());
118 // Make sure GetRegisteredPath returns false for id_ since it is
119 // registered for dragged files.
121 ASSERT_FALSE(isolated_context()->GetRegisteredPath(id_
, &path
));
123 // Deref the current one and registering a new one.
124 isolated_context()->RemoveReference(id_
);
126 std::string id2
= isolated_context()->RegisterFileSystemForPath(
127 kFileSystemTypeNativeLocal
, std::string(),
128 base::FilePath(DRIVE
FPL("/foo")), NULL
);
130 // Make sure the GetDraggedFileInfo returns false for both ones.
131 ASSERT_FALSE(isolated_context()->GetDraggedFileInfo(id2
, &toplevels
));
132 ASSERT_FALSE(isolated_context()->GetDraggedFileInfo(id_
, &toplevels
));
134 // Make sure the GetRegisteredPath returns true only for the new one.
135 ASSERT_FALSE(isolated_context()->GetRegisteredPath(id_
, &path
));
136 ASSERT_TRUE(isolated_context()->GetRegisteredPath(id2
, &path
));
138 // Try registering three more file systems for the same path as id2.
139 std::string id3
= isolated_context()->RegisterFileSystemForPath(
140 kFileSystemTypeNativeLocal
, std::string(), path
, NULL
);
141 std::string id4
= isolated_context()->RegisterFileSystemForPath(
142 kFileSystemTypeNativeLocal
, std::string(), path
, NULL
);
143 std::string id5
= isolated_context()->RegisterFileSystemForPath(
144 kFileSystemTypeNativeLocal
, std::string(), path
, NULL
);
146 // Remove file system for id4.
147 isolated_context()->AddReference(id4
);
148 isolated_context()->RemoveReference(id4
);
150 // Only id4 should become invalid now.
151 ASSERT_TRUE(isolated_context()->GetRegisteredPath(id2
, &path
));
152 ASSERT_TRUE(isolated_context()->GetRegisteredPath(id3
, &path
));
153 ASSERT_FALSE(isolated_context()->GetRegisteredPath(id4
, &path
));
154 ASSERT_TRUE(isolated_context()->GetRegisteredPath(id5
, &path
));
156 // Revoke file system id5, after adding multiple references.
157 isolated_context()->AddReference(id5
);
158 isolated_context()->AddReference(id5
);
159 isolated_context()->AddReference(id5
);
160 isolated_context()->RevokeFileSystem(id5
);
162 // No matter how many references we add id5 must be invalid now.
163 ASSERT_TRUE(isolated_context()->GetRegisteredPath(id2
, &path
));
164 ASSERT_TRUE(isolated_context()->GetRegisteredPath(id3
, &path
));
165 ASSERT_FALSE(isolated_context()->GetRegisteredPath(id4
, &path
));
166 ASSERT_FALSE(isolated_context()->GetRegisteredPath(id5
, &path
));
168 // Revoke the file systems by path.
169 isolated_context()->RevokeFileSystemByPath(path
);
171 // Now all the file systems associated to the path must be invalid.
172 ASSERT_FALSE(isolated_context()->GetRegisteredPath(id2
, &path
));
173 ASSERT_FALSE(isolated_context()->GetRegisteredPath(id3
, &path
));
174 ASSERT_FALSE(isolated_context()->GetRegisteredPath(id4
, &path
));
175 ASSERT_FALSE(isolated_context()->GetRegisteredPath(id5
, &path
));
178 TEST_F(IsolatedContextTest
, CrackWithRelativePaths
) {
180 base::FilePath::StringType path
;
183 { FPL("foo"), true },
184 { FPL("foo/bar"), true },
185 { FPL(".."), false },
186 { FPL("foo/.."), false },
187 { FPL("foo/../bar"), false },
188 #if defined(FILE_PATH_USES_WIN_SEPARATORS)
189 # define SHOULD_FAIL_WITH_WIN_SEPARATORS false
191 # define SHOULD_FAIL_WITH_WIN_SEPARATORS true
193 { FPL("foo\\..\\baz"), SHOULD_FAIL_WITH_WIN_SEPARATORS
},
194 { FPL("foo/..\\baz"), SHOULD_FAIL_WITH_WIN_SEPARATORS
},
197 for (size_t i
= 0; i
< arraysize(kTestPaths
); ++i
) {
198 for (size_t j
= 0; j
< arraysize(relatives
); ++j
) {
199 SCOPED_TRACE(testing::Message() << "Testing "
200 << kTestPaths
[i
].value() << " " << relatives
[j
].path
);
201 base::FilePath virtual_path
=
202 isolated_context()->CreateVirtualRootPath(id_
).AppendASCII(
203 names_
[i
]).Append(relatives
[j
].path
);
204 std::string cracked_id
;
205 base::FilePath cracked_path
;
206 storage::FileSystemType cracked_type
;
207 std::string cracked_inner_id
;
208 FileSystemMountOption cracked_option
;
209 if (!relatives
[j
].valid
) {
210 ASSERT_FALSE(isolated_context()->CrackVirtualPath(
211 virtual_path
, &cracked_id
, &cracked_type
, &cracked_inner_id
,
212 &cracked_path
, &cracked_option
));
215 ASSERT_TRUE(isolated_context()->CrackVirtualPath(
216 virtual_path
, &cracked_id
, &cracked_type
, &cracked_inner_id
,
217 &cracked_path
, &cracked_option
));
218 ASSERT_EQ(kTestPaths
[i
].Append(relatives
[j
].path
)
219 .NormalizePathSeparators().value(),
220 cracked_path
.value());
221 ASSERT_EQ(id_
, cracked_id
);
222 ASSERT_EQ(kFileSystemTypeDragged
, cracked_type
);
223 EXPECT_TRUE(cracked_inner_id
.empty());
228 TEST_F(IsolatedContextTest
, CrackURLWithRelativePaths
) {
230 base::FilePath::StringType path
;
233 { FPL("foo"), true },
234 { FPL("foo/bar"), true },
235 { FPL(".."), false },
236 { FPL("foo/.."), false },
237 { FPL("foo/../bar"), false },
238 #if defined(FILE_PATH_USES_WIN_SEPARATORS)
239 # define SHOULD_FAIL_WITH_WIN_SEPARATORS false
241 # define SHOULD_FAIL_WITH_WIN_SEPARATORS true
243 { FPL("foo\\..\\baz"), SHOULD_FAIL_WITH_WIN_SEPARATORS
},
244 { FPL("foo/..\\baz"), SHOULD_FAIL_WITH_WIN_SEPARATORS
},
247 for (size_t i
= 0; i
< arraysize(kTestPaths
); ++i
) {
248 for (size_t j
= 0; j
< arraysize(relatives
); ++j
) {
249 SCOPED_TRACE(testing::Message() << "Testing "
250 << kTestPaths
[i
].value() << " " << relatives
[j
].path
);
251 base::FilePath virtual_path
=
252 isolated_context()->CreateVirtualRootPath(id_
).AppendASCII(
253 names_
[i
]).Append(relatives
[j
].path
);
255 FileSystemURL cracked
= isolated_context()->CreateCrackedFileSystemURL(
256 GURL("http://chromium.org"), kFileSystemTypeIsolated
, virtual_path
);
258 ASSERT_EQ(relatives
[j
].valid
, cracked
.is_valid());
260 if (!relatives
[j
].valid
)
262 ASSERT_EQ(GURL("http://chromium.org"), cracked
.origin());
263 ASSERT_EQ(kTestPaths
[i
].Append(relatives
[j
].path
)
264 .NormalizePathSeparators().value(),
265 cracked
.path().value());
266 ASSERT_EQ(virtual_path
.NormalizePathSeparators(), cracked
.virtual_path());
267 ASSERT_EQ(id_
, cracked
.filesystem_id());
268 ASSERT_EQ(kFileSystemTypeDragged
, cracked
.type());
269 ASSERT_EQ(kFileSystemTypeIsolated
, cracked
.mount_type());
274 TEST_F(IsolatedContextTest
, TestWithVirtualRoot
) {
275 std::string cracked_id
;
276 base::FilePath cracked_path
;
277 FileSystemMountOption cracked_option
;
279 // Trying to crack virtual root "/" returns true but with empty cracked path
280 // as "/" of the isolated filesystem is a pure virtual directory
281 // that has no corresponding platform directory.
282 base::FilePath virtual_path
= isolated_context()->CreateVirtualRootPath(id_
);
283 ASSERT_TRUE(isolated_context()->CrackVirtualPath(
284 virtual_path
, &cracked_id
, NULL
, NULL
, &cracked_path
, &cracked_option
));
285 ASSERT_EQ(FPL(""), cracked_path
.value());
286 ASSERT_EQ(id_
, cracked_id
);
288 // Trying to crack "/foo" should fail (because "foo" is not the one
289 // included in the kTestPaths).
290 virtual_path
= isolated_context()->CreateVirtualRootPath(
291 id_
).AppendASCII("foo");
292 ASSERT_FALSE(isolated_context()->CrackVirtualPath(
293 virtual_path
, &cracked_id
, NULL
, NULL
, &cracked_path
, &cracked_option
));
296 TEST_F(IsolatedContextTest
, CanHandleURL
) {
297 const GURL
test_origin("http://chromium.org");
298 const base::FilePath
test_path(FPL("/mount"));
300 // Should handle isolated file system.
301 EXPECT_TRUE(isolated_context()->HandlesFileSystemMountType(
302 storage::kFileSystemTypeIsolated
));
304 // Shouldn't handle the rest.
305 EXPECT_FALSE(isolated_context()->HandlesFileSystemMountType(
306 storage::kFileSystemTypeExternal
));
307 EXPECT_FALSE(isolated_context()->HandlesFileSystemMountType(
308 storage::kFileSystemTypeTemporary
));
309 EXPECT_FALSE(isolated_context()->HandlesFileSystemMountType(
310 storage::kFileSystemTypePersistent
));
311 EXPECT_FALSE(isolated_context()->HandlesFileSystemMountType(
312 storage::kFileSystemTypeTest
));
313 // Not even if it's isolated subtype.
314 EXPECT_FALSE(isolated_context()->HandlesFileSystemMountType(
315 storage::kFileSystemTypeNativeLocal
));
316 EXPECT_FALSE(isolated_context()->HandlesFileSystemMountType(
317 storage::kFileSystemTypeDragged
));
318 EXPECT_FALSE(isolated_context()->HandlesFileSystemMountType(
319 storage::kFileSystemTypeNativeMedia
));
320 EXPECT_FALSE(isolated_context()->HandlesFileSystemMountType(
321 storage::kFileSystemTypeDeviceMedia
));
324 TEST_F(IsolatedContextTest
, VirtualFileSystemTests
) {
325 // Should be able to register empty and non-absolute paths
326 std::string empty_fsid
= isolated_context()->RegisterFileSystemForVirtualPath(
327 storage::kFileSystemTypeIsolated
, "_", base::FilePath());
328 std::string relative_fsid
=
329 isolated_context()->RegisterFileSystemForVirtualPath(
330 storage::kFileSystemTypeIsolated
,
332 base::FilePath(FPL("relpath")));
333 ASSERT_FALSE(empty_fsid
.empty());
334 ASSERT_FALSE(relative_fsid
.empty());
336 // Make sure that filesystem root is not prepended to cracked virtual paths.
337 base::FilePath database_root
= base::FilePath(DRIVE
FPL("/database_path"));
338 std::string database_fsid
=
339 isolated_context()->RegisterFileSystemForVirtualPath(
340 storage::kFileSystemTypeIsolated
, "_", database_root
);
342 base::FilePath test_virtual_path
=
343 base::FilePath().AppendASCII("virtualdir").AppendASCII("virtualfile.txt");
345 base::FilePath whole_virtual_path
=
346 isolated_context()->CreateVirtualRootPath(database_fsid
)
347 .AppendASCII("_").Append(test_virtual_path
);
349 std::string cracked_id
;
350 base::FilePath cracked_path
;
351 std::string cracked_inner_id
;
352 FileSystemMountOption cracked_option
;
353 ASSERT_TRUE(isolated_context()->CrackVirtualPath(
354 whole_virtual_path
, &cracked_id
, NULL
, &cracked_inner_id
,
355 &cracked_path
, &cracked_option
));
356 ASSERT_EQ(database_fsid
, cracked_id
);
357 ASSERT_EQ(test_virtual_path
, cracked_path
);
358 EXPECT_TRUE(cracked_inner_id
.empty());
361 } // namespace content