blob: 0698239c45a747357c0075d1ccc198762a66adb0 [file] [log] [blame]
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/browser/storage_partition_impl.h"
#include <stdint.h>
#include <functional>
#include <memory>
#include <optional>
#include <utility>
#include <vector>
#include "base/barrier_callback.h"
#include "base/barrier_closure.h"
#include "base/command_line.h"
#include "base/containers/contains.h"
#include "base/dcheck_is_on.h"
#include "base/feature_list.h"
#include "base/files/file_util.h"
#include "base/functional/bind.h"
#include "base/functional/callback_forward.h"
#include "base/functional/callback_helpers.h"
#include "base/functional/concurrent_closures.h"
#include "base/location.h"
#include "base/memory/ptr_util.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/metrics/histogram_functions.h"
#include "base/numerics/safe_conversions.h"
#include "base/observer_list.h"
#include "base/run_loop.h"
#include "base/task/sequenced_task_runner.h"
#include "base/task/single_thread_task_runner.h"
#include "base/task/thread_pool.h"
#include "base/threading/sequence_local_storage_slot.h"
#include "base/types/optional_util.h"
#include "build/build_config.h"
#include "components/attribution_reporting/features.h"
#include "components/leveldb_proto/public/proto_database_provider.h"
#include "components/services/storage/privileged/cpp/bucket_client_info.h"
#include "components/services/storage/privileged/mojom/indexed_db_control.mojom.h"
#include "components/services/storage/public/cpp/buckets/bucket_locator.h"
#include "components/services/storage/public/cpp/constants.h"
#include "components/services/storage/public/cpp/filesystem/filesystem_impl.h"
#include "components/services/storage/public/mojom/filesystem/directory.mojom.h"
#include "components/services/storage/public/mojom/storage_service.mojom.h"
#include "components/services/storage/shared_storage/shared_storage_manager.h"
#include "components/services/storage/storage_service_impl.h"
#include "components/variations/net/variations_http_headers.h"
#include "content/browser/aggregation_service/aggregation_service.h"
#include "content/browser/aggregation_service/aggregation_service_impl.h"
#include "content/browser/attribution_reporting/attribution_manager_impl.h"
#include "content/browser/background_fetch/background_fetch_context.h"
#include "content/browser/blob_storage/blob_registry_wrapper.h"
#include "content/browser/blob_storage/chrome_blob_storage_context.h"
#include "content/browser/bluetooth/bluetooth_allowed_devices_map.h"
#include "content/browser/broadcast_channel/broadcast_channel_service.h"
#include "content/browser/browsing_data/clear_site_data_handler.h"
#include "content/browser/browsing_data/storage_partition_code_cache_data_remover.h"
#include "content/browser/browsing_topics/browsing_topics_site_data_manager_impl.h"
#include "content/browser/buckets/bucket_manager.h"
#include "content/browser/cache_storage/cache_storage_control_wrapper.h"
#include "content/browser/code_cache/generated_code_cache.h"
#include "content/browser/code_cache/generated_code_cache_context.h"
#include "content/browser/cookie_deprecation_label/cookie_deprecation_label_manager_impl.h"
#include "content/browser/cookie_store/cookie_store_manager.h"
#include "content/browser/devtools/devtools_background_services_context_impl.h"
#include "content/browser/devtools/devtools_instrumentation.h"
#include "content/browser/devtools/devtools_url_loader_interceptor.h"
#include "content/browser/file_system/browser_file_system_helper.h"
#include "content/browser/file_system_access/file_system_access_manager_impl.h"
#include "content/browser/font_access/font_access_manager.h"
#include "content/browser/gpu/gpu_disk_cache_factory.h"
#include "content/browser/guest_page_holder_impl.h"
#include "content/browser/host_zoom_level_context.h"
#include "content/browser/indexed_db/indexed_db_control_wrapper.h"
#include "content/browser/interest_group/interest_group_manager_impl.h"
#include "content/browser/loader/keep_alive_url_loader_service.h"
#include "content/browser/loader/reconnectable_url_loader_factory.h"
#include "content/browser/loader/subresource_proxying_url_loader_service.h"
#include "content/browser/loader/url_loader_factory_utils.h"
#include "content/browser/locks/lock_manager.h"
#include "content/browser/navigation_or_document_handle.h"
#include "content/browser/network/shared_dictionary_util.h"
#include "content/browser/network_context_client_base_impl.h"
#include "content/browser/network_service_instance_impl.h"
#include "content/browser/notifications/platform_notification_context_impl.h"
#include "content/browser/payments/payment_app_context_impl.h"
#include "content/browser/preloading/prerender/prerender_final_status.h"
#include "content/browser/private_aggregation/private_aggregation_manager.h"
#include "content/browser/private_aggregation/private_aggregation_manager_impl.h"
#include "content/browser/push_messaging/push_messaging_context.h"
#include "content/browser/quota/quota_context.h"
#include "content/browser/renderer_host/frame_tree_node.h"
#include "content/browser/renderer_host/navigation_request.h"
#include "content/browser/renderer_host/navigation_state_keep_alive.h"
#include "content/browser/service_worker/service_worker_client.h"
#include "content/browser/service_worker/service_worker_context_wrapper.h"
#include "content/browser/shared_storage/shared_storage_header_observer.h"
#include "content/browser/shared_storage/shared_storage_runtime_manager.h"
#include "content/browser/ssl/ssl_client_auth_handler.h"
#include "content/browser/ssl/ssl_error_handler.h"
#include "content/browser/ssl_private_key_impl.h"
#include "content/browser/web_contents/web_contents_impl.h"
#include "content/browser/worker_host/shared_worker_service_impl.h"
#include "content/common/features.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/browsing_data_filter_builder.h"
#include "content/public/browser/content_browser_client.h"
#include "content/public/browser/cookie_access_details.h"
#include "content/public/browser/dom_storage_context.h"
#include "content/public/browser/login_delegate.h"
#include "content/public/browser/network_service_instance.h"
#include "content/public/browser/permission_controller.h"
#include "content/public/browser/permission_descriptor_util.h"
#include "content/public/browser/permission_result.h"
#include "content/public/browser/private_aggregation_data_model.h"
#include "content/public/browser/private_network_device_delegate.h"
#include "content/public/browser/runtime_feature_state/runtime_feature_state_document_data.h"
#include "content/public/browser/service_process_host.h"
#include "content/public/browser/session_storage_usage_info.h"
#include "content/public/browser/shared_cors_origin_access_list.h"
#include "content/public/browser/storage_notification_service.h"
#include "content/public/browser/storage_partition_config.h"
#include "content/public/browser/storage_usage_info.h"
#include "content/public/common/content_client.h"
#include "content/public/common/content_constants.h"
#include "content/public/common/content_features.h"
#include "content/public/common/content_switches.h"
#include "mojo/public/cpp/bindings/callback_helpers.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "mojo/public/cpp/bindings/self_owned_receiver.h"
#include "net/base/features.h"
#include "net/base/net_errors.h"
#include "net/cookies/cookie_setting_override.h"
#include "net/ssl/client_cert_store.h"
#include "ppapi/buildflags/buildflags.h"
#include "services/cert_verifier/public/mojom/cert_verifier_service_factory.mojom.h"
#include "services/network/public/cpp/cors/origin_access_list.h"
#include "services/network/public/cpp/features.h"
#include "services/network/public/cpp/ip_address_space_util.h"
#include "services/network/public/cpp/is_potentially_trustworthy.h"
#include "services/network/public/cpp/url_loader_factory_builder.h"
#include "services/network/public/mojom/clear_data_filter.mojom.h"
#include "services/network/public/mojom/cookie_access_observer.mojom.h"
#include "services/network/public/mojom/cookie_manager.mojom.h"
#include "services/network/public/mojom/device_bound_sessions.mojom.h"
#include "services/network/public/mojom/network_context.mojom.h"
#include "services/network/public/mojom/shared_dictionary_access_observer.mojom.h"
#include "services/network/public/mojom/trust_tokens.mojom.h"
#include "services/network/public/mojom/url_loader_network_service_observer.mojom.h"
#include "storage/browser/quota/quota_client_type.h"
#include "storage/browser/quota/quota_manager.h"
#include "storage/browser/quota/quota_manager_impl.h"
#include "storage/browser/quota/quota_settings.h"
#include "third_party/blink/public/common/features.h"
#include "third_party/blink/public/common/navigation/preloading_headers.h"
#include "third_party/blink/public/common/permissions/permission_utils.h"
#include "third_party/blink/public/common/storage_key/storage_key.h"
#include "third_party/blink/public/mojom/devtools/inspector_issue.mojom-shared.h"
#include "third_party/blink/public/mojom/private_network_device/private_network_device.mojom.h"
#include "url/scheme_host_port.h"
#if BUILDFLAG(IS_ANDROID)
#include "content/public/browser/android/java_interfaces.h"
#include "net/android/http_auth_negotiate_android.h"
#include "services/service_manager/public/cpp/interface_provider.h"
#endif // BUILDFLAG(IS_ANDROID)
#if BUILDFLAG(ENABLE_LIBRARY_CDMS)
#include "content/browser/media/cdm_storage_common.h"
#include "content/browser/media/cdm_storage_manager.h"
#include "content/public/browser/cdm_storage_data_model.h"
#endif // BUILDFLAG(ENABLE_LIBRARY_CDMS)
using CookieDeletionFilter = network::mojom::CookieDeletionFilter;
using CookieDeletionFilterPtr = network::mojom::CookieDeletionFilterPtr;
namespace content {
namespace {
using Type = StoragePartitionImpl::ContextType;
const storage::QuotaSettings* g_test_quota_settings;
// Timeout after which the
// History.ClearBrowsingData.Duration.SlowTasks180sStoragePartition histogram is
// recorded.
const base::TimeDelta kSlowTaskTimeout = base::Seconds(180);
// If true, Storage Service instances will always be started in-process.
bool g_force_in_process_storage_service = false;
mojo::Remote<storage::mojom::StorageService>& GetStorageServiceRemoteStorage() {
// NOTE: This use of sequence-local storage is only to ensure that the Remote
// only lives as long as the UI-thread sequence, since the UI-thread sequence
// may be torn down and reinitialized e.g. between unit tests.
static base::SequenceLocalStorageSlot<
mojo::Remote<storage::mojom::StorageService>>
remote_slot;
return remote_slot.GetOrCreateValue();
}
void RunInProcessStorageService(
mojo::PendingReceiver<storage::mojom::StorageService> receiver) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
static base::SequenceLocalStorageSlot<
std::unique_ptr<storage::StorageServiceImpl>>
service_storage_slot;
service_storage_slot.GetOrCreateValue() =
std::make_unique<storage::StorageServiceImpl>(std::move(receiver),
/*io_task_runner=*/nullptr);
}
#if !BUILDFLAG(IS_ANDROID)
void BindStorageServiceFilesystemImpl(
const base::FilePath& directory_path,
mojo::PendingReceiver<storage::mojom::Directory> receiver) {
mojo::MakeSelfOwnedReceiver(
std::make_unique<storage::FilesystemImpl>(
directory_path, storage::FilesystemImpl::ClientType::kUntrusted),
std::move(receiver));
}
#endif
mojo::Remote<storage::mojom::StorageService>& GetStorageServiceRemote() {
mojo::Remote<storage::mojom::StorageService>& remote =
GetStorageServiceRemoteStorage();
if (!remote) {
#if !BUILDFLAG(IS_ANDROID)
const base::FilePath sandboxed_data_dir =
GetContentClient()
->browser()
->GetSandboxedStorageServiceDataDirectory();
const bool single_process_mode =
base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kSingleProcess);
const bool oop_storage_enabled = !sandboxed_data_dir.empty() &&
!single_process_mode &&
!g_force_in_process_storage_service;
if (oop_storage_enabled) {
DCHECK(sandboxed_data_dir.IsAbsolute())
<< "Storage Service data directory must be an absolute path, but \""
<< sandboxed_data_dir << "\" is not an absolute path.";
remote = ServiceProcessHost::Launch<storage::mojom::StorageService>(
ServiceProcessHost::Options()
.WithDisplayName("Storage Service")
.Pass());
remote.reset_on_disconnect();
// Provide the service with an API it can use to access filesystem
// contents *only* within the embedder's specified data directory.
mojo::PendingRemote<storage::mojom::Directory> directory;
base::ThreadPool::CreateSequencedTaskRunner(
{base::MayBlock(), base::TaskPriority::USER_VISIBLE})
->PostTask(FROM_HERE,
base::BindOnce(
&BindStorageServiceFilesystemImpl, sandboxed_data_dir,
directory.InitWithNewPipeAndPassReceiver()));
remote->SetDataDirectory(sandboxed_data_dir, std::move(directory));
} else
#endif // !BUILDFLAG(IS_ANDROID)
{
GetIOThreadTaskRunner({})->PostTask(
FROM_HERE, base::BindOnce(&RunInProcessStorageService,
remote.BindNewPipeAndPassReceiver()));
}
if (base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kEnableAggressiveDOMStorageFlushing)) {
remote->EnableAggressiveDomStorageFlushing();
}
}
return remote;
}
void OnClearedCookies(base::OnceClosure callback, uint32_t num_deleted) {
// The final callback needs to happen from UI thread.
if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
GetUIThreadTaskRunner({})->PostTask(
FROM_HERE,
base::BindOnce(&OnClearedCookies, std::move(callback), num_deleted));
return;
}
std::move(callback).Run();
}
void CheckQuotaManagedDataDeletionStatus(size_t* deletion_task_count,
base::OnceClosure callback) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (*deletion_task_count == 0) {
delete deletion_task_count;
std::move(callback).Run();
}
}
void OnQuotaManagedBucketDeleted(const storage::BucketLocator& bucket,
size_t* deletion_task_count,
base::OnceClosure callback,
blink::mojom::QuotaStatusCode status) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
DCHECK_GT(*deletion_task_count, 0u);
if (status != blink::mojom::QuotaStatusCode::kOk) {
DLOG(ERROR) << "Couldn't remove data for bucket with storage key "
<< bucket.storage_key.GetDebugString() << " is_default "
<< bucket.is_default << " and bucket id " << bucket.id
<< ". Status: " << static_cast<int>(status);
}
(*deletion_task_count)--;
CheckQuotaManagedDataDeletionStatus(deletion_task_count, std::move(callback));
}
void PerformQuotaManagerStorageCleanup(
const scoped_refptr<storage::QuotaManager>& quota_manager,
storage::QuotaClientTypes quota_client_types,
base::OnceClosure callback) {
quota_manager->PerformStorageCleanup(std::move(quota_client_types),
std::move(callback));
}
void ClearedGpuCache(base::OnceClosure callback) {
if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
GetUIThreadTaskRunner({})->PostTask(
FROM_HERE, base::BindOnce(&ClearedGpuCache, std::move(callback)));
return;
}
std::move(callback).Run();
}
void OnLocalStorageUsageInfo(
const scoped_refptr<DOMStorageContextWrapper>& dom_storage_context,
const scoped_refptr<storage::SpecialStoragePolicy>& special_storage_policy,
StoragePartition::StorageKeyPolicyMatcherFunction storage_key_matcher,
bool perform_storage_cleanup,
const base::Time delete_begin,
const base::Time delete_end,
base::OnceClosure callback,
const std::vector<StorageUsageInfo>& infos) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
base::OnceClosure done_callback =
perform_storage_cleanup
? base::BindOnce(
&DOMStorageContextWrapper::PerformLocalStorageCleanup,
dom_storage_context, std::move(callback))
: std::move(callback);
base::ConcurrentClosures concurrent;
for (const StorageUsageInfo& info : infos) {
if (storage_key_matcher &&
!storage_key_matcher.Run(info.storage_key,
special_storage_policy.get())) {
continue;
}
if (info.last_modified >= delete_begin &&
info.last_modified <= delete_end) {
dom_storage_context->DeleteLocalStorage(info.storage_key,
concurrent.CreateClosure());
}
}
std::move(concurrent).Done(std::move(done_callback));
}
void OnSessionStorageUsageInfo(
const scoped_refptr<DOMStorageContextWrapper>& dom_storage_context,
const scoped_refptr<storage::SpecialStoragePolicy>& special_storage_policy,
StoragePartition::StorageKeyPolicyMatcherFunction storage_key_matcher,
bool perform_storage_cleanup,
base::OnceClosure callback,
const std::vector<SessionStorageUsageInfo>& infos) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
base::OnceClosure done_callback =
perform_storage_cleanup
? base::BindOnce(
&DOMStorageContextWrapper::PerformSessionStorageCleanup,
dom_storage_context, std::move(callback))
: std::move(callback);
base::ConcurrentClosures concurrent;
for (const SessionStorageUsageInfo& info : infos) {
if (storage_key_matcher &&
!storage_key_matcher.Run(info.storage_key,
special_storage_policy.get())) {
continue;
}
dom_storage_context->DeleteSessionStorage(info, concurrent.CreateClosure());
}
std::move(concurrent).Done(std::move(done_callback));
}
void ClearLocalStorageOnUIThread(
const scoped_refptr<DOMStorageContextWrapper>& dom_storage_context,
const scoped_refptr<storage::SpecialStoragePolicy>& special_storage_policy,
StoragePartition::StorageKeyPolicyMatcherFunction storage_key_matcher,
const blink::StorageKey& storage_key,
bool perform_storage_cleanup,
const base::Time begin,
const base::Time end,
base::OnceClosure callback) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (!storage_key.origin().opaque()) {
bool can_delete =
!storage_key_matcher ||
storage_key_matcher.Run(storage_key, special_storage_policy.get());
if (can_delete) {
dom_storage_context->DeleteLocalStorage(storage_key, std::move(callback));
} else {
std::move(callback).Run();
}
return;
}
dom_storage_context->GetLocalStorageUsage(
base::BindOnce(&OnLocalStorageUsageInfo, dom_storage_context,
special_storage_policy, std::move(storage_key_matcher),
perform_storage_cleanup, begin, end, std::move(callback)));
}
void ClearSessionStorageOnUIThread(
const scoped_refptr<DOMStorageContextWrapper>& dom_storage_context,
const scoped_refptr<storage::SpecialStoragePolicy>& special_storage_policy,
StoragePartition::StorageKeyPolicyMatcherFunction storage_key_matcher,
bool perform_storage_cleanup,
base::OnceClosure callback) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
dom_storage_context->GetSessionStorageUsage(
base::BindOnce(&OnSessionStorageUsageInfo, dom_storage_context,
special_storage_policy, std::move(storage_key_matcher),
perform_storage_cleanup, std::move(callback)));
}
// LoginHandlerDelegate manages HTTP auth. It is self-owning and deletes itself
// when the credentials are resolved or the AuthChallengeResponder is cancelled.
class LoginHandlerDelegate {
public:
LoginHandlerDelegate(
mojo::PendingRemote<network::mojom::AuthChallengeResponder>
auth_challenge_responder,
WebContents* web_contents,
content::BrowserContext* browser_context,
const net::AuthChallengeInfo& auth_info,
bool is_request_for_primary_main_frame_navigation,
bool is_request_for_navigation,
base::StrictNumeric<int32_t> process_id,
base::StrictNumeric<int32_t> request_id,
const GURL& url,
scoped_refptr<net::HttpResponseHeaders> response_headers,
bool first_auth_attempt,
FrameTreeNodeId frame_tree_node_id)
: auth_challenge_responder_(std::move(auth_challenge_responder)),
auth_info_(auth_info),
request_id_(process_id, request_id),
is_request_for_primary_main_frame_navigation_(
is_request_for_primary_main_frame_navigation),
is_request_for_navigation_(is_request_for_navigation),
creating_login_delegate_(false),
url_(url),
response_headers_(std::move(response_headers)),
first_auth_attempt_(first_auth_attempt),
web_contents_(web_contents ? web_contents->GetWeakPtr() : nullptr),
browser_context_(browser_context->GetWeakPtr()),
frame_tree_node_id_(frame_tree_node_id) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
auth_challenge_responder_.set_disconnect_handler(base::BindOnce(
&LoginHandlerDelegate::OnRequestCancelled, base::Unretained(this)));
DevToolsURLLoaderInterceptor::HandleAuthRequest(
request_id_, auth_info_,
base::BindOnce(&LoginHandlerDelegate::ContinueAfterInterceptor,
weak_factory_.GetWeakPtr()));
}
private:
void OnRequestCancelled() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
// This will destroy `login_handler_io_` on the IO thread and, if needed,
// inform the delegate.
delete this;
}
void ContinueAfterInterceptor(
bool use_fallback,
const std::optional<net::AuthCredentials>& auth_credentials) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK(!(use_fallback && auth_credentials.has_value()));
if (!use_fallback) {
OnAuthCredentials(auth_credentials);
return;
}
if (!browser_context_) {
OnAuthCredentials(std::nullopt);
return;
}
if (web_contents_) {
CHECK_EQ(web_contents_->GetBrowserContext(), browser_context_.get());
}
FrameTreeNode* frame_tree_node =
FrameTreeNode::GloballyFindByID(frame_tree_node_id_);
GuestPageHolder* guest = nullptr;
if (frame_tree_node) {
guest = GuestPageHolderImpl::FromRenderFrameHost(
*frame_tree_node->current_frame_host());
}
// WeakPtr is not strictly necessary here due to OnRequestCancelled.
creating_login_delegate_ = true;
login_delegate_ = GetContentClient()->browser()->CreateLoginDelegate(
auth_info_, web_contents_.get(), browser_context_.get(), request_id_,
is_request_for_primary_main_frame_navigation_,
is_request_for_navigation_, url_, response_headers_,
first_auth_attempt_, guest,
base::BindOnce(&LoginHandlerDelegate::OnAuthCredentials,
weak_factory_.GetWeakPtr()));
creating_login_delegate_ = false;
if (!login_delegate_) {
OnAuthCredentials(std::nullopt);
return;
}
}
void OnAuthCredentials(
const std::optional<net::AuthCredentials>& auth_credentials) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
// CreateLoginDelegate must not call the callback reentrantly. For
// robustness, detect this mistake.
CHECK(!creating_login_delegate_);
auth_challenge_responder_->OnAuthCredentials(auth_credentials);
delete this;
}
mojo::Remote<network::mojom::AuthChallengeResponder>
auth_challenge_responder_;
net::AuthChallengeInfo auth_info_;
const content::GlobalRequestID request_id_;
bool is_request_for_primary_main_frame_navigation_;
bool is_request_for_navigation_;
bool creating_login_delegate_;
GURL url_;
const scoped_refptr<net::HttpResponseHeaders> response_headers_;
bool first_auth_attempt_;
base::WeakPtr<WebContents> web_contents_;
base::WeakPtr<BrowserContext> browser_context_;
std::unique_ptr<LoginDelegate> login_delegate_;
FrameTreeNodeId frame_tree_node_id_;
base::WeakPtrFactory<LoginHandlerDelegate> weak_factory_{this};
};
// This class lives on the UI thread. It is self-owned and will delete itself
// after any of the SSLClientAuthHandler::Delegate methods are invoked (or when
// a mojo connection error occurs).
class SSLClientAuthDelegate : public SSLClientAuthHandler::Delegate {
public:
SSLClientAuthDelegate(
mojo::PendingRemote<network::mojom::ClientCertificateResponder>
client_cert_responder_remote,
BrowserContext* browser_context,
int process_id,
base::WeakPtr<WebContents> web_contents,
const scoped_refptr<net::SSLCertRequestInfo>& cert_info)
: client_cert_responder_(std::move(client_cert_responder_remote)),
ssl_client_auth_handler_(std::make_unique<SSLClientAuthHandler>(
GetContentClient()->browser()->CreateClientCertStore(
browser_context),
browser_context->GetWeakPtr(),
process_id,
web_contents,
std::move(cert_info.get()),
this)) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK(client_cert_responder_);
client_cert_responder_.set_disconnect_handler(base::BindOnce(
&SSLClientAuthDelegate::DeleteSelf, base::Unretained(this)));
ssl_client_auth_handler_->SelectCertificate();
}
~SSLClientAuthDelegate() override { DCHECK_CURRENTLY_ON(BrowserThread::UI); }
void DeleteSelf() { delete this; }
// SSLClientAuthHandler::Delegate:
void CancelCertificateSelection() override {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
client_cert_responder_->CancelRequest();
DeleteSelf();
}
// SSLClientAuthHandler::Delegate:
void ContinueWithCertificate(
scoped_refptr<net::X509Certificate> cert,
scoped_refptr<net::SSLPrivateKey> private_key) override {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (cert && private_key) {
mojo::PendingRemote<network::mojom::SSLPrivateKey> ssl_private_key;
mojo::MakeSelfOwnedReceiver(
std::make_unique<SSLPrivateKeyImpl>(private_key),
ssl_private_key.InitWithNewPipeAndPassReceiver());
client_cert_responder_->ContinueWithCertificate(
cert, private_key->GetProviderName(),
private_key->GetAlgorithmPreferences(), std::move(ssl_private_key));
} else {
client_cert_responder_->ContinueWithoutCertificate();
}
DeleteSelf();
}
private:
mojo::Remote<network::mojom::ClientCertificateResponder>
client_cert_responder_;
std::unique_ptr<SSLClientAuthHandler> ssl_client_auth_handler_;
};
void CallCancelRequest(
mojo::PendingRemote<network::mojom::ClientCertificateResponder>
client_cert_responder_remote) {
DCHECK(client_cert_responder_remote);
mojo::Remote<network::mojom::ClientCertificateResponder>
client_cert_responder(std::move(client_cert_responder_remote));
client_cert_responder->CancelRequest();
}
// Cancels prerendering if `navigation_or_document` is in a prerendered frame
// tree, using `final_status` as the cancellation reason. Returns true if
// cancelled.
bool CancelIfPrerendering(NavigationOrDocumentHandle* navigation_or_document,
PrerenderFinalStatus final_status) {
FrameTreeNode* frame_tree_node = nullptr;
// `navigation_or_document` can be null for `kServiceWorkerContext`.
if (!navigation_or_document) {
return false;
}
auto* navigation_request = navigation_or_document->GetNavigationRequest();
if (navigation_request) {
frame_tree_node = navigation_request->frame_tree_node();
}
auto* render_frame_host = navigation_or_document->GetDocument();
if (render_frame_host) {
frame_tree_node = FrameTreeNode::From(render_frame_host);
}
if (!frame_tree_node) {
return false;
}
auto* web_contents = WebContentsImpl::FromFrameTreeNode(frame_tree_node);
return web_contents->CancelPrerendering(frame_tree_node, final_status);
}
class SSLErrorDelegate : public SSLErrorHandler::Delegate {
public:
explicit SSLErrorDelegate(network::mojom::URLLoaderNetworkServiceObserver::
OnSSLCertificateErrorCallback response)
: response_(std::move(response)) {}
~SSLErrorDelegate() override = default;
void CancelSSLRequest(int error, const net::SSLInfo* ssl_info) override {
std::move(response_).Run(error);
delete this;
}
void ContinueSSLRequest() override {
std::move(response_).Run(net::OK);
delete this;
}
base::WeakPtr<SSLErrorDelegate> GetWeakPtr() {
return weak_factory_.GetWeakPtr();
}
private:
network::mojom::URLLoaderNetworkServiceObserver::OnSSLCertificateErrorCallback
response_;
base::WeakPtrFactory<SSLErrorDelegate> weak_factory_{this};
};
#if BUILDFLAG(IS_ANDROID)
void FinishGenerateNegotiateAuthToken(
std::unique_ptr<net::android::HttpAuthNegotiateAndroid> auth_negotiate,
std::unique_ptr<std::string> auth_token,
std::unique_ptr<net::HttpAuthPreferences> prefs,
network::mojom::NetworkContextClient::
OnGenerateHttpNegotiateAuthTokenCallback callback,
int result) {
std::move(callback).Run(result, *auth_token);
}
#endif
// If both `storage_key_matcher` and `storage_key_policy_matcher` are null, this
// should return a null callback that indicates all StorageKeys should match.
// Otherwise, returns true if StorageKey matches both `storage_key_matcher` and
// `storage_key_policy_matcher` if not null.
StoragePartition::StorageKeyPolicyMatcherFunction
CombineStorageKeyMatcherFunctions(
StoragePartition::StorageKeyMatcherFunction storage_key_matcher,
StoragePartition::StorageKeyPolicyMatcherFunction
storage_key_policy_matcher) {
if (storage_key_matcher.is_null() && storage_key_policy_matcher.is_null()) {
return base::NullCallback();
}
return base::BindRepeating(
[](StoragePartition::StorageKeyMatcherFunction storage_key_matcher,
StoragePartition::StorageKeyPolicyMatcherFunction
storage_key_policy_matcher,
const blink::StorageKey& storage_key,
storage::SpecialStoragePolicy* policy) -> bool {
return (!storage_key_matcher || storage_key_matcher.Run(storage_key)) &&
(!storage_key_policy_matcher ||
storage_key_policy_matcher.Run(storage_key, policy));
},
std::move(storage_key_matcher), std::move(storage_key_policy_matcher));
}
// Conceptually, many downstream interfaces don't need to know about the
// complexity of callers into StoragePartition, so this function reduces the API
// surface to something simple and generic. It is designed to be used by
// callsites in ClearDataImpl.
//
// Precondition: `storage_key_matcher`/`storage_key_policy_matcher` and
// `storage_key` cannot both be set. If all of `storage_key_matcher`,
// `storage_key_policy_matcher` and `storage_key` are null/empty, this should
// return a null callback that indicates all StorageKeys should match. This is
// an optimization for backends to efficiently clear all data.
//
// TODO(csharrison, mek): Right now, this is only used by a small set of storage
// backends, e.g. aggregation service. We should consider moving some of the
// backends to use this if they can, and additionally we should consider
// rethinking this approach if / when storage backends move out of process
// (see crbug.com/1016065 for initial work here).
StoragePartition::StorageKeyMatcherFunction CreateGenericStorageKeyMatcher(
const blink::StorageKey& storage_key,
StoragePartition::StorageKeyMatcherFunction storage_key_matcher,
StoragePartition::StorageKeyPolicyMatcherFunction
storage_key_policy_matcher,
scoped_refptr<storage::SpecialStoragePolicy> policy) {
const bool storage_key_origin_empty = storage_key.origin().opaque();
DCHECK(storage_key_origin_empty || storage_key_matcher.is_null());
DCHECK(storage_key_origin_empty || storage_key_policy_matcher.is_null());
if (storage_key_origin_empty && storage_key_matcher.is_null() &&
storage_key_policy_matcher.is_null()) {
return base::NullCallback();
}
if (storage_key_matcher || storage_key_policy_matcher) {
return base::BindRepeating(
[](StoragePartition::StorageKeyPolicyMatcherFunction
storage_key_policy_matcher,
scoped_refptr<storage::SpecialStoragePolicy> policy,
const blink::StorageKey& storage_key) -> bool {
DCHECK(!storage_key_policy_matcher.is_null());
return storage_key_policy_matcher.Run(storage_key, policy.get());
},
CombineStorageKeyMatcherFunctions(
std::move(storage_key_matcher),
std::move(storage_key_policy_matcher)),
std::move(policy));
}
DCHECK(!storage_key_origin_empty);
return base::BindRepeating(std::equal_to<const blink::StorageKey&>(),
storage_key);
}
std::vector<GlobalRenderFrameHostId> GetRoutingIdsForOrigin(
StoragePartitionImpl* storage_partition,
const url::Origin& origin) {
scoped_refptr<ServiceWorkerContextWrapper> service_worker_context =
storage_partition->GetServiceWorkerContext();
return *service_worker_context->GetWindowClientFrameRoutingIds(
blink::StorageKey::CreateFirstParty(origin));
}
} // namespace
// Static.
storage::QuotaClientTypes StoragePartitionImpl::GenerateQuotaClientTypes(
uint32_t remove_mask) {
storage::QuotaClientTypes quota_client_types;
if (remove_mask & StoragePartition::REMOVE_DATA_MASK_FILE_SYSTEMS) {
quota_client_types.insert(storage::QuotaClientType::kFileSystem);
}
if (remove_mask & StoragePartition::REMOVE_DATA_MASK_WEBSQL) {
quota_client_types.insert(storage::QuotaClientType::kDatabase);
}
if (remove_mask & StoragePartition::REMOVE_DATA_MASK_INDEXEDDB) {
quota_client_types.insert(storage::QuotaClientType::kIndexedDatabase);
}
if (remove_mask & StoragePartition::REMOVE_DATA_MASK_SERVICE_WORKERS) {
quota_client_types.insert(storage::QuotaClientType::kServiceWorker);
}
if (remove_mask & StoragePartition::REMOVE_DATA_MASK_CACHE_STORAGE) {
quota_client_types.insert(storage::QuotaClientType::kServiceWorkerCache);
}
if (remove_mask & StoragePartition::REMOVE_DATA_MASK_BACKGROUND_FETCH) {
quota_client_types.insert(storage::QuotaClientType::kBackgroundFetch);
}
return quota_client_types;
}
// static
void StoragePartitionImpl::ForceInProcessStorageServiceForTesting() {
g_force_in_process_storage_service = true;
}
// Helper for deleting quota managed data from a partition.
//
// Most of the operations in this class are done on IO thread.
class StoragePartitionImpl::QuotaManagedDataDeletionHelper {
public:
QuotaManagedDataDeletionHelper(
uint32_t remove_mask,
uint32_t quota_storage_remove_mask,
const std::optional<blink::StorageKey>& storage_key,
base::OnceClosure callback)
: remove_mask_(remove_mask),
quota_storage_remove_mask_(quota_storage_remove_mask),
storage_key_(storage_key),
callback_(std::move(callback)),
task_count_(0) {
DCHECK(!storage_key_.has_value() || !storage_key_->origin().opaque());
}
QuotaManagedDataDeletionHelper(const QuotaManagedDataDeletionHelper&) =
delete;
QuotaManagedDataDeletionHelper& operator=(
const QuotaManagedDataDeletionHelper&) = delete;
void IncrementTaskCountOnIO();
void DecrementTaskCountOnIO();
void ClearDataOnIOThread(
const scoped_refptr<storage::QuotaManager>& quota_manager,
const base::Time begin,
const base::Time end,
const scoped_refptr<storage::SpecialStoragePolicy>&
special_storage_policy,
StoragePartition::StorageKeyPolicyMatcherFunction storage_key_matcher,
bool perform_storage_cleanup);
void ClearBucketsOnIOThread(
storage::QuotaManager* quota_manager,
const scoped_refptr<storage::SpecialStoragePolicy>&
special_storage_policy,
StoragePartition::StorageKeyPolicyMatcherFunction storage_key_matcher,
bool perform_storage_cleanup,
base::OnceClosure callback,
const std::set<storage::BucketLocator>& buckets);
private:
// All of these data are accessed on IO thread.
uint32_t remove_mask_;
uint32_t quota_storage_remove_mask_;
std::optional<blink::StorageKey> storage_key_;
base::OnceClosure callback_;
int task_count_;
};
// Helper for deleting all sorts of data from a partition, keeps track of
// deletion status.
//
// StoragePartitionImpl creates an instance of this class to keep track of
// data deletion progress. Deletion requires deleting multiple bits of data
// (e.g. cookies, local storage, session storage etc.) and hopping between UI
// and IO thread. An instance of this class is created in the beginning of
// deletion process (StoragePartitionImpl::ClearDataImpl) and the instance is
// forwarded and updated on each (sub) deletion's callback. The instance is
// finally destroyed when deletion completes (and `callback` is invoked).
class StoragePartitionImpl::DataDeletionHelper {
public:
DataDeletionHelper(uint32_t remove_mask,
uint32_t quota_storage_remove_mask,
base::OnceClosure callback)
: remove_mask_(remove_mask),
quota_storage_remove_mask_(quota_storage_remove_mask),
callback_(std::move(callback)) {}
DataDeletionHelper(const DataDeletionHelper&) = delete;
DataDeletionHelper& operator=(const DataDeletionHelper&) = delete;
~DataDeletionHelper() = default;
void ClearDataOnUIThread(
const blink::StorageKey& storage_key,
BrowsingDataFilterBuilder* filter_builder,
StorageKeyPolicyMatcherFunction storage_key_policy_matcher,
CookieDeletionFilterPtr cookie_deletion_filter,
const base::FilePath& path,
DOMStorageContextWrapper* dom_storage_context,
storage::QuotaManager* quota_manager,
storage::SpecialStoragePolicy* special_storage_policy,
storage::FileSystemContext* filesystem_context,
network::mojom::CookieManager* cookie_manager,
InterestGroupManagerImpl* interest_group_manager,
AttributionManager* attribution_manager,
AggregationService* aggregation_service,
PrivateAggregationManagerImpl* private_aggregation_manager,
storage::SharedStorageManager* shared_storage_manager,
#if BUILDFLAG(ENABLE_LIBRARY_CDMS)
CdmStorageManager* cdm_storage_manager,
#endif // BUILDFLAG(ENABLE_LIBRARY_CDMS)
network::mojom::DeviceBoundSessionManager* device_bound_session_manager,
bool perform_storage_cleanup,
const base::Time begin,
const base::Time end);
void ClearQuotaManagedDataOnIOThread(
const scoped_refptr<storage::QuotaManager>& quota_manager,
const base::Time begin,
const base::Time end,
const blink::StorageKey& storage_key,
const scoped_refptr<storage::SpecialStoragePolicy>&
special_storage_policy,
StoragePartition::StorageKeyPolicyMatcherFunction storage_key_matcher,
bool perform_storage_cleanup,
base::OnceClosure callback);
private:
// For debugging purposes. Please add new deletion tasks at the end.
// This enum is recorded in a histogram, so don't change or reuse ids.
// LINT.IfChange(TracingDataType)
enum class TracingDataType {
kSynchronous = 1,
kCookies = 2,
kQuota = 3,
kLocalStorage = 4,
kSessionStorage = 5,
kShaderCache = 6, // Deprecated in favor of using kGpuCache.
kPluginPrivate = 7, // Deprecated.
kConversions = 8,
kAggregationService = 9,
kSharedStorage = 10,
kGpuCache = 11,
kPrivateAggregation = 12,
kInterestGroups = 13,
kCdmStorage = 14,
kDeviceBoundSessions = 15,
kMaxValue = kDeviceBoundSessions,
};
// LINT.ThenChange(//tools/metrics/histograms/metadata/history/enums.xml:StoragePartitionRemoverTasks)
base::OnceClosure CreateTaskCompletionClosure(TracingDataType data_type);
void OnTaskComplete(TracingDataType data_type,
int tracing_id); // Callable on any thread.
void RecordUnfinishedSubTasks();
uint32_t remove_mask_;
uint32_t quota_storage_remove_mask_;
// Accessed on UI thread.
base::OnceClosure callback_;
// Accessed on UI thread.
std::set<TracingDataType> pending_tasks_;
base::WeakPtrFactory<StoragePartitionImpl::DataDeletionHelper> weak_factory_{
this};
};
void StoragePartitionImpl::DataDeletionHelper::ClearQuotaManagedDataOnIOThread(
const scoped_refptr<storage::QuotaManager>& quota_manager,
const base::Time begin,
const base::Time end,
const blink::StorageKey& storage_key,
const scoped_refptr<storage::SpecialStoragePolicy>& special_storage_policy,
StoragePartition::StorageKeyPolicyMatcherFunction storage_key_matcher,
bool perform_storage_cleanup,
base::OnceClosure callback) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
StoragePartitionImpl::QuotaManagedDataDeletionHelper* helper =
new StoragePartitionImpl::QuotaManagedDataDeletionHelper(
remove_mask_, quota_storage_remove_mask_,
storage_key.origin().opaque() ? std::nullopt
: std::make_optional(storage_key),
std::move(callback));
helper->ClearDataOnIOThread(quota_manager, begin, end, special_storage_policy,
std::move(storage_key_matcher),
perform_storage_cleanup);
}
class StoragePartitionImpl::ServiceWorkerCookieAccessObserver
: public network::mojom::CookieAccessObserver {
public:
explicit ServiceWorkerCookieAccessObserver(
StoragePartitionImpl* storage_partition)
: storage_partition_(storage_partition) {}
private:
void Clone(mojo::PendingReceiver<network::mojom::CookieAccessObserver>
observer) override {
storage_partition_->service_worker_cookie_observers_.Add(
std::make_unique<ServiceWorkerCookieAccessObserver>(storage_partition_),
std::move(observer));
}
void OnCookiesAccessed(std::vector<network::mojom::CookieAccessDetailsPtr>
details_vector) override {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
for (auto& details : details_vector) {
for (GlobalRenderFrameHostId frame_id : GetRoutingIdsForOrigin(
storage_partition_, url::Origin::Create(details->url))) {
if (RenderFrameHostImpl* rfh = RenderFrameHostImpl::FromID(frame_id)) {
rfh->NotifyCookiesAccessed(
mojo::Clone(details_vector),
CookieAccessDetails::Source::kNonNavigation);
}
}
}
}
// `storage_partition_` owns this object via UniqueReceiverSet
// (service_worker_cookie_observers_).
raw_ptr<StoragePartitionImpl> storage_partition_;
};
class StoragePartitionImpl::ServiceWorkerTrustTokenAccessObserver
: public network::mojom::TrustTokenAccessObserver {
public:
explicit ServiceWorkerTrustTokenAccessObserver(
StoragePartitionImpl* storage_partition)
: storage_partition_(storage_partition) {}
private:
void Clone(mojo::PendingReceiver<network::mojom::TrustTokenAccessObserver>
observer) override {
storage_partition_->service_worker_trust_token_observers_.Add(
std::make_unique<ServiceWorkerTrustTokenAccessObserver>(
storage_partition_),
std::move(observer));
}
void OnTrustTokensAccessed(
network::mojom::TrustTokenAccessDetailsPtr details) override {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
url::Origin origin;
switch (details->which()) {
case network::mojom::TrustTokenAccessDetails::Tag::kIssuance:
origin = details->get_issuance()->origin;
break;
case network::mojom::TrustTokenAccessDetails::Tag::kRedemption:
origin = details->get_redemption()->origin;
break;
case network::mojom::TrustTokenAccessDetails::Tag::kSigning:
origin = details->get_signing()->origin;
break;
}
for (GlobalRenderFrameHostId frame_id :
GetRoutingIdsForOrigin(storage_partition_, origin)) {
if (RenderFrameHostImpl* rfh = RenderFrameHostImpl::FromID(frame_id)) {
rfh->OnTrustTokensAccessed(mojo::Clone(details));
}
}
}
// `storage_partition_` owns this object via UniqueReceiverSet
// (service_worker_trust_token_observers_).
raw_ptr<StoragePartitionImpl> storage_partition_;
};
class StoragePartitionImpl::ServiceWorkerSharedDictionaryAccessObserver
: public network::mojom::SharedDictionaryAccessObserver {
public:
explicit ServiceWorkerSharedDictionaryAccessObserver(
StoragePartitionImpl* storage_partition)
: storage_partition_(storage_partition) {}
private:
void Clone(
mojo::PendingReceiver<network::mojom::SharedDictionaryAccessObserver>
observer) override {
storage_partition_->service_worker_shared_dictionary_observers_.Add(
std::make_unique<ServiceWorkerSharedDictionaryAccessObserver>(
storage_partition_),
std::move(observer));
}
void OnSharedDictionaryAccessed(
network::mojom::SharedDictionaryAccessDetailsPtr details) override {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
for (GlobalRenderFrameHostId frame_id : GetRoutingIdsForOrigin(
storage_partition_, details->isolation_key.frame_origin())) {
if (RenderFrameHostImpl* rfh = RenderFrameHostImpl::FromID(frame_id)) {
rfh->OnSharedDictionaryAccessed(mojo::Clone(details));
}
}
}
// `storage_partition_` owns this object via UniqueReceiverSet
// (service_worker_shared_dictionary_observers_).
raw_ptr<StoragePartitionImpl> storage_partition_;
};
class StoragePartitionImpl::ServiceWorkerDeviceBoundSessionAccessObserver
: public network::mojom::DeviceBoundSessionAccessObserver {
public:
explicit ServiceWorkerDeviceBoundSessionAccessObserver(
StoragePartitionImpl* storage_partition)
: storage_partition_(storage_partition) {}
private:
void Clone(
mojo::PendingReceiver<network::mojom::DeviceBoundSessionAccessObserver>
observer) override {
storage_partition_->service_worker_device_bound_session_observers_.Add(
std::make_unique<ServiceWorkerDeviceBoundSessionAccessObserver>(
storage_partition_),
std::move(observer));
}
void OnDeviceBoundSessionAccessed(
const net::device_bound_sessions::SessionAccess& access) override {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
for (GlobalRenderFrameHostId frame_id : GetRoutingIdsForOrigin(
storage_partition_,
url::Origin::Create(access.session_key.site.GetURL()))) {
if (RenderFrameHostImpl* rfh = RenderFrameHostImpl::FromID(frame_id)) {
rfh->OnDeviceBoundSessionAccessed(access);
}
}
}
// `storage_partition_` owns this object via UniqueReceiverSet
// (service_worker_device_bound_session_observers_).
raw_ptr<StoragePartitionImpl> storage_partition_;
};
struct StoragePartitionImpl::NetworkContextOwner {
mojo::Remote<network::mojom::NetworkContext> network_context;
};
StoragePartitionImpl::StoragePartitionImpl(
BrowserContext* browser_context,
const StoragePartitionConfig& config,
const base::FilePath& partition_path,
const base::FilePath& relative_partition_path,
storage::SpecialStoragePolicy* special_storage_policy)
: browser_context_(browser_context),
partition_path_(partition_path),
config_(config),
relative_partition_path_(relative_partition_path),
special_storage_policy_(special_storage_policy),
network_context_owner_(std::make_unique<NetworkContextOwner>()),
deletion_helpers_running_(0) {}
StoragePartitionImpl::~StoragePartitionImpl() {
#if DCHECK_IS_ON()
DCHECK(on_browser_context_will_be_destroyed_called_);
#endif
browser_context_ = nullptr;
if (GetFileSystemContext()) {
GetFileSystemContext()->Shutdown();
}
if (GetDOMStorageContext()) {
GetDOMStorageContext()->Shutdown();
}
if (GetServiceWorkerContext()) {
GetServiceWorkerContext()->Shutdown();
}
if (GetBackgroundSyncContext()) {
GetBackgroundSyncContext()->Shutdown();
}
if (GetBackgroundFetchContext()) {
GetBackgroundFetchContext()->Shutdown();
}
if (GetGeneratedCodeCacheContext()) {
GetGeneratedCodeCacheContext()->Shutdown();
}
}
void StoragePartitionImpl::OnBrowserContextWillBeDestroyed() {
#if DCHECK_IS_ON()
on_browser_context_will_be_destroyed_called_ = true;
#endif
// Shut down service worker and shared worker machinery because these can keep
// RenderProcessHosts and SiteInstances alive, and the codebase assumes these
// are destroyed before the BrowserContext is destroyed.
GetServiceWorkerContext()->Shutdown();
GetSharedWorkerService()->Shutdown();
// These hold raw pointers to objects that are about to be destroyed, before
// this object is destroyed. Shut them down now to avoid dangling pointers.
if (GetFileSystemAccessManager()) {
GetFileSystemAccessManager()->Shutdown();
}
if (GetContentIndexContext()) {
GetContentIndexContext()->Shutdown();
}
if (GetPlatformNotificationContext()) {
GetPlatformNotificationContext()->Shutdown();
}
if (keep_alive_url_loader_service_) {
keep_alive_url_loader_service_->Shutdown();
}
}
void StoragePartitionImpl::RegisterKeepAliveHandle(
mojo::PendingReceiver<blink::mojom::NavigationStateKeepAliveHandle>
receiver,
std::unique_ptr<NavigationStateKeepAlive> handle) {
navigation_state_keep_alive_map_.erase(handle->frame_token());
navigation_state_keep_alive_map_.insert(
std::make_pair(handle->frame_token(), handle.get()));
keep_alive_handles_receiver_set_.Add(std::move(handle), std::move(receiver));
}
void StoragePartitionImpl::RevokeNetworkForNoncesInNetworkContext(
const std::vector<base::UnguessableToken>& nonces,
network::mojom::NetworkContext::RevokeNetworkForNoncesCallback callback) {
GetNetworkContext()->RevokeNetworkForNonces(nonces, std::move(callback));
// Save nonces in `StoragePartitionImpl`. When there is a crash of
// `NetworkService`, the network revocation nonces of `NetworkContext` will be
// restored using this.
network_revocation_nonces_.insert(std::begin(nonces), std::end(nonces));
}
void StoragePartitionImpl::ClearNoncesInNetworkContextAfterDelay(
const std::vector<base::UnguessableToken>& nonces) {
GetUIThreadTaskRunner({})->PostDelayedTask(
FROM_HERE,
base::BindOnce(
&StoragePartitionImpl::ClearNoncesInNetworkContextAfterDelayCallback,
weak_factory_.GetWeakPtr(), nonces),
clear_nonces_in_network_context_delay_);
}
void StoragePartitionImpl::ClearNoncesInNetworkContextAfterDelayCallback(
const std::vector<base::UnguessableToken>& nonces) {
GetNetworkContext()->ClearNonces(nonces);
for (const auto& nonce : nonces) {
network_revocation_nonces_.erase(nonce);
}
clear_nonces_in_network_context_callback_for_testing_.Run();
}
void StoragePartitionImpl::RemoveKeepAliveHandleFromMap(
blink::LocalFrameToken frame_token,
NavigationStateKeepAlive* keep_alive) {
// The NavigationStateKeepAlive associated with `frame_token` may have
// changed. Make sure the specified one is removed from the map.
auto it = navigation_state_keep_alive_map_.find(frame_token);
if (it != navigation_state_keep_alive_map_.end() &&
it->second == keep_alive) {
navigation_state_keep_alive_map_.erase(frame_token);
}
}
NavigationStateKeepAlive* StoragePartitionImpl::GetNavigationStateKeepAlive(
blink::LocalFrameToken frame_token) {
auto it = navigation_state_keep_alive_map_.find(frame_token);
if (it == navigation_state_keep_alive_map_.end()) {
return nullptr;
}
return it->second;
}
// static
std::unique_ptr<StoragePartitionImpl> StoragePartitionImpl::Create(
BrowserContext* context,
const StoragePartitionConfig& config,
const base::FilePath& relative_partition_path) {
// Ensure that these methods are called on the UI thread, except for
// unittests where a UI thread might not have been created.
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI) ||
!BrowserThread::IsThreadInitialized(BrowserThread::UI));
base::FilePath partition_path =
context->GetPath().Append(relative_partition_path);
return base::WrapUnique(new StoragePartitionImpl(
context, config, partition_path, relative_partition_path,
context->GetSpecialStoragePolicy()));
}
void StoragePartitionImpl::Initialize(
StoragePartitionImpl* fallback_for_blob_urls) {
// Ensure that these methods are called on the UI thread, except for
// unittests where a UI thread might not have been created.
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI) ||
!BrowserThread::IsThreadInitialized(BrowserThread::UI));
DCHECK(!initialized_);
initialized_ = true;
// All of the clients have to be created and registered with the
// QuotaManager prior to the QuotaManager being used. We do them
// all together here prior to handing out a reference to anything
// that utilizes the QuotaManager.
quota_context_ = base::MakeRefCounted<QuotaContext>(
is_in_memory(), partition_path_,
browser_context_->GetSpecialStoragePolicy(),
base::BindRepeating(&StoragePartitionImpl::GetQuotaSettings,
weak_factory_.GetWeakPtr()));
quota_manager_ = quota_context_->quota_manager();
scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy =
quota_manager_->proxy();
StorageNotificationService* storage_notification_service =
browser_context_->GetStorageNotificationService();
if (storage_notification_service) {
// The weak ptr associated with the pressure notification callback will be
// created and evaluated by a task runner on the UI thread, as confirmed by
// the DCHECK's above, ensuring that the task runner does not attempt to run
// the callback in the case that the storage notification service is already
// destructed.
quota_manager_->SetStoragePressureCallback(
storage_notification_service
->CreateThreadSafePressureNotificationCallback());
}
// Each consumer is responsible for registering its QuotaClient during
// its construction.
filesystem_context_ = CreateFileSystemContext(
browser_context_, partition_path_, is_in_memory(), quota_manager_proxy);
dom_storage_context_ = DOMStorageContextWrapper::Create(
this, browser_context_->GetSpecialStoragePolicy());
lock_manager_ = std::make_unique<LockManager<storage::BucketId>>();
shared_storage_runtime_manager_ =
std::make_unique<SharedStorageRuntimeManager>(*this);
scoped_refptr<ChromeBlobStorageContext> blob_context =
ChromeBlobStorageContext::GetFor(browser_context_);
file_system_access_manager_ =
base::MakeRefCounted<FileSystemAccessManagerImpl>(
filesystem_context_, blob_context,
browser_context_->GetFileSystemAccessPermissionContext(),
browser_context_->IsOffTheRecord());
mojo::PendingRemote<storage::mojom::FileSystemAccessContext>
file_system_access_context;
file_system_access_manager_->BindInternalsReceiver(
file_system_access_context.InitWithNewPipeAndPassReceiver());
base::FilePath path = is_in_memory() ? base::FilePath() : partition_path_;
indexed_db_control_wrapper_ =
std::make_unique<indexed_db::IndexedDBControlWrapper>(
path, browser_context_->GetSpecialStoragePolicy(),
quota_manager_proxy,
ChromeBlobStorageContext::GetRemoteFor(browser_context_),
std::move(file_system_access_context), GetIOThreadTaskRunner({}));
cache_storage_control_wrapper_ = std::make_unique<CacheStorageControlWrapper>(
GetIOThreadTaskRunner({}), path,
browser_context_->GetSpecialStoragePolicy(), quota_manager_proxy,
ChromeBlobStorageContext::GetRemoteFor(browser_context_));
service_worker_context_ = new ServiceWorkerContextWrapper(browser_context_);
service_worker_context_->set_storage_partition(this);
dedicated_worker_service_ = std::make_unique<DedicatedWorkerServiceImpl>();
shared_worker_service_ =
std::make_unique<SharedWorkerServiceImpl>(this, service_worker_context_);
push_messaging_context_ = std::make_unique<PushMessagingContext>(
browser_context_, service_worker_context_);
host_zoom_level_context_.reset(new HostZoomLevelContext(
browser_context_->CreateZoomLevelDelegate(partition_path_)));
platform_notification_context_ = new PlatformNotificationContextImpl(
path, browser_context_, service_worker_context_);
platform_notification_context_->Initialize();
devtools_background_services_context_ =
std::make_unique<DevToolsBackgroundServicesContextImpl>(
browser_context_, service_worker_context_);
content_index_context_ = base::MakeRefCounted<ContentIndexContextImpl>(
browser_context_, service_worker_context_);
background_fetch_context_ = base::MakeRefCounted<BackgroundFetchContext>(
weak_factory_.GetWeakPtr(), service_worker_context_, quota_manager_proxy,
*devtools_background_services_context_.get());
background_sync_context_ = base::MakeRefCounted<BackgroundSyncContextImpl>();
background_sync_context_->Init(service_worker_context_,
*devtools_background_services_context_.get());
payment_app_context_ = new PaymentAppContextImpl();
payment_app_context_->Init(service_worker_context_);
broadcast_channel_service_ = std::make_unique<BroadcastChannelService>();
bluetooth_allowed_devices_map_ =
std::make_unique<BluetoothAllowedDevicesMap>();
// Must be initialized before the
// `shared_url_loader_factory_for_browser_process_`. Cookie deprecation
// traffic labels should not be sent for off-the-record profiles, unless the
// "enable_otr_profiles" feature parameter is true.
if (base::FeatureList::IsEnabled(
features::kCookieDeprecationFacilitatedTesting) &&
(!is_in_memory() ||
features::kCookieDeprecationFacilitatedTestingEnableOTRProfiles.Get())) {
cookie_deprecation_label_manager_ =
std::make_unique<CookieDeprecationLabelManagerImpl>(browser_context_);
}
shared_url_loader_factory_for_browser_process_ = std::make_unique<
ReconnectableURLLoaderFactoryForIOThreadWrapper>(base::BindRepeating(
&StoragePartitionImpl::CreateURLLoaderFactoryForBrowserProcessInternal,
GetWeakPtr()));
shared_url_loader_factory_for_browser_process_->factory_for_io_thread()
->Initialize();
service_worker_context_->Init(path, quota_manager_proxy.get(),
browser_context_->GetSpecialStoragePolicy(),
blob_context.get());
blob_url_registry_ = std::make_unique<storage::BlobUrlRegistry>(
fallback_for_blob_urls
? fallback_for_blob_urls->GetBlobUrlRegistry()->AsWeakPtr()
: nullptr);
blob_registry_ = BlobRegistryWrapper::Create(blob_context);
subresource_proxying_url_loader_service_ =
std::make_unique<SubresourceProxyingURLLoaderService>(browser_context_);
if (blink::features::IsKeepAliveURLLoaderServiceEnabled()) {
keep_alive_url_loader_service_ =
std::make_unique<KeepAliveURLLoaderService>(browser_context_);
}
cookie_store_manager_ =
std::make_unique<CookieStoreManager>(service_worker_context_);
// Unit tests use the LoadAllSubscriptions() callback to crash early if
// restoring the CookieManagerStore's state from ServiceWorkerStorage fails.
// Production and browser tests rely on CookieStoreManager's well-defined
// behavior when restoring the state fails.
cookie_store_manager_->LoadAllSubscriptions(base::DoNothing());
bucket_manager_ = std::make_unique<BucketManager>(this);
if (base::FeatureList::IsEnabled(
attribution_reporting::features::kConversionMeasurement)) {
// The Conversion Measurement API is not available in Incognito mode, but
// this is enforced by the `AttributionManagerImpl` itself for better error
// reporting and metrics.
attribution_manager_ = std::make_unique<AttributionManagerImpl>(
this, path, special_storage_policy_);
}
if (base::FeatureList::IsEnabled(network::features::kInterestGroupStorage)) {
// Auction worklets on non-Android use dedicated processes; on Android due
// to high cost of process launch they try to reuse renderers.
interest_group_manager_ = std::make_unique<InterestGroupManagerImpl>(
path, is_in_memory(),
#if BUILDFLAG(IS_ANDROID)
InterestGroupManagerImpl::ProcessMode::kInRenderer,
#else
InterestGroupManagerImpl::ProcessMode::kDedicated,
#endif
GetURLLoaderFactoryForBrowserProcess(),
base::BindRepeating(&BrowserContext::GetKAnonymityServiceDelegate,
// This use of Unretained is safe since the browser
// context owns this storage partition.
base::Unretained(browser_context_)));
}
// The Topics API is not available in Incognito mode.
if (!is_in_memory() &&
base::FeatureList::IsEnabled(network::features::kBrowsingTopics)) {
browsing_topics_site_data_manager_ =
std::make_unique<BrowsingTopicsSiteDataManagerImpl>(path);
}
GeneratedCodeCacheSettings settings =
GetContentClient()->browser()->GetGeneratedCodeCacheSettings(
browser_context_);
// For Incognito mode, we should not persist anything on the disk so
// we do not create a code cache. Caching the generated code in memory
// is not useful, since V8 already maintains one copy in memory.
if (!is_in_memory() && settings.enabled()) {
generated_code_cache_context_ =
base::MakeRefCounted<GeneratedCodeCacheContext>();
base::FilePath code_cache_path;
if (config_.partition_domain().empty()) {
code_cache_path = settings.path().AppendASCII("Code Cache");
} else {
// For site isolated partitions use the config directory.
code_cache_path = settings.path()
.Append(relative_partition_path_)
.AppendASCII("Code Cache");
}
DCHECK_GE(settings.size_in_bytes(), 0);
GetGeneratedCodeCacheContext()->Initialize(code_cache_path,
settings.size_in_bytes());
}
font_access_manager_ = FontAccessManager::Create();
aggregation_service_ =
std::make_unique<AggregationServiceImpl>(is_in_memory(), path, this);
#if BUILDFLAG(ENABLE_LIBRARY_CDMS)
if (is_in_memory()) {
// Pass an empty path if in_memory so that CdmStorage.db is not stored on
// disk.
cdm_storage_manager_ =
std::make_unique<CdmStorageManager>(base::FilePath());
} else {
cdm_storage_manager_ = std::make_unique<CdmStorageManager>(
partition_path_.Append(kCdmStorageDatabaseFileName));
}
#endif // BUILDFLAG(ENABLE_LIBRARY_CDMS)
if (base::FeatureList::IsEnabled(network::features::kSharedStorageAPI)) {
base::FilePath shared_storage_path =
is_in_memory() ? base::FilePath()
: path.Append(storage::kSharedStoragePath);
shared_storage_manager_ = std::make_unique<storage::SharedStorageManager>(
shared_storage_path, special_storage_policy_);
shared_storage_header_observer_ =
std::make_unique<SharedStorageHeaderObserver>(this);
}
if (base::FeatureList::IsEnabled(blink::features::kPrivateAggregationApi)) {
private_aggregation_manager_ =
std::make_unique<PrivateAggregationManagerImpl>(is_in_memory(), path,
this);
}
}
void StoragePartitionImpl::OnStorageServiceDisconnected() {
// This will be lazily re-bound on next use.
remote_partition_.reset();
dom_storage_context_->RecoverFromStorageServiceCrash();
for (const auto& client : dom_storage_clients_) {
client.second->ResetStorageAreaAndNamespaceConnections();
}
}
const StoragePartitionConfig& StoragePartitionImpl::GetConfig() const {
return config_;
}
const base::FilePath& StoragePartitionImpl::GetPath() const {
return partition_path_;
}
const std::string& StoragePartitionImpl::GetPartitionDomain() const {
return config_.partition_domain();
}
network::mojom::NetworkContext* StoragePartitionImpl::GetNetworkContext() {
DCHECK(initialized_);
if (!network_context_owner_->network_context.is_bound()) {
InitNetworkContext();
}
return network_context_owner_->network_context.get();
}
cert_verifier::mojom::CertVerifierServiceUpdater*
StoragePartitionImpl::GetCertVerifierServiceUpdater() {
DCHECK(initialized_);
if (!cert_verifier_service_updater_.is_bound()) {
InitNetworkContext();
}
return cert_verifier_service_updater_.get();
}
scoped_refptr<network::SharedURLLoaderFactory>
StoragePartitionImpl::GetURLLoaderFactoryForBrowserProcess() {
CHECK(shared_url_loader_factory_for_browser_process_);
return shared_url_loader_factory_for_browser_process_->factory();
}
std::unique_ptr<network::PendingSharedURLLoaderFactory>
StoragePartitionImpl::GetURLLoaderFactoryForBrowserProcessIOThread() {
CHECK(shared_url_loader_factory_for_browser_process_);
return shared_url_loader_factory_for_browser_process_->factory_for_io_thread()
->CloneForIOThread();
}
network::mojom::CookieManager*
StoragePartitionImpl::GetCookieManagerForBrowserProcess() {
DCHECK(initialized_);
// Create the CookieManager as needed.
if (!cookie_manager_for_browser_process_ ||
!cookie_manager_for_browser_process_.is_connected()) {
// Reset `cookie_manager_for_browser_process_` before binding it again.
cookie_manager_for_browser_process_.reset();
GetNetworkContext()->GetCookieManager(
cookie_manager_for_browser_process_.BindNewPipeAndPassReceiver());
}
return cookie_manager_for_browser_process_.get();
}
void StoragePartitionImpl::CreateRestrictedCookieManager(
network::mojom::RestrictedCookieManagerRole role,
const url::Origin& origin,
const net::IsolationInfo& isolation_info,
bool is_service_worker,
int process_id,
int routing_id,
net::CookieSettingOverrides cookie_setting_overrides,
net::CookieSettingOverrides devtools_cookie_setting_overrides,
mojo::PendingReceiver<network::mojom::RestrictedCookieManager> receiver,
mojo::PendingRemote<network::mojom::CookieAccessObserver> cookie_observer) {
DCHECK(initialized_);
if (!GetContentClient()->browser()->WillCreateRestrictedCookieManager(
role, browser_context_, origin, isolation_info, is_service_worker,
process_id, routing_id, &receiver)) {
GetNetworkContext()->GetRestrictedCookieManager(
std::move(receiver), role, origin, isolation_info,
cookie_setting_overrides, devtools_cookie_setting_overrides,
std::move(cookie_observer));
}
}
void StoragePartitionImpl::CreateTrustTokenQueryAnswerer(
mojo::PendingReceiver<network::mojom::TrustTokenQueryAnswerer> receiver,
const url::Origin& top_frame_origin) {
DCHECK(initialized_);
GetNetworkContext()->GetTrustTokenQueryAnswerer(std::move(receiver),
top_frame_origin);
}
storage::QuotaManager* StoragePartitionImpl::GetQuotaManager() {
DCHECK(initialized_);
return quota_manager_.get();
}
storage::QuotaManagerProxy* StoragePartitionImpl::GetQuotaManagerProxy() {
DCHECK(initialized_);
return quota_manager_->proxy();
}
BackgroundSyncContextImpl* StoragePartitionImpl::GetBackgroundSyncContext() {
DCHECK(initialized_);
return background_sync_context_.get();
}
storage::FileSystemContext* StoragePartitionImpl::GetFileSystemContext() {
DCHECK(initialized_);
return filesystem_context_.get();
}
DOMStorageContextWrapper* StoragePartitionImpl::GetDOMStorageContext() {
DCHECK(initialized_);
return dom_storage_context_.get();
}
storage::mojom::LocalStorageControl*
StoragePartitionImpl::GetLocalStorageControl() {
DCHECK(initialized_);
return GetDOMStorageContext()->GetLocalStorageControl();
}
LockManager<storage::BucketId>* StoragePartitionImpl::GetLockManager() {
DCHECK(initialized_);
return lock_manager_.get();
}
SharedStorageRuntimeManager*
StoragePartitionImpl::GetSharedStorageRuntimeManager() {
DCHECK(initialized_);
return shared_storage_runtime_manager_.get();
}
storage::mojom::IndexedDBControl& StoragePartitionImpl::GetIndexedDBControl() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
return indexed_db_control_wrapper_->GetIndexedDBControl();
}
FileSystemAccessEntryFactory*
StoragePartitionImpl::GetFileSystemAccessEntryFactory() {
DCHECK(initialized_);
return file_system_access_manager_.get();
}
QuotaContext* StoragePartitionImpl::GetQuotaContext() {
DCHECK(initialized_);
return quota_context_.get();
}
storage::mojom::CacheStorageControl*
StoragePartitionImpl::GetCacheStorageControl() {
DCHECK(initialized_);
return cache_storage_control_wrapper_.get();
}
ServiceWorkerContextWrapper* StoragePartitionImpl::GetServiceWorkerContext() {
DCHECK(initialized_);
return service_worker_context_.get();
}
DedicatedWorkerServiceImpl* StoragePartitionImpl::GetDedicatedWorkerService() {
DCHECK(initialized_);
return dedicated_worker_service_.get();
}
SharedWorkerService* StoragePartitionImpl::GetSharedWorkerService() {
DCHECK(initialized_);
return shared_worker_service_.get();
}
HostZoomMap* StoragePartitionImpl::GetHostZoomMap() {
DCHECK(initialized_);
DCHECK(host_zoom_level_context_.get());
return host_zoom_level_context_->GetHostZoomMap();
}
HostZoomLevelContext* StoragePartitionImpl::GetHostZoomLevelContext() {
DCHECK(initialized_);
return host_zoom_level_context_.get();
}
ZoomLevelDelegate* StoragePartitionImpl::GetZoomLevelDelegate() {
DCHECK(initialized_);
DCHECK(host_zoom_level_context_.get());
return host_zoom_level_context_->GetZoomLevelDelegate();
}
PlatformNotificationContextImpl*
StoragePartitionImpl::GetPlatformNotificationContext() {
DCHECK(initialized_);
return platform_notification_context_.get();
}
BackgroundFetchContext* StoragePartitionImpl::GetBackgroundFetchContext() {
DCHECK(initialized_);
return background_fetch_context_.get();
}
PaymentAppContextImpl* StoragePartitionImpl::GetPaymentAppContext() {
DCHECK(initialized_);
return payment_app_context_.get();
}
BroadcastChannelService* StoragePartitionImpl::GetBroadcastChannelService() {
DCHECK(initialized_);
return broadcast_channel_service_.get();
}
BluetoothAllowedDevicesMap*
StoragePartitionImpl::GetBluetoothAllowedDevicesMap() {
DCHECK(initialized_);
return bluetooth_allowed_devices_map_.get();
}
BlobRegistryWrapper* StoragePartitionImpl::GetBlobRegistry() {
DCHECK(initialized_);
return blob_registry_.get();
}
storage::BlobUrlRegistry* StoragePartitionImpl::GetBlobUrlRegistry() {
DCHECK(initialized_);
return blob_url_registry_.get();
}
SubresourceProxyingURLLoaderService*
StoragePartitionImpl::GetSubresourceProxyingURLLoaderService() {
DCHECK(initialized_);
return subresource_proxying_url_loader_service_.get();
}
KeepAliveURLLoaderService*
StoragePartitionImpl::GetKeepAliveURLLoaderService() {
DCHECK(initialized_);
return keep_alive_url_loader_service_.get();
}
CookieStoreManager* StoragePartitionImpl::GetCookieStoreManager() {
DCHECK(initialized_);
return cookie_store_manager_.get();
}
BucketManager* StoragePartitionImpl::GetBucketManager() {
DCHECK(initialized_);
return bucket_manager_.get();
}
GeneratedCodeCacheContext*
StoragePartitionImpl::GetGeneratedCodeCacheContext() {
DCHECK(initialized_);
return generated_code_cache_context_.get();
}
DevToolsBackgroundServicesContext*
StoragePartitionImpl::GetDevToolsBackgroundServicesContext() {
DCHECK(initialized_);
return devtools_background_services_context_.get();
}
FileSystemAccessManagerImpl*
StoragePartitionImpl::GetFileSystemAccessManager() {
DCHECK(initialized_);
return file_system_access_manager_.get();
}
AttributionManager* StoragePartitionImpl::GetAttributionManager() {
DCHECK(initialized_);
return attribution_manager_.get();
}
AttributionDataModel* StoragePartitionImpl::GetAttributionDataModel() {
DCHECK(initialized_);
return attribution_manager_.get();
}
FontAccessManager* StoragePartitionImpl::GetFontAccessManager() {
DCHECK(initialized_);
return font_access_manager_.get();
}
void StoragePartitionImpl::SetFontAccessManagerForTesting(
std::unique_ptr<FontAccessManager> font_access_manager) {
DCHECK(initialized_);
DCHECK(font_access_manager);
font_access_manager_ = std::move(font_access_manager);
}
#if BUILDFLAG(ENABLE_LIBRARY_CDMS)
CdmStorageDataModel* StoragePartitionImpl::GetCdmStorageDataModel() {
DCHECK(initialized_);
return cdm_storage_manager_.get();
}
#endif // BUILDFLAG(ENABLE_LIBRARY_CDMS)
network::mojom::DeviceBoundSessionManager*
StoragePartitionImpl::GetDeviceBoundSessionManager() {
DCHECK(initialized_);
#if BUILDFLAG(ENABLE_DEVICE_BOUND_SESSIONS)
if (!device_bound_session_manager_ ||
!device_bound_session_manager_.is_connected()) {
// Reset `device_bound_session_manager_` before binding it again.
device_bound_session_manager_.reset();
GetNetworkContext()->GetDeviceBoundSessionManager(
device_bound_session_manager_.BindNewPipeAndPassReceiver());
}
return device_bound_session_manager_.get();
#else
return nullptr;
#endif // BUILDFLAG(ENABLE_DEVICE_BOUND_SESSIONS)
}
InterestGroupManager* StoragePartitionImpl::GetInterestGroupManager() {
DCHECK(initialized_);
return interest_group_manager_.get();
}
BrowsingTopicsSiteDataManager*
StoragePartitionImpl::GetBrowsingTopicsSiteDataManager() {
DCHECK(initialized_);
return browsing_topics_site_data_manager_.get();
}
ContentIndexContextImpl* StoragePartitionImpl::GetContentIndexContext() {
DCHECK(initialized_);
return content_index_context_.get();
}
AggregationService* StoragePartitionImpl::GetAggregationService() {
DCHECK(initialized_);
return aggregation_service_.get();
}
leveldb_proto::ProtoDatabaseProvider*
StoragePartitionImpl::GetProtoDatabaseProvider() {
if (!proto_database_provider_) {
proto_database_provider_ =
std::make_unique<leveldb_proto::ProtoDatabaseProvider>(partition_path_,
is_in_memory());
}
return proto_database_provider_.get();
}
void StoragePartitionImpl::SetProtoDatabaseProvider(
std::unique_ptr<leveldb_proto::ProtoDatabaseProvider> proto_db_provider) {
DCHECK(!proto_database_provider_);
proto_database_provider_ = std::move(proto_db_provider);
}
leveldb_proto::ProtoDatabaseProvider*
StoragePartitionImpl::GetProtoDatabaseProviderForTesting() {
return proto_database_provider_.get();
}
storage::SharedStorageManager* StoragePartitionImpl::GetSharedStorageManager() {
return shared_storage_manager_.get();
}
PrivateAggregationManager*
StoragePartitionImpl::GetPrivateAggregationManager() {
DCHECK(initialized_);
return private_aggregation_manager_.get();
}
PrivateAggregationDataModel*
StoragePartitionImpl::GetPrivateAggregationDataModel() {
DCHECK(initialized_);
return private_aggregation_manager_.get();
}
CookieDeprecationLabelManager*
StoragePartitionImpl::GetCookieDeprecationLabelManager() {
CHECK(initialized_);
return cookie_deprecation_label_manager_.get();
}
void StoragePartitionImpl::DeleteStaleSessionData() {
GetDOMStorageContext()->StartScavengingUnusedSessionStorage();
// We need to delay deleting stale session cookies until after the cookie db
// has initialized, otherwise we will bypass lazy loading and block.
// See crbug.com/40285083 for more info.
CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
GetUIThreadTaskRunner({})->PostDelayedTask(
FROM_HERE,
base::BindOnce(
&StoragePartitionImpl::DeleteStaleSessionOnlyCookiesAfterDelay,
weak_factory_.GetWeakPtr()),
delete_stale_session_only_cookies_delay_);
}
void StoragePartitionImpl::DeleteStaleSessionOnlyCookiesAfterDelay() {
GetCookieManagerForBrowserProcess()->DeleteStaleSessionOnlyCookies(
base::BindOnce([](const uint32_t num_deleted) {
base::UmaHistogramCounts10M(
"Cookie.StaleSessionCookiesDeletedOnStartup", num_deleted);
}));
}
void StoragePartitionImpl::OpenLocalStorage(
const blink::StorageKey& storage_key,
const blink::LocalFrameToken& local_frame_token,
mojo::PendingReceiver<blink::mojom::StorageArea> receiver) {
DCHECK(initialized_);
ChildProcessSecurityPolicyImpl::Handle security_policy_handle =
dom_storage_receivers_.current_context()->Duplicate();
dom_storage_context_->OpenLocalStorage(
storage_key, local_frame_token, std::move(receiver),
std::move(security_policy_handle),
dom_storage_receivers_.GetBadMessageCallback());
}
void StoragePartitionImpl::BindSessionStorageNamespace(
const std::string& namespace_id,
mojo::PendingReceiver<blink::mojom::SessionStorageNamespace> receiver) {
DCHECK(initialized_);
dom_storage_context_->BindNamespace(
namespace_id, dom_storage_receivers_.GetBadMessageCallback(),
std::move(receiver));
}
void StoragePartitionImpl::BindSessionStorageArea(
const blink::StorageKey& storage_key,
const blink::LocalFrameToken& local_frame_token,
const std::string& namespace_id,
mojo::PendingReceiver<blink::mojom::StorageArea> receiver) {
DCHECK(initialized_);
ChildProcessSecurityPolicyImpl::Handle security_policy_handle =
dom_storage_receivers_.current_context()->Duplicate();
dom_storage_context_->BindStorageArea(
storage_key, local_frame_token, namespace_id, std::move(receiver),
std::move(security_policy_handle),
dom_storage_receivers_.GetBadMessageCallback());
}
void StoragePartitionImpl::OnAuthRequired(
const std::optional<base::UnguessableToken>& window_id,
int32_t request_id,
const GURL& url,
bool first_auth_attempt,
const net::AuthChallengeInfo& auth_info,
const scoped_refptr<net::HttpResponseHeaders>& head_headers,
mojo::PendingRemote<network::mojom::AuthChallengeResponder>
auth_challenge_responder) {
URLLoaderNetworkContext context =
url_loader_network_observers_.current_context();
std::optional<bool> is_primary_main_frame_navigation;
std::optional<bool> is_navigation_request;
if (window_id) {
// Use `window_id` if it is provided, because this request was sent by a
// service worker; service workers use `window_id` to identify the frame
// that sends the request since a worker is shared among multiple frames.
// TODO(crbug.com/40194275): Add a DCHECK here that process_id and
// routing_id are invalid. It can't be added yet because somehow routing_id
// is valid here.
if (service_worker_context_->context()) {
auto* service_worker_client =
service_worker_context_->context()
->service_worker_client_owner()
.GetServiceWorkerClientByWindowId(*window_id);
if (service_worker_client) {
if (service_worker_client->GetRenderFrameHostId()) {
// Use ServiceWorkerClient's GlobalRenderFrameHostId when the
// navigation commit has already started.
GlobalRenderFrameHostId render_frame_host_id =
service_worker_client->GetRenderFrameHostId();
context = URLLoaderNetworkContext::CreateForRenderFrameHost(
render_frame_host_id);
// Only the request for a sub resource intercepted by a service worker
// reaches here.
is_primary_main_frame_navigation = false;
is_navigation_request = false;
} else if (NavigationRequest* ongoing_navigation =
service_worker_client
->GetOngoingNavigationRequestBeforeCommit(
base::PassKey<StoragePartitionImpl>())) {
// This auth request is for an ongoing navigation controlled
// by service worker. The navigation request can be nullptr if user
// has closed the WebContents.
// Overwrite the context; set `type` to kNavigationRequestContext.
// TODO(crbug.com/40784852): Optimize locating logic.
context =
URLLoaderNetworkContext::CreateForNavigation(*ongoing_navigation);
}
}
}
}
// If the request is for a prerendering page, prerendering should be cancelled
// because the embedder may show UI for auth requests, and it's unsuitable for
// a hidden page.
if (CancelIfPrerendering(context.navigation_or_document(),
PrerenderFinalStatus::kLoginAuthRequested)) {
return;
}
if (!is_primary_main_frame_navigation.has_value()) {
is_primary_main_frame_navigation = context.IsPrimaryMainFrameRequest();
}
if (!is_navigation_request.has_value()) {
is_navigation_request = context.IsNavigationRequestContext();
}
int process_id = network::mojom::kBrowserProcessId;
if (context.type() == ContextType::kRenderFrameHostContext) {
// Set `process_id` to `kInvalidProcessId` considering `render_frame_host`
// can be null when it's destroyed already. `process_id` is updated only if
// `render_frame_host` is not null. If `render_frame_host` is null,
// later logic will call OnAuthCredentials() with a nullopt that triggers
// CancelAuth().
process_id = network::mojom::kInvalidProcessId;
// `navigation_or_document_` can be null when `context` is created with
// an invalid RenderFrameHost after a page is destroyed.
// It is currently possible for the ServiceWorker case above to use
// kRenderFrameHostContext for the auth request, after the RenderFrameHost
// has been deleted. Treating this as an invalid process ID will cancel the
// auth, which is the same outcome as if the ServiceWorker's process were
// used.
// TODO(crbug.com/40224422): Update the ServiceWorker code to
// recognize when the RenderFrameHost goes away and not use
// CreateForRenderFrameHost above.
if (context.navigation_or_document()) {
auto* render_frame_host = context.navigation_or_document()->GetDocument();
if (render_frame_host) {
process_id = render_frame_host->GetGlobalId().child_id;
}
}
} else if (context.type() == ContextType::kServiceWorkerContext) {
process_id = context.process_id();
}
FrameTreeNodeId frame_tree_node_id;
if (auto* navigation_or_document = context.navigation_or_document()) {
if (auto* frame_tree_node = navigation_or_document->GetFrameTreeNode()) {
frame_tree_node_id = frame_tree_node->frame_tree_node_id();
}
}
WebContents* current_web_contents = context.GetWebContents();
if (current_web_contents) {
// Evict all the BFCache entries that
// 1): are stored in the same BrowserContext
// 2): were loaded with the "Cache-control: no-store" header
// 3): match the challenger information of the page that requires HTTP
// authentication.
for (WebContentsImpl* web_contents : WebContentsImpl::GetAllWebContents()) {
if (web_contents->GetBrowserContext()->UniqueId() ==
current_web_contents->GetBrowserContext()->UniqueId()) {
for (const std::unique_ptr<BackForwardCacheImpl::Entry>& entry :
web_contents->GetController().GetBackForwardCache().GetEntries()) {
RenderFrameHostImpl* rfh = entry->render_frame_host();
const GURL& last_committed_url = rfh->GetLastCommittedURL();
if (rfh->LoadedWithCacheControlNoStoreHeader() &&
auth_info.challenger ==
url::SchemeHostPort(last_committed_url.scheme(),
last_committed_url.host(),
last_committed_url.IntPort())) {
BackForwardCacheCanStoreDocumentResult flattened_reasons;
flattened_reasons.No(BackForwardCacheMetrics::NotRestoredReason::
kCacheControlNoStore);
flattened_reasons.No(
BackForwardCacheMetrics::NotRestoredReason::kHTTPAuthRequired);
rfh->EvictFromBackForwardCacheWithFlattenedReasons(
flattened_reasons);
}
}
}
}
}
new LoginHandlerDelegate(
std::move(auth_challenge_responder), current_web_contents,
browser_context_, auth_info, *is_primary_main_frame_navigation,
*is_navigation_request, process_id, request_id, url, head_headers,
first_auth_attempt, frame_tree_node_id); // deletes self
}
void StoragePartitionImpl::OnPrivateNetworkAccessPermissionRequired(
const GURL& url,
const net::IPAddress& ip_address,
const std::optional<std::string>& private_network_device_id,
const std::optional<std::string>& private_network_device_name,
OnPrivateNetworkAccessPermissionRequiredCallback callback) {
if (!base::FeatureList::IsEnabled(
network::features::kPrivateNetworkAccessPermissionPrompt)) {
std::move(callback).Run(false);
return;
}
if (url_loader_network_observers_.empty()) {
std::move(callback).Run(false);
return;
}
const URLLoaderNetworkContext& context =
url_loader_network_observers_.current_context();
if (context.type() != ContextType::kRenderFrameHostContext ||
!context.navigation_or_document()) {
std::move(callback).Run(false);
return;
}
RenderFrameHost* render_frame_host =
context.navigation_or_document()->GetDocument();
if (!render_frame_host) {
std::move(callback).Run(false);
return;
}
auto device = blink::mojom::PrivateNetworkDevice::New(
private_network_device_id, private_network_device_name, ip_address);
PrivateNetworkDeviceDelegate* delegate =
GetContentClient()->browser()->GetPrivateNetworkDeviceDelegate();
if (!delegate) {
std::move(callback).Run(false);
return;
}
delegate->RequestPermission(*render_frame_host, std::move(device),
std::move(callback));
}
void StoragePartitionImpl::OnLocalNetworkAccessPermissionRequired(
OnLocalNetworkAccessPermissionRequiredCallback callback) {
if (!base::FeatureList::IsEnabled(
network::features::kLocalNetworkAccessChecks) &&
!network::features::kLocalNetworkAccessChecksWarn.Get()) {
// If LNA checks are not enabled, just allow the request by default.
std::move(callback).Run(true);
return;
}
if (url_loader_network_observers_.empty()) {
std::move(callback).Run(false);
return;
}
const URLLoaderNetworkContext& context =
url_loader_network_observers_.current_context();
// Three different cases are handled here depending on the request context:
// 1. Document context (ContextType::kRenderFrameHostContext) covers fetch()
// and subresource requests. These should check for existing permission
// state, and if the state is ASK trigger the permission prompt. These
// should also handle being delegated into subframe documents.
// 2. Navigation context (ContextType::kNavigationRequestContext) covers
// subframe navigations. These should check for existing permission
// state, and if the state is ASK trigger the permission prompt. Nested
// subframes should be allowed iff permission policy delegated the
// permission into the embedding frame.
// 3. Worker context (ContextType::kServiceWorkerContext) covers requests
// from workers. These may not have an existing document around. These
// should check for the permission state, but NOT trigger the permission
// prompt.
// Currently requesting the Local Network Access permission is restricted to
// subresource requests and subframe navigation requests.
// TODO(crbug.com/404887285): Denying permission for a subframe navigation
// results in an error page with text that isn't quite true anymore: "The
// connection is blocked because it was initiated by a public page to connect
// to devices or servers on your private network. Reload this page to allow
// the connection." The last sentence should be removed.
// Handle document (Case 1) and navigation (Case 2) contexts.
if (context.navigation_or_document()) {
RenderFrameHost* rfh = nullptr;
if (context.navigation_or_document()->GetDocument()) {
// Get the document that is making the request.
rfh = context.navigation_or_document()->GetDocument();
} else if (context.navigation_or_document()->GetNavigationRequest()) {
// Get the document that is embedding the frame being navigated.
rfh = context.navigation_or_document()
->GetNavigationRequest()
->GetParentFrameOrOuterDocument();
}
if (!rfh) {
std::move(callback).Run(false);
return;
}
PermissionController* permission_controller =
browser_context_->GetPermissionController();
DCHECK(permission_controller);
auto status = permission_controller->GetPermissionStatusForCurrentDocument(
content::PermissionDescriptorUtil::
CreatePermissionDescriptorForPermissionType(
blink::PermissionType::LOCAL_NETWORK_ACCESS),
rfh);
if (status == blink::mojom::PermissionStatus::GRANTED) {
std::move(callback).Run(true);
return;
} else if (status == blink::mojom::PermissionStatus::DENIED) {
std::move(callback).Run(false);
return;
} else {
// PermissionStatus is ASK, so request the permission. Converts the result
// into a boolean to pass back to `callback`, capturing whether the
// permission is granted or not.
permission_controller->RequestPermissionFromCurrentDocument(
rfh,
PermissionRequestDescription(
content::PermissionDescriptorUtil::
CreatePermissionDescriptorForPermissionType(
blink::PermissionType::LOCAL_NETWORK_ACCESS)),
base::BindOnce(
[](OnLocalNetworkAccessPermissionRequiredCallback cb,
PermissionStatus status) {
std::move(cb).Run(status ==
blink::mojom::PermissionStatus::GRANTED);
},
std::move(callback)));
return;
}
} else if (context.type() == ContextType::kServiceWorkerContext) {
// TODO(crbug.com/404887282): Add support for gating requests from workers
// on whether the user previously granted the permission. This will require
// plumbing through the `window_id` for the fetch to identify the worker
// context and then using that to get the worker origin to use when calling
// PermissionController::GetPermissionStatusForWorker().
std::move(callback).Run(true);
return;
}
// Otherwise default to denying local network access.
std::move(callback).Run(false);
return;
}
void StoragePartitionImpl::OnCertificateRequested(
const std::optional<base::UnguessableToken>& window_id,
const scoped_refptr<net::SSLCertRequestInfo>& cert_info,
mojo::PendingRemote<network::mojom::ClientCertificateResponder>
cert_responder) {
URLLoaderNetworkContext context =
url_loader_network_observers_.current_context();
if (window_id) {
// Use `window_id` if it is provided, because this request was sent by a
// service worker; service workers use `window_id` to identify the frame
// that sends the request since a worker is shared among multiple frames.
// TODO(crbug.com/40194275): Add a DCHECK here that process_id and
// routing_id are invalid. It can't be added yet because somehow routing_id
// is valid here.
if (service_worker_context_->context()) {
auto* service_worker_client =
service_worker_context_->context()
->service_worker_client_owner()
.GetServiceWorkerClientByWindowId(*window_id);
if (service_worker_client) {
if (service_worker_client->GetRenderFrameHostId()) {
// Use ServiceWorkerClient's GlobalRenderFrameHostId when the
// navigation commit has already started.
GlobalRenderFrameHostId render_frame_host_id =
service_worker_client->GetRenderFrameHostId();
context = URLLoaderNetworkContext::CreateForRenderFrameHost(
render_frame_host_id);
} else if (NavigationRequest* ongoing_navigation =
service_worker_client
->GetOngoingNavigationRequestBeforeCommit(
base::PassKey<StoragePartitionImpl>())) {
// This certification request is for an ongoing navigation.
// Overwrite the context; set `type` to kNavigationRequestContext.
// TODO(crbug.com/40784852): Optimize locating logic.
context =
URLLoaderNetworkContext::CreateForNavigation(*ongoing_navigation);
} else {
// The navigation request was canceled since the WebContents was
// discarded, so it is meaningless to continue the certification
// request.
CallCancelRequest(std::move(cert_responder));
return;
}
}
}
}
// If the request is for a prerendering page, prerendering should be cancelled
// because the embedder may show a dialog and ask users to select client
// certificates, and it's unsuitable for a hidden page.
if (CancelIfPrerendering(context.navigation_or_document(),
PrerenderFinalStatus::kClientCertRequested)) {
CallCancelRequest(std::move(cert_responder));
return;
}
base::WeakPtr<WebContents> web_contents_weak;
int process_id = network::mojom::kInvalidProcessId;
if (context.type() == ContextType::kServiceWorkerContext) {
process_id = context.process_id();
} else {
WebContents* web_contents = context.GetWebContents();
// The WebContents is already invalid. Bail.
if (!web_contents) {
CallCancelRequest(std::move(cert_responder));
return;
}
CHECK_EQ(web_contents->GetBrowserContext(), browser_context_.get());
web_contents_weak = web_contents->GetWeakPtr();
if (context.navigation_or_document()) {
auto* render_frame_host = context.navigation_or_document()->GetDocument();
if (render_frame_host) {
process_id = render_frame_host->GetProcess()->GetDeprecatedID();
}
}
}
// SSLClientAuthDelegate handles its own lifetime.
new SSLClientAuthDelegate(std::move(cert_responder), browser_context(),
process_id, web_contents_weak, cert_info);
}
void StoragePartitionImpl::OnSSLCertificateError(
const GURL& url,
int net_error,
const net::SSLInfo& ssl_info,
bool fatal,
OnSSLCertificateErrorCallback response) {
URLLoaderNetworkContext context =
url_loader_network_observers_.current_context();
// Cancel this request and the prerendering if the request is for a
// prerendering page, because prerendering pages are invisible and browser
// cannot show errors on invisible pages.
if (CancelIfPrerendering(context.navigation_or_document(),
PrerenderFinalStatus::kSslCertificateError)) {
std::move(response).Run(net_error);
return;
}
SSLErrorDelegate* delegate =
new SSLErrorDelegate(std::move(response)); // deletes self
bool is_primary_main_frame_request = context.IsPrimaryMainFrameRequest();
SSLManager::OnSSLCertificateError(
delegate->GetWeakPtr(), is_primary_main_frame_request, url,
context.navigation_or_document(), net_error, ssl_info, fatal);
}
void StoragePartitionImpl::OnLoadingStateUpdate(
network::mojom::LoadInfoPtr info,
OnLoadingStateUpdateCallback callback) {
auto* web_contents =
url_loader_network_observers_.current_context().GetWebContents();
if (web_contents) {
static_cast<WebContentsImpl*>(web_contents)
->LoadStateChanged(std::move(info));
}
std::move(callback).Run();
}
void StoragePartitionImpl::OnDataUseUpdate(
int32_t network_traffic_annotation_id_hash,
int64_t recv_bytes,
int64_t sent_bytes) {
GlobalRenderFrameHostId render_frame_host_id =
GetRenderFrameHostIdFromNetworkContext();
GetContentClient()->browser()->OnNetworkServiceDataUseUpdate(
render_frame_host_id, network_traffic_annotation_id_hash, recv_bytes,
sent_bytes);
}
void StoragePartitionImpl::OnSharedStorageHeaderReceived(
const url::Origin& request_origin,
std::vector<network::mojom::SharedStorageModifierMethodWithOptionsPtr>
methods_with_options,
const std::optional<std::string>& with_lock,
OnSharedStorageHeaderReceivedCallback callback) {
if (!shared_storage_header_observer_) {
std::move(callback).Run();
return;
}
// Currently, shared-storage-writable headers aren't available for requests
// initiated by service workers, so `navigation_or_document` should be
// non-null.
//
// TODO(cammie): If we handle the service worker case by allowing service
// workers to initiate shared-storage-writable requests, the assumption that
// `navigation_or_document` must be non-null may become incorrect.
auto* navigation_or_document =
url_loader_network_observers_.current_context().navigation_or_document();
DCHECK(navigation_or_document);
shared_storage_header_observer_->HeaderReceived(
request_origin, url_loader_network_observers_.current_context().type(),
navigation_or_document, std::move(methods_with_options), with_lock,
std::move(callback), mojo::GetBadMessageCallback(), /*can_defer=*/true);
}
void StoragePartitionImpl::OnAdAuctionEventRecordHeaderReceived(
network::AdAuctionEventRecord event_record,
const std::optional<url::Origin>& top_frame_origin) {
DCHECK(browser_context());
interest_group_manager_->RecordViewClick(
*browser_context(),
url_loader_network_observers_.current_context().navigation_or_document(),
top_frame_origin, std::move(event_record));
}
void StoragePartitionImpl::Clone(
mojo::PendingReceiver<network::mojom::URLLoaderNetworkServiceObserver>
observer) {
url_loader_network_observers_.Add(
this, std::move(observer),
url_loader_network_observers_.current_context());
}
void StoragePartitionImpl::OnWebSocketConnectedToPrivateNetwork(
network::mojom::IPAddressSpace ip_address_space) {
RenderFrameHostImpl* render_frame_host_impl =
RenderFrameHostImpl::FromID(GetRenderFrameHostIdFromNetworkContext());
if (render_frame_host_impl &&
network::IsLessPublicAddressSpace(
ip_address_space, render_frame_host_impl->BuildClientSecurityState()
->ip_address_space)) {
GetContentClient()->browser()->LogWebFeatureForCurrentPage(
render_frame_host_impl,
blink::mojom::WebFeature::kPrivateNetworkAccessWebSocketConnected);
}
}
void StoragePartitionImpl::OnUrlLoaderConnectedToPrivateNetwork(
const GURL& request_url,
network::mojom::IPAddressSpace response_address_space,
network::mojom::IPAddressSpace client_address_space,
network::mojom::IPAddressSpace target_address_space) {
RenderFrameHostImpl* render_frame_host_impl =
RenderFrameHostImpl::FromID(GetRenderFrameHostIdFromNetworkContext());
if (!render_frame_host_impl) {
return;
}
// Log a UseCounter for potential PNA 2.0 breakage. We are interested in the
// case where post-PNA 2.0 this request would fail due to mixed content
// blocking:
// 1. The request was to a private or local address space,
// 2. The request was from non-secure context,
// 3. The request was to a URL that is not potentially trustworthy,
// 4. The request is to a less public address space than the client making the
// request, and
// 5. The request was _not_ a priori private. We a priori know a request is
// private (and thus can trigger permission prompts _before_ mixed content
// checks) if the target address space is specified, if the request is to a
// `.local` domain, or if the request is to a private IP address literal.
//
// (1) is checked by the caller in the network service. (2) is implied because
// if it was from a secure context then the request to a not potentially
// trustworthy URL would have been blocked as mixed content. (3-5) are checked
// below.
//
// This may be called multiple times over the lifetime of resource load (due
// to redirect hops), as we want to consider every redirect hop for this
// metric as breakage may occur at the initial request or at any hop in the
// redirect chain. This is logged as a UseCounter for the current page, which
// "deduplicates" these repeated calls.
if (!network::IsUrlPotentiallyTrustworthy(request_url) &&
network::IsLessPublicAddressSpace(response_address_space,
client_address_space) &&
// Not a priori known to be private.
target_address_space == network::mojom::IPAddressSpace::kUnknown &&
!request_url.HostIsIPAddress() && !request_url.DomainIs("local")) {
GetContentClient()->browser()->LogWebFeatureForCurrentPage(
render_frame_host_impl,
blink::mojom::WebFeature::
kPrivateNetworkAccessInsecureResourceNotKnownPrivate);
}
}
mojo::PendingRemote<network::mojom::URLLoaderNetworkServiceObserver>
StoragePartitionImpl::CreateURLLoaderNetworkObserverForFrame(int process_id,
int routing_id) {
mojo::PendingRemote<network::mojom::URLLoaderNetworkServiceObserver> remote;
url_loader_network_observers_.Add(
this, remote.InitWithNewPipeAndPassReceiver(),
URLLoaderNetworkContext::CreateForRenderFrameHost(
GlobalRenderFrameHostId(process_id, routing_id)));
return remote;
}
mojo::PendingRemote<network::mojom::URLLoaderNetworkServiceObserver>
StoragePartitionImpl::CreateURLLoaderNetworkObserverForNavigationRequest(
NavigationRequest& navigation_request) {
mojo::PendingRemote<network::mojom::URLLoaderNetworkServiceObserver> remote;
url_loader_network_observers_.Add(
this, remote.InitWithNewPipeAndPassReceiver(),
URLLoaderNetworkContext::CreateForNavigation(navigation_request));
return remote;
}
mojo::PendingRemote<network::mojom::URLLoaderNetworkServiceObserver>
StoragePartitionImpl::CreateAuthCertObserverForServiceWorker(int process_id) {
mojo::PendingRemote<network::mojom::URLLoaderNetworkServiceObserver> remote;
url_loader_network_observers_.Add(this,
remote.InitWithNewPipeAndPassReceiver(),
URLLoaderNetworkContext(process_id));
return remote;
}
void StoragePartitionImpl::OnFileUploadRequested(
int32_t process_id,
bool async,
const std::vector<base::FilePath>& file_paths,
const GURL& destination_url,
OnFileUploadRequestedCallback callback) {
NetworkContextOnFileUploadRequested(process_id, async, file_paths,
destination_url, std::move(callback));
}
void StoragePartitionImpl::OnCanSendReportingReports(
const std::vector<url::Origin>& origins,
OnCanSendReportingReportsCallback callback) {
DCHECK(initialized_);
PermissionController* permission_controller =
browser_context_->GetPermissionController();
DCHECK(permission_controller);
std::vector<url::Origin> origins_out;
for (auto& origin : origins) {
bool allowed = permission_controller
->GetPermissionResultForOriginWithoutContext(
content::PermissionDescriptorUtil::
CreatePermissionDescriptorForPermissionType(
blink::PermissionType::BACKGROUND_SYNC),
origin)
.status == blink::mojom::PermissionStatus::GRANTED;
if (allowed) {
origins_out.push_back(origin);
}
}
std::move(callback).Run(origins_out);
}
void StoragePartitionImpl::OnCanSendDomainReliabilityUpload(
const url::Origin& origin,
OnCanSendDomainReliabilityUploadCallback callback) {
DCHECK(initialized_);
PermissionController* permission_controller =
browser_context_->GetPermissionController();
std::move(callback).Run(
permission_controller
->GetPermissionResultForOriginWithoutContext(
content::PermissionDescriptorUtil::
CreatePermissionDescriptorForPermissionType(
blink::PermissionType::BACKGROUND_SYNC),
origin)
.status == blink::mojom::PermissionStatus::GRANTED);
}
void StoragePartitionImpl::OnClearSiteData(
const GURL& url,
const std::string& header_value,
int load_flags,
const std::optional<net::CookiePartitionKey>& cookie_partition_key,
bool partitioned_state_allowed_only,
OnClearSiteDataCallback callback) {
DCHECK(initialized_);
base::WeakPtr<WebContents> weak_web_contents;
WebContents* web_contents =
url_loader_network_observers_.current_context().GetWebContents();
if (web_contents) {
weak_web_contents = web_contents->GetWeakPtr();
}
std::optional<blink::StorageKey> storage_key = CalculateStorageKey(
url::Origin::Create(url),
cookie_partition_key.has_value()
? base::OptionalToPtr(cookie_partition_key.value().nonce())
: nullptr);
ClearSiteDataHandler::HandleHeader(
browser_context()->GetWeakPtr(), weak_web_contents, GetConfig(), url,
header_value, load_flags, cookie_partition_key, storage_key,
partitioned_state_allowed_only, std::move(callback));
}
#if BUILDFLAG(IS_ANDROID)
void StoragePartitionImpl::OnGenerateHttpNegotiateAuthToken(
const std::string& server_auth_token,
bool can_delegate,
const std::string& auth_negotiate_android_account_type,
const std::string& spn,
OnGenerateHttpNegotiateAuthTokenCallback callback) {
// The callback takes ownership of these unique_ptrs and destroys them when
// run.
auto prefs = std::make_unique<net::HttpAuthPreferences>();
prefs->set_auth_android_negotiate_account_type(
auth_negotiate_android_account_type);
auto auth_negotiate =
std::make_unique<net::android::HttpAuthNegotiateAndroid>(prefs.get());
net::android::HttpAuthNegotiateAndroid* auth_negotiate_raw =
auth_negotiate.get();
auth_negotiate->set_server_auth_token(server_auth_token);
auth_negotiate->set_can_delegate(can_delegate);
auto auth_token = std::make_unique<std::string>();
auth_negotiate_raw->GenerateAuthTokenAndroid(
nullptr, spn, std::string(), auth_token.get(),
base::BindOnce(&FinishGenerateNegotiateAuthToken,
std::move(auth_negotiate), std::move(auth_token),
std::move(prefs), std::move(callback)));
}
#endif
#if BUILDFLAG(IS_CT_SUPPORTED)
void StoragePartitionImpl::OnCanSendSCTAuditingReport(
OnCanSendSCTAuditingReportCallback callback) {
bool allowed =
GetContentClient()->browser()->CanSendSCTAuditingReport(browser_context_);
std::move(callback).Run(allowed);
}
void StoragePartitionImpl::OnNewSCTAuditingReportSent() {
GetContentClient()->browser()->OnNewSCTAuditingReportSent(browser_context_);
}
#endif
void StoragePartitionImpl::ClearDataImpl(
uint32_t remove_mask,
uint32_t quota_storage_remove_mask,
const blink::StorageKey& storage_key,
BrowsingDataFilterBuilder* filter_builder,
StorageKeyPolicyMatcherFunction storage_key_policy_matcher,
CookieDeletionFilterPtr cookie_deletion_filter,
bool perform_storage_cleanup,
const base::Time begin,
const base::Time end,
base::OnceClosure callback) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
bool storage_key_origin_empty = storage_key.origin().opaque();
DCHECK(storage_key_origin_empty || !filter_builder);
DCHECK(storage_key_origin_empty || storage_key_policy_matcher.is_null());
StorageKeyMatcherFunction storage_key_matcher =
filter_builder ? filter_builder->BuildStorageKeyFilter()
: StorageKeyMatcherFunction();
for (auto& observer : data_removal_observers_) {
auto filter = CreateGenericStorageKeyMatcher(
storage_key, storage_key_matcher, storage_key_policy_matcher,
special_storage_policy_);
observer.OnStorageKeyDataCleared(remove_mask, std::move(filter), begin,
end);
}
DataDeletionHelper* helper = new DataDeletionHelper(
remove_mask, quota_storage_remove_mask,
base::BindOnce(&StoragePartitionImpl::DeletionHelperDone,
weak_factory_.GetWeakPtr(), std::move(callback)));
// `helper` deletes itself when done in
// DataDeletionHelper::DecrementTaskCount().
deletion_helpers_running_++;
helper->ClearDataOnUIThread(
storage_key, filter_builder, std::move(storage_key_policy_matcher),
std::move(cookie_deletion_filter), GetPath(), dom_storage_context_.get(),
quota_manager_.get(), special_storage_policy_.get(),
filesystem_context_.get(), GetCookieManagerForBrowserProcess(),
interest_group_manager_.get(), attribution_manager_.get(),
aggregation_service_.get(), private_aggregation_manager_.get(),
shared_storage_manager_.get(),
#if BUILDFLAG(ENABLE_LIBRARY_CDMS)
cdm_storage_manager_.get(),
#endif // BUILDFLAG(ENABLE_LIBRARY_CDMS)
GetDeviceBoundSessionManager(), perform_storage_cleanup, begin, end);
}
void StoragePartitionImpl::DeletionHelperDone(base::OnceClosure callback) {
std::move(callback).Run();
deletion_helpers_running_--;
if (on_deletion_helpers_done_callback_ && deletion_helpers_running_ == 0) {
// Notify tests that storage partition is done with all deletion tasks.
std::move(on_deletion_helpers_done_callback_).Run();
}
}
void StoragePartitionImpl::QuotaManagedDataDeletionHelper::
IncrementTaskCountOnIO() {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
++task_count_;
}
void StoragePartitionImpl::QuotaManagedDataDeletionHelper::
DecrementTaskCountOnIO() {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
DCHECK_GT(task_count_, 0);
--task_count_;
if (task_count_) {
return;
}
std::move(callback_).Run();
delete this;
}
void StoragePartitionImpl::QuotaManagedDataDeletionHelper::ClearDataOnIOThread(
const scoped_refptr<storage::QuotaManager>& quota_manager,
const base::Time begin,
const base::Time end,
const scoped_refptr<storage::SpecialStoragePolicy>& special_storage_policy,
StoragePartition::StorageKeyPolicyMatcherFunction storage_key_matcher,
bool perform_storage_cleanup) {
IncrementTaskCountOnIO();
base::RepeatingClosure decrement_callback = base::BindRepeating(
&QuotaManagedDataDeletionHelper::DecrementTaskCountOnIO,
base::Unretained(this));
// Ask the QuotaManager for all buckets modified within the user-specified
// timeframe, and deal with the resulting set in ClearBucketsOnIOThread().
if (quota_storage_remove_mask_ & QUOTA_MANAGED_STORAGE_MASK_TEMPORARY) {
IncrementTaskCountOnIO();
quota_manager->GetBucketsModifiedBetween(
begin, end,
base::BindOnce(&QuotaManagedDataDeletionHelper::ClearBucketsOnIOThread,
base::Unretained(this), base::RetainedRef(quota_manager),
special_storage_policy, storage_key_matcher,
perform_storage_cleanup, decrement_callback));
}
DecrementTaskCountOnIO();
}
void StoragePartitionImpl::QuotaManagedDataDeletionHelper::
ClearBucketsOnIOThread(
storage::QuotaManager* quota_manager,
const scoped_refptr<storage::SpecialStoragePolicy>&
special_storage_policy,
StoragePartition::StorageKeyPolicyMatcherFunction storage_key_matcher,
bool perform_storage_cleanup,
base::OnceClosure callback,
const std::set<storage::BucketLocator>& buckets) {
// The QuotaManager manages all storage other than cookies, LocalStorage,
// and SessionStorage. This loop wipes out most HTML5 storage for the given
// storage keys.
DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (buckets.empty()) {
std::move(callback).Run();
return;
}
storage::QuotaClientTypes quota_client_types =
StoragePartitionImpl::GenerateQuotaClientTypes(remove_mask_);
// The logic below (via CheckQuotaManagedDataDeletionStatus) only
// invokes the callback when all processing is complete.
base::OnceClosure done_callback =
perform_storage_cleanup
? base::BindOnce(&PerformQuotaManagerStorageCleanup,
base::WrapRefCounted(quota_manager),
quota_client_types, std::move(callback))
: std::move(callback);
size_t* deletion_task_count = new size_t(0u);
(*deletion_task_count)++;
for (const auto& bucket : buckets) {
// TODO(mkwst): Clean this up, it's slow. http://crbug.com/130746
if (storage_key_.has_value() && bucket.storage_key != *storage_key_) {
continue;
}
if (storage_key_matcher &&
!storage_key_matcher.Run(bucket.storage_key,
special_storage_policy.get())) {
continue;
}
auto split_callback = base::SplitOnceCallback(std::move(done_callback));
done_callback = std::move(split_callback.first);
(*deletion_task_count)++;
quota_manager->DeleteBucketData(
bucket, quota_client_types,
base::BindOnce(&OnQuotaManagedBucketDeleted, bucket,
deletion_task_count, std::move(split_callback.second)));
}
(*deletion_task_count)--;
CheckQuotaManagedDataDeletionStatus(deletion_task_count,
std::move(done_callback));
}
base::OnceClosure
StoragePartitionImpl::DataDeletionHelper::CreateTaskCompletionClosure(
TracingDataType data_type) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
auto result = pending_tasks_.insert(data_type);
DCHECK(result.second) << "Task already started: "
<< static_cast<int>(data_type);
static int tracing_id = 0;
TRACE_EVENT_NESTABLE_ASYNC_BEGIN1(
"browsing_data", "StoragePartitionImpl",
TRACE_ID_WITH_SCOPE("StoragePartitionImpl", ++tracing_id), "data_type",
static_cast<int>(data_type));
return base::BindOnce(
&StoragePartitionImpl::DataDeletionHelper::OnTaskComplete,
base::Unretained(this), data_type, tracing_id);
}
void StoragePartitionImpl::DataDeletionHelper::OnTaskComplete(
TracingDataType data_type,
int tracing_id) {
if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
GetUIThreadTaskRunner({})->PostTask(
FROM_HERE,
base::BindOnce(&DataDeletionHelper::OnTaskComplete,
base::Unretained(this), data_type, tracing_id));
return;
}
size_t num_erased = pending_tasks_.erase(data_type);
DCHECK_EQ(num_erased, 1U) << static_cast<int>(data_type);
TRACE_EVENT_NESTABLE_ASYNC_END0(
"browsing_data", "StoragePartitionImpl",
TRACE_ID_WITH_SCOPE("StoragePartitionImpl", tracing_id));
if (pending_tasks_.empty()) {
std::move(callback_).Run();
delete this;
}
}
void StoragePartitionImpl::DataDeletionHelper::RecordUnfinishedSubTasks() {
DCHECK(!pending_tasks_.empty());
for (TracingDataType task : pending_tasks_) {
base::UmaHistogramEnumeration(
"History.ClearBrowsingData.Duration.SlowTasks180sStoragePartition",
task);
}
}
void StoragePartitionImpl::DataDeletionHelper::ClearDataOnUIThread(
const blink::StorageKey& storage_key,
BrowsingDataFilterBuilder* filter_builder,
StorageKeyPolicyMatcherFunction storage_key_policy_matcher,
CookieDeletionFilterPtr cookie_deletion_filter,
const base::FilePath& path,
DOMStorageContextWrapper* dom_storage_context,
storage::QuotaManager* quota_manager,
storage::SpecialStoragePolicy* special_storage_policy,
storage::FileSystemContext* filesystem_context,
network::mojom::CookieManager* cookie_manager,
InterestGroupManagerImpl* interest_group_manager,
AttributionManager* attribution_manager,
AggregationService* aggregation_service,
PrivateAggregationManagerImpl* private_aggregation_manager,
storage::SharedStorageManager* shared_storage_manager,
#if BUILDFLAG(ENABLE_LIBRARY_CDMS)
CdmStorageManager* cdm_storage_manager,
#endif // BUILDFLAG(ENABLE_LIBRARY_CDMS)
network::mojom::DeviceBoundSessionManager* device_bound_session_manager,
bool perform_storage_cleanup,
const base::Time begin,
const base::Time end) {
DCHECK_NE(remove_mask_, 0u);
DCHECK(callback_);
// Only one of `storage_key`'s origin and
// `filter_builder`/`storage_key_policy_matcher` can be set.
const bool storage_key_origin_empty = storage_key.origin().opaque();
DCHECK(storage_key_origin_empty || !filter_builder);
DCHECK(storage_key_origin_empty || storage_key_policy_matcher.is_null());
GetUIThreadTaskRunner({})->PostDelayedTask(
FROM_HERE,
base::BindOnce(
&StoragePartitionImpl::DataDeletionHelper::RecordUnfinishedSubTasks,
weak_factory_.GetWeakPtr()),
kSlowTaskTimeout);
base::ScopedClosureRunner synchronous_clear_operations(
CreateTaskCompletionClosure(TracingDataType::kSynchronous));
scoped_refptr<storage::SpecialStoragePolicy> storage_policy_ref =
base::WrapRefCounted(special_storage_policy);
StorageKeyMatcherFunction storage_key_matcher =
filter_builder ? filter_builder->BuildStorageKeyFilter()
: StorageKeyMatcherFunction();
// This is preferred for new storage APIs to reduce the complexity.
auto generic_filter = CreateGenericStorageKeyMatcher(
storage_key, storage_key_matcher, storage_key_policy_matcher,
storage_policy_ref);
auto combined_storage_key_matcher = CombineStorageKeyMatcherFunctions(
storage_key_matcher, storage_key_policy_matcher);
if (remove_mask_ & REMOVE_DATA_MASK_COOKIES) {
// The CookieDeletionFilter has a redundant time interval to `begin` and
// `end`. Ensure that the filter has no time interval specified to help
// callers detect when they are using the wrong interval values.
DCHECK(!cookie_deletion_filter->created_after_time.has_value());
DCHECK(!cookie_deletion_filter->created_before_time.has_value());
if (!begin.is_null()) {
cookie_deletion_filter->created_after_time = begin;
}
if (!end.is_null()) {
cookie_deletion_filter->created_before_time = end;
}
if (!storage_key_origin_empty) {
cookie_deletion_filter->cookie_partition_key_collection =
net::CookiePartitionKeyCollection(storage_key.ToCookiePartitionKey());
}
cookie_manager->DeleteCookies(
std::move(cookie_deletion_filter),
base::BindOnce(
&OnClearedCookies,
// Handle the cookie store being destroyed and the callback thus not
// being called.
mojo::WrapCallbackWithDefaultInvokeIfNotRun(
CreateTaskCompletionClosure(TracingDataType::kCookies))));
}
// It is not expected to only delete internal interest group data, or to
// request interest group removal to be extra-thorough w/o asking for
// interest group removal.
DCHECK(!(remove_mask_ & REMOVE_DATA_MASK_INTEREST_GROUPS_INTERNAL) ||
remove_mask_ & REMOVE_DATA_MASK_INTEREST_GROUPS);
DCHECK(!(remove_mask_ & REMOVE_DATA_MASK_INTEREST_GROUPS_USER_CLEAR) ||
remove_mask_ & REMOVE_DATA_MASK_INTEREST_GROUPS);
if (remove_mask_ & REMOVE_DATA_MASK_INTEREST_GROUPS) {
if (interest_group_manager) {
// The internal interest group data is not specific to a site so it only
// makes sense to delete it for all sites (i.e. when
// generic_filter.is_null()).
if ((remove_mask_ & REMOVE_DATA_MASK_INTEREST_GROUPS_INTERNAL) &&
generic_filter.is_null()) {
interest_group_manager->DeleteAllInterestGroupData(
mojo::WrapCallbackWithDefaultInvokeIfNotRun(
CreateTaskCompletionClosure(TracingDataType::kInterestGroups)));
} else {
interest_group_manager->DeleteInterestGroupData(
generic_filter,
remove_mask_ & REMOVE_DATA_MASK_INTEREST_GROUPS_USER_CLEAR,
mojo::WrapCallbackWithDefaultInvokeIfNotRun(
CreateTaskCompletionClosure(TracingDataType::kInterestGroups)));
}
}
}
if (remove_mask_ & REMOVE_DATA_MASK_INTEREST_GROUP_PERMISSIONS_CACHE) {
if (interest_group_manager) {
interest_group_manager->ClearPermissionsCache();
}
}
#if BUILDFLAG(ENABLE_LIBRARY_CDMS)
if ((remove_mask_ & REMOVE_DATA_MASK_MEDIA_LICENSES)) {
auto cdm_deletion_callback = base::BindOnce(
base::IgnoreArgs<bool>(mojo::WrapCallbackWithDefaultInvokeIfNotRun(
CreateTaskCompletionClosure(TracingDataType::kCdmStorage))));
cdm_storage_manager->DeleteData(generic_filter, storage_key, begin, end,
std::move(cdm_deletion_callback));
}
#endif // BUILDFLAG(ENABLE_LIBRARY_CDMS)
if (remove_mask_ & REMOVE_DATA_MASK_INDEXEDDB ||
remove_mask_ & REMOVE_DATA_MASK_WEBSQL ||
remove_mask_ & REMOVE_DATA_MASK_FILE_SYSTEMS ||
remove_mask_ & REMOVE_DATA_MASK_SERVICE_WORKERS ||
remove_mask_ & REMOVE_DATA_MASK_CACHE_STORAGE) {
GetIOThreadTaskRunner({})->PostTask(
FROM_HERE,
base::BindOnce(&DataDeletionHelper::ClearQuotaManagedDataOnIOThread,
base::Unretained(this),
base::WrapRefCounted(quota_manager), begin, end,
storage_key, storage_policy_ref,
combined_storage_key_matcher, perform_storage_cleanup,
CreateTaskCompletionClosure(TracingDataType::kQuota)));
}
if (remove_mask_ & REMOVE_DATA_MASK_LOCAL_STORAGE) {
ClearLocalStorageOnUIThread(
base::WrapRefCounted(dom_storage_context), storage_policy_ref,
combined_storage_key_matcher, storage_key, perform_storage_cleanup,
begin, end,
mojo::WrapCallbackWithDefaultInvokeIfNotRun(
CreateTaskCompletionClosure(TracingDataType::kLocalStorage)));
// ClearDataImpl cannot clear session storage data when a particular origin
// is specified. Therefore we ignore clearing session storage in this case.
// TODO(lazyboy): Fix.
if (storage_key_origin_empty) {
// TODO(crbug.com/41457196): Sometimes SessionStorage fails to call its
// callback. Figure out why.
ClearSessionStorageOnUIThread(
base::WrapRefCounted(dom_storage_context), storage_policy_ref,
combined_storage_key_matcher, perform_storage_cleanup,
mojo::WrapCallbackWithDefaultInvokeIfNotRun(
CreateTaskCompletionClosure(TracingDataType::kSessionStorage)));
}
}
if (remove_mask_ & REMOVE_DATA_MASK_SHADER_CACHE) {
gpu::GpuDiskCacheFactory* gpu_cache_factory =
GetGpuDiskCacheFactorySingleton();
// May be null in tests where it is difficult to plumb through a test
// storage partition.
if (!path.empty() && gpu_cache_factory) {
// Clear the path for all the different GPU cache sub-types.
base::RepeatingClosure barrier = base::BarrierClosure(
gpu::kGpuDiskCacheTypes.size(),
CreateTaskCompletionClosure(TracingDataType::kGpuCache));
for (gpu::GpuDiskCacheType type : gpu::kGpuDiskCacheTypes) {
gpu_cache_factory->ClearByPath(
path.Append(gpu::GetGpuDiskCacheSubdir(type)), begin, end,
base::BindOnce(&ClearedGpuCache, barrier));
}
}
}
// It is not expected to only delete internal attribution reporting data.
DCHECK(!(remove_mask_ & REMOVE_DATA_MASK_ATTRIBUTION_REPORTING_INTERNAL) ||
remove_mask_ & REMOVE_DATA_MASK_ATTRIBUTION_REPORTING_SITE_CREATED);
if (attribution_manager &&
(remove_mask_ & REMOVE_DATA_MASK_ATTRIBUTION_REPORTING_SITE_CREATED)) {
if (storage_key_origin_empty) {
attribution_manager->ClearData(
begin, end, generic_filter, filter_builder,
remove_mask_ & REMOVE_DATA_MASK_ATTRIBUTION_REPORTING_INTERNAL,
mojo::WrapCallbackWithDefaultInvokeIfNotRun(
CreateTaskCompletionClosure(TracingDataType::kConversions)));
} else if (storage_key.IsFirstPartyContext()) {
// Attribution Reporting API doesn't support cross-site data deletion.
std::unique_ptr<BrowsingDataFilterBuilder> effective_filter_builder =
BrowsingDataFilterBuilder::Create(
BrowsingDataFilterBuilder::Mode::kDelete);
effective_filter_builder->AddOrigin(storage_key.origin());
attribution_manager->ClearData(
begin, end, generic_filter, effective_filter_builder.get(),
remove_mask_ & REMOVE_DATA_MASK_ATTRIBUTION_REPORTING_INTERNAL,
mojo::WrapCallbackWithDefaultInvokeIfNotRun(
CreateTaskCompletionClosure(TracingDataType::kConversions)));
}
}
if (aggregation_service &&
(remove_mask_ & REMOVE_DATA_MASK_AGGREGATION_SERVICE)) {
// Currently the aggregation service only stores public keys and we don't
// have information on the page/context that uses the public key origin,
// therefore we don't check origins and instead just delete all rows in the
// given time range.
// TODO(crbug.com/40210305): Consider fine-grained deletion of public keys.
// TODO(crbug.com/40815455): Consider adding aggregation service origins to
// `CookiesTreeModel`.
aggregation_service->ClearData(
begin, end, generic_filter,
mojo::WrapCallbackWithDefaultInvokeIfNotRun(
CreateTaskCompletionClosure(TracingDataType::kAggregationService)));
}
if (private_aggregation_manager &&
(remove_mask_ & REMOVE_DATA_MASK_PRIVATE_AGGREGATION_INTERNAL)) {
private_aggregation_manager->ClearBudgetData(
begin, end, generic_filter,
// Wrapping the callback ensures that the callback is still run in the
// case that the storage partition is deleted before the task is posted.
mojo::WrapCallbackWithDefaultInvokeIfNotRun(
CreateTaskCompletionClosure(TracingDataType::kPrivateAggregation)));
}
if (base::FeatureList::IsEnabled(network::features::kSharedStorageAPI) &&
shared_storage_manager &&
(remove_mask_ & REMOVE_DATA_MASK_SHARED_STORAGE)) {
auto shared_storage_purge_callback = base::BindOnce(
[](base::WeakPtr<storage::SharedStorageManager> manager,
base::OnceClosure callback,
storage::SharedStorageDatabase::OperationResult result) {
if (manager) {
manager->OnOperationResult(result);
}
std::move(callback).Run();
},
shared_storage_manager->GetWeakPtr(),
CreateTaskCompletionClosure(TracingDataType::kSharedStorage));
shared_storage_manager->PurgeMatchingOrigins(
combined_storage_key_matcher, begin, end,
std::move(shared_storage_purge_callback), perform_storage_cleanup);
}
if (remove_mask_ & REMOVE_DATA_MASK_DEVICE_BOUND_SESSIONS &&
device_bound_session_manager) {
device_bound_session_manager->DeleteAllSessions(
begin, end,
filter_builder ? filter_builder->BuildNetworkServiceFilter() : nullptr,
mojo::WrapCallbackWithDefaultInvokeIfNotRun(CreateTaskCompletionClosure(
TracingDataType::kDeviceBoundSessions)));
}
}
void StoragePartitionImpl::ClearDataForOrigin(
uint32_t remove_mask,
uint32_t quota_storage_remove_mask,
const GURL& storage_origin,
base::OnceClosure callback) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK(initialized_);
CookieDeletionFilterPtr deletion_filter = CookieDeletionFilter::New();
if (!storage_origin.host().empty()) {
deletion_filter->host_name = storage_origin.host();
}
// Construct a |BrowsingDataFilterBuilder| instead of just passing a storage
// key based on the origin directly. This is needed to be able to delete the
// associated 3P data embedded on the origin.
auto filter_builder = BrowsingDataFilterBuilder::Create(
content::BrowsingDataFilterBuilder::Mode::kDelete);
filter_builder->AddOrigin(url::Origin::Create(storage_origin));
ClearDataImpl(remove_mask, quota_storage_remove_mask, blink::StorageKey(),
filter_builder.get(), StorageKeyPolicyMatcherFunction(),
std::move(deletion_filter), false, base::Time(),
base::Time::Max(), std::move(callback));
}
void StoragePartitionImpl::ClearDataForBuckets(
const blink::StorageKey& storage_key,
const std::set<std::string>& storage_buckets,
base::OnceClosure callback) {
DCHECK(initialized_);
const auto remove_buckets_done =
base::BarrierCallback<blink::mojom::QuotaStatusCode>(
storage_buckets.size(),
BindPostTaskToCurrentDefault(
base::BindOnce(&StoragePartitionImpl::ClearDataForBucketsDone,
base::Unretained(this), storage_key,
storage_buckets, std::move(callback))));
storage::QuotaManagerProxy* quota_manager_proxy = GetQuotaManagerProxy();
for (const auto& bucket : storage_buckets) {
quota_manager_proxy->DeleteBucket(
storage_key, bucket, base::SequencedTaskRunner::GetCurrentDefault(),
remove_buckets_done);
}
}
void StoragePartitionImpl::ClearDataForBucketsDone(
const blink::StorageKey& storage_key,
const std::set<std::string>& storage_buckets,
base::OnceClosure callback,
const std::vector<blink::mojom::QuotaStatusCode>& status_codes) {
auto bucket_iterator = storage_buckets.begin();
for (const auto status_code : status_codes) {
if (bucket_iterator == storage_buckets.end()) {
break;
}
const std::string bucket_name = *bucket_iterator;
if (status_code != blink::mojom::QuotaStatusCode::kOk) {
DLOG(ERROR) << "Couldn't remove bucket with name" << bucket_name
<< " with storage key " << storage_key.GetDebugString()
<< ". Status: " << static_cast<int>(status_code);
}
++bucket_iterator;
}
std::move(callback).Run();
}
void StoragePartitionImpl::ClearData(uint32_t remove_mask,
uint32_t quota_storage_remove_mask,
const blink::StorageKey& storage_key,
const base::Time begin,
const base::Time end,
base::OnceClosure callback) {
DCHECK(initialized_);
CookieDeletionFilterPtr deletion_filter = CookieDeletionFilter::New();
if (!storage_key.origin().host().empty()) {
deletion_filter->host_name = storage_key.origin().host();
}
bool perform_storage_cleanup =
begin.is_null() && end.is_max() && storage_key.origin().opaque();
ClearDataImpl(remove_mask, quota_storage_remove_mask, storage_key,
/*filter_builder=*/nullptr, StorageKeyPolicyMatcherFunction(),
std::move(deletion_filter), perform_storage_cleanup, begin, end,
std::move(callback));
}
void StoragePartitionImpl::ClearData(
uint32_t remove_mask,
uint32_t quota_storage_remove_mask,
BrowsingDataFilterBuilder* filter_builder,
StorageKeyPolicyMatcherFunction storage_key_policy_matcher,
network::mojom::CookieDeletionFilterPtr cookie_deletion_filter,
bool perform_storage_cleanup,
const base::Time begin,
const base::Time end,
base::OnceClosure callback) {
DCHECK(initialized_);
ClearDataImpl(remove_mask, quota_storage_remove_mask, blink::StorageKey(),
filter_builder, std::move(storage_key_policy_matcher),
std::move(cookie_deletion_filter), perform_storage_cleanup,
begin, end, std::move(callback));
}
void StoragePartitionImpl::ClearCodeCaches(
const base::Time begin,
const base::Time end,
const base::RepeatingCallback<bool(const GURL&)>& url_matcher,
base::OnceClosure callback) {
DCHECK(initialized_);
// StoragePartitionCodeCacheDataRemover deletes itself when it is done.
StoragePartitionCodeCacheDataRemover::Create(this, url_matcher, begin, end)
->Remove(std::move(callback));
}
void StoragePartitionImpl::Flush() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK(initialized_);
if (GetDOMStorageContext()) {
GetDOMStorageContext()->Flush();
}
}
void StoragePartitionImpl::ResetURLLoaderFactories() {
CHECK(initialized_);
GetNetworkContext()->ResetURLLoaderFactories();
shared_url_loader_factory_for_browser_process_->factory()->Reset();
shared_url_loader_factory_for_browser_process_->factory_for_io_thread()
->Reset();
}
void StoragePartitionImpl::ClearBluetoothAllowedDevicesMapForTesting() {
DCHECK(initialized_);
bluetooth_allowed_devices_map_->Clear();
}
void StoragePartitionImpl::AddObserver(DataRemovalObserver* observer) {
data_removal_observers_.AddObserver(observer);
}
void StoragePartitionImpl::RemoveObserver(DataRemovalObserver* observer) {
data_removal_observers_.RemoveObserver(observer);
}
void StoragePartitionImpl::FlushNetworkInterfaceForTesting() {
CHECK(initialized_);
DCHECK(network_context_owner_->network_context);
network_context_owner_->network_context.FlushForTesting(); // IN-TEST
shared_url_loader_factory_for_browser_process_->factory()
->FlushForTesting(); // IN-TEST
if (cookie_manager_for_browser_process_) {
cookie_manager_for_browser_process_.FlushForTesting(); // IN-TEST
}
}
void StoragePartitionImpl::FlushNetworkInterfaceOnIOThreadForTesting() {
CHECK(initialized_);
CHECK(shared_url_loader_factory_for_browser_process_);
shared_url_loader_factory_for_browser_process_->factory_for_io_thread()
->FlushForTesting(); // IN-TEST
}
void StoragePartitionImpl::FlushCertVerifierInterfaceForTesting() {
DCHECK(initialized_);
DCHECK(cert_verifier_service_updater_);
cert_verifier_service_updater_.FlushForTesting(); // IN-TEST
}
void StoragePartitionImpl::WaitForDeletionTasksForTesting() {
DCHECK(initialized_);
if (deletion_helpers_running_) {
base::RunLoop loop;
on_deletion_helpers_done_callback_ = loop.QuitClosure();
loop.Run();
}
}
void StoragePartitionImpl::WaitForCodeCacheShutdownForTesting() {
DCHECK(initialized_);
if (generated_code_cache_context_) {
// If this is still running its initialization task it may check
// enabled features on a sequenced worker pool which could race
// between ScopedFeatureList destruction.
base::RunLoop loop;
GeneratedCodeCacheContext::RunOrPostTask(
generated_code_cache_context_, FROM_HERE,
base::BindOnce(
[](scoped_refptr<GeneratedCodeCacheContext> context,
base::OnceClosure quit) {
context->generated_js_code_cache()->GetBackend(base::BindOnce(
[](base::OnceClosure quit, disk_cache::Backend*) {
std::move(quit).Run();
},
std::move(quit)));
},
generated_code_cache_context_, loop.QuitClosure()));
loop.Run();
generated_code_cache_context_->Shutdown();
}
}
void StoragePartitionImpl::SetNetworkContextForTesting(
mojo::PendingRemote<network::mojom::NetworkContext>
network_context_remote) {
network_context_owner_->network_context.reset();
network_context_owner_->network_context.Bind(
std::move(network_context_remote));
}
void StoragePartitionImpl::OverrideDeleteStaleSessionOnlyCookiesDelayForTesting(
const base::TimeDelta& delay) {
delete_stale_session_only_cookies_delay_ = delay;
}
void StoragePartitionImpl::SetClearNoncesInNetworkContextParamsForTesting(
const base::TimeDelta& delay,
base::RepeatingClosure callback) {
clear_nonces_in_network_context_delay_ = delay;
clear_nonces_in_network_context_callback_for_testing_ = callback;
}
base::WeakPtr<StoragePartitionImpl> StoragePartitionImpl::GetWeakPtr() {
return weak_factory_.GetWeakPtr();
}
BrowserContext* StoragePartitionImpl::browser_context() const {
return browser_context_;
}
storage::mojom::Partition* StoragePartitionImpl::GetStorageServicePartition() {
if (!remote_partition_) {
std::optional<base::FilePath> storage_path;
if (!is_in_memory()) {
storage_path =
browser_context_->GetPath().Append(relative_partition_path_);
}
GetStorageServiceRemote()->BindPartition(
storage_path, remote_partition_.BindNewPipeAndPassReceiver());
remote_partition_.set_disconnect_handler(
base::BindOnce(&StoragePartitionImpl::OnStorageServiceDisconnected,
base::Unretained(this)));
}
return remote_partition_.get();
}
// static
mojo::Remote<storage::mojom::StorageService>&
StoragePartitionImpl::GetStorageServiceForTesting() {
return GetStorageServiceRemote();
}
void StoragePartitionImpl::BindIndexedDB(
const storage::BucketLocator& bucket_locator,
const storage::BucketClientInfo& client_info,
mojo::PendingRemote<storage::mojom::IndexedDBClientStateChecker>
client_state_checker_remote,
mojo::PendingReceiver<blink::mojom::IDBFactory> receiver) {
indexed_db_control_wrapper_->BindIndexedDB(
bucket_locator, client_info, std::move(client_state_checker_remote),
std::move(receiver));
}
mojo::ReceiverId StoragePartitionImpl::BindDomStorage(
int process_id,
mojo::PendingReceiver<blink::mojom::DomStorage> receiver,
mojo::PendingRemote<blink::mojom::DomStorageClient> client) {
DCHECK(initialized_);
auto handle =
ChildProcessSecurityPolicyImpl::GetInstance()->CreateHandle(process_id);
mojo::ReceiverId id = dom_storage_receivers_.Add(
this, std::move(receiver),
std::make_unique<SecurityPolicyHandle>(std::move(handle)));
dom_storage_clients_[id].Bind(std::move(client));
return id;
}
void StoragePartitionImpl::UnbindDomStorage(mojo::ReceiverId receiver_id) {
DCHECK(initialized_);
dom_storage_receivers_.Remove(receiver_id);
dom_storage_clients_.erase(receiver_id);
}
void StoragePartitionImpl::OverrideQuotaManagerForTesting(
storage::QuotaManager* quota_manager) {
DCHECK(initialized_);
quota_manager_ = quota_manager;
}
void StoragePartitionImpl::OverrideSpecialStoragePolicyForTesting(
storage::SpecialStoragePolicy* special_storage_policy) {
DCHECK(initialized_);
special_storage_policy_ = special_storage_policy;
}
void StoragePartitionImpl::ShutdownBackgroundSyncContextForTesting() {
DCHECK(initialized_);
if (GetBackgroundSyncContext()) {
GetBackgroundSyncContext()->Shutdown();
}
}
void StoragePartitionImpl::OverrideBackgroundSyncContextForTesting(
BackgroundSyncContextImpl* background_sync_context) {
DCHECK(initialized_);
DCHECK(!GetBackgroundSyncContext() ||
!GetBackgroundSyncContext()->background_sync_manager());
background_sync_context_ = background_sync_context;
}
void StoragePartitionImpl::OverrideSharedWorkerServiceForTesting(
std::unique_ptr<SharedWorkerServiceImpl> shared_worker_service) {
DCHECK(initialized_);
shared_worker_service_ = std::move(shared_worker_service);
}
void StoragePartitionImpl::OverrideSharedStorageRuntimeManagerForTesting(
std::unique_ptr<SharedStorageRuntimeManager>
shared_storage_runtime_manager) {
DCHECK(initialized_);
shared_storage_runtime_manager_ = std::move(shared_storage_runtime_manager);
}
void StoragePartitionImpl::OverrideSharedStorageHeaderObserverForTesting(
std::unique_ptr<SharedStorageHeaderObserver>
shared_storage_header_observer) {
DCHECK(initialized_);
shared_storage_header_observer_ = std::move(shared_storage_header_observer);
}
void StoragePartitionImpl::OverrideAggregationServiceForTesting(
std::unique_ptr<AggregationService> aggregation_service) {
DCHECK(initialized_);
aggregation_service_ = std::move(aggregation_service);
}
void StoragePartitionImpl::OverrideAttributionManagerForTesting(
std::unique_ptr<AttributionManager> attribution_manager) {
DCHECK(initialized_);
attribution_manager_ = std::move(attribution_manager);
}
void StoragePartitionImpl::OverridePrivateAggregationManagerForTesting(
std::unique_ptr<PrivateAggregationManagerImpl>
private_aggregation_manager) {
DCHECK(initialized_);
private_aggregation_manager_ = std::move(private_aggregation_manager);
}
void StoragePartitionImpl::OverrideDeviceBoundSessionManagerForTesting(
std::unique_ptr<network::mojom::DeviceBoundSessionManager>
device_bound_session_manager) {
DCHECK(initialized_);
mojo::MakeSelfOwnedReceiver(
std::move(device_bound_session_manager),
device_bound_session_manager_.BindNewPipeAndPassReceiver());
}
void StoragePartitionImpl::GetQuotaSettings(
storage::OptionalQuotaSettingsCallback callback) {
if (g_test_quota_settings) {
// For debugging tests harness can inject settings.
std::move(callback).Run(*g_test_quota_settings);
return;
}
storage::GetNominalDynamicSettings(
GetPath(), browser_context_->IsOffTheRecord(),
storage::GetDefaultDeviceInfoHelper(), std::move(callback));
}
void StoragePartitionImpl::InitNetworkContext() {
network::mojom::NetworkContextParamsPtr context_params =
network::mojom::NetworkContextParams::New();
cert_verifier::mojom::CertVerifierCreationParamsPtr
cert_verifier_creation_params =
cert_verifier::mojom::CertVerifierCreationParams::New();
GetContentClient()->browser()->ConfigureNetworkContextParams(
browser_context_, is_in_memory(), relative_partition_path_,
context_params.get(), cert_verifier_creation_params.get());
// Should be initialized with existing per-profile CORS access lists.
DCHECK(context_params->cors_origin_access_list.empty())
<< "NetworkContextParams::cors_origin_access_list should be populated "
"via SharedCorsOriginAccessList";
context_params->cors_origin_access_list =
browser_context_->GetSharedCorsOriginAccessList()
->GetOriginAccessList()
.CreateCorsOriginAccessPatternsList();
devtools_instrumentation::ApplyNetworkContextParamsOverrides(
browser_context_, context_params.get());
DCHECK(!context_params->cert_verifier_params)
<< "`cert_verifier_params` should not be set in the "
"NetworkContextParams, as they will be replaced with a new pipe to "
"the CertVerifierService.";
cert_verifier_service_updater_.reset();
context_params->cert_verifier_params = GetCertVerifierParamsWithUpdater(
std::move(cert_verifier_creation_params),
cert_verifier_service_updater_.BindNewPipeAndPassReceiver());
// This mechanisms should be used only for legacy internal headers. You can
// find a recommended alternative approach on URLRequest::cors_exempt_headers
// at services/network/public/mojom/url_loader.mojom.
context_params->cors_exempt_header_list.push_back(blink::kPurposeHeaderName);
context_params->cors_exempt_header_list.push_back(
GetCorsExemptRequestedWithHeaderName());
variations::UpdateCorsExemptHeaderForVariations(context_params.get());
cors_exempt_header_list_ = context_params->cors_exempt_header_list;
if (base::FeatureList::IsEnabled(
network::features::kCompressionDictionaryTransportBackend) &&
GetContentClient()->browser()->AllowCompressionDictionaryTransport(
browser_context_)) {
context_params->shared_dictionary_enabled = true;
if (!is_in_memory()) {
// Some callers may already initialize NetworkContextFilePaths, and we
// don't want to overwrite them.
if (!context_params->file_paths) {
context_params->file_paths =
network::mojom::NetworkContextFilePaths::New();
}
context_params->file_paths->shared_dictionary_directory =
partition_path_.Append(FILE_PATH_LITERAL("Shared Dictionary"));
}
if (context_params->shared_dictionary_cache_max_size == 0u) {
CalculateAndSetSharedDictionaryCacheMaxSize(
GetWeakPtr(), is_in_memory() ? base::FilePath() : partition_path_);
}
}
if (cookie_deprecation_label_manager_) {
context_params->cookie_deprecation_label =
cookie_deprecation_label_manager_->GetValue().value_or("");
}
network_context_owner_->network_context.reset();
CreateNetworkContextInNetworkService(
network_context_owner_->network_context.BindNewPipeAndPassReceiver(),
std::move(context_params));
DCHECK(network_context_owner_->network_context);
// Restore the saved network revocation nonces. This allows fenced frames'
// untrusted network access states to be persisted in case of a
// `NetworkService` crash.
std::vector<base::UnguessableToken> nonces(
std::begin(network_revocation_nonces_),
std::end(network_revocation_nonces_));
network_context_owner_->network_context->RevokeNetworkForNonces(
nonces, base::NullCallback());
network_context_client_receiver_.reset();
network_context_owner_->network_context->SetClient(
network_context_client_receiver_.BindNewPipeAndPassRemote());
network_context_owner_->network_context.set_disconnect_handler(base::BindOnce(
&StoragePartitionImpl::InitNetworkContext, weak_factory_.GetWeakPtr()));
}
network::mojom::URLLoaderFactoryParamsPtr
StoragePartitionImpl::CreateURLLoaderFactoryParams() {
network::mojom::URLLoaderFactoryParamsPtr params =
network::mojom::URLLoaderFactoryParams::New();
// This method is used for browser-process initiated requests for which there
// is no corresponding RenderProcessHost.
params->process_id = network::mojom::kBrowserProcessId;
params->automatically_assign_isolation_info = true;
params->is_orb_enabled = false;
params->is_trusted = true;
params->url_loader_network_observer =
CreateAuthCertObserverForServiceWorker(params->process_id);
params->disable_web_security =
base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kDisableWebSecurity);
return params;
}
void StoragePartitionImpl::CreateURLLoaderFactoryForBrowserProcessInternal(
mojo::PendingRemote<network::mojom::URLLoaderFactory>* out_factory) {
CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
network::URLLoaderFactoryBuilder factory_builder;
if (url_loader_factory::GetTestingInterceptor()) {
url_loader_factory::GetTestingInterceptor().Run(
network::mojom::kBrowserProcessId, factory_builder);
}
*out_factory =
std::move(factory_builder)
.Finish<mojo::PendingRemote<network::mojom::URLLoaderFactory>>(
GetNetworkContext(), CreateURLLoaderFactoryParams());
}
void StoragePartition::SetDefaultQuotaSettingsForTesting(
const storage::QuotaSettings* settings) {
g_test_quota_settings = settings;
}
mojo::PendingRemote<network::mojom::CookieAccessObserver>
StoragePartitionImpl::CreateCookieAccessObserverForServiceWorker() {
mojo::PendingRemote<network::mojom::CookieAccessObserver> remote;
service_worker_cookie_observers_.Add(
std::make_unique<ServiceWorkerCookieAccessObserver>(this),
remote.InitWithNewPipeAndPassReceiver());
return remote;
}
mojo::PendingRemote<network::mojom::TrustTokenAccessObserver>
StoragePartitionImpl::CreateTrustTokenAccessObserverForServiceWorker() {
mojo::PendingRemote<network::mojom::TrustTokenAccessObserver> remote;
service_worker_trust_token_observers_.Add(
std::make_unique<ServiceWorkerTrustTokenAccessObserver>(this),
remote.InitWithNewPipeAndPassReceiver());
return remote;
}
mojo::PendingRemote<network::mojom::SharedDictionaryAccessObserver>
StoragePartitionImpl::CreateSharedDictionaryAccessObserverForServiceWorker() {
mojo::PendingRemote<network::mojom::SharedDictionaryAccessObserver> remote;
service_worker_shared_dictionary_observers_.Add(
std::make_unique<ServiceWorkerSharedDictionaryAccessObserver>(this),
remote.InitWithNewPipeAndPassReceiver());
return remote;
}
mojo::PendingRemote<network::mojom::DeviceBoundSessionAccessObserver>
StoragePartitionImpl::CreateDeviceBoundSessionObserverForServiceWorker() {
mojo::PendingRemote<network::mojom::DeviceBoundSessionAccessObserver> remote;
service_worker_device_bound_session_observers_.Add(
std::make_unique<ServiceWorkerDeviceBoundSessionAccessObserver>(this),
remote.InitWithNewPipeAndPassReceiver());
return remote;
}
void StoragePartitionImpl::OpenLocalStorageForProcess(
int process_id,
const blink::StorageKey& storage_key,
mojo::PendingReceiver<blink::mojom::StorageArea> receiver) {
DCHECK(initialized_);
auto handle =
ChildProcessSecurityPolicyImpl::GetInstance()->CreateHandle(process_id);
dom_storage_context_->OpenLocalStorage(storage_key, std::nullopt,
std::move(receiver), std::move(handle),
base::DoNothing());
}
void StoragePartitionImpl::BindSessionStorageAreaForProcess(
int process_id,
const blink::StorageKey& storage_key,
const std::string& namespace_id,
mojo::PendingReceiver<blink::mojom::StorageArea> receiver) {
DCHECK(initialized_);
auto handle =
ChildProcessSecurityPolicyImpl::GetInstance()->CreateHandle(process_id);
dom_storage_context_->BindStorageArea(storage_key, std::nullopt, namespace_id,
std::move(receiver), std::move(handle),
base::DoNothing());
}
std::optional<blink::StorageKey> StoragePartitionImpl::CalculateStorageKey(
const url::Origin& origin,
const base::UnguessableToken* nonce) {
if (!blink::StorageKey::IsThirdPartyStoragePartitioningEnabled()) {
return std::nullopt;
}
NavigationOrDocumentHandle* handle =
url_loader_network_observers_.current_context().navigation_or_document();
if (!handle) {
return std::nullopt;
}
FrameTreeNode* node = handle->GetFrameTreeNode();
if (!node) {
return std::nullopt;
}
RenderFrameHostImpl* frame_host = node->current_frame_host();
if (!frame_host) {
return std::nullopt;
}
return frame_host->CalculateStorageKey(origin, nonce);
}
GlobalRenderFrameHostId
StoragePartitionImpl::GetRenderFrameHostIdFromNetworkContext() {
URLLoaderNetworkContext context =
url_loader_network_observers_.current_context();
// `navigation_or_document()` can be null for `kServiceWorkerContext`.
RenderFrameHost* render_frame_host =
context.navigation_or_document()
? context.navigation_or_document()->GetDocument()
: nullptr;
// It can pass empty GlobalRenderFrameHostId() when the context type is
// not `kRenderFrameHostContext`.
return render_frame_host ? render_frame_host->GetGlobalId()
: GlobalRenderFrameHostId();
}
StoragePartitionImpl::URLLoaderNetworkContext::URLLoaderNetworkContext(
GlobalRenderFrameHostId render_frame_host_id)
: type_(Type::kRenderFrameHostContext) {
auto* render_frame_host = RenderFrameHostImpl::FromID(render_frame_host_id);
if (!render_frame_host) {
return;
}
navigation_or_document_ = render_frame_host->GetNavigationOrDocumentHandle();
}
StoragePartitionImpl::URLLoaderNetworkContext::URLLoaderNetworkContext(
NavigationRequest& navigation_request)
: type_(Type::kNavigationRequestContext) {
navigation_or_document_ = navigation_request.navigation_or_document_handle();
}
StoragePartitionImpl::URLLoaderNetworkContext::URLLoaderNetworkContext(
int process_id)
: type_(Type::kServiceWorkerContext), process_id_(process_id) {}
StoragePartitionImpl::URLLoaderNetworkContext::URLLoaderNetworkContext(
const URLLoaderNetworkContext& other) = default;
StoragePartitionImpl::URLLoaderNetworkContext&
StoragePartitionImpl::URLLoaderNetworkContext::operator=(
const URLLoaderNetworkContext& other) = default;
StoragePartitionImpl::URLLoaderNetworkContext::~URLLoaderNetworkContext() =
default;
StoragePartitionImpl::URLLoaderNetworkContext
StoragePartitionImpl::URLLoaderNetworkContext::CreateForRenderFrameHost(
GlobalRenderFrameHostId render_frame_host_id) {
return StoragePartitionImpl::URLLoaderNetworkContext(
render_frame_host_id);
}
StoragePartitionImpl::URLLoaderNetworkContext
StoragePartitionImpl::URLLoaderNetworkContext::CreateForNavigation(
NavigationRequest& navigation_request) {
return StoragePartitionImpl::URLLoaderNetworkContext(navigation_request);
}
bool StoragePartitionImpl::URLLoaderNetworkContext::IsNavigationRequestContext()
const {
return type_ == ContextType::kNavigationRequestContext;
}
// Returns the WebContents corresponding to `context`.
WebContents* StoragePartitionImpl::URLLoaderNetworkContext::GetWebContents() {
if (!navigation_or_document()) {
return nullptr;
}
return navigation_or_document()->GetWebContents();
}
// Returns true if the request is the primary main frame navigation.
bool StoragePartitionImpl::URLLoaderNetworkContext::
IsPrimaryMainFrameRequest() {
if (!IsNavigationRequestContext()) {
return false;
}
return navigation_or_document()->IsInPrimaryMainFrame();
}
} // namespace content