// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "base/memory/scoped_ptr.h" #include "chrome/common/extensions/url_pattern.h" #include "testing/gtest/include/gtest/gtest.h" #include "googleurl/src/gurl.h" // See url_pattern.h for examples of valid and invalid patterns. static const int kAllSchemes = URLPattern::SCHEME_HTTP | URLPattern::SCHEME_HTTPS | URLPattern::SCHEME_FILE | URLPattern::SCHEME_FTP | URLPattern::SCHEME_CHROMEUI; TEST(ExtensionURLPatternTest, ParseInvalid) { const struct { const char* pattern; URLPattern::ParseResult expected_result; } kInvalidPatterns[] = { { "http", URLPattern::PARSE_ERROR_MISSING_SCHEME_SEPARATOR }, { "http:", URLPattern::PARSE_ERROR_WRONG_SCHEME_SEPARATOR }, { "http:/", URLPattern::PARSE_ERROR_WRONG_SCHEME_SEPARATOR }, { "about://", URLPattern::PARSE_ERROR_WRONG_SCHEME_SEPARATOR }, { "http://", URLPattern::PARSE_ERROR_EMPTY_HOST }, { "http:///", URLPattern::PARSE_ERROR_EMPTY_HOST }, { "http://*foo/bar", URLPattern::PARSE_ERROR_INVALID_HOST_WILDCARD }, { "http://foo.*.bar/baz", URLPattern::PARSE_ERROR_INVALID_HOST_WILDCARD }, { "http://fo.*.ba:123/baz", URLPattern::PARSE_ERROR_INVALID_HOST_WILDCARD }, { "http:/bar", URLPattern::PARSE_ERROR_WRONG_SCHEME_SEPARATOR }, { "http://bar", URLPattern::PARSE_ERROR_EMPTY_PATH }, }; for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kInvalidPatterns); ++i) { URLPattern pattern(URLPattern::SCHEME_ALL); EXPECT_EQ(kInvalidPatterns[i].expected_result, pattern.Parse(kInvalidPatterns[i].pattern, URLPattern::IGNORE_PORTS)) << kInvalidPatterns[i].pattern; } }; TEST(ExtensionURLPatternTest, Ports) { const struct { const char* pattern; URLPattern::ParseResult expected_result_error_on_ports; URLPattern::ParseResult expected_result_ignore_ports; URLPattern::ParseResult expected_result_use_ports; const char* expected_host_ignoring_ports; const char* expected_host_using_ports; const char* expected_port; } kTestPatterns[] = { { "http://foo:1234/", URLPattern::PARSE_ERROR_HAS_COLON, URLPattern::PARSE_SUCCESS, URLPattern::PARSE_SUCCESS, "foo:1234", "foo", "1234" }, { "http://foo:1234/bar", URLPattern::PARSE_ERROR_HAS_COLON, URLPattern::PARSE_SUCCESS, URLPattern::PARSE_SUCCESS, "foo:1234", "foo", "1234" }, { "http://*.foo:1234/", URLPattern::PARSE_ERROR_HAS_COLON, URLPattern::PARSE_SUCCESS, URLPattern::PARSE_SUCCESS, "*.foo:1234", "*.foo", "1234" }, { "http://*.foo:1234/bar", URLPattern::PARSE_ERROR_HAS_COLON, URLPattern::PARSE_SUCCESS, URLPattern::PARSE_SUCCESS, "*.foo:1234", "*.foo", "1234" }, { "http://:1234/", URLPattern::PARSE_ERROR_HAS_COLON, URLPattern::PARSE_SUCCESS, URLPattern::PARSE_SUCCESS, ":1234", "", "1234" }, { "http://foo:/", URLPattern::PARSE_ERROR_HAS_COLON, URLPattern::PARSE_SUCCESS, URLPattern::PARSE_ERROR_INVALID_PORT, "foo:", "foo", "*" }, { "http://foo:*/", URLPattern::PARSE_ERROR_HAS_COLON, URLPattern::PARSE_ERROR_INVALID_HOST_WILDCARD, URLPattern::PARSE_SUCCESS, "foo:*", "foo", "*" }, { "http://*.foo:/", URLPattern::PARSE_ERROR_HAS_COLON, URLPattern::PARSE_SUCCESS, URLPattern::PARSE_ERROR_INVALID_PORT, "*.foo:", "*.foo", "*" }, { "http://foo:com/", URLPattern::PARSE_ERROR_HAS_COLON, URLPattern::PARSE_SUCCESS, URLPattern::PARSE_ERROR_INVALID_PORT, "foo:com", "", "*" }, { "http://foo:123456/", URLPattern::PARSE_ERROR_HAS_COLON, URLPattern::PARSE_SUCCESS, URLPattern::PARSE_ERROR_INVALID_PORT, "foo:123456", "", "*" }, { "file://foo:1234/bar", URLPattern::PARSE_SUCCESS, URLPattern::PARSE_SUCCESS, URLPattern::PARSE_SUCCESS, "", "", "*" }, { "chrome://foo:1234/bar", URLPattern::PARSE_ERROR_HAS_COLON, URLPattern::PARSE_SUCCESS, URLPattern::PARSE_ERROR_INVALID_PORT, "foo:1234", "", "*" }, // Port-like strings in the path should not trigger a warning. { "http://*/:1234", URLPattern::PARSE_SUCCESS, URLPattern::PARSE_SUCCESS, URLPattern::PARSE_SUCCESS, "*", "*", "*" }, { "http://*.foo/bar:1234", URLPattern::PARSE_SUCCESS, URLPattern::PARSE_SUCCESS, URLPattern::PARSE_SUCCESS, "*.foo", "*.foo", "*" }, { "http://foo/bar:1234/path", URLPattern::PARSE_SUCCESS, URLPattern::PARSE_SUCCESS, URLPattern::PARSE_SUCCESS, "foo", "foo", "*" }, }; for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kTestPatterns); ++i) { URLPattern use_ports_pattern(URLPattern::SCHEME_ALL); // Check results with |USE_PORTS|. EXPECT_EQ(kTestPatterns[i].expected_result_use_ports, use_ports_pattern.Parse(kTestPatterns[i].pattern, URLPattern::USE_PORTS)) << "Got unexpected result for URL pattern: " << kTestPatterns[i].pattern; EXPECT_EQ(kTestPatterns[i].expected_port, use_ports_pattern.port()) << "Got unexpected port for URL pattern: " << kTestPatterns[i].pattern; URLPattern ignore_ports_pattern(URLPattern::SCHEME_ALL); // Check results with |IGNORE_PORTS|. EXPECT_EQ(kTestPatterns[i].expected_result_ignore_ports, ignore_ports_pattern.Parse(kTestPatterns[i].pattern, URLPattern::IGNORE_PORTS)) << "Got unexpected result for URL pattern: " << kTestPatterns[i].pattern; EXPECT_EQ("*", ignore_ports_pattern.port()) << "Got unexpected port for URL pattern: " << kTestPatterns[i].pattern; URLPattern error_on_ports_pattern(URLPattern::SCHEME_ALL); // Check results with |ERROR_ON_PORTS|. EXPECT_EQ(kTestPatterns[i].expected_result_error_on_ports, error_on_ports_pattern.Parse(kTestPatterns[i].pattern, URLPattern::ERROR_ON_PORTS)) << "Got unexpected result for URL pattern: " << kTestPatterns[i].pattern; } }; // all pages for a given scheme TEST(ExtensionURLPatternTest, Match1) { URLPattern pattern(kAllSchemes); EXPECT_EQ(URLPattern::PARSE_SUCCESS, pattern.Parse("http://*/*", URLPattern::ERROR_ON_PORTS)); EXPECT_EQ("http", pattern.scheme()); EXPECT_EQ("", pattern.host()); EXPECT_TRUE(pattern.match_subdomains()); EXPECT_FALSE(pattern.match_all_urls()); EXPECT_EQ("/*", pattern.path()); EXPECT_TRUE(pattern.MatchesURL(GURL("http://google.com"))); EXPECT_TRUE(pattern.MatchesURL(GURL("http://yahoo.com"))); EXPECT_TRUE(pattern.MatchesURL(GURL("http://google.com/foo"))); EXPECT_FALSE(pattern.MatchesURL(GURL("https://google.com"))); EXPECT_TRUE(pattern.MatchesURL(GURL("http://74.125.127.100/search"))); } // all domains TEST(ExtensionURLPatternTest, Match2) { URLPattern pattern(kAllSchemes); EXPECT_EQ(URLPattern::PARSE_SUCCESS, pattern.Parse("https://*/foo*", URLPattern::ERROR_ON_PORTS)); EXPECT_EQ("https", pattern.scheme()); EXPECT_EQ("", pattern.host()); EXPECT_TRUE(pattern.match_subdomains()); EXPECT_FALSE(pattern.match_all_urls()); EXPECT_EQ("/foo*", pattern.path()); EXPECT_TRUE(pattern.MatchesURL(GURL("https://www.google.com/foo"))); EXPECT_TRUE(pattern.MatchesURL(GURL("https://www.google.com/foobar"))); EXPECT_FALSE(pattern.MatchesURL(GURL("http://www.google.com/foo"))); EXPECT_FALSE(pattern.MatchesURL(GURL("https://www.google.com/"))); } // subdomains TEST(URLPatternTest, Match3) { URLPattern pattern(kAllSchemes); EXPECT_EQ(URLPattern::PARSE_SUCCESS, pattern.Parse("http://*.google.com/foo*bar", URLPattern::ERROR_ON_PORTS)); EXPECT_EQ("http", pattern.scheme()); EXPECT_EQ("google.com", pattern.host()); EXPECT_TRUE(pattern.match_subdomains()); EXPECT_FALSE(pattern.match_all_urls()); EXPECT_EQ("/foo*bar", pattern.path()); EXPECT_TRUE(pattern.MatchesURL(GURL("http://google.com/foobar"))); EXPECT_TRUE(pattern.MatchesURL(GURL("http://www.google.com/foo?bar"))); EXPECT_TRUE(pattern.MatchesURL( GURL("http://monkey.images.google.com/foooobar"))); EXPECT_FALSE(pattern.MatchesURL(GURL("http://yahoo.com/foobar"))); } // glob escaping TEST(ExtensionURLPatternTest, Match5) { URLPattern pattern(kAllSchemes); EXPECT_EQ(URLPattern::PARSE_SUCCESS, pattern.Parse("file:///foo?bar\\*baz", URLPattern::ERROR_ON_PORTS)); EXPECT_EQ("file", pattern.scheme()); EXPECT_EQ("", pattern.host()); EXPECT_FALSE(pattern.match_subdomains()); EXPECT_FALSE(pattern.match_all_urls()); EXPECT_EQ("/foo?bar\\*baz", pattern.path()); EXPECT_TRUE(pattern.MatchesURL(GURL("file:///foo?bar\\hellobaz"))); EXPECT_FALSE(pattern.MatchesURL(GURL("file:///fooXbar\\hellobaz"))); } // ip addresses TEST(ExtensionURLPatternTest, Match6) { URLPattern pattern(kAllSchemes); EXPECT_EQ(URLPattern::PARSE_SUCCESS, pattern.Parse("http://127.0.0.1/*", URLPattern::ERROR_ON_PORTS)); EXPECT_EQ("http", pattern.scheme()); EXPECT_EQ("127.0.0.1", pattern.host()); EXPECT_FALSE(pattern.match_subdomains()); EXPECT_FALSE(pattern.match_all_urls()); EXPECT_EQ("/*", pattern.path()); EXPECT_TRUE(pattern.MatchesURL(GURL("http://127.0.0.1"))); } // subdomain matching with ip addresses TEST(ExtensionURLPatternTest, Match7) { URLPattern pattern(kAllSchemes); EXPECT_EQ(URLPattern::PARSE_SUCCESS, pattern.Parse("http://*.0.0.1/*", URLPattern::ERROR_ON_PORTS)); // allowed, but useless EXPECT_EQ("http", pattern.scheme()); EXPECT_EQ("0.0.1", pattern.host()); EXPECT_TRUE(pattern.match_subdomains()); EXPECT_FALSE(pattern.match_all_urls()); EXPECT_EQ("/*", pattern.path()); // Subdomain matching is never done if the argument has an IP address host. EXPECT_FALSE(pattern.MatchesURL(GURL("http://127.0.0.1"))); }; // unicode TEST(ExtensionURLPatternTest, Match8) { URLPattern pattern(kAllSchemes); // The below is the ASCII encoding of the following URL: // http://*.\xe1\x80\xbf/a\xc2\x81\xe1* EXPECT_EQ(URLPattern::PARSE_SUCCESS, pattern.Parse("http://*.xn--gkd/a%C2%81%E1*", URLPattern::ERROR_ON_PORTS)); EXPECT_EQ("http", pattern.scheme()); EXPECT_EQ("xn--gkd", pattern.host()); EXPECT_TRUE(pattern.match_subdomains()); EXPECT_FALSE(pattern.match_all_urls()); EXPECT_EQ("/a%C2%81%E1*", pattern.path()); EXPECT_TRUE(pattern.MatchesURL( GURL("http://abc.\xe1\x80\xbf/a\xc2\x81\xe1xyz"))); EXPECT_TRUE(pattern.MatchesURL( GURL("http://\xe1\x80\xbf/a\xc2\x81\xe1\xe1"))); }; // chrome:// TEST(ExtensionURLPatternTest, Match9) { URLPattern pattern(kAllSchemes); EXPECT_EQ(URLPattern::PARSE_SUCCESS, pattern.Parse("chrome://favicon/*", URLPattern::ERROR_ON_PORTS)); EXPECT_EQ("chrome", pattern.scheme()); EXPECT_EQ("favicon", pattern.host()); EXPECT_FALSE(pattern.match_subdomains()); EXPECT_FALSE(pattern.match_all_urls()); EXPECT_EQ("/*", pattern.path()); EXPECT_TRUE(pattern.MatchesURL(GURL("chrome://favicon/http://google.com"))); EXPECT_TRUE(pattern.MatchesURL(GURL("chrome://favicon/https://google.com"))); EXPECT_FALSE(pattern.MatchesURL(GURL("chrome://history"))); }; // *:// TEST(ExtensionURLPatternTest, Match10) { URLPattern pattern(kAllSchemes); EXPECT_EQ(URLPattern::PARSE_SUCCESS, pattern.Parse("*://*/*", URLPattern::ERROR_ON_PORTS)); EXPECT_TRUE(pattern.MatchesScheme("http")); EXPECT_TRUE(pattern.MatchesScheme("https")); EXPECT_FALSE(pattern.MatchesScheme("chrome")); EXPECT_FALSE(pattern.MatchesScheme("file")); EXPECT_FALSE(pattern.MatchesScheme("ftp")); EXPECT_TRUE(pattern.match_subdomains()); EXPECT_FALSE(pattern.match_all_urls()); EXPECT_EQ("/*", pattern.path()); EXPECT_TRUE(pattern.MatchesURL(GURL("http://127.0.0.1"))); EXPECT_FALSE(pattern.MatchesURL(GURL("chrome://favicon/http://google.com"))); EXPECT_FALSE(pattern.MatchesURL(GURL("file:///foo/bar"))); EXPECT_FALSE(pattern.MatchesURL(GURL("file://localhost/foo/bar"))); }; // TEST(ExtensionURLPatternTest, Match11) { URLPattern pattern(kAllSchemes); EXPECT_EQ(URLPattern::PARSE_SUCCESS, pattern.Parse("", URLPattern::ERROR_ON_PORTS)); EXPECT_TRUE(pattern.MatchesScheme("chrome")); EXPECT_TRUE(pattern.MatchesScheme("http")); EXPECT_TRUE(pattern.MatchesScheme("https")); EXPECT_TRUE(pattern.MatchesScheme("file")); EXPECT_TRUE(pattern.match_subdomains()); EXPECT_TRUE(pattern.match_all_urls()); EXPECT_EQ("/*", pattern.path()); EXPECT_TRUE(pattern.MatchesURL(GURL("chrome://favicon/http://google.com"))); EXPECT_TRUE(pattern.MatchesURL(GURL("http://127.0.0.1"))); EXPECT_TRUE(pattern.MatchesURL(GURL("file:///foo/bar"))); EXPECT_TRUE(pattern.MatchesURL(GURL("file://localhost/foo/bar"))); // Make sure the properties are the same when creating an pattern // via SetMatchAllURLs and by parsing . URLPattern pattern2(kAllSchemes); pattern2.SetMatchAllURLs(true); EXPECT_EQ(pattern.valid_schemes(), pattern2.valid_schemes()); EXPECT_EQ(pattern.match_subdomains(), pattern2.match_subdomains()); EXPECT_EQ(pattern.path(), pattern2.path()); EXPECT_EQ(pattern.match_all_urls(), pattern2.match_all_urls()); EXPECT_EQ(pattern.scheme(), pattern2.scheme()); EXPECT_EQ(pattern.port(), pattern2.port()); EXPECT_EQ(pattern.GetAsString(), pattern2.GetAsString()); }; // SCHEME_ALL matches all schemes. TEST(ExtensionURLPatternTest, Match12) { URLPattern pattern(URLPattern::SCHEME_ALL); EXPECT_EQ(URLPattern::PARSE_SUCCESS, pattern.Parse("", URLPattern::ERROR_ON_PORTS)); EXPECT_TRUE(pattern.MatchesScheme("chrome")); EXPECT_TRUE(pattern.MatchesScheme("http")); EXPECT_TRUE(pattern.MatchesScheme("https")); EXPECT_TRUE(pattern.MatchesScheme("file")); EXPECT_TRUE(pattern.MatchesScheme("javascript")); EXPECT_TRUE(pattern.MatchesScheme("data")); EXPECT_TRUE(pattern.MatchesScheme("about")); EXPECT_TRUE(pattern.MatchesScheme("chrome-extension")); EXPECT_TRUE(pattern.match_subdomains()); EXPECT_TRUE(pattern.match_all_urls()); EXPECT_EQ("/*", pattern.path()); EXPECT_TRUE(pattern.MatchesURL(GURL("chrome://favicon/http://google.com"))); EXPECT_TRUE(pattern.MatchesURL(GURL("http://127.0.0.1"))); EXPECT_TRUE(pattern.MatchesURL(GURL("file:///foo/bar"))); EXPECT_TRUE(pattern.MatchesURL(GURL("file://localhost/foo/bar"))); EXPECT_TRUE(pattern.MatchesURL(GURL("chrome://newtab"))); EXPECT_TRUE(pattern.MatchesURL(GURL("about:blank"))); EXPECT_TRUE(pattern.MatchesURL(GURL("about:version"))); EXPECT_TRUE(pattern.MatchesURL( GURL("data:text/html;charset=utf-8,asdf"))); }; static const struct MatchPatterns { const char* pattern; const char* matches; } kMatch13UrlPatternTestCases[] = { {"about:*", "about:blank"}, {"about:blank", "about:blank"}, {"about:*", "about:version"}, {"chrome-extension://*/*", "chrome-extension://FTW"}, {"data:*", "data:monkey"}, {"javascript:*", "javascript:atemyhomework"}, }; // SCHEME_ALL and specific schemes. TEST(ExtensionURLPatternTest, Match13) { for (size_t i = 0; i < arraysize(kMatch13UrlPatternTestCases); ++i) { URLPattern pattern(URLPattern::SCHEME_ALL); EXPECT_EQ(URLPattern::PARSE_SUCCESS, pattern.Parse(kMatch13UrlPatternTestCases[i].pattern, URLPattern::ERROR_ON_PORTS)) << " while parsing " << kMatch13UrlPatternTestCases[i].pattern; EXPECT_TRUE(pattern.MatchesURL( GURL(kMatch13UrlPatternTestCases[i].matches))) << " while matching " << kMatch13UrlPatternTestCases[i].matches; } // Negative test. URLPattern pattern(URLPattern::SCHEME_ALL); EXPECT_EQ(URLPattern::PARSE_SUCCESS, pattern.Parse("data:*", URLPattern::ERROR_ON_PORTS)); EXPECT_FALSE(pattern.MatchesURL(GURL("about:blank"))); }; // file scheme with empty hostname TEST(ExtensionURLPatternTest, Match14) { URLPattern pattern(kAllSchemes); EXPECT_EQ(URLPattern::PARSE_SUCCESS, pattern.Parse("file:///foo*", URLPattern::ERROR_ON_PORTS)); EXPECT_EQ("file", pattern.scheme()); EXPECT_EQ("", pattern.host()); EXPECT_FALSE(pattern.match_subdomains()); EXPECT_FALSE(pattern.match_all_urls()); EXPECT_EQ("/foo*", pattern.path()); EXPECT_FALSE(pattern.MatchesURL(GURL("file://foo"))); EXPECT_FALSE(pattern.MatchesURL(GURL("file://foobar"))); EXPECT_TRUE(pattern.MatchesURL(GURL("file:///foo"))); EXPECT_TRUE(pattern.MatchesURL(GURL("file:///foobar"))); EXPECT_TRUE(pattern.MatchesURL(GURL("file://localhost/foo"))); } // file scheme without hostname part TEST(ExtensionURLPatternTest, Match15) { URLPattern pattern(kAllSchemes); EXPECT_EQ(URLPattern::PARSE_SUCCESS, pattern.Parse("file://foo*", URLPattern::ERROR_ON_PORTS)); EXPECT_EQ("file", pattern.scheme()); EXPECT_EQ("", pattern.host()); EXPECT_FALSE(pattern.match_subdomains()); EXPECT_FALSE(pattern.match_all_urls()); EXPECT_EQ("/foo*", pattern.path()); EXPECT_FALSE(pattern.MatchesURL(GURL("file://foo"))); EXPECT_FALSE(pattern.MatchesURL(GURL("file://foobar"))); EXPECT_TRUE(pattern.MatchesURL(GURL("file:///foo"))); EXPECT_TRUE(pattern.MatchesURL(GURL("file:///foobar"))); EXPECT_TRUE(pattern.MatchesURL(GURL("file://localhost/foo"))); } // file scheme with hostname TEST(ExtensionURLPatternTest, Match16) { URLPattern pattern(kAllSchemes); EXPECT_EQ(URLPattern::PARSE_SUCCESS, pattern.Parse("file://localhost/foo*", URLPattern::ERROR_ON_PORTS)); EXPECT_EQ("file", pattern.scheme()); // Since hostname is ignored for file://. EXPECT_EQ("", pattern.host()); EXPECT_FALSE(pattern.match_subdomains()); EXPECT_FALSE(pattern.match_all_urls()); EXPECT_EQ("/foo*", pattern.path()); EXPECT_FALSE(pattern.MatchesURL(GURL("file://foo"))); EXPECT_FALSE(pattern.MatchesURL(GURL("file://foobar"))); EXPECT_TRUE(pattern.MatchesURL(GURL("file:///foo"))); EXPECT_TRUE(pattern.MatchesURL(GURL("file:///foobar"))); EXPECT_TRUE(pattern.MatchesURL(GURL("file://localhost/foo"))); } // Specific port TEST(ExtensionURLPatternTest, Match17) { URLPattern pattern(kAllSchemes); EXPECT_EQ(URLPattern::PARSE_SUCCESS, pattern.Parse("http://www.example.com:80/foo", URLPattern::USE_PORTS)); EXPECT_EQ("http", pattern.scheme()); EXPECT_EQ("www.example.com", pattern.host()); EXPECT_FALSE(pattern.match_subdomains()); EXPECT_FALSE(pattern.match_all_urls()); EXPECT_EQ("/foo", pattern.path()); EXPECT_EQ("80", pattern.port()); EXPECT_TRUE(pattern.MatchesURL(GURL("http://www.example.com:80/foo"))); EXPECT_TRUE(pattern.MatchesURL(GURL("http://www.example.com/foo"))); EXPECT_FALSE(pattern.MatchesURL(GURL("http://www.example.com:8080/foo"))); } // Explicit port wildcard TEST(ExtensionURLPatternTest, Match18) { URLPattern pattern(kAllSchemes); EXPECT_EQ(URLPattern::PARSE_SUCCESS, pattern.Parse("http://www.example.com:*/foo", URLPattern::USE_PORTS)); EXPECT_EQ("http", pattern.scheme()); EXPECT_EQ("www.example.com", pattern.host()); EXPECT_FALSE(pattern.match_subdomains()); EXPECT_FALSE(pattern.match_all_urls()); EXPECT_EQ("/foo", pattern.path()); EXPECT_EQ("*", pattern.port()); EXPECT_TRUE(pattern.MatchesURL(GURL("http://www.example.com:80/foo"))); EXPECT_TRUE(pattern.MatchesURL(GURL("http://www.example.com/foo"))); EXPECT_TRUE(pattern.MatchesURL(GURL("http://www.example.com:8080/foo"))); } static const struct GetAsStringPatterns { const char* pattern; } kGetAsStringTestCases[] = { { "http://www/" }, { "http://*/*" }, { "chrome://*/*" }, { "chrome://newtab/" }, { "about:*" }, { "about:blank" }, { "chrome-extension://*/*" }, { "chrome-extension://FTW/" }, { "data:*" }, { "data:monkey" }, { "javascript:*" }, { "javascript:atemyhomework" }, { "http://www.example.com:8080/foo" }, }; TEST(ExtensionURLPatternTest, GetAsString) { for (size_t i = 0; i < arraysize(kGetAsStringTestCases); ++i) { URLPattern pattern1(URLPattern::SCHEME_ALL); EXPECT_EQ(URLPattern::PARSE_SUCCESS, pattern1.Parse(kGetAsStringTestCases[i].pattern, URLPattern::USE_PORTS)) << "Error parsing " << kGetAsStringTestCases[i].pattern; EXPECT_EQ(kGetAsStringTestCases[i].pattern, pattern1.GetAsString()); URLPattern pattern2(URLPattern::SCHEME_ALL); EXPECT_EQ(URLPattern::PARSE_SUCCESS, pattern2.Parse(kGetAsStringTestCases[i].pattern, URLPattern::IGNORE_PORTS)) << "Error parsing " << kGetAsStringTestCases[i].pattern; EXPECT_EQ(kGetAsStringTestCases[i].pattern, pattern2.GetAsString()); } } void TestPatternOverlap(const URLPattern& pattern1, const URLPattern& pattern2, bool expect_overlap) { EXPECT_EQ(expect_overlap, pattern1.OverlapsWith(pattern2)) << pattern1.GetAsString() << ", " << pattern2.GetAsString(); EXPECT_EQ(expect_overlap, pattern2.OverlapsWith(pattern1)) << pattern2.GetAsString() << ", " << pattern1.GetAsString(); } TEST(ExtensionURLPatternTest, OverlapsWith) { URLPattern pattern1(kAllSchemes, "http://www.google.com/foo/*"); URLPattern pattern2(kAllSchemes, "https://www.google.com/foo/*"); URLPattern pattern3(kAllSchemes, "http://*.google.com/foo/*"); URLPattern pattern4(kAllSchemes, "http://*.yahooo.com/foo/*"); URLPattern pattern5(kAllSchemes, "http://www.yahooo.com/bar/*"); URLPattern pattern6(kAllSchemes, "http://www.yahooo.com/bar/baz/*"); URLPattern pattern7(kAllSchemes, "file:///*"); URLPattern pattern8(kAllSchemes, "*://*/*"); URLPattern pattern9(URLPattern::SCHEME_HTTPS, "*://*/*"); URLPattern pattern10(kAllSchemes, ""); TestPatternOverlap(pattern1, pattern1, true); TestPatternOverlap(pattern1, pattern2, false); TestPatternOverlap(pattern1, pattern3, true); TestPatternOverlap(pattern1, pattern4, false); TestPatternOverlap(pattern3, pattern4, false); TestPatternOverlap(pattern4, pattern5, false); TestPatternOverlap(pattern5, pattern6, true); // Test that scheme restrictions work. TestPatternOverlap(pattern1, pattern8, true); TestPatternOverlap(pattern1, pattern9, false); TestPatternOverlap(pattern1, pattern10, true); // Test that '' includes file URLs, while scheme '*' does not. TestPatternOverlap(pattern7, pattern8, false); TestPatternOverlap(pattern7, pattern10, true); // Test that wildcard schemes are handled correctly, especially when compared // to each-other. URLPattern pattern11(kAllSchemes, "http://example.com/*"); URLPattern pattern12(kAllSchemes, "*://example.com/*"); URLPattern pattern13(kAllSchemes, "*://example.com/foo/*"); URLPattern pattern14(kAllSchemes, "*://google.com/*"); TestPatternOverlap(pattern8, pattern12, true); TestPatternOverlap(pattern9, pattern12, true); TestPatternOverlap(pattern10, pattern12, true); TestPatternOverlap(pattern11, pattern12, true); TestPatternOverlap(pattern12, pattern13, true); TestPatternOverlap(pattern11, pattern13, true); TestPatternOverlap(pattern14, pattern12, false); TestPatternOverlap(pattern14, pattern13, false); } TEST(ExtensionURLPatternTest, ConvertToExplicitSchemes) { URLPatternList all_urls(URLPattern( kAllSchemes, "").ConvertToExplicitSchemes()); URLPatternList all_schemes(URLPattern( kAllSchemes, "*://google.com/foo").ConvertToExplicitSchemes()); URLPatternList monkey(URLPattern( URLPattern::SCHEME_HTTP | URLPattern::SCHEME_HTTPS | URLPattern::SCHEME_FTP, "http://google.com/monkey").ConvertToExplicitSchemes()); ASSERT_EQ(5u, all_urls.size()); ASSERT_EQ(2u, all_schemes.size()); ASSERT_EQ(1u, monkey.size()); EXPECT_EQ("http://*/*", all_urls[0].GetAsString()); EXPECT_EQ("https://*/*", all_urls[1].GetAsString()); EXPECT_EQ("file:///*", all_urls[2].GetAsString()); EXPECT_EQ("ftp://*/*", all_urls[3].GetAsString()); EXPECT_EQ("chrome://*/*", all_urls[4].GetAsString()); EXPECT_EQ("http://google.com/foo", all_schemes[0].GetAsString()); EXPECT_EQ("https://google.com/foo", all_schemes[1].GetAsString()); EXPECT_EQ("http://google.com/monkey", monkey[0].GetAsString()); } TEST(ExtensionURLPatternTest, IgnorePorts) { std::string pattern_str = "http://www.example.com:8080/foo"; GURL url("http://www.example.com:1234/foo"); URLPattern pattern1(kAllSchemes); URLPattern pattern2(kAllSchemes); EXPECT_EQ(URLPattern::PARSE_SUCCESS, pattern1.Parse(pattern_str, URLPattern::IGNORE_PORTS)); EXPECT_EQ(URLPattern::PARSE_SUCCESS, pattern2.Parse(pattern_str, URLPattern::USE_PORTS)); EXPECT_EQ(pattern_str, pattern1.GetAsString()); EXPECT_EQ(pattern_str, pattern2.GetAsString()); EXPECT_FALSE(pattern1.MatchesURL(url)); EXPECT_FALSE(pattern2.MatchesURL(url)); } TEST(ExtensionURLPatternTest, Equals) { const struct { const char* pattern1; const char* pattern2; bool expected_equal; } kEqualsTestCases[] = { // schemes { "http://en.google.com/blah/*/foo", "https://en.google.com/blah/*/foo", false }, { "https://en.google.com/blah/*/foo", "https://en.google.com/blah/*/foo", true }, { "https://en.google.com/blah/*/foo", "ftp://en.google.com/blah/*/foo", false }, // subdomains { "https://en.google.com/blah/*/foo", "https://fr.google.com/blah/*/foo", false }, { "https://www.google.com/blah/*/foo", "https://*.google.com/blah/*/foo", false }, { "https://*.google.com/blah/*/foo", "https://*.google.com/blah/*/foo", true }, // domains { "http://en.example.com/blah/*/foo", "http://en.google.com/blah/*/foo", false }, // ports { "http://en.google.com:8000/blah/*/foo", "http://en.google.com/blah/*/foo", false }, { "http://fr.google.com:8000/blah/*/foo", "http://fr.google.com:8000/blah/*/foo", true }, { "http://en.google.com:8000/blah/*/foo", "http://en.google.com:8080/blah/*/foo", false }, // paths { "http://en.google.com/blah/*/foo", "http://en.google.com/blah/*", false }, { "http://en.google.com/*", "http://en.google.com/", false }, { "http://en.google.com/*", "http://en.google.com/*", true }, // all_urls { "", "", true }, { "", "http://*/*", false } }; for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kEqualsTestCases); ++i) { std::string message = kEqualsTestCases[i].pattern1; message += " "; message += kEqualsTestCases[i].pattern2; URLPattern pattern1(URLPattern::SCHEME_ALL); URLPattern pattern2(URLPattern::SCHEME_ALL); pattern1.Parse(kEqualsTestCases[i].pattern1, URLPattern::USE_PORTS); pattern2.Parse(kEqualsTestCases[i].pattern2, URLPattern::USE_PORTS); EXPECT_EQ(kEqualsTestCases[i].expected_equal, pattern1 == pattern2) << message; } }