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.
8 #include "base/location.h"
9 #include "base/memory/weak_ptr.h"
10 #include "base/message_loop/message_loop.h"
11 #include "base/run_loop.h"
12 #include "base/single_thread_task_runner.h"
13 #include "base/strings/string_util.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "base/thread_task_runner_handle.h"
16 #include "base/time/time.h"
17 #include "net/base/net_errors.h"
18 #include "net/base/test_completion_callback.h"
19 #include "net/dns/mock_host_resolver.h"
20 #include "net/log/net_log.h"
21 #include "net/log/test_net_log.h"
22 #include "net/log/test_net_log_entry.h"
23 #include "net/log/test_net_log_util.h"
24 #include "net/proxy/dhcp_proxy_script_fetcher.h"
25 #include "net/proxy/mock_proxy_script_fetcher.h"
26 #include "net/proxy/proxy_config.h"
27 #include "net/proxy/proxy_resolver.h"
28 #include "net/proxy/proxy_script_decider.h"
29 #include "net/proxy/proxy_script_fetcher.h"
30 #include "net/url_request/url_request_context.h"
31 #include "testing/gtest/include/gtest/gtest.h"
37 kFailedDownloading
= -100,
38 kFailedParsing
= ERR_PAC_SCRIPT_FAILED
,
44 Rule(const GURL
& url
, int fetch_error
, bool is_valid_script
)
46 fetch_error(fetch_error
),
47 is_valid_script(is_valid_script
) {
50 base::string16
text() const {
52 return base::UTF8ToUTF16(url
.spec() + "!FindProxyForURL");
53 if (fetch_error
== OK
)
54 return base::UTF8ToUTF16(url
.spec() + "!invalid-script");
55 return base::string16();
63 Rule
AddSuccessRule(const char* url
) {
64 Rule
rule(GURL(url
), OK
/*fetch_error*/, true);
65 rules_
.push_back(rule
);
69 void AddFailDownloadRule(const char* url
) {
70 rules_
.push_back(Rule(GURL(url
), kFailedDownloading
/*fetch_error*/,
74 void AddFailParsingRule(const char* url
) {
75 rules_
.push_back(Rule(GURL(url
), OK
/*fetch_error*/, false));
78 const Rule
& GetRuleByUrl(const GURL
& url
) const {
79 for (RuleList::const_iterator it
= rules_
.begin(); it
!= rules_
.end();
84 LOG(FATAL
) << "Rule not found for " << url
;
88 const Rule
& GetRuleByText(const base::string16
& text
) const {
89 for (RuleList::const_iterator it
= rules_
.begin(); it
!= rules_
.end();
91 if (it
->text() == text
)
94 LOG(FATAL
) << "Rule not found for " << text
;
99 typedef std::vector
<Rule
> RuleList
;
103 class RuleBasedProxyScriptFetcher
: public ProxyScriptFetcher
{
105 explicit RuleBasedProxyScriptFetcher(const Rules
* rules
)
106 : rules_(rules
), request_context_(NULL
) {}
108 virtual void SetRequestContext(URLRequestContext
* context
) {
109 request_context_
= context
;
112 // ProxyScriptFetcher implementation.
113 int Fetch(const GURL
& url
,
114 base::string16
* text
,
115 const CompletionCallback
& callback
) override
{
116 const Rules::Rule
& rule
= rules_
->GetRuleByUrl(url
);
117 int rv
= rule
.fetch_error
;
118 EXPECT_NE(ERR_UNEXPECTED
, rv
);
124 void Cancel() override
{}
126 URLRequestContext
* GetRequestContext() const override
{
127 return request_context_
;
132 URLRequestContext
* request_context_
;
135 // A mock retriever, returns asynchronously when CompleteRequests() is called.
136 class MockDhcpProxyScriptFetcher
: public DhcpProxyScriptFetcher
{
138 MockDhcpProxyScriptFetcher();
139 ~MockDhcpProxyScriptFetcher() override
;
141 int Fetch(base::string16
* utf16_text
,
142 const CompletionCallback
& callback
) override
;
143 void Cancel() override
;
144 const GURL
& GetPacURL() const override
;
146 virtual void SetPacURL(const GURL
& url
);
148 virtual void CompleteRequests(int result
, const base::string16
& script
);
151 CompletionCallback callback_
;
152 base::string16
* utf16_text_
;
154 DISALLOW_COPY_AND_ASSIGN(MockDhcpProxyScriptFetcher
);
157 MockDhcpProxyScriptFetcher::MockDhcpProxyScriptFetcher() { }
159 MockDhcpProxyScriptFetcher::~MockDhcpProxyScriptFetcher() { }
161 int MockDhcpProxyScriptFetcher::Fetch(base::string16
* utf16_text
,
162 const CompletionCallback
& callback
) {
163 utf16_text_
= utf16_text
;
164 callback_
= callback
;
165 return ERR_IO_PENDING
;
168 void MockDhcpProxyScriptFetcher::Cancel() { }
170 const GURL
& MockDhcpProxyScriptFetcher::GetPacURL() const {
174 void MockDhcpProxyScriptFetcher::SetPacURL(const GURL
& url
) {
178 void MockDhcpProxyScriptFetcher::CompleteRequests(
179 int result
, const base::string16
& script
) {
180 *utf16_text_
= script
;
181 callback_
.Run(result
);
184 // Succeed using custom PAC script.
185 TEST(ProxyScriptDeciderTest
, CustomPacSucceeds
) {
187 RuleBasedProxyScriptFetcher
fetcher(&rules
);
188 DoNothingDhcpProxyScriptFetcher dhcp_fetcher
;
191 config
.set_pac_url(GURL("http://custom/proxy.pac"));
193 Rules::Rule rule
= rules
.AddSuccessRule("http://custom/proxy.pac");
195 TestCompletionCallback callback
;
197 ProxyScriptDecider
decider(&fetcher
, &dhcp_fetcher
, &log
);
198 EXPECT_EQ(OK
, decider
.Start(
199 config
, base::TimeDelta(), true, callback
.callback()));
200 EXPECT_EQ(rule
.text(), decider
.script_data()->utf16());
202 // Check the NetLog was filled correctly.
203 TestNetLogEntry::List entries
;
204 log
.GetEntries(&entries
);
206 EXPECT_EQ(4u, entries
.size());
207 EXPECT_TRUE(LogContainsBeginEvent(
208 entries
, 0, NetLog::TYPE_PROXY_SCRIPT_DECIDER
));
209 EXPECT_TRUE(LogContainsBeginEvent(
210 entries
, 1, NetLog::TYPE_PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT
));
211 EXPECT_TRUE(LogContainsEndEvent(
212 entries
, 2, NetLog::TYPE_PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT
));
213 EXPECT_TRUE(LogContainsEndEvent(
214 entries
, 3, NetLog::TYPE_PROXY_SCRIPT_DECIDER
));
216 EXPECT_TRUE(decider
.effective_config().has_pac_url());
217 EXPECT_EQ(config
.pac_url(), decider
.effective_config().pac_url());
220 // Fail downloading the custom PAC script.
221 TEST(ProxyScriptDeciderTest
, CustomPacFails1
) {
223 RuleBasedProxyScriptFetcher
fetcher(&rules
);
224 DoNothingDhcpProxyScriptFetcher dhcp_fetcher
;
227 config
.set_pac_url(GURL("http://custom/proxy.pac"));
229 rules
.AddFailDownloadRule("http://custom/proxy.pac");
231 TestCompletionCallback callback
;
233 ProxyScriptDecider
decider(&fetcher
, &dhcp_fetcher
, &log
);
234 EXPECT_EQ(kFailedDownloading
,
235 decider
.Start(config
, base::TimeDelta(), true,
236 callback
.callback()));
237 EXPECT_EQ(NULL
, decider
.script_data());
239 // Check the NetLog was filled correctly.
240 TestNetLogEntry::List entries
;
241 log
.GetEntries(&entries
);
243 EXPECT_EQ(4u, entries
.size());
244 EXPECT_TRUE(LogContainsBeginEvent(
245 entries
, 0, NetLog::TYPE_PROXY_SCRIPT_DECIDER
));
246 EXPECT_TRUE(LogContainsBeginEvent(
247 entries
, 1, NetLog::TYPE_PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT
));
248 EXPECT_TRUE(LogContainsEndEvent(
249 entries
, 2, NetLog::TYPE_PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT
));
250 EXPECT_TRUE(LogContainsEndEvent(
251 entries
, 3, NetLog::TYPE_PROXY_SCRIPT_DECIDER
));
253 EXPECT_FALSE(decider
.effective_config().has_pac_url());
256 // Fail parsing the custom PAC script.
257 TEST(ProxyScriptDeciderTest
, CustomPacFails2
) {
259 RuleBasedProxyScriptFetcher
fetcher(&rules
);
260 DoNothingDhcpProxyScriptFetcher dhcp_fetcher
;
263 config
.set_pac_url(GURL("http://custom/proxy.pac"));
265 rules
.AddFailParsingRule("http://custom/proxy.pac");
267 TestCompletionCallback callback
;
268 ProxyScriptDecider
decider(&fetcher
, &dhcp_fetcher
, NULL
);
269 EXPECT_EQ(kFailedParsing
,
270 decider
.Start(config
, base::TimeDelta(), true,
271 callback
.callback()));
272 EXPECT_EQ(NULL
, decider
.script_data());
275 // Fail downloading the custom PAC script, because the fetcher was NULL.
276 TEST(ProxyScriptDeciderTest
, HasNullProxyScriptFetcher
) {
278 DoNothingDhcpProxyScriptFetcher dhcp_fetcher
;
281 config
.set_pac_url(GURL("http://custom/proxy.pac"));
283 TestCompletionCallback callback
;
284 ProxyScriptDecider
decider(NULL
, &dhcp_fetcher
, NULL
);
285 EXPECT_EQ(ERR_UNEXPECTED
,
286 decider
.Start(config
, base::TimeDelta(), true,
287 callback
.callback()));
288 EXPECT_EQ(NULL
, decider
.script_data());
291 // Succeeds in choosing autodetect (WPAD DNS).
292 TEST(ProxyScriptDeciderTest
, AutodetectSuccess
) {
294 RuleBasedProxyScriptFetcher
fetcher(&rules
);
295 DoNothingDhcpProxyScriptFetcher dhcp_fetcher
;
298 config
.set_auto_detect(true);
300 Rules::Rule rule
= rules
.AddSuccessRule("http://wpad/wpad.dat");
302 TestCompletionCallback callback
;
303 ProxyScriptDecider
decider(&fetcher
, &dhcp_fetcher
, NULL
);
304 EXPECT_EQ(OK
, decider
.Start(
305 config
, base::TimeDelta(), true, callback
.callback()));
306 EXPECT_EQ(rule
.text(), decider
.script_data()->utf16());
308 EXPECT_TRUE(decider
.effective_config().has_pac_url());
309 EXPECT_EQ(rule
.url
, decider
.effective_config().pac_url());
312 class ProxyScriptDeciderQuickCheckTest
: public ::testing::Test
{
314 ProxyScriptDeciderQuickCheckTest()
315 : rule_(rules_
.AddSuccessRule("http://wpad/wpad.dat")),
316 fetcher_(&rules_
) { }
318 void SetUp() override
{
319 request_context_
.set_host_resolver(&resolver_
);
320 fetcher_
.SetRequestContext(&request_context_
);
321 config_
.set_auto_detect(true);
322 decider_
.reset(new ProxyScriptDecider(&fetcher_
, &dhcp_fetcher_
, NULL
));
326 return decider_
->Start(config_
, base::TimeDelta(), true,
327 callback_
.callback());
331 scoped_ptr
<ProxyScriptDecider
> decider_
;
332 MockHostResolver resolver_
;
335 TestCompletionCallback callback_
;
336 RuleBasedProxyScriptFetcher fetcher_
;
338 DoNothingDhcpProxyScriptFetcher dhcp_fetcher_
;
341 URLRequestContext request_context_
;
344 // Fails if a synchronous DNS lookup success for wpad causes QuickCheck to fail.
345 TEST_F(ProxyScriptDeciderQuickCheckTest
, SyncSuccess
) {
346 resolver_
.set_synchronous_mode(true);
347 resolver_
.rules()->AddRule("wpad", "1.2.3.4");
349 EXPECT_EQ(OK
, StartDecider());
350 EXPECT_EQ(rule_
.text(), decider_
->script_data()->utf16());
352 EXPECT_TRUE(decider_
->effective_config().has_pac_url());
353 EXPECT_EQ(rule_
.url
, decider_
->effective_config().pac_url());
356 // Fails if an asynchronous DNS lookup success for wpad causes QuickCheck to
358 TEST_F(ProxyScriptDeciderQuickCheckTest
, AsyncSuccess
) {
359 resolver_
.set_ondemand_mode(true);
360 resolver_
.rules()->AddRule("wpad", "1.2.3.4");
362 EXPECT_EQ(ERR_IO_PENDING
, StartDecider());
363 ASSERT_TRUE(resolver_
.has_pending_requests());
364 resolver_
.ResolveAllPending();
365 callback_
.WaitForResult();
366 EXPECT_FALSE(resolver_
.has_pending_requests());
367 EXPECT_EQ(rule_
.text(), decider_
->script_data()->utf16());
368 EXPECT_TRUE(decider_
->effective_config().has_pac_url());
369 EXPECT_EQ(rule_
.url
, decider_
->effective_config().pac_url());
372 // Fails if an asynchronous DNS lookup failure (i.e. an NXDOMAIN) still causes
373 // ProxyScriptDecider to yield a PAC URL.
374 TEST_F(ProxyScriptDeciderQuickCheckTest
, AsyncFail
) {
375 resolver_
.set_ondemand_mode(true);
376 resolver_
.rules()->AddSimulatedFailure("wpad");
377 EXPECT_EQ(ERR_IO_PENDING
, StartDecider());
378 ASSERT_TRUE(resolver_
.has_pending_requests());
379 resolver_
.ResolveAllPending();
380 callback_
.WaitForResult();
381 EXPECT_FALSE(decider_
->effective_config().has_pac_url());
384 // Fails if a DNS lookup timeout either causes ProxyScriptDecider to yield a PAC
385 // URL or causes ProxyScriptDecider not to cancel its pending resolution.
386 TEST_F(ProxyScriptDeciderQuickCheckTest
, AsyncTimeout
) {
387 resolver_
.set_ondemand_mode(true);
388 EXPECT_EQ(ERR_IO_PENDING
, StartDecider());
389 ASSERT_TRUE(resolver_
.has_pending_requests());
390 callback_
.WaitForResult();
391 EXPECT_FALSE(resolver_
.has_pending_requests());
392 EXPECT_FALSE(decider_
->effective_config().has_pac_url());
395 // Fails if DHCP check doesn't take place before QuickCheck.
396 TEST_F(ProxyScriptDeciderQuickCheckTest
, QuickCheckInhibitsDhcp
) {
397 MockDhcpProxyScriptFetcher dhcp_fetcher
;
398 const char *kPac
= "function FindProxyForURL(u,h) { return \"DIRECT\"; }";
399 base::string16 pac_contents
= base::UTF8ToUTF16(kPac
);
400 GURL
url("http://foobar/baz");
401 dhcp_fetcher
.SetPacURL(url
);
402 decider_
.reset(new ProxyScriptDecider(&fetcher_
, &dhcp_fetcher
, NULL
));
403 EXPECT_EQ(ERR_IO_PENDING
, StartDecider());
404 dhcp_fetcher
.CompleteRequests(OK
, pac_contents
);
405 EXPECT_TRUE(decider_
->effective_config().has_pac_url());
406 EXPECT_EQ(decider_
->effective_config().pac_url(), url
);
409 // Fails if QuickCheck still happens when disabled. To ensure QuickCheck is not
410 // happening, we add a synchronous failing resolver, which would ordinarily
411 // mean a QuickCheck failure, then ensure that our ProxyScriptFetcher is still
413 TEST_F(ProxyScriptDeciderQuickCheckTest
, QuickCheckDisabled
) {
414 const char *kPac
= "function FindProxyForURL(u,h) { return \"DIRECT\"; }";
415 resolver_
.set_synchronous_mode(true);
416 resolver_
.rules()->AddSimulatedFailure("wpad");
417 MockProxyScriptFetcher fetcher
;
418 decider_
.reset(new ProxyScriptDecider(&fetcher
, &dhcp_fetcher_
, NULL
));
419 EXPECT_EQ(ERR_IO_PENDING
, StartDecider());
420 EXPECT_TRUE(fetcher
.has_pending_request());
421 fetcher
.NotifyFetchCompletion(OK
, kPac
);
424 TEST_F(ProxyScriptDeciderQuickCheckTest
, ExplicitPacUrl
) {
425 const char *kCustomUrl
= "http://custom/proxy.pac";
426 config_
.set_pac_url(GURL(kCustomUrl
));
427 Rules::Rule rule
= rules_
.AddSuccessRule(kCustomUrl
);
428 resolver_
.rules()->AddSimulatedFailure("wpad");
429 resolver_
.rules()->AddRule("custom", "1.2.3.4");
430 EXPECT_EQ(ERR_IO_PENDING
, StartDecider());
431 callback_
.WaitForResult();
432 EXPECT_TRUE(decider_
->effective_config().has_pac_url());
433 EXPECT_EQ(rule
.url
, decider_
->effective_config().pac_url());
436 // Regression test for http://crbug.com/409698.
437 // This test lets the state machine get into state QUICK_CHECK_COMPLETE, then
438 // destroys the decider, causing a cancel.
439 TEST_F(ProxyScriptDeciderQuickCheckTest
, CancelPartway
) {
440 resolver_
.set_synchronous_mode(false);
441 resolver_
.set_ondemand_mode(true);
442 EXPECT_EQ(ERR_IO_PENDING
, StartDecider());
443 decider_
.reset(NULL
);
446 // Fails at WPAD (downloading), but succeeds in choosing the custom PAC.
447 TEST(ProxyScriptDeciderTest
, AutodetectFailCustomSuccess1
) {
449 RuleBasedProxyScriptFetcher
fetcher(&rules
);
450 DoNothingDhcpProxyScriptFetcher dhcp_fetcher
;
453 config
.set_auto_detect(true);
454 config
.set_pac_url(GURL("http://custom/proxy.pac"));
456 rules
.AddFailDownloadRule("http://wpad/wpad.dat");
457 Rules::Rule rule
= rules
.AddSuccessRule("http://custom/proxy.pac");
459 TestCompletionCallback callback
;
460 ProxyScriptDecider
decider(&fetcher
, &dhcp_fetcher
, NULL
);
461 EXPECT_EQ(OK
, decider
.Start(
462 config
, base::TimeDelta(), true, callback
.callback()));
463 EXPECT_EQ(rule
.text(), decider
.script_data()->utf16());
465 EXPECT_TRUE(decider
.effective_config().has_pac_url());
466 EXPECT_EQ(rule
.url
, decider
.effective_config().pac_url());
469 // Fails at WPAD (no DHCP config, DNS PAC fails parsing), but succeeds in
470 // choosing the custom PAC.
471 TEST(ProxyScriptDeciderTest
, AutodetectFailCustomSuccess2
) {
473 RuleBasedProxyScriptFetcher
fetcher(&rules
);
474 DoNothingDhcpProxyScriptFetcher dhcp_fetcher
;
477 config
.set_auto_detect(true);
478 config
.set_pac_url(GURL("http://custom/proxy.pac"));
479 config
.proxy_rules().ParseFromString("unused-manual-proxy:99");
481 rules
.AddFailParsingRule("http://wpad/wpad.dat");
482 Rules::Rule rule
= rules
.AddSuccessRule("http://custom/proxy.pac");
484 TestCompletionCallback callback
;
487 ProxyScriptDecider
decider(&fetcher
, &dhcp_fetcher
, &log
);
488 EXPECT_EQ(OK
, decider
.Start(config
, base::TimeDelta(),
489 true, callback
.callback()));
490 EXPECT_EQ(rule
.text(), decider
.script_data()->utf16());
492 // Verify that the effective configuration no longer contains auto detect or
493 // any of the manual settings.
494 EXPECT_TRUE(decider
.effective_config().Equals(
495 ProxyConfig::CreateFromCustomPacURL(GURL("http://custom/proxy.pac"))));
497 // Check the NetLog was filled correctly.
498 // (Note that various states are repeated since both WPAD and custom
499 // PAC scripts are tried).
500 TestNetLogEntry::List entries
;
501 log
.GetEntries(&entries
);
503 EXPECT_EQ(10u, entries
.size());
504 EXPECT_TRUE(LogContainsBeginEvent(
505 entries
, 0, NetLog::TYPE_PROXY_SCRIPT_DECIDER
));
506 // This is the DHCP phase, which fails fetching rather than parsing, so
507 // there is no pair of SET_PAC_SCRIPT events.
508 EXPECT_TRUE(LogContainsBeginEvent(
509 entries
, 1, NetLog::TYPE_PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT
));
510 EXPECT_TRUE(LogContainsEndEvent(
511 entries
, 2, NetLog::TYPE_PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT
));
512 EXPECT_TRUE(LogContainsEvent(
514 NetLog::TYPE_PROXY_SCRIPT_DECIDER_FALLING_BACK_TO_NEXT_PAC_SOURCE
,
515 NetLog::PHASE_NONE
));
516 // This is the DNS phase, which attempts a fetch but fails.
517 EXPECT_TRUE(LogContainsBeginEvent(
518 entries
, 4, NetLog::TYPE_PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT
));
519 EXPECT_TRUE(LogContainsEndEvent(
520 entries
, 5, NetLog::TYPE_PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT
));
521 EXPECT_TRUE(LogContainsEvent(
523 NetLog::TYPE_PROXY_SCRIPT_DECIDER_FALLING_BACK_TO_NEXT_PAC_SOURCE
,
524 NetLog::PHASE_NONE
));
525 // Finally, the custom PAC URL phase.
526 EXPECT_TRUE(LogContainsBeginEvent(
527 entries
, 7, NetLog::TYPE_PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT
));
528 EXPECT_TRUE(LogContainsEndEvent(
529 entries
, 8, NetLog::TYPE_PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT
));
530 EXPECT_TRUE(LogContainsEndEvent(
531 entries
, 9, NetLog::TYPE_PROXY_SCRIPT_DECIDER
));
534 // Fails at WPAD (downloading), and fails at custom PAC (downloading).
535 TEST(ProxyScriptDeciderTest
, AutodetectFailCustomFails1
) {
537 RuleBasedProxyScriptFetcher
fetcher(&rules
);
538 DoNothingDhcpProxyScriptFetcher dhcp_fetcher
;
541 config
.set_auto_detect(true);
542 config
.set_pac_url(GURL("http://custom/proxy.pac"));
544 rules
.AddFailDownloadRule("http://wpad/wpad.dat");
545 rules
.AddFailDownloadRule("http://custom/proxy.pac");
547 TestCompletionCallback callback
;
548 ProxyScriptDecider
decider(&fetcher
, &dhcp_fetcher
, NULL
);
549 EXPECT_EQ(kFailedDownloading
,
550 decider
.Start(config
, base::TimeDelta(), true,
551 callback
.callback()));
552 EXPECT_EQ(NULL
, decider
.script_data());
555 // Fails at WPAD (downloading), and fails at custom PAC (parsing).
556 TEST(ProxyScriptDeciderTest
, AutodetectFailCustomFails2
) {
558 RuleBasedProxyScriptFetcher
fetcher(&rules
);
559 DoNothingDhcpProxyScriptFetcher dhcp_fetcher
;
562 config
.set_auto_detect(true);
563 config
.set_pac_url(GURL("http://custom/proxy.pac"));
565 rules
.AddFailDownloadRule("http://wpad/wpad.dat");
566 rules
.AddFailParsingRule("http://custom/proxy.pac");
568 TestCompletionCallback callback
;
569 ProxyScriptDecider
decider(&fetcher
, &dhcp_fetcher
, NULL
);
570 EXPECT_EQ(kFailedParsing
,
571 decider
.Start(config
, base::TimeDelta(), true,
572 callback
.callback()));
573 EXPECT_EQ(NULL
, decider
.script_data());
576 // This is a copy-paste of CustomPacFails1, with the exception that we give it
577 // a 1 millisecond delay. This means it will now complete asynchronously.
578 // Moreover, we test the NetLog to make sure it logged the pause.
579 TEST(ProxyScriptDeciderTest
, CustomPacFails1_WithPositiveDelay
) {
581 RuleBasedProxyScriptFetcher
fetcher(&rules
);
582 DoNothingDhcpProxyScriptFetcher dhcp_fetcher
;
585 config
.set_pac_url(GURL("http://custom/proxy.pac"));
587 rules
.AddFailDownloadRule("http://custom/proxy.pac");
589 TestCompletionCallback callback
;
591 ProxyScriptDecider
decider(&fetcher
, &dhcp_fetcher
, &log
);
592 EXPECT_EQ(ERR_IO_PENDING
,
593 decider
.Start(config
, base::TimeDelta::FromMilliseconds(1),
594 true, callback
.callback()));
596 EXPECT_EQ(kFailedDownloading
, callback
.WaitForResult());
597 EXPECT_EQ(NULL
, decider
.script_data());
599 // Check the NetLog was filled correctly.
600 TestNetLogEntry::List entries
;
601 log
.GetEntries(&entries
);
603 EXPECT_EQ(6u, entries
.size());
604 EXPECT_TRUE(LogContainsBeginEvent(
605 entries
, 0, NetLog::TYPE_PROXY_SCRIPT_DECIDER
));
606 EXPECT_TRUE(LogContainsBeginEvent(
607 entries
, 1, NetLog::TYPE_PROXY_SCRIPT_DECIDER_WAIT
));
608 EXPECT_TRUE(LogContainsEndEvent(
609 entries
, 2, NetLog::TYPE_PROXY_SCRIPT_DECIDER_WAIT
));
610 EXPECT_TRUE(LogContainsBeginEvent(
611 entries
, 3, NetLog::TYPE_PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT
));
612 EXPECT_TRUE(LogContainsEndEvent(
613 entries
, 4, NetLog::TYPE_PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT
));
614 EXPECT_TRUE(LogContainsEndEvent(
615 entries
, 5, NetLog::TYPE_PROXY_SCRIPT_DECIDER
));
618 // This is a copy-paste of CustomPacFails1, with the exception that we give it
619 // a -5 second delay instead of a 0 ms delay. This change should have no effect
620 // so the rest of the test is unchanged.
621 TEST(ProxyScriptDeciderTest
, CustomPacFails1_WithNegativeDelay
) {
623 RuleBasedProxyScriptFetcher
fetcher(&rules
);
624 DoNothingDhcpProxyScriptFetcher dhcp_fetcher
;
627 config
.set_pac_url(GURL("http://custom/proxy.pac"));
629 rules
.AddFailDownloadRule("http://custom/proxy.pac");
631 TestCompletionCallback callback
;
633 ProxyScriptDecider
decider(&fetcher
, &dhcp_fetcher
, &log
);
634 EXPECT_EQ(kFailedDownloading
,
635 decider
.Start(config
, base::TimeDelta::FromSeconds(-5),
636 true, callback
.callback()));
637 EXPECT_EQ(NULL
, decider
.script_data());
639 // Check the NetLog was filled correctly.
640 TestNetLogEntry::List entries
;
641 log
.GetEntries(&entries
);
643 EXPECT_EQ(4u, entries
.size());
644 EXPECT_TRUE(LogContainsBeginEvent(
645 entries
, 0, NetLog::TYPE_PROXY_SCRIPT_DECIDER
));
646 EXPECT_TRUE(LogContainsBeginEvent(
647 entries
, 1, NetLog::TYPE_PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT
));
648 EXPECT_TRUE(LogContainsEndEvent(
649 entries
, 2, NetLog::TYPE_PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT
));
650 EXPECT_TRUE(LogContainsEndEvent(
651 entries
, 3, NetLog::TYPE_PROXY_SCRIPT_DECIDER
));
654 class SynchronousSuccessDhcpFetcher
: public DhcpProxyScriptFetcher
{
656 explicit SynchronousSuccessDhcpFetcher(const base::string16
& expected_text
)
657 : gurl_("http://dhcppac/"), expected_text_(expected_text
) {
660 int Fetch(base::string16
* utf16_text
,
661 const CompletionCallback
& callback
) override
{
662 *utf16_text
= expected_text_
;
666 void Cancel() override
{}
668 const GURL
& GetPacURL() const override
{ return gurl_
; }
670 const base::string16
& expected_text() const {
671 return expected_text_
;
676 base::string16 expected_text_
;
678 DISALLOW_COPY_AND_ASSIGN(SynchronousSuccessDhcpFetcher
);
681 // All of the tests above that use ProxyScriptDecider have tested
682 // failure to fetch a PAC file via DHCP configuration, so we now test
683 // success at downloading and parsing, and then success at downloading,
684 // failure at parsing.
686 TEST(ProxyScriptDeciderTest
, AutodetectDhcpSuccess
) {
688 RuleBasedProxyScriptFetcher
fetcher(&rules
);
689 SynchronousSuccessDhcpFetcher
dhcp_fetcher(
690 base::WideToUTF16(L
"http://bingo/!FindProxyForURL"));
693 config
.set_auto_detect(true);
695 rules
.AddSuccessRule("http://bingo/");
696 rules
.AddFailDownloadRule("http://wpad/wpad.dat");
698 TestCompletionCallback callback
;
699 ProxyScriptDecider
decider(&fetcher
, &dhcp_fetcher
, NULL
);
700 EXPECT_EQ(OK
, decider
.Start(
701 config
, base::TimeDelta(), true, callback
.callback()));
702 EXPECT_EQ(dhcp_fetcher
.expected_text(),
703 decider
.script_data()->utf16());
705 EXPECT_TRUE(decider
.effective_config().has_pac_url());
706 EXPECT_EQ(GURL("http://dhcppac/"), decider
.effective_config().pac_url());
709 TEST(ProxyScriptDeciderTest
, AutodetectDhcpFailParse
) {
711 RuleBasedProxyScriptFetcher
fetcher(&rules
);
712 SynchronousSuccessDhcpFetcher
dhcp_fetcher(
713 base::WideToUTF16(L
"http://bingo/!invalid-script"));
716 config
.set_auto_detect(true);
718 rules
.AddFailParsingRule("http://bingo/");
719 rules
.AddFailDownloadRule("http://wpad/wpad.dat");
721 TestCompletionCallback callback
;
722 ProxyScriptDecider
decider(&fetcher
, &dhcp_fetcher
, NULL
);
723 // Since there is fallback to DNS-based WPAD, the final error will be that
724 // it failed downloading, not that it failed parsing.
725 EXPECT_EQ(kFailedDownloading
,
726 decider
.Start(config
, base::TimeDelta(), true, callback
.callback()));
727 EXPECT_EQ(NULL
, decider
.script_data());
729 EXPECT_FALSE(decider
.effective_config().has_pac_url());
732 class AsyncFailDhcpFetcher
733 : public DhcpProxyScriptFetcher
,
734 public base::SupportsWeakPtr
<AsyncFailDhcpFetcher
> {
736 AsyncFailDhcpFetcher() {}
737 ~AsyncFailDhcpFetcher() override
{}
739 int Fetch(base::string16
* utf16_text
,
740 const CompletionCallback
& callback
) override
{
741 callback_
= callback
;
742 base::ThreadTaskRunnerHandle::Get()->PostTask(
744 base::Bind(&AsyncFailDhcpFetcher::CallbackWithFailure
, AsWeakPtr()));
745 return ERR_IO_PENDING
;
748 void Cancel() override
{ callback_
.Reset(); }
750 const GURL
& GetPacURL() const override
{ return dummy_gurl_
; }
752 void CallbackWithFailure() {
753 if (!callback_
.is_null())
754 callback_
.Run(ERR_PAC_NOT_IN_DHCP
);
759 CompletionCallback callback_
;
762 TEST(ProxyScriptDeciderTest
, DhcpCancelledByDestructor
) {
763 // This regression test would crash before
764 // http://codereview.chromium.org/7044058/
765 // Thus, we don't care much about actual results (hence no EXPECT or ASSERT
766 // macros below), just that it doesn't crash.
768 RuleBasedProxyScriptFetcher
fetcher(&rules
);
770 scoped_ptr
<AsyncFailDhcpFetcher
> dhcp_fetcher(new AsyncFailDhcpFetcher());
773 config
.set_auto_detect(true);
774 rules
.AddFailDownloadRule("http://wpad/wpad.dat");
776 TestCompletionCallback callback
;
778 // Scope so ProxyScriptDecider gets destroyed early.
780 ProxyScriptDecider
decider(&fetcher
, dhcp_fetcher
.get(), NULL
);
781 decider
.Start(config
, base::TimeDelta(), true, callback
.callback());
784 // Run the message loop to let the DHCP fetch complete and post the results
785 // back. Before the fix linked to above, this would try to invoke on
786 // the callback object provided by ProxyScriptDecider after it was
788 base::MessageLoop::current()->RunUntilIdle();