blob: 31c55aba3a486dbd459f3d64ae74fdea7d13e805 [file] [log] [blame]
Avi Drissman4e1b7bc32022-09-15 14:03:501// Copyright 2021 The Chromium Authors
Sreeja Kamishetty9e1d0e732021-05-27 18:20:092// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "content/browser/renderer_host/page_impl.h"
6
7#include "base/command_line.h"
Sreeja Kamishetty1b5c1432021-06-25 11:32:598#include "base/memory/weak_ptr.h"
Sreeja Kamishetty9e1d0e732021-05-27 18:20:099#include "base/test/scoped_feature_list.h"
John Abd-El-Malekea3ba3c2021-06-14 12:05:4810#include "build/build_config.h"
Sreeja Kamishetty9a095852021-06-04 17:26:3311#include "content/browser/renderer_host/frame_tree.h"
Sreeja Kamishetty9e1d0e732021-05-27 18:20:0912#include "content/browser/renderer_host/frame_tree_node.h"
13#include "content/browser/renderer_host/navigation_request.h"
14#include "content/browser/renderer_host/render_frame_host_impl.h"
15#include "content/browser/web_contents/web_contents_impl.h"
16#include "content/common/content_navigation_policy.h"
Sreeja Kamishetty1b5c1432021-06-25 11:32:5917#include "content/public/browser/page.h"
18#include "content/public/browser/page_user_data.h"
Sreeja Kamishetty9e1d0e732021-05-27 18:20:0919#include "content/public/browser/render_frame_host.h"
20#include "content/public/browser/web_contents.h"
21#include "content/public/common/content_features.h"
22#include "content/public/test/back_forward_cache_util.h"
23#include "content/public/test/browser_test.h"
24#include "content/public/test/browser_test_utils.h"
25#include "content/public/test/content_browser_test.h"
26#include "content/public/test/content_browser_test_utils.h"
Sreeja Kamishettya21b4f62021-06-25 07:48:2527#include "content/public/test/mock_web_contents_observer.h"
Dave Tapuska9c9afe82021-06-22 19:07:4528#include "content/public/test/prerender_test_util.h"
Sreeja Kamishetty9e1d0e732021-05-27 18:20:0929#include "content/public/test/render_frame_host_test_support.h"
Sreeja Kamishetty9a095852021-06-04 17:26:3330#include "content/public/test/test_navigation_observer.h"
Sreeja Kamishetty9e1d0e732021-05-27 18:20:0931#include "content/public/test/test_utils.h"
32#include "content/public/test/url_loader_interceptor.h"
33#include "content/shell/browser/shell.h"
34#include "content/test/content_browser_test_utils_internal.h"
35#include "net/dns/mock_host_resolver.h"
36#include "net/test/embedded_test_server/embedded_test_server.h"
37
38namespace content {
39
Sreeja Kamishetty1b5c1432021-06-25 11:32:5940namespace {
41
42int next_id = 0;
43
44// Example class which inherits the PageUserData, all the data is
45// associated to the lifetime of the page.
46class Data : public PageUserData<Data> {
47 public:
48 ~Data() override;
49
50 base::WeakPtr<Data> GetWeakPtr() { return weak_ptr_factory_.GetWeakPtr(); }
51
52 int unique_id() { return unique_id_; }
53
54 private:
55 explicit Data(Page& page) : PageUserData(page) { unique_id_ = ++next_id; }
56
57 friend class content::PageUserData<Data>;
58
59 int unique_id_;
60
61 base::WeakPtrFactory<Data> weak_ptr_factory_{this};
62
63 PAGE_USER_DATA_KEY_DECL();
64};
65
Daniel Cheng383df852021-10-02 03:28:0166PAGE_USER_DATA_KEY_IMPL(Data);
Sreeja Kamishetty1b5c1432021-06-25 11:32:5967
68Data::~Data() {
69 // Both Page and RenderFrameHost should be non-null and valid before Data
70 // deletion, as they will be destroyed after PageUserData destruction.
71 EXPECT_TRUE(&page());
72 EXPECT_TRUE(&(page().GetMainDocument()));
73}
74
75} // namespace
76
Sreeja Kamishetty9e1d0e732021-05-27 18:20:0977class PageImplTest : public ContentBrowserTest {
78 public:
79 ~PageImplTest() override = default;
80
81 protected:
82 void SetUpOnMainThread() override {
83 host_resolver()->AddRule("*", "127.0.0.1");
84 ContentBrowserTest::SetUpOnMainThread();
85 }
86
87 WebContentsImpl* web_contents() const {
88 return static_cast<WebContentsImpl*>(shell()->web_contents());
89 }
90
Dave Tapuska9c9afe82021-06-22 19:07:4591 RenderFrameHostImpl* primary_main_frame_host() {
Carlos Caballero15caeeb2021-10-27 09:57:5592 return web_contents()->GetPrimaryFrameTree().root()->current_frame_host();
Sreeja Kamishetty9e1d0e732021-05-27 18:20:0993 }
Sreeja Kamishetty1b5c1432021-06-25 11:32:5994
95 PageImpl& page() { return primary_main_frame_host()->GetPage(); }
96
97 Data* CreateOrGetDataForPage(Page& page) {
98 Data* data = Data::GetOrCreateForPage(page);
99 EXPECT_TRUE(data);
100 return data;
101 }
102
103 void EnsureEqualPageUserData(Data* data_a, Data* data_b) {
104 EXPECT_EQ(data_a->unique_id(), data_b->unique_id());
105 }
Sreeja Kamishetty9e1d0e732021-05-27 18:20:09106};
107
Dave Tapuska9c9afe82021-06-22 19:07:45108class PageImplPrerenderBrowserTest : public PageImplTest {
109 public:
110 PageImplPrerenderBrowserTest()
111 : prerender_helper_(
112 base::BindRepeating(&PageImplPrerenderBrowserTest::GetWebContents,
113 base::Unretained(this))) {}
114
Ian Vollick6bc0ee22021-08-04 23:36:26115 void SetUp() override {
Robert Lineb2a99c2023-08-24 02:42:26116 prerender_helper_.RegisterServerRequestMonitor(embedded_test_server());
Ian Vollick6bc0ee22021-08-04 23:36:26117 PageImplTest::SetUp();
Dave Tapuska9c9afe82021-06-22 19:07:45118 }
119
120 content::test::PrerenderTestHelper& prerender_test_helper() {
121 return prerender_helper_;
122 }
123
124 content::WebContents* GetWebContents() { return web_contents(); }
125
126 protected:
127 test::PrerenderTestHelper prerender_helper_;
128};
129
Sreeja Kamishetty1b5c1432021-06-25 11:32:59130// Test that Page and PageUserData objects are same for main RenderFrameHosts
131// and subframes which belong to the same Page.
Sreeja Kamishetty9e1d0e732021-05-27 18:20:09132IN_PROC_BROWSER_TEST_F(PageImplTest, AllFramesBelongToTheSamePage) {
133 ASSERT_TRUE(embedded_test_server()->Start());
Sreeja Kamishetty1b5c1432021-06-25 11:32:59134
Sreeja Kamishetty9e1d0e732021-05-27 18:20:09135 GURL url_a(embedded_test_server()->GetURL(
136 "a.com", "/cross_site_iframe_factory.html?a(b)"));
137
138 // 1) Navigate to a(b).
139 EXPECT_TRUE(NavigateToURL(shell(), url_a));
Dave Tapuska9c9afe82021-06-22 19:07:45140 RenderFrameHostImpl* rfh_a = primary_main_frame_host();
Sreeja Kamishetty9e1d0e732021-05-27 18:20:09141 RenderFrameHostImpl* rfh_b = rfh_a->child_at(0)->current_frame_host();
142
143 // 2) Check Page for RenderFrameHosts a and b, they both should point to same
144 // Page object.
Sreeja Kamishetty7c91ab22021-06-03 13:29:52145 PageImpl& page_a = rfh_a->GetPage();
146 PageImpl& page_b = rfh_b->GetPage();
147 EXPECT_EQ(&page_a, &page_b);
Dave Tapuska9c9afe82021-06-22 19:07:45148 EXPECT_TRUE(page_a.IsPrimary());
Sreeja Kamishetty1b5c1432021-06-25 11:32:59149
150 // 3) Check that PageUserData objects for both pages a and b have same
151 // unique_id's.
152 EnsureEqualPageUserData(CreateOrGetDataForPage(page_a),
153 CreateOrGetDataForPage(page_b));
154}
155
156// Test that Page and PageUserData objects are accessible inside
157// RenderFrameDeleted callback.
158IN_PROC_BROWSER_TEST_F(PageImplTest, RenderFrameHostDeleted) {
159 ASSERT_TRUE(embedded_test_server()->Start());
160 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
161 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
162
163 // 1) Navigate to A.
164 EXPECT_TRUE(NavigateToURL(shell(), url_a));
165 RenderFrameHostImpl* rfh_a = primary_main_frame_host();
166 PageImpl& page_a = rfh_a->GetPage();
167 base::WeakPtr<Data> data = CreateOrGetDataForPage(page_a)->GetWeakPtr();
168 RenderFrameDeletedObserver delete_rfh_a(rfh_a);
169
170 // 2) PageUserData associated with page_a should be valid when
171 // RenderFrameDeleted callback is invoked.
172 testing::NiceMock<MockWebContentsObserver> observer(shell()->web_contents());
173 EXPECT_CALL(observer, RenderFrameDeleted(testing::_))
174 .WillOnce(
175 testing::Invoke([data, rfh_a](RenderFrameHost* render_frame_host) {
176 // Both PageUserData and Page objects should be accessible before
177 // RenderFrameHost deletion.
178 EXPECT_EQ(rfh_a, render_frame_host);
179 DCHECK(&render_frame_host->GetPage());
180 EXPECT_TRUE(data);
181 }));
182
183 // Test needs rfh_a to be deleted after navigating but it doesn't happen with
184 // BackForwardCache as it is stored in cache.
185 DisableBackForwardCacheForTesting(web_contents(),
Rakina Zata Amni30af7062022-01-19 23:46:36186 BackForwardCache::TEST_REQUIRES_NO_CACHING);
Sreeja Kamishetty1b5c1432021-06-25 11:32:59187
188 // 3) Navigate to B, deleting rfh_a.
189 EXPECT_TRUE(NavigateToURL(shell(), url_b));
190 delete_rfh_a.WaitUntilDeleted();
191}
192
193// Test basic functionality of PageUserData.
194IN_PROC_BROWSER_TEST_F(PageImplTest, GetCreateAndDeleteUserDataForPage) {
195 ASSERT_TRUE(embedded_test_server()->Start());
196 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
197
198 // 1) Navigate to A.
199 EXPECT_TRUE(NavigateToURL(shell(), url_a));
200 PageImpl& page_a = page();
201
202 // 2) Get the Data associated with this Page. It should be null
203 // before creation.
204 Data* data = Data::GetForPage(page_a);
205 EXPECT_FALSE(data);
206
207 // 3) Create Data and check that GetForPage shouldn't return null
208 // now.
209 Data::CreateForPage(page_a);
210 base::WeakPtr<Data> created_data = Data::GetForPage(page_a)->GetWeakPtr();
211 EXPECT_TRUE(created_data);
212
213 // 4) Delete Data and check that GetForPage should return null.
214 Data::DeleteForPage(page_a);
215 EXPECT_FALSE(created_data);
216 EXPECT_FALSE(Data::GetForPage(page_a));
217}
218
219// Test GetOrCreateForPage API of PageUserData.
220IN_PROC_BROWSER_TEST_F(PageImplTest, GetOrCreateForPage) {
221 ASSERT_TRUE(embedded_test_server()->Start());
222 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
223
224 // 1) Navigate to A.
225 EXPECT_TRUE(NavigateToURL(shell(), url_a));
226 PageImpl& page_a = page();
227
228 // 2) Get the Data associated with this RenderFrameHost. It should be null
229 // before creation.
230 Data* data = Data::GetForPage(page_a);
231 EXPECT_FALSE(data);
232
233 // 3) |GetOrCreateForPage| should create Data.
234 base::WeakPtr<Data> created_data =
235 Data::GetOrCreateForPage(page_a)->GetWeakPtr();
236 EXPECT_TRUE(created_data);
237
238 // 4) Another call to |GetOrCreateForPage| should not create the
239 // new data and the previous data created in 3) should be preserved.
240 Data* new_created_data = Data::GetOrCreateForPage(page_a);
241 EXPECT_TRUE(created_data);
242 EnsureEqualPageUserData(created_data.get(), new_created_data);
Sreeja Kamishetty9e1d0e732021-05-27 18:20:09243}
244
Sreeja Kamishetty9a095852021-06-04 17:26:33245// Test that the Page object doesn't change for new subframe RFHs after
246// subframes does a cross-site or same-site navigation.
247//
248// 1) Navigate to A(A1, B).
249// 2) Navigate cross site A1 to C.
250// 3) Navigate same site B to B2.
251IN_PROC_BROWSER_TEST_F(PageImplTest, PageObjectAfterSubframeNavigation) {
252 ASSERT_TRUE(embedded_test_server()->Start());
253
254 // 1) Navigate to A1(A2, B).
255 GURL main_url(embedded_test_server()->GetURL(
256 "a.com", "/cross_site_iframe_factory.html?a(a,b)"));
257 EXPECT_TRUE(NavigateToURL(shell(), main_url));
Dave Tapuska9c9afe82021-06-22 19:07:45258 RenderFrameHostImpl* rfh_a = primary_main_frame_host();
Sreeja Kamishetty9a095852021-06-04 17:26:33259 RenderFrameHostImpl* rfh_a2 = rfh_a->child_at(0)->current_frame_host();
260 RenderFrameHostImpl* rfh_b = rfh_a->child_at(1)->current_frame_host();
261
262 // It is safe to obtain the root frame tree node here, as it doesn't change.
Carlos Caballero15caeeb2021-10-27 09:57:55263 FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
Sreeja Kamishetty9a095852021-06-04 17:26:33264
265 // 2) Check that Page for A1, A2, B point to same object.
266 PageImpl& page_a = rfh_a->GetPage();
267 PageImpl& page_a2 = rfh_a2->GetPage();
268 PageImpl& page_b = rfh_b->GetPage();
269 EXPECT_EQ(&page_a, &page_a2);
270 EXPECT_EQ(&page_a2, &page_b);
271
272 // 3) Navigate subframe cross-site from A2 -> C.
273 GURL url_c = embedded_test_server()->GetURL("c.com", "/title1.html");
274 EXPECT_TRUE(NavigateToURLFromRenderer(root->child_at(0), url_c));
275
276 // 4) Page object of new subframe C should be same as page_a.
277 RenderFrameHostImpl* rfh_c = rfh_a->child_at(0)->current_frame_host();
278 PageImpl& page_c = rfh_c->GetPage();
279 EXPECT_EQ(&page_c, &page_a);
280
281 // 5) Navigate subframe same-site from B -> B2.
282 GURL url_b = embedded_test_server()->GetURL("b.com", "/title2.html");
283 EXPECT_TRUE(NavigateToURLFromRenderer(root->child_at(1), url_b));
284
285 // 6) Page object of new subframe B2 should be same as page_a.
286 RenderFrameHostImpl* rfh_b2 = rfh_a->child_at(1)->current_frame_host();
287 PageImpl& page_b2 = rfh_b2->GetPage();
288 EXPECT_EQ(&page_b2, &page_a);
289}
290
Sreeja Kamishetty1b5c1432021-06-25 11:32:59291// Test that Page and PageUserData object remains the same for pending page
292// before and after commit.
Sreeja Kamishetty9a095852021-06-04 17:26:33293IN_PROC_BROWSER_TEST_F(PageImplTest, PageObjectBeforeAndAfterCommit) {
294 ASSERT_TRUE(embedded_test_server()->Start());
295 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
296 GURL url_b(embedded_test_server()->GetURL("b.com", "/title2.html"));
297
298 // Isolate "b.com" so we are guaranteed to get a different process
299 // for navigations to this origin on Android. Doing this ensures that a
300 // speculative RenderFrameHost is used.
301 IsolateOriginsForTesting(embedded_test_server(), shell()->web_contents(),
302 {"b.com"});
303
304 // 1) Navigate to A.
305 EXPECT_TRUE(NavigateToURL(shell(), url_a));
Dave Tapuska9c9afe82021-06-22 19:07:45306 RenderFrameHostImpl* rfh_a = primary_main_frame_host();
Sreeja Kamishetty9a095852021-06-04 17:26:33307 PageImpl& page_a = rfh_a->GetPage();
Sreeja Kamishetty1b5c1432021-06-25 11:32:59308 base::WeakPtr<Data> data_a = CreateOrGetDataForPage(page_a)->GetWeakPtr();
Sreeja Kamishetty9a095852021-06-04 17:26:33309
310 // 2) Start navigation to B, but don't commit yet.
311 TestNavigationManager manager(shell()->web_contents(), url_b);
312 shell()->LoadURL(url_b);
Jiacheng Guo4bdd0be2024-06-11 23:35:21313 manager.WaitForSpeculativeRenderFrameHostCreation();
Sreeja Kamishetty9a095852021-06-04 17:26:33314
Carlos Caballero15caeeb2021-10-27 09:57:55315 FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
Sreeja Kamishetty9a095852021-06-04 17:26:33316 RenderFrameHostImpl* pending_rfh =
317 root->render_manager()->speculative_frame_host();
318 NavigationRequest* navigation_request = root->navigation_request();
Rakina Zata Amni8d4ed052022-12-07 23:03:30319 EXPECT_EQ(navigation_request->GetAssociatedRFHType(),
Rakina Zata Amni7af54b12022-06-28 10:36:17320 NavigationRequest::AssociatedRenderFrameHostType::SPECULATIVE);
Sreeja Kamishetty9a095852021-06-04 17:26:33321 EXPECT_TRUE(pending_rfh);
322
323 // 3) While there is a speculative RenderFrameHost in the root FrameTreeNode,
Sreeja Kamishetty1b5c1432021-06-25 11:32:59324 // get the Page associated with this RenderFrameHost and PageUserData
325 // associated with this Page.
Sreeja Kamishetty9a095852021-06-04 17:26:33326 PageImpl& pending_rfh_page = pending_rfh->GetPage();
327 EXPECT_NE(&pending_rfh_page, &page_a);
Dave Tapuska9c9afe82021-06-22 19:07:45328 EXPECT_TRUE(page_a.IsPrimary());
329 EXPECT_FALSE(pending_rfh_page.IsPrimary());
Sreeja Kamishetty1b5c1432021-06-25 11:32:59330 base::WeakPtr<Data> data_before_commit =
331 CreateOrGetDataForPage(pending_rfh_page)->GetWeakPtr();
332 EXPECT_NE(data_before_commit.get()->unique_id(), data_a.get()->unique_id());
Sreeja Kamishetty9a095852021-06-04 17:26:33333
334 // 4) Let the navigation finish and make sure it has succeeded.
Fergal Daly105305ad2023-01-16 08:21:52335 ASSERT_TRUE(manager.WaitForNavigationFinished());
Dave Tapuska327c06c92022-06-13 20:31:51336 EXPECT_EQ(url_b,
337 web_contents()->GetPrimaryMainFrame()->GetLastCommittedURL());
Sreeja Kamishetty9a095852021-06-04 17:26:33338
Dave Tapuska9c9afe82021-06-22 19:07:45339 RenderFrameHostImpl* rfh_b = primary_main_frame_host();
Sreeja Kamishetty9a095852021-06-04 17:26:33340 EXPECT_EQ(pending_rfh, rfh_b);
341 PageImpl& rfh_b_page = rfh_b->GetPage();
342
343 // 5) Check |pending_rfh_page| and |rfh_b_page| point to the same object.
344 EXPECT_EQ(&pending_rfh_page, &rfh_b_page);
Dave Tapuska9c9afe82021-06-22 19:07:45345 EXPECT_TRUE(rfh_b_page.IsPrimary());
Sreeja Kamishetty9a095852021-06-04 17:26:33346}
347
Sreeja Kamishetty53468972021-07-13 11:53:32348// Test that WebContentsObserver::PrimaryPageChanged is invoked on primary page
349// changes after page related data is updated e.g. LastCommittedURL.
Sreeja Kamishettya21b4f62021-06-25 07:48:25350IN_PROC_BROWSER_TEST_F(PageImplTest, PrimaryPageChangedOnCrossSiteNavigation) {
351 ASSERT_TRUE(embedded_test_server()->Start());
352 GURL url_a(embedded_test_server()->GetURL(
Sreeja Kamishetty53468972021-07-13 11:53:32353 "a.com", "/cross_site_iframe_factory.html?a(b, c)"));
354 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
Sreeja Kamishettya21b4f62021-06-25 07:48:25355
356 // 1) Navigate to A.
357 EXPECT_TRUE(NavigateToURL(shell(), url_a));
Sreeja Kamishetty53468972021-07-13 11:53:32358 Page* invoked_page;
359 GURL last_committed_url;
Sreeja Kamishetty799a0ca2021-12-10 10:43:02360 int http_status_code;
Sreeja Kamishettya21b4f62021-06-25 07:48:25361
Sreeja Kamishetty53468972021-07-13 11:53:32362 // 2) Invoke MockWebContentsObserver to check the values inside
363 // PrimaryPageChanged(Page&) match the ones inside
364 // DidFinishNavigation(NavigationHandle*).
365 WebContents* contents = web_contents();
366 testing::NiceMock<MockWebContentsObserver> web_contents_observer(contents);
367 testing::InSequence s;
368
369 {
370 // 3) Stores the values of page invoked on PrimaryPageChanged and
Sreeja Kamishetty799a0ca2021-12-10 10:43:02371 // LastCommittedUrl, HttpStatusCode to match with ones inside
372 // DidFinishNavigation and page after navigation.
Sreeja Kamishetty53468972021-07-13 11:53:32373 EXPECT_CALL(web_contents_observer, PrimaryPageChanged(testing::_))
Sreeja Kamishetty799a0ca2021-12-10 10:43:02374 .WillOnce(testing::Invoke([&invoked_page, &last_committed_url,
375 &http_status_code, url_b, this](Page& page) {
376 invoked_page = &page;
377 last_committed_url = page.GetMainDocument().GetLastCommittedURL();
378 http_status_code = web_contents()
379 ->GetController()
380 .GetVisibleEntry()
381 ->GetHttpStatusCode();
382 EXPECT_EQ(last_committed_url, url_b);
383 EXPECT_TRUE(page.IsPrimary());
384 EXPECT_EQ(&web_contents()->GetPrimaryPage(), &page);
385 }));
Sreeja Kamishetty53468972021-07-13 11:53:32386
387 EXPECT_CALL(web_contents_observer, DidFinishNavigation(testing::_))
Sreeja Kamishetty799a0ca2021-12-10 10:43:02388 .WillOnce(testing::Invoke([&last_committed_url, &http_status_code](
389 NavigationHandle* navigation_handle) {
390 EXPECT_EQ(navigation_handle->GetURL(), last_committed_url);
391 EXPECT_EQ(http_status_code, navigation_handle->GetWebContents()
392 ->GetController()
393 .GetVisibleEntry()
394 ->GetHttpStatusCode());
395 }));
Sreeja Kamishetty53468972021-07-13 11:53:32396 }
397
398 // 4) Navigate to B. PrimaryPageChanged and DidFinishNavigation should be
399 // triggered for new `page_b` and should match `invoked_page`.
Sreeja Kamishettya21b4f62021-06-25 07:48:25400 EXPECT_TRUE(NavigateToURL(shell(), url_b));
Sreeja Kamishetty53468972021-07-13 11:53:32401 RenderFrameHostImpl* rfh_b = primary_main_frame_host();
402 PageImpl& page_b = rfh_b->GetPage();
403 EXPECT_EQ(&page_b, invoked_page);
Sreeja Kamishettya21b4f62021-06-25 07:48:25404}
405
Sreeja Kamishetty9a095852021-06-04 17:26:33406// Test that a new Page object is created for a same-site same-RFH navigation.
Dominique Fauteux-Chapleau3e8d3452021-07-14 17:20:02407IN_PROC_BROWSER_TEST_F(PageImplTest, SameSiteSameRenderFrameHostNavigation) {
Sreeja Kamishetty9a095852021-06-04 17:26:33408 ASSERT_TRUE(embedded_test_server()->Start());
409 GURL url_a1(embedded_test_server()->GetURL("a.com", "/title1.html"));
410 GURL url_a2(embedded_test_server()->GetURL("a.com", "/title2.html"));
411
412 // 1) Navigate to A1.
413 EXPECT_TRUE(NavigateToURL(shell(), url_a1));
Dominique Fauteux-Chapleau3e8d3452021-07-14 17:20:02414 RenderFrameHostImplWrapper main_rfh_a1(primary_main_frame_host());
Daniel Chengbafeee42021-09-27 23:27:57415 base::WeakPtr<Page> page_a1 = main_rfh_a1->GetPage().GetWeakPtr();
Sreeja Kamishettya21b4f62021-06-25 07:48:25416 testing::NiceMock<MockWebContentsObserver> page_changed_observer(
417 web_contents());
Daniel Chengbafeee42021-09-27 23:27:57418 base::WeakPtr<Data> data = CreateOrGetDataForPage(*page_a1)->GetWeakPtr();
Sreeja Kamishetty9a095852021-06-04 17:26:33419
Dominique Fauteux-Chapleau3e8d3452021-07-14 17:20:02420 // 2) Navigate to A2. This will result in invoking PrimaryPageChanged
421 // callback.
Sreeja Kamishetty53468972021-07-13 11:53:32422 EXPECT_CALL(page_changed_observer, PrimaryPageChanged(testing::_)).Times(1);
Sreeja Kamishetty9a095852021-06-04 17:26:33423 EXPECT_TRUE(NavigateToURL(shell(), url_a2));
Dominique Fauteux-Chapleau3e8d3452021-07-14 17:20:02424 RenderFrameHostImplWrapper main_rfh_a2(primary_main_frame_host());
425 EXPECT_EQ(CanSameSiteMainFrameNavigationsChangeRenderFrameHosts(),
426 main_rfh_a1.get() != main_rfh_a2.get());
427 PageImpl& page_a2 = main_rfh_a2.get()->GetPage();
Sreeja Kamishetty9a095852021-06-04 17:26:33428
Mingyu Leif208fa22022-09-08 04:10:49429 if (IsBackForwardCacheEnabled()) {
430 // 3a) With back/forward cache enabled, both Page objects should be in
Daniel Chengbafeee42021-09-27 23:27:57431 // existence at the same time.
432 EXPECT_TRUE(page_a1);
433 EXPECT_NE(page_a1.get(), &page_a2);
434 // And the user data associated with the page (now in bfcache) should also
435 // still be alive.
436 EXPECT_TRUE(data);
437 } else {
438 // 3b) Otherwise, check that the old Page object was destroyed. There is no
439 // other way to validate that the old Page and new Page are different:
440 // comparing pointer values is not a stable test, since the new Page could
441 // be reallocated at the same address.
442 EXPECT_FALSE(page_a1);
443 // Similarly, expect any PageUserData from the old Page to be gone.
Dominique Fauteux-Chapleau3e8d3452021-07-14 17:20:02444 EXPECT_FALSE(data);
Daniel Chengbafeee42021-09-27 23:27:57445 }
Sreeja Kamishetty9a095852021-06-04 17:26:33446}
447
448// Test that a new Page object is created when RenderFrame is recreated after
449// crash.
450IN_PROC_BROWSER_TEST_F(PageImplTest, NewPageObjectCreatedOnFrameCrash) {
451 ASSERT_TRUE(embedded_test_server()->Start());
452 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
453
454 // 1) Navigate to A.
455 EXPECT_TRUE(NavigateToURL(shell(), url_a));
Dave Tapuska9c9afe82021-06-22 19:07:45456 RenderFrameHostImpl* rfh_a = primary_main_frame_host();
Daniel Chengbafeee42021-09-27 23:27:57457 base::WeakPtr<Page> page_a = rfh_a->GetPage().GetWeakPtr();
Sreeja Kamishettya21b4f62021-06-25 07:48:25458 testing::NiceMock<MockWebContentsObserver> page_changed_observer(
459 web_contents());
Daniel Chengbafeee42021-09-27 23:27:57460 base::WeakPtr<Data> data = CreateOrGetDataForPage(*page_a)->GetWeakPtr();
Sreeja Kamishetty9a095852021-06-04 17:26:33461
Sreeja Kamishetty1b5c1432021-06-25 11:32:59462 // 2) Make the renderer crash this should not reset the Page or delete the
463 // PageUserData.
Sreeja Kamishetty9a095852021-06-04 17:26:33464 RenderProcessHost* renderer_process = rfh_a->GetProcess();
465 RenderProcessHostWatcher crash_observer(
466 renderer_process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
467 renderer_process->Shutdown(0);
468 crash_observer.Wait();
469 EXPECT_TRUE(&(rfh_a->GetPage()));
Sreeja Kamishetty1b5c1432021-06-25 11:32:59470 EXPECT_TRUE(data);
Sreeja Kamishetty9a095852021-06-04 17:26:33471
Sreeja Kamishettya21b4f62021-06-25 07:48:25472 // 3) Re-initialize RenderFrame, this should result in invoking
473 // PrimaryPageChanged callback.
Sreeja Kamishetty53468972021-07-13 11:53:32474 EXPECT_CALL(page_changed_observer, PrimaryPageChanged(testing::_)).Times(1);
Carlos Caballero15caeeb2021-10-27 09:57:55475 FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
Sreeja Kamishetty9a095852021-06-04 17:26:33476 root->render_manager()->InitializeMainRenderFrameForImmediateUse();
Sreeja Kamishetty9a095852021-06-04 17:26:33477
Daniel Chengbafeee42021-09-27 23:27:57478 // 4) Check that the old Page object was destroyed. There is no other way to
479 // validate that the old Page and new Page are different: comparing pointer
480 // values is not a stable test, since the new Page could be reallocated at the
481 // same address.
482 EXPECT_FALSE(page_a);
483 // Similarly, expect any PageUserData from the old Page to be gone.
Sreeja Kamishetty1b5c1432021-06-25 11:32:59484 EXPECT_FALSE(data);
Sreeja Kamishetty9a095852021-06-04 17:26:33485}
486
487// Test that a new Page object is created when we do a same-site navigation
488// after renderer crashes.
489IN_PROC_BROWSER_TEST_F(PageImplTest, SameSiteNavigationAfterFrameCrash) {
490 ASSERT_TRUE(embedded_test_server()->Start());
491 GURL url_a1(embedded_test_server()->GetURL("a.com", "/title1.html"));
492 GURL url_a2(embedded_test_server()->GetURL("a.com", "/title2.html"));
493
494 // 1) Navigate to A1.
495 EXPECT_TRUE(NavigateToURL(shell(), url_a1));
Dave Tapuska9c9afe82021-06-22 19:07:45496 RenderFrameHostImpl* rfh_a1 = primary_main_frame_host();
Daniel Chengbafeee42021-09-27 23:27:57497 base::WeakPtr<Page> page_a1 = rfh_a1->GetPage().GetWeakPtr();
Sreeja Kamishettya21b4f62021-06-25 07:48:25498 testing::NiceMock<MockWebContentsObserver> page_changed_observer(
499 web_contents());
Daniel Chengbafeee42021-09-27 23:27:57500 base::WeakPtr<Data> data = CreateOrGetDataForPage(*page_a1)->GetWeakPtr();
Sreeja Kamishetty9a095852021-06-04 17:26:33501
Sreeja Kamishetty1b5c1432021-06-25 11:32:59502 // 2) Crash the renderer hosting current RFH. This should not reset the Page
503 // or delete the PageUserData.
Sreeja Kamishetty9a095852021-06-04 17:26:33504 RenderProcessHost* renderer_process = rfh_a1->GetProcess();
505 RenderProcessHostWatcher crash_observer(
506 renderer_process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
507 renderer_process->Shutdown(0);
508 crash_observer.Wait();
Dave Tapuska327c06c92022-06-13 20:31:51509 EXPECT_TRUE(&(web_contents()->GetPrimaryMainFrame()->GetPage()));
Sreeja Kamishetty1b5c1432021-06-25 11:32:59510 EXPECT_TRUE(data);
Sreeja Kamishetty9a095852021-06-04 17:26:33511
Sreeja Kamishettya21b4f62021-06-25 07:48:25512 // 3) Navigate same-site to A2. This will result in invoking
513 // PrimaryPageChanged callback after new Page creation.
Sreeja Kamishetty53468972021-07-13 11:53:32514 EXPECT_CALL(page_changed_observer, PrimaryPageChanged(testing::_)).Times(1);
Sreeja Kamishetty9a095852021-06-04 17:26:33515 EXPECT_TRUE(NavigateToURL(shell(), url_a2));
Sreeja Kamishetty9a095852021-06-04 17:26:33516
Daniel Chengbafeee42021-09-27 23:27:57517 // 4) Check that the old Page object was destroyed. There is no other way to
518 // validate that the old Page and new Page are different: comparing pointer
519 // values is not a stable test, since the new Page could be reallocated at the
520 // same address.
521 EXPECT_FALSE(page_a1);
522 // Similarly, expect any PageUserData from the old Page to be gone.
Sreeja Kamishetty1b5c1432021-06-25 11:32:59523 EXPECT_FALSE(data);
Sreeja Kamishetty9a095852021-06-04 17:26:33524}
525
526// Test PageImpl with BackForwardCache feature enabled.
527class PageImplWithBackForwardCacheTest : public PageImplTest {
528 public:
529 PageImplWithBackForwardCacheTest() {
530 scoped_feature_list_.InitWithFeaturesAndParameters(
Ming-Ying Chung72636182023-02-28 12:16:04531 GetDefaultEnabledBackForwardCacheFeaturesForTesting(
532 /*ignore_outstanding_network_request=*/false),
533 GetDefaultDisabledBackForwardCacheFeaturesForTesting());
Sreeja Kamishetty9a095852021-06-04 17:26:33534 }
535
536 private:
537 base::test::ScopedFeatureList scoped_feature_list_;
538};
539
540// Tests that PageImpl object is not cleared on storing and restoring a Page
541// from back-forward cache.
542IN_PROC_BROWSER_TEST_F(PageImplWithBackForwardCacheTest,
543 BackForwardCacheNavigation) {
544 ASSERT_TRUE(embedded_test_server()->Start());
545 GURL url_a(embedded_test_server()->GetURL(
546 "a.com", "/cross_site_iframe_factory.html?a(b)"));
547 GURL url_c(embedded_test_server()->GetURL("c.com", "/title1.html"));
548
549 // 1) Navigate to A(B).
550 EXPECT_TRUE(NavigateToURL(shell(), url_a));
Dave Tapuska9c9afe82021-06-22 19:07:45551 RenderFrameHostImpl* rfh_a = primary_main_frame_host();
Sreeja Kamishetty9a095852021-06-04 17:26:33552 RenderFrameHostImpl* rfh_b = rfh_a->child_at(0)->current_frame_host();
Sreeja Kamishettya21b4f62021-06-25 07:48:25553 testing::NiceMock<MockWebContentsObserver> page_changed_observer(
554 web_contents());
Sreeja Kamishetty9a095852021-06-04 17:26:33555
556 // 2) Get the PageImpl object associated with A and B RenderFrameHost.
557 PageImpl& page_a = rfh_a->GetPage();
558 PageImpl& page_b = rfh_b->GetPage();
Sreeja Kamishetty1b5c1432021-06-25 11:32:59559 Data* data = CreateOrGetDataForPage(page_a);
Sreeja Kamishetty9a095852021-06-04 17:26:33560
Sreeja Kamishettya21b4f62021-06-25 07:48:25561 // 3) Navigate to C. PrimaryPageChanged should be triggered as A(B) is stored
562 // in BackForwardCache.
Sreeja Kamishetty53468972021-07-13 11:53:32563 EXPECT_CALL(page_changed_observer, PrimaryPageChanged(testing::_)).Times(1);
Sreeja Kamishetty9a095852021-06-04 17:26:33564 EXPECT_TRUE(NavigateToURL(shell(), url_c));
565 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
566 EXPECT_TRUE(rfh_b->IsInBackForwardCache());
Dave Tapuska9c9afe82021-06-22 19:07:45567 EXPECT_FALSE(page_a.IsPrimary());
568 EXPECT_FALSE(page_b.IsPrimary());
Sreeja Kamishetty9a095852021-06-04 17:26:33569
Sreeja Kamishetty1b5c1432021-06-25 11:32:59570 // 4) PageImpl associated with document should point to the same object.
571 // PageUserData should not be deleted on navigating away with
572 // BackForwardCache.
Sreeja Kamishetty9a095852021-06-04 17:26:33573 EXPECT_EQ(&page_a, &(rfh_a->GetPage()));
574 EXPECT_EQ(&page_b, &(rfh_b->GetPage()));
Sreeja Kamishetty1b5c1432021-06-25 11:32:59575 EXPECT_TRUE(data);
Sreeja Kamishetty9a095852021-06-04 17:26:33576
577 // 5) Go back to A(B) and the Page object before and after restore should
Sreeja Kamishettya21b4f62021-06-25 07:48:25578 // point to the same object. PrimaryPageChanged should still be triggered when
579 // primary page changes to the existing page restored from the
Sreeja Kamishetty1b5c1432021-06-25 11:32:59580 // BackForwardCache point to the same object and PageUserData should not be
581 // deleted.
Sreeja Kamishetty53468972021-07-13 11:53:32582 EXPECT_CALL(page_changed_observer, PrimaryPageChanged(testing::_)).Times(1);
Sreeja Kamishetty9a095852021-06-04 17:26:33583 web_contents()->GetController().GoBack();
584 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
585 EXPECT_EQ(&page_a, &(rfh_a->GetPage()));
586 EXPECT_EQ(&page_b, &(rfh_b->GetPage()));
Dave Tapuska9c9afe82021-06-22 19:07:45587 EXPECT_TRUE(page_a.IsPrimary());
588 EXPECT_TRUE(page_b.IsPrimary());
Sreeja Kamishetty1b5c1432021-06-25 11:32:59589 EXPECT_TRUE(data);
Dave Tapuska9c9afe82021-06-22 19:07:45590}
591
592// Tests that PageImpl object is correct for IsPrimary.
593IN_PROC_BROWSER_TEST_F(PageImplPrerenderBrowserTest, IsPrimary) {
594 ASSERT_TRUE(embedded_test_server()->Start());
595
596 // Navigate to a site.
597 GURL url_a = embedded_test_server()->GetURL("/empty.html");
598 EXPECT_TRUE(NavigateToURL(shell(), url_a));
599 RenderFrameHostImpl* rfh_a = primary_main_frame_host();
600 EXPECT_TRUE(rfh_a->GetPage().IsPrimary());
Sreeja Kamishettya21b4f62021-06-25 07:48:25601 testing::NiceMock<MockWebContentsObserver> page_changed_observer(
602 web_contents());
Dave Tapuska9c9afe82021-06-22 19:07:45603
604 // Prerender to another site.
605 GURL prerender_url = embedded_test_server()->GetURL("/title2.html");
606 prerender_helper_.AddPrerender(prerender_url);
Avi Drissman580a3da62024-09-04 16:16:56607 FrameTreeNodeId host_id =
608 prerender_test_helper().GetHostForUrl(prerender_url);
Dave Tapuska9c9afe82021-06-22 19:07:45609 content::test::PrerenderHostObserver host_observer(*web_contents(), host_id);
610 content::RenderFrameHost* prerender_frame =
611 prerender_test_helper().GetPrerenderedMainFrameHost(host_id);
612 Page& prerender_page = prerender_frame->GetPage();
613 EXPECT_FALSE(prerender_page.IsPrimary());
614
Sreeja Kamishettya21b4f62021-06-25 07:48:25615 // Navigate to the prerendered site. PrimaryPageChanged should only be
616 // triggered on activation.
Sreeja Kamishetty53468972021-07-13 11:53:32617 EXPECT_CALL(page_changed_observer, PrimaryPageChanged(testing::_)).Times(1);
Dave Tapuska9c9afe82021-06-22 19:07:45618 prerender_helper_.NavigatePrimaryPage(prerender_url);
619 EXPECT_TRUE(host_observer.was_activated());
620 EXPECT_EQ(&prerender_page, &(primary_main_frame_host()->GetPage()));
621 EXPECT_TRUE(prerender_page.IsPrimary());
622}
623
624// Tests that IsPrimary returns false when pending deletion.
625IN_PROC_BROWSER_TEST_F(PageImplPrerenderBrowserTest, IsPrimaryPendingDeletion) {
626 ASSERT_TRUE(embedded_test_server()->Start());
627
628 GURL url_a(embedded_test_server()->GetURL(
629 "a.com", "/cross_site_iframe_factory.html?a(b)"));
630 GURL url_d(embedded_test_server()->GetURL("d.com", "/title1.html"));
631
632 EXPECT_TRUE(NavigateToURL(shell(), url_a));
633 RenderFrameHostImpl* rfh_a = primary_main_frame_host();
634 RenderFrameHostImpl* rfh_b = rfh_a->child_at(0)->current_frame_host();
635 EXPECT_TRUE(rfh_a->GetPage().IsPrimary());
636 EXPECT_TRUE(rfh_b->GetPage().IsPrimary());
637 LeaveInPendingDeletionState(rfh_a);
638 LeaveInPendingDeletionState(rfh_b);
639
640 EXPECT_TRUE(NavigateToURL(shell(), url_d));
641
642 EXPECT_FALSE(rfh_a->GetPage().IsPrimary());
643 EXPECT_FALSE(rfh_b->GetPage().IsPrimary());
Sreeja Kamishetty9a095852021-06-04 17:26:33644}
645
Sreeja Kamishetty9e1d0e732021-05-27 18:20:09646} // namespace content