• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_service.h"
6 
7 #include "base/values.h"
8 #include "chrome/browser/prefs/pref_service.h"
9 #include "chrome/browser/prefs/pref_set_observer.h"
10 #include "chrome/browser/prefs/proxy_config_dictionary.h"
11 #include "chrome/common/pref_names.h"
12 #include "content/browser/browser_thread.h"
13 #include "content/common/notification_details.h"
14 #include "content/common/notification_source.h"
15 #include "content/common/notification_type.h"
16 
PrefProxyConfigTracker(PrefService * pref_service)17 PrefProxyConfigTracker::PrefProxyConfigTracker(PrefService* pref_service)
18     : pref_service_(pref_service) {
19   config_state_ = ReadPrefConfig(&pref_config_);
20   proxy_prefs_observer_.reset(
21       PrefSetObserver::CreateProxyPrefSetObserver(pref_service_, this));
22 }
23 
~PrefProxyConfigTracker()24 PrefProxyConfigTracker::~PrefProxyConfigTracker() {
25   DCHECK(pref_service_ == NULL);
26 }
27 
28 PrefProxyConfigTracker::ConfigState
GetProxyConfig(net::ProxyConfig * config)29     PrefProxyConfigTracker::GetProxyConfig(net::ProxyConfig* config) {
30   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
31   if (config_state_ != CONFIG_UNSET)
32     *config = pref_config_;
33   return config_state_;
34 }
35 
DetachFromPrefService()36 void PrefProxyConfigTracker::DetachFromPrefService() {
37   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
38   // Stop notifications.
39   proxy_prefs_observer_.reset();
40   pref_service_ = NULL;
41 }
42 
AddObserver(PrefProxyConfigTracker::Observer * observer)43 void PrefProxyConfigTracker::AddObserver(
44     PrefProxyConfigTracker::Observer* observer) {
45   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
46   observers_.AddObserver(observer);
47 }
48 
RemoveObserver(PrefProxyConfigTracker::Observer * observer)49 void PrefProxyConfigTracker::RemoveObserver(
50     PrefProxyConfigTracker::Observer* observer) {
51   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
52   observers_.RemoveObserver(observer);
53 }
54 
Observe(NotificationType type,const NotificationSource & source,const NotificationDetails & details)55 void PrefProxyConfigTracker::Observe(NotificationType type,
56                                      const NotificationSource& source,
57                                      const NotificationDetails& details) {
58   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
59   if (type == NotificationType::PREF_CHANGED &&
60       Source<PrefService>(source).ptr() == pref_service_) {
61     net::ProxyConfig new_config;
62     ConfigState config_state = ReadPrefConfig(&new_config);
63     BrowserThread::PostTask(
64         BrowserThread::IO, FROM_HERE,
65         NewRunnableMethod(this,
66                           &PrefProxyConfigTracker::InstallProxyConfig,
67                           new_config, config_state));
68   } else {
69     NOTREACHED() << "Unexpected notification of type " << type.value;
70   }
71 }
72 
InstallProxyConfig(const net::ProxyConfig & config,PrefProxyConfigTracker::ConfigState config_state)73 void PrefProxyConfigTracker::InstallProxyConfig(
74     const net::ProxyConfig& config,
75     PrefProxyConfigTracker::ConfigState config_state) {
76   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
77   if (config_state_ != config_state ||
78       (config_state_ != CONFIG_UNSET && !pref_config_.Equals(config))) {
79     config_state_ = config_state;
80     if (config_state_ != CONFIG_UNSET)
81       pref_config_ = config;
82     FOR_EACH_OBSERVER(Observer, observers_, OnPrefProxyConfigChanged());
83   }
84 }
85 
86 PrefProxyConfigTracker::ConfigState
ReadPrefConfig(net::ProxyConfig * config)87     PrefProxyConfigTracker::ReadPrefConfig(net::ProxyConfig* config) {
88   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
89 
90   // Clear the configuration.
91   *config = net::ProxyConfig();
92 
93   const PrefService::Preference* pref =
94       pref_service_->FindPreference(prefs::kProxy);
95   const DictionaryValue* dict = pref_service_->GetDictionary(prefs::kProxy);
96   DCHECK(dict);
97   ProxyConfigDictionary proxy_dict(dict);
98 
99   if (PrefConfigToNetConfig(proxy_dict, config)) {
100     return (!pref->IsUserModifiable() || pref->HasUserSetting()) ?
101         CONFIG_PRESENT : CONFIG_FALLBACK;
102   }
103 
104   return CONFIG_UNSET;
105 }
106 
PrefConfigToNetConfig(const ProxyConfigDictionary & proxy_dict,net::ProxyConfig * config)107 bool PrefProxyConfigTracker::PrefConfigToNetConfig(
108     const ProxyConfigDictionary& proxy_dict,
109     net::ProxyConfig* config) {
110   ProxyPrefs::ProxyMode mode;
111   if (!proxy_dict.GetMode(&mode)) {
112     // Fall back to system settings if the mode preference is invalid.
113     return false;
114   }
115 
116   switch (mode) {
117     case ProxyPrefs::MODE_SYSTEM:
118       // Use system settings.
119       return true;
120     case ProxyPrefs::MODE_DIRECT:
121       // Ignore all the other proxy config preferences if the use of a proxy
122       // has been explicitly disabled.
123       return true;
124     case ProxyPrefs::MODE_AUTO_DETECT:
125       config->set_auto_detect(true);
126       return true;
127     case ProxyPrefs::MODE_PAC_SCRIPT: {
128       std::string proxy_pac;
129       if (!proxy_dict.GetPacUrl(&proxy_pac)) {
130         LOG(ERROR) << "Proxy settings request PAC script but do not specify "
131                    << "its URL. Falling back to direct connection.";
132         return true;
133       }
134       GURL proxy_pac_url(proxy_pac);
135       if (!proxy_pac_url.is_valid()) {
136         LOG(ERROR) << "Invalid proxy PAC url: " << proxy_pac;
137         return true;
138       }
139       config->set_pac_url(proxy_pac_url);
140       return true;
141     }
142     case ProxyPrefs::MODE_FIXED_SERVERS: {
143       std::string proxy_server;
144       if (!proxy_dict.GetProxyServer(&proxy_server)) {
145         LOG(ERROR) << "Proxy settings request fixed proxy servers but do not "
146                    << "specify their URLs. Falling back to direct connection.";
147         return true;
148       }
149       config->proxy_rules().ParseFromString(proxy_server);
150 
151       std::string proxy_bypass;
152       if (proxy_dict.GetBypassList(&proxy_bypass)) {
153         config->proxy_rules().bypass_rules.ParseFromString(proxy_bypass);
154       }
155       return true;
156     }
157     case ProxyPrefs::kModeCount: {
158       // Fall through to NOTREACHED().
159     }
160   }
161   NOTREACHED() << "Unknown proxy mode, falling back to system settings.";
162   return false;
163 }
164 
PrefProxyConfigService(PrefProxyConfigTracker * tracker,net::ProxyConfigService * base_service)165 PrefProxyConfigService::PrefProxyConfigService(
166     PrefProxyConfigTracker* tracker,
167     net::ProxyConfigService* base_service)
168     : base_service_(base_service),
169       pref_config_tracker_(tracker),
170       registered_observers_(false) {
171 }
172 
~PrefProxyConfigService()173 PrefProxyConfigService::~PrefProxyConfigService() {
174   if (registered_observers_) {
175     base_service_->RemoveObserver(this);
176     pref_config_tracker_->RemoveObserver(this);
177   }
178 }
179 
AddObserver(net::ProxyConfigService::Observer * observer)180 void PrefProxyConfigService::AddObserver(
181     net::ProxyConfigService::Observer* observer) {
182   RegisterObservers();
183   observers_.AddObserver(observer);
184 }
185 
RemoveObserver(net::ProxyConfigService::Observer * observer)186 void PrefProxyConfigService::RemoveObserver(
187     net::ProxyConfigService::Observer* observer) {
188   observers_.RemoveObserver(observer);
189 }
190 
191 net::ProxyConfigService::ConfigAvailability
GetLatestProxyConfig(net::ProxyConfig * config)192     PrefProxyConfigService::GetLatestProxyConfig(net::ProxyConfig* config) {
193   RegisterObservers();
194   net::ProxyConfig pref_config;
195   PrefProxyConfigTracker::ConfigState state =
196       pref_config_tracker_->GetProxyConfig(&pref_config);
197   if (state == PrefProxyConfigTracker::CONFIG_PRESENT) {
198     *config = pref_config;
199     return CONFIG_VALID;
200   }
201 
202   // Ask the base service.
203   ConfigAvailability available = base_service_->GetLatestProxyConfig(config);
204 
205   // Base service doesn't have a configuration, fall back to prefs or default.
206   if (available == CONFIG_UNSET) {
207     if (state == PrefProxyConfigTracker::CONFIG_FALLBACK)
208       *config = pref_config;
209     else
210       *config = net::ProxyConfig::CreateDirect();
211     return CONFIG_VALID;
212   }
213 
214   return available;
215 }
216 
OnLazyPoll()217 void PrefProxyConfigService::OnLazyPoll() {
218   base_service_->OnLazyPoll();
219 }
220 
OnProxyConfigChanged(const net::ProxyConfig & config,ConfigAvailability availability)221 void PrefProxyConfigService::OnProxyConfigChanged(
222     const net::ProxyConfig& config,
223     ConfigAvailability availability) {
224   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
225 
226   // Check whether there is a proxy configuration defined by preferences. In
227   // this case that proxy configuration takes precedence and the change event
228   // from the delegate proxy service can be disregarded.
229   net::ProxyConfig actual_config;
230   if (pref_config_tracker_->GetProxyConfig(&actual_config) !=
231           PrefProxyConfigTracker::CONFIG_PRESENT) {
232     availability = GetLatestProxyConfig(&actual_config);
233     FOR_EACH_OBSERVER(net::ProxyConfigService::Observer, observers_,
234                       OnProxyConfigChanged(actual_config, availability));
235   }
236 }
237 
OnPrefProxyConfigChanged()238 void PrefProxyConfigService::OnPrefProxyConfigChanged() {
239   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
240 
241   // Evaluate the proxy configuration. If GetLatestProxyConfig returns
242   // CONFIG_PENDING, we are using the system proxy service, but it doesn't have
243   // a valid configuration yet. Once it is ready, OnProxyConfigChanged() will be
244   // called and broadcast the proxy configuration.
245   // Note: If a switch between a preference proxy configuration and the system
246   // proxy configuration occurs an unnecessary notification might get send if
247   // the two configurations agree. This case should be rare however, so we don't
248   // handle that case specially.
249   net::ProxyConfig new_config;
250   ConfigAvailability availability = GetLatestProxyConfig(&new_config);
251   if (availability != CONFIG_PENDING) {
252     FOR_EACH_OBSERVER(net::ProxyConfigService::Observer, observers_,
253                       OnProxyConfigChanged(new_config, availability));
254   }
255 }
256 
RegisterObservers()257 void PrefProxyConfigService::RegisterObservers() {
258   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
259   if (!registered_observers_) {
260     base_service_->AddObserver(this);
261     pref_config_tracker_->AddObserver(this);
262     registered_observers_ = true;
263   }
264 }
265 
266 // static
RegisterPrefs(PrefService * pref_service)267 void PrefProxyConfigService::RegisterPrefs(PrefService* pref_service) {
268   DictionaryValue* default_settings = ProxyConfigDictionary::CreateSystem();
269   pref_service->RegisterDictionaryPref(prefs::kProxy, default_settings);
270 }
271