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