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