• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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