1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
content / browser / renderer_host / back_forward_cache_subframe_navigation_throttle.cc [blame]
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/browser/renderer_host/back_forward_cache_subframe_navigation_throttle.h"
#include "content/browser/renderer_host/frame_tree_node.h"
#include "content/browser/renderer_host/navigation_request.h"
namespace content {
// static
std::unique_ptr<BackForwardCacheSubframeNavigationThrottle>
BackForwardCacheSubframeNavigationThrottle::MaybeCreateThrottleFor(
NavigationHandle* navigation_handle) {
CHECK(navigation_handle);
// While the NavigationRequest is ongoing (and the throttles are already
// registered), the page might move into BFCache, so we check BFCache status
// later in order to defer navigations in those cases.
if (!navigation_handle->IsInMainFrame()) {
return base::WrapUnique(
new BackForwardCacheSubframeNavigationThrottle(navigation_handle));
}
return nullptr;
}
BackForwardCacheSubframeNavigationThrottle::
BackForwardCacheSubframeNavigationThrottle(NavigationHandle* nav_handle)
: NavigationThrottle(nav_handle),
WebContentsObserver(nav_handle->GetWebContents()) {}
BackForwardCacheSubframeNavigationThrottle::
~BackForwardCacheSubframeNavigationThrottle() = default;
const char* BackForwardCacheSubframeNavigationThrottle::GetNameForLogging() {
return "BackForwardCacheSubframeNavigationThrottle";
}
NavigationThrottle::ThrottleCheckResult
BackForwardCacheSubframeNavigationThrottle::DeferNavigationIfNeeded() {
auto* navigation_request = NavigationRequest::From(navigation_handle());
FrameTreeNode* frame_tree_node = navigation_request->frame_tree_node();
// Defer this navigation if the frame is in BackForwardCache. Otherwise, we
// enable it to proceed.
if (frame_tree_node->current_frame_host()->GetLifecycleState() ==
RenderFrameHost::LifecycleState::kInBackForwardCache) {
is_deferred_ = true;
return NavigationThrottle::DEFER;
}
return NavigationThrottle::PROCEED;
}
void BackForwardCacheSubframeNavigationThrottle::
ConfirmNavigationIsNotInBFCachedFrame() {
auto* navigation_request = NavigationRequest::From(navigation_handle());
FrameTreeNode* frame_tree_node = navigation_request->frame_tree_node();
// We don't bfcache pages with subframe navigations that have sent network
// requests, so it's impossible for subframe navigations in bfcached pages to
// reach `WillRedirectRequest`, `WillProcessResponse`, and `WillFailRequest`
// while bfcached.
CHECK_NE(frame_tree_node->current_frame_host()->GetLifecycleState(),
RenderFrameHost::LifecycleState::kInBackForwardCache);
}
NavigationThrottle::ThrottleCheckResult
BackForwardCacheSubframeNavigationThrottle::WillStartRequest() {
return DeferNavigationIfNeeded();
}
NavigationThrottle::ThrottleCheckResult
BackForwardCacheSubframeNavigationThrottle::WillRedirectRequest() {
ConfirmNavigationIsNotInBFCachedFrame();
return NavigationThrottle::PROCEED;
}
NavigationThrottle::ThrottleCheckResult
BackForwardCacheSubframeNavigationThrottle::WillFailRequest() {
ConfirmNavigationIsNotInBFCachedFrame();
return NavigationThrottle::PROCEED;
}
NavigationThrottle::ThrottleCheckResult
BackForwardCacheSubframeNavigationThrottle::WillProcessResponse() {
ConfirmNavigationIsNotInBFCachedFrame();
return NavigationThrottle::PROCEED;
}
NavigationThrottle::ThrottleCheckResult
BackForwardCacheSubframeNavigationThrottle::WillCommitWithoutUrlLoader() {
return DeferNavigationIfNeeded();
}
void BackForwardCacheSubframeNavigationThrottle::RenderFrameHostStateChanged(
RenderFrameHost* render_frame_host,
RenderFrameHost::LifecycleState old_state,
RenderFrameHost::LifecycleState new_state) {
CHECK(render_frame_host);
// Resume the deferred navigation when the `render_frame_host` is activated
// from BackForwardCache. We check the frame tree node so that we won't resume
// unrelated navigations.
if (is_deferred_ &&
NavigationRequest::From(navigation_handle())->frame_tree_node() ==
static_cast<RenderFrameHostImpl*>(render_frame_host)
->frame_tree_node() &&
old_state == RenderFrameHost::LifecycleState::kInBackForwardCache &&
new_state == RenderFrameHost::LifecycleState::kActive) {
Resume();
}
}
} // namespace content