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