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