blob: 42dddfd440ac0ada3c2f2f6379b051de13d7103b [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/browser/storage_partition_impl.h"
#include <stdint.h>
#include <functional>
#include <memory>
#include <set>
#include <utility>
#include <vector>
#include "base/barrier_closure.h"
#include "base/bind.h"
#include "base/callback_helpers.h"
#include "base/command_line.h"
#include "base/containers/contains.h"
#include "base/feature_list.h"
#include "base/files/file_util.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/no_destructor.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/time/default_clock.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#include "components/leveldb_proto/public/proto_database_provider.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_features.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_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/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/prefetch_url_loader_service.h"
#include "content/browser/locks/lock_manager.h"
#include "content/browser/native_io/native_io_context_impl.h"
#include "content/browser/navigation_or_document_handle.h"
#include "content/browser/network_context_client_base_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_host_registry.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/service_worker/service_worker_container_host.h"
#include "content/browser/service_worker/service_worker_context_wrapper.h"
#include "content/browser/shared_storage/shared_storage_worklet_host_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/private_aggregation_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/content_browser_client.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_result.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_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/net_errors.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/cross_thread_pending_shared_url_loader_factory.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/network_context.mojom.h"
#include "services/network/public/mojom/trust_tokens.mojom.h"
#include "storage/browser/database/database_tracker.h"
#include "storage/browser/quota/quota_client_type.h"
#include "storage/browser/quota/quota_manager.h"
#include "storage/browser/quota/quota_settings.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "third_party/blink/public/common/features.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/quota/quota_types.mojom.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/media_license_manager.h"
#endif // BUILDFLAG(ENABLE_LIBRARY_CDMS)
using CookieDeletionFilter = network::mojom::CookieDeletionFilter;
using CookieDeletionFilterPtr = network::mojom::CookieDeletionFilterPtr;
namespace content {
namespace {
using Type = StoragePartitionImpl::URLLoaderNetworkContext::Type;
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),
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;
}
// A callback to create a URLLoaderFactory that is used in tests.
StoragePartitionImpl::CreateNetworkFactoryCallback&
GetCreateURLLoaderFactoryCallback() {
static base::NoDestructor<StoragePartitionImpl::CreateNetworkFactoryCallback>
create_factory_callback;
return *create_factory_callback;
}
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 type " << static_cast<int>(bucket.type)
<< " 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,
blink::mojom::StorageType quota_storage_type,
storage::QuotaClientTypes quota_client_types,
base::OnceClosure callback) {
quota_manager->PerformStorageCleanup(
quota_storage_type, 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::RepeatingClosure barrier =
base::BarrierClosure(infos.size(), std::move(done_callback));
for (const StorageUsageInfo& info : infos) {
if (storage_key_matcher &&
!storage_key_matcher.Run(blink::StorageKey(info.origin),
special_storage_policy.get())) {
barrier.Run();
continue;
}
if (info.last_modified >= delete_begin &&
info.last_modified <= delete_end) {
dom_storage_context->DeleteLocalStorage(
// TODO(https://crbug.com/1199077): Pass the real StorageKey
// when StoragePartitionImpl is converted.
blink::StorageKey(info.origin), barrier);
} else {
barrier.Run();
}
}
}
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::RepeatingClosure barrier =
base::BarrierClosure(infos.size(), std::move(done_callback));
for (const SessionStorageUsageInfo& info : infos) {
if (storage_key_matcher &&
!storage_key_matcher.Run(info.storage_key,
special_storage_policy.get())) {
barrier.Run();
continue;
}
dom_storage_context->DeleteSessionStorage(info, barrier);
}
}
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)));
}
BrowserContext* GetBrowserContextFromStoragePartition(
base::WeakPtr<StoragePartitionImpl> weak_partition_ptr) {
return weak_partition_ptr ? weak_partition_ptr->browser_context() : nullptr;
}
// Returns the WebContents corresponding to `context`.
WebContents* GetWebContents(
StoragePartitionImpl::URLLoaderNetworkContext context) {
if (!context.navigation_or_document())
return nullptr;
return context.navigation_or_document()->GetWebContents();
}
// 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::Getter web_contents_getter,
const net::AuthChallengeInfo& auth_info,
bool is_request_for_primary_main_frame,
uint32_t process_id,
uint32_t request_id,
const GURL& url,
scoped_refptr<net::HttpResponseHeaders> response_headers,
bool first_auth_attempt)
: auth_challenge_responder_(std::move(auth_challenge_responder)),
auth_info_(auth_info),
request_id_(process_id, request_id),
is_request_for_primary_main_frame_(is_request_for_primary_main_frame),
creating_login_delegate_(false),
url_(url),
response_headers_(std::move(response_headers)),
first_auth_attempt_(first_auth_attempt),
web_contents_getter_(web_contents_getter) {
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 absl::optional<net::AuthCredentials>& auth_credentials) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK(!(use_fallback && auth_credentials.has_value()));
if (!use_fallback) {
OnAuthCredentials(auth_credentials);
return;
}
WebContents* web_contents = web_contents_getter_.Run();
if (!web_contents) {
OnAuthCredentials(absl::nullopt);
return;
}
// WeakPtr is not strictly necessary here due to OnRequestCancelled.
creating_login_delegate_ = true;
login_delegate_ = GetContentClient()->browser()->CreateLoginDelegate(
auth_info_, web_contents, request_id_,
is_request_for_primary_main_frame_, url_, response_headers_,
first_auth_attempt_,
base::BindOnce(&LoginHandlerDelegate::OnAuthCredentials,
weak_factory_.GetWeakPtr()));
creating_login_delegate_ = false;
if (!login_delegate_) {
OnAuthCredentials(absl::nullopt);
return;
}
}
void OnAuthCredentials(
const absl::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_;
bool creating_login_delegate_;
GURL url_;
const scoped_refptr<net::HttpResponseHeaders> response_headers_;
bool first_auth_attempt_;
WebContents::Getter web_contents_getter_;
std::unique_ptr<LoginDelegate> login_delegate_;
base::WeakPtrFactory<LoginHandlerDelegate> weak_factory_{this};
};
void OnAuthRequiredContinuation(
int32_t process_id,
uint32_t request_id,
const GURL& url,
bool is_request_for_primary_main_frame,
bool first_auth_attempt,
const net::AuthChallengeInfo& auth_info,
const scoped_refptr<net::HttpResponseHeaders>& head_headers,
mojo::PendingRemote<network::mojom::AuthChallengeResponder>
auth_challenge_responder,
base::RepeatingCallback<WebContents*(void)> web_contents_getter) {
if (!web_contents_getter || !web_contents_getter.Run()) {
mojo::Remote<network::mojom::AuthChallengeResponder>
auth_challenge_responder_remote(std::move(auth_challenge_responder));
auth_challenge_responder_remote->OnAuthCredentials(absl::nullopt);
return;
}
new LoginHandlerDelegate(
std::move(auth_challenge_responder), std::move(web_contents_getter),
auth_info, is_request_for_primary_main_frame, process_id, request_id, url,
head_headers, first_auth_attempt); // deletes self
}
// Returns true if the request is the primary main frame navigation.
bool IsPrimaryMainFrameRequest(
const StoragePartitionImpl::URLLoaderNetworkContext& context) {
if (!context.IsNavigationRequestContext())
return false;
return context.navigation_or_document()->IsInPrimaryMainFrame();
}
// 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,
content::BrowserContext* browser_context,
WebContents::Getter web_contents_getter,
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),
std::move(web_contents_getter),
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);
DCHECK((cert && private_key) || (!cert && !private_key));
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,
PrerenderHost::FinalStatus 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);
}
void OnCertificateRequestedContinuation(
const scoped_refptr<net::SSLCertRequestInfo>& cert_info,
mojo::PendingRemote<network::mojom::ClientCertificateResponder>
client_cert_responder_remote,
base::RepeatingCallback<WebContents*(void)> web_contents_getter) {
WebContents* web_contents = nullptr;
if (web_contents_getter)
web_contents = web_contents_getter.Run();
if (!web_contents) {
CallCancelRequest(std::move(client_cert_responder_remote));
return;
}
new SSLClientAuthDelegate(std::move(client_cert_responder_remote),
web_contents->GetBrowserContext(),
std::move(web_contents_getter),
cert_info); // deletes self
}
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
// 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` and `storage_key` cannot both be set.
// If both `storage_key_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, the only storage backend that uses this is
// is for conversion measurement. 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::StorageKeyPolicyMatcherFunction storage_key_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());
if (storage_key_origin_empty && storage_key_matcher.is_null())
return base::NullCallback();
if (storage_key_matcher) {
return base::BindRepeating(
[](StoragePartition::StorageKeyPolicyMatcherFunction
storage_key_matcher,
scoped_refptr<storage::SpecialStoragePolicy> policy,
const blink::StorageKey& storage_key) -> bool {
return storage_key_matcher.Run(storage_key, policy.get());
},
std::move(storage_key_matcher), std::move(policy));
}
DCHECK(!storage_key_origin_empty);
return base::BindRepeating(std::equal_to<const blink::StorageKey&>(),
storage_key);
}
void ClearPluginPrivateDataOnFileTaskRunner(
scoped_refptr<storage::FileSystemContext> filesystem_context,
base::OnceClosure callback) {
DCHECK(filesystem_context->default_file_task_runner()
->RunsTasksInCurrentSequence());
DVLOG(3) << "Clearing plugin data: " << filesystem_context;
// The Plugin Private File System has been deprecated. Delete all data at
// %profile/File System/Plugins.
auto plugin_path = filesystem_context->partition_path()
.Append(storage::kFileSystemDirectory)
.Append(FILE_PATH_LITERAL("Plugins"));
filesystem_context->default_file_task_runner()->PostTaskAndReply(
FROM_HERE,
base::BindOnce(base::IgnoreResult(&base::DeletePathRecursively),
plugin_path),
std::move(callback));
}
} // namespace
class StoragePartitionImpl::URLLoaderFactoryForBrowserProcess
: public network::SharedURLLoaderFactory {
public:
explicit URLLoaderFactoryForBrowserProcess(
StoragePartitionImpl* storage_partition)
: storage_partition_(storage_partition) {}
URLLoaderFactoryForBrowserProcess(const URLLoaderFactoryForBrowserProcess&) =
delete;
URLLoaderFactoryForBrowserProcess& operator=(
const URLLoaderFactoryForBrowserProcess&) = delete;
// mojom::URLLoaderFactory implementation:
void CreateLoaderAndStart(
mojo::PendingReceiver<network::mojom::URLLoader> receiver,
int32_t request_id,
uint32_t options,
const network::ResourceRequest& url_request,
mojo::PendingRemote<network::mojom::URLLoaderClient> client,
const net::MutableNetworkTrafficAnnotationTag& traffic_annotation)
override {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
if (!storage_partition_)
return;
storage_partition_->GetURLLoaderFactoryForBrowserProcessInternal()
->CreateLoaderAndStart(std::move(receiver), request_id, options,
url_request, std::move(client),
traffic_annotation);
}
void Clone(mojo::PendingReceiver<network::mojom::URLLoaderFactory> receiver)
override {
if (!storage_partition_)
return;
storage_partition_->GetURLLoaderFactoryForBrowserProcessInternal()->Clone(
std::move(receiver));
}
// SharedURLLoaderFactory implementation:
std::unique_ptr<network::PendingSharedURLLoaderFactory> Clone() override {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
return std::make_unique<network::CrossThreadPendingSharedURLLoaderFactory>(
this);
}
void Shutdown() { storage_partition_ = nullptr; }
private:
friend class base::RefCounted<URLLoaderFactoryForBrowserProcess>;
~URLLoaderFactoryForBrowserProcess() override = default;
raw_ptr<StoragePartitionImpl> storage_partition_;
};
// 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);
// TODO(crbug.com/1137788): Add a removal mask for NativeIO after adopting a
// more inclusive name.
quota_client_types.insert(storage::QuotaClientType::kNativeIO);
}
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);
if (remove_mask & StoragePartition::REMOVE_DATA_MASK_MEDIA_LICENSES)
quota_client_types.insert(storage::QuotaClientType::kMediaLicense);
return quota_client_types;
}
// static
void StoragePartitionImpl::
SetGetURLLoaderFactoryForBrowserProcessCallbackForTesting(
CreateNetworkFactoryCallback url_loader_factory_callback) {
DCHECK(!BrowserThread::IsThreadInitialized(BrowserThread::UI) ||
BrowserThread::CurrentlyOn(BrowserThread::UI));
DCHECK(!url_loader_factory_callback || !GetCreateURLLoaderFactoryCallback())
<< "It is not expected that this is called with non-null callback when "
<< "another overriding callback is already set.";
GetCreateURLLoaderFactoryCallback() = std::move(url_loader_factory_callback);
}
// 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 absl::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,
blink::mojom::StorageType quota_storage_type);
private:
// All of these data are accessed on IO thread.
uint32_t remove_mask_;
uint32_t quota_storage_remove_mask_;
absl::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,
StorageKeyPolicyMatcherFunction storage_key_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,
PrivateAggregationManager* private_aggregation_manager,
storage::SharedStorageManager* shared_storage_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.
// Entries must also be added to StoragePartitionRemoverTasks in enums.xml.
enum class TracingDataType {
kSynchronous = 1,
kCookies = 2,
kQuota = 3,
kLocalStorage = 4,
kSessionStorage = 5,
kShaderCache = 6, // Deprecated in favor of using kGpuCache.
kPluginPrivate = 7,
kConversions = 8,
kAggregationService = 9,
kSharedStorage = 10,
kGpuCache = 11,
kPrivateAggregation = 12,
kMaxValue = kPrivateAggregation,
};
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() ? absl::nullopt
: absl::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(
network::mojom::CookieAccessDetailsPtr details) override {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
scoped_refptr<ServiceWorkerContextWrapper> service_worker_context =
storage_partition_->GetServiceWorkerContext();
std::vector<GlobalRenderFrameHostId> destinations =
*service_worker_context->GetWindowClientFrameRoutingIds(
blink::StorageKey(url::Origin::Create(details->url)));
if (destinations.empty())
return;
for (GlobalRenderFrameHostId frame_id : destinations) {
if (RenderFrameHostImpl* rfh = RenderFrameHostImpl::FromID(frame_id)) {
rfh->OnCookiesAccessed(mojo::Clone(details));
}
}
}
// `storage_partition_` owns this object via UniqueReceiverSet
// (service_worker_cookie_observers_).
raw_ptr<StoragePartitionImpl> storage_partition_;
};
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),
deletion_helpers_running_(0) {}
StoragePartitionImpl::~StoragePartitionImpl() {
browser_context_ = nullptr;
if (url_loader_factory_getter_)
url_loader_factory_getter_->OnStoragePartitionDestroyed();
if (shared_url_loader_factory_for_browser_process_) {
shared_url_loader_factory_for_browser_process_->Shutdown();
}
scoped_refptr<storage::DatabaseTracker> database_tracker(
GetDatabaseTracker());
if (database_tracker) {
storage::DatabaseTracker* database_tracker_ptr = database_tracker.get();
database_tracker_ptr->task_runner()->PostTask(
FROM_HERE, base::BindOnce(&storage::DatabaseTracker::Shutdown,
std::move(database_tracker)));
}
if (GetFileSystemAccessManager())
GetFileSystemAccessManager()->Shutdown();
if (GetFileSystemContext())
GetFileSystemContext()->Shutdown();
if (GetDOMStorageContext())
GetDOMStorageContext()->Shutdown();
if (GetServiceWorkerContext())
GetServiceWorkerContext()->Shutdown();
if (GetPlatformNotificationContext())
GetPlatformNotificationContext()->Shutdown();
if (GetBackgroundSyncContext())
GetBackgroundSyncContext()->Shutdown();
if (GetBackgroundFetchContext())
GetBackgroundFetchContext()->Shutdown();
if (GetContentIndexContext())
GetContentIndexContext()->Shutdown();
if (GetGeneratedCodeCacheContext())
GetGeneratedCodeCacheContext()->Shutdown();
}
// 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);
database_tracker_ = storage::DatabaseTracker::Create(
partition_path_, is_in_memory(),
browser_context_->GetSpecialStoragePolicy(), quota_manager_proxy);
dom_storage_context_ = DOMStorageContextWrapper::Create(
this, browser_context_->GetSpecialStoragePolicy());
lock_manager_ = std::make_unique<LockManager>();
shared_storage_worklet_host_manager_ =
std::make_unique<SharedStorageWorkletHostManager>();
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<IndexedDBControlWrapper>(
path, browser_context_->GetSpecialStoragePolicy(), quota_manager_proxy,
base::DefaultClock::GetInstance(),
ChromeBlobStorageContext::GetRemoteFor(browser_context_),
std::move(file_system_access_context), GetIOThreadTaskRunner({}),
/*task_runner=*/nullptr);
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>();
native_io_context_ = base::MakeRefCounted<NativeIOContextImpl>();
native_io_context_->Initialize(
path, browser_context_->GetSpecialStoragePolicy(), quota_manager_proxy);
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_ =
base::MakeRefCounted<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_);
background_sync_context_ = base::MakeRefCounted<BackgroundSyncContextImpl>();
background_sync_context_->Init(service_worker_context_,
devtools_background_services_context_);
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>();
url_loader_factory_getter_ = new URLLoaderFactoryGetter();
url_loader_factory_getter_->Initialize(this);
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,
blob_url_registry_->AsWeakPtr());
prefetch_url_loader_service_ =
std::make_unique<PrefetchURLLoaderService>(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);
// The Conversion Measurement API is not available in Incognito mode.
if (!is_in_memory() &&
base::FeatureList::IsEnabled(blink::features::kConversionMeasurement)) {
attribution_manager_ = std::make_unique<AttributionManagerImpl>(
this, path, special_storage_policy_);
}
if (base::FeatureList::IsEnabled(blink::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());
}
// The Topics API is not available in Incognito mode.
if (!is_in_memory() &&
base::FeatureList::IsEnabled(blink::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();
if (base::FeatureList::IsEnabled(kPrivacySandboxAggregationService)) {
aggregation_service_ =
std::make_unique<AggregationServiceImpl>(is_in_memory(), path, this);
}
#if BUILDFLAG(ENABLE_LIBRARY_CDMS)
media_license_manager_ = std::make_unique<MediaLicenseManager>(
is_in_memory(), browser_context_->GetSpecialStoragePolicy(),
quota_manager_proxy);
#endif // BUILDFLAG(ENABLE_LIBRARY_CDMS)
if (base::FeatureList::IsEnabled(blink::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_);
}
if (base::FeatureList::IsEnabled(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() {
return config_;
}
base::FilePath StoragePartitionImpl::GetPath() {
return partition_path_;
}
std::string StoragePartitionImpl::GetPartitionDomain() {
return config_.partition_domain();
}
network::mojom::NetworkContext* StoragePartitionImpl::GetNetworkContext() {
DCHECK(initialized_);
if (!network_context_.is_bound())
InitNetworkContext();
return network_context_.get();
}
scoped_refptr<network::SharedURLLoaderFactory>
StoragePartitionImpl::GetURLLoaderFactoryForBrowserProcess() {
DCHECK(initialized_);
if (!shared_url_loader_factory_for_browser_process_) {
shared_url_loader_factory_for_browser_process_ =
new URLLoaderFactoryForBrowserProcess(this);
}
return shared_url_loader_factory_for_browser_process_;
}
std::unique_ptr<network::PendingSharedURLLoaderFactory>
StoragePartitionImpl::GetURLLoaderFactoryForBrowserProcessIOThread() {
DCHECK(initialized_);
return url_loader_factory_getter_->GetPendingNetworkFactory();
}
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,
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,
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();
}
storage::DatabaseTracker* StoragePartitionImpl::GetDatabaseTracker() {
DCHECK(initialized_);
return database_tracker_.get();
}
DOMStorageContextWrapper* StoragePartitionImpl::GetDOMStorageContext() {
DCHECK(initialized_);
return dom_storage_context_.get();
}
storage::mojom::LocalStorageControl*
StoragePartitionImpl::GetLocalStorageControl() {
DCHECK(initialized_);
return GetDOMStorageContext()->GetLocalStorageControl();
}
LockManager* StoragePartitionImpl::GetLockManager() {
DCHECK(initialized_);
return lock_manager_.get();
}
SharedStorageWorkletHostManager*
StoragePartitionImpl::GetSharedStorageWorkletHostManager() {
DCHECK(initialized_);
return shared_storage_worklet_host_manager_.get();
}
storage::mojom::IndexedDBControl& StoragePartitionImpl::GetIndexedDBControl() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
return *indexed_db_control_wrapper_.get();
}
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();
}
PrefetchURLLoaderService* StoragePartitionImpl::GetPrefetchURLLoaderService() {
DCHECK(initialized_);
return prefetch_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();
}
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)
MediaLicenseManager* StoragePartitionImpl::GetMediaLicenseManager() {
DCHECK(initialized_);
return media_license_manager_.get();
}
#endif // BUILDFLAG(ENABLE_LIBRARY_CDMS)
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();
}
NativeIOContext* StoragePartitionImpl::GetNativeIOContext() {
DCHECK(initialized_);
return native_io_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();
}
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 absl::optional<base::UnguessableToken>& window_id,
uint32_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();
absl::optional<bool> is_primary_main_frame;
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(https://crbug.com/1240483): 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* container_host =
service_worker_context_->context()->GetContainerHostByWindowId(
*window_id);
if (container_host) {
if (container_host->GetRenderFrameHostId()) {
// Use ServiceWorkerContainerHost's GlobalRenderFrameHostId when
// the navigation commit has already started.
GlobalRenderFrameHostId render_frame_host_id =
container_host->GetRenderFrameHostId();
context = URLLoaderNetworkContext::CreateForRenderFrameHost(
render_frame_host_id);
// TODO(crbug.com/963748, crbug.com/1251596): `is_primary_main_frame`
// should be false because only the request for a sub resource
// intercepted by a service worker reaches here.
auto* render_frame_host_impl =
RenderFrameHostImpl::FromID(render_frame_host_id);
if (render_frame_host_impl) {
is_primary_main_frame =
render_frame_host_impl->IsInPrimaryMainFrame();
}
} else {
// Overwrite the context; set `type` to kNavigationRequestContext.
// TODO(https://crbug.com/1239554): Optimize locating logic.
int frame_tree_node_id =
container_host->GetFrameTreeNodeIdForOngoingNavigation(
base::PassKey<StoragePartitionImpl>());
context = URLLoaderNetworkContext::CreateForNavigation(
*(FrameTreeNode::GloballyFindByID(frame_tree_node_id)
->navigation_request()));
}
}
}
}
// 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(),
PrerenderHost::FinalStatus::kLoginAuthRequested)) {
return;
}
if (!is_primary_main_frame.has_value())
is_primary_main_frame = IsPrimaryMainFrameRequest(context);
auto web_contents_getter = base::BindRepeating(GetWebContents, context);
int process_id = network::mojom::kBrowserProcessId;
if (context.type() ==
URLLoaderNetworkContext::Type::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,
// OnAuthRequiredContinuation() fails to get the web contents and calls
// 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 render frame host 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(https://crbug.com/1322751): 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;
}
}
OnAuthRequiredContinuation(
process_id, request_id, url, *is_primary_main_frame, first_auth_attempt,
auth_info, head_headers, std::move(auth_challenge_responder),
web_contents_getter);
}
void StoragePartitionImpl::OnCertificateRequested(
const absl::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(https://crbug.com/1240483): 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* container_host =
service_worker_context_->context()->GetContainerHostByWindowId(
*window_id);
if (container_host) {
if (container_host->GetRenderFrameHostId()) {
// Use ServiceWorkerContainerHost's GlobalRenderFrameHostId when
// the navigation commit has already started.
GlobalRenderFrameHostId render_frame_host_id =
container_host->GetRenderFrameHostId();
context = URLLoaderNetworkContext::CreateForRenderFrameHost(
render_frame_host_id);
} else {
// Overwrite the context; set `type` to kNavigationRequestContext.
// TODO(https://crbug.com/1239554): Optimize locating logic.
int frame_tree_node_id =
container_host->GetFrameTreeNodeIdForOngoingNavigation(
base::PassKey<StoragePartitionImpl>());
context = URLLoaderNetworkContext::CreateForNavigation(
*(FrameTreeNode::GloballyFindByID(frame_tree_node_id)
->navigation_request()));
}
}
}
}
// 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(),
PrerenderHost::FinalStatus::kClientCertRequested)) {
CallCancelRequest(std::move(cert_responder));
return;
}
auto web_contents_getter = base::BindRepeating(GetWebContents, context);
OnCertificateRequestedContinuation(cert_info, std::move(cert_responder),
std::move(web_contents_getter));
}
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(),
PrerenderHost::FinalStatus::kSslCertificateError)) {
std::move(response).Run(net_error);
return;
}
SSLErrorDelegate* delegate =
new SSLErrorDelegate(std::move(response)); // deletes self
bool is_primary_main_frame_request = IsPrimaryMainFrameRequest(context);
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 =
GetWebContents(url_loader_network_observers_.current_context());
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) {
URLLoaderNetworkContext context =
url_loader_network_observers_.current_context();
// `navigation_or_document()` can be null for `kServiceWorkerContext`.
auto* 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`.
GlobalRenderFrameHostId render_frame_host_id =
render_frame_host ? render_frame_host->GetGlobalId()
: GlobalRenderFrameHostId();
GetContentClient()->browser()->OnNetworkServiceDataUseUpdate(
render_frame_host_id, network_traffic_annotation_id_hash, recv_bytes,
sent_bytes);
}
void StoragePartitionImpl::Clone(
mojo::PendingReceiver<network::mojom::URLLoaderNetworkServiceObserver>
observer) {
url_loader_network_observers_.Add(
this, std::move(observer),
url_loader_network_observers_.current_context());
}
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() {
mojo::PendingRemote<network::mojom::URLLoaderNetworkServiceObserver> remote;
url_loader_network_observers_.Add(
this, remote.InitWithNewPipeAndPassReceiver(),
URLLoaderNetworkContext::CreateForServiceWorker());
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(
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(
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 absl::optional<net::CookiePartitionKey>& cookie_partition_key,
OnClearSiteDataCallback callback) {
DCHECK(initialized_);
auto browser_context_getter = base::BindRepeating(
GetBrowserContextFromStoragePartition, weak_factory_.GetWeakPtr());
auto web_contents_getter = base::BindRepeating(
GetWebContents, url_loader_network_observers_.current_context());
ClearSiteDataHandler::HandleHeader(
browser_context_getter, web_contents_getter, url, header_value,
load_flags, cookie_partition_key, 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_CHROMEOS)
void StoragePartitionImpl::OnTrustAnchorUsed() {
GetContentClient()->browser()->OnTrustAnchorUsed(browser_context_);
}
#endif
void StoragePartitionImpl::OnTrustTokenIssuanceDivertedToSystem(
network::mojom::FulfillTrustTokenIssuanceRequestPtr request,
OnTrustTokenIssuanceDivertedToSystemCallback callback) {
if (!local_trust_token_fulfiller_ &&
!attempted_to_bind_local_trust_token_fulfiller_) {
attempted_to_bind_local_trust_token_fulfiller_ = true;
ProvisionallyBindUnboundLocalTrustTokenFulfillerIfSupportedBySystem();
}
if (!local_trust_token_fulfiller_) {
auto response = network::mojom::FulfillTrustTokenIssuanceAnswer::New();
response->status =
network::mojom::FulfillTrustTokenIssuanceAnswer::Status::kNotFound;
std::move(callback).Run(std::move(response));
return;
}
int callback_key = next_pending_trust_token_issuance_callback_key_++;
pending_trust_token_issuance_callbacks_.emplace(callback_key,
std::move(callback));
local_trust_token_fulfiller_->FulfillTrustTokenIssuance(
std::move(request),
base::BindOnce(
[](int callback_key, base::WeakPtr<StoragePartitionImpl> partition,
network::mojom::FulfillTrustTokenIssuanceAnswerPtr answer) {
if (!partition)
return;
if (!base::Contains(
partition->pending_trust_token_issuance_callbacks_,
callback_key)) {
return;
}
auto callback =
std::move(partition->pending_trust_token_issuance_callbacks_.at(
callback_key));
partition->pending_trust_token_issuance_callbacks_.erase(
callback_key);
std::move(callback).Run(std::move(answer));
},
callback_key, weak_factory_.GetWeakPtr()));
}
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_);
}
void StoragePartitionImpl::ClearDataImpl(
uint32_t remove_mask,
uint32_t quota_storage_remove_mask,
const blink::StorageKey& storage_key,
StorageKeyPolicyMatcherFunction storage_key_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);
DCHECK(storage_key.origin().opaque() || storage_key_matcher.is_null());
for (auto& observer : data_removal_observers_) {
auto filter = CreateGenericStorageKeyMatcher(
storage_key, storage_key_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, std::move(storage_key_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(), 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));
if (quota_storage_remove_mask_ & QUOTA_MANAGED_STORAGE_MASK_PERSISTENT) {
IncrementTaskCountOnIO();
// Ask the QuotaManager for all buckets with persistent quota modified
// within the user-specified timeframe, and deal with the resulting set in
// ClearBucketsOnIOThread().
quota_manager->GetBucketsModifiedBetween(
blink::mojom::StorageType::kPersistent, begin, end,
base::BindOnce(&QuotaManagedDataDeletionHelper::ClearBucketsOnIOThread,
base::Unretained(this), base::RetainedRef(quota_manager),
special_storage_policy, storage_key_matcher,
perform_storage_cleanup, decrement_callback));
}
// Do the same for temporary quota.
if (quota_storage_remove_mask_ & QUOTA_MANAGED_STORAGE_MASK_TEMPORARY) {
IncrementTaskCountOnIO();
quota_manager->GetBucketsModifiedBetween(
blink::mojom::StorageType::kTemporary, begin, end,
base::BindOnce(&QuotaManagedDataDeletionHelper::ClearBucketsOnIOThread,
base::Unretained(this), base::RetainedRef(quota_manager),
special_storage_policy, storage_key_matcher,
perform_storage_cleanup, decrement_callback));
}
// Do the same for syncable quota.
if (quota_storage_remove_mask_ & QUOTA_MANAGED_STORAGE_MASK_SYNCABLE) {
IncrementTaskCountOnIO();
quota_manager->GetBucketsModifiedBetween(
blink::mojom::StorageType::kSyncable, begin, end,
base::BindOnce(&QuotaManagedDataDeletionHelper::ClearBucketsOnIOThread,
base::Unretained(this), base::RetainedRef(quota_manager),
special_storage_policy, std::move(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,
blink::mojom::StorageType quota_storage_type) {
// 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_storage_type, 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,
StorageKeyPolicyMatcherFunction storage_key_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,
PrivateAggregationManager* private_aggregation_manager,
storage::SharedStorageManager* shared_storage_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 `storage_key_matcher` can be set.
const bool storage_key_origin_empty = storage_key.origin().opaque();
DCHECK(storage_key_origin_empty || storage_key_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);
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;
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))));
}
if (remove_mask_ & REMOVE_DATA_MASK_INTEREST_GROUPS) {
if (interest_group_manager) {
interest_group_manager->DeleteInterestGroupData(
CreateGenericStorageKeyMatcher(storage_key, storage_key_matcher,
storage_policy_ref));
}
}
if (remove_mask_ & REMOVE_DATA_MASK_INTEREST_GROUP_PERMISSIONS_CACHE) {
if (interest_group_manager)
interest_group_manager->ClearPermissionsCache();
}
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 ||
remove_mask_ & REMOVE_DATA_MASK_MEDIA_LICENSES) {
GetIOThreadTaskRunner({})->PostTask(
FROM_HERE,
base::BindOnce(&DataDeletionHelper::ClearQuotaManagedDataOnIOThread,
base::Unretained(this),
base::WrapRefCounted(quota_manager), begin, end,
storage_key, storage_policy_ref, 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,
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/960325): Sometimes SessionStorage fails to call its
// callback. Figure out why.
ClearSessionStorageOnUIThread(
base::WrapRefCounted(dom_storage_context), storage_policy_ref,
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));
}
}
}
auto filter = CreateGenericStorageKeyMatcher(storage_key, storage_key_matcher,
storage_policy_ref);
// 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)) {
attribution_manager->ClearData(
begin, end, filter,
remove_mask_ & REMOVE_DATA_MASK_ATTRIBUTION_REPORTING_INTERNAL,
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/1284971): Consider fine-grained deletion of public keys.
// TODO(crbug.com/1286173): Consider adding aggregation service origins to
// `CookiesTreeModel`.
aggregation_service->ClearData(
begin, end, filter,
CreateTaskCompletionClosure(TracingDataType::kAggregationService));
}
if (private_aggregation_manager &&
(remove_mask_ & REMOVE_DATA_MASK_PRIVATE_AGGREGATION_INTERNAL)) {
private_aggregation_manager->ClearBudgetData(
begin, end, filter,
CreateTaskCompletionClosure(TracingDataType::kPrivateAggregation));
}
// TODO(crbug.com/1340250): The Plugin Private File System is removed, but
// some devices may still have old data on their machine. For now greedily try
// to delete this data, but we'll want to remove this code at some point.
filesystem_context->default_file_task_runner()->PostTask(
FROM_HERE, base::BindOnce(&ClearPluginPrivateDataOnFileTaskRunner,
base::WrapRefCounted(filesystem_context),
CreateTaskCompletionClosure(
TracingDataType::kPluginPrivate)));
if (base::FeatureList::IsEnabled(blink::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(
storage_key_matcher, begin, end,
std::move(shared_storage_purge_callback), perform_storage_cleanup);
}
}
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();
ClearDataImpl(remove_mask, quota_storage_remove_mask,
blink::StorageKey(url::Origin::Create(storage_origin)),
StorageKeyPolicyMatcherFunction(), std::move(deletion_filter),
false, base::Time(), base::Time::Max(), std::move(callback));
}
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,
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,
StorageKeyPolicyMatcherFunction storage_key_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(),
std::move(storage_key_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() {
DCHECK(initialized_);
GetNetworkContext()->ResetURLLoaderFactories();
url_loader_factory_for_browser_process_.reset();
url_loader_factory_getter_->Initialize(this);
}
void StoragePartitionImpl::ClearBluetoothAllowedDevicesMapForTesting() {
DCHECK(initialized_);
bluetooth_allowed_devices_map_->Clear();
}
void StoragePartitionImpl::ResetAttributionManagerForTesting(
base::OnceCallback<void(bool)> callback) {
DCHECK(initialized_);
// Reset the existing manager first to ensure that the underlying DB is only
// accessed by one instance at a time.
attribution_manager_.reset();
attribution_manager_ = AttributionManagerImpl::CreateWithNewDbForTesting(
this, partition_path_, special_storage_policy_);
std::move(callback).Run(/*success=*/!!attribution_manager_);
}
void StoragePartitionImpl::AddObserver(DataRemovalObserver* observer) {
data_removal_observers_.AddObserver(observer);
}
void StoragePartitionImpl::RemoveObserver(DataRemovalObserver* observer) {
data_removal_observers_.RemoveObserver(observer);
}
void StoragePartitionImpl::FlushNetworkInterfaceForTesting() {
DCHECK(initialized_);
DCHECK(network_context_);
network_context_.FlushForTesting();
if (url_loader_factory_for_browser_process_)
url_loader_factory_for_browser_process_.FlushForTesting();
if (cookie_manager_for_browser_process_)
cookie_manager_for_browser_process_.FlushForTesting();
}
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_.reset();
network_context_.Bind(std::move(network_context_remote));
}
base::WeakPtr<StoragePartition> StoragePartitionImpl::GetWeakPtr() {
return weak_factory_.GetWeakPtr();
}
BrowserContext* StoragePartitionImpl::browser_context() const {
return browser_context_;
}
storage::mojom::Partition* StoragePartitionImpl::GetStorageServicePartition() {
if (!remote_partition_) {
absl::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();
}
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::OverrideSharedStorageWorkletHostManagerForTesting(
std::unique_ptr<SharedStorageWorkletHostManager>
shared_storage_worklet_host_manager) {
DCHECK(initialized_);
shared_storage_worklet_host_manager_ =
std::move(shared_storage_worklet_host_manager);
}
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<PrivateAggregationManager> private_aggregation_manager) {
DCHECK(initialized_);
private_aggregation_manager_ = std::move(private_aggregation_manager);
}
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.";
context_params->cert_verifier_params =
GetCertVerifierParams(std::move(cert_verifier_creation_params));
// 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(
kCorsExemptPurposeHeaderName);
context_params->cors_exempt_header_list.push_back(
GetCorsExemptRequestedWithHeaderName());
variations::UpdateCorsExemptHeaderForVariations(context_params.get());
cors_exempt_header_list_ = context_params->cors_exempt_header_list;
network_context_.reset();
CreateNetworkContextInNetworkService(
network_context_.BindNewPipeAndPassReceiver(), std::move(context_params));
DCHECK(network_context_);
network_context_client_receiver_.reset();
network_context_->SetClient(
network_context_client_receiver_.BindNewPipeAndPassRemote());
network_context_.set_disconnect_handler(base::BindOnce(
&StoragePartitionImpl::InitNetworkContext, weak_factory_.GetWeakPtr()));
if (base::FeatureList::IsEnabled(features::kPreloadCookies)) {
mojo::Remote<::network::mojom::CookieManager> cookie_manager;
mojo::PendingRemote<::network::mojom::CookieManager> cookie_manager_remote;
network_context_->GetCookieManager(
cookie_manager_remote.InitWithNewPipeAndPassReceiver());
cookie_manager.Bind(std::move(cookie_manager_remote));
cookie_manager->GetAllCookies(base::NullCallback());
}
}
network::mojom::URLLoaderFactoryParamsPtr
StoragePartitionImpl::CreateURLLoaderFactoryParams() {
network::mojom::URLLoaderFactoryParamsPtr params =
network::mojom::URLLoaderFactoryParams::New();
params->process_id = network::mojom::kBrowserProcessId;
params->automatically_assign_isolation_info = true;
params->is_corb_enabled = false;
params->is_trusted = true;
params->url_loader_network_observer =
CreateAuthCertObserverForServiceWorker();
params->disable_web_security =
base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kDisableWebSecurity);
return params;
}
network::mojom::URLLoaderFactory*
StoragePartitionImpl::GetURLLoaderFactoryForBrowserProcessInternal() {
// Create the URLLoaderFactory as needed, but make sure not to reuse a
// previously created one if the test override has changed.
if (url_loader_factory_for_browser_process_ &&
url_loader_factory_for_browser_process_.is_connected() &&
is_test_url_loader_factory_for_browser_process_ !=
!GetCreateURLLoaderFactoryCallback()) {
return url_loader_factory_for_browser_process_.get();
}
network::mojom::URLLoaderFactoryParamsPtr params =
CreateURLLoaderFactoryParams();
url_loader_factory_for_browser_process_.reset();
if (!GetCreateURLLoaderFactoryCallback()) {
GetNetworkContext()->CreateURLLoaderFactory(
url_loader_factory_for_browser_process_.BindNewPipeAndPassReceiver(),
std::move(params));
is_test_url_loader_factory_for_browser_process_ = false;
return url_loader_factory_for_browser_process_.get();
}
mojo::PendingRemote<network::mojom::URLLoaderFactory> original_factory;
GetNetworkContext()->CreateURLLoaderFactory(
original_factory.InitWithNewPipeAndPassReceiver(), std::move(params));
url_loader_factory_for_browser_process_.Bind(
GetCreateURLLoaderFactoryCallback().Run(std::move(original_factory)));
is_test_url_loader_factory_for_browser_process_ = true;
return url_loader_factory_for_browser_process_.get();
}
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;
}
void StoragePartitionImpl::OnLocalTrustTokenFulfillerConnectionError() {
auto not_found_answer =
network::mojom::FulfillTrustTokenIssuanceAnswer::New();
// kNotFound represents a case where the local system was unable to provide an
// answer to the request.
not_found_answer->status =
network::mojom::FulfillTrustTokenIssuanceAnswer::Status::kNotFound;
for (auto& key_and_callback : pending_trust_token_issuance_callbacks_)
std::move(key_and_callback.second).Run(not_found_answer.Clone());
pending_trust_token_issuance_callbacks_.clear();
}
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, absl::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, absl::nullopt,
namespace_id, std::move(receiver),
std::move(handle), base::DoNothing());
}
void StoragePartitionImpl::
ProvisionallyBindUnboundLocalTrustTokenFulfillerIfSupportedBySystem() {
if (local_trust_token_fulfiller_)
return;
#if BUILDFLAG(IS_ANDROID)
GetGlobalJavaInterfaces()->GetInterface(
local_trust_token_fulfiller_.BindNewPipeAndPassReceiver());
#endif // BUILDFLAG(IS_ANDROID)
if (local_trust_token_fulfiller_) {
local_trust_token_fulfiller_.set_disconnect_handler(base::BindOnce(
&StoragePartitionImpl::OnLocalTrustTokenFulfillerConnectionError,
weak_factory_.GetWeakPtr()));
}
}
StoragePartitionImpl::URLLoaderNetworkContext::URLLoaderNetworkContext(
URLLoaderNetworkContext::Type type,
GlobalRenderFrameHostId render_frame_host_id)
: type_(type) {
// `render_frame_host_id` can be invalid for `kServiceWorkerContext`.
if (!render_frame_host_id)
return;
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(
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(
URLLoaderNetworkContext::Type::kRenderFrameHostContext,
render_frame_host_id);
}
StoragePartitionImpl::URLLoaderNetworkContext
StoragePartitionImpl::URLLoaderNetworkContext::CreateForNavigation(
NavigationRequest& navigation_request) {
return StoragePartitionImpl::URLLoaderNetworkContext(navigation_request);
}
StoragePartitionImpl::URLLoaderNetworkContext
StoragePartitionImpl::URLLoaderNetworkContext::CreateForServiceWorker() {
return StoragePartitionImpl::URLLoaderNetworkContext(
URLLoaderNetworkContext::Type::kServiceWorkerContext,
GlobalRenderFrameHostId());
}
bool StoragePartitionImpl::URLLoaderNetworkContext::IsNavigationRequestContext()
const {
return type_ == URLLoaderNetworkContext::Type::kNavigationRequestContext;
}
} // namespace content