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"
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
;
35 // Shoud we try to push this to base?
36 // Helper comparator functor for the find_if call in |findIfEqual|
38 class EqualsComparator
{
40 explicit EqualsComparator(const T
& key
) : key_(key
) { }
41 bool operator() (const T
& element
) {
42 return element
.Equals(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
,
54 return std::find_if(first
, last
, EqualsComparator
<T
>(key
));
57 const char* ModeToString(ProxyConfigServiceImpl::ProxyConfig::Mode mode
) {
59 case ProxyConfigServiceImpl::ProxyConfig::MODE_DIRECT
:
61 case ProxyConfigServiceImpl::ProxyConfig::MODE_AUTO_DETECT
:
63 case ProxyConfigServiceImpl::ProxyConfig::MODE_PAC_SCRIPT
:
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";
74 const char* ConfigStateToString(ProxyPrefs::ConfigState 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";
93 // Returns true if proxy settings from |network| is editable.
94 bool IsNetworkProxySettingsEditable(const Network
* 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(
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<<(
114 const ProxyConfigServiceImpl::ProxyConfig::ManualProxy
& proxy
) {
115 out
<< (proxy
.server
.is_valid() ? proxy
.server
.ToURI() : "") << "\n";
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";
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";
132 case ProxyConfigServiceImpl::ProxyConfig::MODE_SINGLE_PROXY
:
133 out
<< ModeToString(config
.mode
) << ", "
134 << ConfigStateToString(config
.state
) << "\n " << config
.single_proxy
;
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
;
145 NOTREACHED() << "Unrecognized proxy config mode";
148 if (config
.mode
== ProxyConfigServiceImpl::ProxyConfig::MODE_SINGLE_PROXY
||
150 ProxyConfigServiceImpl::ProxyConfig::MODE_PROXY_PER_SCHEME
) {
151 out
<< "Bypass list: ";
152 if (config
.bypass_rules
.rules().empty()) {
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();
166 std::string
ProxyConfigToString(
167 const ProxyConfigServiceImpl::ProxyConfig
& proxy_config
) {
168 std::ostringstream stream
;
169 stream
<< proxy_config
;
172 #endif // defined(NEED_DEBUG_LOG)
176 //----------- ProxyConfigServiceImpl::ProxyConfig: public methods --------------
178 ProxyConfigServiceImpl::ProxyConfig::ProxyConfig()
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();
202 case net::ProxyConfig::ProxyRules::TYPE_SINGLE_PROXY
:
203 if (!rules
.single_proxy
.is_valid())
205 mode
= MODE_SINGLE_PROXY
;
206 single_proxy
.server
= rules
.single_proxy
;
207 bypass_rules
= rules
.bypass_rules
;
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()) {
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
;
229 NOTREACHED() << "Unrecognized proxy config mode";
235 DictionaryValue
* ProxyConfigServiceImpl::ProxyConfig::ToPrefProxyConfig() {
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
: {
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
: {
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());
266 NOTREACHED() << "Unrecognized proxy config mode for preference";
270 ProxyConfigServiceImpl::ProxyConfig::ManualProxy
*
271 ProxyConfigServiceImpl::ProxyConfig::MapSchemeToProxy(
272 const std::string
& scheme
) {
273 if (scheme
== "http")
275 if (scheme
== "https")
279 if (scheme
== "socks")
281 NOTREACHED() << "Invalid scheme: " << scheme
;
285 bool ProxyConfigServiceImpl::ProxyConfig::DeserializeForDevice(
286 const std::string
& input
) {
287 em::DeviceProxySettingsProto proxy_proto
;
288 if (!proxy_proto
.ParseFromString(input
))
291 const std::string
& mode_string(proxy_proto
.proxy_mode());
292 if (mode_string
== ProxyPrefs::kDirectProxyModeName
) {
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
:
306 case net::ProxyConfig::ProxyRules::TYPE_SINGLE_PROXY
:
307 if (!rules
.single_proxy
.is_valid())
309 mode
= MODE_SINGLE_PROXY
;
310 single_proxy
.server
= rules
.single_proxy
;
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()) {
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
;
332 NOTREACHED() << "Unrecognized proxy config mode";
336 if (proxy_proto
.has_proxy_bypass_list())
337 bypass_rules
.ParseFromString(proxy_proto
.proxy_bypass_list());
342 bool ProxyConfigServiceImpl::ProxyConfig::SerializeForNetwork(
343 std::string
* output
) {
344 scoped_ptr
<DictionaryValue
> proxy_dict_ptr(ToPrefProxyConfig());
345 if (!proxy_dict_ptr
.get())
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
) {
358 JSONStringValueSerializer
serializer(output
);
359 return serializer
.Serialize(*dict
);
362 //----------- ProxyConfigServiceImpl::ProxyConfig: private methods -------------
365 void ProxyConfigServiceImpl::ProxyConfig::EncodeAndAppendProxyServer(
366 const std::string
& scheme
,
367 const net::ProxyServer
& server
,
369 if (!server
.is_valid())
375 if (!scheme
.empty()) {
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()))) {
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();
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(
420 LOG(ERROR
) << "can't find requested network " << current_network
;
423 current_ui_network_
= current_network
;
424 OnUISetCurrentNetwork(network
);
427 void ProxyConfigServiceImpl::UIMakeActiveNetworkCurrent() {
428 Network
* network
= CrosLibrary::Get()->GetNetworkLibrary()->FindNetworkByPath(
432 LOG(ERROR
) << "can't find requested network " << active_network_
;
435 current_ui_network_
= active_network_
;
436 OnUISetCurrentNetwork(network
);
439 void ProxyConfigServiceImpl::UIGetCurrentNetworkName(
440 std::string
* network_name
) {
443 network_name
->clear();
444 Network
* network
= CrosLibrary::Get()->GetNetworkLibrary()->FindNetworkByPath(
445 current_ui_network_
);
447 LOG(ERROR
) << "can't find requested network " << current_ui_network_
;
450 if (network
->name().empty() && network
->type() == chromeos::TYPE_ETHERNET
) {
452 l10n_util::GetStringUTF8(IDS_STATUSBAR_NETWORK_DEVICE_ETHERNET
);
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();
470 bool ProxyConfigServiceImpl::UISetProxyConfigToAutoDetect() {
471 current_ui_config_
.mode
= ProxyConfig::MODE_AUTO_DETECT
;
472 OnUISetProxyConfig();
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();
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();
491 bool ProxyConfigServiceImpl::UISetProxyConfigToProxyPerScheme(
492 const std::string
& scheme
, const net::ProxyServer
& server
) {
493 ProxyConfig::ManualProxy
* proxy
= current_ui_config_
.MapSchemeToProxy(scheme
);
495 NOTREACHED() << "Cannot set proxy: invalid scheme [" << scheme
<< "]";
498 current_ui_config_
.mode
= ProxyConfig::MODE_PROXY_PER_SCHEME
;
499 proxy
->server
= server
;
500 OnUISetProxyConfig();
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
) {
509 VLOG(1) << "Cannot set bypass rules for proxy mode ["
510 << current_ui_config_
.mode
<< "]";
513 current_ui_config_
.bypass_rules
= bypass_rules
;
514 OnUISetProxyConfig();
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(
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
) {
560 VLOG(1) << this << " OnNetworkChanged: "
561 << (network
->name().empty() ? network
->service_path() :
563 << ", use-shared-proxies=" << GetUseSharedProxies();
564 // We only care about active network.
565 if (network
== network_lib
->active_network())
566 OnActiveNetworkChanged(network_lib
, network
);
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
,
575 PrefService::UNSYNCABLE_PREF
);
578 //------------------ ProxyConfigServiceImpl: private methods -------------------
580 void ProxyConfigServiceImpl::Observe(
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(
596 LOG(WARNING
) << "can't find requested network " << active_network_
;
598 DetermineEffectiveConfig(network
, true);
602 PrefProxyConfigTrackerImpl::Observe(type
, source
, details
);
605 void ProxyConfigServiceImpl::OnUISetProxyConfig() {
606 if (current_ui_network_
.empty())
608 // Update config to flimflam.
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
;
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);
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);
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);
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(
680 NOTREACHED() << "can't find requested network " << network_path
;
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
,
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
;
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.
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
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
,
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
788 current_ui_config_
.state
= ProxyPrefs::CONFIG_POLICY
;
789 current_ui_config_
.user_modifiable
= false;
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
);
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
,
825 LOG(WARNING
) << this << ": Error retrieving proxy setting from device";
826 device_config_
.clear();
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();
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