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 50using base::TimeDelta; 51using base::TimeTicks; 52 53namespace net { 54 55namespace { 56 57// When the IP address changes we don't immediately re-run proxy auto-config. 58// Instead, we wait for |kDelayAfterNetworkChangesMs| before 59// attempting to re-valuate proxy auto-config. 60// 61// During this time window, any resolve requests sent to the ProxyService will 62// be queued. Once we have waited the required amount of them, the proxy 63// auto-config step will be run, and the queued requests resumed. 64// 65// The reason we play this game is that our signal for detecting network 66// changes (NetworkChangeNotifier) may fire *before* the system's networking 67// dependencies are fully configured. This is a problem since it means if 68// we were to run proxy auto-config right away, it could fail due to spurious 69// DNS failures. (see http://crbug.com/50779 for more details.) 70// 71// By adding the wait window, we give things a better chance to get properly 72// set up. Network failures can happen at any time though, so we additionally 73// poll the PAC script for changes, which will allow us to recover from these 74// sorts of problems. 75const int64 kDelayAfterNetworkChangesMs = 2000; 76 77// This is the default policy for polling the PAC script. 78// 79// In response to a failure, the poll intervals are: 80// 0: 8 seconds (scheduled on timer) 81// 1: 32 seconds 82// 2: 2 minutes 83// 3+: 4 hours 84// 85// In response to a success, the poll intervals are: 86// 0+: 12 hours 87// 88// Only the 8 second poll is scheduled on a timer, the rest happen in response 89// to network activity (and hence will take longer than the written time). 90// 91// Explanation for these values: 92// 93// TODO(eroman): These values are somewhat arbitrary, and need to be tuned 94// using some histograms data. Trying to be conservative so as not to break 95// existing setups when deployed. A simple exponential retry scheme would be 96// more elegant, but places more load on server. 97// 98// The motivation for trying quickly after failures (8 seconds) is to recover 99// from spurious network failures, which are common after the IP address has 100// just changed (like DNS failing to resolve). The next 32 second boundary is 101// to try and catch other VPN weirdness which anecdotally I have seen take 102// 10+ seconds for some users. 103// 104// The motivation for re-trying after a success is to check for possible 105// content changes to the script, or to the WPAD auto-discovery results. We are 106// not very aggressive with these checks so as to minimize the risk of 107// overloading existing PAC setups. Moreover it is unlikely that PAC scripts 108// change very frequently in existing setups. More research is needed to 109// motivate what safe values are here, and what other user agents do. 110// 111// Comparison to other browsers: 112// 113// In Firefox the PAC URL is re-tried on failures according to 114// network.proxy.autoconfig_retry_interval_min and 115// network.proxy.autoconfig_retry_interval_max. The defaults are 5 seconds and 116// 5 minutes respectively. It doubles the interval at each attempt. 117// 118// TODO(eroman): Figure out what Internet Explorer does. 119class DefaultPollPolicy : public ProxyService::PacPollPolicy { 120 public: 121 DefaultPollPolicy() {} 122 123 virtual Mode GetNextDelay(int initial_error, 124 TimeDelta current_delay, 125 TimeDelta* next_delay) const OVERRIDE { 126 if (initial_error != OK) { 127 // Re-try policy for failures. 128 const int kDelay1Seconds = 8; 129 const int kDelay2Seconds = 32; 130 const int kDelay3Seconds = 2 * 60; // 2 minutes 131 const int kDelay4Seconds = 4 * 60 * 60; // 4 Hours 132 133 // Initial poll. 134 if (current_delay < TimeDelta()) { 135 *next_delay = TimeDelta::FromSeconds(kDelay1Seconds); 136 return MODE_USE_TIMER; 137 } 138 switch (current_delay.InSeconds()) { 139 case kDelay1Seconds: 140 *next_delay = TimeDelta::FromSeconds(kDelay2Seconds); 141 return MODE_START_AFTER_ACTIVITY; 142 case kDelay2Seconds: 143 *next_delay = TimeDelta::FromSeconds(kDelay3Seconds); 144 return MODE_START_AFTER_ACTIVITY; 145 default: 146 *next_delay = TimeDelta::FromSeconds(kDelay4Seconds); 147 return MODE_START_AFTER_ACTIVITY; 148 } 149 } else { 150 // Re-try policy for succeses. 151 *next_delay = TimeDelta::FromHours(12); 152 return MODE_START_AFTER_ACTIVITY; 153 } 154 } 155 156 private: 157 DISALLOW_COPY_AND_ASSIGN(DefaultPollPolicy); 158}; 159 160// Config getter that always returns direct settings. 161class ProxyConfigServiceDirect : public ProxyConfigService { 162 public: 163 // ProxyConfigService implementation: 164 virtual void AddObserver(Observer* observer) OVERRIDE {} 165 virtual void RemoveObserver(Observer* observer) OVERRIDE {} 166 virtual ConfigAvailability GetLatestProxyConfig(ProxyConfig* config) 167 OVERRIDE { 168 *config = ProxyConfig::CreateDirect(); 169 config->set_source(PROXY_CONFIG_SOURCE_UNKNOWN); 170 return CONFIG_VALID; 171 } 172}; 173 174// Proxy resolver that fails every time. 175class ProxyResolverNull : public ProxyResolver { 176 public: 177 ProxyResolverNull() : ProxyResolver(false /*expects_pac_bytes*/) {} 178 179 // ProxyResolver implementation. 180 virtual int GetProxyForURL(const GURL& url, 181 ProxyInfo* results, 182 const CompletionCallback& callback, 183 RequestHandle* request, 184 const BoundNetLog& net_log) OVERRIDE { 185 return ERR_NOT_IMPLEMENTED; 186 } 187 188 virtual void CancelRequest(RequestHandle request) OVERRIDE { 189 NOTREACHED(); 190 } 191 192 virtual LoadState GetLoadState(RequestHandle request) const OVERRIDE { 193 NOTREACHED(); 194 return LOAD_STATE_IDLE; 195 } 196 197 virtual void CancelSetPacScript() OVERRIDE { 198 NOTREACHED(); 199 } 200 201 virtual int SetPacScript( 202 const scoped_refptr<ProxyResolverScriptData>& /*script_data*/, 203 const CompletionCallback& /*callback*/) OVERRIDE { 204 return ERR_NOT_IMPLEMENTED; 205 } 206}; 207 208// ProxyResolver that simulates a PAC script which returns 209// |pac_string| for every single URL. 210class ProxyResolverFromPacString : public ProxyResolver { 211 public: 212 explicit ProxyResolverFromPacString(const std::string& pac_string) 213 : ProxyResolver(false /*expects_pac_bytes*/), 214 pac_string_(pac_string) {} 215 216 virtual int GetProxyForURL(const GURL& url, 217 ProxyInfo* results, 218 const CompletionCallback& callback, 219 RequestHandle* request, 220 const BoundNetLog& net_log) OVERRIDE { 221 results->UsePacString(pac_string_); 222 return OK; 223 } 224 225 virtual void CancelRequest(RequestHandle request) OVERRIDE { 226 NOTREACHED(); 227 } 228 229 virtual LoadState GetLoadState(RequestHandle request) const OVERRIDE { 230 NOTREACHED(); 231 return LOAD_STATE_IDLE; 232 } 233 234 virtual void CancelSetPacScript() OVERRIDE { 235 NOTREACHED(); 236 } 237 238 virtual int SetPacScript( 239 const scoped_refptr<ProxyResolverScriptData>& pac_script, 240 const CompletionCallback& callback) OVERRIDE { 241 return OK; 242 } 243 244 private: 245 const std::string pac_string_; 246}; 247 248// Creates ProxyResolvers using a platform-specific implementation. 249class ProxyResolverFactoryForSystem : public ProxyResolverFactory { 250 public: 251 ProxyResolverFactoryForSystem() 252 : ProxyResolverFactory(false /*expects_pac_bytes*/) {} 253 254 virtual ProxyResolver* CreateProxyResolver() OVERRIDE { 255 DCHECK(IsSupported()); 256#if defined(OS_WIN) 257 return new ProxyResolverWinHttp(); 258#elif defined(OS_MACOSX) 259 return new ProxyResolverMac(); 260#else 261 NOTREACHED(); 262 return NULL; 263#endif 264 } 265 266 static bool IsSupported() { 267#if defined(OS_WIN) || defined(OS_MACOSX) 268 return true; 269#else 270 return false; 271#endif 272 } 273}; 274 275// Returns NetLog parameters describing a proxy configuration change. 276base::Value* NetLogProxyConfigChangedCallback( 277 const ProxyConfig* old_config, 278 const ProxyConfig* new_config, 279 NetLog::LogLevel /* log_level */) { 280 base::DictionaryValue* dict = new base::DictionaryValue(); 281 // The "old_config" is optional -- the first notification will not have 282 // any "previous" configuration. 283 if (old_config->is_valid()) 284 dict->Set("old_config", old_config->ToValue()); 285 dict->Set("new_config", new_config->ToValue()); 286 return dict; 287} 288 289base::Value* NetLogBadProxyListCallback(const ProxyRetryInfoMap* retry_info, 290 NetLog::LogLevel /* log_level */) { 291 base::DictionaryValue* dict = new base::DictionaryValue(); 292 base::ListValue* list = new base::ListValue(); 293 294 for (ProxyRetryInfoMap::const_iterator iter = retry_info->begin(); 295 iter != retry_info->end(); ++iter) { 296 list->Append(new base::StringValue(iter->first)); 297 } 298 dict->Set("bad_proxy_list", list); 299 return dict; 300} 301 302// Returns NetLog parameters on a successfuly proxy resolution. 303base::Value* NetLogFinishedResolvingProxyCallback( 304 ProxyInfo* result, 305 NetLog::LogLevel /* log_level */) { 306 base::DictionaryValue* dict = new base::DictionaryValue(); 307 dict->SetString("pac_string", result->ToPacString()); 308 return dict; 309} 310 311#if defined(OS_CHROMEOS) 312class UnsetProxyConfigService : public ProxyConfigService { 313 public: 314 UnsetProxyConfigService() {} 315 virtual ~UnsetProxyConfigService() {} 316 317 virtual void AddObserver(Observer* observer) OVERRIDE {} 318 virtual void RemoveObserver(Observer* observer) OVERRIDE {} 319 virtual ConfigAvailability GetLatestProxyConfig( 320 ProxyConfig* config) OVERRIDE { 321 return CONFIG_UNSET; 322 } 323}; 324#endif 325 326} // namespace 327 328// ProxyService::InitProxyResolver -------------------------------------------- 329 330// This glues together two asynchronous steps: 331// (1) ProxyScriptDecider -- try to fetch/validate a sequence of PAC scripts 332// to figure out what we should configure against. 333// (2) Feed the fetched PAC script into the ProxyResolver. 334// 335// InitProxyResolver is a single-use class which encapsulates cancellation as 336// part of its destructor. Start() or StartSkipDecider() should be called just 337// once. The instance can be destroyed at any time, and the request will be 338// cancelled. 339 340class ProxyService::InitProxyResolver { 341 public: 342 InitProxyResolver() 343 : proxy_resolver_(NULL), 344 next_state_(STATE_NONE), 345 quick_check_enabled_(true) { 346 } 347 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. 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. 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. 402 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. 409 ProxyResolverScriptData* script_data() { 410 DCHECK_EQ(STATE_NONE, next_state_); 411 return script_data_.get(); 412 } 413 414 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 423 void set_quick_check_enabled(bool enabled) { quick_check_enabled_ = enabled; } 424 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 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 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 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 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 493 int DoSetPacScriptComplete(int result) { 494 return result; 495 } 496 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 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. 528class 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. 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 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 582 static const PacPollPolicy* set_policy(const PacPollPolicy* policy) { 583 const PacPollPolicy* prev = poll_policy_; 584 poll_policy_ = policy; 585 return prev; 586 } 587 588 void set_quick_check_enabled(bool enabled) { quick_check_enabled_ = enabled; } 589 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). 594 const PacPollPolicy* poll_policy() { 595 if (poll_policy_) 596 return poll_policy_; 597 return &default_poll_policy_; 598 } 599 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 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 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 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 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 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 727const ProxyService::PacPollPolicy* 728 ProxyService::ProxyScriptDeciderPoller::poll_policy_ = NULL; 729 730// ProxyService::PacRequest --------------------------------------------------- 731 732class ProxyService::PacRequest 733 : public base::RefCounted<ProxyService::PacRequest> { 734 public: 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. 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 768 bool is_started() const { 769 // Note that !! casts to bool. (VS gives a warning otherwise). 770 return !!resolve_job_; 771 } 772 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 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 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. 804 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. 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 832 BoundNetLog* net_log() { return &net_log_; } 833 834 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 843 ~PacRequest() {} 844 845 // Callback for when the ProxyResolver request has completed. 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 858 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 878ProxyService::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 894ProxyService* 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 916ProxyService* 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 925ProxyService* 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 933ProxyService* 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 940ProxyService* ProxyService::CreateDirect() { 941 return CreateDirectWithNetLog(NULL); 942} 943 944ProxyService* ProxyService::CreateDirectWithNetLog(NetLog* net_log) { 945 // Use direct connections. 946 return new ProxyService(new ProxyConfigServiceDirect, new ProxyResolverNull, 947 net_log); 948} 949 950// static 951ProxyService* 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 967int 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 1019int 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 1043ProxyService::~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 1056void 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 1070void 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 1093void 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 1117void 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 1168int 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 1212bool 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 1227void 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 1249void ProxyService::CancelPacRequest(PacRequest* req) { 1250 DCHECK(CalledOnValidThread()); 1251 DCHECK(req); 1252 req->Cancel(); 1253 RemovePendingRequest(req); 1254} 1255 1256LoadState 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 1263bool 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 1269void 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 1276int 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 1311void 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 1322ProxyScriptFetcher* ProxyService::GetProxyScriptFetcher() const { 1323 DCHECK(CalledOnValidThread()); 1324 return proxy_script_fetcher_.get(); 1325} 1326 1327ProxyService::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 1344void 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 1361void ProxyService::ForceReloadProxyConfig() { 1362 DCHECK(CalledOnValidThread()); 1363 ResetProxyConfig(false); 1364 ApplyProxyConfigIfAvailable(); 1365} 1366 1367// static 1368ProxyConfigService* 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 1417const ProxyService::PacPollPolicy* ProxyService::set_pac_script_poll_policy( 1418 const PacPollPolicy* policy) { 1419 return ProxyScriptDeciderPoller::set_policy(policy); 1420} 1421 1422// static 1423scoped_ptr<ProxyService::PacPollPolicy> 1424 ProxyService::CreateDefaultPacPollPolicy() { 1425 return scoped_ptr<PacPollPolicy>(new DefaultPollPolicy()); 1426} 1427 1428void 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 1445void 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 1464void 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 1499void 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 1536void 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 1560void 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 1570void ProxyService::OnDNSChanged() { 1571 OnIPAddressChanged(); 1572} 1573 1574SyncProxyServiceHelper::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 1585int 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 1603int 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 1621SyncProxyServiceHelper::~SyncProxyServiceHelper() {} 1622 1623void 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 1632void 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 1642void SyncProxyServiceHelper::OnCompletion(int rv) { 1643 result_ = rv; 1644 event_.Signal(); 1645} 1646 1647} // namespace net 1648