• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2012 The Chromium Authors
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_resolution/proxy_config.h"
6 
7 #include "base/json/json_writer.h"
8 #include "base/test/gtest_util.h"
9 #include "base/values.h"
10 #include "build/buildflag.h"
11 #include "net/base/proxy_string_util.h"
12 #include "net/net_buildflags.h"
13 #include "net/proxy_resolution/proxy_config_service_common_unittest.h"
14 #include "net/proxy_resolution/proxy_info.h"
15 #include "testing/gtest/include/gtest/gtest.h"
16 
17 namespace net {
18 namespace {
19 
ExpectProxyServerEquals(const char * expectation,const ProxyList & proxy_list)20 void ExpectProxyServerEquals(const char* expectation,
21                              const ProxyList& proxy_list) {
22   if (expectation == nullptr) {
23     EXPECT_TRUE(proxy_list.IsEmpty());
24   } else {
25     EXPECT_EQ(expectation, proxy_list.ToDebugString());
26   }
27 }
28 
TEST(ProxyConfigTest,Equals)29 TEST(ProxyConfigTest, Equals) {
30   // Test |ProxyConfig::auto_detect|.
31 
32   ProxyConfig config1;
33   config1.set_auto_detect(true);
34 
35   ProxyConfig config2;
36   config2.set_auto_detect(false);
37 
38   EXPECT_FALSE(config1.Equals(config2));
39   EXPECT_FALSE(config2.Equals(config1));
40 
41   config2.set_auto_detect(true);
42 
43   EXPECT_TRUE(config1.Equals(config2));
44   EXPECT_TRUE(config2.Equals(config1));
45 
46   // Test |ProxyConfig::pac_url|.
47 
48   config2.set_pac_url(GURL("http://wpad/wpad.dat"));
49 
50   EXPECT_FALSE(config1.Equals(config2));
51   EXPECT_FALSE(config2.Equals(config1));
52 
53   config1.set_pac_url(GURL("http://wpad/wpad.dat"));
54 
55   EXPECT_TRUE(config1.Equals(config2));
56   EXPECT_TRUE(config2.Equals(config1));
57 
58   // Test |ProxyConfig::proxy_rules|.
59 
60   config2.proxy_rules().type = ProxyConfig::ProxyRules::Type::PROXY_LIST;
61   config2.proxy_rules().single_proxies.SetSingleProxyServer(
62       ProxyUriToProxyServer("myproxy:80", ProxyServer::SCHEME_HTTP));
63 
64   EXPECT_FALSE(config1.Equals(config2));
65   EXPECT_FALSE(config2.Equals(config1));
66 
67   config1.proxy_rules().type = ProxyConfig::ProxyRules::Type::PROXY_LIST;
68   config1.proxy_rules().single_proxies.SetSingleProxyServer(
69       ProxyUriToProxyServer("myproxy:100", ProxyServer::SCHEME_HTTP));
70 
71   EXPECT_FALSE(config1.Equals(config2));
72   EXPECT_FALSE(config2.Equals(config1));
73 
74   config1.proxy_rules().single_proxies.SetSingleProxyServer(
75       ProxyUriToProxyServer("myproxy", ProxyServer::SCHEME_HTTP));
76 
77   EXPECT_TRUE(config1.Equals(config2));
78   EXPECT_TRUE(config2.Equals(config1));
79 
80   // Test |ProxyConfig::bypass_rules|.
81 
82   config2.proxy_rules().bypass_rules.AddRuleFromString("*.google.com");
83 
84   EXPECT_FALSE(config1.Equals(config2));
85   EXPECT_FALSE(config2.Equals(config1));
86 
87   config1.proxy_rules().bypass_rules.AddRuleFromString("*.google.com");
88 
89   EXPECT_TRUE(config1.Equals(config2));
90   EXPECT_TRUE(config2.Equals(config1));
91 
92   // Test |ProxyConfig::proxy_rules.reverse_bypass|.
93 
94   config2.proxy_rules().reverse_bypass = true;
95 
96   EXPECT_FALSE(config1.Equals(config2));
97   EXPECT_FALSE(config2.Equals(config1));
98 
99   config1.proxy_rules().reverse_bypass = true;
100 
101   EXPECT_TRUE(config1.Equals(config2));
102   EXPECT_TRUE(config2.Equals(config1));
103 }
104 
105 #if BUILDFLAG(ENABLE_BRACKETED_PROXY_URIS)
TEST(ProxyConfigTest,EqualsMultiProxyChains)106 TEST(ProxyConfigTest, EqualsMultiProxyChains) {
107   ProxyConfig config1;
108   ProxyConfig config2;
109 
110   config2.proxy_rules().type =
111       ProxyConfig::ProxyRules::Type::PROXY_LIST_PER_SCHEME;
112   config2.proxy_rules().proxies_for_https.SetSingleProxyChain(
113       MultiProxyUrisToProxyChain("[https://foopy:443 https://hoopy:443]",
114                                  ProxyServer::SCHEME_HTTPS));
115 
116   EXPECT_FALSE(config1.Equals(config2));
117   EXPECT_FALSE(config2.Equals(config1));
118 
119   config1.proxy_rules().type =
120       ProxyConfig::ProxyRules::Type::PROXY_LIST_PER_SCHEME;
121   config1.proxy_rules().proxies_for_https.SetSingleProxyChain(
122       MultiProxyUrisToProxyChain("[https://foopy:80 https://hoopy:80]",
123                                  ProxyServer::SCHEME_HTTPS));
124 
125   EXPECT_FALSE(config1.Equals(config2));
126   EXPECT_FALSE(config2.Equals(config1));
127 
128   config1.proxy_rules().proxies_for_https.SetSingleProxyChain(
129       MultiProxyUrisToProxyChain("[https://foopy https://hoopy]",
130                                  ProxyServer::SCHEME_HTTPS));
131 
132   EXPECT_TRUE(config1.Equals(config2));
133   EXPECT_TRUE(config2.Equals(config1));
134 }
135 #endif  // BUILDFLAG(ENABLE_BRACKETED_PROXY_URIS)
136 
137 struct ProxyConfigToValueTestCase {
138   ProxyConfig config;
139   const char* expected_value_json;
140 };
141 
142 class ProxyConfigToValueTest
143     : public ::testing::TestWithParam<ProxyConfigToValueTestCase> {};
144 
TEST_P(ProxyConfigToValueTest,ToValueJSON)145 TEST_P(ProxyConfigToValueTest, ToValueJSON) {
146   const ProxyConfigToValueTestCase& test_case = GetParam();
147 
148   base::Value value = test_case.config.ToValue();
149 
150   std::string json_string;
151   ASSERT_TRUE(base::JSONWriter::Write(value, &json_string));
152 
153   EXPECT_EQ(std::string(test_case.expected_value_json), json_string);
154 }
155 
GetTestCaseDirect()156 ProxyConfigToValueTestCase GetTestCaseDirect() {
157   return {ProxyConfig::CreateDirect(), "{}"};
158 }
159 
GetTestCaseAutoDetect()160 ProxyConfigToValueTestCase GetTestCaseAutoDetect() {
161   return {ProxyConfig::CreateAutoDetect(), "{\"auto_detect\":true}"};
162 }
163 
GetTestCasePacUrl()164 ProxyConfigToValueTestCase GetTestCasePacUrl() {
165   ProxyConfig config;
166   config.set_pac_url(GURL("http://www.example.com/test.pac"));
167 
168   return {std::move(config),
169           "{\"pac_url\":\"http://www.example.com/test.pac\"}"};
170 }
171 
GetTestCasePacUrlMandatory()172 ProxyConfigToValueTestCase GetTestCasePacUrlMandatory() {
173   ProxyConfig config;
174   config.set_pac_url(GURL("http://www.example.com/test.pac"));
175   config.set_pac_mandatory(true);
176 
177   return {std::move(config),
178           "{\"pac_mandatory\":true,\"pac_url\":\"http://www.example.com/"
179           "test.pac\"}"};
180 }
181 
GetTestCasePacUrlAndAutoDetect()182 ProxyConfigToValueTestCase GetTestCasePacUrlAndAutoDetect() {
183   ProxyConfig config = ProxyConfig::CreateAutoDetect();
184   config.set_pac_url(GURL("http://www.example.com/test.pac"));
185 
186   return {
187       std::move(config),
188       "{\"auto_detect\":true,\"pac_url\":\"http://www.example.com/test.pac\"}"};
189 }
190 
GetTestCaseSingleProxy()191 ProxyConfigToValueTestCase GetTestCaseSingleProxy() {
192   ProxyConfig config;
193   config.proxy_rules().ParseFromString("https://proxy1:8080");
194 
195   return {std::move(config), "{\"single_proxy\":[\"[https://proxy1:8080]\"]}"};
196 }
197 
GetTestCaseSingleProxyWithBypass()198 ProxyConfigToValueTestCase GetTestCaseSingleProxyWithBypass() {
199   ProxyConfig config;
200   config.proxy_rules().ParseFromString("https://proxy1:8080");
201   config.proxy_rules().bypass_rules.AddRuleFromString("*.google.com");
202   config.proxy_rules().bypass_rules.AddRuleFromString("192.168.0.1/16");
203 
204   return {std::move(config),
205           "{\"bypass_list\":[\"*.google.com\",\"192.168.0.1/"
206           "16\"],\"single_proxy\":[\"[https://proxy1:8080]\"]}"};
207 }
208 
GetTestCaseSingleProxyWithReversedBypass()209 ProxyConfigToValueTestCase GetTestCaseSingleProxyWithReversedBypass() {
210   ProxyConfig config;
211   config.proxy_rules().ParseFromString("https://proxy1:8080");
212   config.proxy_rules().bypass_rules.AddRuleFromString("*.google.com");
213   config.proxy_rules().reverse_bypass = true;
214 
215   return {std::move(config),
216           "{\"bypass_list\":[\"*.google.com\"],\"reverse_bypass\":true,"
217           "\"single_proxy\":[\"[https://proxy1:8080]\"]}"};
218 }
219 
GetTestCaseProxyPerScheme()220 ProxyConfigToValueTestCase GetTestCaseProxyPerScheme() {
221   ProxyConfig config;
222   config.proxy_rules().ParseFromString(
223       "http=https://proxy1:8080;https=socks5://proxy2");
224   config.proxy_rules().bypass_rules.AddRuleFromString("*.google.com");
225   config.set_pac_url(GURL("http://wpad/wpad.dat"));
226   config.set_auto_detect(true);
227 
228   return {
229       std::move(config),
230       "{\"auto_detect\":true,\"bypass_list\":[\"*.google.com\"],\"pac_url\":"
231       "\"http://wpad/wpad.dat\",\"proxy_per_scheme\":{\"http\":[\"[https://"
232       "proxy1:8080]\"],\"https\":[\"[socks5://proxy2:1080]\"]}}"};
233 }
234 
GetTestCaseSingleProxyList()235 ProxyConfigToValueTestCase GetTestCaseSingleProxyList() {
236   ProxyConfig config;
237   config.proxy_rules().ParseFromString(
238       "https://proxy1:8080,http://proxy2,direct://");
239 
240   return {
241       std::move(config),
242       "{\"single_proxy\":[\"[https://proxy1:8080]\",\"[proxy2:80]\",\"direct://"
243       "\"]}"};
244 }
245 
246 #if BUILDFLAG(ENABLE_BRACKETED_PROXY_URIS)
247 // Multi-proxy chains present
GetTestCaseMultiProxyChainProxyPerScheme()248 ProxyConfigToValueTestCase GetTestCaseMultiProxyChainProxyPerScheme() {
249   ProxyConfig config;
250   config.proxy_rules().ParseFromString(
251       "http=[https://proxy1:8080 https://proxy2:8080];https=socks5://proxy2",
252       /*allow_bracketed_proxy_chains=*/true);
253   config.proxy_rules().bypass_rules.AddRuleFromString("*.google.com");
254   config.set_pac_url(GURL("http://wpad/wpad.dat"));
255   config.set_auto_detect(true);
256 
257   return {std::move(config),
258           "{\"auto_detect\":true,\"bypass_list\":[\"*.google.com\"],\"pac_"
259           "url\":\"http://wpad/"
260           "wpad.dat\",\"proxy_per_scheme\":{\"http\":[\"[https://proxy1:8080, "
261           "https://proxy2:8080]\"],\"https\":[\"[socks5://proxy2:1080]\"]}}"};
262 }
263 #endif  // BUILDFLAG(ENABLE_BRACKETED_PROXY_URIS)
264 
265 INSTANTIATE_TEST_SUITE_P(
266     All,
267     ProxyConfigToValueTest,
268     testing::Values(GetTestCaseDirect(),
269                     GetTestCaseAutoDetect(),
270                     GetTestCasePacUrl(),
271                     GetTestCasePacUrlMandatory(),
272                     GetTestCasePacUrlAndAutoDetect(),
273                     GetTestCaseSingleProxy(),
274                     GetTestCaseSingleProxyWithBypass(),
275                     GetTestCaseSingleProxyWithReversedBypass(),
276                     GetTestCaseProxyPerScheme(),
277 #if BUILDFLAG(ENABLE_BRACKETED_PROXY_URIS)
278                     GetTestCaseMultiProxyChainProxyPerScheme(),
279 #endif  // BUILDFLAG(ENABLE_BRACKETED_PROXY_URIS)
280                     GetTestCaseSingleProxyList()));
281 
TEST(ProxyConfigTest,ParseProxyRules)282 TEST(ProxyConfigTest, ParseProxyRules) {
283   const struct {
284     const char* proxy_rules;
285 
286     ProxyConfig::ProxyRules::Type type;
287     // These will be PAC-stle strings, eg 'PROXY foo.com'
288     const char* single_proxy;
289     const char* proxy_for_http;
290     const char* proxy_for_https;
291     const char* proxy_for_ftp;
292     const char* fallback_proxy;
293   } tests[] = {
294       // One HTTP proxy for all schemes.
295       {
296           "myproxy:80",
297 
298           ProxyConfig::ProxyRules::Type::PROXY_LIST,
299           "PROXY myproxy:80",
300           nullptr,
301           nullptr,
302           nullptr,
303           nullptr,
304       },
305 
306       // Multiple HTTP proxies for all schemes.
307       {
308           "myproxy:80,https://myotherproxy",
309 
310           ProxyConfig::ProxyRules::Type::PROXY_LIST,
311           "PROXY myproxy:80;HTTPS myotherproxy:443",
312           nullptr,
313           nullptr,
314           nullptr,
315           nullptr,
316       },
317 
318       // Only specify a proxy server for "http://" urls.
319       {
320           "http=myproxy:80",
321 
322           ProxyConfig::ProxyRules::Type::PROXY_LIST_PER_SCHEME,
323           nullptr,
324           "PROXY myproxy:80",
325           nullptr,
326           nullptr,
327           nullptr,
328       },
329 
330       // Specify an HTTP proxy for "ftp://" and a SOCKS proxy for "https://"
331       // urls.
332       {
333           "ftp=ftp-proxy ; https=socks4://foopy",
334 
335           ProxyConfig::ProxyRules::Type::PROXY_LIST_PER_SCHEME,
336           nullptr,
337           nullptr,
338           "SOCKS foopy:1080",
339           "PROXY ftp-proxy:80",
340           nullptr,
341       },
342 
343       // Give a scheme-specific proxy as well as a non-scheme specific.
344       // The first entry "foopy" takes precedence marking this list as
345       // Type::PROXY_LIST.
346       {
347           "foopy ; ftp=ftp-proxy",
348 
349           ProxyConfig::ProxyRules::Type::PROXY_LIST,
350           "PROXY foopy:80",
351           nullptr,
352           nullptr,
353           nullptr,
354           nullptr,
355       },
356 
357       // Give a scheme-specific proxy as well as a non-scheme specific.
358       // The first entry "ftp=ftp-proxy" takes precedence marking this list as
359       // Type::PROXY_LIST_PER_SCHEME.
360       {
361           "ftp=ftp-proxy ; foopy",
362 
363           ProxyConfig::ProxyRules::Type::PROXY_LIST_PER_SCHEME,
364           nullptr,
365           nullptr,
366           nullptr,
367           "PROXY ftp-proxy:80",
368           nullptr,
369       },
370 
371       // Include a list of entries for a single scheme.
372       {
373           "ftp=ftp1,ftp2,ftp3",
374 
375           ProxyConfig::ProxyRules::Type::PROXY_LIST_PER_SCHEME,
376           nullptr,
377           nullptr,
378           nullptr,
379           "PROXY ftp1:80;PROXY ftp2:80;PROXY ftp3:80",
380           nullptr,
381       },
382 
383       // Include multiple entries for the same scheme -- they accumulate.
384       {
385           "http=http1,http2; http=http3",
386 
387           ProxyConfig::ProxyRules::Type::PROXY_LIST_PER_SCHEME,
388           nullptr,
389           "PROXY http1:80;PROXY http2:80;PROXY http3:80",
390           nullptr,
391           nullptr,
392           nullptr,
393       },
394 
395       // Include lists of entries for multiple schemes.
396       {
397           "ftp=ftp1,ftp2,ftp3 ; http=http1,http2; ",
398 
399           ProxyConfig::ProxyRules::Type::PROXY_LIST_PER_SCHEME,
400           nullptr,
401           "PROXY http1:80;PROXY http2:80",
402           nullptr,
403           "PROXY ftp1:80;PROXY ftp2:80;PROXY ftp3:80",
404           nullptr,
405       },
406 
407       // Include non-default proxy schemes.
408       {
409           "http=https://secure_proxy; ftp=socks4://socks_proxy; "
410           "https=socks://foo",
411 
412           ProxyConfig::ProxyRules::Type::PROXY_LIST_PER_SCHEME,
413           nullptr,
414           "HTTPS secure_proxy:443",
415           "SOCKS5 foo:1080",
416           "SOCKS socks_proxy:1080",
417           nullptr,
418       },
419 
420       // Only SOCKS proxy present, others being blank.
421       {
422           "socks=foopy",
423 
424           ProxyConfig::ProxyRules::Type::PROXY_LIST_PER_SCHEME,
425           nullptr,
426           nullptr,
427           nullptr,
428           nullptr,
429           "SOCKS foopy:1080",
430       },
431 
432       // SOCKS proxy present along with other proxies too
433       {
434           "http=httpproxy ; https=httpsproxy ; ftp=ftpproxy ; socks=foopy ",
435 
436           ProxyConfig::ProxyRules::Type::PROXY_LIST_PER_SCHEME,
437           nullptr,
438           "PROXY httpproxy:80",
439           "PROXY httpsproxy:80",
440           "PROXY ftpproxy:80",
441           "SOCKS foopy:1080",
442       },
443 
444       // SOCKS proxy (with modifier) present along with some proxies
445       // (FTP being blank)
446       {
447           "http=httpproxy ; https=httpsproxy ; socks=socks5://foopy ",
448 
449           ProxyConfig::ProxyRules::Type::PROXY_LIST_PER_SCHEME,
450           nullptr,
451           "PROXY httpproxy:80",
452           "PROXY httpsproxy:80",
453           nullptr,
454           "SOCKS5 foopy:1080",
455       },
456 
457       // Include unsupported schemes -- they are discarded.
458       {
459           "crazy=foopy ; foo=bar ; https=myhttpsproxy",
460 
461           ProxyConfig::ProxyRules::Type::PROXY_LIST_PER_SCHEME,
462           nullptr,
463           nullptr,
464           "PROXY myhttpsproxy:80",
465           nullptr,
466           nullptr,
467       },
468 
469       // direct:// as first option for a scheme.
470       {
471           "http=direct://,myhttpproxy; https=direct://",
472 
473           ProxyConfig::ProxyRules::Type::PROXY_LIST_PER_SCHEME,
474           nullptr,
475           "DIRECT;PROXY myhttpproxy:80",
476           "DIRECT",
477           nullptr,
478           nullptr,
479       },
480 
481       // direct:// as a second option for a scheme.
482       {
483           "http=myhttpproxy,direct://",
484 
485           ProxyConfig::ProxyRules::Type::PROXY_LIST_PER_SCHEME,
486           nullptr,
487           "PROXY myhttpproxy:80;DIRECT",
488           nullptr,
489           nullptr,
490           nullptr,
491       },
492 
493       // Multi-proxy bracketed URIs will result in no proxy being set
494       {
495           "http=[https://proxy1:8080 https://proxy2:8080]",
496           ProxyConfig::ProxyRules::Type::PROXY_LIST_PER_SCHEME,
497           nullptr,
498           nullptr,
499           nullptr,
500           nullptr,
501           nullptr,
502       }
503 
504   };
505 
506   ProxyConfig config;
507 
508   for (const auto& test : tests) {
509     config.proxy_rules().ParseFromString(test.proxy_rules);
510     EXPECT_EQ(test.type, config.proxy_rules().type);
511     ExpectProxyServerEquals(test.single_proxy,
512                             config.proxy_rules().single_proxies);
513     ExpectProxyServerEquals(test.proxy_for_http,
514                             config.proxy_rules().proxies_for_http);
515     ExpectProxyServerEquals(test.proxy_for_https,
516                             config.proxy_rules().proxies_for_https);
517     ExpectProxyServerEquals(test.proxy_for_ftp,
518                             config.proxy_rules().proxies_for_ftp);
519     ExpectProxyServerEquals(test.fallback_proxy,
520                             config.proxy_rules().fallback_proxies);
521   }
522 }
523 
524 #if BUILDFLAG(ENABLE_QUIC_PROXY_SUPPORT)
525 // When the bool to allow quic proxy support is false, there should be no valid
526 // proxies in the config.
TEST(ProxyConfigTest,ParseProxyRulesQuicIsNotAllowed)527 TEST(ProxyConfigTest, ParseProxyRulesQuicIsNotAllowed) {
528   ProxyConfig config;
529 
530   config.proxy_rules().ParseFromString("quic://foopy:443",
531                                        /*allow_bracketed_proxy_chains=*/false,
532                                        /*is_quic_allowed=*/false);
533 
534   EXPECT_EQ(ProxyConfig::ProxyRules::Type::PROXY_LIST,
535             config.proxy_rules().type);
536   ExpectProxyServerEquals(nullptr, config.proxy_rules().single_proxies);
537   ExpectProxyServerEquals(nullptr, config.proxy_rules().proxies_for_http);
538   ExpectProxyServerEquals(nullptr, config.proxy_rules().proxies_for_https);
539   ExpectProxyServerEquals(nullptr, config.proxy_rules().proxies_for_ftp);
540   ExpectProxyServerEquals(nullptr, config.proxy_rules().fallback_proxies);
541 }
542 
543 // When the bool to allow quic proxy support is true, a valid quic proxy should
544 // be found in the config.
TEST(ProxyConfigTest,ParseProxyRulesQuicIsAllowed)545 TEST(ProxyConfigTest, ParseProxyRulesQuicIsAllowed) {
546   ProxyConfig config;
547 
548   config.proxy_rules().ParseFromString("quic://foopy:443",
549                                        /*allow_bracketed_proxy_chains=*/false,
550                                        /*is_quic_allowed=*/true);
551 
552   EXPECT_EQ(ProxyConfig::ProxyRules::Type::PROXY_LIST,
553             config.proxy_rules().type);
554   ExpectProxyServerEquals("QUIC foopy:443",
555                           config.proxy_rules().single_proxies);
556   ExpectProxyServerEquals(nullptr, config.proxy_rules().proxies_for_http);
557   ExpectProxyServerEquals(nullptr, config.proxy_rules().proxies_for_https);
558   ExpectProxyServerEquals(nullptr, config.proxy_rules().proxies_for_ftp);
559   ExpectProxyServerEquals(nullptr, config.proxy_rules().fallback_proxies);
560 }
561 #endif  // BUILDFLAG(ENABLE_QUIC_PROXY_SUPPORT)
562 
563 #if !BUILDFLAG(ENABLE_QUIC_PROXY_SUPPORT)
564 // When the build flag is disabled for QUIC support, `ParseFromString` should
565 // not allow QUIC proxy support by setting bool to true. A true value should
566 // crash.
TEST(ProxyConfigTest,ParseProxyRulesDisallowQuicProxySupportIfBuildFlagDisabled)567 TEST(ProxyConfigTest,
568      ParseProxyRulesDisallowQuicProxySupportIfBuildFlagDisabled) {
569   ProxyConfig config;
570 
571   EXPECT_CHECK_DEATH(config.proxy_rules().ParseFromString(
572       "quic://foopy:443",
573       /*allow_bracketed_proxy_chains=*/false, /*is_quic_allowed=*/true));
574 }
575 #endif  // !BUILDFLAG(ENABLE_QUIC_PROXY_SUPPORT)
576 
577 #if !BUILDFLAG(ENABLE_BRACKETED_PROXY_URIS)
578 // In release builds, `ParseFromString` should not allow parsing of multi-proxy
579 // chains by setting bool to true. A true value should crash.
TEST(ProxyConfigTest,ParseProxyRulesDisallowMultiProxyChainsInReleaseBuilds)580 TEST(ProxyConfigTest, ParseProxyRulesDisallowMultiProxyChainsInReleaseBuilds) {
581   ProxyConfig config;
582 
583   EXPECT_CHECK_DEATH(config.proxy_rules().ParseFromString(
584       "http=[https://proxy1:8080 https://proxy2:8080]", true));
585 }
586 #endif  // !BUILDFLAG(ENABLE_BRACKETED_PROXY_URIS)
587 
588 #if BUILDFLAG(ENABLE_BRACKETED_PROXY_URIS)
589 // Tests for multi-proxy chains which are currently only allowed in debug mode.
TEST(ProxyConfigTest,MultiProxyChainsParseProxyRules)590 TEST(ProxyConfigTest, MultiProxyChainsParseProxyRules) {
591   const struct {
592     const char* proxy_rules;
593 
594     ProxyConfig::ProxyRules::Type type;
595     // For multi-proxy chains, proxies within a single chain will be formatted
596     // within a bracket separated by a space and comma.
597     const char* single_proxy;
598     const char* proxy_for_http;
599     const char* proxy_for_https;
600     const char* proxy_for_ftp;
601     const char* fallback_proxy;
602   } tests[] = {
603 
604       // One HTTP proxy for all schemes.
605       {
606           "[https://proxy1:8080]",
607           ProxyConfig::ProxyRules::Type::PROXY_LIST,
608           "HTTPS proxy1:8080",
609           nullptr,
610           nullptr,
611           nullptr,
612           nullptr,
613       },
614 
615       // Multiple proxies for all schemes.
616       {
617           "[https://proxy1:8080 https://proxy2:8080],[https://proxy3:8080]",
618           ProxyConfig::ProxyRules::Type::PROXY_LIST,
619           "[https://proxy1:8080, https://proxy2:8080];HTTPS proxy3:8080",
620           nullptr,
621           nullptr,
622           nullptr,
623           nullptr,
624       },
625 
626       // Only specify a proxy chain for "http://" urls.
627       {
628           "http=[https://proxy1:8080 https://proxy2:8080]",
629           ProxyConfig::ProxyRules::Type::PROXY_LIST_PER_SCHEME,
630           nullptr,
631           "[https://proxy1:8080, https://proxy2:8080]",
632           nullptr,
633           nullptr,
634           nullptr,
635       },
636 
637       // Specify different multi-proxy chains for different schemes.
638       {
639           "http=[https://proxy1:8080 https://proxy2:8080] ; "
640           "https=[https://proxy3:8080 https://proxy4:8080]",
641           ProxyConfig::ProxyRules::Type::PROXY_LIST_PER_SCHEME,
642           nullptr,
643           "[https://proxy1:8080, https://proxy2:8080]",
644           "[https://proxy3:8080, https://proxy4:8080]",
645           nullptr,
646           nullptr,
647       },
648 
649       // Give a scheme-specific proxy as well as a non-scheme specific.
650       // The first entry takes precedence marking this list as Type::PROXY_LIST.
651       {
652           "[https://proxy1:8080 https://proxy2:8080] ; "
653           "http=[https://proxy3:8080 https://proxy4:8080]",
654           ProxyConfig::ProxyRules::Type::PROXY_LIST,
655           "[https://proxy1:8080, https://proxy2:8080]",
656           nullptr,
657           nullptr,
658           nullptr,
659           nullptr,
660       },
661 
662       // Give a scheme-specific proxy as well as a non-scheme specific.
663       // The first entry takes precedence marking this list as
664       // Type::PROXY_LIST_PER_SCHEME.
665       {
666           "http=[https://proxy3:8080 https://proxy4:8080] ; "
667           "[https://proxy1:8080 https://proxy2:8080]",
668           ProxyConfig::ProxyRules::Type::PROXY_LIST_PER_SCHEME,
669           nullptr,
670           "[https://proxy3:8080, https://proxy4:8080]",
671           nullptr,
672           nullptr,
673           nullptr,
674       },
675 
676       // Include a list of entries for a single scheme.
677       {
678           "ftp=[https://proxy1:80 https://proxy2:80],[https://proxy3:80 "
679           "https://proxy4:80],[https://proxy5:80 https://proxy6:80]",
680           ProxyConfig::ProxyRules::Type::PROXY_LIST_PER_SCHEME,
681           nullptr,
682           nullptr,
683           nullptr,
684           "[https://proxy1:80, https://proxy2:80];[https://proxy3:80, "
685           "https://proxy4:80];[https://proxy5:80, https://proxy6:80]",
686           nullptr,
687       },
688 
689       // Include multiple entries for the same scheme -- they accumulate.
690       {
691           "http=[https://proxy1:80 https://proxy2:80]; http=[https://proxy3:80 "
692           "https://proxy4:80],[https://proxy5:80 https://proxy6:80]",
693           ProxyConfig::ProxyRules::Type::PROXY_LIST_PER_SCHEME,
694           nullptr,
695           "[https://proxy1:80, https://proxy2:80];[https://proxy3:80, "
696           "https://proxy4:80];[https://proxy5:80, https://proxy6:80]",
697           nullptr,
698           nullptr,
699           nullptr,
700       },
701 
702       // Include lists of entries for multiple schemes.
703       {
704           "http=[https://proxy1:80 https://proxy2:80]; ftp=[https://proxy3:80 "
705           "https://proxy4:80],[https://proxy5:80 https://proxy6:80]",
706           ProxyConfig::ProxyRules::Type::PROXY_LIST_PER_SCHEME,
707           nullptr,
708           "[https://proxy1:80, https://proxy2:80]",
709           nullptr,
710           "[https://proxy3:80, https://proxy4:80];[https://proxy5:80, "
711           "https://proxy6:80]",
712           nullptr,
713       },
714 
715       // Include unsupported schemes -- they are discarded.
716       {
717           "crazy=[https://proxy1:80 https://proxy2:80] ; foo=bar ; "
718           "https=[https://proxy3:80 https://proxy4:80]",
719 
720           ProxyConfig::ProxyRules::Type::PROXY_LIST_PER_SCHEME,
721           nullptr,
722           nullptr,
723           "[https://proxy3:80, https://proxy4:80]",
724           nullptr,
725           nullptr,
726       },
727   };
728 
729   ProxyConfig config;
730 
731   for (const auto& test : tests) {
732     config.proxy_rules().ParseFromString(test.proxy_rules, true);
733     EXPECT_EQ(test.type, config.proxy_rules().type);
734     ExpectProxyServerEquals(test.single_proxy,
735                             config.proxy_rules().single_proxies);
736     ExpectProxyServerEquals(test.proxy_for_http,
737                             config.proxy_rules().proxies_for_http);
738     ExpectProxyServerEquals(test.proxy_for_https,
739                             config.proxy_rules().proxies_for_https);
740     ExpectProxyServerEquals(test.proxy_for_ftp,
741                             config.proxy_rules().proxies_for_ftp);
742     ExpectProxyServerEquals(test.fallback_proxy,
743                             config.proxy_rules().fallback_proxies);
744   }
745 }
746 #endif  // BUILDFLAG(ENABLE_BRACKETED_PROXY_URIS)
747 
TEST(ProxyConfigTest,ProxyRulesSetBypassFlag)748 TEST(ProxyConfigTest, ProxyRulesSetBypassFlag) {
749   // Test whether the did_bypass_proxy() flag is set in proxy info correctly.
750   ProxyConfig::ProxyRules rules;
751   ProxyInfo result;
752 
753   rules.ParseFromString("http=httpproxy:80");
754   rules.bypass_rules.AddRuleFromString(".com");
755 
756   rules.Apply(GURL("http://example.com"), &result);
757   EXPECT_TRUE(result.is_direct_only());
758   EXPECT_TRUE(result.did_bypass_proxy());
759 
760   rules.Apply(GURL("http://example.org"), &result);
761   EXPECT_FALSE(result.is_direct());
762   EXPECT_FALSE(result.did_bypass_proxy());
763 
764   // Try with reversed bypass rules.
765   rules.reverse_bypass = true;
766 
767   rules.Apply(GURL("http://example.org"), &result);
768   EXPECT_TRUE(result.is_direct_only());
769   EXPECT_TRUE(result.did_bypass_proxy());
770 
771   rules.Apply(GURL("http://example.com"), &result);
772   EXPECT_FALSE(result.is_direct());
773   EXPECT_FALSE(result.did_bypass_proxy());
774 }
775 
776 static const char kWsUrl[] = "ws://example.com/echo";
777 static const char kWssUrl[] = "wss://example.com/echo";
778 
779 class ProxyConfigWebSocketTest : public ::testing::Test {
780  protected:
ParseFromString(const std::string & rules)781   void ParseFromString(const std::string& rules) {
782     rules_.ParseFromString(rules);
783   }
Apply(const GURL & gurl)784   void Apply(const GURL& gurl) { rules_.Apply(gurl, &info_); }
ToDebugString() const785   std::string ToDebugString() const { return info_.ToDebugString(); }
786 
WsUrl()787   static GURL WsUrl() { return GURL(kWsUrl); }
WssUrl()788   static GURL WssUrl() { return GURL(kWssUrl); }
789 
790   ProxyConfig::ProxyRules rules_;
791   ProxyInfo info_;
792 };
793 
794 // If a single proxy is set for all protocols, WebSocket uses it.
TEST_F(ProxyConfigWebSocketTest,UsesProxy)795 TEST_F(ProxyConfigWebSocketTest, UsesProxy) {
796   ParseFromString("proxy:3128");
797   Apply(WsUrl());
798   EXPECT_EQ("PROXY proxy:3128", ToDebugString());
799 }
800 
801 // See RFC6455 Section 4.1. item 3, "_Proxy Usage_". Note that this favors a
802 // SOCKSv4 proxy (although technically the spec only notes SOCKSv5).
TEST_F(ProxyConfigWebSocketTest,PrefersSocksV4)803 TEST_F(ProxyConfigWebSocketTest, PrefersSocksV4) {
804   ParseFromString(
805       "http=proxy:3128 ; https=sslproxy:3128 ; socks=socksproxy:1080");
806   Apply(WsUrl());
807   EXPECT_EQ("SOCKS socksproxy:1080", ToDebugString());
808 }
809 
810 // See RFC6455 Section 4.1. item 3, "_Proxy Usage_".
TEST_F(ProxyConfigWebSocketTest,PrefersSocksV5)811 TEST_F(ProxyConfigWebSocketTest, PrefersSocksV5) {
812   ParseFromString(
813       "http=proxy:3128 ; https=sslproxy:3128 ; socks=socks5://socksproxy:1080");
814   Apply(WsUrl());
815   EXPECT_EQ("SOCKS5 socksproxy:1080", ToDebugString());
816 }
817 
TEST_F(ProxyConfigWebSocketTest,PrefersHttpsToHttp)818 TEST_F(ProxyConfigWebSocketTest, PrefersHttpsToHttp) {
819   ParseFromString("http=proxy:3128 ; https=sslproxy:3128");
820   Apply(WssUrl());
821   EXPECT_EQ("PROXY sslproxy:3128", ToDebugString());
822 }
823 
824 // Tests when a proxy-per-url-scheme configuration was used, and proxies are
825 // specified for http://, https://, and a fallback proxy (non-SOCKS).
826 // Even though the fallback proxy is not SOCKS, it is still favored over the
827 // proxy for http://* and https://*.
TEST_F(ProxyConfigWebSocketTest,PrefersNonSocksFallbackOverHttps)828 TEST_F(ProxyConfigWebSocketTest, PrefersNonSocksFallbackOverHttps) {
829   // The notation for "socks=" is abused to set the "fallback proxy".
830   ParseFromString(
831       "http=proxy:3128 ; https=sslproxy:3128; socks=https://httpsproxy");
832   EXPECT_EQ("HTTPS httpsproxy:443", rules_.fallback_proxies.ToDebugString());
833   Apply(WssUrl());
834   EXPECT_EQ("HTTPS httpsproxy:443", ToDebugString());
835 }
836 
837 // Tests when a proxy-per-url-scheme configuration was used, and the fallback
838 // proxy is a non-SOCKS proxy, and no proxy was given for https://* or
839 // http://*. The fallback proxy is used.
TEST_F(ProxyConfigWebSocketTest,UsesNonSocksFallbackProxy)840 TEST_F(ProxyConfigWebSocketTest, UsesNonSocksFallbackProxy) {
841   // The notation for "socks=" is abused to set the "fallback proxy".
842   ParseFromString("ftp=ftpproxy:3128; socks=https://httpsproxy");
843   EXPECT_EQ("HTTPS httpsproxy:443", rules_.fallback_proxies.ToDebugString());
844   Apply(WssUrl());
845   EXPECT_EQ("HTTPS httpsproxy:443", ToDebugString());
846 }
847 
TEST_F(ProxyConfigWebSocketTest,PrefersHttpsEvenForWs)848 TEST_F(ProxyConfigWebSocketTest, PrefersHttpsEvenForWs) {
849   ParseFromString("http=proxy:3128 ; https=sslproxy:3128");
850   Apply(WsUrl());
851   EXPECT_EQ("PROXY sslproxy:3128", ToDebugString());
852 }
853 
TEST_F(ProxyConfigWebSocketTest,PrefersHttpToDirect)854 TEST_F(ProxyConfigWebSocketTest, PrefersHttpToDirect) {
855   ParseFromString("http=proxy:3128");
856   Apply(WssUrl());
857   EXPECT_EQ("PROXY proxy:3128", ToDebugString());
858 }
859 
TEST_F(ProxyConfigWebSocketTest,IgnoresFtpProxy)860 TEST_F(ProxyConfigWebSocketTest, IgnoresFtpProxy) {
861   ParseFromString("ftp=ftpproxy:3128");
862   Apply(WssUrl());
863   EXPECT_EQ("DIRECT", ToDebugString());
864 }
865 
TEST_F(ProxyConfigWebSocketTest,ObeysBypassRules)866 TEST_F(ProxyConfigWebSocketTest, ObeysBypassRules) {
867   ParseFromString("http=proxy:3128 ; https=sslproxy:3128");
868   rules_.bypass_rules.AddRuleFromString(".chromium.org");
869   Apply(GURL("wss://codereview.chromium.org/feed"));
870   EXPECT_EQ("DIRECT", ToDebugString());
871 }
872 
TEST_F(ProxyConfigWebSocketTest,ObeysLocalBypass)873 TEST_F(ProxyConfigWebSocketTest, ObeysLocalBypass) {
874   ParseFromString("http=proxy:3128 ; https=sslproxy:3128");
875   rules_.bypass_rules.AddRuleFromString("<local>");
876   Apply(GURL("ws://localhost/feed"));
877   EXPECT_EQ("DIRECT", ToDebugString());
878 }
879 
880 }  // namespace
881 }  // namespace net
882