Return backed up TemplateURL on default search change
[chromium-blink-merge.git] / chrome / browser / chromeos / proxy_config_service_impl.cc
blob1f6f438e7668868f3824e79206e08f067fe72963
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
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_settings.h"
15 #include "chrome/browser/chromeos/cros_settings_names.h"
16 #include "chrome/browser/chromeos/login/user_manager.h"
17 #include "chrome/browser/policy/proto/chrome_device_policy.pb.h"
18 #include "chrome/browser/prefs/pref_service.h"
19 #include "chrome/browser/prefs/proxy_config_dictionary.h"
20 #include "chrome/browser/prefs/proxy_prefs.h"
21 #include "chrome/browser/profiles/profile_manager.h"
22 #include "chrome/common/chrome_notification_types.h"
23 #include "chrome/common/pref_names.h"
24 #include "content/public/browser/notification_service.h"
25 #include "grit/generated_resources.h"
26 #include "ui/base/l10n/l10n_util.h"
28 namespace em = enterprise_management;
30 namespace chromeos {
32 namespace {
34 // Shoud we try to push this to base?
35 // Helper comparator functor for the find_if call in |findIfEqual|
36 template <class T>
37 class EqualsComparator{
38 public:
39 explicit EqualsComparator(const T& key) : key_(key) { }
40 bool operator() (const T& element) {
41 return element.Equals(key_);
43 private:
44 const T& key_;
47 // Tiny STL helper function to allow using the find_if syntax on objects that
48 // doesn't use the operator== but implement the Equals function which is the
49 // quasi standard with the coding style we have.
50 template<class InputIterator, class T>
51 InputIterator findIfEqual(InputIterator first, InputIterator last,
52 const T& key) {
53 return std::find_if(first, last, EqualsComparator<T>(key));
56 const char* ModeToString(ProxyConfigServiceImpl::ProxyConfig::Mode mode) {
57 switch (mode) {
58 case ProxyConfigServiceImpl::ProxyConfig::MODE_DIRECT:
59 return "direct";
60 case ProxyConfigServiceImpl::ProxyConfig::MODE_AUTO_DETECT:
61 return "auto-detect";
62 case ProxyConfigServiceImpl::ProxyConfig::MODE_PAC_SCRIPT:
63 return "pacurl";
64 case ProxyConfigServiceImpl::ProxyConfig::MODE_SINGLE_PROXY:
65 return "single-proxy";
66 case ProxyConfigServiceImpl::ProxyConfig::MODE_PROXY_PER_SCHEME:
67 return "proxy-per-scheme";
69 NOTREACHED() << "Unrecognized mode type";
70 return "";
73 const char* ConfigStateToString(ProxyPrefs::ConfigState state) {
74 switch (state) {
75 case ProxyPrefs::CONFIG_POLICY:
76 return "config_policy";
77 case ProxyPrefs::CONFIG_EXTENSION:
78 return "config_extension";
79 case ProxyPrefs::CONFIG_OTHER_PRECEDE:
80 return "config_other_precede";
81 case ProxyPrefs::CONFIG_SYSTEM:
82 return "config_network"; // For ChromeOS, system is network.
83 case ProxyPrefs::CONFIG_FALLBACK:
84 return "config_recommended"; // Fallback is recommended.
85 case ProxyPrefs::CONFIG_UNSET:
86 return "config_unset";
88 NOTREACHED() << "Unrecognized config state type";
89 return "";
92 // Only unblock if needed for debugging.
93 #if defined(NEED_DEBUG_LOG)
94 std::ostream& operator<<(
95 std::ostream& out,
96 const ProxyConfigServiceImpl::ProxyConfig::ManualProxy& proxy) {
97 out << (proxy.server.is_valid() ? proxy.server.ToURI() : "") << "\n";
98 return out;
101 std::ostream& operator<<(std::ostream& out,
102 const ProxyConfigServiceImpl::ProxyConfig& config) {
103 switch (config.mode) {
104 case ProxyConfigServiceImpl::ProxyConfig::MODE_DIRECT:
105 case ProxyConfigServiceImpl::ProxyConfig::MODE_AUTO_DETECT:
106 out << ModeToString(config.mode) << ", "
107 << ConfigStateToString(config.state) << "\n";
108 break;
109 case ProxyConfigServiceImpl::ProxyConfig::MODE_PAC_SCRIPT:
110 out << ModeToString(config.mode) << ", "
111 << ConfigStateToString(config.state)
112 << "\n PAC: " << config.automatic_proxy.pac_url << "\n";
113 break;
114 case ProxyConfigServiceImpl::ProxyConfig::MODE_SINGLE_PROXY:
115 out << ModeToString(config.mode) << ", "
116 << ConfigStateToString(config.state) << "\n " << config.single_proxy;
117 break;
118 case ProxyConfigServiceImpl::ProxyConfig::MODE_PROXY_PER_SCHEME:
119 out << ModeToString(config.mode) << ", "
120 << ConfigStateToString(config.state) << "\n"
121 << " HTTP: " << config.http_proxy
122 << " HTTPS: " << config.https_proxy
123 << " FTP: " << config.ftp_proxy
124 << " SOCKS: " << config.socks_proxy;
125 break;
126 default:
127 NOTREACHED() << "Unrecognized proxy config mode";
128 break;
130 if (config.mode == ProxyConfigServiceImpl::ProxyConfig::MODE_SINGLE_PROXY ||
131 config.mode ==
132 ProxyConfigServiceImpl::ProxyConfig::MODE_PROXY_PER_SCHEME) {
133 out << "Bypass list: ";
134 if (config.bypass_rules.rules().empty()) {
135 out << "[None]";
136 } else {
137 const net::ProxyBypassRules& bypass_rules = config.bypass_rules;
138 net::ProxyBypassRules::RuleList::const_iterator it;
139 for (it = bypass_rules.rules().begin();
140 it != bypass_rules.rules().end(); ++it) {
141 out << "\n " << (*it)->ToString();
145 return out;
148 std::string ProxyConfigToString(
149 const ProxyConfigServiceImpl::ProxyConfig& proxy_config) {
150 std::ostringstream stream;
151 stream << proxy_config;
152 return stream.str();
154 #endif // defined(NEED_DEBUG_LOG)
156 } // namespace
158 //----------- ProxyConfigServiceImpl::ProxyConfig: public methods --------------
160 ProxyConfigServiceImpl::ProxyConfig::ProxyConfig()
161 : mode(MODE_DIRECT),
162 state(ProxyPrefs::CONFIG_UNSET),
163 user_modifiable(true) {}
165 ProxyConfigServiceImpl::ProxyConfig::~ProxyConfig() {}
167 bool ProxyConfigServiceImpl::ProxyConfig::FromNetProxyConfig(
168 const net::ProxyConfig& net_config) {
169 *this = ProxyConfigServiceImpl::ProxyConfig(); // Reset to default.
170 const net::ProxyConfig::ProxyRules& rules = net_config.proxy_rules();
171 switch (rules.type) {
172 case net::ProxyConfig::ProxyRules::TYPE_NO_RULES:
173 if (!net_config.HasAutomaticSettings()) {
174 mode = ProxyConfig::MODE_DIRECT;
175 } else if (net_config.auto_detect()) {
176 mode = ProxyConfig::MODE_AUTO_DETECT;
177 } else if (net_config.has_pac_url()) {
178 mode = ProxyConfig::MODE_PAC_SCRIPT;
179 automatic_proxy.pac_url = net_config.pac_url();
180 } else {
181 return false;
183 return true;
184 case net::ProxyConfig::ProxyRules::TYPE_SINGLE_PROXY:
185 if (!rules.single_proxy.is_valid())
186 return false;
187 mode = MODE_SINGLE_PROXY;
188 single_proxy.server = rules.single_proxy;
189 bypass_rules = rules.bypass_rules;
190 return true;
191 case net::ProxyConfig::ProxyRules::TYPE_PROXY_PER_SCHEME:
192 // Make sure we have valid server for at least one of the protocols.
193 if (!rules.proxy_for_http.is_valid() &&
194 !rules.proxy_for_https.is_valid() &&
195 !rules.proxy_for_ftp.is_valid() &&
196 !rules.fallback_proxy.is_valid()) {
197 return false;
199 mode = MODE_PROXY_PER_SCHEME;
200 if (rules.proxy_for_http.is_valid())
201 http_proxy.server = rules.proxy_for_http;
202 if (rules.proxy_for_https.is_valid())
203 https_proxy.server = rules.proxy_for_https;
204 if (rules.proxy_for_ftp.is_valid())
205 ftp_proxy.server = rules.proxy_for_ftp;
206 if (rules.fallback_proxy.is_valid())
207 socks_proxy.server = rules.fallback_proxy;
208 bypass_rules = rules.bypass_rules;
209 return true;
210 default:
211 NOTREACHED() << "Unrecognized proxy config mode";
212 break;
214 return false;
217 DictionaryValue* ProxyConfigServiceImpl::ProxyConfig::ToPrefProxyConfig() {
218 switch (mode) {
219 case MODE_DIRECT: {
220 return ProxyConfigDictionary::CreateDirect();
222 case MODE_AUTO_DETECT: {
223 return ProxyConfigDictionary::CreateAutoDetect();
225 case MODE_PAC_SCRIPT: {
226 return ProxyConfigDictionary::CreatePacScript(
227 automatic_proxy.pac_url.spec(), false);
229 case MODE_SINGLE_PROXY: {
230 std::string spec;
231 if (single_proxy.server.is_valid())
232 spec = single_proxy.server.ToURI();
233 return ProxyConfigDictionary::CreateFixedServers(
234 spec, bypass_rules.ToString());
236 case MODE_PROXY_PER_SCHEME: {
237 std::string spec;
238 EncodeAndAppendProxyServer("http", http_proxy.server, &spec);
239 EncodeAndAppendProxyServer("https", https_proxy.server, &spec);
240 EncodeAndAppendProxyServer("ftp", ftp_proxy.server, &spec);
241 EncodeAndAppendProxyServer("socks", socks_proxy.server, &spec);
242 return ProxyConfigDictionary::CreateFixedServers(
243 spec, bypass_rules.ToString());
245 default:
246 break;
248 NOTREACHED() << "Unrecognized proxy config mode for preference";
249 return NULL;
252 ProxyConfigServiceImpl::ProxyConfig::ManualProxy*
253 ProxyConfigServiceImpl::ProxyConfig::MapSchemeToProxy(
254 const std::string& scheme) {
255 if (scheme == "http")
256 return &http_proxy;
257 if (scheme == "https")
258 return &https_proxy;
259 if (scheme == "ftp")
260 return &ftp_proxy;
261 if (scheme == "socks")
262 return &socks_proxy;
263 NOTREACHED() << "Invalid scheme: " << scheme;
264 return NULL;
267 bool ProxyConfigServiceImpl::ProxyConfig::DeserializeForDevice(
268 const std::string& input) {
269 em::DeviceProxySettingsProto proxy_proto;
270 if (!proxy_proto.ParseFromString(input))
271 return false;
273 const std::string& mode_string(proxy_proto.proxy_mode());
274 if (mode_string == ProxyPrefs::kDirectProxyModeName) {
275 mode = MODE_DIRECT;
276 } else if (mode_string == ProxyPrefs::kAutoDetectProxyModeName) {
277 mode = MODE_AUTO_DETECT;
278 } else if (mode_string == ProxyPrefs::kPacScriptProxyModeName) {
279 mode = MODE_PAC_SCRIPT;
280 if (proxy_proto.has_proxy_pac_url())
281 automatic_proxy.pac_url = GURL(proxy_proto.proxy_pac_url());
282 } else if (mode_string == ProxyPrefs::kFixedServersProxyModeName) {
283 net::ProxyConfig::ProxyRules rules;
284 rules.ParseFromString(proxy_proto.proxy_server());
285 switch (rules.type) {
286 case net::ProxyConfig::ProxyRules::TYPE_NO_RULES:
287 return false;
288 case net::ProxyConfig::ProxyRules::TYPE_SINGLE_PROXY:
289 if (!rules.single_proxy.is_valid())
290 return false;
291 mode = MODE_SINGLE_PROXY;
292 single_proxy.server = rules.single_proxy;
293 break;
294 case net::ProxyConfig::ProxyRules::TYPE_PROXY_PER_SCHEME:
295 // Make sure we have valid server for at least one of the protocols.
296 if (!rules.proxy_for_http.is_valid() &&
297 !rules.proxy_for_https.is_valid() &&
298 !rules.proxy_for_ftp.is_valid() &&
299 !rules.fallback_proxy.is_valid()) {
300 return false;
302 mode = MODE_PROXY_PER_SCHEME;
303 if (rules.proxy_for_http.is_valid())
304 http_proxy.server = rules.proxy_for_http;
305 if (rules.proxy_for_https.is_valid())
306 https_proxy.server = rules.proxy_for_https;
307 if (rules.proxy_for_ftp.is_valid())
308 ftp_proxy.server = rules.proxy_for_ftp;
309 if (rules.fallback_proxy.is_valid())
310 socks_proxy.server = rules.fallback_proxy;
311 break;
313 } else {
314 NOTREACHED() << "Unrecognized proxy config mode";
315 return false;
318 if (proxy_proto.has_proxy_bypass_list())
319 bypass_rules.ParseFromString(proxy_proto.proxy_bypass_list());
321 return true;
324 bool ProxyConfigServiceImpl::ProxyConfig::SerializeForNetwork(
325 std::string* output) {
326 scoped_ptr<DictionaryValue> proxy_dict(ToPrefProxyConfig());
327 if (!proxy_dict.get())
328 return false;
329 JSONStringValueSerializer serializer(output);
330 return serializer.Serialize(*proxy_dict.get());
333 //----------- ProxyConfigServiceImpl::ProxyConfig: private methods -------------
335 // static
336 void ProxyConfigServiceImpl::ProxyConfig::EncodeAndAppendProxyServer(
337 const std::string& scheme,
338 const net::ProxyServer& server,
339 std::string* spec) {
340 if (!server.is_valid())
341 return;
343 if (!spec->empty())
344 *spec += ';';
346 if (!scheme.empty()) {
347 *spec += scheme;
348 *spec += "=";
350 *spec += server.ToURI();
353 //------------------- ProxyConfigServiceImpl: public methods -------------------
355 ProxyConfigServiceImpl::ProxyConfigServiceImpl(PrefService* pref_service)
356 : PrefProxyConfigTrackerImpl(pref_service),
357 active_config_state_(ProxyPrefs::CONFIG_UNSET),
358 pointer_factory_(this) {
360 // Register for notifications of UseSharedProxies user preference.
361 if (pref_service->FindPreference(prefs::kUseSharedProxies))
362 use_shared_proxies_.Init(prefs::kUseSharedProxies, pref_service, this);
364 if (CrosSettings::Get()->GetTrusted(
365 kSettingProxyEverywhere,
366 base::Bind(&ProxyConfigServiceImpl::FetchProxyPolicy,
367 pointer_factory_.GetWeakPtr()))) {
368 FetchProxyPolicy();
371 // Register for flimflam network notifications.
372 NetworkLibrary* network_lib = CrosLibrary::Get()->GetNetworkLibrary();
373 OnActiveNetworkChanged(network_lib, network_lib->active_network());
374 network_lib->AddNetworkManagerObserver(this);
377 ProxyConfigServiceImpl::~ProxyConfigServiceImpl() {
378 NetworkLibrary* netlib = CrosLibrary::Get()->GetNetworkLibrary();
379 if (netlib) {
380 netlib->RemoveNetworkManagerObserver(this);
381 netlib->RemoveObserverForAllNetworks(this);
385 void ProxyConfigServiceImpl::UISetCurrentNetwork(
386 const std::string& current_network) {
387 Network* network = CrosLibrary::Get()->GetNetworkLibrary()->FindNetworkByPath(
388 current_network);
389 if (!network) {
390 ResetUICache();
391 LOG(ERROR) << "can't find requested network " << current_network;
392 return;
394 current_ui_network_ = current_network;
395 OnUISetCurrentNetwork(network);
398 void ProxyConfigServiceImpl::UIMakeActiveNetworkCurrent() {
399 Network* network = CrosLibrary::Get()->GetNetworkLibrary()->FindNetworkByPath(
400 active_network_);
401 if (!network) {
402 ResetUICache();
403 LOG(ERROR) << "can't find requested network " << active_network_;
404 return;
406 current_ui_network_ = active_network_;
407 OnUISetCurrentNetwork(network);
410 void ProxyConfigServiceImpl::UIGetCurrentNetworkName(
411 std::string* network_name) {
412 if (!network_name)
413 return;
414 network_name->clear();
415 Network* network = CrosLibrary::Get()->GetNetworkLibrary()->FindNetworkByPath(
416 current_ui_network_);
417 if (!network) {
418 LOG(ERROR) << "can't find requested network " << current_ui_network_;
419 return;
421 if (network->name().empty() && network->type() == chromeos::TYPE_ETHERNET) {
422 *network_name =
423 l10n_util::GetStringUTF8(IDS_STATUSBAR_NETWORK_DEVICE_ETHERNET);
424 } else {
425 *network_name = network->name();
429 void ProxyConfigServiceImpl::UIGetProxyConfig(ProxyConfig* config) {
430 // Simply returns the copy last set from UI via UISetCurrentNetwork or
431 // UIMakeActiveNetworkCurrent.
432 *config = current_ui_config_;
435 bool ProxyConfigServiceImpl::UISetProxyConfigToDirect() {
436 current_ui_config_.mode = ProxyConfig::MODE_DIRECT;
437 OnUISetProxyConfig();
438 return true;
441 bool ProxyConfigServiceImpl::UISetProxyConfigToAutoDetect() {
442 current_ui_config_.mode = ProxyConfig::MODE_AUTO_DETECT;
443 OnUISetProxyConfig();
444 return true;
447 bool ProxyConfigServiceImpl::UISetProxyConfigToPACScript(const GURL& pac_url) {
448 current_ui_config_.mode = ProxyConfig::MODE_PAC_SCRIPT;
449 current_ui_config_.automatic_proxy.pac_url = pac_url;
450 OnUISetProxyConfig();
451 return true;
454 bool ProxyConfigServiceImpl::UISetProxyConfigToSingleProxy(
455 const net::ProxyServer& server) {
456 current_ui_config_.mode = ProxyConfig::MODE_SINGLE_PROXY;
457 current_ui_config_.single_proxy.server = server;
458 OnUISetProxyConfig();
459 return true;
462 bool ProxyConfigServiceImpl::UISetProxyConfigToProxyPerScheme(
463 const std::string& scheme, const net::ProxyServer& server) {
464 ProxyConfig::ManualProxy* proxy = current_ui_config_.MapSchemeToProxy(scheme);
465 if (!proxy) {
466 NOTREACHED() << "Cannot set proxy: invalid scheme [" << scheme << "]";
467 return false;
469 current_ui_config_.mode = ProxyConfig::MODE_PROXY_PER_SCHEME;
470 proxy->server = server;
471 OnUISetProxyConfig();
472 return true;
475 bool ProxyConfigServiceImpl::UISetProxyConfigBypassRules(
476 const net::ProxyBypassRules& bypass_rules) {
477 if (current_ui_config_.mode != ProxyConfig::MODE_SINGLE_PROXY &&
478 current_ui_config_.mode != ProxyConfig::MODE_PROXY_PER_SCHEME) {
479 NOTREACHED();
480 VLOG(1) << "Cannot set bypass rules for proxy mode ["
481 << current_ui_config_.mode << "]";
482 return false;
484 current_ui_config_.bypass_rules = bypass_rules;
485 OnUISetProxyConfig();
486 return true;
489 void ProxyConfigServiceImpl::AddNotificationCallback(base::Closure callback) {
491 std::vector<base::Closure>::iterator iter =
492 findIfEqual(callbacks_.begin(), callbacks_.end(), callback);
493 if (iter == callbacks_.end())
494 callbacks_.push_back(callback);
497 void ProxyConfigServiceImpl::RemoveNotificationCallback(
498 base::Closure callback) {
499 std::vector<base::Closure>::iterator iter =
500 findIfEqual(callbacks_.begin(), callbacks_.end(), callback);
501 if (iter != callbacks_.end())
502 callbacks_.erase(iter);
505 void ProxyConfigServiceImpl::OnProxyConfigChanged(
506 ProxyPrefs::ConfigState config_state,
507 const net::ProxyConfig& config) {
508 VLOG(1) << this << ": got prefs change: " << ConfigStateToString(config_state)
509 << ", mode=" << config.proxy_rules().type;
510 Network* network = NULL;
511 if (!active_network_.empty()) {
512 network = CrosLibrary::Get()->GetNetworkLibrary()->FindNetworkByPath(
513 active_network_);
514 if (!network)
515 LOG(ERROR) << "can't find requested network " << active_network_;
517 DetermineEffectiveConfig(network, true);
520 void ProxyConfigServiceImpl::OnNetworkManagerChanged(
521 NetworkLibrary* network_lib) {
522 VLOG(1) << this << " OnNetworkManagerChanged: use-shared-proxies="
523 << GetUseSharedProxies();
524 OnActiveNetworkChanged(network_lib, network_lib->active_network());
527 void ProxyConfigServiceImpl::OnNetworkChanged(NetworkLibrary* network_lib,
528 const Network* network) {
529 if (!network)
530 return;
531 VLOG(1) << this << " OnNetworkChanged: "
532 << (network->name().empty() ? network->service_path() :
533 network->name())
534 << ", use-shared-proxies=" << GetUseSharedProxies();
535 // We only care about active network.
536 if (network == network_lib->active_network())
537 OnActiveNetworkChanged(network_lib, network);
540 // static
541 void ProxyConfigServiceImpl::RegisterPrefs(PrefService* pref_service) {
542 // Use shared proxies default to off. GetUseSharedProxies will return the
543 // correct value based on pre-login and login.
544 pref_service->RegisterBooleanPref(prefs::kUseSharedProxies,
545 false,
546 PrefService::UNSYNCABLE_PREF);
549 //------------------ ProxyConfigServiceImpl: private methods -------------------
551 void ProxyConfigServiceImpl::Observe(
552 int type,
553 const content::NotificationSource& source,
554 const content::NotificationDetails& details) {
555 if (type == chrome::NOTIFICATION_PREF_CHANGED &&
556 *(content::Details<std::string>(details).ptr()) ==
557 prefs::kUseSharedProxies) {
558 if (content::Source<PrefService>(source).ptr() == prefs()) {
559 VLOG(1) << this << ": new use-shared-proxies = " << GetUseSharedProxies();
560 // Determine new proxy config which may have changed because of new
561 // use-shared-proxies. If necessary, activate it.
562 Network* network = NULL;
563 if (!active_network_.empty()) {
564 network = CrosLibrary::Get()->GetNetworkLibrary()->FindNetworkByPath(
565 active_network_);
566 if (!network)
567 LOG(WARNING) << "can't find requested network " << active_network_;
569 DetermineEffectiveConfig(network, true);
571 return;
573 PrefProxyConfigTrackerImpl::Observe(type, source, details);
576 void ProxyConfigServiceImpl::OnUISetProxyConfig() {
577 if (current_ui_network_.empty())
578 return;
579 // Update config to flimflam.
580 std::string value;
581 if (current_ui_config_.SerializeForNetwork(&value)) {
582 VLOG(1) << this << ": set proxy (mode=" << current_ui_config_.mode
583 << ") for " << current_ui_network_;
584 current_ui_config_.state = ProxyPrefs::CONFIG_SYSTEM;
585 SetProxyConfigForNetwork(current_ui_network_, value, false);
589 void ProxyConfigServiceImpl::OnActiveNetworkChanged(NetworkLibrary* network_lib,
590 const Network* active_network) {
591 std::string new_network;
592 if (active_network)
593 new_network = active_network->service_path();
595 if (active_network_ == new_network) { // Same active network.
596 VLOG(1) << this << ": same active network: "
597 << (new_network.empty() ? "empty" :
598 (active_network->name().empty() ?
599 new_network : active_network->name()));
600 // Even though network is the same, its proxy config (e.g. if private
601 // version of network replaces the shared version after login), or
602 // use-shared-proxies setting (e.g. after login) may have changed,
603 // so re-determine effective proxy config, and activate if different.
604 if (active_network) {
605 VLOG(1) << this << ": profile=" << active_network->profile_type()
606 << "," << active_network->profile_path()
607 << ", proxy=" << active_network->proxy_config();
608 DetermineEffectiveConfig(active_network, true);
610 return;
613 // If there was a previous active network, remove it as observer.
614 if (!active_network_.empty())
615 network_lib->RemoveNetworkObserver(active_network_, this);
617 active_network_ = new_network;
619 if (active_network_.empty()) {
620 VLOG(1) << this << ": new active network: empty";
621 DetermineEffectiveConfig(active_network, true);
622 return;
625 VLOG(1) << this << ": new active network: path="
626 << active_network->service_path()
627 << ", name=" << active_network->name()
628 << ", profile=" << active_network->profile_type()
629 << "," << active_network->profile_path()
630 << ", proxy=" << active_network->proxy_config();
632 // Register observer for new network.
633 network_lib->AddNetworkObserver(active_network_, this);
635 // If necessary, migrate config to flimflam.
636 if (active_network->proxy_config().empty() && !device_config_.empty()) {
637 VLOG(1) << this << ": try migrating device config to " << active_network_;
638 SetProxyConfigForNetwork(active_network_, device_config_, true);
639 } else {
640 // Otherwise, determine and activate possibly new effective proxy config.
641 DetermineEffectiveConfig(active_network, true);
645 void ProxyConfigServiceImpl::SetProxyConfigForNetwork(
646 const std::string& network_path, const std::string& value,
647 bool only_set_if_empty) {
648 Network* network = CrosLibrary::Get()->GetNetworkLibrary()->FindNetworkByPath(
649 network_path);
650 if (!network) {
651 NOTREACHED() << "can't find requested network " << network_path;
652 return;
654 if (!only_set_if_empty || network->proxy_config().empty()) {
655 network->SetProxyConfig(value);
656 VLOG(1) << this << ": set proxy for " << (network->name().empty() ?
657 network_path : network->name())
658 << ", value=" << value;
659 if (network_path == active_network_)
660 DetermineEffectiveConfig(network, true);
664 bool ProxyConfigServiceImpl::GetUseSharedProxies() {
665 const PrefService::Preference* use_shared_proxies_pref =
666 prefs()->FindPreference(prefs::kUseSharedProxies);
667 if (!use_shared_proxies_pref || use_shared_proxies_pref->IsDefaultValue())
668 return !UserManager::Get()->user_is_logged_in();
669 return use_shared_proxies_.GetValue();
672 void ProxyConfigServiceImpl::DetermineEffectiveConfig(const Network* network,
673 bool activate) {
674 // Get prefs proxy config if available.
675 net::ProxyConfig pref_config;
676 ProxyPrefs::ConfigState pref_state = GetProxyConfig(&pref_config);
678 // Get network proxy config if available.
679 net::ProxyConfig network_config;
680 net::ProxyConfigService::ConfigAvailability network_availability =
681 net::ProxyConfigService::CONFIG_UNSET;
682 bool ignore_proxy = activate;
683 if (network) {
684 // If we're activating proxy, ignore proxy if necessary;
685 // otherwise, for ui, get actual proxy to show user.
686 ignore_proxy = activate ? IgnoreProxy(network) : false;
687 // If network is shared but use-shared-proxies is off, use direct mode.
688 if (ignore_proxy) {
689 VLOG(1) << this << ": shared network && !use-shared-proxies, use direct";
690 network_availability = net::ProxyConfigService::CONFIG_VALID;
691 } else if (!network->proxy_config().empty()) {
692 // Network is private or shared with user using shared proxies.
693 JSONStringValueSerializer serializer(network->proxy_config());
694 scoped_ptr<Value> value(serializer.Deserialize(NULL, NULL));
695 if (value.get() && value->GetType() == Value::TYPE_DICTIONARY) {
696 DictionaryValue* dict = static_cast<DictionaryValue*>(value.get());
697 ProxyConfigDictionary proxy_dict(dict);
698 if (PrefConfigToNetConfig(proxy_dict, &network_config)) {
699 VLOG(1) << this << ": using network proxy: "
700 << network->proxy_config();
701 network_availability = net::ProxyConfigService::CONFIG_VALID;
707 // Determine effective proxy config, either from prefs or network.
708 ProxyPrefs::ConfigState effective_config_state;
709 net::ProxyConfig effective_config;
710 GetEffectiveProxyConfig(pref_state, pref_config,
711 network_availability, network_config, ignore_proxy,
712 &effective_config_state, &effective_config);
714 // Determine if we should activate effective proxy and which proxy config to
715 // store it.
716 if (activate) { // Activate effective proxy and store into |active_config_|.
717 // If last update didn't complete, we definitely update now.
718 bool update_now = update_pending();
719 if (!update_now) { // Otherwise, only update now if there're changes.
720 update_now = active_config_state_ != effective_config_state ||
721 (active_config_state_ != ProxyPrefs::CONFIG_UNSET &&
722 !active_config_.Equals(effective_config));
724 if (update_now) { // Activate and store new effective config.
725 active_config_state_ = effective_config_state;
726 if (active_config_state_ != ProxyPrefs::CONFIG_UNSET)
727 active_config_ = effective_config;
728 // If effective config is from system (i.e. network), it's considered a
729 // special kind of prefs that ranks below policy/extension but above
730 // others, so bump it up to CONFIG_OTHER_PRECEDE to force its precedence
731 // when PrefProxyConfigTrackerImpl pushes it to ChromeProxyConfigService.
732 if (effective_config_state == ProxyPrefs::CONFIG_SYSTEM)
733 effective_config_state = ProxyPrefs::CONFIG_OTHER_PRECEDE;
734 // If config is manual, add rule to bypass local host.
735 if (effective_config.proxy_rules().type !=
736 net::ProxyConfig::ProxyRules::TYPE_NO_RULES)
737 effective_config.proxy_rules().bypass_rules.AddRuleToBypassLocal();
738 PrefProxyConfigTrackerImpl::OnProxyConfigChanged(effective_config_state,
739 effective_config);
740 if (VLOG_IS_ON(1) && !update_pending()) { // Update was successful.
741 scoped_ptr<DictionaryValue> config_dict(static_cast<DictionaryValue*>(
742 effective_config.ToValue()));
743 std::string config_value;
744 JSONStringValueSerializer serializer(&config_value);
745 serializer.Serialize(*config_dict.get());
746 VLOG(1) << this << ": Proxy changed: "
747 << ConfigStateToString(active_config_state_)
748 << ", " << config_value;
751 } else { // For UI, store effective proxy into |current_ui_config_|.
752 current_ui_config_.FromNetProxyConfig(effective_config);
753 current_ui_config_.state = effective_config_state;
754 if (PrefPrecedes(effective_config_state))
755 current_ui_config_.user_modifiable = false;
756 else
757 current_ui_config_.user_modifiable = !network || !IgnoreProxy(network);
761 void ProxyConfigServiceImpl::OnUISetCurrentNetwork(const Network* network) {
762 DetermineEffectiveConfig(network, false);
763 VLOG(1) << this << ": current ui network: "
764 << (network->name().empty() ?
765 current_ui_network_ : network->name())
766 << ", " << ModeToString(current_ui_config_.mode)
767 << ", " << ConfigStateToString(current_ui_config_.state)
768 << ", modifiable:" << current_ui_config_.user_modifiable;
769 // Notify whoever is interested in this change.
770 std::vector<base::Closure>::iterator iter = callbacks_.begin();
771 while (iter != callbacks_.end()) {
772 if (iter->is_null()) {
773 iter = callbacks_.erase(iter);
774 } else {
775 iter->Run();
776 ++iter;
781 void ProxyConfigServiceImpl::ResetUICache() {
782 current_ui_network_.clear();
783 current_ui_config_ = ProxyConfig();
786 void ProxyConfigServiceImpl::FetchProxyPolicy() {
787 std::string policy_value;
788 if (!CrosSettings::Get()->GetString(kSettingProxyEverywhere,
789 &policy_value)) {
790 LOG(WARNING) << this << ": Error retrieving proxy setting from device";
791 device_config_.clear();
792 return;
795 VLOG(1) << this << ": Retrieved proxy setting from device, value=["
796 << policy_value << "]";
797 ProxyConfig device_config;
798 if (!device_config.DeserializeForDevice(policy_value) ||
799 !device_config.SerializeForNetwork(&device_config_)) {
800 LOG(WARNING) << "Can't deserialize device setting or serialize for network";
801 device_config_.clear();
802 return;
804 if (!active_network_.empty()) {
805 VLOG(1) << this << ": try migrating device config to " << active_network_;
806 SetProxyConfigForNetwork(active_network_, device_config_, true);
810 } // namespace chromeos