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 "webkit/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 "testing/gtest/include/gtest/gtest.h"
     14 #include "webkit/browser/fileapi/external_mount_points.h"
     15 #include "webkit/browser/fileapi/file_system_backend.h"
     16 #include "webkit/browser/fileapi/isolated_context.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 fileapi::ExternalMountPoints;
     27 using fileapi::FileSystemBackend;
     28 using fileapi::FileSystemContext;
     29 using fileapi::FileSystemMountOption;
     30 using fileapi::FileSystemURL;
     31 using fileapi::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       fileapi::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<fileapi::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                                   fileapi::FileSystemType expect_mount_type,
     84                                   fileapi::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<quota::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           fileapi::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       fileapi::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       fileapi::kFileSystemTypeIsolated,
    134       fileapi::kFileSystemTypeNativeLocal,
    135       base::FilePath(
    136           DRIVE FPL("/test/isolated/root/file")).NormalizePathSeparators(),
    137       base::FilePath::FromUTF8Unsafe(isolated_id).Append(FPL("root/file")).
    138           NormalizePathSeparators(),
    139       isolated_id);
    140 
    141   FileSystemURL cracked_external = file_system_context->CrackURL(
    142       CreateRawFileSystemURL("external", "system"));
    143 
    144   ExpectFileSystemURLMatches(
    145       cracked_external,
    146       GURL(kTestOrigin),
    147       fileapi::kFileSystemTypeExternal,
    148       fileapi::kFileSystemTypeNativeLocal,
    149       base::FilePath(
    150           DRIVE FPL("/test/sys/root/file")).NormalizePathSeparators(),
    151       base::FilePath(FPL("system/root/file")).NormalizePathSeparators(),
    152       "system");
    153 
    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       fileapi::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       fileapi::kFileSystemTypeExternal,
    186       fileapi::kFileSystemTypeNativeLocal,
    187       base::FilePath(
    188           DRIVE FPL("/test/sys/root/file")).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           fileapi::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       fileapi::kFileSystemTypeDrive,
    214       FileSystemMountOption(),
    215       base::FilePath(DRIVE FPL("/test/sys/"))));
    216   ASSERT_TRUE(ExternalMountPoints::GetSystemInstance()->RegisterFileSystem(
    217       "ext",
    218       fileapi::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       fileapi::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        fileapi::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     fileapi::FileSystemType expect_mount_type;
    247     fileapi::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         fileapi::kFileSystemTypePersistent, fileapi::kFileSystemTypePersistent,
    257         FPL("pers_mount/root/file"),
    258         std::string()  /* filesystem id */
    259       },
    260       {
    261         "temp_mount", "temporary", true /* is_valid */,
    262         fileapi::kFileSystemTypeTemporary, fileapi::kFileSystemTypeTemporary,
    263         FPL("temp_mount/root/file"),
    264         std::string()  /* filesystem id */
    265       },
    266       // Should be cracked by isolated mount points:
    267       {
    268         kIsolatedFileSystemID, "isolated", true /* is_valid */,
    269         fileapi::kFileSystemTypeIsolated, fileapi::kFileSystemTypeNativeLocal,
    270         DRIVE FPL("/test/isolated/root/file"),
    271         kIsolatedFileSystemID
    272       },
    273       // Should be cracked by system mount points:
    274       {
    275         "system", "external", true /* is_valid */,
    276         fileapi::kFileSystemTypeExternal, fileapi::kFileSystemTypeDrive,
    277         DRIVE FPL("/test/sys/root/file"),
    278         "system"
    279       },
    280       {
    281         kIsolatedFileSystemID, "external", true /* is_valid */,
    282         fileapi::kFileSystemTypeExternal,
    283         fileapi::kFileSystemTypeRestrictedNativeLocal,
    284         DRIVE FPL("/test/system/isolated/root/file"),
    285         kIsolatedFileSystemID
    286       },
    287       // Should be cracked by FileSystemContext's ExternalMountPoints.
    288       {
    289         "ext", "external", true /* is_valid */,
    290         fileapi::kFileSystemTypeExternal, fileapi::kFileSystemTypeNativeLocal,
    291         DRIVE FPL("/test/local/ext/root/file"),
    292         "ext"
    293       },
    294       // Test for invalid filesystem url (made invalid by adding invalid
    295       // filesystem type).
    296       {
    297         "sytem", "external", false /* is_valid */,
    298         // The rest of values will be ignored.
    299         fileapi::kFileSystemTypeUnknown, fileapi::kFileSystemTypeUnknown,
    300         FPL(""), std::string()
    301       },
    302       // Test for URL with non-existing filesystem id.
    303       {
    304         "invalid", "external", false /* is_valid */,
    305         // The rest of values will be ignored.
    306         fileapi::kFileSystemTypeUnknown, fileapi::kFileSystemTypeUnknown,
    307         FPL(""), std::string()
    308       },
    309   };
    310 
    311   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kTestCases); ++i) {
    312     const base::FilePath virtual_path =
    313         base::FilePath::FromUTF8Unsafe(
    314             kTestCases[i].root).Append(kVirtualPathNoRoot);
    315 
    316     GURL raw_url =
    317         CreateRawFileSystemURL(kTestCases[i].type_str, kTestCases[i].root);
    318     FileSystemURL cracked_url = file_system_context->CrackURL(raw_url);
    319 
    320     SCOPED_TRACE(testing::Message() << "Test case " << i << ": "
    321                                     << "Cracking URL: " << raw_url);
    322 
    323     EXPECT_EQ(kTestCases[i].expect_is_valid, cracked_url.is_valid());
    324     if (!kTestCases[i].expect_is_valid)
    325       continue;
    326 
    327     ExpectFileSystemURLMatches(
    328         cracked_url,
    329         GURL(kTestOrigin),
    330         kTestCases[i].expect_mount_type,
    331         kTestCases[i].expect_type,
    332         base::FilePath(kTestCases[i].expect_path).NormalizePathSeparators(),
    333         virtual_path.NormalizePathSeparators(),
    334         kTestCases[i].expect_filesystem_id);
    335   }
    336 
    337   IsolatedContext::GetInstance()->RevokeFileSystemByPath(
    338       base::FilePath(DRIVE FPL("/test/isolated/root")));
    339   ExternalMountPoints::GetSystemInstance()->RevokeFileSystem("system");
    340   ExternalMountPoints::GetSystemInstance()->RevokeFileSystem("ext");
    341   ExternalMountPoints::GetSystemInstance()->RevokeFileSystem(
    342       kIsolatedFileSystemID);
    343 }
    344 
    345 TEST_F(FileSystemContextTest, CanServeURLRequest) {
    346   scoped_refptr<ExternalMountPoints> external_mount_points(
    347       ExternalMountPoints::CreateRefCounted());
    348   scoped_refptr<FileSystemContext> context(
    349       CreateFileSystemContextForTest(external_mount_points.get()));
    350 
    351   // A request for a sandbox mount point should be served.
    352   FileSystemURL cracked_url =
    353       context->CrackURL(CreateRawFileSystemURL("persistent", "pers_mount"));
    354   EXPECT_EQ(fileapi::kFileSystemTypePersistent, cracked_url.mount_type());
    355   EXPECT_TRUE(context->CanServeURLRequest(cracked_url));
    356 
    357   // A request for an isolated mount point should NOT be served.
    358   std::string isolated_fs_name = "root";
    359   std::string isolated_fs_id =
    360       IsolatedContext::GetInstance()->RegisterFileSystemForPath(
    361           fileapi::kFileSystemTypeNativeLocal,
    362           std::string(),
    363           base::FilePath(DRIVE FPL("/test/isolated/root")),
    364           &isolated_fs_name);
    365   cracked_url = context->CrackURL(
    366       CreateRawFileSystemURL("isolated", isolated_fs_id));
    367   EXPECT_EQ(fileapi::kFileSystemTypeIsolated, cracked_url.mount_type());
    368   EXPECT_FALSE(context->CanServeURLRequest(cracked_url));
    369 
    370   // A request for an external mount point should be served.
    371   const std::string kExternalMountName = "ext_mount";
    372   ASSERT_TRUE(ExternalMountPoints::GetSystemInstance()->RegisterFileSystem(
    373       kExternalMountName, fileapi::kFileSystemTypeDrive,
    374       FileSystemMountOption(),
    375       base::FilePath()));
    376   cracked_url = context->CrackURL(
    377       CreateRawFileSystemURL("external", kExternalMountName));
    378   EXPECT_EQ(fileapi::kFileSystemTypeExternal, cracked_url.mount_type());
    379   EXPECT_TRUE(context->CanServeURLRequest(cracked_url));
    380 
    381   ExternalMountPoints::GetSystemInstance()->RevokeFileSystem(
    382       kExternalMountName);
    383   IsolatedContext::GetInstance()->RevokeFileSystem(isolated_fs_id);
    384 }
    385 
    386 }  // namespace
    387 
    388 }  // namespace content
    389