This source file includes following definitions.
- max_size
- retry_much_later_entry_
- key
- request
- Start
- OnFetchFinished
- OnFailed
- Reschedule
- shutting_down_
- FetchExternalData
- CancelExternalDataFetch
- StartNextJobs
- ScheduleJob
- OnJobSucceeded
- OnJobFailed
#include "components/policy/core/common/cloud/external_policy_data_updater.h"
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/callback.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/sequenced_task_runner.h"
#include "base/stl_util.h"
#include "components/policy/core/common/cloud/external_policy_data_fetcher.h"
#include "crypto/sha2.h"
#include "net/base/backoff_entry.h"
#include "url/gurl.h"
namespace policy {
namespace {
const net::BackoffEntry::Policy kRetrySoonPolicy = {
0,
1000 * 60,
2,
0.20,
1000 * 60 * 60 * 12,
-1,
false,
};
const net::BackoffEntry::Policy kRetryLaterPolicy = {
0,
1000 * 60 * 60,
2,
0.20,
1000 * 60 * 60 * 12,
-1,
false,
};
const net::BackoffEntry::Policy kRetryMuchLaterPolicy = {
0,
1000 * 60 * 60 * 12,
2,
0.20,
1000 * 60 * 60 * 12,
-1,
false,
};
const int kMaxLimitedRetries = 3;
}
class ExternalPolicyDataUpdater::FetchJob
: public base::SupportsWeakPtr<FetchJob> {
public:
FetchJob(ExternalPolicyDataUpdater* updater,
const std::string& key,
const ExternalPolicyDataUpdater::Request& request,
const ExternalPolicyDataUpdater::FetchSuccessCallback& callback);
virtual ~FetchJob();
const std::string& key() const;
const ExternalPolicyDataUpdater::Request& request() const;
void Start();
void OnFetchFinished(ExternalPolicyDataFetcher::Result result,
scoped_ptr<std::string> data);
private:
void OnFailed(net::BackoffEntry* backoff_entry);
void Reschedule();
ExternalPolicyDataUpdater* updater_;
const std::string key_;
const ExternalPolicyDataUpdater::Request request_;
ExternalPolicyDataUpdater::FetchSuccessCallback callback_;
ExternalPolicyDataFetcher::Job* fetch_job_;
int limited_retries_remaining_;
net::BackoffEntry retry_soon_entry_;
net::BackoffEntry retry_later_entry_;
net::BackoffEntry retry_much_later_entry_;
DISALLOW_COPY_AND_ASSIGN(FetchJob);
};
ExternalPolicyDataUpdater::Request::Request() {
}
ExternalPolicyDataUpdater::Request::Request(const std::string& url,
const std::string& hash,
int64 max_size)
: url(url), hash(hash), max_size(max_size) {
}
bool ExternalPolicyDataUpdater::Request::operator==(
const Request& other) const {
return url == other.url && hash == other.hash && max_size == other.max_size;
}
ExternalPolicyDataUpdater::FetchJob::FetchJob(
ExternalPolicyDataUpdater* updater,
const std::string& key,
const ExternalPolicyDataUpdater::Request& request,
const ExternalPolicyDataUpdater::FetchSuccessCallback& callback)
: updater_(updater),
key_(key),
request_(request),
callback_(callback),
fetch_job_(NULL),
limited_retries_remaining_(kMaxLimitedRetries),
retry_soon_entry_(&kRetrySoonPolicy),
retry_later_entry_(&kRetryLaterPolicy),
retry_much_later_entry_(&kRetryMuchLaterPolicy) {
}
ExternalPolicyDataUpdater::FetchJob::~FetchJob() {
if (fetch_job_) {
updater_->external_policy_data_fetcher_->CancelJob(fetch_job_);
updater_->OnJobFailed(this);
}
}
const std::string& ExternalPolicyDataUpdater::FetchJob::key() const {
return key_;
}
const ExternalPolicyDataUpdater::Request&
ExternalPolicyDataUpdater::FetchJob::request() const {
return request_;
}
void ExternalPolicyDataUpdater::FetchJob::Start() {
DCHECK(!fetch_job_);
fetch_job_ = updater_->external_policy_data_fetcher_->StartJob(
GURL(request_.url), request_.max_size,
base::Bind(&ExternalPolicyDataUpdater::FetchJob::OnFetchFinished,
base::Unretained(this)));
}
void ExternalPolicyDataUpdater::FetchJob::OnFetchFinished(
ExternalPolicyDataFetcher::Result result,
scoped_ptr<std::string> data) {
fetch_job_ = NULL;
switch (result) {
case ExternalPolicyDataFetcher::CONNECTION_INTERRUPTED:
OnFailed(&retry_soon_entry_);
return;
case ExternalPolicyDataFetcher::NETWORK_ERROR:
OnFailed(&retry_later_entry_);
return;
case ExternalPolicyDataFetcher::SERVER_ERROR:
OnFailed(&retry_soon_entry_);
return;
case ExternalPolicyDataFetcher::CLIENT_ERROR:
OnFailed(limited_retries_remaining_ ? &retry_later_entry_ : NULL);
if (limited_retries_remaining_)
--limited_retries_remaining_;
return;
case ExternalPolicyDataFetcher::HTTP_ERROR:
OnFailed(&retry_later_entry_);
return;
case ExternalPolicyDataFetcher::MAX_SIZE_EXCEEDED:
OnFailed(&retry_much_later_entry_);
return;
case ExternalPolicyDataFetcher::SUCCESS:
break;
}
if (crypto::SHA256HashString(*data) != request_.hash) {
OnFailed(&retry_much_later_entry_);
return;
}
if (!callback_.Run(*data)) {
OnFailed(&retry_much_later_entry_);
return;
}
updater_->OnJobSucceeded(this);
}
void ExternalPolicyDataUpdater::FetchJob::OnFailed(net::BackoffEntry* entry) {
if (entry) {
entry->InformOfRequest(false);
updater_->task_runner_->PostDelayedTask(
FROM_HERE,
base::Bind(&FetchJob::Reschedule, AsWeakPtr()),
entry->GetTimeUntilRelease());
}
updater_->OnJobFailed(this);
}
void ExternalPolicyDataUpdater::FetchJob::Reschedule() {
updater_->ScheduleJob(this);
}
ExternalPolicyDataUpdater::ExternalPolicyDataUpdater(
scoped_refptr<base::SequencedTaskRunner> task_runner,
scoped_ptr<ExternalPolicyDataFetcher> external_policy_data_fetcher,
size_t max_parallel_fetches)
: task_runner_(task_runner),
external_policy_data_fetcher_(external_policy_data_fetcher.release()),
max_parallel_jobs_(max_parallel_fetches),
running_jobs_(0),
shutting_down_(false) {
DCHECK(task_runner_->RunsTasksOnCurrentThread());
}
ExternalPolicyDataUpdater::~ExternalPolicyDataUpdater() {
DCHECK(task_runner_->RunsTasksOnCurrentThread());
shutting_down_ = true;
STLDeleteValues(&job_map_);
}
void ExternalPolicyDataUpdater::FetchExternalData(
const std::string key,
const Request& request,
const FetchSuccessCallback& callback) {
DCHECK(task_runner_->RunsTasksOnCurrentThread());
FetchJob* job = job_map_[key];
if (job) {
if (job->request() == request)
return;
delete job;
job_map_.erase(key);
}
job = new FetchJob(this, key, request, callback);
job_map_[key] = job;
ScheduleJob(job);
}
void ExternalPolicyDataUpdater::CancelExternalDataFetch(
const std::string& key) {
DCHECK(task_runner_->RunsTasksOnCurrentThread());
std::map<std::string, FetchJob*>::iterator job = job_map_.find(key);
if (job != job_map_.end()) {
delete job->second;
job_map_.erase(job);
}
}
void ExternalPolicyDataUpdater::StartNextJobs() {
if (shutting_down_)
return;
while (running_jobs_ < max_parallel_jobs_ && !job_queue_.empty()) {
FetchJob* job = job_queue_.front().get();
job_queue_.pop();
if (job) {
++running_jobs_;
job->Start();
}
}
}
void ExternalPolicyDataUpdater::ScheduleJob(FetchJob* job) {
DCHECK_EQ(job_map_[job->key()], job);
job_queue_.push(job->AsWeakPtr());
StartNextJobs();
}
void ExternalPolicyDataUpdater::OnJobSucceeded(FetchJob* job) {
DCHECK(running_jobs_);
DCHECK_EQ(job_map_[job->key()], job);
--running_jobs_;
job_map_.erase(job->key());
delete job;
StartNextJobs();
}
void ExternalPolicyDataUpdater::OnJobFailed(FetchJob* job) {
DCHECK(running_jobs_);
DCHECK_EQ(job_map_[job->key()], job);
--running_jobs_;
StartNextJobs();
}
}