0

Create blink::DocumentToken and populate it when a navigation commits.

== Background ==
blink::DocumentToken will be used for features like GPU's pipeline
caching, allowing the cache to be partitioned using storage keys. The
renderer process is considered untrustworthy, but communicates directly
with the GPU process; rather than having the untrustworthy renderer
directly specify a potentially spoofed storage key, it will send a
document token to the GPU process, which will then ask the trustworthy
browser process for the corresponding storage key.

== Implementation details ==
On the browser side, the blink::DocumentToken is bound to the
RenderFrameHostImpl's DocumentAssociatedMetadata; on the renderer side,
the token is bound to the blink::Document.

When creating a new window or child frame, the browser side allocates a
new DocumentToken and also passes that token to the renderer to plumb
through frame initialization.

When committing a new navigation, the browser side allocates a new
DocumentToken on the NavigationRequest and passes that token to the
renderer in the `CommitNavigation()` IPC.

The intended behavior is that blink::DocumentToken changes each time the
Document changes, though there are some exceptions:
- things like javascript: URLs that end up resulting in a new document
  reuse the old DocumentToken: from the perspective of the browser, the
  document has not really changed.
- when processing something like `window.open()`, Blink has a historical
  quirk where it creates the initial empty document and then immediately
  replaces it with a synchronously-completed navigation to about:blank.
  Like javascript: URLs, this also reuses the old DocumentToken: this
  quirk is renderer-internal and invisible to the browser.

There is also a small hack for speculative RenderFrameHosts: committing
a navigation in a speculative RenderFrameHost does not construct a new
DocumentAssociatedMetadata, instead, the DocumentAssociatedMetadata's
token is simply updated. The hope is that there will be minimal other
document-associated data prior to committing a navigation in a
speculative RenderFrameHost, so this quirk will be mostly invisible
outside the //content implementation.

One open question: when navigating away from the initial empty document
and reusing the Window object, should the DocumentToken be reused
instead of generating a new one? Reusing the token would more closely
mirror the lifetime of LocalDOMWindow and allow it to be a logical
replacement for LocalFrameToken in ExecutionContextToken; however,
reuse of the Window object is also one of the weird edge cases in the
HTML standard that would be nice to minimize if possible.

For now, the implementation chooses not to reuse the DocumentToken even
if the LocalDOMWindow would be reused for a navigation from the initial
empty document to another same-origin page (note that this is distinct
from the synchronous re-navigation to about:blank noted above).

Finally, this CL does not add the ability to look up a RenderFrameHost
by DocumentToken yet: this CL is already far too large due to the amount
of boilerplate changes required.

Bug: 1362938
Change-Id: I4431ed4a7a0739905579fd1585b2a42701d84d7d
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3849601
Reviewed-by: Alex Moshchuk <alexmos@chromium.org>
Reviewed-by: Nate Chapin <japhet@chromium.org>
Commit-Queue: Daniel Cheng <dcheng@chromium.org>
Owners-Override: Nate Chapin <japhet@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1050447}
This commit is contained in:
Daniel Cheng
2022-09-22 23:30:34 +00:00
committed by Chromium LUCI CQ
parent df255c4e85
commit 284c389485
102 changed files with 1321 additions and 326 deletions
components
plugins
printing
content
browser
common
public
renderer
shell
test
extensions/renderer
third_party/blink

@ -287,7 +287,8 @@ WebViewPlugin::WebViewHelper::WebViewHelper(
web_view_->SetRendererPreferences(renderer_preferences);
WebLocalFrame* web_frame = WebLocalFrame::CreateMainFrame(
web_view_, this, nullptr, blink::LocalFrameToken(), nullptr);
web_view_, this, nullptr, blink::LocalFrameToken(),
blink::DocumentToken(), nullptr);
blink::WebFrameWidget* frame_widget = web_frame->InitializeFrameWidget(
blink::CrossVariantMojoAssociatedRemote<
blink::mojom::FrameWidgetHostInterfaceBase>(),

@ -773,7 +773,8 @@ void PrintRenderFrameHelper::PrintHeaderAndFooter(
HeaderAndFooterClient frame_client;
blink::WebLocalFrame* frame = blink::WebLocalFrame::CreateMainFrame(
web_view, &frame_client, nullptr, blink::LocalFrameToken(), nullptr);
web_view, &frame_client, nullptr, blink::LocalFrameToken(),
blink::DocumentToken(), nullptr);
mojo::AssociatedRemote<blink::mojom::FrameWidget> frame_widget;
mojo::PendingAssociatedReceiver<blink::mojom::FrameWidget>
@ -898,8 +899,8 @@ class PrepareFrameAndViewForPrint : public blink::WebViewClient,
const blink::FramePolicy& frame_policy,
const blink::WebFrameOwnerProperties& frame_owner_properties,
blink::FrameOwnerElementType owner_type,
blink::WebPolicyContainerBindParams policy_container_bind_params)
override;
blink::WebPolicyContainerBindParams policy_container_bind_params,
FinishChildFrameCreationFn finish_creation) override;
void FrameDetached() override;
std::unique_ptr<blink::WebURLLoaderFactory> CreateURLLoaderFactory() override;
@ -1048,7 +1049,8 @@ void PrepareFrameAndViewForPrint::CopySelection(
/*page_base_background_color=*/absl::nullopt);
blink::WebView::ApplyWebPreferences(prefs, web_view);
blink::WebLocalFrame* main_frame = blink::WebLocalFrame::CreateMainFrame(
web_view, this, nullptr, blink::LocalFrameToken(), nullptr);
web_view, this, nullptr, blink::LocalFrameToken(), blink::DocumentToken(),
nullptr);
frame_.Reset(main_frame);
mojo::AssociatedRemote<blink::mojom::FrameWidget> frame_widget;
mojo::PendingAssociatedReceiver<blink::mojom::FrameWidget>
@ -1132,7 +1134,8 @@ blink::WebLocalFrame* PrepareFrameAndViewForPrint::CreateChildFrame(
const blink::FramePolicy& frame_policy,
const blink::WebFrameOwnerProperties& frame_owner_properties,
blink::FrameOwnerElementType frame_owner_type,
blink::WebPolicyContainerBindParams policy_container_bind_params) {
blink::WebPolicyContainerBindParams policy_container_bind_params,
FinishChildFrameCreationFn finish_creation) {
// This is called when printing a selection and when this selection contains
// an iframe. This is not supported yet. An empty rectangle will be displayed
// instead.

@ -33,7 +33,8 @@ FrameTreeNode* CreateDelegateFrameTreeNode(
/*associated_interface_provider_receiver=*/mojo::NullAssociatedReceiver(),
blink::mojom::TreeScopeType::kDocument, "", "", true,
blink::LocalFrameToken(), base::UnguessableToken::Create(),
blink::FramePolicy(), blink::mojom::FrameOwnerProperties(), false,
blink::DocumentToken(), blink::FramePolicy(),
blink::mojom::FrameOwnerProperties(), false,
blink::FrameOwnerElementType::kFencedframe,
/*is_dummy_frame_for_inner_tree=*/true);
}

@ -174,13 +174,14 @@ class RenderFrameHostFactoryForHistoryBackInterceptor
int32_t routing_id,
mojo::PendingAssociatedRemote<mojom::Frame> frame_remote,
const blink::LocalFrameToken& frame_token,
const blink::DocumentToken& document_token,
bool renderer_initiated_creation,
RenderFrameHostImpl::LifecycleStateImpl lifecycle_state,
scoped_refptr<BrowsingContextState> browsing_context_state) override {
return base::WrapUnique(new RenderFrameHostImplForHistoryBackInterceptor(
site_instance, std::move(render_view_host), delegate, frame_tree,
frame_tree_node, routing_id, std::move(frame_remote), frame_token,
renderer_initiated_creation, lifecycle_state,
document_token, renderer_initiated_creation, lifecycle_state,
std::move(browsing_context_state),
frame_tree_node->frame_owner_element_type()));
}

@ -153,7 +153,8 @@ RenderFrameProxyHost* Portal::CreateProxyAndAttachPortal(
mojo::NullAssociatedReceiver(),
blink::mojom::TreeScopeType::kDocument, "", "", true,
blink::LocalFrameToken(), base::UnguessableToken::Create(),
blink::FramePolicy(), blink::mojom::FrameOwnerProperties(), false,
blink::DocumentToken(), blink::FramePolicy(),
blink::mojom::FrameOwnerProperties(), false,
blink::FrameOwnerElementType::kPortal,
/*is_dummy_frame_for_inner_tree=*/true);
outer_node->AddObserver(this);

@ -1614,13 +1614,14 @@ class RenderFrameHostFactoryForLocalMainFrameInterceptor
int32_t routing_id,
mojo::PendingAssociatedRemote<mojom::Frame> frame_remote,
const blink::LocalFrameToken& frame_token,
const blink::DocumentToken& document_token,
bool renderer_initiated_creation,
RenderFrameHostImpl::LifecycleStateImpl lifecycle_state,
scoped_refptr<BrowsingContextState> browsing_context_state) override {
return base::WrapUnique(new RenderFrameHostImplForLocalMainFrameInterceptor(
site_instance, std::move(render_view_host), delegate, frame_tree,
frame_tree_node, routing_id, std::move(frame_remote), frame_token,
renderer_initiated_creation, lifecycle_state,
document_token, renderer_initiated_creation, lifecycle_state,
std::move(browsing_context_state),
frame_tree_node->frame_owner_element_type()));
}

@ -57,7 +57,8 @@ class AcceptLanguageUtilsTests : public RenderViewHostImplTestHarness {
CreateStubAssociatedInterfaceProviderReceiver(),
blink::mojom::TreeScopeType::kDocument, std::string(), "uniqueName0",
false, blink::LocalFrameToken(), base::UnguessableToken::Create(),
blink::FramePolicy(), blink::mojom::FrameOwnerProperties(),
blink::DocumentToken(), blink::FramePolicy(),
blink::mojom::FrameOwnerProperties(),
blink::FrameOwnerElementType::kIframe);
}

