Home | History | Annotate | Download | only in fileapi
      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 
      5 #include "storage/browser/fileapi/file_system_context.h"
      6 
      7 #include "base/files/scoped_temp_dir.h"
      8 #include "base/message_loop/message_loop.h"
      9 #include "base/strings/stringprintf.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"
     17 
     18 #define FPL(x) FILE_PATH_LITERAL(x)
     19 
     20 #if defined(FILE_PATH_USES_DRIVE_LETTERS)
     21 #define DRIVE FPL("C:")
     22 #else
     23 #define DRIVE
     24 #endif
     25 
     26 using storage::ExternalMountPoints;
     27 using storage::FileSystemBackend;
     28 using storage::FileSystemContext;
     29 using storage::FileSystemMountOption;
     30 using storage::FileSystemURL;
     31 using storage::IsolatedContext;
     32 
     33 namespace content {
     34 
     35 namespace {
     36 
     37 const char kTestOrigin[] = "http://chromium.org/";
     38 
     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",
     43       type_str.c_str(),
     44       fs_id.c_str());
     45   return GURL(url_str);
     46 }
     47 
     48 class FileSystemContextTest : public testing::Test {
     49  public:
     50   FileSystemContextTest() {}
     51 
     52   virtual void SetUp() {
     53     ASSERT_TRUE(data_dir_.CreateUniqueTempDir());
     54 
     55     storage_policy_ = new MockSpecialStoragePolicy();
     56 
     57     mock_quota_manager_ =
     58         new MockQuotaManager(false /* is_incognito */,
     59                                     data_dir_.path(),
     60                                     base::MessageLoopProxy::current().get(),
     61                                     base::MessageLoopProxy::current().get(),
     62                                     storage_policy_.get());
     63   }
     64 
     65  protected:
     66   FileSystemContext* CreateFileSystemContextForTest(
     67       storage::ExternalMountPoints* external_mount_points) {
     68     return new FileSystemContext(
     69         base::MessageLoopProxy::current().get(),
     70         base::MessageLoopProxy::current().get(),
     71         external_mount_points,
     72         storage_policy_.get(),
     73         mock_quota_manager_->proxy(),
     74         ScopedVector<FileSystemBackend>(),
     75         std::vector<storage::URLRequestAutoMountHandler>(),
     76         data_dir_.path(),
     77         CreateAllowFileAccessOptions());
     78   }
     79 
     80   // Verifies a *valid* filesystem url has expected values.
     81   void ExpectFileSystemURLMatches(const FileSystemURL& url,
     82                                   const GURL& expect_origin,
     83                                   storage::FileSystemType expect_mount_type,
     84                                   storage::FileSystemType expect_type,
     85                                   const base::FilePath& expect_path,
     86                                   const base::FilePath& expect_virtual_path,
     87                                   const std::string& expect_filesystem_id) {
     88     EXPECT_TRUE(url.is_valid());
     89 
     90     EXPECT_EQ(expect_origin, url.origin());
     91     EXPECT_EQ(expect_mount_type, url.mount_type());
     92     EXPECT_EQ(expect_type, url.type());
     93     EXPECT_EQ(expect_path, url.path());
     94     EXPECT_EQ(expect_virtual_path, url.virtual_path());
     95     EXPECT_EQ(expect_filesystem_id, url.filesystem_id());
     96   }
     97 
     98  private:
     99   base::ScopedTempDir data_dir_;
    100   base::MessageLoop message_loop_;
    101   scoped_refptr<storage::SpecialStoragePolicy> storage_policy_;
    102   scoped_refptr<MockQuotaManager> mock_quota_manager_;
    103 };
    104 
    105 // It is not valid to pass NULL ExternalMountPoints to FileSystemContext on
    106 // ChromeOS.
    107 #if !defined(OS_CHROMEOS)
    108 TEST_F(FileSystemContextTest, NullExternalMountPoints) {
    109   scoped_refptr<FileSystemContext> file_system_context(
    110       CreateFileSystemContextForTest(NULL));
    111 
    112   // Cracking system external mount and isolated mount points should work.
    113   std::string isolated_name = "root";
    114   std::string isolated_id =
    115       IsolatedContext::GetInstance()->RegisterFileSystemForPath(
    116           storage::kFileSystemTypeNativeLocal,
    117           std::string(),
    118           base::FilePath(DRIVE FPL("/test/isolated/root")),
    119           &isolated_name);
    120   // Register system external mount point.
    121   ASSERT_TRUE(ExternalMountPoints::GetSystemInstance()->RegisterFileSystem(
    122       "system",
    123       storage::kFileSystemTypeNativeLocal,
    124       FileSystemMountOption(),
    125       base::FilePath(DRIVE FPL("/test/sys/"))));
    126 
    127   FileSystemURL cracked_isolated = file_system_context->CrackURL(
    128       CreateRawFileSystemURL("isolated", isolated_id));
    129 
    130   ExpectFileSystemURLMatches(
    131       cracked_isolated,
    132       GURL(kTestOrigin),
    133       storage::kFileSystemTypeIsolated,
    134       storage::kFileSystemTypeNativeLocal,
    135       base::FilePath(DRIVE FPL("/test/isolated/root/file"))
    136           .NormalizePathSeparators(),
    137       base::FilePath::FromUTF8Unsafe(isolated_id)
    138           .Append(FPL("root/file"))
    139           .NormalizePathSeparators(),
    140       isolated_id);
    141 
    142   FileSystemURL cracked_external = file_system_context->CrackURL(
    143       CreateRawFileSystemURL("external", "system"));
    144 
    145   ExpectFileSystemURLMatches(
    146       cracked_external,
    147       GURL(kTestOrigin),
    148       storage::kFileSystemTypeExternal,
    149       storage::kFileSystemTypeNativeLocal,
    150       base::FilePath(DRIVE FPL("/test/sys/root/file"))
    151           .NormalizePathSeparators(),
    152       base::FilePath(FPL("system/root/file")).NormalizePathSeparators(),
    153       "system");
    154 
    155   IsolatedContext::GetInstance()->RevokeFileSystem(isolated_id);
    156   ExternalMountPoints::GetSystemInstance()->RevokeFileSystem("system");
    157 }
    158 #endif  // !defiend(OS_CHROMEOS)
    159 
    160 TEST_F(FileSystemContextTest, FileSystemContextKeepsMountPointsAlive) {
    161   scoped_refptr<ExternalMountPoints> mount_points =
    162       ExternalMountPoints::CreateRefCounted();
    163 
    164   // Register system external mount point.
    165   ASSERT_TRUE(mount_points->RegisterFileSystem(
    166       "system",
    167       storage::kFileSystemTypeNativeLocal,
    168       FileSystemMountOption(),
    169       base::FilePath(DRIVE FPL("/test/sys/"))));
    170 
    171   scoped_refptr<FileSystemContext> file_system_context(
    172       CreateFileSystemContextForTest(mount_points.get()));
    173 
    174   // Release a MountPoints reference created in the test.
    175   mount_points = NULL;
    176 
    177   // FileSystemContext should keep a reference to the |mount_points|, so it
    178   // should be able to resolve the URL.
    179   FileSystemURL cracked_external = file_system_context->CrackURL(
    180       CreateRawFileSystemURL("external", "system"));
    181 
    182   ExpectFileSystemURLMatches(
    183       cracked_external,
    184       GURL(kTestOrigin),
    185       storage::kFileSystemTypeExternal,
    186       storage::kFileSystemTypeNativeLocal,
    187       base::FilePath(DRIVE FPL("/test/sys/root/file"))
    188           .NormalizePathSeparators(),
    189       base::FilePath(FPL("system/root/file")).NormalizePathSeparators(),
    190       "system");
    191 
    192   // No need to revoke the registered filesystem since |mount_points| lifetime
    193   // is bound to this test.
    194 }
    195 
    196 TEST_F(FileSystemContextTest, CrackFileSystemURL) {
    197   scoped_refptr<ExternalMountPoints> external_mount_points(
    198       ExternalMountPoints::CreateRefCounted());
    199   scoped_refptr<FileSystemContext> file_system_context(
    200       CreateFileSystemContextForTest(external_mount_points.get()));
    201 
    202   // Register an isolated mount point.
    203   std::string isolated_file_system_name = "root";
    204   const std::string kIsolatedFileSystemID =
    205       IsolatedContext::GetInstance()->RegisterFileSystemForPath(
    206           storage::kFileSystemTypeNativeLocal,
    207           std::string(),
    208           base::FilePath(DRIVE FPL("/test/isolated/root")),
    209           &isolated_file_system_name);
    210   // Register system external mount point.
    211   ASSERT_TRUE(ExternalMountPoints::GetSystemInstance()->RegisterFileSystem(
    212       "system",
    213       storage::kFileSystemTypeDrive,
    214       FileSystemMountOption(),
    215       base::FilePath(DRIVE FPL("/test/sys/"))));
    216   ASSERT_TRUE(ExternalMountPoints::GetSystemInstance()->RegisterFileSystem(
    217       "ext",
    218       storage::kFileSystemTypeNativeLocal,
    219       FileSystemMountOption(),
    220       base::FilePath(DRIVE FPL("/test/ext"))));
    221   // Register a system external mount point with the same name/id as the
    222   // registered isolated mount point.
    223   ASSERT_TRUE(ExternalMountPoints::GetSystemInstance()->RegisterFileSystem(
    224       kIsolatedFileSystemID,
    225       storage::kFileSystemTypeRestrictedNativeLocal,
    226       FileSystemMountOption(),
    227       base::FilePath(DRIVE FPL("/test/system/isolated"))));
    228   // Add a mount points with the same name as a system mount point to
    229   // FileSystemContext's external mount points.
    230   ASSERT_TRUE(external_mount_points->RegisterFileSystem(
    231       "ext",
    232       storage::kFileSystemTypeNativeLocal,
    233       FileSystemMountOption(),
    234       base::FilePath(DRIVE FPL("/test/local/ext/"))));
    235 
    236   const GURL kTestOrigin = GURL("http://chromium.org/");
    237   const base::FilePath kVirtualPathNoRoot = base::FilePath(FPL("root/file"));
    238 
    239   struct TestCase {
    240     // Test case values.
    241     std::string root;
    242     std::string type_str;
    243 
    244     // Expected test results.
    245     bool expect_is_valid;
    246     storage::FileSystemType expect_mount_type;
    247     storage::FileSystemType expect_type;
    248     const base::FilePath::CharType* expect_path;
    249     std::string expect_filesystem_id;
    250   };
    251 
    252   const TestCase kTestCases[] = {
    253       // Following should not be handled by the url crackers:
    254       {
    255        "pers_mount", "persistent", true /* is_valid */,
    256        storage::kFileSystemTypePersistent, storage::kFileSystemTypePersistent,
    257        FPL("pers_mount/root/file"), std::string() /* filesystem id */
    258       },
    259       {
    260        "temp_mount", "temporary", true /* is_valid */,
    261        storage::kFileSystemTypeTemporary, storage::kFileSystemTypeTemporary,
    262        FPL("temp_mount/root/file"), std::string() /* filesystem id */
    263       },
    264       // Should be cracked by isolated mount points:
    265       {kIsolatedFileSystemID, "isolated", true /* is_valid */,
    266        storage::kFileSystemTypeIsolated, storage::kFileSystemTypeNativeLocal,
    267        DRIVE FPL("/test/isolated/root/file"), kIsolatedFileSystemID},
    268       // Should be cracked by system mount points:
    269       {"system", "external", true /* is_valid */,
    270        storage::kFileSystemTypeExternal, storage::kFileSystemTypeDrive,
    271        DRIVE FPL("/test/sys/root/file"), "system"},
    272       {kIsolatedFileSystemID, "external", true /* is_valid */,
    273        storage::kFileSystemTypeExternal,
    274        storage::kFileSystemTypeRestrictedNativeLocal,
    275        DRIVE FPL("/test/system/isolated/root/file"), kIsolatedFileSystemID},
    276       // Should be cracked by FileSystemContext's ExternalMountPoints.
    277       {"ext", "external", true /* is_valid */, storage::kFileSystemTypeExternal,
    278        storage::kFileSystemTypeNativeLocal,
    279        DRIVE FPL("/test/local/ext/root/file"), "ext"},
    280       // Test for invalid filesystem url (made invalid by adding invalid
    281       // filesystem type).
    282       {"sytem", "external", false /* is_valid */,
    283        // The rest of values will be ignored.
    284        storage::kFileSystemTypeUnknown, storage::kFileSystemTypeUnknown,
    285        FPL(""), std::string()},
    286       // Test for URL with non-existing filesystem id.
    287       {"invalid", "external", false /* is_valid */,
    288        // The rest of values will be ignored.
    289        storage::kFileSystemTypeUnknown, storage::kFileSystemTypeUnknown,
    290        FPL(""), std::string()},
    291   };
    292 
    293   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kTestCases); ++i) {
    294     const base::FilePath virtual_path =
    295         base::FilePath::FromUTF8Unsafe(
    296             kTestCases[i].root).Append(kVirtualPathNoRoot);
    297 
    298     GURL raw_url =
    299         CreateRawFileSystemURL(kTestCases[i].type_str, kTestCases[i].root);
    300     FileSystemURL cracked_url = file_system_context->CrackURL(raw_url);
    301 
    302     SCOPED_TRACE(testing::Message() << "Test case " << i << ": "
    303                                     << "Cracking URL: " << raw_url);
    304 
    305     EXPECT_EQ(kTestCases[i].expect_is_valid, cracked_url.is_valid());
    306     if (!kTestCases[i].expect_is_valid)
    307       continue;
    308 
    309     ExpectFileSystemURLMatches(
    310         cracked_url,
    311         GURL(kTestOrigin),
    312         kTestCases[i].expect_mount_type,
    313         kTestCases[i].expect_type,
    314         base::FilePath(kTestCases[i].expect_path).NormalizePathSeparators(),
    315         virtual_path.NormalizePathSeparators(),
    316         kTestCases[i].expect_filesystem_id);
    317   }
    318 
    319   IsolatedContext::GetInstance()->RevokeFileSystemByPath(
    320       base::FilePath(DRIVE FPL("/test/isolated/root")));
    321   ExternalMountPoints::GetSystemInstance()->RevokeFileSystem("system");
    322   ExternalMountPoints::GetSystemInstance()->RevokeFileSystem("ext");
    323   ExternalMountPoints::GetSystemInstance()->RevokeFileSystem(
    324       kIsolatedFileSystemID);
    325 }
    326 
    327 TEST_F(FileSystemContextTest, CanServeURLRequest) {
    328   scoped_refptr<ExternalMountPoints> external_mount_points(
    329       ExternalMountPoints::CreateRefCounted());
    330   scoped_refptr<FileSystemContext> context(
    331       CreateFileSystemContextForTest(external_mount_points.get()));
    332 
    333   // A request for a sandbox mount point should be served.
    334   FileSystemURL cracked_url =
    335       context->CrackURL(CreateRawFileSystemURL("persistent", "pers_mount"));
    336   EXPECT_EQ(storage::kFileSystemTypePersistent, cracked_url.mount_type());
    337   EXPECT_TRUE(context->CanServeURLRequest(cracked_url));
    338 
    339   // A request for an isolated mount point should NOT be served.
    340   std::string isolated_fs_name = "root";
    341   std::string isolated_fs_id =
    342       IsolatedContext::GetInstance()->RegisterFileSystemForPath(
    343           storage::kFileSystemTypeNativeLocal,
    344           std::string(),
    345           base::FilePath(DRIVE FPL("/test/isolated/root")),
    346           &isolated_fs_name);
    347   cracked_url = context->CrackURL(
    348       CreateRawFileSystemURL("isolated", isolated_fs_id));
    349   EXPECT_EQ(storage::kFileSystemTypeIsolated, cracked_url.mount_type());
    350   EXPECT_FALSE(context->CanServeURLRequest(cracked_url));
    351 
    352   // A request for an external mount point should be served.
    353   const std::string kExternalMountName = "ext_mount";
    354   ASSERT_TRUE(ExternalMountPoints::GetSystemInstance()->RegisterFileSystem(
    355       kExternalMountName,
    356       storage::kFileSystemTypeDrive,
    357       FileSystemMountOption(),
    358       base::FilePath()));
    359   cracked_url = context->CrackURL(
    360       CreateRawFileSystemURL("external", kExternalMountName));
    361   EXPECT_EQ(storage::kFileSystemTypeExternal, cracked_url.mount_type());
    362   EXPECT_TRUE(context->CanServeURLRequest(cracked_url));
    363 
    364   ExternalMountPoints::GetSystemInstance()->RevokeFileSystem(
    365       kExternalMountName);
    366   IsolatedContext::GetInstance()->RevokeFileSystem(isolated_fs_id);
    367 }
    368 
    369 }  // namespace
    370 
    371 }  // namespace content
    372