blob: 90f63e429a48db303d07eb24c3d9034c82ce54b6 [file] [log] [blame]
// Copyright 2022 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/shared_storage/shared_storage_budget_charger.h"
#include "components/services/storage/shared_storage/shared_storage_manager.h"
#include "content/browser/renderer_host/frame_tree.h"
#include "content/browser/renderer_host/frame_tree_node.h"
#include "content/browser/renderer_host/render_frame_host_impl.h"
#include "content/public/browser/navigation_handle.h"
namespace content {
SharedStorageBudgetCharger::SharedStorageBudgetCharger(
WebContents* web_contents)
: WebContentsObserver(web_contents),
WebContentsUserData<SharedStorageBudgetCharger>(*web_contents) {}
SharedStorageBudgetCharger::~SharedStorageBudgetCharger() = default;
void SharedStorageBudgetCharger::DidStartNavigation(
NavigationHandle* navigation_handle) {
// We are only interested in renderer-initiated navigations taking place in
// the main frame of the primary frame tree.
if (!navigation_handle->IsInPrimaryMainFrame() ||
!navigation_handle->IsRendererInitiated()) {
return;
}
RenderFrameHostImpl* initiator_frame_host =
navigation_handle->GetInitiatorFrameToken().has_value()
? RenderFrameHostImpl::FromFrameToken(
navigation_handle->GetInitiatorProcessId(),
navigation_handle->GetInitiatorFrameToken().value())
: nullptr;
base::UmaHistogramBoolean(
"Navigation.MainFrame.RendererInitiated.InitiatorFramePresentAtStart",
initiator_frame_host);
// Skip if we cannot find the initiator frame host. This can happen when the
// initiator frame starts a top navigation and then triggers its own
// destruction by navigating to a cross-origin frame, so that it may no longer
// exist by the time we get here.
//
// The risk of getting unlimited budget this way seems to be small: the ideal
// timing can vary from time to time, and whether the timing exist at all also
// depends on the ordering of messaging.
//
// For now, allow the leak and track with UMA (and revisit as needed).
// https://crbug.com/1331111
if (!initiator_frame_host)
return;
storage::SharedStorageManager* shared_storage_manager =
initiator_frame_host->GetStoragePartition()->GetSharedStorageManager();
std::vector<const SharedStorageBudgetMetadata*>
shared_storage_budget_metadata = initiator_frame_host->frame_tree_node()
->FindSharedStorageBudgetMetadata();
for (const auto* metadata : shared_storage_budget_metadata) {
if (metadata->top_navigated) {
continue;
}
// We only want to charge the budget the first time a navigation leaves the
// fenced frame, across all fenced frames navigated to the same urn.
// We can do this even though the pointer is const because
// `top_navigated` is a mutable field of `SharedStorageBudgetMetadata`.
metadata->top_navigated = true;
if (metadata->budget_to_charge == 0) {
continue;
}
shared_storage_manager->MakeBudgetWithdrawal(
metadata->site, metadata->budget_to_charge, base::DoNothing());
}
}
WEB_CONTENTS_USER_DATA_KEY_IMPL(SharedStorageBudgetCharger);
} // namespace content