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