diff options
10 files changed, 1141 insertions, 220 deletions
diff --git a/chrome/browser/content_settings/content_settings_pref_provider_unittest.cc b/chrome/browser/content_settings/content_settings_pref_provider_unittest.cc index f3811d7..0409cc7 100644 --- a/chrome/browser/content_settings/content_settings_pref_provider_unittest.cc +++ b/chrome/browser/content_settings/content_settings_pref_provider_unittest.cc @@ -43,10 +43,7 @@ class DeadlockCheckerThread : public base::PlatformThread::Delegate { : provider_(provider) {} void ThreadMain() override { - bool got_lock = provider_->content_settings_pref()->lock_.Try(); - EXPECT_TRUE(got_lock); - if (got_lock) - provider_->content_settings_pref()->lock_.Release(); + EXPECT_TRUE(provider_->TestAllLocks()); } private: PrefProvider* provider_; @@ -465,4 +462,276 @@ TEST(PrefProviderTest, LastUsage) { pref_content_settings_provider.ShutdownOnUIThread(); } + +// TODO(msramek): This tests the correct migration behavior between the old +// aggregate dictionary preferences for all content settings types and the new +// dictionary preferences for individual types. Remove this when the migration +// period is over. +TEST(PrefProviderTest, SyncingOldToNew) { + TestingPrefServiceSyncable prefs; + PrefProvider::RegisterProfilePrefs(prefs.registry()); + PrefProvider provider(&prefs, false); + + const std::string pattern = "google.com,*"; + const std::string resource_id = "abcde12345"; + base::DictionaryValue* exceptions = new base::DictionaryValue(); + base::DictionaryValue* plugin_resources = new base::DictionaryValue(); + + // Add exceptions for images and app banner. + exceptions->SetIntegerWithoutPathExpansion( + GetTypeName(CONTENT_SETTINGS_TYPE_IMAGES), CONTENT_SETTING_ALLOW); + exceptions->SetIntegerWithoutPathExpansion( + GetTypeName(CONTENT_SETTINGS_TYPE_APP_BANNER), CONTENT_SETTING_ALLOW); + + // Add a regular exception for plugins, then one with a resource identifier. + exceptions->SetIntegerWithoutPathExpansion( + GetTypeName(CONTENT_SETTINGS_TYPE_PLUGINS), CONTENT_SETTING_ALLOW); + plugin_resources->SetIntegerWithoutPathExpansion( + resource_id, CONTENT_SETTING_BLOCK); + exceptions->SetWithoutPathExpansion( + "per_plugin", plugin_resources); + + // Change the old dictionary preference and observe changes + // in the new preferences. + { + DictionaryPrefUpdate update(&prefs, prefs::kContentSettingsPatternPairs); + base::DictionaryValue* old_dictionary = update.Get(); + old_dictionary->SetWithoutPathExpansion(pattern, exceptions); + } + + // The images exception was synced. + { + DictionaryPrefUpdate update( + &prefs, prefs::kContentSettingsImagesPatternPairs); + const base::DictionaryValue* images_dictionary = update.Get(); + + EXPECT_EQ(1u, images_dictionary->size()); + const base::DictionaryValue* images_exception; + EXPECT_TRUE(images_dictionary->GetDictionaryWithoutPathExpansion( + pattern, &images_exception)); + + // And it has a correct value. + int images_exception_value = CONTENT_SETTING_DEFAULT; + EXPECT_TRUE(images_exception->GetIntegerWithoutPathExpansion( + "setting", &images_exception_value)); + EXPECT_EQ(CONTENT_SETTING_ALLOW, images_exception_value); + } + + // The app banner exception was not synced. + { + DictionaryPrefUpdate update( + &prefs, prefs::kContentSettingsAppBannerPatternPairs); + const base::DictionaryValue* app_banner_dictionary = update.Get(); + EXPECT_TRUE(app_banner_dictionary->empty()); + } + + // The plugins exception was synced, together with the resource identifiers. + { + DictionaryPrefUpdate update( + &prefs, prefs::kContentSettingsPluginsPatternPairs); + const base::DictionaryValue* plugins_dictionary = update.Get(); + EXPECT_EQ(1u, plugins_dictionary->size()); + + const base::DictionaryValue* plugins_exception; + EXPECT_TRUE(plugins_dictionary->GetDictionaryWithoutPathExpansion( + pattern, &plugins_exception)); + + int plugins_exception_value = CONTENT_SETTING_DEFAULT; + EXPECT_TRUE(plugins_exception->GetIntegerWithoutPathExpansion( + "setting", &plugins_exception_value)); + EXPECT_EQ(CONTENT_SETTING_ALLOW, plugins_exception_value); + + int resource_exception_value = CONTENT_SETTING_DEFAULT; + const base::DictionaryValue* resource_exception; + EXPECT_TRUE(plugins_exception->GetDictionaryWithoutPathExpansion( + "per_resource", &resource_exception)); + EXPECT_TRUE(resource_exception->GetIntegerWithoutPathExpansion( + resource_id, &resource_exception_value)); + EXPECT_EQ(CONTENT_SETTING_BLOCK, resource_exception_value); + } + + provider.ShutdownOnUIThread(); +} + +TEST(PrefProviderTest, SyncingNewToOld) { + TestingPrefServiceSyncable prefs; + PrefProvider::RegisterProfilePrefs(prefs.registry()); + PrefProvider provider(&prefs, false); + + const std::string pattern = "google.com,*"; + const std::string resource_id = "abcde12345"; + base::DictionaryValue block_exception; + block_exception.SetIntegerWithoutPathExpansion( + "setting", CONTENT_SETTING_BLOCK); + + // Add a mouselock exception. + { + DictionaryPrefUpdate update( + &prefs, prefs::kContentSettingsMouseLockPatternPairs); + base::DictionaryValue* mouselock_dictionary = update.Get(); + + mouselock_dictionary->SetWithoutPathExpansion( + pattern, block_exception.DeepCopy()); + } + + // Add a microphone exception. + { + DictionaryPrefUpdate update( + &prefs, prefs::kContentSettingsMediaStreamMicPatternPairs); + base::DictionaryValue* microphone_dictionary = update.Get(); + + microphone_dictionary->SetWithoutPathExpansion( + pattern, block_exception.DeepCopy()); + } + + // Add a plugin exception with resource identifiers. + { + DictionaryPrefUpdate update( + &prefs, prefs::kContentSettingsPluginsPatternPairs); + base::DictionaryValue* plugins_dictionary = update.Get(); + + base::DictionaryValue* plugin_exception = block_exception.DeepCopy(); + plugins_dictionary->SetWithoutPathExpansion( + pattern, plugin_exception); + + base::DictionaryValue* resource_exception = new base::DictionaryValue(); + resource_exception->SetIntegerWithoutPathExpansion( + resource_id, CONTENT_SETTING_ALLOW); + + plugin_exception->SetWithoutPathExpansion( + "per_resource", resource_exception); + } + + // Only the notifications and plugin exceptions should appear in the + // old dictionary. We should also have a resource identifiers section + // for plugins. + { + DictionaryPrefUpdate update( + &prefs, prefs::kContentSettingsPatternPairs); + const base::DictionaryValue* old_dictionary = update.Get(); + + const base::DictionaryValue* exception; + EXPECT_TRUE(old_dictionary->GetDictionaryWithoutPathExpansion( + pattern, &exception)); + EXPECT_EQ(3u, exception->size()); + EXPECT_FALSE(exception->HasKey( + GetTypeName(CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC))); + + int mouselock_exception_value = CONTENT_SETTING_DEFAULT; + exception->GetIntegerWithoutPathExpansion( + GetTypeName(CONTENT_SETTINGS_TYPE_MOUSELOCK), + &mouselock_exception_value); + DCHECK_EQ(CONTENT_SETTING_BLOCK, mouselock_exception_value); + + int plugins_exception_value = CONTENT_SETTING_DEFAULT; + exception->GetIntegerWithoutPathExpansion( + GetTypeName(CONTENT_SETTINGS_TYPE_PLUGINS), + &plugins_exception_value); + DCHECK_EQ(CONTENT_SETTING_BLOCK, plugins_exception_value); + + int resource_exception_value = CONTENT_SETTING_DEFAULT; + const base::DictionaryValue* resource_values; + exception->GetDictionaryWithoutPathExpansion( + "per_plugin", &resource_values); + resource_values->GetIntegerWithoutPathExpansion( + resource_id, &resource_exception_value); + DCHECK_EQ(CONTENT_SETTING_ALLOW, resource_exception_value); + } + + provider.ShutdownOnUIThread(); +} + +#if defined(OS_CHROMEOS) || defined(OS_ANDROID) +TEST(PrefProviderTest, PMIMigrateOnlyAllow) { + TestingPrefServiceSyncable prefs; + PrefProvider::RegisterProfilePrefs(prefs.registry()); + + const std::string pattern_1 = "google.com,*"; + const std::string pattern_2 = "www.google.com,*"; + base::DictionaryValue* exception_1 = new base::DictionaryValue(); + base::DictionaryValue* exception_2 = new base::DictionaryValue(); + + // Add both an "allow" and "block" exception for PMI. + exception_1->SetIntegerWithoutPathExpansion( + GetTypeName(CONTENT_SETTINGS_TYPE_PROTECTED_MEDIA_IDENTIFIER), + CONTENT_SETTING_ALLOW); + exception_2->SetIntegerWithoutPathExpansion( + GetTypeName(CONTENT_SETTINGS_TYPE_PROTECTED_MEDIA_IDENTIFIER), + CONTENT_SETTING_BLOCK); + + // Change the old dictionary preference. + { + DictionaryPrefUpdate update(&prefs, prefs::kContentSettingsPatternPairs); + base::DictionaryValue* old_dictionary = update.Get(); + old_dictionary->SetWithoutPathExpansion(pattern_1, exception_1); + old_dictionary->SetWithoutPathExpansion(pattern_2, exception_2); + } + + // Create the PrefProvider. It should migrate the settings. + PrefProvider provider(&prefs, false); + + // The "block" exception for PMI was migrated, but "allow" was not. + { + DictionaryPrefUpdate update( + &prefs, prefs::kContentSettingsProtectedMediaIdentifierPatternPairs); + const base::DictionaryValue* pmi_dictionary = update.Get(); + EXPECT_FALSE(pmi_dictionary->HasKey(pattern_1)); + EXPECT_TRUE(pmi_dictionary->HasKey(pattern_2)); + } + + provider.ShutdownOnUIThread(); +} +#endif + +TEST(PrefProviderTest, PrefsMigrateVerbatim) { + TestingPrefServiceSyncable prefs; + PrefProvider::RegisterProfilePrefs(prefs.registry()); + + const std::string pattern_1 = "google.com,*"; + const std::string pattern_2 = "www.google.com,*"; + base::DictionaryValue* exception_1 = new base::DictionaryValue(); + base::DictionaryValue* exception_2 = new base::DictionaryValue(); + scoped_ptr<base::DictionaryValue> old_dictionary; + + // Add two exceptions. + exception_1->SetIntegerWithoutPathExpansion( + GetTypeName(CONTENT_SETTINGS_TYPE_COOKIES), + CONTENT_SETTING_ALLOW); + exception_2->SetIntegerWithoutPathExpansion( + GetTypeName(CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS), + CONTENT_SETTING_BLOCK); + + // Change the old dictionary preference. + { + DictionaryPrefUpdate update(&prefs, prefs::kContentSettingsPatternPairs); + base::DictionaryValue* dictionary = update.Get(); + dictionary->SetWithoutPathExpansion(pattern_1, exception_1); + dictionary->SetWithoutPathExpansion(pattern_2, exception_2); + old_dictionary.reset(dictionary->DeepCopy()); + } + + // Create the PrefProvider. It should copy the settings from the old + // preference to the new ones. + PrefProvider provider(&prefs, false); + + // Force copying back from the new preferences to the old one. + { + DictionaryPrefUpdate update( + &prefs, prefs::kContentSettingsCookiesPatternPairs); + } + { + DictionaryPrefUpdate update( + &prefs, prefs::kContentSettingsAutomaticDownloadsPatternPairs); + } + + // Test if the value after copying there and back is the same. + { + DictionaryPrefUpdate update(&prefs, prefs::kContentSettingsPatternPairs); + base::DictionaryValue* new_dictionary = update.Get(); + EXPECT_TRUE(old_dictionary->Equals(new_dictionary)); + } + + provider.ShutdownOnUIThread(); +} + } // namespace content_settings diff --git a/chrome/browser/content_settings/host_content_settings_map_unittest.cc b/chrome/browser/content_settings/host_content_settings_map_unittest.cc index 001ca3b..75b1376 100644 --- a/chrome/browser/content_settings/host_content_settings_map_unittest.cc +++ b/chrome/browser/content_settings/host_content_settings_map_unittest.cc @@ -680,7 +680,8 @@ TEST_F(HostContentSettingsMapTest, CanonicalizeExceptionsUnicodeOnly) { // Set utf-8 data. { - DictionaryPrefUpdate update(prefs, prefs::kContentSettingsPatternPairs); + DictionaryPrefUpdate update( + prefs, prefs::kContentSettingsPatternPairs); base::DictionaryValue* all_settings_dictionary = update.Get(); ASSERT_TRUE(NULL != all_settings_dictionary); @@ -689,10 +690,11 @@ TEST_F(HostContentSettingsMapTest, CanonicalizeExceptionsUnicodeOnly) { all_settings_dictionary->SetWithoutPathExpansion("[*.]\xC4\x87ira.com,*", dummy_payload); } + profile.GetHostContentSettingsMap(); const base::DictionaryValue* all_settings_dictionary = - prefs->GetDictionary(prefs::kContentSettingsPatternPairs); + prefs->GetDictionary(prefs::kContentSettingsImagesPatternPairs); const base::DictionaryValue* result = NULL; EXPECT_FALSE(all_settings_dictionary->GetDictionaryWithoutPathExpansion( "[*.]\xC4\x87ira.com,*", &result)); @@ -706,22 +708,24 @@ TEST_F(HostContentSettingsMapTest, CanonicalizeExceptionsUnicodeAndPunycode) { TestingProfile profile; scoped_ptr<base::Value> value(base::JSONReader::Read( - "{\"[*.]\\xC4\\x87ira.com,*\":{\"images\":1}}")); - profile.GetPrefs()->Set(prefs::kContentSettingsPatternPairs, *value); + "{\"[*.]\\xC4\\x87ira.com,*\":{\"setting\":1}}")); + profile.GetPrefs()->Set(prefs::kContentSettingsImagesPatternPairs, *value); // Set punycode equivalent, with different setting. scoped_ptr<base::Value> puny_value(base::JSONReader::Read( - "{\"[*.]xn--ira-ppa.com,*\":{\"images\":2}}")); - profile.GetPrefs()->Set(prefs::kContentSettingsPatternPairs, *puny_value); + "{\"[*.]xn--ira-ppa.com,*\":{\"setting\":2}}")); + profile.GetPrefs()->Set( + prefs::kContentSettingsImagesPatternPairs, *puny_value); // Initialize the content map. profile.GetHostContentSettingsMap(); const base::DictionaryValue* content_setting_prefs = - profile.GetPrefs()->GetDictionary(prefs::kContentSettingsPatternPairs); + profile.GetPrefs()->GetDictionary( + prefs::kContentSettingsImagesPatternPairs); std::string prefs_as_json; base::JSONWriter::Write(content_setting_prefs, &prefs_as_json); - EXPECT_STREQ("{\"[*.]xn--ira-ppa.com,*\":{\"images\":2}}", + EXPECT_STREQ("{\"[*.]xn--ira-ppa.com,*\":{\"setting\":2}}", prefs_as_json.c_str()); } 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[]; |