xref: /aosp_15_r20/external/cronet/net/proxy_resolution/proxy_config_service_linux.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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           return PROXY_HTTP_PORT;  // Placate compiler.
120       }
121     }
122 
123     // Gets a string type value from the data source and stores it in
124     // |*result|. Returns false if the key is unset or on error. Must only be
125     // called after a successful call to Init(), and not after a failed call
126     // to SetUpNotifications() or after calling Release().
127     virtual bool GetString(StringSetting key, std::string* result) = 0;
128     // Same thing for a bool typed value.
129     virtual bool GetBool(BoolSetting key, bool* result) = 0;
130     // Same for an int typed value.
131     virtual bool GetInt(IntSetting key, int* result) = 0;
132     // And for a string list.
133     virtual bool GetStringList(StringListSetting key,
134                                std::vector<std::string>* result) = 0;
135 
136     // Returns true if the bypass list should be interpreted as a proxy
137     // allow list rather than block list. (This is KDE-specific.)
138     virtual bool BypassListIsReversed() = 0;
139 
140     // Returns true if bypass rules should evaluate using dumb string suffix
141     // matches on the host. For instance when true, "notgoogle.com" will be
142     // considered a match for "google.com", even though the bypass rule does not
143     // include a wildcard, and the matched host is not a subdomain.
144     virtual bool UseSuffixMatching() = 0;
145   };
146 
147   // ProxyConfigServiceLinux is created on the glib thread, and
148   // SetUpAndFetchInitialConfig() is immediately called to synchronously
149   // fetch the original configuration and set up change notifications on
150   // the ProxyConfigService's main SequencedTaskRunner, which is passed to its
151   // constructor (Which may or may not run tasks on the glib thread).
152   //
153   // Past that point, it is accessed periodically through the
154   // ProxyConfigService interface (GetLatestProxyConfig, AddObserver,
155   // RemoveObserver) from the main TaskRunner.
156   //
157   // Setting change notification callbacks can occur at any time and are
158   // run on either the glib thread (gconf/gsettings) or a separate file thread
159   // (KDE). The new settings are fetched on that thread, and the resulting proxy
160   // config is posted to the main TaskRunner through
161   // Delegate::SetNewProxyConfig(). We then notify observers on that TaskRunner
162   // of the configuration change.
163   //
164   // ProxyConfigServiceLinux is deleted from the main TaskRunner.
165   //
166   // The substance of the ProxyConfigServiceLinux implementation is
167   // wrapped in the Delegate ref counted class. On deleting the
168   // ProxyConfigServiceLinux, Delegate::OnDestroy() is posted to either
169   // the glib thread (gconf/gsettings) or a file thread (KDE) where change
170   // notifications will be safely stopped before releasing Delegate.
171 
172   class Delegate : public base::RefCountedThreadSafe<Delegate> {
173    public:
174     // Test code can set |setting_getter| and |traffic_annotation|. If left
175     // unspecified, reasonable defaults will be used.
176     Delegate(std::unique_ptr<base::Environment> env_var_getter,
177              std::optional<std::unique_ptr<SettingGetter>> setting_getter,
178              std::optional<NetworkTrafficAnnotationTag> traffic_annotation);
179 
180     Delegate(const Delegate&) = delete;
181     Delegate& operator=(const Delegate&) = delete;
182 
183     // Synchronously obtains the proxy configuration. If gconf,
184     // gsettings, or kioslaverc are used, also enables notifications for
185     // setting changes. gconf/gsettings must only be accessed from the
186     // thread running the default glib main loop, and so this method
187     // must be called from the glib thread. The message loop for the
188     // ProxyConfigService's main SequencedTaskRunner is specified so that
189     // notifications can post tasks to it (and for assertions).
190     void SetUpAndFetchInitialConfig(
191         const scoped_refptr<base::SingleThreadTaskRunner>& glib_task_runner,
192         const scoped_refptr<base::SequencedTaskRunner>& main_task_runner,
193         const NetworkTrafficAnnotationTag& traffic_annotation);
194 
195     // Handler for setting change notifications: fetches a new proxy
196     // configuration from settings, and if this config is different
197     // than what we had before, posts a task to have it stored in
198     // cached_config_.
199     // Left public for simplicity.
200     void OnCheckProxyConfigSettings();
201 
202     // Called on the service's main TaskRunner.
203     void AddObserver(Observer* observer);
204     void RemoveObserver(Observer* observer);
205     ProxyConfigService::ConfigAvailability GetLatestProxyConfig(
206         ProxyConfigWithAnnotation* config);
207 
208     // Posts a call to OnDestroy() to the glib or a file task runner,
209     // depending on the setting getter in use. Called from
210     // ProxyConfigServiceLinux's destructor.
211     void PostDestroyTask();
212     // Safely stops change notifications. Posted to either the glib thread or
213     // sequenced task runner, depending on the setting getter in use.
214     void OnDestroy();
215 
216    private:
217     friend class base::RefCountedThreadSafe<Delegate>;
218 
219     ~Delegate();
220 
221     // Obtains an environment variable's value. Parses a proxy chain
222     // specification from it and puts it in result. Returns true if the
223     // requested variable is defined and the value valid.
224     bool GetProxyFromEnvVarForScheme(std::string_view variable,
225                                      ProxyServer::Scheme scheme,
226                                      ProxyChain* result_chain);
227     // As above but with scheme set to HTTP, for convenience.
228     bool GetProxyFromEnvVar(std::string_view variable,
229                             ProxyChain* result_chain);
230     // Returns a proxy config based on the environment variables, or empty value
231     // on failure.
232     std::optional<ProxyConfigWithAnnotation> GetConfigFromEnv();
233 
234     // Obtains host and port config settings and parses a proxy server
235     // specification from it and puts it in result. Returns true if the
236     // requested variable is defined and the value valid.
237     bool GetProxyFromSettings(SettingGetter::StringSetting host_key,
238                               ProxyServer* result_server);
239     // Returns a proxy config based on the settings, or empty value
240     // on failure.
241     std::optional<ProxyConfigWithAnnotation> GetConfigFromSettings();
242 
243     // This method is posted from the glib thread to the main TaskRunner to
244     // carry the new config information.
245     void SetNewProxyConfig(
246         const std::optional<ProxyConfigWithAnnotation>& new_config);
247 
248     // This method is run on the getter's notification thread.
249     void SetUpNotifications();
250 
251     std::unique_ptr<base::Environment> env_var_getter_;
252     std::unique_ptr<SettingGetter> setting_getter_;
253 
254     // Cached proxy configuration, to be returned by
255     // GetLatestProxyConfig. Initially populated from the glib thread, but
256     // afterwards only accessed from the main TaskRunner.
257     std::optional<ProxyConfigWithAnnotation> cached_config_;
258 
259     // A copy kept on the glib thread of the last seen proxy config, so as
260     // to avoid posting a call to SetNewProxyConfig when we get a
261     // notification but the config has not actually changed.
262     std::optional<ProxyConfigWithAnnotation> reference_config_;
263 
264     // The task runner for the glib thread, aka main browser thread. This thread
265     // is where we run the glib main loop (see
266     // base/message_loop/message_pump_glib.h). It is the glib default loop in
267     // the sense that it runs the glib default context: as in the context where
268     // sources are added by g_timeout_add and g_idle_add, and returned by
269     // g_main_context_default. gconf uses glib timeouts and idles and possibly
270     // other callbacks that will all be dispatched on this thread. Since gconf
271     // is not thread safe, any use of gconf must be done on the thread running
272     // this loop.
273     scoped_refptr<base::SingleThreadTaskRunner> glib_task_runner_;
274     // Task runner for the main TaskRunner. GetLatestProxyConfig() is called
275     // from the thread running this loop.
276     scoped_refptr<base::SequencedTaskRunner> main_task_runner_;
277 
278     base::ObserverList<Observer>::Unchecked observers_;
279 
280     MutableNetworkTrafficAnnotationTag traffic_annotation_;
281   };
282 
283   // Thin wrapper shell around Delegate.
284 
285   // Usual constructor
286   ProxyConfigServiceLinux();
287 
288   // For testing: take alternate setting and env var getter implementations.
289   explicit ProxyConfigServiceLinux(
290       std::unique_ptr<base::Environment> env_var_getter,
291       const NetworkTrafficAnnotationTag& traffic_annotation);
292   ProxyConfigServiceLinux(
293       std::unique_ptr<base::Environment> env_var_getter,
294       std::unique_ptr<SettingGetter> setting_getter,
295       const NetworkTrafficAnnotationTag& traffic_annotation);
296 
297   ProxyConfigServiceLinux(const ProxyConfigServiceLinux&) = delete;
298   ProxyConfigServiceLinux& operator=(const ProxyConfigServiceLinux&) = delete;
299 
300   ~ProxyConfigServiceLinux() override;
301 
SetupAndFetchInitialConfig(const scoped_refptr<base::SingleThreadTaskRunner> & glib_task_runner,const scoped_refptr<base::SequencedTaskRunner> & main_task_runner,const NetworkTrafficAnnotationTag & traffic_annotation)302   void SetupAndFetchInitialConfig(
303       const scoped_refptr<base::SingleThreadTaskRunner>& glib_task_runner,
304       const scoped_refptr<base::SequencedTaskRunner>& main_task_runner,
305       const NetworkTrafficAnnotationTag& traffic_annotation) {
306     delegate_->SetUpAndFetchInitialConfig(glib_task_runner, main_task_runner,
307                                           traffic_annotation);
308   }
OnCheckProxyConfigSettings()309   void OnCheckProxyConfigSettings() {
310     delegate_->OnCheckProxyConfigSettings();
311   }
312 
313   // ProxyConfigService methods:
314   // Called from main TaskRunner.
315   void AddObserver(Observer* observer) override;
316   void RemoveObserver(Observer* observer) override;
317   ProxyConfigService::ConfigAvailability GetLatestProxyConfig(
318       ProxyConfigWithAnnotation* config) override;
319 
320  private:
321   scoped_refptr<Delegate> delegate_;
322 };
323 
324 }  // namespace net
325 
326 #endif  // NET_PROXY_RESOLUTION_PROXY_CONFIG_SERVICE_LINUX_H_
327