This source file includes following definitions.
- GetDefaultPort
- IsSubDomainOrEqual
- CompareDomainNames
- use_legacy_validate_
- WithPort
- WithPortWildcard
- WithHost
- WithDomainWildcard
- WithScheme
- WithSchemeWildcard
- WithPath
- WithPathWildcard
- Invalid
- Canonicalize
- Validate
- LegacyValidate
- is_path_wildcard
- CreateBuilder
- FromURL
- FromURLNoWildcard
- FromString
- LegacyFromString
- Wildcard
- is_valid_
- WriteToMessage
- ReadFromMessage
- Matches
- MatchesAllHosts
- ToString
- Compare
- CompareHost
- CompareScheme
- ComparePort
#include "chrome/common/content_settings_pattern.h"
#include <vector>
#include "base/memory/scoped_ptr.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "chrome/common/content_settings_pattern_parser.h"
#include "chrome/common/render_messages.h"
#include "chrome/common/url_constants.h"
#include "extensions/common/constants.h"
#include "ipc/ipc_message_utils.h"
#include "net/base/dns_util.h"
#include "net/base/net_util.h"
#include "url/gurl.h"
#include "url/url_canon.h"
namespace {
std::string GetDefaultPort(const std::string& scheme) {
if (scheme == content::kHttpScheme)
return "80";
if (scheme == content::kHttpsScheme)
return "443";
return std::string();
}
bool IsSubDomainOrEqual(const std::string& sub_domain,
const std::string& domain) {
if (domain.empty())
return true;
const size_t match = sub_domain.rfind(domain);
if (match == std::string::npos ||
(match > 0 && sub_domain[match - 1] != '.') ||
(match + domain.length() != sub_domain.length())) {
return false;
}
return true;
}
int CompareDomainNames(const std::string& str1, const std::string& str2) {
std::vector<std::string> domain_name1;
std::vector<std::string> domain_name2;
base::SplitString(str1, '.', &domain_name1);
base::SplitString(str2, '.', &domain_name2);
int i1 = domain_name1.size() - 1;
int i2 = domain_name2.size() - 1;
int rv;
while (i1 >= 0 && i2 >= 0) {
rv = domain_name1[i1].compare(domain_name2[i2]);
if (rv != 0)
return rv;
--i1;
--i2;
}
if (i1 > i2)
return 1;
if (i1 < i2)
return -1;
return 0;
}
typedef ContentSettingsPattern::BuilderInterface BuilderInterface;
}
ContentSettingsPattern::Builder::Builder(bool use_legacy_validate)
: is_valid_(true),
use_legacy_validate_(use_legacy_validate) {}
ContentSettingsPattern::Builder::~Builder() {}
BuilderInterface* ContentSettingsPattern::Builder::WithPort(
const std::string& port) {
parts_.port = port;
parts_.is_port_wildcard = false;
return this;
}
BuilderInterface* ContentSettingsPattern::Builder::WithPortWildcard() {
parts_.port = "";
parts_.is_port_wildcard = true;
return this;
}
BuilderInterface* ContentSettingsPattern::Builder::WithHost(
const std::string& host) {
parts_.host = host;
return this;
}
BuilderInterface* ContentSettingsPattern::Builder::WithDomainWildcard() {
parts_.has_domain_wildcard = true;
return this;
}
BuilderInterface* ContentSettingsPattern::Builder::WithScheme(
const std::string& scheme) {
parts_.scheme = scheme;
parts_.is_scheme_wildcard = false;
return this;
}
BuilderInterface* ContentSettingsPattern::Builder::WithSchemeWildcard() {
parts_.scheme = "";
parts_.is_scheme_wildcard = true;
return this;
}
BuilderInterface* ContentSettingsPattern::Builder::WithPath(
const std::string& path) {
parts_.path = path;
parts_.is_path_wildcard = false;
return this;
}
BuilderInterface* ContentSettingsPattern::Builder::WithPathWildcard() {
parts_.path = "";
parts_.is_path_wildcard = true;
return this;
}
BuilderInterface* ContentSettingsPattern::Builder::Invalid() {
is_valid_ = false;
return this;
}
ContentSettingsPattern ContentSettingsPattern::Builder::Build() {
if (!is_valid_)
return ContentSettingsPattern();
if (!Canonicalize(&parts_))
return ContentSettingsPattern();
if (use_legacy_validate_) {
is_valid_ = LegacyValidate(parts_);
} else {
is_valid_ = Validate(parts_);
}
if (!is_valid_)
return ContentSettingsPattern();
PatternParts parts(parts_);
if (!Canonicalize(&parts))
return ContentSettingsPattern();
if (ContentSettingsPattern(parts_, true) !=
ContentSettingsPattern(parts, true)) {
return ContentSettingsPattern();
}
return ContentSettingsPattern(parts_, is_valid_);
}
bool ContentSettingsPattern::Builder::Canonicalize(PatternParts* parts) {
const std::string scheme(StringToLowerASCII(parts->scheme));
parts->scheme = scheme;
if (parts->scheme == std::string(content::kFileScheme) &&
!parts->is_path_wildcard) {
GURL url(std::string(content::kFileScheme) +
std::string(content::kStandardSchemeSeparator) + parts->path);
parts->path = url.path();
}
const std::string host(parts->host);
url_canon::CanonHostInfo host_info;
std::string canonicalized_host(net::CanonicalizeHost(host, &host_info));
if (host_info.IsIPAddress() && parts->has_domain_wildcard)
return false;
canonicalized_host = net::TrimEndingDot(canonicalized_host);
parts->host = "";
if ((host.find('*') == std::string::npos) &&
!canonicalized_host.empty()) {
parts->host += canonicalized_host;
}
return true;
}
bool ContentSettingsPattern::Builder::Validate(const PatternParts& parts) {
if ((parts.is_scheme_wildcard && !parts.scheme.empty()) ||
(parts.is_port_wildcard && !parts.port.empty())) {
NOTREACHED();
return false;
}
if (parts.scheme == std::string(content::kFileScheme)) {
if (parts.has_domain_wildcard || !parts.host.empty() || !parts.port.empty())
return false;
if (parts.is_path_wildcard)
return parts.path.empty();
return (!parts.path.empty() &&
parts.path != "/" &&
parts.path.find("*") == std::string::npos);
}
if (parts.scheme == std::string(extensions::kExtensionScheme) &&
parts.port.empty() &&
!parts.is_port_wildcard) {
return true;
}
if ((parts.scheme.empty() && !parts.is_scheme_wildcard) ||
(parts.host.empty() && !parts.has_domain_wildcard) ||
(parts.port.empty() && !parts.is_port_wildcard)) {
return false;
}
if (parts.host.find("*") != std::string::npos)
return false;
if (!parts.is_scheme_wildcard &&
parts.scheme != std::string(content::kHttpScheme) &&
parts.scheme != std::string(content::kHttpsScheme)) {
return false;
}
return true;
}
bool ContentSettingsPattern::Builder::LegacyValidate(
const PatternParts& parts) {
if (parts.scheme == std::string(content::kFileScheme) &&
!parts.is_scheme_wildcard &&
parts.host.empty() &&
parts.port.empty())
return true;
if (parts.scheme == std::string(extensions::kExtensionScheme) &&
!parts.is_scheme_wildcard &&
!parts.host.empty() &&
!parts.has_domain_wildcard &&
parts.port.empty() &&
!parts.is_port_wildcard)
return true;
if ((!parts.is_scheme_wildcard) ||
(parts.host.empty() && !parts.has_domain_wildcard) ||
(!parts.is_port_wildcard))
return false;
if (!parts.is_scheme_wildcard &&
parts.scheme != std::string(content::kHttpScheme) &&
parts.scheme != std::string(content::kHttpsScheme)) {
return false;
}
return true;
}
ContentSettingsPattern::PatternParts::PatternParts()
: is_scheme_wildcard(false),
has_domain_wildcard(false),
is_port_wildcard(false),
is_path_wildcard(false) {}
ContentSettingsPattern::PatternParts::~PatternParts() {}
const int ContentSettingsPattern::kContentSettingsPatternVersion = 1;
const char* ContentSettingsPattern::kDomainWildcard = "[*.]";
const size_t ContentSettingsPattern::kDomainWildcardLength = 4;
BuilderInterface* ContentSettingsPattern::CreateBuilder(
bool validate) {
return new Builder(validate);
}
ContentSettingsPattern ContentSettingsPattern::FromURL(
const GURL& url) {
scoped_ptr<ContentSettingsPattern::BuilderInterface> builder(
ContentSettingsPattern::CreateBuilder(false));
const GURL* local_url = &url;
if (url.SchemeIsFileSystem() && url.inner_url()) {
local_url = url.inner_url();
}
if (local_url->SchemeIsFile()) {
builder->WithScheme(local_url->scheme())->WithPath(local_url->path());
} else {
if (local_url->HostIsIPAddress()) {
builder->WithScheme(local_url->scheme())->WithHost(local_url->host());
} else if (local_url->SchemeIs(content::kHttpScheme)) {
builder->WithSchemeWildcard()->WithDomainWildcard()->WithHost(
local_url->host());
} else if (local_url->SchemeIs(content::kHttpsScheme)) {
builder->WithScheme(local_url->scheme())->WithDomainWildcard()->WithHost(
local_url->host());
} else {
}
if (local_url->port().empty()) {
if (local_url->SchemeIs(content::kHttpsScheme))
builder->WithPort(GetDefaultPort(content::kHttpsScheme));
else
builder->WithPortWildcard();
} else {
builder->WithPort(local_url->port());
}
}
return builder->Build();
}
ContentSettingsPattern ContentSettingsPattern::FromURLNoWildcard(
const GURL& url) {
scoped_ptr<ContentSettingsPattern::BuilderInterface> builder(
ContentSettingsPattern::CreateBuilder(false));
const GURL* local_url = &url;
if (url.SchemeIsFileSystem() && url.inner_url()) {
local_url = url.inner_url();
}
if (local_url->SchemeIsFile()) {
builder->WithScheme(local_url->scheme())->WithPath(local_url->path());
} else {
builder->WithScheme(local_url->scheme())->WithHost(local_url->host());
if (local_url->port().empty()) {
builder->WithPort(GetDefaultPort(local_url->scheme()));
} else {
builder->WithPort(local_url->port());
}
}
return builder->Build();
}
ContentSettingsPattern ContentSettingsPattern::FromString(
const std::string& pattern_spec) {
scoped_ptr<ContentSettingsPattern::BuilderInterface> builder(
ContentSettingsPattern::CreateBuilder(false));
content_settings::PatternParser::Parse(pattern_spec, builder.get());
return builder->Build();
}
ContentSettingsPattern ContentSettingsPattern::LegacyFromString(
const std::string& pattern_spec) {
scoped_ptr<ContentSettingsPattern::BuilderInterface> builder(
ContentSettingsPattern::CreateBuilder(true));
content_settings::PatternParser::Parse(pattern_spec, builder.get());
return builder->Build();
}
ContentSettingsPattern ContentSettingsPattern::Wildcard() {
scoped_ptr<ContentSettingsPattern::BuilderInterface> builder(
ContentSettingsPattern::CreateBuilder(true));
builder->WithSchemeWildcard()->WithDomainWildcard()->WithPortWildcard()->
WithPathWildcard();
return builder->Build();
}
ContentSettingsPattern::ContentSettingsPattern()
: is_valid_(false) {
}
ContentSettingsPattern::ContentSettingsPattern(
const PatternParts& parts,
bool valid)
: parts_(parts),
is_valid_(valid) {
}
void ContentSettingsPattern::WriteToMessage(IPC::Message* m) const {
IPC::WriteParam(m, is_valid_);
IPC::WriteParam(m, parts_);
}
bool ContentSettingsPattern::ReadFromMessage(const IPC::Message* m,
PickleIterator* iter) {
return IPC::ReadParam(m, iter, &is_valid_) &&
IPC::ReadParam(m, iter, &parts_);
}
bool ContentSettingsPattern::Matches(
const GURL& url) const {
if (!is_valid_)
return false;
const GURL* local_url = &url;
if (url.SchemeIsFileSystem() && url.inner_url()) {
local_url = url.inner_url();
}
const std::string scheme(local_url->scheme());
if (!parts_.is_scheme_wildcard &&
parts_.scheme != scheme) {
return false;
}
if (!parts_.is_scheme_wildcard && scheme == content::kFileScheme)
return parts_.is_path_wildcard ||
parts_.path == std::string(local_url->path());
const std::string host(net::TrimEndingDot(local_url->host()));
if (!parts_.has_domain_wildcard) {
if (parts_.host != host)
return false;
} else {
if (!IsSubDomainOrEqual(host, parts_.host))
return false;
}
if (parts_.scheme == std::string(extensions::kExtensionScheme))
return true;
std::string port(local_url->port());
if (port.empty()) {
port = GetDefaultPort(scheme);
}
if (!parts_.is_port_wildcard &&
parts_.port != port ) {
return false;
}
return true;
}
bool ContentSettingsPattern::MatchesAllHosts() const {
return parts_.has_domain_wildcard && parts_.host.empty();
}
const std::string ContentSettingsPattern::ToString() const {
if (IsValid())
return content_settings::PatternParser::ToString(parts_);
else
return std::string();
}
ContentSettingsPattern::Relation ContentSettingsPattern::Compare(
const ContentSettingsPattern& other) const {
if ((this == &other) ||
(!is_valid_ && !other.is_valid_))
return IDENTITY;
if (!is_valid_ && other.is_valid_)
return DISJOINT_ORDER_POST;
if (is_valid_ && !other.is_valid_)
return DISJOINT_ORDER_PRE;
Relation host_relation = CompareHost(parts_, other.parts_);
if (host_relation == DISJOINT_ORDER_PRE ||
host_relation == DISJOINT_ORDER_POST)
return host_relation;
Relation port_relation = ComparePort(parts_, other.parts_);
if (port_relation == DISJOINT_ORDER_PRE ||
port_relation == DISJOINT_ORDER_POST)
return port_relation;
Relation scheme_relation = CompareScheme(parts_, other.parts_);
if (scheme_relation == DISJOINT_ORDER_PRE ||
scheme_relation == DISJOINT_ORDER_POST)
return scheme_relation;
if (host_relation != IDENTITY)
return host_relation;
if (port_relation != IDENTITY)
return port_relation;
return scheme_relation;
}
bool ContentSettingsPattern::operator==(
const ContentSettingsPattern& other) const {
return Compare(other) == IDENTITY;
}
bool ContentSettingsPattern::operator!=(
const ContentSettingsPattern& other) const {
return !(*this == other);
}
bool ContentSettingsPattern::operator<(
const ContentSettingsPattern& other) const {
return Compare(other) < 0;
}
bool ContentSettingsPattern::operator>(
const ContentSettingsPattern& other) const {
return Compare(other) > 0;
}
ContentSettingsPattern::Relation ContentSettingsPattern::CompareHost(
const ContentSettingsPattern::PatternParts& parts,
const ContentSettingsPattern::PatternParts& other_parts) {
if (!parts.has_domain_wildcard && !other_parts.has_domain_wildcard) {
int result = CompareDomainNames(parts.host, other_parts.host);
if (result == 0)
return ContentSettingsPattern::IDENTITY;
if (result < 0)
return ContentSettingsPattern::DISJOINT_ORDER_PRE;
return ContentSettingsPattern::DISJOINT_ORDER_POST;
} else if (parts.has_domain_wildcard && !other_parts.has_domain_wildcard) {
if (IsSubDomainOrEqual(other_parts.host, parts.host)) {
return ContentSettingsPattern::SUCCESSOR;
} else {
if (CompareDomainNames(parts.host, other_parts.host) < 0)
return ContentSettingsPattern::DISJOINT_ORDER_PRE;
return ContentSettingsPattern::DISJOINT_ORDER_POST;
}
} else if (!parts.has_domain_wildcard && other_parts.has_domain_wildcard) {
if (IsSubDomainOrEqual(parts.host, other_parts.host)) {
return ContentSettingsPattern::PREDECESSOR;
} else {
if (CompareDomainNames(parts.host, other_parts.host) < 0)
return ContentSettingsPattern::DISJOINT_ORDER_PRE;
return ContentSettingsPattern::DISJOINT_ORDER_POST;
}
} else if (parts.has_domain_wildcard && other_parts.has_domain_wildcard) {
if (parts.host == other_parts.host) {
return ContentSettingsPattern::IDENTITY;
} else if (IsSubDomainOrEqual(other_parts.host, parts.host)) {
return ContentSettingsPattern::SUCCESSOR;
} else if (IsSubDomainOrEqual(parts.host, other_parts.host)) {
return ContentSettingsPattern::PREDECESSOR;
} else {
if (CompareDomainNames(parts.host, other_parts.host) < 0)
return ContentSettingsPattern::DISJOINT_ORDER_PRE;
return ContentSettingsPattern::DISJOINT_ORDER_POST;
}
}
NOTREACHED();
return ContentSettingsPattern::IDENTITY;
}
ContentSettingsPattern::Relation ContentSettingsPattern::CompareScheme(
const ContentSettingsPattern::PatternParts& parts,
const ContentSettingsPattern::PatternParts& other_parts) {
if (parts.is_scheme_wildcard && !other_parts.is_scheme_wildcard)
return ContentSettingsPattern::SUCCESSOR;
if (!parts.is_scheme_wildcard && other_parts.is_scheme_wildcard)
return ContentSettingsPattern::PREDECESSOR;
int result = parts.scheme.compare(other_parts.scheme);
if (result == 0)
return ContentSettingsPattern::IDENTITY;
if (result > 0)
return ContentSettingsPattern::DISJOINT_ORDER_PRE;
return ContentSettingsPattern::DISJOINT_ORDER_POST;
}
ContentSettingsPattern::Relation ContentSettingsPattern::ComparePort(
const ContentSettingsPattern::PatternParts& parts,
const ContentSettingsPattern::PatternParts& other_parts) {
if (parts.is_port_wildcard && !other_parts.is_port_wildcard)
return ContentSettingsPattern::SUCCESSOR;
if (!parts.is_port_wildcard && other_parts.is_port_wildcard)
return ContentSettingsPattern::PREDECESSOR;
int result = parts.port.compare(other_parts.port);
if (result == 0)
return ContentSettingsPattern::IDENTITY;
if (result > 0)
return ContentSettingsPattern::DISJOINT_ORDER_PRE;
return ContentSettingsPattern::DISJOINT_ORDER_POST;
}