xref: /aosp_15_r20/external/cronet/net/proxy_resolution/pac_file_decider.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_PAC_FILE_DECIDER_H_
6 #define NET_PROXY_RESOLUTION_PAC_FILE_DECIDER_H_
7 
8 #include <stddef.h>
9 
10 #include <memory>
11 #include <string>
12 #include <vector>
13 
14 #include "base/memory/raw_ptr.h"
15 #include "base/memory/scoped_refptr.h"
16 #include "base/time/time.h"
17 #include "base/timer/timer.h"
18 #include "base/values.h"
19 #include "net/base/completion_once_callback.h"
20 #include "net/base/net_export.h"
21 #include "net/dns/host_resolver.h"
22 #include "net/log/net_log_with_source.h"
23 #include "net/proxy_resolution/proxy_config_with_annotation.h"
24 #include "net/proxy_resolution/proxy_resolver.h"
25 #include "url/gurl.h"
26 
27 namespace net {
28 
29 class DhcpPacFileFetcher;
30 class NetLog;
31 class ProxyResolver;
32 class PacFileFetcher;
33 
34 // Structure that encapsulates the result a PacFileData along with an
35 // indication of its origin: was it obtained implicitly from auto-detect,
36 // or was it read from a more explicitly configured URL.
37 //
38 // Note that |!from_auto_detect| does NOT imply the script was securely
39 // delivered. Most commonly PAC scripts are configured from http:// URLs,
40 // both for auto-detect and not.
41 struct NET_EXPORT_PRIVATE PacFileDataWithSource {
42   PacFileDataWithSource();
43   PacFileDataWithSource(const PacFileDataWithSource&);
44   ~PacFileDataWithSource();
45 
46   PacFileDataWithSource& operator=(const PacFileDataWithSource&);
47 
48   scoped_refptr<PacFileData> data;
49   bool from_auto_detect = false;
50 };
51 
52 // PacFileDecider is a helper class used by ConfiguredProxyResolutionService to
53 // determine which PAC script to use given our proxy configuration.
54 //
55 // This involves trying to use PAC scripts in this order:
56 //
57 //   (1) WPAD (DHCP) if auto-detect is on.
58 //   (2) WPAD (DNS) if auto-detect is on.
59 //   (3) Custom PAC script if a URL was given.
60 //
61 // If no PAC script was successfully selected, then it fails with either a
62 // network error, or PAC_SCRIPT_FAILED (indicating it did not pass our
63 // validation).
64 //
65 // On successful completion, the fetched PAC script data can be accessed using
66 // script_data().
67 //
68 // Deleting PacFileDecider while Init() is in progress, will
69 // cancel the request.
70 //
71 class NET_EXPORT_PRIVATE PacFileDecider {
72  public:
73   // |pac_file_fetcher|, |dhcp_pac_file_fetcher| and
74   // |net_log| must remain valid for the lifespan of PacFileDecider.
75   PacFileDecider(PacFileFetcher* pac_file_fetcher,
76                  DhcpPacFileFetcher* dhcp_pac_file_fetcher,
77                  NetLog* net_log);
78 
79   PacFileDecider(const PacFileDecider&) = delete;
80   PacFileDecider& operator=(const PacFileDecider&) = delete;
81 
82   // Aborts any in-progress request.
83   ~PacFileDecider();
84 
85   // Evaluates the effective proxy settings for |config|, and downloads the
86   // associated PAC script.
87   // If |wait_delay| is positive, the initialization will pause for this
88   // amount of time before getting started.
89   // On successful completion, the "effective" proxy settings we ended up
90   // deciding on will be available vial the effective_settings() accessor.
91   // Note that this may differ from |config| since we will have stripped any
92   // manual settings, and decided whether to use auto-detect or the custom PAC
93   // URL. Finally, if auto-detect was used we may now have resolved that to a
94   // specific script URL.
95   int Start(const ProxyConfigWithAnnotation& config,
96             const base::TimeDelta wait_delay,
97             bool fetch_pac_bytes,
98             CompletionOnceCallback callback);
99 
100   // Shuts down any in-progress DNS requests, and cancels any ScriptFetcher
101   // requests. Does not call OnShutdown() on the [Dhcp]PacFileFetcher. Any
102   // pending callback will not be invoked.
103   void OnShutdown();
104 
105   const ProxyConfigWithAnnotation& effective_config() const;
106 
107   const PacFileDataWithSource& script_data() const;
108 
set_quick_check_enabled(bool enabled)109   void set_quick_check_enabled(bool enabled) { quick_check_enabled_ = enabled; }
110 
quick_check_enabled()111   bool quick_check_enabled() const { return quick_check_enabled_; }
112 
113  private:
114   // Represents the sources from which we can get PAC files; two types of
115   // auto-detect or a custom URL.
116   struct PacSource {
117     enum Type { WPAD_DHCP, WPAD_DNS, CUSTOM };
118 
PacSourcePacSource119     PacSource(Type type, const GURL& url) : type(type), url(url) {}
120 
121     // Returns a Value representing the PacSource.  |effective_pac_url| is the
122     // URL derived from information contained in
123     // |this|, if Type is not WPAD_DHCP.
124     base::Value::Dict NetLogParams(const GURL& effective_pac_url) const;
125 
126     Type type;
127     GURL url;  // Empty unless |type == PAC_SOURCE_CUSTOM|.
128   };
129 
130   typedef std::vector<PacSource> PacSourceList;
131 
132   enum State {
133     STATE_NONE,
134     STATE_WAIT,
135     STATE_WAIT_COMPLETE,
136     STATE_QUICK_CHECK,
137     STATE_QUICK_CHECK_COMPLETE,
138     STATE_FETCH_PAC_SCRIPT,
139     STATE_FETCH_PAC_SCRIPT_COMPLETE,
140     STATE_VERIFY_PAC_SCRIPT,
141     STATE_VERIFY_PAC_SCRIPT_COMPLETE,
142   };
143 
144   // Returns ordered list of PAC urls to try for |config|.
145   PacSourceList BuildPacSourcesFallbackList(const ProxyConfig& config) const;
146 
147   void OnIOCompletion(int result);
148   int DoLoop(int result);
149 
150   int DoWait();
151   int DoWaitComplete(int result);
152 
153   int DoQuickCheck();
154   int DoQuickCheckComplete(int result);
155 
156   int DoFetchPacScript();
157   int DoFetchPacScriptComplete(int result);
158 
159   int DoVerifyPacScript();
160   int DoVerifyPacScriptComplete(int result);
161 
162   // Tries restarting using the next fallback PAC URL:
163   // |pac_sources_[++current_pac_source_index]|.
164   // Returns OK and rewinds the state machine when there
165   // is something to try, otherwise returns |error|.
166   int TryToFallbackPacSource(int error);
167 
168   // Gets the initial state (we skip fetching when the
169   // ProxyResolver doesn't |expect_pac_bytes()|.
170   State GetStartState() const;
171 
172   void DetermineURL(const PacSource& pac_source, GURL* effective_pac_url);
173 
174   // Returns the current PAC URL we are fetching/testing.
175   const PacSource& current_pac_source() const;
176 
177   void OnWaitTimerFired();
178   void DidComplete();
179   void Cancel();
180 
181   raw_ptr<PacFileFetcher> pac_file_fetcher_;
182   raw_ptr<DhcpPacFileFetcher> dhcp_pac_file_fetcher_;
183 
184   CompletionOnceCallback callback_;
185 
186   size_t current_pac_source_index_ = 0u;
187 
188   // Filled when the PAC script fetch completes.
189   std::u16string pac_script_;
190 
191   // Flag indicating whether the caller requested a mandatory PAC script
192   // (i.e. fallback to direct connections are prohibited).
193   bool pac_mandatory_ = false;
194 
195   // Whether we have an existing custom PAC URL.
196   bool have_custom_pac_url_;
197 
198   PacSourceList pac_sources_;
199   State next_state_ = STATE_NONE;
200 
201   NetLogWithSource net_log_;
202 
203   bool fetch_pac_bytes_ = false;
204 
205   base::TimeDelta wait_delay_;
206   base::OneShotTimer wait_timer_;
207 
208   net::MutableNetworkTrafficAnnotationTag traffic_annotation_;
209 
210   // Whether to do DNS quick check
211   bool quick_check_enabled_ = true;
212 
213   // Results.
214   ProxyConfigWithAnnotation effective_config_;
215   PacFileDataWithSource script_data_;
216 
217   std::unique_ptr<HostResolver::ResolveHostRequest> resolve_request_;
218 
219   base::OneShotTimer quick_check_timer_;
220 };
221 
222 }  // namespace net
223 
224 #endif  // NET_PROXY_RESOLUTION_PAC_FILE_DECIDER_H_
225