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