url_pattern_unittest.cc revision 2a99a7e74a7f215066514fe81d2bfa6639d9eddd
1// Copyright (c) 2012 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 "base/memory/scoped_ptr.h"
6#include "extensions/common/url_pattern.h"
7#include "testing/gtest/include/gtest/gtest.h"
8#include "googleurl/src/gurl.h"
9
10namespace {
11
12// See url_pattern.h for examples of valid and invalid patterns.
13
14static const int kAllSchemes =
15    URLPattern::SCHEME_HTTP |
16    URLPattern::SCHEME_HTTPS |
17    URLPattern::SCHEME_FILE |
18    URLPattern::SCHEME_FTP |
19    URLPattern::SCHEME_CHROMEUI |
20    URLPattern::SCHEME_EXTENSION |
21    URLPattern::SCHEME_FILESYSTEM;
22
23TEST(ExtensionURLPatternTest, ParseInvalid) {
24  const struct {
25    const char* pattern;
26    URLPattern::ParseResult expected_result;
27  } kInvalidPatterns[] = {
28    { "http", URLPattern::PARSE_ERROR_MISSING_SCHEME_SEPARATOR },
29    { "http:", URLPattern::PARSE_ERROR_WRONG_SCHEME_SEPARATOR },
30    { "http:/", URLPattern::PARSE_ERROR_WRONG_SCHEME_SEPARATOR },
31    { "about://", URLPattern::PARSE_ERROR_WRONG_SCHEME_SEPARATOR },
32    { "http://", URLPattern::PARSE_ERROR_EMPTY_HOST },
33    { "http:///", URLPattern::PARSE_ERROR_EMPTY_HOST },
34    { "http://*foo/bar", URLPattern::PARSE_ERROR_INVALID_HOST_WILDCARD },
35    { "http://foo.*.bar/baz", URLPattern::PARSE_ERROR_INVALID_HOST_WILDCARD },
36    { "http://fo.*.ba:123/baz", URLPattern::PARSE_ERROR_INVALID_HOST_WILDCARD },
37    { "http:/bar", URLPattern::PARSE_ERROR_WRONG_SCHEME_SEPARATOR },
38    { "http://bar", URLPattern::PARSE_ERROR_EMPTY_PATH },
39  };
40
41  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kInvalidPatterns); ++i) {
42    URLPattern pattern(URLPattern::SCHEME_ALL);
43    EXPECT_EQ(kInvalidPatterns[i].expected_result,
44              pattern.Parse(kInvalidPatterns[i].pattern))
45        << kInvalidPatterns[i].pattern;
46  }
47};
48
49TEST(ExtensionURLPatternTest, Ports) {
50  const struct {
51    const char* pattern;
52    URLPattern::ParseResult expected_result;
53    const char* expected_port;
54  } kTestPatterns[] = {
55    { "http://foo:1234/", URLPattern::PARSE_SUCCESS, "1234" },
56    { "http://foo:1234/bar", URLPattern::PARSE_SUCCESS, "1234" },
57    { "http://*.foo:1234/", URLPattern::PARSE_SUCCESS, "1234" },
58    { "http://*.foo:1234/bar", URLPattern::PARSE_SUCCESS,"1234" },
59    { "http://:1234/", URLPattern::PARSE_SUCCESS, "1234" },
60    { "http://foo:/", URLPattern::PARSE_ERROR_INVALID_PORT, "*" },
61    { "http://foo:*/", URLPattern::PARSE_SUCCESS, "*" },
62    { "http://*.foo:/", URLPattern::PARSE_ERROR_INVALID_PORT, "*" },
63    { "http://foo:com/", URLPattern::PARSE_ERROR_INVALID_PORT, "*" },
64    { "http://foo:123456/", URLPattern::PARSE_ERROR_INVALID_PORT, "*" },
65    { "http://foo:80:80/monkey", URLPattern::PARSE_ERROR_INVALID_PORT, "*" },
66    { "file://foo:1234/bar", URLPattern::PARSE_SUCCESS, "*" },
67    { "chrome://foo:1234/bar", URLPattern::PARSE_ERROR_INVALID_PORT, "*" },
68
69    // Port-like strings in the path should not trigger a warning.
70    { "http://*/:1234", URLPattern::PARSE_SUCCESS, "*" },
71    { "http://*.foo/bar:1234", URLPattern::PARSE_SUCCESS, "*" },
72    { "http://foo/bar:1234/path", URLPattern::PARSE_SUCCESS,"*" },
73  };
74
75  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kTestPatterns); ++i) {
76    URLPattern pattern(URLPattern::SCHEME_ALL);
77    EXPECT_EQ(kTestPatterns[i].expected_result,
78              pattern.Parse(kTestPatterns[i].pattern))
79        << "Got unexpected result for URL pattern: "
80        << kTestPatterns[i].pattern;
81    EXPECT_EQ(kTestPatterns[i].expected_port, pattern.port())
82        << "Got unexpected port for URL pattern: " << kTestPatterns[i].pattern;
83  }
84};
85
86// all pages for a given scheme
87TEST(ExtensionURLPatternTest, Match1) {
88  URLPattern pattern(kAllSchemes);
89  EXPECT_EQ(URLPattern::PARSE_SUCCESS, pattern.Parse("http://*/*"));
90  EXPECT_EQ("http", pattern.scheme());
91  EXPECT_EQ("", pattern.host());
92  EXPECT_TRUE(pattern.match_subdomains());
93  EXPECT_FALSE(pattern.match_all_urls());
94  EXPECT_EQ("/*", pattern.path());
95  EXPECT_TRUE(pattern.MatchesURL(GURL("http://google.com")));
96  EXPECT_TRUE(pattern.MatchesURL(GURL("http://yahoo.com")));
97  EXPECT_TRUE(pattern.MatchesURL(GURL("http://google.com/foo")));
98  EXPECT_FALSE(pattern.MatchesURL(GURL("https://google.com")));
99  EXPECT_TRUE(pattern.MatchesURL(GURL("http://74.125.127.100/search")));
100}
101
102// all domains
103TEST(ExtensionURLPatternTest, Match2) {
104  URLPattern pattern(kAllSchemes);
105  EXPECT_EQ(URLPattern::PARSE_SUCCESS, pattern.Parse("https://*/foo*"));
106  EXPECT_EQ("https", pattern.scheme());
107  EXPECT_EQ("", pattern.host());
108  EXPECT_TRUE(pattern.match_subdomains());
109  EXPECT_FALSE(pattern.match_all_urls());
110  EXPECT_EQ("/foo*", pattern.path());
111  EXPECT_TRUE(pattern.MatchesURL(GURL("https://www.google.com/foo")));
112  EXPECT_TRUE(pattern.MatchesURL(GURL("https://www.google.com/foobar")));
113  EXPECT_FALSE(pattern.MatchesURL(GURL("http://www.google.com/foo")));
114  EXPECT_FALSE(pattern.MatchesURL(GURL("https://www.google.com/")));
115  EXPECT_TRUE(pattern.MatchesURL(
116      GURL("filesystem:https://www.google.com/foobar/")));
117}
118
119// subdomains
120TEST(URLPatternTest, Match3) {
121  URLPattern pattern(kAllSchemes);
122  EXPECT_EQ(URLPattern::PARSE_SUCCESS,
123            pattern.Parse("http://*.google.com/foo*bar"));
124  EXPECT_EQ("http", pattern.scheme());
125  EXPECT_EQ("google.com", pattern.host());
126  EXPECT_TRUE(pattern.match_subdomains());
127  EXPECT_FALSE(pattern.match_all_urls());
128  EXPECT_EQ("/foo*bar", pattern.path());
129  EXPECT_TRUE(pattern.MatchesURL(GURL("http://google.com/foobar")));
130  EXPECT_TRUE(pattern.MatchesURL(GURL("http://www.google.com/foo?bar")));
131  EXPECT_TRUE(pattern.MatchesURL(
132      GURL("http://monkey.images.google.com/foooobar")));
133  EXPECT_FALSE(pattern.MatchesURL(GURL("http://yahoo.com/foobar")));
134  EXPECT_TRUE(pattern.MatchesURL(
135      GURL("filesystem:http://google.com/foo/bar")));
136  EXPECT_FALSE(pattern.MatchesURL(
137      GURL("filesystem:http://google.com/temporary/foobar")));
138}
139
140// glob escaping
141TEST(ExtensionURLPatternTest, Match5) {
142  URLPattern pattern(kAllSchemes);
143  EXPECT_EQ(URLPattern::PARSE_SUCCESS, pattern.Parse("file:///foo?bar\\*baz"));
144  EXPECT_EQ("file", pattern.scheme());
145  EXPECT_EQ("", pattern.host());
146  EXPECT_FALSE(pattern.match_subdomains());
147  EXPECT_FALSE(pattern.match_all_urls());
148  EXPECT_EQ("/foo?bar\\*baz", pattern.path());
149  EXPECT_TRUE(pattern.MatchesURL(GURL("file:///foo?bar\\hellobaz")));
150  EXPECT_FALSE(pattern.MatchesURL(GURL("file:///fooXbar\\hellobaz")));
151}
152
153// ip addresses
154TEST(ExtensionURLPatternTest, Match6) {
155  URLPattern pattern(kAllSchemes);
156  EXPECT_EQ(URLPattern::PARSE_SUCCESS, pattern.Parse("http://127.0.0.1/*"));
157  EXPECT_EQ("http", pattern.scheme());
158  EXPECT_EQ("127.0.0.1", pattern.host());
159  EXPECT_FALSE(pattern.match_subdomains());
160  EXPECT_FALSE(pattern.match_all_urls());
161  EXPECT_EQ("/*", pattern.path());
162  EXPECT_TRUE(pattern.MatchesURL(GURL("http://127.0.0.1")));
163}
164
165// subdomain matching with ip addresses
166TEST(ExtensionURLPatternTest, Match7) {
167  URLPattern pattern(kAllSchemes);
168  // allowed, but useless
169  EXPECT_EQ(URLPattern::PARSE_SUCCESS, pattern.Parse("http://*.0.0.1/*"));
170  EXPECT_EQ("http", pattern.scheme());
171  EXPECT_EQ("0.0.1", pattern.host());
172  EXPECT_TRUE(pattern.match_subdomains());
173  EXPECT_FALSE(pattern.match_all_urls());
174  EXPECT_EQ("/*", pattern.path());
175  // Subdomain matching is never done if the argument has an IP address host.
176  EXPECT_FALSE(pattern.MatchesURL(GURL("http://127.0.0.1")));
177};
178
179// unicode
180TEST(ExtensionURLPatternTest, Match8) {
181  URLPattern pattern(kAllSchemes);
182  // The below is the ASCII encoding of the following URL:
183  // http://*.\xe1\x80\xbf/a\xc2\x81\xe1*
184  EXPECT_EQ(URLPattern::PARSE_SUCCESS,
185            pattern.Parse("http://*.xn--gkd/a%C2%81%E1*"));
186  EXPECT_EQ("http", pattern.scheme());
187  EXPECT_EQ("xn--gkd", pattern.host());
188  EXPECT_TRUE(pattern.match_subdomains());
189  EXPECT_FALSE(pattern.match_all_urls());
190  EXPECT_EQ("/a%C2%81%E1*", pattern.path());
191  EXPECT_TRUE(pattern.MatchesURL(
192      GURL("http://abc.\xe1\x80\xbf/a\xc2\x81\xe1xyz")));
193  EXPECT_TRUE(pattern.MatchesURL(
194      GURL("http://\xe1\x80\xbf/a\xc2\x81\xe1\xe1")));
195};
196
197// chrome://
198TEST(ExtensionURLPatternTest, Match9) {
199  URLPattern pattern(kAllSchemes);
200  EXPECT_EQ(URLPattern::PARSE_SUCCESS, pattern.Parse("chrome://favicon/*"));
201  EXPECT_EQ("chrome", pattern.scheme());
202  EXPECT_EQ("favicon", pattern.host());
203  EXPECT_FALSE(pattern.match_subdomains());
204  EXPECT_FALSE(pattern.match_all_urls());
205  EXPECT_EQ("/*", pattern.path());
206  EXPECT_TRUE(pattern.MatchesURL(GURL("chrome://favicon/http://google.com")));
207  EXPECT_TRUE(pattern.MatchesURL(GURL("chrome://favicon/https://google.com")));
208  EXPECT_FALSE(pattern.MatchesURL(GURL("chrome://history")));
209};
210
211// *://
212TEST(ExtensionURLPatternTest, Match10) {
213  URLPattern pattern(kAllSchemes);
214  EXPECT_EQ(URLPattern::PARSE_SUCCESS, pattern.Parse("*://*/*"));
215  EXPECT_TRUE(pattern.MatchesScheme("http"));
216  EXPECT_TRUE(pattern.MatchesScheme("https"));
217  EXPECT_FALSE(pattern.MatchesScheme("chrome"));
218  EXPECT_FALSE(pattern.MatchesScheme("file"));
219  EXPECT_FALSE(pattern.MatchesScheme("ftp"));
220  EXPECT_TRUE(pattern.match_subdomains());
221  EXPECT_FALSE(pattern.match_all_urls());
222  EXPECT_EQ("/*", pattern.path());
223  EXPECT_TRUE(pattern.MatchesURL(GURL("http://127.0.0.1")));
224  EXPECT_FALSE(pattern.MatchesURL(GURL("chrome://favicon/http://google.com")));
225  EXPECT_FALSE(pattern.MatchesURL(GURL("file:///foo/bar")));
226  EXPECT_FALSE(pattern.MatchesURL(GURL("file://localhost/foo/bar")));
227};
228
229// <all_urls>
230TEST(ExtensionURLPatternTest, Match11) {
231  URLPattern pattern(kAllSchemes);
232  EXPECT_EQ(URLPattern::PARSE_SUCCESS, pattern.Parse("<all_urls>"));
233  EXPECT_TRUE(pattern.MatchesScheme("chrome"));
234  EXPECT_TRUE(pattern.MatchesScheme("http"));
235  EXPECT_TRUE(pattern.MatchesScheme("https"));
236  EXPECT_TRUE(pattern.MatchesScheme("file"));
237  EXPECT_TRUE(pattern.MatchesScheme("filesystem"));
238  EXPECT_TRUE(pattern.MatchesScheme("chrome-extension"));
239  EXPECT_TRUE(pattern.match_subdomains());
240  EXPECT_TRUE(pattern.match_all_urls());
241  EXPECT_EQ("/*", pattern.path());
242  EXPECT_TRUE(pattern.MatchesURL(GURL("chrome://favicon/http://google.com")));
243  EXPECT_TRUE(pattern.MatchesURL(GURL("http://127.0.0.1")));
244  EXPECT_TRUE(pattern.MatchesURL(GURL("file:///foo/bar")));
245  EXPECT_TRUE(pattern.MatchesURL(GURL("file://localhost/foo/bar")));
246
247  // Make sure the properties are the same when creating an <all_urls> pattern
248  // via SetMatchAllURLs and by parsing <all_urls>.
249  URLPattern pattern2(kAllSchemes);
250  pattern2.SetMatchAllURLs(true);
251
252  EXPECT_EQ(pattern.valid_schemes(), pattern2.valid_schemes());
253  EXPECT_EQ(pattern.match_subdomains(), pattern2.match_subdomains());
254  EXPECT_EQ(pattern.path(), pattern2.path());
255  EXPECT_EQ(pattern.match_all_urls(), pattern2.match_all_urls());
256  EXPECT_EQ(pattern.scheme(), pattern2.scheme());
257  EXPECT_EQ(pattern.port(), pattern2.port());
258  EXPECT_EQ(pattern.GetAsString(), pattern2.GetAsString());
259};
260
261// SCHEME_ALL matches all schemes.
262TEST(ExtensionURLPatternTest, Match12) {
263  URLPattern pattern(URLPattern::SCHEME_ALL);
264  EXPECT_EQ(URLPattern::PARSE_SUCCESS, pattern.Parse("<all_urls>"));
265  EXPECT_TRUE(pattern.MatchesScheme("chrome"));
266  EXPECT_TRUE(pattern.MatchesScheme("http"));
267  EXPECT_TRUE(pattern.MatchesScheme("https"));
268  EXPECT_TRUE(pattern.MatchesScheme("file"));
269  EXPECT_TRUE(pattern.MatchesScheme("filesystem"));
270  EXPECT_TRUE(pattern.MatchesScheme("javascript"));
271  EXPECT_TRUE(pattern.MatchesScheme("data"));
272  EXPECT_TRUE(pattern.MatchesScheme("about"));
273  EXPECT_TRUE(pattern.MatchesScheme("chrome-extension"));
274  EXPECT_TRUE(pattern.match_subdomains());
275  EXPECT_TRUE(pattern.match_all_urls());
276  EXPECT_EQ("/*", pattern.path());
277  EXPECT_TRUE(pattern.MatchesURL(GURL("chrome://favicon/http://google.com")));
278  EXPECT_TRUE(pattern.MatchesURL(GURL("http://127.0.0.1")));
279  EXPECT_TRUE(pattern.MatchesURL(GURL("file:///foo/bar")));
280  EXPECT_TRUE(pattern.MatchesURL(GURL("file://localhost/foo/bar")));
281  EXPECT_TRUE(pattern.MatchesURL(GURL("chrome://newtab")));
282  EXPECT_TRUE(pattern.MatchesURL(GURL("about:blank")));
283  EXPECT_TRUE(pattern.MatchesURL(GURL("about:version")));
284  EXPECT_TRUE(pattern.MatchesURL(
285      GURL("data:text/html;charset=utf-8,<html>asdf</html>")));
286};
287
288static const struct MatchPatterns {
289  const char* pattern;
290  const char* matches;
291} kMatch13UrlPatternTestCases[] = {
292  {"about:*", "about:blank"},
293  {"about:blank", "about:blank"},
294  {"about:*", "about:version"},
295  {"chrome-extension://*/*", "chrome-extension://FTW"},
296  {"data:*", "data:monkey"},
297  {"javascript:*", "javascript:atemyhomework"},
298};
299
300// SCHEME_ALL and specific schemes.
301TEST(ExtensionURLPatternTest, Match13) {
302  for (size_t i = 0; i < arraysize(kMatch13UrlPatternTestCases); ++i) {
303    URLPattern pattern(URLPattern::SCHEME_ALL);
304    EXPECT_EQ(URLPattern::PARSE_SUCCESS,
305              pattern.Parse(kMatch13UrlPatternTestCases[i].pattern))
306        << " while parsing " << kMatch13UrlPatternTestCases[i].pattern;
307    EXPECT_TRUE(pattern.MatchesURL(
308        GURL(kMatch13UrlPatternTestCases[i].matches)))
309        << " while matching " << kMatch13UrlPatternTestCases[i].matches;
310  }
311
312  // Negative test.
313  URLPattern pattern(URLPattern::SCHEME_ALL);
314  EXPECT_EQ(URLPattern::PARSE_SUCCESS, pattern.Parse("data:*"));
315  EXPECT_FALSE(pattern.MatchesURL(GURL("about:blank")));
316};
317
318// file scheme with empty hostname
319TEST(ExtensionURLPatternTest, Match14) {
320  URLPattern pattern(kAllSchemes);
321  EXPECT_EQ(URLPattern::PARSE_SUCCESS, pattern.Parse("file:///foo*"));
322  EXPECT_EQ("file", pattern.scheme());
323  EXPECT_EQ("", pattern.host());
324  EXPECT_FALSE(pattern.match_subdomains());
325  EXPECT_FALSE(pattern.match_all_urls());
326  EXPECT_EQ("/foo*", pattern.path());
327  EXPECT_FALSE(pattern.MatchesURL(GURL("file://foo")));
328  EXPECT_FALSE(pattern.MatchesURL(GURL("file://foobar")));
329  EXPECT_TRUE(pattern.MatchesURL(GURL("file:///foo")));
330  EXPECT_TRUE(pattern.MatchesURL(GURL("file:///foobar")));
331  EXPECT_TRUE(pattern.MatchesURL(GURL("file://localhost/foo")));
332}
333
334// file scheme without hostname part
335TEST(ExtensionURLPatternTest, Match15) {
336  URLPattern pattern(kAllSchemes);
337  EXPECT_EQ(URLPattern::PARSE_SUCCESS, pattern.Parse("file://foo*"));
338  EXPECT_EQ("file", pattern.scheme());
339  EXPECT_EQ("", pattern.host());
340  EXPECT_FALSE(pattern.match_subdomains());
341  EXPECT_FALSE(pattern.match_all_urls());
342  EXPECT_EQ("/foo*", pattern.path());
343  EXPECT_FALSE(pattern.MatchesURL(GURL("file://foo")));
344  EXPECT_FALSE(pattern.MatchesURL(GURL("file://foobar")));
345  EXPECT_TRUE(pattern.MatchesURL(GURL("file:///foo")));
346  EXPECT_TRUE(pattern.MatchesURL(GURL("file:///foobar")));
347  EXPECT_TRUE(pattern.MatchesURL(GURL("file://localhost/foo")));
348}
349
350// file scheme with hostname
351TEST(ExtensionURLPatternTest, Match16) {
352  URLPattern pattern(kAllSchemes);
353  EXPECT_EQ(URLPattern::PARSE_SUCCESS, pattern.Parse("file://localhost/foo*"));
354  EXPECT_EQ("file", pattern.scheme());
355  // Since hostname is ignored for file://.
356  EXPECT_EQ("", pattern.host());
357  EXPECT_FALSE(pattern.match_subdomains());
358  EXPECT_FALSE(pattern.match_all_urls());
359  EXPECT_EQ("/foo*", pattern.path());
360  EXPECT_FALSE(pattern.MatchesURL(GURL("file://foo")));
361  EXPECT_FALSE(pattern.MatchesURL(GURL("file://foobar")));
362  EXPECT_TRUE(pattern.MatchesURL(GURL("file:///foo")));
363  EXPECT_TRUE(pattern.MatchesURL(GURL("file:///foobar")));
364  EXPECT_TRUE(pattern.MatchesURL(GURL("file://localhost/foo")));
365}
366
367// Specific port
368TEST(ExtensionURLPatternTest, Match17) {
369  URLPattern pattern(kAllSchemes);
370  EXPECT_EQ(URLPattern::PARSE_SUCCESS,
371            pattern.Parse("http://www.example.com:80/foo"));
372  EXPECT_EQ("http", pattern.scheme());
373  EXPECT_EQ("www.example.com", pattern.host());
374  EXPECT_FALSE(pattern.match_subdomains());
375  EXPECT_FALSE(pattern.match_all_urls());
376  EXPECT_EQ("/foo", pattern.path());
377  EXPECT_EQ("80", pattern.port());
378  EXPECT_TRUE(pattern.MatchesURL(GURL("http://www.example.com:80/foo")));
379  EXPECT_TRUE(pattern.MatchesURL(GURL("http://www.example.com/foo")));
380  EXPECT_FALSE(pattern.MatchesURL(GURL("http://www.example.com:8080/foo")));
381  EXPECT_FALSE(pattern.MatchesURL(
382      GURL("filesystem:http://www.example.com:8080/foo/")));
383  EXPECT_FALSE(pattern.MatchesURL(GURL("filesystem:http://www.example.com/f/foo")));
384}
385
386// Explicit port wildcard
387TEST(ExtensionURLPatternTest, Match18) {
388  URLPattern pattern(kAllSchemes);
389  EXPECT_EQ(URLPattern::PARSE_SUCCESS,
390            pattern.Parse("http://www.example.com:*/foo"));
391  EXPECT_EQ("http", pattern.scheme());
392  EXPECT_EQ("www.example.com", pattern.host());
393  EXPECT_FALSE(pattern.match_subdomains());
394  EXPECT_FALSE(pattern.match_all_urls());
395  EXPECT_EQ("/foo", pattern.path());
396  EXPECT_EQ("*", pattern.port());
397  EXPECT_TRUE(pattern.MatchesURL(GURL("http://www.example.com:80/foo")));
398  EXPECT_TRUE(pattern.MatchesURL(GURL("http://www.example.com/foo")));
399  EXPECT_TRUE(pattern.MatchesURL(GURL("http://www.example.com:8080/foo")));
400  EXPECT_FALSE(pattern.MatchesURL(
401      GURL("filesystem:http://www.example.com:8080/foo/")));
402}
403
404// chrome-extension://
405TEST(ExtensionURLPatternTest, Match19) {
406  URLPattern pattern(URLPattern::SCHEME_EXTENSION);
407  EXPECT_EQ(URLPattern::PARSE_SUCCESS,
408            pattern.Parse("chrome-extension://ftw/*"));
409  EXPECT_EQ("chrome-extension", pattern.scheme());
410  EXPECT_EQ("ftw", pattern.host());
411  EXPECT_FALSE(pattern.match_subdomains());
412  EXPECT_FALSE(pattern.match_all_urls());
413  EXPECT_EQ("/*", pattern.path());
414  EXPECT_TRUE(pattern.MatchesURL(GURL("chrome-extension://ftw")));
415  EXPECT_TRUE(pattern.MatchesURL(
416      GURL("chrome-extension://ftw/http://google.com")));
417  EXPECT_TRUE(pattern.MatchesURL(
418      GURL("chrome-extension://ftw/https://google.com")));
419  EXPECT_FALSE(pattern.MatchesURL(GURL("chrome-extension://foobar")));
420  EXPECT_TRUE(pattern.MatchesURL(
421      GURL("filesystem:chrome-extension://ftw/t/file.txt")));
422};
423
424static const struct GetAsStringPatterns {
425  const char* pattern;
426} kGetAsStringTestCases[] = {
427  { "http://www/" },
428  { "http://*/*" },
429  { "chrome://*/*" },
430  { "chrome://newtab/" },
431  { "about:*" },
432  { "about:blank" },
433  { "chrome-extension://*/*" },
434  { "chrome-extension://FTW/" },
435  { "data:*" },
436  { "data:monkey" },
437  { "javascript:*" },
438  { "javascript:atemyhomework" },
439  { "http://www.example.com:8080/foo" },
440};
441
442TEST(ExtensionURLPatternTest, GetAsString) {
443  for (size_t i = 0; i < arraysize(kGetAsStringTestCases); ++i) {
444    URLPattern pattern(URLPattern::SCHEME_ALL);
445    EXPECT_EQ(URLPattern::PARSE_SUCCESS,
446              pattern.Parse(kGetAsStringTestCases[i].pattern))
447        << "Error parsing " << kGetAsStringTestCases[i].pattern;
448    EXPECT_EQ(kGetAsStringTestCases[i].pattern,
449              pattern.GetAsString());
450  }
451}
452
453testing::AssertionResult Overlaps(const URLPattern& pattern1,
454                                  const URLPattern& pattern2) {
455  if (!pattern1.OverlapsWith(pattern2)) {
456    return testing::AssertionFailure()
457        << pattern1.GetAsString() << " does not overlap " <<
458                                     pattern2.GetAsString();
459  }
460  if (!pattern2.OverlapsWith(pattern1)) {
461    return testing::AssertionFailure()
462        << pattern2.GetAsString() << " does not overlap " <<
463                                     pattern1.GetAsString();
464  }
465  return testing::AssertionSuccess()
466      << pattern1.GetAsString() << " overlaps with " << pattern2.GetAsString();
467}
468
469TEST(ExtensionURLPatternTest, Overlaps) {
470  URLPattern pattern1(kAllSchemes, "http://www.google.com/foo/*");
471  URLPattern pattern2(kAllSchemes, "https://www.google.com/foo/*");
472  URLPattern pattern3(kAllSchemes, "http://*.google.com/foo/*");
473  URLPattern pattern4(kAllSchemes, "http://*.yahooo.com/foo/*");
474  URLPattern pattern5(kAllSchemes, "http://www.yahooo.com/bar/*");
475  URLPattern pattern6(kAllSchemes,
476                      "http://www.yahooo.com/bar/baz/*");
477  URLPattern pattern7(kAllSchemes, "file:///*");
478  URLPattern pattern8(kAllSchemes, "*://*/*");
479  URLPattern pattern9(URLPattern::SCHEME_HTTPS, "*://*/*");
480  URLPattern pattern10(kAllSchemes, "<all_urls>");
481
482  EXPECT_TRUE(Overlaps(pattern1, pattern1));
483  EXPECT_FALSE(Overlaps(pattern1, pattern2));
484  EXPECT_TRUE(Overlaps(pattern1, pattern3));
485  EXPECT_FALSE(Overlaps(pattern1, pattern4));
486  EXPECT_FALSE(Overlaps(pattern3, pattern4));
487  EXPECT_FALSE(Overlaps(pattern4, pattern5));
488  EXPECT_TRUE(Overlaps(pattern5, pattern6));
489
490  // Test that scheme restrictions work.
491  EXPECT_TRUE(Overlaps(pattern1, pattern8));
492  EXPECT_FALSE(Overlaps(pattern1, pattern9));
493  EXPECT_TRUE(Overlaps(pattern1, pattern10));
494
495  // Test that '<all_urls>' includes file URLs, while scheme '*' does not.
496  EXPECT_FALSE(Overlaps(pattern7, pattern8));
497  EXPECT_TRUE(Overlaps(pattern7, pattern10));
498
499  // Test that wildcard schemes are handled correctly, especially when compared
500  // to each-other.
501  URLPattern pattern11(kAllSchemes, "http://example.com/*");
502  URLPattern pattern12(kAllSchemes, "*://example.com/*");
503  URLPattern pattern13(kAllSchemes, "*://example.com/foo/*");
504  URLPattern pattern14(kAllSchemes, "*://google.com/*");
505  EXPECT_TRUE(Overlaps(pattern8, pattern12));
506  EXPECT_TRUE(Overlaps(pattern9, pattern12));
507  EXPECT_TRUE(Overlaps(pattern10, pattern12));
508  EXPECT_TRUE(Overlaps(pattern11, pattern12));
509  EXPECT_TRUE(Overlaps(pattern12, pattern13));
510  EXPECT_TRUE(Overlaps(pattern11, pattern13));
511  EXPECT_FALSE(Overlaps(pattern14, pattern12));
512  EXPECT_FALSE(Overlaps(pattern14, pattern13));
513}
514
515TEST(ExtensionURLPatternTest, ConvertToExplicitSchemes) {
516  URLPatternList all_urls(URLPattern(
517      kAllSchemes,
518      "<all_urls>").ConvertToExplicitSchemes());
519
520  URLPatternList all_schemes(URLPattern(
521      kAllSchemes,
522      "*://google.com/foo").ConvertToExplicitSchemes());
523
524  URLPatternList monkey(URLPattern(
525      URLPattern::SCHEME_HTTP | URLPattern::SCHEME_HTTPS |
526      URLPattern::SCHEME_FTP,
527      "http://google.com/monkey").ConvertToExplicitSchemes());
528
529  ASSERT_EQ(7u, all_urls.size());
530  ASSERT_EQ(2u, all_schemes.size());
531  ASSERT_EQ(1u, monkey.size());
532
533  EXPECT_EQ("http://*/*", all_urls[0].GetAsString());
534  EXPECT_EQ("https://*/*", all_urls[1].GetAsString());
535  EXPECT_EQ("file:///*", all_urls[2].GetAsString());
536  EXPECT_EQ("ftp://*/*", all_urls[3].GetAsString());
537  EXPECT_EQ("chrome://*/*", all_urls[4].GetAsString());
538
539  EXPECT_EQ("http://google.com/foo", all_schemes[0].GetAsString());
540  EXPECT_EQ("https://google.com/foo", all_schemes[1].GetAsString());
541
542  EXPECT_EQ("http://google.com/monkey", monkey[0].GetAsString());
543}
544
545TEST(ExtensionURLPatternTest, IgnorePorts) {
546  std::string pattern_str = "http://www.example.com:8080/foo";
547  GURL url("http://www.example.com:1234/foo");
548
549  URLPattern pattern(kAllSchemes);
550  EXPECT_EQ(URLPattern::PARSE_SUCCESS, pattern.Parse(pattern_str));
551
552  EXPECT_EQ(pattern_str, pattern.GetAsString());
553  EXPECT_FALSE(pattern.MatchesURL(url));
554}
555
556TEST(ExtensionURLPatternTest, IgnoreMissingBackslashes) {
557  std::string pattern_str1 = "http://www.example.com/example";
558  std::string pattern_str2 = "http://www.example.com/example/*";
559  GURL url1("http://www.example.com/example");
560  GURL url2("http://www.example.com/example/");
561
562  URLPattern pattern1(kAllSchemes);
563  EXPECT_EQ(URLPattern::PARSE_SUCCESS, pattern1.Parse(pattern_str1));
564  URLPattern pattern2(kAllSchemes);
565  EXPECT_EQ(URLPattern::PARSE_SUCCESS, pattern2.Parse(pattern_str2));
566
567  // Same patterns should match same urls.
568  EXPECT_TRUE(pattern1.MatchesURL(url1));
569  EXPECT_TRUE(pattern2.MatchesURL(url2));
570  // The not terminated path should match the terminated pattern.
571  EXPECT_TRUE(pattern2.MatchesURL(url1));
572  // The terminated path however should not match the unterminated pattern.
573  EXPECT_FALSE(pattern1.MatchesURL(url2));
574}
575
576TEST(ExtensionURLPatternTest, Equals) {
577  const struct {
578    const char* pattern1;
579    const char* pattern2;
580    bool expected_equal;
581  } kEqualsTestCases[] = {
582    // schemes
583    { "http://en.google.com/blah/*/foo",
584      "https://en.google.com/blah/*/foo",
585      false
586    },
587    { "https://en.google.com/blah/*/foo",
588      "https://en.google.com/blah/*/foo",
589      true
590    },
591    { "https://en.google.com/blah/*/foo",
592      "ftp://en.google.com/blah/*/foo",
593      false
594    },
595
596    // subdomains
597    { "https://en.google.com/blah/*/foo",
598      "https://fr.google.com/blah/*/foo",
599      false
600    },
601    { "https://www.google.com/blah/*/foo",
602      "https://*.google.com/blah/*/foo",
603      false
604    },
605    { "https://*.google.com/blah/*/foo",
606      "https://*.google.com/blah/*/foo",
607      true
608    },
609
610    // domains
611    { "http://en.example.com/blah/*/foo",
612      "http://en.google.com/blah/*/foo",
613      false
614    },
615
616    // ports
617    { "http://en.google.com:8000/blah/*/foo",
618      "http://en.google.com/blah/*/foo",
619      false
620    },
621    { "http://fr.google.com:8000/blah/*/foo",
622      "http://fr.google.com:8000/blah/*/foo",
623      true
624    },
625    { "http://en.google.com:8000/blah/*/foo",
626      "http://en.google.com:8080/blah/*/foo",
627      false
628    },
629
630    // paths
631    { "http://en.google.com/blah/*/foo",
632      "http://en.google.com/blah/*",
633      false
634    },
635    { "http://en.google.com/*",
636      "http://en.google.com/",
637      false
638    },
639    { "http://en.google.com/*",
640      "http://en.google.com/*",
641      true
642    },
643
644    // all_urls
645    { "<all_urls>",
646      "<all_urls>",
647      true
648    },
649    { "<all_urls>",
650      "http://*/*",
651      false
652    }
653  };
654
655  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kEqualsTestCases); ++i) {
656    std::string message = kEqualsTestCases[i].pattern1;
657    message += " ";
658    message += kEqualsTestCases[i].pattern2;
659
660    URLPattern pattern1(URLPattern::SCHEME_ALL);
661    URLPattern pattern2(URLPattern::SCHEME_ALL);
662
663    pattern1.Parse(kEqualsTestCases[i].pattern1);
664    pattern2.Parse(kEqualsTestCases[i].pattern2);
665    EXPECT_EQ(kEqualsTestCases[i].expected_equal, pattern1 == pattern2)
666        << message;
667  }
668}
669
670TEST(ExtensionURLPatternTest, CanReusePatternWithParse) {
671  URLPattern pattern1(URLPattern::SCHEME_ALL);
672  EXPECT_EQ(URLPattern::PARSE_SUCCESS, pattern1.Parse("http://aa.com/*"));
673  EXPECT_EQ(URLPattern::PARSE_SUCCESS, pattern1.Parse("http://bb.com/*"));
674
675  EXPECT_TRUE(pattern1.MatchesURL(GURL("http://bb.com/path")));
676  EXPECT_FALSE(pattern1.MatchesURL(GURL("http://aa.com/path")));
677
678  URLPattern pattern2(URLPattern::SCHEME_ALL, URLPattern::kAllUrlsPattern);
679  EXPECT_EQ(URLPattern::PARSE_SUCCESS, pattern2.Parse("http://aa.com/*"));
680
681  EXPECT_FALSE(pattern2.MatchesURL(GURL("http://bb.com/path")));
682  EXPECT_TRUE(pattern2.MatchesURL(GURL("http://aa.com/path")));
683  EXPECT_FALSE(pattern2.MatchesURL(GURL("http://sub.aa.com/path")));
684
685  URLPattern pattern3(URLPattern::SCHEME_ALL, "http://aa.com/*");
686  EXPECT_EQ(URLPattern::PARSE_SUCCESS, pattern3.Parse("http://aa.com:88/*"));
687  EXPECT_FALSE(pattern3.MatchesURL(GURL("http://aa.com/path")));
688  EXPECT_TRUE(pattern3.MatchesURL(GURL("http://aa.com:88/path")));
689}
690
691// Returns success if neither |a| nor |b| encompasses the other.
692testing::AssertionResult NeitherContains(const URLPattern& a,
693                                         const URLPattern& b) {
694  if (a.Contains(b))
695    return testing::AssertionFailure() << a.GetAsString() << " encompasses " <<
696                                          b.GetAsString();
697  if (b.Contains(a))
698    return testing::AssertionFailure() << b.GetAsString() << " encompasses " <<
699                                          a.GetAsString();
700  return testing::AssertionSuccess() <<
701      "Neither " << a.GetAsString() << " nor " << b.GetAsString() <<
702      " encompass the other";
703}
704
705// Returns success if |a| encompasses |b| but not the other way around.
706testing::AssertionResult StrictlyContains(const URLPattern& a,
707                                          const URLPattern& b) {
708  if (!a.Contains(b))
709    return testing::AssertionFailure() << a.GetAsString() <<
710                                          " does not encompass " <<
711                                          b.GetAsString();
712  if (b.Contains(a))
713    return testing::AssertionFailure() << b.GetAsString() << " encompasses " <<
714                                          a.GetAsString();
715  return testing::AssertionSuccess() << a.GetAsString() <<
716                                        " strictly encompasses " <<
717                                        b.GetAsString();
718}
719
720TEST(ExtensionURLPatternTest, Subset) {
721  URLPattern pattern1(kAllSchemes, "http://www.google.com/foo/*");
722  URLPattern pattern2(kAllSchemes, "https://www.google.com/foo/*");
723  URLPattern pattern3(kAllSchemes, "http://*.google.com/foo/*");
724  URLPattern pattern4(kAllSchemes, "http://*.yahooo.com/foo/*");
725  URLPattern pattern5(kAllSchemes, "http://www.yahooo.com/bar/*");
726  URLPattern pattern6(kAllSchemes, "http://www.yahooo.com/bar/baz/*");
727  URLPattern pattern7(kAllSchemes, "file:///*");
728  URLPattern pattern8(kAllSchemes, "*://*/*");
729  URLPattern pattern9(URLPattern::SCHEME_HTTPS, "*://*/*");
730  URLPattern pattern10(kAllSchemes, "<all_urls>");
731  URLPattern pattern11(kAllSchemes, "http://example.com/*");
732  URLPattern pattern12(kAllSchemes, "*://example.com/*");
733  URLPattern pattern13(kAllSchemes, "*://example.com/foo/*");
734
735  // All patterns should encompass themselves.
736  EXPECT_TRUE(pattern1.Contains(pattern1));
737  EXPECT_TRUE(pattern2.Contains(pattern2));
738  EXPECT_TRUE(pattern3.Contains(pattern3));
739  EXPECT_TRUE(pattern4.Contains(pattern4));
740  EXPECT_TRUE(pattern5.Contains(pattern5));
741  EXPECT_TRUE(pattern6.Contains(pattern6));
742  EXPECT_TRUE(pattern7.Contains(pattern7));
743  EXPECT_TRUE(pattern8.Contains(pattern8));
744  EXPECT_TRUE(pattern9.Contains(pattern9));
745  EXPECT_TRUE(pattern10.Contains(pattern10));
746  EXPECT_TRUE(pattern11.Contains(pattern11));
747  EXPECT_TRUE(pattern12.Contains(pattern12));
748  EXPECT_TRUE(pattern13.Contains(pattern13));
749
750  // pattern1's relationship to the other patterns.
751  EXPECT_TRUE(NeitherContains(pattern1, pattern2));
752  EXPECT_TRUE(StrictlyContains(pattern3, pattern1));
753  EXPECT_TRUE(NeitherContains(pattern1, pattern4));
754  EXPECT_TRUE(NeitherContains(pattern1, pattern5));
755  EXPECT_TRUE(NeitherContains(pattern1, pattern6));
756  EXPECT_TRUE(NeitherContains(pattern1, pattern7));
757  EXPECT_TRUE(StrictlyContains(pattern8, pattern1));
758  EXPECT_TRUE(NeitherContains(pattern1, pattern9));
759  EXPECT_TRUE(StrictlyContains(pattern10, pattern1));
760  EXPECT_TRUE(NeitherContains(pattern1, pattern11));
761  EXPECT_TRUE(NeitherContains(pattern1, pattern12));
762  EXPECT_TRUE(NeitherContains(pattern1, pattern13));
763
764  // pattern2's relationship to the other patterns.
765  EXPECT_TRUE(NeitherContains(pattern2, pattern3));
766  EXPECT_TRUE(NeitherContains(pattern2, pattern4));
767  EXPECT_TRUE(NeitherContains(pattern2, pattern5));
768  EXPECT_TRUE(NeitherContains(pattern2, pattern6));
769  EXPECT_TRUE(NeitherContains(pattern2, pattern7));
770  EXPECT_TRUE(StrictlyContains(pattern8, pattern2));
771  EXPECT_TRUE(StrictlyContains(pattern9, pattern2));
772  EXPECT_TRUE(StrictlyContains(pattern10, pattern2));
773  EXPECT_TRUE(NeitherContains(pattern2, pattern11));
774  EXPECT_TRUE(NeitherContains(pattern2, pattern12));
775  EXPECT_TRUE(NeitherContains(pattern2, pattern13));
776
777  // Specifically test file:// URLs.
778  EXPECT_TRUE(NeitherContains(pattern7, pattern8));
779  EXPECT_TRUE(NeitherContains(pattern7, pattern9));
780  EXPECT_TRUE(StrictlyContains(pattern10, pattern7));
781
782  // <all_urls> encompasses everything.
783  EXPECT_TRUE(StrictlyContains(pattern10, pattern1));
784  EXPECT_TRUE(StrictlyContains(pattern10, pattern2));
785  EXPECT_TRUE(StrictlyContains(pattern10, pattern3));
786  EXPECT_TRUE(StrictlyContains(pattern10, pattern4));
787  EXPECT_TRUE(StrictlyContains(pattern10, pattern5));
788  EXPECT_TRUE(StrictlyContains(pattern10, pattern6));
789  EXPECT_TRUE(StrictlyContains(pattern10, pattern7));
790  EXPECT_TRUE(StrictlyContains(pattern10, pattern8));
791  EXPECT_TRUE(StrictlyContains(pattern10, pattern9));
792  EXPECT_TRUE(StrictlyContains(pattern10, pattern11));
793  EXPECT_TRUE(StrictlyContains(pattern10, pattern12));
794  EXPECT_TRUE(StrictlyContains(pattern10, pattern13));
795
796  // More...
797  EXPECT_TRUE(StrictlyContains(pattern12, pattern11));
798  EXPECT_TRUE(NeitherContains(pattern11, pattern13));
799  EXPECT_TRUE(StrictlyContains(pattern12, pattern13));
800}
801
802}  // namespace
803