1 // Copyright 2019 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 "content/browser/native_file_system/native_file_system_manager_impl.h"
6
7 #include <string>
8 #include <utility>
9 #include <vector>
10
11 #include "base/bind_helpers.h"
12 #include "base/files/file_util.h"
13 #include "base/files/scoped_temp_dir.h"
14 #include "base/run_loop.h"
15 #include "base/test/bind_test_util.h"
16 #include "base/test/gmock_callback_support.h"
17 #include "base/test/scoped_feature_list.h"
18 #include "base/test/task_environment.h"
19 #include "content/browser/native_file_system/fixed_native_file_system_permission_grant.h"
20 #include "content/browser/native_file_system/mock_native_file_system_permission_context.h"
21 #include "content/browser/native_file_system/native_file_system_directory_handle_impl.h"
22 #include "content/browser/native_file_system/native_file_system_file_handle_impl.h"
23 #include "content/browser/native_file_system/native_file_system_transfer_token_impl.h"
24 #include "content/public/test/browser_task_environment.h"
25 #include "mojo/public/cpp/bindings/pending_remote.h"
26 #include "mojo/public/cpp/bindings/remote.h"
27 #include "storage/browser/blob/blob_storage_context.h"
28 #include "storage/browser/test/async_file_test_helper.h"
29 #include "storage/browser/test/test_file_system_context.h"
30 #include "testing/gtest/include/gtest/gtest.h"
31 #include "third_party/blink/public/common/features.h"
32
33 namespace content {
34
35 using base::test::RunOnceCallback;
36 using blink::mojom::PermissionStatus;
37
38 class NativeFileSystemManagerImplTest : public testing::Test {
39 public:
NativeFileSystemManagerImplTest()40 NativeFileSystemManagerImplTest()
41 : task_environment_(base::test::TaskEnvironment::MainThreadType::IO) {
42 scoped_feature_list_.InitAndEnableFeature(
43 blink::features::kNativeFileSystemAPI);
44 }
45
SetUp()46 void SetUp() override {
47 ASSERT_TRUE(dir_.CreateUniqueTempDir());
48 ASSERT_TRUE(dir_.GetPath().IsAbsolute());
49 file_system_context_ = storage::CreateFileSystemContextForTesting(
50 /*quota_manager_proxy=*/nullptr, dir_.GetPath());
51
52 chrome_blob_context_ = base::MakeRefCounted<ChromeBlobStorageContext>();
53 chrome_blob_context_->InitializeOnIOThread(base::FilePath(),
54 base::FilePath(), nullptr);
55
56 manager_ = base::MakeRefCounted<NativeFileSystemManagerImpl>(
57 file_system_context_, chrome_blob_context_, &permission_context_,
58 /*off_the_record=*/false);
59
60 manager_->BindReceiver(kBindingContext,
61 manager_remote_.BindNewPipeAndPassReceiver());
62 }
63
64 template <typename HandleType>
GetPermissionStatusSync(bool writable,HandleType * handle)65 PermissionStatus GetPermissionStatusSync(bool writable, HandleType* handle) {
66 PermissionStatus result;
67 base::RunLoop loop;
68 handle->GetPermissionStatus(
69 writable, base::BindLambdaForTesting([&](PermissionStatus status) {
70 result = status;
71 loop.Quit();
72 }));
73 loop.Run();
74 return result;
75 }
76
77 mojo::Remote<blink::mojom::NativeFileSystemDirectoryHandle>
GetHandleForDirectory(const base::FilePath & path)78 GetHandleForDirectory(const base::FilePath& path) {
79 EXPECT_CALL(
80 permission_context_,
81 GetReadPermissionGrant(
82 kTestOrigin, path, /*is_directory=*/true, kProcessId, kFrameId,
83 NativeFileSystemPermissionContext::UserAction::kOpen))
84 .WillOnce(testing::Return(allow_grant_));
85 EXPECT_CALL(
86 permission_context_,
87 GetWritePermissionGrant(
88 kTestOrigin, path, /*is_directory=*/true, kProcessId, kFrameId,
89 NativeFileSystemPermissionContext::UserAction::kOpen))
90 .WillOnce(testing::Return(allow_grant_));
91
92 blink::mojom::NativeFileSystemEntryPtr entry =
93 manager_->CreateDirectoryEntryFromPath(kBindingContext, path);
94 return mojo::Remote<blink::mojom::NativeFileSystemDirectoryHandle>(
95 std::move(entry->entry_handle->get_directory()));
96 }
97
SerializeAndDeserializeToken(mojo::PendingRemote<blink::mojom::NativeFileSystemTransferToken> token_remote)98 NativeFileSystemTransferTokenImpl* SerializeAndDeserializeToken(
99 mojo::PendingRemote<blink::mojom::NativeFileSystemTransferToken>
100 token_remote) {
101 std::vector<uint8_t> serialized;
102 base::RunLoop serialize_loop;
103 manager_->SerializeHandle(
104 std::move(token_remote),
105 base::BindLambdaForTesting([&](const std::vector<uint8_t>& bits) {
106 EXPECT_FALSE(bits.empty());
107 serialized = bits;
108 serialize_loop.Quit();
109 }));
110 serialize_loop.Run();
111
112 manager_->DeserializeHandle(kTestOrigin, serialized,
113 token_remote.InitWithNewPipeAndPassReceiver());
114 base::RunLoop resolve_loop;
115 NativeFileSystemTransferTokenImpl* result;
116 manager_->ResolveTransferToken(
117 std::move(token_remote),
118 base::BindLambdaForTesting(
119 [&](NativeFileSystemTransferTokenImpl* token) {
120 result = token;
121 resolve_loop.Quit();
122 }));
123 resolve_loop.Run();
124 return result;
125 }
126
127 protected:
128 const GURL kTestURL = GURL("https://example.com/test");
129 const url::Origin kTestOrigin = url::Origin::Create(kTestURL);
130 const int kProcessId = 1;
131 const int kFrameId = 2;
132 const NativeFileSystemManagerImpl::BindingContext kBindingContext = {
133 kTestOrigin, kTestURL, kProcessId, kFrameId};
134
135 base::test::ScopedFeatureList scoped_feature_list_;
136 BrowserTaskEnvironment task_environment_;
137
138 base::ScopedTempDir dir_;
139 scoped_refptr<storage::FileSystemContext> file_system_context_;
140 scoped_refptr<ChromeBlobStorageContext> chrome_blob_context_;
141
142 testing::StrictMock<MockNativeFileSystemPermissionContext>
143 permission_context_;
144 scoped_refptr<NativeFileSystemManagerImpl> manager_;
145 mojo::Remote<blink::mojom::NativeFileSystemManager> manager_remote_;
146
147 scoped_refptr<FixedNativeFileSystemPermissionGrant> ask_grant_ =
148 base::MakeRefCounted<FixedNativeFileSystemPermissionGrant>(
149 FixedNativeFileSystemPermissionGrant::PermissionStatus::ASK);
150 scoped_refptr<FixedNativeFileSystemPermissionGrant> ask_grant2_ =
151 base::MakeRefCounted<FixedNativeFileSystemPermissionGrant>(
152 FixedNativeFileSystemPermissionGrant::PermissionStatus::ASK);
153 scoped_refptr<FixedNativeFileSystemPermissionGrant> allow_grant_ =
154 base::MakeRefCounted<FixedNativeFileSystemPermissionGrant>(
155 FixedNativeFileSystemPermissionGrant::PermissionStatus::GRANTED);
156 };
157
TEST_F(NativeFileSystemManagerImplTest,GetSandboxedFileSystem_Permissions)158 TEST_F(NativeFileSystemManagerImplTest, GetSandboxedFileSystem_Permissions) {
159 mojo::PendingRemote<blink::mojom::NativeFileSystemDirectoryHandle>
160 directory_remote;
161 base::RunLoop loop;
162 manager_remote_->GetSandboxedFileSystem(base::BindLambdaForTesting(
163 [&](blink::mojom::NativeFileSystemErrorPtr result,
164 mojo::PendingRemote<blink::mojom::NativeFileSystemDirectoryHandle>
165 handle) {
166 EXPECT_EQ(blink::mojom::NativeFileSystemStatus::kOk, result->status);
167 directory_remote = std::move(handle);
168 loop.Quit();
169 }));
170 loop.Run();
171 mojo::Remote<blink::mojom::NativeFileSystemDirectoryHandle> root(
172 std::move(directory_remote));
173 ASSERT_TRUE(root);
174 EXPECT_EQ(PermissionStatus::GRANTED,
175 GetPermissionStatusSync(/*writable=*/false, root.get()));
176 EXPECT_EQ(PermissionStatus::GRANTED,
177 GetPermissionStatusSync(/*writable=*/true, root.get()));
178 }
179
TEST_F(NativeFileSystemManagerImplTest,CreateFileEntryFromPath_Permissions)180 TEST_F(NativeFileSystemManagerImplTest, CreateFileEntryFromPath_Permissions) {
181 const base::FilePath kTestPath(dir_.GetPath().AppendASCII("foo"));
182
183 EXPECT_CALL(
184 permission_context_,
185 GetReadPermissionGrant(
186 kTestOrigin, kTestPath, /*is_directory=*/false, kProcessId, kFrameId,
187 NativeFileSystemPermissionContext::UserAction::kOpen))
188 .WillOnce(testing::Return(allow_grant_));
189 EXPECT_CALL(
190 permission_context_,
191 GetWritePermissionGrant(
192 kTestOrigin, kTestPath, /*is_directory=*/false, kProcessId, kFrameId,
193 NativeFileSystemPermissionContext::UserAction::kOpen))
194 .WillOnce(testing::Return(ask_grant_));
195
196 blink::mojom::NativeFileSystemEntryPtr entry =
197 manager_->CreateFileEntryFromPath(kBindingContext, kTestPath);
198 mojo::Remote<blink::mojom::NativeFileSystemFileHandle> handle(
199 std::move(entry->entry_handle->get_file()));
200
201 EXPECT_EQ(PermissionStatus::GRANTED,
202 GetPermissionStatusSync(/*writable=*/false, handle.get()));
203 EXPECT_EQ(PermissionStatus::ASK,
204 GetPermissionStatusSync(/*writable=*/true, handle.get()));
205 }
206
TEST_F(NativeFileSystemManagerImplTest,CreateWritableFileEntryFromPath_Permissions)207 TEST_F(NativeFileSystemManagerImplTest,
208 CreateWritableFileEntryFromPath_Permissions) {
209 const base::FilePath kTestPath(dir_.GetPath().AppendASCII("foo"));
210
211 EXPECT_CALL(
212 permission_context_,
213 GetReadPermissionGrant(
214 kTestOrigin, kTestPath, /*is_directory=*/false, kProcessId, kFrameId,
215 NativeFileSystemPermissionContext::UserAction::kSave))
216 .WillOnce(testing::Return(allow_grant_));
217 EXPECT_CALL(
218 permission_context_,
219 GetWritePermissionGrant(
220 kTestOrigin, kTestPath, /*is_directory=*/false, kProcessId, kFrameId,
221 NativeFileSystemPermissionContext::UserAction::kSave))
222 .WillOnce(testing::Return(allow_grant_));
223
224 blink::mojom::NativeFileSystemEntryPtr entry =
225 manager_->CreateWritableFileEntryFromPath(kBindingContext, kTestPath);
226 mojo::Remote<blink::mojom::NativeFileSystemFileHandle> handle(
227 std::move(entry->entry_handle->get_file()));
228
229 EXPECT_EQ(PermissionStatus::GRANTED,
230 GetPermissionStatusSync(/*writable=*/false, handle.get()));
231 EXPECT_EQ(PermissionStatus::GRANTED,
232 GetPermissionStatusSync(/*writable=*/true, handle.get()));
233 }
234
TEST_F(NativeFileSystemManagerImplTest,CreateDirectoryEntryFromPath_Permissions)235 TEST_F(NativeFileSystemManagerImplTest,
236 CreateDirectoryEntryFromPath_Permissions) {
237 const base::FilePath kTestPath(dir_.GetPath().AppendASCII("foo"));
238
239 EXPECT_CALL(
240 permission_context_,
241 GetReadPermissionGrant(
242 kTestOrigin, kTestPath, /*is_directory=*/true, kProcessId, kFrameId,
243 NativeFileSystemPermissionContext::UserAction::kOpen))
244 .WillOnce(testing::Return(allow_grant_));
245 EXPECT_CALL(
246 permission_context_,
247 GetWritePermissionGrant(
248 kTestOrigin, kTestPath, /*is_directory=*/true, kProcessId, kFrameId,
249 NativeFileSystemPermissionContext::UserAction::kOpen))
250 .WillOnce(testing::Return(ask_grant_));
251
252 blink::mojom::NativeFileSystemEntryPtr entry =
253 manager_->CreateDirectoryEntryFromPath(kBindingContext, kTestPath);
254 mojo::Remote<blink::mojom::NativeFileSystemDirectoryHandle> handle(
255 std::move(entry->entry_handle->get_directory()));
256 EXPECT_EQ(PermissionStatus::GRANTED,
257 GetPermissionStatusSync(/*writable=*/false, handle.get()));
258 EXPECT_EQ(PermissionStatus::ASK,
259 GetPermissionStatusSync(/*writable=*/true, handle.get()));
260 }
261
TEST_F(NativeFileSystemManagerImplTest,FileWriterSwapDeletedOnConnectionClose)262 TEST_F(NativeFileSystemManagerImplTest,
263 FileWriterSwapDeletedOnConnectionClose) {
264 auto test_file_url = file_system_context_->CreateCrackedFileSystemURL(
265 kTestOrigin, storage::kFileSystemTypeTest,
266 base::FilePath::FromUTF8Unsafe("test"));
267
268 auto test_swap_url = file_system_context_->CreateCrackedFileSystemURL(
269 kTestOrigin, storage::kFileSystemTypeTest,
270 base::FilePath::FromUTF8Unsafe("test.crswap"));
271
272 ASSERT_EQ(base::File::FILE_OK,
273 storage::AsyncFileTestHelper::CreateFile(file_system_context_.get(),
274 test_file_url));
275
276 ASSERT_EQ(base::File::FILE_OK,
277 storage::AsyncFileTestHelper::CreateFile(file_system_context_.get(),
278 test_swap_url));
279
280 mojo::Remote<blink::mojom::NativeFileSystemFileWriter> writer_remote(
281 manager_->CreateFileWriter(kBindingContext, test_file_url, test_swap_url,
282 NativeFileSystemManagerImpl::SharedHandleState(
283 allow_grant_, allow_grant_, {})));
284
285 ASSERT_TRUE(writer_remote.is_bound());
286 ASSERT_TRUE(storage::AsyncFileTestHelper::FileExists(
287 file_system_context_.get(), test_swap_url,
288 storage::AsyncFileTestHelper::kDontCheckSize));
289
290 // Severs the mojo pipe, causing the writer to be destroyed.
291 writer_remote.reset();
292 base::RunLoop().RunUntilIdle();
293
294 ASSERT_FALSE(storage::AsyncFileTestHelper::FileExists(
295 file_system_context_.get(), test_swap_url,
296 storage::AsyncFileTestHelper::kDontCheckSize));
297 }
298
TEST_F(NativeFileSystemManagerImplTest,FileWriterCloseAllowedToCompleteOnDestruct)299 TEST_F(NativeFileSystemManagerImplTest,
300 FileWriterCloseAllowedToCompleteOnDestruct) {
301 auto test_file_url = file_system_context_->CreateCrackedFileSystemURL(
302 kTestOrigin, storage::kFileSystemTypeTest,
303 base::FilePath::FromUTF8Unsafe("test"));
304
305 auto test_swap_url = file_system_context_->CreateCrackedFileSystemURL(
306 kTestOrigin, storage::kFileSystemTypeTest,
307 base::FilePath::FromUTF8Unsafe("test.crswap"));
308
309 ASSERT_EQ(base::File::FILE_OK,
310 storage::AsyncFileTestHelper::CreateFileWithData(
311 file_system_context_.get(), test_swap_url, "foo", 3));
312
313 mojo::Remote<blink::mojom::NativeFileSystemFileWriter> writer_remote(
314 manager_->CreateFileWriter(kBindingContext, test_file_url, test_swap_url,
315 NativeFileSystemManagerImpl::SharedHandleState(
316 allow_grant_, allow_grant_, {})));
317
318 ASSERT_TRUE(writer_remote.is_bound());
319 ASSERT_FALSE(storage::AsyncFileTestHelper::FileExists(
320 file_system_context_.get(), test_file_url,
321 storage::AsyncFileTestHelper::kDontCheckSize));
322 writer_remote->Close(base::DoNothing());
323
324 // Severs the mojo pipe, causing the writer to be destroyed.
325 writer_remote.reset();
326 base::RunLoop().RunUntilIdle();
327
328 ASSERT_FALSE(storage::AsyncFileTestHelper::FileExists(
329 file_system_context_.get(), test_swap_url,
330 storage::AsyncFileTestHelper::kDontCheckSize));
331 ASSERT_TRUE(storage::AsyncFileTestHelper::FileExists(
332 file_system_context_.get(), test_file_url, 3));
333 }
334
TEST_F(NativeFileSystemManagerImplTest,SerializeHandle_SandboxedFile)335 TEST_F(NativeFileSystemManagerImplTest, SerializeHandle_SandboxedFile) {
336 auto test_file_url = file_system_context_->CreateCrackedFileSystemURL(
337 kTestOrigin, storage::kFileSystemTypeTemporary,
338 base::FilePath::FromUTF8Unsafe("test/foo/bar"));
339 NativeFileSystemFileHandleImpl file(manager_.get(), kBindingContext,
340 test_file_url,
341 {ask_grant_, ask_grant_, {}});
342 mojo::PendingRemote<blink::mojom::NativeFileSystemTransferToken> token_remote;
343 manager_->CreateTransferToken(file,
344 token_remote.InitWithNewPipeAndPassReceiver());
345
346 NativeFileSystemTransferTokenImpl* token =
347 SerializeAndDeserializeToken(std::move(token_remote));
348 ASSERT_TRUE(token);
349 EXPECT_EQ(test_file_url, token->url());
350 EXPECT_EQ(NativeFileSystemTransferTokenImpl::HandleType::kFile,
351 token->type());
352
353 // Deserialized sandboxed filesystem handles should always be readable and
354 // writable.
355 EXPECT_EQ(PermissionStatus::GRANTED,
356 token->shared_handle_state().read_grant->GetStatus());
357 EXPECT_EQ(PermissionStatus::GRANTED,
358 token->shared_handle_state().write_grant->GetStatus());
359 }
360
TEST_F(NativeFileSystemManagerImplTest,SerializeHandle_SandboxedDirectory)361 TEST_F(NativeFileSystemManagerImplTest, SerializeHandle_SandboxedDirectory) {
362 auto test_file_url = file_system_context_->CreateCrackedFileSystemURL(
363 kTestOrigin, storage::kFileSystemTypeTemporary,
364 base::FilePath::FromUTF8Unsafe("hello/world/"));
365 NativeFileSystemDirectoryHandleImpl directory(manager_.get(), kBindingContext,
366 test_file_url,
367 {ask_grant_, ask_grant_, {}});
368 mojo::PendingRemote<blink::mojom::NativeFileSystemTransferToken> token_remote;
369 manager_->CreateTransferToken(directory,
370 token_remote.InitWithNewPipeAndPassReceiver());
371
372 NativeFileSystemTransferTokenImpl* token =
373 SerializeAndDeserializeToken(std::move(token_remote));
374 ASSERT_TRUE(token);
375 EXPECT_EQ(test_file_url, token->url());
376 EXPECT_EQ(NativeFileSystemTransferTokenImpl::HandleType::kDirectory,
377 token->type());
378
379 // Deserialized sandboxed filesystem handles should always be readable and
380 // writable.
381 EXPECT_EQ(PermissionStatus::GRANTED,
382 token->shared_handle_state().read_grant->GetStatus());
383 EXPECT_EQ(PermissionStatus::GRANTED,
384 token->shared_handle_state().write_grant->GetStatus());
385 }
386
TEST_F(NativeFileSystemManagerImplTest,SerializeHandle_Native_SingleFile)387 TEST_F(NativeFileSystemManagerImplTest, SerializeHandle_Native_SingleFile) {
388 const base::FilePath kTestPath(dir_.GetPath().AppendASCII("foo"));
389
390 // Expect calls to get grants when creating the initial handle.
391 EXPECT_CALL(
392 permission_context_,
393 GetReadPermissionGrant(
394 kTestOrigin, kTestPath, /*is_directory=*/false, kProcessId, kFrameId,
395 NativeFileSystemPermissionContext::UserAction::kOpen))
396 .WillOnce(testing::Return(allow_grant_));
397 EXPECT_CALL(
398 permission_context_,
399 GetWritePermissionGrant(
400 kTestOrigin, kTestPath, /*is_directory=*/false, kProcessId, kFrameId,
401 NativeFileSystemPermissionContext::UserAction::kOpen))
402 .WillOnce(testing::Return(allow_grant_));
403
404 blink::mojom::NativeFileSystemEntryPtr entry =
405 manager_->CreateFileEntryFromPath(kBindingContext, kTestPath);
406 mojo::Remote<blink::mojom::NativeFileSystemFileHandle> handle(
407 std::move(entry->entry_handle->get_file()));
408
409 mojo::PendingRemote<blink::mojom::NativeFileSystemTransferToken> token_remote;
410 handle->Transfer(token_remote.InitWithNewPipeAndPassReceiver());
411
412 // Deserializing tokens should re-request grants, with correct user action.
413 EXPECT_CALL(
414 permission_context_,
415 GetReadPermissionGrant(
416 kTestOrigin, kTestPath, /*is_directory=*/false,
417 /*process_id=*/ChildProcessHost::kInvalidUniqueID,
418 /*frame_id=*/MSG_ROUTING_NONE,
419 NativeFileSystemPermissionContext::UserAction::kLoadFromStorage))
420 .WillOnce(testing::Return(ask_grant_));
421 EXPECT_CALL(
422 permission_context_,
423 GetWritePermissionGrant(
424 kTestOrigin, kTestPath, /*is_directory=*/false,
425 /*process_id=*/ChildProcessHost::kInvalidUniqueID,
426 /*frame_id=*/MSG_ROUTING_NONE,
427 NativeFileSystemPermissionContext::UserAction::kLoadFromStorage))
428 .WillOnce(testing::Return(ask_grant2_));
429
430 NativeFileSystemTransferTokenImpl* token =
431 SerializeAndDeserializeToken(std::move(token_remote));
432 ASSERT_TRUE(token);
433 EXPECT_EQ(kTestOrigin, token->url().origin());
434 EXPECT_EQ(kTestPath, token->url().path());
435 EXPECT_EQ(storage::kFileSystemTypeNativeLocal, token->url().type());
436 EXPECT_EQ(storage::kFileSystemTypeIsolated, token->url().mount_type());
437 EXPECT_EQ(NativeFileSystemTransferTokenImpl::HandleType::kFile,
438 token->type());
439 EXPECT_EQ(ask_grant_, token->shared_handle_state().read_grant);
440 EXPECT_EQ(ask_grant2_, token->shared_handle_state().write_grant);
441 }
442
TEST_F(NativeFileSystemManagerImplTest,SerializeHandle_Native_SingleDirectory)443 TEST_F(NativeFileSystemManagerImplTest,
444 SerializeHandle_Native_SingleDirectory) {
445 const base::FilePath kTestPath(dir_.GetPath().AppendASCII("foobar"));
446 mojo::Remote<blink::mojom::NativeFileSystemDirectoryHandle> handle =
447 GetHandleForDirectory(kTestPath);
448
449 mojo::PendingRemote<blink::mojom::NativeFileSystemTransferToken> token_remote;
450 handle->Transfer(token_remote.InitWithNewPipeAndPassReceiver());
451
452 // Deserializing tokens should re-request grants, with correct user action.
453 EXPECT_CALL(
454 permission_context_,
455 GetReadPermissionGrant(
456 kTestOrigin, kTestPath, /*is_directory=*/true,
457 /*process_id=*/ChildProcessHost::kInvalidUniqueID,
458 /*frame_id=*/MSG_ROUTING_NONE,
459 NativeFileSystemPermissionContext::UserAction::kLoadFromStorage))
460 .WillOnce(testing::Return(ask_grant_));
461 EXPECT_CALL(
462 permission_context_,
463 GetWritePermissionGrant(
464 kTestOrigin, kTestPath, /*is_directory=*/true,
465 /*process_id=*/ChildProcessHost::kInvalidUniqueID,
466 /*frame_id=*/MSG_ROUTING_NONE,
467 NativeFileSystemPermissionContext::UserAction::kLoadFromStorage))
468 .WillOnce(testing::Return(ask_grant2_));
469
470 NativeFileSystemTransferTokenImpl* token =
471 SerializeAndDeserializeToken(std::move(token_remote));
472 ASSERT_TRUE(token);
473 EXPECT_EQ(kTestOrigin, token->url().origin());
474 EXPECT_EQ(kTestPath, token->url().path());
475 EXPECT_EQ(storage::kFileSystemTypeNativeLocal, token->url().type());
476 EXPECT_EQ(storage::kFileSystemTypeIsolated, token->url().mount_type());
477 EXPECT_EQ(NativeFileSystemTransferTokenImpl::HandleType::kDirectory,
478 token->type());
479 EXPECT_EQ(ask_grant_, token->shared_handle_state().read_grant);
480 EXPECT_EQ(ask_grant2_, token->shared_handle_state().write_grant);
481 }
482
TEST_F(NativeFileSystemManagerImplTest,SerializeHandle_Native_FileInsideDirectory)483 TEST_F(NativeFileSystemManagerImplTest,
484 SerializeHandle_Native_FileInsideDirectory) {
485 const base::FilePath kDirectoryPath(dir_.GetPath().AppendASCII("foo"));
486 const std::string kTestName = "test file name ☺";
487 base::CreateDirectory(kDirectoryPath);
488
489 mojo::Remote<blink::mojom::NativeFileSystemDirectoryHandle> directory_handle =
490 GetHandleForDirectory(kDirectoryPath);
491
492 mojo::Remote<blink::mojom::NativeFileSystemFileHandle> file_handle;
493 base::RunLoop get_file_loop;
494 directory_handle->GetFile(
495 kTestName, /*create=*/true,
496 base::BindLambdaForTesting(
497 [&](blink::mojom::NativeFileSystemErrorPtr result,
498 mojo::PendingRemote<blink::mojom::NativeFileSystemFileHandle>
499 handle) {
500 get_file_loop.Quit();
501 ASSERT_EQ(blink::mojom::NativeFileSystemStatus::kOk,
502 result->status);
503 file_handle.Bind(std::move(handle));
504 }));
505 get_file_loop.Run();
506 ASSERT_TRUE(file_handle.is_bound());
507
508 mojo::PendingRemote<blink::mojom::NativeFileSystemTransferToken> token_remote;
509 file_handle->Transfer(token_remote.InitWithNewPipeAndPassReceiver());
510
511 // Deserializing tokens should re-request grants, with correct user action.
512 EXPECT_CALL(
513 permission_context_,
514 GetReadPermissionGrant(
515 kTestOrigin, kDirectoryPath, /*is_directory=*/true,
516 /*process_id=*/ChildProcessHost::kInvalidUniqueID,
517 /*frame_id=*/MSG_ROUTING_NONE,
518 NativeFileSystemPermissionContext::UserAction::kLoadFromStorage))
519 .WillOnce(testing::Return(ask_grant_));
520 EXPECT_CALL(
521 permission_context_,
522 GetWritePermissionGrant(
523 kTestOrigin, kDirectoryPath, /*is_directory=*/true,
524 /*process_id=*/ChildProcessHost::kInvalidUniqueID,
525 /*frame_id=*/MSG_ROUTING_NONE,
526 NativeFileSystemPermissionContext::UserAction::kLoadFromStorage))
527 .WillOnce(testing::Return(ask_grant2_));
528
529 NativeFileSystemTransferTokenImpl* token =
530 SerializeAndDeserializeToken(std::move(token_remote));
531 ASSERT_TRUE(token);
532 EXPECT_EQ(kTestOrigin, token->url().origin());
533 EXPECT_EQ(kDirectoryPath.Append(base::FilePath::FromUTF8Unsafe(kTestName)),
534 token->url().path());
535 EXPECT_EQ(storage::kFileSystemTypeNativeLocal, token->url().type());
536 EXPECT_EQ(storage::kFileSystemTypeIsolated, token->url().mount_type());
537 EXPECT_EQ(NativeFileSystemTransferTokenImpl::HandleType::kFile,
538 token->type());
539 EXPECT_EQ(ask_grant_, token->shared_handle_state().read_grant);
540 EXPECT_EQ(ask_grant2_, token->shared_handle_state().write_grant);
541 }
542
TEST_F(NativeFileSystemManagerImplTest,SerializeHandle_Native_DirectoryInsideDirectory)543 TEST_F(NativeFileSystemManagerImplTest,
544 SerializeHandle_Native_DirectoryInsideDirectory) {
545 const base::FilePath kDirectoryPath(dir_.GetPath().AppendASCII("foo"));
546 const std::string kTestName = "test dir name";
547 base::CreateDirectory(kDirectoryPath);
548
549 mojo::Remote<blink::mojom::NativeFileSystemDirectoryHandle> directory_handle =
550 GetHandleForDirectory(kDirectoryPath);
551
552 mojo::Remote<blink::mojom::NativeFileSystemDirectoryHandle> child_handle;
553 base::RunLoop get_directory_loop;
554 directory_handle->GetDirectory(
555 kTestName, /*create=*/true,
556 base::BindLambdaForTesting(
557 [&](blink::mojom::NativeFileSystemErrorPtr result,
558 mojo::PendingRemote<blink::mojom::NativeFileSystemDirectoryHandle>
559 handle) {
560 get_directory_loop.Quit();
561 ASSERT_EQ(blink::mojom::NativeFileSystemStatus::kOk,
562 result->status);
563 child_handle.Bind(std::move(handle));
564 }));
565 get_directory_loop.Run();
566 ASSERT_TRUE(child_handle.is_bound());
567
568 mojo::PendingRemote<blink::mojom::NativeFileSystemTransferToken> token_remote;
569 child_handle->Transfer(token_remote.InitWithNewPipeAndPassReceiver());
570
571 // Deserializing tokens should re-request grants, with correct user action.
572 EXPECT_CALL(
573 permission_context_,
574 GetReadPermissionGrant(
575 kTestOrigin, kDirectoryPath, /*is_directory=*/true,
576 /*process_id=*/ChildProcessHost::kInvalidUniqueID,
577 /*frame_id=*/MSG_ROUTING_NONE,
578 NativeFileSystemPermissionContext::UserAction::kLoadFromStorage))
579 .WillOnce(testing::Return(ask_grant_));
580 EXPECT_CALL(
581 permission_context_,
582 GetWritePermissionGrant(
583 kTestOrigin, kDirectoryPath, /*is_directory=*/true,
584 /*process_id=*/ChildProcessHost::kInvalidUniqueID,
585 /*frame_id=*/MSG_ROUTING_NONE,
586 NativeFileSystemPermissionContext::UserAction::kLoadFromStorage))
587 .WillOnce(testing::Return(ask_grant2_));
588
589 NativeFileSystemTransferTokenImpl* token =
590 SerializeAndDeserializeToken(std::move(token_remote));
591 ASSERT_TRUE(token);
592 EXPECT_EQ(kTestOrigin, token->url().origin());
593 EXPECT_EQ(kDirectoryPath.AppendASCII(kTestName), token->url().path());
594 EXPECT_EQ(storage::kFileSystemTypeNativeLocal, token->url().type());
595 EXPECT_EQ(storage::kFileSystemTypeIsolated, token->url().mount_type());
596 EXPECT_EQ(NativeFileSystemTransferTokenImpl::HandleType::kDirectory,
597 token->type());
598 EXPECT_EQ(ask_grant_, token->shared_handle_state().read_grant);
599 EXPECT_EQ(ask_grant2_, token->shared_handle_state().write_grant);
600 }
601
602 } // namespace content
603