15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "extensions/common/url_pattern.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_number_conversions.h"
8c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/strings/string_piece.h"
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/strings/string_split.h"
10868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_util.h"
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/common/url_constants.h"
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "extensions/common/constants.h"
137dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "url/gurl.h"
147dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "url/url_util.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char URLPattern::kAllUrlsPattern[] = "<all_urls>";
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO(aa): What about more obscure schemes like data: and javascript: ?
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Note: keep this array in sync with kValidSchemeMasks.
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char* kValidSchemes[] = {
23d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  content::kHttpScheme,
24424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  content::kHttpsScheme,
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  chrome::kFileScheme,
26a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  content::kFtpScheme,
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  chrome::kChromeUIScheme,
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  extensions::kExtensionScheme,
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  chrome::kFileSystemScheme,
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kValidSchemeMasks[] = {
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  URLPattern::SCHEME_HTTP,
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  URLPattern::SCHEME_HTTPS,
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  URLPattern::SCHEME_FILE,
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  URLPattern::SCHEME_FTP,
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  URLPattern::SCHEME_CHROMEUI,
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  URLPattern::SCHEME_EXTENSION,
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  URLPattern::SCHEME_FILESYSTEM,
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)COMPILE_ASSERT(arraysize(kValidSchemes) == arraysize(kValidSchemeMasks),
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               must_keep_these_arrays_in_sync);
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kParseSuccess[] = "Success.";
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kParseErrorMissingSchemeSeparator[] = "Missing scheme separator.";
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kParseErrorInvalidScheme[] = "Invalid scheme.";
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kParseErrorWrongSchemeType[] = "Wrong scheme type.";
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kParseErrorEmptyHost[] = "Host can not be empty.";
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kParseErrorInvalidHostWildcard[] = "Invalid host wildcard.";
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kParseErrorEmptyPath[] = "Empty path.";
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kParseErrorInvalidPort[] = "Invalid port.";
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Message explaining each URLPattern::ParseResult.
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char* const kParseResultMessages[] = {
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  kParseSuccess,
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  kParseErrorMissingSchemeSeparator,
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  kParseErrorInvalidScheme,
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  kParseErrorWrongSchemeType,
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  kParseErrorEmptyHost,
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  kParseErrorInvalidHostWildcard,
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  kParseErrorEmptyPath,
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  kParseErrorInvalidPort,
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)COMPILE_ASSERT(URLPattern::NUM_PARSE_RESULTS == arraysize(kParseResultMessages),
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               must_add_message_for_each_parse_result);
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kPathSeparator[] = "/";
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool IsStandardScheme(const std::string& scheme) {
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // "*" gets the same treatment as a standard scheme.
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (scheme == "*")
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return url_util::IsStandard(scheme.c_str(),
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      url_parse::Component(0, static_cast<int>(scheme.length())));
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool IsValidPortForScheme(const std::string& scheme, const std::string& port) {
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (port == "*")
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Only accept non-wildcard ports if the scheme uses ports.
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (url_canon::DefaultPortForScheme(scheme.c_str(), scheme.length()) ==
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      url_parse::PORT_UNSPECIFIED) {
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int parsed_port = url_parse::PORT_UNSPECIFIED;
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!base::StringToInt(port, &parsed_port))
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return (parsed_port >= 0) && (parsed_port < 65536);
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Returns |path| with the trailing wildcard stripped if one existed.
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)//
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// The functions that rely on this (OverlapsWith and Contains) are only
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// called for the patterns inside URLPatternSet. In those cases, we know that
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// the path will have only a single wildcard at the end. This makes figuring
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// out overlap much easier. It seems like there is probably a computer-sciency
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// way to solve the general case, but we don't need that yet.
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)std::string StripTrailingWildcard(const std::string& path) {
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  size_t wildcard_index = path.find('*');
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  size_t path_last = path.size() - 1;
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(wildcard_index == std::string::npos || wildcard_index == path_last);
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return wildcard_index == path_last ? path.substr(0, path_last) : path;
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)URLPattern::URLPattern()
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : valid_schemes_(SCHEME_NONE),
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      match_all_urls_(false),
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      match_subdomains_(false),
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      port_("*") {}
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)URLPattern::URLPattern(int valid_schemes)
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : valid_schemes_(valid_schemes),
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      match_all_urls_(false),
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      match_subdomains_(false),
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      port_("*") {}
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)URLPattern::URLPattern(int valid_schemes, const std::string& pattern)
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Strict error checking is used, because this constructor is only
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // appropriate when we know |pattern| is valid.
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : valid_schemes_(valid_schemes),
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      match_all_urls_(false),
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      match_subdomains_(false),
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      port_("*") {
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (PARSE_SUCCESS != Parse(pattern))
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED() << "URLPattern is invalid: " << pattern;
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)URLPattern::~URLPattern() {
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool URLPattern::operator<(const URLPattern& other) const {
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return GetAsString() < other.GetAsString();
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)bool URLPattern::operator>(const URLPattern& other) const {
14368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  return GetAsString() > other.GetAsString();
14468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)}
14568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool URLPattern::operator==(const URLPattern& other) const {
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return GetAsString() == other.GetAsString();
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)URLPattern::ParseResult URLPattern::Parse(const std::string& pattern) {
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  spec_.clear();
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetMatchAllURLs(false);
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetMatchSubdomains(false);
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetPort("*");
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Special case pattern to match every valid URL.
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (pattern == kAllUrlsPattern) {
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SetMatchAllURLs(true);
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return PARSE_SUCCESS;
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Parse out the scheme.
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t scheme_end_pos = pattern.find(content::kStandardSchemeSeparator);
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool has_standard_scheme_separator = true;
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Some urls also use ':' alone as the scheme separator.
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (scheme_end_pos == std::string::npos) {
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scheme_end_pos = pattern.find(':');
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    has_standard_scheme_separator = false;
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (scheme_end_pos == std::string::npos)
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return PARSE_ERROR_MISSING_SCHEME_SEPARATOR;
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!SetScheme(pattern.substr(0, scheme_end_pos)))
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return PARSE_ERROR_INVALID_SCHEME;
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool standard_scheme = IsStandardScheme(scheme_);
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (standard_scheme != has_standard_scheme_separator)
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return PARSE_ERROR_WRONG_SCHEME_SEPARATOR;
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Advance past the scheme separator.
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scheme_end_pos +=
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (standard_scheme ? strlen(content::kStandardSchemeSeparator) : 1);
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (scheme_end_pos >= pattern.size())
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return PARSE_ERROR_EMPTY_HOST;
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Parse out the host and path.
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t host_start_pos = scheme_end_pos;
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t path_start_pos = 0;
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!standard_scheme) {
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    path_start_pos = host_start_pos;
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (scheme_ == chrome::kFileScheme) {
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    size_t host_end_pos = pattern.find(kPathSeparator, host_start_pos);
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (host_end_pos == std::string::npos) {
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Allow hostname omission.
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // e.g. file://* is interpreted as file:///*,
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // file://foo* is interpreted as file:///foo*.
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      path_start_pos = host_start_pos - 1;
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Ignore hostname if scheme is file://.
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // e.g. file://localhost/foo is equal to file:///foo.
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      path_start_pos = host_end_pos;
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    size_t host_end_pos = pattern.find(kPathSeparator, host_start_pos);
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Host is required.
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (host_start_pos == host_end_pos)
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return PARSE_ERROR_EMPTY_HOST;
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (host_end_pos == std::string::npos)
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return PARSE_ERROR_EMPTY_PATH;
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    host_ = pattern.substr(host_start_pos, host_end_pos - host_start_pos);
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The first component can optionally be '*' to match all subdomains.
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::vector<std::string> host_components;
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::SplitString(host_, '.', &host_components);
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (host_components[0] == "*") {
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      match_subdomains_ = true;
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      host_components.erase(host_components.begin(),
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            host_components.begin() + 1);
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    host_ = JoinString(host_components, '.');
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    path_start_pos = host_end_pos;
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetPath(pattern.substr(path_start_pos));
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t port_pos = host_.find(':');
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (port_pos != std::string::npos) {
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!SetPort(host_.substr(port_pos + 1)))
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return PARSE_ERROR_INVALID_PORT;
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    host_ = host_.substr(0, port_pos);
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // No other '*' can occur in the host, though. This isn't necessary, but is
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // done as a convenience to developers who might otherwise be confused and
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // think '*' works as a glob in the host.
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (host_.find('*') != std::string::npos)
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return PARSE_ERROR_INVALID_HOST_WILDCARD;
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return PARSE_SUCCESS;
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void URLPattern::SetValidSchemes(int valid_schemes) {
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  spec_.clear();
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  valid_schemes_ = valid_schemes;
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void URLPattern::SetHost(const std::string& host) {
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  spec_.clear();
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  host_ = host;
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void URLPattern::SetMatchAllURLs(bool val) {
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  spec_.clear();
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  match_all_urls_ = val;
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (val) {
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    match_subdomains_ = true;
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scheme_ = "*";
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    host_.clear();
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SetPath("/*");
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void URLPattern::SetMatchSubdomains(bool val) {
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  spec_.clear();
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  match_subdomains_ = val;
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool URLPattern::SetScheme(const std::string& scheme) {
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  spec_.clear();
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scheme_ = scheme;
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (scheme_ == "*") {
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    valid_schemes_ &= (SCHEME_HTTP | SCHEME_HTTPS);
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (!IsValidScheme(scheme_)) {
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool URLPattern::IsValidScheme(const std::string& scheme) const {
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (valid_schemes_ == SCHEME_ALL)
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < arraysize(kValidSchemes); ++i) {
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (scheme == kValidSchemes[i] && (valid_schemes_ & kValidSchemeMasks[i]))
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return true;
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void URLPattern::SetPath(const std::string& path) {
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  spec_.clear();
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  path_ = path;
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  path_escaped_ = path_;
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ReplaceSubstringsAfterOffset(&path_escaped_, 0, "\\", "\\\\");
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ReplaceSubstringsAfterOffset(&path_escaped_, 0, "?", "\\?");
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool URLPattern::SetPort(const std::string& port) {
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  spec_.clear();
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (IsValidPortForScheme(scheme_, port)) {
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    port_ = port;
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool URLPattern::MatchesURL(const GURL& test) const {
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const GURL* test_url = &test;
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool has_inner_url = test.inner_url() != NULL;
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (has_inner_url) {
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!test.SchemeIsFileSystem())
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;  // The only nested URLs we handle are filesystem URLs.
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    test_url = test.inner_url();
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!MatchesScheme(test_url->scheme()))
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (match_all_urls_)
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string path_for_request = test.PathForRequest();
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (has_inner_url)
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    path_for_request = test_url->path() + path_for_request;
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return MatchesSecurityOriginHelper(*test_url) &&
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         MatchesPath(path_for_request);
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool URLPattern::MatchesSecurityOrigin(const GURL& test) const {
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const GURL* test_url = &test;
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool has_inner_url = test.inner_url() != NULL;
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (has_inner_url) {
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!test.SchemeIsFileSystem())
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;  // The only nested URLs we handle are filesystem URLs.
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    test_url = test.inner_url();
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!MatchesScheme(test_url->scheme()))
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (match_all_urls_)
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return MatchesSecurityOriginHelper(*test_url);
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool URLPattern::MatchesScheme(const std::string& test) const {
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!IsValidScheme(test))
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return scheme_ == "*" || test == scheme_;
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool URLPattern::MatchesHost(const std::string& host) const {
367d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  std::string test(content::kHttpScheme);
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  test += content::kStandardSchemeSeparator;
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  test += host;
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  test += "/";
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return MatchesHost(GURL(test));
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool URLPattern::MatchesHost(const GURL& test) const {
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If the hosts are exactly equal, we have a match.
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (test.host() == host_)
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If we're matching subdomains, and we have no host in the match pattern,
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // that means that we're matching all hosts, which means we have a match no
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // matter what the test host is.
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (match_subdomains_ && host_.empty())
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Otherwise, we can only match if our match pattern matches subdomains.
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!match_subdomains_)
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We don't do subdomain matching against IP addresses, so we can give up now
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // if the test host is an IP address.
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (test.HostIsIPAddress())
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Check if the test host is a subdomain of our host.
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (test.host().length() <= (host_.length() + 1))
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (test.host().compare(test.host().length() - host_.length(),
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          host_.length(), host_) != 0)
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return test.host()[test.host().length() - host_.length() - 1] == '.';
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool URLPattern::MatchesPath(const std::string& test) const {
4062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Make the behaviour of OverlapsWith consistent with MatchesURL, which is
4072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // need to match hosted apps on e.g. 'google.com' also run on 'google.com/'.
4082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (test + "/*" == path_escaped_)
4092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return true;
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return MatchPattern(test, path_escaped_);
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const std::string& URLPattern::GetAsString() const {
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!spec_.empty())
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return spec_;
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (match_all_urls_) {
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    spec_ = kAllUrlsPattern;
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return spec_;
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool standard_scheme = IsStandardScheme(scheme_);
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string spec = scheme_ +
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (standard_scheme ? content::kStandardSchemeSeparator : ":");
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (scheme_ != chrome::kFileScheme && standard_scheme) {
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (match_subdomains_) {
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      spec += "*";
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!host_.empty())
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        spec += ".";
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!host_.empty())
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      spec += host_;
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (port_ != "*") {
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      spec += ":";
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      spec += port_;
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!path_.empty())
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    spec += path_;
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  spec_ = spec;
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return spec_;
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool URLPattern::OverlapsWith(const URLPattern& other) const {
4522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (match_all_urls() || other.match_all_urls())
4532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return true;
4542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return (MatchesAnyScheme(other.GetExplicitSchemes()) ||
4552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          other.MatchesAnyScheme(GetExplicitSchemes()))
4562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      && (MatchesHost(other.host()) || other.MatchesHost(host()))
4572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      && (MatchesPortPattern(other.port()) || other.MatchesPortPattern(port()))
4582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      && (MatchesPath(StripTrailingWildcard(other.path())) ||
4592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          other.MatchesPath(StripTrailingWildcard(path())));
4602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool URLPattern::Contains(const URLPattern& other) const {
4632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (match_all_urls())
4642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return true;
4652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return MatchesAllSchemes(other.GetExplicitSchemes())
4662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      && MatchesHost(other.host())
4672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      && MatchesPortPattern(other.port())
4682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      && MatchesPath(StripTrailingWildcard(other.path()));
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool URLPattern::MatchesAnyScheme(
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::vector<std::string>& schemes) const {
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (std::vector<std::string>::const_iterator i = schemes.begin();
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       i != schemes.end(); ++i) {
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (MatchesScheme(*i))
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return true;
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool URLPattern::MatchesAllSchemes(
4832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::vector<std::string>& schemes) const {
4842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (std::vector<std::string>::const_iterator i = schemes.begin();
4852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       i != schemes.end(); ++i) {
4862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!MatchesScheme(*i))
4872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return false;
4882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
4892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
4912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool URLPattern::MatchesSecurityOriginHelper(const GURL& test) const {
4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Ignore hostname if scheme is file://.
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (scheme_ != chrome::kFileScheme && !MatchesHost(test))
4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!MatchesPortPattern(base::IntToString(test.EffectiveIntPort())))
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool URLPattern::MatchesPortPattern(const std::string& port) const {
5052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return port_ == "*" || port_ == port;
5062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
5072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::vector<std::string> URLPattern::GetExplicitSchemes() const {
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<std::string> result;
5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (scheme_ != "*" && !match_all_urls_ && IsValidScheme(scheme_)) {
5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result.push_back(scheme_);
5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return result;
5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < arraysize(kValidSchemes); ++i) {
5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (MatchesScheme(kValidSchemes[i])) {
5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      result.push_back(kValidSchemes[i]);
5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return result;
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::vector<URLPattern> URLPattern::ConvertToExplicitSchemes() const {
5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<std::string> explicit_schemes = GetExplicitSchemes();
5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<URLPattern> result;
5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (std::vector<std::string>::const_iterator i = explicit_schemes.begin();
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       i != explicit_schemes.end(); ++i) {
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    URLPattern temp = *this;
5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    temp.SetScheme(*i);
5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    temp.SetMatchAllURLs(false);
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result.push_back(temp);
5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return result;
5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char* URLPattern::GetParseResultString(
5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    URLPattern::ParseResult parse_result) {
5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return kParseResultMessages[parse_result];
5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
545