This source file includes following definitions.
- FixObsoleteCookiePromptMode
- GetResourceTypeName
- RegisterProfilePrefs
- updating_preferences_
- SetWebsiteSetting
- ClearAllContentSettingsRules
- GetRuleIterator
- UpdatePref
- MigrateObsoleteMediaContentSetting
- ReadContentSettingsFromPref
- OnContentSettingsPatternPairsChanged
- CanonicalizeContentSettingsExceptions
- ShutdownOnUIThread
- AssertLockNotHeld
#include "chrome/browser/content_settings/content_settings_pref_provider.h"
#include <map>
#include <string>
#include <utility>
#include "base/auto_reset.h"
#include "base/command_line.h"
#include "base/memory/scoped_ptr.h"
#include "base/metrics/histogram.h"
#include "base/prefs/pref_service.h"
#include "base/prefs/scoped_user_pref_update.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/content_settings/content_settings_rule.h"
#include "chrome/browser/content_settings/content_settings_utils.h"
#include "chrome/browser/content_settings/host_content_settings_map.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/content_settings.h"
#include "chrome/common/content_settings_pattern.h"
#include "chrome/common/pref_names.h"
#include "components/user_prefs/pref_registry_syncable.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/notification_details.h"
#include "content/public/browser/notification_source.h"
#include "content/public/browser/user_metrics.h"
#include "url/gurl.h"
using base::UserMetricsAction;
using content::BrowserThread;
namespace {
typedef std::pair<std::string, std::string> StringPair;
typedef std::map<std::string, std::string> StringMap;
const char kPerPluginPrefName[] = "per_plugin";
const char kAudioKey[] = "audio";
const char kVideoKey[] = "video";
ContentSetting FixObsoleteCookiePromptMode(ContentSettingsType content_type,
ContentSetting setting) {
if (content_type == CONTENT_SETTINGS_TYPE_COOKIES &&
setting == CONTENT_SETTING_ASK) {
return CONTENT_SETTING_BLOCK;
}
return setting;
}
bool GetResourceTypeName(ContentSettingsType content_type,
std::string* pref_key) {
if (content_type == CONTENT_SETTINGS_TYPE_PLUGINS) {
*pref_key = kPerPluginPrefName;
return true;
}
return false;
}
}
namespace content_settings {
void PrefProvider::RegisterProfilePrefs(
user_prefs::PrefRegistrySyncable* registry) {
registry->RegisterIntegerPref(
prefs::kContentSettingsVersion,
ContentSettingsPattern::kContentSettingsPatternVersion,
user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
registry->RegisterDictionaryPref(
prefs::kContentSettingsPatternPairs,
user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
}
PrefProvider::PrefProvider(PrefService* prefs,
bool incognito)
: prefs_(prefs),
is_incognito_(incognito),
updating_preferences_(false) {
DCHECK(prefs_);
if (!prefs_->HasPrefPath(prefs::kContentSettingsVersion)) {
prefs_->SetInteger(prefs::kContentSettingsVersion,
ContentSettingsPattern::kContentSettingsPatternVersion);
}
if (prefs_->GetInteger(prefs::kContentSettingsVersion) >
ContentSettingsPattern::kContentSettingsPatternVersion) {
return;
}
ReadContentSettingsFromPref(false);
if (!is_incognito_) {
UMA_HISTOGRAM_COUNTS("ContentSettings.NumberOfExceptions",
value_map_.size());
}
if (!is_incognito_)
MigrateObsoleteMediaContentSetting();
pref_change_registrar_.Init(prefs_);
pref_change_registrar_.Add(
prefs::kContentSettingsPatternPairs,
base::Bind(&PrefProvider::OnContentSettingsPatternPairsChanged,
base::Unretained(this)));
}
bool PrefProvider::SetWebsiteSetting(
const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_pattern,
ContentSettingsType content_type,
const ResourceIdentifier& resource_identifier,
base::Value* in_value) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
DCHECK(prefs_);
if (primary_pattern == ContentSettingsPattern::Wildcard() &&
secondary_pattern == ContentSettingsPattern::Wildcard() &&
resource_identifier.empty()) {
return false;
}
scoped_ptr<base::Value> value(in_value);
OriginIdentifierValueMap* map_to_modify = &incognito_value_map_;
if (!is_incognito_)
map_to_modify = &value_map_;
{
base::AutoLock auto_lock(lock_);
if (value.get()) {
map_to_modify->SetValue(
primary_pattern,
secondary_pattern,
content_type,
resource_identifier,
value->DeepCopy());
} else {
map_to_modify->DeleteValue(
primary_pattern,
secondary_pattern,
content_type,
resource_identifier);
}
}
if (!is_incognito_) {
UpdatePref(primary_pattern,
secondary_pattern,
content_type,
resource_identifier,
value.get());
}
NotifyObservers(
primary_pattern, secondary_pattern, content_type, resource_identifier);
return true;
}
void PrefProvider::ClearAllContentSettingsRules(
ContentSettingsType content_type) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
DCHECK(prefs_);
OriginIdentifierValueMap* map_to_modify = &incognito_value_map_;
if (!is_incognito_)
map_to_modify = &value_map_;
std::vector<Rule> rules_to_delete;
{
base::AutoLock auto_lock(lock_);
scoped_ptr<RuleIterator> rule_iterator(
map_to_modify->GetRuleIterator(content_type, std::string(), NULL));
while (rule_iterator->HasNext())
rules_to_delete.push_back(rule_iterator->Next());
map_to_modify->DeleteValues(content_type, std::string());
}
for (std::vector<Rule>::const_iterator it = rules_to_delete.begin();
it != rules_to_delete.end(); ++it) {
UpdatePref(it->primary_pattern,
it->secondary_pattern,
content_type,
std::string(),
NULL);
}
NotifyObservers(ContentSettingsPattern(),
ContentSettingsPattern(),
content_type,
std::string());
}
PrefProvider::~PrefProvider() {
DCHECK(!prefs_);
}
RuleIterator* PrefProvider::GetRuleIterator(
ContentSettingsType content_type,
const ResourceIdentifier& resource_identifier,
bool incognito) const {
if (incognito)
return incognito_value_map_.GetRuleIterator(content_type,
resource_identifier,
&lock_);
return value_map_.GetRuleIterator(content_type, resource_identifier, &lock_);
}
void PrefProvider::UpdatePref(
const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_pattern,
ContentSettingsType content_type,
const ResourceIdentifier& resource_identifier,
const base::Value* value) {
AssertLockNotHeld();
base::AutoReset<bool> auto_reset(&updating_preferences_, true);
{
DictionaryPrefUpdate update(prefs_,
prefs::kContentSettingsPatternPairs);
base::DictionaryValue* pattern_pairs_settings = update.Get();
std::string pattern_str(CreatePatternString(primary_pattern,
secondary_pattern));
base::DictionaryValue* settings_dictionary = NULL;
bool found = pattern_pairs_settings->GetDictionaryWithoutPathExpansion(
pattern_str, &settings_dictionary);
if (!found && value) {
settings_dictionary = new base::DictionaryValue;
pattern_pairs_settings->SetWithoutPathExpansion(
pattern_str, settings_dictionary);
}
if (settings_dictionary) {
std::string res_dictionary_path;
if (GetResourceTypeName(content_type, &res_dictionary_path) &&
!resource_identifier.empty()) {
base::DictionaryValue* resource_dictionary = NULL;
found = settings_dictionary->GetDictionary(
res_dictionary_path, &resource_dictionary);
if (!found) {
if (value == NULL)
return;
resource_dictionary = new base::DictionaryValue;
settings_dictionary->Set(res_dictionary_path, resource_dictionary);
}
if (value == NULL) {
resource_dictionary->RemoveWithoutPathExpansion(resource_identifier,
NULL);
if (resource_dictionary->empty()) {
settings_dictionary->RemoveWithoutPathExpansion(
res_dictionary_path, NULL);
}
} else {
resource_dictionary->SetWithoutPathExpansion(
resource_identifier, value->DeepCopy());
}
} else {
std::string setting_path = GetTypeName(content_type);
if (value == NULL) {
settings_dictionary->RemoveWithoutPathExpansion(setting_path,
NULL);
} else {
settings_dictionary->SetWithoutPathExpansion(
setting_path, value->DeepCopy());
}
}
if (settings_dictionary->empty()) {
pattern_pairs_settings->RemoveWithoutPathExpansion(
pattern_str, NULL);
}
}
}
}
void PrefProvider::MigrateObsoleteMediaContentSetting() {
std::vector<Rule> rules_to_delete;
{
scoped_ptr<RuleIterator> rule_iterator(GetRuleIterator(
CONTENT_SETTINGS_TYPE_MEDIASTREAM, std::string(), false));
while (rule_iterator->HasNext()) {
const content_settings::Rule& rule = rule_iterator->Next();
DCHECK(rule.primary_pattern != ContentSettingsPattern::Wildcard());
if (!rule.value.get())
continue;
rules_to_delete.push_back(rule);
}
}
for (std::vector<Rule>::const_iterator it = rules_to_delete.begin();
it != rules_to_delete.end(); ++it) {
const base::DictionaryValue* value_dict = NULL;
if (!it->value->GetAsDictionary(&value_dict) || value_dict->empty())
return;
std::string audio_device, video_device;
value_dict->GetString(kAudioKey, &audio_device);
value_dict->GetString(kVideoKey, &video_device);
if (!audio_device.empty()) {
SetWebsiteSetting(it->primary_pattern,
it->secondary_pattern,
CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC,
std::string(),
base::Value::CreateIntegerValue(CONTENT_SETTING_ALLOW));
}
if (!video_device.empty()) {
SetWebsiteSetting(it->primary_pattern,
it->secondary_pattern,
CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA,
std::string(),
base::Value::CreateIntegerValue(CONTENT_SETTING_ALLOW));
}
SetWebsiteSetting(it->primary_pattern,
it->secondary_pattern,
CONTENT_SETTINGS_TYPE_MEDIASTREAM,
std::string(),
NULL);
}
}
void PrefProvider::ReadContentSettingsFromPref(bool overwrite) {
base::AutoReset<bool> auto_reset(&updating_preferences_, true);
DictionaryPrefUpdate update(prefs_, prefs::kContentSettingsPatternPairs);
base::AutoLock auto_lock(lock_);
const base::DictionaryValue* all_settings_dictionary =
prefs_->GetDictionary(prefs::kContentSettingsPatternPairs);
if (overwrite)
value_map_.clear();
if (!all_settings_dictionary)
return;
base::DictionaryValue* mutable_settings;
scoped_ptr<base::DictionaryValue> mutable_settings_scope;
if (!is_incognito_) {
mutable_settings = update.Get();
} else {
mutable_settings = all_settings_dictionary->DeepCopy();
mutable_settings_scope.reset(mutable_settings);
}
CanonicalizeContentSettingsExceptions(mutable_settings);
size_t cookies_block_exception_count = 0;
size_t cookies_allow_exception_count = 0;
size_t cookies_session_only_exception_count = 0;
for (base::DictionaryValue::Iterator i(*mutable_settings); !i.IsAtEnd();
i.Advance()) {
const std::string& pattern_str(i.key());
std::pair<ContentSettingsPattern, ContentSettingsPattern> pattern_pair =
ParsePatternString(pattern_str);
if (!pattern_pair.first.IsValid() ||
!pattern_pair.second.IsValid()) {
LOG(ERROR) << "Invalid pattern strings: " << pattern_str;
continue;
}
const base::DictionaryValue* settings_dictionary = NULL;
bool is_dictionary = i.value().GetAsDictionary(&settings_dictionary);
DCHECK(is_dictionary);
for (size_t i = 0; i < CONTENT_SETTINGS_NUM_TYPES; ++i) {
ContentSettingsType content_type = static_cast<ContentSettingsType>(i);
std::string res_dictionary_path;
if (GetResourceTypeName(content_type, &res_dictionary_path)) {
const base::DictionaryValue* resource_dictionary = NULL;
if (settings_dictionary->GetDictionary(
res_dictionary_path, &resource_dictionary)) {
for (base::DictionaryValue::Iterator j(*resource_dictionary);
!j.IsAtEnd();
j.Advance()) {
const std::string& resource_identifier(j.key());
int setting = CONTENT_SETTING_DEFAULT;
bool is_integer = j.value().GetAsInteger(&setting);
DCHECK(is_integer);
DCHECK_NE(CONTENT_SETTING_DEFAULT, setting);
value_map_.SetValue(pattern_pair.first,
pattern_pair.second,
content_type,
resource_identifier,
base::Value::CreateIntegerValue(setting));
}
}
}
base::Value* value = NULL;
if (HostContentSettingsMap::ContentTypeHasCompoundValue(content_type)) {
const base::DictionaryValue* setting = NULL;
if (settings_dictionary->GetDictionaryWithoutPathExpansion(
GetTypeName(ContentSettingsType(i)), &setting)) {
DCHECK(!setting->empty());
value = setting->DeepCopy();
}
} else {
int setting = CONTENT_SETTING_DEFAULT;
if (settings_dictionary->GetIntegerWithoutPathExpansion(
GetTypeName(ContentSettingsType(i)), &setting)) {
DCHECK_NE(CONTENT_SETTING_DEFAULT, setting);
setting = FixObsoleteCookiePromptMode(content_type,
ContentSetting(setting));
value = base::Value::CreateIntegerValue(setting);
}
}
if (value != NULL) {
value_map_.SetValue(pattern_pair.first,
pattern_pair.second,
content_type,
ResourceIdentifier(),
value);
if (content_type == CONTENT_SETTINGS_TYPE_COOKIES) {
ContentSetting s = ValueToContentSetting(value);
switch (s) {
case CONTENT_SETTING_ALLOW :
++cookies_allow_exception_count;
break;
case CONTENT_SETTING_BLOCK :
++cookies_block_exception_count;
break;
case CONTENT_SETTING_SESSION_ONLY :
++cookies_session_only_exception_count;
break;
default:
NOTREACHED();
break;
}
}
}
}
}
UMA_HISTOGRAM_COUNTS("ContentSettings.NumberOfBlockCookiesExceptions",
cookies_block_exception_count);
UMA_HISTOGRAM_COUNTS("ContentSettings.NumberOfAllowCookiesExceptions",
cookies_allow_exception_count);
UMA_HISTOGRAM_COUNTS("ContentSettings.NumberOfSessionOnlyCookiesExceptions",
cookies_session_only_exception_count);
}
void PrefProvider::OnContentSettingsPatternPairsChanged() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
if (updating_preferences_)
return;
ReadContentSettingsFromPref(true);
NotifyObservers(ContentSettingsPattern(),
ContentSettingsPattern(),
CONTENT_SETTINGS_TYPE_DEFAULT,
std::string());
}
void PrefProvider::CanonicalizeContentSettingsExceptions(
base::DictionaryValue* all_settings_dictionary) {
DCHECK(all_settings_dictionary);
std::vector<std::string> remove_items;
std::vector<std::pair<std::string, std::string> > move_items;
for (base::DictionaryValue::Iterator i(*all_settings_dictionary);
!i.IsAtEnd();
i.Advance()) {
const std::string& pattern_str(i.key());
std::pair<ContentSettingsPattern, ContentSettingsPattern> pattern_pair =
ParsePatternString(pattern_str);
if (!pattern_pair.first.IsValid() ||
!pattern_pair.second.IsValid()) {
LOG(ERROR) << "Invalid pattern strings: " << pattern_str;
continue;
}
const std::string canonicalized_pattern_str = CreatePatternString(
pattern_pair.first, pattern_pair.second);
if (canonicalized_pattern_str.empty() ||
canonicalized_pattern_str == pattern_str) {
continue;
}
const base::DictionaryValue* new_pattern_settings_dictionary = NULL;
if (all_settings_dictionary->GetDictionaryWithoutPathExpansion(
canonicalized_pattern_str, &new_pattern_settings_dictionary)) {
remove_items.push_back(pattern_str);
continue;
}
const base::DictionaryValue* old_pattern_settings_dictionary = NULL;
if (i.value().GetAsDictionary(&old_pattern_settings_dictionary)) {
move_items.push_back(
std::make_pair(pattern_str, canonicalized_pattern_str));
}
}
for (size_t i = 0; i < remove_items.size(); ++i) {
all_settings_dictionary->RemoveWithoutPathExpansion(remove_items[i], NULL);
}
for (size_t i = 0; i < move_items.size(); ++i) {
scoped_ptr<base::Value> pattern_settings_dictionary;
all_settings_dictionary->RemoveWithoutPathExpansion(
move_items[i].first, &pattern_settings_dictionary);
all_settings_dictionary->SetWithoutPathExpansion(
move_items[i].second, pattern_settings_dictionary.release());
}
}
void PrefProvider::ShutdownOnUIThread() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
DCHECK(prefs_);
RemoveAllObservers();
pref_change_registrar_.RemoveAll();
prefs_ = NULL;
}
void PrefProvider::AssertLockNotHeld() const {
#if !defined(NDEBUG)
lock_.Acquire();
lock_.Release();
#endif
}
}