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