1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "net/proxy/proxy_service.h" 6 7 #include <vector> 8 9 #include "base/format_macros.h" 10 #include "base/logging.h" 11 #include "base/string_util.h" 12 #include "base/utf_string_conversions.h" 13 #include "googleurl/src/gurl.h" 14 #include "net/base/net_errors.h" 15 #include "net/base/net_log.h" 16 #include "net/base/net_log_unittest.h" 17 #include "net/base/test_completion_callback.h" 18 #include "net/proxy/mock_proxy_resolver.h" 19 #include "net/proxy/proxy_config_service.h" 20 #include "net/proxy/proxy_resolver.h" 21 #include "net/proxy/proxy_script_fetcher.h" 22 #include "testing/gtest/include/gtest/gtest.h" 23 24 // TODO(eroman): Write a test which exercises 25 // ProxyService::SuspendAllPendingRequests(). 26 namespace net { 27 namespace { 28 29 class MockProxyConfigService: public ProxyConfigService { 30 public: 31 explicit MockProxyConfigService(const ProxyConfig& config) 32 : availability_(CONFIG_VALID), 33 config_(config) { 34 } 35 36 explicit MockProxyConfigService(const std::string& pac_url) 37 : availability_(CONFIG_VALID), 38 config_(ProxyConfig::CreateFromCustomPacURL(GURL(pac_url))) { 39 } 40 41 virtual void AddObserver(Observer* observer) { 42 observers_.AddObserver(observer); 43 } 44 45 virtual void RemoveObserver(Observer* observer) { 46 observers_.RemoveObserver(observer); 47 } 48 49 virtual ConfigAvailability GetLatestProxyConfig(ProxyConfig* results) { 50 if (availability_ == CONFIG_VALID) 51 *results = config_; 52 return availability_; 53 } 54 55 void SetConfig(const ProxyConfig& config) { 56 availability_ = CONFIG_VALID; 57 config_ = config; 58 FOR_EACH_OBSERVER(Observer, observers_, 59 OnProxyConfigChanged(config_, availability_)); 60 } 61 62 private: 63 ConfigAvailability availability_; 64 ProxyConfig config_; 65 ObserverList<Observer, true> observers_; 66 }; 67 68 } // namespace 69 70 // A mock ProxyScriptFetcher. No result will be returned to the fetch client 71 // until we call NotifyFetchCompletion() to set the results. 72 class MockProxyScriptFetcher : public ProxyScriptFetcher { 73 public: 74 MockProxyScriptFetcher() 75 : pending_request_callback_(NULL), pending_request_text_(NULL) { 76 } 77 78 // ProxyScriptFetcher implementation. 79 virtual int Fetch(const GURL& url, 80 string16* text, 81 CompletionCallback* callback) { 82 DCHECK(!has_pending_request()); 83 84 // Save the caller's information, and have them wait. 85 pending_request_url_ = url; 86 pending_request_callback_ = callback; 87 pending_request_text_ = text; 88 return ERR_IO_PENDING; 89 } 90 91 void NotifyFetchCompletion(int result, const std::string& ascii_text) { 92 DCHECK(has_pending_request()); 93 *pending_request_text_ = ASCIIToUTF16(ascii_text); 94 CompletionCallback* callback = pending_request_callback_; 95 pending_request_callback_ = NULL; 96 callback->Run(result); 97 } 98 99 virtual void Cancel() {} 100 101 virtual URLRequestContext* GetRequestContext() { return NULL; } 102 103 const GURL& pending_request_url() const { 104 return pending_request_url_; 105 } 106 107 bool has_pending_request() const { 108 return pending_request_callback_ != NULL; 109 } 110 111 private: 112 GURL pending_request_url_; 113 CompletionCallback* pending_request_callback_; 114 string16* pending_request_text_; 115 }; 116 117 TEST(ProxyServiceTest, Direct) { 118 MockAsyncProxyResolver* resolver = new MockAsyncProxyResolver; 119 scoped_refptr<ProxyService> service( 120 new ProxyService(new MockProxyConfigService( 121 ProxyConfig::CreateDirect()), resolver, NULL)); 122 123 GURL url("http://www.google.com/"); 124 125 ProxyInfo info; 126 TestCompletionCallback callback; 127 CapturingBoundNetLog log(CapturingNetLog::kUnbounded); 128 int rv = service->ResolveProxy(url, &info, &callback, NULL, log.bound()); 129 EXPECT_EQ(OK, rv); 130 EXPECT_TRUE(resolver->pending_requests().empty()); 131 132 EXPECT_TRUE(info.is_direct()); 133 134 // Check the NetLog was filled correctly. 135 CapturingNetLog::EntryList entries; 136 log.GetEntries(&entries); 137 138 EXPECT_EQ(3u, entries.size()); 139 EXPECT_TRUE(LogContainsBeginEvent( 140 entries, 0, NetLog::TYPE_PROXY_SERVICE)); 141 EXPECT_TRUE(LogContainsEvent( 142 entries, 1, NetLog::TYPE_PROXY_SERVICE_RESOLVED_PROXY_LIST, 143 NetLog::PHASE_NONE)); 144 EXPECT_TRUE(LogContainsEndEvent( 145 entries, 2, NetLog::TYPE_PROXY_SERVICE)); 146 } 147 148 TEST(ProxyServiceTest, PAC) { 149 MockProxyConfigService* config_service = 150 new MockProxyConfigService("http://foopy/proxy.pac"); 151 152 MockAsyncProxyResolver* resolver = new MockAsyncProxyResolver; 153 154 scoped_refptr<ProxyService> service( 155 new ProxyService(config_service, resolver, NULL)); 156 157 GURL url("http://www.google.com/"); 158 159 ProxyInfo info; 160 TestCompletionCallback callback; 161 CapturingBoundNetLog log(CapturingNetLog::kUnbounded); 162 163 int rv = service->ResolveProxy(url, &info, &callback, NULL, log.bound()); 164 EXPECT_EQ(ERR_IO_PENDING, rv); 165 166 EXPECT_EQ(GURL("http://foopy/proxy.pac"), 167 resolver->pending_set_pac_script_request()->script_data()->url()); 168 resolver->pending_set_pac_script_request()->CompleteNow(OK); 169 170 ASSERT_EQ(1u, resolver->pending_requests().size()); 171 EXPECT_EQ(url, resolver->pending_requests()[0]->url()); 172 173 // Set the result in proxy resolver. 174 resolver->pending_requests()[0]->results()->UseNamedProxy("foopy"); 175 resolver->pending_requests()[0]->CompleteNow(OK); 176 177 EXPECT_EQ(OK, callback.WaitForResult()); 178 EXPECT_FALSE(info.is_direct()); 179 EXPECT_EQ("foopy:80", info.proxy_server().ToURI()); 180 181 // Check the NetLog was filled correctly. 182 CapturingNetLog::EntryList entries; 183 log.GetEntries(&entries); 184 185 EXPECT_EQ(5u, entries.size()); 186 EXPECT_TRUE(LogContainsBeginEvent( 187 entries, 0, NetLog::TYPE_PROXY_SERVICE)); 188 EXPECT_TRUE(LogContainsBeginEvent( 189 entries, 1, NetLog::TYPE_PROXY_SERVICE_WAITING_FOR_INIT_PAC)); 190 EXPECT_TRUE(LogContainsEndEvent( 191 entries, 2, NetLog::TYPE_PROXY_SERVICE_WAITING_FOR_INIT_PAC)); 192 EXPECT_TRUE(LogContainsEndEvent( 193 entries, 4, NetLog::TYPE_PROXY_SERVICE)); 194 } 195 196 // Test that the proxy resolver does not see the URL's username/password 197 // or its reference section. 198 TEST(ProxyServiceTest, PAC_NoIdentityOrHash) { 199 MockProxyConfigService* config_service = 200 new MockProxyConfigService("http://foopy/proxy.pac"); 201 202 MockAsyncProxyResolver* resolver = new MockAsyncProxyResolver; 203 204 scoped_refptr<ProxyService> service( 205 new ProxyService(config_service, resolver, NULL)); 206 207 GURL url("http://username:password@www.google.com/?ref#hash#hash"); 208 209 ProxyInfo info; 210 TestCompletionCallback callback; 211 int rv = service->ResolveProxy(url, &info, &callback, NULL, BoundNetLog()); 212 EXPECT_EQ(ERR_IO_PENDING, rv); 213 214 EXPECT_EQ(GURL("http://foopy/proxy.pac"), 215 resolver->pending_set_pac_script_request()->script_data()->url()); 216 resolver->pending_set_pac_script_request()->CompleteNow(OK); 217 218 ASSERT_EQ(1u, resolver->pending_requests().size()); 219 // The URL should have been simplified, stripping the username/password/hash. 220 EXPECT_EQ(GURL("http://www.google.com/?ref"), 221 resolver->pending_requests()[0]->url()); 222 223 // We end here without ever completing the request -- destruction of 224 // ProxyService will cancel the outstanding request. 225 } 226 227 TEST(ProxyServiceTest, PAC_FailoverWithoutDirect) { 228 MockProxyConfigService* config_service = 229 new MockProxyConfigService("http://foopy/proxy.pac"); 230 MockAsyncProxyResolver* resolver = new MockAsyncProxyResolver; 231 232 scoped_refptr<ProxyService> service( 233 new ProxyService(config_service, resolver, NULL)); 234 235 GURL url("http://www.google.com/"); 236 237 ProxyInfo info; 238 TestCompletionCallback callback1; 239 int rv = service->ResolveProxy(url, &info, &callback1, NULL, BoundNetLog()); 240 EXPECT_EQ(ERR_IO_PENDING, rv); 241 242 EXPECT_EQ(GURL("http://foopy/proxy.pac"), 243 resolver->pending_set_pac_script_request()->script_data()->url()); 244 resolver->pending_set_pac_script_request()->CompleteNow(OK); 245 246 ASSERT_EQ(1u, resolver->pending_requests().size()); 247 EXPECT_EQ(url, resolver->pending_requests()[0]->url()); 248 249 // Set the result in proxy resolver. 250 resolver->pending_requests()[0]->results()->UseNamedProxy("foopy:8080"); 251 resolver->pending_requests()[0]->CompleteNow(OK); 252 253 EXPECT_EQ(OK, callback1.WaitForResult()); 254 EXPECT_FALSE(info.is_direct()); 255 EXPECT_EQ("foopy:8080", info.proxy_server().ToURI()); 256 257 // Now, imagine that connecting to foopy:8080 fails: there is nothing 258 // left to fallback to, since our proxy list was NOT terminated by 259 // DIRECT. 260 TestCompletionCallback callback2; 261 rv = service->ReconsiderProxyAfterError(url, &info, &callback2, NULL, 262 BoundNetLog()); 263 // ReconsiderProxyAfterError returns error indicating nothing left. 264 EXPECT_EQ(ERR_FAILED, rv); 265 EXPECT_TRUE(info.is_empty()); 266 } 267 268 // The proxy list could potentially contain the DIRECT fallback choice 269 // in a location other than the very end of the list, and could even 270 // specify it multiple times. 271 // 272 // This is not a typical usage, but we will obey it. 273 // (If we wanted to disallow this type of input, the right place to 274 // enforce it would be in parsing the PAC result string). 275 // 276 // This test will use the PAC result string: 277 // 278 // "DIRECT ; PROXY foobar:10 ; DIRECT ; PROXY foobar:20" 279 // 280 // For which we expect it to try DIRECT, then foobar:10, then DIRECT again, 281 // then foobar:20, and then give up and error. 282 // 283 // The important check of this test is to make sure that DIRECT is not somehow 284 // cached as being a bad proxy. 285 TEST(ProxyServiceTest, PAC_FailoverAfterDirect) { 286 MockProxyConfigService* config_service = 287 new MockProxyConfigService("http://foopy/proxy.pac"); 288 MockAsyncProxyResolver* resolver = new MockAsyncProxyResolver; 289 290 scoped_refptr<ProxyService> service( 291 new ProxyService(config_service, resolver, NULL)); 292 293 GURL url("http://www.google.com/"); 294 295 ProxyInfo info; 296 TestCompletionCallback callback1; 297 int rv = service->ResolveProxy(url, &info, &callback1, NULL, BoundNetLog()); 298 EXPECT_EQ(ERR_IO_PENDING, rv); 299 300 EXPECT_EQ(GURL("http://foopy/proxy.pac"), 301 resolver->pending_set_pac_script_request()->script_data()->url()); 302 resolver->pending_set_pac_script_request()->CompleteNow(OK); 303 304 ASSERT_EQ(1u, resolver->pending_requests().size()); 305 EXPECT_EQ(url, resolver->pending_requests()[0]->url()); 306 307 // Set the result in proxy resolver. 308 resolver->pending_requests()[0]->results()->UsePacString( 309 "DIRECT ; PROXY foobar:10 ; DIRECT ; PROXY foobar:20"); 310 resolver->pending_requests()[0]->CompleteNow(OK); 311 312 EXPECT_EQ(OK, callback1.WaitForResult()); 313 EXPECT_TRUE(info.is_direct()); 314 315 // Fallback 1. 316 TestCompletionCallback callback2; 317 rv = service->ReconsiderProxyAfterError(url, &info, &callback2, NULL, 318 BoundNetLog()); 319 EXPECT_EQ(OK, rv); 320 EXPECT_FALSE(info.is_direct()); 321 EXPECT_EQ("foobar:10", info.proxy_server().ToURI()); 322 323 // Fallback 2. 324 TestCompletionCallback callback3; 325 rv = service->ReconsiderProxyAfterError(url, &info, &callback3, NULL, 326 BoundNetLog()); 327 EXPECT_EQ(OK, rv); 328 EXPECT_TRUE(info.is_direct()); 329 330 // Fallback 3. 331 TestCompletionCallback callback4; 332 rv = service->ReconsiderProxyAfterError(url, &info, &callback4, NULL, 333 BoundNetLog()); 334 EXPECT_EQ(OK, rv); 335 EXPECT_FALSE(info.is_direct()); 336 EXPECT_EQ("foobar:20", info.proxy_server().ToURI()); 337 338 // Fallback 4 -- Nothing to fall back to! 339 TestCompletionCallback callback5; 340 rv = service->ReconsiderProxyAfterError(url, &info, &callback5, NULL, 341 BoundNetLog()); 342 EXPECT_EQ(ERR_FAILED, rv); 343 EXPECT_TRUE(info.is_empty()); 344 } 345 346 TEST(ProxyServiceTest, ProxyResolverFails) { 347 // Test what happens when the ProxyResolver fails. The download and setting 348 // of the PAC script have already succeeded, so this corresponds with a 349 // javascript runtime error while calling FindProxyForURL(). 350 351 MockProxyConfigService* config_service = 352 new MockProxyConfigService("http://foopy/proxy.pac"); 353 354 MockAsyncProxyResolver* resolver = new MockAsyncProxyResolver; 355 356 scoped_refptr<ProxyService> service( 357 new ProxyService(config_service, resolver, NULL)); 358 359 // Start first resolve request. 360 GURL url("http://www.google.com/"); 361 ProxyInfo info; 362 TestCompletionCallback callback1; 363 int rv = service->ResolveProxy(url, &info, &callback1, NULL, BoundNetLog()); 364 EXPECT_EQ(ERR_IO_PENDING, rv); 365 366 EXPECT_EQ(GURL("http://foopy/proxy.pac"), 367 resolver->pending_set_pac_script_request()->script_data()->url()); 368 resolver->pending_set_pac_script_request()->CompleteNow(OK); 369 370 ASSERT_EQ(1u, resolver->pending_requests().size()); 371 EXPECT_EQ(url, resolver->pending_requests()[0]->url()); 372 373 // Fail the first resolve request in MockAsyncProxyResolver. 374 resolver->pending_requests()[0]->CompleteNow(ERR_FAILED); 375 376 // Although the proxy resolver failed the request, ProxyService implicitly 377 // falls-back to DIRECT. 378 EXPECT_EQ(OK, callback1.WaitForResult()); 379 EXPECT_TRUE(info.is_direct()); 380 381 // The second resolve request will try to run through the proxy resolver, 382 // regardless of whether the first request failed in it. 383 TestCompletionCallback callback2; 384 rv = service->ResolveProxy(url, &info, &callback2, NULL, BoundNetLog()); 385 EXPECT_EQ(ERR_IO_PENDING, rv); 386 387 ASSERT_EQ(1u, resolver->pending_requests().size()); 388 EXPECT_EQ(url, resolver->pending_requests()[0]->url()); 389 390 // This time we will have the resolver succeed (perhaps the PAC script has 391 // a dependency on the current time). 392 resolver->pending_requests()[0]->results()->UseNamedProxy("foopy_valid:8080"); 393 resolver->pending_requests()[0]->CompleteNow(OK); 394 395 EXPECT_EQ(OK, callback2.WaitForResult()); 396 EXPECT_FALSE(info.is_direct()); 397 EXPECT_EQ("foopy_valid:8080", info.proxy_server().ToURI()); 398 } 399 400 TEST(ProxyServiceTest, ProxyFallback) { 401 // Test what happens when we specify multiple proxy servers and some of them 402 // are bad. 403 404 MockProxyConfigService* config_service = 405 new MockProxyConfigService("http://foopy/proxy.pac"); 406 407 MockAsyncProxyResolver* resolver = new MockAsyncProxyResolver; 408 409 scoped_refptr<ProxyService> service( 410 new ProxyService(config_service, resolver, NULL)); 411 412 GURL url("http://www.google.com/"); 413 414 // Get the proxy information. 415 ProxyInfo info; 416 TestCompletionCallback callback1; 417 int rv = service->ResolveProxy(url, &info, &callback1, NULL, BoundNetLog()); 418 EXPECT_EQ(ERR_IO_PENDING, rv); 419 420 EXPECT_EQ(GURL("http://foopy/proxy.pac"), 421 resolver->pending_set_pac_script_request()->script_data()->url()); 422 resolver->pending_set_pac_script_request()->CompleteNow(OK); 423 424 ASSERT_EQ(1u, resolver->pending_requests().size()); 425 EXPECT_EQ(url, resolver->pending_requests()[0]->url()); 426 427 // Set the result in proxy resolver. 428 resolver->pending_requests()[0]->results()->UseNamedProxy( 429 "foopy1:8080;foopy2:9090"); 430 resolver->pending_requests()[0]->CompleteNow(OK); 431 432 // The first item is valid. 433 EXPECT_EQ(OK, callback1.WaitForResult()); 434 EXPECT_FALSE(info.is_direct()); 435 EXPECT_EQ("foopy1:8080", info.proxy_server().ToURI()); 436 437 // Fake an error on the proxy. 438 TestCompletionCallback callback2; 439 rv = service->ReconsiderProxyAfterError(url, &info, &callback2, NULL, 440 BoundNetLog()); 441 EXPECT_EQ(OK, rv); 442 443 // The second proxy should be specified. 444 EXPECT_EQ("foopy2:9090", info.proxy_server().ToURI()); 445 446 TestCompletionCallback callback3; 447 rv = service->ResolveProxy(url, &info, &callback3, NULL, BoundNetLog()); 448 EXPECT_EQ(ERR_IO_PENDING, rv); 449 450 ASSERT_EQ(1u, resolver->pending_requests().size()); 451 EXPECT_EQ(url, resolver->pending_requests()[0]->url()); 452 453 // Set the result in proxy resolver -- the second result is already known 454 // to be bad, so we will not try to use it initially. 455 resolver->pending_requests()[0]->results()->UseNamedProxy( 456 "foopy3:7070;foopy1:8080;foopy2:9090"); 457 resolver->pending_requests()[0]->CompleteNow(OK); 458 459 EXPECT_EQ(OK, callback3.WaitForResult()); 460 EXPECT_FALSE(info.is_direct()); 461 EXPECT_EQ("foopy3:7070", info.proxy_server().ToURI()); 462 463 // We fake another error. It should now try the third one. 464 TestCompletionCallback callback4; 465 rv = service->ReconsiderProxyAfterError(url, &info, &callback4, NULL, 466 BoundNetLog()); 467 EXPECT_EQ(OK, rv); 468 EXPECT_EQ("foopy2:9090", info.proxy_server().ToURI()); 469 470 // We fake another error. At this point we have tried all of the 471 // proxy servers we thought were valid; next we try the proxy server 472 // that was in our bad proxies map (foopy1:8080). 473 TestCompletionCallback callback5; 474 rv = service->ReconsiderProxyAfterError(url, &info, &callback5, NULL, 475 BoundNetLog()); 476 EXPECT_EQ(OK, rv); 477 EXPECT_EQ("foopy1:8080", info.proxy_server().ToURI()); 478 479 // Fake another error, the last proxy is gone, the list should now be empty, 480 // so there is nothing left to try. 481 TestCompletionCallback callback6; 482 rv = service->ReconsiderProxyAfterError(url, &info, &callback6, NULL, 483 BoundNetLog()); 484 EXPECT_EQ(ERR_FAILED, rv); 485 EXPECT_FALSE(info.is_direct()); 486 EXPECT_TRUE(info.is_empty()); 487 488 // TODO(nsylvain): Test that the proxy can be retried after the delay. 489 } 490 491 // This test is similar to ProxyFallback, but this time we have an explicit 492 // fallback choice to DIRECT. 493 TEST(ProxyServiceTest, ProxyFallbackToDirect) { 494 MockProxyConfigService* config_service = 495 new MockProxyConfigService("http://foopy/proxy.pac"); 496 497 MockAsyncProxyResolver* resolver = new MockAsyncProxyResolver; 498 499 scoped_refptr<ProxyService> service( 500 new ProxyService(config_service, resolver, NULL)); 501 502 GURL url("http://www.google.com/"); 503 504 // Get the proxy information. 505 ProxyInfo info; 506 TestCompletionCallback callback1; 507 int rv = service->ResolveProxy(url, &info, &callback1, NULL, BoundNetLog()); 508 EXPECT_EQ(ERR_IO_PENDING, rv); 509 510 EXPECT_EQ(GURL("http://foopy/proxy.pac"), 511 resolver->pending_set_pac_script_request()->script_data()->url()); 512 resolver->pending_set_pac_script_request()->CompleteNow(OK); 513 514 ASSERT_EQ(1u, resolver->pending_requests().size()); 515 EXPECT_EQ(url, resolver->pending_requests()[0]->url()); 516 517 // Set the result in proxy resolver. 518 resolver->pending_requests()[0]->results()->UsePacString( 519 "PROXY foopy1:8080; PROXY foopy2:9090; DIRECT"); 520 resolver->pending_requests()[0]->CompleteNow(OK); 521 522 // Get the first result. 523 EXPECT_EQ(OK, callback1.WaitForResult()); 524 EXPECT_FALSE(info.is_direct()); 525 EXPECT_EQ("foopy1:8080", info.proxy_server().ToURI()); 526 527 // Fake an error on the proxy. 528 TestCompletionCallback callback2; 529 rv = service->ReconsiderProxyAfterError(url, &info, &callback2, NULL, 530 BoundNetLog()); 531 EXPECT_EQ(OK, rv); 532 533 // Now we get back the second proxy. 534 EXPECT_EQ("foopy2:9090", info.proxy_server().ToURI()); 535 536 // Fake an error on this proxy as well. 537 TestCompletionCallback callback3; 538 rv = service->ReconsiderProxyAfterError(url, &info, &callback3, NULL, 539 BoundNetLog()); 540 EXPECT_EQ(OK, rv); 541 542 // Finally, we get back DIRECT. 543 EXPECT_TRUE(info.is_direct()); 544 545 // Now we tell the proxy service that even DIRECT failed. 546 TestCompletionCallback callback4; 547 rv = service->ReconsiderProxyAfterError(url, &info, &callback4, NULL, 548 BoundNetLog()); 549 // There was nothing left to try after DIRECT, so we are out of 550 // choices. 551 EXPECT_EQ(ERR_FAILED, rv); 552 } 553 554 TEST(ProxyServiceTest, ProxyFallback_NewSettings) { 555 // Test proxy failover when new settings are available. 556 557 MockProxyConfigService* config_service = 558 new MockProxyConfigService("http://foopy/proxy.pac"); 559 560 MockAsyncProxyResolver* resolver = new MockAsyncProxyResolver; 561 562 scoped_refptr<ProxyService> service( 563 new ProxyService(config_service, resolver, NULL)); 564 565 GURL url("http://www.google.com/"); 566 567 // Get the proxy information. 568 ProxyInfo info; 569 TestCompletionCallback callback1; 570 int rv = service->ResolveProxy(url, &info, &callback1, NULL, BoundNetLog()); 571 EXPECT_EQ(ERR_IO_PENDING, rv); 572 573 EXPECT_EQ(GURL("http://foopy/proxy.pac"), 574 resolver->pending_set_pac_script_request()->script_data()->url()); 575 resolver->pending_set_pac_script_request()->CompleteNow(OK); 576 577 ASSERT_EQ(1u, resolver->pending_requests().size()); 578 EXPECT_EQ(url, resolver->pending_requests()[0]->url()); 579 580 // Set the result in proxy resolver. 581 resolver->pending_requests()[0]->results()->UseNamedProxy( 582 "foopy1:8080;foopy2:9090"); 583 resolver->pending_requests()[0]->CompleteNow(OK); 584 585 // The first item is valid. 586 EXPECT_EQ(OK, callback1.WaitForResult()); 587 EXPECT_FALSE(info.is_direct()); 588 EXPECT_EQ("foopy1:8080", info.proxy_server().ToURI()); 589 590 // Fake an error on the proxy, and also a new configuration on the proxy. 591 config_service->SetConfig( 592 ProxyConfig::CreateFromCustomPacURL(GURL("http://foopy-new/proxy.pac"))); 593 594 TestCompletionCallback callback2; 595 rv = service->ReconsiderProxyAfterError(url, &info, &callback2, NULL, 596 BoundNetLog()); 597 EXPECT_EQ(ERR_IO_PENDING, rv); 598 599 EXPECT_EQ(GURL("http://foopy-new/proxy.pac"), 600 resolver->pending_set_pac_script_request()->script_data()->url()); 601 resolver->pending_set_pac_script_request()->CompleteNow(OK); 602 603 ASSERT_EQ(1u, resolver->pending_requests().size()); 604 EXPECT_EQ(url, resolver->pending_requests()[0]->url()); 605 606 resolver->pending_requests()[0]->results()->UseNamedProxy( 607 "foopy1:8080;foopy2:9090"); 608 resolver->pending_requests()[0]->CompleteNow(OK); 609 610 // The first proxy is still there since the configuration changed. 611 EXPECT_EQ(OK, callback2.WaitForResult()); 612 EXPECT_EQ("foopy1:8080", info.proxy_server().ToURI()); 613 614 // We fake another error. It should now ignore the first one. 615 TestCompletionCallback callback3; 616 rv = service->ReconsiderProxyAfterError(url, &info, &callback3, NULL, 617 BoundNetLog()); 618 EXPECT_EQ(OK, rv); 619 EXPECT_EQ("foopy2:9090", info.proxy_server().ToURI()); 620 621 // We simulate a new configuration. 622 config_service->SetConfig( 623 ProxyConfig::CreateFromCustomPacURL( 624 GURL("http://foopy-new2/proxy.pac"))); 625 626 // We fake another error. It should go back to the first proxy. 627 TestCompletionCallback callback4; 628 rv = service->ReconsiderProxyAfterError(url, &info, &callback4, NULL, 629 BoundNetLog()); 630 EXPECT_EQ(ERR_IO_PENDING, rv); 631 632 EXPECT_EQ(GURL("http://foopy-new2/proxy.pac"), 633 resolver->pending_set_pac_script_request()->script_data()->url()); 634 resolver->pending_set_pac_script_request()->CompleteNow(OK); 635 636 ASSERT_EQ(1u, resolver->pending_requests().size()); 637 EXPECT_EQ(url, resolver->pending_requests()[0]->url()); 638 639 resolver->pending_requests()[0]->results()->UseNamedProxy( 640 "foopy1:8080;foopy2:9090"); 641 resolver->pending_requests()[0]->CompleteNow(OK); 642 643 EXPECT_EQ(OK, callback4.WaitForResult()); 644 EXPECT_EQ("foopy1:8080", info.proxy_server().ToURI()); 645 } 646 647 TEST(ProxyServiceTest, ProxyFallback_BadConfig) { 648 // Test proxy failover when the configuration is bad. 649 650 MockProxyConfigService* config_service = 651 new MockProxyConfigService("http://foopy/proxy.pac"); 652 653 MockAsyncProxyResolver* resolver = new MockAsyncProxyResolver; 654 655 scoped_refptr<ProxyService> service( 656 new ProxyService(config_service, resolver, NULL)); 657 658 GURL url("http://www.google.com/"); 659 660 // Get the proxy information. 661 ProxyInfo info; 662 TestCompletionCallback callback1; 663 int rv = service->ResolveProxy(url, &info, &callback1, NULL, BoundNetLog()); 664 EXPECT_EQ(ERR_IO_PENDING, rv); 665 666 EXPECT_EQ(GURL("http://foopy/proxy.pac"), 667 resolver->pending_set_pac_script_request()->script_data()->url()); 668 resolver->pending_set_pac_script_request()->CompleteNow(OK); 669 ASSERT_EQ(1u, resolver->pending_requests().size()); 670 EXPECT_EQ(url, resolver->pending_requests()[0]->url()); 671 672 resolver->pending_requests()[0]->results()->UseNamedProxy( 673 "foopy1:8080;foopy2:9090"); 674 resolver->pending_requests()[0]->CompleteNow(OK); 675 676 // The first item is valid. 677 EXPECT_EQ(OK, callback1.WaitForResult()); 678 EXPECT_FALSE(info.is_direct()); 679 EXPECT_EQ("foopy1:8080", info.proxy_server().ToURI()); 680 681 // Fake a proxy error. 682 TestCompletionCallback callback2; 683 rv = service->ReconsiderProxyAfterError(url, &info, &callback2, NULL, 684 BoundNetLog()); 685 EXPECT_EQ(OK, rv); 686 687 // The first proxy is ignored, and the second one is selected. 688 EXPECT_FALSE(info.is_direct()); 689 EXPECT_EQ("foopy2:9090", info.proxy_server().ToURI()); 690 691 // Fake a PAC failure. 692 ProxyInfo info2; 693 TestCompletionCallback callback3; 694 rv = service->ResolveProxy(url, &info2, &callback3, NULL, BoundNetLog()); 695 EXPECT_EQ(ERR_IO_PENDING, rv); 696 697 ASSERT_EQ(1u, resolver->pending_requests().size()); 698 EXPECT_EQ(url, resolver->pending_requests()[0]->url()); 699 700 // This simulates a javascript runtime error in the PAC script. 701 resolver->pending_requests()[0]->CompleteNow(ERR_FAILED); 702 703 // Although the resolver failed, the ProxyService will implicitly fall-back 704 // to a DIRECT connection. 705 EXPECT_EQ(OK, callback3.WaitForResult()); 706 EXPECT_TRUE(info2.is_direct()); 707 EXPECT_FALSE(info2.is_empty()); 708 709 // The PAC script will work properly next time and successfully return a 710 // proxy list. Since we have not marked the configuration as bad, it should 711 // "just work" the next time we call it. 712 ProxyInfo info3; 713 TestCompletionCallback callback4; 714 rv = service->ReconsiderProxyAfterError(url, &info3, &callback4, NULL, 715 BoundNetLog()); 716 EXPECT_EQ(ERR_IO_PENDING, rv); 717 718 ASSERT_EQ(1u, resolver->pending_requests().size()); 719 EXPECT_EQ(url, resolver->pending_requests()[0]->url()); 720 721 resolver->pending_requests()[0]->results()->UseNamedProxy( 722 "foopy1:8080;foopy2:9090"); 723 resolver->pending_requests()[0]->CompleteNow(OK); 724 725 // The first proxy is not there since the it was added to the bad proxies 726 // list by the earlier ReconsiderProxyAfterError(). 727 EXPECT_EQ(OK, callback4.WaitForResult()); 728 EXPECT_FALSE(info3.is_direct()); 729 EXPECT_EQ("foopy1:8080", info3.proxy_server().ToURI()); 730 } 731 732 TEST(ProxyServiceTest, ProxyBypassList) { 733 // Test that the proxy bypass rules are consulted. 734 735 TestCompletionCallback callback[2]; 736 ProxyInfo info[2]; 737 ProxyConfig config; 738 config.proxy_rules().ParseFromString("foopy1:8080;foopy2:9090"); 739 config.set_auto_detect(false); 740 config.proxy_rules().bypass_rules.ParseFromString("*.org"); 741 742 scoped_refptr<ProxyService> service(new ProxyService( 743 new MockProxyConfigService(config), new MockAsyncProxyResolver, NULL)); 744 745 int rv; 746 GURL url1("http://www.webkit.org"); 747 GURL url2("http://www.webkit.com"); 748 749 // Request for a .org domain should bypass proxy. 750 rv = service->ResolveProxy(url1, &info[0], &callback[0], NULL, BoundNetLog()); 751 EXPECT_EQ(OK, rv); 752 EXPECT_TRUE(info[0].is_direct()); 753 754 // Request for a .com domain hits the proxy. 755 rv = service->ResolveProxy(url2, &info[1], &callback[1], NULL, BoundNetLog()); 756 EXPECT_EQ(OK, rv); 757 EXPECT_EQ("foopy1:8080", info[1].proxy_server().ToURI()); 758 } 759 760 761 TEST(ProxyServiceTest, PerProtocolProxyTests) { 762 ProxyConfig config; 763 config.proxy_rules().ParseFromString("http=foopy1:8080;https=foopy2:8080"); 764 config.set_auto_detect(false); 765 { 766 scoped_refptr<ProxyService> service(new ProxyService( 767 new MockProxyConfigService(config), new MockAsyncProxyResolver, NULL)); 768 GURL test_url("http://www.msn.com"); 769 ProxyInfo info; 770 TestCompletionCallback callback; 771 int rv = service->ResolveProxy(test_url, &info, &callback, NULL, 772 BoundNetLog()); 773 EXPECT_EQ(OK, rv); 774 EXPECT_FALSE(info.is_direct()); 775 EXPECT_EQ("foopy1:8080", info.proxy_server().ToURI()); 776 } 777 { 778 scoped_refptr<ProxyService> service(new ProxyService( 779 new MockProxyConfigService(config), new MockAsyncProxyResolver, NULL)); 780 GURL test_url("ftp://ftp.google.com"); 781 ProxyInfo info; 782 TestCompletionCallback callback; 783 int rv = service->ResolveProxy(test_url, &info, &callback, NULL, 784 BoundNetLog()); 785 EXPECT_EQ(OK, rv); 786 EXPECT_TRUE(info.is_direct()); 787 EXPECT_EQ("direct://", info.proxy_server().ToURI()); 788 } 789 { 790 scoped_refptr<ProxyService> service(new ProxyService( 791 new MockProxyConfigService(config), new MockAsyncProxyResolver, NULL)); 792 GURL test_url("https://webbranch.techcu.com"); 793 ProxyInfo info; 794 TestCompletionCallback callback; 795 int rv = service->ResolveProxy(test_url, &info, &callback, NULL, 796 BoundNetLog()); 797 EXPECT_EQ(OK, rv); 798 EXPECT_FALSE(info.is_direct()); 799 EXPECT_EQ("foopy2:8080", info.proxy_server().ToURI()); 800 } 801 { 802 config.proxy_rules().ParseFromString("foopy1:8080"); 803 scoped_refptr<ProxyService> service(new ProxyService( 804 new MockProxyConfigService(config), new MockAsyncProxyResolver, NULL)); 805 GURL test_url("http://www.microsoft.com"); 806 ProxyInfo info; 807 TestCompletionCallback callback; 808 int rv = service->ResolveProxy(test_url, &info, &callback, NULL, 809 BoundNetLog()); 810 EXPECT_EQ(OK, rv); 811 EXPECT_FALSE(info.is_direct()); 812 EXPECT_EQ("foopy1:8080", info.proxy_server().ToURI()); 813 } 814 } 815 816 // If only HTTP and a SOCKS proxy are specified, check if ftp/https queries 817 // fall back to the SOCKS proxy. 818 TEST(ProxyServiceTest, DefaultProxyFallbackToSOCKS) { 819 ProxyConfig config; 820 config.proxy_rules().ParseFromString("http=foopy1:8080;socks=foopy2:1080"); 821 config.set_auto_detect(false); 822 EXPECT_EQ(ProxyConfig::ProxyRules::TYPE_PROXY_PER_SCHEME, 823 config.proxy_rules().type); 824 825 { 826 scoped_refptr<ProxyService> service(new ProxyService( 827 new MockProxyConfigService(config), new MockAsyncProxyResolver, NULL)); 828 GURL test_url("http://www.msn.com"); 829 ProxyInfo info; 830 TestCompletionCallback callback; 831 int rv = service->ResolveProxy(test_url, &info, &callback, NULL, 832 BoundNetLog()); 833 EXPECT_EQ(OK, rv); 834 EXPECT_FALSE(info.is_direct()); 835 EXPECT_EQ("foopy1:8080", info.proxy_server().ToURI()); 836 } 837 { 838 scoped_refptr<ProxyService> service(new ProxyService( 839 new MockProxyConfigService(config), new MockAsyncProxyResolver, NULL)); 840 GURL test_url("ftp://ftp.google.com"); 841 ProxyInfo info; 842 TestCompletionCallback callback; 843 int rv = service->ResolveProxy(test_url, &info, &callback, NULL, 844 BoundNetLog()); 845 EXPECT_EQ(OK, rv); 846 EXPECT_FALSE(info.is_direct()); 847 EXPECT_EQ("socks4://foopy2:1080", info.proxy_server().ToURI()); 848 } 849 { 850 scoped_refptr<ProxyService> service(new ProxyService( 851 new MockProxyConfigService(config), new MockAsyncProxyResolver, NULL)); 852 GURL test_url("https://webbranch.techcu.com"); 853 ProxyInfo info; 854 TestCompletionCallback callback; 855 int rv = service->ResolveProxy(test_url, &info, &callback, NULL, 856 BoundNetLog()); 857 EXPECT_EQ(OK, rv); 858 EXPECT_FALSE(info.is_direct()); 859 EXPECT_EQ("socks4://foopy2:1080", info.proxy_server().ToURI()); 860 } 861 { 862 scoped_refptr<ProxyService> service(new ProxyService( 863 new MockProxyConfigService(config), new MockAsyncProxyResolver, NULL)); 864 GURL test_url("unknown://www.microsoft.com"); 865 ProxyInfo info; 866 TestCompletionCallback callback; 867 int rv = service->ResolveProxy(test_url, &info, &callback, NULL, 868 BoundNetLog()); 869 EXPECT_EQ(OK, rv); 870 EXPECT_FALSE(info.is_direct()); 871 EXPECT_EQ("socks4://foopy2:1080", info.proxy_server().ToURI()); 872 } 873 } 874 875 // Test cancellation of an in-progress request. 876 TEST(ProxyServiceTest, CancelInProgressRequest) { 877 MockProxyConfigService* config_service = 878 new MockProxyConfigService("http://foopy/proxy.pac"); 879 880 MockAsyncProxyResolver* resolver = new MockAsyncProxyResolver; 881 882 scoped_refptr<ProxyService> service( 883 new ProxyService(config_service, resolver, NULL)); 884 885 // Start 3 requests. 886 887 ProxyInfo info1; 888 TestCompletionCallback callback1; 889 int rv = service->ResolveProxy( 890 GURL("http://request1"), &info1, &callback1, NULL, BoundNetLog()); 891 EXPECT_EQ(ERR_IO_PENDING, rv); 892 893 // Nothing has been sent to the proxy resolver yet, since the proxy 894 // resolver has not been configured yet. 895 ASSERT_EQ(0u, resolver->pending_requests().size()); 896 897 // Successfully initialize the PAC script. 898 EXPECT_EQ(GURL("http://foopy/proxy.pac"), 899 resolver->pending_set_pac_script_request()->script_data()->url()); 900 resolver->pending_set_pac_script_request()->CompleteNow(OK); 901 902 ASSERT_EQ(1u, resolver->pending_requests().size()); 903 EXPECT_EQ(GURL("http://request1"), resolver->pending_requests()[0]->url()); 904 905 ProxyInfo info2; 906 TestCompletionCallback callback2; 907 ProxyService::PacRequest* request2; 908 rv = service->ResolveProxy( 909 GURL("http://request2"), &info2, &callback2, &request2, BoundNetLog()); 910 EXPECT_EQ(ERR_IO_PENDING, rv); 911 ASSERT_EQ(2u, resolver->pending_requests().size()); 912 EXPECT_EQ(GURL("http://request2"), resolver->pending_requests()[1]->url()); 913 914 ProxyInfo info3; 915 TestCompletionCallback callback3; 916 rv = service->ResolveProxy( 917 GURL("http://request3"), &info3, &callback3, NULL, BoundNetLog()); 918 EXPECT_EQ(ERR_IO_PENDING, rv); 919 ASSERT_EQ(3u, resolver->pending_requests().size()); 920 EXPECT_EQ(GURL("http://request3"), resolver->pending_requests()[2]->url()); 921 922 // Cancel the second request 923 service->CancelPacRequest(request2); 924 925 ASSERT_EQ(2u, resolver->pending_requests().size()); 926 EXPECT_EQ(GURL("http://request1"), resolver->pending_requests()[0]->url()); 927 EXPECT_EQ(GURL("http://request3"), resolver->pending_requests()[1]->url()); 928 929 // Complete the two un-cancelled requests. 930 // We complete the last one first, just to mix it up a bit. 931 resolver->pending_requests()[1]->results()->UseNamedProxy("request3:80"); 932 resolver->pending_requests()[1]->CompleteNow(OK); 933 934 resolver->pending_requests()[0]->results()->UseNamedProxy("request1:80"); 935 resolver->pending_requests()[0]->CompleteNow(OK); 936 937 // Complete and verify that requests ran as expected. 938 EXPECT_EQ(OK, callback1.WaitForResult()); 939 EXPECT_EQ("request1:80", info1.proxy_server().ToURI()); 940 941 EXPECT_FALSE(callback2.have_result()); // Cancelled. 942 ASSERT_EQ(1u, resolver->cancelled_requests().size()); 943 EXPECT_EQ(GURL("http://request2"), resolver->cancelled_requests()[0]->url()); 944 945 EXPECT_EQ(OK, callback3.WaitForResult()); 946 EXPECT_EQ("request3:80", info3.proxy_server().ToURI()); 947 } 948 949 // Test the initial PAC download for resolver that expects bytes. 950 TEST(ProxyServiceTest, InitialPACScriptDownload) { 951 MockProxyConfigService* config_service = 952 new MockProxyConfigService("http://foopy/proxy.pac"); 953 954 MockAsyncProxyResolverExpectsBytes* resolver = 955 new MockAsyncProxyResolverExpectsBytes; 956 957 scoped_refptr<ProxyService> service( 958 new ProxyService(config_service, resolver, NULL)); 959 960 MockProxyScriptFetcher* fetcher = new MockProxyScriptFetcher; 961 service->SetProxyScriptFetcher(fetcher); 962 963 // Start 3 requests. 964 965 ProxyInfo info1; 966 TestCompletionCallback callback1; 967 int rv = service->ResolveProxy( 968 GURL("http://request1"), &info1, &callback1, NULL, BoundNetLog()); 969 EXPECT_EQ(ERR_IO_PENDING, rv); 970 971 // The first request should have triggered download of PAC script. 972 EXPECT_TRUE(fetcher->has_pending_request()); 973 EXPECT_EQ(GURL("http://foopy/proxy.pac"), fetcher->pending_request_url()); 974 975 ProxyInfo info2; 976 TestCompletionCallback callback2; 977 rv = service->ResolveProxy( 978 GURL("http://request2"), &info2, &callback2, NULL, BoundNetLog()); 979 EXPECT_EQ(ERR_IO_PENDING, rv); 980 981 ProxyInfo info3; 982 TestCompletionCallback callback3; 983 rv = service->ResolveProxy( 984 GURL("http://request3"), &info3, &callback3, NULL, BoundNetLog()); 985 EXPECT_EQ(ERR_IO_PENDING, rv); 986 987 // Nothing has been sent to the resolver yet. 988 EXPECT_TRUE(resolver->pending_requests().empty()); 989 990 // At this point the ProxyService should be waiting for the 991 // ProxyScriptFetcher to invoke its completion callback, notifying it of 992 // PAC script download completion. 993 fetcher->NotifyFetchCompletion(OK, "pac-v1"); 994 995 // Now that the PAC script is downloaded, it will have been sent to the proxy 996 // resolver. 997 EXPECT_EQ(ASCIIToUTF16("pac-v1"), 998 resolver->pending_set_pac_script_request()->script_data()->utf16()); 999 resolver->pending_set_pac_script_request()->CompleteNow(OK); 1000 1001 ASSERT_EQ(3u, resolver->pending_requests().size()); 1002 EXPECT_EQ(GURL("http://request1"), resolver->pending_requests()[0]->url()); 1003 EXPECT_EQ(GURL("http://request2"), resolver->pending_requests()[1]->url()); 1004 EXPECT_EQ(GURL("http://request3"), resolver->pending_requests()[2]->url()); 1005 1006 // Complete all the requests (in some order). 1007 // Note that as we complete requests, they shift up in |pending_requests()|. 1008 1009 resolver->pending_requests()[2]->results()->UseNamedProxy("request3:80"); 1010 resolver->pending_requests()[2]->CompleteNow(OK); 1011 1012 resolver->pending_requests()[0]->results()->UseNamedProxy("request1:80"); 1013 resolver->pending_requests()[0]->CompleteNow(OK); 1014 1015 resolver->pending_requests()[0]->results()->UseNamedProxy("request2:80"); 1016 resolver->pending_requests()[0]->CompleteNow(OK); 1017 1018 // Complete and verify that requests ran as expected. 1019 EXPECT_EQ(OK, callback1.WaitForResult()); 1020 EXPECT_EQ("request1:80", info1.proxy_server().ToURI()); 1021 1022 EXPECT_EQ(OK, callback2.WaitForResult()); 1023 EXPECT_EQ("request2:80", info2.proxy_server().ToURI()); 1024 1025 EXPECT_EQ(OK, callback3.WaitForResult()); 1026 EXPECT_EQ("request3:80", info3.proxy_server().ToURI()); 1027 } 1028 1029 // Test changing the ProxyScriptFetcher while PAC download is in progress. 1030 TEST(ProxyServiceTest, ChangeScriptFetcherWhilePACDownloadInProgress) { 1031 MockProxyConfigService* config_service = 1032 new MockProxyConfigService("http://foopy/proxy.pac"); 1033 1034 MockAsyncProxyResolverExpectsBytes* resolver = 1035 new MockAsyncProxyResolverExpectsBytes; 1036 1037 scoped_refptr<ProxyService> service( 1038 new ProxyService(config_service, resolver, NULL)); 1039 1040 MockProxyScriptFetcher* fetcher = new MockProxyScriptFetcher; 1041 service->SetProxyScriptFetcher(fetcher); 1042 1043 // Start 2 requests. 1044 1045 ProxyInfo info1; 1046 TestCompletionCallback callback1; 1047 int rv = service->ResolveProxy( 1048 GURL("http://request1"), &info1, &callback1, NULL, BoundNetLog()); 1049 EXPECT_EQ(ERR_IO_PENDING, rv); 1050 1051 // The first request should have triggered download of PAC script. 1052 EXPECT_TRUE(fetcher->has_pending_request()); 1053 EXPECT_EQ(GURL("http://foopy/proxy.pac"), fetcher->pending_request_url()); 1054 1055 ProxyInfo info2; 1056 TestCompletionCallback callback2; 1057 rv = service->ResolveProxy( 1058 GURL("http://request2"), &info2, &callback2, NULL, BoundNetLog()); 1059 EXPECT_EQ(ERR_IO_PENDING, rv); 1060 1061 // At this point the ProxyService should be waiting for the 1062 // ProxyScriptFetcher to invoke its completion callback, notifying it of 1063 // PAC script download completion. 1064 1065 // We now change out the ProxyService's script fetcher. We should restart 1066 // the initialization with the new fetcher. 1067 1068 fetcher = new MockProxyScriptFetcher; 1069 service->SetProxyScriptFetcher(fetcher); 1070 1071 // Nothing has been sent to the resolver yet. 1072 EXPECT_TRUE(resolver->pending_requests().empty()); 1073 1074 fetcher->NotifyFetchCompletion(OK, "pac-v1"); 1075 1076 // Now that the PAC script is downloaded, it will have been sent to the proxy 1077 // resolver. 1078 EXPECT_EQ(ASCIIToUTF16("pac-v1"), 1079 resolver->pending_set_pac_script_request()->script_data()->utf16()); 1080 resolver->pending_set_pac_script_request()->CompleteNow(OK); 1081 1082 ASSERT_EQ(2u, resolver->pending_requests().size()); 1083 EXPECT_EQ(GURL("http://request1"), resolver->pending_requests()[0]->url()); 1084 EXPECT_EQ(GURL("http://request2"), resolver->pending_requests()[1]->url()); 1085 } 1086 1087 // Test cancellation of a request, while the PAC script is being fetched. 1088 TEST(ProxyServiceTest, CancelWhilePACFetching) { 1089 MockProxyConfigService* config_service = 1090 new MockProxyConfigService("http://foopy/proxy.pac"); 1091 1092 MockAsyncProxyResolverExpectsBytes* resolver = 1093 new MockAsyncProxyResolverExpectsBytes; 1094 1095 scoped_refptr<ProxyService> service( 1096 new ProxyService(config_service, resolver, NULL)); 1097 1098 MockProxyScriptFetcher* fetcher = new MockProxyScriptFetcher; 1099 service->SetProxyScriptFetcher(fetcher); 1100 1101 // Start 3 requests. 1102 ProxyInfo info1; 1103 TestCompletionCallback callback1; 1104 ProxyService::PacRequest* request1; 1105 CapturingBoundNetLog log1(CapturingNetLog::kUnbounded); 1106 int rv = service->ResolveProxy( 1107 GURL("http://request1"), &info1, &callback1, &request1, log1.bound()); 1108 EXPECT_EQ(ERR_IO_PENDING, rv); 1109 1110 // The first request should have triggered download of PAC script. 1111 EXPECT_TRUE(fetcher->has_pending_request()); 1112 EXPECT_EQ(GURL("http://foopy/proxy.pac"), fetcher->pending_request_url()); 1113 1114 ProxyInfo info2; 1115 TestCompletionCallback callback2; 1116 ProxyService::PacRequest* request2; 1117 rv = service->ResolveProxy( 1118 GURL("http://request2"), &info2, &callback2, &request2, BoundNetLog()); 1119 EXPECT_EQ(ERR_IO_PENDING, rv); 1120 1121 ProxyInfo info3; 1122 TestCompletionCallback callback3; 1123 rv = service->ResolveProxy( 1124 GURL("http://request3"), &info3, &callback3, NULL, BoundNetLog()); 1125 EXPECT_EQ(ERR_IO_PENDING, rv); 1126 1127 // Nothing has been sent to the resolver yet. 1128 EXPECT_TRUE(resolver->pending_requests().empty()); 1129 1130 // Cancel the first 2 requests. 1131 service->CancelPacRequest(request1); 1132 service->CancelPacRequest(request2); 1133 1134 // At this point the ProxyService should be waiting for the 1135 // ProxyScriptFetcher to invoke its completion callback, notifying it of 1136 // PAC script download completion. 1137 fetcher->NotifyFetchCompletion(OK, "pac-v1"); 1138 1139 // Now that the PAC script is downloaded, it will have been sent to the 1140 // proxy resolver. 1141 EXPECT_EQ(ASCIIToUTF16("pac-v1"), 1142 resolver->pending_set_pac_script_request()->script_data()->utf16()); 1143 resolver->pending_set_pac_script_request()->CompleteNow(OK); 1144 1145 ASSERT_EQ(1u, resolver->pending_requests().size()); 1146 EXPECT_EQ(GURL("http://request3"), resolver->pending_requests()[0]->url()); 1147 1148 // Complete all the requests. 1149 resolver->pending_requests()[0]->results()->UseNamedProxy("request3:80"); 1150 resolver->pending_requests()[0]->CompleteNow(OK); 1151 1152 EXPECT_EQ(OK, callback3.WaitForResult()); 1153 EXPECT_EQ("request3:80", info3.proxy_server().ToURI()); 1154 1155 EXPECT_TRUE(resolver->cancelled_requests().empty()); 1156 1157 EXPECT_FALSE(callback1.have_result()); // Cancelled. 1158 EXPECT_FALSE(callback2.have_result()); // Cancelled. 1159 1160 CapturingNetLog::EntryList entries1; 1161 log1.GetEntries(&entries1); 1162 1163 // Check the NetLog for request 1 (which was cancelled) got filled properly. 1164 EXPECT_EQ(4u, entries1.size()); 1165 EXPECT_TRUE(LogContainsBeginEvent( 1166 entries1, 0, NetLog::TYPE_PROXY_SERVICE)); 1167 EXPECT_TRUE(LogContainsBeginEvent( 1168 entries1, 1, NetLog::TYPE_PROXY_SERVICE_WAITING_FOR_INIT_PAC)); 1169 // Note that TYPE_PROXY_SERVICE_WAITING_FOR_INIT_PAC is never completed before 1170 // the cancellation occured. 1171 EXPECT_TRUE(LogContainsEvent( 1172 entries1, 2, NetLog::TYPE_CANCELLED, NetLog::PHASE_NONE)); 1173 EXPECT_TRUE(LogContainsEndEvent( 1174 entries1, 3, NetLog::TYPE_PROXY_SERVICE)); 1175 } 1176 1177 // Test that if auto-detect fails, we fall-back to the custom pac. 1178 TEST(ProxyServiceTest, FallbackFromAutodetectToCustomPac) { 1179 ProxyConfig config; 1180 config.set_auto_detect(true); 1181 config.set_pac_url(GURL("http://foopy/proxy.pac")); 1182 config.proxy_rules().ParseFromString("http=foopy:80"); // Won't be used. 1183 1184 MockProxyConfigService* config_service = new MockProxyConfigService(config); 1185 MockAsyncProxyResolverExpectsBytes* resolver = 1186 new MockAsyncProxyResolverExpectsBytes; 1187 scoped_refptr<ProxyService> service( 1188 new ProxyService(config_service, resolver, NULL)); 1189 1190 MockProxyScriptFetcher* fetcher = new MockProxyScriptFetcher; 1191 service->SetProxyScriptFetcher(fetcher); 1192 1193 // Start 2 requests. 1194 1195 ProxyInfo info1; 1196 TestCompletionCallback callback1; 1197 int rv = service->ResolveProxy( 1198 GURL("http://request1"), &info1, &callback1, NULL, BoundNetLog()); 1199 EXPECT_EQ(ERR_IO_PENDING, rv); 1200 1201 ProxyInfo info2; 1202 TestCompletionCallback callback2; 1203 ProxyService::PacRequest* request2; 1204 rv = service->ResolveProxy( 1205 GURL("http://request2"), &info2, &callback2, &request2, BoundNetLog()); 1206 EXPECT_EQ(ERR_IO_PENDING, rv); 1207 1208 // Check that nothing has been sent to the proxy resolver yet. 1209 ASSERT_EQ(0u, resolver->pending_requests().size()); 1210 1211 // It should be trying to auto-detect first -- FAIL the autodetect during 1212 // the script download. 1213 EXPECT_TRUE(fetcher->has_pending_request()); 1214 EXPECT_EQ(GURL("http://wpad/wpad.dat"), fetcher->pending_request_url()); 1215 fetcher->NotifyFetchCompletion(ERR_FAILED, ""); 1216 1217 // Next it should be trying the custom PAC url. 1218 EXPECT_TRUE(fetcher->has_pending_request()); 1219 EXPECT_EQ(GURL("http://foopy/proxy.pac"), fetcher->pending_request_url()); 1220 fetcher->NotifyFetchCompletion(OK, "custom-pac-script"); 1221 1222 EXPECT_EQ(ASCIIToUTF16("custom-pac-script"), 1223 resolver->pending_set_pac_script_request()->script_data()->utf16()); 1224 resolver->pending_set_pac_script_request()->CompleteNow(OK); 1225 1226 // Now finally, the pending requests should have been sent to the resolver 1227 // (which was initialized with custom PAC script). 1228 1229 ASSERT_EQ(2u, resolver->pending_requests().size()); 1230 EXPECT_EQ(GURL("http://request1"), resolver->pending_requests()[0]->url()); 1231 EXPECT_EQ(GURL("http://request2"), resolver->pending_requests()[1]->url()); 1232 1233 // Complete the pending requests. 1234 resolver->pending_requests()[1]->results()->UseNamedProxy("request2:80"); 1235 resolver->pending_requests()[1]->CompleteNow(OK); 1236 resolver->pending_requests()[0]->results()->UseNamedProxy("request1:80"); 1237 resolver->pending_requests()[0]->CompleteNow(OK); 1238 1239 // Verify that requests ran as expected. 1240 EXPECT_EQ(OK, callback1.WaitForResult()); 1241 EXPECT_EQ("request1:80", info1.proxy_server().ToURI()); 1242 1243 EXPECT_EQ(OK, callback2.WaitForResult()); 1244 EXPECT_EQ("request2:80", info2.proxy_server().ToURI()); 1245 } 1246 1247 // This is the same test as FallbackFromAutodetectToCustomPac, except 1248 // the auto-detect script fails parsing rather than downloading. 1249 TEST(ProxyServiceTest, FallbackFromAutodetectToCustomPac2) { 1250 ProxyConfig config; 1251 config.set_auto_detect(true); 1252 config.set_pac_url(GURL("http://foopy/proxy.pac")); 1253 config.proxy_rules().ParseFromString("http=foopy:80"); // Won't be used. 1254 1255 MockProxyConfigService* config_service = new MockProxyConfigService(config); 1256 MockAsyncProxyResolverExpectsBytes* resolver = 1257 new MockAsyncProxyResolverExpectsBytes; 1258 scoped_refptr<ProxyService> service( 1259 new ProxyService(config_service, resolver, NULL)); 1260 1261 MockProxyScriptFetcher* fetcher = new MockProxyScriptFetcher; 1262 service->SetProxyScriptFetcher(fetcher); 1263 1264 // Start 2 requests. 1265 1266 ProxyInfo info1; 1267 TestCompletionCallback callback1; 1268 int rv = service->ResolveProxy( 1269 GURL("http://request1"), &info1, &callback1, NULL, BoundNetLog()); 1270 EXPECT_EQ(ERR_IO_PENDING, rv); 1271 1272 ProxyInfo info2; 1273 TestCompletionCallback callback2; 1274 ProxyService::PacRequest* request2; 1275 rv = service->ResolveProxy( 1276 GURL("http://request2"), &info2, &callback2, &request2, BoundNetLog()); 1277 EXPECT_EQ(ERR_IO_PENDING, rv); 1278 1279 // Check that nothing has been sent to the proxy resolver yet. 1280 ASSERT_EQ(0u, resolver->pending_requests().size()); 1281 1282 // It should be trying to auto-detect first -- succeed the download. 1283 EXPECT_TRUE(fetcher->has_pending_request()); 1284 EXPECT_EQ(GURL("http://wpad/wpad.dat"), fetcher->pending_request_url()); 1285 fetcher->NotifyFetchCompletion(OK, "invalid-script-contents"); 1286 1287 // Simulate a parse error. 1288 EXPECT_EQ(ASCIIToUTF16("invalid-script-contents"), 1289 resolver->pending_set_pac_script_request()->script_data()->utf16()); 1290 resolver->pending_set_pac_script_request()->CompleteNow( 1291 ERR_PAC_SCRIPT_FAILED); 1292 1293 // Next it should be trying the custom PAC url. 1294 EXPECT_TRUE(fetcher->has_pending_request()); 1295 EXPECT_EQ(GURL("http://foopy/proxy.pac"), fetcher->pending_request_url()); 1296 fetcher->NotifyFetchCompletion(OK, "custom-pac-script"); 1297 1298 EXPECT_EQ(ASCIIToUTF16("custom-pac-script"), 1299 resolver->pending_set_pac_script_request()->script_data()->utf16()); 1300 resolver->pending_set_pac_script_request()->CompleteNow(OK); 1301 1302 // Now finally, the pending requests should have been sent to the resolver 1303 // (which was initialized with custom PAC script). 1304 1305 ASSERT_EQ(2u, resolver->pending_requests().size()); 1306 EXPECT_EQ(GURL("http://request1"), resolver->pending_requests()[0]->url()); 1307 EXPECT_EQ(GURL("http://request2"), resolver->pending_requests()[1]->url()); 1308 1309 // Complete the pending requests. 1310 resolver->pending_requests()[1]->results()->UseNamedProxy("request2:80"); 1311 resolver->pending_requests()[1]->CompleteNow(OK); 1312 resolver->pending_requests()[0]->results()->UseNamedProxy("request1:80"); 1313 resolver->pending_requests()[0]->CompleteNow(OK); 1314 1315 // Verify that requests ran as expected. 1316 EXPECT_EQ(OK, callback1.WaitForResult()); 1317 EXPECT_EQ("request1:80", info1.proxy_server().ToURI()); 1318 1319 EXPECT_EQ(OK, callback2.WaitForResult()); 1320 EXPECT_EQ("request2:80", info2.proxy_server().ToURI()); 1321 } 1322 1323 // Test that if all of auto-detect, a custom PAC script, and manual settings 1324 // are given, then we will try them in that order. 1325 TEST(ProxyServiceTest, FallbackFromAutodetectToCustomToManual) { 1326 ProxyConfig config; 1327 config.set_auto_detect(true); 1328 config.set_pac_url(GURL("http://foopy/proxy.pac")); 1329 config.proxy_rules().ParseFromString("http=foopy:80"); 1330 1331 MockProxyConfigService* config_service = new MockProxyConfigService(config); 1332 MockAsyncProxyResolverExpectsBytes* resolver = 1333 new MockAsyncProxyResolverExpectsBytes; 1334 scoped_refptr<ProxyService> service( 1335 new ProxyService(config_service, resolver, NULL)); 1336 1337 MockProxyScriptFetcher* fetcher = new MockProxyScriptFetcher; 1338 service->SetProxyScriptFetcher(fetcher); 1339 1340 // Start 2 requests. 1341 1342 ProxyInfo info1; 1343 TestCompletionCallback callback1; 1344 int rv = service->ResolveProxy( 1345 GURL("http://request1"), &info1, &callback1, NULL, BoundNetLog()); 1346 EXPECT_EQ(ERR_IO_PENDING, rv); 1347 1348 ProxyInfo info2; 1349 TestCompletionCallback callback2; 1350 ProxyService::PacRequest* request2; 1351 rv = service->ResolveProxy( 1352 GURL("http://request2"), &info2, &callback2, &request2, BoundNetLog()); 1353 EXPECT_EQ(ERR_IO_PENDING, rv); 1354 1355 // Check that nothing has been sent to the proxy resolver yet. 1356 ASSERT_EQ(0u, resolver->pending_requests().size()); 1357 1358 // It should be trying to auto-detect first -- fail the download. 1359 EXPECT_TRUE(fetcher->has_pending_request()); 1360 EXPECT_EQ(GURL("http://wpad/wpad.dat"), fetcher->pending_request_url()); 1361 fetcher->NotifyFetchCompletion(ERR_FAILED, ""); 1362 1363 // Next it should be trying the custom PAC url -- fail the download. 1364 EXPECT_TRUE(fetcher->has_pending_request()); 1365 EXPECT_EQ(GURL("http://foopy/proxy.pac"), fetcher->pending_request_url()); 1366 fetcher->NotifyFetchCompletion(ERR_FAILED, ""); 1367 1368 // Since we never managed to initialize a ProxyResolver, nothing should have 1369 // been sent to it. 1370 ASSERT_EQ(0u, resolver->pending_requests().size()); 1371 1372 // Verify that requests ran as expected -- they should have fallen back to 1373 // the manual proxy configuration for HTTP urls. 1374 EXPECT_EQ(OK, callback1.WaitForResult()); 1375 EXPECT_EQ("foopy:80", info1.proxy_server().ToURI()); 1376 1377 EXPECT_EQ(OK, callback2.WaitForResult()); 1378 EXPECT_EQ("foopy:80", info2.proxy_server().ToURI()); 1379 } 1380 1381 // Test that the bypass rules are NOT applied when using autodetect. 1382 TEST(ProxyServiceTest, BypassDoesntApplyToPac) { 1383 ProxyConfig config; 1384 config.set_auto_detect(true); 1385 config.set_pac_url(GURL("http://foopy/proxy.pac")); 1386 config.proxy_rules().ParseFromString("http=foopy:80"); // Not used. 1387 config.proxy_rules().bypass_rules.ParseFromString("www.google.com"); 1388 1389 MockProxyConfigService* config_service = new MockProxyConfigService(config); 1390 MockAsyncProxyResolverExpectsBytes* resolver = 1391 new MockAsyncProxyResolverExpectsBytes; 1392 scoped_refptr<ProxyService> service( 1393 new ProxyService(config_service, resolver, NULL)); 1394 1395 MockProxyScriptFetcher* fetcher = new MockProxyScriptFetcher; 1396 service->SetProxyScriptFetcher(fetcher); 1397 1398 // Start 1 requests. 1399 1400 ProxyInfo info1; 1401 TestCompletionCallback callback1; 1402 int rv = service->ResolveProxy( 1403 GURL("http://www.google.com"), &info1, &callback1, NULL, BoundNetLog()); 1404 EXPECT_EQ(ERR_IO_PENDING, rv); 1405 1406 // Check that nothing has been sent to the proxy resolver yet. 1407 ASSERT_EQ(0u, resolver->pending_requests().size()); 1408 1409 // It should be trying to auto-detect first -- succeed the download. 1410 EXPECT_TRUE(fetcher->has_pending_request()); 1411 EXPECT_EQ(GURL("http://wpad/wpad.dat"), fetcher->pending_request_url()); 1412 fetcher->NotifyFetchCompletion(OK, "auto-detect"); 1413 1414 EXPECT_EQ(ASCIIToUTF16("auto-detect"), 1415 resolver->pending_set_pac_script_request()->script_data()->utf16()); 1416 resolver->pending_set_pac_script_request()->CompleteNow(OK); 1417 1418 ASSERT_EQ(1u, resolver->pending_requests().size()); 1419 EXPECT_EQ(GURL("http://www.google.com"), 1420 resolver->pending_requests()[0]->url()); 1421 1422 // Complete the pending request. 1423 resolver->pending_requests()[0]->results()->UseNamedProxy("request1:80"); 1424 resolver->pending_requests()[0]->CompleteNow(OK); 1425 1426 // Verify that request ran as expected. 1427 EXPECT_EQ(OK, callback1.WaitForResult()); 1428 EXPECT_EQ("request1:80", info1.proxy_server().ToURI()); 1429 1430 // Start another request, it should pickup the bypass item. 1431 ProxyInfo info2; 1432 TestCompletionCallback callback2; 1433 rv = service->ResolveProxy( 1434 GURL("http://www.google.com"), &info2, &callback2, NULL, BoundNetLog()); 1435 EXPECT_EQ(ERR_IO_PENDING, rv); 1436 1437 ASSERT_EQ(1u, resolver->pending_requests().size()); 1438 EXPECT_EQ(GURL("http://www.google.com"), 1439 resolver->pending_requests()[0]->url()); 1440 1441 // Complete the pending request. 1442 resolver->pending_requests()[0]->results()->UseNamedProxy("request2:80"); 1443 resolver->pending_requests()[0]->CompleteNow(OK); 1444 1445 EXPECT_EQ(OK, callback2.WaitForResult()); 1446 EXPECT_EQ("request2:80", info2.proxy_server().ToURI()); 1447 } 1448 1449 // Delete the ProxyService while InitProxyResolver has an outstanding 1450 // request to the script fetcher. When run under valgrind, should not 1451 // have any memory errors (used to be that the ProxyScriptFetcher was 1452 // being deleted prior to the InitProxyResolver). 1453 TEST(ProxyServiceTest, DeleteWhileInitProxyResolverHasOutstandingFetch) { 1454 ProxyConfig config = 1455 ProxyConfig::CreateFromCustomPacURL(GURL("http://foopy/proxy.pac")); 1456 1457 MockProxyConfigService* config_service = new MockProxyConfigService(config); 1458 MockAsyncProxyResolverExpectsBytes* resolver = 1459 new MockAsyncProxyResolverExpectsBytes; 1460 scoped_refptr<ProxyService> service( 1461 new ProxyService(config_service, resolver, NULL)); 1462 1463 MockProxyScriptFetcher* fetcher = new MockProxyScriptFetcher; 1464 service->SetProxyScriptFetcher(fetcher); 1465 1466 // Start 1 request. 1467 1468 ProxyInfo info1; 1469 TestCompletionCallback callback1; 1470 int rv = service->ResolveProxy( 1471 GURL("http://www.google.com"), &info1, &callback1, NULL, BoundNetLog()); 1472 EXPECT_EQ(ERR_IO_PENDING, rv); 1473 1474 // Check that nothing has been sent to the proxy resolver yet. 1475 ASSERT_EQ(0u, resolver->pending_requests().size()); 1476 1477 // InitProxyResolver should have issued a request to the ProxyScriptFetcher 1478 // and be waiting on that to complete. 1479 EXPECT_TRUE(fetcher->has_pending_request()); 1480 EXPECT_EQ(GURL("http://foopy/proxy.pac"), fetcher->pending_request_url()); 1481 1482 // Delete the ProxyService 1483 service = NULL; 1484 } 1485 1486 // Delete the ProxyService while InitProxyResolver has an outstanding 1487 // request to the proxy resolver. When run under valgrind, should not 1488 // have any memory errors (used to be that the ProxyResolver was 1489 // being deleted prior to the InitProxyResolver). 1490 TEST(ProxyServiceTest, DeleteWhileInitProxyResolverHasOutstandingSet) { 1491 MockProxyConfigService* config_service = 1492 new MockProxyConfigService("http://foopy/proxy.pac"); 1493 1494 MockAsyncProxyResolver* resolver = new MockAsyncProxyResolver; 1495 1496 scoped_refptr<ProxyService> service( 1497 new ProxyService(config_service, resolver, NULL)); 1498 1499 GURL url("http://www.google.com/"); 1500 1501 ProxyInfo info; 1502 TestCompletionCallback callback; 1503 int rv = service->ResolveProxy(url, &info, &callback, NULL, BoundNetLog()); 1504 EXPECT_EQ(ERR_IO_PENDING, rv); 1505 1506 EXPECT_EQ(GURL("http://foopy/proxy.pac"), 1507 resolver->pending_set_pac_script_request()->script_data()->url()); 1508 1509 // Delete the ProxyService. 1510 service = NULL; 1511 } 1512 1513 TEST(ProxyServiceTest, ResetProxyConfigService) { 1514 ProxyConfig config1; 1515 config1.proxy_rules().ParseFromString("foopy1:8080"); 1516 config1.set_auto_detect(false); 1517 scoped_refptr<ProxyService> service(new ProxyService( 1518 new MockProxyConfigService(config1), 1519 new MockAsyncProxyResolverExpectsBytes, NULL)); 1520 1521 ProxyInfo info; 1522 TestCompletionCallback callback1; 1523 int rv = service->ResolveProxy( 1524 GURL("http://request1"), &info, &callback1, NULL, BoundNetLog()); 1525 EXPECT_EQ(OK, rv); 1526 EXPECT_EQ("foopy1:8080", info.proxy_server().ToURI()); 1527 1528 ProxyConfig config2; 1529 config2.proxy_rules().ParseFromString("foopy2:8080"); 1530 config2.set_auto_detect(false); 1531 service->ResetConfigService(new MockProxyConfigService(config2)); 1532 TestCompletionCallback callback2; 1533 rv = service->ResolveProxy( 1534 GURL("http://request2"), &info, &callback2, NULL, BoundNetLog()); 1535 EXPECT_EQ(OK, rv); 1536 EXPECT_EQ("foopy2:8080", info.proxy_server().ToURI()); 1537 } 1538 1539 // Test that when going from a configuration that required PAC to one 1540 // that does NOT, we unset the variable |should_use_proxy_resolver_|. 1541 TEST(ProxyServiceTest, UpdateConfigFromPACToDirect) { 1542 ProxyConfig config = ProxyConfig::CreateAutoDetect(); 1543 1544 MockProxyConfigService* config_service = new MockProxyConfigService(config); 1545 MockAsyncProxyResolver* resolver = new MockAsyncProxyResolver; 1546 scoped_refptr<ProxyService> service( 1547 new ProxyService(config_service, resolver, NULL)); 1548 1549 // Start 1 request. 1550 1551 ProxyInfo info1; 1552 TestCompletionCallback callback1; 1553 int rv = service->ResolveProxy( 1554 GURL("http://www.google.com"), &info1, &callback1, NULL, BoundNetLog()); 1555 EXPECT_EQ(ERR_IO_PENDING, rv); 1556 1557 // Check that nothing has been sent to the proxy resolver yet. 1558 ASSERT_EQ(0u, resolver->pending_requests().size()); 1559 1560 // Successfully set the autodetect script. 1561 EXPECT_EQ(ProxyResolverScriptData::TYPE_AUTO_DETECT, 1562 resolver->pending_set_pac_script_request()->script_data()->type()); 1563 resolver->pending_set_pac_script_request()->CompleteNow(OK); 1564 1565 // Complete the pending request. 1566 ASSERT_EQ(1u, resolver->pending_requests().size()); 1567 resolver->pending_requests()[0]->results()->UseNamedProxy("request1:80"); 1568 resolver->pending_requests()[0]->CompleteNow(OK); 1569 1570 // Verify that request ran as expected. 1571 EXPECT_EQ(OK, callback1.WaitForResult()); 1572 EXPECT_EQ("request1:80", info1.proxy_server().ToURI()); 1573 1574 // Force the ProxyService to pull down a new proxy configuration. 1575 // (Even though the configuration isn't old/bad). 1576 // 1577 // This new configuration no longer has auto_detect set, so 1578 // requests should complete synchronously now as direct-connect. 1579 config_service->SetConfig(ProxyConfig::CreateDirect()); 1580 1581 // Start another request -- the effective configuration has changed. 1582 ProxyInfo info2; 1583 TestCompletionCallback callback2; 1584 rv = service->ResolveProxy( 1585 GURL("http://www.google.com"), &info2, &callback2, NULL, BoundNetLog()); 1586 EXPECT_EQ(OK, rv); 1587 1588 EXPECT_TRUE(info2.is_direct()); 1589 } 1590 1591 TEST(ProxyServiceTest, NetworkChangeTriggersPacRefetch) { 1592 MockProxyConfigService* config_service = 1593 new MockProxyConfigService("http://foopy/proxy.pac"); 1594 1595 MockAsyncProxyResolverExpectsBytes* resolver = 1596 new MockAsyncProxyResolverExpectsBytes; 1597 1598 CapturingNetLog log(CapturingNetLog::kUnbounded); 1599 1600 scoped_refptr<ProxyService> service( 1601 new ProxyService(config_service, resolver, &log)); 1602 1603 MockProxyScriptFetcher* fetcher = new MockProxyScriptFetcher; 1604 service->SetProxyScriptFetcher(fetcher); 1605 1606 // Disable the "wait after IP address changes" hack, so this unit-test can 1607 // complete quickly. 1608 service->set_stall_proxy_auto_config_delay(base::TimeDelta()); 1609 1610 // Start 1 request. 1611 1612 ProxyInfo info1; 1613 TestCompletionCallback callback1; 1614 int rv = service->ResolveProxy( 1615 GURL("http://request1"), &info1, &callback1, NULL, BoundNetLog()); 1616 EXPECT_EQ(ERR_IO_PENDING, rv); 1617 1618 // The first request should have triggered initial download of PAC script. 1619 EXPECT_TRUE(fetcher->has_pending_request()); 1620 EXPECT_EQ(GURL("http://foopy/proxy.pac"), fetcher->pending_request_url()); 1621 1622 // Nothing has been sent to the resolver yet. 1623 EXPECT_TRUE(resolver->pending_requests().empty()); 1624 1625 // At this point the ProxyService should be waiting for the 1626 // ProxyScriptFetcher to invoke its completion callback, notifying it of 1627 // PAC script download completion. 1628 fetcher->NotifyFetchCompletion(OK, "pac-v1"); 1629 1630 // Now that the PAC script is downloaded, the request will have been sent to 1631 // the proxy resolver. 1632 EXPECT_EQ(ASCIIToUTF16("pac-v1"), 1633 resolver->pending_set_pac_script_request()->script_data()->utf16()); 1634 resolver->pending_set_pac_script_request()->CompleteNow(OK); 1635 1636 ASSERT_EQ(1u, resolver->pending_requests().size()); 1637 EXPECT_EQ(GURL("http://request1"), resolver->pending_requests()[0]->url()); 1638 1639 // Complete the pending request. 1640 resolver->pending_requests()[0]->results()->UseNamedProxy("request1:80"); 1641 resolver->pending_requests()[0]->CompleteNow(OK); 1642 1643 // Wait for completion callback, and verify that the request ran as expected. 1644 EXPECT_EQ(OK, callback1.WaitForResult()); 1645 EXPECT_EQ("request1:80", info1.proxy_server().ToURI()); 1646 1647 // Now simluate a change in the network. The ProxyConfigService is still 1648 // going to return the same PAC URL as before, but this URL needs to be 1649 // refetched on the new network. 1650 NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests(); 1651 MessageLoop::current()->RunAllPending(); // Notification happens async. 1652 1653 // Start a second request. 1654 ProxyInfo info2; 1655 TestCompletionCallback callback2; 1656 rv = service->ResolveProxy( 1657 GURL("http://request2"), &info2, &callback2, NULL, BoundNetLog()); 1658 EXPECT_EQ(ERR_IO_PENDING, rv); 1659 1660 // This second request should have triggered the re-download of the PAC 1661 // script (since we marked the network as having changed). 1662 EXPECT_TRUE(fetcher->has_pending_request()); 1663 EXPECT_EQ(GURL("http://foopy/proxy.pac"), fetcher->pending_request_url()); 1664 1665 // Nothing has been sent to the resolver yet. 1666 EXPECT_TRUE(resolver->pending_requests().empty()); 1667 1668 // Simulate the PAC script fetch as having completed (this time with 1669 // different data). 1670 fetcher->NotifyFetchCompletion(OK, "pac-v2"); 1671 1672 // Now that the PAC script is downloaded, the second request will have been 1673 // sent to the proxy resolver. 1674 EXPECT_EQ(ASCIIToUTF16("pac-v2"), 1675 resolver->pending_set_pac_script_request()->script_data()->utf16()); 1676 resolver->pending_set_pac_script_request()->CompleteNow(OK); 1677 1678 ASSERT_EQ(1u, resolver->pending_requests().size()); 1679 EXPECT_EQ(GURL("http://request2"), resolver->pending_requests()[0]->url()); 1680 1681 // Complete the pending second request. 1682 resolver->pending_requests()[0]->results()->UseNamedProxy("request2:80"); 1683 resolver->pending_requests()[0]->CompleteNow(OK); 1684 1685 // Wait for completion callback, and verify that the request ran as expected. 1686 EXPECT_EQ(OK, callback2.WaitForResult()); 1687 EXPECT_EQ("request2:80", info2.proxy_server().ToURI()); 1688 1689 // Check that the expected events were outputted to the log stream. 1690 // In particular, PROXY_CONFIG_CHANGED should have only been emitted once 1691 // (for the initial setup), and NOT a second time when the IP address 1692 // changed. 1693 CapturingNetLog::EntryList entries; 1694 log.GetEntries(&entries); 1695 1696 EXPECT_TRUE(LogContainsEntryWithType(entries, 0, 1697 NetLog::TYPE_PROXY_CONFIG_CHANGED)); 1698 ASSERT_EQ(13u, entries.size()); 1699 for (size_t i = 1; i < entries.size(); ++i) 1700 EXPECT_NE(NetLog::TYPE_PROXY_CONFIG_CHANGED, entries[i].type); 1701 } 1702 1703 } // namespace net 1704