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