blob: b8415a7e4a3caa409d67953de399c65bf72d43e8 [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
[email protected]d4a8ca482013-10-30 21:06:405#include "content/browser/frame_host/frame_tree_node.h"
[email protected]9b159a52013-10-03 17:24:556
7#include <queue>
dcheng36b6aec92015-12-26 06:16:368#include <utility>
[email protected]9b159a52013-10-03 17:24:559
avib7348942015-12-25 20:57:1010#include "base/macros.h"
fdegansa696e5112015-04-17 01:57:5911#include "base/profiler/scoped_tracker.h"
[email protected]9b159a52013-10-03 17:24:5512#include "base/stl_util.h"
[email protected]94d0cc12013-12-18 00:07:4113#include "content/browser/frame_host/frame_tree.h"
clamydcb434c12015-04-16 19:29:1614#include "content/browser/frame_host/navigation_request.h"
[email protected]190b8c52013-11-09 01:35:4415#include "content/browser/frame_host/navigator.h"
[email protected]d4a8ca482013-10-30 21:06:4016#include "content/browser/frame_host/render_frame_host_impl.h"
[email protected]94d0cc12013-12-18 00:07:4117#include "content/browser/renderer_host/render_view_host_impl.h"
clamyf73862c42015-07-08 12:31:3318#include "content/common/frame_messages.h"
nickd30fd962015-07-27 21:51:0819#include "content/common/site_isolation_policy.h"
dmazzonie950ea232015-03-13 21:39:4520#include "content/public/browser/browser_thread.h"
carloskd80262f52015-12-16 14:40:3521#include "content/public/common/browser_side_navigation_policy.h"
alexmos6e940102016-01-19 22:47:2522#include "third_party/WebKit/public/web/WebSandboxFlags.h"
[email protected]9b159a52013-10-03 17:24:5523
24namespace content {
25
dmazzonie950ea232015-03-13 21:39:4526namespace {
27
28// This is a global map between frame_tree_node_ids and pointers to
29// FrameTreeNodes.
rob97250742015-12-10 17:45:1530typedef base::hash_map<int, FrameTreeNode*> FrameTreeNodeIdMap;
dmazzonie950ea232015-03-13 21:39:4531
rob97250742015-12-10 17:45:1532base::LazyInstance<FrameTreeNodeIdMap> g_frame_tree_node_id_map =
dmazzonie950ea232015-03-13 21:39:4533 LAZY_INSTANCE_INITIALIZER;
34
fdegansa696e5112015-04-17 01:57:5935// These values indicate the loading progress status. The minimum progress
36// value matches what Blink's ProgressTracker has traditionally used for a
37// minimum progress value.
38const double kLoadingProgressNotStarted = 0.0;
39const double kLoadingProgressMinimum = 0.1;
40const double kLoadingProgressDone = 1.0;
dmazzonie950ea232015-03-13 21:39:4541
fdegansa696e5112015-04-17 01:57:5942} // namespace
fdegans1d16355162015-03-26 11:58:3443
alexmose201c7cd2015-06-10 17:14:2144// This observer watches the opener of its owner FrameTreeNode and clears the
45// owner's opener if the opener is destroyed.
46class FrameTreeNode::OpenerDestroyedObserver : public FrameTreeNode::Observer {
47 public:
48 OpenerDestroyedObserver(FrameTreeNode* owner) : owner_(owner) {}
49
50 // FrameTreeNode::Observer
51 void OnFrameTreeNodeDestroyed(FrameTreeNode* node) override {
52 CHECK_EQ(owner_->opener(), node);
53 owner_->SetOpener(nullptr);
54 }
55
56 private:
57 FrameTreeNode* owner_;
58
59 DISALLOW_COPY_AND_ASSIGN(OpenerDestroyedObserver);
60};
61
vishal.b782eb5d2015-04-29 12:22:5762int FrameTreeNode::next_frame_tree_node_id_ = 1;
[email protected]9b159a52013-10-03 17:24:5563
dmazzonie950ea232015-03-13 21:39:4564// static
vishal.b782eb5d2015-04-29 12:22:5765FrameTreeNode* FrameTreeNode::GloballyFindByID(int frame_tree_node_id) {
mostynb366eaf12015-03-26 00:51:1966 DCHECK_CURRENTLY_ON(BrowserThread::UI);
rob97250742015-12-10 17:45:1567 FrameTreeNodeIdMap* nodes = g_frame_tree_node_id_map.Pointer();
68 FrameTreeNodeIdMap::iterator it = nodes->find(frame_tree_node_id);
dmazzonie950ea232015-03-13 21:39:4569 return it == nodes->end() ? nullptr : it->second;
70}
71
lazyboy70605c32015-11-03 01:27:3172FrameTreeNode::FrameTreeNode(
73 FrameTree* frame_tree,
74 Navigator* navigator,
75 RenderFrameHostDelegate* render_frame_delegate,
76 RenderViewHostDelegate* render_view_delegate,
77 RenderWidgetHostDelegate* render_widget_delegate,
78 RenderFrameHostManager::Delegate* manager_delegate,
79 blink::WebTreeScopeType scope,
80 const std::string& name,
lazyboy70605c32015-11-03 01:27:3181 const blink::WebFrameOwnerProperties& frame_owner_properties)
[email protected]bffc8302014-01-23 20:52:1682 : frame_tree_(frame_tree),
83 navigator_(navigator),
84 render_manager_(this,
85 render_frame_delegate,
86 render_view_delegate,
87 render_widget_delegate,
88 manager_delegate),
89 frame_tree_node_id_(next_frame_tree_node_id_++),
naskoa7064ad6e2015-01-15 18:44:5690 parent_(NULL),
alexmose201c7cd2015-06-10 17:14:2191 opener_(nullptr),
92 opener_observer_(nullptr),
creisf0f069a2015-07-23 23:51:5393 has_committed_real_load_(false),
estarka886b8d2015-12-18 21:53:0894 replication_state_(
95 scope,
96 name,
alexmos6e940102016-01-19 22:47:2597 blink::WebSandboxFlags::None,
estarka886b8d2015-12-18 21:53:0898 false /* should enforce strict mixed content checking */),
alexmos6e940102016-01-19 22:47:2599 pending_sandbox_flags_(blink::WebSandboxFlags::None),
lazyboy70605c32015-11-03 01:27:31100 frame_owner_properties_(frame_owner_properties),
fdegans1d16355162015-03-26 11:58:34101 loading_progress_(kLoadingProgressNotStarted) {
rob97250742015-12-10 17:45:15102 std::pair<FrameTreeNodeIdMap::iterator, bool> result =
dmazzonie950ea232015-03-13 21:39:45103 g_frame_tree_node_id_map.Get().insert(
104 std::make_pair(frame_tree_node_id_, this));
105 CHECK(result.second);
alexmos998581d2015-01-22 01:01:59106}
[email protected]9b159a52013-10-03 17:24:55107
108FrameTreeNode::~FrameTreeNode() {
nick8814e652015-12-18 01:44:12109 children_.clear();
dmazzonie950ea232015-03-13 21:39:45110 frame_tree_->FrameRemoved(this);
alexmose201c7cd2015-06-10 17:14:21111 FOR_EACH_OBSERVER(Observer, observers_, OnFrameTreeNodeDestroyed(this));
112
113 if (opener_)
114 opener_->RemoveObserver(opener_observer_.get());
dmazzonie950ea232015-03-13 21:39:45115
116 g_frame_tree_node_id_map.Get().erase(frame_tree_node_id_);
[email protected]9b159a52013-10-03 17:24:55117}
118
alexmose201c7cd2015-06-10 17:14:21119void FrameTreeNode::AddObserver(Observer* observer) {
120 observers_.AddObserver(observer);
121}
122
123void FrameTreeNode::RemoveObserver(Observer* observer) {
124 observers_.RemoveObserver(observer);
125}
126
[email protected]94d0cc12013-12-18 00:07:41127bool FrameTreeNode::IsMainFrame() const {
128 return frame_tree_->root() == this;
129}
130
nick8814e652015-12-18 01:44:12131FrameTreeNode* FrameTreeNode::AddChild(scoped_ptr<FrameTreeNode> child,
132 int process_id,
133 int frame_routing_id) {
dgroganfb22f9a2014-10-20 21:32:32134 // Child frame must always be created in the same process as the parent.
135 CHECK_EQ(process_id, render_manager_.current_host()->GetProcess()->GetID());
creisd06a9422015-11-11 03:08:45136 child->set_parent(this);
dgroganfb22f9a2014-10-20 21:32:32137
[email protected]94d0cc12013-12-18 00:07:41138 // Initialize the RenderFrameHost for the new node. We always create child
139 // frames in the same SiteInstance as the current frame, and they can swap to
140 // a different one if they navigate away.
141 child->render_manager()->Init(
[email protected]94d0cc12013-12-18 00:07:41142 render_manager_.current_host()->GetSiteInstance(),
dcheng29f5a6c2015-08-31 21:43:27143 render_manager_.current_host()->GetRoutingID(), frame_routing_id,
piman5d36dae2015-09-24 22:47:05144 MSG_ROUTING_NONE);
alexmos46e85ec2015-04-03 21:04:35145
146 // Other renderer processes in this BrowsingInstance may need to find out
147 // about the new frame. Create a proxy for the child frame in all
148 // SiteInstances that have a proxy for the frame's parent, since all frames
149 // in a frame tree should have the same set of proxies.
nickd30fd962015-07-27 21:51:08150 // TODO(alexmos, nick): We ought to do this for non-oopif too, for openers.
151 if (SiteIsolationPolicy::AreCrossProcessFramesPossible())
alexmos46e85ec2015-04-03 21:04:35152 render_manager_.CreateProxiesForChildFrame(child.get());
153
dcheng36b6aec92015-12-26 06:16:36154 children_.push_back(std::move(child));
nick8814e652015-12-18 01:44:12155 return children_.back().get();
[email protected]9b159a52013-10-03 17:24:55156}
157
[email protected]741fd682013-11-08 08:26:55158void FrameTreeNode::RemoveChild(FrameTreeNode* child) {
nickb6769e632015-11-13 23:25:18159 for (auto iter = children_.begin(); iter != children_.end(); ++iter) {
160 if (iter->get() == child) {
161 // Subtle: we need to make sure the node is gone from the tree before
162 // observers are notified of its deletion.
dcheng36b6aec92015-12-26 06:16:36163 scoped_ptr<FrameTreeNode> node_to_delete(std::move(*iter));
nickb6769e632015-11-13 23:25:18164 children_.erase(iter);
165 node_to_delete.reset();
166 return;
167 }
[email protected]bffc8302014-01-23 20:52:16168 }
[email protected]9b159a52013-10-03 17:24:55169}
170
[email protected]81c6c5e2014-02-13 20:20:07171void FrameTreeNode::ResetForNewProcess() {
[email protected]9b159a52013-10-03 17:24:55172 current_url_ = GURL();
[email protected]482ce3c2013-11-27 18:17:09173
nickb6769e632015-11-13 23:25:18174 // Remove child nodes from the tree, then delete them. This destruction
175 // operation will notify observers.
176 std::vector<scoped_ptr<FrameTreeNode>>().swap(children_);
[email protected]9b159a52013-10-03 17:24:55177}
178
alexmose201c7cd2015-06-10 17:14:21179void FrameTreeNode::SetOpener(FrameTreeNode* opener) {
180 if (opener_) {
181 opener_->RemoveObserver(opener_observer_.get());
182 opener_observer_.reset();
183 }
184
185 opener_ = opener;
186
187 if (opener_) {
188 if (!opener_observer_)
189 opener_observer_ = make_scoped_ptr(new OpenerDestroyedObserver(this));
190 opener_->AddObserver(opener_observer_.get());
191 }
192}
193
creisf0f069a2015-07-23 23:51:53194void FrameTreeNode::SetCurrentURL(const GURL& url) {
195 if (!has_committed_real_load_ && url != GURL(url::kAboutBlankURL))
196 has_committed_real_load_ = true;
197 current_url_ = url;
198}
199
mkwst13213f32015-07-27 07:06:27200void FrameTreeNode::SetCurrentOrigin(const url::Origin& origin) {
201 if (!origin.IsSameOriginWith(replication_state_.origin))
alexmosa7a4ff822015-04-27 17:59:56202 render_manager_.OnDidUpdateOrigin(origin);
203 replication_state_.origin = origin;
204}
alexmosbe2f4c32015-03-10 02:30:23205
alexmosa7a4ff822015-04-27 17:59:56206void FrameTreeNode::SetFrameName(const std::string& name) {
207 if (name != replication_state_.name)
208 render_manager_.OnDidUpdateName(name);
209 replication_state_.name = name;
alexmosbe2f4c32015-03-10 02:30:23210}
211
estarka886b8d2015-12-18 21:53:08212void FrameTreeNode::SetEnforceStrictMixedContentChecking(bool should_enforce) {
213 if (should_enforce ==
214 replication_state_.should_enforce_strict_mixed_content_checking) {
215 return;
216 }
217 render_manager_.OnEnforceStrictMixedContentChecking(should_enforce);
218 replication_state_.should_enforce_strict_mixed_content_checking =
219 should_enforce;
220}
221
alexmos6e940102016-01-19 22:47:25222void FrameTreeNode::SetPendingSandboxFlags(
223 blink::WebSandboxFlags sandbox_flags) {
224 pending_sandbox_flags_ = sandbox_flags;
225
226 // Subframes should always inherit their parent's sandbox flags.
227 if (parent())
228 pending_sandbox_flags_ |= parent()->effective_sandbox_flags();
229}
230
mlamouria85eb3f2015-01-26 17:36:27231bool FrameTreeNode::IsDescendantOf(FrameTreeNode* other) const {
232 if (!other || !other->child_count())
233 return false;
234
235 for (FrameTreeNode* node = parent(); node; node = node->parent()) {
236 if (node == other)
237 return true;
238 }
239
240 return false;
241}
242
alexmos9f8705a2015-05-06 19:58:59243FrameTreeNode* FrameTreeNode::PreviousSibling() const {
244 if (!parent_)
245 return nullptr;
246
247 for (size_t i = 0; i < parent_->child_count(); ++i) {
248 if (parent_->child_at(i) == this)
249 return (i == 0) ? nullptr : parent_->child_at(i - 1);
250 }
251
252 NOTREACHED() << "FrameTreeNode not found in its parent's children.";
253 return nullptr;
254}
255
fdegans4a49ce932015-03-12 17:11:37256bool FrameTreeNode::IsLoading() const {
257 RenderFrameHostImpl* current_frame_host =
258 render_manager_.current_frame_host();
259 RenderFrameHostImpl* pending_frame_host =
260 render_manager_.pending_frame_host();
261
262 DCHECK(current_frame_host);
fdegans39ff0382015-04-29 19:04:39263
carloskd80262f52015-12-16 14:40:35264 if (IsBrowserSideNavigationEnabled()) {
fdegans39ff0382015-04-29 19:04:39265 if (navigation_request_)
266 return true;
clamy11e11512015-07-07 16:42:17267
268 RenderFrameHostImpl* speculative_frame_host =
269 render_manager_.speculative_frame_host();
270 if (speculative_frame_host && speculative_frame_host->is_loading())
271 return true;
fdegans39ff0382015-04-29 19:04:39272 } else {
273 if (pending_frame_host && pending_frame_host->is_loading())
274 return true;
275 }
fdegans4a49ce932015-03-12 17:11:37276 return current_frame_host->is_loading();
277}
278
alexmos6b294562015-03-05 19:24:10279bool FrameTreeNode::CommitPendingSandboxFlags() {
280 bool did_change_flags =
alexmos6e940102016-01-19 22:47:25281 pending_sandbox_flags_ != replication_state_.sandbox_flags;
282 replication_state_.sandbox_flags = pending_sandbox_flags_;
alexmos6b294562015-03-05 19:24:10283 return did_change_flags;
284}
285
carloskc49005eb2015-06-16 11:25:07286void FrameTreeNode::CreatedNavigationRequest(
clamydcb434c12015-04-16 19:29:16287 scoped_ptr<NavigationRequest> navigation_request) {
carloskd80262f52015-12-16 14:40:35288 CHECK(IsBrowserSideNavigationEnabled());
clamy82a2f4d2016-02-02 14:20:41289
clamydb73eb6c2016-02-10 13:27:56290 bool was_previously_loading = frame_tree()->IsLoading();
291
clamy82a2f4d2016-02-02 14:20:41292 // There's no need to reset the state: there's still an ongoing load, and the
293 // RenderFrameHostManager will take care of updates to the speculative
294 // RenderFrameHost in DidCreateNavigationRequest below.
clamydb73eb6c2016-02-10 13:27:56295 if (was_previously_loading)
296 ResetNavigationRequest(true);
297
298 navigation_request_ = std::move(navigation_request);
299 render_manager()->DidCreateNavigationRequest(*navigation_request_);
fdegans39ff0382015-04-29 19:04:39300
301 // Force the throbber to start to keep it in sync with what is happening in
302 // the UI. Blink doesn't send throb notifications for JavaScript URLs, so it
303 // is not done here either.
clamydb73eb6c2016-02-10 13:27:56304 if (!navigation_request_->common_params().url.SchemeIs(
fdegans39ff0382015-04-29 19:04:39305 url::kJavaScriptScheme)) {
306 // TODO(fdegans): Check if this is a same-document navigation and set the
307 // proper argument.
clamydb73eb6c2016-02-10 13:27:56308 DidStartLoading(true, was_previously_loading);
fdegans39ff0382015-04-29 19:04:39309 }
clamydcb434c12015-04-16 19:29:16310}
311
clamy82a2f4d2016-02-02 14:20:41312void FrameTreeNode::ResetNavigationRequest(bool keep_state) {
carloskd80262f52015-12-16 14:40:35313 CHECK(IsBrowserSideNavigationEnabled());
fdegans39ff0382015-04-29 19:04:39314 if (!navigation_request_)
315 return;
clamydcb434c12015-04-16 19:29:16316 navigation_request_.reset();
fdegans39ff0382015-04-29 19:04:39317
clamy82a2f4d2016-02-02 14:20:41318 if (keep_state)
fdegans39ff0382015-04-29 19:04:39319 return;
320
clamy82a2f4d2016-02-02 14:20:41321 // The RenderFrameHostManager should clean up any speculative RenderFrameHost
322 // it created for the navigation. Also register that the load stopped.
fdegans39ff0382015-04-29 19:04:39323 DidStopLoading();
324 render_manager_.CleanUpNavigation();
clamydcb434c12015-04-16 19:29:16325}
326
fdegansa696e5112015-04-17 01:57:59327bool FrameTreeNode::has_started_loading() const {
328 return loading_progress_ != kLoadingProgressNotStarted;
329}
330
331void FrameTreeNode::reset_loading_progress() {
332 loading_progress_ = kLoadingProgressNotStarted;
333}
334
clamydb73eb6c2016-02-10 13:27:56335void FrameTreeNode::DidStartLoading(bool to_different_document,
336 bool was_previously_loading) {
fdegansa696e5112015-04-17 01:57:59337 // Any main frame load to a new document should reset the load progress since
338 // it will replace the current page and any frames. The WebContents will
339 // be notified when DidChangeLoadProgress is called.
340 if (to_different_document && IsMainFrame())
341 frame_tree_->ResetLoadProgress();
342
343 // Notify the WebContents.
clamydb73eb6c2016-02-10 13:27:56344 if (!was_previously_loading)
fdegansa696e5112015-04-17 01:57:59345 navigator()->GetDelegate()->DidStartLoading(this, to_different_document);
346
347 // Set initial load progress and update overall progress. This will notify
348 // the WebContents of the load progress change.
349 DidChangeLoadProgress(kLoadingProgressMinimum);
350
351 // Notify the RenderFrameHostManager of the event.
352 render_manager()->OnDidStartLoading();
353}
354
355void FrameTreeNode::DidStopLoading() {
356 // TODO(erikchen): Remove ScopedTracker below once crbug.com/465796 is fixed.
357 tracked_objects::ScopedTracker tracking_profile1(
358 FROM_HERE_WITH_EXPLICIT_FUNCTION(
359 "465796 FrameTreeNode::DidStopLoading::Start"));
360
361 // Set final load progress and update overall progress. This will notify
362 // the WebContents of the load progress change.
363 DidChangeLoadProgress(kLoadingProgressDone);
364
365 // TODO(erikchen): Remove ScopedTracker below once crbug.com/465796 is fixed.
366 tracked_objects::ScopedTracker tracking_profile2(
367 FROM_HERE_WITH_EXPLICIT_FUNCTION(
368 "465796 FrameTreeNode::DidStopLoading::WCIDidStopLoading"));
369
370 // Notify the WebContents.
371 if (!frame_tree_->IsLoading())
372 navigator()->GetDelegate()->DidStopLoading();
373
374 // TODO(erikchen): Remove ScopedTracker below once crbug.com/465796 is fixed.
375 tracked_objects::ScopedTracker tracking_profile3(
376 FROM_HERE_WITH_EXPLICIT_FUNCTION(
377 "465796 FrameTreeNode::DidStopLoading::RFHMDidStopLoading"));
378
379 // Notify the RenderFrameHostManager of the event.
380 render_manager()->OnDidStopLoading();
381
382 // TODO(erikchen): Remove ScopedTracker below once crbug.com/465796 is fixed.
383 tracked_objects::ScopedTracker tracking_profile4(
384 FROM_HERE_WITH_EXPLICIT_FUNCTION(
385 "465796 FrameTreeNode::DidStopLoading::End"));
386}
387
388void FrameTreeNode::DidChangeLoadProgress(double load_progress) {
389 loading_progress_ = load_progress;
390 frame_tree_->UpdateLoadProgress();
391}
392
clamyf73862c42015-07-08 12:31:33393bool FrameTreeNode::StopLoading() {
carloskd80262f52015-12-16 14:40:35394 if (IsBrowserSideNavigationEnabled())
clamyf73862c42015-07-08 12:31:33395 ResetNavigationRequest(false);
clamyf73862c42015-07-08 12:31:33396
397 // TODO(nasko): see if child frames should send IPCs in site-per-process
398 // mode.
399 if (!IsMainFrame())
400 return true;
401
402 render_manager_.Stop();
403 return true;
404}
405
alexmos21acae52015-11-07 01:04:43406void FrameTreeNode::DidFocus() {
407 last_focus_time_ = base::TimeTicks::Now();
408 FOR_EACH_OBSERVER(Observer, observers_, OnFrameTreeNodeFocused(this));
409}
410
clamydb73eb6c2016-02-10 13:27:56411void FrameTreeNode::BeforeUnloadCanceled() {
412 if (!IsMainFrame())
413 return;
414
415 RenderFrameHostImpl* current_frame_host =
416 render_manager_.current_frame_host();
417 DCHECK(current_frame_host);
418 current_frame_host->ResetLoadingState();
419
420 if (IsBrowserSideNavigationEnabled()) {
421 RenderFrameHostImpl* speculative_frame_host =
422 render_manager_.speculative_frame_host();
423 if (speculative_frame_host)
424 speculative_frame_host->ResetLoadingState();
425 } else {
426 RenderFrameHostImpl* pending_frame_host =
427 render_manager_.pending_frame_host();
428 if (pending_frame_host)
429 pending_frame_host->ResetLoadingState();
430 }
431}
432
[email protected]9b159a52013-10-03 17:24:55433} // namespace content