url_pattern_unittest.cc revision 4a5e2dc747d50c653511c68ccb2cfbfb740bd5a7
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 "base/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 12static const int kAllSchemes = 13 URLPattern::SCHEME_HTTP | 14 URLPattern::SCHEME_HTTPS | 15 URLPattern::SCHEME_FILE | 16 URLPattern::SCHEME_FTP | 17 URLPattern::SCHEME_CHROMEUI; 18 19TEST(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:/bar", URLPattern::PARSE_ERROR_WRONG_SCHEME_SEPARATOR }, 33 { "http://bar", URLPattern::PARSE_ERROR_EMPTY_PATH }, 34 }; 35 36 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kInvalidPatterns); ++i) { 37 URLPattern pattern(URLPattern::SCHEME_ALL); 38 EXPECT_EQ(kInvalidPatterns[i].expected_result, 39 pattern.Parse(kInvalidPatterns[i].pattern)) 40 << kInvalidPatterns[i].pattern; 41 } 42}; 43 44// all pages for a given scheme 45TEST(ExtensionURLPatternTest, Match1) { 46 URLPattern pattern(kAllSchemes); 47 EXPECT_EQ(URLPattern::PARSE_SUCCESS, pattern.Parse("http://*/*")); 48 EXPECT_EQ("http", pattern.scheme()); 49 EXPECT_EQ("", pattern.host()); 50 EXPECT_TRUE(pattern.match_subdomains()); 51 EXPECT_FALSE(pattern.match_all_urls()); 52 EXPECT_EQ("/*", pattern.path()); 53 EXPECT_TRUE(pattern.MatchesUrl(GURL("http://google.com"))); 54 EXPECT_TRUE(pattern.MatchesUrl(GURL("http://yahoo.com"))); 55 EXPECT_TRUE(pattern.MatchesUrl(GURL("http://google.com/foo"))); 56 EXPECT_FALSE(pattern.MatchesUrl(GURL("https://google.com"))); 57 EXPECT_TRUE(pattern.MatchesUrl(GURL("http://74.125.127.100/search"))); 58} 59 60// all domains 61TEST(ExtensionURLPatternTest, Match2) { 62 URLPattern pattern(kAllSchemes); 63 EXPECT_EQ(URLPattern::PARSE_SUCCESS, pattern.Parse("https://*/foo*")); 64 EXPECT_EQ("https", pattern.scheme()); 65 EXPECT_EQ("", pattern.host()); 66 EXPECT_TRUE(pattern.match_subdomains()); 67 EXPECT_FALSE(pattern.match_all_urls()); 68 EXPECT_EQ("/foo*", pattern.path()); 69 EXPECT_TRUE(pattern.MatchesUrl(GURL("https://www.google.com/foo"))); 70 EXPECT_TRUE(pattern.MatchesUrl(GURL("https://www.google.com/foobar"))); 71 EXPECT_FALSE(pattern.MatchesUrl(GURL("http://www.google.com/foo"))); 72 EXPECT_FALSE(pattern.MatchesUrl(GURL("https://www.google.com/"))); 73} 74 75// subdomains 76TEST(URLPatternTest, Match3) { 77 URLPattern pattern(kAllSchemes); 78 EXPECT_EQ(URLPattern::PARSE_SUCCESS, 79 pattern.Parse("http://*.google.com/foo*bar")); 80 EXPECT_EQ("http", pattern.scheme()); 81 EXPECT_EQ("google.com", pattern.host()); 82 EXPECT_TRUE(pattern.match_subdomains()); 83 EXPECT_FALSE(pattern.match_all_urls()); 84 EXPECT_EQ("/foo*bar", pattern.path()); 85 EXPECT_TRUE(pattern.MatchesUrl(GURL("http://google.com/foobar"))); 86 EXPECT_TRUE(pattern.MatchesUrl(GURL("http://www.google.com/foo?bar"))); 87 EXPECT_TRUE(pattern.MatchesUrl( 88 GURL("http://monkey.images.google.com/foooobar"))); 89 EXPECT_FALSE(pattern.MatchesUrl(GURL("http://yahoo.com/foobar"))); 90} 91 92// glob escaping 93TEST(ExtensionURLPatternTest, Match5) { 94 URLPattern pattern(kAllSchemes); 95 EXPECT_EQ(URLPattern::PARSE_SUCCESS, 96 pattern.Parse("file:///foo?bar\\*baz")); 97 EXPECT_EQ("file", pattern.scheme()); 98 EXPECT_EQ("", pattern.host()); 99 EXPECT_FALSE(pattern.match_subdomains()); 100 EXPECT_FALSE(pattern.match_all_urls()); 101 EXPECT_EQ("/foo?bar\\*baz", pattern.path()); 102 EXPECT_TRUE(pattern.MatchesUrl(GURL("file:///foo?bar\\hellobaz"))); 103 EXPECT_FALSE(pattern.MatchesUrl(GURL("file:///fooXbar\\hellobaz"))); 104} 105 106// ip addresses 107TEST(ExtensionURLPatternTest, Match6) { 108 URLPattern pattern(kAllSchemes); 109 EXPECT_EQ(URLPattern::PARSE_SUCCESS, 110 pattern.Parse("http://127.0.0.1/*")); 111 EXPECT_EQ("http", pattern.scheme()); 112 EXPECT_EQ("127.0.0.1", pattern.host()); 113 EXPECT_FALSE(pattern.match_subdomains()); 114 EXPECT_FALSE(pattern.match_all_urls()); 115 EXPECT_EQ("/*", pattern.path()); 116 EXPECT_TRUE(pattern.MatchesUrl(GURL("http://127.0.0.1"))); 117} 118 119// subdomain matching with ip addresses 120TEST(ExtensionURLPatternTest, Match7) { 121 URLPattern pattern(kAllSchemes); 122 EXPECT_EQ(URLPattern::PARSE_SUCCESS, 123 pattern.Parse("http://*.0.0.1/*")); // allowed, but useless 124 EXPECT_EQ("http", pattern.scheme()); 125 EXPECT_EQ("0.0.1", pattern.host()); 126 EXPECT_TRUE(pattern.match_subdomains()); 127 EXPECT_FALSE(pattern.match_all_urls()); 128 EXPECT_EQ("/*", pattern.path()); 129 // Subdomain matching is never done if the argument has an IP address host. 130 EXPECT_FALSE(pattern.MatchesUrl(GURL("http://127.0.0.1"))); 131}; 132 133// unicode 134TEST(ExtensionURLPatternTest, Match8) { 135 URLPattern pattern(kAllSchemes); 136 // The below is the ASCII encoding of the following URL: 137 // http://*.\xe1\x80\xbf/a\xc2\x81\xe1* 138 EXPECT_EQ(URLPattern::PARSE_SUCCESS, 139 pattern.Parse("http://*.xn--gkd/a%C2%81%E1*")); 140 EXPECT_EQ("http", pattern.scheme()); 141 EXPECT_EQ("xn--gkd", pattern.host()); 142 EXPECT_TRUE(pattern.match_subdomains()); 143 EXPECT_FALSE(pattern.match_all_urls()); 144 EXPECT_EQ("/a%C2%81%E1*", pattern.path()); 145 EXPECT_TRUE(pattern.MatchesUrl( 146 GURL("http://abc.\xe1\x80\xbf/a\xc2\x81\xe1xyz"))); 147 EXPECT_TRUE(pattern.MatchesUrl( 148 GURL("http://\xe1\x80\xbf/a\xc2\x81\xe1\xe1"))); 149}; 150 151// chrome:// 152TEST(ExtensionURLPatternTest, Match9) { 153 URLPattern pattern(kAllSchemes); 154 EXPECT_EQ(URLPattern::PARSE_SUCCESS, 155 pattern.Parse("chrome://favicon/*")); 156 EXPECT_EQ("chrome", pattern.scheme()); 157 EXPECT_EQ("favicon", pattern.host()); 158 EXPECT_FALSE(pattern.match_subdomains()); 159 EXPECT_FALSE(pattern.match_all_urls()); 160 EXPECT_EQ("/*", pattern.path()); 161 EXPECT_TRUE(pattern.MatchesUrl(GURL("chrome://favicon/http://google.com"))); 162 EXPECT_TRUE(pattern.MatchesUrl(GURL("chrome://favicon/https://google.com"))); 163 EXPECT_FALSE(pattern.MatchesUrl(GURL("chrome://history"))); 164}; 165 166// *:// 167TEST(ExtensionURLPatternTest, Match10) { 168 URLPattern pattern(kAllSchemes); 169 EXPECT_EQ(URLPattern::PARSE_SUCCESS, pattern.Parse("*://*/*")); 170 EXPECT_TRUE(pattern.MatchesScheme("http")); 171 EXPECT_TRUE(pattern.MatchesScheme("https")); 172 EXPECT_FALSE(pattern.MatchesScheme("chrome")); 173 EXPECT_FALSE(pattern.MatchesScheme("file")); 174 EXPECT_FALSE(pattern.MatchesScheme("ftp")); 175 EXPECT_TRUE(pattern.match_subdomains()); 176 EXPECT_FALSE(pattern.match_all_urls()); 177 EXPECT_EQ("/*", pattern.path()); 178 EXPECT_TRUE(pattern.MatchesUrl(GURL("http://127.0.0.1"))); 179 EXPECT_FALSE(pattern.MatchesUrl(GURL("chrome://favicon/http://google.com"))); 180 EXPECT_FALSE(pattern.MatchesUrl(GURL("file:///foo/bar"))); 181}; 182 183// <all_urls> 184TEST(ExtensionURLPatternTest, Match11) { 185 URLPattern pattern(kAllSchemes); 186 EXPECT_EQ(URLPattern::PARSE_SUCCESS, pattern.Parse("<all_urls>")); 187 EXPECT_TRUE(pattern.MatchesScheme("chrome")); 188 EXPECT_TRUE(pattern.MatchesScheme("http")); 189 EXPECT_TRUE(pattern.MatchesScheme("https")); 190 EXPECT_TRUE(pattern.MatchesScheme("file")); 191 EXPECT_TRUE(pattern.match_subdomains()); 192 EXPECT_TRUE(pattern.match_all_urls()); 193 EXPECT_EQ("/*", pattern.path()); 194 EXPECT_TRUE(pattern.MatchesUrl(GURL("chrome://favicon/http://google.com"))); 195 EXPECT_TRUE(pattern.MatchesUrl(GURL("http://127.0.0.1"))); 196 EXPECT_TRUE(pattern.MatchesUrl(GURL("file:///foo/bar"))); 197}; 198 199// SCHEME_ALL matches all schemes. 200TEST(ExtensionURLPatternTest, Match12) { 201 URLPattern pattern(URLPattern::SCHEME_ALL); 202 EXPECT_EQ(URLPattern::PARSE_SUCCESS, pattern.Parse("<all_urls>")); 203 EXPECT_TRUE(pattern.MatchesScheme("chrome")); 204 EXPECT_TRUE(pattern.MatchesScheme("http")); 205 EXPECT_TRUE(pattern.MatchesScheme("https")); 206 EXPECT_TRUE(pattern.MatchesScheme("file")); 207 EXPECT_TRUE(pattern.MatchesScheme("javascript")); 208 EXPECT_TRUE(pattern.MatchesScheme("data")); 209 EXPECT_TRUE(pattern.MatchesScheme("about")); 210 EXPECT_TRUE(pattern.MatchesScheme("chrome-extension")); 211 EXPECT_TRUE(pattern.match_subdomains()); 212 EXPECT_TRUE(pattern.match_all_urls()); 213 EXPECT_EQ("/*", pattern.path()); 214 EXPECT_TRUE(pattern.MatchesUrl(GURL("chrome://favicon/http://google.com"))); 215 EXPECT_TRUE(pattern.MatchesUrl(GURL("http://127.0.0.1"))); 216 EXPECT_TRUE(pattern.MatchesUrl(GURL("file:///foo/bar"))); 217 EXPECT_TRUE(pattern.MatchesUrl(GURL("chrome://newtab"))); 218 EXPECT_TRUE(pattern.MatchesUrl(GURL("about:blank"))); 219 EXPECT_TRUE(pattern.MatchesUrl(GURL("about:version"))); 220 EXPECT_TRUE(pattern.MatchesUrl( 221 GURL("data:text/html;charset=utf-8,<html>asdf</html>"))); 222}; 223 224static const struct MatchPatterns { 225 const char* pattern; 226 const char* matches; 227} kMatch13UrlPatternTestCases[] = { 228 {"about:*", "about:blank"}, 229 {"about:blank", "about:blank"}, 230 {"about:*", "about:version"}, 231 {"chrome-extension://*/*", "chrome-extension://FTW"}, 232 {"data:*", "data:monkey"}, 233 {"javascript:*", "javascript:atemyhomework"}, 234}; 235 236// SCHEME_ALL and specific schemes. 237TEST(ExtensionURLPatternTest, Match13) { 238 for (size_t i = 0; i < arraysize(kMatch13UrlPatternTestCases); ++i) { 239 URLPattern pattern(URLPattern::SCHEME_ALL); 240 EXPECT_EQ(URLPattern::PARSE_SUCCESS, 241 pattern.Parse(kMatch13UrlPatternTestCases[i].pattern)) 242 << " while parsing " << kMatch13UrlPatternTestCases[i].pattern; 243 EXPECT_TRUE(pattern.MatchesUrl( 244 GURL(kMatch13UrlPatternTestCases[i].matches))) 245 << " while matching " << kMatch13UrlPatternTestCases[i].matches; 246 } 247 248 // Negative test. 249 URLPattern pattern(URLPattern::SCHEME_ALL); 250 EXPECT_EQ(URLPattern::PARSE_SUCCESS, pattern.Parse("data:*")); 251 EXPECT_FALSE(pattern.MatchesUrl(GURL("about:blank"))); 252}; 253 254static const struct GetAsStringPatterns { 255 const char* pattern; 256} kGetAsStringTestCases[] = { 257 { "http://www/" }, 258 { "http://*/*" }, 259 { "chrome://*/*" }, 260 { "chrome://newtab/" }, 261 { "about:*" }, 262 { "about:blank" }, 263 { "chrome-extension://*/*" }, 264 { "chrome-extension://FTW/" }, 265 { "data:*" }, 266 { "data:monkey" }, 267 { "javascript:*" }, 268 { "javascript:atemyhomework" }, 269}; 270 271TEST(ExtensionURLPatternTest, GetAsString) { 272 for (size_t i = 0; i < arraysize(kGetAsStringTestCases); ++i) { 273 URLPattern pattern(URLPattern::SCHEME_ALL); 274 EXPECT_EQ(URLPattern::PARSE_SUCCESS, 275 pattern.Parse(kGetAsStringTestCases[i].pattern)); 276 EXPECT_STREQ(kGetAsStringTestCases[i].pattern, 277 pattern.GetAsString().c_str()); 278 } 279} 280 281void TestPatternOverlap(const URLPattern& pattern1, const URLPattern& pattern2, 282 bool expect_overlap) { 283 EXPECT_EQ(expect_overlap, pattern1.OverlapsWith(pattern2)) 284 << pattern1.GetAsString() << ", " << pattern2.GetAsString(); 285 EXPECT_EQ(expect_overlap, pattern2.OverlapsWith(pattern1)) 286 << pattern2.GetAsString() << ", " << pattern1.GetAsString(); 287} 288 289TEST(ExtensionURLPatternTest, OverlapsWith) { 290 URLPattern pattern1(kAllSchemes, "http://www.google.com/foo/*"); 291 URLPattern pattern2(kAllSchemes, "https://www.google.com/foo/*"); 292 URLPattern pattern3(kAllSchemes, "http://*.google.com/foo/*"); 293 URLPattern pattern4(kAllSchemes, "http://*.yahooo.com/foo/*"); 294 URLPattern pattern5(kAllSchemes, "http://www.yahooo.com/bar/*"); 295 URLPattern pattern6(kAllSchemes, 296 "http://www.yahooo.com/bar/baz/*"); 297 URLPattern pattern7(kAllSchemes, "file:///*"); 298 URLPattern pattern8(kAllSchemes, "*://*/*"); 299 URLPattern pattern9(URLPattern::SCHEME_HTTPS, "*://*/*"); 300 URLPattern pattern10(kAllSchemes, "<all_urls>"); 301 302 TestPatternOverlap(pattern1, pattern1, true); 303 TestPatternOverlap(pattern1, pattern2, false); 304 TestPatternOverlap(pattern1, pattern3, true); 305 TestPatternOverlap(pattern1, pattern4, false); 306 TestPatternOverlap(pattern3, pattern4, false); 307 TestPatternOverlap(pattern4, pattern5, false); 308 TestPatternOverlap(pattern5, pattern6, true); 309 310 // Test that scheme restrictions work. 311 TestPatternOverlap(pattern1, pattern8, true); 312 TestPatternOverlap(pattern1, pattern9, false); 313 TestPatternOverlap(pattern1, pattern10, true); 314 315 // Test that '<all_urls>' includes file URLs, while scheme '*' does not. 316 TestPatternOverlap(pattern7, pattern8, false); 317 TestPatternOverlap(pattern7, pattern10, true); 318} 319 320TEST(ExtensionURLPatternTest, ConvertToExplicitSchemes) { 321 std::vector<URLPattern> all_urls(URLPattern( 322 kAllSchemes, 323 "<all_urls>").ConvertToExplicitSchemes()); 324 325 std::vector<URLPattern> all_schemes(URLPattern( 326 kAllSchemes, 327 "*://google.com/foo").ConvertToExplicitSchemes()); 328 329 std::vector<URLPattern> monkey(URLPattern( 330 URLPattern::SCHEME_HTTP | URLPattern::SCHEME_HTTPS | 331 URLPattern::SCHEME_FTP, 332 "http://google.com/monkey").ConvertToExplicitSchemes()); 333 334 ASSERT_EQ(5u, all_urls.size()); 335 ASSERT_EQ(2u, all_schemes.size()); 336 ASSERT_EQ(1u, monkey.size()); 337 338 EXPECT_EQ("http://*/*", all_urls[0].GetAsString()); 339 EXPECT_EQ("https://*/*", all_urls[1].GetAsString()); 340 EXPECT_EQ("file:///*", all_urls[2].GetAsString()); 341 EXPECT_EQ("ftp://*/*", all_urls[3].GetAsString()); 342 EXPECT_EQ("chrome://*/*", all_urls[4].GetAsString()); 343 344 EXPECT_EQ("http://google.com/foo", all_schemes[0].GetAsString()); 345 EXPECT_EQ("https://google.com/foo", all_schemes[1].GetAsString()); 346 347 EXPECT_EQ("http://google.com/monkey", monkey[0].GetAsString()); 348} 349