1 // Copyright 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.
5 #include "storage/browser/fileapi/file_system_context.h"
7 #include "base/files/scoped_temp_dir.h"
8 #include "base/strings/stringprintf.h"
9 #include "base/thread_task_runner_handle.h"
10 #include "content/browser/quota/mock_quota_manager.h"
11 #include "content/public/test/mock_special_storage_policy.h"
12 #include "content/public/test/test_file_system_options.h"
13 #include "storage/browser/fileapi/external_mount_points.h"
14 #include "storage/browser/fileapi/file_system_backend.h"
15 #include "storage/browser/fileapi/isolated_context.h"
16 #include "testing/gtest/include/gtest/gtest.h"
18 #define FPL(x) FILE_PATH_LITERAL(x)
20 #if defined(FILE_PATH_USES_DRIVE_LETTERS)
21 #define DRIVE FPL("C:")
26 using storage::ExternalMountPoints
;
27 using storage::FileSystemBackend
;
28 using storage::FileSystemContext
;
29 using storage::FileSystemMountOption
;
30 using storage::FileSystemURL
;
31 using storage::IsolatedContext
;
37 const char kTestOrigin
[] = "http://chromium.org/";
39 GURL
CreateRawFileSystemURL(const std::string
& type_str
,
40 const std::string
& fs_id
) {
41 std::string url_str
= base::StringPrintf(
42 "filesystem:http://chromium.org/%s/%s/root/file",
48 class FileSystemContextTest
: public testing::Test
{
50 FileSystemContextTest() {}
52 void SetUp() override
{
53 ASSERT_TRUE(data_dir_
.CreateUniqueTempDir());
55 storage_policy_
= new MockSpecialStoragePolicy();
57 mock_quota_manager_
= new MockQuotaManager(
58 false /* is_incognito */, data_dir_
.path(),
59 base::ThreadTaskRunnerHandle::Get().get(),
60 base::ThreadTaskRunnerHandle::Get().get(), storage_policy_
.get());
64 FileSystemContext
* CreateFileSystemContextForTest(
65 storage::ExternalMountPoints
* external_mount_points
) {
66 return new FileSystemContext(
67 base::ThreadTaskRunnerHandle::Get().get(),
68 base::ThreadTaskRunnerHandle::Get().get(), external_mount_points
,
69 storage_policy_
.get(), mock_quota_manager_
->proxy(),
70 ScopedVector
<FileSystemBackend
>(),
71 std::vector
<storage::URLRequestAutoMountHandler
>(), data_dir_
.path(),
72 CreateAllowFileAccessOptions());
75 // Verifies a *valid* filesystem url has expected values.
76 void ExpectFileSystemURLMatches(const FileSystemURL
& url
,
77 const GURL
& expect_origin
,
78 storage::FileSystemType expect_mount_type
,
79 storage::FileSystemType expect_type
,
80 const base::FilePath
& expect_path
,
81 const base::FilePath
& expect_virtual_path
,
82 const std::string
& expect_filesystem_id
) {
83 EXPECT_TRUE(url
.is_valid());
85 EXPECT_EQ(expect_origin
, url
.origin());
86 EXPECT_EQ(expect_mount_type
, url
.mount_type());
87 EXPECT_EQ(expect_type
, url
.type());
88 EXPECT_EQ(expect_path
, url
.path());
89 EXPECT_EQ(expect_virtual_path
, url
.virtual_path());
90 EXPECT_EQ(expect_filesystem_id
, url
.filesystem_id());
94 base::ScopedTempDir data_dir_
;
95 base::MessageLoop message_loop_
;
96 scoped_refptr
<storage::SpecialStoragePolicy
> storage_policy_
;
97 scoped_refptr
<MockQuotaManager
> mock_quota_manager_
;
100 // It is not valid to pass NULL ExternalMountPoints to FileSystemContext on
102 #if !defined(OS_CHROMEOS)
103 TEST_F(FileSystemContextTest
, NullExternalMountPoints
) {
104 scoped_refptr
<FileSystemContext
> file_system_context(
105 CreateFileSystemContextForTest(NULL
));
107 // Cracking system external mount and isolated mount points should work.
108 std::string isolated_name
= "root";
109 std::string isolated_id
=
110 IsolatedContext::GetInstance()->RegisterFileSystemForPath(
111 storage::kFileSystemTypeNativeLocal
,
113 base::FilePath(DRIVE
FPL("/test/isolated/root")),
115 // Register system external mount point.
116 ASSERT_TRUE(ExternalMountPoints::GetSystemInstance()->RegisterFileSystem(
118 storage::kFileSystemTypeNativeLocal
,
119 FileSystemMountOption(),
120 base::FilePath(DRIVE
FPL("/test/sys/"))));
122 FileSystemURL cracked_isolated
= file_system_context
->CrackURL(
123 CreateRawFileSystemURL("isolated", isolated_id
));
125 ExpectFileSystemURLMatches(
128 storage::kFileSystemTypeIsolated
,
129 storage::kFileSystemTypeNativeLocal
,
130 base::FilePath(DRIVE
FPL("/test/isolated/root/file"))
131 .NormalizePathSeparators(),
132 base::FilePath::FromUTF8Unsafe(isolated_id
)
133 .Append(FPL("root/file"))
134 .NormalizePathSeparators(),
137 FileSystemURL cracked_external
= file_system_context
->CrackURL(
138 CreateRawFileSystemURL("external", "system"));
140 ExpectFileSystemURLMatches(
143 storage::kFileSystemTypeExternal
,
144 storage::kFileSystemTypeNativeLocal
,
145 base::FilePath(DRIVE
FPL("/test/sys/root/file"))
146 .NormalizePathSeparators(),
147 base::FilePath(FPL("system/root/file")).NormalizePathSeparators(),
150 IsolatedContext::GetInstance()->RevokeFileSystem(isolated_id
);
151 ExternalMountPoints::GetSystemInstance()->RevokeFileSystem("system");
153 #endif // !defiend(OS_CHROMEOS)
155 TEST_F(FileSystemContextTest
, FileSystemContextKeepsMountPointsAlive
) {
156 scoped_refptr
<ExternalMountPoints
> mount_points
=
157 ExternalMountPoints::CreateRefCounted();
159 // Register system external mount point.
160 ASSERT_TRUE(mount_points
->RegisterFileSystem(
162 storage::kFileSystemTypeNativeLocal
,
163 FileSystemMountOption(),
164 base::FilePath(DRIVE
FPL("/test/sys/"))));
166 scoped_refptr
<FileSystemContext
> file_system_context(
167 CreateFileSystemContextForTest(mount_points
.get()));
169 // Release a MountPoints reference created in the test.
172 // FileSystemContext should keep a reference to the |mount_points|, so it
173 // should be able to resolve the URL.
174 FileSystemURL cracked_external
= file_system_context
->CrackURL(
175 CreateRawFileSystemURL("external", "system"));
177 ExpectFileSystemURLMatches(
180 storage::kFileSystemTypeExternal
,
181 storage::kFileSystemTypeNativeLocal
,
182 base::FilePath(DRIVE
FPL("/test/sys/root/file"))
183 .NormalizePathSeparators(),
184 base::FilePath(FPL("system/root/file")).NormalizePathSeparators(),
187 // No need to revoke the registered filesystem since |mount_points| lifetime
188 // is bound to this test.
191 TEST_F(FileSystemContextTest
, CrackFileSystemURL
) {
192 scoped_refptr
<ExternalMountPoints
> external_mount_points(
193 ExternalMountPoints::CreateRefCounted());
194 scoped_refptr
<FileSystemContext
> file_system_context(
195 CreateFileSystemContextForTest(external_mount_points
.get()));
197 // Register an isolated mount point.
198 std::string isolated_file_system_name
= "root";
199 const std::string kIsolatedFileSystemID
=
200 IsolatedContext::GetInstance()->RegisterFileSystemForPath(
201 storage::kFileSystemTypeNativeLocal
,
203 base::FilePath(DRIVE
FPL("/test/isolated/root")),
204 &isolated_file_system_name
);
205 // Register system external mount point.
206 ASSERT_TRUE(ExternalMountPoints::GetSystemInstance()->RegisterFileSystem(
208 storage::kFileSystemTypeDrive
,
209 FileSystemMountOption(),
210 base::FilePath(DRIVE
FPL("/test/sys/"))));
211 ASSERT_TRUE(ExternalMountPoints::GetSystemInstance()->RegisterFileSystem(
213 storage::kFileSystemTypeNativeLocal
,
214 FileSystemMountOption(),
215 base::FilePath(DRIVE
FPL("/test/ext"))));
216 // Register a system external mount point with the same name/id as the
217 // registered isolated mount point.
218 ASSERT_TRUE(ExternalMountPoints::GetSystemInstance()->RegisterFileSystem(
219 kIsolatedFileSystemID
,
220 storage::kFileSystemTypeRestrictedNativeLocal
,
221 FileSystemMountOption(),
222 base::FilePath(DRIVE
FPL("/test/system/isolated"))));
223 // Add a mount points with the same name as a system mount point to
224 // FileSystemContext's external mount points.
225 ASSERT_TRUE(external_mount_points
->RegisterFileSystem(
227 storage::kFileSystemTypeNativeLocal
,
228 FileSystemMountOption(),
229 base::FilePath(DRIVE
FPL("/test/local/ext/"))));
231 const GURL kTestOrigin
= GURL("http://chromium.org/");
232 const base::FilePath kVirtualPathNoRoot
= base::FilePath(FPL("root/file"));
237 std::string type_str
;
239 // Expected test results.
240 bool expect_is_valid
;
241 storage::FileSystemType expect_mount_type
;
242 storage::FileSystemType expect_type
;
243 const base::FilePath::CharType
* expect_path
;
244 std::string expect_filesystem_id
;
247 const TestCase kTestCases
[] = {
248 // Following should not be handled by the url crackers:
250 "pers_mount", "persistent", true /* is_valid */,
251 storage::kFileSystemTypePersistent
, storage::kFileSystemTypePersistent
,
252 FPL("pers_mount/root/file"), std::string() /* filesystem id */
255 "temp_mount", "temporary", true /* is_valid */,
256 storage::kFileSystemTypeTemporary
, storage::kFileSystemTypeTemporary
,
257 FPL("temp_mount/root/file"), std::string() /* filesystem id */
259 // Should be cracked by isolated mount points:
260 {kIsolatedFileSystemID
, "isolated", true /* is_valid */,
261 storage::kFileSystemTypeIsolated
, storage::kFileSystemTypeNativeLocal
,
262 DRIVE
FPL("/test/isolated/root/file"), kIsolatedFileSystemID
},
263 // Should be cracked by system mount points:
264 {"system", "external", true /* is_valid */,
265 storage::kFileSystemTypeExternal
, storage::kFileSystemTypeDrive
,
266 DRIVE
FPL("/test/sys/root/file"), "system"},
267 {kIsolatedFileSystemID
, "external", true /* is_valid */,
268 storage::kFileSystemTypeExternal
,
269 storage::kFileSystemTypeRestrictedNativeLocal
,
270 DRIVE
FPL("/test/system/isolated/root/file"), kIsolatedFileSystemID
},
271 // Should be cracked by FileSystemContext's ExternalMountPoints.
272 {"ext", "external", true /* is_valid */, storage::kFileSystemTypeExternal
,
273 storage::kFileSystemTypeNativeLocal
,
274 DRIVE
FPL("/test/local/ext/root/file"), "ext"},
275 // Test for invalid filesystem url (made invalid by adding invalid
277 {"sytem", "external", false /* is_valid */,
278 // The rest of values will be ignored.
279 storage::kFileSystemTypeUnknown
, storage::kFileSystemTypeUnknown
,
280 FPL(""), std::string()},
281 // Test for URL with non-existing filesystem id.
282 {"invalid", "external", false /* is_valid */,
283 // The rest of values will be ignored.
284 storage::kFileSystemTypeUnknown
, storage::kFileSystemTypeUnknown
,
285 FPL(""), std::string()},
288 for (size_t i
= 0; i
< arraysize(kTestCases
); ++i
) {
289 const base::FilePath virtual_path
=
290 base::FilePath::FromUTF8Unsafe(
291 kTestCases
[i
].root
).Append(kVirtualPathNoRoot
);
294 CreateRawFileSystemURL(kTestCases
[i
].type_str
, kTestCases
[i
].root
);
295 FileSystemURL cracked_url
= file_system_context
->CrackURL(raw_url
);
297 SCOPED_TRACE(testing::Message() << "Test case " << i
<< ": "
298 << "Cracking URL: " << raw_url
);
300 EXPECT_EQ(kTestCases
[i
].expect_is_valid
, cracked_url
.is_valid());
301 if (!kTestCases
[i
].expect_is_valid
)
304 ExpectFileSystemURLMatches(
307 kTestCases
[i
].expect_mount_type
,
308 kTestCases
[i
].expect_type
,
309 base::FilePath(kTestCases
[i
].expect_path
).NormalizePathSeparators(),
310 virtual_path
.NormalizePathSeparators(),
311 kTestCases
[i
].expect_filesystem_id
);
314 IsolatedContext::GetInstance()->RevokeFileSystemByPath(
315 base::FilePath(DRIVE
FPL("/test/isolated/root")));
316 ExternalMountPoints::GetSystemInstance()->RevokeFileSystem("system");
317 ExternalMountPoints::GetSystemInstance()->RevokeFileSystem("ext");
318 ExternalMountPoints::GetSystemInstance()->RevokeFileSystem(
319 kIsolatedFileSystemID
);
322 TEST_F(FileSystemContextTest
, CanServeURLRequest
) {
323 scoped_refptr
<ExternalMountPoints
> external_mount_points(
324 ExternalMountPoints::CreateRefCounted());
325 scoped_refptr
<FileSystemContext
> context(
326 CreateFileSystemContextForTest(external_mount_points
.get()));
328 // A request for a sandbox mount point should be served.
329 FileSystemURL cracked_url
=
330 context
->CrackURL(CreateRawFileSystemURL("persistent", "pers_mount"));
331 EXPECT_EQ(storage::kFileSystemTypePersistent
, cracked_url
.mount_type());
332 EXPECT_TRUE(context
->CanServeURLRequest(cracked_url
));
334 // A request for an isolated mount point should NOT be served.
335 std::string isolated_fs_name
= "root";
336 std::string isolated_fs_id
=
337 IsolatedContext::GetInstance()->RegisterFileSystemForPath(
338 storage::kFileSystemTypeNativeLocal
,
340 base::FilePath(DRIVE
FPL("/test/isolated/root")),
342 cracked_url
= context
->CrackURL(
343 CreateRawFileSystemURL("isolated", isolated_fs_id
));
344 EXPECT_EQ(storage::kFileSystemTypeIsolated
, cracked_url
.mount_type());
345 EXPECT_FALSE(context
->CanServeURLRequest(cracked_url
));
347 // A request for an external mount point should be served.
348 const std::string kExternalMountName
= "ext_mount";
349 ASSERT_TRUE(ExternalMountPoints::GetSystemInstance()->RegisterFileSystem(
351 storage::kFileSystemTypeDrive
,
352 FileSystemMountOption(),
354 cracked_url
= context
->CrackURL(
355 CreateRawFileSystemURL("external", kExternalMountName
));
356 EXPECT_EQ(storage::kFileSystemTypeExternal
, cracked_url
.mount_type());
357 EXPECT_TRUE(context
->CanServeURLRequest(cracked_url
));
359 ExternalMountPoints::GetSystemInstance()->RevokeFileSystem(
361 IsolatedContext::GetInstance()->RevokeFileSystem(isolated_fs_id
);
364 // Ensures that a backend exists for each common isolated file system type.
365 // See http://crbug.com/447027
366 TEST_F(FileSystemContextTest
, IsolatedFileSystemsTypesHandled
) {
367 // This does not provide any "additional" file system handlers. In particular,
368 // on Chrome OS it does not provide chromeos::FileSystemBackend.
369 scoped_refptr
<FileSystemContext
> file_system_context(
370 CreateFileSystemContextForTest(nullptr));
372 // Isolated file system types are handled.
373 EXPECT_TRUE(file_system_context
->GetFileSystemBackend(
374 storage::kFileSystemTypeIsolated
));
375 EXPECT_TRUE(file_system_context
->GetFileSystemBackend(
376 storage::kFileSystemTypeDragged
));
377 EXPECT_TRUE(file_system_context
->GetFileSystemBackend(
378 storage::kFileSystemTypeForTransientFile
));
379 EXPECT_TRUE(file_system_context
->GetFileSystemBackend(
380 storage::kFileSystemTypeNativeLocal
));
381 EXPECT_TRUE(file_system_context
->GetFileSystemBackend(
382 storage::kFileSystemTypeNativeForPlatformApp
));
387 } // namespace content