1 // Copyright (c) 2012 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/sandbox_file_system_backend.h" 6 7 #include <set> 8 9 #include "base/basictypes.h" 10 #include "base/file_util.h" 11 #include "base/files/scoped_temp_dir.h" 12 #include "base/memory/scoped_ptr.h" 13 #include "base/message_loop/message_loop.h" 14 #include "base/message_loop/message_loop_proxy.h" 15 #include "testing/gtest/include/gtest/gtest.h" 16 #include "url/gurl.h" 17 #include "webkit/browser/fileapi/file_system_backend.h" 18 #include "webkit/browser/fileapi/file_system_url.h" 19 #include "webkit/browser/fileapi/mock_file_system_options.h" 20 #include "webkit/browser/fileapi/sandbox_context.h" 21 #include "webkit/common/fileapi/file_system_util.h" 22 23 // PS stands for path separator. 24 #if defined(FILE_PATH_USES_WIN_SEPARATORS) 25 #define PS "\\" 26 #else 27 #define PS "/" 28 #endif 29 30 namespace fileapi { 31 32 namespace { 33 34 const struct RootPathTest { 35 fileapi::FileSystemType type; 36 const char* origin_url; 37 const char* expected_path; 38 } kRootPathTestCases[] = { 39 { fileapi::kFileSystemTypeTemporary, "http://foo:1/", 40 "000" PS "t" }, 41 { fileapi::kFileSystemTypePersistent, "http://foo:1/", 42 "000" PS "p" }, 43 { fileapi::kFileSystemTypeTemporary, "http://bar.com/", 44 "001" PS "t" }, 45 { fileapi::kFileSystemTypePersistent, "http://bar.com/", 46 "001" PS "p" }, 47 { fileapi::kFileSystemTypeTemporary, "https://foo:2/", 48 "002" PS "t" }, 49 { fileapi::kFileSystemTypePersistent, "https://foo:2/", 50 "002" PS "p" }, 51 { fileapi::kFileSystemTypeTemporary, "https://bar.com/", 52 "003" PS "t" }, 53 { fileapi::kFileSystemTypePersistent, "https://bar.com/", 54 "003" PS "p" }, 55 }; 56 57 const struct RootPathFileURITest { 58 fileapi::FileSystemType type; 59 const char* origin_url; 60 const char* expected_path; 61 const char* virtual_path; 62 } kRootPathFileURITestCases[] = { 63 { fileapi::kFileSystemTypeTemporary, "file:///", 64 "000" PS "t", NULL }, 65 { fileapi::kFileSystemTypePersistent, "file:///", 66 "000" PS "p", NULL }, 67 }; 68 69 FileSystemURL CreateFileSystemURL(const char* path) { 70 const GURL kOrigin("http://foo/"); 71 return FileSystemURL::CreateForTest( 72 kOrigin, kFileSystemTypeTemporary, base::FilePath::FromUTF8Unsafe(path)); 73 } 74 75 void DidOpenFileSystem(base::PlatformFileError* error_out, 76 const GURL& origin_url, 77 const std::string& name, 78 base::PlatformFileError error) { 79 *error_out = error; 80 } 81 82 } // namespace 83 84 class SandboxFileSystemBackendTest : public testing::Test { 85 protected: 86 virtual void SetUp() { 87 ASSERT_TRUE(data_dir_.CreateUniqueTempDir()); 88 SetUpNewSandboxContext(CreateAllowFileAccessOptions()); 89 } 90 91 void SetUpNewSandboxContext(const FileSystemOptions& options) { 92 context_.reset(new SandboxContext( 93 NULL /* quota_manager_proxy */, 94 base::MessageLoopProxy::current().get(), 95 data_dir_.path(), 96 NULL /* special_storage_policy */, 97 options)); 98 } 99 100 void SetUpNewBackend(const FileSystemOptions& options) { 101 SetUpNewSandboxContext(options); 102 backend_.reset(new SandboxFileSystemBackend(context_.get())); 103 } 104 105 SandboxContext::OriginEnumerator* CreateOriginEnumerator() const { 106 return backend_->CreateOriginEnumerator(); 107 } 108 109 void CreateOriginTypeDirectory(const GURL& origin, 110 fileapi::FileSystemType type) { 111 base::FilePath target = context_-> 112 GetBaseDirectoryForOriginAndType(origin, type, true); 113 ASSERT_TRUE(!target.empty()); 114 ASSERT_TRUE(base::DirectoryExists(target)); 115 } 116 117 bool GetRootPath(const GURL& origin_url, 118 fileapi::FileSystemType type, 119 OpenFileSystemMode mode, 120 base::FilePath* root_path) { 121 base::PlatformFileError error = base::PLATFORM_FILE_OK; 122 backend_->OpenFileSystem( 123 origin_url, type, mode, 124 base::Bind(&DidOpenFileSystem, &error)); 125 base::MessageLoop::current()->RunUntilIdle(); 126 if (error != base::PLATFORM_FILE_OK) 127 return false; 128 base::FilePath returned_root_path = 129 context_->GetBaseDirectoryForOriginAndType( 130 origin_url, type, false /* create */); 131 if (root_path) 132 *root_path = returned_root_path; 133 return !returned_root_path.empty(); 134 } 135 136 base::FilePath file_system_path() const { 137 return data_dir_.path().Append(SandboxContext::kFileSystemDirectory); 138 } 139 140 base::ScopedTempDir data_dir_; 141 base::MessageLoop message_loop_; 142 scoped_ptr<SandboxContext> context_; 143 scoped_ptr<SandboxFileSystemBackend> backend_; 144 }; 145 146 TEST_F(SandboxFileSystemBackendTest, Empty) { 147 SetUpNewBackend(CreateAllowFileAccessOptions()); 148 scoped_ptr<SandboxContext::OriginEnumerator> enumerator( 149 CreateOriginEnumerator()); 150 ASSERT_TRUE(enumerator->Next().is_empty()); 151 } 152 153 TEST_F(SandboxFileSystemBackendTest, EnumerateOrigins) { 154 SetUpNewBackend(CreateAllowFileAccessOptions()); 155 const char* temporary_origins[] = { 156 "http://www.bar.com/", 157 "http://www.foo.com/", 158 "http://www.foo.com:1/", 159 "http://www.example.com:8080/", 160 "http://www.google.com:80/", 161 }; 162 const char* persistent_origins[] = { 163 "http://www.bar.com/", 164 "http://www.foo.com:8080/", 165 "http://www.foo.com:80/", 166 }; 167 size_t temporary_size = ARRAYSIZE_UNSAFE(temporary_origins); 168 size_t persistent_size = ARRAYSIZE_UNSAFE(persistent_origins); 169 std::set<GURL> temporary_set, persistent_set; 170 for (size_t i = 0; i < temporary_size; ++i) { 171 CreateOriginTypeDirectory(GURL(temporary_origins[i]), 172 fileapi::kFileSystemTypeTemporary); 173 temporary_set.insert(GURL(temporary_origins[i])); 174 } 175 for (size_t i = 0; i < persistent_size; ++i) { 176 CreateOriginTypeDirectory(GURL(persistent_origins[i]), 177 kFileSystemTypePersistent); 178 persistent_set.insert(GURL(persistent_origins[i])); 179 } 180 181 scoped_ptr<SandboxContext::OriginEnumerator> enumerator( 182 CreateOriginEnumerator()); 183 size_t temporary_actual_size = 0; 184 size_t persistent_actual_size = 0; 185 GURL current; 186 while (!(current = enumerator->Next()).is_empty()) { 187 SCOPED_TRACE(testing::Message() << "EnumerateOrigin " << current.spec()); 188 if (enumerator->HasFileSystemType(kFileSystemTypeTemporary)) { 189 ASSERT_TRUE(temporary_set.find(current) != temporary_set.end()); 190 ++temporary_actual_size; 191 } 192 if (enumerator->HasFileSystemType(kFileSystemTypePersistent)) { 193 ASSERT_TRUE(persistent_set.find(current) != persistent_set.end()); 194 ++persistent_actual_size; 195 } 196 } 197 198 EXPECT_EQ(temporary_size, temporary_actual_size); 199 EXPECT_EQ(persistent_size, persistent_actual_size); 200 } 201 202 TEST_F(SandboxFileSystemBackendTest, GetRootPathCreateAndExamine) { 203 std::vector<base::FilePath> returned_root_path( 204 ARRAYSIZE_UNSAFE(kRootPathTestCases)); 205 SetUpNewBackend(CreateAllowFileAccessOptions()); 206 207 // Create a new root directory. 208 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kRootPathTestCases); ++i) { 209 SCOPED_TRACE(testing::Message() << "RootPath (create) #" << i << " " 210 << kRootPathTestCases[i].expected_path); 211 212 base::FilePath root_path; 213 EXPECT_TRUE(GetRootPath(GURL(kRootPathTestCases[i].origin_url), 214 kRootPathTestCases[i].type, 215 OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT, 216 &root_path)); 217 218 base::FilePath expected = file_system_path().AppendASCII( 219 kRootPathTestCases[i].expected_path); 220 EXPECT_EQ(expected.value(), root_path.value()); 221 EXPECT_TRUE(base::DirectoryExists(root_path)); 222 ASSERT_TRUE(returned_root_path.size() > i); 223 returned_root_path[i] = root_path; 224 } 225 226 // Get the root directory with create=false and see if we get the 227 // same directory. 228 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kRootPathTestCases); ++i) { 229 SCOPED_TRACE(testing::Message() << "RootPath (get) #" << i << " " 230 << kRootPathTestCases[i].expected_path); 231 232 base::FilePath root_path; 233 EXPECT_TRUE(GetRootPath(GURL(kRootPathTestCases[i].origin_url), 234 kRootPathTestCases[i].type, 235 OPEN_FILE_SYSTEM_FAIL_IF_NONEXISTENT, 236 &root_path)); 237 ASSERT_TRUE(returned_root_path.size() > i); 238 EXPECT_EQ(returned_root_path[i].value(), root_path.value()); 239 } 240 } 241 242 TEST_F(SandboxFileSystemBackendTest, 243 GetRootPathCreateAndExamineWithNewBackend) { 244 std::vector<base::FilePath> returned_root_path( 245 ARRAYSIZE_UNSAFE(kRootPathTestCases)); 246 SetUpNewBackend(CreateAllowFileAccessOptions()); 247 248 GURL origin_url("http://foo.com:1/"); 249 250 base::FilePath root_path1; 251 EXPECT_TRUE(GetRootPath(origin_url, kFileSystemTypeTemporary, 252 OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT, 253 &root_path1)); 254 255 SetUpNewBackend(CreateDisallowFileAccessOptions()); 256 base::FilePath root_path2; 257 EXPECT_TRUE(GetRootPath(origin_url, kFileSystemTypeTemporary, 258 OPEN_FILE_SYSTEM_FAIL_IF_NONEXISTENT, 259 &root_path2)); 260 261 EXPECT_EQ(root_path1.value(), root_path2.value()); 262 } 263 264 TEST_F(SandboxFileSystemBackendTest, GetRootPathGetWithoutCreate) { 265 SetUpNewBackend(CreateDisallowFileAccessOptions()); 266 267 // Try to get a root directory without creating. 268 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kRootPathTestCases); ++i) { 269 SCOPED_TRACE(testing::Message() << "RootPath (create=false) #" << i << " " 270 << kRootPathTestCases[i].expected_path); 271 EXPECT_FALSE(GetRootPath(GURL(kRootPathTestCases[i].origin_url), 272 kRootPathTestCases[i].type, 273 OPEN_FILE_SYSTEM_FAIL_IF_NONEXISTENT, 274 NULL)); 275 } 276 } 277 278 TEST_F(SandboxFileSystemBackendTest, GetRootPathInIncognito) { 279 SetUpNewBackend(CreateIncognitoFileSystemOptions()); 280 281 // Try to get a root directory. 282 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kRootPathTestCases); ++i) { 283 SCOPED_TRACE(testing::Message() << "RootPath (incognito) #" << i << " " 284 << kRootPathTestCases[i].expected_path); 285 EXPECT_FALSE( 286 GetRootPath(GURL(kRootPathTestCases[i].origin_url), 287 kRootPathTestCases[i].type, 288 OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT, 289 NULL)); 290 } 291 } 292 293 TEST_F(SandboxFileSystemBackendTest, GetRootPathFileURI) { 294 SetUpNewBackend(CreateDisallowFileAccessOptions()); 295 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kRootPathFileURITestCases); ++i) { 296 SCOPED_TRACE(testing::Message() << "RootPathFileURI (disallow) #" 297 << i << " " << kRootPathFileURITestCases[i].expected_path); 298 EXPECT_FALSE( 299 GetRootPath(GURL(kRootPathFileURITestCases[i].origin_url), 300 kRootPathFileURITestCases[i].type, 301 OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT, 302 NULL)); 303 } 304 } 305 306 TEST_F(SandboxFileSystemBackendTest, GetRootPathFileURIWithAllowFlag) { 307 SetUpNewBackend(CreateAllowFileAccessOptions()); 308 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kRootPathFileURITestCases); ++i) { 309 SCOPED_TRACE(testing::Message() << "RootPathFileURI (allow) #" 310 << i << " " << kRootPathFileURITestCases[i].expected_path); 311 base::FilePath root_path; 312 EXPECT_TRUE(GetRootPath(GURL(kRootPathFileURITestCases[i].origin_url), 313 kRootPathFileURITestCases[i].type, 314 OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT, 315 &root_path)); 316 base::FilePath expected = file_system_path().AppendASCII( 317 kRootPathFileURITestCases[i].expected_path); 318 EXPECT_EQ(expected.value(), root_path.value()); 319 EXPECT_TRUE(base::DirectoryExists(root_path)); 320 } 321 } 322 323 } // namespace fileapi 324