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