chromeos: Lock proxy settings UI for policy managed network.
[chromium-blink-merge.git] / chrome / browser / chromeos / proxy_config_service_impl.cc
blob5e74ae16e2bbe3e6014ef258cf8ab29c12a106ec
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
3 // found in the LICENSE file.
5 #include "chrome/browser/chromeos/proxy_config_service_impl.h"
7 #include <ostream>
9 #include "base/bind.h"
10 #include "base/json/json_value_serializer.h"
11 #include "base/logging.h"
12 #include "base/string_util.h"
13 #include "chrome/browser/chromeos/cros/cros_library.h"
14 #include "chrome/browser/chromeos/cros/onc_constants.h"
15 #include "chrome/browser/chromeos/cros_settings.h"
16 #include "chrome/browser/chromeos/cros_settings_names.h"
17 #include "chrome/browser/chromeos/login/user_manager.h"
18 #include "chrome/browser/policy/proto/chrome_device_policy.pb.h"
19 #include "chrome/browser/prefs/pref_service.h"
20 #include "chrome/browser/prefs/proxy_config_dictionary.h"
21 #include "chrome/browser/prefs/proxy_prefs.h"
22 #include "chrome/browser/profiles/profile_manager.h"
23 #include "chrome/common/chrome_notification_types.h"
24 #include "chrome/common/pref_names.h"
25 #include "content/public/browser/notification_service.h"
26 #include "grit/generated_resources.h"
27 #include "ui/base/l10n/l10n_util.h"
29 namespace em = enterprise_management;
31 namespace chromeos {
33 namespace {
35 // Shoud we try to push this to base?
36 // Helper comparator functor for the find_if call in |findIfEqual|
37 template <class T>
38 class EqualsComparator{
39 public:
40 explicit EqualsComparator(const T& key) : key_(key) { }
41 bool operator() (const T& element) {
42 return element.Equals(key_);
44 private:
45 const T& key_;
48 // Tiny STL helper function to allow using the find_if syntax on objects that
49 // doesn't use the operator== but implement the Equals function which is the
50 // quasi standard with the coding style we have.
51 template<class InputIterator, class T>
52 InputIterator findIfEqual(InputIterator first, InputIterator last,
53 const T& key) {
54 return std::find_if(first, last, EqualsComparator<T>(key));
57 const char* ModeToString(ProxyConfigServiceImpl::ProxyConfig::Mode mode) {
58 switch (mode) {
59 case ProxyConfigServiceImpl::ProxyConfig::MODE_DIRECT:
60 return "direct";
61 case ProxyConfigServiceImpl::ProxyConfig::MODE_AUTO_DETECT:
62 return "auto-detect";
63 case ProxyConfigServiceImpl::ProxyConfig::MODE_PAC_SCRIPT:
64 return "pacurl";
65 case ProxyConfigServiceImpl::ProxyConfig::MODE_SINGLE_PROXY:
66 return "single-proxy";
67 case ProxyConfigServiceImpl::ProxyConfig::MODE_PROXY_PER_SCHEME:
68 return "proxy-per-scheme";
70 NOTREACHED() << "Unrecognized mode type";
71 return "";
74 const char* ConfigStateToString(ProxyPrefs::ConfigState state) {
75 switch (state) {
76 case ProxyPrefs::CONFIG_POLICY:
77 return "config_policy";
78 case ProxyPrefs::CONFIG_EXTENSION:
79 return "config_extension";
80 case ProxyPrefs::CONFIG_OTHER_PRECEDE:
81 return "config_other_precede";
82 case ProxyPrefs::CONFIG_SYSTEM:
83 return "config_network"; // For ChromeOS, system is network.
84 case ProxyPrefs::CONFIG_FALLBACK:
85 return "config_recommended"; // Fallback is recommended.
86 case ProxyPrefs::CONFIG_UNSET:
87 return "config_unset";
89 NOTREACHED() << "Unrecognized config state type";
90 return "";
93 // Returns true if proxy settings from |network| is editable.
94 bool IsNetworkProxySettingsEditable(const Network* network) {
95 if (!network)
96 return true; // editable if no network given.
98 NetworkLibrary* network_library = CrosLibrary::Get()->GetNetworkLibrary();
99 const base::DictionaryValue* onc =
100 network_library->FindOncForNetwork(network->unique_id());
102 NetworkPropertyUIData proxy_settings_ui_data;
103 proxy_settings_ui_data.ParseOncProperty(
104 network->ui_data(),
105 onc,
106 onc::kProxySettings);
107 return proxy_settings_ui_data.editable();
110 // Only unblock if needed for debugging.
111 #if defined(NEED_DEBUG_LOG)
112 std::ostream& operator<<(
113 std::ostream& out,
114 const ProxyConfigServiceImpl::ProxyConfig::ManualProxy& proxy) {
115 out << (proxy.server.is_valid() ? proxy.server.ToURI() : "") << "\n";
116 return out;
119 std::ostream& operator<<(std::ostream& out,
120 const ProxyConfigServiceImpl::ProxyConfig& config) {
121 switch (config.mode) {
122 case ProxyConfigServiceImpl::ProxyConfig::MODE_DIRECT:
123 case ProxyConfigServiceImpl::ProxyConfig::MODE_AUTO_DETECT:
124 out << ModeToString(config.mode) << ", "
125 << ConfigStateToString(config.state) << "\n";
126 break;
127 case ProxyConfigServiceImpl::ProxyConfig::MODE_PAC_SCRIPT:
128 out << ModeToString(config.mode) << ", "
129 << ConfigStateToString(config.state)
130 << "\n PAC: " << config.automatic_proxy.pac_url << "\n";
131 break;
132 case ProxyConfigServiceImpl::ProxyConfig::MODE_SINGLE_PROXY:
133 out << ModeToString(config.mode) << ", "
134 << ConfigStateToString(config.state) << "\n " << config.single_proxy;
135 break;
136 case ProxyConfigServiceImpl::ProxyConfig::MODE_PROXY_PER_SCHEME:
137 out << ModeToString(config.mode) << ", "
138 << ConfigStateToString(config.state) << "\n"
139 << " HTTP: " << config.http_proxy
140 << " HTTPS: " << config.https_proxy
141 << " FTP: " << config.ftp_proxy
142 << " SOCKS: " << config.socks_proxy;
143 break;
144 default:
145 NOTREACHED() << "Unrecognized proxy config mode";
146 break;
148 if (config.mode == ProxyConfigServiceImpl::ProxyConfig::MODE_SINGLE_PROXY ||
149 config.mode ==
150 ProxyConfigServiceImpl::ProxyConfig::MODE_PROXY_PER_SCHEME) {
151 out << "Bypass list: ";
152 if (config.bypass_rules.rules().empty()) {
153 out << "[None]";
154 } else {
155 const net::ProxyBypassRules& bypass_rules = config.bypass_rules;
156 net::ProxyBypassRules::RuleList::const_iterator it;
157 for (it = bypass_rules.rules().begin();
158 it != bypass_rules.rules().end(); ++it) {
159 out << "\n " << (*it)->ToString();
163 return out;
166 std::string ProxyConfigToString(
167 const ProxyConfigServiceImpl::ProxyConfig& proxy_config) {
168 std::ostringstream stream;
169 stream << proxy_config;
170 return stream.str();
172 #endif // defined(NEED_DEBUG_LOG)
174 } // namespace
176 //----------- ProxyConfigServiceImpl::ProxyConfig: public methods --------------
178 ProxyConfigServiceImpl::ProxyConfig::ProxyConfig()
179 : mode(MODE_DIRECT),
180 state(ProxyPrefs::CONFIG_UNSET),
181 user_modifiable(true) {}
183 ProxyConfigServiceImpl::ProxyConfig::~ProxyConfig() {}
185 bool ProxyConfigServiceImpl::ProxyConfig::FromNetProxyConfig(
186 const net::ProxyConfig& net_config) {
187 *this = ProxyConfigServiceImpl::ProxyConfig(); // Reset to default.
188 const net::ProxyConfig::ProxyRules& rules = net_config.proxy_rules();
189 switch (rules.type) {
190 case net::ProxyConfig::ProxyRules::TYPE_NO_RULES:
191 if (!net_config.HasAutomaticSettings()) {
192 mode = ProxyConfig::MODE_DIRECT;
193 } else if (net_config.auto_detect()) {
194 mode = ProxyConfig::MODE_AUTO_DETECT;
195 } else if (net_config.has_pac_url()) {
196 mode = ProxyConfig::MODE_PAC_SCRIPT;
197 automatic_proxy.pac_url = net_config.pac_url();
198 } else {
199 return false;
201 return true;
202 case net::ProxyConfig::ProxyRules::TYPE_SINGLE_PROXY:
203 if (!rules.single_proxy.is_valid())
204 return false;
205 mode = MODE_SINGLE_PROXY;
206 single_proxy.server = rules.single_proxy;
207 bypass_rules = rules.bypass_rules;
208 return true;
209 case net::ProxyConfig::ProxyRules::TYPE_PROXY_PER_SCHEME:
210 // Make sure we have valid server for at least one of the protocols.
211 if (!rules.proxy_for_http.is_valid() &&
212 !rules.proxy_for_https.is_valid() &&
213 !rules.proxy_for_ftp.is_valid() &&
214 !rules.fallback_proxy.is_valid()) {
215 return false;
217 mode = MODE_PROXY_PER_SCHEME;
218 if (rules.proxy_for_http.is_valid())
219 http_proxy.server = rules.proxy_for_http;
220 if (rules.proxy_for_https.is_valid())
221 https_proxy.server = rules.proxy_for_https;
222 if (rules.proxy_for_ftp.is_valid())
223 ftp_proxy.server = rules.proxy_for_ftp;
224 if (rules.fallback_proxy.is_valid())
225 socks_proxy.server = rules.fallback_proxy;
226 bypass_rules = rules.bypass_rules;
227 return true;
228 default:
229 NOTREACHED() << "Unrecognized proxy config mode";
230 break;
232 return false;
235 DictionaryValue* ProxyConfigServiceImpl::ProxyConfig::ToPrefProxyConfig() {
236 switch (mode) {
237 case MODE_DIRECT: {
238 return ProxyConfigDictionary::CreateDirect();
240 case MODE_AUTO_DETECT: {
241 return ProxyConfigDictionary::CreateAutoDetect();
243 case MODE_PAC_SCRIPT: {
244 return ProxyConfigDictionary::CreatePacScript(
245 automatic_proxy.pac_url.spec(), false);
247 case MODE_SINGLE_PROXY: {
248 std::string spec;
249 if (single_proxy.server.is_valid())
250 spec = single_proxy.server.ToURI();
251 return ProxyConfigDictionary::CreateFixedServers(
252 spec, bypass_rules.ToString());
254 case MODE_PROXY_PER_SCHEME: {
255 std::string spec;
256 EncodeAndAppendProxyServer("http", http_proxy.server, &spec);
257 EncodeAndAppendProxyServer("https", https_proxy.server, &spec);
258 EncodeAndAppendProxyServer("ftp", ftp_proxy.server, &spec);
259 EncodeAndAppendProxyServer("socks", socks_proxy.server, &spec);
260 return ProxyConfigDictionary::CreateFixedServers(
261 spec, bypass_rules.ToString());
263 default:
264 break;
266 NOTREACHED() << "Unrecognized proxy config mode for preference";
267 return NULL;
270 ProxyConfigServiceImpl::ProxyConfig::ManualProxy*
271 ProxyConfigServiceImpl::ProxyConfig::MapSchemeToProxy(
272 const std::string& scheme) {
273 if (scheme == "http")
274 return &http_proxy;
275 if (scheme == "https")
276 return &https_proxy;
277 if (scheme == "ftp")
278 return &ftp_proxy;
279 if (scheme == "socks")
280 return &socks_proxy;
281 NOTREACHED() << "Invalid scheme: " << scheme;
282 return NULL;
285 bool ProxyConfigServiceImpl::ProxyConfig::DeserializeForDevice(
286 const std::string& input) {
287 em::DeviceProxySettingsProto proxy_proto;
288 if (!proxy_proto.ParseFromString(input))
289 return false;
291 const std::string& mode_string(proxy_proto.proxy_mode());
292 if (mode_string == ProxyPrefs::kDirectProxyModeName) {
293 mode = MODE_DIRECT;
294 } else if (mode_string == ProxyPrefs::kAutoDetectProxyModeName) {
295 mode = MODE_AUTO_DETECT;
296 } else if (mode_string == ProxyPrefs::kPacScriptProxyModeName) {
297 mode = MODE_PAC_SCRIPT;
298 if (proxy_proto.has_proxy_pac_url())
299 automatic_proxy.pac_url = GURL(proxy_proto.proxy_pac_url());
300 } else if (mode_string == ProxyPrefs::kFixedServersProxyModeName) {
301 net::ProxyConfig::ProxyRules rules;
302 rules.ParseFromString(proxy_proto.proxy_server());
303 switch (rules.type) {
304 case net::ProxyConfig::ProxyRules::TYPE_NO_RULES:
305 return false;
306 case net::ProxyConfig::ProxyRules::TYPE_SINGLE_PROXY:
307 if (!rules.single_proxy.is_valid())
308 return false;
309 mode = MODE_SINGLE_PROXY;
310 single_proxy.server = rules.single_proxy;
311 break;
312 case net::ProxyConfig::ProxyRules::TYPE_PROXY_PER_SCHEME:
313 // Make sure we have valid server for at least one of the protocols.
314 if (!rules.proxy_for_http.is_valid() &&
315 !rules.proxy_for_https.is_valid() &&
316 !rules.proxy_for_ftp.is_valid() &&
317 !rules.fallback_proxy.is_valid()) {
318 return false;
320 mode = MODE_PROXY_PER_SCHEME;
321 if (rules.proxy_for_http.is_valid())
322 http_proxy.server = rules.proxy_for_http;
323 if (rules.proxy_for_https.is_valid())
324 https_proxy.server = rules.proxy_for_https;
325 if (rules.proxy_for_ftp.is_valid())
326 ftp_proxy.server = rules.proxy_for_ftp;
327 if (rules.fallback_proxy.is_valid())
328 socks_proxy.server = rules.fallback_proxy;
329 break;
331 } else {
332 NOTREACHED() << "Unrecognized proxy config mode";
333 return false;
336 if (proxy_proto.has_proxy_bypass_list())
337 bypass_rules.ParseFromString(proxy_proto.proxy_bypass_list());
339 return true;
342 bool ProxyConfigServiceImpl::ProxyConfig::SerializeForNetwork(
343 std::string* output) {
344 scoped_ptr<DictionaryValue> proxy_dict_ptr(ToPrefProxyConfig());
345 if (!proxy_dict_ptr.get())
346 return false;
348 // Return empty string for direct mode for portal check to work correctly.
349 DictionaryValue *dict = proxy_dict_ptr.get();
350 ProxyConfigDictionary proxy_dict(dict);
351 ProxyPrefs::ProxyMode mode;
352 if (proxy_dict.GetMode(&mode)) {
353 if (mode == ProxyPrefs::MODE_DIRECT) {
354 output->clear();
355 return true;
358 JSONStringValueSerializer serializer(output);
359 return serializer.Serialize(*dict);
362 //----------- ProxyConfigServiceImpl::ProxyConfig: private methods -------------
364 // static
365 void ProxyConfigServiceImpl::ProxyConfig::EncodeAndAppendProxyServer(
366 const std::string& scheme,
367 const net::ProxyServer& server,
368 std::string* spec) {
369 if (!server.is_valid())
370 return;
372 if (!spec->empty())
373 *spec += ';';
375 if (!scheme.empty()) {
376 *spec += scheme;
377 *spec += "=";
379 *spec += server.ToURI();
382 //------------------- ProxyConfigServiceImpl: public methods -------------------
384 ProxyConfigServiceImpl::ProxyConfigServiceImpl(PrefService* pref_service)
385 : PrefProxyConfigTrackerImpl(pref_service),
386 active_config_state_(ProxyPrefs::CONFIG_UNSET),
387 pointer_factory_(this) {
389 // Register for notifications of UseSharedProxies user preference.
390 if (pref_service->FindPreference(prefs::kUseSharedProxies))
391 use_shared_proxies_.Init(prefs::kUseSharedProxies, pref_service, this);
393 if (CrosSettings::Get()->GetTrusted(
394 kSettingProxyEverywhere,
395 base::Bind(&ProxyConfigServiceImpl::FetchProxyPolicy,
396 pointer_factory_.GetWeakPtr()))) {
397 FetchProxyPolicy();
400 // Register for flimflam network notifications.
401 NetworkLibrary* network_lib = CrosLibrary::Get()->GetNetworkLibrary();
402 OnActiveNetworkChanged(network_lib, network_lib->active_network());
403 network_lib->AddNetworkManagerObserver(this);
406 ProxyConfigServiceImpl::~ProxyConfigServiceImpl() {
407 NetworkLibrary* netlib = CrosLibrary::Get()->GetNetworkLibrary();
408 if (netlib) {
409 netlib->RemoveNetworkManagerObserver(this);
410 netlib->RemoveObserverForAllNetworks(this);
414 void ProxyConfigServiceImpl::UISetCurrentNetwork(
415 const std::string& current_network) {
416 Network* network = CrosLibrary::Get()->GetNetworkLibrary()->FindNetworkByPath(
417 current_network);
418 if (!network) {
419 ResetUICache();
420 LOG(ERROR) << "can't find requested network " << current_network;
421 return;
423 current_ui_network_ = current_network;
424 OnUISetCurrentNetwork(network);
427 void ProxyConfigServiceImpl::UIMakeActiveNetworkCurrent() {
428 Network* network = CrosLibrary::Get()->GetNetworkLibrary()->FindNetworkByPath(
429 active_network_);
430 if (!network) {
431 ResetUICache();
432 LOG(ERROR) << "can't find requested network " << active_network_;
433 return;
435 current_ui_network_ = active_network_;
436 OnUISetCurrentNetwork(network);
439 void ProxyConfigServiceImpl::UIGetCurrentNetworkName(
440 std::string* network_name) {
441 if (!network_name)
442 return;
443 network_name->clear();
444 Network* network = CrosLibrary::Get()->GetNetworkLibrary()->FindNetworkByPath(
445 current_ui_network_);
446 if (!network) {
447 LOG(ERROR) << "can't find requested network " << current_ui_network_;
448 return;
450 if (network->name().empty() && network->type() == chromeos::TYPE_ETHERNET) {
451 *network_name =
452 l10n_util::GetStringUTF8(IDS_STATUSBAR_NETWORK_DEVICE_ETHERNET);
453 } else {
454 *network_name = network->name();
458 void ProxyConfigServiceImpl::UIGetProxyConfig(ProxyConfig* config) {
459 // Simply returns the copy last set from UI via UISetCurrentNetwork or
460 // UIMakeActiveNetworkCurrent.
461 *config = current_ui_config_;
464 bool ProxyConfigServiceImpl::UISetProxyConfigToDirect() {
465 current_ui_config_.mode = ProxyConfig::MODE_DIRECT;
466 OnUISetProxyConfig();
467 return true;
470 bool ProxyConfigServiceImpl::UISetProxyConfigToAutoDetect() {
471 current_ui_config_.mode = ProxyConfig::MODE_AUTO_DETECT;
472 OnUISetProxyConfig();
473 return true;
476 bool ProxyConfigServiceImpl::UISetProxyConfigToPACScript(const GURL& pac_url) {
477 current_ui_config_.mode = ProxyConfig::MODE_PAC_SCRIPT;
478 current_ui_config_.automatic_proxy.pac_url = pac_url;
479 OnUISetProxyConfig();
480 return true;
483 bool ProxyConfigServiceImpl::UISetProxyConfigToSingleProxy(
484 const net::ProxyServer& server) {
485 current_ui_config_.mode = ProxyConfig::MODE_SINGLE_PROXY;
486 current_ui_config_.single_proxy.server = server;
487 OnUISetProxyConfig();
488 return true;
491 bool ProxyConfigServiceImpl::UISetProxyConfigToProxyPerScheme(
492 const std::string& scheme, const net::ProxyServer& server) {
493 ProxyConfig::ManualProxy* proxy = current_ui_config_.MapSchemeToProxy(scheme);
494 if (!proxy) {
495 NOTREACHED() << "Cannot set proxy: invalid scheme [" << scheme << "]";
496 return false;
498 current_ui_config_.mode = ProxyConfig::MODE_PROXY_PER_SCHEME;
499 proxy->server = server;
500 OnUISetProxyConfig();
501 return true;
504 bool ProxyConfigServiceImpl::UISetProxyConfigBypassRules(
505 const net::ProxyBypassRules& bypass_rules) {
506 if (current_ui_config_.mode != ProxyConfig::MODE_SINGLE_PROXY &&
507 current_ui_config_.mode != ProxyConfig::MODE_PROXY_PER_SCHEME) {
508 NOTREACHED();
509 VLOG(1) << "Cannot set bypass rules for proxy mode ["
510 << current_ui_config_.mode << "]";
511 return false;
513 current_ui_config_.bypass_rules = bypass_rules;
514 OnUISetProxyConfig();
515 return true;
518 void ProxyConfigServiceImpl::AddNotificationCallback(base::Closure callback) {
520 std::vector<base::Closure>::iterator iter =
521 findIfEqual(callbacks_.begin(), callbacks_.end(), callback);
522 if (iter == callbacks_.end())
523 callbacks_.push_back(callback);
526 void ProxyConfigServiceImpl::RemoveNotificationCallback(
527 base::Closure callback) {
528 std::vector<base::Closure>::iterator iter =
529 findIfEqual(callbacks_.begin(), callbacks_.end(), callback);
530 if (iter != callbacks_.end())
531 callbacks_.erase(iter);
534 void ProxyConfigServiceImpl::OnProxyConfigChanged(
535 ProxyPrefs::ConfigState config_state,
536 const net::ProxyConfig& config) {
537 VLOG(1) << this << ": got prefs change: " << ConfigStateToString(config_state)
538 << ", mode=" << config.proxy_rules().type;
539 Network* network = NULL;
540 if (!active_network_.empty()) {
541 network = CrosLibrary::Get()->GetNetworkLibrary()->FindNetworkByPath(
542 active_network_);
543 if (!network)
544 LOG(ERROR) << "can't find requested network " << active_network_;
546 DetermineEffectiveConfig(network, true);
549 void ProxyConfigServiceImpl::OnNetworkManagerChanged(
550 NetworkLibrary* network_lib) {
551 VLOG(1) << this << " OnNetworkManagerChanged: use-shared-proxies="
552 << GetUseSharedProxies();
553 OnActiveNetworkChanged(network_lib, network_lib->active_network());
556 void ProxyConfigServiceImpl::OnNetworkChanged(NetworkLibrary* network_lib,
557 const Network* network) {
558 if (!network)
559 return;
560 VLOG(1) << this << " OnNetworkChanged: "
561 << (network->name().empty() ? network->service_path() :
562 network->name())
563 << ", use-shared-proxies=" << GetUseSharedProxies();
564 // We only care about active network.
565 if (network == network_lib->active_network())
566 OnActiveNetworkChanged(network_lib, network);
569 // static
570 void ProxyConfigServiceImpl::RegisterPrefs(PrefService* pref_service) {
571 // Use shared proxies default to off. GetUseSharedProxies will return the
572 // correct value based on pre-login and login.
573 pref_service->RegisterBooleanPref(prefs::kUseSharedProxies,
574 true,
575 PrefService::UNSYNCABLE_PREF);
578 //------------------ ProxyConfigServiceImpl: private methods -------------------
580 void ProxyConfigServiceImpl::Observe(
581 int type,
582 const content::NotificationSource& source,
583 const content::NotificationDetails& details) {
584 if (type == chrome::NOTIFICATION_PREF_CHANGED &&
585 *(content::Details<std::string>(details).ptr()) ==
586 prefs::kUseSharedProxies) {
587 if (content::Source<PrefService>(source).ptr() == prefs()) {
588 VLOG(1) << this << ": new use-shared-proxies = " << GetUseSharedProxies();
589 // Determine new proxy config which may have changed because of new
590 // use-shared-proxies. If necessary, activate it.
591 Network* network = NULL;
592 if (!active_network_.empty()) {
593 network = CrosLibrary::Get()->GetNetworkLibrary()->FindNetworkByPath(
594 active_network_);
595 if (!network)
596 LOG(WARNING) << "can't find requested network " << active_network_;
598 DetermineEffectiveConfig(network, true);
600 return;
602 PrefProxyConfigTrackerImpl::Observe(type, source, details);
605 void ProxyConfigServiceImpl::OnUISetProxyConfig() {
606 if (current_ui_network_.empty())
607 return;
608 // Update config to flimflam.
609 std::string value;
610 if (current_ui_config_.SerializeForNetwork(&value)) {
611 VLOG(1) << this << ": set proxy (mode=" << current_ui_config_.mode
612 << ") for " << current_ui_network_;
613 current_ui_config_.state = ProxyPrefs::CONFIG_SYSTEM;
614 SetProxyConfigForNetwork(current_ui_network_, value, false);
618 void ProxyConfigServiceImpl::OnActiveNetworkChanged(NetworkLibrary* network_lib,
619 const Network* active_network) {
620 std::string new_network;
621 if (active_network)
622 new_network = active_network->service_path();
624 if (active_network_ == new_network) { // Same active network.
625 VLOG(1) << this << ": same active network: "
626 << (new_network.empty() ? "empty" :
627 (active_network->name().empty() ?
628 new_network : active_network->name()));
629 // Even though network is the same, its proxy config (e.g. if private
630 // version of network replaces the shared version after login), or
631 // use-shared-proxies setting (e.g. after login) may have changed,
632 // so re-determine effective proxy config, and activate if different.
633 if (active_network) {
634 VLOG(1) << this << ": profile=" << active_network->profile_type()
635 << "," << active_network->profile_path()
636 << ", proxy=" << active_network->proxy_config();
637 DetermineEffectiveConfig(active_network, true);
639 return;
642 // If there was a previous active network, remove it as observer.
643 if (!active_network_.empty())
644 network_lib->RemoveNetworkObserver(active_network_, this);
646 active_network_ = new_network;
648 if (active_network_.empty()) {
649 VLOG(1) << this << ": new active network: empty";
650 DetermineEffectiveConfig(active_network, true);
651 return;
654 VLOG(1) << this << ": new active network: path="
655 << active_network->service_path()
656 << ", name=" << active_network->name()
657 << ", profile=" << active_network->profile_type()
658 << "," << active_network->profile_path()
659 << ", proxy=" << active_network->proxy_config();
661 // Register observer for new network.
662 network_lib->AddNetworkObserver(active_network_, this);
664 // If necessary, migrate config to flimflam.
665 if (active_network->proxy_config().empty() && !device_config_.empty()) {
666 VLOG(1) << this << ": try migrating device config to " << active_network_;
667 SetProxyConfigForNetwork(active_network_, device_config_, true);
668 } else {
669 // Otherwise, determine and activate possibly new effective proxy config.
670 DetermineEffectiveConfig(active_network, true);
674 void ProxyConfigServiceImpl::SetProxyConfigForNetwork(
675 const std::string& network_path, const std::string& value,
676 bool only_set_if_empty) {
677 Network* network = CrosLibrary::Get()->GetNetworkLibrary()->FindNetworkByPath(
678 network_path);
679 if (!network) {
680 NOTREACHED() << "can't find requested network " << network_path;
681 return;
683 if (!only_set_if_empty || network->proxy_config().empty()) {
684 network->SetProxyConfig(value);
685 VLOG(1) << this << ": set proxy for " << (network->name().empty() ?
686 network_path : network->name())
687 << ", value=" << value;
688 if (network_path == active_network_)
689 DetermineEffectiveConfig(network, true);
693 bool ProxyConfigServiceImpl::GetUseSharedProxies() {
694 const PrefService::Preference* use_shared_proxies_pref =
695 prefs()->FindPreference(prefs::kUseSharedProxies);
696 if (!use_shared_proxies_pref)
697 return !UserManager::Get()->user_is_logged_in();
698 return use_shared_proxies_.GetValue();
701 void ProxyConfigServiceImpl::DetermineEffectiveConfig(const Network* network,
702 bool activate) {
703 // Get prefs proxy config if available.
704 net::ProxyConfig pref_config;
705 ProxyPrefs::ConfigState pref_state = GetProxyConfig(&pref_config);
707 // Get network proxy config if available.
708 net::ProxyConfig network_config;
709 net::ProxyConfigService::ConfigAvailability network_availability =
710 net::ProxyConfigService::CONFIG_UNSET;
711 bool ignore_proxy = activate;
712 if (network) {
713 // If we're activating proxy, ignore proxy if necessary;
714 // otherwise, for ui, get actual proxy to show user.
715 ignore_proxy = activate ? IgnoreProxy(network) : false;
716 // If network is shared but use-shared-proxies is off, use direct mode.
717 if (ignore_proxy) {
718 VLOG(1) << this << ": shared network && !use-shared-proxies, use direct";
719 network_availability = net::ProxyConfigService::CONFIG_VALID;
720 } else if (!network->proxy_config().empty()) {
721 // Network is private or shared with user using shared proxies.
722 JSONStringValueSerializer serializer(network->proxy_config());
723 scoped_ptr<Value> value(serializer.Deserialize(NULL, NULL));
724 if (value.get() && value->GetType() == Value::TYPE_DICTIONARY) {
725 DictionaryValue* dict = static_cast<DictionaryValue*>(value.get());
726 ProxyConfigDictionary proxy_dict(dict);
727 if (PrefConfigToNetConfig(proxy_dict, &network_config)) {
728 VLOG(1) << this << ": using network proxy: "
729 << network->proxy_config();
730 network_availability = net::ProxyConfigService::CONFIG_VALID;
736 // Determine effective proxy config, either from prefs or network.
737 ProxyPrefs::ConfigState effective_config_state;
738 net::ProxyConfig effective_config;
739 GetEffectiveProxyConfig(pref_state, pref_config,
740 network_availability, network_config, ignore_proxy,
741 &effective_config_state, &effective_config);
743 // Determine if we should activate effective proxy and which proxy config to
744 // store it.
745 if (activate) { // Activate effective proxy and store into |active_config_|.
746 // If last update didn't complete, we definitely update now.
747 bool update_now = update_pending();
748 if (!update_now) { // Otherwise, only update now if there're changes.
749 update_now = active_config_state_ != effective_config_state ||
750 (active_config_state_ != ProxyPrefs::CONFIG_UNSET &&
751 !active_config_.Equals(effective_config));
753 if (update_now) { // Activate and store new effective config.
754 active_config_state_ = effective_config_state;
755 if (active_config_state_ != ProxyPrefs::CONFIG_UNSET)
756 active_config_ = effective_config;
757 // If effective config is from system (i.e. network), it's considered a
758 // special kind of prefs that ranks below policy/extension but above
759 // others, so bump it up to CONFIG_OTHER_PRECEDE to force its precedence
760 // when PrefProxyConfigTrackerImpl pushes it to ChromeProxyConfigService.
761 if (effective_config_state == ProxyPrefs::CONFIG_SYSTEM)
762 effective_config_state = ProxyPrefs::CONFIG_OTHER_PRECEDE;
763 // If config is manual, add rule to bypass local host.
764 if (effective_config.proxy_rules().type !=
765 net::ProxyConfig::ProxyRules::TYPE_NO_RULES)
766 effective_config.proxy_rules().bypass_rules.AddRuleToBypassLocal();
767 PrefProxyConfigTrackerImpl::OnProxyConfigChanged(effective_config_state,
768 effective_config);
769 if (VLOG_IS_ON(1) && !update_pending()) { // Update was successful.
770 scoped_ptr<DictionaryValue> config_dict(static_cast<DictionaryValue*>(
771 effective_config.ToValue()));
772 std::string config_value;
773 JSONStringValueSerializer serializer(&config_value);
774 serializer.Serialize(*config_dict.get());
775 VLOG(1) << this << ": Proxy changed: "
776 << ConfigStateToString(active_config_state_)
777 << ", " << config_value;
780 } else { // For UI, store effective proxy into |current_ui_config_|.
781 current_ui_config_.FromNetProxyConfig(effective_config);
782 current_ui_config_.state = effective_config_state;
783 if (PrefPrecedes(effective_config_state)) {
784 current_ui_config_.user_modifiable = false;
785 } else if (!IsNetworkProxySettingsEditable(network)) {
786 // TODO(xiyuan): Figure out the right way to set config state for managed
787 // network.
788 current_ui_config_.state = ProxyPrefs::CONFIG_POLICY;
789 current_ui_config_.user_modifiable = false;
790 } else {
791 current_ui_config_.user_modifiable = !network || !IgnoreProxy(network);
796 void ProxyConfigServiceImpl::OnUISetCurrentNetwork(const Network* network) {
797 DetermineEffectiveConfig(network, false);
798 VLOG(1) << this << ": current ui network: "
799 << (network->name().empty() ?
800 current_ui_network_ : network->name())
801 << ", " << ModeToString(current_ui_config_.mode)
802 << ", " << ConfigStateToString(current_ui_config_.state)
803 << ", modifiable:" << current_ui_config_.user_modifiable;
804 // Notify whoever is interested in this change.
805 std::vector<base::Closure>::iterator iter = callbacks_.begin();
806 while (iter != callbacks_.end()) {
807 if (iter->is_null()) {
808 iter = callbacks_.erase(iter);
809 } else {
810 iter->Run();
811 ++iter;
816 void ProxyConfigServiceImpl::ResetUICache() {
817 current_ui_network_.clear();
818 current_ui_config_ = ProxyConfig();
821 void ProxyConfigServiceImpl::FetchProxyPolicy() {
822 std::string policy_value;
823 if (!CrosSettings::Get()->GetString(kSettingProxyEverywhere,
824 &policy_value)) {
825 LOG(WARNING) << this << ": Error retrieving proxy setting from device";
826 device_config_.clear();
827 return;
830 VLOG(1) << this << ": Retrieved proxy setting from device, value=["
831 << policy_value << "]";
832 ProxyConfig device_config;
833 if (!device_config.DeserializeForDevice(policy_value) ||
834 !device_config.SerializeForNetwork(&device_config_)) {
835 LOG(WARNING) << "Can't deserialize device setting or serialize for network";
836 device_config_.clear();
837 return;
839 if (!active_network_.empty()) {
840 VLOG(1) << this << ": try migrating device config to " << active_network_;
841 SetProxyConfigForNetwork(active_network_, device_config_, true);
845 } // namespace chromeos