- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / content_settings / host_content_settings_map.cc
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/common/constants.h"
38 #include "net/base/net_errors.h"
39 #include "net/base/static_cookie_policy.h"
40 #include "url/gurl.h"
41
42 using content::BrowserThread;
43 using content::UserMetricsAction;
44
45 namespace {
46
47 typedef std::vector<content_settings::Rule> Rules;
48
49 typedef std::pair<std::string, std::string> StringPair;
50
51 const char* kProviderNames[] = {
52   "platform_app",
53   "policy",
54   "extension",
55   "preference",
56   "default"
57 };
58
59 content_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 };
66 COMPILE_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.
72 bool SupportsResourceIdentifier(ContentSettingsType content_type) {
73   return content_type == CONTENT_SETTINGS_TYPE_PLUGINS;
74 }
75
76 }  // namespace
77
78 HostContentSettingsMap::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)
108 void 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
141 void 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
162 ContentSetting 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
179 ContentSetting 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
207 ContentSetting 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
218 void 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
250 void 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
266 void 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
291 void 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
308 void HostContentSettingsMap::AddExceptionForURL(
309     const GURL& primary_url,
310     const GURL& secondary_url,
311     ContentSettingsType content_type,
312     const std::string& resource_identifier,
313     ContentSetting setting) {
314   // TODO(markusheintz): Until the UI supports pattern pairs, both urls must
315   // match.
316   DCHECK(primary_url == secondary_url);
317   DCHECK(!ContentTypeHasCompoundValue(content_type));
318
319   // Make sure there is no entry that would override the pattern we are about
320   // to insert for exactly this URL.
321   SetContentSetting(ContentSettingsPattern::FromURLNoWildcard(primary_url),
322                     ContentSettingsPattern::Wildcard(),
323                     content_type,
324                     resource_identifier,
325                     CONTENT_SETTING_DEFAULT);
326
327   SetContentSetting(ContentSettingsPattern::FromURL(primary_url),
328                     ContentSettingsPattern::Wildcard(),
329                     content_type,
330                     resource_identifier,
331                     setting);
332 }
333
334 void HostContentSettingsMap::ClearSettingsForOneType(
335     ContentSettingsType content_type) {
336   UsedContentSettingsProviders();
337   for (ProviderIterator provider = content_settings_providers_.begin();
338        provider != content_settings_providers_.end();
339        ++provider) {
340     provider->second->ClearAllContentSettingsRules(content_type);
341   }
342 }
343
344 bool HostContentSettingsMap::IsValueAllowedForType(
345     PrefService* prefs, const base::Value* value, ContentSettingsType type) {
346   return ContentTypeHasCompoundValue(type) || IsSettingAllowedForType(
347       prefs, content_settings::ValueToContentSetting(value), type);
348 }
349
350 // static
351 bool HostContentSettingsMap::IsSettingAllowedForType(
352     PrefService* prefs,
353     ContentSetting setting,
354     ContentSettingsType content_type) {
355   // We don't yet support stored content settings for mixed scripting.
356   if (content_type == CONTENT_SETTINGS_TYPE_MIXEDSCRIPT)
357     return false;
358
359   // BLOCK semantics are not implemented for fullscreen.
360   if (content_type == CONTENT_SETTINGS_TYPE_FULLSCREEN &&
361       setting == CONTENT_SETTING_BLOCK) {
362     return false;
363   }
364
365   // We don't support ALLOW for media default setting.
366   if (content_type == CONTENT_SETTINGS_TYPE_MEDIASTREAM &&
367       setting == CONTENT_SETTING_ALLOW) {
368     return false;
369   }
370
371   // DEFAULT, ALLOW and BLOCK are always allowed.
372   if (setting == CONTENT_SETTING_DEFAULT ||
373       setting == CONTENT_SETTING_ALLOW ||
374       setting == CONTENT_SETTING_BLOCK) {
375     return true;
376   }
377   switch (content_type) {
378     case CONTENT_SETTINGS_TYPE_COOKIES:
379       return setting == CONTENT_SETTING_SESSION_ONLY;
380     case CONTENT_SETTINGS_TYPE_PLUGINS:
381     case CONTENT_SETTINGS_TYPE_GEOLOCATION:
382     case CONTENT_SETTINGS_TYPE_NOTIFICATIONS:
383     case CONTENT_SETTINGS_TYPE_MOUSELOCK:
384     case CONTENT_SETTINGS_TYPE_MEDIASTREAM:
385     case CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC:
386     case CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA:
387     case CONTENT_SETTINGS_TYPE_PPAPI_BROKER:
388     case CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS:
389     case CONTENT_SETTINGS_TYPE_MIDI_SYSEX:
390       return setting == CONTENT_SETTING_ASK;
391     default:
392       return false;
393   }
394 }
395
396 // static
397 bool HostContentSettingsMap::ContentTypeHasCompoundValue(
398     ContentSettingsType type) {
399   // Values for content type CONTENT_SETTINGS_TYPE_AUTO_SELECT_CERTIFICATE and
400   // CONTENT_SETTINGS_TYPE_MEDIASTREAM are of type dictionary/map. Compound
401   // types like dictionaries can't be mapped to the type |ContentSetting|.
402   return (type == CONTENT_SETTINGS_TYPE_AUTO_SELECT_CERTIFICATE ||
403           type == CONTENT_SETTINGS_TYPE_MEDIASTREAM);
404 }
405
406 void HostContentSettingsMap::OnContentSettingChanged(
407     const ContentSettingsPattern& primary_pattern,
408     const ContentSettingsPattern& secondary_pattern,
409     ContentSettingsType content_type,
410     std::string resource_identifier) {
411   const ContentSettingsDetails details(primary_pattern,
412                                        secondary_pattern,
413                                        content_type,
414                                        resource_identifier);
415   content::NotificationService::current()->Notify(
416       chrome::NOTIFICATION_CONTENT_SETTINGS_CHANGED,
417       content::Source<HostContentSettingsMap>(this),
418       content::Details<const ContentSettingsDetails>(&details));
419 }
420
421 HostContentSettingsMap::~HostContentSettingsMap() {
422   DCHECK(!prefs_);
423   STLDeleteValues(&content_settings_providers_);
424 }
425
426 void HostContentSettingsMap::ShutdownOnUIThread() {
427   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
428   DCHECK(prefs_);
429   prefs_ = NULL;
430   for (ProviderIterator it = content_settings_providers_.begin();
431        it != content_settings_providers_.end();
432        ++it) {
433     it->second->ShutdownOnUIThread();
434   }
435 }
436
437 void HostContentSettingsMap::MigrateObsoleteClearOnExitPref() {
438   // Don't migrate more than once.
439   if (prefs_->HasPrefPath(prefs::kContentSettingsClearOnExitMigrated) &&
440       prefs_->GetBoolean(prefs::kContentSettingsClearOnExitMigrated)) {
441     return;
442   }
443
444   if (!prefs_->GetBoolean(prefs::kClearSiteDataOnExit)) {
445     // Nothing to be done
446     prefs_->SetBoolean(prefs::kContentSettingsClearOnExitMigrated, true);
447     return;
448   }
449
450   // Change the default cookie settings:
451   //  old              new
452   //  ---------------- ----------------
453   //  ALLOW            SESSION_ONLY
454   //  SESSION_ONLY     SESSION_ONLY
455   //  BLOCK            BLOCK
456   ContentSetting default_setting = GetDefaultContentSettingFromProvider(
457       CONTENT_SETTINGS_TYPE_COOKIES,
458       content_settings_providers_[DEFAULT_PROVIDER]);
459   if (default_setting == CONTENT_SETTING_ALLOW) {
460     SetDefaultContentSetting(
461         CONTENT_SETTINGS_TYPE_COOKIES, CONTENT_SETTING_SESSION_ONLY);
462   }
463
464   // Change the exceptions using the same rules.
465   ContentSettingsForOneType exceptions;
466   AddSettingsForOneType(content_settings_providers_[PREF_PROVIDER],
467                         PREF_PROVIDER,
468                         CONTENT_SETTINGS_TYPE_COOKIES,
469                         std::string(),
470                         &exceptions,
471                         false);
472   for (ContentSettingsForOneType::iterator it = exceptions.begin();
473        it != exceptions.end(); ++it) {
474     if (it->setting != CONTENT_SETTING_ALLOW)
475       continue;
476     SetWebsiteSetting(it->primary_pattern,
477                       it->secondary_pattern,
478                       CONTENT_SETTINGS_TYPE_COOKIES,
479                       std::string(),
480                       Value::CreateIntegerValue(CONTENT_SETTING_SESSION_ONLY));
481   }
482
483   prefs_->SetBoolean(prefs::kContentSettingsClearOnExitMigrated, true);
484 }
485
486 void HostContentSettingsMap::AddSettingsForOneType(
487     const content_settings::ProviderInterface* provider,
488     ProviderType provider_type,
489     ContentSettingsType content_type,
490     const std::string& resource_identifier,
491     ContentSettingsForOneType* settings,
492     bool incognito) const {
493   scoped_ptr<content_settings::RuleIterator> rule_iterator(
494       provider->GetRuleIterator(content_type,
495                                 resource_identifier,
496                                 incognito));
497   while (rule_iterator->HasNext()) {
498     const content_settings::Rule& rule = rule_iterator->Next();
499     ContentSetting setting_value = CONTENT_SETTING_DEFAULT;
500     // TODO(bauerb): Return rules as a list of values, not content settings.
501     // Handle the case using compound values for its exceptions and arbitrary
502     // values for its default setting. Here we assume all the exceptions
503     // are granted as |CONTENT_SETTING_ALLOW|.
504     if (ContentTypeHasCompoundValue(content_type) &&
505         rule.value.get() &&
506         rule.primary_pattern != ContentSettingsPattern::Wildcard()) {
507       setting_value = CONTENT_SETTING_ALLOW;
508     } else {
509       setting_value = content_settings::ValueToContentSetting(rule.value.get());
510     }
511     settings->push_back(ContentSettingPatternSource(
512         rule.primary_pattern, rule.secondary_pattern,
513         setting_value,
514         kProviderNames[provider_type],
515         incognito));
516   }
517 }
518
519 void HostContentSettingsMap::UsedContentSettingsProviders() const {
520 #ifndef NDEBUG
521   if (used_from_thread_id_ == base::kInvalidThreadId)
522     return;
523
524   if (base::PlatformThread::CurrentId() != used_from_thread_id_)
525     used_from_thread_id_ = base::kInvalidThreadId;
526 #endif
527 }
528
529 bool HostContentSettingsMap::ShouldAllowAllContent(
530     const GURL& primary_url,
531     const GURL& secondary_url,
532     ContentSettingsType content_type) {
533   if (content_type == CONTENT_SETTINGS_TYPE_NOTIFICATIONS ||
534       content_type == CONTENT_SETTINGS_TYPE_GEOLOCATION ||
535       content_type == CONTENT_SETTINGS_TYPE_MIDI_SYSEX) {
536     return false;
537   }
538   if (secondary_url.SchemeIs(chrome::kChromeUIScheme) &&
539       content_type == CONTENT_SETTINGS_TYPE_COOKIES &&
540       primary_url.SchemeIsSecure()) {
541     return true;
542   }
543   if (primary_url.SchemeIs(extensions::kExtensionScheme)) {
544     switch (content_type) {
545       case CONTENT_SETTINGS_TYPE_PLUGINS:
546       case CONTENT_SETTINGS_TYPE_MEDIASTREAM:
547       case CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC:
548       case CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA:
549         return false;
550       case CONTENT_SETTINGS_TYPE_COOKIES:
551         return secondary_url.SchemeIs(extensions::kExtensionScheme);
552       default:
553         return true;
554     }
555   }
556   return primary_url.SchemeIs(chrome::kChromeDevToolsScheme) ||
557          primary_url.SchemeIs(chrome::kChromeInternalScheme) ||
558          primary_url.SchemeIs(chrome::kChromeUIScheme);
559 }
560
561 base::Value* HostContentSettingsMap::GetWebsiteSetting(
562     const GURL& primary_url,
563     const GURL& secondary_url,
564     ContentSettingsType content_type,
565     const std::string& resource_identifier,
566     content_settings::SettingInfo* info) const {
567   DCHECK(SupportsResourceIdentifier(content_type) ||
568          resource_identifier.empty());
569
570   // Check if the scheme of the requesting url is whitelisted.
571   if (ShouldAllowAllContent(primary_url, secondary_url, content_type)) {
572     if (info) {
573       info->source = content_settings::SETTING_SOURCE_WHITELIST;
574       info->primary_pattern = ContentSettingsPattern::Wildcard();
575       info->secondary_pattern = ContentSettingsPattern::Wildcard();
576     }
577     return Value::CreateIntegerValue(CONTENT_SETTING_ALLOW);
578   }
579
580   ContentSettingsPattern* primary_pattern = NULL;
581   ContentSettingsPattern* secondary_pattern = NULL;
582   if (info) {
583     primary_pattern = &info->primary_pattern;
584     secondary_pattern = &info->secondary_pattern;
585   }
586
587   // The list of |content_settings_providers_| is ordered according to their
588   // precedence.
589   for (ConstProviderIterator provider = content_settings_providers_.begin();
590        provider != content_settings_providers_.end();
591        ++provider) {
592     base::Value* value = content_settings::GetContentSettingValueAndPatterns(
593         provider->second, primary_url, secondary_url, content_type,
594         resource_identifier, is_off_the_record_,
595         primary_pattern, secondary_pattern);
596     if (value) {
597       if (info)
598         info->source = kProviderSourceMap[provider->first];
599       return value;
600     }
601   }
602
603   if (info) {
604     info->source = content_settings::SETTING_SOURCE_NONE;
605     info->primary_pattern = ContentSettingsPattern();
606     info->secondary_pattern = ContentSettingsPattern();
607   }
608   return NULL;
609 }
610
611 // static
612 HostContentSettingsMap::ProviderType
613     HostContentSettingsMap::GetProviderTypeFromSource(
614         const std::string& source) {
615   for (size_t i = 0; i < arraysize(kProviderNames); ++i) {
616     if (source == kProviderNames[i])
617       return static_cast<ProviderType>(i);
618   }
619
620   NOTREACHED();
621   return DEFAULT_PROVIDER;
622 }