1// Copyright (c) 2010 The Chromium Authors. All rights reserved.
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/proxy_bypass_rules.h"
6
7#include "base/strings/string_util.h"
8#include "base/strings/stringprintf.h"
9#include "net/proxy/proxy_config_service_common_unittest.h"
10#include "testing/gtest/include/gtest/gtest.h"
11
12namespace net {
13
14namespace {
15
16TEST(ProxyBypassRulesTest, ParseAndMatchBasicHost) {
17  ProxyBypassRules rules;
18  rules.ParseFromString("wWw.gOogle.com");
19  ASSERT_EQ(1u, rules.rules().size());
20  EXPECT_EQ("www.google.com", rules.rules()[0]->ToString());
21
22  // All of these match; port, scheme, and non-hostname components don't
23  // matter.
24  EXPECT_TRUE(rules.Matches(GURL("http://www.google.com")));
25  EXPECT_TRUE(rules.Matches(GURL("ftp://www.google.com:99")));
26  EXPECT_TRUE(rules.Matches(GURL("https://www.google.com:81")));
27
28  // Must be a strict host match to work.
29  EXPECT_FALSE(rules.Matches(GURL("http://foo.www.google.com")));
30  EXPECT_FALSE(rules.Matches(GURL("http://xxx.google.com")));
31  EXPECT_FALSE(rules.Matches(GURL("http://google.com")));
32  EXPECT_FALSE(rules.Matches(GURL("http://www.google.com.baz.org")));
33}
34
35TEST(ProxyBypassRulesTest, ParseAndMatchBasicDomain) {
36  ProxyBypassRules rules;
37  rules.ParseFromString(".gOOgle.com");
38  ASSERT_EQ(1u, rules.rules().size());
39  // Note that we inferred this was an "ends with" test.
40  EXPECT_EQ("*.google.com", rules.rules()[0]->ToString());
41
42  // All of these match; port, scheme, and non-hostname components don't
43  // matter.
44  EXPECT_TRUE(rules.Matches(GURL("http://www.google.com")));
45  EXPECT_TRUE(rules.Matches(GURL("ftp://www.google.com:99")));
46  EXPECT_TRUE(rules.Matches(GURL("https://a.google.com:81")));
47  EXPECT_TRUE(rules.Matches(GURL("http://foo.google.com/x/y?q")));
48  EXPECT_TRUE(rules.Matches(GURL("http://foo:bar@baz.google.com#x")));
49
50  // Must be a strict "ends with" to work.
51  EXPECT_FALSE(rules.Matches(GURL("http://google.com")));
52  EXPECT_FALSE(rules.Matches(GURL("http://foo.google.com.baz.org")));
53}
54
55TEST(ProxyBypassRulesTest, ParseAndMatchBasicDomainWithPort) {
56  ProxyBypassRules rules;
57  rules.ParseFromString("*.GOOGLE.com:80");
58  ASSERT_EQ(1u, rules.rules().size());
59  EXPECT_EQ("*.google.com:80", rules.rules()[0]->ToString());
60
61  // All of these match; scheme, and non-hostname components don't matter.
62  EXPECT_TRUE(rules.Matches(GURL("http://www.google.com")));
63  EXPECT_TRUE(rules.Matches(GURL("ftp://www.google.com:80")));
64  EXPECT_TRUE(rules.Matches(GURL("https://a.google.com:80?x")));
65
66  // Must be a strict "ends with" to work.
67  EXPECT_FALSE(rules.Matches(GURL("http://google.com")));
68  EXPECT_FALSE(rules.Matches(GURL("http://foo.google.com.baz.org")));
69
70  // The ports must match.
71  EXPECT_FALSE(rules.Matches(GURL("http://www.google.com:90")));
72  EXPECT_FALSE(rules.Matches(GURL("https://www.google.com")));
73}
74
75TEST(ProxyBypassRulesTest, MatchAll) {
76  ProxyBypassRules rules;
77  rules.ParseFromString("*");
78  ASSERT_EQ(1u, rules.rules().size());
79  EXPECT_EQ("*", rules.rules()[0]->ToString());
80
81  EXPECT_TRUE(rules.Matches(GURL("http://www.google.com")));
82  EXPECT_TRUE(rules.Matches(GURL("ftp://www.foobar.com:99")));
83  EXPECT_TRUE(rules.Matches(GURL("https://a.google.com:80?x")));
84}
85
86TEST(ProxyBypassRulesTest, WildcardAtStart) {
87  ProxyBypassRules rules;
88  rules.ParseFromString("*.org:443");
89  ASSERT_EQ(1u, rules.rules().size());
90  EXPECT_EQ("*.org:443", rules.rules()[0]->ToString());
91
92  EXPECT_TRUE(rules.Matches(GURL("http://www.google.org:443")));
93  EXPECT_TRUE(rules.Matches(GURL("https://www.google.org")));
94
95  EXPECT_FALSE(rules.Matches(GURL("http://www.google.org")));
96  EXPECT_FALSE(rules.Matches(GURL("https://www.google.com")));
97  EXPECT_FALSE(rules.Matches(GURL("https://www.google.org.com")));
98}
99
100TEST(ProxyBypassRulesTest, IPV4Address) {
101  ProxyBypassRules rules;
102  rules.ParseFromString("192.168.1.1");
103  ASSERT_EQ(1u, rules.rules().size());
104  EXPECT_EQ("192.168.1.1", rules.rules()[0]->ToString());
105
106  EXPECT_TRUE(rules.Matches(GURL("http://192.168.1.1")));
107  EXPECT_TRUE(rules.Matches(GURL("https://192.168.1.1:90")));
108
109  EXPECT_FALSE(rules.Matches(GURL("http://www.google.com")));
110  EXPECT_FALSE(rules.Matches(GURL("http://sup.192.168.1.1")));
111}
112
113TEST(ProxyBypassRulesTest, IPV4AddressWithPort) {
114  ProxyBypassRules rules;
115  rules.ParseFromString("192.168.1.1:33");
116  ASSERT_EQ(1u, rules.rules().size());
117  EXPECT_EQ("192.168.1.1:33", rules.rules()[0]->ToString());
118
119  EXPECT_TRUE(rules.Matches(GURL("http://192.168.1.1:33")));
120
121  EXPECT_FALSE(rules.Matches(GURL("http://www.google.com")));
122  EXPECT_FALSE(rules.Matches(GURL("http://192.168.1.1")));
123  EXPECT_FALSE(rules.Matches(GURL("http://sup.192.168.1.1:33")));
124}
125
126TEST(ProxyBypassRulesTest, IPV6Address) {
127  ProxyBypassRules rules;
128  rules.ParseFromString("[3ffe:2a00:100:7031:0:0::1]");
129  ASSERT_EQ(1u, rules.rules().size());
130  // Note that we canonicalized the IP address.
131  EXPECT_EQ("[3ffe:2a00:100:7031::1]", rules.rules()[0]->ToString());
132
133  EXPECT_TRUE(rules.Matches(GURL("http://[3ffe:2a00:100:7031::1]")));
134  EXPECT_TRUE(rules.Matches(GURL("http://[3ffe:2a00:100:7031::1]:33")));
135
136  EXPECT_FALSE(rules.Matches(GURL("http://www.google.com")));
137  EXPECT_FALSE(rules.Matches(GURL("http://sup.192.168.1.1:33")));
138}
139
140TEST(ProxyBypassRulesTest, IPV6AddressWithPort) {
141  ProxyBypassRules rules;
142  rules.ParseFromString("[3ffe:2a00:100:7031::1]:33");
143  ASSERT_EQ(1u, rules.rules().size());
144  EXPECT_EQ("[3ffe:2a00:100:7031::1]:33", rules.rules()[0]->ToString());
145
146  EXPECT_TRUE(rules.Matches(GURL("http://[3ffe:2a00:100:7031::1]:33")));
147
148  EXPECT_FALSE(rules.Matches(GURL("http://[3ffe:2a00:100:7031::1]")));
149  EXPECT_FALSE(rules.Matches(GURL("http://www.google.com")));
150}
151
152TEST(ProxyBypassRulesTest, HTTPOnly) {
153  ProxyBypassRules rules;
154  rules.ParseFromString("http://www.google.com");
155  ASSERT_EQ(1u, rules.rules().size());
156  EXPECT_EQ("http://www.google.com", rules.rules()[0]->ToString());
157
158  EXPECT_TRUE(rules.Matches(GURL("http://www.google.com/foo")));
159  EXPECT_TRUE(rules.Matches(GURL("http://www.google.com:99")));
160
161  EXPECT_FALSE(rules.Matches(GURL("https://www.google.com")));
162  EXPECT_FALSE(rules.Matches(GURL("ftp://www.google.com")));
163  EXPECT_FALSE(rules.Matches(GURL("http://foo.www.google.com")));
164  EXPECT_FALSE(rules.Matches(GURL("http://www.google.com.org")));
165  EXPECT_FALSE(rules.Matches(GURL("https://www.google.com")));
166}
167
168TEST(ProxyBypassRulesTest, HTTPOnlyWithWildcard) {
169  ProxyBypassRules rules;
170  rules.ParseFromString("http://*www.google.com");
171  ASSERT_EQ(1u, rules.rules().size());
172  EXPECT_EQ("http://*www.google.com", rules.rules()[0]->ToString());
173
174  EXPECT_TRUE(rules.Matches(GURL("http://www.google.com/foo")));
175  EXPECT_TRUE(rules.Matches(GURL("http://www.google.com:99")));
176  EXPECT_TRUE(rules.Matches(GURL("http://foo.www.google.com")));
177
178  EXPECT_FALSE(rules.Matches(GURL("https://www.google.com")));
179  EXPECT_FALSE(rules.Matches(GURL("ftp://www.google.com")));
180  EXPECT_FALSE(rules.Matches(GURL("http://www.google.com.org")));
181  EXPECT_FALSE(rules.Matches(GURL("https://www.google.com")));
182}
183
184TEST(ProxyBypassRulesTest, UseSuffixMatching) {
185  ProxyBypassRules rules;
186  rules.ParseFromStringUsingSuffixMatching(
187      "foo1.com, .foo2.com, 192.168.1.1, "
188      "*foobar.com:80, *.foo, http://baz, <local>");
189  ASSERT_EQ(7u, rules.rules().size());
190  EXPECT_EQ("*foo1.com", rules.rules()[0]->ToString());
191  EXPECT_EQ("*.foo2.com", rules.rules()[1]->ToString());
192  EXPECT_EQ("192.168.1.1", rules.rules()[2]->ToString());
193  EXPECT_EQ("*foobar.com:80", rules.rules()[3]->ToString());
194  EXPECT_EQ("*.foo", rules.rules()[4]->ToString());
195  EXPECT_EQ("http://*baz", rules.rules()[5]->ToString());
196  EXPECT_EQ("<local>", rules.rules()[6]->ToString());
197
198  EXPECT_TRUE(rules.Matches(GURL("http://foo1.com")));
199  EXPECT_TRUE(rules.Matches(GURL("http://aaafoo1.com")));
200  EXPECT_FALSE(rules.Matches(GURL("http://aaafoo1.com.net")));
201}
202
203TEST(ProxyBypassRulesTest, MultipleRules) {
204  ProxyBypassRules rules;
205  rules.ParseFromString(".google.com , .foobar.com:30");
206  ASSERT_EQ(2u, rules.rules().size());
207
208  EXPECT_TRUE(rules.Matches(GURL("http://baz.google.com:40")));
209  EXPECT_FALSE(rules.Matches(GURL("http://google.com:40")));
210  EXPECT_TRUE(rules.Matches(GURL("http://bar.foobar.com:30")));
211  EXPECT_FALSE(rules.Matches(GURL("http://bar.foobar.com")));
212  EXPECT_FALSE(rules.Matches(GURL("http://bar.foobar.com:33")));
213}
214
215TEST(ProxyBypassRulesTest, BadInputs) {
216  ProxyBypassRules rules;
217  EXPECT_FALSE(rules.AddRuleFromString("://"));
218  EXPECT_FALSE(rules.AddRuleFromString("  "));
219  EXPECT_FALSE(rules.AddRuleFromString("http://"));
220  EXPECT_FALSE(rules.AddRuleFromString("*.foo.com:-34"));
221  EXPECT_EQ(0u, rules.rules().size());
222}
223
224TEST(ProxyBypassRulesTest, Equals) {
225  ProxyBypassRules rules1;
226  ProxyBypassRules rules2;
227
228  rules1.ParseFromString("foo1.com, .foo2.com");
229  rules2.ParseFromString("foo1.com,.FOo2.com");
230
231  EXPECT_TRUE(rules1.Equals(rules2));
232  EXPECT_TRUE(rules2.Equals(rules1));
233
234  rules1.ParseFromString(".foo2.com");
235  rules2.ParseFromString("foo1.com,.FOo2.com");
236
237  EXPECT_FALSE(rules1.Equals(rules2));
238  EXPECT_FALSE(rules2.Equals(rules1));
239}
240
241TEST(ProxyBypassRulesTest, BypassLocalNames) {
242  const struct {
243    const char* url;
244    bool expected_is_local;
245  } tests[] = {
246    // Single-component hostnames are considered local.
247    {"http://localhost/x", true},
248    {"http://www", true},
249
250    // IPv4 loopback interface.
251    {"http://127.0.0.1/x", true},
252    {"http://127.0.0.1:80/x", true},
253
254    // IPv6 loopback interface.
255    {"http://[::1]:80/x", true},
256    {"http://[0:0::1]:6233/x", true},
257    {"http://[0:0:0:0:0:0:0:1]/x", true},
258
259    // Non-local URLs.
260    {"http://foo.com/", false},
261    {"http://localhost.i/", false},
262    {"http://www.google.com/", false},
263    {"http://192.168.0.1/", false},
264
265    // Try with different protocols.
266    {"ftp://127.0.0.1/x", true},
267    {"ftp://foobar.com/x", false},
268
269    // This is a bit of a gray-area, but GURL does not strip trailing dots
270    // in host-names, so the following are considered non-local.
271    {"http://www./x", false},
272    {"http://localhost./x", false},
273  };
274
275  ProxyBypassRules rules;
276  rules.ParseFromString("<local>");
277
278  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
279    SCOPED_TRACE(base::StringPrintf(
280        "Test[%d]: %s", static_cast<int>(i), tests[i].url));
281    EXPECT_EQ(tests[i].expected_is_local, rules.Matches(GURL(tests[i].url)));
282  }
283}
284
285TEST(ProxyBypassRulesTest, ParseAndMatchCIDR_IPv4) {
286  ProxyBypassRules rules;
287  rules.ParseFromString("192.168.1.1/16");
288  ASSERT_EQ(1u, rules.rules().size());
289  EXPECT_EQ("192.168.1.1/16", rules.rules()[0]->ToString());
290
291  EXPECT_TRUE(rules.Matches(GURL("http://192.168.1.1")));
292  EXPECT_TRUE(rules.Matches(GURL("ftp://192.168.4.4")));
293  EXPECT_TRUE(rules.Matches(GURL("https://192.168.0.0:81")));
294  EXPECT_TRUE(rules.Matches(GURL("http://[::ffff:192.168.11.11]")));
295
296  EXPECT_FALSE(rules.Matches(GURL("http://foobar.com")));
297  EXPECT_FALSE(rules.Matches(GURL("http://192.169.1.1")));
298  EXPECT_FALSE(rules.Matches(GURL("http://xxx.192.168.1.1")));
299  EXPECT_FALSE(rules.Matches(GURL("http://192.168.1.1.xx")));
300}
301
302TEST(ProxyBypassRulesTest, ParseAndMatchCIDR_IPv6) {
303  ProxyBypassRules rules;
304  rules.ParseFromString("a:b:c:d::/48");
305  ASSERT_EQ(1u, rules.rules().size());
306  EXPECT_EQ("a:b:c:d::/48", rules.rules()[0]->ToString());
307
308  EXPECT_TRUE(rules.Matches(GURL("http://[A:b:C:9::]")));
309  EXPECT_FALSE(rules.Matches(GURL("http://foobar.com")));
310  EXPECT_FALSE(rules.Matches(GURL("http://192.169.1.1")));
311}
312
313}  // namespace
314
315}  // namespace net
316