@ -0,0 +1,472 @@
// 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 "base/run_loop.h"
#include "base/test/bind.h"
#include "content/browser/renderer_host/render_frame_host_impl.h"
#include "content/browser/web_contents/web_contents_impl.h"
#include "content/public/browser/weak_document_ptr.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/content_browser_test.h"
#include "content/public/test/content_browser_test_utils.h"
#include "content/shell/browser/shell.h"
#include "content/shell/common/render_frame_test_helper.mojom.h"
#include "content/test/content_browser_test_utils_internal.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "net/dns/mock_host_resolver.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "third_party/blink/public/common/chrome_debug_urls.h"
#include "third_party/blink/public/common/tokens/tokens.h"
#include "url/gurl.h"
namespace content {
namespace {
// The general structure of all tests is to navigate A -> A -> B. A -> A will
// reuse the same `RenderFrameHost` (without RenderDocument) while A -> B will
// swap to a new `RenderFrameHost` (with --site-per-process).
class DocumentTokenBrowserTest : public ContentBrowserTest {
protected:
void SetUpOnMainThread() override {
ContentBrowserTest::SetUpOnMainThread();
host_resolver()->AddRule("*", "127.0.0.1");
ASSERT_TRUE(embedded_test_server()->Start());
}
WebContentsImpl* web_contents() {
return static_cast<WebContentsImpl*>(shell()->web_contents());
}
blink::DocumentToken GetBrowserSideToken(ToRenderFrameHost adapter) {
return static_cast<RenderFrameHostImpl*>(adapter.render_frame_host())
->GetDocumentToken();
}
// Verifies that the browser-side `DocumentToken` and the renderer-side
// `DocumentToken` have matching values.
[[nodiscard]] ::testing::AssertionResult VerifyMatchingTokens(
ToRenderFrameHost adapter) {
blink::DocumentToken token_from_browser = GetBrowserSideToken(adapter);
mojo::Remote<mojom::RenderFrameTestHelper> remote;
adapter.render_frame_host()->GetRemoteInterfaces()->GetInterface(
remote.BindNewPipeAndPassReceiver());
blink::DocumentToken token_from_renderer;
base::RunLoop run_loop;
remote->GetDocumentToken(
base::BindLambdaForTesting([&](const blink::DocumentToken& token) {
token_from_renderer = token;
run_loop.Quit();
}));
run_loop.Run();
if (token_from_browser == token_from_renderer) {
return ::testing::AssertionSuccess();
}
return ::testing::AssertionFailure()
<< "browser token was " << token_from_browser
<< " but renderer token was " << token_from_renderer;
}
// Whether or not `NavigateAndGetNewToken()` should wait for the response and
// validate document token state immediately afterwards. Most tests should
// expect and wait for a response; however, tests that are exercising
// `CommitFailedNavigation()` will probably want to specify `kNo`.
enum class ExpectedResponse {
kYes,
kNo,
};
// Navigate `adapter.render_frame_host()` to `target_url`. Verifies that the
// browser and renderer state are in sync, and that the document token is not
// updated until the navigation actually commits.
//
// Note: this helper makes IPCs to the `RenderFrame`; for the first navigation
// in a WebContents, it is typically more appropriate to use `NavigateToURL()`
// or another similar helper instead.
blink::DocumentToken NavigateAndGetNewToken(
ToRenderFrameHost adapter,
const GURL& target_url,
ExpectedResponse expect_response = ExpectedResponse::kYes) {
SCOPED_TRACE(target_url.spec());
// Capture the FrameTreeNode now; when a navigation commits, the current
// RenderFrameHost may change.
FrameTreeNode* const frame_tree_node =
static_cast<RenderFrameHostImpl*>(adapter.render_frame_host())
->frame_tree_node();
const blink::DocumentToken old_token = GetBrowserSideToken(adapter);
// Start a new navigation in the main frame. The navigation is still
// ongoing, so `DocumentToken` should not be updated yet.
TestNavigationManager nav_manager(
WebContents::FromRenderFrameHost(adapter.render_frame_host()),
target_url);
EXPECT_TRUE(BeginNavigateToURLFromRenderer(adapter, target_url));
EXPECT_TRUE(VerifyMatchingTokens(adapter));
EXPECT_EQ(old_token, GetBrowserSideToken(adapter));
// Just before the request is actually issued, the navigation is still
// ongoing, so `DocumentToken` should not be updated yet.
EXPECT_TRUE(nav_manager.WaitForRequestStart());
EXPECT_TRUE(VerifyMatchingTokens(adapter));
EXPECT_EQ(old_token, GetBrowserSideToken(adapter));
if (ExpectedResponse::kYes == expect_response) {
// Just before reading the response, the navigation is still ongoing, so
// `DocumentToken` should not be updated yet.
EXPECT_TRUE(nav_manager.WaitForResponse());
EXPECT_TRUE(VerifyMatchingTokens(adapter));
EXPECT_EQ(old_token, GetBrowserSideToken(adapter));
}
// Once a cross-document navigation completes, the document token should be
// updated though.
nav_manager.WaitForNavigationFinished();
// The RenderFrameHost may have changed; use the FrameTreeNode captured
// above instead.
EXPECT_EQ(target_url,
frame_tree_node->current_frame_host()->GetLastCommittedURL());
EXPECT_TRUE(VerifyMatchingTokens(frame_tree_node));
const blink::DocumentToken new_token = GetBrowserSideToken(frame_tree_node);
EXPECT_NE(new_token, old_token);
return new_token;
}
};
IN_PROC_BROWSER_TEST_F(DocumentTokenBrowserTest, MainFrameBasic) {
std::vector<blink::DocumentToken> seen_tokens;
ASSERT_TRUE(NavigateToURL(
web_contents(), embedded_test_server()->GetURL("a.com", "/title1.html")));
EXPECT_TRUE(VerifyMatchingTokens(web_contents()));
seen_tokens.push_back(GetBrowserSideToken(web_contents()));
seen_tokens.push_back(NavigateAndGetNewToken(
web_contents(), embedded_test_server()->GetURL("a.com", "/title1.html")));
seen_tokens.push_back(NavigateAndGetNewToken(
web_contents(), embedded_test_server()->GetURL("b.com", "/title1.html")));
std::set unique_tokens(seen_tokens.begin(), seen_tokens.end());
EXPECT_EQ(unique_tokens.size(), seen_tokens.size());
}
IN_PROC_BROWSER_TEST_F(DocumentTokenBrowserTest, SubFrameBasic) {
std::vector<blink::DocumentToken> seen_tokens;
ASSERT_TRUE(NavigateToURL(
web_contents(), embedded_test_server()->GetURL(
"a.com", "/cross_site_iframe_factory.html?a(a)")));
EXPECT_TRUE(VerifyMatchingTokens(web_contents()));
EXPECT_TRUE(VerifyMatchingTokens(ChildFrameAt(web_contents(), 0)));
seen_tokens.push_back(GetBrowserSideToken(web_contents()));
seen_tokens.push_back(GetBrowserSideToken(ChildFrameAt(web_contents(), 0)));
seen_tokens.push_back(NavigateAndGetNewToken(
ChildFrameAt(web_contents(), 0),
embedded_test_server()->GetURL("a.com", "/title1.html")));
// Main document did not navigate so the token should be the same.
EXPECT_EQ(seen_tokens[0], GetBrowserSideToken(web_contents()));
seen_tokens.push_back(NavigateAndGetNewToken(
ChildFrameAt(web_contents(), 0),
embedded_test_server()->GetURL("b.com", "/title1.html")));
// Main document did not navigate so the token should be the same.
EXPECT_EQ(seen_tokens[0], GetBrowserSideToken(web_contents()));
std::set unique_tokens(seen_tokens.begin(), seen_tokens.end());
EXPECT_EQ(unique_tokens.size(), seen_tokens.size());
}
IN_PROC_BROWSER_TEST_F(DocumentTokenBrowserTest, NewWindowBasic) {
std::vector<blink::DocumentToken> seen_tokens;
ASSERT_TRUE(NavigateToURL(
web_contents(), embedded_test_server()->GetURL("a.com", "/title1.html")));
EXPECT_EQ(1u, Shell::windows().size());
seen_tokens.push_back(GetBrowserSideToken(web_contents()));
WebContents* new_contents = nullptr;
{
// This block is largely derived from `NavigateAndGetNewToken()`. This test
// cannot easily reuse that helper because:
//
// - it is important to specify an actual target URL other than about:blank
// for `window.open()`. Specifying no target URL and then later navigating
// the window has subtly different behavior (e.g. the
// `NewWindowSyncCommit` test below).
// - the helper expects the `WebContents` to already exist in order to
// install
// `TestNavigationManager`. However, in this test, a new `WebContents` is
// created in the process of running the test.
ExecuteScriptAsync(web_contents(), JsReplace("window.open($1)",
embedded_test_server()->GetURL(
"a.com", "/title1.html")));
ShellAddedObserver wait_for_new_shell;
new_contents = wait_for_new_shell.GetShell()->web_contents();
DCHECK_EQ(2u, Shell::windows().size());
DCHECK_EQ(new_contents, Shell::windows()[1]->web_contents());
DCHECK_NE(new_contents, web_contents());
seen_tokens.push_back(GetBrowserSideToken(new_contents));
TestNavigationManager nav_manager(
new_contents, embedded_test_server()->GetURL("a.com", "/title1.html"));
// Capture the FrameTreeNode now; when a navigation commits, the current
// RenderFrameHost may change.
FrameTreeNode* const frame_tree_node =
static_cast<RenderFrameHostImpl*>(new_contents->GetPrimaryMainFrame())
->frame_tree_node();
const blink::DocumentToken old_token = GetBrowserSideToken(new_contents);
EXPECT_TRUE(VerifyMatchingTokens(new_contents));
EXPECT_EQ(old_token, GetBrowserSideToken(new_contents));
// Even after creating a new window, the original `WebContents` should still
// have the same `DocumentToken`.
EXPECT_EQ(seen_tokens[0], GetBrowserSideToken(web_contents()));
// Just before the request is actually issued, the navigation is still
// ongoing, so `DocumentToken` should not be updated yet.
EXPECT_TRUE(nav_manager.WaitForRequestStart());
EXPECT_TRUE(VerifyMatchingTokens(new_contents));
EXPECT_EQ(old_token, GetBrowserSideToken(new_contents));
// The original `WebContents` should still have the same `DocumentToken`.
EXPECT_EQ(seen_tokens[0], GetBrowserSideToken(web_contents()));
// Just before reading the response, the navigation is still ongoing, so
// `DocumentToken` should not be updated yet.
EXPECT_TRUE(nav_manager.WaitForResponse());
EXPECT_TRUE(VerifyMatchingTokens(new_contents));
EXPECT_EQ(old_token, GetBrowserSideToken(new_contents));
// The original `WebContents` should still have the same `DocumentToken`.
EXPECT_EQ(seen_tokens[0], GetBrowserSideToken(web_contents()));
// Once a cross-document navigation completes, the document token should be
// updated though.
nav_manager.WaitForNavigationFinished();
// The RenderFrameHost may have changed; use the FrameTreeNode captured
// above instead.
EXPECT_EQ(embedded_test_server()->GetURL("a.com", "/title1.html"),
frame_tree_node->current_frame_host()->GetLastCommittedURL());
EXPECT_TRUE(VerifyMatchingTokens(frame_tree_node));
const blink::DocumentToken new_token = GetBrowserSideToken(frame_tree_node);
EXPECT_NE(new_token, old_token);
seen_tokens.push_back(new_token);
// The original `WebContents` should still have the same `DocumentToken`.
EXPECT_EQ(seen_tokens[0], GetBrowserSideToken(web_contents()));
}
seen_tokens.push_back(NavigateAndGetNewToken(
new_contents, embedded_test_server()->GetURL("a.com", "/title1.html")));
// The original `WebContents` should still have the same `DocumentToken`.
EXPECT_EQ(seen_tokens[0], GetBrowserSideToken(web_contents()));
seen_tokens.push_back(NavigateAndGetNewToken(
new_contents, embedded_test_server()->GetURL("b.com", "/title1.html")));
// The original `WebContents` should still have the same `DocumentToken`.
EXPECT_EQ(seen_tokens[0], GetBrowserSideToken(web_contents()));
std::set unique_tokens(seen_tokens.begin(), seen_tokens.end());
EXPECT_EQ(unique_tokens.size(), seen_tokens.size());
}
IN_PROC_BROWSER_TEST_F(DocumentTokenBrowserTest, SubFrameSyncCommit) {
std::vector<blink::DocumentToken> seen_tokens;
// This is a basic test that the synchronous commit of about:blank reuses the
// same DocumentToken. See https://crbug.com/778318 for more details.
ASSERT_TRUE(NavigateToURL(
web_contents(),
embedded_test_server()->GetURL("a.com", "/page_with_blank_iframe.html")));
EXPECT_TRUE(VerifyMatchingTokens(web_contents()));
EXPECT_TRUE(VerifyMatchingTokens(ChildFrameAt(web_contents(), 0)));
seen_tokens.push_back(GetBrowserSideToken(web_contents()));
seen_tokens.push_back(GetBrowserSideToken(ChildFrameAt(web_contents(), 0)));
seen_tokens.push_back(NavigateAndGetNewToken(
ChildFrameAt(web_contents(), 0),
embedded_test_server()->GetURL("a.com", "/title1.html")));
// Main document did not navigate so the token should be the same.
EXPECT_EQ(seen_tokens[0], GetBrowserSideToken(web_contents()));
seen_tokens.push_back(NavigateAndGetNewToken(
ChildFrameAt(web_contents(), 0),
embedded_test_server()->GetURL("b.com", "/title1.html")));
// Main document did not navigate so the token should be the same.
EXPECT_EQ(seen_tokens[0], GetBrowserSideToken(web_contents()));
std::set unique_tokens(seen_tokens.begin(), seen_tokens.end());
EXPECT_EQ(unique_tokens.size(), seen_tokens.size());
}
IN_PROC_BROWSER_TEST_F(DocumentTokenBrowserTest, NewWindowSyncCommit) {
std::vector<blink::DocumentToken> seen_tokens;
ASSERT_TRUE(NavigateToURL(web_contents(), GURL("about:blank")));
EXPECT_EQ(1u, Shell::windows().size());
EXPECT_TRUE(VerifyMatchingTokens(web_contents()));
seen_tokens.push_back(GetBrowserSideToken(web_contents()));
// This is a basic test that the synchronous commit of about:blank reuses the
// same DocumentToken. See https://crbug.com/778318 for more details.
ASSERT_TRUE(ExecJs(web_contents(), "window.open()"));
ASSERT_EQ(2u, Shell::windows().size());
WebContents* new_contents = Shell::windows()[1]->web_contents();
DCHECK_NE(new_contents, web_contents());
EXPECT_TRUE(VerifyMatchingTokens(new_contents));
// The original `WebContents` should still have the same `DocumentToken`.
EXPECT_EQ(seen_tokens[0], GetBrowserSideToken(web_contents()));
seen_tokens.push_back(NavigateAndGetNewToken(
new_contents, embedded_test_server()->GetURL("a.com", "/title1.html")));
// The original `WebContents` should still have the same `DocumentToken`.
EXPECT_EQ(seen_tokens[0], GetBrowserSideToken(web_contents()));
seen_tokens.push_back(NavigateAndGetNewToken(
new_contents, embedded_test_server()->GetURL("a.com", "/title1.html")));
// The original `WebContents` should still have the same `DocumentToken`.
EXPECT_EQ(seen_tokens[0], GetBrowserSideToken(web_contents()));
seen_tokens.push_back(NavigateAndGetNewToken(
new_contents, embedded_test_server()->GetURL("b.com", "/title1.html")));
// The original `WebContents` should still have the same `DocumentToken`.
EXPECT_EQ(seen_tokens[0], GetBrowserSideToken(web_contents()));
std::set unique_tokens(seen_tokens.begin(), seen_tokens.end());
EXPECT_EQ(unique_tokens.size(), seen_tokens.size());
}
IN_PROC_BROWSER_TEST_F(DocumentTokenBrowserTest, JavascriptURL) {
ASSERT_TRUE(NavigateToURL(
web_contents(), embedded_test_server()->GetURL("a.com", "/title1.html")));
EXPECT_TRUE(VerifyMatchingTokens(web_contents()));
const blink::DocumentToken token = GetBrowserSideToken(web_contents());
// A javascript: navigation that replaces the document should not change the
// DocumentToken. This does not use the normal Navigate*() helpers since it
// does not commit a normal cross-document navigation.
ASSERT_TRUE(ExecJs(web_contents(),
JsReplace("location = $1", "javascript:'Hello world!'")));
EXPECT_EQ("Hello world!", EvalJs(web_contents(), "document.body.innerText"));
EXPECT_TRUE(VerifyMatchingTokens(web_contents()));
EXPECT_EQ(token, GetBrowserSideToken(web_contents()));
}
IN_PROC_BROWSER_TEST_F(DocumentTokenBrowserTest, FailedNavigation) {
std::vector<blink::DocumentToken> seen_tokens;
ASSERT_TRUE(NavigateToURL(
web_contents(), embedded_test_server()->GetURL("a.com", "/title1.html")));
EXPECT_TRUE(VerifyMatchingTokens(web_contents()));
seen_tokens.push_back(GetBrowserSideToken(web_contents()));
seen_tokens.push_back(NavigateAndGetNewToken(
web_contents(), embedded_test_server()->GetURL("a.com", "/close-socket"),
ExpectedResponse::kNo));
seen_tokens.push_back(NavigateAndGetNewToken(
web_contents(), embedded_test_server()->GetURL("a.com", "/close-socket"),
ExpectedResponse::kNo));
seen_tokens.push_back(NavigateAndGetNewToken(
web_contents(), embedded_test_server()->GetURL("b.com", "/close-socket"),
ExpectedResponse::kNo));
// Test that a regular successful navigation still updates the document token.
seen_tokens.push_back(NavigateAndGetNewToken(
web_contents(), embedded_test_server()->GetURL("a.com", "/title1.html")));
std::set unique_tokens(seen_tokens.begin(), seen_tokens.end());
EXPECT_EQ(unique_tokens.size(), seen_tokens.size());
}
IN_PROC_BROWSER_TEST_F(DocumentTokenBrowserTest, CrashThenReload) {
ASSERT_TRUE(NavigateToURL(
web_contents(), embedded_test_server()->GetURL("a.com", "/title1.html")));
EXPECT_TRUE(VerifyMatchingTokens(web_contents()));
const blink::DocumentToken token = GetBrowserSideToken(web_contents());
// Cause the renderer to crash.
RenderProcessHostWatcher crash_observer(
web_contents(), RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
EXPECT_FALSE(NavigateToURL(shell(), GURL(blink::kChromeUICrashURL)));
// Wait for browser to notice the renderer crash.
crash_observer.Wait();
// After a crash, the DocumentToken should still be the same even though the
// renderer process is gone..
EXPECT_EQ(token, GetBrowserSideToken(web_contents()));
// But when a live RenderFrame is needed again, RenderDocument should force a
// new RenderFrameHost, and thus, a new DocumentToken. The remainder of this
// test does not use `NavigateAndGetNewToken()`, which tries to use a
// renderer-initiated navigation (which is not possible when the renderer is
// not live).
TestNavigationManager nav_manager(
web_contents(), embedded_test_server()->GetURL("a.com", "/title1.html"));
shell()->LoadURL(embedded_test_server()->GetURL("a.com", "/title1.html"));
EXPECT_TRUE(VerifyMatchingTokens(web_contents()));
const blink::DocumentToken token_after_navigation_started =
GetBrowserSideToken(web_contents());
EXPECT_NE(token_after_navigation_started, token);
const WeakDocumentPtr document_weak_ptr =
web_contents()->GetPrimaryMainFrame()->GetWeakDocumentPtr();
// After the navigation finishes, the RenderFrameHost's DocumentToken will be
// updated (despite DocumentAssociatedData not changing). The latter is
// indirectly tested by checking if the WeakDocumentPtr is still valid after
// the navigation commits.
nav_manager.WaitForNavigationFinished();
EXPECT_TRUE(VerifyMatchingTokens(web_contents()));
const blink::DocumentToken token_after_navigation_finished =
GetBrowserSideToken(web_contents());
EXPECT_NE(token_after_navigation_finished, token);
EXPECT_NE(token_after_navigation_finished, token_after_navigation_started);
EXPECT_NE(document_weak_ptr.AsRenderFrameHostIfValid(), nullptr);
}
IN_PROC_BROWSER_TEST_F(DocumentTokenBrowserTest,
CrashThenImmediateReinitialize) {
ASSERT_TRUE(NavigateToURL(
web_contents(), embedded_test_server()->GetURL("a.com", "/title1.html")));
EXPECT_TRUE(VerifyMatchingTokens(web_contents()));
const blink::DocumentToken token = GetBrowserSideToken(web_contents());
const WeakDocumentPtr document_weak_ptr =
web_contents()->GetPrimaryMainFrame()->GetWeakDocumentPtr();
// Cause the renderer to crash.
RenderProcessHostWatcher crash_observer(
web_contents(), RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
EXPECT_FALSE(NavigateToURL(shell(), GURL(blink::kChromeUICrashURL)));
// Wait for browser to notice the renderer crash.
crash_observer.Wait();
// If the main render frame is re-initialized, it also gets a new
// DocumentAssociatedData. Validate that the new DocumentAssociatedData is
// created before the renderer is re-created; a typical failure in this path
// will manifest as a mismatch between the browser and renderer-side document
// tokens.
web_contents()
->GetPrimaryFrameTree()
.root()
->render_manager()
->InitializeMainRenderFrameForImmediateUse();
EXPECT_TRUE(VerifyMatchingTokens(web_contents()));
// The re-created RenderFrame should have a distinct document token.
const blink::DocumentToken new_token = GetBrowserSideToken(web_contents());
EXPECT_NE(new_token, token);
// The previous DocumentWeakPtr should be invalidated since the
// DocumentAssociatedData was re-created.
EXPECT_FALSE(document_weak_ptr.AsRenderFrameHostIfValid());
}
// TODO(https://crbug.com/1362938): Add tests for bfcache navigations and
// prerender activations.
} // namespace
} // namespace content

@ -38,7 +38,8 @@ class FencedFrameTreeNodeTest : public RenderViewHostImplTestHarness {
TestRenderFrameHost::CreateStubAssociatedInterfaceProviderReceiver(),
blink::mojom::TreeScopeType::kDocument, std::string(), "uniqueName0",
false, blink::LocalFrameToken(), base::UnguessableToken::Create(),
frame_policy, blink::mojom::FrameOwnerProperties(), false, owner_type,
blink::DocumentToken(), frame_policy,
blink::mojom::FrameOwnerProperties(), false, owner_type,
/*is_dummy_frame_for_inner_tree=*/false);
}

@ -332,6 +332,7 @@ FrameTreeNode* FrameTree::AddFrame(
bool is_created_by_script,
const blink::LocalFrameToken& frame_token,
const base::UnguessableToken& devtools_frame_token,
const blink::DocumentToken& document_token,
const blink::FramePolicy& frame_policy,
const blink::mojom::FrameOwnerProperties& frame_owner_properties,
bool was_discarded,
@ -376,7 +377,7 @@ FrameTreeNode* FrameTree::AddFrame(
// Add the new node to the FrameTree, creating the RenderFrameHost.
FrameTreeNode* added_node = parent->AddChild(
std::move(new_node), new_routing_id, std::move(frame_remote), frame_token,
frame_policy, frame_name, frame_unique_name);
document_token, frame_policy, frame_name, frame_unique_name);
added_node->SetFencedFrameNonceIfNeeded();

@ -339,6 +339,7 @@ class CONTENT_EXPORT FrameTree {
bool is_created_by_script,
const blink::LocalFrameToken& frame_token,
const base::UnguessableToken& devtools_frame_token,
const blink::DocumentToken& document_token,
const blink::FramePolicy& frame_policy,
const blink::mojom::FrameOwnerProperties& frame_owner_properties,
bool was_discarded,

@ -182,8 +182,8 @@ TEST_F(FrameTreeTest, FrameNodeQueue) {
CreateStubAssociatedInterfaceProviderReceiver(),
blink::mojom::TreeScopeType::kDocument, std::string(), "uniqueName0",
false, blink::LocalFrameToken(), base::UnguessableToken::Create(),
blink::FramePolicy(), blink::mojom::FrameOwnerProperties(), false,
kOwnerType, false);
blink::DocumentToken(), blink::FramePolicy(),
blink::mojom::FrameOwnerProperties(), false, kOwnerType, false);
frame_tree.AddFrame(
root->current_frame_host(), process_id, 15, CreateStubFrameRemote(),
CreateStubBrowserInterfaceBrokerReceiver(),
@ -191,8 +191,8 @@ TEST_F(FrameTreeTest, FrameNodeQueue) {
CreateStubAssociatedInterfaceProviderReceiver(),
blink::mojom::TreeScopeType::kDocument, std::string(), "uniqueName1",
false, blink::LocalFrameToken(), base::UnguessableToken::Create(),
blink::FramePolicy(), blink::mojom::FrameOwnerProperties(), false,
kOwnerType, false);
blink::DocumentToken(), blink::FramePolicy(),
blink::mojom::FrameOwnerProperties(), false, kOwnerType, false);
frame_tree.AddFrame(
root->current_frame_host(), process_id, 16, CreateStubFrameRemote(),
CreateStubBrowserInterfaceBrokerReceiver(),
@ -200,8 +200,8 @@ TEST_F(FrameTreeTest, FrameNodeQueue) {
CreateStubAssociatedInterfaceProviderReceiver(),
blink::mojom::TreeScopeType::kDocument, std::string(), "uniqueName2",
false, blink::LocalFrameToken(), base::UnguessableToken::Create(),
blink::FramePolicy(), blink::mojom::FrameOwnerProperties(), false,
kOwnerType, false);
blink::DocumentToken(), blink::FramePolicy(),
blink::mojom::FrameOwnerProperties(), false, kOwnerType, false);
EXPECT_EQ(3U, root->child_count());
FrameTree::NodeIterator node_iterator = frame_tree.Nodes().begin();
@ -248,8 +248,8 @@ TEST_F(FrameTreeTest, Shape) {
CreateStubAssociatedInterfaceProviderReceiver(),
blink::mojom::TreeScopeType::kDocument, std::string(), "uniqueName0",
false, blink::LocalFrameToken(), base::UnguessableToken::Create(),
blink::FramePolicy(), blink::mojom::FrameOwnerProperties(), false,
kOwnerType, false);
blink::DocumentToken(), blink::FramePolicy(),
blink::mojom::FrameOwnerProperties(), false, kOwnerType, false);
frame_tree.AddFrame(
root->current_frame_host(), process_id, 15, CreateStubFrameRemote(),
CreateStubBrowserInterfaceBrokerReceiver(),
@ -257,8 +257,8 @@ TEST_F(FrameTreeTest, Shape) {
CreateStubAssociatedInterfaceProviderReceiver(),
blink::mojom::TreeScopeType::kDocument, std::string(), "uniqueName1",
false, blink::LocalFrameToken(), base::UnguessableToken::Create(),
blink::FramePolicy(), blink::mojom::FrameOwnerProperties(), false,
kOwnerType, false);
blink::DocumentToken(), blink::FramePolicy(),
blink::mojom::FrameOwnerProperties(), false, kOwnerType, false);
frame_tree.AddFrame(
root->current_frame_host(), process_id, 16, CreateStubFrameRemote(),
CreateStubBrowserInterfaceBrokerReceiver(),
@ -266,8 +266,8 @@ TEST_F(FrameTreeTest, Shape) {
CreateStubAssociatedInterfaceProviderReceiver(),
blink::mojom::TreeScopeType::kDocument, std::string(), "uniqueName2",
false, blink::LocalFrameToken(), base::UnguessableToken::Create(),
blink::FramePolicy(), blink::mojom::FrameOwnerProperties(), false,
kOwnerType, false);
blink::DocumentToken(), blink::FramePolicy(),
blink::mojom::FrameOwnerProperties(), false, kOwnerType, false);
frame_tree.AddFrame(
root->child_at(0)->current_frame_host(), process_id, 244,
CreateStubFrameRemote(), CreateStubBrowserInterfaceBrokerReceiver(),
@ -275,8 +275,8 @@ TEST_F(FrameTreeTest, Shape) {
CreateStubAssociatedInterfaceProviderReceiver(),
blink::mojom::TreeScopeType::kDocument, std::string(), "uniqueName3",
false, blink::LocalFrameToken(), base::UnguessableToken::Create(),
blink::FramePolicy(), blink::mojom::FrameOwnerProperties(), false,
kOwnerType, false);
blink::DocumentToken(), blink::FramePolicy(),
blink::mojom::FrameOwnerProperties(), false, kOwnerType, false);
frame_tree.AddFrame(
root->child_at(1)->current_frame_host(), process_id, 255,
CreateStubFrameRemote(), CreateStubBrowserInterfaceBrokerReceiver(),
@ -284,8 +284,8 @@ TEST_F(FrameTreeTest, Shape) {
CreateStubAssociatedInterfaceProviderReceiver(),
blink::mojom::TreeScopeType::kDocument, no_children_node, "uniqueName4",
false, blink::LocalFrameToken(), base::UnguessableToken::Create(),
blink::FramePolicy(), blink::mojom::FrameOwnerProperties(), false,
kOwnerType, false);
blink::DocumentToken(), blink::FramePolicy(),
blink::mojom::FrameOwnerProperties(), false, kOwnerType, false);
frame_tree.AddFrame(
root->child_at(0)->current_frame_host(), process_id, 245,
CreateStubFrameRemote(), CreateStubBrowserInterfaceBrokerReceiver(),
@ -293,8 +293,8 @@ TEST_F(FrameTreeTest, Shape) {
CreateStubAssociatedInterfaceProviderReceiver(),
blink::mojom::TreeScopeType::kDocument, std::string(), "uniqueName5",
false, blink::LocalFrameToken(), base::UnguessableToken::Create(),
blink::FramePolicy(), blink::mojom::FrameOwnerProperties(), false,
kOwnerType, false);
blink::DocumentToken(), blink::FramePolicy(),
blink::mojom::FrameOwnerProperties(), false, kOwnerType, false);
EXPECT_EQ(
"1: [14: [244: [], 245: []], "
@ -310,8 +310,8 @@ TEST_F(FrameTreeTest, Shape) {
CreateStubAssociatedInterfaceProviderReceiver(),
blink::mojom::TreeScopeType::kDocument, std::string(), "uniqueName6",
false, blink::LocalFrameToken(), base::UnguessableToken::Create(),
blink::FramePolicy(), blink::mojom::FrameOwnerProperties(), false,
kOwnerType, false);
blink::DocumentToken(), blink::FramePolicy(),
blink::mojom::FrameOwnerProperties(), false, kOwnerType, false);
frame_tree.AddFrame(
child_16->current_frame_host(), process_id, 265, CreateStubFrameRemote(),
CreateStubBrowserInterfaceBrokerReceiver(),
@ -319,8 +319,8 @@ TEST_F(FrameTreeTest, Shape) {
CreateStubAssociatedInterfaceProviderReceiver(),
blink::mojom::TreeScopeType::kDocument, std::string(), "uniqueName7",
false, blink::LocalFrameToken(), base::UnguessableToken::Create(),
blink::FramePolicy(), blink::mojom::FrameOwnerProperties(), false,
kOwnerType, false);
blink::DocumentToken(), blink::FramePolicy(),
blink::mojom::FrameOwnerProperties(), false, kOwnerType, false);
frame_tree.AddFrame(
child_16->current_frame_host(), process_id, 266, CreateStubFrameRemote(),
CreateStubBrowserInterfaceBrokerReceiver(),
@ -328,8 +328,8 @@ TEST_F(FrameTreeTest, Shape) {
CreateStubAssociatedInterfaceProviderReceiver(),
blink::mojom::TreeScopeType::kDocument, std::string(), "uniqueName8",
false, blink::LocalFrameToken(), base::UnguessableToken::Create(),
blink::FramePolicy(), blink::mojom::FrameOwnerProperties(), false,
kOwnerType, false);
blink::DocumentToken(), blink::FramePolicy(),
blink::mojom::FrameOwnerProperties(), false, kOwnerType, false);
frame_tree.AddFrame(
child_16->current_frame_host(), process_id, 267, CreateStubFrameRemote(),
CreateStubBrowserInterfaceBrokerReceiver(),
@ -337,8 +337,8 @@ TEST_F(FrameTreeTest, Shape) {
CreateStubAssociatedInterfaceProviderReceiver(),
blink::mojom::TreeScopeType::kDocument, deep_subtree, "uniqueName9",
false, blink::LocalFrameToken(), base::UnguessableToken::Create(),
blink::FramePolicy(), blink::mojom::FrameOwnerProperties(), false,
kOwnerType, false);
blink::DocumentToken(), blink::FramePolicy(),
blink::mojom::FrameOwnerProperties(), false, kOwnerType, false);
frame_tree.AddFrame(
child_16->current_frame_host(), process_id, 268, CreateStubFrameRemote(),
CreateStubBrowserInterfaceBrokerReceiver(),
@ -346,8 +346,8 @@ TEST_F(FrameTreeTest, Shape) {
CreateStubAssociatedInterfaceProviderReceiver(),
blink::mojom::TreeScopeType::kDocument, std::string(), "uniqueName10",
false, blink::LocalFrameToken(), base::UnguessableToken::Create(),
blink::FramePolicy(), blink::mojom::FrameOwnerProperties(), false,
kOwnerType, false);
blink::DocumentToken(), blink::FramePolicy(),
blink::mojom::FrameOwnerProperties(), false, kOwnerType, false);
FrameTreeNode* child_267 = child_16->child_at(3);
frame_tree.AddFrame(
@ -357,8 +357,8 @@ TEST_F(FrameTreeTest, Shape) {
CreateStubAssociatedInterfaceProviderReceiver(),
blink::mojom::TreeScopeType::kDocument, std::string(), "uniqueName11",
false, blink::LocalFrameToken(), base::UnguessableToken::Create(),
blink::FramePolicy(), blink::mojom::FrameOwnerProperties(), false,
kOwnerType, false);
blink::DocumentToken(), blink::FramePolicy(),
blink::mojom::FrameOwnerProperties(), false, kOwnerType, false);
frame_tree.AddFrame(
child_267->child_at(0)->current_frame_host(), process_id, 455,
CreateStubFrameRemote(), CreateStubBrowserInterfaceBrokerReceiver(),
@ -366,8 +366,8 @@ TEST_F(FrameTreeTest, Shape) {
CreateStubAssociatedInterfaceProviderReceiver(),
blink::mojom::TreeScopeType::kDocument, std::string(), "uniqueName12",
false, blink::LocalFrameToken(), base::UnguessableToken::Create(),
blink::FramePolicy(), blink::mojom::FrameOwnerProperties(), false,
kOwnerType, false);
blink::DocumentToken(), blink::FramePolicy(),
blink::mojom::FrameOwnerProperties(), false, kOwnerType, false);
frame_tree.AddFrame(
child_267->child_at(0)->child_at(0)->current_frame_host(), process_id,
555, CreateStubFrameRemote(), CreateStubBrowserInterfaceBrokerReceiver(),
@ -375,8 +375,8 @@ TEST_F(FrameTreeTest, Shape) {
CreateStubAssociatedInterfaceProviderReceiver(),
blink::mojom::TreeScopeType::kDocument, std::string(), "uniqueName13",
false, blink::LocalFrameToken(), base::UnguessableToken::Create(),
blink::FramePolicy(), blink::mojom::FrameOwnerProperties(), false,
kOwnerType, false);
blink::DocumentToken(), blink::FramePolicy(),
blink::mojom::FrameOwnerProperties(), false, kOwnerType, false);
frame_tree.AddFrame(
child_267->child_at(0)->child_at(0)->child_at(0)->current_frame_host(),
process_id, 655, CreateStubFrameRemote(),
@ -385,8 +385,8 @@ TEST_F(FrameTreeTest, Shape) {
CreateStubAssociatedInterfaceProviderReceiver(),
blink::mojom::TreeScopeType::kDocument, std::string(), "uniqueName14",
false, blink::LocalFrameToken(), base::UnguessableToken::Create(),
blink::FramePolicy(), blink::mojom::FrameOwnerProperties(), false,
kOwnerType, false);
blink::DocumentToken(), blink::FramePolicy(),
blink::mojom::FrameOwnerProperties(), false, kOwnerType, false);
// Now that's it's fully built, verify the tree structure is as expected.
EXPECT_EQ(
@ -464,21 +464,24 @@ TEST_F(FrameTreeTest, FindFrames) {
CreateStubAssociatedInterfaceProviderReceiver(),
blink::mojom::TreeScopeType::kDocument, "child0", "uniqueName0", false,
blink::LocalFrameToken(), base::UnguessableToken::Create(),
blink::FramePolicy(), blink::mojom::FrameOwnerProperties(), kOwnerType);
blink::DocumentToken(), blink::FramePolicy(),
blink::mojom::FrameOwnerProperties(), kOwnerType);
main_test_rfh()->OnCreateChildFrame(
23, CreateStubFrameRemote(), CreateStubBrowserInterfaceBrokerReceiver(),
CreateStubPolicyContainerBindParams(),
CreateStubAssociatedInterfaceProviderReceiver(),
blink::mojom::TreeScopeType::kDocument, "child1", "uniqueName1", false,
blink::LocalFrameToken(), base::UnguessableToken::Create(),
blink::FramePolicy(), blink::mojom::FrameOwnerProperties(), kOwnerType);
blink::DocumentToken(), blink::FramePolicy(),
blink::mojom::FrameOwnerProperties(), kOwnerType);
main_test_rfh()->OnCreateChildFrame(
24, CreateStubFrameRemote(), CreateStubBrowserInterfaceBrokerReceiver(),
CreateStubPolicyContainerBindParams(),
CreateStubAssociatedInterfaceProviderReceiver(),
blink::mojom::TreeScopeType::kDocument, std::string(), "uniqueName2",
false, blink::LocalFrameToken(), base::UnguessableToken::Create(),
blink::FramePolicy(), blink::mojom::FrameOwnerProperties(), kOwnerType);
blink::DocumentToken(), blink::FramePolicy(),
blink::mojom::FrameOwnerProperties(), kOwnerType);
FrameTreeNode* child0 = root->child_at(0);
FrameTreeNode* child1 = root->child_at(1);
FrameTreeNode* child2 = root->child_at(2);
@ -490,7 +493,8 @@ TEST_F(FrameTreeTest, FindFrames) {
CreateStubAssociatedInterfaceProviderReceiver(),
blink::mojom::TreeScopeType::kDocument, "grandchild", "uniqueName3",
false, blink::LocalFrameToken(), base::UnguessableToken::Create(),
blink::FramePolicy(), blink::mojom::FrameOwnerProperties(), kOwnerType);
blink::DocumentToken(), blink::FramePolicy(),
blink::mojom::FrameOwnerProperties(), kOwnerType);
FrameTreeNode* grandchild = child1->child_at(0);
// Ensure they can be found by FTN id.
@ -533,21 +537,24 @@ TEST_F(FrameTreeTest, GetSibling) {
CreateStubAssociatedInterfaceProviderReceiver(),
blink::mojom::TreeScopeType::kDocument, "child0", "uniqueName0", false,
blink::LocalFrameToken(), base::UnguessableToken::Create(),
blink::FramePolicy(), blink::mojom::FrameOwnerProperties(), kOwnerType);
blink::DocumentToken(), blink::FramePolicy(),
blink::mojom::FrameOwnerProperties(), kOwnerType);
main_test_rfh()->OnCreateChildFrame(
23, CreateStubFrameRemote(), CreateStubBrowserInterfaceBrokerReceiver(),
CreateStubPolicyContainerBindParams(),
CreateStubAssociatedInterfaceProviderReceiver(),
blink::mojom::TreeScopeType::kDocument, "child1", "uniqueName1", false,
blink::LocalFrameToken(), base::UnguessableToken::Create(),
blink::FramePolicy(), blink::mojom::FrameOwnerProperties(), kOwnerType);
blink::DocumentToken(), blink::FramePolicy(),
blink::mojom::FrameOwnerProperties(), kOwnerType);
main_test_rfh()->OnCreateChildFrame(
24, CreateStubFrameRemote(), CreateStubBrowserInterfaceBrokerReceiver(),
CreateStubPolicyContainerBindParams(),
CreateStubAssociatedInterfaceProviderReceiver(),
blink::mojom::TreeScopeType::kDocument, "child2", "uniqueName2", false,
blink::LocalFrameToken(), base::UnguessableToken::Create(),
blink::FramePolicy(), blink::mojom::FrameOwnerProperties(), kOwnerType);
blink::DocumentToken(), blink::FramePolicy(),
blink::mojom::FrameOwnerProperties(), kOwnerType);
FrameTreeNode* child0 = root->child_at(0);
FrameTreeNode* child1 = root->child_at(1);
FrameTreeNode* child2 = root->child_at(2);
@ -559,7 +566,8 @@ TEST_F(FrameTreeTest, GetSibling) {
CreateStubAssociatedInterfaceProviderReceiver(),
blink::mojom::TreeScopeType::kDocument, "grandchild", "uniqueName3",
false, blink::LocalFrameToken(), base::UnguessableToken::Create(),
blink::FramePolicy(), blink::mojom::FrameOwnerProperties(), kOwnerType);
blink::DocumentToken(), blink::FramePolicy(),
blink::mojom::FrameOwnerProperties(), kOwnerType);
FrameTreeNode* grandchild = child1->child_at(0);
// Test PreviousSibling().
@ -595,7 +603,8 @@ TEST_F(FrameTreeTest, ObserverWalksTreeDuringFrameCreation) {
CreateStubAssociatedInterfaceProviderReceiver(),
blink::mojom::TreeScopeType::kDocument, std::string(), "uniqueName0",
false, blink::LocalFrameToken(), base::UnguessableToken::Create(),
blink::FramePolicy(), blink::mojom::FrameOwnerProperties(), kOwnerType);
blink::DocumentToken(), blink::FramePolicy(),
blink::mojom::FrameOwnerProperties(), kOwnerType);
EXPECT_EQ(
"RenderFrameCreated(14) -> 1: [14: []]\n"
"RenderFrameHostChanged(new)(14) -> 1: [14: []]",
@ -606,7 +615,8 @@ TEST_F(FrameTreeTest, ObserverWalksTreeDuringFrameCreation) {
CreateStubAssociatedInterfaceProviderReceiver(),
blink::mojom::TreeScopeType::kDocument, std::string(), "uniqueName1",
false, blink::LocalFrameToken(), base::UnguessableToken::Create(),
blink::FramePolicy(), blink::mojom::FrameOwnerProperties(), kOwnerType);
blink::DocumentToken(), blink::FramePolicy(),
blink::mojom::FrameOwnerProperties(), kOwnerType);
EXPECT_EQ(
"RenderFrameCreated(18) -> 1: [14: [], 18: []]\n"
"RenderFrameHostChanged(new)(18) -> 1: [14: [], 18: []]",
@ -631,7 +641,8 @@ TEST_F(FrameTreeTest, ObserverWalksTreeAfterCrash) {
CreateStubAssociatedInterfaceProviderReceiver(),
blink::mojom::TreeScopeType::kDocument, std::string(), "uniqueName0",
false, blink::LocalFrameToken(), base::UnguessableToken::Create(),
blink::FramePolicy(), blink::mojom::FrameOwnerProperties(), kOwnerType);
blink::DocumentToken(), blink::FramePolicy(),
blink::mojom::FrameOwnerProperties(), kOwnerType);
EXPECT_EQ(
"RenderFrameCreated(22) -> 1: [22: []]\n"
"RenderFrameHostChanged(new)(22) -> 1: [22: []]",
@ -642,7 +653,8 @@ TEST_F(FrameTreeTest, ObserverWalksTreeAfterCrash) {
CreateStubAssociatedInterfaceProviderReceiver(),
blink::mojom::TreeScopeType::kDocument, std::string(), "uniqueName1",
false, blink::LocalFrameToken(), base::UnguessableToken::Create(),
blink::FramePolicy(), blink::mojom::FrameOwnerProperties(), kOwnerType);
blink::DocumentToken(), blink::FramePolicy(),
blink::mojom::FrameOwnerProperties(), kOwnerType);
EXPECT_EQ(
"RenderFrameCreated(23) -> 1: [22: [], 23: []]\n"
"RenderFrameHostChanged(new)(23) -> 1: [22: [], 23: []]",
@ -677,7 +689,8 @@ TEST_F(FrameTreeTest, FailAddFrameWithWrongProcessId) {
CreateStubAssociatedInterfaceProviderReceiver(),
blink::mojom::TreeScopeType::kDocument, std::string(), "uniqueName0",
false, blink::LocalFrameToken(), base::UnguessableToken::Create(),
blink::FramePolicy(), blink::mojom::FrameOwnerProperties(), false,
blink::DocumentToken(), blink::FramePolicy(),
blink::mojom::FrameOwnerProperties(), false,
blink::FrameOwnerElementType::kIframe, false),
"");
ASSERT_EQ("1: []", GetTreeState(frame_tree));
@ -698,14 +711,16 @@ TEST_F(FrameTreeTest, ProcessCrashClearsGlobalMap) {
CreateStubAssociatedInterfaceProviderReceiver(),
blink::mojom::TreeScopeType::kDocument, std::string(), "uniqueName0",
false, blink::LocalFrameToken(), base::UnguessableToken::Create(),
blink::FramePolicy(), blink::mojom::FrameOwnerProperties(), kOwnerType);
blink::DocumentToken(), blink::FramePolicy(),
blink::mojom::FrameOwnerProperties(), kOwnerType);
main_test_rfh()->OnCreateChildFrame(
23, CreateStubFrameRemote(), CreateStubBrowserInterfaceBrokerReceiver(),
CreateStubPolicyContainerBindParams(),
CreateStubAssociatedInterfaceProviderReceiver(),
blink::mojom::TreeScopeType::kDocument, std::string(), "uniqueName1",
false, blink::LocalFrameToken(), base::UnguessableToken::Create(),
blink::FramePolicy(), blink::mojom::FrameOwnerProperties(), kOwnerType);
blink::DocumentToken(), blink::FramePolicy(),
blink::mojom::FrameOwnerProperties(), kOwnerType);
// Add one grandchild frame.
RenderFrameHostImpl* child1_rfh = root->child_at(0)->current_frame_host();
@ -715,7 +730,8 @@ TEST_F(FrameTreeTest, ProcessCrashClearsGlobalMap) {
CreateStubAssociatedInterfaceProviderReceiver(),
blink::mojom::TreeScopeType::kDocument, std::string(), "uniqueName2",
false, blink::LocalFrameToken(), base::UnguessableToken::Create(),
blink::FramePolicy(), blink::mojom::FrameOwnerProperties(), kOwnerType);
blink::DocumentToken(), blink::FramePolicy(),
blink::mojom::FrameOwnerProperties(), kOwnerType);
// Ensure they can be found by id.
int id1 = root->child_at(0)->frame_tree_node_id();

