Index: chrome/common/extensions/url_pattern.cc |
diff --git a/chrome/common/extensions/url_pattern.cc b/chrome/common/extensions/url_pattern.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..bb32cb57f41e0d751dc25de4e01f19da47b721d9 |
--- /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; |
+} |