blob: 3dbb4f57c2e635169c58ad0faade19a2efb967ee [file] [log] [blame]
// Copyright (c) 2012 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 "components/content_settings/core/browser/host_content_settings_map.h"
#include <stddef.h>
#include <utility>
#include "base/command_line.h"
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/metrics/histogram.h"
#include "base/stl_util.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/time/clock.h"
#include "build/build_config.h"
#include "components/content_settings/core/browser/content_settings_default_provider.h"
#include "components/content_settings/core/browser/content_settings_details.h"
#include "components/content_settings/core/browser/content_settings_info.h"
#include "components/content_settings/core/browser/content_settings_observable_provider.h"
#include "components/content_settings/core/browser/content_settings_policy_provider.h"
#include "components/content_settings/core/browser/content_settings_pref_provider.h"
#include "components/content_settings/core/browser/content_settings_provider.h"
#include "components/content_settings/core/browser/content_settings_registry.h"
#include "components/content_settings/core/browser/content_settings_rule.h"
#include "components/content_settings/core/browser/content_settings_utils.h"
#include "components/content_settings/core/browser/website_settings_registry.h"
#include "components/content_settings/core/common/content_settings_pattern.h"
#include "components/content_settings/core/common/pref_names.h"
#include "components/pref_registry/pref_registry_syncable.h"
#include "components/prefs/pref_service.h"
#include "net/base/net_errors.h"
#include "net/base/static_cookie_policy.h"
#include "url/gurl.h"
using content_settings::WebsiteSettingsInfo;
namespace {
typedef std::vector<content_settings::Rule> Rules;
typedef std::pair<std::string, std::string> StringPair;
struct ProviderNamesSourceMapEntry {
const char* provider_name;
content_settings::SettingSource provider_source;
};
const ProviderNamesSourceMapEntry kProviderNamesSourceMap[] = {
{"platform_app", content_settings::SETTING_SOURCE_EXTENSION},
{"policy", content_settings::SETTING_SOURCE_POLICY},
{"supervised_user", content_settings::SETTING_SOURCE_SUPERVISED},
{"extension", content_settings::SETTING_SOURCE_EXTENSION},
{"preference", content_settings::SETTING_SOURCE_USER},
{"default", content_settings::SETTING_SOURCE_USER},
};
static_assert(
arraysize(kProviderNamesSourceMap) ==
HostContentSettingsMap::NUM_PROVIDER_TYPES,
"kProviderNamesSourceMap should have NUM_PROVIDER_TYPES elements");
// Returns true if the |content_type| supports a resource identifier.
// Resource identifiers are supported (but not required) for plugins.
bool SupportsResourceIdentifier(ContentSettingsType content_type) {
return content_type == CONTENT_SETTINGS_TYPE_PLUGINS;
}
bool SchemeCanBeWhitelisted(const std::string& scheme) {
return scheme == content_settings::kChromeDevToolsScheme ||
scheme == content_settings::kExtensionScheme ||
scheme == content_settings::kChromeUIScheme;
}
// Handles inheritance of settings from the regular profile into the incognito
// profile.
std::unique_ptr<base::Value> ProcessIncognitoInheritanceBehavior(
ContentSettingsType content_type,
std::unique_ptr<base::Value> value) {
// Website setting inheritance can be completely disallowed.
const content_settings::WebsiteSettingsInfo* website_settings_info =
content_settings::WebsiteSettingsRegistry::GetInstance()->Get(
content_type);
if (website_settings_info &&
website_settings_info->incognito_behavior() ==
content_settings::WebsiteSettingsInfo::DONT_INHERIT_IN_INCOGNITO) {
return nullptr;
}
// Content setting inheritance can be disabled for CONTENT_SETTING_ALLOW.
const content_settings::ContentSettingsInfo* content_settings_info =
content_settings::ContentSettingsRegistry::GetInstance()->Get(
content_type);
if (content_settings_info) {
if (content_settings_info->incognito_behavior() !=
content_settings::ContentSettingsInfo::
INHERIT_IN_INCOGNITO_EXCEPT_ALLOW)
return value;
ContentSetting setting =
content_settings::ValueToContentSetting(value.get());
if (setting != CONTENT_SETTING_ALLOW)
return value;
DCHECK(content_settings_info->IsSettingValid(CONTENT_SETTING_ASK));
return content_settings::ContentSettingToValue(CONTENT_SETTING_ASK);
}
return value;
}
content_settings::PatternPair GetPatternsFromScopingType(
WebsiteSettingsInfo::ScopingType scoping_type,
const GURL& primary_url,
const GURL& secondary_url) {
DCHECK(!primary_url.is_empty());
content_settings::PatternPair patterns;
switch (scoping_type) {
case WebsiteSettingsInfo::TOP_LEVEL_DOMAIN_ONLY_SCOPE:
case WebsiteSettingsInfo::REQUESTING_DOMAIN_ONLY_SCOPE:
patterns.first = ContentSettingsPattern::FromURL(primary_url);
patterns.second = ContentSettingsPattern::Wildcard();
break;
case WebsiteSettingsInfo::REQUESTING_ORIGIN_ONLY_SCOPE:
patterns.first = ContentSettingsPattern::FromURLNoWildcard(primary_url);
patterns.second = ContentSettingsPattern::Wildcard();
break;
case WebsiteSettingsInfo::REQUESTING_ORIGIN_AND_TOP_LEVEL_ORIGIN_SCOPE:
DCHECK(!secondary_url.is_empty());
patterns.first = ContentSettingsPattern::FromURLNoWildcard(primary_url);
patterns.second =
ContentSettingsPattern::FromURLNoWildcard(secondary_url);
break;
}
return patterns;
}
} // namespace
HostContentSettingsMap::HostContentSettingsMap(PrefService* prefs,
bool is_incognito_profile,
bool is_guest_profile)
:
#ifndef NDEBUG
used_from_thread_id_(base::PlatformThread::CurrentId()),
#endif
prefs_(prefs),
is_off_the_record_(is_incognito_profile || is_guest_profile) {
DCHECK(!(is_incognito_profile && is_guest_profile));
content_settings::PolicyProvider* policy_provider =
new content_settings::PolicyProvider(prefs_);
content_settings_providers_[POLICY_PROVIDER] = policy_provider;
policy_provider->AddObserver(this);
pref_provider_ =
new content_settings::PrefProvider(prefs_, is_off_the_record_);
content_settings_providers_[PREF_PROVIDER] = pref_provider_;
pref_provider_->AddObserver(this);
// This ensures that content settings are cleared for the guest profile. This
// wouldn't be needed except that we used to allow settings to be stored for
// the guest profile and so we need to ensure those get cleared.
if (is_guest_profile)
pref_provider_->ClearPrefs();
content_settings::ObservableProvider* default_provider =
new content_settings::DefaultProvider(prefs_, is_off_the_record_);
default_provider->AddObserver(this);
content_settings_providers_[DEFAULT_PROVIDER] = default_provider;
MigrateKeygenSettings();
RecordNumberOfExceptions();
}
// static
void HostContentSettingsMap::RegisterProfilePrefs(
user_prefs::PrefRegistrySyncable* registry) {
// Ensure the content settings are all registered.
content_settings::ContentSettingsRegistry::GetInstance();
registry->RegisterIntegerPref(prefs::kContentSettingsWindowLastTabIndex, 0);
// Register the prefs for the content settings providers.
content_settings::DefaultProvider::RegisterProfilePrefs(registry);
content_settings::PrefProvider::RegisterProfilePrefs(registry);
content_settings::PolicyProvider::RegisterProfilePrefs(registry);
}
void HostContentSettingsMap::RegisterProvider(
ProviderType type,
std::unique_ptr<content_settings::ObservableProvider> provider) {
DCHECK(!content_settings_providers_[type]);
provider->AddObserver(this);
content_settings_providers_[type] = provider.release();
#ifndef NDEBUG
DCHECK_NE(used_from_thread_id_, base::kInvalidThreadId)
<< "Used from multiple threads before initialization complete.";
#endif
OnContentSettingChanged(ContentSettingsPattern(),
ContentSettingsPattern(),
CONTENT_SETTINGS_TYPE_DEFAULT,
std::string());
}
ContentSetting HostContentSettingsMap::GetDefaultContentSettingFromProvider(
ContentSettingsType content_type,
content_settings::ProviderInterface* provider) const {
std::unique_ptr<content_settings::RuleIterator> rule_iterator(
provider->GetRuleIterator(content_type, std::string(), false));
ContentSettingsPattern wildcard = ContentSettingsPattern::Wildcard();
while (rule_iterator->HasNext()) {
content_settings::Rule rule = rule_iterator->Next();
if (rule.primary_pattern == wildcard &&
rule.secondary_pattern == wildcard) {
return content_settings::ValueToContentSetting(rule.value.get());
}
}
return CONTENT_SETTING_DEFAULT;
}
ContentSetting HostContentSettingsMap::GetDefaultContentSettingInternal(
ContentSettingsType content_type,
ProviderType* provider_type) const {
DCHECK(provider_type);
UsedContentSettingsProviders();
// Iterate through the list of providers and return the first non-NULL value
// that matches |primary_url| and |secondary_url|.
for (ConstProviderIterator provider = content_settings_providers_.begin();
provider != content_settings_providers_.end();
++provider) {
if (provider->first == PREF_PROVIDER)
continue;
ContentSetting default_setting =
GetDefaultContentSettingFromProvider(content_type, provider->second);
if (is_off_the_record_) {
default_setting = content_settings::ValueToContentSetting(
ProcessIncognitoInheritanceBehavior(
content_type,
content_settings::ContentSettingToValue(default_setting))
.get());
}
if (default_setting != CONTENT_SETTING_DEFAULT) {
*provider_type = provider->first;
return default_setting;
}
}
return CONTENT_SETTING_DEFAULT;
}
ContentSetting HostContentSettingsMap::GetDefaultContentSetting(
ContentSettingsType content_type,
std::string* provider_id) const {
ProviderType provider_type = NUM_PROVIDER_TYPES;
ContentSetting content_setting =
GetDefaultContentSettingInternal(content_type, &provider_type);
if (content_setting != CONTENT_SETTING_DEFAULT && provider_id)
*provider_id = kProviderNamesSourceMap[provider_type].provider_name;
return content_setting;
}
ContentSetting HostContentSettingsMap::GetContentSetting(
const GURL& primary_url,
const GURL& secondary_url,
ContentSettingsType content_type,
const std::string& resource_identifier) const {
DCHECK(content_settings::ContentSettingsRegistry::GetInstance()->Get(
content_type));
std::unique_ptr<base::Value> value = GetWebsiteSetting(
primary_url, secondary_url, content_type, resource_identifier, NULL);
return content_settings::ValueToContentSetting(value.get());
}
void HostContentSettingsMap::GetSettingsForOneType(
ContentSettingsType content_type,
const std::string& resource_identifier,
ContentSettingsForOneType* settings) const {
DCHECK(SupportsResourceIdentifier(content_type) ||
resource_identifier.empty());
DCHECK(settings);
UsedContentSettingsProviders();
settings->clear();
for (ConstProviderIterator provider = content_settings_providers_.begin();
provider != content_settings_providers_.end();
++provider) {
// For each provider, iterate first the incognito-specific rules, then the
// normal rules.
if (is_off_the_record_) {
AddSettingsForOneType(provider->second,
provider->first,
content_type,
resource_identifier,
settings,
true);
}
AddSettingsForOneType(provider->second,
provider->first,
content_type,
resource_identifier,
settings,
false);
}
}
void HostContentSettingsMap::SetDefaultContentSetting(
ContentSettingsType content_type,
ContentSetting setting) {
std::unique_ptr<base::Value> value;
// A value of CONTENT_SETTING_DEFAULT implies deleting the content setting.
if (setting != CONTENT_SETTING_DEFAULT) {
DCHECK(IsDefaultSettingAllowedForType(setting, content_type));
value.reset(new base::FundamentalValue(setting));
}
SetWebsiteSettingCustomScope(ContentSettingsPattern::Wildcard(),
ContentSettingsPattern::Wildcard(), content_type,
std::string(), std::move(value));
}
void HostContentSettingsMap::SetWebsiteSettingDefaultScope(
const GURL& primary_url,
const GURL& secondary_url,
ContentSettingsType content_type,
const std::string& resource_identifier,
std::unique_ptr<base::Value> value) {
const WebsiteSettingsInfo* info =
content_settings::WebsiteSettingsRegistry::GetInstance()->Get(
content_type);
content_settings::PatternPair patterns = GetPatternsFromScopingType(
info->scoping_type(), primary_url, secondary_url);
ContentSettingsPattern primary_pattern = patterns.first;
ContentSettingsPattern secondary_pattern = patterns.second;
if (!primary_pattern.IsValid() || !secondary_pattern.IsValid())
return;
SetWebsiteSettingCustomScope(primary_pattern, secondary_pattern, content_type,
resource_identifier, std::move(value));
}
void HostContentSettingsMap::SetWebsiteSettingCustomScope(
const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_pattern,
ContentSettingsType content_type,
const std::string& resource_identifier,
std::unique_ptr<base::Value> value) {
DCHECK(SupportsResourceIdentifier(content_type) ||
resource_identifier.empty());
UsedContentSettingsProviders();
for (auto& provider_pair : content_settings_providers_) {
if (provider_pair.second->SetWebsiteSetting(
primary_pattern, secondary_pattern, content_type,
resource_identifier, value.get())) {
// If succesful then ownership is passed to the provider.
ignore_result(value.release());
return;
}
}
NOTREACHED();
}
void HostContentSettingsMap::SetNarrowestContentSetting(
const GURL& primary_url,
const GURL& secondary_url,
ContentSettingsType type,
ContentSetting setting) {
// Permission settings are specified via rules. There exists always at least
// one rule for the default setting. Get the rule that currently defines
// the permission for the given permission |type|. Then test whether the
// existing rule is more specific than the rule we are about to create. If
// the existing rule is more specific, than change the existing rule instead
// of creating a new rule that would be hidden behind the existing rule.
content_settings::SettingInfo info;
std::unique_ptr<base::Value> v = GetWebsiteSettingInternal(
primary_url, secondary_url, type, std::string(), &info);
DCHECK_EQ(content_settings::SETTING_SOURCE_USER, info.source);
const WebsiteSettingsInfo* website_settings_info =
content_settings::WebsiteSettingsRegistry::GetInstance()->Get(type);
content_settings::PatternPair patterns = GetPatternsFromScopingType(
website_settings_info->scoping_type(), primary_url, secondary_url);
ContentSettingsPattern narrow_primary = patterns.first;
ContentSettingsPattern narrow_secondary = patterns.second;
ContentSettingsPattern::Relation r1 =
info.primary_pattern.Compare(patterns.first);
if (r1 == ContentSettingsPattern::PREDECESSOR) {
narrow_primary = info.primary_pattern;
} else if (r1 == ContentSettingsPattern::IDENTITY) {
ContentSettingsPattern::Relation r2 =
info.secondary_pattern.Compare(patterns.second);
DCHECK(r2 != ContentSettingsPattern::DISJOINT_ORDER_POST &&
r2 != ContentSettingsPattern::DISJOINT_ORDER_PRE);
if (r2 == ContentSettingsPattern::PREDECESSOR)
narrow_secondary = info.secondary_pattern;
}
SetContentSettingCustomScope(narrow_primary, narrow_secondary, type,
std::string(), setting);
}
void HostContentSettingsMap::SetContentSettingCustomScope(
const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_pattern,
ContentSettingsType content_type,
const std::string& resource_identifier,
ContentSetting setting) {
DCHECK(content_settings::ContentSettingsRegistry::GetInstance()->Get(
content_type));
if (setting == CONTENT_SETTING_ALLOW &&
(content_type == CONTENT_SETTINGS_TYPE_GEOLOCATION ||
content_type == CONTENT_SETTINGS_TYPE_NOTIFICATIONS)) {
UpdateLastUsageByPattern(primary_pattern, secondary_pattern, content_type);
}
std::unique_ptr<base::Value> value;
// A value of CONTENT_SETTING_DEFAULT implies deleting the content setting.
if (setting != CONTENT_SETTING_DEFAULT) {
DCHECK(content_settings::ContentSettingsRegistry::GetInstance()
->Get(content_type)
->IsSettingValid(setting));
value.reset(new base::FundamentalValue(setting));
}
SetWebsiteSettingCustomScope(primary_pattern, secondary_pattern, content_type,
resource_identifier, std::move(value));
}
void HostContentSettingsMap::SetContentSettingDefaultScope(
const GURL& primary_url,
const GURL& secondary_url,
ContentSettingsType content_type,
const std::string& resource_identifier,
ContentSetting setting) {
using content_settings::ContentSettingsInfo;
const ContentSettingsInfo* info =
content_settings::ContentSettingsRegistry::GetInstance()->Get(
content_type);
DCHECK(info);
content_settings::PatternPair patterns =
GetPatternsFromScopingType(info->website_settings_info()->scoping_type(),
primary_url, secondary_url);
ContentSettingsPattern primary_pattern = patterns.first;
ContentSettingsPattern secondary_pattern = patterns.second;
if (!primary_pattern.IsValid() || !secondary_pattern.IsValid())
return;
SetContentSettingCustomScope(primary_pattern, secondary_pattern, content_type,
resource_identifier, setting);
}
void HostContentSettingsMap::MigrateKeygenSettings() {
const content_settings::ContentSettingsInfo* info =
content_settings::ContentSettingsRegistry::GetInstance()->Get(
CONTENT_SETTINGS_TYPE_KEYGEN);
if (info) {
ContentSettingsForOneType settings;
GetSettingsForOneType(CONTENT_SETTINGS_TYPE_KEYGEN, std::string(),
&settings);
for (const ContentSettingPatternSource& setting_entry : settings) {
// Migrate user preference settings only.
if (setting_entry.source != "preference")
continue;
// Migrate old-format settings only.
if (setting_entry.secondary_pattern !=
ContentSettingsPattern::Wildcard()) {
GURL url(setting_entry.primary_pattern.ToString());
// Pull out the value of the old-format setting. Only do this if the
// patterns are as we expect them to be, otherwise the setting will just
// be removed for safety.
ContentSetting content_setting = CONTENT_SETTING_DEFAULT;
if (setting_entry.primary_pattern == setting_entry.secondary_pattern &&
url.is_valid()) {
content_setting = GetContentSetting(
url, url, CONTENT_SETTINGS_TYPE_KEYGEN, std::string());
}
// Remove the old pattern.
SetContentSettingCustomScope(setting_entry.primary_pattern,
setting_entry.secondary_pattern,
CONTENT_SETTINGS_TYPE_KEYGEN,
std::string(), CONTENT_SETTING_DEFAULT);
// Set the new pattern.
SetContentSettingDefaultScope(url, GURL(), CONTENT_SETTINGS_TYPE_KEYGEN,
std::string(), content_setting);
}
}
}
}
void HostContentSettingsMap::MigrateDomainScopedSettings() {
const ContentSettingsType kDomainScopedTypes[] = {
CONTENT_SETTINGS_TYPE_COOKIES,
CONTENT_SETTINGS_TYPE_IMAGES,
CONTENT_SETTINGS_TYPE_PLUGINS,
CONTENT_SETTINGS_TYPE_JAVASCRIPT,
CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS,
CONTENT_SETTINGS_TYPE_POPUPS};
for (const ContentSettingsType& type : kDomainScopedTypes) {
if (!content_settings::ContentSettingsRegistry::GetInstance()->Get(type))
continue;
ContentSettingsForOneType settings;
GetSettingsForOneType(type, std::string(), &settings);
for (const ContentSettingPatternSource& setting_entry : settings) {
// Migrate user preference settings only.
if (setting_entry.source != "preference")
continue;
// Migrate ALLOW settings only.
if (setting_entry.setting != CONTENT_SETTING_ALLOW)
continue;
// Skip default settings.
if (setting_entry.primary_pattern == ContentSettingsPattern::Wildcard())
continue;
if (setting_entry.secondary_pattern !=
ContentSettingsPattern::Wildcard()) {
NOTREACHED();
continue;
}
ContentSettingsPattern origin_pattern;
if (!ContentSettingsPattern::MigrateFromDomainToOrigin(
setting_entry.primary_pattern, &origin_pattern)) {
continue;
}
if (!origin_pattern.IsValid())
continue;
GURL origin(origin_pattern.ToString());
DCHECK(origin.is_valid());
// Ensure that the current resolved content setting for this origin is
// allowed. Otherwise we may be overriding some narrower setting which is
// set to block.
ContentSetting origin_setting =
GetContentSetting(origin, origin, type, std::string());
// Remove the domain scoped pattern. If |origin_setting| is not
// CONTENT_SETTING_ALLOW it implies there is some narrower pattern in
// effect, so it's still safe to remove the domain-scoped pattern.
SetContentSettingCustomScope(setting_entry.primary_pattern,
setting_entry.secondary_pattern, type,
std::string(), CONTENT_SETTING_DEFAULT);
// If the current resolved content setting is allowed it's safe to set the
// origin-scoped pattern.
if (origin_setting == CONTENT_SETTING_ALLOW)
SetContentSettingCustomScope(
ContentSettingsPattern::FromURLNoWildcard(origin),
ContentSettingsPattern::Wildcard(), type, std::string(),
CONTENT_SETTING_ALLOW);
}
}
}
void HostContentSettingsMap::RecordNumberOfExceptions() {
for (const content_settings::WebsiteSettingsInfo* info :
*content_settings::WebsiteSettingsRegistry::GetInstance()) {
ContentSettingsType content_type = info->type();
const std::string type_name = info->name();
ContentSettingsForOneType settings;
GetSettingsForOneType(content_type, std::string(), &settings);
size_t num_exceptions = 0;
for (const ContentSettingPatternSource& setting_entry : settings) {
if (setting_entry.source == "preference")
++num_exceptions;
}
std::string histogram_name =
"ContentSettings.Exceptions." + type_name;
base::HistogramBase* histogram_pointer = base::Histogram::FactoryGet(
histogram_name, 1, 1000, 30,
base::HistogramBase::kUmaTargetedHistogramFlag);
histogram_pointer->Add(num_exceptions);
}
}
ContentSetting HostContentSettingsMap::GetContentSettingAndMaybeUpdateLastUsage(
const GURL& primary_url,
const GURL& secondary_url,
ContentSettingsType content_type,
const std::string& resource_identifier) {
DCHECK(thread_checker_.CalledOnValidThread());
ContentSetting setting = GetContentSetting(
primary_url, secondary_url, content_type, resource_identifier);
if (setting == CONTENT_SETTING_ALLOW) {
UpdateLastUsageByPattern(
ContentSettingsPattern::FromURLNoWildcard(primary_url),
ContentSettingsPattern::FromURLNoWildcard(secondary_url),
content_type);
}
return setting;
}
void HostContentSettingsMap::UpdateLastUsage(const GURL& primary_url,
const GURL& secondary_url,
ContentSettingsType content_type) {
UpdateLastUsageByPattern(
ContentSettingsPattern::FromURLNoWildcard(primary_url),
ContentSettingsPattern::FromURLNoWildcard(secondary_url),
content_type);
}
void HostContentSettingsMap::UpdateLastUsageByPattern(
const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_pattern,
ContentSettingsType content_type) {
UsedContentSettingsProviders();
pref_provider_->UpdateLastUsage(
primary_pattern, secondary_pattern, content_type);
}
base::Time HostContentSettingsMap::GetLastUsage(
const GURL& primary_url,
const GURL& secondary_url,
ContentSettingsType content_type) {
return GetLastUsageByPattern(
ContentSettingsPattern::FromURLNoWildcard(primary_url),
ContentSettingsPattern::FromURLNoWildcard(secondary_url),
content_type);
}
base::Time HostContentSettingsMap::GetLastUsageByPattern(
const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_pattern,
ContentSettingsType content_type) {
UsedContentSettingsProviders();
return pref_provider_->GetLastUsage(
primary_pattern, secondary_pattern, content_type);
}
void HostContentSettingsMap::AddObserver(content_settings::Observer* observer) {
observers_.AddObserver(observer);
}
void HostContentSettingsMap::RemoveObserver(
content_settings::Observer* observer) {
observers_.RemoveObserver(observer);
}
void HostContentSettingsMap::FlushLossyWebsiteSettings() {
prefs_->SchedulePendingLossyWrites();
}
void HostContentSettingsMap::SetPrefClockForTesting(
std::unique_ptr<base::Clock> clock) {
UsedContentSettingsProviders();
pref_provider_->SetClockForTesting(std::move(clock));
}
void HostContentSettingsMap::ClearSettingsForOneType(
ContentSettingsType content_type) {
UsedContentSettingsProviders();
for (ProviderIterator provider = content_settings_providers_.begin();
provider != content_settings_providers_.end();
++provider) {
provider->second->ClearAllContentSettingsRules(content_type);
}
FlushLossyWebsiteSettings();
}
// TODO(raymes): Remove this function. Consider making it a property of
// ContentSettingsInfo or removing it altogether (it's unclear whether we should
// be restricting allowed default values at this layer).
// static
bool HostContentSettingsMap::IsDefaultSettingAllowedForType(
ContentSetting setting,
ContentSettingsType content_type) {
#if defined(OS_ANDROID) || defined(OS_CHROMEOS)
// Don't support ALLOW for protected media default setting until migration.
if (content_type == CONTENT_SETTINGS_TYPE_PROTECTED_MEDIA_IDENTIFIER &&
setting == CONTENT_SETTING_ALLOW) {
return false;
}
#endif
// Don't support ALLOW for the default media settings.
if ((content_type == CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA ||
content_type == CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC) &&
setting == CONTENT_SETTING_ALLOW) {
return false;
}
const content_settings::ContentSettingsInfo* info =
content_settings::ContentSettingsRegistry::GetInstance()->Get(
content_type);
DCHECK(info);
return info->IsSettingValid(setting);
}
void HostContentSettingsMap::OnContentSettingChanged(
const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_pattern,
ContentSettingsType content_type,
std::string resource_identifier) {
FOR_EACH_OBSERVER(content_settings::Observer,
observers_,
OnContentSettingChanged(primary_pattern,
secondary_pattern,
content_type,
resource_identifier));
}
HostContentSettingsMap::~HostContentSettingsMap() {
DCHECK(!prefs_);
STLDeleteValues(&content_settings_providers_);
}
void HostContentSettingsMap::ShutdownOnUIThread() {
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(prefs_);
prefs_ = NULL;
for (ProviderIterator it = content_settings_providers_.begin();
it != content_settings_providers_.end();
++it) {
it->second->ShutdownOnUIThread();
}
}
void HostContentSettingsMap::AddSettingsForOneType(
const content_settings::ProviderInterface* provider,
ProviderType provider_type,
ContentSettingsType content_type,
const std::string& resource_identifier,
ContentSettingsForOneType* settings,
bool incognito) const {
std::unique_ptr<content_settings::RuleIterator> rule_iterator(
provider->GetRuleIterator(content_type, resource_identifier, incognito));
while (rule_iterator->HasNext()) {
const content_settings::Rule& rule = rule_iterator->Next();
ContentSetting setting_value = CONTENT_SETTING_DEFAULT;
// TODO(bauerb): Return rules as a list of values, not content settings.
// Handle the case using base::Values for its exceptions and default
// setting. Here we assume all the exceptions are granted as
// |CONTENT_SETTING_ALLOW|.
if (!content_settings::ContentSettingsRegistry::GetInstance()->Get(
content_type) &&
rule.value.get() &&
rule.primary_pattern != ContentSettingsPattern::Wildcard()) {
setting_value = CONTENT_SETTING_ALLOW;
} else {
setting_value = content_settings::ValueToContentSetting(rule.value.get());
}
settings->push_back(ContentSettingPatternSource(
rule.primary_pattern, rule.secondary_pattern, setting_value,
kProviderNamesSourceMap[provider_type].provider_name, incognito));
}
}
void HostContentSettingsMap::UsedContentSettingsProviders() const {
#ifndef NDEBUG
if (used_from_thread_id_ == base::kInvalidThreadId)
return;
if (base::PlatformThread::CurrentId() != used_from_thread_id_)
used_from_thread_id_ = base::kInvalidThreadId;
#endif
}
std::unique_ptr<base::Value> HostContentSettingsMap::GetWebsiteSetting(
const GURL& primary_url,
const GURL& secondary_url,
ContentSettingsType content_type,
const std::string& resource_identifier,
content_settings::SettingInfo* info) const {
DCHECK(SupportsResourceIdentifier(content_type) ||
resource_identifier.empty());
// Check if the requested setting is whitelisted.
// TODO(raymes): Move this into GetContentSetting. This has nothing to do with
// website settings
const content_settings::ContentSettingsInfo* content_settings_info =
content_settings::ContentSettingsRegistry::GetInstance()->Get(
content_type);
if (content_settings_info) {
for (const std::string& scheme :
content_settings_info->whitelisted_schemes()) {
DCHECK(SchemeCanBeWhitelisted(scheme));
if (primary_url.SchemeIs(scheme.c_str())) {
if (info) {
info->source = content_settings::SETTING_SOURCE_WHITELIST;
info->primary_pattern = ContentSettingsPattern::Wildcard();
info->secondary_pattern = ContentSettingsPattern::Wildcard();
}
return std::unique_ptr<base::Value>(
new base::FundamentalValue(CONTENT_SETTING_ALLOW));
}
}
}
return GetWebsiteSettingInternal(primary_url,
secondary_url,
content_type,
resource_identifier,
info);
}
// static
HostContentSettingsMap::ProviderType
HostContentSettingsMap::GetProviderTypeFromSource(const std::string& source) {
for (size_t i = 0; i < arraysize(kProviderNamesSourceMap); ++i) {
if (source == kProviderNamesSourceMap[i].provider_name)
return static_cast<ProviderType>(i);
}
NOTREACHED();
return DEFAULT_PROVIDER;
}
std::unique_ptr<base::Value> HostContentSettingsMap::GetWebsiteSettingInternal(
const GURL& primary_url,
const GURL& secondary_url,
ContentSettingsType content_type,
const std::string& resource_identifier,
content_settings::SettingInfo* info) const {
UsedContentSettingsProviders();
ContentSettingsPattern* primary_pattern = NULL;
ContentSettingsPattern* secondary_pattern = NULL;
if (info) {
primary_pattern = &info->primary_pattern;
secondary_pattern = &info->secondary_pattern;
}
// The list of |content_settings_providers_| is ordered according to their
// precedence.
for (ConstProviderIterator provider = content_settings_providers_.begin();
provider != content_settings_providers_.end();
++provider) {
std::unique_ptr<base::Value> value = GetContentSettingValueAndPatterns(
provider->second, primary_url, secondary_url, content_type,
resource_identifier, is_off_the_record_, primary_pattern,
secondary_pattern);
if (value) {
if (info)
info->source = kProviderNamesSourceMap[provider->first].provider_source;
return value;
}
}
if (info) {
info->source = content_settings::SETTING_SOURCE_NONE;
info->primary_pattern = ContentSettingsPattern();
info->secondary_pattern = ContentSettingsPattern();
}
return std::unique_ptr<base::Value>();
}
// static
std::unique_ptr<base::Value>
HostContentSettingsMap::GetContentSettingValueAndPatterns(
const content_settings::ProviderInterface* provider,
const GURL& primary_url,
const GURL& secondary_url,
ContentSettingsType content_type,
const std::string& resource_identifier,
bool include_incognito,
ContentSettingsPattern* primary_pattern,
ContentSettingsPattern* secondary_pattern) {
if (include_incognito) {
// Check incognito-only specific settings. It's essential that the
// |RuleIterator| gets out of scope before we get a rule iterator for the
// normal mode.
std::unique_ptr<content_settings::RuleIterator> incognito_rule_iterator(
provider->GetRuleIterator(content_type, resource_identifier,
true /* incognito */));
std::unique_ptr<base::Value> value = GetContentSettingValueAndPatterns(
incognito_rule_iterator.get(), primary_url, secondary_url,
primary_pattern, secondary_pattern);
if (value)
return value;
}
// No settings from the incognito; use the normal mode.
std::unique_ptr<content_settings::RuleIterator> rule_iterator(
provider->GetRuleIterator(content_type, resource_identifier,
false /* incognito */));
std::unique_ptr<base::Value> value = GetContentSettingValueAndPatterns(
rule_iterator.get(), primary_url, secondary_url, primary_pattern,
secondary_pattern);
if (value && include_incognito)
value = ProcessIncognitoInheritanceBehavior(content_type, std::move(value));
return value;
}
// static
std::unique_ptr<base::Value>
HostContentSettingsMap::GetContentSettingValueAndPatterns(
content_settings::RuleIterator* rule_iterator,
const GURL& primary_url,
const GURL& secondary_url,
ContentSettingsPattern* primary_pattern,
ContentSettingsPattern* secondary_pattern) {
while (rule_iterator->HasNext()) {
const content_settings::Rule& rule = rule_iterator->Next();
if (rule.primary_pattern.Matches(primary_url) &&
rule.secondary_pattern.Matches(secondary_url)) {
if (primary_pattern)
*primary_pattern = rule.primary_pattern;
if (secondary_pattern)
*secondary_pattern = rule.secondary_pattern;
return base::WrapUnique(rule.value.get()->DeepCopy());
}
}
return std::unique_ptr<base::Value>();
}