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_FETCHER_WIN_H_ 6 #define NET_PROXY_RESOLUTION_WIN_DHCP_PAC_FILE_FETCHER_WIN_H_ 7 8 #include <memory> 9 #include <set> 10 #include <string> 11 #include <vector> 12 13 #include "base/memory/raw_ptr.h" 14 #include "base/memory/ref_counted.h" 15 #include "base/threading/thread_checker.h" 16 #include "base/time/time.h" 17 #include "base/timer/timer.h" 18 #include "net/base/completion_once_callback.h" 19 #include "net/base/net_export.h" 20 #include "net/log/net_log_with_source.h" 21 #include "net/proxy_resolution/dhcp_pac_file_fetcher.h" 22 #include "net/traffic_annotation/network_traffic_annotation.h" 23 24 namespace base { 25 class TaskRunner; 26 } 27 28 namespace net { 29 30 struct DhcpAdapterNamesLoggingInfo; 31 class DhcpPacFileAdapterFetcher; 32 class URLRequestContext; 33 34 // Windows-specific implementation. 35 class NET_EXPORT_PRIVATE DhcpPacFileFetcherWin 36 : public DhcpPacFileFetcher, 37 public base::SupportsWeakPtr<DhcpPacFileFetcherWin> { 38 public: 39 DhcpPacFileFetcherWin() = delete; 40 41 // Creates a DhcpPacFileFetcherWin that issues requests through 42 // |url_request_context|. |url_request_context| must remain valid for 43 // the lifetime of DhcpPacFileFetcherWin. 44 explicit DhcpPacFileFetcherWin(URLRequestContext* url_request_context); 45 46 DhcpPacFileFetcherWin(const DhcpPacFileFetcherWin&) = delete; 47 DhcpPacFileFetcherWin& operator=(const DhcpPacFileFetcherWin&) = delete; 48 49 ~DhcpPacFileFetcherWin() override; 50 51 // DhcpPacFileFetcher implementation. 52 int Fetch(std::u16string* utf16_text, 53 CompletionOnceCallback callback, 54 const NetLogWithSource& net_log, 55 const NetworkTrafficAnnotationTag traffic_annotation) override; 56 void Cancel() override; 57 void OnShutdown() override; 58 const GURL& GetPacURL() const override; 59 std::string GetFetcherName() const override; 60 61 // Sets |adapter_names| to contain the name of each network adapter on 62 // this machine that has DHCP enabled and is not a loop-back adapter. May 63 // optionally update |info| (if non-null) with information for logging. 64 // Returns false on error. 65 static bool GetCandidateAdapterNames(std::set<std::string>* adapter_names, 66 DhcpAdapterNamesLoggingInfo* info); 67 68 protected: 69 int num_pending_fetchers() const; 70 71 URLRequestContext* url_request_context() const; 72 73 scoped_refptr<base::TaskRunner> GetTaskRunner(); 74 75 // This inner class encapsulate work done on a worker pool thread. 76 // The class calls GetCandidateAdapterNames, which can take a couple of 77 // hundred milliseconds. 78 class NET_EXPORT_PRIVATE AdapterQuery 79 : public base::RefCountedThreadSafe<AdapterQuery> { 80 public: 81 AdapterQuery(); 82 83 AdapterQuery(const AdapterQuery&) = delete; 84 AdapterQuery& operator=(const AdapterQuery&) = delete; 85 86 // This is the method that runs on the worker pool thread. 87 void GetCandidateAdapterNames(); 88 89 // This set is valid after GetCandidateAdapterNames has 90 // been run. Its lifetime is scoped by this object. 91 const std::set<std::string>& adapter_names() const; 92 logging_info()93 DhcpAdapterNamesLoggingInfo* logging_info() { return logging_info_.get(); } 94 95 protected: 96 // Virtual method introduced to allow unit testing. 97 virtual bool ImplGetCandidateAdapterNames( 98 std::set<std::string>* adapter_names, 99 DhcpAdapterNamesLoggingInfo* info); 100 101 friend class base::RefCountedThreadSafe<AdapterQuery>; 102 virtual ~AdapterQuery(); 103 104 private: 105 // These are constructed on the originating thread, then used on the 106 // worker thread, then used again on the originating thread only when 107 // the task has completed on the worker thread. No locking required. 108 std::set<std::string> adapter_names_; 109 std::unique_ptr<DhcpAdapterNamesLoggingInfo> logging_info_; 110 }; 111 112 // Virtual methods introduced to allow unit testing. 113 virtual std::unique_ptr<DhcpPacFileAdapterFetcher> ImplCreateAdapterFetcher(); 114 virtual scoped_refptr<AdapterQuery> ImplCreateAdapterQuery(); 115 virtual base::TimeDelta ImplGetMaxWait(); ImplOnGetCandidateAdapterNamesDone()116 virtual void ImplOnGetCandidateAdapterNamesDone() {} 117 118 private: 119 // Event/state transition handlers 120 void CancelImpl(); 121 void OnGetCandidateAdapterNamesDone( 122 scoped_refptr<AdapterQuery> query, 123 const NetworkTrafficAnnotationTag traffic_annotation); 124 void OnFetcherDone(size_t fetcher_i, int result); 125 void OnWaitTimer(); 126 void TransitionToDone(); 127 128 // This is the outer state machine for fetching PAC configuration from 129 // DHCP. It relies for sub-states on the state machine of the 130 // DhcpPacFileAdapterFetcher class. 131 // 132 // The goal of the implementation is to the following work in parallel 133 // for all network adapters that are using DHCP: 134 // a) Try to get the PAC URL configured in DHCP; 135 // b) If one is configured, try to fetch the PAC URL. 136 // c) Once this is done for all adapters, or a timeout has passed after 137 // it has completed for the fastest adapter, return the PAC file 138 // available for the most preferred network adapter, if any. 139 // 140 // The state machine goes from START->WAIT_ADAPTERS when it starts a 141 // worker thread to get the list of adapters with DHCP enabled. 142 // It then goes from WAIT_ADAPTERS->NO_RESULTS when it creates 143 // and starts an DhcpPacFileAdapterFetcher for each adapter. It goes 144 // from NO_RESULTS->SOME_RESULTS when it gets the first result; at this 145 // point a wait timer is started. It goes from SOME_RESULTS->DONE in 146 // two cases: All results are known, or the wait timer expired. A call 147 // to Cancel() will also go straight to DONE from any state. Any 148 // way the DONE state is entered, we will at that point cancel any 149 // outstanding work and return the best known PAC script or the empty 150 // string. 151 // 152 // The state machine is reset for each Fetch(), a call to which is 153 // only valid in states START and DONE, as only one Fetch() is 154 // allowed to be outstanding at any given time. 155 enum State { 156 STATE_START, 157 STATE_WAIT_ADAPTERS, 158 STATE_NO_RESULTS, 159 STATE_SOME_RESULTS, 160 STATE_DONE, 161 }; 162 163 // Vector, in Windows' network adapter preference order, of 164 // DhcpPacFileAdapterFetcher objects that are or were attempting 165 // to fetch a PAC file based on DHCP configuration. 166 using FetcherVector = std::vector<std::unique_ptr<DhcpPacFileAdapterFetcher>>; 167 FetcherVector fetchers_; 168 169 // Current state of this state machine. 170 State state_ = STATE_START; 171 172 // The following members are associated with the latest call to Fetch(). 173 174 // Number of fetchers we are waiting for. 175 int num_pending_fetchers_ = 0; 176 177 // Lets our client know we're done. Not valid in states START or DONE. 178 CompletionOnceCallback callback_; 179 180 // The NetLog to use for the current Fetch(). 181 NetLogWithSource net_log_; 182 183 // Pointer to string we will write results to. Not valid in states 184 // START and DONE. 185 raw_ptr<std::u16string, AcrossTasksDanglingUntriaged> destination_string_ = 186 nullptr; 187 188 // PAC URL retrieved from DHCP, if any. Valid only in state STATE_DONE. 189 GURL pac_url_; 190 191 base::OneShotTimer wait_timer_; 192 193 // Set to nullptr on cancellation. 194 raw_ptr<URLRequestContext> url_request_context_; 195 196 // NULL or the AdapterQuery currently in flight. 197 scoped_refptr<AdapterQuery> last_query_; 198 199 // TaskRunner used for all DHCP lookup tasks. 200 const scoped_refptr<base::TaskRunner> task_runner_; 201 202 THREAD_CHECKER(thread_checker_); 203 }; 204 205 } // namespace net 206 207 #endif // NET_PROXY_RESOLUTION_WIN_DHCP_PAC_FILE_FETCHER_WIN_H_ 208