proxy_service.cc revision 7dbb3d5cf0c15f500944d211057644d6a2f37371
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.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/net_errors.h"
21#include "net/base/net_log.h"
22#include "net/base/net_util.h"
23#include "net/proxy/dhcp_proxy_script_fetcher.h"
24#include "net/proxy/multi_threaded_proxy_resolver.h"
25#include "net/proxy/network_delegate_error_observer.h"
26#include "net/proxy/proxy_config_service_fixed.h"
27#include "net/proxy/proxy_resolver.h"
28#include "net/proxy/proxy_script_decider.h"
29#include "net/proxy/proxy_script_fetcher.h"
30#include "net/url_request/url_request_context.h"
31#include "url/gurl.h"
32
33#if defined(OS_WIN)
34#include "net/proxy/proxy_config_service_win.h"
35#include "net/proxy/proxy_resolver_winhttp.h"
36#elif defined(OS_IOS)
37#include "net/proxy/proxy_config_service_ios.h"
38#include "net/proxy/proxy_resolver_mac.h"
39#elif defined(OS_MACOSX)
40#include "net/proxy/proxy_config_service_mac.h"
41#include "net/proxy/proxy_resolver_mac.h"
42#elif defined(OS_LINUX) && !defined(OS_CHROMEOS)
43#include "net/proxy/proxy_config_service_linux.h"
44#elif defined(OS_ANDROID)
45#include "net/proxy/proxy_config_service_android.h"
46#endif
47
48using base::TimeDelta;
49using base::TimeTicks;
50
51namespace net {
52
53namespace {
54
55const size_t kMaxNumNetLogEntries = 100;
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.
75const 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.
119class DefaultPollPolicy : public ProxyService::PacPollPolicy {
120 public:
121  DefaultPollPolicy() {}
122
123  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.
161class ProxyConfigServiceDirect : public ProxyConfigService {
162 public:
163  // ProxyConfigService implementation:
164  virtual void AddObserver(Observer* observer) OVERRIDE {}
165  virtual void RemoveObserver(Observer* observer) OVERRIDE {}
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.
175class ProxyResolverNull : public ProxyResolver {
176 public:
177  ProxyResolverNull() : ProxyResolver(false /*expects_pac_bytes*/) {}
178
179  // ProxyResolver implementation.
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
188  virtual void CancelRequest(RequestHandle request) OVERRIDE {
189    NOTREACHED();
190  }
191
192  virtual LoadState GetLoadState(RequestHandle request) const OVERRIDE {
193    NOTREACHED();
194    return LOAD_STATE_IDLE;
195  }
196
197  virtual void CancelSetPacScript() OVERRIDE {
198    NOTREACHED();
199  }
200
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.
210class ProxyResolverFromPacString : public ProxyResolver {
211 public:
212  explicit ProxyResolverFromPacString(const std::string& pac_string)
213      : ProxyResolver(false /*expects_pac_bytes*/),
214        pac_string_(pac_string) {}
215
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
225  virtual void CancelRequest(RequestHandle request) OVERRIDE {
226    NOTREACHED();
227  }
228
229  virtual LoadState GetLoadState(RequestHandle request) const OVERRIDE {
230    NOTREACHED();
231    return LOAD_STATE_IDLE;
232  }
233
234  virtual void CancelSetPacScript() OVERRIDE {
235    NOTREACHED();
236  }
237
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.
249class ProxyResolverFactoryForSystem : public ProxyResolverFactory {
250 public:
251  ProxyResolverFactoryForSystem()
252      : ProxyResolverFactory(false /*expects_pac_bytes*/) {}
253
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
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.
276base::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
289base::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.
303base::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)
312class UnsetProxyConfigService : public ProxyConfigService {
313 public:
314  UnsetProxyConfigService() {}
315  virtual ~UnsetProxyConfigService() {}
316
317  virtual void AddObserver(Observer* observer) OVERRIDE {}
318  virtual void RemoveObserver(Observer* observer) OVERRIDE {}
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
340class ProxyService::InitProxyResolver {
341 public:
342  InitProxyResolver()
343      : proxy_resolver_(NULL),
344        next_state_(STATE_NONE) {
345  }
346
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.
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    config_ = config;
369    wait_delay_ = wait_delay;
370    callback_ = callback;
371
372    next_state_ = STATE_DECIDE_PROXY_SCRIPT;
373    return DoLoop(OK);
374  }
375
376  // Similar to Start(), however it skips the ProxyScriptDecider stage. Instead
377  // |effective_config|, |decider_result| and |script_data| will be used as the
378  // inputs for initializing the ProxyResolver.
379  int StartSkipDecider(ProxyResolver* proxy_resolver,
380                       const ProxyConfig& effective_config,
381                       int decider_result,
382                       ProxyResolverScriptData* script_data,
383                       const CompletionCallback& callback) {
384    DCHECK_EQ(STATE_NONE, next_state_);
385    proxy_resolver_ = proxy_resolver;
386
387    effective_config_ = effective_config;
388    script_data_ = script_data;
389    callback_ = callback;
390
391    if (decider_result != OK)
392      return decider_result;
393
394    next_state_ = STATE_SET_PAC_SCRIPT;
395    return DoLoop(OK);
396  }
397
398  // Returns the proxy configuration that was selected by ProxyScriptDecider.
399  // Should only be called upon completion of the initialization.
400  const ProxyConfig& effective_config() const {
401    DCHECK_EQ(STATE_NONE, next_state_);
402    return effective_config_;
403  }
404
405  // Returns the PAC script data that was selected by ProxyScriptDecider.
406  // Should only be called upon completion of the initialization.
407  ProxyResolverScriptData* script_data() {
408    DCHECK_EQ(STATE_NONE, next_state_);
409    return script_data_.get();
410  }
411
412  LoadState GetLoadState() const {
413    if (next_state_ == STATE_DECIDE_PROXY_SCRIPT_COMPLETE) {
414      // In addition to downloading, this state may also include the stall time
415      // after network change events (kDelayAfterNetworkChangesMs).
416      return LOAD_STATE_DOWNLOADING_PROXY_SCRIPT;
417    }
418    return LOAD_STATE_RESOLVING_PROXY_FOR_URL;
419  }
420
421 private:
422  enum State {
423    STATE_NONE,
424    STATE_DECIDE_PROXY_SCRIPT,
425    STATE_DECIDE_PROXY_SCRIPT_COMPLETE,
426    STATE_SET_PAC_SCRIPT,
427    STATE_SET_PAC_SCRIPT_COMPLETE,
428  };
429
430  int DoLoop(int result) {
431    DCHECK_NE(next_state_, STATE_NONE);
432    int rv = result;
433    do {
434      State state = next_state_;
435      next_state_ = STATE_NONE;
436      switch (state) {
437        case STATE_DECIDE_PROXY_SCRIPT:
438          DCHECK_EQ(OK, rv);
439          rv = DoDecideProxyScript();
440          break;
441        case STATE_DECIDE_PROXY_SCRIPT_COMPLETE:
442          rv = DoDecideProxyScriptComplete(rv);
443          break;
444        case STATE_SET_PAC_SCRIPT:
445          DCHECK_EQ(OK, rv);
446          rv = DoSetPacScript();
447          break;
448        case STATE_SET_PAC_SCRIPT_COMPLETE:
449          rv = DoSetPacScriptComplete(rv);
450          break;
451        default:
452          NOTREACHED() << "bad state: " << state;
453          rv = ERR_UNEXPECTED;
454          break;
455      }
456    } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
457    return rv;
458  }
459
460  int DoDecideProxyScript() {
461    next_state_ = STATE_DECIDE_PROXY_SCRIPT_COMPLETE;
462
463    return decider_->Start(
464        config_, wait_delay_, proxy_resolver_->expects_pac_bytes(),
465        base::Bind(&InitProxyResolver::OnIOCompletion, base::Unretained(this)));
466  }
467
468  int DoDecideProxyScriptComplete(int result) {
469    if (result != OK)
470      return result;
471
472    effective_config_ = decider_->effective_config();
473    script_data_ = decider_->script_data();
474
475    next_state_ = STATE_SET_PAC_SCRIPT;
476    return OK;
477  }
478
479  int DoSetPacScript() {
480    DCHECK(script_data_.get());
481    // TODO(eroman): Should log this latency to the NetLog.
482    next_state_ = STATE_SET_PAC_SCRIPT_COMPLETE;
483    return proxy_resolver_->SetPacScript(
484        script_data_,
485        base::Bind(&InitProxyResolver::OnIOCompletion, base::Unretained(this)));
486  }
487
488  int DoSetPacScriptComplete(int result) {
489    return result;
490  }
491
492  void OnIOCompletion(int result) {
493    DCHECK_NE(STATE_NONE, next_state_);
494    int rv = DoLoop(result);
495    if (rv != ERR_IO_PENDING)
496      DoCallback(rv);
497  }
498
499  void DoCallback(int result) {
500    DCHECK_NE(ERR_IO_PENDING, result);
501    callback_.Run(result);
502  }
503
504  ProxyConfig config_;
505  ProxyConfig effective_config_;
506  scoped_refptr<ProxyResolverScriptData> script_data_;
507  TimeDelta wait_delay_;
508  scoped_ptr<ProxyScriptDecider> decider_;
509  ProxyResolver* proxy_resolver_;
510  CompletionCallback callback_;
511  State next_state_;
512
513  DISALLOW_COPY_AND_ASSIGN(InitProxyResolver);
514};
515
516// ProxyService::ProxyScriptDeciderPoller -------------------------------------
517
518// This helper class encapsulates the logic to schedule and run periodic
519// background checks to see if the PAC script (or effective proxy configuration)
520// has changed. If a change is detected, then the caller will be notified via
521// the ChangeCallback.
522class ProxyService::ProxyScriptDeciderPoller {
523 public:
524  typedef base::Callback<void(int, ProxyResolverScriptData*,
525                              const ProxyConfig&)> ChangeCallback;
526
527  // Builds a poller helper, and starts polling for updates. Whenever a change
528  // is observed, |callback| will be invoked with the details.
529  //
530  //   |config| specifies the (unresolved) proxy configuration to poll.
531  //   |proxy_resolver_expects_pac_bytes| the type of proxy resolver we expect
532  //                                      to use the resulting script data with
533  //                                      (so it can choose the right format).
534  //   |proxy_script_fetcher| this pointer must remain alive throughout our
535  //                          lifetime. It is the dependency that will be used
536  //                          for downloading proxy scripts.
537  //   |dhcp_proxy_script_fetcher| similar to |proxy_script_fetcher|, but for
538  //                               the DHCP dependency.
539  //   |init_net_error| This is the initial network error (possibly success)
540  //                    encountered by the first PAC fetch attempt. We use it
541  //                    to schedule updates more aggressively if the initial
542  //                    fetch resulted in an error.
543  //   |init_script_data| the initial script data from the PAC fetch attempt.
544  //                      This is the baseline used to determine when the
545  //                      script's contents have changed.
546  //   |net_log| the NetLog to log progress into.
547  ProxyScriptDeciderPoller(ChangeCallback callback,
548                           const ProxyConfig& config,
549                           bool proxy_resolver_expects_pac_bytes,
550                           ProxyScriptFetcher* proxy_script_fetcher,
551                           DhcpProxyScriptFetcher* dhcp_proxy_script_fetcher,
552                           int init_net_error,
553                           ProxyResolverScriptData* init_script_data,
554                           NetLog* net_log)
555      : weak_factory_(this),
556        change_callback_(callback),
557        config_(config),
558        proxy_resolver_expects_pac_bytes_(proxy_resolver_expects_pac_bytes),
559        proxy_script_fetcher_(proxy_script_fetcher),
560        dhcp_proxy_script_fetcher_(dhcp_proxy_script_fetcher),
561        last_error_(init_net_error),
562        last_script_data_(init_script_data),
563        last_poll_time_(TimeTicks::Now()) {
564    // Set the initial poll delay.
565    next_poll_mode_ = poll_policy()->GetNextDelay(
566        last_error_, TimeDelta::FromSeconds(-1), &next_poll_delay_);
567    TryToStartNextPoll(false);
568  }
569
570  void OnLazyPoll() {
571    // We have just been notified of network activity. Use this opportunity to
572    // see if we can start our next poll.
573    TryToStartNextPoll(true);
574  }
575
576  static const PacPollPolicy* set_policy(const PacPollPolicy* policy) {
577    const PacPollPolicy* prev = poll_policy_;
578    poll_policy_ = policy;
579    return prev;
580  }
581
582 private:
583  // Returns the effective poll policy (the one injected by unit-tests, or the
584  // default).
585  const PacPollPolicy* poll_policy() {
586    if (poll_policy_)
587      return poll_policy_;
588    return &default_poll_policy_;
589  }
590
591  void StartPollTimer() {
592    DCHECK(!decider_.get());
593
594    base::MessageLoop::current()->PostDelayedTask(
595        FROM_HERE,
596        base::Bind(&ProxyScriptDeciderPoller::DoPoll,
597                   weak_factory_.GetWeakPtr()),
598        next_poll_delay_);
599  }
600
601  void TryToStartNextPoll(bool triggered_by_activity) {
602    switch (next_poll_mode_) {
603      case PacPollPolicy::MODE_USE_TIMER:
604        if (!triggered_by_activity)
605          StartPollTimer();
606        break;
607
608      case PacPollPolicy::MODE_START_AFTER_ACTIVITY:
609        if (triggered_by_activity && !decider_.get()) {
610          TimeDelta elapsed_time = TimeTicks::Now() - last_poll_time_;
611          if (elapsed_time >= next_poll_delay_)
612            DoPoll();
613        }
614        break;
615    }
616  }
617
618  void DoPoll() {
619    last_poll_time_ = TimeTicks::Now();
620
621    // Start the proxy script decider to see if anything has changed.
622    // TODO(eroman): Pass a proper NetLog rather than NULL.
623    decider_.reset(new ProxyScriptDecider(
624        proxy_script_fetcher_, dhcp_proxy_script_fetcher_, NULL));
625    int result = decider_->Start(
626        config_, TimeDelta(), proxy_resolver_expects_pac_bytes_,
627        base::Bind(&ProxyScriptDeciderPoller::OnProxyScriptDeciderCompleted,
628                   base::Unretained(this)));
629
630    if (result != ERR_IO_PENDING)
631      OnProxyScriptDeciderCompleted(result);
632  }
633
634  void OnProxyScriptDeciderCompleted(int result) {
635    if (HasScriptDataChanged(result, decider_->script_data())) {
636      // Something has changed, we must notify the ProxyService so it can
637      // re-initialize its ProxyResolver. Note that we post a notification task
638      // rather than calling it directly -- this is done to avoid an ugly
639      // destruction sequence, since |this| might be destroyed as a result of
640      // the notification.
641      base::MessageLoop::current()->PostTask(
642          FROM_HERE,
643          base::Bind(&ProxyScriptDeciderPoller::NotifyProxyServiceOfChange,
644                     weak_factory_.GetWeakPtr(),
645                     result,
646                     make_scoped_refptr(decider_->script_data()),
647                     decider_->effective_config()));
648      return;
649    }
650
651    decider_.reset();
652
653    // Decide when the next poll should take place, and possibly start the
654    // next timer.
655    next_poll_mode_ = poll_policy()->GetNextDelay(
656        last_error_, next_poll_delay_, &next_poll_delay_);
657    TryToStartNextPoll(false);
658  }
659
660  bool HasScriptDataChanged(int result, ProxyResolverScriptData* script_data) {
661    if (result != last_error_) {
662      // Something changed -- it was failing before and now it succeeded, or
663      // conversely it succeeded before and now it failed. Or it failed in
664      // both cases, however the specific failure error codes differ.
665      return true;
666    }
667
668    if (result != OK) {
669      // If it failed last time and failed again with the same error code this
670      // time, then nothing has actually changed.
671      return false;
672    }
673
674    // Otherwise if it succeeded both this time and last time, we need to look
675    // closer and see if we ended up downloading different content for the PAC
676    // script.
677    return !script_data->Equals(last_script_data_.get());
678  }
679
680  void NotifyProxyServiceOfChange(
681      int result,
682      const scoped_refptr<ProxyResolverScriptData>& script_data,
683      const ProxyConfig& effective_config) {
684    // Note that |this| may be deleted after calling into the ProxyService.
685    change_callback_.Run(result, script_data.get(), effective_config);
686  }
687
688  base::WeakPtrFactory<ProxyScriptDeciderPoller> weak_factory_;
689
690  ChangeCallback change_callback_;
691  ProxyConfig config_;
692  bool proxy_resolver_expects_pac_bytes_;
693  ProxyScriptFetcher* proxy_script_fetcher_;
694  DhcpProxyScriptFetcher* dhcp_proxy_script_fetcher_;
695
696  int last_error_;
697  scoped_refptr<ProxyResolverScriptData> last_script_data_;
698
699  scoped_ptr<ProxyScriptDecider> decider_;
700  TimeDelta next_poll_delay_;
701  PacPollPolicy::Mode next_poll_mode_;
702
703  TimeTicks last_poll_time_;
704
705  // Polling policy injected by unit-tests. Otherwise this is NULL and the
706  // default policy will be used.
707  static const PacPollPolicy* poll_policy_;
708
709  const DefaultPollPolicy default_poll_policy_;
710
711  DISALLOW_COPY_AND_ASSIGN(ProxyScriptDeciderPoller);
712};
713
714// static
715const ProxyService::PacPollPolicy*
716    ProxyService::ProxyScriptDeciderPoller::poll_policy_ = NULL;
717
718// ProxyService::PacRequest ---------------------------------------------------
719
720class ProxyService::PacRequest
721    : public base::RefCounted<ProxyService::PacRequest> {
722 public:
723    PacRequest(ProxyService* service,
724               const GURL& url,
725               ProxyInfo* results,
726               const net::CompletionCallback& user_callback,
727               const BoundNetLog& net_log)
728      : service_(service),
729        user_callback_(user_callback),
730        results_(results),
731        url_(url),
732        resolve_job_(NULL),
733        config_id_(ProxyConfig::kInvalidConfigID),
734        config_source_(PROXY_CONFIG_SOURCE_UNKNOWN),
735        net_log_(net_log) {
736    DCHECK(!user_callback.is_null());
737  }
738
739  // Starts the resolve proxy request.
740  int Start() {
741    DCHECK(!was_cancelled());
742    DCHECK(!is_started());
743
744    DCHECK(service_->config_.is_valid());
745
746    config_id_ = service_->config_.id();
747    config_source_ = service_->config_.source();
748    proxy_resolve_start_time_ = TimeTicks::Now();
749
750    return resolver()->GetProxyForURL(
751        url_, results_,
752        base::Bind(&PacRequest::QueryComplete, base::Unretained(this)),
753        &resolve_job_, net_log_);
754  }
755
756  bool is_started() const {
757    // Note that !! casts to bool. (VS gives a warning otherwise).
758    return !!resolve_job_;
759  }
760
761  void StartAndCompleteCheckingForSynchronous() {
762    int rv = service_->TryToCompleteSynchronously(url_, results_);
763    if (rv == ERR_IO_PENDING)
764      rv = Start();
765    if (rv != ERR_IO_PENDING)
766      QueryComplete(rv);
767  }
768
769  void CancelResolveJob() {
770    DCHECK(is_started());
771    // The request may already be running in the resolver.
772    resolver()->CancelRequest(resolve_job_);
773    resolve_job_ = NULL;
774    DCHECK(!is_started());
775  }
776
777  void Cancel() {
778    net_log_.AddEvent(NetLog::TYPE_CANCELLED);
779
780    if (is_started())
781      CancelResolveJob();
782
783    // Mark as cancelled, to prevent accessing this again later.
784    service_ = NULL;
785    user_callback_.Reset();
786    results_ = NULL;
787
788    net_log_.EndEvent(NetLog::TYPE_PROXY_SERVICE);
789  }
790
791  // Returns true if Cancel() has been called.
792  bool was_cancelled() const {
793    return user_callback_.is_null();
794  }
795
796  // Helper to call after ProxyResolver completion (both synchronous and
797  // asynchronous). Fixes up the result that is to be returned to user.
798  int QueryDidComplete(int result_code) {
799    DCHECK(!was_cancelled());
800
801    // Note that DidFinishResolvingProxy might modify |results_|.
802    int rv = service_->DidFinishResolvingProxy(results_, result_code, net_log_);
803
804    // Make a note in the results which configuration was in use at the
805    // time of the resolve.
806    results_->config_id_ = config_id_;
807    results_->config_source_ = config_source_;
808    results_->did_use_pac_script_ = true;
809    results_->proxy_resolve_start_time_ = proxy_resolve_start_time_;
810    results_->proxy_resolve_end_time_ = TimeTicks::Now();
811
812    // Reset the state associated with in-progress-resolve.
813    resolve_job_ = NULL;
814    config_id_ = ProxyConfig::kInvalidConfigID;
815    config_source_ = PROXY_CONFIG_SOURCE_UNKNOWN;
816
817    return rv;
818  }
819
820  BoundNetLog* net_log() { return &net_log_; }
821
822  LoadState GetLoadState() const {
823    if (is_started())
824      return resolver()->GetLoadState(resolve_job_);
825    return LOAD_STATE_RESOLVING_PROXY_FOR_URL;
826  }
827
828 private:
829  friend class base::RefCounted<ProxyService::PacRequest>;
830
831  ~PacRequest() {}
832
833  // Callback for when the ProxyResolver request has completed.
834  void QueryComplete(int result_code) {
835    result_code = QueryDidComplete(result_code);
836
837    // Remove this completed PacRequest from the service's pending list.
838    /// (which will probably cause deletion of |this|).
839    if (!user_callback_.is_null()) {
840      net::CompletionCallback callback = user_callback_;
841      service_->RemovePendingRequest(this);
842      callback.Run(result_code);
843    }
844  }
845
846  ProxyResolver* resolver() const { return service_->resolver_.get(); }
847
848  // Note that we don't hold a reference to the ProxyService. Outstanding
849  // requests are cancelled during ~ProxyService, so this is guaranteed
850  // to be valid throughout our lifetime.
851  ProxyService* service_;
852  net::CompletionCallback user_callback_;
853  ProxyInfo* results_;
854  GURL url_;
855  ProxyResolver::RequestHandle resolve_job_;
856  ProxyConfig::ID config_id_;  // The config id when the resolve was started.
857  ProxyConfigSource config_source_;  // The source of proxy settings.
858  BoundNetLog net_log_;
859  // Time when the PAC is started.  Cached here since resetting ProxyInfo also
860  // clears the proxy times.
861  TimeTicks proxy_resolve_start_time_;
862};
863
864// ProxyService ---------------------------------------------------------------
865
866ProxyService::ProxyService(ProxyConfigService* config_service,
867                           ProxyResolver* resolver,
868                           NetLog* net_log)
869    : resolver_(resolver),
870      next_config_id_(1),
871      current_state_(STATE_NONE) ,
872      net_log_(net_log),
873      stall_proxy_auto_config_delay_(TimeDelta::FromMilliseconds(
874          kDelayAfterNetworkChangesMs)) {
875  NetworkChangeNotifier::AddIPAddressObserver(this);
876  NetworkChangeNotifier::AddDNSObserver(this);
877  ResetConfigService(config_service);
878}
879
880// static
881ProxyService* ProxyService::CreateUsingSystemProxyResolver(
882    ProxyConfigService* proxy_config_service,
883    size_t num_pac_threads,
884    NetLog* net_log) {
885  DCHECK(proxy_config_service);
886
887  if (!ProxyResolverFactoryForSystem::IsSupported()) {
888    LOG(WARNING) << "PAC support disabled because there is no "
889                    "system implementation";
890    return CreateWithoutProxyResolver(proxy_config_service, net_log);
891  }
892
893  if (num_pac_threads == 0)
894    num_pac_threads = kDefaultNumPacThreads;
895
896  ProxyResolver* proxy_resolver = new MultiThreadedProxyResolver(
897      new ProxyResolverFactoryForSystem(), num_pac_threads);
898
899  return new ProxyService(proxy_config_service, proxy_resolver, net_log);
900}
901
902// static
903ProxyService* ProxyService::CreateWithoutProxyResolver(
904    ProxyConfigService* proxy_config_service,
905    NetLog* net_log) {
906  return new ProxyService(proxy_config_service,
907                          new ProxyResolverNull(),
908                          net_log);
909}
910
911// static
912ProxyService* ProxyService::CreateFixed(const ProxyConfig& pc) {
913  // TODO(eroman): This isn't quite right, won't work if |pc| specifies
914  //               a PAC script.
915  return CreateUsingSystemProxyResolver(new ProxyConfigServiceFixed(pc),
916                                        0, NULL);
917}
918
919// static
920ProxyService* ProxyService::CreateFixed(const std::string& proxy) {
921  net::ProxyConfig proxy_config;
922  proxy_config.proxy_rules().ParseFromString(proxy);
923  return ProxyService::CreateFixed(proxy_config);
924}
925
926// static
927ProxyService* ProxyService::CreateDirect() {
928  return CreateDirectWithNetLog(NULL);
929}
930
931ProxyService* ProxyService::CreateDirectWithNetLog(NetLog* net_log) {
932  // Use direct connections.
933  return new ProxyService(new ProxyConfigServiceDirect, new ProxyResolverNull,
934                          net_log);
935}
936
937// static
938ProxyService* ProxyService::CreateFixedFromPacResult(
939    const std::string& pac_string) {
940
941  // We need the settings to contain an "automatic" setting, otherwise the
942  // ProxyResolver dependency we give it will never be used.
943  scoped_ptr<ProxyConfigService> proxy_config_service(
944      new ProxyConfigServiceFixed(ProxyConfig::CreateAutoDetect()));
945
946  scoped_ptr<ProxyResolver> proxy_resolver(
947      new ProxyResolverFromPacString(pac_string));
948
949  return new ProxyService(proxy_config_service.release(),
950                          proxy_resolver.release(),
951                          NULL);
952}
953
954int ProxyService::ResolveProxy(const GURL& raw_url,
955                               ProxyInfo* result,
956                               const net::CompletionCallback& callback,
957                               PacRequest** pac_request,
958                               const BoundNetLog& net_log) {
959  DCHECK(CalledOnValidThread());
960  DCHECK(!callback.is_null());
961
962  net_log.BeginEvent(NetLog::TYPE_PROXY_SERVICE);
963
964  // Notify our polling-based dependencies that a resolve is taking place.
965  // This way they can schedule their polls in response to network activity.
966  config_service_->OnLazyPoll();
967  if (script_poller_.get())
968     script_poller_->OnLazyPoll();
969
970  if (current_state_ == STATE_NONE)
971    ApplyProxyConfigIfAvailable();
972
973  // Strip away any reference fragments and the username/password, as they
974  // are not relevant to proxy resolution.
975  GURL url = SimplifyUrlForRequest(raw_url);
976
977  // Check if the request can be completed right away. (This is the case when
978  // using a direct connection for example).
979  int rv = TryToCompleteSynchronously(url, result);
980  if (rv != ERR_IO_PENDING)
981    return DidFinishResolvingProxy(result, rv, net_log);
982
983  scoped_refptr<PacRequest> req(
984      new PacRequest(this, url, result, callback, net_log));
985
986  if (current_state_ == STATE_READY) {
987    // Start the resolve request.
988    rv = req->Start();
989    if (rv != ERR_IO_PENDING)
990      return req->QueryDidComplete(rv);
991  } else {
992    req->net_log()->BeginEvent(NetLog::TYPE_PROXY_SERVICE_WAITING_FOR_INIT_PAC);
993  }
994
995  DCHECK_EQ(ERR_IO_PENDING, rv);
996  DCHECK(!ContainsPendingRequest(req.get()));
997  pending_requests_.push_back(req);
998
999  // Completion will be notified through |callback|, unless the caller cancels
1000  // the request using |pac_request|.
1001  if (pac_request)
1002    *pac_request = req.get();
1003  return rv;  // ERR_IO_PENDING
1004}
1005
1006int ProxyService::TryToCompleteSynchronously(const GURL& url,
1007                                             ProxyInfo* result) {
1008  DCHECK_NE(STATE_NONE, current_state_);
1009
1010  if (current_state_ != STATE_READY)
1011    return ERR_IO_PENDING;  // Still initializing.
1012
1013  DCHECK_NE(config_.id(), ProxyConfig::kInvalidConfigID);
1014
1015  // If it was impossible to fetch or parse the PAC script, we cannot complete
1016  // the request here and bail out.
1017  if (permanent_error_ != OK)
1018    return permanent_error_;
1019
1020  if (config_.HasAutomaticSettings())
1021    return ERR_IO_PENDING;  // Must submit the request to the proxy resolver.
1022
1023  // Use the manual proxy settings.
1024  config_.proxy_rules().Apply(url, result);
1025  result->config_source_ = config_.source();
1026  result->config_id_ = config_.id();
1027  return OK;
1028}
1029
1030ProxyService::~ProxyService() {
1031  NetworkChangeNotifier::RemoveIPAddressObserver(this);
1032  NetworkChangeNotifier::RemoveDNSObserver(this);
1033  config_service_->RemoveObserver(this);
1034
1035  // Cancel any inprogress requests.
1036  for (PendingRequests::iterator it = pending_requests_.begin();
1037       it != pending_requests_.end();
1038       ++it) {
1039    (*it)->Cancel();
1040  }
1041}
1042
1043void ProxyService::SuspendAllPendingRequests() {
1044  for (PendingRequests::iterator it = pending_requests_.begin();
1045       it != pending_requests_.end();
1046       ++it) {
1047    PacRequest* req = it->get();
1048    if (req->is_started()) {
1049      req->CancelResolveJob();
1050
1051      req->net_log()->BeginEvent(
1052          NetLog::TYPE_PROXY_SERVICE_WAITING_FOR_INIT_PAC);
1053    }
1054  }
1055}
1056
1057void ProxyService::SetReady() {
1058  DCHECK(!init_proxy_resolver_.get());
1059  current_state_ = STATE_READY;
1060
1061  // Make a copy in case |this| is deleted during the synchronous completion
1062  // of one of the requests. If |this| is deleted then all of the PacRequest
1063  // instances will be Cancel()-ed.
1064  PendingRequests pending_copy = pending_requests_;
1065
1066  for (PendingRequests::iterator it = pending_copy.begin();
1067       it != pending_copy.end();
1068       ++it) {
1069    PacRequest* req = it->get();
1070    if (!req->is_started() && !req->was_cancelled()) {
1071      req->net_log()->EndEvent(NetLog::TYPE_PROXY_SERVICE_WAITING_FOR_INIT_PAC);
1072
1073      // Note that we re-check for synchronous completion, in case we are
1074      // no longer using a ProxyResolver (can happen if we fell-back to manual).
1075      req->StartAndCompleteCheckingForSynchronous();
1076    }
1077  }
1078}
1079
1080void ProxyService::ApplyProxyConfigIfAvailable() {
1081  DCHECK_EQ(STATE_NONE, current_state_);
1082
1083  config_service_->OnLazyPoll();
1084
1085  // If we have already fetched the configuration, start applying it.
1086  if (fetched_config_.is_valid()) {
1087    InitializeUsingLastFetchedConfig();
1088    return;
1089  }
1090
1091  // Otherwise we need to first fetch the configuration.
1092  current_state_ = STATE_WAITING_FOR_PROXY_CONFIG;
1093
1094  // Retrieve the current proxy configuration from the ProxyConfigService.
1095  // If a configuration is not available yet, we will get called back later
1096  // by our ProxyConfigService::Observer once it changes.
1097  ProxyConfig config;
1098  ProxyConfigService::ConfigAvailability availability =
1099      config_service_->GetLatestProxyConfig(&config);
1100  if (availability != ProxyConfigService::CONFIG_PENDING)
1101    OnProxyConfigChanged(config, availability);
1102}
1103
1104void ProxyService::OnInitProxyResolverComplete(int result) {
1105  DCHECK_EQ(STATE_WAITING_FOR_INIT_PROXY_RESOLVER, current_state_);
1106  DCHECK(init_proxy_resolver_.get());
1107  DCHECK(fetched_config_.HasAutomaticSettings());
1108  config_ = init_proxy_resolver_->effective_config();
1109
1110  // At this point we have decided which proxy settings to use (i.e. which PAC
1111  // script if any). We start up a background poller to periodically revisit
1112  // this decision. If the contents of the PAC script change, or if the
1113  // result of proxy auto-discovery changes, this poller will notice it and
1114  // will trigger a re-initialization using the newly discovered PAC.
1115  script_poller_.reset(new ProxyScriptDeciderPoller(
1116      base::Bind(&ProxyService::InitializeUsingDecidedConfig,
1117                 base::Unretained(this)),
1118      fetched_config_,
1119      resolver_->expects_pac_bytes(),
1120      proxy_script_fetcher_.get(),
1121      dhcp_proxy_script_fetcher_.get(),
1122      result,
1123      init_proxy_resolver_->script_data(),
1124      NULL));
1125
1126  init_proxy_resolver_.reset();
1127
1128  if (result != OK) {
1129    if (fetched_config_.pac_mandatory()) {
1130      VLOG(1) << "Failed configuring with mandatory PAC script, blocking all "
1131                 "traffic.";
1132      config_ = fetched_config_;
1133      result = ERR_MANDATORY_PROXY_CONFIGURATION_FAILED;
1134    } else {
1135      VLOG(1) << "Failed configuring with PAC script, falling-back to manual "
1136                 "proxy servers.";
1137      config_ = fetched_config_;
1138      config_.ClearAutomaticSettings();
1139      result = OK;
1140    }
1141  }
1142  permanent_error_ = result;
1143
1144  // TODO(eroman): Make this ID unique in the case where configuration changed
1145  //               due to ProxyScriptDeciderPoller.
1146  config_.set_id(fetched_config_.id());
1147  config_.set_source(fetched_config_.source());
1148
1149  // Resume any requests which we had to defer until the PAC script was
1150  // downloaded.
1151  SetReady();
1152}
1153
1154int ProxyService::ReconsiderProxyAfterError(const GURL& url,
1155                                            ProxyInfo* result,
1156                                            const CompletionCallback& callback,
1157                                            PacRequest** pac_request,
1158                                            const BoundNetLog& net_log) {
1159  DCHECK(CalledOnValidThread());
1160
1161  // Check to see if we have a new config since ResolveProxy was called.  We
1162  // want to re-run ResolveProxy in two cases: 1) we have a new config, or 2) a
1163  // direct connection failed and we never tried the current config.
1164
1165  bool re_resolve = result->config_id_ != config_.id();
1166
1167  if (re_resolve) {
1168    // If we have a new config or the config was never tried, we delete the
1169    // list of bad proxies and we try again.
1170    proxy_retry_info_.clear();
1171    return ResolveProxy(url, result, callback, pac_request, net_log);
1172  }
1173
1174  // We don't have new proxy settings to try, try to fallback to the next proxy
1175  // in the list.
1176  bool did_fallback = result->Fallback(net_log);
1177
1178  // Return synchronous failure if there is nothing left to fall-back to.
1179  // TODO(eroman): This is a yucky API, clean it up.
1180  return did_fallback ? OK : ERR_FAILED;
1181}
1182
1183bool ProxyService::MarkProxyAsBad(const ProxyInfo& result,
1184                                  const BoundNetLog& net_log) {
1185  result.proxy_list_.UpdateRetryInfoOnFallback(&proxy_retry_info_, net_log);
1186  return result.proxy_list_.HasUntriedProxies(proxy_retry_info_);
1187}
1188
1189void ProxyService::ReportSuccess(const ProxyInfo& result) {
1190  DCHECK(CalledOnValidThread());
1191
1192  const ProxyRetryInfoMap& new_retry_info = result.proxy_retry_info();
1193  if (new_retry_info.empty())
1194    return;
1195
1196  for (ProxyRetryInfoMap::const_iterator iter = new_retry_info.begin();
1197       iter != new_retry_info.end(); ++iter) {
1198    ProxyRetryInfoMap::iterator existing = proxy_retry_info_.find(iter->first);
1199    if (existing == proxy_retry_info_.end())
1200      proxy_retry_info_[iter->first] = iter->second;
1201    else if (existing->second.bad_until < iter->second.bad_until)
1202      existing->second.bad_until = iter->second.bad_until;
1203  }
1204  if (net_log_) {
1205    net_log_->AddGlobalEntry(
1206        NetLog::TYPE_BAD_PROXY_LIST_REPORTED,
1207        base::Bind(&NetLogBadProxyListCallback, &new_retry_info));
1208  }
1209}
1210
1211void ProxyService::CancelPacRequest(PacRequest* req) {
1212  DCHECK(CalledOnValidThread());
1213  DCHECK(req);
1214  req->Cancel();
1215  RemovePendingRequest(req);
1216}
1217
1218LoadState ProxyService::GetLoadState(const PacRequest* req) const {
1219  CHECK(req);
1220  if (current_state_ == STATE_WAITING_FOR_INIT_PROXY_RESOLVER)
1221    return init_proxy_resolver_->GetLoadState();
1222  return req->GetLoadState();
1223}
1224
1225bool ProxyService::ContainsPendingRequest(PacRequest* req) {
1226  PendingRequests::iterator it = std::find(
1227      pending_requests_.begin(), pending_requests_.end(), req);
1228  return pending_requests_.end() != it;
1229}
1230
1231void ProxyService::RemovePendingRequest(PacRequest* req) {
1232  DCHECK(ContainsPendingRequest(req));
1233  PendingRequests::iterator it = std::find(
1234      pending_requests_.begin(), pending_requests_.end(), req);
1235  pending_requests_.erase(it);
1236}
1237
1238int ProxyService::DidFinishResolvingProxy(ProxyInfo* result,
1239                                          int result_code,
1240                                          const BoundNetLog& net_log) {
1241  // Log the result of the proxy resolution.
1242  if (result_code == OK) {
1243    // When logging all events is enabled, dump the proxy list.
1244    if (net_log.IsLoggingAllEvents()) {
1245      net_log.AddEvent(
1246          NetLog::TYPE_PROXY_SERVICE_RESOLVED_PROXY_LIST,
1247          base::Bind(&NetLogFinishedResolvingProxyCallback, result));
1248    }
1249    result->DeprioritizeBadProxies(proxy_retry_info_);
1250  } else {
1251    net_log.AddEventWithNetErrorCode(
1252        NetLog::TYPE_PROXY_SERVICE_RESOLVED_PROXY_LIST, result_code);
1253
1254    if (!config_.pac_mandatory()) {
1255      // Fall-back to direct when the proxy resolver fails. This corresponds
1256      // with a javascript runtime error in the PAC script.
1257      //
1258      // This implicit fall-back to direct matches Firefox 3.5 and
1259      // Internet Explorer 8. For more information, see:
1260      //
1261      // http://www.chromium.org/developers/design-documents/proxy-settings-fallback
1262      result->UseDirect();
1263      result_code = OK;
1264    } else {
1265      result_code = ERR_MANDATORY_PROXY_CONFIGURATION_FAILED;
1266    }
1267  }
1268
1269  net_log.EndEvent(NetLog::TYPE_PROXY_SERVICE);
1270  return result_code;
1271}
1272
1273void ProxyService::SetProxyScriptFetchers(
1274    ProxyScriptFetcher* proxy_script_fetcher,
1275    DhcpProxyScriptFetcher* dhcp_proxy_script_fetcher) {
1276  DCHECK(CalledOnValidThread());
1277  State previous_state = ResetProxyConfig(false);
1278  proxy_script_fetcher_.reset(proxy_script_fetcher);
1279  dhcp_proxy_script_fetcher_.reset(dhcp_proxy_script_fetcher);
1280  if (previous_state != STATE_NONE)
1281    ApplyProxyConfigIfAvailable();
1282}
1283
1284ProxyScriptFetcher* ProxyService::GetProxyScriptFetcher() const {
1285  DCHECK(CalledOnValidThread());
1286  return proxy_script_fetcher_.get();
1287}
1288
1289ProxyService::State ProxyService::ResetProxyConfig(bool reset_fetched_config) {
1290  DCHECK(CalledOnValidThread());
1291  State previous_state = current_state_;
1292
1293  permanent_error_ = OK;
1294  proxy_retry_info_.clear();
1295  script_poller_.reset();
1296  init_proxy_resolver_.reset();
1297  SuspendAllPendingRequests();
1298  config_ = ProxyConfig();
1299  if (reset_fetched_config)
1300    fetched_config_ = ProxyConfig();
1301  current_state_ = STATE_NONE;
1302
1303  return previous_state;
1304}
1305
1306void ProxyService::ResetConfigService(
1307    ProxyConfigService* new_proxy_config_service) {
1308  DCHECK(CalledOnValidThread());
1309  State previous_state = ResetProxyConfig(true);
1310
1311  // Release the old configuration service.
1312  if (config_service_.get())
1313    config_service_->RemoveObserver(this);
1314
1315  // Set the new configuration service.
1316  config_service_.reset(new_proxy_config_service);
1317  config_service_->AddObserver(this);
1318
1319  if (previous_state != STATE_NONE)
1320    ApplyProxyConfigIfAvailable();
1321}
1322
1323void ProxyService::PurgeMemory() {
1324  DCHECK(CalledOnValidThread());
1325  if (resolver_.get())
1326    resolver_->PurgeMemory();
1327}
1328
1329void ProxyService::ForceReloadProxyConfig() {
1330  DCHECK(CalledOnValidThread());
1331  ResetProxyConfig(false);
1332  ApplyProxyConfigIfAvailable();
1333}
1334
1335// static
1336ProxyConfigService* ProxyService::CreateSystemProxyConfigService(
1337    base::SingleThreadTaskRunner* io_thread_task_runner,
1338    base::MessageLoop* file_loop) {
1339#if defined(OS_WIN)
1340  return new ProxyConfigServiceWin();
1341#elif defined(OS_IOS)
1342  return new ProxyConfigServiceIOS();
1343#elif defined(OS_MACOSX)
1344  return new ProxyConfigServiceMac(io_thread_task_runner);
1345#elif defined(OS_CHROMEOS)
1346  LOG(ERROR) << "ProxyConfigService for ChromeOS should be created in "
1347             << "profile_io_data.cc::CreateProxyConfigService and this should "
1348             << "be used only for examples.";
1349  return new UnsetProxyConfigService;
1350#elif defined(OS_LINUX)
1351  ProxyConfigServiceLinux* linux_config_service =
1352      new ProxyConfigServiceLinux();
1353
1354  // Assume we got called on the thread that runs the default glib
1355  // main loop, so the current thread is where we should be running
1356  // gconf calls from.
1357  scoped_refptr<base::SingleThreadTaskRunner> glib_thread_task_runner =
1358      base::ThreadTaskRunnerHandle::Get();
1359
1360  // The file loop should be a MessageLoopForIO on Linux.
1361  DCHECK_EQ(base::MessageLoop::TYPE_IO, file_loop->type());
1362
1363  // Synchronously fetch the current proxy config (since we are
1364  // running on glib_default_loop). Additionally register for
1365  // notifications (delivered in either |glib_default_loop| or
1366  // |file_loop|) to keep us updated when the proxy config changes.
1367  linux_config_service->SetupAndFetchInitialConfig(
1368      glib_thread_task_runner.get(),
1369      io_thread_task_runner,
1370      static_cast<base::MessageLoopForIO*>(file_loop));
1371
1372  return linux_config_service;
1373#elif defined(OS_ANDROID)
1374  return new ProxyConfigServiceAndroid(
1375      io_thread_task_runner,
1376      base::MessageLoop::current()->message_loop_proxy());
1377#else
1378  LOG(WARNING) << "Failed to choose a system proxy settings fetcher "
1379                  "for this platform.";
1380  return new ProxyConfigServiceDirect();
1381#endif
1382}
1383
1384// static
1385const ProxyService::PacPollPolicy* ProxyService::set_pac_script_poll_policy(
1386    const PacPollPolicy* policy) {
1387  return ProxyScriptDeciderPoller::set_policy(policy);
1388}
1389
1390// static
1391scoped_ptr<ProxyService::PacPollPolicy>
1392  ProxyService::CreateDefaultPacPollPolicy() {
1393  return scoped_ptr<PacPollPolicy>(new DefaultPollPolicy());
1394}
1395
1396void ProxyService::OnProxyConfigChanged(
1397    const ProxyConfig& config,
1398    ProxyConfigService::ConfigAvailability availability) {
1399  // Retrieve the current proxy configuration from the ProxyConfigService.
1400  // If a configuration is not available yet, we will get called back later
1401  // by our ProxyConfigService::Observer once it changes.
1402  ProxyConfig effective_config;
1403  switch (availability) {
1404    case ProxyConfigService::CONFIG_PENDING:
1405      // ProxyConfigService implementors should never pass CONFIG_PENDING.
1406      NOTREACHED() << "Proxy config change with CONFIG_PENDING availability!";
1407      return;
1408    case ProxyConfigService::CONFIG_VALID:
1409      effective_config = config;
1410      break;
1411    case ProxyConfigService::CONFIG_UNSET:
1412      effective_config = ProxyConfig::CreateDirect();
1413      break;
1414  }
1415
1416  // Emit the proxy settings change to the NetLog stream.
1417  if (net_log_) {
1418    net_log_->AddGlobalEntry(
1419        net::NetLog::TYPE_PROXY_CONFIG_CHANGED,
1420        base::Bind(&NetLogProxyConfigChangedCallback,
1421                   &fetched_config_, &effective_config));
1422  }
1423
1424  // Set the new configuration as the most recently fetched one.
1425  fetched_config_ = effective_config;
1426  fetched_config_.set_id(1);  // Needed for a later DCHECK of is_valid().
1427
1428  InitializeUsingLastFetchedConfig();
1429}
1430
1431void ProxyService::InitializeUsingLastFetchedConfig() {
1432  ResetProxyConfig(false);
1433
1434  DCHECK(fetched_config_.is_valid());
1435
1436  // Increment the ID to reflect that the config has changed.
1437  fetched_config_.set_id(next_config_id_++);
1438
1439  if (!fetched_config_.HasAutomaticSettings()) {
1440    config_ = fetched_config_;
1441    SetReady();
1442    return;
1443  }
1444
1445  // Start downloading + testing the PAC scripts for this new configuration.
1446  current_state_ = STATE_WAITING_FOR_INIT_PROXY_RESOLVER;
1447
1448  // If we changed networks recently, we should delay running proxy auto-config.
1449  TimeDelta wait_delay =
1450      stall_proxy_autoconfig_until_ - TimeTicks::Now();
1451
1452  init_proxy_resolver_.reset(new InitProxyResolver());
1453  int rv = init_proxy_resolver_->Start(
1454      resolver_.get(),
1455      proxy_script_fetcher_.get(),
1456      dhcp_proxy_script_fetcher_.get(),
1457      net_log_,
1458      fetched_config_,
1459      wait_delay,
1460      base::Bind(&ProxyService::OnInitProxyResolverComplete,
1461                 base::Unretained(this)));
1462
1463  if (rv != ERR_IO_PENDING)
1464    OnInitProxyResolverComplete(rv);
1465}
1466
1467void ProxyService::InitializeUsingDecidedConfig(
1468    int decider_result,
1469    ProxyResolverScriptData* script_data,
1470    const ProxyConfig& effective_config) {
1471  DCHECK(fetched_config_.is_valid());
1472  DCHECK(fetched_config_.HasAutomaticSettings());
1473
1474  ResetProxyConfig(false);
1475
1476  current_state_ = STATE_WAITING_FOR_INIT_PROXY_RESOLVER;
1477
1478  init_proxy_resolver_.reset(new InitProxyResolver());
1479  int rv = init_proxy_resolver_->StartSkipDecider(
1480      resolver_.get(),
1481      effective_config,
1482      decider_result,
1483      script_data,
1484      base::Bind(&ProxyService::OnInitProxyResolverComplete,
1485                 base::Unretained(this)));
1486
1487  if (rv != ERR_IO_PENDING)
1488    OnInitProxyResolverComplete(rv);
1489}
1490
1491void ProxyService::OnIPAddressChanged() {
1492  // See the comment block by |kDelayAfterNetworkChangesMs| for info.
1493  stall_proxy_autoconfig_until_ =
1494      TimeTicks::Now() + stall_proxy_auto_config_delay_;
1495
1496  State previous_state = ResetProxyConfig(false);
1497  if (previous_state != STATE_NONE)
1498    ApplyProxyConfigIfAvailable();
1499}
1500
1501void ProxyService::OnDNSChanged() {
1502  OnIPAddressChanged();
1503}
1504
1505SyncProxyServiceHelper::SyncProxyServiceHelper(
1506    base::MessageLoop* io_message_loop,
1507    ProxyService* proxy_service)
1508    : io_message_loop_(io_message_loop),
1509      proxy_service_(proxy_service),
1510      event_(false, false),
1511      callback_(base::Bind(&SyncProxyServiceHelper::OnCompletion,
1512                           base::Unretained(this))) {
1513  DCHECK(io_message_loop_ != base::MessageLoop::current());
1514}
1515
1516int SyncProxyServiceHelper::ResolveProxy(const GURL& url,
1517                                         ProxyInfo* proxy_info,
1518                                         const BoundNetLog& net_log) {
1519  DCHECK(io_message_loop_ != base::MessageLoop::current());
1520
1521  io_message_loop_->PostTask(
1522      FROM_HERE,
1523      base::Bind(&SyncProxyServiceHelper::StartAsyncResolve, this, url,
1524                 net_log));
1525
1526  event_.Wait();
1527
1528  if (result_ == net::OK) {
1529    *proxy_info = proxy_info_;
1530  }
1531  return result_;
1532}
1533
1534int SyncProxyServiceHelper::ReconsiderProxyAfterError(
1535    const GURL& url, ProxyInfo* proxy_info, const BoundNetLog& net_log) {
1536  DCHECK(io_message_loop_ != base::MessageLoop::current());
1537
1538  io_message_loop_->PostTask(
1539      FROM_HERE,
1540      base::Bind(&SyncProxyServiceHelper::StartAsyncReconsider, this, url,
1541                 net_log));
1542
1543  event_.Wait();
1544
1545  if (result_ == net::OK) {
1546    *proxy_info = proxy_info_;
1547  }
1548  return result_;
1549}
1550
1551SyncProxyServiceHelper::~SyncProxyServiceHelper() {}
1552
1553void SyncProxyServiceHelper::StartAsyncResolve(const GURL& url,
1554                                               const BoundNetLog& net_log) {
1555  result_ = proxy_service_->ResolveProxy(
1556      url, &proxy_info_, callback_, NULL, net_log);
1557  if (result_ != net::ERR_IO_PENDING) {
1558    OnCompletion(result_);
1559  }
1560}
1561
1562void SyncProxyServiceHelper::StartAsyncReconsider(const GURL& url,
1563                                                  const BoundNetLog& net_log) {
1564  result_ = proxy_service_->ReconsiderProxyAfterError(
1565      url, &proxy_info_, callback_, NULL, net_log);
1566  if (result_ != net::ERR_IO_PENDING) {
1567    OnCompletion(result_);
1568  }
1569}
1570
1571void SyncProxyServiceHelper::OnCompletion(int rv) {
1572  result_ = rv;
1573  event_.Signal();
1574}
1575
1576}  // namespace net
1577