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