1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/content_settings/content_settings_default_provider.h"
10 #include "base/auto_reset.h"
11 #include "base/basictypes.h"
12 #include "base/command_line.h"
13 #include "base/metrics/histogram.h"
14 #include "base/prefs/pref_service.h"
15 #include "base/prefs/scoped_user_pref_update.h"
16 #include "chrome/browser/chrome_notification_types.h"
17 #include "chrome/browser/content_settings/content_settings_rule.h"
18 #include "chrome/browser/content_settings/content_settings_utils.h"
19 #include "chrome/common/content_settings.h"
20 #include "chrome/common/content_settings_pattern.h"
21 #include "chrome/common/pref_names.h"
22 #include "components/user_prefs/pref_registry_syncable.h"
23 #include "content/public/browser/browser_thread.h"
24 #include "content/public/browser/notification_details.h"
25 #include "content/public/browser/notification_source.h"
26 #include "content/public/browser/user_metrics.h"
29 using base::UserMetricsAction
;
30 using content::BrowserThread
;
34 // The default setting for each content type.
35 const ContentSetting kDefaultSettings
[] = {
36 CONTENT_SETTING_ALLOW
, // CONTENT_SETTINGS_TYPE_COOKIES
37 CONTENT_SETTING_ALLOW
, // CONTENT_SETTINGS_TYPE_IMAGES
38 CONTENT_SETTING_ALLOW
, // CONTENT_SETTINGS_TYPE_JAVASCRIPT
39 CONTENT_SETTING_ALLOW
, // CONTENT_SETTINGS_TYPE_PLUGINS
40 CONTENT_SETTING_BLOCK
, // CONTENT_SETTINGS_TYPE_POPUPS
41 CONTENT_SETTING_ASK
, // CONTENT_SETTINGS_TYPE_GEOLOCATION
42 CONTENT_SETTING_ASK
, // CONTENT_SETTINGS_TYPE_NOTIFICATIONS
43 CONTENT_SETTING_DEFAULT
, // CONTENT_SETTINGS_TYPE_AUTO_SELECT_CERTIFICATE
44 CONTENT_SETTING_ASK
, // CONTENT_SETTINGS_TYPE_FULLSCREEN
45 CONTENT_SETTING_ASK
, // CONTENT_SETTINGS_TYPE_MOUSELOCK
46 CONTENT_SETTING_DEFAULT
, // CONTENT_SETTINGS_TYPE_MIXEDSCRIPT
47 CONTENT_SETTING_ASK
, // CONTENT_SETTINGS_TYPE_MEDIASTREAM
48 CONTENT_SETTING_ASK
, // CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC
49 CONTENT_SETTING_ASK
, // CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA
50 CONTENT_SETTING_DEFAULT
, // CONTENT_SETTINGS_TYPE_PROTOCOL_HANDLERS
51 CONTENT_SETTING_ASK
, // CONTENT_SETTINGS_TYPE_PPAPI_BROKER
52 CONTENT_SETTING_ASK
, // CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS
53 CONTENT_SETTING_ASK
, // CONTENT_SETTINGS_TYPE_MIDI_SYSEX
55 CONTENT_SETTING_ASK
, // CONTENT_SETTINGS_TYPE_METRO_SWITCH_TO_DESKTOP
56 #elif defined(OS_ANDROID) || defined(OS_CHROMEOS)
57 CONTENT_SETTING_ASK
, // CONTENT_SETTINGS_TYPE_PROTECTED_MEDIA_IDENTIFIER
60 COMPILE_ASSERT(arraysize(kDefaultSettings
) == CONTENT_SETTINGS_NUM_TYPES
,
61 default_settings_incorrect_size
);
65 namespace content_settings
{
69 class DefaultRuleIterator
: public RuleIterator
{
71 explicit DefaultRuleIterator(const base::Value
* value
) {
73 value_
.reset(value
->DeepCopy());
76 virtual bool HasNext() const OVERRIDE
{
77 return value_
.get() != NULL
;
80 virtual Rule
Next() OVERRIDE
{
82 return Rule(ContentSettingsPattern::Wildcard(),
83 ContentSettingsPattern::Wildcard(),
88 scoped_ptr
<base::Value
> value_
;
94 void DefaultProvider::RegisterProfilePrefs(
95 user_prefs::PrefRegistrySyncable
* registry
) {
96 // The registration of the preference prefs::kDefaultContentSettings should
97 // also include the default values for default content settings. This allows
98 // functional tests to get default content settings by reading the preference
99 // prefs::kDefaultContentSettings via pyauto.
100 // TODO(markusheintz): Write pyauto hooks for the content settings map as
101 // content settings should be read from the host content settings map.
102 base::DictionaryValue
* default_content_settings
= new base::DictionaryValue();
103 registry
->RegisterDictionaryPref(
104 prefs::kDefaultContentSettings
,
105 default_content_settings
,
106 user_prefs::PrefRegistrySyncable::SYNCABLE_PREF
);
109 DefaultProvider::DefaultProvider(PrefService
* prefs
, bool incognito
)
111 is_incognito_(incognito
),
112 updating_preferences_(false) {
115 // Read global defaults.
116 ReadDefaultSettings(true);
118 UMA_HISTOGRAM_ENUMERATION(
119 "ContentSettings.DefaultCookiesSetting",
120 ValueToContentSetting(
121 default_settings_
[CONTENT_SETTINGS_TYPE_COOKIES
].get()),
122 CONTENT_SETTING_NUM_SETTINGS
);
123 UMA_HISTOGRAM_ENUMERATION(
124 "ContentSettings.DefaultImagesSetting",
125 ValueToContentSetting(
126 default_settings_
[CONTENT_SETTINGS_TYPE_IMAGES
].get()),
127 CONTENT_SETTING_NUM_SETTINGS
);
128 UMA_HISTOGRAM_ENUMERATION(
129 "ContentSettings.DefaultJavaScriptSetting",
130 ValueToContentSetting(
131 default_settings_
[CONTENT_SETTINGS_TYPE_JAVASCRIPT
].get()),
132 CONTENT_SETTING_NUM_SETTINGS
);
133 UMA_HISTOGRAM_ENUMERATION(
134 "ContentSettings.DefaultPluginsSetting",
135 ValueToContentSetting(
136 default_settings_
[CONTENT_SETTINGS_TYPE_PLUGINS
].get()),
137 CONTENT_SETTING_NUM_SETTINGS
);
138 UMA_HISTOGRAM_ENUMERATION(
139 "ContentSettings.DefaultPopupsSetting",
140 ValueToContentSetting(
141 default_settings_
[CONTENT_SETTINGS_TYPE_POPUPS
].get()),
142 CONTENT_SETTING_NUM_SETTINGS
);
143 UMA_HISTOGRAM_ENUMERATION(
144 "ContentSettings.DefaultLocationSetting",
145 ValueToContentSetting(
146 default_settings_
[CONTENT_SETTINGS_TYPE_GEOLOCATION
].get()),
147 CONTENT_SETTING_NUM_SETTINGS
);
148 UMA_HISTOGRAM_ENUMERATION(
149 "ContentSettings.DefaultNotificationsSetting",
150 ValueToContentSetting(
151 default_settings_
[CONTENT_SETTINGS_TYPE_NOTIFICATIONS
].get()),
152 CONTENT_SETTING_NUM_SETTINGS
);
153 UMA_HISTOGRAM_ENUMERATION(
154 "ContentSettings.DefaultMouseCursorSetting",
155 ValueToContentSetting(
156 default_settings_
[CONTENT_SETTINGS_TYPE_MOUSELOCK
].get()),
157 CONTENT_SETTING_NUM_SETTINGS
);
158 UMA_HISTOGRAM_ENUMERATION(
159 "ContentSettings.DefaultMediaStreamSetting",
160 ValueToContentSetting(
161 default_settings_
[CONTENT_SETTINGS_TYPE_MEDIASTREAM
].get()),
162 CONTENT_SETTING_NUM_SETTINGS
);
163 UMA_HISTOGRAM_ENUMERATION(
164 "ContentSettings.DefaultMIDISysExSetting",
165 ValueToContentSetting(
166 default_settings_
[CONTENT_SETTINGS_TYPE_MIDI_SYSEX
].get()),
167 CONTENT_SETTING_NUM_SETTINGS
);
169 pref_change_registrar_
.Init(prefs_
);
170 PrefChangeRegistrar::NamedChangeCallback callback
= base::Bind(
171 &DefaultProvider::OnPreferenceChanged
, base::Unretained(this));
172 pref_change_registrar_
.Add(prefs::kDefaultContentSettings
, callback
);
175 DefaultProvider::~DefaultProvider() {
178 bool DefaultProvider::SetWebsiteSetting(
179 const ContentSettingsPattern
& primary_pattern
,
180 const ContentSettingsPattern
& secondary_pattern
,
181 ContentSettingsType content_type
,
182 const ResourceIdentifier
& resource_identifier
,
183 base::Value
* in_value
) {
184 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
187 // Ignore non default settings
188 if (primary_pattern
!= ContentSettingsPattern::Wildcard() ||
189 secondary_pattern
!= ContentSettingsPattern::Wildcard()) {
193 // The default settings may not be directly modified for OTR sessions.
194 // Instead, they are synced to the main profile's setting.
198 // Put |in_value| in a scoped pointer to ensure that it gets cleaned up
199 // properly if we don't pass on the ownership.
200 scoped_ptr
<base::Value
> value(in_value
);
202 base::AutoReset
<bool> auto_reset(&updating_preferences_
, true);
204 // |DefaultProvider| should not send any notifications when holding
205 // |lock_|. |DictionaryPrefUpdate| destructor and
206 // |PrefService::SetInteger()| send out notifications. As a response, the
207 // upper layers may call |GetAllContentSettingRules| which acquires |lock_|
209 DictionaryPrefUpdate
update(prefs_
, prefs::kDefaultContentSettings
);
210 base::DictionaryValue
* default_settings_dictionary
= update
.Get();
211 base::AutoLock
lock(lock_
);
212 if (value
.get() == NULL
||
213 ValueToContentSetting(value
.get()) == kDefaultSettings
[content_type
]) {
214 // If |value| is NULL we need to reset the default setting the the
215 // hardcoded default.
216 default_settings_
[content_type
].reset(
217 base::Value::CreateIntegerValue(kDefaultSettings
[content_type
]));
219 // Remove the corresponding pref entry since the hardcoded default value
221 default_settings_dictionary
->RemoveWithoutPathExpansion(
222 GetTypeName(content_type
), NULL
);
224 default_settings_
[content_type
].reset(value
->DeepCopy());
225 // Transfer ownership of |value| to the |default_settings_dictionary|.
226 default_settings_dictionary
->SetWithoutPathExpansion(
227 GetTypeName(content_type
), value
.release());
231 NotifyObservers(ContentSettingsPattern(),
232 ContentSettingsPattern(),
239 RuleIterator
* DefaultProvider::GetRuleIterator(
240 ContentSettingsType content_type
,
241 const ResourceIdentifier
& resource_identifier
,
242 bool incognito
) const {
243 base::AutoLock
lock(lock_
);
244 if (resource_identifier
.empty()) {
245 ValueMap::const_iterator
it(default_settings_
.find(content_type
));
246 if (it
!= default_settings_
.end()) {
247 return new DefaultRuleIterator(it
->second
.get());
251 return new EmptyRuleIterator();
254 void DefaultProvider::ClearAllContentSettingsRules(
255 ContentSettingsType content_type
) {
256 // TODO(markusheintz): This method is only called when the
257 // |DesktopNotificationService| calls |ClearAllSettingsForType| method on the
258 // |HostContentSettingsMap|. Don't implement this method yet, otherwise the
259 // default notification settings will be cleared as well.
262 void DefaultProvider::ShutdownOnUIThread() {
263 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
265 RemoveAllObservers();
266 pref_change_registrar_
.RemoveAll();
270 void DefaultProvider::OnPreferenceChanged(const std::string
& name
) {
271 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
272 if (updating_preferences_
)
275 if (name
== prefs::kDefaultContentSettings
) {
276 ReadDefaultSettings(true);
278 NOTREACHED() << "Unexpected preference observed";
282 NotifyObservers(ContentSettingsPattern(),
283 ContentSettingsPattern(),
284 CONTENT_SETTINGS_TYPE_DEFAULT
,
288 void DefaultProvider::ReadDefaultSettings(bool overwrite
) {
289 base::AutoLock
lock(lock_
);
290 const base::DictionaryValue
* default_settings_dictionary
=
291 prefs_
->GetDictionary(prefs::kDefaultContentSettings
);
294 default_settings_
.clear();
296 // Careful: The returned value could be NULL if the pref has never been set.
297 if (default_settings_dictionary
)
298 GetSettingsFromDictionary(default_settings_dictionary
);
300 ForceDefaultsToBeExplicit();
303 void DefaultProvider::ForceDefaultsToBeExplicit() {
304 for (int i
= 0; i
< CONTENT_SETTINGS_NUM_TYPES
; ++i
) {
305 ContentSettingsType type
= ContentSettingsType(i
);
306 if (!default_settings_
[type
].get() &&
307 kDefaultSettings
[i
] != CONTENT_SETTING_DEFAULT
) {
308 default_settings_
[type
].reset(
309 base::Value::CreateIntegerValue(kDefaultSettings
[i
]));
314 void DefaultProvider::GetSettingsFromDictionary(
315 const base::DictionaryValue
* dictionary
) {
316 for (base::DictionaryValue::Iterator
i(*dictionary
);
317 !i
.IsAtEnd(); i
.Advance()) {
318 const std::string
& content_type(i
.key());
319 for (size_t type
= 0; type
< CONTENT_SETTINGS_NUM_TYPES
; ++type
) {
320 if (content_type
== GetTypeName(ContentSettingsType(type
))) {
321 int int_value
= CONTENT_SETTING_DEFAULT
;
322 bool is_integer
= i
.value().GetAsInteger(&int_value
);
324 default_settings_
[ContentSettingsType(type
)].reset(
325 base::Value::CreateIntegerValue(int_value
));
330 // Migrate obsolete cookie prompt mode.
331 if (ValueToContentSetting(
332 default_settings_
[CONTENT_SETTINGS_TYPE_COOKIES
].get()) ==
333 CONTENT_SETTING_ASK
) {
334 default_settings_
[CONTENT_SETTINGS_TYPE_COOKIES
].reset(
335 base::Value::CreateIntegerValue(CONTENT_SETTING_BLOCK
));
339 } // namespace content_settings