summaryrefslogtreecommitdiffstats
path: root/chrome/browser/chromeos
diff options
context:
space:
mode:
Diffstat (limited to 'chrome/browser/chromeos')
-rw-r--r--chrome/browser/chromeos/cros/cros_library.cc4
-rw-r--r--chrome/browser/chromeos/cros/cros_library.h3
-rw-r--r--chrome/browser/chromeos/proxy_config_service_impl.cc396
-rw-r--r--chrome/browser/chromeos/proxy_config_service_impl.h87
-rw-r--r--chrome/browser/chromeos/proxy_config_service_impl_unittest.cc286
-rw-r--r--chrome/browser/chromeos/status/clock_menu_button_browsertest.cc5
6 files changed, 590 insertions, 191 deletions
diff --git a/chrome/browser/chromeos/cros/cros_library.cc b/chrome/browser/chromeos/cros/cros_library.cc
index a408c07..9065304 100644
--- a/chrome/browser/chromeos/cros/cros_library.cc
+++ b/chrome/browser/chromeos/cros/cros_library.cc
@@ -121,6 +121,10 @@ void CrosLibrary::TestApi::SetUseStubImpl() {
library_->use_stub_impl_ = true;
}
+void CrosLibrary::TestApi::ResetUseStubImpl() {
+ library_->use_stub_impl_ = false;
+}
+
void CrosLibrary::TestApi::SetLibraryLoader(LibraryLoader* loader, bool own) {
if (library_->library_loader_ == loader)
return;
diff --git a/chrome/browser/chromeos/cros/cros_library.h b/chrome/browser/chromeos/cros/cros_library.h
index d73b223..6695acf 100644
--- a/chrome/browser/chromeos/cros/cros_library.h
+++ b/chrome/browser/chromeos/cros/cros_library.h
@@ -41,6 +41,9 @@ class CrosLibrary {
// Use the stub implementations of the library. This is mainly for
// running the chromeos build of chrome on the desktop.
void SetUseStubImpl();
+ // Reset the stub implementations of the library, called after
+ // SetUseStubImp is called.
+ void ResetUseStubImpl();
// Passing true for own for these setters will cause them to be deleted
// when the CrosLibrary is deleted (or other mocks are set).
// Setter for LibraryLoader.
diff --git a/chrome/browser/chromeos/proxy_config_service_impl.cc b/chrome/browser/chromeos/proxy_config_service_impl.cc
index 6478314..a7fa754 100644
--- a/chrome/browser/chromeos/proxy_config_service_impl.cc
+++ b/chrome/browser/chromeos/proxy_config_service_impl.cc
@@ -9,8 +9,9 @@
#include "base/logging.h"
#include "base/string_util.h"
#include "base/task.h"
-#include "base/values.h"
#include "chrome/browser/chrome_thread.h"
+#include "chrome/browser/chromeos/cros/cros_library.h"
+#include "chrome/common/json_value_serializer.h"
namespace chromeos {
@@ -91,9 +92,27 @@ std::string ProxyConfigToString(
return stream.str();
}
+// Name of signed setting persisted on device, writeable only by owner.
+const char* kSettingProxyEverywhere = "cros.proxy.everywhere";
+
+// Names used for dictionary values to serialize chromeos::ProxyConfig.
+const char* kMode = "mode";
+const char* kSource = "src";
+const char* kAutomaticProxy = "auto";
+const char* kSingleProxy = "single";
+const char* kHttpProxy = "http";
+const char* kHttpsProxy = "https";
+const char* kFtpProxy = "ftp";
+const char* kSocksProxy = "socks";
+const char* kPACUrl = "pac";
+const char* kServer = "server";
+const char* kBypassRules = "bypass_rules";
+const char* kRulesNum = "num";
+const char* kRulesList = "list";
+
} // namespace
-//-------------- ProxyConfigServiceImpl::ProxyConfig methods -------------------
+//---------- ProxyConfigServiceImpl::ProxyConfig::Setting methods --------------
bool ProxyConfigServiceImpl::ProxyConfig::Setting::CanBeWrittenByUser(
bool user_is_owner) {
@@ -102,7 +121,67 @@ bool ProxyConfigServiceImpl::ProxyConfig::Setting::CanBeWrittenByUser(
return user_is_owner && source != ProxyConfig::SOURCE_POLICY;
}
-void ProxyConfigServiceImpl::ProxyConfig::ConvertToNetProxyConfig(
+DictionaryValue* ProxyConfigServiceImpl::ProxyConfig::Setting::Encode() const {
+ DictionaryValue* dict = new DictionaryValue;
+ dict->SetInteger(kSource, source);
+ return dict;
+}
+
+bool ProxyConfigServiceImpl::ProxyConfig::Setting::Decode(
+ DictionaryValue* dict) {
+ int int_source;
+ if (!dict->GetInteger(kSource, &int_source))
+ return false;
+ source = static_cast<Source>(int_source);
+ return true;
+}
+
+//------- ProxyConfigServiceImpl::ProxyConfig::AutomaticProxy methods ----------
+
+DictionaryValue*
+ ProxyConfigServiceImpl::ProxyConfig::AutomaticProxy::Encode() const {
+ DictionaryValue* dict = Setting::Encode();
+ if (!pac_url.is_empty())
+ dict->SetString(kPACUrl, pac_url.spec());
+ return dict;
+}
+
+bool ProxyConfigServiceImpl::ProxyConfig::AutomaticProxy::Decode(
+ DictionaryValue* dict, Mode mode) {
+ if (!Setting::Decode(dict))
+ return false;
+ if (mode == MODE_PAC_SCRIPT) {
+ std::string value;
+ if (!dict->GetString(kPACUrl, &value))
+ return false;
+ pac_url = GURL(value);
+ }
+ return true;
+}
+
+//--------- ProxyConfigServiceImpl::ProxyConfig::ManualProxy methods -----------
+
+DictionaryValue*
+ ProxyConfigServiceImpl::ProxyConfig::ManualProxy::Encode() const {
+ DictionaryValue* dict = Setting::Encode();
+ dict->SetString(kServer, server.ToURI());
+ return dict;
+}
+
+bool ProxyConfigServiceImpl::ProxyConfig::ManualProxy::Decode(
+ DictionaryValue* dict, net::ProxyServer::Scheme scheme) {
+ if (!Setting::Decode(dict))
+ return false;
+ std::string value;
+ if (!dict->GetString(kServer, &value))
+ return false;
+ server = net::ProxyServer::FromURI(value, scheme);
+ return true;
+}
+
+//----------- ProxyConfigServiceImpl::ProxyConfig: public methods --------------
+
+void ProxyConfigServiceImpl::ProxyConfig::ToNetProxyConfig(
net::ProxyConfig* net_config) {
switch (mode) {
case MODE_DIRECT:
@@ -138,28 +217,165 @@ void ProxyConfigServiceImpl::ProxyConfig::ConvertToNetProxyConfig(
}
}
+bool ProxyConfigServiceImpl::ProxyConfig::Serialize(std::string* output) {
+ scoped_ptr<DictionaryValue> dict(new DictionaryValue);
+ dict->SetInteger(kMode, mode);
+ DictionaryValue* proxy_dict;
+ switch (mode) {
+ case MODE_DIRECT:
+ case MODE_AUTO_DETECT:
+ case MODE_PAC_SCRIPT:
+ proxy_dict = automatic_proxy.Encode();
+ dict->Set(kAutomaticProxy, proxy_dict);
+ break;
+ case MODE_SINGLE_PROXY:
+ EncodeManualProxy(single_proxy, dict.get(), kSingleProxy);
+ break;
+ case MODE_PROXY_PER_SCHEME:
+ EncodeManualProxy(http_proxy, dict.get(), kHttpProxy);
+ EncodeManualProxy(https_proxy, dict.get(), kHttpsProxy);
+ EncodeManualProxy(ftp_proxy, dict.get(), kFtpProxy);
+ EncodeManualProxy(socks_proxy, dict.get(), kSocksProxy);
+ break;
+ default:
+ NOTREACHED() << "Unrecognized proxy config mode";
+ break;
+ }
+ net::ProxyBypassRules::RuleList rules = bypass_rules.rules();
+ if (!rules.empty()) {
+ DictionaryValue* bypass_dict = new DictionaryValue;
+ bypass_dict->SetInteger(kRulesNum, rules.size());
+ ListValue* list = new ListValue;
+ for (size_t i = 0; i < rules.size(); ++i) {
+ list->Append(Value::CreateStringValue(rules[i]->ToString()));
+ }
+ bypass_dict->Set(kRulesList, list);
+ dict->Set(kBypassRules, bypass_dict);
+ }
+ JSONStringValueSerializer serializer(output);
+ return serializer.Serialize(*dict.get());
+}
+
+bool ProxyConfigServiceImpl::ProxyConfig::Deserialize(
+ 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* dict = static_cast<DictionaryValue*>(value.get());
+ int int_mode;
+ if (!dict->GetInteger(kMode, &int_mode))
+ return false;
+ mode = static_cast<Mode>(int_mode);
+ DictionaryValue* proxy_dict = NULL;
+ switch (mode) {
+ case MODE_DIRECT:
+ case MODE_AUTO_DETECT:
+ case MODE_PAC_SCRIPT:
+ if (!dict->GetDictionary(kAutomaticProxy, &proxy_dict) ||
+ !automatic_proxy.Decode(proxy_dict, mode))
+ return false;
+ break;
+ case MODE_SINGLE_PROXY:
+ if (!DecodeManualProxy(dict, kSingleProxy, false,
+ net::ProxyServer::SCHEME_HTTP, &single_proxy))
+ return false;
+ break;
+ case MODE_PROXY_PER_SCHEME:
+ if (!DecodeManualProxy(dict, kHttpProxy, true,
+ net::ProxyServer::SCHEME_HTTP, &http_proxy))
+ return false;
+ if (!DecodeManualProxy(dict, kHttpsProxy, true,
+ net::ProxyServer::SCHEME_HTTPS, &https_proxy))
+ return false;
+ if (!DecodeManualProxy(dict, kFtpProxy, true,
+ net::ProxyServer::SCHEME_HTTP, &ftp_proxy))
+ return false;
+ if (!DecodeManualProxy(dict, kSocksProxy, true,
+ net::ProxyServer::SCHEME_SOCKS4, &socks_proxy))
+ return false;
+ // Make sure we have valid server for at least one of the protocols.
+ if (!(http_proxy.server.is_valid() || https_proxy.server.is_valid() ||
+ ftp_proxy.server.is_valid() || socks_proxy.server.is_valid()))
+ return false;
+ break;
+ default:
+ NOTREACHED() << "Unrecognized proxy config mode";
+ break;
+ }
+ DictionaryValue* bypass_dict = NULL;
+ if (dict->GetDictionary(kBypassRules, &bypass_dict)) {
+ int num_rules = 0;
+ if (bypass_dict->GetInteger(kRulesNum, &num_rules) && num_rules > 0) {
+ ListValue* list;
+ if (!bypass_dict->GetList(kRulesList, &list))
+ return false;
+ for (size_t i = 0; i < list->GetSize(); ++i) {
+ std::string rule;
+ if (!list->GetString(i, &rule))
+ return false;
+ bypass_rules.AddRuleFromString(rule);
+ }
+ }
+ }
+ return true;
+}
+
std::string ProxyConfigServiceImpl::ProxyConfig::ToString() const {
return ProxyConfigToString(*this);
}
+//----------- ProxyConfigServiceImpl::ProxyConfig: private methods -------------
+
+void ProxyConfigServiceImpl::ProxyConfig::EncodeManualProxy(
+ const ManualProxy& manual_proxy, DictionaryValue* dict,
+ const char* key_name) {
+ if (!manual_proxy.server.is_valid())
+ return;
+ DictionaryValue* proxy_dict = manual_proxy.Encode();
+ dict->Set(key_name, proxy_dict);
+}
+
+bool ProxyConfigServiceImpl::ProxyConfig::DecodeManualProxy(
+ DictionaryValue* dict, const char* key_name, bool ok_if_absent,
+ net::ProxyServer::Scheme scheme, ManualProxy* manual_proxy) {
+ DictionaryValue* proxy_dict;
+ if (!dict->GetDictionary(key_name, &proxy_dict))
+ return ok_if_absent;
+ return manual_proxy->Decode(proxy_dict, scheme);
+}
+
//------------------- ProxyConfigServiceImpl: public methods -------------------
-ProxyConfigServiceImpl::ProxyConfigServiceImpl() {
- // Fetch and cache proxy config from cros settings persisted on device.
+ProxyConfigServiceImpl::ProxyConfigServiceImpl()
+ : can_post_task_(false),
+ has_config_(false),
+ persist_to_device_pending_(false) {
+ // Start async fetch of proxy config from settings persisted on device.
// TODO(kuan): retrieve config from policy and owner and merge them
- // for now, hardcode it as AUTO_DETECT and it'll pick up the PAC script set in
- // chromeos environment.
- cached_config_.mode = ProxyConfig::MODE_AUTO_DETECT;
- cached_config_.automatic_proxy.source = ProxyConfig::SOURCE_OWNER;
-
- // Update the thread-private copy in |reference_config_| as well.
- reference_config_ = cached_config_;
+ bool use_default = true;
+ if (CrosLibrary::Get()->EnsureLoaded()) {
+ retrieve_property_op_ = SignedSettings::CreateRetrievePropertyOp(
+ kSettingProxyEverywhere, this);
+ if (retrieve_property_op_ && retrieve_property_op_->Execute()) {
+ LOG(INFO) << "Start retrieving proxy setting from device";
+ use_default = false;
+ } else {
+ LOG(INFO) << "Fail to retrieve proxy setting from device";
+ }
+ }
+ if (use_default)
+ InitConfigToDefault(false);
+ can_post_task_ = true;
}
-ProxyConfigServiceImpl::ProxyConfigServiceImpl(const ProxyConfig& init_config) {
- cached_config_ = init_config;
- // Update the thread-private copy in |reference_config_| as well.
- reference_config_ = cached_config_;
+ProxyConfigServiceImpl::ProxyConfigServiceImpl(const ProxyConfig& init_config)
+ : can_post_task_(true),
+ has_config_(true),
+ persist_to_device_pending_(false) {
+ reference_config_ = init_config;
+ // Update the IO-accessible copy in |cached_config_| as well.
+ cached_config_ = reference_config_;
}
ProxyConfigServiceImpl::~ProxyConfigServiceImpl() {
@@ -172,38 +388,50 @@ void ProxyConfigServiceImpl::UIGetProxyConfig(ProxyConfig* config) {
*config = reference_config_;
}
-void ProxyConfigServiceImpl::UISetProxyConfigToDirect() {
+bool ProxyConfigServiceImpl::UISetProxyConfigToDirect() {
// Should be called from UI thread.
CheckCurrentlyOnUIThread();
reference_config_.mode = ProxyConfig::MODE_DIRECT;
- OnUISetProxyConfig();
+ OnUISetProxyConfig(true);
+ return true;
}
-void ProxyConfigServiceImpl::UISetProxyConfigToAutoDetect() {
+bool ProxyConfigServiceImpl::UISetProxyConfigToAutoDetect() {
// Should be called from UI thread.
CheckCurrentlyOnUIThread();
reference_config_.mode = ProxyConfig::MODE_AUTO_DETECT;
- OnUISetProxyConfig();
+ OnUISetProxyConfig(true);
+ return true;
}
-void ProxyConfigServiceImpl::UISetProxyConfigToPACScript(const GURL& url) {
+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 = url;
- OnUISetProxyConfig();
+ reference_config_.automatic_proxy.pac_url = pac_url;
+ if (pac_url.is_valid()) {
+ OnUISetProxyConfig(true);
+ return true;
+ }
+ LOG(INFO) << "Cannot set proxy: invalid pac url";
+ return false;
}
-void ProxyConfigServiceImpl::UISetProxyConfigToSingleProxy(
+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();
+ if (server.is_valid()) {
+ OnUISetProxyConfig(true);
+ return true;
+ }
+ LOG(INFO) << "Cannot set proxy: invalid single server";
+ return false;
}
-void ProxyConfigServiceImpl::UISetProxyConfigToProxyPerScheme(
+bool ProxyConfigServiceImpl::UISetProxyConfigToProxyPerScheme(
const std::string& scheme, const net::ProxyServer& server) {
// Should be called from UI thread.
CheckCurrentlyOnUIThread();
@@ -216,26 +444,35 @@ void ProxyConfigServiceImpl::UISetProxyConfigToProxyPerScheme(
proxy = &reference_config_.ftp_proxy;
else if (scheme == "socks")
proxy = &reference_config_.socks_proxy;
- else
- NOTREACHED() << "Unrecognized scheme for setting proxy config";
- if (proxy) {
- reference_config_.mode = ProxyConfig::MODE_PROXY_PER_SCHEME;
- proxy->server = server;
- OnUISetProxyConfig();
+ if (!proxy) {
+ NOTREACHED() << "Cannot set proxy: invalid scheme [" << scheme << "]";
+ return false;
+ }
+ reference_config_.mode = ProxyConfig::MODE_PROXY_PER_SCHEME;
+ proxy->server = server;
+ if (server.is_valid()) {
+ OnUISetProxyConfig(true);
+ return true;
}
+ LOG(INFO) << "Cannot set proxy: invalid " << scheme << " server";
+ return false;
}
-void ProxyConfigServiceImpl::UISetProxyConfigBypassRules(
+bool ProxyConfigServiceImpl::UISetProxyConfigBypassRules(
const net::ProxyBypassRules& bypass_rules) {
// Should be called from UI thread.
CheckCurrentlyOnUIThread();
DCHECK(reference_config_.mode == ProxyConfig::MODE_SINGLE_PROXY ||
reference_config_.mode == ProxyConfig::MODE_PROXY_PER_SCHEME);
- if (reference_config_.mode == ProxyConfig::MODE_SINGLE_PROXY ||
- reference_config_.mode == ProxyConfig::MODE_PROXY_PER_SCHEME) {
- reference_config_.bypass_rules = bypass_rules;
- OnUISetProxyConfig();
+ if (reference_config_.mode != ProxyConfig::MODE_SINGLE_PROXY &&
+ reference_config_.mode != ProxyConfig::MODE_PROXY_PER_SCHEME) {
+ LOG(INFO) << "Cannot set bypass rules for proxy mode ["
+ << reference_config_.mode << "]";
+ return false;
}
+ reference_config_.bypass_rules = bypass_rules;
+ OnUISetProxyConfig(true);
+ return true;
}
void ProxyConfigServiceImpl::AddObserver(
@@ -255,21 +492,76 @@ void ProxyConfigServiceImpl::RemoveObserver(
bool ProxyConfigServiceImpl::IOGetProxyConfig(net::ProxyConfig* net_config) {
// Should be called from IO thread.
CheckCurrentlyOnIOThread();
+ if (has_config_) {
+ // Simply return the last cached proxy configuration.
+ cached_config_.ToNetProxyConfig(net_config);
+ return true;
+ }
+ return false;
+}
- // Simply return the last cached proxy configuration.
- cached_config_.ConvertToNetProxyConfig(net_config);
+void ProxyConfigServiceImpl::OnSettingsOpSucceeded(bool value) {
+ LOG(INFO) << "Stored proxy setting to device";
+ store_property_op_ = NULL;
+ if (persist_to_device_pending_)
+ PersistConfigToDevice();
+}
- // We return true to indicate that *config was filled in. It is always
- // going to be available since we initialized eagerly on the UI thread.
- // TODO(kuan): do lazy initialization instead, so we no longer need
- // to construct ProxyConfigServiceImpl on the UI thread.
- // In which case, we may return false here.
- return true;
+void ProxyConfigServiceImpl::OnSettingsOpSucceeded(std::string value) {
+ LOG(INFO) << "Retrieved proxy setting from device, value=[" << value << "]";
+ if (reference_config_.Deserialize(value)) {
+ OnUISetProxyConfig(false);
+ } else {
+ LOG(WARNING) << "Error deserializing device's proxy setting";
+ InitConfigToDefault(true);
+ }
+ retrieve_property_op_ = NULL;
+}
+
+void ProxyConfigServiceImpl::OnSettingsOpFailed() {
+ if (retrieve_property_op_) {
+ LOG(WARNING) << "Error retrieving proxy setting from device";
+ InitConfigToDefault(true);
+ retrieve_property_op_ = NULL;
+ } else {
+ LOG(WARNING) << "Error storing proxy setting to device";
+ store_property_op_ = NULL;
+ if (persist_to_device_pending_)
+ PersistConfigToDevice();
+ }
}
//------------------ ProxyConfigServiceImpl: private methods -------------------
-void ProxyConfigServiceImpl::OnUISetProxyConfig() {
+void ProxyConfigServiceImpl::InitConfigToDefault(bool post_to_io_thread) {
+ LOG(INFO) << "Using default proxy config: auto-detect";
+ reference_config_.mode = ProxyConfig::MODE_AUTO_DETECT;
+ reference_config_.automatic_proxy.source = ProxyConfig::SOURCE_OWNER;
+ if (post_to_io_thread && can_post_task_) {
+ OnUISetProxyConfig(false);
+ } else {
+ // Update the IO-accessible copy in |cached_config_| as well.
+ cached_config_ = reference_config_;
+ has_config_ = true;
+ }
+}
+
+void ProxyConfigServiceImpl::PersistConfigToDevice() {
+ DCHECK(!store_property_op_);
+ persist_to_device_pending_ = false;
+ std::string value;
+ if (!reference_config_.Serialize(&value)) {
+ LOG(INFO) << "Error serializing proxy config";
+ return;
+ }
+ store_property_op_ = SignedSettings::CreateStorePropertyOp(
+ kSettingProxyEverywhere, value, this);
+ bool rc = store_property_op_->Execute();
+ LOG(INFO) << "Start storing proxy setting to device, value=" << value
+ << ", rc=" << rc;
+}
+
+void ProxyConfigServiceImpl::OnUISetProxyConfig(bool persist_to_device) {
// Posts a task to IO thread with the new config, so it can update
// |cached_config_|.
Task* task = NewRunnableMethod(this,
@@ -279,7 +571,14 @@ void ProxyConfigServiceImpl::OnUISetProxyConfig() {
delete task;
}
- // TODO(kuan): write new config out to cros settings for persistence.
+ if (persist_to_device && CrosLibrary::Get()->EnsureLoaded()) {
+ if (store_property_op_) {
+ persist_to_device_pending_ = true;
+ LOG(INFO) << "Pending persisting proxy setting to device";
+ } else {
+ PersistConfigToDevice();
+ }
+ }
}
void ProxyConfigServiceImpl::CheckCurrentlyOnIOThread() {
@@ -294,10 +593,11 @@ void ProxyConfigServiceImpl::IOSetProxyConfig(const ProxyConfig& new_config) {
// This is called on the IO thread (posted from UI thread).
CheckCurrentlyOnIOThread();
LOG(INFO) << "Proxy configuration changed";
+ has_config_ = true;
cached_config_ = new_config;
// Notify observers of new proxy config.
net::ProxyConfig net_config;
- cached_config_.ConvertToNetProxyConfig(&net_config);
+ cached_config_.ToNetProxyConfig(&net_config);
FOR_EACH_OBSERVER(net::ProxyConfigService::Observer, observers_,
OnProxyConfigChanged(net_config));
}
diff --git a/chrome/browser/chromeos/proxy_config_service_impl.h b/chrome/browser/chromeos/proxy_config_service_impl.h
index c22f1a5..e8e184d 100644
--- a/chrome/browser/chromeos/proxy_config_service_impl.h
+++ b/chrome/browser/chromeos/proxy_config_service_impl.h
@@ -13,6 +13,8 @@
#include "base/observer_list.h"
#include "base/ref_counted.h"
#include "base/scoped_ptr.h"
+#include "base/values.h"
+#include "chrome/browser/chromeos/login/signed_settings.h"
#include "net/proxy/proxy_config.h"
#include "net/proxy/proxy_config_service.h"
#include "net/proxy/proxy_server.h"
@@ -32,7 +34,9 @@ namespace chromeos {
// - TODO(kuan): persists proxy configuration settings on chromeos device using
// cros settings
class ProxyConfigServiceImpl
- : public base::RefCountedThreadSafe<ProxyConfigServiceImpl> {
+ : public base::RefCountedThreadSafe<ProxyConfigServiceImpl>,
+ public SignedSettings::Delegate<bool>,
+ public SignedSettings::Delegate<std::string> {
public:
// ProxyConfigServiceImpl is created on the UI thread in
// chrome/browser/net/chrome_url_request_context.cc::CreateProxyConfigService
@@ -84,25 +88,40 @@ class ProxyConfigServiceImpl
struct Setting {
Setting() : source(SOURCE_NONE) {}
+ bool CanBeWrittenByUser(bool user_is_owner);
+ virtual DictionaryValue* Encode() const;
+ bool Decode(DictionaryValue* dict);
Source source;
- bool CanBeWrittenByUser(bool user_is_owner);
};
// Proxy setting for mode = direct or auto-detect or using pac script.
struct AutomaticProxy : public Setting {
+ virtual DictionaryValue* Encode() const;
+ bool Decode(DictionaryValue* dict, Mode mode);
+
GURL pac_url; // Set if proxy is using pac script.
};
// Proxy setting for mode = single-proxy or proxy-per-scheme.
struct ManualProxy : public Setting {
+ virtual DictionaryValue* Encode() const;
+ bool Decode(DictionaryValue* dict, net::ProxyServer::Scheme scheme);
+
net::ProxyServer server;
};
ProxyConfig() : mode(MODE_DIRECT) {}
// Converts |this| to net::ProxyConfig.
- void ConvertToNetProxyConfig(net::ProxyConfig* net_config);
+ void ToNetProxyConfig(net::ProxyConfig* net_config);
+
+ // 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);
// Creates a textual dump of the configuration.
std::string ToString() const;
@@ -124,6 +143,17 @@ class ProxyConfigServiceImpl
// Exceptions for when not to use a proxy.
net::ProxyBypassRules bypass_rules;
+
+ private:
+ // Encodes |manual_proxy| and adds it as value into |key_name| of |dict|.
+ void EncodeManualProxy(const ManualProxy& manual_proxy,
+ DictionaryValue* dict, const char* key_name);
+ // Decodes value of |key_name| in |dict| into |manual_proxy| with |scheme|;
+ // if |ok_if_absent| is true, function returns true if |key_name| doesn't
+ // exist in |dict|.
+ bool DecodeManualProxy(DictionaryValue* dict, const char* key_name,
+ bool ok_if_absent, net::ProxyServer::Scheme scheme,
+ ManualProxy* manual_proxy);
};
// Usual constructor.
@@ -144,20 +174,40 @@ class ProxyConfigServiceImpl
void UIGetProxyConfig(ProxyConfig* config);
// Called from UI thread to update proxy configuration for different modes.
- void UISetProxyConfigToDirect();
- void UISetProxyConfigToAutoDetect();
- void UISetProxyConfigToPACScript(const GURL& url);
- void UISetProxyConfigToSingleProxy(const net::ProxyServer& server);
- void UISetProxyConfigToProxyPerScheme(const std::string& scheme,
+ // 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 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
+ // the next UIGetProxyConfig call will return this latest information.
+ bool UISetProxyConfigToDirect();
+ bool UISetProxyConfigToAutoDetect();
+ bool UISetProxyConfigToPACScript(const GURL& pac_url);
+ bool UISetProxyConfigToSingleProxy(const net::ProxyServer& server);
+ bool UISetProxyConfigToProxyPerScheme(const std::string& scheme,
const net::ProxyServer& server);
// Only valid for MODE_SINGLE_PROXY or MODE_PROXY_PER_SCHEME.
- void UISetProxyConfigBypassRules(const net::ProxyBypassRules& bypass_rules);
+ bool UISetProxyConfigBypassRules(const net::ProxyBypassRules& bypass_rules);
+
+ // Implementation for SignedSettings::Delegate
+ virtual void OnSettingsOpSucceeded(bool value);
+ virtual void OnSettingsOpSucceeded(std::string value);
+ virtual void OnSettingsOpFailed();
private:
friend class base::RefCountedThreadSafe<ProxyConfigServiceImpl>;
+ // Init proxy to default config, i.e. AutoDetect.
+ // If |post_to_io_thread| is true, a task will be posted to IO thread to
+ // update |cached_config|.
+ void InitConfigToDefault(bool post_to_io_thread);
+
+ // Persists proxy config to device.
+ void PersistConfigToDevice();
+
// Called from UI thread from the various UISetProxyConfigTo*
- void OnUISetProxyConfig();
+ // |update_to_device| is true to persist new proxy config to device.
+ void OnUISetProxyConfig(bool update_to_device);
// Posted from UI thread to IO thread to carry the new config information.
void IOSetProxyConfig(const ProxyConfig& new_config);
@@ -170,6 +220,17 @@ class ProxyConfigServiceImpl
// Data members.
+ // 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_;
+
+ // True if config has been fetched from device or initialized properly.
+ bool has_config_;
+
+ // True if there's a pending operation to store proxy setting to device.
+ bool persist_to_device_pending_;
+
// Cached proxy configuration, to be converted to net::ProxyConfig and
// returned by IOGetProxyConfig.
// Initially populated from the UI thread, but afterwards only accessed from
@@ -181,8 +242,14 @@ class ProxyConfigServiceImpl
// are called by UI to set new proxy but the config has not actually changed.
ProxyConfig reference_config_;
+ // 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.
+ 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 8c6e5ed..c68e42e 100644
--- a/chrome/browser/chromeos/proxy_config_service_impl_unittest.cc
+++ b/chrome/browser/chromeos/proxy_config_service_impl_unittest.cc
@@ -13,10 +13,15 @@
#include "base/string_util.h"
#include "base/stringprintf.h"
#include "chrome/browser/chrome_thread.h"
+#include "chrome/browser/chromeos/cros/cros_library.h"
#include "net/proxy/proxy_config_service_common_unittest.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/platform_test.h"
+#if !defined(NDEBUG)
+#include "chrome/common/json_value_serializer.h"
+#endif // !defined(NDEBUG)
+
namespace chromeos {
namespace {
@@ -38,12 +43,15 @@ struct Input { // Fields of chromeos::ProxyConfigServiceImpl::ProxyConfig.
// Shortcuts to declare enums within chromeos's ProxyConfig.
#define MK_MODE(mode) ProxyConfigServiceImpl::ProxyConfig::MODE_##mode
#define MK_SRC(src) ProxyConfigServiceImpl::ProxyConfig::SOURCE_##src
+#define MK_SCHM(scheme) net::ProxyServer::SCHEME_##scheme
// Inspired from net/proxy/proxy_config_service_linux_unittest.cc.
const struct {
// Short description to identify the test
std::string description;
+ bool is_valid;
+
Input input;
// Expected outputs from fields of net::ProxyConfig (via IO).
@@ -53,6 +61,8 @@ const struct {
} tests[] = {
{
TEST_DESC("No proxying"),
+ true, // is_valid
+
{ // Input.
MK_MODE(DIRECT), // mode
},
@@ -65,6 +75,8 @@ const struct {
{
TEST_DESC("Auto detect"),
+ true, // is_valid
+
{ // Input.
MK_MODE(AUTO_DETECT), // mode
},
@@ -77,6 +89,8 @@ const struct {
{
TEST_DESC("Valid PAC URL"),
+ true, // is_valid
+
{ // Input.
MK_MODE(PAC_SCRIPT), // mode
"http://wpad/wpad.dat", // pac_url
@@ -90,6 +104,8 @@ const struct {
{
TEST_DESC("Invalid PAC URL"),
+ false, // is_valid
+
{ // Input.
MK_MODE(PAC_SCRIPT), // mode
"wpad.dat", // pac_url
@@ -103,6 +119,8 @@ const struct {
{
TEST_DESC("Single-host in proxy list"),
+ true, // is_valid
+
{ // Input.
MK_MODE(SINGLE_PROXY), // mode
NULL, // pac_url
@@ -119,6 +137,8 @@ const struct {
{
TEST_DESC("Single-host, different port"),
+ true, // is_valid
+
{ // Input.
MK_MODE(SINGLE_PROXY), // mode
NULL, // pac_url
@@ -135,6 +155,8 @@ const struct {
{
TEST_DESC("Tolerate a scheme"),
+ true, // is_valid
+
{ // Input.
MK_MODE(SINGLE_PROXY), // mode
NULL, // pac_url
@@ -151,99 +173,48 @@ const struct {
{
TEST_DESC("Per-scheme proxy rules"),
- { // Input.
- MK_MODE(PROXY_PER_SCHEME), // mode
- NULL, // pac_url
- NULL, // single_uri
- "www.google.com:80", "www.foo.com:110", "ftp.foo.com:121", // per-proto
- },
-
- // Expected result.
- false, // auto_detect
- GURL(), // pac_url
- net::ProxyRulesExpectation::PerScheme( // proxy_rules
- "www.google.com:80", // http
- "www.foo.com:110", // https
- "ftp.foo.com:121", // ftp
- ""), // bypass rules
- },
+ true, // is_valid
-// TODO(kuan): enable these.
-#if defined(TO_ENABLE_SOON)
- {
- TEST_DESC("socks"),
{ // Input.
MK_MODE(PROXY_PER_SCHEME), // mode
NULL, // pac_url
NULL, // single_uri
- NULL, NULL, NULL, // per-proto proxies
+ "www.google.com:80", // http_uri
+ "www.foo.com:110", // https_uri
+ "ftp.foo.com:121", // ftp_uri
"socks.com:888", // socks_uri
},
// Expected result.
- false, // auto_detect
- GURL(), // pac_url
- net::ProxyRulesExpectation::Single( // proxy_rules
- "socks4://socks.com:888", // single proxy
- ""), // bypass rules
- },
-
- {
- TEST_DESC("socks5"),
- { // Input.
- NULL, // auto_proxy
- "", // all_proxy
- NULL, NULL, NULL, // per-proto proxies
- "socks.com:888", "5", // SOCKS
- NULL, // no_proxy
- },
-
- // Expected result.
- false, // auto_detect
- GURL(), // pac_url
- net::ProxyRulesExpectation::Single( // proxy_rules
- "socks5://socks.com:888", // single proxy
- ""), // bypass rules
- ProxyConfigServiceImpl::READ_ONLY_MAIN, // readonly for owner
- ProxyConfigServiceImpl::READ_ONLY_MAIN, // readonly for non-owner
- },
-
- {
- TEST_DESC("socks default port"),
- { // Input.
- NULL, // auto_proxy
- "", // all_proxy
- NULL, NULL, NULL, // per-proto proxies
- "socks.com", NULL, // SOCKS
- NULL, // no_proxy
- },
-
- // Expected result.
- false, // auto_detect
- GURL(), // pac_url
- net::ProxyRulesExpectation::Single( // proxy_rules
- "socks4://socks.com:1080", // single proxy
+ false, // auto_detect
+ GURL(), // pac_url
+ net::ProxyRulesExpectation::PerSchemeWithSocks( // proxy_rules
+ "www.google.com:80", // http
+ "https://www.foo.com:110", // https
+ "ftp.foo.com:121", // ftp
+ "socks4://socks.com:888", // fallback proxy
""), // bypass rules
},
{
- TEST_DESC("bypass"),
+ TEST_DESC("Bypass rules"),
+ true, // is_valid
+
{ // Input.
- MK_MODE(PROXY_PER_SCHEME), // mode
+ MK_MODE(SINGLE_PROXY), // mode
NULL, // pac_url
"www.google.com", // single_uri
- NULL, NULL, NULL, NULL, // per-proto & socks proxies
+ NULL, NULL, NULL, NULL, // per-proto
".google.com, foo.com:99, 1.2.3.4:22, 127.0.0.1/8", // bypass_rules
},
- // Expected result;
- false, // auto_detect
- GURL(), // pac_url
- net::ProxyRulesExpectation::Single( // proxy_rules
- "www.google.com:80",
- "*.google.com,*foo.com:99,1.2.3.4:22,127.0.0.1/8"),
+ // Expected result.
+ false, // auto_detect
+ GURL(), // pac_url
+ net::ProxyRulesExpectation::Single( // proxy_rules
+ "www.google.com:80", // single proxy
+ "*.google.com,*foo.com:99,1.2.3.4:22,127.0.0.1/8"), // bypass_rules
},
-#endif // TO_ENABLE_SOON
}; // tests
} // namespace
@@ -253,6 +224,7 @@ class ProxyConfigServiceImplTest : public PlatformTest {
ProxyConfigServiceImplTest()
: ui_thread_(ChromeThread::UI, &message_loop_),
io_thread_(ChromeThread::IO, &message_loop_) {
+ chromeos::CrosLibrary::Get()->GetTestApi()->SetUseStubImpl();
}
virtual ~ProxyConfigServiceImplTest() {
@@ -282,14 +254,14 @@ class ProxyConfigServiceImplTest : public PlatformTest {
ProxyConfigServiceImpl::ProxyConfig::Mode mode,
ProxyConfigServiceImpl::ProxyConfig::Source source,
const char* server_uri,
+ net::ProxyServer::Scheme scheme,
ProxyConfigServiceImpl::ProxyConfig* config,
ProxyConfigServiceImpl::ProxyConfig::ManualProxy* manual_proxy) {
if (!server_uri)
return;
config->mode = mode;
manual_proxy->source = source;
- manual_proxy->server = net::ProxyServer::FromURI(server_uri,
- net::ProxyServer::SCHEME_HTTP);
+ manual_proxy->server = net::ProxyServer::FromURI(server_uri, scheme);
}
void InitConfigWithTestInput(
@@ -304,18 +276,18 @@ class ProxyConfigServiceImplTest : public PlatformTest {
&init_config->automatic_proxy);
return;
case MK_MODE(SINGLE_PROXY):
- SetManualProxy(input.mode, source, input.single_uri, init_config,
- &init_config->single_proxy);
+ SetManualProxy(input.mode, source, input.single_uri, MK_SCHM(HTTP),
+ init_config, &init_config->single_proxy);
break;
case MK_MODE(PROXY_PER_SCHEME):
- SetManualProxy(input.mode, source, input.http_uri, init_config,
- &init_config->http_proxy);
- SetManualProxy(input.mode, source, input.https_uri, init_config,
- &init_config->https_proxy);
- SetManualProxy(input.mode, source, input.ftp_uri, init_config,
- &init_config->ftp_proxy);
- SetManualProxy(input.mode, source, input.socks_uri, init_config,
- &init_config->socks_proxy);
+ SetManualProxy(input.mode, source, input.http_uri, MK_SCHM(HTTP),
+ init_config, &init_config->http_proxy);
+ SetManualProxy(input.mode, source, input.https_uri, MK_SCHM(HTTPS),
+ init_config, &init_config->https_proxy);
+ SetManualProxy(input.mode, source, input.ftp_uri, MK_SCHM(HTTP),
+ init_config, &init_config->ftp_proxy);
+ SetManualProxy(input.mode, source, input.socks_uri, MK_SCHM(SOCKS4),
+ init_config, &init_config->socks_proxy);
break;
}
if (input.bypass_rules) {
@@ -400,63 +372,70 @@ TEST_F(ProxyConfigServiceImplTest, ReadWriteAccess) {
}
TEST_F(ProxyConfigServiceImplTest, ModifyFromUI) {
- // Init with direct.
- ProxyConfigServiceImpl::ProxyConfig init_config;
- SetAutomaticProxy(MK_MODE(DIRECT), MK_SRC(OWNER), NULL, &init_config,
- &init_config.automatic_proxy);
- CreateConfigService(init_config);
-
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "] %s", i,
tests[i].description.c_str()));
+ // Init with direct.
+ ProxyConfigServiceImpl::ProxyConfig init_config;
+ SetAutomaticProxy(MK_MODE(DIRECT), MK_SRC(OWNER), NULL, &init_config,
+ &init_config.automatic_proxy);
+ CreateConfigService(init_config);
+
// Set config to tests[i].input via UI.
net::ProxyBypassRules bypass_rules;
- net::ProxyServer::Scheme scheme = net::ProxyServer::SCHEME_HTTP;
const Input& input = tests[i].input;
switch (input.mode) {
case MK_MODE(DIRECT) :
- config_service()->UISetProxyConfigToDirect();
+ EXPECT_EQ(tests[i].is_valid,
+ config_service()->UISetProxyConfigToDirect());
break;
case MK_MODE(AUTO_DETECT) :
- config_service()->UISetProxyConfigToAutoDetect();
+ EXPECT_EQ(tests[i].is_valid,
+ config_service()->UISetProxyConfigToAutoDetect());
break;
case MK_MODE(PAC_SCRIPT) :
- config_service()->UISetProxyConfigToPACScript(GURL(input.pac_url));
+ EXPECT_EQ(tests[i].is_valid,
+ config_service()->UISetProxyConfigToPACScript(
+ GURL(input.pac_url)));
break;
case MK_MODE(SINGLE_PROXY) :
- config_service()->UISetProxyConfigToSingleProxy(
- net::ProxyServer::FromURI(input.single_uri,
- net::ProxyServer::SCHEME_HTTP));
+ EXPECT_EQ(tests[i].is_valid,
+ config_service()->UISetProxyConfigToSingleProxy(
+ net::ProxyServer::FromURI(input.single_uri,
+ MK_SCHM(HTTP))));
if (input.bypass_rules) {
bypass_rules.ParseFromStringUsingSuffixMatching(input.bypass_rules);
- config_service()->UISetProxyConfigBypassRules(bypass_rules);
+ EXPECT_EQ(tests[i].is_valid,
+ config_service()->UISetProxyConfigBypassRules(
+ bypass_rules));
}
break;
case MK_MODE(PROXY_PER_SCHEME) :
if (input.http_uri) {
- config_service()->UISetProxyConfigToProxyPerScheme(
- "http",
- net::ProxyServer::FromURI(input.http_uri, scheme));
+ EXPECT_EQ(tests[i].is_valid,
+ config_service()->UISetProxyConfigToProxyPerScheme("http",
+ net::ProxyServer::FromURI(input.http_uri, MK_SCHM(HTTP))));
}
if (input.https_uri) {
- config_service()->UISetProxyConfigToProxyPerScheme(
- "https",
- net::ProxyServer::FromURI(input.https_uri, scheme));
+ EXPECT_EQ(tests[i].is_valid,
+ config_service()->UISetProxyConfigToProxyPerScheme("https",
+ net::ProxyServer::FromURI(input.https_uri, MK_SCHM(HTTPS))));
}
if (input.ftp_uri) {
- config_service()->UISetProxyConfigToProxyPerScheme(
- "ftp",
- net::ProxyServer::FromURI(input.ftp_uri, scheme));
+ EXPECT_EQ(tests[i].is_valid,
+ config_service()->UISetProxyConfigToProxyPerScheme("ftp",
+ net::ProxyServer::FromURI(input.ftp_uri, MK_SCHM(HTTP))));
}
if (input.socks_uri) {
- config_service()->UISetProxyConfigToProxyPerScheme(
- "socks",
- net::ProxyServer::FromURI(input.socks_uri, scheme));
+ EXPECT_EQ(tests[i].is_valid,
+ config_service()->UISetProxyConfigToProxyPerScheme("socks",
+ net::ProxyServer::FromURI(input.socks_uri, MK_SCHM(SOCKS4))));
}
if (input.bypass_rules) {
bypass_rules.ParseFromStringUsingSuffixMatching(input.bypass_rules);
- config_service()->UISetProxyConfigBypassRules(bypass_rules);
+ EXPECT_EQ(tests[i].is_valid,
+ config_service()->UISetProxyConfigBypassRules(bypass_rules));
}
break;
}
@@ -472,26 +451,29 @@ TEST_F(ProxyConfigServiceImplTest, ModifyFromUI) {
ProxyConfigServiceImpl::ProxyConfig ui_config;
config_service()->UIGetProxyConfig(&ui_config);
EXPECT_EQ(input.mode, ui_config.mode);
- if (input.pac_url)
- EXPECT_EQ(GURL(input.pac_url), ui_config.automatic_proxy.pac_url);
- const net::ProxyRulesExpectation& proxy_rules = tests[i].proxy_rules;
- if (input.single_uri)
- EXPECT_EQ(proxy_rules.single_proxy,
- ui_config.single_proxy.server.ToURI());
- if (input.http_uri)
- EXPECT_EQ(proxy_rules.proxy_for_http,
- ui_config.http_proxy.server.ToURI());
- if (input.https_uri)
- EXPECT_EQ(proxy_rules.proxy_for_https,
- ui_config.https_proxy.server.ToURI());
- if (input.ftp_uri)
- EXPECT_EQ(proxy_rules.proxy_for_ftp, ui_config.ftp_proxy.server.ToURI());
- if (input.socks_uri) {
- EXPECT_EQ(proxy_rules.fallback_proxy,
- ui_config.socks_proxy.server.ToURI());
+ if (tests[i].is_valid) {
+ if (input.pac_url)
+ EXPECT_EQ(GURL(input.pac_url), ui_config.automatic_proxy.pac_url);
+ const net::ProxyRulesExpectation& proxy_rules = tests[i].proxy_rules;
+ if (input.single_uri)
+ EXPECT_EQ(proxy_rules.single_proxy,
+ ui_config.single_proxy.server.ToURI());
+ if (input.http_uri)
+ EXPECT_EQ(proxy_rules.proxy_for_http,
+ ui_config.http_proxy.server.ToURI());
+ if (input.https_uri)
+ EXPECT_EQ(proxy_rules.proxy_for_https,
+ ui_config.https_proxy.server.ToURI());
+ if (input.ftp_uri)
+ EXPECT_EQ(proxy_rules.proxy_for_ftp,
+ ui_config.ftp_proxy.server.ToURI());
+ if (input.socks_uri) {
+ EXPECT_EQ(proxy_rules.fallback_proxy,
+ ui_config.socks_proxy.server.ToURI());
+ }
+ if (input.bypass_rules)
+ EXPECT_TRUE(bypass_rules.Equals(ui_config.bypass_rules));
}
- if (input.bypass_rules)
- EXPECT_TRUE(bypass_rules.Equals(ui_config.bypass_rules));
}
}
@@ -529,8 +511,8 @@ TEST_F(ProxyConfigServiceImplTest, ProxyChangedObserver) {
ProxyChangedObserver observer(config_service());
// Set to pac script from UI.
- config_service()->UISetProxyConfigToPACScript(GURL("http://wpad.dat"));
-
+ EXPECT_TRUE(config_service()->UISetProxyConfigToPACScript(
+ GURL("http://wpad.dat")));
// Retrieve config from IO thread.
net::ProxyConfig io_config;
SyncGetLatestProxyConfig(&io_config);
@@ -539,4 +521,42 @@ TEST_F(ProxyConfigServiceImplTest, ProxyChangedObserver) {
EXPECT_TRUE(io_config.Equals(observer.config()));
}
+TEST_F(ProxyConfigServiceImplTest, SerializeAndDeserialize) {
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
+ if (!tests[i].is_valid)
+ continue;
+ SCOPED_TRACE(StringPrintf("Test[%" PRIuS "] %s", i,
+ tests[i].description.c_str()));
+
+ ProxyConfigServiceImpl::ProxyConfig source_config;
+ InitConfigWithTestInput(tests[i].input, &source_config);
+
+ // Serialize source_config into std::string.
+ std::string serialized_value;
+ EXPECT_TRUE(source_config.Serialize(&serialized_value));
+
+ // Deserialize std:string into target_config.
+ ProxyConfigServiceImpl::ProxyConfig target_config;
+ EXPECT_TRUE(target_config.Deserialize(serialized_value));
+
+ // Compare the configs after serialization and deserialization.
+ net::ProxyConfig net_src_cfg;
+ net::ProxyConfig net_tgt_cfg;
+ source_config.ToNetProxyConfig(&net_src_cfg);
+ target_config.ToNetProxyConfig(&net_tgt_cfg);
+#if !defined(NDEBUG)
+ if (!net_src_cfg.Equals(net_tgt_cfg)) {
+ std::string src_output, tgt_output;
+ JSONStringValueSerializer src_serializer(&src_output);
+ src_serializer.Serialize(*net_src_cfg.ToValue());
+ JSONStringValueSerializer tgt_serializer(&tgt_output);
+ tgt_serializer.Serialize(*net_tgt_cfg.ToValue());
+ LOG(INFO) << "source:\n" << src_output;
+ LOG(INFO) << "target:\n" << tgt_output;
+ }
+#endif // !defined(NDEBUG)
+ EXPECT_TRUE(net_src_cfg.Equals(net_tgt_cfg));
+ }
+}
+
} // namespace chromeos
diff --git a/chrome/browser/chromeos/status/clock_menu_button_browsertest.cc b/chrome/browser/chromeos/status/clock_menu_button_browsertest.cc
index 158b3e8..f7a6f1c 100644
--- a/chrome/browser/chromeos/status/clock_menu_button_browsertest.cc
+++ b/chrome/browser/chromeos/status/clock_menu_button_browsertest.cc
@@ -25,6 +25,11 @@ namespace chromeos {
class ClockMenuButtonTest : public InProcessBrowserTest {
protected:
ClockMenuButtonTest() : InProcessBrowserTest() {}
+ virtual void SetUpInProcessBrowserTestFixture() {
+ // This test requires actual libcros, but InProcessBrowserTest has set
+ // to use stub, so reset it here.
+ CrosLibrary::Get()->GetTestApi()->ResetUseStubImpl();
+ }
ClockMenuButton* GetClockMenuButton() {
BrowserView* view = static_cast<BrowserView*>(browser()->window());
return static_cast<StatusAreaView*>(view->