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