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