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