| // Copyright 2014 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include <string> |
| |
| #include "base/basictypes.h" |
| #include "base/logging.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "webkit/browser/fileapi/file_system_url.h" |
| #include "webkit/browser/fileapi/isolated_context.h" |
| |
| #define FPL(x) FILE_PATH_LITERAL(x) |
| |
| #if defined(FILE_PATH_USES_DRIVE_LETTERS) |
| #define DRIVE FPL("C:") |
| #else |
| #define DRIVE |
| #endif |
| |
| using fileapi::FileSystemMountOption; |
| using fileapi::FileSystemURL; |
| using fileapi::IsolatedContext; |
| using fileapi::kFileSystemTypeDragged; |
| using fileapi::kFileSystemTypeIsolated; |
| using fileapi::kFileSystemTypeNativeLocal; |
| |
| namespace content { |
| |
| typedef IsolatedContext::MountPointInfo FileInfo; |
| |
| namespace { |
| |
| const base::FilePath kTestPaths[] = { |
| base::FilePath(DRIVE FPL("/a/b.txt")), |
| base::FilePath(DRIVE FPL("/c/d/e")), |
| base::FilePath(DRIVE FPL("/h/")), |
| base::FilePath(DRIVE FPL("/")), |
| #if defined(FILE_PATH_USES_WIN_SEPARATORS) |
| base::FilePath(DRIVE FPL("\\foo\\bar")), |
| base::FilePath(DRIVE FPL("\\")), |
| #endif |
| // For duplicated base name test. |
| base::FilePath(DRIVE FPL("/")), |
| base::FilePath(DRIVE FPL("/f/e")), |
| base::FilePath(DRIVE FPL("/f/b.txt")), |
| }; |
| |
| } // namespace |
| |
| class IsolatedContextTest : public testing::Test { |
| public: |
| IsolatedContextTest() { |
| for (size_t i = 0; i < arraysize(kTestPaths); ++i) |
| fileset_.insert(kTestPaths[i].NormalizePathSeparators()); |
| } |
| |
| virtual void SetUp() { |
| IsolatedContext::FileInfoSet files; |
| for (size_t i = 0; i < arraysize(kTestPaths); ++i) { |
| std::string name; |
| ASSERT_TRUE( |
| files.AddPath(kTestPaths[i].NormalizePathSeparators(), &name)); |
| names_.push_back(name); |
| } |
| id_ = IsolatedContext::GetInstance()->RegisterDraggedFileSystem(files); |
| IsolatedContext::GetInstance()->AddReference(id_); |
| ASSERT_FALSE(id_.empty()); |
| } |
| |
| virtual void TearDown() { |
| IsolatedContext::GetInstance()->RemoveReference(id_); |
| } |
| |
| IsolatedContext* isolated_context() const { |
| return IsolatedContext::GetInstance(); |
| } |
| |
| protected: |
| std::string id_; |
| std::multiset<base::FilePath> fileset_; |
| std::vector<std::string> names_; |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(IsolatedContextTest); |
| }; |
| |
| TEST_F(IsolatedContextTest, RegisterAndRevokeTest) { |
| // See if the returned top-level entries match with what we registered. |
| std::vector<FileInfo> toplevels; |
| ASSERT_TRUE(isolated_context()->GetDraggedFileInfo(id_, &toplevels)); |
| ASSERT_EQ(fileset_.size(), toplevels.size()); |
| for (size_t i = 0; i < toplevels.size(); ++i) { |
| ASSERT_TRUE(fileset_.find(toplevels[i].path) != fileset_.end()); |
| } |
| |
| // See if the name of each registered kTestPaths (that is what we |
| // register in SetUp() by RegisterDraggedFileSystem) is properly cracked as |
| // a valid virtual path in the isolated filesystem. |
| for (size_t i = 0; i < arraysize(kTestPaths); ++i) { |
| base::FilePath virtual_path = isolated_context()->CreateVirtualRootPath(id_) |
| .AppendASCII(names_[i]); |
| std::string cracked_id; |
| base::FilePath cracked_path; |
| std::string cracked_inner_id; |
| fileapi::FileSystemType cracked_type; |
| FileSystemMountOption cracked_option; |
| ASSERT_TRUE(isolated_context()->CrackVirtualPath( |
| virtual_path, &cracked_id, &cracked_type, &cracked_inner_id, |
| &cracked_path, &cracked_option)); |
| ASSERT_EQ(kTestPaths[i].NormalizePathSeparators().value(), |
| cracked_path.value()); |
| ASSERT_EQ(id_, cracked_id); |
| ASSERT_EQ(kFileSystemTypeDragged, cracked_type); |
| EXPECT_TRUE(cracked_inner_id.empty()); |
| } |
| |
| // Make sure GetRegisteredPath returns false for id_ since it is |
| // registered for dragged files. |
| base::FilePath path; |
| ASSERT_FALSE(isolated_context()->GetRegisteredPath(id_, &path)); |
| |
| // Deref the current one and registering a new one. |
| isolated_context()->RemoveReference(id_); |
| |
| std::string id2 = isolated_context()->RegisterFileSystemForPath( |
| kFileSystemTypeNativeLocal, std::string(), |
| base::FilePath(DRIVE FPL("/foo")), NULL); |
| |
| // Make sure the GetDraggedFileInfo returns false for both ones. |
| ASSERT_FALSE(isolated_context()->GetDraggedFileInfo(id2, &toplevels)); |
| ASSERT_FALSE(isolated_context()->GetDraggedFileInfo(id_, &toplevels)); |
| |
| // Make sure the GetRegisteredPath returns true only for the new one. |
| ASSERT_FALSE(isolated_context()->GetRegisteredPath(id_, &path)); |
| ASSERT_TRUE(isolated_context()->GetRegisteredPath(id2, &path)); |
| |
| // Try registering three more file systems for the same path as id2. |
| std::string id3 = isolated_context()->RegisterFileSystemForPath( |
| kFileSystemTypeNativeLocal, std::string(), path, NULL); |
| std::string id4 = isolated_context()->RegisterFileSystemForPath( |
| kFileSystemTypeNativeLocal, std::string(), path, NULL); |
| std::string id5 = isolated_context()->RegisterFileSystemForPath( |
| kFileSystemTypeNativeLocal, std::string(), path, NULL); |
| |
| // Remove file system for id4. |
| isolated_context()->AddReference(id4); |
| isolated_context()->RemoveReference(id4); |
| |
| // Only id4 should become invalid now. |
| ASSERT_TRUE(isolated_context()->GetRegisteredPath(id2, &path)); |
| ASSERT_TRUE(isolated_context()->GetRegisteredPath(id3, &path)); |
| ASSERT_FALSE(isolated_context()->GetRegisteredPath(id4, &path)); |
| ASSERT_TRUE(isolated_context()->GetRegisteredPath(id5, &path)); |
| |
| // Revoke file system id5, after adding multiple references. |
| isolated_context()->AddReference(id5); |
| isolated_context()->AddReference(id5); |
| isolated_context()->AddReference(id5); |
| isolated_context()->RevokeFileSystem(id5); |
| |
| // No matter how many references we add id5 must be invalid now. |
| ASSERT_TRUE(isolated_context()->GetRegisteredPath(id2, &path)); |
| ASSERT_TRUE(isolated_context()->GetRegisteredPath(id3, &path)); |
| ASSERT_FALSE(isolated_context()->GetRegisteredPath(id4, &path)); |
| ASSERT_FALSE(isolated_context()->GetRegisteredPath(id5, &path)); |
| |
| // Revoke the file systems by path. |
| isolated_context()->RevokeFileSystemByPath(path); |
| |
| // Now all the file systems associated to the path must be invalid. |
| ASSERT_FALSE(isolated_context()->GetRegisteredPath(id2, &path)); |
| ASSERT_FALSE(isolated_context()->GetRegisteredPath(id3, &path)); |
| ASSERT_FALSE(isolated_context()->GetRegisteredPath(id4, &path)); |
| ASSERT_FALSE(isolated_context()->GetRegisteredPath(id5, &path)); |
| } |
| |
| TEST_F(IsolatedContextTest, CrackWithRelativePaths) { |
| const struct { |
| base::FilePath::StringType path; |
| bool valid; |
| } relatives[] = { |
| { FPL("foo"), true }, |
| { FPL("foo/bar"), true }, |
| { FPL(".."), false }, |
| { FPL("foo/.."), false }, |
| { FPL("foo/../bar"), false }, |
| #if defined(FILE_PATH_USES_WIN_SEPARATORS) |
| # define SHOULD_FAIL_WITH_WIN_SEPARATORS false |
| #else |
| # define SHOULD_FAIL_WITH_WIN_SEPARATORS true |
| #endif |
| { FPL("foo\\..\\baz"), SHOULD_FAIL_WITH_WIN_SEPARATORS }, |
| { FPL("foo/..\\baz"), SHOULD_FAIL_WITH_WIN_SEPARATORS }, |
| }; |
| |
| for (size_t i = 0; i < arraysize(kTestPaths); ++i) { |
| for (size_t j = 0; j < ARRAYSIZE_UNSAFE(relatives); ++j) { |
| SCOPED_TRACE(testing::Message() << "Testing " |
| << kTestPaths[i].value() << " " << relatives[j].path); |
| base::FilePath virtual_path = |
| isolated_context()->CreateVirtualRootPath(id_).AppendASCII( |
| names_[i]).Append(relatives[j].path); |
| std::string cracked_id; |
| base::FilePath cracked_path; |
| fileapi::FileSystemType cracked_type; |
| std::string cracked_inner_id; |
| FileSystemMountOption cracked_option; |
| if (!relatives[j].valid) { |
| ASSERT_FALSE(isolated_context()->CrackVirtualPath( |
| virtual_path, &cracked_id, &cracked_type, &cracked_inner_id, |
| &cracked_path, &cracked_option)); |
| continue; |
| } |
| ASSERT_TRUE(isolated_context()->CrackVirtualPath( |
| virtual_path, &cracked_id, &cracked_type, &cracked_inner_id, |
| &cracked_path, &cracked_option)); |
| ASSERT_EQ(kTestPaths[i].Append(relatives[j].path) |
| .NormalizePathSeparators().value(), |
| cracked_path.value()); |
| ASSERT_EQ(id_, cracked_id); |
| ASSERT_EQ(kFileSystemTypeDragged, cracked_type); |
| EXPECT_TRUE(cracked_inner_id.empty()); |
| } |
| } |
| } |
| |
| TEST_F(IsolatedContextTest, CrackURLWithRelativePaths) { |
| const struct { |
| base::FilePath::StringType path; |
| bool valid; |
| } relatives[] = { |
| { FPL("foo"), true }, |
| { FPL("foo/bar"), true }, |
| { FPL(".."), false }, |
| { FPL("foo/.."), false }, |
| { FPL("foo/../bar"), false }, |
| #if defined(FILE_PATH_USES_WIN_SEPARATORS) |
| # define SHOULD_FAIL_WITH_WIN_SEPARATORS false |
| #else |
| # define SHOULD_FAIL_WITH_WIN_SEPARATORS true |
| #endif |
| { FPL("foo\\..\\baz"), SHOULD_FAIL_WITH_WIN_SEPARATORS }, |
| { FPL("foo/..\\baz"), SHOULD_FAIL_WITH_WIN_SEPARATORS }, |
| }; |
| |
| for (size_t i = 0; i < arraysize(kTestPaths); ++i) { |
| for (size_t j = 0; j < ARRAYSIZE_UNSAFE(relatives); ++j) { |
| SCOPED_TRACE(testing::Message() << "Testing " |
| << kTestPaths[i].value() << " " << relatives[j].path); |
| base::FilePath virtual_path = |
| isolated_context()->CreateVirtualRootPath(id_).AppendASCII( |
| names_[i]).Append(relatives[j].path); |
| |
| FileSystemURL cracked = isolated_context()->CreateCrackedFileSystemURL( |
| GURL("http://chromium.org"), kFileSystemTypeIsolated, virtual_path); |
| |
| ASSERT_EQ(relatives[j].valid, cracked.is_valid()); |
| |
| if (!relatives[j].valid) |
| continue; |
| ASSERT_EQ(GURL("http://chromium.org"), cracked.origin()); |
| ASSERT_EQ(kTestPaths[i].Append(relatives[j].path) |
| .NormalizePathSeparators().value(), |
| cracked.path().value()); |
| ASSERT_EQ(virtual_path.NormalizePathSeparators(), cracked.virtual_path()); |
| ASSERT_EQ(id_, cracked.filesystem_id()); |
| ASSERT_EQ(kFileSystemTypeDragged, cracked.type()); |
| ASSERT_EQ(kFileSystemTypeIsolated, cracked.mount_type()); |
| } |
| } |
| } |
| |
| TEST_F(IsolatedContextTest, TestWithVirtualRoot) { |
| std::string cracked_id; |
| base::FilePath cracked_path; |
| FileSystemMountOption cracked_option; |
| |
| // Trying to crack virtual root "/" returns true but with empty cracked path |
| // as "/" of the isolated filesystem is a pure virtual directory |
| // that has no corresponding platform directory. |
| base::FilePath virtual_path = isolated_context()->CreateVirtualRootPath(id_); |
| ASSERT_TRUE(isolated_context()->CrackVirtualPath( |
| virtual_path, &cracked_id, NULL, NULL, &cracked_path, &cracked_option)); |
| ASSERT_EQ(FPL(""), cracked_path.value()); |
| ASSERT_EQ(id_, cracked_id); |
| |
| // Trying to crack "/foo" should fail (because "foo" is not the one |
| // included in the kTestPaths). |
| virtual_path = isolated_context()->CreateVirtualRootPath( |
| id_).AppendASCII("foo"); |
| ASSERT_FALSE(isolated_context()->CrackVirtualPath( |
| virtual_path, &cracked_id, NULL, NULL, &cracked_path, &cracked_option)); |
| } |
| |
| TEST_F(IsolatedContextTest, CanHandleURL) { |
| const GURL test_origin("http://chromium.org"); |
| const base::FilePath test_path(FPL("/mount")); |
| |
| // Should handle isolated file system. |
| EXPECT_TRUE(isolated_context()->HandlesFileSystemMountType( |
| fileapi::kFileSystemTypeIsolated)); |
| |
| // Shouldn't handle the rest. |
| EXPECT_FALSE(isolated_context()->HandlesFileSystemMountType( |
| fileapi::kFileSystemTypeExternal)); |
| EXPECT_FALSE(isolated_context()->HandlesFileSystemMountType( |
| fileapi::kFileSystemTypeTemporary)); |
| EXPECT_FALSE(isolated_context()->HandlesFileSystemMountType( |
| fileapi::kFileSystemTypePersistent)); |
| EXPECT_FALSE(isolated_context()->HandlesFileSystemMountType( |
| fileapi::kFileSystemTypeTest)); |
| // Not even if it's isolated subtype. |
| EXPECT_FALSE(isolated_context()->HandlesFileSystemMountType( |
| fileapi::kFileSystemTypeNativeLocal)); |
| EXPECT_FALSE(isolated_context()->HandlesFileSystemMountType( |
| fileapi::kFileSystemTypeDragged)); |
| EXPECT_FALSE(isolated_context()->HandlesFileSystemMountType( |
| fileapi::kFileSystemTypeNativeMedia)); |
| EXPECT_FALSE(isolated_context()->HandlesFileSystemMountType( |
| fileapi::kFileSystemTypeDeviceMedia)); |
| } |
| |
| TEST_F(IsolatedContextTest, VirtualFileSystemTests) { |
| // Should be able to register empty and non-absolute paths |
| std::string empty_fsid = isolated_context()->RegisterFileSystemForVirtualPath( |
| fileapi::kFileSystemTypeIsolated, "_", base::FilePath()); |
| std::string relative_fsid = |
| isolated_context()->RegisterFileSystemForVirtualPath( |
| fileapi::kFileSystemTypeIsolated, "_", |
| base::FilePath(FPL("relpath"))); |
| ASSERT_FALSE(empty_fsid.empty()); |
| ASSERT_FALSE(relative_fsid.empty()); |
| |
| // Make sure that filesystem root is not prepended to cracked virtual paths. |
| base::FilePath database_root = base::FilePath(DRIVE FPL("/database_path")); |
| std::string database_fsid = |
| isolated_context()->RegisterFileSystemForVirtualPath( |
| fileapi::kFileSystemTypeIsolated, "_", database_root); |
| |
| base::FilePath test_virtual_path = |
| base::FilePath().AppendASCII("virtualdir").AppendASCII("virtualfile.txt"); |
| |
| base::FilePath whole_virtual_path = |
| isolated_context()->CreateVirtualRootPath(database_fsid) |
| .AppendASCII("_").Append(test_virtual_path); |
| |
| std::string cracked_id; |
| base::FilePath cracked_path; |
| std::string cracked_inner_id; |
| FileSystemMountOption cracked_option; |
| ASSERT_TRUE(isolated_context()->CrackVirtualPath( |
| whole_virtual_path, &cracked_id, NULL, &cracked_inner_id, |
| &cracked_path, &cracked_option)); |
| ASSERT_EQ(database_fsid, cracked_id); |
| ASSERT_EQ(test_virtual_path, cracked_path); |
| EXPECT_TRUE(cracked_inner_id.empty()); |
| } |
| |
| } // namespace content |