// Copyright (c) 2011 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/browser/content_settings/content_settings_pattern.h" #include "base/string_util.h" #include "chrome/common/url_constants.h" #include "net/base/net_util.h" #include "googleurl/src/gurl.h" #include "googleurl/src/url_canon.h" namespace { bool IsValidHostlessPattern(const std::string& pattern) { std::string file_scheme_plus_separator(chrome::kFileScheme); file_scheme_plus_separator += chrome::kStandardSchemeSeparator; return StartsWithASCII(pattern, file_scheme_plus_separator, false); } } // namespace // The version of the pattern format implemented. Version 1 includes the // following patterns: // - [*.]domain.tld (matches domain.tld and all sub-domains) // - host (matches an exact hostname) // - a.b.c.d (matches an exact IPv4 ip) // - [a:b:c:d:e:f:g:h] (matches an exact IPv6 ip) // - file:///tmp/test.html (a complete URL without a host) // Version 2 adds a resource identifier for plugins. // TODO(jochen): update once this feature is no longer behind a flag. const int ContentSettingsPattern::kContentSettingsPatternVersion = 1; const char* ContentSettingsPattern::kDomainWildcard = "[*.]"; const size_t ContentSettingsPattern::kDomainWildcardLength = 4; // static ContentSettingsPattern ContentSettingsPattern::FromURL( const GURL& url) { // TODO(markusheintz): Add scheme wildcard; return ContentSettingsPattern(!url.has_host() || url.HostIsIPAddress() ? net::GetHostOrSpecFromURL(url) : std::string(kDomainWildcard) + url.host()); } // static ContentSettingsPattern ContentSettingsPattern::FromURLNoWildcard( const GURL& url) { return ContentSettingsPattern(net::GetHostOrSpecFromURL(url), url.scheme()); } bool ContentSettingsPattern::IsValid() const { if (pattern_.empty()) return false; if (IsValidHostlessPattern(pattern_)) return true; const std::string host(pattern_.length() > kDomainWildcardLength && StartsWithASCII(pattern_, kDomainWildcard, false) ? pattern_.substr(kDomainWildcardLength) : pattern_); url_canon::CanonHostInfo host_info; return host.find('*') == std::string::npos && !net::CanonicalizeHost(host, &host_info).empty(); } bool ContentSettingsPattern::Matches(const GURL& url) const { if (!IsValid()) return false; const std::string host(net::GetHostOrSpecFromURL(url)); if (pattern_.length() < kDomainWildcardLength || !StartsWithASCII(pattern_, kDomainWildcard, false)) return pattern_ == host; const size_t match = host.rfind(pattern_.substr(kDomainWildcardLength)); return (match != std::string::npos) && (match == 0 || host[match - 1] == '.') && (match + pattern_.length() - kDomainWildcardLength == host.length()); } std::string ContentSettingsPattern::CanonicalizePattern() const { if (!IsValid()) return ""; if (IsValidHostlessPattern(pattern_)) return GURL(pattern_).spec(); bool starts_with_wildcard = pattern_.length() > kDomainWildcardLength && StartsWithASCII(pattern_, kDomainWildcard, false); const std::string host(starts_with_wildcard ? pattern_.substr(kDomainWildcardLength) : pattern_); std::string canonicalized_pattern = starts_with_wildcard ? kDomainWildcard : ""; url_canon::CanonHostInfo host_info; canonicalized_pattern += net::CanonicalizeHost(host, &host_info); return canonicalized_pattern; }