// 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 "content/browser/in_process_webkit/indexed_db_quota_client.h" #include #include "base/file_util.h" #include "base/logging.h" #include "base/message_loop_proxy.h" #include "content/browser/in_process_webkit/indexed_db_context_impl.h" #include "content/public/browser/browser_thread.h" #include "net/base/net_util.h" #include "webkit/database/database_util.h" using content::BrowserThread; using quota::QuotaClient; using webkit_database::DatabaseUtil; // Helper tasks --------------------------------------------------------------- class IndexedDBQuotaClient::HelperTask : public quota::QuotaThreadTask { protected: HelperTask( IndexedDBQuotaClient* client, base::MessageLoopProxy* webkit_thread_message_loop) : QuotaThreadTask(client, webkit_thread_message_loop), client_(client), indexed_db_context_(client->indexed_db_context_) { } IndexedDBQuotaClient* client_; scoped_refptr indexed_db_context_; }; class IndexedDBQuotaClient::DeleteOriginTask : public HelperTask { public: DeleteOriginTask(IndexedDBQuotaClient* client, base::MessageLoopProxy* webkit_thread_message_loop, const GURL& origin_url, const DeletionCallback& callback) : HelperTask(client, webkit_thread_message_loop), origin_url_(origin_url), callback_(callback) { } private: virtual void RunOnTargetThread() OVERRIDE { indexed_db_context_->DeleteForOrigin(origin_url_); } virtual void Aborted() OVERRIDE { callback_.Reset(); } virtual void Completed() OVERRIDE { callback_.Run(quota::kQuotaStatusOk); callback_.Reset(); } GURL origin_url_; DeletionCallback callback_; }; class IndexedDBQuotaClient::GetOriginUsageTask : public HelperTask { public: GetOriginUsageTask( IndexedDBQuotaClient* client, base::MessageLoopProxy* webkit_thread_message_loop, const GURL& origin_url) : HelperTask(client, webkit_thread_message_loop), origin_url_(origin_url), usage_(0) { } private: virtual void RunOnTargetThread() OVERRIDE { usage_ = indexed_db_context_->GetOriginDiskUsage(origin_url_); } virtual void Completed() OVERRIDE { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); client_->DidGetOriginUsage(origin_url_, usage_); } GURL origin_url_; int64 usage_; }; class IndexedDBQuotaClient::GetOriginsTaskBase : public HelperTask { protected: GetOriginsTaskBase( IndexedDBQuotaClient* client, base::MessageLoopProxy* webkit_thread_message_loop) : HelperTask(client, webkit_thread_message_loop) { } virtual bool ShouldAddOrigin(const GURL& origin) = 0; virtual void RunOnTargetThread() OVERRIDE { std::vector origins = indexed_db_context_->GetAllOrigins(); for (std::vector::const_iterator iter = origins.begin(); iter != origins.end(); ++iter) { if (ShouldAddOrigin(*iter)) origins_.insert(*iter); } } std::set origins_; }; class IndexedDBQuotaClient::GetAllOriginsTask : public GetOriginsTaskBase { public: GetAllOriginsTask( IndexedDBQuotaClient* client, base::MessageLoopProxy* webkit_thread_message_loop, quota::StorageType type) : GetOriginsTaskBase(client, webkit_thread_message_loop), type_(type) { } protected: virtual bool ShouldAddOrigin(const GURL& origin) OVERRIDE { return true; } virtual void Completed() OVERRIDE { client_->DidGetAllOrigins(origins_, type_); } private: quota::StorageType type_; }; class IndexedDBQuotaClient::GetOriginsForHostTask : public GetOriginsTaskBase { public: GetOriginsForHostTask( IndexedDBQuotaClient* client, base::MessageLoopProxy* webkit_thread_message_loop, const std::string& host, quota::StorageType type) : GetOriginsTaskBase(client, webkit_thread_message_loop), host_(host), type_(type) { } private: virtual bool ShouldAddOrigin(const GURL& origin) OVERRIDE { return host_ == net::GetHostOrSpecFromURL(origin); } virtual void Completed() OVERRIDE { client_->DidGetOriginsForHost(host_, origins_, type_); } std::string host_; quota::StorageType type_; }; // IndexedDBQuotaClient -------------------------------------------------------- IndexedDBQuotaClient::IndexedDBQuotaClient( base::MessageLoopProxy* webkit_thread_message_loop, IndexedDBContextImpl* indexed_db_context) : webkit_thread_message_loop_(webkit_thread_message_loop), indexed_db_context_(indexed_db_context) { } IndexedDBQuotaClient::~IndexedDBQuotaClient() { } QuotaClient::ID IndexedDBQuotaClient::id() const { return kIndexedDatabase; } void IndexedDBQuotaClient::OnQuotaManagerDestroyed() { delete this; } void IndexedDBQuotaClient::GetOriginUsage( const GURL& origin_url, quota::StorageType type, const GetUsageCallback& callback) { DCHECK(!callback.is_null()); DCHECK(indexed_db_context_.get()); // IndexedDB is 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, webkit_thread_message_loop_, origin_url)); task->Start(); } } void IndexedDBQuotaClient::GetOriginsForType( quota::StorageType type, const GetOriginsCallback& callback) { DCHECK(!callback.is_null()); DCHECK(indexed_db_context_.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, webkit_thread_message_loop_, type)); task->Start(); } } void IndexedDBQuotaClient::GetOriginsForHost( quota::StorageType type, const std::string& host, const GetOriginsCallback& callback) { DCHECK(!callback.is_null()); DCHECK(indexed_db_context_.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, webkit_thread_message_loop_, host, type)); task->Start(); } } void IndexedDBQuotaClient::DeleteOriginData( const GURL& origin, quota::StorageType type, const DeletionCallback& callback) { if (type != quota::kStorageTypeTemporary) { callback.Run(quota::kQuotaErrorNotSupported); return; } scoped_refptr task( new DeleteOriginTask(this, webkit_thread_message_loop_, origin, callback)); task->Start(); } void IndexedDBQuotaClient::DidGetOriginUsage( const GURL& origin_url, int64 usage) { DCHECK(usage_for_origin_callbacks_.HasCallbacks(origin_url)); usage_for_origin_callbacks_.Run(origin_url, usage); } void IndexedDBQuotaClient::DidGetAllOrigins(const std::set& origins, quota::StorageType type) { DCHECK(origins_for_type_callbacks_.HasCallbacks()); origins_for_type_callbacks_.Run(origins, type); } void IndexedDBQuotaClient::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); }