| OLD | NEW | 
|    1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |    1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 
|    2 // Use of this source code is governed by a BSD-style license that can be |    2 // Use of this source code is governed by a BSD-style license that can be | 
|    3 // found in the LICENSE file. |    3 // found in the LICENSE file. | 
|    4  |    4  | 
|    5 #include "chrome/common/extensions/url_pattern.h" |    5 #include "chrome/common/extensions/url_pattern.h" | 
|    6  |    6  | 
 |    7 #include "base/string_number_conversions.h" | 
|    7 #include "base/string_piece.h" |    8 #include "base/string_piece.h" | 
|    8 #include "base/string_split.h" |    9 #include "base/string_split.h" | 
|    9 #include "base/string_util.h" |   10 #include "base/string_util.h" | 
|   10 #include "chrome/common/url_constants.h" |   11 #include "chrome/common/url_constants.h" | 
|   11 #include "googleurl/src/gurl.h" |   12 #include "googleurl/src/gurl.h" | 
|   12 #include "googleurl/src/url_util.h" |   13 #include "googleurl/src/url_util.h" | 
|   13  |   14  | 
|   14 const char URLPattern::kAllUrlsPattern[] = "<all_urls>"; |   15 const char URLPattern::kAllUrlsPattern[] = "<all_urls>"; | 
|   15  |   16  | 
|   16 namespace { |   17 namespace { | 
| (...skipping 24 matching lines...) Expand all  Loading... | 
|   41  |   42  | 
|   42 const char* kParseSuccess = "Success."; |   43 const char* kParseSuccess = "Success."; | 
|   43 const char* kParseErrorMissingSchemeSeparator = "Missing scheme separator."; |   44 const char* kParseErrorMissingSchemeSeparator = "Missing scheme separator."; | 
|   44 const char* kParseErrorInvalidScheme = "Invalid scheme."; |   45 const char* kParseErrorInvalidScheme = "Invalid scheme."; | 
|   45 const char* kParseErrorWrongSchemeType = "Wrong scheme type."; |   46 const char* kParseErrorWrongSchemeType = "Wrong scheme type."; | 
|   46 const char* kParseErrorEmptyHost = "Host can not be empty."; |   47 const char* kParseErrorEmptyHost = "Host can not be empty."; | 
|   47 const char* kParseErrorInvalidHostWildcard = "Invalid host wildcard."; |   48 const char* kParseErrorInvalidHostWildcard = "Invalid host wildcard."; | 
|   48 const char* kParseErrorEmptyPath = "Empty path."; |   49 const char* kParseErrorEmptyPath = "Empty path."; | 
|   49 const char* kParseErrorHasColon = |   50 const char* kParseErrorHasColon = | 
|   50     "Ports are not supported in URL patterns. ':' may not be used in a host."; |   51     "Ports are not supported in URL patterns. ':' may not be used in a host."; | 
 |   52 const char* kParseErrorInvalidPort = | 
 |   53     "Invalid port."; | 
|   51  |   54  | 
|   52 // Message explaining each URLPattern::ParseResult. |   55 // Message explaining each URLPattern::ParseResult. | 
|   53 const char* kParseResultMessages[] = { |   56 const char* kParseResultMessages[] = { | 
|   54   kParseSuccess, |   57   kParseSuccess, | 
|   55   kParseErrorMissingSchemeSeparator, |   58   kParseErrorMissingSchemeSeparator, | 
|   56   kParseErrorInvalidScheme, |   59   kParseErrorInvalidScheme, | 
|   57   kParseErrorWrongSchemeType, |   60   kParseErrorWrongSchemeType, | 
|   58   kParseErrorEmptyHost, |   61   kParseErrorEmptyHost, | 
|   59   kParseErrorInvalidHostWildcard, |   62   kParseErrorInvalidHostWildcard, | 
|   60   kParseErrorEmptyPath, |   63   kParseErrorEmptyPath, | 
|   61   kParseErrorHasColon |   64   kParseErrorHasColon, | 
 |   65   kParseErrorInvalidPort, | 
|   62 }; |   66 }; | 
|   63  |   67  | 
|   64 COMPILE_ASSERT(URLPattern::NUM_PARSE_RESULTS == arraysize(kParseResultMessages), |   68 COMPILE_ASSERT(URLPattern::NUM_PARSE_RESULTS == arraysize(kParseResultMessages), | 
|   65                must_add_message_for_each_parse_result); |   69                must_add_message_for_each_parse_result); | 
|   66  |   70  | 
|   67 const char kPathSeparator[] = "/"; |   71 const char kPathSeparator[] = "/"; | 
|   68  |   72  | 
|   69 bool IsStandardScheme(const std::string& scheme) { |   73 bool IsStandardScheme(const std::string& scheme) { | 
|   70   // "*" gets the same treatment as a standard scheme. |   74   // "*" gets the same treatment as a standard scheme. | 
|   71   if (scheme == "*") |   75   if (scheme == "*") | 
|   72     return true; |   76     return true; | 
|   73  |   77  | 
|   74   return url_util::IsStandard(scheme.c_str(), |   78   return url_util::IsStandard(scheme.c_str(), | 
|   75       url_parse::Component(0, static_cast<int>(scheme.length()))); |   79       url_parse::Component(0, static_cast<int>(scheme.length()))); | 
|   76 } |   80 } | 
|   77  |   81  | 
 |   82 bool IsValidPort(const std::string& port) { | 
 |   83   if (port.empty() || port == "*") | 
 |   84     return true; | 
 |   85   int parsed_port; | 
 |   86   if (!base::StringToInt(port, &parsed_port)) | 
 |   87     return false; | 
 |   88   return (parsed_port >= 0) && (parsed_port < 65536); | 
 |   89 } | 
 |   90  | 
|   78 }  // namespace |   91 }  // namespace | 
|   79  |   92  | 
|   80 URLPattern::URLPattern() |   93 URLPattern::URLPattern() | 
|   81     : valid_schemes_(SCHEME_NONE), |   94     : valid_schemes_(SCHEME_NONE), | 
|   82       match_all_urls_(false), |   95       match_all_urls_(false), | 
|   83       match_subdomains_(false) {} |   96       match_subdomains_(false), | 
 |   97       ignore_ports_(true) {} | 
|   84  |   98  | 
|   85 URLPattern::URLPattern(int valid_schemes) |   99 URLPattern::URLPattern(int valid_schemes) | 
|   86     : valid_schemes_(valid_schemes), match_all_urls_(false), |  100     : valid_schemes_(valid_schemes), | 
|   87       match_subdomains_(false) {} |  101       match_all_urls_(false), | 
 |  102       match_subdomains_(false), | 
 |  103       ignore_ports_(true) {} | 
|   88  |  104  | 
|   89 URLPattern::URLPattern(int valid_schemes, const std::string& pattern) |  105 URLPattern::URLPattern(int valid_schemes, const std::string& pattern) | 
|   90     : valid_schemes_(valid_schemes), match_all_urls_(false), |  106     : valid_schemes_(valid_schemes), | 
|   91       match_subdomains_(false) { |  107       match_all_urls_(false), | 
 |  108       match_subdomains_(false), | 
 |  109       ignore_ports_(true) { | 
|   92  |  110  | 
|   93   // Strict error checking is used, because this constructor is only |  111   // Strict error checking is used, because this constructor is only | 
|   94   // appropriate when we know |pattern| is valid. |  112   // appropriate when we know |pattern| is valid. | 
|   95   if (PARSE_SUCCESS != Parse(pattern, PARSE_STRICT)) |  113   if (PARSE_SUCCESS != Parse(pattern, PARSE_STRICT)) | 
|   96     NOTREACHED() << "URLPattern is invalid: " << pattern; |  114     NOTREACHED() << "URLPattern is invalid: " << pattern; | 
|   97 } |  115 } | 
|   98  |  116  | 
|   99 URLPattern::~URLPattern() { |  117 URLPattern::~URLPattern() { | 
|  100 } |  118 } | 
|  101  |  119  | 
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  184     // done as a convenience to developers who might otherwise be confused and |  202     // done as a convenience to developers who might otherwise be confused and | 
|  185     // think '*' works as a glob in the host. |  203     // think '*' works as a glob in the host. | 
|  186     if (host_.find('*') != std::string::npos) |  204     if (host_.find('*') != std::string::npos) | 
|  187       return PARSE_ERROR_INVALID_HOST_WILDCARD; |  205       return PARSE_ERROR_INVALID_HOST_WILDCARD; | 
|  188  |  206  | 
|  189     path_start_pos = host_end_pos; |  207     path_start_pos = host_end_pos; | 
|  190   } |  208   } | 
|  191  |  209  | 
|  192   SetPath(pattern.substr(path_start_pos)); |  210   SetPath(pattern.substr(path_start_pos)); | 
|  193  |  211  | 
|  194   if (strictness == PARSE_STRICT && host_.find(':') != std::string::npos) |  212   std::string port = "*"; | 
|  195     return PARSE_ERROR_HAS_COLON; |  213   size_t port_pos = host_.find(':'); | 
 |  214   if (port_pos != std::string::npos) { | 
 |  215     if (strictness == PARSE_STRICT) | 
 |  216       return PARSE_ERROR_HAS_COLON; | 
 |  217  | 
 |  218     if (!ignore_ports_) | 
 |  219       port = host_.substr(port_pos + 1); | 
 |  220  | 
 |  221     host_ = host_.substr(0, port_pos); | 
 |  222   } | 
 |  223   if (!SetPort(port)) | 
 |  224     return PARSE_ERROR_INVALID_PORT; | 
