| Index: chrome/browser/policy/component_cloud_policy_updater.cc
|
| diff --git a/chrome/browser/policy/component_cloud_policy_updater.cc b/chrome/browser/policy/component_cloud_policy_updater.cc
|
| deleted file mode 100644
|
| index 1ce3f275429949b72c86f12b543789851ead7ce5..0000000000000000000000000000000000000000
|
| --- a/chrome/browser/policy/component_cloud_policy_updater.cc
|
| +++ /dev/null
|
| @@ -1,427 +0,0 @@
|
| -// Copyright (c) 2013 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 "chrome/browser/policy/component_cloud_policy_updater.h"
|
| -
|
| -#include <string>
|
| -
|
| -#include "base/bind.h"
|
| -#include "base/location.h"
|
| -#include "base/logging.h"
|
| -#include "base/sequenced_task_runner.h"
|
| -#include "base/stl_util.h"
|
| -#include "chrome/browser/policy/component_cloud_policy_store.h"
|
| -#include "chrome/browser/policy/proto/chrome_extension_policy.pb.h"
|
| -#include "chrome/browser/policy/proto/device_management_backend.pb.h"
|
| -#include "googleurl/src/gurl.h"
|
| -#include "net/base/backoff_entry.h"
|
| -#include "net/base/load_flags.h"
|
| -#include "net/base/net_errors.h"
|
| -#include "net/url_request/url_fetcher.h"
|
| -#include "net/url_request/url_fetcher_delegate.h"
|
| -#include "net/url_request/url_request_context_getter.h"
|
| -#include "net/url_request/url_request_status.h"
|
| -
|
| -namespace em = enterprise_management;
|
| -
|
| -namespace policy {
|
| -
|
| -namespace {
|
| -
|
| -// The maximum size of the serialized policy protobuf.
|
| -const size_t kPolicyProtoMaxSize = 16 * 1024;
|
| -
|
| -// The maximum size of the downloaded policy data.
|
| -const int64 kPolicyDataMaxSize = 5 * 1024 * 1024;
|
| -
|
| -// Policies for exponential backoff of failed requests. There are 3 policies,
|
| -// corresponding to the 3 RetrySchedule enum values below.
|
| -
|
| -// For temporary errors (HTTP 500, RST, etc).
|
| -const net::BackoffEntry::Policy kRetrySoonPolicy = {
|
| - // Number of initial errors to ignore before starting to back off.
|
| - 0,
|
| -
|
| - // Initial delay in ms: 60 seconds.
|
| - 1000 * 60,
|
| -
|
| - // Factor by which the waiting time is multiplied.
|
| - 2,
|
| -
|
| - // Fuzzing percentage; this spreads delays randomly between 80% and 100%
|
| - // of the calculated time.
|
| - 0.20,
|
| -
|
| - // Maximum delay in ms: 12 hours.
|
| - 1000 * 60 * 60 * 12,
|
| -
|
| - // When to discard an entry: never.
|
| - -1,
|
| -
|
| - // |always_use_initial_delay|; false means that the initial delay is
|
| - // applied after the first error, and starts backing off from there.
|
| - false,
|
| -};
|
| -
|
| -// For other errors (request failed, server errors).
|
| -const net::BackoffEntry::Policy kRetryLaterPolicy = {
|
| - // Number of initial errors to ignore before starting to back off.
|
| - 0,
|
| -
|
| - // Initial delay in ms: 1 hour.
|
| - 1000 * 60 * 60,
|
| -
|
| - // Factor by which the waiting time is multiplied.
|
| - 2,
|
| -
|
| - // Fuzzing percentage; this spreads delays randomly between 80% and 100%
|
| - // of the calculated time.
|
| - 0.20,
|
| -
|
| - // Maximum delay in ms: 12 hours.
|
| - 1000 * 60 * 60 * 12,
|
| -
|
| - // When to discard an entry: never.
|
| - -1,
|
| -
|
| - // |always_use_initial_delay|; false means that the initial delay is
|
| - // applied after the first error, and starts backing off from there.
|
| - false,
|
| -};
|
| -
|
| -// When the data fails validation (maybe because the policy URL and the data
|
| -// served at that URL are out of sync). This essentially retries every 12 hours,
|
| -// with some random jitter.
|
| -const net::BackoffEntry::Policy kRetryMuchLaterPolicy = {
|
| - // Number of initial errors to ignore before starting to back off.
|
| - 0,
|
| -
|
| - // Initial delay in ms: 12 hours.
|
| - 1000 * 60 * 60 * 12,
|
| -
|
| - // Factor by which the waiting time is multiplied.
|
| - 2,
|
| -
|
| - // Fuzzing percentage; this spreads delays randomly between 80% and 100%
|
| - // of the calculated time.
|
| - 0.20,
|
| -
|
| - // Maximum delay in ms: 12 hours.
|
| - 1000 * 60 * 60 * 12,
|
| -
|
| - // When to discard an entry: never.
|
| - -1,
|
| -
|
| - // |always_use_initial_delay|; false means that the initial delay is
|
| - // applied after the first error, and starts backing off from there.
|
| - false,
|
| -};
|
| -
|
| -// Maximum number of retries for requests that aren't likely to get a
|
| -// different response (e.g. HTTP 4xx replies).
|
| -const int kMaxLimitedRetries = 3;
|
| -
|
| -} // namespace
|
| -
|
| -// Each FetchJob contains the data about a particular component, and handles
|
| -// the downloading of its corresponding data. These objects are owned by the
|
| -// updater, and the updater always outlives FetchJobs.
|
| -// A FetchJob can be scheduled for a retry later, but its data never changes.
|
| -// If the ExternalPolicyData for a particular component changes then a new
|
| -// FetchJob is created, and the previous one is discarded.
|
| -class ComponentCloudPolicyUpdater::FetchJob
|
| - : public base::SupportsWeakPtr<FetchJob>,
|
| - public net::URLFetcherDelegate {
|
| - public:
|
| - FetchJob(ComponentCloudPolicyUpdater* updater,
|
| - const PolicyNamespace& ns,
|
| - const std::string& serialized_response,
|
| - const em::ExternalPolicyData& data);
|
| - virtual ~FetchJob();
|
| -
|
| - const PolicyNamespace& policy_namespace() const { return ns_; }
|
| -
|
| - // Returns true if |other| equals |data_|.
|
| - bool ParamsEquals(const em::ExternalPolicyData& other);
|
| -
|
| - void StartJob();
|
| -
|
| - // URLFetcherDelegate implementation:
|
| - virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE;
|
| - virtual void OnURLFetchDownloadProgress(const net::URLFetcher* source,
|
| - int64 current,
|
| - int64 total) OVERRIDE;
|
| -
|
| - private:
|
| - void OnSucceeded();
|
| - void OnFailed(net::BackoffEntry* backoff_entry);
|
| - void Schedule();
|
| -
|
| - // Always valid as long as |this| is alive.
|
| - ComponentCloudPolicyUpdater* updater_;
|
| -
|
| - const PolicyNamespace ns_;
|
| - const std::string serialized_response_;
|
| - const em::ExternalPolicyData data_;
|
| -
|
| - // If |fetcher_| exists then |this| is the current job, and must call either
|
| - // OnSucceeded or OnFailed.
|
| - scoped_ptr<net::URLFetcher> fetcher_;
|
| -
|
| - // Some errors should trigger a limited number of retries, even with backoff.
|
| - // This counts the number of such retries, to stop retrying once the limit
|
| - // is reached.
|
| - int limited_retries_count_;
|
| -
|
| - // Various delays to retry a failed download, depending on the failure reason.
|
| - net::BackoffEntry retry_soon_entry_;
|
| - net::BackoffEntry retry_later_entry_;
|
| - net::BackoffEntry retry_much_later_entry_;
|
| -
|
| - DISALLOW_COPY_AND_ASSIGN(FetchJob);
|
| -};
|
| -
|
| -ComponentCloudPolicyUpdater::FetchJob::FetchJob(
|
| - ComponentCloudPolicyUpdater* updater,
|
| - const PolicyNamespace& ns,
|
| - const std::string& serialized_response,
|
| - const em::ExternalPolicyData& data)
|
| - : updater_(updater),
|
| - ns_(ns),
|
| - serialized_response_(serialized_response),
|
| - data_(data),
|
| - limited_retries_count_(0),
|
| - retry_soon_entry_(&kRetrySoonPolicy),
|
| - retry_later_entry_(&kRetryLaterPolicy),
|
| - retry_much_later_entry_(&kRetryMuchLaterPolicy) {}
|
| -
|
| -ComponentCloudPolicyUpdater::FetchJob::~FetchJob() {
|
| - if (fetcher_) {
|
| - fetcher_.reset();
|
| - // This is the current job; inform the updater that it was cancelled.
|
| - updater_->OnJobFailed(this);
|
| - }
|
| -}
|
| -
|
| -bool ComponentCloudPolicyUpdater::FetchJob::ParamsEquals(
|
| - const em::ExternalPolicyData& other) {
|
| - return data_.download_url() == other.download_url() &&
|
| - data_.secure_hash() == other.secure_hash() &&
|
| - data_.download_auth_method() == other.download_auth_method();
|
| -}
|
| -
|
| -void ComponentCloudPolicyUpdater::FetchJob::StartJob() {
|
| - fetcher_.reset(net::URLFetcher::Create(
|
| - 0, GURL(data_.download_url()), net::URLFetcher::GET, this));
|
| - fetcher_->SetRequestContext(updater_->request_context_);
|
| - fetcher_->SetLoadFlags(net::LOAD_BYPASS_CACHE |
|
| - net::LOAD_DISABLE_CACHE |
|
| - net::LOAD_DO_NOT_SAVE_COOKIES |
|
| - net::LOAD_IS_DOWNLOAD |
|
| - net::LOAD_DO_NOT_SEND_COOKIES |
|
| - net::LOAD_DO_NOT_SEND_AUTH_DATA);
|
| - fetcher_->SetAutomaticallyRetryOnNetworkChanges(3);
|
| - fetcher_->Start();
|
| -}
|
| -
|
| -void ComponentCloudPolicyUpdater::FetchJob::OnURLFetchComplete(
|
| - const net::URLFetcher* source) {
|
| - DCHECK(source == fetcher_.get());
|
| -
|
| - const net::URLRequestStatus status = source->GetStatus();
|
| - if (status.status() != net::URLRequestStatus::SUCCESS) {
|
| - if (status.error() == net::ERR_CONNECTION_RESET ||
|
| - status.error() == net::ERR_TEMPORARILY_THROTTLED) {
|
| - // The connection was interrupted; try again soon.
|
| - OnFailed(&retry_soon_entry_);
|
| - return;
|
| - } else {
|
| - // Other network error; try again later.
|
| - OnFailed(&retry_later_entry_);
|
| - return;
|
| - }
|
| - } else {
|
| - // Status is success; inspect the HTTP response code.
|
| - if (source->GetResponseCode() >= 500) {
|
| - // Problem at the server; try again soon.
|
| - OnFailed(&retry_soon_entry_);
|
| - return;
|
| - } else if (source->GetResponseCode() >= 400) {
|
| - // Client error; this is unlikely to go away. Retry later, and give up
|
| - // retrying after 3 attempts.
|
| - OnFailed(limited_retries_count_ < kMaxLimitedRetries ? &retry_later_entry_
|
| - : NULL);
|
| - limited_retries_count_++;
|
| - return;
|
| - } else if (source->GetResponseCode() != 200) {
|
| - // Other HTTP failure; try again later.
|
| - OnFailed(&retry_later_entry_);
|
| - return;
|
| - }
|
| - }
|
| -
|
| - std::string data;
|
| - if (!source->GetResponseAsString(&data) ||
|
| - static_cast<int64>(data.size()) > kPolicyDataMaxSize ||
|
| - !updater_->store_->Store(
|
| - ns_, serialized_response_, data_.secure_hash(), data)) {
|
| - // Failed to retrieve |data|, or it exceeds the size limit, or it failed
|
| - // validation. This may be a temporary error at the download URL.
|
| - OnFailed(&retry_much_later_entry_);
|
| - return;
|
| - }
|
| -
|
| - OnSucceeded();
|
| -}
|
| -
|
| -void ComponentCloudPolicyUpdater::FetchJob::OnURLFetchDownloadProgress(
|
| - const net::URLFetcher* source,
|
| - int64 current,
|
| - int64 total) {
|
| - DCHECK(source == fetcher_.get());
|
| - // Reject the data if it exceeds the size limit. The content length is in
|
| - // |total|, and it may be -1 when not known.
|
| - if (current > kPolicyDataMaxSize || total > kPolicyDataMaxSize)
|
| - OnFailed(&retry_much_later_entry_);
|
| -}
|
| -
|
| -void ComponentCloudPolicyUpdater::FetchJob::OnSucceeded() {
|
| - fetcher_.reset();
|
| - updater_->OnJobSucceeded(this);
|
| -}
|
| -
|
| -void ComponentCloudPolicyUpdater::FetchJob::OnFailed(net::BackoffEntry* entry) {
|
| - fetcher_.reset();
|
| -
|
| - if (entry) {
|
| - entry->InformOfRequest(false);
|
| -
|
| - // If new ExternalPolicyData for this component is fetched then this job
|
| - // will be deleted, and the retry task is invalidated. A new job using the
|
| - // new data will be scheduled immediately in that case.
|
| - updater_->task_runner_->PostDelayedTask(
|
| - FROM_HERE,
|
| - base::Bind(&FetchJob::Schedule, AsWeakPtr()),
|
| - entry->GetTimeUntilRelease());
|
| - }
|
| -
|
| - updater_->OnJobFailed(this);
|
| -}
|
| -
|
| -void ComponentCloudPolicyUpdater::FetchJob::Schedule() {
|
| - updater_->ScheduleJob(this);
|
| -}
|
| -
|
| -ComponentCloudPolicyUpdater::ComponentCloudPolicyUpdater(
|
| - scoped_refptr<base::SequencedTaskRunner> task_runner,
|
| - scoped_refptr<net::URLRequestContextGetter> request_context,
|
| - ComponentCloudPolicyStore* store)
|
| - : task_runner_(task_runner),
|
| - request_context_(request_context),
|
| - store_(store),
|
| - shutting_down_(false) {
|
| - DCHECK(task_runner_->RunsTasksOnCurrentThread());
|
| -}
|
| -
|
| -ComponentCloudPolicyUpdater::~ComponentCloudPolicyUpdater() {
|
| - DCHECK(CalledOnValidThread());
|
| - shutting_down_ = true;
|
| - STLDeleteValues(&fetch_jobs_);
|
| -}
|
| -
|
| -void ComponentCloudPolicyUpdater::UpdateExternalPolicy(
|
| - scoped_ptr<em::PolicyFetchResponse> response) {
|
| - DCHECK(CalledOnValidThread());
|
| -
|
| - // Keep a serialized copy of |response|, to cache it later.
|
| - // The policy is also rejected if it exceeds the maximum size.
|
| - std::string serialized_response;
|
| - if (!response->SerializeToString(&serialized_response) ||
|
| - serialized_response.size() > kPolicyProtoMaxSize) {
|
| - return;
|
| - }
|
| -
|
| - // Validate the policy before doing anything else.
|
| - PolicyNamespace ns;
|
| - em::ExternalPolicyData data;
|
| - if (!store_->ValidatePolicy(response.Pass(), &ns, &data)) {
|
| - LOG(ERROR) << "Failed to validate component policy fetched from DMServer";
|
| - return;
|
| - }
|
| -
|
| - // Maybe the data for this hash has already been downloaded and cached.
|
| - if (data.has_secure_hash() &&
|
| - data.secure_hash() == store_->GetCachedHash(ns)) {
|
| - return;
|
| - }
|
| -
|
| - // TODO(joaodasilva): implement the other two auth methods.
|
| - if (data.download_auth_method() != em::ExternalPolicyData::NONE)
|
| - return;
|
| -
|
| - // Check for an existing job for this component.
|
| - FetchJob* job = fetch_jobs_[ns];
|
| - if (job) {
|
| - // Check if this data has already been seen.
|
| - if (job->ParamsEquals(data))
|
| - return;
|
| -
|
| - // The existing job is obsolete, cancel it. If |job| is in the job queue
|
| - // then its WeakPtr will be invalided and skipped in the next StartNextJob.
|
| - // If |job| is the current job then it will immediately call OnJobFailed.
|
| - delete job;
|
| - fetch_jobs_.erase(ns);
|
| - }
|
| -
|
| - if (data.download_url().empty()) {
|
| - // There is no policy for this component, or the policy has been removed.
|
| - store_->Delete(ns);
|
| - } else {
|
| - // Start a new job with the new or updated data.
|
| - job = new FetchJob(this, ns, serialized_response, data);
|
| - fetch_jobs_[ns] = job;
|
| - ScheduleJob(job);
|
| - }
|
| -}
|
| -
|
| -void ComponentCloudPolicyUpdater::ScheduleJob(FetchJob* job) {
|
| - job_queue_.push(job->AsWeakPtr());
|
| - // The job at the front of the queue is always the current job. If |job| is
|
| - // at the front then start it immediately. An invalid job is never at the
|
| - // front; as soon as it becomes invalidated it will call OnJobFailed() and
|
| - // flush the queue.
|
| - if (job == job_queue_.front().get())
|
| - StartNextJob();
|
| -}
|
| -
|
| -void ComponentCloudPolicyUpdater::StartNextJob() {
|
| - // Some of the jobs may have been invalidated, and have to be skipped.
|
| - while (!job_queue_.empty() && !job_queue_.front())
|
| - job_queue_.pop();
|
| -
|
| - // A started job will always call OnJobSucceeded or OnJobFailed.
|
| - if (!job_queue_.empty() && !shutting_down_)
|
| - job_queue_.front()->StartJob();
|
| -}
|
| -
|
| -void ComponentCloudPolicyUpdater::OnJobSucceeded(FetchJob* job) {
|
| - DCHECK(fetch_jobs_[job->policy_namespace()] == job);
|
| - DCHECK(!job_queue_.empty() && job_queue_.front() == job);
|
| - fetch_jobs_.erase(job->policy_namespace());
|
| - delete job;
|
| - job_queue_.pop();
|
| - StartNextJob();
|
| -}
|
| -
|
| -void ComponentCloudPolicyUpdater::OnJobFailed(FetchJob* job) {
|
| - DCHECK(fetch_jobs_[job->policy_namespace()] == job);
|
| - DCHECK(!job_queue_.empty() && job_queue_.front() == job);
|
| - // The job isn't deleted when it fails because a retry attempt may have been
|
| - // scheduled. It's also kept so that UpdateExternalPolicy() can see the
|
| - // current data, and avoid a new fetch if the data hasn't changed.
|
| - job_queue_.pop();
|
| - StartNextJob();
|
| -}
|
| -
|
| -} // namespace policy
|
|
|