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
22namespace net {
23
24// Implementation of ProxyConfigService that retrieves the system proxy
25// settings from environment variables or gconf.
26class 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
38    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
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  }
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