1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef NET_PROXY_PROXY_CONFIG_SERVICE_LINUX_H_ 6 #define NET_PROXY_PROXY_CONFIG_SERVICE_LINUX_H_ 7 #pragma once 8 9 #include <string> 10 #include <vector> 11 12 #include "base/basictypes.h" 13 #include "base/environment.h" 14 #include "base/memory/ref_counted.h" 15 #include "base/memory/scoped_ptr.h" 16 #include "base/message_loop.h" 17 #include "base/observer_list.h" 18 #include "net/proxy/proxy_config.h" 19 #include "net/proxy/proxy_config_service.h" 20 #include "net/proxy/proxy_server.h" 21 22 namespace net { 23 24 // Implementation of ProxyConfigService that retrieves the system proxy 25 // settings from environment variables or gconf. 26 class ProxyConfigServiceLinux : public ProxyConfigService { 27 public: 28 29 // Forward declaration of Delegate. 30 class Delegate; 31 32 class GConfSettingGetter { 33 public: 34 // Buffer size used in some implementations of this class when reading 35 // files. Defined here so unit tests can construct worst-case inputs. 36 static const size_t BUFFER_SIZE = 512; 37 GConfSettingGetter()38 GConfSettingGetter() {} ~GConfSettingGetter()39 virtual ~GConfSettingGetter() {} 40 41 // Initializes the class: obtains a gconf client, or simulates one, in 42 // the concrete implementations. Returns true on success. Must be called 43 // before using other methods, and should be called on the thread running 44 // the glib main loop. 45 // One of |glib_default_loop| and |file_loop| will be used for gconf calls 46 // or reading necessary files, depending on the implementation. 47 virtual bool Init(MessageLoop* glib_default_loop, 48 MessageLoopForIO* file_loop) = 0; 49 50 // Releases the gconf client, which clears cached directories and 51 // stops notifications. 52 virtual void Shutdown() = 0; 53 54 // Requests notification of gconf setting changes for proxy 55 // settings. Returns true on success. 56 virtual bool SetupNotification(Delegate* delegate) = 0; 57 58 // Returns the message loop for the thread on which this object 59 // handles notifications, and also on which it must be destroyed. 60 // Returns NULL if it does not matter. 61 virtual MessageLoop* GetNotificationLoop() = 0; 62 63 // Returns the data source's name (e.g. "gconf", "KDE", "test"). 64 // Used only for diagnostic purposes (e.g. VLOG(1) etc.). 65 virtual const char* GetDataSource() = 0; 66 67 // Gets a string type value from gconf and stores it in 68 // result. Returns false if the key is unset or on error. Must 69 // only be called after a successful call to Init(), and not 70 // after a failed call to SetupNotification() or after calling 71 // Release(). 72 virtual bool GetString(const char* key, std::string* result) = 0; 73 // Same thing for a bool typed value. 74 virtual bool GetBoolean(const char* key, bool* result) = 0; 75 // Same for an int typed value. 76 virtual bool GetInt(const char* key, int* result) = 0; 77 // And for a string list. 78 virtual bool GetStringList(const char* key, 79 std::vector<std::string>* result) = 0; 80 81 // Returns true if the bypass list should be interpreted as a proxy 82 // whitelist rather than blacklist. (This is KDE-specific.) 83 virtual bool BypassListIsReversed() = 0; 84 85 // Returns true if the bypass rules should be interpreted as 86 // suffix-matching rules. 87 virtual bool MatchHostsUsingSuffixMatching() = 0; 88 89 private: 90 DISALLOW_COPY_AND_ASSIGN(GConfSettingGetter); 91 }; 92 93 // ProxyConfigServiceLinux is created on the UI thread, and 94 // SetupAndFetchInitialConfig() is immediately called to 95 // synchronously fetch the original configuration and set up gconf 96 // notifications on the UI thread. 97 // 98 // Past that point, it is accessed periodically through the 99 // ProxyConfigService interface (GetLatestProxyConfig, AddObserver, 100 // RemoveObserver) from the IO thread. 101 // 102 // gconf change notification callbacks can occur at any time and are 103 // run on the UI thread. The new gconf settings are fetched on the 104 // UI thread, and the new resulting proxy config is posted to the IO 105 // thread through Delegate::SetNewProxyConfig(). We then notify 106 // observers on the IO thread of the configuration change. 107 // 108 // ProxyConfigServiceLinux is deleted from the IO thread. 109 // 110 // The substance of the ProxyConfigServiceLinux implementation is 111 // wrapped in the Delegate ref counted class. On deleting the 112 // ProxyConfigServiceLinux, Delegate::OnDestroy() is posted to the 113 // UI thread where gconf notifications will be safely stopped before 114 // releasing Delegate. 115 116 class Delegate : public base::RefCountedThreadSafe<Delegate> { 117 public: 118 // Constructor receives env var getter implementation to use, and 119 // takes ownership of it. This is the normal constructor. 120 explicit Delegate(base::Environment* env_var_getter); 121 // Constructor receives gconf and env var getter implementations 122 // to use, and takes ownership of them. Used for testing. 123 Delegate(base::Environment* env_var_getter, 124 GConfSettingGetter* gconf_getter); 125 // Synchronously obtains the proxy configuration. If gconf is 126 // used, also enables gconf notification for setting 127 // changes. gconf must only be accessed from the thread running 128 // the default glib main loop, and so this method must be called 129 // from the UI thread. The message loop for the IO thread is 130 // specified so that notifications can post tasks to it (and for 131 // assertions). The message loop for the file thread is used to 132 // read any files needed to determine proxy settings. 133 void SetupAndFetchInitialConfig(MessageLoop* glib_default_loop, 134 MessageLoop* io_loop, 135 MessageLoopForIO* file_loop); 136 137 // Handler for gconf change notifications: fetches a new proxy 138 // configuration from gconf settings, and if this config is 139 // different than what we had before, posts a task to have it 140 // stored in cached_config_. 141 // Left public for simplicity. 142 void OnCheckProxyConfigSettings(); 143 144 // Called from IO thread. 145 void AddObserver(Observer* observer); 146 void RemoveObserver(Observer* observer); 147 ProxyConfigService::ConfigAvailability GetLatestProxyConfig( 148 ProxyConfig* config); 149 150 // Posts a call to OnDestroy() to the UI thread. Called from 151 // ProxyConfigServiceLinux's destructor. 152 void PostDestroyTask(); 153 // Safely stops gconf notifications. Posted to the UI thread. 154 void OnDestroy(); 155 156 private: 157 friend class base::RefCountedThreadSafe<Delegate>; 158 159 ~Delegate(); 160 161 // Obtains an environment variable's value. Parses a proxy server 162 // specification from it and puts it in result. Returns true if the 163 // requested variable is defined and the value valid. 164 bool GetProxyFromEnvVarForScheme(const char* variable, 165 ProxyServer::Scheme scheme, 166 ProxyServer* result_server); 167 // As above but with scheme set to HTTP, for convenience. 168 bool GetProxyFromEnvVar(const char* variable, ProxyServer* result_server); 169 // Fills proxy config from environment variables. Returns true if 170 // variables were found and the configuration is valid. 171 bool GetConfigFromEnv(ProxyConfig* config); 172 173 // Obtains host and port gconf settings and parses a proxy server 174 // specification from it and puts it in result. Returns true if the 175 // requested variable is defined and the value valid. 176 bool GetProxyFromGConf(const char* key_prefix, bool is_socks, 177 ProxyServer* result_server); 178 // Fills proxy config from gconf. Returns true if settings were found 179 // and the configuration is valid. 180 bool GetConfigFromGConf(ProxyConfig* config); 181 182 // This method is posted from the UI thread to the IO thread to 183 // carry the new config information. 184 void SetNewProxyConfig(const ProxyConfig& new_config); 185 186 scoped_ptr<base::Environment> env_var_getter_; 187 scoped_ptr<GConfSettingGetter> gconf_getter_; 188 189 // Cached proxy configuration, to be returned by 190 // GetLatestProxyConfig. Initially populated from the UI thread, but 191 // afterwards only accessed from the IO thread. 192 ProxyConfig cached_config_; 193 194 // A copy kept on the UI thread of the last seen proxy config, so as 195 // to avoid posting a call to SetNewProxyConfig when we get a 196 // notification but the config has not actually changed. 197 ProxyConfig reference_config_; 198 199 // The MessageLoop for the UI thread, aka main browser thread. This 200 // thread is where we run the glib main loop (see 201 // base/message_pump_glib.h). It is the glib default loop in the 202 // sense that it runs the glib default context: as in the context 203 // where sources are added by g_timeout_add and g_idle_add, and 204 // returned by g_main_context_default. gconf uses glib timeouts and 205 // idles and possibly other callbacks that will all be dispatched on 206 // this thread. Since gconf is not thread safe, any use of gconf 207 // must be done on the thread running this loop. 208 MessageLoop* glib_default_loop_; 209 // MessageLoop for the IO thread. GetLatestProxyConfig() is called from 210 // the thread running this loop. 211 MessageLoop* io_loop_; 212 213 ObserverList<Observer> observers_; 214 215 DISALLOW_COPY_AND_ASSIGN(Delegate); 216 }; 217 218 // Thin wrapper shell around Delegate. 219 220 // Usual constructor 221 ProxyConfigServiceLinux(); 222 // For testing: take alternate gconf and env var getter implementations. 223 explicit ProxyConfigServiceLinux(base::Environment* env_var_getter); 224 ProxyConfigServiceLinux(base::Environment* env_var_getter, 225 GConfSettingGetter* gconf_getter); 226 227 virtual ~ProxyConfigServiceLinux(); 228 SetupAndFetchInitialConfig(MessageLoop * glib_default_loop,MessageLoop * io_loop,MessageLoopForIO * file_loop)229 void SetupAndFetchInitialConfig(MessageLoop* glib_default_loop, 230 MessageLoop* io_loop, 231 MessageLoopForIO* file_loop) { 232 delegate_->SetupAndFetchInitialConfig(glib_default_loop, io_loop, 233 file_loop); 234 } OnCheckProxyConfigSettings()235 void OnCheckProxyConfigSettings() { 236 delegate_->OnCheckProxyConfigSettings(); 237 } 238 239 // ProxyConfigService methods: 240 // Called from IO thread. 241 virtual void AddObserver(Observer* observer); 242 virtual void RemoveObserver(Observer* observer); 243 virtual ProxyConfigService::ConfigAvailability GetLatestProxyConfig( 244 ProxyConfig* config); 245 246 private: 247 scoped_refptr<Delegate> delegate_; 248 249 DISALLOW_COPY_AND_ASSIGN(ProxyConfigServiceLinux); 250 }; 251 252 } // namespace net 253 254 #endif // NET_PROXY_PROXY_CONFIG_SERVICE_LINUX_H_ 255