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