diff options
-rw-r--r-- | chrome/browser/host_content_settings_map.cc | 150 | ||||
-rw-r--r-- | chrome/browser/host_content_settings_map.h | 31 |
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); }; |