diff options
author | aa@chromium.org <aa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-02-02 04:09:58 +0000 |
---|---|---|
committer | aa@chromium.org <aa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-02-02 04:09:58 +0000 |
commit | 0b7c092f7f5b196fd9085f1ab796a0c9ac9473a6 (patch) | |
tree | 53272fae82210fbf553bb3a1a0256fba5b851368 /chrome | |
parent | b112a4cc460212188d353b995a055f6e14029ba3 (diff) | |
download | chromium_src-0b7c092f7f5b196fd9085f1ab796a0c9ac9473a6.zip chromium_src-0b7c092f7f5b196fd9085f1ab796a0c9ac9473a6.tar.gz chromium_src-0b7c092f7f5b196fd9085f1ab796a0c9ac9473a6.tar.bz2 |
Introduce UrlPattern. This is basically me resuming work on
issue 14106, but as it is a complete rewrite, I have started
a new issue.
I also added supporting JoinString() and ReplaceAll()
utility functions.
Review URL: http://codereview.chromium.org/19704
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@9031 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r-- | chrome/chrome.xcodeproj/project.pbxproj | 8 | ||||
-rw-r--r-- | chrome/common/common.scons | 4 | ||||
-rw-r--r-- | chrome/common/common.vcproj | 12 | ||||
-rw-r--r-- | chrome/common/extensions/url_pattern.cc | 128 | ||||
-rw-r--r-- | chrome/common/extensions/url_pattern.h | 122 | ||||
-rw-r--r-- | chrome/common/extensions/url_pattern_unittest.cc | 132 | ||||
-rw-r--r-- | chrome/test/unit/unit_tests.scons | 1 | ||||
-rw-r--r-- | chrome/test/unit/unittests.vcproj | 16 |
8 files changed, 417 insertions, 6 deletions
diff --git a/chrome/chrome.xcodeproj/project.pbxproj b/chrome/chrome.xcodeproj/project.pbxproj index b185e9b..af82b2a 100644 --- a/chrome/chrome.xcodeproj/project.pbxproj +++ b/chrome/chrome.xcodeproj/project.pbxproj @@ -86,6 +86,7 @@ 3380A9D60F2FC8F6004EF74F /* render_dns_master.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4D640CE10EAE86A500EBCFC0 /* render_dns_master.cc */; }; 3380A9D70F2FC8F9004EF74F /* render_dns_master.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4D640CE10EAE86A500EBCFC0 /* render_dns_master.cc */; }; 3AEA44DB19C9D93B63D7A2E4 /* url_fetcher_protect.cc in Sources */ = {isa = PBXBuildFile; fileRef = 0B7CC9C105E90E0665852528 /* url_fetcher_protect.cc */; }; + 406DFE278638D6132B21B2C9 /* url_pattern.cc in Sources */ = {isa = PBXBuildFile; fileRef = 6447F24FADC63E58A44DB762 /* url_pattern.cc */; }; 4D1F59FE0F2A6BBB0040C1E3 /* image_diff.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4D1F59FD0F2A6BBB0040C1E3 /* image_diff.cc */; }; 4D1F5A060F2A6D170040C1E3 /* libbase.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4D7BFDC70E9D525B009A6919 /* libbase.a */; }; 4D1F5AAE0F2A6ECB0040C1E3 /* libbase_gfx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4D7BFDC90E9D525B009A6919 /* libbase_gfx.a */; }; @@ -222,6 +223,7 @@ 826853380F30AE0C009F6555 /* chrome_plugin_lib.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4D7BFB920E9D4C9F009A6919 /* chrome_plugin_lib.cc */; }; 8268533B0F30AE13009F6555 /* render_process.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4D640CCF0EAE868600EBCFC0 /* render_process.cc */; }; 8268533F0F30AE1C009F6555 /* ipc_sync_channel.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4D7BFBB60E9D4C9F009A6919 /* ipc_sync_channel.cc */; }; + 8570EB3F140C07ABF1957F12 /* url_pattern_unittest.cc in Sources */ = {isa = PBXBuildFile; fileRef = A9C335E39D39A7DE087850FC /* url_pattern_unittest.cc */; }; 8F51B73AAAF1772ECF9BD180 /* url_fetcher.cc in Sources */ = {isa = PBXBuildFile; fileRef = 778D7927798B7E3FAA498D3D /* url_fetcher.cc */; }; A54612DC0EE9958600A8EE5D /* extensions_service_unittest.cc in Sources */ = {isa = PBXBuildFile; fileRef = A54612DB0EE9958600A8EE5D /* extensions_service_unittest.cc */; }; A54612E20EE995F600A8EE5D /* extensions_service.cc in Sources */ = {isa = PBXBuildFile; fileRef = A54612D90EE9957000A8EE5D /* extensions_service.cc */; }; @@ -1848,6 +1850,7 @@ 4DCE9E2C0EF0B8C000682526 /* English */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = English; path = English.lproj/MainMenu.xib; sourceTree = "<group>"; }; 4DDC64500EAE392400FB5EBE /* zlib.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = zlib.xcodeproj; path = third_party/zlib/zlib.xcodeproj; sourceTree = "<group>"; }; 534E66C30F311BEC0006B2B2 /* temp_scaffolding_stubs.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = temp_scaffolding_stubs.cc; sourceTree = "<group>"; }; + 6447F24FADC63E58A44DB762 /* url_pattern.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = url_pattern.cc; path = common/extensions/url_pattern.cc; sourceTree = SOURCE_ROOT; }; 778D7927798B7E3FAA498D3D /* url_fetcher.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = url_fetcher.cc; sourceTree = "<group>"; }; 82684C5F0F2FAE68009F6555 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; }; 82684CCF0F2FAEC2009F6555 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; }; @@ -1891,6 +1894,7 @@ A7C6146D0F30DA1D008CEE5D /* ipc_test_sink.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ipc_test_sink.cc; sourceTree = "<group>"; }; A7C6146E0F30DA1D008CEE5D /* ipc_test_sink.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ipc_test_sink.h; sourceTree = "<group>"; }; A7CBAD370F322A7E00360BF5 /* shell_dialogs_mac.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = shell_dialogs_mac.mm; path = cocoa/shell_dialogs_mac.mm; sourceTree = "<group>"; }; + A9C335E39D39A7DE087850FC /* url_pattern_unittest.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = url_pattern_unittest.cc; path = common/extensions/url_pattern_unittest.cc; sourceTree = SOURCE_ROOT; }; B503E0FB0F01764800547DC6 /* user_script_slave_unittest.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = user_script_slave_unittest.cc; sourceTree = "<group>"; }; B54BD8FA0ED622C00093FD54 /* mach_message_source_mac.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = mach_message_source_mac.cc; sourceTree = "<group>"; }; B54BD8FB0ED622C00093FD54 /* mach_message_source_mac.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mach_message_source_mac.h; sourceTree = "<group>"; }; @@ -2429,6 +2433,8 @@ 4D7BFDD00E9D527E009A6919 /* Frameworks */, 4D7BFB090E9D4BA1009A6919 /* Projects */, 4D7BF3070E9D477E009A6919 /* Products */, + A9C335E39D39A7DE087850FC /* url_pattern_unittest.cc */, + 6447F24FADC63E58A44DB762 /* url_pattern.cc */, ); sourceTree = "<group>"; }; @@ -4654,6 +4660,7 @@ E4F324980EE5D7DE002533CE /* snippet_unittest.cc in Sources */, 4D7BFB3E0E9D4C2F009A6919 /* text_database_unittest.cc in Sources */, 4D7BFB610E9D4C4B009A6919 /* units_unittest.cc in Sources */, + 8570EB3F140C07ABF1957F12 /* url_pattern_unittest.cc in Sources */, B503E0FC0F01764800547DC6 /* user_script_slave_unittest.cc in Sources */, B502DA280F098056005BE90C /* visit_database_unittest.cc in Sources */, 4D7BFB420E9D4C35009A6919 /* visit_tracker_unittest.cc in Sources */, @@ -4708,6 +4715,7 @@ 4D7BFC9C0E9D4D46009A6919 /* thumbnail_score.cc in Sources */, E45076AB0F153629003BE099 /* time_format.cc in Sources */, E45076E50F153AB6003BE099 /* unzip.cc in Sources */, + 406DFE278638D6132B21B2C9 /* url_pattern.cc in Sources */, E46C4B3F0F21095400B393B8 /* url_request_intercept_job.cc in Sources */, 4D7BFCA30E9D4D48009A6919 /* visitedlink_common.cc in Sources */, E46C4B490F21096300B393B8 /* worker_thread_ticker.cc in Sources */, diff --git a/chrome/common/common.scons b/chrome/common/common.scons index 93fc73f..90b8a26 100644 --- a/chrome/common/common.scons +++ b/chrome/common/common.scons @@ -43,6 +43,10 @@ input_files = ChromeFileList([ # TODO(sgk): violate standard indentation so we don't have to # reindent too much when we remove the explicit MSVSFilter() calls # in favor of generating the hierarchy to reflect the file system. + MSVSFilter('extensions', [ + 'extensions/url_pattern.cc', + 'extensions/url_pattern.h', + ]), MSVSFilter('net', [ 'net/cookie_monster_sqlite.cc', 'net/cookie_monster_sqlite.h', diff --git a/chrome/common/common.vcproj b/chrome/common/common.vcproj index 48fe00b..bdc1e23 100644 --- a/chrome/common/common.vcproj +++ b/chrome/common/common.vcproj @@ -309,6 +309,18 @@ > </File> </Filter> + <Filter + Name="extensions" + > + <File + RelativePath=".\extensions\url_pattern.cc" + > + </File> + <File + RelativePath=".\extensions\url_pattern.h" + > + </File> + </Filter> <File RelativePath=".\animation.cc" > diff --git a/chrome/common/extensions/url_pattern.cc b/chrome/common/extensions/url_pattern.cc new file mode 100644 index 0000000..bb32cb5 --- /dev/null +++ b/chrome/common/extensions/url_pattern.cc @@ -0,0 +1,128 @@ +// Copyright (c) 2006-2009 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/string_piece.h" +#include "base/string_util.h" +#include "chrome/common/extensions/url_pattern.h" + +// TODO(aa): Consider adding chrome-extension? What about more obscure ones +// like data: and javascript: ? +static const char* kValidSchemes[] = { + "http", + "https", + "file", + "ftp", + "chrome-ui" +}; + +static const char kSchemeSeparator[] = "://"; +static const char kPathSeparator[] = "/"; + +static bool IsValidScheme(const std::string& scheme) { + for (size_t i = 0; i < arraysize(kValidSchemes); ++i) { + if (scheme == kValidSchemes[i]) + return true; + } + + return false; +} + +bool URLPattern::Parse(const std::string& pattern) { + size_t scheme_end_pos = pattern.find(kSchemeSeparator); + if (scheme_end_pos == std::string::npos) + return false; + + scheme_ = pattern.substr(0, scheme_end_pos); + if (!IsValidScheme(scheme_)) + return false; + + size_t host_start_pos = scheme_end_pos + strlen(kSchemeSeparator); + if (host_start_pos >= pattern.length()) + return false; + + // Parse out the host and path. + size_t path_start_pos = 0; + + // File URLs are special because they have no host. There are other schemes + // with the same structure, but we don't support them (yet). + if (scheme_ == "file") { + path_start_pos = host_start_pos; + } else { + size_t host_end_pos = pattern.find(kPathSeparator, host_start_pos); + if (host_end_pos == std::string::npos) + return false; + + host_ = pattern.substr(host_start_pos, host_end_pos - host_start_pos); + + // The first component can optionally be '*' to match all subdomains. + std::vector<std::string> host_components; + SplitString(host_, '.', &host_components); + if (host_components[0] == "*") { + match_subdomains_ = true; + host_components.erase(host_components.begin(), + host_components.begin() + 1); + } + host_ = JoinString(host_components, '.'); + + // No other '*' can occur in the host, though. This isn't necessary, but is + // done as a convenience to developers who might otherwise be confused and + // think '*' works as a glob in the host. + if (host_.find('*') != std::string::npos) + return false; + + path_start_pos = host_end_pos; + } + + path_ = pattern.substr(path_start_pos); + return true; +} + +bool URLPattern::MatchesUrl(const GURL &test) { + if (test.scheme() != scheme_) + return false; + + if (!MatchesHost(test)) + return false; + + if (!MatchesPath(test)) + return false; + + return true; +} + +bool URLPattern::MatchesHost(const GURL& test) { + if (test.host() == host_) + return true; + + if (!match_subdomains_ || test.HostIsIPAddress()) + return false; + + // If we're matching subdomains, and we have no host, that means the pattern + // was <scheme>://*/<whatever>, so we match anything. + if (host_.empty()) + return true; + + // Check if the test host is a subdomain of our host. + if (test.host().length() <= (host_.length() + 1)) + return false; + + if (test.host().compare(test.host().length() - host_.length(), + host_.length(), host_) != 0) + return false; + + return test.host()[test.host().length() - host_.length() - 1] == '.'; +} + +bool URLPattern::MatchesPath(const GURL& test) { + if (path_escaped_.empty()) { + path_escaped_ = path_; + ReplaceSubstringsAfterOffset(&path_escaped_, 0, "\\", "\\\\"); + ReplaceSubstringsAfterOffset(&path_escaped_, 0, "?", "\\?"); + } + + if (!MatchPattern(test.PathForRequest(), path_escaped_)) + return false; + + return true; +} diff --git a/chrome/common/extensions/url_pattern.h b/chrome/common/extensions/url_pattern.h new file mode 100644 index 0000000..0be9660 --- /dev/null +++ b/chrome/common/extensions/url_pattern.h @@ -0,0 +1,122 @@ +// Copyright (c) 2006-2009 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. +#ifndef CHROME_BROWSER_EXTENSIONS_MATCH_PATTERN_H_ +#define CHROME_BROWSER_EXTENSIONS_MATCH_PATTERN_H_ + +#include "googleurl/src/gurl.h" + +// A pattern that can be used to match URLs. A URLPattern is a very restricted +// subset of URL syntax: +// +// <url-pattern> := <scheme>://<host><path> +// <scheme> := 'http' | 'https' | 'file' | 'ftp' | 'chrome-ui' +// <host> := '*' | '*.' <anychar except '/' and '*'>+ +// <path> := '/' <any chars> +// +// * Host is not used when the scheme is 'file'. +// * The path can have embedded '*' characters which act as glob wildcards. +// +// Examples of valid patterns: +// - http://*/* +// - http://*/foo* +// - https://*.google.com/foo*bar +// - chrome-ui://foo/bar +// - file://monkey* +// - http://127.0.0.1/* +// +// Examples of invalid patterns: +// - http://* -- path not specified +// - http://*foo/bar -- * not allowed as substring of host component +// - http://foo.*.bar/baz -- * must be first component +// - http:/bar -- scheme separator not found +// - foo://* -- invalid scheme +// +// Design rationale: +// * We need to be able to tell users what 'sites' a given URLPattern will +// affect. For example "This extension will interact with the site +// 'www.google.com'. +// * We'd like to be able to convert as many existing Greasemonkey @include +// patterns to URLPatterns as possible. Greasemonkey @include patterns are +// simple globs, so this won't be perfect. +// * Although we would like to support any scheme, it isn't clear what to tell +// users about URLPatterns that affect data or javascript URLs, and saying +// something useful about chrome-extension URLs is more work, so those are +// left out for now. +// +// From a 2008-ish crawl of userscripts.org, the following patterns were found +// in @include lines: +// - total lines : 24271 +// - @include * : 919 +// - @include http://[^\*]+?/ : 11128 (no star in host) +// - @include http://\*\.[^\*]+?/ : 2325 (host prefixed by *.) +// - @include http://\*[^\.][^\*]+?/: 1524 (host prefixed by *, no dot -- many +// appear to only need subdomain +// matching, not real prefix matching) +// - @include http://[^\*/]+\*/ : 320 (host suffixed by *) +// - @include contains .tld : 297 (host suffixed by .tld -- a special +// Greasemonkey domain component that +// tries to match all valid registry- +// controlled suffixes) +// - @include http://\*/ : 228 (host is * exactly, but there is +// more to the pattern) +// +// So, we can support at least half of current @include lines without supporting +// subdomain matching. We can pick up at least another 10% by supporting +// subdomain matching. It is probably possible to coerce more of the existing +// patterns to URLPattern, but the resulting pattern will be more restrictive +// than the original glob, which is probably better than nothing. +class URLPattern { + public: + URLPattern() : match_subdomains_(false) {} + + // Initializes this instance by parsing the provided string. On failure, the + // instance will have some intermediate values and is in an invalid state. + bool Parse(const std::string& pattern_str); + + // Returns true if this instance matches the specified URL. + bool MatchesUrl(const GURL& url); + + // Get the scheme the pattern matches. This will always return a valid scheme + // if is_valid() returns true. + std::string scheme() const { return scheme_; } + + // Gets the host the pattern matches. This can be an empty string if the + // pattern matches all hosts (the input was <scheme>://*/<whatever>). + std::string host() const { return host_; } + + // Gets whether to match subdomains of host(). + bool match_subdomains() const { return match_subdomains_; } + + // Gets the path the pattern matches with the leading slash. This can have + // embedded asterisks which are interpreted using glob rules. + std::string path() const { return path_; } + + private: + // Returns true if |test| matches our host. + bool MatchesHost(const GURL& test); + + // Returns true if |test| matches our path. + bool MatchesPath(const GURL& test); + + // The scheme for the pattern. + std::string scheme_; + + // The host without any leading "*" components. + std::string host_; + + // Whether we should match subdomains of the host. This is true if the first + // component of the pattern's host was "*". + bool match_subdomains_; + + // The path to match. This is everything after the host of the URL, or + // everything after the scheme in the case of file:// URLs. + std::string path_; + + // The path with "?" and "\" characters escaped for use with the + // MatchPattern() function. This is populated lazily, the first time it is + // needed. + std::string path_escaped_; +}; + +#endif // CHROME_BROWSER_EXTENSIONS_MATCH_PATTERN_H_ diff --git a/chrome/common/extensions/url_pattern_unittest.cc b/chrome/common/extensions/url_pattern_unittest.cc new file mode 100644 index 0000000..b53fc07 --- /dev/null +++ b/chrome/common/extensions/url_pattern_unittest.cc @@ -0,0 +1,132 @@ +// Copyright (c) 2006-2009 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 "chrome/common/extensions/url_pattern.h" +#include "testing/gtest/include/gtest/gtest.h" + +// See url_pattern.h for examples of valid and invalid patterns. + +TEST(URLPatternTest, ParseInvalid) { + const char* kInvalidPatterns[] = { + "http", // no scheme + "http://", // no path separator + "http://foo", // no path separator + "http://*foo/bar", // not allowed as substring of host component + "http://foo.*.bar/baz", // must be first component + "http:/bar", // scheme separator not found + "foo://*", // invalid scheme + }; + + for (size_t i = 0; i < arraysize(kInvalidPatterns); ++i) { + URLPattern pattern; + EXPECT_FALSE(pattern.Parse(kInvalidPatterns[i])); + } +}; + +// all pages for a given scheme +TEST(URLPatternTest, Match1) { + URLPattern pattern; + EXPECT_TRUE(pattern.Parse("http://*/*")); + EXPECT_EQ("http", pattern.scheme()); + EXPECT_EQ("", pattern.host()); + EXPECT_TRUE(pattern.match_subdomains()); + 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"))); +} + +// all domains +TEST(URLPatternTest, Match2) { + URLPattern pattern; + EXPECT_TRUE(pattern.Parse("https://*/foo*")); + EXPECT_EQ("https", pattern.scheme()); + EXPECT_EQ("", pattern.host()); + EXPECT_TRUE(pattern.match_subdomains()); + 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; + EXPECT_TRUE(pattern.Parse("http://*.google.com/foo*bar")); + EXPECT_EQ("http", pattern.scheme()); + EXPECT_EQ("google.com", pattern.host()); + EXPECT_TRUE(pattern.match_subdomains()); + 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"))); +} + +// odd schemes and normalization +TEST(URLPatternTest, Match4) { + URLPattern pattern; + EXPECT_TRUE(pattern.Parse("chrome-ui://thinger/*")); + EXPECT_EQ("chrome-ui", pattern.scheme()); + EXPECT_EQ("thinger", pattern.host()); + EXPECT_FALSE(pattern.match_subdomains()); + EXPECT_EQ("/*", pattern.path()); + EXPECT_TRUE(pattern.MatchesUrl(GURL("chrome-ui://thinger/foobar"))); + EXPECT_TRUE(pattern.MatchesUrl(GURL("CHROME-UI://thinger/"))); + EXPECT_FALSE(pattern.MatchesUrl(GURL("http://thinger/"))); +} + +// glob escaping +TEST(URLPatternTest, Match5) { + URLPattern pattern; + EXPECT_TRUE(pattern.Parse("file:///foo?bar\\*baz")); + EXPECT_EQ("file", pattern.scheme()); + EXPECT_EQ("", pattern.host()); + EXPECT_FALSE(pattern.match_subdomains()); + 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(URLPatternTest, Match6) { + URLPattern pattern; + EXPECT_TRUE(pattern.Parse("http://127.0.0.1/*")); + EXPECT_EQ("http", pattern.scheme()); + EXPECT_EQ("127.0.0.1", pattern.host()); + EXPECT_FALSE(pattern.match_subdomains()); + EXPECT_EQ("/*", pattern.path()); + EXPECT_TRUE(pattern.MatchesUrl(GURL("http://127.0.0.1"))); +} + +// subdomain matching with ip addresses +TEST(URLPatternTest, Match7) { + URLPattern pattern; + EXPECT_TRUE(pattern.Parse("http://*.0.0.1/*")); // allowed, but useless + EXPECT_EQ("http", pattern.scheme()); + EXPECT_EQ("0.0.1", pattern.host()); + EXPECT_TRUE(pattern.match_subdomains()); + 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(URLPatternTest, Match8) { + URLPattern pattern; + // The below is the ASCII encoding of the following URL: + // http://*.\xe1\x80\xbf/a\xc2\x81\xe1* + EXPECT_TRUE(pattern.Parse("http://*.xn--gkd/a%C2%81%E1*")); + EXPECT_EQ("http", pattern.scheme()); + EXPECT_EQ("xn--gkd", pattern.host()); + EXPECT_TRUE(pattern.match_subdomains()); + 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"))); +}; diff --git a/chrome/test/unit/unit_tests.scons b/chrome/test/unit/unit_tests.scons index 3411657..0c720fa 100644 --- a/chrome/test/unit/unit_tests.scons +++ b/chrome/test/unit/unit_tests.scons @@ -202,6 +202,7 @@ input_files = ChromeFileList([ '$CHROME_DIR/common/animation_unittest.cc', '$CHROME_DIR/common/bzip2_unittest.cc', '$CHROME_DIR/common/chrome_plugin_unittest.cc', + '$CHROME_DIR/common/extensions/url_pattern_unittest.cc', '$CHROME_DIR/common/gfx/emf_unittest.cc', '$CHROME_DIR/common/gfx/icon_util_unittest.cc', '$CHROME_DIR/common/ipc_message_unittest.cc', diff --git a/chrome/test/unit/unittests.vcproj b/chrome/test/unit/unittests.vcproj index 79e15d11..fbd1da5 100644 --- a/chrome/test/unit/unittests.vcproj +++ b/chrome/test/unit/unittests.vcproj @@ -383,10 +383,6 @@ Name="browser" > <File - RelativePath="..\..\browser\views\find_bar_win_unittest.cc" - > - </File> - <File RelativePath="..\..\browser\autocomplete\autocomplete_unittest.cc" > </File> @@ -483,6 +479,10 @@ > </File> <File + RelativePath="..\..\browser\views\find_bar_win_unittest.cc" + > + </File> + <File RelativePath="..\..\browser\importer\firefox_importer_unittest.cc" > </File> @@ -703,6 +703,10 @@ > </File> <File + RelativePath="..\..\common\extensions\url_pattern_unittest.cc" + > + </File> + <File RelativePath="..\..\browser\net\resolve_proxy_msg_helper_unittest.cc" > </File> @@ -807,11 +811,11 @@ > </File> <File - RelativePath="..\..\renderer\render_thread_unittest.cc" + RelativePath="..\..\renderer\render_process_unittest.cc" > </File> <File - RelativePath="..\..\renderer\render_process_unittest.cc" + RelativePath="..\..\renderer\render_thread_unittest.cc" > </File> <File |