Fix gconf for the linux proxy config service.
-Reenables fetching of settings from gconf. -Moves all gconf access to happen from the UI thread only, (where the default glib main loop runs). -Adds support for gconf notifications, avoiding having to poll the settings. -Fixes a small initialization glitch in the unittest. Plus minor code style tweaks. -Permanently removes gdk and glib threading initialization calls that were previously disabled. -Slight reorganization of ProxyService creation to pass down the IO thread MessageLoop. BUG=11111 TEST=none Review URL: http://codereview.chromium.org/113043 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@16739 0039d316-1c4b-4281-b951-d872f2087c98
This commit is contained in:
chrome
net
http
proxy
proxy_config.hproxy_config_service_linux.ccproxy_config_service_linux.hproxy_config_service_linux_unittest.ccproxy_script_fetcher_unittest.ccproxy_service.ccproxy_service.h
url_request
webkit/tools/test_shell
@ -469,18 +469,12 @@ int ChromeMain(int argc, const char** argv) {
|
||||
#endif
|
||||
} else if (process_type.empty()) {
|
||||
#if defined(OS_LINUX)
|
||||
// Glib/GDK type system and threading initializations. Needed at
|
||||
// least for gconf usage in net/proxy/proxy_config_service_linux.cc.
|
||||
// TODO(sdoyon): confirm whether gconf truly needs this. If so,
|
||||
// the GTK main loop (message pump) must also be made to call
|
||||
// gdk_threads_enter/leave(). Similar issue with the clipboard
|
||||
// (estade@ deanm@).
|
||||
// Glib type system initialization. Needed at least for gconf,
|
||||
// used in net/proxy/proxy_config_service_linux.cc. Most likely
|
||||
// this is superfluous as gtk_init() ought to do this. It's
|
||||
// definitely harmless, so retained as a reminder of this
|
||||
// requirement for gconf.
|
||||
g_type_init();
|
||||
#if 0 // gconf temporarily disabled because of races.
|
||||
// See http://crbug.com/11442.
|
||||
g_thread_init(NULL);
|
||||
gdk_threads_init();
|
||||
#endif // 0 (gconf disabled)
|
||||
// gtk_init() can change |argc| and |argv|, but nobody else uses them.
|
||||
gtk_init(&argc, const_cast<char***>(&argv));
|
||||
SetUpGLibLogHandler();
|
||||
|
@ -95,9 +95,11 @@ static net::ProxyService* CreateProxyService(URLRequestContext* context,
|
||||
use_v8 = false; // Fallback to non-v8 implementation.
|
||||
}
|
||||
|
||||
return use_v8 ?
|
||||
net::ProxyService::CreateUsingV8Resolver(proxy_config.get(), context) :
|
||||
net::ProxyService::Create(proxy_config.get());
|
||||
return net::ProxyService::Create(
|
||||
proxy_config.get(),
|
||||
use_v8,
|
||||
context,
|
||||
g_browser_process->io_thread()->message_loop());
|
||||
}
|
||||
|
||||
// static
|
||||
|
@ -347,7 +347,7 @@ ProxyService* CreateNullProxyService() {
|
||||
ProxyService* CreateFixedProxyService(const std::string& proxy) {
|
||||
net::ProxyConfig proxy_config;
|
||||
proxy_config.proxy_rules.ParseFromString(proxy);
|
||||
return ProxyService::Create(&proxy_config);
|
||||
return ProxyService::CreateFixed(proxy_config);
|
||||
}
|
||||
|
||||
|
||||
|
@ -28,6 +28,7 @@ class ProxyConfig {
|
||||
// Used to numerically identify this configuration.
|
||||
ID id() const { return id_; }
|
||||
void set_id(int id) { id_ = id; }
|
||||
bool is_valid() { return id_ != INVALID_ID; }
|
||||
|
||||
// True if the proxy configuration should be auto-detected.
|
||||
bool auto_detect;
|
||||
|
@ -5,12 +5,12 @@
|
||||
#include "net/proxy/proxy_config_service_linux.h"
|
||||
|
||||
#include <gconf/gconf-client.h>
|
||||
#include <gdk/gdk.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "base/string_tokenizer.h"
|
||||
#include "base/string_util.h"
|
||||
#include "base/task.h"
|
||||
#include "googleurl/src/url_canon.h"
|
||||
#include "net/base/net_errors.h"
|
||||
#include "net/http/http_util.h"
|
||||
@ -71,8 +71,7 @@ std::string FixupProxyHostScheme(ProxyServer::Scheme scheme,
|
||||
std::string::size_type at_sign = host.find("@");
|
||||
// Should this be supported?
|
||||
if (at_sign != std::string::npos) {
|
||||
LOG(ERROR) << "ProxyConfigServiceLinux: proxy authentication "
|
||||
"not supported";
|
||||
LOG(ERROR) << "Proxy authentication not supported";
|
||||
// Disregard the authentication parameters and continue with this hostname.
|
||||
host = host.substr(at_sign + 1);
|
||||
}
|
||||
@ -88,7 +87,7 @@ std::string FixupProxyHostScheme(ProxyServer::Scheme scheme,
|
||||
|
||||
} // namespace
|
||||
|
||||
bool ProxyConfigServiceLinux::GetProxyFromEnvVarForScheme(
|
||||
bool ProxyConfigServiceLinux::Delegate::GetProxyFromEnvVarForScheme(
|
||||
const char* variable, ProxyServer::Scheme scheme,
|
||||
ProxyServer* result_server) {
|
||||
std::string env_value;
|
||||
@ -100,21 +99,20 @@ bool ProxyConfigServiceLinux::GetProxyFromEnvVarForScheme(
|
||||
*result_server = proxy_server;
|
||||
return true;
|
||||
} else {
|
||||
LOG(ERROR) << "ProxyConfigServiceLinux: failed to parse "
|
||||
<< "environment variable " << variable;
|
||||
LOG(ERROR) << "Failed to parse environment variable " << variable;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ProxyConfigServiceLinux::GetProxyFromEnvVar(
|
||||
bool ProxyConfigServiceLinux::Delegate::GetProxyFromEnvVar(
|
||||
const char* variable, ProxyServer* result_server) {
|
||||
return GetProxyFromEnvVarForScheme(variable, ProxyServer::SCHEME_HTTP,
|
||||
result_server);
|
||||
}
|
||||
|
||||
bool ProxyConfigServiceLinux::GetConfigFromEnv(ProxyConfig* config) {
|
||||
bool ProxyConfigServiceLinux::Delegate::GetConfigFromEnv(ProxyConfig* config) {
|
||||
// Check for automatic configuration first, in
|
||||
// "auto_proxy". Possibly only the "environment_proxy" firefox
|
||||
// extension has ever used this, but it still sounds like a good
|
||||
@ -160,7 +158,7 @@ bool ProxyConfigServiceLinux::GetConfigFromEnv(ProxyConfig* config) {
|
||||
ProxyServer::Scheme scheme = ProxyServer::SCHEME_SOCKS4;
|
||||
std::string env_version;
|
||||
if (env_var_getter_->Getenv("SOCKS_VERSION", &env_version)
|
||||
&& env_version.compare("5") == 0)
|
||||
&& env_version == "5")
|
||||
scheme = ProxyServer::SCHEME_SOCKS5;
|
||||
if (GetProxyFromEnvVarForScheme("SOCKS_SERVER", scheme, &proxy_server)) {
|
||||
config->proxy_rules.type = ProxyConfig::ProxyRules::TYPE_SINGLE_PROXY;
|
||||
@ -183,37 +181,101 @@ bool ProxyConfigServiceLinux::GetConfigFromEnv(ProxyConfig* config) {
|
||||
|
||||
namespace {
|
||||
|
||||
// static
|
||||
// gconf notification callback, dispatched from the default
|
||||
// glib main loop.
|
||||
void OnGConfChangeNotification(
|
||||
GConfClient* client, guint cnxn_id,
|
||||
GConfEntry* entry, gpointer user_data) {
|
||||
// It would be nice to debounce multiple callbacks in quick
|
||||
// succession, since I guess we'll get one for each changed key. As
|
||||
// it is we will read settings from gconf once for each callback.
|
||||
LOG(INFO) << "gconf change notification for key "
|
||||
<< gconf_entry_get_key(entry);
|
||||
// We don't track which key has changed, just that something did change.
|
||||
// Forward to a method on the proxy config service delegate object.
|
||||
ProxyConfigServiceLinux::Delegate* config_service_delegate =
|
||||
reinterpret_cast<ProxyConfigServiceLinux::Delegate*>(user_data);
|
||||
config_service_delegate->OnCheckProxyConfigSettings();
|
||||
}
|
||||
|
||||
class GConfSettingGetterImpl
|
||||
: public ProxyConfigServiceLinux::GConfSettingGetter {
|
||||
public:
|
||||
GConfSettingGetterImpl() : client_(NULL) {}
|
||||
GConfSettingGetterImpl() : client_(NULL), loop_(NULL) {}
|
||||
|
||||
virtual ~GConfSettingGetterImpl() {
|
||||
if (client_)
|
||||
g_object_unref(client_);
|
||||
LOG(INFO) << "~GConfSettingGetterImpl called";
|
||||
// client_ should have been released before now, from
|
||||
// Delegate::OnDestroy(), while running on the UI thread.
|
||||
DCHECK(!client_);
|
||||
}
|
||||
|
||||
virtual void Enter() {
|
||||
gdk_threads_enter();
|
||||
}
|
||||
virtual void Leave() {
|
||||
gdk_threads_leave();
|
||||
}
|
||||
|
||||
virtual bool InitIfNeeded() {
|
||||
virtual bool Init() {
|
||||
DCHECK(!client_);
|
||||
DCHECK(!loop_);
|
||||
loop_ = MessageLoopForUI::current();
|
||||
client_ = gconf_client_get_default();
|
||||
if (!client_) {
|
||||
Enter();
|
||||
client_ = gconf_client_get_default();
|
||||
Leave();
|
||||
// It's not clear whether/when this can return NULL.
|
||||
if (!client_)
|
||||
LOG(ERROR) << "ProxyConfigServiceLinux: Unable to create "
|
||||
"a gconf client";
|
||||
LOG(ERROR) << "Unable to create a gconf client";
|
||||
loop_ = NULL;
|
||||
return false;
|
||||
}
|
||||
return client_ != NULL;
|
||||
GError* error = NULL;
|
||||
// We need to add the directories for which we'll be asking
|
||||
// notifications, and we might as well ask to preload them.
|
||||
gconf_client_add_dir(client_, "/system/proxy",
|
||||
GCONF_CLIENT_PRELOAD_ONELEVEL, &error);
|
||||
if (error == NULL) {
|
||||
gconf_client_add_dir(client_, "/system/http_proxy",
|
||||
GCONF_CLIENT_PRELOAD_ONELEVEL, &error);
|
||||
}
|
||||
if (error != NULL) {
|
||||
LOG(ERROR) << "Error requesting gconf directory: " << error->message;
|
||||
g_error_free(error);
|
||||
Release();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void Release() {
|
||||
if (client_) {
|
||||
DCHECK(MessageLoop::current() == loop_);
|
||||
// This also disables gconf notifications.
|
||||
g_object_unref(client_);
|
||||
client_ = NULL;
|
||||
loop_ = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bool SetupNotification(void* callback_user_data) {
|
||||
DCHECK(client_);
|
||||
DCHECK(MessageLoop::current() == loop_);
|
||||
GError* error = NULL;
|
||||
gconf_client_notify_add(
|
||||
client_, "/system/proxy",
|
||||
OnGConfChangeNotification, callback_user_data,
|
||||
NULL, &error);
|
||||
if (error == NULL) {
|
||||
gconf_client_notify_add(
|
||||
client_, "/system/http_proxy",
|
||||
OnGConfChangeNotification, callback_user_data,
|
||||
NULL, &error);
|
||||
}
|
||||
if (error != NULL) {
|
||||
LOG(ERROR) << "Error requesting gconf notifications: " << error->message;
|
||||
g_error_free(error);
|
||||
Release();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool GetString(const char* key, std::string* result) {
|
||||
CHECK(client_);
|
||||
DCHECK(client_);
|
||||
DCHECK(MessageLoop::current() == loop_);
|
||||
GError* error = NULL;
|
||||
gchar* value = gconf_client_get_string(client_, key, &error);
|
||||
if (HandleGError(error, key))
|
||||
@ -225,7 +287,8 @@ class GConfSettingGetterImpl
|
||||
return true;
|
||||
}
|
||||
virtual bool GetBoolean(const char* key, bool* result) {
|
||||
CHECK(client_);
|
||||
DCHECK(client_);
|
||||
DCHECK(MessageLoop::current() == loop_);
|
||||
GError* error = NULL;
|
||||
// We want to distinguish unset values from values defaulting to
|
||||
// false. For that we need to use the type-generic
|
||||
@ -247,7 +310,8 @@ class GConfSettingGetterImpl
|
||||
return true;
|
||||
}
|
||||
virtual bool GetInt(const char* key, int* result) {
|
||||
CHECK(client_);
|
||||
DCHECK(client_);
|
||||
DCHECK(MessageLoop::current() == loop_);
|
||||
GError* error = NULL;
|
||||
int value = gconf_client_get_int(client_, key, &error);
|
||||
if (HandleGError(error, key))
|
||||
@ -259,7 +323,8 @@ class GConfSettingGetterImpl
|
||||
}
|
||||
virtual bool GetStringList(const char* key,
|
||||
std::vector<std::string>* result) {
|
||||
CHECK(client_);
|
||||
DCHECK(client_);
|
||||
DCHECK(MessageLoop::current() == loop_);
|
||||
GError* error = NULL;
|
||||
GSList* list = gconf_client_get_list(client_, key,
|
||||
GCONF_VALUE_STRING, &error);
|
||||
@ -282,8 +347,8 @@ class GConfSettingGetterImpl
|
||||
// (error is NULL).
|
||||
bool HandleGError(GError* error, const char* key) {
|
||||
if (error != NULL) {
|
||||
LOG(ERROR) << "ProxyConfigServiceLinux: error getting gconf value for "
|
||||
<< key << ": " << error->message;
|
||||
LOG(ERROR) << "Error getting gconf value for " << key
|
||||
<< ": " << error->message;
|
||||
g_error_free(error);
|
||||
return true;
|
||||
}
|
||||
@ -292,12 +357,17 @@ class GConfSettingGetterImpl
|
||||
|
||||
GConfClient* client_;
|
||||
|
||||
// Message loop of the thread that we make gconf calls on. It should
|
||||
// be the UI thread and all our methods should be called on this
|
||||
// thread. Only for assertions.
|
||||
MessageLoop* loop_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(GConfSettingGetterImpl);
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
bool ProxyConfigServiceLinux::GetProxyFromGConf(
|
||||
bool ProxyConfigServiceLinux::Delegate::GetProxyFromGConf(
|
||||
const char* key_prefix, bool is_socks, ProxyServer* result_server) {
|
||||
std::string key(key_prefix);
|
||||
std::string host;
|
||||
@ -324,7 +394,8 @@ bool ProxyConfigServiceLinux::GetProxyFromGConf(
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ProxyConfigServiceLinux::GetConfigFromGConf(ProxyConfig* config) {
|
||||
bool ProxyConfigServiceLinux::Delegate::GetConfigFromGConf(
|
||||
ProxyConfig* config) {
|
||||
std::string mode;
|
||||
if (!gconf_getter_->GetString("/system/proxy/mode", &mode)) {
|
||||
// We expect this to always be set, so if we don't see it then we
|
||||
@ -332,11 +403,12 @@ bool ProxyConfigServiceLinux::GetConfigFromGConf(ProxyConfig* config) {
|
||||
// proxy config.
|
||||
return false;
|
||||
}
|
||||
if (mode.compare("none") == 0)
|
||||
if (mode == "none") {
|
||||
// Specifically specifies no proxy.
|
||||
return true;
|
||||
}
|
||||
|
||||
if (mode.compare("auto") == 0) {
|
||||
if (mode == "auto") {
|
||||
// automatic proxy config
|
||||
std::string pac_url_str;
|
||||
if (gconf_getter_->GetString("/system/proxy/autoconfig_url",
|
||||
@ -353,7 +425,7 @@ bool ProxyConfigServiceLinux::GetConfigFromGConf(ProxyConfig* config) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (mode.compare("manual") != 0) {
|
||||
if (mode != "manual") {
|
||||
// Mode is unrecognized.
|
||||
return false;
|
||||
}
|
||||
@ -419,8 +491,7 @@ bool ProxyConfigServiceLinux::GetConfigFromGConf(ProxyConfig* config) {
|
||||
gconf_getter_->GetBoolean("/system/http_proxy/use_authentication",
|
||||
&use_auth);
|
||||
if (use_auth)
|
||||
LOG(ERROR) << "ProxyConfigServiceLinux: proxy authentication "
|
||||
"not supported";
|
||||
LOG(ERROR) << "Proxy authentication not supported";
|
||||
|
||||
// Now the bypass list.
|
||||
gconf_getter_->GetStringList("/system/http_proxy/ignore_hosts",
|
||||
@ -431,64 +502,160 @@ bool ProxyConfigServiceLinux::GetConfigFromGConf(ProxyConfig* config) {
|
||||
return true;
|
||||
}
|
||||
|
||||
ProxyConfigServiceLinux::ProxyConfigServiceLinux(
|
||||
ProxyConfigServiceLinux::Delegate::Delegate(
|
||||
EnvironmentVariableGetter* env_var_getter,
|
||||
GConfSettingGetter* gconf_getter)
|
||||
: env_var_getter_(env_var_getter), gconf_getter_(gconf_getter) {
|
||||
: env_var_getter_(env_var_getter), gconf_getter_(gconf_getter),
|
||||
glib_default_loop_(NULL), io_loop_(NULL) {
|
||||
}
|
||||
|
||||
ProxyConfigServiceLinux::ProxyConfigServiceLinux()
|
||||
: env_var_getter_(new EnvironmentVariableGetterImpl()),
|
||||
gconf_getter_(new GConfSettingGetterImpl()) {
|
||||
}
|
||||
|
||||
int ProxyConfigServiceLinux::GetProxyConfig(ProxyConfig* config) {
|
||||
bool ProxyConfigServiceLinux::Delegate::ShouldTryGConf() {
|
||||
// GNOME_DESKTOP_SESSION_ID being defined is a good indication that
|
||||
// we are probably running under GNOME.
|
||||
// Note: KDE_FULL_SESSION is a corresponding env var to recognize KDE.
|
||||
std::string dummy, desktop_session;
|
||||
bool ok = false;
|
||||
#if 0 // gconf temporarily disabled because of races.
|
||||
// See http://crbug.com/11442.
|
||||
if (env_var_getter_->Getenv("GNOME_DESKTOP_SESSION_ID", &dummy)
|
||||
return env_var_getter_->Getenv("GNOME_DESKTOP_SESSION_ID", &dummy)
|
||||
|| (env_var_getter_->Getenv("DESKTOP_SESSION", &desktop_session)
|
||||
&& desktop_session.compare("gnome") == 0)) {
|
||||
// Get settings from gconf.
|
||||
//
|
||||
// I (sdoyon) would have liked to prioritize environment variables
|
||||
// and only fallback to gconf if env vars were unset. But
|
||||
// gnome-terminal "helpfully" sets http_proxy and no_proxy, and it
|
||||
// does so even if the proxy mode is set to auto, which would
|
||||
// mislead us.
|
||||
//
|
||||
// We could introduce a CHROME_PROXY_OBEY_ENV_VARS variable...??
|
||||
if (gconf_getter_->InitIfNeeded()) {
|
||||
gconf_getter_->Enter();
|
||||
ok = GetConfigFromGConf(config);
|
||||
gconf_getter_->Leave();
|
||||
if (ok)
|
||||
LOG(INFO) << "ProxyConfigServiceLinux: obtained proxy setting "
|
||||
"from gconf";
|
||||
&& desktop_session == "gnome");
|
||||
// I (sdoyon) would have liked to prioritize environment variables
|
||||
// and only fallback to gconf if env vars were unset. But
|
||||
// gnome-terminal "helpfully" sets http_proxy and no_proxy, and it
|
||||
// does so even if the proxy mode is set to auto, which would
|
||||
// mislead us.
|
||||
//
|
||||
// We could introduce a CHROME_PROXY_OBEY_ENV_VARS variable...??
|
||||
}
|
||||
|
||||
void ProxyConfigServiceLinux::Delegate::SetupAndFetchInitialConfig(
|
||||
MessageLoop* glib_default_loop, MessageLoop* io_loop) {
|
||||
// We should be running on the default glib main loop thread right
|
||||
// now. gconf can only be accessed from this thread.
|
||||
DCHECK(MessageLoop::current() == glib_default_loop);
|
||||
glib_default_loop_ = glib_default_loop;
|
||||
io_loop_ = io_loop;
|
||||
|
||||
// If we are passed a NULL io_loop, then we don't setup gconf
|
||||
// notifications. This should not be the usual case but is intended
|
||||
// to simplify test setups.
|
||||
if (!io_loop_)
|
||||
LOG(INFO) << "Monitoring of gconf setting changes is disabled";
|
||||
|
||||
// Fetch and cache the current proxy config. The config is left in
|
||||
// cached_config_, where GetProxyConfig() running on the IO thread
|
||||
// will expect to find it. This is safe to do because we return
|
||||
// before this ProxyConfigServiceLinux is passed on to
|
||||
// the ProxyService.
|
||||
bool got_config = false;
|
||||
if (ShouldTryGConf() &&
|
||||
gconf_getter_->Init() &&
|
||||
(!io_loop || gconf_getter_->SetupNotification(this))) {
|
||||
if (GetConfigFromGConf(&cached_config_)) {
|
||||
cached_config_.set_id(1); // mark it as valid
|
||||
got_config = true;
|
||||
LOG(INFO) << "Obtained proxy setting from gconf";
|
||||
// If gconf proxy mode is "none", meaning direct, then we take
|
||||
// that to be a valid config and will not check environment variables.
|
||||
// The alternative would have been to look for a proxy whereever
|
||||
// we can find one.
|
||||
// that to be a valid config and will not check environment
|
||||
// variables. The alternative would have been to look for a proxy
|
||||
// where ever we can find one.
|
||||
//
|
||||
// TODO(sdoyon): Consider wiring in the gconf notification
|
||||
// system. Cache this result config to return on subsequent calls,
|
||||
// and only call GetConfigFromGConf() when we know things have
|
||||
// actually changed.
|
||||
// Keep a copy of the config for use from this thread for
|
||||
// comparison with updated settings when we get notifications.
|
||||
reference_config_ = cached_config_;
|
||||
reference_config_.set_id(1); // mark it as valid
|
||||
} else {
|
||||
gconf_getter_->Release(); // Stop notifications
|
||||
}
|
||||
}
|
||||
#endif // 0 (gconf disabled)
|
||||
// An implementation for KDE settings would be welcome here.
|
||||
if (!ok) {
|
||||
ok = GetConfigFromEnv(config);
|
||||
if (ok)
|
||||
LOG(INFO) << "ProxyConfigServiceLinux: obtained proxy setting "
|
||||
"from environment variables";
|
||||
if (!got_config) {
|
||||
// An implementation for KDE settings would be welcome here.
|
||||
//
|
||||
// Consulting environment variables doesn't need to be done from
|
||||
// the default glib main loop, but it's a tiny enough amount of
|
||||
// work.
|
||||
if (GetConfigFromEnv(&cached_config_)) {
|
||||
cached_config_.set_id(1); // mark it as valid
|
||||
LOG(INFO) << "Obtained proxy setting from environment variables";
|
||||
}
|
||||
}
|
||||
return ok ? OK : ERR_FAILED;
|
||||
}
|
||||
|
||||
void ProxyConfigServiceLinux::Delegate::Reset() {
|
||||
DCHECK(!glib_default_loop_ || MessageLoop::current() == glib_default_loop_);
|
||||
gconf_getter_->Release();
|
||||
cached_config_ = ProxyConfig();
|
||||
}
|
||||
|
||||
int ProxyConfigServiceLinux::Delegate::GetProxyConfig(ProxyConfig* config) {
|
||||
// This is called from the IO thread.
|
||||
DCHECK(!io_loop_ || MessageLoop::current() == io_loop_);
|
||||
|
||||
// Simply return the last proxy configuration that glib_default_loop
|
||||
// notified us of.
|
||||
*config = cached_config_;
|
||||
return cached_config_.is_valid() ? OK : ERR_FAILED;
|
||||
}
|
||||
|
||||
void ProxyConfigServiceLinux::Delegate::OnCheckProxyConfigSettings() {
|
||||
// This should be dispatched from the thread with the default glib
|
||||
// main loop, which allows us to access gconf.
|
||||
DCHECK(MessageLoop::current() == glib_default_loop_);
|
||||
|
||||
ProxyConfig new_config;
|
||||
bool valid = GetConfigFromGConf(&new_config);
|
||||
if (valid)
|
||||
new_config.set_id(1); // mark it as valid
|
||||
|
||||
// See if it is different than what we had before.
|
||||
if (new_config.is_valid() != reference_config_.is_valid() ||
|
||||
!new_config.Equals(reference_config_)) {
|
||||
// Post a task to |io_loop| with the new configuration, so it can
|
||||
// update |cached_config_|.
|
||||
io_loop_->PostTask(
|
||||
FROM_HERE,
|
||||
NewRunnableMethod(
|
||||
this,
|
||||
&ProxyConfigServiceLinux::Delegate::SetNewProxyConfig,
|
||||
new_config));
|
||||
}
|
||||
}
|
||||
|
||||
void ProxyConfigServiceLinux::Delegate::SetNewProxyConfig(
|
||||
const ProxyConfig& new_config) {
|
||||
DCHECK(MessageLoop::current() == io_loop_);
|
||||
LOG(INFO) << "Proxy configuration changed";
|
||||
cached_config_ = new_config;
|
||||
}
|
||||
|
||||
void ProxyConfigServiceLinux::Delegate::PostDestroyTask() {
|
||||
if (MessageLoop::current() == glib_default_loop_) {
|
||||
// Already on the right thread, call directly.
|
||||
// This is the case for the unittests.
|
||||
OnDestroy();
|
||||
} else {
|
||||
// Post to UI thread. Note that on browser shutdown, we may quit
|
||||
// the UI MessageLoop and exit the program before ever running
|
||||
// this.
|
||||
glib_default_loop_->PostTask(
|
||||
FROM_HERE,
|
||||
NewRunnableMethod(
|
||||
this,
|
||||
&ProxyConfigServiceLinux::Delegate::OnDestroy));
|
||||
}
|
||||
}
|
||||
void ProxyConfigServiceLinux::Delegate::OnDestroy() {
|
||||
DCHECK(!glib_default_loop_ || MessageLoop::current() == glib_default_loop_);
|
||||
gconf_getter_->Release();
|
||||
}
|
||||
|
||||
ProxyConfigServiceLinux::ProxyConfigServiceLinux()
|
||||
: delegate_(new Delegate(new EnvironmentVariableGetterImpl(),
|
||||
new GConfSettingGetterImpl())) {
|
||||
}
|
||||
|
||||
ProxyConfigServiceLinux::ProxyConfigServiceLinux(
|
||||
EnvironmentVariableGetter* env_var_getter,
|
||||
GConfSettingGetter* gconf_getter)
|
||||
: delegate_(new Delegate(env_var_getter, gconf_getter)) {
|
||||
}
|
||||
|
||||
} // namespace net
|
||||
|
@ -9,7 +9,10 @@
|
||||
#include <vector>
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "base/message_loop.h"
|
||||
#include "base/ref_counted.h"
|
||||
#include "base/scoped_ptr.h"
|
||||
#include "net/proxy/proxy_config.h"
|
||||
#include "net/proxy/proxy_config_service.h"
|
||||
#include "net/proxy/proxy_server.h"
|
||||
|
||||
@ -33,25 +36,24 @@ class ProxyConfigServiceLinux : public ProxyConfigService {
|
||||
public:
|
||||
virtual ~GConfSettingGetter() {}
|
||||
|
||||
// GDK/GTK+ thread-safety: multi-threaded programs coordinate
|
||||
// around a global lock. See
|
||||
// http://library.gnome.org/devel/gdk/unstable/gdk-Threads.html
|
||||
// and http://research.operationaldynamics.com/blogs/andrew/software/gnome-desktop/gtk-thread-awareness.html
|
||||
// The following methods are used to grab said lock around any
|
||||
// actual gconf usage: including calls to Init() and any of the
|
||||
// Get* methods.
|
||||
virtual void Enter() = 0;
|
||||
virtual void Leave() = 0;
|
||||
|
||||
// Initializes the class: obtains a gconf client, in the concrete
|
||||
// implementation. Returns true on success. Must be called before
|
||||
// any of the Get* methods, and the Get* methods must not be used
|
||||
// if this method returns false. This method may be called again,
|
||||
// whether or not it succeeded before.
|
||||
virtual bool InitIfNeeded() = 0;
|
||||
// using other methods.
|
||||
virtual bool Init() = 0;
|
||||
|
||||
// Gets a string type value from gconf and stores it in result. Returns
|
||||
// false if the key is unset or on error.
|
||||
// Releases the gconf client, which clears cached directories and
|
||||
// stops notifications.
|
||||
virtual void Release() = 0;
|
||||
|
||||
// Requests notification of gconf setting changes for proxy
|
||||
// settings. Returns true on success.
|
||||
virtual bool SetupNotification(void* callback_user_data) = 0;
|
||||
|
||||
// Gets a string type value from gconf and stores it in
|
||||
// result. Returns false if the key is unset or on error. Must
|
||||
// only be called after a successful call to Init(), and not
|
||||
// after a failed call to SetupNotification() or after calling
|
||||
// Release().
|
||||
virtual bool GetString(const char* key, std::string* result) = 0;
|
||||
// Same thing for a bool typed value.
|
||||
virtual bool GetBoolean(const char* key, bool* result) = 0;
|
||||
@ -62,41 +64,154 @@ class ProxyConfigServiceLinux : public ProxyConfigService {
|
||||
std::vector<std::string>* result) = 0;
|
||||
};
|
||||
|
||||
// ProxyConfigServiceLinux is created on the UI thread, and
|
||||
// SetupAndFetchInitialConfig() is immediately called to
|
||||
// synchronously fetch the original configuration and setup gconf
|
||||
// notifications on the UI thread.
|
||||
//
|
||||
// Passed that point, it is accessed periodically through
|
||||
// GetProxyConfig() from the IO thread.
|
||||
//
|
||||
// gconf change notification callbacks can occur at any time and are
|
||||
// run on the UI thread. The new gconf settings are fetched on the
|
||||
// UI thread, and the new resulting proxy config is posted to the IO
|
||||
// thread through Delegate::SetNewProxyConfig().
|
||||
//
|
||||
// ProxyConfigServiceLinux is deleted from the IO thread.
|
||||
//
|
||||
// The substance of the ProxyConfigServiceLinux implementation is
|
||||
// wrapped in the Delegate ref counted class. On deleting the
|
||||
// ProxyConfigServiceLinux, Delegate::OnDestroy() is posted to the
|
||||
// UI thread where gconf notifications will be safely stopped before
|
||||
// releasing Delegate.
|
||||
|
||||
class Delegate : public base::RefCountedThreadSafe<Delegate> {
|
||||
public:
|
||||
// Constructor receives gconf and env var getter implementations
|
||||
// to use, and takes ownership of them.
|
||||
Delegate(EnvironmentVariableGetter* env_var_getter,
|
||||
GConfSettingGetter* gconf_getter);
|
||||
// Synchronously obtains the proxy configuration. If gconf is
|
||||
// used, also enables gconf notification for setting
|
||||
// changes. gconf must only be accessed from the thread running
|
||||
// the default glib main loop, and so this method must be called
|
||||
// from the UI thread. The message loop for the IO thread is
|
||||
// specified so that notifications can post tasks to it (and for
|
||||
// assertions).
|
||||
void SetupAndFetchInitialConfig(MessageLoop* glib_default_loop,
|
||||
MessageLoop* io_loop);
|
||||
// Resets cached_config_ and releases the gconf_getter_, making it
|
||||
// possible to call SetupAndFetchInitialConfig() again. Only used
|
||||
// in testing.
|
||||
void Reset();
|
||||
|
||||
// Handler for gconf change notifications: fetches a new proxy
|
||||
// configuration from gconf settings, and if this config is
|
||||
// different than what we had before, posts a task to have it
|
||||
// stored in cached_config_.
|
||||
// Left public for simplicity.
|
||||
void OnCheckProxyConfigSettings();
|
||||
|
||||
// Called from IO thread.
|
||||
int GetProxyConfig(ProxyConfig* config);
|
||||
|
||||
// Posts a call to OnDestroy() to the UI thread. Called from
|
||||
// ProxyConfigServiceLinux's destructor.
|
||||
void PostDestroyTask();
|
||||
// Safely stops gconf notifications. Posted to the UI thread.
|
||||
void OnDestroy();
|
||||
|
||||
private:
|
||||
// Obtains an environment variable's value. Parses a proxy server
|
||||
// specification from it and puts it in result. Returns true if the
|
||||
// requested variable is defined and the value valid.
|
||||
bool GetProxyFromEnvVarForScheme(const char* variable,
|
||||
ProxyServer::Scheme scheme,
|
||||
ProxyServer* result_server);
|
||||
// As above but with scheme set to HTTP, for convenience.
|
||||
bool GetProxyFromEnvVar(const char* variable, ProxyServer* result_server);
|
||||
// Fills proxy config from environment variables. Returns true if
|
||||
// variables were found and the configuration is valid.
|
||||
bool GetConfigFromEnv(ProxyConfig* config);
|
||||
|
||||
// Obtains host and port gconf settings and parses a proxy server
|
||||
// specification from it and puts it in result. Returns true if the
|
||||
// requested variable is defined and the value valid.
|
||||
bool GetProxyFromGConf(const char* key_prefix, bool is_socks,
|
||||
ProxyServer* result_server);
|
||||
// Fills proxy config from gconf. Returns true if settings were found
|
||||
// and the configuration is valid.
|
||||
bool GetConfigFromGConf(ProxyConfig* config);
|
||||
|
||||
// Returns true if environment variables indicate that we are
|
||||
// running GNOME (and therefore we want to use gconf settings).
|
||||
bool ShouldTryGConf();
|
||||
|
||||
// This method is posted from the UI thread to the IO thread to
|
||||
// carry the new config information.
|
||||
void SetNewProxyConfig(const ProxyConfig& new_config);
|
||||
|
||||
scoped_ptr<EnvironmentVariableGetter> env_var_getter_;
|
||||
scoped_ptr<GConfSettingGetter> gconf_getter_;
|
||||
|
||||
// Cached proxy configuration, to be returned by
|
||||
// GetProxyConfig. Initially populated from the UI thread, but
|
||||
// afterwards only accessed from the IO thread.
|
||||
ProxyConfig cached_config_;
|
||||
|
||||
// A copy kept on the UI thread of the last seen proxy config, so as
|
||||
// to avoid posting a call to SetNewProxyConfig when we get a
|
||||
// notification but the config has not actually changed.
|
||||
ProxyConfig reference_config_;
|
||||
|
||||
// The MessageLoop for the UI thread, aka main browser thread. This
|
||||
// thread is where we run the glib main loop (see
|
||||
// base/message_pump_glib.h). It is the glib default loop in the
|
||||
// sense that it runs the glib default context: as in the context
|
||||
// where sources are added by g_timeout_add and g_idle_add, and
|
||||
// returned by g_main_context_default. gconf uses glib timeouts and
|
||||
// idles and possibly other callbacks that will all be dispatched on
|
||||
// this thread. Since gconf is not thread safe, any use of gconf
|
||||
// must be done on the thread running this loop.
|
||||
MessageLoop* glib_default_loop_;
|
||||
// MessageLoop for the IO thread. GetProxyConfig() is called from
|
||||
// the thread running this loop.
|
||||
MessageLoop* io_loop_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(Delegate);
|
||||
};
|
||||
|
||||
// Thin wrapper shell around Delegate.
|
||||
|
||||
// Usual constructor
|
||||
ProxyConfigServiceLinux();
|
||||
// For testing: pass in alternate gconf and env var getter implementations.
|
||||
// ProxyConfigServiceLinux takes ownership of the getter objects.
|
||||
// For testing: takes alternate gconf and env var getter implementations.
|
||||
ProxyConfigServiceLinux(EnvironmentVariableGetter* env_var_getter,
|
||||
GConfSettingGetter* gconf_getter);
|
||||
|
||||
virtual ~ProxyConfigServiceLinux() {
|
||||
delegate_->PostDestroyTask();
|
||||
}
|
||||
|
||||
void SetupAndFetchInitialConfig(MessageLoop* glib_default_loop,
|
||||
MessageLoop* io_loop) {
|
||||
delegate_->SetupAndFetchInitialConfig(glib_default_loop, io_loop);
|
||||
}
|
||||
void Reset() {
|
||||
delegate_->Reset();
|
||||
}
|
||||
void OnCheckProxyConfigSettings() {
|
||||
delegate_->OnCheckProxyConfigSettings();
|
||||
}
|
||||
|
||||
// ProxyConfigService methods:
|
||||
virtual int GetProxyConfig(ProxyConfig* config);
|
||||
// Called from IO thread.
|
||||
virtual int GetProxyConfig(ProxyConfig* config) {
|
||||
return delegate_->GetProxyConfig(config);
|
||||
}
|
||||
|
||||
private:
|
||||
// Obtains an environment variable's value. Parses a proxy server
|
||||
// specification from it and puts it in result. Returns true if the
|
||||
// requested variable is defined and the value valid.
|
||||
bool GetProxyFromEnvVarForScheme(const char* variable,
|
||||
ProxyServer::Scheme scheme,
|
||||
ProxyServer* result_server);
|
||||
// As above but with scheme set to HTTP, for convenience.
|
||||
bool GetProxyFromEnvVar(const char* variable, ProxyServer* result_server);
|
||||
|
||||
// Fills proxy config from environment variables. Returns true if
|
||||
// variables were found and the configuration is valid.
|
||||
bool GetConfigFromEnv(ProxyConfig* config);
|
||||
|
||||
// Obtains host and port gconf settings and parses a proxy server
|
||||
// specification from it and puts it in result. Returns true if the
|
||||
// requested variable is defined and the value valid.
|
||||
bool GetProxyFromGConf(const char* key_prefix, bool is_socks,
|
||||
ProxyServer* result_server);
|
||||
// Fills proxy config from gconf. Returns true if settings were found
|
||||
// and the configuration is valid.
|
||||
bool GetConfigFromGConf(ProxyConfig* config);
|
||||
|
||||
scoped_ptr<EnvironmentVariableGetter> env_var_getter_;
|
||||
scoped_ptr<GConfSettingGetter> gconf_getter_;
|
||||
scoped_refptr<Delegate> delegate_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(ProxyConfigServiceLinux);
|
||||
};
|
||||
|
@ -10,13 +10,15 @@
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "base/string_util.h"
|
||||
#include "base/task.h"
|
||||
#include "base/thread.h"
|
||||
#include "base/waitable_event.h"
|
||||
#include "net/proxy/proxy_config.h"
|
||||
#include "net/proxy/proxy_config_service_common_unittest.h"
|
||||
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
|
||||
namespace net {
|
||||
|
||||
namespace {
|
||||
|
||||
// Set of values for all environment variables that we might
|
||||
@ -31,6 +33,10 @@ struct EnvVarValues {
|
||||
*no_proxy;
|
||||
};
|
||||
|
||||
// Undo macro pollution from GDK includes (from message_loop.h).
|
||||
#undef TRUE
|
||||
#undef FALSE
|
||||
|
||||
// So as to distinguish between an unset gconf boolean variable and
|
||||
// one that is false.
|
||||
enum BoolSettingValue {
|
||||
@ -84,11 +90,11 @@ class MockEnvironmentVariableGetter
|
||||
ENTRY(SOCKS_SERVER);
|
||||
ENTRY(SOCKS_VERSION);
|
||||
#undef ENTRY
|
||||
reset();
|
||||
Reset();
|
||||
}
|
||||
|
||||
// Zeros all environment values.
|
||||
void reset() {
|
||||
void Reset() {
|
||||
EnvVarValues zero_values = { 0 };
|
||||
values = zero_values;
|
||||
}
|
||||
@ -138,19 +144,22 @@ class MockGConfSettingGetter
|
||||
#undef ENTRY
|
||||
string_lists_table.settings["/system/http_proxy/ignore_hosts"] =
|
||||
&values.ignore_hosts;
|
||||
reset();
|
||||
Reset();
|
||||
}
|
||||
|
||||
// Zeros all environment values.
|
||||
void reset() {
|
||||
GConfValues zero_values;
|
||||
void Reset() {
|
||||
GConfValues zero_values = { 0 };
|
||||
values = zero_values;
|
||||
}
|
||||
|
||||
virtual void Enter() {}
|
||||
virtual void Leave() {}
|
||||
virtual bool Init() {
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool InitIfNeeded() {
|
||||
virtual void Release() {}
|
||||
|
||||
virtual bool SetupNotification(void* callback_user_data) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -201,11 +210,99 @@ class MockGConfSettingGetter
|
||||
};
|
||||
|
||||
} // namespace
|
||||
} // namespace net
|
||||
|
||||
// This helper class runs ProxyConfigServiceLinux::GetProxyConfig() on
|
||||
// the IO thread and synchronously waits for the result.
|
||||
// Some code duplicated from proxy_script_fetcher_unittest.cc.
|
||||
class SynchConfigGetter {
|
||||
public:
|
||||
explicit SynchConfigGetter(net::ProxyConfigServiceLinux* config_service)
|
||||
: event_(false, false),
|
||||
io_thread_("IO_Thread"),
|
||||
config_service_(config_service) {
|
||||
// Start an IO thread.
|
||||
base::Thread::Options options;
|
||||
options.message_loop_type = MessageLoop::TYPE_IO;
|
||||
io_thread_.StartWithOptions(options);
|
||||
|
||||
// Make sure the thread started.
|
||||
io_thread_.message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
|
||||
this, &SynchConfigGetter::Init));
|
||||
Wait();
|
||||
}
|
||||
|
||||
~SynchConfigGetter() {
|
||||
// Cleanup the IO thread.
|
||||
io_thread_.message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
|
||||
this, &SynchConfigGetter::Cleanup));
|
||||
Wait();
|
||||
}
|
||||
|
||||
// Does a reset, gconf setup and initial fetch of the proxy config,
|
||||
// all on the calling thread (meant to be the thread with the
|
||||
// default glib main loop, which is the UI thread).
|
||||
void SetupAndInitialFetch() {
|
||||
config_service_->Reset();
|
||||
config_service_->SetupAndFetchInitialConfig(
|
||||
MessageLoop::current(), io_thread_.message_loop());
|
||||
}
|
||||
// Synchronously gets the proxy config.
|
||||
int SyncGetProxyConfig(net::ProxyConfig* config) {
|
||||
io_thread_.message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
|
||||
this, &SynchConfigGetter::GetConfigOnIOThread));
|
||||
Wait();
|
||||
*config = proxy_config_;
|
||||
return get_config_result_;
|
||||
}
|
||||
|
||||
private:
|
||||
// [Runs on |io_thread_|]
|
||||
void Init() {
|
||||
event_.Signal();
|
||||
}
|
||||
|
||||
// Calls GetProxyConfig, running on |io_thread_|] Signals |event_|
|
||||
// on completion.
|
||||
void GetConfigOnIOThread() {
|
||||
get_config_result_ = config_service_->GetProxyConfig(&proxy_config_);
|
||||
event_.Signal();
|
||||
}
|
||||
|
||||
// [Runs on |io_thread_|] Signals |event_| on cleanup completion.
|
||||
void Cleanup() {
|
||||
MessageLoop::current()->RunAllPending();
|
||||
event_.Signal();
|
||||
}
|
||||
|
||||
void Wait() {
|
||||
event_.Wait();
|
||||
event_.Reset();
|
||||
}
|
||||
|
||||
base::WaitableEvent event_;
|
||||
base::Thread io_thread_;
|
||||
|
||||
net::ProxyConfigServiceLinux* config_service_;
|
||||
|
||||
// The config obtained by |io_thread_| and read back by the main
|
||||
// thread.
|
||||
net::ProxyConfig proxy_config_;
|
||||
int get_config_result_; // Return value from GetProxyConfig().
|
||||
};
|
||||
|
||||
template<>
|
||||
void RunnableMethodTraits<SynchConfigGetter>::RetainCallee(
|
||||
SynchConfigGetter* remover) {}
|
||||
template<>
|
||||
void RunnableMethodTraits<SynchConfigGetter>::ReleaseCallee(
|
||||
SynchConfigGetter* remover) {}
|
||||
|
||||
namespace net {
|
||||
|
||||
// Builds an identifier for each test in an array.
|
||||
#define TEST_DESC(desc) StringPrintf("at line %d <%s>", __LINE__, desc)
|
||||
|
||||
#if 0 // gconf temporarily disabled.
|
||||
TEST(ProxyConfigServiceLinuxTest, BasicGConfTest) {
|
||||
MockEnvironmentVariableGetter* env_getter =
|
||||
new MockEnvironmentVariableGetter;
|
||||
@ -450,15 +547,15 @@ TEST(ProxyConfigServiceLinuxTest, BasicGConfTest) {
|
||||
},
|
||||
};
|
||||
|
||||
SynchConfigGetter sync_config_getter(&service);
|
||||
|
||||
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
|
||||
SCOPED_TRACE(StringPrintf("Test[%d] %s", i, tests[i].description.c_str()));
|
||||
ProxyConfig config;
|
||||
gconf_getter->values = tests[i].values;
|
||||
service.GetProxyConfig(&config);
|
||||
sync_config_getter.SetupAndInitialFetch();
|
||||
sync_config_getter.SyncGetProxyConfig(&config);
|
||||
|
||||
// TODO(sdoyon): Add a description field to each test, and a
|
||||
// corresponding message to the EXPECT statements, so that it is
|
||||
// possible to identify which one of the tests failed.
|
||||
EXPECT_EQ(tests[i].auto_detect, config.auto_detect);
|
||||
EXPECT_EQ(tests[i].pac_url, config.pac_url);
|
||||
EXPECT_EQ(tests[i].proxy_bypass_list,
|
||||
@ -467,7 +564,6 @@ TEST(ProxyConfigServiceLinuxTest, BasicGConfTest) {
|
||||
EXPECT_EQ(tests[i].proxy_rules, config.proxy_rules);
|
||||
}
|
||||
}
|
||||
#endif // 0 (gconf disabled)
|
||||
|
||||
TEST(ProxyConfigServiceLinuxTest, BasicEnvTest) {
|
||||
MockEnvironmentVariableGetter* env_getter =
|
||||
@ -720,11 +816,14 @@ TEST(ProxyConfigServiceLinuxTest, BasicEnvTest) {
|
||||
},
|
||||
};
|
||||
|
||||
SynchConfigGetter sync_config_getter(&service);
|
||||
|
||||
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
|
||||
SCOPED_TRACE(StringPrintf("Test[%d] %s", i, tests[i].description.c_str()));
|
||||
ProxyConfig config;
|
||||
env_getter->values = tests[i].values;
|
||||
service.GetProxyConfig(&config);
|
||||
sync_config_getter.SetupAndInitialFetch();
|
||||
sync_config_getter.SyncGetProxyConfig(&config);
|
||||
|
||||
EXPECT_EQ(tests[i].auto_detect, config.auto_detect);
|
||||
EXPECT_EQ(tests[i].pac_url, config.pac_url);
|
||||
@ -753,10 +852,38 @@ TEST(ProxyConfigServiceLinuxTest, FallbackOnEnv) {
|
||||
env_getter->values.auto_proxy = "http://correct/wpad.dat";
|
||||
|
||||
ProxyConfig config;
|
||||
service.GetProxyConfig(&config);
|
||||
|
||||
SynchConfigGetter sync_config_getter(&service);
|
||||
sync_config_getter.SetupAndInitialFetch();
|
||||
sync_config_getter.SyncGetProxyConfig(&config);
|
||||
|
||||
// Then we expect the environment variable to win.
|
||||
EXPECT_EQ(GURL(env_getter->values.auto_proxy), config.pac_url);
|
||||
}
|
||||
|
||||
TEST(ProxyConfigServiceLinuxTest, GconfNotification) {
|
||||
MockEnvironmentVariableGetter* env_getter =
|
||||
new MockEnvironmentVariableGetter;
|
||||
MockGConfSettingGetter* gconf_getter = new MockGConfSettingGetter;
|
||||
ProxyConfigServiceLinux service(env_getter, gconf_getter);
|
||||
ProxyConfig config;
|
||||
SynchConfigGetter sync_config_getter(&service);
|
||||
|
||||
// Use gconf configuration.
|
||||
env_getter->values.GNOME_DESKTOP_SESSION_ID = "defined";
|
||||
|
||||
// Start with no proxy.
|
||||
gconf_getter->values.mode = "none";
|
||||
sync_config_getter.SetupAndInitialFetch();
|
||||
sync_config_getter.SyncGetProxyConfig(&config);
|
||||
EXPECT_FALSE(config.auto_detect);
|
||||
|
||||
// Now set to auto-detect.
|
||||
gconf_getter->values.mode = "auto";
|
||||
// Simulate gconf notification callback.
|
||||
service.OnCheckProxyConfigSettings();
|
||||
sync_config_getter.SyncGetProxyConfig(&config);
|
||||
EXPECT_TRUE(config.auto_detect);
|
||||
}
|
||||
|
||||
} // namespace net
|
||||
|
@ -28,7 +28,7 @@ class RequestContext : public URLRequestContext {
|
||||
public:
|
||||
RequestContext() {
|
||||
net::ProxyConfig no_proxy;
|
||||
proxy_service_ = net::ProxyService::Create(&no_proxy);
|
||||
proxy_service_ = net::ProxyService::CreateFixed(no_proxy);
|
||||
http_transaction_factory_ = net::HttpNetworkLayer::CreateFactory(
|
||||
proxy_service_);
|
||||
}
|
||||
|
@ -207,33 +207,35 @@ ProxyService::ProxyService(ProxyConfigService* config_service,
|
||||
}
|
||||
|
||||
// static
|
||||
ProxyService* ProxyService::Create(const ProxyConfig* pc) {
|
||||
ProxyService* ProxyService::Create(
|
||||
const ProxyConfig* pc,
|
||||
bool use_v8_resolver,
|
||||
URLRequestContext* url_request_context,
|
||||
MessageLoop* io_loop) {
|
||||
// Choose the system configuration service appropriate for each platform.
|
||||
ProxyConfigService* proxy_config_service = pc ?
|
||||
new ProxyConfigServiceFixed(*pc) :
|
||||
CreateSystemProxyConfigService();
|
||||
CreateSystemProxyConfigService(io_loop);
|
||||
|
||||
// Try to choose a non-v8 proxy resolver implementation.
|
||||
return new ProxyService(proxy_config_service, CreateNonV8ProxyResolver());
|
||||
ProxyResolver* proxy_resolver = use_v8_resolver ?
|
||||
new ProxyResolverV8() : CreateNonV8ProxyResolver();
|
||||
|
||||
ProxyService* proxy_service = new ProxyService(
|
||||
proxy_config_service, proxy_resolver);
|
||||
|
||||
if (!proxy_resolver->does_fetch()) {
|
||||
// Configure PAC script downloads to be issued using |url_request_context|.
|
||||
DCHECK(url_request_context);
|
||||
proxy_service->SetProxyScriptFetcher(
|
||||
ProxyScriptFetcher::Create(url_request_context));
|
||||
}
|
||||
|
||||
return proxy_service;
|
||||
}
|
||||
|
||||
// static
|
||||
ProxyService* ProxyService::CreateUsingV8Resolver(
|
||||
const ProxyConfig* pc, URLRequestContext* url_request_context) {
|
||||
// Choose the system configuration service appropriate for each platform.
|
||||
ProxyConfigService* proxy_config_service = pc ?
|
||||
new ProxyConfigServiceFixed(*pc) :
|
||||
CreateSystemProxyConfigService();
|
||||
|
||||
// Create a ProxyService that uses V8 to evaluate PAC scripts.
|
||||
ProxyService* proxy_service = new ProxyService(
|
||||
proxy_config_service, new ProxyResolverV8());
|
||||
|
||||
// Configure PAC script downloads to be issued using |url_request_context|.
|
||||
proxy_service->SetProxyScriptFetcher(
|
||||
ProxyScriptFetcher::Create(url_request_context));
|
||||
|
||||
return proxy_service;
|
||||
ProxyService* ProxyService::CreateFixed(const ProxyConfig& pc) {
|
||||
return Create(&pc, false, NULL, NULL);
|
||||
}
|
||||
|
||||
// static
|
||||
@ -529,13 +531,28 @@ void ProxyService::DidCompletePacRequest(int config_id, int result_code) {
|
||||
}
|
||||
|
||||
// static
|
||||
ProxyConfigService* ProxyService::CreateSystemProxyConfigService() {
|
||||
ProxyConfigService* ProxyService::CreateSystemProxyConfigService(
|
||||
MessageLoop* io_loop) {
|
||||
#if defined(OS_WIN)
|
||||
return new ProxyConfigServiceWin();
|
||||
#elif defined(OS_MACOSX)
|
||||
return new ProxyConfigServiceMac();
|
||||
#elif defined(OS_LINUX)
|
||||
return new ProxyConfigServiceLinux();
|
||||
ProxyConfigServiceLinux* linux_config_service
|
||||
= new ProxyConfigServiceLinux();
|
||||
|
||||
// Assume we got called from the UI loop, which runs the default
|
||||
// glib main loop, so the current thread is where we should be
|
||||
// running gconf calls from.
|
||||
MessageLoop* glib_default_loop = MessageLoopForUI::current();
|
||||
|
||||
// Synchronously fetch the current proxy config (since we are
|
||||
// running on glib_default_loop). Additionally register for gconf
|
||||
// notifications (delivered in |glib_default_loop|) to keep us
|
||||
// updated on when the proxy config has changed.
|
||||
linux_config_service->SetupAndFetchInitialConfig(glib_default_loop, io_loop);
|
||||
|
||||
return linux_config_service;
|
||||
#else
|
||||
LOG(WARNING) << "Failed to choose a system proxy settings fetcher "
|
||||
"for this platform.";
|
||||
|
@ -89,21 +89,29 @@ class ProxyService {
|
||||
// Creates a proxy service using the specified settings. If |pc| is NULL then
|
||||
// the system's default proxy settings will be used (on Windows this will
|
||||
// use IE's settings).
|
||||
static ProxyService* Create(const ProxyConfig* pc);
|
||||
|
||||
// Creates a proxy service using the specified settings. If |pc| is NULL then
|
||||
// the system's default proxy settings will be used. This is basically the
|
||||
// same as Create(const ProxyConfig*), however under the hood it uses a
|
||||
// different implementation (V8). |url_request_context| is the URL request
|
||||
// context that will be used if a PAC script needs to be fetched.
|
||||
// Iff |use_v8_resolver| is true, then the V8 implementation is
|
||||
// used.
|
||||
// |url_request_context| is only used when use_v8_resolver is true:
|
||||
// it specifies the URL request context that will be used if a PAC
|
||||
// script needs to be fetched.
|
||||
// |io_loop| points to the IO thread's message loop. It is only used
|
||||
// when pc is NULL. If both pc and io_loop are NULL, then monitoring
|
||||
// of gconf setting changes will be disabled in
|
||||
// ProxyConfigServiceLinux.
|
||||
// ##########################################################################
|
||||
// # See the warnings in net/proxy/proxy_resolver_v8.h describing the
|
||||
// # multi-threading model. In order for this to be safe to use, *ALL* the
|
||||
// # other V8's running in the process must use v8::Locker.
|
||||
// ##########################################################################
|
||||
static ProxyService* CreateUsingV8Resolver(
|
||||
static ProxyService* Create(
|
||||
const ProxyConfig* pc,
|
||||
URLRequestContext* url_request_context);
|
||||
bool use_v8_resolver,
|
||||
URLRequestContext* url_request_context,
|
||||
MessageLoop* io_loop);
|
||||
|
||||
// Convenience method that creates a proxy service using the
|
||||
// specified fixed settings. |pc| must not be NULL.
|
||||
static ProxyService* CreateFixed(const ProxyConfig& pc);
|
||||
|
||||
// Creates a proxy service that always fails to fetch the proxy configuration,
|
||||
// so it falls back to direct connect.
|
||||
@ -114,7 +122,8 @@ class ProxyService {
|
||||
|
||||
// Creates a config service appropriate for this platform that fetches the
|
||||
// system proxy settings.
|
||||
static ProxyConfigService* CreateSystemProxyConfigService();
|
||||
static ProxyConfigService* CreateSystemProxyConfigService(
|
||||
MessageLoop* io_loop);
|
||||
|
||||
// Creates a proxy resolver appropriate for this platform that doesn't rely
|
||||
// on V8.
|
||||
|
@ -50,7 +50,7 @@ class TestURLRequestContext : public URLRequestContext {
|
||||
explicit TestURLRequestContext(const std::string& proxy) {
|
||||
net::ProxyConfig proxy_config;
|
||||
proxy_config.proxy_rules.ParseFromString(proxy);
|
||||
proxy_service_ = net::ProxyService::Create(&proxy_config);
|
||||
proxy_service_ = net::ProxyService::CreateFixed(proxy_config);
|
||||
http_transaction_factory_ =
|
||||
net::HttpNetworkLayer::CreateFactory(proxy_service_);
|
||||
}
|
||||
|
@ -76,7 +76,7 @@ int main(int argc, char* argv[]) {
|
||||
|
||||
// Allocate a message loop for this thread. Although it is not used
|
||||
// directly, its constructor sets up some necessary state.
|
||||
MessageLoop main_message_loop;
|
||||
MessageLoopForUI main_message_loop;
|
||||
|
||||
// Load ICU data tables
|
||||
icu_util::Initialize();
|
||||
|
@ -30,7 +30,8 @@ void TestShellRequestContext::Init(
|
||||
accept_charset_ = "iso-8859-1,*,utf-8";
|
||||
|
||||
net::ProxyConfig proxy_config;
|
||||
proxy_service_ = net::ProxyService::Create(no_proxy ? &proxy_config : NULL);
|
||||
proxy_service_ = net::ProxyService::Create(no_proxy ? &proxy_config : NULL,
|
||||
false, NULL, NULL);
|
||||
|
||||
net::HttpCache *cache;
|
||||
if (cache_path.empty()) {
|
||||
|
Reference in New Issue
Block a user