Index: chrome/browser/content_settings/pref_content_settings_provider.cc |
diff --git a/chrome/browser/content_settings/pref_content_settings_provider.cc b/chrome/browser/content_settings/pref_content_settings_provider.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..01ac0552448a89653290b4fa0997ebee5a35e041 |
--- /dev/null |
+++ b/chrome/browser/content_settings/pref_content_settings_provider.cc |
@@ -0,0 +1,263 @@ |
+// Copyright (c) 2010 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "chrome/browser/content_settings/pref_content_settings_provider.h" |
+ |
+#include "base/command_line.h" |
+#include "chrome/browser/browser_thread.h" |
+#include "chrome/browser/content_settings/content_settings_details.h" |
+#include "chrome/browser/content_settings/content_settings_pattern.h" |
+#include "chrome/browser/prefs/pref_service.h" |
+#include "chrome/browser/prefs/scoped_pref_update.h" |
+#include "chrome/browser/profiles/profile.h" |
+#include "chrome/common/chrome_switches.h" |
+#include "chrome/common/notification_details.h" |
+#include "chrome/common/notification_service.h" |
+#include "chrome/common/notification_source.h" |
+#include "chrome/common/pref_names.h" |
+ |
+namespace { |
+ |
+// The default setting for each content type. |
+const ContentSetting kDefaultSettings[CONTENT_SETTINGS_NUM_TYPES] = { |
+ CONTENT_SETTING_ALLOW, // CONTENT_SETTINGS_TYPE_COOKIES |
+ CONTENT_SETTING_ALLOW, // CONTENT_SETTINGS_TYPE_IMAGES |
+ CONTENT_SETTING_ALLOW, // CONTENT_SETTINGS_TYPE_JAVASCRIPT |
+ CONTENT_SETTING_ALLOW, // CONTENT_SETTINGS_TYPE_PLUGINS |
+ CONTENT_SETTING_BLOCK, // CONTENT_SETTINGS_TYPE_POPUPS |
+ CONTENT_SETTING_ASK, // Not used for Geolocation |
+ CONTENT_SETTING_ASK, // Not used for Notifications |
+}; |
+ |
+// The names of the ContentSettingsType values, for use with dictionary prefs. |
+const char* kTypeNames[CONTENT_SETTINGS_NUM_TYPES] = { |
+ "cookies", |
+ "images", |
+ "javascript", |
+ "plugins", |
+ "popups", |
+ NULL, // Not used for Geolocation |
+ NULL, // Not used for Notifications |
+}; |
+ |
+ |
+// Map ASK for the plugins content type to BLOCK if click-to-play is |
+// not enabled. |
+ContentSetting ClickToPlayFixup(ContentSettingsType content_type, |
+ ContentSetting setting) { |
+ if (setting == CONTENT_SETTING_ASK && |
+ content_type == CONTENT_SETTINGS_TYPE_PLUGINS && |
+ !CommandLine::ForCurrentProcess()->HasSwitch( |
+ switches::kEnableClickToPlay)) { |
+ return CONTENT_SETTING_BLOCK; |
+ } |
+ return setting; |
+} |
+ |
+} // namespace |
+ |
+PrefContentSettingsProvider::PrefContentSettingsProvider(Profile* profile) |
+ : profile_(profile), |
+ is_off_the_record_(profile_->IsOffTheRecord()), |
+ updating_preferences_(false) { |
+ PrefService* prefs = profile->GetPrefs(); |
+ |
+ // Read global defaults. |
+ DCHECK_EQ(arraysize(kTypeNames), |
+ static_cast<size_t>(CONTENT_SETTINGS_NUM_TYPES)); |
+ ReadDefaultSettings(true); |
+ |
+ pref_change_registrar_.Init(prefs); |
+ pref_change_registrar_.Add(prefs::kDefaultContentSettings, this); |
+ notification_registrar_.Add(this, NotificationType::PROFILE_DESTROYED, |
+ Source<Profile>(profile_)); |
+} |
+ |
+PrefContentSettingsProvider::~PrefContentSettingsProvider() { |
+ UnregisterObservers(); |
+} |
+ |
+bool PrefContentSettingsProvider::CanProvideDefaultSetting( |
+ ContentSettingsType content_type) const { |
+ return true; |
+} |
+ |
+ContentSetting PrefContentSettingsProvider::ProvideDefaultSetting( |
+ ContentSettingsType content_type) const { |
+ AutoLock lock(lock_); |
+ return default_content_settings_.settings[content_type]; |
+} |
+ |
+void PrefContentSettingsProvider::UpdateDefaultSetting( |
+ ContentSettingsType content_type, |
+ ContentSetting setting) { |
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
+ DCHECK(kTypeNames[content_type] != NULL); // Don't call this for Geolocation. |
+ DCHECK(content_type != CONTENT_SETTINGS_TYPE_PLUGINS || |
+ setting != CONTENT_SETTING_ASK || |
+ CommandLine::ForCurrentProcess()->HasSwitch( |
+ switches::kEnableClickToPlay)); |
+ |
+ // The default settings may not be directly modified for OTR sessions. |
+ // Instead, they are synced to the main profile's setting. |
+ if (is_off_the_record_) |
+ return; |
+ |
+ PrefService* prefs = profile_->GetPrefs(); |
+ |
+ DictionaryValue* default_settings_dictionary = |
+ prefs->GetMutableDictionary(prefs::kDefaultContentSettings); |
+ std::string dictionary_path(kTypeNames[content_type]); |
+ updating_preferences_ = true; |
+ { |
+ AutoLock lock(lock_); |
+ ScopedPrefUpdate update(prefs, prefs::kDefaultContentSettings); |
+ if ((setting == CONTENT_SETTING_DEFAULT) || |
+ (setting == kDefaultSettings[content_type])) { |
+ default_content_settings_.settings[content_type] = |
+ kDefaultSettings[content_type]; |
+ default_settings_dictionary->RemoveWithoutPathExpansion(dictionary_path, |
+ NULL); |
+ } else { |
+ default_content_settings_.settings[content_type] = setting; |
+ default_settings_dictionary->SetWithoutPathExpansion( |
+ dictionary_path, Value::CreateIntegerValue(setting)); |
+ } |
+ } |
+ updating_preferences_ = false; |
+ |
+ NotifyObservers( |
+ ContentSettingsDetails(ContentSettingsPattern(), content_type, "")); |
+} |
+ |
+bool PrefContentSettingsProvider::DefaultSettingIsManaged( |
+ ContentSettingsType content_type) const { |
+ return false; |
+} |
+ |
+void PrefContentSettingsProvider::ResetToDefaults() { |
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
+ AutoLock lock(lock_); |
+ default_content_settings_ = ContentSettings(); |
+ ForceDefaultsToBeExplicit(); |
+ |
+ if (!is_off_the_record_) { |
+ PrefService* prefs = profile_->GetPrefs(); |
+ updating_preferences_ = true; |
+ prefs->ClearPref(prefs::kDefaultContentSettings); |
+ updating_preferences_ = false; |
+ } |
+} |
+ |
+void PrefContentSettingsProvider::Observe(NotificationType type, |
+ const NotificationSource& source, |
+ const NotificationDetails& details) { |
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
+ |
+ if (type == NotificationType::PREF_CHANGED) { |
+ DCHECK_EQ(profile_->GetPrefs(), Source<PrefService>(source).ptr()); |
+ if (updating_preferences_) |
+ return; |
+ |
+ std::string* name = Details<std::string>(details).ptr(); |
+ if (*name == prefs::kDefaultContentSettings) { |
+ ReadDefaultSettings(true); |
+ } else { |
+ NOTREACHED() << "Unexpected preference observed"; |
+ return; |
+ } |
+ |
+ if (!is_off_the_record_) { |
+ NotifyObservers(ContentSettingsDetails( |
+ ContentSettingsPattern(), CONTENT_SETTINGS_TYPE_DEFAULT, "")); |
+ } |
+ } else if (type == NotificationType::PROFILE_DESTROYED) { |
+ DCHECK_EQ(profile_, Source<Profile>(source).ptr()); |
+ UnregisterObservers(); |
+ } else { |
+ NOTREACHED() << "Unexpected notification"; |
+ } |
+} |
+ |
+void PrefContentSettingsProvider::UnregisterObservers() { |
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
+ if (!profile_) |
+ return; |
+ pref_change_registrar_.RemoveAll(); |
+ notification_registrar_.Remove(this, NotificationType::PROFILE_DESTROYED, |
+ Source<Profile>(profile_)); |
+ profile_ = NULL; |
+} |
+ |
+void PrefContentSettingsProvider::ReadDefaultSettings(bool overwrite) { |
+ PrefService* prefs = profile_->GetPrefs(); |
+ const DictionaryValue* default_settings_dictionary = |
+ prefs->GetDictionary(prefs::kDefaultContentSettings); |
+ |
+ AutoLock lock(lock_); |
+ |
+ if (overwrite) |
+ default_content_settings_ = ContentSettings(); |
+ |
+ // Careful: The returned value could be NULL if the pref has never been set. |
+ if (default_settings_dictionary != NULL) { |
+ GetSettingsFromDictionary(default_settings_dictionary, |
+ &default_content_settings_); |
+ } |
+ ForceDefaultsToBeExplicit(); |
+} |
+ |
+void PrefContentSettingsProvider::ForceDefaultsToBeExplicit() { |
+ DCHECK_EQ(arraysize(kDefaultSettings), |
+ static_cast<size_t>(CONTENT_SETTINGS_NUM_TYPES)); |
+ |
+ for (int i = 0; i < CONTENT_SETTINGS_NUM_TYPES; ++i) { |
+ if (default_content_settings_.settings[i] == CONTENT_SETTING_DEFAULT) |
+ default_content_settings_.settings[i] = kDefaultSettings[i]; |
+ } |
+} |
+ |
+void PrefContentSettingsProvider::GetSettingsFromDictionary( |
+ const DictionaryValue* dictionary, |
+ ContentSettings* settings) { |
+ for (DictionaryValue::key_iterator i(dictionary->begin_keys()); |
+ i != dictionary->end_keys(); ++i) { |
+ const std::string& content_type(*i); |
+ for (size_t type = 0; type < arraysize(kTypeNames); ++type) { |
+ if ((kTypeNames[type] != NULL) && (kTypeNames[type] == content_type)) { |
+ int setting = CONTENT_SETTING_DEFAULT; |
+ bool found = dictionary->GetIntegerWithoutPathExpansion(content_type, |
+ &setting); |
+ DCHECK(found); |
+ settings->settings[type] = IntToContentSetting(setting); |
+ break; |
+ } |
+ } |
+ } |
+ // Migrate obsolete cookie prompt mode. |
+ if (settings->settings[CONTENT_SETTINGS_TYPE_COOKIES] == |
+ CONTENT_SETTING_ASK) |
+ settings->settings[CONTENT_SETTINGS_TYPE_COOKIES] = CONTENT_SETTING_BLOCK; |
+ |
+ settings->settings[CONTENT_SETTINGS_TYPE_PLUGINS] = |
+ ClickToPlayFixup(CONTENT_SETTINGS_TYPE_PLUGINS, |
+ settings->settings[CONTENT_SETTINGS_TYPE_PLUGINS]); |
+} |
+ |
+void PrefContentSettingsProvider::NotifyObservers( |
+ const ContentSettingsDetails& details) { |
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
+ if (profile_ == NULL) |
+ return; |
+ NotificationService::current()->Notify( |
+ NotificationType::CONTENT_SETTINGS_CHANGED, |
+ Source<HostContentSettingsMap>(profile_->GetHostContentSettingsMap()), |
+ Details<const ContentSettingsDetails>(&details)); |
+} |
+ |
+ |
+// static |
+void PrefContentSettingsProvider::RegisterUserPrefs(PrefService* prefs) { |
+ prefs->RegisterDictionaryPref(prefs::kDefaultContentSettings); |
+} |