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