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