xref: /aosp_15_r20/external/cronet/net/proxy_resolution/win/dhcp_pac_file_adapter_fetcher_win.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_WIN_DHCP_PAC_FILE_ADAPTER_FETCHER_WIN_H_
6 #define NET_PROXY_RESOLUTION_WIN_DHCP_PAC_FILE_ADAPTER_FETCHER_WIN_H_
7 
8 #include <stddef.h>
9 
10 #include <memory>
11 #include <string>
12 
13 #include "base/memory/raw_ptr.h"
14 #include "base/memory/ref_counted.h"
15 #include "base/memory/weak_ptr.h"
16 #include "base/threading/thread_checker.h"
17 #include "base/timer/timer.h"
18 #include "net/base/completion_once_callback.h"
19 #include "net/base/net_errors.h"
20 #include "net/base/net_export.h"
21 #include "net/traffic_annotation/network_traffic_annotation.h"
22 #include "url/gurl.h"
23 
24 namespace base {
25 class TaskRunner;
26 }
27 
28 namespace net {
29 
30 class PacFileFetcher;
31 class URLRequestContext;
32 
33 // For a given adapter, this class takes care of first doing a DHCP lookup
34 // to get the PAC URL, then if there is one, trying to fetch it.
35 class NET_EXPORT_PRIVATE DhcpPacFileAdapterFetcher
36     : public base::SupportsWeakPtr<DhcpPacFileAdapterFetcher> {
37  public:
38   DhcpPacFileAdapterFetcher() = delete;
39 
40   // |url_request_context| must outlive DhcpPacFileAdapterFetcher.
41   // |task_runner| will be used to post tasks to a thread.
42   DhcpPacFileAdapterFetcher(URLRequestContext* url_request_context,
43                             scoped_refptr<base::TaskRunner> task_runner);
44 
45   DhcpPacFileAdapterFetcher(const DhcpPacFileAdapterFetcher&) = delete;
46   DhcpPacFileAdapterFetcher& operator=(const DhcpPacFileAdapterFetcher&) =
47       delete;
48 
49   virtual ~DhcpPacFileAdapterFetcher();
50 
51   // Starts a fetch.  On completion (but not cancellation), |callback|
52   // will be invoked with the network error indicating success or failure
53   // of fetching a DHCP-configured PAC file on this adapter.
54   //
55   // On completion, results can be obtained via |GetPacScript()|, |GetPacURL()|.
56   //
57   // You may only call Fetch() once on a given instance of
58   // DhcpPacFileAdapterFetcher.
59   virtual void Fetch(const std::string& adapter_name,
60                      CompletionOnceCallback callback,
61                      const NetworkTrafficAnnotationTag traffic_annotation);
62 
63   // Cancels the fetch on this adapter.
64   virtual void Cancel();
65 
66   // Returns true if in the FINISH state (not CANCEL).
67   virtual bool DidFinish() const;
68 
69   // Returns the network error indicating the result of the fetch. Will
70   // return IO_PENDING until the fetch is complete or cancelled. This is
71   // the same network error passed to the |callback| provided to |Fetch()|.
72   virtual int GetResult() const;
73 
74   // Returns the contents of the PAC file retrieved.  Only valid if
75   // |IsComplete()| is true.  Returns the empty string if |GetResult()|
76   // returns anything other than OK.
77   virtual std::u16string GetPacScript() const;
78 
79   // Returns the PAC URL retrieved from DHCP.  Only guaranteed to be
80   // valid if |IsComplete()| is true.  Returns an empty URL if no URL was
81   // configured in DHCP.  May return a valid URL even if |result()| does
82   // not return OK (this would indicate that we found a URL configured in
83   // DHCP but failed to download it).
84   virtual GURL GetPacURL() const;
85 
86   // Returns the PAC URL configured in DHCP for the given |adapter_name|, or
87   // the empty string if none is configured.
88   //
89   // This function executes synchronously due to limitations of the Windows
90   // DHCP client API.
91   static std::string GetPacURLFromDhcp(const std::string& adapter_name);
92 
93   // Sanitizes a string returned via the DHCP API.
94   static std::string SanitizeDhcpApiString(const char* data,
95                                            size_t count_bytes);
96 
97  protected:
98   // This is the state machine for fetching from a given adapter.
99   //
100   // The state machine goes from START->WAIT_DHCP when it starts
101   // a worker thread to fetch the PAC URL from DHCP.
102   //
103   // In state WAIT_DHCP, if the DHCP query finishes and has no URL, it
104   // moves to state FINISH.  If there is a URL, it starts a
105   // PacFileFetcher to fetch it and moves to state WAIT_URL.
106   //
107   // It goes from WAIT_URL->FINISH when the PacFileFetcher completes.
108   //
109   // In state FINISH, completion is indicated to the outer class, with
110   // the results of the fetch if a PAC script was successfully fetched.
111   //
112   // In state WAIT_DHCP, our timeout occurring can push us to FINISH.
113   //
114   // In any state except FINISH, a call to Cancel() will move to state
115   // CANCEL and cause all outstanding work to be cancelled or its
116   // results ignored when available.
117   enum State {
118     STATE_START,
119     STATE_WAIT_DHCP,
120     STATE_WAIT_URL,
121     STATE_FINISH,
122     STATE_CANCEL,
123   };
124 
125   State state() const;
126 
127   // This inner class encapsulates work done on a worker pool thread.
128   // By using a separate object, we can keep the main object completely
129   // thread safe and let it be non-refcounted.
130   class NET_EXPORT_PRIVATE DhcpQuery
131       : public base::RefCountedThreadSafe<DhcpQuery> {
132    public:
133     DhcpQuery();
134 
135     DhcpQuery(const DhcpQuery&) = delete;
136     DhcpQuery& operator=(const DhcpQuery&) = delete;
137 
138     // This method should run on a worker pool thread, via PostTaskAndReply.
139     // After it has run, the |url()| method on this object will return the
140     // URL retrieved.
141     void GetPacURLForAdapter(const std::string& adapter_name);
142 
143     // Returns the URL retrieved for the given adapter, once the task has run.
144     const std::string& url() const;
145 
146    protected:
147     // Virtual method introduced to allow unit testing.
148     virtual std::string ImplGetPacURLFromDhcp(const std::string& adapter_name);
149 
150     friend class base::RefCountedThreadSafe<DhcpQuery>;
151     virtual ~DhcpQuery();
152 
153    private:
154     // The URL retrieved for the given adapter.
155     std::string url_;
156   };
157 
158   // Virtual methods introduced to allow unit testing.
159   virtual std::unique_ptr<PacFileFetcher> ImplCreateScriptFetcher();
160   virtual scoped_refptr<DhcpQuery> ImplCreateDhcpQuery();
161   virtual base::TimeDelta ImplGetTimeout() const;
162 
163  private:
164   // Event/state transition handlers
165   void OnDhcpQueryDone(scoped_refptr<DhcpQuery> dhcp_query,
166                        const NetworkTrafficAnnotationTag traffic_annotation);
167   void OnTimeout();
168   void OnFetcherDone(int result);
169   void TransitionToFinish();
170 
171   // TaskRunner for posting tasks to a worker thread.
172   scoped_refptr<base::TaskRunner> task_runner_;
173 
174   // Current state of this state machine.
175   State state_ = STATE_START;
176 
177   // A network error indicating result of operation.
178   int result_ = ERR_IO_PENDING;
179 
180   // Empty string or the PAC script downloaded.
181   std::u16string pac_script_;
182 
183   // Empty URL or the PAC URL configured in DHCP.
184   GURL pac_url_;
185 
186   // Callback to let our client know we're done. Invalid in states
187   // START, FINISH and CANCEL.
188   CompletionOnceCallback callback_;
189 
190   // Fetcher to retrieve PAC files once URL is known.
191   std::unique_ptr<PacFileFetcher> script_fetcher_;
192 
193   // Implements a timeout on the call to the Win32 DHCP API.
194   base::OneShotTimer wait_timer_;
195 
196   const raw_ptr<URLRequestContext, DanglingUntriaged> url_request_context_;
197 
198   THREAD_CHECKER(thread_checker_);
199 };
200 
201 }  // namespace net
202 
203 #endif  // NET_PROXY_RESOLUTION_WIN_DHCP_PAC_FILE_ADAPTER_FETCHER_WIN_H_
204