summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/host_content_settings_map.cc150
-rw-r--r--chrome/browser/host_content_settings_map.h31
2 files changed, 146 insertions, 35 deletions
diff --git a/chrome/browser/host_content_settings_map.cc b/chrome/browser/host_content_settings_map.cc
index 378dfad..dfcdfad 100644
--- a/chrome/browser/host_content_settings_map.cc
+++ b/chrome/browser/host_content_settings_map.cc
@@ -9,6 +9,7 @@
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/pref_service.h"
#include "chrome/browser/profile.h"
+#include "chrome/browser/scoped_pref_update.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/notification_type.h"
#include "chrome/common/pref_names.h"
@@ -103,7 +104,8 @@ const ContentSetting
HostContentSettingsMap::HostContentSettingsMap(Profile* profile)
: profile_(profile),
block_third_party_cookies_(false),
- is_off_the_record_(profile_->IsOffTheRecord()) {
+ is_off_the_record_(profile_->IsOffTheRecord()),
+ updating_preferences_(false) {
PrefService* prefs = profile_->GetPrefs();
// Migrate obsolete cookie pref.
@@ -161,14 +163,7 @@ HostContentSettingsMap::HostContentSettingsMap(Profile* profile)
// Read global defaults.
DCHECK_EQ(arraysize(kTypeNames),
static_cast<size_t>(CONTENT_SETTINGS_NUM_TYPES));
- const DictionaryValue* default_settings_dictionary =
- prefs->GetDictionary(prefs::kDefaultContentSettings);
- // 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();
+ ReadDefaultSettings(false);
// Read misc. global settings.
block_third_party_cookies_ =
@@ -186,24 +181,15 @@ HostContentSettingsMap::HostContentSettingsMap(Profile* profile)
}
// Read exceptions.
- const DictionaryValue* all_settings_dictionary =
- prefs->GetMutableDictionary(prefs::kContentSettingsPatterns);
- // Careful: The returned value could be NULL if the pref has never been set.
- if (all_settings_dictionary != NULL) {
- for (DictionaryValue::key_iterator i(all_settings_dictionary->begin_keys());
- i != all_settings_dictionary->end_keys(); ++i) {
- std::wstring wide_pattern(*i);
- if (!Pattern(WideToUTF8(wide_pattern)).IsValid())
- LOG(WARNING) << "Invalid pattern stored in content settings";
- DictionaryValue* pattern_settings_dictionary = NULL;
- bool found = all_settings_dictionary->GetDictionaryWithoutPathExpansion(
- wide_pattern, &pattern_settings_dictionary);
- DCHECK(found);
- ContentSettings settings;
- GetSettingsFromDictionary(pattern_settings_dictionary, &settings);
- host_content_settings_[WideToUTF8(wide_pattern)] = settings;
- }
+ ReadExceptions(false);
+
+ if (!is_off_the_record_) {
+ prefs->AddPrefObserver(prefs::kDefaultContentSettings, this);
+ prefs->AddPrefObserver(prefs::kContentSettingsPatterns, this);
+ prefs->AddPrefObserver(prefs::kBlockThirdPartyCookies, this);
}
+ notification_registrar_.Add(this, NotificationType::PROFILE_DESTROYED,
+ NotificationService::AllSources());
}
// static
@@ -296,6 +282,7 @@ void HostContentSettingsMap::SetDefaultContentSetting(
ContentSetting setting) {
DCHECK(kTypeNames[content_type] != NULL); // Don't call this for Geolocation.
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
+ PrefService* prefs = profile_->GetPrefs();
// Settings may not be modified for OTR sessions.
if (is_off_the_record_) {
@@ -304,11 +291,12 @@ void HostContentSettingsMap::SetDefaultContentSetting(
}
DictionaryValue* default_settings_dictionary =
- profile_->GetPrefs()->GetMutableDictionary(
- prefs::kDefaultContentSettings);
+ prefs->GetMutableDictionary(prefs::kDefaultContentSettings);
std::wstring dictionary_path(kTypeNames[content_type]);
+ updating_preferences_ = true;
{
AutoLock auto_lock(lock_);
+ ScopedPrefUpdate update(prefs, prefs::kDefaultContentSettings);
if ((setting == CONTENT_SETTING_DEFAULT) ||
(setting == kDefaultSettings[content_type])) {
default_content_settings_.settings[content_type] =
@@ -321,6 +309,7 @@ void HostContentSettingsMap::SetDefaultContentSetting(
dictionary_path, Value::CreateIntegerValue(setting));
}
}
+ updating_preferences_ = false;
NotifyObservers(ContentSettingsDetails(true));
}
@@ -330,6 +319,7 @@ void HostContentSettingsMap::SetContentSetting(const Pattern& pattern,
ContentSetting setting) {
DCHECK(kTypeNames[content_type] != NULL); // Don't call this for Geolocation.
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
+ PrefService* prefs = profile_->GetPrefs();
// Settings may not be modified for OTR sessions.
if (is_off_the_record_) {
@@ -340,8 +330,7 @@ void HostContentSettingsMap::SetContentSetting(const Pattern& pattern,
bool early_exit = false;
std::wstring wide_pattern(UTF8ToWide(pattern.AsString()));
DictionaryValue* all_settings_dictionary =
- profile_->GetPrefs()->GetMutableDictionary(
- prefs::kContentSettingsPatterns);
+ prefs->GetMutableDictionary(prefs::kContentSettingsPatterns);
{
AutoLock auto_lock(lock_);
if (!host_content_settings_.count(pattern.AsString()))
@@ -380,6 +369,12 @@ void HostContentSettingsMap::SetContentSetting(const Pattern& pattern,
}
}
+ updating_preferences_ = true;
+ {
+ ScopedPrefUpdate update(prefs, prefs::kContentSettingsPatterns);
+ }
+ updating_preferences_ = false;
+
NotifyObservers(ContentSettingsDetails(pattern));
}
@@ -393,16 +388,18 @@ void HostContentSettingsMap::ClearSettingsForOneType(
return;
}
+ PrefService* prefs = profile_->GetPrefs();
+ updating_preferences_ = true;
{
AutoLock auto_lock(lock_);
+ ScopedPrefUpdate update(prefs, prefs::kContentSettingsPatterns);
for (HostContentSettings::iterator i(host_content_settings_.begin());
i != host_content_settings_.end(); ) {
if (i->second.settings[content_type] != CONTENT_SETTING_DEFAULT) {
i->second.settings[content_type] = CONTENT_SETTING_DEFAULT;
std::wstring wide_host(UTF8ToWide(i->first));
DictionaryValue* all_settings_dictionary =
- profile_->GetPrefs()->GetMutableDictionary(
- prefs::kContentSettingsPatterns);
+ prefs->GetMutableDictionary(prefs::kContentSettingsPatterns);
if (AllDefault(i->second)) {
all_settings_dictionary->RemoveWithoutPathExpansion(wide_host, NULL);
host_content_settings_.erase(i++);
@@ -421,6 +418,7 @@ void HostContentSettingsMap::ClearSettingsForOneType(
}
}
}
+ updating_preferences_ = false;
NotifyObservers(ContentSettingsDetails(true));
}
@@ -458,9 +456,11 @@ void HostContentSettingsMap::ResetToDefaults() {
}
PrefService* prefs = profile_->GetPrefs();
+ updating_preferences_ = true;
prefs->ClearPref(prefs::kDefaultContentSettings);
prefs->ClearPref(prefs::kContentSettingsPatterns);
prefs->ClearPref(prefs::kBlockThirdPartyCookies);
+ updating_preferences_ = false;
NotifyObservers(ContentSettingsDetails(true));
}
@@ -469,7 +469,40 @@ bool HostContentSettingsMap::IsOffTheRecord() {
return profile_->IsOffTheRecord();
}
+void HostContentSettingsMap::Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
+
+ if (NotificationType::PREF_CHANGED == type) {
+ if (updating_preferences_)
+ return;
+
+ std::wstring* name = Details<std::wstring>(details).ptr();
+ if (prefs::kDefaultContentSettings == *name) {
+ ReadDefaultSettings(true);
+ } else if (prefs::kContentSettingsPatterns == *name) {
+ ReadExceptions(true);
+ } else if (prefs::kBlockThirdPartyCookies == *name) {
+ updating_preferences_ = true;
+ SetBlockThirdPartyCookies(profile_->GetPrefs()->GetBoolean(
+ prefs::kBlockThirdPartyCookies));
+ updating_preferences_ = false;
+ } else {
+ NOTREACHED() << "Unexpected preference observed";
+ return;
+ }
+
+ NotifyObservers(ContentSettingsDetails(true));
+ } else if (NotificationType::PROFILE_DESTROYED == type) {
+ UnregisterObservers();
+ } else {
+ NOTREACHED() << "Unexpected notification";
+ }
+}
+
HostContentSettingsMap::~HostContentSettingsMap() {
+ UnregisterObservers();
}
// static
@@ -519,6 +552,44 @@ bool HostContentSettingsMap::AllDefault(const ContentSettings& settings) const {
return true;
}
+void HostContentSettingsMap::ReadDefaultSettings(bool overwrite) {
+ PrefService* prefs = profile_->GetPrefs();
+ const DictionaryValue* default_settings_dictionary =
+ prefs->GetDictionary(prefs::kDefaultContentSettings);
+ // Careful: The returned value could be NULL if the pref has never been set.
+ if (default_settings_dictionary != NULL) {
+ if (overwrite)
+ default_content_settings_ = ContentSettings();
+ GetSettingsFromDictionary(default_settings_dictionary,
+ &default_content_settings_);
+ }
+ ForceDefaultsToBeExplicit();
+}
+
+void HostContentSettingsMap::ReadExceptions(bool overwrite) {
+ PrefService* prefs = profile_->GetPrefs();
+ const DictionaryValue* all_settings_dictionary =
+ prefs->GetMutableDictionary(prefs::kContentSettingsPatterns);
+ // Careful: The returned value could be NULL if the pref has never been set.
+ if (all_settings_dictionary != NULL) {
+ if (overwrite)
+ host_content_settings_.clear();
+ for (DictionaryValue::key_iterator i(all_settings_dictionary->begin_keys());
+ i != all_settings_dictionary->end_keys(); ++i) {
+ std::wstring wide_pattern(*i);
+ if (!Pattern(WideToUTF8(wide_pattern)).IsValid())
+ LOG(WARNING) << "Invalid pattern stored in content settings";
+ DictionaryValue* pattern_settings_dictionary = NULL;
+ bool found = all_settings_dictionary->GetDictionaryWithoutPathExpansion(
+ wide_pattern, &pattern_settings_dictionary);
+ DCHECK(found);
+ ContentSettings settings;
+ GetSettingsFromDictionary(pattern_settings_dictionary, &settings);
+ host_content_settings_[WideToUTF8(wide_pattern)] = settings;
+ }
+ }
+}
+
void HostContentSettingsMap::NotifyObservers(
const ContentSettingsDetails& details) {
NotificationService::current()->Notify(
@@ -526,3 +597,18 @@ void HostContentSettingsMap::NotifyObservers(
Source<HostContentSettingsMap>(this),
Details<const ContentSettingsDetails>(&details));
}
+
+void HostContentSettingsMap::UnregisterObservers() {
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
+ if (!profile_)
+ return;
+ if (!is_off_the_record_) {
+ PrefService* prefs = profile_->GetPrefs();
+ prefs->RemovePrefObserver(prefs::kDefaultContentSettings, this);
+ prefs->RemovePrefObserver(prefs::kContentSettingsPatterns, this);
+ prefs->RemovePrefObserver(prefs::kBlockThirdPartyCookies, this);
+ }
+ notification_registrar_.Remove(this, NotificationType::PROFILE_DESTROYED,
+ NotificationService::AllSources());
+ profile_ = NULL;
+}
diff --git a/chrome/browser/host_content_settings_map.h b/chrome/browser/host_content_settings_map.h
index 4107fb4..1317eb3 100644
--- a/chrome/browser/host_content_settings_map.h
+++ b/chrome/browser/host_content_settings_map.h
@@ -16,7 +16,10 @@
#include "base/basictypes.h"
#include "base/lock.h"
#include "base/ref_counted.h"
+#include "chrome/browser/chrome_thread.h"
#include "chrome/common/content_settings.h"
+#include "chrome/common/notification_observer.h"
+#include "chrome/common/notification_registrar.h"
class DictionaryValue;
class GURL;
@@ -24,7 +27,9 @@ class PrefService;
class Profile;
class HostContentSettingsMap
- : public base::RefCountedThreadSafe<HostContentSettingsMap> {
+ : public NotificationObserver,
+ public base::RefCountedThreadSafe<HostContentSettingsMap,
+ ChromeThread::DeleteOnUIThread> {
public:
// A hostname pattern. See |IsValid| for a description of possible patterns.
class Pattern {
@@ -86,6 +91,7 @@ class HostContentSettingsMap
typedef std::vector<PatternSettingPair> SettingsForOneType;
explicit HostContentSettingsMap(Profile* profile);
+ ~HostContentSettingsMap();
static void RegisterUserPrefs(PrefService* prefs);
@@ -151,6 +157,11 @@ class HostContentSettingsMap
// Whether this settings map is associated with an OTR session.
bool IsOffTheRecord();
+ // NotificationObserver implementation.
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
+
private:
friend class base::RefCountedThreadSafe<HostContentSettingsMap>;
@@ -162,8 +173,6 @@ class HostContentSettingsMap
// The default setting for each content type.
static const ContentSetting kDefaultSettings[CONTENT_SETTINGS_NUM_TYPES];
- ~HostContentSettingsMap();
-
// Returns true if we should allow all content types for this URL. This is
// true for various internal objects like chrome:// URLs, so UI and other
// things users think of as "not webpages" don't break.
@@ -180,15 +189,27 @@ class HostContentSettingsMap
// Returns true if |settings| consists entirely of CONTENT_SETTING_DEFAULT.
bool AllDefault(const ContentSettings& settings) const;
+ // Reads the default settings from the prefereces service. If |overwrite| is
+ // true and the preference is missing, the local copy will be cleared as well.
+ void ReadDefaultSettings(bool overwrite);
+
+ // Reads the host exceptions from the prefereces service. If |overwrite| is
+ // true and the preference is missing, the local copy will be cleared as well.
+ void ReadExceptions(bool overwrite);
+
// Informs observers that content settings have changed. Make sure that
// |lock_| is not held when calling this, as listeners will usually call one
// of the GetSettings functions in response, which would then lead to a
// mutex deadlock.
void NotifyObservers(const ContentSettingsDetails& details);
+ void UnregisterObservers();
+
// The profile we're associated with.
Profile* profile_;
+ NotificationRegistrar notification_registrar_;
+
// Copies of the pref data, so that we can read it on the IO thread.
ContentSettings default_content_settings_;
HostContentSettings host_content_settings_;
@@ -202,6 +223,10 @@ class HostContentSettingsMap
// Whether this settings map is for an OTR session.
bool is_off_the_record_;
+ // Whether we are currently updating preferences, this is used to ignore
+ // notifications from the preferences service that we triggered ourself.
+ bool updating_preferences_;
+
DISALLOW_COPY_AND_ASSIGN(HostContentSettingsMap);
};