QUIC - wait for disk cache to load server config if the server is among
[chromium-blink-merge.git] / net / proxy / polling_proxy_config_service.cc
blob4044e1b5904fb4b8942d7ca5193ec0f564bd50a1
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "net/proxy/polling_proxy_config_service.h"
7 #include "base/bind.h"
8 #include "base/location.h"
9 #include "base/memory/scoped_ptr.h"
10 #include "base/observer_list.h"
11 #include "base/single_thread_task_runner.h"
12 #include "base/synchronization/lock.h"
13 #include "base/thread_task_runner_handle.h"
14 #include "base/threading/worker_pool.h"
15 #include "net/proxy/proxy_config.h"
17 namespace net {
19 // Reference-counted wrapper that does all the work (needs to be
20 // reference-counted since we post tasks between threads; may outlive
21 // the parent PollingProxyConfigService).
22 class PollingProxyConfigService::Core
23 : public base::RefCountedThreadSafe<PollingProxyConfigService::Core> {
24 public:
25 Core(base::TimeDelta poll_interval, GetConfigFunction get_config_func)
26 : get_config_func_(get_config_func),
27 poll_interval_(poll_interval),
28 have_initialized_origin_runner_(false),
29 has_config_(false),
30 poll_task_outstanding_(false),
31 poll_task_queued_(false) {}
33 // Called when the parent PollingProxyConfigService is destroyed
34 // (observers should not be called past this point).
35 void Orphan() {
36 base::AutoLock l(lock_);
37 origin_task_runner_ = NULL;
40 bool GetLatestProxyConfig(ProxyConfig* config) {
41 LazyInitializeOriginLoop();
42 DCHECK(origin_task_runner_->BelongsToCurrentThread());
44 OnLazyPoll();
46 // If we have already retrieved the proxy settings (on worker thread)
47 // then return what we last saw.
48 if (has_config_) {
49 *config = last_config_;
50 return true;
52 return false;
55 void AddObserver(Observer* observer) {
56 LazyInitializeOriginLoop();
57 DCHECK(origin_task_runner_->BelongsToCurrentThread());
58 observers_.AddObserver(observer);
61 void RemoveObserver(Observer* observer) {
62 DCHECK(origin_task_runner_->BelongsToCurrentThread());
63 observers_.RemoveObserver(observer);
66 // Check for a new configuration if enough time has elapsed.
67 void OnLazyPoll() {
68 LazyInitializeOriginLoop();
69 DCHECK(origin_task_runner_->BelongsToCurrentThread());
71 if (last_poll_time_.is_null() ||
72 (base::TimeTicks::Now() - last_poll_time_) > poll_interval_) {
73 CheckForChangesNow();
77 void CheckForChangesNow() {
78 LazyInitializeOriginLoop();
79 DCHECK(origin_task_runner_->BelongsToCurrentThread());
81 if (poll_task_outstanding_) {
82 // Only allow one task to be outstanding at a time. If we get a poll
83 // request while we are busy, we will defer it until the current poll
84 // completes.
85 poll_task_queued_ = true;
86 return;
89 last_poll_time_ = base::TimeTicks::Now();
90 poll_task_outstanding_ = true;
91 poll_task_queued_ = false;
92 base::WorkerPool::PostTask(
93 FROM_HERE,
94 base::Bind(&Core::PollOnWorkerThread, this, get_config_func_),
95 true);
98 private:
99 friend class base::RefCountedThreadSafe<Core>;
100 ~Core() {}
102 void PollOnWorkerThread(GetConfigFunction func) {
103 ProxyConfig config;
104 func(&config);
106 base::AutoLock l(lock_);
107 if (origin_task_runner_.get()) {
108 origin_task_runner_->PostTask(
109 FROM_HERE, base::Bind(&Core::GetConfigCompleted, this, config));
113 // Called after the worker thread has finished retrieving a configuration.
114 void GetConfigCompleted(const ProxyConfig& config) {
115 DCHECK(poll_task_outstanding_);
116 poll_task_outstanding_ = false;
118 if (!origin_task_runner_.get())
119 return; // Was orphaned (parent has already been destroyed).
121 DCHECK(origin_task_runner_->BelongsToCurrentThread());
123 if (!has_config_ || !last_config_.Equals(config)) {
124 // If the configuration has changed, notify the observers.
125 has_config_ = true;
126 last_config_ = config;
127 FOR_EACH_OBSERVER(Observer, observers_,
128 OnProxyConfigChanged(config,
129 ProxyConfigService::CONFIG_VALID));
132 if (poll_task_queued_)
133 CheckForChangesNow();
136 void LazyInitializeOriginLoop() {
137 // TODO(eroman): Really this should be done in the constructor, but right
138 // now chrome is constructing the ProxyConfigService on the
139 // UI thread so we can't cache the IO thread for the purpose
140 // of DCHECKs until the first call is made.
141 if (!have_initialized_origin_runner_) {
142 origin_task_runner_ = base::ThreadTaskRunnerHandle::Get();
143 have_initialized_origin_runner_ = true;
147 GetConfigFunction get_config_func_;
148 base::ObserverList<Observer> observers_;
149 ProxyConfig last_config_;
150 base::TimeTicks last_poll_time_;
151 base::TimeDelta poll_interval_;
153 base::Lock lock_;
154 scoped_refptr<base::SingleThreadTaskRunner> origin_task_runner_;
156 bool have_initialized_origin_runner_;
157 bool has_config_;
158 bool poll_task_outstanding_;
159 bool poll_task_queued_;
162 void PollingProxyConfigService::AddObserver(Observer* observer) {
163 core_->AddObserver(observer);
166 void PollingProxyConfigService::RemoveObserver(Observer* observer) {
167 core_->RemoveObserver(observer);
170 ProxyConfigService::ConfigAvailability
171 PollingProxyConfigService::GetLatestProxyConfig(ProxyConfig* config) {
172 return core_->GetLatestProxyConfig(config) ? CONFIG_VALID : CONFIG_PENDING;
175 void PollingProxyConfigService::OnLazyPoll() {
176 core_->OnLazyPoll();
179 PollingProxyConfigService::PollingProxyConfigService(
180 base::TimeDelta poll_interval,
181 GetConfigFunction get_config_func)
182 : core_(new Core(poll_interval, get_config_func)) {
185 PollingProxyConfigService::~PollingProxyConfigService() {
186 core_->Orphan();
189 void PollingProxyConfigService::CheckForChangesNow() {
190 core_->CheckForChangesNow();
193 } // namespace net