Home | History | Annotate | Download | only in fileapi
      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.
      4 
      5 #include <string>
      6 
      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"
     12 
     13 #define FPL(x) FILE_PATH_LITERAL(x)
     14 
     15 #if defined(FILE_PATH_USES_DRIVE_LETTERS)
     16 #define DRIVE FPL("C:")
     17 #else
     18 #define DRIVE
     19 #endif
     20 
     21 using storage::FileSystemMountOption;
     22 using storage::FileSystemURL;
     23 using storage::IsolatedContext;
     24 using storage::kFileSystemTypeDragged;
     25 using storage::kFileSystemTypeIsolated;
     26 using storage::kFileSystemTypeNativeLocal;
     27 
     28 namespace content {
     29 
     30 typedef IsolatedContext::MountPointInfo FileInfo;
     31 
     32 namespace {
     33 
     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("\\")),
     42 #endif
     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")),
     47 };
     48 
     49 }  // namespace
     50 
     51 class IsolatedContextTest : public testing::Test {
     52  public:
     53   IsolatedContextTest() {
     54     for (size_t i = 0; i < arraysize(kTestPaths); ++i)
     55       fileset_.insert(kTestPaths[i].NormalizePathSeparators());
     56   }
     57 
     58   virtual void SetUp() {
     59     IsolatedContext::FileInfoSet files;
     60     for (size_t i = 0; i < arraysize(kTestPaths); ++i) {
     61       std::string name;
     62       ASSERT_TRUE(
     63           files.AddPath(kTestPaths[i].NormalizePathSeparators(), &name));
     64       names_.push_back(name);
     65     }
     66     id_ = IsolatedContext::GetInstance()->RegisterDraggedFileSystem(files);
     67     IsolatedContext::GetInstance()->AddReference(id_);
     68     ASSERT_FALSE(id_.empty());
     69   }
     70 
     71   virtual void TearDown() {
     72     IsolatedContext::GetInstance()->RemoveReference(id_);
     73   }
     74 
     75   IsolatedContext* isolated_context() const {
     76     return IsolatedContext::GetInstance();
     77   }
     78 
     79  protected:
     80   std::string id_;
     81   std::multiset<base::FilePath> fileset_;
     82   std::vector<std::string> names_;
     83 
     84  private:
     85   DISALLOW_COPY_AND_ASSIGN(IsolatedContextTest);
     86 };
     87 
     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());
     95   }
     96 
     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());
    116   }
    117 
    118   // Make sure GetRegisteredPath returns false for id_ since it is
    119   // registered for dragged files.
    120   base::FilePath path;
    121   ASSERT_FALSE(isolated_context()->GetRegisteredPath(id_, &path));
    122 
    123   // Deref the current one and registering a new one.
    124   isolated_context()->RemoveReference(id_);
    125 
    126   std::string id2 = isolated_context()->RegisterFileSystemForPath(
    127       kFileSystemTypeNativeLocal, std::string(),
    128       base::FilePath(DRIVE FPL("/foo")), NULL);
    129 
    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));
    133 
    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));
    137 
    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);
    145 
    146   // Remove file system for id4.
    147   isolated_context()->AddReference(id4);
    148   isolated_context()->RemoveReference(id4);
    149 
    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));
    155 
    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);
    161 
    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));
    167 
    168   // Revoke the file systems by path.
    169   isolated_context()->RevokeFileSystemByPath(path);
    170 
    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));
    176 }
    177 
    178 TEST_F(IsolatedContextTest, CrackWithRelativePaths) {
    179   const struct {
    180     base::FilePath::StringType path;
    181     bool valid;
    182   } relatives[] = {
    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
    190 #else
    191 # define SHOULD_FAIL_WITH_WIN_SEPARATORS true
    192 #endif
    193     { FPL("foo\\..\\baz"), SHOULD_FAIL_WITH_WIN_SEPARATORS },
    194     { FPL("foo/..\\baz"), SHOULD_FAIL_WITH_WIN_SEPARATORS },
    195   };
    196 
    197   for (size_t i = 0; i < arraysize(kTestPaths); ++i) {
    198     for (size_t j = 0; j < ARRAYSIZE_UNSAFE(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));
    213         continue;
    214       }
    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());
    224     }
    225   }
    226 }
    227 
    228 TEST_F(IsolatedContextTest, CrackURLWithRelativePaths) {
    229   const struct {
    230     base::FilePath::StringType path;
    231     bool valid;
    232   } relatives[] = {
    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
    240 #else
    241 # define SHOULD_FAIL_WITH_WIN_SEPARATORS true
    242 #endif
    243     { FPL("foo\\..\\baz"), SHOULD_FAIL_WITH_WIN_SEPARATORS },
    244     { FPL("foo/..\\baz"), SHOULD_FAIL_WITH_WIN_SEPARATORS },
    245   };
    246 
    247   for (size_t i = 0; i < arraysize(kTestPaths); ++i) {
    248     for (size_t j = 0; j < ARRAYSIZE_UNSAFE(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);
    254 
    255       FileSystemURL cracked = isolated_context()->CreateCrackedFileSystemURL(
    256           GURL("http://chromium.org"), kFileSystemTypeIsolated, virtual_path);
    257 
    258       ASSERT_EQ(relatives[j].valid, cracked.is_valid());
    259 
    260       if (!relatives[j].valid)
    261         continue;
    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());
    270     }
    271   }
    272 }
    273 
    274 TEST_F(IsolatedContextTest, TestWithVirtualRoot) {
    275   std::string cracked_id;
    276   base::FilePath cracked_path;
    277   FileSystemMountOption cracked_option;
    278 
    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);
    287 
    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));
    294 }
    295 
    296 TEST_F(IsolatedContextTest, CanHandleURL) {
    297   const GURL test_origin("http://chromium.org");
    298   const base::FilePath test_path(FPL("/mount"));
    299 
    300   // Should handle isolated file system.
    301   EXPECT_TRUE(isolated_context()->HandlesFileSystemMountType(
    302       storage::kFileSystemTypeIsolated));
    303 
    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));
    322 }
    323 
    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,
    331           "_",
    332           base::FilePath(FPL("relpath")));
    333   ASSERT_FALSE(empty_fsid.empty());
    334   ASSERT_FALSE(relative_fsid.empty());
    335 
    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);
    341 
    342   base::FilePath test_virtual_path =
    343       base::FilePath().AppendASCII("virtualdir").AppendASCII("virtualfile.txt");
    344 
    345   base::FilePath whole_virtual_path =
    346       isolated_context()->CreateVirtualRootPath(database_fsid)
    347           .AppendASCII("_").Append(test_virtual_path);
    348 
    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());
    359 }
    360 
    361 }  // namespace content
    362