|  196  |  225  | 
|  197   return PARSE_SUCCESS; |  226   return PARSE_SUCCESS; | 
|  198 } |  227 } | 
|  199  |  228  | 
|  200 bool URLPattern::SetScheme(const std::string& scheme) { |  229 bool URLPattern::SetScheme(const std::string& scheme) { | 
|  201   scheme_ = scheme; |  230   scheme_ = scheme; | 
|  202   if (scheme_ == "*") { |  231   if (scheme_ == "*") { | 
|  203     valid_schemes_ &= (SCHEME_HTTP | SCHEME_HTTPS); |  232     valid_schemes_ &= (SCHEME_HTTP | SCHEME_HTTPS); | 
|  204   } else if (!IsValidScheme(scheme_)) { |  233   } else if (!IsValidScheme(scheme_)) { | 
|  205     return false; |  234     return false; | 
| (...skipping 13 matching lines...) Expand all  Loading... | 
|  219   return false; |  248   return false; | 
|  220 } |  249 } | 
|  221  |  250  | 
|  222 void URLPattern::SetPath(const std::string& path) { |  251 void URLPattern::SetPath(const std::string& path) { | 
|  223   path_ = path; |  252   path_ = path; | 
|  224   path_escaped_ = path_; |  253   path_escaped_ = path_; | 
|  225   ReplaceSubstringsAfterOffset(&path_escaped_, 0, "\\", "\\\\"); |  254   ReplaceSubstringsAfterOffset(&path_escaped_, 0, "\\", "\\\\"); | 
|  226   ReplaceSubstringsAfterOffset(&path_escaped_, 0, "?", "\\?"); |  255   ReplaceSubstringsAfterOffset(&path_escaped_, 0, "?", "\\?"); | 
|  227 } |  256 } | 
|  228  |  257  | 
 |  258 bool URLPattern::SetPort(const std::string& port) { | 
 |  259   if (IsValidPort(port)) { | 
 |  260     port_ = port; | 
 |  261     return true; | 
 |  262   } | 
 |  263   return false; | 
 |  264 } | 
 |  265  | 
|  229 bool URLPattern::MatchesURL(const GURL &test) const { |  266 bool URLPattern::MatchesURL(const GURL &test) const { | 
|  230   if (!MatchesScheme(test.scheme())) |  267   if (!MatchesScheme(test.scheme())) | 
|  231     return false; |  268     return false; | 
|  232  |  269  | 
|  233   if (match_all_urls_) |  270   if (match_all_urls_) | 
|  234     return true; |  271     return true; | 
|  235  |  272  | 
|  236   // Ignore hostname if scheme is file://. |  273   // Ignore hostname if scheme is file://. | 
|  237   if (scheme_ != chrome::kFileScheme && !MatchesHost(test)) |  274   if (scheme_ != chrome::kFileScheme && !MatchesHost(test)) | 
|  238     return false; |  275     return false; | 
|  239  |  276  | 
|  240   if (!MatchesPath(test.PathForRequest())) |  277   if (!MatchesPath(test.PathForRequest())) | 
|  241     return false; |  278     return false; | 
|  242  |  279  | 
 |  280   if (!MatchesPort(test.port())) | 
 |  281     return false; | 
 |  282  | 
|  243   return true; |  283   return true; | 
|  244 } |  284 } | 
|  245  |  285  | 
|  246 bool URLPattern::MatchesScheme(const std::string& test) const { |  286 bool URLPattern::MatchesScheme(const std::string& test) const { | 
|  247   if (!IsValidScheme(test)) |  287   if (!IsValidScheme(test)) | 
|  248     return false; |  288     return false; | 
|  249  |  289  | 
|  250   return scheme_ == "*" || test == scheme_; |  290   return scheme_ == "*" || test == scheme_; | 
|  251 } |  291 } | 
|  252  |  292  | 
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  289   return test.host()[test.host().length() - host_.length() - 1] == '.'; |  329   return test.host()[test.host().length() - host_.length() - 1] == '.'; | 
|  290 } |  330 } | 
|  291  |  331  | 
|  292 bool URLPattern::MatchesPath(const std::string& test) const { |  332 bool URLPattern::MatchesPath(const std::string& test) const { | 
|  293   if (!MatchPattern(test, path_escaped_)) |  333   if (!MatchPattern(test, path_escaped_)) | 
|  294     return false; |  334     return false; | 
|  295  |  335  | 
|  296   return true; |  336   return true; | 
|  297 } |  337 } | 
|  298  |  338  | 
 |  339 bool URLPattern::MatchesPort(const std::string& test) const { | 
 |  340   if (!IsValidPort(test)) | 
 |  341     return false; | 
 |  342  | 
 |  343   return port_ == "*" || port_ == test; | 
 |  344 } | 
 |  345  | 
