123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198 |
- // 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 "net/proxy_resolution/polling_proxy_config_service.h"
- #include <memory>
- #include "base/bind.h"
- #include "base/location.h"
- #include "base/observer_list.h"
- #include "base/synchronization/lock.h"
- #include "base/task/single_thread_task_runner.h"
- #include "base/task/thread_pool.h"
- #include "base/threading/thread_task_runner_handle.h"
- #include "net/proxy_resolution/proxy_config_with_annotation.h"
- namespace net {
- // Reference-counted wrapper that does all the work (needs to be
- // reference-counted since we post tasks between threads; may outlive
- // the parent PollingProxyConfigService).
- class PollingProxyConfigService::Core
- : public base::RefCountedThreadSafe<PollingProxyConfigService::Core> {
- public:
- Core(base::TimeDelta poll_interval,
- GetConfigFunction get_config_func,
- const NetworkTrafficAnnotationTag& traffic_annotation)
- : get_config_func_(get_config_func),
- poll_interval_(poll_interval),
- traffic_annotation_(traffic_annotation) {}
- // Called when the parent PollingProxyConfigService is destroyed
- // (observers should not be called past this point).
- void Orphan() {
- base::AutoLock lock(lock_);
- origin_task_runner_ = nullptr;
- }
- bool GetLatestProxyConfig(ProxyConfigWithAnnotation* config) {
- LazyInitializeOriginLoop();
- DCHECK(origin_task_runner_->BelongsToCurrentThread());
- OnLazyPoll();
- // If we have already retrieved the proxy settings (on worker thread)
- // then return what we last saw.
- if (has_config_) {
- *config = last_config_;
- return true;
- }
- return false;
- }
- void AddObserver(Observer* observer) {
- LazyInitializeOriginLoop();
- DCHECK(origin_task_runner_->BelongsToCurrentThread());
- observers_.AddObserver(observer);
- }
- void RemoveObserver(Observer* observer) {
- DCHECK(origin_task_runner_->BelongsToCurrentThread());
- observers_.RemoveObserver(observer);
- }
- // Check for a new configuration if enough time has elapsed.
- void OnLazyPoll() {
- LazyInitializeOriginLoop();
- DCHECK(origin_task_runner_->BelongsToCurrentThread());
- if (last_poll_time_.is_null() ||
- (base::TimeTicks::Now() - last_poll_time_) > poll_interval_) {
- CheckForChangesNow();
- }
- }
- void CheckForChangesNow() {
- LazyInitializeOriginLoop();
- DCHECK(origin_task_runner_->BelongsToCurrentThread());
- if (poll_task_outstanding_) {
- // Only allow one task to be outstanding at a time. If we get a poll
- // request while we are busy, we will defer it until the current poll
- // completes.
- poll_task_queued_ = true;
- return;
- }
- last_poll_time_ = base::TimeTicks::Now();
- poll_task_outstanding_ = true;
- poll_task_queued_ = false;
- base::ThreadPool::PostTask(
- FROM_HERE,
- {base::MayBlock(), base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
- base::BindOnce(&Core::PollAsync, this, get_config_func_));
- }
- private:
- friend class base::RefCountedThreadSafe<Core>;
- ~Core() = default;
- void PollAsync(GetConfigFunction func) {
- ProxyConfigWithAnnotation config;
- func(traffic_annotation_, &config);
- base::AutoLock lock(lock_);
- if (origin_task_runner_.get()) {
- origin_task_runner_->PostTask(
- FROM_HERE, base::BindOnce(&Core::GetConfigCompleted, this, config));
- }
- }
- // Called after the worker thread has finished retrieving a configuration.
- void GetConfigCompleted(const ProxyConfigWithAnnotation& config) {
- DCHECK(poll_task_outstanding_);
- poll_task_outstanding_ = false;
- if (!origin_task_runner_.get())
- return; // Was orphaned (parent has already been destroyed).
- DCHECK(origin_task_runner_->BelongsToCurrentThread());
- if (!has_config_ || !last_config_.value().Equals(config.value())) {
- // If the configuration has changed, notify the observers.
- has_config_ = true;
- last_config_ = config;
- for (auto& observer : observers_)
- observer.OnProxyConfigChanged(config, ProxyConfigService::CONFIG_VALID);
- }
- if (poll_task_queued_)
- CheckForChangesNow();
- }
- void LazyInitializeOriginLoop() {
- // TODO(eroman): Really this should be done in the constructor, but some
- // consumers constructing the ProxyConfigService on threads
- // other than the ProxyConfigService's main thread, so we
- // can't cache the main thread for the purpose of DCHECKs
- // until the first call is made.
- if (!have_initialized_origin_runner_) {
- origin_task_runner_ = base::ThreadTaskRunnerHandle::Get();
- have_initialized_origin_runner_ = true;
- }
- }
- GetConfigFunction get_config_func_;
- base::ObserverList<Observer>::Unchecked observers_;
- ProxyConfigWithAnnotation last_config_;
- base::TimeTicks last_poll_time_;
- base::TimeDelta poll_interval_;
- const NetworkTrafficAnnotationTag traffic_annotation_;
- base::Lock lock_;
- scoped_refptr<base::SingleThreadTaskRunner> origin_task_runner_;
- bool have_initialized_origin_runner_ = false;
- bool has_config_ = false;
- bool poll_task_outstanding_ = false;
- bool poll_task_queued_ = false;
- };
- void PollingProxyConfigService::AddObserver(Observer* observer) {
- core_->AddObserver(observer);
- }
- void PollingProxyConfigService::RemoveObserver(Observer* observer) {
- core_->RemoveObserver(observer);
- }
- ProxyConfigService::ConfigAvailability
- PollingProxyConfigService::GetLatestProxyConfig(
- ProxyConfigWithAnnotation* config) {
- return core_->GetLatestProxyConfig(config) ? CONFIG_VALID : CONFIG_PENDING;
- }
- void PollingProxyConfigService::OnLazyPoll() {
- core_->OnLazyPoll();
- }
- PollingProxyConfigService::PollingProxyConfigService(
- base::TimeDelta poll_interval,
- GetConfigFunction get_config_func,
- const NetworkTrafficAnnotationTag& traffic_annotation)
- : core_(base::MakeRefCounted<Core>(poll_interval,
- get_config_func,
- traffic_annotation)) {}
- PollingProxyConfigService::~PollingProxyConfigService() {
- core_->Orphan();
- }
- void PollingProxyConfigService::CheckForChangesNow() {
- core_->CheckForChangesNow();
- }
- } // namespace net
|