blob: 669052c15c0780e7cb005af4ff58dcaddfbb71e1 [file] [log] [blame]
// 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/database/database_quota_client.h"
#include <vector>
#include "base/bind.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_) {
}
DatabaseQuotaClient* client_;
scoped_refptr<DatabaseTracker> 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) {
}
private:
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_);
}
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 bool ShouldAddOrigin(const GURL& origin) = 0;
virtual void RunOnTargetThread() OVERRIDE {
std::vector<string16> origin_identifiers;
if (db_tracker_->GetAllOriginIdentifiers(&origin_identifiers)) {
for (std::vector<string16>::const_iterator iter =
origin_identifiers.begin();
iter != origin_identifiers.end(); ++iter) {
GURL origin = DatabaseUtil::GetOriginFromIdentifier(*iter);
if (ShouldAddOrigin(origin))
origins_.insert(origin);
}
}
}
std::set<GURL> 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 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) {
}
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_;
};
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),
ALLOW_THIS_IN_INITIALIZER_LIST(completion_callback_(
this, &DeleteOriginTask::OnOldCompletionCallback)) {
}
private:
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 OnOldCompletionCallback
string16 origin_id = DatabaseUtil::GetOriginIdentifier(origin_url_);
int rv = db_tracker_->DeleteDataForOrigin(origin_id, &completion_callback_);
if (rv == net::ERR_IO_PENDING)
return false; // we wait for the callback
OnOldCompletionCallback(rv);
return false;
}
void OnOldCompletionCallback(int rv) {
if (rv == net::OK)
result_ = quota::kQuotaStatusOk;
original_message_loop()->PostTask(
FROM_HERE, base::Bind(&DeleteOriginTask::CallCompleted, this));
Release(); // balanced in RunOnTargetThreadAsync
}
const GURL origin_url_;
quota::QuotaStatusCode result_;
DeletionCallback caller_callback_;
net::OldCompletionCallbackImpl<DeleteOriginTask> 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<GetOriginUsageTask> 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<GURL>(), type);
return;
}
if (origins_for_type_callbacks_.Add(callback)) {
scoped_refptr<GetAllOriginsTask> 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<GURL>(), type);
return;
}
if (origins_for_host_callbacks_.Add(host, callback)) {
scoped_refptr<GetOriginsForHostTask> 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<DeleteOriginTask> 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<GURL>& 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<GURL>& origins,
quota::StorageType type) {
DCHECK(origins_for_host_callbacks_.HasCallbacks(host));
origins_for_host_callbacks_.Run(host, origins, type);
}
} // namespace webkit_database