file_system_context_unittest.cc 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409
  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.
  4. #include "storage/browser/file_system/file_system_context.h"
  5. #include <stddef.h>
  6. #include "base/files/scoped_temp_dir.h"
  7. #include "base/memory/scoped_refptr.h"
  8. #include "base/strings/stringprintf.h"
  9. #include "base/test/bind.h"
  10. #include "base/test/task_environment.h"
  11. #include "base/test/test_future.h"
  12. #include "base/threading/thread_task_runner_handle.h"
  13. #include "build/build_config.h"
  14. #include "build/chromeos_buildflags.h"
  15. #include "components/services/storage/public/cpp/quota_error_or.h"
  16. #include "storage/browser/file_system/external_mount_points.h"
  17. #include "storage/browser/file_system/file_system_backend.h"
  18. #include "storage/browser/file_system/isolated_context.h"
  19. #include "storage/browser/file_system/open_file_system_mode.h"
  20. #include "storage/browser/quota/quota_manager_proxy.h"
  21. #include "storage/browser/test/mock_quota_manager.h"
  22. #include "storage/browser/test/mock_special_storage_policy.h"
  23. #include "storage/browser/test/test_file_system_backend.h"
  24. #include "storage/browser/test/test_file_system_options.h"
  25. #include "testing/gtest/include/gtest/gtest.h"
  26. #define FPL(x) FILE_PATH_LITERAL(x)
  27. #if defined(FILE_PATH_USES_DRIVE_LETTERS)
  28. #define DRIVE FPL("C:")
  29. #else
  30. #define DRIVE
  31. #endif
  32. namespace storage {
  33. namespace {
  34. const char kTestOrigin[] = "http://chromium.org/";
  35. GURL CreateRawFileSystemURL(const std::string& type_str,
  36. const std::string& fs_id) {
  37. std::string url_str =
  38. base::StringPrintf("filesystem:http://chromium.org/%s/%s/root/file",
  39. type_str.c_str(), fs_id.c_str());
  40. return GURL(url_str);
  41. }
  42. class FileSystemContextTest : public testing::Test {
  43. public:
  44. FileSystemContextTest() = default;
  45. void SetUp() override {
  46. ASSERT_TRUE(data_dir_.CreateUniqueTempDir());
  47. storage_policy_ = base::MakeRefCounted<MockSpecialStoragePolicy>();
  48. mock_quota_manager_ = base::MakeRefCounted<MockQuotaManager>(
  49. false /* is_incognito */, data_dir_.GetPath(),
  50. base::ThreadTaskRunnerHandle::Get().get(), storage_policy_.get());
  51. }
  52. protected:
  53. scoped_refptr<FileSystemContext> CreateFileSystemContextForTest(
  54. scoped_refptr<ExternalMountPoints> external_mount_points) {
  55. std::vector<std::unique_ptr<storage::FileSystemBackend>>
  56. additional_providers;
  57. additional_providers.push_back(std::make_unique<TestFileSystemBackend>(
  58. base::ThreadTaskRunnerHandle::Get().get(), data_dir_.GetPath()));
  59. return FileSystemContext::Create(
  60. base::ThreadTaskRunnerHandle::Get(),
  61. base::ThreadTaskRunnerHandle::Get(), std::move(external_mount_points),
  62. storage_policy_, mock_quota_manager_->proxy(),
  63. std::move(additional_providers),
  64. std::vector<URLRequestAutoMountHandler>(), data_dir_.GetPath(),
  65. CreateAllowFileAccessOptions());
  66. }
  67. QuotaManagerProxy* proxy() { return mock_quota_manager_->proxy(); }
  68. // Verifies a *valid* filesystem url has expected values.
  69. void ExpectFileSystemURLMatches(const FileSystemURL& url,
  70. const GURL& expect_origin,
  71. FileSystemType expect_mount_type,
  72. FileSystemType expect_type,
  73. const base::FilePath& expect_path,
  74. const base::FilePath& expect_virtual_path,
  75. const std::string& expect_filesystem_id) {
  76. EXPECT_TRUE(url.is_valid());
  77. EXPECT_EQ(expect_origin, url.origin().GetURL());
  78. EXPECT_EQ(expect_mount_type, url.mount_type());
  79. EXPECT_EQ(expect_type, url.type());
  80. EXPECT_EQ(expect_path, url.path());
  81. EXPECT_EQ(expect_virtual_path, url.virtual_path());
  82. EXPECT_EQ(expect_filesystem_id, url.filesystem_id());
  83. }
  84. inline static absl::optional<FileSystemURL> last_resolved_url_ =
  85. absl::nullopt;
  86. private:
  87. base::ScopedTempDir data_dir_;
  88. base::test::TaskEnvironment task_environment_;
  89. scoped_refptr<SpecialStoragePolicy> storage_policy_;
  90. scoped_refptr<MockQuotaManager> mock_quota_manager_;
  91. // Mock FileSystemBackend implementation which saves the last resolved URL.
  92. class TestFileSystemBackend : public storage::TestFileSystemBackend {
  93. public:
  94. TestFileSystemBackend(base::SequencedTaskRunner* task_runner,
  95. const base::FilePath& base_path)
  96. : storage::TestFileSystemBackend(task_runner, base_path) {}
  97. void ResolveURL(const FileSystemURL& url,
  98. OpenFileSystemMode mode,
  99. ResolveURLCallback callback) override {
  100. last_resolved_url_ = url;
  101. }
  102. };
  103. };
  104. // It is not valid to pass nullptr ExternalMountPoints to FileSystemContext on
  105. // ChromeOS.
  106. #if !BUILDFLAG(IS_CHROMEOS_ASH)
  107. TEST_F(FileSystemContextTest, NullExternalMountPoints) {
  108. scoped_refptr<FileSystemContext> file_system_context =
  109. CreateFileSystemContextForTest(/*external_mount_points=*/nullptr);
  110. // Cracking system external mount and isolated mount points should work.
  111. std::string isolated_name = "root";
  112. IsolatedContext::ScopedFSHandle isolated_fs =
  113. IsolatedContext::GetInstance()->RegisterFileSystemForPath(
  114. kFileSystemTypeLocal, std::string(),
  115. base::FilePath(DRIVE FPL("/test/isolated/root")), &isolated_name);
  116. std::string isolated_id = isolated_fs.id();
  117. // Register system external mount point.
  118. ASSERT_TRUE(ExternalMountPoints::GetSystemInstance()->RegisterFileSystem(
  119. "system", kFileSystemTypeLocal, FileSystemMountOption(),
  120. base::FilePath(DRIVE FPL("/test/sys/"))));
  121. FileSystemURL cracked_isolated =
  122. file_system_context->CrackURLInFirstPartyContext(
  123. CreateRawFileSystemURL("isolated", isolated_id));
  124. ExpectFileSystemURLMatches(
  125. cracked_isolated, GURL(kTestOrigin), kFileSystemTypeIsolated,
  126. kFileSystemTypeLocal,
  127. base::FilePath(DRIVE FPL("/test/isolated/root/file"))
  128. .NormalizePathSeparators(),
  129. base::FilePath::FromUTF8Unsafe(isolated_id)
  130. .Append(FPL("root/file"))
  131. .NormalizePathSeparators(),
  132. isolated_id);
  133. FileSystemURL cracked_external =
  134. file_system_context->CrackURLInFirstPartyContext(
  135. CreateRawFileSystemURL("external", "system"));
  136. ExpectFileSystemURLMatches(
  137. cracked_external, GURL(kTestOrigin), kFileSystemTypeExternal,
  138. kFileSystemTypeLocal,
  139. base::FilePath(DRIVE FPL("/test/sys/root/file"))
  140. .NormalizePathSeparators(),
  141. base::FilePath(FPL("system/root/file")).NormalizePathSeparators(),
  142. "system");
  143. IsolatedContext::GetInstance()->RevokeFileSystem(isolated_id);
  144. ExternalMountPoints::GetSystemInstance()->RevokeFileSystem("system");
  145. }
  146. #endif // !defiend(OS_CHROMEOS)
  147. TEST_F(FileSystemContextTest, FileSystemContextKeepsMountPointsAlive) {
  148. scoped_refptr<ExternalMountPoints> mount_points =
  149. ExternalMountPoints::CreateRefCounted();
  150. // Register system external mount point.
  151. ASSERT_TRUE(mount_points->RegisterFileSystem(
  152. "system", kFileSystemTypeLocal, FileSystemMountOption(),
  153. base::FilePath(DRIVE FPL("/test/sys/"))));
  154. scoped_refptr<FileSystemContext> file_system_context =
  155. CreateFileSystemContextForTest(std::move(mount_points));
  156. // FileSystemContext should keep a reference to the |mount_points|, so it
  157. // should be able to resolve the URL.
  158. FileSystemURL cracked_external =
  159. file_system_context->CrackURLInFirstPartyContext(
  160. CreateRawFileSystemURL("external", "system"));
  161. ExpectFileSystemURLMatches(
  162. cracked_external, GURL(kTestOrigin), kFileSystemTypeExternal,
  163. kFileSystemTypeLocal,
  164. base::FilePath(DRIVE FPL("/test/sys/root/file"))
  165. .NormalizePathSeparators(),
  166. base::FilePath(FPL("system/root/file")).NormalizePathSeparators(),
  167. "system");
  168. // No need to revoke the registered filesystem since |mount_points| lifetime
  169. // is bound to this test.
  170. }
  171. TEST_F(FileSystemContextTest, ResolveURLOnOpenFileSystem_CustomBucket) {
  172. scoped_refptr<FileSystemContext> file_system_context =
  173. CreateFileSystemContextForTest(/*external_mount_points=*/nullptr);
  174. const auto open_callback = base::BindLambdaForTesting(
  175. [&](const FileSystemURL& root_url, const std::string& name,
  176. base::File::Error error) { return; });
  177. const auto storage_key =
  178. blink::StorageKey::CreateFromStringForTesting("http://host/test.crswap");
  179. base::test::TestFuture<storage::QuotaErrorOr<storage::BucketInfo>>
  180. bucket_future;
  181. proxy()->CreateBucketForTesting(
  182. storage_key, "custom_bucket", blink::mojom::StorageType::kTemporary,
  183. base::SequencedTaskRunnerHandle::Get(), bucket_future.GetCallback());
  184. auto bucket = bucket_future.Take();
  185. EXPECT_TRUE(bucket.ok());
  186. ASSERT_FALSE(last_resolved_url_.has_value());
  187. file_system_context->ResolveURLOnOpenFileSystemForTesting(
  188. storage_key, bucket->ToBucketLocator(), kFileSystemTypeTest,
  189. OpenFileSystemMode::OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT,
  190. std::move(open_callback));
  191. ASSERT_TRUE(last_resolved_url_.has_value());
  192. ASSERT_EQ(last_resolved_url_.value().bucket(), bucket->ToBucketLocator());
  193. }
  194. TEST_F(FileSystemContextTest, CrackFileSystemURL) {
  195. scoped_refptr<ExternalMountPoints> external_mount_points =
  196. ExternalMountPoints::CreateRefCounted();
  197. scoped_refptr<FileSystemContext> file_system_context =
  198. CreateFileSystemContextForTest(external_mount_points);
  199. // Register an isolated mount point.
  200. std::string isolated_file_system_name = "root";
  201. IsolatedContext::ScopedFSHandle isolated_fs =
  202. IsolatedContext::GetInstance()->RegisterFileSystemForPath(
  203. kFileSystemTypeLocal, std::string(),
  204. base::FilePath(DRIVE FPL("/test/isolated/root")),
  205. &isolated_file_system_name);
  206. const std::string kIsolatedFileSystemID = isolated_fs.id();
  207. // Register system external mount point.
  208. ASSERT_TRUE(ExternalMountPoints::GetSystemInstance()->RegisterFileSystem(
  209. "system", kFileSystemTypeLocal, FileSystemMountOption(),
  210. base::FilePath(DRIVE FPL("/test/sys/"))));
  211. ASSERT_TRUE(ExternalMountPoints::GetSystemInstance()->RegisterFileSystem(
  212. "ext", kFileSystemTypeLocal, FileSystemMountOption(),
  213. base::FilePath(DRIVE FPL("/test/ext"))));
  214. // Register a system external mount point with the same name/id as the
  215. // registered isolated mount point.
  216. ASSERT_TRUE(ExternalMountPoints::GetSystemInstance()->RegisterFileSystem(
  217. kIsolatedFileSystemID, kFileSystemTypeRestrictedLocal,
  218. FileSystemMountOption(),
  219. base::FilePath(DRIVE FPL("/test/system/isolated"))));
  220. // Add a mount points with the same name as a system mount point to
  221. // FileSystemContext's external mount points.
  222. ASSERT_TRUE(external_mount_points->RegisterFileSystem(
  223. "ext", kFileSystemTypeLocal, FileSystemMountOption(),
  224. base::FilePath(DRIVE FPL("/test/local/ext/"))));
  225. const base::FilePath kVirtualPathNoRoot = base::FilePath(FPL("root/file"));
  226. struct TestCase {
  227. // Test case values.
  228. std::string root;
  229. std::string type_str;
  230. // Expected test results.
  231. bool expect_is_valid;
  232. FileSystemType expect_mount_type;
  233. FileSystemType expect_type;
  234. const base::FilePath::CharType* expect_path;
  235. std::string expect_filesystem_id;
  236. };
  237. const TestCase kTestCases[] = {
  238. // Following should not be handled by the url crackers:
  239. {
  240. "pers_mount", "persistent", true /* is_valid */,
  241. kFileSystemTypePersistent, kFileSystemTypePersistent,
  242. FPL("pers_mount/root/file"), std::string() /* filesystem id */
  243. },
  244. {
  245. "temp_mount", "temporary", true /* is_valid */,
  246. kFileSystemTypeTemporary, kFileSystemTypeTemporary,
  247. FPL("temp_mount/root/file"), std::string() /* filesystem id */
  248. },
  249. // Should be cracked by isolated mount points:
  250. {kIsolatedFileSystemID, "isolated", true /* is_valid */,
  251. kFileSystemTypeIsolated, kFileSystemTypeLocal,
  252. DRIVE FPL("/test/isolated/root/file"), kIsolatedFileSystemID},
  253. // Should be cracked by system mount points:
  254. {"system", "external", true /* is_valid */, kFileSystemTypeExternal,
  255. kFileSystemTypeLocal, DRIVE FPL("/test/sys/root/file"), "system"},
  256. {kIsolatedFileSystemID, "external", true /* is_valid */,
  257. kFileSystemTypeExternal, kFileSystemTypeRestrictedLocal,
  258. DRIVE FPL("/test/system/isolated/root/file"), kIsolatedFileSystemID},
  259. // Should be cracked by FileSystemContext's ExternalMountPoints.
  260. {"ext", "external", true /* is_valid */, kFileSystemTypeExternal,
  261. kFileSystemTypeLocal, DRIVE FPL("/test/local/ext/root/file"), "ext"},
  262. // Test for invalid filesystem url (made invalid by adding invalid
  263. // filesystem type).
  264. {"sytem", "external", false /* is_valid */,
  265. // The rest of values will be ignored.
  266. kFileSystemTypeUnknown, kFileSystemTypeUnknown, FPL(""), std::string()},
  267. // Test for URL with non-existing filesystem id.
  268. {"invalid", "external", false /* is_valid */,
  269. // The rest of values will be ignored.
  270. kFileSystemTypeUnknown, kFileSystemTypeUnknown, FPL(""), std::string()},
  271. };
  272. for (size_t i = 0; i < std::size(kTestCases); ++i) {
  273. const base::FilePath virtual_path =
  274. base::FilePath::FromASCII(kTestCases[i].root)
  275. .Append(kVirtualPathNoRoot);
  276. GURL raw_url =
  277. CreateRawFileSystemURL(kTestCases[i].type_str, kTestCases[i].root);
  278. FileSystemURL cracked_url =
  279. file_system_context->CrackURLInFirstPartyContext(raw_url);
  280. SCOPED_TRACE(testing::Message() << "Test case " << i << ": "
  281. << "Cracking URL: " << raw_url);
  282. EXPECT_EQ(kTestCases[i].expect_is_valid, cracked_url.is_valid());
  283. if (!kTestCases[i].expect_is_valid)
  284. continue;
  285. ExpectFileSystemURLMatches(
  286. cracked_url, GURL(kTestOrigin), kTestCases[i].expect_mount_type,
  287. kTestCases[i].expect_type,
  288. base::FilePath(kTestCases[i].expect_path).NormalizePathSeparators(),
  289. virtual_path.NormalizePathSeparators(),
  290. kTestCases[i].expect_filesystem_id);
  291. }
  292. IsolatedContext::GetInstance()->RevokeFileSystemByPath(
  293. base::FilePath(DRIVE FPL("/test/isolated/root")));
  294. ExternalMountPoints::GetSystemInstance()->RevokeFileSystem("system");
  295. ExternalMountPoints::GetSystemInstance()->RevokeFileSystem("ext");
  296. ExternalMountPoints::GetSystemInstance()->RevokeFileSystem(
  297. kIsolatedFileSystemID);
  298. }
  299. TEST_F(FileSystemContextTest, CanServeURLRequest) {
  300. scoped_refptr<ExternalMountPoints> external_mount_points =
  301. ExternalMountPoints::CreateRefCounted();
  302. scoped_refptr<FileSystemContext> context =
  303. CreateFileSystemContextForTest(std::move(external_mount_points));
  304. // A request for a sandbox mount point should be served.
  305. FileSystemURL cracked_url = context->CrackURLInFirstPartyContext(
  306. CreateRawFileSystemURL("persistent", "pers_mount"));
  307. EXPECT_EQ(kFileSystemTypePersistent, cracked_url.mount_type());
  308. EXPECT_TRUE(context->CanServeURLRequest(cracked_url));
  309. // A request for an isolated mount point should NOT be served.
  310. std::string isolated_fs_name = "root";
  311. IsolatedContext::ScopedFSHandle isolated_fs =
  312. IsolatedContext::GetInstance()->RegisterFileSystemForPath(
  313. kFileSystemTypeLocal, std::string(),
  314. base::FilePath(DRIVE FPL("/test/isolated/root")), &isolated_fs_name);
  315. std::string isolated_fs_id = isolated_fs.id();
  316. cracked_url = context->CrackURLInFirstPartyContext(
  317. CreateRawFileSystemURL("isolated", isolated_fs_id));
  318. EXPECT_EQ(kFileSystemTypeIsolated, cracked_url.mount_type());
  319. EXPECT_FALSE(context->CanServeURLRequest(cracked_url));
  320. // A request for an external mount point should be served.
  321. const std::string kExternalMountName = "ext_mount";
  322. ASSERT_TRUE(ExternalMountPoints::GetSystemInstance()->RegisterFileSystem(
  323. kExternalMountName, kFileSystemTypeLocal, FileSystemMountOption(),
  324. base::FilePath()));
  325. cracked_url = context->CrackURLInFirstPartyContext(
  326. CreateRawFileSystemURL("external", kExternalMountName));
  327. EXPECT_EQ(kFileSystemTypeExternal, cracked_url.mount_type());
  328. EXPECT_TRUE(context->CanServeURLRequest(cracked_url));
  329. ExternalMountPoints::GetSystemInstance()->RevokeFileSystem(
  330. kExternalMountName);
  331. IsolatedContext::GetInstance()->RevokeFileSystem(isolated_fs_id);
  332. }
  333. // Ensures that a backend exists for each common isolated file system type.
  334. // See http://crbug.com/447027
  335. TEST_F(FileSystemContextTest, IsolatedFileSystemsTypesHandled) {
  336. // This does not provide any "additional" file system handlers. In particular,
  337. // on Chrome OS it does not provide chromeos::FileSystemBackend.
  338. scoped_refptr<FileSystemContext> file_system_context =
  339. CreateFileSystemContextForTest(/*external_mount_points=*/nullptr);
  340. // Isolated file system types are handled.
  341. EXPECT_TRUE(
  342. file_system_context->GetFileSystemBackend(kFileSystemTypeIsolated));
  343. EXPECT_TRUE(
  344. file_system_context->GetFileSystemBackend(kFileSystemTypeDragged));
  345. EXPECT_TRUE(file_system_context->GetFileSystemBackend(
  346. kFileSystemTypeForTransientFile));
  347. EXPECT_TRUE(file_system_context->GetFileSystemBackend(kFileSystemTypeLocal));
  348. EXPECT_TRUE(file_system_context->GetFileSystemBackend(
  349. kFileSystemTypeLocalForPlatformApp));
  350. }
  351. } // namespace
  352. } // namespace storage