Index: net/proxy/proxy_config_service_linux.h |
=================================================================== |
--- net/proxy/proxy_config_service_linux.h (revision 16488) |
+++ net/proxy/proxy_config_service_linux.h (working copy) |
@@ -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 @@ |
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,42 +64,155 @@ |
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); |
+ scoped_refptr<Delegate> delegate_; |
- // 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_; |
- |
DISALLOW_COPY_AND_ASSIGN(ProxyConfigServiceLinux); |
}; |