blob: 456176534a5bcc8c59358b0503bf6352c66ed2e0 [file] [log] [blame]
[email protected]9b159a52013-10-03 17:24:551// Copyright 2013 The Chromium Authors. All rights reserved.
2// 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"
danakjc492bf82020-09-09 20:02:4423#include "content/browser/renderer_host/navigation_controller_impl.h"
24#include "content/browser/renderer_host/navigation_request.h"
25#include "content/browser/renderer_host/navigator.h"
26#include "content/browser/renderer_host/navigator_delegate.h"
27#include "content/browser/renderer_host/render_frame_host_impl.h"
[email protected]94d0cc12013-12-18 00:07:4128#include "content/browser/renderer_host/render_view_host_impl.h"
Lucas Furukawa Gadanief8290a2019-07-29 20:27:5129#include "content/common/navigation_params_utils.h"
dmazzonie950ea232015-03-13 21:39:4530#include "content/public/browser/browser_thread.h"
Nan Linaaf84f72021-12-02 22:31:5631#include "content/public/browser/site_isolation_policy.h"
Mustaq Ahmeda5dfa60b2018-12-08 00:30:1432#include "content/public/common/content_features.h"
arthursonzognib93a4472020-04-10 07:38:0033#include "services/network/public/cpp/web_sandbox_flags.h"
34#include "services/network/public/mojom/web_sandbox_flags.mojom-shared.h"
Harkiran Bolaria59290d62021-03-17 01:53:0135#include "third_party/blink/public/common/features.h"
Sreeja Kamishetty0be3b1b2021-08-12 17:04:1536#include "third_party/blink/public/common/loader/loader_constants.h"
Antonio Gomes4b2c5132020-01-16 11:49:4837#include "third_party/blink/public/mojom/frame/user_activation_update_types.mojom.h"
Julie Jeongeun Kimd90e2dd2020-03-03 11:45:3738#include "third_party/blink/public/mojom/security_context/insecure_request_policy.mojom.h"
[email protected]9b159a52013-10-03 17:24:5539
40namespace content {
41
dmazzonie950ea232015-03-13 21:39:4542namespace {
43
44// This is a global map between frame_tree_node_ids and pointers to
45// FrameTreeNodes.
Takuto Ikutaadf31eb2019-01-05 00:32:4846typedef std::unordered_map<int, FrameTreeNode*> FrameTreeNodeIdMap;
dmazzonie950ea232015-03-13 21:39:4547
scottmg5e65e3a2017-03-08 08:48:4648base::LazyInstance<FrameTreeNodeIdMap>::DestructorAtExit
49 g_frame_tree_node_id_map = LAZY_INSTANCE_INITIALIZER;
dmazzonie950ea232015-03-13 21:39:4550
Nan Line376738a2022-03-25 22:05:4151FencedFrame* FindFencedFrame(const FrameTreeNode* frame_tree_node) {
52 // TODO(crbug.com/1123606): Consider having a pointer to `FencedFrame` in
53 // `FrameTreeNode` or having a map between them.
54
55 // Try and find the `FencedFrame` that `frame_tree_node` represents.
56 DCHECK(frame_tree_node->parent());
57 std::vector<FencedFrame*> fenced_frames =
58 frame_tree_node->parent()->GetFencedFrames();
59 for (FencedFrame* fenced_frame : fenced_frames) {
60 if (frame_tree_node->frame_tree_node_id() ==
61 fenced_frame->GetOuterDelegateFrameTreeNodeId()) {
62 return fenced_frame;
63 }
64 }
65 return nullptr;
66}
67
fdegansa696e5112015-04-17 01:57:5968} // namespace
fdegans1d16355162015-03-26 11:58:3469
alexmose201c7cd2015-06-10 17:14:2170// This observer watches the opener of its owner FrameTreeNode and clears the
Arthur Hemerye4659282022-03-28 08:36:1571// owner's opener if the opener is destroyed or swaps BrowsingInstance.
alexmose201c7cd2015-06-10 17:14:2172class FrameTreeNode::OpenerDestroyedObserver : public FrameTreeNode::Observer {
73 public:
jochen6004a362017-02-04 00:11:4074 OpenerDestroyedObserver(FrameTreeNode* owner, bool observing_original_opener)
75 : owner_(owner), observing_original_opener_(observing_original_opener) {}
alexmose201c7cd2015-06-10 17:14:2176
Peter Boström9b036532021-10-28 23:37:2877 OpenerDestroyedObserver(const OpenerDestroyedObserver&) = delete;
78 OpenerDestroyedObserver& operator=(const OpenerDestroyedObserver&) = delete;
79
alexmose201c7cd2015-06-10 17:14:2180 // FrameTreeNode::Observer
81 void OnFrameTreeNodeDestroyed(FrameTreeNode* node) override {
Arthur Hemerye4659282022-03-28 08:36:1582 NullifyOpener(node);
83 }
84
85 // FrameTreeNode::Observer
86 void OnFrameTreeNodeDisownedOpenee(FrameTreeNode* node) override {
87 NullifyOpener(node);
88 }
89
90 void NullifyOpener(FrameTreeNode* node) {
jochen6004a362017-02-04 00:11:4091 if (observing_original_opener_) {
Rakina Zata Amni3a48ae42022-05-05 03:39:5692 // The "original opener" is special. It's used for attribution, and
93 // clients walk down the original opener chain. Therefore, if a link in
94 // the chain is being destroyed, reconnect the observation to the parent
95 // of the link being destroyed.
96 CHECK_EQ(owner_->first_live_main_frame_in_original_opener_chain(), node);
97 owner_->SetOriginalOpener(
98 node->first_live_main_frame_in_original_opener_chain());
Avi Drissman36465f332017-09-11 20:49:3999 // |this| is deleted at this point.
jochen6004a362017-02-04 00:11:40100 } else {
101 CHECK_EQ(owner_->opener(), node);
102 owner_->SetOpener(nullptr);
Avi Drissman36465f332017-09-11 20:49:39103 // |this| is deleted at this point.
jochen6004a362017-02-04 00:11:40104 }
alexmose201c7cd2015-06-10 17:14:21105 }
106
107 private:
Keishi Hattori0e45c022021-11-27 09:25:52108 raw_ptr<FrameTreeNode> owner_;
jochen6004a362017-02-04 00:11:40109 bool observing_original_opener_;
alexmose201c7cd2015-06-10 17:14:21110};
111
Kevin McNee88e61552020-10-22 20:41:11112const int FrameTreeNode::kFrameTreeNodeInvalidId = -1;
113
114static_assert(FrameTreeNode::kFrameTreeNodeInvalidId ==
115 RenderFrameHost::kNoFrameTreeNodeId,
116 "Have consistent sentinel values for an invalid FTN id.");
117
vishal.b782eb5d2015-04-29 12:22:57118int FrameTreeNode::next_frame_tree_node_id_ = 1;
[email protected]9b159a52013-10-03 17:24:55119
dmazzonie950ea232015-03-13 21:39:45120// static
vishal.b782eb5d2015-04-29 12:22:57121FrameTreeNode* FrameTreeNode::GloballyFindByID(int frame_tree_node_id) {
mostynb366eaf12015-03-26 00:51:19122 DCHECK_CURRENTLY_ON(BrowserThread::UI);
rob97250742015-12-10 17:45:15123 FrameTreeNodeIdMap* nodes = g_frame_tree_node_id_map.Pointer();
jdoerrie55ec69d2018-10-08 13:34:46124 auto it = nodes->find(frame_tree_node_id);
dmazzonie950ea232015-03-13 21:39:45125 return it == nodes->end() ? nullptr : it->second;
126}
127
Alexander Timin381e7e182020-04-28 19:04:03128// static
129FrameTreeNode* FrameTreeNode::From(RenderFrameHost* rfh) {
130 if (!rfh)
131 return nullptr;
132 return static_cast<RenderFrameHostImpl*>(rfh)->frame_tree_node();
133}
134
Harkiran Bolaria16f2c48d2022-04-22 12:39:57135RenderFrameHostImpl::FencedFrameStatus ComputeFencedFrameStatus(
136 FrameTree* frame_tree,
137 RenderFrameHostImpl* parent,
138 const blink::FramePolicy& frame_policy) {
139 if (blink::features::IsFencedFramesEnabled()) {
140 switch (blink::features::kFencedFramesImplementationTypeParam.Get()) {
141 case blink::features::FencedFramesImplementationType::kMPArch: {
142 if (frame_tree->type() == FrameTree::Type::kFencedFrame) {
143 if (!parent)
144 return RenderFrameHostImpl::FencedFrameStatus::kFencedFrameRoot;
145 return RenderFrameHostImpl::FencedFrameStatus::
146 kIframeNestedWithinFencedFrame;
147 } else {
148 return RenderFrameHostImpl::FencedFrameStatus::
149 kNotNestedInFencedFrame;
150 }
151 }
152 case blink::features::FencedFramesImplementationType::kShadowDOM: {
153 // Different from the MPArch case, the ShadowDOM implementation of
154 // fenced frame lives in the same FrameTree as its parent, so we need to
155 // check its effective frame policy instead.
156 if (frame_policy.is_fenced) {
157 return RenderFrameHostImpl::FencedFrameStatus::kFencedFrameRoot;
158 } else if (parent && parent->frame_tree_node()->IsInFencedFrameTree()) {
159 return RenderFrameHostImpl::FencedFrameStatus::
160 kIframeNestedWithinFencedFrame;
161 }
162 return RenderFrameHostImpl::FencedFrameStatus::kNotNestedInFencedFrame;
163 }
164 default: {
165 return RenderFrameHostImpl::FencedFrameStatus::kNotNestedInFencedFrame;
166 }
167 }
168 }
169
170 return RenderFrameHostImpl::FencedFrameStatus::kNotNestedInFencedFrame;
171}
172
Julie Jeongeun Kim70a2e4e2020-02-21 05:09:54173FrameTreeNode::FrameTreeNode(
174 FrameTree* frame_tree,
Alexander Timin381e7e182020-04-28 19:04:03175 RenderFrameHostImpl* parent,
Daniel Cheng6ac128172021-05-25 18:49:01176 blink::mojom::TreeScopeType tree_scope_type,
Julie Jeongeun Kim70a2e4e2020-02-21 05:09:54177 bool is_created_by_script,
178 const base::UnguessableToken& devtools_frame_token,
179 const blink::mojom::FrameOwnerProperties& frame_owner_properties,
Kevin McNee43fe8292021-10-04 22:59:41180 blink::FrameOwnerElementType owner_type,
Dominic Farolino08662c82021-06-11 07:36:34181 const blink::FramePolicy& frame_policy)
[email protected]bffc8302014-01-23 20:52:16182 : frame_tree_(frame_tree),
[email protected]bffc8302014-01-23 20:52:16183 frame_tree_node_id_(next_frame_tree_node_id_++),
xiaochengh98488162016-05-19 15:17:59184 parent_(parent),
Daniel Cheng9bd90f92021-04-23 20:49:45185 frame_owner_element_type_(owner_type),
Daniel Cheng6ac128172021-05-25 18:49:01186 tree_scope_type_(tree_scope_type),
Dominic Farolino08662c82021-06-11 07:36:34187 pending_frame_policy_(frame_policy),
Lukasz Anforowicz7bfb2e92017-11-22 17:19:45188 is_created_by_script_(is_created_by_script),
Pavel Feldman25234722017-10-11 02:49:06189 devtools_frame_token_(devtools_frame_token),
lazyboy70605c32015-11-03 01:27:31190 frame_owner_properties_(frame_owner_properties),
Harkiran Bolaria16f2c48d2022-04-22 12:39:57191 fenced_frame_status_(
192 ComputeFencedFrameStatus(frame_tree_, parent_, frame_policy)),
Harkiran Bolaria0b3bdef02022-03-10 13:04:40193 render_manager_(this, frame_tree->manager_delegate()) {
Harkiran Bolariaa8347782022-04-06 09:25:11194 TRACE_EVENT_BEGIN("navigation", "FrameTreeNode",
195 perfetto::Track::FromPointer(this),
196 "frame_tree_node_when_created", this);
rob97250742015-12-10 17:45:15197 std::pair<FrameTreeNodeIdMap::iterator, bool> result =
dmazzonie950ea232015-03-13 21:39:45198 g_frame_tree_node_id_map.Get().insert(
199 std::make_pair(frame_tree_node_id_, this));
200 CHECK(result.second);
alexmos998581d2015-01-22 01:01:59201}
[email protected]9b159a52013-10-03 17:24:55202
Dominic Farolino8a2187b2021-12-24 20:44:21203void FrameTreeNode::DestroyInnerFrameTreeIfExists() {
204 // If `this` is an dummy outer delegate node, then we really are representing
205 // an inner FrameTree for one of the following consumers:
206 // - `Portal`
207 // - `FencedFrame`
208 // - `GuestView`
209 // If we are representing a `FencedFrame` object, we need to destroy it
210 // alongside ourself. `Portals` and `GuestView` however, *currently* have a
211 // more complex lifetime and are dealt with separately.
212 bool is_outer_dummy_node = false;
213 if (current_frame_host() &&
214 current_frame_host()->inner_tree_main_frame_tree_node_id() !=
215 FrameTreeNode::kFrameTreeNodeInvalidId) {
216 is_outer_dummy_node = true;
217 }
218
219 if (is_outer_dummy_node) {
Nan Line376738a2022-03-25 22:05:41220 FencedFrame* doomed_fenced_frame = FindFencedFrame(this);
Dominic Farolino8a2187b2021-12-24 20:44:21221 // `doomed_fenced_frame` might not actually exist, because some outer dummy
222 // `FrameTreeNode`s might correspond to `Portal`s, which do not have their
223 // lifetime managed in the same way as `FencedFrames`.
224 if (doomed_fenced_frame) {
225 parent()->DestroyFencedFrame(*doomed_fenced_frame);
226 }
227 }
228}
229
[email protected]9b159a52013-10-03 17:24:55230FrameTreeNode::~FrameTreeNode() {
Harkiran Bolariaa8347782022-04-06 09:25:11231 TRACE_EVENT("navigation", "FrameTreeNode::~FrameTreeNode");
Daniel Chengc3d1e8d2021-06-23 02:11:45232 // There should always be a current RenderFrameHost except during prerender
233 // activation. Prerender activation moves the current RenderFrameHost from
234 // the old FrameTree's FrameTreeNode to the new FrameTree's FrameTreeNode and
235 // then destroys the old FrameTree. See
236 // `RenderFrameHostManager::TakePrerenderedPage()`.
Harkiran Bolaria59290d62021-03-17 01:53:01237 if (current_frame_host()) {
238 // Remove the children.
239 current_frame_host()->ResetChildren();
Lukasz Anforowicz7bfb2e92017-11-22 17:19:45240
Harkiran Bolaria59290d62021-03-17 01:53:01241 current_frame_host()->ResetLoadingState();
242 } else {
Hiroki Nakagawa0a90bd42021-04-21 01:53:05243 DCHECK(blink::features::IsPrerender2Enabled());
Harkiran Bolaria59290d62021-03-17 01:53:01244 DCHECK(!parent()); // Only main documents can be activated.
245 DCHECK(!opener()); // Prerendered frame trees can't have openers.
246
247 // Activation is not allowed during ongoing navigations.
248 DCHECK(!navigation_request_);
249
Carlos Caballerod1c80432021-04-20 08:16:32250 // TODO(https://crbug.com/1199693): Need to determine how to handle pending
Harkiran Bolaria59290d62021-03-17 01:53:01251 // deletions, as observers will be notified.
252 DCHECK(!render_manager()->speculative_frame_host());
253 }
Nate Chapin22ea6592019-03-05 22:29:02254
Lukasz Anforowicz7bfb2e92017-11-22 17:19:45255 // If the removed frame was created by a script, then its history entry will
256 // never be reused - we can save some memory by removing the history entry.
257 // See also https://crbug.com/784356.
258 if (is_created_by_script_ && parent_) {
Carlos Caballero04aab362021-02-15 17:38:16259 NavigationEntryImpl* nav_entry =
260 navigator().controller().GetLastCommittedEntry();
Lukasz Anforowicz7bfb2e92017-11-22 17:19:45261 if (nav_entry) {
262 nav_entry->RemoveEntryForFrame(this,
263 /* only_if_different_position = */ false);
264 }
265 }
266
dmazzonie950ea232015-03-13 21:39:45267 frame_tree_->FrameRemoved(this);
Carlos Caballero6ff6ace2021-02-05 16:53:00268
Dominic Farolino8a2187b2021-12-24 20:44:21269 DestroyInnerFrameTreeIfExists();
270
Carlos Caballero6ff6ace2021-02-05 16:53:00271 // Do not dispatch notification for the root frame as ~WebContentsImpl already
272 // dispatches it for now.
273 // TODO(https://crbug.com/1170277): This is only needed because the FrameTree
274 // is a member of WebContentsImpl and we would call back into it during
275 // destruction. We should clean up the FrameTree destruction code and call the
276 // delegate unconditionally.
277 if (parent())
278 render_manager_.delegate()->OnFrameTreeNodeDestroyed(this);
279
ericwilligers254597b2016-10-17 10:32:31280 for (auto& observer : observers_)
281 observer.OnFrameTreeNodeDestroyed(this);
Lukasz Anforowicz147141962020-12-16 18:03:24282 observers_.Clear();
alexmose201c7cd2015-06-10 17:14:21283
284 if (opener_)
285 opener_->RemoveObserver(opener_observer_.get());
Rakina Zata Amni3a48ae42022-05-05 03:39:56286 if (first_live_main_frame_in_original_opener_chain_)
287 first_live_main_frame_in_original_opener_chain_->RemoveObserver(
288 original_opener_observer_.get());
dmazzonie950ea232015-03-13 21:39:45289
290 g_frame_tree_node_id_map.Get().erase(frame_tree_node_id_);
jam39258caf2016-11-02 14:48:18291
Daniel Chengc3d1e8d2021-06-23 02:11:45292 // If a frame with a pending navigation is detached, make sure the
293 // WebContents (and its observers) update their loading state.
294 // TODO(dcheng): This should just check `IsLoading()`, but `IsLoading()`
295 // assumes that `current_frame_host_` is not null. This is incompatible with
296 // prerender activation when destroying the old frame tree (see above).
danakjf9400602019-06-07 15:44:58297 bool did_stop_loading = false;
298
jam39258caf2016-11-02 14:48:18299 if (navigation_request_) {
danakjf9400602019-06-07 15:44:58300 navigation_request_.reset();
danakjf9400602019-06-07 15:44:58301 did_stop_loading = true;
jam39258caf2016-11-02 14:48:18302 }
Nate Chapin22ea6592019-03-05 22:29:02303
danakjf9400602019-06-07 15:44:58304 // ~SiteProcessCountTracker DCHECKs in some tests if the speculative
305 // RenderFrameHostImpl is not destroyed last. Ideally this would be closer to
306 // (possible before) the ResetLoadingState() call above.
danakjf9400602019-06-07 15:44:58307 if (render_manager_.speculative_frame_host()) {
Daniel Chengc3d1e8d2021-06-23 02:11:45308 // TODO(dcheng): Shouldn't a FrameTreeNode with a speculative
309 // RenderFrameHost always be considered loading?
danakjf9400602019-06-07 15:44:58310 did_stop_loading |= render_manager_.speculative_frame_host()->is_loading();
Daniel Chengc3d1e8d2021-06-23 02:11:45311 // `FrameTree::Shutdown()` has special handling for the main frame's
312 // speculative RenderFrameHost, and the speculative RenderFrameHost should
313 // already be reset for main frames.
314 DCHECK(!IsMainFrame());
315
316 // This does not use `UnsetSpeculativeRenderFrameHost()`: if the speculative
317 // RenderFrameHost has already reached kPendingCommit, it would needlessly
318 // re-create a proxy for a frame that's going away.
319 render_manager_.DiscardSpeculativeRenderFrameHostForShutdown();
danakjf9400602019-06-07 15:44:58320 }
321
322 if (did_stop_loading)
323 DidStopLoading();
324
Harkiran Bolaria59290d62021-03-17 01:53:01325 // IsLoading() requires that current_frame_host() is non-null.
326 DCHECK(!current_frame_host() || !IsLoading());
Harkiran Bolariaa8347782022-04-06 09:25:11327
328 // Matches the TRACE_EVENT_BEGIN in the constructor.
329 TRACE_EVENT_END("navigation", perfetto::Track::FromPointer(this));
[email protected]9b159a52013-10-03 17:24:55330}
331
alexmose201c7cd2015-06-10 17:14:21332void FrameTreeNode::AddObserver(Observer* observer) {
333 observers_.AddObserver(observer);
334}
335
336void FrameTreeNode::RemoveObserver(Observer* observer) {
337 observers_.RemoveObserver(observer);
338}
339
[email protected]94d0cc12013-12-18 00:07:41340bool FrameTreeNode::IsMainFrame() const {
341 return frame_tree_->root() == this;
342}
343
Ian Vollick25a9d032022-04-12 23:20:17344bool FrameTreeNode::IsOutermostMainFrame() {
345 return !GetParentOrOuterDocument();
346}
347
Hiroki Nakagawaab309622021-05-19 16:38:13348void FrameTreeNode::ResetForNavigation() {
arthursonzogni76098e52020-11-25 14:18:45349 // This frame has had its user activation bits cleared in the renderer before
350 // arriving here. We just need to clear them here and in the other renderer
351 // processes that may have a reference to this frame.
Alexander Timin45b716c2020-11-06 01:40:31352 //
353 // We do not take user activation into account when calculating
354 // |ResetForNavigationResult|, as we are using it to determine bfcache
355 // eligibility and the page can get another user gesture after restore.
Antonio Gomes4b2c5132020-01-16 11:49:48356 UpdateUserActivationState(
Mustaq Ahmeddc195e5b2020-08-04 18:45:11357 blink::mojom::UserActivationUpdateType::kClearActivation,
358 blink::mojom::UserActivationNotificationType::kNone);
Ian Clelland5cbaaf82017-11-27 22:00:03359}
360
Dave Tapuskac8de3b02021-12-03 21:51:01361RenderFrameHostImpl* FrameTreeNode::GetParentOrOuterDocument() {
362 return GetParentOrOuterDocumentHelper(/*escape_guest_view=*/false);
363}
364
365RenderFrameHostImpl* FrameTreeNode::GetParentOrOuterDocumentOrEmbedder() {
366 return GetParentOrOuterDocumentHelper(/*escape_guest_view=*/true);
367}
368
369RenderFrameHostImpl* FrameTreeNode::GetParentOrOuterDocumentHelper(
370 bool escape_guest_view) {
371 // Find the parent in the FrameTree (iframe).
372 if (parent_)
373 return parent_;
374
375 if (!escape_guest_view) {
376 // If we are not a fenced frame root nor inside a portal then return early.
377 // This code does not escape GuestViews.
378 if (!IsFencedFrameRoot() && !frame_tree_->delegate()->IsPortal())
379 return nullptr;
380 }
381
382 // Find the parent in the outer embedder (GuestView, Portal, or Fenced Frame).
383 FrameTreeNode* frame_in_embedder = render_manager()->GetOuterDelegateNode();
384 if (frame_in_embedder)
385 return frame_in_embedder->current_frame_host()->GetParent();
386
387 // No parent found.
388 return nullptr;
389}
390
Julie Jeongeun Kimf38c1eca2021-12-14 07:46:55391FrameType FrameTreeNode::GetFrameType() const {
392 if (!IsMainFrame())
393 return FrameType::kSubframe;
394
395 switch (frame_tree()->type()) {
396 case FrameTree::Type::kPrimary:
397 return FrameType::kPrimaryMainFrame;
398 case FrameTree::Type::kPrerender:
399 return FrameType::kPrerenderMainFrame;
400 case FrameTree::Type::kFencedFrame:
401 // We also have FencedFramesImplementationType::kShadowDOM for a
402 // fenced frame implementation based on <iframe> + shadowDOM,
403 // which will return kSubframe as it's a modified <iframe> rather
404 // than a dedicated FrameTree. This returns kSubframe for the
405 // shadow dom implementation in order to keep consistency (i.e.
406 // NavigationHandle::GetParentFrame returning non-null value for
407 // shadow-dom based FFs).
408 return FrameType::kFencedFrameRoot;
409 }
410}
411
alexmose201c7cd2015-06-10 17:14:21412void FrameTreeNode::SetOpener(FrameTreeNode* opener) {
Harkiran Bolariaa8347782022-04-06 09:25:11413 TRACE_EVENT("navigation", "FrameTreeNode::SetOpener",
414 ChromeTrackEvent::kFrameTreeNodeInfo, opener);
alexmose201c7cd2015-06-10 17:14:21415 if (opener_) {
416 opener_->RemoveObserver(opener_observer_.get());
417 opener_observer_.reset();
418 }
419
420 opener_ = opener;
421
422 if (opener_) {
Jeremy Roman04f27c372017-10-27 15:20:55423 opener_observer_ = std::make_unique<OpenerDestroyedObserver>(this, false);
alexmose201c7cd2015-06-10 17:14:21424 opener_->AddObserver(opener_observer_.get());
425 }
426}
427
Wolfgang Beyerd8809db2020-09-30 15:29:39428void FrameTreeNode::SetOpenerDevtoolsFrameToken(
429 base::UnguessableToken opener_devtools_frame_token) {
430 DCHECK(!opener_devtools_frame_token_ ||
431 opener_devtools_frame_token_->is_empty());
432 opener_devtools_frame_token_ = std::move(opener_devtools_frame_token);
433}
434
jochen6004a362017-02-04 00:11:40435void FrameTreeNode::SetOriginalOpener(FrameTreeNode* opener) {
Avi Drissman36465f332017-09-11 20:49:39436 // The original opener tracks main frames only.
avi8d1aa162017-03-27 18:27:37437 DCHECK(opener == nullptr || !opener->parent());
jochen6004a362017-02-04 00:11:40438
Rakina Zata Amni3a48ae42022-05-05 03:39:56439 if (first_live_main_frame_in_original_opener_chain_) {
440 first_live_main_frame_in_original_opener_chain_->RemoveObserver(
441 original_opener_observer_.get());
Avi Drissman36465f332017-09-11 20:49:39442 original_opener_observer_.reset();
443 }
444
Rakina Zata Amni3a48ae42022-05-05 03:39:56445 first_live_main_frame_in_original_opener_chain_ = opener;
jochen6004a362017-02-04 00:11:40446
Rakina Zata Amni3a48ae42022-05-05 03:39:56447 if (first_live_main_frame_in_original_opener_chain_) {
448 original_opener_observer_ = std::make_unique<OpenerDestroyedObserver>(
449 this, true /* observing_original_opener */);
450 first_live_main_frame_in_original_opener_chain_->AddObserver(
451 original_opener_observer_.get());
jochen6004a362017-02-04 00:11:40452 }
453}
454
creisf0f069a2015-07-23 23:51:53455void FrameTreeNode::SetCurrentURL(const GURL& url) {
Erik Chen173bf3042017-07-31 06:06:21456 current_frame_host()->SetLastCommittedUrl(url);
creisf0f069a2015-07-23 23:51:53457}
458
engedy6e2e0992017-05-25 18:58:42459void FrameTreeNode::SetCollapsed(bool collapsed) {
Dave Tapuska65e50aa2022-03-09 23:44:13460 DCHECK(!IsMainFrame() || IsFencedFrameRoot());
engedy6e2e0992017-05-25 18:58:42461 if (is_collapsed_ == collapsed)
462 return;
463
464 is_collapsed_ = collapsed;
465 render_manager_.OnDidChangeCollapsedState(collapsed);
466}
467
Harkiran Bolaria59290d62021-03-17 01:53:01468void FrameTreeNode::SetFrameTree(FrameTree& frame_tree) {
Hiroki Nakagawa0a90bd42021-04-21 01:53:05469 DCHECK(blink::features::IsPrerender2Enabled());
Harkiran Bolaria59290d62021-03-17 01:53:01470 frame_tree_ = &frame_tree;
Kevin McNeeb110d0c2021-10-26 15:53:00471 DCHECK(current_frame_host());
472 current_frame_host()->SetFrameTree(frame_tree);
473 RenderFrameHostImpl* speculative_frame_host =
474 render_manager_.speculative_frame_host();
475 if (speculative_frame_host)
476 speculative_frame_host->SetFrameTree(frame_tree);
Harkiran Bolaria59290d62021-03-17 01:53:01477}
478
Luna Luc3fdacdf2017-11-08 04:48:53479void FrameTreeNode::SetPendingFramePolicy(blink::FramePolicy frame_policy) {
Dominic Farolinobfd1f0292022-03-23 19:12:24480 // The `is_fenced` and `fenced_frame_mode` bits should never be able to
481 // transition from their initial values. Since we never expect to be in a
482 // position where it can even be updated to new value, if we catch this
483 // happening we have to kill the renderer and refuse to accept any other frame
484 // policy changes here.
485 if (pending_frame_policy_.is_fenced != frame_policy.is_fenced ||
486 pending_frame_policy_.fenced_frame_mode !=
487 frame_policy.fenced_frame_mode) {
Dominic Farolino08662c82021-06-11 07:36:34488 mojo::ReportBadMessage(
Dominic Farolinobfd1f0292022-03-23 19:12:24489 "FramePolicy properties dealing with fenced frames are considered "
490 "immutable, and therefore should never be changed by the renderer.");
Dominic Farolino08662c82021-06-11 07:36:34491 return;
492 }
493
Ian Clellandcdc4f312017-10-13 22:24:12494 pending_frame_policy_.sandbox_flags = frame_policy.sandbox_flags;
alexmos6e940102016-01-19 22:47:25495
Ian Clellandcdc4f312017-10-13 22:24:12496 if (parent()) {
497 // Subframes should always inherit their parent's sandbox flags.
Alexander Timin381e7e182020-04-28 19:04:03498 pending_frame_policy_.sandbox_flags |=
Harkiran Bolaria4eacb3a2021-12-13 20:03:47499 parent()->browsing_context_state()->active_sandbox_flags();
Charlie Hue1b77ac2019-12-13 21:30:17500 // This is only applied on subframes; container policy and required document
501 // policy are not mutable on main frame.
Ian Clellandcdc4f312017-10-13 22:24:12502 pending_frame_policy_.container_policy = frame_policy.container_policy;
Charlie Hue1b77ac2019-12-13 21:30:17503 pending_frame_policy_.required_document_policy =
504 frame_policy.required_document_policy;
Ian Clellandcdc4f312017-10-13 22:24:12505 }
iclelland92f8c0b2017-04-19 12:43:05506}
507
Arthur Sonzogni2e9c6111392022-05-02 08:37:13508void FrameTreeNode::SetAnonymous(bool anonymous) {
509 if (anonymous) {
510 if (!parent_) {
511 bad_message::ReceivedBadMessage(current_frame_host()->GetProcess(),
512 bad_message::FTN_ANONYMOUS);
513 return;
514 }
515
516 GetContentClient()->browser()->LogWebFeatureForCurrentPage(
517 parent_, blink::mojom::WebFeature::kAnonymousIframe);
518 }
519
520 anonymous_ = anonymous;
521}
522
fdegans4a49ce932015-03-12 17:11:37523bool FrameTreeNode::IsLoading() const {
524 RenderFrameHostImpl* current_frame_host =
525 render_manager_.current_frame_host();
fdegans4a49ce932015-03-12 17:11:37526
527 DCHECK(current_frame_host);
fdegans39ff0382015-04-29 19:04:39528
clamy610c63b32017-12-22 15:05:18529 if (navigation_request_)
530 return true;
clamy11e11512015-07-07 16:42:17531
clamy610c63b32017-12-22 15:05:18532 RenderFrameHostImpl* speculative_frame_host =
533 render_manager_.speculative_frame_host();
Daniel Chengc3d1e8d2021-06-23 02:11:45534 // TODO(dcheng): Shouldn't a FrameTreeNode with a speculative RenderFrameHost
535 // always be considered loading?
clamy610c63b32017-12-22 15:05:18536 if (speculative_frame_host && speculative_frame_host->is_loading())
537 return true;
fdegans4a49ce932015-03-12 17:11:37538 return current_frame_host->is_loading();
539}
540
Alex Moshchuk9b0fd822020-10-26 23:08:15541bool FrameTreeNode::HasPendingCrossDocumentNavigation() const {
542 // Having a |navigation_request_| on FrameTreeNode implies that there's an
543 // ongoing navigation that hasn't reached the ReadyToCommit state. If the
544 // navigation is between ReadyToCommit and DidCommitNavigation, the
545 // NavigationRequest will be held by RenderFrameHost, which is checked below.
546 if (navigation_request_ && !navigation_request_->IsSameDocument())
547 return true;
548
549 // Having a speculative RenderFrameHost should imply a cross-document
550 // navigation.
551 if (render_manager_.speculative_frame_host())
552 return true;
553
554 return render_manager_.current_frame_host()
555 ->HasPendingCommitForCrossDocumentNavigation();
556}
557
Arthur Hemeryc3380172018-01-22 14:00:17558void FrameTreeNode::TransferNavigationRequestOwnership(
559 RenderFrameHostImpl* render_frame_host) {
Andrey Kosyakovf2d4ff72018-10-29 20:09:59560 devtools_instrumentation::OnResetNavigationRequest(navigation_request_.get());
Arthur Hemeryc3380172018-01-22 14:00:17561 render_frame_host->SetNavigationRequest(std::move(navigation_request_));
562}
563
carloskc49005eb2015-06-16 11:25:07564void FrameTreeNode::CreatedNavigationRequest(
dcheng9bfa5162016-04-09 01:00:57565 std::unique_ptr<NavigationRequest> navigation_request) {
arthursonzognic79c251c2016-08-18 15:00:37566 // This is never called when navigating to a Javascript URL. For the loading
567 // state, this matches what Blink is doing: Blink doesn't send throbber
568 // notifications for Javascript URLS.
569 DCHECK(!navigation_request->common_params().url.SchemeIs(
570 url::kJavaScriptScheme));
571
Sreeja Kamishetty15f9944a22022-03-10 10:16:08572 bool was_previously_loading = frame_tree()->LoadingTree()->IsLoading();
clamy44e84ce2016-02-22 15:38:25573
clamy82a2f4d2016-02-02 14:20:41574 // There's no need to reset the state: there's still an ongoing load, and the
575 // RenderFrameHostManager will take care of updates to the speculative
576 // RenderFrameHost in DidCreateNavigationRequest below.
jamcd0b7b22017-03-24 22:13:05577 if (was_previously_loading) {
Mohamed Abdelhalimf03d4a22019-10-01 13:34:31578 if (navigation_request_ && navigation_request_->IsNavigationStarted()) {
jamcd0b7b22017-03-24 22:13:05579 // Mark the old request as aborted.
Mohamed Abdelhalimb4db22a2019-06-18 10:46:52580 navigation_request_->set_net_error(net::ERR_ABORTED);
jamcd0b7b22017-03-24 22:13:05581 }
Arthur Hemery241b9392019-10-24 11:08:41582 ResetNavigationRequest(true);
jamcd0b7b22017-03-24 22:13:05583 }
clamy44e84ce2016-02-22 15:38:25584
585 navigation_request_ = std::move(navigation_request);
Shubhie Panickerddf2a4e2018-03-06 00:09:06586 if (was_discarded_) {
587 navigation_request_->set_was_discarded();
588 was_discarded_ = false;
589 }
clamy8e2e299202016-04-05 11:44:59590 render_manager()->DidCreateNavigationRequest(navigation_request_.get());
fdegans39ff0382015-04-29 19:04:39591
Lucas Furukawa Gadanief8290a2019-07-29 20:27:51592 bool to_different_document = !NavigationTypeUtils::IsSameDocument(
arthursonzogni92f18682017-02-08 23:00:04593 navigation_request_->common_params().navigation_type);
594
595 DidStartLoading(to_different_document, was_previously_loading);
clamydcb434c12015-04-16 19:29:16596}
597
Arthur Hemery241b9392019-10-24 11:08:41598void FrameTreeNode::ResetNavigationRequest(bool keep_state) {
fdegans39ff0382015-04-29 19:04:39599 if (!navigation_request_)
600 return;
John Abd-El-Malekdcc7bf42017-09-12 22:30:23601
Andrey Kosyakovf2d4ff72018-10-29 20:09:59602 devtools_instrumentation::OnResetNavigationRequest(navigation_request_.get());
clamydcb434c12015-04-16 19:29:16603 navigation_request_.reset();
fdegans39ff0382015-04-29 19:04:39604
clamy82a2f4d2016-02-02 14:20:41605 if (keep_state)
fdegans39ff0382015-04-29 19:04:39606 return;
607
clamy82a2f4d2016-02-02 14:20:41608 // The RenderFrameHostManager should clean up any speculative RenderFrameHost
609 // it created for the navigation. Also register that the load stopped.
fdegans39ff0382015-04-29 19:04:39610 DidStopLoading();
611 render_manager_.CleanUpNavigation();
clamydcb434c12015-04-16 19:29:16612}
613
Nate Chapin9aabf5f2021-11-12 00:31:19614void FrameTreeNode::DidStartLoading(bool should_show_loading_ui,
clamy44e84ce2016-02-22 15:38:25615 bool was_previously_loading) {
Camille Lamyefd54b02018-10-04 16:54:14616 TRACE_EVENT2("navigation", "FrameTreeNode::DidStartLoading",
Nate Chapin9aabf5f2021-11-12 00:31:19617 "frame_tree_node", frame_tree_node_id(),
618 "should_show_loading_ui ", should_show_loading_ui);
Clark DuVallc97bcf72021-12-08 22:58:24619 base::ElapsedTimer timer;
fdegansa696e5112015-04-17 01:57:59620
Sreeja Kamishetty15f9944a22022-03-10 10:16:08621 frame_tree()->LoadingTree()->DidStartLoadingNode(
622 *this, should_show_loading_ui, was_previously_loading);
fdegansa696e5112015-04-17 01:57:59623
624 // Set initial load progress and update overall progress. This will notify
625 // the WebContents of the load progress change.
Sreeja Kamishetty15f9944a22022-03-10 10:16:08626 //
627 // Only notify when the load is triggered from primary/prerender main frame as
628 // we only update load progress for these nodes which happens when the frame
629 // tree matches the loading tree.
630 if (frame_tree() == frame_tree()->LoadingTree())
631 DidChangeLoadProgress(blink::kInitialLoadProgress);
fdegansa696e5112015-04-17 01:57:59632
Harkiran Bolaria3f83fba72022-03-10 17:48:40633 // Notify the proxies of the event.
634 current_frame_host()->browsing_context_state()->OnDidStartLoading();
Clark DuVallc97bcf72021-12-08 22:58:24635 base::UmaHistogramTimes(
636 base::StrCat({"Navigation.DidStartLoading.",
637 IsMainFrame() ? "MainFrame" : "Subframe"}),
638 timer.Elapsed());
fdegansa696e5112015-04-17 01:57:59639}
640
641void FrameTreeNode::DidStopLoading() {
Camille Lamyefd54b02018-10-04 16:54:14642 TRACE_EVENT1("navigation", "FrameTreeNode::DidStopLoading", "frame_tree_node",
643 frame_tree_node_id());
fdegansa696e5112015-04-17 01:57:59644 // Set final load progress and update overall progress. This will notify
645 // the WebContents of the load progress change.
Sreeja Kamishetty15f9944a22022-03-10 10:16:08646 //
647 // Only notify when the load is triggered from primary/prerender main frame as
648 // we only update load progress for these nodes which happens when the frame
649 // tree matches the loading tree.
650 if (frame_tree() == frame_tree()->LoadingTree())
651 DidChangeLoadProgress(blink::kFinalLoadProgress);
fdegansa696e5112015-04-17 01:57:59652
Harkiran Bolaria3f83fba72022-03-10 17:48:40653 // Notify the proxies of the event.
654 current_frame_host()->browsing_context_state()->OnDidStopLoading();
Lucas Furukawa Gadani6faef602019-05-06 21:16:03655
Sreeja Kamishetty15f9944a22022-03-10 10:16:08656 FrameTree* loading_tree = frame_tree()->LoadingTree();
657 // When loading tree is null, ignore invoking DidStopLoadingNode as the frame
658 // tree is already deleted. This can happen when prerendering gets cancelled
659 // and DidStopLoading is called during FrameTree destruction.
660 if (loading_tree)
661 loading_tree->DidStopLoadingNode(*this);
fdegansa696e5112015-04-17 01:57:59662}
663
664void FrameTreeNode::DidChangeLoadProgress(double load_progress) {
Sreeja Kamishetty0be3b1b2021-08-12 17:04:15665 DCHECK_GE(load_progress, blink::kInitialLoadProgress);
666 DCHECK_LE(load_progress, blink::kFinalLoadProgress);
667 current_frame_host()->DidChangeLoadProgress(load_progress);
fdegansa696e5112015-04-17 01:57:59668}
669
clamyf73862c42015-07-08 12:31:33670bool FrameTreeNode::StopLoading() {
arthursonzogni66f711c2019-10-08 14:40:36671 if (navigation_request_ && navigation_request_->IsNavigationStarted())
672 navigation_request_->set_net_error(net::ERR_ABORTED);
Arthur Hemery241b9392019-10-24 11:08:41673 ResetNavigationRequest(false);
clamyf73862c42015-07-08 12:31:33674
clamyf73862c42015-07-08 12:31:33675 if (!IsMainFrame())
676 return true;
677
678 render_manager_.Stop();
679 return true;
680}
681
alexmos21acae52015-11-07 01:04:43682void FrameTreeNode::DidFocus() {
683 last_focus_time_ = base::TimeTicks::Now();
ericwilligers254597b2016-10-17 10:32:31684 for (auto& observer : observers_)
685 observer.OnFrameTreeNodeFocused(this);
alexmos21acae52015-11-07 01:04:43686}
687
clamy44e84ce2016-02-22 15:38:25688void FrameTreeNode::BeforeUnloadCanceled() {
Julie Jeongeun Kim8cf7ae32022-05-02 03:47:29689 // TODO(clamy): Support BeforeUnload in subframes. Fenced Frames don't run
690 // BeforeUnload. Maybe need to check whether other MPArch inner pages cases
691 // need beforeunload(e.g., portals, GuestView if it gets ported to MPArch).
Ian Vollick1c6dd3e2022-04-13 02:06:26692 if (!IsOutermostMainFrame())
clamy44e84ce2016-02-22 15:38:25693 return;
694
695 RenderFrameHostImpl* current_frame_host =
696 render_manager_.current_frame_host();
697 DCHECK(current_frame_host);
698 current_frame_host->ResetLoadingState();
699
clamy610c63b32017-12-22 15:05:18700 RenderFrameHostImpl* speculative_frame_host =
701 render_manager_.speculative_frame_host();
702 if (speculative_frame_host)
703 speculative_frame_host->ResetLoadingState();
Alexander Timin23c110b2021-01-14 02:39:04704 // Note: there is no need to set an error code on the NavigationHandle as
705 // the observers have not been notified about its creation.
706 // We also reset navigation request only when this navigation request was
707 // responsible for this dialog, as a new navigation request might cancel
708 // existing unrelated dialog.
709 if (navigation_request_ && navigation_request_->IsWaitingForBeforeUnload())
Arthur Hemery241b9392019-10-24 11:08:41710 ResetNavigationRequest(false);
clamy44e84ce2016-02-22 15:38:25711}
712
Mustaq Ahmedecb5c38e2020-07-29 00:34:30713bool FrameTreeNode::NotifyUserActivation(
714 blink::mojom::UserActivationNotificationType notification_type) {
Garrett Tanzer753cc532022-03-02 21:30:59715 // User activation notifications shouldn't propagate into/out of fenced
716 // frames.
717 // For ShadowDOM, fenced frames are in the same frame tree as their embedder,
718 // so we need to perform additional checks to enforce the boundary.
719 // For MPArch, fenced frames have a separate frame tree, so this boundary is
720 // enforced by default.
721 // https://docs.google.com/document/d/1WnIhXOFycoje_sEoZR3Mo0YNSR2Ki7LABIC_HEWFaog
722 bool shadow_dom_fenced_frame_enabled =
723 blink::features::IsFencedFramesEnabled() &&
724 blink::features::IsFencedFramesShadowDOMBased();
725
Alex Moshchuk03904192021-04-02 07:29:08726 // User Activation V2 requires activating all ancestor frames in addition to
727 // the current frame. See
728 // https://html.spec.whatwg.org/multipage/interaction.html#tracking-user-activation.
Alexander Timina1dfadaa2020-04-28 13:30:06729 for (RenderFrameHostImpl* rfh = current_frame_host(); rfh;
730 rfh = rfh->GetParent()) {
John Delaneyb625dca92021-04-14 17:00:34731 rfh->DidReceiveUserActivation();
Mustaq Ahmedecb5c38e2020-07-29 00:34:30732 rfh->frame_tree_node()->user_activation_state_.Activate(notification_type);
Garrett Tanzer753cc532022-03-02 21:30:59733
734 if (shadow_dom_fenced_frame_enabled &&
735 rfh->frame_tree_node()->IsFencedFrameRoot()) {
736 break;
737 }
John Delaneyedd8d6c2019-01-25 00:23:57738 }
Alex Moshchuk03904192021-04-02 07:29:08739
Harkiran Bolaria0b3bdef02022-03-10 13:04:40740 current_frame_host()->browsing_context_state()->set_has_active_user_gesture(
741 true);
Mustaq Ahmeda5dfa60b2018-12-08 00:30:14742
Garrett Tanzer753cc532022-03-02 21:30:59743 absl::optional<base::UnguessableToken> originator_nonce =
744 fenced_frame_nonce();
745
Mustaq Ahmed0180320f2019-03-21 16:07:01746 // See the "Same-origin Visibility" section in |UserActivationState| class
747 // doc.
Mustaq Ahmede5f12562019-10-30 18:02:03748 if (base::FeatureList::IsEnabled(
Garrett Tanzer753cc532022-03-02 21:30:59749 features::kUserActivationSameOriginVisibility)) {
Mustaq Ahmeda5dfa60b2018-12-08 00:30:14750 const url::Origin& current_origin =
751 this->current_frame_host()->GetLastCommittedOrigin();
752 for (FrameTreeNode* node : frame_tree()->Nodes()) {
Garrett Tanzer753cc532022-03-02 21:30:59753 if (shadow_dom_fenced_frame_enabled &&
754 node->fenced_frame_nonce() != originator_nonce) {
755 continue;
756 }
757
Mustaq Ahmeda5dfa60b2018-12-08 00:30:14758 if (node->current_frame_host()->GetLastCommittedOrigin().IsSameOriginWith(
759 current_origin)) {
Mustaq Ahmedecb5c38e2020-07-29 00:34:30760 node->user_activation_state_.Activate(notification_type);
Mustaq Ahmeda5dfa60b2018-12-08 00:30:14761 }
762 }
763 }
764
Carlos Caballero40b0efd2021-01-26 11:55:00765 navigator().controller().NotifyUserActivation();
Alex Moshchuk03904192021-04-02 07:29:08766 current_frame_host()->MaybeIsolateForUserActivation();
Shivani Sharma194877032019-03-07 17:52:47767
Mustaq Ahmedc4cb7162018-06-05 16:28:36768 return true;
769}
770
771bool FrameTreeNode::ConsumeTransientUserActivation() {
Garrett Tanzer753cc532022-03-02 21:30:59772 // User activation consumptions shouldn't propagate into/out of fenced
773 // frames.
774 // For ShadowDOM, fenced frames are in the same frame tree as their embedder,
775 // so we need to perform additional checks to enforce the boundary.
776 // For MPArch, fenced frames have a separate frame tree, so this boundary is
777 // enforced by default.
778 // https://docs.google.com/document/d/1WnIhXOFycoje_sEoZR3Mo0YNSR2Ki7LABIC_HEWFaog
779 bool shadow_dom_fenced_frame_enabled =
780 blink::features::IsFencedFramesEnabled() &&
781 blink::features::IsFencedFramesShadowDOMBased();
782 absl::optional<base::UnguessableToken> originator_nonce =
783 fenced_frame_nonce();
784
Mustaq Ahmedc4cb7162018-06-05 16:28:36785 bool was_active = user_activation_state_.IsActive();
Garrett Tanzer753cc532022-03-02 21:30:59786 for (FrameTreeNode* node : frame_tree()->Nodes()) {
787 if (shadow_dom_fenced_frame_enabled &&
788 node->fenced_frame_nonce() != originator_nonce) {
789 continue;
790 }
791
Mustaq Ahmedc4cb7162018-06-05 16:28:36792 node->user_activation_state_.ConsumeIfActive();
Garrett Tanzer753cc532022-03-02 21:30:59793 }
Harkiran Bolaria0b3bdef02022-03-10 13:04:40794 current_frame_host()->browsing_context_state()->set_has_active_user_gesture(
795 false);
Mustaq Ahmedc4cb7162018-06-05 16:28:36796 return was_active;
797}
798
Shivani Sharmac4f561582018-11-15 15:58:39799bool FrameTreeNode::ClearUserActivation() {
Shivani Sharmac4f561582018-11-15 15:58:39800 for (FrameTreeNode* node : frame_tree()->SubtreeNodes(this))
801 node->user_activation_state_.Clear();
Harkiran Bolaria0b3bdef02022-03-10 13:04:40802 current_frame_host()->browsing_context_state()->set_has_active_user_gesture(
803 false);
Shivani Sharmac4f561582018-11-15 15:58:39804 return true;
805}
806
Ella Ge9caed612019-08-09 16:17:25807bool FrameTreeNode::VerifyUserActivation() {
Ella Gea78f6772019-12-11 10:35:25808 DCHECK(base::FeatureList::IsEnabled(
809 features::kBrowserVerifiedUserActivationMouse) ||
810 base::FeatureList::IsEnabled(
811 features::kBrowserVerifiedUserActivationKeyboard));
812
Ella Ge9caed612019-08-09 16:17:25813 return render_manager_.current_frame_host()
814 ->GetRenderWidgetHost()
Mustaq Ahmed83bb1722019-10-22 20:00:10815 ->RemovePendingUserActivationIfAvailable();
Ella Ge9caed612019-08-09 16:17:25816}
817
Mustaq Ahmedc4cb7162018-06-05 16:28:36818bool FrameTreeNode::UpdateUserActivationState(
Mustaq Ahmeddc195e5b2020-08-04 18:45:11819 blink::mojom::UserActivationUpdateType update_type,
820 blink::mojom::UserActivationNotificationType notification_type) {
Ella Ge9caed612019-08-09 16:17:25821 bool update_result = false;
Mustaq Ahmedc4cb7162018-06-05 16:28:36822 switch (update_type) {
Antonio Gomes4b2c5132020-01-16 11:49:48823 case blink::mojom::UserActivationUpdateType::kConsumeTransientActivation:
Ella Ge9caed612019-08-09 16:17:25824 update_result = ConsumeTransientUserActivation();
825 break;
Antonio Gomes4b2c5132020-01-16 11:49:48826 case blink::mojom::UserActivationUpdateType::kNotifyActivation:
Mustaq Ahmeddc195e5b2020-08-04 18:45:11827 update_result = NotifyUserActivation(notification_type);
Ella Ge9caed612019-08-09 16:17:25828 break;
Antonio Gomes4b2c5132020-01-16 11:49:48829 case blink::mojom::UserActivationUpdateType::
Liviu Tintad9391fb92020-09-28 23:50:07830 kNotifyActivationPendingBrowserVerification: {
831 const bool user_activation_verified = VerifyUserActivation();
832 // Add UMA metric for when browser user activation verification succeeds
833 base::UmaHistogramBoolean("Event.BrowserVerifiedUserActivation",
834 user_activation_verified);
835 if (user_activation_verified) {
Mustaq Ahmedecb5c38e2020-07-29 00:34:30836 update_result = NotifyUserActivation(
Mustaq Ahmed2cfb0402020-09-29 19:24:35837 blink::mojom::UserActivationNotificationType::kInteraction);
Antonio Gomes4b2c5132020-01-16 11:49:48838 update_type = blink::mojom::UserActivationUpdateType::kNotifyActivation;
Ella Ge9caed612019-08-09 16:17:25839 } else {
arthursonzogni9816b9192021-03-29 16:09:19840 // TODO(https://crbug.com/848778): We need to decide what to do when
841 // user activation verification failed. NOTREACHED here will make all
Ella Ge9caed612019-08-09 16:17:25842 // unrelated tests that inject event to renderer fail.
843 return false;
844 }
Liviu Tintad9391fb92020-09-28 23:50:07845 } break;
Antonio Gomes4b2c5132020-01-16 11:49:48846 case blink::mojom::UserActivationUpdateType::kClearActivation:
Ella Ge9caed612019-08-09 16:17:25847 update_result = ClearUserActivation();
848 break;
Mustaq Ahmedc4cb7162018-06-05 16:28:36849 }
Mustaq Ahmeddc195e5b2020-08-04 18:45:11850 render_manager_.UpdateUserActivationState(update_type, notification_type);
Ella Ge9caed612019-08-09 16:17:25851 return update_result;
japhet61835ae12017-01-20 01:25:39852}
853
Arthur Sonzognif8840b92018-11-07 14:10:35854void FrameTreeNode::PruneChildFrameNavigationEntries(
855 NavigationEntryImpl* entry) {
856 for (size_t i = 0; i < current_frame_host()->child_count(); ++i) {
857 FrameTreeNode* child = current_frame_host()->child_at(i);
858 if (child->is_created_by_script_) {
859 entry->RemoveEntryForFrame(child,
860 /* only_if_different_position = */ false);
861 } else {
862 child->PruneChildFrameNavigationEntries(entry);
863 }
864 }
865}
866
arthursonzogni034bb9c2020-10-01 08:29:56867void FrameTreeNode::SetInitialPopupURL(const GURL& initial_popup_url) {
868 DCHECK(initial_popup_url_.is_empty());
Rakina Zata Amni4182b032021-11-01 04:22:01869 DCHECK(is_on_initial_empty_document_);
arthursonzogni034bb9c2020-10-01 08:29:56870 initial_popup_url_ = initial_popup_url;
871}
872
873void FrameTreeNode::SetPopupCreatorOrigin(
874 const url::Origin& popup_creator_origin) {
Rakina Zata Amni4182b032021-11-01 04:22:01875 DCHECK(is_on_initial_empty_document_);
arthursonzogni034bb9c2020-10-01 08:29:56876 popup_creator_origin_ = popup_creator_origin;
877}
878
Rakina Zata Amni4b1968d2021-09-09 03:29:47879void FrameTreeNode::WriteIntoTrace(
Alexander Timin074cd182022-03-23 18:11:22880 perfetto::TracedProto<TraceProto> proto) const {
Rakina Zata Amni4b1968d2021-09-09 03:29:47881 proto->set_frame_tree_node_id(frame_tree_node_id());
Ian Vollick95e83f42022-04-19 14:55:36882 // TODO(crbug.com/1314749): we should also capture the concept of outermost
883 // main frame here.
Alexander Timin074cd182022-03-23 18:11:22884 proto->set_is_main_frame(IsMainFrame());
885 proto.Set(TraceProto::kCurrentFrameHost, current_frame_host());
886 proto.Set(TraceProto::kSpeculativeFrameHost,
887 render_manager()->speculative_frame_host());
Rakina Zata Amni4b1968d2021-09-09 03:29:47888}
889
Carlos Caballero76711352021-03-24 17:38:21890bool FrameTreeNode::HasNavigation() {
891 if (navigation_request())
892 return true;
893
894 // Same-RenderFrameHost navigation is committing:
895 if (current_frame_host()->HasPendingCommitNavigation())
896 return true;
897
898 // Cross-RenderFrameHost navigation is committing:
899 if (render_manager()->speculative_frame_host())
900 return true;
901
902 return false;
903}
904
Dominic Farolino4bc10ee2021-08-31 00:37:36905bool FrameTreeNode::IsFencedFrameRoot() const {
Harkiran Bolaria16f2c48d2022-04-22 12:39:57906 return fenced_frame_status_ ==
907 RenderFrameHostImpl::FencedFrameStatus::kFencedFrameRoot;
shivanigithubf3ddff52021-07-03 22:06:30908}
909
910bool FrameTreeNode::IsInFencedFrameTree() const {
Harkiran Bolaria16f2c48d2022-04-22 12:39:57911 return fenced_frame_status_ !=
912 RenderFrameHostImpl::FencedFrameStatus::kNotNestedInFencedFrame;
shivanigithubf3ddff52021-07-03 22:06:30913}
914
shivanigithub4cd016a2021-09-20 21:10:30915void FrameTreeNode::SetFencedFrameNonceIfNeeded() {
916 if (!IsInFencedFrameTree()) {
917 return;
918 }
919
920 if (IsFencedFrameRoot()) {
921 fenced_frame_nonce_ = base::UnguessableToken::Create();
922 return;
923 }
924
925 // For nested iframes in a fenced frame tree, propagate the same nonce as was
926 // set in the fenced frame root.
927 DCHECK(parent_);
928 absl::optional<base::UnguessableToken> nonce =
929 parent_->frame_tree_node()->fenced_frame_nonce();
930 DCHECK(nonce.has_value());
931 fenced_frame_nonce_ = nonce;
932}
933
Nan Line376738a2022-03-25 22:05:41934absl::optional<blink::mojom::FencedFrameMode>
935FrameTreeNode::GetFencedFrameMode() {
Garrett Tanzera42fdef2022-06-13 16:09:14936 if (!IsInFencedFrameTree()) {
Nan Line376738a2022-03-25 22:05:41937 return absl::nullopt;
Garrett Tanzera42fdef2022-06-13 16:09:14938 }
Nan Lin171fe9a2022-02-17 16:42:16939
Garrett Tanzera42fdef2022-06-13 16:09:14940 switch (blink::features::kFencedFramesImplementationTypeParam.Get()) {
941 case blink::features::FencedFramesImplementationType::kMPArch: {
942 FrameTreeNode* outer_delegate_node =
943 render_manager()->GetOuterDelegateNode();
944 DCHECK(outer_delegate_node);
Nan Lin171fe9a2022-02-17 16:42:16945
Garrett Tanzera42fdef2022-06-13 16:09:14946 FencedFrame* fenced_frame = FindFencedFrame(outer_delegate_node);
947 DCHECK(fenced_frame);
Nan Line376738a2022-03-25 22:05:41948
Garrett Tanzera42fdef2022-06-13 16:09:14949 return fenced_frame->mode();
950 }
951 case blink::features::FencedFramesImplementationType::kShadowDOM: {
952 FrameTreeNode* node = this;
953 while (!node->IsFencedFrameRoot()) {
954 FrameTreeNode* next_node = parent()->frame_tree_node();
955 node = next_node;
956 }
957 return node->pending_frame_policy_.fenced_frame_mode;
958 }
959 }
Nan Lin171fe9a2022-02-17 16:42:16960}
961
Nan Linaaf84f72021-12-02 22:31:56962bool FrameTreeNode::IsErrorPageIsolationEnabled() const {
Nan Lind9de87d2022-03-18 16:53:03963 // Error page isolation is enabled for main frames only (crbug.com/1092524).
964 // Note that this will also enable error page isolation for fenced frames in
965 // MPArch mode, but not ShadowDOM mode.
966 // See the issue in crbug.com/1264224#c7 for why it can't be enabled for
967 // ShadowDOM mode.
968 return SiteIsolationPolicy::IsErrorPageIsolationEnabled(IsMainFrame());
Nan Linaaf84f72021-12-02 22:31:56969}
970
W. James MacLean81b8d01f2022-01-25 20:50:59971void FrameTreeNode::SetSrcdocValue(const std::string& srcdoc_value) {
972 srcdoc_value_ = srcdoc_value;
973}
974
Yao Xiao1ac702d2022-06-08 17:20:49975FencedFrameURLMapping::SharedStorageBudgetMetadata*
976FrameTreeNode::FindSharedStorageBudgetMetadata() {
977 FrameTreeNode* node = this;
978
979 while (true) {
980 if (node->shared_storage_budget_metadata()) {
981 DCHECK(node->IsFencedFrameRoot());
982 return node->shared_storage_budget_metadata();
983 }
984
985 if (node->GetParentOrOuterDocument()) {
986 node = node->GetParentOrOuterDocument()->frame_tree_node();
987 } else {
988 break;
989 }
990 }
991
992 return nullptr;
993}
994
Harkiran Bolariaebbe7702022-02-22 19:19:03995const scoped_refptr<BrowsingContextState>&
996FrameTreeNode::GetBrowsingContextStateForSubframe() const {
997 DCHECK(!IsMainFrame());
998 return current_frame_host()->browsing_context_state();
999}
1000
Arthur Hemerye4659282022-03-28 08:36:151001void FrameTreeNode::ClearOpenerReferences() {
1002 // Simulate the FrameTreeNode being dead to opener observers. They will
1003 // nullify their opener.
1004 // Note: observers remove themselves from observers_, no need to take care of
1005 // that manually.
1006 for (auto& observer : observers_)
1007 observer.OnFrameTreeNodeDisownedOpenee(this);
1008}
1009
[email protected]9b159a52013-10-03 17:24:551010} // namespace content