blob: c644c262dace77ad04b94de9cf4321075a164cc7 [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"
Paul Semel3e241042022-10-11 12:57:3123#include "content/browser/renderer_host/frame_tree.h"
danakjc492bf82020-09-09 20:02:4424#include "content/browser/renderer_host/navigation_controller_impl.h"
25#include "content/browser/renderer_host/navigation_request.h"
26#include "content/browser/renderer_host/navigator.h"
27#include "content/browser/renderer_host/navigator_delegate.h"
28#include "content/browser/renderer_host/render_frame_host_impl.h"
[email protected]94d0cc12013-12-18 00:07:4129#include "content/browser/renderer_host/render_view_host_impl.h"
Lucas Furukawa Gadanief8290a2019-07-29 20:27:5130#include "content/common/navigation_params_utils.h"
dmazzonie950ea232015-03-13 21:39:4531#include "content/public/browser/browser_thread.h"
Nan Linaaf84f72021-12-02 22:31:5632#include "content/public/browser/site_isolation_policy.h"
Mustaq Ahmeda5dfa60b2018-12-08 00:30:1433#include "content/public/common/content_features.h"
arthursonzognib93a4472020-04-10 07:38:0034#include "services/network/public/cpp/web_sandbox_flags.h"
35#include "services/network/public/mojom/web_sandbox_flags.mojom-shared.h"
Harkiran Bolaria59290d62021-03-17 01:53:0136#include "third_party/blink/public/common/features.h"
Liam Bradyb0f1f0e2022-08-19 21:42:1137#include "third_party/blink/public/common/frame/fenced_frame_sandbox_flags.h"
Sreeja Kamishetty0be3b1b2021-08-12 17:04:1538#include "third_party/blink/public/common/loader/loader_constants.h"
Antonio Gomes4b2c5132020-01-16 11:49:4839#include "third_party/blink/public/mojom/frame/user_activation_update_types.mojom.h"
Julie Jeongeun Kimd90e2dd2020-03-03 11:45:3740#include "third_party/blink/public/mojom/security_context/insecure_request_policy.mojom.h"
[email protected]9b159a52013-10-03 17:24:5541
42namespace content {
43
dmazzonie950ea232015-03-13 21:39:4544namespace {
45
46// This is a global map between frame_tree_node_ids and pointers to
47// FrameTreeNodes.
Takuto Ikutaadf31eb2019-01-05 00:32:4848typedef std::unordered_map<int, FrameTreeNode*> FrameTreeNodeIdMap;
dmazzonie950ea232015-03-13 21:39:4549
scottmg5e65e3a2017-03-08 08:48:4650base::LazyInstance<FrameTreeNodeIdMap>::DestructorAtExit
51 g_frame_tree_node_id_map = LAZY_INSTANCE_INITIALIZER;
dmazzonie950ea232015-03-13 21:39:4552
Nan Line376738a2022-03-25 22:05:4153FencedFrame* FindFencedFrame(const FrameTreeNode* frame_tree_node) {
54 // TODO(crbug.com/1123606): Consider having a pointer to `FencedFrame` in
55 // `FrameTreeNode` or having a map between them.
56
57 // Try and find the `FencedFrame` that `frame_tree_node` represents.
58 DCHECK(frame_tree_node->parent());
59 std::vector<FencedFrame*> fenced_frames =
60 frame_tree_node->parent()->GetFencedFrames();
61 for (FencedFrame* fenced_frame : fenced_frames) {
62 if (frame_tree_node->frame_tree_node_id() ==
63 fenced_frame->GetOuterDelegateFrameTreeNodeId()) {
64 return fenced_frame;
65 }
66 }
67 return nullptr;
68}
69
fdegansa696e5112015-04-17 01:57:5970} // namespace
fdegans1d16355162015-03-26 11:58:3471
alexmose201c7cd2015-06-10 17:14:2172// This observer watches the opener of its owner FrameTreeNode and clears the
Arthur Hemerye4659282022-03-28 08:36:1573// owner's opener if the opener is destroyed or swaps BrowsingInstance.
alexmose201c7cd2015-06-10 17:14:2174class FrameTreeNode::OpenerDestroyedObserver : public FrameTreeNode::Observer {
75 public:
jochen6004a362017-02-04 00:11:4076 OpenerDestroyedObserver(FrameTreeNode* owner, bool observing_original_opener)
77 : owner_(owner), observing_original_opener_(observing_original_opener) {}
alexmose201c7cd2015-06-10 17:14:2178
Peter Boström9b036532021-10-28 23:37:2879 OpenerDestroyedObserver(const OpenerDestroyedObserver&) = delete;
80 OpenerDestroyedObserver& operator=(const OpenerDestroyedObserver&) = delete;
81
alexmose201c7cd2015-06-10 17:14:2182 // FrameTreeNode::Observer
83 void OnFrameTreeNodeDestroyed(FrameTreeNode* node) override {
Arthur Hemerye4659282022-03-28 08:36:1584 NullifyOpener(node);
85 }
86
87 // FrameTreeNode::Observer
88 void OnFrameTreeNodeDisownedOpenee(FrameTreeNode* node) override {
89 NullifyOpener(node);
90 }
91
92 void NullifyOpener(FrameTreeNode* node) {
jochen6004a362017-02-04 00:11:4093 if (observing_original_opener_) {
Rakina Zata Amni3a48ae42022-05-05 03:39:5694 // The "original opener" is special. It's used for attribution, and
95 // clients walk down the original opener chain. Therefore, if a link in
96 // the chain is being destroyed, reconnect the observation to the parent
97 // of the link being destroyed.
98 CHECK_EQ(owner_->first_live_main_frame_in_original_opener_chain(), node);
99 owner_->SetOriginalOpener(
100 node->first_live_main_frame_in_original_opener_chain());
Avi Drissman36465f332017-09-11 20:49:39101 // |this| is deleted at this point.
jochen6004a362017-02-04 00:11:40102 } else {
103 CHECK_EQ(owner_->opener(), node);
104 owner_->SetOpener(nullptr);
Avi Drissman36465f332017-09-11 20:49:39105 // |this| is deleted at this point.
jochen6004a362017-02-04 00:11:40106 }
alexmose201c7cd2015-06-10 17:14:21107 }
108
109 private:
Keishi Hattori0e45c022021-11-27 09:25:52110 raw_ptr<FrameTreeNode> owner_;
jochen6004a362017-02-04 00:11:40111 bool observing_original_opener_;
alexmose201c7cd2015-06-10 17:14:21112};
113
Kevin McNee88e61552020-10-22 20:41:11114const int FrameTreeNode::kFrameTreeNodeInvalidId = -1;
115
116static_assert(FrameTreeNode::kFrameTreeNodeInvalidId ==
117 RenderFrameHost::kNoFrameTreeNodeId,
118 "Have consistent sentinel values for an invalid FTN id.");
119
vishal.b782eb5d2015-04-29 12:22:57120int FrameTreeNode::next_frame_tree_node_id_ = 1;
[email protected]9b159a52013-10-03 17:24:55121
dmazzonie950ea232015-03-13 21:39:45122// static
vishal.b782eb5d2015-04-29 12:22:57123FrameTreeNode* FrameTreeNode::GloballyFindByID(int frame_tree_node_id) {
mostynb366eaf12015-03-26 00:51:19124 DCHECK_CURRENTLY_ON(BrowserThread::UI);
rob97250742015-12-10 17:45:15125 FrameTreeNodeIdMap* nodes = g_frame_tree_node_id_map.Pointer();
jdoerrie55ec69d2018-10-08 13:34:46126 auto it = nodes->find(frame_tree_node_id);
dmazzonie950ea232015-03-13 21:39:45127 return it == nodes->end() ? nullptr : it->second;
128}
129
Alexander Timin381e7e182020-04-28 19:04:03130// static
131FrameTreeNode* FrameTreeNode::From(RenderFrameHost* rfh) {
132 if (!rfh)
133 return nullptr;
134 return static_cast<RenderFrameHostImpl*>(rfh)->frame_tree_node();
135}
136
Abhijeet Kandalkarb43affa72022-09-27 16:48:01137FrameTreeNode::FencedFrameStatus ComputeFencedFrameStatus(
Harkiran Bolaria16f2c48d2022-04-22 12:39:57138 FrameTree* frame_tree,
139 RenderFrameHostImpl* parent,
140 const blink::FramePolicy& frame_policy) {
Abhijeet Kandalkarb43affa72022-09-27 16:48:01141 using FencedFrameStatus = FrameTreeNode::FencedFrameStatus;
Harkiran Bolaria16f2c48d2022-04-22 12:39:57142 if (blink::features::IsFencedFramesEnabled()) {
143 switch (blink::features::kFencedFramesImplementationTypeParam.Get()) {
144 case blink::features::FencedFramesImplementationType::kMPArch: {
145 if (frame_tree->type() == FrameTree::Type::kFencedFrame) {
146 if (!parent)
Abhijeet Kandalkar3f29bc42022-09-23 12:39:58147 return FencedFrameStatus::kFencedFrameRoot;
148 return FencedFrameStatus::kIframeNestedWithinFencedFrame;
Harkiran Bolaria16f2c48d2022-04-22 12:39:57149 } else {
Abhijeet Kandalkar3f29bc42022-09-23 12:39:58150 return FencedFrameStatus::kNotNestedInFencedFrame;
Harkiran Bolaria16f2c48d2022-04-22 12:39:57151 }
152 }
153 case blink::features::FencedFramesImplementationType::kShadowDOM: {
154 // Different from the MPArch case, the ShadowDOM implementation of
155 // fenced frame lives in the same FrameTree as its parent, so we need to
156 // check its effective frame policy instead.
157 if (frame_policy.is_fenced) {
Abhijeet Kandalkar3f29bc42022-09-23 12:39:58158 return FencedFrameStatus::kFencedFrameRoot;
Abhijeet Kandalkardf9af612022-10-06 07:02:45159 } else if (parent && parent->IsNestedWithinFencedFrame()) {
Abhijeet Kandalkar3f29bc42022-09-23 12:39:58160 return FencedFrameStatus::kIframeNestedWithinFencedFrame;
Harkiran Bolaria16f2c48d2022-04-22 12:39:57161 }
Abhijeet Kandalkar3f29bc42022-09-23 12:39:58162 return FencedFrameStatus::kNotNestedInFencedFrame;
Harkiran Bolaria16f2c48d2022-04-22 12:39:57163 }
164 default: {
Abhijeet Kandalkar3f29bc42022-09-23 12:39:58165 return FencedFrameStatus::kNotNestedInFencedFrame;
Harkiran Bolaria16f2c48d2022-04-22 12:39:57166 }
167 }
168 }
169
Abhijeet Kandalkar3f29bc42022-09-23 12:39:58170 return FencedFrameStatus::kNotNestedInFencedFrame;
Harkiran Bolaria16f2c48d2022-04-22 12:39:57171}
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),
Yuzu Saijo03dbf9b2022-07-22 04:29:45191 attributes_(blink::mojom::IframeAttributes::New()),
Harkiran Bolaria16f2c48d2022-04-22 12:39:57192 fenced_frame_status_(
193 ComputeFencedFrameStatus(frame_tree_, parent_, frame_policy)),
Harkiran Bolaria0b3bdef02022-03-10 13:04:40194 render_manager_(this, frame_tree->manager_delegate()) {
Harkiran Bolariaa8347782022-04-06 09:25:11195 TRACE_EVENT_BEGIN("navigation", "FrameTreeNode",
196 perfetto::Track::FromPointer(this),
197 "frame_tree_node_when_created", this);
rob97250742015-12-10 17:45:15198 std::pair<FrameTreeNodeIdMap::iterator, bool> result =
dmazzonie950ea232015-03-13 21:39:45199 g_frame_tree_node_id_map.Get().insert(
200 std::make_pair(frame_tree_node_id_, this));
201 CHECK(result.second);
alexmos998581d2015-01-22 01:01:59202}
[email protected]9b159a52013-10-03 17:24:55203
Dominic Farolino8a2187b2021-12-24 20:44:21204void FrameTreeNode::DestroyInnerFrameTreeIfExists() {
205 // If `this` is an dummy outer delegate node, then we really are representing
206 // an inner FrameTree for one of the following consumers:
207 // - `Portal`
208 // - `FencedFrame`
209 // - `GuestView`
210 // If we are representing a `FencedFrame` object, we need to destroy it
211 // alongside ourself. `Portals` and `GuestView` however, *currently* have a
212 // more complex lifetime and are dealt with separately.
213 bool is_outer_dummy_node = false;
214 if (current_frame_host() &&
215 current_frame_host()->inner_tree_main_frame_tree_node_id() !=
216 FrameTreeNode::kFrameTreeNodeInvalidId) {
217 is_outer_dummy_node = true;
218 }
219
220 if (is_outer_dummy_node) {
Nan Line376738a2022-03-25 22:05:41221 FencedFrame* doomed_fenced_frame = FindFencedFrame(this);
Dominic Farolino8a2187b2021-12-24 20:44:21222 // `doomed_fenced_frame` might not actually exist, because some outer dummy
223 // `FrameTreeNode`s might correspond to `Portal`s, which do not have their
224 // lifetime managed in the same way as `FencedFrames`.
225 if (doomed_fenced_frame) {
226 parent()->DestroyFencedFrame(*doomed_fenced_frame);
227 }
228 }
229}
230
[email protected]9b159a52013-10-03 17:24:55231FrameTreeNode::~FrameTreeNode() {
Harkiran Bolariaa8347782022-04-06 09:25:11232 TRACE_EVENT("navigation", "FrameTreeNode::~FrameTreeNode");
Daniel Chengc3d1e8d2021-06-23 02:11:45233 // There should always be a current RenderFrameHost except during prerender
234 // activation. Prerender activation moves the current RenderFrameHost from
235 // the old FrameTree's FrameTreeNode to the new FrameTree's FrameTreeNode and
236 // then destroys the old FrameTree. See
237 // `RenderFrameHostManager::TakePrerenderedPage()`.
Harkiran Bolaria59290d62021-03-17 01:53:01238 if (current_frame_host()) {
239 // Remove the children.
240 current_frame_host()->ResetChildren();
Lukasz Anforowicz7bfb2e92017-11-22 17:19:45241
Harkiran Bolaria59290d62021-03-17 01:53:01242 current_frame_host()->ResetLoadingState();
243 } else {
Hiroki Nakagawa0a90bd42021-04-21 01:53:05244 DCHECK(blink::features::IsPrerender2Enabled());
Harkiran Bolaria59290d62021-03-17 01:53:01245 DCHECK(!parent()); // Only main documents can be activated.
246 DCHECK(!opener()); // Prerendered frame trees can't have openers.
247
248 // Activation is not allowed during ongoing navigations.
249 DCHECK(!navigation_request_);
250
Carlos Caballerod1c80432021-04-20 08:16:32251 // TODO(https://crbug.com/1199693): Need to determine how to handle pending
Harkiran Bolaria59290d62021-03-17 01:53:01252 // deletions, as observers will be notified.
253 DCHECK(!render_manager()->speculative_frame_host());
254 }
Nate Chapin22ea6592019-03-05 22:29:02255
Lukasz Anforowicz7bfb2e92017-11-22 17:19:45256 // If the removed frame was created by a script, then its history entry will
257 // never be reused - we can save some memory by removing the history entry.
258 // See also https://crbug.com/784356.
259 if (is_created_by_script_ && parent_) {
Carlos Caballero04aab362021-02-15 17:38:16260 NavigationEntryImpl* nav_entry =
261 navigator().controller().GetLastCommittedEntry();
Lukasz Anforowicz7bfb2e92017-11-22 17:19:45262 if (nav_entry) {
263 nav_entry->RemoveEntryForFrame(this,
264 /* only_if_different_position = */ false);
265 }
266 }
267
dmazzonie950ea232015-03-13 21:39:45268 frame_tree_->FrameRemoved(this);
Carlos Caballero6ff6ace2021-02-05 16:53:00269
Dominic Farolino8a2187b2021-12-24 20:44:21270 DestroyInnerFrameTreeIfExists();
271
Alex Rudenkobfc5c192022-11-03 07:27:37272 devtools_instrumentation::OnFrameTreeNodeDestroyed(*this);
Carlos Caballero6ff6ace2021-02-05 16:53:00273 // Do not dispatch notification for the root frame as ~WebContentsImpl already
274 // dispatches it for now.
275 // TODO(https://crbug.com/1170277): This is only needed because the FrameTree
276 // is a member of WebContentsImpl and we would call back into it during
277 // destruction. We should clean up the FrameTree destruction code and call the
278 // delegate unconditionally.
279 if (parent())
280 render_manager_.delegate()->OnFrameTreeNodeDestroyed(this);
281
ericwilligers254597b2016-10-17 10:32:31282 for (auto& observer : observers_)
283 observer.OnFrameTreeNodeDestroyed(this);
Lukasz Anforowicz147141962020-12-16 18:03:24284 observers_.Clear();
alexmose201c7cd2015-06-10 17:14:21285
286 if (opener_)
287 opener_->RemoveObserver(opener_observer_.get());
Rakina Zata Amni3a48ae42022-05-05 03:39:56288 if (first_live_main_frame_in_original_opener_chain_)
289 first_live_main_frame_in_original_opener_chain_->RemoveObserver(
290 original_opener_observer_.get());
dmazzonie950ea232015-03-13 21:39:45291
292 g_frame_tree_node_id_map.Get().erase(frame_tree_node_id_);
jam39258caf2016-11-02 14:48:18293
Daniel Chengc3d1e8d2021-06-23 02:11:45294 // If a frame with a pending navigation is detached, make sure the
295 // WebContents (and its observers) update their loading state.
296 // TODO(dcheng): This should just check `IsLoading()`, but `IsLoading()`
297 // assumes that `current_frame_host_` is not null. This is incompatible with
298 // prerender activation when destroying the old frame tree (see above).
danakjf9400602019-06-07 15:44:58299 bool did_stop_loading = false;
300
jam39258caf2016-11-02 14:48:18301 if (navigation_request_) {
danakjf9400602019-06-07 15:44:58302 navigation_request_.reset();
danakjf9400602019-06-07 15:44:58303 did_stop_loading = true;
jam39258caf2016-11-02 14:48:18304 }
Nate Chapin22ea6592019-03-05 22:29:02305
danakjf9400602019-06-07 15:44:58306 // ~SiteProcessCountTracker DCHECKs in some tests if the speculative
307 // RenderFrameHostImpl is not destroyed last. Ideally this would be closer to
308 // (possible before) the ResetLoadingState() call above.
danakjf9400602019-06-07 15:44:58309 if (render_manager_.speculative_frame_host()) {
Daniel Chengc3d1e8d2021-06-23 02:11:45310 // TODO(dcheng): Shouldn't a FrameTreeNode with a speculative
311 // RenderFrameHost always be considered loading?
danakjf9400602019-06-07 15:44:58312 did_stop_loading |= render_manager_.speculative_frame_host()->is_loading();
Daniel Chengc3d1e8d2021-06-23 02:11:45313 // `FrameTree::Shutdown()` has special handling for the main frame's
314 // speculative RenderFrameHost, and the speculative RenderFrameHost should
315 // already be reset for main frames.
316 DCHECK(!IsMainFrame());
317
318 // This does not use `UnsetSpeculativeRenderFrameHost()`: if the speculative
319 // RenderFrameHost has already reached kPendingCommit, it would needlessly
320 // re-create a proxy for a frame that's going away.
321 render_manager_.DiscardSpeculativeRenderFrameHostForShutdown();
danakjf9400602019-06-07 15:44:58322 }
323
324 if (did_stop_loading)
325 DidStopLoading();
326
Harkiran Bolaria59290d62021-03-17 01:53:01327 // IsLoading() requires that current_frame_host() is non-null.
328 DCHECK(!current_frame_host() || !IsLoading());
Harkiran Bolariaa8347782022-04-06 09:25:11329
330 // Matches the TRACE_EVENT_BEGIN in the constructor.
331 TRACE_EVENT_END("navigation", perfetto::Track::FromPointer(this));
[email protected]9b159a52013-10-03 17:24:55332}
333
alexmose201c7cd2015-06-10 17:14:21334void FrameTreeNode::AddObserver(Observer* observer) {
335 observers_.AddObserver(observer);
336}
337
338void FrameTreeNode::RemoveObserver(Observer* observer) {
339 observers_.RemoveObserver(observer);
340}
341
[email protected]94d0cc12013-12-18 00:07:41342bool FrameTreeNode::IsMainFrame() const {
343 return frame_tree_->root() == this;
344}
345
Paul Semel3e241042022-10-11 12:57:31346Navigator& FrameTreeNode::navigator() {
347 return frame_tree()->navigator();
348}
349
Ian Vollick25a9d032022-04-12 23:20:17350bool FrameTreeNode::IsOutermostMainFrame() {
351 return !GetParentOrOuterDocument();
352}
353
Hiroki Nakagawaab309622021-05-19 16:38:13354void FrameTreeNode::ResetForNavigation() {
arthursonzogni76098e52020-11-25 14:18:45355 // This frame has had its user activation bits cleared in the renderer before
356 // arriving here. We just need to clear them here and in the other renderer
357 // processes that may have a reference to this frame.
Alexander Timin45b716c2020-11-06 01:40:31358 //
359 // We do not take user activation into account when calculating
360 // |ResetForNavigationResult|, as we are using it to determine bfcache
361 // eligibility and the page can get another user gesture after restore.
Antonio Gomes4b2c5132020-01-16 11:49:48362 UpdateUserActivationState(
Mustaq Ahmeddc195e5b2020-08-04 18:45:11363 blink::mojom::UserActivationUpdateType::kClearActivation,
364 blink::mojom::UserActivationNotificationType::kNone);
Ian Clelland5cbaaf82017-11-27 22:00:03365}
366
Dave Tapuskac8de3b02021-12-03 21:51:01367RenderFrameHostImpl* FrameTreeNode::GetParentOrOuterDocument() {
368 return GetParentOrOuterDocumentHelper(/*escape_guest_view=*/false);
369}
370
371RenderFrameHostImpl* FrameTreeNode::GetParentOrOuterDocumentOrEmbedder() {
372 return GetParentOrOuterDocumentHelper(/*escape_guest_view=*/true);
373}
374
375RenderFrameHostImpl* FrameTreeNode::GetParentOrOuterDocumentHelper(
376 bool escape_guest_view) {
377 // Find the parent in the FrameTree (iframe).
378 if (parent_)
379 return parent_;
380
381 if (!escape_guest_view) {
382 // If we are not a fenced frame root nor inside a portal then return early.
383 // This code does not escape GuestViews.
384 if (!IsFencedFrameRoot() && !frame_tree_->delegate()->IsPortal())
385 return nullptr;
386 }
387
388 // Find the parent in the outer embedder (GuestView, Portal, or Fenced Frame).
389 FrameTreeNode* frame_in_embedder = render_manager()->GetOuterDelegateNode();
390 if (frame_in_embedder)
391 return frame_in_embedder->current_frame_host()->GetParent();
392
393 // No parent found.
394 return nullptr;
395}
396
Julie Jeongeun Kimf38c1eca2021-12-14 07:46:55397FrameType FrameTreeNode::GetFrameType() const {
398 if (!IsMainFrame())
399 return FrameType::kSubframe;
400
401 switch (frame_tree()->type()) {
402 case FrameTree::Type::kPrimary:
403 return FrameType::kPrimaryMainFrame;
404 case FrameTree::Type::kPrerender:
405 return FrameType::kPrerenderMainFrame;
406 case FrameTree::Type::kFencedFrame:
407 // We also have FencedFramesImplementationType::kShadowDOM for a
408 // fenced frame implementation based on <iframe> + shadowDOM,
409 // which will return kSubframe as it's a modified <iframe> rather
410 // than a dedicated FrameTree. This returns kSubframe for the
411 // shadow dom implementation in order to keep consistency (i.e.
412 // NavigationHandle::GetParentFrame returning non-null value for
413 // shadow-dom based FFs).
414 return FrameType::kFencedFrameRoot;
415 }
416}
417
alexmose201c7cd2015-06-10 17:14:21418void FrameTreeNode::SetOpener(FrameTreeNode* opener) {
Harkiran Bolariaa8347782022-04-06 09:25:11419 TRACE_EVENT("navigation", "FrameTreeNode::SetOpener",
420 ChromeTrackEvent::kFrameTreeNodeInfo, opener);
alexmose201c7cd2015-06-10 17:14:21421 if (opener_) {
422 opener_->RemoveObserver(opener_observer_.get());
423 opener_observer_.reset();
424 }
425
426 opener_ = opener;
427
428 if (opener_) {
Jeremy Roman04f27c372017-10-27 15:20:55429 opener_observer_ = std::make_unique<OpenerDestroyedObserver>(this, false);
alexmose201c7cd2015-06-10 17:14:21430 opener_->AddObserver(opener_observer_.get());
431 }
432}
433
Wolfgang Beyerd8809db2020-09-30 15:29:39434void FrameTreeNode::SetOpenerDevtoolsFrameToken(
435 base::UnguessableToken opener_devtools_frame_token) {
436 DCHECK(!opener_devtools_frame_token_ ||
437 opener_devtools_frame_token_->is_empty());
438 opener_devtools_frame_token_ = std::move(opener_devtools_frame_token);
439}
440
jochen6004a362017-02-04 00:11:40441void FrameTreeNode::SetOriginalOpener(FrameTreeNode* opener) {
Avi Drissman36465f332017-09-11 20:49:39442 // The original opener tracks main frames only.
avi8d1aa162017-03-27 18:27:37443 DCHECK(opener == nullptr || !opener->parent());
jochen6004a362017-02-04 00:11:40444
Rakina Zata Amni3a48ae42022-05-05 03:39:56445 if (first_live_main_frame_in_original_opener_chain_) {
446 first_live_main_frame_in_original_opener_chain_->RemoveObserver(
447 original_opener_observer_.get());
Avi Drissman36465f332017-09-11 20:49:39448 original_opener_observer_.reset();
449 }
450
Rakina Zata Amni3a48ae42022-05-05 03:39:56451 first_live_main_frame_in_original_opener_chain_ = opener;
jochen6004a362017-02-04 00:11:40452
Rakina Zata Amni3a48ae42022-05-05 03:39:56453 if (first_live_main_frame_in_original_opener_chain_) {
454 original_opener_observer_ = std::make_unique<OpenerDestroyedObserver>(
455 this, true /* observing_original_opener */);
456 first_live_main_frame_in_original_opener_chain_->AddObserver(
457 original_opener_observer_.get());
jochen6004a362017-02-04 00:11:40458 }
459}
460
engedy6e2e0992017-05-25 18:58:42461void FrameTreeNode::SetCollapsed(bool collapsed) {
Dave Tapuska65e50aa2022-03-09 23:44:13462 DCHECK(!IsMainFrame() || IsFencedFrameRoot());
engedy6e2e0992017-05-25 18:58:42463 if (is_collapsed_ == collapsed)
464 return;
465
466 is_collapsed_ = collapsed;
467 render_manager_.OnDidChangeCollapsedState(collapsed);
468}
469
Harkiran Bolaria59290d62021-03-17 01:53:01470void FrameTreeNode::SetFrameTree(FrameTree& frame_tree) {
Hiroki Nakagawa0a90bd42021-04-21 01:53:05471 DCHECK(blink::features::IsPrerender2Enabled());
Harkiran Bolaria59290d62021-03-17 01:53:01472 frame_tree_ = &frame_tree;
Kevin McNeeb110d0c2021-10-26 15:53:00473 DCHECK(current_frame_host());
474 current_frame_host()->SetFrameTree(frame_tree);
475 RenderFrameHostImpl* speculative_frame_host =
476 render_manager_.speculative_frame_host();
477 if (speculative_frame_host)
478 speculative_frame_host->SetFrameTree(frame_tree);
Harkiran Bolaria59290d62021-03-17 01:53:01479}
480
Luna Luc3fdacdf2017-11-08 04:48:53481void FrameTreeNode::SetPendingFramePolicy(blink::FramePolicy frame_policy) {
Dominic Farolinobfd1f0292022-03-23 19:12:24482 // The `is_fenced` and `fenced_frame_mode` bits should never be able to
483 // transition from their initial values. Since we never expect to be in a
484 // position where it can even be updated to new value, if we catch this
485 // happening we have to kill the renderer and refuse to accept any other frame
486 // policy changes here.
487 if (pending_frame_policy_.is_fenced != frame_policy.is_fenced ||
488 pending_frame_policy_.fenced_frame_mode !=
489 frame_policy.fenced_frame_mode) {
Dominic Farolino08662c82021-06-11 07:36:34490 mojo::ReportBadMessage(
Dominic Farolinobfd1f0292022-03-23 19:12:24491 "FramePolicy properties dealing with fenced frames are considered "
492 "immutable, and therefore should never be changed by the renderer.");
Dominic Farolino08662c82021-06-11 07:36:34493 return;
494 }
495
Liam Bradyb0f1f0e2022-08-19 21:42:11496 // Inside of a fenced frame, the sandbox flags should not be able to change
497 // from its initial value. If the flags change, we have to assume the change
498 // came from a compromised renderer and terminate it.
499 // We will only do the check if the sandbox flags are already set to
500 // kFencedFrameForcedSandboxFlags. This is to allow the sandbox flags to
501 // be set initially (go from kNone -> kFencedFrameForcedSandboxFlags). Once
502 // it has been set, it cannot change to another value.
503 // Note: The bad message is only expected to hit for ShadowDOM fenced frames.
504 // For MPArch, the RFHI will detect that the change is not coming from the
505 // frame's parent in DidChangeFramePolicy() (an MPArch fenced frame parent
506 // is null since it's the root frame in its tree) and terminate the
507 // renderer before we reach this point.
508 // TODO(crbug.com/1262022) When ShadowDOM is removed, turn this into a DCHECK
509 // and remove the BadMessage call.
510 if (IsFencedFrameRoot() &&
511 pending_frame_policy_.sandbox_flags ==
512 blink::kFencedFrameForcedSandboxFlags &&
513 frame_policy.sandbox_flags != blink::kFencedFrameForcedSandboxFlags) {
514 DCHECK(frame_tree()->IsFencedFramesShadowDOMBased());
515 bad_message::ReceivedBadMessage(
516 current_frame_host()->GetProcess(),
517 bad_message::FF_FROZEN_SANDBOX_FLAGS_CHANGED);
518 return;
519 }
520
Ian Clellandcdc4f312017-10-13 22:24:12521 pending_frame_policy_.sandbox_flags = frame_policy.sandbox_flags;
alexmos6e940102016-01-19 22:47:25522
Ian Clellandcdc4f312017-10-13 22:24:12523 if (parent()) {
524 // Subframes should always inherit their parent's sandbox flags.
Alexander Timin381e7e182020-04-28 19:04:03525 pending_frame_policy_.sandbox_flags |=
Harkiran Bolaria4eacb3a2021-12-13 20:03:47526 parent()->browsing_context_state()->active_sandbox_flags();
Charlie Hue1b77ac2019-12-13 21:30:17527 // This is only applied on subframes; container policy and required document
528 // policy are not mutable on main frame.
Ian Clellandcdc4f312017-10-13 22:24:12529 pending_frame_policy_.container_policy = frame_policy.container_policy;
Charlie Hue1b77ac2019-12-13 21:30:17530 pending_frame_policy_.required_document_policy =
531 frame_policy.required_document_policy;
Ian Clellandcdc4f312017-10-13 22:24:12532 }
iclelland92f8c0b2017-04-19 12:43:05533}
534
Yuzu Saijo03dbf9b2022-07-22 04:29:45535void FrameTreeNode::SetAttributes(
536 blink::mojom::IframeAttributesPtr attributes) {
537 if (!anonymous() && attributes->anonymous) {
538 // Log this only when anonymous is changed to true.
Arthur Sonzogni2e9c6111392022-05-02 08:37:13539 GetContentClient()->browser()->LogWebFeatureForCurrentPage(
540 parent_, blink::mojom::WebFeature::kAnonymousIframe);
541 }
Yuzu Saijo03dbf9b2022-07-22 04:29:45542 attributes_ = std::move(attributes);
Arthur Sonzogni2e9c6111392022-05-02 08:37:13543}
544
fdegans4a49ce932015-03-12 17:11:37545bool FrameTreeNode::IsLoading() const {
546 RenderFrameHostImpl* current_frame_host =
547 render_manager_.current_frame_host();
fdegans4a49ce932015-03-12 17:11:37548
549 DCHECK(current_frame_host);
fdegans39ff0382015-04-29 19:04:39550
clamy610c63b32017-12-22 15:05:18551 if (navigation_request_)
552 return true;
clamy11e11512015-07-07 16:42:17553
clamy610c63b32017-12-22 15:05:18554 RenderFrameHostImpl* speculative_frame_host =
555 render_manager_.speculative_frame_host();
Daniel Chengc3d1e8d2021-06-23 02:11:45556 // TODO(dcheng): Shouldn't a FrameTreeNode with a speculative RenderFrameHost
557 // always be considered loading?
clamy610c63b32017-12-22 15:05:18558 if (speculative_frame_host && speculative_frame_host->is_loading())
559 return true;
fdegans4a49ce932015-03-12 17:11:37560 return current_frame_host->is_loading();
561}
562
Alex Moshchuk9b0fd822020-10-26 23:08:15563bool FrameTreeNode::HasPendingCrossDocumentNavigation() const {
564 // Having a |navigation_request_| on FrameTreeNode implies that there's an
565 // ongoing navigation that hasn't reached the ReadyToCommit state. If the
566 // navigation is between ReadyToCommit and DidCommitNavigation, the
567 // NavigationRequest will be held by RenderFrameHost, which is checked below.
568 if (navigation_request_ && !navigation_request_->IsSameDocument())
569 return true;
570
571 // Having a speculative RenderFrameHost should imply a cross-document
572 // navigation.
573 if (render_manager_.speculative_frame_host())
574 return true;
575
576 return render_manager_.current_frame_host()
577 ->HasPendingCommitForCrossDocumentNavigation();
578}
579
Arthur Hemeryc3380172018-01-22 14:00:17580void FrameTreeNode::TransferNavigationRequestOwnership(
581 RenderFrameHostImpl* render_frame_host) {
Andrey Kosyakovf2d4ff72018-10-29 20:09:59582 devtools_instrumentation::OnResetNavigationRequest(navigation_request_.get());
Arthur Hemeryc3380172018-01-22 14:00:17583 render_frame_host->SetNavigationRequest(std::move(navigation_request_));
584}
585
carloskc49005eb2015-06-16 11:25:07586void FrameTreeNode::CreatedNavigationRequest(
dcheng9bfa5162016-04-09 01:00:57587 std::unique_ptr<NavigationRequest> navigation_request) {
arthursonzognic79c251c2016-08-18 15:00:37588 // This is never called when navigating to a Javascript URL. For the loading
589 // state, this matches what Blink is doing: Blink doesn't send throbber
590 // notifications for Javascript URLS.
591 DCHECK(!navigation_request->common_params().url.SchemeIs(
592 url::kJavaScriptScheme));
593
Yu Gaoc8c18552022-06-22 14:38:45594 bool was_previously_loading =
595 frame_tree()->LoadingTree()->IsLoadingIncludingInnerFrameTrees();
clamy44e84ce2016-02-22 15:38:25596
clamy82a2f4d2016-02-02 14:20:41597 // There's no need to reset the state: there's still an ongoing load, and the
598 // RenderFrameHostManager will take care of updates to the speculative
599 // RenderFrameHost in DidCreateNavigationRequest below.
jamcd0b7b22017-03-24 22:13:05600 if (was_previously_loading) {
Mohamed Abdelhalimf03d4a22019-10-01 13:34:31601 if (navigation_request_ && navigation_request_->IsNavigationStarted()) {
jamcd0b7b22017-03-24 22:13:05602 // Mark the old request as aborted.
Mohamed Abdelhalimb4db22a2019-06-18 10:46:52603 navigation_request_->set_net_error(net::ERR_ABORTED);
jamcd0b7b22017-03-24 22:13:05604 }
Daniel Cheng390e2a72022-09-28 06:07:53605 ResetNavigationRequestButKeepState();
jamcd0b7b22017-03-24 22:13:05606 }
clamy44e84ce2016-02-22 15:38:25607
608 navigation_request_ = std::move(navigation_request);
Shubhie Panickerddf2a4e2018-03-06 00:09:06609 if (was_discarded_) {
610 navigation_request_->set_was_discarded();
611 was_discarded_ = false;
612 }
clamy8e2e299202016-04-05 11:44:59613 render_manager()->DidCreateNavigationRequest(navigation_request_.get());
fdegans39ff0382015-04-29 19:04:39614
Lucas Furukawa Gadanief8290a2019-07-29 20:27:51615 bool to_different_document = !NavigationTypeUtils::IsSameDocument(
arthursonzogni92f18682017-02-08 23:00:04616 navigation_request_->common_params().navigation_type);
617
618 DidStartLoading(to_different_document, was_previously_loading);
clamydcb434c12015-04-16 19:29:16619}
620
Daniel Cheng390e2a72022-09-28 06:07:53621void FrameTreeNode::ResetNavigationRequest(NavigationDiscardReason reason) {
622 if (!navigation_request_)
623 return;
624
625 ResetNavigationRequestButKeepState();
626
627 // The RenderFrameHostManager should clean up any speculative RenderFrameHost
628 // it created for the navigation. Also register that the load stopped.
629 DidStopLoading();
630 render_manager_.CleanUpNavigation(reason);
631}
632
633void FrameTreeNode::ResetNavigationRequestButKeepState() {
fdegans39ff0382015-04-29 19:04:39634 if (!navigation_request_)
635 return;
John Abd-El-Malekdcc7bf42017-09-12 22:30:23636
Andrey Kosyakovf2d4ff72018-10-29 20:09:59637 devtools_instrumentation::OnResetNavigationRequest(navigation_request_.get());
clamydcb434c12015-04-16 19:29:16638 navigation_request_.reset();
639}
640
Nate Chapin9aabf5f2021-11-12 00:31:19641void FrameTreeNode::DidStartLoading(bool should_show_loading_ui,
clamy44e84ce2016-02-22 15:38:25642 bool was_previously_loading) {
Camille Lamyefd54b02018-10-04 16:54:14643 TRACE_EVENT2("navigation", "FrameTreeNode::DidStartLoading",
Nate Chapin9aabf5f2021-11-12 00:31:19644 "frame_tree_node", frame_tree_node_id(),
645 "should_show_loading_ui ", should_show_loading_ui);
Clark DuVallc97bcf72021-12-08 22:58:24646 base::ElapsedTimer timer;
fdegansa696e5112015-04-17 01:57:59647
Sreeja Kamishetty15f9944a22022-03-10 10:16:08648 frame_tree()->LoadingTree()->DidStartLoadingNode(
649 *this, should_show_loading_ui, was_previously_loading);
fdegansa696e5112015-04-17 01:57:59650
651 // Set initial load progress and update overall progress. This will notify
652 // the WebContents of the load progress change.
Sreeja Kamishetty15f9944a22022-03-10 10:16:08653 //
654 // Only notify when the load is triggered from primary/prerender main frame as
655 // we only update load progress for these nodes which happens when the frame
656 // tree matches the loading tree.
657 if (frame_tree() == frame_tree()->LoadingTree())
658 DidChangeLoadProgress(blink::kInitialLoadProgress);
fdegansa696e5112015-04-17 01:57:59659
Harkiran Bolaria3f83fba72022-03-10 17:48:40660 // Notify the proxies of the event.
661 current_frame_host()->browsing_context_state()->OnDidStartLoading();
Clark DuVallc97bcf72021-12-08 22:58:24662 base::UmaHistogramTimes(
663 base::StrCat({"Navigation.DidStartLoading.",
Ian Vollick5f45867c2022-08-05 08:29:56664 IsOutermostMainFrame() ? "MainFrame" : "Subframe"}),
Clark DuVallc97bcf72021-12-08 22:58:24665 timer.Elapsed());
fdegansa696e5112015-04-17 01:57:59666}
667
668void FrameTreeNode::DidStopLoading() {
Camille Lamyefd54b02018-10-04 16:54:14669 TRACE_EVENT1("navigation", "FrameTreeNode::DidStopLoading", "frame_tree_node",
670 frame_tree_node_id());
fdegansa696e5112015-04-17 01:57:59671 // Set final load progress and update overall progress. This will notify
672 // the WebContents of the load progress change.
Sreeja Kamishetty15f9944a22022-03-10 10:16:08673 //
674 // Only notify when the load is triggered from primary/prerender main frame as
675 // we only update load progress for these nodes which happens when the frame
676 // tree matches the loading tree.
677 if (frame_tree() == frame_tree()->LoadingTree())
678 DidChangeLoadProgress(blink::kFinalLoadProgress);
fdegansa696e5112015-04-17 01:57:59679
Harkiran Bolaria3f83fba72022-03-10 17:48:40680 // Notify the proxies of the event.
681 current_frame_host()->browsing_context_state()->OnDidStopLoading();
Lucas Furukawa Gadani6faef602019-05-06 21:16:03682
Sreeja Kamishetty15f9944a22022-03-10 10:16:08683 FrameTree* loading_tree = frame_tree()->LoadingTree();
684 // When loading tree is null, ignore invoking DidStopLoadingNode as the frame
685 // tree is already deleted. This can happen when prerendering gets cancelled
686 // and DidStopLoading is called during FrameTree destruction.
687 if (loading_tree)
688 loading_tree->DidStopLoadingNode(*this);
fdegansa696e5112015-04-17 01:57:59689}
690
691void FrameTreeNode::DidChangeLoadProgress(double load_progress) {
Sreeja Kamishetty0be3b1b2021-08-12 17:04:15692 DCHECK_GE(load_progress, blink::kInitialLoadProgress);
693 DCHECK_LE(load_progress, blink::kFinalLoadProgress);
694 current_frame_host()->DidChangeLoadProgress(load_progress);
fdegansa696e5112015-04-17 01:57:59695}
696
clamyf73862c42015-07-08 12:31:33697bool FrameTreeNode::StopLoading() {
arthursonzogni66f711c2019-10-08 14:40:36698 if (navigation_request_ && navigation_request_->IsNavigationStarted())
699 navigation_request_->set_net_error(net::ERR_ABORTED);
Daniel Cheng390e2a72022-09-28 06:07:53700 ResetNavigationRequest(NavigationDiscardReason::kCancelled);
clamyf73862c42015-07-08 12:31:33701
clamyf73862c42015-07-08 12:31:33702 if (!IsMainFrame())
703 return true;
704
705 render_manager_.Stop();
706 return true;
707}
708
alexmos21acae52015-11-07 01:04:43709void FrameTreeNode::DidFocus() {
710 last_focus_time_ = base::TimeTicks::Now();
ericwilligers254597b2016-10-17 10:32:31711 for (auto& observer : observers_)
712 observer.OnFrameTreeNodeFocused(this);
alexmos21acae52015-11-07 01:04:43713}
714
clamy44e84ce2016-02-22 15:38:25715void FrameTreeNode::BeforeUnloadCanceled() {
Julie Jeongeun Kim8cf7ae32022-05-02 03:47:29716 // TODO(clamy): Support BeforeUnload in subframes. Fenced Frames don't run
717 // BeforeUnload. Maybe need to check whether other MPArch inner pages cases
718 // need beforeunload(e.g., portals, GuestView if it gets ported to MPArch).
Ian Vollick1c6dd3e2022-04-13 02:06:26719 if (!IsOutermostMainFrame())
clamy44e84ce2016-02-22 15:38:25720 return;
721
722 RenderFrameHostImpl* current_frame_host =
723 render_manager_.current_frame_host();
724 DCHECK(current_frame_host);
725 current_frame_host->ResetLoadingState();
726
clamy610c63b32017-12-22 15:05:18727 RenderFrameHostImpl* speculative_frame_host =
728 render_manager_.speculative_frame_host();
729 if (speculative_frame_host)
730 speculative_frame_host->ResetLoadingState();
Alexander Timin23c110b2021-01-14 02:39:04731 // Note: there is no need to set an error code on the NavigationHandle as
732 // the observers have not been notified about its creation.
733 // We also reset navigation request only when this navigation request was
734 // responsible for this dialog, as a new navigation request might cancel
735 // existing unrelated dialog.
Daniel Cheng390e2a72022-09-28 06:07:53736 if (navigation_request_ && navigation_request_->IsWaitingForBeforeUnload()) {
737 ResetNavigationRequest(NavigationDiscardReason::kCancelled);
738 }
clamy44e84ce2016-02-22 15:38:25739}
740
Mustaq Ahmedecb5c38e2020-07-29 00:34:30741bool FrameTreeNode::NotifyUserActivation(
742 blink::mojom::UserActivationNotificationType notification_type) {
Garrett Tanzer753cc532022-03-02 21:30:59743 // User activation notifications shouldn't propagate into/out of fenced
744 // frames.
745 // For ShadowDOM, fenced frames are in the same frame tree as their embedder,
746 // so we need to perform additional checks to enforce the boundary.
747 // For MPArch, fenced frames have a separate frame tree, so this boundary is
748 // enforced by default.
749 // https://docs.google.com/document/d/1WnIhXOFycoje_sEoZR3Mo0YNSR2Ki7LABIC_HEWFaog
750 bool shadow_dom_fenced_frame_enabled =
David Bokanc3fb5fa2022-07-04 14:55:31751 frame_tree()->IsFencedFramesShadowDOMBased();
Garrett Tanzer753cc532022-03-02 21:30:59752
Alex Moshchuk03904192021-04-02 07:29:08753 // User Activation V2 requires activating all ancestor frames in addition to
754 // the current frame. See
755 // https://html.spec.whatwg.org/multipage/interaction.html#tracking-user-activation.
Alexander Timina1dfadaa2020-04-28 13:30:06756 for (RenderFrameHostImpl* rfh = current_frame_host(); rfh;
757 rfh = rfh->GetParent()) {
John Delaneyb625dca92021-04-14 17:00:34758 rfh->DidReceiveUserActivation();
Mustaq Ahmedecb5c38e2020-07-29 00:34:30759 rfh->frame_tree_node()->user_activation_state_.Activate(notification_type);
Garrett Tanzer753cc532022-03-02 21:30:59760
761 if (shadow_dom_fenced_frame_enabled &&
762 rfh->frame_tree_node()->IsFencedFrameRoot()) {
763 break;
764 }
John Delaneyedd8d6c2019-01-25 00:23:57765 }
Alex Moshchuk03904192021-04-02 07:29:08766
Harkiran Bolaria0b3bdef02022-03-10 13:04:40767 current_frame_host()->browsing_context_state()->set_has_active_user_gesture(
768 true);
Mustaq Ahmeda5dfa60b2018-12-08 00:30:14769
Garrett Tanzer753cc532022-03-02 21:30:59770 absl::optional<base::UnguessableToken> originator_nonce =
Garrett Tanzer34cb92fe2022-09-28 17:50:54771 GetFencedFrameNonce();
Garrett Tanzer753cc532022-03-02 21:30:59772
Mustaq Ahmed0180320f2019-03-21 16:07:01773 // See the "Same-origin Visibility" section in |UserActivationState| class
774 // doc.
Mustaq Ahmede5f12562019-10-30 18:02:03775 if (base::FeatureList::IsEnabled(
Garrett Tanzer753cc532022-03-02 21:30:59776 features::kUserActivationSameOriginVisibility)) {
Mustaq Ahmeda5dfa60b2018-12-08 00:30:14777 const url::Origin& current_origin =
778 this->current_frame_host()->GetLastCommittedOrigin();
779 for (FrameTreeNode* node : frame_tree()->Nodes()) {
Garrett Tanzer753cc532022-03-02 21:30:59780 if (shadow_dom_fenced_frame_enabled &&
Garrett Tanzer34cb92fe2022-09-28 17:50:54781 node->GetFencedFrameNonce() != originator_nonce) {
Garrett Tanzer753cc532022-03-02 21:30:59782 continue;
783 }
784
Mustaq Ahmeda5dfa60b2018-12-08 00:30:14785 if (node->current_frame_host()->GetLastCommittedOrigin().IsSameOriginWith(
786 current_origin)) {
Mustaq Ahmedecb5c38e2020-07-29 00:34:30787 node->user_activation_state_.Activate(notification_type);
Mustaq Ahmeda5dfa60b2018-12-08 00:30:14788 }
789 }
790 }
791
Carlos Caballero40b0efd2021-01-26 11:55:00792 navigator().controller().NotifyUserActivation();
Alex Moshchuk03904192021-04-02 07:29:08793 current_frame_host()->MaybeIsolateForUserActivation();
Shivani Sharma194877032019-03-07 17:52:47794
Mustaq Ahmedc4cb7162018-06-05 16:28:36795 return true;
796}
797
798bool FrameTreeNode::ConsumeTransientUserActivation() {
Garrett Tanzer753cc532022-03-02 21:30:59799 // User activation consumptions shouldn't propagate into/out of fenced
800 // frames.
801 // For ShadowDOM, fenced frames are in the same frame tree as their embedder,
802 // so we need to perform additional checks to enforce the boundary.
803 // For MPArch, fenced frames have a separate frame tree, so this boundary is
804 // enforced by default.
805 // https://docs.google.com/document/d/1WnIhXOFycoje_sEoZR3Mo0YNSR2Ki7LABIC_HEWFaog
806 bool shadow_dom_fenced_frame_enabled =
David Bokanc3fb5fa2022-07-04 14:55:31807 frame_tree()->IsFencedFramesShadowDOMBased();
Garrett Tanzer753cc532022-03-02 21:30:59808 absl::optional<base::UnguessableToken> originator_nonce =
Garrett Tanzer34cb92fe2022-09-28 17:50:54809 GetFencedFrameNonce();
Garrett Tanzer753cc532022-03-02 21:30:59810
Mustaq Ahmedc4cb7162018-06-05 16:28:36811 bool was_active = user_activation_state_.IsActive();
Garrett Tanzer753cc532022-03-02 21:30:59812 for (FrameTreeNode* node : frame_tree()->Nodes()) {
813 if (shadow_dom_fenced_frame_enabled &&
Garrett Tanzer34cb92fe2022-09-28 17:50:54814 node->GetFencedFrameNonce() != originator_nonce) {
Garrett Tanzer753cc532022-03-02 21:30:59815 continue;
816 }
817
Mustaq Ahmedc4cb7162018-06-05 16:28:36818 node->user_activation_state_.ConsumeIfActive();
Garrett Tanzer753cc532022-03-02 21:30:59819 }
Harkiran Bolaria0b3bdef02022-03-10 13:04:40820 current_frame_host()->browsing_context_state()->set_has_active_user_gesture(
821 false);
Mustaq Ahmedc4cb7162018-06-05 16:28:36822 return was_active;
823}
824
Shivani Sharmac4f561582018-11-15 15:58:39825bool FrameTreeNode::ClearUserActivation() {
Shivani Sharmac4f561582018-11-15 15:58:39826 for (FrameTreeNode* node : frame_tree()->SubtreeNodes(this))
827 node->user_activation_state_.Clear();
Harkiran Bolaria0b3bdef02022-03-10 13:04:40828 current_frame_host()->browsing_context_state()->set_has_active_user_gesture(
829 false);
Shivani Sharmac4f561582018-11-15 15:58:39830 return true;
831}
832
Ella Ge9caed612019-08-09 16:17:25833bool FrameTreeNode::VerifyUserActivation() {
Ella Gea78f6772019-12-11 10:35:25834 DCHECK(base::FeatureList::IsEnabled(
835 features::kBrowserVerifiedUserActivationMouse) ||
836 base::FeatureList::IsEnabled(
837 features::kBrowserVerifiedUserActivationKeyboard));
838
Ella Ge9caed612019-08-09 16:17:25839 return render_manager_.current_frame_host()
840 ->GetRenderWidgetHost()
Mustaq Ahmed83bb1722019-10-22 20:00:10841 ->RemovePendingUserActivationIfAvailable();
Ella Ge9caed612019-08-09 16:17:25842}
843
Mustaq Ahmedc4cb7162018-06-05 16:28:36844bool FrameTreeNode::UpdateUserActivationState(
Mustaq Ahmeddc195e5b2020-08-04 18:45:11845 blink::mojom::UserActivationUpdateType update_type,
846 blink::mojom::UserActivationNotificationType notification_type) {
Ella Ge9caed612019-08-09 16:17:25847 bool update_result = false;
Mustaq Ahmedc4cb7162018-06-05 16:28:36848 switch (update_type) {
Antonio Gomes4b2c5132020-01-16 11:49:48849 case blink::mojom::UserActivationUpdateType::kConsumeTransientActivation:
Ella Ge9caed612019-08-09 16:17:25850 update_result = ConsumeTransientUserActivation();
851 break;
Antonio Gomes4b2c5132020-01-16 11:49:48852 case blink::mojom::UserActivationUpdateType::kNotifyActivation:
Mustaq Ahmeddc195e5b2020-08-04 18:45:11853 update_result = NotifyUserActivation(notification_type);
Ella Ge9caed612019-08-09 16:17:25854 break;
Antonio Gomes4b2c5132020-01-16 11:49:48855 case blink::mojom::UserActivationUpdateType::
Liviu Tintad9391fb92020-09-28 23:50:07856 kNotifyActivationPendingBrowserVerification: {
857 const bool user_activation_verified = VerifyUserActivation();
858 // Add UMA metric for when browser user activation verification succeeds
859 base::UmaHistogramBoolean("Event.BrowserVerifiedUserActivation",
860 user_activation_verified);
861 if (user_activation_verified) {
Mustaq Ahmedecb5c38e2020-07-29 00:34:30862 update_result = NotifyUserActivation(
Mustaq Ahmed2cfb0402020-09-29 19:24:35863 blink::mojom::UserActivationNotificationType::kInteraction);
Antonio Gomes4b2c5132020-01-16 11:49:48864 update_type = blink::mojom::UserActivationUpdateType::kNotifyActivation;
Ella Ge9caed612019-08-09 16:17:25865 } else {
arthursonzogni9816b9192021-03-29 16:09:19866 // TODO(https://crbug.com/848778): We need to decide what to do when
867 // user activation verification failed. NOTREACHED here will make all
Ella Ge9caed612019-08-09 16:17:25868 // unrelated tests that inject event to renderer fail.
869 return false;
870 }
Liviu Tintad9391fb92020-09-28 23:50:07871 } break;
Antonio Gomes4b2c5132020-01-16 11:49:48872 case blink::mojom::UserActivationUpdateType::kClearActivation:
Ella Ge9caed612019-08-09 16:17:25873 update_result = ClearUserActivation();
874 break;
Mustaq Ahmedc4cb7162018-06-05 16:28:36875 }
Mustaq Ahmeddc195e5b2020-08-04 18:45:11876 render_manager_.UpdateUserActivationState(update_type, notification_type);
Ella Ge9caed612019-08-09 16:17:25877 return update_result;
japhet61835ae12017-01-20 01:25:39878}
879
Arthur Sonzognif8840b92018-11-07 14:10:35880void FrameTreeNode::PruneChildFrameNavigationEntries(
881 NavigationEntryImpl* entry) {
882 for (size_t i = 0; i < current_frame_host()->child_count(); ++i) {
883 FrameTreeNode* child = current_frame_host()->child_at(i);
884 if (child->is_created_by_script_) {
885 entry->RemoveEntryForFrame(child,
886 /* only_if_different_position = */ false);
887 } else {
888 child->PruneChildFrameNavigationEntries(entry);
889 }
890 }
891}
892
arthursonzogni034bb9c2020-10-01 08:29:56893void FrameTreeNode::SetInitialPopupURL(const GURL& initial_popup_url) {
894 DCHECK(initial_popup_url_.is_empty());
Rakina Zata Amni4182b032021-11-01 04:22:01895 DCHECK(is_on_initial_empty_document_);
arthursonzogni034bb9c2020-10-01 08:29:56896 initial_popup_url_ = initial_popup_url;
897}
898
899void FrameTreeNode::SetPopupCreatorOrigin(
900 const url::Origin& popup_creator_origin) {
Rakina Zata Amni4182b032021-11-01 04:22:01901 DCHECK(is_on_initial_empty_document_);
arthursonzogni034bb9c2020-10-01 08:29:56902 popup_creator_origin_ = popup_creator_origin;
903}
904
Rakina Zata Amni4b1968d2021-09-09 03:29:47905void FrameTreeNode::WriteIntoTrace(
Alexander Timin074cd182022-03-23 18:11:22906 perfetto::TracedProto<TraceProto> proto) const {
Rakina Zata Amni4b1968d2021-09-09 03:29:47907 proto->set_frame_tree_node_id(frame_tree_node_id());
Alexander Timin074cd182022-03-23 18:11:22908 proto->set_is_main_frame(IsMainFrame());
909 proto.Set(TraceProto::kCurrentFrameHost, current_frame_host());
910 proto.Set(TraceProto::kSpeculativeFrameHost,
911 render_manager()->speculative_frame_host());
Rakina Zata Amni4b1968d2021-09-09 03:29:47912}
913
Carlos Caballero76711352021-03-24 17:38:21914bool FrameTreeNode::HasNavigation() {
915 if (navigation_request())
916 return true;
917
918 // Same-RenderFrameHost navigation is committing:
919 if (current_frame_host()->HasPendingCommitNavigation())
920 return true;
921
922 // Cross-RenderFrameHost navigation is committing:
923 if (render_manager()->speculative_frame_host())
924 return true;
925
926 return false;
927}
928
Dominic Farolino4bc10ee2021-08-31 00:37:36929bool FrameTreeNode::IsFencedFrameRoot() const {
Abhijeet Kandalkar3f29bc42022-09-23 12:39:58930 return fenced_frame_status_ == FencedFrameStatus::kFencedFrameRoot;
shivanigithubf3ddff52021-07-03 22:06:30931}
932
933bool FrameTreeNode::IsInFencedFrameTree() const {
Abhijeet Kandalkar3f29bc42022-09-23 12:39:58934 return fenced_frame_status_ != FencedFrameStatus::kNotNestedInFencedFrame;
shivanigithubf3ddff52021-07-03 22:06:30935}
936
Garrett Tanzer34cb92fe2022-09-28 17:50:54937const absl::optional<FencedFrameURLMapping::FencedFrameProperties>&
938FrameTreeNode::GetFencedFrameProperties() {
shivanigithub4cd016a2021-09-20 21:10:30939 if (!IsInFencedFrameTree()) {
Garrett Tanzer34cb92fe2022-09-28 17:50:54940 // If we might be in a urn iframe, try to find the "urn iframe root"
941 // and if it exists, return the attached `FencedFrameProperties`.
942 if (blink::features::IsAllowURNsInIframeEnabled()) {
943 FrameTreeNode* node = this;
944 while (node->parent()) {
945 CHECK(node->parent()->frame_tree_node());
946 if (node->fenced_frame_properties_.has_value()) {
947 return node->fenced_frame_properties_;
948 }
949 node = node->parent()->frame_tree_node();
950 }
951 }
952 return fenced_frame_properties_;
953 }
954
955 switch (blink::features::kFencedFramesImplementationTypeParam.Get()) {
956 case blink::features::FencedFramesImplementationType::kMPArch: {
957 // Because we already confirmed we're in a fenced frame tree, we know
958 // there must be a fenced frame root with properties stored.
959 CHECK(frame_tree());
960 CHECK(frame_tree()->root());
961 CHECK(frame_tree()->root()->fenced_frame_properties_.has_value());
962 return frame_tree()->root()->fenced_frame_properties_;
963 }
964 case blink::features::FencedFramesImplementationType::kShadowDOM: {
965 FrameTreeNode* node = this;
966
967 while (true) {
968 if (node->IsFencedFrameRoot()) {
969 // Because non-opaque url navigations in ShadowDOM fenced frames
970 // do not install fenced frame properties, this may be absl::nullopt
971 // underneath.
972 return node->fenced_frame_properties_;
973 }
974
975 CHECK(node->parent());
976 CHECK(node->parent()->frame_tree_node());
977 node = node->parent()->frame_tree_node();
978 }
979 }
980 }
981}
982
Yao Xiaoa2337ad2022-10-12 20:59:29983size_t FrameTreeNode::GetFencedFrameDepth() {
984 size_t depth = 0;
985 FrameTreeNode* node = this;
986
987 while (node->fenced_frame_status() !=
988 FencedFrameStatus::kNotNestedInFencedFrame) {
989 if (node->fenced_frame_status() == FencedFrameStatus::kFencedFrameRoot) {
990 depth += 1;
991 } else {
992 DCHECK_EQ(node->fenced_frame_status(),
993 FencedFrameStatus::kIframeNestedWithinFencedFrame);
994 }
995
996 DCHECK(node->GetParentOrOuterDocument());
997 node = node->GetParentOrOuterDocument()->frame_tree_node();
998 }
999
1000 return depth;
1001}
1002
Garrett Tanzer34cb92fe2022-09-28 17:50:541003absl::optional<base::UnguessableToken> FrameTreeNode::GetFencedFrameNonce() {
1004 auto& root_fenced_frame_properties = GetFencedFrameProperties();
1005 if (!root_fenced_frame_properties.has_value()) {
1006 return absl::nullopt;
1007 }
1008 return root_fenced_frame_properties->partition_nonce;
1009}
1010
1011void FrameTreeNode::SetFencedFramePropertiesIfNeeded() {
1012 if (!IsFencedFrameRoot()) {
shivanigithub4cd016a2021-09-20 21:10:301013 return;
1014 }
1015
Garrett Tanzer34cb92fe2022-09-28 17:50:541016 // The fenced frame properties are set only on the fenced frame root.
1017 // In the future, they will be set on the FrameTree instead.
1018 fenced_frame_properties_ = FencedFrameURLMapping::FencedFrameProperties();
shivanigithub4cd016a2021-09-20 21:10:301019}
1020
Nan Line376738a2022-03-25 22:05:411021absl::optional<blink::mojom::FencedFrameMode>
1022FrameTreeNode::GetFencedFrameMode() {
Garrett Tanzera42fdef2022-06-13 16:09:141023 if (!IsInFencedFrameTree()) {
Nan Line376738a2022-03-25 22:05:411024 return absl::nullopt;
Garrett Tanzera42fdef2022-06-13 16:09:141025 }
Nan Lin171fe9a2022-02-17 16:42:161026
Garrett Tanzera42fdef2022-06-13 16:09:141027 switch (blink::features::kFencedFramesImplementationTypeParam.Get()) {
1028 case blink::features::FencedFramesImplementationType::kMPArch: {
1029 FrameTreeNode* outer_delegate_node =
1030 render_manager()->GetOuterDelegateNode();
1031 DCHECK(outer_delegate_node);
Nan Lin171fe9a2022-02-17 16:42:161032
Garrett Tanzera42fdef2022-06-13 16:09:141033 FencedFrame* fenced_frame = FindFencedFrame(outer_delegate_node);
1034 DCHECK(fenced_frame);
Nan Line376738a2022-03-25 22:05:411035
Garrett Tanzera42fdef2022-06-13 16:09:141036 return fenced_frame->mode();
1037 }
1038 case blink::features::FencedFramesImplementationType::kShadowDOM: {
1039 FrameTreeNode* node = this;
1040 while (!node->IsFencedFrameRoot()) {
Liam Brady582b21bc82022-08-10 14:03:211041 node = node->parent()->frame_tree_node();
Garrett Tanzera42fdef2022-06-13 16:09:141042 }
1043 return node->pending_frame_policy_.fenced_frame_mode;
1044 }
1045 }
Nan Lin171fe9a2022-02-17 16:42:161046}
1047
Nan Linaaf84f72021-12-02 22:31:561048bool FrameTreeNode::IsErrorPageIsolationEnabled() const {
Nan Lind9de87d2022-03-18 16:53:031049 // Error page isolation is enabled for main frames only (crbug.com/1092524).
1050 // Note that this will also enable error page isolation for fenced frames in
1051 // MPArch mode, but not ShadowDOM mode.
1052 // See the issue in crbug.com/1264224#c7 for why it can't be enabled for
1053 // ShadowDOM mode.
1054 return SiteIsolationPolicy::IsErrorPageIsolationEnabled(IsMainFrame());
Nan Linaaf84f72021-12-02 22:31:561055}
1056
W. James MacLean81b8d01f2022-01-25 20:50:591057void FrameTreeNode::SetSrcdocValue(const std::string& srcdoc_value) {
1058 srcdoc_value_ = srcdoc_value;
1059}
1060
Yao Xiaoa2337ad2022-10-12 20:59:291061std::vector<const FencedFrameURLMapping::SharedStorageBudgetMetadata*>
Yao Xiao1ac702d2022-06-08 17:20:491062FrameTreeNode::FindSharedStorageBudgetMetadata() {
Yao Xiaoa2337ad2022-10-12 20:59:291063 std::vector<const FencedFrameURLMapping::SharedStorageBudgetMetadata*> result;
Yao Xiao1ac702d2022-06-08 17:20:491064 FrameTreeNode* node = this;
1065
1066 while (true) {
Garrett Tanzer2975eeac2022-08-22 16:34:011067 if (node->fenced_frame_properties_ &&
1068 node->fenced_frame_properties_->shared_storage_budget_metadata) {
Yao Xiaoa2337ad2022-10-12 20:59:291069 result.emplace_back(node->fenced_frame_properties_
1070 ->shared_storage_budget_metadata.value());
Yao Xiao1ac702d2022-06-08 17:20:491071 }
1072
1073 if (node->GetParentOrOuterDocument()) {
1074 node = node->GetParentOrOuterDocument()->frame_tree_node();
1075 } else {
1076 break;
1077 }
1078 }
1079
Yao Xiaoa2337ad2022-10-12 20:59:291080 return result;
Yao Xiao1ac702d2022-06-08 17:20:491081}
1082
Harkiran Bolariaebbe7702022-02-22 19:19:031083const scoped_refptr<BrowsingContextState>&
1084FrameTreeNode::GetBrowsingContextStateForSubframe() const {
1085 DCHECK(!IsMainFrame());
1086 return current_frame_host()->browsing_context_state();
1087}
1088
Arthur Hemerye4659282022-03-28 08:36:151089void FrameTreeNode::ClearOpenerReferences() {
1090 // Simulate the FrameTreeNode being dead to opener observers. They will
1091 // nullify their opener.
1092 // Note: observers remove themselves from observers_, no need to take care of
1093 // that manually.
1094 for (auto& observer : observers_)
1095 observer.OnFrameTreeNodeDisownedOpenee(this);
1096}
1097
Liam Bradyd2a41e152022-07-19 13:58:481098bool FrameTreeNode::AncestorOrSelfHasCSPEE() const {
1099 // Check if CSPEE is set in this frame or any ancestor frames.
Yuzu Saijo03dbf9b2022-07-22 04:29:451100 return csp_attribute() || (parent() && parent()->required_csp());
Liam Bradyd2a41e152022-07-19 13:58:481101}
1102
Miyoung Shin7cf88b42022-11-07 13:22:301103void FrameTreeNode::RestartNavigationAsCrossDocument(
1104 std::unique_ptr<NavigationRequest> navigation_request) {
1105 navigator().RestartNavigationAsCrossDocument(std::move(navigation_request));
1106}
1107
[email protected]9b159a52013-10-03 17:24:551108} // namespace content