COOP: restrict-properties 7/*: tokens update after navigation.
This patch is concerned with updating the blink::Page browsing context group when a cross browsing context group navigation takes place. This can take two forms: - When a local frame navigates, the BrowsingContextGroupInfo is passed directly to the CommitNavigationParams, for an immediate update. - When a remote frame navigates in another process, the renderer gets updated by a message from the PageBroadcast interface. This incurs an inevitable small delay. DETAILS For the local frame update, the passed BrowsingContextGroupInfo is optional and is only set for top-level navigations to a different browsing context group. It takes the following route: - RenderFrameImpl::CommitNavigation - WebLocalFrameImpl::CommitNavigation - FrameLoader::CommitNavigation - DocumentLoader::DocumentLoader - DocumentLoader::CommitNavigation - Page::UpdateBrowsingContextGroup When the browser receives the information that a page has navigated to another browsing context group, we use the PageBroadcast interface to tell each renderer process holding a proxy of the navigated frame, that the blink::Page is now in another browsing context group. This goes through: - Navigator::DidNavigate - RenderFrameHostManager::ExecutePageBroadcastMethod - WebViewImpl::UpdatePageBrowsingContextGroup - Page::UpdateBrowsingContextGroup Testing is done in the next patch with the CoopRestrictPropertiesAccessBrowserTest suite. Bug: 1221127 Change-Id: Ie6300caee1c3b3e92add97a002416c8e5eddf316 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4514696 Reviewed-by: Charlie Reis <creis@chromium.org> Commit-Queue: Daniel Cheng <dcheng@chromium.org> Cr-Commit-Position: refs/heads/main@{#1152564}
This commit is contained in:

committed by
Chromium LUCI CQ

parent
d81e47fbca
commit
d51484b18b
content
browser
renderer_host
renderer
test
third_party/blink
public
renderer
@@ -3981,7 +3981,8 @@ NavigationControllerImpl::CreateNavigationRequestFromLoadParams(
|
||||
base::flat_map<::blink::mojom::RuntimeFeatureState, bool>(),
|
||||
/*fenced_frame_properties=*/absl::nullopt,
|
||||
/*not_restored_reasons=*/nullptr,
|
||||
/*load_with_storage_access=*/false);
|
||||
/*load_with_storage_access=*/false,
|
||||
/*browsing_context_group_info=*/absl::nullopt);
|
||||
#if BUILDFLAG(IS_ANDROID)
|
||||
if (ValidateDataURLAsString(params.data_url_as_string)) {
|
||||
commit_params->data_url_as_string = params.data_url_as_string->data();
|
||||
|
@@ -59,6 +59,7 @@
|
||||
#include "testing/gmock/include/gmock/gmock.h"
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
#include "third_party/blink/public/common/frame/frame_policy.h"
|
||||
#include "third_party/blink/public/common/page/browsing_context_group_info.h"
|
||||
#include "third_party/blink/public/common/page_state/page_state.h"
|
||||
#include "third_party/blink/public/common/tokens/tokens.h"
|
||||
#include "third_party/blink/public/mojom/frame/frame_owner_properties.mojom.h"
|
||||
@@ -144,6 +145,12 @@ class MockPageBroadcast : public blink::mojom::PageBroadcast {
|
||||
blink::mojom::RemoteMainFrameInterfacesPtr remote_main_frame_interfaces),
|
||||
(override));
|
||||
|
||||
MOCK_METHOD(
|
||||
void,
|
||||
UpdatePageBrowsingContextGroup,
|
||||
(const blink::BrowsingContextGroupInfo& browsing_context_group_info),
|
||||
(override));
|
||||
|
||||
mojo::PendingAssociatedRemote<blink::mojom::PageBroadcast> GetRemote() {
|
||||
return receiver_.BindNewEndpointAndPassDedicatedRemote();
|
||||
}
|
||||
@@ -4661,6 +4668,53 @@ TEST_F(NavigationControllerTest, NavigationApiDisposedEntries) {
|
||||
EXPECT_EQ(main_frame_disposed_keys[0], "3");
|
||||
}
|
||||
|
||||
// Once instantiated, will insert `mock_page_broadcast` as the PageBroadcast on
|
||||
// a newly created RenderViewHost. This is important for listening for the
|
||||
// update to a RenderViewHost which was created for a proxy, as it swaps to a
|
||||
// local frame in a different browsing context group. Note that this this will
|
||||
// only work once, as MockPageBroadcast does not support multiple bindings.
|
||||
class PageBroadcastMockInserter : public WebContentsObserver {
|
||||
public:
|
||||
explicit PageBroadcastMockInserter(
|
||||
content::WebContents* web_contents,
|
||||
testing::NiceMock<MockPageBroadcast>* mock_page_broadcast)
|
||||
: WebContentsObserver(web_contents),
|
||||
mock_page_broadcast_(mock_page_broadcast) {}
|
||||
|
||||
void RenderViewHostChanged(RenderViewHost* old_host,
|
||||
RenderViewHost* new_host) override {
|
||||
static_cast<TestRenderViewHost*>(new_host)->BindPageBroadcast(
|
||||
mock_page_broadcast_->GetRemote());
|
||||
}
|
||||
|
||||
private:
|
||||
raw_ptr<testing::NiceMock<MockPageBroadcast>> mock_page_broadcast_;
|
||||
};
|
||||
|
||||
// Test that navigations across browsing context groups trigger a page broadcast
|
||||
// with up to date browsing context group information.
|
||||
TEST_F(NavigationControllerTest, BrowsingContextGroupUpdate) {
|
||||
const GURL url1("http://a/");
|
||||
const GURL url2("chrome://ukm");
|
||||
|
||||
// Start on a first page.
|
||||
NavigateAndCommit(url1);
|
||||
SiteInstanceImpl* initial_instance = main_test_rfh()->GetSiteInstance();
|
||||
|
||||
// Setup the page broadcast expectations. We expect no call to be made, as the
|
||||
// RenderViewHost for B will get its update through the local frame commit.
|
||||
testing::NiceMock<MockPageBroadcast> mock_page_broadcast;
|
||||
EXPECT_CALL(mock_page_broadcast, UpdatePageBrowsingContextGroup(testing::_))
|
||||
.Times(0);
|
||||
PageBroadcastMockInserter mock_inserter(contents(), &mock_page_broadcast);
|
||||
|
||||
// Navigate to a cross browsing context group page. The update function should
|
||||
// not be called.
|
||||
NavigateAndCommit(url2);
|
||||
SiteInstanceImpl* final_instance = main_test_rfh()->GetSiteInstance();
|
||||
EXPECT_FALSE(initial_instance->IsRelatedSiteInstance(final_instance));
|
||||
}
|
||||
|
||||
class NavigationControllerFencedFrameTest : public NavigationControllerTest {
|
||||
public:
|
||||
NavigationControllerFencedFrameTest() {
|
||||
|
@@ -964,7 +964,8 @@ NavigationEntryImpl::ConstructCommitNavigationParams(
|
||||
base::flat_map<::blink::mojom::RuntimeFeatureState, bool>(),
|
||||
/*fenced_frame_properties=*/absl::nullopt,
|
||||
/*not_restored_reasons=*/nullptr,
|
||||
/*load_with_storage_access=*/false);
|
||||
/*load_with_storage_access=*/false,
|
||||
/*browsing_context_group_info=*/absl::nullopt);
|
||||
#if BUILDFLAG(IS_ANDROID)
|
||||
// `data_url_as_string` is saved in NavigationEntry but should only be used by
|
||||
// main frames, because loadData* navigations can only happen on the main
|
||||
|
@@ -1318,7 +1318,8 @@ std::unique_ptr<NavigationRequest> NavigationRequest::CreateRendererInitiated(
|
||||
base::flat_map<::blink::mojom::RuntimeFeatureState, bool>(),
|
||||
/*fenced_frame_properties=*/absl::nullopt,
|
||||
/*not_restored_reasons=*/nullptr,
|
||||
/*load_with_storage_access=*/load_with_storage_access);
|
||||
/*load_with_storage_access=*/load_with_storage_access,
|
||||
/*browsing_context_group_info=*/absl::nullopt);
|
||||
|
||||
commit_params->navigation_timing->system_entropy_at_navigation_start =
|
||||
SystemEntropyUtils::ComputeSystemEntropyForFrameTreeNode(
|
||||
@@ -1460,7 +1461,8 @@ NavigationRequest::CreateForSynchronousRendererCommit(
|
||||
base::flat_map<::blink::mojom::RuntimeFeatureState, bool>(),
|
||||
/*fenced_frame_properties=*/absl::nullopt,
|
||||
/*not_restored_reasons=*/nullptr,
|
||||
/*load_with_storage_access=*/false);
|
||||
/*load_with_storage_access=*/false,
|
||||
/*browsing_context_group_info=*/absl::nullopt);
|
||||
blink::mojom::BeginNavigationParamsPtr begin_params =
|
||||
blink::mojom::BeginNavigationParams::New();
|
||||
std::unique_ptr<NavigationRequest> navigation_request(new NavigationRequest(
|
||||
|
@@ -615,6 +615,31 @@ void Navigator::DidNavigate(
|
||||
site_instance->group());
|
||||
}
|
||||
|
||||
// If this was the navigation of a top-level frame to another browsing context
|
||||
// group, update the browsing context group in all the renderers that have a
|
||||
// representation of this page. Do not update the page in the main frame's own
|
||||
// process, as it was already updated during commit.
|
||||
// TODO(https://crbug.com/1446696): See if that can be consolidated with other
|
||||
// similar IPCs.
|
||||
if (render_frame_host->is_main_frame() &&
|
||||
navigation_request->browsing_context_group_swap().ShouldSwap()) {
|
||||
SiteInstanceImpl* final_site_instance =
|
||||
render_frame_host->GetSiteInstance();
|
||||
blink::BrowsingContextGroupInfo browsing_context_group_info(
|
||||
final_site_instance->browsing_instance_token(),
|
||||
final_site_instance->coop_related_group_token());
|
||||
frame_tree.root()->render_manager()->ExecutePageBroadcastMethod(
|
||||
base::BindRepeating(
|
||||
[](const blink::BrowsingContextGroupInfo& info,
|
||||
RenderViewHostImpl* rvh) {
|
||||
if (auto& broadcast = rvh->GetAssociatedPageBroadcast()) {
|
||||
broadcast->UpdatePageBrowsingContextGroup(info);
|
||||
}
|
||||
},
|
||||
browsing_context_group_info),
|
||||
final_site_instance->group());
|
||||
}
|
||||
|
||||
// Store some information for recording WebPlatform security metrics. These
|
||||
// metrics depends on information present in the NavigationRequest. However
|
||||
// they must be recorded after the NavigationRequest has been destroyed and
|
||||
|
@@ -13107,6 +13107,20 @@ void RenderFrameHostImpl::SendCommitNavigation(
|
||||
// otherwise).
|
||||
MaybeSendFencedFrameReportingBeacon(*navigation_request);
|
||||
|
||||
// If this commit is for a main frame in another browsing context group, warn
|
||||
// the renderer that it should update the browsing context group information
|
||||
// of the page if this frame successfully commits. Note that the
|
||||
// BrowsingContextGroupInfo in the params should only be populated at commit
|
||||
// time, and only in the case of a swap.
|
||||
CHECK(!commit_params->browsing_context_group_info.has_value());
|
||||
if (is_main_frame() &&
|
||||
navigation_request->browsing_context_group_swap().ShouldSwap()) {
|
||||
commit_params->browsing_context_group_info =
|
||||
blink::BrowsingContextGroupInfo(
|
||||
GetSiteInstance()->browsing_instance_token(),
|
||||
GetSiteInstance()->coop_related_group_token());
|
||||
}
|
||||
|
||||
commit_params->commit_sent = base::TimeTicks::Now();
|
||||
navigation_client->CommitNavigation(
|
||||
std::move(common_params), std::move(commit_params),
|
||||
@@ -13146,6 +13160,20 @@ void RenderFrameHostImpl::SendCommitFailedNavigation(
|
||||
DCHECK_NE(GURL(), common_params->url);
|
||||
DCHECK_NE(net::OK, error_code);
|
||||
IncreaseCommitNavigationCounter();
|
||||
|
||||
// If this commit is for a main frame in another browsing context group, warn
|
||||
// the renderer that it should update the browsing context group information
|
||||
// of the page. Note that the BrowsingContextGroupInfo in the params should
|
||||
// only be populated at commit time, and only in the case of a swap.
|
||||
CHECK(!commit_params->browsing_context_group_info.has_value());
|
||||
if (is_main_frame() &&
|
||||
navigation_request->browsing_context_group_swap().ShouldSwap()) {
|
||||
commit_params->browsing_context_group_info =
|
||||
blink::BrowsingContextGroupInfo(
|
||||
GetSiteInstance()->browsing_instance_token(),
|
||||
GetSiteInstance()->coop_related_group_token());
|
||||
}
|
||||
|
||||
navigation_client->CommitFailedNavigation(
|
||||
std::move(common_params), std::move(commit_params),
|
||||
has_stale_copy_in_cache, error_code, extended_error_code,
|
||||
|
@@ -1072,6 +1072,9 @@ void FillMiscNavigationParams(
|
||||
|
||||
navigation_params->ancestor_or_self_has_cspee =
|
||||
commit_params.ancestor_or_self_has_cspee;
|
||||
|
||||
navigation_params->browsing_context_group_info =
|
||||
commit_params.browsing_context_group_info;
|
||||
}
|
||||
|
||||
std::string GetUniqueNameOfWebFrame(WebFrame* web_frame) {
|
||||
|
@@ -57,4 +57,7 @@ void TestPageBroadcast::CreateRemoteMainFrame(
|
||||
blink::mojom::RemoteFrameInterfacesFromBrowserPtr remote_frame_interfaces,
|
||||
blink::mojom::RemoteMainFrameInterfacesPtr remote_main_frame_interfaces) {}
|
||||
|
||||
void TestPageBroadcast::UpdatePageBrowsingContextGroup(
|
||||
const blink::BrowsingContextGroupInfo& browsing_context_group_info) {}
|
||||
|
||||
} // namespace content
|
||||
|
@@ -43,6 +43,8 @@ class TestPageBroadcast : public blink::mojom::PageBroadcast {
|
||||
blink::mojom::RemoteFrameInterfacesFromBrowserPtr remote_frame_interfaces,
|
||||
blink::mojom::RemoteMainFrameInterfacesPtr remote_main_frame_interfaces)
|
||||
override;
|
||||
void UpdatePageBrowsingContextGroup(const blink::BrowsingContextGroupInfo&
|
||||
browsing_context_group_info) override;
|
||||
|
||||
mojo::AssociatedReceiver<blink::mojom::PageBroadcast> receiver_;
|
||||
};
|
||||
|
Reference in New Issue
Block a user