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/net_errors.h" 21 #include "net/base/net_log.h" 22 #include "net/base/net_util.h" 23 #include "net/proxy/dhcp_proxy_script_fetcher.h" 24 #include "net/proxy/multi_threaded_proxy_resolver.h" 25 #include "net/proxy/network_delegate_error_observer.h" 26 #include "net/proxy/proxy_config_service_fixed.h" 27 #include "net/proxy/proxy_resolver.h" 28 #include "net/proxy/proxy_script_decider.h" 29 #include "net/proxy/proxy_script_fetcher.h" 30 #include "net/url_request/url_request_context.h" 31 #include "url/gurl.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 48 using base::TimeDelta; 49 using base::TimeTicks; 50 51 namespace net { 52 53 namespace { 54 55 const 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. 75 const int64 kDelayAfterNetworkChangesMs = 2000; 76 77 // This is the default policy for polling the PAC script. 78 // 79 // In response to a failure, the poll intervals are: 80 // 0: 8 seconds (scheduled on timer) 81 // 1: 32 seconds 82 // 2: 2 minutes 83 // 3+: 4 hours 84 // 85 // In response to a success, the poll intervals are: 86 // 0+: 12 hours 87 // 88 // Only the 8 second poll is scheduled on a timer, the rest happen in response 89 // to network activity (and hence will take longer than the written time). 90 // 91 // Explanation for these values: 92 // 93 // TODO(eroman): These values are somewhat arbitrary, and need to be tuned 94 // using some histograms data. Trying to be conservative so as not to break 95 // existing setups when deployed. A simple exponential retry scheme would be 96 // more elegant, but places more load on server. 97 // 98 // The motivation for trying quickly after failures (8 seconds) is to recover 99 // from spurious network failures, which are common after the IP address has 100 // just changed (like DNS failing to resolve). The next 32 second boundary is 101 // to try and catch other VPN weirdness which anecdotally I have seen take 102 // 10+ seconds for some users. 103 // 104 // The motivation for re-trying after a success is to check for possible 105 // content changes to the script, or to the WPAD auto-discovery results. We are 106 // not very aggressive with these checks so as to minimize the risk of 107 // overloading existing PAC setups. Moreover it is unlikely that PAC scripts 108 // change very frequently in existing setups. More research is needed to 109 // motivate what safe values are here, and what other user agents do. 110 // 111 // Comparison to other browsers: 112 // 113 // In Firefox the PAC URL is re-tried on failures according to 114 // network.proxy.autoconfig_retry_interval_min and 115 // network.proxy.autoconfig_retry_interval_max. The defaults are 5 seconds and 116 // 5 minutes respectively. It doubles the interval at each attempt. 117 // 118 // TODO(eroman): Figure out what Internet Explorer does. 119 class DefaultPollPolicy : public ProxyService::PacPollPolicy { 120 public: 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. 161 class 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. 175 class 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. 210 class 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. 249 class 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. 276 base::Value* NetLogProxyConfigChangedCallback( 277 const ProxyConfig* old_config, 278 const ProxyConfig* new_config, 279 NetLog::LogLevel /* log_level */) { 280 base::DictionaryValue* dict = new base::DictionaryValue(); 281 // The "old_config" is optional -- the first notification will not have 282 // any "previous" configuration. 283 if (old_config->is_valid()) 284 dict->Set("old_config", old_config->ToValue()); 285 dict->Set("new_config", new_config->ToValue()); 286 return dict; 287 } 288 289 base::Value* NetLogBadProxyListCallback(const ProxyRetryInfoMap* retry_info, 290 NetLog::LogLevel /* log_level */) { 291 base::DictionaryValue* dict = new base::DictionaryValue(); 292 base::ListValue* list = new base::ListValue(); 293 294 for (ProxyRetryInfoMap::const_iterator iter = retry_info->begin(); 295 iter != retry_info->end(); ++iter) { 296 list->Append(new base::StringValue(iter->first)); 297 } 298 dict->Set("bad_proxy_list", list); 299 return dict; 300 } 301 302 // Returns NetLog parameters on a successfuly proxy resolution. 303 base::Value* NetLogFinishedResolvingProxyCallback( 304 ProxyInfo* result, 305 NetLog::LogLevel /* log_level */) { 306 base::DictionaryValue* dict = new base::DictionaryValue(); 307 dict->SetString("pac_string", result->ToPacString()); 308 return dict; 309 } 310 311 #if defined(OS_CHROMEOS) 312 class UnsetProxyConfigService : public ProxyConfigService { 313 public: 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 340 class 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_.get()); 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. 522 class 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 base::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 base::MessageLoop::current()->PostTask( 642 FROM_HERE, 643 base::Bind(&ProxyScriptDeciderPoller::NotifyProxyServiceOfChange, 644 weak_factory_.GetWeakPtr(), 645 result, 646 make_scoped_refptr(decider_->script_data()), 647 decider_->effective_config())); 648 return; 649 } 650 651 decider_.reset(); 652 653 // Decide when the next poll should take place, and possibly start the 654 // next timer. 655 next_poll_mode_ = poll_policy()->GetNextDelay( 656 last_error_, next_poll_delay_, &next_poll_delay_); 657 TryToStartNextPoll(false); 658 } 659 660 bool HasScriptDataChanged(int result, ProxyResolverScriptData* script_data) { 661 if (result != last_error_) { 662 // Something changed -- it was failing before and now it succeeded, or 663 // conversely it succeeded before and now it failed. Or it failed in 664 // both cases, however the specific failure error codes differ. 665 return true; 666 } 667 668 if (result != OK) { 669 // If it failed last time and failed again with the same error code this 670 // time, then nothing has actually changed. 671 return false; 672 } 673 674 // Otherwise if it succeeded both this time and last time, we need to look 675 // closer and see if we ended up downloading different content for the PAC 676 // script. 677 return !script_data->Equals(last_script_data_.get()); 678 } 679 680 void NotifyProxyServiceOfChange( 681 int result, 682 const scoped_refptr<ProxyResolverScriptData>& script_data, 683 const ProxyConfig& effective_config) { 684 // Note that |this| may be deleted after calling into the ProxyService. 685 change_callback_.Run(result, script_data.get(), effective_config); 686 } 687 688 base::WeakPtrFactory<ProxyScriptDeciderPoller> weak_factory_; 689 690 ChangeCallback change_callback_; 691 ProxyConfig config_; 692 bool proxy_resolver_expects_pac_bytes_; 693 ProxyScriptFetcher* proxy_script_fetcher_; 694 DhcpProxyScriptFetcher* dhcp_proxy_script_fetcher_; 695 696 int last_error_; 697 scoped_refptr<ProxyResolverScriptData> last_script_data_; 698 699 scoped_ptr<ProxyScriptDecider> decider_; 700 TimeDelta next_poll_delay_; 701 PacPollPolicy::Mode next_poll_mode_; 702 703 TimeTicks last_poll_time_; 704 705 // Polling policy injected by unit-tests. Otherwise this is NULL and the 706 // default policy will be used. 707 static const PacPollPolicy* poll_policy_; 708 709 const DefaultPollPolicy default_poll_policy_; 710 711 DISALLOW_COPY_AND_ASSIGN(ProxyScriptDeciderPoller); 712 }; 713 714 // static 715 const ProxyService::PacPollPolicy* 716 ProxyService::ProxyScriptDeciderPoller::poll_policy_ = NULL; 717 718 // ProxyService::PacRequest --------------------------------------------------- 719 720 class ProxyService::PacRequest 721 : public base::RefCounted<ProxyService::PacRequest> { 722 public: 723 PacRequest(ProxyService* service, 724 const GURL& url, 725 ProxyInfo* results, 726 const net::CompletionCallback& user_callback, 727 const BoundNetLog& net_log) 728 : service_(service), 729 user_callback_(user_callback), 730 results_(results), 731 url_(url), 732 resolve_job_(NULL), 733 config_id_(ProxyConfig::kInvalidConfigID), 734 config_source_(PROXY_CONFIG_SOURCE_UNKNOWN), 735 net_log_(net_log) { 736 DCHECK(!user_callback.is_null()); 737 } 738 739 // Starts the resolve proxy request. 740 int Start() { 741 DCHECK(!was_cancelled()); 742 DCHECK(!is_started()); 743 744 DCHECK(service_->config_.is_valid()); 745 746 config_id_ = service_->config_.id(); 747 config_source_ = service_->config_.source(); 748 proxy_resolve_start_time_ = TimeTicks::Now(); 749 750 return resolver()->GetProxyForURL( 751 url_, results_, 752 base::Bind(&PacRequest::QueryComplete, base::Unretained(this)), 753 &resolve_job_, net_log_); 754 } 755 756 bool is_started() const { 757 // Note that !! casts to bool. (VS gives a warning otherwise). 758 return !!resolve_job_; 759 } 760 761 void StartAndCompleteCheckingForSynchronous() { 762 int rv = service_->TryToCompleteSynchronously(url_, results_); 763 if (rv == ERR_IO_PENDING) 764 rv = Start(); 765 if (rv != ERR_IO_PENDING) 766 QueryComplete(rv); 767 } 768 769 void CancelResolveJob() { 770 DCHECK(is_started()); 771 // The request may already be running in the resolver. 772 resolver()->CancelRequest(resolve_job_); 773 resolve_job_ = NULL; 774 DCHECK(!is_started()); 775 } 776 777 void Cancel() { 778 net_log_.AddEvent(NetLog::TYPE_CANCELLED); 779 780 if (is_started()) 781 CancelResolveJob(); 782 783 // Mark as cancelled, to prevent accessing this again later. 784 service_ = NULL; 785 user_callback_.Reset(); 786 results_ = NULL; 787 788 net_log_.EndEvent(NetLog::TYPE_PROXY_SERVICE); 789 } 790 791 // Returns true if Cancel() has been called. 792 bool was_cancelled() const { 793 return user_callback_.is_null(); 794 } 795 796 // Helper to call after ProxyResolver completion (both synchronous and 797 // asynchronous). Fixes up the result that is to be returned to user. 798 int QueryDidComplete(int result_code) { 799 DCHECK(!was_cancelled()); 800 801 // Note that DidFinishResolvingProxy might modify |results_|. 802 int rv = service_->DidFinishResolvingProxy(results_, result_code, net_log_); 803 804 // Make a note in the results which configuration was in use at the 805 // time of the resolve. 806 results_->config_id_ = config_id_; 807 results_->config_source_ = config_source_; 808 results_->did_use_pac_script_ = true; 809 results_->proxy_resolve_start_time_ = proxy_resolve_start_time_; 810 results_->proxy_resolve_end_time_ = TimeTicks::Now(); 811 812 // Reset the state associated with in-progress-resolve. 813 resolve_job_ = NULL; 814 config_id_ = ProxyConfig::kInvalidConfigID; 815 config_source_ = PROXY_CONFIG_SOURCE_UNKNOWN; 816 817 return rv; 818 } 819 820 BoundNetLog* net_log() { return &net_log_; } 821 822 LoadState GetLoadState() const { 823 if (is_started()) 824 return resolver()->GetLoadState(resolve_job_); 825 return LOAD_STATE_RESOLVING_PROXY_FOR_URL; 826 } 827 828 private: 829 friend class base::RefCounted<ProxyService::PacRequest>; 830 831 ~PacRequest() {} 832 833 // Callback for when the ProxyResolver request has completed. 834 void QueryComplete(int result_code) { 835 result_code = QueryDidComplete(result_code); 836 837 // Remove this completed PacRequest from the service's pending list. 838 /// (which will probably cause deletion of |this|). 839 if (!user_callback_.is_null()) { 840 net::CompletionCallback callback = user_callback_; 841 service_->RemovePendingRequest(this); 842 callback.Run(result_code); 843 } 844 } 845 846 ProxyResolver* resolver() const { return service_->resolver_.get(); } 847 848 // Note that we don't hold a reference to the ProxyService. Outstanding 849 // requests are cancelled during ~ProxyService, so this is guaranteed 850 // to be valid throughout our lifetime. 851 ProxyService* service_; 852 net::CompletionCallback user_callback_; 853 ProxyInfo* results_; 854 GURL url_; 855 ProxyResolver::RequestHandle resolve_job_; 856 ProxyConfig::ID config_id_; // The config id when the resolve was started. 857 ProxyConfigSource config_source_; // The source of proxy settings. 858 BoundNetLog net_log_; 859 // Time when the PAC is started. Cached here since resetting ProxyInfo also 860 // clears the proxy times. 861 TimeTicks proxy_resolve_start_time_; 862 }; 863 864 // ProxyService --------------------------------------------------------------- 865 866 ProxyService::ProxyService(ProxyConfigService* config_service, 867 ProxyResolver* resolver, 868 NetLog* net_log) 869 : resolver_(resolver), 870 next_config_id_(1), 871 current_state_(STATE_NONE) , 872 net_log_(net_log), 873 stall_proxy_auto_config_delay_(TimeDelta::FromMilliseconds( 874 kDelayAfterNetworkChangesMs)) { 875 NetworkChangeNotifier::AddIPAddressObserver(this); 876 NetworkChangeNotifier::AddDNSObserver(this); 877 ResetConfigService(config_service); 878 } 879 880 // static 881 ProxyService* ProxyService::CreateUsingSystemProxyResolver( 882 ProxyConfigService* proxy_config_service, 883 size_t num_pac_threads, 884 NetLog* net_log) { 885 DCHECK(proxy_config_service); 886 887 if (!ProxyResolverFactoryForSystem::IsSupported()) { 888 LOG(WARNING) << "PAC support disabled because there is no " 889 "system implementation"; 890 return CreateWithoutProxyResolver(proxy_config_service, net_log); 891 } 892 893 if (num_pac_threads == 0) 894 num_pac_threads = kDefaultNumPacThreads; 895 896 ProxyResolver* proxy_resolver = new MultiThreadedProxyResolver( 897 new ProxyResolverFactoryForSystem(), num_pac_threads); 898 899 return new ProxyService(proxy_config_service, proxy_resolver, net_log); 900 } 901 902 // static 903 ProxyService* ProxyService::CreateWithoutProxyResolver( 904 ProxyConfigService* proxy_config_service, 905 NetLog* net_log) { 906 return new ProxyService(proxy_config_service, 907 new ProxyResolverNull(), 908 net_log); 909 } 910 911 // static 912 ProxyService* ProxyService::CreateFixed(const ProxyConfig& pc) { 913 // TODO(eroman): This isn't quite right, won't work if |pc| specifies 914 // a PAC script. 915 return CreateUsingSystemProxyResolver(new ProxyConfigServiceFixed(pc), 916 0, NULL); 917 } 918 919 // static 920 ProxyService* ProxyService::CreateFixed(const std::string& proxy) { 921 net::ProxyConfig proxy_config; 922 proxy_config.proxy_rules().ParseFromString(proxy); 923 return ProxyService::CreateFixed(proxy_config); 924 } 925 926 // static 927 ProxyService* ProxyService::CreateDirect() { 928 return CreateDirectWithNetLog(NULL); 929 } 930 931 ProxyService* ProxyService::CreateDirectWithNetLog(NetLog* net_log) { 932 // Use direct connections. 933 return new ProxyService(new ProxyConfigServiceDirect, new ProxyResolverNull, 934 net_log); 935 } 936 937 // static 938 ProxyService* ProxyService::CreateFixedFromPacResult( 939 const std::string& pac_string) { 940 941 // We need the settings to contain an "automatic" setting, otherwise the 942 // ProxyResolver dependency we give it will never be used. 943 scoped_ptr<ProxyConfigService> proxy_config_service( 944 new ProxyConfigServiceFixed(ProxyConfig::CreateAutoDetect())); 945 946 scoped_ptr<ProxyResolver> proxy_resolver( 947 new ProxyResolverFromPacString(pac_string)); 948 949 return new ProxyService(proxy_config_service.release(), 950 proxy_resolver.release(), 951 NULL); 952 } 953 954 int ProxyService::ResolveProxy(const GURL& raw_url, 955 ProxyInfo* result, 956 const net::CompletionCallback& callback, 957 PacRequest** pac_request, 958 const BoundNetLog& net_log) { 959 DCHECK(CalledOnValidThread()); 960 DCHECK(!callback.is_null()); 961 962 net_log.BeginEvent(NetLog::TYPE_PROXY_SERVICE); 963 964 // Notify our polling-based dependencies that a resolve is taking place. 965 // This way they can schedule their polls in response to network activity. 966 config_service_->OnLazyPoll(); 967 if (script_poller_.get()) 968 script_poller_->OnLazyPoll(); 969 970 if (current_state_ == STATE_NONE) 971 ApplyProxyConfigIfAvailable(); 972 973 // Strip away any reference fragments and the username/password, as they 974 // are not relevant to proxy resolution. 975 GURL url = SimplifyUrlForRequest(raw_url); 976 977 // Check if the request can be completed right away. (This is the case when 978 // using a direct connection for example). 979 int rv = TryToCompleteSynchronously(url, result); 980 if (rv != ERR_IO_PENDING) 981 return DidFinishResolvingProxy(result, rv, net_log); 982 983 scoped_refptr<PacRequest> req( 984 new PacRequest(this, url, result, callback, net_log)); 985 986 if (current_state_ == STATE_READY) { 987 // Start the resolve request. 988 rv = req->Start(); 989 if (rv != ERR_IO_PENDING) 990 return req->QueryDidComplete(rv); 991 } else { 992 req->net_log()->BeginEvent(NetLog::TYPE_PROXY_SERVICE_WAITING_FOR_INIT_PAC); 993 } 994 995 DCHECK_EQ(ERR_IO_PENDING, rv); 996 DCHECK(!ContainsPendingRequest(req.get())); 997 pending_requests_.push_back(req); 998 999 // Completion will be notified through |callback|, unless the caller cancels 1000 // the request using |pac_request|. 1001 if (pac_request) 1002 *pac_request = req.get(); 1003 return rv; // ERR_IO_PENDING 1004 } 1005 1006 int ProxyService::TryToCompleteSynchronously(const GURL& url, 1007 ProxyInfo* result) { 1008 DCHECK_NE(STATE_NONE, current_state_); 1009 1010 if (current_state_ != STATE_READY) 1011 return ERR_IO_PENDING; // Still initializing. 1012 1013 DCHECK_NE(config_.id(), ProxyConfig::kInvalidConfigID); 1014 1015 // If it was impossible to fetch or parse the PAC script, we cannot complete 1016 // the request here and bail out. 1017 if (permanent_error_ != OK) 1018 return permanent_error_; 1019 1020 if (config_.HasAutomaticSettings()) 1021 return ERR_IO_PENDING; // Must submit the request to the proxy resolver. 1022 1023 // Use the manual proxy settings. 1024 config_.proxy_rules().Apply(url, result); 1025 result->config_source_ = config_.source(); 1026 result->config_id_ = config_.id(); 1027 return OK; 1028 } 1029 1030 ProxyService::~ProxyService() { 1031 NetworkChangeNotifier::RemoveIPAddressObserver(this); 1032 NetworkChangeNotifier::RemoveDNSObserver(this); 1033 config_service_->RemoveObserver(this); 1034 1035 // Cancel any inprogress requests. 1036 for (PendingRequests::iterator it = pending_requests_.begin(); 1037 it != pending_requests_.end(); 1038 ++it) { 1039 (*it)->Cancel(); 1040 } 1041 } 1042 1043 void ProxyService::SuspendAllPendingRequests() { 1044 for (PendingRequests::iterator it = pending_requests_.begin(); 1045 it != pending_requests_.end(); 1046 ++it) { 1047 PacRequest* req = it->get(); 1048 if (req->is_started()) { 1049 req->CancelResolveJob(); 1050 1051 req->net_log()->BeginEvent( 1052 NetLog::TYPE_PROXY_SERVICE_WAITING_FOR_INIT_PAC); 1053 } 1054 } 1055 } 1056 1057 void ProxyService::SetReady() { 1058 DCHECK(!init_proxy_resolver_.get()); 1059 current_state_ = STATE_READY; 1060 1061 // Make a copy in case |this| is deleted during the synchronous completion 1062 // of one of the requests. If |this| is deleted then all of the PacRequest 1063 // instances will be Cancel()-ed. 1064 PendingRequests pending_copy = pending_requests_; 1065 1066 for (PendingRequests::iterator it = pending_copy.begin(); 1067 it != pending_copy.end(); 1068 ++it) { 1069 PacRequest* req = it->get(); 1070 if (!req->is_started() && !req->was_cancelled()) { 1071 req->net_log()->EndEvent(NetLog::TYPE_PROXY_SERVICE_WAITING_FOR_INIT_PAC); 1072 1073 // Note that we re-check for synchronous completion, in case we are 1074 // no longer using a ProxyResolver (can happen if we fell-back to manual). 1075 req->StartAndCompleteCheckingForSynchronous(); 1076 } 1077 } 1078 } 1079 1080 void ProxyService::ApplyProxyConfigIfAvailable() { 1081 DCHECK_EQ(STATE_NONE, current_state_); 1082 1083 config_service_->OnLazyPoll(); 1084 1085 // If we have already fetched the configuration, start applying it. 1086 if (fetched_config_.is_valid()) { 1087 InitializeUsingLastFetchedConfig(); 1088 return; 1089 } 1090 1091 // Otherwise we need to first fetch the configuration. 1092 current_state_ = STATE_WAITING_FOR_PROXY_CONFIG; 1093 1094 // Retrieve the current proxy configuration from the ProxyConfigService. 1095 // If a configuration is not available yet, we will get called back later 1096 // by our ProxyConfigService::Observer once it changes. 1097 ProxyConfig config; 1098 ProxyConfigService::ConfigAvailability availability = 1099 config_service_->GetLatestProxyConfig(&config); 1100 if (availability != ProxyConfigService::CONFIG_PENDING) 1101 OnProxyConfigChanged(config, availability); 1102 } 1103 1104 void ProxyService::OnInitProxyResolverComplete(int result) { 1105 DCHECK_EQ(STATE_WAITING_FOR_INIT_PROXY_RESOLVER, current_state_); 1106 DCHECK(init_proxy_resolver_.get()); 1107 DCHECK(fetched_config_.HasAutomaticSettings()); 1108 config_ = init_proxy_resolver_->effective_config(); 1109 1110 // At this point we have decided which proxy settings to use (i.e. which PAC 1111 // script if any). We start up a background poller to periodically revisit 1112 // this decision. If the contents of the PAC script change, or if the 1113 // result of proxy auto-discovery changes, this poller will notice it and 1114 // will trigger a re-initialization using the newly discovered PAC. 1115 script_poller_.reset(new ProxyScriptDeciderPoller( 1116 base::Bind(&ProxyService::InitializeUsingDecidedConfig, 1117 base::Unretained(this)), 1118 fetched_config_, 1119 resolver_->expects_pac_bytes(), 1120 proxy_script_fetcher_.get(), 1121 dhcp_proxy_script_fetcher_.get(), 1122 result, 1123 init_proxy_resolver_->script_data(), 1124 NULL)); 1125 1126 init_proxy_resolver_.reset(); 1127 1128 if (result != OK) { 1129 if (fetched_config_.pac_mandatory()) { 1130 VLOG(1) << "Failed configuring with mandatory PAC script, blocking all " 1131 "traffic."; 1132 config_ = fetched_config_; 1133 result = ERR_MANDATORY_PROXY_CONFIGURATION_FAILED; 1134 } else { 1135 VLOG(1) << "Failed configuring with PAC script, falling-back to manual " 1136 "proxy servers."; 1137 config_ = fetched_config_; 1138 config_.ClearAutomaticSettings(); 1139 result = OK; 1140 } 1141 } 1142 permanent_error_ = result; 1143 1144 // TODO(eroman): Make this ID unique in the case where configuration changed 1145 // due to ProxyScriptDeciderPoller. 1146 config_.set_id(fetched_config_.id()); 1147 config_.set_source(fetched_config_.source()); 1148 1149 // Resume any requests which we had to defer until the PAC script was 1150 // downloaded. 1151 SetReady(); 1152 } 1153 1154 int ProxyService::ReconsiderProxyAfterError(const GURL& url, 1155 ProxyInfo* result, 1156 const CompletionCallback& callback, 1157 PacRequest** pac_request, 1158 const BoundNetLog& net_log) { 1159 DCHECK(CalledOnValidThread()); 1160 1161 // Check to see if we have a new config since ResolveProxy was called. We 1162 // want to re-run ResolveProxy in two cases: 1) we have a new config, or 2) a 1163 // direct connection failed and we never tried the current config. 1164 1165 bool re_resolve = result->config_id_ != config_.id(); 1166 1167 if (re_resolve) { 1168 // If we have a new config or the config was never tried, we delete the 1169 // list of bad proxies and we try again. 1170 proxy_retry_info_.clear(); 1171 return ResolveProxy(url, result, callback, pac_request, net_log); 1172 } 1173 1174 // We don't have new proxy settings to try, try to fallback to the next proxy 1175 // in the list. 1176 bool did_fallback = result->Fallback(net_log); 1177 1178 // Return synchronous failure if there is nothing left to fall-back to. 1179 // TODO(eroman): This is a yucky API, clean it up. 1180 return did_fallback ? OK : ERR_FAILED; 1181 } 1182 1183 bool ProxyService::MarkProxyAsBad(const ProxyInfo& result, 1184 const BoundNetLog& net_log) { 1185 result.proxy_list_.UpdateRetryInfoOnFallback(&proxy_retry_info_, net_log); 1186 return result.proxy_list_.HasUntriedProxies(proxy_retry_info_); 1187 } 1188 1189 void ProxyService::ReportSuccess(const ProxyInfo& result) { 1190 DCHECK(CalledOnValidThread()); 1191 1192 const ProxyRetryInfoMap& new_retry_info = result.proxy_retry_info(); 1193 if (new_retry_info.empty()) 1194 return; 1195 1196 for (ProxyRetryInfoMap::const_iterator iter = new_retry_info.begin(); 1197 iter != new_retry_info.end(); ++iter) { 1198 ProxyRetryInfoMap::iterator existing = proxy_retry_info_.find(iter->first); 1199 if (existing == proxy_retry_info_.end()) 1200 proxy_retry_info_[iter->first] = iter->second; 1201 else if (existing->second.bad_until < iter->second.bad_until) 1202 existing->second.bad_until = iter->second.bad_until; 1203 } 1204 if (net_log_) { 1205 net_log_->AddGlobalEntry( 1206 NetLog::TYPE_BAD_PROXY_LIST_REPORTED, 1207 base::Bind(&NetLogBadProxyListCallback, &new_retry_info)); 1208 } 1209 } 1210 1211 void ProxyService::CancelPacRequest(PacRequest* req) { 1212 DCHECK(CalledOnValidThread()); 1213 DCHECK(req); 1214 req->Cancel(); 1215 RemovePendingRequest(req); 1216 } 1217 1218 LoadState ProxyService::GetLoadState(const PacRequest* req) const { 1219 CHECK(req); 1220 if (current_state_ == STATE_WAITING_FOR_INIT_PROXY_RESOLVER) 1221 return init_proxy_resolver_->GetLoadState(); 1222 return req->GetLoadState(); 1223 } 1224 1225 bool ProxyService::ContainsPendingRequest(PacRequest* req) { 1226 PendingRequests::iterator it = std::find( 1227 pending_requests_.begin(), pending_requests_.end(), req); 1228 return pending_requests_.end() != it; 1229 } 1230 1231 void ProxyService::RemovePendingRequest(PacRequest* req) { 1232 DCHECK(ContainsPendingRequest(req)); 1233 PendingRequests::iterator it = std::find( 1234 pending_requests_.begin(), pending_requests_.end(), req); 1235 pending_requests_.erase(it); 1236 } 1237 1238 int ProxyService::DidFinishResolvingProxy(ProxyInfo* result, 1239 int result_code, 1240 const BoundNetLog& net_log) { 1241 // Log the result of the proxy resolution. 1242 if (result_code == OK) { 1243 // When logging all events is enabled, dump the proxy list. 1244 if (net_log.IsLoggingAllEvents()) { 1245 net_log.AddEvent( 1246 NetLog::TYPE_PROXY_SERVICE_RESOLVED_PROXY_LIST, 1247 base::Bind(&NetLogFinishedResolvingProxyCallback, result)); 1248 } 1249 result->DeprioritizeBadProxies(proxy_retry_info_); 1250 } else { 1251 net_log.AddEventWithNetErrorCode( 1252 NetLog::TYPE_PROXY_SERVICE_RESOLVED_PROXY_LIST, result_code); 1253 1254 if (!config_.pac_mandatory()) { 1255 // Fall-back to direct when the proxy resolver fails. This corresponds 1256 // with a javascript runtime error in the PAC script. 1257 // 1258 // This implicit fall-back to direct matches Firefox 3.5 and 1259 // Internet Explorer 8. For more information, see: 1260 // 1261 // http://www.chromium.org/developers/design-documents/proxy-settings-fallback 1262 result->UseDirect(); 1263 result_code = OK; 1264 } else { 1265 result_code = ERR_MANDATORY_PROXY_CONFIGURATION_FAILED; 1266 } 1267 } 1268 1269 net_log.EndEvent(NetLog::TYPE_PROXY_SERVICE); 1270 return result_code; 1271 } 1272 1273 void ProxyService::SetProxyScriptFetchers( 1274 ProxyScriptFetcher* proxy_script_fetcher, 1275 DhcpProxyScriptFetcher* dhcp_proxy_script_fetcher) { 1276 DCHECK(CalledOnValidThread()); 1277 State previous_state = ResetProxyConfig(false); 1278 proxy_script_fetcher_.reset(proxy_script_fetcher); 1279 dhcp_proxy_script_fetcher_.reset(dhcp_proxy_script_fetcher); 1280 if (previous_state != STATE_NONE) 1281 ApplyProxyConfigIfAvailable(); 1282 } 1283 1284 ProxyScriptFetcher* ProxyService::GetProxyScriptFetcher() const { 1285 DCHECK(CalledOnValidThread()); 1286 return proxy_script_fetcher_.get(); 1287 } 1288 1289 ProxyService::State ProxyService::ResetProxyConfig(bool reset_fetched_config) { 1290 DCHECK(CalledOnValidThread()); 1291 State previous_state = current_state_; 1292 1293 permanent_error_ = OK; 1294 proxy_retry_info_.clear(); 1295 script_poller_.reset(); 1296 init_proxy_resolver_.reset(); 1297 SuspendAllPendingRequests(); 1298 config_ = ProxyConfig(); 1299 if (reset_fetched_config) 1300 fetched_config_ = ProxyConfig(); 1301 current_state_ = STATE_NONE; 1302 1303 return previous_state; 1304 } 1305 1306 void ProxyService::ResetConfigService( 1307 ProxyConfigService* new_proxy_config_service) { 1308 DCHECK(CalledOnValidThread()); 1309 State previous_state = ResetProxyConfig(true); 1310 1311 // Release the old configuration service. 1312 if (config_service_.get()) 1313 config_service_->RemoveObserver(this); 1314 1315 // Set the new configuration service. 1316 config_service_.reset(new_proxy_config_service); 1317 config_service_->AddObserver(this); 1318 1319 if (previous_state != STATE_NONE) 1320 ApplyProxyConfigIfAvailable(); 1321 } 1322 1323 void ProxyService::PurgeMemory() { 1324 DCHECK(CalledOnValidThread()); 1325 if (resolver_.get()) 1326 resolver_->PurgeMemory(); 1327 } 1328 1329 void ProxyService::ForceReloadProxyConfig() { 1330 DCHECK(CalledOnValidThread()); 1331 ResetProxyConfig(false); 1332 ApplyProxyConfigIfAvailable(); 1333 } 1334 1335 // static 1336 ProxyConfigService* ProxyService::CreateSystemProxyConfigService( 1337 base::SingleThreadTaskRunner* io_thread_task_runner, 1338 base::MessageLoop* file_loop) { 1339 #if defined(OS_WIN) 1340 return new ProxyConfigServiceWin(); 1341 #elif defined(OS_IOS) 1342 return new ProxyConfigServiceIOS(); 1343 #elif defined(OS_MACOSX) 1344 return new ProxyConfigServiceMac(io_thread_task_runner); 1345 #elif defined(OS_CHROMEOS) 1346 LOG(ERROR) << "ProxyConfigService for ChromeOS should be created in " 1347 << "profile_io_data.cc::CreateProxyConfigService and this should " 1348 << "be used only for examples."; 1349 return new UnsetProxyConfigService; 1350 #elif defined(OS_LINUX) 1351 ProxyConfigServiceLinux* linux_config_service = 1352 new ProxyConfigServiceLinux(); 1353 1354 // Assume we got called on the thread that runs the default glib 1355 // main loop, so the current thread is where we should be running 1356 // gconf calls from. 1357 scoped_refptr<base::SingleThreadTaskRunner> glib_thread_task_runner = 1358 base::ThreadTaskRunnerHandle::Get(); 1359 1360 // The file loop should be a MessageLoopForIO on Linux. 1361 DCHECK_EQ(base::MessageLoop::TYPE_IO, file_loop->type()); 1362 1363 // Synchronously fetch the current proxy config (since we are 1364 // running on glib_default_loop). Additionally register for 1365 // notifications (delivered in either |glib_default_loop| or 1366 // |file_loop|) to keep us updated when the proxy config changes. 1367 linux_config_service->SetupAndFetchInitialConfig( 1368 glib_thread_task_runner.get(), 1369 io_thread_task_runner, 1370 static_cast<base::MessageLoopForIO*>(file_loop)); 1371 1372 return linux_config_service; 1373 #elif defined(OS_ANDROID) 1374 return new ProxyConfigServiceAndroid( 1375 io_thread_task_runner, 1376 base::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 1385 const ProxyService::PacPollPolicy* ProxyService::set_pac_script_poll_policy( 1386 const PacPollPolicy* policy) { 1387 return ProxyScriptDeciderPoller::set_policy(policy); 1388 } 1389 1390 // static 1391 scoped_ptr<ProxyService::PacPollPolicy> 1392 ProxyService::CreateDefaultPacPollPolicy() { 1393 return scoped_ptr<PacPollPolicy>(new DefaultPollPolicy()); 1394 } 1395 1396 void 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 1431 void 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 1467 void 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 1491 void 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 1501 void ProxyService::OnDNSChanged() { 1502 OnIPAddressChanged(); 1503 } 1504 1505 SyncProxyServiceHelper::SyncProxyServiceHelper( 1506 base::MessageLoop* io_message_loop, 1507 ProxyService* proxy_service) 1508 : io_message_loop_(io_message_loop), 1509 proxy_service_(proxy_service), 1510 event_(false, false), 1511 callback_(base::Bind(&SyncProxyServiceHelper::OnCompletion, 1512 base::Unretained(this))) { 1513 DCHECK(io_message_loop_ != base::MessageLoop::current()); 1514 } 1515 1516 int SyncProxyServiceHelper::ResolveProxy(const GURL& url, 1517 ProxyInfo* proxy_info, 1518 const BoundNetLog& net_log) { 1519 DCHECK(io_message_loop_ != base::MessageLoop::current()); 1520 1521 io_message_loop_->PostTask( 1522 FROM_HERE, 1523 base::Bind(&SyncProxyServiceHelper::StartAsyncResolve, this, url, 1524 net_log)); 1525 1526 event_.Wait(); 1527 1528 if (result_ == net::OK) { 1529 *proxy_info = proxy_info_; 1530 } 1531 return result_; 1532 } 1533 1534 int SyncProxyServiceHelper::ReconsiderProxyAfterError( 1535 const GURL& url, ProxyInfo* proxy_info, const BoundNetLog& net_log) { 1536 DCHECK(io_message_loop_ != base::MessageLoop::current()); 1537 1538 io_message_loop_->PostTask( 1539 FROM_HERE, 1540 base::Bind(&SyncProxyServiceHelper::StartAsyncReconsider, this, url, 1541 net_log)); 1542 1543 event_.Wait(); 1544 1545 if (result_ == net::OK) { 1546 *proxy_info = proxy_info_; 1547 } 1548 return result_; 1549 } 1550 1551 SyncProxyServiceHelper::~SyncProxyServiceHelper() {} 1552 1553 void SyncProxyServiceHelper::StartAsyncResolve(const GURL& url, 1554 const BoundNetLog& net_log) { 1555 result_ = proxy_service_->ResolveProxy( 1556 url, &proxy_info_, callback_, NULL, net_log); 1557 if (result_ != net::ERR_IO_PENDING) { 1558 OnCompletion(result_); 1559 } 1560 } 1561 1562 void SyncProxyServiceHelper::StartAsyncReconsider(const GURL& url, 1563 const BoundNetLog& net_log) { 1564 result_ = proxy_service_->ReconsiderProxyAfterError( 1565 url, &proxy_info_, callback_, NULL, net_log); 1566 if (result_ != net::ERR_IO_PENDING) { 1567 OnCompletion(result_); 1568 } 1569 } 1570 1571 void SyncProxyServiceHelper::OnCompletion(int rv) { 1572 result_ = rv; 1573 event_.Signal(); 1574 } 1575 1576 } // namespace net 1577