proxy_config_service_impl.cc revision 90dce4d38c5ff5333bea97d859d4e484e27edf0c
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. 4 5#include "chrome/browser/chromeos/proxy_config_service_impl.h" 6 7#include <ostream> 8 9#include "base/bind.h" 10#include "base/json/json_string_value_serializer.h" 11#include "base/logging.h" 12#include "base/prefs/pref_registry_simple.h" 13#include "base/prefs/pref_service.h" 14#include "base/string_util.h" 15#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" 19#include "chrome/browser/policy/browser_policy_connector.h" 20#include "chrome/browser/policy/cloud/cloud_policy_constants.h" 21#include "chrome/browser/prefs/proxy_config_dictionary.h" 22#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" 26#include "chromeos/network/network_ui_data.h" 27#include "chromeos/network/onc/onc_constants.h" 28#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 33namespace chromeos { 34 35namespace { 36 37// Shoud we try to push this to base? 38// Helper comparator functor for the find_if call in |findIfEqual| 39template <class T> 40class EqualsComparator{ 41 public: 42 explicit EqualsComparator(const T& key) : key_(key) { } 43 bool operator() (const T& element) { 44 return element.Equals(key_); 45 } 46 private: 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. 53template<class InputIterator, class T> 54InputIterator findIfEqual(InputIterator first, InputIterator last, 55 const T& key) { 56 return std::find_if(first, last, EqualsComparator<T>(key)); 57} 58 59const 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 76const 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. 96bool 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} 111 112} // namespace 113 114//----------- ProxyConfigServiceImpl::ProxyConfig: public methods -------------- 115 116ProxyConfigServiceImpl::ProxyConfig::ProxyConfig() 117 : mode(MODE_DIRECT), 118 state(ProxyPrefs::CONFIG_UNSET), 119 user_modifiable(true) {} 120 121ProxyConfigServiceImpl::ProxyConfig::~ProxyConfig() {} 122 123bool 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 173DictionaryValue* 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 208ProxyConfigServiceImpl::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 223bool 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 246void 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 265ProxyConfigServiceImpl::ProxyConfigServiceImpl(PrefService* pref_service) 266 : PrefProxyConfigTrackerImpl(pref_service), 267 active_config_state_(ProxyPrefs::CONFIG_UNSET), 268 pointer_factory_(this) { 269 270 // Register for notifications of UseSharedProxies user preference. 271 if (pref_service->FindPreference(prefs::kUseSharedProxies)) { 272 use_shared_proxies_.Init( 273 prefs::kUseSharedProxies, pref_service, 274 base::Bind(&ProxyConfigServiceImpl::OnUseSharedProxiesChanged, 275 base::Unretained(this))); 276 } 277 278 // Register for shill network notifications. 279 NetworkLibrary* network_lib = CrosLibrary::Get()->GetNetworkLibrary(); 280 OnActiveNetworkChanged(network_lib, network_lib->active_network()); 281 network_lib->AddNetworkManagerObserver(this); 282} 283 284ProxyConfigServiceImpl::~ProxyConfigServiceImpl() { 285 NetworkLibrary* netlib = CrosLibrary::Get()->GetNetworkLibrary(); 286 if (netlib) { 287 netlib->RemoveNetworkManagerObserver(this); 288 netlib->RemoveObserverForAllNetworks(this); 289 } 290} 291 292void ProxyConfigServiceImpl::UISetCurrentNetwork( 293 const std::string& current_network) { 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 305void 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 317void 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 336void 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 342bool ProxyConfigServiceImpl::UISetProxyConfigToDirect() { 343 current_ui_config_.mode = ProxyConfig::MODE_DIRECT; 344 OnUISetProxyConfig(); 345 return true; 346} 347 348bool ProxyConfigServiceImpl::UISetProxyConfigToAutoDetect() { 349 current_ui_config_.mode = ProxyConfig::MODE_AUTO_DETECT; 350 OnUISetProxyConfig(); 351 return true; 352} 353 354bool 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 361bool 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 369bool 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 382bool 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 396void 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 404void 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} 411 412void ProxyConfigServiceImpl::OnProxyConfigChanged( 413 ProxyPrefs::ConfigState config_state, 414 const net::ProxyConfig& config) { 415 VLOG(1) << "Got prefs change: " << ConfigStateToString(config_state) 416 << ", mode=" << config.proxy_rules().type; 417 Network* network = NULL; 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 427void 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 434void 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} 446 447// static 448bool 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 463void ProxyConfigServiceImpl::RegisterPrefs(PrefRegistrySimple* registry) { 464 // Use shared proxies default to off. GetUseSharedProxies will return the 465 // correct value based on pre-login and login. 466 registry->RegisterBooleanPref(prefs::kUseSharedProxies, true); 467} 468 469// static 470void ProxyConfigServiceImpl::RegisterUserPrefs( 471 user_prefs::PrefRegistrySyncable* registry) { 472 registry->RegisterBooleanPref( 473 prefs::kUseSharedProxies, 474 true, 475 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); 476} 477 478//------------------ ProxyConfigServiceImpl: private methods ------------------- 479 480void ProxyConfigServiceImpl::OnUseSharedProxiesChanged() { 481 VLOG(1) << "New use-shared-proxies = " << GetUseSharedProxies(); 482 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} 494 495void ProxyConfigServiceImpl::OnUISetProxyConfig() { 496 if (current_ui_network_.empty()) 497 return; 498 // Update config to shill. 499 std::string value; 500 if (current_ui_config_.SerializeForNetwork(&value)) { 501 VLOG(1) << "Set proxy (mode=" << current_ui_config_.mode 502 << ") for " << current_ui_network_; 503 current_ui_config_.state = ProxyPrefs::CONFIG_SYSTEM; 504 SetProxyConfigForNetwork(current_ui_network_, value, false); 505 } 506} 507 508void ProxyConfigServiceImpl::OnActiveNetworkChanged(NetworkLibrary* network_lib, 509 const Network* active_network) { 510 std::string new_network; 511 if (active_network) 512 new_network = active_network->service_path(); 513 514 if (active_network_ == new_network) { // Same active network. 515 VLOG(1) << "Same active network: " 516 << (new_network.empty() ? "empty" : 517 (active_network->name().empty() ? 518 new_network : active_network->name())); 519 // Even though network is the same, its proxy config (e.g. if private 520 // version of network replaces the shared version after login), or 521 // use-shared-proxies setting (e.g. after login) may have changed, 522 // so re-determine effective proxy config, and activate if different. 523 if (active_network) { 524 VLOG(1) << "Profile=" << active_network->profile_type() 525 << "," << active_network->profile_path() 526 << ", proxy=" << active_network->proxy_config(); 527 DetermineEffectiveConfig(active_network, true); 528 } 529 return; 530 } 531 532 // If there was a previous active network, remove it as observer. 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 557void 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 576bool 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 586bool 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()) { 592 policy::BrowserPolicyConnector* connector = 593 g_browser_process->browser_policy_connector(); 594 const User* logged_in_user = UserManager::Get()->GetLoggedInUser(); 595 if (connector->GetUserAffiliation(logged_in_user->email()) == 596 policy::USER_AFFILIATION_MANAGED) { 597 VLOG(1) << "Respecting proxy for network " << network->name() 598 << ", as logged-in user belongs to the domain the device " 599 << "is enrolled to."; 600 return false; 601 } 602 } 603 604 return !GetUseSharedProxies(); 605} 606 607void ProxyConfigServiceImpl::DetermineEffectiveConfig(const Network* network, 608 bool activate) { 609 // Get prefs proxy config if available. 610 net::ProxyConfig pref_config; 611 ProxyPrefs::ConfigState pref_state = GetProxyConfig(&pref_config); 612 613 // Get network proxy config if available. 614 net::ProxyConfig network_config; 615 net::ProxyConfigService::ConfigAvailability network_availability = 616 net::ProxyConfigService::CONFIG_UNSET; 617 bool ignore_proxy = activate; 618 if (network) { 619 // If we're activating proxy, ignore proxy if necessary; 620 // otherwise, for ui, get actual proxy to show user. 621 ignore_proxy = activate ? IgnoreProxy(network) : false; 622 // If network is shared but use-shared-proxies is off, use direct mode. 623 if (ignore_proxy) { 624 VLOG(1) << "Shared network && !use-shared-proxies, use direct"; 625 network_availability = net::ProxyConfigService::CONFIG_VALID; 626 } else if (!network->proxy_config().empty()) { 627 // Network is private or shared with user using shared proxies. 628 if (ParseProxyConfig(network->proxy_config(), &network_config)) { 629 VLOG(1) << this << ": using network proxy: " 630 << network->proxy_config(); 631 network_availability = net::ProxyConfigService::CONFIG_VALID; 632 } 633 } 634 } 635 636 // Determine effective proxy config, either from prefs or network. 637 ProxyPrefs::ConfigState effective_config_state; 638 net::ProxyConfig effective_config; 639 GetEffectiveProxyConfig(pref_state, pref_config, 640 network_availability, network_config, ignore_proxy, 641 &effective_config_state, &effective_config); 642 643 // Determine if we should activate effective proxy and which proxy config to 644 // store it. 645 if (activate) { // Activate effective proxy and store into |active_config_|. 646 // If last update didn't complete, we definitely update now. 647 bool update_now = update_pending(); 648 if (!update_now) { // Otherwise, only update now if there're changes. 649 update_now = active_config_state_ != effective_config_state || 650 (active_config_state_ != ProxyPrefs::CONFIG_UNSET && 651 !active_config_.Equals(effective_config)); 652 } 653 if (update_now) { // Activate and store new effective config. 654 active_config_state_ = effective_config_state; 655 if (active_config_state_ != ProxyPrefs::CONFIG_UNSET) 656 active_config_ = effective_config; 657 // If effective config is from system (i.e. network), it's considered a 658 // special kind of prefs that ranks below policy/extension but above 659 // others, so bump it up to CONFIG_OTHER_PRECEDE to force its precedence 660 // when PrefProxyConfigTrackerImpl pushes it to ChromeProxyConfigService. 661 if (effective_config_state == ProxyPrefs::CONFIG_SYSTEM) 662 effective_config_state = ProxyPrefs::CONFIG_OTHER_PRECEDE; 663 // If config is manual, add rule to bypass local host. 664 if (effective_config.proxy_rules().type != 665 net::ProxyConfig::ProxyRules::TYPE_NO_RULES) 666 effective_config.proxy_rules().bypass_rules.AddRuleToBypassLocal(); 667 PrefProxyConfigTrackerImpl::OnProxyConfigChanged(effective_config_state, 668 effective_config); 669 if (VLOG_IS_ON(1) && !update_pending()) { // Update was successful. 670 scoped_ptr<DictionaryValue> config_dict(static_cast<DictionaryValue*>( 671 effective_config.ToValue())); 672 std::string config_value; 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 } 693 } 694} 695 696void 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 715void ProxyConfigServiceImpl::ResetUICache() { 716 current_ui_network_.clear(); 717 current_ui_config_ = ProxyConfig(); 718} 719 720} // namespace chromeos 721