blob: 5c6fdd82f95701d91820da256426b7f520c7a484 [file] [log] [blame]
// Copyright 2014 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 "net/ssl/default_channel_id_store.h"
#include <utility>
#include "base/bind.h"
#include "base/metrics/histogram_macros.h"
#include "crypto/ec_private_key.h"
#include "net/base/net_errors.h"
namespace {
bool AllDomainsPredicate(const std::string& domain) {
return true;
}
} // namespace
namespace net {
// --------------------------------------------------------------------------
// Task
class DefaultChannelIDStore::Task {
public:
virtual ~Task();
// Runs the task and invokes the client callback on the thread that
// originally constructed the task.
virtual void Run(DefaultChannelIDStore* store) = 0;
protected:
void InvokeCallback(base::OnceClosure callback) const;
};
DefaultChannelIDStore::Task::~Task() = default;
void DefaultChannelIDStore::Task::InvokeCallback(
base::OnceClosure callback) const {
if (!callback.is_null())
std::move(callback).Run();
}
// --------------------------------------------------------------------------
// GetChannelIDTask
class DefaultChannelIDStore::GetChannelIDTask
: public DefaultChannelIDStore::Task {
public:
GetChannelIDTask(const std::string& server_identifier,
GetChannelIDCallback callback);
~GetChannelIDTask() override;
void Run(DefaultChannelIDStore* store) override;
private:
std::string server_identifier_;
GetChannelIDCallback callback_;
};
DefaultChannelIDStore::GetChannelIDTask::GetChannelIDTask(
const std::string& server_identifier,
GetChannelIDCallback callback)
: server_identifier_(server_identifier), callback_(std::move(callback)) {}
DefaultChannelIDStore::GetChannelIDTask::~GetChannelIDTask() = default;
void DefaultChannelIDStore::GetChannelIDTask::Run(
DefaultChannelIDStore* store) {
std::unique_ptr<crypto::ECPrivateKey> key_result;
int err = store->GetChannelID(server_identifier_, &key_result,
GetChannelIDCallback());
DCHECK(err != ERR_IO_PENDING);
InvokeCallback(base::BindOnce(std::move(callback_), err, server_identifier_,
std::move(key_result)));
}
// --------------------------------------------------------------------------
// SetChannelIDTask
class DefaultChannelIDStore::SetChannelIDTask
: public DefaultChannelIDStore::Task {
public:
SetChannelIDTask(std::unique_ptr<ChannelID> channel_id);
~SetChannelIDTask() override;
void Run(DefaultChannelIDStore* store) override;
private:
std::unique_ptr<ChannelID> channel_id_;
};
DefaultChannelIDStore::SetChannelIDTask::SetChannelIDTask(
std::unique_ptr<ChannelID> channel_id)
: channel_id_(std::move(channel_id)) {}
DefaultChannelIDStore::SetChannelIDTask::~SetChannelIDTask() = default;
void DefaultChannelIDStore::SetChannelIDTask::Run(
DefaultChannelIDStore* store) {
store->SyncSetChannelID(std::move(channel_id_));
}
// --------------------------------------------------------------------------
// DeleteChannelIDTask
class DefaultChannelIDStore::DeleteChannelIDTask
: public DefaultChannelIDStore::Task {
public:
DeleteChannelIDTask(const std::string& server_identifier,
base::OnceClosure callback);
~DeleteChannelIDTask() override;
void Run(DefaultChannelIDStore* store) override;
private:
std::string server_identifier_;
base::OnceClosure callback_;
};
DefaultChannelIDStore::DeleteChannelIDTask::DeleteChannelIDTask(
const std::string& server_identifier,
base::OnceClosure callback)
: server_identifier_(server_identifier), callback_(std::move(callback)) {}
DefaultChannelIDStore::DeleteChannelIDTask::~DeleteChannelIDTask() = default;
void DefaultChannelIDStore::DeleteChannelIDTask::Run(
DefaultChannelIDStore* store) {
store->SyncDeleteChannelID(server_identifier_);
InvokeCallback(std::move(callback_));
}
// --------------------------------------------------------------------------
// DeleteForDomainssCreatedBetweenTask
class DefaultChannelIDStore::DeleteForDomainsCreatedBetweenTask
: public DefaultChannelIDStore::Task {
public:
DeleteForDomainsCreatedBetweenTask(
const base::Callback<bool(const std::string&)>& domain_predicate,
base::Time delete_begin,
base::Time delete_end,
base::OnceClosure callback);
~DeleteForDomainsCreatedBetweenTask() override;
void Run(DefaultChannelIDStore* store) override;
private:
const base::Callback<bool(const std::string&)> domain_predicate_;
base::Time delete_begin_;
base::Time delete_end_;
base::OnceClosure callback_;
};
DefaultChannelIDStore::DeleteForDomainsCreatedBetweenTask::
DeleteForDomainsCreatedBetweenTask(
const base::Callback<bool(const std::string&)>& domain_predicate,
base::Time delete_begin,
base::Time delete_end,
base::OnceClosure callback)
: domain_predicate_(domain_predicate),
delete_begin_(delete_begin),
delete_end_(delete_end),
callback_(std::move(callback)) {}
DefaultChannelIDStore::DeleteForDomainsCreatedBetweenTask::
~DeleteForDomainsCreatedBetweenTask() = default;
void DefaultChannelIDStore::DeleteForDomainsCreatedBetweenTask::Run(
DefaultChannelIDStore* store) {
store->SyncDeleteForDomainsCreatedBetween(domain_predicate_, delete_begin_,
delete_end_);
InvokeCallback(std::move(callback_));
}
// --------------------------------------------------------------------------
// GetAllChannelIDsTask
class DefaultChannelIDStore::GetAllChannelIDsTask
: public DefaultChannelIDStore::Task {
public:
explicit GetAllChannelIDsTask(GetChannelIDListCallback callback);
~GetAllChannelIDsTask() override;
void Run(DefaultChannelIDStore* store) override;
private:
std::string server_identifier_;
GetChannelIDListCallback callback_;
};
DefaultChannelIDStore::GetAllChannelIDsTask::GetAllChannelIDsTask(
GetChannelIDListCallback callback)
: callback_(std::move(callback)) {}
DefaultChannelIDStore::GetAllChannelIDsTask::~GetAllChannelIDsTask() = default;
void DefaultChannelIDStore::GetAllChannelIDsTask::Run(
DefaultChannelIDStore* store) {
ChannelIDList key_list;
store->SyncGetAllChannelIDs(&key_list);
InvokeCallback(base::BindOnce(std::move(callback_), key_list));
}
// --------------------------------------------------------------------------
// DefaultChannelIDStore
DefaultChannelIDStore::DefaultChannelIDStore(
PersistentStore* store)
: initialized_(false),
loaded_(false),
store_(store),
weak_ptr_factory_(this) {}
int DefaultChannelIDStore::GetChannelID(
const std::string& server_identifier,
std::unique_ptr<crypto::ECPrivateKey>* key_result,
GetChannelIDCallback callback) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
InitIfNecessary();
if (!loaded_) {
EnqueueTask(std::unique_ptr<Task>(
new GetChannelIDTask(server_identifier, std::move(callback))));
return ERR_IO_PENDING;
}
auto it = channel_ids_.find(server_identifier);
if (it == channel_ids_.end())
return ERR_FILE_NOT_FOUND;
ChannelID* channel_id = it->second;
*key_result = channel_id->key()->Copy();
return OK;
}
void DefaultChannelIDStore::SetChannelID(
std::unique_ptr<ChannelID> channel_id) {
auto* task = new SetChannelIDTask(std::move(channel_id));
RunOrEnqueueTask(std::unique_ptr<Task>(task));
}
void DefaultChannelIDStore::DeleteChannelID(
const std::string& server_identifier,
base::OnceClosure callback) {
RunOrEnqueueTask(std::unique_ptr<Task>(
new DeleteChannelIDTask(server_identifier, std::move(callback))));
}
void DefaultChannelIDStore::DeleteForDomainsCreatedBetween(
const base::Callback<bool(const std::string&)>& domain_predicate,
base::Time delete_begin,
base::Time delete_end,
base::OnceClosure callback) {
RunOrEnqueueTask(std::unique_ptr<Task>(new DeleteForDomainsCreatedBetweenTask(
domain_predicate, delete_begin, delete_end, std::move(callback))));
}
void DefaultChannelIDStore::DeleteAll(base::OnceClosure callback) {
DeleteForDomainsCreatedBetween(base::Bind(&AllDomainsPredicate), base::Time(),
base::Time(), std::move(callback));
}
void DefaultChannelIDStore::GetAllChannelIDs(
GetChannelIDListCallback callback) {
RunOrEnqueueTask(
std::unique_ptr<Task>(new GetAllChannelIDsTask(std::move(callback))));
}
void DefaultChannelIDStore::Flush() {
store_->Flush();
}
int DefaultChannelIDStore::GetChannelIDCount() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
return channel_ids_.size();
}
void DefaultChannelIDStore::SetForceKeepSessionState() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
InitIfNecessary();
if (store_)
store_->SetForceKeepSessionState();
}
DefaultChannelIDStore::~DefaultChannelIDStore() {
DeleteAllInMemory();
}
void DefaultChannelIDStore::DeleteAllInMemory() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
for (auto it = channel_ids_.begin(); it != channel_ids_.end(); ++it) {
delete it->second;
}
channel_ids_.clear();
}
void DefaultChannelIDStore::InitStore() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
DCHECK(store_) << "Store must exist to initialize";
DCHECK(!loaded_);
store_->Load(base::Bind(&DefaultChannelIDStore::OnLoaded,
weak_ptr_factory_.GetWeakPtr()));
}
void DefaultChannelIDStore::OnLoaded(
std::unique_ptr<std::vector<std::unique_ptr<ChannelID>>> channel_ids) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
for (auto it = channel_ids->begin(); it != channel_ids->end(); ++it) {
DCHECK(channel_ids_.find((*it)->server_identifier()) ==
channel_ids_.end());
std::string ident = (*it)->server_identifier();
channel_ids_[ident] = it->release();
}
channel_ids->clear();
loaded_ = true;
for (std::unique_ptr<Task>& i : waiting_tasks_)
i->Run(this);
waiting_tasks_.clear();
}
void DefaultChannelIDStore::SyncSetChannelID(
std::unique_ptr<ChannelID> channel_id) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
DCHECK(loaded_);
InternalDeleteChannelID(channel_id->server_identifier());
InternalInsertChannelID(std::move(channel_id));
}
void DefaultChannelIDStore::SyncDeleteChannelID(
const std::string& server_identifier) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
DCHECK(loaded_);
InternalDeleteChannelID(server_identifier);
}
void DefaultChannelIDStore::SyncDeleteForDomainsCreatedBetween(
const base::Callback<bool(const std::string&)>& domain_predicate,
base::Time delete_begin,
base::Time delete_end) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
DCHECK(loaded_);
for (auto it = channel_ids_.begin(); it != channel_ids_.end();) {
auto cur = it;
++it;
ChannelID* channel_id = cur->second;
if ((delete_begin.is_null() ||
channel_id->creation_time() >= delete_begin) &&
(delete_end.is_null() || channel_id->creation_time() < delete_end) &&
domain_predicate.Run(channel_id->server_identifier())) {
if (store_)
store_->DeleteChannelID(*channel_id);
delete channel_id;
channel_ids_.erase(cur);
}
}
}
void DefaultChannelIDStore::SyncGetAllChannelIDs(
ChannelIDList* channel_id_list) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
DCHECK(loaded_);
for (auto it = channel_ids_.begin(); it != channel_ids_.end(); ++it)
channel_id_list->push_back(*it->second);
}
void DefaultChannelIDStore::EnqueueTask(std::unique_ptr<Task> task) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
DCHECK(!loaded_);
waiting_tasks_.push_back(std::move(task));
}
void DefaultChannelIDStore::RunOrEnqueueTask(std::unique_ptr<Task> task) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
InitIfNecessary();
if (!loaded_) {
EnqueueTask(std::move(task));
return;
}
task->Run(this);
}
void DefaultChannelIDStore::InternalDeleteChannelID(
const std::string& server_identifier) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
DCHECK(loaded_);
auto it = channel_ids_.find(server_identifier);
if (it == channel_ids_.end())
return; // There is nothing to delete.
ChannelID* channel_id = it->second;
if (store_)
store_->DeleteChannelID(*channel_id);
channel_ids_.erase(it);
delete channel_id;
}
void DefaultChannelIDStore::InternalInsertChannelID(
std::unique_ptr<ChannelID> channel_id) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
DCHECK(loaded_);
if (store_)
store_->AddChannelID(*channel_id);
const std::string& server_identifier = channel_id->server_identifier();
channel_ids_[server_identifier] = channel_id.release();
}
bool DefaultChannelIDStore::IsEphemeral() {
return !store_;
}
DefaultChannelIDStore::PersistentStore::PersistentStore() = default;
DefaultChannelIDStore::PersistentStore::~PersistentStore() = default;
} // namespace net