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