diff options
25 files changed, 715 insertions, 215 deletions
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index be7b281..9d9de08 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd @@ -10627,6 +10627,9 @@ ls' lab."> <message name="IDS_OPTIONS_SETTINGS_ADD_VPN" desc="In the settings tab, the text on the button to add a private network."> Add private network </message> + <message name="IDS_OPTIONS_SETTINGS_USE_SHARED_PROXIES" desc="In the settings tab, the text next to the checkbox for using shared proxies."> + Use shared proxies + </message> <message name="IDS_OPTIONS_SETTINGS_ENABLE_DATA_ROAMING" desc="In the settings tab, the text next to the checkbox for data roaming."> Allow mobile data roaming </message> @@ -10852,6 +10855,9 @@ ls' lab."> <message name="IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_DNSSERVER" desc="In settings Internet options, the label dns server."> DNS server: </message> + <message name="IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_CHANGE_PROXY_BUTTON" desc="For ethernet and remembered services, change proxy button text in chrome:settings/internet."> + Change proxy settings... + </message> <message name="IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_HARDWARE_ADDRESS" desc="In settings Internet options, the label hardware address."> Hardware address: </message> diff --git a/chrome/browser/chromeos/cros/network_library.cc b/chrome/browser/chromeos/cros/network_library.cc index 15a6bc8..5ddb0a5 100644 --- a/chrome/browser/chromeos/cros/network_library.cc +++ b/chrome/browser/chromeos/cros/network_library.cc @@ -163,6 +163,7 @@ const char kEntriesProperty[] = "Entries"; const char kDevicesProperty[] = "Devices"; const char kProviderProperty[] = "Provider"; const char kHostProperty[] = "Host"; +const char* kProxyConfigProperty = "ProxyConfig"; // Flimflam property names for SIMLock status. const char kSIMLockStatusProperty[] = "Cellular.SIMLockStatus"; @@ -516,6 +517,7 @@ enum PropertyIndex { PROPERTY_INDEX_PROFILE, PROPERTY_INDEX_PROFILES, PROPERTY_INDEX_PROVIDER, + PROPERTY_INDEX_PROXY_CONFIG, PROPERTY_INDEX_ROAMING_STATE, PROPERTY_INDEX_SAVE_CREDENTIALS, PROPERTY_INDEX_SCANNING, @@ -609,6 +611,7 @@ StringToEnum<PropertyIndex>::Pair property_index_table[] = { { kProfileProperty, PROPERTY_INDEX_PROFILE }, { kProfilesProperty, PROPERTY_INDEX_PROFILES }, { kProviderProperty, PROPERTY_INDEX_PROVIDER }, + { kProxyConfigProperty, PROPERTY_INDEX_PROXY_CONFIG }, { kRoamingStateProperty, PROPERTY_INDEX_ROAMING_STATE }, { kSaveCredentialsProperty, PROPERTY_INDEX_SAVE_CREDENTIALS }, { kScanningProperty, PROPERTY_INDEX_SCANNING }, @@ -1212,6 +1215,8 @@ bool Network::ParseValue(int index, const Value* value) { return value->GetAsBoolean(&auto_connect_); case PROPERTY_INDEX_SAVE_CREDENTIALS: return value->GetAsBoolean(&save_credentials_); + case PROPERTY_INDEX_PROXY_CONFIG: + return value->GetAsString(&proxy_config_); default: break; } @@ -1385,6 +1390,10 @@ std::string Network::GetErrorString() const { return l10n_util::GetStringUTF8(IDS_CHROMEOS_NETWORK_STATE_UNRECOGNIZED); } +void Network::SetProxyConfig(const std::string& proxy_config) { + SetStringProperty(kProxyConfigProperty, proxy_config, &proxy_config_); +} + void Network::SendTpmPin(const std::string& tpm_pin) { // TODO(jamescook): Create a more specific D-Bus property for the TPM PIN. // For now, this is the only one flimflam understands. @@ -2113,7 +2122,7 @@ bool WifiNetwork::SetHexSsid(const std::string& ssid_hex) { // Converts ascii hex dump (eg. "49656c6c6f") to string (eg. "Hello"). std::vector<uint8> ssid_raw; if (!base::HexStringToBytes(ssid_hex, &ssid_raw)) { - LOG(ERROR) << "Iligal hex char is found in WiFi.HexSSID."; + LOG(ERROR) << "Illegal hex char is found in WiFi.HexSSID."; ssid_raw.clear(); return false; } @@ -5120,6 +5129,7 @@ class NetworkLibraryImplStub : public NetworkLibraryImplBase { wifi1->set_connecting(true); wifi1->set_active(true); wifi1->set_encryption(SECURITY_NONE); + wifi1->set_profile_type(PROFILE_SHARED); AddNetwork(wifi1); WifiNetwork* wifi2 = new WifiNetwork("fw2"); @@ -5127,6 +5137,7 @@ class NetworkLibraryImplStub : public NetworkLibraryImplBase { wifi2->set_strength(70); wifi2->set_connected(false); wifi2->set_encryption(SECURITY_NONE); + wifi2->set_profile_type(PROFILE_SHARED); AddNetwork(wifi2); WifiNetwork* wifi3 = new WifiNetwork("fw3"); @@ -5135,6 +5146,7 @@ class NetworkLibraryImplStub : public NetworkLibraryImplBase { wifi3->set_connected(false); wifi3->set_encryption(SECURITY_WEP); wifi3->set_passphrase_required(true); + wifi3->set_profile_type(PROFILE_USER); AddNetwork(wifi3); WifiNetwork* wifi4 = new WifiNetwork("fw4"); diff --git a/chrome/browser/chromeos/cros/network_library.h b/chrome/browser/chromeos/cros/network_library.h index cb0a315..fc55ad7 100644 --- a/chrome/browser/chromeos/cros/network_library.h +++ b/chrome/browser/chromeos/cros/network_library.h @@ -354,6 +354,8 @@ class Network { const std::string& unique_id() const { return unique_id_; } + const std::string& proxy_config() const { return proxy_config_; } + void set_notify_failure(bool state) { notify_failure_ = state; } // We don't have a setter for |favorite_| because to unfavorite a network is @@ -372,6 +374,8 @@ class Network { // Return a string representation of the error code. std::string GetErrorString() const; + void SetProxyConfig(const std::string& proxy_config); + // Return true if the network must be in the user profile (e.g. has certs). virtual bool RequiresUserProfile() const; @@ -438,6 +442,7 @@ class Network { bool favorite_; bool auto_connect_; bool save_credentials_; // save passphrase and EAP credentials to disk. + std::string proxy_config_; // Unique identifier, set the first time the network is parsed. std::string unique_id_; diff --git a/chrome/browser/chromeos/cros_settings.h b/chrome/browser/chromeos/cros_settings.h index a225313..cc15f2f 100644 --- a/chrome/browser/chromeos/cros_settings.h +++ b/chrome/browser/chromeos/cros_settings.h @@ -69,6 +69,9 @@ class CrosSettings : public base::NonThreadSafe { void AddSettingsObserver(const char* path, NotificationObserver* obs); void RemoveSettingsObserver(const char* path, NotificationObserver* obs); + // Returns the provider that handles settings with the path or prefix. + CrosSettingsProvider* GetProvider(const std::string& path) const; + private: // List of ChromeOS system settings providers. std::vector<CrosSettingsProvider*> providers_; @@ -82,7 +85,6 @@ class CrosSettings : public base::NonThreadSafe { CrosSettings(); ~CrosSettings(); - CrosSettingsProvider* GetProvider(const std::string& path) const; friend struct base::DefaultLazyInstanceTraits<CrosSettings>; DISALLOW_COPY_AND_ASSIGN(CrosSettings); diff --git a/chrome/browser/chromeos/preferences.cc b/chrome/browser/chromeos/preferences.cc index cda87b2..5cd8e6c 100644 --- a/chrome/browser/chromeos/preferences.cc +++ b/chrome/browser/chromeos/preferences.cc @@ -9,12 +9,14 @@ #include "base/string_split.h" #include "base/string_util.h" #include "base/utf_string_conversions.h" +#include "chrome/browser/browser_process.h" #include "chrome/browser/chromeos/cros/cros_library.h" #include "chrome/browser/chromeos/cros/power_library.h" #include "chrome/browser/chromeos/input_method/input_method_manager.h" #include "chrome/browser/chromeos/input_method/input_method_util.h" #include "chrome/browser/chromeos/input_method/xkeyboard.h" #include "chrome/browser/chromeos/login/login_utils.h" +#include "chrome/browser/chromeos/proxy_config_service_impl.h" #include "chrome/browser/chromeos/system/touchpad_settings.h" #include "chrome/browser/prefs/pref_member.h" #include "chrome/browser/prefs/pref_service.h" @@ -186,6 +188,11 @@ void Preferences::RegisterUserPrefs(PrefService* prefs) { // The map of timestamps of the last used file browser handlers. prefs->RegisterDictionaryPref(prefs::kLastUsedFileBrowserHandlers, PrefService::UNSYNCABLE_PREF); + + // Use shared proxies default to off. + prefs->RegisterBooleanPref(prefs::kUseSharedProxies, + false, + PrefService::SYNCABLE_PREF); } void Preferences::Init(PrefService* prefs) { @@ -254,6 +261,8 @@ void Preferences::Init(PrefService* prefs) { enable_screen_lock_.Init(prefs::kEnableScreenLock, prefs, this); + use_shared_proxies_.Init(prefs::kUseSharedProxies, prefs, this); + // Initialize preferences to currently saved state. NotifyPrefChanged(NULL); @@ -440,6 +449,11 @@ void Preferences::NotifyPrefChanged(const std::string* pref_name) { CrosLibrary::Get()->GetPowerLibrary()->EnableScreenLock( enable_screen_lock_.GetValue()); } + + if (!pref_name || *pref_name == prefs::kUseSharedProxies) { + g_browser_process->chromeos_proxy_config_service_impl()-> + UISetUseSharedProxies(use_shared_proxies_.GetValue()); + } } void Preferences::SetLanguageConfigBoolean(const char* section, diff --git a/chrome/browser/chromeos/preferences.h b/chrome/browser/chromeos/preferences.h index 11a554a..db280aa 100644 --- a/chrome/browser/chromeos/preferences.h +++ b/chrome/browser/chromeos/preferences.h @@ -123,6 +123,8 @@ class Preferences : public NotificationObserver { BooleanPrefMember enable_screen_lock_; + BooleanPrefMember use_shared_proxies_; + DISALLOW_COPY_AND_ASSIGN(Preferences); }; diff --git a/chrome/browser/chromeos/proxy_config_service_impl.cc b/chrome/browser/chromeos/proxy_config_service_impl.cc index 681688c..53b8928 100644 --- a/chrome/browser/chromeos/proxy_config_service_impl.cc +++ b/chrome/browser/chromeos/proxy_config_service_impl.cc @@ -12,8 +12,10 @@ #include "chrome/browser/chromeos/cros/cros_library.h" #include "chrome/browser/chromeos/cros_settings_names.h" #include "chrome/browser/policy/proto/chrome_device_policy.pb.h" +#include "chrome/browser/prefs/proxy_config_dictionary.h" #include "chrome/browser/prefs/proxy_prefs.h" #include "content/browser/browser_thread.h" +#include "content/common/json_value_serializer.h" namespace em = enterprise_management; @@ -191,50 +193,7 @@ ProxyConfigServiceImpl::ProxyConfig::ManualProxy* return NULL; } -bool ProxyConfigServiceImpl::ProxyConfig::Serialize(std::string* output) { - em::DeviceProxySettingsProto proxy_proto; - switch (mode) { - case MODE_DIRECT: { - proxy_proto.set_proxy_mode(ProxyPrefs::kDirectProxyModeName); - break; - } - case MODE_AUTO_DETECT: { - proxy_proto.set_proxy_mode(ProxyPrefs::kAutoDetectProxyModeName); - break; - } - case MODE_PAC_SCRIPT: { - proxy_proto.set_proxy_mode(ProxyPrefs::kPacScriptProxyModeName); - if (!automatic_proxy.pac_url.is_empty()) - proxy_proto.set_proxy_pac_url(automatic_proxy.pac_url.spec()); - break; - } - case MODE_SINGLE_PROXY: { - proxy_proto.set_proxy_mode(ProxyPrefs::kFixedServersProxyModeName); - if (single_proxy.server.is_valid()) - proxy_proto.set_proxy_server(single_proxy.server.ToURI()); - break; - } - case MODE_PROXY_PER_SCHEME: { - proxy_proto.set_proxy_mode(ProxyPrefs::kFixedServersProxyModeName); - std::string spec; - EncodeAndAppendProxyServer("http", http_proxy.server, &spec); - EncodeAndAppendProxyServer("https", https_proxy.server, &spec); - EncodeAndAppendProxyServer("ftp", ftp_proxy.server, &spec); - EncodeAndAppendProxyServer("socks", socks_proxy.server, &spec); - if (!spec.empty()) - proxy_proto.set_proxy_server(spec); - break; - } - default: { - NOTREACHED() << "Unrecognized proxy config mode"; - break; - } - } - proxy_proto.set_proxy_bypass_list(bypass_rules.ToString()); - return proxy_proto.SerializeToString(output); -} - -bool ProxyConfigServiceImpl::ProxyConfig::Deserialize( +bool ProxyConfigServiceImpl::ProxyConfig::DeserializeForDevice( const std::string& input) { em::DeviceProxySettingsProto proxy_proto; if (!proxy_proto.ParseFromString(input)) @@ -291,6 +250,52 @@ bool ProxyConfigServiceImpl::ProxyConfig::Deserialize( return true; } +bool ProxyConfigServiceImpl::ProxyConfig::SerializeForNetwork( + std::string* output) { + scoped_ptr<DictionaryValue> proxy_dict(ToPrefProxyConfig()); + if (!proxy_dict.get()) + return false; + JSONStringValueSerializer serializer(output); + return serializer.Serialize(*proxy_dict.get()); +} + +bool ProxyConfigServiceImpl::ProxyConfig::DeserializeForNetwork( + const std::string& input) { + JSONStringValueSerializer serializer(input); + scoped_ptr<Value> value(serializer.Deserialize(NULL, NULL)); + if (!value.get() || value->GetType() != Value::TYPE_DICTIONARY) + return false; + DictionaryValue* proxy_dict = static_cast<DictionaryValue*>(value.get()); + return FromPrefProxyConfig(proxy_dict); +} + +bool ProxyConfigServiceImpl::ProxyConfig::Equals( + const ProxyConfig& other) const { + if (mode != other.mode) + return false; + switch (mode) { + case MODE_DIRECT: + case MODE_AUTO_DETECT: + return true; + case MODE_PAC_SCRIPT: + return automatic_proxy.pac_url == other.automatic_proxy.pac_url; + case MODE_SINGLE_PROXY: + return single_proxy.server == other.single_proxy.server && + bypass_rules.Equals(other.bypass_rules); + case MODE_PROXY_PER_SCHEME: + return http_proxy.server == other.http_proxy.server && + https_proxy.server == other.https_proxy.server && + ftp_proxy.server == other.ftp_proxy.server && + socks_proxy.server == other.socks_proxy.server && + bypass_rules.Equals(other.bypass_rules); + default: { + NOTREACHED() << "Unrecognized proxy config mode"; + break; + } + } + return false; +} + std::string ProxyConfigServiceImpl::ProxyConfig::ToString() const { return ProxyConfigToString(*this); } @@ -315,74 +320,245 @@ void ProxyConfigServiceImpl::ProxyConfig::EncodeAndAppendProxyServer( *spec += server.ToURI(); } +DictionaryValue* ProxyConfigServiceImpl::ProxyConfig::ToPrefProxyConfig() { + switch (mode) { + case MODE_DIRECT: { + return ProxyConfigDictionary::CreateDirect(); + } + case MODE_AUTO_DETECT: { + return ProxyConfigDictionary::CreateAutoDetect(); + } + case MODE_PAC_SCRIPT: { + return ProxyConfigDictionary::CreatePacScript( + automatic_proxy.pac_url.spec(), false); + } + case MODE_SINGLE_PROXY: { + std::string spec; + if (single_proxy.server.is_valid()) + spec = single_proxy.server.ToURI(); + return ProxyConfigDictionary::CreateFixedServers( + spec, bypass_rules.ToString()); + } + case MODE_PROXY_PER_SCHEME: { + std::string spec; + EncodeAndAppendProxyServer("http", http_proxy.server, &spec); + EncodeAndAppendProxyServer("https", https_proxy.server, &spec); + EncodeAndAppendProxyServer("ftp", ftp_proxy.server, &spec); + EncodeAndAppendProxyServer("socks", socks_proxy.server, &spec); + return ProxyConfigDictionary::CreateFixedServers( + spec, bypass_rules.ToString()); + } + default: + break; + } + NOTREACHED() << "Unrecognized proxy config mode for preference"; + return NULL; +} + +bool ProxyConfigServiceImpl::ProxyConfig::FromPrefProxyConfig( + const DictionaryValue* dict) { + ProxyConfigDictionary proxy_dict(dict); + + *this = ProxyConfigServiceImpl::ProxyConfig(); // Reset to default. + + ProxyPrefs::ProxyMode proxy_mode; + if (!proxy_dict.GetMode(&proxy_mode)) { + // Fall back to system settings if the mode preference is invalid. + return false; + } + + switch (proxy_mode) { + case ProxyPrefs::MODE_SYSTEM: + // Use system settings, so we shouldn't use |this| proxy config. + return false; + case ProxyPrefs::MODE_DIRECT: + // Ignore all the other proxy config preferences if the use of a proxy + // has been explicitly disabled. + return true; + case ProxyPrefs::MODE_AUTO_DETECT: + mode = MODE_AUTO_DETECT; + return true; + case ProxyPrefs::MODE_PAC_SCRIPT: { + std::string proxy_pac; + if (!proxy_dict.GetPacUrl(&proxy_pac)) { + LOG(ERROR) << "Proxy settings request PAC script but do not specify " + << "its URL. Falling back to direct connection."; + return true; + } + GURL proxy_pac_url(proxy_pac); + if (!proxy_pac_url.is_valid()) { + LOG(ERROR) << "Invalid proxy PAC url: " << proxy_pac; + return true; + } + mode = MODE_PAC_SCRIPT; + automatic_proxy.pac_url = proxy_pac_url; + return true; + } + case ProxyPrefs::MODE_FIXED_SERVERS: { + std::string proxy_server; + if (!proxy_dict.GetProxyServer(&proxy_server)) { + LOG(ERROR) << "Proxy settings request fixed proxy servers but do not " + << "specify their URLs. Falling back to direct connection."; + return true; + } + net::ProxyConfig::ProxyRules proxy_rules; + proxy_rules.ParseFromString(proxy_server); + if (proxy_rules.type == net::ProxyConfig::ProxyRules::TYPE_SINGLE_PROXY) { + mode = MODE_SINGLE_PROXY; + single_proxy.server = proxy_rules.single_proxy; + } else if (proxy_rules.type == + net::ProxyConfig::ProxyRules::TYPE_PROXY_PER_SCHEME) { + mode = MODE_PROXY_PER_SCHEME; + http_proxy.server = proxy_rules.proxy_for_http; + https_proxy.server = proxy_rules.proxy_for_https; + ftp_proxy.server = proxy_rules.proxy_for_ftp; + socks_proxy.server = proxy_rules.fallback_proxy; + } else { + LOG(ERROR) << "Proxy settings request fixed proxy servers but do not " + << "have valid proxy rules type. " + << "Falling back to direct connection."; + return true; + } + + std::string proxy_bypass; + if (proxy_dict.GetBypassList(&proxy_bypass)) { + bypass_rules.ParseFromString(proxy_bypass); + } + return true; + } + case ProxyPrefs::kModeCount: { + // Fall through to NOTREACHED(). + } + } + NOTREACHED() << "Unknown proxy mode, falling back to system settings."; + return false; +} + //------------------- ProxyConfigServiceImpl: public methods ------------------- ProxyConfigServiceImpl::ProxyConfigServiceImpl() - : can_post_task_(false), - config_availability_(net::ProxyConfigService::CONFIG_PENDING), - persist_to_device_(true), - persist_to_device_pending_(false) { + : testing_(false), + can_post_task_(false), + config_availability_(net::ProxyConfigService::CONFIG_UNSET), + use_shared_proxies_(false) { // Start async fetch of proxy config from settings persisted on device. - // TODO(kuan): retrieve config from policy and owner and merge them - bool use_default = true; if (CrosLibrary::Get()->EnsureLoaded()) { retrieve_property_op_ = SignedSettings::CreateRetrievePropertyOp( kSettingProxyEverywhere, this); if (retrieve_property_op_) { retrieve_property_op_->Execute(); VLOG(1) << "Start retrieving proxy setting from device"; - use_default = false; } else { VLOG(1) << "Fail to retrieve proxy setting from device"; } } - if (use_default) - config_availability_ = net::ProxyConfigService::CONFIG_UNSET; + + NetworkLibrary* network_lib = CrosLibrary::Get()->GetNetworkLibrary(); + OnActiveNetworkChanged(network_lib, network_lib->active_network()); + network_lib->AddNetworkManagerObserver(this); + can_post_task_ = true; } ProxyConfigServiceImpl::ProxyConfigServiceImpl(const ProxyConfig& init_config) - : can_post_task_(true), + : testing_(false), + can_post_task_(true), config_availability_(net::ProxyConfigService::CONFIG_VALID), - persist_to_device_(false), - persist_to_device_pending_(false) { - reference_config_ = init_config; + use_shared_proxies_(false) { + active_config_ = init_config; // Update the IO-accessible copy in |cached_config_| as well. - cached_config_ = reference_config_; + cached_config_ = active_config_; } ProxyConfigServiceImpl::~ProxyConfigServiceImpl() { + NetworkLibrary* netlib = CrosLibrary::Get()->GetNetworkLibrary(); + if (netlib) { + netlib->RemoveNetworkManagerObserver(this); + netlib->RemoveObserverForAllNetworks(this); + } } void ProxyConfigServiceImpl::UIGetProxyConfig(ProxyConfig* config) { // Should be called from UI thread. CheckCurrentlyOnUIThread(); // Simply returns the copy on the UI thread. - *config = reference_config_; + *config = current_ui_config_; +} + +bool ProxyConfigServiceImpl::UISetCurrentNetwork( + const std::string& current_network) { + // Should be called from UI thread. + CheckCurrentlyOnUIThread(); + if (current_ui_network_ == current_network) + return false; + Network* network = CrosLibrary::Get()->GetNetworkLibrary()->FindNetworkByPath( + current_network); + if (!network) { + LOG(ERROR) << "can't find requested network " << current_network; + return false; + } + current_ui_network_ = current_network; + current_ui_config_ = ProxyConfig(); + if (!network->proxy_config().empty()) + current_ui_config_.DeserializeForNetwork(network->proxy_config()); + VLOG(1) << "current ui network: " + << (network->name().empty() ? current_ui_network_ : network->name()) + << ", proxy mode: " << current_ui_config_.mode; + return true; +} + +bool ProxyConfigServiceImpl::UIMakeActiveNetworkCurrent() { + // Should be called from UI thread. + CheckCurrentlyOnUIThread(); + if (current_ui_network_ == active_network_) + return false; + current_ui_network_ = active_network_; + current_ui_config_ = active_config_; + VLOG(1) << "current ui network: " << current_ui_network_ + << ", proxy mode: " << current_ui_config_.mode; + return true; +} + +void ProxyConfigServiceImpl::UISetUseSharedProxies(bool use_shared) { + // Should be called from UI thread. + CheckCurrentlyOnUIThread(); + if (use_shared_proxies_ == use_shared) + return; + use_shared_proxies_ = use_shared; + VLOG(1) << "use_shared_proxies = " << use_shared_proxies_; + if (active_network_.empty()) + return; + Network* network = CrosLibrary::Get()->GetNetworkLibrary()->FindNetworkByPath( + active_network_); + if (!network) { + LOG(ERROR) << "can't find requested network " << active_network_; + return; + } + DetermineConfigFromNetwork(network); } bool ProxyConfigServiceImpl::UISetProxyConfigToDirect() { // Should be called from UI thread. CheckCurrentlyOnUIThread(); - reference_config_.mode = ProxyConfig::MODE_DIRECT; - OnUISetProxyConfig(persist_to_device_); + current_ui_config_.mode = ProxyConfig::MODE_DIRECT; + OnUISetProxyConfig(); return true; } bool ProxyConfigServiceImpl::UISetProxyConfigToAutoDetect() { // Should be called from UI thread. CheckCurrentlyOnUIThread(); - reference_config_.mode = ProxyConfig::MODE_AUTO_DETECT; - OnUISetProxyConfig(persist_to_device_); + current_ui_config_.mode = ProxyConfig::MODE_AUTO_DETECT; + OnUISetProxyConfig(); return true; } bool ProxyConfigServiceImpl::UISetProxyConfigToPACScript(const GURL& pac_url) { // Should be called from UI thread. CheckCurrentlyOnUIThread(); - reference_config_.mode = ProxyConfig::MODE_PAC_SCRIPT; - reference_config_.automatic_proxy.pac_url = pac_url; - OnUISetProxyConfig(persist_to_device_); + current_ui_config_.mode = ProxyConfig::MODE_PAC_SCRIPT; + current_ui_config_.automatic_proxy.pac_url = pac_url; + OnUISetProxyConfig(); return true; } @@ -390,9 +566,9 @@ bool ProxyConfigServiceImpl::UISetProxyConfigToSingleProxy( const net::ProxyServer& server) { // Should be called from UI thread. CheckCurrentlyOnUIThread(); - reference_config_.mode = ProxyConfig::MODE_SINGLE_PROXY; - reference_config_.single_proxy.server = server; - OnUISetProxyConfig(persist_to_device_); + current_ui_config_.mode = ProxyConfig::MODE_SINGLE_PROXY; + current_ui_config_.single_proxy.server = server; + OnUISetProxyConfig(); return true; } @@ -400,14 +576,14 @@ bool ProxyConfigServiceImpl::UISetProxyConfigToProxyPerScheme( const std::string& scheme, const net::ProxyServer& server) { // Should be called from UI thread. CheckCurrentlyOnUIThread(); - ProxyConfig::ManualProxy* proxy = reference_config_.MapSchemeToProxy(scheme); + ProxyConfig::ManualProxy* proxy = current_ui_config_.MapSchemeToProxy(scheme); if (!proxy) { NOTREACHED() << "Cannot set proxy: invalid scheme [" << scheme << "]"; return false; } - reference_config_.mode = ProxyConfig::MODE_PROXY_PER_SCHEME; + current_ui_config_.mode = ProxyConfig::MODE_PROXY_PER_SCHEME; proxy->server = server; - OnUISetProxyConfig(persist_to_device_); + OnUISetProxyConfig(); return true; } @@ -415,15 +591,15 @@ bool ProxyConfigServiceImpl::UISetProxyConfigBypassRules( const net::ProxyBypassRules& bypass_rules) { // Should be called from UI thread. CheckCurrentlyOnUIThread(); - if (reference_config_.mode != ProxyConfig::MODE_SINGLE_PROXY && - reference_config_.mode != ProxyConfig::MODE_PROXY_PER_SCHEME) { + if (current_ui_config_.mode != ProxyConfig::MODE_SINGLE_PROXY && + current_ui_config_.mode != ProxyConfig::MODE_PROXY_PER_SCHEME) { NOTREACHED(); VLOG(1) << "Cannot set bypass rules for proxy mode [" - << reference_config_.mode << "]"; + << current_ui_config_.mode << "]"; return false; } - reference_config_.bypass_rules = bypass_rules; - OnUISetProxyConfig(persist_to_device_); + current_ui_config_.bypass_rules = bypass_rules; + OnUISetProxyConfig(); return true; } @@ -445,70 +621,70 @@ net::ProxyConfigService::ConfigAvailability ProxyConfigServiceImpl::IOGetProxyConfig(net::ProxyConfig* net_config) { // Should be called from IO thread. CheckCurrentlyOnIOThread(); - if (config_availability_ == net::ProxyConfigService::CONFIG_VALID) + if (config_availability_ == net::ProxyConfigService::CONFIG_VALID) { + VLOG(1) << "returning proxy mode=" << cached_config_.mode; cached_config_.ToNetProxyConfig(net_config); - + } return config_availability_; } void ProxyConfigServiceImpl::OnSettingsOpCompleted( SignedSettings::ReturnCode code, - bool value) { - if (SignedSettings::SUCCESS == code) - VLOG(1) << "Stored proxy setting to device"; - else - LOG(WARNING) << "Error storing proxy setting to device"; - store_property_op_ = NULL; - if (persist_to_device_pending_) - PersistConfigToDevice(); -} - -void ProxyConfigServiceImpl::OnSettingsOpCompleted( - SignedSettings::ReturnCode code, std::string value) { retrieve_property_op_ = NULL; - if (SignedSettings::SUCCESS == code) { - VLOG(1) << "Retrieved proxy setting from device, value=[" << value << "]"; - if (reference_config_.Deserialize(value)) { - IOSetProxyConfig(reference_config_, - net::ProxyConfigService::CONFIG_VALID); - return; - } else { - LOG(WARNING) << "Error deserializing device's proxy setting"; - } - } else { + if (code != SignedSettings::SUCCESS) { LOG(WARNING) << "Error retrieving proxy setting from device"; + device_config_.clear(); + return; } + VLOG(1) << "Retrieved proxy setting from device, value=[" << value << "]"; + ProxyConfig device_config; + if (!device_config.DeserializeForDevice(value) || + !device_config.SerializeForNetwork(&device_config_)) { + LOG(WARNING) << "Can't deserialize device setting or serialize for network"; + device_config_.clear(); + return; + } + if (!active_network_.empty()) { + VLOG(1) << "try migrating device config to " << active_network_; + SetProxyConfigForNetwork(active_network_, device_config_, true); + } +} - // Update the configuration state on the IO thread. - IOSetProxyConfig(reference_config_, net::ProxyConfigService::CONFIG_UNSET); +void ProxyConfigServiceImpl::OnNetworkManagerChanged( + NetworkLibrary* network_lib) { + VLOG(1) << "OnNetworkManagerChanged"; + OnActiveNetworkChanged(network_lib, network_lib->active_network()); +} + +void ProxyConfigServiceImpl::OnNetworkChanged(NetworkLibrary* network_lib, + const Network* network) { + if (!network) + return; + VLOG(1) << "OnNetworkChanged: " + << (network->name().empty() ? network->service_path() : + network->name()); + // We only care about active network. + if (network == network_lib->active_network()) + OnActiveNetworkChanged(network_lib, network); } //------------------ ProxyConfigServiceImpl: private methods ------------------- -void ProxyConfigServiceImpl::PersistConfigToDevice() { - DCHECK(!store_property_op_); - persist_to_device_pending_ = false; - std::string value; - if (!reference_config_.Serialize(&value)) { - LOG(WARNING) << "Error serializing proxy config"; +void ProxyConfigServiceImpl::OnUISetProxyConfig() { + if (testing_) { + active_config_ = current_ui_config_; + IOSetProxyConfig(active_config_, net::ProxyConfigService::CONFIG_VALID); return; } - store_property_op_ = SignedSettings::CreateStorePropertyOp( - kSettingProxyEverywhere, value, this); - store_property_op_->Execute(); - VLOG(1) << "Start storing proxy setting to device, value=" << value; -} - -void ProxyConfigServiceImpl::OnUISetProxyConfig(bool persist_to_device) { - IOSetProxyConfig(reference_config_, net::ProxyConfigService::CONFIG_VALID); - if (persist_to_device && CrosLibrary::Get()->EnsureLoaded()) { - if (store_property_op_) { - persist_to_device_pending_ = true; - VLOG(1) << "Pending persisting proxy setting to device"; - } else { - PersistConfigToDevice(); - } + if (current_ui_network_.empty()) + return; + // Update config to flimflam. + std::string value; + if (current_ui_config_.SerializeForNetwork(&value)) { + VLOG(1) << "set proxy (mode=" << current_ui_config_.mode + << ") for " << current_ui_network_; + SetProxyConfigForNetwork(current_ui_network_, value, false); } } @@ -528,7 +704,13 @@ void ProxyConfigServiceImpl::IOSetProxyConfig( } // Now guaranteed to be on the correct thread. - VLOG(1) << "Proxy configuration changed"; + + if (config_availability_ == new_availability && + cached_config_.Equals(new_config)) + return; + + VLOG(1) << "Proxy changed: mode=" << new_config.mode + << ", avail=" << new_availability; cached_config_ = new_config; config_availability_ = new_availability; // Notify observers of new proxy config. @@ -542,6 +724,81 @@ void ProxyConfigServiceImpl::IOSetProxyConfig( OnProxyConfigChanged(net_config, config_availability_)); } +void ProxyConfigServiceImpl::OnActiveNetworkChanged(NetworkLibrary* network_lib, + const Network* active_network) { + std::string new_network; + if (active_network) + new_network = active_network->service_path(); + if (active_network_ == new_network) + return; + + // If there was a previous active network, remove it as observer. + if (!active_network_.empty()) + network_lib->RemoveNetworkObserver(active_network_, this); + + active_network_ = new_network; + + if (active_network_.empty()) { + VLOG(1) << "new active network: empty"; + active_config_ = ProxyConfig(); + IOSetProxyConfig(active_config_, net::ProxyConfigService::CONFIG_UNSET); + return; + } + + VLOG(1) << "new active network: path=" << active_network->service_path() + << ", name=" << active_network->name() + << ", profile=" << active_network->profile_path() + << ", proxy=" << active_network->proxy_config(); + + // Register observer for new network. + network_lib->AddNetworkObserver(active_network_, this); + + // If necessary, migrate config to flimflam. + if (active_network->proxy_config().empty() && !device_config_.empty()) { + VLOG(1) << "try migrating device config to " << active_network_; + SetProxyConfigForNetwork(active_network_, device_config_, true); + } else { + DetermineConfigFromNetwork(active_network); + } +} + +void ProxyConfigServiceImpl::SetProxyConfigForNetwork( + const std::string& network_path, const std::string& value, + bool only_set_if_empty) { + Network* network = CrosLibrary::Get()->GetNetworkLibrary()->FindNetworkByPath( + network_path); + if (!network) { + NOTREACHED() << "can't find requested network " << network_path; + return; + } + if (!only_set_if_empty || network->proxy_config().empty()) { + network->SetProxyConfig(value); + VLOG(1) << "set proxy for " + << (network->name().empty() ? network_path : network->name()) + << ", value=" << value; + if (network_path == active_network_) + DetermineConfigFromNetwork(network); + } +} + +void ProxyConfigServiceImpl::DetermineConfigFromNetwork( + const Network* network) { + active_config_ = ProxyConfig(); // Default is DIRECT mode (i.e. no proxy). + net::ProxyConfigService::ConfigAvailability available = + net::ProxyConfigService::CONFIG_UNSET; + // If network is shared but user doesn't use shared proxies, use direct mode. + if (network->profile_type() == PROFILE_SHARED && !use_shared_proxies_) { + VLOG(1) << "shared network and !use_shared_proxies, using direct"; + available = net::ProxyConfigService::CONFIG_VALID; + } else if (!network->proxy_config().empty() && + active_config_.DeserializeForNetwork(network->proxy_config())) { + // Network is private or shared with user using shared proxies. + VLOG(1) << "using proxy of network, mode=" << active_config_.mode; + available = net::ProxyConfigService::CONFIG_VALID; + } + IOSetProxyConfig(active_config_, available); +} + void ProxyConfigServiceImpl::CheckCurrentlyOnIOThread() { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); } diff --git a/chrome/browser/chromeos/proxy_config_service_impl.h b/chrome/browser/chromeos/proxy_config_service_impl.h index 5511363..0a38273 100644 --- a/chrome/browser/chromeos/proxy_config_service_impl.h +++ b/chrome/browser/chromeos/proxy_config_service_impl.h @@ -14,6 +14,7 @@ #include "base/memory/scoped_ptr.h" #include "base/observer_list.h" #include "base/values.h" +#include "chrome/browser/chromeos/cros/network_library.h" #include "chrome/browser/chromeos/login/signed_settings.h" #include "net/proxy/proxy_config.h" #include "net/proxy/proxy_config_service.h" @@ -26,17 +27,17 @@ namespace chromeos { // - is wrapped by chromeos::ProxyConfigService which implements // net::ProxyConfigService interface by fowarding the methods to this class // - retrieves initial system proxy configuration from cros settings persisted -// on chromeos device -// - provides network stack with latest system proxy configuration for use on -// IO thread -// - provides UI with methods to retrieve and modify system proxy configuration -// on UI thread -// - TODO(kuan): persists proxy configuration settings on chromeos device using -// cros settings +// on chromeos device from chromeos revisions before migration to flimflam, +// - persists proxy setting per network in flimflim +// - provides network stack with latest proxy configuration for currently +// active network for use on IO thread +// - provides UI with methods to retrieve and modify proxy configuration for +// any network (either currently active or non-active) on UI thread class ProxyConfigServiceImpl : public base::RefCountedThreadSafe<ProxyConfigServiceImpl>, - public SignedSettings::Delegate<bool>, - public SignedSettings::Delegate<std::string> { + public SignedSettings::Delegate<std::string>, + public NetworkLibrary::NetworkManagerObserver, + public NetworkLibrary::NetworkObserver { public: // ProxyConfigServiceImpl is created on the UI thread in // chrome/browser/net/proxy_service_factory.cc::CreateProxyConfigService @@ -118,12 +119,23 @@ class ProxyConfigServiceImpl // ManualProxy. Returns NULL if scheme is invalid. ManualProxy* MapSchemeToProxy(const std::string& scheme); - // Serializes config into a DictionaryValue and then into std::string - // persisted as property on device. - bool Serialize(std::string* output); - // Deserializes from property value on device as std::string into a - // DictionaryValue and then into the config. Opposite of Serialize. - bool Deserialize(const std::string& input); + // We've migrated device settings to flimflam, so we only need to + // deserialize previously persisted device settings. + // Deserializes from signed setting on device as std::string into a + // protobuf and then into the config. + bool DeserializeForDevice(const std::string& input); + + // Serializes config into a ProxyConfigDictionary and then std::string + // persisted as string property in flimflam for a network. + bool SerializeForNetwork(std::string* output); + + // Deserializes from string property in flimflam for a network into a + // ProxyConfigDictionary and then into the config. + // Opposite of SerializeForNetwork. + bool DeserializeForNetwork(const std::string& input); + + // Returns true if the given config is equivalent to this config. + bool Equals(const ProxyConfig& other) const; // Creates a textual dump of the configuration. std::string ToString() const; @@ -151,6 +163,13 @@ class ProxyConfigServiceImpl static void EncodeAndAppendProxyServer(const std::string& scheme, const net::ProxyServer& server, std::string* spec); + + // Converts |this| to Dictionary of ProxyConfigDictionary format (which + // is the same format used by prefs). + DictionaryValue* ToPrefProxyConfig(); + + // Converts |this| from Dictionary of ProxyConfigDictionary format. + bool FromPrefProxyConfig(const DictionaryValue* proxy_dict); }; // Usual constructor. @@ -171,16 +190,27 @@ class ProxyConfigServiceImpl // Called from UI thread to retrieve proxy configuration in |config|. void UIGetProxyConfig(ProxyConfig* config); - // Called from UI thread to set flag to persist settings to device. - // Subsequent UISet* methods will use this flag, until UI calls it again with - // a different flag. - void UISetPersistToDevice(bool persist) { - persist_to_device_ = persist; + // Called from UI thread to set service path of network to be displayed or + // edited. Subsequent UISet* methods will use this network, until UI calls + // it again with a different network. + bool UISetCurrentNetwork(const std::string& current_network); + + // Called from UI thread to make the currently active network the one to be + // displayed or edited. Subsequent UISet* methods will use this network. until + // UI calls it again when the active network has changed. + bool UIMakeActiveNetworkCurrent(); + + // Called from UI thread to set/get user preference use_shared_proxies. + void UISetUseSharedProxies(bool use_shared); + bool use_shared_proxies() const { + return use_shared_proxies_; } // Called from UI thread to update proxy configuration for different modes. - // Returns true if config is set properly and config service has proceeded to - // start activating it on network stack and persisting it to device. + // Returns true if config is set properly and persisted to flimflam for the + // current network (set via UISetCurrentNetwork/UIMakeActiveNetworkCurrent). + // If this network is also currently active, config service proceeds to start + // activating it on network stack. // Returns false if config is not set properly, probably because information // is incomplete or invalid; while config service won't proceed to activate or // persist this config, the information is "cached" in the service, so that @@ -198,24 +228,50 @@ class ProxyConfigServiceImpl // Implementation for SignedSettings::Delegate virtual void OnSettingsOpCompleted(SignedSettings::ReturnCode code, std::string value); - virtual void OnSettingsOpCompleted(SignedSettings::ReturnCode code, - bool value); + + // NetworkLibrary::NetworkManagerObserver implementation. + virtual void OnNetworkManagerChanged(NetworkLibrary* cros); + + // NetworkLibrary::NetworkObserver implementation. + virtual void OnNetworkChanged(NetworkLibrary* cros, const Network* network); + +#if defined(UNIT_TEST) + void SetTesting() { + testing_ = true; + active_network_ = "test"; + UIMakeActiveNetworkCurrent(); + use_shared_proxies_ = true; + } +#endif // defined(UNIT_TEST) private: friend class base::RefCountedThreadSafe<ProxyConfigServiceImpl>; - // Persists proxy config to device. - void PersistConfigToDevice(); - - // Called from UI thread from the various UISetProxyConfigTo* - // |update_to_device| is true to persist new proxy config to device. - void OnUISetProxyConfig(bool update_to_device); + // Called from UI thread from the various UISetProxyConfigTo*. + void OnUISetProxyConfig(); // Posted from UI thread to IO thread to carry the new config information. void IOSetProxyConfig( const ProxyConfig& new_config, net::ProxyConfigService::ConfigAvailability new_availability); + // Called from OnNetworkManagerChanged and OnNetworkChanged for currently + // active network, to handle previously active network, new active network, + // and if necessary, migrates device settings to flimflam and/or activates + // proxy setting of new network. + void OnActiveNetworkChanged(NetworkLibrary* cros, + const Network* active_network); + + // Sets proxy config for |network_path| into flimflam and activates setting + // if the network is currently active. + void SetProxyConfigForNetwork(const std::string& network_path, + const std::string& value, + bool only_set_if_empty); + + // Determines and activates proxy config of |network| based on if network is + // shared/private or user is using shared proxies, etc. + void DetermineConfigFromNetwork(const Network* network); + // Checks that method is called on BrowserThread::IO thread. void CheckCurrentlyOnIOThread(); @@ -224,38 +280,50 @@ class ProxyConfigServiceImpl // Data members. + // True if running unit_tests, which will need to specifically exclude + // flimflam logic. + bool testing_; + // True if tasks can be posted, which can only happen if constructor has // completed (NewRunnableMethod cannot be created for a RefCountedThreadBase's // method until the class's ref_count is at least one). bool can_post_task_; - // Availability status of the configuration. + // Availability status of the configuration, initialized on UI thread, but + // afterwards only accessed from IO thread. net::ProxyConfigService::ConfigAvailability config_availability_; - // True if settings are to be persisted to device. - bool persist_to_device_; + // Service path of currently active network (determined via flimflam + // notifications) whose proxy config is taking effect. + std::string active_network_; + // Proxy configuration of |active_network_|, only accessed from UI thread. + ProxyConfig active_config_; - // True if there's a pending operation to store proxy setting to device. - bool persist_to_device_pending_; + // Proxy config retreived from device, in format generated from + // SerializeForNetwork, that can be directly set into flimflam. + std::string device_config_; // Cached proxy configuration, to be converted to net::ProxyConfig and // returned by IOGetProxyConfig. - // Initially populated from the UI thread, but afterwards only accessed from - // the IO thread. + // Initially populated from UI thread, but afterwards only accessed from IO + // thread. ProxyConfig cached_config_; - // Copy of the proxy configuration kept on the UI thread of the last seen - // proxy config, so as to avoid posting a call to SetNewProxyConfig when we - // are called by UI to set new proxy but the config has not actually changed. - ProxyConfig reference_config_; + // Service path of network whose proxy configuration is being displayed or + // edited via UI, separate from |active_network_| which may be same or + // different. + std::string current_ui_network_; + // Proxy configuration of |current_ui_network|. + ProxyConfig current_ui_config_; + + // True if user preference UseSharedProxies is true. + bool use_shared_proxies_; // List of observers for changes in proxy config. ObserverList<net::ProxyConfigService::Observer> observers_; - // Operations to retrieve and store proxy setting from and to device - // respectively. + // Operation to retrieve proxy setting from device. scoped_refptr<SignedSettings> retrieve_property_op_; - scoped_refptr<SignedSettings> store_property_op_; DISALLOW_COPY_AND_ASSIGN(ProxyConfigServiceImpl); }; diff --git a/chrome/browser/chromeos/proxy_config_service_impl_unittest.cc b/chrome/browser/chromeos/proxy_config_service_impl_unittest.cc index b7f303e..11bf46a 100644 --- a/chrome/browser/chromeos/proxy_config_service_impl_unittest.cc +++ b/chrome/browser/chromeos/proxy_config_service_impl_unittest.cc @@ -221,7 +221,7 @@ const struct { NULL, // pac_url "www.google.com", // single_uri NULL, NULL, NULL, NULL, // per-proto - ".google.com, foo.com:99, 1.2.3.4:22, 127.0.0.1/8", // bypass_rules + "*.google.com, *foo.com:99, 1.2.3.4:22, 127.0.0.1/8", // bypass_rules }, // Expected result. @@ -251,6 +251,7 @@ class ProxyConfigServiceImplTest : public PlatformTest { const ProxyConfigServiceImpl::ProxyConfig& init_config) { // Instantiate proxy config service with |init_config|. config_service_ = new ProxyConfigServiceImpl(init_config); + config_service_->SetTesting(); } void SetAutomaticProxy( @@ -305,8 +306,7 @@ class ProxyConfigServiceImplTest : public PlatformTest { break; } if (input.bypass_rules) { - init_config->bypass_rules.ParseFromStringUsingSuffixMatching( - input.bypass_rules); + init_config->bypass_rules.ParseFromString(input.bypass_rules); } } @@ -467,7 +467,7 @@ TEST_F(ProxyConfigServiceImplTest, ModifyFromUI) { config_service()->UISetProxyConfigToSingleProxy( net::ProxyServer::FromURI(input.single_uri, MK_SCHM(HTTP))); if (input.bypass_rules) { - bypass_rules.ParseFromStringUsingSuffixMatching(input.bypass_rules); + bypass_rules.ParseFromString(input.bypass_rules); config_service()->UISetProxyConfigBypassRules(bypass_rules); } break; @@ -489,7 +489,7 @@ TEST_F(ProxyConfigServiceImplTest, ModifyFromUI) { net::ProxyServer::FromURI(input.socks_uri, MK_SCHM(SOCKS5))); } if (input.bypass_rules) { - bypass_rules.ParseFromStringUsingSuffixMatching(input.bypass_rules); + bypass_rules.ParseFromString(input.bypass_rules); config_service()->UISetProxyConfigBypassRules(bypass_rules); } break; @@ -584,7 +584,7 @@ TEST_F(ProxyConfigServiceImplTest, ProxyChangedObserver) { EXPECT_TRUE(io_config.Equals(observer.config())); } -TEST_F(ProxyConfigServiceImplTest, SerializeAndDeserialize) { +TEST_F(ProxyConfigServiceImplTest, SerializeAndDeserializeForNetwork) { for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) { if (!tests[i].is_valid) continue; @@ -597,11 +597,11 @@ TEST_F(ProxyConfigServiceImplTest, SerializeAndDeserialize) { // Serialize source_config into std::string. std::string serialized_value; - EXPECT_TRUE(source_config.Serialize(&serialized_value)); + EXPECT_TRUE(source_config.SerializeForNetwork(&serialized_value)); // Deserialize std:string into target_config. ProxyConfigServiceImpl::ProxyConfig target_config; - EXPECT_TRUE(target_config.Deserialize(serialized_value)); + EXPECT_TRUE(target_config.DeserializeForNetwork(serialized_value)); // Compare the configs after serialization and deserialization. net::ProxyConfig net_src_cfg; diff --git a/chrome/browser/chromeos/proxy_cros_settings_provider.cc b/chrome/browser/chromeos/proxy_cros_settings_provider.cc index 2d35e49..0a8624c 100644 --- a/chrome/browser/chromeos/proxy_cros_settings_provider.cc +++ b/chrome/browser/chromeos/proxy_cros_settings_provider.cc @@ -7,6 +7,7 @@ #include "base/command_line.h" #include "base/string_util.h" #include "chrome/browser/browser_process.h" +#include "chrome/browser/chromeos/cros_settings.h" #include "chrome/browser/ui/browser_list.h" #include "chrome/common/chrome_switches.h" @@ -27,10 +28,45 @@ static const char kProxySocks[] = "cros.session.proxy.socks"; static const char kProxySocksPort[] = "cros.session.proxy.socksport"; static const char kProxyIgnoreList[] = "cros.session.proxy.ignorelist"; +static const char* const kProxySettings[] = { + kProxyPacUrl, + kProxySingleHttp, + kProxySingleHttpPort, + kProxyHttpUrl, + kProxyHttpPort, + kProxyHttpsUrl, + kProxyHttpsPort, + kProxyType, + kProxySingle, + kProxyFtpUrl, + kProxyFtpPort, + kProxySocks, + kProxySocksPort, + kProxyIgnoreList, +}; + //------------------ ProxyCrosSettingsProvider: public methods ----------------- ProxyCrosSettingsProvider::ProxyCrosSettingsProvider() { } +void ProxyCrosSettingsProvider::SetCurrentNetwork(const std::string& network) { + if (!GetConfigService()->UISetCurrentNetwork(network)) + return; + for (size_t i = 0; i < arraysize(kProxySettings); ++i) + CrosSettings::Get()->FireObservers(kProxySettings[i]); +} + +void ProxyCrosSettingsProvider::MakeActiveNetworkCurrent() { + if (!GetConfigService()->UIMakeActiveNetworkCurrent()) + return; + for (size_t i = 0; i < arraysize(kProxySettings); ++i) + CrosSettings::Get()->FireObservers(kProxySettings[i]); +} + +bool ProxyCrosSettingsProvider::IsUsingSharedProxies() const { + return GetConfigService()->use_shared_proxies(); +} + void ProxyCrosSettingsProvider::DoSet(const std::string& path, Value* in_value) { if (!in_value) { @@ -38,9 +74,6 @@ void ProxyCrosSettingsProvider::DoSet(const std::string& path, } chromeos::ProxyConfigServiceImpl* config_service = GetConfigService(); - // Don't persist settings to device for guest session. - config_service->UISetPersistToDevice( - !CommandLine::ForCurrentProcess()->HasSwitch(switches::kGuestSession)); // Retrieve proxy config. chromeos::ProxyConfigServiceImpl::ProxyConfig config; config_service->UIGetProxyConfig(&config); @@ -200,29 +233,31 @@ bool ProxyCrosSettingsProvider::Get(const std::string& path, Value** out_value) const { bool found = false; bool managed = false; - Value* data; + Value* data = NULL; chromeos::ProxyConfigServiceImpl* config_service = GetConfigService(); chromeos::ProxyConfigServiceImpl::ProxyConfig config; config_service->UIGetProxyConfig(&config); if (path == kProxyPacUrl) { - // For auto-detect mode, there should be no pac url. - // For pac-script mode, there should be a pac url that is taking effect. - // For manual modes, the pac url, if previously cached, will be disabled. - if (config.mode != - chromeos::ProxyConfigServiceImpl::ProxyConfig::MODE_AUTO_DETECT && + // Only show pacurl for pac-script mode. + if (config.mode == + chromeos::ProxyConfigServiceImpl::ProxyConfig::MODE_PAC_SCRIPT && config.automatic_proxy.pac_url.is_valid()) { data = Value::CreateStringValue(config.automatic_proxy.pac_url.spec()); - found = true; } + found = true; } else if (path == kProxySingleHttp) { - found = (data = CreateServerHostValue(config.single_proxy)); + data = CreateServerHostValue(config.single_proxy); + found = true; } else if (path == kProxySingleHttpPort) { - found = (data = CreateServerPortValue(config.single_proxy)); + data = CreateServerPortValue(config.single_proxy); + found = true; } else if (path == kProxyHttpUrl) { - found = (data = CreateServerHostValue(config.http_proxy)); + data = CreateServerHostValue(config.http_proxy); + found = true; } else if (path == kProxyHttpsUrl) { - found = (data = CreateServerHostValue(config.https_proxy)); + data = CreateServerHostValue(config.https_proxy); + found = true; } else if (path == kProxyType) { if (config.mode == chromeos::ProxyConfigServiceImpl::ProxyConfig::MODE_AUTO_DETECT || @@ -243,17 +278,23 @@ bool ProxyCrosSettingsProvider::Get(const std::string& path, chromeos::ProxyConfigServiceImpl::ProxyConfig::MODE_SINGLE_PROXY); found = true; } else if (path == kProxyFtpUrl) { - found = (data = CreateServerHostValue(config.ftp_proxy)); + data = CreateServerHostValue(config.ftp_proxy); + found = true; } else if (path == kProxySocks) { - found = (data = CreateServerHostValue(config.socks_proxy)); + data = CreateServerHostValue(config.socks_proxy); + found = true; } else if (path == kProxyHttpPort) { - found = (data = CreateServerPortValue(config.http_proxy)); + data = CreateServerPortValue(config.http_proxy); + found = true; } else if (path == kProxyHttpsPort) { - found = (data = CreateServerPortValue(config.https_proxy)); + data = CreateServerPortValue(config.https_proxy); + found = true; } else if (path == kProxyFtpPort) { - found = (data = CreateServerPortValue(config.ftp_proxy)); + data = CreateServerPortValue(config.ftp_proxy); + found = true; } else if (path == kProxySocksPort) { - found = (data = CreateServerPortValue(config.socks_proxy)); + data = CreateServerPortValue(config.socks_proxy); + found = true; } else if (path == kProxyIgnoreList) { ListValue* list = new ListValue(); net::ProxyBypassRules::RuleList bypass_rules = config.bypass_rules.rules(); @@ -265,6 +306,8 @@ bool ProxyCrosSettingsProvider::Get(const std::string& path, } if (found) { DictionaryValue* dict = new DictionaryValue; + if (!data) + data = Value::CreateStringValue(""); dict->Set("value", data); dict->SetBoolean("managed", managed); *out_value = dict; diff --git a/chrome/browser/chromeos/proxy_cros_settings_provider.h b/chrome/browser/chromeos/proxy_cros_settings_provider.h index 6c42dbd..4d2be6e 100644 --- a/chrome/browser/chromeos/proxy_cros_settings_provider.h +++ b/chrome/browser/chromeos/proxy_cros_settings_provider.h @@ -20,6 +20,17 @@ class ProxyCrosSettingsProvider : public CrosSettingsProvider { virtual bool Get(const std::string& path, Value** out_value) const; virtual bool HandlesSetting(const std::string& path); + // Set the current network whose proxy settings will be displayed and possibly + // edited on. + void SetCurrentNetwork(const std::string& network); + + // Make the active network the current one whose proxy settings will be + // displayed and possibly edited on. + void MakeActiveNetworkCurrent(); + + // Returns true if user has selected to use shared proxies. + bool IsUsingSharedProxies() const; + private: // CrosSettingsProvider implementation. virtual void DoSet(const std::string& path, Value* value); diff --git a/chrome/browser/resources/options/advanced_options.html b/chrome/browser/resources/options/advanced_options.html index 37911d0..64f620d 100644 --- a/chrome/browser/resources/options/advanced_options.html +++ b/chrome/browser/resources/options/advanced_options.html @@ -128,6 +128,7 @@ </if> </div> </section> +<if expr="not pp_ifdef('chromeos')"> <section> <h3 i18n-content="advancedSectionTitleNetwork"></h3> <div> @@ -138,6 +139,7 @@ </div> </div> </section> +</if> <section> <h3 i18n-content="advancedSectionTitleTranslate"></h3> <div class="checkbox"> diff --git a/chrome/browser/resources/options/advanced_options.js b/chrome/browser/resources/options/advanced_options.js index e24b212..07c49f0 100644 --- a/chrome/browser/resources/options/advanced_options.js +++ b/chrome/browser/resources/options/advanced_options.js @@ -92,12 +92,6 @@ var OptionsPage = options.OptionsPage; chrome.send('promptForDownloadAction', [String($('promptForDownload').checked)]); }; - } else { - $('proxiesConfigureButton').onclick = function(event) { - OptionsPage.navigateToPage('proxy'); - chrome.send('coreOptionsUserMetricsAction', - ['Options_ShowProxySettings']); - }; } $('sslCheckRevocation').onclick = function(event) { @@ -218,8 +212,10 @@ var OptionsPage = options.OptionsPage; // Set the enabled state for the proxy settings button. AdvancedOptions.SetupProxySettingsSection = function(disabled, label) { - $('proxiesConfigureButton').disabled = disabled; - $('proxiesLabel').textContent = label; + if (!cr.isChromeOS) { + $('proxiesConfigureButton').disabled = disabled; + $('proxiesLabel').textContent = label; + } }; // Set the checked state for the sslCheckRevocation checkbox. diff --git a/chrome/browser/resources/options/chromeos/internet_detail.html b/chrome/browser/resources/options/chromeos/internet_detail.html index 98d3033..37511ea 100644 --- a/chrome/browser/resources/options/chromeos/internet_detail.html +++ b/chrome/browser/resources/options/chromeos/internet_detail.html @@ -286,6 +286,11 @@ </div> </div> </section> + <section id="change-proxy-section"> + <div> + <button id="change-proxy" i18n-content="changeProxyButton"></button> + </div> + </section> </div> <div id="security-tab" class="subpages-tab-contents cellular-details gsm-only"> diff --git a/chrome/browser/resources/options/chromeos/internet_options.html b/chrome/browser/resources/options/chromeos/internet_options.html index ebbe652..012dd6e 100644 --- a/chrome/browser/resources/options/chromeos/internet_options.html +++ b/chrome/browser/resources/options/chromeos/internet_options.html @@ -18,6 +18,13 @@ <button id="disable-cellular" hidden i18n-content="disableCellular"></button> </div> + <div id="shared-proxies" class="checkbox"> + <label> + <input id="use-shared-proxies" type="checkbox" + pref="settings.use_shared_proxies"> + <span i18n-content="useSharedProxies"></span> + </label> + </div> <div id="internet-owner-only-warning" hidden> <span i18n-content="ownerOnly"></span> <span i18n-content="ownerUserId"></span> diff --git a/chrome/browser/resources/options/chromeos/internet_options.js b/chrome/browser/resources/options/chromeos/internet_options.js index 79e6119..7fb9059 100644 --- a/chrome/browser/resources/options/chromeos/internet_options.js +++ b/chrome/browser/resources/options/chromeos/internet_options.js @@ -82,6 +82,12 @@ cr.define('options', function() { event.target.disabled = true; chrome.send('disableCellular', []); }); + $('change-proxy').addEventListener('click', function(event) { + OptionsPage.closeOverlay(); + OptionsPage.showPageByName('proxy', false); + chrome.send('coreOptionsUserMetricsAction', + ['Options_ShowProxySettings']); + }); $('buyplanDetails').addEventListener('click', function(event) { chrome.send('buyDataPlan', []); OptionsPage.closeOverlay(); @@ -340,6 +346,9 @@ cr.define('options', function() { $('ipTypeDHCPDiv').hidden = !data.showStaticIPConfig; $('ipTypeStaticDiv').hidden = !data.showStaticIPConfig; + // Hide change-proxy-section if proxy is not configurable. + $('change-proxy-section').hidden = !data.proxyConfigurable; + var ipConfigList = $('ipConfigList'); ipConfigList.disabled = $('ipTypeDHCP').checked || !data.showStaticIPConfig; options.internet.IPConfigList.decorate(ipConfigList); diff --git a/chrome/browser/resources/options/chromeos/proxy_options.js b/chrome/browser/resources/options/chromeos/proxy_options.js index fbfc443..537e2f9 100644 --- a/chrome/browser/resources/options/chromeos/proxy_options.js +++ b/chrome/browser/resources/options/chromeos/proxy_options.js @@ -98,7 +98,7 @@ cr.define('options', function() { * @param {Event} e Click Event. */ toggleSingle_: function(e) { - if($('proxyAllProtocols').value) { + if ($('proxyAllProtocols').checked) { $('multiProxy').style.display = 'none'; $('singleProxy').style.display = 'block'; } else { diff --git a/chrome/browser/resources/options/options.js b/chrome/browser/resources/options/options.js index 409eb6d..93fd19e 100644 --- a/chrome/browser/resources/options/options.js +++ b/chrome/browser/resources/options/options.js @@ -155,8 +155,7 @@ function load() { if (cr.isChromeOS) { OptionsPage.register(AccountsOptions.getInstance()); OptionsPage.registerSubPage(ProxyOptions.getInstance(), - AdvancedOptions.getInstance(), - [$('proxiesConfigureButton')]); + InternetOptions.getInstance()); OptionsPage.registerSubPage(ChangePictureOptions.getInstance(), PersonalOptions.getInstance(), [$('change-picture-button')]); @@ -184,8 +183,11 @@ function load() { if (path.length > 1) { // Skip starting slash and remove trailing slash (if any). var pageName = path.slice(1).replace(/\/$/, ''); - // Show page, but don't update history (there's already an entry for it). - OptionsPage.showPageByName(pageName, false); + // Proxy page is now per network and only reachable from internet details. + if (pageName != 'proxy') { + // Show page, but don't update history (there's already an entry for it). + OptionsPage.showPageByName(pageName, false); + } } else { OptionsPage.showDefaultPage(); } diff --git a/chrome/browser/ui/webui/chromeos/proxy_settings_ui.cc b/chrome/browser/ui/webui/chromeos/proxy_settings_ui.cc index 83e96fd..da4e0bd 100644 --- a/chrome/browser/ui/webui/chromeos/proxy_settings_ui.cc +++ b/chrome/browser/ui/webui/chromeos/proxy_settings_ui.cc @@ -7,6 +7,7 @@ #include "base/memory/scoped_ptr.h" #include "base/message_loop.h" #include "base/values.h" +#include "chrome/browser/chromeos/cros_settings.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/webui/chrome_url_data_manager.h" #include "chrome/browser/ui/webui/options/chromeos/core_chromeos_options_handler.h" @@ -67,7 +68,8 @@ void ProxySettingsHTMLSource::StartDataRequest(const std::string& path, namespace chromeos { ProxySettingsUI::ProxySettingsUI(TabContents* contents) - : ChromeWebUI(contents) { + : ChromeWebUI(contents), + proxy_settings_(NULL) { // |localized_strings| will be owned by ProxySettingsHTMLSource. DictionaryValue* localized_strings = new DictionaryValue(); @@ -101,6 +103,18 @@ void ProxySettingsUI::InitializeHandlers() { for (iter = handlers_.begin() + 1; iter != handlers_.end(); ++iter) { (static_cast<OptionsPageUIHandler*>(*iter))->Initialize(); } + if (proxy_settings()) + proxy_settings()->MakeActiveNetworkCurrent(); +} + +chromeos::ProxyCrosSettingsProvider* ProxySettingsUI::proxy_settings() { + if (!proxy_settings_) { + proxy_settings_ = static_cast<chromeos::ProxyCrosSettingsProvider*>( + chromeos::CrosSettings::Get()->GetProvider("cros.session.proxy")); + if (!proxy_settings_) + NOTREACHED() << "Error getting access to proxy cros settings provider"; + } + return proxy_settings_; } } // namespace chromeos diff --git a/chrome/browser/ui/webui/chromeos/proxy_settings_ui.h b/chrome/browser/ui/webui/chromeos/proxy_settings_ui.h index e209c8e..f4268f9 100644 --- a/chrome/browser/ui/webui/chromeos/proxy_settings_ui.h +++ b/chrome/browser/ui/webui/chromeos/proxy_settings_ui.h @@ -6,6 +6,7 @@ #define CHROME_BROWSER_UI_WEBUI_CHROMEOS_PROXY_SETTINGS_UI_H_ #pragma once +#include "chrome/browser/chromeos/proxy_cros_settings_provider.h" #include "chrome/browser/ui/webui/chrome_web_ui.h" #include "chrome/browser/ui/webui/options/options_ui.h" @@ -23,6 +24,10 @@ class ProxySettingsUI : public ChromeWebUI, // Overridden from OptionsPageUIHandlerHost: virtual void InitializeHandlers() OVERRIDE; + chromeos::ProxyCrosSettingsProvider* proxy_settings(); + + chromeos::ProxyCrosSettingsProvider* proxy_settings_; + DISALLOW_COPY_AND_ASSIGN(ProxySettingsUI); }; diff --git a/chrome/browser/ui/webui/options/advanced_options_handler.cc b/chrome/browser/ui/webui/options/advanced_options_handler.cc index 6915bdc..1aefe60 100644 --- a/chrome/browser/ui/webui/options/advanced_options_handler.cc +++ b/chrome/browser/ui/webui/options/advanced_options_handler.cc @@ -83,8 +83,10 @@ void AdvancedOptionsHandler::GetLocalizedValues( IDS_OPTIONS_CERTIFICATES_MANAGE_BUTTON }, { "proxiesLabel", IDS_OPTIONS_PROXIES_LABEL }, +#if !defined(OS_CHROMEOS) { "proxiesConfigureButton", IDS_OPTIONS_PROXIES_CONFIGURE_BUTTON }, +#endif { "safeBrowsingEnableProtection", IDS_OPTIONS_SAFEBROWSING_ENABLEPROTECTION }, { "sslGroupDescription", diff --git a/chrome/browser/ui/webui/options/chromeos/internet_options_handler.cc b/chrome/browser/ui/webui/options/chromeos/internet_options_handler.cc index 2e1e76e..4f7d034 100644 --- a/chrome/browser/ui/webui/options/chromeos/internet_options_handler.cc +++ b/chrome/browser/ui/webui/options/chromeos/internet_options_handler.cc @@ -22,6 +22,7 @@ #include "chrome/browser/browser_process.h" #include "chrome/browser/chromeos/choose_mobile_network_dialog.h" #include "chrome/browser/chromeos/cros/cros_library.h" +#include "chrome/browser/chromeos/cros_settings.h" #include "chrome/browser/chromeos/customization_document.h" #include "chrome/browser/chromeos/login/user_manager.h" #include "chrome/browser/chromeos/options/network_config_view.h" @@ -50,8 +51,8 @@ static const char kOtherNetworksFakePath[] = "?"; InternetOptionsHandler::InternetOptionsHandler() - : chromeos::CrosOptionsPageUIHandler( - new chromeos::UserCrosSettingsProvider) { + : chromeos::CrosOptionsPageUIHandler(NULL), + proxy_settings_(NULL) { registrar_.Add(this, chrome::NOTIFICATION_REQUIRE_PIN_SETTING_CHANGE_ENDED, NotificationService::AllSources()); registrar_.Add(this, chrome::NOTIFICATION_ENTER_PIN_ENDED, @@ -111,6 +112,10 @@ void InternetOptionsHandler::GetLocalizedValues( l10n_util::GetStringUTF16( IDS_OPTIONS_SETTINGS_BUY_PLAN)); + localized_strings->SetString("changeProxyButton", + l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_CHANGE_PROXY_BUTTON)); + localized_strings->SetString("wifiNetworkTabLabel", l10n_util::GetStringUTF16( IDS_OPTIONS_SETTINGS_INTERNET_TAB_WIFI)); @@ -317,6 +322,8 @@ void InternetOptionsHandler::GetLocalizedValues( l10n_util::GetStringFUTF16( IDS_STATUSBAR_NETWORK_DEVICE_DISABLE, l10n_util::GetStringUTF16(IDS_STATUSBAR_NETWORK_DEVICE_CELLULAR))); + localized_strings->SetString("useSharedProxies", + l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_USE_SHARED_PROXIES)); localized_strings->SetString("enableDataRoaming", l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_ENABLE_DATA_ROAMING)); localized_strings->SetString("generalNetworkingTitle", @@ -641,6 +648,11 @@ void InternetOptionsHandler::SetIPConfigCallback(const ListValue* args) { void InternetOptionsHandler::PopulateDictionaryDetails( const chromeos::Network* network) { DCHECK(network); + bool use_shared_proxies = false; + if (proxy_settings()) { + proxy_settings()->SetCurrentNetwork(network->service_path()); + use_shared_proxies = proxy_settings()->IsUsingSharedProxies(); + } DictionaryValue dictionary; std::string hardware_address; chromeos::NetworkIPConfigVector ipconfigs = cros_->GetIPConfigs( @@ -668,6 +680,11 @@ void InternetOptionsHandler::PopulateDictionaryDetails( dictionary.SetBoolean("connecting", network->connecting()); dictionary.SetBoolean("connected", network->connected()); dictionary.SetString("connectionState", network->GetStateString()); + bool remembered = (network->profile_type() != chromeos::PROFILE_NONE); + dictionary.SetBoolean("proxyConfigurable", + (remembered && (network->profile_type() == chromeos::PROFILE_USER || + use_shared_proxies)) || + (type == chromeos::TYPE_ETHERNET && use_shared_proxies)); // Hide the dhcp/static radio if not ethernet or wifi (or if not enabled) bool staticIPConfig = CommandLine::ForCurrentProcess()->HasSwitch( @@ -711,6 +728,16 @@ void InternetOptionsHandler::PopulateDictionaryDetails( "options.InternetOptions.showDetailedInfo", dictionary); } +chromeos::ProxyCrosSettingsProvider* InternetOptionsHandler::proxy_settings() { + if (!proxy_settings_) { + proxy_settings_ = static_cast<chromeos::ProxyCrosSettingsProvider*>( + chromeos::CrosSettings::Get()->GetProvider("cros.session.proxy")); + if (!proxy_settings_) + NOTREACHED() << "Error getting access to proxy cros settings provider"; + } + return proxy_settings_; +} + void InternetOptionsHandler::PopulateWifiDetails( const chromeos::WifiNetwork* wifi, DictionaryValue* dictionary) { @@ -936,6 +963,7 @@ void InternetOptionsHandler::HandleVPNButtonClick( } } } + void InternetOptionsHandler::RefreshCellularPlanCallback( const ListValue* args) { std::string service_path; diff --git a/chrome/browser/ui/webui/options/chromeos/internet_options_handler.h b/chrome/browser/ui/webui/options/chromeos/internet_options_handler.h index cf0fb22..e0355b9 100644 --- a/chrome/browser/ui/webui/options/chromeos/internet_options_handler.h +++ b/chrome/browser/ui/webui/options/chromeos/internet_options_handler.h @@ -8,6 +8,7 @@ #include <string> #include "chrome/browser/chromeos/cros/network_library.h" +#include "chrome/browser/chromeos/proxy_cros_settings_provider.h" #include "chrome/browser/ui/webui/options/chromeos/cros_options_page_ui_handler.h" #include "content/common/notification_registrar.h" #include "ui/gfx/native_widget_types.h" @@ -131,11 +132,15 @@ class InternetOptionsHandler // case of cellular networks, network technology and roaming status. void MonitorNetworks(); + chromeos::ProxyCrosSettingsProvider* proxy_settings(); + // Convenience pointer to netwrok library (will not change). chromeos::NetworkLibrary* cros_; NotificationRegistrar registrar_; + chromeos::ProxyCrosSettingsProvider* proxy_settings_; + DISALLOW_COPY_AND_ASSIGN(InternetOptionsHandler); }; diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc index 2d6d4ab..9e02af0 100644 --- a/chrome/common/pref_names.cc +++ b/chrome/common/pref_names.cc @@ -489,6 +489,10 @@ const char kShow3gPromoNotification[] = // Map of timestamps of the last used file browser tasks. const char kLastUsedFileBrowserHandlers[] = "filebrowser.handler.lastused"; + +// A boolean pref that uses shared proxies. +const char kUseSharedProxies[] = "settings.use_shared_proxies"; + #endif // defined(OS_CHROMEOS) // The disabled messages in IPC logging. diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h index 6dd2468..42ffefa 100644 --- a/chrome/common/pref_names.h +++ b/chrome/common/pref_names.h @@ -168,6 +168,7 @@ extern const char kEnableScreenLock[]; extern const char kShowPlanNotifications[]; extern const char kShow3gPromoNotification[]; extern const char kLastUsedFileBrowserHandlers[]; +extern const char kUseSharedProxies[]; #endif extern const char kIpcDisabledMessages[]; extern const char kShowHomeButton[]; |