• 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 <optional>
12 #include <string>
13 #include <string_view>
14 #include <vector>
15 
16 #include "base/compiler_specific.h"
17 #include "base/environment.h"
18 #include "base/memory/ref_counted.h"
19 #include "base/notreached.h"
20 #include "base/observer_list.h"
21 #include "net/base/net_export.h"
22 #include "net/base/proxy_server.h"
23 #include "net/proxy_resolution/proxy_config_service.h"
24 #include "net/proxy_resolution/proxy_config_with_annotation.h"
25 
26 namespace base {
27 class SingleThreadTaskRunner;
28 class SequencedTaskRunner;
29 }  // namespace base
30 
31 namespace net {
32 
33 // Implementation of ProxyConfigService that retrieves the system proxy
34 // settings from environment variables, gconf, gsettings, or kioslaverc (KDE).
35 class NET_EXPORT_PRIVATE ProxyConfigServiceLinux : public ProxyConfigService {
36  public:
37   class Delegate;
38 
39   class SettingGetter {
40    public:
41     // Buffer size used in some implementations of this class when reading
42     // files. Defined here so unit tests can construct worst-case inputs.
43     static const size_t BUFFER_SIZE = 512;
44 
45     SettingGetter() = default;
46 
47     SettingGetter(const SettingGetter&) = delete;
48     SettingGetter& operator=(const SettingGetter&) = delete;
49 
50     virtual ~SettingGetter() = default;
51 
52     // Initializes the class: obtains a gconf/gsettings client, or simulates
53     // one, in the concrete implementations. Returns true on success. Must be
54     // called before using other methods, and should be called on the thread
55     // running the glib main loop.
56     // This interface supports both GNOME and KDE implementations. In the
57     // case of GNOME, the glib_task_runner will be used for interacting with
58     // gconf/gsettings as those APIs have thread affinity. Whereas in the case
59     // of KDE, its configuration files will be monitored at well-known locations
60     // and glib_task_runner will not be used. Instead, blocking file I/O
61     // operations will be posted directly using the task scheduler.
62     virtual bool Init(const scoped_refptr<base::SingleThreadTaskRunner>&
63                           glib_task_runner) = 0;
64 
65     // Releases the gconf/gsettings client, which clears cached directories and
66     // stops notifications.
67     virtual void ShutDown() = 0;
68 
69     // Requests notification of gconf/gsettings changes for proxy
70     // settings. Returns true on success.
71     virtual bool SetUpNotifications(Delegate* delegate) = 0;
72 
73     // Returns the message loop for the thread on which this object
74     // handles notifications, and also on which it must be destroyed.
75     // Returns NULL if it does not matter.
76     virtual const scoped_refptr<base::SequencedTaskRunner>&
77     GetNotificationTaskRunner() = 0;
78 
79     // These are all the values that can be fetched. We used to just use the
80     // corresponding paths in gconf for these, but gconf is now obsolete and
81     // in the future we'll be using mostly gsettings/kioslaverc so we
82     // enumerate them instead to avoid unnecessary string operations.
83     enum StringSetting {
84       PROXY_MODE,
85       PROXY_AUTOCONF_URL,
86       PROXY_HTTP_HOST,
87       PROXY_HTTPS_HOST,
88       PROXY_FTP_HOST,
89       PROXY_SOCKS_HOST,
90     };
91     enum BoolSetting {
92       PROXY_USE_HTTP_PROXY,
93       PROXY_USE_SAME_PROXY,
94       PROXY_USE_AUTHENTICATION,
95     };
96     enum IntSetting {
97       PROXY_HTTP_PORT,
98       PROXY_HTTPS_PORT,
99       PROXY_FTP_PORT,
100       PROXY_SOCKS_PORT,
101     };
102     enum StringListSetting {
103       PROXY_IGNORE_HOSTS,
104     };
105 
106     // Given a PROXY_*_HOST value, return the corresponding PROXY_*_PORT value.
HostSettingToPortSetting(StringSetting host)107     static IntSetting HostSettingToPortSetting(StringSetting host) {
108       switch (host) {
109         case PROXY_HTTP_HOST:
110           return PROXY_HTTP_PORT;
111         case PROXY_HTTPS_HOST:
112           return PROXY_HTTPS_PORT;
113         case PROXY_FTP_HOST:
114           return PROXY_FTP_PORT;
115         case PROXY_SOCKS_HOST:
116           return PROXY_SOCKS_PORT;
117         default:
118           NOTREACHED();
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              std::optional<std::unique_ptr<SettingGetter>> setting_getter,
177              std::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 chain
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(std::string_view variable,
224                                      ProxyServer::Scheme scheme,
225                                      ProxyChain* result_chain);
226     // As above but with scheme set to HTTP, for convenience.
227     bool GetProxyFromEnvVar(std::string_view variable,
228                             ProxyChain* result_chain);
229     // Returns a proxy config based on the environment variables, or empty value
230     // on failure.
231     std::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     std::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 std::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     std::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     std::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