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