blob: cc7b284398985d73ebd103d55117c8519ed9437a [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/content_settings/core/browser/cookie_settings.h"
#include "base/bind.h"
#include "base/feature_list.h"
#include "base/logging.h"
#include "components/content_settings/core/browser/content_settings_utils.h"
#include "components/content_settings/core/browser/host_content_settings_map.h"
#include "components/content_settings/core/common/content_settings.h"
#include "components/content_settings/core/common/content_settings_pattern.h"
#include "components/content_settings/core/common/content_settings_utils.h"
#include "components/content_settings/core/common/features.h"
#include "components/content_settings/core/common/pref_names.h"
#include "components/pref_registry/pref_registry_syncable.h"
#include "components/prefs/pref_service.h"
#include "extensions/buildflags/buildflags.h"
#include "url/gurl.h"
namespace content_settings {
CookieSettings::CookieSettings(
HostContentSettingsMap* host_content_settings_map,
PrefService* prefs,
bool is_incognito,
const char* extension_scheme)
: host_content_settings_map_(host_content_settings_map),
is_incognito_(is_incognito),
extension_scheme_(extension_scheme),
block_third_party_cookies_(false) {
pref_change_registrar_.Init(prefs);
pref_change_registrar_.Add(
prefs::kBlockThirdPartyCookies,
base::Bind(&CookieSettings::OnCookiePreferencesChanged,
base::Unretained(this)));
pref_change_registrar_.Add(
prefs::kCookieControlsMode,
base::Bind(&CookieSettings::OnCookiePreferencesChanged,
base::Unretained(this)));
OnCookiePreferencesChanged();
}
ContentSetting CookieSettings::GetDefaultCookieSetting(
std::string* provider_id) const {
return host_content_settings_map_->GetDefaultContentSetting(
CONTENT_SETTINGS_TYPE_COOKIES, provider_id);
}
void CookieSettings::GetCookieSettings(
ContentSettingsForOneType* settings) const {
host_content_settings_map_->GetSettingsForOneType(
CONTENT_SETTINGS_TYPE_COOKIES, std::string(), settings);
}
void CookieSettings::RegisterProfilePrefs(
user_prefs::PrefRegistrySyncable* registry) {
registry->RegisterBooleanPref(
prefs::kBlockThirdPartyCookies, false,
user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
registry->RegisterIntegerPref(
prefs::kCookieControlsMode,
static_cast<int>(CookieControlsMode::kIncognitoOnly),
user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
}
void CookieSettings::SetDefaultCookieSetting(ContentSetting setting) {
DCHECK(IsValidSetting(setting));
host_content_settings_map_->SetDefaultContentSetting(
CONTENT_SETTINGS_TYPE_COOKIES, setting);
}
void CookieSettings::SetCookieSetting(const GURL& primary_url,
ContentSetting setting) {
DCHECK(IsValidSetting(setting));
host_content_settings_map_->SetContentSettingDefaultScope(
primary_url, GURL(), CONTENT_SETTINGS_TYPE_COOKIES, std::string(),
setting);
}
void CookieSettings::ResetCookieSetting(const GURL& primary_url) {
host_content_settings_map_->SetNarrowestContentSetting(
primary_url, GURL(), CONTENT_SETTINGS_TYPE_COOKIES,
CONTENT_SETTING_DEFAULT);
}
bool CookieSettings::IsThirdPartyAccessAllowed(const GURL& first_party_url) {
// Use GURL() as an opaque primary url to check if any site
// could access cookies in a 3p context on |first_party_url|.
return IsCookieAccessAllowed(GURL(), first_party_url);
}
void CookieSettings::SetThirdPartyCookieSetting(const GURL& first_party_url,
ContentSetting setting) {
DCHECK(IsValidSetting(setting));
host_content_settings_map_->SetContentSettingCustomScope(
ContentSettingsPattern::Wildcard(),
ContentSettingsPattern::FromURLNoWildcard(first_party_url),
ContentSettingsType::CONTENT_SETTINGS_TYPE_COOKIES, std::string(),
setting);
}
void CookieSettings::ResetThirdPartyCookieSetting(const GURL& first_party_url) {
host_content_settings_map_->SetContentSettingCustomScope(
ContentSettingsPattern::Wildcard(),
ContentSettingsPattern::FromURLNoWildcard(first_party_url),
ContentSettingsType::CONTENT_SETTINGS_TYPE_COOKIES, std::string(),
CONTENT_SETTING_DEFAULT);
}
bool CookieSettings::IsStorageDurable(const GURL& origin) const {
// TODO(dgrogan): Don't use host_content_settings_map_ directly.
// https://crbug.com/539538
ContentSetting setting = host_content_settings_map_->GetContentSetting(
origin /*primary*/, origin /*secondary*/,
CONTENT_SETTINGS_TYPE_DURABLE_STORAGE,
std::string() /*resource_identifier*/);
return setting == CONTENT_SETTING_ALLOW;
}
void CookieSettings::GetSettingForLegacyCookieAccess(
const GURL& cookie_domain,
ContentSetting* setting) const {
DCHECK(setting);
*setting = host_content_settings_map_->GetContentSetting(
cookie_domain, GURL(), CONTENT_SETTINGS_TYPE_LEGACY_COOKIE_ACCESS,
std::string() /* resource_identifier */);
}
void CookieSettings::ShutdownOnUIThread() {
DCHECK(thread_checker_.CalledOnValidThread());
pref_change_registrar_.RemoveAll();
}
void CookieSettings::GetCookieSettingInternal(
const GURL& url,
const GURL& first_party_url,
bool is_third_party_request,
content_settings::SettingSource* source,
ContentSetting* cookie_setting) const {
DCHECK(cookie_setting);
// Auto-allow in extensions or for WebUI embedded in a secure origin.
if (first_party_url.SchemeIs(kChromeUIScheme) &&
url.SchemeIsCryptographic()) {
*cookie_setting = CONTENT_SETTING_ALLOW;
return;
}
#if BUILDFLAG(ENABLE_EXTENSIONS)
if (url.SchemeIs(extension_scheme_) &&
first_party_url.SchemeIs(extension_scheme_)) {
*cookie_setting = CONTENT_SETTING_ALLOW;
return;
}
#endif
// First get any host-specific settings.
SettingInfo info;
std::unique_ptr<base::Value> value =
host_content_settings_map_->GetWebsiteSetting(
url, first_party_url, CONTENT_SETTINGS_TYPE_COOKIES, std::string(),
&info);
if (source)
*source = info.source;
// If no explicit exception has been made and third-party cookies are blocked
// by default, apply CONTENT_SETTING_BLOCKED.
bool block_third = info.primary_pattern.MatchesAllHosts() &&
info.secondary_pattern.MatchesAllHosts() &&
ShouldBlockThirdPartyCookies() &&
!first_party_url.SchemeIs(extension_scheme_);
// We should always have a value, at least from the default provider.
DCHECK(value);
ContentSetting setting = ValueToContentSetting(value.get());
bool block = block_third && is_third_party_request;
*cookie_setting = block ? CONTENT_SETTING_BLOCK : setting;
}
CookieSettings::~CookieSettings() {
}
bool CookieSettings::IsCookieControlsEnabled() {
if (!base::FeatureList::IsEnabled(kImprovedCookieControls))
return false;
CookieControlsMode mode = static_cast<CookieControlsMode>(
pref_change_registrar_.prefs()->GetInteger(prefs::kCookieControlsMode));
switch (mode) {
case CookieControlsMode::kOn:
return true;
case CookieControlsMode::kIncognitoOnly:
return is_incognito_;
case CookieControlsMode::kOff:
return false;
}
return false;
}
void CookieSettings::OnCookiePreferencesChanged() {
DCHECK(thread_checker_.CalledOnValidThread());
bool new_block_third_party_cookies =
pref_change_registrar_.prefs()->GetBoolean(
prefs::kBlockThirdPartyCookies) ||
IsCookieControlsEnabled();
// Safe to read |block_third_party_cookies_| without locking here because the
// only place that writes to it is this method and it will always be run on
// the same thread.
if (block_third_party_cookies_ != new_block_third_party_cookies) {
{
base::AutoLock auto_lock(lock_);
block_third_party_cookies_ = new_block_third_party_cookies;
}
for (Observer& obs : observers_)
obs.OnThirdPartyCookieBlockingChanged(new_block_third_party_cookies);
}
}
bool CookieSettings::ShouldBlockThirdPartyCookies() const {
base::AutoLock auto_lock(lock_);
return block_third_party_cookies_;
}
} // namespace content_settings