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