OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/chromeos/proxy_config_service_impl.h" | 5 #include "chrome/browser/chromeos/proxy_config_service_impl.h" |
6 | 6 |
7 #include <ostream> | |
8 | |
9 #include "base/bind.h" | 7 #include "base/bind.h" |
10 #include "base/json/json_string_value_serializer.h" | |
11 #include "base/logging.h" | 8 #include "base/logging.h" |
12 #include "base/prefs/pref_registry_simple.h" | 9 #include "base/prefs/pref_registry_simple.h" |
13 #include "base/prefs/pref_service.h" | 10 #include "base/prefs/pref_service.h" |
14 #include "base/string_util.h" | 11 #include "base/values.h" |
15 #include "chrome/browser/browser_process.h" | 12 #include "chrome/browser/browser_process.h" |
16 #include "chrome/browser/chromeos/cros/cros_library.h" | |
17 #include "chrome/browser/chromeos/cros/network_property_ui_data.h" | |
18 #include "chrome/browser/chromeos/login/user_manager.h" | 13 #include "chrome/browser/chromeos/login/user_manager.h" |
19 #include "chrome/browser/policy/browser_policy_connector.h" | 14 #include "chrome/browser/policy/browser_policy_connector.h" |
20 #include "chrome/browser/policy/cloud/cloud_policy_constants.h" | 15 #include "chrome/browser/policy/cloud/cloud_policy_constants.h" |
21 #include "chrome/browser/prefs/proxy_config_dictionary.h" | 16 #include "chrome/browser/prefs/proxy_config_dictionary.h" |
22 #include "chrome/browser/prefs/proxy_prefs.h" | 17 #include "chrome/browser/prefs/proxy_prefs.h" |
23 #include "chrome/browser/profiles/profile_manager.h" | |
24 #include "chrome/common/chrome_notification_types.h" | |
25 #include "chrome/common/pref_names.h" | 18 #include "chrome/common/pref_names.h" |
26 #include "chromeos/network/network_ui_data.h" | 19 #include "chromeos/network/network_profile.h" |
27 #include "chromeos/network/onc/onc_constants.h" | 20 #include "chromeos/network/network_profile_handler.h" |
| 21 #include "chromeos/network/network_state.h" |
| 22 #include "chromeos/network/network_state_handler.h" |
| 23 #include "chromeos/network/onc/onc_utils.h" |
28 #include "components/user_prefs/pref_registry_syncable.h" | 24 #include "components/user_prefs/pref_registry_syncable.h" |
29 #include "content/public/browser/notification_service.h" | |
30 #include "grit/generated_resources.h" | |
31 #include "ui/base/l10n/l10n_util.h" | |
32 | 25 |
33 namespace chromeos { | 26 namespace chromeos { |
34 | 27 |
35 namespace { | 28 namespace { |
36 | 29 |
37 // Shoud we try to push this to base? | 30 // Convert and store the proxy config of |pref_proxy_config| of |
38 // Helper comparator functor for the find_if call in |findIfEqual| | 31 // ProxyConfigDictionary format to |proxy_config|. Returns true if |
39 template <class T> | 32 // |pref_proxy_config| was not empty and if it was successfully converted. |
40 class EqualsComparator{ | 33 bool ParseProxyConfig(const base::DictionaryValue& pref_proxy_config, |
41 public: | 34 net::ProxyConfig* proxy_config) { |
42 explicit EqualsComparator(const T& key) : key_(key) { } | 35 if (pref_proxy_config.empty()) |
43 bool operator() (const T& element) { | 36 return false; |
44 return element.Equals(key_); | 37 ProxyConfigDictionary proxy_dict(&pref_proxy_config); |
45 } | 38 return PrefProxyConfigTrackerImpl::PrefConfigToNetConfig(proxy_dict, |
46 private: | 39 proxy_config); |
47 const T& key_; | |
48 }; | |
49 | |
50 // Tiny STL helper function to allow using the find_if syntax on objects that | |
51 // doesn't use the operator== but implement the Equals function which is the | |
52 // quasi standard with the coding style we have. | |
53 template<class InputIterator, class T> | |
54 InputIterator findIfEqual(InputIterator first, InputIterator last, | |
55 const T& key) { | |
56 return std::find_if(first, last, EqualsComparator<T>(key)); | |
57 } | |
58 | |
59 const char* ModeToString(ProxyConfigServiceImpl::ProxyConfig::Mode mode) { | |
60 switch (mode) { | |
61 case ProxyConfigServiceImpl::ProxyConfig::MODE_DIRECT: | |
62 return "direct"; | |
63 case ProxyConfigServiceImpl::ProxyConfig::MODE_AUTO_DETECT: | |
64 return "auto-detect"; | |
65 case ProxyConfigServiceImpl::ProxyConfig::MODE_PAC_SCRIPT: | |
66 return "pacurl"; | |
67 case ProxyConfigServiceImpl::ProxyConfig::MODE_SINGLE_PROXY: | |
68 return "single-proxy"; | |
69 case ProxyConfigServiceImpl::ProxyConfig::MODE_PROXY_PER_SCHEME: | |
70 return "proxy-per-scheme"; | |
71 } | |
72 NOTREACHED() << "Unrecognized mode type"; | |
73 return ""; | |
74 } | |
75 | |
76 const char* ConfigStateToString(ProxyPrefs::ConfigState state) { | |
77 switch (state) { | |
78 case ProxyPrefs::CONFIG_POLICY: | |
79 return "config_policy"; | |
80 case ProxyPrefs::CONFIG_EXTENSION: | |
81 return "config_extension"; | |
82 case ProxyPrefs::CONFIG_OTHER_PRECEDE: | |
83 return "config_other_precede"; | |
84 case ProxyPrefs::CONFIG_SYSTEM: | |
85 return "config_network"; // For ChromeOS, system is network. | |
86 case ProxyPrefs::CONFIG_FALLBACK: | |
87 return "config_recommended"; // Fallback is recommended. | |
88 case ProxyPrefs::CONFIG_UNSET: | |
89 return "config_unset"; | |
90 } | |
91 NOTREACHED() << "Unrecognized config state type"; | |
92 return ""; | |
93 } | |
94 | |
95 // Returns true if proxy settings from |network| is editable. | |
96 bool IsNetworkProxySettingsEditable(const Network* network) { | |
97 if (!network) | |
98 return true; // editable if no network given. | |
99 | |
100 NetworkLibrary* network_library = CrosLibrary::Get()->GetNetworkLibrary(); | |
101 const base::DictionaryValue* onc = | |
102 network_library->FindOncForNetwork(network->unique_id()); | |
103 | |
104 NetworkPropertyUIData proxy_settings_ui_data; | |
105 proxy_settings_ui_data.ParseOncProperty( | |
106 network->ui_data().onc_source(), | |
107 onc, | |
108 onc::network_config::kProxySettings); | |
109 return proxy_settings_ui_data.IsEditable(); | |
110 } | 40 } |
111 | 41 |
112 } // namespace | 42 } // namespace |
113 | 43 |
114 //----------- ProxyConfigServiceImpl::ProxyConfig: public methods -------------- | |
115 | |
116 ProxyConfigServiceImpl::ProxyConfig::ProxyConfig() | |
117 : mode(MODE_DIRECT), | |
118 state(ProxyPrefs::CONFIG_UNSET), | |
119 user_modifiable(true) {} | |
120 | |
121 ProxyConfigServiceImpl::ProxyConfig::~ProxyConfig() {} | |
122 | |
123 bool ProxyConfigServiceImpl::ProxyConfig::FromNetProxyConfig( | |
124 const net::ProxyConfig& net_config) { | |
125 *this = ProxyConfigServiceImpl::ProxyConfig(); // Reset to default. | |
126 const net::ProxyConfig::ProxyRules& rules = net_config.proxy_rules(); | |
127 switch (rules.type) { | |
128 case net::ProxyConfig::ProxyRules::TYPE_NO_RULES: | |
129 if (!net_config.HasAutomaticSettings()) { | |
130 mode = ProxyConfig::MODE_DIRECT; | |
131 } else if (net_config.auto_detect()) { | |
132 mode = ProxyConfig::MODE_AUTO_DETECT; | |
133 } else if (net_config.has_pac_url()) { | |
134 mode = ProxyConfig::MODE_PAC_SCRIPT; | |
135 automatic_proxy.pac_url = net_config.pac_url(); | |
136 } else { | |
137 return false; | |
138 } | |
139 return true; | |
140 case net::ProxyConfig::ProxyRules::TYPE_SINGLE_PROXY: | |
141 if (rules.single_proxies.IsEmpty()) | |
142 return false; | |
143 mode = MODE_SINGLE_PROXY; | |
144 single_proxy.server = rules.single_proxies.Get(); | |
145 bypass_rules = rules.bypass_rules; | |
146 return true; | |
147 case net::ProxyConfig::ProxyRules::TYPE_PROXY_PER_SCHEME: | |
148 // Make sure we have valid server for at least one of the protocols. | |
149 if (rules.proxies_for_http.IsEmpty() && | |
150 rules.proxies_for_https.IsEmpty() && | |
151 rules.proxies_for_ftp.IsEmpty() && | |
152 rules.fallback_proxies.IsEmpty()) { | |
153 return false; | |
154 } | |
155 mode = MODE_PROXY_PER_SCHEME; | |
156 if (!rules.proxies_for_http.IsEmpty()) | |
157 http_proxy.server = rules.proxies_for_http.Get(); | |
158 if (!rules.proxies_for_https.IsEmpty()) | |
159 https_proxy.server = rules.proxies_for_https.Get(); | |
160 if (!rules.proxies_for_ftp.IsEmpty()) | |
161 ftp_proxy.server = rules.proxies_for_ftp.Get(); | |
162 if (!rules.fallback_proxies.IsEmpty()) | |
163 socks_proxy.server = rules.fallback_proxies.Get(); | |
164 bypass_rules = rules.bypass_rules; | |
165 return true; | |
166 default: | |
167 NOTREACHED() << "Unrecognized proxy config mode"; | |
168 break; | |
169 } | |
170 return false; | |
171 } | |
172 | |
173 DictionaryValue* ProxyConfigServiceImpl::ProxyConfig::ToPrefProxyConfig() { | |
174 switch (mode) { | |
175 case MODE_DIRECT: { | |
176 return ProxyConfigDictionary::CreateDirect(); | |
177 } | |
178 case MODE_AUTO_DETECT: { | |
179 return ProxyConfigDictionary::CreateAutoDetect(); | |
180 } | |
181 case MODE_PAC_SCRIPT: { | |
182 return ProxyConfigDictionary::CreatePacScript( | |
183 automatic_proxy.pac_url.spec(), false); | |
184 } | |
185 case MODE_SINGLE_PROXY: { | |
186 std::string spec; | |
187 if (single_proxy.server.is_valid()) | |
188 spec = single_proxy.server.ToURI(); | |
189 return ProxyConfigDictionary::CreateFixedServers( | |
190 spec, bypass_rules.ToString()); | |
191 } | |
192 case MODE_PROXY_PER_SCHEME: { | |
193 std::string spec; | |
194 EncodeAndAppendProxyServer("http", http_proxy.server, &spec); | |
195 EncodeAndAppendProxyServer("https", https_proxy.server, &spec); | |
196 EncodeAndAppendProxyServer("ftp", ftp_proxy.server, &spec); | |
197 EncodeAndAppendProxyServer("socks", socks_proxy.server, &spec); | |
198 return ProxyConfigDictionary::CreateFixedServers( | |
199 spec, bypass_rules.ToString()); | |
200 } | |
201 default: | |
202 break; | |
203 } | |
204 NOTREACHED() << "Unrecognized proxy config mode for preference"; | |
205 return NULL; | |
206 } | |
207 | |
208 ProxyConfigServiceImpl::ProxyConfig::ManualProxy* | |
209 ProxyConfigServiceImpl::ProxyConfig::MapSchemeToProxy( | |
210 const std::string& scheme) { | |
211 if (scheme == "http") | |
212 return &http_proxy; | |
213 if (scheme == "https") | |
214 return &https_proxy; | |
215 if (scheme == "ftp") | |
216 return &ftp_proxy; | |
217 if (scheme == "socks") | |
218 return &socks_proxy; | |
219 NOTREACHED() << "Invalid scheme: " << scheme; | |
220 return NULL; | |
221 } | |
222 | |
223 bool ProxyConfigServiceImpl::ProxyConfig::SerializeForNetwork( | |
224 std::string* output) { | |
225 scoped_ptr<DictionaryValue> proxy_dict_ptr(ToPrefProxyConfig()); | |
226 if (!proxy_dict_ptr.get()) | |
227 return false; | |
228 | |
229 // Return empty string for direct mode for portal check to work correctly. | |
230 DictionaryValue *dict = proxy_dict_ptr.get(); | |
231 ProxyConfigDictionary proxy_dict(dict); | |
232 ProxyPrefs::ProxyMode mode; | |
233 if (proxy_dict.GetMode(&mode)) { | |
234 if (mode == ProxyPrefs::MODE_DIRECT) { | |
235 output->clear(); | |
236 return true; | |
237 } | |
238 } | |
239 JSONStringValueSerializer serializer(output); | |
240 return serializer.Serialize(*dict); | |
241 } | |
242 | |
243 //----------- ProxyConfigServiceImpl::ProxyConfig: private methods ------------- | |
244 | |
245 // static | |
246 void ProxyConfigServiceImpl::ProxyConfig::EncodeAndAppendProxyServer( | |
247 const std::string& url_scheme, | |
248 const net::ProxyServer& server, | |
249 std::string* spec) { | |
250 if (!server.is_valid()) | |
251 return; | |
252 | |
253 if (!spec->empty()) | |
254 *spec += ';'; | |
255 | |
256 if (!url_scheme.empty()) { | |
257 *spec += url_scheme; | |
258 *spec += "="; | |
259 } | |
260 *spec += server.ToURI(); | |
261 } | |
262 | |
263 //------------------- ProxyConfigServiceImpl: public methods ------------------- | |
264 | |
265 ProxyConfigServiceImpl::ProxyConfigServiceImpl(PrefService* pref_service) | 44 ProxyConfigServiceImpl::ProxyConfigServiceImpl(PrefService* pref_service) |
266 : PrefProxyConfigTrackerImpl(pref_service), | 45 : PrefProxyConfigTrackerImpl(pref_service), |
267 active_config_state_(ProxyPrefs::CONFIG_UNSET), | 46 active_config_state_(ProxyPrefs::CONFIG_UNSET), |
| 47 ui_proxy_config_service_(pref_service), |
268 pointer_factory_(this) { | 48 pointer_factory_(this) { |
269 | 49 |
270 // Register for notifications of UseSharedProxies user preference. | 50 // Register for notifications of UseSharedProxies user preference. |
271 if (pref_service->FindPreference(prefs::kUseSharedProxies)) { | 51 if (pref_service->FindPreference(prefs::kUseSharedProxies)) { |
272 use_shared_proxies_.Init( | 52 use_shared_proxies_.Init( |
273 prefs::kUseSharedProxies, pref_service, | 53 prefs::kUseSharedProxies, pref_service, |
274 base::Bind(&ProxyConfigServiceImpl::OnUseSharedProxiesChanged, | 54 base::Bind(&ProxyConfigServiceImpl::OnUseSharedProxiesChanged, |
275 base::Unretained(this))); | 55 base::Unretained(this))); |
276 } | 56 } |
277 | 57 |
278 // Register for shill network notifications. | 58 // Register for changes to the default network. |
279 NetworkLibrary* network_lib = CrosLibrary::Get()->GetNetworkLibrary(); | 59 NetworkStateHandler* state_handler = |
280 OnActiveNetworkChanged(network_lib, network_lib->active_network()); | 60 NetworkHandler::Get()->network_state_handler(); |
281 network_lib->AddNetworkManagerObserver(this); | 61 state_handler->AddObserver(this); |
| 62 DefaultNetworkChanged(state_handler->DefaultNetwork()); |
282 } | 63 } |
283 | 64 |
284 ProxyConfigServiceImpl::~ProxyConfigServiceImpl() { | 65 ProxyConfigServiceImpl::~ProxyConfigServiceImpl() { |
285 NetworkLibrary* netlib = CrosLibrary::Get()->GetNetworkLibrary(); | 66 if (NetworkHandler::IsInitialized()) |
286 if (netlib) { | 67 NetworkHandler::Get()->network_state_handler()->RemoveObserver(this); |
287 netlib->RemoveNetworkManagerObserver(this); | |
288 netlib->RemoveObserverForAllNetworks(this); | |
289 } | |
290 } | 68 } |
291 | 69 |
292 void ProxyConfigServiceImpl::UISetCurrentNetwork( | 70 UIProxyConfigService& ProxyConfigServiceImpl::GetUIService() { |
293 const std::string& current_network) { | 71 return ui_proxy_config_service_; |
294 Network* network = CrosLibrary::Get()->GetNetworkLibrary()->FindNetworkByPath( | |
295 current_network); | |
296 if (!network) { | |
297 ResetUICache(); | |
298 LOG(ERROR) << "Can't find requested network " << current_network; | |
299 return; | |
300 } | |
301 current_ui_network_ = current_network; | |
302 OnUISetCurrentNetwork(network); | |
303 } | |
304 | |
305 void ProxyConfigServiceImpl::UIMakeActiveNetworkCurrent() { | |
306 Network* network = CrosLibrary::Get()->GetNetworkLibrary()->FindNetworkByPath( | |
307 active_network_); | |
308 if (!network) { | |
309 ResetUICache(); | |
310 LOG(ERROR) << "Can't find requested network " << active_network_; | |
311 return; | |
312 } | |
313 current_ui_network_ = active_network_; | |
314 OnUISetCurrentNetwork(network); | |
315 } | |
316 | |
317 void ProxyConfigServiceImpl::UIGetCurrentNetworkName( | |
318 std::string* network_name) { | |
319 if (!network_name) | |
320 return; | |
321 network_name->clear(); | |
322 Network* network = CrosLibrary::Get()->GetNetworkLibrary()->FindNetworkByPath( | |
323 current_ui_network_); | |
324 if (!network) { | |
325 LOG(ERROR) << "Can't find requested network " << current_ui_network_; | |
326 return; | |
327 } | |
328 if (network->name().empty() && network->type() == chromeos::TYPE_ETHERNET) { | |
329 *network_name = | |
330 l10n_util::GetStringUTF8(IDS_STATUSBAR_NETWORK_DEVICE_ETHERNET); | |
331 } else { | |
332 *network_name = network->name(); | |
333 } | |
334 } | |
335 | |
336 void ProxyConfigServiceImpl::UIGetProxyConfig(ProxyConfig* config) { | |
337 // Simply returns the copy last set from UI via UISetCurrentNetwork or | |
338 // UIMakeActiveNetworkCurrent. | |
339 *config = current_ui_config_; | |
340 } | |
341 | |
342 bool ProxyConfigServiceImpl::UISetProxyConfigToDirect() { | |
343 current_ui_config_.mode = ProxyConfig::MODE_DIRECT; | |
344 OnUISetProxyConfig(); | |
345 return true; | |
346 } | |
347 | |
348 bool ProxyConfigServiceImpl::UISetProxyConfigToAutoDetect() { | |
349 current_ui_config_.mode = ProxyConfig::MODE_AUTO_DETECT; | |
350 OnUISetProxyConfig(); | |
351 return true; | |
352 } | |
353 | |
354 bool ProxyConfigServiceImpl::UISetProxyConfigToPACScript(const GURL& pac_url) { | |
355 current_ui_config_.mode = ProxyConfig::MODE_PAC_SCRIPT; | |
356 current_ui_config_.automatic_proxy.pac_url = pac_url; | |
357 OnUISetProxyConfig(); | |
358 return true; | |
359 } | |
360 | |
361 bool ProxyConfigServiceImpl::UISetProxyConfigToSingleProxy( | |
362 const net::ProxyServer& server) { | |
363 current_ui_config_.mode = ProxyConfig::MODE_SINGLE_PROXY; | |
364 current_ui_config_.single_proxy.server = server; | |
365 OnUISetProxyConfig(); | |
366 return true; | |
367 } | |
368 | |
369 bool ProxyConfigServiceImpl::UISetProxyConfigToProxyPerScheme( | |
370 const std::string& scheme, const net::ProxyServer& server) { | |
371 ProxyConfig::ManualProxy* proxy = current_ui_config_.MapSchemeToProxy(scheme); | |
372 if (!proxy) { | |
373 NOTREACHED() << "Cannot set proxy: invalid scheme [" << scheme << "]"; | |
374 return false; | |
375 } | |
376 current_ui_config_.mode = ProxyConfig::MODE_PROXY_PER_SCHEME; | |
377 proxy->server = server; | |
378 OnUISetProxyConfig(); | |
379 return true; | |
380 } | |
381 | |
382 bool ProxyConfigServiceImpl::UISetProxyConfigBypassRules( | |
383 const net::ProxyBypassRules& bypass_rules) { | |
384 if (current_ui_config_.mode != ProxyConfig::MODE_SINGLE_PROXY && | |
385 current_ui_config_.mode != ProxyConfig::MODE_PROXY_PER_SCHEME) { | |
386 NOTREACHED(); | |
387 VLOG(1) << "Cannot set bypass rules for proxy mode [" | |
388 << current_ui_config_.mode << "]"; | |
389 return false; | |
390 } | |
391 current_ui_config_.bypass_rules = bypass_rules; | |
392 OnUISetProxyConfig(); | |
393 return true; | |
394 } | |
395 | |
396 void ProxyConfigServiceImpl::AddNotificationCallback(base::Closure callback) { | |
397 | |
398 std::vector<base::Closure>::iterator iter = | |
399 findIfEqual(callbacks_.begin(), callbacks_.end(), callback); | |
400 if (iter == callbacks_.end()) | |
401 callbacks_.push_back(callback); | |
402 } | |
403 | |
404 void ProxyConfigServiceImpl::RemoveNotificationCallback( | |
405 base::Closure callback) { | |
406 std::vector<base::Closure>::iterator iter = | |
407 findIfEqual(callbacks_.begin(), callbacks_.end(), callback); | |
408 if (iter != callbacks_.end()) | |
409 callbacks_.erase(iter); | |
410 } | 72 } |
411 | 73 |
412 void ProxyConfigServiceImpl::OnProxyConfigChanged( | 74 void ProxyConfigServiceImpl::OnProxyConfigChanged( |
413 ProxyPrefs::ConfigState config_state, | 75 ProxyPrefs::ConfigState config_state, |
414 const net::ProxyConfig& config) { | 76 const net::ProxyConfig& config) { |
415 VLOG(1) << "Got prefs change: " << ConfigStateToString(config_state) | 77 VLOG(1) << "Got prefs change: " |
| 78 << ProxyPrefs::ConfigStateToDebugString(config_state) |
416 << ", mode=" << config.proxy_rules().type; | 79 << ", mode=" << config.proxy_rules().type; |
417 Network* network = NULL; | 80 DetermineEffectiveConfigFromDefaultNetwork(); |
418 if (!active_network_.empty()) { | |
419 network = CrosLibrary::Get()->GetNetworkLibrary()->FindNetworkByPath( | |
420 active_network_); | |
421 if (!network) | |
422 LOG(ERROR) << "can't find requested network " << active_network_; | |
423 } | |
424 DetermineEffectiveConfig(network, true); | |
425 } | |
426 | |
427 void ProxyConfigServiceImpl::OnNetworkManagerChanged( | |
428 NetworkLibrary* network_lib) { | |
429 VLOG(1) << "OnNetworkManagerChanged: use-shared-proxies=" | |
430 << GetUseSharedProxies(); | |
431 OnActiveNetworkChanged(network_lib, network_lib->active_network()); | |
432 } | |
433 | |
434 void ProxyConfigServiceImpl::OnNetworkChanged(NetworkLibrary* network_lib, | |
435 const Network* network) { | |
436 if (!network) | |
437 return; | |
438 VLOG(1) << "OnNetworkChanged: " | |
439 << (network->name().empty() ? network->service_path() : | |
440 network->name()) | |
441 << ", use-shared-proxies=" << GetUseSharedProxies(); | |
442 // We only care about active network. | |
443 if (network == network_lib->active_network()) | |
444 OnActiveNetworkChanged(network_lib, network); | |
445 } | 81 } |
446 | 82 |
447 // static | 83 // static |
448 bool ProxyConfigServiceImpl::ParseProxyConfig( | |
449 const std::string& proxy_config_string, | |
450 net::ProxyConfig* proxy_config) { | |
451 if (!proxy_config) | |
452 return false; | |
453 JSONStringValueSerializer serializer(proxy_config_string); | |
454 scoped_ptr<Value> value(serializer.Deserialize(NULL, NULL)); | |
455 if (!value.get() || value->GetType() != Value::TYPE_DICTIONARY) | |
456 return false; | |
457 ProxyConfigDictionary proxy_dict(static_cast<DictionaryValue*>(value.get())); | |
458 return PrefProxyConfigTrackerImpl::PrefConfigToNetConfig(proxy_dict, | |
459 proxy_config); | |
460 } | |
461 | |
462 // static | |
463 void ProxyConfigServiceImpl::RegisterPrefs(PrefRegistrySimple* registry) { | 84 void ProxyConfigServiceImpl::RegisterPrefs(PrefRegistrySimple* registry) { |
464 // Use shared proxies default to off. GetUseSharedProxies will return the | 85 // Use shared proxies default to off. GetUseSharedProxies will return the |
465 // correct value based on pre-login and login. | 86 // correct value based on pre-login and login. |
466 registry->RegisterBooleanPref(prefs::kUseSharedProxies, true); | 87 registry->RegisterBooleanPref(prefs::kUseSharedProxies, true); |
467 } | 88 } |
468 | 89 |
469 // static | 90 // static |
470 void ProxyConfigServiceImpl::RegisterUserPrefs( | 91 void ProxyConfigServiceImpl::RegisterUserPrefs( |
471 user_prefs::PrefRegistrySyncable* registry) { | 92 user_prefs::PrefRegistrySyncable* registry) { |
472 registry->RegisterBooleanPref( | 93 registry->RegisterBooleanPref( |
473 prefs::kUseSharedProxies, | 94 prefs::kUseSharedProxies, |
474 true, | 95 true, |
475 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); | 96 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); |
476 } | 97 } |
477 | 98 |
478 //------------------ ProxyConfigServiceImpl: private methods ------------------- | |
479 | |
480 void ProxyConfigServiceImpl::OnUseSharedProxiesChanged() { | 99 void ProxyConfigServiceImpl::OnUseSharedProxiesChanged() { |
481 VLOG(1) << "New use-shared-proxies = " << GetUseSharedProxies(); | 100 VLOG(1) << "New use-shared-proxies = " << GetUseSharedProxies(prefs()); |
482 | 101 DetermineEffectiveConfigFromDefaultNetwork(); |
483 // Determine new proxy config which may have changed because of new | |
484 // use-shared-proxies. If necessary, activate it. | |
485 Network* network = NULL; | |
486 if (!active_network_.empty()) { | |
487 network = CrosLibrary::Get()->GetNetworkLibrary()->FindNetworkByPath( | |
488 active_network_); | |
489 if (!network) | |
490 LOG(WARNING) << "Can't find requested network " << active_network_; | |
491 } | |
492 DetermineEffectiveConfig(network, true); | |
493 } | 102 } |
494 | 103 |
495 void ProxyConfigServiceImpl::OnUISetProxyConfig() { | 104 void ProxyConfigServiceImpl::DefaultNetworkChanged( |
496 if (current_ui_network_.empty()) | 105 const NetworkState* new_network) { |
497 return; | 106 std::string new_network_path; |
498 // Update config to shill. | 107 if (new_network) |
499 std::string value; | 108 new_network_path = new_network->path(); |
500 if (current_ui_config_.SerializeForNetwork(&value)) { | 109 |
501 VLOG(1) << "Set proxy (mode=" << current_ui_config_.mode | 110 VLOG(1) << "DefaultNetworkChanged to '" << new_network_path << "'."; |
502 << ") for " << current_ui_network_; | 111 VLOG_IF(1, new_network) << "New network: name=" << new_network->name() |
503 current_ui_config_.state = ProxyPrefs::CONFIG_SYSTEM; | 112 << ", proxy=" << new_network->proxy_config() |
504 SetProxyConfigForNetwork(current_ui_network_, value, false); | 113 << ", profile=" << new_network->profile_path(); |
505 } | 114 |
| 115 // Even if the default network is the same, its proxy config (e.g. if private |
| 116 // version of network replaces the shared version after login), or |
| 117 // use-shared-proxies setting (e.g. after login) may have changed, so |
| 118 // re-determine effective proxy config, and activate if different. |
| 119 DetermineEffectiveConfigFromDefaultNetwork(); |
506 } | 120 } |
507 | 121 |
508 void ProxyConfigServiceImpl::OnActiveNetworkChanged(NetworkLibrary* network_lib, | 122 // static |
509 const Network* active_network) { | 123 bool ProxyConfigServiceImpl::GetUseSharedProxies( |
510 std::string new_network; | 124 const PrefService* pref_service) { |
511 if (active_network) | 125 const PrefService::Preference* use_shared_proxies_pref = |
512 new_network = active_network->service_path(); | 126 pref_service->FindPreference(prefs::kUseSharedProxies); |
| 127 if (!use_shared_proxies_pref || !use_shared_proxies_pref->GetValue()) { |
| 128 if (UserManager::Get()->IsUserLoggedIn()) { |
| 129 VLOG(1) << "use-shared-proxies not set, defaulting to false/IgnoreProxy."; |
| 130 return false; |
| 131 } else { |
| 132 // Make sure that proxies are always enabled at sign in screen. |
| 133 VLOG(1) << "Use proxy on login screen."; |
| 134 return true; |
| 135 } |
| 136 } |
| 137 bool use_shared_proxies = false; |
| 138 use_shared_proxies_pref->GetValue()->GetAsBoolean(&use_shared_proxies); |
| 139 return use_shared_proxies; |
| 140 } |
513 | 141 |
514 if (active_network_ == new_network) { // Same active network. | 142 // static |
515 VLOG(1) << "Same active network: " | 143 bool ProxyConfigServiceImpl::IgnoreProxy(const PrefService* pref_service, |
516 << (new_network.empty() ? "empty" : | 144 const std::string network_profile_path, |
517 (active_network->name().empty() ? | 145 onc::ONCSource onc_source) { |
518 new_network : active_network->name())); | 146 const NetworkProfile* profile = |
519 // Even though network is the same, its proxy config (e.g. if private | 147 NetworkHandler::Get()->network_profile_handler()-> |
520 // version of network replaces the shared version after login), or | 148 GetProfileForPath(network_profile_path); |
521 // use-shared-proxies setting (e.g. after login) may have changed, | 149 if (!profile) { |
522 // so re-determine effective proxy config, and activate if different. | 150 LOG(WARNING) << "Unknown profile_path " << network_profile_path; |
523 if (active_network) { | 151 return true; |
524 VLOG(1) << "Profile=" << active_network->profile_type() | 152 } |
525 << "," << active_network->profile_path() | 153 if (profile->type() == NetworkProfile::TYPE_USER) { |
526 << ", proxy=" << active_network->proxy_config(); | 154 VLOG(1) << "Respect proxy of not-shared networks."; |
527 DetermineEffectiveConfig(active_network, true); | 155 return false; |
528 } | |
529 return; | |
530 } | 156 } |
531 | 157 |
532 // If there was a previous active network, remove it as observer. | 158 if (onc_source == onc::ONC_SOURCE_DEVICE_POLICY && |
533 if (!active_network_.empty()) | |
534 network_lib->RemoveNetworkObserver(active_network_, this); | |
535 | |
536 active_network_ = new_network; | |
537 | |
538 if (active_network_.empty()) { | |
539 VLOG(1) << "New active network: empty"; | |
540 DetermineEffectiveConfig(active_network, true); | |
541 return; | |
542 } | |
543 | |
544 VLOG(1) << "New active network: path=" << active_network->service_path() | |
545 << ", name=" << active_network->name() | |
546 << ", profile=" << active_network->profile_type() | |
547 << "," << active_network->profile_path() | |
548 << ", proxy=" << active_network->proxy_config(); | |
549 | |
550 // Register observer for new network. | |
551 network_lib->AddNetworkObserver(active_network_, this); | |
552 | |
553 // Determine and activate possibly new effective proxy config. | |
554 DetermineEffectiveConfig(active_network, true); | |
555 } | |
556 | |
557 void ProxyConfigServiceImpl::SetProxyConfigForNetwork( | |
558 const std::string& network_path, const std::string& value, | |
559 bool only_set_if_empty) { | |
560 Network* network = CrosLibrary::Get()->GetNetworkLibrary()->FindNetworkByPath( | |
561 network_path); | |
562 if (!network) { | |
563 NOTREACHED() << "Can't find requested network " << network_path; | |
564 return; | |
565 } | |
566 if (!only_set_if_empty || network->proxy_config().empty()) { | |
567 network->SetProxyConfig(value); | |
568 VLOG(1) << "Set proxy for " | |
569 << (network->name().empty() ? network_path : network->name()) | |
570 << ", value=" << value; | |
571 if (network_path == active_network_) | |
572 DetermineEffectiveConfig(network, true); | |
573 } | |
574 } | |
575 | |
576 bool ProxyConfigServiceImpl::GetUseSharedProxies() { | |
577 const PrefService::Preference* use_shared_proxies_pref = | |
578 prefs()->FindPreference(prefs::kUseSharedProxies); | |
579 if (!use_shared_proxies_pref) { | |
580 // Make sure that proxies are always enabled at sign in screen. | |
581 return !UserManager::Get()->IsUserLoggedIn(); | |
582 } | |
583 return use_shared_proxies_.GetValue(); | |
584 } | |
585 | |
586 bool ProxyConfigServiceImpl::IgnoreProxy(const Network* network) { | |
587 if (network->profile_type() == PROFILE_USER) | |
588 return false; | |
589 | |
590 if (network->ui_data().onc_source() == onc::ONC_SOURCE_DEVICE_POLICY && | |
591 UserManager::Get()->IsUserLoggedIn()) { | 159 UserManager::Get()->IsUserLoggedIn()) { |
592 policy::BrowserPolicyConnector* connector = | 160 policy::BrowserPolicyConnector* connector = |
593 g_browser_process->browser_policy_connector(); | 161 g_browser_process->browser_policy_connector(); |
594 const User* logged_in_user = UserManager::Get()->GetLoggedInUser(); | 162 const User* logged_in_user = UserManager::Get()->GetLoggedInUser(); |
595 if (connector->GetUserAffiliation(logged_in_user->email()) == | 163 if (connector->GetUserAffiliation(logged_in_user->email()) == |
596 policy::USER_AFFILIATION_MANAGED) { | 164 policy::USER_AFFILIATION_MANAGED) { |
597 VLOG(1) << "Respecting proxy for network " << network->name() | 165 VLOG(1) << "Respecting proxy for network, as logged-in user belongs to " |
598 << ", as logged-in user belongs to the domain the device " | 166 << "the domain the device is enrolled to."; |
599 << "is enrolled to."; | |
600 return false; | 167 return false; |
601 } | 168 } |
602 } | 169 } |
603 | 170 |
604 return !GetUseSharedProxies(); | 171 return !GetUseSharedProxies(pref_service); |
605 } | 172 } |
606 | 173 |
607 void ProxyConfigServiceImpl::DetermineEffectiveConfig(const Network* network, | 174 void ProxyConfigServiceImpl::DetermineEffectiveConfigFromDefaultNetwork() { |
608 bool activate) { | 175 const NetworkState* network = |
| 176 NetworkHandler::Get()->network_state_handler()->DefaultNetwork(); |
| 177 |
609 // Get prefs proxy config if available. | 178 // Get prefs proxy config if available. |
610 net::ProxyConfig pref_config; | 179 net::ProxyConfig pref_config; |
611 ProxyPrefs::ConfigState pref_state = GetProxyConfig(&pref_config); | 180 ProxyPrefs::ConfigState pref_state = GetProxyConfig(&pref_config); |
612 | 181 |
613 // Get network proxy config if available. | 182 // Get network proxy config if available. |
614 net::ProxyConfig network_config; | 183 net::ProxyConfig network_config; |
615 net::ProxyConfigService::ConfigAvailability network_availability = | 184 net::ProxyConfigService::ConfigAvailability network_availability = |
616 net::ProxyConfigService::CONFIG_UNSET; | 185 net::ProxyConfigService::CONFIG_UNSET; |
617 bool ignore_proxy = activate; | 186 bool ignore_proxy = true; |
618 if (network) { | 187 if (network) { |
619 // If we're activating proxy, ignore proxy if necessary; | 188 ignore_proxy = |
620 // otherwise, for ui, get actual proxy to show user. | 189 IgnoreProxy(prefs(), network->profile_path(), network->onc_source()); |
621 ignore_proxy = activate ? IgnoreProxy(network) : false; | |
622 // If network is shared but use-shared-proxies is off, use direct mode. | 190 // If network is shared but use-shared-proxies is off, use direct mode. |
623 if (ignore_proxy) { | 191 if (ignore_proxy) { |
624 VLOG(1) << "Shared network && !use-shared-proxies, use direct"; | 192 VLOG(1) << "Shared network && !use-shared-proxies, use direct"; |
625 network_availability = net::ProxyConfigService::CONFIG_VALID; | 193 network_availability = net::ProxyConfigService::CONFIG_VALID; |
626 } else if (!network->proxy_config().empty()) { | 194 } else if (ParseProxyConfig(network->proxy_config(), &network_config)) { |
627 // Network is private or shared with user using shared proxies. | 195 // Network is private or shared with user using shared proxies. |
628 if (ParseProxyConfig(network->proxy_config(), &network_config)) { | 196 VLOG(1) << this << ": using network proxy: " |
629 VLOG(1) << this << ": using network proxy: " | 197 << network->proxy_config(); |
630 << network->proxy_config(); | 198 network_availability = net::ProxyConfigService::CONFIG_VALID; |
631 network_availability = net::ProxyConfigService::CONFIG_VALID; | |
632 } | |
633 } | 199 } |
634 } | 200 } |
635 | 201 |
636 // Determine effective proxy config, either from prefs or network. | 202 // Determine effective proxy config, either from prefs or network. |
637 ProxyPrefs::ConfigState effective_config_state; | 203 ProxyPrefs::ConfigState effective_config_state; |
638 net::ProxyConfig effective_config; | 204 net::ProxyConfig effective_config; |
639 GetEffectiveProxyConfig(pref_state, pref_config, | 205 GetEffectiveProxyConfig(pref_state, pref_config, |
640 network_availability, network_config, ignore_proxy, | 206 network_availability, network_config, ignore_proxy, |
641 &effective_config_state, &effective_config); | 207 &effective_config_state, &effective_config); |
642 | 208 |
643 // Determine if we should activate effective proxy and which proxy config to | 209 // Activate effective proxy and store into |active_config_|. |
644 // store it. | 210 // If last update didn't complete, we definitely update now. |
645 if (activate) { // Activate effective proxy and store into |active_config_|. | 211 bool update_now = update_pending(); |
646 // If last update didn't complete, we definitely update now. | 212 if (!update_now) { // Otherwise, only update now if there're changes. |
647 bool update_now = update_pending(); | 213 update_now = active_config_state_ != effective_config_state || |
648 if (!update_now) { // Otherwise, only update now if there're changes. | 214 (active_config_state_ != ProxyPrefs::CONFIG_UNSET && |
649 update_now = active_config_state_ != effective_config_state || | 215 !active_config_.Equals(effective_config)); |
650 (active_config_state_ != ProxyPrefs::CONFIG_UNSET && | 216 } |
651 !active_config_.Equals(effective_config)); | 217 if (update_now) { // Activate and store new effective config. |
652 } | 218 active_config_state_ = effective_config_state; |
653 if (update_now) { // Activate and store new effective config. | 219 if (active_config_state_ != ProxyPrefs::CONFIG_UNSET) |
654 active_config_state_ = effective_config_state; | 220 active_config_ = effective_config; |
655 if (active_config_state_ != ProxyPrefs::CONFIG_UNSET) | 221 // If effective config is from system (i.e. network), it's considered a |
656 active_config_ = effective_config; | 222 // special kind of prefs that ranks below policy/extension but above |
657 // If effective config is from system (i.e. network), it's considered a | 223 // others, so bump it up to CONFIG_OTHER_PRECEDE to force its precedence |
658 // special kind of prefs that ranks below policy/extension but above | 224 // when PrefProxyConfigTrackerImpl pushes it to ChromeProxyConfigService. |
659 // others, so bump it up to CONFIG_OTHER_PRECEDE to force its precedence | 225 if (effective_config_state == ProxyPrefs::CONFIG_SYSTEM) |
660 // when PrefProxyConfigTrackerImpl pushes it to ChromeProxyConfigService. | 226 effective_config_state = ProxyPrefs::CONFIG_OTHER_PRECEDE; |
661 if (effective_config_state == ProxyPrefs::CONFIG_SYSTEM) | 227 // If config is manual, add rule to bypass local host. |
662 effective_config_state = ProxyPrefs::CONFIG_OTHER_PRECEDE; | 228 if (effective_config.proxy_rules().type != |
663 // If config is manual, add rule to bypass local host. | 229 net::ProxyConfig::ProxyRules::TYPE_NO_RULES) |
664 if (effective_config.proxy_rules().type != | 230 effective_config.proxy_rules().bypass_rules.AddRuleToBypassLocal(); |
665 net::ProxyConfig::ProxyRules::TYPE_NO_RULES) | 231 PrefProxyConfigTrackerImpl::OnProxyConfigChanged(effective_config_state, |
666 effective_config.proxy_rules().bypass_rules.AddRuleToBypassLocal(); | 232 effective_config); |
667 PrefProxyConfigTrackerImpl::OnProxyConfigChanged(effective_config_state, | 233 if (VLOG_IS_ON(1) && !update_pending()) { // Update was successful. |
668 effective_config); | 234 scoped_ptr<base::DictionaryValue> config_dict( |
669 if (VLOG_IS_ON(1) && !update_pending()) { // Update was successful. | 235 effective_config.ToValue()); |
670 scoped_ptr<DictionaryValue> config_dict(static_cast<DictionaryValue*>( | 236 VLOG(1) << this << ": Proxy changed: " |
671 effective_config.ToValue())); | 237 << ProxyPrefs::ConfigStateToDebugString(active_config_state_) |
672 std::string config_value; | 238 << ", " << *config_dict; |
673 JSONStringValueSerializer serializer(&config_value); | |
674 serializer.Serialize(*config_dict.get()); | |
675 VLOG(1) << this << ": Proxy changed: " | |
676 << ConfigStateToString(active_config_state_) | |
677 << ", " << config_value; | |
678 } | |
679 } | |
680 } else { // For UI, store effective proxy into |current_ui_config_|. | |
681 current_ui_config_.FromNetProxyConfig(effective_config); | |
682 current_ui_config_.state = effective_config_state; | |
683 if (PrefPrecedes(effective_config_state)) { | |
684 current_ui_config_.user_modifiable = false; | |
685 } else if (!IsNetworkProxySettingsEditable(network)) { | |
686 // TODO(xiyuan): Figure out the right way to set config state for managed | |
687 // network. | |
688 current_ui_config_.state = ProxyPrefs::CONFIG_POLICY; | |
689 current_ui_config_.user_modifiable = false; | |
690 } else { | |
691 current_ui_config_.user_modifiable = !network || !IgnoreProxy(network); | |
692 } | 239 } |
693 } | 240 } |
694 } | 241 } |
695 | 242 |
696 void ProxyConfigServiceImpl::OnUISetCurrentNetwork(const Network* network) { | |
697 DetermineEffectiveConfig(network, false); | |
698 VLOG(1) << "Current ui network: " | |
699 << (network->name().empty() ? current_ui_network_ : network->name()) | |
700 << ", " << ModeToString(current_ui_config_.mode) | |
701 << ", " << ConfigStateToString(current_ui_config_.state) | |
702 << ", modifiable:" << current_ui_config_.user_modifiable; | |
703 // Notify whoever is interested in this change. | |
704 std::vector<base::Closure>::iterator iter = callbacks_.begin(); | |
705 while (iter != callbacks_.end()) { | |
706 if (iter->is_null()) { | |
707 iter = callbacks_.erase(iter); | |
708 } else { | |
709 iter->Run(); | |
710 ++iter; | |
711 } | |
712 } | |
713 } | |
714 | |
715 void ProxyConfigServiceImpl::ResetUICache() { | |
716 current_ui_network_.clear(); | |
717 current_ui_config_ = ProxyConfig(); | |
718 } | |
719 | |
720 } // namespace chromeos | 243 } // namespace chromeos |
OLD | NEW |