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