diff options
author | kinuko@chromium.org <kinuko@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-05-09 06:29:59 +0000 |
---|---|---|
committer | kinuko@chromium.org <kinuko@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-05-09 06:29:59 +0000 |
commit | c62983a7fcbd13cb5aade8da6d4f27c44dd5c069 (patch) | |
tree | 7532ffa1f81bbf1eed6dbf5c9009c4c4ecd89f4e /webkit/fileapi | |
parent | d36f941bbea3e9fa6d13829626a1911008b37f17 (diff) | |
download | chromium_src-c62983a7fcbd13cb5aade8da6d4f27c44dd5c069.zip chromium_src-c62983a7fcbd13cb5aade8da6d4f27c44dd5c069.tar.gz chromium_src-c62983a7fcbd13cb5aade8da6d4f27c44dd5c069.tar.bz2 |
Implement SandboxQuotaClient for Quota support in sandboxed filesystem
- Refactored FileSystemUsageTracker as a SandboxQuotaClient
- Added a few more tests
BUG=61676
TEST=SandboxQuotaClientTest.*
Review URL: http://codereview.chromium.org/6883002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@84604 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'webkit/fileapi')
21 files changed, 1028 insertions, 657 deletions
diff --git a/webkit/fileapi/file_system_context.cc b/webkit/fileapi/file_system_context.cc index 7e0d62e..d27b87d 100644 --- a/webkit/fileapi/file_system_context.cc +++ b/webkit/fileapi/file_system_context.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -8,15 +8,32 @@ #include "base/message_loop_proxy.h" #include "googleurl/src/gurl.h" #include "webkit/fileapi/file_system_path_manager.h" -#include "webkit/fileapi/file_system_usage_tracker.h" #include "webkit/fileapi/sandbox_mount_point_provider.h" +#include "webkit/fileapi/sandbox_quota_client.h" +#include "webkit/quota/quota_manager.h" + +using quota::QuotaClient; namespace fileapi { +namespace { +QuotaClient* CreateQuotaClient( + scoped_refptr<base::MessageLoopProxy> file_message_loop, + FileSystemContext* context, + bool is_incognito) { + // TODO(kinuko): For now we assume only sandbox filesystem uses + // the quota feature. If we want to support multiple filesystem types + // that require different quota we'll need to add more QuotaClientID + // and more factory-like code around QuotaClient. + return new SandboxQuotaClient(file_message_loop, context, is_incognito); +} +} // anonymous namespace + FileSystemContext::FileSystemContext( scoped_refptr<base::MessageLoopProxy> file_message_loop, scoped_refptr<base::MessageLoopProxy> io_message_loop, scoped_refptr<quota::SpecialStoragePolicy> special_storage_policy, + quota::QuotaManagerProxy* quota_manager_proxy, const FilePath& profile_path, bool is_incognito, bool allow_file_access, @@ -25,16 +42,19 @@ FileSystemContext::FileSystemContext( : file_message_loop_(file_message_loop), io_message_loop_(io_message_loop), special_storage_policy_(special_storage_policy), + quota_manager_proxy_(quota_manager_proxy), allow_file_access_from_files_(allow_file_access), unlimited_quota_(unlimited_quota), - path_manager_(path_manager), - usage_tracker_(new FileSystemUsageTracker( - file_message_loop, profile_path, is_incognito)) { + path_manager_(path_manager) { if (!path_manager) { path_manager_.reset(new FileSystemPathManager( file_message_loop, profile_path, special_storage_policy, is_incognito, allow_file_access)); } + if (quota_manager_proxy) { + quota_manager_proxy->RegisterClient(CreateQuotaClient( + file_message_loop, this, is_incognito)); + } } FileSystemContext::~FileSystemContext() { @@ -55,11 +75,8 @@ void FileSystemContext::DeleteDataForOriginOnFileThread( DCHECK(path_manager_.get()); DCHECK(file_message_loop_->BelongsToCurrentThread()); - std::string origin_identifier = - SandboxMountPointProvider::GetOriginIdentifierFromURL(origin_url); - FilePath path_for_origin = sandbox_provider()->base_path().AppendASCII( - origin_identifier); - + FilePath path_for_origin = + sandbox_provider()->GetBaseDirectoryForOrigin(origin_url); file_util::Delete(path_for_origin, true /* recursive */); } diff --git a/webkit/fileapi/file_system_context.h b/webkit/fileapi/file_system_context.h index aa1804a..f80e5f0 100644 --- a/webkit/fileapi/file_system_context.h +++ b/webkit/fileapi/file_system_context.h @@ -16,6 +16,11 @@ namespace base { class MessageLoopProxy; } +namespace quota { +class QuotaClient; +class QuotaManagerProxy; +} + namespace fileapi { class FileSystemContext; @@ -34,6 +39,7 @@ class FileSystemContext scoped_refptr<base::MessageLoopProxy> file_message_loop, scoped_refptr<base::MessageLoopProxy> io_message_loop, scoped_refptr<quota::SpecialStoragePolicy> special_storage_policy, + quota::QuotaManagerProxy* quota_manager_proxy, const FilePath& profile_path, bool is_incognito, bool allow_file_access_from_files, @@ -46,8 +52,10 @@ class FileSystemContext void DeleteDataForOriginOnFileThread(const GURL& origin_url); - FileSystemPathManager* path_manager() { return path_manager_.get(); } - FileSystemUsageTracker* usage_tracker() { return usage_tracker_.get(); } + FileSystemPathManager* path_manager() const { return path_manager_.get(); } + quota::QuotaManagerProxy* quota_manager_proxy() const { + return quota_manager_proxy_.get(); + } private: friend struct DefaultContextDeleter; @@ -58,11 +66,11 @@ class FileSystemContext scoped_refptr<base::MessageLoopProxy> io_message_loop_; scoped_refptr<quota::SpecialStoragePolicy> special_storage_policy_; + scoped_refptr<quota::QuotaManagerProxy> quota_manager_proxy_; const bool allow_file_access_from_files_; const bool unlimited_quota_; scoped_ptr<FileSystemPathManager> path_manager_; - scoped_ptr<FileSystemUsageTracker> usage_tracker_; DISALLOW_IMPLICIT_CONSTRUCTORS(FileSystemContext); }; diff --git a/webkit/fileapi/file_system_context_unittest.cc b/webkit/fileapi/file_system_context_unittest.cc index 30ec54e..025b7f3 100644 --- a/webkit/fileapi/file_system_context_unittest.cc +++ b/webkit/fileapi/file_system_context_unittest.cc @@ -12,6 +12,7 @@ #include "base/string_number_conversions.h" #include "googleurl/src/gurl.h" #include "testing/gtest/include/gtest/gtest.h" +#include "webkit/quota/quota_manager.h" using namespace fileapi; @@ -46,6 +47,7 @@ scoped_refptr<FileSystemContext> NewFileSystemContext( return new FileSystemContext(base::MessageLoopProxy::CreateForCurrentThread(), base::MessageLoopProxy::CreateForCurrentThread(), special_storage_policy, + NULL /* quota manager */, FilePath(), false /* is_incognito */, allow_file_access, unlimited_quota, NULL); } diff --git a/webkit/fileapi/file_system_dir_url_request_job_unittest.cc b/webkit/fileapi/file_system_dir_url_request_job_unittest.cc index 6b2882b..888121b 100644 --- a/webkit/fileapi/file_system_dir_url_request_job_unittest.cc +++ b/webkit/fileapi/file_system_dir_url_request_job_unittest.cc @@ -68,7 +68,7 @@ class FileSystemDirURLRequestJobTest : public testing::Test { new FileSystemContext( base::MessageLoopProxy::CreateForCurrentThread(), base::MessageLoopProxy::CreateForCurrentThread(), - special_storage_policy_, + special_storage_policy_, NULL, FilePath(), false /* is_incognito */, false, true, new FileSystemPathManager( diff --git a/webkit/fileapi/file_system_operation_write_unittest.cc b/webkit/fileapi/file_system_operation_write_unittest.cc index 2f996ab..053cc68 100644 --- a/webkit/fileapi/file_system_operation_write_unittest.cc +++ b/webkit/fileapi/file_system_operation_write_unittest.cc @@ -188,7 +188,7 @@ FileSystemOperation* FileSystemOperationWriteTest::operation() { base::MessageLoopProxy::CreateForCurrentThread(), new FileSystemContext(base::MessageLoopProxy::CreateForCurrentThread(), base::MessageLoopProxy::CreateForCurrentThread(), - NULL, FilePath(), false /* is_incognito */, + NULL, NULL, FilePath(), false /* is_incognito */, true, true, new MockFileSystemPathManager(filesystem_dir_)), LocalFileSystemFileUtil::GetInstance()); diff --git a/webkit/fileapi/file_system_url_request_job_unittest.cc b/webkit/fileapi/file_system_url_request_job_unittest.cc index 62e6d8f..c0e60a1 100644 --- a/webkit/fileapi/file_system_url_request_job_unittest.cc +++ b/webkit/fileapi/file_system_url_request_job_unittest.cc @@ -88,7 +88,7 @@ class FileSystemURLRequestJobTest : public testing::Test { new FileSystemContext( base::MessageLoopProxy::CreateForCurrentThread(), base::MessageLoopProxy::CreateForCurrentThread(), - special_storage_policy_, + special_storage_policy_, NULL, FilePath(), false /* is_incognito */, false, true, new FileSystemPathManager( diff --git a/webkit/fileapi/file_system_usage_tracker.cc b/webkit/fileapi/file_system_usage_tracker.cc deleted file mode 100644 index 687884f..0000000 --- a/webkit/fileapi/file_system_usage_tracker.cc +++ /dev/null @@ -1,183 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "webkit/fileapi/file_system_usage_tracker.h" - -#include <algorithm> - -#include "base/file_path.h" -#include "base/file_util.h" -#include "base/logging.h" -#include "base/memory/scoped_ptr.h" -#include "base/message_loop_proxy.h" -#include "base/task.h" -#include "googleurl/src/gurl.h" -#include "webkit/fileapi/file_system_path_manager.h" -#include "webkit/fileapi/file_system_usage_cache.h" -#include "webkit/fileapi/sandbox_mount_point_provider.h" - -namespace fileapi { - -class FileSystemUsageTracker::GetUsageTask - : public base::RefCountedThreadSafe<GetUsageTask> { - public: - GetUsageTask( - FileSystemUsageTracker* tracker, - scoped_refptr<base::MessageLoopProxy> file_message_loop, - std::string fs_identifier, - const FilePath& origin_base_path) - : tracker_(tracker), - file_message_loop_(file_message_loop), - original_message_loop_( - base::MessageLoopProxy::CreateForCurrentThread()), - fs_identifier_(fs_identifier), - fs_usage_(0), - origin_base_path_(origin_base_path) { - } - - virtual ~GetUsageTask() {} - - void Start() { - DCHECK(tracker_); - tracker_->RegisterUsageTask(this); - file_message_loop_->PostTask( - FROM_HERE, NewRunnableMethod(this, &GetUsageTask::RunOnFileThread)); - } - - void Cancel() { - DCHECK(original_message_loop_->BelongsToCurrentThread()); - tracker_ = NULL; - } - - private: - void RunOnFileThread() { - DCHECK(file_message_loop_->BelongsToCurrentThread()); - - if (!file_util::DirectoryExists(origin_base_path_)) - fs_usage_ = 0; - else { - FilePath usage_file_path = origin_base_path_.AppendASCII( - FileSystemUsageCache::kUsageFileName); - - if (FileSystemUsageCache::GetDirty(usage_file_path) != 0) { - FilePath content_file_path = origin_base_path_; - if (FileSystemUsageCache::Exists(usage_file_path)) - FileSystemUsageCache::Delete(usage_file_path); - fs_usage_ = file_util::ComputeDirectorySize(content_file_path); - // fs_usage_ will include the size of .usage. - // The result of ComputeDirectorySize does not include it. - fs_usage_ += FileSystemUsageCache::kUsageFileSize; - FileSystemUsageCache::UpdateUsage(usage_file_path, fs_usage_); - } else { - fs_usage_ = FileSystemUsageCache::GetUsage(usage_file_path); - } - } - - original_message_loop_->PostTask( - FROM_HERE, NewRunnableMethod(this, &GetUsageTask::Completed)); - } - - void Completed() { - DCHECK(original_message_loop_->BelongsToCurrentThread()); - if (tracker_) { - tracker_->UnregisterUsageTask(this); - tracker_->DidGetOriginUsage(fs_identifier_, fs_usage_); - } - } - - FileSystemUsageTracker* tracker_; - scoped_refptr<base::MessageLoopProxy> file_message_loop_; - scoped_refptr<base::MessageLoopProxy> original_message_loop_; - std::string fs_identifier_; - int64 fs_usage_; - FilePath origin_base_path_; -}; - -FileSystemUsageTracker::FileSystemUsageTracker( - scoped_refptr<base::MessageLoopProxy> file_message_loop, - const FilePath& profile_path, - bool is_incognito) - : file_message_loop_(file_message_loop), - base_path_(profile_path.Append( - SandboxMountPointProvider::kFileSystemDirectory)), - is_incognito_(is_incognito) { - DCHECK(file_message_loop); -} - -FileSystemUsageTracker::~FileSystemUsageTracker() { - std::for_each(running_usage_tasks_.begin(), - running_usage_tasks_.end(), - std::mem_fun(&GetUsageTask::Cancel)); -} - -void FileSystemUsageTracker::GetOriginUsage( - const GURL& origin_url, - fileapi::FileSystemType type, - GetUsageCallback* callback_ptr) { - DCHECK(callback_ptr); - scoped_ptr<GetUsageCallback> callback(callback_ptr); - - if (is_incognito_) { - // We don't support FileSystem in incognito mode yet. - callback->Run(0); - return; - } - - std::string origin_identifier = - SandboxMountPointProvider::GetOriginIdentifierFromURL(origin_url); - std::string type_string = - FileSystemPathManager::GetFileSystemTypeString(type); - std::string fs_identifier = origin_identifier + ":" + type_string; - - if (pending_usage_callbacks_.find(fs_identifier) != - pending_usage_callbacks_.end()) { - // Another get usage task is running. Add the callback to - // the pending queue and return. - pending_usage_callbacks_[fs_identifier].push_back(callback.release()); - return; - } - - // Get the filesystem base path (i.e. "FileSystem/<origin>/<type>", - // without unique part). - FilePath origin_base_path = - SandboxMountPointProvider::GetFileSystemBaseDirectoryForOriginAndType( - base_path_, origin_identifier, type); - if (origin_base_path.empty()) { - // The directory does not exist. - callback->Run(0); - return; - } - - pending_usage_callbacks_[fs_identifier].push_back(callback.release()); - scoped_refptr<GetUsageTask> task( - new GetUsageTask(this, file_message_loop_, fs_identifier, - origin_base_path)); - task->Start(); -} - -void FileSystemUsageTracker::RegisterUsageTask(GetUsageTask* task) { - running_usage_tasks_.push_back(task); -} - -void FileSystemUsageTracker::UnregisterUsageTask(GetUsageTask* task) { - DCHECK(running_usage_tasks_.front() == task); - running_usage_tasks_.pop_front(); -} - -void FileSystemUsageTracker::DidGetOriginUsage( - const std::string& fs_identifier, int64 usage) { - PendingUsageCallbackMap::iterator cb_list_iter = - pending_usage_callbacks_.find(fs_identifier); - DCHECK(cb_list_iter != pending_usage_callbacks_.end()); - PendingCallbackList cb_list = cb_list_iter->second; - for (PendingCallbackList::iterator cb_iter = cb_list.begin(); - cb_iter != cb_list.end(); - ++cb_iter) { - scoped_ptr<GetUsageCallback> callback(*cb_iter); - callback->Run(usage); - } - pending_usage_callbacks_.erase(cb_list_iter); -} - -} // namespace fileapi diff --git a/webkit/fileapi/file_system_usage_tracker.h b/webkit/fileapi/file_system_usage_tracker.h deleted file mode 100644 index 6328693..0000000 --- a/webkit/fileapi/file_system_usage_tracker.h +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef WEBKIT_FILEAPI_FILE_SYSTEM_USAGE_TRACKER_H_ -#define WEBKIT_FILEAPI_FILE_SYSTEM_USAGE_TRACKER_H_ - -#include <deque> -#include <list> -#include <map> -#include <string> - -#include "base/basictypes.h" -#include "base/callback.h" -#include "base/file_path.h" -#include "base/memory/ref_counted.h" -#include "webkit/fileapi/file_system_types.h" - -class GURL; - -namespace base { -class MessageLoopProxy; -} - -namespace fileapi { - -// Owned by the FileSystemContext, which is a per-profile instance, and has the -// same lifetime as the FileSystemContext. It's going to be created and -// destroyed on the IO thread in chrome. (The destruction on the same thread -// where it is created was guaranteed by its owner, FileSystemContext.) -class FileSystemUsageTracker { - public: - FileSystemUsageTracker( - scoped_refptr<base::MessageLoopProxy> file_message_loop, - const FilePath& profile_path, - bool is_incognito); - ~FileSystemUsageTracker(); - - // Get the amount of data stored in the filesystem specified by - // |origin_url| and |type|. - typedef Callback1<int64 /* usage */>::Type GetUsageCallback; - void GetOriginUsage(const GURL& origin_url, - fileapi::FileSystemType type, - GetUsageCallback* callback); - - private: - class GetUsageTask; - - void RegisterUsageTask(GetUsageTask* task); - void UnregisterUsageTask(GetUsageTask* task); - - void DidGetOriginUsage(const std::string& fs_name, int64 usage); - - scoped_refptr<base::MessageLoopProxy> file_message_loop_; - FilePath base_path_; - bool is_incognito_; - - typedef std::deque<GetUsageTask*> UsageTaskQueue; - UsageTaskQueue running_usage_tasks_; - - typedef std::list<GetUsageCallback*> PendingCallbackList; - typedef std::map<std::string, PendingCallbackList> PendingUsageCallbackMap; - PendingUsageCallbackMap pending_usage_callbacks_; - - DISALLOW_COPY_AND_ASSIGN(FileSystemUsageTracker); -}; - -} // namespace fileapi - -#endif // WEBKIT_FILEAPI_FILE_SYSTEM_USAGE_TRACKER_H_ diff --git a/webkit/fileapi/file_system_usage_tracker_unittest.cc b/webkit/fileapi/file_system_usage_tracker_unittest.cc deleted file mode 100644 index e198363..0000000 --- a/webkit/fileapi/file_system_usage_tracker_unittest.cc +++ /dev/null @@ -1,279 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "webkit/fileapi/file_system_usage_tracker.h" - -#include "base/basictypes.h" -#include "base/file_util.h" -#include "base/memory/scoped_callback_factory.h" -#include "base/memory/scoped_temp_dir.h" -#include "base/message_loop.h" -#include "base/message_loop_proxy.h" -#include "base/platform_file.h" -#include "googleurl/src/gurl.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "webkit/fileapi/file_system_types.h" -#include "webkit/fileapi/file_system_usage_cache.h" -#include "webkit/fileapi/sandbox_mount_point_provider.h" - -using namespace fileapi; - -namespace { - -static const GURL kDummyURL1("http://www.dummy.org"); -static const GURL kDummyURL2("http://www.example.com"); - -// Declared to shorten the variable names. -static const fileapi::FileSystemType kTemporary = - fileapi::kFileSystemTypeTemporary; -static const fileapi::FileSystemType kPersistent = - fileapi::kFileSystemTypePersistent; -static const int kUsageFileSize = FileSystemUsageCache::kUsageFileSize; - -} - -class FileSystemUsageTrackerTest : public testing::Test { - public: - FileSystemUsageTrackerTest() - : callback_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) { - } - - void SetUp() { - ASSERT_TRUE(data_dir_.CreateUniqueTempDir()); - } - - struct TestFile { - bool isDirectory; - const char* name; - int64 size; - GURL origin_url; - fileapi::FileSystemType type; - }; - - protected: - FileSystemUsageTracker* NewUsageTracker(bool is_incognito) { - return new FileSystemUsageTracker( - base::MessageLoopProxy::CreateForCurrentThread(), - data_dir_.path(), is_incognito); - } - - int64 GetOriginUsage(FileSystemUsageTracker* tracker, - const GURL& origin_url, - fileapi::FileSystemType type) { - tracker->GetOriginUsage(origin_url, type, - callback_factory_.NewCallback( - &FileSystemUsageTrackerTest::OnGetUsage)); - MessageLoop::current()->RunAllPending(); - return usage_; - } - - FilePath GetOriginBasePath(const GURL& origin_url, - fileapi::FileSystemType type) { - return - SandboxMountPointProvider::GetFileSystemBaseDirectoryForOriginAndType( - data_dir_.path().Append( - SandboxMountPointProvider::kFileSystemDirectory), - SandboxMountPointProvider::GetOriginIdentifierFromURL(origin_url), - type); - } - - bool CreateFileSystemDirectory(const char* dir_name, - const GURL& origin_url, - fileapi::FileSystemType type) { - FilePath origin_base_path = GetOriginBasePath(origin_url, type); - FilePath dir_path; - if (dir_name != NULL) - dir_path = origin_base_path.AppendASCII(dir_name); - else - dir_path = origin_base_path; - if (dir_path.empty()) - return false; - - return file_util::CreateDirectory(dir_path); - } - - bool CreateFileSystemFile(const char* file_name, - int64 file_size, - const GURL& origin_url, - fileapi::FileSystemType type) { - FilePath origin_base_path = GetOriginBasePath(origin_url, type); - FilePath file_path = origin_base_path.AppendASCII(file_name); - - if (file_path.empty()) - return false; - - int file_flags = base::PLATFORM_FILE_CREATE_ALWAYS | - base::PLATFORM_FILE_WRITE; - base::PlatformFileError error_code; - base::PlatformFile file = - base::CreatePlatformFile(file_path, file_flags, NULL, &error_code); - if (error_code != base::PLATFORM_FILE_OK) - return false; - - bool succeeded; - succeeded = base::TruncatePlatformFile(file, file_size); - succeeded = succeeded && base::ClosePlatformFile(file); - return succeeded; - } - - void CreateFiles(const TestFile* files, int num_files) { - for (int i = 0; i < num_files; i++) { - if (files[i].isDirectory) { - ASSERT_TRUE(CreateFileSystemDirectory( - files[i].name, files[i].origin_url, files[i].type)); - } else { - ASSERT_TRUE(CreateFileSystemFile( - files[i].name, files[i].size, files[i].origin_url, files[i].type)); - } - } - } - - private: - void OnGetUsage(int64 usage) { - usage_ = usage; - } - - ScopedTempDir data_dir_; - base::ScopedCallbackFactory<FileSystemUsageTrackerTest> callback_factory_; - int64 usage_; - - DISALLOW_COPY_AND_ASSIGN(FileSystemUsageTrackerTest); -}; - -TEST_F(FileSystemUsageTrackerTest, NoFileSystemTest) { - scoped_ptr<FileSystemUsageTracker> tracker(NewUsageTracker(false)); - - EXPECT_EQ(0, - GetOriginUsage(tracker.get(), kDummyURL1, kTemporary)); -} - -TEST_F(FileSystemUsageTrackerTest, NoFileTest) { - scoped_ptr<FileSystemUsageTracker> tracker(NewUsageTracker(false)); - TestFile files[] = { - {true, NULL, 0, kDummyURL1, kTemporary}, - }; - CreateFiles(files, ARRAYSIZE_UNSAFE(files)); - - for (int i = 0; i < 2; i++) { - EXPECT_EQ(kUsageFileSize, - GetOriginUsage(tracker.get(), kDummyURL1, kTemporary)); - } -} - -TEST_F(FileSystemUsageTrackerTest, OneFileTest) { - scoped_ptr<FileSystemUsageTracker> tracker(NewUsageTracker(false)); - TestFile files[] = { - {true, NULL, 0, kDummyURL1, kTemporary}, - {false, "foo", 4921, kDummyURL1, kTemporary}, - }; - CreateFiles(files, ARRAYSIZE_UNSAFE(files)); - - for (int i = 0; i < 2; i++) { - EXPECT_EQ(4921 + kUsageFileSize, - GetOriginUsage(tracker.get(), kDummyURL1, kTemporary)); - } -} - -TEST_F(FileSystemUsageTrackerTest, TwoFilesTest) { - scoped_ptr<FileSystemUsageTracker> tracker(NewUsageTracker(false)); - TestFile files[] = { - {true, NULL, 0, kDummyURL1, kTemporary}, - {false, "foo", 10310, kDummyURL1, kTemporary}, - {false, "bar", 41, kDummyURL1, kTemporary}, - }; - CreateFiles(files, ARRAYSIZE_UNSAFE(files)); - - for (int i = 0; i < 2; i++) { - EXPECT_EQ(10310 + 41 + kUsageFileSize, - GetOriginUsage(tracker.get(), kDummyURL1, kTemporary)); - } -} - -TEST_F(FileSystemUsageTrackerTest, EmptyFilesTest) { - scoped_ptr<FileSystemUsageTracker> tracker(NewUsageTracker(false)); - TestFile files[] = { - {true, NULL, 0, kDummyURL1, kTemporary}, - {false, "foo", 0, kDummyURL1, kTemporary}, - {false, "bar", 0, kDummyURL1, kTemporary}, - {false, "baz", 0, kDummyURL1, kTemporary}, - }; - CreateFiles(files, ARRAYSIZE_UNSAFE(files)); - - for (int i = 0; i < 2; i++) { - EXPECT_EQ(kUsageFileSize, - GetOriginUsage(tracker.get(), kDummyURL1, kTemporary)); - } -} - -TEST_F(FileSystemUsageTrackerTest, SubDirectoryTest) { - scoped_ptr<FileSystemUsageTracker> tracker(NewUsageTracker(false)); - TestFile files[] = { - {true, NULL, 0, kDummyURL1, kTemporary}, - {true, "dirtest", 0, kDummyURL1, kTemporary}, - {false, "dirtest/foo", 11921, kDummyURL1, kTemporary}, - {false, "bar", 4814, kDummyURL1, kTemporary}, - }; - CreateFiles(files, ARRAYSIZE_UNSAFE(files)); - - for (int i = 0; i < 2; i++) { - EXPECT_EQ(11921 + 4814 + kUsageFileSize, - GetOriginUsage(tracker.get(), kDummyURL1, kTemporary)); - } -} - -TEST_F(FileSystemUsageTrackerTest, MultiTypeTest) { - scoped_ptr<FileSystemUsageTracker> tracker(NewUsageTracker(false)); - TestFile files[] = { - {true, NULL, 0, kDummyURL1, kTemporary}, - {true, "dirtest", 0, kDummyURL1, kTemporary}, - {false, "dirtest/foo", 133, kDummyURL1, kTemporary}, - {false, "bar", 14, kDummyURL1, kTemporary}, - {true, NULL, 0, kDummyURL1, kPersistent}, - {true, "dirtest", 0, kDummyURL1, kPersistent}, - {false, "dirtest/foo", 193, kDummyURL1, kPersistent}, - {false, "bar", 9, kDummyURL1, kPersistent}, - }; - CreateFiles(files, ARRAYSIZE_UNSAFE(files)); - - for (int i = 0; i < 2; i++) { - EXPECT_EQ(133 + 14 + kUsageFileSize, - GetOriginUsage(tracker.get(), kDummyURL1, kTemporary)); - EXPECT_EQ(193 + 9 + kUsageFileSize, - GetOriginUsage(tracker.get(), kDummyURL1, kPersistent)); - } -} - -TEST_F(FileSystemUsageTrackerTest, MultiDomainTest) { - scoped_ptr<FileSystemUsageTracker> tracker(NewUsageTracker(false)); - TestFile files[] = { - {true, NULL, 0, kDummyURL1, kTemporary}, - {true, "dir1", 0, kDummyURL1, kTemporary}, - {false, "dir1/foo", 1331, kDummyURL1, kTemporary}, - {false, "bar", 134, kDummyURL1, kTemporary}, - {true, NULL, 0, kDummyURL1, kPersistent}, - {true, "dir2", 0, kDummyURL1, kPersistent}, - {false, "dir2/foo", 1903, kDummyURL1, kPersistent}, - {false, "bar", 19, kDummyURL1, kPersistent}, - {true, NULL, 0, kDummyURL2, kTemporary}, - {true, "dom", 0, kDummyURL2, kTemporary}, - {false, "dom/fan", 1319, kDummyURL2, kTemporary}, - {false, "bar", 113, kDummyURL2, kTemporary}, - {true, NULL, 0, kDummyURL2, kPersistent}, - {true, "dom", 0, kDummyURL2, kPersistent}, - {false, "dom/fan", 2013, kDummyURL2, kPersistent}, - {false, "baz", 18, kDummyURL2, kPersistent}, - }; - CreateFiles(files, ARRAYSIZE_UNSAFE(files)); - - for (int i = 0; i < 2; i++) { - EXPECT_EQ(1331 + 134 + kUsageFileSize, - GetOriginUsage(tracker.get(), kDummyURL1, kTemporary)); - EXPECT_EQ(1903 + 19 + kUsageFileSize, - GetOriginUsage(tracker.get(), kDummyURL1, kPersistent)); - EXPECT_EQ(1319 + 113 + kUsageFileSize, - GetOriginUsage(tracker.get(), kDummyURL2, kTemporary)); - EXPECT_EQ(2013 + 18 + kUsageFileSize, - GetOriginUsage(tracker.get(), kDummyURL2, kPersistent)); - } -} diff --git a/webkit/fileapi/file_system_util.cc b/webkit/fileapi/file_system_util.cc index f3e6278..5aa3cf2 100644 --- a/webkit/fileapi/file_system_util.cc +++ b/webkit/fileapi/file_system_util.cc @@ -128,4 +128,27 @@ GURL GetFileSystemRootURI( return GURL(path); } +FileSystemType QuotaStorageTypeToFileSystemType( + quota::StorageType storage_type) { + switch (storage_type) { + case quota::kStorageTypeTemporary: + return kFileSystemTypeTemporary; + case quota::kStorageTypePersistent: + return kFileSystemTypePersistent; + default: + return kFileSystemTypeUnknown; + } +} + +quota::StorageType FileSystemTypeToQuotaStorageType(FileSystemType type) { + switch (type) { + case kFileSystemTypeTemporary: + return quota::kStorageTypeTemporary; + case kFileSystemTypePersistent: + return quota::kStorageTypePersistent; + default: + return quota::kStorageTypeUnknown; + } +} + } // namespace fileapi diff --git a/webkit/fileapi/file_system_util.h b/webkit/fileapi/file_system_util.h index 272e432..6f3bdca 100644 --- a/webkit/fileapi/file_system_util.h +++ b/webkit/fileapi/file_system_util.h @@ -7,6 +7,7 @@ #pragma once #include "webkit/fileapi/file_system_types.h" +#include "webkit/quota/quota_types.h" class FilePath; class GURL; @@ -27,6 +28,11 @@ bool CrackFileSystemURL(const GURL& url, GURL* origin_url, FileSystemType* type, GURL GetFileSystemRootURI(const GURL& origin_url, fileapi::FileSystemType type); +FileSystemType QuotaStorageTypeToFileSystemType( + quota::StorageType storage_type); + +quota::StorageType FileSystemTypeToQuotaStorageType(FileSystemType type); + } // namespace fileapi #endif // WEBKIT_FILEAPI_FILE_SYSTEM_UTIL_H_ diff --git a/webkit/fileapi/file_writer_delegate_unittest.cc b/webkit/fileapi/file_writer_delegate_unittest.cc index c25a69f..d56c7ae 100644 --- a/webkit/fileapi/file_writer_delegate_unittest.cc +++ b/webkit/fileapi/file_writer_delegate_unittest.cc @@ -208,7 +208,7 @@ void FileWriterDelegateTest::SetUp() { context_.reset(new FileSystemOperationContext( new FileSystemContext(base::MessageLoopProxy::CreateForCurrentThread(), base::MessageLoopProxy::CreateForCurrentThread(), - NULL, FilePath(), false /* is_incognito */, + NULL, NULL, FilePath(), false /* is_incognito */, true, true, new MockFileSystemPathManager(filesystem_dir_)), NULL)); @@ -345,7 +345,7 @@ TEST_F(FileWriterDelegateTest, WriteSuccessWithoutQuotaLimitConcurrent) { context2.reset(new FileSystemOperationContext( new FileSystemContext(base::MessageLoopProxy::CreateForCurrentThread(), base::MessageLoopProxy::CreateForCurrentThread(), - NULL, FilePath(), false /* is_incognito */, + NULL, NULL, FilePath(), false /* is_incognito */, true, true, new MockFileSystemPathManager(filesystem_dir_)), NULL)); diff --git a/webkit/fileapi/local_file_system_file_util_unittest.cc b/webkit/fileapi/local_file_system_file_util_unittest.cc index c60d6c8..26ba04d 100644 --- a/webkit/fileapi/local_file_system_file_util_unittest.cc +++ b/webkit/fileapi/local_file_system_file_util_unittest.cc @@ -74,7 +74,7 @@ class LocalFileSystemFileUtilTest : public testing::Test { return new FileSystemOperationContext( new FileSystemContext(base::MessageLoopProxy::CreateForCurrentThread(), base::MessageLoopProxy::CreateForCurrentThread(), - NULL, FilePath(), false /* is_incognito */, + NULL, NULL, FilePath(), false /* is_incognito */, true, true, new MockFileSystemPathManager(filesystem_dir_)), FileUtil()); diff --git a/webkit/fileapi/quota_file_util_unittest.cc b/webkit/fileapi/quota_file_util_unittest.cc index b01a178..bb76f65 100644 --- a/webkit/fileapi/quota_file_util_unittest.cc +++ b/webkit/fileapi/quota_file_util_unittest.cc @@ -62,7 +62,7 @@ class QuotaFileUtilTest : public testing::Test { FileSystemOperationContext *context = new FileSystemOperationContext( new FileSystemContext(base::MessageLoopProxy::CreateForCurrentThread(), base::MessageLoopProxy::CreateForCurrentThread(), - NULL, FilePath(), false, + NULL, NULL, FilePath(), false, true, true, new MockFileSystemPathManager(filesystem_dir_)), QuotaFileUtil::GetInstance()); diff --git a/webkit/fileapi/sandbox_mount_point_provider.cc b/webkit/fileapi/sandbox_mount_point_provider.cc index 51954ce..ad46f3b 100644 --- a/webkit/fileapi/sandbox_mount_point_provider.cc +++ b/webkit/fileapi/sandbox_mount_point_provider.cc @@ -19,6 +19,7 @@ #include "third_party/WebKit/Source/WebKit/chromium/public/WebString.h" #include "webkit/fileapi/file_system_path_manager.h" #include "webkit/fileapi/file_system_util.h" +#include "webkit/fileapi/sandbox_mount_point_provider.h" #include "webkit/glue/webkit_glue.h" namespace { @@ -51,6 +52,28 @@ inline std::string FilePathStringToASCII( #endif } +// TODO(kinuko): Merge these two methods (conversion methods between +// origin url <==> identifier) with the ones in the database module. +std::string GetOriginIdentifierFromURL(const GURL& url) { + WebKit::WebSecurityOrigin web_security_origin = + WebKit::WebSecurityOrigin::createFromString(UTF8ToUTF16(url.spec())); + return web_security_origin.databaseIdentifier().utf8(); +} + +GURL GetOriginURLFromIdentifier(const std::string& origin_identifier) { + WebKit::WebSecurityOrigin web_security_origin = + WebKit::WebSecurityOrigin::createFromDatabaseIdentifier( + UTF8ToUTF16(origin_identifier)); + GURL origin_url(web_security_origin.toString()); + + // We need this work-around for file:/// URIs as + // createFromDatabaseIdentifier returns empty origin_url for them. + if (origin_url.spec().empty() && + origin_identifier.find("file__") == 0) + return GURL("file:///"); + return origin_url; +} + FilePath::StringType CreateUniqueDirectoryName(const GURL& origin_url) { // This can be anything but need to be unpredictable. static const FilePath::CharType letters[] = FILE_PATH_LITERAL( @@ -104,6 +127,36 @@ FilePath GetFileSystemRootPathOnFileThreadHelper( return root; } +class SandboxOriginEnumerator + : public fileapi::SandboxMountPointProvider::OriginEnumerator { + public: + explicit SandboxOriginEnumerator(const FilePath& base_path) + : enumerator_(base_path, false /* recursive */, + file_util::FileEnumerator::DIRECTORIES) {} + virtual ~SandboxOriginEnumerator() {} + + virtual GURL Next() OVERRIDE { + current_ = enumerator_.Next(); + if (current_.empty()) + return GURL(); + return GetOriginURLFromIdentifier( + FilePathStringToASCII(current_.BaseName().value())); + } + + virtual bool HasFileSystemType(fileapi::FileSystemType type) const OVERRIDE { + if (current_.empty()) + return false; + std::string directory = + fileapi::FileSystemPathManager::GetFileSystemTypeString(type); + DCHECK(!directory.empty()); + return file_util::DirectoryExists(current_.AppendASCII(directory)); + } + + private: + file_util::FileEnumerator enumerator_; + FilePath current_; +}; + } // anonymous namespace namespace fileapi { @@ -220,6 +273,11 @@ std::vector<FilePath> SandboxMountPointProvider::GetRootDirectories() const { return std::vector<FilePath>(); } +SandboxMountPointProvider::OriginEnumerator* +SandboxMountPointProvider::CreateOriginEnumerator() const { + return new SandboxOriginEnumerator(base_path_); +} + void SandboxMountPointProvider::ValidateFileSystemRootAndGetURL( const GURL& origin_url, fileapi::FileSystemType type, bool create, FileSystemPathManager::GetRootPathCallback* callback_ptr) { @@ -251,49 +309,20 @@ SandboxMountPointProvider::ValidateFileSystemRootAndGetPathOnFileThread( origin_url, origin_base_path, create); } -// static -std::string SandboxMountPointProvider::GetOriginIdentifierFromURL( - const GURL& url) { - WebKit::WebSecurityOrigin web_security_origin = - WebKit::WebSecurityOrigin::createFromString(UTF8ToUTF16(url.spec())); - return web_security_origin.databaseIdentifier().utf8(); +FilePath SandboxMountPointProvider::GetBaseDirectoryForOrigin( + const GURL& origin_url) const { + return base_path_.AppendASCII(GetOriginIdentifierFromURL(origin_url)); } -// static -FilePath SandboxMountPointProvider::GetFileSystemBaseDirectoryForOriginAndType( - const FilePath& base_path, const std::string& origin_identifier, - fileapi::FileSystemType type) { - if (origin_identifier.empty()) - return FilePath(); +FilePath SandboxMountPointProvider::GetBaseDirectoryForOriginAndType( + const GURL& origin_url, fileapi::FileSystemType type) const { std::string type_string = FileSystemPathManager::GetFileSystemTypeString(type); if (type_string.empty()) { LOG(WARNING) << "Unknown filesystem type is requested:" << type; return FilePath(); } - return base_path.AppendASCII(origin_identifier) - .AppendASCII(type_string); -} - -SandboxMountPointProvider::OriginEnumerator::OriginEnumerator( - const FilePath& base_path) - : enumerator_(base_path, false /* recursive */, - file_util::FileEnumerator::DIRECTORIES) { -} - -std::string SandboxMountPointProvider::OriginEnumerator::Next() { - current_ = enumerator_.Next(); - return FilePathStringToASCII(current_.BaseName().value()); -} - -bool SandboxMountPointProvider::OriginEnumerator::HasTemporary() { - return !current_.empty() && file_util::DirectoryExists(current_.AppendASCII( - fileapi::kTemporaryName)); -} - -bool SandboxMountPointProvider::OriginEnumerator::HasPersistent() { - return !current_.empty() && file_util::DirectoryExists(current_.AppendASCII( - fileapi::kPersistentName)); + return GetBaseDirectoryForOrigin(origin_url).AppendASCII(type_string); } bool SandboxMountPointProvider::GetOriginBasePathAndName( @@ -309,12 +338,11 @@ bool SandboxMountPointProvider::GetOriginBasePathAndName( if (!path_manager_->IsAllowedScheme(origin_url)) return false; - std::string origin_identifier = GetOriginIdentifierFromURL(origin_url); - *origin_base_path = GetFileSystemBaseDirectoryForOriginAndType( - base_path(), origin_identifier, type); + *origin_base_path = GetBaseDirectoryForOriginAndType(origin_url, type); if (origin_base_path->empty()) return false; + std::string origin_identifier = GetOriginIdentifierFromURL(origin_url); std::string type_string = FileSystemPathManager::GetFileSystemTypeString(type); DCHECK(!type_string.empty()); diff --git a/webkit/fileapi/sandbox_mount_point_provider.h b/webkit/fileapi/sandbox_mount_point_provider.h index 6f8cff8..748ced8 100644 --- a/webkit/fileapi/sandbox_mount_point_provider.h +++ b/webkit/fileapi/sandbox_mount_point_provider.h @@ -12,8 +12,6 @@ #include "googleurl/src/gurl.h" #include "webkit/fileapi/file_system_mount_point_provider.h" -class GURL; - namespace base { class MessageLoopProxy; } @@ -22,6 +20,18 @@ namespace fileapi { class SandboxMountPointProvider : public FileSystemMountPointProvider { public: + // Origin enumerator interface. + // An instance of this interface is assumed to be called on the file thread. + class OriginEnumerator { + public: + virtual ~OriginEnumerator() {} + + // Returns the next origin. Returns empty if there are no more origins. + virtual GURL Next() = 0; + + // Returns the current origin's information. + virtual bool HasFileSystemType(FileSystemType type) const = 0; + }; SandboxMountPointProvider( FileSystemPathManager* path_manager, @@ -63,40 +73,26 @@ class SandboxMountPointProvider : public FileSystemMountPointProvider { virtual std::vector<FilePath> GetRootDirectories() const; - // Returns the origin identifier string, which is used as a part of the - // sandboxed path component, for the given |url|. - static std::string GetOriginIdentifierFromURL(const GURL& url); + // Returns an origin enumerator of this provider. + // This method is supposed to be called on the file thread. + OriginEnumerator* CreateOriginEnumerator() const; // Gets a base directory path of the sandboxed filesystem that is - // specified by |origin_identifier| and |type|. - // |base_path| must be pointing the FileSystem's data directory - // under the profile directory, i.e. <profile_dir>/kFileSystemDirectory. - // Returns an empty path if any of the given parameters are invalid. - // Returned directory path does not contain 'unique' part, therefore - // it is not an actual root path for the filesystem. - static FilePath GetFileSystemBaseDirectoryForOriginAndType( - const FilePath& base_path, - const std::string& origin_identifier, - fileapi::FileSystemType type); - - // Enumerates origins under the given |base_path|. - // This must be used on the FILE thread. - class OriginEnumerator { - public: - explicit OriginEnumerator(const FilePath& base_path); - - // Returns the next origin identifier. Returns empty if there are no - // more origins. - std::string Next(); + // specified by |origin_url|. + // (The path is similar to the origin's root path but doesn't contain + // the 'unique' and 'type' part.) + // This method is portable and can be called on any threads. + FilePath GetBaseDirectoryForOrigin(const GURL& origin_url) const; - bool HasTemporary(); - bool HasPersistent(); - const FilePath& path() { return current_; } - - private: - file_util::FileEnumerator enumerator_; - FilePath current_; - }; + // Gets a base directory path of the sandboxed filesystem that is + // specified by |origin_url| and |type|. + // (The path is similar to the origin's root path but doesn't contain + // the 'unique' part.) + // Returns an empty path if the given type is invalid. + // This method is portable and can be called on any threads. + FilePath GetBaseDirectoryForOriginAndType( + const GURL& origin_url, + fileapi::FileSystemType type) const; private: bool GetOriginBasePathAndName( @@ -121,4 +117,3 @@ class SandboxMountPointProvider : public FileSystemMountPointProvider { } // namespace fileapi #endif // WEBKIT_FILEAPI_SANDBOX_MOUNT_POINT_PROVIDER_H_ - diff --git a/webkit/fileapi/sandbox_mount_point_provider_unittest.cc b/webkit/fileapi/sandbox_mount_point_provider_unittest.cc index 767f0ef..54f6865 100644 --- a/webkit/fileapi/sandbox_mount_point_provider_unittest.cc +++ b/webkit/fileapi/sandbox_mount_point_provider_unittest.cc @@ -22,12 +22,20 @@ using namespace fileapi; +class MockFileSystemPathManager : public FileSystemPathManager { + public: + MockFileSystemPathManager(const FilePath& filesystem_path) + : FileSystemPathManager(base::MessageLoopProxy::CreateForCurrentThread(), + filesystem_path, NULL, false, true) {} +}; + class SandboxMountPointProviderOriginEnumeratorTest : public testing::Test { public: void SetUp() { ASSERT_TRUE(data_dir_.CreateUniqueTempDir()); - enumerator_.reset(new SandboxMountPointProvider::OriginEnumerator( - data_dir_.path())); + path_manager_.reset(new MockFileSystemPathManager(data_dir_.path())); + enumerator_.reset( + path_manager_->sandbox_provider()->CreateOriginEnumerator()); } SandboxMountPointProvider::OriginEnumerator* enumerator() const { @@ -35,61 +43,60 @@ class SandboxMountPointProviderOriginEnumeratorTest : public testing::Test { } protected: - void CreateOriginTypeDirectory(const std::string& origin_identifier, + void CreateOriginTypeDirectory(const GURL& origin, fileapi::FileSystemType type) { - std::string type_string = - FileSystemPathManager::GetFileSystemTypeString(type); - ASSERT_TRUE(!type_string.empty()); - FilePath target = data_dir_.path().AppendASCII(origin_identifier) - .AppendASCII(type_string); + FilePath target = path_manager_->sandbox_provider()-> + GetBaseDirectoryForOriginAndType(origin, type); file_util::CreateDirectory(target); ASSERT_TRUE(file_util::DirectoryExists(target)); } ScopedTempDir data_dir_; + scoped_ptr<FileSystemPathManager> path_manager_; scoped_ptr<SandboxMountPointProvider::OriginEnumerator> enumerator_; }; TEST_F(SandboxMountPointProviderOriginEnumeratorTest, Empty) { - ASSERT_TRUE(enumerator()->Next().empty()); + ASSERT_TRUE(enumerator()->Next().is_empty()); } TEST_F(SandboxMountPointProviderOriginEnumeratorTest, EnumerateOrigins) { const char* temporary_origins[] = { - "http_www.bar.com_0", - "http_www.foo.com_0", - "http_www.foo.com_80", - "http_www.example.com_8080", - "http_www.google.com_80", + "http://www.bar.com/", + "http://www.foo.com/", + "http://www.foo.com:1/", + "http://www.example.com:8080/", + "http://www.google.com:80/", }; const char* persistent_origins[] = { - "http_www.bar.com_0", - "http_www.foo.com_8080", - "http_www.foo.com_80", + "http://www.bar.com/", + "http://www.foo.com:8080/", + "http://www.foo.com:80/", }; size_t temporary_size = ARRAYSIZE_UNSAFE(temporary_origins); size_t persistent_size = ARRAYSIZE_UNSAFE(persistent_origins); - std::set<std::string> temporary_set, persistent_set; + std::set<GURL> temporary_set, persistent_set; for (size_t i = 0; i < temporary_size; ++i) { - CreateOriginTypeDirectory(temporary_origins[i], + CreateOriginTypeDirectory(GURL(temporary_origins[i]), fileapi::kFileSystemTypeTemporary); - temporary_set.insert(temporary_origins[i]); + temporary_set.insert(GURL(temporary_origins[i])); } for (size_t i = 0; i < persistent_size; ++i) { - CreateOriginTypeDirectory(persistent_origins[i], kFileSystemTypePersistent); - persistent_set.insert(persistent_origins[i]); + CreateOriginTypeDirectory(GURL(persistent_origins[i]), + kFileSystemTypePersistent); + persistent_set.insert(GURL(persistent_origins[i])); } size_t temporary_actual_size = 0; size_t persistent_actual_size = 0; - std::string current; - while (!(current = enumerator()->Next()).empty()) { - SCOPED_TRACE(testing::Message() << "EnumerateOrigin " << current); - if (enumerator()->HasTemporary()) { + GURL current; + while (!(current = enumerator()->Next()).is_empty()) { + SCOPED_TRACE(testing::Message() << "EnumerateOrigin " << current.spec()); + if (enumerator()->HasFileSystemType(kFileSystemTypeTemporary)) { ASSERT_TRUE(temporary_set.find(current) != temporary_set.end()); ++temporary_actual_size; } - if (enumerator()->HasPersistent()) { + if (enumerator()->HasFileSystemType(kFileSystemTypePersistent)) { ASSERT_TRUE(persistent_set.find(current) != persistent_set.end()); ++persistent_actual_size; } diff --git a/webkit/fileapi/sandbox_quota_client.cc b/webkit/fileapi/sandbox_quota_client.cc new file mode 100644 index 0000000..b35e7ba --- /dev/null +++ b/webkit/fileapi/sandbox_quota_client.cc @@ -0,0 +1,292 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "webkit/fileapi/sandbox_quota_client.h" + +#include <algorithm> +#include <set> + +#include "base/file_path.h" +#include "base/file_util.h" +#include "base/logging.h" +#include "base/memory/scoped_ptr.h" +#include "base/message_loop_proxy.h" +#include "base/task.h" +#include "googleurl/src/gurl.h" +#include "net/base/net_util.h" +#include "webkit/fileapi/file_system_context.h" +#include "webkit/fileapi/file_system_path_manager.h" +#include "webkit/fileapi/file_system_usage_cache.h" +#include "webkit/fileapi/file_system_util.h" +#include "webkit/fileapi/sandbox_mount_point_provider.h" + +using namespace std; + +using base::MessageLoopProxy; +using quota::QuotaThreadTask; +using quota::StorageType; + +namespace fileapi { + +class SandboxQuotaClient::GetOriginUsageTask : public QuotaThreadTask { + public: + GetOriginUsageTask( + SandboxQuotaClient* quota_client, + scoped_refptr<MessageLoopProxy> file_message_loop, + const GURL& origin_url, + FileSystemType type) + : QuotaThreadTask(quota_client, file_message_loop), + quota_client_(quota_client), + origin_url_(origin_url), + type_(type), + fs_usage_(0) { + DCHECK(quota_client_); + file_system_context_ = quota_client_->file_system_context_; + visited_ = (quota_client_->visited_origins_.find(origin_url) != + quota_client_->visited_origins_.end()); + } + + virtual ~GetOriginUsageTask() {} + + protected: + virtual void RunOnTargetThread() OVERRIDE { + FilePath base_path = + file_system_context_->path_manager()->sandbox_provider()-> + GetBaseDirectoryForOriginAndType(origin_url_, type_); + if (!file_util::DirectoryExists(base_path)) { + fs_usage_ = 0; + } else { + FilePath usage_file_path = base_path.AppendASCII( + FileSystemUsageCache::kUsageFileName); + int32 dirty_status = FileSystemUsageCache::GetDirty(usage_file_path); + if (dirty_status == 0 || (dirty_status > 0 && visited_)) { + // The usage cache is clean (dirty == 0) or the origin has already + // initialized and running. Read the cache file to get the usage. + fs_usage_ = FileSystemUsageCache::GetUsage(usage_file_path); + } else { + // The usage cache has not been initialized or the cache is dirty. + // Get the directory size now and update the cache. + if (FileSystemUsageCache::Exists(usage_file_path)) + FileSystemUsageCache::Delete(usage_file_path); + int64 usage = file_util::ComputeDirectorySize(base_path); + // The result of ComputeDirectorySize does not include .usage file size. + usage += FileSystemUsageCache::kUsageFileSize; + // This clears the dirty flag too. + FileSystemUsageCache::UpdateUsage(usage_file_path, usage); + fs_usage_ = usage; + } + } + } + + virtual void Completed() OVERRIDE { + quota_client_->DidGetOriginUsage(type_, origin_url_, fs_usage_); + } + + SandboxQuotaClient* quota_client_; + scoped_refptr<FileSystemContext> file_system_context_; + GURL origin_url_; + FileSystemType type_; + int64 fs_usage_; + bool visited_; +}; + +class SandboxQuotaClient::GetOriginsTaskBase : public QuotaThreadTask { + public: + GetOriginsTaskBase( + SandboxQuotaClient* quota_client, + scoped_refptr<MessageLoopProxy> file_message_loop, + FileSystemType type) + : QuotaThreadTask(quota_client, file_message_loop), + quota_client_(quota_client), + type_(type) { + DCHECK(quota_client_); + file_system_context_ = quota_client_->file_system_context_; + } + virtual ~GetOriginsTaskBase() {} + + protected: + virtual bool ShouldAddThisOrigin(const GURL& origin) const = 0; + + virtual void RunOnTargetThread() OVERRIDE { + scoped_ptr<SandboxMountPointProvider::OriginEnumerator> enumerator( + sandbox_provider()->CreateOriginEnumerator()); + GURL origin; + while (!(origin = enumerator->Next()).is_empty()) { + if (ShouldAddThisOrigin(origin) && enumerator->HasFileSystemType(type_)) + origins_.insert(origin); + } + } + + SandboxQuotaClient* quota_client() const { return quota_client_; } + const std::set<GURL>& origins() const { return origins_; } + FileSystemType type() const { return type_; } + SandboxMountPointProvider* sandbox_provider() const { + return file_system_context_->path_manager()->sandbox_provider(); + } + + private: + SandboxQuotaClient * quota_client_; + scoped_refptr<FileSystemContext> file_system_context_; + std::set<GURL> origins_; + FileSystemType type_; +}; + +class SandboxQuotaClient::GetOriginsForTypeTask + : public SandboxQuotaClient::GetOriginsTaskBase { + public: + GetOriginsForTypeTask( + SandboxQuotaClient* quota_client, + scoped_refptr<MessageLoopProxy> file_message_loop, + FileSystemType type) + : GetOriginsTaskBase(quota_client, file_message_loop, type) {} + virtual ~GetOriginsForTypeTask() {} + + protected: + virtual bool ShouldAddThisOrigin(const GURL& origin) const OVERRIDE { + return true; + } + + virtual void Completed() OVERRIDE { + quota_client()->DidGetOriginsForType(type(), origins()); + } +}; + +quota::QuotaClient::ID SandboxQuotaClient::id() const { + return quota::QuotaClient::kFileSystem; +} + +void SandboxQuotaClient::OnQuotaManagerDestroyed() { + delete this; +} + +class SandboxQuotaClient::GetOriginsForHostTask + : public SandboxQuotaClient::GetOriginsTaskBase { + public: + GetOriginsForHostTask( + SandboxQuotaClient* quota_client, + scoped_refptr<MessageLoopProxy> file_message_loop, + FileSystemType type, + const std::string& host) + : GetOriginsTaskBase(quota_client, file_message_loop, type), + host_(host) {} + virtual ~GetOriginsForHostTask() {} + + protected: + virtual bool ShouldAddThisOrigin(const GURL& origin) const OVERRIDE { + return (host_ == net::GetHostOrSpecFromURL(origin)); + } + + virtual void Completed() OVERRIDE { + quota_client()->DidGetOriginsForHost(std::make_pair(type(), host_), + origins()); + } + + private: + std::string host_; +}; + +SandboxQuotaClient::SandboxQuotaClient( + scoped_refptr<base::MessageLoopProxy> file_message_loop, + FileSystemContext* file_system_context, + bool is_incognito) + : file_message_loop_(file_message_loop), + file_system_context_(file_system_context), + is_incognito_(is_incognito) { + DCHECK(file_message_loop); +} + +SandboxQuotaClient::~SandboxQuotaClient() { +} + +void SandboxQuotaClient::GetOriginUsage( + const GURL& origin_url, + StorageType storage_type, + GetUsageCallback* callback_ptr) { + DCHECK(callback_ptr); + scoped_ptr<GetUsageCallback> callback(callback_ptr); + + if (is_incognito_) { + // We don't support FileSystem in incognito mode yet. + callback->Run(0); + return; + } + + FileSystemType type = QuotaStorageTypeToFileSystemType(storage_type); + DCHECK(type != kFileSystemTypeUnknown); + + if (pending_usage_callbacks_.Add( + std::make_pair(type, origin_url.spec()), callback.release())) { + scoped_refptr<GetOriginUsageTask> task( + new GetOriginUsageTask(this, file_message_loop_, origin_url, type)); + task->Start(); + } +} + +void SandboxQuotaClient::GetOriginsForType( + StorageType storage_type, + GetOriginsCallback* callback_ptr) { + std::set<GURL> origins; + scoped_ptr<GetOriginsCallback> callback(callback_ptr); + if (is_incognito_) { + // We don't support FileSystem in incognito mode yet. + callback->Run(origins); + return; + } + + FileSystemType type = QuotaStorageTypeToFileSystemType(storage_type); + DCHECK(type != kFileSystemTypeUnknown); + + if (pending_origins_for_type_callbacks_.Add(type, callback.release())) { + scoped_refptr<GetOriginsForTypeTask> task( + new GetOriginsForTypeTask(this, file_message_loop_, type)); + task->Start(); + } +} + +void SandboxQuotaClient::GetOriginsForHost( + StorageType storage_type, + const std::string& host, + GetOriginsCallback* callback_ptr) { + std::set<GURL> origins; + scoped_ptr<GetOriginsCallback> callback(callback_ptr); + if (is_incognito_) { + // We don't support FileSystem in incognito mode yet. + callback->Run(origins); + return; + } + + FileSystemType type = QuotaStorageTypeToFileSystemType(storage_type); + DCHECK(type != kFileSystemTypeUnknown); + + if (pending_origins_for_host_callbacks_.Add( + std::make_pair(type, host), callback.release())) { + scoped_refptr<GetOriginsForHostTask> task( + new GetOriginsForHostTask(this, file_message_loop_, + type, host)); + task->Start(); + } +} + +void SandboxQuotaClient::DidGetOriginUsage( + FileSystemType type, const GURL& origin_url, int64 usage) { + visited_origins_.insert(origin_url); + TypeAndHostOrOrigin type_and_origin(std::make_pair( + type, origin_url.spec())); + DCHECK(pending_usage_callbacks_.HasCallbacks(type_and_origin)); + pending_usage_callbacks_.Run(type_and_origin, usage); +} + +void SandboxQuotaClient::DidGetOriginsForType( + FileSystemType type, const std::set<GURL>& origins) { + DCHECK(pending_origins_for_type_callbacks_.HasCallbacks(type)); + pending_origins_for_type_callbacks_.Run(type, origins); +} + +void SandboxQuotaClient::DidGetOriginsForHost( + const TypeAndHostOrOrigin& type_and_host, const std::set<GURL>& origins) { + DCHECK(pending_origins_for_host_callbacks_.HasCallbacks(type_and_host)); + pending_origins_for_host_callbacks_.Run(type_and_host, origins); +} + +} // namespace fileapi diff --git a/webkit/fileapi/sandbox_quota_client.h b/webkit/fileapi/sandbox_quota_client.h new file mode 100644 index 0000000..7aae5fb --- /dev/null +++ b/webkit/fileapi/sandbox_quota_client.h @@ -0,0 +1,93 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef WEBKIT_FILEAPI_SANDBOX_QUOTA_CLIENT_H_ +#define WEBKIT_FILEAPI_SANDBOX_QUOTA_CLIENT_H_ + +#include <deque> +#include <list> +#include <map> +#include <string> + +#include "base/basictypes.h" +#include "base/file_path.h" +#include "base/memory/scoped_ptr.h" +#include "webkit/fileapi/file_system_path_manager.h" +#include "webkit/fileapi/file_system_types.h" +#include "webkit/quota/quota_client.h" +#include "webkit/quota/quota_task.h" + +namespace fileapi { + +class FileSystemContext; + +// An instance of this class is created per-profile. This class +// is self-destructed and will delete itself when OnQuotaManagerDestroyed +// is called. +class SandboxQuotaClient : public quota::QuotaClient, + public quota::QuotaTaskObserver { + public: + SandboxQuotaClient( + scoped_refptr<base::MessageLoopProxy> file_message_loop, + FileSystemContext* file_system_context, + bool is_incognito); + virtual ~SandboxQuotaClient(); + + // QuotaClient methods. + virtual quota::QuotaClient::ID id() const OVERRIDE; + virtual void OnQuotaManagerDestroyed() OVERRIDE; + virtual void GetOriginUsage(const GURL& origin_url, + quota::StorageType type, + GetUsageCallback* callback) OVERRIDE; + virtual void GetOriginsForType(quota::StorageType type, + GetOriginsCallback* callback) OVERRIDE; + virtual void GetOriginsForHost(quota::StorageType type, + const std::string& host, + GetOriginsCallback* callback) OVERRIDE; + + private: + class GetOriginUsageTask; + class GetOriginsTaskBase; + class GetOriginsForTypeTask; + class GetOriginsForHostTask; + + typedef std::pair<fileapi::FileSystemType, std::string> TypeAndHostOrOrigin; + typedef quota::CallbackQueueMap1<GetUsageCallback*, + TypeAndHostOrOrigin, + int64 + > UsageCallbackMap; + typedef quota::CallbackQueueMap1<GetOriginsCallback*, + fileapi::FileSystemType, + const std::set<GURL>& + > OriginsForTypeCallbackMap; + typedef quota::CallbackQueueMap1<GetOriginsCallback*, + TypeAndHostOrOrigin, + const std::set<GURL>& + > OriginsForHostCallbackMap; + + void DidGetOriginUsage(fileapi::FileSystemType type, + const GURL& origin, int64 usage); + void DidGetOriginsForType(fileapi::FileSystemType type, + const std::set<GURL>& origins); + void DidGetOriginsForHost(const TypeAndHostOrOrigin& type_and_host, + const std::set<GURL>& origins); + + scoped_refptr<base::MessageLoopProxy> file_message_loop_; + scoped_refptr<FileSystemContext> file_system_context_; + + bool is_incognito_; + + std::set<GURL> visited_origins_; + + // Pending callbacks. + UsageCallbackMap pending_usage_callbacks_; + OriginsForTypeCallbackMap pending_origins_for_type_callbacks_; + OriginsForHostCallbackMap pending_origins_for_host_callbacks_; + + DISALLOW_COPY_AND_ASSIGN(SandboxQuotaClient); +}; + +} // namespace fileapi + +#endif // WEBKIT_FILEAPI_SANDBOX_QUOTA_CLIENT_H_ diff --git a/webkit/fileapi/sandbox_quota_client_unittest.cc b/webkit/fileapi/sandbox_quota_client_unittest.cc new file mode 100644 index 0000000..c77e423 --- /dev/null +++ b/webkit/fileapi/sandbox_quota_client_unittest.cc @@ -0,0 +1,431 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/basictypes.h" +#include "base/file_util.h" +#include "base/memory/scoped_callback_factory.h" +#include "base/memory/scoped_temp_dir.h" +#include "base/message_loop.h" +#include "base/message_loop_proxy.h" +#include "base/platform_file.h" +#include "googleurl/src/gurl.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "webkit/fileapi/file_system_context.h" +#include "webkit/fileapi/file_system_types.h" +#include "webkit/fileapi/file_system_usage_cache.h" +#include "webkit/fileapi/file_system_util.h" +#include "webkit/fileapi/sandbox_mount_point_provider.h" +#include "webkit/fileapi/sandbox_quota_client.h" +#include "webkit/quota/quota_types.h" + +using namespace fileapi; + +namespace { +const char kDummyURL1[] = "http://www.dummy.org"; +const char kDummyURL2[] = "http://www.example.com"; +const char kDummyURL3[] = "http://www.bleh"; + +// Declared to shorten the variable names. +const quota::StorageType kTemporary = quota::kStorageTypeTemporary; +const quota::StorageType kPersistent = quota::kStorageTypePersistent; +const int kUsageFileSize = FileSystemUsageCache::kUsageFileSize; + +class MockFileSystemPathManager : public FileSystemPathManager { + public: + MockFileSystemPathManager(const FilePath& filesystem_path) + : FileSystemPathManager(base::MessageLoopProxy::CreateForCurrentThread(), + filesystem_path, NULL, false, true) {} +}; +} + +class SandboxQuotaClientTest : public testing::Test { + public: + SandboxQuotaClientTest() + : callback_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)), + additional_callback_count_(0) { + } + + void SetUp() { + ASSERT_TRUE(data_dir_.CreateUniqueTempDir()); + file_system_context_ = + new FileSystemContext( + base::MessageLoopProxy::CreateForCurrentThread(), + base::MessageLoopProxy::CreateForCurrentThread(), + NULL, NULL, + FilePath(), false /* is_incognito */, + false, true, + new MockFileSystemPathManager(data_dir_.path())); + } + + struct TestFile { + bool isDirectory; + const char* name; + int64 size; + const char* origin_url; + quota::StorageType type; + }; + + protected: + SandboxQuotaClient* NewQuotaClient(bool is_incognito) { + return new SandboxQuotaClient( + base::MessageLoopProxy::CreateForCurrentThread(), + file_system_context_, is_incognito); + } + + void GetOriginUsageAsync(SandboxQuotaClient* quota_client, + const char* origin_url, + quota::StorageType type) { + quota_client->GetOriginUsage(GURL(origin_url), type, + callback_factory_.NewCallback( + &SandboxQuotaClientTest::OnGetUsage)); + } + + int64 GetOriginUsage(SandboxQuotaClient* quota_client, + const char* origin_url, + quota::StorageType type) { + GetOriginUsageAsync(quota_client, origin_url, type); + MessageLoop::current()->RunAllPending(); + return usage_; + } + + const std::set<GURL>& GetOriginsForType(SandboxQuotaClient* quota_client, + quota::StorageType type) { + origins_.clear(); + quota_client->GetOriginsForType(type, + callback_factory_.NewCallback( + &SandboxQuotaClientTest::OnGetOrigins)); + MessageLoop::current()->RunAllPending(); + return origins_; + } + + const std::set<GURL>& GetOriginsForHost(SandboxQuotaClient* quota_client, + quota::StorageType type, + const char* host) { + origins_.clear(); + quota_client->GetOriginsForHost(type, host, + callback_factory_.NewCallback( + &SandboxQuotaClientTest::OnGetOrigins)); + MessageLoop::current()->RunAllPending(); + return origins_; + } + + void RunAdditionalOriginUsageTask(SandboxQuotaClient* quota_client, + const char* origin_url, + quota::StorageType type) { + quota_client->GetOriginUsage(GURL(origin_url), type, + callback_factory_.NewCallback( + &SandboxQuotaClientTest::OnGetAdditionalUsage)); + } + + FilePath GetOriginBasePath(const char* origin_url, + quota::StorageType type) { + return file_system_context_->path_manager()->sandbox_provider()-> + GetBaseDirectoryForOriginAndType( + GURL(origin_url), QuotaStorageTypeToFileSystemType(type)); + } + + bool CreateFileSystemDirectory(const char* dir_name, + const char* origin_url, + quota::StorageType type) { + FilePath origin_base_path = GetOriginBasePath(origin_url, type); + FilePath dir_path; + if (dir_name != NULL) + dir_path = origin_base_path.AppendASCII(dir_name); + else + dir_path = origin_base_path; + if (dir_path.empty()) + return false; + + return file_util::CreateDirectory(dir_path); + } + + bool CreateFileSystemFile(const char* file_name, + int64 file_size, + const char* origin_url, + quota::StorageType type) { + FilePath origin_base_path = GetOriginBasePath(origin_url, type); + FilePath file_path = origin_base_path.AppendASCII(file_name); + + if (file_path.empty()) + return false; + + int file_flags = base::PLATFORM_FILE_CREATE_ALWAYS | + base::PLATFORM_FILE_WRITE; + base::PlatformFileError error_code; + base::PlatformFile file = + base::CreatePlatformFile(file_path, file_flags, NULL, &error_code); + if (error_code != base::PLATFORM_FILE_OK) + return false; + + bool succeeded; + succeeded = base::TruncatePlatformFile(file, file_size); + succeeded = succeeded && base::ClosePlatformFile(file); + return succeeded; + } + + void CreateFiles(const TestFile* files, int num_files) { + for (int i = 0; i < num_files; i++) { + if (files[i].isDirectory) { + ASSERT_TRUE(CreateFileSystemDirectory( + files[i].name, files[i].origin_url, files[i].type)); + } else { + ASSERT_TRUE(CreateFileSystemFile( + files[i].name, files[i].size, files[i].origin_url, files[i].type)); + } + } + } + + int64 usage() const { return usage_; } + int additional_callback_count() const { return additional_callback_count_; } + void set_additional_callback_count(int count) { + additional_callback_count_ = count; + } + + private: + void OnGetUsage(int64 usage) { + usage_ = usage; + } + + void OnGetOrigins(const std::set<GURL>& origins) { + origins_ = origins; + } + + void OnGetAdditionalUsage(int64) { + ++additional_callback_count_; + } + + ScopedTempDir data_dir_; + scoped_refptr<FileSystemContext> file_system_context_; + base::ScopedCallbackFactory<SandboxQuotaClientTest> callback_factory_; + int64 usage_; + int additional_callback_count_; + std::set<GURL> origins_; + + DISALLOW_COPY_AND_ASSIGN(SandboxQuotaClientTest); +}; + +TEST_F(SandboxQuotaClientTest, NoFileSystemTest) { + scoped_ptr<SandboxQuotaClient> quota_client(NewQuotaClient(false)); + + EXPECT_EQ(0, GetOriginUsage(quota_client.get(), kDummyURL1, kTemporary)); +} + +TEST_F(SandboxQuotaClientTest, NoFileTest) { + scoped_ptr<SandboxQuotaClient> quota_client(NewQuotaClient(false)); + const TestFile kFiles[] = { + {true, NULL, 0, kDummyURL1, kTemporary}, + }; + CreateFiles(kFiles, ARRAYSIZE_UNSAFE(kFiles)); + + for (int i = 0; i < 2; i++) { + EXPECT_EQ(kUsageFileSize, + GetOriginUsage(quota_client.get(), kDummyURL1, kTemporary)); + } +} + +TEST_F(SandboxQuotaClientTest, OneFileTest) { + scoped_ptr<SandboxQuotaClient> quota_client(NewQuotaClient(false)); + const TestFile kFiles[] = { + {true, NULL, 0, kDummyURL1, kTemporary}, + {false, "foo", 4921, kDummyURL1, kTemporary}, + }; + CreateFiles(kFiles, ARRAYSIZE_UNSAFE(kFiles)); + + for (int i = 0; i < 2; i++) { + EXPECT_EQ(4921 + kUsageFileSize, + GetOriginUsage(quota_client.get(), kDummyURL1, kTemporary)); + } +} + +TEST_F(SandboxQuotaClientTest, TwoFilesTest) { + scoped_ptr<SandboxQuotaClient> quota_client(NewQuotaClient(false)); + const TestFile kFiles[] = { + {true, NULL, 0, kDummyURL1, kTemporary}, + {false, "foo", 10310, kDummyURL1, kTemporary}, + {false, "bar", 41, kDummyURL1, kTemporary}, + }; + CreateFiles(kFiles, ARRAYSIZE_UNSAFE(kFiles)); + + for (int i = 0; i < 2; i++) { + EXPECT_EQ(10310 + 41 + kUsageFileSize, + GetOriginUsage(quota_client.get(), kDummyURL1, kTemporary)); + } +} + +TEST_F(SandboxQuotaClientTest, EmptyFilesTest) { + scoped_ptr<SandboxQuotaClient> quota_client(NewQuotaClient(false)); + const TestFile kFiles[] = { + {true, NULL, 0, kDummyURL1, kTemporary}, + {false, "foo", 0, kDummyURL1, kTemporary}, + {false, "bar", 0, kDummyURL1, kTemporary}, + {false, "baz", 0, kDummyURL1, kTemporary}, + }; + CreateFiles(kFiles, ARRAYSIZE_UNSAFE(kFiles)); + + for (int i = 0; i < 2; i++) { + EXPECT_EQ(kUsageFileSize, + GetOriginUsage(quota_client.get(), kDummyURL1, kTemporary)); + } +} + +TEST_F(SandboxQuotaClientTest, SubDirectoryTest) { + scoped_ptr<SandboxQuotaClient> quota_client(NewQuotaClient(false)); + const TestFile kFiles[] = { + {true, NULL, 0, kDummyURL1, kTemporary}, + {true, "dirtest", 0, kDummyURL1, kTemporary}, + {false, "dirtest/foo", 11921, kDummyURL1, kTemporary}, + {false, "bar", 4814, kDummyURL1, kTemporary}, + }; + CreateFiles(kFiles, ARRAYSIZE_UNSAFE(kFiles)); + + for (int i = 0; i < 2; i++) { + EXPECT_EQ(11921 + 4814 + kUsageFileSize, + GetOriginUsage(quota_client.get(), kDummyURL1, kTemporary)); + } +} + +TEST_F(SandboxQuotaClientTest, MultiTypeTest) { + scoped_ptr<SandboxQuotaClient> quota_client(NewQuotaClient(false)); + const TestFile kFiles[] = { + {true, NULL, 0, kDummyURL1, kTemporary}, + {true, "dirtest", 0, kDummyURL1, kTemporary}, + {false, "dirtest/foo", 133, kDummyURL1, kTemporary}, + {false, "bar", 14, kDummyURL1, kTemporary}, + {true, NULL, 0, kDummyURL1, kPersistent}, + {true, "dirtest", 0, kDummyURL1, kPersistent}, + {false, "dirtest/foo", 193, kDummyURL1, kPersistent}, + {false, "bar", 9, kDummyURL1, kPersistent}, + }; + CreateFiles(kFiles, ARRAYSIZE_UNSAFE(kFiles)); + + for (int i = 0; i < 2; i++) { + EXPECT_EQ(133 + 14 + kUsageFileSize, + GetOriginUsage(quota_client.get(), kDummyURL1, kTemporary)); + EXPECT_EQ(193 + 9 + kUsageFileSize, + GetOriginUsage(quota_client.get(), kDummyURL1, kPersistent)); + } +} + +TEST_F(SandboxQuotaClientTest, MultiDomainTest) { + scoped_ptr<SandboxQuotaClient> quota_client(NewQuotaClient(false)); + const TestFile kFiles[] = { + {true, NULL, 0, kDummyURL1, kTemporary}, + {true, "dir1", 0, kDummyURL1, kTemporary}, + {false, "dir1/foo", 1331, kDummyURL1, kTemporary}, + {false, "bar", 134, kDummyURL1, kTemporary}, + {true, NULL, 0, kDummyURL1, kPersistent}, + {true, "dir2", 0, kDummyURL1, kPersistent}, + {false, "dir2/foo", 1903, kDummyURL1, kPersistent}, + {false, "bar", 19, kDummyURL1, kPersistent}, + {true, NULL, 0, kDummyURL2, kTemporary}, + {true, "dom", 0, kDummyURL2, kTemporary}, + {false, "dom/fan", 1319, kDummyURL2, kTemporary}, + {false, "bar", 113, kDummyURL2, kTemporary}, + {true, NULL, 0, kDummyURL2, kPersistent}, + {true, "dom", 0, kDummyURL2, kPersistent}, + {false, "dom/fan", 2013, kDummyURL2, kPersistent}, + {false, "baz", 18, kDummyURL2, kPersistent}, + }; + CreateFiles(kFiles, ARRAYSIZE_UNSAFE(kFiles)); + + for (int i = 0; i < 2; i++) { + EXPECT_EQ(1331 + 134 + kUsageFileSize, + GetOriginUsage(quota_client.get(), kDummyURL1, kTemporary)); + EXPECT_EQ(1903 + 19 + kUsageFileSize, + GetOriginUsage(quota_client.get(), kDummyURL1, kPersistent)); + EXPECT_EQ(1319 + 113 + kUsageFileSize, + GetOriginUsage(quota_client.get(), kDummyURL2, kTemporary)); + EXPECT_EQ(2013 + 18 + kUsageFileSize, + GetOriginUsage(quota_client.get(), kDummyURL2, kPersistent)); + } +} + +TEST_F(SandboxQuotaClientTest, GetUsage_MultipleTasks) { + scoped_ptr<SandboxQuotaClient> quota_client(NewQuotaClient(false)); + const TestFile kFiles[] = { + {true, NULL, 0, kDummyURL1, kTemporary}, + {false, "foo", 11, kDummyURL1, kTemporary}, + {false, "bar", 22, kDummyURL1, kTemporary}, + }; + CreateFiles(kFiles, ARRAYSIZE_UNSAFE(kFiles)); + + // Dispatching three GetUsage tasks. + set_additional_callback_count(0); + GetOriginUsageAsync(quota_client.get(), kDummyURL1, kTemporary); + RunAdditionalOriginUsageTask(quota_client.get(), kDummyURL1, kTemporary); + RunAdditionalOriginUsageTask(quota_client.get(), kDummyURL1, kTemporary); + MessageLoop::current()->RunAllPending(); + EXPECT_EQ(11 + 22 + kUsageFileSize, usage()); + EXPECT_EQ(2, additional_callback_count()); + + // Once more, in a different order. + set_additional_callback_count(0); + RunAdditionalOriginUsageTask(quota_client.get(), kDummyURL1, kTemporary); + GetOriginUsageAsync(quota_client.get(), kDummyURL1, kTemporary); + RunAdditionalOriginUsageTask(quota_client.get(), kDummyURL1, kTemporary); + MessageLoop::current()->RunAllPending(); + EXPECT_EQ(11 + 22 + kUsageFileSize, usage()); + EXPECT_EQ(2, additional_callback_count()); +} + +TEST_F(SandboxQuotaClientTest, GetOriginsForType) { + scoped_ptr<SandboxQuotaClient> quota_client(NewQuotaClient(false)); + const TestFile kFiles[] = { + {true, NULL, 0, kDummyURL1, kTemporary}, + {true, NULL, 0, kDummyURL2, kTemporary}, + {true, NULL, 0, kDummyURL3, kPersistent}, + }; + CreateFiles(kFiles, ARRAYSIZE_UNSAFE(kFiles)); + + std::set<GURL> origins = GetOriginsForType(quota_client.get(), kTemporary); + EXPECT_EQ(2U, origins.size()); + EXPECT_TRUE(origins.find(GURL(kDummyURL1)) != origins.end()); + EXPECT_TRUE(origins.find(GURL(kDummyURL2)) != origins.end()); + EXPECT_TRUE(origins.find(GURL(kDummyURL3)) == origins.end()); +} + +TEST_F(SandboxQuotaClientTest, GetOriginsForHost) { + scoped_ptr<SandboxQuotaClient> quota_client(NewQuotaClient(false)); + const char* kURL1 = "http://foo.com/"; + const char* kURL2 = "https://foo.com/"; + const char* kURL3 = "http://foo.com:1/"; + const char* kURL4 = "http://foo2.com/"; + const char* kURL5 = "http://foo.com:2/"; + const TestFile kFiles[] = { + {true, NULL, 0, kURL1, kTemporary}, + {true, NULL, 0, kURL2, kTemporary}, + {true, NULL, 0, kURL3, kTemporary}, + {true, NULL, 0, kURL4, kTemporary}, + {true, NULL, 0, kURL5, kPersistent}, + }; + CreateFiles(kFiles, ARRAYSIZE_UNSAFE(kFiles)); + + std::set<GURL> origins = GetOriginsForHost( + quota_client.get(), kTemporary, "foo.com"); + EXPECT_EQ(3U, origins.size()); + EXPECT_TRUE(origins.find(GURL(kURL1)) != origins.end()); + EXPECT_TRUE(origins.find(GURL(kURL2)) != origins.end()); + EXPECT_TRUE(origins.find(GURL(kURL3)) != origins.end()); + EXPECT_TRUE(origins.find(GURL(kURL4)) == origins.end()); // Different host. + EXPECT_TRUE(origins.find(GURL(kURL5)) == origins.end()); // Different type. +} + +TEST_F(SandboxQuotaClientTest, IncognitoTest) { + scoped_ptr<SandboxQuotaClient> quota_client(NewQuotaClient(true)); + const TestFile kFiles[] = { + {true, NULL, 0, kDummyURL1, kTemporary}, + {false, "foo", 10, kDummyURL1, kTemporary}, + }; + CreateFiles(kFiles, ARRAYSIZE_UNSAFE(kFiles)); + + // Having files in the usual directory wouldn't affect the result + // queried in incognito mode. + EXPECT_EQ(0, GetOriginUsage(quota_client.get(), kDummyURL1, kTemporary)); + EXPECT_EQ(0, GetOriginUsage(quota_client.get(), kDummyURL1, kPersistent)); + + std::set<GURL> origins = GetOriginsForType(quota_client.get(), kTemporary); + EXPECT_EQ(0U, origins.size()); + origins = GetOriginsForHost(quota_client.get(), kTemporary, "www.dummy.org"); + EXPECT_EQ(0U, origins.size()); +} diff --git a/webkit/fileapi/webkit_fileapi.gypi b/webkit/fileapi/webkit_fileapi.gypi index 4d0ef77..aa70b0b 100644 --- a/webkit/fileapi/webkit_fileapi.gypi +++ b/webkit/fileapi/webkit_fileapi.gypi @@ -13,6 +13,7 @@ '<(DEPTH)/base/base.gyp:base', '<(DEPTH)/net/net.gyp:net', '<(DEPTH)/third_party/leveldb/leveldb.gyp:leveldb', + '<(DEPTH)/webkit/support/webkit_support.gyp:quota', ], 'sources': [ 'file_system_callback_dispatcher.cc', @@ -41,20 +42,20 @@ 'file_system_url_request_job.h', 'file_system_url_request_job_base.cc', 'file_system_url_request_job_base.h', - 'file_system_usage_tracker.cc', - 'file_system_usage_tracker.h', + 'file_system_usage_cache.cc', + 'file_system_usage_cache.h', 'file_system_util.cc', 'file_system_util.h', - 'file_system_usage_cache.h', - 'file_system_usage_cache.cc', 'file_writer_delegate.cc', 'file_writer_delegate.h', 'local_file_system_file_util.cc', 'local_file_system_file_util.h', - 'sandbox_mount_point_provider.cc', - 'sandbox_mount_point_provider.h', 'quota_file_util.cc', 'quota_file_util.h', + 'sandbox_mount_point_provider.cc', + 'sandbox_mount_point_provider.h', + 'sandbox_quota_client.cc', + 'sandbox_quota_client.h', 'webfilewriter_base.cc', 'webfilewriter_base.h', ], |