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