xref: /aosp_15_r20/external/cronet/net/proxy_resolution/configured_proxy_resolution_service.cc (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 #include "net/proxy_resolution/configured_proxy_resolution_service.h"
6 
7 #include <algorithm>
8 #include <cmath>
9 #include <memory>
10 #include <utility>
11 
12 #include "base/compiler_specific.h"
13 #include "base/functional/bind.h"
14 #include "base/functional/callback_helpers.h"
15 #include "base/location.h"
16 #include "base/logging.h"
17 #include "base/memory/raw_ptr.h"
18 #include "base/memory/weak_ptr.h"
19 #include "base/metrics/histogram_macros.h"
20 #include "base/strings/string_util.h"
21 #include "base/task/single_thread_task_runner.h"
22 #include "base/time/time.h"
23 #include "base/values.h"
24 #include "build/build_config.h"
25 #include "build/chromeos_buildflags.h"
26 #include "net/base/net_errors.h"
27 #include "net/base/net_info_source_list.h"
28 #include "net/base/network_anonymization_key.h"
29 #include "net/base/proxy_delegate.h"
30 #include "net/base/proxy_server.h"
31 #include "net/base/proxy_string_util.h"
32 #include "net/base/url_util.h"
33 #include "net/log/net_log.h"
34 #include "net/log/net_log_event_type.h"
35 #include "net/log/net_log_util.h"
36 #include "net/log/net_log_with_source.h"
37 #include "net/proxy_resolution/configured_proxy_resolution_request.h"
38 #include "net/proxy_resolution/dhcp_pac_file_fetcher.h"
39 #include "net/proxy_resolution/multi_threaded_proxy_resolver.h"
40 #include "net/proxy_resolution/pac_file_decider.h"
41 #include "net/proxy_resolution/pac_file_fetcher.h"
42 #include "net/proxy_resolution/proxy_config_service_fixed.h"
43 #include "net/proxy_resolution/proxy_resolver_factory.h"
44 #include "net/url_request/url_request_context.h"
45 
46 #if BUILDFLAG(IS_WIN)
47 #include "net/proxy_resolution/win/proxy_resolver_winhttp.h"
48 #elif BUILDFLAG(IS_APPLE)
49 #include "net/proxy_resolution/proxy_resolver_apple.h"
50 #endif
51 
52 using base::TimeTicks;
53 
54 namespace net {
55 
56 namespace {
57 
58 const size_t kDefaultNumPacThreads = 4;
59 
60 // When the IP address changes we don't immediately re-run proxy auto-config.
61 // Instead, we  wait for |kDelayAfterNetworkChangesMs| before
62 // attempting to re-valuate proxy auto-config.
63 //
64 // During this time window, any resolve requests sent to the
65 // ConfiguredProxyResolutionService will be queued. Once we have waited the
66 // required amount of them, the proxy auto-config step will be run, and the
67 // queued requests resumed.
68 //
69 // The reason we play this game is that our signal for detecting network
70 // changes (NetworkChangeNotifier) may fire *before* the system's networking
71 // dependencies are fully configured. This is a problem since it means if
72 // we were to run proxy auto-config right away, it could fail due to spurious
73 // DNS failures. (see http://crbug.com/50779 for more details.)
74 //
75 // By adding the wait window, we give things a better chance to get properly
76 // set up. Network failures can happen at any time though, so we additionally
77 // poll the PAC script for changes, which will allow us to recover from these
78 // sorts of problems.
79 const int64_t kDelayAfterNetworkChangesMs = 2000;
80 
81 // This is the default policy for polling the PAC script.
82 //
83 // In response to a failure, the poll intervals are:
84 //    0: 8 seconds  (scheduled on timer)
85 //    1: 32 seconds
86 //    2: 2 minutes
87 //    3+: 4 hours
88 //
89 // In response to a success, the poll intervals are:
90 //    0+: 12 hours
91 //
92 // Only the 8 second poll is scheduled on a timer, the rest happen in response
93 // to network activity (and hence will take longer than the written time).
94 //
95 // Explanation for these values:
96 //
97 // TODO(eroman): These values are somewhat arbitrary, and need to be tuned
98 // using some histograms data. Trying to be conservative so as not to break
99 // existing setups when deployed. A simple exponential retry scheme would be
100 // more elegant, but places more load on server.
101 //
102 // The motivation for trying quickly after failures (8 seconds) is to recover
103 // from spurious network failures, which are common after the IP address has
104 // just changed (like DNS failing to resolve). The next 32 second boundary is
105 // to try and catch other VPN weirdness which anecdotally I have seen take
106 // 10+ seconds for some users.
107 //
108 // The motivation for re-trying after a success is to check for possible
109 // content changes to the script, or to the WPAD auto-discovery results. We are
110 // not very aggressive with these checks so as to minimize the risk of
111 // overloading existing PAC setups. Moreover it is unlikely that PAC scripts
112 // change very frequently in existing setups. More research is needed to
113 // motivate what safe values are here, and what other user agents do.
114 //
115 // Comparison to other browsers:
116 //
117 // In Firefox the PAC URL is re-tried on failures according to
118 // network.proxy.autoconfig_retry_interval_min and
119 // network.proxy.autoconfig_retry_interval_max. The defaults are 5 seconds and
120 // 5 minutes respectively. It doubles the interval at each attempt.
121 //
122 // TODO(eroman): Figure out what Internet Explorer does.
123 class DefaultPollPolicy
124     : public ConfiguredProxyResolutionService::PacPollPolicy {
125  public:
126   DefaultPollPolicy() = default;
127 
128   DefaultPollPolicy(const DefaultPollPolicy&) = delete;
129   DefaultPollPolicy& operator=(const DefaultPollPolicy&) = delete;
130 
GetNextDelay(int initial_error,base::TimeDelta current_delay,base::TimeDelta * next_delay) const131   Mode GetNextDelay(int initial_error,
132                     base::TimeDelta current_delay,
133                     base::TimeDelta* next_delay) const override {
134     if (initial_error != OK) {
135       // Re-try policy for failures.
136       const int kDelay1Seconds = 8;
137       const int kDelay2Seconds = 32;
138       const int kDelay3Seconds = 2 * 60;       // 2 minutes
139       const int kDelay4Seconds = 4 * 60 * 60;  // 4 Hours
140 
141       // Initial poll.
142       if (current_delay.is_negative()) {
143         *next_delay = base::Seconds(kDelay1Seconds);
144         return MODE_USE_TIMER;
145       }
146       switch (current_delay.InSeconds()) {
147         case kDelay1Seconds:
148           *next_delay = base::Seconds(kDelay2Seconds);
149           return MODE_START_AFTER_ACTIVITY;
150         case kDelay2Seconds:
151           *next_delay = base::Seconds(kDelay3Seconds);
152           return MODE_START_AFTER_ACTIVITY;
153         default:
154           *next_delay = base::Seconds(kDelay4Seconds);
155           return MODE_START_AFTER_ACTIVITY;
156       }
157     } else {
158       // Re-try policy for succeses.
159       *next_delay = base::Hours(12);
160       return MODE_START_AFTER_ACTIVITY;
161     }
162   }
163 };
164 
165 // Config getter that always returns direct settings.
166 class ProxyConfigServiceDirect : public ProxyConfigService {
167  public:
168   // ProxyConfigService implementation:
AddObserver(Observer * observer)169   void AddObserver(Observer* observer) override {}
RemoveObserver(Observer * observer)170   void RemoveObserver(Observer* observer) override {}
GetLatestProxyConfig(ProxyConfigWithAnnotation * config)171   ConfigAvailability GetLatestProxyConfig(
172       ProxyConfigWithAnnotation* config) override {
173     *config = ProxyConfigWithAnnotation::CreateDirect();
174     return CONFIG_VALID;
175   }
176 };
177 
178 // Proxy resolver that fails every time.
179 class ProxyResolverNull : public ProxyResolver {
180  public:
181   ProxyResolverNull() = default;
182 
183   // ProxyResolver implementation.
GetProxyForURL(const GURL & url,const NetworkAnonymizationKey & network_anonymization_key,ProxyInfo * results,CompletionOnceCallback callback,std::unique_ptr<Request> * request,const NetLogWithSource & net_log)184   int GetProxyForURL(const GURL& url,
185                      const NetworkAnonymizationKey& network_anonymization_key,
186                      ProxyInfo* results,
187                      CompletionOnceCallback callback,
188                      std::unique_ptr<Request>* request,
189                      const NetLogWithSource& net_log) override {
190     return ERR_NOT_IMPLEMENTED;
191   }
192 };
193 
194 // ProxyResolver that simulates a PAC script which returns
195 // |pac_string| for every single URL.
196 class ProxyResolverFromPacString : public ProxyResolver {
197  public:
ProxyResolverFromPacString(const std::string & pac_string)198   explicit ProxyResolverFromPacString(const std::string& pac_string)
199       : pac_string_(pac_string) {}
200 
GetProxyForURL(const GURL & url,const NetworkAnonymizationKey & network_anonymization_key,ProxyInfo * results,CompletionOnceCallback callback,std::unique_ptr<Request> * request,const NetLogWithSource & net_log)201   int GetProxyForURL(const GURL& url,
202                      const NetworkAnonymizationKey& network_anonymization_key,
203                      ProxyInfo* results,
204                      CompletionOnceCallback callback,
205                      std::unique_ptr<Request>* request,
206                      const NetLogWithSource& net_log) override {
207     results->UsePacString(pac_string_);
208     return OK;
209   }
210 
211  private:
212   const std::string pac_string_;
213 };
214 
215 // ProxyResolver that simulates a proxy chain which returns
216 // |proxy_chain| for every single URL.
217 class ProxyResolverFromProxyChains : public ProxyResolver {
218  public:
ProxyResolverFromProxyChains(const std::vector<ProxyChain> & proxy_chains)219   explicit ProxyResolverFromProxyChains(
220       const std::vector<ProxyChain>& proxy_chains)
221       : proxy_chains_(proxy_chains) {}
222 
GetProxyForURL(const GURL & url,const NetworkAnonymizationKey & network_anonymization_key,ProxyInfo * results,CompletionOnceCallback callback,std::unique_ptr<Request> * request,const NetLogWithSource & net_log)223   int GetProxyForURL(const GURL& url,
224                      const NetworkAnonymizationKey& network_anonymization_key,
225                      ProxyInfo* results,
226                      CompletionOnceCallback callback,
227                      std::unique_ptr<Request>* request,
228                      const NetLogWithSource& net_log) override {
229     net::ProxyList proxy_list;
230     for (const ProxyChain& proxy_chain : proxy_chains_) {
231       proxy_list.AddProxyChain(proxy_chain);
232     }
233     results->UseProxyList(proxy_list);
234     return OK;
235   }
236 
237  private:
238   const std::vector<ProxyChain> proxy_chains_;
239 };
240 
241 // Creates ProxyResolvers using a platform-specific implementation.
242 class ProxyResolverFactoryForSystem : public MultiThreadedProxyResolverFactory {
243  public:
ProxyResolverFactoryForSystem(size_t max_num_threads)244   explicit ProxyResolverFactoryForSystem(size_t max_num_threads)
245       : MultiThreadedProxyResolverFactory(max_num_threads,
246                                           false /*expects_pac_bytes*/) {}
247 
248   ProxyResolverFactoryForSystem(const ProxyResolverFactoryForSystem&) = delete;
249   ProxyResolverFactoryForSystem& operator=(
250       const ProxyResolverFactoryForSystem&) = delete;
251 
CreateProxyResolverFactory()252   std::unique_ptr<ProxyResolverFactory> CreateProxyResolverFactory() override {
253 #if BUILDFLAG(IS_WIN)
254     return std::make_unique<ProxyResolverFactoryWinHttp>();
255 #elif BUILDFLAG(IS_APPLE)
256     return std::make_unique<ProxyResolverFactoryApple>();
257 #else
258     NOTREACHED();
259     return nullptr;
260 #endif
261   }
262 
IsSupported()263   static bool IsSupported() {
264 #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_APPLE)
265     return true;
266 #else
267     return false;
268 #endif
269   }
270 };
271 
272 class ProxyResolverFactoryForNullResolver : public ProxyResolverFactory {
273  public:
ProxyResolverFactoryForNullResolver()274   ProxyResolverFactoryForNullResolver() : ProxyResolverFactory(false) {}
275 
276   ProxyResolverFactoryForNullResolver(
277       const ProxyResolverFactoryForNullResolver&) = delete;
278   ProxyResolverFactoryForNullResolver& operator=(
279       const ProxyResolverFactoryForNullResolver&) = delete;
280 
281   // ProxyResolverFactory overrides.
CreateProxyResolver(const scoped_refptr<PacFileData> & pac_script,std::unique_ptr<ProxyResolver> * resolver,CompletionOnceCallback callback,std::unique_ptr<Request> * request)282   int CreateProxyResolver(const scoped_refptr<PacFileData>& pac_script,
283                           std::unique_ptr<ProxyResolver>* resolver,
284                           CompletionOnceCallback callback,
285                           std::unique_ptr<Request>* request) override {
286     *resolver = std::make_unique<ProxyResolverNull>();
287     return OK;
288   }
289 };
290 
291 class ProxyResolverFactoryForPacResult : public ProxyResolverFactory {
292  public:
ProxyResolverFactoryForPacResult(const std::string & pac_string)293   explicit ProxyResolverFactoryForPacResult(const std::string& pac_string)
294       : ProxyResolverFactory(false), pac_string_(pac_string) {}
295 
296   ProxyResolverFactoryForPacResult(const ProxyResolverFactoryForPacResult&) =
297       delete;
298   ProxyResolverFactoryForPacResult& operator=(
299       const ProxyResolverFactoryForPacResult&) = delete;
300 
301   // ProxyResolverFactory override.
CreateProxyResolver(const scoped_refptr<PacFileData> & pac_script,std::unique_ptr<ProxyResolver> * resolver,CompletionOnceCallback callback,std::unique_ptr<Request> * request)302   int CreateProxyResolver(const scoped_refptr<PacFileData>& pac_script,
303                           std::unique_ptr<ProxyResolver>* resolver,
304                           CompletionOnceCallback callback,
305                           std::unique_ptr<Request>* request) override {
306     *resolver = std::make_unique<ProxyResolverFromPacString>(pac_string_);
307     return OK;
308   }
309 
310  private:
311   const std::string pac_string_;
312 };
313 
314 class ProxyResolverFactoryForProxyChains : public ProxyResolverFactory {
315  public:
ProxyResolverFactoryForProxyChains(const std::vector<ProxyChain> & proxy_chains)316   explicit ProxyResolverFactoryForProxyChains(
317       const std::vector<ProxyChain>& proxy_chains)
318       : ProxyResolverFactory(false), proxy_chains_(proxy_chains) {}
319 
320   ProxyResolverFactoryForProxyChains(
321       const ProxyResolverFactoryForProxyChains&) = delete;
322   ProxyResolverFactoryForProxyChains& operator=(
323       const ProxyResolverFactoryForProxyChains&) = delete;
324 
325   // ProxyResolverFactory override.
CreateProxyResolver(const scoped_refptr<PacFileData> & pac_script,std::unique_ptr<ProxyResolver> * resolver,CompletionOnceCallback callback,std::unique_ptr<Request> * request)326   int CreateProxyResolver(const scoped_refptr<PacFileData>& pac_script,
327                           std::unique_ptr<ProxyResolver>* resolver,
328                           CompletionOnceCallback callback,
329                           std::unique_ptr<Request>* request) override {
330     *resolver = std::make_unique<ProxyResolverFromProxyChains>(proxy_chains_);
331     return OK;
332   }
333 
334  private:
335   const std::vector<ProxyChain> proxy_chains_;
336 };
337 
338 // Returns NetLog parameters describing a proxy configuration change.
NetLogProxyConfigChangedParams(const std::optional<ProxyConfigWithAnnotation> * old_config,const ProxyConfigWithAnnotation * new_config)339 base::Value::Dict NetLogProxyConfigChangedParams(
340     const std::optional<ProxyConfigWithAnnotation>* old_config,
341     const ProxyConfigWithAnnotation* new_config) {
342   base::Value::Dict dict;
343   // The "old_config" is optional -- the first notification will not have
344   // any "previous" configuration.
345   if (old_config->has_value())
346     dict.Set("old_config", (*old_config)->value().ToValue());
347   dict.Set("new_config", new_config->value().ToValue());
348   return dict;
349 }
350 
NetLogBadProxyListParams(const ProxyRetryInfoMap * retry_info)351 base::Value::Dict NetLogBadProxyListParams(
352     const ProxyRetryInfoMap* retry_info) {
353   base::Value::Dict dict;
354   base::Value::List list;
355 
356   for (const auto& retry_info_pair : *retry_info)
357     list.Append(retry_info_pair.first.ToDebugString());
358   dict.Set("bad_proxy_list", std::move(list));
359   return dict;
360 }
361 
362 // Returns NetLog parameters on a successful proxy resolution.
NetLogFinishedResolvingProxyParams(const ProxyInfo * result)363 base::Value::Dict NetLogFinishedResolvingProxyParams(const ProxyInfo* result) {
364   base::Value::Dict dict;
365   dict.Set("proxy_info", result->ToDebugString());
366   return dict;
367 }
368 
369 // Returns a sanitized copy of |url| which is safe to pass on to a PAC script.
370 //
371 // PAC scripts are modelled as being controllable by a network-present
372 // attacker (since such an attacker can influence the outcome of proxy
373 // auto-discovery, or modify the contents of insecurely delivered PAC scripts).
374 //
375 // As such, it is important that the full path/query of https:// URLs not be
376 // sent to PAC scripts, since that would give an attacker access to data that
377 // is ordinarily protected by TLS.
378 //
379 // Obscuring the path for http:// URLs isn't being done since it doesn't matter
380 // for security (attacker can already route traffic through their HTTP proxy
381 // and see the full URL for http:// requests).
382 //
383 // TODO(https://crbug.com/882536): Use the same stripping for insecure URL
384 // schemes.
SanitizeUrl(const GURL & url)385 GURL SanitizeUrl(const GURL& url) {
386   DCHECK(url.is_valid());
387 
388   GURL::Replacements replacements;
389   replacements.ClearUsername();
390   replacements.ClearPassword();
391   replacements.ClearRef();
392 
393   if (url.SchemeIsCryptographic()) {
394     replacements.ClearPath();
395     replacements.ClearQuery();
396   }
397 
398   return url.ReplaceComponents(replacements);
399 }
400 
401 }  // namespace
402 
403 // ConfiguredProxyResolutionService::InitProxyResolver
404 // ----------------------------------
405 
406 // This glues together two asynchronous steps:
407 //   (1) PacFileDecider -- try to fetch/validate a sequence of PAC scripts
408 //       to figure out what we should configure against.
409 //   (2) Feed the fetched PAC script into the ProxyResolver.
410 //
411 // InitProxyResolver is a single-use class which encapsulates cancellation as
412 // part of its destructor. Start() or StartSkipDecider() should be called just
413 // once. The instance can be destroyed at any time, and the request will be
414 // cancelled.
415 
416 class ConfiguredProxyResolutionService::InitProxyResolver {
417  public:
418   InitProxyResolver() = default;
419 
420   InitProxyResolver(const InitProxyResolver&) = delete;
421   InitProxyResolver& operator=(const InitProxyResolver&) = delete;
422 
423   // Note that the destruction of PacFileDecider will automatically cancel
424   // any outstanding work.
425   ~InitProxyResolver() = default;
426 
427   // Begins initializing the proxy resolver; calls |callback| when done. A
428   // ProxyResolver instance will be created using |proxy_resolver_factory| and
429   // assigned to |*proxy_resolver| if the final result is OK.
Start(std::unique_ptr<ProxyResolver> * proxy_resolver,ProxyResolverFactory * proxy_resolver_factory,PacFileFetcher * pac_file_fetcher,DhcpPacFileFetcher * dhcp_pac_file_fetcher,NetLog * net_log,const ProxyConfigWithAnnotation & config,base::TimeDelta wait_delay,CompletionOnceCallback callback)430   int Start(std::unique_ptr<ProxyResolver>* proxy_resolver,
431             ProxyResolverFactory* proxy_resolver_factory,
432             PacFileFetcher* pac_file_fetcher,
433             DhcpPacFileFetcher* dhcp_pac_file_fetcher,
434             NetLog* net_log,
435             const ProxyConfigWithAnnotation& config,
436             base::TimeDelta wait_delay,
437             CompletionOnceCallback callback) {
438     DCHECK_EQ(State::kNone, next_state_);
439     proxy_resolver_ = proxy_resolver;
440     proxy_resolver_factory_ = proxy_resolver_factory;
441 
442     decider_ = std::make_unique<PacFileDecider>(pac_file_fetcher,
443                                                 dhcp_pac_file_fetcher, net_log);
444     decider_->set_quick_check_enabled(quick_check_enabled_);
445     config_ = config;
446     wait_delay_ = wait_delay;
447     callback_ = std::move(callback);
448 
449     next_state_ = State::kDecidePacFile;
450     return DoLoop(OK);
451   }
452 
453   // Similar to Start(), however it skips the PacFileDecider stage. Instead
454   // |effective_config|, |decider_result| and |script_data| will be used as the
455   // inputs for initializing the ProxyResolver. A ProxyResolver instance will
456   // be created using |proxy_resolver_factory| and assigned to
457   // |*proxy_resolver| if the final result is OK.
StartSkipDecider(std::unique_ptr<ProxyResolver> * proxy_resolver,ProxyResolverFactory * proxy_resolver_factory,const ProxyConfigWithAnnotation & effective_config,int decider_result,const PacFileDataWithSource & script_data,CompletionOnceCallback callback)458   int StartSkipDecider(std::unique_ptr<ProxyResolver>* proxy_resolver,
459                        ProxyResolverFactory* proxy_resolver_factory,
460                        const ProxyConfigWithAnnotation& effective_config,
461                        int decider_result,
462                        const PacFileDataWithSource& script_data,
463                        CompletionOnceCallback callback) {
464     DCHECK_EQ(State::kNone, next_state_);
465     proxy_resolver_ = proxy_resolver;
466     proxy_resolver_factory_ = proxy_resolver_factory;
467 
468     effective_config_ = effective_config;
469     script_data_ = script_data;
470     callback_ = std::move(callback);
471 
472     if (decider_result != OK)
473       return decider_result;
474 
475     next_state_ = State::kCreateResolver;
476     return DoLoop(OK);
477   }
478 
479   // Returns the proxy configuration that was selected by PacFileDecider.
480   // Should only be called upon completion of the initialization.
effective_config() const481   const ProxyConfigWithAnnotation& effective_config() const {
482     DCHECK_EQ(State::kNone, next_state_);
483     return effective_config_;
484   }
485 
486   // Returns the PAC script data that was selected by PacFileDecider.
487   // Should only be called upon completion of the initialization.
script_data()488   const PacFileDataWithSource& script_data() {
489     DCHECK_EQ(State::kNone, next_state_);
490     return script_data_;
491   }
492 
GetLoadState() const493   LoadState GetLoadState() const {
494     if (next_state_ == State::kDecidePacFileComplete) {
495       // In addition to downloading, this state may also include the stall time
496       // after network change events (kDelayAfterNetworkChangesMs).
497       return LOAD_STATE_DOWNLOADING_PAC_FILE;
498     }
499     return LOAD_STATE_RESOLVING_PROXY_FOR_URL;
500   }
501 
502   // This must be called before the HostResolver is torn down.
OnShutdown()503   void OnShutdown() {
504     if (decider_)
505       decider_->OnShutdown();
506   }
507 
set_quick_check_enabled(bool enabled)508   void set_quick_check_enabled(bool enabled) { quick_check_enabled_ = enabled; }
quick_check_enabled() const509   bool quick_check_enabled() const { return quick_check_enabled_; }
510 
511  private:
512   enum class State {
513     kNone,
514     kDecidePacFile,
515     kDecidePacFileComplete,
516     kCreateResolver,
517     kCreateResolverComplete,
518   };
519 
DoLoop(int result)520   int DoLoop(int result) {
521     DCHECK_NE(next_state_, State::kNone);
522     int rv = result;
523     do {
524       State state = next_state_;
525       next_state_ = State::kNone;
526       switch (state) {
527         case State::kDecidePacFile:
528           DCHECK_EQ(OK, rv);
529           rv = DoDecidePacFile();
530           break;
531         case State::kDecidePacFileComplete:
532           rv = DoDecidePacFileComplete(rv);
533           break;
534         case State::kCreateResolver:
535           DCHECK_EQ(OK, rv);
536           rv = DoCreateResolver();
537           break;
538         case State::kCreateResolverComplete:
539           rv = DoCreateResolverComplete(rv);
540           break;
541         default:
542           NOTREACHED() << "bad state: " << static_cast<int>(state);
543           rv = ERR_UNEXPECTED;
544           break;
545       }
546     } while (rv != ERR_IO_PENDING && next_state_ != State::kNone);
547     return rv;
548   }
549 
DoDecidePacFile()550   int DoDecidePacFile() {
551     next_state_ = State::kDecidePacFileComplete;
552 
553     return decider_->Start(config_, wait_delay_,
554                            proxy_resolver_factory_->expects_pac_bytes(),
555                            base::BindOnce(&InitProxyResolver::OnIOCompletion,
556                                           base::Unretained(this)));
557   }
558 
DoDecidePacFileComplete(int result)559   int DoDecidePacFileComplete(int result) {
560     if (result != OK)
561       return result;
562 
563     effective_config_ = decider_->effective_config();
564     script_data_ = decider_->script_data();
565 
566     next_state_ = State::kCreateResolver;
567     return OK;
568   }
569 
DoCreateResolver()570   int DoCreateResolver() {
571     DCHECK(script_data_.data);
572     // TODO(eroman): Should log this latency to the NetLog.
573     next_state_ = State::kCreateResolverComplete;
574     return proxy_resolver_factory_->CreateProxyResolver(
575         script_data_.data, proxy_resolver_,
576         base::BindOnce(&InitProxyResolver::OnIOCompletion,
577                        base::Unretained(this)),
578         &create_resolver_request_);
579   }
580 
DoCreateResolverComplete(int result)581   int DoCreateResolverComplete(int result) {
582     if (result != OK)
583       proxy_resolver_->reset();
584     return result;
585   }
586 
OnIOCompletion(int result)587   void OnIOCompletion(int result) {
588     DCHECK_NE(State::kNone, next_state_);
589     int rv = DoLoop(result);
590     if (rv != ERR_IO_PENDING)
591       std::move(callback_).Run(result);
592   }
593 
594   ProxyConfigWithAnnotation config_;
595   ProxyConfigWithAnnotation effective_config_;
596   PacFileDataWithSource script_data_;
597   base::TimeDelta wait_delay_;
598   std::unique_ptr<PacFileDecider> decider_;
599   raw_ptr<ProxyResolverFactory> proxy_resolver_factory_ = nullptr;
600   std::unique_ptr<ProxyResolverFactory::Request> create_resolver_request_;
601   raw_ptr<std::unique_ptr<ProxyResolver>> proxy_resolver_ = nullptr;
602   CompletionOnceCallback callback_;
603   State next_state_ = State::kNone;
604   bool quick_check_enabled_ = true;
605 };
606 
607 // ConfiguredProxyResolutionService::PacFileDeciderPoller
608 // ---------------------------
609 
610 // This helper class encapsulates the logic to schedule and run periodic
611 // background checks to see if the PAC script (or effective proxy configuration)
612 // has changed. If a change is detected, then the caller will be notified via
613 // the ChangeCallback.
614 class ConfiguredProxyResolutionService::PacFileDeciderPoller {
615  public:
616   typedef base::RepeatingCallback<
617       void(int, const PacFileDataWithSource&, const ProxyConfigWithAnnotation&)>
618       ChangeCallback;
619 
620   // Builds a poller helper, and starts polling for updates. Whenever a change
621   // is observed, |callback| will be invoked with the details.
622   //
623   //   |config| specifies the (unresolved) proxy configuration to poll.
624   //   |proxy_resolver_expects_pac_bytes| the type of proxy resolver we expect
625   //                                      to use the resulting script data with
626   //                                      (so it can choose the right format).
627   //   |pac_file_fetcher| this pointer must remain alive throughout our
628   //                      lifetime. It is the dependency that will be used
629   //                      for downloading PAC files.
630   //   |dhcp_pac_file_fetcher| similar to |pac_file_fetcher|, but for
631   //                           he DHCP dependency.
632   //   |init_net_error| This is the initial network error (possibly success)
633   //                    encountered by the first PAC fetch attempt. We use it
634   //                    to schedule updates more aggressively if the initial
635   //                    fetch resulted in an error.
636   //   |init_script_data| the initial script data from the PAC fetch attempt.
637   //                      This is the baseline used to determine when the
638   //                      script's contents have changed.
639   //   |net_log| the NetLog to log progress into.
PacFileDeciderPoller(ChangeCallback callback,const ProxyConfigWithAnnotation & config,bool proxy_resolver_expects_pac_bytes,PacFileFetcher * pac_file_fetcher,DhcpPacFileFetcher * dhcp_pac_file_fetcher,int init_net_error,const PacFileDataWithSource & init_script_data,NetLog * net_log)640   PacFileDeciderPoller(ChangeCallback callback,
641                        const ProxyConfigWithAnnotation& config,
642                        bool proxy_resolver_expects_pac_bytes,
643                        PacFileFetcher* pac_file_fetcher,
644                        DhcpPacFileFetcher* dhcp_pac_file_fetcher,
645                        int init_net_error,
646                        const PacFileDataWithSource& init_script_data,
647                        NetLog* net_log)
648       : change_callback_(callback),
649         config_(config),
650         proxy_resolver_expects_pac_bytes_(proxy_resolver_expects_pac_bytes),
651         pac_file_fetcher_(pac_file_fetcher),
652         dhcp_pac_file_fetcher_(dhcp_pac_file_fetcher),
653         last_error_(init_net_error),
654         last_script_data_(init_script_data),
655         last_poll_time_(TimeTicks::Now()),
656         net_log_(net_log) {
657     // Set the initial poll delay.
658     next_poll_mode_ = poll_policy()->GetNextDelay(
659         last_error_, base::Seconds(-1), &next_poll_delay_);
660     TryToStartNextPoll(false);
661   }
662 
663   PacFileDeciderPoller(const PacFileDeciderPoller&) = delete;
664   PacFileDeciderPoller& operator=(const PacFileDeciderPoller&) = delete;
665 
OnLazyPoll()666   void OnLazyPoll() {
667     // We have just been notified of network activity. Use this opportunity to
668     // see if we can start our next poll.
669     TryToStartNextPoll(true);
670   }
671 
set_policy(const PacPollPolicy * policy)672   static const PacPollPolicy* set_policy(const PacPollPolicy* policy) {
673     const PacPollPolicy* prev = poll_policy_;
674     poll_policy_ = policy;
675     return prev;
676   }
677 
set_quick_check_enabled(bool enabled)678   void set_quick_check_enabled(bool enabled) { quick_check_enabled_ = enabled; }
quick_check_enabled() const679   bool quick_check_enabled() const { return quick_check_enabled_; }
680 
681  private:
682   // Returns the effective poll policy (the one injected by unit-tests, or the
683   // default).
poll_policy()684   const PacPollPolicy* poll_policy() {
685     if (poll_policy_)
686       return poll_policy_;
687     return &default_poll_policy_;
688   }
689 
StartPollTimer()690   void StartPollTimer() {
691     DCHECK(!decider_.get());
692 
693     base::SingleThreadTaskRunner::GetCurrentDefault()->PostDelayedTask(
694         FROM_HERE,
695         base::BindOnce(&PacFileDeciderPoller::DoPoll,
696                        weak_factory_.GetWeakPtr()),
697         next_poll_delay_);
698   }
699 
TryToStartNextPoll(bool triggered_by_activity)700   void TryToStartNextPoll(bool triggered_by_activity) {
701     switch (next_poll_mode_) {
702       case PacPollPolicy::MODE_USE_TIMER:
703         if (!triggered_by_activity)
704           StartPollTimer();
705         break;
706 
707       case PacPollPolicy::MODE_START_AFTER_ACTIVITY:
708         if (triggered_by_activity && !decider_.get()) {
709           base::TimeDelta elapsed_time = TimeTicks::Now() - last_poll_time_;
710           if (elapsed_time >= next_poll_delay_)
711             DoPoll();
712         }
713         break;
714     }
715   }
716 
DoPoll()717   void DoPoll() {
718     last_poll_time_ = TimeTicks::Now();
719 
720     // Start the PAC file decider to see if anything has changed.
721     decider_ = std::make_unique<PacFileDecider>(
722         pac_file_fetcher_, dhcp_pac_file_fetcher_, net_log_);
723     decider_->set_quick_check_enabled(quick_check_enabled_);
724     int result = decider_->Start(
725         config_, base::TimeDelta(), proxy_resolver_expects_pac_bytes_,
726         base::BindOnce(&PacFileDeciderPoller::OnPacFileDeciderCompleted,
727                        base::Unretained(this)));
728 
729     if (result != ERR_IO_PENDING)
730       OnPacFileDeciderCompleted(result);
731   }
732 
OnPacFileDeciderCompleted(int result)733   void OnPacFileDeciderCompleted(int result) {
734     if (HasScriptDataChanged(result, decider_->script_data())) {
735       // Something has changed, we must notify the
736       // ConfiguredProxyResolutionService so it can re-initialize its
737       // ProxyResolver. Note that we post a notification task rather than
738       // calling it directly -- this is done to avoid an ugly destruction
739       // sequence, since |this| might be destroyed as a result of the
740       // notification.
741       base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
742           FROM_HERE,
743           base::BindOnce(
744               &PacFileDeciderPoller::NotifyProxyResolutionServiceOfChange,
745               weak_factory_.GetWeakPtr(), result, decider_->script_data(),
746               decider_->effective_config()));
747       return;
748     }
749 
750     decider_.reset();
751 
752     // Decide when the next poll should take place, and possibly start the
753     // next timer.
754     next_poll_mode_ = poll_policy()->GetNextDelay(last_error_, next_poll_delay_,
755                                                   &next_poll_delay_);
756     TryToStartNextPoll(false);
757   }
758 
HasScriptDataChanged(int result,const PacFileDataWithSource & script_data)759   bool HasScriptDataChanged(int result,
760                             const PacFileDataWithSource& script_data) {
761     if (result != last_error_) {
762       // Something changed -- it was failing before and now it succeeded, or
763       // conversely it succeeded before and now it failed. Or it failed in
764       // both cases, however the specific failure error codes differ.
765       return true;
766     }
767 
768     if (result != OK) {
769       // If it failed last time and failed again with the same error code this
770       // time, then nothing has actually changed.
771       return false;
772     }
773 
774     // Otherwise if it succeeded both this time and last time, we need to look
775     // closer and see if we ended up downloading different content for the PAC
776     // script.
777     return !script_data.data->Equals(last_script_data_.data.get()) ||
778            (script_data.from_auto_detect != last_script_data_.from_auto_detect);
779   }
780 
NotifyProxyResolutionServiceOfChange(int result,const PacFileDataWithSource & script_data,const ProxyConfigWithAnnotation & effective_config)781   void NotifyProxyResolutionServiceOfChange(
782       int result,
783       const PacFileDataWithSource& script_data,
784       const ProxyConfigWithAnnotation& effective_config) {
785     // Note that |this| may be deleted after calling into the
786     // ConfiguredProxyResolutionService.
787     change_callback_.Run(result, script_data, effective_config);
788   }
789 
790   ChangeCallback change_callback_;
791   ProxyConfigWithAnnotation config_;
792   bool proxy_resolver_expects_pac_bytes_;
793   raw_ptr<PacFileFetcher> pac_file_fetcher_;
794   raw_ptr<DhcpPacFileFetcher> dhcp_pac_file_fetcher_;
795 
796   int last_error_;
797   PacFileDataWithSource last_script_data_;
798 
799   std::unique_ptr<PacFileDecider> decider_;
800   base::TimeDelta next_poll_delay_;
801   PacPollPolicy::Mode next_poll_mode_;
802 
803   TimeTicks last_poll_time_;
804 
805   const raw_ptr<NetLog> net_log_;
806 
807   // Polling policy injected by unit-tests. Otherwise this is nullptr and the
808   // default policy will be used.
809   static const PacPollPolicy* poll_policy_;
810 
811   const DefaultPollPolicy default_poll_policy_;
812 
813   bool quick_check_enabled_;
814 
815   base::WeakPtrFactory<PacFileDeciderPoller> weak_factory_{this};
816 };
817 
818 // static
819 const ConfiguredProxyResolutionService::PacPollPolicy*
820     ConfiguredProxyResolutionService::PacFileDeciderPoller::poll_policy_ =
821         nullptr;
822 
823 // ConfiguredProxyResolutionService
824 // -----------------------------------------------------
825 
ConfiguredProxyResolutionService(std::unique_ptr<ProxyConfigService> config_service,std::unique_ptr<ProxyResolverFactory> resolver_factory,NetLog * net_log,bool quick_check_enabled)826 ConfiguredProxyResolutionService::ConfiguredProxyResolutionService(
827     std::unique_ptr<ProxyConfigService> config_service,
828     std::unique_ptr<ProxyResolverFactory> resolver_factory,
829     NetLog* net_log,
830     bool quick_check_enabled)
831     : config_service_(std::move(config_service)),
832       resolver_factory_(std::move(resolver_factory)),
833       net_log_(net_log),
834       stall_proxy_auto_config_delay_(
835           base::Milliseconds(kDelayAfterNetworkChangesMs)),
836       quick_check_enabled_(quick_check_enabled) {
837   NetworkChangeNotifier::AddIPAddressObserver(this);
838   NetworkChangeNotifier::AddDNSObserver(this);
839   config_service_->AddObserver(this);
840 }
841 
842 // static
843 std::unique_ptr<ConfiguredProxyResolutionService>
CreateUsingSystemProxyResolver(std::unique_ptr<ProxyConfigService> proxy_config_service,NetLog * net_log,bool quick_check_enabled)844 ConfiguredProxyResolutionService::CreateUsingSystemProxyResolver(
845     std::unique_ptr<ProxyConfigService> proxy_config_service,
846     NetLog* net_log,
847     bool quick_check_enabled) {
848   DCHECK(proxy_config_service);
849 
850   if (!ProxyResolverFactoryForSystem::IsSupported()) {
851     VLOG(1) << "PAC support disabled because there is no system implementation";
852     return CreateWithoutProxyResolver(std::move(proxy_config_service), net_log);
853   }
854 
855   std::unique_ptr<ConfiguredProxyResolutionService> proxy_resolution_service =
856       std::make_unique<ConfiguredProxyResolutionService>(
857           std::move(proxy_config_service),
858           std::make_unique<ProxyResolverFactoryForSystem>(
859               kDefaultNumPacThreads),
860           net_log, quick_check_enabled);
861   return proxy_resolution_service;
862 }
863 
864 // static
865 std::unique_ptr<ConfiguredProxyResolutionService>
CreateWithoutProxyResolver(std::unique_ptr<ProxyConfigService> proxy_config_service,NetLog * net_log)866 ConfiguredProxyResolutionService::CreateWithoutProxyResolver(
867     std::unique_ptr<ProxyConfigService> proxy_config_service,
868     NetLog* net_log) {
869   return std::make_unique<ConfiguredProxyResolutionService>(
870       std::move(proxy_config_service),
871       std::make_unique<ProxyResolverFactoryForNullResolver>(), net_log,
872       /*quick_check_enabled=*/false);
873 }
874 
875 // static
876 std::unique_ptr<ConfiguredProxyResolutionService>
CreateFixedForTest(const ProxyConfigWithAnnotation & pc)877 ConfiguredProxyResolutionService::CreateFixedForTest(
878     const ProxyConfigWithAnnotation& pc) {
879   // TODO(eroman): This isn't quite right, won't work if |pc| specifies
880   //               a PAC script.
881   return CreateUsingSystemProxyResolver(
882       std::make_unique<ProxyConfigServiceFixed>(pc), nullptr,
883       /*quick_check_enabled=*/true);
884 }
885 
886 // static
887 std::unique_ptr<ConfiguredProxyResolutionService>
CreateFixedForTest(const std::string & proxy,const NetworkTrafficAnnotationTag & traffic_annotation)888 ConfiguredProxyResolutionService::CreateFixedForTest(
889     const std::string& proxy,
890     const NetworkTrafficAnnotationTag& traffic_annotation) {
891   ProxyConfig proxy_config;
892   proxy_config.proxy_rules().ParseFromString(proxy);
893   ProxyConfigWithAnnotation annotated_config(proxy_config, traffic_annotation);
894   return ConfiguredProxyResolutionService::CreateFixedForTest(annotated_config);
895 }
896 
897 // static
898 std::unique_ptr<ConfiguredProxyResolutionService>
CreateDirect()899 ConfiguredProxyResolutionService::CreateDirect() {
900   // Use direct connections.
901   return std::make_unique<ConfiguredProxyResolutionService>(
902       std::make_unique<ProxyConfigServiceDirect>(),
903       std::make_unique<ProxyResolverFactoryForNullResolver>(), nullptr,
904       /*quick_check_enabled=*/true);
905 }
906 
907 // static
908 std::unique_ptr<ConfiguredProxyResolutionService>
CreateFixedFromPacResultForTest(const std::string & pac_string,const NetworkTrafficAnnotationTag & traffic_annotation)909 ConfiguredProxyResolutionService::CreateFixedFromPacResultForTest(
910     const std::string& pac_string,
911     const NetworkTrafficAnnotationTag& traffic_annotation) {
912   // We need the settings to contain an "automatic" setting, otherwise the
913   // ProxyResolver dependency we give it will never be used.
914   auto proxy_config_service = std::make_unique<ProxyConfigServiceFixed>(
915       ProxyConfigWithAnnotation(ProxyConfig::CreateFromCustomPacURL(GURL(
916                                     "https://my-pac-script.invalid/wpad.dat")),
917                                 traffic_annotation));
918 
919   return std::make_unique<ConfiguredProxyResolutionService>(
920       std::move(proxy_config_service),
921       std::make_unique<ProxyResolverFactoryForPacResult>(pac_string), nullptr,
922       /*quick_check_enabled=*/true);
923 }
924 
925 // static
926 std::unique_ptr<ConfiguredProxyResolutionService>
CreateFixedFromAutoDetectedPacResultForTest(const std::string & pac_string,const NetworkTrafficAnnotationTag & traffic_annotation)927 ConfiguredProxyResolutionService::CreateFixedFromAutoDetectedPacResultForTest(
928     const std::string& pac_string,
929     const NetworkTrafficAnnotationTag& traffic_annotation) {
930   auto proxy_config_service =
931       std::make_unique<ProxyConfigServiceFixed>(ProxyConfigWithAnnotation(
932           ProxyConfig::CreateAutoDetect(), traffic_annotation));
933 
934   return std::make_unique<ConfiguredProxyResolutionService>(
935       std::move(proxy_config_service),
936       std::make_unique<ProxyResolverFactoryForPacResult>(pac_string), nullptr,
937       /*quick_check_enabled=*/true);
938 }
939 
940 // static
941 std::unique_ptr<ConfiguredProxyResolutionService>
CreateFixedFromProxyChainsForTest(const std::vector<ProxyChain> & proxy_chains,const NetworkTrafficAnnotationTag & traffic_annotation)942 ConfiguredProxyResolutionService::CreateFixedFromProxyChainsForTest(
943     const std::vector<ProxyChain>& proxy_chains,
944     const NetworkTrafficAnnotationTag& traffic_annotation) {
945   // We need the settings to contain an "automatic" setting, otherwise the
946   // ProxyResolver dependency we give it will never be used.
947   auto proxy_config_service = std::make_unique<ProxyConfigServiceFixed>(
948       ProxyConfigWithAnnotation(ProxyConfig::CreateFromCustomPacURL(GURL(
949                                     "https://my-pac-script.invalid/wpad.dat")),
950                                 traffic_annotation));
951 
952   return std::make_unique<ConfiguredProxyResolutionService>(
953       std::move(proxy_config_service),
954       std::make_unique<ProxyResolverFactoryForProxyChains>(proxy_chains),
955       nullptr,
956       /*quick_check_enabled=*/true);
957 }
958 
ResolveProxy(const GURL & raw_url,const std::string & method,const NetworkAnonymizationKey & network_anonymization_key,ProxyInfo * result,CompletionOnceCallback callback,std::unique_ptr<ProxyResolutionRequest> * out_request,const NetLogWithSource & net_log)959 int ConfiguredProxyResolutionService::ResolveProxy(
960     const GURL& raw_url,
961     const std::string& method,
962     const NetworkAnonymizationKey& network_anonymization_key,
963     ProxyInfo* result,
964     CompletionOnceCallback callback,
965     std::unique_ptr<ProxyResolutionRequest>* out_request,
966     const NetLogWithSource& net_log) {
967   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
968   DCHECK(!callback.is_null());
969   DCHECK(out_request);
970 
971   net_log.BeginEvent(NetLogEventType::PROXY_RESOLUTION_SERVICE);
972 
973   // Notify our polling-based dependencies that a resolve is taking place.
974   // This way they can schedule their polls in response to network activity.
975   config_service_->OnLazyPoll();
976   if (script_poller_.get())
977     script_poller_->OnLazyPoll();
978 
979   if (current_state_ == STATE_NONE)
980     ApplyProxyConfigIfAvailable();
981 
982   // Sanitize the URL before passing it on to the proxy resolver (i.e. PAC
983   // script). The goal is to remove sensitive data (like embedded user names
984   // and password), and local data (i.e. reference fragment) which does not need
985   // to be disclosed to the resolver.
986   GURL url = SanitizeUrl(raw_url);
987 
988   // Check if the request can be completed right away. (This is the case when
989   // using a direct connection for example).
990   int rv = TryToCompleteSynchronously(url, result);
991   if (rv != ERR_IO_PENDING) {
992     rv = DidFinishResolvingProxy(url, network_anonymization_key, method, result,
993                                  rv, net_log);
994     return rv;
995   }
996 
997   auto req = std::make_unique<ConfiguredProxyResolutionRequest>(
998       this, url, method, network_anonymization_key, result, std::move(callback),
999       net_log);
1000 
1001   if (current_state_ == STATE_READY) {
1002     // Start the resolve request.
1003     rv = req->Start();
1004     if (rv != ERR_IO_PENDING)
1005       return req->QueryDidCompleteSynchronously(rv);
1006   } else {
1007     req->net_log()->BeginEvent(
1008         NetLogEventType::PROXY_RESOLUTION_SERVICE_WAITING_FOR_INIT_PAC);
1009   }
1010 
1011   DCHECK_EQ(ERR_IO_PENDING, rv);
1012   DCHECK(!ContainsPendingRequest(req.get()));
1013   pending_requests_.insert(req.get());
1014 
1015   // Completion will be notified through |callback|, unless the caller cancels
1016   // the request using |out_request|.
1017   *out_request = std::move(req);
1018   return rv;  // ERR_IO_PENDING
1019 }
1020 
TryToCompleteSynchronously(const GURL & url,ProxyInfo * result)1021 int ConfiguredProxyResolutionService::TryToCompleteSynchronously(
1022     const GURL& url,
1023     ProxyInfo* result) {
1024   DCHECK_NE(STATE_NONE, current_state_);
1025 
1026   if (current_state_ != STATE_READY)
1027     return ERR_IO_PENDING;  // Still initializing.
1028 
1029   DCHECK(config_);
1030   // If it was impossible to fetch or parse the PAC script, we cannot complete
1031   // the request here and bail out.
1032   if (permanent_error_ != OK) {
1033     // Before returning the permanent error check if the URL would have been
1034     // implicitly bypassed.
1035     if (ApplyPacBypassRules(url, result))
1036       return OK;
1037     return permanent_error_;
1038   }
1039 
1040   if (config_->value().HasAutomaticSettings())
1041     return ERR_IO_PENDING;  // Must submit the request to the proxy resolver.
1042 
1043   // Use the manual proxy settings.
1044   config_->value().proxy_rules().Apply(url, result);
1045   result->set_traffic_annotation(
1046       MutableNetworkTrafficAnnotationTag(config_->traffic_annotation()));
1047 
1048   return OK;
1049 }
1050 
~ConfiguredProxyResolutionService()1051 ConfiguredProxyResolutionService::~ConfiguredProxyResolutionService() {
1052   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
1053   NetworkChangeNotifier::RemoveIPAddressObserver(this);
1054   NetworkChangeNotifier::RemoveDNSObserver(this);
1055   config_service_->RemoveObserver(this);
1056 
1057   // Cancel any inprogress requests.
1058   // This cancels the internal requests, but leaves the responsibility of
1059   // canceling the high-level Request (by deleting it) to the client.
1060   // Since |pending_requests_| might be modified in one of the requests'
1061   // callbacks (if it deletes another request), iterating through the set in a
1062   // for-loop will not work.
1063   while (!pending_requests_.empty()) {
1064     ConfiguredProxyResolutionRequest* req = *pending_requests_.begin();
1065     req->QueryComplete(ERR_ABORTED);
1066   }
1067 }
1068 
SuspendAllPendingRequests()1069 void ConfiguredProxyResolutionService::SuspendAllPendingRequests() {
1070   for (ConfiguredProxyResolutionRequest* req : pending_requests_) {
1071     if (req->is_started()) {
1072       req->CancelResolveJob();
1073 
1074       req->net_log()->BeginEvent(
1075           NetLogEventType::PROXY_RESOLUTION_SERVICE_WAITING_FOR_INIT_PAC);
1076     }
1077   }
1078 }
1079 
SetReady()1080 void ConfiguredProxyResolutionService::SetReady() {
1081   DCHECK(!init_proxy_resolver_.get());
1082   current_state_ = STATE_READY;
1083 
1084   // TODO(lilyhoughton): This is necessary because a callback invoked by
1085   // |StartAndCompleteCheckingForSynchronous()| might delete |this|.  A better
1086   // solution would be to disallow synchronous callbacks altogether.
1087   base::WeakPtr<ConfiguredProxyResolutionService> weak_this =
1088       weak_ptr_factory_.GetWeakPtr();
1089 
1090   auto pending_requests_copy = pending_requests_;
1091   for (ConfiguredProxyResolutionRequest* req : pending_requests_copy) {
1092     if (!ContainsPendingRequest(req))
1093       continue;
1094 
1095     if (!req->is_started()) {
1096       req->net_log()->EndEvent(
1097           NetLogEventType::PROXY_RESOLUTION_SERVICE_WAITING_FOR_INIT_PAC);
1098 
1099       // Note that we re-check for synchronous completion, in case we are
1100       // no longer using a ProxyResolver (can happen if we fell-back to manual.)
1101       req->StartAndCompleteCheckingForSynchronous();
1102       if (!weak_this)
1103         return;  // Synchronous callback deleted |this|
1104     }
1105   }
1106 }
1107 
ApplyProxyConfigIfAvailable()1108 void ConfiguredProxyResolutionService::ApplyProxyConfigIfAvailable() {
1109   DCHECK_EQ(STATE_NONE, current_state_);
1110 
1111   config_service_->OnLazyPoll();
1112 
1113   // If we have already fetched the configuration, start applying it.
1114   if (fetched_config_) {
1115     InitializeUsingLastFetchedConfig();
1116     return;
1117   }
1118 
1119   // Otherwise we need to first fetch the configuration.
1120   current_state_ = STATE_WAITING_FOR_PROXY_CONFIG;
1121 
1122   // Retrieve the current proxy configuration from the ProxyConfigService.
1123   // If a configuration is not available yet, we will get called back later
1124   // by our ProxyConfigService::Observer once it changes.
1125   ProxyConfigWithAnnotation config;
1126   ProxyConfigService::ConfigAvailability availability =
1127       config_service_->GetLatestProxyConfig(&config);
1128   if (availability != ProxyConfigService::CONFIG_PENDING)
1129     OnProxyConfigChanged(config, availability);
1130 }
1131 
OnInitProxyResolverComplete(int result)1132 void ConfiguredProxyResolutionService::OnInitProxyResolverComplete(int result) {
1133   DCHECK_EQ(STATE_WAITING_FOR_INIT_PROXY_RESOLVER, current_state_);
1134   DCHECK(init_proxy_resolver_.get());
1135   DCHECK(fetched_config_);
1136   DCHECK(fetched_config_->value().HasAutomaticSettings());
1137   config_ = init_proxy_resolver_->effective_config();
1138 
1139   // At this point we have decided which proxy settings to use (i.e. which PAC
1140   // script if any). We start up a background poller to periodically revisit
1141   // this decision. If the contents of the PAC script change, or if the
1142   // result of proxy auto-discovery changes, this poller will notice it and
1143   // will trigger a re-initialization using the newly discovered PAC.
1144   script_poller_ = std::make_unique<PacFileDeciderPoller>(
1145       base::BindRepeating(
1146           &ConfiguredProxyResolutionService::InitializeUsingDecidedConfig,
1147           base::Unretained(this)),
1148       fetched_config_.value(), resolver_factory_->expects_pac_bytes(),
1149       pac_file_fetcher_.get(), dhcp_pac_file_fetcher_.get(), result,
1150       init_proxy_resolver_->script_data(), net_log_);
1151   script_poller_->set_quick_check_enabled(quick_check_enabled_);
1152 
1153   init_proxy_resolver_.reset();
1154 
1155   if (result != OK) {
1156     if (fetched_config_->value().pac_mandatory()) {
1157       VLOG(1) << "Failed configuring with mandatory PAC script, blocking all "
1158                  "traffic.";
1159       config_ = fetched_config_;
1160       result = ERR_MANDATORY_PROXY_CONFIGURATION_FAILED;
1161     } else {
1162       VLOG(1) << "Failed configuring with PAC script, falling-back to manual "
1163                  "proxy servers.";
1164       ProxyConfig proxy_config = fetched_config_->value();
1165       proxy_config.ClearAutomaticSettings();
1166       config_ = ProxyConfigWithAnnotation(
1167           proxy_config, fetched_config_->traffic_annotation());
1168       result = OK;
1169     }
1170   }
1171   permanent_error_ = result;
1172 
1173   // Resume any requests which we had to defer until the PAC script was
1174   // downloaded.
1175   SetReady();
1176 }
1177 
ReportSuccess(const ProxyInfo & result)1178 void ConfiguredProxyResolutionService::ReportSuccess(const ProxyInfo& result) {
1179   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
1180 
1181   const ProxyRetryInfoMap& new_retry_info = result.proxy_retry_info();
1182   if (new_retry_info.empty())
1183     return;
1184 
1185   if (proxy_delegate_) {
1186     proxy_delegate_->OnSuccessfulRequestAfterFailures(new_retry_info);
1187   }
1188 
1189   for (const auto& iter : new_retry_info) {
1190     auto existing = proxy_retry_info_.find(iter.first);
1191     if (existing == proxy_retry_info_.end()) {
1192       proxy_retry_info_[iter.first] = iter.second;
1193       if (proxy_delegate_) {
1194         const ProxyChain& bad_proxy = iter.first;
1195         DCHECK(!bad_proxy.is_direct());
1196         const ProxyRetryInfo& proxy_retry_info = iter.second;
1197         proxy_delegate_->OnFallback(bad_proxy, proxy_retry_info.net_error);
1198       }
1199     } else if (existing->second.bad_until < iter.second.bad_until) {
1200       existing->second.bad_until = iter.second.bad_until;
1201     }
1202   }
1203   if (net_log_) {
1204     net_log_->AddGlobalEntry(NetLogEventType::BAD_PROXY_LIST_REPORTED, [&] {
1205       return NetLogBadProxyListParams(&new_retry_info);
1206     });
1207   }
1208 }
1209 
ContainsPendingRequest(ConfiguredProxyResolutionRequest * req)1210 bool ConfiguredProxyResolutionService::ContainsPendingRequest(
1211     ConfiguredProxyResolutionRequest* req) {
1212   return pending_requests_.count(req) == 1;
1213 }
1214 
RemovePendingRequest(ConfiguredProxyResolutionRequest * req)1215 void ConfiguredProxyResolutionService::RemovePendingRequest(
1216     ConfiguredProxyResolutionRequest* req) {
1217   DCHECK(ContainsPendingRequest(req));
1218   pending_requests_.erase(req);
1219 }
1220 
DidFinishResolvingProxy(const GURL & url,const NetworkAnonymizationKey & network_anonymization_key,const std::string & method,ProxyInfo * result,int result_code,const NetLogWithSource & net_log)1221 int ConfiguredProxyResolutionService::DidFinishResolvingProxy(
1222     const GURL& url,
1223     const NetworkAnonymizationKey& network_anonymization_key,
1224     const std::string& method,
1225     ProxyInfo* result,
1226     int result_code,
1227     const NetLogWithSource& net_log) {
1228   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
1229 
1230   // Log the result of the proxy resolution.
1231   if (result_code == OK) {
1232     // Allow the proxy delegate to interpose on the resolution decision,
1233     // possibly modifying the ProxyInfo.
1234     if (proxy_delegate_)
1235       proxy_delegate_->OnResolveProxy(url, network_anonymization_key, method,
1236                                       proxy_retry_info_, result);
1237 
1238     net_log.AddEvent(
1239         NetLogEventType::PROXY_RESOLUTION_SERVICE_RESOLVED_PROXY_LIST,
1240         [&] { return NetLogFinishedResolvingProxyParams(result); });
1241 
1242     // This check is done to only log the NetLog event when necessary, it's
1243     // not a performance optimization.
1244     if (!proxy_retry_info_.empty()) {
1245       result->DeprioritizeBadProxyChains(proxy_retry_info_);
1246       net_log.AddEvent(
1247           NetLogEventType::PROXY_RESOLUTION_SERVICE_DEPRIORITIZED_BAD_PROXIES,
1248           [&] { return NetLogFinishedResolvingProxyParams(result); });
1249     }
1250   } else {
1251     net_log.AddEventWithNetErrorCode(
1252         NetLogEventType::PROXY_RESOLUTION_SERVICE_RESOLVED_PROXY_LIST,
1253         result_code);
1254 
1255     bool reset_config = result_code == ERR_PAC_SCRIPT_TERMINATED;
1256     if (config_ && !config_->value().pac_mandatory()) {
1257       // Fall-back to direct when the proxy resolver fails. This corresponds
1258       // with a javascript runtime error in the PAC script.
1259       //
1260       // This implicit fall-back to direct matches Firefox 3.5 and
1261       // Internet Explorer 8. For more information, see:
1262       //
1263       // http://www.chromium.org/developers/design-documents/proxy-settings-fallback
1264       result->UseDirect();
1265       result_code = OK;
1266 
1267       // Allow the proxy delegate to interpose on the resolution decision,
1268       // possibly modifying the ProxyInfo.
1269       if (proxy_delegate_)
1270         proxy_delegate_->OnResolveProxy(url, network_anonymization_key, method,
1271                                         proxy_retry_info_, result);
1272     } else {
1273       result_code = ERR_MANDATORY_PROXY_CONFIGURATION_FAILED;
1274     }
1275     if (reset_config) {
1276       ResetProxyConfig(false);
1277       // If the ProxyResolver crashed, force it to be re-initialized for the
1278       // next request by resetting the proxy config. If there are other pending
1279       // requests, trigger the recreation immediately so those requests retry.
1280       if (pending_requests_.size() > 1)
1281         ApplyProxyConfigIfAvailable();
1282     }
1283   }
1284 
1285   net_log.EndEvent(NetLogEventType::PROXY_RESOLUTION_SERVICE);
1286   return result_code;
1287 }
1288 
SetPacFileFetchers(std::unique_ptr<PacFileFetcher> pac_file_fetcher,std::unique_ptr<DhcpPacFileFetcher> dhcp_pac_file_fetcher)1289 void ConfiguredProxyResolutionService::SetPacFileFetchers(
1290     std::unique_ptr<PacFileFetcher> pac_file_fetcher,
1291     std::unique_ptr<DhcpPacFileFetcher> dhcp_pac_file_fetcher) {
1292   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
1293   State previous_state = ResetProxyConfig(false);
1294   pac_file_fetcher_ = std::move(pac_file_fetcher);
1295   dhcp_pac_file_fetcher_ = std::move(dhcp_pac_file_fetcher);
1296   if (previous_state != STATE_NONE)
1297     ApplyProxyConfigIfAvailable();
1298 }
1299 
SetProxyDelegate(ProxyDelegate * delegate)1300 void ConfiguredProxyResolutionService::SetProxyDelegate(
1301     ProxyDelegate* delegate) {
1302   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
1303   DCHECK(!proxy_delegate_ || !delegate);
1304   proxy_delegate_ = delegate;
1305 }
1306 
OnShutdown()1307 void ConfiguredProxyResolutionService::OnShutdown() {
1308   // Order here does not matter for correctness. |init_proxy_resolver_| is first
1309   // because shutting it down also cancels its requests using the fetcher.
1310   if (init_proxy_resolver_)
1311     init_proxy_resolver_->OnShutdown();
1312   if (pac_file_fetcher_)
1313     pac_file_fetcher_->OnShutdown();
1314   if (dhcp_pac_file_fetcher_)
1315     dhcp_pac_file_fetcher_->OnShutdown();
1316 }
1317 
proxy_retry_info() const1318 const ProxyRetryInfoMap& ConfiguredProxyResolutionService::proxy_retry_info()
1319     const {
1320   return proxy_retry_info_;
1321 }
1322 
ClearBadProxiesCache()1323 void ConfiguredProxyResolutionService::ClearBadProxiesCache() {
1324   proxy_retry_info_.clear();
1325 }
1326 
GetPacFileFetcher() const1327 PacFileFetcher* ConfiguredProxyResolutionService::GetPacFileFetcher() const {
1328   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
1329   return pac_file_fetcher_.get();
1330 }
1331 
GetLoadStateIfAvailable(LoadState * load_state) const1332 bool ConfiguredProxyResolutionService::GetLoadStateIfAvailable(
1333     LoadState* load_state) const {
1334   if (current_state_ == STATE_WAITING_FOR_INIT_PROXY_RESOLVER) {
1335     *load_state = init_proxy_resolver_->GetLoadState();
1336     return true;
1337   }
1338 
1339   return false;
1340 }
1341 
GetProxyResolver() const1342 ProxyResolver* ConfiguredProxyResolutionService::GetProxyResolver() const {
1343   return resolver_.get();
1344 }
1345 
1346 ConfiguredProxyResolutionService::State
ResetProxyConfig(bool reset_fetched_config)1347 ConfiguredProxyResolutionService::ResetProxyConfig(bool reset_fetched_config) {
1348   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
1349   State previous_state = current_state_;
1350 
1351   permanent_error_ = OK;
1352   proxy_retry_info_.clear();
1353   script_poller_.reset();
1354   init_proxy_resolver_.reset();
1355   SuspendAllPendingRequests();
1356   resolver_.reset();
1357   config_ = std::nullopt;
1358   if (reset_fetched_config)
1359     fetched_config_ = std::nullopt;
1360   current_state_ = STATE_NONE;
1361 
1362   return previous_state;
1363 }
1364 
ForceReloadProxyConfig()1365 void ConfiguredProxyResolutionService::ForceReloadProxyConfig() {
1366   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
1367   ResetProxyConfig(false);
1368   ApplyProxyConfigIfAvailable();
1369 }
1370 
GetProxyNetLogValues()1371 base::Value::Dict ConfiguredProxyResolutionService::GetProxyNetLogValues() {
1372   base::Value::Dict net_info_dict;
1373 
1374   // Log Proxy Settings.
1375   {
1376     base::Value::Dict dict;
1377     if (fetched_config_)
1378       dict.Set("original", fetched_config_->value().ToValue());
1379     if (config_)
1380       dict.Set("effective", config_->value().ToValue());
1381 
1382     net_info_dict.Set(kNetInfoProxySettings, std::move(dict));
1383   }
1384 
1385   // Log Bad Proxies.
1386   {
1387     base::Value::List list;
1388 
1389     for (const auto& it : proxy_retry_info_) {
1390       const std::string& proxy_chain_uri = it.first.ToDebugString();
1391       const ProxyRetryInfo& retry_info = it.second;
1392 
1393       base::Value::Dict dict;
1394       dict.Set("proxy_chain_uri", proxy_chain_uri);
1395       dict.Set("bad_until", NetLog::TickCountToString(retry_info.bad_until));
1396 
1397       list.Append(base::Value(std::move(dict)));
1398     }
1399 
1400     net_info_dict.Set(kNetInfoBadProxies, std::move(list));
1401   }
1402 
1403   return net_info_dict;
1404 }
1405 
CastToConfiguredProxyResolutionService(ConfiguredProxyResolutionService ** configured_proxy_resolution_service)1406 bool ConfiguredProxyResolutionService::CastToConfiguredProxyResolutionService(
1407     ConfiguredProxyResolutionService** configured_proxy_resolution_service) {
1408   *configured_proxy_resolution_service = this;
1409   return true;
1410 }
1411 
1412 // static
1413 const ConfiguredProxyResolutionService::PacPollPolicy*
set_pac_script_poll_policy(const PacPollPolicy * policy)1414 ConfiguredProxyResolutionService::set_pac_script_poll_policy(
1415     const PacPollPolicy* policy) {
1416   return PacFileDeciderPoller::set_policy(policy);
1417 }
1418 
1419 // static
1420 std::unique_ptr<ConfiguredProxyResolutionService::PacPollPolicy>
CreateDefaultPacPollPolicy()1421 ConfiguredProxyResolutionService::CreateDefaultPacPollPolicy() {
1422   return std::make_unique<DefaultPollPolicy>();
1423 }
1424 
OnProxyConfigChanged(const ProxyConfigWithAnnotation & config,ProxyConfigService::ConfigAvailability availability)1425 void ConfiguredProxyResolutionService::OnProxyConfigChanged(
1426     const ProxyConfigWithAnnotation& config,
1427     ProxyConfigService::ConfigAvailability availability) {
1428   // Retrieve the current proxy configuration from the ProxyConfigService.
1429   // If a configuration is not available yet, we will get called back later
1430   // by our ProxyConfigService::Observer once it changes.
1431   ProxyConfigWithAnnotation effective_config;
1432   switch (availability) {
1433     case ProxyConfigService::CONFIG_PENDING:
1434       // ProxyConfigService implementors should never pass CONFIG_PENDING.
1435       NOTREACHED() << "Proxy config change with CONFIG_PENDING availability!";
1436       return;
1437     case ProxyConfigService::CONFIG_VALID:
1438       effective_config = config;
1439       break;
1440     case ProxyConfigService::CONFIG_UNSET:
1441       effective_config = ProxyConfigWithAnnotation::CreateDirect();
1442       break;
1443   }
1444 
1445   // Emit the proxy settings change to the NetLog stream.
1446   if (net_log_) {
1447     net_log_->AddGlobalEntry(NetLogEventType::PROXY_CONFIG_CHANGED, [&] {
1448       return NetLogProxyConfigChangedParams(&fetched_config_,
1449                                             &effective_config);
1450     });
1451   }
1452 
1453   // Set the new configuration as the most recently fetched one.
1454   fetched_config_ = effective_config;
1455 
1456   InitializeUsingLastFetchedConfig();
1457 }
1458 
ApplyPacBypassRules(const GURL & url,ProxyInfo * results)1459 bool ConfiguredProxyResolutionService::ApplyPacBypassRules(const GURL& url,
1460                                                            ProxyInfo* results) {
1461   DCHECK(config_);
1462 
1463   if (ProxyBypassRules::MatchesImplicitRules(url)) {
1464     results->UseDirectWithBypassedProxy();
1465     return true;
1466   }
1467 
1468   return false;
1469 }
1470 
InitializeUsingLastFetchedConfig()1471 void ConfiguredProxyResolutionService::InitializeUsingLastFetchedConfig() {
1472   ResetProxyConfig(false);
1473 
1474   DCHECK(fetched_config_);
1475   if (!fetched_config_->value().HasAutomaticSettings()) {
1476     config_ = fetched_config_;
1477     SetReady();
1478     return;
1479   }
1480 
1481   // Start downloading + testing the PAC scripts for this new configuration.
1482   current_state_ = STATE_WAITING_FOR_INIT_PROXY_RESOLVER;
1483 
1484   // If we changed networks recently, we should delay running proxy auto-config.
1485   base::TimeDelta wait_delay = stall_proxy_autoconfig_until_ - TimeTicks::Now();
1486 
1487   init_proxy_resolver_ = std::make_unique<InitProxyResolver>();
1488   init_proxy_resolver_->set_quick_check_enabled(quick_check_enabled_);
1489   int rv = init_proxy_resolver_->Start(
1490       &resolver_, resolver_factory_.get(), pac_file_fetcher_.get(),
1491       dhcp_pac_file_fetcher_.get(), net_log_, fetched_config_.value(),
1492       wait_delay,
1493       base::BindOnce(
1494           &ConfiguredProxyResolutionService::OnInitProxyResolverComplete,
1495           base::Unretained(this)));
1496 
1497   if (rv != ERR_IO_PENDING)
1498     OnInitProxyResolverComplete(rv);
1499 }
1500 
InitializeUsingDecidedConfig(int decider_result,const PacFileDataWithSource & script_data,const ProxyConfigWithAnnotation & effective_config)1501 void ConfiguredProxyResolutionService::InitializeUsingDecidedConfig(
1502     int decider_result,
1503     const PacFileDataWithSource& script_data,
1504     const ProxyConfigWithAnnotation& effective_config) {
1505   DCHECK(fetched_config_);
1506   DCHECK(fetched_config_->value().HasAutomaticSettings());
1507 
1508   ResetProxyConfig(false);
1509 
1510   current_state_ = STATE_WAITING_FOR_INIT_PROXY_RESOLVER;
1511 
1512   init_proxy_resolver_ = std::make_unique<InitProxyResolver>();
1513   int rv = init_proxy_resolver_->StartSkipDecider(
1514       &resolver_, resolver_factory_.get(), effective_config, decider_result,
1515       script_data,
1516       base::BindOnce(
1517           &ConfiguredProxyResolutionService::OnInitProxyResolverComplete,
1518           base::Unretained(this)));
1519 
1520   if (rv != ERR_IO_PENDING)
1521     OnInitProxyResolverComplete(rv);
1522 }
1523 
OnIPAddressChanged()1524 void ConfiguredProxyResolutionService::OnIPAddressChanged() {
1525   // See the comment block by |kDelayAfterNetworkChangesMs| for info.
1526   stall_proxy_autoconfig_until_ =
1527       TimeTicks::Now() + stall_proxy_auto_config_delay_;
1528 
1529   // With a new network connection, using the proper proxy configuration for the
1530   // new connection may be essential for URL requests to work properly. Reset
1531   // the config to ensure new URL requests are blocked until the potential new
1532   // proxy configuration is loaded.
1533   State previous_state = ResetProxyConfig(false);
1534   if (previous_state != STATE_NONE)
1535     ApplyProxyConfigIfAvailable();
1536 }
1537 
OnDNSChanged()1538 void ConfiguredProxyResolutionService::OnDNSChanged() {
1539   // Do not fully reset proxy config on DNS change notifications. Instead,
1540   // inform the poller that it would be a good time to check for changes.
1541   //
1542   // While a change to DNS servers in use could lead to different WPAD results,
1543   // and thus a different proxy configuration, it is extremely unlikely to ever
1544   // be essential for that changed proxy configuration to be picked up
1545   // immediately. Either URL requests on the connection are generally working
1546   // fine without the proxy, or requests are already broken, leaving little harm
1547   // in letting a couple more requests fail until Chrome picks up the new proxy.
1548   if (script_poller_.get())
1549     script_poller_->OnLazyPoll();
1550 }
1551 
1552 }  // namespace net
1553