proxy_script_decider_unittest.cc revision d0247b1b59f9c528cb6df88b4f2b9afaf80d181e
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 <vector> 6 7#include "base/bind.h" 8#include "base/memory/weak_ptr.h" 9#include "base/message_loop/message_loop.h" 10#include "base/run_loop.h" 11#include "base/strings/string_util.h" 12#include "base/strings/utf_string_conversions.h" 13#include "base/time/time.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/dns/mock_host_resolver.h" 19#include "net/proxy/dhcp_proxy_script_fetcher.h" 20#include "net/proxy/proxy_config.h" 21#include "net/proxy/proxy_resolver.h" 22#include "net/proxy/proxy_script_decider.h" 23#include "net/proxy/proxy_script_fetcher.h" 24#include "net/url_request/url_request_context.h" 25#include "testing/gtest/include/gtest/gtest.h" 26 27namespace net { 28namespace { 29 30enum Error { 31 kFailedDownloading = -100, 32 kFailedParsing = ERR_PAC_SCRIPT_FAILED, 33}; 34 35class Rules { 36 public: 37 struct Rule { 38 Rule(const GURL& url, int fetch_error, bool is_valid_script) 39 : url(url), 40 fetch_error(fetch_error), 41 is_valid_script(is_valid_script) { 42 } 43 44 base::string16 text() const { 45 if (is_valid_script) 46 return UTF8ToUTF16(url.spec() + "!FindProxyForURL"); 47 if (fetch_error == OK) 48 return UTF8ToUTF16(url.spec() + "!invalid-script"); 49 return base::string16(); 50 } 51 52 GURL url; 53 int fetch_error; 54 bool is_valid_script; 55 }; 56 57 Rule AddSuccessRule(const char* url) { 58 Rule rule(GURL(url), OK /*fetch_error*/, true); 59 rules_.push_back(rule); 60 return rule; 61 } 62 63 void AddFailDownloadRule(const char* url) { 64 rules_.push_back(Rule(GURL(url), kFailedDownloading /*fetch_error*/, 65 false)); 66 } 67 68 void AddFailParsingRule(const char* url) { 69 rules_.push_back(Rule(GURL(url), OK /*fetch_error*/, false)); 70 } 71 72 const Rule& GetRuleByUrl(const GURL& url) const { 73 for (RuleList::const_iterator it = rules_.begin(); it != rules_.end(); 74 ++it) { 75 if (it->url == url) 76 return *it; 77 } 78 LOG(FATAL) << "Rule not found for " << url; 79 return rules_[0]; 80 } 81 82 const Rule& GetRuleByText(const base::string16& text) const { 83 for (RuleList::const_iterator it = rules_.begin(); it != rules_.end(); 84 ++it) { 85 if (it->text() == text) 86 return *it; 87 } 88 LOG(FATAL) << "Rule not found for " << text; 89 return rules_[0]; 90 } 91 92 private: 93 typedef std::vector<Rule> RuleList; 94 RuleList rules_; 95}; 96 97class RuleBasedProxyScriptFetcher : public ProxyScriptFetcher { 98 public: 99 explicit RuleBasedProxyScriptFetcher(const Rules* rules) 100 : rules_(rules), request_context_(NULL) {} 101 102 virtual void SetRequestContext(URLRequestContext* context) { 103 request_context_ = context; 104 } 105 106 // ProxyScriptFetcher implementation. 107 virtual int Fetch(const GURL& url, 108 base::string16* text, 109 const CompletionCallback& callback) OVERRIDE { 110 const Rules::Rule& rule = rules_->GetRuleByUrl(url); 111 int rv = rule.fetch_error; 112 EXPECT_NE(ERR_UNEXPECTED, rv); 113 if (rv == OK) 114 *text = rule.text(); 115 return rv; 116 } 117 118 virtual void Cancel() OVERRIDE {} 119 120 virtual URLRequestContext* GetRequestContext() const OVERRIDE { 121 return request_context_; 122 } 123 124 private: 125 const Rules* rules_; 126 URLRequestContext* request_context_; 127}; 128 129// Succeed using custom PAC script. 130TEST(ProxyScriptDeciderTest, CustomPacSucceeds) { 131 Rules rules; 132 RuleBasedProxyScriptFetcher fetcher(&rules); 133 DoNothingDhcpProxyScriptFetcher dhcp_fetcher; 134 135 ProxyConfig config; 136 config.set_pac_url(GURL("http://custom/proxy.pac")); 137 138 Rules::Rule rule = rules.AddSuccessRule("http://custom/proxy.pac"); 139 140 TestCompletionCallback callback; 141 CapturingNetLog log; 142 ProxyScriptDecider decider(&fetcher, &dhcp_fetcher, &log); 143 EXPECT_EQ(OK, decider.Start( 144 config, base::TimeDelta(), true, callback.callback())); 145 EXPECT_EQ(rule.text(), decider.script_data()->utf16()); 146 147 // Check the NetLog was filled correctly. 148 CapturingNetLog::CapturedEntryList entries; 149 log.GetEntries(&entries); 150 151 EXPECT_EQ(4u, entries.size()); 152 EXPECT_TRUE(LogContainsBeginEvent( 153 entries, 0, NetLog::TYPE_PROXY_SCRIPT_DECIDER)); 154 EXPECT_TRUE(LogContainsBeginEvent( 155 entries, 1, NetLog::TYPE_PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT)); 156 EXPECT_TRUE(LogContainsEndEvent( 157 entries, 2, NetLog::TYPE_PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT)); 158 EXPECT_TRUE(LogContainsEndEvent( 159 entries, 3, NetLog::TYPE_PROXY_SCRIPT_DECIDER)); 160 161 EXPECT_TRUE(decider.effective_config().has_pac_url()); 162 EXPECT_EQ(config.pac_url(), decider.effective_config().pac_url()); 163} 164 165// Fail downloading the custom PAC script. 166TEST(ProxyScriptDeciderTest, CustomPacFails1) { 167 Rules rules; 168 RuleBasedProxyScriptFetcher fetcher(&rules); 169 DoNothingDhcpProxyScriptFetcher dhcp_fetcher; 170 171 ProxyConfig config; 172 config.set_pac_url(GURL("http://custom/proxy.pac")); 173 174 rules.AddFailDownloadRule("http://custom/proxy.pac"); 175 176 TestCompletionCallback callback; 177 CapturingNetLog log; 178 ProxyScriptDecider decider(&fetcher, &dhcp_fetcher, &log); 179 EXPECT_EQ(kFailedDownloading, 180 decider.Start(config, base::TimeDelta(), true, 181 callback.callback())); 182 EXPECT_EQ(NULL, decider.script_data()); 183 184 // Check the NetLog was filled correctly. 185 CapturingNetLog::CapturedEntryList entries; 186 log.GetEntries(&entries); 187 188 EXPECT_EQ(4u, entries.size()); 189 EXPECT_TRUE(LogContainsBeginEvent( 190 entries, 0, NetLog::TYPE_PROXY_SCRIPT_DECIDER)); 191 EXPECT_TRUE(LogContainsBeginEvent( 192 entries, 1, NetLog::TYPE_PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT)); 193 EXPECT_TRUE(LogContainsEndEvent( 194 entries, 2, NetLog::TYPE_PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT)); 195 EXPECT_TRUE(LogContainsEndEvent( 196 entries, 3, NetLog::TYPE_PROXY_SCRIPT_DECIDER)); 197 198 EXPECT_FALSE(decider.effective_config().has_pac_url()); 199} 200 201// Fail parsing the custom PAC script. 202TEST(ProxyScriptDeciderTest, CustomPacFails2) { 203 Rules rules; 204 RuleBasedProxyScriptFetcher fetcher(&rules); 205 DoNothingDhcpProxyScriptFetcher dhcp_fetcher; 206 207 ProxyConfig config; 208 config.set_pac_url(GURL("http://custom/proxy.pac")); 209 210 rules.AddFailParsingRule("http://custom/proxy.pac"); 211 212 TestCompletionCallback callback; 213 ProxyScriptDecider decider(&fetcher, &dhcp_fetcher, NULL); 214 EXPECT_EQ(kFailedParsing, 215 decider.Start(config, base::TimeDelta(), true, 216 callback.callback())); 217 EXPECT_EQ(NULL, decider.script_data()); 218} 219 220// Fail downloading the custom PAC script, because the fetcher was NULL. 221TEST(ProxyScriptDeciderTest, HasNullProxyScriptFetcher) { 222 Rules rules; 223 DoNothingDhcpProxyScriptFetcher dhcp_fetcher; 224 225 ProxyConfig config; 226 config.set_pac_url(GURL("http://custom/proxy.pac")); 227 228 TestCompletionCallback callback; 229 ProxyScriptDecider decider(NULL, &dhcp_fetcher, NULL); 230 EXPECT_EQ(ERR_UNEXPECTED, 231 decider.Start(config, base::TimeDelta(), true, 232 callback.callback())); 233 EXPECT_EQ(NULL, decider.script_data()); 234} 235 236// Succeeds in choosing autodetect (WPAD DNS). 237TEST(ProxyScriptDeciderTest, AutodetectSuccess) { 238 Rules rules; 239 RuleBasedProxyScriptFetcher fetcher(&rules); 240 DoNothingDhcpProxyScriptFetcher dhcp_fetcher; 241 242 ProxyConfig config; 243 config.set_auto_detect(true); 244 245 Rules::Rule rule = rules.AddSuccessRule("http://wpad/wpad.dat"); 246 247 TestCompletionCallback callback; 248 ProxyScriptDecider decider(&fetcher, &dhcp_fetcher, NULL); 249 EXPECT_EQ(OK, decider.Start( 250 config, base::TimeDelta(), true, callback.callback())); 251 EXPECT_EQ(rule.text(), decider.script_data()->utf16()); 252 253 EXPECT_TRUE(decider.effective_config().has_pac_url()); 254 EXPECT_EQ(rule.url, decider.effective_config().pac_url()); 255} 256 257class ProxyScriptDeciderQuickCheckTest : public ::testing::Test { 258 public: 259 ProxyScriptDeciderQuickCheckTest() 260 : rule_(rules_.AddSuccessRule("http://wpad/wpad.dat")), 261 fetcher_(&rules_) { } 262 263 virtual void SetUp() OVERRIDE { 264 request_context_.set_host_resolver(&resolver_); 265 fetcher_.SetRequestContext(&request_context_); 266 config_.set_auto_detect(true); 267 decider_.reset(new ProxyScriptDecider(&fetcher_, &dhcp_fetcher_, NULL)); 268 } 269 270 int StartDecider() { 271 return decider_->Start(config_, base::TimeDelta(), true, 272 callback_.callback()); 273 } 274 275 protected: 276 scoped_ptr<ProxyScriptDecider> decider_; 277 MockHostResolver resolver_; 278 Rules rules_; 279 Rules::Rule rule_; 280 TestCompletionCallback callback_; 281 282 private: 283 URLRequestContext request_context_; 284 285 RuleBasedProxyScriptFetcher fetcher_; 286 DoNothingDhcpProxyScriptFetcher dhcp_fetcher_; 287 288 ProxyConfig config_; 289}; 290 291// Fails if a synchronous DNS lookup success for wpad causes QuickCheck to fail. 292TEST_F(ProxyScriptDeciderQuickCheckTest, SyncSuccess) { 293 resolver_.set_synchronous_mode(true); 294 resolver_.rules()->AddRule("wpad", "1.2.3.4"); 295 296 EXPECT_EQ(OK, StartDecider()); 297 EXPECT_EQ(rule_.text(), decider_->script_data()->utf16()); 298 299 EXPECT_TRUE(decider_->effective_config().has_pac_url()); 300 EXPECT_EQ(rule_.url, decider_->effective_config().pac_url()); 301} 302 303// Fails if an asynchronous DNS lookup success for wpad causes QuickCheck to 304// fail. 305TEST_F(ProxyScriptDeciderQuickCheckTest, AsyncSuccess) { 306 resolver_.set_ondemand_mode(true); 307 resolver_.rules()->AddRule("wpad", "1.2.3.4"); 308 309 EXPECT_EQ(ERR_IO_PENDING, StartDecider()); 310 ASSERT_TRUE(resolver_.has_pending_requests()); 311 resolver_.ResolveAllPending(); 312 callback_.WaitForResult(); 313 EXPECT_FALSE(resolver_.has_pending_requests()); 314 EXPECT_EQ(rule_.text(), decider_->script_data()->utf16()); 315 EXPECT_TRUE(decider_->effective_config().has_pac_url()); 316 EXPECT_EQ(rule_.url, decider_->effective_config().pac_url()); 317} 318 319// Fails if an asynchronous DNS lookup failure (i.e. an NXDOMAIN) still causes 320// ProxyScriptDecider to yield a PAC URL. 321TEST_F(ProxyScriptDeciderQuickCheckTest, AsyncFail) { 322 resolver_.set_ondemand_mode(true); 323 resolver_.rules()->AddSimulatedFailure("wpad"); 324 EXPECT_EQ(ERR_IO_PENDING, StartDecider()); 325 ASSERT_TRUE(resolver_.has_pending_requests()); 326 resolver_.ResolveAllPending(); 327 callback_.WaitForResult(); 328 EXPECT_FALSE(decider_->effective_config().has_pac_url()); 329} 330 331// Fails if a DNS lookup timeout either causes ProxyScriptDecider to yield a PAC 332// URL or causes ProxyScriptDecider not to cancel its pending resolution. 333TEST_F(ProxyScriptDeciderQuickCheckTest, AsyncTimeout) { 334 resolver_.set_ondemand_mode(true); 335 EXPECT_EQ(ERR_IO_PENDING, StartDecider()); 336 ASSERT_TRUE(resolver_.has_pending_requests()); 337 callback_.WaitForResult(); 338 EXPECT_FALSE(resolver_.has_pending_requests()); 339 EXPECT_FALSE(decider_->effective_config().has_pac_url()); 340} 341 342// Fails at WPAD (downloading), but succeeds in choosing the custom PAC. 343TEST(ProxyScriptDeciderTest, AutodetectFailCustomSuccess1) { 344 Rules rules; 345 RuleBasedProxyScriptFetcher fetcher(&rules); 346 DoNothingDhcpProxyScriptFetcher dhcp_fetcher; 347 348 ProxyConfig config; 349 config.set_auto_detect(true); 350 config.set_pac_url(GURL("http://custom/proxy.pac")); 351 352 rules.AddFailDownloadRule("http://wpad/wpad.dat"); 353 Rules::Rule rule = rules.AddSuccessRule("http://custom/proxy.pac"); 354 355 TestCompletionCallback callback; 356 ProxyScriptDecider decider(&fetcher, &dhcp_fetcher, NULL); 357 EXPECT_EQ(OK, decider.Start( 358 config, base::TimeDelta(), true, callback.callback())); 359 EXPECT_EQ(rule.text(), decider.script_data()->utf16()); 360 361 EXPECT_TRUE(decider.effective_config().has_pac_url()); 362 EXPECT_EQ(rule.url, decider.effective_config().pac_url()); 363} 364 365// Fails at WPAD (no DHCP config, DNS PAC fails parsing), but succeeds in 366// choosing the custom PAC. 367TEST(ProxyScriptDeciderTest, AutodetectFailCustomSuccess2) { 368 Rules rules; 369 RuleBasedProxyScriptFetcher fetcher(&rules); 370 DoNothingDhcpProxyScriptFetcher dhcp_fetcher; 371 372 ProxyConfig config; 373 config.set_auto_detect(true); 374 config.set_pac_url(GURL("http://custom/proxy.pac")); 375 config.proxy_rules().ParseFromString("unused-manual-proxy:99"); 376 377 rules.AddFailParsingRule("http://wpad/wpad.dat"); 378 Rules::Rule rule = rules.AddSuccessRule("http://custom/proxy.pac"); 379 380 TestCompletionCallback callback; 381 CapturingNetLog log; 382 383 ProxyScriptDecider decider(&fetcher, &dhcp_fetcher, &log); 384 EXPECT_EQ(OK, decider.Start(config, base::TimeDelta(), 385 true, callback.callback())); 386 EXPECT_EQ(rule.text(), decider.script_data()->utf16()); 387 388 // Verify that the effective configuration no longer contains auto detect or 389 // any of the manual settings. 390 EXPECT_TRUE(decider.effective_config().Equals( 391 ProxyConfig::CreateFromCustomPacURL(GURL("http://custom/proxy.pac")))); 392 393 // Check the NetLog was filled correctly. 394 // (Note that various states are repeated since both WPAD and custom 395 // PAC scripts are tried). 396 CapturingNetLog::CapturedEntryList entries; 397 log.GetEntries(&entries); 398 399 EXPECT_EQ(10u, entries.size()); 400 EXPECT_TRUE(LogContainsBeginEvent( 401 entries, 0, NetLog::TYPE_PROXY_SCRIPT_DECIDER)); 402 // This is the DHCP phase, which fails fetching rather than parsing, so 403 // there is no pair of SET_PAC_SCRIPT events. 404 EXPECT_TRUE(LogContainsBeginEvent( 405 entries, 1, NetLog::TYPE_PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT)); 406 EXPECT_TRUE(LogContainsEndEvent( 407 entries, 2, NetLog::TYPE_PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT)); 408 EXPECT_TRUE(LogContainsEvent( 409 entries, 3, 410 NetLog::TYPE_PROXY_SCRIPT_DECIDER_FALLING_BACK_TO_NEXT_PAC_SOURCE, 411 NetLog::PHASE_NONE)); 412 // This is the DNS phase, which attempts a fetch but fails. 413 EXPECT_TRUE(LogContainsBeginEvent( 414 entries, 4, NetLog::TYPE_PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT)); 415 EXPECT_TRUE(LogContainsEndEvent( 416 entries, 5, NetLog::TYPE_PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT)); 417 EXPECT_TRUE(LogContainsEvent( 418 entries, 6, 419 NetLog::TYPE_PROXY_SCRIPT_DECIDER_FALLING_BACK_TO_NEXT_PAC_SOURCE, 420 NetLog::PHASE_NONE)); 421 // Finally, the custom PAC URL phase. 422 EXPECT_TRUE(LogContainsBeginEvent( 423 entries, 7, NetLog::TYPE_PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT)); 424 EXPECT_TRUE(LogContainsEndEvent( 425 entries, 8, NetLog::TYPE_PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT)); 426 EXPECT_TRUE(LogContainsEndEvent( 427 entries, 9, NetLog::TYPE_PROXY_SCRIPT_DECIDER)); 428} 429 430// Fails at WPAD (downloading), and fails at custom PAC (downloading). 431TEST(ProxyScriptDeciderTest, AutodetectFailCustomFails1) { 432 Rules rules; 433 RuleBasedProxyScriptFetcher fetcher(&rules); 434 DoNothingDhcpProxyScriptFetcher dhcp_fetcher; 435 436 ProxyConfig config; 437 config.set_auto_detect(true); 438 config.set_pac_url(GURL("http://custom/proxy.pac")); 439 440 rules.AddFailDownloadRule("http://wpad/wpad.dat"); 441 rules.AddFailDownloadRule("http://custom/proxy.pac"); 442 443 TestCompletionCallback callback; 444 ProxyScriptDecider decider(&fetcher, &dhcp_fetcher, NULL); 445 EXPECT_EQ(kFailedDownloading, 446 decider.Start(config, base::TimeDelta(), true, 447 callback.callback())); 448 EXPECT_EQ(NULL, decider.script_data()); 449} 450 451// Fails at WPAD (downloading), and fails at custom PAC (parsing). 452TEST(ProxyScriptDeciderTest, AutodetectFailCustomFails2) { 453 Rules rules; 454 RuleBasedProxyScriptFetcher fetcher(&rules); 455 DoNothingDhcpProxyScriptFetcher dhcp_fetcher; 456 457 ProxyConfig config; 458 config.set_auto_detect(true); 459 config.set_pac_url(GURL("http://custom/proxy.pac")); 460 461 rules.AddFailDownloadRule("http://wpad/wpad.dat"); 462 rules.AddFailParsingRule("http://custom/proxy.pac"); 463 464 TestCompletionCallback callback; 465 ProxyScriptDecider decider(&fetcher, &dhcp_fetcher, NULL); 466 EXPECT_EQ(kFailedParsing, 467 decider.Start(config, base::TimeDelta(), true, 468 callback.callback())); 469 EXPECT_EQ(NULL, decider.script_data()); 470} 471 472// This is a copy-paste of CustomPacFails1, with the exception that we give it 473// a 1 millisecond delay. This means it will now complete asynchronously. 474// Moreover, we test the NetLog to make sure it logged the pause. 475TEST(ProxyScriptDeciderTest, CustomPacFails1_WithPositiveDelay) { 476 Rules rules; 477 RuleBasedProxyScriptFetcher fetcher(&rules); 478 DoNothingDhcpProxyScriptFetcher dhcp_fetcher; 479 480 ProxyConfig config; 481 config.set_pac_url(GURL("http://custom/proxy.pac")); 482 483 rules.AddFailDownloadRule("http://custom/proxy.pac"); 484 485 TestCompletionCallback callback; 486 CapturingNetLog log; 487 ProxyScriptDecider decider(&fetcher, &dhcp_fetcher, &log); 488 EXPECT_EQ(ERR_IO_PENDING, 489 decider.Start(config, base::TimeDelta::FromMilliseconds(1), 490 true, callback.callback())); 491 492 EXPECT_EQ(kFailedDownloading, callback.WaitForResult()); 493 EXPECT_EQ(NULL, decider.script_data()); 494 495 // Check the NetLog was filled correctly. 496 CapturingNetLog::CapturedEntryList entries; 497 log.GetEntries(&entries); 498 499 EXPECT_EQ(6u, entries.size()); 500 EXPECT_TRUE(LogContainsBeginEvent( 501 entries, 0, NetLog::TYPE_PROXY_SCRIPT_DECIDER)); 502 EXPECT_TRUE(LogContainsBeginEvent( 503 entries, 1, NetLog::TYPE_PROXY_SCRIPT_DECIDER_WAIT)); 504 EXPECT_TRUE(LogContainsEndEvent( 505 entries, 2, NetLog::TYPE_PROXY_SCRIPT_DECIDER_WAIT)); 506 EXPECT_TRUE(LogContainsBeginEvent( 507 entries, 3, NetLog::TYPE_PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT)); 508 EXPECT_TRUE(LogContainsEndEvent( 509 entries, 4, NetLog::TYPE_PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT)); 510 EXPECT_TRUE(LogContainsEndEvent( 511 entries, 5, NetLog::TYPE_PROXY_SCRIPT_DECIDER)); 512} 513 514// This is a copy-paste of CustomPacFails1, with the exception that we give it 515// a -5 second delay instead of a 0 ms delay. This change should have no effect 516// so the rest of the test is unchanged. 517TEST(ProxyScriptDeciderTest, CustomPacFails1_WithNegativeDelay) { 518 Rules rules; 519 RuleBasedProxyScriptFetcher fetcher(&rules); 520 DoNothingDhcpProxyScriptFetcher dhcp_fetcher; 521 522 ProxyConfig config; 523 config.set_pac_url(GURL("http://custom/proxy.pac")); 524 525 rules.AddFailDownloadRule("http://custom/proxy.pac"); 526 527 TestCompletionCallback callback; 528 CapturingNetLog log; 529 ProxyScriptDecider decider(&fetcher, &dhcp_fetcher, &log); 530 EXPECT_EQ(kFailedDownloading, 531 decider.Start(config, base::TimeDelta::FromSeconds(-5), 532 true, callback.callback())); 533 EXPECT_EQ(NULL, decider.script_data()); 534 535 // Check the NetLog was filled correctly. 536 CapturingNetLog::CapturedEntryList entries; 537 log.GetEntries(&entries); 538 539 EXPECT_EQ(4u, entries.size()); 540 EXPECT_TRUE(LogContainsBeginEvent( 541 entries, 0, NetLog::TYPE_PROXY_SCRIPT_DECIDER)); 542 EXPECT_TRUE(LogContainsBeginEvent( 543 entries, 1, NetLog::TYPE_PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT)); 544 EXPECT_TRUE(LogContainsEndEvent( 545 entries, 2, NetLog::TYPE_PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT)); 546 EXPECT_TRUE(LogContainsEndEvent( 547 entries, 3, NetLog::TYPE_PROXY_SCRIPT_DECIDER)); 548} 549 550class SynchronousSuccessDhcpFetcher : public DhcpProxyScriptFetcher { 551 public: 552 explicit SynchronousSuccessDhcpFetcher(const base::string16& expected_text) 553 : gurl_("http://dhcppac/"), expected_text_(expected_text) { 554 } 555 556 virtual int Fetch(base::string16* utf16_text, 557 const CompletionCallback& callback) OVERRIDE { 558 *utf16_text = expected_text_; 559 return OK; 560 } 561 562 virtual void Cancel() OVERRIDE { 563 } 564 565 virtual const GURL& GetPacURL() const OVERRIDE { 566 return gurl_; 567 } 568 569 const base::string16& expected_text() const { 570 return expected_text_; 571 } 572 573 private: 574 GURL gurl_; 575 base::string16 expected_text_; 576 577 DISALLOW_COPY_AND_ASSIGN(SynchronousSuccessDhcpFetcher); 578}; 579 580// All of the tests above that use ProxyScriptDecider have tested 581// failure to fetch a PAC file via DHCP configuration, so we now test 582// success at downloading and parsing, and then success at downloading, 583// failure at parsing. 584 585TEST(ProxyScriptDeciderTest, AutodetectDhcpSuccess) { 586 Rules rules; 587 RuleBasedProxyScriptFetcher fetcher(&rules); 588 SynchronousSuccessDhcpFetcher dhcp_fetcher( 589 WideToUTF16(L"http://bingo/!FindProxyForURL")); 590 591 ProxyConfig config; 592 config.set_auto_detect(true); 593 594 rules.AddSuccessRule("http://bingo/"); 595 rules.AddFailDownloadRule("http://wpad/wpad.dat"); 596 597 TestCompletionCallback callback; 598 ProxyScriptDecider decider(&fetcher, &dhcp_fetcher, NULL); 599 EXPECT_EQ(OK, decider.Start( 600 config, base::TimeDelta(), true, callback.callback())); 601 EXPECT_EQ(dhcp_fetcher.expected_text(), 602 decider.script_data()->utf16()); 603 604 EXPECT_TRUE(decider.effective_config().has_pac_url()); 605 EXPECT_EQ(GURL("http://dhcppac/"), decider.effective_config().pac_url()); 606} 607 608TEST(ProxyScriptDeciderTest, AutodetectDhcpFailParse) { 609 Rules rules; 610 RuleBasedProxyScriptFetcher fetcher(&rules); 611 SynchronousSuccessDhcpFetcher dhcp_fetcher( 612 WideToUTF16(L"http://bingo/!invalid-script")); 613 614 ProxyConfig config; 615 config.set_auto_detect(true); 616 617 rules.AddFailParsingRule("http://bingo/"); 618 rules.AddFailDownloadRule("http://wpad/wpad.dat"); 619 620 TestCompletionCallback callback; 621 ProxyScriptDecider decider(&fetcher, &dhcp_fetcher, NULL); 622 // Since there is fallback to DNS-based WPAD, the final error will be that 623 // it failed downloading, not that it failed parsing. 624 EXPECT_EQ(kFailedDownloading, 625 decider.Start(config, base::TimeDelta(), true, callback.callback())); 626 EXPECT_EQ(NULL, decider.script_data()); 627 628 EXPECT_FALSE(decider.effective_config().has_pac_url()); 629} 630 631class AsyncFailDhcpFetcher 632 : public DhcpProxyScriptFetcher, 633 public base::SupportsWeakPtr<AsyncFailDhcpFetcher> { 634 public: 635 AsyncFailDhcpFetcher() {} 636 virtual ~AsyncFailDhcpFetcher() {} 637 638 virtual int Fetch(base::string16* utf16_text, 639 const CompletionCallback& callback) OVERRIDE { 640 callback_ = callback; 641 base::MessageLoop::current()->PostTask( 642 FROM_HERE, 643 base::Bind(&AsyncFailDhcpFetcher::CallbackWithFailure, AsWeakPtr())); 644 return ERR_IO_PENDING; 645 } 646 647 virtual void Cancel() OVERRIDE { 648 callback_.Reset(); 649 } 650 651 virtual const GURL& GetPacURL() const OVERRIDE { 652 return dummy_gurl_; 653 } 654 655 void CallbackWithFailure() { 656 if (!callback_.is_null()) 657 callback_.Run(ERR_PAC_NOT_IN_DHCP); 658 } 659 660 private: 661 GURL dummy_gurl_; 662 CompletionCallback callback_; 663}; 664 665TEST(ProxyScriptDeciderTest, DhcpCancelledByDestructor) { 666 // This regression test would crash before 667 // http://codereview.chromium.org/7044058/ 668 // Thus, we don't care much about actual results (hence no EXPECT or ASSERT 669 // macros below), just that it doesn't crash. 670 Rules rules; 671 RuleBasedProxyScriptFetcher fetcher(&rules); 672 673 scoped_ptr<AsyncFailDhcpFetcher> dhcp_fetcher(new AsyncFailDhcpFetcher()); 674 675 ProxyConfig config; 676 config.set_auto_detect(true); 677 rules.AddFailDownloadRule("http://wpad/wpad.dat"); 678 679 TestCompletionCallback callback; 680 681 // Scope so ProxyScriptDecider gets destroyed early. 682 { 683 ProxyScriptDecider decider(&fetcher, dhcp_fetcher.get(), NULL); 684 decider.Start(config, base::TimeDelta(), true, callback.callback()); 685 } 686 687 // Run the message loop to let the DHCP fetch complete and post the results 688 // back. Before the fix linked to above, this would try to invoke on 689 // the callback object provided by ProxyScriptDecider after it was 690 // no longer valid. 691 base::MessageLoop::current()->RunUntilIdle(); 692} 693 694} // namespace 695} // namespace net 696