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