• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2011 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 "chrome/common/extensions/url_pattern.h"
7 #include "testing/gtest/include/gtest/gtest.h"
8 #include "googleurl/src/gurl.h"
9 
10 // See url_pattern.h for examples of valid and invalid patterns.
11 
12 static const int kAllSchemes =
13     URLPattern::SCHEME_HTTP |
14     URLPattern::SCHEME_HTTPS |
15     URLPattern::SCHEME_FILE |
16     URLPattern::SCHEME_FTP |
17     URLPattern::SCHEME_CHROMEUI;
18 
TEST(ExtensionURLPatternTest,ParseInvalid)19 TEST(ExtensionURLPatternTest, ParseInvalid) {
20   const struct {
21     const char* pattern;
22     URLPattern::ParseResult expected_result;
23   } kInvalidPatterns[] = {
24     { "http", URLPattern::PARSE_ERROR_MISSING_SCHEME_SEPARATOR },
25     { "http:", URLPattern::PARSE_ERROR_WRONG_SCHEME_SEPARATOR },
26     { "http:/", URLPattern::PARSE_ERROR_WRONG_SCHEME_SEPARATOR },
27     { "about://", URLPattern::PARSE_ERROR_WRONG_SCHEME_SEPARATOR },
28     { "http://", URLPattern::PARSE_ERROR_EMPTY_HOST },
29     { "http:///", URLPattern::PARSE_ERROR_EMPTY_HOST },
30     { "http://*foo/bar", URLPattern::PARSE_ERROR_INVALID_HOST_WILDCARD },
31     { "http://foo.*.bar/baz", URLPattern::PARSE_ERROR_INVALID_HOST_WILDCARD },
32     { "http://fo.*.ba:123/baz", URLPattern::PARSE_ERROR_INVALID_HOST_WILDCARD },
33     { "http:/bar", URLPattern::PARSE_ERROR_WRONG_SCHEME_SEPARATOR },
34     { "http://bar", URLPattern::PARSE_ERROR_EMPTY_PATH },
35   };
36 
37   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kInvalidPatterns); ++i) {
38     URLPattern pattern(URLPattern::SCHEME_ALL);
39     EXPECT_EQ(kInvalidPatterns[i].expected_result,
40               pattern.Parse(kInvalidPatterns[i].pattern,
41                             URLPattern::PARSE_LENIENT))
42         << kInvalidPatterns[i].pattern;
43   }
44 };
45 
TEST(ExtensionURLPatternTest,Colons)46 TEST(ExtensionURLPatternTest, Colons) {
47   const struct {
48     const char* pattern;
49     URLPattern::ParseResult expected_result;
50   } kTestPatterns[] = {
51     { "http://foo:1234/", URLPattern::PARSE_ERROR_HAS_COLON },
52     { "http://foo:1234/bar", URLPattern::PARSE_ERROR_HAS_COLON },
53     { "http://*.foo:1234/", URLPattern::PARSE_ERROR_HAS_COLON },
54     { "http://*.foo:1234/bar", URLPattern::PARSE_ERROR_HAS_COLON },
55     { "http://:1234/", URLPattern::PARSE_ERROR_HAS_COLON },
56     { "http://foo:/", URLPattern::PARSE_ERROR_HAS_COLON },
57     { "http://*.foo:/", URLPattern::PARSE_ERROR_HAS_COLON },
58     { "http://foo:com/", URLPattern::PARSE_ERROR_HAS_COLON },
59 
60     // Port-like strings in the path should not trigger a warning.
61     { "http://*/:1234", URLPattern::PARSE_SUCCESS },
62     { "http://*.foo/bar:1234", URLPattern::PARSE_SUCCESS },
63     { "http://foo/bar:1234/path", URLPattern::PARSE_SUCCESS },
64   };
65 
66   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kTestPatterns); ++i) {
67     URLPattern pattern(URLPattern::SCHEME_ALL);
68 
69     // Without |strict_error_checks|, expect success.
70     EXPECT_EQ(URLPattern::PARSE_SUCCESS,
71               pattern.Parse(kTestPatterns[i].pattern,
72                             URLPattern::PARSE_LENIENT))
73         << "Got unexpected error for URL pattern: "
74         << kTestPatterns[i].pattern;
75 
76     EXPECT_EQ(kTestPatterns[i].expected_result,
77               pattern.Parse(kTestPatterns[i].pattern,
78                             URLPattern::PARSE_STRICT))
79         << "Got unexpected result for URL pattern: "
80         << kTestPatterns[i].pattern;
81   }
82 };
83 
84 // all pages for a given scheme
TEST(ExtensionURLPatternTest,Match1)85 TEST(ExtensionURLPatternTest, Match1) {
86   URLPattern pattern(kAllSchemes);
87   EXPECT_EQ(URLPattern::PARSE_SUCCESS,
88             pattern.Parse("http://*/*", URLPattern::PARSE_STRICT));
89   EXPECT_EQ("http", pattern.scheme());
90   EXPECT_EQ("", pattern.host());
91   EXPECT_TRUE(pattern.match_subdomains());
92   EXPECT_FALSE(pattern.match_all_urls());
93   EXPECT_EQ("/*", pattern.path());
94   EXPECT_TRUE(pattern.MatchesUrl(GURL("http://google.com")));
95   EXPECT_TRUE(pattern.MatchesUrl(GURL("http://yahoo.com")));
96   EXPECT_TRUE(pattern.MatchesUrl(GURL("http://google.com/foo")));
97   EXPECT_FALSE(pattern.MatchesUrl(GURL("https://google.com")));
98   EXPECT_TRUE(pattern.MatchesUrl(GURL("http://74.125.127.100/search")));
99 }
100 
101 // all domains
TEST(ExtensionURLPatternTest,Match2)102 TEST(ExtensionURLPatternTest, Match2) {
103   URLPattern pattern(kAllSchemes);
104   EXPECT_EQ(URLPattern::PARSE_SUCCESS,
105             pattern.Parse("https://*/foo*", URLPattern::PARSE_STRICT));
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 }
116 
117 // subdomains
TEST(URLPatternTest,Match3)118 TEST(URLPatternTest, Match3) {
119   URLPattern pattern(kAllSchemes);
120   EXPECT_EQ(URLPattern::PARSE_SUCCESS,
121             pattern.Parse("http://*.google.com/foo*bar",
122                           URLPattern::PARSE_STRICT));
123   EXPECT_EQ("http", pattern.scheme());
124   EXPECT_EQ("google.com", pattern.host());
125   EXPECT_TRUE(pattern.match_subdomains());
126   EXPECT_FALSE(pattern.match_all_urls());
127   EXPECT_EQ("/foo*bar", pattern.path());
128   EXPECT_TRUE(pattern.MatchesUrl(GURL("http://google.com/foobar")));
129   EXPECT_TRUE(pattern.MatchesUrl(GURL("http://www.google.com/foo?bar")));
130   EXPECT_TRUE(pattern.MatchesUrl(
131       GURL("http://monkey.images.google.com/foooobar")));
132   EXPECT_FALSE(pattern.MatchesUrl(GURL("http://yahoo.com/foobar")));
133 }
134 
135 // glob escaping
TEST(ExtensionURLPatternTest,Match5)136 TEST(ExtensionURLPatternTest, Match5) {
137   URLPattern pattern(kAllSchemes);
138   EXPECT_EQ(URLPattern::PARSE_SUCCESS,
139             pattern.Parse("file:///foo?bar\\*baz", URLPattern::PARSE_STRICT));
140   EXPECT_EQ("file", pattern.scheme());
141   EXPECT_EQ("", pattern.host());
142   EXPECT_FALSE(pattern.match_subdomains());
143   EXPECT_FALSE(pattern.match_all_urls());
144   EXPECT_EQ("/foo?bar\\*baz", pattern.path());
145   EXPECT_TRUE(pattern.MatchesUrl(GURL("file:///foo?bar\\hellobaz")));
146   EXPECT_FALSE(pattern.MatchesUrl(GURL("file:///fooXbar\\hellobaz")));
147 }
148 
149 // ip addresses
TEST(ExtensionURLPatternTest,Match6)150 TEST(ExtensionURLPatternTest, Match6) {
151   URLPattern pattern(kAllSchemes);
152   EXPECT_EQ(URLPattern::PARSE_SUCCESS,
153             pattern.Parse("http://127.0.0.1/*", URLPattern::PARSE_STRICT));
154   EXPECT_EQ("http", pattern.scheme());
155   EXPECT_EQ("127.0.0.1", pattern.host());
156   EXPECT_FALSE(pattern.match_subdomains());
157   EXPECT_FALSE(pattern.match_all_urls());
158   EXPECT_EQ("/*", pattern.path());
159   EXPECT_TRUE(pattern.MatchesUrl(GURL("http://127.0.0.1")));
160 }
161 
162 // subdomain matching with ip addresses
TEST(ExtensionURLPatternTest,Match7)163 TEST(ExtensionURLPatternTest, Match7) {
164   URLPattern pattern(kAllSchemes);
165   EXPECT_EQ(URLPattern::PARSE_SUCCESS,
166             pattern.Parse("http://*.0.0.1/*",
167                           URLPattern::PARSE_STRICT)); // allowed, but useless
168   EXPECT_EQ("http", pattern.scheme());
169   EXPECT_EQ("0.0.1", pattern.host());
170   EXPECT_TRUE(pattern.match_subdomains());
171   EXPECT_FALSE(pattern.match_all_urls());
172   EXPECT_EQ("/*", pattern.path());
173   // Subdomain matching is never done if the argument has an IP address host.
174   EXPECT_FALSE(pattern.MatchesUrl(GURL("http://127.0.0.1")));
175 };
176 
177 // unicode
TEST(ExtensionURLPatternTest,Match8)178 TEST(ExtensionURLPatternTest, Match8) {
179   URLPattern pattern(kAllSchemes);
180   // The below is the ASCII encoding of the following URL:
181   // http://*.\xe1\x80\xbf/a\xc2\x81\xe1*
182   EXPECT_EQ(URLPattern::PARSE_SUCCESS,
183             pattern.Parse("http://*.xn--gkd/a%C2%81%E1*",
184                           URLPattern::PARSE_STRICT));
185   EXPECT_EQ("http", pattern.scheme());
186   EXPECT_EQ("xn--gkd", pattern.host());
187   EXPECT_TRUE(pattern.match_subdomains());
188   EXPECT_FALSE(pattern.match_all_urls());
189   EXPECT_EQ("/a%C2%81%E1*", pattern.path());
190   EXPECT_TRUE(pattern.MatchesUrl(
191       GURL("http://abc.\xe1\x80\xbf/a\xc2\x81\xe1xyz")));
192   EXPECT_TRUE(pattern.MatchesUrl(
193       GURL("http://\xe1\x80\xbf/a\xc2\x81\xe1\xe1")));
194 };
195 
196 // chrome://
TEST(ExtensionURLPatternTest,Match9)197 TEST(ExtensionURLPatternTest, Match9) {
198   URLPattern pattern(kAllSchemes);
199   EXPECT_EQ(URLPattern::PARSE_SUCCESS,
200             pattern.Parse("chrome://favicon/*", URLPattern::PARSE_STRICT));
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 // *://
TEST(ExtensionURLPatternTest,Match10)212 TEST(ExtensionURLPatternTest, Match10) {
213   URLPattern pattern(kAllSchemes);
214   EXPECT_EQ(URLPattern::PARSE_SUCCESS,
215             pattern.Parse("*://*/*", URLPattern::PARSE_STRICT));
216   EXPECT_TRUE(pattern.MatchesScheme("http"));
217   EXPECT_TRUE(pattern.MatchesScheme("https"));
218   EXPECT_FALSE(pattern.MatchesScheme("chrome"));
219   EXPECT_FALSE(pattern.MatchesScheme("file"));
220   EXPECT_FALSE(pattern.MatchesScheme("ftp"));
221   EXPECT_TRUE(pattern.match_subdomains());
222   EXPECT_FALSE(pattern.match_all_urls());
223   EXPECT_EQ("/*", pattern.path());
224   EXPECT_TRUE(pattern.MatchesUrl(GURL("http://127.0.0.1")));
225   EXPECT_FALSE(pattern.MatchesUrl(GURL("chrome://favicon/http://google.com")));
226   EXPECT_FALSE(pattern.MatchesUrl(GURL("file:///foo/bar")));
227 };
228 
229 // <all_urls>
TEST(ExtensionURLPatternTest,Match11)230 TEST(ExtensionURLPatternTest, Match11) {
231   URLPattern pattern(kAllSchemes);
232   EXPECT_EQ(URLPattern::PARSE_SUCCESS,
233             pattern.Parse("<all_urls>", URLPattern::PARSE_STRICT));
234   EXPECT_TRUE(pattern.MatchesScheme("chrome"));
235   EXPECT_TRUE(pattern.MatchesScheme("http"));
236   EXPECT_TRUE(pattern.MatchesScheme("https"));
237   EXPECT_TRUE(pattern.MatchesScheme("file"));
238   EXPECT_TRUE(pattern.match_subdomains());
239   EXPECT_TRUE(pattern.match_all_urls());
240   EXPECT_EQ("/*", pattern.path());
241   EXPECT_TRUE(pattern.MatchesUrl(GURL("chrome://favicon/http://google.com")));
242   EXPECT_TRUE(pattern.MatchesUrl(GURL("http://127.0.0.1")));
243   EXPECT_TRUE(pattern.MatchesUrl(GURL("file:///foo/bar")));
244 };
245 
246 // SCHEME_ALL matches all schemes.
TEST(ExtensionURLPatternTest,Match12)247 TEST(ExtensionURLPatternTest, Match12) {
248   URLPattern pattern(URLPattern::SCHEME_ALL);
249   EXPECT_EQ(URLPattern::PARSE_SUCCESS,
250             pattern.Parse("<all_urls>", URLPattern::PARSE_STRICT));
251   EXPECT_TRUE(pattern.MatchesScheme("chrome"));
252   EXPECT_TRUE(pattern.MatchesScheme("http"));
253   EXPECT_TRUE(pattern.MatchesScheme("https"));
254   EXPECT_TRUE(pattern.MatchesScheme("file"));
255   EXPECT_TRUE(pattern.MatchesScheme("javascript"));
256   EXPECT_TRUE(pattern.MatchesScheme("data"));
257   EXPECT_TRUE(pattern.MatchesScheme("about"));
258   EXPECT_TRUE(pattern.MatchesScheme("chrome-extension"));
259   EXPECT_TRUE(pattern.match_subdomains());
260   EXPECT_TRUE(pattern.match_all_urls());
261   EXPECT_EQ("/*", pattern.path());
262   EXPECT_TRUE(pattern.MatchesUrl(GURL("chrome://favicon/http://google.com")));
263   EXPECT_TRUE(pattern.MatchesUrl(GURL("http://127.0.0.1")));
264   EXPECT_TRUE(pattern.MatchesUrl(GURL("file:///foo/bar")));
265   EXPECT_TRUE(pattern.MatchesUrl(GURL("chrome://newtab")));
266   EXPECT_TRUE(pattern.MatchesUrl(GURL("about:blank")));
267   EXPECT_TRUE(pattern.MatchesUrl(GURL("about:version")));
268   EXPECT_TRUE(pattern.MatchesUrl(
269       GURL("data:text/html;charset=utf-8,<html>asdf</html>")));
270 };
271 
272 static const struct MatchPatterns {
273   const char* pattern;
274   const char* matches;
275 } kMatch13UrlPatternTestCases[] = {
276   {"about:*", "about:blank"},
277   {"about:blank", "about:blank"},
278   {"about:*", "about:version"},
279   {"chrome-extension://*/*", "chrome-extension://FTW"},
280   {"data:*", "data:monkey"},
281   {"javascript:*", "javascript:atemyhomework"},
282 };
283 
284 // SCHEME_ALL and specific schemes.
TEST(ExtensionURLPatternTest,Match13)285 TEST(ExtensionURLPatternTest, Match13) {
286   for (size_t i = 0; i < arraysize(kMatch13UrlPatternTestCases); ++i) {
287     URLPattern pattern(URLPattern::SCHEME_ALL);
288     EXPECT_EQ(URLPattern::PARSE_SUCCESS,
289               pattern.Parse(kMatch13UrlPatternTestCases[i].pattern,
290                             URLPattern::PARSE_STRICT))
291         << " while parsing " << kMatch13UrlPatternTestCases[i].pattern;
292     EXPECT_TRUE(pattern.MatchesUrl(
293         GURL(kMatch13UrlPatternTestCases[i].matches)))
294         << " while matching " << kMatch13UrlPatternTestCases[i].matches;
295   }
296 
297   // Negative test.
298   URLPattern pattern(URLPattern::SCHEME_ALL);
299   EXPECT_EQ(URLPattern::PARSE_SUCCESS,
300             pattern.Parse("data:*", URLPattern::PARSE_STRICT));
301   EXPECT_FALSE(pattern.MatchesUrl(GURL("about:blank")));
302 };
303 
304 static const struct GetAsStringPatterns {
305   const char* pattern;
306 } kGetAsStringTestCases[] = {
307   { "http://www/" },
308   { "http://*/*" },
309   { "chrome://*/*" },
310   { "chrome://newtab/" },
311   { "about:*" },
312   { "about:blank" },
313   { "chrome-extension://*/*" },
314   { "chrome-extension://FTW/" },
315   { "data:*" },
316   { "data:monkey" },
317   { "javascript:*" },
318   { "javascript:atemyhomework" },
319 };
320 
TEST(ExtensionURLPatternTest,GetAsString)321 TEST(ExtensionURLPatternTest, GetAsString) {
322   for (size_t i = 0; i < arraysize(kGetAsStringTestCases); ++i) {
323     URLPattern pattern(URLPattern::SCHEME_ALL);
324     EXPECT_EQ(URLPattern::PARSE_SUCCESS,
325               pattern.Parse(kGetAsStringTestCases[i].pattern,
326                             URLPattern::PARSE_STRICT));
327     EXPECT_STREQ(kGetAsStringTestCases[i].pattern,
328                  pattern.GetAsString().c_str());
329   }
330 }
331 
TestPatternOverlap(const URLPattern & pattern1,const URLPattern & pattern2,bool expect_overlap)332 void TestPatternOverlap(const URLPattern& pattern1, const URLPattern& pattern2,
333                         bool expect_overlap) {
334   EXPECT_EQ(expect_overlap, pattern1.OverlapsWith(pattern2))
335       << pattern1.GetAsString() << ", " << pattern2.GetAsString();
336   EXPECT_EQ(expect_overlap, pattern2.OverlapsWith(pattern1))
337       << pattern2.GetAsString() << ", " << pattern1.GetAsString();
338 }
339 
TEST(ExtensionURLPatternTest,OverlapsWith)340 TEST(ExtensionURLPatternTest, OverlapsWith) {
341   URLPattern pattern1(kAllSchemes, "http://www.google.com/foo/*");
342   URLPattern pattern2(kAllSchemes, "https://www.google.com/foo/*");
343   URLPattern pattern3(kAllSchemes, "http://*.google.com/foo/*");
344   URLPattern pattern4(kAllSchemes, "http://*.yahooo.com/foo/*");
345   URLPattern pattern5(kAllSchemes, "http://www.yahooo.com/bar/*");
346   URLPattern pattern6(kAllSchemes,
347                       "http://www.yahooo.com/bar/baz/*");
348   URLPattern pattern7(kAllSchemes, "file:///*");
349   URLPattern pattern8(kAllSchemes, "*://*/*");
350   URLPattern pattern9(URLPattern::SCHEME_HTTPS, "*://*/*");
351   URLPattern pattern10(kAllSchemes, "<all_urls>");
352 
353   TestPatternOverlap(pattern1, pattern1, true);
354   TestPatternOverlap(pattern1, pattern2, false);
355   TestPatternOverlap(pattern1, pattern3, true);
356   TestPatternOverlap(pattern1, pattern4, false);
357   TestPatternOverlap(pattern3, pattern4, false);
358   TestPatternOverlap(pattern4, pattern5, false);
359   TestPatternOverlap(pattern5, pattern6, true);
360 
361   // Test that scheme restrictions work.
362   TestPatternOverlap(pattern1, pattern8, true);
363   TestPatternOverlap(pattern1, pattern9, false);
364   TestPatternOverlap(pattern1, pattern10, true);
365 
366   // Test that '<all_urls>' includes file URLs, while scheme '*' does not.
367   TestPatternOverlap(pattern7, pattern8, false);
368   TestPatternOverlap(pattern7, pattern10, true);
369 }
370 
TEST(ExtensionURLPatternTest,ConvertToExplicitSchemes)371 TEST(ExtensionURLPatternTest, ConvertToExplicitSchemes) {
372   std::vector<URLPattern> all_urls(URLPattern(
373       kAllSchemes,
374       "<all_urls>").ConvertToExplicitSchemes());
375 
376   std::vector<URLPattern> all_schemes(URLPattern(
377       kAllSchemes,
378       "*://google.com/foo").ConvertToExplicitSchemes());
379 
380   std::vector<URLPattern> monkey(URLPattern(
381       URLPattern::SCHEME_HTTP | URLPattern::SCHEME_HTTPS |
382       URLPattern::SCHEME_FTP,
383       "http://google.com/monkey").ConvertToExplicitSchemes());
384 
385   ASSERT_EQ(5u, all_urls.size());
386   ASSERT_EQ(2u, all_schemes.size());
387   ASSERT_EQ(1u, monkey.size());
388 
389   EXPECT_EQ("http://*/*", all_urls[0].GetAsString());
390   EXPECT_EQ("https://*/*", all_urls[1].GetAsString());
391   EXPECT_EQ("file:///*", all_urls[2].GetAsString());
392   EXPECT_EQ("ftp://*/*", all_urls[3].GetAsString());
393   EXPECT_EQ("chrome://*/*", all_urls[4].GetAsString());
394 
395   EXPECT_EQ("http://google.com/foo", all_schemes[0].GetAsString());
396   EXPECT_EQ("https://google.com/foo", all_schemes[1].GetAsString());
397 
398   EXPECT_EQ("http://google.com/monkey", monkey[0].GetAsString());
399 }
400