1// Copyright (c) 2011 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/compiler_specific.h"
10#include "base/logging.h"
11#include "base/message_loop.h"
12#include "base/string_util.h"
13#include "base/values.h"
14#include "googleurl/src/gurl.h"
15#include "net/base/net_errors.h"
16#include "net/base/net_log.h"
17#include "net/base/net_util.h"
18#include "net/proxy/init_proxy_resolver.h"
19#include "net/proxy/multi_threaded_proxy_resolver.h"
20#include "net/proxy/proxy_config_service_fixed.h"
21#include "net/proxy/proxy_resolver.h"
22#include "net/proxy/proxy_resolver_js_bindings.h"
23#ifndef ANDROID
24#include "net/proxy/proxy_resolver_v8.h"
25#endif
26#include "net/proxy/proxy_script_fetcher.h"
27#include "net/proxy/sync_host_resolver_bridge.h"
28#include "net/url_request/url_request_context.h"
29
30#if defined(OS_WIN)
31#include "net/proxy/proxy_config_service_win.h"
32#include "net/proxy/proxy_resolver_winhttp.h"
33#elif defined(OS_MACOSX)
34#include "net/proxy/proxy_config_service_mac.h"
35#include "net/proxy/proxy_resolver_mac.h"
36#elif defined(OS_LINUX) && !defined(OS_CHROMEOS)
37#include "net/proxy/proxy_config_service_linux.h"
38#endif
39
40using base::TimeDelta;
41using base::TimeTicks;
42
43namespace net {
44
45namespace {
46
47const size_t kMaxNumNetLogEntries = 100;
48const size_t kDefaultNumPacThreads = 4;
49
50// When the IP address changes we don't immediately re-run proxy auto-config.
51// Instead, we  wait for |kNumMillisToStallAfterNetworkChanges| before
52// attempting to re-valuate proxy auto-config.
53//
54// During this time window, any resolve requests sent to the ProxyService will
55// be queued. Once we have waited the required amount of them, the proxy
56// auto-config step will be run, and the queued requests resumed.
57//
58// The reason we play this game is that our signal for detecting network
59// changes (NetworkChangeNotifier) may fire *before* the system's networking
60// dependencies are fully configured. This is a problem since it means if
61// we were to run proxy auto-config right away, it could fail due to spurious
62// DNS failures. (see http://crbug.com/50779 for more details.)
63//
64// By adding the wait window, we give things a chance to get properly set up.
65// Now by the time we run the proxy-autoconfig there is a lower chance of
66// getting transient DNS / connect failures.
67//
68// Admitedly this is a hack. Ideally we would have NetworkChangeNotifier
69// deliver a reliable signal indicating that the network has changed AND is
70// ready for action... But until then, we can reduce the likelihood of users
71// getting wedged because of proxy detection failures on network switch.
72//
73// The obvious downside to this strategy is it introduces an additional
74// latency when switching networks. This delay shouldn't be too disruptive
75// assuming network switches are infrequent and user initiated. However if
76// NetworkChangeNotifier delivers network changes more frequently this could
77// cause jankiness. (NetworkChangeNotifier broadcasts a change event when ANY
78// interface goes up/down. So in theory if the non-primary interface were
79// hopping on and off wireless networks our constant delayed reconfiguration
80// could add noticeable jank.)
81//
82// The specific hard-coded wait time below is arbitrary.
83// Basically I ran some experiments switching between wireless networks on
84// a Linux Ubuntu (Lucid) laptop, and experimentally found this timeout fixes
85// things. It is entirely possible that the value is insuficient for other
86// setups.
87const int64 kNumMillisToStallAfterNetworkChanges = 2000;
88
89// Config getter that always returns direct settings.
90class ProxyConfigServiceDirect : public ProxyConfigService {
91 public:
92  // ProxyConfigService implementation:
93  virtual void AddObserver(Observer* observer) {}
94  virtual void RemoveObserver(Observer* observer) {}
95  virtual ConfigAvailability GetLatestProxyConfig(ProxyConfig* config) {
96    *config = ProxyConfig::CreateDirect();
97    return CONFIG_VALID;
98  }
99};
100
101// Proxy resolver that fails every time.
102class ProxyResolverNull : public ProxyResolver {
103 public:
104  ProxyResolverNull() : ProxyResolver(false /*expects_pac_bytes*/) {}
105
106  // ProxyResolver implementation:
107  virtual int GetProxyForURL(const GURL& url,
108                             ProxyInfo* results,
109                             CompletionCallback* callback,
110                             RequestHandle* request,
111                             const BoundNetLog& net_log) {
112    return ERR_NOT_IMPLEMENTED;
113  }
114
115  virtual void CancelRequest(RequestHandle request) {
116    NOTREACHED();
117  }
118
119  virtual void CancelSetPacScript() {
120    NOTREACHED();
121  }
122
123  virtual int SetPacScript(
124      const scoped_refptr<ProxyResolverScriptData>& /*script_data*/,
125      CompletionCallback* /*callback*/) {
126    return ERR_NOT_IMPLEMENTED;
127  }
128};
129
130// ProxyResolver that simulates a PAC script which returns
131// |pac_string| for every single URL.
132class ProxyResolverFromPacString : public ProxyResolver {
133 public:
134  ProxyResolverFromPacString(const std::string& pac_string)
135      : ProxyResolver(false /*expects_pac_bytes*/),
136        pac_string_(pac_string) {}
137
138  virtual int GetProxyForURL(const GURL& url,
139                             ProxyInfo* results,
140                             CompletionCallback* callback,
141                             RequestHandle* request,
142                             const BoundNetLog& net_log) {
143    results->UsePacString(pac_string_);
144    return OK;
145  }
146
147  virtual void CancelRequest(RequestHandle request) {
148    NOTREACHED();
149  }
150
151  virtual void CancelSetPacScript() {
152    NOTREACHED();
153  }
154
155  virtual int SetPacScript(
156      const scoped_refptr<ProxyResolverScriptData>& pac_script,
157      CompletionCallback* callback) {
158    return OK;
159  }
160
161 private:
162  const std::string pac_string_;
163};
164
165#ifndef ANDROID
166// This factory creates V8ProxyResolvers with appropriate javascript bindings.
167class ProxyResolverFactoryForV8 : public ProxyResolverFactory {
168 public:
169  // |async_host_resolver|, |io_loop| and |net_log| must remain
170  // valid for the duration of our lifetime.
171  // |async_host_resolver| will only be operated on |io_loop|.
172  ProxyResolverFactoryForV8(HostResolver* async_host_resolver,
173                            MessageLoop* io_loop,
174                            NetLog* net_log)
175      : ProxyResolverFactory(true /*expects_pac_bytes*/),
176        async_host_resolver_(async_host_resolver),
177        io_loop_(io_loop),
178        net_log_(net_log) {
179  }
180
181  virtual ProxyResolver* CreateProxyResolver() {
182    // Create a synchronous host resolver wrapper that operates
183    // |async_host_resolver_| on |io_loop_|.
184    SyncHostResolverBridge* sync_host_resolver =
185        new SyncHostResolverBridge(async_host_resolver_, io_loop_);
186
187    ProxyResolverJSBindings* js_bindings =
188        ProxyResolverJSBindings::CreateDefault(sync_host_resolver, net_log_);
189
190    // ProxyResolverV8 takes ownership of |js_bindings|.
191    return new ProxyResolverV8(js_bindings);
192  }
193
194 private:
195  HostResolver* const async_host_resolver_;
196  MessageLoop* io_loop_;
197  NetLog* net_log_;
198};
199#endif
200
201// Creates ProxyResolvers using a platform-specific implementation.
202class ProxyResolverFactoryForSystem : public ProxyResolverFactory {
203 public:
204  ProxyResolverFactoryForSystem()
205      : ProxyResolverFactory(false /*expects_pac_bytes*/) {}
206
207  virtual ProxyResolver* CreateProxyResolver() {
208    DCHECK(IsSupported());
209#if defined(OS_WIN)
210    return new ProxyResolverWinHttp();
211#elif defined(OS_MACOSX)
212    return new ProxyResolverMac();
213#else
214    NOTREACHED();
215    return NULL;
216#endif
217  }
218
219  static bool IsSupported() {
220#if defined(OS_WIN) || defined(OS_MACOSX)
221    return true;
222#else
223    return false;
224#endif
225  }
226};
227
228// NetLog parameter to describe a proxy configuration change.
229class ProxyConfigChangedNetLogParam : public NetLog::EventParameters {
230 public:
231  ProxyConfigChangedNetLogParam(const ProxyConfig& old_config,
232                                const ProxyConfig& new_config)
233      : old_config_(old_config),
234        new_config_(new_config) {
235  }
236
237  virtual Value* ToValue() const {
238    DictionaryValue* dict = new DictionaryValue();
239    // The "old_config" is optional -- the first notification will not have
240    // any "previous" configuration.
241    if (old_config_.is_valid())
242      dict->Set("old_config", old_config_.ToValue());
243    dict->Set("new_config", new_config_.ToValue());
244    return dict;
245  }
246
247 private:
248  const ProxyConfig old_config_;
249  const ProxyConfig new_config_;
250  DISALLOW_COPY_AND_ASSIGN(ProxyConfigChangedNetLogParam);
251};
252
253}  // namespace
254
255// ProxyService::PacRequest ---------------------------------------------------
256
257class ProxyService::PacRequest
258    : public base::RefCounted<ProxyService::PacRequest> {
259 public:
260  PacRequest(ProxyService* service,
261             const GURL& url,
262             ProxyInfo* results,
263             CompletionCallback* user_callback,
264             const BoundNetLog& net_log)
265      : service_(service),
266        user_callback_(user_callback),
267        ALLOW_THIS_IN_INITIALIZER_LIST(io_callback_(
268            this, &PacRequest::QueryComplete)),
269        results_(results),
270        url_(url),
271        resolve_job_(NULL),
272        config_id_(ProxyConfig::INVALID_ID),
273        net_log_(net_log) {
274    DCHECK(user_callback);
275  }
276
277  // Starts the resolve proxy request.
278  int Start() {
279    DCHECK(!was_cancelled());
280    DCHECK(!is_started());
281
282    DCHECK(service_->config_.is_valid());
283
284    config_id_ = service_->config_.id();
285
286    return resolver()->GetProxyForURL(
287        url_, results_, &io_callback_, &resolve_job_, net_log_);
288  }
289
290  bool is_started() const {
291    // Note that !! casts to bool. (VS gives a warning otherwise).
292    return !!resolve_job_;
293  }
294
295  void StartAndCompleteCheckingForSynchronous() {
296    int rv = service_->TryToCompleteSynchronously(url_, results_);
297    if (rv == ERR_IO_PENDING)
298      rv = Start();
299    if (rv != ERR_IO_PENDING)
300      QueryComplete(rv);
301  }
302
303  void CancelResolveJob() {
304    DCHECK(is_started());
305    // The request may already be running in the resolver.
306    resolver()->CancelRequest(resolve_job_);
307    resolve_job_ = NULL;
308    DCHECK(!is_started());
309  }
310
311  void Cancel() {
312    net_log_.AddEvent(NetLog::TYPE_CANCELLED, NULL);
313
314    if (is_started())
315      CancelResolveJob();
316
317    // Mark as cancelled, to prevent accessing this again later.
318    service_ = NULL;
319    user_callback_ = NULL;
320    results_ = NULL;
321
322    net_log_.EndEvent(NetLog::TYPE_PROXY_SERVICE, NULL);
323  }
324
325  // Returns true if Cancel() has been called.
326  bool was_cancelled() const { return user_callback_ == NULL; }
327
328  // Helper to call after ProxyResolver completion (both synchronous and
329  // asynchronous). Fixes up the result that is to be returned to user.
330  int QueryDidComplete(int result_code) {
331    DCHECK(!was_cancelled());
332
333    // Make a note in the results which configuration was in use at the
334    // time of the resolve.
335    results_->config_id_ = config_id_;
336
337    // Reset the state associated with in-progress-resolve.
338    resolve_job_ = NULL;
339    config_id_ = ProxyConfig::INVALID_ID;
340
341    return service_->DidFinishResolvingProxy(results_, result_code, net_log_);
342  }
343
344  BoundNetLog* net_log() { return &net_log_; }
345
346 private:
347  friend class base::RefCounted<ProxyService::PacRequest>;
348
349  ~PacRequest() {}
350
351  // Callback for when the ProxyResolver request has completed.
352  void QueryComplete(int result_code) {
353    result_code = QueryDidComplete(result_code);
354
355    // Remove this completed PacRequest from the service's pending list.
356    /// (which will probably cause deletion of |this|).
357    CompletionCallback* callback = user_callback_;
358    service_->RemovePendingRequest(this);
359
360    callback->Run(result_code);
361  }
362
363  ProxyResolver* resolver() const { return service_->resolver_.get(); }
364
365  // Note that we don't hold a reference to the ProxyService. Outstanding
366  // requests are cancelled during ~ProxyService, so this is guaranteed
367  // to be valid throughout our lifetime.
368  ProxyService* service_;
369  CompletionCallback* user_callback_;
370  CompletionCallbackImpl<PacRequest> io_callback_;
371  ProxyInfo* results_;
372  GURL url_;
373  ProxyResolver::RequestHandle resolve_job_;
374  ProxyConfig::ID config_id_;  // The config id when the resolve was started.
375  BoundNetLog net_log_;
376};
377
378// ProxyService ---------------------------------------------------------------
379
380ProxyService::ProxyService(ProxyConfigService* config_service,
381                           ProxyResolver* resolver,
382                           NetLog* net_log)
383    : resolver_(resolver),
384      next_config_id_(1),
385      ALLOW_THIS_IN_INITIALIZER_LIST(init_proxy_resolver_callback_(
386          this, &ProxyService::OnInitProxyResolverComplete)),
387      current_state_(STATE_NONE) ,
388      net_log_(net_log),
389      stall_proxy_auto_config_delay_(
390          base::TimeDelta::FromMilliseconds(
391              kNumMillisToStallAfterNetworkChanges)) {
392  NetworkChangeNotifier::AddIPAddressObserver(this);
393  ResetConfigService(config_service);
394}
395
396#ifndef ANDROID
397// static
398ProxyService* ProxyService::CreateUsingV8ProxyResolver(
399    ProxyConfigService* proxy_config_service,
400    size_t num_pac_threads,
401    ProxyScriptFetcher* proxy_script_fetcher,
402    HostResolver* host_resolver,
403    NetLog* net_log) {
404  DCHECK(proxy_config_service);
405  DCHECK(proxy_script_fetcher);
406  DCHECK(host_resolver);
407
408  if (num_pac_threads == 0)
409    num_pac_threads = kDefaultNumPacThreads;
410
411  ProxyResolverFactory* sync_resolver_factory =
412      new ProxyResolverFactoryForV8(
413          host_resolver,
414          MessageLoop::current(),
415          net_log);
416
417  ProxyResolver* proxy_resolver =
418      new MultiThreadedProxyResolver(sync_resolver_factory, num_pac_threads);
419
420  ProxyService* proxy_service =
421      new ProxyService(proxy_config_service, proxy_resolver, net_log);
422
423  // Configure PAC script downloads to be issued using |proxy_script_fetcher|.
424  proxy_service->SetProxyScriptFetcher(proxy_script_fetcher);
425
426  return proxy_service;
427}
428#endif
429
430// static
431ProxyService* ProxyService::CreateUsingSystemProxyResolver(
432    ProxyConfigService* proxy_config_service,
433    size_t num_pac_threads,
434    NetLog* net_log) {
435  DCHECK(proxy_config_service);
436
437  if (!ProxyResolverFactoryForSystem::IsSupported()) {
438    LOG(WARNING) << "PAC support disabled because there is no "
439                    "system implementation";
440    return CreateWithoutProxyResolver(proxy_config_service, net_log);
441  }
442
443  if (num_pac_threads == 0)
444    num_pac_threads = kDefaultNumPacThreads;
445
446  ProxyResolver* proxy_resolver = new MultiThreadedProxyResolver(
447      new ProxyResolverFactoryForSystem(), num_pac_threads);
448
449  return new ProxyService(proxy_config_service, proxy_resolver, net_log);
450}
451
452// static
453ProxyService* ProxyService::CreateWithoutProxyResolver(
454    ProxyConfigService* proxy_config_service,
455    NetLog* net_log) {
456  return new ProxyService(proxy_config_service,
457                          new ProxyResolverNull(),
458                          net_log);
459}
460
461// static
462ProxyService* ProxyService::CreateFixed(const ProxyConfig& pc) {
463  // TODO(eroman): This isn't quite right, won't work if |pc| specifies
464  //               a PAC script.
465  return CreateUsingSystemProxyResolver(new ProxyConfigServiceFixed(pc),
466                                        0, NULL);
467}
468
469// static
470ProxyService* ProxyService::CreateFixed(const std::string& proxy) {
471  net::ProxyConfig proxy_config;
472  proxy_config.proxy_rules().ParseFromString(proxy);
473  return ProxyService::CreateFixed(proxy_config);
474}
475
476// static
477ProxyService* ProxyService::CreateDirect() {
478  return CreateDirectWithNetLog(NULL);
479}
480
481ProxyService* ProxyService::CreateDirectWithNetLog(NetLog* net_log) {
482  // Use direct connections.
483  return new ProxyService(new ProxyConfigServiceDirect, new ProxyResolverNull,
484                          net_log);
485}
486
487// static
488ProxyService* ProxyService::CreateFixedFromPacResult(
489    const std::string& pac_string) {
490
491  // We need the settings to contain an "automatic" setting, otherwise the
492  // ProxyResolver dependency we give it will never be used.
493  scoped_ptr<ProxyConfigService> proxy_config_service(
494      new ProxyConfigServiceFixed(ProxyConfig::CreateAutoDetect()));
495
496  scoped_ptr<ProxyResolver> proxy_resolver(
497      new ProxyResolverFromPacString(pac_string));
498
499  return new ProxyService(proxy_config_service.release(),
500                          proxy_resolver.release(),
501                          NULL);
502}
503
504int ProxyService::ResolveProxy(const GURL& raw_url,
505                               ProxyInfo* result,
506                               CompletionCallback* callback,
507                               PacRequest** pac_request,
508                               const BoundNetLog& net_log) {
509  DCHECK(CalledOnValidThread());
510  DCHECK(callback);
511
512  net_log.BeginEvent(NetLog::TYPE_PROXY_SERVICE, NULL);
513
514  config_service_->OnLazyPoll();
515  if (current_state_ == STATE_NONE)
516    ApplyProxyConfigIfAvailable();
517
518  // Strip away any reference fragments and the username/password, as they
519  // are not relevant to proxy resolution.
520  GURL url = SimplifyUrlForRequest(raw_url);
521
522  // Check if the request can be completed right away. (This is the case when
523  // using a direct connection for example).
524  int rv = TryToCompleteSynchronously(url, result);
525  if (rv != ERR_IO_PENDING)
526    return DidFinishResolvingProxy(result, rv, net_log);
527
528  scoped_refptr<PacRequest> req(
529      new PacRequest(this, url, result, callback, net_log));
530
531  if (current_state_ == STATE_READY) {
532    // Start the resolve request.
533    rv = req->Start();
534    if (rv != ERR_IO_PENDING)
535      return req->QueryDidComplete(rv);
536  } else {
537    req->net_log()->BeginEvent(NetLog::TYPE_PROXY_SERVICE_WAITING_FOR_INIT_PAC,
538                               NULL);
539  }
540
541  DCHECK_EQ(ERR_IO_PENDING, rv);
542  DCHECK(!ContainsPendingRequest(req));
543  pending_requests_.push_back(req);
544
545  // Completion will be notifed through |callback|, unless the caller cancels
546  // the request using |pac_request|.
547  if (pac_request)
548    *pac_request = req.get();
549  return rv;  // ERR_IO_PENDING
550}
551
552int ProxyService::TryToCompleteSynchronously(const GURL& url,
553                                             ProxyInfo* result) {
554  DCHECK_NE(STATE_NONE, current_state_);
555
556  if (current_state_ != STATE_READY)
557    return ERR_IO_PENDING;  // Still initializing.
558
559  DCHECK_NE(config_.id(), ProxyConfig::INVALID_ID);
560
561  if (config_.HasAutomaticSettings())
562    return ERR_IO_PENDING;  // Must submit the request to the proxy resolver.
563
564  // Use the manual proxy settings.
565  config_.proxy_rules().Apply(url, result);
566  result->config_id_ = config_.id();
567  return OK;
568}
569
570ProxyService::~ProxyService() {
571  NetworkChangeNotifier::RemoveIPAddressObserver(this);
572  config_service_->RemoveObserver(this);
573
574  // Cancel any inprogress requests.
575  for (PendingRequests::iterator it = pending_requests_.begin();
576       it != pending_requests_.end();
577       ++it) {
578    (*it)->Cancel();
579  }
580}
581
582void ProxyService::SuspendAllPendingRequests() {
583  for (PendingRequests::iterator it = pending_requests_.begin();
584       it != pending_requests_.end();
585       ++it) {
586    PacRequest* req = it->get();
587    if (req->is_started()) {
588      req->CancelResolveJob();
589
590      req->net_log()->BeginEvent(
591          NetLog::TYPE_PROXY_SERVICE_WAITING_FOR_INIT_PAC, NULL);
592    }
593  }
594}
595
596void ProxyService::SetReady() {
597  DCHECK(!init_proxy_resolver_.get());
598  current_state_ = STATE_READY;
599
600  // Make a copy in case |this| is deleted during the synchronous completion
601  // of one of the requests. If |this| is deleted then all of the PacRequest
602  // instances will be Cancel()-ed.
603  PendingRequests pending_copy = pending_requests_;
604
605  for (PendingRequests::iterator it = pending_copy.begin();
606       it != pending_copy.end();
607       ++it) {
608    PacRequest* req = it->get();
609    if (!req->is_started() && !req->was_cancelled()) {
610      req->net_log()->EndEvent(NetLog::TYPE_PROXY_SERVICE_WAITING_FOR_INIT_PAC,
611                               NULL);
612
613      // Note that we re-check for synchronous completion, in case we are
614      // no longer using a ProxyResolver (can happen if we fell-back to manual).
615      req->StartAndCompleteCheckingForSynchronous();
616    }
617  }
618}
619
620void ProxyService::ApplyProxyConfigIfAvailable() {
621  DCHECK_EQ(STATE_NONE, current_state_);
622
623  config_service_->OnLazyPoll();
624
625  // If we have already fetched the configuration, start applying it.
626  if (fetched_config_.is_valid()) {
627    InitializeUsingLastFetchedConfig();
628    return;
629  }
630
631  // Otherwise we need to first fetch the configuration.
632  current_state_ = STATE_WAITING_FOR_PROXY_CONFIG;
633
634  // Retrieve the current proxy configuration from the ProxyConfigService.
635  // If a configuration is not available yet, we will get called back later
636  // by our ProxyConfigService::Observer once it changes.
637  ProxyConfig config;
638  ProxyConfigService::ConfigAvailability availability =
639      config_service_->GetLatestProxyConfig(&config);
640  if (availability != ProxyConfigService::CONFIG_PENDING)
641    OnProxyConfigChanged(config, availability);
642}
643
644void ProxyService::OnInitProxyResolverComplete(int result) {
645  DCHECK_EQ(STATE_WAITING_FOR_INIT_PROXY_RESOLVER, current_state_);
646  DCHECK(init_proxy_resolver_.get());
647  DCHECK(fetched_config_.HasAutomaticSettings());
648  init_proxy_resolver_.reset();
649
650  if (result != OK) {
651    VLOG(1) << "Failed configuring with PAC script, falling-back to manual "
652               "proxy servers.";
653    config_ = fetched_config_;
654    config_.ClearAutomaticSettings();
655  }
656
657  config_.set_id(fetched_config_.id());
658
659  // Resume any requests which we had to defer until the PAC script was
660  // downloaded.
661  SetReady();
662}
663
664int ProxyService::ReconsiderProxyAfterError(const GURL& url,
665                                            ProxyInfo* result,
666                                            CompletionCallback* callback,
667                                            PacRequest** pac_request,
668                                            const BoundNetLog& net_log) {
669  DCHECK(CalledOnValidThread());
670
671  // Check to see if we have a new config since ResolveProxy was called.  We
672  // want to re-run ResolveProxy in two cases: 1) we have a new config, or 2) a
673  // direct connection failed and we never tried the current config.
674
675  bool re_resolve = result->config_id_ != config_.id();
676
677  if (re_resolve) {
678    // If we have a new config or the config was never tried, we delete the
679    // list of bad proxies and we try again.
680    proxy_retry_info_.clear();
681    return ResolveProxy(url, result, callback, pac_request, net_log);
682  }
683
684  // We don't have new proxy settings to try, try to fallback to the next proxy
685  // in the list.
686  bool did_fallback = result->Fallback(&proxy_retry_info_);
687
688  // Return synchronous failure if there is nothing left to fall-back to.
689  // TODO(eroman): This is a yucky API, clean it up.
690  return did_fallback ? OK : ERR_FAILED;
691}
692
693void ProxyService::CancelPacRequest(PacRequest* req) {
694  DCHECK(CalledOnValidThread());
695  DCHECK(req);
696  req->Cancel();
697  RemovePendingRequest(req);
698}
699
700bool ProxyService::ContainsPendingRequest(PacRequest* req) {
701  PendingRequests::iterator it = std::find(
702      pending_requests_.begin(), pending_requests_.end(), req);
703  return pending_requests_.end() != it;
704}
705
706void ProxyService::RemovePendingRequest(PacRequest* req) {
707  DCHECK(ContainsPendingRequest(req));
708  PendingRequests::iterator it = std::find(
709      pending_requests_.begin(), pending_requests_.end(), req);
710  pending_requests_.erase(it);
711}
712
713int ProxyService::DidFinishResolvingProxy(ProxyInfo* result,
714                                          int result_code,
715                                          const BoundNetLog& net_log) {
716  // Log the result of the proxy resolution.
717  if (result_code == OK) {
718    // When logging all events is enabled, dump the proxy list.
719    if (net_log.IsLoggingAllEvents()) {
720      net_log.AddEvent(
721          NetLog::TYPE_PROXY_SERVICE_RESOLVED_PROXY_LIST,
722          make_scoped_refptr(new NetLogStringParameter(
723              "pac_string", result->ToPacString())));
724    }
725    result->DeprioritizeBadProxies(proxy_retry_info_);
726  } else {
727    net_log.AddEvent(
728        NetLog::TYPE_PROXY_SERVICE_RESOLVED_PROXY_LIST,
729        make_scoped_refptr(new NetLogIntegerParameter(
730            "net_error", result_code)));
731
732    // Fall-back to direct when the proxy resolver fails. This corresponds
733    // with a javascript runtime error in the PAC script.
734    //
735    // This implicit fall-back to direct matches Firefox 3.5 and
736    // Internet Explorer 8. For more information, see:
737    //
738    // http://www.chromium.org/developers/design-documents/proxy-settings-fallback
739    result->UseDirect();
740    result_code = OK;
741  }
742
743  net_log.EndEvent(NetLog::TYPE_PROXY_SERVICE, NULL);
744  return result_code;
745}
746
747void ProxyService::SetProxyScriptFetcher(
748    ProxyScriptFetcher* proxy_script_fetcher) {
749  DCHECK(CalledOnValidThread());
750  State previous_state = ResetProxyConfig(false);
751  proxy_script_fetcher_.reset(proxy_script_fetcher);
752  if (previous_state != STATE_NONE)
753    ApplyProxyConfigIfAvailable();
754}
755
756ProxyScriptFetcher* ProxyService::GetProxyScriptFetcher() const {
757  DCHECK(CalledOnValidThread());
758  return proxy_script_fetcher_.get();
759}
760
761ProxyService::State ProxyService::ResetProxyConfig(bool reset_fetched_config) {
762  DCHECK(CalledOnValidThread());
763  State previous_state = current_state_;
764
765  proxy_retry_info_.clear();
766  init_proxy_resolver_.reset();
767  SuspendAllPendingRequests();
768  config_ = ProxyConfig();
769  if (reset_fetched_config)
770    fetched_config_ = ProxyConfig();
771  current_state_ = STATE_NONE;
772
773  return previous_state;
774}
775
776void ProxyService::ResetConfigService(
777    ProxyConfigService* new_proxy_config_service) {
778  DCHECK(CalledOnValidThread());
779  State previous_state = ResetProxyConfig(true);
780
781  // Release the old configuration service.
782  if (config_service_.get())
783    config_service_->RemoveObserver(this);
784
785  // Set the new configuration service.
786  config_service_.reset(new_proxy_config_service);
787  config_service_->AddObserver(this);
788
789  if (previous_state != STATE_NONE)
790    ApplyProxyConfigIfAvailable();
791}
792
793void ProxyService::PurgeMemory() {
794  DCHECK(CalledOnValidThread());
795  if (resolver_.get())
796    resolver_->PurgeMemory();
797}
798
799void ProxyService::ForceReloadProxyConfig() {
800  DCHECK(CalledOnValidThread());
801  ResetProxyConfig(false);
802  ApplyProxyConfigIfAvailable();
803}
804
805// static
806ProxyConfigService* ProxyService::CreateSystemProxyConfigService(
807    MessageLoop* io_loop, MessageLoop* file_loop) {
808#if defined(OS_WIN)
809  return new ProxyConfigServiceWin();
810#elif defined(OS_MACOSX)
811  return new ProxyConfigServiceMac(io_loop);
812#elif defined(OS_CHROMEOS)
813  NOTREACHED() << "ProxyConfigService for ChromeOS should be created in "
814               << "profile_io_data.cc::CreateProxyConfigService.";
815  return NULL;
816#elif defined(ANDROID)
817  NOTREACHED() << "ProxyConfigService for Android should be created in "
818               << "WebCache.cpp: WebCache::WebCache";
819  return NULL;
820#elif defined(OS_LINUX)
821  ProxyConfigServiceLinux* linux_config_service =
822      new ProxyConfigServiceLinux();
823
824  // Assume we got called from the UI loop, which runs the default
825  // glib main loop, so the current thread is where we should be
826  // running gconf calls from.
827  MessageLoop* glib_default_loop = MessageLoopForUI::current();
828
829  // The file loop should be a MessageLoopForIO on Linux.
830  DCHECK_EQ(MessageLoop::TYPE_IO, file_loop->type());
831
832  // Synchronously fetch the current proxy config (since we are
833  // running on glib_default_loop). Additionally register for
834  // notifications (delivered in either |glib_default_loop| or
835  // |file_loop|) to keep us updated when the proxy config changes.
836  linux_config_service->SetupAndFetchInitialConfig(glib_default_loop, io_loop,
837      static_cast<MessageLoopForIO*>(file_loop));
838
839  return linux_config_service;
840#else
841  LOG(WARNING) << "Failed to choose a system proxy settings fetcher "
842                  "for this platform.";
843  return new ProxyConfigServiceNull();
844#endif
845}
846
847void ProxyService::OnProxyConfigChanged(
848    const ProxyConfig& config,
849    ProxyConfigService::ConfigAvailability availability) {
850  // Retrieve the current proxy configuration from the ProxyConfigService.
851  // If a configuration is not available yet, we will get called back later
852  // by our ProxyConfigService::Observer once it changes.
853  ProxyConfig effective_config;
854  switch (availability) {
855    case ProxyConfigService::CONFIG_PENDING:
856      // ProxyConfigService implementors should never pass CONFIG_PENDING.
857      NOTREACHED() << "Proxy config change with CONFIG_PENDING availability!";
858      return;
859    case ProxyConfigService::CONFIG_VALID:
860      effective_config = config;
861      break;
862    case ProxyConfigService::CONFIG_UNSET:
863      effective_config = ProxyConfig::CreateDirect();
864      break;
865  }
866
867  // Emit the proxy settings change to the NetLog stream.
868  if (net_log_) {
869    scoped_refptr<NetLog::EventParameters> params(
870        new ProxyConfigChangedNetLogParam(fetched_config_, effective_config));
871    net_log_->AddEntry(net::NetLog::TYPE_PROXY_CONFIG_CHANGED,
872                       base::TimeTicks::Now(),
873                       NetLog::Source(),
874                       NetLog::PHASE_NONE,
875                       params);
876  }
877
878  // Set the new configuration as the most recently fetched one.
879  fetched_config_ = effective_config;
880  fetched_config_.set_id(1);  // Needed for a later DCHECK of is_valid().
881
882  InitializeUsingLastFetchedConfig();
883}
884
885void ProxyService::InitializeUsingLastFetchedConfig() {
886  ResetProxyConfig(false);
887
888  DCHECK(fetched_config_.is_valid());
889
890  // Increment the ID to reflect that the config has changed.
891  fetched_config_.set_id(next_config_id_++);
892
893  if (!fetched_config_.HasAutomaticSettings()) {
894    config_ = fetched_config_;
895    SetReady();
896    return;
897  }
898
899  // Start downloading + testing the PAC scripts for this new configuration.
900  current_state_ = STATE_WAITING_FOR_INIT_PROXY_RESOLVER;
901
902  init_proxy_resolver_.reset(
903      new InitProxyResolver(resolver_.get(), proxy_script_fetcher_.get(),
904                            net_log_));
905
906  // If we changed networks recently, we should delay running proxy auto-config.
907  base::TimeDelta wait_delay =
908      stall_proxy_autoconfig_until_ - base::TimeTicks::Now();
909
910  int rv = init_proxy_resolver_->Init(
911      fetched_config_, wait_delay, &config_, &init_proxy_resolver_callback_);
912
913  if (rv != ERR_IO_PENDING)
914    OnInitProxyResolverComplete(rv);
915}
916
917void ProxyService::OnIPAddressChanged() {
918  // See the comment block by |kNumMillisToStallAfterNetworkChanges| for info.
919  stall_proxy_autoconfig_until_ =
920      base::TimeTicks::Now() + stall_proxy_auto_config_delay_;
921
922  State previous_state = ResetProxyConfig(false);
923  if (previous_state != STATE_NONE)
924    ApplyProxyConfigIfAvailable();
925}
926
927SyncProxyServiceHelper::SyncProxyServiceHelper(MessageLoop* io_message_loop,
928                                               ProxyService* proxy_service)
929    : io_message_loop_(io_message_loop),
930      proxy_service_(proxy_service),
931      event_(false, false),
932      ALLOW_THIS_IN_INITIALIZER_LIST(callback_(
933          this, &SyncProxyServiceHelper::OnCompletion)) {
934  DCHECK(io_message_loop_ != MessageLoop::current());
935}
936
937int SyncProxyServiceHelper::ResolveProxy(const GURL& url,
938                                         ProxyInfo* proxy_info,
939                                         const BoundNetLog& net_log) {
940  DCHECK(io_message_loop_ != MessageLoop::current());
941
942  io_message_loop_->PostTask(FROM_HERE, NewRunnableMethod(
943      this, &SyncProxyServiceHelper::StartAsyncResolve, url, net_log));
944
945  event_.Wait();
946
947  if (result_ == net::OK) {
948    *proxy_info = proxy_info_;
949  }
950  return result_;
951}
952
953int SyncProxyServiceHelper::ReconsiderProxyAfterError(
954    const GURL& url, ProxyInfo* proxy_info, const BoundNetLog& net_log) {
955  DCHECK(io_message_loop_ != MessageLoop::current());
956
957  io_message_loop_->PostTask(FROM_HERE, NewRunnableMethod(
958      this, &SyncProxyServiceHelper::StartAsyncReconsider, url, net_log));
959
960  event_.Wait();
961
962  if (result_ == net::OK) {
963    *proxy_info = proxy_info_;
964  }
965  return result_;
966}
967
968SyncProxyServiceHelper::~SyncProxyServiceHelper() {}
969
970void SyncProxyServiceHelper::StartAsyncResolve(const GURL& url,
971                                               const BoundNetLog& net_log) {
972  result_ = proxy_service_->ResolveProxy(
973      url, &proxy_info_, &callback_, NULL, net_log);
974  if (result_ != net::ERR_IO_PENDING) {
975    OnCompletion(result_);
976  }
977}
978
979void SyncProxyServiceHelper::StartAsyncReconsider(const GURL& url,
980                                                  const BoundNetLog& net_log) {
981  result_ = proxy_service_->ReconsiderProxyAfterError(
982      url, &proxy_info_, &callback_, NULL, net_log);
983  if (result_ != net::ERR_IO_PENDING) {
984    OnCompletion(result_);
985  }
986}
987
988void SyncProxyServiceHelper::OnCompletion(int rv) {
989  result_ = rv;
990  event_.Signal();
991}
992
993}  // namespace net
994