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