blob: 2d0fce9bcab66160d9596f018ce5d1fa318918b7 [file] [log] [blame]
Avi Drissman4e1b7bc32022-09-15 14:03:501// Copyright 2013 The Chromium Authors
[email protected]9b159a52013-10-03 17:24:552// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
danakjc492bf82020-09-09 20:02:445#include "content/browser/renderer_host/frame_tree_node.h"
[email protected]9b159a52013-10-03 17:24:556
Daniel Cheng6ca7f1c92017-08-09 21:45:417#include <math.h>
[email protected]9b159a52013-10-03 17:24:558#include <queue>
Takuto Ikutaadf31eb2019-01-05 00:32:489#include <unordered_map>
dcheng36b6aec92015-12-26 06:16:3610#include <utility>
[email protected]9b159a52013-10-03 17:24:5511
Mustaq Ahmeda5dfa60b2018-12-08 00:30:1412#include "base/feature_list.h"
scottmg6ece5ae2017-02-01 18:25:1913#include "base/lazy_instance.h"
Keishi Hattori0e45c022021-11-27 09:25:5214#include "base/memory/raw_ptr.h"
Liviu Tintad9391fb92020-09-28 23:50:0715#include "base/metrics/histogram_functions.h"
dcheng23ca947d2016-05-04 20:04:1516#include "base/metrics/histogram_macros.h"
David Sandersd4bf5eb2022-03-17 07:12:0517#include "base/observer_list.h"
Clark DuVallc97bcf72021-12-08 22:58:2418#include "base/strings/strcat.h"
Daniel Cheng6ca7f1c92017-08-09 21:45:4119#include "base/strings/string_util.h"
Clark DuVallc97bcf72021-12-08 22:58:2420#include "base/timer/elapsed_timer.h"
Andrey Kosyakovf2d4ff72018-10-29 20:09:5921#include "content/browser/devtools/devtools_instrumentation.h"
Dominic Farolino8a2187b2021-12-24 20:44:2122#include "content/browser/fenced_frame/fenced_frame.h"
Miyoung Shinff13ed22022-11-30 09:21:4723#include "content/browser/network/cross_origin_embedder_policy_reporter.h"
Paul Semel3e241042022-10-11 12:57:3124#include "content/browser/renderer_host/frame_tree.h"
danakjc492bf82020-09-09 20:02:4425#include "content/browser/renderer_host/navigation_controller_impl.h"
26#include "content/browser/renderer_host/navigation_request.h"
27#include "content/browser/renderer_host/navigator.h"
28#include "content/browser/renderer_host/navigator_delegate.h"
29#include "content/browser/renderer_host/render_frame_host_impl.h"
[email protected]94d0cc12013-12-18 00:07:4130#include "content/browser/renderer_host/render_view_host_impl.h"
Miyoung Shinff13ed22022-11-30 09:21:4731#include "content/browser/web_package/subresource_web_bundle_navigation_info.h"
32#include "content/browser/web_package/web_bundle_navigation_info.h"
Lucas Furukawa Gadanief8290a2019-07-29 20:27:5133#include "content/common/navigation_params_utils.h"
dmazzonie950ea232015-03-13 21:39:4534#include "content/public/browser/browser_thread.h"
Nan Linaaf84f72021-12-02 22:31:5635#include "content/public/browser/site_isolation_policy.h"
Mustaq Ahmeda5dfa60b2018-12-08 00:30:1436#include "content/public/common/content_features.h"
arthursonzognib93a4472020-04-10 07:38:0037#include "services/network/public/cpp/web_sandbox_flags.h"
38#include "services/network/public/mojom/web_sandbox_flags.mojom-shared.h"
Harkiran Bolaria59290d62021-03-17 01:53:0139#include "third_party/blink/public/common/features.h"
Liam Bradyb0f1f0e2022-08-19 21:42:1140#include "third_party/blink/public/common/frame/fenced_frame_sandbox_flags.h"
Sreeja Kamishetty0be3b1b2021-08-12 17:04:1541#include "third_party/blink/public/common/loader/loader_constants.h"
Antonio Gomes4b2c5132020-01-16 11:49:4842#include "third_party/blink/public/mojom/frame/user_activation_update_types.mojom.h"
Julie Jeongeun Kimd90e2dd2020-03-03 11:45:3743#include "third_party/blink/public/mojom/security_context/insecure_request_policy.mojom.h"
[email protected]9b159a52013-10-03 17:24:5544
45namespace content {
46
dmazzonie950ea232015-03-13 21:39:4547namespace {
48
49// This is a global map between frame_tree_node_ids and pointers to
50// FrameTreeNodes.
Takuto Ikutaadf31eb2019-01-05 00:32:4851typedef std::unordered_map<int, FrameTreeNode*> FrameTreeNodeIdMap;
dmazzonie950ea232015-03-13 21:39:4552
scottmg5e65e3a2017-03-08 08:48:4653base::LazyInstance<FrameTreeNodeIdMap>::DestructorAtExit
54 g_frame_tree_node_id_map = LAZY_INSTANCE_INITIALIZER;
dmazzonie950ea232015-03-13 21:39:4555
Nan Line376738a2022-03-25 22:05:4156FencedFrame* FindFencedFrame(const FrameTreeNode* frame_tree_node) {
57 // TODO(crbug.com/1123606): Consider having a pointer to `FencedFrame` in
58 // `FrameTreeNode` or having a map between them.
59
60 // Try and find the `FencedFrame` that `frame_tree_node` represents.
61 DCHECK(frame_tree_node->parent());
62 std::vector<FencedFrame*> fenced_frames =
63 frame_tree_node->parent()->GetFencedFrames();
64 for (FencedFrame* fenced_frame : fenced_frames) {
65 if (frame_tree_node->frame_tree_node_id() ==
66 fenced_frame->GetOuterDelegateFrameTreeNodeId()) {
67 return fenced_frame;
68 }
69 }
70 return nullptr;
71}
72
fdegansa696e5112015-04-17 01:57:5973} // namespace
fdegans1d16355162015-03-26 11:58:3474
alexmose201c7cd2015-06-10 17:14:2175// This observer watches the opener of its owner FrameTreeNode and clears the
Arthur Hemerye4659282022-03-28 08:36:1576// owner's opener if the opener is destroyed or swaps BrowsingInstance.
alexmose201c7cd2015-06-10 17:14:2177class FrameTreeNode::OpenerDestroyedObserver : public FrameTreeNode::Observer {
78 public:
jochen6004a362017-02-04 00:11:4079 OpenerDestroyedObserver(FrameTreeNode* owner, bool observing_original_opener)
80 : owner_(owner), observing_original_opener_(observing_original_opener) {}
alexmose201c7cd2015-06-10 17:14:2181
Peter Boström9b036532021-10-28 23:37:2882 OpenerDestroyedObserver(const OpenerDestroyedObserver&) = delete;
83 OpenerDestroyedObserver& operator=(const OpenerDestroyedObserver&) = delete;
84
alexmose201c7cd2015-06-10 17:14:2185 // FrameTreeNode::Observer
86 void OnFrameTreeNodeDestroyed(FrameTreeNode* node) override {
Arthur Hemerye4659282022-03-28 08:36:1587 NullifyOpener(node);
88 }
89
90 // FrameTreeNode::Observer
91 void OnFrameTreeNodeDisownedOpenee(FrameTreeNode* node) override {
92 NullifyOpener(node);
93 }
94
95 void NullifyOpener(FrameTreeNode* node) {
jochen6004a362017-02-04 00:11:4096 if (observing_original_opener_) {
Rakina Zata Amni3a48ae42022-05-05 03:39:5697 // The "original opener" is special. It's used for attribution, and
98 // clients walk down the original opener chain. Therefore, if a link in
99 // the chain is being destroyed, reconnect the observation to the parent
100 // of the link being destroyed.
101 CHECK_EQ(owner_->first_live_main_frame_in_original_opener_chain(), node);
102 owner_->SetOriginalOpener(
103 node->first_live_main_frame_in_original_opener_chain());
Avi Drissman36465f332017-09-11 20:49:39104 // |this| is deleted at this point.
jochen6004a362017-02-04 00:11:40105 } else {
106 CHECK_EQ(owner_->opener(), node);
107 owner_->SetOpener(nullptr);
Avi Drissman36465f332017-09-11 20:49:39108 // |this| is deleted at this point.
jochen6004a362017-02-04 00:11:40109 }
alexmose201c7cd2015-06-10 17:14:21110 }
111
112 private:
Keishi Hattori0e45c022021-11-27 09:25:52113 raw_ptr<FrameTreeNode> owner_;
jochen6004a362017-02-04 00:11:40114 bool observing_original_opener_;
alexmose201c7cd2015-06-10 17:14:21115};
116
Kevin McNee88e61552020-10-22 20:41:11117const int FrameTreeNode::kFrameTreeNodeInvalidId = -1;
118
119static_assert(FrameTreeNode::kFrameTreeNodeInvalidId ==
120 RenderFrameHost::kNoFrameTreeNodeId,
121 "Have consistent sentinel values for an invalid FTN id.");
122
vishal.b782eb5d2015-04-29 12:22:57123int FrameTreeNode::next_frame_tree_node_id_ = 1;
[email protected]9b159a52013-10-03 17:24:55124
dmazzonie950ea232015-03-13 21:39:45125// static
vishal.b782eb5d2015-04-29 12:22:57126FrameTreeNode* FrameTreeNode::GloballyFindByID(int frame_tree_node_id) {
mostynb366eaf12015-03-26 00:51:19127 DCHECK_CURRENTLY_ON(BrowserThread::UI);
rob97250742015-12-10 17:45:15128 FrameTreeNodeIdMap* nodes = g_frame_tree_node_id_map.Pointer();
jdoerrie55ec69d2018-10-08 13:34:46129 auto it = nodes->find(frame_tree_node_id);
dmazzonie950ea232015-03-13 21:39:45130 return it == nodes->end() ? nullptr : it->second;
131}
132
Alexander Timin381e7e182020-04-28 19:04:03133// static
134FrameTreeNode* FrameTreeNode::From(RenderFrameHost* rfh) {
135 if (!rfh)
136 return nullptr;
137 return static_cast<RenderFrameHostImpl*>(rfh)->frame_tree_node();
138}
139
Abhijeet Kandalkarb43affa72022-09-27 16:48:01140FrameTreeNode::FencedFrameStatus ComputeFencedFrameStatus(
Arthur Sonzognif6785ec2022-12-05 10:11:50141 const FrameTree& frame_tree,
Harkiran Bolaria16f2c48d2022-04-22 12:39:57142 RenderFrameHostImpl* parent,
143 const blink::FramePolicy& frame_policy) {
Abhijeet Kandalkarb43affa72022-09-27 16:48:01144 using FencedFrameStatus = FrameTreeNode::FencedFrameStatus;
Dominic Farolino0b067632022-11-11 02:57:49145 if (blink::features::IsFencedFramesEnabled() &&
Arthur Sonzognif6785ec2022-12-05 10:11:50146 frame_tree.type() == FrameTree::Type::kFencedFrame) {
Dominic Farolino0b067632022-11-11 02:57:49147 if (!parent)
148 return FencedFrameStatus::kFencedFrameRoot;
149 return FencedFrameStatus::kIframeNestedWithinFencedFrame;
Harkiran Bolaria16f2c48d2022-04-22 12:39:57150 }
151
Abhijeet Kandalkar3f29bc42022-09-23 12:39:58152 return FencedFrameStatus::kNotNestedInFencedFrame;
Harkiran Bolaria16f2c48d2022-04-22 12:39:57153}
154
Julie Jeongeun Kim70a2e4e2020-02-21 05:09:54155FrameTreeNode::FrameTreeNode(
Arthur Sonzognif6785ec2022-12-05 10:11:50156 FrameTree& frame_tree,
Alexander Timin381e7e182020-04-28 19:04:03157 RenderFrameHostImpl* parent,
Daniel Cheng6ac128172021-05-25 18:49:01158 blink::mojom::TreeScopeType tree_scope_type,
Julie Jeongeun Kim70a2e4e2020-02-21 05:09:54159 bool is_created_by_script,
Julie Jeongeun Kim70a2e4e2020-02-21 05:09:54160 const blink::mojom::FrameOwnerProperties& frame_owner_properties,
Kevin McNee43fe8292021-10-04 22:59:41161 blink::FrameOwnerElementType owner_type,
Dominic Farolino08662c82021-06-11 07:36:34162 const blink::FramePolicy& frame_policy)
[email protected]bffc8302014-01-23 20:52:16163 : frame_tree_(frame_tree),
[email protected]bffc8302014-01-23 20:52:16164 frame_tree_node_id_(next_frame_tree_node_id_++),
xiaochengh98488162016-05-19 15:17:59165 parent_(parent),
Daniel Cheng9bd90f92021-04-23 20:49:45166 frame_owner_element_type_(owner_type),
Daniel Cheng6ac128172021-05-25 18:49:01167 tree_scope_type_(tree_scope_type),
Dominic Farolino08662c82021-06-11 07:36:34168 pending_frame_policy_(frame_policy),
Lukasz Anforowicz7bfb2e92017-11-22 17:19:45169 is_created_by_script_(is_created_by_script),
lazyboy70605c32015-11-03 01:27:31170 frame_owner_properties_(frame_owner_properties),
Yuzu Saijo03dbf9b2022-07-22 04:29:45171 attributes_(blink::mojom::IframeAttributes::New()),
Harkiran Bolaria16f2c48d2022-04-22 12:39:57172 fenced_frame_status_(
Arthur Sonzognif6785ec2022-12-05 10:11:50173 ComputeFencedFrameStatus(frame_tree, parent_, frame_policy)),
174 render_manager_(this, frame_tree.manager_delegate()) {
Harkiran Bolariaa8347782022-04-06 09:25:11175 TRACE_EVENT_BEGIN("navigation", "FrameTreeNode",
176 perfetto::Track::FromPointer(this),
177 "frame_tree_node_when_created", this);
rob97250742015-12-10 17:45:15178 std::pair<FrameTreeNodeIdMap::iterator, bool> result =
dmazzonie950ea232015-03-13 21:39:45179 g_frame_tree_node_id_map.Get().insert(
180 std::make_pair(frame_tree_node_id_, this));
181 CHECK(result.second);
alexmos998581d2015-01-22 01:01:59182}
[email protected]9b159a52013-10-03 17:24:55183
Dominic Farolino8a2187b2021-12-24 20:44:21184void FrameTreeNode::DestroyInnerFrameTreeIfExists() {
185 // If `this` is an dummy outer delegate node, then we really are representing
186 // an inner FrameTree for one of the following consumers:
187 // - `Portal`
188 // - `FencedFrame`
189 // - `GuestView`
190 // If we are representing a `FencedFrame` object, we need to destroy it
191 // alongside ourself. `Portals` and `GuestView` however, *currently* have a
192 // more complex lifetime and are dealt with separately.
193 bool is_outer_dummy_node = false;
194 if (current_frame_host() &&
195 current_frame_host()->inner_tree_main_frame_tree_node_id() !=
196 FrameTreeNode::kFrameTreeNodeInvalidId) {
197 is_outer_dummy_node = true;
198 }
199
200 if (is_outer_dummy_node) {
Nan Line376738a2022-03-25 22:05:41201 FencedFrame* doomed_fenced_frame = FindFencedFrame(this);
Dominic Farolino8a2187b2021-12-24 20:44:21202 // `doomed_fenced_frame` might not actually exist, because some outer dummy
203 // `FrameTreeNode`s might correspond to `Portal`s, which do not have their
204 // lifetime managed in the same way as `FencedFrames`.
205 if (doomed_fenced_frame) {
206 parent()->DestroyFencedFrame(*doomed_fenced_frame);
207 }
208 }
209}
210
[email protected]9b159a52013-10-03 17:24:55211FrameTreeNode::~FrameTreeNode() {
Harkiran Bolariaa8347782022-04-06 09:25:11212 TRACE_EVENT("navigation", "FrameTreeNode::~FrameTreeNode");
Daniel Chengc3d1e8d2021-06-23 02:11:45213 // There should always be a current RenderFrameHost except during prerender
214 // activation. Prerender activation moves the current RenderFrameHost from
215 // the old FrameTree's FrameTreeNode to the new FrameTree's FrameTreeNode and
216 // then destroys the old FrameTree. See
217 // `RenderFrameHostManager::TakePrerenderedPage()`.
Harkiran Bolaria59290d62021-03-17 01:53:01218 if (current_frame_host()) {
219 // Remove the children.
220 current_frame_host()->ResetChildren();
Lukasz Anforowicz7bfb2e92017-11-22 17:19:45221
Harkiran Bolaria59290d62021-03-17 01:53:01222 current_frame_host()->ResetLoadingState();
223 } else {
Harkiran Bolaria59290d62021-03-17 01:53:01224 DCHECK(!parent()); // Only main documents can be activated.
225 DCHECK(!opener()); // Prerendered frame trees can't have openers.
226
227 // Activation is not allowed during ongoing navigations.
228 DCHECK(!navigation_request_);
229
Carlos Caballerod1c80432021-04-20 08:16:32230 // TODO(https://crbug.com/1199693): Need to determine how to handle pending
Harkiran Bolaria59290d62021-03-17 01:53:01231 // deletions, as observers will be notified.
232 DCHECK(!render_manager()->speculative_frame_host());
233 }
Nate Chapin22ea6592019-03-05 22:29:02234
Lukasz Anforowicz7bfb2e92017-11-22 17:19:45235 // If the removed frame was created by a script, then its history entry will
236 // never be reused - we can save some memory by removing the history entry.
237 // See also https://crbug.com/784356.
238 if (is_created_by_script_ && parent_) {
Carlos Caballero04aab362021-02-15 17:38:16239 NavigationEntryImpl* nav_entry =
240 navigator().controller().GetLastCommittedEntry();
Lukasz Anforowicz7bfb2e92017-11-22 17:19:45241 if (nav_entry) {
242 nav_entry->RemoveEntryForFrame(this,
243 /* only_if_different_position = */ false);
244 }
245 }
246
dmazzonie950ea232015-03-13 21:39:45247 frame_tree_->FrameRemoved(this);
Carlos Caballero6ff6ace2021-02-05 16:53:00248
Dominic Farolino8a2187b2021-12-24 20:44:21249 DestroyInnerFrameTreeIfExists();
250
Alex Rudenkobfc5c192022-11-03 07:27:37251 devtools_instrumentation::OnFrameTreeNodeDestroyed(*this);
Carlos Caballero6ff6ace2021-02-05 16:53:00252 // Do not dispatch notification for the root frame as ~WebContentsImpl already
253 // dispatches it for now.
254 // TODO(https://crbug.com/1170277): This is only needed because the FrameTree
255 // is a member of WebContentsImpl and we would call back into it during
256 // destruction. We should clean up the FrameTree destruction code and call the
257 // delegate unconditionally.
258 if (parent())
259 render_manager_.delegate()->OnFrameTreeNodeDestroyed(this);
260
ericwilligers254597b2016-10-17 10:32:31261 for (auto& observer : observers_)
262 observer.OnFrameTreeNodeDestroyed(this);
Lukasz Anforowicz147141962020-12-16 18:03:24263 observers_.Clear();
alexmose201c7cd2015-06-10 17:14:21264
265 if (opener_)
266 opener_->RemoveObserver(opener_observer_.get());
Rakina Zata Amni3a48ae42022-05-05 03:39:56267 if (first_live_main_frame_in_original_opener_chain_)
268 first_live_main_frame_in_original_opener_chain_->RemoveObserver(
269 original_opener_observer_.get());
dmazzonie950ea232015-03-13 21:39:45270
271 g_frame_tree_node_id_map.Get().erase(frame_tree_node_id_);
jam39258caf2016-11-02 14:48:18272
Daniel Chengc3d1e8d2021-06-23 02:11:45273 // If a frame with a pending navigation is detached, make sure the
274 // WebContents (and its observers) update their loading state.
275 // TODO(dcheng): This should just check `IsLoading()`, but `IsLoading()`
276 // assumes that `current_frame_host_` is not null. This is incompatible with
277 // prerender activation when destroying the old frame tree (see above).
danakjf9400602019-06-07 15:44:58278 bool did_stop_loading = false;
279
jam39258caf2016-11-02 14:48:18280 if (navigation_request_) {
danakjf9400602019-06-07 15:44:58281 navigation_request_.reset();
danakjf9400602019-06-07 15:44:58282 did_stop_loading = true;
jam39258caf2016-11-02 14:48:18283 }
Nate Chapin22ea6592019-03-05 22:29:02284
danakjf9400602019-06-07 15:44:58285 // ~SiteProcessCountTracker DCHECKs in some tests if the speculative
286 // RenderFrameHostImpl is not destroyed last. Ideally this would be closer to
287 // (possible before) the ResetLoadingState() call above.
danakjf9400602019-06-07 15:44:58288 if (render_manager_.speculative_frame_host()) {
Daniel Chengc3d1e8d2021-06-23 02:11:45289 // TODO(dcheng): Shouldn't a FrameTreeNode with a speculative
290 // RenderFrameHost always be considered loading?
danakjf9400602019-06-07 15:44:58291 did_stop_loading |= render_manager_.speculative_frame_host()->is_loading();
Daniel Chengc3d1e8d2021-06-23 02:11:45292 // `FrameTree::Shutdown()` has special handling for the main frame's
293 // speculative RenderFrameHost, and the speculative RenderFrameHost should
294 // already be reset for main frames.
295 DCHECK(!IsMainFrame());
296
297 // This does not use `UnsetSpeculativeRenderFrameHost()`: if the speculative
298 // RenderFrameHost has already reached kPendingCommit, it would needlessly
299 // re-create a proxy for a frame that's going away.
300 render_manager_.DiscardSpeculativeRenderFrameHostForShutdown();
danakjf9400602019-06-07 15:44:58301 }
302
303 if (did_stop_loading)
304 DidStopLoading();
305
Harkiran Bolaria59290d62021-03-17 01:53:01306 // IsLoading() requires that current_frame_host() is non-null.
307 DCHECK(!current_frame_host() || !IsLoading());
Harkiran Bolariaa8347782022-04-06 09:25:11308
309 // Matches the TRACE_EVENT_BEGIN in the constructor.
310 TRACE_EVENT_END("navigation", perfetto::Track::FromPointer(this));
[email protected]9b159a52013-10-03 17:24:55311}
312
alexmose201c7cd2015-06-10 17:14:21313void FrameTreeNode::AddObserver(Observer* observer) {
314 observers_.AddObserver(observer);
315}
316
317void FrameTreeNode::RemoveObserver(Observer* observer) {
318 observers_.RemoveObserver(observer);
319}
320
[email protected]94d0cc12013-12-18 00:07:41321bool FrameTreeNode::IsMainFrame() const {
322 return frame_tree_->root() == this;
323}
324
Paul Semel3e241042022-10-11 12:57:31325Navigator& FrameTreeNode::navigator() {
Arthur Sonzognif6785ec2022-12-05 10:11:50326 return frame_tree().navigator();
Paul Semel3e241042022-10-11 12:57:31327}
328
Ian Vollick25a9d032022-04-12 23:20:17329bool FrameTreeNode::IsOutermostMainFrame() {
330 return !GetParentOrOuterDocument();
331}
332
Hiroki Nakagawaab309622021-05-19 16:38:13333void FrameTreeNode::ResetForNavigation() {
arthursonzogni76098e52020-11-25 14:18:45334 // This frame has had its user activation bits cleared in the renderer before
335 // arriving here. We just need to clear them here and in the other renderer
336 // processes that may have a reference to this frame.
Alexander Timin45b716c2020-11-06 01:40:31337 //
338 // We do not take user activation into account when calculating
339 // |ResetForNavigationResult|, as we are using it to determine bfcache
340 // eligibility and the page can get another user gesture after restore.
Antonio Gomes4b2c5132020-01-16 11:49:48341 UpdateUserActivationState(
Mustaq Ahmeddc195e5b2020-08-04 18:45:11342 blink::mojom::UserActivationUpdateType::kClearActivation,
343 blink::mojom::UserActivationNotificationType::kNone);
Ian Clelland5cbaaf82017-11-27 22:00:03344}
345
Dave Tapuskac8de3b02021-12-03 21:51:01346RenderFrameHostImpl* FrameTreeNode::GetParentOrOuterDocument() {
347 return GetParentOrOuterDocumentHelper(/*escape_guest_view=*/false);
348}
349
350RenderFrameHostImpl* FrameTreeNode::GetParentOrOuterDocumentOrEmbedder() {
351 return GetParentOrOuterDocumentHelper(/*escape_guest_view=*/true);
352}
353
354RenderFrameHostImpl* FrameTreeNode::GetParentOrOuterDocumentHelper(
355 bool escape_guest_view) {
356 // Find the parent in the FrameTree (iframe).
357 if (parent_)
358 return parent_;
359
360 if (!escape_guest_view) {
361 // If we are not a fenced frame root nor inside a portal then return early.
362 // This code does not escape GuestViews.
363 if (!IsFencedFrameRoot() && !frame_tree_->delegate()->IsPortal())
364 return nullptr;
365 }
366
367 // Find the parent in the outer embedder (GuestView, Portal, or Fenced Frame).
368 FrameTreeNode* frame_in_embedder = render_manager()->GetOuterDelegateNode();
369 if (frame_in_embedder)
370 return frame_in_embedder->current_frame_host()->GetParent();
371
372 // No parent found.
373 return nullptr;
374}
375
Julie Jeongeun Kimf38c1eca2021-12-14 07:46:55376FrameType FrameTreeNode::GetFrameType() const {
377 if (!IsMainFrame())
378 return FrameType::kSubframe;
379
Arthur Sonzognif6785ec2022-12-05 10:11:50380 switch (frame_tree().type()) {
Julie Jeongeun Kimf38c1eca2021-12-14 07:46:55381 case FrameTree::Type::kPrimary:
382 return FrameType::kPrimaryMainFrame;
383 case FrameTree::Type::kPrerender:
384 return FrameType::kPrerenderMainFrame;
385 case FrameTree::Type::kFencedFrame:
Julie Jeongeun Kimf38c1eca2021-12-14 07:46:55386 return FrameType::kFencedFrameRoot;
387 }
388}
389
alexmose201c7cd2015-06-10 17:14:21390void FrameTreeNode::SetOpener(FrameTreeNode* opener) {
Harkiran Bolariaa8347782022-04-06 09:25:11391 TRACE_EVENT("navigation", "FrameTreeNode::SetOpener",
392 ChromeTrackEvent::kFrameTreeNodeInfo, opener);
alexmose201c7cd2015-06-10 17:14:21393 if (opener_) {
394 opener_->RemoveObserver(opener_observer_.get());
395 opener_observer_.reset();
396 }
397
398 opener_ = opener;
399
400 if (opener_) {
Jeremy Roman04f27c372017-10-27 15:20:55401 opener_observer_ = std::make_unique<OpenerDestroyedObserver>(this, false);
alexmose201c7cd2015-06-10 17:14:21402 opener_->AddObserver(opener_observer_.get());
403 }
404}
405
Wolfgang Beyerd8809db2020-09-30 15:29:39406void FrameTreeNode::SetOpenerDevtoolsFrameToken(
407 base::UnguessableToken opener_devtools_frame_token) {
408 DCHECK(!opener_devtools_frame_token_ ||
409 opener_devtools_frame_token_->is_empty());
410 opener_devtools_frame_token_ = std::move(opener_devtools_frame_token);
411}
412
jochen6004a362017-02-04 00:11:40413void FrameTreeNode::SetOriginalOpener(FrameTreeNode* opener) {
Avi Drissman36465f332017-09-11 20:49:39414 // The original opener tracks main frames only.
avi8d1aa162017-03-27 18:27:37415 DCHECK(opener == nullptr || !opener->parent());
jochen6004a362017-02-04 00:11:40416
Rakina Zata Amni3a48ae42022-05-05 03:39:56417 if (first_live_main_frame_in_original_opener_chain_) {
418 first_live_main_frame_in_original_opener_chain_->RemoveObserver(
419 original_opener_observer_.get());
Avi Drissman36465f332017-09-11 20:49:39420 original_opener_observer_.reset();
421 }
422
Rakina Zata Amni3a48ae42022-05-05 03:39:56423 first_live_main_frame_in_original_opener_chain_ = opener;
jochen6004a362017-02-04 00:11:40424
Rakina Zata Amni3a48ae42022-05-05 03:39:56425 if (first_live_main_frame_in_original_opener_chain_) {
426 original_opener_observer_ = std::make_unique<OpenerDestroyedObserver>(
427 this, true /* observing_original_opener */);
428 first_live_main_frame_in_original_opener_chain_->AddObserver(
429 original_opener_observer_.get());
jochen6004a362017-02-04 00:11:40430 }
431}
432
engedy6e2e0992017-05-25 18:58:42433void FrameTreeNode::SetCollapsed(bool collapsed) {
Dave Tapuska65e50aa2022-03-09 23:44:13434 DCHECK(!IsMainFrame() || IsFencedFrameRoot());
engedy6e2e0992017-05-25 18:58:42435 if (is_collapsed_ == collapsed)
436 return;
437
438 is_collapsed_ = collapsed;
439 render_manager_.OnDidChangeCollapsedState(collapsed);
440}
441
Harkiran Bolaria59290d62021-03-17 01:53:01442void FrameTreeNode::SetFrameTree(FrameTree& frame_tree) {
Arthur Sonzognif6785ec2022-12-05 10:11:50443 frame_tree_ = frame_tree;
Kevin McNeeb110d0c2021-10-26 15:53:00444 DCHECK(current_frame_host());
445 current_frame_host()->SetFrameTree(frame_tree);
446 RenderFrameHostImpl* speculative_frame_host =
447 render_manager_.speculative_frame_host();
448 if (speculative_frame_host)
449 speculative_frame_host->SetFrameTree(frame_tree);
Harkiran Bolaria59290d62021-03-17 01:53:01450}
451
Luna Luc3fdacdf2017-11-08 04:48:53452void FrameTreeNode::SetPendingFramePolicy(blink::FramePolicy frame_policy) {
Liam Bradyb0f1f0e2022-08-19 21:42:11453 // Inside of a fenced frame, the sandbox flags should not be able to change
454 // from its initial value. If the flags change, we have to assume the change
455 // came from a compromised renderer and terminate it.
456 // We will only do the check if the sandbox flags are already set to
457 // kFencedFrameForcedSandboxFlags. This is to allow the sandbox flags to
458 // be set initially (go from kNone -> kFencedFrameForcedSandboxFlags). Once
459 // it has been set, it cannot change to another value.
Dominic Farolino0b067632022-11-11 02:57:49460 // If the flags do change via a compromised fenced frame, then
461 // `RenderFrameHostImpl::DidChangeFramePolicy()` will detect that the change
462 // wasn't initiated by the parent, and will terminate the renderer before we
463 // reach this point, so we can CHECK() here.
464 bool fenced_frame_sandbox_flags_changed =
465 (IsFencedFrameRoot() &&
466 pending_frame_policy_.sandbox_flags ==
467 blink::kFencedFrameForcedSandboxFlags &&
468 frame_policy.sandbox_flags != blink::kFencedFrameForcedSandboxFlags);
469 CHECK(!fenced_frame_sandbox_flags_changed);
Liam Bradyb0f1f0e2022-08-19 21:42:11470
Ian Clellandcdc4f312017-10-13 22:24:12471 pending_frame_policy_.sandbox_flags = frame_policy.sandbox_flags;
alexmos6e940102016-01-19 22:47:25472
Ian Clellandcdc4f312017-10-13 22:24:12473 if (parent()) {
474 // Subframes should always inherit their parent's sandbox flags.
Alexander Timin381e7e182020-04-28 19:04:03475 pending_frame_policy_.sandbox_flags |=
Harkiran Bolaria4eacb3a2021-12-13 20:03:47476 parent()->browsing_context_state()->active_sandbox_flags();
Charlie Hue1b77ac2019-12-13 21:30:17477 // This is only applied on subframes; container policy and required document
478 // policy are not mutable on main frame.
Ian Clellandcdc4f312017-10-13 22:24:12479 pending_frame_policy_.container_policy = frame_policy.container_policy;
Charlie Hue1b77ac2019-12-13 21:30:17480 pending_frame_policy_.required_document_policy =
481 frame_policy.required_document_policy;
Ian Clellandcdc4f312017-10-13 22:24:12482 }
Liam Brady25a14162022-12-02 15:25:57483
484 // Fenced frame roots do not have a parent, so add an extra check here to
485 // still allow a fenced frame to properly set its container policy. The
486 // required document policy and sandbox flags should stay unmodified.
487 if (IsFencedFrameRoot()) {
488 DCHECK(pending_frame_policy_.required_document_policy.empty());
489 DCHECK_EQ(pending_frame_policy_.sandbox_flags, frame_policy.sandbox_flags);
490 pending_frame_policy_.container_policy = frame_policy.container_policy;
491 }
iclelland92f8c0b2017-04-19 12:43:05492}
493
Yuzu Saijo03dbf9b2022-07-22 04:29:45494void FrameTreeNode::SetAttributes(
495 blink::mojom::IframeAttributesPtr attributes) {
Arthur Sonzogni64457592022-11-22 11:08:59496 if (!credentialless() && attributes->credentialless) {
497 // Log this only when credentialless is changed to true.
Arthur Sonzogni2e9c6111392022-05-02 08:37:13498 GetContentClient()->browser()->LogWebFeatureForCurrentPage(
499 parent_, blink::mojom::WebFeature::kAnonymousIframe);
500 }
Yuzu Saijo03dbf9b2022-07-22 04:29:45501 attributes_ = std::move(attributes);
Arthur Sonzogni2e9c6111392022-05-02 08:37:13502}
503
fdegans4a49ce932015-03-12 17:11:37504bool FrameTreeNode::IsLoading() const {
505 RenderFrameHostImpl* current_frame_host =
506 render_manager_.current_frame_host();
fdegans4a49ce932015-03-12 17:11:37507
508 DCHECK(current_frame_host);
fdegans39ff0382015-04-29 19:04:39509
clamy610c63b32017-12-22 15:05:18510 if (navigation_request_)
511 return true;
clamy11e11512015-07-07 16:42:17512
clamy610c63b32017-12-22 15:05:18513 RenderFrameHostImpl* speculative_frame_host =
514 render_manager_.speculative_frame_host();
Daniel Chengc3d1e8d2021-06-23 02:11:45515 // TODO(dcheng): Shouldn't a FrameTreeNode with a speculative RenderFrameHost
516 // always be considered loading?
clamy610c63b32017-12-22 15:05:18517 if (speculative_frame_host && speculative_frame_host->is_loading())
518 return true;
fdegans4a49ce932015-03-12 17:11:37519 return current_frame_host->is_loading();
520}
521
Alex Moshchuk9b0fd822020-10-26 23:08:15522bool FrameTreeNode::HasPendingCrossDocumentNavigation() const {
523 // Having a |navigation_request_| on FrameTreeNode implies that there's an
524 // ongoing navigation that hasn't reached the ReadyToCommit state. If the
525 // navigation is between ReadyToCommit and DidCommitNavigation, the
526 // NavigationRequest will be held by RenderFrameHost, which is checked below.
527 if (navigation_request_ && !navigation_request_->IsSameDocument())
528 return true;
529
530 // Having a speculative RenderFrameHost should imply a cross-document
531 // navigation.
532 if (render_manager_.speculative_frame_host())
533 return true;
534
535 return render_manager_.current_frame_host()
536 ->HasPendingCommitForCrossDocumentNavigation();
537}
538
Arthur Hemeryc3380172018-01-22 14:00:17539void FrameTreeNode::TransferNavigationRequestOwnership(
540 RenderFrameHostImpl* render_frame_host) {
Andrey Kosyakovf2d4ff72018-10-29 20:09:59541 devtools_instrumentation::OnResetNavigationRequest(navigation_request_.get());
Arthur Hemeryc3380172018-01-22 14:00:17542 render_frame_host->SetNavigationRequest(std::move(navigation_request_));
543}
544
carloskc49005eb2015-06-16 11:25:07545void FrameTreeNode::CreatedNavigationRequest(
dcheng9bfa5162016-04-09 01:00:57546 std::unique_ptr<NavigationRequest> navigation_request) {
arthursonzognic79c251c2016-08-18 15:00:37547 // This is never called when navigating to a Javascript URL. For the loading
548 // state, this matches what Blink is doing: Blink doesn't send throbber
549 // notifications for Javascript URLS.
550 DCHECK(!navigation_request->common_params().url.SchemeIs(
551 url::kJavaScriptScheme));
552
Yu Gaoc8c18552022-06-22 14:38:45553 bool was_previously_loading =
Arthur Sonzognif6785ec2022-12-05 10:11:50554 frame_tree().LoadingTree()->IsLoadingIncludingInnerFrameTrees();
clamy44e84ce2016-02-22 15:38:25555
Rakina Zata Amnif8f2bb62022-11-23 05:54:32556 // Reset the previous NavigationRequest owned by `this`. However, there's no
557 // need to reset the state: there's still an ongoing load, and the
clamy82a2f4d2016-02-02 14:20:41558 // RenderFrameHostManager will take care of updates to the speculative
559 // RenderFrameHost in DidCreateNavigationRequest below.
jamcd0b7b22017-03-24 22:13:05560 if (was_previously_loading) {
Mohamed Abdelhalimf03d4a22019-10-01 13:34:31561 if (navigation_request_ && navigation_request_->IsNavigationStarted()) {
jamcd0b7b22017-03-24 22:13:05562 // Mark the old request as aborted.
Mohamed Abdelhalimb4db22a2019-06-18 10:46:52563 navigation_request_->set_net_error(net::ERR_ABORTED);
jamcd0b7b22017-03-24 22:13:05564 }
Daniel Cheng390e2a72022-09-28 06:07:53565 ResetNavigationRequestButKeepState();
jamcd0b7b22017-03-24 22:13:05566 }
clamy44e84ce2016-02-22 15:38:25567
568 navigation_request_ = std::move(navigation_request);
Shubhie Panickerddf2a4e2018-03-06 00:09:06569 if (was_discarded_) {
570 navigation_request_->set_was_discarded();
571 was_discarded_ = false;
572 }
clamy8e2e299202016-04-05 11:44:59573 render_manager()->DidCreateNavigationRequest(navigation_request_.get());
fdegans39ff0382015-04-29 19:04:39574
Lucas Furukawa Gadanief8290a2019-07-29 20:27:51575 bool to_different_document = !NavigationTypeUtils::IsSameDocument(
arthursonzogni92f18682017-02-08 23:00:04576 navigation_request_->common_params().navigation_type);
577
578 DidStartLoading(to_different_document, was_previously_loading);
clamydcb434c12015-04-16 19:29:16579}
580
Daniel Cheng390e2a72022-09-28 06:07:53581void FrameTreeNode::ResetNavigationRequest(NavigationDiscardReason reason) {
582 if (!navigation_request_)
583 return;
584
585 ResetNavigationRequestButKeepState();
586
587 // The RenderFrameHostManager should clean up any speculative RenderFrameHost
588 // it created for the navigation. Also register that the load stopped.
589 DidStopLoading();
Rakina Zata Amnif8f2bb62022-11-23 05:54:32590 render_manager_.DiscardSpeculativeRFHIfUnused(reason);
Daniel Cheng390e2a72022-09-28 06:07:53591}
592
593void FrameTreeNode::ResetNavigationRequestButKeepState() {
fdegans39ff0382015-04-29 19:04:39594 if (!navigation_request_)
595 return;
John Abd-El-Malekdcc7bf42017-09-12 22:30:23596
Andrey Kosyakovf2d4ff72018-10-29 20:09:59597 devtools_instrumentation::OnResetNavigationRequest(navigation_request_.get());
clamydcb434c12015-04-16 19:29:16598 navigation_request_.reset();
599}
600
Nate Chapin9aabf5f2021-11-12 00:31:19601void FrameTreeNode::DidStartLoading(bool should_show_loading_ui,
clamy44e84ce2016-02-22 15:38:25602 bool was_previously_loading) {
Camille Lamyefd54b02018-10-04 16:54:14603 TRACE_EVENT2("navigation", "FrameTreeNode::DidStartLoading",
Nate Chapin9aabf5f2021-11-12 00:31:19604 "frame_tree_node", frame_tree_node_id(),
605 "should_show_loading_ui ", should_show_loading_ui);
Clark DuVallc97bcf72021-12-08 22:58:24606 base::ElapsedTimer timer;
fdegansa696e5112015-04-17 01:57:59607
Arthur Sonzognif6785ec2022-12-05 10:11:50608 frame_tree().LoadingTree()->DidStartLoadingNode(*this, should_show_loading_ui,
609 was_previously_loading);
fdegansa696e5112015-04-17 01:57:59610
611 // Set initial load progress and update overall progress. This will notify
612 // the WebContents of the load progress change.
Sreeja Kamishetty15f9944a22022-03-10 10:16:08613 //
614 // Only notify when the load is triggered from primary/prerender main frame as
615 // we only update load progress for these nodes which happens when the frame
616 // tree matches the loading tree.
Arthur Sonzognif6785ec2022-12-05 10:11:50617 if (&frame_tree() == frame_tree().LoadingTree())
Sreeja Kamishetty15f9944a22022-03-10 10:16:08618 DidChangeLoadProgress(blink::kInitialLoadProgress);
fdegansa696e5112015-04-17 01:57:59619
Harkiran Bolaria3f83fba72022-03-10 17:48:40620 // Notify the proxies of the event.
621 current_frame_host()->browsing_context_state()->OnDidStartLoading();
Clark DuVallc97bcf72021-12-08 22:58:24622 base::UmaHistogramTimes(
623 base::StrCat({"Navigation.DidStartLoading.",
Ian Vollick5f45867c2022-08-05 08:29:56624 IsOutermostMainFrame() ? "MainFrame" : "Subframe"}),
Clark DuVallc97bcf72021-12-08 22:58:24625 timer.Elapsed());
fdegansa696e5112015-04-17 01:57:59626}
627
628void FrameTreeNode::DidStopLoading() {
Camille Lamyefd54b02018-10-04 16:54:14629 TRACE_EVENT1("navigation", "FrameTreeNode::DidStopLoading", "frame_tree_node",
630 frame_tree_node_id());
fdegansa696e5112015-04-17 01:57:59631 // Set final load progress and update overall progress. This will notify
632 // the WebContents of the load progress change.
Sreeja Kamishetty15f9944a22022-03-10 10:16:08633 //
634 // Only notify when the load is triggered from primary/prerender main frame as
635 // we only update load progress for these nodes which happens when the frame
636 // tree matches the loading tree.
Arthur Sonzognif6785ec2022-12-05 10:11:50637 if (&frame_tree() == frame_tree().LoadingTree())
Sreeja Kamishetty15f9944a22022-03-10 10:16:08638 DidChangeLoadProgress(blink::kFinalLoadProgress);
fdegansa696e5112015-04-17 01:57:59639
Harkiran Bolaria3f83fba72022-03-10 17:48:40640 // Notify the proxies of the event.
641 current_frame_host()->browsing_context_state()->OnDidStopLoading();
Lucas Furukawa Gadani6faef602019-05-06 21:16:03642
Arthur Sonzognif6785ec2022-12-05 10:11:50643 FrameTree* loading_tree = frame_tree().LoadingTree();
Sreeja Kamishetty15f9944a22022-03-10 10:16:08644 // When loading tree is null, ignore invoking DidStopLoadingNode as the frame
645 // tree is already deleted. This can happen when prerendering gets cancelled
646 // and DidStopLoading is called during FrameTree destruction.
647 if (loading_tree)
648 loading_tree->DidStopLoadingNode(*this);
fdegansa696e5112015-04-17 01:57:59649}
650
651void FrameTreeNode::DidChangeLoadProgress(double load_progress) {
Sreeja Kamishetty0be3b1b2021-08-12 17:04:15652 DCHECK_GE(load_progress, blink::kInitialLoadProgress);
653 DCHECK_LE(load_progress, blink::kFinalLoadProgress);
654 current_frame_host()->DidChangeLoadProgress(load_progress);
fdegansa696e5112015-04-17 01:57:59655}
656
clamyf73862c42015-07-08 12:31:33657bool FrameTreeNode::StopLoading() {
arthursonzogni66f711c2019-10-08 14:40:36658 if (navigation_request_ && navigation_request_->IsNavigationStarted())
659 navigation_request_->set_net_error(net::ERR_ABORTED);
Daniel Cheng390e2a72022-09-28 06:07:53660 ResetNavigationRequest(NavigationDiscardReason::kCancelled);
clamyf73862c42015-07-08 12:31:33661
clamyf73862c42015-07-08 12:31:33662 if (!IsMainFrame())
663 return true;
664
665 render_manager_.Stop();
666 return true;
667}
668
alexmos21acae52015-11-07 01:04:43669void FrameTreeNode::DidFocus() {
670 last_focus_time_ = base::TimeTicks::Now();
ericwilligers254597b2016-10-17 10:32:31671 for (auto& observer : observers_)
672 observer.OnFrameTreeNodeFocused(this);
alexmos21acae52015-11-07 01:04:43673}
674
clamy44e84ce2016-02-22 15:38:25675void FrameTreeNode::BeforeUnloadCanceled() {
Julie Jeongeun Kim8cf7ae32022-05-02 03:47:29676 // TODO(clamy): Support BeforeUnload in subframes. Fenced Frames don't run
677 // BeforeUnload. Maybe need to check whether other MPArch inner pages cases
678 // need beforeunload(e.g., portals, GuestView if it gets ported to MPArch).
Ian Vollick1c6dd3e2022-04-13 02:06:26679 if (!IsOutermostMainFrame())
clamy44e84ce2016-02-22 15:38:25680 return;
681
682 RenderFrameHostImpl* current_frame_host =
683 render_manager_.current_frame_host();
684 DCHECK(current_frame_host);
685 current_frame_host->ResetLoadingState();
686
clamy610c63b32017-12-22 15:05:18687 RenderFrameHostImpl* speculative_frame_host =
688 render_manager_.speculative_frame_host();
689 if (speculative_frame_host)
690 speculative_frame_host->ResetLoadingState();
Alexander Timin23c110b2021-01-14 02:39:04691 // Note: there is no need to set an error code on the NavigationHandle as
692 // the observers have not been notified about its creation.
693 // We also reset navigation request only when this navigation request was
694 // responsible for this dialog, as a new navigation request might cancel
695 // existing unrelated dialog.
Daniel Cheng390e2a72022-09-28 06:07:53696 if (navigation_request_ && navigation_request_->IsWaitingForBeforeUnload()) {
697 ResetNavigationRequest(NavigationDiscardReason::kCancelled);
698 }
clamy44e84ce2016-02-22 15:38:25699}
700
Mustaq Ahmedecb5c38e2020-07-29 00:34:30701bool FrameTreeNode::NotifyUserActivation(
702 blink::mojom::UserActivationNotificationType notification_type) {
Alex Moshchuk03904192021-04-02 07:29:08703 // User Activation V2 requires activating all ancestor frames in addition to
704 // the current frame. See
705 // https://html.spec.whatwg.org/multipage/interaction.html#tracking-user-activation.
Alexander Timina1dfadaa2020-04-28 13:30:06706 for (RenderFrameHostImpl* rfh = current_frame_host(); rfh;
707 rfh = rfh->GetParent()) {
John Delaneyb625dca92021-04-14 17:00:34708 rfh->DidReceiveUserActivation();
Miyoung Shin8a66ec022022-11-28 23:50:09709 rfh->ActivateUserActivation(notification_type);
John Delaneyedd8d6c2019-01-25 00:23:57710 }
Alex Moshchuk03904192021-04-02 07:29:08711
Harkiran Bolaria0b3bdef02022-03-10 13:04:40712 current_frame_host()->browsing_context_state()->set_has_active_user_gesture(
713 true);
Mustaq Ahmeda5dfa60b2018-12-08 00:30:14714
Mustaq Ahmed0180320f2019-03-21 16:07:01715 // See the "Same-origin Visibility" section in |UserActivationState| class
716 // doc.
Mustaq Ahmede5f12562019-10-30 18:02:03717 if (base::FeatureList::IsEnabled(
Garrett Tanzer753cc532022-03-02 21:30:59718 features::kUserActivationSameOriginVisibility)) {
Mustaq Ahmeda5dfa60b2018-12-08 00:30:14719 const url::Origin& current_origin =
720 this->current_frame_host()->GetLastCommittedOrigin();
Arthur Sonzognif6785ec2022-12-05 10:11:50721 for (FrameTreeNode* node : frame_tree().Nodes()) {
Mustaq Ahmeda5dfa60b2018-12-08 00:30:14722 if (node->current_frame_host()->GetLastCommittedOrigin().IsSameOriginWith(
723 current_origin)) {
Miyoung Shin8a66ec022022-11-28 23:50:09724 node->current_frame_host()->ActivateUserActivation(notification_type);
Mustaq Ahmeda5dfa60b2018-12-08 00:30:14725 }
726 }
727 }
728
Carlos Caballero40b0efd2021-01-26 11:55:00729 navigator().controller().NotifyUserActivation();
Alex Moshchuk03904192021-04-02 07:29:08730 current_frame_host()->MaybeIsolateForUserActivation();
Shivani Sharma194877032019-03-07 17:52:47731
Mustaq Ahmedc4cb7162018-06-05 16:28:36732 return true;
733}
734
735bool FrameTreeNode::ConsumeTransientUserActivation() {
Miyoung Shin8a66ec022022-11-28 23:50:09736 bool was_active = current_frame_host()->IsActiveUserActivation();
Arthur Sonzognif6785ec2022-12-05 10:11:50737 for (FrameTreeNode* node : frame_tree().Nodes()) {
Miyoung Shin8a66ec022022-11-28 23:50:09738 node->current_frame_host()->ConsumeTransientUserActivation();
Garrett Tanzer753cc532022-03-02 21:30:59739 }
Harkiran Bolaria0b3bdef02022-03-10 13:04:40740 current_frame_host()->browsing_context_state()->set_has_active_user_gesture(
741 false);
Mustaq Ahmedc4cb7162018-06-05 16:28:36742 return was_active;
743}
744
Shivani Sharmac4f561582018-11-15 15:58:39745bool FrameTreeNode::ClearUserActivation() {
Arthur Sonzognif6785ec2022-12-05 10:11:50746 for (FrameTreeNode* node : frame_tree().SubtreeNodes(this))
Miyoung Shin8a66ec022022-11-28 23:50:09747 node->current_frame_host()->ClearUserActivation();
Harkiran Bolaria0b3bdef02022-03-10 13:04:40748 current_frame_host()->browsing_context_state()->set_has_active_user_gesture(
749 false);
Shivani Sharmac4f561582018-11-15 15:58:39750 return true;
751}
752
Ella Ge9caed612019-08-09 16:17:25753bool FrameTreeNode::VerifyUserActivation() {
Ella Gea78f6772019-12-11 10:35:25754 DCHECK(base::FeatureList::IsEnabled(
755 features::kBrowserVerifiedUserActivationMouse) ||
756 base::FeatureList::IsEnabled(
757 features::kBrowserVerifiedUserActivationKeyboard));
758
Ella Ge9caed612019-08-09 16:17:25759 return render_manager_.current_frame_host()
760 ->GetRenderWidgetHost()
Mustaq Ahmed83bb1722019-10-22 20:00:10761 ->RemovePendingUserActivationIfAvailable();
Ella Ge9caed612019-08-09 16:17:25762}
763
Mustaq Ahmedc4cb7162018-06-05 16:28:36764bool FrameTreeNode::UpdateUserActivationState(
Mustaq Ahmeddc195e5b2020-08-04 18:45:11765 blink::mojom::UserActivationUpdateType update_type,
766 blink::mojom::UserActivationNotificationType notification_type) {
Ella Ge9caed612019-08-09 16:17:25767 bool update_result = false;
Mustaq Ahmedc4cb7162018-06-05 16:28:36768 switch (update_type) {
Antonio Gomes4b2c5132020-01-16 11:49:48769 case blink::mojom::UserActivationUpdateType::kConsumeTransientActivation:
Ella Ge9caed612019-08-09 16:17:25770 update_result = ConsumeTransientUserActivation();
771 break;
Antonio Gomes4b2c5132020-01-16 11:49:48772 case blink::mojom::UserActivationUpdateType::kNotifyActivation:
Mustaq Ahmeddc195e5b2020-08-04 18:45:11773 update_result = NotifyUserActivation(notification_type);
Ella Ge9caed612019-08-09 16:17:25774 break;
Antonio Gomes4b2c5132020-01-16 11:49:48775 case blink::mojom::UserActivationUpdateType::
Liviu Tintad9391fb92020-09-28 23:50:07776 kNotifyActivationPendingBrowserVerification: {
777 const bool user_activation_verified = VerifyUserActivation();
778 // Add UMA metric for when browser user activation verification succeeds
779 base::UmaHistogramBoolean("Event.BrowserVerifiedUserActivation",
780 user_activation_verified);
781 if (user_activation_verified) {
Mustaq Ahmedecb5c38e2020-07-29 00:34:30782 update_result = NotifyUserActivation(
Mustaq Ahmed2cfb0402020-09-29 19:24:35783 blink::mojom::UserActivationNotificationType::kInteraction);
Antonio Gomes4b2c5132020-01-16 11:49:48784 update_type = blink::mojom::UserActivationUpdateType::kNotifyActivation;
Ella Ge9caed612019-08-09 16:17:25785 } else {
arthursonzogni9816b9192021-03-29 16:09:19786 // TODO(https://crbug.com/848778): We need to decide what to do when
787 // user activation verification failed. NOTREACHED here will make all
Ella Ge9caed612019-08-09 16:17:25788 // unrelated tests that inject event to renderer fail.
789 return false;
790 }
Liviu Tintad9391fb92020-09-28 23:50:07791 } break;
Antonio Gomes4b2c5132020-01-16 11:49:48792 case blink::mojom::UserActivationUpdateType::kClearActivation:
Ella Ge9caed612019-08-09 16:17:25793 update_result = ClearUserActivation();
794 break;
Mustaq Ahmedc4cb7162018-06-05 16:28:36795 }
Mustaq Ahmeddc195e5b2020-08-04 18:45:11796 render_manager_.UpdateUserActivationState(update_type, notification_type);
Ella Ge9caed612019-08-09 16:17:25797 return update_result;
japhet61835ae12017-01-20 01:25:39798}
799
Arthur Sonzognif8840b92018-11-07 14:10:35800void FrameTreeNode::PruneChildFrameNavigationEntries(
801 NavigationEntryImpl* entry) {
802 for (size_t i = 0; i < current_frame_host()->child_count(); ++i) {
803 FrameTreeNode* child = current_frame_host()->child_at(i);
804 if (child->is_created_by_script_) {
805 entry->RemoveEntryForFrame(child,
806 /* only_if_different_position = */ false);
807 } else {
808 child->PruneChildFrameNavigationEntries(entry);
809 }
810 }
811}
812
arthursonzogni034bb9c2020-10-01 08:29:56813void FrameTreeNode::SetInitialPopupURL(const GURL& initial_popup_url) {
814 DCHECK(initial_popup_url_.is_empty());
Abhijeet Kandalkarb86993b2022-11-22 05:17:40815 DCHECK(is_on_initial_empty_document());
arthursonzogni034bb9c2020-10-01 08:29:56816 initial_popup_url_ = initial_popup_url;
817}
818
819void FrameTreeNode::SetPopupCreatorOrigin(
820 const url::Origin& popup_creator_origin) {
Abhijeet Kandalkarb86993b2022-11-22 05:17:40821 DCHECK(is_on_initial_empty_document());
arthursonzogni034bb9c2020-10-01 08:29:56822 popup_creator_origin_ = popup_creator_origin;
823}
824
Rakina Zata Amni4b1968d2021-09-09 03:29:47825void FrameTreeNode::WriteIntoTrace(
Alexander Timin074cd182022-03-23 18:11:22826 perfetto::TracedProto<TraceProto> proto) const {
Rakina Zata Amni4b1968d2021-09-09 03:29:47827 proto->set_frame_tree_node_id(frame_tree_node_id());
Alexander Timin074cd182022-03-23 18:11:22828 proto->set_is_main_frame(IsMainFrame());
829 proto.Set(TraceProto::kCurrentFrameHost, current_frame_host());
830 proto.Set(TraceProto::kSpeculativeFrameHost,
831 render_manager()->speculative_frame_host());
Rakina Zata Amni4b1968d2021-09-09 03:29:47832}
833
Carlos Caballero76711352021-03-24 17:38:21834bool FrameTreeNode::HasNavigation() {
835 if (navigation_request())
836 return true;
837
838 // Same-RenderFrameHost navigation is committing:
839 if (current_frame_host()->HasPendingCommitNavigation())
840 return true;
841
842 // Cross-RenderFrameHost navigation is committing:
843 if (render_manager()->speculative_frame_host())
844 return true;
845
846 return false;
847}
848
Dominic Farolino4bc10ee2021-08-31 00:37:36849bool FrameTreeNode::IsFencedFrameRoot() const {
Abhijeet Kandalkar3f29bc42022-09-23 12:39:58850 return fenced_frame_status_ == FencedFrameStatus::kFencedFrameRoot;
shivanigithubf3ddff52021-07-03 22:06:30851}
852
853bool FrameTreeNode::IsInFencedFrameTree() const {
Abhijeet Kandalkar3f29bc42022-09-23 12:39:58854 return fenced_frame_status_ != FencedFrameStatus::kNotNestedInFencedFrame;
shivanigithubf3ddff52021-07-03 22:06:30855}
856
Garrett Tanzer34cb92fe2022-09-28 17:50:54857const absl::optional<FencedFrameURLMapping::FencedFrameProperties>&
858FrameTreeNode::GetFencedFrameProperties() {
shivanigithub4cd016a2021-09-20 21:10:30859 if (!IsInFencedFrameTree()) {
Garrett Tanzer34cb92fe2022-09-28 17:50:54860 // If we might be in a urn iframe, try to find the "urn iframe root"
861 // and if it exists, return the attached `FencedFrameProperties`.
862 if (blink::features::IsAllowURNsInIframeEnabled()) {
863 FrameTreeNode* node = this;
864 while (node->parent()) {
865 CHECK(node->parent()->frame_tree_node());
866 if (node->fenced_frame_properties_.has_value()) {
867 return node->fenced_frame_properties_;
868 }
869 node = node->parent()->frame_tree_node();
870 }
871 }
872 return fenced_frame_properties_;
873 }
874
Dominic Farolino0b067632022-11-11 02:57:49875 // Because we already confirmed we're in a fenced frame tree, we know
876 // there must be a fenced frame root with properties stored.
Arthur Sonzognif6785ec2022-12-05 10:11:50877 CHECK(frame_tree().root()->fenced_frame_properties_.has_value());
878 return frame_tree().root()->fenced_frame_properties_;
Garrett Tanzer34cb92fe2022-09-28 17:50:54879}
880
Yao Xiaoa2337ad2022-10-12 20:59:29881size_t FrameTreeNode::GetFencedFrameDepth() {
882 size_t depth = 0;
883 FrameTreeNode* node = this;
884
885 while (node->fenced_frame_status() !=
886 FencedFrameStatus::kNotNestedInFencedFrame) {
887 if (node->fenced_frame_status() == FencedFrameStatus::kFencedFrameRoot) {
888 depth += 1;
889 } else {
890 DCHECK_EQ(node->fenced_frame_status(),
891 FencedFrameStatus::kIframeNestedWithinFencedFrame);
892 }
893
894 DCHECK(node->GetParentOrOuterDocument());
895 node = node->GetParentOrOuterDocument()->frame_tree_node();
896 }
897
898 return depth;
899}
900
Garrett Tanzer34cb92fe2022-09-28 17:50:54901absl::optional<base::UnguessableToken> FrameTreeNode::GetFencedFrameNonce() {
902 auto& root_fenced_frame_properties = GetFencedFrameProperties();
903 if (!root_fenced_frame_properties.has_value()) {
904 return absl::nullopt;
905 }
906 return root_fenced_frame_properties->partition_nonce;
907}
908
909void FrameTreeNode::SetFencedFramePropertiesIfNeeded() {
910 if (!IsFencedFrameRoot()) {
shivanigithub4cd016a2021-09-20 21:10:30911 return;
912 }
913
Garrett Tanzer34cb92fe2022-09-28 17:50:54914 // The fenced frame properties are set only on the fenced frame root.
915 // In the future, they will be set on the FrameTree instead.
916 fenced_frame_properties_ = FencedFrameURLMapping::FencedFrameProperties();
shivanigithub4cd016a2021-09-20 21:10:30917}
918
Nan Line376738a2022-03-25 22:05:41919absl::optional<blink::mojom::FencedFrameMode>
920FrameTreeNode::GetFencedFrameMode() {
Garrett Tanzera42fdef2022-06-13 16:09:14921 if (!IsInFencedFrameTree()) {
Nan Line376738a2022-03-25 22:05:41922 return absl::nullopt;
Garrett Tanzera42fdef2022-06-13 16:09:14923 }
Nan Lin171fe9a2022-02-17 16:42:16924
Dominic Farolino0b067632022-11-11 02:57:49925 FrameTreeNode* outer_delegate_node = render_manager()->GetOuterDelegateNode();
926 DCHECK(outer_delegate_node);
Nan Lin171fe9a2022-02-17 16:42:16927
Dominic Farolino0b067632022-11-11 02:57:49928 FencedFrame* fenced_frame = FindFencedFrame(outer_delegate_node);
929 DCHECK(fenced_frame);
Nan Line376738a2022-03-25 22:05:41930
Dominic Farolino0b067632022-11-11 02:57:49931 return fenced_frame->mode();
Nan Lin171fe9a2022-02-17 16:42:16932}
933
Nan Linaaf84f72021-12-02 22:31:56934bool FrameTreeNode::IsErrorPageIsolationEnabled() const {
Nan Lind9de87d2022-03-18 16:53:03935 // Error page isolation is enabled for main frames only (crbug.com/1092524).
936 // Note that this will also enable error page isolation for fenced frames in
937 // MPArch mode, but not ShadowDOM mode.
938 // See the issue in crbug.com/1264224#c7 for why it can't be enabled for
939 // ShadowDOM mode.
940 return SiteIsolationPolicy::IsErrorPageIsolationEnabled(IsMainFrame());
Nan Linaaf84f72021-12-02 22:31:56941}
942
W. James MacLean81b8d01f2022-01-25 20:50:59943void FrameTreeNode::SetSrcdocValue(const std::string& srcdoc_value) {
944 srcdoc_value_ = srcdoc_value;
945}
946
Yao Xiaoa2337ad2022-10-12 20:59:29947std::vector<const FencedFrameURLMapping::SharedStorageBudgetMetadata*>
Yao Xiao1ac702d2022-06-08 17:20:49948FrameTreeNode::FindSharedStorageBudgetMetadata() {
Yao Xiaoa2337ad2022-10-12 20:59:29949 std::vector<const FencedFrameURLMapping::SharedStorageBudgetMetadata*> result;
Yao Xiao1ac702d2022-06-08 17:20:49950 FrameTreeNode* node = this;
951
952 while (true) {
Garrett Tanzer2975eeac2022-08-22 16:34:01953 if (node->fenced_frame_properties_ &&
954 node->fenced_frame_properties_->shared_storage_budget_metadata) {
Yao Xiaoa2337ad2022-10-12 20:59:29955 result.emplace_back(node->fenced_frame_properties_
956 ->shared_storage_budget_metadata.value());
Yao Xiao1ac702d2022-06-08 17:20:49957 }
958
959 if (node->GetParentOrOuterDocument()) {
960 node = node->GetParentOrOuterDocument()->frame_tree_node();
961 } else {
962 break;
963 }
964 }
965
Yao Xiaoa2337ad2022-10-12 20:59:29966 return result;
Yao Xiao1ac702d2022-06-08 17:20:49967}
968
Harkiran Bolariaebbe7702022-02-22 19:19:03969const scoped_refptr<BrowsingContextState>&
970FrameTreeNode::GetBrowsingContextStateForSubframe() const {
971 DCHECK(!IsMainFrame());
972 return current_frame_host()->browsing_context_state();
973}
974
Arthur Hemerye4659282022-03-28 08:36:15975void FrameTreeNode::ClearOpenerReferences() {
976 // Simulate the FrameTreeNode being dead to opener observers. They will
977 // nullify their opener.
978 // Note: observers remove themselves from observers_, no need to take care of
979 // that manually.
980 for (auto& observer : observers_)
981 observer.OnFrameTreeNodeDisownedOpenee(this);
982}
983
Liam Bradyd2a41e152022-07-19 13:58:48984bool FrameTreeNode::AncestorOrSelfHasCSPEE() const {
985 // Check if CSPEE is set in this frame or any ancestor frames.
Yuzu Saijo03dbf9b2022-07-22 04:29:45986 return csp_attribute() || (parent() && parent()->required_csp());
Liam Bradyd2a41e152022-07-19 13:58:48987}
988
Miyoung Shin7cf88b42022-11-07 13:22:30989void FrameTreeNode::RestartNavigationAsCrossDocument(
990 std::unique_ptr<NavigationRequest> navigation_request) {
991 navigator().RestartNavigationAsCrossDocument(std::move(navigation_request));
992}
993
Julie Jeongeun Kimc1b07c32022-11-11 10:26:32994Navigator& FrameTreeNode::GetCurrentNavigator() {
995 return navigator();
996}
997
Miyoung Shine16cd2262022-11-30 05:52:16998RenderFrameHostManager& FrameTreeNode::GetRenderFrameHostManager() {
999 return render_manager_;
1000}
1001
Julie Jeongeun Kim2132b37f82022-11-23 08:30:461002void FrameTreeNode::SetFocusedFrame(SiteInstanceGroup* source) {
1003 frame_tree_->delegate()->SetFocusedFrame(this, source);
1004}
1005
Julie Jeongeun Kim0e242242022-11-30 10:45:091006void FrameTreeNode::DidChangeReferrerPolicy(
1007 network::mojom::ReferrerPolicy referrer_policy) {
1008 navigator().controller().DidChangeReferrerPolicy(this, referrer_policy);
1009}
1010
Miyoung Shinff13ed22022-11-30 09:21:471011std::unique_ptr<NavigationRequest>
1012FrameTreeNode::CreateNavigationRequestForSynchronousRendererCommit(
1013 RenderFrameHostImpl* render_frame_host,
1014 bool is_same_document,
1015 const GURL& url,
1016 const url::Origin& origin,
1017 const net::IsolationInfo& isolation_info_for_subresources,
1018 blink::mojom::ReferrerPtr referrer,
1019 const ui::PageTransition& transition,
1020 bool should_replace_current_entry,
1021 const std::string& method,
1022 bool has_transient_activation,
1023 bool is_overriding_user_agent,
1024 const std::vector<GURL>& redirects,
1025 const GURL& original_url,
1026 std::unique_ptr<CrossOriginEmbedderPolicyReporter> coep_reporter,
1027 std::unique_ptr<WebBundleNavigationInfo> web_bundle_navigation_info,
1028 std::unique_ptr<SubresourceWebBundleNavigationInfo>
1029 subresource_web_bundle_navigation_info,
1030 int http_response_code) {
1031 return NavigationRequest::CreateForSynchronousRendererCommit(
1032 this, render_frame_host, is_same_document, url, origin,
1033 isolation_info_for_subresources, std::move(referrer), transition,
1034 should_replace_current_entry, method, has_transient_activation,
1035 is_overriding_user_agent, redirects, original_url,
1036 std::move(coep_reporter), std::move(web_bundle_navigation_info),
1037 std::move(subresource_web_bundle_navigation_info), http_response_code);
1038}
1039
Miyoung Shinb5561802022-12-01 08:21:351040void FrameTreeNode::CancelNavigation() {
1041 if (navigation_request() && navigation_request()->IsNavigationStarted()) {
1042 navigation_request()->set_net_error(net::ERR_ABORTED);
1043 }
1044 ResetNavigationRequest(NavigationDiscardReason::kCancelled);
1045}
1046
[email protected]9b159a52013-10-03 17:24:551047} // namespace content