Replace SetContentSetting method of the content_settings::Provider interface...

Replace SetContentSetting method of the content_settings::Provider interface with GetWebsiteSetting.

This is part of a series of cleanup CLs to make all content settings Providers and the HostContentSetting map use only |Values| instead of |ContentSettings|. The HostContentSettingsMap should only contain conveniences methods that take |ContentSetting| parameters.

BUG=102637
TEST=HostContentSettingsMapTest*,
     PrefProviderTest*,
     PolicyProviderTest*,
     DefaultProviderTest*,
     ExtensionProviderTest*

Review URL: http://codereview.chromium.org/8539004

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@110500 0039d316-1c4b-4281-b951-d872f2087c98
parent 5656f8a3
......@@ -70,6 +70,7 @@ class DefaultRuleIterator : public RuleIterator {
}
private:
// TODO(markusheintz): |ContentSetting| should be replaced with a |Value|.
ContentSetting setting_;
};
......@@ -109,8 +110,10 @@ DefaultProvider::DefaultProvider(PrefService* prefs, bool incognito)
// Read global defaults.
ReadDefaultSettings(true);
if (default_content_settings_[CONTENT_SETTINGS_TYPE_COOKIES] ==
CONTENT_SETTING_BLOCK) {
ContentSetting cookie_setting = ValueToContentSetting(
default_settings_[CONTENT_SETTINGS_TYPE_COOKIES].get());
if (cookie_setting == CONTENT_SETTING_BLOCK) {
UserMetrics::RecordAction(
UserMetricsAction("CookieBlockingEnabledPerDefault"));
} else {
......@@ -126,58 +129,62 @@ DefaultProvider::DefaultProvider(PrefService* prefs, bool incognito)
DefaultProvider::~DefaultProvider() {
}
void DefaultProvider::SetContentSetting(
bool DefaultProvider::SetWebsiteSetting(
const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_pattern,
ContentSettingsType content_type,
const ResourceIdentifier& resource_identifier,
ContentSetting setting) {
Value* value) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
DCHECK(prefs_);
// Ignore non default settings
if (primary_pattern != ContentSettingsPattern::Wildcard() ||
secondary_pattern != ContentSettingsPattern::Wildcard()) {
return;
return false;
}
// 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;
return false;
std::string dictionary_path = GetTypeName(content_type);
{
AutoReset<bool> auto_reset(&updating_preferences_, true);
DictionaryPrefUpdate update(prefs_, prefs::kDefaultContentSettings);
DictionaryValue* default_settings_dictionary = update.Get();
// Keep the obsolete pref in sync as long as backwards compatibility is
// required. This is required to keep sync working correctly.
if (content_type == CONTENT_SETTINGS_TYPE_GEOLOCATION) {
if (value) {
prefs_->Set(prefs::kGeolocationDefaultContentSetting, *value);
} else {
prefs_->ClearPref(prefs::kGeolocationDefaultContentSetting);
}
}
// |DefaultProvider| should not send any notifications when holding
// |lock_|. |DictionaryPrefUpdate| destructor and
// |PrefService::SetInteger()| send out notifications. As a response, the
// upper layers may call |GetAllContentSettingRules| which acquires |lock_|
// again.
{
DictionaryPrefUpdate update(prefs_, prefs::kDefaultContentSettings);
DictionaryValue* default_settings_dictionary = update.Get();
base::AutoLock lock(lock_);
if (setting == CONTENT_SETTING_DEFAULT ||
setting == kDefaultSettings[content_type]) {
default_content_settings_[content_type] =
kDefaultSettings[content_type];
default_settings_dictionary->RemoveWithoutPathExpansion(dictionary_path,
NULL);
if (value == NULL ||
ValueToContentSetting(value) == kDefaultSettings[content_type]) {
// If |value| is NULL we need to reset the default setting the the
// hardcoded default.
default_settings_[content_type].reset(
Value::CreateIntegerValue(kDefaultSettings[content_type]));
// Remove the corresponding pref entry since the hardcoded default value
// is used.
default_settings_dictionary->RemoveWithoutPathExpansion(
GetTypeName(content_type), NULL);
} else {
default_content_settings_[content_type] = setting;
default_settings_[content_type].reset(value->DeepCopy());
// Transfer ownership of |value| to the |default_settings_dictionary|.
default_settings_dictionary->SetWithoutPathExpansion(
dictionary_path, Value::CreateIntegerValue(setting));
}
}
// Keep the obsolete pref in sync as long as backwards compatibility is
// required. This is required to keep sync working correctly.
if (content_type == CONTENT_SETTINGS_TYPE_GEOLOCATION) {
prefs_->SetInteger(prefs::kGeolocationDefaultContentSetting,
setting == CONTENT_SETTING_DEFAULT ?
kDefaultSettings[content_type] : setting);
GetTypeName(content_type), value);
}
}
......@@ -185,6 +192,8 @@ void DefaultProvider::SetContentSetting(
ContentSettingsPattern(),
content_type,
std::string());
return true;
}
RuleIterator* DefaultProvider::GetRuleIterator(
......@@ -193,7 +202,14 @@ RuleIterator* DefaultProvider::GetRuleIterator(
bool incognito) const {
base::AutoLock lock(lock_);
if (resource_identifier.empty()) {
return new DefaultRuleIterator(default_content_settings_[content_type]);
int int_value = 0;
ValueMap::const_iterator it(default_settings_.find(content_type));
if (it != default_settings_.end()) {
it->second->GetAsInteger(&int_value);
} else {
NOTREACHED();
}
return new DefaultRuleIterator(ContentSetting(int_value));
} else {
return new EmptyRuleIterator();
}
......@@ -253,78 +269,88 @@ void DefaultProvider::ReadDefaultSettings(bool overwrite) {
const DictionaryValue* default_settings_dictionary =
prefs_->GetDictionary(prefs::kDefaultContentSettings);
if (overwrite) {
for (int i = 0; i < CONTENT_SETTINGS_NUM_TYPES; ++i)
default_content_settings_[i] = CONTENT_SETTING_DEFAULT;
}
if (overwrite)
default_settings_.clear();
// Careful: The returned value could be NULL if the pref has never been set.
if (default_settings_dictionary) {
GetSettingsFromDictionary(default_settings_dictionary,
default_content_settings_);
}
if (default_settings_dictionary)
GetSettingsFromDictionary(default_settings_dictionary);
ForceDefaultsToBeExplicit();
}
void DefaultProvider::ForceDefaultsToBeExplicit() {
for (int i = 0; i < CONTENT_SETTINGS_NUM_TYPES; ++i) {
if (default_content_settings_[i] == CONTENT_SETTING_DEFAULT)
default_content_settings_[i] = kDefaultSettings[i];
ContentSettingsType type = ContentSettingsType(i);
if (!default_settings_[type].get())
default_settings_[type].reset(
Value::CreateIntegerValue(kDefaultSettings[i]));
}
}
void DefaultProvider::GetSettingsFromDictionary(
const DictionaryValue* dictionary,
ContentSetting* settings) {
const DictionaryValue* dictionary) {
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 < CONTENT_SETTINGS_NUM_TYPES; ++type) {
if (content_type == GetTypeName(ContentSettingsType(type))) {
int setting = CONTENT_SETTING_DEFAULT;
int int_value = CONTENT_SETTING_DEFAULT;
bool found = dictionary->GetIntegerWithoutPathExpansion(content_type,
&setting);
&int_value);
DCHECK(found);
settings[type] = IntToContentSetting(setting);
default_settings_[ContentSettingsType(type)].reset(
Value::CreateIntegerValue(int_value));
break;
}
}
}
// Migrate obsolete cookie prompt mode/
if (settings[CONTENT_SETTINGS_TYPE_COOKIES] == CONTENT_SETTING_ASK)
settings[CONTENT_SETTINGS_TYPE_COOKIES] = CONTENT_SETTING_BLOCK;
// Migrate obsolete cookie prompt mode.
if (ValueToContentSetting(
default_settings_[CONTENT_SETTINGS_TYPE_COOKIES].get()) ==
CONTENT_SETTING_ASK) {
default_settings_[CONTENT_SETTINGS_TYPE_COOKIES].reset(
Value::CreateIntegerValue(CONTENT_SETTING_BLOCK));
}
settings[CONTENT_SETTINGS_TYPE_PLUGINS] =
ClickToPlayFixup(CONTENT_SETTINGS_TYPE_PLUGINS,
settings[CONTENT_SETTINGS_TYPE_PLUGINS]);
if (default_settings_[CONTENT_SETTINGS_TYPE_PLUGINS].get()) {
ContentSetting plugin_setting = ValueToContentSetting(
default_settings_[CONTENT_SETTINGS_TYPE_PLUGINS].get());
plugin_setting =
ClickToPlayFixup(CONTENT_SETTINGS_TYPE_PLUGINS, plugin_setting);
default_settings_[CONTENT_SETTINGS_TYPE_PLUGINS].reset(
Value::CreateIntegerValue(plugin_setting));
}
}
void DefaultProvider::MigrateObsoleteNotificationPref() {
if (prefs_->HasPrefPath(prefs::kDesktopNotificationDefaultContentSetting)) {
ContentSetting setting = IntToContentSetting(
prefs_->GetInteger(prefs::kDesktopNotificationDefaultContentSetting));
SetContentSetting(
const base::Value* value = prefs_->FindPreference(
prefs::kDesktopNotificationDefaultContentSetting)->GetValue();
// Do not clear the old preference yet as long as we need to maintain
// backward compatibility.
SetWebsiteSetting(
ContentSettingsPattern::Wildcard(),
ContentSettingsPattern::Wildcard(),
CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
std::string(),
setting);
value->DeepCopy());
prefs_->ClearPref(prefs::kDesktopNotificationDefaultContentSetting);
}
}
void DefaultProvider::MigrateObsoleteGeolocationPref() {
if (prefs_->HasPrefPath(prefs::kGeolocationDefaultContentSetting)) {
ContentSetting setting = IntToContentSetting(
prefs_->GetInteger(prefs::kGeolocationDefaultContentSetting));
const base::Value* value = prefs_->FindPreference(
prefs::kGeolocationDefaultContentSetting)->GetValue();
// Do not clear the old preference yet as long as we need to maintain
// backward compatibility.
SetContentSetting(
SetWebsiteSetting(
ContentSettingsPattern::Wildcard(),
ContentSettingsPattern::Wildcard(),
CONTENT_SETTINGS_TYPE_GEOLOCATION,
std::string(),
setting);
value->DeepCopy());
}
}
......
......@@ -5,10 +5,12 @@
#ifndef CHROME_BROWSER_CONTENT_SETTINGS_CONTENT_SETTINGS_DEFAULT_PROVIDER_H_
#define CHROME_BROWSER_CONTENT_SETTINGS_CONTENT_SETTINGS_DEFAULT_PROVIDER_H_
#include <map>
#include <string>
#include <vector>
#include "base/basictypes.h"
#include "base/memory/linked_ptr.h"
#include "base/synchronization/lock.h"
#include "chrome/browser/content_settings/content_settings_observable_provider.h"
#include "chrome/browser/prefs/pref_change_registrar.h"
......@@ -37,12 +39,12 @@ class DefaultProvider : public ObservableProvider,
const ResourceIdentifier& resource_identifier,
bool incognito) const OVERRIDE;
virtual void SetContentSetting(
virtual bool SetWebsiteSetting(
const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_pattern,
ContentSettingsType content_type,
const ResourceIdentifier& resource_identifier,
ContentSetting content_setting) OVERRIDE;
Value* value) OVERRIDE;
virtual void ClearAllContentSettingsRules(
ContentSettingsType content_type) OVERRIDE;
......@@ -56,8 +58,7 @@ class DefaultProvider : public ObservableProvider,
private:
// Sets the fields of |settings| based on the values in |dictionary|.
void GetSettingsFromDictionary(const base::DictionaryValue* dictionary,
ContentSetting* settings);
void GetSettingsFromDictionary(const base::DictionaryValue* dictionary);
// Forces the default settings to be explicitly set instead of themselves
// being CONTENT_SETTING_DEFAULT.
......@@ -70,8 +71,10 @@ class DefaultProvider : public ObservableProvider,
void MigrateObsoleteNotificationPref();
void MigrateObsoleteGeolocationPref();
typedef linked_ptr<base::Value> ValuePtr;
typedef std::map<ContentSettingsType, ValuePtr> ValueMap;
// Copies of the pref data, so that we can read it on the IO thread.
ContentSetting default_content_settings_[CONTENT_SETTINGS_NUM_TYPES];
ValueMap default_settings_;
PrefService* prefs_;
......
......@@ -43,11 +43,12 @@ TEST_F(DefaultProviderTest, DefaultValues) {
CONTENT_SETTINGS_TYPE_COOKIES,
std::string(),
false));
provider_.SetContentSetting(ContentSettingsPattern::Wildcard(),
provider_.SetWebsiteSetting(
ContentSettingsPattern::Wildcard(),
ContentSettingsPattern::Wildcard(),
CONTENT_SETTINGS_TYPE_COOKIES,
std::string(),
CONTENT_SETTING_BLOCK);
Value::CreateIntegerValue(CONTENT_SETTING_BLOCK));
EXPECT_EQ(CONTENT_SETTING_BLOCK,
GetContentSetting(&provider_,
GURL(),
......@@ -63,11 +64,12 @@ TEST_F(DefaultProviderTest, DefaultValues) {
CONTENT_SETTINGS_TYPE_GEOLOCATION,
std::string(),
false));
provider_.SetContentSetting(ContentSettingsPattern::Wildcard(),
provider_.SetWebsiteSetting(
ContentSettingsPattern::Wildcard(),
ContentSettingsPattern::Wildcard(),
CONTENT_SETTINGS_TYPE_GEOLOCATION,
std::string(),
CONTENT_SETTING_BLOCK);
Value::CreateIntegerValue(CONTENT_SETTING_BLOCK));
EXPECT_EQ(CONTENT_SETTING_BLOCK,
GetContentSetting(&provider_,
GURL(),
......@@ -88,11 +90,15 @@ TEST_F(DefaultProviderTest, IgnoreNonDefaultSettings) {
CONTENT_SETTINGS_TYPE_COOKIES,
std::string(),
false));
provider_.SetContentSetting(ContentSettingsPattern::FromURL(primary_url),
scoped_ptr<base::Value> value(
Value::CreateIntegerValue(CONTENT_SETTING_BLOCK));
bool owned = provider_.SetWebsiteSetting(
ContentSettingsPattern::FromURL(primary_url),
ContentSettingsPattern::FromURL(secondary_url),
CONTENT_SETTINGS_TYPE_COOKIES,
std::string(),
CONTENT_SETTING_BLOCK);
value.get());
EXPECT_FALSE(owned);
EXPECT_EQ(CONTENT_SETTING_ALLOW,
GetContentSetting(&provider_,
primary_url,
......@@ -108,20 +114,22 @@ TEST_F(DefaultProviderTest, Observer) {
OnContentSettingChanged(
_, _, CONTENT_SETTINGS_TYPE_IMAGES, ""));
provider_.AddObserver(&mock_observer);
provider_.SetContentSetting(ContentSettingsPattern::Wildcard(),
provider_.SetWebsiteSetting(
ContentSettingsPattern::Wildcard(),
ContentSettingsPattern::Wildcard(),
CONTENT_SETTINGS_TYPE_IMAGES,
std::string(),
CONTENT_SETTING_BLOCK);
Value::CreateIntegerValue(CONTENT_SETTING_BLOCK));
EXPECT_CALL(mock_observer,
OnContentSettingChanged(
_, _, CONTENT_SETTINGS_TYPE_GEOLOCATION, ""));
provider_.SetContentSetting(ContentSettingsPattern::Wildcard(),
provider_.SetWebsiteSetting(
ContentSettingsPattern::Wildcard(),
ContentSettingsPattern::Wildcard(),
CONTENT_SETTINGS_TYPE_GEOLOCATION,
std::string(),
CONTENT_SETTING_BLOCK);
Value::CreateIntegerValue(CONTENT_SETTING_BLOCK));
}
......@@ -132,11 +140,12 @@ TEST_F(DefaultProviderTest, ObserveDefaultPref) {
scoped_ptr<Value> default_value(prefs->FindPreference(
prefs::kDefaultContentSettings)->GetValue()->DeepCopy());
provider_.SetContentSetting(ContentSettingsPattern::Wildcard(),
provider_.SetWebsiteSetting(
ContentSettingsPattern::Wildcard(),
ContentSettingsPattern::Wildcard(),
CONTENT_SETTINGS_TYPE_COOKIES,
std::string(),
CONTENT_SETTING_BLOCK);
Value::CreateIntegerValue(CONTENT_SETTING_BLOCK));
EXPECT_EQ(CONTENT_SETTING_BLOCK,
GetContentSetting(&provider_,
GURL(),
......@@ -189,11 +198,12 @@ TEST_F(DefaultProviderTest, OffTheRecord) {
// Changing content settings on the main provider should also affect the
// incognito map.
provider_.SetContentSetting(ContentSettingsPattern::Wildcard(),
provider_.SetWebsiteSetting(
ContentSettingsPattern::Wildcard(),
ContentSettingsPattern::Wildcard(),
CONTENT_SETTINGS_TYPE_COOKIES,
std::string(),
CONTENT_SETTING_BLOCK);
Value::CreateIntegerValue(CONTENT_SETTING_BLOCK));
EXPECT_EQ(CONTENT_SETTING_BLOCK,
GetContentSetting(&provider_,
GURL(),
......@@ -211,11 +221,15 @@ TEST_F(DefaultProviderTest, OffTheRecord) {
true));
// Changing content settings on the incognito provider should be ignored.
otr_provider.SetContentSetting(ContentSettingsPattern::Wildcard(),
scoped_ptr<base::Value> value(
Value::CreateIntegerValue(CONTENT_SETTING_ALLOW));
bool owned = otr_provider.SetWebsiteSetting(
ContentSettingsPattern::Wildcard(),
ContentSettingsPattern::Wildcard(),
CONTENT_SETTINGS_TYPE_COOKIES,
std::string(),
CONTENT_SETTING_ALLOW);
value.get());
EXPECT_FALSE(owned);
EXPECT_EQ(CONTENT_SETTING_BLOCK,
GetContentSetting(&provider_,
GURL(),
......
......@@ -31,6 +31,15 @@ RuleIterator* ExtensionProvider::GetRuleIterator(
incognito);
}
bool ExtensionProvider::SetWebsiteSetting(
const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_pattern,
ContentSettingsType content_type,
const ResourceIdentifier& resource_identifier,
Value* value) {
return false;
}
void ExtensionProvider::ShutdownOnUIThread() {
RemoveAllObservers();
extensions_settings_->RemoveObserver(this);
......
......@@ -28,12 +28,12 @@ class ExtensionProvider : public ObservableProvider,
const ResourceIdentifier& resource_identifier,
bool incognito) const OVERRIDE;
virtual void SetContentSetting(
const ContentSettingsPattern& embedded_url_pattern,
const ContentSettingsPattern& top_level_url_pattern,
virtual bool SetWebsiteSetting(
const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_pattern,
ContentSettingsType content_type,
const ResourceIdentifier& resource_identifier,
ContentSetting content_setting) OVERRIDE {}
Value* value) OVERRIDE;
virtual void ClearAllContentSettingsRules(ContentSettingsType content_type)
OVERRIDE {}
......
......@@ -33,20 +33,21 @@ RuleIterator* MockProvider::GetRuleIterator(
return value_map_.GetRuleIterator(content_type, resource_identifier, NULL);
}
void MockProvider::SetContentSetting(
bool MockProvider::SetWebsiteSetting(
const ContentSettingsPattern& requesting_url_pattern,
const ContentSettingsPattern& embedding_url_pattern,
ContentSettingsType content_type,
const ResourceIdentifier& resource_identifier,
ContentSetting content_setting) {
base::Value* value) {
if (read_only_)
return;
return false;
value_map_.clear();
value_map_.SetValue(requesting_url_pattern,
embedding_url_pattern,
content_type,
resource_identifier,
Value::CreateIntegerValue(content_setting));
value);
return true;
}
void MockProvider::ShutdownOnUIThread() {
......
......@@ -35,12 +35,12 @@ class MockProvider : public ObservableProvider {
// The MockProvider is only able to store one content setting. So every time
// this method is called the previously set content settings is overwritten.
virtual void SetContentSetting(
virtual bool SetWebsiteSetting(
const ContentSettingsPattern& requesting_url_pattern,
const ContentSettingsPattern& embedding_url_pattern,
ContentSettingsType content_type,
const ResourceIdentifier& resource_identifier,
ContentSetting content_setting) OVERRIDE;
base::Value* value) OVERRIDE;
virtual void ClearAllContentSettingsRules(
ContentSettingsType content_type) OVERRIDE {}
......
......@@ -384,12 +384,13 @@ void PolicyProvider::ReadManagedContentSettings(bool overwrite) {
// Since the PolicyProvider is a read only content settings provider, all
// methodes of the ProviderInterface that set or delete any settings do nothing.
void PolicyProvider::SetContentSetting(
bool PolicyProvider::SetWebsiteSetting(
const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_pattern,
ContentSettingsType content_type,
const ResourceIdentifier& resource_identifier,
ContentSetting content_setting) {
Value* value) {
return false;
}
void PolicyProvider::ClearAllContentSettingsRules(
......
......@@ -35,12 +35,12 @@ class PolicyProvider : public ObservableProvider,
const ResourceIdentifier& resource_identifier,
bool incognito) const OVERRIDE;
virtual void SetContentSetting(
virtual bool SetWebsiteSetting(
const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_pattern,
ContentSettingsType content_type,
const ResourceIdentifier& resource_identifier,
ContentSetting content_setting) OVERRIDE;
Value* value) OVERRIDE;
virtual void ClearAllContentSettingsRules(
ContentSettingsType content_type) OVERRIDE;
......
......@@ -190,13 +190,16 @@ TEST_F(PolicyProviderTest, GettingManagedContentSettings) {
// The PolicyProvider does not allow setting content settings as they are
// enforced via policies and not set by the user or extension. So a call to
// SetContentSetting does nothing.
provider.SetContentSetting(
// SetWebsiteSetting does nothing.
scoped_ptr<base::Value> value_block(
Value::CreateIntegerValue(CONTENT_SETTING_BLOCK));
bool owned = provider.SetWebsiteSetting(
yt_url_pattern,
yt_url_pattern,
CONTENT_SETTINGS_TYPE_COOKIES,
"",
CONTENT_SETTING_BLOCK);
value_block.get());
EXPECT_FALSE(owned);
EXPECT_EQ(CONTENT_SETTING_DEFAULT,
GetContentSetting(
&provider, youtube_url, youtube_url,
......
......@@ -151,15 +151,26 @@ PrefProvider::PrefProvider(PrefService* prefs,
pref_change_registrar_.Add(prefs::kDesktopNotificationDeniedOrigins, this);
}
void PrefProvider::SetContentSetting(
bool PrefProvider::SetWebsiteSetting(
const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_pattern,
ContentSettingsType content_type,
const ResourceIdentifier& resource_identifier,
ContentSetting setting) {
Value* in_value) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
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()) {
return false;
}
// 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_)
......@@ -167,19 +178,19 @@ void PrefProvider::SetContentSetting(
{
base::AutoLock auto_lock(lock_);
if (setting == CONTENT_SETTING_DEFAULT) {
map_to_modify->DeleteValue(
if (value.get()) {
map_to_modify->SetValue(
primary_pattern,
secondary_pattern,
content_type,
resource_identifier);
resource_identifier,
value->DeepCopy());
} else {
map_to_modify->SetValue(
map_to_modify->DeleteValue(
primary_pattern,
secondary_pattern,
content_type,
resource_identifier,
Value::CreateIntegerValue(setting));
resource_identifier);
}
}
// Update the content settings preference.
......@@ -188,12 +199,14 @@ void PrefProvider::SetContentSetting(
secondary_pattern,
content_type,
resource_identifier,
setting);
value.get());
prefs_->ScheduleSavePersistentPrefs();
}
NotifyObservers(
primary_pattern, secondary_pattern, content_type, resource_identifier);
return true;
}
void PrefProvider::ClearAllContentSettingsRules(
......@@ -225,7 +238,7 @@ void PrefProvider::ClearAllContentSettingsRules(
it->secondary_pattern,
content_type,
"",
CONTENT_SETTING_DEFAULT);
NULL);
}
NotifyObservers(ContentSettingsPattern(),
ContentSettingsPattern(),
......@@ -297,7 +310,7 @@ void PrefProvider::UpdatePref(
const ContentSettingsPattern& secondary_pattern,
ContentSettingsType content_type,
const ResourceIdentifier& resource_identifier,
ContentSetting setting) {
const base::Value* value) {
// Ensure that |lock_| is not held by this thread, since this function will
// send out notifications (by |~DictionaryPrefUpdate|).
AssertLockNotHeld();
......@@ -311,7 +324,7 @@ void PrefProvider::UpdatePref(
secondary_pattern,
content_type,
resource_identifier,
setting,
value,
pattern_pairs_settings);
}
if (content_type != CONTENT_SETTINGS_TYPE_GEOLOCATION &&
......@@ -320,9 +333,12 @@ void PrefProvider::UpdatePref(
secondary_pattern,
content_type,
resource_identifier,
setting);
ValueToContentSetting(value));
} else if (content_type == CONTENT_SETTINGS_TYPE_GEOLOCATION) {
UpdateObsoleteGeolocationPref(primary_pattern, secondary_pattern, setting);
UpdateObsoleteGeolocationPref(
primary_pattern,
secondary_pattern,
ValueToContentSetting(value));
} else if (content_type == CONTENT_SETTINGS_TYPE_NOTIFICATIONS) {
ListPrefUpdate update_allowed_sites(
prefs_, prefs::kDesktopNotificationAllowedOrigins);
......@@ -330,7 +346,7 @@ void PrefProvider::UpdatePref(
prefs_, prefs::kDesktopNotificationDeniedOrigins);
UpdateObsoleteNotificationsSettings(primary_pattern,
secondary_pattern,
setting,
ValueToContentSetting(value),
update_allowed_sites.Get(),
update_denied_sites.Get());
}
......@@ -507,7 +523,7 @@ void PrefProvider::UpdatePatternPairsSettings(
const ContentSettingsPattern& secondary_pattern,
ContentSettingsType content_type,
const ResourceIdentifier& resource_identifier,
ContentSetting setting,
const base::Value* value,
DictionaryValue* pattern_pairs_settings) {
// Get settings dictionary for the given patterns.
std::string pattern_str(CreatePatternString(primary_pattern,
......@@ -516,7 +532,7 @@ void PrefProvider::UpdatePatternPairsSettings(
bool found = pattern_pairs_settings->GetDictionaryWithoutPathExpansion(
pattern_str, &settings_dictionary);
if (!found && (setting != CONTENT_SETTING_DEFAULT)) {
if (!found && value) {
settings_dictionary = new DictionaryValue;
pattern_pairs_settings->SetWithoutPathExpansion(
pattern_str, settings_dictionary);
......@@ -529,13 +545,13 @@ void PrefProvider::UpdatePatternPairsSettings(
found = settings_dictionary->GetDictionary(
res_dictionary_path, &resource_dictionary);
if (!found) {
if (setting == CONTENT_SETTING_DEFAULT)
if (value == NULL)
return; // Nothing to remove. Exit early.
resource_dictionary = new DictionaryValue;
settings_dictionary->Set(res_dictionary_path, resource_dictionary);
}
// Update resource dictionary.
if (setting == CONTENT_SETTING_DEFAULT) {
if (value == NULL) {
resource_dictionary->RemoveWithoutPathExpansion(resource_identifier,
NULL);
if (resource_dictionary->empty()) {
......@@ -544,17 +560,17 @@ void PrefProvider::UpdatePatternPairsSettings(
}
} else {
resource_dictionary->SetWithoutPathExpansion(
resource_identifier, Value::CreateIntegerValue(setting));
resource_identifier, value->DeepCopy());
}
} else {
// Update settings dictionary.
std::string setting_path = GetTypeName(content_type);
if (setting == CONTENT_SETTING_DEFAULT) {
if (value == NULL) {
settings_dictionary->RemoveWithoutPathExpansion(setting_path,
NULL);
} else {
settings_dictionary->SetWithoutPathExpansion(
setting_path, Value::CreateIntegerValue(setting));
setting_path, value->DeepCopy());
}
}
// Remove the settings dictionary if it is empty.
......@@ -722,14 +738,13 @@ void PrefProvider::MigrateObsoletePerhostPref() {
setting = FixObsoleteCookiePromptMode(content_type, setting);
setting = ClickToPlayFixup(content_type, setting);
// TODO(markusheintz): Maybe this check can be removed.
if (setting != CONTENT_SETTING_DEFAULT) {
SetContentSetting(
SetWebsiteSetting(
pattern,
pattern,
content_type,
"",
setting);
Value::CreateIntegerValue(setting));
}
}
}
......@@ -746,11 +761,12 @@ void PrefProvider::MigrateObsoletePopupsPref() {
i != whitelist_pref->end(); ++i) {
std::string host;
(*i)->GetAsString(&host);
SetContentSetting(ContentSettingsPattern::FromString(host),
SetWebsiteSetting(ContentSettingsPattern::FromString(host),
ContentSettingsPattern::FromString(host),
CONTENT_SETTINGS_TYPE_POPUPS,
"",
CONTENT_SETTING_ALLOW);
Value::CreateIntegerValue(
CONTENT_SETTING_ALLOW));
}
prefs_->ClearPref(prefs::kPopupWhitelistedHosts);
}
......@@ -931,9 +947,9 @@ void PrefProvider::MigrateObsoleteGeolocationPref() {
GURL secondary_url(secondary_key);
DCHECK(secondary_url.is_valid());
int setting_value;
found = requesting_origin_settings->GetIntegerWithoutPathExpansion(
secondary_key, &setting_value);
base::Value* value = NULL;
found = requesting_origin_settings->GetWithoutPathExpansion(
secondary_key, &value);
DCHECK(found);
ContentSettingsPattern primary_pattern =
......@@ -946,7 +962,7 @@ void PrefProvider::MigrateObsoleteGeolocationPref() {
secondary_pattern,
CONTENT_SETTINGS_TYPE_GEOLOCATION,
std::string(),
IntToContentSetting(setting_value),
value,
pattern_pairs_settings);
}
}
......@@ -975,11 +991,13 @@ void PrefProvider::MigrateObsoleteNotificationsPrefs() {
ContentSettingsPattern primary_pattern =
ContentSettingsPattern::FromURLNoWildcard(GURL(url_string));
DCHECK(primary_pattern.IsValid());
scoped_ptr<base::Value> value(
Value::CreateIntegerValue(CONTENT_SETTING_ALLOW));
UpdatePatternPairsSettings(primary_pattern,
ContentSettingsPattern::Wildcard(),
CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
std::string(),
CONTENT_SETTING_ALLOW,
value.get(),
pattern_pairs_settings);
}
......@@ -992,11 +1010,13 @@ void PrefProvider::MigrateObsoleteNotificationsPrefs() {
ContentSettingsPattern primary_pattern =
ContentSettingsPattern::FromURLNoWildcard(GURL(url_string));
DCHECK(primary_pattern.IsValid());
scoped_ptr<base::Value> value(
Value::CreateIntegerValue(CONTENT_SETTING_BLOCK));
UpdatePatternPairsSettings(primary_pattern,
ContentSettingsPattern::Wildcard(),
CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
std::string(),
CONTENT_SETTING_BLOCK,
value.get(),
pattern_pairs_settings);
}
}
......
......@@ -44,12 +44,12 @@ class PrefProvider : public ObservableProvider,
const ResourceIdentifier& resource_identifier,
bool incognito) const OVERRIDE;
virtual void SetContentSetting(
virtual bool SetWebsiteSetting(
const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_pattern,
ContentSettingsType content_type,
const ResourceIdentifier& resource_identifier,
ContentSetting content_setting) OVERRIDE;
Value* value) OVERRIDE;
virtual void ClearAllContentSettingsRules(
ContentSettingsType content_type) OVERRIDE;
......@@ -77,7 +77,7 @@ class PrefProvider : public ObservableProvider,
const ContentSettingsPattern& secondary_pattern,
ContentSettingsType content_type,
const ResourceIdentifier& resource_identifier,
ContentSetting setting);
const base::Value* value);
// Updates the given |pattern_pairs_settings| dictionary value.
void UpdatePatternPairsSettings(
......@@ -85,7 +85,7 @@ class PrefProvider : public ObservableProvider,
const ContentSettingsPattern& secondary_pattern,
ContentSettingsType content_type,
const ResourceIdentifier& resource_identifier,
ContentSetting setting,
const base::Value* value,
DictionaryValue* pattern_pairs_settings);
// Updates the preferences prefs::kContentSettingsPatterns. This preferences
......
......@@ -8,6 +8,7 @@
#include "base/command_line.h"
#include "base/memory/scoped_ptr.h"
#include "base/threading/platform_thread.h"
#include "base/values.h"
#include "chrome/browser/content_settings/content_settings_mock_observer.h"
#include "chrome/browser/content_settings/content_settings_utils.h"
#include "chrome/browser/prefs/browser_prefs.h"
......@@ -133,12 +134,12 @@ TEST_F(PrefProviderTest, Observer) {
pref_content_settings_provider.AddObserver(&mock_observer);
pref_content_settings_provider.SetContentSetting(
pref_content_settings_provider.SetWebsiteSetting(
pattern,
ContentSettingsPattern::Wildcard(),
CONTENT_SETTINGS_TYPE_IMAGES,
"",
CONTENT_SETTING_ALLOW);
Value::CreateIntegerValue(CONTENT_SETTING_ALLOW));
pref_content_settings_provider.ShutdownOnUIThread();
}
......@@ -172,12 +173,12 @@ TEST_F(PrefProviderTest, Incognito) {
PrefProvider pref_content_settings_provider_incognito(otr_prefs, true);
ContentSettingsPattern pattern =
ContentSettingsPattern::FromString("[*.]example.com");
pref_content_settings_provider.SetContentSetting(
pref_content_settings_provider.SetWebsiteSetting(
pattern,
pattern,
CONTENT_SETTINGS_TYPE_IMAGES,
"",
CONTENT_SETTING_ALLOW);
Value::CreateIntegerValue(CONTENT_SETTING_ALLOW));
GURL host("http://example.com/");
// The value should of course be visible in the regular PrefProvider.
......@@ -214,11 +215,12 @@ TEST_F(PrefProviderTest, GetContentSettingsValue) {
&provider, primary_url, primary_url,
CONTENT_SETTINGS_TYPE_IMAGES, "", false));
provider.SetContentSetting(primary_pattern,
provider.SetWebsiteSetting(
primary_pattern,
primary_pattern,
CONTENT_SETTINGS_TYPE_IMAGES,
"",
CONTENT_SETTING_BLOCK);
Value::CreateIntegerValue(CONTENT_SETTING_BLOCK));
EXPECT_EQ(CONTENT_SETTING_BLOCK,
GetContentSetting(&provider, primary_url, primary_url,
CONTENT_SETTINGS_TYPE_IMAGES, "", false));
......@@ -229,11 +231,11 @@ TEST_F(PrefProviderTest, GetContentSettingsValue) {
value_ptr->GetAsInteger(&int_value);
EXPECT_EQ(CONTENT_SETTING_BLOCK, IntToContentSetting(int_value));
provider.SetContentSetting(primary_pattern,
provider.SetWebsiteSetting(primary_pattern,
primary_pattern,
CONTENT_SETTINGS_TYPE_IMAGES,
"",
CONTENT_SETTING_DEFAULT);
NULL);
EXPECT_EQ(NULL,
GetContentSettingValue(
&provider, primary_url, primary_url,
......@@ -261,12 +263,12 @@ TEST_F(PrefProviderTest, Patterns) {
GetContentSetting(
&pref_content_settings_provider,
host1, host1, CONTENT_SETTINGS_TYPE_IMAGES, "", false));
pref_content_settings_provider.SetContentSetting(
pref_content_settings_provider.SetWebsiteSetting(
pattern1,
pattern1,
CONTENT_SETTINGS_TYPE_IMAGES,
"",
CONTENT_SETTING_BLOCK);
Value::CreateIntegerValue(CONTENT_SETTING_BLOCK));
EXPECT_EQ(CONTENT_SETTING_BLOCK,
GetContentSetting(
&pref_content_settings_provider,
......@@ -280,12 +282,12 @@ TEST_F(PrefProviderTest, Patterns) {
GetContentSetting(
&pref_content_settings_provider,
host3, host3, CONTENT_SETTINGS_TYPE_IMAGES, "", false));
pref_content_settings_provider.SetContentSetting(
pref_content_settings_provider.SetWebsiteSetting(
pattern2,
pattern2,
CONTENT_SETTINGS_TYPE_IMAGES,
"",
CONTENT_SETTING_BLOCK);
Value::CreateIntegerValue(CONTENT_SETTING_BLOCK));
EXPECT_EQ(CONTENT_SETTING_BLOCK,
GetContentSetting(
&pref_content_settings_provider,
......@@ -295,12 +297,12 @@ TEST_F(PrefProviderTest, Patterns) {
GetContentSetting(&pref_content_settings_provider,
host4, host4, CONTENT_SETTINGS_TYPE_IMAGES, "",
false));
pref_content_settings_provider.SetContentSetting(
pref_content_settings_provider.SetWebsiteSetting(
pattern3,
pattern3,
CONTENT_SETTINGS_TYPE_IMAGES,
"",
CONTENT_SETTING_BLOCK);
Value::CreateIntegerValue(CONTENT_SETTING_BLOCK));
EXPECT_EQ(CONTENT_SETTING_BLOCK,
GetContentSetting(
&pref_content_settings_provider,
......@@ -325,12 +327,12 @@ TEST_F(PrefProviderTest, ResourceIdentifier) {
&pref_content_settings_provider,
host, host, CONTENT_SETTINGS_TYPE_PLUGINS,
resource1, false));
pref_content_settings_provider.SetContentSetting(
pref_content_settings_provider.SetWebsiteSetting(
pattern,
pattern,
CONTENT_SETTINGS_TYPE_PLUGINS,
resource1,
CONTENT_SETTING_BLOCK);
Value::CreateIntegerValue(CONTENT_SETTING_BLOCK));
EXPECT_EQ(CONTENT_SETTING_BLOCK,
GetContentSetting(
&pref_content_settings_provider,
......@@ -413,11 +415,11 @@ TEST_F(PrefProviderTest, SyncObsoletePref) {
ContentSettingsPattern::FromString("[*.]example.com");
ContentSettingsPattern secondary_pattern =
ContentSettingsPattern::Wildcard();
provider.SetContentSetting(primary_pattern,
provider.SetWebsiteSetting(primary_pattern,
secondary_pattern,
CONTENT_SETTINGS_TYPE_JAVASCRIPT,
std::string(),
CONTENT_SETTING_BLOCK);
Value::CreateIntegerValue(CONTENT_SETTING_BLOCK));
// Test whether the obsolete preference is synced correctly.
patterns = prefs->GetDictionary(prefs::kContentSettingsPatterns);
......@@ -679,12 +681,12 @@ TEST_F(PrefProviderTest, AutoSubmitCertificateContentSetting) {
std::string(),
false));
provider.SetContentSetting(
provider.SetWebsiteSetting(
ContentSettingsPattern::FromURL(primary_url),
ContentSettingsPattern::Wildcard(),
CONTENT_SETTINGS_TYPE_AUTO_SELECT_CERTIFICATE,
std::string(),
CONTENT_SETTING_ALLOW);
Value::CreateIntegerValue(CONTENT_SETTING_ALLOW));
EXPECT_EQ(CONTENT_SETTING_ALLOW,
GetContentSetting(
&provider,
......
......@@ -42,19 +42,20 @@ class ProviderInterface {
const ResourceIdentifier& resource_identifier,
bool incognito) const = 0;
// Sets the content setting for a particular |primary_pattern|,
// |secondary_pattern|, |content_type| tuple. For ContentSettingsTypes that
// require a resource identifier to be specified, the |resource_identifier|
// must be non-empty.
// Askes the provider to set the website setting for a particular
// |primary_pattern|, |secondary_pattern|, |content_type| tuple. If the
// provider accepts the setting it returns true and takes the ownership of the
// |value|. Otherwise false is returned and the ownership of the |value| stays
// with the caller.
//
// This should only be called on the UI thread, and not after
// ShutdownOnUIThread has been called.
virtual void SetContentSetting(
virtual bool SetWebsiteSetting(
const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_pattern,
ContentSettingsType content_type,
const ResourceIdentifier& resource_identifier,
ContentSetting content_setting) = 0;
Value* value) = 0;
// Resets all content settings for the given |content_type| and empty resource
// identifier to CONTENT_SETTING_DEFAULT.
......
......@@ -53,24 +53,28 @@ TEST(ContentSettingsProviderTest, Mock) {
CONTENT_SETTINGS_TYPE_GEOLOCATION, "",
false));
mock_provider.SetContentSetting(
bool owned = mock_provider.SetWebsiteSetting(
pattern,
pattern,
CONTENT_SETTINGS_TYPE_PLUGINS,
"java_plugin",
CONTENT_SETTING_ALLOW);
Value::CreateIntegerValue(CONTENT_SETTING_ALLOW));
EXPECT_TRUE(owned);
EXPECT_EQ(CONTENT_SETTING_ALLOW,
GetContentSetting(&mock_provider, url, url,
CONTENT_SETTINGS_TYPE_PLUGINS, "java_plugin",
false));
mock_provider.set_read_only(true);
mock_provider.SetContentSetting(
scoped_ptr<base::Value> value(
Value::CreateIntegerValue(CONTENT_SETTING_BLOCK));
owned = mock_provider.SetWebsiteSetting(
pattern,
pattern,
CONTENT_SETTINGS_TYPE_PLUGINS,
"java_plugin",
CONTENT_SETTING_BLOCK);
value.get());
EXPECT_FALSE(owned);
EXPECT_EQ(CONTENT_SETTING_ALLOW,
GetContentSetting(&mock_provider, url, url,
CONTENT_SETTINGS_TYPE_PLUGINS, "java_plugin",
......@@ -79,12 +83,13 @@ TEST(ContentSettingsProviderTest, Mock) {
EXPECT_TRUE(mock_provider.read_only());
mock_provider.set_read_only(false);
mock_provider.SetContentSetting(
owned = mock_provider.SetWebsiteSetting(
pattern,
pattern,
CONTENT_SETTINGS_TYPE_PLUGINS,
"java_plugin",
CONTENT_SETTING_BLOCK);
Value::CreateIntegerValue(CONTENT_SETTING_BLOCK));
EXPECT_TRUE(owned);
EXPECT_EQ(CONTENT_SETTING_BLOCK,
GetContentSetting(&mock_provider, url, url,
CONTENT_SETTINGS_TYPE_PLUGINS, "java_plugin",
......
......@@ -210,34 +210,53 @@ void HostContentSettingsMap::SetDefaultContentSetting(
DCHECK_NE(content_type, CONTENT_SETTINGS_TYPE_AUTO_SELECT_CERTIFICATE);
DCHECK(IsSettingAllowedForType(setting, content_type));
content_settings_providers_[DEFAULT_PROVIDER]->SetContentSetting(
base::Value* value = Value::CreateIntegerValue(setting);
content_settings_providers_[DEFAULT_PROVIDER]->SetWebsiteSetting(
ContentSettingsPattern::Wildcard(),
ContentSettingsPattern::Wildcard(),
content_type,
std::string(),
setting);
value);
}
void HostContentSettingsMap::SetContentSetting(
void HostContentSettingsMap::SetWebsiteSetting(
const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_pattern,
ContentSettingsType content_type,
const std::string& resource_identifier,
ContentSetting setting) {
DCHECK_NE(content_type, CONTENT_SETTINGS_TYPE_AUTO_SELECT_CERTIFICATE);
DCHECK(IsSettingAllowedForType(setting, content_type));
base::Value* value) {
DCHECK(IsValueAllowedForType(value, content_type));
DCHECK(content_settings::SupportsResourceIdentifier(content_type) ||
resource_identifier.empty());
for (ProviderIterator provider = content_settings_providers_.begin();
provider != content_settings_providers_.end();
++provider) {
provider->second->SetContentSetting(
primary_pattern,
if (provider->second->SetWebsiteSetting(primary_pattern,
secondary_pattern,
content_type,
resource_identifier,
setting);
value)) {
return;
}
}
NOTREACHED();
}
void HostContentSettingsMap::SetContentSetting(
const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_pattern,
ContentSettingsType content_type,
const std::string& resource_identifier,
ContentSetting setting) {
DCHECK_NE(content_type, CONTENT_SETTINGS_TYPE_AUTO_SELECT_CERTIFICATE);
base::Value* value = NULL;
if (setting != CONTENT_SETTING_DEFAULT)
value = Value::CreateIntegerValue(setting);
SetWebsiteSetting(primary_pattern,
secondary_pattern,
content_type,
resource_identifier,
value);
}
void HostContentSettingsMap::AddExceptionForURL(
......@@ -274,6 +293,12 @@ void HostContentSettingsMap::ClearSettingsForOneType(
}
}
bool HostContentSettingsMap::IsValueAllowedForType(
const base::Value* value, ContentSettingsType type) {
return IsSettingAllowedForType(
content_settings::ValueToContentSetting(value), type);
}
// static
bool HostContentSettingsMap::IsSettingAllowedForType(
ContentSetting setting, ContentSettingsType content_type) {
......
......@@ -109,11 +109,13 @@ class HostContentSettingsMap
void SetDefaultContentSetting(ContentSettingsType content_type,
ContentSetting setting);
// Sets the content setting for the given patterns and content type.
// Setting the value to CONTENT_SETTING_DEFAULT causes the default setting
// for that type to be used when loading pages matching this pattern. For
// ContentSettingsTypes that require an resource identifier to be specified,
// the |resource_identifier| must be non-empty.
// Sets the content |setting| for the given patterns, |content_type| and
// |resource_identifier|. Setting the value to CONTENT_SETTING_DEFAULT causes
// the default setting for that type to be used when loading pages matching
// this pattern.
// NOTICE: This is just a convenience method for content types that use
// |CONTENT_SETTING| as their data type. For content types that use other
// data types please use the method SetWebsiteSetting.
//
// This should only be called on the UI thread.
void SetContentSetting(const ContentSettingsPattern& primary_pattern,
......@@ -122,6 +124,17 @@ class HostContentSettingsMap
const std::string& resource_identifier,
ContentSetting setting);
// Sets the |value| for the given patterns, |content_type| and
// |resource_identifier|. Setting the value to NULL causes the default value
// for that type to be used when loading pages matching this pattern.
//
// Takes ownership of the passed value.
void SetWebsiteSetting(const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_pattern,
ContentSettingsType content_type,
const std::string& resource_identifier,
base::Value* value);
// Convenience method to add a content setting for the given URLs, making sure
// that there is no setting overriding it. For ContentSettingsTypes that
// require an resource identifier to be specified, the |resource_identifier|
......@@ -139,6 +152,8 @@ class HostContentSettingsMap
// This should only be called on the UI thread.
void ClearSettingsForOneType(ContentSettingsType content_type);
static bool IsValueAllowedForType(const base::Value* value,
ContentSettingsType content_type);
static bool IsSettingAllowedForType(ContentSetting setting,
ContentSettingsType content_type);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment