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 <vector> 8 9#include "base/format_macros.h" 10#include "base/logging.h" 11#include "base/strings/string_util.h" 12#include "base/strings/utf_string_conversions.h" 13#include "net/base/net_errors.h" 14#include "net/base/net_log.h" 15#include "net/base/net_log_unittest.h" 16#include "net/base/test_completion_callback.h" 17#include "net/proxy/dhcp_proxy_script_fetcher.h" 18#include "net/proxy/mock_proxy_resolver.h" 19#include "net/proxy/mock_proxy_script_fetcher.h" 20#include "net/proxy/proxy_config_service.h" 21#include "net/proxy/proxy_resolver.h" 22#include "net/proxy/proxy_script_fetcher.h" 23#include "testing/gtest/include/gtest/gtest.h" 24#include "url/gurl.h" 25 26// TODO(eroman): Write a test which exercises 27// ProxyService::SuspendAllPendingRequests(). 28namespace net { 29namespace { 30 31// This polling policy will decide to poll every 1 ms. 32class ImmediatePollPolicy : public ProxyService::PacPollPolicy { 33 public: 34 ImmediatePollPolicy() {} 35 36 virtual Mode GetNextDelay(int error, base::TimeDelta current_delay, 37 base::TimeDelta* next_delay) const OVERRIDE { 38 *next_delay = base::TimeDelta::FromMilliseconds(1); 39 return MODE_USE_TIMER; 40 } 41 42 private: 43 DISALLOW_COPY_AND_ASSIGN(ImmediatePollPolicy); 44}; 45 46// This polling policy chooses a fantastically large delay. In other words, it 47// will never trigger a poll 48class NeverPollPolicy : public ProxyService::PacPollPolicy { 49 public: 50 NeverPollPolicy() {} 51 52 virtual Mode GetNextDelay(int error, base::TimeDelta current_delay, 53 base::TimeDelta* next_delay) const OVERRIDE { 54 *next_delay = base::TimeDelta::FromDays(60); 55 return MODE_USE_TIMER; 56 } 57 58 private: 59 DISALLOW_COPY_AND_ASSIGN(NeverPollPolicy); 60}; 61 62// This polling policy starts a poll immediately after network activity. 63class ImmediateAfterActivityPollPolicy : public ProxyService::PacPollPolicy { 64 public: 65 ImmediateAfterActivityPollPolicy() {} 66 67 virtual Mode GetNextDelay(int error, base::TimeDelta current_delay, 68 base::TimeDelta* next_delay) const OVERRIDE { 69 *next_delay = base::TimeDelta(); 70 return MODE_START_AFTER_ACTIVITY; 71 } 72 73 private: 74 DISALLOW_COPY_AND_ASSIGN(ImmediateAfterActivityPollPolicy); 75}; 76 77// This test fixture is used to partially disable the background polling done by 78// the ProxyService (which it uses to detect whenever its PAC script contents or 79// WPAD results have changed). 80// 81// We disable the feature by setting the poll interval to something really 82// large, so it will never actually be reached even on the slowest bots that run 83// these tests. 84// 85// We disable the polling in order to avoid any timing dependencies in the 86// tests. If the bot were to run the tests very slowly and we hadn't disabled 87// polling, then it might start a background re-try in the middle of our test 88// and confuse our expectations leading to flaky failures. 89// 90// The tests which verify the polling code re-enable the polling behavior but 91// are careful to avoid timing problems. 92class ProxyServiceTest : public testing::Test { 93 protected: 94 virtual void SetUp() OVERRIDE { 95 testing::Test::SetUp(); 96 previous_policy_ = 97 ProxyService::set_pac_script_poll_policy(&never_poll_policy_); 98 } 99 100 virtual void TearDown() OVERRIDE { 101 // Restore the original policy. 102 ProxyService::set_pac_script_poll_policy(previous_policy_); 103 testing::Test::TearDown(); 104 } 105 106 private: 107 NeverPollPolicy never_poll_policy_; 108 const ProxyService::PacPollPolicy* previous_policy_; 109}; 110 111const char kValidPacScript1[] = "pac-script-v1-FindProxyForURL"; 112const char kValidPacScript2[] = "pac-script-v2-FindProxyForURL"; 113 114class MockProxyConfigService: public ProxyConfigService { 115 public: 116 explicit MockProxyConfigService(const ProxyConfig& config) 117 : availability_(CONFIG_VALID), 118 config_(config) { 119 } 120 121 explicit MockProxyConfigService(const std::string& pac_url) 122 : availability_(CONFIG_VALID), 123 config_(ProxyConfig::CreateFromCustomPacURL(GURL(pac_url))) { 124 } 125 126 virtual void AddObserver(Observer* observer) OVERRIDE { 127 observers_.AddObserver(observer); 128 } 129 130 virtual void RemoveObserver(Observer* observer) OVERRIDE { 131 observers_.RemoveObserver(observer); 132 } 133 134 virtual ConfigAvailability GetLatestProxyConfig(ProxyConfig* results) 135 OVERRIDE { 136 if (availability_ == CONFIG_VALID) 137 *results = config_; 138 return availability_; 139 } 140 141 void SetConfig(const ProxyConfig& config) { 142 availability_ = CONFIG_VALID; 143 config_ = config; 144 FOR_EACH_OBSERVER(Observer, observers_, 145 OnProxyConfigChanged(config_, availability_)); 146 } 147 148 private: 149 ConfigAvailability availability_; 150 ProxyConfig config_; 151 ObserverList<Observer, true> observers_; 152}; 153 154} // namespace 155 156TEST_F(ProxyServiceTest, Direct) { 157 MockAsyncProxyResolver* resolver = new MockAsyncProxyResolver; 158 ProxyService service(new MockProxyConfigService( 159 ProxyConfig::CreateDirect()), resolver, NULL); 160 161 GURL url("http://www.google.com/"); 162 163 ProxyInfo info; 164 TestCompletionCallback callback; 165 CapturingBoundNetLog log; 166 int rv = service.ResolveProxy( 167 url, &info, callback.callback(), NULL, log.bound()); 168 EXPECT_EQ(OK, rv); 169 EXPECT_TRUE(resolver->pending_requests().empty()); 170 171 EXPECT_TRUE(info.is_direct()); 172 EXPECT_TRUE(info.proxy_resolve_start_time().is_null()); 173 EXPECT_TRUE(info.proxy_resolve_end_time().is_null()); 174 175 // Check the NetLog was filled correctly. 176 CapturingNetLog::CapturedEntryList entries; 177 log.GetEntries(&entries); 178 179 EXPECT_EQ(3u, entries.size()); 180 EXPECT_TRUE(LogContainsBeginEvent( 181 entries, 0, NetLog::TYPE_PROXY_SERVICE)); 182 EXPECT_TRUE(LogContainsEvent( 183 entries, 1, NetLog::TYPE_PROXY_SERVICE_RESOLVED_PROXY_LIST, 184 NetLog::PHASE_NONE)); 185 EXPECT_TRUE(LogContainsEndEvent( 186 entries, 2, NetLog::TYPE_PROXY_SERVICE)); 187} 188 189TEST_F(ProxyServiceTest, PAC) { 190 MockProxyConfigService* config_service = 191 new MockProxyConfigService("http://foopy/proxy.pac"); 192 193 MockAsyncProxyResolver* resolver = new MockAsyncProxyResolver; 194 195 ProxyService service(config_service, resolver, NULL); 196 197 GURL url("http://www.google.com/"); 198 199 ProxyInfo info; 200 TestCompletionCallback callback; 201 ProxyService::PacRequest* request; 202 CapturingBoundNetLog log; 203 204 int rv = service.ResolveProxy( 205 url, &info, callback.callback(), &request, log.bound()); 206 EXPECT_EQ(ERR_IO_PENDING, rv); 207 208 EXPECT_EQ(LOAD_STATE_RESOLVING_PROXY_FOR_URL, service.GetLoadState(request)); 209 210 EXPECT_EQ(GURL("http://foopy/proxy.pac"), 211 resolver->pending_set_pac_script_request()->script_data()->url()); 212 resolver->pending_set_pac_script_request()->CompleteNow(OK); 213 214 ASSERT_EQ(1u, resolver->pending_requests().size()); 215 EXPECT_EQ(url, resolver->pending_requests()[0]->url()); 216 217 // Set the result in proxy resolver. 218 resolver->pending_requests()[0]->results()->UseNamedProxy("foopy"); 219 resolver->pending_requests()[0]->CompleteNow(OK); 220 221 EXPECT_EQ(OK, callback.WaitForResult()); 222 EXPECT_FALSE(info.is_direct()); 223 EXPECT_EQ("foopy:80", info.proxy_server().ToURI()); 224 EXPECT_TRUE(info.did_use_pac_script()); 225 226 EXPECT_FALSE(info.proxy_resolve_start_time().is_null()); 227 EXPECT_FALSE(info.proxy_resolve_end_time().is_null()); 228 EXPECT_LE(info.proxy_resolve_start_time(), info.proxy_resolve_end_time()); 229 230 // Check the NetLog was filled correctly. 231 CapturingNetLog::CapturedEntryList entries; 232 log.GetEntries(&entries); 233 234 EXPECT_EQ(5u, entries.size()); 235 EXPECT_TRUE(LogContainsBeginEvent( 236 entries, 0, NetLog::TYPE_PROXY_SERVICE)); 237 EXPECT_TRUE(LogContainsBeginEvent( 238 entries, 1, NetLog::TYPE_PROXY_SERVICE_WAITING_FOR_INIT_PAC)); 239 EXPECT_TRUE(LogContainsEndEvent( 240 entries, 2, NetLog::TYPE_PROXY_SERVICE_WAITING_FOR_INIT_PAC)); 241 EXPECT_TRUE(LogContainsEndEvent( 242 entries, 4, NetLog::TYPE_PROXY_SERVICE)); 243} 244 245// Test that the proxy resolver does not see the URL's username/password 246// or its reference section. 247TEST_F(ProxyServiceTest, PAC_NoIdentityOrHash) { 248 MockProxyConfigService* config_service = 249 new MockProxyConfigService("http://foopy/proxy.pac"); 250 251 MockAsyncProxyResolver* resolver = new MockAsyncProxyResolver; 252 253 ProxyService service(config_service, resolver, NULL); 254 255 GURL url("http://username:password@www.google.com/?ref#hash#hash"); 256 257 ProxyInfo info; 258 TestCompletionCallback callback; 259 int rv = service.ResolveProxy( 260 url, &info, callback.callback(), NULL, BoundNetLog()); 261 EXPECT_EQ(ERR_IO_PENDING, rv); 262 263 EXPECT_EQ(GURL("http://foopy/proxy.pac"), 264 resolver->pending_set_pac_script_request()->script_data()->url()); 265 resolver->pending_set_pac_script_request()->CompleteNow(OK); 266 267 ASSERT_EQ(1u, resolver->pending_requests().size()); 268 // The URL should have been simplified, stripping the username/password/hash. 269 EXPECT_EQ(GURL("http://www.google.com/?ref"), 270 resolver->pending_requests()[0]->url()); 271 272 // We end here without ever completing the request -- destruction of 273 // ProxyService will cancel the outstanding request. 274} 275 276TEST_F(ProxyServiceTest, PAC_FailoverWithoutDirect) { 277 MockProxyConfigService* config_service = 278 new MockProxyConfigService("http://foopy/proxy.pac"); 279 MockAsyncProxyResolver* resolver = new MockAsyncProxyResolver; 280 281 ProxyService service(config_service, resolver, NULL); 282 283 GURL url("http://www.google.com/"); 284 285 ProxyInfo info; 286 TestCompletionCallback callback1; 287 int rv = service.ResolveProxy( 288 url, &info, callback1.callback(), NULL, BoundNetLog()); 289 EXPECT_EQ(ERR_IO_PENDING, rv); 290 291 EXPECT_EQ(GURL("http://foopy/proxy.pac"), 292 resolver->pending_set_pac_script_request()->script_data()->url()); 293 resolver->pending_set_pac_script_request()->CompleteNow(OK); 294 295 ASSERT_EQ(1u, resolver->pending_requests().size()); 296 EXPECT_EQ(url, resolver->pending_requests()[0]->url()); 297 298 // Set the result in proxy resolver. 299 resolver->pending_requests()[0]->results()->UseNamedProxy("foopy:8080"); 300 resolver->pending_requests()[0]->CompleteNow(OK); 301 302 EXPECT_EQ(OK, callback1.WaitForResult()); 303 EXPECT_FALSE(info.is_direct()); 304 EXPECT_EQ("foopy:8080", info.proxy_server().ToURI()); 305 EXPECT_TRUE(info.did_use_pac_script()); 306 307 EXPECT_FALSE(info.proxy_resolve_start_time().is_null()); 308 EXPECT_FALSE(info.proxy_resolve_end_time().is_null()); 309 EXPECT_LE(info.proxy_resolve_start_time(), info.proxy_resolve_end_time()); 310 311 // Now, imagine that connecting to foopy:8080 fails: there is nothing 312 // left to fallback to, since our proxy list was NOT terminated by 313 // DIRECT. 314 TestCompletionCallback callback2; 315 rv = service.ReconsiderProxyAfterError( 316 url, &info, callback2.callback(), NULL, BoundNetLog()); 317 // ReconsiderProxyAfterError returns error indicating nothing left. 318 EXPECT_EQ(ERR_FAILED, rv); 319 EXPECT_TRUE(info.is_empty()); 320} 321 322// Test that if the execution of the PAC script fails (i.e. javascript runtime 323// error), and the PAC settings are non-mandatory, that we fall-back to direct. 324TEST_F(ProxyServiceTest, PAC_RuntimeError) { 325 MockProxyConfigService* config_service = 326 new MockProxyConfigService("http://foopy/proxy.pac"); 327 MockAsyncProxyResolver* resolver = new MockAsyncProxyResolver; 328 329 ProxyService service(config_service, resolver, NULL); 330 331 GURL url("http://this-causes-js-error/"); 332 333 ProxyInfo info; 334 TestCompletionCallback callback1; 335 int rv = service.ResolveProxy( 336 url, &info, callback1.callback(), NULL, BoundNetLog()); 337 EXPECT_EQ(ERR_IO_PENDING, rv); 338 339 EXPECT_EQ(GURL("http://foopy/proxy.pac"), 340 resolver->pending_set_pac_script_request()->script_data()->url()); 341 resolver->pending_set_pac_script_request()->CompleteNow(OK); 342 343 ASSERT_EQ(1u, resolver->pending_requests().size()); 344 EXPECT_EQ(url, resolver->pending_requests()[0]->url()); 345 346 // Simulate a failure in the PAC executor. 347 resolver->pending_requests()[0]->CompleteNow(ERR_PAC_SCRIPT_FAILED); 348 349 EXPECT_EQ(OK, callback1.WaitForResult()); 350 351 // Since the PAC script was non-mandatory, we should have fallen-back to 352 // DIRECT. 353 EXPECT_TRUE(info.is_direct()); 354 EXPECT_TRUE(info.did_use_pac_script()); 355 EXPECT_EQ(1, info.config_id()); 356 357 EXPECT_FALSE(info.proxy_resolve_start_time().is_null()); 358 EXPECT_FALSE(info.proxy_resolve_end_time().is_null()); 359 EXPECT_LE(info.proxy_resolve_start_time(), info.proxy_resolve_end_time()); 360} 361 362// The proxy list could potentially contain the DIRECT fallback choice 363// in a location other than the very end of the list, and could even 364// specify it multiple times. 365// 366// This is not a typical usage, but we will obey it. 367// (If we wanted to disallow this type of input, the right place to 368// enforce it would be in parsing the PAC result string). 369// 370// This test will use the PAC result string: 371// 372// "DIRECT ; PROXY foobar:10 ; DIRECT ; PROXY foobar:20" 373// 374// For which we expect it to try DIRECT, then foobar:10, then DIRECT again, 375// then foobar:20, and then give up and error. 376// 377// The important check of this test is to make sure that DIRECT is not somehow 378// cached as being a bad proxy. 379TEST_F(ProxyServiceTest, PAC_FailoverAfterDirect) { 380 MockProxyConfigService* config_service = 381 new MockProxyConfigService("http://foopy/proxy.pac"); 382 MockAsyncProxyResolver* resolver = new MockAsyncProxyResolver; 383 384 ProxyService service(config_service, resolver, NULL); 385 386 GURL url("http://www.google.com/"); 387 388 ProxyInfo info; 389 TestCompletionCallback callback1; 390 int rv = service.ResolveProxy( 391 url, &info, callback1.callback(), NULL, BoundNetLog()); 392 EXPECT_EQ(ERR_IO_PENDING, rv); 393 394 EXPECT_EQ(GURL("http://foopy/proxy.pac"), 395 resolver->pending_set_pac_script_request()->script_data()->url()); 396 resolver->pending_set_pac_script_request()->CompleteNow(OK); 397 398 ASSERT_EQ(1u, resolver->pending_requests().size()); 399 EXPECT_EQ(url, resolver->pending_requests()[0]->url()); 400 401 // Set the result in proxy resolver. 402 resolver->pending_requests()[0]->results()->UsePacString( 403 "DIRECT ; PROXY foobar:10 ; DIRECT ; PROXY foobar:20"); 404 resolver->pending_requests()[0]->CompleteNow(OK); 405 406 EXPECT_EQ(OK, callback1.WaitForResult()); 407 EXPECT_TRUE(info.is_direct()); 408 409 // Fallback 1. 410 TestCompletionCallback callback2; 411 rv = service.ReconsiderProxyAfterError(url, &info, callback2.callback(), NULL, 412 BoundNetLog()); 413 EXPECT_EQ(OK, rv); 414 EXPECT_FALSE(info.is_direct()); 415 EXPECT_EQ("foobar:10", info.proxy_server().ToURI()); 416 417 // Fallback 2. 418 TestCompletionCallback callback3; 419 rv = service.ReconsiderProxyAfterError(url, &info, callback3.callback(), NULL, 420 BoundNetLog()); 421 EXPECT_EQ(OK, rv); 422 EXPECT_TRUE(info.is_direct()); 423 424 // Fallback 3. 425 TestCompletionCallback callback4; 426 rv = service.ReconsiderProxyAfterError(url, &info, callback4.callback(), NULL, 427 BoundNetLog()); 428 EXPECT_EQ(OK, rv); 429 EXPECT_FALSE(info.is_direct()); 430 EXPECT_EQ("foobar:20", info.proxy_server().ToURI()); 431 432 // Fallback 4 -- Nothing to fall back to! 433 TestCompletionCallback callback5; 434 rv = service.ReconsiderProxyAfterError(url, &info, callback5.callback(), NULL, 435 BoundNetLog()); 436 EXPECT_EQ(ERR_FAILED, rv); 437 EXPECT_TRUE(info.is_empty()); 438} 439 440TEST_F(ProxyServiceTest, PAC_ConfigSourcePropagates) { 441 // Test whether the ProxyConfigSource set by the ProxyConfigService is applied 442 // to ProxyInfo after the proxy is resolved via a PAC script. 443 ProxyConfig config = 444 ProxyConfig::CreateFromCustomPacURL(GURL("http://foopy/proxy.pac")); 445 config.set_source(PROXY_CONFIG_SOURCE_TEST); 446 447 MockProxyConfigService* config_service = new MockProxyConfigService(config); 448 MockAsyncProxyResolver* resolver = new MockAsyncProxyResolver; 449 ProxyService service(config_service, resolver, NULL); 450 451 // Resolve something. 452 GURL url("http://www.google.com/"); 453 ProxyInfo info; 454 TestCompletionCallback callback; 455 int rv = service.ResolveProxy( 456 url, &info, callback.callback(), NULL, BoundNetLog()); 457 ASSERT_EQ(ERR_IO_PENDING, rv); 458 resolver->pending_set_pac_script_request()->CompleteNow(OK); 459 ASSERT_EQ(1u, resolver->pending_requests().size()); 460 461 // Set the result in proxy resolver. 462 resolver->pending_requests()[0]->results()->UseNamedProxy("foopy"); 463 resolver->pending_requests()[0]->CompleteNow(OK); 464 465 EXPECT_EQ(OK, callback.WaitForResult()); 466 EXPECT_EQ(PROXY_CONFIG_SOURCE_TEST, info.config_source()); 467 EXPECT_TRUE(info.did_use_pac_script()); 468 469 EXPECT_FALSE(info.proxy_resolve_start_time().is_null()); 470 EXPECT_FALSE(info.proxy_resolve_end_time().is_null()); 471 EXPECT_LE(info.proxy_resolve_start_time(), info.proxy_resolve_end_time()); 472} 473 474TEST_F(ProxyServiceTest, ProxyResolverFails) { 475 // Test what happens when the ProxyResolver fails. The download and setting 476 // of the PAC script have already succeeded, so this corresponds with a 477 // javascript runtime error while calling FindProxyForURL(). 478 479 MockProxyConfigService* config_service = 480 new MockProxyConfigService("http://foopy/proxy.pac"); 481 482 MockAsyncProxyResolver* resolver = new MockAsyncProxyResolver; 483 484 ProxyService service(config_service, resolver, NULL); 485 486 // Start first resolve request. 487 GURL url("http://www.google.com/"); 488 ProxyInfo info; 489 TestCompletionCallback callback1; 490 int rv = service.ResolveProxy( 491 url, &info, callback1.callback(), NULL, BoundNetLog()); 492 EXPECT_EQ(ERR_IO_PENDING, rv); 493 494 EXPECT_EQ(GURL("http://foopy/proxy.pac"), 495 resolver->pending_set_pac_script_request()->script_data()->url()); 496 resolver->pending_set_pac_script_request()->CompleteNow(OK); 497 498 ASSERT_EQ(1u, resolver->pending_requests().size()); 499 EXPECT_EQ(url, resolver->pending_requests()[0]->url()); 500 501 // Fail the first resolve request in MockAsyncProxyResolver. 502 resolver->pending_requests()[0]->CompleteNow(ERR_FAILED); 503 504 // Although the proxy resolver failed the request, ProxyService implicitly 505 // falls-back to DIRECT. 506 EXPECT_EQ(OK, callback1.WaitForResult()); 507 EXPECT_TRUE(info.is_direct()); 508 509 // Failed PAC executions still have proxy resolution times. 510 EXPECT_FALSE(info.proxy_resolve_start_time().is_null()); 511 EXPECT_FALSE(info.proxy_resolve_end_time().is_null()); 512 EXPECT_LE(info.proxy_resolve_start_time(), info.proxy_resolve_end_time()); 513 514 // The second resolve request will try to run through the proxy resolver, 515 // regardless of whether the first request failed in it. 516 TestCompletionCallback callback2; 517 rv = service.ResolveProxy( 518 url, &info, callback2.callback(), NULL, BoundNetLog()); 519 EXPECT_EQ(ERR_IO_PENDING, rv); 520 521 ASSERT_EQ(1u, resolver->pending_requests().size()); 522 EXPECT_EQ(url, resolver->pending_requests()[0]->url()); 523 524 // This time we will have the resolver succeed (perhaps the PAC script has 525 // a dependency on the current time). 526 resolver->pending_requests()[0]->results()->UseNamedProxy("foopy_valid:8080"); 527 resolver->pending_requests()[0]->CompleteNow(OK); 528 529 EXPECT_EQ(OK, callback2.WaitForResult()); 530 EXPECT_FALSE(info.is_direct()); 531 EXPECT_EQ("foopy_valid:8080", info.proxy_server().ToURI()); 532} 533 534TEST_F(ProxyServiceTest, ProxyScriptFetcherFailsDownloadingMandatoryPac) { 535 // Test what happens when the ProxyScriptResolver fails to download a 536 // mandatory PAC script. 537 538 ProxyConfig config( 539 ProxyConfig::CreateFromCustomPacURL(GURL("http://foopy/proxy.pac"))); 540 config.set_pac_mandatory(true); 541 542 MockProxyConfigService* config_service = new MockProxyConfigService(config); 543 544 MockAsyncProxyResolver* resolver = new MockAsyncProxyResolver; 545 546 ProxyService service(config_service, resolver, NULL); 547 548 // Start first resolve request. 549 GURL url("http://www.google.com/"); 550 ProxyInfo info; 551 TestCompletionCallback callback1; 552 int rv = service.ResolveProxy( 553 url, &info, callback1.callback(), NULL, BoundNetLog()); 554 EXPECT_EQ(ERR_IO_PENDING, rv); 555 556 EXPECT_EQ(GURL("http://foopy/proxy.pac"), 557 resolver->pending_set_pac_script_request()->script_data()->url()); 558 resolver->pending_set_pac_script_request()->CompleteNow(ERR_FAILED); 559 560 ASSERT_EQ(0u, resolver->pending_requests().size()); 561 562 // As the proxy resolver failed the request and is configured for a mandatory 563 // PAC script, ProxyService must not implicitly fall-back to DIRECT. 564 EXPECT_EQ(ERR_MANDATORY_PROXY_CONFIGURATION_FAILED, 565 callback1.WaitForResult()); 566 EXPECT_FALSE(info.is_direct()); 567 568 // As the proxy resolver failed the request and is configured for a mandatory 569 // PAC script, ProxyService must not implicitly fall-back to DIRECT. 570 TestCompletionCallback callback2; 571 rv = service.ResolveProxy( 572 url, &info, callback2.callback(), NULL, BoundNetLog()); 573 EXPECT_EQ(ERR_MANDATORY_PROXY_CONFIGURATION_FAILED, rv); 574 EXPECT_FALSE(info.is_direct()); 575} 576 577TEST_F(ProxyServiceTest, ProxyResolverFailsParsingJavaScriptMandatoryPac) { 578 // Test what happens when the ProxyResolver fails that is configured to use a 579 // mandatory PAC script. The download of the PAC script has already 580 // succeeded but the PAC script contains no valid javascript. 581 582 ProxyConfig config( 583 ProxyConfig::CreateFromCustomPacURL(GURL("http://foopy/proxy.pac"))); 584 config.set_pac_mandatory(true); 585 586 MockProxyConfigService* config_service = new MockProxyConfigService(config); 587 588 MockAsyncProxyResolverExpectsBytes* resolver = 589 new MockAsyncProxyResolverExpectsBytes; 590 591 ProxyService service(config_service, resolver, NULL); 592 593 MockProxyScriptFetcher* fetcher = new MockProxyScriptFetcher; 594 DhcpProxyScriptFetcher* dhcp_fetcher = new DoNothingDhcpProxyScriptFetcher(); 595 service.SetProxyScriptFetchers(fetcher, dhcp_fetcher); 596 597 // Start resolve request. 598 GURL url("http://www.google.com/"); 599 ProxyInfo info; 600 TestCompletionCallback callback; 601 int rv = service.ResolveProxy( 602 url, &info, callback.callback(), NULL, BoundNetLog()); 603 EXPECT_EQ(ERR_IO_PENDING, rv); 604 605 // Check that nothing has been sent to the proxy resolver yet. 606 ASSERT_EQ(0u, resolver->pending_requests().size()); 607 608 // Downloading the PAC script succeeds. 609 EXPECT_TRUE(fetcher->has_pending_request()); 610 EXPECT_EQ(GURL("http://foopy/proxy.pac"), fetcher->pending_request_url()); 611 fetcher->NotifyFetchCompletion(OK, "invalid-script-contents"); 612 613 EXPECT_FALSE(fetcher->has_pending_request()); 614 ASSERT_EQ(0u, resolver->pending_requests().size()); 615 616 // Since ProxyScriptDecider failed to identify a valid PAC and PAC was 617 // mandatory for this configuration, the ProxyService must not implicitly 618 // fall-back to DIRECT. 619 EXPECT_EQ(ERR_MANDATORY_PROXY_CONFIGURATION_FAILED, 620 callback.WaitForResult()); 621 EXPECT_FALSE(info.is_direct()); 622} 623 624TEST_F(ProxyServiceTest, ProxyResolverFailsInJavaScriptMandatoryPac) { 625 // Test what happens when the ProxyResolver fails that is configured to use a 626 // mandatory PAC script. The download and setting of the PAC script have 627 // already succeeded, so this corresponds with a javascript runtime error 628 // while calling FindProxyForURL(). 629 630 ProxyConfig config( 631 ProxyConfig::CreateFromCustomPacURL(GURL("http://foopy/proxy.pac"))); 632 config.set_pac_mandatory(true); 633 634 MockProxyConfigService* config_service = new MockProxyConfigService(config); 635 636 MockAsyncProxyResolver* resolver = new MockAsyncProxyResolver; 637 638 ProxyService service(config_service, resolver, NULL); 639 640 // Start first resolve request. 641 GURL url("http://www.google.com/"); 642 ProxyInfo info; 643 TestCompletionCallback callback1; 644 int rv = service.ResolveProxy( 645 url, &info, callback1.callback(), NULL, BoundNetLog()); 646 EXPECT_EQ(ERR_IO_PENDING, rv); 647 648 EXPECT_EQ(GURL("http://foopy/proxy.pac"), 649 resolver->pending_set_pac_script_request()->script_data()->url()); 650 resolver->pending_set_pac_script_request()->CompleteNow(OK); 651 652 ASSERT_EQ(1u, resolver->pending_requests().size()); 653 EXPECT_EQ(url, resolver->pending_requests()[0]->url()); 654 655 // Fail the first resolve request in MockAsyncProxyResolver. 656 resolver->pending_requests()[0]->CompleteNow(ERR_FAILED); 657 658 // As the proxy resolver failed the request and is configured for a mandatory 659 // PAC script, ProxyService must not implicitly fall-back to DIRECT. 660 EXPECT_EQ(ERR_MANDATORY_PROXY_CONFIGURATION_FAILED, 661 callback1.WaitForResult()); 662 EXPECT_FALSE(info.is_direct()); 663 664 // The second resolve request will try to run through the proxy resolver, 665 // regardless of whether the first request failed in it. 666 TestCompletionCallback callback2; 667 rv = service.ResolveProxy( 668 url, &info, callback2.callback(), NULL, BoundNetLog()); 669 EXPECT_EQ(ERR_IO_PENDING, rv); 670 671 ASSERT_EQ(1u, resolver->pending_requests().size()); 672 EXPECT_EQ(url, resolver->pending_requests()[0]->url()); 673 674 // This time we will have the resolver succeed (perhaps the PAC script has 675 // a dependency on the current time). 676 resolver->pending_requests()[0]->results()->UseNamedProxy("foopy_valid:8080"); 677 resolver->pending_requests()[0]->CompleteNow(OK); 678 679 EXPECT_EQ(OK, callback2.WaitForResult()); 680 EXPECT_FALSE(info.is_direct()); 681 EXPECT_EQ("foopy_valid:8080", info.proxy_server().ToURI()); 682} 683 684TEST_F(ProxyServiceTest, ProxyFallback) { 685 // Test what happens when we specify multiple proxy servers and some of them 686 // are bad. 687 688 MockProxyConfigService* config_service = 689 new MockProxyConfigService("http://foopy/proxy.pac"); 690 691 MockAsyncProxyResolver* resolver = new MockAsyncProxyResolver; 692 693 ProxyService service(config_service, resolver, NULL); 694 695 GURL url("http://www.google.com/"); 696 697 // Get the proxy information. 698 ProxyInfo info; 699 TestCompletionCallback callback1; 700 int rv = service.ResolveProxy( 701 url, &info, callback1.callback(), NULL, BoundNetLog()); 702 EXPECT_EQ(ERR_IO_PENDING, rv); 703 704 EXPECT_EQ(GURL("http://foopy/proxy.pac"), 705 resolver->pending_set_pac_script_request()->script_data()->url()); 706 resolver->pending_set_pac_script_request()->CompleteNow(OK); 707 708 ASSERT_EQ(1u, resolver->pending_requests().size()); 709 EXPECT_EQ(url, resolver->pending_requests()[0]->url()); 710 711 // Set the result in proxy resolver. 712 resolver->pending_requests()[0]->results()->UseNamedProxy( 713 "foopy1:8080;foopy2:9090"); 714 resolver->pending_requests()[0]->CompleteNow(OK); 715 716 // The first item is valid. 717 EXPECT_EQ(OK, callback1.WaitForResult()); 718 EXPECT_FALSE(info.is_direct()); 719 EXPECT_EQ("foopy1:8080", info.proxy_server().ToURI()); 720 721 EXPECT_FALSE(info.proxy_resolve_start_time().is_null()); 722 EXPECT_FALSE(info.proxy_resolve_end_time().is_null()); 723 EXPECT_LE(info.proxy_resolve_start_time(), info.proxy_resolve_end_time()); 724 base::TimeTicks proxy_resolve_start_time = info.proxy_resolve_start_time(); 725 base::TimeTicks proxy_resolve_end_time = info.proxy_resolve_end_time(); 726 727 // Fake an error on the proxy. 728 TestCompletionCallback callback2; 729 rv = service.ReconsiderProxyAfterError(url, &info, callback2.callback(), NULL, 730 BoundNetLog()); 731 EXPECT_EQ(OK, rv); 732 733 // Proxy times should not have been modified by fallback. 734 EXPECT_EQ(proxy_resolve_start_time, info.proxy_resolve_start_time()); 735 EXPECT_EQ(proxy_resolve_end_time, info.proxy_resolve_end_time()); 736 737 // The second proxy should be specified. 738 EXPECT_EQ("foopy2:9090", info.proxy_server().ToURI()); 739 // Report back that the second proxy worked. This will globally mark the 740 // first proxy as bad. 741 service.ReportSuccess(info); 742 743 TestCompletionCallback callback3; 744 rv = service.ResolveProxy( 745 url, &info, callback3.callback(), NULL, BoundNetLog()); 746 EXPECT_EQ(ERR_IO_PENDING, rv); 747 748 ASSERT_EQ(1u, resolver->pending_requests().size()); 749 EXPECT_EQ(url, resolver->pending_requests()[0]->url()); 750 751 // Set the result in proxy resolver -- the second result is already known 752 // to be bad, so we will not try to use it initially. 753 resolver->pending_requests()[0]->results()->UseNamedProxy( 754 "foopy3:7070;foopy1:8080;foopy2:9090"); 755 resolver->pending_requests()[0]->CompleteNow(OK); 756 757 EXPECT_EQ(OK, callback3.WaitForResult()); 758 EXPECT_FALSE(info.is_direct()); 759 EXPECT_EQ("foopy3:7070", info.proxy_server().ToURI()); 760 761 // Proxy times should have been updated, so get them again. 762 EXPECT_LE(proxy_resolve_end_time, info.proxy_resolve_start_time()); 763 EXPECT_FALSE(info.proxy_resolve_start_time().is_null()); 764 EXPECT_FALSE(info.proxy_resolve_end_time().is_null()); 765 EXPECT_LE(info.proxy_resolve_start_time(), info.proxy_resolve_end_time()); 766 proxy_resolve_start_time = info.proxy_resolve_start_time(); 767 proxy_resolve_end_time = info.proxy_resolve_end_time(); 768 769 // We fake another error. It should now try the third one. 770 TestCompletionCallback callback4; 771 rv = service.ReconsiderProxyAfterError(url, &info, callback4.callback(), NULL, 772 BoundNetLog()); 773 EXPECT_EQ(OK, rv); 774 EXPECT_EQ("foopy2:9090", info.proxy_server().ToURI()); 775 776 // We fake another error. At this point we have tried all of the 777 // proxy servers we thought were valid; next we try the proxy server 778 // that was in our bad proxies map (foopy1:8080). 779 TestCompletionCallback callback5; 780 rv = service.ReconsiderProxyAfterError(url, &info, callback5.callback(), NULL, 781 BoundNetLog()); 782 EXPECT_EQ(OK, rv); 783 EXPECT_EQ("foopy1:8080", info.proxy_server().ToURI()); 784 785 // Fake another error, the last proxy is gone, the list should now be empty, 786 // so there is nothing left to try. 787 TestCompletionCallback callback6; 788 rv = service.ReconsiderProxyAfterError(url, &info, callback6.callback(), NULL, 789 BoundNetLog()); 790 EXPECT_EQ(ERR_FAILED, rv); 791 EXPECT_FALSE(info.is_direct()); 792 EXPECT_TRUE(info.is_empty()); 793 794 // Proxy times should not have been modified by fallback. 795 EXPECT_EQ(proxy_resolve_start_time, info.proxy_resolve_start_time()); 796 EXPECT_EQ(proxy_resolve_end_time, info.proxy_resolve_end_time()); 797 798 // Look up proxies again 799 TestCompletionCallback callback7; 800 rv = service.ResolveProxy(url, &info, callback7.callback(), NULL, 801 BoundNetLog()); 802 EXPECT_EQ(ERR_IO_PENDING, rv); 803 804 ASSERT_EQ(1u, resolver->pending_requests().size()); 805 EXPECT_EQ(url, resolver->pending_requests()[0]->url()); 806 807 // This time, the first 3 results have been found to be bad, but only the 808 // first proxy has been confirmed ... 809 resolver->pending_requests()[0]->results()->UseNamedProxy( 810 "foopy1:8080;foopy3:7070;foopy2:9090;foopy4:9091"); 811 resolver->pending_requests()[0]->CompleteNow(OK); 812 813 // ... therefore, we should see the second proxy first. 814 EXPECT_EQ(OK, callback7.WaitForResult()); 815 EXPECT_FALSE(info.is_direct()); 816 EXPECT_EQ("foopy3:7070", info.proxy_server().ToURI()); 817 818 EXPECT_LE(proxy_resolve_end_time, info.proxy_resolve_start_time()); 819 EXPECT_FALSE(info.proxy_resolve_start_time().is_null()); 820 EXPECT_FALSE(info.proxy_resolve_end_time().is_null()); 821 // TODO(nsylvain): Test that the proxy can be retried after the delay. 822} 823 824// This test is similar to ProxyFallback, but this time we have an explicit 825// fallback choice to DIRECT. 826TEST_F(ProxyServiceTest, ProxyFallbackToDirect) { 827 MockProxyConfigService* config_service = 828 new MockProxyConfigService("http://foopy/proxy.pac"); 829 830 MockAsyncProxyResolver* resolver = new MockAsyncProxyResolver; 831 832 ProxyService service(config_service, resolver, NULL); 833 834 GURL url("http://www.google.com/"); 835 836 // Get the proxy information. 837 ProxyInfo info; 838 TestCompletionCallback callback1; 839 int rv = service.ResolveProxy( 840 url, &info, callback1.callback(), NULL, BoundNetLog()); 841 EXPECT_EQ(ERR_IO_PENDING, rv); 842 843 EXPECT_EQ(GURL("http://foopy/proxy.pac"), 844 resolver->pending_set_pac_script_request()->script_data()->url()); 845 resolver->pending_set_pac_script_request()->CompleteNow(OK); 846 847 ASSERT_EQ(1u, resolver->pending_requests().size()); 848 EXPECT_EQ(url, resolver->pending_requests()[0]->url()); 849 850 // Set the result in proxy resolver. 851 resolver->pending_requests()[0]->results()->UsePacString( 852 "PROXY foopy1:8080; PROXY foopy2:9090; DIRECT"); 853 resolver->pending_requests()[0]->CompleteNow(OK); 854 855 // Get the first result. 856 EXPECT_EQ(OK, callback1.WaitForResult()); 857 EXPECT_FALSE(info.is_direct()); 858 EXPECT_EQ("foopy1:8080", info.proxy_server().ToURI()); 859 860 // Fake an error on the proxy. 861 TestCompletionCallback callback2; 862 rv = service.ReconsiderProxyAfterError(url, &info, callback2.callback(), NULL, 863 BoundNetLog()); 864 EXPECT_EQ(OK, rv); 865 866 // Now we get back the second proxy. 867 EXPECT_EQ("foopy2:9090", info.proxy_server().ToURI()); 868 869 // Fake an error on this proxy as well. 870 TestCompletionCallback callback3; 871 rv = service.ReconsiderProxyAfterError(url, &info, callback3.callback(), NULL, 872 BoundNetLog()); 873 EXPECT_EQ(OK, rv); 874 875 // Finally, we get back DIRECT. 876 EXPECT_TRUE(info.is_direct()); 877 878 EXPECT_FALSE(info.proxy_resolve_start_time().is_null()); 879 EXPECT_FALSE(info.proxy_resolve_end_time().is_null()); 880 EXPECT_LE(info.proxy_resolve_start_time(), info.proxy_resolve_end_time()); 881 882 // Now we tell the proxy service that even DIRECT failed. 883 TestCompletionCallback callback4; 884 rv = service.ReconsiderProxyAfterError(url, &info, callback4.callback(), NULL, 885 BoundNetLog()); 886 // There was nothing left to try after DIRECT, so we are out of 887 // choices. 888 EXPECT_EQ(ERR_FAILED, rv); 889} 890 891TEST_F(ProxyServiceTest, ProxyFallback_NewSettings) { 892 // Test proxy failover when new settings are available. 893 894 MockProxyConfigService* config_service = 895 new MockProxyConfigService("http://foopy/proxy.pac"); 896 897 MockAsyncProxyResolver* resolver = new MockAsyncProxyResolver; 898 899 ProxyService service(config_service, resolver, NULL); 900 901 GURL url("http://www.google.com/"); 902 903 // Get the proxy information. 904 ProxyInfo info; 905 TestCompletionCallback callback1; 906 int rv = service.ResolveProxy( 907 url, &info, callback1.callback(), NULL, BoundNetLog()); 908 EXPECT_EQ(ERR_IO_PENDING, rv); 909 910 EXPECT_EQ(GURL("http://foopy/proxy.pac"), 911 resolver->pending_set_pac_script_request()->script_data()->url()); 912 resolver->pending_set_pac_script_request()->CompleteNow(OK); 913 914 ASSERT_EQ(1u, resolver->pending_requests().size()); 915 EXPECT_EQ(url, resolver->pending_requests()[0]->url()); 916 917 // Set the result in proxy resolver. 918 resolver->pending_requests()[0]->results()->UseNamedProxy( 919 "foopy1:8080;foopy2:9090"); 920 resolver->pending_requests()[0]->CompleteNow(OK); 921 922 // The first item is valid. 923 EXPECT_EQ(OK, callback1.WaitForResult()); 924 EXPECT_FALSE(info.is_direct()); 925 EXPECT_EQ("foopy1:8080", info.proxy_server().ToURI()); 926 927 // Fake an error on the proxy, and also a new configuration on the proxy. 928 config_service->SetConfig( 929 ProxyConfig::CreateFromCustomPacURL(GURL("http://foopy-new/proxy.pac"))); 930 931 TestCompletionCallback callback2; 932 rv = service.ReconsiderProxyAfterError(url, &info, callback2.callback(), NULL, 933 BoundNetLog()); 934 EXPECT_EQ(ERR_IO_PENDING, rv); 935 936 EXPECT_EQ(GURL("http://foopy-new/proxy.pac"), 937 resolver->pending_set_pac_script_request()->script_data()->url()); 938 resolver->pending_set_pac_script_request()->CompleteNow(OK); 939 940 ASSERT_EQ(1u, resolver->pending_requests().size()); 941 EXPECT_EQ(url, resolver->pending_requests()[0]->url()); 942 943 resolver->pending_requests()[0]->results()->UseNamedProxy( 944 "foopy1:8080;foopy2:9090"); 945 resolver->pending_requests()[0]->CompleteNow(OK); 946 947 // The first proxy is still there since the configuration changed. 948 EXPECT_EQ(OK, callback2.WaitForResult()); 949 EXPECT_EQ("foopy1:8080", info.proxy_server().ToURI()); 950 951 // We fake another error. It should now ignore the first one. 952 TestCompletionCallback callback3; 953 rv = service.ReconsiderProxyAfterError(url, &info, callback3.callback(), NULL, 954 BoundNetLog()); 955 EXPECT_EQ(OK, rv); 956 EXPECT_EQ("foopy2:9090", info.proxy_server().ToURI()); 957 958 // We simulate a new configuration. 959 config_service->SetConfig( 960 ProxyConfig::CreateFromCustomPacURL( 961 GURL("http://foopy-new2/proxy.pac"))); 962 963 // We fake another error. It should go back to the first proxy. 964 TestCompletionCallback callback4; 965 rv = service.ReconsiderProxyAfterError(url, &info, callback4.callback(), NULL, 966 BoundNetLog()); 967 EXPECT_EQ(ERR_IO_PENDING, rv); 968 969 EXPECT_EQ(GURL("http://foopy-new2/proxy.pac"), 970 resolver->pending_set_pac_script_request()->script_data()->url()); 971 resolver->pending_set_pac_script_request()->CompleteNow(OK); 972 973 ASSERT_EQ(1u, resolver->pending_requests().size()); 974 EXPECT_EQ(url, resolver->pending_requests()[0]->url()); 975 976 resolver->pending_requests()[0]->results()->UseNamedProxy( 977 "foopy1:8080;foopy2:9090"); 978 resolver->pending_requests()[0]->CompleteNow(OK); 979 980 EXPECT_EQ(OK, callback4.WaitForResult()); 981 EXPECT_EQ("foopy1:8080", info.proxy_server().ToURI()); 982 983 EXPECT_FALSE(info.proxy_resolve_start_time().is_null()); 984 EXPECT_FALSE(info.proxy_resolve_end_time().is_null()); 985 EXPECT_LE(info.proxy_resolve_start_time(), info.proxy_resolve_end_time()); 986} 987 988TEST_F(ProxyServiceTest, ProxyFallback_BadConfig) { 989 // Test proxy failover when the configuration is bad. 990 991 MockProxyConfigService* config_service = 992 new MockProxyConfigService("http://foopy/proxy.pac"); 993 994 MockAsyncProxyResolver* resolver = new MockAsyncProxyResolver; 995 996 ProxyService service(config_service, resolver, NULL); 997 998 GURL url("http://www.google.com/"); 999 1000 // Get the proxy information. 1001 ProxyInfo info; 1002 TestCompletionCallback callback1; 1003 int rv = service.ResolveProxy( 1004 url, &info, callback1.callback(), NULL, BoundNetLog()); 1005 EXPECT_EQ(ERR_IO_PENDING, rv); 1006 1007 EXPECT_EQ(GURL("http://foopy/proxy.pac"), 1008 resolver->pending_set_pac_script_request()->script_data()->url()); 1009 resolver->pending_set_pac_script_request()->CompleteNow(OK); 1010 ASSERT_EQ(1u, resolver->pending_requests().size()); 1011 EXPECT_EQ(url, resolver->pending_requests()[0]->url()); 1012 1013 resolver->pending_requests()[0]->results()->UseNamedProxy( 1014 "foopy1:8080;foopy2:9090"); 1015 resolver->pending_requests()[0]->CompleteNow(OK); 1016 1017 // The first item is valid. 1018 EXPECT_EQ(OK, callback1.WaitForResult()); 1019 EXPECT_FALSE(info.is_direct()); 1020 EXPECT_EQ("foopy1:8080", info.proxy_server().ToURI()); 1021 1022 // Fake a proxy error. 1023 TestCompletionCallback callback2; 1024 rv = service.ReconsiderProxyAfterError(url, &info, callback2.callback(), NULL, 1025 BoundNetLog()); 1026 EXPECT_EQ(OK, rv); 1027 1028 // The first proxy is ignored, and the second one is selected. 1029 EXPECT_FALSE(info.is_direct()); 1030 EXPECT_EQ("foopy2:9090", info.proxy_server().ToURI()); 1031 1032 // Fake a PAC failure. 1033 ProxyInfo info2; 1034 TestCompletionCallback callback3; 1035 rv = service.ResolveProxy( 1036 url, &info2, callback3.callback(), NULL, BoundNetLog()); 1037 EXPECT_EQ(ERR_IO_PENDING, rv); 1038 1039 ASSERT_EQ(1u, resolver->pending_requests().size()); 1040 EXPECT_EQ(url, resolver->pending_requests()[0]->url()); 1041 1042 // This simulates a javascript runtime error in the PAC script. 1043 resolver->pending_requests()[0]->CompleteNow(ERR_FAILED); 1044 1045 // Although the resolver failed, the ProxyService will implicitly fall-back 1046 // to a DIRECT connection. 1047 EXPECT_EQ(OK, callback3.WaitForResult()); 1048 EXPECT_TRUE(info2.is_direct()); 1049 EXPECT_FALSE(info2.is_empty()); 1050 1051 // The PAC script will work properly next time and successfully return a 1052 // proxy list. Since we have not marked the configuration as bad, it should 1053 // "just work" the next time we call it. 1054 ProxyInfo info3; 1055 TestCompletionCallback callback4; 1056 rv = service.ReconsiderProxyAfterError(url, &info3, callback4.callback(), 1057 NULL, BoundNetLog()); 1058 EXPECT_EQ(ERR_IO_PENDING, rv); 1059 1060 ASSERT_EQ(1u, resolver->pending_requests().size()); 1061 EXPECT_EQ(url, resolver->pending_requests()[0]->url()); 1062 1063 resolver->pending_requests()[0]->results()->UseNamedProxy( 1064 "foopy1:8080;foopy2:9090"); 1065 resolver->pending_requests()[0]->CompleteNow(OK); 1066 1067 // The first proxy is not there since the it was added to the bad proxies 1068 // list by the earlier ReconsiderProxyAfterError(). 1069 EXPECT_EQ(OK, callback4.WaitForResult()); 1070 EXPECT_FALSE(info3.is_direct()); 1071 EXPECT_EQ("foopy1:8080", info3.proxy_server().ToURI()); 1072 1073 EXPECT_FALSE(info.proxy_resolve_start_time().is_null()); 1074 EXPECT_FALSE(info.proxy_resolve_end_time().is_null()); 1075 EXPECT_LE(info.proxy_resolve_start_time(), info.proxy_resolve_end_time()); 1076} 1077 1078TEST_F(ProxyServiceTest, ProxyFallback_BadConfigMandatory) { 1079 // Test proxy failover when the configuration is bad. 1080 1081 ProxyConfig config( 1082 ProxyConfig::CreateFromCustomPacURL(GURL("http://foopy/proxy.pac"))); 1083 1084 config.set_pac_mandatory(true); 1085 MockProxyConfigService* config_service = new MockProxyConfigService(config); 1086 1087 MockAsyncProxyResolver* resolver = new MockAsyncProxyResolver; 1088 1089 ProxyService service(config_service, resolver, NULL); 1090 1091 GURL url("http://www.google.com/"); 1092 1093 // Get the proxy information. 1094 ProxyInfo info; 1095 TestCompletionCallback callback1; 1096 int rv = service.ResolveProxy( 1097 url, &info, callback1.callback(), NULL, BoundNetLog()); 1098 EXPECT_EQ(ERR_IO_PENDING, rv); 1099 1100 EXPECT_EQ(GURL("http://foopy/proxy.pac"), 1101 resolver->pending_set_pac_script_request()->script_data()->url()); 1102 resolver->pending_set_pac_script_request()->CompleteNow(OK); 1103 ASSERT_EQ(1u, resolver->pending_requests().size()); 1104 EXPECT_EQ(url, resolver->pending_requests()[0]->url()); 1105 1106 resolver->pending_requests()[0]->results()->UseNamedProxy( 1107 "foopy1:8080;foopy2:9090"); 1108 resolver->pending_requests()[0]->CompleteNow(OK); 1109 1110 // The first item is valid. 1111 EXPECT_EQ(OK, callback1.WaitForResult()); 1112 EXPECT_FALSE(info.is_direct()); 1113 EXPECT_EQ("foopy1:8080", info.proxy_server().ToURI()); 1114 1115 // Fake a proxy error. 1116 TestCompletionCallback callback2; 1117 rv = service.ReconsiderProxyAfterError(url, &info, callback2.callback(), NULL, 1118 BoundNetLog()); 1119 EXPECT_EQ(OK, rv); 1120 1121 // The first proxy is ignored, and the second one is selected. 1122 EXPECT_FALSE(info.is_direct()); 1123 EXPECT_EQ("foopy2:9090", info.proxy_server().ToURI()); 1124 1125 // Fake a PAC failure. 1126 ProxyInfo info2; 1127 TestCompletionCallback callback3; 1128 rv = service.ResolveProxy( 1129 url, &info2, callback3.callback(), NULL, BoundNetLog()); 1130 EXPECT_EQ(ERR_IO_PENDING, rv); 1131 1132 ASSERT_EQ(1u, resolver->pending_requests().size()); 1133 EXPECT_EQ(url, resolver->pending_requests()[0]->url()); 1134 1135 // This simulates a javascript runtime error in the PAC script. 1136 resolver->pending_requests()[0]->CompleteNow(ERR_FAILED); 1137 1138 // Although the resolver failed, the ProxyService will NOT fall-back 1139 // to a DIRECT connection as it is configured as mandatory. 1140 EXPECT_EQ(ERR_MANDATORY_PROXY_CONFIGURATION_FAILED, 1141 callback3.WaitForResult()); 1142 EXPECT_FALSE(info2.is_direct()); 1143 EXPECT_TRUE(info2.is_empty()); 1144 1145 // The PAC script will work properly next time and successfully return a 1146 // proxy list. Since we have not marked the configuration as bad, it should 1147 // "just work" the next time we call it. 1148 ProxyInfo info3; 1149 TestCompletionCallback callback4; 1150 rv = service.ReconsiderProxyAfterError(url, &info3, callback4.callback(), 1151 NULL, BoundNetLog()); 1152 EXPECT_EQ(ERR_IO_PENDING, rv); 1153 1154 ASSERT_EQ(1u, resolver->pending_requests().size()); 1155 EXPECT_EQ(url, resolver->pending_requests()[0]->url()); 1156 1157 resolver->pending_requests()[0]->results()->UseNamedProxy( 1158 "foopy1:8080;foopy2:9090"); 1159 resolver->pending_requests()[0]->CompleteNow(OK); 1160 1161 // The first proxy is not there since the it was added to the bad proxies 1162 // list by the earlier ReconsiderProxyAfterError(). 1163 EXPECT_EQ(OK, callback4.WaitForResult()); 1164 EXPECT_FALSE(info3.is_direct()); 1165 EXPECT_EQ("foopy1:8080", info3.proxy_server().ToURI()); 1166} 1167 1168TEST_F(ProxyServiceTest, ProxyBypassList) { 1169 // Test that the proxy bypass rules are consulted. 1170 1171 TestCompletionCallback callback[2]; 1172 ProxyInfo info[2]; 1173 ProxyConfig config; 1174 config.proxy_rules().ParseFromString("foopy1:8080;foopy2:9090"); 1175 config.set_auto_detect(false); 1176 config.proxy_rules().bypass_rules.ParseFromString("*.org"); 1177 1178 ProxyService service( 1179 new MockProxyConfigService(config), new MockAsyncProxyResolver, NULL); 1180 1181 int rv; 1182 GURL url1("http://www.webkit.org"); 1183 GURL url2("http://www.webkit.com"); 1184 1185 // Request for a .org domain should bypass proxy. 1186 rv = service.ResolveProxy( 1187 url1, &info[0], callback[0].callback(), NULL, BoundNetLog()); 1188 EXPECT_EQ(OK, rv); 1189 EXPECT_TRUE(info[0].is_direct()); 1190 1191 // Request for a .com domain hits the proxy. 1192 rv = service.ResolveProxy( 1193 url2, &info[1], callback[1].callback(), NULL, BoundNetLog()); 1194 EXPECT_EQ(OK, rv); 1195 EXPECT_EQ("foopy1:8080", info[1].proxy_server().ToURI()); 1196} 1197 1198 1199TEST_F(ProxyServiceTest, PerProtocolProxyTests) { 1200 ProxyConfig config; 1201 config.proxy_rules().ParseFromString("http=foopy1:8080;https=foopy2:8080"); 1202 config.set_auto_detect(false); 1203 { 1204 ProxyService service( 1205 new MockProxyConfigService(config), new MockAsyncProxyResolver, NULL); 1206 GURL test_url("http://www.msn.com"); 1207 ProxyInfo info; 1208 TestCompletionCallback callback; 1209 int rv = service.ResolveProxy(test_url, &info, callback.callback(), NULL, 1210 BoundNetLog()); 1211 EXPECT_EQ(OK, rv); 1212 EXPECT_FALSE(info.is_direct()); 1213 EXPECT_EQ("foopy1:8080", info.proxy_server().ToURI()); 1214 } 1215 { 1216 ProxyService service( 1217 new MockProxyConfigService(config), new MockAsyncProxyResolver, NULL); 1218 GURL test_url("ftp://ftp.google.com"); 1219 ProxyInfo info; 1220 TestCompletionCallback callback; 1221 int rv = service.ResolveProxy(test_url, &info, callback.callback(), NULL, 1222 BoundNetLog()); 1223 EXPECT_EQ(OK, rv); 1224 EXPECT_TRUE(info.is_direct()); 1225 EXPECT_EQ("direct://", info.proxy_server().ToURI()); 1226 } 1227 { 1228 ProxyService service( 1229 new MockProxyConfigService(config), new MockAsyncProxyResolver, NULL); 1230 GURL test_url("https://webbranch.techcu.com"); 1231 ProxyInfo info; 1232 TestCompletionCallback callback; 1233 int rv = service.ResolveProxy(test_url, &info, callback.callback(), NULL, 1234 BoundNetLog()); 1235 EXPECT_EQ(OK, rv); 1236 EXPECT_FALSE(info.is_direct()); 1237 EXPECT_EQ("foopy2:8080", info.proxy_server().ToURI()); 1238 } 1239 { 1240 config.proxy_rules().ParseFromString("foopy1:8080"); 1241 ProxyService service( 1242 new MockProxyConfigService(config), new MockAsyncProxyResolver, NULL); 1243 GURL test_url("http://www.microsoft.com"); 1244 ProxyInfo info; 1245 TestCompletionCallback callback; 1246 int rv = service.ResolveProxy(test_url, &info, callback.callback(), NULL, 1247 BoundNetLog()); 1248 EXPECT_EQ(OK, rv); 1249 EXPECT_FALSE(info.is_direct()); 1250 EXPECT_EQ("foopy1:8080", info.proxy_server().ToURI()); 1251 } 1252} 1253 1254TEST_F(ProxyServiceTest, ProxyConfigSourcePropagates) { 1255 // Test that the proxy config source is set correctly when resolving proxies 1256 // using manual proxy rules. Namely, the config source should only be set if 1257 // any of the rules were applied. 1258 { 1259 ProxyConfig config; 1260 config.set_source(PROXY_CONFIG_SOURCE_TEST); 1261 config.proxy_rules().ParseFromString("https=foopy2:8080"); 1262 ProxyService service( 1263 new MockProxyConfigService(config), new MockAsyncProxyResolver, NULL); 1264 GURL test_url("http://www.google.com"); 1265 ProxyInfo info; 1266 TestCompletionCallback callback; 1267 int rv = service.ResolveProxy(test_url, &info, callback.callback(), NULL, 1268 BoundNetLog()); 1269 ASSERT_EQ(OK, rv); 1270 // Should be SOURCE_TEST, even if there are no HTTP proxies configured. 1271 EXPECT_EQ(PROXY_CONFIG_SOURCE_TEST, info.config_source()); 1272 } 1273 { 1274 ProxyConfig config; 1275 config.set_source(PROXY_CONFIG_SOURCE_TEST); 1276 config.proxy_rules().ParseFromString("https=foopy2:8080"); 1277 ProxyService service( 1278 new MockProxyConfigService(config), new MockAsyncProxyResolver, NULL); 1279 GURL test_url("https://www.google.com"); 1280 ProxyInfo info; 1281 TestCompletionCallback callback; 1282 int rv = service.ResolveProxy(test_url, &info, callback.callback(), NULL, 1283 BoundNetLog()); 1284 ASSERT_EQ(OK, rv); 1285 // Used the HTTPS proxy. So source should be TEST. 1286 EXPECT_EQ(PROXY_CONFIG_SOURCE_TEST, info.config_source()); 1287 } 1288 { 1289 ProxyConfig config; 1290 config.set_source(PROXY_CONFIG_SOURCE_TEST); 1291 ProxyService service( 1292 new MockProxyConfigService(config), new MockAsyncProxyResolver, NULL); 1293 GURL test_url("http://www.google.com"); 1294 ProxyInfo info; 1295 TestCompletionCallback callback; 1296 int rv = service.ResolveProxy(test_url, &info, callback.callback(), NULL, 1297 BoundNetLog()); 1298 ASSERT_EQ(OK, rv); 1299 // ProxyConfig is empty. Source should still be TEST. 1300 EXPECT_EQ(PROXY_CONFIG_SOURCE_TEST, info.config_source()); 1301 } 1302} 1303 1304// If only HTTP and a SOCKS proxy are specified, check if ftp/https queries 1305// fall back to the SOCKS proxy. 1306TEST_F(ProxyServiceTest, DefaultProxyFallbackToSOCKS) { 1307 ProxyConfig config; 1308 config.proxy_rules().ParseFromString("http=foopy1:8080;socks=foopy2:1080"); 1309 config.set_auto_detect(false); 1310 EXPECT_EQ(ProxyConfig::ProxyRules::TYPE_PROXY_PER_SCHEME, 1311 config.proxy_rules().type); 1312 1313 { 1314 ProxyService service( 1315 new MockProxyConfigService(config), new MockAsyncProxyResolver, NULL); 1316 GURL test_url("http://www.msn.com"); 1317 ProxyInfo info; 1318 TestCompletionCallback callback; 1319 int rv = service.ResolveProxy(test_url, &info, callback.callback(), NULL, 1320 BoundNetLog()); 1321 EXPECT_EQ(OK, rv); 1322 EXPECT_FALSE(info.is_direct()); 1323 EXPECT_EQ("foopy1:8080", info.proxy_server().ToURI()); 1324 } 1325 { 1326 ProxyService service( 1327 new MockProxyConfigService(config), new MockAsyncProxyResolver, NULL); 1328 GURL test_url("ftp://ftp.google.com"); 1329 ProxyInfo info; 1330 TestCompletionCallback callback; 1331 int rv = service.ResolveProxy(test_url, &info, callback.callback(), NULL, 1332 BoundNetLog()); 1333 EXPECT_EQ(OK, rv); 1334 EXPECT_FALSE(info.is_direct()); 1335 EXPECT_EQ("socks4://foopy2:1080", info.proxy_server().ToURI()); 1336 } 1337 { 1338 ProxyService service( 1339 new MockProxyConfigService(config), new MockAsyncProxyResolver, NULL); 1340 GURL test_url("https://webbranch.techcu.com"); 1341 ProxyInfo info; 1342 TestCompletionCallback callback; 1343 int rv = service.ResolveProxy(test_url, &info, callback.callback(), NULL, 1344 BoundNetLog()); 1345 EXPECT_EQ(OK, rv); 1346 EXPECT_FALSE(info.is_direct()); 1347 EXPECT_EQ("socks4://foopy2:1080", info.proxy_server().ToURI()); 1348 } 1349 { 1350 ProxyService service( 1351 new MockProxyConfigService(config), new MockAsyncProxyResolver, NULL); 1352 GURL test_url("unknown://www.microsoft.com"); 1353 ProxyInfo info; 1354 TestCompletionCallback callback; 1355 int rv = service.ResolveProxy(test_url, &info, callback.callback(), NULL, 1356 BoundNetLog()); 1357 EXPECT_EQ(OK, rv); 1358 EXPECT_FALSE(info.is_direct()); 1359 EXPECT_EQ("socks4://foopy2:1080", info.proxy_server().ToURI()); 1360 } 1361} 1362 1363// Test cancellation of an in-progress request. 1364TEST_F(ProxyServiceTest, CancelInProgressRequest) { 1365 MockProxyConfigService* config_service = 1366 new MockProxyConfigService("http://foopy/proxy.pac"); 1367 1368 MockAsyncProxyResolver* resolver = new MockAsyncProxyResolver; 1369 1370 ProxyService service(config_service, resolver, NULL); 1371 1372 // Start 3 requests. 1373 1374 ProxyInfo info1; 1375 TestCompletionCallback callback1; 1376 int rv = service.ResolveProxy(GURL("http://request1"), &info1, 1377 callback1.callback(), NULL, BoundNetLog()); 1378 EXPECT_EQ(ERR_IO_PENDING, rv); 1379 1380 // Nothing has been sent to the proxy resolver yet, since the proxy 1381 // resolver has not been configured yet. 1382 ASSERT_EQ(0u, resolver->pending_requests().size()); 1383 1384 // Successfully initialize the PAC script. 1385 EXPECT_EQ(GURL("http://foopy/proxy.pac"), 1386 resolver->pending_set_pac_script_request()->script_data()->url()); 1387 resolver->pending_set_pac_script_request()->CompleteNow(OK); 1388 1389 ASSERT_EQ(1u, resolver->pending_requests().size()); 1390 EXPECT_EQ(GURL("http://request1"), resolver->pending_requests()[0]->url()); 1391 1392 ProxyInfo info2; 1393 TestCompletionCallback callback2; 1394 ProxyService::PacRequest* request2; 1395 rv = service.ResolveProxy(GURL("http://request2"), &info2, 1396 callback2.callback(), &request2, BoundNetLog()); 1397 EXPECT_EQ(ERR_IO_PENDING, rv); 1398 ASSERT_EQ(2u, resolver->pending_requests().size()); 1399 EXPECT_EQ(GURL("http://request2"), resolver->pending_requests()[1]->url()); 1400 1401 ProxyInfo info3; 1402 TestCompletionCallback callback3; 1403 rv = service.ResolveProxy(GURL("http://request3"), &info3, 1404 callback3.callback(), NULL, BoundNetLog()); 1405 EXPECT_EQ(ERR_IO_PENDING, rv); 1406 ASSERT_EQ(3u, resolver->pending_requests().size()); 1407 EXPECT_EQ(GURL("http://request3"), resolver->pending_requests()[2]->url()); 1408 1409 // Cancel the second request 1410 service.CancelPacRequest(request2); 1411 1412 ASSERT_EQ(2u, resolver->pending_requests().size()); 1413 EXPECT_EQ(GURL("http://request1"), resolver->pending_requests()[0]->url()); 1414 EXPECT_EQ(GURL("http://request3"), resolver->pending_requests()[1]->url()); 1415 1416 // Complete the two un-cancelled requests. 1417 // We complete the last one first, just to mix it up a bit. 1418 resolver->pending_requests()[1]->results()->UseNamedProxy("request3:80"); 1419 resolver->pending_requests()[1]->CompleteNow(OK); 1420 1421 resolver->pending_requests()[0]->results()->UseNamedProxy("request1:80"); 1422 resolver->pending_requests()[0]->CompleteNow(OK); 1423 1424 // Complete and verify that requests ran as expected. 1425 EXPECT_EQ(OK, callback1.WaitForResult()); 1426 EXPECT_EQ("request1:80", info1.proxy_server().ToURI()); 1427 1428 EXPECT_FALSE(callback2.have_result()); // Cancelled. 1429 ASSERT_EQ(1u, resolver->cancelled_requests().size()); 1430 EXPECT_EQ(GURL("http://request2"), resolver->cancelled_requests()[0]->url()); 1431 1432 EXPECT_EQ(OK, callback3.WaitForResult()); 1433 EXPECT_EQ("request3:80", info3.proxy_server().ToURI()); 1434} 1435 1436// Test the initial PAC download for resolver that expects bytes. 1437TEST_F(ProxyServiceTest, InitialPACScriptDownload) { 1438 MockProxyConfigService* config_service = 1439 new MockProxyConfigService("http://foopy/proxy.pac"); 1440 1441 MockAsyncProxyResolverExpectsBytes* resolver = 1442 new MockAsyncProxyResolverExpectsBytes; 1443 1444 ProxyService service(config_service, resolver, NULL); 1445 1446 MockProxyScriptFetcher* fetcher = new MockProxyScriptFetcher; 1447 service.SetProxyScriptFetchers(fetcher, 1448 new DoNothingDhcpProxyScriptFetcher()); 1449 1450 // Start 3 requests. 1451 1452 ProxyInfo info1; 1453 TestCompletionCallback callback1; 1454 ProxyService::PacRequest* request1; 1455 int rv = service.ResolveProxy(GURL("http://request1"), &info1, 1456 callback1.callback(), &request1, BoundNetLog()); 1457 EXPECT_EQ(ERR_IO_PENDING, rv); 1458 1459 // The first request should have triggered download of PAC script. 1460 EXPECT_TRUE(fetcher->has_pending_request()); 1461 EXPECT_EQ(GURL("http://foopy/proxy.pac"), fetcher->pending_request_url()); 1462 1463 ProxyInfo info2; 1464 TestCompletionCallback callback2; 1465 ProxyService::PacRequest* request2; 1466 rv = service.ResolveProxy(GURL("http://request2"), &info2, 1467 callback2.callback(), &request2, BoundNetLog()); 1468 EXPECT_EQ(ERR_IO_PENDING, rv); 1469 1470 ProxyInfo info3; 1471 TestCompletionCallback callback3; 1472 ProxyService::PacRequest* request3; 1473 rv = service.ResolveProxy(GURL("http://request3"), &info3, 1474 callback3.callback(), &request3, BoundNetLog()); 1475 EXPECT_EQ(ERR_IO_PENDING, rv); 1476 1477 // Nothing has been sent to the resolver yet. 1478 EXPECT_TRUE(resolver->pending_requests().empty()); 1479 1480 EXPECT_EQ(LOAD_STATE_DOWNLOADING_PROXY_SCRIPT, 1481 service.GetLoadState(request1)); 1482 EXPECT_EQ(LOAD_STATE_DOWNLOADING_PROXY_SCRIPT, 1483 service.GetLoadState(request2)); 1484 EXPECT_EQ(LOAD_STATE_DOWNLOADING_PROXY_SCRIPT, 1485 service.GetLoadState(request3)); 1486 1487 // At this point the ProxyService should be waiting for the 1488 // ProxyScriptFetcher to invoke its completion callback, notifying it of 1489 // PAC script download completion. 1490 fetcher->NotifyFetchCompletion(OK, kValidPacScript1); 1491 1492 // Now that the PAC script is downloaded, it will have been sent to the proxy 1493 // resolver. 1494 EXPECT_EQ(ASCIIToUTF16(kValidPacScript1), 1495 resolver->pending_set_pac_script_request()->script_data()->utf16()); 1496 resolver->pending_set_pac_script_request()->CompleteNow(OK); 1497 1498 ASSERT_EQ(3u, resolver->pending_requests().size()); 1499 EXPECT_EQ(GURL("http://request1"), resolver->pending_requests()[0]->url()); 1500 EXPECT_EQ(GURL("http://request2"), resolver->pending_requests()[1]->url()); 1501 EXPECT_EQ(GURL("http://request3"), resolver->pending_requests()[2]->url()); 1502 1503 EXPECT_EQ(LOAD_STATE_RESOLVING_PROXY_FOR_URL, service.GetLoadState(request1)); 1504 EXPECT_EQ(LOAD_STATE_RESOLVING_PROXY_FOR_URL, service.GetLoadState(request2)); 1505 EXPECT_EQ(LOAD_STATE_RESOLVING_PROXY_FOR_URL, service.GetLoadState(request3)); 1506 1507 // Complete all the requests (in some order). 1508 // Note that as we complete requests, they shift up in |pending_requests()|. 1509 1510 resolver->pending_requests()[2]->results()->UseNamedProxy("request3:80"); 1511 resolver->pending_requests()[2]->CompleteNow(OK); 1512 1513 resolver->pending_requests()[0]->results()->UseNamedProxy("request1:80"); 1514 resolver->pending_requests()[0]->CompleteNow(OK); 1515 1516 resolver->pending_requests()[0]->results()->UseNamedProxy("request2:80"); 1517 resolver->pending_requests()[0]->CompleteNow(OK); 1518 1519 // Complete and verify that requests ran as expected. 1520 EXPECT_EQ(OK, callback1.WaitForResult()); 1521 EXPECT_EQ("request1:80", info1.proxy_server().ToURI()); 1522 EXPECT_FALSE(info1.proxy_resolve_start_time().is_null()); 1523 EXPECT_FALSE(info1.proxy_resolve_end_time().is_null()); 1524 EXPECT_LE(info1.proxy_resolve_start_time(), info1.proxy_resolve_end_time()); 1525 1526 EXPECT_EQ(OK, callback2.WaitForResult()); 1527 EXPECT_EQ("request2:80", info2.proxy_server().ToURI()); 1528 EXPECT_FALSE(info2.proxy_resolve_start_time().is_null()); 1529 EXPECT_FALSE(info2.proxy_resolve_end_time().is_null()); 1530 EXPECT_LE(info2.proxy_resolve_start_time(), info2.proxy_resolve_end_time()); 1531 1532 EXPECT_EQ(OK, callback3.WaitForResult()); 1533 EXPECT_EQ("request3:80", info3.proxy_server().ToURI()); 1534 EXPECT_FALSE(info3.proxy_resolve_start_time().is_null()); 1535 EXPECT_FALSE(info3.proxy_resolve_end_time().is_null()); 1536 EXPECT_LE(info3.proxy_resolve_start_time(), info3.proxy_resolve_end_time()); 1537} 1538 1539// Test changing the ProxyScriptFetcher while PAC download is in progress. 1540TEST_F(ProxyServiceTest, ChangeScriptFetcherWhilePACDownloadInProgress) { 1541 MockProxyConfigService* config_service = 1542 new MockProxyConfigService("http://foopy/proxy.pac"); 1543 1544 MockAsyncProxyResolverExpectsBytes* resolver = 1545 new MockAsyncProxyResolverExpectsBytes; 1546 1547 ProxyService service(config_service, resolver, NULL); 1548 1549 MockProxyScriptFetcher* fetcher = new MockProxyScriptFetcher; 1550 service.SetProxyScriptFetchers(fetcher, 1551 new DoNothingDhcpProxyScriptFetcher()); 1552 1553 // Start 2 requests. 1554 1555 ProxyInfo info1; 1556 TestCompletionCallback callback1; 1557 int rv = service.ResolveProxy(GURL("http://request1"), &info1, 1558 callback1.callback(), NULL, BoundNetLog()); 1559 EXPECT_EQ(ERR_IO_PENDING, rv); 1560 1561 // The first request should have triggered download of PAC script. 1562 EXPECT_TRUE(fetcher->has_pending_request()); 1563 EXPECT_EQ(GURL("http://foopy/proxy.pac"), fetcher->pending_request_url()); 1564 1565 ProxyInfo info2; 1566 TestCompletionCallback callback2; 1567 rv = service.ResolveProxy(GURL("http://request2"), &info2, 1568 callback2.callback(), NULL, BoundNetLog()); 1569 EXPECT_EQ(ERR_IO_PENDING, rv); 1570 1571 // At this point the ProxyService should be waiting for the 1572 // ProxyScriptFetcher to invoke its completion callback, notifying it of 1573 // PAC script download completion. 1574 1575 // We now change out the ProxyService's script fetcher. We should restart 1576 // the initialization with the new fetcher. 1577 1578 fetcher = new MockProxyScriptFetcher; 1579 service.SetProxyScriptFetchers(fetcher, 1580 new DoNothingDhcpProxyScriptFetcher()); 1581 1582 // Nothing has been sent to the resolver yet. 1583 EXPECT_TRUE(resolver->pending_requests().empty()); 1584 1585 fetcher->NotifyFetchCompletion(OK, kValidPacScript1); 1586 1587 // Now that the PAC script is downloaded, it will have been sent to the proxy 1588 // resolver. 1589 EXPECT_EQ(ASCIIToUTF16(kValidPacScript1), 1590 resolver->pending_set_pac_script_request()->script_data()->utf16()); 1591 resolver->pending_set_pac_script_request()->CompleteNow(OK); 1592 1593 ASSERT_EQ(2u, resolver->pending_requests().size()); 1594 EXPECT_EQ(GURL("http://request1"), resolver->pending_requests()[0]->url()); 1595 EXPECT_EQ(GURL("http://request2"), resolver->pending_requests()[1]->url()); 1596} 1597 1598// Test cancellation of a request, while the PAC script is being fetched. 1599TEST_F(ProxyServiceTest, CancelWhilePACFetching) { 1600 MockProxyConfigService* config_service = 1601 new MockProxyConfigService("http://foopy/proxy.pac"); 1602 1603 MockAsyncProxyResolverExpectsBytes* resolver = 1604 new MockAsyncProxyResolverExpectsBytes; 1605 1606 ProxyService service(config_service, resolver, NULL); 1607 1608 MockProxyScriptFetcher* fetcher = new MockProxyScriptFetcher; 1609 service.SetProxyScriptFetchers(fetcher, 1610 new DoNothingDhcpProxyScriptFetcher()); 1611 1612 // Start 3 requests. 1613 ProxyInfo info1; 1614 TestCompletionCallback callback1; 1615 ProxyService::PacRequest* request1; 1616 CapturingBoundNetLog log1; 1617 int rv = service.ResolveProxy(GURL("http://request1"), &info1, 1618 callback1.callback(), &request1, log1.bound()); 1619 EXPECT_EQ(ERR_IO_PENDING, rv); 1620 1621 // The first request should have triggered download of PAC script. 1622 EXPECT_TRUE(fetcher->has_pending_request()); 1623 EXPECT_EQ(GURL("http://foopy/proxy.pac"), fetcher->pending_request_url()); 1624 1625 ProxyInfo info2; 1626 TestCompletionCallback callback2; 1627 ProxyService::PacRequest* request2; 1628 rv = service.ResolveProxy(GURL("http://request2"), &info2, 1629 callback2.callback(), &request2, BoundNetLog()); 1630 EXPECT_EQ(ERR_IO_PENDING, rv); 1631 1632 ProxyInfo info3; 1633 TestCompletionCallback callback3; 1634 rv = service.ResolveProxy(GURL("http://request3"), &info3, 1635 callback3.callback(), NULL, BoundNetLog()); 1636 EXPECT_EQ(ERR_IO_PENDING, rv); 1637 1638 // Nothing has been sent to the resolver yet. 1639 EXPECT_TRUE(resolver->pending_requests().empty()); 1640 1641 // Cancel the first 2 requests. 1642 service.CancelPacRequest(request1); 1643 service.CancelPacRequest(request2); 1644 1645 // At this point the ProxyService should be waiting for the 1646 // ProxyScriptFetcher to invoke its completion callback, notifying it of 1647 // PAC script download completion. 1648 fetcher->NotifyFetchCompletion(OK, kValidPacScript1); 1649 1650 // Now that the PAC script is downloaded, it will have been sent to the 1651 // proxy resolver. 1652 EXPECT_EQ(ASCIIToUTF16(kValidPacScript1), 1653 resolver->pending_set_pac_script_request()->script_data()->utf16()); 1654 resolver->pending_set_pac_script_request()->CompleteNow(OK); 1655 1656 ASSERT_EQ(1u, resolver->pending_requests().size()); 1657 EXPECT_EQ(GURL("http://request3"), resolver->pending_requests()[0]->url()); 1658 1659 // Complete all the requests. 1660 resolver->pending_requests()[0]->results()->UseNamedProxy("request3:80"); 1661 resolver->pending_requests()[0]->CompleteNow(OK); 1662 1663 EXPECT_EQ(OK, callback3.WaitForResult()); 1664 EXPECT_EQ("request3:80", info3.proxy_server().ToURI()); 1665 1666 EXPECT_TRUE(resolver->cancelled_requests().empty()); 1667 1668 EXPECT_FALSE(callback1.have_result()); // Cancelled. 1669 EXPECT_FALSE(callback2.have_result()); // Cancelled. 1670 1671 CapturingNetLog::CapturedEntryList entries1; 1672 log1.GetEntries(&entries1); 1673 1674 // Check the NetLog for request 1 (which was cancelled) got filled properly. 1675 EXPECT_EQ(4u, entries1.size()); 1676 EXPECT_TRUE(LogContainsBeginEvent( 1677 entries1, 0, NetLog::TYPE_PROXY_SERVICE)); 1678 EXPECT_TRUE(LogContainsBeginEvent( 1679 entries1, 1, NetLog::TYPE_PROXY_SERVICE_WAITING_FOR_INIT_PAC)); 1680 // Note that TYPE_PROXY_SERVICE_WAITING_FOR_INIT_PAC is never completed before 1681 // the cancellation occured. 1682 EXPECT_TRUE(LogContainsEvent( 1683 entries1, 2, NetLog::TYPE_CANCELLED, NetLog::PHASE_NONE)); 1684 EXPECT_TRUE(LogContainsEndEvent( 1685 entries1, 3, NetLog::TYPE_PROXY_SERVICE)); 1686} 1687 1688// Test that if auto-detect fails, we fall-back to the custom pac. 1689TEST_F(ProxyServiceTest, FallbackFromAutodetectToCustomPac) { 1690 ProxyConfig config; 1691 config.set_auto_detect(true); 1692 config.set_pac_url(GURL("http://foopy/proxy.pac")); 1693 config.proxy_rules().ParseFromString("http=foopy:80"); // Won't be used. 1694 1695 MockProxyConfigService* config_service = new MockProxyConfigService(config); 1696 MockAsyncProxyResolverExpectsBytes* resolver = 1697 new MockAsyncProxyResolverExpectsBytes; 1698 ProxyService service(config_service, resolver, NULL); 1699 1700 MockProxyScriptFetcher* fetcher = new MockProxyScriptFetcher; 1701 service.SetProxyScriptFetchers(fetcher, 1702 new DoNothingDhcpProxyScriptFetcher()); 1703 1704 // Start 2 requests. 1705 1706 ProxyInfo info1; 1707 TestCompletionCallback callback1; 1708 int rv = service.ResolveProxy(GURL("http://request1"), &info1, 1709 callback1.callback(), NULL, BoundNetLog()); 1710 EXPECT_EQ(ERR_IO_PENDING, rv); 1711 1712 ProxyInfo info2; 1713 TestCompletionCallback callback2; 1714 ProxyService::PacRequest* request2; 1715 rv = service.ResolveProxy(GURL("http://request2"), &info2, 1716 callback2.callback(), &request2, BoundNetLog()); 1717 EXPECT_EQ(ERR_IO_PENDING, rv); 1718 1719 // Check that nothing has been sent to the proxy resolver yet. 1720 ASSERT_EQ(0u, resolver->pending_requests().size()); 1721 1722 // It should be trying to auto-detect first -- FAIL the autodetect during 1723 // the script download. 1724 EXPECT_TRUE(fetcher->has_pending_request()); 1725 EXPECT_EQ(GURL("http://wpad/wpad.dat"), fetcher->pending_request_url()); 1726 fetcher->NotifyFetchCompletion(ERR_FAILED, std::string()); 1727 1728 // Next it should be trying the custom PAC url. 1729 EXPECT_TRUE(fetcher->has_pending_request()); 1730 EXPECT_EQ(GURL("http://foopy/proxy.pac"), fetcher->pending_request_url()); 1731 fetcher->NotifyFetchCompletion(OK, kValidPacScript1); 1732 1733 EXPECT_EQ(ASCIIToUTF16(kValidPacScript1), 1734 resolver->pending_set_pac_script_request()->script_data()->utf16()); 1735 resolver->pending_set_pac_script_request()->CompleteNow(OK); 1736 1737 // Now finally, the pending requests should have been sent to the resolver 1738 // (which was initialized with custom PAC script). 1739 1740 ASSERT_EQ(2u, resolver->pending_requests().size()); 1741 EXPECT_EQ(GURL("http://request1"), resolver->pending_requests()[0]->url()); 1742 EXPECT_EQ(GURL("http://request2"), resolver->pending_requests()[1]->url()); 1743 1744 // Complete the pending requests. 1745 resolver->pending_requests()[1]->results()->UseNamedProxy("request2:80"); 1746 resolver->pending_requests()[1]->CompleteNow(OK); 1747 resolver->pending_requests()[0]->results()->UseNamedProxy("request1:80"); 1748 resolver->pending_requests()[0]->CompleteNow(OK); 1749 1750 // Verify that requests ran as expected. 1751 EXPECT_EQ(OK, callback1.WaitForResult()); 1752 EXPECT_EQ("request1:80", info1.proxy_server().ToURI()); 1753 EXPECT_FALSE(info1.proxy_resolve_start_time().is_null()); 1754 EXPECT_FALSE(info1.proxy_resolve_end_time().is_null()); 1755 EXPECT_LE(info1.proxy_resolve_start_time(), info1.proxy_resolve_end_time()); 1756 1757 EXPECT_EQ(OK, callback2.WaitForResult()); 1758 EXPECT_EQ("request2:80", info2.proxy_server().ToURI()); 1759 EXPECT_FALSE(info2.proxy_resolve_start_time().is_null()); 1760 EXPECT_FALSE(info2.proxy_resolve_end_time().is_null()); 1761 EXPECT_LE(info2.proxy_resolve_start_time(), info2.proxy_resolve_end_time()); 1762} 1763 1764// This is the same test as FallbackFromAutodetectToCustomPac, except 1765// the auto-detect script fails parsing rather than downloading. 1766TEST_F(ProxyServiceTest, FallbackFromAutodetectToCustomPac2) { 1767 ProxyConfig config; 1768 config.set_auto_detect(true); 1769 config.set_pac_url(GURL("http://foopy/proxy.pac")); 1770 config.proxy_rules().ParseFromString("http=foopy:80"); // Won't be used. 1771 1772 MockProxyConfigService* config_service = new MockProxyConfigService(config); 1773 MockAsyncProxyResolverExpectsBytes* resolver = 1774 new MockAsyncProxyResolverExpectsBytes; 1775 ProxyService service(config_service, resolver, NULL); 1776 1777 MockProxyScriptFetcher* fetcher = new MockProxyScriptFetcher; 1778 service.SetProxyScriptFetchers(fetcher, 1779 new DoNothingDhcpProxyScriptFetcher()); 1780 1781 // Start 2 requests. 1782 1783 ProxyInfo info1; 1784 TestCompletionCallback callback1; 1785 int rv = service.ResolveProxy(GURL("http://request1"), &info1, 1786 callback1.callback(), NULL, BoundNetLog()); 1787 EXPECT_EQ(ERR_IO_PENDING, rv); 1788 1789 ProxyInfo info2; 1790 TestCompletionCallback callback2; 1791 ProxyService::PacRequest* request2; 1792 rv = service.ResolveProxy(GURL("http://request2"), &info2, 1793 callback2.callback(), &request2, BoundNetLog()); 1794 EXPECT_EQ(ERR_IO_PENDING, rv); 1795 1796 // Check that nothing has been sent to the proxy resolver yet. 1797 ASSERT_EQ(0u, resolver->pending_requests().size()); 1798 1799 // It should be trying to auto-detect first -- succeed the download. 1800 EXPECT_TRUE(fetcher->has_pending_request()); 1801 EXPECT_EQ(GURL("http://wpad/wpad.dat"), fetcher->pending_request_url()); 1802 fetcher->NotifyFetchCompletion(OK, "invalid-script-contents"); 1803 1804 // The script contents passed failed basic verification step (since didn't 1805 // contain token FindProxyForURL), so it was never passed to the resolver. 1806 1807 // Next it should be trying the custom PAC url. 1808 EXPECT_TRUE(fetcher->has_pending_request()); 1809 EXPECT_EQ(GURL("http://foopy/proxy.pac"), fetcher->pending_request_url()); 1810 fetcher->NotifyFetchCompletion(OK, kValidPacScript1); 1811 1812 EXPECT_EQ(ASCIIToUTF16(kValidPacScript1), 1813 resolver->pending_set_pac_script_request()->script_data()->utf16()); 1814 resolver->pending_set_pac_script_request()->CompleteNow(OK); 1815 1816 // Now finally, the pending requests should have been sent to the resolver 1817 // (which was initialized with custom PAC script). 1818 1819 ASSERT_EQ(2u, resolver->pending_requests().size()); 1820 EXPECT_EQ(GURL("http://request1"), resolver->pending_requests()[0]->url()); 1821 EXPECT_EQ(GURL("http://request2"), resolver->pending_requests()[1]->url()); 1822 1823 // Complete the pending requests. 1824 resolver->pending_requests()[1]->results()->UseNamedProxy("request2:80"); 1825 resolver->pending_requests()[1]->CompleteNow(OK); 1826 resolver->pending_requests()[0]->results()->UseNamedProxy("request1:80"); 1827 resolver->pending_requests()[0]->CompleteNow(OK); 1828 1829 // Verify that requests ran as expected. 1830 EXPECT_EQ(OK, callback1.WaitForResult()); 1831 EXPECT_EQ("request1:80", info1.proxy_server().ToURI()); 1832 1833 EXPECT_EQ(OK, callback2.WaitForResult()); 1834 EXPECT_EQ("request2:80", info2.proxy_server().ToURI()); 1835} 1836 1837// Test that if all of auto-detect, a custom PAC script, and manual settings 1838// are given, then we will try them in that order. 1839TEST_F(ProxyServiceTest, FallbackFromAutodetectToCustomToManual) { 1840 ProxyConfig config; 1841 config.set_auto_detect(true); 1842 config.set_pac_url(GURL("http://foopy/proxy.pac")); 1843 config.proxy_rules().ParseFromString("http=foopy:80"); 1844 1845 MockProxyConfigService* config_service = new MockProxyConfigService(config); 1846 MockAsyncProxyResolverExpectsBytes* resolver = 1847 new MockAsyncProxyResolverExpectsBytes; 1848 ProxyService service(config_service, resolver, NULL); 1849 1850 MockProxyScriptFetcher* fetcher = new MockProxyScriptFetcher; 1851 service.SetProxyScriptFetchers(fetcher, 1852 new DoNothingDhcpProxyScriptFetcher()); 1853 1854 // Start 2 requests. 1855 1856 ProxyInfo info1; 1857 TestCompletionCallback callback1; 1858 int rv = service.ResolveProxy(GURL("http://request1"), &info1, 1859 callback1.callback(), NULL, BoundNetLog()); 1860 EXPECT_EQ(ERR_IO_PENDING, rv); 1861 1862 ProxyInfo info2; 1863 TestCompletionCallback callback2; 1864 ProxyService::PacRequest* request2; 1865 rv = service.ResolveProxy(GURL("http://request2"), &info2, 1866 callback2.callback(), &request2, BoundNetLog()); 1867 EXPECT_EQ(ERR_IO_PENDING, rv); 1868 1869 // Check that nothing has been sent to the proxy resolver yet. 1870 ASSERT_EQ(0u, resolver->pending_requests().size()); 1871 1872 // It should be trying to auto-detect first -- fail the download. 1873 EXPECT_TRUE(fetcher->has_pending_request()); 1874 EXPECT_EQ(GURL("http://wpad/wpad.dat"), fetcher->pending_request_url()); 1875 fetcher->NotifyFetchCompletion(ERR_FAILED, std::string()); 1876 1877 // Next it should be trying the custom PAC url -- fail the download. 1878 EXPECT_TRUE(fetcher->has_pending_request()); 1879 EXPECT_EQ(GURL("http://foopy/proxy.pac"), fetcher->pending_request_url()); 1880 fetcher->NotifyFetchCompletion(ERR_FAILED, std::string()); 1881 1882 // Since we never managed to initialize a ProxyResolver, nothing should have 1883 // been sent to it. 1884 ASSERT_EQ(0u, resolver->pending_requests().size()); 1885 1886 // Verify that requests ran as expected -- they should have fallen back to 1887 // the manual proxy configuration for HTTP urls. 1888 EXPECT_EQ(OK, callback1.WaitForResult()); 1889 EXPECT_EQ("foopy:80", info1.proxy_server().ToURI()); 1890 1891 EXPECT_EQ(OK, callback2.WaitForResult()); 1892 EXPECT_EQ("foopy:80", info2.proxy_server().ToURI()); 1893} 1894 1895// Test that the bypass rules are NOT applied when using autodetect. 1896TEST_F(ProxyServiceTest, BypassDoesntApplyToPac) { 1897 ProxyConfig config; 1898 config.set_auto_detect(true); 1899 config.set_pac_url(GURL("http://foopy/proxy.pac")); 1900 config.proxy_rules().ParseFromString("http=foopy:80"); // Not used. 1901 config.proxy_rules().bypass_rules.ParseFromString("www.google.com"); 1902 1903 MockProxyConfigService* config_service = new MockProxyConfigService(config); 1904 MockAsyncProxyResolverExpectsBytes* resolver = 1905 new MockAsyncProxyResolverExpectsBytes; 1906 ProxyService service(config_service, resolver, NULL); 1907 1908 MockProxyScriptFetcher* fetcher = new MockProxyScriptFetcher; 1909 service.SetProxyScriptFetchers(fetcher, 1910 new DoNothingDhcpProxyScriptFetcher()); 1911 1912 // Start 1 requests. 1913 1914 ProxyInfo info1; 1915 TestCompletionCallback callback1; 1916 int rv = service.ResolveProxy( 1917 GURL("http://www.google.com"), &info1, callback1.callback(), NULL, 1918 BoundNetLog()); 1919 EXPECT_EQ(ERR_IO_PENDING, rv); 1920 1921 // Check that nothing has been sent to the proxy resolver yet. 1922 ASSERT_EQ(0u, resolver->pending_requests().size()); 1923 1924 // It should be trying to auto-detect first -- succeed the download. 1925 EXPECT_TRUE(fetcher->has_pending_request()); 1926 EXPECT_EQ(GURL("http://wpad/wpad.dat"), fetcher->pending_request_url()); 1927 fetcher->NotifyFetchCompletion(OK, kValidPacScript1); 1928 1929 EXPECT_EQ(ASCIIToUTF16(kValidPacScript1), 1930 resolver->pending_set_pac_script_request()->script_data()->utf16()); 1931 resolver->pending_set_pac_script_request()->CompleteNow(OK); 1932 1933 ASSERT_EQ(1u, resolver->pending_requests().size()); 1934 EXPECT_EQ(GURL("http://www.google.com"), 1935 resolver->pending_requests()[0]->url()); 1936 1937 // Complete the pending request. 1938 resolver->pending_requests()[0]->results()->UseNamedProxy("request1:80"); 1939 resolver->pending_requests()[0]->CompleteNow(OK); 1940 1941 // Verify that request ran as expected. 1942 EXPECT_EQ(OK, callback1.WaitForResult()); 1943 EXPECT_EQ("request1:80", info1.proxy_server().ToURI()); 1944 1945 // Start another request, it should pickup the bypass item. 1946 ProxyInfo info2; 1947 TestCompletionCallback callback2; 1948 rv = service.ResolveProxy(GURL("http://www.google.com"), &info2, 1949 callback2.callback(), NULL, BoundNetLog()); 1950 EXPECT_EQ(ERR_IO_PENDING, rv); 1951 1952 ASSERT_EQ(1u, resolver->pending_requests().size()); 1953 EXPECT_EQ(GURL("http://www.google.com"), 1954 resolver->pending_requests()[0]->url()); 1955 1956 // Complete the pending request. 1957 resolver->pending_requests()[0]->results()->UseNamedProxy("request2:80"); 1958 resolver->pending_requests()[0]->CompleteNow(OK); 1959 1960 EXPECT_EQ(OK, callback2.WaitForResult()); 1961 EXPECT_EQ("request2:80", info2.proxy_server().ToURI()); 1962} 1963 1964// Delete the ProxyService while InitProxyResolver has an outstanding 1965// request to the script fetcher. When run under valgrind, should not 1966// have any memory errors (used to be that the ProxyScriptFetcher was 1967// being deleted prior to the InitProxyResolver). 1968TEST_F(ProxyServiceTest, DeleteWhileInitProxyResolverHasOutstandingFetch) { 1969 ProxyConfig config = 1970 ProxyConfig::CreateFromCustomPacURL(GURL("http://foopy/proxy.pac")); 1971 1972 MockProxyConfigService* config_service = new MockProxyConfigService(config); 1973 MockAsyncProxyResolverExpectsBytes* resolver = 1974 new MockAsyncProxyResolverExpectsBytes; 1975 ProxyService service(config_service, resolver, NULL); 1976 1977 MockProxyScriptFetcher* fetcher = new MockProxyScriptFetcher; 1978 service.SetProxyScriptFetchers(fetcher, 1979 new DoNothingDhcpProxyScriptFetcher()); 1980 1981 // Start 1 request. 1982 1983 ProxyInfo info1; 1984 TestCompletionCallback callback1; 1985 int rv = service.ResolveProxy(GURL("http://www.google.com"), &info1, 1986 callback1.callback(), NULL, BoundNetLog()); 1987 EXPECT_EQ(ERR_IO_PENDING, rv); 1988 1989 // Check that nothing has been sent to the proxy resolver yet. 1990 ASSERT_EQ(0u, resolver->pending_requests().size()); 1991 1992 // InitProxyResolver should have issued a request to the ProxyScriptFetcher 1993 // and be waiting on that to complete. 1994 EXPECT_TRUE(fetcher->has_pending_request()); 1995 EXPECT_EQ(GURL("http://foopy/proxy.pac"), fetcher->pending_request_url()); 1996} 1997 1998// Delete the ProxyService while InitProxyResolver has an outstanding 1999// request to the proxy resolver. When run under valgrind, should not 2000// have any memory errors (used to be that the ProxyResolver was 2001// being deleted prior to the InitProxyResolver). 2002TEST_F(ProxyServiceTest, DeleteWhileInitProxyResolverHasOutstandingSet) { 2003 MockProxyConfigService* config_service = 2004 new MockProxyConfigService("http://foopy/proxy.pac"); 2005 2006 MockAsyncProxyResolver* resolver = new MockAsyncProxyResolver; 2007 2008 ProxyService service(config_service, resolver, NULL); 2009 2010 GURL url("http://www.google.com/"); 2011 2012 ProxyInfo info; 2013 TestCompletionCallback callback; 2014 int rv = service.ResolveProxy( 2015 url, &info, callback.callback(), NULL, BoundNetLog()); 2016 EXPECT_EQ(ERR_IO_PENDING, rv); 2017 2018 EXPECT_EQ(GURL("http://foopy/proxy.pac"), 2019 resolver->pending_set_pac_script_request()->script_data()->url()); 2020} 2021 2022TEST_F(ProxyServiceTest, ResetProxyConfigService) { 2023 ProxyConfig config1; 2024 config1.proxy_rules().ParseFromString("foopy1:8080"); 2025 config1.set_auto_detect(false); 2026 ProxyService service( 2027 new MockProxyConfigService(config1), 2028 new MockAsyncProxyResolverExpectsBytes, NULL); 2029 2030 ProxyInfo info; 2031 TestCompletionCallback callback1; 2032 int rv = service.ResolveProxy(GURL("http://request1"), &info, 2033 callback1.callback(), NULL, BoundNetLog()); 2034 EXPECT_EQ(OK, rv); 2035 EXPECT_EQ("foopy1:8080", info.proxy_server().ToURI()); 2036 2037 ProxyConfig config2; 2038 config2.proxy_rules().ParseFromString("foopy2:8080"); 2039 config2.set_auto_detect(false); 2040 service.ResetConfigService(new MockProxyConfigService(config2)); 2041 TestCompletionCallback callback2; 2042 rv = service.ResolveProxy(GURL("http://request2"), &info, 2043 callback2.callback(), NULL, BoundNetLog()); 2044 EXPECT_EQ(OK, rv); 2045 EXPECT_EQ("foopy2:8080", info.proxy_server().ToURI()); 2046} 2047 2048// Test that when going from a configuration that required PAC to one 2049// that does NOT, we unset the variable |should_use_proxy_resolver_|. 2050TEST_F(ProxyServiceTest, UpdateConfigFromPACToDirect) { 2051 ProxyConfig config = ProxyConfig::CreateAutoDetect(); 2052 2053 MockProxyConfigService* config_service = new MockProxyConfigService(config); 2054 MockAsyncProxyResolver* resolver = new MockAsyncProxyResolver; 2055 ProxyService service(config_service, resolver, NULL); 2056 2057 // Start 1 request. 2058 2059 ProxyInfo info1; 2060 TestCompletionCallback callback1; 2061 int rv = service.ResolveProxy(GURL("http://www.google.com"), &info1, 2062 callback1.callback(), NULL, BoundNetLog()); 2063 EXPECT_EQ(ERR_IO_PENDING, rv); 2064 2065 // Check that nothing has been sent to the proxy resolver yet. 2066 ASSERT_EQ(0u, resolver->pending_requests().size()); 2067 2068 // Successfully set the autodetect script. 2069 EXPECT_EQ(ProxyResolverScriptData::TYPE_AUTO_DETECT, 2070 resolver->pending_set_pac_script_request()->script_data()->type()); 2071 resolver->pending_set_pac_script_request()->CompleteNow(OK); 2072 2073 // Complete the pending request. 2074 ASSERT_EQ(1u, resolver->pending_requests().size()); 2075 resolver->pending_requests()[0]->results()->UseNamedProxy("request1:80"); 2076 resolver->pending_requests()[0]->CompleteNow(OK); 2077 2078 // Verify that request ran as expected. 2079 EXPECT_EQ(OK, callback1.WaitForResult()); 2080 EXPECT_EQ("request1:80", info1.proxy_server().ToURI()); 2081 2082 // Force the ProxyService to pull down a new proxy configuration. 2083 // (Even though the configuration isn't old/bad). 2084 // 2085 // This new configuration no longer has auto_detect set, so 2086 // requests should complete synchronously now as direct-connect. 2087 config_service->SetConfig(ProxyConfig::CreateDirect()); 2088 2089 // Start another request -- the effective configuration has changed. 2090 ProxyInfo info2; 2091 TestCompletionCallback callback2; 2092 rv = service.ResolveProxy(GURL("http://www.google.com"), &info2, 2093 callback2.callback(), NULL, BoundNetLog()); 2094 EXPECT_EQ(OK, rv); 2095 2096 EXPECT_TRUE(info2.is_direct()); 2097} 2098 2099TEST_F(ProxyServiceTest, NetworkChangeTriggersPacRefetch) { 2100 MockProxyConfigService* config_service = 2101 new MockProxyConfigService("http://foopy/proxy.pac"); 2102 2103 MockAsyncProxyResolverExpectsBytes* resolver = 2104 new MockAsyncProxyResolverExpectsBytes; 2105 2106 CapturingNetLog log; 2107 2108 ProxyService service(config_service, resolver, &log); 2109 2110 MockProxyScriptFetcher* fetcher = new MockProxyScriptFetcher; 2111 service.SetProxyScriptFetchers(fetcher, 2112 new DoNothingDhcpProxyScriptFetcher()); 2113 2114 // Disable the "wait after IP address changes" hack, so this unit-test can 2115 // complete quickly. 2116 service.set_stall_proxy_auto_config_delay(base::TimeDelta()); 2117 2118 // Start 1 request. 2119 2120 ProxyInfo info1; 2121 TestCompletionCallback callback1; 2122 int rv = service.ResolveProxy(GURL("http://request1"), &info1, 2123 callback1.callback(), NULL, BoundNetLog()); 2124 EXPECT_EQ(ERR_IO_PENDING, rv); 2125 2126 // The first request should have triggered initial download of PAC script. 2127 EXPECT_TRUE(fetcher->has_pending_request()); 2128 EXPECT_EQ(GURL("http://foopy/proxy.pac"), fetcher->pending_request_url()); 2129 2130 // Nothing has been sent to the resolver yet. 2131 EXPECT_TRUE(resolver->pending_requests().empty()); 2132 2133 // At this point the ProxyService should be waiting for the 2134 // ProxyScriptFetcher to invoke its completion callback, notifying it of 2135 // PAC script download completion. 2136 fetcher->NotifyFetchCompletion(OK, kValidPacScript1); 2137 2138 // Now that the PAC script is downloaded, the request will have been sent to 2139 // the proxy resolver. 2140 EXPECT_EQ(ASCIIToUTF16(kValidPacScript1), 2141 resolver->pending_set_pac_script_request()->script_data()->utf16()); 2142 resolver->pending_set_pac_script_request()->CompleteNow(OK); 2143 2144 ASSERT_EQ(1u, resolver->pending_requests().size()); 2145 EXPECT_EQ(GURL("http://request1"), resolver->pending_requests()[0]->url()); 2146 2147 // Complete the pending request. 2148 resolver->pending_requests()[0]->results()->UseNamedProxy("request1:80"); 2149 resolver->pending_requests()[0]->CompleteNow(OK); 2150 2151 // Wait for completion callback, and verify that the request ran as expected. 2152 EXPECT_EQ(OK, callback1.WaitForResult()); 2153 EXPECT_EQ("request1:80", info1.proxy_server().ToURI()); 2154 2155 // Now simluate a change in the network. The ProxyConfigService is still 2156 // going to return the same PAC URL as before, but this URL needs to be 2157 // refetched on the new network. 2158 NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests(); 2159 base::MessageLoop::current()->RunUntilIdle(); // Notification happens async. 2160 2161 // Start a second request. 2162 ProxyInfo info2; 2163 TestCompletionCallback callback2; 2164 rv = service.ResolveProxy(GURL("http://request2"), &info2, 2165 callback2.callback(), NULL, BoundNetLog()); 2166 EXPECT_EQ(ERR_IO_PENDING, rv); 2167 2168 // This second request should have triggered the re-download of the PAC 2169 // script (since we marked the network as having changed). 2170 EXPECT_TRUE(fetcher->has_pending_request()); 2171 EXPECT_EQ(GURL("http://foopy/proxy.pac"), fetcher->pending_request_url()); 2172 2173 // Nothing has been sent to the resolver yet. 2174 EXPECT_TRUE(resolver->pending_requests().empty()); 2175 2176 // Simulate the PAC script fetch as having completed (this time with 2177 // different data). 2178 fetcher->NotifyFetchCompletion(OK, kValidPacScript2); 2179 2180 // Now that the PAC script is downloaded, the second request will have been 2181 // sent to the proxy resolver. 2182 EXPECT_EQ(ASCIIToUTF16(kValidPacScript2), 2183 resolver->pending_set_pac_script_request()->script_data()->utf16()); 2184 resolver->pending_set_pac_script_request()->CompleteNow(OK); 2185 2186 ASSERT_EQ(1u, resolver->pending_requests().size()); 2187 EXPECT_EQ(GURL("http://request2"), resolver->pending_requests()[0]->url()); 2188 2189 // Complete the pending second request. 2190 resolver->pending_requests()[0]->results()->UseNamedProxy("request2:80"); 2191 resolver->pending_requests()[0]->CompleteNow(OK); 2192 2193 // Wait for completion callback, and verify that the request ran as expected. 2194 EXPECT_EQ(OK, callback2.WaitForResult()); 2195 EXPECT_EQ("request2:80", info2.proxy_server().ToURI()); 2196 2197 // Check that the expected events were output to the log stream. In particular 2198 // PROXY_CONFIG_CHANGED should have only been emitted once (for the initial 2199 // setup), and NOT a second time when the IP address changed. 2200 CapturingNetLog::CapturedEntryList entries; 2201 log.GetEntries(&entries); 2202 2203 EXPECT_TRUE(LogContainsEntryWithType(entries, 0, 2204 NetLog::TYPE_PROXY_CONFIG_CHANGED)); 2205 ASSERT_EQ(9u, entries.size()); 2206 for (size_t i = 1; i < entries.size(); ++i) 2207 EXPECT_NE(NetLog::TYPE_PROXY_CONFIG_CHANGED, entries[i].type); 2208} 2209 2210// This test verifies that the PAC script specified by the settings is 2211// periodically polled for changes. Specifically, if the initial fetch fails due 2212// to a network error, we will eventually re-configure the service to use the 2213// script once it becomes available. 2214TEST_F(ProxyServiceTest, PACScriptRefetchAfterFailure) { 2215 // Change the retry policy to wait a mere 1 ms before retrying, so the test 2216 // runs quickly. 2217 ImmediatePollPolicy poll_policy; 2218 ProxyService::set_pac_script_poll_policy(&poll_policy); 2219 2220 MockProxyConfigService* config_service = 2221 new MockProxyConfigService("http://foopy/proxy.pac"); 2222 2223 MockAsyncProxyResolverExpectsBytes* resolver = 2224 new MockAsyncProxyResolverExpectsBytes; 2225 2226 ProxyService service(config_service, resolver, NULL); 2227 2228 MockProxyScriptFetcher* fetcher = new MockProxyScriptFetcher; 2229 service.SetProxyScriptFetchers(fetcher, 2230 new DoNothingDhcpProxyScriptFetcher()); 2231 2232 // Start 1 request. 2233 2234 ProxyInfo info1; 2235 TestCompletionCallback callback1; 2236 int rv = service.ResolveProxy( 2237 GURL("http://request1"), &info1, callback1.callback(), 2238 NULL, BoundNetLog()); 2239 EXPECT_EQ(ERR_IO_PENDING, rv); 2240 2241 // The first request should have triggered initial download of PAC script. 2242 EXPECT_TRUE(fetcher->has_pending_request()); 2243 EXPECT_EQ(GURL("http://foopy/proxy.pac"), fetcher->pending_request_url()); 2244 2245 // Nothing has been sent to the resolver yet. 2246 EXPECT_TRUE(resolver->pending_requests().empty()); 2247 2248 // At this point the ProxyService should be waiting for the 2249 // ProxyScriptFetcher to invoke its completion callback, notifying it of 2250 // PAC script download completion. 2251 // 2252 // We simulate a failed download attempt, the proxy service should now 2253 // fall-back to DIRECT connections. 2254 fetcher->NotifyFetchCompletion(ERR_FAILED, std::string()); 2255 2256 ASSERT_TRUE(resolver->pending_requests().empty()); 2257 2258 // Wait for completion callback, and verify it used DIRECT. 2259 EXPECT_EQ(OK, callback1.WaitForResult()); 2260 EXPECT_TRUE(info1.is_direct()); 2261 2262 // At this point we have initialized the proxy service using a PAC script, 2263 // however it failed and fell-back to DIRECT. 2264 // 2265 // A background task to periodically re-check the PAC script for validity will 2266 // have been started. We will now wait for the next download attempt to start. 2267 // 2268 // Note that we shouldn't have to wait long here, since our test enables a 2269 // special unit-test mode. 2270 fetcher->WaitUntilFetch(); 2271 2272 ASSERT_TRUE(resolver->pending_requests().empty()); 2273 2274 // Make sure that our background checker is trying to download the expected 2275 // PAC script (same one as before). This time we will simulate a successful 2276 // download of the script. 2277 EXPECT_TRUE(fetcher->has_pending_request()); 2278 EXPECT_EQ(GURL("http://foopy/proxy.pac"), fetcher->pending_request_url()); 2279 fetcher->NotifyFetchCompletion(OK, kValidPacScript1); 2280 2281 base::MessageLoop::current()->RunUntilIdle(); 2282 2283 // Now that the PAC script is downloaded, it should be used to initialize the 2284 // ProxyResolver. Simulate a successful parse. 2285 EXPECT_EQ(ASCIIToUTF16(kValidPacScript1), 2286 resolver->pending_set_pac_script_request()->script_data()->utf16()); 2287 resolver->pending_set_pac_script_request()->CompleteNow(OK); 2288 2289 // At this point the ProxyService should have re-configured itself to use the 2290 // PAC script (thereby recovering from the initial fetch failure). We will 2291 // verify that the next Resolve request uses the resolver rather than 2292 // DIRECT. 2293 2294 // Start a second request. 2295 ProxyInfo info2; 2296 TestCompletionCallback callback2; 2297 rv = service.ResolveProxy( 2298 GURL("http://request2"), &info2, callback2.callback(), NULL, 2299 BoundNetLog()); 2300 EXPECT_EQ(ERR_IO_PENDING, rv); 2301 2302 // Check that it was sent to the resolver. 2303 ASSERT_EQ(1u, resolver->pending_requests().size()); 2304 EXPECT_EQ(GURL("http://request2"), resolver->pending_requests()[0]->url()); 2305 2306 // Complete the pending second request. 2307 resolver->pending_requests()[0]->results()->UseNamedProxy("request2:80"); 2308 resolver->pending_requests()[0]->CompleteNow(OK); 2309 2310 // Wait for completion callback, and verify that the request ran as expected. 2311 EXPECT_EQ(OK, callback2.WaitForResult()); 2312 EXPECT_EQ("request2:80", info2.proxy_server().ToURI()); 2313} 2314 2315// This test verifies that the PAC script specified by the settings is 2316// periodically polled for changes. Specifically, if the initial fetch succeeds, 2317// however at a later time its *contents* change, we will eventually 2318// re-configure the service to use the new script. 2319TEST_F(ProxyServiceTest, PACScriptRefetchAfterContentChange) { 2320 // Change the retry policy to wait a mere 1 ms before retrying, so the test 2321 // runs quickly. 2322 ImmediatePollPolicy poll_policy; 2323 ProxyService::set_pac_script_poll_policy(&poll_policy); 2324 2325 MockProxyConfigService* config_service = 2326 new MockProxyConfigService("http://foopy/proxy.pac"); 2327 2328 MockAsyncProxyResolverExpectsBytes* resolver = 2329 new MockAsyncProxyResolverExpectsBytes; 2330 2331 ProxyService service(config_service, resolver, NULL); 2332 2333 MockProxyScriptFetcher* fetcher = new MockProxyScriptFetcher; 2334 service.SetProxyScriptFetchers(fetcher, 2335 new DoNothingDhcpProxyScriptFetcher()); 2336 2337 // Start 1 request. 2338 2339 ProxyInfo info1; 2340 TestCompletionCallback callback1; 2341 int rv = service.ResolveProxy( 2342 GURL("http://request1"), &info1, callback1.callback(), NULL, 2343 BoundNetLog()); 2344 EXPECT_EQ(ERR_IO_PENDING, rv); 2345 2346 // The first request should have triggered initial download of PAC script. 2347 EXPECT_TRUE(fetcher->has_pending_request()); 2348 EXPECT_EQ(GURL("http://foopy/proxy.pac"), fetcher->pending_request_url()); 2349 2350 // Nothing has been sent to the resolver yet. 2351 EXPECT_TRUE(resolver->pending_requests().empty()); 2352 2353 // At this point the ProxyService should be waiting for the 2354 // ProxyScriptFetcher to invoke its completion callback, notifying it of 2355 // PAC script download completion. 2356 fetcher->NotifyFetchCompletion(OK, kValidPacScript1); 2357 2358 // Now that the PAC script is downloaded, the request will have been sent to 2359 // the proxy resolver. 2360 EXPECT_EQ(ASCIIToUTF16(kValidPacScript1), 2361 resolver->pending_set_pac_script_request()->script_data()->utf16()); 2362 resolver->pending_set_pac_script_request()->CompleteNow(OK); 2363 2364 ASSERT_EQ(1u, resolver->pending_requests().size()); 2365 EXPECT_EQ(GURL("http://request1"), resolver->pending_requests()[0]->url()); 2366 2367 // Complete the pending request. 2368 resolver->pending_requests()[0]->results()->UseNamedProxy("request1:80"); 2369 resolver->pending_requests()[0]->CompleteNow(OK); 2370 2371 // Wait for completion callback, and verify that the request ran as expected. 2372 EXPECT_EQ(OK, callback1.WaitForResult()); 2373 EXPECT_EQ("request1:80", info1.proxy_server().ToURI()); 2374 2375 // At this point we have initialized the proxy service using a PAC script. 2376 // 2377 // A background task to periodically re-check the PAC script for validity will 2378 // have been started. We will now wait for the next download attempt to start. 2379 // 2380 // Note that we shouldn't have to wait long here, since our test enables a 2381 // special unit-test mode. 2382 fetcher->WaitUntilFetch(); 2383 2384 ASSERT_TRUE(resolver->pending_requests().empty()); 2385 2386 // Make sure that our background checker is trying to download the expected 2387 // PAC script (same one as before). This time we will simulate a successful 2388 // download of a DIFFERENT script. 2389 EXPECT_TRUE(fetcher->has_pending_request()); 2390 EXPECT_EQ(GURL("http://foopy/proxy.pac"), fetcher->pending_request_url()); 2391 fetcher->NotifyFetchCompletion(OK, kValidPacScript2); 2392 2393 base::MessageLoop::current()->RunUntilIdle(); 2394 2395 // Now that the PAC script is downloaded, it should be used to initialize the 2396 // ProxyResolver. Simulate a successful parse. 2397 EXPECT_EQ(ASCIIToUTF16(kValidPacScript2), 2398 resolver->pending_set_pac_script_request()->script_data()->utf16()); 2399 resolver->pending_set_pac_script_request()->CompleteNow(OK); 2400 2401 // At this point the ProxyService should have re-configured itself to use the 2402 // new PAC script. 2403 2404 // Start a second request. 2405 ProxyInfo info2; 2406 TestCompletionCallback callback2; 2407 rv = service.ResolveProxy( 2408 GURL("http://request2"), &info2, callback2.callback(), NULL, 2409 BoundNetLog()); 2410 EXPECT_EQ(ERR_IO_PENDING, rv); 2411 2412 // Check that it was sent to the resolver. 2413 ASSERT_EQ(1u, resolver->pending_requests().size()); 2414 EXPECT_EQ(GURL("http://request2"), resolver->pending_requests()[0]->url()); 2415 2416 // Complete the pending second request. 2417 resolver->pending_requests()[0]->results()->UseNamedProxy("request2:80"); 2418 resolver->pending_requests()[0]->CompleteNow(OK); 2419 2420 // Wait for completion callback, and verify that the request ran as expected. 2421 EXPECT_EQ(OK, callback2.WaitForResult()); 2422 EXPECT_EQ("request2:80", info2.proxy_server().ToURI()); 2423} 2424 2425// This test verifies that the PAC script specified by the settings is 2426// periodically polled for changes. Specifically, if the initial fetch succeeds 2427// and so does the next poll, however the contents of the downloaded script 2428// have NOT changed, then we do not bother to re-initialize the proxy resolver. 2429TEST_F(ProxyServiceTest, PACScriptRefetchAfterContentUnchanged) { 2430 // Change the retry policy to wait a mere 1 ms before retrying, so the test 2431 // runs quickly. 2432 ImmediatePollPolicy poll_policy; 2433 ProxyService::set_pac_script_poll_policy(&poll_policy); 2434 2435 MockProxyConfigService* config_service = 2436 new MockProxyConfigService("http://foopy/proxy.pac"); 2437 2438 MockAsyncProxyResolverExpectsBytes* resolver = 2439 new MockAsyncProxyResolverExpectsBytes; 2440 2441 ProxyService service(config_service, resolver, NULL); 2442 2443 MockProxyScriptFetcher* fetcher = new MockProxyScriptFetcher; 2444 service.SetProxyScriptFetchers(fetcher, 2445 new DoNothingDhcpProxyScriptFetcher()); 2446 2447 // Start 1 request. 2448 2449 ProxyInfo info1; 2450 TestCompletionCallback callback1; 2451 int rv = service.ResolveProxy( 2452 GURL("http://request1"), &info1, callback1.callback(), NULL, 2453 BoundNetLog()); 2454 EXPECT_EQ(ERR_IO_PENDING, rv); 2455 2456 // The first request should have triggered initial download of PAC script. 2457 EXPECT_TRUE(fetcher->has_pending_request()); 2458 EXPECT_EQ(GURL("http://foopy/proxy.pac"), fetcher->pending_request_url()); 2459 2460 // Nothing has been sent to the resolver yet. 2461 EXPECT_TRUE(resolver->pending_requests().empty()); 2462 2463 // At this point the ProxyService should be waiting for the 2464 // ProxyScriptFetcher to invoke its completion callback, notifying it of 2465 // PAC script download completion. 2466 fetcher->NotifyFetchCompletion(OK, kValidPacScript1); 2467 2468 // Now that the PAC script is downloaded, the request will have been sent to 2469 // the proxy resolver. 2470 EXPECT_EQ(ASCIIToUTF16(kValidPacScript1), 2471 resolver->pending_set_pac_script_request()->script_data()->utf16()); 2472 resolver->pending_set_pac_script_request()->CompleteNow(OK); 2473 2474 ASSERT_EQ(1u, resolver->pending_requests().size()); 2475 EXPECT_EQ(GURL("http://request1"), resolver->pending_requests()[0]->url()); 2476 2477 // Complete the pending request. 2478 resolver->pending_requests()[0]->results()->UseNamedProxy("request1:80"); 2479 resolver->pending_requests()[0]->CompleteNow(OK); 2480 2481 // Wait for completion callback, and verify that the request ran as expected. 2482 EXPECT_EQ(OK, callback1.WaitForResult()); 2483 EXPECT_EQ("request1:80", info1.proxy_server().ToURI()); 2484 2485 // At this point we have initialized the proxy service using a PAC script. 2486 // 2487 // A background task to periodically re-check the PAC script for validity will 2488 // have been started. We will now wait for the next download attempt to start. 2489 // 2490 // Note that we shouldn't have to wait long here, since our test enables a 2491 // special unit-test mode. 2492 fetcher->WaitUntilFetch(); 2493 2494 ASSERT_TRUE(resolver->pending_requests().empty()); 2495 2496 // Make sure that our background checker is trying to download the expected 2497 // PAC script (same one as before). We will simulate the same response as 2498 // last time (i.e. the script is unchanged). 2499 EXPECT_TRUE(fetcher->has_pending_request()); 2500 EXPECT_EQ(GURL("http://foopy/proxy.pac"), fetcher->pending_request_url()); 2501 fetcher->NotifyFetchCompletion(OK, kValidPacScript1); 2502 2503 base::MessageLoop::current()->RunUntilIdle(); 2504 2505 ASSERT_FALSE(resolver->has_pending_set_pac_script_request()); 2506 2507 // At this point the ProxyService is still running the same PAC script as 2508 // before. 2509 2510 // Start a second request. 2511 ProxyInfo info2; 2512 TestCompletionCallback callback2; 2513 rv = service.ResolveProxy( 2514 GURL("http://request2"), &info2, callback2.callback(), NULL, 2515 BoundNetLog()); 2516 EXPECT_EQ(ERR_IO_PENDING, rv); 2517 2518 // Check that it was sent to the resolver. 2519 ASSERT_EQ(1u, resolver->pending_requests().size()); 2520 EXPECT_EQ(GURL("http://request2"), resolver->pending_requests()[0]->url()); 2521 2522 // Complete the pending second request. 2523 resolver->pending_requests()[0]->results()->UseNamedProxy("request2:80"); 2524 resolver->pending_requests()[0]->CompleteNow(OK); 2525 2526 // Wait for completion callback, and verify that the request ran as expected. 2527 EXPECT_EQ(OK, callback2.WaitForResult()); 2528 EXPECT_EQ("request2:80", info2.proxy_server().ToURI()); 2529} 2530 2531// This test verifies that the PAC script specified by the settings is 2532// periodically polled for changes. Specifically, if the initial fetch succeeds, 2533// however at a later time it starts to fail, we should re-configure the 2534// ProxyService to stop using that PAC script. 2535TEST_F(ProxyServiceTest, PACScriptRefetchAfterSuccess) { 2536 // Change the retry policy to wait a mere 1 ms before retrying, so the test 2537 // runs quickly. 2538 ImmediatePollPolicy poll_policy; 2539 ProxyService::set_pac_script_poll_policy(&poll_policy); 2540 2541 MockProxyConfigService* config_service = 2542 new MockProxyConfigService("http://foopy/proxy.pac"); 2543 2544 MockAsyncProxyResolverExpectsBytes* resolver = 2545 new MockAsyncProxyResolverExpectsBytes; 2546 2547 ProxyService service(config_service, resolver, NULL); 2548 2549 MockProxyScriptFetcher* fetcher = new MockProxyScriptFetcher; 2550 service.SetProxyScriptFetchers(fetcher, 2551 new DoNothingDhcpProxyScriptFetcher()); 2552 2553 // Start 1 request. 2554 2555 ProxyInfo info1; 2556 TestCompletionCallback callback1; 2557 int rv = service.ResolveProxy( 2558 GURL("http://request1"), &info1, callback1.callback(), NULL, 2559 BoundNetLog()); 2560 EXPECT_EQ(ERR_IO_PENDING, rv); 2561 2562 // The first request should have triggered initial download of PAC script. 2563 EXPECT_TRUE(fetcher->has_pending_request()); 2564 EXPECT_EQ(GURL("http://foopy/proxy.pac"), fetcher->pending_request_url()); 2565 2566 // Nothing has been sent to the resolver yet. 2567 EXPECT_TRUE(resolver->pending_requests().empty()); 2568 2569 // At this point the ProxyService should be waiting for the 2570 // ProxyScriptFetcher to invoke its completion callback, notifying it of 2571 // PAC script download completion. 2572 fetcher->NotifyFetchCompletion(OK, kValidPacScript1); 2573 2574 // Now that the PAC script is downloaded, the request will have been sent to 2575 // the proxy resolver. 2576 EXPECT_EQ(ASCIIToUTF16(kValidPacScript1), 2577 resolver->pending_set_pac_script_request()->script_data()->utf16()); 2578 resolver->pending_set_pac_script_request()->CompleteNow(OK); 2579 2580 ASSERT_EQ(1u, resolver->pending_requests().size()); 2581 EXPECT_EQ(GURL("http://request1"), resolver->pending_requests()[0]->url()); 2582 2583 // Complete the pending request. 2584 resolver->pending_requests()[0]->results()->UseNamedProxy("request1:80"); 2585 resolver->pending_requests()[0]->CompleteNow(OK); 2586 2587 // Wait for completion callback, and verify that the request ran as expected. 2588 EXPECT_EQ(OK, callback1.WaitForResult()); 2589 EXPECT_EQ("request1:80", info1.proxy_server().ToURI()); 2590 2591 // At this point we have initialized the proxy service using a PAC script. 2592 // 2593 // A background task to periodically re-check the PAC script for validity will 2594 // have been started. We will now wait for the next download attempt to start. 2595 // 2596 // Note that we shouldn't have to wait long here, since our test enables a 2597 // special unit-test mode. 2598 fetcher->WaitUntilFetch(); 2599 2600 ASSERT_TRUE(resolver->pending_requests().empty()); 2601 2602 // Make sure that our background checker is trying to download the expected 2603 // PAC script (same one as before). This time we will simulate a failure 2604 // to download the script. 2605 EXPECT_TRUE(fetcher->has_pending_request()); 2606 EXPECT_EQ(GURL("http://foopy/proxy.pac"), fetcher->pending_request_url()); 2607 fetcher->NotifyFetchCompletion(ERR_FAILED, std::string()); 2608 2609 base::MessageLoop::current()->RunUntilIdle(); 2610 2611 // At this point the ProxyService should have re-configured itself to use 2612 // DIRECT connections rather than the given proxy resolver. 2613 2614 // Start a second request. 2615 ProxyInfo info2; 2616 TestCompletionCallback callback2; 2617 rv = service.ResolveProxy( 2618 GURL("http://request2"), &info2, callback2.callback(), NULL, 2619 BoundNetLog()); 2620 EXPECT_EQ(OK, rv); 2621 EXPECT_TRUE(info2.is_direct()); 2622} 2623 2624// Tests that the code which decides at what times to poll the PAC 2625// script follows the expected policy. 2626TEST_F(ProxyServiceTest, PACScriptPollingPolicy) { 2627 // Retrieve the internal polling policy implementation used by ProxyService. 2628 scoped_ptr<ProxyService::PacPollPolicy> policy = 2629 ProxyService::CreateDefaultPacPollPolicy(); 2630 2631 int error; 2632 ProxyService::PacPollPolicy::Mode mode; 2633 const base::TimeDelta initial_delay = base::TimeDelta::FromMilliseconds(-1); 2634 base::TimeDelta delay = initial_delay; 2635 2636 // -------------------------------------------------- 2637 // Test the poll sequence in response to a failure. 2638 // -------------------------------------------------- 2639 error = ERR_NAME_NOT_RESOLVED; 2640 2641 // Poll #0 2642 mode = policy->GetNextDelay(error, initial_delay, &delay); 2643 EXPECT_EQ(8, delay.InSeconds()); 2644 EXPECT_EQ(ProxyService::PacPollPolicy::MODE_USE_TIMER, mode); 2645 2646 // Poll #1 2647 mode = policy->GetNextDelay(error, delay, &delay); 2648 EXPECT_EQ(32, delay.InSeconds()); 2649 EXPECT_EQ(ProxyService::PacPollPolicy::MODE_START_AFTER_ACTIVITY, mode); 2650 2651 // Poll #2 2652 mode = policy->GetNextDelay(error, delay, &delay); 2653 EXPECT_EQ(120, delay.InSeconds()); 2654 EXPECT_EQ(ProxyService::PacPollPolicy::MODE_START_AFTER_ACTIVITY, mode); 2655 2656 // Poll #3 2657 mode = policy->GetNextDelay(error, delay, &delay); 2658 EXPECT_EQ(14400, delay.InSeconds()); 2659 EXPECT_EQ(ProxyService::PacPollPolicy::MODE_START_AFTER_ACTIVITY, mode); 2660 2661 // Poll #4 2662 mode = policy->GetNextDelay(error, delay, &delay); 2663 EXPECT_EQ(14400, delay.InSeconds()); 2664 EXPECT_EQ(ProxyService::PacPollPolicy::MODE_START_AFTER_ACTIVITY, mode); 2665 2666 // -------------------------------------------------- 2667 // Test the poll sequence in response to a success. 2668 // -------------------------------------------------- 2669 error = OK; 2670 2671 // Poll #0 2672 mode = policy->GetNextDelay(error, initial_delay, &delay); 2673 EXPECT_EQ(43200, delay.InSeconds()); 2674 EXPECT_EQ(ProxyService::PacPollPolicy::MODE_START_AFTER_ACTIVITY, mode); 2675 2676 // Poll #1 2677 mode = policy->GetNextDelay(error, delay, &delay); 2678 EXPECT_EQ(43200, delay.InSeconds()); 2679 EXPECT_EQ(ProxyService::PacPollPolicy::MODE_START_AFTER_ACTIVITY, mode); 2680 2681 // Poll #2 2682 mode = policy->GetNextDelay(error, delay, &delay); 2683 EXPECT_EQ(43200, delay.InSeconds()); 2684 EXPECT_EQ(ProxyService::PacPollPolicy::MODE_START_AFTER_ACTIVITY, mode); 2685} 2686 2687// This tests the polling of the PAC script. Specifically, it tests that 2688// polling occurs in response to user activity. 2689TEST_F(ProxyServiceTest, PACScriptRefetchAfterActivity) { 2690 ImmediateAfterActivityPollPolicy poll_policy; 2691 ProxyService::set_pac_script_poll_policy(&poll_policy); 2692 2693 MockProxyConfigService* config_service = 2694 new MockProxyConfigService("http://foopy/proxy.pac"); 2695 2696 MockAsyncProxyResolverExpectsBytes* resolver = 2697 new MockAsyncProxyResolverExpectsBytes; 2698 2699 ProxyService service(config_service, resolver, NULL); 2700 2701 MockProxyScriptFetcher* fetcher = new MockProxyScriptFetcher; 2702 service.SetProxyScriptFetchers(fetcher, 2703 new DoNothingDhcpProxyScriptFetcher()); 2704 2705 // Start 1 request. 2706 2707 ProxyInfo info1; 2708 TestCompletionCallback callback1; 2709 int rv = service.ResolveProxy( 2710 GURL("http://request1"), &info1, callback1.callback(), NULL, 2711 BoundNetLog()); 2712 EXPECT_EQ(ERR_IO_PENDING, rv); 2713 2714 // The first request should have triggered initial download of PAC script. 2715 EXPECT_TRUE(fetcher->has_pending_request()); 2716 EXPECT_EQ(GURL("http://foopy/proxy.pac"), fetcher->pending_request_url()); 2717 2718 // Nothing has been sent to the resolver yet. 2719 EXPECT_TRUE(resolver->pending_requests().empty()); 2720 2721 // At this point the ProxyService should be waiting for the 2722 // ProxyScriptFetcher to invoke its completion callback, notifying it of 2723 // PAC script download completion. 2724 fetcher->NotifyFetchCompletion(OK, kValidPacScript1); 2725 2726 // Now that the PAC script is downloaded, the request will have been sent to 2727 // the proxy resolver. 2728 EXPECT_EQ(ASCIIToUTF16(kValidPacScript1), 2729 resolver->pending_set_pac_script_request()->script_data()->utf16()); 2730 resolver->pending_set_pac_script_request()->CompleteNow(OK); 2731 2732 ASSERT_EQ(1u, resolver->pending_requests().size()); 2733 EXPECT_EQ(GURL("http://request1"), resolver->pending_requests()[0]->url()); 2734 2735 // Complete the pending request. 2736 resolver->pending_requests()[0]->results()->UseNamedProxy("request1:80"); 2737 resolver->pending_requests()[0]->CompleteNow(OK); 2738 2739 // Wait for completion callback, and verify that the request ran as expected. 2740 EXPECT_EQ(OK, callback1.WaitForResult()); 2741 EXPECT_EQ("request1:80", info1.proxy_server().ToURI()); 2742 2743 // At this point we have initialized the proxy service using a PAC script. 2744 // Our PAC poller is set to update ONLY in response to network activity, 2745 // (i.e. another call to ResolveProxy()). 2746 2747 ASSERT_FALSE(fetcher->has_pending_request()); 2748 ASSERT_TRUE(resolver->pending_requests().empty()); 2749 2750 // Start a second request. 2751 ProxyInfo info2; 2752 TestCompletionCallback callback2; 2753 rv = service.ResolveProxy( 2754 GURL("http://request2"), &info2, callback2.callback(), NULL, 2755 BoundNetLog()); 2756 EXPECT_EQ(ERR_IO_PENDING, rv); 2757 2758 // This request should have sent work to the resolver; complete it. 2759 ASSERT_EQ(1u, resolver->pending_requests().size()); 2760 EXPECT_EQ(GURL("http://request2"), resolver->pending_requests()[0]->url()); 2761 resolver->pending_requests()[0]->results()->UseNamedProxy("request2:80"); 2762 resolver->pending_requests()[0]->CompleteNow(OK); 2763 2764 EXPECT_EQ(OK, callback2.WaitForResult()); 2765 EXPECT_EQ("request2:80", info2.proxy_server().ToURI()); 2766 2767 // In response to getting that resolve request, the poller should have 2768 // started the next poll, and made it as far as to request the download. 2769 2770 EXPECT_TRUE(fetcher->has_pending_request()); 2771 EXPECT_EQ(GURL("http://foopy/proxy.pac"), fetcher->pending_request_url()); 2772 2773 // This time we will fail the download, to simulate a PAC script change. 2774 fetcher->NotifyFetchCompletion(ERR_FAILED, std::string()); 2775 2776 // Drain the message loop, so ProxyService is notified of the change 2777 // and has a chance to re-configure itself. 2778 base::MessageLoop::current()->RunUntilIdle(); 2779 2780 // Start a third request -- this time we expect to get a direct connection 2781 // since the PAC script poller experienced a failure. 2782 ProxyInfo info3; 2783 TestCompletionCallback callback3; 2784 rv = service.ResolveProxy( 2785 GURL("http://request3"), &info3, callback3.callback(), NULL, 2786 BoundNetLog()); 2787 EXPECT_EQ(OK, rv); 2788 EXPECT_TRUE(info3.is_direct()); 2789} 2790 2791} // namespace net 2792