[M120 Migration]Fix for crash during chrome exit
[platform/framework/web/chromium-efl.git] / chrome / browser / chrome_back_forward_cache_browsertest.cc
1 // Copyright 2019 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "base/command_line.h"
6 #include "base/functional/callback.h"
7 #include "base/test/bind.h"
8 #include "base/test/mock_callback.h"
9 #include "base/test/scoped_feature_list.h"
10 #include "base/test/scoped_logging_settings.h"
11 #include "build/build_config.h"
12 #include "build/chromeos_buildflags.h"
13 #include "chrome/browser/content_settings/host_content_settings_map_factory.h"
14 #include "chrome/browser/content_settings/mixed_content_settings_tab_helper.h"
15 #include "chrome/browser/pdf/pdf_extension_test_util.h"
16 #include "chrome/browser/profiles/profile.h"
17 #include "chrome/browser/task_manager/task_manager_tester.h"
18 #include "chrome/browser/ui/browser.h"
19 #include "chrome/browser/ui/browser_content_setting_bubble_model_delegate.h"
20 #include "chrome/browser/ui/content_settings/content_setting_bubble_model.h"
21 #include "chrome/browser/ui/tabs/tab_strip_model.h"
22 #include "chrome/grit/generated_resources.h"
23 #include "chrome/test/base/in_process_browser_test.h"
24 #include "chrome/test/base/ui_test_utils.h"
25 #include "components/content_settings/core/browser/host_content_settings_map.h"
26 #include "components/content_settings/core/common/content_settings.h"
27 #include "components/content_settings/core/common/content_settings_types.h"
28 #include "components/metrics/content/subprocess_metrics_provider.h"
29 #include "components/network_session_configurator/common/network_switches.h"
30 #include "components/page_load_metrics/browser/observers/core/uma_page_load_metrics_observer.h"
31 #include "components/permissions/permission_manager.h"
32 #include "content/public/browser/permission_controller.h"
33 #include "content/public/browser/permission_request_description.h"
34 #include "content/public/browser/render_process_host.h"
35 #include "content/public/common/content_features.h"
36 #include "content/public/common/content_switches.h"
37 #include "content/public/test/back_forward_cache_util.h"
38 #include "content/public/test/browser_test.h"
39 #include "content/public/test/browser_test_utils.h"
40 #include "content/public/test/test_navigation_observer.h"
41 #include "content/public/test/test_utils.h"
42 #include "net/dns/mock_host_resolver.h"
43 #include "net/test/embedded_test_server/embedded_test_server.h"
44 #include "pdf/buildflags.h"
45 #include "third_party/blink/public/common/permissions/permission_utils.h"
46 #include "third_party/blink/public/common/scheduler/web_scheduler_tracked_feature.h"
47 #include "third_party/blink/public/mojom/webshare/webshare.mojom.h"
48 #include "ui/base/l10n/l10n_util.h"
49
50 class ChromeBackForwardCacheBrowserTest : public InProcessBrowserTest {
51  public:
52   ChromeBackForwardCacheBrowserTest() = default;
53
54   ChromeBackForwardCacheBrowserTest(const ChromeBackForwardCacheBrowserTest&) =
55       delete;
56   ChromeBackForwardCacheBrowserTest& operator=(
57       const ChromeBackForwardCacheBrowserTest&) = delete;
58
59   ~ChromeBackForwardCacheBrowserTest() override = default;
60
61   void SetUpOnMainThread() override {
62     host_resolver()->AddRule("*", "127.0.0.1");
63     histogram_tester_ = std::make_unique<base::HistogramTester>();
64   }
65
66   // At the chrome layer, an outstanding request to /favicon.ico is made. It is
67   // made by the renderer on behalf of the browser process. It counts as an
68   // outstanding request, which prevents the page from entering the
69   // BackForwardCache, as long as it hasn't resolved.
70   //
71   // There are no real way to wait for this to complete. Not waiting would make
72   // the test potentially flaky. To prevent this, the no-favicon.html page is
73   // used, the image is not loaded from the network.
74   GURL GetURL(const std::string& host) {
75     return embedded_test_server()->GetURL(
76         host, "/back_forward_cache/no-favicon.html");
77   }
78
79  protected:
80   void SetUpCommandLine(base::CommandLine* command_line) override {
81     // For using an HTTPS server.
82     base::CommandLine::ForCurrentProcess()->AppendSwitch(
83         switches::kIgnoreCertificateErrors);
84     // For using WebBluetooth.
85     command_line->AppendSwitch(
86         switches::kEnableExperimentalWebPlatformFeatures);
87
88     SetupFeaturesAndParameters();
89   }
90
91   content::WebContents* web_contents() const {
92     return browser()->tab_strip_model()->GetActiveWebContents();
93   }
94
95   content::RenderFrameHost* current_frame_host() {
96     return web_contents()->GetPrimaryMainFrame();
97   }
98
99   void SetupFeaturesAndParameters() {
100     scoped_feature_list_.InitWithFeaturesAndParameters(
101         content::GetDefaultEnabledBackForwardCacheFeaturesForTesting(),
102         content::GetDefaultDisabledBackForwardCacheFeaturesForTesting(
103             {// Entry to the cache can be slow during testing and cause
104              // flakiness.
105              features::kBackForwardCacheEntryTimeout}));
106     vmodule_switches_.InitWithSwitches("back_forward_cache_impl=1");
107   }
108
109   std::unique_ptr<base::HistogramTester> histogram_tester_;
110
111  private:
112   base::test::ScopedFeatureList scoped_feature_list_;
113   logging::ScopedVmoduleSwitches vmodule_switches_;
114 };
115
116 IN_PROC_BROWSER_TEST_F(ChromeBackForwardCacheBrowserTest, Basic) {
117   ASSERT_TRUE(embedded_test_server()->Start());
118
119   // 1) Navigate to A.
120   EXPECT_TRUE(content::NavigateToURL(web_contents(), GetURL("a.com")));
121   content::RenderFrameHostWrapper rfh_a(current_frame_host());
122
123   // 2) Navigate to B.
124   EXPECT_TRUE(content::NavigateToURL(web_contents(), GetURL("b.com")));
125   content::RenderFrameHostWrapper rfh_b(current_frame_host());
126
127   // A is frozen in the BackForwardCache.
128   EXPECT_EQ(rfh_a->GetLifecycleState(),
129             content::RenderFrameHost::LifecycleState::kInBackForwardCache);
130
131   // 3) Navigate back.
132   web_contents()->GetController().GoBack();
133   EXPECT_TRUE(content::WaitForLoadStop(web_contents()));
134
135   // A is restored, B is stored.
136   EXPECT_EQ(rfh_b->GetLifecycleState(),
137             content::RenderFrameHost::LifecycleState::kInBackForwardCache);
138
139   // 4) Navigate forward.
140   web_contents()->GetController().GoForward();
141   EXPECT_TRUE(content::WaitForLoadStop(web_contents()));
142
143   // A is stored, B is restored.
144   EXPECT_EQ(rfh_a->GetLifecycleState(),
145             content::RenderFrameHost::LifecycleState::kInBackForwardCache);
146 }
147
148 IN_PROC_BROWSER_TEST_F(ChromeBackForwardCacheBrowserTest, BasicIframe) {
149   ASSERT_TRUE(embedded_test_server()->Start());
150
151   // 1) Navigate to A.
152   EXPECT_TRUE(content::NavigateToURL(web_contents(), GetURL("a.com")));
153   content::RenderFrameHostWrapper rfh_a(current_frame_host());
154
155   // 2) Add an iframe B.
156   EXPECT_TRUE(content::ExecJs(rfh_a.get(), R"(
157     let url = new URL(location.href);
158     url.hostname = 'b.com';
159     let iframe = document.createElement('iframe');
160     iframe.url = url;
161     document.body.appendChild(iframe);
162   )"));
163   EXPECT_TRUE(content::WaitForLoadStop(web_contents()));
164
165   content::RenderFrameHost* rfh_b = nullptr;
166   rfh_a->ForEachRenderFrameHost([&](content::RenderFrameHost* rfh) {
167     if (rfh != rfh_a.get())
168       rfh_b = rfh;
169   });
170   EXPECT_TRUE(rfh_b);
171   content::RenderFrameHostWrapper rfh_b_wrapper(rfh_b);
172
173   // 2) Navigate to C.
174   EXPECT_TRUE(content::NavigateToURL(web_contents(), GetURL("c.com")));
175   content::RenderFrameHostWrapper rfh_c(current_frame_host());
176
177   // A and B are frozen. The page A(B) is stored in the BackForwardCache.
178   EXPECT_EQ(rfh_a->GetLifecycleState(),
179             content::RenderFrameHost::LifecycleState::kInBackForwardCache);
180   EXPECT_EQ(rfh_b_wrapper->GetLifecycleState(),
181             content::RenderFrameHost::LifecycleState::kInBackForwardCache);
182
183   // 3) Navigate back.
184   web_contents()->GetController().GoBack();
185   EXPECT_TRUE(content::WaitForLoadStop(web_contents()));
186
187   // The page A(B) is restored and C is frozen.
188   EXPECT_EQ(rfh_c->GetLifecycleState(),
189             content::RenderFrameHost::LifecycleState::kInBackForwardCache);
190 }
191
192 IN_PROC_BROWSER_TEST_F(ChromeBackForwardCacheBrowserTest,
193                        PermissionContextBase) {
194   // HTTPS needed for GEOLOCATION permission
195   net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS);
196   https_server.AddDefaultHandlers(GetChromeTestDataDir());
197   https_server.SetSSLConfig(net::EmbeddedTestServer::CERT_TEST_NAMES);
198   ASSERT_TRUE(https_server.Start());
199
200   GURL url_a(https_server.GetURL("a.test", "/title1.html"));
201   GURL url_b(https_server.GetURL("b.test", "/title1.html"));
202
203   // 1) Navigate to A.
204   EXPECT_TRUE(NavigateToURL(web_contents(), url_a));
205   content::RenderFrameHostWrapper rfh_a(current_frame_host());
206
207   // 2) Navigate to B.
208   EXPECT_TRUE(NavigateToURL(web_contents(), url_b));
209   EXPECT_EQ(rfh_a->GetLifecycleState(),
210             content::RenderFrameHost::LifecycleState::kInBackForwardCache);
211   base::MockOnceCallback<void(blink::mojom::PermissionStatus)> callback;
212   EXPECT_CALL(callback, Run(blink::mojom::PermissionStatus::ASK));
213   browser()
214       ->profile()
215       ->GetPermissionController()
216       ->RequestPermissionFromCurrentDocument(
217           rfh_a.get(),
218           content::PermissionRequestDescription(
219               blink::PermissionType::GEOLOCATION, /* user_gesture = */ true),
220           callback.Get());
221
222   // Ensure |rfh_a| is evicted from the cache because it is not allowed to
223   // service the GEOLOCATION permission request.
224   ASSERT_TRUE(rfh_a.WaitUntilRenderFrameDeleted());
225 }
226
227 IN_PROC_BROWSER_TEST_F(ChromeBackForwardCacheBrowserTest,
228                        DoesNotCacheIfPictureInPicture) {
229   embedded_test_server()->ServeFilesFromSourceDirectory("content/test/data");
230   ASSERT_TRUE(embedded_test_server()->Start());
231
232   // Navigate to a page with picture-in-picture functionality.
233   const base::FilePath::CharType picture_in_picture_page[] =
234       FILE_PATH_LITERAL("media/picture-in-picture/window-size.html");
235   GURL test_page_url = ui_test_utils::GetTestUrl(
236       base::FilePath(base::FilePath::kCurrentDirectory),
237       base::FilePath(picture_in_picture_page));
238   EXPECT_TRUE(content::NavigateToURL(web_contents(), test_page_url));
239   content::RenderFrameHostWrapper rfh(current_frame_host());
240
241   // Execute picture-in-picture on the page.
242   ASSERT_EQ(true, content::EvalJs(web_contents(), "enterPictureInPicture();"));
243
244   // Navigate away.
245   EXPECT_TRUE(content::NavigateToURL(web_contents(), GetURL("b.com")));
246
247   // The page uses Picture-in-Picture so it must be evicted from the cache and
248   // deleted.
249   ASSERT_TRUE(rfh.WaitUntilRenderFrameDeleted());
250 }
251
252 #if BUILDFLAG(IS_ANDROID)
253 IN_PROC_BROWSER_TEST_F(ChromeBackForwardCacheBrowserTest,
254                        DoesNotCacheIfWebShare) {
255   // HTTPS needed for WebShare permission.
256   net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS);
257   https_server.AddDefaultHandlers(GetChromeTestDataDir());
258   https_server.SetSSLConfig(net::EmbeddedTestServer::CERT_TEST_NAMES);
259   ASSERT_TRUE(https_server.Start());
260
261   GURL url_a(https_server.GetURL("a.test", "/title1.html"));
262   GURL url_b(https_server.GetURL("b.test", "/title1.html"));
263
264   // 1) Navigate to A.
265   EXPECT_TRUE(content::NavigateToURL(web_contents(), url_a));
266   content::RenderFrameHostWrapper rfh_a(current_frame_host());
267
268   // Use the WebShare feature on the empty page.
269   EXPECT_EQ("success", content::EvalJs(current_frame_host(), R"(
270     new Promise(resolve => {
271       navigator.share({title: 'the title'})
272         .then(m => { resolve("success"); })
273         .catch(error => { resolve(error.message); });
274     });
275   )"));
276
277   // 2) Navigate away.
278   EXPECT_TRUE(content::NavigateToURL(web_contents(), url_b));
279
280   // The page uses WebShare so it must be evicted from the cache and deleted.
281   ASSERT_TRUE(rfh_a.WaitUntilRenderFrameDeleted());
282
283   // 3) Go back.
284   web_contents()->GetController().GoBack();
285   EXPECT_TRUE(content::WaitForLoadStop(web_contents()));
286 }
287
288 IN_PROC_BROWSER_TEST_F(ChromeBackForwardCacheBrowserTest,
289                        DoesNotCacheIfWebNfc) {
290   // HTTPS needed for WebNfc permission.
291   net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS);
292   https_server.AddDefaultHandlers(GetChromeTestDataDir());
293   https_server.SetSSLConfig(net::EmbeddedTestServer::CERT_TEST_NAMES);
294   ASSERT_TRUE(https_server.Start());
295
296   GURL url_a(https_server.GetURL("a.test", "/title1.html"));
297   GURL url_b(https_server.GetURL("b.test", "/title1.html"));
298
299   // 1) Navigate to A.
300   EXPECT_TRUE(content::NavigateToURL(web_contents(), url_a));
301   content::RenderFrameHostWrapper rfh_a(current_frame_host());
302
303   // Use the WebNfc feature on the empty page.
304   EXPECT_EQ("success", content::EvalJs(current_frame_host(), R"(
305     const ndef = new NDEFReader();
306     new Promise(async resolve => {
307       try {
308         await ndef.write("Hello");
309         resolve('success');
310       } catch (error) {
311         resolve(error.message);
312       }
313     });
314   )"));
315
316   // 2) Navigate away.
317   EXPECT_TRUE(content::NavigateToURL(web_contents(), url_b));
318
319   // The page uses WebNfc so it must be evicted from the cache and deleted.
320   ASSERT_TRUE(rfh_a.WaitUntilRenderFrameDeleted());
321
322   // 3) Go back.
323   web_contents()->GetController().GoBack();
324   EXPECT_TRUE(content::WaitForLoadStop(web_contents()));
325 }
326 #endif
327
328 IN_PROC_BROWSER_TEST_F(ChromeBackForwardCacheBrowserTest,
329                        RestoresMixedContentSettings) {
330   net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS);
331   https_server.AddDefaultHandlers(GetChromeTestDataDir());
332   https_server.SetSSLConfig(net::EmbeddedTestServer::CERT_TEST_NAMES);
333   ASSERT_TRUE(https_server.Start());
334   GURL url_a(https_server.GetURL("a.test",
335                                  "/content_setting_bubble/mixed_script.html"));
336   GURL url_b(https_server.GetURL("b.test",
337                                  "/content_setting_bubble/mixed_script.html"));
338
339   // 1) Load page A that has mixed content.
340   EXPECT_TRUE(content::NavigateToURL(web_contents(), url_a));
341   // Mixed content should be blocked at first.
342   EXPECT_FALSE(MixedContentSettingsTabHelper::FromWebContents(web_contents())
343                    ->IsRunningInsecureContentAllowed(*current_frame_host()));
344
345   // 2) Emulate link clicking on the mixed script bubble to allow mixed content
346   // to run.
347   content::TestNavigationObserver observer(
348       browser()->tab_strip_model()->GetActiveWebContents());
349   std::unique_ptr<ContentSettingBubbleModel> model(
350       ContentSettingBubbleModel::CreateContentSettingBubbleModel(
351           browser()->content_setting_bubble_model_delegate(),
352           browser()->tab_strip_model()->GetActiveWebContents(),
353           ContentSettingsType::MIXEDSCRIPT));
354   model->OnCustomLinkClicked();
355
356   // 3) Wait for reload.
357   observer.Wait();
358   content::RenderFrameHostWrapper rfh_a(current_frame_host());
359
360   // Mixed content should no longer be blocked.
361   EXPECT_TRUE(MixedContentSettingsTabHelper::FromWebContents(web_contents())
362                   ->IsRunningInsecureContentAllowed(*current_frame_host()));
363
364   // 4) Navigate to page B, which should use a different SiteInstance and
365   // resets the mixed content settings.
366   EXPECT_TRUE(content::NavigateToURL(web_contents(), url_b));
367   // Mixed content should be blocked in the new page.
368   EXPECT_FALSE(MixedContentSettingsTabHelper::FromWebContents(web_contents())
369                    ->IsRunningInsecureContentAllowed(*current_frame_host()));
370
371   // 5) A is stored in BackForwardCache.
372   EXPECT_EQ(rfh_a->GetLifecycleState(),
373             content::RenderFrameHost::LifecycleState::kInBackForwardCache);
374
375   // 6) Go back to page A.
376   web_contents()->GetController().GoBack();
377   EXPECT_TRUE(content::WaitForLoadStop(web_contents()));
378   // Mixed content settings is restored, so it's no longer blocked.
379   EXPECT_TRUE(MixedContentSettingsTabHelper::FromWebContents(web_contents())
380                   ->IsRunningInsecureContentAllowed(*current_frame_host()));
381 }
382
383 class MetricsChromeBackForwardCacheBrowserTest
384     : public ChromeBackForwardCacheBrowserTest,
385       public ::testing::WithParamInterface<std::string> {
386  public:
387   MetricsChromeBackForwardCacheBrowserTest() = default;
388   ~MetricsChromeBackForwardCacheBrowserTest() override = default;
389
390  protected:
391   void SetUpCommandLine(base::CommandLine* command_line) override {
392     // TODO(crbug.com/1224780): This test used an experiment param (which no
393     // longer exists) to suppress the metrics send timer. If and when the test
394     // is re-enabled, it should be updated to use a different mechanism.
395     ChromeBackForwardCacheBrowserTest::SetUpCommandLine(command_line);
396   }
397 };
398
399 // Flaky https://crbug.com/1224780
400 IN_PROC_BROWSER_TEST_P(MetricsChromeBackForwardCacheBrowserTest,
401                        DISABLED_FirstInputDelay) {
402   ASSERT_TRUE(embedded_test_server()->Start());
403
404   GURL url1(embedded_test_server()->GetURL("a.com", "/title1.html"));
405   GURL url2(embedded_test_server()->GetURL(
406       (GetParam() == "SameSite") ? "a.com" : "b.com", "/title2.html"));
407
408   EXPECT_THAT(histogram_tester_->GetAllSamples(
409                   internal::kHistogramFirstContentfulPaint),
410               testing::IsEmpty());
411
412   // 1) Navigate to url1.
413   EXPECT_TRUE(content::NavigateToURL(web_contents(), url1));
414   content::RenderFrameHostWrapper rfh_url1(current_frame_host());
415
416   // Simulate mouse click. FirstInputDelay won't get updated immediately.
417   content::SimulateMouseClickAt(web_contents(), 0,
418                                 blink::WebMouseEvent::Button::kLeft,
419                                 gfx::Point(100, 100));
420   // Run arbitrary script and run tasks in the browser to ensure the input is
421   // processed in the renderer.
422   EXPECT_TRUE(content::ExecJs(rfh_url1.get(), "var foo = 42;"));
423   base::RunLoop().RunUntilIdle();
424   content::FetchHistogramsFromChildProcesses();
425   histogram_tester_->ExpectTotalCount(internal::kHistogramFirstInputDelay, 0);
426
427   // 2) Immediately navigate to url2.
428   if (GetParam() == "CrossSiteRendererInitiated") {
429     EXPECT_TRUE(content::NavigateToURLFromRenderer(web_contents(), url2));
430   } else {
431     EXPECT_TRUE(content::NavigateToURL(web_contents(), url2));
432   }
433
434   // Ensure |rfh_url1| is cached.
435   EXPECT_EQ(rfh_url1->GetLifecycleState(),
436             content::RenderFrameHost::LifecycleState::kInBackForwardCache);
437
438   content::FetchHistogramsFromChildProcesses();
439   if (GetParam() != "CrossSiteBrowserInitiated" ||
440       rfh_url1.get()->GetProcess() == current_frame_host()->GetProcess()) {
441     // - For "SameSite" case, since the old and new RenderFrame share a process,
442     // the metrics update will be sent to the browser during commit and won't
443     // get ignored, successfully updating the FirstInputDelay histogram.
444     // - For "CrossSiteRendererInitiated" case, FirstInputDelay was sent when
445     // the renderer-initiated navigation started on the old frame.
446     // - For "CrossSiteBrowserInitiated" case, if the old and new RenderFrame
447     // share a process, the metrics update will be sent to the browser during
448     // commit and won't get ignored, successfully updating the histogram.
449     histogram_tester_->ExpectTotalCount(internal::kHistogramFirstInputDelay, 1);
450   } else {
451     // Note that in some cases the metrics might flakily get updated in time,
452     // before the browser changed the current RFH. So, we can neither expect it
453     // to be 0 all the time or 1 all the time.
454     // TODO(crbug.com/1150242): Support updating metrics consistently on
455     // cross-RFH cross-process navigations.
456   }
457 }
458
459 std::vector<std::string> MetricsChromeBackForwardCacheBrowserTestValues() {
460   return {"SameSite", "CrossSiteRendererInitiated",
461           "CrossSiteBrowserInitiated"};
462 }
463
464 INSTANTIATE_TEST_SUITE_P(
465     All,
466     MetricsChromeBackForwardCacheBrowserTest,
467     testing::ValuesIn(MetricsChromeBackForwardCacheBrowserTestValues()));
468
469 // Ensure that BackForwardCache RenderFrameHosts are shown in the Task Manager.
470 IN_PROC_BROWSER_TEST_F(ChromeBackForwardCacheBrowserTest,
471                        ShowMainFrameInTaskManager) {
472   ASSERT_TRUE(embedded_test_server()->Start());
473
474   GURL url_a(embedded_test_server()->GetURL("a.com", "/title2.html"));
475   const std::u16string expected_url_a_active_title = l10n_util::GetStringFUTF16(
476       IDS_TASK_MANAGER_TAB_PREFIX, u"Title Of Awesomeness");
477   const std::u16string expected_url_a_cached_title = l10n_util::GetStringFUTF16(
478       IDS_TASK_MANAGER_BACK_FORWARD_CACHE_PREFIX, u"http://a.com/");
479
480   GURL url_b(embedded_test_server()->GetURL("b.com", "/title3.html"));
481   const std::u16string expected_url_b_active_title = l10n_util::GetStringFUTF16(
482       IDS_TASK_MANAGER_TAB_PREFIX, u"Title Of More Awesomeness");
483   const std::u16string expected_url_b_cached_title = l10n_util::GetStringFUTF16(
484       IDS_TASK_MANAGER_BACK_FORWARD_CACHE_PREFIX, u"http://b.com/");
485
486   auto tester =
487       task_manager::TaskManagerTester::Create(base::RepeatingClosure());
488
489   // 1) Navigate to |url_a|.
490   ASSERT_TRUE(content::NavigateToURL(web_contents(), url_a));
491   content::RenderFrameHostWrapper rfh_a(current_frame_host());
492
493   // 2) Navigate to |url_b|.
494   ASSERT_TRUE(content::NavigateToURL(web_contents(), url_b));
495   content::RenderFrameHostWrapper rfh_b(current_frame_host());
496
497   // 3) Verify |url_a| is in the BackForwardCache.
498   ASSERT_EQ(rfh_a->GetLifecycleState(),
499             content::RenderFrameHost::LifecycleState::kInBackForwardCache);
500
501   // 4) Ensure both tabs show up in Task Manager.
502   task_manager::browsertest_util::WaitForTaskManagerRows(
503       1, expected_url_b_active_title);
504   task_manager::browsertest_util::WaitForTaskManagerRows(
505       1, expected_url_a_cached_title);
506   EXPECT_THAT(tester->GetWebContentsTaskTitles(),
507               ::testing::ElementsAre(expected_url_b_active_title,
508                                      expected_url_a_cached_title));
509
510   // 5) Navigate back to |url_a|.
511   web_contents()->GetController().GoBack();
512   ASSERT_TRUE(content::WaitForLoadStop(web_contents()));
513
514   // 6) Verify |url_b| is in the BackForwardCache.
515   ASSERT_EQ(rfh_b->GetLifecycleState(),
516             content::RenderFrameHost::LifecycleState::kInBackForwardCache);
517
518   // 7) Ensure both tabs show up in Task Manager.
519   task_manager::browsertest_util::WaitForTaskManagerRows(
520       1, expected_url_a_active_title);
521   task_manager::browsertest_util::WaitForTaskManagerRows(
522       1, expected_url_b_cached_title);
523   EXPECT_THAT(tester->GetWebContentsTaskTitles(),
524               ::testing::ElementsAre(expected_url_a_active_title,
525                                      expected_url_b_cached_title));
526 }
527
528 // Ensure that BackForwardCache cross-site subframes are shown in the Task
529 // Manager.
530 IN_PROC_BROWSER_TEST_F(ChromeBackForwardCacheBrowserTest,
531                        ShowCrossSiteOOPIFInTaskManager) {
532   ASSERT_TRUE(embedded_test_server()->Start());
533
534   // Load a page on a.com with cross-site iframes on b.com and c.com.
535   GURL url_a(
536       embedded_test_server()->GetURL("a.com", "/iframe_cross_site.html"));
537   const std::u16string expected_url_a_cached_title = l10n_util::GetStringFUTF16(
538       IDS_TASK_MANAGER_BACK_FORWARD_CACHE_PREFIX, u"http://a.com/");
539   const std::u16string expected_url_a_cached_subframe_b_title =
540       l10n_util::GetStringFUTF16(
541           IDS_TASK_MANAGER_BACK_FORWARD_CACHE_SUBFRAME_PREFIX,
542           u"http://b.com/");
543   const std::u16string expected_url_a_cached_subframe_c_title =
544       l10n_util::GetStringFUTF16(
545           IDS_TASK_MANAGER_BACK_FORWARD_CACHE_SUBFRAME_PREFIX,
546           u"http://c.com/");
547
548   GURL url_b(embedded_test_server()->GetURL("b.com", "/title3.html"));
549   const std::u16string expected_url_b_active_title = l10n_util::GetStringFUTF16(
550       IDS_TASK_MANAGER_TAB_PREFIX, u"Title Of More Awesomeness");
551
552   auto tester =
553       task_manager::TaskManagerTester::Create(base::RepeatingClosure());
554
555   // 1) Navigate to |url_a|.
556   EXPECT_TRUE(content::NavigateToURL(web_contents(), url_a));
557   content::RenderFrameHostWrapper rfh_a(current_frame_host());
558
559   // 2) Navigate to |url_b|.
560   EXPECT_TRUE(content::NavigateToURL(web_contents(), url_b));
561
562   // 3) Verify |url_a| is in the BackForwardCache.
563   EXPECT_EQ(rfh_a->GetLifecycleState(),
564             content::RenderFrameHost::LifecycleState::kInBackForwardCache);
565
566   // 4) Ensure the subframe tasks for |url_a| show up in Task Manager.
567   task_manager::browsertest_util::WaitForTaskManagerRows(
568       1, expected_url_b_active_title);
569   task_manager::browsertest_util::WaitForTaskManagerRows(
570       1, expected_url_a_cached_title);
571   task_manager::browsertest_util::WaitForTaskManagerRows(
572       1, expected_url_a_cached_subframe_b_title);
573   task_manager::browsertest_util::WaitForTaskManagerRows(
574       1, expected_url_a_cached_subframe_c_title);
575   EXPECT_THAT(tester->GetWebContentsTaskTitles(),
576               ::testing::ElementsAre(expected_url_b_active_title,
577                                      expected_url_a_cached_title,
578                                      expected_url_a_cached_subframe_b_title,
579                                      expected_url_a_cached_subframe_c_title));
580 }
581
582 // Ensure that BackForwardCache same-site subframes are not shown in the Task
583 // Manager.
584 IN_PROC_BROWSER_TEST_F(ChromeBackForwardCacheBrowserTest,
585                        DoNotShowSameSiteSubframeInTaskManager) {
586   ASSERT_TRUE(embedded_test_server()->Start());
587
588   // Load a page on a.com with an a.com iframe.
589   GURL url_a(embedded_test_server()->GetURL("a.com", "/iframe.html"));
590   const std::u16string expected_url_a_cached_title = l10n_util::GetStringFUTF16(
591       IDS_TASK_MANAGER_BACK_FORWARD_CACHE_PREFIX, u"http://a.com/");
592
593   GURL url_b(embedded_test_server()->GetURL("b.com", "/title3.html"));
594   const std::u16string expected_url_b_active_title = l10n_util::GetStringFUTF16(
595       IDS_TASK_MANAGER_TAB_PREFIX, u"Title Of More Awesomeness");
596
597   auto tester =
598       task_manager::TaskManagerTester::Create(base::RepeatingClosure());
599
600   // 1) Navigate to |url_a|.
601   EXPECT_TRUE(content::NavigateToURL(web_contents(), url_a));
602   content::RenderFrameHostWrapper rfh_a(current_frame_host());
603
604   // 2) Navigate to |url_b|.
605   EXPECT_TRUE(content::NavigateToURL(web_contents(), url_b));
606
607   // 3) Verify |url_a| is in the BackForwardCache.
608   EXPECT_EQ(rfh_a->GetLifecycleState(),
609             content::RenderFrameHost::LifecycleState::kInBackForwardCache);
610
611   // 4) Ensure that only one task for |url_a| shows up in Task Manager.
612   task_manager::browsertest_util::WaitForTaskManagerRows(
613       1, expected_url_b_active_title);
614   task_manager::browsertest_util::WaitForTaskManagerRows(
615       1, expected_url_a_cached_title);
616   EXPECT_THAT(tester->GetWebContentsTaskTitles(),
617               ::testing::ElementsAre(expected_url_b_active_title,
618                                      expected_url_a_cached_title));
619 }
620
621 class ChromeBackForwardCacheBrowserWithEmbedTest
622     : public ChromeBackForwardCacheBrowserTest,
623       public ::testing::WithParamInterface<std::string> {
624  public:
625   ChromeBackForwardCacheBrowserWithEmbedTest() = default;
626   ~ChromeBackForwardCacheBrowserWithEmbedTest() override = default;
627
628   static std::string GetSrcAttributeForTag(const std::string& tag) {
629     return tag == "embed" ? "src" : "data";
630   }
631
632   void SetUpOnMainThread() override {
633     ChromeBackForwardCacheBrowserTest::SetUpOnMainThread();
634     ASSERT_TRUE(embedded_test_server()->Start());
635   }
636
637  protected:
638   void ExpectBlocklistedFeature(
639       blink::scheduler::WebSchedulerTrackedFeature feature,
640       base::Location location) {
641     content::FetchHistogramsFromChildProcesses();
642     base::HistogramBase::Sample sample = base::HistogramBase::Sample(feature);
643     base::Bucket expected_blocklisted(sample, 1);
644
645     EXPECT_THAT(histogram_tester_->GetAllSamples(
646                     "BackForwardCache.HistoryNavigationOutcome."
647                     "BlocklistedFeature"),
648                 testing::Contains(expected_blocklisted))
649         << location.ToString();
650
651     EXPECT_THAT(histogram_tester_->GetAllSamples(
652                     "BackForwardCache.AllSites.HistoryNavigationOutcome."
653                     "BlocklistedFeature"),
654                 testing::Contains(expected_blocklisted))
655         << location.ToString();
656   }
657
658   void ExpectNotRestoredReasonHaveInnerContents(base::Location location) {
659     // BackForwardCacheMetrics::NotRestoredReason::kHaveInnerContents
660     uint8_t reason = 32;
661     content::FetchHistogramsFromChildProcesses();
662     base::HistogramBase::Sample sample = base::HistogramBase::Sample(reason);
663     base::Bucket expected_not_restored(sample, 1);
664
665     EXPECT_THAT(histogram_tester_->GetAllSamples(
666                     "BackForwardCache.HistoryNavigationOutcome."
667                     "NotRestoredReason"),
668                 testing::Contains(expected_not_restored))
669         << location.ToString();
670
671     EXPECT_THAT(histogram_tester_->GetAllSamples(
672                     "BackForwardCache.AllSites.HistoryNavigationOutcome."
673                     "NotRestoredReason"),
674                 testing::Contains(expected_not_restored))
675         << location.ToString();
676   }
677 };
678 INSTANTIATE_TEST_SUITE_P(
679     All,
680     ChromeBackForwardCacheBrowserWithEmbedTest,
681     testing::ValuesIn<std::vector<std::string>>({"embed", "object"}));
682
683 // TODO(crbug.com/1491942): This fails with the field trial testing config.
684 class ChromeBackForwardCacheBrowserWithEmbedTestNoTestingConfig
685     : public ChromeBackForwardCacheBrowserWithEmbedTest {
686  public:
687   void SetUpCommandLine(base::CommandLine* command_line) override {
688     ChromeBackForwardCacheBrowserWithEmbedTest::SetUpCommandLine(command_line);
689     command_line->AppendSwitch("disable-field-trial-config");
690   }
691 };
692 INSTANTIATE_TEST_SUITE_P(
693     All,
694     ChromeBackForwardCacheBrowserWithEmbedTestNoTestingConfig,
695     testing::ValuesIn<std::vector<std::string>>({"embed", "object"}));
696
697 IN_PROC_BROWSER_TEST_P(
698     ChromeBackForwardCacheBrowserWithEmbedTestNoTestingConfig,
699     DoesNotCachePageWithEmbeddedPlugin) {
700   const auto tag = GetParam();
701   const auto page_with_plugin = base::StringPrintf(
702       "/back_forward_cache/page_with_%s_plugin.html", tag.c_str());
703
704   // Navigate to A, a page with embedded Pepper plugin.
705   ASSERT_TRUE(content::NavigateToURL(
706       web_contents(),
707       embedded_test_server()->GetURL("a.com", page_with_plugin)));
708   content::RenderFrameHostWrapper rfh_a(current_frame_host());
709
710   // Navigate to B.
711   bool will_change_rfh =
712       rfh_a->ShouldChangeRenderFrameHostOnSameSiteNavigation();
713
714   ASSERT_TRUE(content::NavigateToURL(
715       web_contents(), embedded_test_server()->GetURL("a.com", "/title2.html")));
716
717   // Verify A is NOT stored in the BackForwardCache.
718   if (will_change_rfh) {
719     EXPECT_TRUE(rfh_a.WaitUntilRenderFrameDeleted());
720   } else {
721     EXPECT_NE(rfh_a->GetLifecycleState(),
722               content::RenderFrameHost::LifecycleState::kInBackForwardCache);
723   }
724
725   // Navigate back to A.
726   ASSERT_TRUE(content::HistoryGoBack(web_contents()));
727   // Verify A is not restored from BackForwardCache due to |kContainsPlugins|.
728   ExpectBlocklistedFeature(
729       blink::scheduler::WebSchedulerTrackedFeature::kContainsPlugins,
730       FROM_HERE);
731 }
732
733 #if BUILDFLAG(ENABLE_PDF)
734 IN_PROC_BROWSER_TEST_P(
735     ChromeBackForwardCacheBrowserWithEmbedTestNoTestingConfig,
736     DoesNotCachePageWithEmbeddedPdf) {
737   const auto tag = GetParam();
738   const auto page_with_pdf = base::StringPrintf(
739       "/back_forward_cache/page_with_%s_pdf.html", tag.c_str());
740
741   // Navigate to A, a page with embedded PDF.
742   ASSERT_TRUE(content::NavigateToURL(
743       web_contents(), embedded_test_server()->GetURL("a.com", page_with_pdf)));
744   ASSERT_TRUE(pdf_extension_test_util::EnsurePDFHasLoaded(
745       web_contents(), /*wait_for_hit_test_data=*/true, tag));
746   content::RenderFrameHostWrapper rfh_a(current_frame_host());
747
748   // Navigate to B.
749   bool will_change_rfh =
750       rfh_a->ShouldChangeRenderFrameHostOnSameSiteNavigation();
751
752   ASSERT_TRUE(content::NavigateToURL(
753       web_contents(), embedded_test_server()->GetURL("a.com", "/title2.html")));
754
755   // Verify A is NOT stored in the BackForwardCache.
756   if (will_change_rfh) {
757     EXPECT_TRUE(rfh_a.WaitUntilRenderFrameDeleted());
758   } else {
759     EXPECT_NE(rfh_a->GetLifecycleState(),
760               content::RenderFrameHost::LifecycleState::kInBackForwardCache);
761   }
762
763   // Navigate back to A.
764   ASSERT_TRUE(content::HistoryGoBack(web_contents()));
765   // Verify A is not restored from BackForwardCache. Loading PDF plugins
766   // in chrome actually creates a nested WebContents which takes precedent over
767   // the blocklisted feature kContainsPlugins.
768   ExpectNotRestoredReasonHaveInnerContents(FROM_HERE);
769 }
770 #endif  // BUILDFLAG(ENABLE_PDF)
771
772 // Flaky on Mac: crbug.com/1492026
773 #if BUILDFLAG(IS_MAC)
774 #define MAYBE_DoesNotCachePageWithEmbeddedPdfAppendedOnPageLoaded DISABLED_DoesNotCachePageWithEmbeddedPdfAppendedOnPageLoaded
775 #else
776 #define MAYBE_DoesNotCachePageWithEmbeddedPdfAppendedOnPageLoaded DoesNotCachePageWithEmbeddedPdfAppendedOnPageLoaded
777 #endif
778 IN_PROC_BROWSER_TEST_P(ChromeBackForwardCacheBrowserWithEmbedTest,
779                        MAYBE_DoesNotCachePageWithEmbeddedPdfAppendedOnPageLoaded) {
780   const auto tag = GetParam();
781
782   // Navigate to A.
783   ASSERT_TRUE(content::NavigateToURL(
784       web_contents(), embedded_test_server()->GetURL("a.com", "/title1.html")));
785   content::RenderFrameHostWrapper rfh_a(current_frame_host());
786   //  Embed a PDF into A, and wait until PDF is loaded.
787   ASSERT_TRUE(content::ExecJs(
788       rfh_a.get(), content::JsReplace(R"(
789     new Promise(async resolve => {
790       let el = document.createElement($1);
791       el.type = 'application/pdf';
792       el[$2] = '/pdf/test.pdf';
793       el.onload = e => resolve();
794       document.body.append(el);
795     });
796   )",
797                                       tag, GetSrcAttributeForTag(tag))));
798
799   // Navigate to B.
800   ASSERT_TRUE(content::NavigateToURL(
801       web_contents(), embedded_test_server()->GetURL("a.com", "/title2.html")));
802
803   // Verify A is NOT stored in the BackForwardCache.
804   if (content::WillSameSiteNavigationChangeRenderFrameHosts(
805           /*is_main_frame=*/true)) {
806     EXPECT_TRUE(rfh_a.WaitUntilRenderFrameDeleted());
807   } else {
808     EXPECT_NE(rfh_a->GetLifecycleState(),
809               content::RenderFrameHost::LifecycleState::kInBackForwardCache);
810   }
811
812   //  Navigate back to A.
813   ASSERT_TRUE(content::HistoryGoBack(web_contents()));
814   // Verify A is not restored from BackForwardCache. Loading PDF plugins
815   // in chrome actually creates a nested WebContents which takes precedent over
816   // the blocklisted feature kContainsPlugins.
817   ExpectNotRestoredReasonHaveInnerContents(FROM_HERE);
818 }
819
820 IN_PROC_BROWSER_TEST_P(ChromeBackForwardCacheBrowserWithEmbedTest,
821                        DoesCachePageWithEmbeddedHtml) {
822   const auto tag = GetParam();
823   const auto page_with_html = base::StringPrintf(
824       "/back_forward_cache/page_with_%s_html.html", tag.c_str());
825
826   // Navigate to A, a page with embedded HTML.
827   ASSERT_TRUE(content::NavigateToURL(
828       web_contents(), embedded_test_server()->GetURL("a.com", page_with_html)));
829   content::RenderFrameHostWrapper rfh_a(current_frame_host());
830
831   // Navigate to B.
832   ASSERT_TRUE(content::NavigateToURL(
833       web_contents(), embedded_test_server()->GetURL("a.com", "/title2.html")));
834
835   // Verify A is stored in the BackForwardCache.
836   EXPECT_EQ(rfh_a->GetLifecycleState(),
837             content::RenderFrameHost::LifecycleState::kInBackForwardCache);
838 }
839
840 // Flaky on Mac and Linux: crbug.com/1492026
841 #if (BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX))
842 #define MAYBE_DoesNotCachePageWithEmbeddedHtmlMutatedIntoPdf DISABLED_DoesNotCachePageWithEmbeddedHtmlMutatedIntoPdf
843 #else
844 #define MAYBE_DoesNotCachePageWithEmbeddedHtmlMutatedIntoPdf DoesNotCachePageWithEmbeddedHtmlMutatedIntoPdf
845 #endif
846 IN_PROC_BROWSER_TEST_P(ChromeBackForwardCacheBrowserWithEmbedTest,
847                        MAYBE_DoesNotCachePageWithEmbeddedHtmlMutatedIntoPdf) {
848   const auto tag = GetParam();
849   const auto page_with_html = base::StringPrintf(
850       "/back_forward_cache/page_with_%s_html.html", tag.c_str());
851
852   // Navigate to A, a page with embedded HTML.
853   ASSERT_TRUE(content::NavigateToURL(
854       web_contents(), embedded_test_server()->GetURL("a.com", page_with_html)));
855   content::RenderFrameHostWrapper rfh_a(current_frame_host());
856   //  Mutate the embed into PDF, and wait until PDF is loaded.
857   ASSERT_TRUE(content::ExecJs(
858       rfh_a.get(), content::JsReplace(R"(
859     new Promise(async resolve => {
860       let el = document.getElementById($1);
861       el.type = 'application/pdf';
862       el[$2] = '/pdf/test.pdf';
863       el.onload = e => resolve();
864     });
865   )",
866                                       tag, GetSrcAttributeForTag(tag))));
867
868   bool will_change_rfh =
869       rfh_a->ShouldChangeRenderFrameHostOnSameSiteNavigation();
870   // Navigate to B.
871   ASSERT_TRUE(content::NavigateToURL(
872       web_contents(), embedded_test_server()->GetURL("a.com", "/title2.html")));
873
874   // Verify A is NOT stored in the BackForwardCache.
875   if (will_change_rfh) {
876     EXPECT_TRUE(rfh_a.WaitUntilRenderFrameDeleted());
877   } else {
878     EXPECT_NE(rfh_a->GetLifecycleState(),
879               content::RenderFrameHost::LifecycleState::kInBackForwardCache);
880   }
881
882   // Navigate back to A.
883   ASSERT_TRUE(content::HistoryGoBack(web_contents()));
884   // Verify A is not restored from BackForwardCache. Loading PDF plugins
885   // in chrome actually creates a nested WebContents which takes precedent over
886   // the blocklisted feature kContainsPlugins.
887   ExpectNotRestoredReasonHaveInnerContents(FROM_HERE);
888 }
889
890 IN_PROC_BROWSER_TEST_P(ChromeBackForwardCacheBrowserWithEmbedTest,
891                        DoesCachePageWithEmbeddedPdfMutatedIntoHtml) {
892   const auto tag = GetParam();
893   const auto page_with_pdf = base::StringPrintf(
894       "/back_forward_cache/page_with_%s_pdf.html", tag.c_str());
895
896   // Navigate to A, a page with embedded PDF.
897   ASSERT_TRUE(content::NavigateToURL(
898       web_contents(), embedded_test_server()->GetURL("a.com", page_with_pdf)));
899   content::RenderFrameHostWrapper rfh_a(current_frame_host());
900   //  Mutate the embed into HTML, and wait until HTML is loaded.
901   ASSERT_TRUE(content::ExecJs(
902       rfh_a.get(), content::JsReplace(R"(
903     new Promise(async resolve => {
904       let el = document.getElementById($1);
905       el.type = 'text/html';
906       el[$2] = '/title1.html';
907       el.onload = e => resolve();
908     });
909   )",
910                                       tag, GetSrcAttributeForTag(tag))));
911
912   // Navigate to B.
913   ASSERT_TRUE(content::NavigateToURL(
914       web_contents(), embedded_test_server()->GetURL("a.com", "/title2.html")));
915
916   // Verify A is stored in the BackForwardCache.
917   EXPECT_EQ(rfh_a->GetLifecycleState(),
918             content::RenderFrameHost::LifecycleState::kInBackForwardCache);
919 }