1 // Copyright (c) 2011 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/compiler_specific.h" 10 #include "base/logging.h" 11 #include "base/message_loop.h" 12 #include "base/string_util.h" 13 #include "base/values.h" 14 #include "googleurl/src/gurl.h" 15 #include "net/base/net_errors.h" 16 #include "net/base/net_log.h" 17 #include "net/base/net_util.h" 18 #include "net/proxy/init_proxy_resolver.h" 19 #include "net/proxy/multi_threaded_proxy_resolver.h" 20 #include "net/proxy/proxy_config_service_fixed.h" 21 #include "net/proxy/proxy_resolver.h" 22 #include "net/proxy/proxy_resolver_js_bindings.h" 23 #ifndef ANDROID 24 #include "net/proxy/proxy_resolver_v8.h" 25 #endif 26 #include "net/proxy/proxy_script_fetcher.h" 27 #include "net/proxy/sync_host_resolver_bridge.h" 28 #include "net/url_request/url_request_context.h" 29 30 #if defined(OS_WIN) 31 #include "net/proxy/proxy_config_service_win.h" 32 #include "net/proxy/proxy_resolver_winhttp.h" 33 #elif defined(OS_MACOSX) 34 #include "net/proxy/proxy_config_service_mac.h" 35 #include "net/proxy/proxy_resolver_mac.h" 36 #elif defined(OS_LINUX) && !defined(OS_CHROMEOS) 37 #include "net/proxy/proxy_config_service_linux.h" 38 #endif 39 40 using base::TimeDelta; 41 using base::TimeTicks; 42 43 namespace net { 44 45 namespace { 46 47 const size_t kMaxNumNetLogEntries = 100; 48 const size_t kDefaultNumPacThreads = 4; 49 50 // When the IP address changes we don't immediately re-run proxy auto-config. 51 // Instead, we wait for |kNumMillisToStallAfterNetworkChanges| before 52 // attempting to re-valuate proxy auto-config. 53 // 54 // During this time window, any resolve requests sent to the ProxyService will 55 // be queued. Once we have waited the required amount of them, the proxy 56 // auto-config step will be run, and the queued requests resumed. 57 // 58 // The reason we play this game is that our signal for detecting network 59 // changes (NetworkChangeNotifier) may fire *before* the system's networking 60 // dependencies are fully configured. This is a problem since it means if 61 // we were to run proxy auto-config right away, it could fail due to spurious 62 // DNS failures. (see http://crbug.com/50779 for more details.) 63 // 64 // By adding the wait window, we give things a chance to get properly set up. 65 // Now by the time we run the proxy-autoconfig there is a lower chance of 66 // getting transient DNS / connect failures. 67 // 68 // Admitedly this is a hack. Ideally we would have NetworkChangeNotifier 69 // deliver a reliable signal indicating that the network has changed AND is 70 // ready for action... But until then, we can reduce the likelihood of users 71 // getting wedged because of proxy detection failures on network switch. 72 // 73 // The obvious downside to this strategy is it introduces an additional 74 // latency when switching networks. This delay shouldn't be too disruptive 75 // assuming network switches are infrequent and user initiated. However if 76 // NetworkChangeNotifier delivers network changes more frequently this could 77 // cause jankiness. (NetworkChangeNotifier broadcasts a change event when ANY 78 // interface goes up/down. So in theory if the non-primary interface were 79 // hopping on and off wireless networks our constant delayed reconfiguration 80 // could add noticeable jank.) 81 // 82 // The specific hard-coded wait time below is arbitrary. 83 // Basically I ran some experiments switching between wireless networks on 84 // a Linux Ubuntu (Lucid) laptop, and experimentally found this timeout fixes 85 // things. It is entirely possible that the value is insuficient for other 86 // setups. 87 const int64 kNumMillisToStallAfterNetworkChanges = 2000; 88 89 // Config getter that always returns direct settings. 90 class ProxyConfigServiceDirect : public ProxyConfigService { 91 public: 92 // ProxyConfigService implementation: 93 virtual void AddObserver(Observer* observer) {} 94 virtual void RemoveObserver(Observer* observer) {} 95 virtual ConfigAvailability GetLatestProxyConfig(ProxyConfig* config) { 96 *config = ProxyConfig::CreateDirect(); 97 return CONFIG_VALID; 98 } 99 }; 100 101 // Proxy resolver that fails every time. 102 class ProxyResolverNull : public ProxyResolver { 103 public: 104 ProxyResolverNull() : ProxyResolver(false /*expects_pac_bytes*/) {} 105 106 // ProxyResolver implementation: 107 virtual int GetProxyForURL(const GURL& url, 108 ProxyInfo* results, 109 CompletionCallback* callback, 110 RequestHandle* request, 111 const BoundNetLog& net_log) { 112 return ERR_NOT_IMPLEMENTED; 113 } 114 115 virtual void CancelRequest(RequestHandle request) { 116 NOTREACHED(); 117 } 118 119 virtual void CancelSetPacScript() { 120 NOTREACHED(); 121 } 122 123 virtual int SetPacScript( 124 const scoped_refptr<ProxyResolverScriptData>& /*script_data*/, 125 CompletionCallback* /*callback*/) { 126 return ERR_NOT_IMPLEMENTED; 127 } 128 }; 129 130 // ProxyResolver that simulates a PAC script which returns 131 // |pac_string| for every single URL. 132 class ProxyResolverFromPacString : public ProxyResolver { 133 public: 134 ProxyResolverFromPacString(const std::string& pac_string) 135 : ProxyResolver(false /*expects_pac_bytes*/), 136 pac_string_(pac_string) {} 137 138 virtual int GetProxyForURL(const GURL& url, 139 ProxyInfo* results, 140 CompletionCallback* callback, 141 RequestHandle* request, 142 const BoundNetLog& net_log) { 143 results->UsePacString(pac_string_); 144 return OK; 145 } 146 147 virtual void CancelRequest(RequestHandle request) { 148 NOTREACHED(); 149 } 150 151 virtual void CancelSetPacScript() { 152 NOTREACHED(); 153 } 154 155 virtual int SetPacScript( 156 const scoped_refptr<ProxyResolverScriptData>& pac_script, 157 CompletionCallback* callback) { 158 return OK; 159 } 160 161 private: 162 const std::string pac_string_; 163 }; 164 165 #ifndef ANDROID 166 // This factory creates V8ProxyResolvers with appropriate javascript bindings. 167 class ProxyResolverFactoryForV8 : public ProxyResolverFactory { 168 public: 169 // |async_host_resolver|, |io_loop| and |net_log| must remain 170 // valid for the duration of our lifetime. 171 // |async_host_resolver| will only be operated on |io_loop|. 172 ProxyResolverFactoryForV8(HostResolver* async_host_resolver, 173 MessageLoop* io_loop, 174 NetLog* net_log) 175 : ProxyResolverFactory(true /*expects_pac_bytes*/), 176 async_host_resolver_(async_host_resolver), 177 io_loop_(io_loop), 178 net_log_(net_log) { 179 } 180 181 virtual ProxyResolver* CreateProxyResolver() { 182 // Create a synchronous host resolver wrapper that operates 183 // |async_host_resolver_| on |io_loop_|. 184 SyncHostResolverBridge* sync_host_resolver = 185 new SyncHostResolverBridge(async_host_resolver_, io_loop_); 186 187 ProxyResolverJSBindings* js_bindings = 188 ProxyResolverJSBindings::CreateDefault(sync_host_resolver, net_log_); 189 190 // ProxyResolverV8 takes ownership of |js_bindings|. 191 return new ProxyResolverV8(js_bindings); 192 } 193 194 private: 195 HostResolver* const async_host_resolver_; 196 MessageLoop* io_loop_; 197 NetLog* net_log_; 198 }; 199 #endif 200 201 // Creates ProxyResolvers using a platform-specific implementation. 202 class ProxyResolverFactoryForSystem : public ProxyResolverFactory { 203 public: 204 ProxyResolverFactoryForSystem() 205 : ProxyResolverFactory(false /*expects_pac_bytes*/) {} 206 207 virtual ProxyResolver* CreateProxyResolver() { 208 DCHECK(IsSupported()); 209 #if defined(OS_WIN) 210 return new ProxyResolverWinHttp(); 211 #elif defined(OS_MACOSX) 212 return new ProxyResolverMac(); 213 #else 214 NOTREACHED(); 215 return NULL; 216 #endif 217 } 218 219 static bool IsSupported() { 220 #if defined(OS_WIN) || defined(OS_MACOSX) 221 return true; 222 #else 223 return false; 224 #endif 225 } 226 }; 227 228 // NetLog parameter to describe a proxy configuration change. 229 class ProxyConfigChangedNetLogParam : public NetLog::EventParameters { 230 public: 231 ProxyConfigChangedNetLogParam(const ProxyConfig& old_config, 232 const ProxyConfig& new_config) 233 : old_config_(old_config), 234 new_config_(new_config) { 235 } 236 237 virtual Value* ToValue() const { 238 DictionaryValue* dict = new DictionaryValue(); 239 // The "old_config" is optional -- the first notification will not have 240 // any "previous" configuration. 241 if (old_config_.is_valid()) 242 dict->Set("old_config", old_config_.ToValue()); 243 dict->Set("new_config", new_config_.ToValue()); 244 return dict; 245 } 246 247 private: 248 const ProxyConfig old_config_; 249 const ProxyConfig new_config_; 250 DISALLOW_COPY_AND_ASSIGN(ProxyConfigChangedNetLogParam); 251 }; 252 253 } // namespace 254 255 // ProxyService::PacRequest --------------------------------------------------- 256 257 class ProxyService::PacRequest 258 : public base::RefCounted<ProxyService::PacRequest> { 259 public: 260 PacRequest(ProxyService* service, 261 const GURL& url, 262 ProxyInfo* results, 263 CompletionCallback* user_callback, 264 const BoundNetLog& net_log) 265 : service_(service), 266 user_callback_(user_callback), 267 ALLOW_THIS_IN_INITIALIZER_LIST(io_callback_( 268 this, &PacRequest::QueryComplete)), 269 results_(results), 270 url_(url), 271 resolve_job_(NULL), 272 config_id_(ProxyConfig::INVALID_ID), 273 net_log_(net_log) { 274 DCHECK(user_callback); 275 } 276 277 // Starts the resolve proxy request. 278 int Start() { 279 DCHECK(!was_cancelled()); 280 DCHECK(!is_started()); 281 282 DCHECK(service_->config_.is_valid()); 283 284 config_id_ = service_->config_.id(); 285 286 return resolver()->GetProxyForURL( 287 url_, results_, &io_callback_, &resolve_job_, net_log_); 288 } 289 290 bool is_started() const { 291 // Note that !! casts to bool. (VS gives a warning otherwise). 292 return !!resolve_job_; 293 } 294 295 void StartAndCompleteCheckingForSynchronous() { 296 int rv = service_->TryToCompleteSynchronously(url_, results_); 297 if (rv == ERR_IO_PENDING) 298 rv = Start(); 299 if (rv != ERR_IO_PENDING) 300 QueryComplete(rv); 301 } 302 303 void CancelResolveJob() { 304 DCHECK(is_started()); 305 // The request may already be running in the resolver. 306 resolver()->CancelRequest(resolve_job_); 307 resolve_job_ = NULL; 308 DCHECK(!is_started()); 309 } 310 311 void Cancel() { 312 net_log_.AddEvent(NetLog::TYPE_CANCELLED, NULL); 313 314 if (is_started()) 315 CancelResolveJob(); 316 317 // Mark as cancelled, to prevent accessing this again later. 318 service_ = NULL; 319 user_callback_ = NULL; 320 results_ = NULL; 321 322 net_log_.EndEvent(NetLog::TYPE_PROXY_SERVICE, NULL); 323 } 324 325 // Returns true if Cancel() has been called. 326 bool was_cancelled() const { return user_callback_ == NULL; } 327 328 // Helper to call after ProxyResolver completion (both synchronous and 329 // asynchronous). Fixes up the result that is to be returned to user. 330 int QueryDidComplete(int result_code) { 331 DCHECK(!was_cancelled()); 332 333 // Make a note in the results which configuration was in use at the 334 // time of the resolve. 335 results_->config_id_ = config_id_; 336 337 // Reset the state associated with in-progress-resolve. 338 resolve_job_ = NULL; 339 config_id_ = ProxyConfig::INVALID_ID; 340 341 return service_->DidFinishResolvingProxy(results_, result_code, net_log_); 342 } 343 344 BoundNetLog* net_log() { return &net_log_; } 345 346 private: 347 friend class base::RefCounted<ProxyService::PacRequest>; 348 349 ~PacRequest() {} 350 351 // Callback for when the ProxyResolver request has completed. 352 void QueryComplete(int result_code) { 353 result_code = QueryDidComplete(result_code); 354 355 // Remove this completed PacRequest from the service's pending list. 356 /// (which will probably cause deletion of |this|). 357 CompletionCallback* callback = user_callback_; 358 service_->RemovePendingRequest(this); 359 360 callback->Run(result_code); 361 } 362 363 ProxyResolver* resolver() const { return service_->resolver_.get(); } 364 365 // Note that we don't hold a reference to the ProxyService. Outstanding 366 // requests are cancelled during ~ProxyService, so this is guaranteed 367 // to be valid throughout our lifetime. 368 ProxyService* service_; 369 CompletionCallback* user_callback_; 370 CompletionCallbackImpl<PacRequest> io_callback_; 371 ProxyInfo* results_; 372 GURL url_; 373 ProxyResolver::RequestHandle resolve_job_; 374 ProxyConfig::ID config_id_; // The config id when the resolve was started. 375 BoundNetLog net_log_; 376 }; 377 378 // ProxyService --------------------------------------------------------------- 379 380 ProxyService::ProxyService(ProxyConfigService* config_service, 381 ProxyResolver* resolver, 382 NetLog* net_log) 383 : resolver_(resolver), 384 next_config_id_(1), 385 ALLOW_THIS_IN_INITIALIZER_LIST(init_proxy_resolver_callback_( 386 this, &ProxyService::OnInitProxyResolverComplete)), 387 current_state_(STATE_NONE) , 388 net_log_(net_log), 389 stall_proxy_auto_config_delay_( 390 base::TimeDelta::FromMilliseconds( 391 kNumMillisToStallAfterNetworkChanges)) { 392 NetworkChangeNotifier::AddIPAddressObserver(this); 393 ResetConfigService(config_service); 394 } 395 396 #ifndef ANDROID 397 // static 398 ProxyService* ProxyService::CreateUsingV8ProxyResolver( 399 ProxyConfigService* proxy_config_service, 400 size_t num_pac_threads, 401 ProxyScriptFetcher* proxy_script_fetcher, 402 HostResolver* host_resolver, 403 NetLog* net_log) { 404 DCHECK(proxy_config_service); 405 DCHECK(proxy_script_fetcher); 406 DCHECK(host_resolver); 407 408 if (num_pac_threads == 0) 409 num_pac_threads = kDefaultNumPacThreads; 410 411 ProxyResolverFactory* sync_resolver_factory = 412 new ProxyResolverFactoryForV8( 413 host_resolver, 414 MessageLoop::current(), 415 net_log); 416 417 ProxyResolver* proxy_resolver = 418 new MultiThreadedProxyResolver(sync_resolver_factory, num_pac_threads); 419 420 ProxyService* proxy_service = 421 new ProxyService(proxy_config_service, proxy_resolver, net_log); 422 423 // Configure PAC script downloads to be issued using |proxy_script_fetcher|. 424 proxy_service->SetProxyScriptFetcher(proxy_script_fetcher); 425 426 return proxy_service; 427 } 428 #endif 429 430 // static 431 ProxyService* ProxyService::CreateUsingSystemProxyResolver( 432 ProxyConfigService* proxy_config_service, 433 size_t num_pac_threads, 434 NetLog* net_log) { 435 DCHECK(proxy_config_service); 436 437 if (!ProxyResolverFactoryForSystem::IsSupported()) { 438 LOG(WARNING) << "PAC support disabled because there is no " 439 "system implementation"; 440 return CreateWithoutProxyResolver(proxy_config_service, net_log); 441 } 442 443 if (num_pac_threads == 0) 444 num_pac_threads = kDefaultNumPacThreads; 445 446 ProxyResolver* proxy_resolver = new MultiThreadedProxyResolver( 447 new ProxyResolverFactoryForSystem(), num_pac_threads); 448 449 return new ProxyService(proxy_config_service, proxy_resolver, net_log); 450 } 451 452 // static 453 ProxyService* ProxyService::CreateWithoutProxyResolver( 454 ProxyConfigService* proxy_config_service, 455 NetLog* net_log) { 456 return new ProxyService(proxy_config_service, 457 new ProxyResolverNull(), 458 net_log); 459 } 460 461 // static 462 ProxyService* ProxyService::CreateFixed(const ProxyConfig& pc) { 463 // TODO(eroman): This isn't quite right, won't work if |pc| specifies 464 // a PAC script. 465 return CreateUsingSystemProxyResolver(new ProxyConfigServiceFixed(pc), 466 0, NULL); 467 } 468 469 // static 470 ProxyService* ProxyService::CreateFixed(const std::string& proxy) { 471 net::ProxyConfig proxy_config; 472 proxy_config.proxy_rules().ParseFromString(proxy); 473 return ProxyService::CreateFixed(proxy_config); 474 } 475 476 // static 477 ProxyService* ProxyService::CreateDirect() { 478 return CreateDirectWithNetLog(NULL); 479 } 480 481 ProxyService* ProxyService::CreateDirectWithNetLog(NetLog* net_log) { 482 // Use direct connections. 483 return new ProxyService(new ProxyConfigServiceDirect, new ProxyResolverNull, 484 net_log); 485 } 486 487 // static 488 ProxyService* ProxyService::CreateFixedFromPacResult( 489 const std::string& pac_string) { 490 491 // We need the settings to contain an "automatic" setting, otherwise the 492 // ProxyResolver dependency we give it will never be used. 493 scoped_ptr<ProxyConfigService> proxy_config_service( 494 new ProxyConfigServiceFixed(ProxyConfig::CreateAutoDetect())); 495 496 scoped_ptr<ProxyResolver> proxy_resolver( 497 new ProxyResolverFromPacString(pac_string)); 498 499 return new ProxyService(proxy_config_service.release(), 500 proxy_resolver.release(), 501 NULL); 502 } 503 504 int ProxyService::ResolveProxy(const GURL& raw_url, 505 ProxyInfo* result, 506 CompletionCallback* callback, 507 PacRequest** pac_request, 508 const BoundNetLog& net_log) { 509 DCHECK(CalledOnValidThread()); 510 DCHECK(callback); 511 512 net_log.BeginEvent(NetLog::TYPE_PROXY_SERVICE, NULL); 513 514 config_service_->OnLazyPoll(); 515 if (current_state_ == STATE_NONE) 516 ApplyProxyConfigIfAvailable(); 517 518 // Strip away any reference fragments and the username/password, as they 519 // are not relevant to proxy resolution. 520 GURL url = SimplifyUrlForRequest(raw_url); 521 522 // Check if the request can be completed right away. (This is the case when 523 // using a direct connection for example). 524 int rv = TryToCompleteSynchronously(url, result); 525 if (rv != ERR_IO_PENDING) 526 return DidFinishResolvingProxy(result, rv, net_log); 527 528 scoped_refptr<PacRequest> req( 529 new PacRequest(this, url, result, callback, net_log)); 530 531 if (current_state_ == STATE_READY) { 532 // Start the resolve request. 533 rv = req->Start(); 534 if (rv != ERR_IO_PENDING) 535 return req->QueryDidComplete(rv); 536 } else { 537 req->net_log()->BeginEvent(NetLog::TYPE_PROXY_SERVICE_WAITING_FOR_INIT_PAC, 538 NULL); 539 } 540 541 DCHECK_EQ(ERR_IO_PENDING, rv); 542 DCHECK(!ContainsPendingRequest(req)); 543 pending_requests_.push_back(req); 544 545 // Completion will be notifed through |callback|, unless the caller cancels 546 // the request using |pac_request|. 547 if (pac_request) 548 *pac_request = req.get(); 549 return rv; // ERR_IO_PENDING 550 } 551 552 int ProxyService::TryToCompleteSynchronously(const GURL& url, 553 ProxyInfo* result) { 554 DCHECK_NE(STATE_NONE, current_state_); 555 556 if (current_state_ != STATE_READY) 557 return ERR_IO_PENDING; // Still initializing. 558 559 DCHECK_NE(config_.id(), ProxyConfig::INVALID_ID); 560 561 if (config_.HasAutomaticSettings()) 562 return ERR_IO_PENDING; // Must submit the request to the proxy resolver. 563 564 // Use the manual proxy settings. 565 config_.proxy_rules().Apply(url, result); 566 result->config_id_ = config_.id(); 567 return OK; 568 } 569 570 ProxyService::~ProxyService() { 571 NetworkChangeNotifier::RemoveIPAddressObserver(this); 572 config_service_->RemoveObserver(this); 573 574 // Cancel any inprogress requests. 575 for (PendingRequests::iterator it = pending_requests_.begin(); 576 it != pending_requests_.end(); 577 ++it) { 578 (*it)->Cancel(); 579 } 580 } 581 582 void ProxyService::SuspendAllPendingRequests() { 583 for (PendingRequests::iterator it = pending_requests_.begin(); 584 it != pending_requests_.end(); 585 ++it) { 586 PacRequest* req = it->get(); 587 if (req->is_started()) { 588 req->CancelResolveJob(); 589 590 req->net_log()->BeginEvent( 591 NetLog::TYPE_PROXY_SERVICE_WAITING_FOR_INIT_PAC, NULL); 592 } 593 } 594 } 595 596 void ProxyService::SetReady() { 597 DCHECK(!init_proxy_resolver_.get()); 598 current_state_ = STATE_READY; 599 600 // Make a copy in case |this| is deleted during the synchronous completion 601 // of one of the requests. If |this| is deleted then all of the PacRequest 602 // instances will be Cancel()-ed. 603 PendingRequests pending_copy = pending_requests_; 604 605 for (PendingRequests::iterator it = pending_copy.begin(); 606 it != pending_copy.end(); 607 ++it) { 608 PacRequest* req = it->get(); 609 if (!req->is_started() && !req->was_cancelled()) { 610 req->net_log()->EndEvent(NetLog::TYPE_PROXY_SERVICE_WAITING_FOR_INIT_PAC, 611 NULL); 612 613 // Note that we re-check for synchronous completion, in case we are 614 // no longer using a ProxyResolver (can happen if we fell-back to manual). 615 req->StartAndCompleteCheckingForSynchronous(); 616 } 617 } 618 } 619 620 void ProxyService::ApplyProxyConfigIfAvailable() { 621 DCHECK_EQ(STATE_NONE, current_state_); 622 623 config_service_->OnLazyPoll(); 624 625 // If we have already fetched the configuration, start applying it. 626 if (fetched_config_.is_valid()) { 627 InitializeUsingLastFetchedConfig(); 628 return; 629 } 630 631 // Otherwise we need to first fetch the configuration. 632 current_state_ = STATE_WAITING_FOR_PROXY_CONFIG; 633 634 // Retrieve the current proxy configuration from the ProxyConfigService. 635 // If a configuration is not available yet, we will get called back later 636 // by our ProxyConfigService::Observer once it changes. 637 ProxyConfig config; 638 ProxyConfigService::ConfigAvailability availability = 639 config_service_->GetLatestProxyConfig(&config); 640 if (availability != ProxyConfigService::CONFIG_PENDING) 641 OnProxyConfigChanged(config, availability); 642 } 643 644 void ProxyService::OnInitProxyResolverComplete(int result) { 645 DCHECK_EQ(STATE_WAITING_FOR_INIT_PROXY_RESOLVER, current_state_); 646 DCHECK(init_proxy_resolver_.get()); 647 DCHECK(fetched_config_.HasAutomaticSettings()); 648 init_proxy_resolver_.reset(); 649 650 if (result != OK) { 651 VLOG(1) << "Failed configuring with PAC script, falling-back to manual " 652 "proxy servers."; 653 config_ = fetched_config_; 654 config_.ClearAutomaticSettings(); 655 } 656 657 config_.set_id(fetched_config_.id()); 658 659 // Resume any requests which we had to defer until the PAC script was 660 // downloaded. 661 SetReady(); 662 } 663 664 int ProxyService::ReconsiderProxyAfterError(const GURL& url, 665 ProxyInfo* result, 666 CompletionCallback* callback, 667 PacRequest** pac_request, 668 const BoundNetLog& net_log) { 669 DCHECK(CalledOnValidThread()); 670 671 // Check to see if we have a new config since ResolveProxy was called. We 672 // want to re-run ResolveProxy in two cases: 1) we have a new config, or 2) a 673 // direct connection failed and we never tried the current config. 674 675 bool re_resolve = result->config_id_ != config_.id(); 676 677 if (re_resolve) { 678 // If we have a new config or the config was never tried, we delete the 679 // list of bad proxies and we try again. 680 proxy_retry_info_.clear(); 681 return ResolveProxy(url, result, callback, pac_request, net_log); 682 } 683 684 // We don't have new proxy settings to try, try to fallback to the next proxy 685 // in the list. 686 bool did_fallback = result->Fallback(&proxy_retry_info_); 687 688 // Return synchronous failure if there is nothing left to fall-back to. 689 // TODO(eroman): This is a yucky API, clean it up. 690 return did_fallback ? OK : ERR_FAILED; 691 } 692 693 void ProxyService::CancelPacRequest(PacRequest* req) { 694 DCHECK(CalledOnValidThread()); 695 DCHECK(req); 696 req->Cancel(); 697 RemovePendingRequest(req); 698 } 699 700 bool ProxyService::ContainsPendingRequest(PacRequest* req) { 701 PendingRequests::iterator it = std::find( 702 pending_requests_.begin(), pending_requests_.end(), req); 703 return pending_requests_.end() != it; 704 } 705 706 void ProxyService::RemovePendingRequest(PacRequest* req) { 707 DCHECK(ContainsPendingRequest(req)); 708 PendingRequests::iterator it = std::find( 709 pending_requests_.begin(), pending_requests_.end(), req); 710 pending_requests_.erase(it); 711 } 712 713 int ProxyService::DidFinishResolvingProxy(ProxyInfo* result, 714 int result_code, 715 const BoundNetLog& net_log) { 716 // Log the result of the proxy resolution. 717 if (result_code == OK) { 718 // When logging all events is enabled, dump the proxy list. 719 if (net_log.IsLoggingAllEvents()) { 720 net_log.AddEvent( 721 NetLog::TYPE_PROXY_SERVICE_RESOLVED_PROXY_LIST, 722 make_scoped_refptr(new NetLogStringParameter( 723 "pac_string", result->ToPacString()))); 724 } 725 result->DeprioritizeBadProxies(proxy_retry_info_); 726 } else { 727 net_log.AddEvent( 728 NetLog::TYPE_PROXY_SERVICE_RESOLVED_PROXY_LIST, 729 make_scoped_refptr(new NetLogIntegerParameter( 730 "net_error", result_code))); 731 732 // Fall-back to direct when the proxy resolver fails. This corresponds 733 // with a javascript runtime error in the PAC script. 734 // 735 // This implicit fall-back to direct matches Firefox 3.5 and 736 // Internet Explorer 8. For more information, see: 737 // 738 // http://www.chromium.org/developers/design-documents/proxy-settings-fallback 739 result->UseDirect(); 740 result_code = OK; 741 } 742 743 net_log.EndEvent(NetLog::TYPE_PROXY_SERVICE, NULL); 744 return result_code; 745 } 746 747 void ProxyService::SetProxyScriptFetcher( 748 ProxyScriptFetcher* proxy_script_fetcher) { 749 DCHECK(CalledOnValidThread()); 750 State previous_state = ResetProxyConfig(false); 751 proxy_script_fetcher_.reset(proxy_script_fetcher); 752 if (previous_state != STATE_NONE) 753 ApplyProxyConfigIfAvailable(); 754 } 755 756 ProxyScriptFetcher* ProxyService::GetProxyScriptFetcher() const { 757 DCHECK(CalledOnValidThread()); 758 return proxy_script_fetcher_.get(); 759 } 760 761 ProxyService::State ProxyService::ResetProxyConfig(bool reset_fetched_config) { 762 DCHECK(CalledOnValidThread()); 763 State previous_state = current_state_; 764 765 proxy_retry_info_.clear(); 766 init_proxy_resolver_.reset(); 767 SuspendAllPendingRequests(); 768 config_ = ProxyConfig(); 769 if (reset_fetched_config) 770 fetched_config_ = ProxyConfig(); 771 current_state_ = STATE_NONE; 772 773 return previous_state; 774 } 775 776 void ProxyService::ResetConfigService( 777 ProxyConfigService* new_proxy_config_service) { 778 DCHECK(CalledOnValidThread()); 779 State previous_state = ResetProxyConfig(true); 780 781 // Release the old configuration service. 782 if (config_service_.get()) 783 config_service_->RemoveObserver(this); 784 785 // Set the new configuration service. 786 config_service_.reset(new_proxy_config_service); 787 config_service_->AddObserver(this); 788 789 if (previous_state != STATE_NONE) 790 ApplyProxyConfigIfAvailable(); 791 } 792 793 void ProxyService::PurgeMemory() { 794 DCHECK(CalledOnValidThread()); 795 if (resolver_.get()) 796 resolver_->PurgeMemory(); 797 } 798 799 void ProxyService::ForceReloadProxyConfig() { 800 DCHECK(CalledOnValidThread()); 801 ResetProxyConfig(false); 802 ApplyProxyConfigIfAvailable(); 803 } 804 805 // static 806 ProxyConfigService* ProxyService::CreateSystemProxyConfigService( 807 MessageLoop* io_loop, MessageLoop* file_loop) { 808 #if defined(OS_WIN) 809 return new ProxyConfigServiceWin(); 810 #elif defined(OS_MACOSX) 811 return new ProxyConfigServiceMac(io_loop); 812 #elif defined(OS_CHROMEOS) 813 NOTREACHED() << "ProxyConfigService for ChromeOS should be created in " 814 << "profile_io_data.cc::CreateProxyConfigService."; 815 return NULL; 816 #elif defined(ANDROID) 817 NOTREACHED() << "ProxyConfigService for Android should be created in " 818 << "WebCache.cpp: WebCache::WebCache"; 819 return NULL; 820 #elif defined(OS_LINUX) 821 ProxyConfigServiceLinux* linux_config_service = 822 new ProxyConfigServiceLinux(); 823 824 // Assume we got called from the UI loop, which runs the default 825 // glib main loop, so the current thread is where we should be 826 // running gconf calls from. 827 MessageLoop* glib_default_loop = MessageLoopForUI::current(); 828 829 // The file loop should be a MessageLoopForIO on Linux. 830 DCHECK_EQ(MessageLoop::TYPE_IO, file_loop->type()); 831 832 // Synchronously fetch the current proxy config (since we are 833 // running on glib_default_loop). Additionally register for 834 // notifications (delivered in either |glib_default_loop| or 835 // |file_loop|) to keep us updated when the proxy config changes. 836 linux_config_service->SetupAndFetchInitialConfig(glib_default_loop, io_loop, 837 static_cast<MessageLoopForIO*>(file_loop)); 838 839 return linux_config_service; 840 #else 841 LOG(WARNING) << "Failed to choose a system proxy settings fetcher " 842 "for this platform."; 843 return new ProxyConfigServiceNull(); 844 #endif 845 } 846 847 void ProxyService::OnProxyConfigChanged( 848 const ProxyConfig& config, 849 ProxyConfigService::ConfigAvailability availability) { 850 // Retrieve the current proxy configuration from the ProxyConfigService. 851 // If a configuration is not available yet, we will get called back later 852 // by our ProxyConfigService::Observer once it changes. 853 ProxyConfig effective_config; 854 switch (availability) { 855 case ProxyConfigService::CONFIG_PENDING: 856 // ProxyConfigService implementors should never pass CONFIG_PENDING. 857 NOTREACHED() << "Proxy config change with CONFIG_PENDING availability!"; 858 return; 859 case ProxyConfigService::CONFIG_VALID: 860 effective_config = config; 861 break; 862 case ProxyConfigService::CONFIG_UNSET: 863 effective_config = ProxyConfig::CreateDirect(); 864 break; 865 } 866 867 // Emit the proxy settings change to the NetLog stream. 868 if (net_log_) { 869 scoped_refptr<NetLog::EventParameters> params( 870 new ProxyConfigChangedNetLogParam(fetched_config_, effective_config)); 871 net_log_->AddEntry(net::NetLog::TYPE_PROXY_CONFIG_CHANGED, 872 base::TimeTicks::Now(), 873 NetLog::Source(), 874 NetLog::PHASE_NONE, 875 params); 876 } 877 878 // Set the new configuration as the most recently fetched one. 879 fetched_config_ = effective_config; 880 fetched_config_.set_id(1); // Needed for a later DCHECK of is_valid(). 881 882 InitializeUsingLastFetchedConfig(); 883 } 884 885 void ProxyService::InitializeUsingLastFetchedConfig() { 886 ResetProxyConfig(false); 887 888 DCHECK(fetched_config_.is_valid()); 889 890 // Increment the ID to reflect that the config has changed. 891 fetched_config_.set_id(next_config_id_++); 892 893 if (!fetched_config_.HasAutomaticSettings()) { 894 config_ = fetched_config_; 895 SetReady(); 896 return; 897 } 898 899 // Start downloading + testing the PAC scripts for this new configuration. 900 current_state_ = STATE_WAITING_FOR_INIT_PROXY_RESOLVER; 901 902 init_proxy_resolver_.reset( 903 new InitProxyResolver(resolver_.get(), proxy_script_fetcher_.get(), 904 net_log_)); 905 906 // If we changed networks recently, we should delay running proxy auto-config. 907 base::TimeDelta wait_delay = 908 stall_proxy_autoconfig_until_ - base::TimeTicks::Now(); 909 910 int rv = init_proxy_resolver_->Init( 911 fetched_config_, wait_delay, &config_, &init_proxy_resolver_callback_); 912 913 if (rv != ERR_IO_PENDING) 914 OnInitProxyResolverComplete(rv); 915 } 916 917 void ProxyService::OnIPAddressChanged() { 918 // See the comment block by |kNumMillisToStallAfterNetworkChanges| for info. 919 stall_proxy_autoconfig_until_ = 920 base::TimeTicks::Now() + stall_proxy_auto_config_delay_; 921 922 State previous_state = ResetProxyConfig(false); 923 if (previous_state != STATE_NONE) 924 ApplyProxyConfigIfAvailable(); 925 } 926 927 SyncProxyServiceHelper::SyncProxyServiceHelper(MessageLoop* io_message_loop, 928 ProxyService* proxy_service) 929 : io_message_loop_(io_message_loop), 930 proxy_service_(proxy_service), 931 event_(false, false), 932 ALLOW_THIS_IN_INITIALIZER_LIST(callback_( 933 this, &SyncProxyServiceHelper::OnCompletion)) { 934 DCHECK(io_message_loop_ != MessageLoop::current()); 935 } 936 937 int SyncProxyServiceHelper::ResolveProxy(const GURL& url, 938 ProxyInfo* proxy_info, 939 const BoundNetLog& net_log) { 940 DCHECK(io_message_loop_ != MessageLoop::current()); 941 942 io_message_loop_->PostTask(FROM_HERE, NewRunnableMethod( 943 this, &SyncProxyServiceHelper::StartAsyncResolve, url, net_log)); 944 945 event_.Wait(); 946 947 if (result_ == net::OK) { 948 *proxy_info = proxy_info_; 949 } 950 return result_; 951 } 952 953 int SyncProxyServiceHelper::ReconsiderProxyAfterError( 954 const GURL& url, ProxyInfo* proxy_info, const BoundNetLog& net_log) { 955 DCHECK(io_message_loop_ != MessageLoop::current()); 956 957 io_message_loop_->PostTask(FROM_HERE, NewRunnableMethod( 958 this, &SyncProxyServiceHelper::StartAsyncReconsider, url, net_log)); 959 960 event_.Wait(); 961 962 if (result_ == net::OK) { 963 *proxy_info = proxy_info_; 964 } 965 return result_; 966 } 967 968 SyncProxyServiceHelper::~SyncProxyServiceHelper() {} 969 970 void SyncProxyServiceHelper::StartAsyncResolve(const GURL& url, 971 const BoundNetLog& net_log) { 972 result_ = proxy_service_->ResolveProxy( 973 url, &proxy_info_, &callback_, NULL, net_log); 974 if (result_ != net::ERR_IO_PENDING) { 975 OnCompletion(result_); 976 } 977 } 978 979 void SyncProxyServiceHelper::StartAsyncReconsider(const GURL& url, 980 const BoundNetLog& net_log) { 981 result_ = proxy_service_->ReconsiderProxyAfterError( 982 url, &proxy_info_, &callback_, NULL, net_log); 983 if (result_ != net::ERR_IO_PENDING) { 984 OnCompletion(result_); 985 } 986 } 987 988 void SyncProxyServiceHelper::OnCompletion(int rv) { 989 result_ = rv; 990 event_.Signal(); 991 } 992 993 } // namespace net 994