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