• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
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/proxy_service.h"
6 
7 #include <algorithm>
8 
9 #include "base/bind.h"
10 #include "base/bind_helpers.h"
11 #include "base/compiler_specific.h"
12 #include "base/logging.h"
13 #include "base/memory/weak_ptr.h"
14 #include "base/message_loop/message_loop.h"
15 #include "base/message_loop/message_loop_proxy.h"
16 #include "base/metrics/histogram.h"
17 #include "base/metrics/sparse_histogram.h"
18 #include "base/strings/string_util.h"
19 #include "base/thread_task_runner_handle.h"
20 #include "base/values.h"
21 #include "net/base/completion_callback.h"
22 #include "net/base/net_errors.h"
23 #include "net/base/net_log.h"
24 #include "net/base/net_util.h"
25 #include "net/proxy/dhcp_proxy_script_fetcher.h"
26 #include "net/proxy/multi_threaded_proxy_resolver.h"
27 #include "net/proxy/network_delegate_error_observer.h"
28 #include "net/proxy/proxy_config_service_fixed.h"
29 #include "net/proxy/proxy_resolver.h"
30 #include "net/proxy/proxy_script_decider.h"
31 #include "net/proxy/proxy_script_fetcher.h"
32 #include "net/url_request/url_request_context.h"
33 #include "url/gurl.h"
34 
35 #if defined(OS_WIN)
36 #include "net/proxy/proxy_config_service_win.h"
37 #include "net/proxy/proxy_resolver_winhttp.h"
38 #elif defined(OS_IOS)
39 #include "net/proxy/proxy_config_service_ios.h"
40 #include "net/proxy/proxy_resolver_mac.h"
41 #elif defined(OS_MACOSX)
42 #include "net/proxy/proxy_config_service_mac.h"
43 #include "net/proxy/proxy_resolver_mac.h"
44 #elif defined(OS_LINUX) && !defined(OS_CHROMEOS)
45 #include "net/proxy/proxy_config_service_linux.h"
46 #elif defined(OS_ANDROID)
47 #include "net/proxy/proxy_config_service_android.h"
48 #endif
49 
50 using base::TimeDelta;
51 using base::TimeTicks;
52 
53 namespace net {
54 
55 namespace {
56 
57 // When the IP address changes we don't immediately re-run proxy auto-config.
58 // Instead, we  wait for |kDelayAfterNetworkChangesMs| before
59 // attempting to re-valuate proxy auto-config.
60 //
61 // During this time window, any resolve requests sent to the ProxyService will
62 // be queued. Once we have waited the required amount of them, the proxy
63 // auto-config step will be run, and the queued requests resumed.
64 //
65 // The reason we play this game is that our signal for detecting network
66 // changes (NetworkChangeNotifier) may fire *before* the system's networking
67 // dependencies are fully configured. This is a problem since it means if
68 // we were to run proxy auto-config right away, it could fail due to spurious
69 // DNS failures. (see http://crbug.com/50779 for more details.)
70 //
71 // By adding the wait window, we give things a better chance to get properly
72 // set up. Network failures can happen at any time though, so we additionally
73 // poll the PAC script for changes, which will allow us to recover from these
74 // sorts of problems.
75 const int64 kDelayAfterNetworkChangesMs = 2000;
76 
77 // This is the default policy for polling the PAC script.
78 //
79 // In response to a failure, the poll intervals are:
80 //    0: 8 seconds  (scheduled on timer)
81 //    1: 32 seconds
82 //    2: 2 minutes
83 //    3+: 4 hours
84 //
85 // In response to a success, the poll intervals are:
86 //    0+: 12 hours
87 //
88 // Only the 8 second poll is scheduled on a timer, the rest happen in response
89 // to network activity (and hence will take longer than the written time).
90 //
91 // Explanation for these values:
92 //
93 // TODO(eroman): These values are somewhat arbitrary, and need to be tuned
94 // using some histograms data. Trying to be conservative so as not to break
95 // existing setups when deployed. A simple exponential retry scheme would be
96 // more elegant, but places more load on server.
97 //
98 // The motivation for trying quickly after failures (8 seconds) is to recover
99 // from spurious network failures, which are common after the IP address has
100 // just changed (like DNS failing to resolve). The next 32 second boundary is
101 // to try and catch other VPN weirdness which anecdotally I have seen take
102 // 10+ seconds for some users.
103 //
104 // The motivation for re-trying after a success is to check for possible
105 // content changes to the script, or to the WPAD auto-discovery results. We are
106 // not very aggressive with these checks so as to minimize the risk of
107 // overloading existing PAC setups. Moreover it is unlikely that PAC scripts
108 // change very frequently in existing setups. More research is needed to
109 // motivate what safe values are here, and what other user agents do.
110 //
111 // Comparison to other browsers:
112 //
113 // In Firefox the PAC URL is re-tried on failures according to
114 // network.proxy.autoconfig_retry_interval_min and
115 // network.proxy.autoconfig_retry_interval_max. The defaults are 5 seconds and
116 // 5 minutes respectively. It doubles the interval at each attempt.
117 //
118 // TODO(eroman): Figure out what Internet Explorer does.
119 class DefaultPollPolicy : public ProxyService::PacPollPolicy {
120  public:
DefaultPollPolicy()121   DefaultPollPolicy() {}
122 
GetNextDelay(int initial_error,TimeDelta current_delay,TimeDelta * next_delay) const123   virtual Mode GetNextDelay(int initial_error,
124                             TimeDelta current_delay,
125                             TimeDelta* next_delay) const OVERRIDE {
126     if (initial_error != OK) {
127       // Re-try policy for failures.
128       const int kDelay1Seconds = 8;
129       const int kDelay2Seconds = 32;
130       const int kDelay3Seconds = 2 * 60;  // 2 minutes
131       const int kDelay4Seconds = 4 * 60 * 60;  // 4 Hours
132 
133       // Initial poll.
134       if (current_delay < TimeDelta()) {
135         *next_delay = TimeDelta::FromSeconds(kDelay1Seconds);
136         return MODE_USE_TIMER;
137       }
138       switch (current_delay.InSeconds()) {
139         case kDelay1Seconds:
140           *next_delay = TimeDelta::FromSeconds(kDelay2Seconds);
141           return MODE_START_AFTER_ACTIVITY;
142         case kDelay2Seconds:
143           *next_delay = TimeDelta::FromSeconds(kDelay3Seconds);
144           return MODE_START_AFTER_ACTIVITY;
145         default:
146           *next_delay = TimeDelta::FromSeconds(kDelay4Seconds);
147           return MODE_START_AFTER_ACTIVITY;
148       }
149     } else {
150       // Re-try policy for succeses.
151       *next_delay = TimeDelta::FromHours(12);
152       return MODE_START_AFTER_ACTIVITY;
153     }
154   }
155 
156  private:
157   DISALLOW_COPY_AND_ASSIGN(DefaultPollPolicy);
158 };
159 
160 // Config getter that always returns direct settings.
161 class ProxyConfigServiceDirect : public ProxyConfigService {
162  public:
163   // ProxyConfigService implementation:
AddObserver(Observer * observer)164   virtual void AddObserver(Observer* observer) OVERRIDE {}
RemoveObserver(Observer * observer)165   virtual void RemoveObserver(Observer* observer) OVERRIDE {}
GetLatestProxyConfig(ProxyConfig * config)166   virtual ConfigAvailability GetLatestProxyConfig(ProxyConfig* config)
167       OVERRIDE {
168     *config = ProxyConfig::CreateDirect();
169     config->set_source(PROXY_CONFIG_SOURCE_UNKNOWN);
170     return CONFIG_VALID;
171   }
172 };
173 
174 // Proxy resolver that fails every time.
175 class ProxyResolverNull : public ProxyResolver {
176  public:
ProxyResolverNull()177   ProxyResolverNull() : ProxyResolver(false /*expects_pac_bytes*/) {}
178 
179   // ProxyResolver implementation.
GetProxyForURL(const GURL & url,ProxyInfo * results,const CompletionCallback & callback,RequestHandle * request,const BoundNetLog & net_log)180   virtual int GetProxyForURL(const GURL& url,
181                              ProxyInfo* results,
182                              const CompletionCallback& callback,
183                              RequestHandle* request,
184                              const BoundNetLog& net_log) OVERRIDE {
185     return ERR_NOT_IMPLEMENTED;
186   }
187 
CancelRequest(RequestHandle request)188   virtual void CancelRequest(RequestHandle request) OVERRIDE {
189     NOTREACHED();
190   }
191 
GetLoadState(RequestHandle request) const192   virtual LoadState GetLoadState(RequestHandle request) const OVERRIDE {
193     NOTREACHED();
194     return LOAD_STATE_IDLE;
195   }
196 
CancelSetPacScript()197   virtual void CancelSetPacScript() OVERRIDE {
198     NOTREACHED();
199   }
200 
SetPacScript(const scoped_refptr<ProxyResolverScriptData> &,const CompletionCallback &)201   virtual int SetPacScript(
202       const scoped_refptr<ProxyResolverScriptData>& /*script_data*/,
203       const CompletionCallback& /*callback*/) OVERRIDE {
204     return ERR_NOT_IMPLEMENTED;
205   }
206 };
207 
208 // ProxyResolver that simulates a PAC script which returns
209 // |pac_string| for every single URL.
210 class ProxyResolverFromPacString : public ProxyResolver {
211  public:
ProxyResolverFromPacString(const std::string & pac_string)212   explicit ProxyResolverFromPacString(const std::string& pac_string)
213       : ProxyResolver(false /*expects_pac_bytes*/),
214         pac_string_(pac_string) {}
215 
GetProxyForURL(const GURL & url,ProxyInfo * results,const CompletionCallback & callback,RequestHandle * request,const BoundNetLog & net_log)216   virtual int GetProxyForURL(const GURL& url,
217                              ProxyInfo* results,
218                              const CompletionCallback& callback,
219                              RequestHandle* request,
220                              const BoundNetLog& net_log) OVERRIDE {
221     results->UsePacString(pac_string_);
222     return OK;
223   }
224 
CancelRequest(RequestHandle request)225   virtual void CancelRequest(RequestHandle request) OVERRIDE {
226     NOTREACHED();
227   }
228 
GetLoadState(RequestHandle request) const229   virtual LoadState GetLoadState(RequestHandle request) const OVERRIDE {
230     NOTREACHED();
231     return LOAD_STATE_IDLE;
232   }
233 
CancelSetPacScript()234   virtual void CancelSetPacScript() OVERRIDE {
235     NOTREACHED();
236   }
237 
SetPacScript(const scoped_refptr<ProxyResolverScriptData> & pac_script,const CompletionCallback & callback)238   virtual int SetPacScript(
239       const scoped_refptr<ProxyResolverScriptData>& pac_script,
240       const CompletionCallback& callback) OVERRIDE {
241     return OK;
242   }
243 
244  private:
245   const std::string pac_string_;
246 };
247 
248 // Creates ProxyResolvers using a platform-specific implementation.
249 class ProxyResolverFactoryForSystem : public ProxyResolverFactory {
250  public:
ProxyResolverFactoryForSystem()251   ProxyResolverFactoryForSystem()
252       : ProxyResolverFactory(false /*expects_pac_bytes*/) {}
253 
CreateProxyResolver()254   virtual ProxyResolver* CreateProxyResolver() OVERRIDE {
255     DCHECK(IsSupported());
256 #if defined(OS_WIN)
257     return new ProxyResolverWinHttp();
258 #elif defined(OS_MACOSX)
259     return new ProxyResolverMac();
260 #else
261     NOTREACHED();
262     return NULL;
263 #endif
264   }
265 
IsSupported()266   static bool IsSupported() {
267 #if defined(OS_WIN) || defined(OS_MACOSX)
268     return true;
269 #else
270     return false;
271 #endif
272   }
273 };
274 
275 // Returns NetLog parameters describing a proxy configuration change.
NetLogProxyConfigChangedCallback(const ProxyConfig * old_config,const ProxyConfig * new_config,NetLog::LogLevel)276 base::Value* NetLogProxyConfigChangedCallback(
277     const ProxyConfig* old_config,
278     const ProxyConfig* new_config,
279     NetLog::LogLevel /* log_level */) {
280   base::DictionaryValue* dict = new base::DictionaryValue();
281   // The "old_config" is optional -- the first notification will not have
282   // any "previous" configuration.
283   if (old_config->is_valid())
284     dict->Set("old_config", old_config->ToValue());
285   dict->Set("new_config", new_config->ToValue());
286   return dict;
287 }
288 
NetLogBadProxyListCallback(const ProxyRetryInfoMap * retry_info,NetLog::LogLevel)289 base::Value* NetLogBadProxyListCallback(const ProxyRetryInfoMap* retry_info,
290                                         NetLog::LogLevel /* log_level */) {
291   base::DictionaryValue* dict = new base::DictionaryValue();
292   base::ListValue* list = new base::ListValue();
293 
294   for (ProxyRetryInfoMap::const_iterator iter = retry_info->begin();
295        iter != retry_info->end(); ++iter) {
296     list->Append(new base::StringValue(iter->first));
297   }
298   dict->Set("bad_proxy_list", list);
299   return dict;
300 }
301 
302 // Returns NetLog parameters on a successfuly proxy resolution.
NetLogFinishedResolvingProxyCallback(ProxyInfo * result,NetLog::LogLevel)303 base::Value* NetLogFinishedResolvingProxyCallback(
304     ProxyInfo* result,
305     NetLog::LogLevel /* log_level */) {
306   base::DictionaryValue* dict = new base::DictionaryValue();
307   dict->SetString("pac_string", result->ToPacString());
308   return dict;
309 }
310 
311 #if defined(OS_CHROMEOS)
312 class UnsetProxyConfigService : public ProxyConfigService {
313  public:
UnsetProxyConfigService()314   UnsetProxyConfigService() {}
~UnsetProxyConfigService()315   virtual ~UnsetProxyConfigService() {}
316 
AddObserver(Observer * observer)317   virtual void AddObserver(Observer* observer) OVERRIDE {}
RemoveObserver(Observer * observer)318   virtual void RemoveObserver(Observer* observer) OVERRIDE {}
GetLatestProxyConfig(ProxyConfig * config)319   virtual ConfigAvailability GetLatestProxyConfig(
320       ProxyConfig* config) OVERRIDE {
321     return CONFIG_UNSET;
322   }
323 };
324 #endif
325 
326 }  // namespace
327 
328 // ProxyService::InitProxyResolver --------------------------------------------
329 
330 // This glues together two asynchronous steps:
331 //   (1) ProxyScriptDecider -- try to fetch/validate a sequence of PAC scripts
332 //       to figure out what we should configure against.
333 //   (2) Feed the fetched PAC script into the ProxyResolver.
334 //
335 // InitProxyResolver is a single-use class which encapsulates cancellation as
336 // part of its destructor. Start() or StartSkipDecider() should be called just
337 // once. The instance can be destroyed at any time, and the request will be
338 // cancelled.
339 
340 class ProxyService::InitProxyResolver {
341  public:
InitProxyResolver()342   InitProxyResolver()
343       : proxy_resolver_(NULL),
344         next_state_(STATE_NONE),
345         quick_check_enabled_(true) {
346   }
347 
~InitProxyResolver()348   ~InitProxyResolver() {
349     // Note that the destruction of ProxyScriptDecider will automatically cancel
350     // any outstanding work.
351     if (next_state_ == STATE_SET_PAC_SCRIPT_COMPLETE) {
352       proxy_resolver_->CancelSetPacScript();
353     }
354   }
355 
356   // Begins initializing the proxy resolver; calls |callback| when done.
Start(ProxyResolver * proxy_resolver,ProxyScriptFetcher * proxy_script_fetcher,DhcpProxyScriptFetcher * dhcp_proxy_script_fetcher,NetLog * net_log,const ProxyConfig & config,TimeDelta wait_delay,const CompletionCallback & callback)357   int Start(ProxyResolver* proxy_resolver,
358             ProxyScriptFetcher* proxy_script_fetcher,
359             DhcpProxyScriptFetcher* dhcp_proxy_script_fetcher,
360             NetLog* net_log,
361             const ProxyConfig& config,
362             TimeDelta wait_delay,
363             const CompletionCallback& callback) {
364     DCHECK_EQ(STATE_NONE, next_state_);
365     proxy_resolver_ = proxy_resolver;
366 
367     decider_.reset(new ProxyScriptDecider(
368         proxy_script_fetcher, dhcp_proxy_script_fetcher, net_log));
369     decider_->set_quick_check_enabled(quick_check_enabled_);
370     config_ = config;
371     wait_delay_ = wait_delay;
372     callback_ = callback;
373 
374     next_state_ = STATE_DECIDE_PROXY_SCRIPT;
375     return DoLoop(OK);
376   }
377 
378   // Similar to Start(), however it skips the ProxyScriptDecider stage. Instead
379   // |effective_config|, |decider_result| and |script_data| will be used as the
380   // inputs for initializing the ProxyResolver.
StartSkipDecider(ProxyResolver * proxy_resolver,const ProxyConfig & effective_config,int decider_result,ProxyResolverScriptData * script_data,const CompletionCallback & callback)381   int StartSkipDecider(ProxyResolver* proxy_resolver,
382                        const ProxyConfig& effective_config,
383                        int decider_result,
384                        ProxyResolverScriptData* script_data,
385                        const CompletionCallback& callback) {
386     DCHECK_EQ(STATE_NONE, next_state_);
387     proxy_resolver_ = proxy_resolver;
388 
389     effective_config_ = effective_config;
390     script_data_ = script_data;
391     callback_ = callback;
392 
393     if (decider_result != OK)
394       return decider_result;
395 
396     next_state_ = STATE_SET_PAC_SCRIPT;
397     return DoLoop(OK);
398   }
399 
400   // Returns the proxy configuration that was selected by ProxyScriptDecider.
401   // Should only be called upon completion of the initialization.
effective_config() const402   const ProxyConfig& effective_config() const {
403     DCHECK_EQ(STATE_NONE, next_state_);
404     return effective_config_;
405   }
406 
407   // Returns the PAC script data that was selected by ProxyScriptDecider.
408   // Should only be called upon completion of the initialization.
script_data()409   ProxyResolverScriptData* script_data() {
410     DCHECK_EQ(STATE_NONE, next_state_);
411     return script_data_.get();
412   }
413 
GetLoadState() const414   LoadState GetLoadState() const {
415     if (next_state_ == STATE_DECIDE_PROXY_SCRIPT_COMPLETE) {
416       // In addition to downloading, this state may also include the stall time
417       // after network change events (kDelayAfterNetworkChangesMs).
418       return LOAD_STATE_DOWNLOADING_PROXY_SCRIPT;
419     }
420     return LOAD_STATE_RESOLVING_PROXY_FOR_URL;
421   }
422 
set_quick_check_enabled(bool enabled)423   void set_quick_check_enabled(bool enabled) { quick_check_enabled_ = enabled; }
quick_check_enabled() const424   bool quick_check_enabled() const { return quick_check_enabled_; }
425 
426  private:
427   enum State {
428     STATE_NONE,
429     STATE_DECIDE_PROXY_SCRIPT,
430     STATE_DECIDE_PROXY_SCRIPT_COMPLETE,
431     STATE_SET_PAC_SCRIPT,
432     STATE_SET_PAC_SCRIPT_COMPLETE,
433   };
434 
DoLoop(int result)435   int DoLoop(int result) {
436     DCHECK_NE(next_state_, STATE_NONE);
437     int rv = result;
438     do {
439       State state = next_state_;
440       next_state_ = STATE_NONE;
441       switch (state) {
442         case STATE_DECIDE_PROXY_SCRIPT:
443           DCHECK_EQ(OK, rv);
444           rv = DoDecideProxyScript();
445           break;
446         case STATE_DECIDE_PROXY_SCRIPT_COMPLETE:
447           rv = DoDecideProxyScriptComplete(rv);
448           break;
449         case STATE_SET_PAC_SCRIPT:
450           DCHECK_EQ(OK, rv);
451           rv = DoSetPacScript();
452           break;
453         case STATE_SET_PAC_SCRIPT_COMPLETE:
454           rv = DoSetPacScriptComplete(rv);
455           break;
456         default:
457           NOTREACHED() << "bad state: " << state;
458           rv = ERR_UNEXPECTED;
459           break;
460       }
461     } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
462     return rv;
463   }
464 
DoDecideProxyScript()465   int DoDecideProxyScript() {
466     next_state_ = STATE_DECIDE_PROXY_SCRIPT_COMPLETE;
467 
468     return decider_->Start(
469         config_, wait_delay_, proxy_resolver_->expects_pac_bytes(),
470         base::Bind(&InitProxyResolver::OnIOCompletion, base::Unretained(this)));
471   }
472 
DoDecideProxyScriptComplete(int result)473   int DoDecideProxyScriptComplete(int result) {
474     if (result != OK)
475       return result;
476 
477     effective_config_ = decider_->effective_config();
478     script_data_ = decider_->script_data();
479 
480     next_state_ = STATE_SET_PAC_SCRIPT;
481     return OK;
482   }
483 
DoSetPacScript()484   int DoSetPacScript() {
485     DCHECK(script_data_.get());
486     // TODO(eroman): Should log this latency to the NetLog.
487     next_state_ = STATE_SET_PAC_SCRIPT_COMPLETE;
488     return proxy_resolver_->SetPacScript(
489         script_data_,
490         base::Bind(&InitProxyResolver::OnIOCompletion, base::Unretained(this)));
491   }
492 
DoSetPacScriptComplete(int result)493   int DoSetPacScriptComplete(int result) {
494     return result;
495   }
496 
OnIOCompletion(int result)497   void OnIOCompletion(int result) {
498     DCHECK_NE(STATE_NONE, next_state_);
499     int rv = DoLoop(result);
500     if (rv != ERR_IO_PENDING)
501       DoCallback(rv);
502   }
503 
DoCallback(int result)504   void DoCallback(int result) {
505     DCHECK_NE(ERR_IO_PENDING, result);
506     callback_.Run(result);
507   }
508 
509   ProxyConfig config_;
510   ProxyConfig effective_config_;
511   scoped_refptr<ProxyResolverScriptData> script_data_;
512   TimeDelta wait_delay_;
513   scoped_ptr<ProxyScriptDecider> decider_;
514   ProxyResolver* proxy_resolver_;
515   CompletionCallback callback_;
516   State next_state_;
517   bool quick_check_enabled_;
518 
519   DISALLOW_COPY_AND_ASSIGN(InitProxyResolver);
520 };
521 
522 // ProxyService::ProxyScriptDeciderPoller -------------------------------------
523 
524 // This helper class encapsulates the logic to schedule and run periodic
525 // background checks to see if the PAC script (or effective proxy configuration)
526 // has changed. If a change is detected, then the caller will be notified via
527 // the ChangeCallback.
528 class ProxyService::ProxyScriptDeciderPoller {
529  public:
530   typedef base::Callback<void(int, ProxyResolverScriptData*,
531                               const ProxyConfig&)> ChangeCallback;
532 
533   // Builds a poller helper, and starts polling for updates. Whenever a change
534   // is observed, |callback| will be invoked with the details.
535   //
536   //   |config| specifies the (unresolved) proxy configuration to poll.
537   //   |proxy_resolver_expects_pac_bytes| the type of proxy resolver we expect
538   //                                      to use the resulting script data with
539   //                                      (so it can choose the right format).
540   //   |proxy_script_fetcher| this pointer must remain alive throughout our
541   //                          lifetime. It is the dependency that will be used
542   //                          for downloading proxy scripts.
543   //   |dhcp_proxy_script_fetcher| similar to |proxy_script_fetcher|, but for
544   //                               the DHCP dependency.
545   //   |init_net_error| This is the initial network error (possibly success)
546   //                    encountered by the first PAC fetch attempt. We use it
547   //                    to schedule updates more aggressively if the initial
548   //                    fetch resulted in an error.
549   //   |init_script_data| the initial script data from the PAC fetch attempt.
550   //                      This is the baseline used to determine when the
551   //                      script's contents have changed.
552   //   |net_log| the NetLog to log progress into.
ProxyScriptDeciderPoller(ChangeCallback callback,const ProxyConfig & config,bool proxy_resolver_expects_pac_bytes,ProxyScriptFetcher * proxy_script_fetcher,DhcpProxyScriptFetcher * dhcp_proxy_script_fetcher,int init_net_error,ProxyResolverScriptData * init_script_data,NetLog * net_log)553   ProxyScriptDeciderPoller(ChangeCallback callback,
554                            const ProxyConfig& config,
555                            bool proxy_resolver_expects_pac_bytes,
556                            ProxyScriptFetcher* proxy_script_fetcher,
557                            DhcpProxyScriptFetcher* dhcp_proxy_script_fetcher,
558                            int init_net_error,
559                            ProxyResolverScriptData* init_script_data,
560                            NetLog* net_log)
561       : weak_factory_(this),
562         change_callback_(callback),
563         config_(config),
564         proxy_resolver_expects_pac_bytes_(proxy_resolver_expects_pac_bytes),
565         proxy_script_fetcher_(proxy_script_fetcher),
566         dhcp_proxy_script_fetcher_(dhcp_proxy_script_fetcher),
567         last_error_(init_net_error),
568         last_script_data_(init_script_data),
569         last_poll_time_(TimeTicks::Now()) {
570     // Set the initial poll delay.
571     next_poll_mode_ = poll_policy()->GetNextDelay(
572         last_error_, TimeDelta::FromSeconds(-1), &next_poll_delay_);
573     TryToStartNextPoll(false);
574   }
575 
OnLazyPoll()576   void OnLazyPoll() {
577     // We have just been notified of network activity. Use this opportunity to
578     // see if we can start our next poll.
579     TryToStartNextPoll(true);
580   }
581 
set_policy(const PacPollPolicy * policy)582   static const PacPollPolicy* set_policy(const PacPollPolicy* policy) {
583     const PacPollPolicy* prev = poll_policy_;
584     poll_policy_ = policy;
585     return prev;
586   }
587 
set_quick_check_enabled(bool enabled)588   void set_quick_check_enabled(bool enabled) { quick_check_enabled_ = enabled; }
quick_check_enabled() const589   bool quick_check_enabled() const { return quick_check_enabled_; }
590 
591  private:
592   // Returns the effective poll policy (the one injected by unit-tests, or the
593   // default).
poll_policy()594   const PacPollPolicy* poll_policy() {
595     if (poll_policy_)
596       return poll_policy_;
597     return &default_poll_policy_;
598   }
599 
StartPollTimer()600   void StartPollTimer() {
601     DCHECK(!decider_.get());
602 
603     base::MessageLoop::current()->PostDelayedTask(
604         FROM_HERE,
605         base::Bind(&ProxyScriptDeciderPoller::DoPoll,
606                    weak_factory_.GetWeakPtr()),
607         next_poll_delay_);
608   }
609 
TryToStartNextPoll(bool triggered_by_activity)610   void TryToStartNextPoll(bool triggered_by_activity) {
611     switch (next_poll_mode_) {
612       case PacPollPolicy::MODE_USE_TIMER:
613         if (!triggered_by_activity)
614           StartPollTimer();
615         break;
616 
617       case PacPollPolicy::MODE_START_AFTER_ACTIVITY:
618         if (triggered_by_activity && !decider_.get()) {
619           TimeDelta elapsed_time = TimeTicks::Now() - last_poll_time_;
620           if (elapsed_time >= next_poll_delay_)
621             DoPoll();
622         }
623         break;
624     }
625   }
626 
DoPoll()627   void DoPoll() {
628     last_poll_time_ = TimeTicks::Now();
629 
630     // Start the proxy script decider to see if anything has changed.
631     // TODO(eroman): Pass a proper NetLog rather than NULL.
632     decider_.reset(new ProxyScriptDecider(
633         proxy_script_fetcher_, dhcp_proxy_script_fetcher_, NULL));
634     decider_->set_quick_check_enabled(quick_check_enabled_);
635     int result = decider_->Start(
636         config_, TimeDelta(), proxy_resolver_expects_pac_bytes_,
637         base::Bind(&ProxyScriptDeciderPoller::OnProxyScriptDeciderCompleted,
638                    base::Unretained(this)));
639 
640     if (result != ERR_IO_PENDING)
641       OnProxyScriptDeciderCompleted(result);
642   }
643 
OnProxyScriptDeciderCompleted(int result)644   void OnProxyScriptDeciderCompleted(int result) {
645     if (HasScriptDataChanged(result, decider_->script_data())) {
646       // Something has changed, we must notify the ProxyService so it can
647       // re-initialize its ProxyResolver. Note that we post a notification task
648       // rather than calling it directly -- this is done to avoid an ugly
649       // destruction sequence, since |this| might be destroyed as a result of
650       // the notification.
651       base::MessageLoop::current()->PostTask(
652           FROM_HERE,
653           base::Bind(&ProxyScriptDeciderPoller::NotifyProxyServiceOfChange,
654                      weak_factory_.GetWeakPtr(),
655                      result,
656                      make_scoped_refptr(decider_->script_data()),
657                      decider_->effective_config()));
658       return;
659     }
660 
661     decider_.reset();
662 
663     // Decide when the next poll should take place, and possibly start the
664     // next timer.
665     next_poll_mode_ = poll_policy()->GetNextDelay(
666         last_error_, next_poll_delay_, &next_poll_delay_);
667     TryToStartNextPoll(false);
668   }
669 
HasScriptDataChanged(int result,ProxyResolverScriptData * script_data)670   bool HasScriptDataChanged(int result, ProxyResolverScriptData* script_data) {
671     if (result != last_error_) {
672       // Something changed -- it was failing before and now it succeeded, or
673       // conversely it succeeded before and now it failed. Or it failed in
674       // both cases, however the specific failure error codes differ.
675       return true;
676     }
677 
678     if (result != OK) {
679       // If it failed last time and failed again with the same error code this
680       // time, then nothing has actually changed.
681       return false;
682     }
683 
684     // Otherwise if it succeeded both this time and last time, we need to look
685     // closer and see if we ended up downloading different content for the PAC
686     // script.
687     return !script_data->Equals(last_script_data_.get());
688   }
689 
NotifyProxyServiceOfChange(int result,const scoped_refptr<ProxyResolverScriptData> & script_data,const ProxyConfig & effective_config)690   void NotifyProxyServiceOfChange(
691       int result,
692       const scoped_refptr<ProxyResolverScriptData>& script_data,
693       const ProxyConfig& effective_config) {
694     // Note that |this| may be deleted after calling into the ProxyService.
695     change_callback_.Run(result, script_data.get(), effective_config);
696   }
697 
698   base::WeakPtrFactory<ProxyScriptDeciderPoller> weak_factory_;
699 
700   ChangeCallback change_callback_;
701   ProxyConfig config_;
702   bool proxy_resolver_expects_pac_bytes_;
703   ProxyScriptFetcher* proxy_script_fetcher_;
704   DhcpProxyScriptFetcher* dhcp_proxy_script_fetcher_;
705 
706   int last_error_;
707   scoped_refptr<ProxyResolverScriptData> last_script_data_;
708 
709   scoped_ptr<ProxyScriptDecider> decider_;
710   TimeDelta next_poll_delay_;
711   PacPollPolicy::Mode next_poll_mode_;
712 
713   TimeTicks last_poll_time_;
714 
715   // Polling policy injected by unit-tests. Otherwise this is NULL and the
716   // default policy will be used.
717   static const PacPollPolicy* poll_policy_;
718 
719   const DefaultPollPolicy default_poll_policy_;
720 
721   bool quick_check_enabled_;
722 
723   DISALLOW_COPY_AND_ASSIGN(ProxyScriptDeciderPoller);
724 };
725 
726 // static
727 const ProxyService::PacPollPolicy*
728     ProxyService::ProxyScriptDeciderPoller::poll_policy_ = NULL;
729 
730 // ProxyService::PacRequest ---------------------------------------------------
731 
732 class ProxyService::PacRequest
733     : public base::RefCounted<ProxyService::PacRequest> {
734  public:
PacRequest(ProxyService * service,const GURL & url,ProxyInfo * results,const net::CompletionCallback & user_callback,const BoundNetLog & net_log)735     PacRequest(ProxyService* service,
736                const GURL& url,
737                ProxyInfo* results,
738                const net::CompletionCallback& user_callback,
739                const BoundNetLog& net_log)
740       : service_(service),
741         user_callback_(user_callback),
742         results_(results),
743         url_(url),
744         resolve_job_(NULL),
745         config_id_(ProxyConfig::kInvalidConfigID),
746         config_source_(PROXY_CONFIG_SOURCE_UNKNOWN),
747         net_log_(net_log) {
748     DCHECK(!user_callback.is_null());
749   }
750 
751   // Starts the resolve proxy request.
Start()752   int Start() {
753     DCHECK(!was_cancelled());
754     DCHECK(!is_started());
755 
756     DCHECK(service_->config_.is_valid());
757 
758     config_id_ = service_->config_.id();
759     config_source_ = service_->config_.source();
760     proxy_resolve_start_time_ = TimeTicks::Now();
761 
762     return resolver()->GetProxyForURL(
763         url_, results_,
764         base::Bind(&PacRequest::QueryComplete, base::Unretained(this)),
765         &resolve_job_, net_log_);
766   }
767 
is_started() const768   bool is_started() const {
769     // Note that !! casts to bool. (VS gives a warning otherwise).
770     return !!resolve_job_;
771   }
772 
StartAndCompleteCheckingForSynchronous()773   void StartAndCompleteCheckingForSynchronous() {
774     int rv = service_->TryToCompleteSynchronously(url_, results_);
775     if (rv == ERR_IO_PENDING)
776       rv = Start();
777     if (rv != ERR_IO_PENDING)
778       QueryComplete(rv);
779   }
780 
CancelResolveJob()781   void CancelResolveJob() {
782     DCHECK(is_started());
783     // The request may already be running in the resolver.
784     resolver()->CancelRequest(resolve_job_);
785     resolve_job_ = NULL;
786     DCHECK(!is_started());
787   }
788 
Cancel()789   void Cancel() {
790     net_log_.AddEvent(NetLog::TYPE_CANCELLED);
791 
792     if (is_started())
793       CancelResolveJob();
794 
795     // Mark as cancelled, to prevent accessing this again later.
796     service_ = NULL;
797     user_callback_.Reset();
798     results_ = NULL;
799 
800     net_log_.EndEvent(NetLog::TYPE_PROXY_SERVICE);
801   }
802 
803   // Returns true if Cancel() has been called.
was_cancelled() const804   bool was_cancelled() const {
805     return user_callback_.is_null();
806   }
807 
808   // Helper to call after ProxyResolver completion (both synchronous and
809   // asynchronous). Fixes up the result that is to be returned to user.
QueryDidComplete(int result_code)810   int QueryDidComplete(int result_code) {
811     DCHECK(!was_cancelled());
812 
813     // Note that DidFinishResolvingProxy might modify |results_|.
814     int rv = service_->DidFinishResolvingProxy(results_, result_code, net_log_);
815 
816     // Make a note in the results which configuration was in use at the
817     // time of the resolve.
818     results_->config_id_ = config_id_;
819     results_->config_source_ = config_source_;
820     results_->did_use_pac_script_ = true;
821     results_->proxy_resolve_start_time_ = proxy_resolve_start_time_;
822     results_->proxy_resolve_end_time_ = TimeTicks::Now();
823 
824     // Reset the state associated with in-progress-resolve.
825     resolve_job_ = NULL;
826     config_id_ = ProxyConfig::kInvalidConfigID;
827     config_source_ = PROXY_CONFIG_SOURCE_UNKNOWN;
828 
829     return rv;
830   }
831 
net_log()832   BoundNetLog* net_log() { return &net_log_; }
833 
GetLoadState() const834   LoadState GetLoadState() const {
835     if (is_started())
836       return resolver()->GetLoadState(resolve_job_);
837     return LOAD_STATE_RESOLVING_PROXY_FOR_URL;
838   }
839 
840  private:
841   friend class base::RefCounted<ProxyService::PacRequest>;
842 
~PacRequest()843   ~PacRequest() {}
844 
845   // Callback for when the ProxyResolver request has completed.
QueryComplete(int result_code)846   void QueryComplete(int result_code) {
847     result_code = QueryDidComplete(result_code);
848 
849     // Remove this completed PacRequest from the service's pending list.
850     /// (which will probably cause deletion of |this|).
851     if (!user_callback_.is_null()) {
852       net::CompletionCallback callback = user_callback_;
853       service_->RemovePendingRequest(this);
854       callback.Run(result_code);
855     }
856   }
857 
resolver() const858   ProxyResolver* resolver() const { return service_->resolver_.get(); }
859 
860   // Note that we don't hold a reference to the ProxyService. Outstanding
861   // requests are cancelled during ~ProxyService, so this is guaranteed
862   // to be valid throughout our lifetime.
863   ProxyService* service_;
864   net::CompletionCallback user_callback_;
865   ProxyInfo* results_;
866   GURL url_;
867   ProxyResolver::RequestHandle resolve_job_;
868   ProxyConfig::ID config_id_;  // The config id when the resolve was started.
869   ProxyConfigSource config_source_;  // The source of proxy settings.
870   BoundNetLog net_log_;
871   // Time when the PAC is started.  Cached here since resetting ProxyInfo also
872   // clears the proxy times.
873   TimeTicks proxy_resolve_start_time_;
874 };
875 
876 // ProxyService ---------------------------------------------------------------
877 
ProxyService(ProxyConfigService * config_service,ProxyResolver * resolver,NetLog * net_log)878 ProxyService::ProxyService(ProxyConfigService* config_service,
879                            ProxyResolver* resolver,
880                            NetLog* net_log)
881     : resolver_(resolver),
882       next_config_id_(1),
883       current_state_(STATE_NONE) ,
884       net_log_(net_log),
885       stall_proxy_auto_config_delay_(TimeDelta::FromMilliseconds(
886           kDelayAfterNetworkChangesMs)),
887       quick_check_enabled_(true) {
888   NetworkChangeNotifier::AddIPAddressObserver(this);
889   NetworkChangeNotifier::AddDNSObserver(this);
890   ResetConfigService(config_service);
891 }
892 
893 // static
CreateUsingSystemProxyResolver(ProxyConfigService * proxy_config_service,size_t num_pac_threads,NetLog * net_log)894 ProxyService* ProxyService::CreateUsingSystemProxyResolver(
895     ProxyConfigService* proxy_config_service,
896     size_t num_pac_threads,
897     NetLog* net_log) {
898   DCHECK(proxy_config_service);
899 
900   if (!ProxyResolverFactoryForSystem::IsSupported()) {
901     LOG(WARNING) << "PAC support disabled because there is no "
902                     "system implementation";
903     return CreateWithoutProxyResolver(proxy_config_service, net_log);
904   }
905 
906   if (num_pac_threads == 0)
907     num_pac_threads = kDefaultNumPacThreads;
908 
909   ProxyResolver* proxy_resolver = new MultiThreadedProxyResolver(
910       new ProxyResolverFactoryForSystem(), num_pac_threads);
911 
912   return new ProxyService(proxy_config_service, proxy_resolver, net_log);
913 }
914 
915 // static
CreateWithoutProxyResolver(ProxyConfigService * proxy_config_service,NetLog * net_log)916 ProxyService* ProxyService::CreateWithoutProxyResolver(
917     ProxyConfigService* proxy_config_service,
918     NetLog* net_log) {
919   return new ProxyService(proxy_config_service,
920                           new ProxyResolverNull(),
921                           net_log);
922 }
923 
924 // static
CreateFixed(const ProxyConfig & pc)925 ProxyService* ProxyService::CreateFixed(const ProxyConfig& pc) {
926   // TODO(eroman): This isn't quite right, won't work if |pc| specifies
927   //               a PAC script.
928   return CreateUsingSystemProxyResolver(new ProxyConfigServiceFixed(pc),
929                                         0, NULL);
930 }
931 
932 // static
CreateFixed(const std::string & proxy)933 ProxyService* ProxyService::CreateFixed(const std::string& proxy) {
934   net::ProxyConfig proxy_config;
935   proxy_config.proxy_rules().ParseFromString(proxy);
936   return ProxyService::CreateFixed(proxy_config);
937 }
938 
939 // static
CreateDirect()940 ProxyService* ProxyService::CreateDirect() {
941   return CreateDirectWithNetLog(NULL);
942 }
943 
CreateDirectWithNetLog(NetLog * net_log)944 ProxyService* ProxyService::CreateDirectWithNetLog(NetLog* net_log) {
945   // Use direct connections.
946   return new ProxyService(new ProxyConfigServiceDirect, new ProxyResolverNull,
947                           net_log);
948 }
949 
950 // static
CreateFixedFromPacResult(const std::string & pac_string)951 ProxyService* ProxyService::CreateFixedFromPacResult(
952     const std::string& pac_string) {
953 
954   // We need the settings to contain an "automatic" setting, otherwise the
955   // ProxyResolver dependency we give it will never be used.
956   scoped_ptr<ProxyConfigService> proxy_config_service(
957       new ProxyConfigServiceFixed(ProxyConfig::CreateAutoDetect()));
958 
959   scoped_ptr<ProxyResolver> proxy_resolver(
960       new ProxyResolverFromPacString(pac_string));
961 
962   return new ProxyService(proxy_config_service.release(),
963                           proxy_resolver.release(),
964                           NULL);
965 }
966 
ResolveProxy(const GURL & raw_url,ProxyInfo * result,const net::CompletionCallback & callback,PacRequest ** pac_request,const BoundNetLog & net_log)967 int ProxyService::ResolveProxy(const GURL& raw_url,
968                                ProxyInfo* result,
969                                const net::CompletionCallback& callback,
970                                PacRequest** pac_request,
971                                const BoundNetLog& net_log) {
972   DCHECK(CalledOnValidThread());
973   DCHECK(!callback.is_null());
974 
975   net_log.BeginEvent(NetLog::TYPE_PROXY_SERVICE);
976 
977   // Notify our polling-based dependencies that a resolve is taking place.
978   // This way they can schedule their polls in response to network activity.
979   config_service_->OnLazyPoll();
980   if (script_poller_.get())
981      script_poller_->OnLazyPoll();
982 
983   if (current_state_ == STATE_NONE)
984     ApplyProxyConfigIfAvailable();
985 
986   // Strip away any reference fragments and the username/password, as they
987   // are not relevant to proxy resolution.
988   GURL url = SimplifyUrlForRequest(raw_url);
989 
990   // Check if the request can be completed right away. (This is the case when
991   // using a direct connection for example).
992   int rv = TryToCompleteSynchronously(url, result);
993   if (rv != ERR_IO_PENDING)
994     return DidFinishResolvingProxy(result, rv, net_log);
995 
996   scoped_refptr<PacRequest> req(
997       new PacRequest(this, url, result, callback, net_log));
998 
999   if (current_state_ == STATE_READY) {
1000     // Start the resolve request.
1001     rv = req->Start();
1002     if (rv != ERR_IO_PENDING)
1003       return req->QueryDidComplete(rv);
1004   } else {
1005     req->net_log()->BeginEvent(NetLog::TYPE_PROXY_SERVICE_WAITING_FOR_INIT_PAC);
1006   }
1007 
1008   DCHECK_EQ(ERR_IO_PENDING, rv);
1009   DCHECK(!ContainsPendingRequest(req.get()));
1010   pending_requests_.push_back(req);
1011 
1012   // Completion will be notified through |callback|, unless the caller cancels
1013   // the request using |pac_request|.
1014   if (pac_request)
1015     *pac_request = req.get();
1016   return rv;  // ERR_IO_PENDING
1017 }
1018 
TryToCompleteSynchronously(const GURL & url,ProxyInfo * result)1019 int ProxyService::TryToCompleteSynchronously(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_NE(config_.id(), ProxyConfig::kInvalidConfigID);
1027 
1028   // If it was impossible to fetch or parse the PAC script, we cannot complete
1029   // the request here and bail out.
1030   if (permanent_error_ != OK)
1031     return permanent_error_;
1032 
1033   if (config_.HasAutomaticSettings())
1034     return ERR_IO_PENDING;  // Must submit the request to the proxy resolver.
1035 
1036   // Use the manual proxy settings.
1037   config_.proxy_rules().Apply(url, result);
1038   result->config_source_ = config_.source();
1039   result->config_id_ = config_.id();
1040   return OK;
1041 }
1042 
~ProxyService()1043 ProxyService::~ProxyService() {
1044   NetworkChangeNotifier::RemoveIPAddressObserver(this);
1045   NetworkChangeNotifier::RemoveDNSObserver(this);
1046   config_service_->RemoveObserver(this);
1047 
1048   // Cancel any inprogress requests.
1049   for (PendingRequests::iterator it = pending_requests_.begin();
1050        it != pending_requests_.end();
1051        ++it) {
1052     (*it)->Cancel();
1053   }
1054 }
1055 
SuspendAllPendingRequests()1056 void ProxyService::SuspendAllPendingRequests() {
1057   for (PendingRequests::iterator it = pending_requests_.begin();
1058        it != pending_requests_.end();
1059        ++it) {
1060     PacRequest* req = it->get();
1061     if (req->is_started()) {
1062       req->CancelResolveJob();
1063 
1064       req->net_log()->BeginEvent(
1065           NetLog::TYPE_PROXY_SERVICE_WAITING_FOR_INIT_PAC);
1066     }
1067   }
1068 }
1069 
SetReady()1070 void ProxyService::SetReady() {
1071   DCHECK(!init_proxy_resolver_.get());
1072   current_state_ = STATE_READY;
1073 
1074   // Make a copy in case |this| is deleted during the synchronous completion
1075   // of one of the requests. If |this| is deleted then all of the PacRequest
1076   // instances will be Cancel()-ed.
1077   PendingRequests pending_copy = pending_requests_;
1078 
1079   for (PendingRequests::iterator it = pending_copy.begin();
1080        it != pending_copy.end();
1081        ++it) {
1082     PacRequest* req = it->get();
1083     if (!req->is_started() && !req->was_cancelled()) {
1084       req->net_log()->EndEvent(NetLog::TYPE_PROXY_SERVICE_WAITING_FOR_INIT_PAC);
1085 
1086       // Note that we re-check for synchronous completion, in case we are
1087       // no longer using a ProxyResolver (can happen if we fell-back to manual).
1088       req->StartAndCompleteCheckingForSynchronous();
1089     }
1090   }
1091 }
1092 
ApplyProxyConfigIfAvailable()1093 void ProxyService::ApplyProxyConfigIfAvailable() {
1094   DCHECK_EQ(STATE_NONE, current_state_);
1095 
1096   config_service_->OnLazyPoll();
1097 
1098   // If we have already fetched the configuration, start applying it.
1099   if (fetched_config_.is_valid()) {
1100     InitializeUsingLastFetchedConfig();
1101     return;
1102   }
1103 
1104   // Otherwise we need to first fetch the configuration.
1105   current_state_ = STATE_WAITING_FOR_PROXY_CONFIG;
1106 
1107   // Retrieve the current proxy configuration from the ProxyConfigService.
1108   // If a configuration is not available yet, we will get called back later
1109   // by our ProxyConfigService::Observer once it changes.
1110   ProxyConfig config;
1111   ProxyConfigService::ConfigAvailability availability =
1112       config_service_->GetLatestProxyConfig(&config);
1113   if (availability != ProxyConfigService::CONFIG_PENDING)
1114     OnProxyConfigChanged(config, availability);
1115 }
1116 
OnInitProxyResolverComplete(int result)1117 void ProxyService::OnInitProxyResolverComplete(int result) {
1118   DCHECK_EQ(STATE_WAITING_FOR_INIT_PROXY_RESOLVER, current_state_);
1119   DCHECK(init_proxy_resolver_.get());
1120   DCHECK(fetched_config_.HasAutomaticSettings());
1121   config_ = init_proxy_resolver_->effective_config();
1122 
1123   // At this point we have decided which proxy settings to use (i.e. which PAC
1124   // script if any). We start up a background poller to periodically revisit
1125   // this decision. If the contents of the PAC script change, or if the
1126   // result of proxy auto-discovery changes, this poller will notice it and
1127   // will trigger a re-initialization using the newly discovered PAC.
1128   script_poller_.reset(new ProxyScriptDeciderPoller(
1129       base::Bind(&ProxyService::InitializeUsingDecidedConfig,
1130                  base::Unretained(this)),
1131       fetched_config_,
1132       resolver_->expects_pac_bytes(),
1133       proxy_script_fetcher_.get(),
1134       dhcp_proxy_script_fetcher_.get(),
1135       result,
1136       init_proxy_resolver_->script_data(),
1137       NULL));
1138   script_poller_->set_quick_check_enabled(quick_check_enabled_);
1139 
1140   init_proxy_resolver_.reset();
1141 
1142   if (result != OK) {
1143     if (fetched_config_.pac_mandatory()) {
1144       VLOG(1) << "Failed configuring with mandatory PAC script, blocking all "
1145                  "traffic.";
1146       config_ = fetched_config_;
1147       result = ERR_MANDATORY_PROXY_CONFIGURATION_FAILED;
1148     } else {
1149       VLOG(1) << "Failed configuring with PAC script, falling-back to manual "
1150                  "proxy servers.";
1151       config_ = fetched_config_;
1152       config_.ClearAutomaticSettings();
1153       result = OK;
1154     }
1155   }
1156   permanent_error_ = result;
1157 
1158   // TODO(eroman): Make this ID unique in the case where configuration changed
1159   //               due to ProxyScriptDeciderPoller.
1160   config_.set_id(fetched_config_.id());
1161   config_.set_source(fetched_config_.source());
1162 
1163   // Resume any requests which we had to defer until the PAC script was
1164   // downloaded.
1165   SetReady();
1166 }
1167 
ReconsiderProxyAfterError(const GURL & url,int net_error,ProxyInfo * result,const CompletionCallback & callback,PacRequest ** pac_request,const BoundNetLog & net_log)1168 int ProxyService::ReconsiderProxyAfterError(const GURL& url,
1169                                             int net_error,
1170                                             ProxyInfo* result,
1171                                             const CompletionCallback& callback,
1172                                             PacRequest** pac_request,
1173                                             const BoundNetLog& net_log) {
1174   DCHECK(CalledOnValidThread());
1175 
1176   // Check to see if we have a new config since ResolveProxy was called.  We
1177   // want to re-run ResolveProxy in two cases: 1) we have a new config, or 2) a
1178   // direct connection failed and we never tried the current config.
1179 
1180   bool re_resolve = result->config_id_ != config_.id();
1181 
1182   if (re_resolve) {
1183     // If we have a new config or the config was never tried, we delete the
1184     // list of bad proxies and we try again.
1185     proxy_retry_info_.clear();
1186     return ResolveProxy(url, result, callback, pac_request, net_log);
1187   }
1188 
1189 #if defined(SPDY_PROXY_AUTH_ORIGIN)
1190   if (result->proxy_server().isDataReductionProxy()) {
1191     RecordDataReductionProxyBypassInfo(
1192         true, result->proxy_server(), ERROR_BYPASS);
1193     RecordDataReductionProxyBypassOnNetworkError(
1194         true, result->proxy_server(), net_error);
1195   } else if (result->proxy_server().isDataReductionProxyFallback()) {
1196     RecordDataReductionProxyBypassInfo(
1197         false, result->proxy_server(), ERROR_BYPASS);
1198     RecordDataReductionProxyBypassOnNetworkError(
1199         false, result->proxy_server(), net_error);
1200   }
1201 #endif
1202 
1203   // We don't have new proxy settings to try, try to fallback to the next proxy
1204   // in the list.
1205   bool did_fallback = result->Fallback(net_log);
1206 
1207   // Return synchronous failure if there is nothing left to fall-back to.
1208   // TODO(eroman): This is a yucky API, clean it up.
1209   return did_fallback ? OK : ERR_FAILED;
1210 }
1211 
MarkProxiesAsBadUntil(const ProxyInfo & result,base::TimeDelta retry_delay,const ProxyServer & another_bad_proxy,const BoundNetLog & net_log)1212 bool ProxyService::MarkProxiesAsBadUntil(
1213     const ProxyInfo& result,
1214     base::TimeDelta retry_delay,
1215     const ProxyServer& another_bad_proxy,
1216     const BoundNetLog& net_log) {
1217   result.proxy_list_.UpdateRetryInfoOnFallback(&proxy_retry_info_, retry_delay,
1218                                                false,
1219                                                another_bad_proxy,
1220                                                net_log);
1221   if (another_bad_proxy.is_valid())
1222     return result.proxy_list_.size() > 2;
1223   else
1224     return result.proxy_list_.size() > 1;
1225 }
1226 
ReportSuccess(const ProxyInfo & result)1227 void ProxyService::ReportSuccess(const ProxyInfo& result) {
1228   DCHECK(CalledOnValidThread());
1229 
1230   const ProxyRetryInfoMap& new_retry_info = result.proxy_retry_info();
1231   if (new_retry_info.empty())
1232     return;
1233 
1234   for (ProxyRetryInfoMap::const_iterator iter = new_retry_info.begin();
1235        iter != new_retry_info.end(); ++iter) {
1236     ProxyRetryInfoMap::iterator existing = proxy_retry_info_.find(iter->first);
1237     if (existing == proxy_retry_info_.end())
1238       proxy_retry_info_[iter->first] = iter->second;
1239     else if (existing->second.bad_until < iter->second.bad_until)
1240       existing->second.bad_until = iter->second.bad_until;
1241   }
1242   if (net_log_) {
1243     net_log_->AddGlobalEntry(
1244         NetLog::TYPE_BAD_PROXY_LIST_REPORTED,
1245         base::Bind(&NetLogBadProxyListCallback, &new_retry_info));
1246   }
1247 }
1248 
CancelPacRequest(PacRequest * req)1249 void ProxyService::CancelPacRequest(PacRequest* req) {
1250   DCHECK(CalledOnValidThread());
1251   DCHECK(req);
1252   req->Cancel();
1253   RemovePendingRequest(req);
1254 }
1255 
GetLoadState(const PacRequest * req) const1256 LoadState ProxyService::GetLoadState(const PacRequest* req) const {
1257   CHECK(req);
1258   if (current_state_ == STATE_WAITING_FOR_INIT_PROXY_RESOLVER)
1259     return init_proxy_resolver_->GetLoadState();
1260   return req->GetLoadState();
1261 }
1262 
ContainsPendingRequest(PacRequest * req)1263 bool ProxyService::ContainsPendingRequest(PacRequest* req) {
1264   PendingRequests::iterator it = std::find(
1265       pending_requests_.begin(), pending_requests_.end(), req);
1266   return pending_requests_.end() != it;
1267 }
1268 
RemovePendingRequest(PacRequest * req)1269 void ProxyService::RemovePendingRequest(PacRequest* req) {
1270   DCHECK(ContainsPendingRequest(req));
1271   PendingRequests::iterator it = std::find(
1272       pending_requests_.begin(), pending_requests_.end(), req);
1273   pending_requests_.erase(it);
1274 }
1275 
DidFinishResolvingProxy(ProxyInfo * result,int result_code,const BoundNetLog & net_log)1276 int ProxyService::DidFinishResolvingProxy(ProxyInfo* result,
1277                                           int result_code,
1278                                           const BoundNetLog& net_log) {
1279   // Log the result of the proxy resolution.
1280   if (result_code == OK) {
1281     // When logging all events is enabled, dump the proxy list.
1282     if (net_log.IsLogging()) {
1283       net_log.AddEvent(
1284           NetLog::TYPE_PROXY_SERVICE_RESOLVED_PROXY_LIST,
1285           base::Bind(&NetLogFinishedResolvingProxyCallback, result));
1286     }
1287     result->DeprioritizeBadProxies(proxy_retry_info_);
1288   } else {
1289     net_log.AddEventWithNetErrorCode(
1290         NetLog::TYPE_PROXY_SERVICE_RESOLVED_PROXY_LIST, result_code);
1291 
1292     if (!config_.pac_mandatory()) {
1293       // Fall-back to direct when the proxy resolver fails. This corresponds
1294       // with a javascript runtime error in the PAC script.
1295       //
1296       // This implicit fall-back to direct matches Firefox 3.5 and
1297       // Internet Explorer 8. For more information, see:
1298       //
1299       // http://www.chromium.org/developers/design-documents/proxy-settings-fallback
1300       result->UseDirect();
1301       result_code = OK;
1302     } else {
1303       result_code = ERR_MANDATORY_PROXY_CONFIGURATION_FAILED;
1304     }
1305   }
1306 
1307   net_log.EndEvent(NetLog::TYPE_PROXY_SERVICE);
1308   return result_code;
1309 }
1310 
SetProxyScriptFetchers(ProxyScriptFetcher * proxy_script_fetcher,DhcpProxyScriptFetcher * dhcp_proxy_script_fetcher)1311 void ProxyService::SetProxyScriptFetchers(
1312     ProxyScriptFetcher* proxy_script_fetcher,
1313     DhcpProxyScriptFetcher* dhcp_proxy_script_fetcher) {
1314   DCHECK(CalledOnValidThread());
1315   State previous_state = ResetProxyConfig(false);
1316   proxy_script_fetcher_.reset(proxy_script_fetcher);
1317   dhcp_proxy_script_fetcher_.reset(dhcp_proxy_script_fetcher);
1318   if (previous_state != STATE_NONE)
1319     ApplyProxyConfigIfAvailable();
1320 }
1321 
GetProxyScriptFetcher() const1322 ProxyScriptFetcher* ProxyService::GetProxyScriptFetcher() const {
1323   DCHECK(CalledOnValidThread());
1324   return proxy_script_fetcher_.get();
1325 }
1326 
ResetProxyConfig(bool reset_fetched_config)1327 ProxyService::State ProxyService::ResetProxyConfig(bool reset_fetched_config) {
1328   DCHECK(CalledOnValidThread());
1329   State previous_state = current_state_;
1330 
1331   permanent_error_ = OK;
1332   proxy_retry_info_.clear();
1333   script_poller_.reset();
1334   init_proxy_resolver_.reset();
1335   SuspendAllPendingRequests();
1336   config_ = ProxyConfig();
1337   if (reset_fetched_config)
1338     fetched_config_ = ProxyConfig();
1339   current_state_ = STATE_NONE;
1340 
1341   return previous_state;
1342 }
1343 
ResetConfigService(ProxyConfigService * new_proxy_config_service)1344 void ProxyService::ResetConfigService(
1345     ProxyConfigService* new_proxy_config_service) {
1346   DCHECK(CalledOnValidThread());
1347   State previous_state = ResetProxyConfig(true);
1348 
1349   // Release the old configuration service.
1350   if (config_service_.get())
1351     config_service_->RemoveObserver(this);
1352 
1353   // Set the new configuration service.
1354   config_service_.reset(new_proxy_config_service);
1355   config_service_->AddObserver(this);
1356 
1357   if (previous_state != STATE_NONE)
1358     ApplyProxyConfigIfAvailable();
1359 }
1360 
ForceReloadProxyConfig()1361 void ProxyService::ForceReloadProxyConfig() {
1362   DCHECK(CalledOnValidThread());
1363   ResetProxyConfig(false);
1364   ApplyProxyConfigIfAvailable();
1365 }
1366 
1367 // static
CreateSystemProxyConfigService(base::SingleThreadTaskRunner * io_thread_task_runner,base::MessageLoop * file_loop)1368 ProxyConfigService* ProxyService::CreateSystemProxyConfigService(
1369     base::SingleThreadTaskRunner* io_thread_task_runner,
1370     base::MessageLoop* file_loop) {
1371 #if defined(OS_WIN)
1372   return new ProxyConfigServiceWin();
1373 #elif defined(OS_IOS)
1374   return new ProxyConfigServiceIOS();
1375 #elif defined(OS_MACOSX)
1376   return new ProxyConfigServiceMac(io_thread_task_runner);
1377 #elif defined(OS_CHROMEOS)
1378   LOG(ERROR) << "ProxyConfigService for ChromeOS should be created in "
1379              << "profile_io_data.cc::CreateProxyConfigService and this should "
1380              << "be used only for examples.";
1381   return new UnsetProxyConfigService;
1382 #elif defined(OS_LINUX)
1383   ProxyConfigServiceLinux* linux_config_service =
1384       new ProxyConfigServiceLinux();
1385 
1386   // Assume we got called on the thread that runs the default glib
1387   // main loop, so the current thread is where we should be running
1388   // gconf calls from.
1389   scoped_refptr<base::SingleThreadTaskRunner> glib_thread_task_runner =
1390       base::ThreadTaskRunnerHandle::Get();
1391 
1392   // The file loop should be a MessageLoopForIO on Linux.
1393   DCHECK_EQ(base::MessageLoop::TYPE_IO, file_loop->type());
1394 
1395   // Synchronously fetch the current proxy config (since we are
1396   // running on glib_default_loop). Additionally register for
1397   // notifications (delivered in either |glib_default_loop| or
1398   // |file_loop|) to keep us updated when the proxy config changes.
1399   linux_config_service->SetupAndFetchInitialConfig(
1400       glib_thread_task_runner.get(),
1401       io_thread_task_runner,
1402       static_cast<base::MessageLoopForIO*>(file_loop));
1403 
1404   return linux_config_service;
1405 #elif defined(OS_ANDROID)
1406   return new ProxyConfigServiceAndroid(
1407       io_thread_task_runner,
1408       base::MessageLoop::current()->message_loop_proxy());
1409 #else
1410   LOG(WARNING) << "Failed to choose a system proxy settings fetcher "
1411                   "for this platform.";
1412   return new ProxyConfigServiceDirect();
1413 #endif
1414 }
1415 
1416 // static
set_pac_script_poll_policy(const PacPollPolicy * policy)1417 const ProxyService::PacPollPolicy* ProxyService::set_pac_script_poll_policy(
1418     const PacPollPolicy* policy) {
1419   return ProxyScriptDeciderPoller::set_policy(policy);
1420 }
1421 
1422 // static
1423 scoped_ptr<ProxyService::PacPollPolicy>
CreateDefaultPacPollPolicy()1424   ProxyService::CreateDefaultPacPollPolicy() {
1425   return scoped_ptr<PacPollPolicy>(new DefaultPollPolicy());
1426 }
1427 
RecordDataReductionProxyBypassInfo(bool is_primary,const ProxyServer & proxy_server,DataReductionProxyBypassEventType bypass_type) const1428 void ProxyService::RecordDataReductionProxyBypassInfo(
1429     bool is_primary,
1430     const ProxyServer& proxy_server,
1431     DataReductionProxyBypassEventType bypass_type) const {
1432   // Only record UMA if the proxy isn't already on the retry list.
1433   if (proxy_retry_info_.find(proxy_server.ToURI()) != proxy_retry_info_.end())
1434     return;
1435 
1436   if (is_primary) {
1437     UMA_HISTOGRAM_ENUMERATION("DataReductionProxy.BypassInfoPrimary",
1438                               bypass_type, BYPASS_EVENT_TYPE_MAX);
1439   } else {
1440     UMA_HISTOGRAM_ENUMERATION("DataReductionProxy.BypassInfoFallback",
1441                               bypass_type, BYPASS_EVENT_TYPE_MAX);
1442   }
1443 }
1444 
RecordDataReductionProxyBypassOnNetworkError(bool is_primary,const ProxyServer & proxy_server,int net_error)1445 void ProxyService::RecordDataReductionProxyBypassOnNetworkError(
1446     bool is_primary,
1447     const ProxyServer& proxy_server,
1448     int net_error) {
1449   // Only record UMA if the proxy isn't already on the retry list.
1450   if (proxy_retry_info_.find(proxy_server.ToURI()) != proxy_retry_info_.end())
1451     return;
1452 
1453   if (is_primary) {
1454     UMA_HISTOGRAM_SPARSE_SLOWLY(
1455         "DataReductionProxy.BypassOnNetworkErrorPrimary",
1456         std::abs(net_error));
1457     return;
1458   }
1459   UMA_HISTOGRAM_SPARSE_SLOWLY(
1460       "DataReductionProxy.BypassOnNetworkErrorFallback",
1461       std::abs(net_error));
1462 }
1463 
OnProxyConfigChanged(const ProxyConfig & config,ProxyConfigService::ConfigAvailability availability)1464 void ProxyService::OnProxyConfigChanged(
1465     const ProxyConfig& config,
1466     ProxyConfigService::ConfigAvailability availability) {
1467   // Retrieve the current proxy configuration from the ProxyConfigService.
1468   // If a configuration is not available yet, we will get called back later
1469   // by our ProxyConfigService::Observer once it changes.
1470   ProxyConfig effective_config;
1471   switch (availability) {
1472     case ProxyConfigService::CONFIG_PENDING:
1473       // ProxyConfigService implementors should never pass CONFIG_PENDING.
1474       NOTREACHED() << "Proxy config change with CONFIG_PENDING availability!";
1475       return;
1476     case ProxyConfigService::CONFIG_VALID:
1477       effective_config = config;
1478       break;
1479     case ProxyConfigService::CONFIG_UNSET:
1480       effective_config = ProxyConfig::CreateDirect();
1481       break;
1482   }
1483 
1484   // Emit the proxy settings change to the NetLog stream.
1485   if (net_log_) {
1486     net_log_->AddGlobalEntry(
1487         net::NetLog::TYPE_PROXY_CONFIG_CHANGED,
1488         base::Bind(&NetLogProxyConfigChangedCallback,
1489                    &fetched_config_, &effective_config));
1490   }
1491 
1492   // Set the new configuration as the most recently fetched one.
1493   fetched_config_ = effective_config;
1494   fetched_config_.set_id(1);  // Needed for a later DCHECK of is_valid().
1495 
1496   InitializeUsingLastFetchedConfig();
1497 }
1498 
InitializeUsingLastFetchedConfig()1499 void ProxyService::InitializeUsingLastFetchedConfig() {
1500   ResetProxyConfig(false);
1501 
1502   DCHECK(fetched_config_.is_valid());
1503 
1504   // Increment the ID to reflect that the config has changed.
1505   fetched_config_.set_id(next_config_id_++);
1506 
1507   if (!fetched_config_.HasAutomaticSettings()) {
1508     config_ = fetched_config_;
1509     SetReady();
1510     return;
1511   }
1512 
1513   // Start downloading + testing the PAC scripts for this new configuration.
1514   current_state_ = STATE_WAITING_FOR_INIT_PROXY_RESOLVER;
1515 
1516   // If we changed networks recently, we should delay running proxy auto-config.
1517   TimeDelta wait_delay =
1518       stall_proxy_autoconfig_until_ - TimeTicks::Now();
1519 
1520   init_proxy_resolver_.reset(new InitProxyResolver());
1521   init_proxy_resolver_->set_quick_check_enabled(quick_check_enabled_);
1522   int rv = init_proxy_resolver_->Start(
1523       resolver_.get(),
1524       proxy_script_fetcher_.get(),
1525       dhcp_proxy_script_fetcher_.get(),
1526       net_log_,
1527       fetched_config_,
1528       wait_delay,
1529       base::Bind(&ProxyService::OnInitProxyResolverComplete,
1530                  base::Unretained(this)));
1531 
1532   if (rv != ERR_IO_PENDING)
1533     OnInitProxyResolverComplete(rv);
1534 }
1535 
InitializeUsingDecidedConfig(int decider_result,ProxyResolverScriptData * script_data,const ProxyConfig & effective_config)1536 void ProxyService::InitializeUsingDecidedConfig(
1537     int decider_result,
1538     ProxyResolverScriptData* script_data,
1539     const ProxyConfig& effective_config) {
1540   DCHECK(fetched_config_.is_valid());
1541   DCHECK(fetched_config_.HasAutomaticSettings());
1542 
1543   ResetProxyConfig(false);
1544 
1545   current_state_ = STATE_WAITING_FOR_INIT_PROXY_RESOLVER;
1546 
1547   init_proxy_resolver_.reset(new InitProxyResolver());
1548   int rv = init_proxy_resolver_->StartSkipDecider(
1549       resolver_.get(),
1550       effective_config,
1551       decider_result,
1552       script_data,
1553       base::Bind(&ProxyService::OnInitProxyResolverComplete,
1554                  base::Unretained(this)));
1555 
1556   if (rv != ERR_IO_PENDING)
1557     OnInitProxyResolverComplete(rv);
1558 }
1559 
OnIPAddressChanged()1560 void ProxyService::OnIPAddressChanged() {
1561   // See the comment block by |kDelayAfterNetworkChangesMs| for info.
1562   stall_proxy_autoconfig_until_ =
1563       TimeTicks::Now() + stall_proxy_auto_config_delay_;
1564 
1565   State previous_state = ResetProxyConfig(false);
1566   if (previous_state != STATE_NONE)
1567     ApplyProxyConfigIfAvailable();
1568 }
1569 
OnDNSChanged()1570 void ProxyService::OnDNSChanged() {
1571   OnIPAddressChanged();
1572 }
1573 
SyncProxyServiceHelper(base::MessageLoop * io_message_loop,ProxyService * proxy_service)1574 SyncProxyServiceHelper::SyncProxyServiceHelper(
1575     base::MessageLoop* io_message_loop,
1576     ProxyService* proxy_service)
1577     : io_message_loop_(io_message_loop),
1578       proxy_service_(proxy_service),
1579       event_(false, false),
1580       callback_(base::Bind(&SyncProxyServiceHelper::OnCompletion,
1581                            base::Unretained(this))) {
1582   DCHECK(io_message_loop_ != base::MessageLoop::current());
1583 }
1584 
ResolveProxy(const GURL & url,ProxyInfo * proxy_info,const BoundNetLog & net_log)1585 int SyncProxyServiceHelper::ResolveProxy(const GURL& url,
1586                                          ProxyInfo* proxy_info,
1587                                          const BoundNetLog& net_log) {
1588   DCHECK(io_message_loop_ != base::MessageLoop::current());
1589 
1590   io_message_loop_->PostTask(
1591       FROM_HERE,
1592       base::Bind(&SyncProxyServiceHelper::StartAsyncResolve, this, url,
1593                  net_log));
1594 
1595   event_.Wait();
1596 
1597   if (result_ == net::OK) {
1598     *proxy_info = proxy_info_;
1599   }
1600   return result_;
1601 }
1602 
ReconsiderProxyAfterError(const GURL & url,int net_error,ProxyInfo * proxy_info,const BoundNetLog & net_log)1603 int SyncProxyServiceHelper::ReconsiderProxyAfterError(
1604     const GURL& url, int net_error, ProxyInfo* proxy_info,
1605     const BoundNetLog& net_log) {
1606   DCHECK(io_message_loop_ != base::MessageLoop::current());
1607 
1608   io_message_loop_->PostTask(
1609       FROM_HERE,
1610       base::Bind(&SyncProxyServiceHelper::StartAsyncReconsider, this, url,
1611                  net_error, net_log));
1612 
1613   event_.Wait();
1614 
1615   if (result_ == net::OK) {
1616     *proxy_info = proxy_info_;
1617   }
1618   return result_;
1619 }
1620 
~SyncProxyServiceHelper()1621 SyncProxyServiceHelper::~SyncProxyServiceHelper() {}
1622 
StartAsyncResolve(const GURL & url,const BoundNetLog & net_log)1623 void SyncProxyServiceHelper::StartAsyncResolve(const GURL& url,
1624                                                const BoundNetLog& net_log) {
1625   result_ = proxy_service_->ResolveProxy(
1626       url, &proxy_info_, callback_, NULL, net_log);
1627   if (result_ != net::ERR_IO_PENDING) {
1628     OnCompletion(result_);
1629   }
1630 }
1631 
StartAsyncReconsider(const GURL & url,int net_error,const BoundNetLog & net_log)1632 void SyncProxyServiceHelper::StartAsyncReconsider(const GURL& url,
1633                                                   int net_error,
1634                                                   const BoundNetLog& net_log) {
1635   result_ = proxy_service_->ReconsiderProxyAfterError(
1636       url, net_error, &proxy_info_, callback_, NULL, net_log);
1637   if (result_ != net::ERR_IO_PENDING) {
1638     OnCompletion(result_);
1639   }
1640 }
1641 
OnCompletion(int rv)1642 void SyncProxyServiceHelper::OnCompletion(int rv) {
1643   result_ = rv;
1644   event_.Signal();
1645 }
1646 
1647 }  // namespace net
1648