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