summaryrefslogtreecommitdiffstats
path: root/components/content_settings
diff options
context:
space:
mode:
authormsramek <msramek@chromium.org>2015-04-02 21:57:21 -0700
committerCommit bot <commit-bot@chromium.org>2015-04-03 04:58:07 +0000
commitc2bda48205f8246990caf262f87f52dd971c78a5 (patch)
treeb5676d5a12c3828c77af04759fcc2d50ff139b6a /components/content_settings
parentb7f527b44458aa70b8b7c52f4de229f6f243e190 (diff)
downloadchromium_src-c2bda48205f8246990caf262f87f52dd971c78a5.zip
chromium_src-c2bda48205f8246990caf262f87f52dd971c78a5.tar.gz
chromium_src-c2bda48205f8246990caf262f87f52dd971c78a5.tar.bz2
Split the aggregate dictionary that contains content settings exceptions for all content types into separate dictionary holding one content type each.
Old dictionary entry example: "www.google.com,*": {"cookies": <value>, "plugins": <value>, last_used: {"cookies": <timestamp>, "plugins": <timestamp>}, "per_plugin": {<resource_id>: <value>}} Split into separate dictionaries: cookies: "www.google.com,*": {"setting": <value>, "last_used": <timestamp>} plugins: "www.google.com,*": {"setting": <value>, "last_used": <timestamp>, "per_resource": {<resource_id>: <value>}} For migration between versions of Chrome, we use a similar logic as when we migrated the default preferences in https://codereview.chromium.org/1004733003/ . 1. On the first run, migrate all settings (PrefProvider::MigrateAllExceptions()). 2. Whenever the old dictionary preference changes, propagate the syncable entries into the new preferences (PrefProvider::OnOldContentSettingsPatternPairsChanged()). 3. Whenever one of the new preferences changes, and it is syncable, we write it back to the old dictionary preference as well (ContentSettingsPref::OnPrefChanged()). Note that PrefProvider manages its old dictionary preference the same way as ContentSettingsPref does a new preference, and ContentSettingsPref needs access to the old preference as well, which leads to some duplication in the code (UpdateOldPref() is just a modified version of UpdatePref(); both use some of the same constructs). We use the convention of referring to attributes and methods managing the old dictionary preference as "old" in the name. BUG=452388 Review URL: https://codereview.chromium.org/1005303003 Cr-Commit-Position: refs/heads/master@{#323585}
Diffstat (limited to 'components/content_settings')
-rw-r--r--components/content_settings/core/browser/content_settings_pref.cc428
-rw-r--r--components/content_settings/core/browser/content_settings_pref.h61
-rw-r--r--components/content_settings/core/browser/content_settings_pref_provider.cc371
-rw-r--r--components/content_settings/core/browser/content_settings_pref_provider.h64
-rw-r--r--components/content_settings/core/common/content_settings.cc42
-rw-r--r--components/content_settings/core/common/content_settings.h3
-rw-r--r--components/content_settings/core/common/pref_names.cc65
-rw-r--r--components/content_settings/core/common/pref_names.h30
8 files changed, 856 insertions, 208 deletions
diff --git a/components/content_settings/core/browser/content_settings_pref.cc b/components/content_settings/core/browser/content_settings_pref.cc
index a643697..7cfd31a 100644
--- a/components/content_settings/core/browser/content_settings_pref.cc
+++ b/components/content_settings/core/browser/content_settings_pref.cc
@@ -21,8 +21,8 @@
namespace {
-typedef std::pair<std::string, std::string> StringPair;
-
+const char kSettingPath[] = "setting";
+const char kPerResourceIdentifierPrefName[] = "per_resource";
const char kPerPluginPrefName[] = "per_plugin";
const char kLastUsed[] = "last_used";
@@ -39,13 +39,8 @@ ContentSetting FixObsoleteCookiePromptMode(ContentSettingsType content_type,
// returns true and sets |pref_key| to the key in the content settings
// dictionary under which per-resource content settings are stored.
// Otherwise, returns false.
-bool GetResourceTypeName(ContentSettingsType content_type,
- std::string* pref_key) {
- if (content_type == CONTENT_SETTINGS_TYPE_PLUGINS) {
- *pref_key = kPerPluginPrefName;
- return true;
- }
- return false;
+bool SupportsResourceIdentifiers(ContentSettingsType content_type) {
+ return content_type == CONTENT_SETTINGS_TYPE_PLUGINS;
}
} // namespace
@@ -53,64 +48,66 @@ bool GetResourceTypeName(ContentSettingsType content_type,
namespace content_settings {
ContentSettingsPref::ContentSettingsPref(
+ ContentSettingsType content_type,
PrefService* prefs,
PrefChangeRegistrar* registrar,
- base::Clock* clock,
+ const char* pref_name,
bool incognito,
+ bool* updating_old_preferences_flag,
NotifyObserversCallback notify_callback)
- : prefs_(prefs),
- clock_(clock),
+ : content_type_(content_type),
+ prefs_(prefs),
registrar_(registrar),
+ pref_name_(pref_name),
is_incognito_(incognito),
updating_preferences_(false),
+ updating_old_preferences_(updating_old_preferences_flag),
notify_callback_(notify_callback) {
DCHECK(prefs_);
- // Read content settings exceptions.
- ReadContentSettingsFromPref();
+ // If the migration hasn't happened yet, or if this content setting
+ // is syncable, the parent |PrefProvider| is going to copy the contents
+ // of the old preference to this new preference. There is no need
+ // to initialize this preference separately (in fact, in the case
+ // of migration, we would be writing the empty new preference back to the
+ // old one, erasing it).
+ if (prefs_->GetBoolean(prefs::kMigratedContentSettingsPatternPairs) &&
+ !IsContentSettingsTypeSyncable(content_type_)) {
+ ReadContentSettingsFromPrefAndWriteToOldPref();
+ }
- registrar->Add(
- prefs::kContentSettingsPatternPairs,
- base::Bind(&ContentSettingsPref::OnContentSettingsPatternPairsChanged,
- base::Unretained(this)));
+ registrar_->Add(
+ pref_name_,
+ base::Bind(&ContentSettingsPref::OnPrefChanged, base::Unretained(this)));
}
ContentSettingsPref::~ContentSettingsPref() {
}
RuleIterator* ContentSettingsPref::GetRuleIterator(
- ContentSettingsType content_type,
const ResourceIdentifier& resource_identifier,
bool incognito) const {
if (incognito)
- return incognito_value_map_.GetRuleIterator(content_type,
+ return incognito_value_map_.GetRuleIterator(content_type_,
resource_identifier,
&lock_);
- return value_map_.GetRuleIterator(content_type, resource_identifier, &lock_);
+ return value_map_.GetRuleIterator(content_type_, resource_identifier, &lock_);
}
bool ContentSettingsPref::SetWebsiteSetting(
const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_pattern,
- ContentSettingsType content_type,
const ResourceIdentifier& resource_identifier,
base::Value* in_value) {
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(prefs_);
-
- // Default settings are set using a wildcard pattern for both
- // |primary_pattern| and |secondary_pattern|. Don't store default settings in
- // the |PrefProvider|. The |PrefProvider| handles settings for specific
- // sites/origins defined by the |primary_pattern| and the |secondary_pattern|.
- // Default settings are handled by the |DefaultProvider|.
- if (primary_pattern == ContentSettingsPattern::Wildcard() &&
- secondary_pattern == ContentSettingsPattern::Wildcard() &&
- resource_identifier.empty()) {
- return false;
- }
+ DCHECK(primary_pattern != ContentSettingsPattern::Wildcard() ||
+ secondary_pattern != ContentSettingsPattern::Wildcard() ||
+ !resource_identifier.empty());
// At this point take the ownership of the |in_value|.
scoped_ptr<base::Value> value(in_value);
+
// Update in memory value map.
OriginIdentifierValueMap* map_to_modify = &incognito_value_map_;
if (!is_incognito_)
@@ -122,14 +119,14 @@ bool ContentSettingsPref::SetWebsiteSetting(
map_to_modify->SetValue(
primary_pattern,
secondary_pattern,
- content_type,
+ content_type_,
resource_identifier,
value->DeepCopy());
} else {
map_to_modify->DeleteValue(
primary_pattern,
secondary_pattern,
- content_type,
+ content_type_,
resource_identifier);
}
}
@@ -137,19 +134,23 @@ bool ContentSettingsPref::SetWebsiteSetting(
if (!is_incognito_) {
UpdatePref(primary_pattern,
secondary_pattern,
- content_type,
resource_identifier,
value.get());
+ if (IsContentSettingsTypeSyncable(content_type_)) {
+ UpdateOldPref(primary_pattern,
+ secondary_pattern,
+ resource_identifier,
+ value.get());
+ }
}
notify_callback_.Run(
- primary_pattern, secondary_pattern, content_type, resource_identifier);
+ primary_pattern, secondary_pattern, content_type_, resource_identifier);
return true;
}
-void ContentSettingsPref::ClearAllContentSettingsRules(
- ContentSettingsType content_type) {
+void ContentSettingsPref::ClearAllContentSettingsRules() {
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(prefs_);
@@ -161,32 +162,37 @@ void ContentSettingsPref::ClearAllContentSettingsRules(
{
base::AutoLock auto_lock(lock_);
scoped_ptr<RuleIterator> rule_iterator(
- map_to_modify->GetRuleIterator(content_type, std::string(), NULL));
+ map_to_modify->GetRuleIterator(content_type_, std::string(), NULL));
// Copy the rules; we cannot call |UpdatePref| while holding |lock_|.
while (rule_iterator->HasNext())
rules_to_delete.push_back(rule_iterator->Next());
- map_to_modify->DeleteValues(content_type, std::string());
+ 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);
+ if (IsContentSettingsTypeSyncable(content_type_)) {
+ UpdateOldPref(it->primary_pattern,
+ it->secondary_pattern,
+ std::string(),
+ NULL);
+ }
}
notify_callback_.Run(ContentSettingsPattern(),
ContentSettingsPattern(),
- content_type,
+ content_type_,
std::string());
}
void ContentSettingsPref::UpdateLastUsage(
const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_pattern,
- ContentSettingsType content_type) {
+ base::Clock* clock) {
// Don't write if in incognito.
if (is_incognito_) {
return;
@@ -198,7 +204,7 @@ void ContentSettingsPref::UpdateLastUsage(
base::AutoReset<bool> auto_reset(&updating_preferences_, true);
{
- DictionaryPrefUpdate update(prefs_, prefs::kContentSettingsPatternPairs);
+ DictionaryPrefUpdate update(prefs_, pref_name_);
base::DictionaryValue* pattern_pairs_settings = update.Get();
std::string pattern_str(
@@ -213,28 +219,16 @@ void ContentSettingsPref::UpdateLastUsage(
settings_dictionary);
}
- base::DictionaryValue* last_used_dictionary = NULL;
- found = settings_dictionary->GetDictionaryWithoutPathExpansion(
- kLastUsed, &last_used_dictionary);
-
- if (!found) {
- last_used_dictionary = new base::DictionaryValue;
- settings_dictionary->SetWithoutPathExpansion(kLastUsed,
- last_used_dictionary);
- }
-
- std::string settings_path = GetTypeName(content_type);
- last_used_dictionary->Set(
- settings_path, new base::FundamentalValue(clock_->Now().ToDoubleT()));
+ settings_dictionary->SetWithoutPathExpansion(
+ kLastUsed, new base::FundamentalValue(clock->Now().ToDoubleT()));
}
}
base::Time ContentSettingsPref::GetLastUsage(
const ContentSettingsPattern& primary_pattern,
- const ContentSettingsPattern& secondary_pattern,
- ContentSettingsType content_type) {
+ const ContentSettingsPattern& secondary_pattern) {
const base::DictionaryValue* pattern_pairs_settings =
- prefs_->GetDictionary(prefs::kContentSettingsPatternPairs);
+ prefs_->GetDictionary(pref_name_);
std::string pattern_str(
CreatePatternString(primary_pattern, secondary_pattern));
@@ -245,16 +239,9 @@ base::Time ContentSettingsPref::GetLastUsage(
if (!found)
return base::Time();
- const base::DictionaryValue* last_used_dictionary = NULL;
- found = settings_dictionary->GetDictionaryWithoutPathExpansion(
- kLastUsed, &last_used_dictionary);
-
- if (!found)
- return base::Time();
-
double last_used_time;
- found = last_used_dictionary->GetDoubleWithoutPathExpansion(
- GetTypeName(content_type), &last_used_time);
+ found = settings_dictionary->GetDoubleWithoutPathExpansion(
+ kLastUsed, &last_used_time);
if (!found)
return base::Time();
@@ -266,22 +253,25 @@ size_t ContentSettingsPref::GetNumExceptions() {
return value_map_.size();
}
-void ContentSettingsPref::SetClockForTesting(base::Clock* clock) {
- clock_ = clock;
-}
+void ContentSettingsPref::ReadContentSettingsFromPrefAndWriteToOldPref() {
+ // Clear the old preference, so we can copy the exceptions from the new
+ // preference into it. Note that copying in this direction is disallowed
+ // in incognito, to avoid the echo effect: New preference -> PrefProvider ->
+ // Old preference -> Incognito PrefProvider -> New preference -> etc.
+ if (!is_incognito_ && IsContentSettingsTypeSyncable(content_type_))
+ ClearOldPreference();
-void ContentSettingsPref::ReadContentSettingsFromPref() {
// |DictionaryPrefUpdate| sends out notifications when destructed. This
// construction order ensures |AutoLock| gets destroyed first and |lock_| is
// not held when the notifications are sent. Also, |auto_reset| must be still
// valid when the notifications are sent, so that |Observe| skips the
// notification.
base::AutoReset<bool> auto_reset(&updating_preferences_, true);
- DictionaryPrefUpdate update(prefs_, prefs::kContentSettingsPatternPairs);
+ DictionaryPrefUpdate update(prefs_, pref_name_);
base::AutoLock auto_lock(lock_);
const base::DictionaryValue* all_settings_dictionary =
- prefs_->GetDictionary(prefs::kContentSettingsPatternPairs);
+ prefs_->GetDictionary(pref_name_);
value_map_.clear();
@@ -323,103 +313,115 @@ void ContentSettingsPref::ReadContentSettingsFromPref() {
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,
- new base::FundamentalValue(setting));
+ if (SupportsResourceIdentifiers(content_type_)) {
+ const base::DictionaryValue* resource_dictionary = NULL;
+ if (settings_dictionary->GetDictionary(
+ kPerResourceIdentifierPrefName, &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);
+ scoped_ptr<base::Value> setting_ptr(
+ new base::FundamentalValue(setting));
+ value_map_.SetValue(pattern_pair.first,
+ pattern_pair.second,
+ content_type_,
+ resource_identifier,
+ setting_ptr->DeepCopy());
+ if (!is_incognito_ && IsContentSettingsTypeSyncable(content_type_)) {
+ UpdateOldPref(pattern_pair.first,
+ pattern_pair.second,
+ resource_identifier,
+ setting_ptr.get());
}
}
}
- base::Value* value = NULL;
- if (HostContentSettingsMap::ContentTypeHasCompoundValue(content_type)) {
- const base::DictionaryValue* setting = NULL;
- // TODO(xians): Handle the non-dictionary types.
- 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 = new base::FundamentalValue(setting);
- }
+ }
+ base::Value* value = NULL;
+ if (HostContentSettingsMap::ContentTypeHasCompoundValue(content_type_)) {
+ const base::DictionaryValue* setting = NULL;
+ // TODO(xians): Handle the non-dictionary types.
+ if (settings_dictionary->GetDictionaryWithoutPathExpansion(
+ kSettingPath, &setting)) {
+ DCHECK(!setting->empty());
+ value = setting->DeepCopy();
+ }
+ } else {
+ int setting = CONTENT_SETTING_DEFAULT;
+ if (settings_dictionary->GetIntegerWithoutPathExpansion(
+ kSettingPath, &setting)) {
+ DCHECK_NE(CONTENT_SETTING_DEFAULT, setting);
+ setting = FixObsoleteCookiePromptMode(content_type_,
+ ContentSetting(setting));
+ value = new base::FundamentalValue(setting);
}
+ }
- // |value_map_| will take the ownership of |value|.
- 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;
- }
+ if (value != NULL) {
+ scoped_ptr<base::Value> value_ptr(value);
+ value_map_.SetValue(pattern_pair.first,
+ pattern_pair.second,
+ content_type_,
+ ResourceIdentifier(),
+ value->DeepCopy());
+ if (!is_incognito_ && IsContentSettingsTypeSyncable(content_type_)) {
+ UpdateOldPref(pattern_pair.first,
+ pattern_pair.second,
+ ResourceIdentifier(),
+ value_ptr.get());
+ }
+ 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;
}
}
}
+
+ }
+
+ if (content_type_ == CONTENT_SETTINGS_TYPE_COOKIES) {
+ 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);
}
- 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 ContentSettingsPref::OnContentSettingsPatternPairsChanged() {
+void ContentSettingsPref::OnPrefChanged() {
DCHECK(thread_checker_.CalledOnValidThread());
if (updating_preferences_)
return;
- ReadContentSettingsFromPref();
+ ReadContentSettingsFromPrefAndWriteToOldPref();
notify_callback_.Run(ContentSettingsPattern(),
ContentSettingsPattern(),
- CONTENT_SETTINGS_TYPE_DEFAULT,
+ content_type_,
std::string());
}
void ContentSettingsPref::UpdatePref(
const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_pattern,
- ContentSettingsType content_type,
const ResourceIdentifier& resource_identifier,
const base::Value* value) {
// Ensure that |lock_| is not held by this thread, since this function will
@@ -428,6 +430,83 @@ void ContentSettingsPref::UpdatePref(
base::AutoReset<bool> auto_reset(&updating_preferences_, true);
{
+ DictionaryPrefUpdate update(prefs_, pref_name_);
+ base::DictionaryValue* pattern_pairs_settings = update.Get();
+
+ // Get settings dictionary for the given patterns.
+ 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) {
+ if (SupportsResourceIdentifiers(content_type_) &&
+ !resource_identifier.empty()) {
+ base::DictionaryValue* resource_dictionary = NULL;
+ found = settings_dictionary->GetDictionary(
+ kPerResourceIdentifierPrefName, &resource_dictionary);
+ if (!found) {
+ if (value == NULL)
+ return; // Nothing to remove. Exit early.
+ resource_dictionary = new base::DictionaryValue;
+ settings_dictionary->Set(
+ kPerResourceIdentifierPrefName, resource_dictionary);
+ }
+ // Update resource dictionary.
+ if (value == NULL) {
+ resource_dictionary->RemoveWithoutPathExpansion(resource_identifier,
+ NULL);
+ if (resource_dictionary->empty()) {
+ settings_dictionary->RemoveWithoutPathExpansion(
+ kPerResourceIdentifierPrefName, NULL);
+ }
+ } else {
+ resource_dictionary->SetWithoutPathExpansion(
+ resource_identifier, value->DeepCopy());
+ }
+ } else {
+ // Update settings dictionary.
+ if (value == NULL) {
+ settings_dictionary->RemoveWithoutPathExpansion(kSettingPath, NULL);
+ settings_dictionary->RemoveWithoutPathExpansion(kLastUsed, NULL);
+ } else {
+ settings_dictionary->SetWithoutPathExpansion(
+ kSettingPath, value->DeepCopy());
+ }
+ }
+ // Remove the settings dictionary if it is empty.
+ if (settings_dictionary->empty()) {
+ pattern_pairs_settings->RemoveWithoutPathExpansion(
+ pattern_str, NULL);
+ }
+ }
+ }
+}
+
+void ContentSettingsPref::UpdateOldPref(
+ const ContentSettingsPattern& primary_pattern,
+ const ContentSettingsPattern& secondary_pattern,
+ const ResourceIdentifier& resource_identifier,
+ const base::Value* value) {
+ DCHECK(IsContentSettingsTypeSyncable(content_type_));
+
+ // The incognito provider cannot write the settings to avoid echo effect:
+ // New preference -> PrefProvider -> Old preference ->
+ // -> Incognito PrefProvider -> New preference -> etc.
+ DCHECK(!is_incognito_);
+
+ if (*updating_old_preferences_)
+ return;
+
+ base::AutoReset<bool> auto_reset(updating_old_preferences_, true);
+ {
DictionaryPrefUpdate update(prefs_,
prefs::kContentSettingsPatternPairs);
base::DictionaryValue* pattern_pairs_settings = update.Get();
@@ -446,17 +525,16 @@ void ContentSettingsPref::UpdatePref(
}
if (settings_dictionary) {
- std::string res_dictionary_path;
- if (GetResourceTypeName(content_type, &res_dictionary_path) &&
+ if (content_type_ == CONTENT_SETTINGS_TYPE_PLUGINS &&
!resource_identifier.empty()) {
base::DictionaryValue* resource_dictionary = NULL;
found = settings_dictionary->GetDictionary(
- res_dictionary_path, &resource_dictionary);
+ kPerPluginPrefName, &resource_dictionary);
if (!found) {
if (value == NULL)
return; // Nothing to remove. Exit early.
resource_dictionary = new base::DictionaryValue;
- settings_dictionary->Set(res_dictionary_path, resource_dictionary);
+ settings_dictionary->Set(kPerPluginPrefName, resource_dictionary);
}
// Update resource dictionary.
if (value == NULL) {
@@ -464,7 +542,7 @@ void ContentSettingsPref::UpdatePref(
NULL);
if (resource_dictionary->empty()) {
settings_dictionary->RemoveWithoutPathExpansion(
- res_dictionary_path, NULL);
+ kPerPluginPrefName, NULL);
}
} else {
resource_dictionary->SetWithoutPathExpansion(
@@ -472,7 +550,7 @@ void ContentSettingsPref::UpdatePref(
}
} else {
// Update settings dictionary.
- std::string setting_path = GetTypeName(content_type);
+ std::string setting_path = GetTypeName(content_type_);
if (value == NULL) {
settings_dictionary->RemoveWithoutPathExpansion(setting_path,
NULL);
@@ -491,6 +569,48 @@ void ContentSettingsPref::UpdatePref(
}
}
+void ContentSettingsPref::ClearOldPreference() {
+ DCHECK(IsContentSettingsTypeSyncable(content_type_));
+
+ if (*updating_old_preferences_)
+ return;
+
+ std::vector<std::string> keys;
+
+ base::AutoReset<bool> auto_reset(updating_old_preferences_, true);
+ DictionaryPrefUpdate update(prefs_, prefs::kContentSettingsPatternPairs);
+ base::DictionaryValue* old_dictionary = update.Get();
+
+ for (base::DictionaryValue::Iterator it(*old_dictionary);
+ !it.IsAtEnd(); it.Advance()) {
+ keys.push_back(it.key());
+ }
+
+ for (const std::string& key : keys) {
+ base::DictionaryValue* exception;
+ bool is_dictionary =
+ old_dictionary->GetDictionaryWithoutPathExpansion(key, &exception);
+ DCHECK(is_dictionary);
+
+ exception->RemoveWithoutPathExpansion(GetTypeName(content_type_), NULL);
+
+ base::DictionaryValue* last_used;
+ if (exception->GetDictionaryWithoutPathExpansion(kLastUsed, &last_used)) {
+ last_used->RemoveWithoutPathExpansion(GetTypeName(content_type_), NULL);
+
+ if (last_used->empty())
+ exception->RemoveWithoutPathExpansion(kLastUsed, NULL);
+ }
+
+ if (content_type_ == CONTENT_SETTINGS_TYPE_PLUGINS)
+ exception->RemoveWithoutPathExpansion(kPerPluginPrefName, NULL);
+
+ if (exception->empty())
+ old_dictionary->RemoveWithoutPathExpansion(key, NULL);
+ }
+
+}
+
// static
void ContentSettingsPref::CanonicalizeContentSettingsExceptions(
base::DictionaryValue* all_settings_dictionary) {
diff --git a/components/content_settings/core/browser/content_settings_pref.h b/components/content_settings/core/browser/content_settings_pref.h
index a571a2a..1314e16 100644
--- a/components/content_settings/core/browser/content_settings_pref.h
+++ b/components/content_settings/core/browser/content_settings_pref.h
@@ -32,10 +32,7 @@ namespace content_settings {
class RuleIterator;
-// Represents a single pref for reading/writing content settings.
-// TODO(raymes): Currently all content settings types are stored in a single
-// instance of one of these. But the intention is that there will be one
-// instance of this class per content settings type.
+// Represents a single pref for reading/writing content settings of one type.
class ContentSettingsPref {
public:
typedef base::Callback<void(const ContentSettingsPattern&,
@@ -43,45 +40,46 @@ class ContentSettingsPref {
ContentSettingsType,
const std::string&)> NotifyObserversCallback;
- ContentSettingsPref(PrefService* prefs,
+ ContentSettingsPref(ContentSettingsType content_type,
+ PrefService* prefs,
PrefChangeRegistrar* registrar,
- base::Clock* clock,
+ const char* pref_name,
bool incognito,
+ bool* updating_old_preferences_flag,
NotifyObserversCallback notify_callback);
~ContentSettingsPref();
- RuleIterator* GetRuleIterator(ContentSettingsType content_type,
- const ResourceIdentifier& resource_identifier,
+ RuleIterator* GetRuleIterator(const ResourceIdentifier& resource_identifier,
bool incognito) const;
bool SetWebsiteSetting(const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_pattern,
- ContentSettingsType content_type,
const ResourceIdentifier& resource_identifier,
base::Value* value);
- void ClearAllContentSettingsRules(ContentSettingsType content_type);
+ void ClearAllContentSettingsRules();
void UpdateLastUsage(const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_pattern,
- ContentSettingsType content_type);
+ base::Clock* clock);
base::Time GetLastUsage(const ContentSettingsPattern& primary_pattern,
- const ContentSettingsPattern& secondary_pattern,
- ContentSettingsType content_type);
+ const ContentSettingsPattern& secondary_pattern);
size_t GetNumExceptions();
- void SetClockForTesting(base::Clock* clock);
private:
- friend class DeadlockCheckerThread; // For testing.
+ // Only to access static method CanonicalizeContentSettingsExceptions,
+ // so that we reduce duplicity between the two.
+ // TODO(msramek): Remove this after the migration is over.
+ friend class PrefProvider;
// Reads all content settings exceptions from the preference and load them
// into the |value_map_|. The |value_map_| is cleared first.
- void ReadContentSettingsFromPref();
+ void ReadContentSettingsFromPrefAndWriteToOldPref();
// Callback for changes in the pref with the same name.
- void OnContentSettingsPatternPairsChanged();
+ void OnPrefChanged();
// Update the preference that stores content settings exceptions and syncs the
// value to the obsolete preference. When calling this function, |lock_|
@@ -90,7 +88,6 @@ class ContentSettingsPref {
void UpdatePref(
const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_pattern,
- ContentSettingsType content_type,
const ResourceIdentifier& resource_identifier,
const base::Value* value);
@@ -102,21 +99,43 @@ class ContentSettingsPref {
// release it.
void AssertLockNotHeld() const;
+ // Update the old aggregate preference, so that the settings can be synced
+ // to old versions of Chrome.
+ // TODO(msramek): Remove after the migration is over.
+ void UpdateOldPref(
+ const ContentSettingsPattern& primary_pattern,
+ const ContentSettingsPattern& secondary_pattern,
+ const ResourceIdentifier& resource_identifier,
+ const base::Value* value);
+
+ // Remove all exceptions of |content_type_| from the old aggregate dictionary
+ // preference.
+ // TODO(msramek): Remove after the migration is over.
+ void ClearOldPreference();
+
+ // The type of content settings stored in this pref.
+ ContentSettingsType content_type_;
+
// Weak; owned by the Profile and reset in ShutdownOnUIThread.
PrefService* prefs_;
// Owned by the PrefProvider.
- base::Clock* clock_;
-
- // Owned by the PrefProvider.
PrefChangeRegistrar* registrar_;
+ // Name of the dictionary preference managed by this class.
+ const char* pref_name_;
+
bool is_incognito_;
// Whether we are currently updating preferences, this is used to ignore
// notifications from the preferences service that we triggered ourself.
bool updating_preferences_;
+ // Whether we are currently updating the old aggregate dictionary preference.
+ // Owned by the parent |PrefProvider| and shared by all its children
+ // |ContentSettingsPref|s.
+ bool* updating_old_preferences_;
+
OriginIdentifierValueMap value_map_;
OriginIdentifierValueMap incognito_value_map_;
diff --git a/components/content_settings/core/browser/content_settings_pref_provider.cc b/components/content_settings/core/browser/content_settings_pref_provider.cc
index 6c855d3..f53acc3 100644
--- a/components/content_settings/core/browser/content_settings_pref_provider.cc
+++ b/components/content_settings/core/browser/content_settings_pref_provider.cc
@@ -8,10 +8,13 @@
#include <string>
#include <utility>
+#include "base/auto_reset.h"
#include "base/bind.h"
#include "base/memory/scoped_ptr.h"
+#include "base/memory/scoped_vector.h"
#include "base/metrics/histogram.h"
#include "base/prefs/pref_service.h"
+#include "base/prefs/scoped_user_pref_update.h"
#include "base/strings/string_split.h"
#include "base/time/clock.h"
#include "base/time/default_clock.h"
@@ -26,9 +29,76 @@
namespace {
+const char kPerPluginPrefName[] = "per_plugin";
+
+// Returns true and sets |pref_key| to the key in the content settings
+// dictionary under which per-resource content settings are stored,
+// if the given content type supports resource identifiers in user preferences.
+bool GetResourceTypeName(ContentSettingsType content_type,
+ std::string* pref_key) {
+ if (content_type == CONTENT_SETTINGS_TYPE_PLUGINS) {
+ *pref_key = kPerPluginPrefName;
+ return true;
+ }
+ return false;
+}
+
+// TODO(msramek): Check if we still need this migration code. If not, remove it.
+ContentSetting FixObsoleteCookiePromptMode(ContentSettingsType content_type,
+ ContentSetting setting) {
+ if (content_type == CONTENT_SETTINGS_TYPE_COOKIES &&
+ setting == CONTENT_SETTING_ASK) {
+ return CONTENT_SETTING_BLOCK;
+ }
+ return setting;
+}
+
+// A helper function to duplicate |ContentSettingsPattern|, so that
+// |ReadContentSettingsFromOldPref| can export them in a vector. We cannot pass
+// them by pointer, because the original values will go out of scope when
+// the vector is used in |WriteSettingsToNewPreferences|.
+ContentSettingsPattern CopyPattern(const ContentSettingsPattern& pattern) {
+ return ContentSettingsPattern::FromString(pattern.ToString());
+}
+
const char kAudioKey[] = "audio";
const char kVideoKey[] = "video";
+// A list of exception preferences corresponding to individual content settings
+// types. Must be kept in sync with the enum |ContentSettingsType|.
+const char* kContentSettingsExceptionsPrefs[] = {
+ prefs::kContentSettingsCookiesPatternPairs,
+ prefs::kContentSettingsImagesPatternPairs,
+ prefs::kContentSettingsJavaScriptPatternPairs,
+ prefs::kContentSettingsPluginsPatternPairs,
+ prefs::kContentSettingsPopupsPatternPairs,
+ prefs::kContentSettingsGeolocationPatternPairs,
+ prefs::kContentSettingsNotificationsPatternPairs,
+ prefs::kContentSettingsAutoSelectCertificatePatternPairs,
+ prefs::kContentSettingsFullScreenPatternPairs,
+ prefs::kContentSettingsMouseLockPatternPairs,
+ prefs::kContentSettingsMixedScriptPatternPairs,
+ prefs::kContentSettingsMediaStreamPatternPairs,
+ prefs::kContentSettingsMediaStreamMicPatternPairs,
+ prefs::kContentSettingsMediaStreamCameraPatternPairs,
+ prefs::kContentSettingsProtocolHandlersPatternPairs,
+ prefs::kContentSettingsPpapiBrokerPatternPairs,
+ prefs::kContentSettingsAutomaticDownloadsPatternPairs,
+ prefs::kContentSettingsMidiSysexPatternPairs,
+ prefs::kContentSettingsPushMessagingPatternPairs,
+ prefs::kContentSettingsSSLCertDecisionsPatternPairs,
+#if defined(OS_WIN)
+ prefs::kContentSettingsMetroSwitchToDesktopPatternPairs,
+#elif defined(OS_ANDROID) || defined(OS_CHROMEOS)
+ prefs::kContentSettingsProtectedMediaIdentifierPatternPairs,
+#endif
+ prefs::kContentSettingsAppBannerPatternPairs
+};
+static_assert(arraysize(kContentSettingsExceptionsPrefs)
+ == CONTENT_SETTINGS_NUM_TYPES,
+ "kContentSettingsExceptionsPrefs should have "
+ "CONTENT_SETTINGS_NUM_TYPES elements");
+
} // namespace
namespace content_settings {
@@ -47,11 +117,26 @@ void PrefProvider::RegisterProfilePrefs(
registry->RegisterDictionaryPref(
prefs::kContentSettingsPatternPairs,
user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
+ registry->RegisterBooleanPref(
+ prefs::kMigratedContentSettingsPatternPairs,
+ false,
+ user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
+
+ for (int i = 0; i < CONTENT_SETTINGS_NUM_TYPES; ++i) {
+ registry->RegisterDictionaryPref(
+ kContentSettingsExceptionsPrefs[i],
+ IsContentSettingsTypeSyncable(ContentSettingsType(i))
+ ? user_prefs::PrefRegistrySyncable::SYNCABLE_PREF
+ : user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF
+ );
+ }
}
PrefProvider::PrefProvider(PrefService* prefs, bool incognito)
: prefs_(prefs),
- clock_(new base::DefaultClock()) {
+ clock_(new base::DefaultClock()),
+ is_incognito_(incognito),
+ updating_old_preferences_(false) {
DCHECK(prefs_);
// Verify preferences version.
if (!prefs_->HasPrefPath(prefs::kContentSettingsVersion)) {
@@ -64,18 +149,43 @@ PrefProvider::PrefProvider(PrefService* prefs, bool incognito)
}
pref_change_registrar_.Init(prefs_);
- content_settings_pref_.reset(new ContentSettingsPref(
- prefs_, &pref_change_registrar_, clock_.get(), incognito,
- base::Bind(&PrefProvider::Notify,
- base::Unretained(this))));
- if (!incognito) {
+ pref_change_registrar_.Add(prefs::kContentSettingsPatternPairs, base::Bind(
+ &PrefProvider::OnOldContentSettingsPatternPairsChanged,
+ base::Unretained(this)));
+
+ for (size_t i = 0; i < CONTENT_SETTINGS_NUM_TYPES; ++i) {
+ content_settings_prefs_.push_back(new ContentSettingsPref(
+ ContentSettingsType(i), prefs_, &pref_change_registrar_,
+ kContentSettingsExceptionsPrefs[i], is_incognito_,
+ &updating_old_preferences_, base::Bind(&PrefProvider::Notify,
+ base::Unretained(this))));
+ }
+
+ // Migrate all the exceptions from the aggregate dictionary preference
+ // to the separate dictionaries, if this hasn't been done before.
+ if (!prefs_->GetBoolean(prefs::kMigratedContentSettingsPatternPairs)) {
+ WriteSettingsToNewPreferences(false);
+ prefs_->SetBoolean(prefs::kMigratedContentSettingsPatternPairs, true);
+ } else {
+ // Trigger the update of old preference, and as a result,
+ // the new preferences as well.
+ OnOldContentSettingsPatternPairsChanged();
+ }
+
+ if (!is_incognito_) {
+ size_t num_exceptions = 0;
+ for (size_t i = 0; i < CONTENT_SETTINGS_NUM_TYPES; ++i)
+ num_exceptions += content_settings_prefs_[i]->GetNumExceptions();
+
UMA_HISTOGRAM_COUNTS("ContentSettings.NumberOfExceptions",
- content_settings_pref_->GetNumExceptions());
+ num_exceptions);
+
// Migrate the obsolete media content setting exceptions to the new
- // settings. This needs to be done after ReadContentSettingsFromPref().
+ // settings.
MigrateObsoleteMediaContentSetting();
}
+
}
PrefProvider::~PrefProvider() {
@@ -86,9 +196,9 @@ RuleIterator* PrefProvider::GetRuleIterator(
ContentSettingsType content_type,
const ResourceIdentifier& resource_identifier,
bool incognito) const {
- return content_settings_pref_->GetRuleIterator(content_type,
- resource_identifier,
- incognito);
+ return content_settings_prefs_[content_type]->GetRuleIterator(
+ resource_identifier,
+ incognito);
}
bool PrefProvider::SetWebsiteSetting(
@@ -100,11 +210,22 @@ bool PrefProvider::SetWebsiteSetting(
DCHECK(CalledOnValidThread());
DCHECK(prefs_);
- return content_settings_pref_->SetWebsiteSetting(primary_pattern,
- secondary_pattern,
- content_type,
- resource_identifier,
- in_value);
+ // Default settings are set using a wildcard pattern for both
+ // |primary_pattern| and |secondary_pattern|. Don't store default settings in
+ // the |PrefProvider|. The |PrefProvider| handles settings for specific
+ // sites/origins defined by the |primary_pattern| and the |secondary_pattern|.
+ // Default settings are handled by the |DefaultProvider|.
+ if (primary_pattern == ContentSettingsPattern::Wildcard() &&
+ secondary_pattern == ContentSettingsPattern::Wildcard() &&
+ resource_identifier.empty()) {
+ return false;
+ }
+
+ return content_settings_prefs_[content_type]->SetWebsiteSetting(
+ primary_pattern,
+ secondary_pattern,
+ resource_identifier,
+ in_value);
}
void PrefProvider::ClearAllContentSettingsRules(
@@ -112,7 +233,7 @@ void PrefProvider::ClearAllContentSettingsRules(
DCHECK(CalledOnValidThread());
DCHECK(prefs_);
- content_settings_pref_->ClearAllContentSettingsRules(content_type);
+ content_settings_prefs_[content_type]->ClearAllContentSettingsRules();
}
void PrefProvider::ShutdownOnUIThread() {
@@ -127,23 +248,54 @@ void PrefProvider::UpdateLastUsage(
const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_pattern,
ContentSettingsType content_type) {
- content_settings_pref_->UpdateLastUsage(primary_pattern,
- secondary_pattern,
- content_type);
+ content_settings_prefs_[content_type]->UpdateLastUsage(primary_pattern,
+ secondary_pattern,
+ clock_.get());
}
base::Time PrefProvider::GetLastUsage(
const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_pattern,
ContentSettingsType content_type) {
- return content_settings_pref_->GetLastUsage(primary_pattern,
- secondary_pattern,
- content_type);
+ return content_settings_prefs_[content_type]->GetLastUsage(primary_pattern,
+ secondary_pattern);
}
// ////////////////////////////////////////////////////////////////////////////
// Private
+PrefProvider::ContentSettingsPrefEntry::ContentSettingsPrefEntry(
+ const ContentSettingsPattern primary_pattern,
+ const ContentSettingsPattern secondary_pattern,
+ const ResourceIdentifier resource_identifier,
+ base::Value* value)
+ : primary_pattern(CopyPattern(primary_pattern)),
+ secondary_pattern(CopyPattern(secondary_pattern)),
+ resource_identifier(resource_identifier),
+ value(value) {
+}
+
+PrefProvider::ContentSettingsPrefEntry::ContentSettingsPrefEntry(
+ const ContentSettingsPrefEntry& entry)
+ : primary_pattern(CopyPattern(entry.primary_pattern)),
+ secondary_pattern(CopyPattern(entry.secondary_pattern)),
+ resource_identifier(entry.resource_identifier),
+ value(entry.value->DeepCopy()) {
+}
+
+PrefProvider::ContentSettingsPrefEntry&
+ PrefProvider::ContentSettingsPrefEntry::operator=(
+ const ContentSettingsPrefEntry& entry) {
+ this->primary_pattern = CopyPattern(entry.primary_pattern);
+ this->secondary_pattern = CopyPattern(entry.secondary_pattern);
+ this->resource_identifier = entry.resource_identifier;
+ this->value.reset(entry.value->DeepCopy());
+
+ return *this;
+}
+
+PrefProvider::ContentSettingsPrefEntry::~ContentSettingsPrefEntry() {}
+
void PrefProvider::MigrateObsoleteMediaContentSetting() {
std::vector<Rule> rules_to_delete;
{
@@ -205,9 +357,180 @@ void PrefProvider::Notify(
resource_identifier);
}
+void PrefProvider::ReadContentSettingsFromOldPref() {
+ // |DictionaryPrefUpdate| sends out notifications when destructed. This
+ // construction order ensures |AutoLock| gets destroyed first and |old_lock_|
+ // is not held when the notifications are sent. Also, |auto_reset| must be
+ // still valid when the notifications are sent, so that |Observe| skips the
+ // notification.
+ base::AutoReset<bool> auto_reset(&updating_old_preferences_, true);
+ DictionaryPrefUpdate update(prefs_, prefs::kContentSettingsPatternPairs);
+
+ ClearPrefEntryMap();
+
+ const base::DictionaryValue* all_settings_dictionary =
+ prefs_->GetDictionary(prefs::kContentSettingsPatternPairs);
+
+ // Careful: The returned value could be NULL if the pref has never been set.
+ if (!all_settings_dictionary)
+ return;
+
+ base::DictionaryValue* mutable_settings;
+ scoped_ptr<base::DictionaryValue> mutable_settings_scope;
+
+ if (!is_incognito_) {
+ mutable_settings = update.Get();
+ } else {
+ // Create copy as we do not want to persist anything in OTR prefs.
+ mutable_settings = all_settings_dictionary->DeepCopy();
+ mutable_settings_scope.reset(mutable_settings);
+ }
+ // Convert all Unicode patterns into punycode form, then read.
+ ContentSettingsPref::CanonicalizeContentSettingsExceptions(mutable_settings);
+
+ 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()) {
+ // TODO: Change this to DFATAL when crbug.com/132659 is fixed.
+ LOG(ERROR) << "Invalid pattern strings: " << pattern_str;
+ continue;
+ }
+
+ // Get settings dictionary for the current pattern string, and read
+ // settings from the dictionary.
+ 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);
+
+ pref_entry_map_[content_type].push_back(
+ new ContentSettingsPrefEntry(
+ pattern_pair.first,
+ pattern_pair.second,
+ resource_identifier,
+ new base::FundamentalValue(setting)));
+ }
+ }
+ }
+ base::Value* value = NULL;
+ if (HostContentSettingsMap::ContentTypeHasCompoundValue(content_type)) {
+ const base::DictionaryValue* setting = NULL;
+ // TODO(xians): Handle the non-dictionary types.
+ 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 = new base::FundamentalValue(setting);
+ }
+ }
+
+ // |pref_entry_map_| will take the ownership of |value|.
+ if (value != NULL) {
+ pref_entry_map_[content_type].push_back(
+ new ContentSettingsPrefEntry(
+ pattern_pair.first,
+ pattern_pair.second,
+ ResourceIdentifier(),
+ value));
+ }
+ }
+ }
+}
+
+void PrefProvider::WriteSettingsToNewPreferences(bool syncable_only) {
+ // The incognito provider cannot write the settings to avoid echo effect:
+ // New preference -> PrefProvider -> Old preference ->
+ // -> Incognito PrefProvider -> New preference -> etc.
+ if (is_incognito_)
+ return;
+
+ if (updating_old_preferences_)
+ return;
+
+ base::AutoReset<bool> auto_reset(&updating_old_preferences_, true);
+ base::AutoLock auto_lock(old_lock_);
+
+ ReadContentSettingsFromOldPref();
+
+ for (int k = 0; k < CONTENT_SETTINGS_NUM_TYPES; ++k) {
+ ContentSettingsType content_type = ContentSettingsType(k);
+
+ if (syncable_only && !IsContentSettingsTypeSyncable(content_type))
+ continue;
+
+ content_settings_prefs_[content_type]->ClearAllContentSettingsRules();
+
+ for (size_t i = 0; i < pref_entry_map_[content_type].size(); ++i) {
+#if defined(OS_CHROMEOS) || defined(OS_ANDROID)
+ // Protected Media Identifier "Allow" exceptions can not be migrated.
+ const base::FundamentalValue allow_value(CONTENT_SETTING_ALLOW);
+ if (content_type == CONTENT_SETTINGS_TYPE_PROTECTED_MEDIA_IDENTIFIER &&
+ pref_entry_map_[content_type][i]->value->Equals(&allow_value)) {
+ continue;
+ }
+#endif
+
+ content_settings_prefs_[content_type]->SetWebsiteSetting(
+ pref_entry_map_[content_type][i]->primary_pattern,
+ pref_entry_map_[content_type][i]->secondary_pattern,
+ pref_entry_map_[content_type][i]->resource_identifier,
+ pref_entry_map_[content_type][i]->value.release());
+ }
+ }
+
+ ClearPrefEntryMap();
+}
+
+void PrefProvider::ClearPrefEntryMap() {
+ for (int i = 0; i < CONTENT_SETTINGS_NUM_TYPES; ++i)
+ pref_entry_map_[i].clear();
+}
+
+void PrefProvider::OnOldContentSettingsPatternPairsChanged() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+
+ WriteSettingsToNewPreferences(true);
+}
+
void PrefProvider::SetClockForTesting(scoped_ptr<base::Clock> clock) {
clock_ = clock.Pass();
- content_settings_pref_->SetClockForTesting(clock_.get());
+}
+
+bool PrefProvider::TestAllLocks() const {
+ for (size_t i = 0; i < CONTENT_SETTINGS_NUM_TYPES; ++i) {
+ if (!content_settings_prefs_[i]->lock_.Try())
+ return false;
+ content_settings_prefs_[i]->lock_.Release();
+ }
+ return true;
}
} // namespace content_settings
diff --git a/components/content_settings/core/browser/content_settings_pref_provider.h b/components/content_settings/core/browser/content_settings_pref_provider.h
index 8c26c4d..ec235a9 100644
--- a/components/content_settings/core/browser/content_settings_pref_provider.h
+++ b/components/content_settings/core/browser/content_settings_pref_provider.h
@@ -10,6 +10,7 @@
#include <vector>
#include "base/basictypes.h"
+#include "base/memory/scoped_vector.h"
#include "base/prefs/pref_change_registrar.h"
#include "components/content_settings/core/browser/content_settings_observable_provider.h"
#include "components/content_settings/core/browser/content_settings_utils.h"
@@ -70,14 +71,20 @@ class PrefProvider : public ObservableProvider {
// Gains ownership of |clock|.
void SetClockForTesting(scoped_ptr<base::Clock> clock);
- ContentSettingsPref* content_settings_pref() {
- return content_settings_pref_.get();
- }
-
private:
+ friend class DeadlockCheckerThread; // For testing.
+
// Migrate the old media setting into new mic/camera content settings.
void MigrateObsoleteMediaContentSetting();
+ // Migrate the settings from the old aggregate dictionary into the new format.
+ void MigrateAllExceptions();
+
+ // Writes the contents of the old aggregate dictionary preferences into
+ // separate dictionaries for content types. If |syncable_only| is true,
+ // only syncable content types will be written.
+ void WriteSettingsToNewPreferences(bool syncable_only);
+
// Weak; owned by the Profile and reset in ShutdownOnUIThread.
PrefService* prefs_;
@@ -88,9 +95,56 @@ class PrefProvider : public ObservableProvider {
PrefChangeRegistrar pref_change_registrar_;
- scoped_ptr<ContentSettingsPref> content_settings_pref_;
+ ScopedVector<ContentSettingsPref> content_settings_prefs_;
DISALLOW_COPY_AND_ASSIGN(PrefProvider);
+
+ bool TestAllLocks() const;
+
+ // All functionality regarding reading and writing of preferences has been
+ // moved to |ContentSettingsPref|, which manages one content type per
+ // instance. However, for backward compatibility, we need to be able to write
+ // to the old and deprecated aggregate dictionary preference which maintains
+ // all content types. Therefore, |ContentSettingsPrefProvider| must still
+ // retain some of the functionality of |ContentSettingsPref|. The following
+ // attributes and methods serve this purpose.
+ // TODO(msramek): Remove this migration code after two stable releases.
+ struct ContentSettingsPrefEntry {
+ ContentSettingsPrefEntry(const ContentSettingsPattern primary_pattern,
+ const ContentSettingsPattern secondary_pattern,
+ const ResourceIdentifier resource_identifier,
+ base::Value* value);
+ ContentSettingsPrefEntry(const ContentSettingsPrefEntry& entry);
+ ContentSettingsPrefEntry& operator=(const ContentSettingsPrefEntry& entry);
+ ~ContentSettingsPrefEntry();
+
+ ContentSettingsPattern primary_pattern;
+ ContentSettingsPattern secondary_pattern;
+ ResourceIdentifier resource_identifier;
+ scoped_ptr<base::Value> value;
+ };
+
+ // Stores exceptions read from the old preference before writing them
+ // to the new one.
+ ScopedVector<ContentSettingsPrefEntry>
+ pref_entry_map_[CONTENT_SETTINGS_NUM_TYPES];
+
+ // Clears |pref_entry_map_|.
+ void ClearPrefEntryMap();
+
+ // Guards access to |pref_entry_map_|.
+ mutable base::Lock old_lock_;
+
+ // Indicates whether the old preferences are updated.
+ bool updating_old_preferences_;
+
+ // Called when the old preference changes.
+ void OnOldContentSettingsPatternPairsChanged();
+
+ // Reads the old preference and writes it to |pref_entry_map_|.
+ void ReadContentSettingsFromOldPref();
+
+ base::ThreadChecker thread_checker_;
};
} // namespace content_settings
diff --git a/components/content_settings/core/common/content_settings.cc b/components/content_settings/core/common/content_settings.cc
index 00403e9..491f973 100644
--- a/components/content_settings/core/common/content_settings.cc
+++ b/components/content_settings/core/common/content_settings.cc
@@ -73,6 +73,48 @@ ContentSettingsTypeHistogram ContentSettingTypeToHistogramValue(
return CONTENT_SETTINGS_TYPE_HISTOGRAM_INVALID;
}
+bool IsContentSettingsTypeSyncable(ContentSettingsType content_setting) {
+ switch (content_setting) {
+ case CONTENT_SETTINGS_TYPE_COOKIES:
+ case CONTENT_SETTINGS_TYPE_IMAGES:
+ case CONTENT_SETTINGS_TYPE_JAVASCRIPT:
+ case CONTENT_SETTINGS_TYPE_PLUGINS:
+ case CONTENT_SETTINGS_TYPE_POPUPS:
+ case CONTENT_SETTINGS_TYPE_FULLSCREEN:
+ case CONTENT_SETTINGS_TYPE_MOUSELOCK:
+ case CONTENT_SETTINGS_TYPE_MIXEDSCRIPT:
+ case CONTENT_SETTINGS_TYPE_PROTOCOL_HANDLERS:
+ case CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS:
+ case CONTENT_SETTINGS_TYPE_MIDI_SYSEX:
+ case CONTENT_SETTINGS_TYPE_PUSH_MESSAGING:
+#if defined(OS_WIN)
+ case CONTENT_SETTINGS_TYPE_METRO_SWITCH_TO_DESKTOP:
+#endif
+ return true;
+
+ case CONTENT_SETTINGS_TYPE_GEOLOCATION:
+ case CONTENT_SETTINGS_TYPE_NOTIFICATIONS:
+ case CONTENT_SETTINGS_TYPE_AUTO_SELECT_CERTIFICATE:
+ case CONTENT_SETTINGS_TYPE_MEDIASTREAM:
+ case CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC:
+ case CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA:
+ case CONTENT_SETTINGS_TYPE_PPAPI_BROKER:
+ case CONTENT_SETTINGS_TYPE_SSL_CERT_DECISIONS:
+#if defined(OS_ANDROID) || defined(OS_CHROMEOS)
+ case CONTENT_SETTINGS_TYPE_PROTECTED_MEDIA_IDENTIFIER:
+#endif
+ case CONTENT_SETTINGS_TYPE_APP_BANNER:
+ return false;
+
+ case CONTENT_SETTINGS_TYPE_DEFAULT:
+ case CONTENT_SETTINGS_NUM_TYPES:
+ NOTREACHED();
+ return false;
+ }
+ NOTREACHED();
+ return false;
+}
+
ContentSettingPatternSource::ContentSettingPatternSource(
const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_pattern,
diff --git a/components/content_settings/core/common/content_settings.h b/components/content_settings/core/common/content_settings.h
index 7f49a8c..7745ac1 100644
--- a/components/content_settings/core/common/content_settings.h
+++ b/components/content_settings/core/common/content_settings.h
@@ -34,6 +34,9 @@ ContentSetting IntToContentSetting(int content_setting);
ContentSettingsTypeHistogram ContentSettingTypeToHistogramValue(
ContentSettingsType content_setting);
+// Whether this content setting should be synced.
+bool IsContentSettingsTypeSyncable(ContentSettingsType content_setting);
+
struct ContentSettingPatternSource {
ContentSettingPatternSource(const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_patttern,
diff --git a/components/content_settings/core/common/pref_names.cc b/components/content_settings/core/common/pref_names.cc
index da7bd8b..bffdc49 100644
--- a/components/content_settings/core/common/pref_names.cc
+++ b/components/content_settings/core/common/pref_names.cc
@@ -80,15 +80,72 @@ const char kDefaultProtectedMediaIdentifierSetting[] =
const char kDefaultAppBannerSetting[] =
"profile.default_content_setting_values.app_banner";
+// Boolean indicating whether the media stream default setting had been
+// migrated into two separate microphone and camera settings.
+const char kMigratedDefaultMediaStreamSetting[] =
+ "profile.migrated_default_media_stream_content_settings";
+
// Dictionary of content settings that can globally disallow all hosts by
// default. If a value is set, it means the setting is globally disallowed.
// If a value is not set, it means the setting is allowed.
const char kOverrideContentSettings[] = "profile.override_content_settings";
-// Boolean indicating whether the media stream default setting had been
-// migrated into two separate microphone and camera settings.
-const char kMigratedDefaultMediaStreamSetting[] =
- "profile.migrated_default_media_stream_content_settings";
+// Preferences storing the content settings exceptions.
+const char kContentSettingsCookiesPatternPairs[] =
+ "profile.content_settings.exceptions.cookies";
+const char kContentSettingsImagesPatternPairs[] =
+ "profile.content_settings.exceptions.images";
+const char kContentSettingsJavaScriptPatternPairs[] =
+ "profile.content_settings.exceptions.javascript";
+const char kContentSettingsPluginsPatternPairs[] =
+ "profile.content_settings.exceptions.plugins";
+const char kContentSettingsPopupsPatternPairs[] =
+ "profile.content_settings.exceptions.popups";
+const char kContentSettingsGeolocationPatternPairs[] =
+ "profile.content_settings.exceptions.geolocation";
+const char kContentSettingsNotificationsPatternPairs[] =
+ "profile.content_settings.exceptions.notifications";
+const char kContentSettingsAutoSelectCertificatePatternPairs[] =
+ "profile.content_settings.exceptions.auto_select_certificate";
+const char kContentSettingsFullScreenPatternPairs[] =
+ "profile.content_settings.exceptions.fullscreen";
+const char kContentSettingsMouseLockPatternPairs[] =
+ "profile.content_settings.exceptions.mouselock";
+const char kContentSettingsMixedScriptPatternPairs[] =
+ "profile.content_settings.exceptions.mixed_script";
+const char kContentSettingsMediaStreamPatternPairs[] =
+ "profile.content_settings.exceptions.media_stream";
+const char kContentSettingsMediaStreamMicPatternPairs[] =
+ "profile.content_settings.exceptions.media_stream_mic";
+const char kContentSettingsMediaStreamCameraPatternPairs[] =
+ "profile.content_settings.exceptions.media_stream_camera";
+const char kContentSettingsProtocolHandlersPatternPairs[] =
+ "profile.content_settings.exceptions.protocol_handlers";
+const char kContentSettingsPpapiBrokerPatternPairs[] =
+ "profile.content_settings.exceptions.ppapi_broker";
+const char kContentSettingsAutomaticDownloadsPatternPairs[] =
+ "profile.content_settings.exceptions.automatic_downloads";
+const char kContentSettingsMidiSysexPatternPairs[] =
+ "profile.content_settings.exceptions.midi_sysex";
+const char kContentSettingsPushMessagingPatternPairs[] =
+ "profile.content_settings.exceptions.push_messaging";
+const char kContentSettingsSSLCertDecisionsPatternPairs[] =
+ "profile.content_settings.exceptions.ssl_cert_decisions";
+#if defined(OS_WIN)
+const char kContentSettingsMetroSwitchToDesktopPatternPairs[] =
+ "profile.content_settings.exceptions.metro_switch_to_desktop";
+#elif defined(OS_ANDROID) || defined(OS_CHROMEOS)
+const char kContentSettingsProtectedMediaIdentifierPatternPairs[] =
+ "profile.content_settings.exceptions.protected_media_identifier";
+#endif
+const char kContentSettingsAppBannerPatternPairs[] =
+ "profile.content_settings.exceptions.app_banner";
+
+// Whether the patern pairs have been migrated from the deprecated aggregate
+// preference |kContentSettingsPatternPairs| to the separate preferences
+// |kContentSettings<type>PatternPairs|.
+const char kMigratedContentSettingsPatternPairs[] =
+ "profile.migrated_content_settings_exceptions";
// Preferences that are exclusively used to store managed values for default
// content settings.
diff --git a/components/content_settings/core/common/pref_names.h b/components/content_settings/core/common/pref_names.h
index 01620a3..69591d5 100644
--- a/components/content_settings/core/common/pref_names.h
+++ b/components/content_settings/core/common/pref_names.h
@@ -45,6 +45,36 @@ extern const char kDefaultAppBannerSetting[];
extern const char kMigratedDefaultMediaStreamSetting[];
+// Preferences storing the default values for individual content settings.
+extern const char kContentSettingsCookiesPatternPairs[];
+extern const char kContentSettingsImagesPatternPairs[];
+extern const char kContentSettingsJavaScriptPatternPairs[];
+extern const char kContentSettingsPluginsPatternPairs[];
+extern const char kContentSettingsPopupsPatternPairs[];
+extern const char kContentSettingsGeolocationPatternPairs[];
+extern const char kContentSettingsNotificationsPatternPairs[];
+extern const char kContentSettingsAutoSelectCertificatePatternPairs[];
+extern const char kContentSettingsFullScreenPatternPairs[];
+extern const char kContentSettingsMouseLockPatternPairs[];
+extern const char kContentSettingsMixedScriptPatternPairs[];
+extern const char kContentSettingsMediaStreamPatternPairs[];
+extern const char kContentSettingsMediaStreamMicPatternPairs[];
+extern const char kContentSettingsMediaStreamCameraPatternPairs[];
+extern const char kContentSettingsProtocolHandlersPatternPairs[];
+extern const char kContentSettingsPpapiBrokerPatternPairs[];
+extern const char kContentSettingsAutomaticDownloadsPatternPairs[];
+extern const char kContentSettingsMidiSysexPatternPairs[];
+extern const char kContentSettingsPushMessagingPatternPairs[];
+extern const char kContentSettingsSSLCertDecisionsPatternPairs[];
+#if defined(OS_WIN)
+extern const char kContentSettingsMetroSwitchToDesktopPatternPairs[];
+#elif defined(OS_ANDROID) || defined(OS_CHROMEOS)
+extern const char kContentSettingsProtectedMediaIdentifierPatternPairs[];
+#endif
+extern const char kContentSettingsAppBannerPatternPairs[];
+
+extern const char kMigratedContentSettingsPatternPairs[];
+
extern const char kManagedDefaultCookiesSetting[];
extern const char kManagedDefaultImagesSetting[];
extern const char kManagedDefaultJavaScriptSetting[];