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