|  299 std::string URLPattern::GetAsString() const { |  346 std::string URLPattern::GetAsString() const { | 
|  300   if (match_all_urls_) |  347   if (match_all_urls_) | 
|  301     return kAllUrlsPattern; |  348     return kAllUrlsPattern; | 
|  302  |  349  | 
|  303   bool standard_scheme = IsStandardScheme(scheme_); |  350   bool standard_scheme = IsStandardScheme(scheme_); | 
|  304  |  351  | 
|  305   std::string spec = scheme_ + |  352   std::string spec = scheme_ + | 
|  306       (standard_scheme ? chrome::kStandardSchemeSeparator : ":"); |  353       (standard_scheme ? chrome::kStandardSchemeSeparator : ":"); | 
|  307  |  354  | 
|  308   if (scheme_ != chrome::kFileScheme && standard_scheme) { |  355   if (scheme_ != chrome::kFileScheme && standard_scheme) { | 
|  309     if (match_subdomains_) { |  356     if (match_subdomains_) { | 
|  310       spec += "*"; |  357       spec += "*"; | 
|  311       if (!host_.empty()) |  358       if (!host_.empty()) | 
|  312         spec += "."; |  359         spec += "."; | 
|  313     } |  360     } | 
|  314  |  361  | 
|  315     if (!host_.empty()) |  362     if (!host_.empty()) | 
|  316       spec += host_; |  363       spec += host_; | 
 |  364  | 
 |  365     if (!ignore_ports_ && !port_.empty()) { | 
 |  366       spec += ":"; | 
 |  367       spec += port_; | 
 |  368     } | 
|  317   } |  369   } | 
|  318  |  370  | 
|  319   if (!path_.empty()) |  371   if (!path_.empty()) | 
|  320     spec += path_; |  372     spec += path_; | 
|  321  |  373  | 
|  322   return spec; |  374   return spec; | 
|  323 } |  375 } | 
|  324  |  376  | 
|  325 bool URLPattern::OverlapsWith(const URLPattern& other) const { |  377 bool URLPattern::OverlapsWith(const URLPattern& other) const { | 
|  326   if (!MatchesAnyScheme(other.GetExplicitSchemes()) && |  378   if (!MatchesAnyScheme(other.GetExplicitSchemes()) && | 
|  327       !other.MatchesAnyScheme(GetExplicitSchemes())) { |  379       !other.MatchesAnyScheme(GetExplicitSchemes())) { | 
|  328     return false; |  380     return false; | 
|  329   } |  381   } | 
|  330  |  382  | 
|  331   if (!MatchesHost(other.host()) && !other.MatchesHost(host_)) |  383   if (!MatchesHost(other.host()) && !other.MatchesHost(host_)) | 
|  332     return false; |  384     return false; | 
|  333  |  385  | 
 |  386   if (port_ != "*" && other.port() != "*" && port_ != other.port()) | 
 |  387     return false; | 
 |  388  | 
|  334   // We currently only use OverlapsWith() for the patterns inside |  389   // We currently only use OverlapsWith() for the patterns inside | 
|  335   // URLPatternSet. In those cases, we know that the path will have only a |  390   // URLPatternSet. In those cases, we know that the path will have only a | 
|  336   // single wildcard at the end. This makes figuring out overlap much easier. It |  391   // single wildcard at the end. This makes figuring out overlap much easier. It | 
|  337   // seems like there is probably a computer-sciency way to solve the general |  392   // seems like there is probably a computer-sciency way to solve the general | 
|  338   // case, but we don't need that yet. |  393   // case, but we don't need that yet. | 
|  339   DCHECK(path_.find('*') == path_.size() - 1); |  394   DCHECK(path_.find('*') == path_.size() - 1); | 
|  340   DCHECK(other.path().find('*') == other.path().size() - 1); |  395   DCHECK(other.path().find('*') == other.path().size() - 1); | 
|  341  |  396  | 
|  342   if (!MatchesPath(other.path().substr(0, other.path().size() - 1)) && |  397   if (!MatchesPath(other.path().substr(0, other.path().size() - 1)) && | 
|  343       !other.MatchesPath(path_.substr(0, path_.size() - 1))) |  398       !other.MatchesPath(path_.substr(0, path_.size() - 1))) | 
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  387   } |  442   } | 
|  388  |  443  | 
|  389   return result; |  444   return result; | 
|  390 } |  445 } | 
|  391  |  446  | 
|  392 // static |  447 // static | 
|  393 const char* URLPattern::GetParseResultString( |  448 const char* URLPattern::GetParseResultString( | 
|  394     URLPattern::ParseResult parse_result) { |  449     URLPattern::ParseResult parse_result) { | 
|  395   return kParseResultMessages[parse_result]; |  450   return kParseResultMessages[parse_result]; | 
|  396 } |  451 } | 
| OLD | NEW |