Introduce ProfilerMetricsProvider
[chromium-blink-merge.git] / chrome / browser / content_settings / content_settings_default_provider.cc
blob9f278790b249347180f41d81d2907a8e7f1ec72f
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"
7 #include <string>
8 #include <vector>
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/pref_registry/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"
27 #include "url/gurl.h"
29 using base::UserMetricsAction;
30 using content::BrowserThread;
32 namespace {
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
54 #if defined(OS_WIN)
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
58 #endif
59 #if defined(OS_ANDROID)
60 CONTENT_SETTING_DEFAULT, // CONTENT_SETTINGS_TYPE_APP_BANNER
61 #endif
63 COMPILE_ASSERT(arraysize(kDefaultSettings) == CONTENT_SETTINGS_NUM_TYPES,
64 default_settings_incorrect_size);
66 } // namespace
68 namespace content_settings {
70 namespace {
72 class DefaultRuleIterator : public RuleIterator {
73 public:
74 explicit DefaultRuleIterator(const base::Value* value) {
75 if (value)
76 value_.reset(value->DeepCopy());
79 virtual bool HasNext() const OVERRIDE {
80 return value_.get() != NULL;
83 virtual Rule Next() OVERRIDE {
84 DCHECK(value_.get());
85 return Rule(ContentSettingsPattern::Wildcard(),
86 ContentSettingsPattern::Wildcard(),
87 value_.release());
90 private:
91 scoped_ptr<base::Value> value_;
94 } // namespace
96 // static
97 void DefaultProvider::RegisterProfilePrefs(
98 user_prefs::PrefRegistrySyncable* registry) {
99 // The registration of the preference prefs::kDefaultContentSettings should
100 // also include the default values for default content settings. This allows
101 // functional tests to get default content settings by reading the preference
102 // prefs::kDefaultContentSettings via pyauto.
103 // TODO(markusheintz): Write pyauto hooks for the content settings map as
104 // content settings should be read from the host content settings map.
105 base::DictionaryValue* default_content_settings = new base::DictionaryValue();
106 registry->RegisterDictionaryPref(
107 prefs::kDefaultContentSettings,
108 default_content_settings,
109 user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
112 DefaultProvider::DefaultProvider(PrefService* prefs, bool incognito)
113 : prefs_(prefs),
114 is_incognito_(incognito),
115 updating_preferences_(false) {
116 DCHECK(prefs_);
118 // Read global defaults.
119 ReadDefaultSettings(true);
121 UMA_HISTOGRAM_ENUMERATION(
122 "ContentSettings.DefaultCookiesSetting",
123 ValueToContentSetting(
124 default_settings_[CONTENT_SETTINGS_TYPE_COOKIES].get()),
125 CONTENT_SETTING_NUM_SETTINGS);
126 UMA_HISTOGRAM_ENUMERATION(
127 "ContentSettings.DefaultImagesSetting",
128 ValueToContentSetting(
129 default_settings_[CONTENT_SETTINGS_TYPE_IMAGES].get()),
130 CONTENT_SETTING_NUM_SETTINGS);
131 UMA_HISTOGRAM_ENUMERATION(
132 "ContentSettings.DefaultJavaScriptSetting",
133 ValueToContentSetting(
134 default_settings_[CONTENT_SETTINGS_TYPE_JAVASCRIPT].get()),
135 CONTENT_SETTING_NUM_SETTINGS);
136 UMA_HISTOGRAM_ENUMERATION(
137 "ContentSettings.DefaultPluginsSetting",
138 ValueToContentSetting(
139 default_settings_[CONTENT_SETTINGS_TYPE_PLUGINS].get()),
140 CONTENT_SETTING_NUM_SETTINGS);
141 UMA_HISTOGRAM_ENUMERATION(
142 "ContentSettings.DefaultPopupsSetting",
143 ValueToContentSetting(
144 default_settings_[CONTENT_SETTINGS_TYPE_POPUPS].get()),
145 CONTENT_SETTING_NUM_SETTINGS);
146 UMA_HISTOGRAM_ENUMERATION(
147 "ContentSettings.DefaultLocationSetting",
148 ValueToContentSetting(
149 default_settings_[CONTENT_SETTINGS_TYPE_GEOLOCATION].get()),
150 CONTENT_SETTING_NUM_SETTINGS);
151 UMA_HISTOGRAM_ENUMERATION(
152 "ContentSettings.DefaultNotificationsSetting",
153 ValueToContentSetting(
154 default_settings_[CONTENT_SETTINGS_TYPE_NOTIFICATIONS].get()),
155 CONTENT_SETTING_NUM_SETTINGS);
156 UMA_HISTOGRAM_ENUMERATION(
157 "ContentSettings.DefaultMouseCursorSetting",
158 ValueToContentSetting(
159 default_settings_[CONTENT_SETTINGS_TYPE_MOUSELOCK].get()),
160 CONTENT_SETTING_NUM_SETTINGS);
161 UMA_HISTOGRAM_ENUMERATION(
162 "ContentSettings.DefaultMediaStreamSetting",
163 ValueToContentSetting(
164 default_settings_[CONTENT_SETTINGS_TYPE_MEDIASTREAM].get()),
165 CONTENT_SETTING_NUM_SETTINGS);
166 UMA_HISTOGRAM_ENUMERATION(
167 "ContentSettings.DefaultMIDISysExSetting",
168 ValueToContentSetting(
169 default_settings_[CONTENT_SETTINGS_TYPE_MIDI_SYSEX].get()),
170 CONTENT_SETTING_NUM_SETTINGS);
172 pref_change_registrar_.Init(prefs_);
173 PrefChangeRegistrar::NamedChangeCallback callback = base::Bind(
174 &DefaultProvider::OnPreferenceChanged, base::Unretained(this));
175 pref_change_registrar_.Add(prefs::kDefaultContentSettings, callback);
178 DefaultProvider::~DefaultProvider() {
181 bool DefaultProvider::SetWebsiteSetting(
182 const ContentSettingsPattern& primary_pattern,
183 const ContentSettingsPattern& secondary_pattern,
184 ContentSettingsType content_type,
185 const ResourceIdentifier& resource_identifier,
186 base::Value* in_value) {
187 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
188 DCHECK(prefs_);
190 // Ignore non default settings
191 if (primary_pattern != ContentSettingsPattern::Wildcard() ||
192 secondary_pattern != ContentSettingsPattern::Wildcard()) {
193 return false;
196 // The default settings may not be directly modified for OTR sessions.
197 // Instead, they are synced to the main profile's setting.
198 if (is_incognito_)
199 return false;
201 // Put |in_value| in a scoped pointer to ensure that it gets cleaned up
202 // properly if we don't pass on the ownership.
203 scoped_ptr<base::Value> value(in_value);
205 base::AutoReset<bool> auto_reset(&updating_preferences_, true);
207 // |DefaultProvider| should not send any notifications when holding
208 // |lock_|. |DictionaryPrefUpdate| destructor and
209 // |PrefService::SetInteger()| send out notifications. As a response, the
210 // upper layers may call |GetAllContentSettingRules| which acquires |lock_|
211 // again.
212 DictionaryPrefUpdate update(prefs_, prefs::kDefaultContentSettings);
213 base::DictionaryValue* default_settings_dictionary = update.Get();
214 base::AutoLock lock(lock_);
215 if (value.get() == NULL ||
216 ValueToContentSetting(value.get()) == kDefaultSettings[content_type]) {
217 // If |value| is NULL we need to reset the default setting the the
218 // hardcoded default.
219 default_settings_[content_type].reset(
220 base::Value::CreateIntegerValue(kDefaultSettings[content_type]));
222 // Remove the corresponding pref entry since the hardcoded default value
223 // is used.
224 default_settings_dictionary->RemoveWithoutPathExpansion(
225 GetTypeName(content_type), NULL);
226 } else {
227 default_settings_[content_type].reset(value->DeepCopy());
228 // Transfer ownership of |value| to the |default_settings_dictionary|.
229 default_settings_dictionary->SetWithoutPathExpansion(
230 GetTypeName(content_type), value.release());
234 NotifyObservers(ContentSettingsPattern(),
235 ContentSettingsPattern(),
236 content_type,
237 std::string());
239 return true;
242 RuleIterator* DefaultProvider::GetRuleIterator(
243 ContentSettingsType content_type,
244 const ResourceIdentifier& resource_identifier,
245 bool incognito) const {
246 base::AutoLock lock(lock_);
247 if (resource_identifier.empty()) {
248 ValueMap::const_iterator it(default_settings_.find(content_type));
249 if (it != default_settings_.end()) {
250 return new DefaultRuleIterator(it->second.get());
252 NOTREACHED();
254 return new EmptyRuleIterator();
257 void DefaultProvider::ClearAllContentSettingsRules(
258 ContentSettingsType content_type) {
259 // TODO(markusheintz): This method is only called when the
260 // |DesktopNotificationService| calls |ClearAllSettingsForType| method on the
261 // |HostContentSettingsMap|. Don't implement this method yet, otherwise the
262 // default notification settings will be cleared as well.
265 void DefaultProvider::ShutdownOnUIThread() {
266 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
267 DCHECK(prefs_);
268 RemoveAllObservers();
269 pref_change_registrar_.RemoveAll();
270 prefs_ = NULL;
273 void DefaultProvider::OnPreferenceChanged(const std::string& name) {
274 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
275 if (updating_preferences_)
276 return;
278 if (name == prefs::kDefaultContentSettings) {
279 ReadDefaultSettings(true);
280 } else {
281 NOTREACHED() << "Unexpected preference observed";
282 return;
285 NotifyObservers(ContentSettingsPattern(),
286 ContentSettingsPattern(),
287 CONTENT_SETTINGS_TYPE_DEFAULT,
288 std::string());
291 void DefaultProvider::ReadDefaultSettings(bool overwrite) {
292 base::AutoLock lock(lock_);
293 const base::DictionaryValue* default_settings_dictionary =
294 prefs_->GetDictionary(prefs::kDefaultContentSettings);
296 if (overwrite)
297 default_settings_.clear();
299 // Careful: The returned value could be NULL if the pref has never been set.
300 if (default_settings_dictionary)
301 GetSettingsFromDictionary(default_settings_dictionary);
303 ForceDefaultsToBeExplicit();
306 void DefaultProvider::ForceDefaultsToBeExplicit() {
307 for (int i = 0; i < CONTENT_SETTINGS_NUM_TYPES; ++i) {
308 ContentSettingsType type = ContentSettingsType(i);
309 if (!default_settings_[type].get() &&
310 kDefaultSettings[i] != CONTENT_SETTING_DEFAULT) {
311 default_settings_[type].reset(
312 base::Value::CreateIntegerValue(kDefaultSettings[i]));
317 void DefaultProvider::GetSettingsFromDictionary(
318 const base::DictionaryValue* dictionary) {
319 for (base::DictionaryValue::Iterator i(*dictionary);
320 !i.IsAtEnd(); i.Advance()) {
321 const std::string& content_type(i.key());
322 for (size_t type = 0; type < CONTENT_SETTINGS_NUM_TYPES; ++type) {
323 if (content_type == GetTypeName(ContentSettingsType(type))) {
324 int int_value = CONTENT_SETTING_DEFAULT;
325 bool is_integer = i.value().GetAsInteger(&int_value);
326 DCHECK(is_integer);
327 default_settings_[ContentSettingsType(type)].reset(
328 base::Value::CreateIntegerValue(int_value));
329 break;
333 // Migrate obsolete cookie prompt mode.
334 if (ValueToContentSetting(
335 default_settings_[CONTENT_SETTINGS_TYPE_COOKIES].get()) ==
336 CONTENT_SETTING_ASK) {
337 default_settings_[CONTENT_SETTINGS_TYPE_COOKIES].reset(
338 base::Value::CreateIntegerValue(CONTENT_SETTING_BLOCK));
342 } // namespace content_settings