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