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/host_content_settings_map.h"
      6 
      7 #include <utility>
      8 
      9 #include "base/basictypes.h"
     10 #include "base/command_line.h"
     11 #include "base/prefs/pref_service.h"
     12 #include "base/stl_util.h"
     13 #include "base/strings/string_util.h"
     14 #include "base/strings/utf_string_conversions.h"
     15 #include "base/time/clock.h"
     16 #include "chrome/browser/content_settings/content_settings_default_provider.h"
     17 #include "chrome/browser/content_settings/content_settings_policy_provider.h"
     18 #include "chrome/browser/content_settings/content_settings_pref_provider.h"
     19 #include "chrome/browser/content_settings/content_settings_utils.h"
     20 #include "chrome/common/chrome_switches.h"
     21 #include "chrome/common/pref_names.h"
     22 #include "chrome/common/url_constants.h"
     23 #include "components/content_settings/core/browser/content_settings_details.h"
     24 #include "components/content_settings/core/browser/content_settings_observable_provider.h"
     25 #include "components/content_settings/core/browser/content_settings_provider.h"
     26 #include "components/content_settings/core/browser/content_settings_rule.h"
     27 #include "components/content_settings/core/common/content_settings_pattern.h"
     28 #include "components/pref_registry/pref_registry_syncable.h"
     29 #include "content/public/browser/browser_thread.h"
     30 #include "content/public/common/content_switches.h"
     31 #include "net/base/net_errors.h"
     32 #include "net/base/static_cookie_policy.h"
     33 #include "url/gurl.h"
     34 
     35 #if defined(ENABLE_EXTENSIONS)
     36 #include "extensions/common/constants.h"
     37 #endif
     38 
     39 using content::BrowserThread;
     40 
     41 namespace {
     42 
     43 typedef std::vector<content_settings::Rule> Rules;
     44 
     45 typedef std::pair<std::string, std::string> StringPair;
     46 
     47 // TODO(bauerb): Expose constants.
     48 const char* kProviderNames[] = {
     49   "platform_app",
     50   "policy",
     51   "extension",
     52   "override",
     53   "preference",
     54   "default"
     55 };
     56 
     57 content_settings::SettingSource kProviderSourceMap[] = {
     58   content_settings::SETTING_SOURCE_EXTENSION,
     59   content_settings::SETTING_SOURCE_POLICY,
     60   content_settings::SETTING_SOURCE_EXTENSION,
     61   content_settings::SETTING_SOURCE_USER,
     62   content_settings::SETTING_SOURCE_USER,
     63   content_settings::SETTING_SOURCE_USER,
     64 };
     65 COMPILE_ASSERT(arraysize(kProviderSourceMap) ==
     66                    HostContentSettingsMap::NUM_PROVIDER_TYPES,
     67                kProviderSourceMap_has_incorrect_size);
     68 
     69 // Returns true if the |content_type| supports a resource identifier.
     70 // Resource identifiers are supported (but not required) for plug-ins.
     71 bool SupportsResourceIdentifier(ContentSettingsType content_type) {
     72   return content_type == CONTENT_SETTINGS_TYPE_PLUGINS;
     73 }
     74 
     75 }  // namespace
     76 
     77 HostContentSettingsMap::HostContentSettingsMap(PrefService* prefs,
     78                                                bool incognito)
     79     :
     80 #ifndef NDEBUG
     81       used_from_thread_id_(base::PlatformThread::CurrentId()),
     82 #endif
     83       prefs_(prefs),
     84       is_off_the_record_(incognito) {
     85   content_settings::ObservableProvider* policy_provider =
     86       new content_settings::PolicyProvider(prefs_);
     87   policy_provider->AddObserver(this);
     88   content_settings_providers_[POLICY_PROVIDER] = policy_provider;
     89 
     90   content_settings::ObservableProvider* pref_provider =
     91       new content_settings::PrefProvider(prefs_, is_off_the_record_);
     92   pref_provider->AddObserver(this);
     93   content_settings_providers_[PREF_PROVIDER] = pref_provider;
     94 
     95   content_settings::ObservableProvider* default_provider =
     96       new content_settings::DefaultProvider(prefs_, is_off_the_record_);
     97   default_provider->AddObserver(this);
     98   content_settings_providers_[DEFAULT_PROVIDER] = default_provider;
     99 
    100   content_settings_providers_[OVERRIDE_PROVIDER] =
    101       new content_settings::OverrideProvider(prefs_, is_off_the_record_);
    102 
    103   if (!is_off_the_record_) {
    104     // Migrate obsolete preferences.
    105     MigrateObsoleteClearOnExitPref();
    106   }
    107 }
    108 
    109 // static
    110 void HostContentSettingsMap::RegisterProfilePrefs(
    111     user_prefs::PrefRegistrySyncable* registry) {
    112   registry->RegisterIntegerPref(
    113       prefs::kContentSettingsWindowLastTabIndex,
    114       0,
    115       user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
    116   registry->RegisterBooleanPref(
    117       prefs::kContentSettingsClearOnExitMigrated,
    118       false,
    119       user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
    120 
    121   // Register the prefs for the content settings providers.
    122   content_settings::DefaultProvider::RegisterProfilePrefs(registry);
    123   content_settings::PrefProvider::RegisterProfilePrefs(registry);
    124   content_settings::PolicyProvider::RegisterProfilePrefs(registry);
    125   content_settings::OverrideProvider::RegisterProfilePrefs(registry);
    126 }
    127 
    128 void HostContentSettingsMap::RegisterProvider(
    129     ProviderType type,
    130     scoped_ptr<content_settings::ObservableProvider> provider) {
    131   DCHECK(!content_settings_providers_[type]);
    132   provider->AddObserver(this);
    133   content_settings_providers_[type] = provider.release();
    134 
    135 #ifndef NDEBUG
    136   DCHECK_NE(used_from_thread_id_, base::kInvalidThreadId)
    137       << "Used from multiple threads before initialization complete.";
    138 #endif
    139 
    140   OnContentSettingChanged(ContentSettingsPattern(),
    141                           ContentSettingsPattern(),
    142                           CONTENT_SETTINGS_TYPE_DEFAULT,
    143                           std::string());
    144 }
    145 
    146 ContentSetting HostContentSettingsMap::GetDefaultContentSettingFromProvider(
    147     ContentSettingsType content_type,
    148     content_settings::ProviderInterface* provider) const {
    149   scoped_ptr<content_settings::RuleIterator> rule_iterator(
    150       provider->GetRuleIterator(content_type, std::string(), false));
    151 
    152   ContentSettingsPattern wildcard = ContentSettingsPattern::Wildcard();
    153   while (rule_iterator->HasNext()) {
    154     content_settings::Rule rule = rule_iterator->Next();
    155     if (rule.primary_pattern == wildcard &&
    156         rule.secondary_pattern == wildcard) {
    157       return content_settings::ValueToContentSetting(rule.value.get());
    158     }
    159   }
    160   return CONTENT_SETTING_DEFAULT;
    161 }
    162 
    163 ContentSetting HostContentSettingsMap::GetDefaultContentSetting(
    164     ContentSettingsType content_type,
    165     std::string* provider_id) const {
    166   UsedContentSettingsProviders();
    167 
    168   // Iterate through the list of providers and return the first non-NULL value
    169   // that matches |primary_url| and |secondary_url|.
    170   for (ConstProviderIterator provider = content_settings_providers_.begin();
    171        provider != content_settings_providers_.end();
    172        ++provider) {
    173     if (provider->first == PREF_PROVIDER ||
    174         provider->first == OVERRIDE_PROVIDER)
    175       continue;
    176     ContentSetting default_setting =
    177         GetDefaultContentSettingFromProvider(content_type, provider->second);
    178     if (default_setting != CONTENT_SETTING_DEFAULT) {
    179       if (provider_id)
    180         *provider_id = kProviderNames[provider->first];
    181       return default_setting;
    182     }
    183   }
    184 
    185   return CONTENT_SETTING_DEFAULT;
    186 }
    187 
    188 ContentSetting HostContentSettingsMap::GetContentSetting(
    189     const GURL& primary_url,
    190     const GURL& secondary_url,
    191     ContentSettingsType content_type,
    192     const std::string& resource_identifier) const {
    193   DCHECK(!ContentTypeHasCompoundValue(content_type));
    194   scoped_ptr<base::Value> value = GetWebsiteSetting(
    195       primary_url, secondary_url, content_type, resource_identifier, NULL);
    196   return content_settings::ValueToContentSetting(value.get());
    197 }
    198 
    199 void HostContentSettingsMap::GetSettingsForOneType(
    200     ContentSettingsType content_type,
    201     const std::string& resource_identifier,
    202     ContentSettingsForOneType* settings) const {
    203   DCHECK(SupportsResourceIdentifier(content_type) ||
    204          resource_identifier.empty());
    205   DCHECK(settings);
    206   UsedContentSettingsProviders();
    207 
    208   settings->clear();
    209   for (ConstProviderIterator provider = content_settings_providers_.begin();
    210        provider != content_settings_providers_.end();
    211        ++provider) {
    212     if (provider->first == OVERRIDE_PROVIDER)
    213       continue;
    214     // For each provider, iterate first the incognito-specific rules, then the
    215     // normal rules.
    216     if (is_off_the_record_) {
    217       AddSettingsForOneType(provider->second,
    218                             provider->first,
    219                             content_type,
    220                             resource_identifier,
    221                             settings,
    222                             true);
    223     }
    224     AddSettingsForOneType(provider->second,
    225                           provider->first,
    226                           content_type,
    227                           resource_identifier,
    228                           settings,
    229                           false);
    230   }
    231 }
    232 
    233 void HostContentSettingsMap::SetDefaultContentSetting(
    234     ContentSettingsType content_type,
    235     ContentSetting setting) {
    236   DCHECK(IsSettingAllowedForType(prefs_, setting, content_type));
    237 
    238   base::Value* value = NULL;
    239   if (setting != CONTENT_SETTING_DEFAULT)
    240     value = new base::FundamentalValue(setting);
    241   SetWebsiteSetting(
    242       ContentSettingsPattern::Wildcard(),
    243       ContentSettingsPattern::Wildcard(),
    244       content_type,
    245       std::string(),
    246       value);
    247 }
    248 
    249 void HostContentSettingsMap::SetWebsiteSetting(
    250     const ContentSettingsPattern& primary_pattern,
    251     const ContentSettingsPattern& secondary_pattern,
    252     ContentSettingsType content_type,
    253     const std::string& resource_identifier,
    254     base::Value* value) {
    255   DCHECK(IsValueAllowedForType(prefs_, value, content_type));
    256   DCHECK(SupportsResourceIdentifier(content_type) ||
    257          resource_identifier.empty());
    258   UsedContentSettingsProviders();
    259 
    260   for (ProviderIterator provider = content_settings_providers_.begin();
    261        provider != content_settings_providers_.end();
    262        ++provider) {
    263     if (provider->second->SetWebsiteSetting(primary_pattern,
    264                                             secondary_pattern,
    265                                             content_type,
    266                                             resource_identifier,
    267                                             value)) {
    268       return;
    269     }
    270   }
    271   NOTREACHED();
    272 }
    273 
    274 void HostContentSettingsMap::SetNarrowestWebsiteSetting(
    275     const ContentSettingsPattern& primary_pattern,
    276     const ContentSettingsPattern& secondary_pattern,
    277     ContentSettingsType content_type,
    278     const std::string& resource_identifier,
    279     ContentSetting setting,
    280     content_settings::SettingInfo existing_info) {
    281   ContentSettingsPattern narrow_primary = primary_pattern;
    282   ContentSettingsPattern narrow_secondary = secondary_pattern;
    283 
    284   DCHECK_EQ(content_settings::SETTING_SOURCE_USER, existing_info.source);
    285   ContentSettingsPattern::Relation r1 =
    286       existing_info.primary_pattern.Compare(primary_pattern);
    287   if (r1 == ContentSettingsPattern::PREDECESSOR) {
    288     narrow_primary = existing_info.primary_pattern;
    289   } else if (r1 == ContentSettingsPattern::IDENTITY) {
    290     ContentSettingsPattern::Relation r2 =
    291         existing_info.secondary_pattern.Compare(secondary_pattern);
    292     DCHECK(r2 != ContentSettingsPattern::DISJOINT_ORDER_POST &&
    293            r2 != ContentSettingsPattern::DISJOINT_ORDER_PRE);
    294     if (r2 == ContentSettingsPattern::PREDECESSOR)
    295       narrow_secondary = existing_info.secondary_pattern;
    296   }
    297 
    298   SetContentSetting(
    299       narrow_primary, narrow_secondary, content_type, std::string(), setting);
    300 }
    301 
    302 void HostContentSettingsMap::SetContentSetting(
    303     const ContentSettingsPattern& primary_pattern,
    304     const ContentSettingsPattern& secondary_pattern,
    305     ContentSettingsType content_type,
    306     const std::string& resource_identifier,
    307     ContentSetting setting) {
    308   DCHECK(!ContentTypeHasCompoundValue(content_type));
    309 
    310   if (setting == CONTENT_SETTING_ALLOW &&
    311       (content_type == CONTENT_SETTINGS_TYPE_GEOLOCATION ||
    312        content_type == CONTENT_SETTINGS_TYPE_NOTIFICATIONS)) {
    313     UpdateLastUsageByPattern(primary_pattern, secondary_pattern, content_type);
    314   }
    315 
    316   base::Value* value = NULL;
    317   if (setting != CONTENT_SETTING_DEFAULT)
    318     value = new base::FundamentalValue(setting);
    319   SetWebsiteSetting(primary_pattern,
    320                     secondary_pattern,
    321                     content_type,
    322                     resource_identifier,
    323                     value);
    324 }
    325 
    326 ContentSetting HostContentSettingsMap::GetContentSettingAndMaybeUpdateLastUsage(
    327     const GURL& primary_url,
    328     const GURL& secondary_url,
    329     ContentSettingsType content_type,
    330     const std::string& resource_identifier) {
    331   DCHECK_CURRENTLY_ON(BrowserThread::UI);
    332 
    333   ContentSetting setting = GetContentSetting(
    334       primary_url, secondary_url, content_type, resource_identifier);
    335   if (setting == CONTENT_SETTING_ALLOW) {
    336     UpdateLastUsageByPattern(
    337         ContentSettingsPattern::FromURLNoWildcard(primary_url),
    338         ContentSettingsPattern::FromURLNoWildcard(secondary_url),
    339         content_type);
    340   }
    341   return setting;
    342 }
    343 
    344 void HostContentSettingsMap::UpdateLastUsage(const GURL& primary_url,
    345                                              const GURL& secondary_url,
    346                                              ContentSettingsType content_type) {
    347   UpdateLastUsageByPattern(
    348       ContentSettingsPattern::FromURLNoWildcard(primary_url),
    349       ContentSettingsPattern::FromURLNoWildcard(secondary_url),
    350       content_type);
    351 }
    352 
    353 void HostContentSettingsMap::UpdateLastUsageByPattern(
    354     const ContentSettingsPattern& primary_pattern,
    355     const ContentSettingsPattern& secondary_pattern,
    356     ContentSettingsType content_type) {
    357   UsedContentSettingsProviders();
    358 
    359   GetPrefProvider()->UpdateLastUsage(
    360       primary_pattern, secondary_pattern, content_type);
    361 
    362   FOR_EACH_OBSERVER(
    363       content_settings::Observer,
    364       observers_,
    365       OnContentSettingUsed(primary_pattern, secondary_pattern, content_type));
    366 }
    367 
    368 base::Time HostContentSettingsMap::GetLastUsage(
    369     const GURL& primary_url,
    370     const GURL& secondary_url,
    371     ContentSettingsType content_type) {
    372   return GetLastUsageByPattern(
    373       ContentSettingsPattern::FromURLNoWildcard(primary_url),
    374       ContentSettingsPattern::FromURLNoWildcard(secondary_url),
    375       content_type);
    376 }
    377 
    378 base::Time HostContentSettingsMap::GetLastUsageByPattern(
    379     const ContentSettingsPattern& primary_pattern,
    380     const ContentSettingsPattern& secondary_pattern,
    381     ContentSettingsType content_type) {
    382   UsedContentSettingsProviders();
    383 
    384   return GetPrefProvider()->GetLastUsage(
    385       primary_pattern, secondary_pattern, content_type);
    386 }
    387 
    388 ContentSetting HostContentSettingsMap::GetContentSettingWithoutOverride(
    389     const GURL& primary_url,
    390     const GURL& secondary_url,
    391     ContentSettingsType content_type,
    392     const std::string& resource_identifier) {
    393   scoped_ptr<base::Value> value(GetWebsiteSettingWithoutOverride(
    394       primary_url, secondary_url, content_type, resource_identifier, NULL));
    395   return content_settings::ValueToContentSetting(value.get());
    396 }
    397 
    398 scoped_ptr<base::Value>
    399 HostContentSettingsMap::GetWebsiteSettingWithoutOverride(
    400     const GURL& primary_url,
    401     const GURL& secondary_url,
    402     ContentSettingsType content_type,
    403     const std::string& resource_identifier,
    404     content_settings::SettingInfo* info) const {
    405   return GetWebsiteSettingInternal(primary_url,
    406                                    secondary_url,
    407                                    content_type,
    408                                    resource_identifier,
    409                                    info,
    410                                    false);
    411 }
    412 
    413 void HostContentSettingsMap::SetContentSettingOverride(
    414     ContentSettingsType content_type,
    415     bool is_enabled) {
    416   UsedContentSettingsProviders();
    417 
    418   content_settings::OverrideProvider* override =
    419       static_cast<content_settings::OverrideProvider*>(
    420           content_settings_providers_[OVERRIDE_PROVIDER]);
    421   override->SetOverrideSetting(content_type, is_enabled);
    422 }
    423 
    424 bool HostContentSettingsMap::GetContentSettingOverride(
    425     ContentSettingsType content_type) {
    426   UsedContentSettingsProviders();
    427 
    428   content_settings::OverrideProvider* override =
    429       static_cast<content_settings::OverrideProvider*>(
    430           content_settings_providers_[OVERRIDE_PROVIDER]);
    431   return override->IsEnabled(content_type);
    432 }
    433 
    434 void HostContentSettingsMap::AddObserver(content_settings::Observer* observer) {
    435   observers_.AddObserver(observer);
    436 }
    437 
    438 void HostContentSettingsMap::RemoveObserver(
    439     content_settings::Observer* observer) {
    440   observers_.RemoveObserver(observer);
    441 }
    442 
    443 void HostContentSettingsMap::SetPrefClockForTesting(
    444     scoped_ptr<base::Clock> clock) {
    445   UsedContentSettingsProviders();
    446 
    447   GetPrefProvider()->SetClockForTesting(clock.Pass());
    448 }
    449 
    450 void HostContentSettingsMap::AddExceptionForURL(
    451     const GURL& primary_url,
    452     const GURL& secondary_url,
    453     ContentSettingsType content_type,
    454     ContentSetting setting) {
    455   // TODO(markusheintz): Until the UI supports pattern pairs, both urls must
    456   // match.
    457   DCHECK(primary_url == secondary_url);
    458   DCHECK(!ContentTypeHasCompoundValue(content_type));
    459 
    460   // Make sure there is no entry that would override the pattern we are about
    461   // to insert for exactly this URL.
    462   SetContentSetting(ContentSettingsPattern::FromURLNoWildcard(primary_url),
    463                     ContentSettingsPattern::Wildcard(),
    464                     content_type,
    465                     std::string(),
    466                     CONTENT_SETTING_DEFAULT);
    467 
    468   SetContentSetting(ContentSettingsPattern::FromURL(primary_url),
    469                     ContentSettingsPattern::Wildcard(),
    470                     content_type,
    471                     std::string(),
    472                     setting);
    473 }
    474 
    475 void HostContentSettingsMap::ClearSettingsForOneType(
    476     ContentSettingsType content_type) {
    477   UsedContentSettingsProviders();
    478   for (ProviderIterator provider = content_settings_providers_.begin();
    479        provider != content_settings_providers_.end();
    480        ++provider) {
    481     provider->second->ClearAllContentSettingsRules(content_type);
    482   }
    483 }
    484 
    485 bool HostContentSettingsMap::IsValueAllowedForType(
    486     PrefService* prefs, const base::Value* value, ContentSettingsType type) {
    487   return ContentTypeHasCompoundValue(type) || IsSettingAllowedForType(
    488       prefs, content_settings::ValueToContentSetting(value), type);
    489 }
    490 
    491 // static
    492 bool HostContentSettingsMap::IsSettingAllowedForType(
    493     PrefService* prefs,
    494     ContentSetting setting,
    495     ContentSettingsType content_type) {
    496   // We don't yet support stored content settings for mixed scripting.
    497   if (content_type == CONTENT_SETTINGS_TYPE_MIXEDSCRIPT)
    498     return false;
    499 
    500   // BLOCK semantics are not implemented for fullscreen.
    501   if (content_type == CONTENT_SETTINGS_TYPE_FULLSCREEN &&
    502       setting == CONTENT_SETTING_BLOCK) {
    503     return false;
    504   }
    505 
    506   // We don't support ALLOW for media default setting.
    507   if (content_type == CONTENT_SETTINGS_TYPE_MEDIASTREAM &&
    508       setting == CONTENT_SETTING_ALLOW) {
    509     return false;
    510   }
    511 
    512 #if defined(OS_ANDROID)
    513   // App banners store a dictionary.
    514   if (content_type == CONTENT_SETTINGS_TYPE_APP_BANNER)
    515     return false;
    516 #endif
    517 
    518   // DEFAULT, ALLOW and BLOCK are always allowed.
    519   if (setting == CONTENT_SETTING_DEFAULT ||
    520       setting == CONTENT_SETTING_ALLOW ||
    521       setting == CONTENT_SETTING_BLOCK) {
    522     return true;
    523   }
    524   switch (content_type) {
    525     case CONTENT_SETTINGS_TYPE_COOKIES:
    526       return setting == CONTENT_SETTING_SESSION_ONLY;
    527     case CONTENT_SETTINGS_TYPE_PLUGINS:
    528     case CONTENT_SETTINGS_TYPE_GEOLOCATION:
    529     case CONTENT_SETTINGS_TYPE_NOTIFICATIONS:
    530     case CONTENT_SETTINGS_TYPE_MOUSELOCK:
    531     case CONTENT_SETTINGS_TYPE_MEDIASTREAM:
    532     case CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC:
    533     case CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA:
    534     case CONTENT_SETTINGS_TYPE_PPAPI_BROKER:
    535     case CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS:
    536     case CONTENT_SETTINGS_TYPE_MIDI_SYSEX:
    537       return setting == CONTENT_SETTING_ASK;
    538     default:
    539       return false;
    540   }
    541 }
    542 
    543 // static
    544 bool HostContentSettingsMap::ContentTypeHasCompoundValue(
    545     ContentSettingsType type) {
    546   // Values for content type CONTENT_SETTINGS_TYPE_AUTO_SELECT_CERTIFICATE,
    547   // CONTENT_SETTINGS_TYPE_MEDIASTREAM, and
    548   // CONTENT_SETTINGS_TYPE_SSL_CERT_DECISIONS are of type dictionary/map.
    549   // Compound types like dictionaries can't be mapped to the type
    550   // |ContentSetting|.
    551 #if defined(OS_ANDROID)
    552   if (type == CONTENT_SETTINGS_TYPE_APP_BANNER)
    553     return true;
    554 #endif
    555 
    556   return (type == CONTENT_SETTINGS_TYPE_AUTO_SELECT_CERTIFICATE ||
    557           type == CONTENT_SETTINGS_TYPE_MEDIASTREAM ||
    558           type == CONTENT_SETTINGS_TYPE_SSL_CERT_DECISIONS);
    559 }
    560 
    561 void HostContentSettingsMap::OnContentSettingChanged(
    562     const ContentSettingsPattern& primary_pattern,
    563     const ContentSettingsPattern& secondary_pattern,
    564     ContentSettingsType content_type,
    565     std::string resource_identifier) {
    566   FOR_EACH_OBSERVER(content_settings::Observer,
    567                     observers_,
    568                     OnContentSettingChanged(primary_pattern,
    569                                             secondary_pattern,
    570                                             content_type,
    571                                             resource_identifier));
    572 }
    573 
    574 HostContentSettingsMap::~HostContentSettingsMap() {
    575   DCHECK(!prefs_);
    576   STLDeleteValues(&content_settings_providers_);
    577 }
    578 
    579 void HostContentSettingsMap::ShutdownOnUIThread() {
    580   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    581   DCHECK(prefs_);
    582   prefs_ = NULL;
    583   for (ProviderIterator it = content_settings_providers_.begin();
    584        it != content_settings_providers_.end();
    585        ++it) {
    586     it->second->ShutdownOnUIThread();
    587   }
    588 }
    589 
    590 void HostContentSettingsMap::MigrateObsoleteClearOnExitPref() {
    591   // Don't migrate more than once.
    592   if (prefs_->HasPrefPath(prefs::kContentSettingsClearOnExitMigrated) &&
    593       prefs_->GetBoolean(prefs::kContentSettingsClearOnExitMigrated)) {
    594     return;
    595   }
    596 
    597   if (!prefs_->GetBoolean(prefs::kClearSiteDataOnExit)) {
    598     // Nothing to be done
    599     prefs_->SetBoolean(prefs::kContentSettingsClearOnExitMigrated, true);
    600     return;
    601   }
    602 
    603   // Change the default cookie settings:
    604   //  old              new
    605   //  ---------------- ----------------
    606   //  ALLOW            SESSION_ONLY
    607   //  SESSION_ONLY     SESSION_ONLY
    608   //  BLOCK            BLOCK
    609   ContentSetting default_setting = GetDefaultContentSettingFromProvider(
    610       CONTENT_SETTINGS_TYPE_COOKIES,
    611       content_settings_providers_[DEFAULT_PROVIDER]);
    612   if (default_setting == CONTENT_SETTING_ALLOW) {
    613     SetDefaultContentSetting(
    614         CONTENT_SETTINGS_TYPE_COOKIES, CONTENT_SETTING_SESSION_ONLY);
    615   }
    616 
    617   // Change the exceptions using the same rules.
    618   ContentSettingsForOneType exceptions;
    619   AddSettingsForOneType(content_settings_providers_[PREF_PROVIDER],
    620                         PREF_PROVIDER,
    621                         CONTENT_SETTINGS_TYPE_COOKIES,
    622                         std::string(),
    623                         &exceptions,
    624                         false);
    625   for (ContentSettingsForOneType::iterator it = exceptions.begin();
    626        it != exceptions.end(); ++it) {
    627     if (it->setting != CONTENT_SETTING_ALLOW)
    628       continue;
    629     SetWebsiteSetting(it->primary_pattern,
    630                       it->secondary_pattern,
    631                       CONTENT_SETTINGS_TYPE_COOKIES,
    632                       std::string(),
    633                       new base::FundamentalValue(CONTENT_SETTING_SESSION_ONLY));
    634   }
    635 
    636   prefs_->SetBoolean(prefs::kContentSettingsClearOnExitMigrated, true);
    637 }
    638 
    639 void HostContentSettingsMap::AddSettingsForOneType(
    640     const content_settings::ProviderInterface* provider,
    641     ProviderType provider_type,
    642     ContentSettingsType content_type,
    643     const std::string& resource_identifier,
    644     ContentSettingsForOneType* settings,
    645     bool incognito) const {
    646   scoped_ptr<content_settings::RuleIterator> rule_iterator(
    647       provider->GetRuleIterator(content_type,
    648                                 resource_identifier,
    649                                 incognito));
    650   while (rule_iterator->HasNext()) {
    651     const content_settings::Rule& rule = rule_iterator->Next();
    652     ContentSetting setting_value = CONTENT_SETTING_DEFAULT;
    653     // TODO(bauerb): Return rules as a list of values, not content settings.
    654     // Handle the case using compound values for its exceptions and arbitrary
    655     // values for its default setting. Here we assume all the exceptions
    656     // are granted as |CONTENT_SETTING_ALLOW|.
    657     if (ContentTypeHasCompoundValue(content_type) &&
    658         rule.value.get() &&
    659         rule.primary_pattern != ContentSettingsPattern::Wildcard()) {
    660       setting_value = CONTENT_SETTING_ALLOW;
    661     } else {
    662       setting_value = content_settings::ValueToContentSetting(rule.value.get());
    663     }
    664     settings->push_back(ContentSettingPatternSource(
    665         rule.primary_pattern, rule.secondary_pattern,
    666         setting_value,
    667         kProviderNames[provider_type],
    668         incognito));
    669   }
    670 }
    671 
    672 void HostContentSettingsMap::UsedContentSettingsProviders() const {
    673 #ifndef NDEBUG
    674   if (used_from_thread_id_ == base::kInvalidThreadId)
    675     return;
    676 
    677   if (base::PlatformThread::CurrentId() != used_from_thread_id_)
    678     used_from_thread_id_ = base::kInvalidThreadId;
    679 #endif
    680 }
    681 
    682 bool HostContentSettingsMap::ShouldAllowAllContent(
    683     const GURL& primary_url,
    684     const GURL& secondary_url,
    685     ContentSettingsType content_type) {
    686   if (content_type == CONTENT_SETTINGS_TYPE_NOTIFICATIONS ||
    687       content_type == CONTENT_SETTINGS_TYPE_GEOLOCATION ||
    688       content_type == CONTENT_SETTINGS_TYPE_MIDI_SYSEX) {
    689     return false;
    690   }
    691 #if defined(OS_ANDROID) || defined(OS_CHROMEOS)
    692   if (content_type == CONTENT_SETTINGS_TYPE_PROTECTED_MEDIA_IDENTIFIER) {
    693     return false;
    694   }
    695 #endif
    696   if (secondary_url.SchemeIs(content::kChromeUIScheme) &&
    697       content_type == CONTENT_SETTINGS_TYPE_COOKIES &&
    698       primary_url.SchemeIsSecure()) {
    699     return true;
    700   }
    701 #if defined(ENABLE_EXTENSIONS)
    702   if (primary_url.SchemeIs(extensions::kExtensionScheme)) {
    703     switch (content_type) {
    704       case CONTENT_SETTINGS_TYPE_PLUGINS:
    705       case CONTENT_SETTINGS_TYPE_MEDIASTREAM:
    706       case CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC:
    707       case CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA:
    708         return false;
    709       case CONTENT_SETTINGS_TYPE_COOKIES:
    710         return secondary_url.SchemeIs(extensions::kExtensionScheme);
    711       default:
    712         return true;
    713     }
    714   }
    715 #endif
    716   return primary_url.SchemeIs(content::kChromeDevToolsScheme) ||
    717          primary_url.SchemeIs(content::kChromeUIScheme);
    718 }
    719 
    720 scoped_ptr<base::Value> HostContentSettingsMap::GetWebsiteSetting(
    721     const GURL& primary_url,
    722     const GURL& secondary_url,
    723     ContentSettingsType content_type,
    724     const std::string& resource_identifier,
    725     content_settings::SettingInfo* info) const {
    726   DCHECK(SupportsResourceIdentifier(content_type) ||
    727          resource_identifier.empty());
    728 
    729   // Check if the scheme of the requesting url is whitelisted.
    730   if (ShouldAllowAllContent(primary_url, secondary_url, content_type)) {
    731     if (info) {
    732       info->source = content_settings::SETTING_SOURCE_WHITELIST;
    733       info->primary_pattern = ContentSettingsPattern::Wildcard();
    734       info->secondary_pattern = ContentSettingsPattern::Wildcard();
    735     }
    736     return scoped_ptr<base::Value>(
    737         new base::FundamentalValue(CONTENT_SETTING_ALLOW));
    738   }
    739 
    740   return GetWebsiteSettingInternal(primary_url,
    741                                    secondary_url,
    742                                    content_type,
    743                                    resource_identifier,
    744                                    info,
    745                                    true);
    746 }
    747 
    748 // static
    749 HostContentSettingsMap::ProviderType
    750 HostContentSettingsMap::GetProviderTypeFromSource(const std::string& source) {
    751   for (size_t i = 0; i < arraysize(kProviderNames); ++i) {
    752     if (source == kProviderNames[i])
    753       return static_cast<ProviderType>(i);
    754   }
    755 
    756   NOTREACHED();
    757   return DEFAULT_PROVIDER;
    758 }
    759 
    760 content_settings::PrefProvider* HostContentSettingsMap::GetPrefProvider() {
    761   return static_cast<content_settings::PrefProvider*>(
    762       content_settings_providers_[PREF_PROVIDER]);
    763 }
    764 
    765 scoped_ptr<base::Value> HostContentSettingsMap::GetWebsiteSettingInternal(
    766     const GURL& primary_url,
    767     const GURL& secondary_url,
    768     ContentSettingsType content_type,
    769     const std::string& resource_identifier,
    770     content_settings::SettingInfo* info,
    771     bool get_override) const {
    772   UsedContentSettingsProviders();
    773   ContentSettingsPattern* primary_pattern = NULL;
    774   ContentSettingsPattern* secondary_pattern = NULL;
    775   if (info) {
    776     primary_pattern = &info->primary_pattern;
    777     secondary_pattern = &info->secondary_pattern;
    778   }
    779 
    780   // The list of |content_settings_providers_| is ordered according to their
    781   // precedence.
    782   for (ConstProviderIterator provider = content_settings_providers_.begin();
    783        provider != content_settings_providers_.end();
    784        ++provider) {
    785     if (!get_override && provider->first == OVERRIDE_PROVIDER)
    786       continue;
    787 
    788     scoped_ptr<base::Value> value(
    789         content_settings::GetContentSettingValueAndPatterns(provider->second,
    790                                                             primary_url,
    791                                                             secondary_url,
    792                                                             content_type,
    793                                                             resource_identifier,
    794                                                             is_off_the_record_,
    795                                                             primary_pattern,
    796                                                             secondary_pattern));
    797     if (value) {
    798       if (info)
    799         info->source = kProviderSourceMap[provider->first];
    800       return value.Pass();
    801     }
    802   }
    803 
    804   if (info) {
    805     info->source = content_settings::SETTING_SOURCE_NONE;
    806     info->primary_pattern = ContentSettingsPattern();
    807     info->secondary_pattern = ContentSettingsPattern();
    808   }
    809   return scoped_ptr<base::Value>();
    810 }
    811