xref: /aosp_15_r20/external/cronet/net/proxy_resolution/proxy_bypass_rules_unittest.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2010 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_bypass_rules.h"
6 
7 #include "base/strings/string_util.h"
8 #include "build/build_config.h"
9 #include "net/proxy_resolution/proxy_config_service_common_unittest.h"
10 #include "testing/gtest/include/gtest/gtest.h"
11 
12 #if BUILDFLAG(IS_WIN)
13 // On Windows, "loopback" resolves to localhost and is implicitly bypassed to
14 // match WinInet.
15 #define BYPASS_LOOPBACK
16 #endif
17 
18 namespace net {
19 
20 namespace {
21 
22 // Calls |rules.Matches()| for each name in |hosts| (for various URL schemes),
23 // and checks that the result is |bypasses|. If the host is in |inverted_hosts|
24 // then the expectation is reversed.
ExpectRulesMatch(const ProxyBypassRules & rules,const char * hosts[],size_t num_hosts,bool bypasses,const std::set<std::string> & inverted_hosts)25 void ExpectRulesMatch(const ProxyBypassRules& rules,
26                       const char* hosts[],
27                       size_t num_hosts,
28                       bool bypasses,
29                       const std::set<std::string>& inverted_hosts) {
30   // The scheme of the URL shouldn't matter.
31   const char* kUrlSchemes[] = {"http://", "https://", "ftp://"};
32 
33   for (auto* scheme : kUrlSchemes) {
34     for (size_t i = 0; i < num_hosts; ++i) {
35       const char* host = hosts[i];
36 
37       bool expectation = bypasses;
38 
39       if (inverted_hosts.count(std::string(host)) != 0)
40         expectation = !expectation;
41 
42       std::string url = std::string(scheme) + std::string(host);
43 
44       EXPECT_EQ(expectation, rules.Matches(GURL(url))) << url;
45     }
46   }
47 }
48 
49 // Tests calling |rules.Matches()| for localhost URLs returns |bypasses|.
ExpectBypassLocalhost(const ProxyBypassRules & rules,bool bypasses,const std::set<std::string> & inverted_hosts=std::set<std::string> ())50 void ExpectBypassLocalhost(
51     const ProxyBypassRules& rules,
52     bool bypasses,
53     const std::set<std::string>& inverted_hosts = std::set<std::string>()) {
54   const char* kHosts[] = {
55     "localhost",
56     "localhost.",
57     "foo.localhost",
58     "127.0.0.1",
59     "127.100.0.2",
60     "[::1]",
61     "[::0:FFFF:127.0.0.1]",
62     "[::fFfF:127.100.0.0]",
63     "[0::ffff:7f00:1]",
64 #if defined(BYPASS_LOOPBACK)
65     "loopback",
66     "loopback.",
67 #endif
68   };
69 
70   ExpectRulesMatch(rules, kHosts, std::size(kHosts), bypasses, inverted_hosts);
71 }
72 
73 // Tests calling |rules.Matches()| for link-local URLs returns |bypasses|.
ExpectBypassLinkLocal(const ProxyBypassRules & rules,bool bypasses)74 void ExpectBypassLinkLocal(const ProxyBypassRules& rules, bool bypasses) {
75   const char* kHosts[] = {
76       "169.254.3.2", "169.254.100.1",        "[FE80::8]",
77       "[fe91::1]",   "[::ffff:169.254.3.2]",
78   };
79 
80   ExpectRulesMatch(rules, kHosts, std::size(kHosts), bypasses, {});
81 }
82 
83 // Tests calling |rules.Matches()| with miscelaneous URLs that are neither
84 // localhost or link local IPs, returns |bypasses|.
ExpectBypassMisc(const ProxyBypassRules & rules,bool bypasses,const std::set<std::string> & inverted_hosts=std::set<std::string> ())85 void ExpectBypassMisc(
86     const ProxyBypassRules& rules,
87     bool bypasses,
88     const std::set<std::string>& inverted_hosts = std::set<std::string>()) {
89   const char* kHosts[] = {
90     "192.168.0.1",
91     "170.254.0.0",
92     "128.0.0.1",
93     "[::2]",
94     "[FD80::1]",
95     "foo",
96     "www.example3.com",
97     "[::ffff:128.0.0.1]",
98     "[::ffff:126.100.0.0]",
99     "[::ffff::ffff:127.0.0.1]",
100     "[::ffff:0:127.0.0.1]",
101     "[::127.0.0.1]",
102 #if !defined(BYPASS_LOOPBACK)
103     "loopback",
104     "loopback.",
105 #endif
106   };
107 
108   ExpectRulesMatch(rules, kHosts, std::size(kHosts), bypasses, inverted_hosts);
109 }
110 
TEST(ProxyBypassRulesTest,ParseAndMatchBasicHost)111 TEST(ProxyBypassRulesTest, ParseAndMatchBasicHost) {
112   ProxyBypassRules rules;
113   rules.ParseFromString("wWw.gOogle.com");
114   ASSERT_EQ(1u, rules.rules().size());
115   // Hostname rules are normalized to lower-case.
116   EXPECT_EQ("www.google.com", rules.rules()[0]->ToString());
117 
118   // All of these match; port, scheme, and non-hostname components don't
119   // matter.
120   EXPECT_TRUE(rules.Matches(GURL("http://www.google.com")));
121   EXPECT_TRUE(rules.Matches(GURL("ftp://www.google.com:99")));
122   EXPECT_TRUE(rules.Matches(GURL("https://www.google.com:81")));
123 
124   // Must be a strict host match to work.
125   EXPECT_FALSE(rules.Matches(GURL("http://foo.www.google.com")));
126   EXPECT_FALSE(rules.Matches(GURL("http://xxx.google.com")));
127   EXPECT_FALSE(rules.Matches(GURL("http://google.com")));
128   EXPECT_FALSE(rules.Matches(GURL("http://www.google.com.baz.org")));
129 }
130 
TEST(ProxyBypassRulesTest,ParseAndMatchBasicDomain)131 TEST(ProxyBypassRulesTest, ParseAndMatchBasicDomain) {
132   ProxyBypassRules rules;
133   rules.ParseFromString(".gOOgle.com");
134   ASSERT_EQ(1u, rules.rules().size());
135   // Hostname rules are normalized to lower-case.
136   // Note that we inferred this was an "ends with" test.
137   EXPECT_EQ("*.google.com", rules.rules()[0]->ToString());
138 
139   // All of these match; port, scheme, and non-hostname components don't
140   // matter.
141   EXPECT_TRUE(rules.Matches(GURL("http://www.google.com")));
142   EXPECT_TRUE(rules.Matches(GURL("ftp://www.google.com:99")));
143   EXPECT_TRUE(rules.Matches(GURL("https://a.google.com:81")));
144   EXPECT_TRUE(rules.Matches(GURL("http://foo.google.com/x/y?q")));
145   EXPECT_TRUE(rules.Matches(GURL("http://foo:[email protected]#x")));
146 
147   // Must be a strict "ends with" to work.
148   EXPECT_FALSE(rules.Matches(GURL("http://google.com")));
149   EXPECT_FALSE(rules.Matches(GURL("http://foo.google.com.baz.org")));
150 }
151 
TEST(ProxyBypassRulesTest,ParseAndMatchBasicDomainWithPort)152 TEST(ProxyBypassRulesTest, ParseAndMatchBasicDomainWithPort) {
153   ProxyBypassRules rules;
154   rules.ParseFromString("*.GOOGLE.com:80");
155   ASSERT_EQ(1u, rules.rules().size());
156   // Hostname rules are normalized to lower-case.
157   EXPECT_EQ("*.google.com:80", rules.rules()[0]->ToString());
158 
159   // All of these match; scheme, and non-hostname components don't matter.
160   EXPECT_TRUE(rules.Matches(GURL("http://www.google.com")));
161   EXPECT_TRUE(rules.Matches(GURL("ftp://www.google.com:80")));
162   EXPECT_TRUE(rules.Matches(GURL("https://a.google.com:80?x")));
163 
164   // Must be a strict "ends with" to work.
165   EXPECT_FALSE(rules.Matches(GURL("http://google.com")));
166   EXPECT_FALSE(rules.Matches(GURL("http://foo.google.com.baz.org")));
167 
168   // The ports must match.
169   EXPECT_FALSE(rules.Matches(GURL("http://www.google.com:90")));
170   EXPECT_FALSE(rules.Matches(GURL("https://www.google.com")));
171 }
172 
TEST(ProxyBypassRulesTest,MatchAll)173 TEST(ProxyBypassRulesTest, MatchAll) {
174   ProxyBypassRules rules;
175   rules.ParseFromString("*");
176   ASSERT_EQ(1u, rules.rules().size());
177   EXPECT_EQ("*", rules.rules()[0]->ToString());
178 
179   EXPECT_TRUE(rules.Matches(GURL("http://www.google.com")));
180   EXPECT_TRUE(rules.Matches(GURL("ftp://www.foobar.com:99")));
181   EXPECT_TRUE(rules.Matches(GURL("https://a.google.com:80?x")));
182 }
183 
TEST(ProxyBypassRulesTest,WildcardAtStart)184 TEST(ProxyBypassRulesTest, WildcardAtStart) {
185   ProxyBypassRules rules;
186   rules.ParseFromString("*.org:443");
187   ASSERT_EQ(1u, rules.rules().size());
188   EXPECT_EQ("*.org:443", rules.rules()[0]->ToString());
189 
190   EXPECT_TRUE(rules.Matches(GURL("http://www.google.org:443")));
191   EXPECT_TRUE(rules.Matches(GURL("https://www.google.org")));
192 
193   EXPECT_FALSE(rules.Matches(GURL("http://www.google.org")));
194   EXPECT_FALSE(rules.Matches(GURL("https://www.google.com")));
195   EXPECT_FALSE(rules.Matches(GURL("https://www.google.org.com")));
196 }
197 
198 // Tests a codepath that parses hostnamepattern:port, where "port" is invalid
199 // by containing a leading plus.
TEST(ProxyBypassRulesTest,ParseInvalidPort)200 TEST(ProxyBypassRulesTest, ParseInvalidPort) {
201   ProxyBypassRules rules;
202   EXPECT_TRUE(rules.AddRuleFromString("*.org:443"));
203   EXPECT_FALSE(rules.AddRuleFromString("*.com:+443"));
204   EXPECT_FALSE(rules.AddRuleFromString("*.com:-443"));
205 }
206 
TEST(ProxyBypassRulesTest,IPV4Address)207 TEST(ProxyBypassRulesTest, IPV4Address) {
208   ProxyBypassRules rules;
209   rules.ParseFromString("192.168.1.1");
210   ASSERT_EQ(1u, rules.rules().size());
211   EXPECT_EQ("192.168.1.1", rules.rules()[0]->ToString());
212 
213   EXPECT_TRUE(rules.Matches(GURL("http://192.168.1.1")));
214   EXPECT_TRUE(rules.Matches(GURL("https://192.168.1.1:90")));
215 
216   EXPECT_FALSE(rules.Matches(GURL("http://www.google.com")));
217   EXPECT_FALSE(rules.Matches(GURL("http://sup.192.168.1.1")));
218 }
219 
TEST(ProxyBypassRulesTest,IPV4AddressWithPort)220 TEST(ProxyBypassRulesTest, IPV4AddressWithPort) {
221   ProxyBypassRules rules;
222   rules.ParseFromString("192.168.1.1:33");
223   ASSERT_EQ(1u, rules.rules().size());
224   EXPECT_EQ("192.168.1.1:33", rules.rules()[0]->ToString());
225 
226   EXPECT_TRUE(rules.Matches(GURL("http://192.168.1.1:33")));
227 
228   EXPECT_FALSE(rules.Matches(GURL("http://www.google.com")));
229   EXPECT_FALSE(rules.Matches(GURL("http://192.168.1.1")));
230   EXPECT_FALSE(rules.Matches(GURL("http://sup.192.168.1.1:33")));
231 }
232 
TEST(ProxyBypassRulesTest,IPV6Address)233 TEST(ProxyBypassRulesTest, IPV6Address) {
234   ProxyBypassRules rules;
235   rules.ParseFromString("[3ffe:2a00:100:7031:0:0::1]");
236   ASSERT_EQ(1u, rules.rules().size());
237   // Note that we canonicalized the IP address.
238   EXPECT_EQ("[3ffe:2a00:100:7031::1]", rules.rules()[0]->ToString());
239 
240   EXPECT_TRUE(rules.Matches(GURL("http://[3ffe:2a00:100:7031::1]")));
241   EXPECT_TRUE(rules.Matches(GURL("http://[3ffe:2a00:100:7031::1]:33")));
242 
243   EXPECT_FALSE(rules.Matches(GURL("http://www.google.com")));
244   EXPECT_FALSE(rules.Matches(GURL("http://sup.192.168.1.1:33")));
245 }
246 
TEST(ProxyBypassRulesTest,IPV6AddressWithPort)247 TEST(ProxyBypassRulesTest, IPV6AddressWithPort) {
248   ProxyBypassRules rules;
249   rules.ParseFromString("[3ffe:2a00:100:7031::1]:33");
250   ASSERT_EQ(1u, rules.rules().size());
251   EXPECT_EQ("[3ffe:2a00:100:7031::1]:33", rules.rules()[0]->ToString());
252 
253   EXPECT_TRUE(rules.Matches(GURL("http://[3ffe:2a00:100:7031::1]:33")));
254 
255   EXPECT_FALSE(rules.Matches(GURL("http://[3ffe:2a00:100:7031::1]")));
256   EXPECT_FALSE(rules.Matches(GURL("http://www.google.com")));
257 }
258 
TEST(ProxyBypassRulesTest,HTTPOnly)259 TEST(ProxyBypassRulesTest, HTTPOnly) {
260   ProxyBypassRules rules;
261   rules.ParseFromString("http://www.google.com");
262   ASSERT_EQ(1u, rules.rules().size());
263   EXPECT_EQ("http://www.google.com", rules.rules()[0]->ToString());
264 
265   EXPECT_TRUE(rules.Matches(GURL("http://www.google.com/foo")));
266   EXPECT_TRUE(rules.Matches(GURL("http://www.google.com:99")));
267 
268   EXPECT_FALSE(rules.Matches(GURL("https://www.google.com")));
269   EXPECT_FALSE(rules.Matches(GURL("ftp://www.google.com")));
270   EXPECT_FALSE(rules.Matches(GURL("http://foo.www.google.com")));
271   EXPECT_FALSE(rules.Matches(GURL("http://www.google.com.org")));
272   EXPECT_FALSE(rules.Matches(GURL("https://www.google.com")));
273 }
274 
TEST(ProxyBypassRulesTest,HTTPOnlyWithWildcard)275 TEST(ProxyBypassRulesTest, HTTPOnlyWithWildcard) {
276   ProxyBypassRules rules;
277   rules.ParseFromString("http://*www.google.com");
278   ASSERT_EQ(1u, rules.rules().size());
279   EXPECT_EQ("http://*www.google.com", rules.rules()[0]->ToString());
280 
281   EXPECT_TRUE(rules.Matches(GURL("http://www.google.com/foo")));
282   EXPECT_TRUE(rules.Matches(GURL("http://www.google.com:99")));
283   EXPECT_TRUE(rules.Matches(GURL("http://foo.www.google.com")));
284 
285   EXPECT_FALSE(rules.Matches(GURL("https://www.google.com")));
286   EXPECT_FALSE(rules.Matches(GURL("ftp://www.google.com")));
287   EXPECT_FALSE(rules.Matches(GURL("http://www.google.com.org")));
288   EXPECT_FALSE(rules.Matches(GURL("https://www.google.com")));
289 }
290 
TEST(ProxyBypassRulesTest,DoesNotUseSuffixMatching)291 TEST(ProxyBypassRulesTest, DoesNotUseSuffixMatching) {
292   ProxyBypassRules rules;
293   rules.ParseFromString(
294       "foo1.com, .foo2.com, 192.168.1.1, "
295       "*foobar.com:80, *.foo, http://baz, <local>");
296   ASSERT_EQ(7u, rules.rules().size());
297   EXPECT_EQ("foo1.com", rules.rules()[0]->ToString());
298   EXPECT_EQ("*.foo2.com", rules.rules()[1]->ToString());
299   EXPECT_EQ("192.168.1.1", rules.rules()[2]->ToString());
300   EXPECT_EQ("*foobar.com:80", rules.rules()[3]->ToString());
301   EXPECT_EQ("*.foo", rules.rules()[4]->ToString());
302   EXPECT_EQ("http://baz", rules.rules()[5]->ToString());
303   EXPECT_EQ("<local>", rules.rules()[6]->ToString());
304 
305   EXPECT_TRUE(rules.Matches(GURL("http://foo1.com")));
306   EXPECT_FALSE(rules.Matches(GURL("http://aaafoo1.com")));
307   EXPECT_FALSE(rules.Matches(GURL("http://aaafoo1.com.net")));
308 }
309 
TEST(ProxyBypassRulesTest,MultipleRules)310 TEST(ProxyBypassRulesTest, MultipleRules) {
311   ProxyBypassRules rules;
312   rules.ParseFromString(".google.com , .foobar.com:30");
313   ASSERT_EQ(2u, rules.rules().size());
314 
315   EXPECT_TRUE(rules.Matches(GURL("http://baz.google.com:40")));
316   EXPECT_FALSE(rules.Matches(GURL("http://google.com:40")));
317   EXPECT_TRUE(rules.Matches(GURL("http://bar.foobar.com:30")));
318   EXPECT_FALSE(rules.Matches(GURL("http://bar.foobar.com")));
319   EXPECT_FALSE(rules.Matches(GURL("http://bar.foobar.com:33")));
320 }
321 
TEST(ProxyBypassRulesTest,BadInputs)322 TEST(ProxyBypassRulesTest, BadInputs) {
323   ProxyBypassRules rules;
324   EXPECT_FALSE(rules.AddRuleFromString("://"));
325   EXPECT_FALSE(rules.AddRuleFromString("  "));
326   EXPECT_FALSE(rules.AddRuleFromString("http://"));
327   EXPECT_FALSE(rules.AddRuleFromString("*.foo.com:-34"));
328   EXPECT_EQ(0u, rules.rules().size());
329 }
330 
TEST(ProxyBypassRulesTest,Equals)331 TEST(ProxyBypassRulesTest, Equals) {
332   ProxyBypassRules rules1;
333   ProxyBypassRules rules2;
334 
335   rules1.ParseFromString("foo1.com, .foo2.com");
336   rules2.ParseFromString("foo1.com,.FOo2.com");
337 
338   EXPECT_EQ(rules1, rules2);
339   EXPECT_EQ(rules2, rules1);
340 
341   rules1.ParseFromString(".foo2.com");
342   rules2.ParseFromString("foo1.com,.FOo2.com");
343 
344   EXPECT_FALSE(rules1 == rules2);
345   EXPECT_FALSE(rules2 == rules1);
346 }
347 
TEST(ProxyBypassRulesTest,BypassSimpleHostnames)348 TEST(ProxyBypassRulesTest, BypassSimpleHostnames) {
349   // Test the simple hostnames rule in isolation, by first removing the
350   // implicit rules.
351   ProxyBypassRules rules;
352   rules.ParseFromString("<-loopback>; <local>");
353 
354   ASSERT_EQ(2u, rules.rules().size());
355   EXPECT_EQ("<-loopback>", rules.rules()[0]->ToString());
356   EXPECT_EQ("<local>", rules.rules()[1]->ToString());
357 
358   EXPECT_TRUE(rules.Matches(GURL("http://example/")));
359 
360   EXPECT_FALSE(rules.Matches(GURL("http://example./")));
361   EXPECT_FALSE(rules.Matches(GURL("http://example.com/")));
362   EXPECT_FALSE(rules.Matches(GURL("http://[dead::beef]/")));
363   EXPECT_FALSE(rules.Matches(GURL("http://192.168.1.1/")));
364 
365   // Confusingly, <local> rule is NOT about localhost names.
366   ExpectBypassLocalhost(rules, false, {"localhost", "loopback"});
367 
368   // Should NOT bypass link-local addresses.
369   ExpectBypassLinkLocal(rules, false);
370 
371   // Should not bypass other names either (except for the ones with no dot).
372   ExpectBypassMisc(rules, false, {"foo", "loopback"});
373 }
374 
TEST(ProxyBypassRulesTest,ParseAndMatchCIDR_IPv4)375 TEST(ProxyBypassRulesTest, ParseAndMatchCIDR_IPv4) {
376   ProxyBypassRules rules;
377   rules.ParseFromString("192.168.1.1/16");
378   ASSERT_EQ(1u, rules.rules().size());
379   EXPECT_EQ("192.168.1.1/16", rules.rules()[0]->ToString());
380 
381   EXPECT_TRUE(rules.Matches(GURL("http://192.168.1.1")));
382   EXPECT_TRUE(rules.Matches(GURL("ftp://192.168.4.4")));
383   EXPECT_TRUE(rules.Matches(GURL("https://192.168.0.0:81")));
384   // Test that an IPv4 mapped IPv6 literal matches an IPv4 CIDR rule.
385   EXPECT_TRUE(rules.Matches(GURL("http://[::ffff:192.168.11.11]")));
386 
387   EXPECT_FALSE(rules.Matches(GURL("http://foobar.com")));
388   EXPECT_FALSE(rules.Matches(GURL("http://192.169.1.1")));
389   EXPECT_FALSE(rules.Matches(GURL("http://xxx.192.168.1.1")));
390   EXPECT_FALSE(rules.Matches(GURL("http://192.168.1.1.xx")));
391 }
392 
TEST(ProxyBypassRulesTest,ParseAndMatchCIDR_IPv6)393 TEST(ProxyBypassRulesTest, ParseAndMatchCIDR_IPv6) {
394   ProxyBypassRules rules;
395   rules.ParseFromString("a:b:c:d::/48");
396   ASSERT_EQ(1u, rules.rules().size());
397   EXPECT_EQ("a:b:c:d::/48", rules.rules()[0]->ToString());
398 
399   EXPECT_TRUE(rules.Matches(GURL("http://[A:b:C:9::]")));
400   EXPECT_FALSE(rules.Matches(GURL("http://foobar.com")));
401   EXPECT_FALSE(rules.Matches(GURL("http://192.169.1.1")));
402 
403   // Test that an IPv4 literal matches an IPv4 mapped IPv6 CIDR rule.
404   // This is the IPv4 mapped equivalent to 192.168.1.1/16.
405   rules.ParseFromString("::ffff:192.168.1.1/112");
406   EXPECT_TRUE(rules.Matches(GURL("http://[::ffff:192.168.1.3]")));
407   EXPECT_TRUE(rules.Matches(GURL("http://192.168.11.11")));
408   EXPECT_FALSE(rules.Matches(GURL("http://10.10.1.1")));
409 
410   // Test using an IP range that is close to IPv4 mapped, but not
411   // quite. Should not result in matches.
412   rules.ParseFromString("::fffe:192.168.1.1/112");
413   EXPECT_TRUE(rules.Matches(GURL("http://[::fffe:192.168.1.3]")));
414   EXPECT_FALSE(rules.Matches(GURL("http://[::ffff:192.168.1.3]")));
415   EXPECT_FALSE(rules.Matches(GURL("http://192.168.11.11")));
416   EXPECT_FALSE(rules.Matches(GURL("http://10.10.1.1")));
417 }
418 
419 // Test that parsing an IPv6 range given a bracketed literal is not supported.
420 // Whether IPv6 literals need to be bracketed or not is pretty much a coin toss
421 // depending on the context, and here it is expected to be unbracketed to match
422 // macOS. It would be fine to support bracketed too, however none of the
423 // grammars we parse need that.
TEST(ProxyBypassRulesTest,ParseBracketedIPv6Range)424 TEST(ProxyBypassRulesTest, ParseBracketedIPv6Range) {
425   ProxyBypassRules rules;
426   rules.ParseFromString("[a:b:c:d::]/48");
427   ASSERT_EQ(0u, rules.rules().size());
428 }
429 
430 // Check which URLs an empty ProxyBypassRules matches.
TEST(ProxyBypassRulesTest,DefaultImplicitRules)431 TEST(ProxyBypassRulesTest, DefaultImplicitRules) {
432   ProxyBypassRules rules;
433 
434   EXPECT_EQ("", rules.ToString());
435 
436   // Should bypass all localhost and loopback names.
437   ExpectBypassLocalhost(rules, true);
438 
439   // Should bypass all link-local addresses.
440   ExpectBypassLinkLocal(rules, true);
441 
442   // Should not bypass other names.
443   ExpectBypassMisc(rules, false);
444 }
445 
446 // Test use of the <-loopback> bypass rule.
TEST(ProxyBypassRulesTest,NegativeWinLoopback)447 TEST(ProxyBypassRulesTest, NegativeWinLoopback) {
448   ProxyBypassRules rules;
449 
450   rules.ParseFromString("www.example.com;<-loopback>");
451   ASSERT_EQ(2u, rules.rules().size());
452   EXPECT_EQ("www.example.com", rules.rules()[0]->ToString());
453   EXPECT_EQ("<-loopback>", rules.rules()[1]->ToString());
454 
455   // Should NOT bypass localhost and loopback names.
456   ExpectBypassLocalhost(rules, false);
457 
458   // Should NOT bypass link-local addresses.
459   ExpectBypassLinkLocal(rules, false);
460 
461   // Should not bypass other names either.
462   ExpectBypassMisc(rules, false);
463 
464   // Only www.example.com should be bypassed.
465   EXPECT_TRUE(rules.Matches(GURL("http://www.example.com/")));
466 }
467 
468 // Verifies the evaluation order of mixing negative and positive rules. This
469 // expectation comes from WinInet (which is where <-loopback> comes from).
TEST(ProxyBypassRulesTest,RemoveImplicitAndAddLocalhost)470 TEST(ProxyBypassRulesTest, RemoveImplicitAndAddLocalhost) {
471   ProxyBypassRules rules;
472 
473   rules.ParseFromString("<-loopback>; localhost");
474   ASSERT_EQ(2u, rules.rules().size());
475   EXPECT_EQ("<-loopback>", rules.rules()[0]->ToString());
476   EXPECT_EQ("localhost", rules.rules()[1]->ToString());
477 
478   // Should not bypass localhost names because of <-loopback>. Except for
479   // "localhost" which was added at the end.
480   ExpectBypassLocalhost(rules, false, {"localhost"});
481 
482   // Should NOT bypass link-local addresses.
483   ExpectBypassLinkLocal(rules, false);
484 
485   // Should not bypass other names either.
486   ExpectBypassMisc(rules, false);
487 }
488 
489 // Verifies the evaluation order of mixing negative and positive rules. This
490 // expectation comes from WinInet (which is where <-loopback> comes from).
TEST(ProxyBypassRulesTest,AddLocalhostThenRemoveImplicit)491 TEST(ProxyBypassRulesTest, AddLocalhostThenRemoveImplicit) {
492   ProxyBypassRules rules;
493 
494   rules.ParseFromString("localhost; <-loopback>");
495   ASSERT_EQ(2u, rules.rules().size());
496   EXPECT_EQ("localhost", rules.rules()[0]->ToString());
497   EXPECT_EQ("<-loopback>", rules.rules()[1]->ToString());
498 
499   // Because of the ordering, localhost is not bypassed, because <-loopback>
500   // "unbypasses" it.
501   ExpectBypassLocalhost(rules, false);
502 
503   // Should NOT bypass link-local addresses.
504   ExpectBypassLinkLocal(rules, false);
505 
506   // Should not bypass other names either.
507   ExpectBypassMisc(rules, false);
508 }
509 
TEST(ProxyBypassRulesTest,AddRulesToSubtractImplicit)510 TEST(ProxyBypassRulesTest, AddRulesToSubtractImplicit) {
511   ProxyBypassRules rules;
512   rules.ParseFromString("foo");
513 
514   rules.AddRulesToSubtractImplicit();
515 
516   ASSERT_EQ(2u, rules.rules().size());
517   EXPECT_EQ("foo", rules.rules()[0]->ToString());
518   EXPECT_EQ("<-loopback>", rules.rules()[1]->ToString());
519 }
520 
TEST(ProxyBypassRulesTest,GetRulesToSubtractImplicit)521 TEST(ProxyBypassRulesTest, GetRulesToSubtractImplicit) {
522   EXPECT_EQ("<-loopback>;", ProxyBypassRules::GetRulesToSubtractImplicit());
523 }
524 
525 // Verifies that the <local> and <-loopback> rules can be specified in any
526 // case. This matches how WinInet's parses them.
TEST(ProxyBypassRulesTest,LoopbackAndLocalCaseInsensitive)527 TEST(ProxyBypassRulesTest, LoopbackAndLocalCaseInsensitive) {
528   ProxyBypassRules rules;
529 
530   rules.ParseFromString("<Local>; <-LoopBacK>; <LoCaL>; <-LoOpBack>");
531   ASSERT_EQ(4u, rules.rules().size());
532   EXPECT_EQ("<local>", rules.rules()[0]->ToString());
533   EXPECT_EQ("<-loopback>", rules.rules()[1]->ToString());
534   EXPECT_EQ("<local>", rules.rules()[2]->ToString());
535   EXPECT_EQ("<-loopback>", rules.rules()[3]->ToString());
536 }
537 
538 }  // namespace
539 
540 }  // namespace net
541