// Copyright (c) 2012 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/database/database_quota_client.h" #include #include "base/bind.h" #include "base/bind_helpers.h" #include "base/location.h" #include "base/memory/scoped_ptr.h" #include "base/message_loop_proxy.h" #include "net/base/completion_callback.h" #include "net/base/net_errors.h" #include "net/base/net_util.h" #include "webkit/database/database_tracker.h" #include "webkit/database/database_util.h" using quota::QuotaClient; namespace webkit_database { // Helper tasks --------------------------------------------------------------- class DatabaseQuotaClient::HelperTask : public quota::QuotaThreadTask { protected: HelperTask( DatabaseQuotaClient* client, base::MessageLoopProxy* db_tracker_thread) : QuotaThreadTask(client, db_tracker_thread), client_(client), db_tracker_(client->db_tracker_) { } virtual ~HelperTask() {} DatabaseQuotaClient* client_; scoped_refptr db_tracker_; }; class DatabaseQuotaClient::GetOriginUsageTask : public HelperTask { public: GetOriginUsageTask( DatabaseQuotaClient* client, base::MessageLoopProxy* db_tracker_thread, const GURL& origin_url) : HelperTask(client, db_tracker_thread), origin_url_(origin_url), usage_(0) { } protected: virtual ~GetOriginUsageTask() {} virtual void RunOnTargetThread() OVERRIDE { OriginInfo info; if (db_tracker_->GetOriginInfo( DatabaseUtil::GetOriginIdentifier(origin_url_), &info)) { usage_ = info.TotalSize(); } } virtual void Completed() OVERRIDE { client_->DidGetOriginUsage(origin_url_, usage_); } private: GURL origin_url_; int64 usage_; }; class DatabaseQuotaClient::GetOriginsTaskBase : public HelperTask { protected: GetOriginsTaskBase( DatabaseQuotaClient* client, base::MessageLoopProxy* db_tracker_thread) : HelperTask(client, db_tracker_thread) { } virtual ~GetOriginsTaskBase() {} virtual bool ShouldAddOrigin(const GURL& origin) = 0; virtual void RunOnTargetThread() OVERRIDE { std::vector origin_identifiers; if (db_tracker_->GetAllOriginIdentifiers(&origin_identifiers)) { for (std::vector::const_iterator iter = origin_identifiers.begin(); iter != origin_identifiers.end(); ++iter) { GURL origin = DatabaseUtil::GetOriginFromIdentifier(*iter); if (ShouldAddOrigin(origin)) origins_.insert(origin); } } } std::set origins_; }; class DatabaseQuotaClient::GetAllOriginsTask : public GetOriginsTaskBase { public: GetAllOriginsTask( DatabaseQuotaClient* client, base::MessageLoopProxy* db_tracker_thread, quota::StorageType type) : GetOriginsTaskBase(client, db_tracker_thread), type_(type) { } protected: virtual ~GetAllOriginsTask() {} virtual bool ShouldAddOrigin(const GURL& origin) OVERRIDE { return true; } virtual void Completed() OVERRIDE { client_->DidGetAllOrigins(origins_, type_); } private: quota::StorageType type_; }; class DatabaseQuotaClient::GetOriginsForHostTask : public GetOriginsTaskBase { public: GetOriginsForHostTask( DatabaseQuotaClient* client, base::MessageLoopProxy* db_tracker_thread, const std::string& host, quota::StorageType type) : GetOriginsTaskBase(client, db_tracker_thread), host_(host), type_(type) { } protected: virtual ~GetOriginsForHostTask() {} virtual bool ShouldAddOrigin(const GURL& origin) OVERRIDE { return host_ == net::GetHostOrSpecFromURL(origin); } virtual void Completed() OVERRIDE { client_->DidGetOriginsForHost(host_, origins_, type_); } private: std::string host_; quota::StorageType type_; }; class DatabaseQuotaClient::DeleteOriginTask : public HelperTask { public: DeleteOriginTask( DatabaseQuotaClient* client, base::MessageLoopProxy* db_tracker_thread, const GURL& origin_url, const DeletionCallback& caller_callback) : HelperTask(client, db_tracker_thread), origin_url_(origin_url), result_(quota::kQuotaStatusUnknown), caller_callback_(caller_callback) { } protected: virtual ~DeleteOriginTask() {} virtual void Completed() OVERRIDE { if (caller_callback_.is_null()) return; caller_callback_.Run(result_); caller_callback_.Reset(); } virtual void Aborted() OVERRIDE { caller_callback_.Reset(); } virtual bool RunOnTargetThreadAsync() OVERRIDE { AddRef(); // balanced in OnCompletionCallback string16 origin_id = DatabaseUtil::GetOriginIdentifier(origin_url_); int rv = db_tracker_->DeleteDataForOrigin( origin_id, base::Bind(&DeleteOriginTask::OnCompletionCallback, base::Unretained(this))); if (rv == net::ERR_IO_PENDING) return false; // we wait for the callback OnCompletionCallback(rv); return false; } private: void OnCompletionCallback(int rv) { if (rv == net::OK) result_ = quota::kQuotaStatusOk; original_task_runner()->PostTask( FROM_HERE, base::Bind(&DeleteOriginTask::CallCompleted, this)); Release(); // balanced in RunOnTargetThreadAsync } const GURL origin_url_; quota::QuotaStatusCode result_; DeletionCallback caller_callback_; net::CompletionCallback completion_callback_; }; // DatabaseQuotaClient -------------------------------------------------------- DatabaseQuotaClient::DatabaseQuotaClient( base::MessageLoopProxy* db_tracker_thread, DatabaseTracker* db_tracker) : db_tracker_thread_(db_tracker_thread), db_tracker_(db_tracker) { } DatabaseQuotaClient::~DatabaseQuotaClient() { } QuotaClient::ID DatabaseQuotaClient::id() const { return kDatabase; } void DatabaseQuotaClient::OnQuotaManagerDestroyed() { delete this; } void DatabaseQuotaClient::GetOriginUsage( const GURL& origin_url, quota::StorageType type, const GetUsageCallback& callback) { DCHECK(!callback.is_null()); DCHECK(db_tracker_.get()); // All databases are in the temp namespace for now. if (type != quota::kStorageTypeTemporary) { callback.Run(0); return; } if (usage_for_origin_callbacks_.Add(origin_url, callback)) { scoped_refptr task( new GetOriginUsageTask(this, db_tracker_thread_, origin_url)); task->Start(); } } void DatabaseQuotaClient::GetOriginsForType( quota::StorageType type, const GetOriginsCallback& callback) { DCHECK(!callback.is_null()); DCHECK(db_tracker_.get()); // All databases are in the temp namespace for now. if (type != quota::kStorageTypeTemporary) { callback.Run(std::set(), type); return; } if (origins_for_type_callbacks_.Add(callback)) { scoped_refptr task( new GetAllOriginsTask(this, db_tracker_thread_, type)); task->Start(); } } void DatabaseQuotaClient::GetOriginsForHost( quota::StorageType type, const std::string& host, const GetOriginsCallback& callback) { DCHECK(!callback.is_null()); DCHECK(db_tracker_.get()); // All databases are in the temp namespace for now. if (type != quota::kStorageTypeTemporary) { callback.Run(std::set(), type); return; } if (origins_for_host_callbacks_.Add(host, callback)) { scoped_refptr task( new GetOriginsForHostTask(this, db_tracker_thread_, host, type)); task->Start(); } } void DatabaseQuotaClient::DeleteOriginData(const GURL& origin, quota::StorageType type, const DeletionCallback& callback) { DCHECK(!callback.is_null()); DCHECK(db_tracker_.get()); // All databases are in the temp namespace for now, so nothing to delete. if (type != quota::kStorageTypeTemporary) { callback.Run(quota::kQuotaStatusOk); return; } scoped_refptr task( new DeleteOriginTask(this, db_tracker_thread_, origin, callback)); task->Start(); } void DatabaseQuotaClient::DidGetOriginUsage( const GURL& origin_url, int64 usage) { DCHECK(usage_for_origin_callbacks_.HasCallbacks(origin_url)); usage_for_origin_callbacks_.Run(origin_url, usage); } void DatabaseQuotaClient::DidGetAllOrigins(const std::set& origins, quota::StorageType type) { DCHECK(origins_for_type_callbacks_.HasCallbacks()); origins_for_type_callbacks_.Run(origins, type); } void DatabaseQuotaClient::DidGetOriginsForHost( const std::string& host, const std::set& origins, quota::StorageType type) { DCHECK(origins_for_host_callbacks_.HasCallbacks(host)); origins_for_host_callbacks_.Run(host, origins, type); } } // namespace webkit_database