@ -1915,7 +1915,8 @@ TEST_F(NavigationControllerTest, AutoSubframe) {
TestRenderFrameHost::CreateStubAssociatedInterfaceProviderReceiver(),
blink::mojom::TreeScopeType::kDocument, std::string(), unique_name0,
false, blink::LocalFrameToken(), base::UnguessableToken::Create(),
blink::FramePolicy(), blink::mojom::FrameOwnerProperties(), kOwnerType);
blink::DocumentToken(), blink::FramePolicy(),
blink::mojom::FrameOwnerProperties(), kOwnerType);
TestRenderFrameHost* subframe =
static_cast<TestRenderFrameHost*>(contents()
->GetPrimaryFrameTree()
@ -1959,7 +1960,8 @@ TEST_F(NavigationControllerTest, AutoSubframe) {
TestRenderFrameHost::CreateStubAssociatedInterfaceProviderReceiver(),
blink::mojom::TreeScopeType::kDocument, std::string(), unique_name1,
false, blink::LocalFrameToken(), base::UnguessableToken::Create(),
blink::FramePolicy(), blink::mojom::FrameOwnerProperties(), kOwnerType);
blink::DocumentToken(), blink::FramePolicy(),
blink::mojom::FrameOwnerProperties(), kOwnerType);
TestRenderFrameHost* subframe2 =
static_cast<TestRenderFrameHost*>(contents()
->GetPrimaryFrameTree()
@ -2003,7 +2005,8 @@ TEST_F(NavigationControllerTest, AutoSubframe) {
TestRenderFrameHost::CreateStubAssociatedInterfaceProviderReceiver(),
blink::mojom::TreeScopeType::kDocument, std::string(), unique_name2,
false, blink::LocalFrameToken(), base::UnguessableToken::Create(),
blink::FramePolicy(), blink::mojom::FrameOwnerProperties(), kOwnerType);
blink::DocumentToken(), blink::FramePolicy(),
blink::mojom::FrameOwnerProperties(), kOwnerType);
TestRenderFrameHost* subframe3 =
static_cast<TestRenderFrameHost*>(contents()
->GetPrimaryFrameTree()
@ -2061,7 +2064,8 @@ TEST_F(NavigationControllerTest, BackSubframe) {
TestRenderFrameHost::CreateStubAssociatedInterfaceProviderReceiver(),
blink::mojom::TreeScopeType::kDocument, std::string(), unique_name, false,
blink::LocalFrameToken(), base::UnguessableToken::Create(),
blink::FramePolicy(), blink::mojom::FrameOwnerProperties(),
blink::DocumentToken(), blink::FramePolicy(),
blink::mojom::FrameOwnerProperties(),
blink::FrameOwnerElementType::kIframe);
FrameTreeNode* subframe =
contents()->GetPrimaryFrameTree().root()->child_at(0);
@ -2895,7 +2899,8 @@ TEST_F(NavigationControllerTest, SameSubframe) {
TestRenderFrameHost::CreateStubAssociatedInterfaceProviderReceiver(),
blink::mojom::TreeScopeType::kDocument, std::string(), unique_name, false,
blink::LocalFrameToken(), base::UnguessableToken::Create(),
blink::FramePolicy(), blink::mojom::FrameOwnerProperties(),
blink::DocumentToken(), blink::FramePolicy(),
blink::mojom::FrameOwnerProperties(),
blink::FrameOwnerElementType::kIframe);
TestRenderFrameHost* subframe =
static_cast<TestRenderFrameHost*>(contents()
@ -3053,7 +3058,8 @@ TEST_F(NavigationControllerTest, SubframeWhilePending) {
TestRenderFrameHost::CreateStubAssociatedInterfaceProviderReceiver(),
blink::mojom::TreeScopeType::kDocument, std::string(), unique_name, false,
blink::LocalFrameToken(), base::UnguessableToken::Create(),
blink::FramePolicy(), blink::mojom::FrameOwnerProperties(),
blink::DocumentToken(), blink::FramePolicy(),
blink::mojom::FrameOwnerProperties(),
blink::FrameOwnerElementType::kIframe);
TestRenderFrameHost* subframe =
static_cast<TestRenderFrameHost*>(contents()
@ -4247,7 +4253,8 @@ TEST_F(NavigationControllerTest, SubFrameNavigationUIData) {
TestRenderFrameHost::CreateStubAssociatedInterfaceProviderReceiver(),
blink::mojom::TreeScopeType::kDocument, std::string(), unique_name, false,
blink::LocalFrameToken(), base::UnguessableToken::Create(),
blink::FramePolicy(), blink::mojom::FrameOwnerProperties(),
blink::DocumentToken(), blink::FramePolicy(),
blink::mojom::FrameOwnerProperties(),
blink::FrameOwnerElementType::kIframe);
TestRenderFrameHost* subframe =
static_cast<TestRenderFrameHost*>(contents()

@ -2651,6 +2651,13 @@ NavigationRequest::GetInitiatorPolicyContainerPolicies() const {
return policy_container_builder_->InitiatorPolicies();
}
const blink::DocumentToken& NavigationRequest::GetDocumentToken() const {
DCHECK(!IsSameDocument());
DCHECK_GE(state_, READY_TO_COMMIT);
return *document_token_;
}
const PolicyContainerPolicies& NavigationRequest::GetPolicyContainerPolicies()
const {
DCHECK_GE(state_, READY_TO_COMMIT);
@ -4843,9 +4850,10 @@ void NavigationRequest::CommitErrorPage(
// Use a separate cache shard, and no cookies, for error pages.
isolation_info_for_subresources_ = net::IsolationInfo::CreateTransient();
render_frame_host_->FailedNavigation(
this, *common_params_, *commit_params_, has_stale_copy_in_cache_,
net_error_, extended_error_code_, error_page_content);
render_frame_host_->FailedNavigation(this, *common_params_, *commit_params_,
has_stale_copy_in_cache_, net_error_,
extended_error_code_, error_page_content,
document_token_.emplace());
SendDeferredConsoleMessages();
}
@ -5057,8 +5065,8 @@ void NavigationRequest::CommitNavigation() {
std::move(response_head), std::move(response_body_),
std::move(url_loader_client_endpoints_),
std::move(subresource_loader_params_), std::move(subresource_overrides_),
std::move(service_worker_container_info), devtools_navigation_token_,
std::move(web_bundle_handle_));
std::move(service_worker_container_info), document_token_.emplace(),
devtools_navigation_token_, std::move(web_bundle_handle_));
UpdateNavigationHandleTimingsOnCommitSent();
// Give SpareRenderProcessHostManager a heads-up about the most recently used
@ -5775,7 +5783,7 @@ void NavigationRequest::IgnoreCommitInterfaceDisconnection() {
return commit_navigation_client_.set_disconnect_handler(base::DoNothing());
}
bool NavigationRequest::IsSameDocument() {
bool NavigationRequest::IsSameDocument() const {
return NavigationTypeUtils::IsSameDocument(common_params_->navigation_type);
}

@ -326,7 +326,7 @@ class CONTENT_EXPORT NavigationRequest
bool IsExternalProtocol() override;
net::Error GetNetErrorCode() override;
RenderFrameHostImpl* GetRenderFrameHost() const override;
bool IsSameDocument() override;
bool IsSameDocument() const override;
bool HasCommitted() const override;
bool IsErrorPage() const override;
bool HasSubframeNavigationEntryCommitted() override;
@ -727,6 +727,12 @@ class CONTENT_EXPORT NavigationRequest
// Returns nullptr if this navigation had no initiator.
const PolicyContainerPolicies* GetInitiatorPolicyContainerPolicies() const;
// The DocumentToken that should be used for the document created as a result
// of committing this navigation.
// - must only be called for cross-document navigations
// - must not be called before the navigation is ready to commit
const blink::DocumentToken& GetDocumentToken() const;
// Returns the policies of the new document being navigated to.
//
// Must only be called after ReadyToCommitNavigation().
@ -1723,6 +1729,13 @@ class CONTENT_EXPORT NavigationRequest
// SignedExchangeSubresourcePrefetch.
absl::optional<SubresourceLoaderParams> subresource_loader_params_;
// DocumentToken to use for the newly-committed document in a cross-document
// navigation. Currently set immediately before sending CommitNavigation to
// the renderer. In the future, this may be populated earlier to allow lookup
// of a navigation request by the document that it may create, similar to how
// `NavigationOrDocumentHandle` behaves.
absl::optional<blink::DocumentToken> document_token_;
// See comment on accessor.
const base::UnguessableToken devtools_navigation_token_ =
base::UnguessableToken::Create();

@ -237,7 +237,8 @@ class NavigationRequestTest : public RenderViewHostImplTestHarness {
TestRenderFrameHost::CreateStubAssociatedInterfaceProviderReceiver(),
blink::mojom::TreeScopeType::kDocument, std::string(), "uniqueName0",
false, blink::LocalFrameToken(), base::UnguessableToken::Create(),
frame_policy, blink::mojom::FrameOwnerProperties(), false, owner_type,
blink::DocumentToken(), frame_policy,
blink::mojom::FrameOwnerProperties(), false, owner_type,
/*is_dummy_frame_for_inner_tree=*/false);
}

@ -24,6 +24,7 @@ std::unique_ptr<RenderFrameHostImpl> RenderFrameHostFactory::Create(
int32_t routing_id,
mojo::PendingAssociatedRemote<mojom::Frame> frame_remote,
const blink::LocalFrameToken& frame_token,
const blink::DocumentToken& document_token,
bool renderer_initiated_creation,
RenderFrameHostImpl::LifecycleStateImpl lifecycle_state,
scoped_refptr<BrowsingContextState> browsing_context_state) {
@ -31,13 +32,13 @@ std::unique_ptr<RenderFrameHostImpl> RenderFrameHostFactory::Create(
return factory_->CreateRenderFrameHost(
site_instance, std::move(render_view_host), delegate, frame_tree,
frame_tree_node, routing_id, std::move(frame_remote), frame_token,
renderer_initiated_creation, lifecycle_state,
document_token, renderer_initiated_creation, lifecycle_state,
std::move(browsing_context_state));
}
return base::WrapUnique(new RenderFrameHostImpl(
site_instance, std::move(render_view_host), delegate, frame_tree,
frame_tree_node, routing_id, std::move(frame_remote), frame_token,
renderer_initiated_creation, lifecycle_state,
document_token, renderer_initiated_creation, lifecycle_state,
std::move(browsing_context_state),
frame_tree_node->frame_owner_element_type()));
}

@ -39,6 +39,7 @@ class CONTENT_EXPORT RenderFrameHostFactory {
int32_t routing_id,
mojo::PendingAssociatedRemote<mojom::Frame> frame_remote,
const blink::LocalFrameToken& frame_token,
const blink::DocumentToken& document_token,
bool renderer_initiated_creation,
RenderFrameHostImpl::LifecycleStateImpl lifecycle_state,
scoped_refptr<BrowsingContextState> browsing_context_state);
@ -64,6 +65,7 @@ class CONTENT_EXPORT RenderFrameHostFactory {
int32_t routing_id,
mojo::PendingAssociatedRemote<mojom::Frame> frame_remote,
const blink::LocalFrameToken& frame_token,
const blink::DocumentToken& document_token,
bool renderer_initiated_creation,
RenderFrameHostImpl::LifecycleStateImpl lifecycle_state,
scoped_refptr<BrowsingContextState> browsing_context_state) = 0;

@ -1608,6 +1608,7 @@ RenderFrameHostImpl::RenderFrameHostImpl(
int32_t routing_id,
mojo::PendingAssociatedRemote<mojom::Frame> frame_remote,
const blink::LocalFrameToken& frame_token,
const blink::DocumentToken& document_token,
bool renderer_initiated_creation_of_main_frame,
LifecycleStateImpl lifecycle_state,
scoped_refptr<BrowsingContextState> browsing_context_state,
@ -1635,7 +1636,7 @@ RenderFrameHostImpl::RenderFrameHostImpl(
subframe_unload_timeout_(RenderViewHostImpl::kUnloadTimeout),
media_device_id_salt_base_(
BrowserContext::CreateRandomMediaDeviceIDSalt()),
document_associated_data_(absl::in_place, *this),
document_associated_data_(absl::in_place, *this, document_token),
lifecycle_state_(lifecycle_state),
inner_tree_main_frame_tree_node_id_(
FrameTreeNode::kFrameTreeNodeInvalidId),
@ -3277,11 +3278,12 @@ bool RenderFrameHostImpl::CreateRenderFrame(
params->tree_scope_type = frame_tree_node()->tree_scope_type();
params->replication_state =
browsing_context_state_->current_replication_state().Clone();
params->token = frame_token_;
params->frame_token = frame_token_;
params->devtools_frame_token = frame_tree_node()->devtools_frame_token();
BindAssociatedInterfaceProviderReceiver(
params->associated_interface_provider_remote
.InitWithNewEndpointAndPassReceiver());
params->document_token = document_associated_data_->token;
// If this is a new RenderFrameHost for a frame that has already committed a
// document, we don't have a policy container yet. Indeed, in that case, this
@ -3462,26 +3464,15 @@ void RenderFrameHostImpl::RenderFrameCreated() {
render_frame_state_ = RenderFrameState::kCreated;
if (old_render_frame_state == RenderFrameState::kDeleted) {
// Clear all the document-associated data for this RenderFrameHost when its
// RenderFrame is recreated after a crash. Note that the user data is
// intentionally not cleared at the time of crash. Please refer to
// https://crbug.com/1099237 for more details.
//
// Clearing of user data should be called before RenderFrameCreated to
// ensure:
// - a) the new state set in RenderFrameCreated doesn't get deleted.
// - b) the old state is not leaked to a new RenderFrameHost.
document_associated_data_.emplace(*this);
// Dispatch update notification when a Page is recreated after a crash.
if (is_main_frame()) {
// Only a current RenderFrameHost should be recreating its RenderFrame
// here, since speculative and pending deletion RenderFrameHosts get
// deleted immediately after crash, whereas prerender gets cancelled and
// bfcache entry gets evicted.
DCHECK_EQ(frame_tree_node_->current_frame_host(), this);
frame_tree_node_->frame_tree()->delegate()->NotifyPageChanged(GetPage());
}
// Dispatch update notification when a Page is recreated after a crash. Only
// main RenderFrameHosts should ever be reused.
DCHECK(is_main_frame());
// Only a current RenderFrameHost should be recreating its RenderFrame
// here, since speculative and pending deletion RenderFrameHosts get
// deleted immediately after crash, whereas prerender gets cancelled and
// bfcache entry gets evicted.
DCHECK_EQ(frame_tree_node_->current_frame_host(), this);
frame_tree_node_->frame_tree()->delegate()->NotifyPageChanged(GetPage());
}
// Initialize the RenderWidgetHost which marks it and the RenderViewHost as
@ -3751,6 +3742,7 @@ void RenderFrameHostImpl::OnCreateChildFrame(
bool is_created_by_script,
const blink::LocalFrameToken& frame_token,
const base::UnguessableToken& devtools_frame_token,
const blink::DocumentToken& document_token,
const blink::FramePolicy& frame_policy,
const blink::mojom::FrameOwnerProperties& frame_owner_properties,
blink::FrameOwnerElementType owner_type) {
@ -3778,17 +3770,17 @@ void RenderFrameHostImpl::OnCreateChildFrame(
return;
}
// |new_routing_id|, |browser_interface_broker_receiver| and
// |devtools_frame_token| were generated on the browser's IO thread and not
// taken from the renderer process.
// `new_routing_id`, `frame_token`, `devtools_frame_token` and
// `document_token` were generated on the browser's IO thread and not taken
// from the renderer process.
frame_tree_->AddFrame(
this, GetProcess()->GetID(), new_routing_id, std::move(frame_remote),
std::move(browser_interface_broker_receiver),
std::move(policy_container_bind_params),
std::move(associated_interface_provider_receiver), scope, frame_name,
frame_unique_name, is_created_by_script, frame_token,
devtools_frame_token, frame_policy, frame_owner_properties,
was_discarded_, owner_type,
devtools_frame_token, document_token, frame_policy,
frame_owner_properties, was_discarded_, owner_type,
/*is_dummy_frame_for_inner_tree=*/false);
}
@ -3809,9 +3801,11 @@ void RenderFrameHostImpl::CreateChildFrame(
blink::FrameOwnerElementType owner_type) {
blink::LocalFrameToken frame_token;
base::UnguessableToken devtools_frame_token;
blink::DocumentToken document_token;
if (!static_cast<RenderProcessHostImpl*>(GetProcess())
->TakeFrameTokensForFrameRoutingID(new_routing_id, frame_token,
devtools_frame_token)) {
devtools_frame_token,
document_token)) {
bad_message::ReceivedBadMessage(
GetProcess(), bad_message::RFH_CREATE_CHILD_FRAME_TOKENS_NOT_FOUND);
return;
@ -3844,8 +3838,8 @@ void RenderFrameHostImpl::CreateChildFrame(
std::move(policy_container_bind_params),
std::move(associated_interface_provider_receiver), scope,
frame_name, frame_unique_name, is_created_by_script,
frame_token, devtools_frame_token, frame_policy,
*frame_owner_properties, owner_type);
frame_token, devtools_frame_token, document_token,
frame_policy, *frame_owner_properties, owner_type);
}
void RenderFrameHostImpl::DidNavigate(
@ -4176,6 +4170,7 @@ FrameTreeNode* RenderFrameHostImpl::AddChild(
int frame_routing_id,
mojo::PendingAssociatedRemote<mojom::Frame> frame_remote,
const blink::LocalFrameToken& frame_token,
const blink::DocumentToken& document_token,
const blink::FramePolicy& frame_policy,
std::string frame_name,
std::string frame_unique_name) {
@ -4184,7 +4179,7 @@ FrameTreeNode* RenderFrameHostImpl::AddChild(
// a different one if they navigate away.
child->render_manager()->InitChild(
GetSiteInstance(), frame_routing_id, std::move(frame_remote), frame_token,
frame_policy, frame_name, frame_unique_name);
document_token, frame_policy, frame_name, frame_unique_name);
// Other renderer processes in this BrowsingInstance may need to find out
// about the new frame. Create a proxy for the child frame in all
@ -7507,6 +7502,7 @@ void RenderFrameHostImpl::CreateNewWindow(
std::move(page_broadcast_receiver), std::move(browser_interface_broker),
std::move(pending_associated_interface_provider), cloned_namespace->id(),
new_main_rfh->GetDevToolsFrameToken(), wait_for_debugger,
new_main_rfh->GetDocumentToken(),
new_main_rfh->policy_container_host()->CreatePolicyContainerForBlink());
std::move(callback).Run(mojom::CreateNewWindowStatus::kSuccess,
@ -8757,6 +8753,7 @@ void RenderFrameHostImpl::CommitNavigation(
absl::optional<std::vector<blink::mojom::TransferrableURLLoaderPtr>>
subresource_overrides,
blink::mojom::ServiceWorkerContainerInfoForClientPtr container_info,
const blink::DocumentToken& document_token,
const base::UnguessableToken& devtools_navigation_token,
std::unique_ptr<WebBundleHandle> web_bundle_handle) {
TRACE_EVENT2("navigation", "RenderFrameHostImpl::CommitNavigation",
@ -9187,7 +9184,7 @@ void RenderFrameHostImpl::CommitNavigation(
std::move(subresource_loader_factories),
std::move(subresource_overrides), std::move(controller),
std::move(container_info), std::move(prefetch_loader_factory),
manifest_policy, std::move(policy_container),
manifest_policy, std::move(policy_container), document_token,
devtools_navigation_token);
navigation_request->frame_tree_node()
->navigator()
@ -9211,7 +9208,8 @@ void RenderFrameHostImpl::FailedNavigation(
bool has_stale_copy_in_cache,
int error_code,
int extended_error_code,
const absl::optional<std::string>& error_page_content) {
const absl::optional<std::string>& error_page_content,
const blink::DocumentToken& document_token) {
TRACE_EVENT2("navigation", "RenderFrameHostImpl::FailedNavigation",
"navigation_request", navigation_request, "error", error_code);
@ -9248,11 +9246,12 @@ void RenderFrameHostImpl::FailedNavigation(
blink::mojom::PolicyContainerPtr policy_container =
navigation_request->CreatePolicyContainerForBlink();
SendCommitFailedNavigation(
navigation_client, navigation_request, common_params.Clone(),
commit_params.Clone(), has_stale_copy_in_cache, error_code,
extended_error_code, error_page_content,
std::move(subresource_loader_factories), std::move(policy_container));
SendCommitFailedNavigation(navigation_client, navigation_request,
common_params.Clone(), commit_params.Clone(),
has_stale_copy_in_cache, error_code,
extended_error_code, error_page_content,
std::move(subresource_loader_factories),
document_token, std::move(policy_container));
// TODO(crbug/1129537): support UKM source creation for failed navigations
// too.
@ -11830,7 +11829,28 @@ bool RenderFrameHostImpl::DidCommitNavigationInternal(
// RenderFrameHost commits before the navigation commits. This happens
// when the current RenderFrameHost crashes before navigating to a new
// URL.
document_associated_data_.emplace(*this);
document_associated_data_.emplace(*this,
navigation_request->GetDocumentToken());
} else {
// Cross-RenderFrameHost navigations that commit into a speculative
// RenderFrameHost do not create a new DocumentAssociatedData.
// Unfortunately, this means that DocumentAssociatedData::token cannot be
// immutable: skipping this update means the tokens would be mismatched
// between the browser and the renderer. This is unfortunate, but still
// better than the alternative:
//
// - change NavigationRequest to figure out if the above branch will be
// taken; if not, reuse the DocumentToken. This means the logic between
// RenderFrameHostImpl and NavigationRequest must remain in sync.
//
// - in addition, the resulting commit will reuse the DocumentToken
// between the ostensibly non-observable initial document in a
// speculative RenderFrameHost and the actual document committed by the
// navigation. As much as possible, it would be better to minimize
// DocumentToken reuse across cross-document navigations. Note that this
// reuse *does* happen internally to the renderer in one case that is
// almost never visible. See https://crbug.com/778318 for the details.
document_associated_data_->token = navigation_request->GetDocumentToken();
}
const absl::optional<FencedFrameURLMapping::FencedFrameProperties>&
@ -12230,6 +12250,7 @@ void RenderFrameHostImpl::SendCommitNavigation(
prefetch_loader_factory,
const absl::optional<blink::ParsedPermissionsPolicy>& permissions_policy,
blink::mojom::PolicyContainerPtr policy_container,
const blink::DocumentToken& document_token,
const base::UnguessableToken& devtools_navigation_token) {
TRACE_EVENT0("navigation", "RenderFrameHostImpl::SendCommitNavigation");
base::ElapsedTimer timer;
@ -12318,10 +12339,11 @@ void RenderFrameHostImpl::SendCommitNavigation(
std::move(url_loader_client_endpoints),
std::move(subresource_loader_factories), std::move(subresource_overrides),
std::move(controller), std::move(container_info),
std::move(prefetch_loader_factory), devtools_navigation_token,
permissions_policy, std::move(policy_container),
std::move(code_cache_host), std::move(cookie_manager_info),
std::move(storage_info), std::move(not_restored_reasons),
std::move(prefetch_loader_factory), document_token,
devtools_navigation_token, permissions_policy,
std::move(policy_container), std::move(code_cache_host),
std::move(cookie_manager_info), std::move(storage_info),
std::move(not_restored_reasons),
BuildCommitNavigationCallback(navigation_request));
base::UmaHistogramTimes(
base::StrCat({"Navigation.SendCommitNavigationTime.",
@ -12340,6 +12362,7 @@ void RenderFrameHostImpl::SendCommitFailedNavigation(
const absl::optional<std::string>& error_page_content,
std::unique_ptr<blink::PendingURLLoaderFactoryBundle>
subresource_loader_factories,
const blink::DocumentToken& document_token,
blink::mojom::PolicyContainerPtr policy_container) {
DCHECK(navigation_client && navigation_request);
DCHECK_NE(GURL(), common_params->url);
@ -12349,7 +12372,8 @@ void RenderFrameHostImpl::SendCommitFailedNavigation(
std::move(common_params), std::move(commit_params),
has_stale_copy_in_cache, error_code, extended_error_code,
navigation_request->GetResolveErrorInfo(), error_page_content,
std::move(subresource_loader_factories), std::move(policy_container),
std::move(subresource_loader_factories), document_token,
std::move(policy_container),
GetContentClient()->browser()->GetAlternativeErrorPageOverrideInfo(
navigation_request->GetURL(), this, GetBrowserContext(), error_code),
BuildCommitFailedNavigationCallback(navigation_request));
@ -13765,6 +13789,30 @@ RenderFrameHostImpl::PerformMakeCredentialWebAuthSecurityChecks(
}
#endif
const blink::DocumentToken& RenderFrameHostImpl::GetDocumentToken() const {
DCHECK_NE(LifecycleStateImpl::kPendingCommit, lifecycle_state());
DCHECK_NE(LifecycleStateImpl::kSpeculative, lifecycle_state());
return GetDocumentTokenIgnoringSafetyRestrictions();
}
void RenderFrameHostImpl::
ReinitializeDocumentAssociatedDataForReuseAfterCrash() {
DCHECK(is_main_frame());
DCHECK_EQ(RenderFrameState::kDeleted, render_frame_state_);
// Clear all the document-associated data for this RenderFrameHost when its
// RenderFrame is recreated after a crash. Note that the user data is
// intentionally not cleared at the time of crash. Please refer to
// https://crbug.com/1099237 for more details.
//
// Clearing of user data should be called before RenderFrameCreated to
// ensure:
// - a) the new state set in RenderFrameCreated doesn't get deleted.
// - b) the old state is not leaked to a new RenderFrameHost.
document_associated_data_.emplace(*this, blink::DocumentToken());
}
void RenderFrameHostImpl::IsClipboardPasteContentAllowed(
const ui::ClipboardFormatType& data_type,
const std::string& data,
@ -14328,8 +14376,9 @@ void RenderFrameHostImpl::BindCacheStorageForBucket(
}
RenderFrameHostImpl::DocumentAssociatedData::DocumentAssociatedData(
RenderFrameHostImpl& document)
: weak_ptr_factory(&document) {
RenderFrameHostImpl& document,
const blink::DocumentToken& token)
: token(token), weak_ptr_factory(&document) {
// Only create page object for the main document as the PageImpl is 1:1 with
// main document.
if (!document.GetParent()) {

@ -109,6 +109,7 @@
#include "third_party/blink/public/common/permissions_policy/permissions_policy_declaration.h"
#include "third_party/blink/public/common/scheduler/web_scheduler_tracked_feature.h"
#include "third_party/blink/public/common/storage_key/storage_key.h"
#include "third_party/blink/public/common/tokens/tokens.h"
#include "third_party/blink/public/mojom/back_forward_cache_not_restored_reasons.mojom.h"
#include "third_party/blink/public/mojom/bluetooth/web_bluetooth.mojom-forward.h"
#include "third_party/blink/public/mojom/broadcastchannel/broadcast_channel.mojom.h"
@ -478,6 +479,37 @@ class CONTENT_EXPORT RenderFrameHostImpl
// Additional non-override const version of GetMainFrame.
const RenderFrameHostImpl* GetMainFrame() const;
// Returns the token for the document currently associated with this frame.
// This can change over time if a `RenderFrameHost` is reused when navigating
// to a new document.
//
// Retrieving the document token is disallowed if:
// - the RenderFrameHost is pending commit, e.g. waiting for the renderer to
// acknowledge the commit, since the DocumentToken will change as soon as
// the navigation actually commits.
// - the RenderFrameHost is speculative
const blink::DocumentToken& GetDocumentToken() const;
// Retrieving the document token is disallowed during times when the result
// might be misleading / confusing (kPendingCommit or kSpeculative).
// Internally, the content implementation may still need to retrieve the
// document token at those times, so provide an escape hatch.
const blink::DocumentToken& GetDocumentTokenIgnoringSafetyRestrictions()
const {
return document_associated_data_->token;
}
// A RenderFrame was previously created but no longer exists, e.g. the
// renderer process is gone due to a crash.
bool is_render_frame_deleted() const {
return render_frame_state_ == RenderFrameState::kDeleted;
}
// Immediately reinitializes DocumentUserData when the RenderFrameHost needs
// to be immediately reused after a crash. Only usable for a main frame where
// `is_render_frame_deleted()` is true.
void ReinitializeDocumentAssociatedDataForReuseAfterCrash();
// Determines if a clipboard paste using |data| of type |data_type| is allowed
// in this renderer frame. The implementation delegates to
// RenderFrameHostDelegate::IsClipboardPasteContentAllowed(). See the
@ -613,13 +645,13 @@ class CONTENT_EXPORT RenderFrameHostImpl
// Called when this frame has added a child. This is a continuation of an IPC
// that was partially handled on the IO thread (to allocate |new_routing_id|,
// |frame_token| and |devtools_frame_token|), and is forwarded here. The
// renderer has already been told to create a RenderFrame with the specified
// ID values. |browser_interface_broker_receiver| is the receiver end of the
// BrowserInterfaceBroker interface in the child frame. RenderFrameHost should
// bind this receiver to expose services to the renderer process. The caller
// takes care of sending down the client end of the pipe to the child
// RenderFrame to use.
// |frame_token|, |devtools_frame_token|, |document_token|), and is forwarded
// here. The renderer has already been told to create a RenderFrame with the
// specified ID values. |browser_interface_broker_receiver| is the receiver
// end of the BrowserInterfaceBroker interface in the child frame.
// RenderFrameHost should bind this receiver to expose services to the
// renderer process. The caller takes care of sending down the client end of
// the pipe to the child RenderFrame to use.
void OnCreateChildFrame(
int new_routing_id,
mojo::PendingAssociatedRemote<mojom::Frame> frame_remote,
@ -634,6 +666,7 @@ class CONTENT_EXPORT RenderFrameHostImpl
bool is_created_by_script,
const blink::LocalFrameToken& frame_token,
const base::UnguessableToken& devtools_frame_token,
const blink::DocumentToken& document_token,
const blink::FramePolicy& frame_policy,
const blink::mojom::FrameOwnerProperties& frame_owner_properties,
blink::FrameOwnerElementType owner_type);
@ -665,6 +698,7 @@ class CONTENT_EXPORT RenderFrameHostImpl
int frame_routing_id,
mojo::PendingAssociatedRemote<mojom::Frame> frame_remote,
const blink::LocalFrameToken& frame_token,
const blink::DocumentToken& document_token,
const blink::FramePolicy& frame_policy,
std::string frame_name,
std::string frame_unique_name);
@ -1273,6 +1307,7 @@ class CONTENT_EXPORT RenderFrameHostImpl
absl::optional<std::vector<blink::mojom::TransferrableURLLoaderPtr>>
subresource_overrides,
blink::mojom::ServiceWorkerContainerInfoForClientPtr container_info,
const blink::DocumentToken& document_token,
const base::UnguessableToken& devtools_navigation_token,
std::unique_ptr<WebBundleHandle> web_bundle_handle);
@ -1285,7 +1320,8 @@ class CONTENT_EXPORT RenderFrameHostImpl
bool has_stale_copy_in_cache,
int error_code,
int extended_error_code,
const absl::optional<std::string>& error_page_content);
const absl::optional<std::string>& error_page_content,
const blink::DocumentToken& document_token);
// Sends a renderer-debug URL to the renderer process for handling.
void HandleRendererDebugURL(const GURL& url);
@ -2574,6 +2610,7 @@ class CONTENT_EXPORT RenderFrameHostImpl
int32_t routing_id,
mojo::PendingAssociatedRemote<mojom::Frame> frame_remote,
const blink::LocalFrameToken& frame_token,
const blink::DocumentToken& document_token,
bool renderer_initiated_creation_of_main_frame,
LifecycleStateImpl lifecycle_state,
scoped_refptr<BrowsingContextState> browsing_context_state,
@ -2601,6 +2638,7 @@ class CONTENT_EXPORT RenderFrameHostImpl
prefetch_loader_factory,
const absl::optional<blink::ParsedPermissionsPolicy>& permissions_policy,
blink::mojom::PolicyContainerPtr policy_container,
const blink::DocumentToken& document_token,
const base::UnguessableToken& devtools_navigation_token);
virtual void SendCommitFailedNavigation(
mojom::NavigationClient* navigation_client,
@ -2613,6 +2651,7 @@ class CONTENT_EXPORT RenderFrameHostImpl
const absl::optional<std::string>& error_page_content,
std::unique_ptr<blink::PendingURLLoaderFactoryBundle>
subresource_loader_factories,
const blink::DocumentToken& document_token,
blink::mojom::PolicyContainerPtr policy_container);
// The Build*Callback functions below are responsible for building the
@ -3395,7 +3434,7 @@ class CONTENT_EXPORT RenderFrameHostImpl
// Has the RenderFrame been created in the renderer process and not yet been
// deleted, exited or crashed. See RenderFrameState.
bool is_render_frame_created() {
bool is_render_frame_created() const {
return render_frame_state_ == RenderFrameState::kCreated;
}
@ -4117,11 +4156,21 @@ class CONTENT_EXPORT RenderFrameHostImpl
// GetDocumentUserData(). Please refer to the description at
// content/public/browser/document_user_data.h for more details.
struct DocumentAssociatedData : public base::SupportsUserData {
explicit DocumentAssociatedData(RenderFrameHostImpl& document);
explicit DocumentAssociatedData(RenderFrameHostImpl& document,
const blink::DocumentToken& token);
~DocumentAssociatedData() override;
DocumentAssociatedData(const DocumentAssociatedData&) = delete;
DocumentAssociatedData& operator=(const DocumentAssociatedData&) = delete;
// An opaque token that uniquely identifies the document currently
// associated with this RenderFrameHost. In general, this token does not
// change for the lifetime of the DocumentAssociatedData, with one
// exception: a speculative RenderFrameHost is created with an initial
// DocumentAssociatedData. If the speculative RenderFrameHost commits, the
// DocumentAssociatedData is not reset, but a new DocumentToken is still
// assigned.
blink::DocumentToken token;
// The Page object associated with the main document. It is nullptr for
// subframes.
std::unique_ptr<PageImpl> owned_page;

@ -615,13 +615,14 @@ class RenderFrameHostFactoryForBeforeUnloadInterceptor
int32_t routing_id,
mojo::PendingAssociatedRemote<mojom::Frame> frame_remote,
const blink::LocalFrameToken& frame_token,
const blink::DocumentToken& document_token,
bool renderer_initiated_creation,
RenderFrameHostImpl::LifecycleStateImpl lifecycle_state,
scoped_refptr<BrowsingContextState> browsing_context_state) override {
return base::WrapUnique(new RenderFrameHostImplForBeforeUnloadInterceptor(
site_instance, std::move(render_view_host), delegate, frame_tree,
frame_tree_node, routing_id, std::move(frame_remote), frame_token,
renderer_initiated_creation, lifecycle_state,
document_token, renderer_initiated_creation, lifecycle_state,
std::move(browsing_context_state),
frame_tree_node->frame_owner_element_type()));
}

@ -390,7 +390,8 @@ void RenderFrameHostManager::InitRoot(
CreateFrameCase::kInitRoot, site_instance,
/*frame_routing_id=*/MSG_ROUTING_NONE,
mojo::PendingAssociatedRemote<mojom::Frame>(), blink::LocalFrameToken(),
renderer_initiated_creation, browsing_context_state));
blink::DocumentToken(), renderer_initiated_creation,
browsing_context_state));
// Creating a main RenderFrameHost also creates a new Page, so notify the
// delegate about this.
@ -403,6 +404,7 @@ void RenderFrameHostManager::InitChild(
int32_t frame_routing_id,
mojo::PendingAssociatedRemote<mojom::Frame> frame_remote,
const blink::LocalFrameToken& frame_token,
const blink::DocumentToken& document_token,
blink::FramePolicy frame_policy,
std::string frame_name,
std::string frame_unique_name) {
@ -429,7 +431,7 @@ void RenderFrameHostManager::InitChild(
browsing_context_state->CommitFramePolicy(frame_policy);
SetRenderFrameHost(CreateRenderFrameHost(
CreateFrameCase::kInitChild, site_instance, frame_routing_id,
std::move(frame_remote), frame_token,
std::move(frame_remote), frame_token, document_token,
/*renderer_initiated_creation=*/false, browsing_context_state));
}
@ -2111,6 +2113,17 @@ bool RenderFrameHostManager::InitializeMainRenderFrameForImmediateUse() {
render_frame_host_->reset_must_be_replaced();
// If the render frame was previously deleted, this is a signal that the
// RenderFrameHost is being reused after a crash.
if (render_frame_host_->is_render_frame_deleted()) {
// The DocumentAssociatedData needs to be reinitialized now to ensure that
// the render frame is created with a new DocumentToken. Note that this
// needs to remain in sync with `RenderFrameHostImpl::RenderFrameCreated()`,
// which dispatches the actual notification about a new Page object for this
// case.
render_frame_host_->ReinitializeDocumentAssociatedDataForReuseAfterCrash();
}
if (!ReinitializeMainRenderFrame(render_frame_host_.get())) {
NOTREACHED();
return false;
@ -2706,6 +2719,7 @@ RenderFrameHostManager::CreateRenderFrameHost(
int32_t frame_routing_id,
mojo::PendingAssociatedRemote<mojom::Frame> frame_remote,
const blink::LocalFrameToken& frame_token,
const blink::DocumentToken& document_token,
bool renderer_initiated_creation,
scoped_refptr<BrowsingContextState> browsing_context_state) {
FrameTree* frame_tree = frame_tree_node_->frame_tree();
@ -2781,7 +2795,7 @@ RenderFrameHostManager::CreateRenderFrameHost(
return RenderFrameHostFactory::Create(
site_instance, std::move(render_view_host),
frame_tree->render_frame_delegate(), frame_tree, frame_tree_node_,
frame_routing_id, std::move(frame_remote), frame_token,
frame_routing_id, std::move(frame_remote), frame_token, document_token,
renderer_initiated_creation, lifecycle_state,
std::move(browsing_context_state));
}
@ -2919,7 +2933,7 @@ RenderFrameHostManager::CreateSpeculativeRenderFrame(
CreateRenderFrameHost(CreateFrameCase::kCreateSpeculative, instance,
/*frame_routing_id=*/MSG_ROUTING_NONE,
mojo::PendingAssociatedRemote<mojom::Frame>(),
blink::LocalFrameToken(),
blink::LocalFrameToken(), blink::DocumentToken(),
/*renderer_initiated_creation=*/false,
browsing_context_state);
DCHECK_EQ(new_render_frame_host->GetSiteInstance(), instance);

@ -190,6 +190,7 @@ class CONTENT_EXPORT RenderFrameHostManager {
int32_t frame_routing_id,
mojo::PendingAssociatedRemote<mojom::Frame> frame_remote,
const blink::LocalFrameToken& frame_token,
const blink::DocumentToken& document_token,
blink::FramePolicy frame_policy,
std::string frame_name,
std::string frame_unique_name);
@ -781,6 +782,7 @@ class CONTENT_EXPORT RenderFrameHostManager {
int32_t frame_routing_id,
mojo::PendingAssociatedRemote<mojom::Frame> frame_remote,
const blink::LocalFrameToken& frame_token,
const blink::DocumentToken& document_token,
bool renderer_initiated_creation,
scoped_refptr<BrowsingContextState> browsing_context_state);

@ -1927,7 +1927,8 @@ TEST_P(RenderFrameHostManagerTestWithSiteIsolation, DetachPendingChild) {
TestRenderFrameHost::CreateStubAssociatedInterfaceProviderReceiver(),
blink::mojom::TreeScopeType::kDocument, "frame_name", "uniqueName1",
false, blink::LocalFrameToken(), base::UnguessableToken::Create(),
blink::FramePolicy(), blink::mojom::FrameOwnerProperties(), kOwnerType);
blink::DocumentToken(), blink::FramePolicy(),
blink::mojom::FrameOwnerProperties(), kOwnerType);
contents()->GetPrimaryMainFrame()->OnCreateChildFrame(
contents()->GetPrimaryMainFrame()->GetProcess()->GetNextRoutingID(),
TestRenderFrameHost::CreateStubFrameRemote(),
@ -1936,7 +1937,8 @@ TEST_P(RenderFrameHostManagerTestWithSiteIsolation, DetachPendingChild) {
TestRenderFrameHost::CreateStubAssociatedInterfaceProviderReceiver(),
blink::mojom::TreeScopeType::kDocument, "frame_name", "uniqueName2",
false, blink::LocalFrameToken(), base::UnguessableToken::Create(),
blink::FramePolicy(), blink::mojom::FrameOwnerProperties(), kOwnerType);
blink::DocumentToken(), blink::FramePolicy(),
blink::mojom::FrameOwnerProperties(), kOwnerType);
RenderFrameHostManager* root_manager =
contents()->GetPrimaryFrameTree().root()->render_manager();
RenderFrameHostManager* iframe1 =
@ -2105,7 +2107,8 @@ TEST_P(RenderFrameHostManagerTestWithSiteIsolation,
TestRenderFrameHost::CreateStubAssociatedInterfaceProviderReceiver(),
blink::mojom::TreeScopeType::kDocument, "frame_name", "uniqueName1",
false, blink::LocalFrameToken(), base::UnguessableToken::Create(),
blink::FramePolicy(), blink::mojom::FrameOwnerProperties(),
blink::DocumentToken(), blink::FramePolicy(),
blink::mojom::FrameOwnerProperties(),
blink::FrameOwnerElementType::kIframe);
RenderFrameHostManager* iframe =
contents()->GetPrimaryFrameTree().root()->child_at(0)->render_manager();
@ -2253,7 +2256,8 @@ TEST_P(RenderFrameHostManagerTestWithSiteIsolation,
TestRenderFrameHost::CreateStubAssociatedInterfaceProviderReceiver(),
blink::mojom::TreeScopeType::kDocument, std::string(), "uniqueName1",
false, blink::LocalFrameToken(), base::UnguessableToken::Create(),
blink::FramePolicy(), blink::mojom::FrameOwnerProperties(),
blink::DocumentToken(), blink::FramePolicy(),
blink::mojom::FrameOwnerProperties(),
blink::FrameOwnerElementType::kIframe);
RenderFrameHostManager* subframe_rfhm =
contents()->GetPrimaryFrameTree().root()->child_at(0)->render_manager();
@ -2472,8 +2476,9 @@ TEST_P(RenderFrameHostManagerTest, TraverseComplexOpenerChain) {
TestRenderFrameHost::CreateStubAssociatedInterfaceProviderReceiver(),
blink::mojom::TreeScopeType::kDocument, std::string(), "uniqueName0",
false, blink::LocalFrameToken(), base::UnguessableToken::Create(),
blink::FramePolicy(), blink::mojom::FrameOwnerProperties(), false,
kOwnerType, is_dummy_frame_for_inner_tree);
blink::DocumentToken(), blink::FramePolicy(),
blink::mojom::FrameOwnerProperties(), false, kOwnerType,
is_dummy_frame_for_inner_tree);
tree1->AddFrame(
root1->current_frame_host(), process_id, 13,
TestRenderFrameHost::CreateStubFrameRemote(),
@ -2482,8 +2487,9 @@ TEST_P(RenderFrameHostManagerTest, TraverseComplexOpenerChain) {
TestRenderFrameHost::CreateStubAssociatedInterfaceProviderReceiver(),
blink::mojom::TreeScopeType::kDocument, std::string(), "uniqueName1",
false, blink::LocalFrameToken(), base::UnguessableToken::Create(),
blink::FramePolicy(), blink::mojom::FrameOwnerProperties(), false,
kOwnerType, is_dummy_frame_for_inner_tree);
blink::DocumentToken(), blink::FramePolicy(),
blink::mojom::FrameOwnerProperties(), false, kOwnerType,
is_dummy_frame_for_inner_tree);
std::unique_ptr<TestWebContents> tab2(
TestWebContents::Create(browser_context(), nullptr));
@ -2499,8 +2505,9 @@ TEST_P(RenderFrameHostManagerTest, TraverseComplexOpenerChain) {
TestRenderFrameHost::CreateStubAssociatedInterfaceProviderReceiver(),
blink::mojom::TreeScopeType::kDocument, std::string(), "uniqueName2",
false, blink::LocalFrameToken(), base::UnguessableToken::Create(),
blink::FramePolicy(), blink::mojom::FrameOwnerProperties(), false,
kOwnerType, is_dummy_frame_for_inner_tree);
blink::DocumentToken(), blink::FramePolicy(),
blink::mojom::FrameOwnerProperties(), false, kOwnerType,
is_dummy_frame_for_inner_tree);
tree2->AddFrame(
root2->current_frame_host(), process_id, 23,
TestRenderFrameHost::CreateStubFrameRemote(),
@ -2509,8 +2516,9 @@ TEST_P(RenderFrameHostManagerTest, TraverseComplexOpenerChain) {
TestRenderFrameHost::CreateStubAssociatedInterfaceProviderReceiver(),
blink::mojom::TreeScopeType::kDocument, std::string(), "uniqueName3",
false, blink::LocalFrameToken(), base::UnguessableToken::Create(),
blink::FramePolicy(), blink::mojom::FrameOwnerProperties(), false,
kOwnerType, is_dummy_frame_for_inner_tree);
blink::DocumentToken(), blink::FramePolicy(),
blink::mojom::FrameOwnerProperties(), false, kOwnerType,
is_dummy_frame_for_inner_tree);
std::unique_ptr<TestWebContents> tab3(
TestWebContents::Create(browser_context(), nullptr));
@ -2531,8 +2539,9 @@ TEST_P(RenderFrameHostManagerTest, TraverseComplexOpenerChain) {
TestRenderFrameHost::CreateStubAssociatedInterfaceProviderReceiver(),
blink::mojom::TreeScopeType::kDocument, std::string(), "uniqueName4",
false, blink::LocalFrameToken(), base::UnguessableToken::Create(),
blink::FramePolicy(), blink::mojom::FrameOwnerProperties(), false,
kOwnerType, is_dummy_frame_for_inner_tree);
blink::DocumentToken(), blink::FramePolicy(),
blink::mojom::FrameOwnerProperties(), false, kOwnerType,
is_dummy_frame_for_inner_tree);
root1->child_at(1)->SetOpener(root1->child_at(1));
root1->SetOpener(root2->child_at(1));
@ -2627,7 +2636,8 @@ TEST_P(RenderFrameHostManagerTest, PageFocusPropagatesToSubframeProcesses) {
TestRenderFrameHost::CreateStubAssociatedInterfaceProviderReceiver(),
blink::mojom::TreeScopeType::kDocument, "frame1", "uniqueName1", false,
blink::LocalFrameToken(), base::UnguessableToken::Create(),
blink::FramePolicy(), blink::mojom::FrameOwnerProperties(), kOwnerType);
blink::DocumentToken(), blink::FramePolicy(),
blink::mojom::FrameOwnerProperties(), kOwnerType);
main_test_rfh()->OnCreateChildFrame(
main_test_rfh()->GetProcess()->GetNextRoutingID(),
TestRenderFrameHost::CreateStubFrameRemote(),
@ -2636,7 +2646,8 @@ TEST_P(RenderFrameHostManagerTest, PageFocusPropagatesToSubframeProcesses) {
TestRenderFrameHost::CreateStubAssociatedInterfaceProviderReceiver(),
blink::mojom::TreeScopeType::kDocument, "frame2", "uniqueName2", false,
blink::LocalFrameToken(), base::UnguessableToken::Create(),
blink::FramePolicy(), blink::mojom::FrameOwnerProperties(), kOwnerType);
blink::DocumentToken(), blink::FramePolicy(),
blink::mojom::FrameOwnerProperties(), kOwnerType);
main_test_rfh()->OnCreateChildFrame(
main_test_rfh()->GetProcess()->GetNextRoutingID(),
TestRenderFrameHost::CreateStubFrameRemote(),
@ -2645,7 +2656,8 @@ TEST_P(RenderFrameHostManagerTest, PageFocusPropagatesToSubframeProcesses) {
TestRenderFrameHost::CreateStubAssociatedInterfaceProviderReceiver(),
blink::mojom::TreeScopeType::kDocument, "frame3", "uniqueName3", false,
blink::LocalFrameToken(), base::UnguessableToken::Create(),
blink::FramePolicy(), blink::mojom::FrameOwnerProperties(), kOwnerType);
blink::DocumentToken(), blink::FramePolicy(),
blink::mojom::FrameOwnerProperties(), kOwnerType);
FrameTreeNode* root = contents()->GetPrimaryFrameTree().root();
RenderFrameHostManager* child1 = root->child_at(0)->render_manager();
@ -2757,7 +2769,8 @@ TEST_P(RenderFrameHostManagerTest,
TestRenderFrameHost::CreateStubAssociatedInterfaceProviderReceiver(),
blink::mojom::TreeScopeType::kDocument, "frame1", "uniqueName1", false,
blink::LocalFrameToken(), base::UnguessableToken::Create(),
blink::FramePolicy(), blink::mojom::FrameOwnerProperties(), kOwnerType);
blink::DocumentToken(), blink::FramePolicy(),
blink::mojom::FrameOwnerProperties(), kOwnerType);
FrameTreeNode* root = contents()->GetPrimaryFrameTree().root();
RenderFrameHostManager* child = root->child_at(0)->render_manager();
@ -3329,7 +3342,8 @@ TEST_P(RenderFrameHostManagerTestWithSiteIsolation,
TestRenderFrameHost::CreateStubAssociatedInterfaceProviderReceiver(),
blink::mojom::TreeScopeType::kDocument, "frame1", "uniqueName1", false,
blink::LocalFrameToken(), base::UnguessableToken::Create(),
blink::FramePolicy(), blink::mojom::FrameOwnerProperties(),
blink::DocumentToken(), blink::FramePolicy(),
blink::mojom::FrameOwnerProperties(),
blink::FrameOwnerElementType::kIframe);
FrameTreeNode* root = contents()->GetPrimaryFrameTree().root();

@ -123,9 +123,11 @@ void RenderMessageFilter::GenerateFrameRoutingID(
int32_t routing_id = render_widget_helper_->GetNextRoutingID();
auto frame_token = blink::LocalFrameToken();
auto devtools_frame_token = base::UnguessableToken::Create();
render_widget_helper_->StoreNextFrameRoutingID(routing_id, frame_token,
devtools_frame_token);
std::move(callback).Run(routing_id, frame_token, devtools_frame_token);
auto document_token = blink::DocumentToken();
render_widget_helper_->StoreNextFrameRoutingID(
routing_id, frame_token, devtools_frame_token, document_token);
std::move(callback).Run(routing_id, frame_token, devtools_frame_token,
document_token);
}
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)

@ -2796,9 +2796,10 @@ void RenderProcessHostImpl::RemoveRoute(int32_t routing_id) {
bool RenderProcessHostImpl::TakeFrameTokensForFrameRoutingID(
int32_t new_routing_id,
blink::LocalFrameToken& frame_token,
base::UnguessableToken& devtools_frame_token) {
base::UnguessableToken& devtools_frame_token,
blink::DocumentToken& document_token) {
return widget_helper_->TakeFrameTokensForFrameRoutingID(
new_routing_id, frame_token, devtools_frame_token);
new_routing_id, frame_token, devtools_frame_token, document_token);
}
void RenderProcessHostImpl::AddObserver(RenderProcessHostObserver* observer) {

@ -346,7 +346,8 @@ class CONTENT_EXPORT RenderProcessHostImpl
bool TakeFrameTokensForFrameRoutingID(
int32_t new_routing_id,
blink::LocalFrameToken& frame_token,
base::UnguessableToken& devtools_frame_token);
base::UnguessableToken& devtools_frame_token,
blink::DocumentToken& document_token);
void AddInternalObserver(RenderProcessHostInternalObserver* observer);
void RemoveInternalObserver(RenderProcessHostInternalObserver* observer);

@ -172,7 +172,8 @@ TEST_F(RenderProcessHostUnitTest, ReuseCommittedSite) {
TestRenderFrameHost::CreateStubAssociatedInterfaceProviderReceiver(),
blink::mojom::TreeScopeType::kDocument, std::string(), unique_name, false,
blink::LocalFrameToken(), base::UnguessableToken::Create(),
blink::FramePolicy(), blink::mojom::FrameOwnerProperties(),
blink::DocumentToken(), blink::FramePolicy(),
blink::mojom::FrameOwnerProperties(),
blink::FrameOwnerElementType::kIframe);
TestRenderFrameHost* subframe =
static_cast<TestRenderFrameHost*>(contents()

@ -438,7 +438,7 @@ bool RenderViewHostImpl::CreateRenderView(
if (main_rfh) {
auto local_frame_params = mojom::CreateLocalMainFrameParams::New();
local_frame_params->token = main_rfh->GetFrameToken();
local_frame_params->frame_token = main_rfh->GetFrameToken();
local_frame_params->routing_id = main_frame_routing_id_;
mojo::PendingAssociatedRemote<mojom::Frame> pending_frame_remote;
local_frame_params->frame =
@ -452,6 +452,11 @@ bool RenderViewHostImpl::CreateRenderView(
local_frame_params->is_on_initial_empty_document =
main_rfh->frame_tree_node()->is_on_initial_empty_document();
// It is safe to ignore safety restrictions here, since it is necessary to
// retrieve the document token, even if the frame is speculative, in order
// to create the corresponding renderer-side objects.
local_frame_params->document_token =
main_rfh->GetDocumentTokenIgnoringSafetyRestrictions();
// If this is a new RenderFrameHost for a frame that has already committed a
// document, we don't have a PolicyContainerHost yet. Indeed, in that case,

@ -30,8 +30,11 @@ void AddWidgetHelper(int render_process_id,
RenderWidgetHelper::FrameTokens::FrameTokens(
const blink::LocalFrameToken& frame_token,
const base::UnguessableToken& devtools_frame_token)
: frame_token(frame_token), devtools_frame_token(devtools_frame_token) {}
const base::UnguessableToken& devtools_frame_token,
const blink::DocumentToken& document_token)
: frame_token(frame_token),
devtools_frame_token(devtools_frame_token),
document_token(document_token) {}
RenderWidgetHelper::FrameTokens::FrameTokens(const FrameTokens& other) =
default;
@ -70,13 +73,15 @@ int RenderWidgetHelper::GetNextRoutingID() {
bool RenderWidgetHelper::TakeFrameTokensForFrameRoutingID(
int32_t routing_id,
blink::LocalFrameToken& frame_token,
base::UnguessableToken& devtools_frame_token) {
base::UnguessableToken& devtools_frame_token,
blink::DocumentToken& document_token) {
base::AutoLock lock(frame_token_map_lock_);
auto iter = frame_token_routing_id_map_.find(routing_id);
if (iter == frame_token_routing_id_map_.end())
return false;
frame_token = iter->second.frame_token;
devtools_frame_token = iter->second.devtools_frame_token;
document_token = iter->second.document_token;
frame_token_routing_id_map_.erase(iter);
return true;
}
@ -84,11 +89,13 @@ bool RenderWidgetHelper::TakeFrameTokensForFrameRoutingID(
void RenderWidgetHelper::StoreNextFrameRoutingID(
int32_t routing_id,
const blink::LocalFrameToken& frame_token,
const base::UnguessableToken& devtools_frame_token) {
const base::UnguessableToken& devtools_frame_token,
const blink::DocumentToken& document_token) {
base::AutoLock lock(frame_token_map_lock_);
bool result =
frame_token_routing_id_map_
.emplace(routing_id, FrameTokens(frame_token, devtools_frame_token))
.emplace(routing_id, FrameTokens(frame_token, devtools_frame_token,
document_token))
.second;
DCHECK(result);
}

@ -47,7 +47,8 @@ class RenderWidgetHelper
bool TakeFrameTokensForFrameRoutingID(
int32_t routing_id,
blink::LocalFrameToken& frame_token,
base::UnguessableToken& devtools_frame_token);
base::UnguessableToken& devtools_frame_token,
blink::DocumentToken& document_token);
// Store a set of frame tokens given a routing id. This is usually called on
// the IO thread, and |GetFrameTokensForFrameRoutingID| will be called on the
@ -55,7 +56,8 @@ class RenderWidgetHelper
void StoreNextFrameRoutingID(
int32_t routing_id,
const blink::LocalFrameToken& frame_token,
const base::UnguessableToken& devtools_frame_token);
const base::UnguessableToken& devtools_frame_token,
const blink::DocumentToken& document_token);
// IO THREAD ONLY -----------------------------------------------------------
@ -70,13 +72,15 @@ class RenderWidgetHelper
struct FrameTokens {
FrameTokens(const blink::LocalFrameToken& frame_token,
const base::UnguessableToken& devtools_frame_token);
const base::UnguessableToken& devtools_frame_token,
const blink::DocumentToken& document_token);
FrameTokens(const FrameTokens& other);
FrameTokens& operator=(const FrameTokens& other);
~FrameTokens();
blink::LocalFrameToken frame_token;
base::UnguessableToken devtools_frame_token;
blink::DocumentToken document_token;
};
// Lock that is used to provide access to |frame_token_routing_id_map_|

@ -91,6 +91,7 @@ class FakeNavigationClient : public mojom::NavigationClient {
blink::mojom::ServiceWorkerContainerInfoForClientPtr container_info,
mojo::PendingRemote<network::mojom::URLLoaderFactory>
prefetch_loader_factory,
const blink::DocumentToken& document_token,
const base::UnguessableToken& devtools_navigation_token,
const absl::optional<blink::ParsedPermissionsPolicy>& permissions_policy,
blink::mojom::PolicyContainerPtr policy_container,
@ -111,6 +112,7 @@ class FakeNavigationClient : public mojom::NavigationClient {
const net::ResolveErrorInfo& resolve_error_info,
const absl::optional<std::string>& error_page_content,
std::unique_ptr<blink::PendingURLLoaderFactoryBundle> subresource_loaders,
const blink::DocumentToken& document_token,
blink::mojom::PolicyContainerPtr policy_container,
mojom::AlternativeErrorPageOverrideInfoPtr alternative_error_page_info,
CommitFailedNavigationCallback callback) override {
@ -255,7 +257,7 @@ void ServiceWorkerRemoteContainerEndpoint::BindForWindow(
blink::CreateCommitNavigationParams(),
network::mojom::URLResponseHead::New(),
mojo::ScopedDataPipeConsumerHandle(), nullptr, nullptr, absl::nullopt,
nullptr, std::move(info), mojo::NullRemote(),
nullptr, std::move(info), mojo::NullRemote(), blink::DocumentToken(),
base::UnguessableToken::Create(),
std::vector<blink::ParsedPermissionsPolicyDeclaration>(),
CreateStubPolicyContainer(), mojo::NullRemote(), nullptr, nullptr,

@ -4428,8 +4428,9 @@ IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
params->parent_frame_token =
shell()->web_contents()->GetPrimaryMainFrame()->GetFrameToken();
params->frame_owner_properties = blink::mojom::FrameOwnerProperties::New();
params->token = frame_token;
params->frame_token = frame_token;
params->devtools_frame_token = base::UnguessableToken::Create();
params->document_token = blink::DocumentToken();
params->policy_container = CreateStubPolicyContainer();
params->replication_state = blink::mojom::FrameReplicationState::New();
agent_scheduling_group->CreateFrame(std::move(params));
@ -4527,8 +4528,9 @@ IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest, ParentDetachRemoteChild) {
params->replication_state = blink::mojom::FrameReplicationState::New();
params->replication_state->name = "name";
params->replication_state->unique_name = "name";
params->token = frame_token;
params->frame_token = frame_token;
params->devtools_frame_token = base::UnguessableToken::Create();
params->document_token = blink::DocumentToken();
params->policy_container = CreateStubPolicyContainer();
agent_scheduling_group->CreateFrame(std::move(params));
}

@ -173,7 +173,7 @@ union CreateMainFrameUnion {
// Parameters used for browser-initiated local main frame creation.
struct CreateLocalMainFrameParams {
// The frame token. Used to map between LocalFrame and RenderFrameHostImpl.
blink.mojom.LocalFrameToken token;
blink.mojom.LocalFrameToken frame_token;
// The ID of the main frame hosted in the view. Must not be kRoutingIdNone.
int32 routing_id = IPC.mojom.kRoutingIdNone;
@ -192,6 +192,12 @@ struct CreateLocalMainFrameParams {
// Whether the frame is still on the initial empty document or not.
bool is_on_initial_empty_document = true;
// The document token to use for the initial document in the created frame.
// Note that this is independent of `is_on_initial_empty_document`: every
// fully-initialized frame always contains a document, even a provisional
// frame that is not yet swapped in.
blink.mojom.DocumentToken document_token;
// Null when the main frame has no policy container yet (for example, because
// it is a speculative RenderFrameHost), and the policy container will be
// sent during CommitNavigation.
@ -241,7 +247,7 @@ struct CreateFrameWidgetParams {
//
struct CreateFrameParams {
// The frame token. Used to map between LocalFrame and RenderFrameHostImpl.
blink.mojom.LocalFrameToken token;
blink.mojom.LocalFrameToken frame_token;
// Specifies the routing ID of the new RenderFrame object.
int32 routing_id;
@ -296,6 +302,12 @@ struct CreateFrameParams {
// Whether the frame is still on the initial empty document or not.
bool is_on_initial_empty_document = true;
// The document token to use for the initial document in the created frame.
// Note that this is independent of `is_on_initial_empty_document`: every
// fully-initialized frame always contains a document, even a provisional
// frame that is not yet swapped in.
blink.mojom.DocumentToken document_token;
// The policy container for the frame to be created. This can be null if we
// could not determine a policy container yet, for example in case of a
// speculative RenderFrameHost. In that case, the final policy container will
@ -643,6 +655,8 @@ struct CreateNewWindowReply {
// from the client.
bool wait_for_debugger;
blink.mojom.DocumentToken document_token;
// The policy container for the new frame that will be created by Blink in
// response.
blink.mojom.PolicyContainer policy_container;

@ -30,6 +30,7 @@ import "third_party/blink/public/mojom/permissions_policy/policy_value.mojom";
import "third_party/blink/public/mojom/security_context/insecure_request_policy.mojom";
import "third_party/blink/public/mojom/service_worker/controller_service_worker.mojom";
import "third_party/blink/public/mojom/service_worker/service_worker_container.mojom";
import "third_party/blink/public/mojom/tokens/tokens.mojom";
import "url/mojom/origin.mojom";
import "url/mojom/url.mojom";
@ -258,6 +259,7 @@ interface NavigationClient {
blink.mojom.ControllerServiceWorkerInfo? controller_service_worker_info,
blink.mojom.ServiceWorkerContainerInfoForClient? container_info,
pending_remote<network.mojom.URLLoaderFactory>? prefetch_loader_factory,
blink.mojom.DocumentToken document_token,
mojo_base.mojom.UnguessableToken devtools_navigation_token,
array<blink.mojom.ParsedPermissionsPolicyDeclaration>? permissions_policy,
blink.mojom.PolicyContainer policy_container,
@ -289,6 +291,7 @@ interface NavigationClient {
network.mojom.ResolveErrorInfo resolve_error_info,
string? error_page_content,
blink.mojom.URLLoaderFactoryBundle? subresource_loader_factories,
blink.mojom.DocumentToken document_token,
blink.mojom.PolicyContainer policy_container,
AlternativeErrorPageOverrideInfo? alternative_error_page_info)
=> (DidCommitProvisionalLoadParams params,

@ -12,12 +12,13 @@ interface RenderMessageFilter {
// Synchronously generates a new routing ID for the caller.
[Sync] GenerateRoutingID() => (int32 routing_id);
// Similar to GenerateRoutingID but also generates a frame token and
// devtools_frame_token. A subsequent call to FrameHost::CreateChildFrame
// is expected after this call.
// Similar to GenerateRoutingID but also generates a `frame token`,
// `devtools_frame_token`, and `document_token`. A subsequent call to
// `FrameHost::CreateChildFrame` is expected after this call.
[Sync] GenerateFrameRoutingID() => (int32 routing_id,
blink.mojom.LocalFrameToken frame_token,
mojo_base.mojom.UnguessableToken devtools_frame_token);
mojo_base.mojom.UnguessableToken devtools_frame_token,
blink.mojom.DocumentToken document_token);
// A renderer sends this when it wants to know whether a gpu process exists.
[Sync] HasGpuProcess() => (bool has_gpu_process);

@ -291,7 +291,7 @@ class CONTENT_EXPORT NavigationHandle : public base::SupportsUserData {
// * reference fragment navigations
// * pushState/replaceState
// * same page history navigation
virtual bool IsSameDocument() = 0;
virtual bool IsSameDocument() const = 0;
// Whether the navigation has encountered a server redirect or not.
virtual bool WasServerRedirect() = 0;

@ -77,7 +77,8 @@ class CONTENT_EXPORT RenderThread : virtual public ChildThread {
virtual bool GenerateFrameRoutingID(
int32_t& routing_id,
blink::LocalFrameToken& frame_token,
base::UnguessableToken& devtools_frame_token) = 0;
base::UnguessableToken& devtools_frame_token,
blink::DocumentToken& document_token) = 0;
// These map to IPC::ChannelProxy methods.
virtual void AddFilter(IPC::MessageFilter* filter) = 0;

@ -116,7 +116,7 @@ class MockNavigationHandle : public NavigationHandle {
RenderFrameHost* GetRenderFrameHost() const override {
return render_frame_host_;
}
bool IsSameDocument() override { return is_same_document_; }
bool IsSameDocument() const override { return is_same_document_; }
MOCK_METHOD0(WasServerRedirect, bool());
const std::vector<GURL>& GetRedirectChain() override {
return redirect_chain_;

@ -53,9 +53,11 @@ class MockRenderMessageFilterImpl : public mojom::RenderMessageFilter {
int routing_id;
blink::LocalFrameToken frame_token;
base::UnguessableToken devtools_frame_token;
RenderThread::Get()->GenerateFrameRoutingID(routing_id, frame_token,
devtools_frame_token);
std::move(callback).Run(routing_id, frame_token, devtools_frame_token);
blink::DocumentToken document_token;
RenderThread::Get()->GenerateFrameRoutingID(
routing_id, frame_token, devtools_frame_token, document_token);
std::move(callback).Run(routing_id, frame_token, devtools_frame_token,
document_token);
}
void HasGpuProcess(HasGpuProcessCallback callback) override {
@ -148,10 +150,12 @@ int MockRenderThread::GenerateRoutingID() {
bool MockRenderThread::GenerateFrameRoutingID(
int32_t& routing_id,
blink::LocalFrameToken& frame_token,
base::UnguessableToken& devtools_frame_token) {
base::UnguessableToken& devtools_frame_token,
blink::DocumentToken& document_token) {
routing_id = GetNextRoutingID();
frame_token = blink::LocalFrameToken();
devtools_frame_token = base::UnguessableToken::Create();
document_token = blink::DocumentToken();
return true;
}

@ -65,10 +65,10 @@ class MockRenderThread : public RenderThread {
scoped_refptr<base::SingleThreadTaskRunner> task_runner) override;
void RemoveRoute(int32_t routing_id) override;
int GenerateRoutingID() override;
bool GenerateFrameRoutingID(
int32_t& routing_id,
blink::LocalFrameToken& frame_token,
base::UnguessableToken& devtools_frame_token) override;
bool GenerateFrameRoutingID(int32_t& routing_id,
blink::LocalFrameToken& frame_token,
base::UnguessableToken& devtools_frame_token,
blink::DocumentToken& document_token) override;
void AddFilter(IPC::MessageFilter* filter) override;
void RemoveFilter(IPC::MessageFilter* filter) override;
void AddObserver(RenderThreadObserver* observer) override;

@ -334,7 +334,7 @@ blink::WebView* AgentSchedulingGroup::CreateWebView(
void AgentSchedulingGroup::CreateFrame(mojom::CreateFrameParamsPtr params) {
RenderFrameImpl::CreateFrame(
*this, params->token, params->routing_id, std::move(params->frame),
*this, params->frame_token, params->routing_id, std::move(params->frame),
std::move(params->interface_broker),
std::move(params->associated_interface_provider_remote),
params->previous_frame_token, params->opener_frame_token,
@ -342,7 +342,7 @@ void AgentSchedulingGroup::CreateFrame(mojom::CreateFrameParamsPtr params) {
params->devtools_frame_token, params->tree_scope_type,
std::move(params->replication_state), std::move(params->widget_params),
std::move(params->frame_owner_properties),
params->is_on_initial_empty_document,
params->is_on_initial_empty_document, params->document_token,
std::move(params->policy_container));
}

@ -37,6 +37,7 @@ void NavigationClient::CommitNavigation(
blink::mojom::ServiceWorkerContainerInfoForClientPtr container_info,
mojo::PendingRemote<network::mojom::URLLoaderFactory>
prefetch_loader_factory,
const blink::DocumentToken& document_token,
const base::UnguessableToken& devtools_navigation_token,
const absl::optional<blink::ParsedPermissionsPolicy>& permissions_policy,
blink::mojom::PolicyContainerPtr policy_container,
@ -58,11 +59,11 @@ void NavigationClient::CommitNavigation(
std::move(url_loader_client_endpoints), std::move(subresource_loaders),
std::move(subresource_overrides),
std::move(controller_service_worker_info), std::move(container_info),
std::move(prefetch_loader_factory), devtools_navigation_token,
permissions_policy, std::move(policy_container),
std::move(code_cache_host), std::move(cookie_manager_info),
std::move(storage_info), std::move(not_restored_reasons),
std::move(callback));
std::move(prefetch_loader_factory), document_token,
devtools_navigation_token, permissions_policy,
std::move(policy_container), std::move(code_cache_host),
std::move(cookie_manager_info), std::move(storage_info),
std::move(not_restored_reasons), std::move(callback));
}
void NavigationClient::CommitFailedNavigation(
@ -74,6 +75,7 @@ void NavigationClient::CommitFailedNavigation(
const net::ResolveErrorInfo& resolve_error_info,
const absl::optional<std::string>& error_page_content,
std::unique_ptr<blink::PendingURLLoaderFactoryBundle> subresource_loaders,
const blink::DocumentToken& document_token,
blink::mojom::PolicyContainerPtr policy_container,
mojom::AlternativeErrorPageOverrideInfoPtr alternative_error_page_info,
CommitFailedNavigationCallback callback) {
@ -82,8 +84,8 @@ void NavigationClient::CommitFailedNavigation(
std::move(common_params), std::move(commit_params),
has_stale_copy_in_cache, error_code, extended_error_code,
resolve_error_info, error_page_content, std::move(subresource_loaders),
std::move(policy_container), std::move(alternative_error_page_info),
std::move(callback));
document_token, std::move(policy_container),
std::move(alternative_error_page_info), std::move(callback));
}
void NavigationClient::Bind(

@ -37,6 +37,7 @@ class NavigationClient : mojom::NavigationClient {
blink::mojom::ServiceWorkerContainerInfoForClientPtr container_info,
mojo::PendingRemote<network::mojom::URLLoaderFactory>
prefetch_loader_factory,
const blink::DocumentToken& document_token,
const base::UnguessableToken& devtools_navigation_token,
const absl::optional<blink::ParsedPermissionsPolicy>& permissions_policy,
blink::mojom::PolicyContainerPtr policy_container,
@ -54,6 +55,7 @@ class NavigationClient : mojom::NavigationClient {
const net::ResolveErrorInfo& resolve_error_info,
const absl::optional<std::string>& error_page_content,
std::unique_ptr<blink::PendingURLLoaderFactoryBundle> subresource_loaders,
const blink::DocumentToken& document_token,
blink::mojom::PolicyContainerPtr policy_container,
mojom::AlternativeErrorPageOverrideInfoPtr alternative_error_page_info,
CommitFailedNavigationCallback callback) override;

@ -1476,8 +1476,8 @@ RenderFrameImpl* RenderFrameImpl::CreateMainFrame(
WebLocalFrame* web_frame = WebLocalFrame::CreateMainFrame(
web_view, render_frame, render_frame->blink_interface_registry_.get(),
params->token, ToWebPolicyContainer(std::move(params->policy_container)),
opener,
params->frame_token, params->document_token,
ToWebPolicyContainer(std::move(params->policy_container)), opener,
// This conversion is a little sad, as this often comes from a
// WebString...
WebString::FromUTF8(replication_state->name),
@ -1547,7 +1547,7 @@ RenderFrameImpl* RenderFrameImpl::CreateMainFrame(
// static
void RenderFrameImpl::CreateFrame(
AgentSchedulingGroup& agent_scheduling_group,
const blink::LocalFrameToken& token,
const blink::LocalFrameToken& frame_token,
int routing_id,
mojo::PendingAssociatedReceiver<mojom::Frame> frame_receiver,
mojo::PendingRemote<blink::mojom::BrowserInterfaceBroker>
@ -1564,6 +1564,7 @@ void RenderFrameImpl::CreateFrame(
mojom::CreateFrameWidgetParamsPtr widget_params,
blink::mojom::FrameOwnerPropertiesPtr frame_owner_properties,
bool is_on_initial_empty_document,
const blink::DocumentToken& document_token,
blink::mojom::PolicyContainerPtr policy_container) {
// TODO(danakj): Split this method into two pieces. The first block makes a
// WebLocalFrame and collects the `blink::WebView` and RenderFrame for it. The
@ -1610,8 +1611,9 @@ void RenderFrameImpl::CreateFrame(
replicated_state->frame_policy, render_frame,
render_frame->blink_interface_registry_.get(),
previous_sibling_web_frame,
frame_owner_properties->To<blink::WebFrameOwnerProperties>(), token,
opener, ToWebPolicyContainer(std::move(policy_container)));
frame_owner_properties->To<blink::WebFrameOwnerProperties>(),
frame_token, opener, document_token,
ToWebPolicyContainer(std::move(policy_container)));
// The RenderFrame is created and inserted into the frame tree in the above
// call to createLocalChild.
@ -1635,8 +1637,8 @@ void RenderFrameImpl::CreateFrame(
std::move(browser_interface_broker),
std::move(associated_interface_provider), devtools_frame_token);
web_frame = blink::WebLocalFrame::CreateProvisional(
render_frame, render_frame->blink_interface_registry_.get(), token,
previous_web_frame, replicated_state->frame_policy,
render_frame, render_frame->blink_interface_registry_.get(),
frame_token, previous_web_frame, replicated_state->frame_policy,
WebString::FromUTF8(replicated_state->name));
// The new |web_frame| is a main frame iff the previous frame was.
DCHECK_EQ(!previous_web_frame->Parent(), !web_frame->Parent());
@ -2557,6 +2559,7 @@ void RenderFrameImpl::CommitNavigation(
blink::mojom::ServiceWorkerContainerInfoForClientPtr container_info,
mojo::PendingRemote<network::mojom::URLLoaderFactory>
prefetch_loader_factory,
const blink::DocumentToken& document_token,
const base::UnguessableToken& devtools_navigation_token,
const absl::optional<blink::ParsedPermissionsPolicy>& permissions_policy,
blink::mojom::PolicyContainerPtr policy_container,
@ -2594,8 +2597,8 @@ void RenderFrameImpl::CommitNavigation(
// Check if the navigation being committed originated as a client redirect.
bool is_client_redirect =
!!(common_params->transition & ui::PAGE_TRANSITION_CLIENT_REDIRECT);
auto navigation_params =
std::make_unique<WebNavigationParams>(devtools_navigation_token);
auto navigation_params = std::make_unique<WebNavigationParams>(
document_token, devtools_navigation_token);
navigation_params->is_client_redirect = is_client_redirect;
FillMiscNavigationParams(*common_params, *commit_params,
navigation_params.get());
@ -2852,6 +2855,7 @@ void RenderFrameImpl::CommitFailedNavigation(
const absl::optional<std::string>& error_page_content,
std::unique_ptr<blink::PendingURLLoaderFactoryBundle>
subresource_loader_factories,
const blink::DocumentToken& document_token,
blink::mojom::PolicyContainerPtr policy_container,
mojom::AlternativeErrorPageOverrideInfoPtr alternative_error_page_info,
mojom::NavigationClient::CommitFailedNavigationCallback callback) {
@ -2894,7 +2898,9 @@ void RenderFrameImpl::CommitFailedNavigation(
WebURLError::IsWebSecurityViolation::kFalse, common_params->url,
WebURLError::ShouldCollapseInitiator::kFalse);
auto navigation_params = std::make_unique<WebNavigationParams>();
auto navigation_params = std::make_unique<WebNavigationParams>(
document_token,
/*devtools_navigation_token=*/base::UnguessableToken::Create());
FillNavigationParamsRequest(*common_params, *commit_params,
navigation_params.get());
// Use kUnreachableWebDataURL as the document URL (instead of the URL that
@ -3410,7 +3416,8 @@ blink::WebLocalFrame* RenderFrameImpl::CreateChildFrame(
const blink::FramePolicy& frame_policy,
const blink::WebFrameOwnerProperties& frame_owner_properties,
blink::FrameOwnerElementType frame_owner_element_type,
blink::WebPolicyContainerBindParams policy_container_bind_params) {
blink::WebPolicyContainerBindParams policy_container_bind_params,
FinishChildFrameCreationFn finish_creation) {
// Tracing analysis uses this to find main frames when this value is
// MSG_ROUTING_NONE, and build the frame tree otherwise.
CreateChildFrameTraceEvent trace_event(routing_id_);
@ -3419,8 +3426,10 @@ blink::WebLocalFrame* RenderFrameImpl::CreateChildFrame(
int child_routing_id;
blink::LocalFrameToken frame_token;
base::UnguessableToken devtools_frame_token;
blink::DocumentToken document_token;
if (!RenderThread::Get()->GenerateFrameRoutingID(
child_routing_id, frame_token, devtools_frame_token)) {
child_routing_id, frame_token, devtools_frame_token,
document_token)) {
return nullptr;
}
trace_event.child_routing_id = child_routing_id;
@ -3479,19 +3488,14 @@ blink::WebLocalFrame* RenderFrameImpl::CreateChildFrame(
blink::WebLocalFrame* web_frame = frame_->CreateLocalChild(
scope, child_render_frame,
child_render_frame->blink_interface_registry_.get(), frame_token);
finish_creation(web_frame, document_token);
child_render_frame->in_frame_tree_ = true;
child_render_frame->Initialize(/*parent=*/GetWebFrame());
// The WebLocalFrame created here is not fully initialized yet, so we delay
// our Initialize() step until that has completed, at which point
// InitializeAsChildFrame() is called.
return web_frame;
}
void RenderFrameImpl::InitializeAsChildFrame(blink::WebLocalFrame* parent) {
Initialize(parent);
}
void RenderFrameImpl::DidCreateFencedFrame(
const blink::RemoteFrameToken& frame_token) {
for (auto& observer : observers_)
@ -5223,6 +5227,9 @@ void RenderFrameImpl::SynchronouslyCommitAboutBlankForBug778318(
// TODO(dgozman): should we follow the RFI::CommitNavigation path instead?
auto navigation_params = WebNavigationParams::CreateFromInfo(*info);
// This quirk is internal to the renderer, so just reuse the previous
// DocumentToken.
navigation_params->document_token = frame_->GetDocument().Token();
navigation_params->is_synchronous_commit_for_bug_778318 = true;
// We need the provider to be non-null, otherwise Blink crashes, even
// though the provider should not be used for any actual networking.
@ -6261,11 +6268,12 @@ WebView* RenderFrameImpl::CreateNewWindow(
view_params->devtools_main_frame_token = reply->devtools_main_frame_token;
auto main_frame_params = mojom::CreateLocalMainFrameParams::New();
main_frame_params->token = reply->main_frame_token;
main_frame_params->frame_token = reply->main_frame_token;
main_frame_params->routing_id = reply->main_frame_route_id;
main_frame_params->frame = std::move(reply->frame);
main_frame_params->interface_broker =
std::move(reply->main_frame_interface_broker);
main_frame_params->document_token = reply->document_token;
main_frame_params->policy_container = std::move(reply->policy_container);
main_frame_params->associated_interface_provider_remote =
std::move(reply->associated_interface_provider);

@ -225,6 +225,7 @@ class CONTENT_EXPORT RenderFrameImpl
mojom::CreateFrameWidgetParamsPtr widget_params,
blink::mojom::FrameOwnerPropertiesPtr frame_owner_properties,
bool is_on_initial_empty_document,
const blink::DocumentToken& document_token,
blink::mojom::PolicyContainerPtr policy_container);
// Returns the RenderFrameImpl for the given routing ID.
@ -440,6 +441,7 @@ class CONTENT_EXPORT RenderFrameImpl
blink::mojom::ServiceWorkerContainerInfoForClientPtr container_info,
mojo::PendingRemote<network::mojom::URLLoaderFactory>
prefetch_loader_factory,
const blink::DocumentToken& document_token,
const base::UnguessableToken& devtools_navigation_token,
const absl::optional<blink::ParsedPermissionsPolicy>& permissions_policy,
blink::mojom::PolicyContainerPtr policy_container,
@ -458,6 +460,7 @@ class CONTENT_EXPORT RenderFrameImpl
const absl::optional<std::string>& error_page_content,
std::unique_ptr<blink::PendingURLLoaderFactoryBundle>
subresource_loader_factories,
const blink::DocumentToken& document_token,
blink::mojom::PolicyContainerPtr policy_container,
mojom::AlternativeErrorPageOverrideInfoPtr alternative_error_page_info,
mojom::NavigationClient::CommitFailedNavigationCallback
@ -505,9 +508,8 @@ class CONTENT_EXPORT RenderFrameImpl
const blink::FramePolicy& frame_policy,
const blink::WebFrameOwnerProperties& frame_owner_properties,
blink::FrameOwnerElementType frame_owner_element_type,
blink::WebPolicyContainerBindParams policy_container_bind_params)
override;
void InitializeAsChildFrame(blink::WebLocalFrame* parent) override;
blink::WebPolicyContainerBindParams policy_container_bind_params,
FinishChildFrameCreationFn finish_creation) override;
void DidCreateFencedFrame(
const blink::RemoteFrameToken& frame_token) override;
blink::WebFrame* FindFrame(const blink::WebString& name) override;

@ -168,7 +168,7 @@ class RenderFrameImplTest : public RenderViewTest {
blink::mojom::TreeScopeType::kDocument,
std::move(frame_replication_state), std::move(widget_params),
blink::mojom::FrameOwnerProperties::New(),
/*has_committed_real_load=*/true,
/*has_committed_real_load=*/true, blink::DocumentToken(),
blink::mojom::PolicyContainer::New(
blink::mojom::PolicyContainerPolicies::New(),
mock_policy_container_host

@ -797,9 +797,10 @@ int RenderThreadImpl::GenerateRoutingID() {
bool RenderThreadImpl::GenerateFrameRoutingID(
int32_t& routing_id,
blink::LocalFrameToken& frame_token,
base::UnguessableToken& devtools_frame_token) {
base::UnguessableToken& devtools_frame_token,
blink::DocumentToken& document_token) {
return render_message_filter()->GenerateFrameRoutingID(
&routing_id, &frame_token, &devtools_frame_token);
&routing_id, &frame_token, &devtools_frame_token, &document_token);
}
void RenderThreadImpl::AddFilter(IPC::MessageFilter* filter) {

@ -160,10 +160,10 @@ class CONTENT_EXPORT RenderThreadImpl
scoped_refptr<base::SingleThreadTaskRunner> task_runner) override;
void RemoveRoute(int32_t routing_id) override;
int GenerateRoutingID() override;
bool GenerateFrameRoutingID(
int32_t& routing_id,
blink::LocalFrameToken& frame_token,
base::UnguessableToken& devtools_frame_token) override;
bool GenerateFrameRoutingID(int32_t& routing_id,
blink::LocalFrameToken& frame_token,
base::UnguessableToken& devtools_frame_token,
blink::DocumentToken& document_token) override;
void AddFilter(IPC::MessageFilter* filter) override;
void RemoveFilter(IPC::MessageFilter* filter) override;
void AddObserver(RenderThreadObserver* observer) override;

@ -1142,7 +1142,8 @@ TEST_F(RenderViewImplScaleFactorTest, DeviceScaleCorrectAfterCrossOriginNav) {
base::UnguessableToken::Create(), blink::mojom::TreeScopeType::kDocument,
std::move(replication_state), std::move(widget_params),
blink::mojom::FrameOwnerProperties::New(),
/*is_on_initial_empty_document=*/true, CreateStubPolicyContainer());
/*is_on_initial_empty_document=*/true, blink::DocumentToken(),
CreateStubPolicyContainer());
TestRenderFrame* provisional_frame =
static_cast<TestRenderFrame*>(RenderFrameImpl::FromRoutingID(routing_id));
@ -1208,7 +1209,8 @@ TEST_F(RenderViewImplTest, DetachingProxyAlsoDestroysProvisionalFrame) {
base::UnguessableToken::Create(), blink::mojom::TreeScopeType::kDocument,
std::move(replication_state),
/*widget_params=*/nullptr, blink::mojom::FrameOwnerProperties::New(),
/*is_on_initial_empty_document=*/true, CreateStubPolicyContainer());
/*is_on_initial_empty_document=*/true, blink::DocumentToken(),
CreateStubPolicyContainer());
{
TestRenderFrame* provisional_frame = static_cast<TestRenderFrame*>(
RenderFrameImpl::FromRoutingID(routing_id));

@ -166,6 +166,8 @@ static_library("content_shell_lib") {
"common/shell_switches.h",
"gpu/shell_content_gpu_client.cc",
"gpu/shell_content_gpu_client.h",
"renderer/render_frame_test_helper.cc",
"renderer/render_frame_test_helper.h",
"renderer/shell_content_renderer_client.cc",
"renderer/shell_content_renderer_client.h",
"renderer/shell_render_frame_observer.cc",
@ -862,8 +864,12 @@ mojom("content_browsertests_mojom") {
sources = [
"common/main_frame_counter_test.mojom",
"common/power_monitor_test.mojom",
"common/render_frame_test_helper.mojom",
]
public_deps = [
"//sandbox/policy/mojom",
"//third_party/blink/public/mojom/tokens",
]
public_deps = [ "//sandbox/policy/mojom" ]
}
group("content_shell_crash_test") {

@ -0,0 +1,15 @@
// 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.
module content.mojom;
import "third_party/blink/public/mojom/tokens/tokens.mojom";
// Helper to facilitate testing of renderer-side state in content_browsertests.
interface RenderFrameTestHelper {
// Get the DocumentToken for the RenderFrame's active document. A RenderFrame
// can be reused for a cross-document navigation; after the navigation, the
// newly-committed document is considered the active document.
GetDocumentToken() => (blink.mojom.DocumentToken token);
};

@ -0,0 +1,39 @@
// 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/shell/renderer/render_frame_test_helper.h"
#include <utility>
#include "content/public/renderer/render_frame.h"
#include "third_party/blink/public/common/tokens/tokens.h"
#include "third_party/blink/public/web/web_document.h"
#include "third_party/blink/public/web/web_local_frame.h"
namespace content {
void RenderFrameTestHelper::Create(
RenderFrame& render_frame,
mojo::PendingReceiver<mojom::RenderFrameTestHelper> receiver) {
new RenderFrameTestHelper(render_frame, std::move(receiver));
}
RenderFrameTestHelper::~RenderFrameTestHelper() {}
void RenderFrameTestHelper::GetDocumentToken(
GetDocumentTokenCallback callback) {
std::move(callback).Run(render_frame()->GetWebFrame()->GetDocument().Token());
}
void RenderFrameTestHelper::OnDestruct() {
delete this;
}
RenderFrameTestHelper::RenderFrameTestHelper(
RenderFrame& render_frame,
mojo::PendingReceiver<mojom::RenderFrameTestHelper> receiver)
: RenderFrameObserver(&render_frame),
receiver_(this, std::move(receiver)) {}
} // namespace content

@ -0,0 +1,42 @@
// 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.
#ifndef CONTENT_SHELL_RENDERER_RENDER_FRAME_TEST_HELPER_H_
#define CONTENT_SHELL_RENDERER_RENDER_FRAME_TEST_HELPER_H_
#include "content/public/renderer/render_frame_observer.h"
#include "content/shell/common/render_frame_test_helper.mojom.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/receiver.h"
namespace content {
class RenderFrameTestHelper : public mojom::RenderFrameTestHelper,
public RenderFrameObserver {
public:
// Creates a new instance that deletes itself when the RenderFrame is
// destroyed.
static void Create(
RenderFrame& render_frame,
mojo::PendingReceiver<mojom::RenderFrameTestHelper> receiver);
~RenderFrameTestHelper() override;
// mojom::RenderFrameTestHelper overrides:
void GetDocumentToken(GetDocumentTokenCallback callback) override;
// RenderFrameObserver overrides:
void OnDestruct() override;
private:
explicit RenderFrameTestHelper(
RenderFrame& render_frame,
mojo::PendingReceiver<mojom::RenderFrameTestHelper> receiver);
const mojo::Receiver<mojom::RenderFrameTestHelper> receiver_;
};
} // namespace content
#endif // CONTENT_SHELL_RENDERER_RENDER_FRAME_TEST_HELPER_H_

@ -7,7 +7,9 @@
#include "base/command_line.h"
#include "content/public/renderer/render_frame.h"
#include "content/public/renderer/render_frame_observer.h"
#include "content/shell/common/render_frame_test_helper.mojom.h"
#include "content/shell/common/shell_switches.h"
#include "content/shell/renderer/render_frame_test_helper.h"
#include "third_party/blink/public/web/web_testing_support.h"
namespace content {
@ -17,6 +19,10 @@ ShellRenderFrameObserver::ShellRenderFrameObserver(RenderFrame* render_frame)
ShellRenderFrameObserver::~ShellRenderFrameObserver() = default;
void ShellRenderFrameObserver::OnDestruct() {
delete this;
}
void ShellRenderFrameObserver::DidClearWindowObject() {
auto& cmd = *base::CommandLine::ForCurrentProcess();
if (cmd.HasSwitch(switches::kExposeInternalsForTesting)) {
@ -25,8 +31,15 @@ void ShellRenderFrameObserver::DidClearWindowObject() {
}
}
void ShellRenderFrameObserver::OnDestruct() {
delete this;
void ShellRenderFrameObserver::OnInterfaceRequestForFrame(
const std::string& interface_name,
mojo::ScopedMessagePipeHandle* interface_pipe) {
if (interface_name == mojom::RenderFrameTestHelper::Name_) {
RenderFrameTestHelper::Create(
*render_frame(), mojo::PendingReceiver<mojom::RenderFrameTestHelper>(
std::move(*interface_pipe)));
return;
}
}
} // namespace content

@ -19,8 +19,11 @@ class ShellRenderFrameObserver : public RenderFrameObserver {
private:
// RenderFrameObserver implementation.
void DidClearWindowObject() override;
void OnDestruct() override;
void DidClearWindowObject() override;
void OnInterfaceRequestForFrame(
const std::string& interface_name,
mojo::ScopedMessagePipeHandle* interface_pipe) override;
};
} // namespace content

@ -1374,6 +1374,7 @@ test("content_browsertests") {
"../browser/renderer_host/close_listener_host_browsertest.cc",
"../browser/renderer_host/cookie_browsertest.cc",
"../browser/renderer_host/document_service_browsertest.cc",
"../browser/renderer_host/document_token_browsertest.cc",
"../browser/renderer_host/document_user_data_browsertest.cc",
"../browser/renderer_host/embedding_token_browsertest.cc",
"../browser/renderer_host/frame_tree_browsertest.cc",

@ -267,7 +267,7 @@ void TestRenderFrame::Navigate(
std::move(pending_factory_bundle), absl::nullopt,
blink::mojom::ControllerServiceWorkerInfoPtr(),
blink::mojom::ServiceWorkerContainerInfoForClientPtr(),
mojo::NullRemote() /* prefetch_loader_factory */,
mojo::NullRemote() /* prefetch_loader_factory */, blink::DocumentToken(),
base::UnguessableToken::Create(), blink::ParsedPermissionsPolicy(),
blink::mojom::PolicyContainer::New(
blink::mojom::PolicyContainerPolicies::New(),
@ -301,7 +301,8 @@ void TestRenderFrame::NavigateWithError(
std::move(common_params), std::move(commit_params),
/*has_stale_copy_in_cache=*/false, error_code,
/*extended_error_code=*/0, resolve_error_info, error_page_content,
std::move(pending_factory_bundle), CreateStubPolicyContainer(),
std::move(pending_factory_bundle), blink::DocumentToken(),
CreateStubPolicyContainer(),
/*alternative_error_page_info=*/nullptr,
base::BindOnce(&MockFrameHost::DidCommitProvisionalLoad,
base::Unretained(mock_frame_host_.get())));

@ -71,6 +71,7 @@ TestRenderFrameHost::TestRenderFrameHost(
int32_t routing_id,
mojo::PendingAssociatedRemote<mojom::Frame> frame_remote,
const blink::LocalFrameToken& frame_token,
const blink::DocumentToken& document_token,
RenderFrameHostImpl::LifecycleStateImpl lifecycle_state,
scoped_refptr<BrowsingContextState> browsing_context_state)
: RenderFrameHostImpl(site_instance,
@ -81,6 +82,7 @@ TestRenderFrameHost::TestRenderFrameHost(
routing_id,
std::move(frame_remote),
frame_token,
document_token,
/*renderer_initiated_creation_of_main_frame=*/false,
lifecycle_state,
browsing_context_state,
@ -178,6 +180,7 @@ TestRenderFrameHost* TestRenderFrameHost::AppendChildWithPolicy(
CreateStubAssociatedInterfaceProviderReceiver(),
blink::mojom::TreeScopeType::kDocument, frame_name, frame_unique_name,
false, blink::LocalFrameToken(), base::UnguessableToken::Create(),
blink::DocumentToken(),
blink::FramePolicy({network::mojom::WebSandboxFlags::kNone, allow, {}}),
blink::mojom::FrameOwnerProperties(),
blink::FrameOwnerElementType::kIframe);
@ -588,6 +591,7 @@ void TestRenderFrameHost::SendCommitNavigation(
prefetch_loader_factory,
const absl::optional<blink::ParsedPermissionsPolicy>& permissions_policy,
blink::mojom::PolicyContainerPtr policy_container,
const blink::DocumentToken& document_token,
const base::UnguessableToken& devtools_navigation_token) {
CHECK(navigation_client);
commit_callback_[navigation_request] =
@ -605,6 +609,7 @@ void TestRenderFrameHost::SendCommitFailedNavigation(
const absl::optional<std::string>& error_page_content,
std::unique_ptr<blink::PendingURLLoaderFactoryBundle>
subresource_loader_factories,
const blink::DocumentToken& document_token,
blink::mojom::PolicyContainerPtr policy_container) {
CHECK(navigation_client);
commit_failed_callback_[navigation_request] =

@ -67,6 +67,7 @@ class TestRenderFrameHost : public RenderFrameHostImpl,
int32_t routing_id,
mojo::PendingAssociatedRemote<mojom::Frame> frame_remote,
const blink::LocalFrameToken& frame_token,
const blink::DocumentToken& document_token,
LifecycleStateImpl lifecycle_state,
scoped_refptr<BrowsingContextState> browsing_context_state);
@ -269,6 +270,7 @@ class TestRenderFrameHost : public RenderFrameHostImpl,
prefetch_loader_factory,
const absl::optional<blink::ParsedPermissionsPolicy>& permissions_policy,
blink::mojom::PolicyContainerPtr policy_container,
const blink::DocumentToken& document_token,
const base::UnguessableToken& devtools_navigation_token) override;
void SendCommitFailedNavigation(
mojom::NavigationClient* navigation_client,
@ -281,6 +283,7 @@ class TestRenderFrameHost : public RenderFrameHostImpl,
const absl::optional<std::string>& error_page_content,
std::unique_ptr<blink::PendingURLLoaderFactoryBundle>
subresource_loader_factories,
const blink::DocumentToken& document_token,
blink::mojom::PolicyContainerPtr policy_container) override;
private:

@ -28,6 +28,7 @@ TestRenderFrameHostFactory::CreateRenderFrameHost(
int32_t routing_id,
mojo::PendingAssociatedRemote<mojom::Frame> frame_remote,
const blink::LocalFrameToken& frame_token,
const blink::DocumentToken& document_token,
bool renderer_initiated_creation,
RenderFrameHostImpl::LifecycleStateImpl lifecycle_state,
scoped_refptr<BrowsingContextState> browsing_context_state) {
@ -35,7 +36,7 @@ TestRenderFrameHostFactory::CreateRenderFrameHost(
return std::make_unique<TestRenderFrameHost>(
site_instance, std::move(render_view_host), delegate, frame_tree,
frame_tree_node, routing_id, std::move(frame_remote), frame_token,
lifecycle_state, std::move(browsing_context_state));
document_token, lifecycle_state, std::move(browsing_context_state));
}
} // namespace content

@ -39,6 +39,7 @@ class TestRenderFrameHostFactory : public RenderFrameHostFactory {
int32_t routing_id,
mojo::PendingAssociatedRemote<mojom::Frame> frame_remote,
const blink::LocalFrameToken& frame_token,
const blink::DocumentToken& document_token,
bool renderer_initiated_creation,
RenderFrameHostImpl::LifecycleStateImpl lifecycle_state,
scoped_refptr<BrowsingContextState> browsing_context_state) override;

@ -35,6 +35,7 @@ ScopedWebFrame::ScopedWebFrame()
&frame_client_,
nullptr,
blink::LocalFrameToken(),
blink::DocumentToken(),
nullptr)) {
view_->DidAttachLocalMainFrame();
}

@ -2,6 +2,7 @@ include_rules = [
"+base/callback.h",
"+base/callback_forward.h",
"+base/callback_helpers.h",
"+base/functional/function_ref.h",
"+base/memory/raw_ptr.h",
"+base/notreached.h",
"+base/observer_list.h",

@ -21,6 +21,10 @@ namespace blink {
//
// See README.md for more details.
////////////////////////////////////////////////////////////////////////////////
// DOCUMENT TOKENS
using DocumentToken = base::TokenType<class DocumentTokenTypeMarker>;
////////////////////////////////////////////////////////////////////////////////
// FRAME TOKENS

@ -15,6 +15,13 @@ namespace mojo {
// Mojom traits for the various token types.
// See third_party/blink/public/common/tokens/tokens.h for more details.
////////////////////////////////////////////////////////////////////////////////
// DOCUMENT TOKENS
template <>
struct StructTraits<blink::mojom::DocumentTokenDataView, blink::DocumentToken>
: public blink::TokenMojomTraitsHelper<blink::mojom::DocumentTokenDataView,
blink::DocumentToken> {};
////////////////////////////////////////////////////////////////////////////////
// FRAME TOKENS

@ -14,6 +14,12 @@ mojom_component("tokens") {
shared_cpp_typemaps = [
{
types = [
# DOCUMENT TOKENS
{
mojom = "blink.mojom.DocumentToken"
cpp = "::blink::DocumentToken"
},
# FRAME TOKENS
{
mojom = "blink.mojom.LocalFrameToken"

@ -16,6 +16,12 @@ import "mojo/public/mojom/base/unguessable_token.mojom";
//
// See third_party/blink/public/common/tokens/tokens.h for more details.
////////////////////////////////////////////////////////////////////////////////
// DOCUMENT TOKENS
struct DocumentToken {
mojo_base.mojom.UnguessableToken value;
};
////////////////////////////////////////////////////////////////////////////////
// FRAME TOKENS
@ -113,4 +119,4 @@ struct PortalToken {
struct V8ContextToken {
mojo_base.mojom.UnguessableToken value;
};
};

@ -35,6 +35,7 @@
#include "services/metrics/public/cpp/ukm_source_id.h"
#include "services/network/public/mojom/referrer_policy.mojom-shared.h"
#include "services/network/public/mojom/restricted_cookie_manager.mojom-shared.h"
#include "third_party/blink/public/common/tokens/tokens.h"
#include "third_party/blink/public/platform/cross_variant_mojo_util.h"
#include "third_party/blink/public/platform/web_common.h"
#include "third_party/blink/public/platform/web_security_origin.h"
@ -77,7 +78,9 @@ class BLINK_EXPORT WebDocument : public WebNode {
}
void Assign(const WebDocument& e) { WebNode::Assign(e); }
const DocumentToken& Token() const;
WebURL Url() const;
// Note: Security checks should use the getSecurityOrigin(), not url().
WebSecurityOrigin GetSecurityOrigin() const;
bool IsSecureContext() const;

@ -130,6 +130,7 @@ class BLINK_EXPORT WebLocalFrame : public WebFrame {
WebLocalFrameClient*,
blink::InterfaceRegistry*,
const LocalFrameToken& frame_token,
const DocumentToken& document_token,
std::unique_ptr<blink::WebPolicyContainer> policy_container,
WebFrame* opener = nullptr,
const WebString& name = WebString(),

@ -34,6 +34,7 @@
#include <memory>
#include <utility>
#include "base/functional/function_ref.h"
#include "base/i18n/rtl.h"
#include "base/notreached.h"
#include "base/unguessable_token.h"
@ -233,8 +234,13 @@ class BLINK_EXPORT WebLocalFrameClient {
// Request the creation of a new child frame. Embedders may return nullptr
// to prevent the new child frame from being attached. Otherwise, embedders
// should create a new WebLocalFrame, insert it into the frame tree, and
// return the created frame.
// should create a new WebLocalFrame, insert it into the frame tree, call
// `complete_creation()`, and return the created frame.
//
// `complete_creation` takes the newly-created `WebLocalFrame` and the
// `DocumentToken` to use for its initial empty document as arguments.
using FinishChildFrameCreationFn =
base::FunctionRef<void(WebLocalFrame*, const DocumentToken&)>;
virtual WebLocalFrame* CreateChildFrame(
mojom::TreeScopeType,
const WebString& name,
@ -242,14 +248,10 @@ class BLINK_EXPORT WebLocalFrameClient {
const FramePolicy&,
const WebFrameOwnerProperties&,
FrameOwnerElementType,
WebPolicyContainerBindParams policy_container_bind_params) {
WebPolicyContainerBindParams policy_container_bind_params,
FinishChildFrameCreationFn complete_creation) {
return nullptr;
}
// When CreateChildFrame() returns there is no core LocalFrame backing the
// WebFrame yet so using the WebLocalFrame is not entirely valid. This is
// called after finishing the initialization of WebLocalFrame so that the
// client can complete its initialization making use of it.
virtual void InitializeAsChildFrame(WebLocalFrame* parent) {}
// Notification a new fenced frame was created.
virtual void DidCreateFencedFrame(const blink::RemoteFrameToken& token) {}

@ -181,9 +181,11 @@ struct BLINK_EXPORT WebNavigationParams {
WebNavigationParams();
~WebNavigationParams();
// Allows to specify |devtools_navigation_token|, instead of creating
// a new one.
explicit WebNavigationParams(const base::UnguessableToken&);
// Construct with a specific `document_token` and `devtools_navigation_token`,
// rather than randomly creating new ones.
explicit WebNavigationParams(
const blink::DocumentToken& document_token,
const base::UnguessableToken& devtools_navigation_token);
// Shortcut for navigating based on WebNavigationInfo parameters.
//
@ -324,6 +326,7 @@ struct BLINK_EXPORT WebNavigationParams {
// taking into account the origin computed by the renderer.
StorageKey storage_key;
blink::DocumentToken document_token;
// The devtools token for this navigation. See DocumentLoader
// for details.
base::UnguessableToken devtools_navigation_token;

@ -64,6 +64,7 @@ class BLINK_EXPORT WebRemoteFrame : public WebFrame {
const WebFrameOwnerProperties&,
const LocalFrameToken& frame_token,
WebFrame* opener,
const DocumentToken& document_token,
std::unique_ptr<WebPolicyContainer> policy_container) = 0;
// Returns the frame associated with the |frame_token|.

@ -690,6 +690,7 @@ Document::Document(const DocumentInit& initializer,
&Document::OnAdoptedStyleSheetSet),
static_cast<V8ObservableArrayCSSStyleSheet::DeleteAlgorithmCallback>(
&Document::OnAdoptedStyleSheetDelete)),
token_(initializer.GetToken()),
is_initial_empty_document_(initializer.IsInitialEmptyDocument()),
is_prerendering_(initializer.IsPrerendering()),
evaluate_media_queries_on_style_recalc_(false),

@ -44,6 +44,7 @@
#include "services/network/public/mojom/web_sandbox_flags.mojom-blink-forward.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "third_party/blink/public/common/metrics/document_update_reason.h"
#include "third_party/blink/public/common/tokens/tokens.h"
#include "third_party/blink/public/mojom/css/preferred_color_scheme.mojom-blink-forward.h"
#include "third_party/blink/public/mojom/frame/color_scheme.mojom-blink-forward.h"
#include "third_party/blink/public/mojom/input/focus_type.mojom-blink-forward.h"
@ -848,6 +849,8 @@ class CORE_EXPORT Document : public ContainerNode,
bool WellFormed() const { return well_formed_; }
const DocumentToken& Token() const { return token_; }
// Return the document URL, or an empty URL if it's unavailable.
// This is not an implementation of web-exposed Document.prototype.URL.
const KURL& Url() const { return url_; }
@ -2118,6 +2121,8 @@ class CORE_EXPORT Document : public ContainerNode,
void RunPostPrerenderingActivationSteps();
const DocumentToken token_;
// Bitfield used for tracking UKM sampling of media features such that each
// media feature is sampled only once per document.
uint64_t evaluated_media_features_ = 0;

@ -30,6 +30,7 @@
#include "third_party/blink/renderer/core/dom/document_init.h"
#include "services/metrics/public/cpp/ukm_source_id.h"
#include "third_party/blink/public/common/tokens/tokens.h"
#include "third_party/blink/public/mojom/security_context/insecure_request_policy.mojom-blink.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/dom/dom_implementation.h"
@ -97,6 +98,18 @@ DocumentInit& DocumentInit::WithWindow(LocalDOMWindow* window,
return *this;
}
DocumentInit& DocumentInit::WithToken(const DocumentToken& token) {
token_ = token;
return *this;
}
const DocumentToken& DocumentInit::GetToken() const {
if (!token_) {
token_.emplace();
}
return *token_;
}
DocumentInit& DocumentInit::ForInitialEmptyDocument(bool empty) {
is_initial_empty_document_ = empty;
return *this;

@ -32,6 +32,7 @@
#include "base/dcheck_is_on.h"
#include "services/metrics/public/cpp/ukm_source_id.h"
#include "third_party/blink/public/common/tokens/tokens.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/execution_context/security_context.h"
#include "third_party/blink/renderer/platform/graphics/color.h"
@ -100,6 +101,9 @@ class CORE_EXPORT DocumentInit final {
DocumentInit& WithWindow(LocalDOMWindow*, Document* owner_document);
LocalDOMWindow* GetWindow() const { return window_; }
DocumentInit& WithToken(const DocumentToken& token);
const DocumentToken& GetToken() const;
DocumentInit& ForInitialEmptyDocument(bool empty);
bool IsInitialEmptyDocument() const { return is_initial_empty_document_; }
@ -147,6 +151,9 @@ class CORE_EXPORT DocumentInit final {
bool is_initial_empty_document_ = false;
String mime_type_;
LocalDOMWindow* window_ = nullptr;
// Mutable because the token is lazily-generated on demand if no token is
// explicitly set.
mutable absl::optional<DocumentToken> token_;
ExecutionContext* execution_context_ = nullptr;
KURL url_;
Document* owner_document_ = nullptr;

@ -926,7 +926,8 @@ static Document* CreateStagingDocumentForMarkupSanitization(
MakeGarbageCollected<LocalFrameView>(*frame, gfx::Size(800, 600));
frame->SetView(frame_view);
// TODO(https://crbug.com/1355751) Initialize `storage_key`.
frame->Init(/*opener=*/nullptr, /*policy_container=*/nullptr, StorageKey());
frame->Init(/*opener=*/nullptr, DocumentToken(), /*policy_container=*/nullptr,
StorageKey());
Document* document = frame->GetDocument();
DCHECK(document);

@ -82,6 +82,10 @@ static const blink::WebStyleSheetKey GenerateStyleSheetKey() {
namespace blink {
const DocumentToken& WebDocument::Token() const {
return ConstUnwrap<Document>()->Token();
}
WebURL WebDocument::Url() const {
return ConstUnwrap<Document>()->Url();
}

@ -19,8 +19,10 @@ WebNavigationParams::WebNavigationParams()
WebNavigationParams::~WebNavigationParams() = default;
WebNavigationParams::WebNavigationParams(
const blink::DocumentToken& document_token,
const base::UnguessableToken& devtools_navigation_token)
: http_method(http_names::kGET),
document_token(document_token),
devtools_navigation_token(devtools_navigation_token) {}
// static

@ -400,7 +400,8 @@ WebPagePopupImpl::WebPagePopupImpl(
}
// TODO(https://crbug.com/1355751) Initialize `storage_key`.
frame->Init(/*opener=*/nullptr, /*policy_container=*/nullptr, StorageKey());
frame->Init(/*opener=*/nullptr, DocumentToken(), /*policy_container=*/nullptr,
StorageKey());
frame->View()->SetParentVisible(true);
frame->View()->SetSelfVisible(true);

@ -202,10 +202,11 @@ class TestPluginWebFrameClient : public frame_test_helpers::TestWebFrameClient {
const FramePolicy&,
const WebFrameOwnerProperties&,
FrameOwnerElementType owner_type,
WebPolicyContainerBindParams policy_container_bind_params) override {
return CreateLocalChild(*Frame(), scope,
std::make_unique<TestPluginWebFrameClient>(),
std::move(policy_container_bind_params));
WebPolicyContainerBindParams policy_container_bind_params,
FinishChildFrameCreationFn finish_creation) override {
return CreateLocalChild(
*Frame(), scope, std::make_unique<TestPluginWebFrameClient>(),
std::move(policy_container_bind_params), finish_creation);
}
WebPlugin* CreatePlugin(const WebPluginParams& params) override {

@ -488,7 +488,8 @@ TEST_F(WebViewTest, SetBaseBackgroundColorBeforeMainFrame) {
frame_test_helpers::TestWebFrameClient web_frame_client;
WebLocalFrame* frame = WebLocalFrame::CreateMainFrame(
web_view, &web_frame_client, nullptr, LocalFrameToken(), nullptr);
web_view, &web_frame_client, nullptr, LocalFrameToken(), DocumentToken(),
nullptr);
web_frame_client.Bind(frame);
frame_test_helpers::TestWebFrameWidget* widget =
@ -2737,7 +2738,8 @@ TEST_F(WebViewTest, ClientTapHandlingNullWebViewClient) {
/*page_base_background_color=*/absl::nullopt));
frame_test_helpers::TestWebFrameClient web_frame_client;
WebLocalFrame* local_frame = WebLocalFrame::CreateMainFrame(
web_view, &web_frame_client, nullptr, LocalFrameToken(), nullptr);
web_view, &web_frame_client, nullptr, LocalFrameToken(), DocumentToken(),
nullptr);
web_frame_client.Bind(local_frame);
WebNonCompositedWidgetClient widget_client;
frame_test_helpers::TestWebFrameWidget* widget =
@ -4087,7 +4089,9 @@ class CreateChildCounterFrameClient
const FramePolicy&,
const WebFrameOwnerProperties&,
FrameOwnerElementType,
WebPolicyContainerBindParams policy_container_bind_params) override;
WebPolicyContainerBindParams policy_container_bind_params,
base::FunctionRef<void(WebLocalFrame*, const DocumentToken&)>
complete_initialization) override;
int Count() const { return count_; }
@ -4102,11 +4106,14 @@ WebLocalFrame* CreateChildCounterFrameClient::CreateChildFrame(
const FramePolicy& frame_policy,
const WebFrameOwnerProperties& frame_owner_properties,
FrameOwnerElementType frame_owner_element_type,
WebPolicyContainerBindParams policy_container_bind_params) {
WebPolicyContainerBindParams policy_container_bind_params,
base::FunctionRef<void(WebLocalFrame*, const DocumentToken&)>
complete_initialization) {
++count_;
return TestWebFrameClient::CreateChildFrame(
scope, name, fallback_name, frame_policy, frame_owner_properties,
frame_owner_element_type, std::move(policy_container_bind_params));
frame_owner_element_type, std::move(policy_container_bind_params),
complete_initialization);
}
TEST_F(WebViewTest, ChangeDisplayMode) {

@ -288,7 +288,8 @@ WebLocalFrameImpl* CreateLocalChild(
WebLocalFrame& parent,
mojom::blink::TreeScopeType scope,
TestWebFrameClient* client,
WebPolicyContainerBindParams policy_container_bind_params) {
WebPolicyContainerBindParams policy_container_bind_params,
WebLocalFrameClient::FinishChildFrameCreationFn finish_creation) {
MockPolicyContainerHost mock_policy_container_host;
mock_policy_container_host.BindWithNewEndpoint(
std::move(policy_container_bind_params.receiver));
@ -297,6 +298,7 @@ WebLocalFrameImpl* CreateLocalChild(
auto* frame = To<WebLocalFrameImpl>(
parent.CreateLocalChild(scope, client, nullptr, LocalFrameToken()));
client->Bind(frame, std::move(owned_client));
finish_creation(frame, DocumentToken());
return frame;
}
@ -304,7 +306,8 @@ WebLocalFrameImpl* CreateLocalChild(
WebLocalFrame& parent,
mojom::blink::TreeScopeType scope,
std::unique_ptr<TestWebFrameClient> self_owned,
WebPolicyContainerBindParams policy_container_bind_params) {
WebPolicyContainerBindParams policy_container_bind_params,
WebLocalFrameClient::FinishChildFrameCreationFn finish_creation) {
MockPolicyContainerHost mock_policy_container_host;
mock_policy_container_host.BindWithNewEndpoint(
std::move(policy_container_bind_params.receiver));
@ -313,6 +316,7 @@ WebLocalFrameImpl* CreateLocalChild(
auto* frame = To<WebLocalFrameImpl>(
parent.CreateLocalChild(scope, client, nullptr, LocalFrameToken()));
client->Bind(frame, std::move(self_owned));
finish_creation(frame, DocumentToken());
return frame;
}
@ -426,7 +430,7 @@ WebViewImpl* WebViewHelper::InitializeWithOpener(
web_frame_client =
CreateDefaultClientIfNeeded(web_frame_client, owned_web_frame_client);
WebLocalFrame* frame = WebLocalFrame::CreateMainFrame(
web_view_, web_frame_client, nullptr, LocalFrameToken(),
web_view_, web_frame_client, nullptr, LocalFrameToken(), DocumentToken(),
// Passing a null policy_container will create an empty, default policy
// container.
/*policy_container=*/nullptr, opener,
@ -526,6 +530,7 @@ WebLocalFrameImpl* WebViewHelper::CreateLocalChild(
auto* frame = To<WebLocalFrameImpl>(parent.CreateLocalChild(
mojom::blink::TreeScopeType::kDocument, name, FramePolicy(), client,
nullptr, previous_sibling, properties, LocalFrameToken(), nullptr,
DocumentToken(),
std::make_unique<WebPolicyContainer>(
WebPolicyContainerPolicies(),
mock_policy_container_host.BindNewEndpointAndPassDedicatedRemote())));
@ -730,7 +735,8 @@ WebLocalFrame* TestWebFrameClient::CreateChildFrame(
const FramePolicy& frame_policy,
const WebFrameOwnerProperties&,
FrameOwnerElementType,
WebPolicyContainerBindParams policy_container_bind_params) {
WebPolicyContainerBindParams policy_container_bind_params,
FinishChildFrameCreationFn finish_creation) {
MockPolicyContainerHost mock_policy_container_host;
mock_policy_container_host.BindWithNewEndpoint(
std::move(policy_container_bind_params.receiver));
@ -740,11 +746,10 @@ WebLocalFrame* TestWebFrameClient::CreateChildFrame(
client->sandbox_flags_ = frame_policy.sandbox_flags;
TestWebFrameClient* client_ptr = client.get();
client_ptr->Bind(frame, std::move(client));
finish_creation(frame, DocumentToken());
return frame;
}
void TestWebFrameClient::InitializeAsChildFrame(WebLocalFrame* parent) {}
void TestWebFrameClient::DidStartLoading() {
++loads_in_progress_;
}

@ -37,6 +37,7 @@
#include <string>
#include "base/callback_helpers.h"
#include "base/functional/function_ref.h"
#include "base/memory/weak_ptr.h"
#include "cc/test/fake_layer_tree_frame_sink.h"
#include "cc/trees/layer_tree_host.h"
@ -126,9 +127,10 @@ WebMouseEvent CreateMouseEvent(WebInputEvent::Type,
// Helper for creating a local child frame of a local parent frame.
WebLocalFrameImpl* CreateLocalChild(
WebLocalFrame& parent,
blink::mojom::blink::TreeScopeType,
mojom::blink::TreeScopeType,
TestWebFrameClient*,
WebPolicyContainerBindParams policy_container_bind_params);
WebPolicyContainerBindParams policy_container_bind_params,
WebLocalFrameClient::FinishChildFrameCreationFn finish_creation);
// Similar, but unlike the overload which takes the client as a raw pointer,
// ownership of the TestWebFrameClient is transferred to the test framework.
@ -137,7 +139,8 @@ WebLocalFrameImpl* CreateLocalChild(
WebLocalFrame& parent,
blink::mojom::blink::TreeScopeType,
std::unique_ptr<TestWebFrameClient>,
WebPolicyContainerBindParams policy_container_bind_params);
WebPolicyContainerBindParams policy_container_bind_params,
WebLocalFrameClient::FinishChildFrameCreationFn finish_creation);
// Helper for creating a remote frame. Generally used when creating a remote
// frame to swap into the frame tree.
@ -490,8 +493,8 @@ class TestWebFrameClient : public WebLocalFrameClient {
const FramePolicy&,
const WebFrameOwnerProperties&,
FrameOwnerElementType,
WebPolicyContainerBindParams policy_container_bind_params) override;
void InitializeAsChildFrame(WebLocalFrame* parent) override;
WebPolicyContainerBindParams policy_container_bind_params,
FinishChildFrameCreationFn finish_creation) override;
void DidStartLoading() override;
void DidStopLoading() override;
bool SwapIn(WebFrame* previous_frame) override;

@ -305,6 +305,7 @@ LocalFrame* LocalFrame::FromFrameToken(const LocalFrameToken& frame_token) {
}
void LocalFrame::Init(Frame* opener,
const DocumentToken& document_token,
std::unique_ptr<PolicyContainer> policy_container,
const StorageKey& storage_key) {
if (!policy_container)
@ -318,7 +319,7 @@ void LocalFrame::Init(Frame* opener,
mojo_handler_ = MakeGarbageCollected<LocalFrameMojoHandler>(*this);
SetOpenerDoNotNotify(opener);
loader_.Init(std::move(policy_container), storage_key);
loader_.Init(document_token, std::move(policy_container), storage_key);
}
void LocalFrame::SetView(LocalFrameView* view) {

@ -42,6 +42,7 @@
#include "services/network/public/mojom/fetch_api.mojom-blink-forward.h"
#include "third_party/blink/public/common/frame/frame_ad_evidence.h"
#include "third_party/blink/public/common/frame/transient_allow_fullscreen.h"
#include "third_party/blink/public/common/tokens/tokens.h"
#include "third_party/blink/public/mojom/blob/blob_url_store.mojom-blink-forward.h"
#include "third_party/blink/public/mojom/devtools/devtools_agent.mojom-blink-forward.h"
#include "third_party/blink/public/mojom/devtools/inspector_issue.mojom-blink-forward.h"
@ -206,6 +207,7 @@ class CORE_EXPORT LocalFrame final
// response to the creation of a RenderFrameHost) or by blink if this is a
// synchronously created LocalFrame child.
void Init(Frame* opener,
const DocumentToken& document_token,
std::unique_ptr<PolicyContainer> policy_container,
const StorageKey& storage_key);
void SetView(LocalFrameView*);

@ -4794,11 +4794,13 @@ class ContextLifetimeTestWebFrameClient
const FramePolicy&,
const WebFrameOwnerProperties&,
FrameOwnerElementType,
WebPolicyContainerBindParams policy_container_bind_params) override {
WebPolicyContainerBindParams policy_container_bind_params,
FinishChildFrameCreationFn finish_creation) override {
return CreateLocalChild(*Frame(), scope,
std::make_unique<ContextLifetimeTestWebFrameClient>(
create_notifications_, release_notifications_),
std::move(policy_container_bind_params));
std::move(policy_container_bind_params),
finish_creation);
}
void DidCreateScriptContext(v8::Local<v8::Context> context,
@ -7736,12 +7738,14 @@ class TestCachePolicyWebFrameClient
const FramePolicy&,
const WebFrameOwnerProperties& frame_owner_properties,
FrameOwnerElementType,
WebPolicyContainerBindParams policy_container_bind_params) override {
WebPolicyContainerBindParams policy_container_bind_params,
FinishChildFrameCreationFn finish_creation) override {
auto child = std::make_unique<TestCachePolicyWebFrameClient>();
auto* child_ptr = child.get();
child_clients_.push_back(std::move(child));
return CreateLocalChild(*Frame(), scope, child_ptr,
std::move(policy_container_bind_params));
std::move(policy_container_bind_params),
finish_creation);
}
void BeginNavigation(std::unique_ptr<WebNavigationInfo> info) override {
cache_mode_ = info->url_request.GetCacheMode();
@ -8172,7 +8176,8 @@ class FailCreateChildFrame : public frame_test_helpers::TestWebFrameClient {
const FramePolicy&,
const WebFrameOwnerProperties& frame_owner_properties,
FrameOwnerElementType,
WebPolicyContainerBindParams policy_container_bind_params) override {
WebPolicyContainerBindParams policy_container_bind_params,
FinishChildFrameCreationFn finish_creation) override {
++call_count_;
return nullptr;
}
@ -9188,10 +9193,11 @@ class WebFrameSwapTestClient : public frame_test_helpers::TestWebFrameClient {
const FramePolicy&,
const WebFrameOwnerProperties&,
FrameOwnerElementType,
WebPolicyContainerBindParams policy_container_bind_params) override {
return CreateLocalChild(*Frame(), scope,
std::make_unique<WebFrameSwapTestClient>(this),
std::move(policy_container_bind_params));
WebPolicyContainerBindParams policy_container_bind_params,
FinishChildFrameCreationFn finish_creation) override {
return CreateLocalChild(
*Frame(), scope, std::make_unique<WebFrameSwapTestClient>(this),
std::move(policy_container_bind_params), finish_creation);
}
void DidChangeFrameOwnerProperties(
@ -11282,9 +11288,11 @@ class WebLocalFrameVisibilityChangeTest
const FramePolicy&,
const WebFrameOwnerProperties&,
FrameOwnerElementType,
WebPolicyContainerBindParams policy_container_bind_params) override {
WebPolicyContainerBindParams policy_container_bind_params,
FinishChildFrameCreationFn finish_creation) override {
return CreateLocalChild(*Frame(), scope, &child_client_,
std::move(policy_container_bind_params));
std::move(policy_container_bind_params),
finish_creation);
}
TestLocalFrameHostForVisibility& ChildHost() { return child_host_; }
@ -13036,9 +13044,11 @@ TEST_F(WebFrameTest, NoLoadingCompletionCallbacksInDetach) {
const FramePolicy&,
const WebFrameOwnerProperties&,
FrameOwnerElementType,
WebPolicyContainerBindParams policy_container_bind_params) override {
WebPolicyContainerBindParams policy_container_bind_params,
FinishChildFrameCreationFn finish_creation) override {
return CreateLocalChild(*Frame(), scope, &child_client_,
std::move(policy_container_bind_params));
std::move(policy_container_bind_params),
finish_creation);
}
LoadingObserverFrameClient& ChildClient() { return child_client_; }

@ -1976,13 +1976,14 @@ WebLocalFrame* WebLocalFrame::CreateMainFrame(
WebLocalFrameClient* client,
InterfaceRegistry* interface_registry,
const LocalFrameToken& frame_token,
const DocumentToken& document_token,
std::unique_ptr<WebPolicyContainer> policy_container,
WebFrame* opener,
const WebString& name,
network::mojom::blink::WebSandboxFlags sandbox_flags) {
return WebLocalFrameImpl::CreateMainFrame(
web_view, client, interface_registry, frame_token, opener, name,
sandbox_flags, std::move(policy_container));
sandbox_flags, document_token, std::move(policy_container));
}
WebLocalFrame* WebLocalFrame::CreateProvisional(
@ -2005,6 +2006,7 @@ WebLocalFrameImpl* WebLocalFrameImpl::CreateMainFrame(
WebFrame* opener,
const WebString& name,
network::mojom::blink::WebSandboxFlags sandbox_flags,
const DocumentToken& document_token,
std::unique_ptr<WebPolicyContainer> policy_container) {
auto* frame = MakeGarbageCollected<WebLocalFrameImpl>(
base::PassKey<WebLocalFrameImpl>(),
@ -2022,7 +2024,8 @@ WebLocalFrameImpl* WebLocalFrameImpl::CreateMainFrame(
frame->InitializeCoreFrame(
page, nullptr, nullptr, nullptr, FrameInsertType::kInsertInConstructor,
name, opener ? &ToCoreFrame(*opener)->window_agent_factory() : nullptr,
opener, std::move(policy_container), storage_key, sandbox_flags);
opener, document_token, std::move(policy_container), storage_key,
sandbox_flags);
return frame;
}
@ -2062,12 +2065,18 @@ WebLocalFrameImpl* WebLocalFrameImpl::CreateProvisional(
// unscriptable. Once the provisional frame gets properly attached and is
// observable, it will have the real FrameOwner, and any subsequent real
// documents will correctly inherit sandbox flags from the owner.
//
// Note: this intentionally initializes the initial document of the
// provisional frame with a random DocumentToken rather than plumbing it
// through from //content. The fact that provisional frames have an initial
// document is a weird implementation detail and this is an attempt to
// minimize its visibility/usefulness.
web_frame->InitializeCoreFrame(
*previous_frame->GetPage(), MakeGarbageCollected<DummyFrameOwner>(),
previous_web_frame->Parent(), nullptr, FrameInsertType::kInsertLater,
name, &ToCoreFrame(*previous_web_frame)->window_agent_factory(),
previous_web_frame->Opener(), /*policy_container=*/nullptr, StorageKey(),
sandbox_flags);
previous_web_frame->Opener(), DocumentToken(),
/*policy_container=*/nullptr, StorageKey(), sandbox_flags);
LocalFrame* new_frame = web_frame->GetFrame();
previous_frame->SetProvisionalFrame(new_frame);
@ -2154,11 +2163,13 @@ void WebLocalFrameImpl::InitializeCoreFrame(
const AtomicString& name,
WindowAgentFactory* window_agent_factory,
WebFrame* opener,
const DocumentToken& document_token,
std::unique_ptr<blink::WebPolicyContainer> policy_container,
const StorageKey& storage_key,
network::mojom::blink::WebSandboxFlags sandbox_flags) {
InitializeCoreFrameInternal(page, owner, parent, previous_sibling,
insert_type, name, window_agent_factory, opener,
document_token,
PolicyContainer::CreateFromWebPolicyContainer(
std::move(policy_container)),
storage_key, sandbox_flags);
@ -2173,6 +2184,7 @@ void WebLocalFrameImpl::InitializeCoreFrameInternal(
const AtomicString& name,
WindowAgentFactory* window_agent_factory,
WebFrame* opener,
const DocumentToken& document_token,
std::unique_ptr<PolicyContainer> policy_container,
const StorageKey& storage_key,
network::mojom::blink::WebSandboxFlags sandbox_flags) {
@ -2211,7 +2223,8 @@ void WebLocalFrameImpl::InitializeCoreFrameInternal(
// We must call init() after frame_ is assigned because it is referenced
// during init().
frame_->Init(opener_frame, std::move(policy_container), storage_key);
frame_->Init(opener_frame, document_token, std::move(policy_container),
storage_key);
if (!owner) {
// This trace event is needed to detect the main frame of the
@ -2260,6 +2273,28 @@ LocalFrame* WebLocalFrameImpl::CreateChildFrame(
policy_container_data->sandbox_flags |= frame_policy.sandbox_flags;
frame_policy.sandbox_flags = policy_container_data->sandbox_flags;
auto complete_initialization = [this, owner_element, &policy_container_remote,
&policy_container_data,
&name](WebLocalFrame* new_child_frame,
const DocumentToken& document_token) {
// The initial empty document's anonymous bit is the union of:
// - its parent's anonymous bit.
// - its frame's anonymous attribute.
policy_container_data->is_anonymous |= owner_element->Anonymous();
std::unique_ptr<PolicyContainer> policy_container =
std::make_unique<PolicyContainer>(std::move(policy_container_remote),
std::move(policy_container_data));
To<WebLocalFrameImpl>(new_child_frame)
->InitializeCoreFrameInternal(
*GetFrame()->GetPage(), owner_element, this, LastChild(),
FrameInsertType::kInsertInConstructor, name,
&GetFrame()->window_agent_factory(), nullptr, document_token,
std::move(policy_container),
GetFrame()->DomWindow()->GetStorageKey());
};
// FIXME: Using subResourceAttributeName as fallback is not a perfect
// solution. subResourceAttributeName returns just one attribute name. The
// element might not have the attribute, and there might be other attributes
@ -2270,28 +2305,14 @@ LocalFrame* WebLocalFrameImpl::CreateChildFrame(
owner_element->getAttribute(
owner_element->SubResourceAttributeName()),
std::move(frame_policy), owner_properties, owner_element->OwnerType(),
WebPolicyContainerBindParams{std::move(policy_container_receiver)}));
WebPolicyContainerBindParams{std::move(policy_container_receiver)},
complete_initialization));
if (!webframe_child)
return nullptr;
// The initial empty document's anonymous bit is the union of:
// - its parent's anonymous bit.
// - its frame's anonymous attribute.
policy_container_data->is_anonymous |= owner_element->Anonymous();
std::unique_ptr<PolicyContainer> policy_container =
std::make_unique<PolicyContainer>(std::move(policy_container_remote),
std::move(policy_container_data));
webframe_child->InitializeCoreFrameInternal(
*GetFrame()->GetPage(), owner_element, this, LastChild(),
FrameInsertType::kInsertInConstructor, name,
&GetFrame()->window_agent_factory(), nullptr, std::move(policy_container),
GetFrame()->DomWindow()->GetStorageKey());
webframe_child->Client()->InitializeAsChildFrame(/*parent=*/this);
DCHECK(webframe_child->Parent());
// If the lambda to complete initialization is not called, this will fail.
DCHECK(webframe_child->GetFrame());
return webframe_child->GetFrame();
}

@ -395,6 +395,7 @@ class CORE_EXPORT WebLocalFrameImpl final
const AtomicString& name,
WindowAgentFactory*,
WebFrame* opener,
const DocumentToken& document_token,
std::unique_ptr<blink::WebPolicyContainer> policy_container,
const StorageKey& storage_key,
network::mojom::blink::WebSandboxFlags sandbox_flags =
@ -413,6 +414,7 @@ class CORE_EXPORT WebLocalFrameImpl final
WebFrame* opener,
const WebString& name,
network::mojom::blink::WebSandboxFlags,
const DocumentToken& document_token,
std::unique_ptr<WebPolicyContainer>);
static WebLocalFrameImpl* CreateProvisional(
WebLocalFrameClient*,
@ -603,6 +605,7 @@ class CORE_EXPORT WebLocalFrameImpl final
const AtomicString& name,
WindowAgentFactory*,
WebFrame* opener,
const DocumentToken& document_token,
std::unique_ptr<PolicyContainer> policy_container,
const StorageKey& storage_key,
network::mojom::blink::WebSandboxFlags sandbox_flags =

@ -224,6 +224,7 @@ WebLocalFrame* WebRemoteFrameImpl::CreateLocalChild(
const WebFrameOwnerProperties& frame_owner_properties,
const LocalFrameToken& frame_token,
WebFrame* opener,
const DocumentToken& document_token,
std::unique_ptr<WebPolicyContainer> policy_container) {
auto* child = MakeGarbageCollected<WebLocalFrameImpl>(
base::PassKey<WebRemoteFrameImpl>(), scope, client, interface_registry,
@ -248,7 +249,7 @@ WebLocalFrame* WebRemoteFrameImpl::CreateLocalChild(
child->InitializeCoreFrame(
*GetFrame()->GetPage(), owner, this, previous_sibling,
FrameInsertType::kInsertInConstructor, name, window_agent_factory, opener,
std::move(policy_container), storage_key);
document_token, std::move(policy_container), storage_key);
DCHECK(child->GetFrame());
return child;
}

@ -69,6 +69,7 @@ class CORE_EXPORT WebRemoteFrameImpl final
const WebFrameOwnerProperties&,
const LocalFrameToken& frame_token,
WebFrame* opener,
const DocumentToken& document_token,
std::unique_ptr<blink::WebPolicyContainer> policy_container) override;
void SetReplicatedOrigin(
const WebSecurityOrigin&,

@ -1234,7 +1234,8 @@ void InspectorOverlayAgent::LoadOverlayPageResource() {
FrameInsertType::kInsertInConstructor, LocalFrameToken(), nullptr,
nullptr);
frame->SetView(MakeGarbageCollected<LocalFrameView>(*frame));
frame->Init(/*opener=*/nullptr, /*policy_container=*/nullptr, StorageKey());
frame->Init(/*opener=*/nullptr, DocumentToken(), /*policy_container=*/nullptr,
StorageKey());
frame->View()->SetCanHaveScrollbars(false);
frame->View()->SetBaseBackgroundColor(Color::kTransparent);

@ -218,6 +218,7 @@ struct SameSizeAsDocumentLoader
std::unique_ptr<WebNavigationParams> params;
std::unique_ptr<PolicyContainer> policy_container;
absl::optional<ParsedPermissionsPolicy> isolated_app_permissions_policy;
DocumentToken token;
KURL url;
AtomicString http_method;
AtomicString referrer;
@ -322,6 +323,7 @@ DocumentLoader::DocumentLoader(
: params_(std::move(navigation_params)),
policy_container_(std::move(policy_container)),
initial_permissions_policy_(params_->permissions_policy_override),
token_(params_->document_token),
url_(params_->url),
http_method_(static_cast<String>(params_->http_method)),
referrer_(static_cast<String>(params_->referrer)),
@ -403,6 +405,7 @@ DocumentLoader::DocumentLoader(
extra_data_(std::move(extra_data)),
reduced_accept_language_(params_->reduced_accept_language) {
DCHECK(frame_);
DCHECK(params_);
// TODO(dgozman): we should get rid of this boolean field, and make client
// responsible for it's own view of "replaces current item", based on the
@ -506,6 +509,7 @@ DocumentLoader::CreateWebNavigationParamsToCloneDocument() {
// TODO(https://crbug.com/1151954): Copy |archive_| and other attributes.
auto params = std::make_unique<WebNavigationParams>();
LocalDOMWindow* window = frame_->DomWindow();
params->document_token = frame_->GetDocument()->Token();
params->url = window->Url();
params->unreachable_url = unreachable_url_;
params->referrer = referrer_;
@ -2371,6 +2375,7 @@ void DocumentLoader::CommitNavigation() {
Document* document = frame_->DomWindow()->InstallNewDocument(
DocumentInit::Create()
.WithWindow(frame_->DomWindow(), owner_document)
.WithToken(token_)
.ForInitialEmptyDocument(commit_reason_ ==
CommitReason::kInitialization)
.ForPrerendering(is_prerendering_)

@ -554,6 +554,7 @@ class CORE_EXPORT DocumentLoader : public GarbageCollected<DocumentLoader>,
const absl::optional<ParsedPermissionsPolicy> initial_permissions_policy_;
// These fields are copied from WebNavigationParams, see there for definition.
DocumentToken token_;
KURL url_;
AtomicString http_method_;
// The referrer on the final request for this document.

@ -241,7 +241,8 @@ void FrameLoader::Trace(Visitor* visitor) const {
visitor->Trace(document_loader_);
}
void FrameLoader::Init(std::unique_ptr<PolicyContainer> policy_container,
void FrameLoader::Init(const DocumentToken& document_token,
std::unique_ptr<PolicyContainer> policy_container,
const StorageKey& storage_key) {
DCHECK(policy_container);
ScriptForbiddenScope forbid_scripts;
@ -249,9 +250,10 @@ void FrameLoader::Init(std::unique_ptr<PolicyContainer> policy_container,
// Load the initial empty document:
auto navigation_params = std::make_unique<WebNavigationParams>();
navigation_params->url = KURL(g_empty_string);
navigation_params->storage_key = storage_key;
navigation_params->document_token = document_token;
navigation_params->frame_policy =
frame_->Owner() ? frame_->Owner()->GetFramePolicy() : FramePolicy();
navigation_params->storage_key = storage_key;
DocumentLoader* new_document_loader = MakeGarbageCollected<DocumentLoader>(
frame_, kWebNavigationTypeOther, std::move(navigation_params),

@ -38,6 +38,7 @@
#include "base/callback_helpers.h"
#include "services/network/public/mojom/web_sandbox_flags.mojom-blink-forward.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "third_party/blink/public/common/tokens/tokens.h"
#include "third_party/blink/public/common/user_agent/user_agent_metadata.h"
#include "third_party/blink/public/mojom/loader/request_context_frame_type.mojom-blink-forward.h"
#include "third_party/blink/public/mojom/page_state/page_state.mojom-blink-forward.h"
@ -84,7 +85,8 @@ class CORE_EXPORT FrameLoader final {
FrameLoader& operator=(const FrameLoader&) = delete;
~FrameLoader();
void Init(std::unique_ptr<PolicyContainer> policy_container,
void Init(const DocumentToken& document_token,
std::unique_ptr<PolicyContainer> policy_container,
const StorageKey& storage_key);
ResourceRequest ResourceRequestForReload(

@ -154,7 +154,8 @@ void ValidationMessageOverlayDelegate::CreatePage(const FrameOverlay& overlay) {
nullptr, FrameInsertType::kInsertInConstructor, LocalFrameToken(),
nullptr, nullptr);
frame->SetView(MakeGarbageCollected<LocalFrameView>(*frame, view_size));
frame->Init(/*opener=*/nullptr, /*policy_container=*/nullptr, StorageKey());
frame->Init(/*opener=*/nullptr, DocumentToken(), /*policy_container=*/nullptr,
StorageKey());
frame->View()->SetCanHaveScrollbars(false);
frame->View()->SetBaseBackgroundColor(Color::kTransparent);
page_->GetVisualViewport().SetSize(view_size);

@ -867,7 +867,8 @@ Image::SizeAvailability SVGImage::DataChanged(bool all_data_received) {
FrameInsertType::kInsertInConstructor, LocalFrameToken(), nullptr,
nullptr);
frame->SetView(MakeGarbageCollected<LocalFrameView>(*frame));
frame->Init(/*opener=*/nullptr, /*policy_container=*/nullptr, StorageKey());
frame->Init(/*opener=*/nullptr, DocumentToken(),
/*policy_container=*/nullptr, StorageKey());
}
// SVG Images will always synthesize a viewBox, if it's not available, and

@ -56,7 +56,7 @@ LocalFrame* SingleChildLocalFrameClient::CreateFrame(
auto policy_container = std::make_unique<PolicyContainer>(
dummy_host.Unbind(), std::move(policy_container_data));
child->Init(/*opener=*/nullptr, std::move(policy_container),
child->Init(/*opener=*/nullptr, DocumentToken(), std::move(policy_container),
parent_frame->DomWindow()->GetStorageKey());
return child;

Some files were not shown because too many files have changed in this diff Show More