• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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