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