Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(455)

Side by Side Diff: chrome/browser/net/pref_proxy_config_tracker_impl.cc

Issue 1296663003: Componentize proxy code from chrome/browser/net (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: updating for win p/f Created 5 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2011 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 "chrome/browser/net/pref_proxy_config_tracker_impl.h"
6
7 #include "base/bind.h"
8 #include "base/metrics/histogram_macros.h"
9 #include "base/prefs/pref_registry_simple.h"
10 #include "base/prefs/pref_service.h"
11 #include "base/strings/string_util.h"
12 #include "base/values.h"
13 #include "chrome/browser/chrome_notification_types.h"
14 #include "chrome/common/pref_names.h"
15 #include "components/pref_registry/pref_registry_syncable.h"
16 #include "components/proxy_config/proxy_config_dictionary.h"
17 #include "content/public/browser/browser_thread.h"
18 #include "content/public/browser/notification_details.h"
19 #include "content/public/browser/notification_source.h"
20 #include "net/proxy/proxy_list.h"
21 #include "net/proxy/proxy_server.h"
22
23 using content::BrowserThread;
24
25 namespace {
26
27 // Determine if |proxy| is of the form "*.googlezip.net".
28 bool IsGooglezipDataReductionProxy(const net::ProxyServer& proxy) {
29 return proxy.is_valid() && !proxy.is_direct() &&
30 base::EndsWith(proxy.host_port_pair().host(), ".googlezip.net",
31 base::CompareCase::SENSITIVE);
32 }
33
34 // Removes any Data Reduction Proxies like *.googlezip.net from |proxy_list|.
35 // Returns the number of proxies that were removed from |proxy_list|.
36 size_t RemoveGooglezipDataReductionProxiesFromList(net::ProxyList* proxy_list) {
37 bool found_googlezip_proxy = false;
38 for (const net::ProxyServer& proxy : proxy_list->GetAll()) {
39 if (IsGooglezipDataReductionProxy(proxy)) {
40 found_googlezip_proxy = true;
41 break;
42 }
43 }
44 if (!found_googlezip_proxy)
45 return 0;
46
47 size_t num_removed_proxies = 0;
48 net::ProxyList replacement_list;
49 for (const net::ProxyServer& proxy : proxy_list->GetAll()) {
50 if (!IsGooglezipDataReductionProxy(proxy))
51 replacement_list.AddProxyServer(proxy);
52 else
53 ++num_removed_proxies;
54 }
55
56 if (replacement_list.IsEmpty())
57 replacement_list.AddProxyServer(net::ProxyServer::Direct());
58 *proxy_list = replacement_list;
59 return num_removed_proxies;
60 }
61
62 // Remove any Data Reduction Proxies like *.googlezip.net from |proxy_rules|.
63 // This is to prevent a Data Reduction Proxy from being activated in an
64 // unsupported way, such as from a proxy pref, which could cause Chrome to use
65 // the Data Reduction Proxy without adding any of the necessary authentication
66 // headers or applying the Data Reduction Proxy bypass logic. See
67 // http://crbug.com/476610.
68 // TODO(sclittle): This method should be removed once the UMA indicates that
69 // *.googlezip.net proxies are no longer present in the |proxy_rules|.
70 void RemoveGooglezipDataReductionProxies(
71 net::ProxyConfig::ProxyRules* proxy_rules) {
72 size_t num_removed_proxies =
73 RemoveGooglezipDataReductionProxiesFromList(
74 &proxy_rules->fallback_proxies) +
75 RemoveGooglezipDataReductionProxiesFromList(
76 &proxy_rules->proxies_for_ftp) +
77 RemoveGooglezipDataReductionProxiesFromList(
78 &proxy_rules->proxies_for_http) +
79 RemoveGooglezipDataReductionProxiesFromList(
80 &proxy_rules->proxies_for_https) +
81 RemoveGooglezipDataReductionProxiesFromList(&proxy_rules->single_proxies);
82
83 UMA_HISTOGRAM_COUNTS_100("Net.PrefProxyConfig.GooglezipProxyRemovalCount",
84 num_removed_proxies);
85 }
86
87 } // namespace
88
89 //============================= ChromeProxyConfigService =======================
90
91 ChromeProxyConfigService::ChromeProxyConfigService(
92 net::ProxyConfigService* base_service)
93 : base_service_(base_service),
94 pref_config_state_(ProxyPrefs::CONFIG_UNSET),
95 pref_config_read_pending_(true),
96 registered_observer_(false) {
97 }
98
99 ChromeProxyConfigService::~ChromeProxyConfigService() {
100 if (registered_observer_ && base_service_.get())
101 base_service_->RemoveObserver(this);
102 }
103
104 void ChromeProxyConfigService::AddObserver(
105 net::ProxyConfigService::Observer* observer) {
106 RegisterObserver();
107 observers_.AddObserver(observer);
108 }
109
110 void ChromeProxyConfigService::RemoveObserver(
111 net::ProxyConfigService::Observer* observer) {
112 observers_.RemoveObserver(observer);
113 }
114
115 net::ProxyConfigService::ConfigAvailability
116 ChromeProxyConfigService::GetLatestProxyConfig(net::ProxyConfig* config) {
117 RegisterObserver();
118
119 if (pref_config_read_pending_)
120 return net::ProxyConfigService::CONFIG_PENDING;
121
122 // Ask the base service if available.
123 net::ProxyConfig system_config;
124 ConfigAvailability system_availability =
125 net::ProxyConfigService::CONFIG_UNSET;
126 if (base_service_.get())
127 system_availability = base_service_->GetLatestProxyConfig(&system_config);
128
129 ProxyPrefs::ConfigState config_state;
130 return PrefProxyConfigTrackerImpl::GetEffectiveProxyConfig(
131 pref_config_state_, pref_config_,
132 system_availability, system_config, false,
133 &config_state, config);
134 }
135
136 void ChromeProxyConfigService::OnLazyPoll() {
137 if (base_service_.get())
138 base_service_->OnLazyPoll();
139 }
140
141 void ChromeProxyConfigService::UpdateProxyConfig(
142 ProxyPrefs::ConfigState config_state,
143 const net::ProxyConfig& config) {
144 DCHECK_CURRENTLY_ON(BrowserThread::IO);
145
146 pref_config_read_pending_ = false;
147 pref_config_state_ = config_state;
148 pref_config_ = config;
149
150 if (!observers_.might_have_observers())
151 return;
152
153 // Evaluate the proxy configuration. If GetLatestProxyConfig returns
154 // CONFIG_PENDING, we are using the system proxy service, but it doesn't have
155 // a valid configuration yet. Once it is ready, OnProxyConfigChanged() will be
156 // called and broadcast the proxy configuration.
157 // Note: If a switch between a preference proxy configuration and the system
158 // proxy configuration occurs an unnecessary notification might get send if
159 // the two configurations agree. This case should be rare however, so we don't
160 // handle that case specially.
161 net::ProxyConfig new_config;
162 ConfigAvailability availability = GetLatestProxyConfig(&new_config);
163 if (availability != CONFIG_PENDING) {
164 FOR_EACH_OBSERVER(net::ProxyConfigService::Observer, observers_,
165 OnProxyConfigChanged(new_config, availability));
166 }
167 }
168
169 void ChromeProxyConfigService::OnProxyConfigChanged(
170 const net::ProxyConfig& config,
171 ConfigAvailability availability) {
172 DCHECK_CURRENTLY_ON(BrowserThread::IO);
173
174 // Check whether there is a proxy configuration defined by preferences. In
175 // this case that proxy configuration takes precedence and the change event
176 // from the delegate proxy service can be disregarded.
177 if (!PrefProxyConfigTrackerImpl::PrefPrecedes(pref_config_state_)) {
178 net::ProxyConfig actual_config;
179 availability = GetLatestProxyConfig(&actual_config);
180 FOR_EACH_OBSERVER(net::ProxyConfigService::Observer, observers_,
181 OnProxyConfigChanged(actual_config, availability));
182 }
183 }
184
185 void ChromeProxyConfigService::RegisterObserver() {
186 DCHECK_CURRENTLY_ON(BrowserThread::IO);
187 if (!registered_observer_ && base_service_.get()) {
188 base_service_->AddObserver(this);
189 registered_observer_ = true;
190 }
191 }
192
193 //========================= PrefProxyConfigTrackerImpl =========================
194
195 PrefProxyConfigTrackerImpl::PrefProxyConfigTrackerImpl(
196 PrefService* pref_service)
197 : pref_service_(pref_service),
198 chrome_proxy_config_service_(NULL),
199 update_pending_(true) {
200 config_state_ = ReadPrefConfig(pref_service_, &pref_config_);
201 proxy_prefs_.Init(pref_service);
202 proxy_prefs_.Add(prefs::kProxy,
203 base::Bind(&PrefProxyConfigTrackerImpl::OnProxyPrefChanged,
204 base::Unretained(this)));
205 }
206
207 PrefProxyConfigTrackerImpl::~PrefProxyConfigTrackerImpl() {
208 DCHECK(pref_service_ == NULL);
209 }
210
211 scoped_ptr<net::ProxyConfigService>
212 PrefProxyConfigTrackerImpl::CreateTrackingProxyConfigService(
213 scoped_ptr<net::ProxyConfigService> base_service) {
214 chrome_proxy_config_service_ =
215 new ChromeProxyConfigService(base_service.release());
216 VLOG(1) << this << ": set chrome proxy config service to "
217 << chrome_proxy_config_service_;
218 if (chrome_proxy_config_service_ && update_pending_)
219 OnProxyConfigChanged(config_state_, pref_config_);
220
221 return scoped_ptr<net::ProxyConfigService>(chrome_proxy_config_service_);
222 }
223
224 void PrefProxyConfigTrackerImpl::DetachFromPrefService() {
225 DCHECK_CURRENTLY_ON(BrowserThread::UI);
226 // Stop notifications.
227 proxy_prefs_.RemoveAll();
228 pref_service_ = NULL;
229 chrome_proxy_config_service_ = NULL;
230 }
231
232 // static
233 bool PrefProxyConfigTrackerImpl::PrefPrecedes(
234 ProxyPrefs::ConfigState config_state) {
235 return config_state == ProxyPrefs::CONFIG_POLICY ||
236 config_state == ProxyPrefs::CONFIG_EXTENSION ||
237 config_state == ProxyPrefs::CONFIG_OTHER_PRECEDE;
238 }
239
240 // static
241 net::ProxyConfigService::ConfigAvailability
242 PrefProxyConfigTrackerImpl::GetEffectiveProxyConfig(
243 ProxyPrefs::ConfigState pref_state,
244 const net::ProxyConfig& pref_config,
245 net::ProxyConfigService::ConfigAvailability system_availability,
246 const net::ProxyConfig& system_config,
247 bool ignore_fallback_config,
248 ProxyPrefs::ConfigState* effective_config_state,
249 net::ProxyConfig* effective_config) {
250 net::ProxyConfigService::ConfigAvailability rv;
251 *effective_config_state = pref_state;
252
253 if (PrefPrecedes(pref_state)) {
254 *effective_config = pref_config;
255 rv = net::ProxyConfigService::CONFIG_VALID;
256 } else if (system_availability == net::ProxyConfigService::CONFIG_UNSET) {
257 // If there's no system proxy config, fall back to prefs or default.
258 if (pref_state == ProxyPrefs::CONFIG_FALLBACK && !ignore_fallback_config)
259 *effective_config = pref_config;
260 else
261 *effective_config = net::ProxyConfig::CreateDirect();
262 rv = net::ProxyConfigService::CONFIG_VALID;
263 } else {
264 *effective_config_state = ProxyPrefs::CONFIG_SYSTEM;
265 *effective_config = system_config;
266 rv = system_availability;
267 }
268
269 // Remove any Data Reduction Proxies like *.googlezip.net from the proxy
270 // config rules, since specifying a DRP in the proxy rules is not a supported
271 // means of activating the DRP, and could cause requests to be sent to the DRP
272 // without the appropriate authentication headers and without using any of the
273 // DRP bypass logic. This prevents the Data Reduction Proxy from being
274 // improperly activated via the proxy pref.
275 // TODO(sclittle): This is a temporary fix for http://crbug.com/476610, and
276 // should be removed once that bug is fixed and verified.
277 if (rv == net::ProxyConfigService::CONFIG_VALID)
278 RemoveGooglezipDataReductionProxies(&effective_config->proxy_rules());
279
280 return rv;
281 }
282
283 // static
284 void PrefProxyConfigTrackerImpl::RegisterPrefs(PrefRegistrySimple* registry) {
285 base::DictionaryValue* default_settings =
286 ProxyConfigDictionary::CreateSystem();
287 registry->RegisterDictionaryPref(prefs::kProxy, default_settings);
288 }
289
290 // static
291 void PrefProxyConfigTrackerImpl::RegisterProfilePrefs(
292 user_prefs::PrefRegistrySyncable* pref_service) {
293 base::DictionaryValue* default_settings =
294 ProxyConfigDictionary::CreateSystem();
295 pref_service->RegisterDictionaryPref(prefs::kProxy, default_settings);
296 }
297
298 // static
299 ProxyPrefs::ConfigState PrefProxyConfigTrackerImpl::ReadPrefConfig(
300 const PrefService* pref_service,
301 net::ProxyConfig* config) {
302 DCHECK_CURRENTLY_ON(BrowserThread::UI);
303
304 // Clear the configuration and source.
305 *config = net::ProxyConfig();
306 ProxyPrefs::ConfigState config_state = ProxyPrefs::CONFIG_UNSET;
307
308 const PrefService::Preference* pref =
309 pref_service->FindPreference(prefs::kProxy);
310 DCHECK(pref);
311
312 const base::DictionaryValue* dict =
313 pref_service->GetDictionary(prefs::kProxy);
314 DCHECK(dict);
315 ProxyConfigDictionary proxy_dict(dict);
316
317 if (PrefConfigToNetConfig(proxy_dict, config)) {
318 if (!pref->IsUserModifiable() || pref->HasUserSetting()) {
319 if (pref->IsManaged())
320 config_state = ProxyPrefs::CONFIG_POLICY;
321 else if (pref->IsExtensionControlled())
322 config_state = ProxyPrefs::CONFIG_EXTENSION;
323 else
324 config_state = ProxyPrefs::CONFIG_OTHER_PRECEDE;
325 } else {
326 config_state = ProxyPrefs::CONFIG_FALLBACK;
327 }
328 }
329
330 return config_state;
331 }
332
333 ProxyPrefs::ConfigState PrefProxyConfigTrackerImpl::GetProxyConfig(
334 net::ProxyConfig* config) {
335 DCHECK_CURRENTLY_ON(BrowserThread::UI);
336 if (config_state_ != ProxyPrefs::CONFIG_UNSET)
337 *config = pref_config_;
338 return config_state_;
339 }
340
341 void PrefProxyConfigTrackerImpl::OnProxyConfigChanged(
342 ProxyPrefs::ConfigState config_state,
343 const net::ProxyConfig& config) {
344 if (!chrome_proxy_config_service_) {
345 VLOG(1) << "No chrome proxy config service to push to UpdateProxyConfig";
346 update_pending_ = true;
347 return;
348 }
349 update_pending_ = !BrowserThread::PostTask(
350 BrowserThread::IO, FROM_HERE,
351 base::Bind(&ChromeProxyConfigService::UpdateProxyConfig,
352 base::Unretained(chrome_proxy_config_service_),
353 config_state, config));
354 VLOG(1) << this << (update_pending_ ? ": Error" : ": Done")
355 << " pushing proxy to UpdateProxyConfig";
356 }
357
358 bool PrefProxyConfigTrackerImpl::PrefConfigToNetConfig(
359 const ProxyConfigDictionary& proxy_dict,
360 net::ProxyConfig* config) {
361 ProxyPrefs::ProxyMode mode;
362 if (!proxy_dict.GetMode(&mode)) {
363 // Fall back to system settings if the mode preference is invalid.
364 return false;
365 }
366
367 switch (mode) {
368 case ProxyPrefs::MODE_SYSTEM:
369 // Use system settings.
370 return false;
371 case ProxyPrefs::MODE_DIRECT:
372 // Ignore all the other proxy config preferences if the use of a proxy
373 // has been explicitly disabled.
374 return true;
375 case ProxyPrefs::MODE_AUTO_DETECT:
376 config->set_auto_detect(true);
377 return true;
378 case ProxyPrefs::MODE_PAC_SCRIPT: {
379 std::string proxy_pac;
380 if (!proxy_dict.GetPacUrl(&proxy_pac)) {
381 LOG(ERROR) << "Proxy settings request PAC script but do not specify "
382 << "its URL. Falling back to direct connection.";
383 return true;
384 }
385 GURL proxy_pac_url(proxy_pac);
386 if (!proxy_pac_url.is_valid()) {
387 LOG(ERROR) << "Invalid proxy PAC url: " << proxy_pac;
388 return true;
389 }
390 config->set_pac_url(proxy_pac_url);
391 bool pac_mandatory = false;
392 proxy_dict.GetPacMandatory(&pac_mandatory);
393 config->set_pac_mandatory(pac_mandatory);
394 return true;
395 }
396 case ProxyPrefs::MODE_FIXED_SERVERS: {
397 std::string proxy_server;
398 if (!proxy_dict.GetProxyServer(&proxy_server)) {
399 LOG(ERROR) << "Proxy settings request fixed proxy servers but do not "
400 << "specify their URLs. Falling back to direct connection.";
401 return true;
402 }
403 config->proxy_rules().ParseFromString(proxy_server);
404
405 std::string proxy_bypass;
406 if (proxy_dict.GetBypassList(&proxy_bypass)) {
407 config->proxy_rules().bypass_rules.ParseFromString(proxy_bypass);
408 }
409 return true;
410 }
411 case ProxyPrefs::kModeCount: {
412 // Fall through to NOTREACHED().
413 }
414 }
415 NOTREACHED() << "Unknown proxy mode, falling back to system settings.";
416 return false;
417 }
418
419 void PrefProxyConfigTrackerImpl::OnProxyPrefChanged() {
420 DCHECK_CURRENTLY_ON(BrowserThread::UI);
421 net::ProxyConfig new_config;
422 ProxyPrefs::ConfigState config_state = ReadPrefConfig(pref_service_,
423 &new_config);
424 if (config_state_ != config_state ||
425 (config_state_ != ProxyPrefs::CONFIG_UNSET &&
426 !pref_config_.Equals(new_config))) {
427 config_state_ = config_state;
428 if (config_state_ != ProxyPrefs::CONFIG_UNSET)
429 pref_config_ = new_config;
430 update_pending_ = true;
431 }
432 if (update_pending_)
433 OnProxyConfigChanged(config_state, new_config);
434 }
OLDNEW
« no previous file with comments | « chrome/browser/net/pref_proxy_config_tracker_impl.h ('k') | chrome/browser/net/pref_proxy_config_tracker_impl_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698