• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2012 The Chromium Authors
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_RESOLUTION_PROXY_CONFIG_SERVICE_LINUX_H_
6 #define NET_PROXY_RESOLUTION_PROXY_CONFIG_SERVICE_LINUX_H_
7 
8 #include <stddef.h>
9 
10 #include <memory>
11 #include <string>
12 #include <vector>
13 
14 #include "base/compiler_specific.h"
15 #include "base/environment.h"
16 #include "base/memory/ref_counted.h"
17 #include "base/notreached.h"
18 #include "base/observer_list.h"
19 #include "net/base/net_export.h"
20 #include "net/base/proxy_server.h"
21 #include "net/proxy_resolution/proxy_config_service.h"
22 #include "net/proxy_resolution/proxy_config_with_annotation.h"
23 #include "third_party/abseil-cpp/absl/types/optional.h"
24 
25 namespace base {
26 class SingleThreadTaskRunner;
27 class SequencedTaskRunner;
28 }  // namespace base
29 
30 namespace net {
31 
32 // Implementation of ProxyConfigService that retrieves the system proxy
33 // settings from environment variables, gconf, gsettings, or kioslaverc (KDE).
34 class NET_EXPORT_PRIVATE ProxyConfigServiceLinux : public ProxyConfigService {
35  public:
36   class Delegate;
37 
38   class SettingGetter {
39    public:
40     // Buffer size used in some implementations of this class when reading
41     // files. Defined here so unit tests can construct worst-case inputs.
42     static const size_t BUFFER_SIZE = 512;
43 
44     SettingGetter() = default;
45 
46     SettingGetter(const SettingGetter&) = delete;
47     SettingGetter& operator=(const SettingGetter&) = delete;
48 
49     virtual ~SettingGetter() = default;
50 
51     // Initializes the class: obtains a gconf/gsettings client, or simulates
52     // one, in the concrete implementations. Returns true on success. Must be
53     // called before using other methods, and should be called on the thread
54     // running the glib main loop.
55     // This interface supports both GNOME and KDE implementations. In the
56     // case of GNOME, the glib_task_runner will be used for interacting with
57     // gconf/gsettings as those APIs have thread affinity. Whereas in the case
58     // of KDE, its configuration files will be monitored at well-known locations
59     // and glib_task_runner will not be used. Instead, blocking file I/O
60     // operations will be posted directly using the task scheduler.
61     virtual bool Init(const scoped_refptr<base::SingleThreadTaskRunner>&
62                           glib_task_runner) = 0;
63 
64     // Releases the gconf/gsettings client, which clears cached directories and
65     // stops notifications.
66     virtual void ShutDown() = 0;
67 
68     // Requests notification of gconf/gsettings changes for proxy
69     // settings. Returns true on success.
70     virtual bool SetUpNotifications(Delegate* delegate) = 0;
71 
72     // Returns the message loop for the thread on which this object
73     // handles notifications, and also on which it must be destroyed.
74     // Returns NULL if it does not matter.
75     virtual const scoped_refptr<base::SequencedTaskRunner>&
76     GetNotificationTaskRunner() = 0;
77 
78     // These are all the values that can be fetched. We used to just use the
79     // corresponding paths in gconf for these, but gconf is now obsolete and
80     // in the future we'll be using mostly gsettings/kioslaverc so we
81     // enumerate them instead to avoid unnecessary string operations.
82     enum StringSetting {
83       PROXY_MODE,
84       PROXY_AUTOCONF_URL,
85       PROXY_HTTP_HOST,
86       PROXY_HTTPS_HOST,
87       PROXY_FTP_HOST,
88       PROXY_SOCKS_HOST,
89     };
90     enum BoolSetting {
91       PROXY_USE_HTTP_PROXY,
92       PROXY_USE_SAME_PROXY,
93       PROXY_USE_AUTHENTICATION,
94     };
95     enum IntSetting {
96       PROXY_HTTP_PORT,
97       PROXY_HTTPS_PORT,
98       PROXY_FTP_PORT,
99       PROXY_SOCKS_PORT,
100     };
101     enum StringListSetting {
102       PROXY_IGNORE_HOSTS,
103     };
104 
105     // Given a PROXY_*_HOST value, return the corresponding PROXY_*_PORT value.
HostSettingToPortSetting(StringSetting host)106     static IntSetting HostSettingToPortSetting(StringSetting host) {
107       switch (host) {
108         case PROXY_HTTP_HOST:
109           return PROXY_HTTP_PORT;
110         case PROXY_HTTPS_HOST:
111           return PROXY_HTTPS_PORT;
112         case PROXY_FTP_HOST:
113           return PROXY_FTP_PORT;
114         case PROXY_SOCKS_HOST:
115           return PROXY_SOCKS_PORT;
116         default:
117           NOTREACHED();
118           return PROXY_HTTP_PORT;  // Placate compiler.
119       }
120     }
121 
122     // Gets a string type value from the data source and stores it in
123     // |*result|. Returns false if the key is unset or on error. Must only be
124     // called after a successful call to Init(), and not after a failed call
125     // to SetUpNotifications() or after calling Release().
126     virtual bool GetString(StringSetting key, std::string* result) = 0;
127     // Same thing for a bool typed value.
128     virtual bool GetBool(BoolSetting key, bool* result) = 0;
129     // Same for an int typed value.
130     virtual bool GetInt(IntSetting key, int* result) = 0;
131     // And for a string list.
132     virtual bool GetStringList(StringListSetting key,
133                                std::vector<std::string>* result) = 0;
134 
135     // Returns true if the bypass list should be interpreted as a proxy
136     // allow list rather than block list. (This is KDE-specific.)
137     virtual bool BypassListIsReversed() = 0;
138 
139     // Returns true if bypass rules should evaluate using dumb string suffix
140     // matches on the host. For instance when true, "notgoogle.com" will be
141     // considered a match for "google.com", even though the bypass rule does not
142     // include a wildcard, and the matched host is not a subdomain.
143     virtual bool UseSuffixMatching() = 0;
144   };
145 
146   // ProxyConfigServiceLinux is created on the glib thread, and
147   // SetUpAndFetchInitialConfig() is immediately called to synchronously
148   // fetch the original configuration and set up change notifications on
149   // the ProxyConfigService's main SequencedTaskRunner, which is passed to its
150   // constructor (Which may or may not run tasks on the glib thread).
151   //
152   // Past that point, it is accessed periodically through the
153   // ProxyConfigService interface (GetLatestProxyConfig, AddObserver,
154   // RemoveObserver) from the main TaskRunner.
155   //
156   // Setting change notification callbacks can occur at any time and are
157   // run on either the glib thread (gconf/gsettings) or a separate file thread
158   // (KDE). The new settings are fetched on that thread, and the resulting proxy
159   // config is posted to the main TaskRunner through
160   // Delegate::SetNewProxyConfig(). We then notify observers on that TaskRunner
161   // of the configuration change.
162   //
163   // ProxyConfigServiceLinux is deleted from the main TaskRunner.
164   //
165   // The substance of the ProxyConfigServiceLinux implementation is
166   // wrapped in the Delegate ref counted class. On deleting the
167   // ProxyConfigServiceLinux, Delegate::OnDestroy() is posted to either
168   // the glib thread (gconf/gsettings) or a file thread (KDE) where change
169   // notifications will be safely stopped before releasing Delegate.
170 
171   class Delegate : public base::RefCountedThreadSafe<Delegate> {
172    public:
173     // Test code can set |setting_getter| and |traffic_annotation|. If left
174     // unspecified, reasonable defaults will be used.
175     Delegate(std::unique_ptr<base::Environment> env_var_getter,
176              absl::optional<std::unique_ptr<SettingGetter>> setting_getter,
177              absl::optional<NetworkTrafficAnnotationTag> traffic_annotation);
178 
179     Delegate(const Delegate&) = delete;
180     Delegate& operator=(const Delegate&) = delete;
181 
182     // Synchronously obtains the proxy configuration. If gconf,
183     // gsettings, or kioslaverc are used, also enables notifications for
184     // setting changes. gconf/gsettings must only be accessed from the
185     // thread running the default glib main loop, and so this method
186     // must be called from the glib thread. The message loop for the
187     // ProxyConfigService's main SequencedTaskRunner is specified so that
188     // notifications can post tasks to it (and for assertions).
189     void SetUpAndFetchInitialConfig(
190         const scoped_refptr<base::SingleThreadTaskRunner>& glib_task_runner,
191         const scoped_refptr<base::SequencedTaskRunner>& main_task_runner,
192         const NetworkTrafficAnnotationTag& traffic_annotation);
193 
194     // Handler for setting change notifications: fetches a new proxy
195     // configuration from settings, and if this config is different
196     // than what we had before, posts a task to have it stored in
197     // cached_config_.
198     // Left public for simplicity.
199     void OnCheckProxyConfigSettings();
200 
201     // Called on the service's main TaskRunner.
202     void AddObserver(Observer* observer);
203     void RemoveObserver(Observer* observer);
204     ProxyConfigService::ConfigAvailability GetLatestProxyConfig(
205         ProxyConfigWithAnnotation* config);
206 
207     // Posts a call to OnDestroy() to the glib or a file task runner,
208     // depending on the setting getter in use. Called from
209     // ProxyConfigServiceLinux's destructor.
210     void PostDestroyTask();
211     // Safely stops change notifications. Posted to either the glib thread or
212     // sequenced task runner, depending on the setting getter in use.
213     void OnDestroy();
214 
215    private:
216     friend class base::RefCountedThreadSafe<Delegate>;
217 
218     ~Delegate();
219 
220     // Obtains an environment variable's value. Parses a proxy server
221     // specification from it and puts it in result. Returns true if the
222     // requested variable is defined and the value valid.
223     bool GetProxyFromEnvVarForScheme(base::StringPiece variable,
224                                      ProxyServer::Scheme scheme,
225                                      ProxyServer* result_server);
226     // As above but with scheme set to HTTP, for convenience.
227     bool GetProxyFromEnvVar(base::StringPiece variable,
228                             ProxyServer* result_server);
229     // Returns a proxy config based on the environment variables, or empty value
230     // on failure.
231     absl::optional<ProxyConfigWithAnnotation> GetConfigFromEnv();
232 
233     // Obtains host and port config settings and parses a proxy server
234     // specification from it and puts it in result. Returns true if the
235     // requested variable is defined and the value valid.
236     bool GetProxyFromSettings(SettingGetter::StringSetting host_key,
237                               ProxyServer* result_server);
238     // Returns a proxy config based on the settings, or empty value
239     // on failure.
240     absl::optional<ProxyConfigWithAnnotation> GetConfigFromSettings();
241 
242     // This method is posted from the glib thread to the main TaskRunner to
243     // carry the new config information.
244     void SetNewProxyConfig(
245         const absl::optional<ProxyConfigWithAnnotation>& new_config);
246 
247     // This method is run on the getter's notification thread.
248     void SetUpNotifications();
249 
250     std::unique_ptr<base::Environment> env_var_getter_;
251     std::unique_ptr<SettingGetter> setting_getter_;
252 
253     // Cached proxy configuration, to be returned by
254     // GetLatestProxyConfig. Initially populated from the glib thread, but
255     // afterwards only accessed from the main TaskRunner.
256     absl::optional<ProxyConfigWithAnnotation> cached_config_;
257 
258     // A copy kept on the glib thread of the last seen proxy config, so as
259     // to avoid posting a call to SetNewProxyConfig when we get a
260     // notification but the config has not actually changed.
261     absl::optional<ProxyConfigWithAnnotation> reference_config_;
262 
263     // The task runner for the glib thread, aka main browser thread. This thread
264     // is where we run the glib main loop (see
265     // base/message_loop/message_pump_glib.h). It is the glib default loop in
266     // the sense that it runs the glib default context: as in the context where
267     // sources are added by g_timeout_add and g_idle_add, and returned by
268     // g_main_context_default. gconf uses glib timeouts and idles and possibly
269     // other callbacks that will all be dispatched on this thread. Since gconf
270     // is not thread safe, any use of gconf must be done on the thread running
271     // this loop.
272     scoped_refptr<base::SingleThreadTaskRunner> glib_task_runner_;
273     // Task runner for the main TaskRunner. GetLatestProxyConfig() is called
274     // from the thread running this loop.
275     scoped_refptr<base::SequencedTaskRunner> main_task_runner_;
276 
277     base::ObserverList<Observer>::Unchecked observers_;
278 
279     MutableNetworkTrafficAnnotationTag traffic_annotation_;
280   };
281 
282   // Thin wrapper shell around Delegate.
283 
284   // Usual constructor
285   ProxyConfigServiceLinux();
286 
287   // For testing: take alternate setting and env var getter implementations.
288   explicit ProxyConfigServiceLinux(
289       std::unique_ptr<base::Environment> env_var_getter,
290       const NetworkTrafficAnnotationTag& traffic_annotation);
291   ProxyConfigServiceLinux(
292       std::unique_ptr<base::Environment> env_var_getter,
293       std::unique_ptr<SettingGetter> setting_getter,
294       const NetworkTrafficAnnotationTag& traffic_annotation);
295 
296   ProxyConfigServiceLinux(const ProxyConfigServiceLinux&) = delete;
297   ProxyConfigServiceLinux& operator=(const ProxyConfigServiceLinux&) = delete;
298 
299   ~ProxyConfigServiceLinux() override;
300 
SetupAndFetchInitialConfig(const scoped_refptr<base::SingleThreadTaskRunner> & glib_task_runner,const scoped_refptr<base::SequencedTaskRunner> & main_task_runner,const NetworkTrafficAnnotationTag & traffic_annotation)301   void SetupAndFetchInitialConfig(
302       const scoped_refptr<base::SingleThreadTaskRunner>& glib_task_runner,
303       const scoped_refptr<base::SequencedTaskRunner>& main_task_runner,
304       const NetworkTrafficAnnotationTag& traffic_annotation) {
305     delegate_->SetUpAndFetchInitialConfig(glib_task_runner, main_task_runner,
306                                           traffic_annotation);
307   }
OnCheckProxyConfigSettings()308   void OnCheckProxyConfigSettings() {
309     delegate_->OnCheckProxyConfigSettings();
310   }
311 
312   // ProxyConfigService methods:
313   // Called from main TaskRunner.
314   void AddObserver(Observer* observer) override;
315   void RemoveObserver(Observer* observer) override;
316   ProxyConfigService::ConfigAvailability GetLatestProxyConfig(
317       ProxyConfigWithAnnotation* config) override;
318 
319  private:
320   scoped_refptr<Delegate> delegate_;
321 };
322 
323 }  // namespace net
324 
325 #endif  // NET_PROXY_RESOLUTION_PROXY_CONFIG_SERVICE_LINUX_H_
326