// Copyright (c) 2011 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/content_settings_pref_provider.h"
#include <string>
#include <utility>
#include <vector>
#include "base/command_line.h"
#include "chrome/browser/content_settings/content_settings_details.h"
#include "chrome/browser/content_settings/content_settings_pattern.h"
#include "chrome/browser/metrics/user_metrics.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/prefs/scoped_user_pref_update.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/content_settings.h"
#include "chrome/common/pref_names.h"
#include "content/browser/browser_thread.h"
#include "content/common/notification_details.h"
#include "content/common/notification_service.h"
#include "content/common/notification_source.h"
#include "googleurl/src/gurl.h"
#include "net/base/net_util.h"
namespace {
// The preference keys where resource identifiers are stored for
// ContentSettingsType values that support resource identifiers.
const char* kResourceTypeNames[] = {
NULL,
NULL,
NULL,
"per_plugin",
NULL,
NULL, // Not used for Geolocation
NULL, // Not used for Notifications
NULL, // Not used for Prerender.
};
COMPILE_ASSERT(arraysize(kResourceTypeNames) == CONTENT_SETTINGS_NUM_TYPES,
resource_type_names_incorrect_size);
// The default setting for each content type.
const ContentSetting kDefaultSettings[] = {
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, // CONTENT_SETTINGS_TYPE_NOTIFICATIONS
CONTENT_SETTING_ALLOW, // CONTENT_SETTINGS_TYPE_PRERENDER
};
COMPILE_ASSERT(arraysize(kDefaultSettings) == CONTENT_SETTINGS_NUM_TYPES,
default_settings_incorrect_size);
// The names of the ContentSettingsType values, for use with dictionary prefs.
const char* kTypeNames[] = {
"cookies",
"images",
"javascript",
"plugins",
"popups",
NULL, // Not used for Geolocation
// TODO(markusheintz): Refactoring in progress. Content settings exceptions
// for notifications will be added next.
"notifications", // Only used for default Notifications settings.
NULL, // Not used for Prerender
};
COMPILE_ASSERT(arraysize(kTypeNames) == CONTENT_SETTINGS_NUM_TYPES,
type_names_incorrect_size);
void SetDefaultContentSettings(DictionaryValue* default_settings) {
default_settings->Clear();
for (int i = 0; i < CONTENT_SETTINGS_NUM_TYPES; ++i) {
if (kTypeNames[i] != NULL) {
default_settings->SetInteger(kTypeNames[i],
kDefaultSettings[i]);
}
}
}
} // namespace
namespace content_settings {
PrefDefaultProvider::PrefDefaultProvider(Profile* profile)
: profile_(profile),
is_incognito_(profile_->IsOffTheRecord()),
updating_preferences_(false) {
initializing_ = true;
PrefService* prefs = profile->GetPrefs();
MigrateObsoleteNotificationPref(prefs);
// Read global defaults.
DCHECK_EQ(arraysize(kTypeNames),
static_cast<size_t>(CONTENT_SETTINGS_NUM_TYPES));
ReadDefaultSettings(true);
if (default_content_settings_.settings[CONTENT_SETTINGS_TYPE_COOKIES] ==
CONTENT_SETTING_BLOCK) {
UserMetrics::RecordAction(
UserMetricsAction("CookieBlockingEnabledPerDefault"));
} else {
UserMetrics::RecordAction(
UserMetricsAction("CookieBlockingDisabledPerDefault"));
}
pref_change_registrar_.Init(prefs);
pref_change_registrar_.Add(prefs::kDefaultContentSettings, this);
notification_registrar_.Add(this, NotificationType::PROFILE_DESTROYED,
Source<Profile>(profile_));
initializing_ = false;
}
PrefDefaultProvider::~PrefDefaultProvider() {
UnregisterObservers();
}
ContentSetting PrefDefaultProvider::ProvideDefaultSetting(
ContentSettingsType content_type) const {
base::AutoLock lock(lock_);
return default_content_settings_.settings[content_type];
}
void PrefDefaultProvider::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_incognito_)
return;
PrefService* prefs = profile_->GetPrefs();
std::string dictionary_path(kTypeNames[content_type]);
updating_preferences_ = true;
{
base::AutoLock lock(lock_);
DictionaryPrefUpdate update(prefs, prefs::kDefaultContentSettings);
DictionaryValue* default_settings_dictionary = update.Get();
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 PrefDefaultProvider::DefaultSettingIsManaged(
ContentSettingsType content_type) const {
return false;
}
void PrefDefaultProvider::ResetToDefaults() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
base::AutoLock lock(lock_);
default_content_settings_ = ContentSettings();
ForceDefaultsToBeExplicit();
if (!is_incognito_) {
PrefService* prefs = profile_->GetPrefs();
updating_preferences_ = true;
prefs->ClearPref(prefs::kDefaultContentSettings);
updating_preferences_ = false;
}
}
void PrefDefaultProvider::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_incognito_) {
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 PrefDefaultProvider::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 PrefDefaultProvider::ReadDefaultSettings(bool overwrite) {
PrefService* prefs = profile_->GetPrefs();
const DictionaryValue* default_settings_dictionary =
prefs->GetDictionary(prefs::kDefaultContentSettings);
base::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 PrefDefaultProvider::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 PrefDefaultProvider::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] =
BaseProvider::ClickToPlayFixup(
CONTENT_SETTINGS_TYPE_PLUGINS,
settings->settings[CONTENT_SETTINGS_TYPE_PLUGINS]);
}
void PrefDefaultProvider::NotifyObservers(
const ContentSettingsDetails& details) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
if (initializing_ || profile_ == NULL)
return;
NotificationService::current()->Notify(
NotificationType::CONTENT_SETTINGS_CHANGED,
Source<HostContentSettingsMap>(profile_->GetHostContentSettingsMap()),
Details<const ContentSettingsDetails>(&details));
}
void PrefDefaultProvider::MigrateObsoleteNotificationPref(PrefService* prefs) {
if (prefs->HasPrefPath(prefs::kDesktopNotificationDefaultContentSetting)) {
ContentSetting setting = IntToContentSetting(
prefs->GetInteger(prefs::kDesktopNotificationDefaultContentSetting));
UpdateDefaultSetting(CONTENT_SETTINGS_TYPE_NOTIFICATIONS, setting);
prefs->ClearPref(prefs::kDesktopNotificationDefaultContentSetting);
}
}
// static
void PrefDefaultProvider::RegisterUserPrefs(PrefService* prefs) {
// The registration of the preference prefs::kDefaultContentSettings should
// also include the default values for default content settings. This allows
// functional tests to get default content settings by reading the preference
// prefs::kDefaultContentSettings via pyauto.
// TODO(markusheintz): Write pyauto hooks for the content settings map as
// content settings should be read from the host content settings map.
DictionaryValue* default_content_settings = new DictionaryValue();
SetDefaultContentSettings(default_content_settings);
prefs->RegisterDictionaryPref(prefs::kDefaultContentSettings,
default_content_settings);
// Obsolete prefs, for migrations:
prefs->RegisterIntegerPref(
prefs::kDesktopNotificationDefaultContentSetting,
kDefaultSettings[CONTENT_SETTINGS_TYPE_NOTIFICATIONS]);
}
// ////////////////////////////////////////////////////////////////////////////
// PrefProvider:
//
// static
void PrefProvider::RegisterUserPrefs(PrefService* prefs) {
prefs->RegisterIntegerPref(prefs::kContentSettingsVersion,
ContentSettingsPattern::kContentSettingsPatternVersion);
prefs->RegisterDictionaryPref(prefs::kContentSettingsPatterns);
// Obsolete prefs, for migration:
prefs->RegisterListPref(prefs::kPopupWhitelistedHosts);
prefs->RegisterDictionaryPref(prefs::kPerHostContentSettings);
}
PrefProvider::PrefProvider(Profile* profile)
: BaseProvider(profile->IsOffTheRecord()),
profile_(profile),
updating_preferences_(false) {
Init();
}
void PrefProvider::Init() {
initializing_ = true;
PrefService* prefs = profile_->GetPrefs();
// Migrate obsolete preferences.
MigrateObsoletePerhostPref(prefs);
MigrateObsoletePopupsPref(prefs);
// Verify preferences version.
if (!prefs->HasPrefPath(prefs::kContentSettingsVersion)) {
prefs->SetInteger(prefs::kContentSettingsVersion,
ContentSettingsPattern::kContentSettingsPatternVersion);
}
if (prefs->GetInteger(prefs::kContentSettingsVersion) >
ContentSettingsPattern::kContentSettingsPatternVersion) {
LOG(ERROR) << "Unknown content settings version in preferences.";
return;
}
// Read exceptions.
ReadExceptions(false);
pref_change_registrar_.Init(prefs);
pref_change_registrar_.Add(prefs::kContentSettingsPatterns, this);
notification_registrar_.Add(this, NotificationType::PROFILE_DESTROYED,
Source<Profile>(profile_));
initializing_ = false;
}
bool PrefProvider::ContentSettingsTypeIsManaged(
ContentSettingsType content_type) {
return false;
}
void PrefProvider::SetContentSetting(
const ContentSettingsPattern& requesting_pattern,
const ContentSettingsPattern& embedding_pattern,
ContentSettingsType content_type,
const ResourceIdentifier& resource_identifier,
ContentSetting setting) {
// Support for embedding_patterns is not implemented yet.
DCHECK(requesting_pattern == embedding_pattern);
DCHECK(kTypeNames[content_type] != NULL); // Don't call this for Geolocation.
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
DCHECK_NE(RequiresResourceIdentifier(content_type),
resource_identifier.empty());
DCHECK(content_type != CONTENT_SETTINGS_TYPE_PLUGINS ||
setting != CONTENT_SETTING_ASK ||
CommandLine::ForCurrentProcess()->HasSwitch(
switches::kEnableClickToPlay));
const ContentSettingsPattern pattern(
requesting_pattern.CanonicalizePattern());
bool early_exit = false;
std::string pattern_str(pattern.AsString());
DictionaryValue* all_settings_dictionary = NULL;
updating_preferences_ = true;
{ // Begin scope of update.
// profile_ may be NULL in unit tests.
DictionaryPrefUpdate update(profile_ ? profile_->GetPrefs() : NULL,
prefs::kContentSettingsPatterns);
// Select content-settings-map to write to.
HostContentSettings* map_to_modify = incognito_settings();
if (!is_incognito()) {
all_settings_dictionary = update.Get();
map_to_modify = host_content_settings();
}
// Update content-settings-map.
{
base::AutoLock auto_lock(lock());
if (!map_to_modify->count(pattern_str))
(*map_to_modify)[pattern_str].content_settings = ContentSettings();
HostContentSettings::iterator i(map_to_modify->find(pattern_str));
ContentSettings& settings = i->second.content_settings;
if (RequiresResourceIdentifier(content_type)) {
settings.settings[content_type] = CONTENT_SETTING_DEFAULT;
if (setting != CONTENT_SETTING_DEFAULT) {
i->second.content_settings_for_resources[
ContentSettingsTypeResourceIdentifierPair(content_type,
resource_identifier)] = setting;
} else {
i->second.content_settings_for_resources.erase(
ContentSettingsTypeResourceIdentifierPair(content_type,
resource_identifier));
}
} else {
settings.settings[content_type] = setting;
}
if (AllDefault(i->second)) {
map_to_modify->erase(i);
if (all_settings_dictionary)
all_settings_dictionary->RemoveWithoutPathExpansion(
pattern_str, NULL);
// We can't just return because |NotifyObservers()| needs to be called,
// without lock() being held.
early_exit = true;
}
}
// Update the content_settings preference.
if (!early_exit && all_settings_dictionary) {
DictionaryValue* host_settings_dictionary = NULL;
bool found = all_settings_dictionary->GetDictionaryWithoutPathExpansion(
pattern_str, &host_settings_dictionary);
if (!found) {
host_settings_dictionary = new DictionaryValue;
all_settings_dictionary->SetWithoutPathExpansion(
pattern_str, host_settings_dictionary);
DCHECK_NE(setting, CONTENT_SETTING_DEFAULT);
}
if (RequiresResourceIdentifier(content_type)) {
std::string dictionary_path(kResourceTypeNames[content_type]);
DictionaryValue* resource_dictionary = NULL;
found = host_settings_dictionary->GetDictionary(
dictionary_path, &resource_dictionary);
if (!found) {
resource_dictionary = new DictionaryValue;
host_settings_dictionary->Set(dictionary_path, resource_dictionary);
}
if (setting == CONTENT_SETTING_DEFAULT) {
resource_dictionary->RemoveWithoutPathExpansion(resource_identifier,
NULL);
} else {
resource_dictionary->SetWithoutPathExpansion(
resource_identifier, Value::CreateIntegerValue(setting));
}
} else {
std::string dictionary_path(kTypeNames[content_type]);
if (setting == CONTENT_SETTING_DEFAULT) {
host_settings_dictionary->RemoveWithoutPathExpansion(dictionary_path,
NULL);
} else {
host_settings_dictionary->SetWithoutPathExpansion(
dictionary_path, Value::CreateIntegerValue(setting));
}
}
}
} // End scope of update.
updating_preferences_ = false;
NotifyObservers(ContentSettingsDetails(pattern, content_type, ""));
}
void PrefProvider::ResetToDefaults() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
{
base::AutoLock auto_lock(lock());
host_content_settings()->clear();
incognito_settings()->clear();
}
if (!is_incognito()) {
PrefService* prefs = profile_->GetPrefs();
updating_preferences_ = true;
prefs->ClearPref(prefs::kContentSettingsPatterns);
updating_preferences_ = false;
}
}
void PrefProvider::ClearAllContentSettingsRules(
ContentSettingsType content_type) {
DCHECK(kTypeNames[content_type] != NULL); // Don't call this for Geolocation.
DictionaryValue* all_settings_dictionary = NULL;
HostContentSettings* map_to_modify = incognito_settings();
updating_preferences_ = true;
{ // Begin scope of update.
DictionaryPrefUpdate update(profile_->GetPrefs(),
prefs::kContentSettingsPatterns);
if (!is_incognito()) {
all_settings_dictionary = update.Get();
map_to_modify = host_content_settings();
}
{
base::AutoLock auto_lock(lock());
for (HostContentSettings::iterator i(map_to_modify->begin());
i != map_to_modify->end(); ) {
if (RequiresResourceIdentifier(content_type) ||
i->second.content_settings.settings[content_type] !=
CONTENT_SETTING_DEFAULT) {
if (RequiresResourceIdentifier(content_type))
i->second.content_settings_for_resources.clear();
i->second.content_settings.settings[content_type] =
CONTENT_SETTING_DEFAULT;
std::string host(i->first);
if (AllDefault(i->second)) {
if (all_settings_dictionary)
all_settings_dictionary->RemoveWithoutPathExpansion(host, NULL);
map_to_modify->erase(i++);
} else if (all_settings_dictionary) {
DictionaryValue* host_settings_dictionary;
bool found =
all_settings_dictionary->GetDictionaryWithoutPathExpansion(
host, &host_settings_dictionary);
DCHECK(found);
host_settings_dictionary->RemoveWithoutPathExpansion(
kTypeNames[content_type], NULL);
++i;
}
} else {
++i;
}
}
}
} // End scope of update.
updating_preferences_ = false;
NotifyObservers(
ContentSettingsDetails(ContentSettingsPattern(), content_type, ""));
}
void PrefProvider::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::kContentSettingsPatterns) {
ReadExceptions(true);
} else {
NOTREACHED() << "Unexpected preference observed";
return;
}
if (!is_incognito()) {
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";
}
}
PrefProvider::~PrefProvider() {
UnregisterObservers();
}
// ////////////////////////////////////////////////////////////////////////////
// Private
void PrefProvider::ReadExceptions(bool overwrite) {
base::AutoLock auto_lock(lock());
PrefService* prefs = profile_->GetPrefs();
const DictionaryValue* all_settings_dictionary =
prefs->GetDictionary(prefs::kContentSettingsPatterns);
if (overwrite)
host_content_settings()->clear();
updating_preferences_ = true;
// Careful: The returned value could be NULL if the pref has never been set.
if (all_settings_dictionary != NULL) {
DictionaryPrefUpdate update(prefs, prefs::kContentSettingsPatterns);
DictionaryValue* mutable_settings;
scoped_ptr<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.
CanonicalizeContentSettingsExceptions(mutable_settings);
for (DictionaryValue::key_iterator i(mutable_settings->begin_keys());
i != mutable_settings->end_keys(); ++i) {
const std::string& pattern(*i);
if (!ContentSettingsPattern(pattern).IsValid())
LOG(WARNING) << "Invalid pattern stored in content settings";
DictionaryValue* pattern_settings_dictionary = NULL;
bool found = mutable_settings->GetDictionaryWithoutPathExpansion(
pattern, &pattern_settings_dictionary);
DCHECK(found);
ExtendedContentSettings extended_settings;
GetSettingsFromDictionary(pattern_settings_dictionary,
&extended_settings.content_settings);
GetResourceSettingsFromDictionary(
pattern_settings_dictionary,
&extended_settings.content_settings_for_resources);
(*host_content_settings())[pattern] = extended_settings;
}
}
updating_preferences_ = false;
}
void PrefProvider::CanonicalizeContentSettingsExceptions(
DictionaryValue* all_settings_dictionary) {
DCHECK(all_settings_dictionary);
std::vector<std::string> remove_items;
std::vector<std::pair<std::string, std::string> > move_items;
for (DictionaryValue::key_iterator i(all_settings_dictionary->begin_keys());
i != all_settings_dictionary->end_keys(); ++i) {
const std::string& pattern(*i);
const std::string canonicalized_pattern =
ContentSettingsPattern(pattern).CanonicalizePattern();
if (canonicalized_pattern.empty() || canonicalized_pattern == pattern)
continue;
// Clear old pattern if prefs already have canonicalized pattern.
DictionaryValue* new_pattern_settings_dictionary = NULL;
if (all_settings_dictionary->GetDictionaryWithoutPathExpansion(
canonicalized_pattern, &new_pattern_settings_dictionary)) {
remove_items.push_back(pattern);
continue;
}
// Move old pattern to canonicalized pattern.
DictionaryValue* old_pattern_settings_dictionary = NULL;
if (all_settings_dictionary->GetDictionaryWithoutPathExpansion(
pattern, &old_pattern_settings_dictionary)) {
move_items.push_back(std::make_pair(pattern, canonicalized_pattern));
}
}
for (size_t i = 0; i < remove_items.size(); ++i) {
all_settings_dictionary->RemoveWithoutPathExpansion(remove_items[i], NULL);
}
for (size_t i = 0; i < move_items.size(); ++i) {
Value* pattern_settings_dictionary = NULL;
all_settings_dictionary->RemoveWithoutPathExpansion(
move_items[i].first, &pattern_settings_dictionary);
all_settings_dictionary->SetWithoutPathExpansion(
move_items[i].second, pattern_settings_dictionary);
}
}
void PrefProvider::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 PrefProvider::GetResourceSettingsFromDictionary(
const DictionaryValue* dictionary,
ResourceContentSettings* 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(kResourceTypeNames); ++type) {
if ((kResourceTypeNames[type] != NULL) &&
(kResourceTypeNames[type] == content_type)) {
DictionaryValue* resource_dictionary = NULL;
bool found = dictionary->GetDictionary(content_type,
&resource_dictionary);
DCHECK(found);
for (DictionaryValue::key_iterator j(resource_dictionary->begin_keys());
j != resource_dictionary->end_keys(); ++j) {
const std::string& resource_identifier(*j);
int setting = CONTENT_SETTING_DEFAULT;
bool found = resource_dictionary->GetIntegerWithoutPathExpansion(
resource_identifier, &setting);
DCHECK(found);
(*settings)[ContentSettingsTypeResourceIdentifierPair(
ContentSettingsType(type), resource_identifier)] =
ClickToPlayFixup(ContentSettingsType(type),
ContentSetting(setting));
}
break;
}
}
}
}
void PrefProvider::NotifyObservers(
const ContentSettingsDetails& details) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
if (initializing_ || profile_ == NULL)
return;
NotificationService::current()->Notify(
NotificationType::CONTENT_SETTINGS_CHANGED,
Source<HostContentSettingsMap>(
profile_->GetHostContentSettingsMap()),
Details<const ContentSettingsDetails>(&details));
}
void PrefProvider::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 PrefProvider::MigrateObsoletePerhostPref(PrefService* prefs) {
if (prefs->HasPrefPath(prefs::kPerHostContentSettings)) {
const DictionaryValue* all_settings_dictionary =
prefs->GetDictionary(prefs::kPerHostContentSettings);
DCHECK(all_settings_dictionary);
for (DictionaryValue::key_iterator
i(all_settings_dictionary->begin_keys());
i != all_settings_dictionary->end_keys(); ++i) {
const std::string& host(*i);
ContentSettingsPattern pattern(
std::string(ContentSettingsPattern::kDomainWildcard) + host);
DictionaryValue* host_settings_dictionary = NULL;
bool found = all_settings_dictionary->GetDictionaryWithoutPathExpansion(
host, &host_settings_dictionary);
DCHECK(found);
ContentSettings settings;
GetSettingsFromDictionary(host_settings_dictionary, &settings);
for (int j = 0; j < CONTENT_SETTINGS_NUM_TYPES; ++j) {
if (settings.settings[j] != CONTENT_SETTING_DEFAULT &&
!RequiresResourceIdentifier(ContentSettingsType(j))) {
SetContentSetting(
pattern,
pattern,
ContentSettingsType(j),
"",
settings.settings[j]);
}
}
}
prefs->ClearPref(prefs::kPerHostContentSettings);
}
}
void PrefProvider::MigrateObsoletePopupsPref(PrefService* prefs) {
if (prefs->HasPrefPath(prefs::kPopupWhitelistedHosts)) {
const ListValue* whitelist_pref =
prefs->GetList(prefs::kPopupWhitelistedHosts);
for (ListValue::const_iterator i(whitelist_pref->begin());
i != whitelist_pref->end(); ++i) {
std::string host;
(*i)->GetAsString(&host);
SetContentSetting(ContentSettingsPattern(host),
ContentSettingsPattern(host),
CONTENT_SETTINGS_TYPE_POPUPS,
"",
CONTENT_SETTING_ALLOW);
}
prefs->ClearPref(prefs::kPopupWhitelistedHosts);
}
}
} // namespace content_settings