 Chromium Code Reviews
 Chromium Code Reviews Issue 5005002:
  Dynamically refresh pref-configured proxies.  (Closed) 
  Base URL: svn://svn.chromium.org/chrome/trunk/src
    
  
    Issue 5005002:
  Dynamically refresh pref-configured proxies.  (Closed) 
  Base URL: svn://svn.chromium.org/chrome/trunk/src| Index: chrome/browser/net/pref_proxy_config_service.cc | 
| diff --git a/chrome/browser/net/pref_proxy_config_service.cc b/chrome/browser/net/pref_proxy_config_service.cc | 
| new file mode 100644 | 
| index 0000000000000000000000000000000000000000..5cd62136945832d5832a5929d6f8a5615d6eb6fb | 
| --- /dev/null | 
| +++ b/chrome/browser/net/pref_proxy_config_service.cc | 
| @@ -0,0 +1,222 @@ | 
| +// Copyright (c) 2010 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 "chrome/browser/net/pref_proxy_config_service.h" | 
| + | 
| +#include "chrome/browser/browser_thread.h" | 
| +#include "chrome/browser/prefs/pref_service.h" | 
| +#include "chrome/browser/prefs/pref_set_observer.h" | 
| +#include "chrome/common/notification_details.h" | 
| +#include "chrome/common/notification_source.h" | 
| +#include "chrome/common/notification_type.h" | 
| +#include "chrome/common/pref_names.h" | 
| + | 
| +PrefProxyConfigTracker::PrefProxyConfigTracker(PrefService* pref_service) | 
| + : pref_service_(pref_service) { | 
| + valid_ = ReadPrefConfig(&pref_config_); | 
| + proxy_prefs_observer_.reset( | 
| + PrefSetObserver::CreateProxyPrefSetObserver(pref_service_, this)); | 
| +} | 
| + | 
| +PrefProxyConfigTracker::~PrefProxyConfigTracker() { | 
| + DCHECK(pref_service_ == NULL); | 
| +} | 
| + | 
| +bool PrefProxyConfigTracker::GetProxyConfig(net::ProxyConfig* config) { | 
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 
| + if (valid_) | 
| + *config = pref_config_; | 
| + return valid_; | 
| +} | 
| + | 
| +void PrefProxyConfigTracker::DetachFromPrefService() { | 
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 
| + // Stop notifications. | 
| + proxy_prefs_observer_.reset(); | 
| + pref_service_ = NULL; | 
| +} | 
| + | 
| +void PrefProxyConfigTracker::AddObserver( | 
| + PrefProxyConfigTracker::ObserverInterface* observer) { | 
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 
| + observers_.AddObserver(observer); | 
| +} | 
| + | 
| +void PrefProxyConfigTracker::RemoveObserver( | 
| + PrefProxyConfigTracker::ObserverInterface* observer) { | 
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 
| + observers_.RemoveObserver(observer); | 
| +} | 
| + | 
| +void PrefProxyConfigTracker::Observe(NotificationType type, | 
| + const NotificationSource& source, | 
| + const NotificationDetails& details) { | 
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 
| + if (type == NotificationType::PREF_CHANGED && | 
| + Source<PrefService>(source).ptr() == pref_service_) { | 
| + net::ProxyConfig new_config; | 
| + bool valid = ReadPrefConfig(&new_config); | 
| + BrowserThread::PostTask( | 
| + BrowserThread::IO, FROM_HERE, | 
| + NewRunnableMethod(this, | 
| + &PrefProxyConfigTracker::InstallProxyConfig, | 
| + new_config, valid)); | 
| + } else { | 
| + NOTREACHED() << "Unexpected notification of type " << type.value; | 
| + } | 
| +} | 
| + | 
| +void PrefProxyConfigTracker::InstallProxyConfig(const net::ProxyConfig& config, | 
| + bool valid) { | 
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 
| + if (valid_ != valid || !pref_config_.Equals(config)) { | 
| 
eroman
2010/11/30 02:58:54
This is a little weird in the case where (!valid_
 
battre (please use the other)
2010/12/02 18:06:12
Done.
 | 
| + valid_ = valid; | 
| + if (valid_) | 
| + pref_config_ = config; | 
| + FOR_EACH_OBSERVER(ObserverInterface, observers_, | 
| + OnPrefProxyConfigChanged()); | 
| + } | 
| +} | 
| + | 
| +bool PrefProxyConfigTracker::ReadPrefConfig(net::ProxyConfig* config) { | 
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 
| + | 
| + // Clear the configuration. | 
| + *config = net::ProxyConfig(); | 
| + | 
| + // Scan for all "enable" type proxy switches. | 
| + static const char* proxy_prefs[] = { | 
| + prefs::kProxyPacUrl, | 
| + prefs::kProxyServer, | 
| + prefs::kProxyBypassList, | 
| + prefs::kProxyAutoDetect | 
| + }; | 
| + | 
| + // Check whether the preference system holds a valid proxy configuration. Note | 
| + // that preferences coming from a lower-priority source than the user settings | 
| + // are ignored. That's because chrome treats the system settings as the | 
| + // default values, which should apply if there's no explicit value forced by | 
| + // policy or the user. | 
| + bool found_enable_proxy_pref = false; | 
| + for (size_t i = 0; i < arraysize(proxy_prefs); i++) { | 
| + const PrefService::Preference* pref = | 
| + pref_service_->FindPreference(proxy_prefs[i]); | 
| + DCHECK(pref); | 
| + if (pref && (!pref->IsUserModifiable() || pref->HasUserSetting())) { | 
| + found_enable_proxy_pref = true; | 
| + break; | 
| + } | 
| + } | 
| + | 
| + if (!found_enable_proxy_pref && | 
| + !pref_service_->GetBoolean(prefs::kNoProxyServer)) { | 
| + return false; | 
| + } | 
| + | 
| + if (pref_service_->GetBoolean(prefs::kNoProxyServer)) { | 
| + // Ignore all the other proxy config preferences if the use of a proxy | 
| + // has been explicitly disabled. | 
| + return true; | 
| + } | 
| + | 
| + if (pref_service_->HasPrefPath(prefs::kProxyServer)) { | 
| + std::string proxy_server = pref_service_->GetString(prefs::kProxyServer); | 
| + config->proxy_rules().ParseFromString(proxy_server); | 
| + } | 
| + | 
| + if (pref_service_->HasPrefPath(prefs::kProxyPacUrl)) { | 
| + std::string proxy_pac = pref_service_->GetString(prefs::kProxyPacUrl); | 
| + config->set_pac_url(GURL(proxy_pac)); | 
| + } | 
| + | 
| + config->set_auto_detect(pref_service_->GetBoolean(prefs::kProxyAutoDetect)); | 
| + | 
| + if (pref_service_->HasPrefPath(prefs::kProxyBypassList)) { | 
| + std::string proxy_bypass = | 
| + pref_service_->GetString(prefs::kProxyBypassList); | 
| + config->proxy_rules().bypass_rules.ParseFromString(proxy_bypass); | 
| + } | 
| + | 
| + return true; | 
| +} | 
| + | 
| +PrefProxyConfigService::PrefProxyConfigService( | 
| + PrefProxyConfigTracker* tracker, | 
| + net::ProxyConfigService* base_service) | 
| + : base_service_(base_service), | 
| + pref_config_tracker_(tracker), | 
| + registered_observers_(false) { | 
| +} | 
| + | 
| +PrefProxyConfigService::~PrefProxyConfigService() { | 
| + if (registered_observers_) { | 
| + base_service_->RemoveObserver(this); | 
| + pref_config_tracker_->RemoveObserver(this); | 
| + } | 
| +} | 
| + | 
| +void PrefProxyConfigService::AddObserver( | 
| + net::ProxyConfigService::Observer* observer) { | 
| + RegisterObservers(); | 
| + observers_.AddObserver(observer); | 
| +} | 
| + | 
| +void PrefProxyConfigService::RemoveObserver( | 
| + net::ProxyConfigService::Observer* observer) { | 
| + observers_.RemoveObserver(observer); | 
| +} | 
| + | 
| +bool PrefProxyConfigService::GetLatestProxyConfig(net::ProxyConfig* config) { | 
| + RegisterObservers(); | 
| + const net::ProxyConfig pref_config; | 
| + if (pref_config_tracker_->GetProxyConfig(config)) | 
| + return true; | 
| + | 
| + return base_service_->GetLatestProxyConfig(config); | 
| +} | 
| + | 
| +void PrefProxyConfigService::OnLazyPoll() { | 
| + base_service_->OnLazyPoll(); | 
| +} | 
| + | 
| +void PrefProxyConfigService::OnProxyConfigChanged( | 
| + const net::ProxyConfig& config) { | 
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 
| + | 
| + // Check whether there is a proxy configuration defined by preferences. In | 
| + // this case that proxy configuration takes precedence and the change event | 
| + // from the delegate proxy service can be disregarded. | 
| + net::ProxyConfig pref_config; | 
| + if (!pref_config_tracker_->GetProxyConfig(&pref_config)) { | 
| + FOR_EACH_OBSERVER(net::ProxyConfigService::Observer, observers_, | 
| + OnProxyConfigChanged(config)); | 
| + } | 
| +} | 
| + | 
| +void PrefProxyConfigService::OnPrefProxyConfigChanged() { | 
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 
| + | 
| + // Evaluate the proxy configuration. If GetLatestProxyConfig returns false, | 
| + // we are using the system proxy service, but it doesn't have a valid | 
| + // configuration yet. Once it is ready, OnProxyConfigChanged() will be called | 
| + // and broadcast the proxy configuration. | 
| + // Note: If a switch between a preference proxy configuration and the system | 
| + // proxy configuration occurs an unnecessary notification might get send if | 
| + // the two configurations agree. This case should be rare however, so we don't | 
| + // handle that case specially. | 
| + net::ProxyConfig new_config; | 
| + if (GetLatestProxyConfig(&new_config)) { | 
| + FOR_EACH_OBSERVER(net::ProxyConfigService::Observer, observers_, | 
| + OnProxyConfigChanged(new_config)); | 
| + } | 
| +} | 
| + | 
| +void PrefProxyConfigService::RegisterObservers() { | 
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 
| + if (!registered_observers_) { | 
| + base_service_->AddObserver(this); | 
| + pref_config_tracker_->AddObserver(this); | 
| + registered_observers_ = true; | 
| + } | 
| +} |