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