blob: 500340e7bdf6d428084b95c051365ac722b77b10 [file] [log] [blame]
[email protected]a9813302012-04-28 09:29:281// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]119655002010-07-23 06:02:402// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "net/proxy/polling_proxy_config_service.h"
6
danakj8a98ca22016-04-16 02:47:367#include <memory>
8
[email protected]235786812011-12-20 02:15:319#include "base/bind.h"
[email protected]c62dd9d2011-09-21 18:05:4110#include "base/location.h"
[email protected]119655002010-07-23 06:02:4011#include "base/observer_list.h"
pranay.kumar55c065b62015-05-15 04:19:0112#include "base/single_thread_task_runner.h"
[email protected]20305ec2011-01-21 04:55:5213#include "base/synchronization/lock.h"
fdoraya16c9ba2017-02-17 17:51:3914#include "base/task_scheduler/post_task.h"
gabf767595f2016-05-11 18:50:3515#include "base/threading/thread_task_runner_handle.h"
[email protected]119655002010-07-23 06:02:4016#include "net/proxy/proxy_config.h"
17
18namespace net {
19
20// Reference-counted wrapper that does all the work (needs to be
21// reference-counted since we post tasks between threads; may outlive
22// the parent PollingProxyConfigService).
23class PollingProxyConfigService::Core
24 : public base::RefCountedThreadSafe<PollingProxyConfigService::Core> {
25 public:
pranay.kumar55c065b62015-05-15 04:19:0126 Core(base::TimeDelta poll_interval, GetConfigFunction get_config_func)
[email protected]119655002010-07-23 06:02:4027 : get_config_func_(get_config_func),
[email protected]e9b8d0af2010-08-17 04:10:2928 poll_interval_(poll_interval),
pranay.kumar55c065b62015-05-15 04:19:0129 have_initialized_origin_runner_(false),
[email protected]119655002010-07-23 06:02:4030 has_config_(false),
31 poll_task_outstanding_(false),
pranay.kumar55c065b62015-05-15 04:19:0132 poll_task_queued_(false) {}
[email protected]119655002010-07-23 06:02:4033
34 // Called when the parent PollingProxyConfigService is destroyed
35 // (observers should not be called past this point).
36 void Orphan() {
[email protected]20305ec2011-01-21 04:55:5237 base::AutoLock l(lock_);
pranay.kumar55c065b62015-05-15 04:19:0138 origin_task_runner_ = NULL;
[email protected]119655002010-07-23 06:02:4039 }
40
41 bool GetLatestProxyConfig(ProxyConfig* config) {
42 LazyInitializeOriginLoop();
pranay.kumar55c065b62015-05-15 04:19:0143 DCHECK(origin_task_runner_->BelongsToCurrentThread());
[email protected]119655002010-07-23 06:02:4044
45 OnLazyPoll();
46
47 // If we have already retrieved the proxy settings (on worker thread)
48 // then return what we last saw.
49 if (has_config_) {
50 *config = last_config_;
51 return true;
52 }
53 return false;
54 }
55
56 void AddObserver(Observer* observer) {
57 LazyInitializeOriginLoop();
pranay.kumar55c065b62015-05-15 04:19:0158 DCHECK(origin_task_runner_->BelongsToCurrentThread());
[email protected]119655002010-07-23 06:02:4059 observers_.AddObserver(observer);
60 }
61
62 void RemoveObserver(Observer* observer) {
pranay.kumar55c065b62015-05-15 04:19:0163 DCHECK(origin_task_runner_->BelongsToCurrentThread());
[email protected]119655002010-07-23 06:02:4064 observers_.RemoveObserver(observer);
65 }
66
67 // Check for a new configuration if enough time has elapsed.
68 void OnLazyPoll() {
69 LazyInitializeOriginLoop();
pranay.kumar55c065b62015-05-15 04:19:0170 DCHECK(origin_task_runner_->BelongsToCurrentThread());
[email protected]119655002010-07-23 06:02:4071
[email protected]119655002010-07-23 06:02:4072 if (last_poll_time_.is_null() ||
[email protected]e9b8d0af2010-08-17 04:10:2973 (base::TimeTicks::Now() - last_poll_time_) > poll_interval_) {
74 CheckForChangesNow();
[email protected]119655002010-07-23 06:02:4075 }
76 }
77
[email protected]e9b8d0af2010-08-17 04:10:2978 void CheckForChangesNow() {
79 LazyInitializeOriginLoop();
pranay.kumar55c065b62015-05-15 04:19:0180 DCHECK(origin_task_runner_->BelongsToCurrentThread());
[email protected]e9b8d0af2010-08-17 04:10:2981
82 if (poll_task_outstanding_) {
83 // Only allow one task to be outstanding at a time. If we get a poll
84 // request while we are busy, we will defer it until the current poll
85 // completes.
86 poll_task_queued_ = true;
87 return;
88 }
89
90 last_poll_time_ = base::TimeTicks::Now();
91 poll_task_outstanding_ = true;
92 poll_task_queued_ = false;
fdoraya16c9ba2017-02-17 17:51:3993 base::PostTaskWithTraits(
fdoray2f60799d2017-05-03 22:54:5894 FROM_HERE,
95 {base::MayBlock(), base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
fdoraya16c9ba2017-02-17 17:51:3996 base::Bind(&Core::PollAsync, this, get_config_func_));
[email protected]e9b8d0af2010-08-17 04:10:2997 }
98
[email protected]119655002010-07-23 06:02:4099 private:
[email protected]a9813302012-04-28 09:29:28100 friend class base::RefCountedThreadSafe<Core>;
101 ~Core() {}
102
fdoraya16c9ba2017-02-17 17:51:39103 void PollAsync(GetConfigFunction func) {
[email protected]119655002010-07-23 06:02:40104 ProxyConfig config;
105 func(&config);
106
[email protected]20305ec2011-01-21 04:55:52107 base::AutoLock l(lock_);
pranay.kumar55c065b62015-05-15 04:19:01108 if (origin_task_runner_.get()) {
109 origin_task_runner_->PostTask(
[email protected]90499482013-06-01 00:39:50110 FROM_HERE, base::Bind(&Core::GetConfigCompleted, this, config));
[email protected]119655002010-07-23 06:02:40111 }
112 }
113
114 // Called after the worker thread has finished retrieving a configuration.
115 void GetConfigCompleted(const ProxyConfig& config) {
116 DCHECK(poll_task_outstanding_);
117 poll_task_outstanding_ = false;
118
pranay.kumar55c065b62015-05-15 04:19:01119 if (!origin_task_runner_.get())
[email protected]119655002010-07-23 06:02:40120 return; // Was orphaned (parent has already been destroyed).
121
pranay.kumar55c065b62015-05-15 04:19:01122 DCHECK(origin_task_runner_->BelongsToCurrentThread());
[email protected]119655002010-07-23 06:02:40123
124 if (!has_config_ || !last_config_.Equals(config)) {
125 // If the configuration has changed, notify the observers.
126 has_config_ = true;
127 last_config_ = config;
ericwilligers9d64a5f2016-10-18 00:28:49128 for (auto& observer : observers_)
129 observer.OnProxyConfigChanged(config, ProxyConfigService::CONFIG_VALID);
[email protected]119655002010-07-23 06:02:40130 }
[email protected]e9b8d0af2010-08-17 04:10:29131
132 if (poll_task_queued_)
133 CheckForChangesNow();
[email protected]119655002010-07-23 06:02:40134 }
135
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.
pranay.kumar55c065b62015-05-15 04:19:01141 if (!have_initialized_origin_runner_) {
142 origin_task_runner_ = base::ThreadTaskRunnerHandle::Get();
143 have_initialized_origin_runner_ = true;
[email protected]119655002010-07-23 06:02:40144 }
145 }
146
147 GetConfigFunction get_config_func_;
brettw236d3172015-06-03 16:31:43148 base::ObserverList<Observer> observers_;
[email protected]119655002010-07-23 06:02:40149 ProxyConfig last_config_;
150 base::TimeTicks last_poll_time_;
151 base::TimeDelta poll_interval_;
[email protected]119655002010-07-23 06:02:40152
[email protected]20305ec2011-01-21 04:55:52153 base::Lock lock_;
pranay.kumar55c065b62015-05-15 04:19:01154 scoped_refptr<base::SingleThreadTaskRunner> origin_task_runner_;
[email protected]e9b8d0af2010-08-17 04:10:29155
pranay.kumar55c065b62015-05-15 04:19:01156 bool have_initialized_origin_runner_;
[email protected]e9b8d0af2010-08-17 04:10:29157 bool has_config_;
158 bool poll_task_outstanding_;
159 bool poll_task_queued_;
[email protected]119655002010-07-23 06:02:40160};
161
[email protected]119655002010-07-23 06:02:40162void PollingProxyConfigService::AddObserver(Observer* observer) {
163 core_->AddObserver(observer);
164}
165
166void PollingProxyConfigService::RemoveObserver(Observer* observer) {
167 core_->RemoveObserver(observer);
168}
169
[email protected]3a29593d2011-04-11 10:07:52170ProxyConfigService::ConfigAvailability
171 PollingProxyConfigService::GetLatestProxyConfig(ProxyConfig* config) {
172 return core_->GetLatestProxyConfig(config) ? CONFIG_VALID : CONFIG_PENDING;
[email protected]119655002010-07-23 06:02:40173}
174
175void PollingProxyConfigService::OnLazyPoll() {
176 core_->OnLazyPoll();
177}
178
[email protected]be1a48b2011-01-20 00:12:13179PollingProxyConfigService::PollingProxyConfigService(
180 base::TimeDelta poll_interval,
181 GetConfigFunction get_config_func)
182 : core_(new Core(poll_interval, get_config_func)) {
183}
184
185PollingProxyConfigService::~PollingProxyConfigService() {
186 core_->Orphan();
187}
188
[email protected]e9b8d0af2010-08-17 04:10:29189void PollingProxyConfigService::CheckForChangesNow() {
190 core_->CheckForChangesNow();
191}
192
[email protected]119655002010-07-23 06:02:40193} // namespace net