| Index: chrome/common/extensions/url_pattern.cc
|
| diff --git a/chrome/common/extensions/url_pattern.cc b/chrome/common/extensions/url_pattern.cc
|
| index 6749ab8632bef945643b225c8f250476ffc58717..af0fd0ae4ffa27b1b5a0a92bc843ea39dc5f85f8 100644
|
| --- a/chrome/common/extensions/url_pattern.cc
|
| +++ b/chrome/common/extensions/url_pattern.cc
|
| @@ -4,6 +4,7 @@
|
|
|
| #include "chrome/common/extensions/url_pattern.h"
|
|
|
| +#include "base/string_number_conversions.h"
|
| #include "base/string_piece.h"
|
| #include "base/string_split.h"
|
| #include "base/string_util.h"
|
| @@ -48,6 +49,8 @@ const char* kParseErrorInvalidHostWildcard = "Invalid host wildcard.";
|
| const char* kParseErrorEmptyPath = "Empty path.";
|
| const char* kParseErrorHasColon =
|
| "Ports are not supported in URL patterns. ':' may not be used in a host.";
|
| +const char* kParseErrorInvalidPort =
|
| + "Invalid port.";
|
|
|
| // Message explaining each URLPattern::ParseResult.
|
| const char* kParseResultMessages[] = {
|
| @@ -58,7 +61,8 @@ const char* kParseResultMessages[] = {
|
| kParseErrorEmptyHost,
|
| kParseErrorInvalidHostWildcard,
|
| kParseErrorEmptyPath,
|
| - kParseErrorHasColon
|
| + kParseErrorHasColon,
|
| + kParseErrorInvalidPort,
|
| };
|
|
|
| COMPILE_ASSERT(URLPattern::NUM_PARSE_RESULTS == arraysize(kParseResultMessages),
|
| @@ -75,24 +79,45 @@ bool IsStandardScheme(const std::string& scheme) {
|
| url_parse::Component(0, static_cast<int>(scheme.length())));
|
| }
|
|
|
| +bool IsValidPortForScheme(const std::string scheme, const std::string& port) {
|
| + if (port == "*")
|
| + return true;
|
| +
|
| + // Only accept non-wildcard ports if the scheme uses ports.
|
| + if (url_canon::DefaultPortForScheme(scheme.c_str(), scheme.length()) ==
|
| + url_parse::PORT_UNSPECIFIED) {
|
| + return false;
|
| + }
|
| +
|
| + int parsed_port = url_parse::PORT_UNSPECIFIED;
|
| + if (!base::StringToInt(port, &parsed_port))
|
| + return false;
|
| + return (parsed_port >= 0) && (parsed_port < 65536);
|
| +}
|
| +
|
| } // namespace
|
|
|
| URLPattern::URLPattern()
|
| : valid_schemes_(SCHEME_NONE),
|
| match_all_urls_(false),
|
| - match_subdomains_(false) {}
|
| + match_subdomains_(false),
|
| + port_("*") {}
|
|
|
| URLPattern::URLPattern(int valid_schemes)
|
| - : valid_schemes_(valid_schemes), match_all_urls_(false),
|
| - match_subdomains_(false) {}
|
| + : valid_schemes_(valid_schemes),
|
| + match_all_urls_(false),
|
| + match_subdomains_(false),
|
| + port_("*") {}
|
|
|
| URLPattern::URLPattern(int valid_schemes, const std::string& pattern)
|
| - : valid_schemes_(valid_schemes), match_all_urls_(false),
|
| - match_subdomains_(false) {
|
| + : valid_schemes_(valid_schemes),
|
| + match_all_urls_(false),
|
| + match_subdomains_(false),
|
| + port_("*") {
|
|
|
| // Strict error checking is used, because this constructor is only
|
| // appropriate when we know |pattern| is valid.
|
| - if (PARSE_SUCCESS != Parse(pattern, PARSE_STRICT))
|
| + if (PARSE_SUCCESS != Parse(pattern, ERROR_ON_PORTS))
|
| NOTREACHED() << "URLPattern is invalid: " << pattern;
|
| }
|
|
|
| @@ -101,9 +126,6 @@ URLPattern::~URLPattern() {
|
|
|
| URLPattern::ParseResult URLPattern::Parse(const std::string& pattern,
|
| ParseOption strictness) {
|
| - CHECK(strictness == PARSE_LENIENT ||
|
| - strictness == PARSE_STRICT);
|
| -
|
| // Special case pattern to match every valid URL.
|
| if (pattern == kAllUrlsPattern) {
|
| match_all_urls_ = true;
|
| @@ -180,19 +202,34 @@ URLPattern::ParseResult URLPattern::Parse(const std::string& pattern,
|
| }
|
| 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 PARSE_ERROR_INVALID_HOST_WILDCARD;
|
| -
|
| path_start_pos = host_end_pos;
|
| }
|
|
|
| SetPath(pattern.substr(path_start_pos));
|
|
|
| - if (strictness == PARSE_STRICT && host_.find(':') != std::string::npos)
|
| - return PARSE_ERROR_HAS_COLON;
|
| + size_t port_pos = host_.find(':');
|
| + if (port_pos != std::string::npos) {
|
| + switch (strictness) {
|
| + case USE_PORTS: {
|
| + if (!SetPort(host_.substr(port_pos + 1)))
|
| + return PARSE_ERROR_INVALID_PORT;
|
| + host_ = host_.substr(0, port_pos);
|
| + break;
|
| + }
|
| + case ERROR_ON_PORTS: {
|
| + return PARSE_ERROR_HAS_COLON;
|
| + }
|
| + case IGNORE_PORTS: {
|
| + // Do nothing, i.e. leave the colon in the host.
|
| + }
|
| + }
|
| + }
|
| +
|
| + // 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 PARSE_ERROR_INVALID_HOST_WILDCARD;
|
|
|
| return PARSE_SUCCESS;
|
| }
|
| @@ -226,6 +263,14 @@ void URLPattern::SetPath(const std::string& path) {
|
| ReplaceSubstringsAfterOffset(&path_escaped_, 0, "?", "\\?");
|
| }
|
|
|
| +bool URLPattern::SetPort(const std::string& port) {
|
| + if (IsValidPortForScheme(scheme_, port)) {
|
| + port_ = port;
|
| + return true;
|
| + }
|
| + return false;
|
| +}
|
| +
|
| bool URLPattern::MatchesURL(const GURL &test) const {
|
| if (!MatchesScheme(test.scheme()))
|
| return false;
|
| @@ -240,6 +285,9 @@ bool URLPattern::MatchesURL(const GURL &test) const {
|
| if (!MatchesPath(test.PathForRequest()))
|
| return false;
|
|
|
| + if (!MatchesPort(test.EffectiveIntPort()))
|
| + return false;
|
| +
|
| return true;
|
| }
|
|
|
| @@ -296,6 +344,13 @@ bool URLPattern::MatchesPath(const std::string& test) const {
|
| return true;
|
| }
|
|
|
| +bool URLPattern::MatchesPort(int port) const {
|
| + if (port == url_parse::PORT_INVALID)
|
| + return false;
|
| +
|
| + return port_ == "*" || port_ == base::IntToString(port);
|
| +}
|
| +
|
| std::string URLPattern::GetAsString() const {
|
| if (match_all_urls_)
|
| return kAllUrlsPattern;
|
| @@ -314,6 +369,11 @@ std::string URLPattern::GetAsString() const {
|
|
|
| if (!host_.empty())
|
| spec += host_;
|
| +
|
| + if (port_ != "*") {
|
| + spec += ":";
|
| + spec += port_;
|
| + }
|
| }
|
|
|
| if (!path_.empty())
|
| @@ -331,6 +391,9 @@ bool URLPattern::OverlapsWith(const URLPattern& other) const {
|
| if (!MatchesHost(other.host()) && !other.MatchesHost(host_))
|
| return false;
|
|
|
| + if (port_ != "*" && other.port() != "*" && port_ != other.port())
|
| + return false;
|
| +
|
| // We currently only use OverlapsWith() for the patterns inside
|
| // URLPatternSet. In those cases, we know that the path will have only a
|
| // single wildcard at the end. This makes figuring out overlap much easier. It
|
|
|