blob: ac42d9c04cd4dd82176f56c98945652de2752502 [file] [log] [blame]
[email protected]119655002010-07-23 06:02:401// Copyright (c) 2010 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.
4
5#include "net/proxy/polling_proxy_config_service.h"
6
7#include "base/lock.h"
8#include "base/message_loop_proxy.h"
9#include "base/observer_list.h"
10#include "base/scoped_ptr.h"
11#include "base/worker_pool.h"
12#include "net/proxy/proxy_config.h"
13
14namespace net {
15
16// Reference-counted wrapper that does all the work (needs to be
17// reference-counted since we post tasks between threads; may outlive
18// the parent PollingProxyConfigService).
19class PollingProxyConfigService::Core
20 : public base::RefCountedThreadSafe<PollingProxyConfigService::Core> {
21 public:
22 Core(base::TimeDelta poll_interval,
23 GetConfigFunction get_config_func)
24 : get_config_func_(get_config_func),
25 has_config_(false),
26 poll_task_outstanding_(false),
27 poll_interval_(poll_interval),
28 have_initialized_origin_loop_(false) {
29 }
30
31 // Called when the parent PollingProxyConfigService is destroyed
32 // (observers should not be called past this point).
33 void Orphan() {
34 AutoLock l(lock_);
35 origin_loop_proxy_ = NULL;
36 }
37
38 bool GetLatestProxyConfig(ProxyConfig* config) {
39 LazyInitializeOriginLoop();
40 DCHECK(origin_loop_proxy_->BelongsToCurrentThread());
41
42 OnLazyPoll();
43
44 // If we have already retrieved the proxy settings (on worker thread)
45 // then return what we last saw.
46 if (has_config_) {
47 *config = last_config_;
48 return true;
49 }
50 return false;
51 }
52
53 void AddObserver(Observer* observer) {
54 LazyInitializeOriginLoop();
55 DCHECK(origin_loop_proxy_->BelongsToCurrentThread());
56 observers_.AddObserver(observer);
57 }
58
59 void RemoveObserver(Observer* observer) {
60 DCHECK(origin_loop_proxy_->BelongsToCurrentThread());
61 observers_.RemoveObserver(observer);
62 }
63
64 // Check for a new configuration if enough time has elapsed.
65 void OnLazyPoll() {
66 LazyInitializeOriginLoop();
67 DCHECK(origin_loop_proxy_->BelongsToCurrentThread());
68
69 if (poll_task_outstanding_)
70 return; // Still waiting for earlier test to finish.
71
72 base::TimeTicks now = base::TimeTicks::Now();
73
74 if (last_poll_time_.is_null() ||
75 (now - last_poll_time_) > poll_interval_) {
76 last_poll_time_ = now;
77 poll_task_outstanding_ = true;
78 WorkerPool::PostTask(
79 FROM_HERE,
80 NewRunnableMethod(
81 this, &Core::PollOnWorkerThread, get_config_func_), true);
82 }
83 }
84
85 private:
86 void PollOnWorkerThread(GetConfigFunction func) {
87 ProxyConfig config;
88 func(&config);
89
90 AutoLock l(lock_);
91 if (origin_loop_proxy_) {
92 origin_loop_proxy_->PostTask(
93 FROM_HERE,
94 NewRunnableMethod(this, &Core::GetConfigCompleted, config));
95 }
96 }
97
98 // Called after the worker thread has finished retrieving a configuration.
99 void GetConfigCompleted(const ProxyConfig& config) {
100 DCHECK(poll_task_outstanding_);
101 poll_task_outstanding_ = false;
102
103 if (!origin_loop_proxy_)
104 return; // Was orphaned (parent has already been destroyed).
105
106 DCHECK(origin_loop_proxy_->BelongsToCurrentThread());
107
108 if (!has_config_ || !last_config_.Equals(config)) {
109 // If the configuration has changed, notify the observers.
110 has_config_ = true;
111 last_config_ = config;
112 FOR_EACH_OBSERVER(Observer, observers_, OnProxyConfigChanged(config));
113 }
114 }
115
116 void LazyInitializeOriginLoop() {
117 // TODO(eroman): Really this should be done in the constructor, but right
118 // now chrome is constructing the ProxyConfigService on the
119 // UI thread so we can't cache the IO thread for the purpose
120 // of DCHECKs until the first call is made.
121 if (!have_initialized_origin_loop_) {
122 origin_loop_proxy_ = base::MessageLoopProxy::CreateForCurrentThread();
123 have_initialized_origin_loop_ = true;
124 }
125 }
126
127 GetConfigFunction get_config_func_;
128 ObserverList<Observer> observers_;
129 bool has_config_;
130 bool poll_task_outstanding_;
131 ProxyConfig last_config_;
132 base::TimeTicks last_poll_time_;
133 base::TimeDelta poll_interval_;
134 bool have_initialized_origin_loop_;
135
136 Lock lock_;
137 scoped_refptr<base::MessageLoopProxy> origin_loop_proxy_;
138};
139
140PollingProxyConfigService::PollingProxyConfigService(
141 base::TimeDelta poll_interval,
142 GetConfigFunction get_config_func)
143 : core_(new Core(poll_interval, get_config_func)) {
144}
145
146PollingProxyConfigService::~PollingProxyConfigService() {
147 core_->Orphan();
148}
149
150void PollingProxyConfigService::AddObserver(Observer* observer) {
151 core_->AddObserver(observer);
152}
153
154void PollingProxyConfigService::RemoveObserver(Observer* observer) {
155 core_->RemoveObserver(observer);
156}
157
158bool PollingProxyConfigService::GetLatestProxyConfig(ProxyConfig* config) {
159 return core_->GetLatestProxyConfig(config);
160}
161
162void PollingProxyConfigService::OnLazyPoll() {
163 core_->OnLazyPoll();
164}
165
166} // namespace net