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