proxy_service.cc revision c2e0dbddbe15c98d52c4786dac06cb8952a8ae6d
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_proxy.h"
16#include "base/string_util.h"
17#include "base/thread_task_runner_handle.h"
18#include "base/values.h"
19#include "googleurl/src/gurl.h"
20#include "net/base/completion_callback.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
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_);
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    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      MessageLoop::current()->PostTask(
642        FROM_HERE,
643        base::Bind(
644            &ProxyScriptDeciderPoller::NotifyProxyServiceOfChange,
645            weak_factory_.GetWeakPtr(),
646            result,
647            make_scoped_refptr(decider_->script_data()),
648            decider_->effective_config()));
649      return;
650    }
651
652    decider_.reset();
653
654    // Decide when the next poll should take place, and possibly start the
655    // next timer.
656    next_poll_mode_ = poll_policy()->GetNextDelay(
657        last_error_, next_poll_delay_, &next_poll_delay_);
658    TryToStartNextPoll(false);
659  }
660
661  bool HasScriptDataChanged(int result, ProxyResolverScriptData* script_data) {
662    if (result != last_error_) {
663      // Something changed -- it was failing before and now it succeeded, or
664      // conversely it succeeded before and now it failed. Or it failed in
665      // both cases, however the specific failure error codes differ.
666      return true;
667    }
668
669    if (result != OK) {
670      // If it failed last time and failed again with the same error code this
671      // time, then nothing has actually changed.
672      return false;
673    }
674
675    // Otherwise if it succeeded both this time and last time, we need to look
676    // closer and see if we ended up downloading different content for the PAC
677    // script.
678    return !script_data->Equals(last_script_data_);
679  }
680
681  void NotifyProxyServiceOfChange(
682      int result,
683      const scoped_refptr<ProxyResolverScriptData>& script_data,
684      const ProxyConfig& effective_config) {
685    // Note that |this| may be deleted after calling into the ProxyService.
686    change_callback_.Run(result, script_data, effective_config);
687  }
688
689  base::WeakPtrFactory<ProxyScriptDeciderPoller> weak_factory_;
690
691  ChangeCallback change_callback_;
692  ProxyConfig config_;
693  bool proxy_resolver_expects_pac_bytes_;
694  ProxyScriptFetcher* proxy_script_fetcher_;
695  DhcpProxyScriptFetcher* dhcp_proxy_script_fetcher_;
696
697  int last_error_;
698  scoped_refptr<ProxyResolverScriptData> last_script_data_;
699
700  scoped_ptr<ProxyScriptDecider> decider_;
701  TimeDelta next_poll_delay_;
702  PacPollPolicy::Mode next_poll_mode_;
703
704  TimeTicks last_poll_time_;
705
706  // Polling policy injected by unit-tests. Otherwise this is NULL and the
707  // default policy will be used.
708  static const PacPollPolicy* poll_policy_;
709
710  const DefaultPollPolicy default_poll_policy_;
711
712  DISALLOW_COPY_AND_ASSIGN(ProxyScriptDeciderPoller);
713};
714
715// static
716const ProxyService::PacPollPolicy*
717    ProxyService::ProxyScriptDeciderPoller::poll_policy_ = NULL;
718
719// ProxyService::PacRequest ---------------------------------------------------
720
721class ProxyService::PacRequest
722    : public base::RefCounted<ProxyService::PacRequest> {
723 public:
724    PacRequest(ProxyService* service,
725               const GURL& url,
726               ProxyInfo* results,
727               const net::CompletionCallback& user_callback,
728               const BoundNetLog& net_log)
729      : service_(service),
730        user_callback_(user_callback),
731        results_(results),
732        url_(url),
733        resolve_job_(NULL),
734        config_id_(ProxyConfig::kInvalidConfigID),
735        config_source_(PROXY_CONFIG_SOURCE_UNKNOWN),
736        net_log_(net_log) {
737    DCHECK(!user_callback.is_null());
738  }
739
740  // Starts the resolve proxy request.
741  int Start() {
742    DCHECK(!was_cancelled());
743    DCHECK(!is_started());
744
745    DCHECK(service_->config_.is_valid());
746
747    config_id_ = service_->config_.id();
748    config_source_ = service_->config_.source();
749    proxy_resolve_start_time_ = TimeTicks::Now();
750
751    return resolver()->GetProxyForURL(
752        url_, results_,
753        base::Bind(&PacRequest::QueryComplete, base::Unretained(this)),
754        &resolve_job_, net_log_);
755  }
756
757  bool is_started() const {
758    // Note that !! casts to bool. (VS gives a warning otherwise).
759    return !!resolve_job_;
760  }
761
762  void StartAndCompleteCheckingForSynchronous() {
763    int rv = service_->TryToCompleteSynchronously(url_, results_);
764    if (rv == ERR_IO_PENDING)
765      rv = Start();
766    if (rv != ERR_IO_PENDING)
767      QueryComplete(rv);
768  }
769
770  void CancelResolveJob() {
771    DCHECK(is_started());
772    // The request may already be running in the resolver.
773    resolver()->CancelRequest(resolve_job_);
774    resolve_job_ = NULL;
775    DCHECK(!is_started());
776  }
777
778  void Cancel() {
779    net_log_.AddEvent(NetLog::TYPE_CANCELLED);
780
781    if (is_started())
782      CancelResolveJob();
783
784    // Mark as cancelled, to prevent accessing this again later.
785    service_ = NULL;
786    user_callback_.Reset();
787    results_ = NULL;
788
789    net_log_.EndEvent(NetLog::TYPE_PROXY_SERVICE);
790  }
791
792  // Returns true if Cancel() has been called.
793  bool was_cancelled() const {
794    return user_callback_.is_null();
795  }
796
797  // Helper to call after ProxyResolver completion (both synchronous and
798  // asynchronous). Fixes up the result that is to be returned to user.
799  int QueryDidComplete(int result_code) {
800    DCHECK(!was_cancelled());
801
802    // Note that DidFinishResolvingProxy might modify |results_|.
803    int rv = service_->DidFinishResolvingProxy(results_, result_code, net_log_);
804
805    // Make a note in the results which configuration was in use at the
806    // time of the resolve.
807    results_->config_id_ = config_id_;
808    results_->config_source_ = config_source_;
809    results_->did_use_pac_script_ = true;
810    results_->proxy_resolve_start_time_ = proxy_resolve_start_time_;
811    results_->proxy_resolve_end_time_ = TimeTicks::Now();
812
813    // Reset the state associated with in-progress-resolve.
814    resolve_job_ = NULL;
815    config_id_ = ProxyConfig::kInvalidConfigID;
816    config_source_ = PROXY_CONFIG_SOURCE_UNKNOWN;
817
818    return rv;
819  }
820
821  BoundNetLog* net_log() { return &net_log_; }
822
823  LoadState GetLoadState() const {
824    if (is_started())
825      return resolver()->GetLoadState(resolve_job_);
826    return LOAD_STATE_RESOLVING_PROXY_FOR_URL;
827  }
828
829 private:
830  friend class base::RefCounted<ProxyService::PacRequest>;
831
832  ~PacRequest() {}
833
834  // Callback for when the ProxyResolver request has completed.
835  void QueryComplete(int result_code) {
836    result_code = QueryDidComplete(result_code);
837
838    // Remove this completed PacRequest from the service's pending list.
839    /// (which will probably cause deletion of |this|).
840    if (!user_callback_.is_null()) {
841      net::CompletionCallback callback = user_callback_;
842      service_->RemovePendingRequest(this);
843      callback.Run(result_code);
844    }
845  }
846
847  ProxyResolver* resolver() const { return service_->resolver_.get(); }
848
849  // Note that we don't hold a reference to the ProxyService. Outstanding
850  // requests are cancelled during ~ProxyService, so this is guaranteed
851  // to be valid throughout our lifetime.
852  ProxyService* service_;
853  net::CompletionCallback user_callback_;
854  ProxyInfo* results_;
855  GURL url_;
856  ProxyResolver::RequestHandle resolve_job_;
857  ProxyConfig::ID config_id_;  // The config id when the resolve was started.
858  ProxyConfigSource config_source_;  // The source of proxy settings.
859  BoundNetLog net_log_;
860  // Time when the PAC is started.  Cached here since resetting ProxyInfo also
861  // clears the proxy times.
862  TimeTicks proxy_resolve_start_time_;
863};
864
865// ProxyService ---------------------------------------------------------------
866
867ProxyService::ProxyService(ProxyConfigService* config_service,
868                           ProxyResolver* resolver,
869                           NetLog* net_log)
870    : resolver_(resolver),
871      next_config_id_(1),
872      current_state_(STATE_NONE) ,
873      net_log_(net_log),
874      stall_proxy_auto_config_delay_(TimeDelta::FromMilliseconds(
875          kDelayAfterNetworkChangesMs)) {
876  NetworkChangeNotifier::AddIPAddressObserver(this);
877  NetworkChangeNotifier::AddDNSObserver(this);
878  ResetConfigService(config_service);
879}
880
881// static
882ProxyService* ProxyService::CreateUsingSystemProxyResolver(
883    ProxyConfigService* proxy_config_service,
884    size_t num_pac_threads,
885    NetLog* net_log) {
886  DCHECK(proxy_config_service);
887
888  if (!ProxyResolverFactoryForSystem::IsSupported()) {
889    LOG(WARNING) << "PAC support disabled because there is no "
890                    "system implementation";
891    return CreateWithoutProxyResolver(proxy_config_service, net_log);
892  }
893
894  if (num_pac_threads == 0)
895    num_pac_threads = kDefaultNumPacThreads;
896
897  ProxyResolver* proxy_resolver = new MultiThreadedProxyResolver(
898      new ProxyResolverFactoryForSystem(), num_pac_threads);
899
900  return new ProxyService(proxy_config_service, proxy_resolver, net_log);
901}
902
903// static
904ProxyService* ProxyService::CreateWithoutProxyResolver(
905    ProxyConfigService* proxy_config_service,
906    NetLog* net_log) {
907  return new ProxyService(proxy_config_service,
908                          new ProxyResolverNull(),
909                          net_log);
910}
911
912// static
913ProxyService* ProxyService::CreateFixed(const ProxyConfig& pc) {
914  // TODO(eroman): This isn't quite right, won't work if |pc| specifies
915  //               a PAC script.
916  return CreateUsingSystemProxyResolver(new ProxyConfigServiceFixed(pc),
917                                        0, NULL);
918}
919
920// static
921ProxyService* ProxyService::CreateFixed(const std::string& proxy) {
922  net::ProxyConfig proxy_config;
923  proxy_config.proxy_rules().ParseFromString(proxy);
924  return ProxyService::CreateFixed(proxy_config);
925}
926
927// static
928ProxyService* ProxyService::CreateDirect() {
929  return CreateDirectWithNetLog(NULL);
930}
931
932ProxyService* ProxyService::CreateDirectWithNetLog(NetLog* net_log) {
933  // Use direct connections.
934  return new ProxyService(new ProxyConfigServiceDirect, new ProxyResolverNull,
935                          net_log);
936}
937
938// static
939ProxyService* ProxyService::CreateFixedFromPacResult(
940    const std::string& pac_string) {
941
942  // We need the settings to contain an "automatic" setting, otherwise the
943  // ProxyResolver dependency we give it will never be used.
944  scoped_ptr<ProxyConfigService> proxy_config_service(
945      new ProxyConfigServiceFixed(ProxyConfig::CreateAutoDetect()));
946
947  scoped_ptr<ProxyResolver> proxy_resolver(
948      new ProxyResolverFromPacString(pac_string));
949
950  return new ProxyService(proxy_config_service.release(),
951                          proxy_resolver.release(),
952                          NULL);
953}
954
955int ProxyService::ResolveProxy(const GURL& raw_url,
956                               ProxyInfo* result,
957                               const net::CompletionCallback& callback,
958                               PacRequest** pac_request,
959                               const BoundNetLog& net_log) {
960  DCHECK(CalledOnValidThread());
961  DCHECK(!callback.is_null());
962
963  net_log.BeginEvent(NetLog::TYPE_PROXY_SERVICE);
964
965  // Notify our polling-based dependencies that a resolve is taking place.
966  // This way they can schedule their polls in response to network activity.
967  config_service_->OnLazyPoll();
968  if (script_poller_.get())
969     script_poller_->OnLazyPoll();
970
971  if (current_state_ == STATE_NONE)
972    ApplyProxyConfigIfAvailable();
973
974  // Strip away any reference fragments and the username/password, as they
975  // are not relevant to proxy resolution.
976  GURL url = SimplifyUrlForRequest(raw_url);
977
978  // Check if the request can be completed right away. (This is the case when
979  // using a direct connection for example).
980  int rv = TryToCompleteSynchronously(url, result);
981  if (rv != ERR_IO_PENDING)
982    return DidFinishResolvingProxy(result, rv, net_log);
983
984  scoped_refptr<PacRequest> req(
985      new PacRequest(this, url, result, callback, net_log));
986
987  if (current_state_ == STATE_READY) {
988    // Start the resolve request.
989    rv = req->Start();
990    if (rv != ERR_IO_PENDING)
991      return req->QueryDidComplete(rv);
992  } else {
993    req->net_log()->BeginEvent(NetLog::TYPE_PROXY_SERVICE_WAITING_FOR_INIT_PAC);
994  }
995
996  DCHECK_EQ(ERR_IO_PENDING, rv);
997  DCHECK(!ContainsPendingRequest(req));
998  pending_requests_.push_back(req);
999
1000  // Completion will be notified through |callback|, unless the caller cancels
1001  // the request using |pac_request|.
1002  if (pac_request)
1003    *pac_request = req.get();
1004  return rv;  // ERR_IO_PENDING
1005}
1006
1007int ProxyService::TryToCompleteSynchronously(const GURL& url,
1008                                             ProxyInfo* result) {
1009  DCHECK_NE(STATE_NONE, current_state_);
1010
1011  if (current_state_ != STATE_READY)
1012    return ERR_IO_PENDING;  // Still initializing.
1013
1014  DCHECK_NE(config_.id(), ProxyConfig::kInvalidConfigID);
1015
1016  // If it was impossible to fetch or parse the PAC script, we cannot complete
1017  // the request here and bail out.
1018  if (permanent_error_ != OK)
1019    return permanent_error_;
1020
1021  if (config_.HasAutomaticSettings())
1022    return ERR_IO_PENDING;  // Must submit the request to the proxy resolver.
1023
1024  // Use the manual proxy settings.
1025  config_.proxy_rules().Apply(url, result);
1026  result->config_source_ = config_.source();
1027  result->config_id_ = config_.id();
1028  return OK;
1029}
1030
1031ProxyService::~ProxyService() {
1032  NetworkChangeNotifier::RemoveIPAddressObserver(this);
1033  NetworkChangeNotifier::RemoveDNSObserver(this);
1034  config_service_->RemoveObserver(this);
1035
1036  // Cancel any inprogress requests.
1037  for (PendingRequests::iterator it = pending_requests_.begin();
1038       it != pending_requests_.end();
1039       ++it) {
1040    (*it)->Cancel();
1041  }
1042}
1043
1044void ProxyService::SuspendAllPendingRequests() {
1045  for (PendingRequests::iterator it = pending_requests_.begin();
1046       it != pending_requests_.end();
1047       ++it) {
1048    PacRequest* req = it->get();
1049    if (req->is_started()) {
1050      req->CancelResolveJob();
1051
1052      req->net_log()->BeginEvent(
1053          NetLog::TYPE_PROXY_SERVICE_WAITING_FOR_INIT_PAC);
1054    }
1055  }
1056}
1057
1058void ProxyService::SetReady() {
1059  DCHECK(!init_proxy_resolver_.get());
1060  current_state_ = STATE_READY;
1061
1062  // Make a copy in case |this| is deleted during the synchronous completion
1063  // of one of the requests. If |this| is deleted then all of the PacRequest
1064  // instances will be Cancel()-ed.
1065  PendingRequests pending_copy = pending_requests_;
1066
1067  for (PendingRequests::iterator it = pending_copy.begin();
1068       it != pending_copy.end();
1069       ++it) {
1070    PacRequest* req = it->get();
1071    if (!req->is_started() && !req->was_cancelled()) {
1072      req->net_log()->EndEvent(NetLog::TYPE_PROXY_SERVICE_WAITING_FOR_INIT_PAC);
1073
1074      // Note that we re-check for synchronous completion, in case we are
1075      // no longer using a ProxyResolver (can happen if we fell-back to manual).
1076      req->StartAndCompleteCheckingForSynchronous();
1077    }
1078  }
1079}
1080
1081void ProxyService::ApplyProxyConfigIfAvailable() {
1082  DCHECK_EQ(STATE_NONE, current_state_);
1083
1084  config_service_->OnLazyPoll();
1085
1086  // If we have already fetched the configuration, start applying it.
1087  if (fetched_config_.is_valid()) {
1088    InitializeUsingLastFetchedConfig();
1089    return;
1090  }
1091
1092  // Otherwise we need to first fetch the configuration.
1093  current_state_ = STATE_WAITING_FOR_PROXY_CONFIG;
1094
1095  // Retrieve the current proxy configuration from the ProxyConfigService.
1096  // If a configuration is not available yet, we will get called back later
1097  // by our ProxyConfigService::Observer once it changes.
1098  ProxyConfig config;
1099  ProxyConfigService::ConfigAvailability availability =
1100      config_service_->GetLatestProxyConfig(&config);
1101  if (availability != ProxyConfigService::CONFIG_PENDING)
1102    OnProxyConfigChanged(config, availability);
1103}
1104
1105void ProxyService::OnInitProxyResolverComplete(int result) {
1106  DCHECK_EQ(STATE_WAITING_FOR_INIT_PROXY_RESOLVER, current_state_);
1107  DCHECK(init_proxy_resolver_.get());
1108  DCHECK(fetched_config_.HasAutomaticSettings());
1109  config_ = init_proxy_resolver_->effective_config();
1110
1111  // At this point we have decided which proxy settings to use (i.e. which PAC
1112  // script if any). We start up a background poller to periodically revisit
1113  // this decision. If the contents of the PAC script change, or if the
1114  // result of proxy auto-discovery changes, this poller will notice it and
1115  // will trigger a re-initialization using the newly discovered PAC.
1116  script_poller_.reset(new ProxyScriptDeciderPoller(
1117      base::Bind(&ProxyService::InitializeUsingDecidedConfig,
1118                 base::Unretained(this)),
1119      fetched_config_,
1120      resolver_->expects_pac_bytes(),
1121      proxy_script_fetcher_.get(),
1122      dhcp_proxy_script_fetcher_.get(),
1123      result,
1124      init_proxy_resolver_->script_data(),
1125      NULL));
1126
1127  init_proxy_resolver_.reset();
1128
1129  if (result != OK) {
1130    if (fetched_config_.pac_mandatory()) {
1131      VLOG(1) << "Failed configuring with mandatory PAC script, blocking all "
1132                 "traffic.";
1133      config_ = fetched_config_;
1134      result = ERR_MANDATORY_PROXY_CONFIGURATION_FAILED;
1135    } else {
1136      VLOG(1) << "Failed configuring with PAC script, falling-back to manual "
1137                 "proxy servers.";
1138      config_ = fetched_config_;
1139      config_.ClearAutomaticSettings();
1140      result = OK;
1141    }
1142  }
1143  permanent_error_ = result;
1144
1145  // TODO(eroman): Make this ID unique in the case where configuration changed
1146  //               due to ProxyScriptDeciderPoller.
1147  config_.set_id(fetched_config_.id());
1148  config_.set_source(fetched_config_.source());
1149
1150  // Resume any requests which we had to defer until the PAC script was
1151  // downloaded.
1152  SetReady();
1153}
1154
1155int ProxyService::ReconsiderProxyAfterError(const GURL& url,
1156                                            ProxyInfo* result,
1157                                            const CompletionCallback& callback,
1158                                            PacRequest** pac_request,
1159                                            const BoundNetLog& net_log) {
1160  DCHECK(CalledOnValidThread());
1161
1162  // Check to see if we have a new config since ResolveProxy was called.  We
1163  // want to re-run ResolveProxy in two cases: 1) we have a new config, or 2) a
1164  // direct connection failed and we never tried the current config.
1165
1166  bool re_resolve = result->config_id_ != config_.id();
1167
1168  if (re_resolve) {
1169    // If we have a new config or the config was never tried, we delete the
1170    // list of bad proxies and we try again.
1171    proxy_retry_info_.clear();
1172    return ResolveProxy(url, result, callback, pac_request, net_log);
1173  }
1174
1175  // We don't have new proxy settings to try, try to fallback to the next proxy
1176  // in the list.
1177  bool did_fallback = result->Fallback(net_log);
1178
1179  // Return synchronous failure if there is nothing left to fall-back to.
1180  // TODO(eroman): This is a yucky API, clean it up.
1181  return did_fallback ? OK : ERR_FAILED;
1182}
1183
1184bool ProxyService::MarkProxyAsBad(const ProxyInfo& result,
1185                                  const BoundNetLog& net_log) {
1186  result.proxy_list_.UpdateRetryInfoOnFallback(&proxy_retry_info_, net_log);
1187  return result.proxy_list_.HasUntriedProxies(proxy_retry_info_);
1188}
1189
1190void ProxyService::ReportSuccess(const ProxyInfo& result) {
1191  DCHECK(CalledOnValidThread());
1192
1193  const ProxyRetryInfoMap& new_retry_info = result.proxy_retry_info();
1194  if (new_retry_info.empty())
1195    return;
1196
1197  for (ProxyRetryInfoMap::const_iterator iter = new_retry_info.begin();
1198       iter != new_retry_info.end(); ++iter) {
1199    ProxyRetryInfoMap::iterator existing = proxy_retry_info_.find(iter->first);
1200    if (existing == proxy_retry_info_.end())
1201      proxy_retry_info_[iter->first] = iter->second;
1202    else if (existing->second.bad_until < iter->second.bad_until)
1203      existing->second.bad_until = iter->second.bad_until;
1204  }
1205  if (net_log_) {
1206    net_log_->AddGlobalEntry(
1207        NetLog::TYPE_BAD_PROXY_LIST_REPORTED,
1208        base::Bind(&NetLogBadProxyListCallback, &new_retry_info));
1209  }
1210}
1211
1212void ProxyService::CancelPacRequest(PacRequest* req) {
1213  DCHECK(CalledOnValidThread());
1214  DCHECK(req);
1215  req->Cancel();
1216  RemovePendingRequest(req);
1217}
1218
1219LoadState ProxyService::GetLoadState(const PacRequest* req) const {
1220  CHECK(req);
1221  if (current_state_ == STATE_WAITING_FOR_INIT_PROXY_RESOLVER)
1222    return init_proxy_resolver_->GetLoadState();
1223  return req->GetLoadState();
1224}
1225
1226bool ProxyService::ContainsPendingRequest(PacRequest* req) {
1227  PendingRequests::iterator it = std::find(
1228      pending_requests_.begin(), pending_requests_.end(), req);
1229  return pending_requests_.end() != it;
1230}
1231
1232void ProxyService::RemovePendingRequest(PacRequest* req) {
1233  DCHECK(ContainsPendingRequest(req));
1234  PendingRequests::iterator it = std::find(
1235      pending_requests_.begin(), pending_requests_.end(), req);
1236  pending_requests_.erase(it);
1237}
1238
1239int ProxyService::DidFinishResolvingProxy(ProxyInfo* result,
1240                                          int result_code,
1241                                          const BoundNetLog& net_log) {
1242  // Log the result of the proxy resolution.
1243  if (result_code == OK) {
1244    // When logging all events is enabled, dump the proxy list.
1245    if (net_log.IsLoggingAllEvents()) {
1246      net_log.AddEvent(
1247          NetLog::TYPE_PROXY_SERVICE_RESOLVED_PROXY_LIST,
1248          base::Bind(&NetLogFinishedResolvingProxyCallback, result));
1249    }
1250    result->DeprioritizeBadProxies(proxy_retry_info_);
1251  } else {
1252    net_log.AddEventWithNetErrorCode(
1253        NetLog::TYPE_PROXY_SERVICE_RESOLVED_PROXY_LIST, result_code);
1254
1255    if (!config_.pac_mandatory()) {
1256      // Fall-back to direct when the proxy resolver fails. This corresponds
1257      // with a javascript runtime error in the PAC script.
1258      //
1259      // This implicit fall-back to direct matches Firefox 3.5 and
1260      // Internet Explorer 8. For more information, see:
1261      //
1262      // http://www.chromium.org/developers/design-documents/proxy-settings-fallback
1263      result->UseDirect();
1264      result_code = OK;
1265    } else {
1266      result_code = ERR_MANDATORY_PROXY_CONFIGURATION_FAILED;
1267    }
1268  }
1269
1270  net_log.EndEvent(NetLog::TYPE_PROXY_SERVICE);
1271  return result_code;
1272}
1273
1274void ProxyService::SetProxyScriptFetchers(
1275    ProxyScriptFetcher* proxy_script_fetcher,
1276    DhcpProxyScriptFetcher* dhcp_proxy_script_fetcher) {
1277  DCHECK(CalledOnValidThread());
1278  State previous_state = ResetProxyConfig(false);
1279  proxy_script_fetcher_.reset(proxy_script_fetcher);
1280  dhcp_proxy_script_fetcher_.reset(dhcp_proxy_script_fetcher);
1281  if (previous_state != STATE_NONE)
1282    ApplyProxyConfigIfAvailable();
1283}
1284
1285ProxyScriptFetcher* ProxyService::GetProxyScriptFetcher() const {
1286  DCHECK(CalledOnValidThread());
1287  return proxy_script_fetcher_.get();
1288}
1289
1290ProxyService::State ProxyService::ResetProxyConfig(bool reset_fetched_config) {
1291  DCHECK(CalledOnValidThread());
1292  State previous_state = current_state_;
1293
1294  permanent_error_ = OK;
1295  proxy_retry_info_.clear();
1296  script_poller_.reset();
1297  init_proxy_resolver_.reset();
1298  SuspendAllPendingRequests();
1299  config_ = ProxyConfig();
1300  if (reset_fetched_config)
1301    fetched_config_ = ProxyConfig();
1302  current_state_ = STATE_NONE;
1303
1304  return previous_state;
1305}
1306
1307void ProxyService::ResetConfigService(
1308    ProxyConfigService* new_proxy_config_service) {
1309  DCHECK(CalledOnValidThread());
1310  State previous_state = ResetProxyConfig(true);
1311
1312  // Release the old configuration service.
1313  if (config_service_.get())
1314    config_service_->RemoveObserver(this);
1315
1316  // Set the new configuration service.
1317  config_service_.reset(new_proxy_config_service);
1318  config_service_->AddObserver(this);
1319
1320  if (previous_state != STATE_NONE)
1321    ApplyProxyConfigIfAvailable();
1322}
1323
1324void ProxyService::PurgeMemory() {
1325  DCHECK(CalledOnValidThread());
1326  if (resolver_.get())
1327    resolver_->PurgeMemory();
1328}
1329
1330void ProxyService::ForceReloadProxyConfig() {
1331  DCHECK(CalledOnValidThread());
1332  ResetProxyConfig(false);
1333  ApplyProxyConfigIfAvailable();
1334}
1335
1336// static
1337ProxyConfigService* ProxyService::CreateSystemProxyConfigService(
1338    base::SingleThreadTaskRunner* io_thread_task_runner,
1339    MessageLoop* file_loop) {
1340#if defined(OS_WIN)
1341  return new ProxyConfigServiceWin();
1342#elif defined(OS_IOS)
1343  return new ProxyConfigServiceIOS();
1344#elif defined(OS_MACOSX)
1345  return new ProxyConfigServiceMac(io_thread_task_runner);
1346#elif defined(OS_CHROMEOS)
1347  LOG(ERROR) << "ProxyConfigService for ChromeOS should be created in "
1348             << "profile_io_data.cc::CreateProxyConfigService and this should "
1349             << "be used only for examples.";
1350  return new UnsetProxyConfigService;
1351#elif defined(OS_LINUX)
1352  ProxyConfigServiceLinux* linux_config_service =
1353      new ProxyConfigServiceLinux();
1354
1355  // Assume we got called on the thread that runs the default glib
1356  // main loop, so the current thread is where we should be running
1357  // gconf calls from.
1358  scoped_refptr<base::SingleThreadTaskRunner> glib_thread_task_runner =
1359      base::ThreadTaskRunnerHandle::Get();
1360
1361  // The file loop should be a MessageLoopForIO on Linux.
1362  DCHECK_EQ(MessageLoop::TYPE_IO, file_loop->type());
1363
1364  // Synchronously fetch the current proxy config (since we are
1365  // running on glib_default_loop). Additionally register for
1366  // notifications (delivered in either |glib_default_loop| or
1367  // |file_loop|) to keep us updated when the proxy config changes.
1368  linux_config_service->SetupAndFetchInitialConfig(
1369      glib_thread_task_runner, io_thread_task_runner,
1370      static_cast<MessageLoopForIO*>(file_loop));
1371
1372  return linux_config_service;
1373#elif defined(OS_ANDROID)
1374  return new ProxyConfigServiceAndroid(
1375      io_thread_task_runner,
1376      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(MessageLoop* io_message_loop,
1506                                               ProxyService* proxy_service)
1507    : io_message_loop_(io_message_loop),
1508      proxy_service_(proxy_service),
1509      event_(false, false),
1510      callback_(base::Bind(&SyncProxyServiceHelper::OnCompletion,
1511                           base::Unretained(this))) {
1512  DCHECK(io_message_loop_ != MessageLoop::current());
1513}
1514
1515int SyncProxyServiceHelper::ResolveProxy(const GURL& url,
1516                                         ProxyInfo* proxy_info,
1517                                         const BoundNetLog& net_log) {
1518  DCHECK(io_message_loop_ != MessageLoop::current());
1519
1520  io_message_loop_->PostTask(
1521      FROM_HERE,
1522      base::Bind(&SyncProxyServiceHelper::StartAsyncResolve, this, url,
1523                 net_log));
1524
1525  event_.Wait();
1526
1527  if (result_ == net::OK) {
1528    *proxy_info = proxy_info_;
1529  }
1530  return result_;
1531}
1532
1533int SyncProxyServiceHelper::ReconsiderProxyAfterError(
1534    const GURL& url, ProxyInfo* proxy_info, const BoundNetLog& net_log) {
1535  DCHECK(io_message_loop_ != MessageLoop::current());
1536
1537  io_message_loop_->PostTask(
1538      FROM_HERE,
1539      base::Bind(&SyncProxyServiceHelper::StartAsyncReconsider, this, url,
1540                 net_log));
1541
1542  event_.Wait();
1543
1544  if (result_ == net::OK) {
1545    *proxy_info = proxy_info_;
1546  }
1547  return result_;
1548}
1549
1550SyncProxyServiceHelper::~SyncProxyServiceHelper() {}
1551
1552void SyncProxyServiceHelper::StartAsyncResolve(const GURL& url,
1553                                               const BoundNetLog& net_log) {
1554  result_ = proxy_service_->ResolveProxy(
1555      url, &proxy_info_, callback_, NULL, net_log);
1556  if (result_ != net::ERR_IO_PENDING) {
1557    OnCompletion(result_);
1558  }
1559}
1560
1561void SyncProxyServiceHelper::StartAsyncReconsider(const GURL& url,
1562                                                  const BoundNetLog& net_log) {
1563  result_ = proxy_service_->ReconsiderProxyAfterError(
1564      url, &proxy_info_, callback_, NULL, net_log);
1565  if (result_ != net::ERR_IO_PENDING) {
1566    OnCompletion(result_);
1567  }
1568}
1569
1570void SyncProxyServiceHelper::OnCompletion(int rv) {
1571  result_ = rv;
1572  event_.Signal();
1573}
1574
1575}  // namespace net
1576