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