blob: d6f7510792fcad7c473fd328e56eec6adb4aa1dc [file] [log] [blame]
// Copyright 2019 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 "chrome/browser/extensions/chrome_extension_cookies.h"
#include "base/task/post_task.h"
#include "base/threading/sequenced_task_runner_handle.h"
#include "chrome/browser/content_settings/cookie_settings_factory.h"
#include "chrome/browser/content_settings/host_content_settings_map_factory.h"
#include "chrome/browser/extensions/chrome_extension_cookies_factory.h"
#include "chrome/browser/net/profile_network_context_service.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/chrome_constants.h"
#include "components/cookie_config/cookie_store_util.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/cookie_store_factory.h"
#include "extensions/common/constants.h"
#include "services/network/cookie_manager.h"
#include "services/network/restricted_cookie_manager.h"
namespace extensions {
ChromeExtensionCookies::ChromeExtensionCookies(Profile* profile)
: profile_(profile) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
cookie_settings_ = CookieSettingsFactory::GetForProfile(profile);
cookie_settings_observer_.Add(cookie_settings_.get());
HostContentSettingsMapFactory::GetForProfile(profile_)->AddObserver(this);
std::unique_ptr<content::CookieStoreConfig> creation_config;
if (profile_->IsIncognitoProfile() || profile_->AsTestingProfile()) {
creation_config = std::make_unique<content::CookieStoreConfig>();
} else {
creation_config = std::make_unique<content::CookieStoreConfig>(
profile_->GetPath().Append(chrome::kExtensionsCookieFilename),
profile_->ShouldRestoreOldSessionCookies(),
profile_->ShouldPersistSessionCookies(), nullptr /* storage_policy */);
creation_config->crypto_delegate = cookie_config::GetCookieCryptoDelegate();
}
creation_config->cookieable_schemes.push_back(extensions::kExtensionScheme);
network::mojom::CookieManagerParamsPtr initial_settings =
ProfileNetworkContextService::CreateCookieManagerParams(
profile_, *cookie_settings_);
io_data_ = std::make_unique<IOData>(std::move(creation_config),
std::move(initial_settings));
}
ChromeExtensionCookies::~ChromeExtensionCookies() {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
DCHECK(!io_data_);
}
// static
ChromeExtensionCookies* ChromeExtensionCookies::Get(
content::BrowserContext* context) {
return ChromeExtensionCookiesFactory::GetForBrowserContext(context);
}
void ChromeExtensionCookies::CreateRestrictedCookieManager(
const url::Origin& origin,
const GURL& site_for_cookies,
const url::Origin& top_frame_origin,
mojo::PendingReceiver<network::mojom::RestrictedCookieManager> receiver) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
if (!io_data_)
return;
// Safe since |io_data_| is non-null so no IOData deletion is queued.
base::PostTask(
FROM_HERE, {content::BrowserThread::IO},
base::BindOnce(&IOData::CreateRestrictedCookieManager,
base::Unretained(io_data_.get()), origin, site_for_cookies,
top_frame_origin, std::move(receiver)));
}
void ChromeExtensionCookies::ClearCookies(const GURL& origin) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
if (!io_data_) // null after shutdown.
return;
// Safe since |io_data_| is non-null so no IOData deletion is queued.
base::PostTask(FROM_HERE, {content::BrowserThread::IO},
base::BindOnce(&IOData::ClearCookies,
base::Unretained(io_data_.get()), origin));
}
net::CookieStore* ChromeExtensionCookies::GetCookieStoreForTesting() {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
if (!io_data_) // null after shutdown.
return nullptr;
return io_data_->GetOrCreateCookieStore();
}
ChromeExtensionCookies::IOData::IOData(
std::unique_ptr<content::CookieStoreConfig> creation_config,
network::mojom::CookieManagerParamsPtr initial_mojo_cookie_settings)
: creation_config_(std::move(creation_config)),
mojo_cookie_settings_(std::move(initial_mojo_cookie_settings)) {
UpdateNetworkCookieSettings();
}
ChromeExtensionCookies::IOData::~IOData() {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
}
void ChromeExtensionCookies::IOData::CreateRestrictedCookieManager(
const url::Origin& origin,
const GURL& site_for_cookies,
const url::Origin& top_frame_origin,
mojo::PendingReceiver<network::mojom::RestrictedCookieManager> receiver) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
restricted_cookie_managers_.Add(
std::make_unique<network::RestrictedCookieManager>(
network::mojom::RestrictedCookieManagerRole::SCRIPT,
GetOrCreateCookieStore(), &network_cookie_settings_, origin,
site_for_cookies, top_frame_origin,
/* null network_context_client disables logging, making later
arguments irrelevant */
nullptr, false, -1, -1),
std::move(receiver));
}
void ChromeExtensionCookies::IOData::ClearCookies(const GURL& origin) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
net::CookieDeletionInfo delete_info;
delete_info.host = origin.host();
GetOrCreateCookieStore()->DeleteAllMatchingInfoAsync(
std::move(delete_info), net::CookieStore::DeleteCallback());
}
void ChromeExtensionCookies::IOData::OnContentSettingChanged(
ContentSettingsForOneType settings) {
mojo_cookie_settings_->settings = std::move(settings);
UpdateNetworkCookieSettings();
}
void ChromeExtensionCookies::IOData::OnThirdPartyCookieBlockingChanged(
bool block_third_party_cookies) {
mojo_cookie_settings_->block_third_party_cookies = block_third_party_cookies;
UpdateNetworkCookieSettings();
}
net::CookieStore* ChromeExtensionCookies::IOData::GetOrCreateCookieStore() {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
if (!cookie_store_) {
cookie_store_ =
content::CreateCookieStore(*creation_config_, nullptr /* netlog */);
}
return cookie_store_.get();
}
void ChromeExtensionCookies::IOData::UpdateNetworkCookieSettings() {
network::CookieManager::ConfigureCookieSettings(*mojo_cookie_settings_,
&network_cookie_settings_);
}
void ChromeExtensionCookies::OnContentSettingChanged(
const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_pattern,
ContentSettingsType content_type,
const std::string& resource_identifier) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
if (!io_data_) // null after shutdown.
return;
if (content_type != ContentSettingsType::COOKIES &&
content_type != ContentSettingsType::DEFAULT) {
return;
}
ContentSettingsForOneType settings;
HostContentSettingsMapFactory::GetForProfile(profile_)->GetSettingsForOneType(
ContentSettingsType::COOKIES, std::string(), &settings);
// Safe since |io_data_| is non-null so no IOData deletion is queued.
base::PostTask(
FROM_HERE, {content::BrowserThread::IO},
base::BindOnce(&IOData::OnContentSettingChanged,
base::Unretained(io_data_.get()), std::move(settings)));
}
void ChromeExtensionCookies::OnThirdPartyCookieBlockingChanged(
bool block_third_party_cookies) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
if (!io_data_) // null after shutdown.
return;
// Safe since |io_data_| is non-null so no IOData deletion is queued.
base::PostTask(FROM_HERE, {content::BrowserThread::IO},
base::BindOnce(&IOData::OnThirdPartyCookieBlockingChanged,
base::Unretained(io_data_.get()),
block_third_party_cookies));
}
void ChromeExtensionCookies::Shutdown() {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
// Async delete on IO thread, sequencing it after any previously posted
// operations.
//
// Note: during tests this may be called with IO thread == UI thread. If this
// were to use unique_ptr<.., DeleteOnIOThread> that case would result in
// unwanted synchronous deletion; hence DeleteSoon is used by hand.
base::DeleteSoon(FROM_HERE, {content::BrowserThread::IO},
std::move(io_data_));
profile_ = nullptr;
}
} // namespace extensions