Home | History | Annotate | Download | only in content_settings
      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