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