xref: /aosp_15_r20/external/cronet/net/proxy_resolution/configured_proxy_resolution_service.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_CONFIGURED_PROXY_RESOLUTION_SERVICE_H_
6 #define NET_PROXY_RESOLUTION_CONFIGURED_PROXY_RESOLUTION_SERVICE_H_
7 
8 #include <stddef.h>
9 
10 #include <memory>
11 #include <optional>
12 #include <set>
13 #include <string>
14 #include <vector>
15 
16 #include "base/gtest_prod_util.h"
17 #include "base/memory/raw_ptr.h"
18 #include "base/synchronization/waitable_event.h"
19 #include "base/threading/thread_checker.h"
20 #include "net/base/completion_once_callback.h"
21 #include "net/base/load_states.h"
22 #include "net/base/net_errors.h"
23 #include "net/base/net_export.h"
24 #include "net/base/network_change_notifier.h"
25 #include "net/log/net_log_with_source.h"
26 #include "net/proxy_resolution/proxy_config_service.h"
27 #include "net/proxy_resolution/proxy_config_with_annotation.h"
28 #include "net/proxy_resolution/proxy_info.h"
29 #include "net/proxy_resolution/proxy_resolution_request.h"
30 #include "net/proxy_resolution/proxy_resolution_service.h"
31 #include "net/proxy_resolution/proxy_resolver.h"
32 #include "net/traffic_annotation/network_traffic_annotation.h"
33 #include "url/gurl.h"
34 
35 namespace base {
36 class TimeDelta;
37 }  // namespace base
38 
39 namespace net {
40 
41 class ConfiguredProxyResolutionRequest;
42 class DhcpPacFileFetcher;
43 class NetLog;
44 class PacFileFetcher;
45 class ProxyDelegate;
46 class ProxyResolverFactory;
47 struct PacFileDataWithSource;
48 
49 // This class decides which proxy server(s) to use for a particular URL request.
50 // It uses the given ProxyResolver to evaluate a PAC file, which the
51 // ConfiguredProxyResolutionService then uses to resolve a proxy.  All proxy
52 // resolution in this class is based on first getting proxy configurations (ex:
53 // a PAC URL) from some source and then using these configurations to attempt to
54 // resolve that proxy.
55 class NET_EXPORT ConfiguredProxyResolutionService
56     : public ProxyResolutionService,
57       public NetworkChangeNotifier::IPAddressObserver,
58       public NetworkChangeNotifier::DNSObserver,
59       public ProxyConfigService::Observer {
60  public:
61   // This interface defines the set of policies for when to poll the PAC
62   // script for changes.
63   //
64   // The polling policy decides what the next poll delay should be in
65   // milliseconds. It also decides how to wait for this delay -- either
66   // by starting a timer to do the poll at exactly |next_delay_ms|
67   // (MODE_USE_TIMER) or by waiting for the first network request issued after
68   // |next_delay_ms| (MODE_START_AFTER_ACTIVITY).
69   //
70   // The timer method is more precise and guarantees that polling happens when
71   // it was requested. However it has the disadvantage of causing spurious CPU
72   // and network activity. It is a reasonable choice to use for short poll
73   // intervals which only happen a couple times.
74   //
75   // However for repeated timers this will prevent the browser from going
76   // idle. MODE_START_AFTER_ACTIVITY solves this problem by only polling in
77   // direct response to network activity. The drawback to
78   // MODE_START_AFTER_ACTIVITY is since the poll is initiated only after the
79   // request is received, the first couple requests initiated after a long
80   // period of inactivity will likely see a stale version of the PAC script
81   // until the background polling gets a chance to update things.
82   class NET_EXPORT_PRIVATE PacPollPolicy {
83    public:
84     enum Mode {
85       MODE_USE_TIMER,
86       MODE_START_AFTER_ACTIVITY,
87     };
88 
89     virtual ~PacPollPolicy() = default;
90 
91     // Decides the next poll delay. |current_delay| is the delay used
92     // by the preceding poll, or a negative TimeDelta value if determining
93     // the delay for the initial poll. |initial_error| is the network error
94     // code that the last PAC fetch (or WPAD initialization) failed with,
95     // or OK if it completed successfully. Implementations must set
96     // |next_delay| to a non-negative value.
97     virtual Mode GetNextDelay(int initial_error,
98                               base::TimeDelta current_delay,
99                               base::TimeDelta* next_delay) const = 0;
100   };
101 
102   // |net_log| is a possibly nullptr destination to send log events to. It must
103   // remain alive for the lifetime of this ConfiguredProxyResolutionService.
104   ConfiguredProxyResolutionService(
105       std::unique_ptr<ProxyConfigService> config_service,
106       std::unique_ptr<ProxyResolverFactory> resolver_factory,
107       NetLog* net_log,
108       bool quick_check_enabled);
109 
110   ConfiguredProxyResolutionService(const ConfiguredProxyResolutionService&) =
111       delete;
112   ConfiguredProxyResolutionService& operator=(
113       const ConfiguredProxyResolutionService&) = delete;
114 
115   ~ConfiguredProxyResolutionService() override;
116 
117   // ProxyResolutionService
118   //
119   // We use the three possible proxy access types in the following order,
120   // doing fallback if one doesn't work.  See "pac_script_decider.h"
121   // for the specifics.
122   //   1.  WPAD auto-detection
123   //   2.  PAC URL
124   //   3.  named proxy
125   int ResolveProxy(const GURL& url,
126                    const std::string& method,
127                    const NetworkAnonymizationKey& network_anonymization_key,
128                    ProxyInfo* results,
129                    CompletionOnceCallback callback,
130                    std::unique_ptr<ProxyResolutionRequest>* request,
131                    const NetLogWithSource& net_log) override;
132 
133   // ProxyResolutionService
134   void ReportSuccess(const ProxyInfo& proxy_info) override;
135 
136   // Sets the PacFileFetcher and DhcpPacFileFetcher dependencies. This
137   // is needed if the ProxyResolver is of type ProxyResolverWithoutFetch.
138   void SetPacFileFetchers(
139       std::unique_ptr<PacFileFetcher> pac_file_fetcher,
140       std::unique_ptr<DhcpPacFileFetcher> dhcp_pac_file_fetcher);
141   PacFileFetcher* GetPacFileFetcher() const;
142 
143   // ProxyResolutionService
144   void SetProxyDelegate(ProxyDelegate* delegate) override;
145 
146   // ProxyResolutionService
147   void OnShutdown() override;
148 
149   // Returns the last configuration fetched from ProxyConfigService.
fetched_config()150   const std::optional<ProxyConfigWithAnnotation>& fetched_config() const {
151     return fetched_config_;
152   }
153 
154   // Returns the current configuration being used by ProxyConfigService.
config()155   const std::optional<ProxyConfigWithAnnotation>& config() const {
156     return config_;
157   }
158 
159   // ProxyResolutionService
160   const ProxyRetryInfoMap& proxy_retry_info() const override;
161 
162   // ProxyResolutionService
163   void ClearBadProxiesCache() override;
164 
165   // Forces refetching the proxy configuration, and applying it.
166   // This re-does everything from fetching the system configuration,
167   // to downloading and testing the PAC files.
168   void ForceReloadProxyConfig();
169 
170   // ProxyResolutionService
171   base::Value::Dict GetProxyNetLogValues() override;
172 
173   // ProxyResolutionService
174   [[nodiscard]] bool CastToConfiguredProxyResolutionService(
175       ConfiguredProxyResolutionService** configured_proxy_resolution_service)
176       override;
177 
178   // Same as CreateProxyResolutionServiceUsingV8ProxyResolver, except it uses
179   // system libraries for evaluating the PAC script if available, otherwise
180   // skips proxy autoconfig.
181   static std::unique_ptr<ConfiguredProxyResolutionService>
182   CreateUsingSystemProxyResolver(
183       std::unique_ptr<ProxyConfigService> proxy_config_service,
184       NetLog* net_log,
185       bool quick_check_enabled);
186 
187   // Creates a ConfiguredProxyResolutionService without support for proxy
188   // autoconfig.
189   static std::unique_ptr<ConfiguredProxyResolutionService>
190   CreateWithoutProxyResolver(
191       std::unique_ptr<ProxyConfigService> proxy_config_service,
192       NetLog* net_log);
193 
194   // Convenience methods that creates a proxy service using the
195   // specified fixed settings.
196   static std::unique_ptr<ConfiguredProxyResolutionService> CreateFixedForTest(
197       const ProxyConfigWithAnnotation& pc);
198   static std::unique_ptr<ConfiguredProxyResolutionService> CreateFixedForTest(
199       const std::string& proxy,
200       const NetworkTrafficAnnotationTag& traffic_annotation);
201 
202   // Creates a proxy service that uses a DIRECT connection for all requests.
203   static std::unique_ptr<ConfiguredProxyResolutionService> CreateDirect();
204 
205   // This method is used by tests to create a ConfiguredProxyResolutionService
206   // that returns a hardcoded proxy fallback list (|pac_string|) for every URL.
207   //
208   // |pac_string| is a list of proxy servers, in the format that a PAC script
209   // would return it. For example, "PROXY foobar:99; SOCKS fml:2; DIRECT"
210   static std::unique_ptr<ConfiguredProxyResolutionService>
211   CreateFixedFromPacResultForTest(
212       const std::string& pac_string,
213       const NetworkTrafficAnnotationTag& traffic_annotation);
214 
215   // Same as CreateFixedFromPacResultForTest(), except the resulting ProxyInfo
216   // from resolutions will be tagged as having been auto-detected.
217   static std::unique_ptr<ConfiguredProxyResolutionService>
218   CreateFixedFromAutoDetectedPacResultForTest(
219       const std::string& pac_string,
220       const NetworkTrafficAnnotationTag& traffic_annotation);
221 
222   // This method is used by tests to create a ConfiguredProxyResolutionService
223   // that returns a proxy fallback list (|proxy_chain|) for every URL.
224   static std::unique_ptr<ConfiguredProxyResolutionService>
225   CreateFixedFromProxyChainsForTest(
226       const std::vector<ProxyChain>& proxy_chains,
227       const NetworkTrafficAnnotationTag& traffic_annotation);
228 
229   // This method should only be used by unit tests.
set_stall_proxy_auto_config_delay(base::TimeDelta delay)230   void set_stall_proxy_auto_config_delay(base::TimeDelta delay) {
231     stall_proxy_auto_config_delay_ = delay;
232   }
233 
234   // This method should only be used by unit tests. Returns the previously
235   // active policy.
236   static const PacPollPolicy* set_pac_script_poll_policy(
237       const PacPollPolicy* policy);
238 
239   // This method should only be used by unit tests. Creates an instance
240   // of the default internal PacPollPolicy used by
241   // ConfiguredProxyResolutionService.
242   static std::unique_ptr<PacPollPolicy> CreateDefaultPacPollPolicy();
243 
quick_check_enabled_for_testing()244   bool quick_check_enabled_for_testing() const { return quick_check_enabled_; }
245 
246  private:
247   friend class ConfiguredProxyResolutionRequest;
248   FRIEND_TEST_ALL_PREFIXES(ProxyResolutionServiceTest,
249                            UpdateConfigAfterFailedAutodetect);
250   FRIEND_TEST_ALL_PREFIXES(ProxyResolutionServiceTest,
251                            UpdateConfigFromPACToDirect);
252   class InitProxyResolver;
253   class PacFileDeciderPoller;
254 
255   typedef std::set<raw_ptr<ConfiguredProxyResolutionRequest, SetExperimental>>
256       PendingRequests;
257 
258   enum State {
259     STATE_NONE,
260     STATE_WAITING_FOR_PROXY_CONFIG,
261     STATE_WAITING_FOR_INIT_PROXY_RESOLVER,
262     STATE_READY,
263   };
264 
265   // We won't always be able to return a good LoadState. For example, the
266   // ConfiguredProxyResolutionService can only get this information from the
267   // InitProxyResolver, which is not always available.
268   bool GetLoadStateIfAvailable(LoadState* load_state) const;
269 
270   ProxyResolver* GetProxyResolver() const;
271 
272   // Resets all the variables associated with the current proxy configuration,
273   // and rewinds the current state to |STATE_NONE|. Returns the previous value
274   // of |current_state_|.  If |reset_fetched_config| is true then
275   // |fetched_config_| will also be reset, otherwise it will be left as-is.
276   // Resetting it means that we will have to re-fetch the configuration from
277   // the ProxyConfigService later.
278   State ResetProxyConfig(bool reset_fetched_config);
279 
280   // Retrieves the current proxy configuration from the ProxyConfigService, and
281   // starts initializing for it.
282   void ApplyProxyConfigIfAvailable();
283 
284   // Callback for when the proxy resolver has been initialized with a
285   // PAC script.
286   void OnInitProxyResolverComplete(int result);
287 
288   // Returns ERR_IO_PENDING if the request cannot be completed synchronously.
289   // Otherwise it fills |result| with the proxy information for |url|.
290   // Completing synchronously means we don't need to query ProxyResolver.
291   int TryToCompleteSynchronously(const GURL& url, ProxyInfo* result);
292 
293   // Cancels all of the requests sent to the ProxyResolver. These will be
294   // restarted when calling SetReady().
295   void SuspendAllPendingRequests();
296 
297   // Advances the current state to |STATE_READY|, and resumes any pending
298   // requests which had been stalled waiting for initialization to complete.
299   void SetReady();
300 
301   // Returns true if |pending_requests_| contains |req|.
302   bool ContainsPendingRequest(ConfiguredProxyResolutionRequest* req);
303 
304   // Removes |req| from the list of pending requests.
305   void RemovePendingRequest(ConfiguredProxyResolutionRequest* req);
306 
307   // Called when proxy resolution has completed (either synchronously or
308   // asynchronously). Handles logging the result, and cleaning out
309   // bad entries from the results list.
310   int DidFinishResolvingProxy(
311       const GURL& url,
312       const NetworkAnonymizationKey& network_anonymization_key,
313       const std::string& method,
314       ProxyInfo* result,
315       int result_code,
316       const NetLogWithSource& net_log);
317 
318   // Start initialization using |fetched_config_|.
319   void InitializeUsingLastFetchedConfig();
320 
321   // Start the initialization skipping past the "decision" phase.
322   void InitializeUsingDecidedConfig(
323       int decider_result,
324       const PacFileDataWithSource& script_data,
325       const ProxyConfigWithAnnotation& effective_config);
326 
327   // NetworkChangeNotifier::IPAddressObserver
328   // When this is called, we re-fetch PAC scripts and re-run WPAD.
329   void OnIPAddressChanged() override;
330 
331   // NetworkChangeNotifier::DNSObserver
332   // We respond as above.
333   void OnDNSChanged() override;
334 
335   // ProxyConfigService::Observer
336   void OnProxyConfigChanged(
337       const ProxyConfigWithAnnotation& config,
338       ProxyConfigService::ConfigAvailability availability) override;
339 
340   // When using a PAC script there isn't a user-configurable ProxyBypassRules to
341   // check, as the one from manual settings doesn't apply. However we
342   // still check for matches against the implicit bypass rules, to prevent PAC
343   // scripts from being able to proxy localhost.
344   bool ApplyPacBypassRules(const GURL& url, ProxyInfo* results);
345 
346   std::unique_ptr<ProxyConfigService> config_service_;
347   std::unique_ptr<ProxyResolverFactory> resolver_factory_;
348 
349   // If non-null, the initialized ProxyResolver to use for requests.
350   std::unique_ptr<ProxyResolver> resolver_;
351 
352   // We store the proxy configuration that was last fetched from the
353   // ProxyConfigService, as well as the resulting "effective" configuration.
354   // The effective configuration is what we condense the original fetched
355   // settings to after testing the various automatic settings (auto-detect
356   // and custom PAC url).
357   //
358   // These are "optional" as their value remains unset while being calculated.
359   std::optional<ProxyConfigWithAnnotation> fetched_config_;
360   std::optional<ProxyConfigWithAnnotation> config_;
361 
362   // Map of the known bad proxies and the information about the retry time.
363   ProxyRetryInfoMap proxy_retry_info_;
364 
365   // Set of pending/inprogress requests.
366   PendingRequests pending_requests_;
367 
368   // The fetcher to use when downloading PAC scripts for the ProxyResolver.
369   // This dependency can be nullptr if our ProxyResolver has no need for
370   // external PAC script fetching.
371   std::unique_ptr<PacFileFetcher> pac_file_fetcher_;
372 
373   // The fetcher to use when attempting to download the most appropriate PAC
374   // script configured in DHCP, if any. Can be nullptr if the ProxyResolver has
375   // no need for DHCP PAC script fetching.
376   std::unique_ptr<DhcpPacFileFetcher> dhcp_pac_file_fetcher_;
377 
378   // Helper to download the PAC script (wpad + custom) and apply fallback rules.
379   //
380   // Note that the declaration is important here: |pac_file_fetcher_| and
381   // |proxy_resolver_| must outlive |init_proxy_resolver_|.
382   std::unique_ptr<InitProxyResolver> init_proxy_resolver_;
383 
384   // Helper to poll the PAC script for changes.
385   std::unique_ptr<PacFileDeciderPoller> script_poller_;
386 
387   State current_state_ = STATE_NONE;
388 
389   // Either OK or an ERR_* value indicating that a permanent error (e.g.
390   // failed to fetch the PAC script) prevents proxy resolution.
391   int permanent_error_ = OK;
392 
393   // This is the log where any events generated by |init_proxy_resolver_| are
394   // sent to.
395   raw_ptr<NetLog> net_log_;
396 
397   // The earliest time at which we should run any proxy auto-config. (Used to
398   // stall re-configuration following an IP address change).
399   base::TimeTicks stall_proxy_autoconfig_until_;
400 
401   // The amount of time to stall requests following IP address changes.
402   base::TimeDelta stall_proxy_auto_config_delay_;
403 
404   // Whether child PacFileDeciders should use QuickCheck
405   bool quick_check_enabled_;
406 
407   THREAD_CHECKER(thread_checker_);
408 
409   raw_ptr<ProxyDelegate> proxy_delegate_ = nullptr;
410 
411   // Flag used by |SetReady()| to check if |this| has been deleted by a
412   // synchronous callback.
413   base::WeakPtrFactory<ConfiguredProxyResolutionService> weak_ptr_factory_{
414       this};
415 };
416 
417 }  // namespace net
418 
419 #endif  // NET_PROXY_RESOLUTION_CONFIGURED_PROXY_RESOLUTION_SERVICE_H_
420