blob: 094d0dcf01f5740b7a0a0e6be09f04366dccf395 [file] [log] [blame]
Arthur Sonzogni620cec62018-12-13 13:08:571// Copyright 2018 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
Carlos Caballeroec26d422019-12-11 11:28:145#include <memory>
Ken Rockot05499cf2019-12-12 05:22:546#include <unordered_map>
7
danakjdb9ae7942020-11-11 16:01:358#include "base/callback_helpers.h"
Arthur Sonzogni620cec62018-12-13 13:08:579#include "base/command_line.h"
[email protected]54eaf622019-11-25 12:36:0310#include "base/hash/hash.h"
Alexander Timin44ccede2020-01-23 09:00:3411#include "base/location.h"
Hajime Hoshi0d93f3b2019-10-08 07:01:5012#include "base/metrics/metrics_hashes.h"
Carlos Caballero8b114db2020-08-13 08:57:0313#include "base/run_loop.h"
Carlos Caballerob6b466482019-11-29 13:33:1814#include "base/strings/string_piece_forward.h"
Fergal Daly92229c42021-04-08 11:51:4215#include "base/strings/stringprintf.h"
[email protected]54eaf622019-11-25 12:36:0316#include "base/system/sys_info.h"
Harkiran Bolaria875dd0d2020-09-15 18:10:4617#include "base/task/common/task_annotator.h"
arthursonzogni9cd875342019-09-04 14:53:4618#include "base/task/post_task.h"
Guido Urdanetaef4e91942020-11-09 15:06:2419#include "base/test/bind.h"
Arthur Sonzogni620cec62018-12-13 13:08:5720#include "base/test/scoped_feature_list.h"
[email protected]3900bde02019-09-18 14:54:4421#include "base/test/test_mock_time_task_runner.h"
Harkiran Bolaria12818bc2020-11-03 22:44:2722#include "base/test/test_timeouts.h"
Carlos Caballero8b114db2020-08-13 08:57:0323#include "base/threading/thread_restrictions.h"
24#include "base/threading/thread_task_runner_handle.h"
arthursonzogni9cd875342019-09-04 14:53:4625#include "base/time/time.h"
Carlos Caballero8b114db2020-08-13 08:57:0326#include "base/trace_event/trace_log.h"
Rakina Zata Amni06343cc2019-10-11 01:33:2327#include "build/build_config.h"
Christian Dullweber5c5a42a2021-07-15 09:16:1428#include "build/chromecast_buildflags.h"
Yuta Hijikatad0a8b6b2020-11-20 16:36:1529#include "build/chromeos_buildflags.h"
Hajime Hoshi765845d62020-02-21 02:56:2130#include "components/ukm/test_ukm_recorder.h"
Carlos Caballero8b114db2020-08-13 08:57:0331#include "content/browser/bad_message.h"
Ken Rockot05499cf2019-12-12 05:22:5432#include "content/browser/generic_sensor/sensor_provider_proxy_impl.h"
Rakina Zata Amnic7bc82632019-12-09 05:21:2233#include "content/browser/presentation/presentation_test_utils.h"
Adithya Srinivasan7fe5ce662021-06-04 21:36:0434#include "content/browser/renderer_host/back_forward_cache_can_store_document_result.h"
Fergal Daly23b8ae62021-03-30 05:43:4635#include "content/browser/renderer_host/back_forward_cache_disable.h"
danakj10f32372020-09-15 22:25:1636#include "content/browser/renderer_host/back_forward_cache_impl.h"
37#include "content/browser/renderer_host/frame_tree_node.h"
Alexander Timin8aeee642021-05-12 08:39:3338#include "content/browser/renderer_host/navigation_request.h"
Carlos Caballero8b114db2020-08-13 08:57:0339#include "content/browser/renderer_host/page_lifecycle_state_manager.h"
danakj10f32372020-09-15 22:25:1640#include "content/browser/renderer_host/render_frame_host_impl.h"
Hajime Hoshi8fd675e02020-10-29 14:28:4141#include "content/browser/renderer_host/should_swap_browsing_instance.h"
Sreeja Kamishettybfd828d2020-06-10 11:56:0542#include "content/browser/web_contents/file_chooser_impl.h"
Arthur Sonzogni620cec62018-12-13 13:08:5743#include "content/browser/web_contents/web_contents_impl.h"
[email protected]ee8ae332020-01-29 03:49:4544#include "content/common/content_navigation_policy.h"
Carlos Caballero8b114db2020-08-13 08:57:0345#include "content/common/render_accessibility.mojom.h"
Carlos Caballerob6b466482019-11-29 13:33:1846#include "content/public/browser/back_forward_cache.h"
Alexander Timina085dd42021-06-04 16:55:4147#include "content/public/browser/document_service_base.h"
Carlos Caballerob6b466482019-11-29 13:33:1848#include "content/public/browser/global_routing_id.h"
Reilly Grant4b6aa442021-07-26 21:00:3049#include "content/public/browser/idle_time_provider.h"
Hajime Hoshic52208f2021-04-14 13:22:4150#include "content/public/browser/media_session.h"
Fergal Daly87f79d62019-11-11 01:24:0451#include "content/public/browser/navigation_handle.h"
Carlos Caballero35ce710c2019-09-19 10:59:4552#include "content/public/browser/render_frame_host.h"
arthursonzogni1dddb712019-07-12 10:42:1753#include "content/public/browser/site_isolation_policy.h"
Carlos Caballero91fffb22019-10-29 15:24:3054#include "content/public/browser/web_contents.h"
55#include "content/public/browser/web_contents_observer.h"
Arthur Sonzogni620cec62018-12-13 13:08:5756#include "content/public/common/content_features.h"
Kouhei Ueno01b0f1192019-08-14 05:28:0757#include "content/public/common/content_switches.h"
Khushalc5eaf222021-06-30 20:15:4858#include "content/public/common/result_codes.h"
arthursonzognibec31272019-10-09 11:51:2159#include "content/public/test/back_forward_cache_util.h"
Peter Kasting919ce652020-05-07 10:22:3660#include "content/public/test/browser_test.h"
Arthur Sonzogni620cec62018-12-13 13:08:5761#include "content/public/test/browser_test_utils.h"
Adithya Srinivasan7fe5ce662021-06-04 21:36:0462#include "content/public/test/commit_message_delayer.h"
Arthur Sonzogni620cec62018-12-13 13:08:5763#include "content/public/test/content_browser_test.h"
64#include "content/public/test/content_browser_test_utils.h"
Arthur Sonzognidc3d3b2a2021-08-06 13:13:2365#include "content/public/test/content_mock_cert_verifier.h"
Wei Lee01971182020-09-18 09:15:2166#include "content/public/test/idle_test_utils.h"
Kevin McNee0c88f7af2021-04-30 15:17:2467#include "content/public/test/mock_web_contents_observer.h"
Mohamed Abdelhalim462fff32019-08-13 14:13:4268#include "content/public/test/navigation_handle_observer.h"
Hajime Hoshie9262d32019-08-28 07:40:2369#include "content/public/test/test_navigation_observer.h"
Lowell Manners889189f2019-08-22 16:47:4570#include "content/public/test/test_navigation_throttle.h"
71#include "content/public/test/test_navigation_throttle_inserter.h"
Arthur Sonzogni620cec62018-12-13 13:08:5772#include "content/public/test/test_utils.h"
Rakina Zata Amniefcc2932020-08-28 07:24:3773#include "content/public/test/text_input_test_utils.h"
Mohamed Abdelhalim462fff32019-08-13 14:13:4274#include "content/public/test/url_loader_interceptor.h"
Yutaka Hiranobbfe1822021-08-30 10:09:0975#include "content/public/test/web_transport_simple_test_server.h"
Arthur Sonzogni620cec62018-12-13 13:08:5776#include "content/shell/browser/shell.h"
David Bokan377fb3e2021-06-09 16:19:5777#include "content/shell/browser/shell_content_browser_client.h"
Fergal Daly7991d9362019-12-20 02:28:2578#include "content/shell/browser/shell_javascript_dialog_manager.h"
arthursonzogni1dddb712019-07-12 10:42:1779#include "content/test/content_browser_test_utils_internal.h"
Ken Rockot9652fa62020-11-05 05:30:2280#include "content/test/echo.test-mojom.h"
Alexander Timin8aeee642021-05-12 08:39:3381#include "content/test/web_contents_observer_test_utils.h"
Fergal Dalydd2190472021-03-25 09:14:2582#include "device/bluetooth/bluetooth_adapter_factory.h"
83#include "device/bluetooth/test/mock_bluetooth_adapter.h"
Hajime Hoshi925793e72019-11-26 07:58:5584#include "media/base/media_switches.h"
Carlos Caballero8b114db2020-08-13 08:57:0385#include "mojo/public/cpp/bindings/message.h"
86#include "mojo/public/cpp/bindings/pending_remote.h"
87#include "mojo/public/cpp/bindings/remote.h"
arthursonzognie385b7b2019-09-02 11:11:5388#include "net/base/filename_util.h"
Arthur Sonzogni620cec62018-12-13 13:08:5789#include "net/dns/mock_host_resolver.h"
Lowell Mannersb3b30c22019-07-26 11:31:4190#include "net/test/embedded_test_server/controllable_http_response.h"
Arthur Sonzogni620cec62018-12-13 13:08:5791#include "net/test/embedded_test_server/embedded_test_server.h"
Kouhei Ueno0cf9a1a2019-11-19 10:03:5892#include "net/test/spawned_test_server/spawned_test_server.h"
93#include "net/test/test_data_directory.h"
Kouhei Uenoe0688712019-11-08 01:00:1494#include "services/device/public/cpp/test/fake_sensor_and_provider.h"
Kouhei Ueno7b6f3cd02019-09-09 04:48:5095#include "services/device/public/cpp/test/scoped_geolocation_overrider.h"
Yuzu Saijo698e4342020-04-06 03:12:0596#include "services/device/public/mojom/vibration_manager.mojom.h"
Yuzu Saijob0f001b22020-04-08 04:07:0497#include "services/service_manager/public/cpp/interface_provider.h"
arthursonzogni2f84dd62019-06-05 09:47:1298#include "testing/gmock/include/gmock/gmock.h"
Anton Bikineevf62d1bf2021-05-15 17:56:0799#include "third_party/abseil-cpp/absl/types/optional.h"
Sreeja Kamishetty92006e02021-02-05 05:18:11100#include "third_party/blink/public/common/device_memory/approximated_device_memory.h"
Harkiran Bolaria875dd0d2020-09-15 18:10:46101#include "third_party/blink/public/common/features.h"
Lowell Manners5cd4de42019-06-13 11:12:22102#include "third_party/blink/public/common/scheduler/web_scheduler_tracked_feature.h"
Stephen Chenney91a186b2021-03-23 10:42:01103#include "third_party/blink/public/common/switches.h"
Yuzu Saijob0f001b22020-04-08 04:07:04104#include "third_party/blink/public/mojom/app_banner/app_banner.mojom.h"
arthursonzogni2f84dd62019-06-05 09:47:12105
Rakina Zata Amnic7bc82632019-12-09 05:21:22106using testing::_;
arthursonzogni2f84dd62019-06-05 09:47:12107using testing::Each;
Hajime Hoshif9eba2b2019-10-02 08:27:42108using testing::ElementsAre;
arthursonzogni2f84dd62019-06-05 09:47:12109using testing::Not;
Hajime Hoshi5e86bc82019-11-26 05:41:12110using testing::UnorderedElementsAreArray;
Arthur Sonzogni620cec62018-12-13 13:08:57111
112namespace content {
113
114namespace {
115
[email protected]54eaf622019-11-25 12:36:03116// hash for std::unordered_map.
117struct FeatureHash {
118 size_t operator()(base::Feature feature) const {
119 return base::FastHash(feature.name);
120 }
121};
122
123// compare operator for std::unordered_map.
124struct FeatureEqualOperator {
125 bool operator()(base::Feature feature1, base::Feature feature2) const {
126 return std::strcmp(feature1.name, feature2.name) == 0;
127 }
128};
129
Yuzu Saijo6ddce412021-08-17 05:09:15130class DOMContentLoadedObserver : public WebContentsObserver {
131 public:
132 explicit DOMContentLoadedObserver(RenderFrameHostImpl* render_frame_host)
133 : WebContentsObserver(
134 WebContents::FromRenderFrameHost(render_frame_host)),
135 render_frame_host_(render_frame_host) {}
136
137 void DOMContentLoaded(RenderFrameHost* render_frame_host) override {
138 if (render_frame_host_ == render_frame_host)
139 run_loop_.Quit();
140 }
141
142 void Wait() {
143 if (render_frame_host_->IsDOMContentLoaded())
144 run_loop_.Quit();
145 run_loop_.Run();
146 }
147
148 private:
149 RenderFrameHostImpl* render_frame_host_;
150 base::RunLoop run_loop_;
151};
152
153void WaitForDOMContentLoaded(RenderFrameHostImpl* rfh) {
154 DOMContentLoadedObserver observer(rfh);
155 observer.Wait();
156}
157
Arthur Sonzogni620cec62018-12-13 13:08:57158// Test about the BackForwardCache.
Hajime Hoshi765845d62020-02-21 02:56:21159class BackForwardCacheBrowserTest : public ContentBrowserTest,
160 public WebContentsObserver {
Alexander Timin8304ddd942019-09-02 15:53:59161 public:
Carlos Caballero0e2fff922020-09-15 12:52:19162 ~BackForwardCacheBrowserTest() override {
163 if (fail_for_unexpected_messages_while_cached_) {
Fergal Daly2e36c62fb2021-04-30 11:49:44164 // If this is triggered, see
Peter Kasting977345832021-07-29 14:05:59165 // tools/metrics/histograms/metadata/navigation/histograms.xml for
Fergal Daly2e36c62fb2021-04-30 11:49:44166 // which values correspond which messages.
167 EXPECT_THAT(histogram_tester_.GetAllSamples(
168 "BackForwardCache.UnexpectedRendererToBrowserMessage."
169 "InterfaceName"),
170 testing::ElementsAre());
Carlos Caballero0e2fff922020-09-15 12:52:19171 }
172 }
Alexander Timin8304ddd942019-09-02 15:53:59173
Arthur Sonzogni620cec62018-12-13 13:08:57174 protected:
Hajime Hoshi765845d62020-02-21 02:56:21175 using UkmMetrics = ukm::TestUkmRecorder::HumanReadableUkmMetrics;
176
177 // Disables checking metrics that are recorded recardless of the domains. By
178 // default, this class' Expect* function checks the metrics both for the
179 // specific domain and for all domains at the same time. In the case when the
180 // test results need to be different, call this function.
181 void DisableCheckingMetricsForAllSites() { check_all_sites_ = false; }
182
Arthur Sonzogni620cec62018-12-13 13:08:57183 void SetUpCommandLine(base::CommandLine* command_line) override {
Arthur Sonzognidc3d3b2a2021-08-06 13:13:23184 ContentBrowserTest::SetUpCommandLine(command_line);
185 mock_cert_verifier_.SetUpCommandLine(command_line);
186
Kouhei Ueno01b0f1192019-08-14 05:28:07187 base::CommandLine::ForCurrentProcess()->AppendSwitch(
188 switches::kUseFakeUIForMediaStream);
arthursonzognie385b7b2019-09-02 11:11:53189 base::CommandLine::ForCurrentProcess()->AppendSwitch(
Rakina Zata Amni06343cc2019-10-11 01:33:23190 switches::kEnableExperimentalWebPlatformFeatures);
[email protected]54eaf622019-11-25 12:36:03191 // TODO(sreejakshetty): Initialize ScopedFeatureLists from test constructor.
192 EnableFeatureAndSetParams(features::kBackForwardCache,
193 "TimeToLiveInBackForwardCacheInSeconds", "3600");
Carlos Caballero8b114db2020-08-13 08:57:03194 EnableFeatureAndSetParams(features::kBackForwardCache,
Carlos Caballero0e2fff922020-09-15 12:52:19195 "message_handling_when_cached", "log");
Rakina Zata Amni95a2a91d2020-07-14 12:41:44196 EnableFeatureAndSetParams(
197 features::kBackForwardCache, "enable_same_site",
198 same_site_back_forward_cache_enabled_ ? "true" : "false");
Rakina Zata Amniff89a032020-08-14 16:48:50199 EnableFeatureAndSetParams(
200 features::kBackForwardCache, "skip_same_site_if_unload_exists",
201 skip_same_site_if_unload_exists_ ? "true" : "false");
Minoru Chikamune1a0a99dc2021-06-09 15:39:50202 EnableFeatureAndSetParams(features::kBackForwardCache, "unload_support",
203 unload_support_);
Harkiran Bolaria875dd0d2020-09-15 18:10:46204 EnableFeatureAndSetParams(
Yuzu Saijo948c2ce2021-02-18 16:16:43205 features::kBackForwardCache, "check_eligibility_after_pagehide",
206 check_eligibility_after_pagehide_ ? "true" : "false");
207 EnableFeatureAndSetParams(
Harkiran Bolaria875dd0d2020-09-15 18:10:46208 blink::features::kLogUnexpectedIPCPostedToBackForwardCachedDocuments,
209 "delay_before_tracking_ms", "0");
Yuzu Saijo6ddce412021-08-17 05:09:15210 EnableFeatureAndSetParams(
211 blink::features::kLoadingTasksUnfreezable, "max_buffered_bytes",
212 base::NumberToString(kMaxBufferedBytesPerRequest));
213 EnableFeatureAndSetParams(
214 blink::features::kLoadingTasksUnfreezable,
215 "max_buffered_bytes_per_process",
216 base::NumberToString(kMaxBufferedBytesPerProcess));
217 EnableFeatureAndSetParams(
218 blink::features::kLoadingTasksUnfreezable,
219 "grace_period_to_finish_loading_in_seconds",
220 base::NumberToString(kGracePeriodToFinishLoading.InSeconds()));
[email protected]42e682e52019-12-05 04:13:46221#if defined(OS_ANDROID)
222 EnableFeatureAndSetParams(features::kBackForwardCache,
223 "process_binding_strength", "NORMAL");
224#endif
Sreeja Kamishetty92006e02021-02-05 05:18:11225 // Allow BackForwardCache for all devices regardless of their memory.
John Abd-El-Malek3c868c292021-02-19 20:00:09226 DisableFeature(features::kBackForwardCacheMemoryControls);
Sreeja Kamishetty92006e02021-02-05 05:18:11227
[email protected]54eaf622019-11-25 12:36:03228 SetupFeaturesAndParameters();
Alexander Timin8304ddd942019-09-02 15:53:59229
Hajime Hoshi925793e72019-11-26 07:58:55230 command_line->AppendSwitchASCII(
231 switches::kAutoplayPolicy,
232 switches::autoplay::kNoUserGestureRequiredPolicy);
Stephen Chenney91a186b2021-03-23 10:42:01233 // Unfortunately needed for one test on slow bots, TextInputStateUpdated,
234 // where deferred commits delays input too much.
235 command_line->AppendSwitch(blink::switches::kAllowPreCommitInput);
Arthur Sonzognidc3d3b2a2021-08-06 13:13:23236 }
237
238 void SetUpInProcessBrowserTestFixture() override {
239 ContentBrowserTest::SetUpInProcessBrowserTestFixture();
240 mock_cert_verifier_.SetUpInProcessBrowserTestFixture();
241 }
242
243 void TearDownInProcessBrowserTestFixture() override {
244 ContentBrowserTest::TearDownInProcessBrowserTestFixture();
245 mock_cert_verifier_.TearDownInProcessBrowserTestFixture();
Arthur Sonzogni620cec62018-12-13 13:08:57246 }
247
[email protected]54eaf622019-11-25 12:36:03248 void SetupFeaturesAndParameters() {
249 std::vector<base::test::ScopedFeatureList::FeatureAndParams>
250 enabled_features;
251
Fergal Dalyb0693732021-03-15 14:11:32252 for (auto& features_with_param : features_with_params_) {
253 enabled_features.emplace_back(features_with_param.first,
254 features_with_param.second);
[email protected]54eaf622019-11-25 12:36:03255 }
256
257 feature_list_.InitWithFeaturesAndParameters(enabled_features,
Yuzu Saijo1a476612019-12-02 07:57:16258 disabled_features_);
[email protected]54eaf622019-11-25 12:36:03259 }
260
261 void EnableFeatureAndSetParams(base::Feature feature,
262 std::string param_name,
263 std::string param_value) {
264 features_with_params_[feature][param_name] = param_value;
Lowell Manners0a0419c2019-09-23 08:15:50265 }
Alexander Timin8304ddd942019-09-02 15:53:59266
Yuzu Saijo1a476612019-12-02 07:57:16267 void DisableFeature(base::Feature feature) {
268 disabled_features_.push_back(feature);
269 }
270
Fergal Dalydd2190472021-03-25 09:14:25271 void SetUp() override {
272 // Fake the BluetoothAdapter to say it's present.
273 // Used in WebBluetooth test.
274 adapter_ =
275 base::MakeRefCounted<testing::NiceMock<device::MockBluetoothAdapter>>();
276 device::BluetoothAdapterFactory::SetAdapterForTesting(adapter_);
277#if BUILDFLAG(IS_CHROMEOS_ASH)
278 // In CHROMEOS build, even when |adapter_| object is released at TearDown()
279 // it causes the test to fail on exit with an error indicating |adapter_| is
280 // leaked.
281 testing::Mock::AllowLeak(adapter_.get());
282#endif
283
284 ContentBrowserTest::SetUp();
285 }
286
287 void TearDown() override {
288 testing::Mock::VerifyAndClearExpectations(adapter_.get());
289 adapter_.reset();
290 ContentBrowserTest::TearDown();
291 }
292
Arthur Sonzogni620cec62018-12-13 13:08:57293 void SetUpOnMainThread() override {
Arthur Sonzognidc3d3b2a2021-08-06 13:13:23294 mock_cert_verifier_.mock_cert_verifier()->set_default_result(net::OK);
Arthur Sonzogni620cec62018-12-13 13:08:57295 host_resolver()->AddRule("*", "127.0.0.1");
Hajime Hoshi765845d62020-02-21 02:56:21296 // TestAutoSetUkmRecorder's constructor requires a sequenced context.
297 ukm_recorder_ = std::make_unique<ukm::TestAutoSetUkmRecorder>();
Kouhei Ueno01b0f1192019-08-14 05:28:07298 ContentBrowserTest::SetUpOnMainThread();
Arthur Sonzogni620cec62018-12-13 13:08:57299 }
300
Hajime Hoshi765845d62020-02-21 02:56:21301 void TearDownOnMainThread() override {
302 ukm_recorder_.reset();
303 ContentBrowserTest::TearDownOnMainThread();
304 }
305
Arthur Sonzogni620cec62018-12-13 13:08:57306 WebContentsImpl* web_contents() const {
307 return static_cast<WebContentsImpl*>(shell()->web_contents());
308 }
309
310 RenderFrameHostImpl* current_frame_host() {
311 return web_contents()->GetFrameTree()->root()->current_frame_host();
312 }
313
Arthur Hemery549850f6e2019-10-01 13:17:43314 RenderFrameHostManager* render_frame_host_manager() {
315 return web_contents()->GetFrameTree()->root()->render_manager();
316 }
317
Lowell Manners75055a132019-10-11 10:30:29318 std::string DepictFrameTree(FrameTreeNode* node) {
319 return visualizer_.DepictFrameTree(node);
320 }
321
Harkiran Bolaria12818bc2020-11-03 22:44:27322 bool HistogramContainsIntValue(base::HistogramBase::Sample sample,
323 std::vector<base::Bucket> histogram_values) {
324 auto it = std::find_if(histogram_values.begin(), histogram_values.end(),
325 [sample](const base::Bucket& bucket) {
326 return bucket.min == static_cast<int>(sample);
327 });
328 return it != histogram_values.end();
329 }
330
Hajime Hoshib03d6ddf52019-11-21 09:41:24331 void ExpectOutcomeDidNotChange(base::Location location) {
332 EXPECT_EQ(expected_outcomes_,
333 histogram_tester_.GetAllSamples(
334 "BackForwardCache.HistoryNavigationOutcome"))
Hajime Hoshif9eba2b2019-10-02 08:27:42335 << location.ToString();
Hajime Hoshi765845d62020-02-21 02:56:21336
337 if (!check_all_sites_)
338 return;
339
340 EXPECT_EQ(expected_outcomes_,
341 histogram_tester_.GetAllSamples(
342 "BackForwardCache.AllSites.HistoryNavigationOutcome"))
343 << location.ToString();
344
345 std::string is_served_from_bfcache =
346 "BackForwardCache.IsServedFromBackForwardCache";
347 EXPECT_THAT(ukm_recorder_->GetMetrics("HistoryNavigation",
348 {is_served_from_bfcache}),
349 expected_ukm_outcomes_)
350 << location.ToString();
Hajime Hoshif9eba2b2019-10-02 08:27:42351 }
352
Fergal Daly09833062021-02-09 07:10:00353 void ExpectRestored(base::Location location) {
354 ExpectOutcome(BackForwardCacheMetrics::HistoryNavigationOutcome::kRestored,
355 location);
Fergal Daly6755cbf2021-02-12 03:06:58356 ExpectReasons({}, {}, {}, {}, location);
Fergal Daly09833062021-02-09 07:10:00357 }
358
Hajime Hoshi15f6b5012019-10-24 05:25:49359 void ExpectNotRestored(
Fergal Daly6755cbf2021-02-12 03:06:58360 std::vector<BackForwardCacheMetrics::NotRestoredReason> not_restored,
361 std::vector<blink::scheduler::WebSchedulerTrackedFeature> block_listed,
362 const std::vector<ShouldSwapBrowsingInstance>& not_swapped,
Fergal Daly23b8ae62021-03-30 05:43:46363 const std::vector<BackForwardCache::DisabledReason>&
364 disabled_for_render_frame_host,
Hajime Hoshi15f6b5012019-10-24 05:25:49365 base::Location location) {
Fergal Daly09833062021-02-09 07:10:00366 ExpectOutcome(
367 BackForwardCacheMetrics::HistoryNavigationOutcome::kNotRestored,
368 location);
Fergal Daly6755cbf2021-02-12 03:06:58369 ExpectReasons(not_restored, block_listed, not_swapped,
370 disabled_for_render_frame_host, location);
Hajime Hoshi45255602019-10-18 07:26:59371 }
372
Hajime Hoshib03d6ddf52019-11-21 09:41:24373 void ExpectNotRestoredDidNotChange(base::Location location) {
374 EXPECT_EQ(expected_not_restored_,
375 histogram_tester_.GetAllSamples(
376 "BackForwardCache.HistoryNavigationOutcome."
377 "NotRestoredReason"))
Hajime Hoshi45255602019-10-18 07:26:59378 << location.ToString();
Hajime Hoshi765845d62020-02-21 02:56:21379
380 std::string not_restored_reasons = "BackForwardCache.NotRestoredReasons";
381
382 if (!check_all_sites_)
383 return;
384
385 EXPECT_EQ(expected_not_restored_,
386 histogram_tester_.GetAllSamples(
387 "BackForwardCache.AllSites.HistoryNavigationOutcome."
388 "NotRestoredReason"))
389 << location.ToString();
390
391 EXPECT_THAT(
392 ukm_recorder_->GetMetrics("HistoryNavigation", {not_restored_reasons}),
393 expected_ukm_not_restored_reasons_)
394 << location.ToString();
Hajime Hoshi45255602019-10-18 07:26:59395 }
396
Hajime Hoshidac62b22019-10-30 13:50:54397 void ExpectBlocklistedFeature(
398 blink::scheduler::WebSchedulerTrackedFeature feature,
399 base::Location location) {
Rakina Zata Amni9fd73cc2020-10-03 09:06:59400 ExpectBlocklistedFeatures({feature}, location);
401 }
402
Fergal Daly09833062021-02-09 07:10:00403 void ExpectBrowsingInstanceNotSwappedReason(ShouldSwapBrowsingInstance reason,
404 base::Location location) {
405 ExpectBrowsingInstanceNotSwappedReasons({reason}, location);
406 }
407
Hajime Hoshid3f99e72019-10-09 06:21:25408 void ExpectEvictedAfterCommitted(
409 std::vector<BackForwardCacheMetrics::EvictedAfterDocumentRestoredReason>
410 reasons,
411 base::Location location) {
412 for (BackForwardCacheMetrics::EvictedAfterDocumentRestoredReason reason :
413 reasons) {
414 base::HistogramBase::Sample sample = base::HistogramBase::Sample(reason);
415 AddSampleToBuckets(&expected_eviction_after_committing_, sample);
416 }
417
Hajime Hoshi5e86bc82019-11-26 05:41:12418 EXPECT_THAT(histogram_tester_.GetAllSamples(
419 "BackForwardCache.EvictedAfterDocumentRestoredReason"),
420 UnorderedElementsAreArray(expected_eviction_after_committing_))
Hajime Hoshid3f99e72019-10-09 06:21:25421 << location.ToString();
Hajime Hoshi765845d62020-02-21 02:56:21422 if (!check_all_sites_)
423 return;
424
425 EXPECT_THAT(
426 histogram_tester_.GetAllSamples(
427 "BackForwardCache.AllSites.EvictedAfterDocumentRestoredReason"),
428 UnorderedElementsAreArray(expected_eviction_after_committing_))
429 << location.ToString();
Hajime Hoshid3f99e72019-10-09 06:21:25430 }
431
Yuzu Saijo6a935bbd2019-11-01 16:31:38432 void EvictByJavaScript(RenderFrameHostImpl* rfh) {
433 // Run JavaScript on a page in the back-forward cache. The page should be
434 // evicted. As the frame is deleted, ExecJs returns false without executing.
Carlos Caballero8b114db2020-08-13 08:57:03435 // Run without user gesture to prevent UpdateUserActivationState message
436 // being sent back to browser.
437 EXPECT_FALSE(
438 ExecJs(rfh, "console.log('hi');", EXECUTE_SCRIPT_NO_USER_GESTURE));
Yuzu Saijo6a935bbd2019-11-01 16:31:38439 }
440
Yuzu Saijoecb779c2019-11-06 12:59:37441 void StartRecordingEvents(RenderFrameHostImpl* rfh) {
442 EXPECT_TRUE(ExecJs(rfh, R"(
443 window.testObservedEvents = [];
444 let event_list = [
445 'visibilitychange',
446 'pagehide',
447 'pageshow',
448 'freeze',
449 'resume',
Rakina Zata Amni67d49f22020-10-10 01:57:34450 'unload',
Yuzu Saijoecb779c2019-11-06 12:59:37451 ];
452 for (event_name of event_list) {
453 let result = event_name;
454 window.addEventListener(event_name, event => {
455 if (event.persisted)
Alexander Timin44ccede2020-01-23 09:00:34456 result += '.persisted';
457 window.testObservedEvents.push('window.' + result);
Yuzu Saijoecb779c2019-11-06 12:59:37458 });
459 document.addEventListener(event_name,
Alexander Timin44ccede2020-01-23 09:00:34460 () => window.testObservedEvents.push('document.' + result));
Yuzu Saijoecb779c2019-11-06 12:59:37461 }
462 )"));
463 }
464
Alexander Timin44ccede2020-01-23 09:00:34465 void MatchEventList(RenderFrameHostImpl* rfh,
466 base::ListValue list,
467 base::Location location = base::Location::Current()) {
468 EXPECT_EQ(list, EvalJs(rfh, "window.testObservedEvents"))
469 << location.ToString();
Yuzu Saijoecb779c2019-11-06 12:59:37470 }
471
Fergal Daly637c4522019-11-22 00:21:31472 // Creates a minimal HTTPS server, accessible through https_server().
473 // Returns a pointer to the server.
474 net::EmbeddedTestServer* CreateHttpsServer() {
475 https_server_ = std::make_unique<net::EmbeddedTestServer>(
476 net::EmbeddedTestServer::TYPE_HTTPS);
477 https_server_->AddDefaultHandlers(GetTestDataFilePath());
478 https_server_->SetSSLConfig(net::EmbeddedTestServer::CERT_OK);
479 return https_server();
480 }
481
482 net::EmbeddedTestServer* https_server() { return https_server_.get(); }
483
Rakina Zata Amni7a8fca52020-08-20 07:59:31484 void ExpectTotalCount(base::StringPiece name,
485 base::HistogramBase::Count count) {
486 histogram_tester_.ExpectTotalCount(name, count);
487 }
488
489 template <typename T>
490 void ExpectBucketCount(base::StringPiece name,
491 T sample,
492 base::HistogramBase::Count expected_count) {
493 histogram_tester_.ExpectBucketCount(name, sample, expected_count);
494 }
495
Carlos Caballero0e2fff922020-09-15 12:52:19496 // Do not fail this test if a message from a renderer arrives at the browser
497 // for a cached page.
498 void DoNotFailForUnexpectedMessagesWhileCached() {
499 fail_for_unexpected_messages_while_cached_ = false;
500 }
501
Yuzu Saijo6ddce412021-08-17 05:09:15502 // Navigates to a page at |page_url| with an img element with src set to
503 // "image.png".
504 RenderFrameHostImpl* NavigateToPageWithImage(const GURL& page_url) {
505 EXPECT_TRUE(NavigateToURL(shell(), page_url));
506 RenderFrameHostImpl* rfh = current_frame_host();
507 // Wait for the document to load DOM to ensure that kLoading is not
508 // one of the reasons why the document wasn't cached.
509 WaitForDOMContentLoaded(rfh);
510
511 EXPECT_TRUE(ExecJs(rfh, R"(
512 var image = document.createElement("img");
513 image.src = "image.png";
514 document.body.appendChild(image);
515
516 var image_load_status = new Promise((resolve, reject) => {
517 image.onload = () => { resolve("loaded"); }
518 image.onerror = () => { resolve("error"); }
519 });
520 )"));
521 return rfh;
522 }
523
Alexander Timin8c51c422020-01-22 13:52:07524 base::HistogramTester histogram_tester_;
525
Rakina Zata Amni95a2a91d2020-07-14 12:41:44526 bool same_site_back_forward_cache_enabled_ = true;
Rakina Zata Amniff89a032020-08-14 16:48:50527 bool skip_same_site_if_unload_exists_ = false;
Yuzu Saijo948c2ce2021-02-18 16:16:43528 bool check_eligibility_after_pagehide_ = false;
Minoru Chikamune1a0a99dc2021-06-09 15:39:50529 std::string unload_support_ = "always";
Rakina Zata Amni95a2a91d2020-07-14 12:41:44530
Yuzu Saijo6ddce412021-08-17 05:09:15531 const int kMaxBufferedBytesPerRequest = 7000;
532 const int kMaxBufferedBytesPerProcess = 10000;
533 const base::TimeDelta kGracePeriodToFinishLoading =
534 base::TimeDelta::FromSeconds(5);
535
Arthur Sonzogni620cec62018-12-13 13:08:57536 private:
Hajime Hoshi0d93f3b2019-10-08 07:01:50537 void AddSampleToBuckets(std::vector<base::Bucket>* buckets,
538 base::HistogramBase::Sample sample) {
539 auto it = std::find_if(
540 buckets->begin(), buckets->end(),
541 [sample](const base::Bucket& bucket) { return bucket.min == sample; });
542 if (it == buckets->end()) {
543 buckets->push_back(base::Bucket(sample, 1));
544 } else {
545 it->count++;
546 }
547 }
548
Fergal Daly09833062021-02-09 07:10:00549 void ExpectOutcome(BackForwardCacheMetrics::HistoryNavigationOutcome outcome,
550 base::Location location) {
551 base::HistogramBase::Sample sample = base::HistogramBase::Sample(outcome);
552 AddSampleToBuckets(&expected_outcomes_, sample);
553
554 EXPECT_THAT(histogram_tester_.GetAllSamples(
555 "BackForwardCache.HistoryNavigationOutcome"),
556 UnorderedElementsAreArray(expected_outcomes_))
557 << location.ToString();
Fergal Daly09833062021-02-09 07:10:00558 if (!check_all_sites_)
559 return;
560
561 EXPECT_THAT(histogram_tester_.GetAllSamples(
562 "BackForwardCache.AllSites.HistoryNavigationOutcome"),
563 UnorderedElementsAreArray(expected_outcomes_))
564 << location.ToString();
565
566 std::string is_served_from_bfcache =
567 "BackForwardCache.IsServedFromBackForwardCache";
568 bool ukm_outcome =
569 outcome == BackForwardCacheMetrics::HistoryNavigationOutcome::kRestored;
570 expected_ukm_outcomes_.push_back(
571 {{is_served_from_bfcache, static_cast<int64_t>(ukm_outcome)}});
572 EXPECT_THAT(ukm_recorder_->GetMetrics("HistoryNavigation",
573 {is_served_from_bfcache}),
574 expected_ukm_outcomes_)
575 << location.ToString();
576 }
577
Fergal Daly6755cbf2021-02-12 03:06:58578 void ExpectReasons(
579 std::vector<BackForwardCacheMetrics::NotRestoredReason> not_restored,
580 std::vector<blink::scheduler::WebSchedulerTrackedFeature> block_listed,
581 const std::vector<ShouldSwapBrowsingInstance>& not_swapped,
Fergal Daly23b8ae62021-03-30 05:43:46582 const std::vector<BackForwardCache::DisabledReason>&
583 disabled_for_render_frame_host,
Fergal Daly6755cbf2021-02-12 03:06:58584 base::Location location) {
585 // Check that the expected reasons are consistent.
586 bool expect_blocklisted =
587 std::count(
588 not_restored.begin(), not_restored.end(),
589 BackForwardCacheMetrics::NotRestoredReason::kBlocklistedFeatures) >
590 0;
591 bool has_blocklisted = block_listed.size() > 0;
592 EXPECT_EQ(expect_blocklisted, has_blocklisted);
593 bool expect_disabled_for_render_frame_host =
594 std::count(not_restored.begin(), not_restored.end(),
595 BackForwardCacheMetrics::NotRestoredReason::
596 kDisableForRenderFrameHostCalled) > 0;
597 bool has_disabled_for_render_frame_host =
598 disabled_for_render_frame_host.size() > 0;
599 EXPECT_EQ(expect_disabled_for_render_frame_host,
600 has_disabled_for_render_frame_host);
601
602 // Check that the reasons are as expected.
603 ExpectNotRestoredReasons(not_restored, location);
604 ExpectBlocklistedFeatures(block_listed, location);
605 ExpectBrowsingInstanceNotSwappedReasons(not_swapped, location);
606 ExpectDisabledWithReasons(disabled_for_render_frame_host, location);
607 }
608
609 void ExpectNotRestoredReasons(
610 std::vector<BackForwardCacheMetrics::NotRestoredReason> reasons,
611 base::Location location) {
612 uint64_t not_restored_reasons_bits = 0;
613 for (BackForwardCacheMetrics::NotRestoredReason reason : reasons) {
614 base::HistogramBase::Sample sample = base::HistogramBase::Sample(reason);
615 AddSampleToBuckets(&expected_not_restored_, sample);
616 not_restored_reasons_bits |= 1ull << static_cast<int>(reason);
617 }
618
619 EXPECT_THAT(histogram_tester_.GetAllSamples(
620 "BackForwardCache.HistoryNavigationOutcome."
621 "NotRestoredReason"),
622 UnorderedElementsAreArray(expected_not_restored_))
623 << location.ToString();
624
625 if (!check_all_sites_)
626 return;
627
628 EXPECT_THAT(histogram_tester_.GetAllSamples(
629 "BackForwardCache.AllSites.HistoryNavigationOutcome."
630 "NotRestoredReason"),
631 UnorderedElementsAreArray(expected_not_restored_))
632 << location.ToString();
633
634 std::string not_restored_reasons = "BackForwardCache.NotRestoredReasons";
635 expected_ukm_not_restored_reasons_.push_back(
636 {{not_restored_reasons, not_restored_reasons_bits}});
637 EXPECT_THAT(
638 ukm_recorder_->GetMetrics("HistoryNavigation", {not_restored_reasons}),
639 expected_ukm_not_restored_reasons_)
640 << location.ToString();
641 }
642
643 void ExpectBlocklistedFeatures(
644 std::vector<blink::scheduler::WebSchedulerTrackedFeature> features,
645 base::Location location) {
646 for (auto feature : features) {
647 base::HistogramBase::Sample sample = base::HistogramBase::Sample(feature);
648 AddSampleToBuckets(&expected_blocklisted_features_, sample);
649 }
650
651 EXPECT_THAT(histogram_tester_.GetAllSamples(
652 "BackForwardCache.HistoryNavigationOutcome."
653 "BlocklistedFeature"),
654 UnorderedElementsAreArray(expected_blocklisted_features_))
655 << location.ToString();
656
657 if (!check_all_sites_)
658 return;
659
660 EXPECT_THAT(histogram_tester_.GetAllSamples(
661 "BackForwardCache.AllSites.HistoryNavigationOutcome."
662 "BlocklistedFeature"),
663 UnorderedElementsAreArray(expected_blocklisted_features_))
664 << location.ToString();
665 }
666
Fergal Daly23b8ae62021-03-30 05:43:46667 void ExpectDisabledWithReasons(
668 const std::vector<BackForwardCache::DisabledReason>& reasons,
669 base::Location location) {
670 for (BackForwardCache::DisabledReason reason : reasons) {
671 base::HistogramBase::Sample sample = base::HistogramBase::Sample(
672 content::BackForwardCacheMetrics::MetricValue(reason));
Fergal Daly6755cbf2021-02-12 03:06:58673 AddSampleToBuckets(&expected_disabled_reasons_, sample);
674 }
675 EXPECT_THAT(histogram_tester_.GetAllSamples(
676 "BackForwardCache.HistoryNavigationOutcome."
Fergal Daly23b8ae62021-03-30 05:43:46677 "DisabledForRenderFrameHostReason2"),
Fergal Daly6755cbf2021-02-12 03:06:58678 UnorderedElementsAreArray(expected_disabled_reasons_))
679 << location.ToString();
680 }
681
682 void ExpectBrowsingInstanceNotSwappedReasons(
683 const std::vector<ShouldSwapBrowsingInstance>& reasons,
684 base::Location location) {
685 for (auto reason : reasons) {
686 base::HistogramBase::Sample sample = base::HistogramBase::Sample(reason);
687 AddSampleToBuckets(&expected_browsing_instance_not_swapped_reasons_,
688 sample);
689 }
690 EXPECT_THAT(histogram_tester_.GetAllSamples(
691 "BackForwardCache.HistoryNavigationOutcome."
692 "BrowsingInstanceNotSwappedReason"),
693 UnorderedElementsAreArray(
694 expected_browsing_instance_not_swapped_reasons_))
695 << location.ToString();
696 if (!check_all_sites_)
697 return;
698
699 EXPECT_THAT(histogram_tester_.GetAllSamples(
700 "BackForwardCache.AllSites.HistoryNavigationOutcome."
701 "BrowsingInstanceNotSwappedReason"),
702 UnorderedElementsAreArray(
703 expected_browsing_instance_not_swapped_reasons_))
704 << location.ToString();
705 }
706
Arthur Sonzognidc3d3b2a2021-08-06 13:13:23707 content::ContentMockCertVerifier mock_cert_verifier_;
708
Arthur Sonzogni620cec62018-12-13 13:08:57709 base::test::ScopedFeatureList feature_list_;
Hajime Hoshif9eba2b2019-10-02 08:27:42710
Lowell Manners75055a132019-10-11 10:30:29711 FrameTreeVisualizer visualizer_;
Hajime Hoshif9eba2b2019-10-02 08:27:42712 std::vector<base::Bucket> expected_outcomes_;
Hajime Hoshi45255602019-10-18 07:26:59713 std::vector<base::Bucket> expected_not_restored_;
Hajime Hoshidac62b22019-10-30 13:50:54714 std::vector<base::Bucket> expected_blocklisted_features_;
Hajime Hoshi0d93f3b2019-10-08 07:01:50715 std::vector<base::Bucket> expected_disabled_reasons_;
Hajime Hoshi8fd675e02020-10-29 14:28:41716 std::vector<base::Bucket> expected_browsing_instance_not_swapped_reasons_;
Hajime Hoshid3f99e72019-10-09 06:21:25717 std::vector<base::Bucket> expected_eviction_after_committing_;
Fergal Daly637c4522019-11-22 00:21:31718 std::unique_ptr<net::EmbeddedTestServer> https_server_;
[email protected]54eaf622019-11-25 12:36:03719 std::unordered_map<base::Feature,
720 std::map<std::string, std::string>,
721 FeatureHash,
722 FeatureEqualOperator>
723 features_with_params_;
Yuzu Saijo1a476612019-12-02 07:57:16724 std::vector<base::Feature> disabled_features_;
Hajime Hoshi765845d62020-02-21 02:56:21725
726 std::vector<UkmMetrics> expected_ukm_outcomes_;
727 std::vector<UkmMetrics> expected_ukm_not_restored_reasons_;
728 std::unique_ptr<ukm::TestAutoSetUkmRecorder> ukm_recorder_;
729
730 // Indicates whether metrics for all sites regardless of the domains are
731 // checked or not.
732 bool check_all_sites_ = true;
Carlos Caballero0e2fff922020-09-15 12:52:19733 // Whether we should fail the test if a message arrived at the browser from a
734 // renderer for a bfcached page.
735 bool fail_for_unexpected_messages_while_cached_ = true;
Fergal Dalydd2190472021-03-25 09:14:25736
737 scoped_refptr<device::MockBluetoothAdapter> adapter_;
Arthur Sonzogni620cec62018-12-13 13:08:57738};
739
arthursonzogni2f84dd62019-06-05 09:47:12740// Match RenderFrameHostImpl* that are in the BackForwardCache.
741MATCHER(InBackForwardCache, "") {
Hajime Hoshibbc509c2020-04-06 08:55:08742 return arg->IsInBackForwardCache();
arthursonzogni2f84dd62019-06-05 09:47:12743}
744
745// Match RenderFrameDeleteObserver* which observed deletion of the RenderFrame.
746MATCHER(Deleted, "") {
747 return arg->deleted();
748}
749
750// Helper function to pass an initializer list to the EXPECT_THAT macro. This is
751// indeed the identity function.
752std::initializer_list<RenderFrameHostImpl*> Elements(
753 std::initializer_list<RenderFrameHostImpl*> t) {
754 return t;
755}
756
Alexander Timinfa953bff2019-12-05 14:31:49757// Execute a custom callback when navigation is ready to commit. This is
Hajime Hoshie9262d32019-08-28 07:40:23758// useful for simulating race conditions happening when a page enters the
759// BackForwardCache and receive inflight messages sent when it wasn't frozen
760// yet.
Alexander Timinfa953bff2019-12-05 14:31:49761class ReadyToCommitNavigationCallback : public WebContentsObserver {
Hajime Hoshie9262d32019-08-28 07:40:23762 public:
Alexander Timinfa953bff2019-12-05 14:31:49763 ReadyToCommitNavigationCallback(
Hajime Hoshie9262d32019-08-28 07:40:23764 WebContents* content,
Alexander Timinfa953bff2019-12-05 14:31:49765 base::OnceCallback<void(NavigationHandle*)> callback)
Hajime Hoshie9262d32019-08-28 07:40:23766 : WebContentsObserver(content), callback_(std::move(callback)) {}
767
768 private:
769 // WebContentsObserver:
Alexander Timinfa953bff2019-12-05 14:31:49770 void ReadyToCommitNavigation(NavigationHandle* navigation_handle) override {
Hajime Hoshie9262d32019-08-28 07:40:23771 if (callback_)
Alexander Timinfa953bff2019-12-05 14:31:49772 std::move(callback_).Run(navigation_handle);
Hajime Hoshie9262d32019-08-28 07:40:23773 }
774
Alexander Timinfa953bff2019-12-05 14:31:49775 base::OnceCallback<void(NavigationHandle*)> callback_;
Hajime Hoshie9262d32019-08-28 07:40:23776
Alexander Timinfa953bff2019-12-05 14:31:49777 DISALLOW_COPY_AND_ASSIGN(ReadyToCommitNavigationCallback);
Hajime Hoshie9262d32019-08-28 07:40:23778};
779
Carlos Caballero91fffb22019-10-29 15:24:30780class FirstVisuallyNonEmptyPaintObserver : public WebContentsObserver {
781 public:
782 explicit FirstVisuallyNonEmptyPaintObserver(WebContents* contents)
783 : WebContentsObserver(contents) {}
784 void DidFirstVisuallyNonEmptyPaint() override {
785 if (observed_)
786 return;
787 observed_ = true;
788 run_loop_.Quit();
789 }
790
791 bool did_fire() const { return observed_; }
792
793 void Wait() { run_loop_.Run(); }
794
795 private:
796 bool observed_ = false;
797 base::RunLoop run_loop_{base::RunLoop::Type::kNestableTasksAllowed};
798};
799
800void WaitForFirstVisuallyNonEmptyPaint(WebContents* contents) {
801 if (contents->CompletedFirstVisuallyNonEmptyPaint())
802 return;
803 FirstVisuallyNonEmptyPaintObserver observer(contents);
804 observer.Wait();
805}
806
Carlos Caballero1215f882019-10-29 15:58:43807class ThemeColorObserver : public WebContentsObserver {
808 public:
809 explicit ThemeColorObserver(WebContents* contents)
810 : WebContentsObserver(contents) {}
Peter Kastingb14e5782020-01-06 23:55:04811 void DidChangeThemeColor() override { observed_ = true; }
Carlos Caballero1215f882019-10-29 15:58:43812
813 bool did_fire() const { return observed_; }
814
815 private:
816 bool observed_ = false;
Carlos Caballero1215f882019-10-29 15:58:43817};
818
Carlos Caballero8b114db2020-08-13 08:57:03819class PageLifecycleStateManagerTestDelegate
820 : public PageLifecycleStateManager::TestDelegate {
821 public:
822 explicit PageLifecycleStateManagerTestDelegate(
823 PageLifecycleStateManager* manager)
824 : manager_(manager) {
825 manager->SetDelegateForTesting(this);
826 }
827
828 ~PageLifecycleStateManagerTestDelegate() override {
Carlos Caballero8f4c0c662020-12-01 19:26:07829 if (manager_)
830 manager_->SetDelegateForTesting(nullptr);
Carlos Caballero8b114db2020-08-13 08:57:03831 }
832
833 void WaitForInBackForwardCacheAck() {
Carlos Caballero8f4c0c662020-12-01 19:26:07834 DCHECK(manager_);
Carlos Caballero8b114db2020-08-13 08:57:03835 if (manager_->last_acknowledged_state().is_in_back_forward_cache) {
836 return;
837 }
838 base::RunLoop loop;
839 store_in_back_forward_cache_ack_received_ = loop.QuitClosure();
840 loop.Run();
841 }
842
843 void OnStoreInBackForwardCacheSent(base::OnceClosure cb) {
844 store_in_back_forward_cache_sent_ = std::move(cb);
845 }
846
Carlos Caballero8f4c0c662020-12-01 19:26:07847 void OnDisableJsEvictionSent(base::OnceClosure cb) {
848 disable_eviction_sent_ = std::move(cb);
849 }
850
Carlos Caballero8b114db2020-08-13 08:57:03851 void OnRestoreFromBackForwardCacheSent(base::OnceClosure cb) {
852 restore_from_back_forward_cache_sent_ = std::move(cb);
853 }
854
855 private:
856 void OnLastAcknowledgedStateChanged(
857 const blink::mojom::PageLifecycleState& old_state,
858 const blink::mojom::PageLifecycleState& new_state) override {
859 if (store_in_back_forward_cache_ack_received_ &&
860 new_state.is_in_back_forward_cache)
861 std::move(store_in_back_forward_cache_ack_received_).Run();
862 }
863
864 void OnUpdateSentToRenderer(
865 const blink::mojom::PageLifecycleState& new_state) override {
866 if (store_in_back_forward_cache_sent_ &&
867 new_state.is_in_back_forward_cache) {
868 std::move(store_in_back_forward_cache_sent_).Run();
869 }
870
Carlos Caballero8f4c0c662020-12-01 19:26:07871 if (disable_eviction_sent_ && new_state.eviction_enabled == false) {
872 std::move(disable_eviction_sent_).Run();
873 }
874
Carlos Caballero8b114db2020-08-13 08:57:03875 if (restore_from_back_forward_cache_sent_ &&
876 !new_state.is_in_back_forward_cache) {
877 std::move(restore_from_back_forward_cache_sent_).Run();
878 }
879 }
880
Carlos Caballero8f4c0c662020-12-01 19:26:07881 void OnDeleted() override { manager_ = nullptr; }
882
883 PageLifecycleStateManager* manager_;
Carlos Caballero8b114db2020-08-13 08:57:03884 base::OnceClosure store_in_back_forward_cache_sent_;
885 base::OnceClosure store_in_back_forward_cache_ack_received_;
886 base::OnceClosure restore_from_back_forward_cache_sent_;
Carlos Caballero8f4c0c662020-12-01 19:26:07887 base::OnceClosure disable_eviction_sent_;
Carlos Caballero8b114db2020-08-13 08:57:03888};
889
Reilly Grant4b6aa442021-07-26 21:00:30890class FakeIdleTimeProvider : public IdleTimeProvider {
Wei Lee01971182020-09-18 09:15:21891 public:
892 FakeIdleTimeProvider() = default;
893 ~FakeIdleTimeProvider() override = default;
894 FakeIdleTimeProvider(const FakeIdleTimeProvider&) = delete;
895 FakeIdleTimeProvider& operator=(const FakeIdleTimeProvider&) = delete;
896
897 base::TimeDelta CalculateIdleTime() override {
898 return base::TimeDelta::FromSeconds(0);
899 }
900
901 bool CheckIdleStateIsLocked() override { return false; }
902};
903
Arthur Sonzogni620cec62018-12-13 13:08:57904} // namespace
905
906// Navigate from A to B and go back.
907IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, Basic) {
908 ASSERT_TRUE(embedded_test_server()->Start());
arthursonzogni72b66492019-11-04 12:24:33909 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
910 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
911 url::Origin origin_a = url::Origin::Create(url_a);
912 url::Origin origin_b = url::Origin::Create(url_b);
Arthur Sonzogni620cec62018-12-13 13:08:57913
914 // 1) Navigate to A.
arthursonzogni2f84dd62019-06-05 09:47:12915 EXPECT_TRUE(NavigateToURL(shell(), url_a));
Arthur Sonzogni620cec62018-12-13 13:08:57916 RenderFrameHostImpl* rfh_a = current_frame_host();
Hajime Hoshif53fa7ca2019-08-13 06:52:34917 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
Arthur Sonzogni620cec62018-12-13 13:08:57918
919 // 2) Navigate to B.
arthursonzogni2f84dd62019-06-05 09:47:12920 EXPECT_TRUE(NavigateToURL(shell(), url_b));
Arthur Sonzogni620cec62018-12-13 13:08:57921 RenderFrameHostImpl* rfh_b = current_frame_host();
Hajime Hoshif53fa7ca2019-08-13 06:52:34922 RenderFrameDeletedObserver delete_observer_rfh_b(rfh_b);
923 EXPECT_FALSE(delete_observer_rfh_a.deleted());
Hajime Hoshibbc509c2020-04-06 08:55:08924 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
Yuzu Saijo1710eeb2019-07-12 03:48:36925 EXPECT_EQ(rfh_a->GetVisibilityState(), PageVisibilityState::kHidden);
Lowell Manners960750f92019-08-09 12:30:31926 EXPECT_EQ(origin_a, rfh_a->GetLastCommittedOrigin());
927 EXPECT_EQ(origin_b, rfh_b->GetLastCommittedOrigin());
Hajime Hoshibbc509c2020-04-06 08:55:08928 EXPECT_FALSE(rfh_b->IsInBackForwardCache());
Yuzu Saijo1710eeb2019-07-12 03:48:36929 EXPECT_EQ(rfh_b->GetVisibilityState(), PageVisibilityState::kVisible);
Arthur Sonzogni620cec62018-12-13 13:08:57930
931 // 3) Go back to A.
932 web_contents()->GetController().GoBack();
933 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
Hajime Hoshif53fa7ca2019-08-13 06:52:34934 EXPECT_FALSE(delete_observer_rfh_a.deleted());
935 EXPECT_FALSE(delete_observer_rfh_b.deleted());
Lowell Manners960750f92019-08-09 12:30:31936 EXPECT_EQ(origin_a, rfh_a->GetLastCommittedOrigin());
937 EXPECT_EQ(origin_b, rfh_b->GetLastCommittedOrigin());
Arthur Sonzogni620cec62018-12-13 13:08:57938 EXPECT_EQ(rfh_a, current_frame_host());
Hajime Hoshibbc509c2020-04-06 08:55:08939 EXPECT_FALSE(rfh_a->IsInBackForwardCache());
Yuzu Saijo1710eeb2019-07-12 03:48:36940 EXPECT_EQ(rfh_a->GetVisibilityState(), PageVisibilityState::kVisible);
Hajime Hoshibbc509c2020-04-06 08:55:08941 EXPECT_TRUE(rfh_b->IsInBackForwardCache());
Yuzu Saijo1710eeb2019-07-12 03:48:36942 EXPECT_EQ(rfh_b->GetVisibilityState(), PageVisibilityState::kHidden);
Hajime Hoshif9eba2b2019-10-02 08:27:42943
Fergal Daly09833062021-02-09 07:10:00944 ExpectRestored(FROM_HERE);
Arthur Sonzogni620cec62018-12-13 13:08:57945}
946
arthursonzogni1dddb712019-07-12 10:42:17947// Navigate from A to B and go back.
948IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, BasicDocumentInitiated) {
949 ASSERT_TRUE(embedded_test_server()->Start());
arthursonzogni72b66492019-11-04 12:24:33950 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
951 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
arthursonzogni1dddb712019-07-12 10:42:17952
953 // 1) Navigate to A.
954 EXPECT_TRUE(NavigateToURL(shell(), url_a));
955 RenderFrameHostImpl* rfh_a = current_frame_host();
Hajime Hoshif53fa7ca2019-08-13 06:52:34956 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
arthursonzogni1dddb712019-07-12 10:42:17957
958 // 2) Navigate to B.
959 EXPECT_TRUE(ExecJs(shell(), JsReplace("location = $1;", url_b.spec())));
960 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
961 RenderFrameHostImpl* rfh_b = current_frame_host();
Hajime Hoshif53fa7ca2019-08-13 06:52:34962 RenderFrameDeletedObserver delete_observer_rfh_b(rfh_b);
963 EXPECT_FALSE(delete_observer_rfh_a.deleted());
Hajime Hoshibbc509c2020-04-06 08:55:08964 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
965 EXPECT_FALSE(rfh_b->IsInBackForwardCache());
arthursonzogni1dddb712019-07-12 10:42:17966
967 // The two pages are using different BrowsingInstances.
968 EXPECT_FALSE(rfh_a->GetSiteInstance()->IsRelatedSiteInstance(
969 rfh_b->GetSiteInstance()));
970
971 // 3) Go back to A.
972 EXPECT_TRUE(ExecJs(shell(), "history.back();"));
973 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
Hajime Hoshif53fa7ca2019-08-13 06:52:34974 EXPECT_FALSE(delete_observer_rfh_a.deleted());
975 EXPECT_FALSE(delete_observer_rfh_b.deleted());
arthursonzogni1dddb712019-07-12 10:42:17976 EXPECT_EQ(rfh_a, current_frame_host());
Hajime Hoshibbc509c2020-04-06 08:55:08977 EXPECT_FALSE(rfh_a->IsInBackForwardCache());
978 EXPECT_TRUE(rfh_b->IsInBackForwardCache());
Hajime Hoshif9eba2b2019-10-02 08:27:42979
Fergal Daly09833062021-02-09 07:10:00980 ExpectRestored(FROM_HERE);
arthursonzogni1dddb712019-07-12 10:42:17981}
982
Lowell Manners21946052019-07-09 09:16:43983// Navigate from back and forward repeatedly.
984IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
Carlos Caballero0e2fff922020-09-15 12:52:19985 NavigateBackForwardRepeatedly) {
986 // Do not check for unexpected messages because the input task queue is not
987 // currently frozen, causing flakes in this test: crbug.com/1099395.
988 DoNotFailForUnexpectedMessagesWhileCached();
Lowell Manners21946052019-07-09 09:16:43989 ASSERT_TRUE(embedded_test_server()->Start());
arthursonzogni72b66492019-11-04 12:24:33990 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
991 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
Lowell Manners21946052019-07-09 09:16:43992
993 // 1) Navigate to A.
994 EXPECT_TRUE(NavigateToURL(shell(), url_a));
995 RenderFrameHostImpl* rfh_a = current_frame_host();
Hajime Hoshif53fa7ca2019-08-13 06:52:34996 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
Lowell Manners21946052019-07-09 09:16:43997
998 // 2) Navigate to B.
999 EXPECT_TRUE(NavigateToURL(shell(), url_b));
1000 RenderFrameHostImpl* rfh_b = current_frame_host();
Hajime Hoshif53fa7ca2019-08-13 06:52:341001 RenderFrameDeletedObserver delete_observer_rfh_b(rfh_b);
Hajime Hoshibbc509c2020-04-06 08:55:081002 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
1003 EXPECT_FALSE(rfh_b->IsInBackForwardCache());
Lowell Manners21946052019-07-09 09:16:431004
1005 // 3) Go back to A.
1006 web_contents()->GetController().GoBack();
1007 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
1008
1009 EXPECT_EQ(rfh_a, current_frame_host());
Hajime Hoshibbc509c2020-04-06 08:55:081010 EXPECT_FALSE(rfh_a->IsInBackForwardCache());
1011 EXPECT_TRUE(rfh_b->IsInBackForwardCache());
Lowell Manners21946052019-07-09 09:16:431012
Fergal Daly09833062021-02-09 07:10:001013 ExpectRestored(FROM_HERE);
Hajime Hoshif9eba2b2019-10-02 08:27:421014
Lowell Manners21946052019-07-09 09:16:431015 // 4) Go forward to B.
1016 web_contents()->GetController().GoForward();
1017 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
1018
1019 EXPECT_EQ(rfh_b, current_frame_host());
Hajime Hoshibbc509c2020-04-06 08:55:081020 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
1021 EXPECT_FALSE(rfh_b->IsInBackForwardCache());
Lowell Manners21946052019-07-09 09:16:431022
Fergal Daly09833062021-02-09 07:10:001023 ExpectRestored(FROM_HERE);
Hajime Hoshif9eba2b2019-10-02 08:27:421024
Lowell Manners21946052019-07-09 09:16:431025 // 5) Go back to A.
1026 web_contents()->GetController().GoBack();
1027 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
1028
1029 EXPECT_EQ(rfh_a, current_frame_host());
Hajime Hoshibbc509c2020-04-06 08:55:081030 EXPECT_FALSE(rfh_a->IsInBackForwardCache());
1031 EXPECT_TRUE(rfh_b->IsInBackForwardCache());
Lowell Manners21946052019-07-09 09:16:431032
Fergal Daly09833062021-02-09 07:10:001033 ExpectRestored(FROM_HERE);
Hajime Hoshif9eba2b2019-10-02 08:27:421034
Lowell Manners21946052019-07-09 09:16:431035 // 6) Go forward to B.
1036 web_contents()->GetController().GoForward();
1037 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
1038
1039 EXPECT_EQ(rfh_b, current_frame_host());
Hajime Hoshibbc509c2020-04-06 08:55:081040 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
1041 EXPECT_FALSE(rfh_b->IsInBackForwardCache());
Lowell Manners21946052019-07-09 09:16:431042
Hajime Hoshif53fa7ca2019-08-13 06:52:341043 EXPECT_FALSE(delete_observer_rfh_a.deleted());
1044 EXPECT_FALSE(delete_observer_rfh_b.deleted());
Hajime Hoshif9eba2b2019-10-02 08:27:421045
Fergal Daly09833062021-02-09 07:10:001046 ExpectRestored(FROM_HERE);
Lowell Manners21946052019-07-09 09:16:431047}
1048
arthursonzogni1dddb712019-07-12 10:42:171049// The current page can't enter the BackForwardCache if another page can script
1050// it. This can happen when one document opens a popup using window.open() for
1051// instance. It prevents the BackForwardCache from being used.
Carlos Caballero0e2fff922020-09-15 12:52:191052IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, WindowOpen) {
arthursonzogni1dddb712019-07-12 10:42:171053 // This test assumes cross-site navigation staying in the same
1054 // BrowsingInstance to use a different SiteInstance. Otherwise, it will
1055 // timeout at step 2).
1056 if (!SiteIsolationPolicy::UseDedicatedProcessesForAllSites())
1057 return;
1058
1059 ASSERT_TRUE(embedded_test_server()->Start());
arthursonzogni72b66492019-11-04 12:24:331060 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
1061 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
arthursonzogni1dddb712019-07-12 10:42:171062
1063 // 1) Navigate to A and open a popup.
1064 EXPECT_TRUE(NavigateToURL(shell(), url_a));
1065 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
1066 RenderFrameHostImpl* rfh_a = current_frame_host();
Hajime Hoshif53fa7ca2019-08-13 06:52:341067 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
arthursonzogni1dddb712019-07-12 10:42:171068 EXPECT_EQ(1u, rfh_a->GetSiteInstance()->GetRelatedActiveContentsCount());
1069 Shell* popup = OpenPopup(rfh_a, url_a, "");
1070 EXPECT_EQ(2u, rfh_a->GetSiteInstance()->GetRelatedActiveContentsCount());
1071
1072 // 2) Navigate to B. The previous document can't enter the BackForwardCache,
1073 // because of the popup.
1074 EXPECT_TRUE(ExecJs(rfh_a, JsReplace("location = $1;", url_b.spec())));
Hajime Hoshif53fa7ca2019-08-13 06:52:341075 delete_observer_rfh_a.WaitUntilDeleted();
arthursonzogni1dddb712019-07-12 10:42:171076 RenderFrameHostImpl* rfh_b = current_frame_host();
1077 EXPECT_EQ(2u, rfh_b->GetSiteInstance()->GetRelatedActiveContentsCount());
1078
1079 // 3) Go back to A. The previous document can't enter the BackForwardCache,
1080 // because of the popup.
Hajime Hoshif53fa7ca2019-08-13 06:52:341081 RenderFrameDeletedObserver delete_observer_rfh_b(rfh_b);
arthursonzogni1dddb712019-07-12 10:42:171082 EXPECT_TRUE(ExecJs(rfh_b, "history.back();"));
Hajime Hoshif53fa7ca2019-08-13 06:52:341083 delete_observer_rfh_b.WaitUntilDeleted();
arthursonzogni1dddb712019-07-12 10:42:171084
1085 // 4) Make the popup drop the window.opener connection. It happens when the
1086 // user does an omnibox-initiated navigation, which happens in a new
1087 // BrowsingInstance.
1088 RenderFrameHostImpl* rfh_a_new = current_frame_host();
1089 EXPECT_EQ(2u, rfh_a_new->GetSiteInstance()->GetRelatedActiveContentsCount());
Lowell Manners2d0163e42019-07-30 09:24:301090 EXPECT_TRUE(NavigateToURL(popup, url_b));
arthursonzogni1dddb712019-07-12 10:42:171091 EXPECT_EQ(1u, rfh_a_new->GetSiteInstance()->GetRelatedActiveContentsCount());
1092
Alexander Timinca73c2b2020-03-19 14:50:151093 // 5) Navigate to B again. As the scripting relationship with the popup is
1094 // now severed, the current page (|rfh_a_new|) can enter back-forward cache.
Hajime Hoshif53fa7ca2019-08-13 06:52:341095 RenderFrameDeletedObserver delete_observer_rfh_a_new(rfh_a_new);
arthursonzogni1dddb712019-07-12 10:42:171096 EXPECT_TRUE(ExecJs(rfh_a_new, JsReplace("location = $1;", url_b.spec())));
1097 EXPECT_TRUE(WaitForLoadStop(web_contents()));
Alexander Timinca73c2b2020-03-19 14:50:151098 EXPECT_FALSE(delete_observer_rfh_a_new.deleted());
Hajime Hoshibbc509c2020-04-06 08:55:081099 EXPECT_TRUE(rfh_a_new->IsInBackForwardCache());
arthursonzogni1dddb712019-07-12 10:42:171100
1101 // 6) Go back to A. The current document can finally enter the
1102 // BackForwardCache, because it is alone in its BrowsingInstance and has never
1103 // been related to any other document.
1104 RenderFrameHostImpl* rfh_b_new = current_frame_host();
Hajime Hoshif53fa7ca2019-08-13 06:52:341105 RenderFrameDeletedObserver delete_observer_rfh_b_new(rfh_b_new);
arthursonzogni1dddb712019-07-12 10:42:171106 EXPECT_TRUE(ExecJs(rfh_b_new, "history.back();"));
1107 EXPECT_TRUE(WaitForLoadStop(web_contents()));
Hajime Hoshif53fa7ca2019-08-13 06:52:341108 EXPECT_FALSE(delete_observer_rfh_b_new.deleted());
Hajime Hoshibbc509c2020-04-06 08:55:081109 EXPECT_TRUE(rfh_b_new->IsInBackForwardCache());
arthursonzogni1dddb712019-07-12 10:42:171110}
1111
Arthur Sonzogni620cec62018-12-13 13:08:571112// Navigate from A(B) to C and go back.
1113IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, BasicIframe) {
1114 ASSERT_TRUE(embedded_test_server()->Start());
arthursonzogni72b66492019-11-04 12:24:331115 GURL url_a(embedded_test_server()->GetURL(
Arthur Sonzogni620cec62018-12-13 13:08:571116 "a.com", "/cross_site_iframe_factory.html?a(b)"));
arthursonzogni72b66492019-11-04 12:24:331117 GURL url_c(embedded_test_server()->GetURL("c.com", "/title1.html"));
Arthur Sonzogni620cec62018-12-13 13:08:571118
1119 // 1) Navigate to A(B).
arthursonzogni2f84dd62019-06-05 09:47:121120 EXPECT_TRUE(NavigateToURL(shell(), url_a));
Arthur Sonzogni620cec62018-12-13 13:08:571121 RenderFrameHostImpl* rfh_a = current_frame_host();
1122 RenderFrameHostImpl* rfh_b = rfh_a->child_at(0)->current_frame_host();
Hajime Hoshif53fa7ca2019-08-13 06:52:341123 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
1124 RenderFrameDeletedObserver delete_observer_rfh_b(rfh_b);
Arthur Sonzogni620cec62018-12-13 13:08:571125
1126 // 2) Navigate to C.
arthursonzogni2f84dd62019-06-05 09:47:121127 EXPECT_TRUE(NavigateToURL(shell(), url_c));
Arthur Sonzogni620cec62018-12-13 13:08:571128 RenderFrameHostImpl* rfh_c = current_frame_host();
Hajime Hoshif53fa7ca2019-08-13 06:52:341129 RenderFrameDeletedObserver delete_observer_rfh_c(rfh_c);
1130 EXPECT_FALSE(delete_observer_rfh_a.deleted());
1131 EXPECT_FALSE(delete_observer_rfh_b.deleted());
Hajime Hoshibbc509c2020-04-06 08:55:081132 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
1133 EXPECT_TRUE(rfh_b->IsInBackForwardCache());
1134 EXPECT_FALSE(rfh_c->IsInBackForwardCache());
Arthur Sonzogni620cec62018-12-13 13:08:571135
1136 // 3) Go back to A(B).
1137 web_contents()->GetController().GoBack();
1138 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
Hajime Hoshif53fa7ca2019-08-13 06:52:341139 EXPECT_FALSE(delete_observer_rfh_a.deleted());
1140 EXPECT_FALSE(delete_observer_rfh_b.deleted());
1141 EXPECT_FALSE(delete_observer_rfh_c.deleted());
Arthur Sonzogni620cec62018-12-13 13:08:571142 EXPECT_EQ(rfh_a, current_frame_host());
Hajime Hoshibbc509c2020-04-06 08:55:081143 EXPECT_FALSE(rfh_a->IsInBackForwardCache());
1144 EXPECT_FALSE(rfh_b->IsInBackForwardCache());
1145 EXPECT_TRUE(rfh_c->IsInBackForwardCache());
Hajime Hoshif9eba2b2019-10-02 08:27:421146
Fergal Daly09833062021-02-09 07:10:001147 ExpectRestored(FROM_HERE);
Arthur Sonzogni620cec62018-12-13 13:08:571148}
1149
1150// Ensure flushing the BackForwardCache works properly.
1151IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, BackForwardCacheFlush) {
1152 ASSERT_TRUE(embedded_test_server()->Start());
arthursonzogni72b66492019-11-04 12:24:331153 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
1154 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
Arthur Sonzogni620cec62018-12-13 13:08:571155
1156 // 1) Navigate to A.
arthursonzogni2f84dd62019-06-05 09:47:121157 EXPECT_TRUE(NavigateToURL(shell(), url_a));
Arthur Sonzogni620cec62018-12-13 13:08:571158 RenderFrameHostImpl* rfh_a = current_frame_host();
Hajime Hoshif53fa7ca2019-08-13 06:52:341159 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
Arthur Sonzogni620cec62018-12-13 13:08:571160
1161 // 2) Navigate to B.
arthursonzogni2f84dd62019-06-05 09:47:121162 EXPECT_TRUE(NavigateToURL(shell(), url_b));
Arthur Sonzogni620cec62018-12-13 13:08:571163 RenderFrameHostImpl* rfh_b = current_frame_host();
Hajime Hoshif53fa7ca2019-08-13 06:52:341164 RenderFrameDeletedObserver delete_observer_rfh_b(rfh_b);
1165 EXPECT_FALSE(delete_observer_rfh_a.deleted());
Arthur Sonzogni620cec62018-12-13 13:08:571166
1167 // 3) Flush A.
Carlos Caballero35ce710c2019-09-19 10:59:451168 web_contents()->GetController().GetBackForwardCache().Flush();
Lowell Manners20250112019-10-18 15:06:151169 delete_observer_rfh_a.WaitUntilDeleted();
Hajime Hoshif53fa7ca2019-08-13 06:52:341170 EXPECT_FALSE(delete_observer_rfh_b.deleted());
Arthur Sonzogni620cec62018-12-13 13:08:571171
1172 // 4) Go back to a new A.
1173 web_contents()->GetController().GoBack();
1174 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
Hajime Hoshif53fa7ca2019-08-13 06:52:341175 EXPECT_FALSE(delete_observer_rfh_b.deleted());
Arthur Sonzogni620cec62018-12-13 13:08:571176
1177 // 5) Flush B.
Carlos Caballero35ce710c2019-09-19 10:59:451178 web_contents()->GetController().GetBackForwardCache().Flush();
Lowell Manners20250112019-10-18 15:06:151179 delete_observer_rfh_b.WaitUntilDeleted();
Arthur Sonzogni620cec62018-12-13 13:08:571180}
1181
1182// Check the visible URL in the omnibox is properly updated when restoring a
1183// document from the BackForwardCache.
1184IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, VisibleURL) {
1185 ASSERT_TRUE(embedded_test_server()->Start());
arthursonzogni72b66492019-11-04 12:24:331186 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
1187 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
Arthur Sonzogni620cec62018-12-13 13:08:571188
1189 // 1) Go to A.
arthursonzogni2f84dd62019-06-05 09:47:121190 EXPECT_TRUE(NavigateToURL(shell(), url_a));
Arthur Sonzogni620cec62018-12-13 13:08:571191
1192 // 2) Go to B.
arthursonzogni2f84dd62019-06-05 09:47:121193 EXPECT_TRUE(NavigateToURL(shell(), url_b));
Arthur Sonzogni620cec62018-12-13 13:08:571194
1195 // 3) Go back to A.
1196 web_contents()->GetController().GoBack();
Lowell Manners0c04d632019-08-05 10:52:021197 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
Arthur Sonzogni620cec62018-12-13 13:08:571198 EXPECT_EQ(url_a, web_contents()->GetVisibleURL());
1199
1200 // 4) Go forward to B.
1201 web_contents()->GetController().GoForward();
Lowell Manners0c04d632019-08-05 10:52:021202 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
Arthur Sonzogni620cec62018-12-13 13:08:571203 EXPECT_EQ(url_b, web_contents()->GetVisibleURL());
1204}
1205
Lowell Manners3c64d3a22019-09-06 10:52:331206// Test only 1 document is kept in the at a time BackForwardCache.
1207IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
1208 CacheSizeLimitedToOneDocumentPerTab) {
Arthur Sonzogni620cec62018-12-13 13:08:571209 ASSERT_TRUE(embedded_test_server()->Start());
arthursonzogni72b66492019-11-04 12:24:331210 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
1211 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
1212 GURL url_c(embedded_test_server()->GetURL("c.com", "/title1.html"));
Arthur Sonzogni620cec62018-12-13 13:08:571213
Lowell Manners3c64d3a22019-09-06 10:52:331214 EXPECT_TRUE(NavigateToURL(shell(), url_a));
1215 // BackForwardCache is empty.
Arthur Sonzogni620cec62018-12-13 13:08:571216 RenderFrameHostImpl* rfh_a = current_frame_host();
Hajime Hoshif53fa7ca2019-08-13 06:52:341217 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
Arthur Sonzogni620cec62018-12-13 13:08:571218
Lowell Manners3c64d3a22019-09-06 10:52:331219 EXPECT_TRUE(NavigateToURL(shell(), url_b));
1220 // BackForwardCache contains only rfh_a.
Arthur Sonzogni620cec62018-12-13 13:08:571221 RenderFrameHostImpl* rfh_b = current_frame_host();
Hajime Hoshif53fa7ca2019-08-13 06:52:341222 RenderFrameDeletedObserver delete_observer_rfh_b(rfh_b);
Arthur Sonzogni620cec62018-12-13 13:08:571223
Lowell Manners3c64d3a22019-09-06 10:52:331224 EXPECT_TRUE(NavigateToURL(shell(), url_c));
1225 // BackForwardCache contains only rfh_b.
1226 delete_observer_rfh_a.WaitUntilDeleted();
1227 EXPECT_FALSE(delete_observer_rfh_b.deleted());
Arthur Sonzogni620cec62018-12-13 13:08:571228
Lowell Manners3c64d3a22019-09-06 10:52:331229 // If/when the cache size is increased, this can be tested iteratively, see
1230 // deleted code in: https://crrev.com/c/1782902.
Hajime Hoshif9eba2b2019-10-02 08:27:421231
1232 web_contents()->GetController().GoToOffset(-2);
1233 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
Hajime Hoshi15f6b5012019-10-24 05:25:491234 ExpectNotRestored({BackForwardCacheMetrics::NotRestoredReason::kCacheLimit},
Fergal Daly6755cbf2021-02-12 03:06:581235 {}, {}, {}, FROM_HERE);
Arthur Sonzogni620cec62018-12-13 13:08:571236}
1237
Hajime Hoshiac6b8542021-02-25 15:18:521238IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, ResponseHeaders) {
1239 CreateHttpsServer();
1240 ASSERT_TRUE(https_server()->Start());
1241
1242 GURL url_a(https_server()->GetURL("a.com", "/set-header?X-Foo: bar"));
1243 GURL url_b(https_server()->GetURL("b.com", "/title1.html"));
1244
1245 // 1) Navigate to A.
1246 NavigationHandleObserver observer1(web_contents(), url_a);
1247 EXPECT_TRUE(NavigateToURL(shell(), url_a));
1248 RenderFrameHostImpl* rfh_a = current_frame_host();
1249 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
1250 EXPECT_TRUE(observer1.has_committed());
1251 EXPECT_EQ("bar", observer1.GetNormalizedResponseHeader("x-foo"));
1252
1253 // 2) Navigate to B.
1254 NavigationHandleObserver observer2(web_contents(), url_b);
1255 EXPECT_TRUE(NavigateToURL(shell(), url_b));
1256 RenderFrameHostImpl* rfh_b = current_frame_host();
1257 RenderFrameDeletedObserver delete_observer_rfh_b(rfh_b);
1258 EXPECT_FALSE(delete_observer_rfh_a.deleted());
1259 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
1260 EXPECT_FALSE(rfh_b->IsInBackForwardCache());
1261 EXPECT_TRUE(observer2.has_committed());
1262
1263 // 3) Go back to A.
1264 NavigationHandleObserver observer3(web_contents(), url_a);
1265 web_contents()->GetController().GoBack();
1266 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
1267 EXPECT_FALSE(delete_observer_rfh_a.deleted());
1268 EXPECT_FALSE(delete_observer_rfh_b.deleted());
1269 EXPECT_EQ(rfh_a, current_frame_host());
1270 EXPECT_FALSE(rfh_a->IsInBackForwardCache());
1271 EXPECT_TRUE(rfh_b->IsInBackForwardCache());
1272 EXPECT_TRUE(observer3.has_committed());
1273 EXPECT_EQ("bar", observer3.GetNormalizedResponseHeader("x-foo"));
1274
1275 ExpectRestored(FROM_HERE);
1276}
1277
Rakina Zata Amni8d49da52020-11-06 09:23:101278class HighCacheSizeBackForwardCacheBrowserTest
1279 : public BackForwardCacheBrowserTest {
1280 protected:
1281 void SetUpCommandLine(base::CommandLine* command_line) override {
1282 EnableFeatureAndSetParams(features::kBackForwardCache, "cache_size",
1283 base::NumberToString(kBackForwardCacheSize));
1284 BackForwardCacheBrowserTest::SetUpCommandLine(command_line);
1285 }
Lowell Manners9f1a5492019-09-10 09:28:441286
Fergal Daly92229c42021-04-08 11:51:421287 // The number of pages the BackForwardCache can hold per tab.
kouheibd168c02021-05-24 13:47:231288 // The number 5 was picked since Android ASAN trybot failed to keep more than
1289 // 6 pages in memory.
kouheie8cd7ea52021-05-24 05:24:261290 const size_t kBackForwardCacheSize = 5;
Rakina Zata Amni8d49da52020-11-06 09:23:101291};
1292
1293// Test documents are evicted from the BackForwardCache at some point.
1294IN_PROC_BROWSER_TEST_F(HighCacheSizeBackForwardCacheBrowserTest,
kouheie8cd7ea52021-05-24 05:24:261295 CacheEvictionWithIncreasedCacheSize) {
Rakina Zata Amni8d49da52020-11-06 09:23:101296 ASSERT_TRUE(embedded_test_server()->Start());
Lowell Manners9f1a5492019-09-10 09:28:441297
arthursonzogni72b66492019-11-04 12:24:331298 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
1299 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
Lowell Manners9f1a5492019-09-10 09:28:441300
1301 EXPECT_TRUE(NavigateToURL(shell(), url_a)); // BackForwardCache size is 0.
1302 RenderFrameHostImpl* rfh_a = current_frame_host();
1303 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
1304
1305 EXPECT_TRUE(NavigateToURL(shell(), url_b)); // BackForwardCache size is 1.
1306 RenderFrameHostImpl* rfh_b = current_frame_host();
1307 RenderFrameDeletedObserver delete_observer_rfh_b(rfh_b);
1308
Rakina Zata Amni8d49da52020-11-06 09:23:101309 for (size_t i = 2; i < kBackForwardCacheSize; ++i) {
Lowell Manners9f1a5492019-09-10 09:28:441310 EXPECT_TRUE(NavigateToURL(shell(), i % 2 ? url_b : url_a));
1311 // After |i+1| navigations, |i| documents went into the BackForwardCache.
1312 // When |i| is greater than the BackForwardCache size limit, they are
1313 // evicted:
Rakina Zata Amni8d49da52020-11-06 09:23:101314 EXPECT_EQ(i >= kBackForwardCacheSize + 1, delete_observer_rfh_a.deleted());
1315 EXPECT_EQ(i >= kBackForwardCacheSize + 2, delete_observer_rfh_b.deleted());
Lowell Manners9f1a5492019-09-10 09:28:441316 }
1317}
1318
Fergal Daly92229c42021-04-08 11:51:421319class BackgroundForegroundProcessLimitBackForwardCacheBrowserTest
1320 : public BackForwardCacheBrowserTest {
1321 protected:
1322 void SetUpCommandLine(base::CommandLine* command_line) override {
1323 EnableFeatureAndSetParams(features::kBackForwardCache, "cache_size",
1324 base::NumberToString(kBackForwardCacheSize));
1325 EnableFeatureAndSetParams(
1326 features::kBackForwardCache, "foreground_cache_size",
1327 base::NumberToString(kForegroundBackForwardCacheSize));
1328 BackForwardCacheBrowserTest::SetUpCommandLine(command_line);
1329 }
1330
Fergal Daly30507e62021-07-01 02:51:311331 void ExpectCached(const RenderFrameHostImplWrapper& rfh,
Fergal Daly92229c42021-04-08 11:51:421332 bool cached,
1333 bool backgrounded) {
Fergal Daly225adc12021-05-25 02:58:391334 EXPECT_FALSE(rfh.IsDestroyed());
1335 EXPECT_EQ(cached, rfh->IsInBackForwardCache());
1336 EXPECT_EQ(backgrounded, rfh->GetProcess()->IsProcessBackgrounded());
Fergal Daly92229c42021-04-08 11:51:421337 }
1338 // The number of pages the BackForwardCache can hold per tab.
1339 const size_t kBackForwardCacheSize = 4;
1340 const size_t kForegroundBackForwardCacheSize = 2;
1341};
1342
1343// Test that a series of same-site navigations (which use the same process)
1344// uses the foreground limit.
1345IN_PROC_BROWSER_TEST_F(
1346 BackgroundForegroundProcessLimitBackForwardCacheBrowserTest,
1347 CacheEvictionSameSite) {
1348 ASSERT_TRUE(embedded_test_server()->Start());
1349
Fergal Daly30507e62021-07-01 02:51:311350 std::vector<RenderFrameHostImplWrapper> rfhs;
Fergal Daly92229c42021-04-08 11:51:421351
1352 for (size_t i = 0; i <= kBackForwardCacheSize * 2; ++i) {
1353 SCOPED_TRACE(i);
1354 GURL url(embedded_test_server()->GetURL(
1355 "a.com", base::StringPrintf("/title1.html?i=%zu", i)));
1356 ASSERT_TRUE(NavigateToURL(shell(), url));
Fergal Daly225adc12021-05-25 02:58:391357 rfhs.emplace_back(current_frame_host());
1358 EXPECT_FALSE(rfhs.back()->GetProcess()->IsProcessBackgrounded());
Fergal Daly92229c42021-04-08 11:51:421359
1360 for (size_t j = 0; j <= i; ++j) {
1361 SCOPED_TRACE(j);
1362 // The last page is active, the previous |kForegroundBackForwardCacheSize|
1363 // should be in the cache, any before that should be deleted.
1364 if (i - j <= kForegroundBackForwardCacheSize) {
1365 // All of the processes should be in the foreground.
Fergal Daly225adc12021-05-25 02:58:391366 ExpectCached(rfhs[j], /*cached=*/i != j,
Fergal Daly92229c42021-04-08 11:51:421367 /*backgrounded=*/false);
1368 } else {
Fergal Daly225adc12021-05-25 02:58:391369 rfhs[j].WaitUntilRenderFrameDeleted();
Fergal Daly92229c42021-04-08 11:51:421370 }
1371 }
1372 }
1373
1374 // Navigate back but not to the initial about:blank.
1375 for (size_t i = 0; i <= kBackForwardCacheSize * 2 - 1; ++i) {
1376 SCOPED_TRACE(i);
1377 web_contents()->GetController().GoBack();
1378 ASSERT_TRUE(WaitForLoadStop(shell()->web_contents()));
1379 // The first |kBackForwardCacheSize| navigations should be restored from the
1380 // cache. The rest should not.
1381 if (i < kForegroundBackForwardCacheSize) {
1382 ExpectRestored(FROM_HERE);
1383 } else {
1384 ExpectNotRestored(
1385 {BackForwardCacheMetrics::NotRestoredReason::kForegroundCacheLimit},
1386 {}, {}, {}, FROM_HERE);
1387 }
1388 }
1389}
1390
1391// Test that a series of cross-site navigations (which use different processes)
1392// use the background limit.
Francois Doray8ef927982021-04-27 21:13:141393//
1394// TODO(crbug.com/1203418): This test is flaky.
Fergal Daly92229c42021-04-08 11:51:421395IN_PROC_BROWSER_TEST_F(
1396 BackgroundForegroundProcessLimitBackForwardCacheBrowserTest,
Francois Doray8ef927982021-04-27 21:13:141397 DISABLED_CacheEvictionCrossSite) {
Fergal Daly92229c42021-04-08 11:51:421398 ASSERT_TRUE(embedded_test_server()->Start());
1399
Fergal Daly30507e62021-07-01 02:51:311400 std::vector<RenderFrameHostImplWrapper> rfhs;
Fergal Daly92229c42021-04-08 11:51:421401
1402 for (size_t i = 0; i <= kBackForwardCacheSize * 2; ++i) {
1403 SCOPED_TRACE(i);
1404 GURL url(embedded_test_server()->GetURL(base::StringPrintf("a%zu.com", i),
1405 "/title1.html"));
1406 ASSERT_TRUE(NavigateToURL(shell(), url));
Fergal Daly225adc12021-05-25 02:58:391407 rfhs.emplace_back(current_frame_host());
1408 EXPECT_FALSE(rfhs.back()->GetProcess()->IsProcessBackgrounded());
Fergal Daly92229c42021-04-08 11:51:421409
1410 for (size_t j = 0; j <= i; ++j) {
1411 SCOPED_TRACE(j);
1412 // The last page is active, the previous |kBackgroundBackForwardCacheSize|
1413 // should be in the cache, any before that should be deleted.
1414 if (i - j <= kBackForwardCacheSize) {
Fergal Daly225adc12021-05-25 02:58:391415 EXPECT_FALSE(rfhs[j].IsDestroyed());
Fergal Daly92229c42021-04-08 11:51:421416 // Pages except the active one should be cached and in the background.
Fergal Daly225adc12021-05-25 02:58:391417 ExpectCached(rfhs[j], /*cached=*/i != j,
Fergal Daly92229c42021-04-08 11:51:421418 /*backgrounded=*/i != j);
1419 } else {
Fergal Daly225adc12021-05-25 02:58:391420 rfhs[j].WaitUntilRenderFrameDeleted();
Fergal Daly92229c42021-04-08 11:51:421421 }
1422 }
1423 }
1424
1425 // Navigate back but not to the initial about:blank.
1426 for (size_t i = 0; i <= kBackForwardCacheSize * 2 - 1; ++i) {
1427 SCOPED_TRACE(i);
1428 web_contents()->GetController().GoBack();
1429 ASSERT_TRUE(WaitForLoadStop(shell()->web_contents()));
1430 // The first |kBackForwardCacheSize| navigations should be restored from the
1431 // cache. The rest should not.
1432 if (i < kBackForwardCacheSize) {
1433 ExpectRestored(FROM_HERE);
1434 } else {
1435 ExpectNotRestored(
1436 {BackForwardCacheMetrics::NotRestoredReason::kCacheLimit}, {}, {}, {},
1437 FROM_HERE);
1438 }
1439 }
1440}
1441
1442// Test that the cache responds to processes switching from background to
1443// foreground. We set things up so that we have
1444// Cached sites:
1445// a0.com
1446// a1.com
1447// a2.com
1448// a3.com
1449// and the active page is a4.com. Then set the process for a[1-3] to
1450// foregrounded so that there are 3 entries whose processes are foregrounded.
1451// BFCache should evict the eldest (a1) leaving a0 because despite being older,
1452// it is backgrounded. Setting the priority directly is not ideal but there is
1453// no reliable way to cause the processes to go into the foreground just by
1454// navigating because proactive browsing instance swap makes it impossible to
1455// reliably create a new a1.com renderer in the same process as the old a1.com.
1456IN_PROC_BROWSER_TEST_F(
1457 BackgroundForegroundProcessLimitBackForwardCacheBrowserTest,
1458 ChangeToForeground) {
1459 ASSERT_TRUE(embedded_test_server()->Start());
1460
Fergal Daly30507e62021-07-01 02:51:311461 std::vector<RenderFrameHostImplWrapper> rfhs;
Fergal Daly92229c42021-04-08 11:51:421462
1463 // Navigate through a[0-3].com.
1464 for (size_t i = 0; i < kBackForwardCacheSize; ++i) {
1465 SCOPED_TRACE(i);
1466 GURL url(embedded_test_server()->GetURL(base::StringPrintf("a%zu.com", i),
1467 "/title1.html"));
1468 ASSERT_TRUE(NavigateToURL(shell(), url));
Fergal Daly225adc12021-05-25 02:58:391469 rfhs.emplace_back(current_frame_host());
1470 EXPECT_FALSE(rfhs.back()->GetProcess()->IsProcessBackgrounded());
Fergal Daly92229c42021-04-08 11:51:421471 }
1472 // Check that a0-2 are cached and backgrounded.
1473 for (size_t i = 0; i < kBackForwardCacheSize - 1; ++i) {
1474 SCOPED_TRACE(i);
Fergal Daly225adc12021-05-25 02:58:391475 ExpectCached(rfhs[i], /*cached=*/true, /*backgrounded=*/true);
Fergal Daly92229c42021-04-08 11:51:421476 }
1477
1478 // Navigate to a page which causes the processes for a[1-3] to be
1479 // foregrounded.
1480 GURL url(embedded_test_server()->GetURL("a4.com", "/title1.html"));
1481 ASSERT_TRUE(NavigateToURL(shell(), url));
1482
1483 // Assert that we really have set up the situation we want where the processes
1484 // are shared and in the foreground.
1485 RenderFrameHostImpl* rfh = current_frame_host();
1486 ASSERT_FALSE(rfh->GetProcess()->IsProcessBackgrounded());
1487
Fergal Daly225adc12021-05-25 02:58:391488 rfhs[1]->GetProcess()->SetPriorityOverride(
Fergal Daly92229c42021-04-08 11:51:421489 /*foreground=*/true);
Fergal Daly225adc12021-05-25 02:58:391490 rfhs[2]->GetProcess()->SetPriorityOverride(
Fergal Daly92229c42021-04-08 11:51:421491 /*foreground=*/true);
Fergal Daly225adc12021-05-25 02:58:391492 rfhs[3]->GetProcess()->SetPriorityOverride(
Fergal Daly92229c42021-04-08 11:51:421493 /*foreground=*/true);
1494
1495 // The page should be evicted.
Fergal Daly225adc12021-05-25 02:58:391496 rfhs[1].WaitUntilRenderFrameDeleted();
Fergal Daly92229c42021-04-08 11:51:421497
1498 // Check that a0 is cached and backgrounded.
Fergal Daly225adc12021-05-25 02:58:391499 ExpectCached(rfhs[0], /*cached=*/true, /*backgrounded=*/true);
Fergal Daly92229c42021-04-08 11:51:421500 // Check that a2-3 are cached and foregrounded.
Fergal Daly225adc12021-05-25 02:58:391501 ExpectCached(rfhs[2], /*cached=*/true, /*backgrounded=*/false);
1502 ExpectCached(rfhs[3], /*cached=*/true, /*backgrounded=*/false);
Fergal Daly92229c42021-04-08 11:51:421503}
1504
Kevin McNeec9d0fda2021-05-19 15:55:171505// Tests that |RenderFrameHost::ForEachRenderFrameHost| and
1506// |WebContents::ForEachRenderFrameHost| behave correctly with bfcached
1507// RenderFrameHosts.
Kevin McNee5898e5622021-05-11 00:42:481508IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, ForEachRenderFrameHost) {
Kevin McNee5f594382021-05-06 23:18:231509 ASSERT_TRUE(embedded_test_server()->Start());
1510 GURL url_a(embedded_test_server()->GetURL(
1511 "a.com", "/cross_site_iframe_factory.html?a(b(c),d)"));
1512 GURL url_e(embedded_test_server()->GetURL("e.com", "/title1.html"));
1513
1514 std::vector<RenderFrameDeletedObserver*> rfh_observers;
1515
1516 // 1) Navigate to a(b(c),d).
1517 EXPECT_TRUE(NavigateToURL(shell(), url_a));
1518 RenderFrameHostImpl* rfh_a = current_frame_host();
1519 RenderFrameHostImpl* rfh_b = rfh_a->child_at(0)->current_frame_host();
1520 RenderFrameHostImpl* rfh_c = rfh_b->child_at(0)->current_frame_host();
1521 RenderFrameHostImpl* rfh_d = rfh_a->child_at(1)->current_frame_host();
1522 RenderFrameDeletedObserver a_observer(rfh_a), b_observer(rfh_b),
1523 c_observer(rfh_c), d_observer(rfh_d);
1524 rfh_observers.insert(rfh_observers.end(),
1525 {&a_observer, &b_observer, &c_observer, &d_observer});
1526
1527 // Ensure the visited frames are what we would expect for the page before
1528 // entering bfcache.
Kevin McNee5898e5622021-05-11 00:42:481529 EXPECT_THAT(CollectAllRenderFrameHosts(rfh_a),
Kevin McNee5f594382021-05-06 23:18:231530 testing::ElementsAre(rfh_a, rfh_b, rfh_d, rfh_c));
Kevin McNeec9d0fda2021-05-19 15:55:171531 EXPECT_THAT(CollectAllRenderFrameHosts(web_contents()),
1532 testing::ElementsAre(rfh_a, rfh_b, rfh_d, rfh_c));
Kevin McNee5f594382021-05-06 23:18:231533
1534 // 2) Navigate to e.
1535 EXPECT_TRUE(NavigateToURL(shell(), url_e));
1536 RenderFrameHostImpl* rfh_e = current_frame_host();
1537 RenderFrameDeletedObserver e_observer(rfh_e);
1538 rfh_observers.push_back(&e_observer);
1539 ASSERT_THAT(rfh_observers, Each(Not(Deleted())));
1540 EXPECT_THAT(Elements({rfh_a, rfh_b, rfh_c, rfh_d}),
1541 Each(InBackForwardCache()));
1542 EXPECT_THAT(rfh_e, Not(InBackForwardCache()));
1543
1544 // When starting iteration from the primary frame, we shouldn't see any of the
1545 // frames in bfcache.
Kevin McNee5898e5622021-05-11 00:42:481546 EXPECT_THAT(CollectAllRenderFrameHosts(rfh_e), testing::ElementsAre(rfh_e));
Kevin McNee5f594382021-05-06 23:18:231547
1548 // When starting iteration from a bfcached RFH, we should see the frame itself
1549 // and its descendants in breadth first order.
Kevin McNee5898e5622021-05-11 00:42:481550 EXPECT_THAT(CollectAllRenderFrameHosts(rfh_a),
Kevin McNee5f594382021-05-06 23:18:231551 testing::ElementsAre(rfh_a, rfh_b, rfh_d, rfh_c));
1552
1553 // Ensure that starting iteration from a subframe of a bfcached frame also
1554 // works.
Kevin McNee5898e5622021-05-11 00:42:481555 EXPECT_THAT(CollectAllRenderFrameHosts(rfh_b),
1556 testing::ElementsAre(rfh_b, rfh_c));
Kevin McNeec9d0fda2021-05-19 15:55:171557
1558 // When iterating over all RenderFrameHosts in a WebContents, we should see
1559 // the RFHs of both the primary page and the bfcached page.
1560 EXPECT_THAT(CollectAllRenderFrameHosts(web_contents()),
1561 testing::UnorderedElementsAre(rfh_a, rfh_b, rfh_c, rfh_d, rfh_e));
1562
1563 {
1564 // If we stop iteration in |WebContents::ForEachRenderFrameHost|, we stop
1565 // the entire iteration, not just iteration in the page being iterated at
1566 // that point. In this case, if we stop iteration in the primary page, we do
1567 // not continue to iterate in the bfcached page.
1568 bool stopped = false;
1569 web_contents()->ForEachRenderFrameHost(
1570 base::BindLambdaForTesting([&](RenderFrameHostImpl* rfh) {
1571 EXPECT_FALSE(stopped);
1572 stopped = true;
1573 return RenderFrameHost::FrameIterationAction::kStop;
1574 }));
1575 }
Kevin McNee5f594382021-05-06 23:18:231576}
1577
Kevin McNeec9d0fda2021-05-19 15:55:171578// Tests that |RenderFrameHostImpl::ForEachRenderFrameHostIncludingSpeculative|
1579// and |WebContentsImpl::ForEachRenderFrameHostIncludingSpeculative|
1580// behave correctly when a FrameTreeNode has both a speculative RFH and a
Kevin McNee5898e5622021-05-11 00:42:481581// bfcached RFH.
Kevin McNee5f594382021-05-06 23:18:231582IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
Kevin McNee5898e5622021-05-11 00:42:481583 ForEachRenderFrameHostWithSpeculative) {
Kevin McNee5f594382021-05-06 23:18:231584 IsolateAllSitesForTesting(base::CommandLine::ForCurrentProcess());
1585 ASSERT_TRUE(embedded_test_server()->Start());
1586 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
1587 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
1588 GURL url_c(embedded_test_server()->GetURL("c.com", "/title1.html"));
1589
1590 std::vector<RenderFrameDeletedObserver*> rfh_observers;
1591
1592 // 1) Navigate to a.
1593 EXPECT_TRUE(NavigateToURL(shell(), url_a));
1594 RenderFrameHostImpl* rfh_a = current_frame_host();
1595 RenderFrameDeletedObserver a_observer(rfh_a);
1596 rfh_observers.push_back(&a_observer);
1597
1598 // 2) Navigate to b.
1599 EXPECT_TRUE(NavigateToURL(shell(), url_b));
1600 RenderFrameHostImpl* rfh_b = current_frame_host();
1601 RenderFrameDeletedObserver b_observer(rfh_b);
1602 rfh_observers.push_back(&b_observer);
1603 ASSERT_THAT(rfh_observers, Each(Not(Deleted())));
1604
1605 // 3) Begin navigation to c.
1606 TestNavigationManager nav_manager(web_contents(), url_c);
1607 shell()->LoadURL(url_c);
1608 ASSERT_TRUE(nav_manager.WaitForRequestStart());
1609
1610 RenderFrameHostImpl* rfh_c =
1611 rfh_b->frame_tree_node()->render_manager()->speculative_frame_host();
1612 ASSERT_TRUE(rfh_c);
1613 EXPECT_EQ(RenderFrameHostImpl::LifecycleStateImpl::kInBackForwardCache,
1614 rfh_a->lifecycle_state());
Dave Tapuska9c9afe82021-06-22 19:07:451615 EXPECT_FALSE(rfh_a->GetPage().IsPrimary());
Kevin McNee5f594382021-05-06 23:18:231616 EXPECT_EQ(RenderFrameHostImpl::LifecycleStateImpl::kActive,
1617 rfh_b->lifecycle_state());
Dave Tapuska9c9afe82021-06-22 19:07:451618 EXPECT_TRUE(rfh_b->GetPage().IsPrimary());
Kevin McNee5f594382021-05-06 23:18:231619 EXPECT_EQ(RenderFrameHostImpl::LifecycleStateImpl::kSpeculative,
1620 rfh_c->lifecycle_state());
Dave Tapuska9c9afe82021-06-22 19:07:451621 EXPECT_FALSE(rfh_c->GetPage().IsPrimary());
Kevin McNee5f594382021-05-06 23:18:231622
1623 // When starting iteration from the bfcached RFH, we should not see the
1624 // speculative RFH.
Kevin McNee5898e5622021-05-11 00:42:481625 EXPECT_THAT(CollectAllRenderFrameHostsIncludingSpeculative(rfh_a),
Kevin McNee5f594382021-05-06 23:18:231626 testing::ElementsAre(rfh_a));
1627
1628 // When starting iteration from the primary frame, we shouldn't see the
1629 // bfcached RFH, but we should see the speculative RFH.
Kevin McNee5898e5622021-05-11 00:42:481630 EXPECT_THAT(CollectAllRenderFrameHostsIncludingSpeculative(rfh_b),
Kevin McNee5f594382021-05-06 23:18:231631 testing::UnorderedElementsAre(rfh_b, rfh_c));
1632
1633 // When starting iteration from the speculative RFH, we should only see
1634 // the speculative RFH. In particular, we should not see the bfcached RFH.
Kevin McNee5898e5622021-05-11 00:42:481635 EXPECT_THAT(CollectAllRenderFrameHostsIncludingSpeculative(rfh_c),
Kevin McNee5f594382021-05-06 23:18:231636 testing::ElementsAre(rfh_c));
Kevin McNeec9d0fda2021-05-19 15:55:171637
1638 // When iterating over all RenderFrameHosts in a WebContents, we should see
1639 // the RFHs of both the primary page and the bfcached page.
1640 EXPECT_THAT(CollectAllRenderFrameHostsIncludingSpeculative(web_contents()),
1641 testing::UnorderedElementsAre(rfh_a, rfh_b, rfh_c));
Kevin McNee5f594382021-05-06 23:18:231642}
1643
arthursonzogni2f84dd62019-06-05 09:47:121644// Similar to BackForwardCacheBrowserTest.SubframeSurviveCache*
1645// Test case: a1(b2) -> c3 -> a1(b2)
1646IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, SubframeSurviveCache1) {
1647 ASSERT_TRUE(embedded_test_server()->Start());
arthursonzogni72b66492019-11-04 12:24:331648 GURL url_a(embedded_test_server()->GetURL(
arthursonzogni2f84dd62019-06-05 09:47:121649 "a.com", "/cross_site_iframe_factory.html?a(b)"));
arthursonzogni72b66492019-11-04 12:24:331650 GURL url_c(embedded_test_server()->GetURL("c.com", "/title1.html"));
arthursonzogni2f84dd62019-06-05 09:47:121651
1652 std::vector<RenderFrameDeletedObserver*> rfh_observer;
1653
1654 // 1) Navigate to a1(b2).
Lowell Manners2d0163e42019-07-30 09:24:301655 EXPECT_TRUE(NavigateToURL(shell(), url_a));
arthursonzogni2f84dd62019-06-05 09:47:121656 RenderFrameHostImpl* a1 = current_frame_host();
1657 RenderFrameHostImpl* b2 = a1->child_at(0)->current_frame_host();
1658 RenderFrameDeletedObserver a1_observer(a1), b2_observer(b2);
1659 rfh_observer.insert(rfh_observer.end(), {&a1_observer, &b2_observer});
1660 EXPECT_TRUE(ExecJs(b2, "window.alive = 'I am alive';"));
1661
1662 // 2) Navigate to c3.
Lowell Manners2d0163e42019-07-30 09:24:301663 EXPECT_TRUE(NavigateToURL(shell(), url_c));
arthursonzogni2f84dd62019-06-05 09:47:121664 RenderFrameHostImpl* c3 = current_frame_host();
1665 RenderFrameDeletedObserver c3_observer(c3);
1666 rfh_observer.push_back(&c3_observer);
1667 ASSERT_THAT(rfh_observer, Each(Not(Deleted())));
1668 EXPECT_THAT(Elements({a1, b2}), Each(InBackForwardCache()));
1669 EXPECT_THAT(c3, Not(InBackForwardCache()));
1670
1671 // 3) Go back to a1(b2).
1672 web_contents()->GetController().GoBack();
1673 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
1674 ASSERT_THAT(rfh_observer, Each(Not(Deleted())));
1675 EXPECT_THAT(Elements({a1, b2}), Each(Not(InBackForwardCache())));
1676 EXPECT_THAT(c3, InBackForwardCache());
1677
1678 // Even after a new IPC round trip with the renderer, b2 must still be alive.
1679 EXPECT_EQ("I am alive", EvalJs(b2, "window.alive"));
1680 EXPECT_FALSE(b2_observer.deleted());
Hajime Hoshif9eba2b2019-10-02 08:27:421681
Fergal Daly09833062021-02-09 07:10:001682 ExpectRestored(FROM_HERE);
arthursonzogni2f84dd62019-06-05 09:47:121683}
1684
1685// Similar to BackForwardCacheBrowserTest.SubframeSurviveCache*
1686// Test case: a1(b2) -> b3 -> a1(b2).
1687IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, SubframeSurviveCache2) {
1688 ASSERT_TRUE(embedded_test_server()->Start());
arthursonzogni72b66492019-11-04 12:24:331689 GURL url_a(embedded_test_server()->GetURL(
arthursonzogni2f84dd62019-06-05 09:47:121690 "a.com", "/cross_site_iframe_factory.html?a(b)"));
arthursonzogni72b66492019-11-04 12:24:331691 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
arthursonzogni2f84dd62019-06-05 09:47:121692
1693 std::vector<RenderFrameDeletedObserver*> rfh_observer;
1694
1695 // 1) Navigate to a1(b2).
Lowell Manners2d0163e42019-07-30 09:24:301696 EXPECT_TRUE(NavigateToURL(shell(), url_a));
arthursonzogni2f84dd62019-06-05 09:47:121697 RenderFrameHostImpl* a1 = current_frame_host();
1698 RenderFrameHostImpl* b2 = a1->child_at(0)->current_frame_host();
1699 RenderFrameDeletedObserver a1_observer(a1), b2_observer(b2);
1700 rfh_observer.insert(rfh_observer.end(), {&a1_observer, &b2_observer});
1701 EXPECT_TRUE(ExecJs(b2, "window.alive = 'I am alive';"));
1702
1703 // 2) Navigate to b3.
Lowell Manners2d0163e42019-07-30 09:24:301704 EXPECT_TRUE(NavigateToURL(shell(), url_b));
arthursonzogni2f84dd62019-06-05 09:47:121705 RenderFrameHostImpl* b3 = current_frame_host();
1706 RenderFrameDeletedObserver b3_observer(b3);
1707 rfh_observer.push_back(&b3_observer);
1708 ASSERT_THAT(rfh_observer, Each(Not(Deleted())));
1709 EXPECT_THAT(Elements({a1, b2}), Each(InBackForwardCache()));
1710 EXPECT_THAT(b3, Not(InBackForwardCache()));
1711
1712 // 3) Go back to a1(b2).
1713 web_contents()->GetController().GoBack();
1714 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
1715 ASSERT_THAT(rfh_observer, Each(Not(Deleted())));
1716 EXPECT_EQ(a1, current_frame_host());
1717 EXPECT_THAT(Elements({a1, b2}), Each(Not(InBackForwardCache())));
1718 EXPECT_THAT(b3, InBackForwardCache());
1719
1720 // Even after a new IPC round trip with the renderer, b2 must still be alive.
1721 EXPECT_EQ("I am alive", EvalJs(b2, "window.alive"));
1722 EXPECT_FALSE(b2_observer.deleted());
Hajime Hoshif9eba2b2019-10-02 08:27:421723
Fergal Daly09833062021-02-09 07:10:001724 ExpectRestored(FROM_HERE);
arthursonzogni2f84dd62019-06-05 09:47:121725}
1726
1727// Similar to BackForwardCacheBrowserTest.tSubframeSurviveCache*
1728// Test case: a1(b2) -> b3(a4) -> a1(b2) -> b3(a4)
1729IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, SubframeSurviveCache3) {
1730 ASSERT_TRUE(embedded_test_server()->Start());
arthursonzogni72b66492019-11-04 12:24:331731 GURL url_a(embedded_test_server()->GetURL(
arthursonzogni2f84dd62019-06-05 09:47:121732 "a.com", "/cross_site_iframe_factory.html?a(b)"));
arthursonzogni72b66492019-11-04 12:24:331733 GURL url_b(embedded_test_server()->GetURL(
arthursonzogni2f84dd62019-06-05 09:47:121734 "b.com", "/cross_site_iframe_factory.html?b(a)"));
1735
1736 std::vector<RenderFrameDeletedObserver*> rfh_observer;
1737
1738 // 1) Navigate to a1(b2).
Lowell Manners2d0163e42019-07-30 09:24:301739 EXPECT_TRUE(NavigateToURL(shell(), url_a));
arthursonzogni2f84dd62019-06-05 09:47:121740 RenderFrameHostImpl* a1 = current_frame_host();
1741 RenderFrameHostImpl* b2 = a1->child_at(0)->current_frame_host();
1742 RenderFrameDeletedObserver a1_observer(a1), b2_observer(b2);
1743 rfh_observer.insert(rfh_observer.end(), {&a1_observer, &b2_observer});
1744 EXPECT_TRUE(ExecJs(b2, "window.alive = 'I am alive';"));
1745
1746 // 2) Navigate to b3(a4)
Lowell Manners2d0163e42019-07-30 09:24:301747 EXPECT_TRUE(NavigateToURL(shell(), url_b));
arthursonzogni2f84dd62019-06-05 09:47:121748 RenderFrameHostImpl* b3 = current_frame_host();
1749 RenderFrameHostImpl* a4 = b3->child_at(0)->current_frame_host();
1750 RenderFrameDeletedObserver b3_observer(b3), a4_observer(a4);
1751 rfh_observer.insert(rfh_observer.end(), {&b3_observer, &a4_observer});
1752 ASSERT_THAT(rfh_observer, Each(Not(Deleted())));
1753 EXPECT_THAT(Elements({a1, b2}), Each(InBackForwardCache()));
1754 EXPECT_THAT(Elements({b3, a4}), Each(Not(InBackForwardCache())));
1755 EXPECT_TRUE(ExecJs(a4, "window.alive = 'I am alive';"));
1756
1757 // 3) Go back to a1(b2).
1758 web_contents()->GetController().GoBack();
1759 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
1760 ASSERT_THAT(rfh_observer, Each(Not(Deleted())));
1761 EXPECT_EQ(a1, current_frame_host());
1762 EXPECT_THAT(Elements({a1, b2}), Each(Not(InBackForwardCache())));
1763 EXPECT_THAT(Elements({b3, a4}), Each(InBackForwardCache()));
1764
1765 // Even after a new IPC round trip with the renderer, b2 must still be alive.
1766 EXPECT_EQ("I am alive", EvalJs(b2, "window.alive"));
1767 EXPECT_FALSE(b2_observer.deleted());
1768
Fergal Daly09833062021-02-09 07:10:001769 ExpectRestored(FROM_HERE);
Hajime Hoshif9eba2b2019-10-02 08:27:421770
arthursonzogni2f84dd62019-06-05 09:47:121771 // 4) Go forward to b3(a4).
1772 web_contents()->GetController().GoForward();
1773 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
1774 ASSERT_THAT(rfh_observer, Each(Not(Deleted())));
1775 EXPECT_EQ(b3, current_frame_host());
1776 EXPECT_THAT(Elements({a1, b2}), Each(InBackForwardCache()));
1777 EXPECT_THAT(Elements({b3, a4}), Each(Not(InBackForwardCache())));
1778
1779 // Even after a new IPC round trip with the renderer, a4 must still be alive.
1780 EXPECT_EQ("I am alive", EvalJs(a4, "window.alive"));
1781 EXPECT_FALSE(a4_observer.deleted());
Hajime Hoshif9eba2b2019-10-02 08:27:421782
Fergal Daly09833062021-02-09 07:10:001783 ExpectRestored(FROM_HERE);
arthursonzogni2f84dd62019-06-05 09:47:121784}
1785
Lowell Manners9f1a5492019-09-10 09:28:441786// Similar to BackForwardCacheBrowserTest.SubframeSurviveCache*
1787// Test case: a1(b2) -> b3 -> a4 -> b5 -> a1(b2).
Rakina Zata Amni8d49da52020-11-06 09:23:101788IN_PROC_BROWSER_TEST_F(HighCacheSizeBackForwardCacheBrowserTest,
1789 SubframeSurviveCache4) {
Lowell Manners9f1a5492019-09-10 09:28:441790 ASSERT_TRUE(embedded_test_server()->Start());
arthursonzogni72b66492019-11-04 12:24:331791 GURL url_ab(embedded_test_server()->GetURL(
Lowell Manners9f1a5492019-09-10 09:28:441792 "a.com", "/cross_site_iframe_factory.html?a(b)"));
arthursonzogni72b66492019-11-04 12:24:331793 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
1794 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
Lowell Manners9f1a5492019-09-10 09:28:441795
1796 std::vector<RenderFrameDeletedObserver*> rfh_observer;
1797
1798 // 1) Navigate to a1(b2).
1799 EXPECT_TRUE(NavigateToURL(shell(), url_ab));
1800 RenderFrameHostImpl* a1 = current_frame_host();
1801 RenderFrameHostImpl* b2 = a1->child_at(0)->current_frame_host();
1802 RenderFrameDeletedObserver a1_observer(a1), b2_observer(b2);
1803 rfh_observer.insert(rfh_observer.end(), {&a1_observer, &b2_observer});
1804 EXPECT_TRUE(ExecJs(b2, "window.alive = 'I am alive';"));
1805
1806 // 2) Navigate to b3.
1807 EXPECT_TRUE(NavigateToURL(shell(), url_b));
1808 RenderFrameHostImpl* b3 = current_frame_host();
1809 RenderFrameDeletedObserver b3_observer(b3);
1810 rfh_observer.push_back(&b3_observer);
1811 ASSERT_THAT(rfh_observer, Each(Not(Deleted())));
1812 EXPECT_THAT(Elements({a1, b2}), Each(InBackForwardCache()));
1813 EXPECT_THAT(b3, Not(InBackForwardCache()));
1814
1815 // 3) Navigate to a4.
1816 EXPECT_TRUE(NavigateToURL(shell(), url_a));
1817 RenderFrameHostImpl* a4 = current_frame_host();
1818 RenderFrameDeletedObserver a4_observer(a4);
1819 rfh_observer.push_back(&a4_observer);
1820 ASSERT_THAT(rfh_observer, Each(Not(Deleted())));
1821
1822 // 4) Navigate to b5
1823 EXPECT_TRUE(NavigateToURL(shell(), url_b));
1824 RenderFrameHostImpl* b5 = current_frame_host();
1825 RenderFrameDeletedObserver b5_observer(b5);
1826 rfh_observer.push_back(&b5_observer);
1827 ASSERT_THAT(rfh_observer, Each(Not(Deleted())));
1828 EXPECT_THAT(Elements({a1, b2, b3, a4}), Each(InBackForwardCache()));
1829 EXPECT_THAT(b5, Not(InBackForwardCache()));
1830
1831 // 3) Go back to a1(b2).
1832 web_contents()->GetController().GoToOffset(-3);
1833 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
1834 EXPECT_EQ(a1, current_frame_host());
1835 ASSERT_THAT(rfh_observer, Each(Not(Deleted())));
1836 EXPECT_THAT(Elements({b3, a4, b5}), Each(InBackForwardCache()));
1837 EXPECT_THAT(Elements({a1, b2}), Each(Not(InBackForwardCache())));
1838
1839 // Even after a new IPC round trip with the renderer, b2 must still be alive.
1840 EXPECT_EQ("I am alive", EvalJs(b2, "window.alive"));
1841 EXPECT_FALSE(b2_observer.deleted());
1842}
1843
Lowell Manners2d0163e42019-07-30 09:24:301844IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
1845 NavigationsAreFullyCommitted) {
Lowell Manners5cd4de42019-06-13 11:12:221846 ASSERT_TRUE(embedded_test_server()->Start());
1847
Lowell Manners2d0163e42019-07-30 09:24:301848 // During a navigation, the document being navigated *away from* can either be
1849 // deleted or stored into the BackForwardCache. The document being navigated
1850 // *to* can either be new or restored from the BackForwardCache.
1851 //
1852 // This test covers every combination:
1853 //
1854 // 1. Navigate to a cacheable page (()->A)
1855 // 2. Navigate to an uncacheable page (A->B)
1856 // 3. Go Back to a cached page (B->A)
1857 // 4. Navigate to a cacheable page (A->C)
1858 // 5. Go Back to a cached page (C->A)
1859 //
1860 // +-+-------+----------------+---------------+
1861 // |#|nav | curr_document | dest_document |
1862 // +-+-------+----------------+---------------|
1863 // |1|(()->A)| N/A | new |
1864 // |2|(A->B) | cached | new |
1865 // |3|(B->A) | deleted | restored |
1866 // |4|(A->C) | cached | new |
1867 // |5|(C->A) | cached | restored |
1868 // +-+-------+----------------+---------------+
1869 //
1870 // As part of these navigations we check that LastCommittedURL was updated,
1871 // to verify that the frame wasn't simply swapped in without actually
1872 // committing.
1873
arthursonzogni72b66492019-11-04 12:24:331874 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
1875 GURL url_b(embedded_test_server()->GetURL(
Lowell Mannersab6fb752019-07-23 09:31:091876 "b.com", "/back_forward_cache/page_with_dedicated_worker.html"));
arthursonzogni72b66492019-11-04 12:24:331877 GURL url_c(embedded_test_server()->GetURL("c.com", "/title1.html"));
Lowell Manners5cd4de42019-06-13 11:12:221878
Lowell Manners2d0163e42019-07-30 09:24:301879 // 1. Navigate to a cacheable page (A).
1880 EXPECT_TRUE(NavigateToURL(shell(), url_a));
Lowell Mannersab6fb752019-07-23 09:31:091881 RenderFrameHostImpl* rfh_a = current_frame_host();
Hajime Hoshif53fa7ca2019-08-13 06:52:341882 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
Lowell Manners5cd4de42019-06-13 11:12:221883
Lowell Manners2d0163e42019-07-30 09:24:301884 // 2. Navigate from a cacheable page to an uncacheable page (A->B).
1885 EXPECT_TRUE(NavigateToURL(shell(), url_b));
1886 EXPECT_EQ(web_contents()->GetLastCommittedURL(), url_b);
Lowell Mannersab6fb752019-07-23 09:31:091887 RenderFrameHostImpl* rfh_b = current_frame_host();
Hajime Hoshif53fa7ca2019-08-13 06:52:341888 RenderFrameDeletedObserver delete_observer_rfh_b(rfh_b);
Lowell Mannersab6fb752019-07-23 09:31:091889
Lowell Manners2d0163e42019-07-30 09:24:301890 // Page A should be in the cache.
Hajime Hoshif53fa7ca2019-08-13 06:52:341891 EXPECT_FALSE(delete_observer_rfh_a.deleted());
Hajime Hoshibbc509c2020-04-06 08:55:081892 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
Lowell Mannersab6fb752019-07-23 09:31:091893
Lowell Manners2d0163e42019-07-30 09:24:301894 // 3. Navigate from an uncacheable to a cached page page (B->A).
Lowell Mannersab6fb752019-07-23 09:31:091895 web_contents()->GetController().GoBack();
1896 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
Lowell Manners2d0163e42019-07-30 09:24:301897 EXPECT_EQ(web_contents()->GetLastCommittedURL(), url_a);
Lowell Mannersab6fb752019-07-23 09:31:091898
Lowell Manners2d0163e42019-07-30 09:24:301899 // Page B should be deleted (not cached).
Hajime Hoshif53fa7ca2019-08-13 06:52:341900 delete_observer_rfh_b.WaitUntilDeleted();
Lowell Manners2d0163e42019-07-30 09:24:301901
Fergal Daly09833062021-02-09 07:10:001902 ExpectRestored(FROM_HERE);
Hajime Hoshif9eba2b2019-10-02 08:27:421903
Lowell Manners2d0163e42019-07-30 09:24:301904 // 4. Navigate from a cacheable page to a cacheable page (A->C).
1905 EXPECT_TRUE(NavigateToURL(shell(), url_c));
1906 EXPECT_EQ(web_contents()->GetLastCommittedURL(), url_c);
1907 RenderFrameHostImpl* rfh_c = current_frame_host();
Hajime Hoshif53fa7ca2019-08-13 06:52:341908 RenderFrameDeletedObserver delete_observer_rfh_c(rfh_c);
Lowell Manners2d0163e42019-07-30 09:24:301909
1910 // Page A should be in the cache.
Hajime Hoshif53fa7ca2019-08-13 06:52:341911 EXPECT_FALSE(delete_observer_rfh_a.deleted());
Hajime Hoshibbc509c2020-04-06 08:55:081912 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
Lowell Manners2d0163e42019-07-30 09:24:301913
1914 // 5. Navigate from a cacheable page to a cached page (C->A).
1915 web_contents()->GetController().GoBack();
1916 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
1917 EXPECT_EQ(web_contents()->GetLastCommittedURL(), url_a);
1918
1919 // Page C should be in the cache.
Hajime Hoshif53fa7ca2019-08-13 06:52:341920 EXPECT_FALSE(delete_observer_rfh_c.deleted());
Hajime Hoshibbc509c2020-04-06 08:55:081921 EXPECT_TRUE(rfh_c->IsInBackForwardCache());
Hajime Hoshif9eba2b2019-10-02 08:27:421922
Fergal Daly09833062021-02-09 07:10:001923 ExpectRestored(FROM_HERE);
Lowell Manners2d0163e42019-07-30 09:24:301924}
1925
1926IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
Arthur Hemery549850f6e2019-10-01 13:17:431927 ProxiesAreStoredAndRestored) {
1928 // This test makes assumption about where iframe processes live.
1929 if (!AreAllSitesIsolatedForTesting())
1930 return;
1931
1932 ASSERT_TRUE(embedded_test_server()->Start());
1933
1934 // During a navigation, the document being navigated *away from* can either be
1935 // deleted or stored into the BackForwardCache. The document being navigated
1936 // *to* can either be new or restored from the BackForwardCache.
1937 //
1938 // This test covers every combination:
1939 //
1940 // 1. Navigate to a cacheable page (()->A)
1941 // 2. Navigate to an uncacheable page (A->B)
1942 // 3. Go Back to a cached page (B->A)
1943 // 4. Navigate to a cacheable page (A->C)
1944 // 5. Go Back to a cached page (C->A)
1945 //
1946 // +-+-------+----------------+---------------+
1947 // |#|nav | curr_document | dest_document |
1948 // +-+-------+----------------+---------------|
1949 // |1|(()->A)| N/A | new |
1950 // |2|(A->B) | cached | new |
1951 // |3|(B->A) | deleted | restored |
1952 // |4|(A->C) | cached | new |
1953 // |5|(C->A) | cached | restored |
1954 // +-+-------+----------------+---------------+
1955 //
1956 // We use pages with cross process iframes to verify that proxy storage and
1957 // retrieval works well in every possible combination.
1958
arthursonzogni72b66492019-11-04 12:24:331959 GURL url_a(embedded_test_server()->GetURL(
Arthur Hemery549850f6e2019-10-01 13:17:431960 "a.com", "/cross_site_iframe_factory.html?a(i,j)"));
arthursonzogni72b66492019-11-04 12:24:331961 GURL url_b(embedded_test_server()->GetURL(
Arthur Hemery549850f6e2019-10-01 13:17:431962 "b.com", "/back_forward_cache/page_with_dedicated_worker.html"));
arthursonzogni72b66492019-11-04 12:24:331963 GURL url_c(embedded_test_server()->GetURL(
Arthur Hemery549850f6e2019-10-01 13:17:431964 "c.com", "/cross_site_iframe_factory.html?c(k,l,m)"));
1965
1966 NavigationControllerImpl& controller = web_contents()->GetController();
1967 BackForwardCacheImpl& cache = controller.GetBackForwardCache();
1968
1969 // 1. Navigate to a cacheable page (A).
1970 EXPECT_TRUE(NavigateToURL(shell(), url_a));
1971 EXPECT_EQ(2u, render_frame_host_manager()->GetProxyCount());
1972 RenderFrameHostImpl* rfh_a = current_frame_host();
1973 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
Lowell Manners75055a132019-10-11 10:30:291974 std::string frame_tree_a = DepictFrameTree(rfh_a->frame_tree_node());
Arthur Hemery549850f6e2019-10-01 13:17:431975
1976 // 2. Navigate from a cacheable page to an uncacheable page (A->B).
1977 EXPECT_TRUE(NavigateToURL(shell(), url_b));
1978 EXPECT_EQ(0u, render_frame_host_manager()->GetProxyCount());
1979 RenderFrameHostImpl* rfh_b = current_frame_host();
1980 RenderFrameDeletedObserver delete_observer_rfh_b(rfh_b);
1981
1982 // Page A should be in the cache.
1983 EXPECT_FALSE(delete_observer_rfh_a.deleted());
Hajime Hoshibbc509c2020-04-06 08:55:081984 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
Arthur Hemery549850f6e2019-10-01 13:17:431985
1986 // Verify proxies are stored as well.
1987 auto* cached_entry = cache.GetEntry(rfh_a->nav_entry_id());
Yuzu Saijo68390b992021-07-27 06:17:201988 EXPECT_EQ(2u, cached_entry->proxy_hosts_size());
Arthur Hemery549850f6e2019-10-01 13:17:431989
1990 // 3. Navigate from an uncacheable to a cached page page (B->A).
1991 web_contents()->GetController().GoBack();
1992 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
Yuzu Saijo26b52292021-08-16 04:26:011993 // Note: Since we put the page B into BackForwardCache briefly, we do not
1994 // create a transition proxy. So there should be only proxies for i.com and
1995 // j.com.
1996 EXPECT_EQ(2u, render_frame_host_manager()->GetProxyCount());
Arthur Hemery549850f6e2019-10-01 13:17:431997
1998 // Page B should be deleted (not cached).
1999 delete_observer_rfh_b.WaitUntilDeleted();
2000 EXPECT_EQ(2u, render_frame_host_manager()->GetProxyCount());
2001
Lowell Manners75055a132019-10-11 10:30:292002 // Page A should still have the correct frame tree.
2003 EXPECT_EQ(frame_tree_a,
2004 DepictFrameTree(current_frame_host()->frame_tree_node()));
2005
Arthur Hemery549850f6e2019-10-01 13:17:432006 // 4. Navigate from a cacheable page to a cacheable page (A->C).
2007 EXPECT_TRUE(NavigateToURL(shell(), url_c));
2008 EXPECT_EQ(3u, render_frame_host_manager()->GetProxyCount());
2009 RenderFrameHostImpl* rfh_c = current_frame_host();
2010 RenderFrameDeletedObserver delete_observer_rfh_c(rfh_c);
2011
2012 // Page A should be in the cache.
2013 EXPECT_FALSE(delete_observer_rfh_a.deleted());
Hajime Hoshibbc509c2020-04-06 08:55:082014 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
Arthur Hemery549850f6e2019-10-01 13:17:432015
2016 // Verify proxies are stored as well.
2017 cached_entry = cache.GetEntry(rfh_a->nav_entry_id());
Yuzu Saijo68390b992021-07-27 06:17:202018 EXPECT_EQ(2u, cached_entry->proxy_hosts_size());
Arthur Hemery549850f6e2019-10-01 13:17:432019
2020 // 5. Navigate from a cacheable page to a cached page (C->A).
2021 web_contents()->GetController().GoBack();
2022 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
2023 EXPECT_EQ(2u, render_frame_host_manager()->GetProxyCount());
2024
Lowell Manners75055a132019-10-11 10:30:292025 // Page A should still have the correct frame tree.
2026 EXPECT_EQ(frame_tree_a,
2027 DepictFrameTree(current_frame_host()->frame_tree_node()));
2028
Arthur Hemery549850f6e2019-10-01 13:17:432029 // Page C should be in the cache.
2030 EXPECT_FALSE(delete_observer_rfh_c.deleted());
Hajime Hoshibbc509c2020-04-06 08:55:082031 EXPECT_TRUE(rfh_c->IsInBackForwardCache());
Arthur Hemery549850f6e2019-10-01 13:17:432032
2033 // Verify proxies are stored as well.
2034 cached_entry = cache.GetEntry(rfh_c->nav_entry_id());
Yuzu Saijo68390b992021-07-27 06:17:202035 EXPECT_EQ(3u, cached_entry->proxy_hosts_size());
Arthur Hemery549850f6e2019-10-01 13:17:432036}
2037
2038IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
2039 RestoredProxiesAreFunctional) {
2040 // This test makes assumption about where iframe processes live.
2041 if (!AreAllSitesIsolatedForTesting())
2042 return;
2043
2044 ASSERT_TRUE(embedded_test_server()->Start());
2045
2046 // Page A is cacheable, while page B is not.
arthursonzogni72b66492019-11-04 12:24:332047 GURL url_a(embedded_test_server()->GetURL(
Arthur Hemery549850f6e2019-10-01 13:17:432048 "a.com", "/cross_site_iframe_factory.html?a(z)"));
arthursonzogni72b66492019-11-04 12:24:332049 GURL url_b(embedded_test_server()->GetURL(
Arthur Hemery549850f6e2019-10-01 13:17:432050 "b.com", "/back_forward_cache/page_with_dedicated_worker.html"));
arthursonzogni72b66492019-11-04 12:24:332051 GURL test_url(embedded_test_server()->GetURL("c.com", "/title1.html"));
Arthur Hemery549850f6e2019-10-01 13:17:432052
2053 NavigationControllerImpl& controller = web_contents()->GetController();
2054
2055 // 1. Navigate to a cacheable page (A).
2056 EXPECT_TRUE(NavigateToURL(shell(), url_a));
2057 RenderFrameHostImpl* rfh_a = current_frame_host();
2058
2059 // 2. Navigate from a cacheable page to an uncacheable page (A->B).
2060 EXPECT_TRUE(NavigateToURL(shell(), url_b));
2061
2062 // 3. Navigate from an uncacheable to a cached page page (B->A).
2063 // This restores the top frame's proxy in the z.com (iframe's) process.
2064 web_contents()->GetController().GoBack();
2065 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
2066
2067 // 4. Verify that the main frame's z.com proxy is still functional.
2068 RenderFrameHostImpl* iframe =
2069 rfh_a->frame_tree_node()->child_at(0)->current_frame_host();
2070 EXPECT_TRUE(ExecJs(iframe, "top.location.href = '" + test_url.spec() + "';"));
2071 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
2072
2073 // We expect to have navigated through the proxy.
2074 EXPECT_EQ(test_url, controller.GetLastCommittedEntry()->GetURL());
2075}
2076
2077IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
Lowell Manners2d0163e42019-07-30 09:24:302078 PageWithDedicatedWorkerNotCached) {
2079 ASSERT_TRUE(embedded_test_server()->Start());
2080
2081 EXPECT_TRUE(NavigateToURL(
2082 shell(),
2083 embedded_test_server()->GetURL(
2084 "a.com", "/back_forward_cache/page_with_dedicated_worker.html")));
Hajime Hoshif53fa7ca2019-08-13 06:52:342085 RenderFrameDeletedObserver delete_observer_rfh_a(current_frame_host());
Lowell Manners2d0163e42019-07-30 09:24:302086
2087 // Navigate away.
2088 EXPECT_TRUE(NavigateToURL(
2089 shell(), embedded_test_server()->GetURL("b.com", "/title1.html")));
2090
2091 // The page with the unsupported feature should be deleted (not cached).
Hajime Hoshif53fa7ca2019-08-13 06:52:342092 delete_observer_rfh_a.WaitUntilDeleted();
Lowell Manners5cd4de42019-06-13 11:12:222093}
Hajime Hoshia0fc0872019-07-09 04:20:342094
Yuzu Saijo5344e4eb2019-09-26 05:56:582095// TODO(https://crbug.com/154571): Shared workers are not available on Android.
2096#if defined(OS_ANDROID)
2097#define MAYBE_PageWithSharedWorkerNotCached \
2098 DISABLED_PageWithSharedWorkerNotCached
2099#else
2100#define MAYBE_PageWithSharedWorkerNotCached PageWithSharedWorkerNotCached
2101#endif
2102IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
2103 MAYBE_PageWithSharedWorkerNotCached) {
2104 ASSERT_TRUE(embedded_test_server()->Start());
2105
2106 EXPECT_TRUE(NavigateToURL(
2107 shell(),
2108 embedded_test_server()->GetURL(
2109 "a.com", "/back_forward_cache/page_with_shared_worker.html")));
2110 RenderFrameDeletedObserver delete_observer_rfh_a(current_frame_host());
2111
2112 // Navigate away.
2113 EXPECT_TRUE(NavigateToURL(
2114 shell(), embedded_test_server()->GetURL("b.com", "/title1.html")));
2115
2116 // The page with the unsupported feature should be deleted (not cached).
2117 delete_observer_rfh_a.WaitUntilDeleted();
Hajime Hoshi45255602019-10-18 07:26:592118
2119 // Go back.
2120 web_contents()->GetController().GoBack();
2121 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
2122 ExpectNotRestored(
Hajime Hoshi15f6b5012019-10-24 05:25:492123 {BackForwardCacheMetrics::NotRestoredReason::kBlocklistedFeatures},
Fergal Daly6755cbf2021-02-12 03:06:582124 {blink::scheduler::WebSchedulerTrackedFeature::kSharedWorker}, {}, {},
Hajime Hoshi45255602019-10-18 07:26:592125 FROM_HERE);
Yuzu Saijo5344e4eb2019-09-26 05:56:582126}
2127
Lowell Manners531e623d2019-08-21 17:01:522128IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
kouheic618f7c2021-05-21 11:05:522129 SubframeWithDisallowedFeatureNotCached) {
Lowell Manners531e623d2019-08-21 17:01:522130 ASSERT_TRUE(embedded_test_server()->Start());
2131
2132 // Navigate to a page with an iframe that contains a dedicated worker.
2133 EXPECT_TRUE(NavigateToURL(
2134 shell(),
2135 embedded_test_server()->GetURL(
2136 "a.com", "/back_forward_cache/dedicated_worker_in_subframe.html")));
kouheic618f7c2021-05-21 11:05:522137 EXPECT_EQ(42, EvalJs(current_frame_host()->child_at(0)->current_frame_host(),
2138 "window.receivedMessagePromise"));
2139
Lowell Manners531e623d2019-08-21 17:01:522140 RenderFrameDeletedObserver delete_rfh_a(current_frame_host());
2141
2142 // Navigate away.
2143 EXPECT_TRUE(NavigateToURL(
2144 shell(), embedded_test_server()->GetURL("b.com", "/title1.html")));
2145
2146 // The page with the unsupported feature should be deleted (not cached).
2147 delete_rfh_a.WaitUntilDeleted();
Hajime Hoshi45255602019-10-18 07:26:592148
2149 // Go back.
2150 web_contents()->GetController().GoBack();
2151 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
2152 ExpectNotRestored(
Hajime Hoshi15f6b5012019-10-24 05:25:492153 {BackForwardCacheMetrics::NotRestoredReason::kBlocklistedFeatures},
Fergal Daly6755cbf2021-02-12 03:06:582154 {blink::scheduler::WebSchedulerTrackedFeature::kDedicatedWorkerOrWorklet},
2155 {}, {}, FROM_HERE);
Lowell Manners531e623d2019-08-21 17:01:522156}
2157
Alexander Timin26864e12019-10-18 02:00:062158IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
2159 SubframeWithOngoingNavigationNotCached) {
2160 net::test_server::ControllableHttpResponse response(embedded_test_server(),
2161 "/hung");
2162 ASSERT_TRUE(embedded_test_server()->Start());
2163
2164 // Navigate to a page with an iframe.
2165 TestNavigationObserver navigation_observer1(web_contents());
2166 GURL main_url(embedded_test_server()->GetURL(
2167 "a.com", "/back_forward_cache/page_with_hung_iframe.html"));
2168 shell()->LoadURL(main_url);
2169 navigation_observer1.WaitForNavigationFinished();
2170
2171 RenderFrameHostImpl* main_frame = current_frame_host();
2172 RenderFrameDeletedObserver frame_deleted_observer(main_frame);
2173 response.WaitForRequest();
2174
2175 // Navigate away.
2176 TestNavigationObserver navigation_observer2(web_contents());
2177 shell()->LoadURL(embedded_test_server()->GetURL("b.com", "/title1.html"));
2178 navigation_observer2.WaitForNavigationFinished();
2179
2180 // The page with the unsupported feature should be deleted (not cached).
2181 frame_deleted_observer.WaitUntilDeleted();
2182}
2183
Hajime Hoshia0fc0872019-07-09 04:20:342184// Check that unload event handlers are not dispatched when the page goes
2185// into BackForwardCache.
2186IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
2187 ConfirmUnloadEventNotFired) {
2188 ASSERT_TRUE(embedded_test_server()->Start());
arthursonzogni72b66492019-11-04 12:24:332189 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
2190 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
Hajime Hoshia0fc0872019-07-09 04:20:342191
2192 // 1) Navigate to A.
2193 EXPECT_TRUE(NavigateToURL(shell(), url_a));
2194 RenderFrameHostImpl* rfh_a = current_frame_host();
Hajime Hoshif53fa7ca2019-08-13 06:52:342195 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
Hajime Hoshia0fc0872019-07-09 04:20:342196
2197 // 2) Set unload handler and check the title.
2198 EXPECT_TRUE(ExecJs(rfh_a,
2199 "document.title = 'loaded!';"
2200 "window.addEventListener('unload', () => {"
2201 " document.title = 'unloaded!';"
2202 "});"));
2203 {
Jan Wilken Dörrie2c470ea2021-03-22 22:26:242204 std::u16string title_when_loaded = u"loaded!";
Hajime Hoshia0fc0872019-07-09 04:20:342205 TitleWatcher title_watcher(web_contents(), title_when_loaded);
2206 EXPECT_EQ(title_watcher.WaitAndGetTitle(), title_when_loaded);
2207 }
2208
2209 // 3) Navigate to B.
2210 EXPECT_TRUE(NavigateToURL(shell(), url_b));
2211 RenderFrameHostImpl* rfh_b = current_frame_host();
Hajime Hoshif53fa7ca2019-08-13 06:52:342212 RenderFrameDeletedObserver delete_observer_rfh_b(rfh_b);
2213 EXPECT_FALSE(delete_observer_rfh_a.deleted());
Hajime Hoshibbc509c2020-04-06 08:55:082214 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
2215 EXPECT_FALSE(rfh_b->IsInBackForwardCache());
Hajime Hoshia0fc0872019-07-09 04:20:342216
2217 // 4) Go back to A and check the title again.
2218 web_contents()->GetController().GoBack();
2219 EXPECT_TRUE(WaitForLoadStop(web_contents()));
Hajime Hoshif53fa7ca2019-08-13 06:52:342220 EXPECT_FALSE(delete_observer_rfh_a.deleted());
2221 EXPECT_FALSE(delete_observer_rfh_b.deleted());
Hajime Hoshia0fc0872019-07-09 04:20:342222 EXPECT_EQ(rfh_a, current_frame_host());
Hajime Hoshibbc509c2020-04-06 08:55:082223 EXPECT_TRUE(rfh_b->IsInBackForwardCache());
Hajime Hoshia0fc0872019-07-09 04:20:342224 {
Jan Wilken Dörrie2c470ea2021-03-22 22:26:242225 std::u16string title_when_loaded = u"loaded!";
Hajime Hoshia0fc0872019-07-09 04:20:342226 TitleWatcher title_watcher(web_contents(), title_when_loaded);
2227 EXPECT_EQ(title_watcher.WaitAndGetTitle(), title_when_loaded);
2228 }
2229}
2230
Lowell Mannersb3b30c22019-07-26 11:31:412231IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
kouhei48ca3222021-05-24 06:17:462232 DoesNotCacheIfRecordingAudio) {
Kouhei Ueno01b0f1192019-08-14 05:28:072233 ASSERT_TRUE(embedded_test_server()->Start());
2234
Harkiran Bolariacc39d8a2020-06-12 02:14:272235 BackForwardCacheDisabledTester tester;
2236
Kouhei Ueno01b0f1192019-08-14 05:28:072237 // Navigate to an empty page.
2238 GURL url(embedded_test_server()->GetURL("/title1.html"));
2239 EXPECT_TRUE(NavigateToURL(shell(), url));
Harkiran Bolariacc39d8a2020-06-12 02:14:272240 int process_id = current_frame_host()->GetProcess()->GetID();
2241 int routing_id = current_frame_host()->GetRoutingID();
Kouhei Ueno01b0f1192019-08-14 05:28:072242
2243 // Request for audio recording.
2244 EXPECT_EQ("success", EvalJs(current_frame_host(), R"(
2245 new Promise(resolve => {
2246 navigator.mediaDevices.getUserMedia({audio: true})
kouhei48ca3222021-05-24 06:17:462247 .then(m => { window.keepaliveMedia = m; resolve("success"); })
Kouhei Ueno01b0f1192019-08-14 05:28:072248 .catch(() => { resolve("error"); });
2249 });
2250 )"));
2251
2252 RenderFrameDeletedObserver deleted(current_frame_host());
2253
2254 // 2) Navigate away.
2255 shell()->LoadURL(embedded_test_server()->GetURL("b.com", "/title1.html"));
2256
2257 // The page was still recording audio when we navigated away, so it shouldn't
2258 // have been cached.
2259 deleted.WaitUntilDeleted();
Hajime Hoshi45255602019-10-18 07:26:592260
Harkiran Bolariacc39d8a2020-06-12 02:14:272261 // 3) Go back. Note that the reason for kWasGrantedMediaAccess occurs after
2262 // MediaDevicesDispatcherHost is called, hence, both are reasons for the page
2263 // not being restored.
Hajime Hoshi45255602019-10-18 07:26:592264 web_contents()->GetController().GoBack();
2265 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
Fergal Daly23b8ae62021-03-30 05:43:462266 auto reason = BackForwardCacheDisable::DisabledReason(
2267 BackForwardCacheDisable::DisabledReasonId::kMediaDevicesDispatcherHost);
Hajime Hoshi45255602019-10-18 07:26:592268 ExpectNotRestored(
Harkiran Bolariacc39d8a2020-06-12 02:14:272269 {BackForwardCacheMetrics::NotRestoredReason::kWasGrantedMediaAccess,
2270 BackForwardCacheMetrics::NotRestoredReason::
2271 kDisableForRenderFrameHostCalled},
Fergal Daly23b8ae62021-03-30 05:43:462272 {}, {}, {reason}, FROM_HERE);
2273 EXPECT_TRUE(
2274 tester.IsDisabledForFrameWithReason(process_id, routing_id, reason));
Kouhei Ueno01b0f1192019-08-14 05:28:072275}
2276
2277IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
Lowell Manners0cc90622019-08-22 12:12:572278 DoesNotCacheIfSubframeRecordingAudio) {
2279 ASSERT_TRUE(embedded_test_server()->Start());
2280
Harkiran Bolariacc39d8a2020-06-12 02:14:272281 BackForwardCacheDisabledTester tester;
2282
Lowell Manners0cc90622019-08-22 12:12:572283 // Navigate to a page with an iframe.
2284 GURL url(embedded_test_server()->GetURL("/page_with_iframe.html"));
2285 EXPECT_TRUE(NavigateToURL(shell(), url));
2286 RenderFrameHostImpl* rfh = current_frame_host();
Harkiran Bolariacc39d8a2020-06-12 02:14:272287 int process_id =
2288 rfh->child_at(0)->current_frame_host()->GetProcess()->GetID();
2289 int routing_id = rfh->child_at(0)->current_frame_host()->GetRoutingID();
Lowell Manners0cc90622019-08-22 12:12:572290
2291 // Request for audio recording from the subframe.
2292 EXPECT_EQ("success", EvalJs(rfh->child_at(0)->current_frame_host(), R"(
2293 new Promise(resolve => {
2294 navigator.mediaDevices.getUserMedia({audio: true})
2295 .then(m => { resolve("success"); })
2296 .catch(() => { resolve("error"); });
2297 });
2298 )"));
2299
2300 RenderFrameDeletedObserver deleted(current_frame_host());
2301
2302 // 2) Navigate away.
2303 shell()->LoadURL(embedded_test_server()->GetURL("b.com", "/title1.html"));
2304
2305 // The page was still recording audio when we navigated away, so it shouldn't
2306 // have been cached.
2307 deleted.WaitUntilDeleted();
Hajime Hoshi45255602019-10-18 07:26:592308
Harkiran Bolariacc39d8a2020-06-12 02:14:272309 // 3) Go back. Note that the reason for kWasGrantedMediaAccess occurs after
2310 // MediaDevicesDispatcherHost is called, hence, both are reasons for the page
2311 // not being restored.
Hajime Hoshi45255602019-10-18 07:26:592312 web_contents()->GetController().GoBack();
2313 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
Fergal Daly23b8ae62021-03-30 05:43:462314 auto reason = BackForwardCacheDisable::DisabledReason(
2315 BackForwardCacheDisable::DisabledReasonId::kMediaDevicesDispatcherHost);
2316
Hajime Hoshi45255602019-10-18 07:26:592317 ExpectNotRestored(
Harkiran Bolariacc39d8a2020-06-12 02:14:272318 {BackForwardCacheMetrics::NotRestoredReason::kWasGrantedMediaAccess,
2319 BackForwardCacheMetrics::NotRestoredReason::
2320 kDisableForRenderFrameHostCalled},
Fergal Daly23b8ae62021-03-30 05:43:462321 {}, {}, {reason}, FROM_HERE);
2322 EXPECT_TRUE(
2323 tester.IsDisabledForFrameWithReason(process_id, routing_id, reason));
Harkiran Bolariacc39d8a2020-06-12 02:14:272324}
2325
2326IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
2327 DoesNotCacheIfMediaDeviceSubscribed) {
2328 ASSERT_TRUE(embedded_test_server()->Start());
2329
2330 BackForwardCacheDisabledTester tester;
2331
2332 // Navigate to a page with an iframe.
2333 GURL url(embedded_test_server()->GetURL("/page_with_iframe.html"));
2334 EXPECT_TRUE(NavigateToURL(shell(), url));
2335 RenderFrameHostImpl* rfh = current_frame_host();
2336 int process_id =
2337 rfh->child_at(0)->current_frame_host()->GetProcess()->GetID();
2338 int routing_id = rfh->child_at(0)->current_frame_host()->GetRoutingID();
2339
2340 EXPECT_EQ("success", EvalJs(rfh->child_at(0)->current_frame_host(), R"(
2341 new Promise(resolve => {
2342 navigator.mediaDevices.addEventListener('devicechange', function(event){});
2343 resolve("success");
2344 });
2345 )"));
2346
2347 RenderFrameDeletedObserver deleted(current_frame_host());
2348
2349 // 2) Navigate away.
2350 shell()->LoadURL(embedded_test_server()->GetURL("b.com", "/title1.html"));
2351
2352 // The page was subscribed to media devices when we navigated away, so it
2353 // shouldn't have been cached.
2354 deleted.WaitUntilDeleted();
2355
2356 // 3) Go back.
2357 web_contents()->GetController().GoBack();
2358 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
Fergal Daly23b8ae62021-03-30 05:43:462359 auto reason = BackForwardCacheDisable::DisabledReason(
2360 BackForwardCacheDisable::DisabledReasonId::kMediaDevicesDispatcherHost);
Harkiran Bolariacc39d8a2020-06-12 02:14:272361 ExpectNotRestored({BackForwardCacheMetrics::NotRestoredReason::
2362 kDisableForRenderFrameHostCalled},
Fergal Daly23b8ae62021-03-30 05:43:462363 {}, {}, {reason}, FROM_HERE);
2364 EXPECT_TRUE(
2365 tester.IsDisabledForFrameWithReason(process_id, routing_id, reason));
Lowell Manners0cc90622019-08-22 12:12:572366}
2367
Alexander Hendrich06842842020-04-28 11:46:252368// TODO(https://crbug.com/1075936) disabled due to flakiness
Lowell Manners0cc90622019-08-22 12:12:572369IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
Alexander Hendrich06842842020-04-28 11:46:252370 DISABLED_DoesNotCacheIfMainFrameStillLoading) {
Lowell Mannersb3b30c22019-07-26 11:31:412371 net::test_server::ControllableHttpResponse response(embedded_test_server(),
2372 "/main_document");
2373 ASSERT_TRUE(embedded_test_server()->Start());
2374
2375 // 1) Navigate to a page that doesn't finish loading.
2376 GURL url(embedded_test_server()->GetURL("a.com", "/main_document"));
2377 TestNavigationManager navigation_manager(shell()->web_contents(), url);
2378 shell()->LoadURL(url);
2379
2380 // The navigation starts.
2381 EXPECT_TRUE(navigation_manager.WaitForRequestStart());
2382 navigation_manager.ResumeNavigation();
2383
2384 // The server sends the first part of the response and waits.
2385 response.WaitForRequest();
2386 response.Send(
2387 "HTTP/1.1 200 OK\r\n"
2388 "Content-Type: text/html; charset=utf-8\r\n"
2389 "\r\n"
2390 "<html><body> ... ");
2391
2392 // The navigation finishes while the body is still loading.
2393 navigation_manager.WaitForNavigationFinished();
Hajime Hoshif53fa7ca2019-08-13 06:52:342394 RenderFrameDeletedObserver delete_observer_rfh_a(current_frame_host());
Lowell Mannersb3b30c22019-07-26 11:31:412395
2396 // 2) Navigate away.
2397 shell()->LoadURL(embedded_test_server()->GetURL("b.com", "/title1.html"));
2398
2399 // The page was still loading when we navigated away, so it shouldn't have
2400 // been cached.
Hajime Hoshif53fa7ca2019-08-13 06:52:342401 delete_observer_rfh_a.WaitUntilDeleted();
Hajime Hoshi45255602019-10-18 07:26:592402
2403 // 3) Go back.
2404 web_contents()->GetController().GoBack();
2405 EXPECT_FALSE(WaitForLoadStop(shell()->web_contents()));
Fergal Daly6755cbf2021-02-12 03:06:582406 ExpectNotRestored({BackForwardCacheMetrics::NotRestoredReason::kLoading}, {},
2407 {}, {}, FROM_HERE);
Lowell Mannersb3b30c22019-07-26 11:31:412408}
2409
2410IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
Lowell Manners6d662e22019-08-21 15:03:012411 DoesNotCacheLoadingSubframe) {
2412 net::test_server::ControllableHttpResponse response(embedded_test_server(),
2413 "/controlled");
Lowell Mannersb3b30c22019-07-26 11:31:412414 ASSERT_TRUE(embedded_test_server()->Start());
2415
2416 // 1) Navigate to a page with an iframe that loads forever.
Lowell Manners6d662e22019-08-21 15:03:012417 GURL url(embedded_test_server()->GetURL(
2418 "a.com", "/back_forward_cache/controllable_subframe.html"));
Lowell Mannersb3b30c22019-07-26 11:31:412419 TestNavigationManager navigation_manager(shell()->web_contents(), url);
2420 shell()->LoadURL(url);
2421
2422 // The navigation finishes while the iframe is still loading.
2423 navigation_manager.WaitForNavigationFinished();
Lowell Manners6d662e22019-08-21 15:03:012424
2425 // Wait for the iframe request to arrive, and leave it hanging with no
2426 // response.
2427 response.WaitForRequest();
2428
Lowell Mannersb3b30c22019-07-26 11:31:412429 RenderFrameHostImpl* rfh_a = current_frame_host();
Hajime Hoshif53fa7ca2019-08-13 06:52:342430 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
Lowell Mannersb3b30c22019-07-26 11:31:412431
2432 // 2) Navigate away.
2433 shell()->LoadURL(embedded_test_server()->GetURL("b.com", "/title1.html"));
2434 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
2435
Lowell Manners6d662e22019-08-21 15:03:012436 // The page should not have been added to cache, since it had a subframe that
2437 // was still loading at the time it was navigated away from.
2438 delete_observer_rfh_a.WaitUntilDeleted();
Hajime Hoshi45255602019-10-18 07:26:592439
2440 // 3) Go back.
2441 web_contents()->GetController().GoBack();
2442 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
Hajime Hoshi15f6b5012019-10-24 05:25:492443 ExpectNotRestored(
2444 {
2445 BackForwardCacheMetrics::NotRestoredReason::kLoading,
2446 BackForwardCacheMetrics::NotRestoredReason::kSubframeIsNavigating,
2447 },
Fergal Daly6755cbf2021-02-12 03:06:582448 {}, {}, {}, FROM_HERE);
Lowell Manners6d662e22019-08-21 15:03:012449}
2450
2451IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
2452 DoesNotCacheLoadingSubframeOfSubframe) {
2453 net::test_server::ControllableHttpResponse response(embedded_test_server(),
2454 "/controlled");
2455 ASSERT_TRUE(embedded_test_server()->Start());
2456
2457 // 1) Navigate to a page with an iframe that contains yet another iframe, that
2458 // hangs while loading.
2459 GURL url(embedded_test_server()->GetURL(
2460 "a.com", "/back_forward_cache/controllable_subframe_of_subframe.html"));
2461 TestNavigationManager navigation_manager(shell()->web_contents(), url);
2462 shell()->LoadURL(url);
2463
2464 // The navigation finishes while the iframe within an iframe is still loading.
2465 navigation_manager.WaitForNavigationFinished();
2466
2467 // Wait for the innermost iframe request to arrive, and leave it hanging with
2468 // no response.
2469 response.WaitForRequest();
2470
2471 RenderFrameHostImpl* rfh_a = current_frame_host();
2472 RenderFrameDeletedObserver delete_rfh_a(rfh_a);
2473
2474 // 2) Navigate away.
2475 shell()->LoadURL(embedded_test_server()->GetURL("b.com", "/title1.html"));
2476 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
2477
2478 // The page should not have been added to the cache, since it had an iframe
2479 // that was still loading at the time it was navigated away from.
2480 delete_rfh_a.WaitUntilDeleted();
Hajime Hoshi45255602019-10-18 07:26:592481
2482 // 3) Go back.
2483 web_contents()->GetController().GoBack();
2484 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
Hajime Hoshi15f6b5012019-10-24 05:25:492485 ExpectNotRestored(
2486 {
2487 BackForwardCacheMetrics::NotRestoredReason::kLoading,
2488 BackForwardCacheMetrics::NotRestoredReason::kSubframeIsNavigating,
2489 },
Fergal Daly6755cbf2021-02-12 03:06:582490 {}, {}, {}, FROM_HERE);
Lowell Mannersb3b30c22019-07-26 11:31:412491}
Kouhei Ueno19a5591f2019-08-01 07:29:422492
Hajime Hoshibc21e732020-11-11 03:09:532493IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, CacheIfWebGL) {
Kouhei Ueno19a5591f2019-08-01 07:29:422494 ASSERT_TRUE(embedded_test_server()->Start());
2495
2496 // 1) Navigate to a page with WebGL usage
2497 GURL url(embedded_test_server()->GetURL(
2498 "example.com", "/back_forward_cache/page_with_webgl.html"));
2499 EXPECT_TRUE(NavigateToURL(shell(), url));
2500
Kouhei Ueno19a5591f2019-08-01 07:29:422501 // 2) Navigate away.
Hajime Hoshibc21e732020-11-11 03:09:532502 EXPECT_TRUE(NavigateToURL(
2503 shell(), embedded_test_server()->GetURL("b.com", "/title1.html")));
Kouhei Ueno19a5591f2019-08-01 07:29:422504
2505 // The page had an active WebGL context when we navigated away,
Hajime Hoshibc21e732020-11-11 03:09:532506 // but it should be cached.
Hajime Hoshi45255602019-10-18 07:26:592507
2508 // 3) Go back.
2509 web_contents()->GetController().GoBack();
2510 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
Fergal Daly09833062021-02-09 07:10:002511 ExpectRestored(FROM_HERE);
Lowell Manners573470e2019-08-02 12:36:232512}
2513
Oksana Zhuravlova3f3295d2020-03-06 21:43:072514// Since blink::mojom::HidService binder is not added in
2515// content/browser/browser_interface_binders.cc for Android, this test is not
2516// applicable for this OS.
2517#if !defined(OS_ANDROID)
Yuzu Saijo20713482020-01-08 04:04:092518IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, DoesNotCacheIfWebHID) {
2519 ASSERT_TRUE(embedded_test_server()->Start());
2520
Yuzu Saijobaa102872020-01-10 08:24:082521 // 1) Navigate to an empty page.
Yuzu Saijo20713482020-01-08 04:04:092522 GURL url(embedded_test_server()->GetURL("/title1.html"));
2523 EXPECT_TRUE(NavigateToURL(shell(), url));
2524
2525 // Request for HID devices.
2526 EXPECT_EQ("success", EvalJs(current_frame_host(), R"(
2527 new Promise(resolve => {
2528 navigator.hid.getDevices()
2529 .then(m => { resolve("success"); })
2530 .catch(() => { resolve("error"); });
2531 });
2532 )"));
2533
2534 RenderFrameDeletedObserver deleted(current_frame_host());
2535
2536 // 2) Navigate away.
2537 shell()->LoadURL(embedded_test_server()->GetURL("b.com", "/title1.html"));
2538
2539 // The page uses WebHID so it should be deleted.
2540 deleted.WaitUntilDeleted();
2541
2542 // 3) Go back.
2543 web_contents()->GetController().GoBack();
2544 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
2545 ExpectNotRestored(
2546 {BackForwardCacheMetrics::NotRestoredReason::kBlocklistedFeatures},
Fergal Daly6755cbf2021-02-12 03:06:582547 {blink::scheduler::WebSchedulerTrackedFeature::kWebHID}, {}, {},
Yuzu Saijo20713482020-01-08 04:04:092548 FROM_HERE);
Yuzu Saijo20713482020-01-08 04:04:092549}
Oksana Zhuravlova3f3295d2020-03-06 21:43:072550#endif // !defined(OS_ANDROID)
Yuzu Saijo20713482020-01-08 04:04:092551
Yuzu Saijobaa102872020-01-10 08:24:082552IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
Yuzu Saijo6595e5c2021-02-08 03:25:472553 WakeLockReleasedUponEnteringBfcache) {
Yuzu Saijo45d8cfd2020-10-02 03:52:232554 ASSERT_TRUE(CreateHttpsServer()->Start());
Yuzu Saijobaa102872020-01-10 08:24:082555
2556 // 1) Navigate to a page with WakeLock usage.
Yuzu Saijo6595e5c2021-02-08 03:25:472557 GURL url(https_server()->GetURL(
2558 "a.com", "/back_forward_cache/page_with_wakelock.html"));
Yuzu Saijobaa102872020-01-10 08:24:082559 EXPECT_TRUE(NavigateToURL(shell(), url));
2560
2561 RenderFrameHostImpl* rfh_a = current_frame_host();
Yuzu Saijobaa102872020-01-10 08:24:082562 // Acquire WakeLock.
Yuzu Saijo6595e5c2021-02-08 03:25:472563 EXPECT_EQ("DONE", EvalJs(rfh_a, "acquireWakeLock()"));
2564 // Make sure that WakeLock is not released yet.
2565 EXPECT_FALSE(EvalJs(rfh_a, "wakeLockIsReleased()").ExtractBool());
Yuzu Saijobaa102872020-01-10 08:24:082566
Yuzu Saijobaa102872020-01-10 08:24:082567 // 2) Navigate away.
Yuzu Saijo45d8cfd2020-10-02 03:52:232568 shell()->LoadURL(https_server()->GetURL("b.com", "/title1.html"));
2569 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
2570 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
Yuzu Saijobaa102872020-01-10 08:24:082571
Yuzu Saijo6595e5c2021-02-08 03:25:472572 // 3) Go back to the page with WakeLock, restored from BackForwardCache.
Yuzu Saijobaa102872020-01-10 08:24:082573 web_contents()->GetController().GoBack();
2574 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
Yuzu Saijo45d8cfd2020-10-02 03:52:232575 EXPECT_EQ(current_frame_host(), rfh_a);
Yuzu Saijo6595e5c2021-02-08 03:25:472576 EXPECT_TRUE(EvalJs(rfh_a, "wakeLockIsReleased()").ExtractBool());
Fergal Daly09833062021-02-09 07:10:002577 ExpectRestored(FROM_HERE);
Yuzu Saijo45d8cfd2020-10-02 03:52:232578}
2579
Hajime Hoshi459690152021-08-17 14:08:022580IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, CacheWithWebFileSystem) {
Yuzu Saijo70940462020-03-16 09:32:302581 ASSERT_TRUE(embedded_test_server()->Start());
2582
2583 // 1) Navigate to a page with WebFileSystem usage.
Hajime Hoshi459690152021-08-17 14:08:022584 GURL url(embedded_test_server()->GetURL("a.test", "/title1.html"));
Yuzu Saijo70940462020-03-16 09:32:302585 EXPECT_TRUE(NavigateToURL(shell(), url));
2586 RenderFrameHostImpl* rfh_a = current_frame_host();
Hajime Hoshi459690152021-08-17 14:08:022587 // Writer a file 'file.txt' with a content 'foo'.
2588 EXPECT_EQ("success", EvalJs(rfh_a, R"(
2589 new Promise((resolve, reject) => {
2590 window.webkitRequestFileSystem(
2591 window.TEMPORARY,
2592 1024 * 1024,
2593 (fs) => {
2594 fs.root.getFile('file.txt', {create: true}, (entry) => {
2595 entry.createWriter((writer) => {
2596 writer.onwriteend = () => {
2597 resolve('success');
2598 };
2599 writer.onerror = reject;
2600 var blob = new Blob(['foo'], {type: 'text/plain'});
2601 writer.write(blob);
2602 }, reject);
2603 }, reject);
2604 }, reject);
2605 });
2606 )"));
Yuzu Saijo70940462020-03-16 09:32:302607
2608 // 2) Navigate away.
Hajime Hoshi459690152021-08-17 14:08:022609 shell()->LoadURL(embedded_test_server()->GetURL("b.test", "/title1.html"));
2610 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
Yuzu Saijo70940462020-03-16 09:32:302611
2612 // 3) Go back to the page with WebFileSystem.
2613 web_contents()->GetController().GoBack();
2614 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
Hajime Hoshi459690152021-08-17 14:08:022615 ExpectRestored(FROM_HERE);
2616 // Check the file content is reserved.
2617 EXPECT_EQ("foo", EvalJs(rfh_a, R"(
2618 new Promise((resolve, reject) => {
2619 window.webkitRequestFileSystem(
2620 window.TEMPORARY,
2621 1024 * 1024,
2622 (fs) => {
2623 fs.root.getFile('file.txt', {}, (entry) => {
2624 entry.file((file) => {
2625 const reader = new FileReader();
2626 reader.onloadend = (e) => {
2627 resolve(e.target.result);
2628 };
2629 reader.readAsText(file);
2630 }, reject);
2631 }, reject);
2632 }, reject);
2633 });
2634 )"));
Yuzu Saijo70940462020-03-16 09:32:302635}
2636
Mohamed Abdelhalim462fff32019-08-13 14:13:422637IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, DoesNotCacheIfHttpError) {
2638 ASSERT_TRUE(embedded_test_server()->Start());
2639
2640 GURL error_url(embedded_test_server()->GetURL("a.com", "/page404.html"));
2641 GURL url(embedded_test_server()->GetURL("b.com", "/title1.html"));
2642
2643 // Navigate to an error page.
2644 EXPECT_TRUE(NavigateToURL(shell(), error_url));
2645 EXPECT_EQ(net::HTTP_NOT_FOUND, current_frame_host()->last_http_status_code());
2646 RenderFrameDeletedObserver delete_rfh_a(current_frame_host());
2647
2648 // Navigate away.
2649 EXPECT_TRUE(NavigateToURL(shell(), url));
2650
2651 // The page did not return 200 (OK), so it shouldn't have been cached.
2652 delete_rfh_a.WaitUntilDeleted();
Hajime Hoshi45255602019-10-18 07:26:592653
2654 // Go back.
2655 web_contents()->GetController().GoBack();
2656 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
2657 ExpectNotRestored(
Fergal Daly6755cbf2021-02-12 03:06:582658 {BackForwardCacheMetrics::NotRestoredReason::kHTTPStatusNotOK}, {}, {},
2659 {}, FROM_HERE);
Mohamed Abdelhalim462fff32019-08-13 14:13:422660}
2661
Harkiran Bolaria335ae2c2020-06-02 15:22:302662IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, DoesNotCacheIdleManager) {
2663 ASSERT_TRUE(embedded_test_server()->Start());
2664
2665 // 1) Navigate to a page and start using the IdleManager class.
2666 GURL url(embedded_test_server()->GetURL("/title1.html"));
2667 EXPECT_TRUE(NavigateToURL(shell(), url));
2668 RenderFrameHostImpl* rfh_a = current_frame_host();
2669 RenderFrameDeletedObserver deleted(rfh_a);
2670
Reilly Grant980a89b2021-07-24 02:52:592671 ScopedIdleProviderForTest scoped_idle_provider(
2672 std::make_unique<FakeIdleTimeProvider>());
Wei Lee01971182020-09-18 09:15:212673
Harkiran Bolaria335ae2c2020-06-02 15:22:302674 EXPECT_TRUE(ExecJs(rfh_a, R"(
2675 new Promise(async resolve => {
2676 let idleDetector = new IdleDetector();
2677 idleDetector.start();
2678 resolve();
2679 });
2680 )"));
2681
2682 // 2) Navigate away.
2683 shell()->LoadURL(embedded_test_server()->GetURL("b.com", "/title1.html"));
2684
2685 // The page uses IdleManager so it should be deleted.
2686 deleted.WaitUntilDeleted();
2687
2688 // 3) Go back and make sure the IdleManager page wasn't in the cache.
2689 web_contents()->GetController().GoBack();
2690 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
2691 ExpectNotRestored(
2692 {BackForwardCacheMetrics::NotRestoredReason::kBlocklistedFeatures},
Fergal Daly6755cbf2021-02-12 03:06:582693 {blink::scheduler::WebSchedulerTrackedFeature::kIdleManager}, {}, {},
Harkiran Bolaria335ae2c2020-06-02 15:22:302694 FROM_HERE);
Harkiran Bolaria335ae2c2020-06-02 15:22:302695}
2696
Harkiran Bolaria4ecdd822020-06-26 21:42:402697IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, DoesNotCacheSMSService) {
2698 ASSERT_TRUE(embedded_test_server()->Start());
2699
2700 // 1) Navigate to a page and start using the SMSService.
2701 GURL url(embedded_test_server()->GetURL("/title1.html"));
2702 EXPECT_TRUE(NavigateToURL(shell(), url));
2703 RenderFrameHostImpl* rfh_a = current_frame_host();
2704 RenderFrameDeletedObserver rfh_a_deleted(rfh_a);
2705
2706 EXPECT_TRUE(ExecJs(rfh_a, R"(
arthursonzogni3d3ec9e2021-03-04 11:00:502707 navigator.credentials.get({otp: {transport: ["sms"]}});
2708 )",
2709 EXECUTE_SCRIPT_NO_RESOLVE_PROMISES));
Harkiran Bolaria4ecdd822020-06-26 21:42:402710
2711 // 2) Navigate away.
2712 EXPECT_TRUE(NavigateToURL(
2713 shell(), embedded_test_server()->GetURL("b.com", "/title1.html")));
2714
2715 // The page uses SMSService so it should be deleted.
2716 rfh_a_deleted.WaitUntilDeleted();
2717
2718 // 3) Go back and make sure the SMSService page wasn't in the cache.
2719 web_contents()->GetController().GoBack();
2720 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
2721
2722 // Note that on certain linux tests, there is occasionally a not restored
2723 // reason of kDisableForRenderFrameHostCalled. This is due to the javascript
2724 // navigator.credentials.get, which will call on authentication code for linux
2725 // but not other operating systems. The authenticator code explicitly invokes
2726 // kDisableForRenderFrameHostCalled. This causes flakiness if we check against
2727 // all not restored reasons. As a result, we only check for the blocklist
2728 // reason.
2729 ExpectBlocklistedFeature(
Majid Valipourae11335e2020-10-14 04:09:242730 blink::scheduler::WebSchedulerTrackedFeature::kWebOTPService, FROM_HERE);
Harkiran Bolaria4ecdd822020-06-26 21:42:402731}
2732
Dmitry Titovd470035d2020-06-08 22:25:022733// crbug.com/1090223
Harkiran Bolaria06cfe902020-06-03 16:35:582734IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
Dominic Battre32899072021-02-15 08:40:462735 DISABLED_DoesNotCachePaymentManager) {
Harkiran Bolaria06cfe902020-06-03 16:35:582736 ASSERT_TRUE(CreateHttpsServer()->Start());
2737
2738 // 1) Navigate to a page which includes PaymentManager functionality. Note
2739 // that service workers are used, and therefore we use https server instead of
2740 // embedded_server()
2741 EXPECT_TRUE(NavigateToURL(
2742 shell(), https_server()->GetURL(
2743 "a.com", "/payments/payment_app_invocation.html")));
2744 RenderFrameHostImpl* rfh_a = current_frame_host();
2745 RenderFrameDeletedObserver rfh_a_deleted(rfh_a);
2746
2747 // Execute functionality that calls PaymentManager.
2748 EXPECT_TRUE(ExecJs(rfh_a, R"(
2749 new Promise(async resolve => {
2750 registerPaymentApp();
2751 resolve();
2752 });
2753 )"));
2754
2755 // 2) Navigate away.
2756 EXPECT_TRUE(
2757 NavigateToURL(shell(), https_server()->GetURL("b.com", "/title1.html")));
2758
2759 // The page uses PaymentManager so it should be deleted.
2760 rfh_a_deleted.WaitUntilDeleted();
2761
2762 // 3) Go back.
2763 web_contents()->GetController().GoBack();
2764 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
2765 ExpectNotRestored(
2766 {BackForwardCacheMetrics::NotRestoredReason::kBlocklistedFeatures},
Fergal Daly6755cbf2021-02-12 03:06:582767 {blink::scheduler::WebSchedulerTrackedFeature::kPaymentManager}, {}, {},
Harkiran Bolaria06cfe902020-06-03 16:35:582768 FROM_HERE);
2769
2770 // Note that on Mac10.10, there is occasionally blocklisting for network
2771 // requests (kOutstandingNetworkRequestOthers). This causes flakiness if we
2772 // check against all blocklisted features. As a result, we only check for the
2773 // blocklist we care about.
2774 base::HistogramBase::Sample sample = base::HistogramBase::Sample(
2775 blink::scheduler::WebSchedulerTrackedFeature::kPaymentManager);
2776 std::vector<base::Bucket> blocklist_values = histogram_tester_.GetAllSamples(
2777 "BackForwardCache.HistoryNavigationOutcome."
2778 "BlocklistedFeature");
2779 auto it = std::find_if(
2780 blocklist_values.begin(), blocklist_values.end(),
2781 [sample](const base::Bucket& bucket) { return bucket.min == sample; });
2782 EXPECT_TRUE(it != blocklist_values.end());
2783
2784 std::vector<base::Bucket> all_sites_blocklist_values =
2785 histogram_tester_.GetAllSamples(
2786 "BackForwardCache.AllSites.HistoryNavigationOutcome."
2787 "BlocklistedFeature");
2788
2789 auto all_sites_it = std::find_if(
2790 all_sites_blocklist_values.begin(), all_sites_blocklist_values.end(),
2791 [sample](const base::Bucket& bucket) { return bucket.min == sample; });
2792 EXPECT_TRUE(all_sites_it != all_sites_blocklist_values.end());
2793}
2794
Harkiran Bolaria757ef2e2020-06-12 01:22:252795IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
2796 DoesNotCacheOnKeyboardLock) {
2797 ASSERT_TRUE(embedded_test_server()->Start());
2798
2799 // 1) Navigate to a page and start using the IdleManager class.
2800 GURL url(embedded_test_server()->GetURL("/title1.html"));
2801 EXPECT_TRUE(NavigateToURL(shell(), url));
2802 RenderFrameHostImpl* rfh_a = current_frame_host();
2803 RenderFrameDeletedObserver rfh_a_deleted(rfh_a);
2804
2805 EXPECT_TRUE(ExecJs(rfh_a, R"(
2806 new Promise(resolve => {
2807 navigator.keyboard.lock();
2808 resolve();
2809 });
2810 )"));
2811
2812 // 2) Navigate away.
2813 EXPECT_TRUE(NavigateToURL(
2814 shell(), embedded_test_server()->GetURL("b.com", "/title1.html")));
2815
2816 // The page uses IdleManager so it should be deleted.
2817 rfh_a_deleted.WaitUntilDeleted();
2818
2819 // 3) Go back and make sure the IdleManager page wasn't in the cache.
2820 web_contents()->GetController().GoBack();
2821 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
2822 ExpectNotRestored(
2823 {BackForwardCacheMetrics::NotRestoredReason::kBlocklistedFeatures},
Fergal Daly6755cbf2021-02-12 03:06:582824 {blink::scheduler::WebSchedulerTrackedFeature::kKeyboardLock}, {}, {},
Harkiran Bolaria757ef2e2020-06-12 01:22:252825 FROM_HERE);
Harkiran Bolaria757ef2e2020-06-12 01:22:252826}
2827
Rakina Zata Amni9fd73cc2020-10-03 09:06:592828// Tests which blocklisted features are tracked in the metrics when we used
2829// blocklisted features (sticky and non-sticky) and do a browser-initiated
2830// cross-site navigation.
2831IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
2832 BlocklistedFeaturesTracking_CrossSite_BrowserInitiated) {
2833 ASSERT_TRUE(CreateHttpsServer()->Start());
2834 GURL url_a(https_server()->GetURL("a.com", "/title1.html"));
2835 GURL url_b(https_server()->GetURL("b.com", "/title2.html"));
2836 // 1) Navigate to a page.
2837 EXPECT_TRUE(NavigateToURL(shell(), url_a));
2838 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
2839
2840 RenderFrameHostImpl* rfh_a = current_frame_host();
2841 scoped_refptr<SiteInstanceImpl> site_instance_a =
2842 static_cast<SiteInstanceImpl*>(rfh_a->GetSiteInstance());
2843 RenderFrameDeletedObserver rfh_a_deleted(rfh_a);
2844
Hajime Hoshi309f3236f92020-12-01 05:34:172845 // 2) Use BroadcastChannel (non-sticky) and KeyboardLock (sticky) blocklisted
2846 // features.
2847 EXPECT_TRUE(ExecJs(rfh_a, "window.foo = new BroadcastChannel('foo');"));
Rakina Zata Amni9fd73cc2020-10-03 09:06:592848 EXPECT_TRUE(ExecJs(rfh_a, R"(
2849 new Promise(resolve => {
2850 navigator.keyboard.lock();
2851 resolve();
2852 });
2853 )"));
2854
2855 // 3) Navigate cross-site, browser-initiated.
2856 EXPECT_TRUE(NavigateToURL(shell(), url_b));
2857 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
2858
2859 // The previous page won't get into the back-forward cache because of the
2860 // blocklisted features. Because we used sticky blocklisted features, we will
2861 // not do a proactive BrowsingInstance swap, however the RFH will still change
2862 // and get deleted.
2863 rfh_a_deleted.WaitUntilDeleted();
2864 EXPECT_FALSE(site_instance_a->IsRelatedSiteInstance(
2865 web_contents()->GetMainFrame()->GetSiteInstance()));
2866
2867 // 4) Go back.
2868 web_contents()->GetController().GoBack();
2869 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
2870
Yuzu Saijo26b52292021-08-16 04:26:012871 // Only sticky features are recorded because they're tracked in
2872 // RenderFrameHostManager::UnloadOldFrame.
Fergal Daly6755cbf2021-02-12 03:06:582873 ExpectNotRestored(
2874 {BackForwardCacheMetrics::NotRestoredReason::kBlocklistedFeatures},
Yuzu Saijo26b52292021-08-16 04:26:012875 {blink::scheduler::WebSchedulerTrackedFeature::kKeyboardLock}, {}, {},
2876 FROM_HERE);
Rakina Zata Amni9fd73cc2020-10-03 09:06:592877}
2878
2879// Tests which blocklisted features are tracked in the metrics when we used
2880// blocklisted features (sticky and non-sticky) and do a renderer-initiated
2881// cross-site navigation.
2882IN_PROC_BROWSER_TEST_F(
2883 BackForwardCacheBrowserTest,
2884 BlocklistedFeaturesTracking_CrossSite_RendererInitiated) {
2885 ASSERT_TRUE(CreateHttpsServer()->Start());
2886 GURL url_a(https_server()->GetURL("a.com", "/title1.html"));
2887 GURL url_b(https_server()->GetURL("b.com", "/title2.html"));
2888
2889 // 1) Navigate to a page.
2890 EXPECT_TRUE(NavigateToURL(shell(), url_a));
2891 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
2892
2893 RenderFrameHostImpl* rfh_a = current_frame_host();
2894 scoped_refptr<SiteInstanceImpl> site_instance_a =
2895 static_cast<SiteInstanceImpl*>(rfh_a->GetSiteInstance());
2896
Hajime Hoshi309f3236f92020-12-01 05:34:172897 // 2) Use BroadcastChannel (non-sticky) and KeyboardLock (sticky) blocklisted
Rakina Zata Amni9fd73cc2020-10-03 09:06:592898 // features.
Hajime Hoshi309f3236f92020-12-01 05:34:172899 EXPECT_TRUE(ExecJs(rfh_a, "window.foo = new BroadcastChannel('foo');"));
Rakina Zata Amni9fd73cc2020-10-03 09:06:592900 EXPECT_TRUE(ExecJs(rfh_a, R"(
2901 new Promise(resolve => {
2902 navigator.keyboard.lock();
2903 resolve();
2904 });
2905 )"));
2906
2907 // 3) Navigate cross-site, renderer-inititated.
2908 EXPECT_TRUE(ExecJs(shell(), JsReplace("location = $1;", url_b.spec())));
2909 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
2910 // The previous page won't get into the back-forward cache because of the
2911 // blocklisted features. Because we used sticky blocklisted features, we will
2912 // not do a proactive BrowsingInstance swap.
2913 EXPECT_TRUE(site_instance_a->IsRelatedSiteInstance(
2914 web_contents()->GetMainFrame()->GetSiteInstance()));
2915
2916 // 4) Go back.
2917 web_contents()->GetController().GoBack();
2918 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
2919
Aaron Colwell5fb878042020-12-17 19:48:442920 if (AreStrictSiteInstancesEnabled()) {
Yuzu Saijo26b52292021-08-16 04:26:012921 // Only sticky features are recorded because they're tracked in
2922 // RenderFrameHostManager::UnloadOldFrame.
Rakina Zata Amni9fd73cc2020-10-03 09:06:592923 ExpectNotRestored(
2924 {BackForwardCacheMetrics::NotRestoredReason::
2925 kRelatedActiveContentsExist,
Hajime Hoshic7606502021-04-14 02:42:162926 BackForwardCacheMetrics::NotRestoredReason::kBlocklistedFeatures,
2927 BackForwardCacheMetrics::NotRestoredReason::
2928 kBrowsingInstanceNotSwapped},
Yuzu Saijo26b52292021-08-16 04:26:012929 {blink::scheduler::WebSchedulerTrackedFeature::kKeyboardLock},
Fergal Daly6755cbf2021-02-12 03:06:582930 {ShouldSwapBrowsingInstance::kNo_NotNeededForBackForwardCache}, {},
Hajime Hoshi8fd675e02020-10-29 14:28:412931 FROM_HERE);
2932
2933 web_contents()->GetController().GoForward();
2934 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
2935
2936 ExpectBrowsingInstanceNotSwappedReason(
2937 ShouldSwapBrowsingInstance::kNo_AlreadyHasMatchingBrowsingInstance,
2938 FROM_HERE);
2939
2940 web_contents()->GetController().GoBack();
2941 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
2942
2943 ExpectBrowsingInstanceNotSwappedReason(
2944 ShouldSwapBrowsingInstance::kNo_AlreadyHasMatchingBrowsingInstance,
2945 FROM_HERE);
Rakina Zata Amni9fd73cc2020-10-03 09:06:592946 } else {
Fergal Daly6755cbf2021-02-12 03:06:582947 // Non-sticky reasons are not recorded here.
Hajime Hoshid5834252020-11-06 13:10:032948 ExpectNotRestored(
Hajime Hoshic7606502021-04-14 02:42:162949 {
2950 BackForwardCacheMetrics::NotRestoredReason::kBlocklistedFeatures,
2951 BackForwardCacheMetrics::NotRestoredReason::
2952 kBrowsingInstanceNotSwapped,
2953 },
2954 {blink::scheduler::WebSchedulerTrackedFeature::kKeyboardLock},
2955 {ShouldSwapBrowsingInstance::kNo_NotNeededForBackForwardCache}, {},
Hajime Hoshid5834252020-11-06 13:10:032956 FROM_HERE);
Rakina Zata Amni9fd73cc2020-10-03 09:06:592957 }
2958}
2959
2960// Tests which blocklisted features are tracked in the metrics when we used
2961// blocklisted features (sticky and non-sticky) and do a same-site navigation.
2962IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
2963 BlocklistedFeaturesTracking_SameSite) {
2964 ASSERT_TRUE(CreateHttpsServer()->Start());
2965
2966 ASSERT_TRUE(CreateHttpsServer()->Start());
2967 GURL url_1(https_server()->GetURL("/title1.html"));
2968 GURL url_2(https_server()->GetURL("/title2.html"));
2969
2970 // 1) Navigate to a page.
2971 EXPECT_TRUE(NavigateToURL(shell(), url_1));
2972 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
2973
2974 RenderFrameHostImpl* rfh_1 = current_frame_host();
2975 scoped_refptr<SiteInstanceImpl> site_instance_1 =
2976 static_cast<SiteInstanceImpl*>(rfh_1->GetSiteInstance());
2977
Hajime Hoshi309f3236f92020-12-01 05:34:172978 // 2) Use BroadcastChannel (non-sticky) and KeyboardLock (sticky) blocklisted
2979 // features.
2980 EXPECT_TRUE(ExecJs(rfh_1, "window.foo = new BroadcastChannel('foo');"));
Rakina Zata Amni9fd73cc2020-10-03 09:06:592981 EXPECT_TRUE(ExecJs(rfh_1, R"(
2982 new Promise(resolve => {
2983 navigator.keyboard.lock();
2984 resolve();
2985 });
2986 )"));
2987
2988 // 3) Navigate same-site.
2989 EXPECT_TRUE(NavigateToURL(shell(), url_2));
2990 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
2991
2992 // Because we used sticky blocklisted features, we will not do a proactive
2993 // BrowsingInstance swap.
2994 EXPECT_TRUE(site_instance_1->IsRelatedSiteInstance(
2995 web_contents()->GetMainFrame()->GetSiteInstance()));
2996
2997 // 4) Go back.
2998 web_contents()->GetController().GoBack();
2999 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
3000
Fergal Daly6755cbf2021-02-12 03:06:583001 // Non-sticky reasons are not recorded here.
Hajime Hoshid5834252020-11-06 13:10:033002 ExpectNotRestored(
Hajime Hoshic7606502021-04-14 02:42:163003 {
3004 BackForwardCacheMetrics::NotRestoredReason::kBlocklistedFeatures,
3005 BackForwardCacheMetrics::NotRestoredReason::
3006 kBrowsingInstanceNotSwapped,
3007 },
3008 {blink::scheduler::WebSchedulerTrackedFeature::kKeyboardLock},
3009 {ShouldSwapBrowsingInstance::kNo_NotNeededForBackForwardCache}, {},
Hajime Hoshid5834252020-11-06 13:10:033010 FROM_HERE);
Rakina Zata Amni9fd73cc2020-10-03 09:06:593011}
3012
3013// Tests which blocklisted features are tracked in the metrics when we used a
3014// non-sticky blocklisted feature and do a browser-initiated cross-site
3015// navigation.
3016IN_PROC_BROWSER_TEST_F(
3017 BackForwardCacheBrowserTest,
3018 BlocklistedFeaturesTracking_CrossSite_BrowserInitiated_NonSticky) {
3019 ASSERT_TRUE(CreateHttpsServer()->Start());
3020
3021 // 1) Navigate to an empty page.
3022 GURL url_a(https_server()->GetURL("a.com", "/title1.html"));
3023 GURL url_b(https_server()->GetURL("b.com", "/title2.html"));
3024 EXPECT_TRUE(NavigateToURL(shell(), url_a));
3025 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
3026
3027 RenderFrameHostImpl* rfh_a = current_frame_host();
Hajime Hoshi309f3236f92020-12-01 05:34:173028 // 2) Use BroadcastChannel (a non-sticky blocklisted feature).
3029 EXPECT_TRUE(ExecJs(rfh_a, "window.foo = new BroadcastChannel('foo');"));
Rakina Zata Amni9fd73cc2020-10-03 09:06:593030 scoped_refptr<SiteInstanceImpl> site_instance_a =
3031 static_cast<SiteInstanceImpl*>(
3032 web_contents()->GetMainFrame()->GetSiteInstance());
3033
3034 // 3) Navigate cross-site, browser-initiated.
3035 // The previous page won't get into the back-forward cache because of the
3036 // blocklisted feature.
3037 EXPECT_TRUE(NavigateToURL(shell(), url_b));
3038 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
3039 // Because we only used non-sticky blocklisted features, we will still do a
3040 // proactive BrowsingInstance swap.
3041 EXPECT_FALSE(site_instance_a->IsRelatedSiteInstance(
3042 web_contents()->GetMainFrame()->GetSiteInstance()));
3043
3044 // 4) Go back.
3045 web_contents()->GetController().GoBack();
3046 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
3047
3048 // Because the RenderFrameHostManager changed, the blocklisted features will
3049 // be tracked in RenderFrameHostManager::UnloadOldFrame.
3050 ExpectNotRestored(
3051 {BackForwardCacheMetrics::NotRestoredReason::kBlocklistedFeatures},
Fergal Daly6755cbf2021-02-12 03:06:583052 {blink::scheduler::WebSchedulerTrackedFeature::kBroadcastChannel}, {}, {},
Hajime Hoshi309f3236f92020-12-01 05:34:173053 FROM_HERE);
Rakina Zata Amni9fd73cc2020-10-03 09:06:593054}
3055
3056// Tests which blocklisted features are tracked in the metrics when we used a
3057// non-sticky blocklisted feature and do a renderer-initiated cross-site
3058// navigation.
3059IN_PROC_BROWSER_TEST_F(
3060 BackForwardCacheBrowserTest,
3061 BlocklistedFeaturesTracking_CrossSite_RendererInitiated_NonSticky) {
3062 ASSERT_TRUE(CreateHttpsServer()->Start());
3063
3064 // 1) Navigate to an empty page.
3065 GURL url_a(https_server()->GetURL("a.com", "/title1.html"));
3066 GURL url_b(https_server()->GetURL("b.com", "/title1.html"));
3067 EXPECT_TRUE(NavigateToURL(shell(), url_a));
3068 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
3069
3070 RenderFrameHostImpl* rfh_a = current_frame_host();
Hajime Hoshi309f3236f92020-12-01 05:34:173071 // 2) Use BroadcastChannel (a non-sticky blocklisted feature).
3072 EXPECT_TRUE(ExecJs(rfh_a, "window.foo = new BroadcastChannel('foo');"));
Rakina Zata Amni9fd73cc2020-10-03 09:06:593073 scoped_refptr<SiteInstanceImpl> site_instance_a =
3074 static_cast<SiteInstanceImpl*>(
3075 web_contents()->GetMainFrame()->GetSiteInstance());
3076
3077 // 3) Navigate cross-site, renderer-inititated.
3078 // The previous page won't get into the back-forward cache because of the
3079 // blocklisted feature.
3080 EXPECT_TRUE(ExecJs(shell(), JsReplace("location = $1;", url_b.spec())));
3081 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
3082 // Because we only used non-sticky blocklisted features, we will still do a
3083 // proactive BrowsingInstance swap.
3084 EXPECT_FALSE(site_instance_a->IsRelatedSiteInstance(
3085 web_contents()->GetMainFrame()->GetSiteInstance()));
3086
3087 // 4) Go back.
3088 web_contents()->GetController().GoBack();
3089 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
3090
3091 // Because the RenderFrameHostManager changed, the blocklisted features will
3092 // be tracked in RenderFrameHostManager::UnloadOldFrame.
3093 ExpectNotRestored(
3094 {BackForwardCacheMetrics::NotRestoredReason::kBlocklistedFeatures},
Fergal Daly6755cbf2021-02-12 03:06:583095 {blink::scheduler::WebSchedulerTrackedFeature::kBroadcastChannel}, {}, {},
Hajime Hoshi309f3236f92020-12-01 05:34:173096 FROM_HERE);
Rakina Zata Amni9fd73cc2020-10-03 09:06:593097}
3098
3099// Tests which blocklisted features are tracked in the metrics when we used a
3100// non-sticky blocklisted feature and do a same-site navigation.
3101IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
3102 BlocklistedFeaturesTracking_SameSite_NonSticky) {
3103 ASSERT_TRUE(CreateHttpsServer()->Start());
3104
3105 // 1) Navigate to an empty page.
3106 GURL url_1(https_server()->GetURL("/title1.html"));
3107 GURL url_2(https_server()->GetURL("/title2.html"));
3108 EXPECT_TRUE(NavigateToURL(shell(), url_1));
3109 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
3110
3111 RenderFrameHostImpl* rfh_1 = current_frame_host();
Hajime Hoshi309f3236f92020-12-01 05:34:173112 // 2) Use BroadcastChannel (a non-sticky blocklisted feature).
3113 EXPECT_TRUE(ExecJs(rfh_1, "window.foo = new BroadcastChannel('foo');"));
Rakina Zata Amni9fd73cc2020-10-03 09:06:593114 scoped_refptr<SiteInstanceImpl> site_instance_1 =
3115 static_cast<SiteInstanceImpl*>(
3116 web_contents()->GetMainFrame()->GetSiteInstance());
3117
3118 // 3) Navigate same-site.
3119 // The previous page won't get into the back-forward cache because of the
3120 // blocklisted feature.
3121 EXPECT_TRUE(NavigateToURL(shell(), url_2));
3122 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
3123 // Because we only used non-sticky blocklisted features, we will still do a
3124 // proactive BrowsingInstance swap.
3125 EXPECT_FALSE(site_instance_1->IsRelatedSiteInstance(
3126 web_contents()->GetMainFrame()->GetSiteInstance()));
3127
3128 // 4) Go back.
3129 web_contents()->GetController().GoBack();
3130 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
3131
3132 // Because the RenderFrameHostManager changed, the blocklisted features will
3133 // be tracked in RenderFrameHostManager::UnloadOldFrame.
3134 ExpectNotRestored(
3135 {BackForwardCacheMetrics::NotRestoredReason::kBlocklistedFeatures},
Fergal Daly6755cbf2021-02-12 03:06:583136 {blink::scheduler::WebSchedulerTrackedFeature::kBroadcastChannel}, {}, {},
Hajime Hoshi309f3236f92020-12-01 05:34:173137 FROM_HERE);
Rakina Zata Amni9fd73cc2020-10-03 09:06:593138}
3139
Ioana Pandele4892be8b2021-01-26 18:05:493140// Flaky on Android, see crbug.com/1135601 and on other platforms, see
3141// crbug.com/1128772.
Tim Volodineff063c32020-10-06 17:45:593142IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
Ioana Pandele4892be8b2021-01-26 18:05:493143 DISABLED_LogIpcPostedToCachedFrame) {
Harkiran Bolaria875dd0d2020-09-15 18:10:463144 ASSERT_TRUE(embedded_test_server()->Start());
3145
3146 // 1) Navigate to a page.
3147 GURL url(embedded_test_server()->GetURL("/title1.html"));
3148 EXPECT_TRUE(NavigateToURL(shell(), url));
3149 RenderFrameHostImpl* rfh_a = current_frame_host();
3150
3151 // 2) Navigate away. The first page should be in the cache.
3152 EXPECT_TRUE(NavigateToURL(
3153 shell(), embedded_test_server()->GetURL("b.com", "/title1.html")));
3154
3155 // 3) Post IPC tasks to the page, testing both mojo remote and associated
3156 // remote objects.
3157
Harkiran Bolaria12818bc2020-11-03 22:44:273158 // Send a message via an associated interface - which will post a task with an
3159 // IPC hash and will be routed to the per-thread task queue.
3160 base::RunLoop run_loop;
3161 rfh_a->RequestTextSurroundingSelection(
3162 base::BindOnce(
Jan Wilken Dörrieaace0cfef2021-03-11 22:01:583163 [](base::RepeatingClosure quit_closure, const std::u16string& str,
Harkiran Bolaria12818bc2020-11-03 22:44:273164 uint32_t num, uint32_t num2) { quit_closure.Run(); },
3165 run_loop.QuitClosure()),
3166 1);
3167 run_loop.Run();
Harkiran Bolaria875dd0d2020-09-15 18:10:463168
3169 // Post a non-associated interface. Will be routed to a frame-specific task
3170 // queue with IPC set in SimpleWatcher.
Harkiran Bolaria12818bc2020-11-03 22:44:273171 base::RunLoop run_loop2;
Harkiran Bolaria875dd0d2020-09-15 18:10:463172 rfh_a->GetHighPriorityLocalFrame()->DispatchBeforeUnload(
3173 false,
3174 base::BindOnce([](base::RepeatingClosure quit_closure, bool proceed,
3175 base::TimeTicks start_time,
3176 base::TimeTicks end_time) { quit_closure.Run(); },
Harkiran Bolaria12818bc2020-11-03 22:44:273177 run_loop2.QuitClosure()));
3178 run_loop2.Run();
Harkiran Bolaria875dd0d2020-09-15 18:10:463179
3180 // 4) Check the histogram.
Harkiran Bolaria12818bc2020-11-03 22:44:273181 std::vector<base::HistogramBase::Sample> samples = {
3182 base::HistogramBase::Sample(
3183 base::TaskAnnotator::ScopedSetIpcHash::MD5HashMetricName(
3184 "blink.mojom.HighPriorityLocalFrame")),
3185 base::HistogramBase::Sample(
3186 base::TaskAnnotator::ScopedSetIpcHash::MD5HashMetricName(
3187 "blink.mojom.LocalFrame"))};
3188
3189 for (base::HistogramBase::Sample sample : samples) {
3190 FetchHistogramsFromChildProcesses();
3191 EXPECT_TRUE(HistogramContainsIntValue(
3192 sample, histogram_tester_.GetAllSamples(
3193 "BackForwardCache.Experimental."
3194 "UnexpectedIPCMessagePostedToCachedFrame.MethodHash")));
3195 }
Harkiran Bolaria875dd0d2020-09-15 18:10:463196}
3197
Yuzu Saijob0f001b22020-04-08 04:07:043198class MockAppBannerService : public blink::mojom::AppBannerService {
3199 public:
3200 MockAppBannerService() = default;
3201 ~MockAppBannerService() override = default;
3202
3203 void Bind(mojo::ScopedMessagePipeHandle handle) {
3204 receiver_.Bind(mojo::PendingReceiver<blink::mojom::AppBannerService>(
3205 std::move(handle)));
3206 }
3207
3208 mojo::Remote<blink::mojom::AppBannerController>& controller() {
3209 return controller_;
3210 }
3211
3212 void OnBannerPromptRequested(bool) {}
3213
3214 void SendBannerPromptRequest() {
3215 blink::mojom::AppBannerController* controller_ptr = controller_.get();
3216 base::OnceCallback<void(bool)> callback = base::BindOnce(
3217 &MockAppBannerService::OnBannerPromptRequested, base::Unretained(this));
3218 controller_ptr->BannerPromptRequest(
3219 receiver_.BindNewPipeAndPassRemote(),
3220 event_.BindNewPipeAndPassReceiver(), {"web"},
3221 base::BindOnce(&MockAppBannerService::OnBannerPromptReply,
3222 base::Unretained(this), std::move(callback)));
3223 }
3224
3225 void OnBannerPromptReply(base::OnceCallback<void(bool)> callback,
3226 blink::mojom::AppBannerPromptReply reply) {
3227 std::move(callback).Run(reply ==
3228 blink::mojom::AppBannerPromptReply::CANCEL);
3229 }
3230
3231 // blink::mojom::AppBannerService:
3232 void DisplayAppBanner() override {}
3233
3234 private:
3235 mojo::Receiver<blink::mojom::AppBannerService> receiver_{this};
3236 mojo::Remote<blink::mojom::AppBannerEvent> event_;
3237 mojo::Remote<blink::mojom::AppBannerController> controller_;
3238
3239 DISALLOW_COPY_AND_ASSIGN(MockAppBannerService);
3240};
3241
danakj3dd67eaa2020-12-22 21:14:123242IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, DoesNotCacheIfAppBanner) {
Yuzu Saijob0f001b22020-04-08 04:07:043243 ASSERT_TRUE(embedded_test_server()->Start());
3244
3245 // 1) Navigate to A and request a PWA app banner.
3246 EXPECT_TRUE(NavigateToURL(
3247 shell(), embedded_test_server()->GetURL("a.com", "/title1.html")));
danakj3dd67eaa2020-12-22 21:14:123248
3249 // Connect the MockAppBannerService mojom to the renderer's frame.
3250 MockAppBannerService mock_app_banner_service;
3251 web_contents()->GetMainFrame()->GetRemoteInterfaces()->GetInterface(
3252 mock_app_banner_service.controller().BindNewPipeAndPassReceiver());
3253 // Send the request to the renderer's frame.
3254 mock_app_banner_service.SendBannerPromptRequest();
3255
Yuzu Saijob0f001b22020-04-08 04:07:043256 RenderFrameDeletedObserver delete_observer_rfh(current_frame_host());
3257
3258 // 2) Navigate away. Page A requested a PWA app banner, and thus not cached.
Yuzu Saijo31fa4f22020-04-16 04:11:333259 EXPECT_TRUE(NavigateToURL(
3260 shell(), embedded_test_server()->GetURL("b.com", "/title1.html")));
Yuzu Saijob0f001b22020-04-08 04:07:043261 delete_observer_rfh.WaitUntilDeleted();
3262
3263 // 3) Go back to A.
3264 web_contents()->GetController().GoBack();
3265 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
3266 ExpectNotRestored(
3267 {BackForwardCacheMetrics::NotRestoredReason::kBlocklistedFeatures},
Fergal Daly6755cbf2021-02-12 03:06:583268 {blink::scheduler::WebSchedulerTrackedFeature::kAppBanner}, {}, {},
Yuzu Saijob0f001b22020-04-08 04:07:043269 FROM_HERE);
Yuzu Saijob0f001b22020-04-08 04:07:043270}
3271
Yuzu Saijoa80438e2020-04-23 06:03:053272IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, DoesNotCacheIfWebDatabase) {
3273 ASSERT_TRUE(embedded_test_server()->Start());
3274
3275 // 1) Navigate to a page with WebDatabase usage.
3276 GURL url(embedded_test_server()->GetURL("/simple_database.html"));
3277 EXPECT_TRUE(NavigateToURL(shell(), url));
3278 RenderFrameHostImpl* rfh_a = current_frame_host();
3279 RenderFrameDeletedObserver deleted(rfh_a);
3280
3281 // 2) Navigate away.
3282 shell()->LoadURL(embedded_test_server()->GetURL("b.com", "/title1.html"));
3283 // The page uses WebDatabase so it should be deleted.
3284 deleted.WaitUntilDeleted();
3285
3286 // 3) Go back to the page with WebDatabase.
3287 web_contents()->GetController().GoBack();
3288 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
3289 ExpectNotRestored(
3290 {BackForwardCacheMetrics::NotRestoredReason::kBlocklistedFeatures},
Fergal Daly6755cbf2021-02-12 03:06:583291 {blink::scheduler::WebSchedulerTrackedFeature::kWebDatabase}, {}, {},
Yuzu Saijoa80438e2020-04-23 06:03:053292 FROM_HERE);
Yuzu Saijoa80438e2020-04-23 06:03:053293}
3294
Mohamed Abdelhalim462fff32019-08-13 14:13:423295IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
3296 DoesNotCacheIfPageUnreachable) {
3297 ASSERT_TRUE(embedded_test_server()->Start());
3298
3299 GURL error_url(embedded_test_server()->GetURL("a.com", "/empty.html"));
3300 GURL url(embedded_test_server()->GetURL("b.com", "/title1.html"));
3301
3302 std::unique_ptr<URLLoaderInterceptor> url_interceptor =
3303 URLLoaderInterceptor::SetupRequestFailForURL(error_url,
3304 net::ERR_DNS_TIMED_OUT);
3305
3306 // Start with a successful navigation to a document.
3307 EXPECT_TRUE(NavigateToURL(shell(), url));
3308 EXPECT_EQ(net::HTTP_OK, current_frame_host()->last_http_status_code());
3309
3310 // Navigate to an error page.
3311 NavigationHandleObserver observer(shell()->web_contents(), error_url);
3312 EXPECT_FALSE(NavigateToURL(shell(), error_url));
3313 EXPECT_TRUE(observer.is_error());
3314 EXPECT_EQ(net::ERR_DNS_TIMED_OUT, observer.net_error_code());
3315 EXPECT_EQ(
3316 GURL(kUnreachableWebDataURL),
3317 shell()->web_contents()->GetMainFrame()->GetSiteInstance()->GetSiteURL());
3318 EXPECT_EQ(net::OK, current_frame_host()->last_http_status_code());
3319
3320 RenderFrameDeletedObserver delete_rfh_a(current_frame_host());
3321
3322 // Navigate away.
3323 EXPECT_TRUE(NavigateToURL(shell(), url));
3324
3325 // The page had a networking error, so it shouldn't have been cached.
3326 delete_rfh_a.WaitUntilDeleted();
Hajime Hoshi45255602019-10-18 07:26:593327
3328 // Go back.
3329 web_contents()->GetController().GoBack();
3330 EXPECT_FALSE(WaitForLoadStop(shell()->web_contents()));
3331 ExpectNotRestored(
Takashi Toyoshima300eb1c2021-07-27 11:08:393332 {BackForwardCacheMetrics::NotRestoredReason::kHTTPStatusNotOK,
3333 BackForwardCacheMetrics::NotRestoredReason::kNoResponseHead},
3334 {}, {}, {}, FROM_HERE);
Mohamed Abdelhalim462fff32019-08-13 14:13:423335}
3336
Lowell Manners573470e2019-08-02 12:36:233337IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
3338 DisableBackforwardCacheForTesting) {
3339 ASSERT_TRUE(embedded_test_server()->Start());
3340
3341 // Disable the BackForwardCache.
Carlos Caballero35ce710c2019-09-19 10:59:453342 web_contents()->GetController().GetBackForwardCache().DisableForTesting(
3343 BackForwardCacheImpl::TEST_ASSUMES_NO_CACHING);
Lowell Manners573470e2019-08-02 12:36:233344
3345 // Navigate to a page that would normally be cacheable.
Alex Moshchukaeb20fe32019-09-25 17:40:013346 EXPECT_TRUE(NavigateToURL(
3347 shell(), embedded_test_server()->GetURL("a.com", "/title1.html")));
Hajime Hoshif53fa7ca2019-08-13 06:52:343348 RenderFrameDeletedObserver delete_observer_rfh_a(current_frame_host());
Lowell Manners573470e2019-08-02 12:36:233349
3350 // Navigate away.
Alex Moshchukaeb20fe32019-09-25 17:40:013351 EXPECT_TRUE(NavigateToURL(
3352 shell(), embedded_test_server()->GetURL("b.com", "/title1.html")));
Lowell Manners573470e2019-08-02 12:36:233353
3354 // The page should be deleted (not cached).
Hajime Hoshif53fa7ca2019-08-13 06:52:343355 delete_observer_rfh_a.WaitUntilDeleted();
Kouhei Ueno19a5591f2019-08-01 07:29:423356}
3357
Hajime Hoshia2f68032019-08-05 13:22:383358// Navigate from A to B, then cause JavaScript execution on A, then go back.
3359// Test the RenderFrameHost in the cache is evicted by JavaScript.
3360IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
3361 EvictionOnJavaScriptExecution) {
3362 ASSERT_TRUE(embedded_test_server()->Start());
3363 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
3364 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
3365
3366 // 1) Navigate to A.
3367 EXPECT_TRUE(NavigateToURL(shell(), url_a));
3368 RenderFrameHostImpl* rfh_a = current_frame_host();
Hajime Hoshif53fa7ca2019-08-13 06:52:343369 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
Hajime Hoshia2f68032019-08-05 13:22:383370
3371 // 2) Navigate to B.
3372 EXPECT_TRUE(NavigateToURL(shell(), url_b));
3373 RenderFrameHostImpl* rfh_b = current_frame_host();
Hajime Hoshif53fa7ca2019-08-13 06:52:343374 RenderFrameDeletedObserver delete_observer_rfh_b(rfh_b);
Hajime Hoshia2f68032019-08-05 13:22:383375
Hajime Hoshif53fa7ca2019-08-13 06:52:343376 EXPECT_FALSE(delete_observer_rfh_a.deleted());
3377 EXPECT_FALSE(delete_observer_rfh_b.deleted());
Hajime Hoshibbc509c2020-04-06 08:55:083378 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
3379 EXPECT_FALSE(rfh_b->IsInBackForwardCache());
Hajime Hoshia2f68032019-08-05 13:22:383380
3381 // 3) Execute JavaScript on A.
Yuzu Saijo6a935bbd2019-11-01 16:31:383382 EvictByJavaScript(rfh_a);
Hajime Hoshia2f68032019-08-05 13:22:383383
3384 // RenderFrameHost A is evicted from the BackForwardCache:
Hajime Hoshif53fa7ca2019-08-13 06:52:343385 delete_observer_rfh_a.WaitUntilDeleted();
Hajime Hoshif9eba2b2019-10-02 08:27:423386
3387 // 4) Go back to A.
3388 web_contents()->GetController().GoBack();
3389 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
Hajime Hoshi45255602019-10-18 07:26:593390 ExpectNotRestored(
Fergal Daly6755cbf2021-02-12 03:06:583391 {BackForwardCacheMetrics::NotRestoredReason::kJavaScriptExecution}, {},
3392 {}, {}, FROM_HERE);
Hajime Hoshia2f68032019-08-05 13:22:383393}
3394
3395// Similar to BackForwardCacheBrowserTest.EvictionOnJavaScriptExecution.
3396// Test case: A(B) -> C -> JS on B -> A(B)
3397IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
3398 EvictionOnJavaScriptExecutionIframe) {
3399 ASSERT_TRUE(embedded_test_server()->Start());
3400 GURL url_a(embedded_test_server()->GetURL(
3401 "a.com", "/cross_site_iframe_factory.html?a(b)"));
3402 GURL url_c(embedded_test_server()->GetURL("c.com", "/title1.html"));
3403
3404 // 1) Navigate to A(B).
3405 EXPECT_TRUE(NavigateToURL(shell(), url_a));
3406 RenderFrameHostImpl* rfh_a = current_frame_host();
3407 RenderFrameHostImpl* rfh_b = rfh_a->child_at(0)->current_frame_host();
Hajime Hoshif53fa7ca2019-08-13 06:52:343408 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
3409 RenderFrameDeletedObserver delete_observer_rfh_b(rfh_b);
Hajime Hoshia2f68032019-08-05 13:22:383410
3411 // 2) Navigate to C.
3412 EXPECT_TRUE(NavigateToURL(shell(), url_c));
3413 RenderFrameHostImpl* rfh_c = current_frame_host();
Hajime Hoshif53fa7ca2019-08-13 06:52:343414 RenderFrameDeletedObserver delete_observer_rfh_c(rfh_c);
Hajime Hoshia2f68032019-08-05 13:22:383415
Hajime Hoshif53fa7ca2019-08-13 06:52:343416 EXPECT_FALSE(delete_observer_rfh_a.deleted());
3417 EXPECT_FALSE(delete_observer_rfh_b.deleted());
3418 EXPECT_FALSE(delete_observer_rfh_c.deleted());
Hajime Hoshibbc509c2020-04-06 08:55:083419 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
3420 EXPECT_TRUE(rfh_b->IsInBackForwardCache());
3421 EXPECT_FALSE(rfh_c->IsInBackForwardCache());
Hajime Hoshia2f68032019-08-05 13:22:383422
3423 // 3) Execute JavaScript on B.
3424 //
Yuzu Saijo6a935bbd2019-11-01 16:31:383425 EvictByJavaScript(rfh_b);
Hajime Hoshia2f68032019-08-05 13:22:383426
3427 // The A(B) page is evicted. So A and B are removed:
Hajime Hoshif53fa7ca2019-08-13 06:52:343428 delete_observer_rfh_a.WaitUntilDeleted();
3429 delete_observer_rfh_b.WaitUntilDeleted();
Hajime Hoshif9eba2b2019-10-02 08:27:423430
Hajime Hoshi3b2e4222019-10-10 10:17:073431 // 4) Go back to A(B).
Hajime Hoshif9eba2b2019-10-02 08:27:423432 web_contents()->GetController().GoBack();
3433 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
Hajime Hoshi45255602019-10-18 07:26:593434 ExpectNotRestored(
Fergal Daly6755cbf2021-02-12 03:06:583435 {BackForwardCacheMetrics::NotRestoredReason::kJavaScriptExecution}, {},
3436 {}, {}, FROM_HERE);
Hajime Hoshif53fa7ca2019-08-13 06:52:343437}
3438
3439IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
3440 EvictionOnJavaScriptExecutionInAnotherWorld) {
3441 ASSERT_TRUE(embedded_test_server()->Start());
3442 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
3443 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
3444
3445 // 1) Navigate to A.
3446 EXPECT_TRUE(NavigateToURL(shell(), url_a));
3447 RenderFrameHostImpl* rfh_a = current_frame_host();
3448 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
3449
3450 // 2) Execute JavaScript on A in a new world. This ensures a new world.
3451 const int32_t kNewWorldId = content::ISOLATED_WORLD_ID_CONTENT_END + 1;
3452 EXPECT_TRUE(ExecJs(rfh_a, "console.log('hi');",
3453 EXECUTE_SCRIPT_DEFAULT_OPTIONS, kNewWorldId));
3454
3455 // 3) Navigate to B.
3456 EXPECT_TRUE(NavigateToURL(shell(), url_b));
3457 RenderFrameHostImpl* rfh_b = current_frame_host();
3458 RenderFrameDeletedObserver delete_observer_rfh_b(rfh_b);
3459
3460 EXPECT_FALSE(delete_observer_rfh_a.deleted());
3461 EXPECT_FALSE(delete_observer_rfh_b.deleted());
Hajime Hoshibbc509c2020-04-06 08:55:083462 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
3463 EXPECT_FALSE(rfh_b->IsInBackForwardCache());
Hajime Hoshif53fa7ca2019-08-13 06:52:343464
3465 // 4) Execute JavaScript on A in the new world.
3466 EXPECT_FALSE(ExecJs(rfh_a, "console.log('hi');",
3467 EXECUTE_SCRIPT_DEFAULT_OPTIONS, kNewWorldId));
3468
3469 // RenderFrameHost A is evicted from the BackForwardCache:
3470 delete_observer_rfh_a.WaitUntilDeleted();
Hajime Hoshif9eba2b2019-10-02 08:27:423471
3472 // 5) Go back to A.
3473 web_contents()->GetController().GoBack();
3474 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
Hajime Hoshi45255602019-10-18 07:26:593475 ExpectNotRestored(
Fergal Daly6755cbf2021-02-12 03:06:583476 {BackForwardCacheMetrics::NotRestoredReason::kJavaScriptExecution}, {},
3477 {}, {}, FROM_HERE);
Hajime Hoshia2f68032019-08-05 13:22:383478}
3479
Hajime Hoshif7d7b1a2019-08-14 13:39:253480// Tests the events are fired when going back from the cache.
3481IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, Events) {
3482 ASSERT_TRUE(embedded_test_server()->Start());
Hajime Hoshi21c9ce612021-08-26 11:07:523483 GURL url_a(embedded_test_server()->GetURL(
3484 "a.com", "/back_forward_cache/record_events.html"));
3485 GURL url_b(embedded_test_server()->GetURL(
3486 "b.com", "/back_forward_cache/record_events.html"));
Hajime Hoshif7d7b1a2019-08-14 13:39:253487
3488 // 1) Navigate to A.
3489 EXPECT_TRUE(NavigateToURL(shell(), url_a));
3490 RenderFrameHostImpl* rfh_a = current_frame_host();
3491 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
Hajime Hoshi21c9ce612021-08-26 11:07:523492
3493 // At A, a page-show event is recorded for the first loading.
3494 MatchEventList(rfh_a, ListValueOf("window.pageshow"));
3495
3496 const char kEventPageShowPersisted[] = "Event.PageShow.Persisted";
3497 const int kPageShowNoPersist = 0;
3498 const int kPageShowPersist = 1;
3499 content::FetchHistogramsFromChildProcesses();
3500 EXPECT_THAT(
3501 histogram_tester_.GetAllSamples(kEventPageShowPersisted),
3502 testing::UnorderedElementsAre(base::Bucket(kPageShowNoPersist, 1)));
Hajime Hoshif7d7b1a2019-08-14 13:39:253503
3504 // 2) Navigate to B.
3505 EXPECT_TRUE(NavigateToURL(shell(), url_b));
3506 RenderFrameHostImpl* rfh_b = current_frame_host();
3507 RenderFrameDeletedObserver delete_observer_rfh_b(rfh_b);
3508
3509 EXPECT_FALSE(delete_observer_rfh_a.deleted());
3510 EXPECT_FALSE(delete_observer_rfh_b.deleted());
Hajime Hoshibbc509c2020-04-06 08:55:083511 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
3512 EXPECT_FALSE(rfh_b->IsInBackForwardCache());
Yuzu Saijodfba8fa62019-08-27 02:15:223513 // TODO(yuzus): Post message to the frozen page, and make sure that the
3514 // messages arrive after the page visibility events, not before them.
Hajime Hoshif7d7b1a2019-08-14 13:39:253515
Hajime Hoshi21c9ce612021-08-26 11:07:523516 // As |rfh_a| is in back-forward cache, we cannot get the event list of A.
3517 // At B, a page-show event is recorded for the first loading.
3518 MatchEventList(rfh_b, ListValueOf("window.pageshow"));
3519 content::FetchHistogramsFromChildProcesses();
3520 EXPECT_THAT(
3521 histogram_tester_.GetAllSamples(kEventPageShowPersisted),
3522 testing::UnorderedElementsAre(base::Bucket(kPageShowNoPersist, 2)));
3523
Hajime Hoshif7d7b1a2019-08-14 13:39:253524 // 3) Go back to A. Confirm that expected events are fired.
3525 web_contents()->GetController().GoBack();
3526 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
3527 EXPECT_FALSE(delete_observer_rfh_a.deleted());
3528 EXPECT_FALSE(delete_observer_rfh_b.deleted());
3529 EXPECT_EQ(rfh_a, current_frame_host());
Yuzu Saijodfba8fa62019-08-27 02:15:223530 // visibilitychange events are added twice per each because it is fired for
3531 // both window and document.
Alexander Timin44ccede2020-01-23 09:00:343532 MatchEventList(
Hajime Hoshi21c9ce612021-08-26 11:07:523533 rfh_a, ListValueOf("window.pageshow", "window.pagehide.persisted",
3534 "document.visibilitychange", "window.visibilitychange",
3535 "document.freeze", "document.resume",
3536 "document.visibilitychange", "window.visibilitychange",
3537 "window.pageshow.persisted"));
3538
3539 content::FetchHistogramsFromChildProcesses();
3540 EXPECT_THAT(histogram_tester_.GetAllSamples(kEventPageShowPersisted),
3541 testing::UnorderedElementsAre(base::Bucket(kPageShowNoPersist, 2),
3542 base::Bucket(kPageShowPersist, 1)));
Yuzu Saijoecb779c2019-11-06 12:59:373543}
3544
3545// Tests the events are fired for subframes when going back from the cache.
3546// Test case: a(b) -> c -> a(b)
3547IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, EventsForSubframes) {
3548 ASSERT_TRUE(embedded_test_server()->Start());
3549 GURL url_a(embedded_test_server()->GetURL(
3550 "a.com", "/cross_site_iframe_factory.html?a(b)"));
3551 GURL url_c(embedded_test_server()->GetURL("c.com", "/title1.html"));
3552
3553 // 1) Navigate to A(B).
3554 EXPECT_TRUE(NavigateToURL(shell(), url_a));
3555 RenderFrameHostImpl* rfh_a = current_frame_host();
3556 RenderFrameHostImpl* rfh_b = rfh_a->child_at(0)->current_frame_host();
3557 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
3558 RenderFrameDeletedObserver delete_observer_rfh_b(rfh_b);
3559 StartRecordingEvents(rfh_a);
3560 StartRecordingEvents(rfh_b);
3561
3562 // 2) Navigate to C.
3563 EXPECT_TRUE(NavigateToURL(shell(), url_c));
3564 RenderFrameHostImpl* rfh_c = current_frame_host();
3565 RenderFrameDeletedObserver delete_observer_rfh_c(rfh_c);
3566 EXPECT_FALSE(delete_observer_rfh_a.deleted());
3567 EXPECT_FALSE(delete_observer_rfh_b.deleted());
Hajime Hoshibbc509c2020-04-06 08:55:083568 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
3569 EXPECT_TRUE(rfh_b->IsInBackForwardCache());
3570 EXPECT_FALSE(rfh_c->IsInBackForwardCache());
Yuzu Saijoecb779c2019-11-06 12:59:373571 // TODO(yuzus): Post message to the frozen page, and make sure that the
3572 // messages arrive after the page visibility events, not before them.
3573
3574 // 3) Go back to A(B). Confirm that expected events are fired on the subframe.
3575 web_contents()->GetController().GoBack();
3576 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
3577 EXPECT_FALSE(delete_observer_rfh_a.deleted());
3578 EXPECT_FALSE(delete_observer_rfh_b.deleted());
3579 EXPECT_FALSE(delete_observer_rfh_c.deleted());
3580 EXPECT_EQ(rfh_a, current_frame_host());
Hajime Hoshibbc509c2020-04-06 08:55:083581 EXPECT_FALSE(rfh_a->IsInBackForwardCache());
3582 EXPECT_FALSE(rfh_b->IsInBackForwardCache());
3583 EXPECT_TRUE(rfh_c->IsInBackForwardCache());
Yuzu Saijoecb779c2019-11-06 12:59:373584 // visibilitychange events are added twice per each because it is fired for
3585 // both window and document.
Alexander Timin44ccede2020-01-23 09:00:343586 MatchEventList(
3587 rfh_a,
Rakina Zata Amni5e8442642020-09-30 15:03:213588 ListValueOf("window.pagehide.persisted", "document.visibilitychange",
3589 "window.visibilitychange", "document.freeze",
3590 "document.resume", "document.visibilitychange",
3591 "window.visibilitychange", "window.pageshow.persisted"));
Alexander Timin44ccede2020-01-23 09:00:343592 MatchEventList(
3593 rfh_b,
Rakina Zata Amni5e8442642020-09-30 15:03:213594 ListValueOf("window.pagehide.persisted", "document.visibilitychange",
3595 "window.visibilitychange", "document.freeze",
3596 "document.resume", "document.visibilitychange",
3597 "window.visibilitychange", "window.pageshow.persisted"));
Hajime Hoshif7d7b1a2019-08-14 13:39:253598}
3599
arthursonzogni026e9ea2019-09-05 08:24:513600// Tests the events are fired when going back from the cache.
3601// Same as: BackForwardCacheBrowserTest.Events, but with a document-initiated
3602// navigation. This is a regression test for https://crbug.com/1000324
3603IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
3604 EventsAfterDocumentInitiatedNavigation) {
3605 ASSERT_TRUE(embedded_test_server()->Start());
3606 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
3607 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
3608
3609 // 1) Navigate to A.
3610 EXPECT_TRUE(NavigateToURL(shell(), url_a));
3611 RenderFrameHostImpl* rfh_a = current_frame_host();
3612 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
Yuzu Saijoecb779c2019-11-06 12:59:373613 StartRecordingEvents(rfh_a);
arthursonzogni026e9ea2019-09-05 08:24:513614
3615 // 2) Navigate to B.
3616 EXPECT_TRUE(ExecJs(shell(), JsReplace("location = $1;", url_b.spec())));
3617 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
3618 RenderFrameHostImpl* rfh_b = current_frame_host();
3619 RenderFrameDeletedObserver delete_observer_rfh_b(rfh_b);
3620
arthursonzogni026e9ea2019-09-05 08:24:513621 EXPECT_FALSE(delete_observer_rfh_a.deleted());
3622 EXPECT_FALSE(delete_observer_rfh_b.deleted());
Hajime Hoshibbc509c2020-04-06 08:55:083623 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
3624 EXPECT_FALSE(rfh_b->IsInBackForwardCache());
arthursonzogni026e9ea2019-09-05 08:24:513625 // TODO(yuzus): Post message to the frozen page, and make sure that the
3626 // messages arrive after the page visibility events, not before them.
3627
3628 // 3) Go back to A. Confirm that expected events are fired.
3629 web_contents()->GetController().GoBack();
3630 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
3631 EXPECT_FALSE(delete_observer_rfh_a.deleted());
3632 EXPECT_FALSE(delete_observer_rfh_b.deleted());
3633 EXPECT_EQ(rfh_a, current_frame_host());
3634 // visibilitychange events are added twice per each because it is fired for
3635 // both window and document.
Alexander Timin44ccede2020-01-23 09:00:343636 MatchEventList(
3637 rfh_a,
Rakina Zata Amni5e8442642020-09-30 15:03:213638 ListValueOf("window.pagehide.persisted", "document.visibilitychange",
3639 "window.visibilitychange", "document.freeze",
3640 "document.resume", "document.visibilitychange",
3641 "window.visibilitychange", "window.pageshow.persisted"));
arthursonzogni026e9ea2019-09-05 08:24:513642}
3643
Yuzu Saijo26b52292021-08-16 04:26:013644IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
3645 DoesNotCacheIfBroadcastChannelStillOpen) {
Yuzu Saijo948c2ce2021-02-18 16:16:433646 ASSERT_TRUE(CreateHttpsServer()->Start());
3647
3648 // 1) Navigate to an empty page.
3649 GURL url_a(https_server()->GetURL(
3650 "a.com", "/back_forward_cache/page_with_broadcastchannel.html"));
3651 GURL url_b(https_server()->GetURL("b.com", "/title1.html"));
3652 EXPECT_TRUE(NavigateToURL(shell(), url_a));
3653 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
3654
3655 // 2) Use BroadcastChannel (a non-sticky blocklisted feature).
3656 RenderFrameHostImpl* rfh_a = current_frame_host();
3657 EXPECT_TRUE(ExecJs(rfh_a, "acquireBroadcastChannel();"));
3658 EXPECT_TRUE(ExecJs(rfh_a, "setShouldCloseChannelInPageHide(false);"));
3659
3660 // 3) Navigate cross-site, browser-initiated.
3661 // The previous page won't get into the back-forward cache because of the
3662 // blocklisted feature.
3663 EXPECT_TRUE(NavigateToURL(shell(), url_b));
3664 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
3665
3666 // 4) Go back.
3667 web_contents()->GetController().GoBack();
3668 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
3669
3670 // Because the RenderFrameHostManager changed, the blocklisted features will
3671 // be tracked in RenderFrameHostManager::UnloadOldFrame.
3672 ExpectNotRestored(
3673 {BackForwardCacheMetrics::NotRestoredReason::kBlocklistedFeatures},
3674 {blink::scheduler::WebSchedulerTrackedFeature::kBroadcastChannel}, {}, {},
3675 FROM_HERE);
3676}
3677
Yuzu Saijo26b52292021-08-16 04:26:013678IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
3679 CacheIfBroadcastChannelIsClosedInPagehide) {
Yuzu Saijo948c2ce2021-02-18 16:16:433680 ASSERT_TRUE(CreateHttpsServer()->Start());
3681
3682 // 1) Navigate to an empty page.
3683 GURL url_a(https_server()->GetURL(
3684 "a.com", "/back_forward_cache/page_with_broadcastchannel.html"));
3685 GURL url_b(https_server()->GetURL("b.com", "/title1.html"));
3686 EXPECT_TRUE(NavigateToURL(shell(), url_a));
3687 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
3688
3689 RenderFrameHostImpl* rfh_a = current_frame_host();
3690 // 2) Use BroadcastChannel (a non-sticky blocklisted feature).
3691 EXPECT_TRUE(ExecJs(rfh_a, "acquireBroadcastChannel();"));
3692 EXPECT_TRUE(ExecJs(rfh_a, "setShouldCloseChannelInPageHide(true);"));
3693
3694 // 3) Navigate cross-site, browser-initiated.
3695 // The previous page won't get into the back-forward cache because of the
3696 // blocklisted feature.
3697 EXPECT_TRUE(NavigateToURL(shell(), url_b));
3698 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
3699
3700 // 4) Go back.
3701 web_contents()->GetController().GoBack();
3702 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
3703 ExpectRestored(FROM_HERE);
3704}
3705
Yuzu Saijo3a3f2222021-05-18 08:05:063706// Navigates from page A -> page B -> page C -> page B -> page C. Page B becomes
3707// ineligible for bfcache in pagehide handler, so Page A stays in bfcache
3708// without being evicted even after the navigation to Page C.
3709IN_PROC_BROWSER_TEST_F(
Yuzu Saijo26b52292021-08-16 04:26:013710 BackForwardCacheBrowserTest,
Yuzu Saijo3a3f2222021-05-18 08:05:063711 PagehideMakesPageIneligibleForBackForwardCacheAndNotCountedInCacheSize) {
3712 ASSERT_TRUE(CreateHttpsServer()->Start());
3713 GURL url_a(https_server()->GetURL("a.com", "/title1.html"));
3714 GURL url_b(https_server()->GetURL(
3715 "b.com", "/back_forward_cache/page_with_broadcastchannel.html"));
3716 GURL url_c(https_server()->GetURL("c.com", "/title1.html"));
3717
3718 // 1) Navigate to a.com.
3719 EXPECT_TRUE(NavigateToURL(shell(), url_a));
3720 RenderFrameHostImpl* rfh_a = current_frame_host();
3721
3722 // 2) Navigate to b.com.
3723 EXPECT_TRUE(NavigateToURL(shell(), url_b));
3724 RenderFrameHostImpl* rfh_b = current_frame_host();
3725 RenderFrameDeletedObserver deleted_observer_rfh_b(rfh_b);
3726 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
3727 // Acquire broadcast in pagehide. Now b.com is not eligible for bfcache.
3728 EXPECT_TRUE(
3729 ExecJs(rfh_b, "setShouldAcquireBroadcastChannelInPageHide(true);"));
3730
3731 // 3) Navigate to c.com.
3732 EXPECT_TRUE(NavigateToURL(shell(), url_c));
3733 // RenderFrameHostImpl* rfh_c = current_frame_host();
3734 // Since the b.com is not eligible for bfcache, |rfh_a| should stay in
3735 // bfcache.
3736 deleted_observer_rfh_b.WaitUntilDeleted();
3737 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
3738
3739 // 4) Navigate back to b.com.
3740 web_contents()->GetController().GoBack();
3741 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
3742 ExpectNotRestored(
3743 {BackForwardCacheMetrics::NotRestoredReason::kBlocklistedFeatures},
3744 {blink::scheduler::WebSchedulerTrackedFeature::kBroadcastChannel}, {}, {},
3745 FROM_HERE);
3746 RenderFrameHostImpl* rfh_b_2 = current_frame_host();
3747 // Do not acquire broadcast channel. Now b.com is eligible for bfcache.
3748 EXPECT_TRUE(
3749 ExecJs(rfh_b_2, "setShouldAcquireBroadcastChannelInPageHide(false);"));
3750
3751 // 5) Navigate forward to c.com.
3752 web_contents()->GetController().GoForward();
3753 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
3754 ExpectRestored(FROM_HERE);
3755 // b.com was eligible for bfcache and should stay in bfcache.
3756 EXPECT_TRUE(rfh_b_2->IsInBackForwardCache());
3757}
3758
Yuzu Saijoc407d6b42021-07-28 14:52:023759// Disabled on Android, since we have problems starting up the websocket test
3760// server in the host
3761#if defined(OS_ANDROID)
3762#define MAYBE_WebSocketCachedIfClosed DISABLED_WebSocketCachedIfClosed
3763#else
3764#define MAYBE_WebSocketCachedIfClosed WebSocketCachedIfClosed
3765#endif
3766// Pages with WebSocket should be cached if the connection is closed.
Yuzu Saijo26b52292021-08-16 04:26:013767IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
3768 MAYBE_WebSocketCachedIfClosed) {
Yuzu Saijoc407d6b42021-07-28 14:52:023769 net::SpawnedTestServer ws_server(net::SpawnedTestServer::TYPE_WS,
3770 net::GetWebSocketTestDataDirectory());
3771 ASSERT_TRUE(ws_server.Start());
3772
3773 ASSERT_TRUE(embedded_test_server()->Start());
3774
3775 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
3776 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
3777
3778 // 1) Navigate to A.
3779 ASSERT_TRUE(NavigateToURL(shell(), url_a));
3780 RenderFrameHostImplWrapper rfh_a(current_frame_host());
3781
3782 // Open a WebSocket.
3783 const char script[] = R"(
3784 let socket;
3785 window.onpagehide = event => {
3786 socket.close();
3787 }
3788 new Promise(resolve => {
3789 socket = new WebSocket($1);
3790 socket.addEventListener('open', () => resolve());
3791 });)";
3792 ASSERT_TRUE(
3793 ExecJs(rfh_a.get(),
3794 JsReplace(script, ws_server.GetURL("echo-with-no-extension"))));
3795
3796 // 2) Navigate to B.
3797 ASSERT_TRUE(NavigateToURL(shell(), url_b));
3798 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
3799
3800 // 3) Navigate back.
3801 web_contents()->GetController().GoBack();
3802 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
3803 ExpectRestored(FROM_HERE);
3804}
3805
Yutaka Hiranobbfe1822021-08-30 10:09:093806class WebTransportBackForwardCacheBrowserTest
3807 : public BackForwardCacheBrowserTest {
3808 public:
3809 WebTransportBackForwardCacheBrowserTest() { server_.Start(); }
3810 void SetUpCommandLine(base::CommandLine* command_line) override {
3811 BackForwardCacheBrowserTest::SetUpCommandLine(command_line);
3812 server_.SetUpCommandLine(command_line);
3813 }
3814 int port() const { return server_.server_address().port(); }
3815
3816 private:
3817 WebTransportSimpleTestServer server_;
3818};
3819
3820// Pages with active WebTransport should not be cached.
3821// TODO(yhirano): Update this test once
3822// https://github.com/w3c/webtransport/issues/326 is resolved.
3823IN_PROC_BROWSER_TEST_F(WebTransportBackForwardCacheBrowserTest,
3824 ActiveWebTransportEvictsPage) {
3825 ASSERT_TRUE(embedded_test_server()->Start());
3826
3827 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
3828 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
3829
3830 // 1) Navigate to A.
3831 ASSERT_TRUE(NavigateToURL(shell(), url_a));
3832 RenderFrameHostImplWrapper rfh_a(current_frame_host());
3833 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a.get());
3834
3835 // Establish a WebTransport session.
3836 const char script[] = R"(
3837 let transport = new WebTransport('https://localhost:$1/echo');
3838 )";
3839 ASSERT_TRUE(ExecJs(rfh_a.get(), JsReplace(script, port())));
3840
3841 // 2) Navigate to B.
3842 ASSERT_TRUE(NavigateToURL(shell(), url_b));
3843
3844 // Confirm A is evicted.
3845 delete_observer_rfh_a.WaitUntilDeleted();
3846
3847 // 3) Go back.
3848 web_contents()->GetController().GoBack();
3849 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
3850 ExpectNotRestored(
3851 {BackForwardCacheMetrics::NotRestoredReason::kBlocklistedFeatures},
3852 {blink::scheduler::WebSchedulerTrackedFeature::kWebTransport}, {}, {},
3853 FROM_HERE);
3854}
3855
3856// Pages with inactive WebTransport should be cached.
3857IN_PROC_BROWSER_TEST_F(WebTransportBackForwardCacheBrowserTest,
3858 WebTransportCachedIfClosed) {
3859 ASSERT_TRUE(embedded_test_server()->Start());
3860
3861 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
3862 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
3863
3864 // 1) Navigate to A.
3865 ASSERT_TRUE(NavigateToURL(shell(), url_a));
3866 RenderFrameHostImplWrapper rfh_a(current_frame_host());
3867
3868 // Establish a WebTransport session.
3869 const char script[] = R"(
3870 let transport;
3871 window.onpagehide = event => {
3872 transport.close();
3873 };
3874 transport = new WebTransport('https://localhost:$1/echo');
3875 )";
3876 ASSERT_TRUE(ExecJs(rfh_a.get(), JsReplace(script, port())));
3877
3878 // 2) Navigate to B.
3879 ASSERT_TRUE(NavigateToURL(shell(), url_b));
3880 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
3881
3882 // 3) Navigate back.
3883 web_contents()->GetController().GoBack();
3884 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
3885 ExpectRestored(FROM_HERE);
3886}
3887
Rakina Zata Amni67d49f22020-10-10 01:57:343888// Track the events dispatched when a page is deemed ineligible for back-forward
3889// cache after we've dispatched the 'pagehide' event with persisted set to true.
3890IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
3891 EventsForPageIneligibleAfterPagehidePersisted) {
3892 ASSERT_TRUE(CreateHttpsServer()->Start());
3893 GURL url_1(https_server()->GetURL("a.com", "/title1.html"));
3894 GURL url_2(https_server()->GetURL("a.com", "/title2.html"));
3895
3896 // 1) Navigate to |url_1|.
3897 EXPECT_TRUE(NavigateToURL(shell(), url_1));
3898 RenderFrameHostImpl* rfh_1 = current_frame_host();
3899 RenderFrameDeletedObserver delete_observer_rfh_1(rfh_1);
Hajime Hoshi309f3236f92020-12-01 05:34:173900 // 2) Use BroadcastChannel (a non-sticky blocklisted feature), so that we
3901 // would still do a RFH swap on same-site navigation and fire the 'pagehide'
3902 // event during commit of the new page with 'persisted' set to true, but the
3903 // page will not be eligible for back-forward cache after commit.
3904 EXPECT_TRUE(ExecJs(rfh_1, "window.foo = new BroadcastChannel('foo');"));
Rakina Zata Amni67d49f22020-10-10 01:57:343905
3906 EXPECT_TRUE(ExecJs(rfh_1, R"(
3907 window.onpagehide = (e) => {
3908 if (e.persisted) {
3909 window.domAutomationController.send('pagehide.persisted');
3910 }
3911 }
3912 document.onvisibilitychange = () => {
3913 if (document.visibilityState == 'hidden') {
3914 window.domAutomationController.send('visibilitychange.hidden');
3915 }
3916 }
3917 window.onunload = () => {
3918 window.domAutomationController.send('unload');
3919 }
3920 )"));
3921
3922 DOMMessageQueue dom_message_queue(shell()->web_contents());
3923 // 3) Navigate to |url_2|.
3924 EXPECT_TRUE(NavigateToURL(shell(), url_2));
3925 // |rfh_1| will not get into the back-forward cache and eventually get deleted
3926 // because it uses a blocklisted feature.
3927 delete_observer_rfh_1.WaitUntilDeleted();
3928
3929 // Only the pagehide and visibilitychange events will be dispatched.
3930 int num_messages_received = 0;
3931 std::string expected_messages[] = {"\"pagehide.persisted\"",
3932 "\"visibilitychange.hidden\""};
3933 std::string message;
3934 while (dom_message_queue.PopMessage(&message)) {
3935 EXPECT_EQ(expected_messages[num_messages_received], message);
3936 num_messages_received++;
3937 }
3938 EXPECT_EQ(num_messages_received, 2);
3939}
3940
3941// Track the events dispatched when a page is deemed ineligible for back-forward
3942// cache before we've dispatched the pagehide event on it.
3943IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
3944 EventsForPageIneligibleBeforePagehide) {
3945 ASSERT_TRUE(CreateHttpsServer()->Start());
3946 GURL url_1(https_server()->GetURL("a.com", "/title1.html"));
3947 GURL url_2(https_server()->GetURL("b.com", "/title2.html"));
3948
3949 // 1) Navigate to |url_1|.
3950 EXPECT_TRUE(NavigateToURL(shell(), url_1));
3951 RenderFrameHostImpl* rfh_1 = current_frame_host();
3952 RenderFrameDeletedObserver delete_observer_rfh_1(rfh_1);
3953 // 2) Use keyboard lock (a sticky blocklisted feature), so that the page is
3954 // known to be ineligible for bfcache at commit time, before we dispatch the
3955 // pagehide event.
3956 EXPECT_TRUE(ExecJs(rfh_1, R"(
3957 new Promise(resolve => {
3958 navigator.keyboard.lock();
3959 resolve();
3960 });
3961 )"));
3962
3963 EXPECT_TRUE(ExecJs(rfh_1, R"(
3964 window.onpagehide = (e) => {
3965 if (!e.persisted) {
3966 window.domAutomationController.send('pagehide.not_persisted');
3967 }
3968 }
3969 document.onvisibilitychange = () => {
3970 if (document.visibilityState == 'hidden') {
3971 window.domAutomationController.send('visibilitychange.hidden');
3972 }
3973 }
3974 window.onunload = () => {
3975 window.domAutomationController.send('unload');
3976 }
3977 )"));
3978
3979 DOMMessageQueue dom_message_queue(shell()->web_contents());
3980 // 3) Navigate to |url_2|.
3981 EXPECT_TRUE(NavigateToURL(shell(), url_2));
3982 // |rfh_1| will not get into the back-forward cache and eventually get deleted
3983 // because it uses a blocklisted feature.
3984 delete_observer_rfh_1.WaitUntilDeleted();
3985
3986 // "pagehide", "visibilitychange", and "unload" events will be dispatched.
3987 int num_messages_received = 0;
3988 std::string expected_messages[] = {"\"pagehide.not_persisted\"",
3989 "\"visibilitychange.hidden\"",
3990 "\"unload\""};
3991 std::string message;
3992 while (dom_message_queue.PopMessage(&message)) {
3993 EXPECT_EQ(expected_messages[num_messages_received], message);
3994 num_messages_received++;
3995 }
3996 EXPECT_EQ(num_messages_received, 3);
3997}
3998
Yuzu Saijo95b77322020-06-16 17:50:223999IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, EvictPageWithInfiniteLoop) {
4000 ASSERT_TRUE(embedded_test_server()->Start());
4001 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
4002 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
4003
4004 // 1) Navigate to A.
4005 EXPECT_TRUE(NavigateToURL(shell(), url_a));
4006 RenderFrameHostImpl* rfh_a = current_frame_host();
4007
4008 ExecuteScriptAsync(rfh_a, R"(
4009 let i = 0;
4010 while (true) { i++; }
4011 )");
4012
4013 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
4014 RenderProcessHost* process = rfh_a->GetProcess();
4015 RenderProcessHostWatcher destruction_observer(
4016 process, RenderProcessHostWatcher::WATCH_FOR_HOST_DESTRUCTION);
4017
4018 // 2) Navigate to B.
4019 EXPECT_TRUE(NavigateToURL(shell(), url_b));
4020 RenderFrameHostImpl* rfh_b = current_frame_host();
4021 RenderFrameDeletedObserver delete_observer_rfh_b(rfh_b);
4022
4023 // rfh_a should be destroyed (not kept in the cache).
4024 destruction_observer.Wait();
4025 delete_observer_rfh_a.WaitUntilDeleted();
4026
4027 // rfh_b should still be the current frame.
4028 EXPECT_EQ(current_frame_host(), rfh_b);
4029 EXPECT_FALSE(delete_observer_rfh_b.deleted());
4030
4031 // 3) Go back to A.
4032 web_contents()->GetController().GoBack();
4033 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
Yuzu Saijo95b77322020-06-16 17:50:224034 ExpectNotRestored(
Fergal Daly6755cbf2021-02-12 03:06:584035 {BackForwardCacheMetrics::NotRestoredReason::kTimeoutPuttingInCache}, {},
4036 {}, {}, FROM_HERE);
Yuzu Saijo95b77322020-06-16 17:50:224037}
4038
Lowell Manners075b4422019-08-28 15:12:284039// Test the race condition where a document is evicted from the BackForwardCache
Carlos Caballero8f4c0c662020-12-01 19:26:074040// while it is in the middle of being restored and before URL loader starts a
4041// response.
Lowell Manners075b4422019-08-28 15:12:284042//
4043// ┌───────┐ ┌────────┐
4044// │Browser│ │Renderer│
4045// └───┬───┘ └───┬────┘
4046// (Freeze & store the cache) │
4047// │────────────────────────>│
4048// │ │
4049// (Navigate to cached document) │
4050// │──┐ │
4051// │ │ │
4052// │EvictFromBackForwardCache│
4053// │<────────────────────────│
4054// │ │ │
4055// │ x Navigation cancelled │
4056// │ and reissued │
4057// ┌───┴───┐ ┌───┴────┐
4058// │Browser│ │Renderer│
4059// └───────┘ └────────┘
4060//
4061// When the eviction occurs, the in flight NavigationRequest to the cached
4062// document should be reissued (cancelled and replaced by a normal navigation).
Carlos Caballero8f4c0c662020-12-01 19:26:074063//
Andrey Kosyakov7292c1942020-10-09 01:50:314064// Flaky on most platforms (see crbug.com/1136683)
Alexander Timin27ea67372020-10-08 22:53:014065IN_PROC_BROWSER_TEST_F(
4066 BackForwardCacheBrowserTest,
Aya ElAttar7098eca62020-10-09 07:41:454067 DISABLED_ReissuesNavigationIfEvictedDuringNavigation_BeforeResponse) {
Alexander Timin27ea67372020-10-08 22:53:014068 ASSERT_TRUE(embedded_test_server()->Start());
4069 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
4070 GURL url_b(embedded_test_server()->GetURL("b.com", "/title2.html"));
4071
4072 // 1) Navigate to page A.
4073 EXPECT_TRUE(NavigateToURL(shell(), url_a));
4074 RenderFrameHostImpl* rfh_a = current_frame_host();
4075 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
4076
4077 // 2) Navigate to page B.
4078 EXPECT_TRUE(NavigateToURL(shell(), url_b));
4079 RenderFrameHostImpl* rfh_b = current_frame_host();
4080 RenderFrameDeletedObserver delete_observer_rfh_b(rfh_b);
4081 EXPECT_FALSE(delete_observer_rfh_a.deleted());
4082 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
4083 EXPECT_NE(rfh_a, rfh_b);
4084
4085 // 3) Start navigation to page A, and cause the document to be evicted during
4086 // the navigation immediately before navigation makes any meaningful progress.
4087 web_contents()->GetController().GoBack();
4088 EvictByJavaScript(rfh_a);
4089
4090 // rfh_a should have been deleted, and page A navigated to normally.
4091 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
4092 delete_observer_rfh_a.WaitUntilDeleted();
4093 RenderFrameHostImpl* rfh_a2 = current_frame_host();
4094 EXPECT_NE(rfh_a2, rfh_b);
4095 EXPECT_EQ(rfh_a2->GetLastCommittedURL(), url_a);
4096
Alexander Timin27ea67372020-10-08 22:53:014097 ExpectNotRestored(
Fergal Daly6755cbf2021-02-12 03:06:584098 {BackForwardCacheMetrics::NotRestoredReason::kJavaScriptExecution}, {},
4099 {}, {}, FROM_HERE);
Alexander Timin27ea67372020-10-08 22:53:014100}
4101
Lowell Manners20250112019-10-18 15:06:154102// Similar to ReissuesNavigationIfEvictedDuringNavigation, except that
4103// BackForwardCache::Flush is the source of the eviction.
4104IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
4105 FlushCacheDuringNavigationToCachedPage) {
4106 ASSERT_TRUE(embedded_test_server()->Start());
4107 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
4108 GURL url_b(embedded_test_server()->GetURL("b.com", "/title2.html"));
4109
4110 // 1) Navigate to page A.
4111 EXPECT_TRUE(NavigateToURL(shell(), url_a));
4112 RenderFrameHostImpl* rfh_a1 = current_frame_host();
4113 RenderFrameDeletedObserver delete_observer_rfh_a1(rfh_a1);
4114
4115 // 2) Navigate to page B.
4116 EXPECT_TRUE(NavigateToURL(shell(), url_b));
4117 RenderFrameHostImpl* rfh_b2 = current_frame_host();
4118 RenderFrameDeletedObserver delete_observer_rfh_b2(rfh_b2);
4119 EXPECT_FALSE(delete_observer_rfh_a1.deleted());
Hajime Hoshibbc509c2020-04-06 08:55:084120 EXPECT_TRUE(rfh_a1->IsInBackForwardCache());
Lowell Manners20250112019-10-18 15:06:154121 EXPECT_NE(rfh_a1, rfh_b2);
4122
4123 // 3) Start navigation to page A, and flush the cache during the navigation.
4124 TestNavigationManager navigation_manager(shell()->web_contents(), url_a);
4125 web_contents()->GetController().GoBack();
4126
David Bokan377fb3e2021-06-09 16:19:574127 EXPECT_TRUE(navigation_manager.WaitForResponse());
Lowell Manners20250112019-10-18 15:06:154128
4129 // Flush the cache, which contains the document being navigated to.
4130 web_contents()->GetController().GetBackForwardCache().Flush();
4131
4132 // The navigation should get canceled, then reissued; ultimately resulting in
4133 // a successful navigation using a new RenderFrameHost.
4134 navigation_manager.WaitForNavigationFinished();
4135
4136 // rfh_a should have been deleted, and page A navigated to normally.
4137 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
4138 delete_observer_rfh_a1.WaitUntilDeleted();
Hajime Hoshibbc509c2020-04-06 08:55:084139 EXPECT_TRUE(rfh_b2->IsInBackForwardCache());
Lowell Manners20250112019-10-18 15:06:154140 RenderFrameHostImpl* rfh_a3 = current_frame_host();
4141 EXPECT_EQ(rfh_a3->GetLastCommittedURL(), url_a);
4142}
4143
Lowell Mannersda3ffd42019-08-28 17:33:584144// Test that if the renderer process crashes while a document is in the
4145// BackForwardCache, it gets evicted.
4146IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
4147 EvictsFromCacheIfRendererProcessCrashes) {
4148 ASSERT_TRUE(embedded_test_server()->Start());
arthursonzogni72b66492019-11-04 12:24:334149 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
4150 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
Lowell Mannersda3ffd42019-08-28 17:33:584151
4152 // 1) Navigate to A.
4153 EXPECT_TRUE(NavigateToURL(shell(), url_a));
4154 RenderFrameHostImpl* rfh_a = current_frame_host();
Lowell Mannersda3ffd42019-08-28 17:33:584155
4156 // 2) Navigate to B.
4157 EXPECT_TRUE(NavigateToURL(shell(), url_b));
4158 RenderFrameHostImpl* rfh_b = current_frame_host();
Lowell Mannersda3ffd42019-08-28 17:33:584159
Hajime Hoshibbc509c2020-04-06 08:55:084160 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
Lowell Mannersda3ffd42019-08-28 17:33:584161
4162 // 3) Crash A's renderer process while it is in the cache.
Johann2fad7002021-04-13 09:02:094163 {
4164 RenderProcessHost* process = rfh_a->GetProcess();
4165 RenderProcessHostWatcher crash_observer(
4166 process, RenderProcessHostWatcher::WATCH_FOR_HOST_DESTRUCTION);
4167 EXPECT_TRUE(process->Shutdown(0));
4168 crash_observer.Wait();
4169 }
Lowell Mannersda3ffd42019-08-28 17:33:584170
4171 // rfh_b should still be the current frame.
4172 EXPECT_EQ(current_frame_host(), rfh_b);
Hajime Hoshif9eba2b2019-10-02 08:27:424173
4174 // 4) Go back to A.
4175 web_contents()->GetController().GoBack();
4176 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
Hajime Hoshi45255602019-10-18 07:26:594177 ExpectNotRestored(
Fergal Daly6755cbf2021-02-12 03:06:584178 {BackForwardCacheMetrics::NotRestoredReason::kRendererProcessKilled}, {},
4179 {}, {}, FROM_HERE);
Lowell Mannersda3ffd42019-08-28 17:33:584180}
4181
arthursonzognie667c382019-08-30 11:50:134182// The test is simulating a race condition. The scheduler tracked features are
4183// updated during the "freeze" event in a way that would have prevented the
4184// document from entering the BackForwardCache in the first place.
4185//
4186// TODO(https://crbug.com/996267): The document should be evicted.
4187//
4188// ┌───────┐ ┌────────┐
4189// │browser│ │renderer│
4190// └───┬───┘ └────┬───┘
4191// (enter cache) │
4192// │ Freeze() │
4193// │─────────────────────────────>│
4194// │ (onfreeze)
4195// │OnSchedulerTrackedFeaturesUsed│
4196// │<─────────────────────────────│
4197// │ (frozen)
4198// │ │
4199// ┌───┴───┐ ┌────┴───┐
4200// │browser│ │renderer│
4201// └───────┘ └────────┘
4202IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
arthursonzogni9cd875342019-09-04 14:53:464203 SchedulerTrackedFeaturesUpdatedWhileStoring) {
arthursonzognie667c382019-08-30 11:50:134204 ASSERT_TRUE(embedded_test_server()->Start());
4205
4206 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
4207 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
4208
4209 // 1) Navigate to A.
4210 EXPECT_TRUE(NavigateToURL(shell(), url_a));
4211 RenderFrameHostImpl* rfh_a = current_frame_host();
4212 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
4213
4214 // When the page will enter the BackForwardCache, just before being frozen,
4215 // use a feature that would have been prevented the document from being
4216 // cached.
4217 EXPECT_TRUE(ExecJs(rfh_a, R"(
4218 document.addEventListener('freeze', event => {
Hajime Hoshi309f3236f92020-12-01 05:34:174219 window.foo = new BroadcastChannel('foo');
arthursonzognie667c382019-08-30 11:50:134220 });
4221 )"));
4222
4223 // 2) Navigate to B.
4224 EXPECT_TRUE(NavigateToURL(shell(), url_b));
4225
Lowell Manners080c38d2019-09-09 13:24:184226 // rfh_a should be evicted from the cache and destroyed.
4227 delete_observer_rfh_a.WaitUntilDeleted();
arthursonzognie667c382019-08-30 11:50:134228}
4229
Yuzu Saijod80d8562020-11-10 12:28:054230// When loading task is unfreezable with the feature flag
4231// kLoadingTaskUnfreezable, a page will keep processing the in-flight network
4232// requests while the page is frozen in BackForwardCache.
Yuzu Saijo6ddce412021-08-17 05:09:154233IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, FetchWhileStoring) {
Yuzu Saijod80d8562020-11-10 12:28:054234 net::test_server::ControllableHttpResponse fetch_response(
4235 embedded_test_server(), "/fetch");
4236 ASSERT_TRUE(embedded_test_server()->Start());
4237
4238 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
4239 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
4240
4241 // 1) Navigate to A.
4242 EXPECT_TRUE(NavigateToURL(shell(), url_a));
4243 RenderFrameHostImpl* rfh_a = current_frame_host();
4244 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
4245
4246 // Use "fetch" immediately before being frozen.
4247 EXPECT_TRUE(ExecJs(rfh_a, R"(
4248 document.addEventListener('freeze', event => {
4249 my_fetch = fetch('/fetch', { keepalive: true});
4250 });
4251 )"));
4252
4253 // 2) Navigate to B.
4254 EXPECT_TRUE(NavigateToURL(shell(), url_b));
4255
4256 fetch_response.WaitForRequest();
4257 fetch_response.Send(net::HTTP_OK, "text/html", "TheResponse");
4258 fetch_response.Done();
4259 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
4260 EXPECT_FALSE(delete_observer_rfh_a.deleted());
4261
4262 // 3) Go back to A.
4263 web_contents()->GetController().GoBack();
4264 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
Fergal Daly09833062021-02-09 07:10:004265 ExpectRestored(FROM_HERE);
Yuzu Saijod80d8562020-11-10 12:28:054266}
arthursonzognie667c382019-08-30 11:50:134267
Rakina Zata Amni6d7c7002021-05-17 09:13:464268// Eviction is triggered when a normal fetch request gets redirected while the
4269// page is in back-forward cache.
Yuzu Saijo6ddce412021-08-17 05:09:154270IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
Rakina Zata Amni6d7c7002021-05-17 09:13:464271 FetchRedirectedWhileStoring) {
4272 net::test_server::ControllableHttpResponse fetch_response(
4273 embedded_test_server(), "/fetch");
4274 net::test_server::ControllableHttpResponse fetch2_response(
4275 embedded_test_server(), "/fetch2");
4276 ASSERT_TRUE(embedded_test_server()->Start());
4277
4278 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
4279 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
4280
4281 // 1) Navigate to A.
4282 EXPECT_TRUE(NavigateToURL(shell(), url_a));
4283 RenderFrameHostImpl* rfh_a = current_frame_host();
4284 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
4285
4286 // Trigger a fetch.
4287 ExecuteScriptAsync(rfh_a, "my_fetch = fetch('/fetch');");
4288
4289 // 2) Navigate to B.
4290 EXPECT_TRUE(NavigateToURL(shell(), url_b));
4291
4292 // Page A is initially stored in the back-forward cache.
4293 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
4294
4295 // Respond the fetch with a redirect.
4296 fetch_response.WaitForRequest();
4297 fetch_response.Send(
4298 "HTTP/1.1 302 Moved Temporarily\r\n"
4299 "Location: /fetch2");
4300 fetch_response.Done();
4301
4302 // Ensure that the request to /fetch2 was never sent (because the page is
4303 // immediately evicted) by checking after 3 seconds.
4304 base::RunLoop loop;
4305 base::OneShotTimer timer;
4306 timer.Start(FROM_HERE, base::TimeDelta::FromSeconds(3), loop.QuitClosure());
4307 loop.Run();
4308 EXPECT_EQ(nullptr, fetch2_response.http_request());
4309
4310 // Page A should be evicted from the back-forward cache.
4311 delete_observer_rfh_a.WaitUntilDeleted();
4312
4313 // 3) Go back to A.
4314 web_contents()->GetController().GoBack();
4315 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
4316 ExpectNotRestored(
4317 {BackForwardCacheMetrics::NotRestoredReason::kNetworkRequestRedirected},
4318 {}, {}, {}, FROM_HERE);
4319}
4320
4321// Eviction is triggered when a keepalive fetch request gets redirected while
4322// the page is in back-forward cache.
4323// TODO(https://crbug.com/1137682): We should not trigger eviction on redirects
4324// of keepalive fetches.
Yuzu Saijo6ddce412021-08-17 05:09:154325IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
Rakina Zata Amni6d7c7002021-05-17 09:13:464326 KeepAliveFetchRedirectedWhileStoring) {
4327 net::test_server::ControllableHttpResponse fetch_response(
4328 embedded_test_server(), "/fetch");
4329 net::test_server::ControllableHttpResponse fetch2_response(
4330 embedded_test_server(), "/fetch2");
4331 ASSERT_TRUE(embedded_test_server()->Start());
4332
4333 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
4334 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
4335
4336 // 1) Navigate to A.
4337 EXPECT_TRUE(NavigateToURL(shell(), url_a));
4338 RenderFrameHostImpl* rfh_a = current_frame_host();
4339 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
4340
4341 // Trigger a keepalive fetch.
4342 ExecuteScriptAsync(rfh_a, "my_fetch = fetch('/fetch', { keepalive: true });");
4343
4344 // 2) Navigate to B.
4345 EXPECT_TRUE(NavigateToURL(shell(), url_b));
4346
4347 // Page A is initially stored in the back-forward cache.
4348 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
4349
4350 // Respond the fetch with a redirect.
4351 fetch_response.WaitForRequest();
4352 fetch_response.Send(
4353 "HTTP/1.1 302 Moved Temporarily\r\n"
4354 "Location: /fetch2");
4355 fetch_response.Done();
4356
4357 // Ensure that the request to /fetch2 was never sent (because the page is
4358 // immediately evicted) by checking after 3 seconds.
4359 // TODO(https://crbug.com/1137682): We should not trigger eviction on
4360 // redirects of keepalive fetches and the redirect request should be sent.
4361 base::RunLoop loop;
4362 base::OneShotTimer timer;
4363 timer.Start(FROM_HERE, base::TimeDelta::FromSeconds(3), loop.QuitClosure());
4364 loop.Run();
4365 EXPECT_EQ(nullptr, fetch2_response.http_request());
4366
4367 // Page A should be evicted from the back-forward cache.
4368 delete_observer_rfh_a.WaitUntilDeleted();
4369
4370 // 3) Go back to A.
4371 web_contents()->GetController().GoBack();
4372 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
4373 ExpectNotRestored(
4374 {BackForwardCacheMetrics::NotRestoredReason::kNetworkRequestRedirected},
4375 {}, {}, {}, FROM_HERE);
4376}
4377
Rakina Zata Amnia3fdcbe2020-11-11 23:35:544378// Tests the case when the header was received before the page is frozen,
4379// but parts of the response body is received when the page is frozen.
Yuzu Saijo6ddce412021-08-17 05:09:154380IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
Yuzu Saijo60bc1902021-04-06 01:39:224381 PageWithDrainedDatapipeRequestsForFetchShouldBeEvicted) {
Rakina Zata Amnia3fdcbe2020-11-11 23:35:544382 net::test_server::ControllableHttpResponse fetch_response(
4383 embedded_test_server(), "/fetch");
4384 ASSERT_TRUE(embedded_test_server()->Start());
4385
4386 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
4387 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
4388
4389 // 1) Navigate to A.
4390 EXPECT_TRUE(NavigateToURL(shell(), url_a));
4391 RenderFrameHostImpl* rfh_a = current_frame_host();
4392 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
4393
4394 // Call fetch before navigating away.
4395 EXPECT_TRUE(ExecJs(rfh_a, R"(
4396 var fetch_response_promise = my_fetch = fetch('/fetch').then(response => {
4397 return response.text();
4398 });
4399 )"));
4400 // Send response header and a piece of the body before navigating away.
4401 fetch_response.WaitForRequest();
4402 fetch_response.Send(net::HTTP_OK, "text/plain");
Yuzu Saijo17691232020-11-30 07:27:414403 fetch_response.Send("body");
Rakina Zata Amnia3fdcbe2020-11-11 23:35:544404
4405 // 2) Navigate to B.
4406 EXPECT_TRUE(NavigateToURL(shell(), url_b));
4407
Yuzu Saijo17691232020-11-30 07:27:414408 delete_observer_rfh_a.WaitUntilDeleted();
Rakina Zata Amnia3fdcbe2020-11-11 23:35:544409
4410 // 3) Go back to A.
4411 web_contents()->GetController().GoBack();
4412 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
Yuzu Saijo73fa301222020-12-10 09:33:514413 ExpectNotRestored({BackForwardCacheMetrics::NotRestoredReason::
Yuzu Saijo60bc1902021-04-06 01:39:224414 kNetworkRequestDatapipeDrainedAsBytesConsumer},
Fergal Daly6755cbf2021-02-12 03:06:584415 {}, {}, {}, FROM_HERE);
Rakina Zata Amnia3fdcbe2020-11-11 23:35:544416}
4417
Yuzu Saijo87d34992021-04-08 06:22:264418IN_PROC_BROWSER_TEST_F(
Yuzu Saijo6ddce412021-08-17 05:09:154419 BackForwardCacheBrowserTest,
Yuzu Saijo24afcb052021-04-26 08:04:414420 PageWithDrainedDatapipeRequestsForScriptStreamerShouldNotBeEvicted) {
Yuzu Saijo87d34992021-04-08 06:22:264421 net::test_server::ControllableHttpResponse response(embedded_test_server(),
4422 "/small_script.js");
4423 ASSERT_TRUE(embedded_test_server()->Start());
4424
4425 GURL url_a(embedded_test_server()->GetURL("a.com", "/empty.html"));
4426 GURL url_b(embedded_test_server()->GetURL("b.com", "/empty.html"));
4427
4428 // 1) Navigate to A.
4429 EXPECT_TRUE(NavigateToURL(shell(), url_a));
4430 // Append the script tag.
4431 EXPECT_TRUE(ExecJs(shell(), R"(
4432 var script = document.createElement('script');
4433 script.src = 'small_script.js'
4434 document.body.appendChild(script);
4435 )"));
4436
4437 response.WaitForRequest();
4438 // Send the small_script.js but not complete, so that the datapipe is passed
4439 // to ScriptStreamer upon bfcache entrance.
4440 const char kHttpResponseHeader[] =
4441 "HTTP/1.1 200 OK\r\n"
4442 "Content-Type: text/html; charset=utf-8\r\n"
4443 "\r\n";
4444 response.Send(kHttpResponseHeader);
4445 response.Send("alert('more than 4 bytes');");
4446
4447 // 2) Navigate to B.
4448 EXPECT_TRUE(NavigateToURL(shell(), url_b));
4449 // Complete the response after navigating away.
Yuzu Saijo24afcb052021-04-26 08:04:414450 response.Send("alert('more than 4 bytes');");
Yuzu Saijo87d34992021-04-08 06:22:264451 response.Done();
4452
4453 // 3) Go back to A.
4454 web_contents()->GetController().GoBack();
4455 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
Yuzu Saijo24afcb052021-04-26 08:04:414456 ExpectRestored(FROM_HERE);
4457}
4458
Mike Wasserman57618e982021-08-04 19:52:474459// TODO(crbug.com/1236190) Disabled for flaky failures on various configs.
Yuzu Saijo24afcb052021-04-26 08:04:414460IN_PROC_BROWSER_TEST_F(
Yuzu Saijo6ddce412021-08-17 05:09:154461 BackForwardCacheBrowserTest,
Mike Wasserman57618e982021-08-04 19:52:474462 DISABLED_PageWithDrainedDatapipeRequestsForScriptStreamerShouldBeEvictedIfStreamedTooMuch) {
Yuzu Saijo24afcb052021-04-26 08:04:414463 net::test_server::ControllableHttpResponse response(embedded_test_server(),
4464 "/small_script.js");
4465 ASSERT_TRUE(embedded_test_server()->Start());
4466
4467 GURL url_a(embedded_test_server()->GetURL("a.com", "/empty.html"));
4468 GURL url_b(embedded_test_server()->GetURL("b.com", "/empty.html"));
4469
4470 // 1) Navigate to A.
4471 EXPECT_TRUE(NavigateToURL(shell(), url_a));
4472 // Append the script tag.
4473 EXPECT_TRUE(ExecJs(shell(), R"(
4474 var script = document.createElement('script');
4475 script.src = 'small_script.js'
4476 document.body.appendChild(script);
4477 )"));
4478
4479 response.WaitForRequest();
4480 // Send the small_script.js but not complete, so that the datapipe is passed
4481 // to ScriptStreamer upon bfcache entrance.
4482 const char kHttpResponseHeader[] =
4483 "HTTP/1.1 200 OK\r\n"
4484 "Content-Type: text/html; charset=utf-8\r\n"
4485 "\r\n";
4486 response.Send(kHttpResponseHeader);
4487 response.Send("alert('more than 4 bytes');");
4488
4489 // 2) Navigate to B.
4490 EXPECT_TRUE(NavigateToURL(shell(), url_b));
4491
4492 // Complete the response after navigating away.
4493 std::string body(kMaxBufferedBytesPerRequest + 1, '*');
4494 response.Send(body);
4495 response.Done();
4496
4497 // 3) Go back to A.
4498 web_contents()->GetController().GoBack();
4499 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
4500 ExpectNotRestored(
4501 {BackForwardCacheMetrics::NotRestoredReason::kNetworkExceedsBufferLimit},
4502 {}, {}, {}, FROM_HERE);
Yuzu Saijo87d34992021-04-08 06:22:264503}
4504
Yuzu Saijo6ddce412021-08-17 05:09:154505IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
Rakina Zata Amni525a2922020-12-03 12:28:154506 ImageStillLoading_ResponseStartedWhileFrozen) {
4507 net::test_server::ControllableHttpResponse image_response(
4508 embedded_test_server(), "/image.png");
4509 ASSERT_TRUE(embedded_test_server()->Start());
4510
4511 // 1) Navigate to a page with an image with src == "image.png".
4512 RenderFrameHostImpl* rfh_1 = NavigateToPageWithImage(
4513 embedded_test_server()->GetURL("a.com", "/title1.html"));
4514 image_response.WaitForRequest();
4515
4516 // 2) Navigate away.
4517 EXPECT_TRUE(NavigateToURL(
4518 shell(), embedded_test_server()->GetURL("b.com", "/title2.html")));
4519 // The page was still loading when we navigated away, but it's still eligible
4520 // for back-forward cache.
4521 EXPECT_TRUE(rfh_1->IsInBackForwardCache());
4522
4523 // Start sending the image body while in the back-forward cache.
4524 image_response.Send(net::HTTP_OK, "image/png");
4525 image_response.Send("image_body");
4526 image_response.Done();
4527
4528 // 3) Go back to the first page. We should restore the page from the
4529 // back-forward cache.
4530 web_contents()->GetController().GoBack();
4531 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
Fergal Daly09833062021-02-09 07:10:004532 ExpectRestored(FROM_HERE);
Rakina Zata Amni525a2922020-12-03 12:28:154533
4534 // Wait until the deferred body is processed. Since it's not a valid image
4535 // value, we'll get the "error" event.
4536 EXPECT_EQ("error", EvalJs(rfh_1, "image_load_status"));
4537}
4538
4539IN_PROC_BROWSER_TEST_F(
Yuzu Saijo6ddce412021-08-17 05:09:154540 BackForwardCacheBrowserTest,
Rakina Zata Amnibd10ef6d2021-01-19 02:50:114541 ImageStillLoading_ResponseStartedWhileFrozen_ExceedsPerRequestBytesLimit) {
Rakina Zata Amni525a2922020-12-03 12:28:154542 net::test_server::ControllableHttpResponse image_response(
4543 embedded_test_server(), "/image.png");
4544 ASSERT_TRUE(embedded_test_server()->Start());
4545
4546 // 1) Navigate to a page with an image with src == "image.png".
4547 RenderFrameHostImpl* rfh_1 = NavigateToPageWithImage(
4548 embedded_test_server()->GetURL("a.com", "/title1.html"));
4549
4550 // Wait for the image request, but don't send anything yet.
4551 image_response.WaitForRequest();
4552
4553 // 2) Navigate away.
4554 EXPECT_TRUE(NavigateToURL(
4555 shell(), embedded_test_server()->GetURL("b.com", "/title2.html")));
4556 // The page was still loading when we navigated away, but it's still eligible
4557 // for back-forward cache.
4558 EXPECT_TRUE(rfh_1->IsInBackForwardCache());
4559
4560 RenderFrameDeletedObserver delete_observer(rfh_1);
4561 // Start sending the image response while in the back-forward cache.
4562 image_response.Send(net::HTTP_OK, "image/png");
Rakina Zata Amnibd10ef6d2021-01-19 02:50:114563 std::string body(kMaxBufferedBytesPerRequest + 1, '*');
Rakina Zata Amni525a2922020-12-03 12:28:154564 image_response.Send(body);
4565 image_response.Done();
4566 delete_observer.WaitUntilDeleted();
4567
4568 // 3) Go back to the first page. We should not restore the page from the
4569 // back-forward cache.
4570 web_contents()->GetController().GoBack();
4571 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
Yuzu Saijo73fa301222020-12-10 09:33:514572 ExpectNotRestored(
4573 {BackForwardCacheMetrics::NotRestoredReason::kNetworkExceedsBufferLimit},
Fergal Daly6755cbf2021-02-12 03:06:584574 {}, {}, {}, FROM_HERE);
Yuzu Saijo73fa301222020-12-10 09:33:514575}
4576
Rakina Zata Amnibd10ef6d2021-01-19 02:50:114577IN_PROC_BROWSER_TEST_F(
Yuzu Saijo6ddce412021-08-17 05:09:154578 BackForwardCacheBrowserTest,
Yuzu Saijo7f3ee742021-04-02 06:59:374579 ImageStillLoading_ResponseStartedWhileRestoring_DoNotTriggerEviction) {
4580 net::test_server::ControllableHttpResponse image_response(
4581 embedded_test_server(), "/image.png");
4582 ASSERT_TRUE(embedded_test_server()->Start());
4583
4584 // 1) Navigate to a page with an image with src == "image.png".
4585 GURL url(embedded_test_server()->GetURL("a.com", "/title1.html"));
4586 RenderFrameHostImpl* rfh_1 = NavigateToPageWithImage(url);
4587
4588 // Wait for the image request, but don't send anything yet.
4589 image_response.WaitForRequest();
4590
4591 // 2) Navigate away.
4592 EXPECT_TRUE(NavigateToURL(
4593 shell(), embedded_test_server()->GetURL("b.com", "/title2.html")));
4594 // The page was still loading when we navigated away, but it's still eligible
4595 // for back-forward cache.
4596 EXPECT_TRUE(rfh_1->IsInBackForwardCache());
4597
4598 // 3) Go back to the first page using TestNavigationManager so that we split
4599 // the navigation into stages.
Yuzu Saijo7f3ee742021-04-02 06:59:374600 TestNavigationManager navigation_manager_back(shell()->web_contents(), url);
4601 web_contents()->GetController().GoBack();
David Bokan1bdb3701f2021-04-30 22:02:354602 EXPECT_TRUE(navigation_manager_back.WaitForResponse());
Yuzu Saijo7f3ee742021-04-02 06:59:374603
David Bokan1bdb3701f2021-04-30 22:02:354604 // Before we try to commit the navigation, BFCache will defer to wait
4605 // asynchronously for renderers to reply that they've unfrozen. Finish the
4606 // image response in that time.
4607 navigation_manager_back.ResumeNavigation();
David Bokan377fb3e2021-06-09 16:19:574608 ASSERT_TRUE(
4609 NavigationRequest::From(navigation_manager_back.GetNavigationHandle())
4610 ->IsCommitDeferringConditionDeferredForTesting());
David Bokan1bdb3701f2021-04-30 22:02:354611 ASSERT_FALSE(navigation_manager_back.GetNavigationHandle()->HasCommitted());
4612
Yuzu Saijo7f3ee742021-04-02 06:59:374613 image_response.Send(net::HTTP_OK, "image/png");
4614 std::string body(kMaxBufferedBytesPerRequest + 1, '*');
4615 image_response.Send(body);
4616 image_response.Done();
4617
4618 // Finish the navigation.
4619 navigation_manager_back.WaitForNavigationFinished();
4620 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
4621 ExpectRestored(FROM_HERE);
4622}
4623
4624IN_PROC_BROWSER_TEST_F(
Yuzu Saijo6ddce412021-08-17 05:09:154625 BackForwardCacheBrowserTest,
Rakina Zata Amnibd10ef6d2021-01-19 02:50:114626 ImageStillLoading_ResponseStartedWhileFrozen_ExceedsPerProcessBytesLimit) {
4627 net::test_server::ControllableHttpResponse image1_response(
4628 embedded_test_server(), "/image1.png");
4629 net::test_server::ControllableHttpResponse image2_response(
4630 embedded_test_server(), "/image2.png");
4631 ASSERT_TRUE(embedded_test_server()->Start());
4632
4633 // 1) Navigate to a page with 2 images.
4634 EXPECT_TRUE(NavigateToURL(
4635 shell(), embedded_test_server()->GetURL("a.com", "/title1.html")));
4636 RenderFrameHostImpl* rfh_1 = current_frame_host();
4637 // Wait for the document to load DOM to ensure that kLoading is not
4638 // one of the reasons why the document wasn't cached.
4639 WaitForDOMContentLoaded(rfh_1);
4640
4641 EXPECT_TRUE(ExecJs(rfh_1, R"(
4642 var image1 = document.createElement("img");
4643 image1.src = "image1.png";
4644 document.body.appendChild(image1);
4645 var image2 = document.createElement("img");
4646 image2.src = "image2.png";
4647 document.body.appendChild(image1);
4648
4649 var image1_load_status = new Promise((resolve, reject) => {
4650 image1.onload = () => { resolve("loaded"); }
4651 image1.onerror = () => { resolve("error"); }
4652 });
4653
4654 var image2_load_status = new Promise((resolve, reject) => {
4655 image2.onload = () => { resolve("loaded"); }
4656 image2.onerror = () => { resolve("error"); }
4657 });
4658 )"));
4659
4660 // Wait for the image requests, but don't send anything yet.
4661 image1_response.WaitForRequest();
4662 image2_response.WaitForRequest();
4663
4664 // 2) Navigate away.
4665 EXPECT_TRUE(NavigateToURL(
4666 shell(), embedded_test_server()->GetURL("b.com", "/title2.html")));
4667 // The page was still loading when we navigated away, but it's still eligible
4668 // for back-forward cache.
4669 EXPECT_TRUE(rfh_1->IsInBackForwardCache());
4670
4671 RenderFrameDeletedObserver delete_observer(rfh_1);
4672 // Start sending the image responses while in the back-forward cache. The
4673 // body size of the responses individually is less than the per-request limit,
4674 // but together they surpass the per-process limit.
4675 const int image_body_size = kMaxBufferedBytesPerProcess / 2 + 1;
4676 DCHECK_LT(image_body_size, kMaxBufferedBytesPerRequest);
4677 std::string body(image_body_size, '*');
4678 image1_response.Send(net::HTTP_OK, "image/png");
4679 image1_response.Send(body);
4680 image1_response.Done();
4681 image2_response.Send(net::HTTP_OK, "image/png");
4682 image2_response.Send(body);
4683 image2_response.Done();
4684 delete_observer.WaitUntilDeleted();
4685
4686 // 3) Go back to the first page. We should not restore the page from the
4687 // back-forward cache.
4688 web_contents()->GetController().GoBack();
4689 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
Rakina Zata Amnibd10ef6d2021-01-19 02:50:114690 ExpectNotRestored(
4691 {BackForwardCacheMetrics::NotRestoredReason::kNetworkExceedsBufferLimit},
Fergal Daly6755cbf2021-02-12 03:06:584692 {}, {}, {}, FROM_HERE);
Rakina Zata Amnibd10ef6d2021-01-19 02:50:114693}
4694
4695IN_PROC_BROWSER_TEST_F(
Yuzu Saijo6ddce412021-08-17 05:09:154696 BackForwardCacheBrowserTest,
Rakina Zata Amnibd10ef6d2021-01-19 02:50:114697 ImageStillLoading_ResponseStartedWhileFrozen_ExceedsPerProcessBytesLimit_SameSiteSubframe) {
4698 net::test_server::ControllableHttpResponse image1_response(
4699 embedded_test_server(), "/image1.png");
4700 net::test_server::ControllableHttpResponse image2_response(
4701 embedded_test_server(), "/image2.png");
4702 ASSERT_TRUE(embedded_test_server()->Start());
4703
4704 // 1) Navigate main frame to a page with 1 image.
4705 EXPECT_TRUE(NavigateToURL(shell(), embedded_test_server()->GetURL(
4706 "a.com", "/page_with_iframe.html")));
4707 RenderFrameHostImpl* main_rfh = current_frame_host();
4708 // Wait for the document to load DOM to ensure that kLoading is not
4709 // one of the reasons why the document wasn't cached.
4710 WaitForDOMContentLoaded(main_rfh);
4711
4712 EXPECT_TRUE(ExecJs(main_rfh, R"(
4713 var image1 = document.createElement("img");
4714 image1.src = "image1.png";
4715 document.body.appendChild(image1);
4716 var image1_load_status = new Promise((resolve, reject) => {
4717 image1.onload = () => { resolve("loaded"); }
4718 image1.onerror = () => { resolve("error"); }
4719 });
4720 )"));
4721
4722 // 2) Add 1 image to the subframe.
4723 RenderFrameHostImpl* subframe_rfh =
4724 main_rfh->child_at(0)->current_frame_host();
4725
4726 // First, wait for the subframe document to load DOM to ensure that kLoading
4727 // is not one of the reasons why the document wasn't cached.
4728 WaitForDOMContentLoaded(subframe_rfh);
4729
4730 EXPECT_TRUE(ExecJs(subframe_rfh, R"(
4731 var image2 = document.createElement("img");
4732 image2.src = "image2.png";
4733 document.body.appendChild(image2);
4734 var image2_load_status = new Promise((resolve, reject) => {
4735 image2.onload = () => { resolve("loaded"); }
4736 image2.onerror = () => { resolve("error"); }
4737 });
4738 )"));
4739
4740 // Wait for the image requests, but don't send anything yet.
4741 image1_response.WaitForRequest();
4742 image2_response.WaitForRequest();
4743
4744 // 3) Navigate away on the main frame.
4745 EXPECT_TRUE(NavigateToURL(
4746 shell(), embedded_test_server()->GetURL("b.com", "/title2.html")));
4747 // The page was still loading images when we navigated away, but it's still
4748 // eligible for back-forward cache.
4749 EXPECT_TRUE(main_rfh->IsInBackForwardCache());
4750 EXPECT_TRUE(subframe_rfh->IsInBackForwardCache());
4751
4752 RenderFrameDeletedObserver delete_observer_1(main_rfh);
4753 RenderFrameDeletedObserver delete_observer_2(subframe_rfh);
4754 // Start sending the image responses while in the back-forward cache. The
4755 // body size of the responses individually is less than the per-request limit,
4756 // but together they surpass the per-process limit since both the main frame
4757 // and the subframe are put in the same renderer process (because they're
4758 // same-site).
4759 const int image_body_size = kMaxBufferedBytesPerProcess / 2 + 1;
4760 DCHECK_LT(image_body_size, kMaxBufferedBytesPerRequest);
4761 std::string body(image_body_size, '*');
4762 image1_response.Send(net::HTTP_OK, "image/png");
4763 image1_response.Send(body);
4764 image1_response.Done();
4765 image2_response.Send(net::HTTP_OK, "image/png");
4766 image2_response.Send(body);
4767 image2_response.Done();
4768 delete_observer_1.WaitUntilDeleted();
4769 delete_observer_2.WaitUntilDeleted();
4770
4771 // 3) Go back to the first page. We should not restore the page from the
4772 // back-forward cache.
4773 web_contents()->GetController().GoBack();
4774 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
Rakina Zata Amnibd10ef6d2021-01-19 02:50:114775 ExpectNotRestored(
4776 {BackForwardCacheMetrics::NotRestoredReason::kNetworkExceedsBufferLimit},
Fergal Daly6755cbf2021-02-12 03:06:584777 {}, {}, {}, FROM_HERE);
Rakina Zata Amnibd10ef6d2021-01-19 02:50:114778}
4779
4780IN_PROC_BROWSER_TEST_F(
Yuzu Saijo6ddce412021-08-17 05:09:154781 BackForwardCacheBrowserTest,
Rakina Zata Amnibd10ef6d2021-01-19 02:50:114782 ImageStillLoading_ResponseStartedWhileFrozen_ExceedsPerProcessBytesLimit_ResetOnRestore) {
4783 net::test_server::ControllableHttpResponse image1_response(
4784 embedded_test_server(), "/image.png");
4785 net::test_server::ControllableHttpResponse image2_response(
4786 embedded_test_server(), "/image2.png");
4787 ASSERT_TRUE(embedded_test_server()->Start());
4788
4789 // 1) Navigate to a page with an image with src == "image.png".
4790 RenderFrameHostImpl* rfh_1 = NavigateToPageWithImage(
4791 embedded_test_server()->GetURL("a.com", "/title1.html"));
4792
4793 // Wait for the image request, but don't send anything yet.
4794 image1_response.WaitForRequest();
4795
4796 // 2) Navigate away on the main frame.
4797 EXPECT_TRUE(NavigateToURL(
4798 shell(), embedded_test_server()->GetURL("a.com", "/title2.html")));
4799 RenderFrameHostImpl* rfh_2 = current_frame_host();
4800 WaitForDOMContentLoaded(rfh_2);
4801
4802 // The first page was still loading images when we navigated away, but it's
4803 // still eligible for back-forward cache.
4804 EXPECT_TRUE(rfh_1->IsInBackForwardCache());
4805
4806 // 3) Add 1 image to the second page.
4807 EXPECT_TRUE(ExecJs(rfh_2, R"(
4808 var image2 = document.createElement("img");
4809 image2.src = "image2.png";
4810 document.body.appendChild(image2);
4811 var image2_load_status = new Promise((resolve, reject) => {
4812 image2.onload = () => { resolve("loaded"); }
4813 image2.onerror = () => { resolve("error"); }
4814 });
4815 )"));
4816 image2_response.WaitForRequest();
4817
4818 // Start sending the image response for the first page while in the
4819 // back-forward cache. The body size of the response is half of the
4820 // per-process limit.
4821 const int image_body_size = kMaxBufferedBytesPerProcess / 2 + 1;
4822 DCHECK_LT(image_body_size, kMaxBufferedBytesPerRequest);
4823 std::string body(image_body_size, '*');
4824 image1_response.Send(net::HTTP_OK, "image/png");
4825 image1_response.Send(body);
4826 image1_response.Done();
4827
4828 // 4) Go back to the first page. We should restore the page from the
4829 // back-forward cache.
4830 web_contents()->GetController().GoBack();
4831 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
Fergal Daly09833062021-02-09 07:10:004832 ExpectRestored(FROM_HERE);
Rakina Zata Amnibd10ef6d2021-01-19 02:50:114833
4834 // The second page was still loading images when we navigated away, but it's
4835 // still eligible for back-forward cache.
4836 EXPECT_TRUE(rfh_2->IsInBackForwardCache());
4837
4838 // Start sending the image response for the second page's image request.
4839 // The second page should still stay in the back-forward cache since the
4840 // per-process buffer limit is reset back to 0 after the first page gets
4841 // restored from the back-forward cache, so we wouldn't go over the
4842 // per-process buffer limit even when the total body size buffered during the
4843 // lifetime of the test actually exceeds the per-process buffer limit.
4844 image2_response.Send(net::HTTP_OK, "image/png");
4845 image2_response.Send(body);
4846 image2_response.Done();
4847
4848 EXPECT_TRUE(rfh_2->IsInBackForwardCache());
4849
4850 // 5) Go forward. We should restore the second page from the back-forward
4851 // cache.
4852 web_contents()->GetController().GoForward();
4853 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
Fergal Daly09833062021-02-09 07:10:004854 ExpectRestored(FROM_HERE);
Rakina Zata Amnibd10ef6d2021-01-19 02:50:114855}
4856
4857IN_PROC_BROWSER_TEST_F(
Yuzu Saijo6ddce412021-08-17 05:09:154858 BackForwardCacheBrowserTest,
Rakina Zata Amnibd10ef6d2021-01-19 02:50:114859 ImageStillLoading_ResponseStartedWhileFrozen_ExceedsPerProcessBytesLimit_ResetOnDetach) {
4860 net::test_server::ControllableHttpResponse image1_response(
4861 embedded_test_server(), "/image.png");
4862 net::test_server::ControllableHttpResponse image2_response(
4863 embedded_test_server(), "/image2.png");
4864 ASSERT_TRUE(embedded_test_server()->Start());
4865
4866 // 1) Navigate to a page with an image with src == "image.png".
4867 RenderFrameHostImpl* rfh_1 = NavigateToPageWithImage(
4868 embedded_test_server()->GetURL("a.com", "/title1.html"));
4869
4870 // Wait for the image request, but don't send anything yet.
4871 image1_response.WaitForRequest();
4872
4873 // 2) Navigate away on the main frame.
4874 EXPECT_TRUE(NavigateToURL(
4875 shell(), embedded_test_server()->GetURL("a.com", "/title2.html")));
4876 RenderFrameHostImpl* rfh_2 = current_frame_host();
4877 WaitForDOMContentLoaded(rfh_2);
4878
4879 // The first page was still loading images when we navigated away, but it's
4880 // still eligible for back-forward cache.
4881 EXPECT_TRUE(rfh_1->IsInBackForwardCache());
4882
4883 // 3) Add 1 image to the second page.
4884 EXPECT_TRUE(ExecJs(rfh_2, R"(
4885 var image2 = document.createElement("img");
4886 image2.src = "image2.png";
4887 document.body.appendChild(image2);
4888 var image2_load_status = new Promise((resolve, reject) => {
4889 image2.onload = () => { resolve("loaded"); }
4890 image2.onerror = () => { resolve("error"); }
4891 });
4892 )"));
4893 image2_response.WaitForRequest();
4894
4895 RenderFrameDeletedObserver delete_observer_1(rfh_1);
4896 // Start sending an image response that's larger than the per-process and
4897 // per-request buffer limit, causing the page to get evicted from the
4898 // back-forward cache.
4899 std::string body(kMaxBufferedBytesPerProcess + 1, '*');
4900 image1_response.Send(net::HTTP_OK, "image/png");
4901 image1_response.Send(body);
4902 image1_response.Done();
4903 delete_observer_1.WaitUntilDeleted();
4904
4905 // 4) Go back to the first page. We should not restore the page from the
4906 // back-forward cache.
4907 web_contents()->GetController().GoBack();
4908 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
Rakina Zata Amnibd10ef6d2021-01-19 02:50:114909 ExpectNotRestored(
4910 {BackForwardCacheMetrics::NotRestoredReason::kNetworkExceedsBufferLimit},
Fergal Daly6755cbf2021-02-12 03:06:584911 {}, {}, {}, FROM_HERE);
Rakina Zata Amnibd10ef6d2021-01-19 02:50:114912
4913 // The second page was still loading images when we navigated away, but it's
4914 // still eligible for back-forward cache.
4915 EXPECT_TRUE(rfh_2->IsInBackForwardCache());
4916
4917 // Start sending a small image response for the second page's image request.
4918 // The second page should still stay in the back-forward cache since the
4919 // per-process buffer limit is reset back to 0 after the first page gets
4920 // evicted and deleted
4921 image2_response.Send(net::HTTP_OK, "image/png");
4922 image2_response.Send("*");
4923 image2_response.Done();
4924
4925 EXPECT_TRUE(rfh_2->IsInBackForwardCache());
4926
4927 // 5) Go forward. We should restore the second page from the back-forward
4928 // cache.
4929 web_contents()->GetController().GoForward();
4930 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
Fergal Daly09833062021-02-09 07:10:004931 ExpectRestored(FROM_HERE);
Rakina Zata Amnibd10ef6d2021-01-19 02:50:114932
4933 // Wait until the deferred body is processed. Since it's not a valid image
4934 // value, we'll get the "error" event.
4935 EXPECT_EQ("error", EvalJs(rfh_2, "image2_load_status"));
4936}
4937
Yuzu Saijo6ddce412021-08-17 05:09:154938IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
Yuzu Saijo73fa301222020-12-10 09:33:514939 ImageStillLoading_ResponseStartedWhileFrozen_Timeout) {
4940 net::test_server::ControllableHttpResponse image_response(
4941 embedded_test_server(), "/image.png");
4942 ASSERT_TRUE(embedded_test_server()->Start());
4943
4944 // 1) Navigate to a page with an image with src == "image.png".
4945 RenderFrameHostImpl* rfh_1 = NavigateToPageWithImage(
4946 embedded_test_server()->GetURL("a.com", "/title1.html"));
4947
4948 // Wait for the image request, but don't send anything yet.
4949 image_response.WaitForRequest();
4950
4951 // 2) Navigate away.
4952 EXPECT_TRUE(NavigateToURL(
4953 shell(), embedded_test_server()->GetURL("b.com", "/title2.html")));
4954 // The page was still loading when we navigated away, but it's still eligible
4955 // for back-forward cache.
4956 EXPECT_TRUE(rfh_1->IsInBackForwardCache());
4957
4958 RenderFrameDeletedObserver delete_observer(rfh_1);
Rakina Zata Amni6e599ec2020-12-14 03:16:184959 // Start sending the image response while in the back-forward cache, but never
4960 // finish the request. Eventually the page will get deleted due to network
4961 // request timeout.
Yuzu Saijo73fa301222020-12-10 09:33:514962 image_response.Send(net::HTTP_OK, "image/png");
Rakina Zata Amnibd10ef6d2021-01-19 02:50:114963 std::string body(kMaxBufferedBytesPerRequest + 1, '*');
Yuzu Saijo73fa301222020-12-10 09:33:514964 delete_observer.WaitUntilDeleted();
4965
4966 // 3) Go back to the first page. We should not restore the page from the
4967 // back-forward cache.
4968 web_contents()->GetController().GoBack();
4969 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
Yuzu Saijo73fa301222020-12-10 09:33:514970 ExpectNotRestored(
Fergal Daly6755cbf2021-02-12 03:06:584971 {BackForwardCacheMetrics::NotRestoredReason::kNetworkRequestTimeout}, {},
4972 {}, {}, FROM_HERE);
Rakina Zata Amni525a2922020-12-03 12:28:154973}
4974
Rakina Zata Amni525a2922020-12-03 12:28:154975IN_PROC_BROWSER_TEST_F(
Yuzu Saijo6ddce412021-08-17 05:09:154976 BackForwardCacheBrowserTest,
Rakina Zata Amnibd10ef6d2021-01-19 02:50:114977 ImageStillLoading_ResponseStartedBeforeFreezing_ExceedsPerRequestBytesLimit) {
Rakina Zata Amni525a2922020-12-03 12:28:154978 net::test_server::ControllableHttpResponse image_response(
4979 embedded_test_server(), "/image.png");
4980 ASSERT_TRUE(embedded_test_server()->Start());
4981
4982 // 1) Navigate to a page with an image with src == "image.png".
4983 RenderFrameHostImpl* rfh_1 = NavigateToPageWithImage(
4984 embedded_test_server()->GetURL("a.com", "/title1.html"));
4985
4986 // Start sending response before the page gets in the back-forward cache.
4987 image_response.WaitForRequest();
4988 image_response.Send(net::HTTP_OK, "image/png");
4989 image_response.Send(" ");
4990 // Run some script to ensure the renderer processed its pending tasks.
4991 EXPECT_TRUE(ExecJs(rfh_1, "var foo = 42;"));
4992
4993 // 2) Navigate away.
4994 EXPECT_TRUE(NavigateToURL(
4995 shell(), embedded_test_server()->GetURL("b.com", "/title2.html")));
4996 // The page was still loading when we navigated away, but it's still eligible
4997 // for back-forward cache.
4998 EXPECT_TRUE(rfh_1->IsInBackForwardCache());
4999
5000 // Send the image response body while in the back-forward cache.
5001 RenderFrameDeletedObserver delete_observer(rfh_1);
Rakina Zata Amnibd10ef6d2021-01-19 02:50:115002 std::string body(kMaxBufferedBytesPerRequest + 1, '*');
Rakina Zata Amni525a2922020-12-03 12:28:155003 image_response.Send(body);
5004 image_response.Done();
5005 delete_observer.WaitUntilDeleted();
5006
5007 // 3) Go back to the first page. We should not restore the page from the
5008 // back-forward cache.
5009 web_contents()->GetController().GoBack();
5010 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
Yuzu Saijo73fa301222020-12-10 09:33:515011 ExpectNotRestored(
5012 {BackForwardCacheMetrics::NotRestoredReason::kNetworkExceedsBufferLimit},
Fergal Daly6755cbf2021-02-12 03:06:585013 {}, {}, {}, FROM_HERE);
Rakina Zata Amni525a2922020-12-03 12:28:155014}
5015
Rakina Zata Amnibd10ef6d2021-01-19 02:50:115016IN_PROC_BROWSER_TEST_F(
Yuzu Saijo6ddce412021-08-17 05:09:155017 BackForwardCacheBrowserTest,
Rakina Zata Amnibd10ef6d2021-01-19 02:50:115018 ImageStillLoading_ResponseStartedBeforeFreezing_ExceedsPerProcessBytesLimit) {
5019 net::test_server::ControllableHttpResponse image1_response(
5020 embedded_test_server(), "/image1.png");
5021 net::test_server::ControllableHttpResponse image2_response(
5022 embedded_test_server(), "/image2.png");
5023 ASSERT_TRUE(embedded_test_server()->Start());
5024
5025 // 1) Navigate to a page with 2 images.
5026 EXPECT_TRUE(NavigateToURL(
5027 shell(), embedded_test_server()->GetURL("a.com", "/title1.html")));
5028 RenderFrameHostImpl* rfh_1 = current_frame_host();
5029 // Wait for the document to load DOM to ensure that kLoading is not
5030 // one of the reasons why the document wasn't cached.
5031 WaitForDOMContentLoaded(rfh_1);
5032
5033 EXPECT_TRUE(ExecJs(rfh_1, R"(
5034 var image1 = document.createElement("img");
5035 image1.src = "image1.png";
5036 document.body.appendChild(image1);
5037 var image2 = document.createElement("img");
5038 image2.src = "image2.png";
5039 document.body.appendChild(image1);
5040
5041 var image1_load_status = new Promise((resolve, reject) => {
5042 image1.onload = () => { resolve("loaded"); }
5043 image1.onerror = () => { resolve("error"); }
5044 });
5045
5046 var image2_load_status = new Promise((resolve, reject) => {
5047 image2.onload = () => { resolve("loaded"); }
5048 image2.onerror = () => { resolve("error"); }
5049 });
5050 )"));
5051
5052 // Wait for the image requests, but don't send anything yet.
5053
5054 // Start sending response before the page gets in the back-forward cache.
5055 image1_response.WaitForRequest();
5056 image1_response.Send(net::HTTP_OK, "image/png");
5057 image1_response.Send(" ");
5058 image2_response.WaitForRequest();
5059 image2_response.Send(net::HTTP_OK, "image/png");
5060 image2_response.Send(" ");
5061 // Run some script to ensure the renderer processed its pending tasks.
5062 EXPECT_TRUE(ExecJs(rfh_1, "var foo = 42;"));
5063
5064 // 2) Navigate away.
5065 EXPECT_TRUE(NavigateToURL(
5066 shell(), embedded_test_server()->GetURL("b.com", "/title2.html")));
5067 // The page was still loading when we navigated away, but it's still eligible
5068 // for back-forward cache.
5069 EXPECT_TRUE(rfh_1->IsInBackForwardCache());
5070
5071 RenderFrameDeletedObserver delete_observer(rfh_1);
5072 // Send the image response body while in the back-forward cache. The body size
5073 // of the responses individually is less than the per-request limit, but
5074 // together they surpass the per-process limit.
5075 const int image_body_size = kMaxBufferedBytesPerProcess / 2 + 1;
5076 DCHECK_LT(image_body_size, kMaxBufferedBytesPerRequest);
5077 std::string body(image_body_size, '*');
5078 image1_response.Send(body);
5079 image1_response.Done();
5080 image2_response.Send(body);
5081 image2_response.Done();
5082 delete_observer.WaitUntilDeleted();
5083
5084 // 3) Go back to the first page. We should not restore the page from the
5085 // back-forward cache.
5086 web_contents()->GetController().GoBack();
5087 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
Rakina Zata Amnibd10ef6d2021-01-19 02:50:115088 ExpectNotRestored(
5089 {BackForwardCacheMetrics::NotRestoredReason::kNetworkExceedsBufferLimit},
Fergal Daly6755cbf2021-02-12 03:06:585090 {}, {}, {}, FROM_HERE);
Rakina Zata Amnibd10ef6d2021-01-19 02:50:115091}
5092
Yuzu Saijo6ddce412021-08-17 05:09:155093IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
Rakina Zata Amni6e599ec2020-12-14 03:16:185094 TimeoutNotTriggeredAfterDone) {
5095 net::test_server::ControllableHttpResponse image_response(
5096 embedded_test_server(), "/image.png");
5097 ASSERT_TRUE(embedded_test_server()->Start());
5098 // 1) Navigate to a page with an image with src == "image.png".
5099 RenderFrameHostImpl* rfh_1 = NavigateToPageWithImage(
5100 embedded_test_server()->GetURL("a.com", "/title1.html"));
5101
5102 // Wait for the image request, but don't send anything yet.
5103 image_response.WaitForRequest();
5104
5105 // 2) Navigate away.
5106 EXPECT_TRUE(NavigateToURL(
5107 shell(), embedded_test_server()->GetURL("b.com", "/title2.html")));
5108 // The page was still loading when we navigated away, but it's still eligible
5109 // for back-forward cache.
5110 EXPECT_TRUE(rfh_1->IsInBackForwardCache());
5111
5112 RenderFrameDeletedObserver delete_observer(rfh_1);
5113 // Start sending the image response while in the back-forward cache and finish
5114 // the request before the active request timeout hits.
5115 image_response.Send(net::HTTP_OK, "image/png");
5116 image_response.Send(" ");
5117 image_response.Done();
5118
5119 // Make sure enough time passed to trigger network request eviction if the
5120 // load above didn't finish.
5121 base::RunLoop run_loop;
5122 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
5123 FROM_HERE, run_loop.QuitClosure(),
5124 kGracePeriodToFinishLoading + base::TimeDelta::FromSeconds(1));
5125 run_loop.Run();
5126
5127 // Ensure that the page is still in bfcache.
5128 EXPECT_FALSE(delete_observer.deleted());
5129 EXPECT_TRUE(rfh_1->IsInBackForwardCache());
5130
5131 // 3) Go back to the first page. We should restore the page from the
5132 // back-forward cache.
5133 web_contents()->GetController().GoBack();
5134 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
Fergal Daly09833062021-02-09 07:10:005135 ExpectRestored(FROM_HERE);
Rakina Zata Amni6e599ec2020-12-14 03:16:185136}
5137
5138IN_PROC_BROWSER_TEST_F(
Yuzu Saijo6ddce412021-08-17 05:09:155139 BackForwardCacheBrowserTest,
Rakina Zata Amni6e599ec2020-12-14 03:16:185140 TimeoutNotTriggeredAfterDone_ResponseStartedBeforeFreezing) {
5141 net::test_server::ControllableHttpResponse image_response(
5142 embedded_test_server(), "/image.png");
5143 ASSERT_TRUE(embedded_test_server()->Start());
5144 // 1) Navigate to a page with an image with src == "image.png".
5145 RenderFrameHostImpl* rfh_1 = NavigateToPageWithImage(
5146 embedded_test_server()->GetURL("a.com", "/title1.html"));
5147
5148 // Start sending response before the page gets in the back-forward cache.
5149 image_response.WaitForRequest();
5150 image_response.Send(net::HTTP_OK, "image/png");
5151 image_response.Send(" ");
5152
5153 // 2) Navigate away.
5154 EXPECT_TRUE(NavigateToURL(
5155 shell(), embedded_test_server()->GetURL("b.com", "/title2.html")));
5156 // The page was still loading when we navigated away, but it's still eligible
5157 // for back-forward cache.
5158 EXPECT_TRUE(rfh_1->IsInBackForwardCache());
5159
5160 RenderFrameDeletedObserver delete_observer(rfh_1);
5161 // Finish the request before the active request timeout hits.
5162 image_response.Done();
5163
5164 // Make sure enough time passed to trigger network request eviction if the
5165 // load above didn't finish.
5166 base::RunLoop run_loop;
5167 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
5168 FROM_HERE, run_loop.QuitClosure(),
5169 kGracePeriodToFinishLoading + base::TimeDelta::FromSeconds(1));
5170 run_loop.Run();
5171
5172 // Ensure that the page is still in bfcache.
5173 EXPECT_FALSE(delete_observer.deleted());
5174 EXPECT_TRUE(rfh_1->IsInBackForwardCache());
5175
5176 // 3) Go back to the first page. We should restore the page from the
5177 // back-forward cache.
5178 web_contents()->GetController().GoBack();
5179 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
Fergal Daly09833062021-02-09 07:10:005180 ExpectRestored(FROM_HERE);
Rakina Zata Amni6e599ec2020-12-14 03:16:185181}
5182
Yuzu Saijo6ddce412021-08-17 05:09:155183IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
Rakina Zata Amni6e599ec2020-12-14 03:16:185184 ImageStillLoading_ResponseStartedBeforeFreezing) {
5185 net::test_server::ControllableHttpResponse image_response(
5186 embedded_test_server(), "/image.png");
5187 ASSERT_TRUE(embedded_test_server()->Start());
5188
5189 // 1) Navigate to a page with an image with src == "image.png".
5190 RenderFrameHostImpl* rfh_1 = NavigateToPageWithImage(
5191 embedded_test_server()->GetURL("a.com", "/title1.html"));
5192
5193 // Start sending response before the page gets in the back-forward cache.
5194 image_response.WaitForRequest();
5195 image_response.Send(net::HTTP_OK, "image/png");
5196 image_response.Send(" ");
5197 // Run some script to ensure the renderer processed its pending tasks.
5198 EXPECT_TRUE(ExecJs(rfh_1, "var foo = 42;"));
5199
5200 // 2) Navigate away.
5201 EXPECT_TRUE(NavigateToURL(
5202 shell(), embedded_test_server()->GetURL("b.com", "/title2.html")));
5203 // The page was still loading when we navigated away, but it's still eligible
5204 // for back-forward cache.
5205 EXPECT_TRUE(rfh_1->IsInBackForwardCache());
5206
5207 // Send body while in the back-forward cache.
5208 image_response.Send("image_body");
5209 image_response.Done();
5210
5211 // 3) Go back to the first page. We should restore the page from the
5212 // back-forward cache.
5213 web_contents()->GetController().GoBack();
5214 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
Fergal Daly09833062021-02-09 07:10:005215 ExpectRestored(FROM_HERE);
Rakina Zata Amni6e599ec2020-12-14 03:16:185216
5217 // Wait until the deferred body is processed. Since it's not a valid image
5218 // value, we'll get the "error" event.
5219 EXPECT_EQ("error", EvalJs(rfh_1, "image_load_status"));
5220}
5221
Kouhei Ueno0cf9a1a2019-11-19 10:03:585222// Disabled on Android, since we have problems starting up the websocket test
5223// server in the host
kouhei2a91acc2021-05-24 06:32:265224#if defined(OS_ANDROID)
Kouhei Ueno0cf9a1a2019-11-19 10:03:585225#define MAYBE_WebSocketNotCached DISABLED_WebSocketNotCached
5226#else
5227#define MAYBE_WebSocketNotCached WebSocketNotCached
5228#endif
5229IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, MAYBE_WebSocketNotCached) {
5230 net::SpawnedTestServer ws_server(net::SpawnedTestServer::TYPE_WS,
5231 net::GetWebSocketTestDataDirectory());
5232 ASSERT_TRUE(ws_server.Start());
5233
5234 ASSERT_TRUE(embedded_test_server()->Start());
5235
5236 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
5237 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
5238
5239 // 1) Navigate to A.
5240 ASSERT_TRUE(NavigateToURL(shell(), url_a));
5241 RenderFrameHostImpl* rfh_a = current_frame_host();
5242 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
5243
5244 // Open a WebSocket.
5245 const char script[] = R"(
5246 new Promise(resolve => {
5247 const socket = new WebSocket($1);
5248 socket.addEventListener('open', () => resolve());
5249 });)";
5250 ASSERT_TRUE(ExecJs(
5251 rfh_a, JsReplace(script, ws_server.GetURL("echo-with-no-extension"))));
5252
5253 // 2) Navigate to B.
5254 ASSERT_TRUE(NavigateToURL(shell(), url_b));
5255
Kouhei Ueno763b7d52019-11-20 06:08:105256 // Confirm A is evicted.
5257 delete_observer_rfh_a.WaitUntilDeleted();
Kouhei Ueno0cf9a1a2019-11-19 10:03:585258}
5259
arthursonzognie385b7b2019-09-02 11:11:535260// Only HTTP/HTTPS main document can enter the BackForwardCache.
5261IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, CacheHTTPDocumentOnly) {
5262 ASSERT_TRUE(embedded_test_server()->Start());
Fergal Daly637c4522019-11-22 00:21:315263 ASSERT_TRUE(CreateHttpsServer()->Start());
arthursonzognie385b7b2019-09-02 11:11:535264
5265 GURL http_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
Fergal Daly637c4522019-11-22 00:21:315266 GURL https_url(https_server()->GetURL("a.com", "/title1.html"));
arthursonzognie385b7b2019-09-02 11:11:535267 GURL file_url = net::FilePathToFileURL(GetTestFilePath("", "title1.html"));
5268 GURL data_url = GURL("data:text/html,");
5269 GURL blank_url = GURL(url::kAboutBlankURL);
5270 GURL webui_url = GetWebUIURL("gpu");
5271
5272 enum { STORED, DELETED };
5273 struct {
5274 int expectation;
5275 GURL url;
5276 } test_cases[] = {
5277 // Only document with HTTP/HTTPS URLs are allowed to enter the
5278 // BackForwardCache.
5279 {STORED, http_url},
5280 {STORED, https_url},
5281
5282 // Others aren't allowed.
5283 {DELETED, file_url},
5284 {DELETED, data_url},
5285 {DELETED, webui_url},
5286 {DELETED, blank_url},
5287 };
5288
5289 char hostname[] = "a.unique";
5290 for (auto& test_case : test_cases) {
5291 SCOPED_TRACE(testing::Message()
5292 << std::endl
5293 << "expectation = " << test_case.expectation << std::endl
5294 << "url = " << test_case.url << std::endl);
5295
5296 // 1) Navigate to.
5297 EXPECT_TRUE(NavigateToURL(shell(), test_case.url));
Rakina Zata Amni348fe2b2021-07-09 05:28:525298 RenderFrameHostImplWrapper rfh(current_frame_host());
arthursonzognie385b7b2019-09-02 11:11:535299
5300 // 2) Navigate away.
5301 hostname[0]++;
5302 GURL reset_url(embedded_test_server()->GetURL(hostname, "/title1.html"));
5303 EXPECT_TRUE(NavigateToURL(shell(), reset_url));
5304
5305 if (test_case.expectation == STORED) {
Rakina Zata Amni348fe2b2021-07-09 05:28:525306 EXPECT_FALSE(rfh.IsRenderFrameDeleted());
Hajime Hoshibbc509c2020-04-06 08:55:085307 EXPECT_TRUE(rfh->IsInBackForwardCache());
arthursonzognie385b7b2019-09-02 11:11:535308 continue;
5309 }
5310
Rakina Zata Amni348fe2b2021-07-09 05:28:525311 if (rfh.get() == current_frame_host()) {
5312 // If the RenderFrameHost is reused, it won't be deleted, so don't wait
5313 // for deletion. Just check that it's not saved in the back-forward cache.
5314 EXPECT_FALSE(rfh.IsRenderFrameDeleted());
Hajime Hoshibbc509c2020-04-06 08:55:085315 EXPECT_FALSE(rfh->IsInBackForwardCache());
arthursonzognie385b7b2019-09-02 11:11:535316 continue;
5317 }
5318
Rakina Zata Amni348fe2b2021-07-09 05:28:525319 // When the RenderFrameHost is not reused and it's not stored in the
5320 // back-forward cache, it will eventually be deleted.
5321 rfh.WaitUntilRenderFrameDeleted();
arthursonzognie385b7b2019-09-02 11:11:535322 }
5323}
5324
Alexander Timin8304ddd942019-09-02 15:53:595325namespace {
5326
5327void RegisterServiceWorker(RenderFrameHostImpl* rfh) {
5328 EXPECT_EQ("success", EvalJs(rfh, R"(
5329 let controller_changed_promise = new Promise(resolve_controller_change => {
5330 navigator.serviceWorker.oncontrollerchange = resolve_controller_change;
5331 });
5332
5333 new Promise(async resolve => {
5334 try {
5335 await navigator.serviceWorker.register(
5336 "./service-worker.js", {scope: "./"})
5337 } catch (e) {
5338 resolve("error: registration has failed");
5339 }
5340
5341 await controller_changed_promise;
5342
5343 if (navigator.serviceWorker.controller) {
5344 resolve("success");
5345 } else {
5346 resolve("error: not controlled by service worker");
5347 }
5348 });
5349 )"));
5350}
5351
Yuzu Saijo6a935bbd2019-11-01 16:31:385352// Returns a unique script for each request, to test service worker update.
5353std::unique_ptr<net::test_server::HttpResponse> RequestHandlerForUpdateWorker(
5354 const net::test_server::HttpRequest& request) {
5355 if (request.relative_url != "/back_forward_cache/service-worker.js")
Lei Zhangdf291f62021-04-14 17:23:445356 return nullptr;
Yuzu Saijo6a935bbd2019-11-01 16:31:385357 static int counter = 0;
5358 auto http_response = std::make_unique<net::test_server::BasicHttpResponse>();
5359 http_response->set_code(net::HTTP_OK);
5360 const char script[] = R"(
5361 // counter = $1
5362 self.addEventListener('activate', function(event) {
5363 event.waitUntil(self.clients.claim());
5364 });
5365 )";
5366 http_response->set_content(JsReplace(script, counter++));
5367 http_response->set_content_type("text/javascript");
5368 http_response->AddCustomHeader("Cache-Control",
5369 "no-cache, no-store, must-revalidate");
5370 return http_response;
5371}
5372
Alexander Timin8304ddd942019-09-02 15:53:595373} // namespace
5374
Yuzu Saijo698e4342020-04-06 03:12:055375class BackForwardCacheBrowserTestWithVibration
5376 : public BackForwardCacheBrowserTest,
5377 public device::mojom::VibrationManager {
5378 public:
5379 BackForwardCacheBrowserTestWithVibration() {
5380 OverrideVibrationManagerBinderForTesting(base::BindRepeating(
5381 &BackForwardCacheBrowserTestWithVibration::BindVibrationManager,
5382 base::Unretained(this)));
5383 }
5384
5385 ~BackForwardCacheBrowserTestWithVibration() override {
5386 OverrideVibrationManagerBinderForTesting(base::NullCallback());
5387 }
5388
5389 void BindVibrationManager(
5390 mojo::PendingReceiver<device::mojom::VibrationManager> receiver) {
5391 receiver_.Bind(std::move(receiver));
5392 }
5393
5394 bool TriggerVibrate(RenderFrameHostImpl* rfh,
5395 int duration,
5396 base::OnceClosure vibrate_done) {
5397 vibrate_done_ = std::move(vibrate_done);
Avi Drissmanc91bd8e2021-04-19 23:58:445398 return EvalJs(rfh, JsReplace("navigator.vibrate($1)", duration))
5399 .ExtractBool();
Yuzu Saijo698e4342020-04-06 03:12:055400 }
5401
5402 bool TriggerShortVibrationSequence(RenderFrameHostImpl* rfh,
5403 base::OnceClosure vibrate_done) {
5404 vibrate_done_ = std::move(vibrate_done);
Avi Drissmanc91bd8e2021-04-19 23:58:445405 return EvalJs(rfh, "navigator.vibrate([10] * 1000)").ExtractBool();
Yuzu Saijo698e4342020-04-06 03:12:055406 }
5407
5408 bool IsCancelled() { return cancelled_; }
5409
5410 private:
5411 // device::mojom::VibrationManager:
5412 void Vibrate(int64_t milliseconds, VibrateCallback callback) override {
5413 cancelled_ = false;
5414 std::move(callback).Run();
5415 std::move(vibrate_done_).Run();
5416 }
5417
5418 void Cancel(CancelCallback callback) override {
5419 cancelled_ = true;
5420 std::move(callback).Run();
5421 }
5422
5423 bool cancelled_ = false;
5424 base::OnceClosure vibrate_done_;
5425 mojo::Receiver<device::mojom::VibrationManager> receiver_{this};
5426};
5427
5428IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTestWithVibration,
5429 VibrationStopsAfterEnteringCache) {
5430 ASSERT_TRUE(embedded_test_server()->Start());
5431
5432 // 1) Navigate to a page with a long vibration.
5433 GURL url(embedded_test_server()->GetURL("a.com", "/title1.html"));
5434 EXPECT_TRUE(NavigateToURL(shell(), url));
5435 base::RunLoop run_loop;
5436 RenderFrameHostImpl* rfh_a = current_frame_host();
5437 ASSERT_TRUE(TriggerVibrate(rfh_a, 10000, run_loop.QuitClosure()));
5438 EXPECT_FALSE(IsCancelled());
5439
5440 // 2) Navigate away and expect the vibration to be canceled.
5441 EXPECT_TRUE(NavigateToURL(
5442 shell(), embedded_test_server()->GetURL("b.com", "/title1.html")));
5443 EXPECT_NE(current_frame_host(), rfh_a);
Hajime Hoshibbc509c2020-04-06 08:55:085444 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
Yuzu Saijo698e4342020-04-06 03:12:055445 EXPECT_TRUE(IsCancelled());
5446
5447 // 3) Go back to A.
5448 web_contents()->GetController().GoBack();
5449 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
Fergal Daly09833062021-02-09 07:10:005450 ExpectRestored(FROM_HERE);
Yuzu Saijo698e4342020-04-06 03:12:055451}
5452
5453IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTestWithVibration,
5454 ShortVibrationSequenceStopsAfterEnteringCache) {
5455 ASSERT_TRUE(embedded_test_server()->Start());
5456
5457 // 1) Navigate to a page with a long vibration.
5458 GURL url(embedded_test_server()->GetURL("a.com", "/title1.html"));
5459 EXPECT_TRUE(NavigateToURL(shell(), url));
5460 base::RunLoop run_loop;
5461 RenderFrameHostImpl* rfh_a = current_frame_host();
5462 ASSERT_TRUE(TriggerShortVibrationSequence(rfh_a, run_loop.QuitClosure()));
5463 EXPECT_FALSE(IsCancelled());
5464
5465 // 2) Navigate away and expect the vibration to be canceled.
5466 EXPECT_TRUE(NavigateToURL(
5467 shell(), embedded_test_server()->GetURL("b.com", "/title1.html")));
5468 EXPECT_NE(current_frame_host(), rfh_a);
Hajime Hoshibbc509c2020-04-06 08:55:085469 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
Yuzu Saijo698e4342020-04-06 03:12:055470 EXPECT_TRUE(IsCancelled());
5471
5472 // 3) Go back to A.
5473 web_contents()->GetController().GoBack();
5474 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
Fergal Daly09833062021-02-09 07:10:005475 ExpectRestored(FROM_HERE);
Yuzu Saijo698e4342020-04-06 03:12:055476}
5477
Darren W233c1022021-06-18 03:48:155478IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
Alexander Timin8304ddd942019-09-02 15:53:595479 CachedPagesWithServiceWorkers) {
Fergal Daly637c4522019-11-22 00:21:315480 CreateHttpsServer();
5481 SetupCrossSiteRedirector(https_server());
5482 ASSERT_TRUE(https_server()->Start());
Alexander Timin8304ddd942019-09-02 15:53:595483
5484 // 1) Navigate to A.
5485 EXPECT_TRUE(NavigateToURL(
Fergal Daly637c4522019-11-22 00:21:315486 shell(),
5487 https_server()->GetURL("a.com", "/back_forward_cache/empty.html")));
Alexander Timin8304ddd942019-09-02 15:53:595488
5489 // Register a service worker.
5490 RegisterServiceWorker(current_frame_host());
5491
5492 RenderFrameHostImpl* rfh_a = current_frame_host();
5493 RenderFrameDeletedObserver deleted(rfh_a);
5494
5495 // 2) Navigate away.
5496 EXPECT_TRUE(
Fergal Daly637c4522019-11-22 00:21:315497 NavigateToURL(shell(), https_server()->GetURL("b.com", "/title1.html")));
Alexander Timin8304ddd942019-09-02 15:53:595498
5499 EXPECT_FALSE(deleted.deleted());
Hajime Hoshibbc509c2020-04-06 08:55:085500 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
Alexander Timin8304ddd942019-09-02 15:53:595501
5502 // 3) Go back to A. The navigation should be served from the cache.
5503 web_contents()->GetController().GoBack();
5504 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
5505 EXPECT_FALSE(deleted.deleted());
5506 EXPECT_EQ(rfh_a, current_frame_host());
5507}
5508
Darren W233c1022021-06-18 03:48:155509IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
Yuzu Saijo6a935bbd2019-11-01 16:31:385510 EvictIfCacheBlocksServiceWorkerVersionActivation) {
Fergal Daly637c4522019-11-22 00:21:315511 CreateHttpsServer();
5512 https_server()->RegisterRequestHandler(
Yuzu Saijo6a935bbd2019-11-01 16:31:385513 base::BindRepeating(&RequestHandlerForUpdateWorker));
Fergal Daly637c4522019-11-22 00:21:315514 SetupCrossSiteRedirector(https_server());
5515 ASSERT_TRUE(https_server()->Start());
Yuzu Saijo6a935bbd2019-11-01 16:31:385516 Shell* tab_x = shell();
5517 Shell* tab_y = CreateBrowser();
5518 // 1) Navigate to A in tab X.
5519 EXPECT_TRUE(NavigateToURL(
Fergal Daly637c4522019-11-22 00:21:315520 tab_x,
5521 https_server()->GetURL("a.com", "/back_forward_cache/empty.html")));
Yuzu Saijo6a935bbd2019-11-01 16:31:385522 // 2) Register a service worker.
5523 RegisterServiceWorker(current_frame_host());
5524
5525 RenderFrameHostImpl* rfh_a = current_frame_host();
5526 RenderFrameDeletedObserver deleted(rfh_a);
5527 // 3) Navigate away to B in tab X.
5528 EXPECT_TRUE(
Fergal Daly637c4522019-11-22 00:21:315529 NavigateToURL(tab_x, https_server()->GetURL("b.com", "/title1.html")));
Yuzu Saijo6a935bbd2019-11-01 16:31:385530 EXPECT_FALSE(deleted.deleted());
Hajime Hoshibbc509c2020-04-06 08:55:085531 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
Yuzu Saijo6a935bbd2019-11-01 16:31:385532 // 4) Navigate to A in tab Y.
5533 EXPECT_TRUE(NavigateToURL(
Fergal Daly637c4522019-11-22 00:21:315534 tab_y,
5535 https_server()->GetURL("a.com", "/back_forward_cache/empty.html")));
Yuzu Saijo6a935bbd2019-11-01 16:31:385536 // 5) Close tab Y to activate a service worker version.
5537 // This should evict |rfh_a| from the cache.
5538 tab_y->Close();
5539 deleted.WaitUntilDeleted();
5540 // 6) Navigate to A in tab X.
5541 tab_x->web_contents()->GetController().GoBack();
5542 EXPECT_TRUE(WaitForLoadStop(tab_x->web_contents()));
Yuzu Saijo6a935bbd2019-11-01 16:31:385543 ExpectNotRestored(
5544 {
5545 BackForwardCacheMetrics::NotRestoredReason::
5546 kServiceWorkerVersionActivation,
5547 },
Fergal Daly6755cbf2021-02-12 03:06:585548 {}, {}, {}, FROM_HERE);
Yuzu Saijo6a935bbd2019-11-01 16:31:385549}
5550
Darren W233c1022021-06-18 03:48:155551IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
Yuzu Saijoa01e4192019-11-27 04:58:185552 EvictWithPostMessageToCachedClient) {
5553 net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS);
5554 https_server.RegisterRequestHandler(
5555 base::BindRepeating(&RequestHandlerForUpdateWorker));
5556 https_server.AddDefaultHandlers(GetTestDataFilePath());
5557 https_server.SetSSLConfig(net::EmbeddedTestServer::CERT_OK);
5558 SetupCrossSiteRedirector(&https_server);
5559 ASSERT_TRUE(https_server.Start());
5560 Shell* tab_to_execute_service_worker = shell();
5561 Shell* tab_to_be_bfcached = CreateBrowser();
5562
Hajime Hoshi765845d62020-02-21 02:56:215563 // Observe the new WebContents to trace the navigtion ID.
5564 WebContentsObserver::Observe(tab_to_be_bfcached->web_contents());
5565
Yuzu Saijoa01e4192019-11-27 04:58:185566 // 1) Navigate to A in |tab_to_execute_service_worker|.
5567 EXPECT_TRUE(NavigateToURL(
5568 tab_to_execute_service_worker,
5569 https_server.GetURL(
5570 "a.com", "/back_forward_cache/service_worker_post_message.html")));
5571
5572 // 2) Register a service worker.
5573 EXPECT_EQ("DONE", EvalJs(tab_to_execute_service_worker,
5574 "register('service_worker_post_message.js')"));
5575
5576 // 3) Navigate to A in |tab_to_be_bfcached|.
5577 EXPECT_TRUE(NavigateToURL(
5578 tab_to_be_bfcached,
5579 https_server.GetURL(
5580 "a.com", "/back_forward_cache/service_worker_post_message.html")));
5581 const std::string script_to_store =
5582 "executeCommandOnServiceWorker('StoreClients')";
5583 EXPECT_EQ("DONE", EvalJs(tab_to_execute_service_worker, script_to_store));
Fergal Daly30507e62021-07-01 02:51:315584 RenderFrameHostImplWrapper rfh(
Fergal Daly225adc12021-05-25 02:58:395585 tab_to_be_bfcached->web_contents()->GetMainFrame());
Yuzu Saijoa01e4192019-11-27 04:58:185586
5587 // 4) Navigate away to B in |tab_to_be_bfcached|.
5588 EXPECT_TRUE(NavigateToURL(tab_to_be_bfcached,
5589 https_server.GetURL("b.com", "/title1.html")));
Fergal Daly225adc12021-05-25 02:58:395590 EXPECT_FALSE(rfh.IsDestroyed());
Hajime Hoshibbc509c2020-04-06 08:55:085591 EXPECT_TRUE(rfh->IsInBackForwardCache());
Yuzu Saijoa01e4192019-11-27 04:58:185592
5593 // 5) Trigger client.postMessage via |tab_to_execute_service_worker|. Cache in
5594 // |tab_to_be_bfcached| will be evicted.
5595 const std::string script_to_post_message =
5596 "executeCommandOnServiceWorker('PostMessageToStoredClients')";
5597 EXPECT_EQ("DONE",
5598 EvalJs(tab_to_execute_service_worker, script_to_post_message));
Fergal Daly225adc12021-05-25 02:58:395599 rfh.WaitUntilRenderFrameDeleted();
Yuzu Saijoa01e4192019-11-27 04:58:185600
5601 // 6) Go back to A in |tab_to_be_bfcached|.
5602 tab_to_be_bfcached->web_contents()->GetController().GoBack();
5603 EXPECT_TRUE(WaitForLoadStop(tab_to_be_bfcached->web_contents()));
Yuzu Saijoa01e4192019-11-27 04:58:185604 ExpectNotRestored(
5605 {BackForwardCacheMetrics::NotRestoredReason::kServiceWorkerPostMessage},
Fergal Daly6755cbf2021-02-12 03:06:585606 {}, {}, {}, FROM_HERE);
Yuzu Saijoa01e4192019-11-27 04:58:185607}
5608
Darren W233c1022021-06-18 03:48:155609IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, EvictOnServiceWorkerClaim) {
Yuzu Saijo602ff7c2019-12-19 04:41:005610 net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS);
5611 https_server.RegisterRequestHandler(
5612 base::BindRepeating(&RequestHandlerForUpdateWorker));
5613 https_server.AddDefaultHandlers(GetTestDataFilePath());
5614 https_server.SetSSLConfig(net::EmbeddedTestServer::CERT_OK);
5615 SetupCrossSiteRedirector(&https_server);
5616 ASSERT_TRUE(https_server.Start());
5617
5618 Shell* tab_to_be_bfcached = shell();
5619 Shell* tab_to_execute_service_worker = CreateBrowser();
5620
5621 // 1) Navigate to A in |tab_to_be_bfcached|.
5622 EXPECT_TRUE(NavigateToURL(
5623 tab_to_be_bfcached,
5624 https_server.GetURL(
5625 "a.com", "/back_forward_cache/service_worker_registration.html")));
5626 RenderFrameHostImpl* rfh_a = current_frame_host();
5627 RenderFrameDeletedObserver deleted(rfh_a);
5628
5629 // 2) Navigate away to B in |tab_to_be_bfcached|.
5630 EXPECT_TRUE(NavigateToURL(tab_to_be_bfcached,
5631 https_server.GetURL("b.com", "/title1.html")));
5632 EXPECT_FALSE(deleted.deleted());
Hajime Hoshibbc509c2020-04-06 08:55:085633 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
Yuzu Saijo602ff7c2019-12-19 04:41:005634
5635 // 3) Navigate to A in |tab_to_execute_service_worker|.
5636 EXPECT_TRUE(NavigateToURL(
5637 tab_to_execute_service_worker,
5638 https_server.GetURL(
5639 "a.com", "/back_forward_cache/service_worker_registration.html")));
5640
5641 // 4) Register a service worker for |tab_to_execute_service_worker|.
Yuzu Saijo602ff7c2019-12-19 04:41:005642 EXPECT_EQ("DONE", EvalJs(tab_to_execute_service_worker,
5643 "register('service_worker_registration.js')"));
Yuzu Saijo012ada72020-01-06 06:54:145644
5645 // 5) The service worker calls clients.claim(). |rfh_a| would normally be
5646 // claimed but because it's in bfcache, it is evicted from the cache.
Yuzu Saijo2c848d0a2019-12-24 02:48:405647 EXPECT_EQ("DONE", EvalJs(tab_to_execute_service_worker, "claim()"));
Yuzu Saijo602ff7c2019-12-19 04:41:005648
Yuzu Saijo012ada72020-01-06 06:54:145649 // 6) Navigate to A in |tab_to_be_bfcached|.
Yuzu Saijo602ff7c2019-12-19 04:41:005650 tab_to_be_bfcached->web_contents()->GetController().GoBack();
5651 EXPECT_TRUE(WaitForLoadStop(tab_to_be_bfcached->web_contents()));
5652 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
Yuzu Saijo012ada72020-01-06 06:54:145653 EXPECT_TRUE(deleted.deleted());
Yuzu Saijo012ada72020-01-06 06:54:145654 ExpectNotRestored(
Fergal Daly6755cbf2021-02-12 03:06:585655 {BackForwardCacheMetrics::NotRestoredReason::kServiceWorkerClaim}, {}, {},
5656 {}, FROM_HERE);
Yuzu Saijo602ff7c2019-12-19 04:41:005657}
5658
Darren W233c1022021-06-18 03:48:155659IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
Yuzu Saijobc69a5d2021-06-15 09:30:545660 EvictOnServiceWorkerUnregistration) {
5661 net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS);
5662 https_server.RegisterRequestHandler(
5663 base::BindRepeating(&RequestHandlerForUpdateWorker));
5664 https_server.AddDefaultHandlers(GetTestDataFilePath());
5665 https_server.SetSSLConfig(net::EmbeddedTestServer::CERT_OK);
5666 SetupCrossSiteRedirector(&https_server);
5667 ASSERT_TRUE(https_server.Start());
5668
5669 Shell* tab_to_be_bfcached = shell();
5670 Shell* tab_to_unregister_service_worker = CreateBrowser();
5671
5672 // 1) Navigate to A in |tab_to_be_bfcached|. This tab will be controlled by a
5673 // service worker.
5674 EXPECT_TRUE(NavigateToURL(
5675 tab_to_be_bfcached,
5676 https_server.GetURL("a.com",
5677 "/back_forward_cache/"
5678 "service_worker_registration.html?to_be_bfcached")));
5679
5680 // 2) Register a service worker for |tab_to_be_bfcached|, but with a narrow
5681 // scope with URL param. This is to prevent |tab_to_unregister_service_worker|
5682 // from being controlled by the service worker.
5683 EXPECT_EQ("DONE",
5684 EvalJs(tab_to_be_bfcached,
5685 "register('service_worker_registration.js', "
5686 "'service_worker_registration.html?to_be_bfcached')"));
5687 EXPECT_EQ("DONE", EvalJs(tab_to_be_bfcached, "claim()"));
5688 RenderFrameHostImpl* rfh_a = current_frame_host();
5689 RenderFrameDeletedObserver deleted(rfh_a);
5690
5691 // 3) Navigate to A in |tab_to_unregister_service_worker|. This tab is not
5692 // controlled by the service worker.
5693 EXPECT_TRUE(NavigateToURL(
5694 tab_to_unregister_service_worker,
5695 https_server.GetURL(
5696 "a.com", "/back_forward_cache/service_worker_registration.html")));
5697
5698 // 5) Navigate from A to B in |tab_to_be_bfcached|. Now |tab_to_be_bfcached|
5699 // should be in bfcache.
5700 EXPECT_TRUE(NavigateToURL(tab_to_be_bfcached,
5701 https_server.GetURL("b.com", "/title1.html")));
5702 EXPECT_FALSE(deleted.deleted());
5703 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
5704
5705 // 6) The service worker gets unregistered. Now |tab_to_be_bfcached| should be
5706 // notified of the unregistration and evicted from bfcache.
5707 EXPECT_EQ(
5708 "DONE",
5709 EvalJs(tab_to_unregister_service_worker,
5710 "unregister('service_worker_registration.html?to_be_bfcached')"));
5711
5712 // 7) Navigate back to A in |tab_to_be_bfcached|.
5713 tab_to_be_bfcached->web_contents()->GetController().GoBack();
5714 EXPECT_TRUE(WaitForLoadStop(tab_to_be_bfcached->web_contents()));
5715 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
5716 EXPECT_TRUE(deleted.deleted());
5717 ExpectNotRestored({BackForwardCacheMetrics::NotRestoredReason::
5718 kServiceWorkerUnregistration},
5719 {}, {}, {}, FROM_HERE);
5720}
5721
Kouhei Ueno60d52912019-09-03 10:47:155722IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, CachePagesWithBeacon) {
5723 constexpr char kKeepalivePath[] = "/keepalive";
5724
5725 net::test_server::ControllableHttpResponse keepalive(embedded_test_server(),
5726 kKeepalivePath);
5727 ASSERT_TRUE(embedded_test_server()->Start());
5728
5729 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
5730 GURL url_ping(embedded_test_server()->GetURL("a.com", kKeepalivePath));
5731
5732 // 1) Navigate to A.
5733 EXPECT_TRUE(NavigateToURL(shell(), url_a));
5734 RenderFrameHostImpl* rfh_a = current_frame_host();
5735 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
5736
5737 EXPECT_TRUE(
5738 ExecJs(shell(), JsReplace(R"(navigator.sendBeacon($1, "");)", url_ping)));
5739
5740 // 2) Navigate to B.
5741 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
5742 EXPECT_TRUE(NavigateToURL(shell(), url_b));
5743
5744 // Ensure that the keepalive request is sent.
5745 keepalive.WaitForRequest();
5746 // Don't actually send the response.
5747
5748 // Page A should be in the cache.
5749 EXPECT_FALSE(delete_observer_rfh_a.deleted());
Hajime Hoshibbc509c2020-04-06 08:55:085750 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
Kouhei Ueno60d52912019-09-03 10:47:155751}
5752
arthursonzogni6c27c3152019-09-12 08:00:575753// Regression test for https://crbug.com/993337.
Lowell Mannerscc67fc62019-10-18 10:21:475754//
5755// A note about sharing BrowsingInstances and the BackForwardCache:
5756//
5757// We should never keep around more than one main frame that belongs to the same
5758// BrowsingInstance. When swapping two pages, when one is stored in the
5759// back-forward cache or one is restored from it, the current code expects the
5760// two to live in different BrowsingInstances.
5761//
5762// History navigation can recreate a page with the same BrowsingInstance as the
5763// one stored in the back-forward cache. This case must to be handled. When it
5764// happens, the back-forward cache page is evicted.
5765//
5766// Since cache eviction is asynchronous, it's is possible for two main frames
5767// belonging to the same BrowsingInstance to be alive for a brief period of time
5768// (the new page being navigated to, and a page in the cache, until it is
5769// destroyed asynchronously via eviction).
5770//
5771// The test below tests that the brief period of time where two main frames are
5772// alive in the same BrowsingInstance does not cause anything to blow up.
Asami Doi5dd0f6b2021-08-23 08:27:045773
Titouan Rigoudy2a990bd2021-08-26 13:01:545774// TODO(crbug.com/1127979): Flaky on Linux and Windows
5775#if defined(OS_LINUX) || defined(OS_WIN)
Asami Doi5dd0f6b2021-08-23 08:27:045776#define MAYBE_NavigateToTwoPagesOnSameSite DISABLED_NavigateToTwoPagesOnSameSite
5777#else
5778#define MAYBE_NavigateToTwoPagesOnSameSite NavigateToTwoPagesOnSameSite
5779#endif
Lowell Mannersfa8d9222019-09-05 09:47:035780IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
Asami Doi5dd0f6b2021-08-23 08:27:045781 MAYBE_NavigateToTwoPagesOnSameSite) {
Lowell Mannersfa8d9222019-09-05 09:47:035782 ASSERT_TRUE(embedded_test_server()->Start());
5783 GURL url_a1(embedded_test_server()->GetURL("a.com", "/title1.html"));
5784 GURL url_a2(embedded_test_server()->GetURL("a.com", "/title2.html"));
Lowell Mannerscc67fc62019-10-18 10:21:475785 GURL url_b3(embedded_test_server()->GetURL("b.com", "/title1.html"));
Lowell Mannersfa8d9222019-09-05 09:47:035786
5787 // 1) Navigate to A1.
5788 EXPECT_TRUE(NavigateToURL(shell(), url_a1));
5789
5790 // 2) Navigate to A2.
5791 EXPECT_TRUE(NavigateToURL(shell(), url_a2));
5792 RenderFrameHostImpl* rfh_a2 = current_frame_host();
arthursonzogni6c27c3152019-09-12 08:00:575793 RenderFrameDeletedObserver delete_rfh_a2(current_frame_host());
Lowell Mannersfa8d9222019-09-05 09:47:035794
Lowell Mannerscc67fc62019-10-18 10:21:475795 // 3) Navigate to B3.
5796 EXPECT_TRUE(NavigateToURL(shell(), url_b3));
Hajime Hoshibbc509c2020-04-06 08:55:085797 EXPECT_TRUE(rfh_a2->IsInBackForwardCache());
Lowell Mannerscc67fc62019-10-18 10:21:475798 RenderFrameHostImpl* rfh_b3 = current_frame_host();
Lowell Mannersfa8d9222019-09-05 09:47:035799
5800 // 4) Do a history navigation back to A1.
Lowell Mannersfa8d9222019-09-05 09:47:035801 web_contents()->GetController().GoToIndex(0);
arthursonzogni6c27c3152019-09-12 08:00:575802 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
Hajime Hoshibbc509c2020-04-06 08:55:085803 EXPECT_TRUE(rfh_b3->IsInBackForwardCache());
arthursonzogni6c27c3152019-09-12 08:00:575804
Lowell Mannerscc67fc62019-10-18 10:21:475805 // Note that the frame for A1 gets created before A2 is deleted from the
5806 // cache, so there will be a brief period where two the main frames (A1 and
5807 // A2) are alive in the same BrowsingInstance/SiteInstance, at the same time.
5808 // That is the scenario this test is covering. This used to cause a CHECK,
5809 // because the two main frames shared a single RenderViewHost (no longer the
5810 // case after https://crrev.com/c/1833616).
5811
5812 // A2 should be evicted from the cache and asynchronously deleted, due to the
5813 // cache size limit (B3 took its place in the cache).
arthursonzogni6c27c3152019-09-12 08:00:575814 delete_rfh_a2.WaitUntilDeleted();
Lowell Mannersfa8d9222019-09-05 09:47:035815}
Kouhei Ueno7b6f3cd02019-09-09 04:48:505816
Lowell Mannerscc67fc62019-10-18 10:21:475817IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
5818 NavigateToTwoPagesOnSameSiteWithSubframes) {
5819 ASSERT_TRUE(embedded_test_server()->Start());
5820 // This test covers the same scenario as NavigateToTwoPagesOnSameSite, except
5821 // the pages contain subframes:
5822 // A1(B) -> A2(B(C)) -> D3 -> A1(B)
5823 //
5824 // The subframes shouldn't make a difference, so the expected behavior is the
5825 // same as NavigateToTwoPagesOnSameSite.
5826 GURL url_a1(embedded_test_server()->GetURL(
5827 "a.com", "/cross_site_iframe_factory.html?a(b)"));
5828 GURL url_a2(embedded_test_server()->GetURL(
5829 "a.com", "/cross_site_iframe_factory.html?a(b(c))"));
5830 GURL url_d3(embedded_test_server()->GetURL("d.com", "/title1.html"));
5831
5832 // 1) Navigate to A1(B).
5833 EXPECT_TRUE(NavigateToURL(shell(), url_a1));
5834
5835 // 2) Navigate to A2(B(C)).
5836 EXPECT_TRUE(NavigateToURL(shell(), url_a2));
5837 RenderFrameHostImpl* rfh_a2 = current_frame_host();
5838 RenderFrameDeletedObserver delete_rfh_a2(current_frame_host());
5839
5840 // 3) Navigate to D3.
5841 EXPECT_TRUE(NavigateToURL(shell(), url_d3));
Hajime Hoshibbc509c2020-04-06 08:55:085842 EXPECT_TRUE(rfh_a2->IsInBackForwardCache());
Lowell Mannerscc67fc62019-10-18 10:21:475843 RenderFrameHostImpl* rfh_d3 = current_frame_host();
5844
5845 // 4) Do a history navigation back to A1(B).
5846 web_contents()->GetController().GoToIndex(0);
5847 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
5848
5849 // D3 takes A2(B(C))'s place in the cache.
Hajime Hoshibbc509c2020-04-06 08:55:085850 EXPECT_TRUE(rfh_d3->IsInBackForwardCache());
Lowell Mannerscc67fc62019-10-18 10:21:475851 delete_rfh_a2.WaitUntilDeleted();
5852}
5853
Rakina Zata Amni95a2a91d2020-07-14 12:41:445854class BackForwardCacheBrowserTestWithSameSiteDisabled
5855 : public BackForwardCacheBrowserTest {
5856 public:
5857 BackForwardCacheBrowserTestWithSameSiteDisabled() = default;
5858 ~BackForwardCacheBrowserTestWithSameSiteDisabled() override = default;
5859
5860 protected:
5861 void SetUpCommandLine(base::CommandLine* command_line) override {
5862 same_site_back_forward_cache_enabled_ = false;
5863 DisableFeature(features::kProactivelySwapBrowsingInstance);
Rakina Zata Amnif77ee9b2021-07-15 16:39:165864 // Ensure that the bot flags won't override the same-site back/forward cache
5865 // disabling.
5866 DisableFeature(features::kBackForwardCacheSameSiteForBots);
Rakina Zata Amni95a2a91d2020-07-14 12:41:445867 BackForwardCacheBrowserTest::SetUpCommandLine(command_line);
5868 }
5869};
5870
5871IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTestWithSameSiteDisabled,
Lowell Mannerscc67fc62019-10-18 10:21:475872 ConflictingBrowsingInstances) {
Rakina Zata Amni95a2a91d2020-07-14 12:41:445873 // This test assumes navigation from A1 to A2 will not switch
5874 // BrowsingInstances, which is not true when either BackForwardCache or
5875 // ProactivelySwapBrowsingInstance is enabled on same-site navigations.
5876 DCHECK(!CanSameSiteMainFrameNavigationsChangeSiteInstances());
Lowell Mannerscc67fc62019-10-18 10:21:475877 ASSERT_TRUE(embedded_test_server()->Start());
5878 GURL url_a1(embedded_test_server()->GetURL("a.com", "/title1.html"));
5879 GURL url_a2(embedded_test_server()->GetURL("a.com", "/title2.html"));
5880 GURL url_b3(embedded_test_server()->GetURL("b.com", "/title1.html"));
5881
5882 // 1) Navigate to A1.
5883 EXPECT_TRUE(NavigateToURL(shell(), url_a1));
5884
5885 // 2) Navigate to A2.
5886 EXPECT_TRUE(NavigateToURL(shell(), url_a2));
5887 RenderFrameHostImpl* rfh_a2 = current_frame_host();
5888 RenderFrameDeletedObserver delete_rfh_a2(current_frame_host());
5889
5890 // 3) Navigate to B3.
5891 EXPECT_TRUE(NavigateToURL(shell(), url_b3));
Hajime Hoshibbc509c2020-04-06 08:55:085892 EXPECT_TRUE(rfh_a2->IsInBackForwardCache());
Lowell Mannerscc67fc62019-10-18 10:21:475893 RenderFrameHostImpl* rfh_b3 = current_frame_host();
5894 // Make B3 ineligible for caching, so that navigating doesn't evict A2
5895 // due to the cache size limit.
Julie Jeongeun Kim8ecd5142021-08-04 07:18:435896 DisableBFCacheForRFHForTesting(rfh_b3);
Lowell Mannerscc67fc62019-10-18 10:21:475897
5898 // 4) Do a history navigation back to A1. At this point, A1 is going to have
5899 // the same BrowsingInstance as A2. This should cause A2 to get
5900 // evicted from the BackForwardCache due to its conflicting BrowsingInstance.
5901 web_contents()->GetController().GoToIndex(0);
5902 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
5903 EXPECT_EQ(current_frame_host()->GetLastCommittedURL(), url_a1);
5904 delete_rfh_a2.WaitUntilDeleted();
Hajime Hoshifb90ec82019-10-24 06:39:265905
Hajime Hoshi5e86bc82019-11-26 05:41:125906 ExpectNotRestored(
Hajime Hoshic7606502021-04-14 02:42:165907 {BackForwardCacheMetrics::NotRestoredReason::kBrowsingInstanceNotSwapped},
5908 {}, {ShouldSwapBrowsingInstance::kNo_SameSiteNavigation}, {}, FROM_HERE);
Hajime Hoshifb90ec82019-10-24 06:39:265909
Alexander Timinde527cd2019-12-02 09:41:125910 // 5) Go to A2.
5911 web_contents()->GetController().GoForward();
Hajime Hoshifb90ec82019-10-24 06:39:265912 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
5913
Hajime Hoshifb90ec82019-10-24 06:39:265914 ExpectNotRestored(
5915 {
5916 BackForwardCacheMetrics::NotRestoredReason::
Alexander Timinde527cd2019-12-02 09:41:125917 kConflictingBrowsingInstance,
Hajime Hoshifb90ec82019-10-24 06:39:265918 },
Fergal Daly6755cbf2021-02-12 03:06:585919 {}, {}, {}, FROM_HERE);
Lowell Mannerscc67fc62019-10-18 10:21:475920}
5921
Rakina Zata Amni95a2a91d2020-07-14 12:41:445922// When same-site bfcache is disabled, we should not cache on same-site
5923// navigations.
5924IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTestWithSameSiteDisabled,
5925 DoesNotCacheOnSameSiteNavigation) {
5926 ASSERT_TRUE(embedded_test_server()->Start());
5927 GURL url_a1(embedded_test_server()->GetURL("a.com", "/title1.html"));
5928 GURL url_a2(embedded_test_server()->GetURL("a.com", "/title2.html"));
5929 GURL url_a3(
5930 embedded_test_server()->GetURL("subdomain.a.com", "/title3.html"));
5931
5932 // 1) Navigate to A1.
5933 EXPECT_TRUE(NavigateToURL(shell(), url_a1));
5934 RenderFrameHostImpl* rfh_a1 = current_frame_host();
5935 RenderFrameDeletedObserver delete_rfh_a1(rfh_a1);
Lukasz Anforowicz15ba43e2021-07-21 22:50:095936 auto browsing_instance_id =
5937 rfh_a1->GetSiteInstance()->GetBrowsingInstanceId();
Rakina Zata Amni95a2a91d2020-07-14 12:41:445938
5939 // 2) Navigate same-site and same-origin to A2.
5940 EXPECT_TRUE(NavigateToURL(shell(), url_a2));
5941 RenderFrameHostImpl* rfh_a2 = current_frame_host();
5942 // The BrowsingInstance shouldn't have changed.
5943 EXPECT_EQ(browsing_instance_id,
5944 rfh_a2->GetSiteInstance()->GetBrowsingInstanceId());
5945 // The previous page should not be cached.
5946 EXPECT_FALSE(rfh_a1->IsInBackForwardCache());
5947
5948 // 2) Navigate same-site but cross-origin to A3.
5949 EXPECT_TRUE(NavigateToURL(shell(), url_a3));
5950 RenderFrameHostImpl* rfh_a3 = current_frame_host();
5951 // The BrowsingInstance shouldn't have changed.
5952 EXPECT_EQ(browsing_instance_id,
5953 rfh_a3->GetSiteInstance()->GetBrowsingInstanceId());
5954 // The previous page should not be cached.
5955 EXPECT_FALSE(rfh_a2->IsInBackForwardCache());
5956}
5957
5958// Check that during a same-RenderFrameHost cross-document navigation, the
5959// disabled reasons is still tracked.
5960IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTestWithSameSiteDisabled,
5961 DisableForRenderFrameHostPersistsAcrossNavigations) {
5962 // This test assumes navigation from A1 to A2 will not switch
5963 // RenderFrameHosts which is not true when BackForwardCache,
5964 // ProactivelySwapBrowsingInstance or RenderDocument is enabled on same-site
5965 // main frame navigations.
5966 DCHECK(!CanSameSiteMainFrameNavigationsChangeRenderFrameHosts());
5967 ASSERT_TRUE(embedded_test_server()->Start());
5968 GURL url_a1(embedded_test_server()->GetURL("a.com", "/title1.html"));
5969 GURL url_a2(embedded_test_server()->GetURL("a.com", "/title2.html"));
5970 GURL url_b3(embedded_test_server()->GetURL("b.com", "/title1.html"));
5971
5972 // 1) Navigate to A1.
5973 EXPECT_TRUE(NavigateToURL(shell(), url_a1));
5974 RenderFrameHostImpl* rfh_a1 = current_frame_host();
5975 RenderFrameDeletedObserver deleted_observer_rfh_a1(rfh_a1);
5976 // Disable back-forward cache for A.
Julie Jeongeun Kim8ecd5142021-08-04 07:18:435977 DisableBFCacheForRFHForTesting(rfh_a1);
Rakina Zata Amni95a2a91d2020-07-14 12:41:445978
5979 // 2) Navigate to A2.
5980 EXPECT_TRUE(NavigateToURL(shell(), url_a2));
5981 EXPECT_FALSE(deleted_observer_rfh_a1.deleted());
5982 EXPECT_EQ(rfh_a1, current_frame_host());
5983
5984 // 3) Navigate to B3.
5985 EXPECT_TRUE(NavigateToURL(shell(), url_b3));
5986 deleted_observer_rfh_a1.WaitUntilDeleted();
5987
5988 // 4) Go back to A2.
5989 web_contents()->GetController().GoBack();
5990 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
Rakina Zata Amni95a2a91d2020-07-14 12:41:445991 ExpectNotRestored({BackForwardCacheMetrics::NotRestoredReason::
5992 kDisableForRenderFrameHostCalled},
Fergal Daly23b8ae62021-03-30 05:43:465993 {}, {}, {RenderFrameHostDisabledForTestingReason()},
5994 FROM_HERE);
Rakina Zata Amni95a2a91d2020-07-14 12:41:445995}
5996
5997// The BackForwardCache caches same-website navigations.
5998IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, SameSiteNavigationCaching) {
5999 ASSERT_TRUE(embedded_test_server()->Start());
6000 GURL url_a1(embedded_test_server()->GetURL("a.com", "/title1.html"));
6001 GURL url_a2(embedded_test_server()->GetURL("a.com", "/title2.html"));
6002
6003 // 1) Navigate to A1.
6004 EXPECT_TRUE(NavigateToURL(shell(), url_a1));
6005 RenderFrameHostImpl* rfh_a1 = current_frame_host();
6006 RenderFrameDeletedObserver delete_rfh_a1(rfh_a1);
Lukasz Anforowicz15ba43e2021-07-21 22:50:096007 auto browsing_instance_id =
6008 rfh_a1->GetSiteInstance()->GetBrowsingInstanceId();
Rakina Zata Amni95a2a91d2020-07-14 12:41:446009
6010 // 2) Navigate to A2.
6011 EXPECT_TRUE(NavigateToURL(shell(), url_a2));
6012 RenderFrameHostImpl* rfh_a2 = current_frame_host();
6013 EXPECT_NE(browsing_instance_id,
6014 rfh_a2->GetSiteInstance()->GetBrowsingInstanceId());
6015 EXPECT_TRUE(rfh_a1->IsInBackForwardCache());
6016 EXPECT_NE(rfh_a1, rfh_a2);
6017}
6018
Rakina Zata Amni8d49da52020-11-06 09:23:106019IN_PROC_BROWSER_TEST_F(HighCacheSizeBackForwardCacheBrowserTest,
Lowell Mannerscc67fc62019-10-18 10:21:476020 CanCacheMultiplesPagesOnSameDomain) {
6021 ASSERT_TRUE(embedded_test_server()->Start());
6022 GURL url_a1(embedded_test_server()->GetURL("a.com", "/title1.html"));
6023 GURL url_b2(embedded_test_server()->GetURL("b.com", "/title1.html"));
6024 GURL url_a3(embedded_test_server()->GetURL("a.com", "/title2.html"));
6025 GURL url_b4(embedded_test_server()->GetURL("b.com", "/title2.html"));
6026
Lowell Mannerscc67fc62019-10-18 10:21:476027 // 1) Navigate to A1.
6028 EXPECT_TRUE(NavigateToURL(shell(), url_a1));
6029 RenderFrameHostImpl* rfh_a1 = current_frame_host();
6030
6031 // 2) Navigate to B2.
6032 EXPECT_TRUE(NavigateToURL(shell(), url_b2));
6033 RenderFrameHostImpl* rfh_b2 = current_frame_host();
Hajime Hoshibbc509c2020-04-06 08:55:086034 EXPECT_TRUE(rfh_a1->IsInBackForwardCache());
Lowell Mannerscc67fc62019-10-18 10:21:476035
6036 // 3) Navigate to A3.
6037 EXPECT_TRUE(NavigateToURL(shell(), url_a3));
6038 RenderFrameHostImpl* rfh_a3 = current_frame_host();
Hajime Hoshibbc509c2020-04-06 08:55:086039 EXPECT_TRUE(rfh_a1->IsInBackForwardCache());
6040 EXPECT_TRUE(rfh_b2->IsInBackForwardCache());
Lowell Mannerscc67fc62019-10-18 10:21:476041 // A1 and A3 shouldn't be treated as the same site instance.
6042 EXPECT_NE(rfh_a1->GetSiteInstance(), rfh_a3->GetSiteInstance());
6043
6044 // 4) Navigate to B4.
6045 // Make sure we can store A1 and A3 in the cache at the same time.
6046 EXPECT_TRUE(NavigateToURL(shell(), url_b4));
6047 RenderFrameHostImpl* rfh_b4 = current_frame_host();
Hajime Hoshibbc509c2020-04-06 08:55:086048 EXPECT_TRUE(rfh_a1->IsInBackForwardCache());
6049 EXPECT_TRUE(rfh_b2->IsInBackForwardCache());
6050 EXPECT_TRUE(rfh_a3->IsInBackForwardCache());
Lowell Mannerscc67fc62019-10-18 10:21:476051
6052 // 5) Go back to A3.
6053 // Make sure we can restore A3, while A1 remains in the cache.
6054 web_contents()->GetController().GoBack();
6055 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
Hajime Hoshibbc509c2020-04-06 08:55:086056 EXPECT_TRUE(rfh_a1->IsInBackForwardCache());
6057 EXPECT_TRUE(rfh_b2->IsInBackForwardCache());
6058 EXPECT_TRUE(rfh_b4->IsInBackForwardCache());
Lowell Mannerscc67fc62019-10-18 10:21:476059 EXPECT_EQ(rfh_a3, current_frame_host());
6060 // B2 and B4 shouldn't be treated as the same site instance.
6061 EXPECT_NE(rfh_b2->GetSiteInstance(), rfh_b4->GetSiteInstance());
6062
6063 // 6) Do a history navigation back to A1.
6064 // Make sure we can restore A1, while coming from A3.
6065 web_contents()->GetController().GoToIndex(0);
6066 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
Hajime Hoshibbc509c2020-04-06 08:55:086067 EXPECT_TRUE(rfh_b2->IsInBackForwardCache());
6068 EXPECT_TRUE(rfh_b4->IsInBackForwardCache());
6069 EXPECT_TRUE(rfh_a3->IsInBackForwardCache());
Lowell Mannerscc67fc62019-10-18 10:21:476070 EXPECT_EQ(rfh_a1, current_frame_host());
6071}
6072
Rakina Zata Amniff89a032020-08-14 16:48:506073class BackForwardCacheBrowserTestSkipSameSiteUnload
6074 : public BackForwardCacheBrowserTest {
6075 public:
6076 BackForwardCacheBrowserTestSkipSameSiteUnload() = default;
6077 ~BackForwardCacheBrowserTestSkipSameSiteUnload() override = default;
6078
6079 protected:
6080 void SetUpCommandLine(base::CommandLine* command_line) override {
6081 skip_same_site_if_unload_exists_ = true;
6082 BackForwardCacheBrowserTest::SetUpCommandLine(command_line);
6083 }
6084};
6085
6086// We won't cache pages with unload handler on same-site navigations when
6087// skip_same_site_if_unload_exists is set to true.
6088IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTestSkipSameSiteUnload,
6089 SameSiteNavigationFromPageWithUnload) {
6090 ASSERT_TRUE(embedded_test_server()->Start());
6091 GURL url_a1(embedded_test_server()->GetURL("a.com", "/title1.html"));
6092 GURL url_a2(embedded_test_server()->GetURL("a.com", "/title2.html"));
6093
6094 // 1) Navigate to A1 and add an unload handler.
6095 EXPECT_TRUE(NavigateToURL(shell(), url_a1));
Rakina Zata Amni7a8fca52020-08-20 07:59:316096
Rakina Zata Amniff89a032020-08-14 16:48:506097 RenderFrameHostImpl* rfh_a1 = current_frame_host();
6098 EXPECT_TRUE(ExecJs(rfh_a1, "window.onunload = () => {} "));
6099
6100 // 2) Navigate to A2.
6101 EXPECT_TRUE(NavigateToURL(shell(), url_a2));
6102 RenderFrameHostImpl* rfh_a2 = current_frame_host();
6103 // We should not swap RFHs and A1 should not be in the back-forward cache.
6104 EXPECT_EQ(rfh_a1, rfh_a2);
6105 EXPECT_FALSE(rfh_a1->IsInBackForwardCache());
6106}
6107
6108// We won't cache pages with an unload handler in a same-SiteInstance subframe
6109// on same-site navigations when skip_same_site_if_unload_exists is set to true.
6110IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTestSkipSameSiteUnload,
6111 SameSiteNavigationFromPageWithUnloadInSameSiteSubframe) {
6112 ASSERT_TRUE(embedded_test_server()->Start());
6113 GURL url_a1(embedded_test_server()->GetURL(
6114 "a.com", "/cross_site_iframe_factory.html?a(b(a))"));
6115 GURL url_a2(embedded_test_server()->GetURL("a.com", "/title2.html"));
6116
6117 // 1) Navigate to A1 and add an unload handler to a.com subframe.
6118 EXPECT_TRUE(NavigateToURL(shell(), url_a1));
6119 RenderFrameHostImpl* rfh_a_main = current_frame_host();
6120 RenderFrameHostImpl* rfh_b = rfh_a_main->child_at(0)->current_frame_host();
6121 RenderFrameHostImpl* rfh_a_subframe =
6122 rfh_b->child_at(0)->current_frame_host();
6123 EXPECT_TRUE(ExecJs(rfh_a_subframe, "window.onunload = () => {} "));
6124
6125 // 2) Navigate to A2.
6126 EXPECT_TRUE(NavigateToURL(shell(), url_a2));
6127 RenderFrameHostImpl* rfh_a2 = current_frame_host();
6128 // We should not swap RFHs and A1 should not be in the back-forward cache.
6129 EXPECT_EQ(rfh_a_main, rfh_a2);
6130 EXPECT_FALSE(rfh_a_main->IsInBackForwardCache());
6131}
6132
6133// We won't cache pages with an unload handler in a cross-site subframe on
6134// same-site navigations when skip_same_site_if_unload_exists is set to true
6135// iff the cross-site subframe is in the same SiteInstance as the mainframe.
6136IN_PROC_BROWSER_TEST_F(
6137 BackForwardCacheBrowserTestSkipSameSiteUnload,
6138 SameSiteNavigationFromPageWithUnloadInCrossSiteSubframe) {
Rakina Zata Amniff89a032020-08-14 16:48:506139 ASSERT_TRUE(embedded_test_server()->Start());
6140 GURL url_a1(embedded_test_server()->GetURL(
6141 "a.com", "/cross_site_iframe_factory.html?a(b)"));
6142 GURL url_a2(embedded_test_server()->GetURL("a.com", "/title2.html"));
6143
6144 // 1) Navigate to A1 and add an unload handler to b.com subframe.
6145 EXPECT_TRUE(NavigateToURL(shell(), url_a1));
6146 RenderFrameHostImpl* rfh_a1 = current_frame_host();
6147 RenderFrameHostImpl* rfh_b = rfh_a1->child_at(0)->current_frame_host();
6148 EXPECT_TRUE(ExecJs(rfh_b, "window.onunload = () => {} "));
Aaron Colwell5fb878042020-12-17 19:48:446149 EXPECT_EQ(AreStrictSiteInstancesEnabled(),
Rakina Zata Amniff89a032020-08-14 16:48:506150 rfh_a1->GetSiteInstance() != rfh_b->GetSiteInstance());
6151
6152 // 2) Navigate to A2.
6153 EXPECT_TRUE(NavigateToURL(shell(), url_a2));
6154 RenderFrameHostImpl* rfh_a2 = current_frame_host();
Aaron Colwell5fb878042020-12-17 19:48:446155 if (AreStrictSiteInstancesEnabled()) {
Rakina Zata Amniff89a032020-08-14 16:48:506156 // We should swap RFH & BIs and A1 should be in the back-forward cache.
6157 EXPECT_NE(rfh_a1, rfh_a2);
6158 EXPECT_FALSE(rfh_a1->GetSiteInstance()->IsRelatedSiteInstance(
6159 rfh_a2->GetSiteInstance()));
6160 EXPECT_TRUE(rfh_a1->IsInBackForwardCache());
6161 } else {
6162 // We should not swap RFHs and A1 should not be in the back-forward cache.
6163 EXPECT_EQ(rfh_a1, rfh_a2);
6164 EXPECT_FALSE(rfh_a1->IsInBackForwardCache());
6165 }
6166}
6167
6168// We will cache pages with unload handler on cross-site navigations even when
6169// skip_same_site_if_unload_exists is set to true.
6170IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTestSkipSameSiteUnload,
6171 CrossSiteNavigationFromPageWithUnload) {
6172 ASSERT_TRUE(embedded_test_server()->Start());
6173 GURL url_a1(embedded_test_server()->GetURL("a.com", "/title1.html"));
6174 GURL url_a2(embedded_test_server()->GetURL("b.com", "/title2.html"));
6175
6176 // 1) Navigate to A and add an unload handler.
6177 EXPECT_TRUE(NavigateToURL(shell(), url_a1));
6178 RenderFrameHostImpl* rfh_a = current_frame_host();
6179 EXPECT_TRUE(ExecJs(rfh_a, "window.onunload = () => {} "));
6180
6181 // 2) Navigate to B.
6182 EXPECT_TRUE(NavigateToURL(shell(), url_a2));
6183 RenderFrameHostImpl* rfh_b = current_frame_host();
6184 // We should swap RFHs and A should be in the back-forward cache.
6185 EXPECT_NE(rfh_a, rfh_b);
6186 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
6187}
6188
Sreeja Kamishetty299329ad2021-03-25 14:06:016189// Sub-frame doesn't transition from LifecycleStateImpl::kInBackForwardCache to
6190// LifecycleStateImpl::kRunningUnloadHandlers even when the sub-frame having
6191// unload handlers is being evicted from BackForwardCache.
Sreeja Kamishetty9bcdc972020-10-23 13:33:216192IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, SubframeWithUnloadHandler) {
6193 ASSERT_TRUE(embedded_test_server()->Start());
6194 GURL main_url(embedded_test_server()->GetURL(
6195 "a.com", "/cross_site_iframe_factory.html?a.com(a.com)"));
6196 GURL child_url = embedded_test_server()->GetURL(
6197 "a.com", "/cross_site_iframe_factory.html?a.com()");
6198 GURL url_2(embedded_test_server()->GetURL("a.com", "/title1.html"));
6199
6200 // 1) Navigate to |main_url|.
6201 EXPECT_TRUE(NavigateToURL(shell(), main_url));
6202 RenderFrameHostImpl* main_rfh = current_frame_host();
6203 ASSERT_EQ(1U, main_rfh->child_count());
6204 RenderFrameHostImpl* child_rfh = main_rfh->child_at(0)->current_frame_host();
6205 RenderFrameDeletedObserver main_rfh_observer(main_rfh),
6206 child_rfh_observer(child_rfh);
6207
6208 // 2) Add an unload handler to the child RFH.
6209 EXPECT_TRUE(ExecJs(child_rfh, "window.onunload = () => {} "));
6210
6211 // 3) Navigate to |url_2|.
6212 EXPECT_TRUE(NavigateToURL(shell(), url_2));
6213
6214 // 4) The previous main RFH and child RFH should be in the back-forward
6215 // cache.
6216 EXPECT_FALSE(main_rfh_observer.deleted());
6217 EXPECT_FALSE(child_rfh_observer.deleted());
6218 EXPECT_TRUE(main_rfh->IsInBackForwardCache());
6219 EXPECT_TRUE(child_rfh->IsInBackForwardCache());
6220
6221 // Destruction of bfcached page happens after shutdown and it should not
6222 // trigger unload handlers and be destroyed directly.
6223}
6224
Kouhei Ueno7b6f3cd02019-09-09 04:48:506225class GeolocationBackForwardCacheBrowserTest
6226 : public BackForwardCacheBrowserTest {
6227 protected:
6228 GeolocationBackForwardCacheBrowserTest() : geo_override_(0.0, 0.0) {}
6229
6230 device::ScopedGeolocationOverrider geo_override_;
6231};
6232
6233// Test that a page which has queried geolocation in the past, but have no
6234// active geolocation query, can be bfcached.
6235IN_PROC_BROWSER_TEST_F(GeolocationBackForwardCacheBrowserTest,
6236 CacheAfterGeolocationRequest) {
6237 ASSERT_TRUE(embedded_test_server()->Start());
arthursonzogni72b66492019-11-04 12:24:336238 GURL url_a(embedded_test_server()->GetURL("/title1.html"));
6239 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
Kouhei Ueno7b6f3cd02019-09-09 04:48:506240
6241 // 1) Navigate to A.
6242 EXPECT_TRUE(NavigateToURL(shell(), url_a));
6243 RenderFrameHostImpl* rfh_a = current_frame_host();
6244
6245 // Query current position, and wait for the query to complete.
6246 EXPECT_EQ("received", EvalJs(rfh_a, R"(
6247 new Promise(resolve => {
6248 navigator.geolocation.getCurrentPosition(() => resolve('received'));
6249 });
6250 )"));
6251
6252 RenderFrameDeletedObserver deleted(rfh_a);
6253
6254 // 2) Navigate away.
6255 EXPECT_TRUE(NavigateToURL(shell(), url_b));
6256
6257 // The page has no inflight geolocation request when we navigated away,
6258 // so it should have been cached.
6259 EXPECT_FALSE(deleted.deleted());
Hajime Hoshibbc509c2020-04-06 08:55:086260 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
Kouhei Ueno7b6f3cd02019-09-09 04:48:506261}
6262
6263// Test that a page which has an inflight geolocation query can be bfcached,
6264// and verify that the page does not observe any geolocation while the page
6265// was inside bfcache.
Sahel Sharify0d8127c12019-12-16 21:43:226266// The test is flaky on multiple platforms: crbug.com/1033270
Kouhei Ueno7b6f3cd02019-09-09 04:48:506267IN_PROC_BROWSER_TEST_F(GeolocationBackForwardCacheBrowserTest,
Sahel Sharify0d8127c12019-12-16 21:43:226268 DISABLED_CancelGeolocationRequestInFlight) {
Kouhei Ueno7b6f3cd02019-09-09 04:48:506269 ASSERT_TRUE(embedded_test_server()->Start());
arthursonzogni72b66492019-11-04 12:24:336270 GURL url_a(embedded_test_server()->GetURL("/title1.html"));
6271 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
Kouhei Ueno7b6f3cd02019-09-09 04:48:506272
6273 // 1) Navigate to A.
6274 EXPECT_TRUE(NavigateToURL(shell(), url_a));
6275 RenderFrameHostImpl* rfh_a = current_frame_host();
6276
6277 // Continuously query current geolocation.
6278 EXPECT_TRUE(ExecJs(rfh_a, R"(
6279 window.longitude_log = [];
6280 window.err_log = [];
6281 window.wait_for_first_position = new Promise(resolve => {
6282 navigator.geolocation.watchPosition(
6283 pos => {
6284 window.longitude_log.push(pos.coords.longitude);
6285 resolve("resolved");
6286 },
6287 err => window.err_log.push(err)
6288 );
6289 })
6290 )"));
6291 geo_override_.UpdateLocation(0.0, 0.0);
6292 EXPECT_EQ("resolved", EvalJs(rfh_a, "window.wait_for_first_position"));
6293
6294 // Pause resolving Geoposition queries to keep the request inflight.
6295 geo_override_.Pause();
6296 geo_override_.UpdateLocation(1.0, 1.0);
6297 EXPECT_EQ(1u, geo_override_.GetGeolocationInstanceCount());
6298
6299 // 2) Navigate away.
6300 base::RunLoop loop_until_close;
6301 geo_override_.SetGeolocationCloseCallback(loop_until_close.QuitClosure());
6302
6303 RenderFrameDeletedObserver deleted(rfh_a);
6304 EXPECT_TRUE(NavigateToURL(shell(), url_b));
6305
6306 loop_until_close.Run();
6307
6308 // The page has no inflight geolocation request when we navigated away,
6309 // so it should have been cached.
6310 EXPECT_FALSE(deleted.deleted());
Hajime Hoshibbc509c2020-04-06 08:55:086311 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
Kouhei Ueno7b6f3cd02019-09-09 04:48:506312
6313 // Resume resolving Geoposition queries.
6314 geo_override_.Resume();
6315
6316 // We update the location while the page is BFCached, but this location should
6317 // not be observed.
6318 geo_override_.UpdateLocation(2.0, 2.0);
6319
6320 // 3) Navigate back to A.
6321
6322 // The location when navigated back can be observed
6323 geo_override_.UpdateLocation(3.0, 3.0);
6324
6325 web_contents()->GetController().GoBack();
6326 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
6327 EXPECT_EQ(rfh_a, current_frame_host());
Hajime Hoshibbc509c2020-04-06 08:55:086328 EXPECT_FALSE(rfh_a->IsInBackForwardCache());
Kouhei Ueno7b6f3cd02019-09-09 04:48:506329
6330 // Wait for an update after the user navigates back to A.
6331 EXPECT_EQ("resolved", EvalJs(rfh_a, R"(
6332 window.wait_for_position_after_resume = new Promise(resolve => {
6333 navigator.geolocation.watchPosition(
6334 pos => {
6335 window.longitude_log.push(pos.coords.longitude);
6336 resolve("resolved");
6337 },
6338 err => window.err_log.push(err)
6339 );
6340 })
6341 )"));
6342
6343 EXPECT_LE(0, EvalJs(rfh_a, "longitude_log.indexOf(0.0)").ExtractInt())
6344 << "Geoposition before the page is put into BFCache should be visible";
6345 EXPECT_EQ(-1, EvalJs(rfh_a, "longitude_log.indexOf(1.0)").ExtractInt())
6346 << "Geoposition while the page is put into BFCache should be invisible";
6347 EXPECT_EQ(-1, EvalJs(rfh_a, "longitude_log.indexOf(2.0)").ExtractInt())
6348 << "Geoposition while the page is put into BFCache should be invisible";
6349 EXPECT_LT(0, EvalJs(rfh_a, "longitude_log.indexOf(3.0)").ExtractInt())
6350 << "Geoposition when the page is restored from BFCache should be visible";
6351 EXPECT_EQ(0, EvalJs(rfh_a, "err_log.length"))
6352 << "watchPosition API should have reported no errors";
6353}
6354
[email protected]3900bde02019-09-18 14:54:446355// Test that documents are evicted correctly from BackForwardCache after time to
6356// live.
[email protected]3900bde02019-09-18 14:54:446357IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, TimedEviction) {
6358 // Inject mock time task runner to be used in the eviction timer, so we can,
6359 // check for the functionality we are interested before and after the time to
6360 // live. We don't replace ThreadTaskRunnerHandle::Get to ensure that it
6361 // doesn't affect other unrelated callsites.
6362 scoped_refptr<base::TestMockTimeTaskRunner> task_runner =
6363 base::MakeRefCounted<base::TestMockTimeTaskRunner>();
6364
Carlos Caballero35ce710c2019-09-19 10:59:456365 web_contents()->GetController().GetBackForwardCache().SetTaskRunnerForTesting(
[email protected]3900bde02019-09-18 14:54:446366 task_runner);
6367
6368 base::TimeDelta time_to_live_in_back_forward_cache =
Carlos Caballero35ce710c2019-09-19 10:59:456369 BackForwardCacheImpl::GetTimeToLiveInBackForwardCache();
[email protected]54eaf622019-11-25 12:36:036370 // This should match the value we set in EnableFeatureAndSetParams.
Lowell Manners0a0419c2019-09-23 08:15:506371 EXPECT_EQ(time_to_live_in_back_forward_cache,
6372 base::TimeDelta::FromSeconds(3600));
[email protected]3900bde02019-09-18 14:54:446373
6374 base::TimeDelta delta = base::TimeDelta::FromMilliseconds(1);
6375
6376 ASSERT_TRUE(embedded_test_server()->Start());
arthursonzogni72b66492019-11-04 12:24:336377 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
6378 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
[email protected]3900bde02019-09-18 14:54:446379
6380 // 1) Navigate to A.
6381 EXPECT_TRUE(NavigateToURL(shell(), url_a));
6382 RenderFrameHostImpl* rfh_a = current_frame_host();
6383 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
6384
6385 // 2) Navigate to B.
6386 EXPECT_TRUE(NavigateToURL(shell(), url_b));
6387 RenderFrameHostImpl* rfh_b = current_frame_host();
6388
Lowell Manners0a0419c2019-09-23 08:15:506389 // 3) Fast forward to just before eviction is due.
6390 task_runner->FastForwardBy(time_to_live_in_back_forward_cache - delta);
6391
6392 // 4) Confirm A is still in BackForwardCache.
[email protected]3900bde02019-09-18 14:54:446393 ASSERT_FALSE(delete_observer_rfh_a.deleted());
Hajime Hoshibbc509c2020-04-06 08:55:086394 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
[email protected]3900bde02019-09-18 14:54:446395
Lowell Manners0a0419c2019-09-23 08:15:506396 // 5) Fast forward to when eviction is due.
6397 task_runner->FastForwardBy(delta);
[email protected]3900bde02019-09-18 14:54:446398
Lowell Manners0a0419c2019-09-23 08:15:506399 // 6) Confirm A is evicted.
[email protected]3900bde02019-09-18 14:54:446400 delete_observer_rfh_a.WaitUntilDeleted();
6401 EXPECT_EQ(current_frame_host(), rfh_b);
Hajime Hoshi3b2e4222019-10-10 10:17:076402
6403 // 7) Go back to A.
6404 web_contents()->GetController().GoBack();
6405 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
Fergal Daly6755cbf2021-02-12 03:06:586406 ExpectNotRestored({BackForwardCacheMetrics::NotRestoredReason::kTimeout}, {},
6407 {}, {}, FROM_HERE);
[email protected]3900bde02019-09-18 14:54:446408}
6409
Carlos Caballero35ce710c2019-09-19 10:59:456410IN_PROC_BROWSER_TEST_F(
6411 BackForwardCacheBrowserTest,
6412 DisableBackForwardCachePreventsDocumentsFromBeingCached) {
6413 ASSERT_TRUE(embedded_test_server()->Start());
arthursonzogni72b66492019-11-04 12:24:336414 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
6415 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
6416 url::Origin origin_a = url::Origin::Create(url_a);
6417 url::Origin origin_b = url::Origin::Create(url_b);
Carlos Caballero35ce710c2019-09-19 10:59:456418
6419 // 1) Navigate to A.
6420 EXPECT_TRUE(NavigateToURL(shell(), url_a));
6421 RenderFrameHostImpl* rfh_a = current_frame_host();
6422 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
Julie Jeongeun Kim8ecd5142021-08-04 07:18:436423 DisableBFCacheForRFHForTesting(rfh_a);
Carlos Caballero35ce710c2019-09-19 10:59:456424
6425 // 2) Navigate to B.
6426 EXPECT_TRUE(NavigateToURL(shell(), url_b));
arthursonzogni084581b2019-10-17 11:55:296427 delete_observer_rfh_a.WaitUntilDeleted();
Hajime Hoshi0d93f3b2019-10-08 07:01:506428
6429 // 3) Go back to A.
6430 web_contents()->GetController().GoBack();
6431 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
Hajime Hoshi15f6b5012019-10-24 05:25:496432 ExpectNotRestored({BackForwardCacheMetrics::NotRestoredReason::
6433 kDisableForRenderFrameHostCalled},
Fergal Daly23b8ae62021-03-30 05:43:466434 {}, {}, {RenderFrameHostDisabledForTestingReason()},
6435 FROM_HERE);
Carlos Caballero35ce710c2019-09-19 10:59:456436}
6437
6438IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
6439 DisableBackForwardIsNoOpIfRfhIsGone) {
6440 ASSERT_TRUE(embedded_test_server()->Start());
arthursonzogni72b66492019-11-04 12:24:336441 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
6442 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
6443 url::Origin origin_a = url::Origin::Create(url_a);
6444 url::Origin origin_b = url::Origin::Create(url_b);
Carlos Caballero35ce710c2019-09-19 10:59:456445
6446 // 1) Navigate to A.
6447 EXPECT_TRUE(NavigateToURL(shell(), url_a));
6448 RenderFrameHostImpl* rfh_a = current_frame_host();
6449 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
Alexander Timin8690530c2021-06-19 00:34:326450 GlobalRenderFrameHostId rfh_a_id = rfh_a->GetGlobalId();
Julie Jeongeun Kim8ecd5142021-08-04 07:18:436451 DisableBFCacheForRFHForTesting(rfh_a_id);
Carlos Caballero35ce710c2019-09-19 10:59:456452
6453 // 2) Navigate to B.
6454 EXPECT_TRUE(NavigateToURL(shell(), url_b));
arthursonzogni084581b2019-10-17 11:55:296455 delete_observer_rfh_a.WaitUntilDeleted();
Carlos Caballero35ce710c2019-09-19 10:59:456456
6457 // This should not die
Julie Jeongeun Kim8ecd5142021-08-04 07:18:436458 DisableBFCacheForRFHForTesting(rfh_a_id);
Hajime Hoshi0d93f3b2019-10-08 07:01:506459
6460 // 3) Go back to A.
6461 web_contents()->GetController().GoBack();
6462 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
Hajime Hoshi15f6b5012019-10-24 05:25:496463 ExpectNotRestored({BackForwardCacheMetrics::NotRestoredReason::
6464 kDisableForRenderFrameHostCalled},
Fergal Daly23b8ae62021-03-30 05:43:466465 {}, {}, {RenderFrameHostDisabledForTestingReason()},
6466 FROM_HERE);
Carlos Caballero35ce710c2019-09-19 10:59:456467}
6468
6469IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
arthursonzogni084581b2019-10-17 11:55:296470 DisableBackForwardCacheIframe) {
arthursonzogni1516ee32019-10-04 10:27:586471 ASSERT_TRUE(embedded_test_server()->Start());
6472 GURL url_a(embedded_test_server()->GetURL(
6473 "a.com", "/cross_site_iframe_factory.html?a(b)"));
6474 GURL url_c(embedded_test_server()->GetURL("b.com", "/title1.html"));
6475
6476 // 1) Navigate to A.
6477 EXPECT_TRUE(NavigateToURL(shell(), url_a));
6478 RenderFrameHostImpl* rfh_a = current_frame_host();
6479 RenderFrameHostImpl* rfh_b = rfh_a->child_at(0)->current_frame_host();
6480 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
6481 RenderFrameDeletedObserver delete_observer_rfh_b(rfh_b);
6482
Julie Jeongeun Kim8ecd5142021-08-04 07:18:436483 DisableBFCacheForRFHForTesting(rfh_b);
arthursonzogni1516ee32019-10-04 10:27:586484
arthursonzogni084581b2019-10-17 11:55:296485 // 2) Navigate to C. A and B are deleted.
arthursonzogni1516ee32019-10-04 10:27:586486 EXPECT_TRUE(NavigateToURL(shell(), url_c));
arthursonzogni084581b2019-10-17 11:55:296487 delete_observer_rfh_a.WaitUntilDeleted();
6488 delete_observer_rfh_b.WaitUntilDeleted();
Hajime Hoshi3b2e4222019-10-10 10:17:076489
6490 // 3) Go back to A.
6491 web_contents()->GetController().GoBack();
6492 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
Hajime Hoshi15f6b5012019-10-24 05:25:496493 ExpectNotRestored({BackForwardCacheMetrics::NotRestoredReason::
6494 kDisableForRenderFrameHostCalled},
Fergal Daly23b8ae62021-03-30 05:43:466495 {}, {}, {RenderFrameHostDisabledForTestingReason()},
6496 FROM_HERE);
arthursonzogni1516ee32019-10-04 10:27:586497}
6498
6499IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
Carlos Caballero35ce710c2019-09-19 10:59:456500 DisableBackForwardEvictsIfAlreadyInCache) {
6501 ASSERT_TRUE(embedded_test_server()->Start());
arthursonzogni72b66492019-11-04 12:24:336502 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
6503 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
6504 url::Origin origin_a = url::Origin::Create(url_a);
6505 url::Origin origin_b = url::Origin::Create(url_b);
Carlos Caballero35ce710c2019-09-19 10:59:456506
6507 // 1) Navigate to A.
6508 EXPECT_TRUE(NavigateToURL(shell(), url_a));
6509 RenderFrameHostImpl* rfh_a = current_frame_host();
6510 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
6511
6512 // 2) Navigate to B.
6513 EXPECT_TRUE(NavigateToURL(shell(), url_b));
Hajime Hoshibbc509c2020-04-06 08:55:086514 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
Carlos Caballero35ce710c2019-09-19 10:59:456515 EXPECT_FALSE(rfh_a->is_evicted_from_back_forward_cache());
6516
Julie Jeongeun Kim8ecd5142021-08-04 07:18:436517 DisableBFCacheForRFHForTesting(rfh_a);
Carlos Caballero35ce710c2019-09-19 10:59:456518
Carlos Caballero35ce710c2019-09-19 10:59:456519 delete_observer_rfh_a.WaitUntilDeleted();
Hajime Hoshi0d93f3b2019-10-08 07:01:506520
6521 // 3) Go back to A.
6522 web_contents()->GetController().GoBack();
6523 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
Hajime Hoshib03d6ddf52019-11-21 09:41:246524 ExpectNotRestored({BackForwardCacheMetrics::NotRestoredReason::
6525 kDisableForRenderFrameHostCalled},
Fergal Daly23b8ae62021-03-30 05:43:466526 {}, {}, {RenderFrameHostDisabledForTestingReason()},
6527 FROM_HERE);
Hajime Hoshib03d6ddf52019-11-21 09:41:246528}
6529
Hajime Hoshif9eba2b2019-10-02 08:27:426530// Confirm that same-document navigation and not history-navigation does not
6531// record metrics.
6532IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, MetricsNotRecorded) {
6533 ASSERT_TRUE(embedded_test_server()->Start());
arthursonzogni72b66492019-11-04 12:24:336534 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
6535 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
6536 GURL url_b2(embedded_test_server()->GetURL("b.com", "/title1.html#2"));
Hajime Hoshif9eba2b2019-10-02 08:27:426537
6538 // 1) Navigate to A.
6539 EXPECT_TRUE(NavigateToURL(shell(), url_a));
6540 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
6541
6542 // 2) Navigate to B.
6543 EXPECT_TRUE(NavigateToURL(shell(), url_b));
6544 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
6545
6546 // 3) Navigate to B#2 (same document navigation).
[email protected]8fa10fd2020-04-07 11:59:206547 EXPECT_TRUE(NavigateToURLFromRenderer(shell(), url_b2));
Hajime Hoshif9eba2b2019-10-02 08:27:426548
6549 // 4) Go back to B.
6550 web_contents()->GetController().GoBack();
6551 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
Hajime Hoshib03d6ddf52019-11-21 09:41:246552 ExpectOutcomeDidNotChange(FROM_HERE);
Hajime Hoshif9eba2b2019-10-02 08:27:426553
6554 // 5) Navigate to A.
6555 EXPECT_TRUE(NavigateToURL(shell(), url_a));
6556 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
Hajime Hoshib03d6ddf52019-11-21 09:41:246557 ExpectOutcomeDidNotChange(FROM_HERE);
Hajime Hoshif9eba2b2019-10-02 08:27:426558}
6559
[email protected]5c1dcb32019-10-04 12:23:296560// Test for functionality of domain specific controls in back-forward cache.
6561class BackForwardCacheBrowserTestWithDomainControlEnabled
6562 : public BackForwardCacheBrowserTest {
6563 protected:
[email protected]54eaf622019-11-25 12:36:036564 void SetUpCommandLine(base::CommandLine* command_line) override {
[email protected]5c1dcb32019-10-04 12:23:296565 // Sets the allowed websites for testing, additionally adding the params
6566 // used by BackForwardCacheBrowserTest.
[email protected]54eaf622019-11-25 12:36:036567 std::string allowed_websites =
6568 "https://a.allowed/back_forward_cache/, "
6569 "https://b.allowed/back_forward_cache/allowed_path.html";
6570 EnableFeatureAndSetParams(features::kBackForwardCache, "allowed_websites",
6571 allowed_websites);
6572
6573 BackForwardCacheBrowserTest::SetUpCommandLine(command_line);
[email protected]5c1dcb32019-10-04 12:23:296574 }
6575};
6576
6577// Check the RenderFrameHost allowed to enter the BackForwardCache are the ones
6578// matching with the "allowed_websites" feature params.
6579IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTestWithDomainControlEnabled,
6580 CachePagesWithMatchedURLs) {
6581 ASSERT_TRUE(embedded_test_server()->Start());
arthursonzogni72b66492019-11-04 12:24:336582 GURL url_a(embedded_test_server()->GetURL(
[email protected]5c1dcb32019-10-04 12:23:296583 "a.allowed", "/back_forward_cache/allowed_path.html"));
arthursonzogni72b66492019-11-04 12:24:336584 GURL url_b(embedded_test_server()->GetURL(
[email protected]5c1dcb32019-10-04 12:23:296585 "b.allowed", "/back_forward_cache/allowed_path.html?query=bar"));
6586
6587 // 1) Navigate to A.
6588 EXPECT_TRUE(NavigateToURL(shell(), url_a));
6589 RenderFrameHostImpl* rfh_a = current_frame_host();
6590 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
6591
6592 // 2) Navigate to B.
6593 EXPECT_TRUE(NavigateToURL(shell(), url_b));
6594 RenderFrameHostImpl* rfh_b = current_frame_host();
6595 RenderFrameDeletedObserver delete_observer_rfh_b(rfh_b);
6596
6597 // 3) Check if rfh_a is stored in back-forward cache, since it matches to
6598 // the list of allowed urls, it should be stored.
6599 EXPECT_FALSE(delete_observer_rfh_a.deleted());
Hajime Hoshibbc509c2020-04-06 08:55:086600 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
[email protected]5c1dcb32019-10-04 12:23:296601
6602 // 4) Now go back to the last stored page, which in our case should be A.
6603 web_contents()->GetController().GoBack();
6604 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
6605 EXPECT_EQ(rfh_a, current_frame_host());
6606
6607 // 5) Check if rfh_b is stored in back-forward cache, since it matches to
6608 // the list of allowed urls, it should be stored.
6609 EXPECT_FALSE(delete_observer_rfh_b.deleted());
Hajime Hoshibbc509c2020-04-06 08:55:086610 EXPECT_TRUE(rfh_b->IsInBackForwardCache());
[email protected]5c1dcb32019-10-04 12:23:296611}
6612
6613// We don't want to allow websites which doesn't match "allowed_websites" of
6614// feature params to be stored in back-forward cache.
6615IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTestWithDomainControlEnabled,
6616 DoNotCachePagesWithUnMatchedURLs) {
Hajime Hoshi765845d62020-02-21 02:56:216617 DisableCheckingMetricsForAllSites();
6618
[email protected]5c1dcb32019-10-04 12:23:296619 ASSERT_TRUE(embedded_test_server()->Start());
arthursonzogni72b66492019-11-04 12:24:336620 GURL url_a(embedded_test_server()->GetURL(
[email protected]5c1dcb32019-10-04 12:23:296621 "a.disallowed", "/back_forward_cache/disallowed_path.html"));
arthursonzogni72b66492019-11-04 12:24:336622 GURL url_b(embedded_test_server()->GetURL(
[email protected]5c1dcb32019-10-04 12:23:296623 "b.allowed", "/back_forward_cache/disallowed_path.html"));
arthursonzogni72b66492019-11-04 12:24:336624 GURL url_c(embedded_test_server()->GetURL(
[email protected]5c1dcb32019-10-04 12:23:296625 "c.disallowed", "/back_forward_cache/disallowed_path.html"));
6626
6627 // 1) Navigate to A.
6628 EXPECT_TRUE(NavigateToURL(shell(), url_a));
6629 RenderFrameHostImpl* rfh_a = current_frame_host();
6630 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
6631
6632 // 2) Navigate to B.
6633 EXPECT_TRUE(NavigateToURL(shell(), url_b));
6634 RenderFrameHostImpl* rfh_b = current_frame_host();
6635 RenderFrameDeletedObserver delete_observer_rfh_b(rfh_b);
6636
6637 // 3) Since url of A doesn't match to the the list of allowed urls it should
6638 // not be stored in back-forward cache.
6639 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
6640 delete_observer_rfh_a.WaitUntilDeleted();
6641
6642 // 4) Navigate to C.
6643 EXPECT_TRUE(NavigateToURL(shell(), url_c));
6644
6645 // 5) Since url of B doesn't match to the the list of allowed urls it should
6646 // not be stored in back-forward cache.
6647 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
6648 delete_observer_rfh_b.WaitUntilDeleted();
Hajime Hoshi446206e2019-10-18 18:36:256649
6650 // 6) Go back to B.
6651 web_contents()->GetController().GoBack();
6652 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
6653
6654 // Nothing is recorded when the domain does not match.
Hajime Hoshib03d6ddf52019-11-21 09:41:246655 ExpectOutcomeDidNotChange(FROM_HERE);
6656 ExpectNotRestoredDidNotChange(FROM_HERE);
[email protected]5c1dcb32019-10-04 12:23:296657}
arthursonzognibec31272019-10-09 11:51:216658
Minoru Chikamune7a588f5e2021-05-03 00:19:366659// Test the "blocked_websites" feature params in back-forward cache.
6660class BackForwardCacheBrowserTestWithBlockedWebsites
6661 : public BackForwardCacheBrowserTest {
6662 protected:
6663 void SetUpCommandLine(base::CommandLine* command_line) override {
6664 // Sets the blocked websites for testing, additionally adding the params
6665 // used by BackForwardCacheBrowserTest.
6666 std::string blocked_websites =
6667 "https://a.blocked/, "
6668 "https://b.blocked/";
6669 EnableFeatureAndSetParams(features::kBackForwardCache, "blocked_websites",
6670 blocked_websites);
6671
6672 BackForwardCacheBrowserTest::SetUpCommandLine(command_line);
6673 }
6674};
6675
6676// Check the disallowed page isn't bfcached when it's navigated from allowed
6677// page.
6678IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTestWithBlockedWebsites,
6679 NavigateFromAllowedPageToDisallowedPage) {
Minoru Chikamunedb359912021-05-14 07:04:146680 // Skip checking the AllSites metrics since BackForwardCacheMetrics stop
6681 // recording except BackForwardCache.AllSites.* metrics when the target URL is
6682 // disallowed by allowed_websites or blocked_websites.
6683 DisableCheckingMetricsForAllSites();
6684
Minoru Chikamune7a588f5e2021-05-03 00:19:366685 ASSERT_TRUE(embedded_test_server()->Start());
6686 GURL url_a(embedded_test_server()->GetURL(
6687 "a.allowed", "/back_forward_cache/allowed_path.html"));
6688 GURL url_b(embedded_test_server()->GetURL(
6689 "b.blocked", "/back_forward_cache/disallowed_path.html"));
6690
6691 // 1) Navigate to A.
6692 EXPECT_TRUE(NavigateToURL(shell(), url_a));
6693 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
6694 RenderFrameHostImpl* rfh_a = current_frame_host();
6695 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
6696
6697 // 2) Navigate to B.
6698 EXPECT_TRUE(NavigateToURL(shell(), url_b));
6699 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
6700 RenderFrameHostImpl* rfh_b = current_frame_host();
6701 RenderFrameDeletedObserver delete_observer_rfh_b(rfh_b);
6702
6703 // 3) Check if rfh_a is stored in back-forward cache, since it doesn't match
Minoru Chikamunedb359912021-05-14 07:04:146704 // to the blocked_websites, and allowed_websites are empty, so it should
Minoru Chikamune7a588f5e2021-05-03 00:19:366705 // be stored.
6706 EXPECT_FALSE(delete_observer_rfh_a.deleted());
6707 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
6708
6709 // 4) Now go back to the last stored page, which in our case should be A.
6710 web_contents()->GetController().GoBack();
6711 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
6712 EXPECT_EQ(rfh_a, current_frame_host());
Minoru Chikamunedb359912021-05-14 07:04:146713 ExpectRestored(FROM_HERE);
Minoru Chikamune7a588f5e2021-05-03 00:19:366714
6715 // 5) Check if rfh_b is not stored in back-forward cache, since it matches to
Minoru Chikamunedb359912021-05-14 07:04:146716 // the blocked_websites.
Minoru Chikamune7a588f5e2021-05-03 00:19:366717 delete_observer_rfh_b.WaitUntilDeleted();
6718 EXPECT_TRUE(delete_observer_rfh_b.deleted());
Minoru Chikamunedb359912021-05-14 07:04:146719
6720 // 6) Go forward to B. B should not restored from the back-forward cache.
6721 web_contents()->GetController().GoForward();
6722 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
6723
6724 // Nothing is recorded since B is disallowed.
6725 ExpectOutcomeDidNotChange(FROM_HERE);
6726 ExpectNotRestoredDidNotChange(FROM_HERE);
Minoru Chikamune7a588f5e2021-05-03 00:19:366727}
6728
6729// Check the allowed page is bfcached when it's navigated from disallowed
6730// page.
6731IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTestWithBlockedWebsites,
6732 NavigateFromDisallowedPageToAllowedPage) {
Minoru Chikamunedb359912021-05-14 07:04:146733 // Skip checking the AllSites metrics since BackForwardCacheMetrics stop
6734 // recording except BackForwardCache.AllSites.* metrics when the target URL is
6735 // disallowed by allowed_websites or blocked_websites.
6736 DisableCheckingMetricsForAllSites();
6737
Minoru Chikamune7a588f5e2021-05-03 00:19:366738 ASSERT_TRUE(embedded_test_server()->Start());
6739 GURL url_a(embedded_test_server()->GetURL(
6740 "a.blocked", "/back_forward_cache/disallowed_path.html"));
6741 GURL url_b(embedded_test_server()->GetURL(
6742 "b.allowed", "/back_forward_cache/allowed_path.html"));
6743
6744 // 1) Navigate to A.
6745 EXPECT_TRUE(NavigateToURL(shell(), url_a));
6746 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
6747 RenderFrameHostImpl* rfh_a = current_frame_host();
6748 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
6749
6750 // 2) Navigate to B.
6751 EXPECT_TRUE(NavigateToURL(shell(), url_b));
6752 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
6753 RenderFrameHostImpl* rfh_b = current_frame_host();
6754 RenderFrameDeletedObserver delete_observer_rfh_b(rfh_b);
6755
6756 // 3) Check if rfh_a is not stored in back-forward cache, since it matches to
Minoru Chikamunedb359912021-05-14 07:04:146757 // the blocked_websites.
Minoru Chikamune7a588f5e2021-05-03 00:19:366758 delete_observer_rfh_a.WaitUntilDeleted();
6759 EXPECT_TRUE(delete_observer_rfh_a.deleted());
6760
6761 // 4) Now go back to url_a which is not bfcached.
6762 web_contents()->GetController().GoBack();
6763 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
6764
Minoru Chikamunedb359912021-05-14 07:04:146765 // Nothing is recorded since A is disallowed.
6766 ExpectOutcomeDidNotChange(FROM_HERE);
6767 ExpectNotRestoredDidNotChange(FROM_HERE);
6768
Minoru Chikamune7a588f5e2021-05-03 00:19:366769 // 5) Check if rfh_b is stored in back-forward cache, since it doesn't match
Minoru Chikamunedb359912021-05-14 07:04:146770 // to the blocked_websites, and allowed_websites are empty, so it should
Minoru Chikamune7a588f5e2021-05-03 00:19:366771 // be stored.
6772 EXPECT_FALSE(delete_observer_rfh_b.deleted());
6773 EXPECT_TRUE(rfh_b->IsInBackForwardCache());
Minoru Chikamunedb359912021-05-14 07:04:146774
6775 // 6) Go forward to url_b which is bfcached.
6776 web_contents()->GetController().GoForward();
6777 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
6778 ExpectRestored(FROM_HERE);
Minoru Chikamune7a588f5e2021-05-03 00:19:366779}
6780
Minoru Chikamune79cda022021-05-14 07:00:386781// Test BackForwardCache::IsAllowed() with several allowed_websites URL
6782// patterns.
6783class BackForwardCacheBrowserTestForAllowedWebsitesUrlPatterns
6784 : public BackForwardCacheBrowserTest {
6785 protected:
6786 void SetUpCommandLine(base::CommandLine* command_line) override {
6787 // Sets the allowed websites for testing, additionally adding the params
6788 // used by BackForwardCacheBrowserTest.
6789 std::string allowed_websites =
6790 "https://a.com/,"
6791 "https://b.com/path,"
6792 "https://c.com/path/";
6793 EnableFeatureAndSetParams(features::kBackForwardCache, "allowed_websites",
6794 allowed_websites);
6795
6796 BackForwardCacheBrowserTest::SetUpCommandLine(command_line);
6797 }
6798};
6799
6800// Check if the URLs are allowed when allowed_websites are specified.
6801IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTestForAllowedWebsitesUrlPatterns,
6802 AllowedWebsitesUrlPatterns) {
6803 BackForwardCacheImpl& bfcache =
6804 web_contents()->GetController().GetBackForwardCache();
6805
6806 // Doesn't match with any allowed_websites.
6807 EXPECT_FALSE(bfcache.IsAllowed(GURL("https://a.org/")));
6808
6809 // Exact match with https://a.com/.
6810 EXPECT_TRUE(bfcache.IsAllowed(GURL("https://a.com/")));
6811 EXPECT_TRUE(bfcache.IsAllowed(GURL("https://a.com")));
6812
6813 // Match with https://a.com/ since we don't take into account the difference
6814 // on port number.
6815 EXPECT_TRUE(bfcache.IsAllowed(GURL("https://a.com:123/")));
6816
6817 // Match with https://a.com/ since we don't take into account the difference
6818 // on query.
6819 EXPECT_TRUE(bfcache.IsAllowed(GURL("https://a.com:123/?x=1")));
6820
6821 // Match with https://a.com/ since we don't take into account the difference
6822 // on scheme.
6823 EXPECT_TRUE(bfcache.IsAllowed(GURL("http://a.com/")));
6824
6825 // Match with https://a.com/ since we are checking the prefix on path.
6826 EXPECT_TRUE(bfcache.IsAllowed(GURL("https://a.com/path")));
6827
6828 // Doesn't match with https://a.com/ since the host doesn't match with a.com.
6829 EXPECT_FALSE(bfcache.IsAllowed(GURL("https://prefix.a.com/")));
6830
6831 // Doesn't match with https://b.com/path since the path prefix doesn't match.
6832 EXPECT_FALSE(bfcache.IsAllowed(GURL("https://b.com/")));
6833
6834 // Exact match with https://b.com/path.
6835 EXPECT_TRUE(bfcache.IsAllowed(GURL("https://b.com/path")));
6836
6837 // Match with https://b.com/path since we are checking the prefix on path.
6838 EXPECT_TRUE(bfcache.IsAllowed(GURL("https://b.com/path/")));
6839 EXPECT_TRUE(bfcache.IsAllowed(GURL("https://b.com/path_abc")));
6840 EXPECT_TRUE(bfcache.IsAllowed(GURL("https://b.com/path_abc?x=1")));
6841
6842 // Doesn't match with https://c.com/path/ since the path prefix doesn't match.
6843 EXPECT_FALSE(bfcache.IsAllowed(GURL("https://c.com/path")));
6844}
6845
6846// Test BackForwardCache::IsAllowed() with several blocked_websites URL
6847// patterns.
6848class BackForwardCacheBrowserTestForBlockedWebsitesUrlPatterns
6849 : public BackForwardCacheBrowserTest {
6850 protected:
6851 void SetUpCommandLine(base::CommandLine* command_line) override {
6852 // Sets the blocked websites for testing, additionally adding the params
6853 // used by BackForwardCacheBrowserTest.
6854 std::string blocked_websites =
6855 "https://a.com/,"
6856 "https://b.com/path,"
6857 "https://c.com/path/";
6858 EnableFeatureAndSetParams(features::kBackForwardCache, "blocked_websites",
6859 blocked_websites);
6860
6861 BackForwardCacheBrowserTest::SetUpCommandLine(command_line);
6862 }
6863};
6864
6865// Check if the URLs are allowed when blocked_websites are specified.
6866IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTestForBlockedWebsitesUrlPatterns,
6867 BlockedWebsitesUrlPatterns) {
6868 BackForwardCacheImpl& bfcache =
6869 web_contents()->GetController().GetBackForwardCache();
6870
6871 // Doesn't match with any blocked_websites.
6872 EXPECT_TRUE(bfcache.IsAllowed(GURL("https://a.org/")));
6873
6874 // Exact match with https://a.com/.
6875 EXPECT_FALSE(bfcache.IsAllowed(GURL("https://a.com/")));
6876 EXPECT_FALSE(bfcache.IsAllowed(GURL("https://a.com")));
6877
6878 // Match with https://a.com/ since we don't take into account the difference
6879 // on port number.
6880 EXPECT_FALSE(bfcache.IsAllowed(GURL("https://a.com:123/")));
6881
6882 // Match with https://a.com/ since we don't take into account the difference
6883 // on query.
6884 EXPECT_FALSE(bfcache.IsAllowed(GURL("https://a.com:123/?x=1")));
6885
6886 // Match with https://a.com/ since we don't take into account the difference
6887 // on scheme.
6888 EXPECT_FALSE(bfcache.IsAllowed(GURL("http://a.com/")));
6889
6890 // Match with https://a.com/ since we are checking the prefix on path.
6891 EXPECT_FALSE(bfcache.IsAllowed(GURL("https://a.com/path")));
6892
6893 // Doesn't match with https://a.com/ since the host doesn't match with a.com.
6894 EXPECT_TRUE(bfcache.IsAllowed(GURL("https://prefix.a.com/")));
6895
6896 // Doesn't match with https://b.com/path since the path prefix doesn't match.
6897 EXPECT_TRUE(bfcache.IsAllowed(GURL("https://b.com/")));
6898
6899 // Exact match with https://b.com/path.
6900 EXPECT_FALSE(bfcache.IsAllowed(GURL("https://b.com/path")));
6901
6902 // Match with https://b.com/path since we are checking the prefix on path.
6903 EXPECT_FALSE(bfcache.IsAllowed(GURL("https://b.com/path/")));
6904 EXPECT_FALSE(bfcache.IsAllowed(GURL("https://b.com/path_abc")));
6905 EXPECT_FALSE(bfcache.IsAllowed(GURL("https://b.com/path_abc?x=1")));
6906
6907 // Doesn't match with https://c.com/path/ since the path prefix doesn't match.
6908 EXPECT_TRUE(bfcache.IsAllowed(GURL("https://c.com/path")));
6909}
6910
6911// Test BackForwardCache::IsAllowed() with several allowed_websites and
6912// blocked_websites URL patterns.
6913class BackForwardCacheBrowserTestForWebsitesUrlPatterns
6914 : public BackForwardCacheBrowserTest {
6915 protected:
6916 void SetUpCommandLine(base::CommandLine* command_line) override {
6917 // Sets the allowed websites for testing, additionally adding the params
6918 // used by BackForwardCacheBrowserTest.
6919 std::string allowed_websites = "https://a.com/";
6920 EnableFeatureAndSetParams(features::kBackForwardCache, "allowed_websites",
6921 allowed_websites);
6922
6923 // Sets the blocked websites for testing, additionally adding the params
6924 // used by BackForwardCacheBrowserTest.
6925 std::string blocked_websites = "https://a.com/";
6926 EnableFeatureAndSetParams(features::kBackForwardCache, "blocked_websites",
6927 blocked_websites);
6928
6929 BackForwardCacheBrowserTest::SetUpCommandLine(command_line);
6930 }
6931};
6932
6933// Check if the URLs are allowed when allowed_websites and blocked_websites are
6934// specified.
6935IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTestForWebsitesUrlPatterns,
6936 WebsitesUrlPatterns) {
6937 BackForwardCacheImpl& bfcache =
6938 web_contents()->GetController().GetBackForwardCache();
6939
6940 // https://a.com/ is not allowed since blocked_websites will be prioritized
6941 // when the same website is specified in allowed_websites and
6942 // blocked_websites.
6943 EXPECT_FALSE(bfcache.IsAllowed(GURL("https://a.com/")));
6944 EXPECT_FALSE(bfcache.IsAllowed(GURL("https://a.com")));
6945}
6946
Fergal Daly24ef401c2021-05-21 04:08:516947// Test the "blocked_cgi_params" feature params in back-forward cache.
6948class BackForwardCacheBrowserTestWithBlockedCgiParams
6949 : public BackForwardCacheBrowserTest {
6950 protected:
6951 void SetUpCommandLine(base::CommandLine* command_line) override {
6952 // Sets the blocked websites for testing, additionally adding the params
6953 // used by BackForwardCacheBrowserTest.
6954 std::string blocked_cgi_params = "ibp=1|tbm=1";
6955 EnableFeatureAndSetParams(features::kBackForwardCache, "blocked_cgi_params",
6956 blocked_cgi_params);
6957
6958 BackForwardCacheBrowserTest::SetUpCommandLine(command_line);
6959 }
6960};
6961
6962// Check the disallowed page isn't bfcached when it's navigated from allowed
6963// page.
6964IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTestWithBlockedCgiParams,
6965 NavigateFromAllowedPageToDisallowedPage) {
6966 // Skip checking the AllSites metrics since BackForwardCacheMetrics stop
6967 // recording except BackForwardCache.AllSites.* metrics when the target URL is
6968 // disallowed by allowed_websites or blocked_websites.
6969 DisableCheckingMetricsForAllSites();
6970
6971 ASSERT_TRUE(embedded_test_server()->Start());
6972 GURL url_allowed(
6973 embedded_test_server()->GetURL("a.llowed", "/title1.html?tbm=0"));
6974 GURL url_not_allowed(
6975 embedded_test_server()->GetURL("nota.llowed", "/title1.html?tbm=1"));
6976
6977 // 1) Navigate to url_allowed.
6978 EXPECT_TRUE(NavigateToURL(shell(), url_allowed));
6979 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
6980 RenderFrameHostImpl* rfh_allowed = current_frame_host();
6981 RenderFrameDeletedObserver delete_observer_rfh_allowed(rfh_allowed);
6982
6983 // 2) Navigate to url_not_allowed.
6984 EXPECT_TRUE(NavigateToURL(shell(), url_not_allowed));
6985 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
6986 RenderFrameHostImpl* rfh_not_allowed = current_frame_host();
6987 RenderFrameDeletedObserver delete_observer_rfh_not_allowed(rfh_not_allowed);
6988
6989 // 3) Check that url_allowed is stored in back-forward cache.
6990 EXPECT_FALSE(delete_observer_rfh_allowed.deleted());
6991 EXPECT_TRUE(rfh_allowed->IsInBackForwardCache());
6992
6993 // 4) Now go back to url_allowed.
6994 web_contents()->GetController().GoBack();
6995 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
6996 EXPECT_EQ(rfh_allowed, current_frame_host());
6997 ExpectRestored(FROM_HERE);
6998
6999 // 5) Check that url_not_allowed is not stored in back-forward cache
7000 delete_observer_rfh_not_allowed.WaitUntilDeleted();
7001 EXPECT_TRUE(delete_observer_rfh_not_allowed.deleted());
7002
7003 // 6) Go forward to url_not_allowed, it should not be restored from the
7004 // back-forward cache.
7005 web_contents()->GetController().GoForward();
7006 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
7007
7008 // Nothing is recorded since it is disallowed.
7009 ExpectOutcomeDidNotChange(FROM_HERE);
7010 ExpectNotRestoredDidNotChange(FROM_HERE);
7011}
7012
7013// Check the allowed page is bfcached when it's navigated from disallowed
7014// page.
7015IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTestWithBlockedCgiParams,
7016 NavigateFromDisallowedPageToAllowedPage) {
7017 // Skip checking the AllSites metrics since BackForwardCacheMetrics stop
7018 // recording except BackForwardCache.AllSites.* metrics when the target URL is
7019 // disallowed by allowed_websites or blocked_websites.
7020 DisableCheckingMetricsForAllSites();
7021
7022 ASSERT_TRUE(embedded_test_server()->Start());
7023 GURL url_allowed(
7024 embedded_test_server()->GetURL("a.llowed", "/title1.html?tbm=0"));
7025 GURL url_not_allowed(
7026 embedded_test_server()->GetURL("nota.llowed", "/title1.html?tbm=1"));
7027
7028 // 1) Navigate to url_not_allowed.
7029 EXPECT_TRUE(NavigateToURL(shell(), url_not_allowed));
7030 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
7031 RenderFrameHostImpl* rfh_not_allowed = current_frame_host();
7032 RenderFrameDeletedObserver delete_observer_rfh_not_allowed(rfh_not_allowed);
7033
7034 // 2) Navigate to url_allowed.
7035 EXPECT_TRUE(NavigateToURL(shell(), url_allowed));
7036 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
7037 RenderFrameHostImpl* rfh_allowed = current_frame_host();
7038 RenderFrameDeletedObserver delete_observer_rfh_allowed(rfh_allowed);
7039
7040 // 3) Check that url_not_allowed is not stored in back-forward cache.
7041 delete_observer_rfh_not_allowed.WaitUntilDeleted();
7042 EXPECT_TRUE(delete_observer_rfh_not_allowed.deleted());
7043
7044 // 4) Now go back to url_not_allowed.
7045 web_contents()->GetController().GoBack();
7046 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
7047
7048 // Nothing is recorded since it is disallowed.
7049 ExpectOutcomeDidNotChange(FROM_HERE);
7050 ExpectNotRestoredDidNotChange(FROM_HERE);
7051
7052 // 5) Check that url_allowed is stored in back-forward cache
7053 EXPECT_FALSE(delete_observer_rfh_allowed.deleted());
7054 EXPECT_TRUE(rfh_allowed->IsInBackForwardCache());
7055
7056 // 6) Go forward to url_allowed, it should be restored from the
7057 // back-forward cache.
7058 web_contents()->GetController().GoForward();
7059 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
7060 ExpectRestored(FROM_HERE);
7061}
7062
Rakina Zata Amni347b70902020-07-22 10:49:047063// Check that if WebPreferences was changed while a page was bfcached, it will
7064// get up-to-date WebPreferences when it was restored.
7065IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, WebPreferences) {
7066 ASSERT_TRUE(embedded_test_server()->Start());
7067 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
7068 GURL url_b(embedded_test_server()->GetURL("b.com", "/title2.html"));
7069
7070 // 1) Navigate to A.
7071 EXPECT_TRUE(NavigateToURL(shell(), url_a));
7072 RenderFrameHostImpl* rfh_a = current_frame_host();
Lukasz Anforowicz15ba43e2021-07-21 22:50:097073 auto browsing_instance_id = rfh_a->GetSiteInstance()->GetBrowsingInstanceId();
Rakina Zata Amni347b70902020-07-22 10:49:047074
7075 // A should prefer light color scheme (which is the default).
Avi Drissmanc91bd8e2021-04-19 23:58:447076 EXPECT_EQ(
7077 true,
7078 EvalJs(web_contents(),
7079 "window.matchMedia('(prefers-color-scheme: light)').matches"));
Rakina Zata Amni347b70902020-07-22 10:49:047080
7081 // 2) Navigate to B. A should be stored in the back-forward cache.
7082 EXPECT_TRUE(NavigateToURL(shell(), url_b));
7083 RenderFrameHostImpl* rfh_b = current_frame_host();
7084 EXPECT_NE(browsing_instance_id,
7085 rfh_b->GetSiteInstance()->GetBrowsingInstanceId());
7086 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
7087 EXPECT_NE(rfh_a, rfh_b);
7088
Gyuyoung Kim1ac4ca782020-09-11 03:32:517089 blink::web_pref::WebPreferences prefs =
7090 web_contents()->GetOrCreateWebPreferences();
Gyuyoung Kim0746a012020-10-08 23:34:507091 prefs.preferred_color_scheme = blink::mojom::PreferredColorScheme::kDark;
Rakina Zata Amni347b70902020-07-22 10:49:047092 web_contents()->SetWebPreferences(prefs);
7093
7094 // 3) Set WebPreferences to prefer dark color scheme.
Avi Drissmanc91bd8e2021-04-19 23:58:447095 EXPECT_EQ(
7096 true,
7097 EvalJs(web_contents(),
7098 "window.matchMedia('(prefers-color-scheme: dark)').matches"));
7099
Rakina Zata Amni347b70902020-07-22 10:49:047100 // 4) Go back to A, which should also prefer the dark color scheme now.
7101 web_contents()->GetController().GoBack();
7102 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
7103 EXPECT_EQ(rfh_a, current_frame_host());
7104
Avi Drissmanc91bd8e2021-04-19 23:58:447105 EXPECT_EQ(
7106 true,
7107 EvalJs(web_contents(),
7108 "window.matchMedia('(prefers-color-scheme: dark)').matches"));
Rakina Zata Amni347b70902020-07-22 10:49:047109}
7110
Yuzu Saijo3f86fb22020-06-11 03:51:107111// Check the BackForwardCache is disabled when there is a nested WebContents
7112// inside a page.
7113IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, NestedWebContents) {
7114 // 1) Navigate to a page.
7115 ASSERT_TRUE(embedded_test_server()->Start());
7116 GURL url(embedded_test_server()->GetURL("a.com", "/page_with_iframe.html"));
7117
7118 EXPECT_TRUE(NavigateToURL(shell(), url));
7119
7120 RenderFrameHostImpl* rfh_a = current_frame_host();
7121 RenderFrameHostImpl* child = rfh_a->child_at(0)->current_frame_host();
7122 EXPECT_TRUE(child);
7123
7124 // Create and attach an inner WebContents.
7125 CreateAndAttachInnerContents(child);
7126 RenderFrameDeletedObserver deleted(rfh_a);
7127
7128 // 2) Navigate away.
7129 shell()->LoadURL(embedded_test_server()->GetURL("b.com", "/title1.html"));
7130 // The page has an inner WebContents so it should be deleted.
7131 deleted.WaitUntilDeleted();
7132
7133 // 3) Go back to the page with an inner WebContents.
7134 web_contents()->GetController().GoBack();
7135 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
7136 ExpectNotRestored(
Fergal Daly6755cbf2021-02-12 03:06:587137 {BackForwardCacheMetrics::NotRestoredReason::kHaveInnerContents}, {}, {},
7138 {}, FROM_HERE);
Yuzu Saijo3f86fb22020-06-11 03:51:107139}
7140
Fergal Dalydd2190472021-03-25 09:14:257141IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, WebBluetooth) {
7142 // The test requires a mock Bluetooth adapter to perform a
7143 // WebBluetooth API call. To avoid conflicts with the default Bluetooth
7144 // adapter, e.g. Windows adapter, which is configured during Bluetooth
7145 // initialization, the mock adapter is configured in SetUp().
7146
7147 // WebBluetooth requires HTTPS.
7148 ASSERT_TRUE(CreateHttpsServer()->Start());
7149 GURL url(https_server()->GetURL("a.com", "/back_forward_cache/empty.html"));
7150
7151 ASSERT_TRUE(NavigateToURL(web_contents(), url));
7152 BackForwardCacheDisabledTester tester;
7153
7154 EXPECT_EQ("device not found", EvalJs(current_frame_host(), R"(
7155 new Promise(resolve => {
7156 navigator.bluetooth.requestDevice({
7157 filters: [
7158 { services: [0x1802, 0x1803] },
7159 ]
7160 })
7161 .then(() => resolve("device found"))
7162 .catch(() => resolve("device not found"))
7163 });
7164 )"));
Fergal Daly23b8ae62021-03-30 05:43:467165 auto reason = BackForwardCacheDisable::DisabledReason(
7166 BackForwardCacheDisable::DisabledReasonId::kWebBluetooth);
Fergal Dalydd2190472021-03-25 09:14:257167 EXPECT_TRUE(tester.IsDisabledForFrameWithReason(
7168 current_frame_host()->GetProcess()->GetID(),
Fergal Daly23b8ae62021-03-30 05:43:467169 current_frame_host()->GetRoutingID(), reason));
Fergal Dalydd2190472021-03-25 09:14:257170
7171 ASSERT_TRUE(NavigateToURL(web_contents(),
7172 https_server()->GetURL("b.com", "/title1.html")));
7173 web_contents()->GetController().GoBack();
7174 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
7175 ExpectNotRestored({BackForwardCacheMetrics::NotRestoredReason::
7176 kDisableForRenderFrameHostCalled},
Fergal Daly23b8ae62021-03-30 05:43:467177 {}, {}, {reason}, FROM_HERE);
Fergal Dalydd2190472021-03-25 09:14:257178}
7179
arthursonzognibec31272019-10-09 11:51:217180// Check the BackForwardCache is disabled when the WebUSB feature is used.
7181IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, WebUSB) {
7182 // WebUSB requires HTTPS.
Fergal Daly637c4522019-11-22 00:21:317183 ASSERT_TRUE(CreateHttpsServer()->Start());
arthursonzognibec31272019-10-09 11:51:217184
Fergal Daly23b8ae62021-03-30 05:43:467185 auto web_usb_reason = BackForwardCacheDisable::DisabledReason(
7186 BackForwardCacheDisable::DisabledReasonId::kWebUSB);
7187
arthursonzognibec31272019-10-09 11:51:217188 // Main document.
7189 {
7190 content::BackForwardCacheDisabledTester tester;
Fergal Daly637c4522019-11-22 00:21:317191 GURL url(https_server()->GetURL("a.com", "/title1.html"));
arthursonzognibec31272019-10-09 11:51:217192
7193 EXPECT_TRUE(NavigateToURL(shell(), url));
7194
Hajime Hoshib03d6ddf52019-11-21 09:41:247195 EXPECT_FALSE(current_frame_host()->IsBackForwardCacheDisabled());
arthursonzognibec31272019-10-09 11:51:217196 EXPECT_EQ("Found 0 devices", content::EvalJs(current_frame_host(), R"(
7197 new Promise(async resolve => {
7198 let devices = await navigator.usb.getDevices();
7199 resolve("Found " + devices.length + " devices");
7200 });
7201 )"));
Hajime Hoshib03d6ddf52019-11-21 09:41:247202 EXPECT_TRUE(current_frame_host()->IsBackForwardCacheDisabled());
arthursonzognibec31272019-10-09 11:51:217203 EXPECT_TRUE(tester.IsDisabledForFrameWithReason(
7204 current_frame_host()->GetProcess()->GetID(),
Fergal Daly23b8ae62021-03-30 05:43:467205 current_frame_host()->GetRoutingID(), web_usb_reason));
arthursonzognibec31272019-10-09 11:51:217206 }
7207
7208 // Nested document.
7209 {
7210 content::BackForwardCacheDisabledTester tester;
Fergal Daly637c4522019-11-22 00:21:317211 GURL url(https_server()->GetURL("c.com",
7212 "/cross_site_iframe_factory.html?c(d)"));
arthursonzognibec31272019-10-09 11:51:217213 EXPECT_TRUE(NavigateToURL(shell(), url));
7214 RenderFrameHostImpl* rfh_c = current_frame_host();
7215 RenderFrameHostImpl* rfh_d = rfh_c->child_at(0)->current_frame_host();
7216
Hajime Hoshib03d6ddf52019-11-21 09:41:247217 EXPECT_FALSE(rfh_c->IsBackForwardCacheDisabled());
7218 EXPECT_FALSE(rfh_d->IsBackForwardCacheDisabled());
arthursonzognibec31272019-10-09 11:51:217219 EXPECT_EQ("Found 0 devices", content::EvalJs(rfh_c, R"(
7220 new Promise(async resolve => {
7221 let devices = await navigator.usb.getDevices();
7222 resolve("Found " + devices.length + " devices");
7223 });
7224 )"));
Hajime Hoshib03d6ddf52019-11-21 09:41:247225 EXPECT_TRUE(rfh_c->IsBackForwardCacheDisabled());
7226 EXPECT_FALSE(rfh_d->IsBackForwardCacheDisabled());
arthursonzognibec31272019-10-09 11:51:217227 EXPECT_TRUE(tester.IsDisabledForFrameWithReason(
Fergal Daly23b8ae62021-03-30 05:43:467228 rfh_c->GetProcess()->GetID(), rfh_c->GetRoutingID(), web_usb_reason));
arthursonzognibec31272019-10-09 11:51:217229 }
7230
7231 // Worker.
7232 {
7233 content::BackForwardCacheDisabledTester tester;
Fergal Daly637c4522019-11-22 00:21:317234 GURL url(https_server()->GetURL("e.com", "/title1.html"));
arthursonzognibec31272019-10-09 11:51:217235 EXPECT_TRUE(NavigateToURL(shell(), url));
Hajime Hoshib03d6ddf52019-11-21 09:41:247236 EXPECT_FALSE(current_frame_host()->IsBackForwardCacheDisabled());
arthursonzognibec31272019-10-09 11:51:217237 EXPECT_EQ("Found 0 devices", content::EvalJs(current_frame_host(), R"(
7238 new Promise(async resolve => {
7239 const worker = new Worker("/back_forward_cache/webusb/worker.js");
7240 worker.onmessage = message => resolve(message.data);
7241 worker.postMessage("Run");
7242 });
7243 )"));
Hajime Hoshib03d6ddf52019-11-21 09:41:247244 EXPECT_TRUE(current_frame_host()->IsBackForwardCacheDisabled());
arthursonzognibec31272019-10-09 11:51:217245 EXPECT_TRUE(tester.IsDisabledForFrameWithReason(
7246 current_frame_host()->GetProcess()->GetID(),
Fergal Daly23b8ae62021-03-30 05:43:467247 current_frame_host()->GetRoutingID(), web_usb_reason));
arthursonzognibec31272019-10-09 11:51:217248 }
7249
7250 // Nested worker.
7251 {
7252 content::BackForwardCacheDisabledTester tester;
Fergal Daly637c4522019-11-22 00:21:317253 GURL url(https_server()->GetURL("f.com", "/title1.html"));
arthursonzognibec31272019-10-09 11:51:217254 EXPECT_TRUE(NavigateToURL(shell(), url));
Hajime Hoshib03d6ddf52019-11-21 09:41:247255 EXPECT_FALSE(current_frame_host()->IsBackForwardCacheDisabled());
arthursonzognibec31272019-10-09 11:51:217256 EXPECT_EQ("Found 0 devices", content::EvalJs(current_frame_host(), R"(
7257 new Promise(async resolve => {
7258 const worker = new Worker(
7259 "/back_forward_cache/webusb/nested-worker.js");
7260 worker.onmessage = message => resolve(message.data);
7261 worker.postMessage("Run");
7262 });
7263 )"));
Hajime Hoshib03d6ddf52019-11-21 09:41:247264 EXPECT_TRUE(current_frame_host()->IsBackForwardCacheDisabled());
arthursonzognibec31272019-10-09 11:51:217265 EXPECT_TRUE(tester.IsDisabledForFrameWithReason(
7266 current_frame_host()->GetProcess()->GetID(),
Fergal Daly23b8ae62021-03-30 05:43:467267 current_frame_host()->GetRoutingID(), web_usb_reason));
arthursonzognibec31272019-10-09 11:51:217268 }
7269}
7270
Rakina Zata Amni06343cc2019-10-11 01:33:237271#if !defined(OS_ANDROID)
7272// Check that the back-forward cache is disabled when the Serial API is used.
7273IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, Serial) {
7274 // Serial API requires HTTPS.
Fergal Daly637c4522019-11-22 00:21:317275 ASSERT_TRUE(CreateHttpsServer()->Start());
Rakina Zata Amni06343cc2019-10-11 01:33:237276
Fergal Daly23b8ae62021-03-30 05:43:467277 auto serial_reason = BackForwardCacheDisable::DisabledReason(
7278 BackForwardCacheDisable::DisabledReasonId::kSerial);
Rakina Zata Amni06343cc2019-10-11 01:33:237279 // Main document.
7280 {
7281 content::BackForwardCacheDisabledTester tester;
Fergal Daly637c4522019-11-22 00:21:317282 GURL url(https_server()->GetURL("a.com", "/title1.html"));
Rakina Zata Amni06343cc2019-10-11 01:33:237283
7284 EXPECT_TRUE(NavigateToURL(shell(), url));
7285
Hajime Hoshib03d6ddf52019-11-21 09:41:247286 EXPECT_FALSE(current_frame_host()->IsBackForwardCacheDisabled());
Rakina Zata Amni06343cc2019-10-11 01:33:237287 EXPECT_EQ("Found 0 ports", content::EvalJs(current_frame_host(), R"(
7288 new Promise(async resolve => {
7289 let ports = await navigator.serial.getPorts();
7290 resolve("Found " + ports.length + " ports");
7291 });
7292 )"));
Hajime Hoshib03d6ddf52019-11-21 09:41:247293 EXPECT_TRUE(current_frame_host()->IsBackForwardCacheDisabled());
Rakina Zata Amni06343cc2019-10-11 01:33:237294 EXPECT_TRUE(tester.IsDisabledForFrameWithReason(
7295 current_frame_host()->GetProcess()->GetID(),
Fergal Daly23b8ae62021-03-30 05:43:467296 current_frame_host()->GetRoutingID(), serial_reason));
Rakina Zata Amni06343cc2019-10-11 01:33:237297 }
7298
7299 // Nested document.
7300 {
7301 content::BackForwardCacheDisabledTester tester;
Fergal Daly637c4522019-11-22 00:21:317302 GURL url(https_server()->GetURL("c.com",
7303 "/cross_site_iframe_factory.html?c(d)"));
Rakina Zata Amni06343cc2019-10-11 01:33:237304 EXPECT_TRUE(NavigateToURL(shell(), url));
7305 RenderFrameHostImpl* rfh_c = current_frame_host();
7306 RenderFrameHostImpl* rfh_d = rfh_c->child_at(0)->current_frame_host();
7307
Hajime Hoshib03d6ddf52019-11-21 09:41:247308 EXPECT_FALSE(rfh_c->IsBackForwardCacheDisabled());
7309 EXPECT_FALSE(rfh_d->IsBackForwardCacheDisabled());
Rakina Zata Amni06343cc2019-10-11 01:33:237310 EXPECT_EQ("Found 0 ports", content::EvalJs(rfh_c, R"(
7311 new Promise(async resolve => {
7312 let ports = await navigator.serial.getPorts();
7313 resolve("Found " + ports.length + " ports");
7314 });
7315 )"));
Hajime Hoshib03d6ddf52019-11-21 09:41:247316 EXPECT_TRUE(rfh_c->IsBackForwardCacheDisabled());
7317 EXPECT_FALSE(rfh_d->IsBackForwardCacheDisabled());
Rakina Zata Amni06343cc2019-10-11 01:33:237318 EXPECT_TRUE(tester.IsDisabledForFrameWithReason(
Fergal Daly23b8ae62021-03-30 05:43:467319 rfh_c->GetProcess()->GetID(), rfh_c->GetRoutingID(), serial_reason));
Rakina Zata Amni06343cc2019-10-11 01:33:237320 }
7321
7322 // Worker.
7323 {
7324 content::BackForwardCacheDisabledTester tester;
Fergal Daly637c4522019-11-22 00:21:317325 GURL url(https_server()->GetURL("e.com", "/title1.html"));
Rakina Zata Amni06343cc2019-10-11 01:33:237326 EXPECT_TRUE(NavigateToURL(shell(), url));
Hajime Hoshib03d6ddf52019-11-21 09:41:247327 EXPECT_FALSE(current_frame_host()->IsBackForwardCacheDisabled());
Rakina Zata Amni06343cc2019-10-11 01:33:237328 EXPECT_EQ("Found 0 ports", content::EvalJs(current_frame_host(), R"(
7329 new Promise(async resolve => {
7330 const worker = new Worker("/back_forward_cache/serial/worker.js");
7331 worker.onmessage = message => resolve(message.data);
7332 worker.postMessage("Run");
7333 });
7334 )"));
Hajime Hoshib03d6ddf52019-11-21 09:41:247335 EXPECT_TRUE(current_frame_host()->IsBackForwardCacheDisabled());
Rakina Zata Amni06343cc2019-10-11 01:33:237336 EXPECT_TRUE(tester.IsDisabledForFrameWithReason(
7337 current_frame_host()->GetProcess()->GetID(),
Fergal Daly23b8ae62021-03-30 05:43:467338 current_frame_host()->GetRoutingID(), serial_reason));
Rakina Zata Amni06343cc2019-10-11 01:33:237339 }
7340
7341 // Nested worker.
7342 {
7343 content::BackForwardCacheDisabledTester tester;
Fergal Daly637c4522019-11-22 00:21:317344 GURL url(https_server()->GetURL("f.com", "/title1.html"));
Rakina Zata Amni06343cc2019-10-11 01:33:237345 EXPECT_TRUE(NavigateToURL(shell(), url));
Hajime Hoshib03d6ddf52019-11-21 09:41:247346 EXPECT_FALSE(current_frame_host()->IsBackForwardCacheDisabled());
Rakina Zata Amni06343cc2019-10-11 01:33:237347 EXPECT_EQ("Found 0 ports", content::EvalJs(current_frame_host(), R"(
7348 new Promise(async resolve => {
7349 const worker = new Worker(
7350 "/back_forward_cache/serial/nested-worker.js");
7351 worker.onmessage = message => resolve(message.data);
7352 worker.postMessage("Run");
7353 });
7354 )"));
Hajime Hoshib03d6ddf52019-11-21 09:41:247355 EXPECT_TRUE(current_frame_host()->IsBackForwardCacheDisabled());
Rakina Zata Amni06343cc2019-10-11 01:33:237356 EXPECT_TRUE(tester.IsDisabledForFrameWithReason(
7357 current_frame_host()->GetProcess()->GetID(),
Fergal Daly23b8ae62021-03-30 05:43:467358 current_frame_host()->GetRoutingID(), serial_reason));
Rakina Zata Amni06343cc2019-10-11 01:33:237359 }
7360}
7361#endif
7362
Alexander Timine5f20e22019-10-09 23:22:357363IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, Encoding) {
7364 ASSERT_TRUE(embedded_test_server()->Start());
arthursonzogni72b66492019-11-04 12:24:337365 GURL url_a(embedded_test_server()->GetURL(
Alexander Timine5f20e22019-10-09 23:22:357366 "a.com", "/back_forward_cache/charset_windows-1250.html"));
arthursonzogni72b66492019-11-04 12:24:337367 GURL url_b(embedded_test_server()->GetURL(
Alexander Timine5f20e22019-10-09 23:22:357368 "b.com", "/back_forward_cache/charset_utf-8.html"));
arthursonzogni72b66492019-11-04 12:24:337369 url::Origin origin_a = url::Origin::Create(url_a);
7370 url::Origin origin_b = url::Origin::Create(url_b);
Alexander Timine5f20e22019-10-09 23:22:357371
7372 EXPECT_TRUE(NavigateToURL(shell(), url_a));
7373 RenderFrameHostImpl* rfh_a = current_frame_host();
7374 EXPECT_EQ(web_contents()->GetEncoding(), "windows-1250");
7375
7376 EXPECT_TRUE(NavigateToURL(shell(), url_b));
Hajime Hoshibbc509c2020-04-06 08:55:087377 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
Alexander Timine5f20e22019-10-09 23:22:357378 EXPECT_EQ(web_contents()->GetEncoding(), "UTF-8");
7379
7380 web_contents()->GetController().GoBack();
7381 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
7382 EXPECT_EQ(web_contents()->GetEncoding(), "windows-1250");
7383}
7384
Alexander Timin84fcc8e2019-10-16 17:31:557385IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, RestoreWhilePendingCommit) {
7386 net::test_server::ControllableHttpResponse response(embedded_test_server(),
7387 "/main_document");
7388 ASSERT_TRUE(embedded_test_server()->Start());
arthursonzogni72b66492019-11-04 12:24:337389 GURL url1(embedded_test_server()->GetURL("a.com", "/title1.html"));
7390 GURL url2(embedded_test_server()->GetURL("b.com", "/title2.html"));
7391 GURL url3(embedded_test_server()->GetURL("c.com", "/main_document"));
Alexander Timin84fcc8e2019-10-16 17:31:557392
7393 // Load a page and navigate away from it, so it is stored in the back-forward
7394 // cache.
7395 EXPECT_TRUE(NavigateToURL(shell(), url1));
7396 RenderFrameHost* rfh1 = current_frame_host();
7397 EXPECT_TRUE(NavigateToURL(shell(), url2));
7398
7399 // Try to navigate to a new page, but leave it in a pending state.
7400 shell()->LoadURL(url3);
7401 response.WaitForRequest();
7402
7403 // Navigate back and restore page from the cache, cancelling the previous
7404 // navigation.
7405 web_contents()->GetController().GoBack();
7406 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
7407 EXPECT_EQ(rfh1, current_frame_host());
7408}
7409
Lowell Manners7e027932019-10-17 11:39:587410IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
7411 DoesNotCacheCrossSiteHttpPost) {
7412 SetupCrossSiteRedirector(embedded_test_server());
7413 ASSERT_TRUE(embedded_test_server()->Start());
7414
7415 // Note we do a cross-site post because same-site navigations of any kind
7416 // aren't cached currently.
7417 GURL form_url(embedded_test_server()->GetURL(
7418 "a.com", "/form_that_posts_cross_site.html"));
7419 GURL redirect_target_url(embedded_test_server()->GetURL("x.com", "/echoall"));
7420 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
7421
7422 // Navigate to the page with form that posts via 307 redirection to
7423 // |redirect_target_url| (cross-site from |form_url|).
7424 EXPECT_TRUE(NavigateToURL(shell(), form_url));
7425
7426 // Submit the form.
7427 TestNavigationObserver form_post_observer(shell()->web_contents(), 1);
7428 EXPECT_TRUE(ExecJs(shell(), "document.getElementById('text-form').submit()"));
7429 form_post_observer.Wait();
7430
7431 // Verify that we arrived at the expected, redirected location.
7432 EXPECT_EQ(redirect_target_url,
7433 shell()->web_contents()->GetLastCommittedURL());
7434 RenderFrameDeletedObserver delete_observer_rfh(current_frame_host());
7435
7436 // Navigate away. |redirect_target_url|'s page should not be cached.
7437 EXPECT_TRUE(NavigateToURL(shell(), url_b));
7438 delete_observer_rfh.WaitUntilDeleted();
7439}
7440
Alexander Timin10d794372019-10-18 01:48:367441namespace {
7442
7443const char kResponseWithNoCache[] =
7444 "HTTP/1.1 200 OK\r\n"
7445 "Content-Type: text/html; charset=utf-8\r\n"
7446 "Cache-Control: no-store\r\n"
7447 "\r\n"
7448 "The server speaks HTTP!";
7449
7450} // namespace
7451
7452IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
7453 MainFrameWithNoStoreNotCached) {
7454 net::test_server::ControllableHttpResponse response(embedded_test_server(),
7455 "/main_document");
7456 ASSERT_TRUE(embedded_test_server()->Start());
7457
7458 GURL url_a(embedded_test_server()->GetURL("a.com", "/main_document"));
7459 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
7460
7461 // 1. Load the document and specify no-store for the main resource.
7462 TestNavigationObserver observer(web_contents());
7463 shell()->LoadURL(url_a);
7464 response.WaitForRequest();
7465 response.Send(kResponseWithNoCache);
7466 response.Done();
7467 observer.Wait();
7468
7469 // 2. Navigate away and expect frame to be deleted.
7470 RenderFrameDeletedObserver delete_observer_rfh_a(current_frame_host());
7471 EXPECT_TRUE(NavigateToURL(shell(), url_b));
7472 delete_observer_rfh_a.WaitUntilDeleted();
7473}
7474
Takumi Fujimoto4b9a759b2020-08-14 00:43:147475// Disabled for being flaky. See crbug.com/1116190.
7476IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
7477 DISABLED_SubframeWithNoStoreCached) {
Alexander Timin10d794372019-10-18 01:48:367478 // iframe will try to load title1.html.
7479 net::test_server::ControllableHttpResponse response(embedded_test_server(),
7480 "/title1.html");
7481 ASSERT_TRUE(embedded_test_server()->Start());
7482
7483 GURL url_a(embedded_test_server()->GetURL("a.com", "/page_with_iframe.html"));
7484 GURL url_b(embedded_test_server()->GetURL("b.com", "/title2.html"));
7485
7486 // 1) Load the document and specify no-store for the main resource.
7487 TestNavigationObserver observer(web_contents());
7488 shell()->LoadURL(url_a);
7489 response.WaitForRequest();
7490 response.Send(kResponseWithNoCache);
7491 response.Done();
7492 observer.Wait();
7493 RenderFrameHostImpl* rfh_a = current_frame_host();
7494 RenderFrameDeletedObserver delete_observer_rfh_a(current_frame_host());
7495
7496 // 2) Navigate away.
7497 EXPECT_TRUE(NavigateToURL(shell(), url_b));
7498
7499 // 3) Navigate back and expect everything to be restored.
7500 web_contents()->GetController().GoBack();
7501 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
7502 EXPECT_FALSE(delete_observer_rfh_a.deleted());
7503 EXPECT_EQ(rfh_a, current_frame_host());
7504}
7505
Fergal Daly87f79d62019-11-11 01:24:047506// On windows, the expected value is off by ~20ms. In order to get the
7507// feature out to canary, the test is disabled for WIN.
7508// TODO(crbug.com/1022191): Fix this for Win.
Katie Dektar72cc7362021-05-20 19:20:497509// TODO(crbug.com/1211428): Flaky on other platforms.
Fergal Daly87f79d62019-11-11 01:24:047510// Make sure we are exposing the duration between back navigation's
7511// navigationStart and the page's original navigationStart through pageshow
7512// event's timeStamp, and that we aren't modifying
7513// performance.timing.navigationStart.
Katie Dektar72cc7362021-05-20 19:20:497514IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, DISABLED_NavigationStart) {
Fergal Daly87f79d62019-11-11 01:24:047515 ASSERT_TRUE(embedded_test_server()->Start());
7516 GURL url_a(embedded_test_server()->GetURL(
7517 "a.com", "/back_forward_cache/record_navigation_start_time_stamp.html"));
7518 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
7519
7520 // 1) Navigate to A.
7521 EXPECT_TRUE(NavigateToURL(shell(), url_a));
7522 RenderFrameHostImpl* rfh_a = current_frame_host();
7523 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
7524
7525 double initial_page_show_time_stamp =
7526 EvalJs(shell(), "window.initialPageShowTimeStamp").ExtractDouble();
Fergal Daly57c15332021-04-06 09:22:017527 EXPECT_DOUBLE_EQ(
7528 initial_page_show_time_stamp,
7529 EvalJs(shell(), "window.latestPageShowTimeStamp").ExtractDouble());
Fergal Daly87f79d62019-11-11 01:24:047530 double initial_navigation_start =
7531 EvalJs(shell(), "window.initialNavigationStart").ExtractDouble();
7532
7533 // 2) Navigate to B. A should be in the back forward cache.
7534 EXPECT_TRUE(NavigateToURL(shell(), url_b));
7535 EXPECT_FALSE(delete_observer_rfh_a.deleted());
Hajime Hoshibbc509c2020-04-06 08:55:087536 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
Fergal Daly87f79d62019-11-11 01:24:047537
7538 // 3) Navigate back and expect everything to be restored.
7539 NavigationHandleObserver observer(web_contents(), url_a);
7540 base::TimeTicks time_before_navigation = base::TimeTicks::Now();
7541 double js_time_before_navigation =
7542 EvalJs(shell(), "performance.now()").ExtractDouble();
7543 web_contents()->GetController().GoBack();
7544 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
7545 base::TimeTicks time_after_navigation = base::TimeTicks::Now();
7546 double js_time_after_navigation =
7547 EvalJs(shell(), "performance.now()").ExtractDouble();
7548
7549 // The navigation start time should be between the time we saved just before
7550 // calling GoBack() and the time we saved just after calling GoBack().
7551 base::TimeTicks back_navigation_start = observer.navigation_start();
7552 EXPECT_LT(time_before_navigation, back_navigation_start);
7553 EXPECT_GT(time_after_navigation, back_navigation_start);
7554
7555 // Check JS values. window.initialNavigationStart should not change.
Fergal Daly57c15332021-04-06 09:22:017556 EXPECT_DOUBLE_EQ(
7557 initial_navigation_start,
7558 EvalJs(shell(), "window.initialNavigationStart").ExtractDouble());
Fergal Daly87f79d62019-11-11 01:24:047559 // performance.timing.navigationStart should not change.
Fergal Daly57c15332021-04-06 09:22:017560 EXPECT_DOUBLE_EQ(
7561 initial_navigation_start,
7562 EvalJs(shell(), "performance.timing.navigationStart").ExtractDouble());
Fergal Daly87f79d62019-11-11 01:24:047563 // window.initialPageShowTimeStamp should not change.
Fergal Daly57c15332021-04-06 09:22:017564 EXPECT_DOUBLE_EQ(
7565 initial_page_show_time_stamp,
7566 EvalJs(shell(), "window.initialPageShowTimeStamp").ExtractDouble());
Fergal Daly87f79d62019-11-11 01:24:047567 // window.latestPageShowTimeStamp should be updated with the timestamp of the
7568 // last pageshow event, which occurs after the page is restored. This should
7569 // be greater than the initial pageshow event's timestamp.
7570 double latest_page_show_time_stamp =
7571 EvalJs(shell(), "window.latestPageShowTimeStamp").ExtractDouble();
7572 EXPECT_LT(initial_page_show_time_stamp, latest_page_show_time_stamp);
7573
7574 // |latest_page_show_time_stamp| should be the duration between initial
7575 // navigation start and |back_navigation_start|. Note that since
7576 // performance.timing.navigationStart returns a 64-bit integer instead of
7577 // double, we might be losing somewhere between 0 to 1 milliseconds of
7578 // precision, hence the usage of EXPECT_NEAR.
7579 EXPECT_NEAR(
7580 (back_navigation_start - base::TimeTicks::UnixEpoch()).InMillisecondsF(),
7581 latest_page_show_time_stamp + initial_navigation_start, 1.0);
7582 // Expect that the back navigation start value calculated from the JS results
7583 // are between time taken before & after navigation, just like
7584 // |before_navigation_start|.
7585 EXPECT_LT(js_time_before_navigation, latest_page_show_time_stamp);
7586 EXPECT_GT(js_time_after_navigation, latest_page_show_time_stamp);
7587}
7588
Carlos Caballero2380e022019-10-30 18:27:187589// Do a same document navigation and make sure we do not fire the
7590// DidFirstVisuallyNonEmptyPaint again
Carlos Caballero91fffb22019-10-29 15:24:307591IN_PROC_BROWSER_TEST_F(
7592 BackForwardCacheBrowserTest,
Carlos Caballero2380e022019-10-30 18:27:187593 DoesNotFireDidFirstVisuallyNonEmptyPaintForSameDocumentNavigation) {
Carlos Caballero91fffb22019-10-29 15:24:307594 ASSERT_TRUE(embedded_test_server()->Start());
arthursonzogni72b66492019-11-04 12:24:337595 GURL url_a_1(embedded_test_server()->GetURL(
Carlos Caballero91fffb22019-10-29 15:24:307596 "a.com", "/accessibility/html/a-name.html"));
arthursonzogni72b66492019-11-04 12:24:337597 GURL url_a_2(embedded_test_server()->GetURL(
Carlos Caballero91fffb22019-10-29 15:24:307598 "a.com", "/accessibility/html/a-name.html#id"));
Carlos Caballero91fffb22019-10-29 15:24:307599
7600 EXPECT_TRUE(NavigateToURL(shell(), url_a_1));
7601 WaitForFirstVisuallyNonEmptyPaint(shell()->web_contents());
Carlos Caballero91fffb22019-10-29 15:24:307602
7603 FirstVisuallyNonEmptyPaintObserver observer(web_contents());
7604 EXPECT_TRUE(NavigateToURL(shell(), url_a_2));
7605 // Make sure the bfcache restore code does not fire the event during commit
7606 // navigation.
7607 EXPECT_FALSE(observer.did_fire());
Carlos Caballero2380e022019-10-30 18:27:187608 EXPECT_TRUE(web_contents()->CompletedFirstVisuallyNonEmptyPaint());
Carlos Caballero91fffb22019-10-29 15:24:307609}
7610
7611// Make sure we fire DidFirstVisuallyNonEmptyPaint when restoring from bf-cache.
7612IN_PROC_BROWSER_TEST_F(
7613 BackForwardCacheBrowserTest,
7614 FiresDidFirstVisuallyNonEmptyPaintWhenRestoredFromCache) {
7615 ASSERT_TRUE(embedded_test_server()->Start());
arthursonzogni72b66492019-11-04 12:24:337616 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
7617 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
Carlos Caballero91fffb22019-10-29 15:24:307618
7619 // 1) Navigate to A.
7620 EXPECT_TRUE(NavigateToURL(shell(), url_a));
7621 WaitForFirstVisuallyNonEmptyPaint(shell()->web_contents());
7622 RenderFrameHostImpl* rfh_a = current_frame_host();
Carlos Caballeroddf98dc2019-10-30 19:00:477623 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
Carlos Caballero91fffb22019-10-29 15:24:307624
7625 // 2) Navigate to B.
7626 EXPECT_TRUE(NavigateToURL(shell(), url_b));
Carlos Caballeroddf98dc2019-10-30 19:00:477627 ASSERT_FALSE(delete_observer_rfh_a.deleted());
Hajime Hoshibbc509c2020-04-06 08:55:087628 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
Carlos Caballero91fffb22019-10-29 15:24:307629 WaitForFirstVisuallyNonEmptyPaint(shell()->web_contents());
7630
7631 // 3) Navigate to back to A.
7632 FirstVisuallyNonEmptyPaintObserver observer(web_contents());
7633 web_contents()->GetController().GoBack();
7634 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
7635 // Make sure the bfcache restore code does fire the event during commit
7636 // navigation.
7637 EXPECT_TRUE(web_contents()->CompletedFirstVisuallyNonEmptyPaint());
7638 EXPECT_TRUE(observer.did_fire());
7639}
7640
Carlos Caballero1215f882019-10-29 15:58:437641IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
7642 SetsThemeColorWhenRestoredFromCache) {
7643 ASSERT_TRUE(embedded_test_server()->Start());
arthursonzogni72b66492019-11-04 12:24:337644 GURL url_a(embedded_test_server()->GetURL("a.com", "/theme_color.html"));
7645 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
Carlos Caballero1215f882019-10-29 15:58:437646
7647 EXPECT_TRUE(NavigateToURL(shell(), url_a));
7648 WaitForFirstVisuallyNonEmptyPaint(web_contents());
7649 RenderFrameHostImpl* rfh_a = current_frame_host();
Carlos Caballeroddf98dc2019-10-30 19:00:477650 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
Carlos Caballero1215f882019-10-29 15:58:437651 EXPECT_EQ(web_contents()->GetThemeColor(), 0xFFFF0000u);
7652
7653 EXPECT_TRUE(NavigateToURL(shell(), url_b));
7654 WaitForFirstVisuallyNonEmptyPaint(web_contents());
Carlos Caballeroddf98dc2019-10-30 19:00:477655 ASSERT_FALSE(delete_observer_rfh_a.deleted());
Hajime Hoshibbc509c2020-04-06 08:55:087656 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
Anton Bikineevf62d1bf2021-05-15 17:56:077657 EXPECT_EQ(web_contents()->GetThemeColor(), absl::nullopt);
Carlos Caballero1215f882019-10-29 15:58:437658
7659 ThemeColorObserver observer(web_contents());
7660 web_contents()->GetController().GoBack();
7661 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
7662 EXPECT_TRUE(observer.did_fire());
Carlos Caballero1215f882019-10-29 15:58:437663 EXPECT_EQ(web_contents()->GetThemeColor(), 0xFFFF0000u);
7664}
7665
Yuzu Saijo40aa84e72020-05-28 07:18:287666IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
7667 ContentsMimeTypeWhenRestoredFromCache) {
7668 ASSERT_TRUE(embedded_test_server()->Start());
7669 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
7670 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
7671
7672 // Navigate to A.
7673 EXPECT_TRUE(NavigateToURL(shell(), url_a));
7674 RenderFrameHostImpl* rfh_a = current_frame_host();
7675 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
7676 EXPECT_EQ(web_contents()->GetContentsMimeType(), "text/html");
7677
7678 // Navigate to B.
7679 EXPECT_TRUE(NavigateToURL(shell(), url_b));
7680 ASSERT_FALSE(delete_observer_rfh_a.deleted());
7681 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
7682
7683 // Go back to A, which restores A from bfcache. ContentsMimeType should be
7684 // restored as well.
7685 web_contents()->GetController().GoBack();
7686 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
7687 EXPECT_EQ(rfh_a, current_frame_host());
Fergal Daly09833062021-02-09 07:10:007688 ExpectRestored(FROM_HERE);
Yuzu Saijo40aa84e72020-05-28 07:18:287689 EXPECT_EQ(web_contents()->GetContentsMimeType(), "text/html");
7690}
7691
Hajime Hoshi925793e72019-11-26 07:58:557692// Check that an audio suspends when the page goes to the cache and can resume
7693// after restored.
7694IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, AudioSuspendAndResume) {
7695 ASSERT_TRUE(embedded_test_server()->Start());
7696 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
7697 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
7698
7699 // 1) Navigate to A.
7700 EXPECT_TRUE(NavigateToURL(shell(), url_a));
7701 RenderFrameHostImpl* rfh_a = current_frame_host();
7702 EXPECT_TRUE(ExecJs(rfh_a, R"(
7703 var audio = document.createElement('audio');
7704 document.body.appendChild(audio);
7705
7706 audio.testObserverEvents = [];
7707 let event_list = [
7708 'canplaythrough',
7709 'pause',
7710 'play',
7711 'error',
7712 ];
7713 for (event_name of event_list) {
7714 let result = event_name;
7715 audio.addEventListener(event_name, event => {
7716 document.title = result;
7717 audio.testObserverEvents.push(result);
7718 });
7719 }
7720
7721 audio.src = 'media/bear-opus.ogg';
7722
7723 var timeOnFrozen = 0.0;
7724 audio.addEventListener('pause', () => {
7725 timeOnFrozen = audio.currentTime;
7726 });
7727 )"));
7728
7729 // Load the media.
7730 {
Jan Wilken Dörrie8aeb5742021-03-23 19:27:027731 TitleWatcher title_watcher(shell()->web_contents(), u"canplaythrough");
7732 title_watcher.AlsoWaitForTitle(u"error");
7733 EXPECT_EQ(u"canplaythrough", title_watcher.WaitAndGetTitle());
Hajime Hoshi925793e72019-11-26 07:58:557734 }
7735
7736 EXPECT_TRUE(ExecJs(rfh_a, R"(
7737 new Promise(async resolve => {
7738 audio.play();
7739 while (audio.currentTime === 0)
7740 await new Promise(r => setTimeout(r, 1));
7741 resolve();
7742 });
7743 )"));
7744
7745 // 2) Navigate to B.
7746 EXPECT_TRUE(NavigateToURL(shell(), url_b));
Hajime Hoshibbc509c2020-04-06 08:55:087747 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
Hajime Hoshi925793e72019-11-26 07:58:557748
7749 // 3) Navigate back to A.
7750 web_contents()->GetController().GoBack();
7751 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
7752 EXPECT_EQ(rfh_a, current_frame_host());
7753
7754 // Check that the media position is not changed when the page is in cache.
7755 double duration1 = EvalJs(rfh_a, "timeOnFrozen;").ExtractDouble();
7756 double duration2 = EvalJs(rfh_a, "audio.currentTime;").ExtractDouble();
7757 EXPECT_LE(0.0, duration2 - duration1);
7758 EXPECT_GT(0.01, duration2 - duration1);
7759
7760 // Resume the media.
7761 EXPECT_TRUE(ExecJs(rfh_a, "audio.play();"));
7762
7763 // Confirm that the media pauses automatically when going to the cache.
7764 // TODO(hajimehoshi): Confirm that this media automatically resumes if
7765 // autoplay attribute exists.
7766 EXPECT_EQ(ListValueOf("canplaythrough", "play", "pause", "play"),
7767 EvalJs(rfh_a, "audio.testObserverEvents"));
7768}
7769
7770// Check that a video suspends when the page goes to the cache and can resume
7771// after restored.
Hajime Hoshid8915a02021-04-13 06:29:017772IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, VideoSuspendAndResume) {
Hajime Hoshi925793e72019-11-26 07:58:557773 ASSERT_TRUE(embedded_test_server()->Start());
7774 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
7775 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
7776
7777 // 1) Navigate to A.
7778 EXPECT_TRUE(NavigateToURL(shell(), url_a));
7779 RenderFrameHostImpl* rfh_a = current_frame_host();
7780 EXPECT_TRUE(ExecJs(rfh_a, R"(
7781 var video = document.createElement('video');
7782 document.body.appendChild(video);
7783
7784 video.testObserverEvents = [];
7785 let event_list = [
7786 'canplaythrough',
7787 'pause',
7788 'play',
7789 'error',
7790 ];
7791 for (event_name of event_list) {
7792 let result = event_name;
7793 video.addEventListener(event_name, event => {
7794 document.title = result;
Hajime Hoshid8915a02021-04-13 06:29:017795 // Ignore 'canplaythrough' event as we can randomly get extra
7796 // 'canplaythrough' events after playing here.
7797 if (result != 'canplaythrough')
7798 video.testObserverEvents.push(result);
Hajime Hoshi925793e72019-11-26 07:58:557799 });
7800 }
7801
7802 video.src = 'media/bear.webm';
7803
7804 var timeOnFrozen = 0.0;
7805 video.addEventListener('pause', () => {
7806 timeOnFrozen = video.currentTime;
7807 });
7808 )"));
7809
7810 // Load the media.
7811 {
Jan Wilken Dörrie8aeb5742021-03-23 19:27:027812 TitleWatcher title_watcher(shell()->web_contents(), u"canplaythrough");
7813 title_watcher.AlsoWaitForTitle(u"error");
7814 EXPECT_EQ(u"canplaythrough", title_watcher.WaitAndGetTitle());
Hajime Hoshi925793e72019-11-26 07:58:557815 }
7816
7817 EXPECT_TRUE(ExecJs(rfh_a, R"(
7818 new Promise(async resolve => {
7819 video.play();
7820 while (video.currentTime == 0)
7821 await new Promise(r => setTimeout(r, 1));
7822 resolve();
7823 });
7824 )"));
7825
7826 // 2) Navigate to B.
7827 EXPECT_TRUE(NavigateToURL(shell(), url_b));
Hajime Hoshibbc509c2020-04-06 08:55:087828 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
Hajime Hoshi925793e72019-11-26 07:58:557829
7830 // 3) Navigate back to A.
7831 web_contents()->GetController().GoBack();
7832 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
7833 EXPECT_EQ(rfh_a, current_frame_host());
7834
7835 // Check that the media position is not changed when the page is in cache.
7836 double duration1 = EvalJs(rfh_a, "timeOnFrozen;").ExtractDouble();
7837 double duration2 = EvalJs(rfh_a, "video.currentTime;").ExtractDouble();
7838 EXPECT_LE(0.0, duration2 - duration1);
arthursonzognie7b8dad2020-09-14 12:00:597839 EXPECT_GT(0.02, duration2 - duration1);
Hajime Hoshi925793e72019-11-26 07:58:557840
7841 // Resume the media.
7842 EXPECT_TRUE(ExecJs(rfh_a, "video.play();"));
7843
7844 // Confirm that the media pauses automatically when going to the cache.
7845 // TODO(hajimehoshi): Confirm that this media automatically resumes if
7846 // autoplay attribute exists.
Hajime Hoshid8915a02021-04-13 06:29:017847 EXPECT_EQ(ListValueOf("play", "pause", "play"),
Hajime Hoshi925793e72019-11-26 07:58:557848 EvalJs(rfh_a, "video.testObserverEvents"));
7849}
7850
Kouhei Uenoe0688712019-11-08 01:00:147851class SensorBackForwardCacheBrowserTest : public BackForwardCacheBrowserTest {
7852 protected:
7853 SensorBackForwardCacheBrowserTest() {
Ken Rockot05499cf2019-12-12 05:22:547854 SensorProviderProxyImpl::OverrideSensorProviderBinderForTesting(
Kouhei Uenoe0688712019-11-08 01:00:147855 base::BindRepeating(
7856 &SensorBackForwardCacheBrowserTest::BindSensorProvider,
7857 base::Unretained(this)));
7858 }
7859
7860 ~SensorBackForwardCacheBrowserTest() override {
Ken Rockot05499cf2019-12-12 05:22:547861 SensorProviderProxyImpl::OverrideSensorProviderBinderForTesting(
7862 base::NullCallback());
Kouhei Uenoe0688712019-11-08 01:00:147863 }
7864
7865 void SetUpOnMainThread() override {
7866 provider_ = std::make_unique<device::FakeSensorProvider>();
7867 provider_->SetAccelerometerData(1.0, 2.0, 3.0);
7868
7869 BackForwardCacheBrowserTest::SetUpOnMainThread();
7870 }
7871
7872 std::unique_ptr<device::FakeSensorProvider> provider_;
7873
7874 private:
7875 void BindSensorProvider(
7876 mojo::PendingReceiver<device::mojom::SensorProvider> receiver) {
7877 provider_->Bind(std::move(receiver));
7878 }
7879};
7880
7881IN_PROC_BROWSER_TEST_F(SensorBackForwardCacheBrowserTest,
7882 AccelerometerNotCached) {
7883 ASSERT_TRUE(embedded_test_server()->Start());
7884 GURL url_a(embedded_test_server()->GetURL("/title1.html"));
7885 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
7886
7887 // 1) Navigate to A.
7888 ASSERT_TRUE(NavigateToURL(shell(), url_a));
7889 RenderFrameHostImpl* rfh_a = current_frame_host();
7890 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
7891
7892 EXPECT_TRUE(ExecJs(rfh_a, R"(
7893 new Promise(resolve => {
7894 const sensor = new Accelerometer();
7895 sensor.addEventListener('reading', () => { resolve(); });
7896 sensor.start();
7897 })
7898 )"));
7899
Rakina Zata Amni9fd73cc2020-10-03 09:06:597900 // 2) Navigate to B.
7901 ASSERT_TRUE(NavigateToURL(shell(), url_b));
Kouhei Uenoe0688712019-11-08 01:00:147902
Rakina Zata Amni9fd73cc2020-10-03 09:06:597903 // - Page A should not be in the cache.
Kouhei Uenoe0688712019-11-08 01:00:147904 delete_observer_rfh_a.WaitUntilDeleted();
7905
7906 // 3) Go back.
7907 web_contents()->GetController().GoBack();
7908 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
7909 ExpectNotRestored(
7910 {BackForwardCacheMetrics::NotRestoredReason::kBlocklistedFeatures},
Fergal Daly6755cbf2021-02-12 03:06:587911 {blink::scheduler::WebSchedulerTrackedFeature::
7912 kRequestedBackForwardCacheBlockedSensors},
7913 {}, {}, FROM_HERE);
Kouhei Uenoe0688712019-11-08 01:00:147914}
7915
Fergal Daly4289f932019-11-27 03:09:307916IN_PROC_BROWSER_TEST_F(SensorBackForwardCacheBrowserTest, OrientationCached) {
7917 ASSERT_TRUE(embedded_test_server()->Start());
7918 GURL url_a(embedded_test_server()->GetURL("/title1.html"));
7919 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
7920
7921 // 1) Navigate to A.
7922 ASSERT_TRUE(NavigateToURL(shell(), url_a));
7923 RenderFrameHostImpl* rfh_a = current_frame_host();
7924 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
7925
7926 EXPECT_TRUE(ExecJs(rfh_a, R"(
arthursonzogni3d3ec9e2021-03-04 11:00:507927 window.addEventListener("deviceorientation", () => {});
Fergal Daly4289f932019-11-27 03:09:307928 )"));
7929
7930 // 2) Navigate to B.
7931 ASSERT_TRUE(NavigateToURL(shell(), url_b));
7932
7933 EXPECT_FALSE(delete_observer_rfh_a.deleted());
7934 EXPECT_THAT(rfh_a, InBackForwardCache());
7935}
7936
7937// Tests that the orientation sensor's events are not delivered to a page in the
7938// back-forward cache.
7939//
7940// This sets some JS functions in the pages to enable the sensors, capture and
7941// validate the events. The a-page should only receive events with alpha=0, the
7942// b-page is allowed to receive any alpha value. The test captures 3 events in
7943// the a-page, then navigates to the b-page and changes the reading to have
7944// alpha=1. While on the b-page it captures 3 more events. If the a-page is
7945// still receiving events it should receive one or more of these. Finally it
7946// resets the reasing back to have alpha=0 and navigates back to the a-page and
7947// catpures 3 more events and verifies that all events on the a-page have
7948// alpha=1.
7949IN_PROC_BROWSER_TEST_F(SensorBackForwardCacheBrowserTest,
Fergal Dalyd6e6b7b92021-03-25 21:51:397950 SensorPausedWhileCached) {
Fergal Daly4289f932019-11-27 03:09:307951 ASSERT_TRUE(CreateHttpsServer()->Start());
7952 GURL url_a(https_server()->GetURL("a.com", "/title1.html"));
7953 GURL url_b(https_server()->GetURL("b.com", "/title1.html"));
7954
7955 provider_->SetRelativeOrientationSensorData(0, 0, 0);
7956
7957 // JS to cause a page to listen to, capture and validate orientation events.
7958 const std::string sensor_js = R"(
7959 // Collects events that have happened so far.
7960 var events = [];
7961 // If set, will be called by handleEvent.
7962 var pendingResolve = null;
7963
7964 // Handles one event, pushing it to |events| and calling |pendingResolve| if
7965 // set.
7966 function handleEvent(event) {
7967 events.push(event);
7968 if (pendingResolve !== null) {
7969 pendingResolve('event');
7970 pendingResolve = null;
7971 }
7972 }
7973
Fergal Daly2e241022019-12-03 01:44:177974 // Returns a promise that will resolve when the events array has at least
7975 // |eventCountMin| elements. Returns the number of elements.
7976 function waitForEventsPromise(eventCountMin) {
7977 if (events.length >= eventCountMin) {
7978 return Promise.resolve(events.length);
7979 }
Fergal Daly4289f932019-11-27 03:09:307980 return new Promise(resolve => {
7981 pendingResolve = resolve;
Fergal Daly2e241022019-12-03 01:44:177982 }).then(() => waitForEventsPromise(eventCountMin));
Fergal Daly4289f932019-11-27 03:09:307983 }
7984
7985 // Pretty print an orientation event.
7986 function eventToString(event) {
7987 return `${event.alpha} ${event.beta} ${event.gamma}`;
7988 }
7989
Fergal Daly2e241022019-12-03 01:44:177990 // Ensure that that |expectedAlpha| matches the alpha of all events.
7991 function validateEvents(expectedAlpha = null) {
Fergal Daly4289f932019-11-27 03:09:307992 if (expectedAlpha !== null) {
7993 let count = 0;
7994 for (event of events) {
7995 count++;
7996 if (Math.abs(event.alpha - expectedAlpha) > 0.01) {
7997 return `fail - ${count}/${events.length}: ` +
7998 `${expectedAlpha} != ${event.alpha} (${eventToString(event)})`;
7999 }
8000 }
8001 }
Fergal Daly4289f932019-11-27 03:09:308002 return 'pass';
8003 }
8004
8005 window.addEventListener('deviceorientation', handleEvent);
8006 )";
8007
8008 // 1) Navigate to A.
8009 ASSERT_TRUE(NavigateToURL(shell(), url_a));
8010 ASSERT_TRUE(WaitForLoadStop(shell()->web_contents()));
8011 RenderFrameHostImpl* rfh_a = current_frame_host();
8012 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
8013
8014 ASSERT_TRUE(ExecJs(rfh_a, sensor_js));
8015
8016 // Collect 3 orientation events.
Fergal Daly2e241022019-12-03 01:44:178017 ASSERT_EQ(1, EvalJs(rfh_a, "waitForEventsPromise(1)"));
Fergal Daly4289f932019-11-27 03:09:308018 provider_->UpdateRelativeOrientationSensorData(0, 0, 0.2);
Fergal Daly2e241022019-12-03 01:44:178019 ASSERT_EQ(2, EvalJs(rfh_a, "waitForEventsPromise(2)"));
Fergal Daly4289f932019-11-27 03:09:308020 provider_->UpdateRelativeOrientationSensorData(0, 0, 0.4);
Fergal Daly2e241022019-12-03 01:44:178021 ASSERT_EQ(3, EvalJs(rfh_a, "waitForEventsPromise(3)"));
Fergal Daly4289f932019-11-27 03:09:308022 // We should have 3 events with alpha=0.
Fergal Daly2e241022019-12-03 01:44:178023 ASSERT_EQ("pass", EvalJs(rfh_a, "validateEvents(0)"));
Fergal Daly4289f932019-11-27 03:09:308024
8025 // 2) Navigate to B.
8026 ASSERT_TRUE(NavigateToURL(shell(), url_b));
8027 ASSERT_TRUE(WaitForLoadStop(shell()->web_contents()));
8028 RenderFrameHostImpl* rfh_b = current_frame_host();
8029
8030 ASSERT_FALSE(delete_observer_rfh_a.deleted());
8031 ASSERT_THAT(rfh_a, InBackForwardCache());
8032 ASSERT_NE(rfh_a, rfh_b);
8033
8034 ASSERT_TRUE(ExecJs(rfh_b, sensor_js));
8035
8036 // Collect 3 orientation events.
8037 provider_->SetRelativeOrientationSensorData(1, 0, 0);
Fergal Daly2e241022019-12-03 01:44:178038 ASSERT_EQ(1, EvalJs(rfh_b, "waitForEventsPromise(1)"));
Fergal Daly4289f932019-11-27 03:09:308039 provider_->UpdateRelativeOrientationSensorData(1, 0, 0.2);
Fergal Daly2e241022019-12-03 01:44:178040 ASSERT_EQ(2, EvalJs(rfh_b, "waitForEventsPromise(2)"));
Fergal Daly4289f932019-11-27 03:09:308041 provider_->UpdateRelativeOrientationSensorData(1, 0, 0.4);
Fergal Daly2e241022019-12-03 01:44:178042 ASSERT_EQ(3, EvalJs(rfh_b, "waitForEventsPromise(3)"));
Fergal Daly4289f932019-11-27 03:09:308043 // We should have 3 events with alpha=1.
Fergal Daly2e241022019-12-03 01:44:178044 ASSERT_EQ("pass", EvalJs(rfh_b, "validateEvents()"));
Fergal Daly4289f932019-11-27 03:09:308045
8046 // 3) Go back to A.
8047 provider_->UpdateRelativeOrientationSensorData(0, 0, 0);
8048 web_contents()->GetController().GoBack();
8049 ASSERT_TRUE(WaitForLoadStop(shell()->web_contents()));
8050 ASSERT_EQ(rfh_a, current_frame_host());
8051
8052 // Collect 3 orientation events.
8053 provider_->UpdateRelativeOrientationSensorData(0, 0, 0);
Fergal Daly2e241022019-12-03 01:44:178054 // There are 2 processes so, it's possible that more events crept in. So we
8055 // capture how many there are at this point and uses to wait for at least 3
8056 // more.
8057 int count = EvalJs(rfh_a, "waitForEventsPromise(4)").ExtractInt();
Fergal Daly4289f932019-11-27 03:09:308058 provider_->UpdateRelativeOrientationSensorData(0, 0, 0.2);
Fergal Daly2e241022019-12-03 01:44:178059 count++;
8060 ASSERT_EQ(count, EvalJs(rfh_a, base::StringPrintf("waitForEventsPromise(%d)",
8061 count)));
Fergal Daly4289f932019-11-27 03:09:308062 provider_->UpdateRelativeOrientationSensorData(0, 0, 0.4);
Fergal Daly2e241022019-12-03 01:44:178063 count++;
8064 ASSERT_EQ(count, EvalJs(rfh_a, base::StringPrintf("waitForEventsPromise(%d)",
8065 count)));
Fergal Daly4289f932019-11-27 03:09:308066
8067 // We should have the earlier 3 plus another 3 events with alpha=0.
Fergal Daly2e241022019-12-03 01:44:178068 ASSERT_EQ("pass", EvalJs(rfh_a, "validateEvents(0)"));
Fergal Daly4289f932019-11-27 03:09:308069}
8070
Alexander Timin9edf0cc2019-11-21 04:59:488071IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
8072 AllowedFeaturesForSubframesDoNotEvict) {
8073 // The main purpose of this test is to check that when a state of a subframe
8074 // is updated, CanStoreDocument is still called for the main frame - otherwise
8075 // we would always evict the document, even when the feature is allowed as
8076 // CanStoreDocument always returns false for non-main frames.
8077
8078 ASSERT_TRUE(embedded_test_server()->Start());
8079 GURL url_a(embedded_test_server()->GetURL(
8080 "a.com", "/cross_site_iframe_factory.html?a(b)"));
8081 GURL url_c(embedded_test_server()->GetURL("c.com", "/title1.html"));
8082
8083 // 1) Navigate to A.
8084 ASSERT_TRUE(NavigateToURL(shell(), url_a));
8085 RenderFrameHostImpl* rfh_a = current_frame_host();
8086 RenderFrameHostImpl* rfh_b = rfh_a->child_at(0)->current_frame_host();
8087 RenderFrameDeletedObserver delete_observer_rfh_b(rfh_b);
8088
8089 // 2) Navigate to C.
8090 ASSERT_TRUE(NavigateToURL(shell(), url_c));
8091
8092 // 3) No-op feature update on a subframe while in cache, should be no-op.
8093 ASSERT_FALSE(delete_observer_rfh_b.deleted());
8094 static_cast<blink::mojom::LocalFrameHost*>(rfh_b)
8095 ->DidChangeActiveSchedulerTrackedFeatures(0);
8096
8097 // 4) Go back.
8098 web_contents()->GetController().GoBack();
8099 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
8100 EXPECT_EQ(current_frame_host(), rfh_a);
8101
Fergal Daly09833062021-02-09 07:10:008102 ExpectRestored(FROM_HERE);
Alexander Timin9edf0cc2019-11-21 04:59:488103}
8104
Carlos Caballerob6b466482019-11-29 13:33:188105IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
Sreeja Kamishettydb8e2892021-03-10 09:30:588106 IsInactiveAndDisallowActivationIsNoopWhenActive) {
Carlos Caballerob6b466482019-11-29 13:33:188107 ASSERT_TRUE(embedded_test_server()->Start());
8108 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
8109 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
8110
8111 // 1) Navigate to A.
8112 EXPECT_TRUE(NavigateToURL(shell(), url_a));
Sreeja Kamishettydb8e2892021-03-10 09:30:588113 EXPECT_FALSE(current_frame_host()->IsInactiveAndDisallowActivation());
Carlos Caballerob6b466482019-11-29 13:33:188114
8115 // 2) Navigate to B.
8116 EXPECT_TRUE(NavigateToURL(shell(), url_b));
8117
8118 // 3) Go back to A.
8119 web_contents()->GetController().GoBack();
8120 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
Fergal Daly09833062021-02-09 07:10:008121 ExpectRestored(FROM_HERE);
Carlos Caballerob6b466482019-11-29 13:33:188122}
8123
Sreeja Kamishetty113235c2020-07-16 12:47:208124IN_PROC_BROWSER_TEST_F(
8125 BackForwardCacheBrowserTest,
Sreeja Kamishettydb8e2892021-03-10 09:30:588126 IsInactiveAndDisallowActivationDoesEvictForCachedFrames) {
Carlos Caballerob6b466482019-11-29 13:33:188127 ASSERT_TRUE(embedded_test_server()->Start());
8128 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
8129 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
8130
8131 // 1) Navigate to A.
8132 EXPECT_TRUE(NavigateToURL(shell(), url_a));
8133 RenderFrameDeletedObserver delete_observer_rfh_a(current_frame_host());
Sreeja Kamishetty113235c2020-07-16 12:47:208134 RenderFrameHostImpl* rfh_a = current_frame_host();
Carlos Caballerob6b466482019-11-29 13:33:188135
8136 // 2) Navigate to B.
8137 EXPECT_TRUE(NavigateToURL(shell(), url_b));
Sreeja Kamishettydb8e2892021-03-10 09:30:588138 EXPECT_TRUE(rfh_a->IsInactiveAndDisallowActivation());
Carlos Caballerob6b466482019-11-29 13:33:188139
8140 // 3) Go back to A.
8141 web_contents()->GetController().GoBack();
8142 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
Sreeja Kamishetty113235c2020-07-16 12:47:208143 ExpectNotRestored(
Fergal Daly6755cbf2021-02-12 03:06:588144 {BackForwardCacheMetrics::NotRestoredReason::kIgnoreEventAndEvict}, {},
8145 {}, {}, FROM_HERE);
Carlos Caballerob6b466482019-11-29 13:33:188146}
8147
Sreeja Kamishetty92006e02021-02-05 05:18:118148// Check BackForwardCache is enabled and works for devices with very low memory.
8149// Navigate from A -> B and go back.
8150IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
8151 BackForwardCacheEnabledOnLowMemoryDevices) {
8152 // Set device physical memory to 10 MB.
8153 blink::ApproximatedDeviceMemory::SetPhysicalMemoryMBForTesting(10);
8154 ASSERT_TRUE(embedded_test_server()->Start());
8155 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
8156 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
8157
8158 // 1) Navigate to A.
8159 EXPECT_TRUE(NavigateToURL(shell(), url_a));
8160 RenderFrameDeletedObserver delete_observer_rfh_a(current_frame_host());
8161 RenderFrameHostImpl* rfh_a = current_frame_host();
8162
8163 // 2) Navigate to B. A should be in BackForwardCache.
8164 EXPECT_TRUE(NavigateToURL(shell(), url_b));
8165 RenderFrameHostImpl* rfh_b = current_frame_host();
8166 RenderFrameDeletedObserver delete_observer_rfh_b(rfh_b);
8167 EXPECT_FALSE(delete_observer_rfh_a.deleted());
8168 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
8169
8170 // 3) Go back to A. B should be in BackForwardCache.
8171 web_contents()->GetController().GoBack();
8172 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
8173 EXPECT_FALSE(delete_observer_rfh_b.deleted());
8174 EXPECT_TRUE(rfh_b->IsInBackForwardCache());
8175}
8176
[email protected]54eaf622019-11-25 12:36:038177// Test for functionality of memory controls in back-forward cache for low
8178// memory devices.
8179class BackForwardCacheBrowserTestForLowMemoryDevices
8180 : public BackForwardCacheBrowserTest {
8181 protected:
8182 void SetUpCommandLine(base::CommandLine* command_line) override {
Sreeja Kamishetty92006e02021-02-05 05:18:118183 BackForwardCacheBrowserTest::SetUpCommandLine(command_line);
8184
[email protected]54eaf622019-11-25 12:36:038185 // Set the value of memory threshold more than the physical memory and check
8186 // if back-forward cache is disabled or not.
8187 std::string memory_threshold =
8188 base::NumberToString(base::SysInfo::AmountOfPhysicalMemoryMB() + 1);
Sreeja Kamishetty92006e02021-02-05 05:18:118189 scoped_feature_list_.InitWithFeaturesAndParameters(
John Abd-El-Malek3c868c292021-02-19 20:00:098190 {{features::kBackForwardCacheMemoryControls,
Sreeja Kamishetty92006e02021-02-05 05:18:118191 {{"memory_threshold_for_back_forward_cache_in_mb",
Rakina Zata Amnib6b7f7bf2021-02-12 10:25:398192 memory_threshold}}},
8193 {blink::features::kLoadingTasksUnfreezable, {}}},
Sreeja Kamishetty92006e02021-02-05 05:18:118194 {});
[email protected]54eaf622019-11-25 12:36:038195 }
Sreeja Kamishetty92006e02021-02-05 05:18:118196
8197 private:
8198 base::test::ScopedFeatureList scoped_feature_list_;
[email protected]54eaf622019-11-25 12:36:038199};
8200
8201// Navigate from A to B and go back.
8202IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTestForLowMemoryDevices,
8203 DisableBFCacheForLowEndDevices) {
[email protected]54eaf622019-11-25 12:36:038204 ASSERT_TRUE(embedded_test_server()->Start());
Alexander Timin3e88b8f2019-12-16 16:32:208205 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
8206 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
[email protected]54eaf622019-11-25 12:36:038207
Alexander Timinddc49312020-02-28 15:24:198208 // Ensure that the trial starts inactive.
8209 EXPECT_FALSE(base::FieldTrialList::IsTrialActive(
8210 base::FeatureList::GetFieldTrial(features::kBackForwardCache)
8211 ->trial_name()));
8212
8213 EXPECT_FALSE(IsBackForwardCacheEnabled());
8214
8215 // Ensure that we do not activate the trial when querying bfcache status,
8216 // which is protected by low-memory setting.
8217 EXPECT_FALSE(base::FieldTrialList::IsTrialActive(
8218 base::FeatureList::GetFieldTrial(features::kBackForwardCache)
8219 ->trial_name()));
8220
[email protected]54eaf622019-11-25 12:36:038221 // 1) Navigate to A.
8222 EXPECT_TRUE(NavigateToURL(shell(), url_a));
8223 RenderFrameHostImpl* rfh_a = current_frame_host();
8224 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
8225
8226 // 2) Navigate to B.
8227 EXPECT_TRUE(NavigateToURL(shell(), url_b));
8228
8229 // 3) A shouldn't be stored in back-forward cache because the physical
8230 // memory is less than the memory threshold.
8231 delete_observer_rfh_a.WaitUntilDeleted();
8232
8233 // Nothing is recorded when the memory is less than the threshold value.
8234 ExpectOutcomeDidNotChange(FROM_HERE);
8235 ExpectNotRestoredDidNotChange(FROM_HERE);
Alexander Timinddc49312020-02-28 15:24:198236
8237 // Ensure that the trial still hasn't been activated.
8238 EXPECT_FALSE(base::FieldTrialList::IsTrialActive(
8239 base::FeatureList::GetFieldTrial(features::kBackForwardCache)
8240 ->trial_name()));
[email protected]54eaf622019-11-25 12:36:038241}
8242
Rakina Zata Amnib6b7f7bf2021-02-12 10:25:398243// Trigger network reqeuests, then navigate from A to B, then go back.
8244IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTestForLowMemoryDevices,
Rakina Zata Amnieaf87b72021-03-02 02:04:358245 DisableBFCacheForLowEndDevices_NetworkRequests) {
Rakina Zata Amnib6b7f7bf2021-02-12 10:25:398246 net::test_server::ControllableHttpResponse image_response(
8247 embedded_test_server(), "/image.png");
8248 ASSERT_TRUE(embedded_test_server()->Start());
8249 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
8250 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
8251
8252 // Ensure that the trials starts inactive.
8253 EXPECT_FALSE(base::FieldTrialList::IsTrialActive(
8254 base::FeatureList::GetFieldTrial(features::kBackForwardCache)
8255 ->trial_name()));
8256 EXPECT_FALSE(base::FieldTrialList::IsTrialActive(
8257 base::FeatureList::GetFieldTrial(
8258 blink::features::kLoadingTasksUnfreezable)
8259 ->trial_name()));
8260
8261 EXPECT_FALSE(IsBackForwardCacheEnabled());
8262
8263 // Ensure that we do not activate the trials for kBackForwardCache and
8264 // kLoadingTasksUnfreezable when querying bfcache or unfreezable loading tasks
8265 // status.
8266 EXPECT_FALSE(base::FieldTrialList::IsTrialActive(
8267 base::FeatureList::GetFieldTrial(features::kBackForwardCache)
8268 ->trial_name()));
8269 EXPECT_FALSE(base::FieldTrialList::IsTrialActive(
8270 base::FeatureList::GetFieldTrial(
8271 blink::features::kLoadingTasksUnfreezable)
8272 ->trial_name()));
8273
8274 // 1) Navigate to A.
8275 EXPECT_TRUE(NavigateToURL(shell(), url_a));
8276 RenderFrameHostImpl* rfh_a = current_frame_host();
8277 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
8278
8279 // Request for an image and send a response to trigger loading code. This is
8280 // to ensure kLoadingTasksUnfreezable won't trigger bfcache activation.
8281 EXPECT_TRUE(ExecJs(rfh_a, R"(
8282 var image = document.createElement("img");
8283 image.src = "image.png";
8284 document.body.appendChild(image);
8285 )"));
8286 image_response.WaitForRequest();
8287 image_response.Send(net::HTTP_OK, "image/png");
8288 image_response.Send("image_body");
8289 image_response.Done();
8290
8291 // 2) Navigate to B.
8292 EXPECT_TRUE(NavigateToURL(shell(), url_b));
8293
8294 // 3) A shouldn't be stored in back-forward cache because the physical
8295 // memory is less than the memory threshold.
8296 delete_observer_rfh_a.WaitUntilDeleted();
8297
8298 // Nothing is recorded when the memory is less than the threshold value.
8299 ExpectOutcomeDidNotChange(FROM_HERE);
8300 ExpectNotRestoredDidNotChange(FROM_HERE);
8301
8302 // Ensure that the trials still haven't been activated.
8303 EXPECT_FALSE(base::FieldTrialList::IsTrialActive(
8304 base::FeatureList::GetFieldTrial(features::kBackForwardCache)
8305 ->trial_name()));
8306 EXPECT_FALSE(base::FieldTrialList::IsTrialActive(
8307 base::FeatureList::GetFieldTrial(
8308 blink::features::kLoadingTasksUnfreezable)
8309 ->trial_name()));
8310}
8311
[email protected]54eaf622019-11-25 12:36:038312// Test for functionality of memory controls in back-forward cache for high
8313// memory devices.
8314class BackForwardCacheBrowserTestForHighMemoryDevices
8315 : public BackForwardCacheBrowserTest {
8316 protected:
8317 void SetUpCommandLine(base::CommandLine* command_line) override {
8318 // Set the value of memory threshold less than the physical memory and check
8319 // if back-forward cache is enabled or not.
8320 std::string memory_threshold =
8321 base::NumberToString(base::SysInfo::AmountOfPhysicalMemoryMB() - 1);
John Abd-El-Malek3c868c292021-02-19 20:00:098322 EnableFeatureAndSetParams(features::kBackForwardCacheMemoryControls,
[email protected]54eaf622019-11-25 12:36:038323 "memory_threshold_for_back_forward_cache_in_mb",
8324 memory_threshold);
Rakina Zata Amnib6b7f7bf2021-02-12 10:25:398325 EnableFeatureAndSetParams(blink::features::kLoadingTasksUnfreezable,
8326 "max_buffered_bytes", "1000");
[email protected]54eaf622019-11-25 12:36:038327
8328 BackForwardCacheBrowserTest::SetUpCommandLine(command_line);
8329 }
8330};
8331
8332// Navigate from A to B and go back.
8333IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTestForHighMemoryDevices,
8334 EnableBFCacheForHighMemoryDevices) {
8335 ASSERT_TRUE(embedded_test_server()->Start());
Alexander Timin3e88b8f2019-12-16 16:32:208336 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
8337 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
[email protected]54eaf622019-11-25 12:36:038338
8339 // 1) Navigate to A.
8340 EXPECT_TRUE(NavigateToURL(shell(), url_a));
8341 RenderFrameHostImpl* rfh_a = current_frame_host();
8342
8343 // 2) Navigate to B.
8344 EXPECT_TRUE(NavigateToURL(shell(), url_b));
8345
8346 // 3) A should be stored in back-forward cache because the physical memory is
8347 // greater than the memory threshold.
Hajime Hoshibbc509c2020-04-06 08:55:088348 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
[email protected]54eaf622019-11-25 12:36:038349}
Alexander Timine92f1652019-11-27 14:51:188350
Rakina Zata Amnib6b7f7bf2021-02-12 10:25:398351// Trigger network reqeuests, then navigate from A to B, then go back.
8352IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTestForHighMemoryDevices,
Rakina Zata Amnieaf87b72021-03-02 02:04:358353 EnableBFCacheForHighMemoryDevices_NetworkRequests) {
Rakina Zata Amnib6b7f7bf2021-02-12 10:25:398354 net::test_server::ControllableHttpResponse image_response(
8355 embedded_test_server(), "/image.png");
8356 ASSERT_TRUE(embedded_test_server()->Start());
8357 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
8358 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
8359
8360 // Ensure that back-forward cache flag is enabled and the trial is active.
8361 EXPECT_TRUE(IsBackForwardCacheEnabled());
8362 EXPECT_TRUE(base::FieldTrialList::IsTrialActive(
8363 base::FeatureList::GetFieldTrial(features::kBackForwardCache)
8364 ->trial_name()));
8365
8366 // Ensure that the LoadingTasksUnfreezable trials starts as inactive.
8367 EXPECT_FALSE(base::FieldTrialList::IsTrialActive(
8368 base::FeatureList::GetFieldTrial(
8369 blink::features::kLoadingTasksUnfreezable)
8370 ->trial_name()));
8371
8372 // 1) Navigate to A.
8373 EXPECT_TRUE(NavigateToURL(shell(), url_a));
8374 RenderFrameHostImpl* rfh_a = current_frame_host();
8375 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
8376
8377 // Request for an image and send a response to trigger loading code.
8378 EXPECT_TRUE(ExecJs(rfh_a, R"(
8379 var image = document.createElement("img");
8380 image.src = "image.png";
8381 document.body.appendChild(image);
8382 )"));
8383 image_response.WaitForRequest();
8384 image_response.Send(net::HTTP_OK, "image/png");
8385 image_response.Send("image_body");
8386 image_response.Done();
8387
8388 // The loading code activates the LoadingTasksUnfreezable trial.
8389 EXPECT_TRUE(base::FieldTrialList::IsTrialActive(
8390 base::FeatureList::GetFieldTrial(
8391 blink::features::kLoadingTasksUnfreezable)
8392 ->trial_name()));
8393
8394 // 2) Navigate to B.
8395 EXPECT_TRUE(NavigateToURL(shell(), url_b));
8396
8397 // 3) A should be stored in back-forward cache because the physical memory is
8398 // greater than the memory threshold.
8399 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
8400
8401 // Ensure that the trials stay activated.
8402 EXPECT_TRUE(base::FieldTrialList::IsTrialActive(
8403 base::FeatureList::GetFieldTrial(features::kBackForwardCache)
8404 ->trial_name()));
8405 EXPECT_TRUE(base::FieldTrialList::IsTrialActive(
8406 base::FeatureList::GetFieldTrial(
8407 blink::features::kLoadingTasksUnfreezable)
8408 ->trial_name()));
8409}
8410
Rakina Zata Amnieaf87b72021-03-02 02:04:358411// Test scenarios where the "BackForwardCache" content flag is enabled but
8412// the command line flag "DisableBackForwardCache" is turned on, resulting in
8413// the feature being disabled.
8414class BackForwardCacheDisabledThroughCommandLineBrowserTest
8415 : public BackForwardCacheBrowserTest {
8416 protected:
8417 void SetUpCommandLine(base::CommandLine* command_line) override {
8418 BackForwardCacheBrowserTest::SetUpCommandLine(command_line);
8419 command_line->AppendSwitch(switches::kDisableBackForwardCache);
8420 EnableFeatureAndSetParams(blink::features::kLoadingTasksUnfreezable,
8421 "max_buffered_bytes", "1000");
8422 }
8423};
8424
8425// Ensures that the back-forward cache trial stays inactivated.
8426IN_PROC_BROWSER_TEST_F(BackForwardCacheDisabledThroughCommandLineBrowserTest,
8427 BFCacheDisabled) {
8428 ASSERT_TRUE(embedded_test_server()->Start());
8429 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
8430 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
8431
8432 // Ensure that the trial starts inactive.
8433 EXPECT_FALSE(base::FieldTrialList::IsTrialActive(
8434 base::FeatureList::GetFieldTrial(features::kBackForwardCache)
8435 ->trial_name()));
8436
8437 EXPECT_FALSE(IsBackForwardCacheEnabled());
8438
8439 // Ensure that we do not activate the trial when querying bfcache status,
8440 // which is protected by low-memory setting.
8441 EXPECT_FALSE(base::FieldTrialList::IsTrialActive(
8442 base::FeatureList::GetFieldTrial(features::kBackForwardCache)
8443 ->trial_name()));
8444
8445 // 1) Navigate to A.
8446 EXPECT_TRUE(NavigateToURL(shell(), url_a));
8447 RenderFrameHostImpl* rfh_a = current_frame_host();
8448 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
8449
8450 // 2) Navigate to B.
8451 EXPECT_TRUE(NavigateToURL(shell(), url_b));
8452
8453 // 3) A shouldn't be stored in back-forward cache because it's disabled.
8454 delete_observer_rfh_a.WaitUntilDeleted();
8455
8456 // Nothing is recorded when back-forward cache is disabled.
8457 ExpectOutcomeDidNotChange(FROM_HERE);
8458 ExpectNotRestoredDidNotChange(FROM_HERE);
8459
8460 // Ensure that the trial still hasn't been activated.
8461 EXPECT_FALSE(base::FieldTrialList::IsTrialActive(
8462 base::FeatureList::GetFieldTrial(features::kBackForwardCache)
8463 ->trial_name()));
8464}
8465
8466// Ensures that the back-forward cache trial stays inactivated even when
8467// renderer code related to back-forward cache runs (in this case, network
8468// request loading).
8469IN_PROC_BROWSER_TEST_F(BackForwardCacheDisabledThroughCommandLineBrowserTest,
8470 BFCacheDisabled_NetworkRequests) {
8471 net::test_server::ControllableHttpResponse image_response(
8472 embedded_test_server(), "/image.png");
8473 ASSERT_TRUE(embedded_test_server()->Start());
8474 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
8475 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
8476
8477 // Ensure that the trials starts inactive.
8478 EXPECT_FALSE(base::FieldTrialList::IsTrialActive(
8479 base::FeatureList::GetFieldTrial(features::kBackForwardCache)
8480 ->trial_name()));
8481
8482 EXPECT_FALSE(IsBackForwardCacheEnabled());
8483
8484 // Ensure that we do not activate the trials for kBackForwardCache and
8485 // kLoadingTasksUnfreezable when querying bfcache or unfreezable loading tasks
8486 // status.
8487 EXPECT_FALSE(base::FieldTrialList::IsTrialActive(
8488 base::FeatureList::GetFieldTrial(features::kBackForwardCache)
8489 ->trial_name()));
8490
8491 // 1) Navigate to A.
8492 EXPECT_TRUE(NavigateToURL(shell(), url_a));
8493 RenderFrameHostImpl* rfh_a = current_frame_host();
8494 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
8495
8496 // Request for an image and send a response to trigger loading code. This is
8497 // to ensure kLoadingTasksUnfreezable won't trigger bfcache activation.
8498 EXPECT_TRUE(ExecJs(rfh_a, R"(
8499 var image = document.createElement("img");
8500 image.src = "image.png";
8501 document.body.appendChild(image);
8502 )"));
8503 image_response.WaitForRequest();
8504 image_response.Send(net::HTTP_OK, "image/png");
8505 image_response.Send("image_body");
8506 image_response.Done();
8507
8508 // 2) Navigate to B.
8509 EXPECT_TRUE(NavigateToURL(shell(), url_b));
8510
8511 // 3) A shouldn't be stored in back-forward cache because it's disabled.
8512 delete_observer_rfh_a.WaitUntilDeleted();
8513
8514 // Nothing is recorded when back-forward cache is disabled.
8515 ExpectOutcomeDidNotChange(FROM_HERE);
8516 ExpectNotRestoredDidNotChange(FROM_HERE);
8517
8518 // Ensure that the trials still haven't been activated.
8519 EXPECT_FALSE(base::FieldTrialList::IsTrialActive(
8520 base::FeatureList::GetFieldTrial(features::kBackForwardCache)
8521 ->trial_name()));
8522}
8523
Alexander Timine92f1652019-11-27 14:51:188524IN_PROC_BROWSER_TEST_F(
8525 BackForwardCacheBrowserTest,
8526 EvictingDocumentsInRelatedSiteInstancesDoesNotRestartNavigation) {
8527 ASSERT_TRUE(embedded_test_server()->Start());
8528 GURL url_a1(embedded_test_server()->GetURL("a.com", "/title1.html#part1"));
8529 GURL url_a2(embedded_test_server()->GetURL("a.com", "/title1.html#part2"));
8530 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
8531
8532 // 1) Navigate to A1.
8533 EXPECT_TRUE(NavigateToURL(shell(), url_a1));
8534
8535 // 2) Navigate to A2.
8536 EXPECT_TRUE(NavigateToURL(shell(), url_a2));
8537
8538 // 3) Navigate to B.
8539 EXPECT_TRUE(NavigateToURL(shell(), url_b));
8540
8541 // 4) Go back to A2, but do not wait for the navigation to commit.
8542 web_contents()->GetController().GoBack();
8543
8544 // 5) Go back to A1.
8545 // This will attempt to evict A2 from the cache because
8546 // their navigation entries have related site instances, while a navigation
8547 // to A2 is in flight. Ensure that we do not try to restart it as it should
8548 // be superseded by a navigation to A1.
8549 web_contents()->GetController().GoBack();
8550 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
8551 EXPECT_EQ(url_a1, web_contents()->GetURL());
8552}
8553
Hajime Hoshi60fe1592021-01-28 05:33:068554// This tests that even if a page initializes WebRTC, tha page can be cached as
8555// long as it doesn't make a connection.
8556// On the Android test environments, the test might fail due to IP restrictions.
8557// See the discussion at http://crrev.com/c/2564926.
8558#if !defined(OS_ANDROID)
Lukasz Anforowicz88c36b42021-05-25 19:02:278559
8560// TODO(https://crbug.com/1213145): The test is consistently failing on some Mac
8561// bots.
8562#if defined(OS_MAC)
8563#define MAYBE_TrivialRTCPeerConnectionCached \
8564 DISABLED_TrivialRTCPeerConnectionCached
8565#else
8566#define MAYBE_TrivialRTCPeerConnectionCached TrivialRTCPeerConnectionCached
8567#endif
Kouhei Uenoca31f792019-12-02 05:24:598568IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
Lukasz Anforowicz88c36b42021-05-25 19:02:278569 MAYBE_TrivialRTCPeerConnectionCached) {
Hajime Hoshi60fe1592021-01-28 05:33:068570 ASSERT_TRUE(CreateHttpsServer()->Start());
8571
8572 GURL url_a(https_server()->GetURL("/title1.html"));
8573 GURL url_b(https_server()->GetURL("b.com", "/title1.html"));
8574
8575 // 1) Navigate to A.
8576 ASSERT_TRUE(NavigateToURL(shell(), url_a));
8577 RenderFrameHostImpl* rfh_a = current_frame_host();
8578
8579 // Create an RTCPeerConnection without starting a connection.
8580 EXPECT_TRUE(ExecJs(rfh_a, "const pc1 = new RTCPeerConnection()"));
8581
8582 // 2) Navigate to B.
8583 ASSERT_TRUE(NavigateToURL(shell(), url_b));
8584
8585 // 3) Go back.
8586 web_contents()->GetController().GoBack();
8587 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
Fergal Daly09833062021-02-09 07:10:008588 ExpectRestored(FROM_HERE);
Hajime Hoshi60fe1592021-01-28 05:33:068589
8590 // RTCPeerConnection object, that is created before being put into the cache,
8591 // is still available.
8592 EXPECT_EQ("success", EvalJs(rfh_a, R"(
8593 new Promise(async resolve => {
8594 const pc1 = new RTCPeerConnection();
8595 const pc2 = new RTCPeerConnection();
8596 pc1.onicecandidate = e => {
8597 if (e.candidate)
8598 pc2.addIceCandidate(e.candidate);
8599 }
8600 pc2.onicecandidate = e => {
8601 if (e.candidate)
8602 pc1.addIceCandidate(e.candidate);
8603 }
8604 pc1.addTransceiver("audio");
8605 const connectionEstablished = new Promise((resolve, reject) => {
8606 pc1.oniceconnectionstatechange = () => {
8607 const state = pc1.iceConnectionState;
8608 switch (state) {
8609 case "connected":
8610 case "completed":
8611 resolve();
8612 break;
8613 case "failed":
8614 case "disconnected":
8615 case "closed":
8616 reject(state);
8617 break;
8618 }
8619 }
8620 });
8621 await pc1.setLocalDescription();
8622 await pc2.setRemoteDescription(pc1.localDescription);
8623 await pc2.setLocalDescription();
8624 await pc1.setRemoteDescription(pc2.localDescription);
8625 try {
8626 await connectionEstablished;
8627 } catch (e) {
8628 resolve("fail " + e);
8629 return;
8630 }
8631 resolve("success");
8632 });
8633 )"));
8634}
8635#endif // !defined(OS_ANDROID)
8636
8637// This tests that a page using WebRTC and creating actual connections cannot be
8638// cached.
8639// On the Android test environments, the test might fail due to IP restrictions.
8640// See the discussion at http://crrev.com/c/2564926.
8641#if !defined(OS_ANDROID)
Lukasz Anforowicz88c36b42021-05-25 19:02:278642
8643// TODO(https://crbug.com/1213145): The test is consistently failing on some Mac
8644// bots.
8645#if defined(OS_MAC)
8646#define MAYBE_NonTrivialRTCPeerConnectionNotCached \
8647 DISABLED_NonTrivialRTCPeerConnectionNotCached
8648#else
8649#define MAYBE_NonTrivialRTCPeerConnectionNotCached \
8650 NonTrivialRTCPeerConnectionNotCached
8651#endif
Hajime Hoshi60fe1592021-01-28 05:33:068652IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
Lukasz Anforowicz88c36b42021-05-25 19:02:278653 MAYBE_NonTrivialRTCPeerConnectionNotCached) {
Hajime Hoshi60fe1592021-01-28 05:33:068654 ASSERT_TRUE(CreateHttpsServer()->Start());
8655
8656 GURL url_a(https_server()->GetURL("/title1.html"));
8657 GURL url_b(https_server()->GetURL("b.com", "/title1.html"));
Kouhei Uenoca31f792019-12-02 05:24:598658
8659 // 1) Navigate to A.
8660 ASSERT_TRUE(NavigateToURL(shell(), url_a));
8661 RenderFrameHostImpl* rfh_a = current_frame_host();
8662 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
8663
Hajime Hoshi60fe1592021-01-28 05:33:068664 // Create an RTCPeerConnection with starting a connection.
8665 EXPECT_EQ("success", EvalJs(rfh_a, R"(
8666 new Promise(async resolve => {
8667 const pc1 = new RTCPeerConnection();
8668 const pc2 = new RTCPeerConnection();
8669 pc1.onicecandidate = e => {
8670 if (e.candidate)
8671 pc2.addIceCandidate(e.candidate);
8672 }
8673 pc2.onicecandidate = e => {
8674 if (e.candidate)
8675 pc1.addIceCandidate(e.candidate);
8676 }
8677 pc1.addTransceiver("audio");
8678 const connectionEstablished = new Promise(resolve => {
8679 pc1.oniceconnectionstatechange = () => {
8680 const state = pc1.iceConnectionState;
8681 switch (state) {
8682 case "connected":
8683 case "completed":
8684 resolve();
8685 break;
8686 case "failed":
8687 case "disconnected":
8688 case "closed":
8689 reject(state);
8690 break;
8691 }
8692 }
8693 });
8694 await pc1.setLocalDescription();
8695 await pc2.setRemoteDescription(pc1.localDescription);
8696 await pc2.setLocalDescription();
8697 await pc1.setRemoteDescription(pc2.localDescription);
8698 await connectionEstablished;
8699 try {
8700 await connectionEstablished;
8701 } catch (e) {
8702 resolve("fail " + e);
8703 return;
8704 }
8705 resolve("success");
8706 });
8707 )"));
Kouhei Uenoca31f792019-12-02 05:24:598708
8709 // 2) Navigate to B.
8710 ASSERT_TRUE(NavigateToURL(shell(), url_b));
8711
8712 // - Page A should not be in the cache.
8713 delete_observer_rfh_a.WaitUntilDeleted();
8714
8715 // 3) Go back.
8716 web_contents()->GetController().GoBack();
8717 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
8718 ExpectNotRestored(
8719 {BackForwardCacheMetrics::NotRestoredReason::kBlocklistedFeatures},
Fergal Daly6755cbf2021-02-12 03:06:588720 {blink::scheduler::WebSchedulerTrackedFeature::kWebRTC}, {}, {},
Kouhei Uenoca31f792019-12-02 05:24:598721 FROM_HERE);
Kouhei Uenoca31f792019-12-02 05:24:598722}
Hajime Hoshi60fe1592021-01-28 05:33:068723#endif // !defined(OS_ANDROID)
Kouhei Uenoca31f792019-12-02 05:24:598724
8725IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, WebLocksNotCached) {
8726 ASSERT_TRUE(embedded_test_server()->Start());
8727 GURL url_a(embedded_test_server()->GetURL("/title1.html"));
8728 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
8729
8730 // 1) Navigate to A.
8731 ASSERT_TRUE(NavigateToURL(shell(), url_a));
8732 RenderFrameHostImpl* rfh_a = current_frame_host();
8733 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
8734
8735 // Wait for the page to acquire a lock and ensure that it continues to do so.
8736 EXPECT_TRUE(ExecJs(rfh_a, R"(
8737 const never_resolved = new Promise(resolve => {});
8738 new Promise(continue_test => {
8739 navigator.locks.request('test', async () => {
8740 continue_test();
8741 await never_resolved;
8742 });
8743 })
8744 )"));
8745
8746 // 2) Navigate to B.
8747 ASSERT_TRUE(NavigateToURL(shell(), url_b));
8748
8749 // - Page A should not be in the cache.
8750 delete_observer_rfh_a.WaitUntilDeleted();
8751
8752 // 3) Go back.
8753 web_contents()->GetController().GoBack();
8754 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
8755 ExpectNotRestored(
8756 {BackForwardCacheMetrics::NotRestoredReason::kBlocklistedFeatures},
Fergal Daly6755cbf2021-02-12 03:06:588757 {blink::scheduler::WebSchedulerTrackedFeature::kWebLocks}, {}, {},
Kouhei Uenoca31f792019-12-02 05:24:598758 FROM_HERE);
Kouhei Uenoca31f792019-12-02 05:24:598759}
8760
Alexander Timin3bcde782019-12-02 16:08:008761IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
8762 CanUseCacheWhenNavigatingAwayToErrorPage) {
8763 ASSERT_TRUE(embedded_test_server()->Start());
8764
8765 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
8766 GURL error_url(embedded_test_server()->GetURL("b.com", "/empty.html"));
8767 auto url_interceptor = URLLoaderInterceptor::SetupRequestFailForURL(
8768 error_url, net::ERR_DNS_TIMED_OUT);
8769
8770 // 1) Navigate to A.
8771 EXPECT_TRUE(NavigateToURL(shell(), url_a));
8772 RenderFrameHostImpl* rfh_a = current_frame_host();
8773
8774 // 2) Navigate to an error page and expect the old page to be stored in
8775 // bfcache.
8776 EXPECT_FALSE(NavigateToURL(shell(), error_url));
Hajime Hoshibbc509c2020-04-06 08:55:088777 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
Alexander Timin3bcde782019-12-02 16:08:008778
8779 // 3) Navigate back and expect the page to be restored from bfcache.
8780 web_contents()->GetController().GoBack();
8781 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
Alexander Timinfa953bff2019-12-05 14:31:498782}
8783
Fergal Daly7991d9362019-12-20 02:28:258784// Start an inifite dialogs in JS, yielding after each. The first dialog should
8785// be dismissed by navigation. The later dialogs should be handled gracefully
8786// and not appear while in BFCache. Finally, when the page comes out of BFCache,
8787// dialogs should appear again.
8788IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
8789 CanUseCacheWhenPageAlertsInTimeoutLoop) {
8790 ASSERT_TRUE(embedded_test_server()->Start());
8791
8792 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
8793 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
8794
8795 // Navigate to A.
8796 EXPECT_TRUE(NavigateToURL(shell(), url_a));
8797 RenderFrameHostImpl* rfh_a = current_frame_host();
8798 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
8799
Marko Ivanovich7e403fc2020-10-09 05:56:478800 AppModalDialogWaiter dialog_waiter(shell());
Fergal Daly7991d9362019-12-20 02:28:258801
8802 EXPECT_TRUE(ExecJs(rfh_a, R"(
8803 function alertLoop() {
8804 setTimeout(alertLoop, 0);
8805 window.alert("alert");
8806 }
8807 // Don't block this script.
8808 setTimeout(alertLoop, 0);
8809 )"));
8810
Marko Ivanovich7e403fc2020-10-09 05:56:478811 dialog_waiter.Wait();
Fergal Daly7991d9362019-12-20 02:28:258812
8813 // Navigate to B.
8814 ASSERT_TRUE(NavigateToURL(shell(), url_b));
8815 RenderFrameHostImpl* rfh_b = current_frame_host();
8816
8817 ASSERT_FALSE(delete_observer_rfh_a.deleted());
8818 ASSERT_THAT(rfh_a, InBackForwardCache());
8819 ASSERT_NE(rfh_a, rfh_b);
8820
Marko Ivanovich7e403fc2020-10-09 05:56:478821 dialog_waiter.Restart();
Fergal Daly7991d9362019-12-20 02:28:258822
8823 // Go back.
8824 web_contents()->GetController().GoBack();
8825 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
8826 EXPECT_EQ(rfh_a, current_frame_host());
Hajime Hoshibbc509c2020-04-06 08:55:088827 EXPECT_FALSE(rfh_a->IsInBackForwardCache());
Fergal Daly7991d9362019-12-20 02:28:258828
8829 // The page should still be requesting dialogs in a loop. Wait for one to be
8830 // requested.
Marko Ivanovich7e403fc2020-10-09 05:56:478831 dialog_waiter.Wait();
Fergal Daly7991d9362019-12-20 02:28:258832}
8833
Nasko Oskov0f3cbb12020-01-07 17:52:148834// UnloadOldFrame will clear all dialogs. We test that further requests for
Fergal Daly7991d9362019-12-20 02:28:258835// dialogs coming from JS do not result in the creation of a dialog. This test
8836// posts some dialog creation JS to the render from inside the
8837// CommitNavigationCallback task. This JS is then able to post a task back to
8838// the renders to show a dialog. By the time this task runs, we the
8839// RenderFrameHostImpl's is_active() should be false.
8840//
8841// This test is not perfect, it can pass simply because the renderer thread does
8842// not run the JS in time. Ideally it would block until the renderer posts the
8843// request for a dialog but it's possible to do that without creating a nested
8844// message loop and if we do that, we risk processing the dialog request.
8845IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
8846 DialogsCancelledAndSuppressedWhenCached) {
8847 ASSERT_TRUE(embedded_test_server()->Start());
8848
8849 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
8850 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
8851
8852 // Navigate to A.
8853 EXPECT_TRUE(NavigateToURL(shell(), url_a));
8854 RenderFrameHostImpl* rfh_a = current_frame_host();
8855 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
8856
8857 // Let's us know whether the following callback ran. Not strictly necessary
8858 // since it really should run.
8859 bool posted_dialog_js = false;
8860 // Create a callback that will be called during the DidCommitNavigation task.
8861 WillEnterBackForwardCacheCallbackForTesting
8862 will_enter_back_forward_cache_callback =
8863 base::BindLambdaForTesting([&]() {
8864 // Post a dialog, it should not result in a dialog being created.
8865 ExecuteScriptAsync(rfh_a, R"(window.alert("alert");)");
8866 posted_dialog_js = true;
8867 });
8868 rfh_a->render_view_host()->SetWillEnterBackForwardCacheCallbackForTesting(
8869 will_enter_back_forward_cache_callback);
8870
Marko Ivanovich7e403fc2020-10-09 05:56:478871 AppModalDialogWaiter dialog_waiter(shell());
Fergal Daly7991d9362019-12-20 02:28:258872
8873 // Try show another dialog. It should work.
8874 ExecuteScriptAsync(rfh_a, R"(window.alert("alert");)");
Marko Ivanovich7e403fc2020-10-09 05:56:478875 dialog_waiter.Wait();
Fergal Daly7991d9362019-12-20 02:28:258876
Marko Ivanovich7e403fc2020-10-09 05:56:478877 dialog_waiter.Restart();
Fergal Daly7991d9362019-12-20 02:28:258878
8879 // Navigate to B.
8880 ASSERT_TRUE(NavigateToURL(shell(), url_b));
8881 RenderFrameHostImpl* rfh_b = current_frame_host();
8882
8883 ASSERT_FALSE(delete_observer_rfh_a.deleted());
8884 ASSERT_THAT(rfh_a, InBackForwardCache());
8885 ASSERT_NE(rfh_a, rfh_b);
8886 // Test that the JS was run and that it didn't result in a dialog.
8887 ASSERT_TRUE(posted_dialog_js);
Marko Ivanovich7e403fc2020-10-09 05:56:478888 ASSERT_FALSE(dialog_waiter.WasDialogRequestedCallbackCalled());
Fergal Daly7991d9362019-12-20 02:28:258889
8890 // Go back.
8891 web_contents()->GetController().GoBack();
8892 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
8893
8894 EXPECT_EQ(rfh_a, current_frame_host());
Hajime Hoshibbc509c2020-04-06 08:55:088895 EXPECT_FALSE(rfh_a->IsInBackForwardCache());
Fergal Daly7991d9362019-12-20 02:28:258896
8897 // Try show another dialog. It should work.
8898 ExecuteScriptAsync(rfh_a, R"(window.alert("alert");)");
Marko Ivanovich7e403fc2020-10-09 05:56:478899 dialog_waiter.Wait();
Fergal Daly7991d9362019-12-20 02:28:258900}
8901
Alexander Timinfa953bff2019-12-05 14:31:498902namespace {
8903
8904class ExecJsInDidFinishNavigation : public WebContentsObserver {
8905 public:
Fergal Dalyb0693732021-03-15 14:11:328906 explicit ExecJsInDidFinishNavigation(WebContents* web_contents)
Alexander Timinfa953bff2019-12-05 14:31:498907 : WebContentsObserver(web_contents) {}
8908
8909 void DidFinishNavigation(NavigationHandle* navigation_handle) override {
8910 if (!navigation_handle->IsInMainFrame() ||
8911 !navigation_handle->HasCommitted() ||
8912 navigation_handle->IsSameDocument()) {
8913 return;
8914 }
8915
8916 ExecuteScriptAsync(navigation_handle->GetRenderFrameHost(),
8917 "var foo = 42;");
8918 }
8919};
8920
8921} // namespace
8922
8923// This test checks that the message posted from DidFinishNavigation
8924// (ExecuteScriptAsync) is received after the message restoring the page from
8925// the back-forward cache (PageMsg_RestorePageFromBackForwardCache).
8926IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
8927 MessageFromDidFinishNavigation) {
8928 ASSERT_TRUE(embedded_test_server()->Start());
8929 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
8930 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
8931
8932 // 1) Navigate to A.
8933 EXPECT_TRUE(NavigateToURL(shell(), url_a));
8934 RenderFrameHostImpl* rfh_a = current_frame_host();
8935 EXPECT_TRUE(ExecJs(rfh_a, "window.alive = 'I am alive';"));
8936
8937 // 2) Navigate to B.
8938 EXPECT_TRUE(NavigateToURL(shell(), url_b));
8939
8940 ExecJsInDidFinishNavigation observer(shell()->web_contents());
8941
8942 // 3) Go back to A. Expect the page to be restored from the cache.
8943 web_contents()->GetController().GoBack();
8944 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
8945 EXPECT_EQ("I am alive", EvalJs(rfh_a, "window.alive"));
8946
8947 // Make sure that the javascript execution requested from DidFinishNavigation
8948 // did not result in eviction. If the document was evicted, the document
8949 // would be reloaded - check that it didn't happen and the tab is not
8950 // loading.
8951 EXPECT_FALSE(web_contents()->IsLoading());
8952
Alexander Timin3bcde782019-12-02 16:08:008953 EXPECT_EQ(rfh_a, current_frame_host());
8954}
8955
Kouhei Uenoc5ebe122019-12-04 08:03:238956IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, WebMidiNotCached) {
8957 ASSERT_TRUE(embedded_test_server()->Start());
8958 GURL url_a(embedded_test_server()->GetURL("/title1.html"));
8959 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
8960
8961 // 1) Navigate to A.
8962 ASSERT_TRUE(NavigateToURL(shell(), url_a));
8963 RenderFrameHostImpl* rfh_a = current_frame_host();
8964 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
8965
arthursonzogni3d3ec9e2021-03-04 11:00:508966 // Request access to MIDI. This should prevent the page from entering the
8967 // BackForwardCache.
8968 EXPECT_TRUE(ExecJs(rfh_a, "navigator.requestMIDIAccess()",
8969 EXECUTE_SCRIPT_NO_RESOLVE_PROMISES));
Kouhei Uenoc5ebe122019-12-04 08:03:238970
8971 // 2) Navigate to B.
8972 ASSERT_TRUE(NavigateToURL(shell(), url_b));
8973
8974 // - Page A should not be in the cache.
8975 delete_observer_rfh_a.WaitUntilDeleted();
8976
8977 // 3) Go back.
8978 web_contents()->GetController().GoBack();
8979 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
8980 ExpectNotRestored(
8981 {BackForwardCacheMetrics::NotRestoredReason::kBlocklistedFeatures},
Fergal Daly6755cbf2021-02-12 03:06:588982 {blink::scheduler::WebSchedulerTrackedFeature::kRequestedMIDIPermission},
8983 {}, {}, FROM_HERE);
Kouhei Uenoc5ebe122019-12-04 08:03:238984}
8985
[email protected]42e682e52019-12-05 04:13:468986#if defined(OS_ANDROID)
8987IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
8988 ChildImportanceTestForBackForwardCachedPagesTest) {
Khushalb8aabcf42021-06-22 11:55:038989 web_contents()->SetPrimaryMainFrameImportance(
8990 ChildProcessImportance::MODERATE);
[email protected]42e682e52019-12-05 04:13:468991
8992 ASSERT_TRUE(embedded_test_server()->Start());
8993 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
8994 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
8995
8996 // 1) Navigate to A.
8997 EXPECT_TRUE(NavigateToURL(shell(), url_a));
8998 RenderFrameHostImpl* rfh_a = current_frame_host();
8999 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
9000
9001 // 2) Navigate to B.
9002 EXPECT_TRUE(NavigateToURL(shell(), url_b));
9003 ASSERT_FALSE(delete_observer_rfh_a.deleted());
9004
9005 // 3) Verify the importance of page after entering back-forward cache to be
9006 // "NORMAL".
9007 EXPECT_EQ(ChildProcessImportance::NORMAL,
9008 rfh_a->GetProcess()->GetEffectiveImportance());
9009
9010 // 4) Go back to A.
9011 web_contents()->GetController().GoBack();
9012 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
9013
9014 // 5) Verify the importance was restored correctly after page leaves
9015 // back-forward cache.
9016 EXPECT_EQ(ChildProcessImportance::MODERATE,
9017 rfh_a->GetProcess()->GetEffectiveImportance());
9018}
9019#endif
Rakina Zata Amnic7bc82632019-12-09 05:21:229020
9021IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
9022 PresentationConnectionClosed) {
9023 ASSERT_TRUE(CreateHttpsServer()->Start());
9024 GURL url_a(https_server()->GetURL(
9025 "a.com", "/back_forward_cache/presentation_controller.html"));
9026
9027 // Navigate to A (presentation controller page).
9028 ASSERT_TRUE(NavigateToURL(shell(), url_a));
9029 auto* rfh_a = current_frame_host();
9030 // Start a presentation connection in A.
9031 MockPresentationServiceDelegate mock_presentation_service_delegate;
9032 auto& presentation_service = rfh_a->GetPresentationServiceForTesting();
9033 presentation_service.SetControllerDelegateForTesting(
9034 &mock_presentation_service_delegate);
9035 EXPECT_CALL(mock_presentation_service_delegate, StartPresentation(_, _, _));
arthursonzogni3d3ec9e2021-03-04 11:00:509036 EXPECT_TRUE(ExecJs(rfh_a, "presentationRequest.start().then(setConnection)",
9037 EXECUTE_SCRIPT_NO_RESOLVE_PROMISES));
Rakina Zata Amnic7bc82632019-12-09 05:21:229038
9039 // Send a mock connection to the renderer.
9040 MockPresentationConnection mock_controller_connection;
9041 mojo::Receiver<PresentationConnection> controller_connection_receiver(
9042 &mock_controller_connection);
9043 mojo::Remote<PresentationConnection> receiver_connection;
9044 const std::string presentation_connection_id = "foo";
9045 presentation_service.OnStartPresentationSucceeded(
9046 presentation_service.start_presentation_request_id_,
9047 PresentationConnectionResult::New(
9048 blink::mojom::PresentationInfo::New(GURL("fake-url"),
9049 presentation_connection_id),
9050 controller_connection_receiver.BindNewPipeAndPassRemote(),
9051 receiver_connection.BindNewPipeAndPassReceiver()));
9052
9053 // Navigate to B, make sure that the connection started in A is closed.
9054 GURL url_b(https_server()->GetURL("b.com", "/title1.html"));
9055 EXPECT_CALL(
9056 mock_controller_connection,
9057 DidClose(blink::mojom::PresentationConnectionCloseReason::WENT_AWAY));
9058 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
9059 ASSERT_TRUE(NavigateToURL(shell(), url_b));
9060 EXPECT_FALSE(delete_observer_rfh_a.deleted());
Hajime Hoshibbc509c2020-04-06 08:55:089061 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
Rakina Zata Amnic7bc82632019-12-09 05:21:229062
9063 // Navigate back to A. Ensure that connection state has been updated
9064 // accordingly.
9065 web_contents()->GetController().GoBack();
9066 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
Hajime Hoshibbc509c2020-04-06 08:55:089067 EXPECT_FALSE(rfh_a->IsInBackForwardCache());
Rakina Zata Amnic7bc82632019-12-09 05:21:229068 EXPECT_EQ(presentation_connection_id, EvalJs(rfh_a, "connection.id"));
9069 EXPECT_EQ("closed", EvalJs(rfh_a, "connection.state"));
9070 EXPECT_TRUE(EvalJs(rfh_a, "connectionClosed").ExtractBool());
9071
9072 // Try to start another connection, should successfully reach the browser side
9073 // PresentationServiceDelegate.
9074 EXPECT_CALL(mock_presentation_service_delegate,
9075 ReconnectPresentation(_, presentation_connection_id, _, _));
arthursonzogni3d3ec9e2021-03-04 11:00:509076 EXPECT_TRUE(ExecJs(rfh_a, "presentationRequest.reconnect(connection.id);",
9077 EXECUTE_SCRIPT_NO_RESOLVE_PROMISES));
Rakina Zata Amnic7bc82632019-12-09 05:21:229078 base::RunLoop().RunUntilIdle();
9079
9080 // Reset |presentation_service|'s controller delegate so that it won't try to
9081 // call Reset() on it on destruction time.
9082 presentation_service.OnDelegateDestroyed();
9083}
9084
Alexander Timin8c51c422020-01-22 13:52:079085IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, PageshowMetrics) {
Carlos Caballero8f4c0c662020-12-01 19:26:079086 // TODO(https://crbug.com/1099395): Do not check for unexpected messages
9087 // because the input task queue is not currently frozen, causing flakes in
9088 // this test.
9089 DoNotFailForUnexpectedMessagesWhileCached();
Alexander Timin8c51c422020-01-22 13:52:079090 ASSERT_TRUE(embedded_test_server()->Start());
9091
9092 const char kHistogramName[] =
9093 "BackForwardCache.MainFrameHasPageshowListenersOnRestore";
9094
9095 const GURL url1(embedded_test_server()->GetURL("a.com", "/title1.html"));
9096 const GURL url2(embedded_test_server()->GetURL("b.com", "/title1.html"));
9097
9098 // 1) Navigate to the page.
9099 EXPECT_TRUE(NavigateToURL(shell(), url1));
9100 EXPECT_TRUE(ExecJs(current_frame_host(), R"(
9101 window.foo = 42;
9102 )"));
9103
9104 // 2) Navigate away and back.
9105 EXPECT_TRUE(NavigateToURL(shell(), url2));
9106 web_contents()->GetController().GoBack();
9107 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
9108
9109 // As we don't get an explicit ACK when the page is restored (yet), force
9110 // a round-trip to the renderer to effectively flush the queue.
9111 EXPECT_EQ(42, EvalJs(current_frame_host(), "window.foo"));
9112
9113 // Expect the back-forward restore without pageshow to be detected.
9114 content::FetchHistogramsFromChildProcesses();
9115 EXPECT_THAT(histogram_tester_.GetAllSamples(kHistogramName),
9116 ElementsAre(base::Bucket(0, 1)));
9117
9118 EXPECT_TRUE(ExecJs(current_frame_host(), R"(
9119 window.addEventListener("pageshow", () => {});
9120 )"));
9121
9122 // 3) Navigate away and back (again).
9123 EXPECT_TRUE(NavigateToURL(shell(), url2));
9124 web_contents()->GetController().GoBack();
9125 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
9126
9127 // As we don't get an explicit ACK when the page is restored (yet), force
9128 // a round-trip to the renderer to effectively flush the queue.
9129 EXPECT_EQ(42, EvalJs(current_frame_host(), "window.foo"));
9130
9131 // Expect the back-forward restore with pageshow to be detected.
9132 content::FetchHistogramsFromChildProcesses();
9133 EXPECT_THAT(histogram_tester_.GetAllSamples(kHistogramName),
9134 ElementsAre(base::Bucket(0, 1), base::Bucket(1, 1)));
9135}
9136
Sreeja Kamishettye49854f82021-06-02 00:52:039137// Navigate from A(B) to C and check IsActive status for RenderFrameHost A
[email protected]ced590ab292020-03-12 00:37:219138// and B before and after entering back-forward cache.
Sreeja Kamishettye49854f82021-06-02 00:52:039139IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, CheckIsActive) {
[email protected]ced590ab292020-03-12 00:37:219140 ASSERT_TRUE(embedded_test_server()->Start());
9141 GURL url_a(embedded_test_server()->GetURL(
9142 "a.com", "/cross_site_iframe_factory.html?a(b)"));
9143 GURL url_c(embedded_test_server()->GetURL("c.com", "/title1.html"));
9144
9145 // 1) Navigate to A(B).
9146 EXPECT_TRUE(NavigateToURL(shell(), url_a));
9147 RenderFrameHostImpl* rfh_a = current_frame_host();
9148 RenderFrameHostImpl* rfh_b = rfh_a->child_at(0)->current_frame_host();
9149
Sreeja Kamishettye49854f82021-06-02 00:52:039150 EXPECT_TRUE(rfh_a->IsActive());
9151 EXPECT_TRUE(rfh_b->IsActive());
[email protected]ced590ab292020-03-12 00:37:219152
9153 // 2) Navigate to C.
9154 EXPECT_TRUE(NavigateToURL(shell(), url_c));
Hajime Hoshibbc509c2020-04-06 08:55:089155 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
9156 EXPECT_TRUE(rfh_b->IsInBackForwardCache());
[email protected]ced590ab292020-03-12 00:37:219157
Sreeja Kamishettye49854f82021-06-02 00:52:039158 EXPECT_FALSE(rfh_a->IsActive());
9159 EXPECT_FALSE(rfh_b->IsActive());
[email protected]ced590ab292020-03-12 00:37:219160}
Sreeja Kamishetty19c72912020-04-30 15:49:369161
Sreeja Kamishetty299329ad2021-03-25 14:06:019162// Test that LifecycleStateImpl is updated correctly when page enters and
9163// restores back from BackForwardCache.
Sreeja Kamishetty19c72912020-04-30 15:49:369164IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
9165 CheckLifecycleStateTransition) {
9166 ASSERT_TRUE(embedded_test_server()->Start());
9167 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
9168 GURL url_b(embedded_test_server()->GetURL("b.com", "/title2.html"));
9169
Sreeja Kamishetty299329ad2021-03-25 14:06:019170 // 1) Navigate to A and check the LifecycleStateImpl of A.
Sreeja Kamishetty19c72912020-04-30 15:49:369171 EXPECT_TRUE(NavigateToURL(shell(), url_a));
9172 RenderFrameHostImpl* rfh_a = current_frame_host();
Sreeja Kamishetty299329ad2021-03-25 14:06:019173 EXPECT_EQ(RenderFrameHostImpl::LifecycleStateImpl::kActive,
Sreeja Kamishetty19c72912020-04-30 15:49:369174 rfh_a->lifecycle_state());
Sreeja Kamishetty600f7842021-04-06 14:27:319175 EXPECT_EQ(RenderFrameHost::LifecycleState::kActive,
9176 rfh_a->GetLifecycleState());
Dave Tapuska9c9afe82021-06-22 19:07:459177 EXPECT_TRUE(rfh_a->GetPage().IsPrimary());
Sreeja Kamishetty19c72912020-04-30 15:49:369178
Sreeja Kamishetty299329ad2021-03-25 14:06:019179 // 2) Navigate to B, now A enters BackForwardCache. Check the
9180 // LifecycleStateImpl of both RenderFrameHost A and B.
Kevin McNee0c88f7af2021-04-30 15:17:249181 {
9182 testing::NiceMock<MockWebContentsObserver> state_change_observer(
9183 web_contents());
9184 EXPECT_CALL(state_change_observer,
9185 RenderFrameHostStateChanged(
9186 rfh_a, RenderFrameHost::LifecycleState::kActive,
9187 RenderFrameHost::LifecycleState::kInBackForwardCache));
9188 // We don't know |rfh_b| yet, so we'll match any frame.
9189 EXPECT_CALL(state_change_observer,
9190 RenderFrameHostStateChanged(
9191 testing::Not(rfh_a),
9192 RenderFrameHost::LifecycleState::kPendingCommit,
9193 RenderFrameHost::LifecycleState::kActive));
9194
9195 EXPECT_TRUE(NavigateToURL(shell(), url_b));
9196 }
Sreeja Kamishetty19c72912020-04-30 15:49:369197 RenderFrameHostImpl* rfh_b = current_frame_host();
9198 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
Sreeja Kamishetty299329ad2021-03-25 14:06:019199 EXPECT_EQ(RenderFrameHostImpl::LifecycleStateImpl::kInBackForwardCache,
Sreeja Kamishetty19c72912020-04-30 15:49:369200 rfh_a->lifecycle_state());
Sreeja Kamishetty600f7842021-04-06 14:27:319201 EXPECT_EQ(RenderFrameHost::LifecycleState::kInBackForwardCache,
9202 rfh_a->GetLifecycleState());
Dave Tapuska9c9afe82021-06-22 19:07:459203 EXPECT_FALSE(rfh_a->GetPage().IsPrimary());
Sreeja Kamishetty299329ad2021-03-25 14:06:019204 EXPECT_EQ(RenderFrameHostImpl::LifecycleStateImpl::kActive,
Sreeja Kamishetty19c72912020-04-30 15:49:369205 rfh_b->lifecycle_state());
Sreeja Kamishetty600f7842021-04-06 14:27:319206 EXPECT_EQ(RenderFrameHost::LifecycleState::kActive,
9207 rfh_b->GetLifecycleState());
Dave Tapuska9c9afe82021-06-22 19:07:459208 EXPECT_TRUE(rfh_b->GetPage().IsPrimary());
Sreeja Kamishetty19c72912020-04-30 15:49:369209
Sreeja Kamishetty299329ad2021-03-25 14:06:019210 // 3) Go back to A and check again the LifecycleStateImpl of both
9211 // RenderFrameHost A and B.
Kevin McNee0c88f7af2021-04-30 15:17:249212 {
9213 testing::NiceMock<MockWebContentsObserver> state_change_observer(
9214 web_contents());
9215 EXPECT_CALL(state_change_observer,
9216 RenderFrameHostStateChanged(
9217 rfh_a, RenderFrameHost::LifecycleState::kInBackForwardCache,
9218 RenderFrameHost::LifecycleState::kActive));
9219 EXPECT_CALL(state_change_observer,
9220 RenderFrameHostStateChanged(
9221 rfh_b, RenderFrameHost::LifecycleState::kActive,
9222 RenderFrameHost::LifecycleState::kInBackForwardCache));
9223
9224 web_contents()->GetController().GoBack();
9225 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
9226 }
Sreeja Kamishetty299329ad2021-03-25 14:06:019227 EXPECT_EQ(RenderFrameHostImpl::LifecycleStateImpl::kActive,
Sreeja Kamishetty19c72912020-04-30 15:49:369228 rfh_a->lifecycle_state());
Dave Tapuska9c9afe82021-06-22 19:07:459229 EXPECT_TRUE(rfh_a->GetPage().IsPrimary());
Sreeja Kamishetty19c72912020-04-30 15:49:369230 EXPECT_TRUE(rfh_b->IsInBackForwardCache());
Sreeja Kamishetty299329ad2021-03-25 14:06:019231 EXPECT_EQ(RenderFrameHostImpl::LifecycleStateImpl::kInBackForwardCache,
Sreeja Kamishetty19c72912020-04-30 15:49:369232 rfh_b->lifecycle_state());
Dave Tapuska9c9afe82021-06-22 19:07:459233 EXPECT_FALSE(rfh_b->GetPage().IsPrimary());
Sreeja Kamishetty19c72912020-04-30 15:49:369234}
Sreeja Kamishettydcb4eca2020-06-01 18:05:349235
9236IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
Kevin McNee0c88f7af2021-04-30 15:17:249237 CheckLifecycleStateTransitionWithSubframes) {
9238 IsolateAllSitesForTesting(base::CommandLine::ForCurrentProcess());
9239 ASSERT_TRUE(embedded_test_server()->Start());
9240 GURL url_a(embedded_test_server()->GetURL(
9241 "a.com", "/cross_site_iframe_factory.html?a(b)"));
9242 GURL url_c(embedded_test_server()->GetURL(
9243 "c.com", "/cross_site_iframe_factory.html?c(d)"));
9244
9245 // Navigate to A(B) and check the lifecycle states of A and B.
9246 EXPECT_TRUE(NavigateToURL(shell(), url_a));
9247 RenderFrameHostImpl* rfh_a = current_frame_host();
9248 RenderFrameHostImpl* rfh_b = rfh_a->child_at(0)->current_frame_host();
9249 EXPECT_FALSE(rfh_a->IsInBackForwardCache());
9250 EXPECT_FALSE(rfh_b->IsInBackForwardCache());
9251 EXPECT_EQ(RenderFrameHostImpl::LifecycleStateImpl::kActive,
9252 rfh_a->lifecycle_state());
9253 EXPECT_EQ(RenderFrameHost::LifecycleState::kActive,
9254 rfh_a->GetLifecycleState());
9255 EXPECT_EQ(RenderFrameHostImpl::LifecycleStateImpl::kActive,
9256 rfh_b->lifecycle_state());
9257 EXPECT_EQ(RenderFrameHost::LifecycleState::kActive,
9258 rfh_b->GetLifecycleState());
9259
9260 // Navigate to C(D), now A(B) enters BackForwardCache.
9261 {
9262 testing::NiceMock<MockWebContentsObserver> state_change_observer(
9263 web_contents());
9264 EXPECT_CALL(state_change_observer,
9265 RenderFrameHostStateChanged(
9266 rfh_a, RenderFrameHost::LifecycleState::kActive,
9267 RenderFrameHost::LifecycleState::kInBackForwardCache));
9268 EXPECT_CALL(state_change_observer,
9269 RenderFrameHostStateChanged(
9270 rfh_b, RenderFrameHost::LifecycleState::kActive,
9271 RenderFrameHost::LifecycleState::kInBackForwardCache));
9272 // We don't know |rfh_c| and |rfh_d| yet, so we'll match any frame.
9273 EXPECT_CALL(state_change_observer,
9274 RenderFrameHostStateChanged(
9275 testing::Not(testing::AnyOf(rfh_a, rfh_b)),
9276 RenderFrameHost::LifecycleState::kPendingCommit,
9277 RenderFrameHost::LifecycleState::kActive))
9278 .Times(2);
9279 // Deletion of frame D's initial RFH.
9280 EXPECT_CALL(state_change_observer,
9281 RenderFrameHostStateChanged(
9282 testing::Not(testing::AnyOf(rfh_a, rfh_b)),
9283 RenderFrameHost::LifecycleState::kActive,
9284 RenderFrameHost::LifecycleState::kPendingDeletion));
9285
9286 EXPECT_TRUE(NavigateToURL(shell(), url_c));
9287 }
9288 RenderFrameHostImpl* rfh_c = current_frame_host();
9289 RenderFrameHostImpl* rfh_d = rfh_c->child_at(0)->current_frame_host();
9290 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
9291 EXPECT_TRUE(rfh_b->IsInBackForwardCache());
9292 EXPECT_FALSE(rfh_c->IsInBackForwardCache());
9293 EXPECT_FALSE(rfh_d->IsInBackForwardCache());
9294 EXPECT_EQ(RenderFrameHostImpl::LifecycleStateImpl::kInBackForwardCache,
9295 rfh_a->lifecycle_state());
9296 EXPECT_EQ(RenderFrameHost::LifecycleState::kInBackForwardCache,
9297 rfh_a->GetLifecycleState());
9298 EXPECT_EQ(RenderFrameHostImpl::LifecycleStateImpl::kInBackForwardCache,
9299 rfh_b->lifecycle_state());
9300 EXPECT_EQ(RenderFrameHost::LifecycleState::kInBackForwardCache,
9301 rfh_b->GetLifecycleState());
9302 EXPECT_EQ(RenderFrameHostImpl::LifecycleStateImpl::kActive,
9303 rfh_c->lifecycle_state());
9304 EXPECT_EQ(RenderFrameHost::LifecycleState::kActive,
9305 rfh_c->GetLifecycleState());
9306 EXPECT_EQ(RenderFrameHostImpl::LifecycleStateImpl::kActive,
9307 rfh_d->lifecycle_state());
9308 EXPECT_EQ(RenderFrameHost::LifecycleState::kActive,
9309 rfh_d->GetLifecycleState());
9310
9311 // Go back to A(B), A(B) is restored and C(D) enters BackForwardCache.
9312 {
9313 testing::NiceMock<MockWebContentsObserver> state_change_observer(
9314 web_contents());
9315 EXPECT_CALL(state_change_observer,
9316 RenderFrameHostStateChanged(
9317 rfh_a, RenderFrameHost::LifecycleState::kInBackForwardCache,
9318 RenderFrameHost::LifecycleState::kActive));
9319 EXPECT_CALL(state_change_observer,
9320 RenderFrameHostStateChanged(
9321 rfh_b, RenderFrameHost::LifecycleState::kInBackForwardCache,
9322 RenderFrameHost::LifecycleState::kActive));
9323 EXPECT_CALL(state_change_observer,
9324 RenderFrameHostStateChanged(
9325 rfh_c, RenderFrameHost::LifecycleState::kActive,
9326 RenderFrameHost::LifecycleState::kInBackForwardCache));
9327 EXPECT_CALL(state_change_observer,
9328 RenderFrameHostStateChanged(
9329 rfh_d, RenderFrameHost::LifecycleState::kActive,
9330 RenderFrameHost::LifecycleState::kInBackForwardCache));
9331
9332 web_contents()->GetController().GoBack();
9333 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
9334 }
9335 EXPECT_FALSE(rfh_a->IsInBackForwardCache());
9336 EXPECT_FALSE(rfh_b->IsInBackForwardCache());
9337 EXPECT_TRUE(rfh_c->IsInBackForwardCache());
9338 EXPECT_TRUE(rfh_d->IsInBackForwardCache());
9339 EXPECT_EQ(RenderFrameHostImpl::LifecycleStateImpl::kActive,
9340 rfh_a->lifecycle_state());
9341 EXPECT_EQ(RenderFrameHost::LifecycleState::kActive,
9342 rfh_a->GetLifecycleState());
9343 EXPECT_EQ(RenderFrameHostImpl::LifecycleStateImpl::kActive,
9344 rfh_b->lifecycle_state());
9345 EXPECT_EQ(RenderFrameHost::LifecycleState::kActive,
9346 rfh_b->GetLifecycleState());
9347 EXPECT_EQ(RenderFrameHostImpl::LifecycleStateImpl::kInBackForwardCache,
9348 rfh_c->lifecycle_state());
9349 EXPECT_EQ(RenderFrameHost::LifecycleState::kInBackForwardCache,
9350 rfh_c->GetLifecycleState());
9351 EXPECT_EQ(RenderFrameHostImpl::LifecycleStateImpl::kInBackForwardCache,
9352 rfh_d->lifecycle_state());
9353 EXPECT_EQ(RenderFrameHost::LifecycleState::kInBackForwardCache,
9354 rfh_d->GetLifecycleState());
9355}
9356
9357IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
Sreeja Kamishettydbcb3b502020-07-01 15:44:019358 DoesNotCacheIfSpeechRecognitionIsStarted) {
Sreeja Kamishettydcb4eca2020-06-01 18:05:349359 ASSERT_TRUE(embedded_test_server()->Start());
Sreeja Kamishettydbcb3b502020-07-01 15:44:019360 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
9361 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
Sreeja Kamishettydcb4eca2020-06-01 18:05:349362
Sreeja Kamishettydbcb3b502020-07-01 15:44:019363 // 1) Navigate to url_a.
9364 EXPECT_TRUE(NavigateToURL(shell(), url_a));
Sreeja Kamishettydcb4eca2020-06-01 18:05:349365 RenderFrameHostImpl* rfh_a = current_frame_host();
Sreeja Kamishettydbcb3b502020-07-01 15:44:019366 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
Sreeja Kamishettydcb4eca2020-06-01 18:05:349367
Sreeja Kamishettydbcb3b502020-07-01 15:44:019368 // 2) Start SpeechRecognition.
9369 EXPECT_TRUE(ExecJs(rfh_a, R"(
9370 new Promise(async resolve => {
9371 var r = new webkitSpeechRecognition();
9372 r.start();
9373 resolve();
9374 });
9375 )"));
Sreeja Kamishettydcb4eca2020-06-01 18:05:349376
Sreeja Kamishettydbcb3b502020-07-01 15:44:019377 // 3) Navigate away.
9378 EXPECT_TRUE(NavigateToURL(shell(), url_b));
Sreeja Kamishettydcb4eca2020-06-01 18:05:349379
Sreeja Kamishettydbcb3b502020-07-01 15:44:019380 // 4) The page uses SpeechRecognition so it should be deleted.
9381 delete_observer_rfh_a.WaitUntilDeleted();
9382
9383 // 5) Go back to the page with SpeechRecognition.
Sreeja Kamishettydcb4eca2020-06-01 18:05:349384 web_contents()->GetController().GoBack();
9385 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
9386 ExpectNotRestored(
9387 {BackForwardCacheMetrics::NotRestoredReason::kBlocklistedFeatures},
Fergal Daly6755cbf2021-02-12 03:06:589388 {blink::scheduler::WebSchedulerTrackedFeature::kSpeechRecognizer}, {}, {},
Sreeja Kamishettydcb4eca2020-06-01 18:05:349389 FROM_HERE);
9390}
9391
Sreeja Kamishettydbcb3b502020-07-01 15:44:019392IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
9393 CanCacheIfSpeechRecognitionIsNotStarted) {
9394 ASSERT_TRUE(embedded_test_server()->Start());
9395 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
9396 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
9397
9398 // 1) Navigate to url_a.
9399 EXPECT_TRUE(NavigateToURL(shell(), url_a));
9400 RenderFrameHostImpl* rfh_a = current_frame_host();
9401 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
9402
9403 // 2) Initialise SpeechRecognition but don't start it yet.
9404 EXPECT_TRUE(ExecJs(rfh_a, R"(
9405 new Promise(async resolve => {
9406 var r = new webkitSpeechRecognition();
9407 resolve();
9408 });
9409 )"));
9410
9411 // 3) Navigate away.
9412 EXPECT_TRUE(NavigateToURL(shell(), url_b));
9413
9414 // 4) The page didn't start using SpeechRecognition so it shouldn't be deleted
9415 // and enter BackForwardCache.
9416 EXPECT_FALSE(delete_observer_rfh_a.deleted());
9417 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
9418
9419 // 5) Go back to the page with SpeechRecognition.
9420 web_contents()->GetController().GoBack();
9421 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
9422 EXPECT_EQ(rfh_a, current_frame_host());
9423
Fergal Daly09833062021-02-09 07:10:009424 ExpectRestored(FROM_HERE);
Sreeja Kamishettydbcb3b502020-07-01 15:44:019425}
9426
Sreeja Kamishettye6c1ca72020-06-09 22:40:389427// This test is not important for Chrome OS if TTS is called in content. For
9428// more details refer (content/browser/speech/tts_platform_impl.cc).
Yuta Hijikatad0a8b6b2020-11-20 16:36:159429#if BUILDFLAG(IS_CHROMEOS_ASH)
Sreeja Kamishettye6c1ca72020-06-09 22:40:389430#define MAYBE_DoesNotCacheIfUsingSpeechSynthesis \
9431 DISABLED_DoesNotCacheIfUsingSpeechSynthesis
9432#else
9433#define MAYBE_DoesNotCacheIfUsingSpeechSynthesis \
9434 DoesNotCacheIfUsingSpeechSynthesis
Yuta Hijikatad0a8b6b2020-11-20 16:36:159435#endif // BUILDFLAG(IS_CHROMEOS_ASH)
Sreeja Kamishettye6c1ca72020-06-09 22:40:389436IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
9437 MAYBE_DoesNotCacheIfUsingSpeechSynthesis) {
9438 ASSERT_TRUE(embedded_test_server()->Start());
9439 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
9440 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
9441
9442 // 1) Navigate to a page and start using SpeechSynthesis.
9443 EXPECT_TRUE(NavigateToURL(shell(), url_a));
9444 RenderFrameHostImpl* rfh_a = current_frame_host();
9445 RenderFrameDeletedObserver rhf_a_deleted(rfh_a);
9446
9447 EXPECT_TRUE(ExecJs(rfh_a, R"(
9448 new Promise(async resolve => {
9449 var u = new SpeechSynthesisUtterance(" ");
9450 speechSynthesis.speak(u);
9451 resolve();
9452 });
9453 )"));
9454
9455 // 2) Navigate away.
9456 EXPECT_TRUE(NavigateToURL(shell(), url_b));
9457
9458 // The page uses SpeechSynthesis so it should be deleted.
9459 rhf_a_deleted.WaitUntilDeleted();
9460
9461 // 3) Go back to the page with SpeechSynthesis.
9462 web_contents()->GetController().GoBack();
9463 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
9464 ExpectNotRestored(
9465 {BackForwardCacheMetrics::NotRestoredReason::kBlocklistedFeatures},
Fergal Daly6755cbf2021-02-12 03:06:589466 {blink::scheduler::WebSchedulerTrackedFeature::kSpeechSynthesis}, {}, {},
Sreeja Kamishettye6c1ca72020-06-09 22:40:389467 FROM_HERE);
9468}
9469
Sreeja Kamishettybfd828d2020-06-10 11:56:059470IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
9471 DoesNotCacheIfRunFileChooserIsInvoked) {
9472 ASSERT_TRUE(embedded_test_server()->Start());
9473 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
9474 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
9475
9476 // 1) Navigate to url_a and open file chooser.
9477 EXPECT_TRUE(NavigateToURL(shell(), url_a));
9478 RenderFrameHostImpl* rfh_a = current_frame_host();
9479 RenderFrameDeletedObserver deleted_rfh_a(rfh_a);
9480 content::BackForwardCacheDisabledTester tester;
9481
9482 // 2) Bind FileChooser to RenderFrameHost.
9483 mojo::Remote<blink::mojom::FileChooser> chooser =
9484 FileChooserImpl::CreateBoundForTesting(rfh_a);
9485
9486 auto quit_run_loop = [](base::OnceClosure callback,
9487 blink::mojom::FileChooserResultPtr result) {
9488 std::move(callback).Run();
9489 };
9490
9491 // 3) Run OpenFileChooser and wait till its run.
9492 base::RunLoop run_loop;
9493 chooser->OpenFileChooser(
9494 blink::mojom::FileChooserParams::New(),
9495 base::BindOnce(quit_run_loop, run_loop.QuitClosure()));
9496 run_loop.Run();
9497
9498 // 4) rfh_a should be disabled for BackForwardCache after opening file
9499 // chooser.
9500 EXPECT_TRUE(rfh_a->IsBackForwardCacheDisabled());
Fergal Daly23b8ae62021-03-30 05:43:469501 auto reason = BackForwardCacheDisable::DisabledReason(
9502 BackForwardCacheDisable::DisabledReasonId::kFileChooser);
Sreeja Kamishettybfd828d2020-06-10 11:56:059503 EXPECT_TRUE(tester.IsDisabledForFrameWithReason(
Fergal Daly23b8ae62021-03-30 05:43:469504 rfh_a->GetProcess()->GetID(), rfh_a->GetRoutingID(), reason));
Sreeja Kamishettybfd828d2020-06-10 11:56:059505
9506 // 5) Navigate to B having the file chooser open.
9507 EXPECT_TRUE(NavigateToURL(shell(), url_b));
9508
9509 // The page uses FileChooser so it should be deleted.
9510 deleted_rfh_a.WaitUntilDeleted();
9511
9512 // 6) Go back to the page with FileChooser.
9513 web_contents()->GetController().GoBack();
9514 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
Fergal Daly09833062021-02-09 07:10:009515 ExpectNotRestored({BackForwardCacheMetrics::NotRestoredReason::
9516 kDisableForRenderFrameHostCalled},
Fergal Daly23b8ae62021-03-30 05:43:469517 {}, {}, {reason}, FROM_HERE);
Sreeja Kamishettybfd828d2020-06-10 11:56:059518}
9519
arthursonzogni3e6b1412020-08-05 19:02:389520// RenderFrameHostImpl::coep_reporter() must be preserved when doing a back
9521// navigation using the BackForwardCache.
9522// Regression test for https://crbug.com/1102285.
9523IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, CoepReporter) {
9524 ASSERT_TRUE(CreateHttpsServer()->Start());
9525 GURL url_a(https_server()->GetURL("a.com",
9526 "/set-header?"
9527 "Cross-Origin-Embedder-Policy-Report-Only: "
Camille Lamy9566ead2020-12-15 13:59:409528 "require-corp; report-to%3d\"a\""));
arthursonzogni3e6b1412020-08-05 19:02:389529 GURL url_b(https_server()->GetURL("b.com", "/title1.html"));
9530
9531 // Navigate to a document that set RenderFrameHostImpl::coep_reporter().
9532 EXPECT_TRUE(NavigateToURL(shell(), url_a));
9533 RenderFrameHostImpl* rfh_a = current_frame_host();
9534 EXPECT_TRUE(rfh_a->coep_reporter());
9535
9536 // Navigate away and back using the BackForwardCache. The
9537 // RenderFrameHostImpl::coep_reporter() must still be there.
9538 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
9539 EXPECT_TRUE(NavigateToURL(shell(), url_b));
9540 web_contents()->GetController().GoBack();
9541 EXPECT_TRUE(WaitForLoadStop(web_contents()));
9542 EXPECT_FALSE(delete_observer_rfh_a.deleted());
9543 EXPECT_EQ(rfh_a, current_frame_host());
9544
9545 EXPECT_TRUE(rfh_a->coep_reporter());
9546}
9547
9548// RenderFrameHostImpl::coop_reporter() must be preserved when doing a back
9549// navigation using the BackForwardCache.
9550// Regression test for https://crbug.com/1102285.
9551IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, CoopReporter) {
9552 ASSERT_TRUE(CreateHttpsServer()->Start());
9553 GURL url_a(https_server()->GetURL("a.com",
9554 "/set-header?"
9555 "Cross-Origin-Opener-Policy-Report-Only: "
9556 "same-origin; report-to%3d\"a\""));
9557 GURL url_b(https_server()->GetURL("b.com", "/title1.html"));
9558
9559 // Navigate to a document that set RenderFrameHostImpl::coop_reporter().
9560 EXPECT_TRUE(NavigateToURL(shell(), url_a));
9561 RenderFrameHostImpl* rfh_a = current_frame_host();
Camille Lamy091346f62021-08-27 09:57:409562 EXPECT_TRUE(rfh_a->coop_access_report_manager()->coop_reporter());
arthursonzogni3e6b1412020-08-05 19:02:389563
9564 // Navigate away and back using the BackForwardCache. The
9565 // RenderFrameHostImpl::coop_reporter() must still be there.
9566 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
9567 EXPECT_TRUE(NavigateToURL(shell(), url_b));
9568 web_contents()->GetController().GoBack();
9569 EXPECT_TRUE(WaitForLoadStop(web_contents()));
9570 EXPECT_FALSE(delete_observer_rfh_a.deleted());
9571 EXPECT_EQ(rfh_a, current_frame_host());
9572
Camille Lamy091346f62021-08-27 09:57:409573 EXPECT_TRUE(rfh_a->coop_access_report_manager()->coop_reporter());
arthursonzogni3e6b1412020-08-05 19:02:389574}
9575
Camille Lamy9566ead2020-12-15 13:59:409576// RenderFrameHostImpl::cross_origin_embedder_policy() must be preserved when
9577// doing a back navigation using the BackForwardCache.
9578// Regression test for https://crbug.com/1021846.
9579IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, Coep) {
9580 ASSERT_TRUE(CreateHttpsServer()->Start());
9581 GURL url_a(https_server()->GetURL(
9582 "a.com", "/set-header?Cross-Origin-Embedder-Policy: require-corp"));
9583 GURL url_b(https_server()->GetURL("b.com", "/title1.html"));
9584
9585 // Navigate to a document that sets COEP.
9586 network::CrossOriginEmbedderPolicy coep;
9587 coep.value = network::mojom::CrossOriginEmbedderPolicyValue::kRequireCorp;
9588 EXPECT_TRUE(NavigateToURL(shell(), url_a));
9589 RenderFrameHostImpl* rfh_a = current_frame_host();
9590 EXPECT_EQ(coep, rfh_a->cross_origin_embedder_policy());
9591
9592 // Navigate away and back using the BackForwardCache.
9593 // RenderFrameHostImpl::cross_origin_embedder_policy() should return the same
9594 // result.
9595 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
9596 EXPECT_TRUE(NavigateToURL(shell(), url_b));
9597 web_contents()->GetController().GoBack();
9598 EXPECT_TRUE(WaitForLoadStop(web_contents()));
9599 EXPECT_FALSE(delete_observer_rfh_a.deleted());
9600 EXPECT_EQ(rfh_a, current_frame_host());
9601
9602 EXPECT_EQ(coep, rfh_a->cross_origin_embedder_policy());
9603}
9604
Carlos Caballero8b114db2020-08-13 08:57:039605namespace {
9606
9607class EchoFakeWithFilter final : public mojom::Echo {
9608 public:
9609 explicit EchoFakeWithFilter(mojo::PendingReceiver<mojom::Echo> receiver,
9610 std::unique_ptr<mojo::MessageFilter> filter)
9611 : receiver_(this, std::move(receiver)) {
9612 receiver_.SetFilter(std::move(filter));
9613 }
9614 ~EchoFakeWithFilter() override = default;
9615
9616 // mojom::Echo implementation
9617 void EchoString(const std::string& input,
9618 EchoStringCallback callback) override {
9619 std::move(callback).Run(input);
9620 }
9621
9622 private:
9623 mojo::Receiver<mojom::Echo> receiver_;
9624};
9625
9626} // namespace
9627
Carlos Caballero0e2fff922020-09-15 12:52:199628IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
9629 MessageReceivedOnAssociatedInterfaceWhileCached) {
9630 DoNotFailForUnexpectedMessagesWhileCached();
Carlos Caballero8b114db2020-08-13 08:57:039631 ASSERT_TRUE(embedded_test_server()->Start());
9632 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
9633 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
Carlos Caballero8b114db2020-08-13 08:57:039634
9635 // 1) Navigate to A.
9636 EXPECT_TRUE(NavigateToURL(shell(), url_a));
9637 RenderFrameHostImpl* rfh_a = current_frame_host();
9638 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
9639 PageLifecycleStateManagerTestDelegate delegate(
9640 rfh_a->render_view_host()->GetPageLifecycleStateManager());
9641
9642 // 2) Navigate to B.
9643 EXPECT_TRUE(NavigateToURL(shell(), url_b));
9644 delegate.WaitForInBackForwardCacheAck();
9645 ASSERT_FALSE(delete_observer_rfh_a.deleted());
9646 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
9647
9648 mojo::Remote<mojom::Echo> remote;
9649 EchoFakeWithFilter echo(
9650 remote.BindNewPipeAndPassReceiver(),
9651 rfh_a->CreateMessageFilterForAssociatedReceiver(mojom::Echo::Name_));
9652
Carlos Caballero0e2fff922020-09-15 12:52:199653 base::RunLoop loop;
9654 remote->EchoString(
9655 "", base::BindLambdaForTesting([&](const std::string&) { loop.Quit(); }));
9656 loop.Run();
Carlos Caballero8b114db2020-08-13 08:57:039657
Rakina Zata Amni7a8fca52020-08-20 07:59:319658 ExpectBucketCount(
Carlos Caballero87885792020-08-13 12:30:049659 "BackForwardCache.UnexpectedRendererToBrowserMessage.InterfaceName",
9660 base::HistogramBase::Sample(
9661 static_cast<int32_t>(base::HashMetricName(mojom::Echo::Name_))),
9662 1);
Carlos Caballero8b114db2020-08-13 08:57:039663}
9664
9665IN_PROC_BROWSER_TEST_F(
9666 BackForwardCacheBrowserTest,
Carlos Caballero0e2fff922020-09-15 12:52:199667 MessageReceivedOnAssociatedInterfaceWhileCachedForProcessWithNonCachedPages) {
9668 ASSERT_TRUE(embedded_test_server()->Start());
9669 GURL url_a(embedded_test_server()->GetURL("/title1.html"));
9670 GURL url_b(embedded_test_server()->GetURL("/title2.html"));
9671
9672 // 1) Navigate to A.
9673 EXPECT_TRUE(NavigateToURL(shell(), url_a));
9674 RenderFrameHostImpl* rfh_a = current_frame_host();
9675 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
9676 PageLifecycleStateManagerTestDelegate delegate(
9677 rfh_a->render_view_host()->GetPageLifecycleStateManager());
9678
9679 // 2) Navigate to B.
9680 EXPECT_TRUE(NavigateToURL(shell(), url_b));
9681 delegate.WaitForInBackForwardCacheAck();
9682 RenderFrameHostImpl* rfh_b = current_frame_host();
9683 ASSERT_FALSE(delete_observer_rfh_a.deleted());
9684 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
9685 // Make sure both pages are on the same process (they are same site so they
9686 // should).
9687 ASSERT_EQ(rfh_a->GetProcess(), rfh_b->GetProcess());
9688
9689 mojo::Remote<mojom::Echo> remote;
9690 EchoFakeWithFilter echo(
9691 remote.BindNewPipeAndPassReceiver(),
9692 rfh_a->CreateMessageFilterForAssociatedReceiver(mojom::Echo::Name_));
9693
9694 remote->EchoString("", base::NullCallback());
9695 // Give the killing a chance to run. (We do not expect a kill but need to
9696 // "wait" for it to not happen)
9697 base::RunLoop().RunUntilIdle();
9698
9699 // 3) Go back to A.
9700 web_contents()->GetController().GoBack();
9701 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
9702
Fergal Daly09833062021-02-09 07:10:009703 ExpectRestored(FROM_HERE);
Carlos Caballero0e2fff922020-09-15 12:52:199704}
9705
9706IN_PROC_BROWSER_TEST_F(
Rakina Zata Amni8d49da52020-11-06 09:23:109707 HighCacheSizeBackForwardCacheBrowserTest,
Carlos Caballero0e2fff922020-09-15 12:52:199708 MessageReceivedOnAssociatedInterfaceForProcessWithMultipleCachedPages) {
9709 DoNotFailForUnexpectedMessagesWhileCached();
Carlos Caballero0e2fff922020-09-15 12:52:199710 ASSERT_TRUE(embedded_test_server()->Start());
9711 GURL url_a_1(embedded_test_server()->GetURL("a.com", "/title1.html"));
9712 GURL url_a_2(embedded_test_server()->GetURL("a.com", "/title2.html"));
9713 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
9714
9715 // Get url_a_1 and url_a_2 into the cache.
9716 EXPECT_TRUE(NavigateToURL(shell(), url_a_1));
9717 RenderFrameHostImpl* rfh_a_1 = current_frame_host();
9718 RenderFrameDeletedObserver delete_observer_rfh_a_1(rfh_a_1);
9719
9720 EXPECT_TRUE(NavigateToURL(shell(), url_a_2));
9721 RenderFrameHostImpl* rfh_a_2 = current_frame_host();
9722 RenderFrameDeletedObserver delete_observer_rfh_a_2(rfh_a_2);
9723
9724 EXPECT_TRUE(NavigateToURL(shell(), url_b));
9725 RenderFrameHostImpl* rfh_b = current_frame_host();
9726 RenderFrameDeletedObserver delete_observer_rfh_b(rfh_b);
9727
9728 ASSERT_FALSE(delete_observer_rfh_a_1.deleted());
9729 ASSERT_FALSE(delete_observer_rfh_a_2.deleted());
9730 EXPECT_TRUE(rfh_a_1->IsInBackForwardCache());
9731 EXPECT_TRUE(rfh_a_2->IsInBackForwardCache());
9732 ASSERT_EQ(rfh_a_1->GetProcess(), rfh_a_2->GetProcess());
9733
9734 mojo::Remote<mojom::Echo> remote;
9735 EchoFakeWithFilter echo(
9736 remote.BindNewPipeAndPassReceiver(),
9737 rfh_a_1->CreateMessageFilterForAssociatedReceiver(mojom::Echo::Name_));
9738
9739 base::RunLoop loop;
9740 remote->EchoString(
9741 "", base::BindLambdaForTesting([&](const std::string&) { loop.Quit(); }));
9742 loop.Run();
9743
9744 ExpectBucketCount(
9745 "BackForwardCache.UnexpectedRendererToBrowserMessage.InterfaceName",
9746 base::HistogramBase::Sample(
9747 static_cast<int32_t>(base::HashMetricName(mojom::Echo::Name_))),
9748 1);
9749
9750 EXPECT_FALSE(delete_observer_rfh_b.deleted());
9751}
9752
9753IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
9754 MessageReceivedOnAssociatedInterfaceWhileFreezing) {
Carlos Caballero8b114db2020-08-13 08:57:039755 ASSERT_TRUE(embedded_test_server()->Start());
9756 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
9757 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
9758 url::Origin origin_a = url::Origin::Create(url_a);
9759 url::Origin origin_b = url::Origin::Create(url_b);
9760
9761 // 1) Navigate to A.
9762 EXPECT_TRUE(NavigateToURL(shell(), url_a));
9763 RenderFrameHostImpl* rfh_a = current_frame_host();
9764 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
9765 PageLifecycleStateManagerTestDelegate delegate(
9766 rfh_a->render_view_host()->GetPageLifecycleStateManager());
9767
9768 mojo::Remote<mojom::Echo> remote;
9769 EchoFakeWithFilter echo(
9770 remote.BindNewPipeAndPassReceiver(),
9771 rfh_a->CreateMessageFilterForAssociatedReceiver(mojom::Echo::Name_));
9772
9773 delegate.OnStoreInBackForwardCacheSent(base::BindLambdaForTesting(
9774 [&]() { remote->EchoString("", base::NullCallback()); }));
9775
9776 delegate.OnRestoreFromBackForwardCacheSent(base::BindLambdaForTesting(
9777 [&]() { remote->EchoString("", base::NullCallback()); }));
9778
9779 // 2) Navigate to B.
9780 EXPECT_TRUE(NavigateToURL(shell(), url_b));
9781
9782 // 3) Go back to A.
9783 web_contents()->GetController().GoBack();
9784 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
9785
Fergal Daly09833062021-02-09 07:10:009786 ExpectRestored(FROM_HERE);
Carlos Caballero8b114db2020-08-13 08:57:039787}
9788
Rakina Zata Amni72570182020-08-14 13:25:399789// Tests that if a page is already ineligible to be saved in the back-forward
9790// cache at navigation time, we shouldn't try to proactively swap
9791// BrowsingInstances.
9792IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
9793 ShouldNotSwapBrowsingInstanceWhenPageWillNotBeCached) {
9794 ASSERT_TRUE(embedded_test_server()->Start());
9795 GURL url_1(embedded_test_server()->GetURL("/title1.html"));
9796 GURL url_2(embedded_test_server()->GetURL("/title2.html"));
9797 GURL url_3(embedded_test_server()->GetURL("/title3.html"));
9798
9799 // 1) Navigate to |url_1| .
9800 EXPECT_TRUE(NavigateToURL(shell(), url_1));
9801 RenderFrameHostImpl* rfh_1 = current_frame_host();
9802 scoped_refptr<SiteInstanceImpl> site_instance_1 =
9803 static_cast<SiteInstanceImpl*>(rfh_1->GetSiteInstance());
9804
9805 // 2) Navigate to |url_2|.
9806 EXPECT_TRUE(NavigateToURL(shell(), url_2));
9807 RenderFrameHostImpl* rfh_2 = current_frame_host();
9808 RenderFrameDeletedObserver rfh_2_deleted_observer(rfh_2);
9809 scoped_refptr<SiteInstanceImpl> site_instance_2 =
9810 static_cast<SiteInstanceImpl*>(rfh_2->GetSiteInstance());
9811
9812 // |rfh_1| should get into the back-forward cache.
9813 EXPECT_TRUE(rfh_1->IsInBackForwardCache());
9814 // Check that title1.html and title2.html are in different BrowsingInstances.
9815 EXPECT_FALSE(site_instance_1->IsRelatedSiteInstance(site_instance_2.get()));
9816
9817 // Disable the BackForwardCache for |rfh_2|.
Julie Jeongeun Kim8ecd5142021-08-04 07:18:439818 DisableBFCacheForRFHForTesting(rfh_2->GetGlobalId());
Rakina Zata Amni72570182020-08-14 13:25:399819
9820 // 3) Navigate to |url_3|.
9821 EXPECT_TRUE(NavigateToURL(shell(), url_3));
9822 RenderFrameHostImpl* rfh_3 = current_frame_host();
9823 scoped_refptr<SiteInstanceImpl> site_instance_3 =
9824 static_cast<SiteInstanceImpl*>(rfh_3->GetSiteInstance());
9825
9826 // Check that |url_2| and |url_3| are reusing the same SiteInstance (and
9827 // BrowsingInstance).
9828 EXPECT_EQ(site_instance_2, site_instance_3);
9829 if (rfh_2 != rfh_3) {
9830 // If we aren't reusing the RenderFrameHost then |rfh_2| will eventually
9831 // get deleted because it's not saved in the back-forward cache.
9832 rfh_2_deleted_observer.WaitUntilDeleted();
9833 }
9834}
9835
Rakina Zata Amni60858132020-08-19 10:33:489836// Tests that pagehide and visibilitychange handlers of the old RFH are run for
9837// bfcached pages.
9838IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
9839 PagehideAndVisibilitychangeRuns) {
9840 ASSERT_TRUE(embedded_test_server()->Start());
9841 GURL url_1(embedded_test_server()->GetURL("a.com", "/title1.html"));
9842 GURL url_2(embedded_test_server()->GetURL("b.com", "/title2.html"));
9843 GURL url_3(embedded_test_server()->GetURL("a.com", "/title2.html"));
9844 WebContentsImpl* web_contents =
9845 static_cast<WebContentsImpl*>(shell()->web_contents());
9846
9847 // 1) Navigate to |url_1|.
9848 EXPECT_TRUE(NavigateToURL(shell(), url_1));
9849 RenderFrameHostImpl* main_frame_1 = web_contents->GetMainFrame();
9850
9851 // Create a pagehide handler that sets item "pagehide_storage" and a
9852 // visibilitychange handler that sets item "visibilitychange_storage" in
9853 // localStorage.
9854 EXPECT_TRUE(ExecJs(main_frame_1,
9855 R"(
9856 localStorage.setItem('pagehide_storage', 'not_dispatched');
9857 var dispatched_pagehide = false;
9858 window.onpagehide = function(e) {
9859 if (dispatched_pagehide) {
9860 // We shouldn't dispatch pagehide more than once.
9861 localStorage.setItem('pagehide_storage', 'dispatched_more_than_once');
9862 } else if (!e.persisted) {
9863 localStorage.setItem('pagehide_storage', 'wrong_persisted');
9864 } else {
9865 localStorage.setItem('pagehide_storage', 'dispatched_once');
9866 }
9867 dispatched_pagehide = true;
9868 }
9869 localStorage.setItem('visibilitychange_storage', 'not_dispatched');
9870 var dispatched_visibilitychange = false;
9871 document.onvisibilitychange = function(e) {
9872 if (dispatched_visibilitychange) {
9873 // We shouldn't dispatch visibilitychange more than once.
9874 localStorage.setItem('visibilitychange_storage',
9875 'dispatched_more_than_once');
9876 } else if (document.visibilityState != 'hidden') {
9877 // We should dispatch the event when the visibilityState is 'hidden'.
9878 localStorage.setItem('visibilitychange_storage', 'not_hidden');
9879 } else {
9880 localStorage.setItem('visibilitychange_storage', 'dispatched_once');
9881 }
9882 dispatched_visibilitychange = true;
9883 }
9884 )"));
9885
9886 // 2) Navigate cross-site to |url_2|. We need to navigate cross-site to make
9887 // sure we won't run pagehide and visibilitychange during new page's commit,
9888 // which is tested in ProactivelySwapBrowsingInstancesSameSiteTest.
9889 EXPECT_TRUE(NavigateToURL(shell(), url_2));
9890
9891 // |main_frame_1| should be in the back-forward cache.
9892 EXPECT_TRUE(main_frame_1->IsInBackForwardCache());
9893
9894 // 3) Navigate to |url_3| which is same-origin with |url_1|, so we can check
9895 // the localStorage values.
9896 EXPECT_TRUE(NavigateToURL(shell(), url_3));
9897 RenderFrameHostImpl* main_frame_3 = web_contents->GetMainFrame();
9898
9899 // Check that the value for 'pagehide_storage' and 'visibilitychange_storage'
9900 // are set correctly.
9901 EXPECT_EQ("dispatched_once",
9902 EvalJs(main_frame_3, "localStorage.getItem('pagehide_storage')"));
9903 EXPECT_EQ(
9904 "dispatched_once",
9905 EvalJs(main_frame_3, "localStorage.getItem('visibilitychange_storage')"));
9906}
9907
9908// Tests that pagehide handlers of the old RFH are run for bfcached pages even
9909// if the page is already hidden (and visibilitychange won't run).
Ioana Pandele4892be8b2021-01-26 18:05:499910// Disabled on Linux and Win because of flakiness, see crbug.com/1170802.
Yuta Hijikata9ffc83fb2021-01-29 16:46:019911// TODO(crbug.com/1052397): Revisit once build flag switch of lacros-chrome is
9912// complete.
9913#if (defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)) || defined(OS_WIN)
Ioana Pandele4892be8b2021-01-26 18:05:499914#define MAYBE_PagehideRunsWhenPageIsHidden DISABLED_PagehideRunsWhenPageIsHidden
9915#else
9916#define MAYBE_PagehideRunsWhenPageIsHidden PagehideRunsWhenPageIsHidden
9917#endif
Rakina Zata Amni60858132020-08-19 10:33:489918IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
Ioana Pandele4892be8b2021-01-26 18:05:499919 MAYBE_PagehideRunsWhenPageIsHidden) {
Rakina Zata Amni60858132020-08-19 10:33:489920 ASSERT_TRUE(embedded_test_server()->Start());
9921 GURL url_1(embedded_test_server()->GetURL("a.com", "/title1.html"));
9922 GURL url_2(embedded_test_server()->GetURL("b.com", "/title2.html"));
9923 GURL url_3(embedded_test_server()->GetURL("a.com", "/title2.html"));
9924 WebContentsImpl* web_contents =
9925 static_cast<WebContentsImpl*>(shell()->web_contents());
9926
9927 // 1) Navigate to |url_1| and hide the tab.
9928 EXPECT_TRUE(NavigateToURL(shell(), url_1));
9929 RenderFrameHostImpl* main_frame_1 = web_contents->GetMainFrame();
9930 // We need to set it to Visibility::VISIBLE first in case this is the first
9931 // time the visibility is updated.
9932 web_contents->UpdateWebContentsVisibility(Visibility::VISIBLE);
9933 web_contents->UpdateWebContentsVisibility(Visibility::HIDDEN);
9934 EXPECT_EQ(Visibility::HIDDEN, web_contents->GetVisibility());
9935
9936 // Create a pagehide handler that sets item "pagehide_storage" and a
9937 // visibilitychange handler that sets item "visibilitychange_storage" in
9938 // localStorage.
9939 EXPECT_TRUE(ExecJs(main_frame_1,
9940 R"(
9941 localStorage.setItem('pagehide_storage', 'not_dispatched');
9942 var dispatched_pagehide = false;
9943 window.onpagehide = function(e) {
9944 if (dispatched_pagehide) {
9945 // We shouldn't dispatch pagehide more than once.
9946 localStorage.setItem('pagehide_storage', 'dispatched_more_than_once');
9947 } else if (!e.persisted) {
9948 localStorage.setItem('pagehide_storage', 'wrong_persisted');
9949 } else {
9950 localStorage.setItem('pagehide_storage', 'dispatched_once');
9951 }
9952 dispatched_pagehide = true;
9953 }
9954 localStorage.setItem('visibilitychange_storage', 'not_dispatched');
9955 document.onvisibilitychange = function(e) {
9956 localStorage.setItem('visibilitychange_storage',
9957 'should_not_be_dispatched');
9958 }
9959 )"));
9960 // |visibilitychange_storage| should be set to its initial correct value.
9961 EXPECT_EQ(
9962 "not_dispatched",
9963 EvalJs(main_frame_1, "localStorage.getItem('visibilitychange_storage')"));
9964
9965 // 2) Navigate cross-site to |url_2|. We need to navigate cross-site to make
9966 // sure we won't run pagehide and visibilitychange during new page's commit,
9967 // which is tested in ProactivelySwapBrowsingInstancesSameSiteTest.
9968 EXPECT_TRUE(NavigateToURL(shell(), url_2));
9969
9970 // |main_frame_1| should be in the back-forward cache.
9971 EXPECT_TRUE(main_frame_1->IsInBackForwardCache());
9972
9973 // 3) Navigate to |url_3| which is same-origin with |url_1|, so we can check
9974 // the localStorage values.
9975 EXPECT_TRUE(NavigateToURL(shell(), url_3));
9976 RenderFrameHostImpl* main_frame_3 = web_contents->GetMainFrame();
9977
9978 // Check that the value for 'pagehide_storage' and 'visibilitychange_storage'
9979 // are set correctly.
9980 EXPECT_EQ("dispatched_once",
9981 EvalJs(main_frame_3, "localStorage.getItem('pagehide_storage')"));
9982 EXPECT_EQ(
9983 "not_dispatched",
9984 EvalJs(main_frame_3, "localStorage.getItem('visibilitychange_storage')"));
9985}
9986
Rakina Zata Amniefcc2932020-08-28 07:24:379987// Tests that we're getting the correct TextInputState and focus updates when a
9988// page enters the back-forward cache and when it gets restored.
9989IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, TextInputStateUpdated) {
9990 ASSERT_TRUE(embedded_test_server()->Start());
9991 GURL url_1(embedded_test_server()->GetURL("a.com", "/title1.html"));
9992 GURL url_2(embedded_test_server()->GetURL("b.com", "/title2.html"));
9993
9994 // 1) Navigate to |url_1| and add a text input with "foo" as the value.
9995 EXPECT_TRUE(NavigateToURL(shell(), url_1));
9996 RenderFrameHostImpl* rfh_1 = current_frame_host();
9997 EXPECT_TRUE(ExecJs(rfh_1,
9998 "document.title='bfcached';"
9999 "var input = document.createElement('input');"
10000 "input.setAttribute('type', 'text');"
10001 "input.setAttribute('value', 'foo');"
10002 "document.body.appendChild(input);"
10003 "var focusCount = 0;"
10004 "var blurCount = 0;"
10005 "input.onfocus = () => { focusCount++;};"
10006 "input.onblur = () => { blurCount++; };"));
10007
10008 {
10009 TextInputManagerTypeObserver type_observer(web_contents(),
10010 ui::TEXT_INPUT_TYPE_TEXT);
10011 TextInputManagerValueObserver value_observer(web_contents(), "foo");
10012 // 2) Press tab key to focus the <input>, and verify the type & value.
10013 SimulateKeyPress(web_contents(), ui::DomKey::TAB, ui::DomCode::TAB,
10014 ui::VKEY_TAB, false, false, false, false);
10015 type_observer.Wait();
10016 value_observer.Wait();
10017
10018 EXPECT_EQ(rfh_1, web_contents()->GetFocusedFrame());
10019 EXPECT_EQ(EvalJs(rfh_1, "focusCount").ExtractInt(), 1);
10020 EXPECT_EQ(EvalJs(rfh_1, "blurCount").ExtractInt(), 0);
10021 }
10022
10023 {
10024 TextInputManagerTester tester(web_contents());
10025 TextInputManagerValueObserver value_observer(web_contents(), "A");
10026 // 3) Press the "A" key to change the text input value. This should notify
10027 // the browser that the text input value has changed.
10028 SimulateKeyPress(web_contents(), ui::DomKey::FromCharacter('A'),
10029 ui::DomCode::US_A, ui::VKEY_A, false, false, false, false);
10030 value_observer.Wait();
10031
10032 EXPECT_EQ(rfh_1, web_contents()->GetFocusedFrame());
10033 EXPECT_EQ(EvalJs(rfh_1, "focusCount").ExtractInt(), 1);
10034 EXPECT_EQ(EvalJs(rfh_1, "blurCount").ExtractInt(), 0);
10035 }
10036
10037 {
10038 TextInputManagerTypeObserver type_observer(web_contents(),
10039 ui::TEXT_INPUT_TYPE_NONE);
10040 // 4) Navigating to |url_2| should reset type to TEXT_INPUT_TYPE_NONE.
10041 EXPECT_TRUE(NavigateToURL(shell(), url_2));
10042 type_observer.Wait();
10043 // |rfh_1| should get into the back-forward cache.
10044 EXPECT_TRUE(rfh_1->IsInBackForwardCache());
10045 EXPECT_EQ(current_frame_host(), web_contents()->GetFocusedFrame());
10046 EXPECT_NE(rfh_1, web_contents()->GetFocusedFrame());
10047 }
10048
10049 {
10050 // 5) Navigating back to |url_1|, we shouldn't restore the focus to the
10051 // text input, but |rfh_1| will be focused again as we will restore focus
10052 // to main frame after navigation.
10053 web_contents()->GetController().GoBack();
10054 EXPECT_TRUE(WaitForLoadStop(web_contents()));
10055
10056 EXPECT_EQ(rfh_1, web_contents()->GetFocusedFrame());
10057 EXPECT_EQ(EvalJs(rfh_1, "focusCount").ExtractInt(), 1);
10058 EXPECT_EQ(EvalJs(rfh_1, "blurCount").ExtractInt(), 1);
10059 }
10060
10061 {
10062 TextInputManagerTypeObserver type_observer(web_contents(),
10063 ui::TEXT_INPUT_TYPE_TEXT);
10064 TextInputManagerValueObserver value_observer(web_contents(), "A");
10065 // 6) Press tab key to focus the <input> again. Note that we need to press
10066 // the tab key twice here, because the last "tab focus" point was the
10067 // <input> element. The first tab key press would focus on the UI/url bar,
10068 // then the second tab key would go back to the <input>.
10069 SimulateKeyPress(web_contents(), ui::DomKey::TAB, ui::DomCode::TAB,
10070 ui::VKEY_TAB, false, false, false, false);
10071 SimulateKeyPress(web_contents(), ui::DomKey::TAB, ui::DomCode::TAB,
10072 ui::VKEY_TAB, false, false, false, false);
10073 type_observer.Wait();
10074 value_observer.Wait();
10075
10076 EXPECT_EQ(rfh_1, web_contents()->GetFocusedFrame());
10077 EXPECT_EQ(EvalJs(rfh_1, "focusCount").ExtractInt(), 2);
10078 EXPECT_EQ(EvalJs(rfh_1, "blurCount").ExtractInt(), 1);
10079 }
10080}
10081
10082IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
10083 SubframeTextInputStateUpdated) {
10084 ASSERT_TRUE(embedded_test_server()->Start());
10085 GURL url_1(embedded_test_server()->GetURL(
10086 "a.com", "/cross_site_iframe_factory.html?a(b(a))"));
10087 GURL url_2(embedded_test_server()->GetURL("b.com", "/title2.html"));
10088
10089 // 1) Navigate to |url_1| and add a text input with "foo" as the value in the
10090 // a.com subframe.
10091 EXPECT_TRUE(NavigateToURL(shell(), url_1));
10092 RenderFrameHostImpl* rfh_a = current_frame_host();
10093 RenderFrameHostImpl* rfh_b = rfh_a->child_at(0)->current_frame_host();
10094 RenderFrameHostImpl* rfh_subframe_a =
10095 rfh_b->child_at(0)->current_frame_host();
10096 EXPECT_TRUE(ExecJs(rfh_subframe_a,
10097 "var input = document.createElement('input');"
10098 "input.setAttribute('type', 'text');"
10099 "input.setAttribute('value', 'foo');"
10100 "document.body.appendChild(input);"
10101 "var focusCount = 0;"
10102 "var blurCount = 0;"
10103 "input.onfocus = () => { focusCount++;};"
10104 "input.onblur = () => { blurCount++; };"));
10105
10106 {
10107 TextInputManagerTypeObserver type_observer(web_contents(),
10108 ui::TEXT_INPUT_TYPE_TEXT);
10109 TextInputManagerValueObserver value_observer(web_contents(), "foo");
10110 // 2) Press tab key to focus the <input>, and verify the type & value.
10111 SimulateKeyPress(web_contents(), ui::DomKey::TAB, ui::DomCode::TAB,
10112 ui::VKEY_TAB, false, false, false, false);
10113 type_observer.Wait();
10114 value_observer.Wait();
10115
10116 EXPECT_EQ(rfh_subframe_a, web_contents()->GetFocusedFrame());
10117 EXPECT_EQ(EvalJs(rfh_subframe_a, "focusCount").ExtractInt(), 1);
10118 EXPECT_EQ(EvalJs(rfh_subframe_a, "blurCount").ExtractInt(), 0);
10119 }
10120
10121 {
10122 TextInputManagerTester tester(web_contents());
10123 TextInputManagerValueObserver value_observer(web_contents(), "A");
10124 // 3) Press the "A" key to change the text input value. This should notify
10125 // the browser that the text input value has changed.
10126 SimulateKeyPress(web_contents(), ui::DomKey::FromCharacter('A'),
10127 ui::DomCode::US_A, ui::VKEY_A, false, false, false, false);
10128 value_observer.Wait();
10129
10130 EXPECT_EQ(rfh_subframe_a, web_contents()->GetFocusedFrame());
10131 EXPECT_EQ(EvalJs(rfh_subframe_a, "focusCount").ExtractInt(), 1);
10132 EXPECT_EQ(EvalJs(rfh_subframe_a, "blurCount").ExtractInt(), 0);
10133 }
10134
10135 {
10136 TextInputManagerTypeObserver type_observer(web_contents(),
10137 ui::TEXT_INPUT_TYPE_NONE);
10138 // 4) Navigating to |url_2| should reset type to TEXT_INPUT_TYPE_NONE and
10139 // changed focus to the new page's main frame.
10140 EXPECT_TRUE(NavigateToURL(shell(), url_2));
10141 type_observer.Wait();
10142
10143 // |rfh_a| and its subframes should get into the back-forward cache.
10144 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
10145 EXPECT_TRUE(rfh_b->IsInBackForwardCache());
10146 EXPECT_TRUE(rfh_subframe_a->IsInBackForwardCache());
10147 EXPECT_EQ(current_frame_host(), web_contents()->GetFocusedFrame());
10148 }
10149
10150 {
10151 // 5) Navigating back to |url_1|, we shouldn't restore the focus to the
10152 // text input in the subframe (we will focus on the main frame |rfh_a|
10153 // instead).
10154 web_contents()->GetController().GoBack();
10155 EXPECT_TRUE(WaitForLoadStop(web_contents()));
10156
10157 EXPECT_EQ(rfh_a, web_contents()->GetFocusedFrame());
10158 EXPECT_EQ(EvalJs(rfh_subframe_a, "focusCount").ExtractInt(), 1);
10159 EXPECT_EQ(EvalJs(rfh_subframe_a, "blurCount").ExtractInt(), 1);
10160 }
10161
10162 {
10163 TextInputManagerTypeObserver type_observer(web_contents(),
10164 ui::TEXT_INPUT_TYPE_TEXT);
10165 TextInputManagerValueObserver value_observer(web_contents(), "A");
10166 // 6) Press tab key to focus the <input> again.
10167 SimulateKeyPress(web_contents(), ui::DomKey::TAB, ui::DomCode::TAB,
10168 ui::VKEY_TAB, false, false, false, false);
10169 type_observer.Wait();
10170 value_observer.Wait();
10171
10172 EXPECT_EQ(rfh_subframe_a, web_contents()->GetFocusedFrame());
10173 EXPECT_EQ(EvalJs(rfh_subframe_a, "focusCount").ExtractInt(), 2);
10174 EXPECT_EQ(EvalJs(rfh_subframe_a, "blurCount").ExtractInt(), 1);
10175 }
10176}
10177
Rakina Zata Amnia96a4162020-08-29 11:19:1810178// We should try to reuse process on same-site renderer-initiated navigations.
10179IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
10180 RendererInitiatedSameSiteNavigationReusesProcess) {
10181 ASSERT_TRUE(embedded_test_server()->Start());
10182 GURL url_1(embedded_test_server()->GetURL("/title1.html"));
10183 GURL url_2(embedded_test_server()->GetURL("/title2.html"));
10184
10185 // Navigate to title1.html.
10186 EXPECT_TRUE(NavigateToURL(shell(), url_1));
10187 scoped_refptr<SiteInstanceImpl> site_instance_1 =
10188 web_contents()->GetMainFrame()->GetSiteInstance();
10189 // Navigate to title2.html. The navigation is document/renderer initiated.
10190 EXPECT_TRUE(NavigateToURLFromRenderer(shell(), url_2));
10191 scoped_refptr<SiteInstanceImpl> site_instance_2 =
10192 web_contents()->GetMainFrame()->GetSiteInstance();
10193
10194 // Check that title1.html and title2.html are in different BrowsingInstances
10195 // but have the same renderer process.
10196 EXPECT_FALSE(site_instance_1->IsRelatedSiteInstance(site_instance_2.get()));
10197 EXPECT_EQ(site_instance_1->GetProcess(), site_instance_2->GetProcess());
10198}
10199
10200// We should try to reuse process on same-site browser-initiated navigations.
10201IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
10202 BrowserInitiatedSameSiteNavigationReusesProcess) {
10203 ASSERT_TRUE(embedded_test_server()->Start());
10204 GURL url_1(embedded_test_server()->GetURL("/title1.html"));
10205 GURL url_2(embedded_test_server()->GetURL("/title2.html"));
10206
10207 // 1) Navigate to title1.html.
10208 EXPECT_TRUE(NavigateToURL(shell(), url_1));
10209 scoped_refptr<SiteInstanceImpl> site_instance_1 =
10210 web_contents()->GetMainFrame()->GetSiteInstance();
10211 // 2) Navigate to title2.html. The navigation is browser initiated.
10212 EXPECT_TRUE(NavigateToURL(shell(), url_2));
10213 scoped_refptr<SiteInstanceImpl> site_instance_2 =
10214 web_contents()->GetMainFrame()->GetSiteInstance();
10215
10216 // Check that title1.html and title2.html are in different BrowsingInstances
10217 // but have the same renderer process.
10218 EXPECT_FALSE(site_instance_1->IsRelatedSiteInstance(site_instance_2.get()));
10219 EXPECT_EQ(site_instance_1->GetProcess(), site_instance_2->GetProcess());
10220
10221 // 3) Do a back navigation to title1.html.
10222 web_contents()->GetController().GoBack();
10223 EXPECT_TRUE(WaitForLoadStop(web_contents()));
10224 EXPECT_EQ(web_contents()->GetLastCommittedURL(), url_1);
10225 scoped_refptr<SiteInstanceImpl> site_instance_1_history_nav =
10226 web_contents()->GetMainFrame()->GetSiteInstance();
10227
10228 // We will reuse the SiteInstance and renderer process of |site_instance_1|.
10229 EXPECT_EQ(site_instance_1_history_nav, site_instance_1);
10230 EXPECT_EQ(site_instance_1_history_nav->GetProcess(),
10231 site_instance_1->GetProcess());
10232}
10233
10234// We should not try to reuse process on cross-site navigations.
10235IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
10236 CrossSiteNavigationDoesNotReuseProcess) {
10237 ASSERT_TRUE(embedded_test_server()->Start());
10238 GURL a1_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
10239 GURL b_url(embedded_test_server()->GetURL("b.com", "/title1.html"));
10240 GURL a2_url(embedded_test_server()->GetURL("a.com", "/title2.html"));
10241
10242 // Navigate to A1.
10243 EXPECT_TRUE(NavigateToURL(shell(), a1_url));
10244 scoped_refptr<SiteInstanceImpl> a1_site_instance =
10245 web_contents()->GetMainFrame()->GetSiteInstance();
10246 // Navigate to B. The navigation is browser initiated.
10247 EXPECT_TRUE(NavigateToURL(shell(), b_url));
10248 scoped_refptr<SiteInstanceImpl> b_site_instance =
10249 web_contents()->GetMainFrame()->GetSiteInstance();
10250
10251 // Check that A1 and B are in different BrowsingInstances and renderer
10252 // processes.
10253 EXPECT_FALSE(a1_site_instance->IsRelatedSiteInstance(b_site_instance.get()));
10254 EXPECT_NE(a1_site_instance->GetProcess(), b_site_instance->GetProcess());
10255
10256 // Navigate to A2. The navigation is renderer-initiated.
10257 EXPECT_TRUE(NavigateToURLFromRenderer(shell(), a2_url));
10258 scoped_refptr<SiteInstanceImpl> a2_site_instance =
10259 web_contents()->GetMainFrame()->GetSiteInstance();
10260
10261 // Check that B and A2 are in different BrowsingInstances and renderer
10262 // processes.
10263 EXPECT_FALSE(b_site_instance->IsRelatedSiteInstance(a2_site_instance.get()));
10264 EXPECT_NE(b_site_instance->GetProcess(), a2_site_instance->GetProcess());
10265}
10266
Rakina Zata Amnicf97f3f82020-09-02 15:42:1910267// Tests that the history value saved in the renderer is updated correctly when
10268// a page gets restored from the back-forward cache through browser-initiated
10269// navigation.
10270IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
10271 RendererHistory_BrowserInitiated) {
10272 ASSERT_TRUE(embedded_test_server()->Start());
10273 GURL url1(embedded_test_server()->GetURL(
10274 "a.com", "/cross_site_iframe_factory.html?a(b)"));
10275 GURL url2(embedded_test_server()->GetURL("a.com", "/title1.html"));
10276
10277 // 1) Go to |url1|, then |url2|. Both pages should have script to save the
10278 // history.length value when getting restored from the back-forward cache.
10279 EXPECT_TRUE(NavigateToURL(shell(), url1));
10280 FrameTreeNode* root = web_contents()->GetFrameTree()->root();
10281 FrameTreeNode* subframe = root->child_at(0);
10282
10283 std::string restore_time_length_saver_script =
10284 "var resumeLength = -1;"
10285 "var pageshowLength = -1;"
10286 "document.onresume = () => {"
10287 " resumeLength = history.length;"
10288 "};"
10289 "window.onpageshow = () => {"
10290 " pageshowLength = history.length;"
10291 "};";
10292 EXPECT_TRUE(ExecJs(root, restore_time_length_saver_script));
10293 EXPECT_TRUE(ExecJs(subframe, restore_time_length_saver_script));
10294 // We should have one history entry.
10295 EXPECT_EQ(EvalJs(root, "history.length").ExtractInt(), 1);
10296 EXPECT_EQ(EvalJs(subframe, "history.length").ExtractInt(), 1);
10297
10298 EXPECT_TRUE(NavigateToURL(shell(), url2));
10299 EXPECT_TRUE(ExecJs(root, restore_time_length_saver_script));
10300 // We should have two history entries.
10301 EXPECT_EQ(EvalJs(root, "history.length").ExtractInt(), 2);
10302
10303 // 2) Go back to |url1|, browser-initiated.
10304 web_contents()->GetController().GoBack();
10305 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
10306 EXPECT_EQ(web_contents()->GetLastCommittedURL(), url1);
10307
10308 // We should still have two history entries, and recorded the correct length
10309 // when the 'resume' and 'pageshow' events were dispatched.
10310 EXPECT_EQ(EvalJs(root, "history.length").ExtractInt(), 2);
10311 EXPECT_EQ(EvalJs(root, "resumeLength").ExtractInt(), 2);
10312 EXPECT_EQ(EvalJs(root, "pageshowLength").ExtractInt(), 2);
10313 EXPECT_EQ(EvalJs(subframe, "history.length").ExtractInt(), 2);
10314 EXPECT_EQ(EvalJs(subframe, "resumeLength").ExtractInt(), 2);
10315 EXPECT_EQ(EvalJs(subframe, "pageshowLength").ExtractInt(), 2);
10316
10317 // 3) Go forward to |url2|, browser-initiated.
10318 web_contents()->GetController().GoForward();
10319 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
10320 EXPECT_EQ(web_contents()->GetLastCommittedURL(), url2);
10321
10322 // We should still have two history entries, and recorded the correct length
10323 // when the 'resume' and 'pageshow' events were dispatched.
10324 EXPECT_EQ(EvalJs(root, "history.length").ExtractInt(), 2);
10325 EXPECT_EQ(EvalJs(root, "resumeLength").ExtractInt(), 2);
10326 EXPECT_EQ(EvalJs(root, "pageshowLength").ExtractInt(), 2);
10327}
10328
10329// Tests that the history value saved in the renderer is updated correctly when
10330// a page gets restored from the back-forward cache through renderer-initiated
10331// navigation.
10332IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
10333 RendererHistory_RendererInitiated) {
10334 ASSERT_TRUE(embedded_test_server()->Start());
10335
10336 GURL url1(embedded_test_server()->GetURL(
10337 "a.com", "/cross_site_iframe_factory.html?a(b)"));
10338 GURL url2(embedded_test_server()->GetURL("a.com", "/title1.html"));
10339
10340 // 1) Go to |url1|, then |url2|. Both pages should have script to save the
10341 // history.length value when getting restored from the back-forward cache.
10342 EXPECT_TRUE(NavigateToURL(shell(), url1));
10343 FrameTreeNode* root = web_contents()->GetFrameTree()->root();
10344 FrameTreeNode* subframe = root->child_at(0);
10345
10346 std::string restore_time_length_saver_script =
10347 "var resumeLength = -1;"
10348 "var pageshowLength = -1;"
10349 "document.onresume = () => {"
10350 " resumeLength = history.length;"
10351 "};"
10352 "window.onpageshow = () => {"
10353 " pageshowLength = history.length;"
10354 "};";
10355 EXPECT_TRUE(ExecJs(root, restore_time_length_saver_script));
10356 EXPECT_TRUE(ExecJs(subframe, restore_time_length_saver_script));
10357 // We should have one history entry.
10358 EXPECT_EQ(EvalJs(root, "history.length").ExtractInt(), 1);
10359 EXPECT_EQ(EvalJs(subframe, "history.length").ExtractInt(), 1);
10360
10361 EXPECT_TRUE(NavigateToURL(shell(), url2));
10362 EXPECT_TRUE(ExecJs(root, restore_time_length_saver_script));
10363 // We should have two history entries.
10364 EXPECT_EQ(EvalJs(root, "history.length").ExtractInt(), 2);
10365
10366 // 2) Go back to |url1|, renderer-initiated.
10367 EXPECT_TRUE(ExecJs(root, "history.back()"));
10368 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
10369 EXPECT_EQ(web_contents()->GetLastCommittedURL(), url1);
10370
10371 // We should still have two history entries, and recorded the correct length
10372 // when the 'resume' and 'pageshow' events were dispatched.
10373 EXPECT_EQ(EvalJs(root, "history.length").ExtractInt(), 2);
10374 EXPECT_EQ(EvalJs(root, "resumeLength").ExtractInt(), 2);
10375 EXPECT_EQ(EvalJs(root, "pageshowLength").ExtractInt(), 2);
10376 EXPECT_EQ(EvalJs(subframe, "history.length").ExtractInt(), 2);
10377 EXPECT_EQ(EvalJs(subframe, "resumeLength").ExtractInt(), 2);
10378 EXPECT_EQ(EvalJs(subframe, "pageshowLength").ExtractInt(), 2);
10379
10380 // 3) Go forward to |url2|, renderer-initiated.
10381 EXPECT_TRUE(ExecJs(root, "history.forward()"));
10382 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
10383
10384 EXPECT_EQ(web_contents()->GetLastCommittedURL(), url2);
10385
10386 // We should still have two history entries, and recorded the correct length
10387 // when the 'resume' and 'pageshow' events were dispatched.
10388 EXPECT_EQ(EvalJs(root, "history.length").ExtractInt(), 2);
10389 EXPECT_EQ(EvalJs(root, "resumeLength").ExtractInt(), 2);
10390 EXPECT_EQ(EvalJs(root, "pageshowLength").ExtractInt(), 2);
10391}
10392
Sreeja Kamishetty7b9e64a2020-10-02 10:15:4510393// This observer keeps tracks whether a given RenderViewHost is deleted or not
10394// to avoid accessing it and causing use-after-free condition.
10395class RenderViewHostDeletedObserver : public WebContentsObserver {
10396 public:
10397 explicit RenderViewHostDeletedObserver(RenderViewHost* rvh)
10398 : WebContentsObserver(WebContents::FromRenderViewHost(rvh)),
10399 render_view_host_(rvh),
10400 deleted_(false) {}
10401
10402 void RenderViewDeleted(RenderViewHost* render_view_host) override {
10403 if (render_view_host_ == render_view_host)
10404 deleted_ = true;
10405 }
10406
10407 bool deleted() const { return deleted_; }
10408
10409 private:
10410 RenderViewHost* render_view_host_;
10411 bool deleted_;
10412};
10413
10414// Tests that RenderViewHost is deleted on eviction along with
10415// RenderProcessHost.
10416IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
10417 RenderViewHostDeletedOnEviction) {
10418 ASSERT_TRUE(embedded_test_server()->Start());
10419 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
10420 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
10421
10422 NavigationControllerImpl& controller = web_contents()->GetController();
10423 BackForwardCacheImpl& cache = controller.GetBackForwardCache();
10424
10425 // 1) Navigate to A.
10426 EXPECT_TRUE(NavigateToURL(shell(), url_a));
10427 RenderFrameHostImpl* rfh_a = current_frame_host();
10428 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
10429 RenderViewHostDeletedObserver delete_observer_rvh_a(
10430 rfh_a->GetRenderViewHost());
10431
10432 RenderProcessHost* process = rfh_a->GetProcess();
10433 RenderProcessHostWatcher destruction_observer(
10434 process, RenderProcessHostWatcher::WATCH_FOR_HOST_DESTRUCTION);
10435 cache.Flush();
10436
10437 // 2) Navigate to B. A should be stored in cache, count of entries should
10438 // be 1.
10439 EXPECT_TRUE(NavigateToURL(shell(), url_b));
10440 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
10441 EXPECT_EQ(1u, cache.GetEntries().size());
10442
10443 // 3) Initiate eviction of rfh_a from BackForwardCache. Entries should be 0.
10444 // RenderViewHost, RenderProcessHost and RenderFrameHost should all be
10445 // deleted.
Sreeja Kamishettydb8e2892021-03-10 09:30:5810446 EXPECT_TRUE(rfh_a->IsInactiveAndDisallowActivation());
Sreeja Kamishetty7b9e64a2020-10-02 10:15:4510447 destruction_observer.Wait();
10448 ASSERT_TRUE(delete_observer_rvh_a.deleted());
10449 delete_observer_rfh_a.WaitUntilDeleted();
10450 EXPECT_EQ(0u, cache.GetEntries().size());
10451}
10452
10453// Tests that cross-process sub-frame's RenderViewHost is deleted on root
10454// RenderFrameHost eviction from BackForwardCache along with its
10455// RenderProcessHost.
10456IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
10457 CrossProcessSubFrameRenderViewHostDeletedOnEviction) {
10458 ASSERT_TRUE(embedded_test_server()->Start());
10459 GURL url_a(embedded_test_server()->GetURL(
10460 "a.com", "/cross_site_iframe_factory.html?a(b)"));
10461 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
10462
10463 // 1) Navigate to A.
10464 EXPECT_TRUE(NavigateToURL(shell(), url_a));
10465 RenderFrameHostImpl* a1 = current_frame_host();
10466 RenderFrameHostImpl* b1 = a1->child_at(0)->current_frame_host();
10467 RenderFrameDeletedObserver delete_observer_rfh_b1(b1);
10468
10469 RenderViewHostDeletedObserver delete_observer_rvh_b1(b1->GetRenderViewHost());
10470
10471 RenderProcessHost* process = b1->GetProcess();
10472 RenderProcessHostWatcher destruction_observer(
10473 process, RenderProcessHostWatcher::WATCH_FOR_HOST_DESTRUCTION);
10474
10475 // 2) Navigate to URL B.
10476 EXPECT_TRUE(NavigateToURL(shell(), url_b));
10477 EXPECT_TRUE(a1->IsInBackForwardCache());
10478
10479 // 3) Initiate eviction of rfh a1 from BackForwardCache. RenderViewHost,
10480 // RenderProcessHost and RenderFrameHost of sub-frame b1 should all be deleted
10481 // on eviction.
Sreeja Kamishettydb8e2892021-03-10 09:30:5810482 EXPECT_TRUE(a1->IsInactiveAndDisallowActivation());
Sreeja Kamishetty7b9e64a2020-10-02 10:15:4510483 destruction_observer.Wait();
10484 ASSERT_TRUE(delete_observer_rvh_b1.deleted());
10485 delete_observer_rfh_b1.WaitUntilDeleted();
10486}
10487
10488// Tests that same-process sub-frame's RenderViewHost is deleted on root
10489// RenderFrameHost eviction from BackForwardCache along with its
10490// RenderProcessHost.
10491IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
10492 SameProcessSubFrameRenderViewHostDeletedOnEviction) {
10493 ASSERT_TRUE(embedded_test_server()->Start());
10494 GURL url_a(embedded_test_server()->GetURL(
10495 "a.com", "/cross_site_iframe_factory.html?a(a)"));
10496 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
10497
10498 // 1) Navigate to A.
10499 EXPECT_TRUE(NavigateToURL(shell(), url_a));
10500 RenderFrameHostImpl* a1 = current_frame_host();
10501 RenderFrameHostImpl* a2 = a1->child_at(0)->current_frame_host();
10502 RenderFrameDeletedObserver delete_observer_rfh_a2(a2);
10503
10504 RenderViewHostDeletedObserver delete_observer_rvh_a2(a2->GetRenderViewHost());
10505
10506 RenderProcessHost* process = a2->GetProcess();
10507 RenderProcessHostWatcher destruction_observer(
10508 process, RenderProcessHostWatcher::WATCH_FOR_HOST_DESTRUCTION);
10509
10510 // 2) Navigate to URL B.
10511 EXPECT_TRUE(NavigateToURL(shell(), url_b));
10512 EXPECT_TRUE(a1->IsInBackForwardCache());
10513
10514 // 3) Initiate eviction of rfh a1 from BackForwardCache. RenderViewHost,
10515 // RenderProcessHost and RenderFrameHost of sub-frame a2 should all be
10516 // deleted.
Sreeja Kamishettydb8e2892021-03-10 09:30:5810517 EXPECT_TRUE(a1->IsInactiveAndDisallowActivation());
Sreeja Kamishetty7b9e64a2020-10-02 10:15:4510518 destruction_observer.Wait();
10519 ASSERT_TRUE(delete_observer_rvh_a2.deleted());
10520 delete_observer_rfh_a2.WaitUntilDeleted();
10521}
10522
Alexander Timin45b716c2020-11-06 01:40:3110523IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
10524 MainDocumentCSPHeadersAreRestored) {
10525 ASSERT_TRUE(embedded_test_server()->Start());
10526
10527 GURL url_a(embedded_test_server()->GetURL(
10528 "a.com",
10529 "/set-header?"
10530 "Content-Security-Policy: frame-src 'none'"));
10531 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
10532
10533 // 1) Navigate to A, which should set CSP.
10534 EXPECT_TRUE(NavigateToURL(shell(), url_a));
10535 RenderFrameHostImpl* rfh_a = current_frame_host();
10536
10537 // Check that CSP was set.
10538 {
Antonio Sartori8f5b7ee2021-01-29 13:00:5410539 const std::vector<network::mojom::ContentSecurityPolicyPtr>& root_csp =
10540 current_frame_host()
Antonio Sartorif45b2fc2021-03-04 10:15:0710541 ->policy_container_host()
10542 ->policies()
10543 .content_security_policies;
Alexander Timin45b716c2020-11-06 01:40:3110544 EXPECT_EQ(1u, root_csp.size());
Antonio Sartori8f5b7ee2021-01-29 13:00:5410545 EXPECT_EQ("frame-src 'none'", root_csp[0]->header->header_value);
Alexander Timin45b716c2020-11-06 01:40:3110546 }
10547
10548 // 2) Navigate to B.
10549 EXPECT_TRUE(NavigateToURL(shell(), url_b));
10550
10551 // 3) Navigate back and expect that the CSP headers are present on the main
10552 // frame.
10553 web_contents()->GetController().GoBack();
10554 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
10555 EXPECT_EQ(rfh_a, current_frame_host());
Fergal Daly09833062021-02-09 07:10:0010556 ExpectRestored(FROM_HERE);
Alexander Timin45b716c2020-11-06 01:40:3110557
10558 // Check that CSP was restored.
10559 {
Antonio Sartori8f5b7ee2021-01-29 13:00:5410560 const std::vector<network::mojom::ContentSecurityPolicyPtr>& root_csp =
10561 current_frame_host()
Antonio Sartorif45b2fc2021-03-04 10:15:0710562 ->policy_container_host()
10563 ->policies()
10564 .content_security_policies;
Alexander Timin45b716c2020-11-06 01:40:3110565 EXPECT_EQ(1u, root_csp.size());
Antonio Sartori8f5b7ee2021-01-29 13:00:5410566 EXPECT_EQ("frame-src 'none'", root_csp[0]->header->header_value);
Alexander Timin45b716c2020-11-06 01:40:3110567 }
10568}
10569
arthursonzogni76098e52020-11-25 14:18:4510570// Check that sandboxed documents are cached and won't lose their sandbox flags
10571// after restoration.
10572IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, CspSandbox) {
Alexander Timin45b716c2020-11-06 01:40:3110573 ASSERT_TRUE(embedded_test_server()->Start());
10574
10575 GURL url_a(
10576 embedded_test_server()->GetURL("a.com",
10577 "/set-header?"
10578 "Content-Security-Policy: sandbox"));
10579 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
10580
10581 // 1) Navigate to A, which should set CSP.
10582 EXPECT_TRUE(NavigateToURL(shell(), url_a));
arthursonzogni76098e52020-11-25 14:18:4510583 RenderFrameHostImpl* rfh_a = current_frame_host();
10584 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
Alexander Timin45b716c2020-11-06 01:40:3110585 {
Antonio Sartori8f5b7ee2021-01-29 13:00:5410586 const std::vector<network::mojom::ContentSecurityPolicyPtr>& root_csp =
10587 current_frame_host()
Antonio Sartorif45b2fc2021-03-04 10:15:0710588 ->policy_container_host()
10589 ->policies()
10590 .content_security_policies;
arthursonzogni76098e52020-11-25 14:18:4510591 ASSERT_EQ(1u, root_csp.size());
Antonio Sartori8f5b7ee2021-01-29 13:00:5410592 ASSERT_EQ("sandbox", root_csp[0]->header->header_value);
arthursonzogni76098e52020-11-25 14:18:4510593 ASSERT_EQ(network::mojom::WebSandboxFlags::kAll,
10594 current_frame_host()->active_sandbox_flags());
10595 };
Alexander Timin45b716c2020-11-06 01:40:3110596
arthursonzogni76098e52020-11-25 14:18:4510597 // 2) Navigate to B. Expect the previous RenderFrameHost to enter the bfcache.
Alexander Timin45b716c2020-11-06 01:40:3110598 EXPECT_TRUE(NavigateToURL(shell(), url_b));
arthursonzogni76098e52020-11-25 14:18:4510599 EXPECT_FALSE(delete_observer_rfh_a.deleted());
10600 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
10601 {
Antonio Sartori8f5b7ee2021-01-29 13:00:5410602 const std::vector<network::mojom::ContentSecurityPolicyPtr>& root_csp =
10603 current_frame_host()
Antonio Sartorif45b2fc2021-03-04 10:15:0710604 ->policy_container_host()
10605 ->policies()
10606 .content_security_policies;
arthursonzogni76098e52020-11-25 14:18:4510607 ASSERT_EQ(0u, root_csp.size());
10608 ASSERT_EQ(network::mojom::WebSandboxFlags::kNone,
10609 current_frame_host()->active_sandbox_flags());
10610 };
Alexander Timin45b716c2020-11-06 01:40:3110611
arthursonzogni76098e52020-11-25 14:18:4510612 // 3) Navigate back and expect the page to be restored, with the correct
10613 // CSP and sandbox flags.
Alexander Timin45b716c2020-11-06 01:40:3110614 web_contents()->GetController().GoBack();
10615 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
arthursonzogni76098e52020-11-25 14:18:4510616 EXPECT_FALSE(delete_observer_rfh_a.deleted());
10617 EXPECT_EQ(current_frame_host(), rfh_a);
10618 {
Antonio Sartori8f5b7ee2021-01-29 13:00:5410619 const std::vector<network::mojom::ContentSecurityPolicyPtr>& root_csp =
10620 current_frame_host()
Antonio Sartorif45b2fc2021-03-04 10:15:0710621 ->policy_container_host()
10622 ->policies()
10623 .content_security_policies;
arthursonzogni76098e52020-11-25 14:18:4510624 ASSERT_EQ(1u, root_csp.size());
Antonio Sartori8f5b7ee2021-01-29 13:00:5410625 ASSERT_EQ("sandbox", root_csp[0]->header->header_value);
arthursonzogni76098e52020-11-25 14:18:4510626 ASSERT_EQ(network::mojom::WebSandboxFlags::kAll,
10627 current_frame_host()->active_sandbox_flags());
10628 };
Alexander Timin45b716c2020-11-06 01:40:3110629}
10630
Carlos Caballero8f4c0c662020-12-01 19:26:0710631IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
10632 NavigationCancelledAfterJsEvictionWasDisabled) {
10633 ASSERT_TRUE(embedded_test_server()->Start());
10634 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
10635 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
10636
10637 // 1) Navigate to A.
10638 EXPECT_TRUE(NavigateToURL(shell(), url_a));
10639 RenderFrameHostImpl* rfh_a = current_frame_host();
10640 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
10641
10642 PageLifecycleStateManagerTestDelegate delegate(
10643 rfh_a->render_view_host()->GetPageLifecycleStateManager());
10644
10645 // 2) Navigate to B.
10646 EXPECT_TRUE(NavigateToURL(shell(), url_b));
10647
10648 RenderFrameHostImpl* rfh_b = current_frame_host();
10649
David Bokan1bdb3701f2021-04-30 22:02:3510650 delegate.OnDisableJsEvictionSent(base::BindLambdaForTesting([&]() {
10651 // Posted because Stop() will destroy the NavigationRequest but
10652 // DisableJsEviction will be called from inside the navigation which may
10653 // not be a safe place to destruct a NavigationRequest.
10654 base::ThreadTaskRunnerHandle::Get()->PostTask(
10655 FROM_HERE, base::BindOnce(&WebContentsImpl::Stop,
10656 base::Unretained(web_contents())));
10657 }));
Carlos Caballero8f4c0c662020-12-01 19:26:0710658
10659 // 3) Do not go back to A (navigation cancelled).
10660 web_contents()->GetController().GoBack();
10661 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
10662
10663 EXPECT_EQ(rfh_b, current_frame_host());
10664
10665 delete_observer_rfh_a.WaitUntilDeleted();
10666
10667 // 4) Go back to A.
10668 web_contents()->GetController().GoBack();
10669 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
10670
10671 ExpectNotRestored({BackForwardCacheMetrics::NotRestoredReason::
10672 kNavigationCancelledWhileRestoring},
Fergal Daly6755cbf2021-02-12 03:06:5810673 {}, {}, {}, FROM_HERE);
Carlos Caballero8f4c0c662020-12-01 19:26:0710674}
10675
Hajime Hoshic7606502021-04-14 02:42:1610676// Check that about:blank is not cached.
10677IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, AboutBlankWillNotBeCached) {
10678 ASSERT_TRUE(embedded_test_server()->Start());
10679
10680 // 1) Navigate to about:blank.
10681 GURL blank_url(url::kAboutBlankURL);
10682 EXPECT_TRUE(NavigateToURL(shell(), blank_url));
10683
10684 // 2) Navigate to a.com.
10685 GURL url_a(embedded_test_server()->GetURL("a.com", "/empty.html"));
10686 EXPECT_TRUE(NavigateToURL(shell(), url_a));
10687
10688 // 3) Navigate back to about:blank.
10689 web_contents()->GetController().GoBack();
10690 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
10691
10692 // This about:blank document does not have a SiteInstance and then loading a
10693 // page on it doesn't swap the browsing instance.
10694 ExpectNotRestored(
10695 {
10696 BackForwardCacheMetrics::NotRestoredReason::
10697 kBrowsingInstanceNotSwapped,
10698 },
10699 {}, {ShouldSwapBrowsingInstance::kNo_DoesNotHaveSite}, {}, FROM_HERE);
10700}
10701
Rakina Zata Amni348fe2b2021-07-09 05:28:5210702// Check that an eligible page is cached when navigating to about:blank.
Hajime Hoshic7606502021-04-14 02:42:1610703IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
Rakina Zata Amni348fe2b2021-07-09 05:28:5210704 NavigatingToAboutBlankDoesNotPreventCaching) {
Hajime Hoshic7606502021-04-14 02:42:1610705 ASSERT_TRUE(embedded_test_server()->Start());
10706
10707 // 1) Navigate to a.com,
10708 GURL url_a(embedded_test_server()->GetURL("a.com", "/empty.html"));
10709 EXPECT_TRUE(NavigateToURL(shell(), url_a));
10710
10711 // 2) Navigate to about:blank.
10712 GURL blank_url(url::kAboutBlankURL);
10713 EXPECT_TRUE(NavigateToURL(shell(), blank_url));
10714
10715 // 3) Navigate back to a.com.
10716 web_contents()->GetController().GoBack();
10717 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
10718
Rakina Zata Amni348fe2b2021-07-09 05:28:5210719 ExpectRestored(FROM_HERE);
Hajime Hoshic7606502021-04-14 02:42:1610720}
10721
10722// Check that browsing instances are not swapped when a navigation redirects
10723// toward the last committed URL and the reasons are recorded correctly.
10724IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, RedirectToSelf) {
10725 ASSERT_TRUE(embedded_test_server()->Start());
10726 NavigationControllerImpl& controller = web_contents()->GetController();
10727
10728 // 1) Navigate to a.com/empty.html.
10729 GURL url_a(embedded_test_server()->GetURL("a.com", "/empty.html"));
10730 EXPECT_TRUE(NavigateToURL(shell(), url_a));
10731 RenderFrameHostImpl* rfh_a = current_frame_host();
10732 EXPECT_EQ(1, controller.GetEntryCount());
10733 EXPECT_EQ(url_a, controller.GetLastCommittedEntry()->GetURL());
10734
10735 // 2) Navigate to the same page by redirection.
10736 GURL url_a2(embedded_test_server()->GetURL(
10737 "a.com", "/server-redirect-301?" + url_a.spec()));
10738 EXPECT_TRUE(NavigateToURL(shell(), url_a2, url_a));
10739 RenderFrameHostImpl* rfh_b = current_frame_host();
10740 EXPECT_EQ(2, controller.GetEntryCount());
10741
10742 EXPECT_FALSE(rfh_a->IsInBackForwardCache());
10743 EXPECT_TRUE(rfh_a->GetSiteInstance()->IsRelatedSiteInstance(
10744 rfh_b->GetSiteInstance()));
10745 EXPECT_EQ(url_a, controller.GetLastCommittedEntry()->GetURL());
10746
10747 // 3) Navigate back to the previous page.
10748 web_contents()->GetController().GoBack();
10749 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
10750 EXPECT_EQ(2, controller.GetEntryCount());
10751 EXPECT_EQ(url_a, controller.GetLastCommittedEntry()->GetURL());
10752
10753 // TODO(crbug.com/1198030): Investigate whether these navigation results are
10754 // expected.
10755
10756 ExpectNotRestored(
10757 {
10758 BackForwardCacheMetrics::NotRestoredReason::
10759 kBrowsingInstanceNotSwapped,
10760 },
10761 {}, {ShouldSwapBrowsingInstance::kNo_SameUrlNavigation}, {}, FROM_HERE);
10762}
10763
10764// Check that the response 204 No Content doesn't affect back-forward cache.
10765IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, NoContent) {
10766 ASSERT_TRUE(embedded_test_server()->Start());
10767 NavigationControllerImpl& controller = web_contents()->GetController();
10768
10769 // 1) Navigate to a.com.
10770 GURL url_a(embedded_test_server()->GetURL("a.com", "/empty.html"));
10771 EXPECT_TRUE(NavigateToURL(shell(), url_a));
10772 EXPECT_EQ(1, controller.GetEntryCount());
10773 EXPECT_EQ(url_a, controller.GetLastCommittedEntry()->GetURL());
10774
10775 // 2) Navigate to b.com
10776 GURL url_b(embedded_test_server()->GetURL("b.com", "/empty.html"));
10777 EXPECT_TRUE(NavigateToURL(shell(), url_b));
10778 EXPECT_EQ(2, controller.GetEntryCount());
10779 EXPECT_EQ(url_b, controller.GetLastCommittedEntry()->GetURL());
10780
10781 // 3) Navigate to c.com with 204 No Content, then the URL will still be b.com.
10782 GURL url_c(embedded_test_server()->GetURL("c.com", "/echo?status=204"));
10783 EXPECT_TRUE(NavigateToURL(shell(), url_c, url_b));
10784 EXPECT_EQ(2, controller.GetEntryCount());
10785 EXPECT_EQ(url_b, controller.GetLastCommittedEntry()->GetURL());
10786
10787 // 4) Navigate back to a.com.
10788 web_contents()->GetController().GoBack();
10789 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
10790 EXPECT_EQ(2, controller.GetEntryCount());
10791 EXPECT_EQ(url_a, controller.GetLastCommittedEntry()->GetURL());
10792
10793 ExpectRestored(FROM_HERE);
10794}
10795
10796// Check that reloading doesn't affect the back-forward cache usage.
10797IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, ReloadDoesntAffectCache) {
10798 ASSERT_TRUE(embedded_test_server()->Start());
10799 NavigationControllerImpl& controller = web_contents()->GetController();
10800
10801 // 1) Navigate to a.com.
10802 GURL url_a(embedded_test_server()->GetURL("a.com", "/empty.html"));
10803 EXPECT_TRUE(NavigateToURL(shell(), url_a));
10804 EXPECT_EQ(1, controller.GetEntryCount());
10805 EXPECT_EQ(url_a, controller.GetLastCommittedEntry()->GetURL());
10806
10807 // 2) Navigate to b.com.
10808 GURL url_b(embedded_test_server()->GetURL("b.com", "/empty.html"));
10809 EXPECT_TRUE(NavigateToURL(shell(), url_b));
10810 EXPECT_EQ(2, controller.GetEntryCount());
10811 EXPECT_EQ(url_b, controller.GetLastCommittedEntry()->GetURL());
10812
10813 // 3) Go back to a.com and reload.
10814 web_contents()->GetController().GoBack();
10815 EXPECT_TRUE(WaitForLoadStop(web_contents()));
10816 EXPECT_EQ(2, controller.GetEntryCount());
10817 EXPECT_EQ(url_a, controller.GetLastCommittedEntry()->GetURL());
10818
10819 ExpectRestored(FROM_HERE);
10820
10821 // 4) Reload the tab.
10822 web_contents()->GetController().Reload(content::ReloadType::NORMAL, false);
10823 EXPECT_TRUE(WaitForLoadStop(web_contents()));
10824 EXPECT_EQ(2, controller.GetEntryCount());
10825 EXPECT_EQ(url_a, controller.GetLastCommittedEntry()->GetURL());
10826
10827 // By reloading the tab, ShouldSwapBrowsingInstance::
10828 // kNo_AlreadyHasMatchingBrowsingInstance is set once. This should be reset
10829 // when the navigation 4)'s commit finishes and should not prevent putting the
10830 // page into the back-forward cache.
10831 //
Hajime Hoshi07618442021-04-21 08:38:0010832 // Note that SetBrowsingInstanceSwapResult might not be called for every
Hajime Hoshic7606502021-04-14 02:42:1610833 // navigation because we might not get to this point for some navigations,
10834 // e.g. if the navigation uses a pre-existing RenderFrameHost and SiteInstance
10835 // for navigation.
10836 //
Hajime Hoshi07618442021-04-21 08:38:0010837 // TODO(crbug.com/1176061): Tie BrowsingInstanceSwapResult to
10838 // NavigationRequest instead and move the SetBrowsingInstanceSwapResult call
10839 // for navigations to happen at commit time instead.
Hajime Hoshic7606502021-04-14 02:42:1610840
10841 // 5) Go forward to b.com and reload.
10842 web_contents()->GetController().GoForward();
10843 EXPECT_TRUE(WaitForLoadStop(web_contents()));
10844 EXPECT_EQ(2, controller.GetEntryCount());
10845 EXPECT_EQ(url_b, controller.GetLastCommittedEntry()->GetURL());
10846
10847 // The page loaded at B) is correctly cached and restored. Reloading doesn't
10848 // affect the cache usage.
10849 ExpectRestored(FROM_HERE);
10850
10851 // 6) Go back to a.com.
10852 web_contents()->GetController().GoBack();
10853 EXPECT_TRUE(WaitForLoadStop(web_contents()));
10854 EXPECT_EQ(2, controller.GetEntryCount());
10855 EXPECT_EQ(url_a, controller.GetLastCommittedEntry()->GetURL());
10856
10857 // The page loaded at 3) is correctly cached and restored. Reloading doesn't
10858 // affect the cache usage.
10859 ExpectRestored(FROM_HERE);
10860}
10861
Hajime Hoshi9743cf12021-05-13 15:54:1210862IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
10863 SubframeNavigationDoesNotRecordMetrics) {
10864 ASSERT_TRUE(embedded_test_server()->Start());
10865 GURL url_a(embedded_test_server()->GetURL(
10866 "a.com", "/cross_site_iframe_factory.html?a(b)"));
10867 GURL url_c(embedded_test_server()->GetURL("c.com", "/title1.html"));
10868
10869 // 1) Navigate to A(B).
10870 EXPECT_TRUE(NavigateToURL(shell(), url_a));
10871 RenderFrameHostImpl* rfh_a = current_frame_host();
10872
10873 // 2) Navigate from B to C.
10874 EXPECT_TRUE(NavigateFrameToURL(rfh_a->child_at(0), url_c));
10875 EXPECT_EQ(url_c,
10876 rfh_a->child_at(0)->current_frame_host()->GetLastCommittedURL());
10877 EXPECT_FALSE(rfh_a->IsInBackForwardCache());
10878
10879 // 4) Go back from C to B.
10880 web_contents()->GetController().GoBack();
10881 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
10882 EXPECT_TRUE(
10883 rfh_a->child_at(0)->current_frame_host()->GetLastCommittedURL().DomainIs(
10884 "b.com"));
10885 EXPECT_FALSE(rfh_a->IsInBackForwardCache());
10886
10887 // The reason why the frame is not cached in a subframe navigation is not
10888 // recorded.
10889 ExpectOutcomeDidNotChange(FROM_HERE);
10890}
10891
WangHui0baeaa82020-12-15 03:25:3210892IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
10893 EnsureIsolationInfoForSubresourcesNotEmpty) {
10894 ASSERT_TRUE(embedded_test_server()->Start());
10895 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
10896 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
10897
10898 NavigationControllerImpl& controller = web_contents()->GetController();
10899 BackForwardCacheImpl& cache = controller.GetBackForwardCache();
10900
10901 // 1) Navigate to A.
10902 EXPECT_TRUE(NavigateToURL(shell(), url_a));
10903 RenderFrameHostImpl* rfh_a = current_frame_host();
10904
10905 cache.Flush();
10906
10907 // 2) Navigate to B. A should be stored in cache, count of entries should
10908 // be 1.
10909 EXPECT_TRUE(NavigateToURL(shell(), url_b));
10910 RenderFrameHostImpl* rfh_b = current_frame_host();
10911 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
10912 EXPECT_EQ(1u, cache.GetEntries().size());
10913
10914 // 3) GoBack to A. RenderFrameHost of A should be restored and B should be
10915 // stored in cache, count of entries should be 1. IsolationInfoForSubresources
10916 // of rfh_a should not be empty.
10917 controller.GoBack();
10918 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
10919 EXPECT_EQ(rfh_a, current_frame_host());
10920 EXPECT_TRUE(rfh_b->IsInBackForwardCache());
10921 EXPECT_EQ(1u, cache.GetEntries().size());
10922 EXPECT_FALSE(rfh_a->GetIsolationInfoForSubresources().IsEmpty());
10923
10924 // 4) GoForward to B. RenderFrameHost of B should be restored and A should be
10925 // stored in cache, count of entries should be 1. IsolationInfoForSubresources
10926 // of rfh_b should not be empty.
10927 controller.GoForward();
10928 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
10929 EXPECT_EQ(rfh_b, current_frame_host());
10930 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
10931 EXPECT_EQ(1u, cache.GetEntries().size());
10932 EXPECT_FALSE(rfh_b->GetIsolationInfoForSubresources().IsEmpty());
10933}
10934
Hajime Hoshiafd7a0c2021-08-24 10:44:1410935IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, CacheWithMediaSession) {
Hajime Hoshi44e053522021-04-02 10:51:5010936 ASSERT_TRUE(embedded_test_server()->Start());
10937
10938 // 1) Navigate to a page using MediaSession.
10939 EXPECT_TRUE(NavigateToURL(
10940 shell(), embedded_test_server()->GetURL("a.com", "/title1.html")));
Hajime Hoshiafd7a0c2021-08-24 10:44:1410941 RenderFrameHostImplWrapper rfh_a(current_frame_host());
10942 EXPECT_TRUE(ExecJs(rfh_a.get(), R"(
Hajime Hoshi44e053522021-04-02 10:51:5010943 navigator.mediaSession.metadata = new MediaMetadata({
10944 artwork: [
10945 {src: "test_image.jpg", sizes: "1x1", type: "image/jpeg"},
10946 {src: "test_image.jpg", sizes: "10x10", type: "image/jpeg"}
10947 ]
10948 });
10949 )"));
10950
10951 // 2) Navigate away.
10952 EXPECT_TRUE(NavigateToURL(
10953 shell(), embedded_test_server()->GetURL("b.com", "/title1.html")));
Hajime Hoshiafd7a0c2021-08-24 10:44:1410954 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
Hajime Hoshi44e053522021-04-02 10:51:5010955
10956 // 3) Go back.
10957 web_contents()->GetController().GoBack();
10958 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
Hajime Hoshiafd7a0c2021-08-24 10:44:1410959 EXPECT_EQ(rfh_a.get(), current_frame_host());
10960 ExpectRestored(FROM_HERE);
10961 // Check the media session state is reserved.
10962 EXPECT_EQ("10x10", EvalJs(rfh_a.get(), R"(
10963 navigator.mediaSession.metadata.artwork[1].sizes;
10964 )"));
Hajime Hoshi44e053522021-04-02 10:51:5010965}
10966
Hajime Hoshi7a964b42020-12-15 08:13:5110967class BackForwardCacheBrowserTestWithSupportedFeatures
10968 : public BackForwardCacheBrowserTest {
10969 protected:
10970 void SetUpCommandLine(base::CommandLine* command_line) override {
10971 EnableFeatureAndSetParams(features::kBackForwardCache, "supported_features",
10972 "BroadcastChannel,KeyboardLock");
10973 BackForwardCacheBrowserTest::SetUpCommandLine(command_line);
10974 }
10975};
10976
10977IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTestWithSupportedFeatures,
10978 CacheWithSpecifiedFeatures) {
10979 ASSERT_TRUE(CreateHttpsServer()->Start());
10980
10981 GURL url_a(https_server()->GetURL("a.com", "/title1.html"));
10982 GURL url_b(https_server()->GetURL("b.com", "/title1.html"));
10983
10984 // 1) Navigate to the page A with BroadcastChannel.
10985 EXPECT_TRUE(NavigateToURL(shell(), url_a));
10986 RenderFrameHostImpl* rfh_a = current_frame_host();
10987 RenderFrameDeletedObserver deleted(rfh_a);
10988 EXPECT_TRUE(ExecJs(rfh_a, "window.foo = new BroadcastChannel('foo');"));
10989
10990 // 2) Navigate away.
10991 EXPECT_TRUE(NavigateToURL(shell(), url_b));
10992 EXPECT_FALSE(deleted.deleted());
10993 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
10994
10995 // 3) Go back to the page A
10996 web_contents()->GetController().GoBack();
10997 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
10998 EXPECT_EQ(rfh_a, current_frame_host());
Fergal Daly09833062021-02-09 07:10:0010999 ExpectRestored(FROM_HERE);
Hajime Hoshi7a964b42020-12-15 08:13:5111000
11001 // 4) Use KeyboardLock
11002 EXPECT_EQ("DONE", EvalJs(rfh_a, R"(
11003 new Promise(resolve => {
11004 navigator.keyboard.lock();
11005 resolve('DONE');
11006 });
11007 )"));
11008
11009 // 5) Navigate away again.
11010 EXPECT_TRUE(NavigateToURL(shell(), url_b));
11011 EXPECT_FALSE(deleted.deleted());
11012 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
11013
11014 // 6) Go back to the page A again.
11015 web_contents()->GetController().GoBack();
11016 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
11017 EXPECT_EQ(rfh_a, current_frame_host());
Fergal Daly09833062021-02-09 07:10:0011018 ExpectRestored(FROM_HERE);
Hajime Hoshi7a964b42020-12-15 08:13:5111019}
11020
11021class BackForwardCacheBrowserTestWithNoSupportedFeatures
11022 : public BackForwardCacheBrowserTest {
11023 protected:
11024 void SetUpCommandLine(base::CommandLine* command_line) override {
11025 // Specify empty supported features explicitly.
11026 EnableFeatureAndSetParams(features::kBackForwardCache, "supported_features",
11027 "");
11028 BackForwardCacheBrowserTest::SetUpCommandLine(command_line);
11029 }
11030};
11031
11032IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTestWithNoSupportedFeatures,
11033 DontCache) {
11034 ASSERT_TRUE(CreateHttpsServer()->Start());
11035
11036 GURL url_a(https_server()->GetURL("a.com", "/title1.html"));
11037 GURL url_b(https_server()->GetURL("b.com", "/title1.html"));
11038
11039 // 1) Navigate to the page A with BoradcastChannel.
11040 EXPECT_TRUE(NavigateToURL(shell(), url_a));
11041 RenderFrameHostImpl* rfh_a1 = current_frame_host();
11042 RenderFrameDeletedObserver deleted_a1(rfh_a1);
11043 EXPECT_TRUE(ExecJs(rfh_a1, "window.foo = new BroadcastChannel('foo');"));
11044
11045 // 2) Navigate away.
11046 EXPECT_TRUE(NavigateToURL(shell(), url_b));
11047 deleted_a1.WaitUntilDeleted();
11048
11049 // 3) Go back to the page A
11050 web_contents()->GetController().GoBack();
11051 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
11052 ExpectNotRestored(
11053 {BackForwardCacheMetrics::NotRestoredReason::kBlocklistedFeatures},
Fergal Daly6755cbf2021-02-12 03:06:5811054 {blink::scheduler::WebSchedulerTrackedFeature::kBroadcastChannel}, {}, {},
Hajime Hoshi7a964b42020-12-15 08:13:5111055 FROM_HERE);
11056
11057 RenderFrameHostImpl* rfh_a2 = current_frame_host();
11058 RenderFrameDeletedObserver deleted_a2(rfh_a2);
11059
11060 // 4) Use KeyboardLock
11061 EXPECT_EQ("DONE", EvalJs(rfh_a2, R"(
11062 new Promise(resolve => {
11063 navigator.keyboard.lock();
11064 resolve('DONE');
11065 });
11066 )"));
11067
11068 // 5) Navigate away again.
11069 EXPECT_TRUE(NavigateToURL(shell(), url_b));
11070 deleted_a2.WaitUntilDeleted();
11071
11072 // 6) Go back to the page A again.
11073 web_contents()->GetController().GoBack();
11074 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
11075 ExpectNotRestored(
11076 {BackForwardCacheMetrics::NotRestoredReason::kBlocklistedFeatures},
Fergal Daly6755cbf2021-02-12 03:06:5811077 {blink::scheduler::WebSchedulerTrackedFeature::kKeyboardLock}, {}, {},
Hajime Hoshi7a964b42020-12-15 08:13:5111078 FROM_HERE);
Hajime Hoshi7a964b42020-12-15 08:13:5111079}
11080
Rakina Zata Amnia6558682021-03-05 04:10:5711081// Regression test for crbug.com/1183313. Checks that CommitNavigationParam's
11082// |has_user_gesture| value reflects the gesture from the latest navigation
11083// after the commit finished.
11084IN_PROC_BROWSER_TEST_F(
11085 BackForwardCacheBrowserTest,
11086 SameDocumentNavAfterRestoringDocumentLoadedWithUserGesture) {
11087 ASSERT_TRUE(embedded_test_server()->Start());
11088
11089 GURL start_url(embedded_test_server()->GetURL("/title1.html"));
11090 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
11091 GURL url_a_foo(embedded_test_server()->GetURL("a.com", "/title1.html#foo"));
11092 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
11093 NavigationControllerImpl& controller = web_contents()->GetController();
11094 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
11095 ->GetFrameTree()
11096 ->root();
11097
11098 // Initial navigation (so that we can initiate a navigation from renderer).
11099 EXPECT_TRUE(NavigateToURL(shell(), start_url));
11100
11101 // 1) Navigate to A with user gesture.
11102 {
11103 FrameNavigateParamsCapturer params_capturer(root);
11104 EXPECT_TRUE(NavigateToURLFromRenderer(shell(), url_a));
11105 params_capturer.Wait();
11106 EXPECT_TRUE(params_capturer.has_user_gesture());
11107 }
11108 RenderFrameHostImpl* rfh_a = current_frame_host();
11109
11110 // 2) Navigate to B. A should be stored in the back-forward cache.
11111 EXPECT_TRUE(NavigateToURL(shell(), url_b));
11112 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
11113
11114 // 3) GoBack to A. RenderFrameHost of A should be restored from the
11115 // back-forward cache, and "has_user_gesture" is set to false correctly.
11116 // Note that since this is a back-forward cache restore we create the
11117 // DidCommitProvisionalLoadParams completely in the browser, so we got the
11118 // correct value from the latest navigation. However, we did not update the
11119 // renderer's navigation-related values, so the renderer's DocumentLoader
11120 // still thinks the last "gesture" value is "true", which will get corrected
11121 // on the next navigation.
11122 {
11123 FrameNavigateParamsCapturer params_capturer(root);
11124 controller.GoBack();
11125 params_capturer.Wait();
11126 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
11127 EXPECT_EQ(rfh_a, current_frame_host());
11128 // The navigation doesn't have user gesture.
11129 EXPECT_FALSE(params_capturer.has_user_gesture());
11130 }
11131
11132 // 4) Same-document navigation to A#foo without user gesture. At this point
11133 // we will update the renderer's DocumentLoader's latest gesture value to
11134 // "no user gesture", and we'll get the correct gesture value in
11135 // DidCommitProvisionalLoadParams.
11136 {
11137 FrameNavigateParamsCapturer params_capturer(root);
11138 EXPECT_TRUE(
11139 NavigateToURLFromRendererWithoutUserGesture(shell(), url_a_foo));
11140 params_capturer.Wait();
11141 // The navigation doesn't have user gesture.
11142 EXPECT_FALSE(params_capturer.has_user_gesture());
11143 }
11144}
11145
Rakina Zata Amni2c46e88b2021-04-02 05:22:3311146// Regression test for crbug.com/1183313, but for is_overriding_user_agent.
11147// Checks that we won't restore an entry from the BackForwardCache if the
11148// is_overriding_user_agent value used in the entry differs from the one used
11149// in the restoring navigation.
11150IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
11151 DoNotRestoreWhenIsOverridingUserAgentDiffers) {
11152 ASSERT_TRUE(embedded_test_server()->Start());
11153
11154 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
11155 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
11156 GURL url_c(embedded_test_server()->GetURL("c.com", "/title1.html"));
11157 NavigationControllerImpl& controller = web_contents()->GetController();
11158 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
11159 ->GetFrameTree()
11160 ->root();
11161
11162 const std::string user_agent_override = "foo";
11163
11164 // 1) Navigate to A without user agent override.
11165 {
11166 FrameNavigateParamsCapturer params_capturer(root);
11167 EXPECT_TRUE(NavigateToURL(shell(), url_a));
11168 params_capturer.Wait();
11169 EXPECT_FALSE(params_capturer.is_overriding_user_agent());
11170 EXPECT_NE(user_agent_override,
11171 EvalJs(shell()->web_contents(), "navigator.userAgent"));
11172 }
11173
11174 RenderFrameHostImpl* rfh_a = current_frame_host();
11175
11176 // Enable user agent override for future navigations.
11177 UserAgentInjector injector(shell()->web_contents(), user_agent_override);
11178
11179 // 2) Navigate to B with user agent override.
11180 {
11181 FrameNavigateParamsCapturer params_capturer(root);
11182 EXPECT_TRUE(NavigateToURL(shell(), url_b));
11183 params_capturer.Wait();
11184 EXPECT_TRUE(params_capturer.is_overriding_user_agent());
11185 EXPECT_EQ(user_agent_override,
11186 EvalJs(shell()->web_contents(), "navigator.userAgent"));
11187 }
11188
11189 // A should be stored in the back-forward cache.
11190 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
11191
11192 RenderFrameHostImpl* rfh_b = current_frame_host();
11193
11194 // 3) Go back to A. RenderFrameHost of A should not be restored from the
11195 // back-forward cache, and "is_overriding_user_agent" is set to true
11196 // correctly.
11197 {
11198 RenderFrameDeletedObserver delete_observer(rfh_a);
11199 FrameNavigateParamsCapturer params_capturer(root);
11200 controller.GoBack();
11201 params_capturer.Wait();
11202 delete_observer.WaitUntilDeleted();
11203 EXPECT_TRUE(params_capturer.is_overriding_user_agent());
11204 EXPECT_EQ(user_agent_override,
11205 EvalJs(shell()->web_contents(), "navigator.userAgent"));
11206 ExpectNotRestored(
11207 {BackForwardCacheMetrics::NotRestoredReason::kUserAgentOverrideDiffers},
11208 {}, {}, {}, FROM_HERE);
11209 }
11210
11211 // B should be stored in the back-forward cache.
11212 EXPECT_TRUE(rfh_b->IsInBackForwardCache());
11213
11214 // 4) Go forward to B. RenderFrameHost of B should be restored from the
11215 // back-forward cache, and "is_overriding_user_agent" is set to true
11216 // correctly.
11217 {
11218 FrameNavigateParamsCapturer params_capturer(root);
11219 controller.GoForward();
11220 params_capturer.Wait();
11221 EXPECT_TRUE(params_capturer.is_overriding_user_agent());
11222 EXPECT_EQ(user_agent_override,
11223 EvalJs(shell()->web_contents(), "navigator.userAgent"));
11224 EXPECT_EQ(rfh_b, current_frame_host());
11225 ExpectRestored(FROM_HERE);
11226 }
11227
11228 // Stop overriding user agent from now on.
11229 injector.set_is_overriding_user_agent(false);
11230
11231 // 5) Go to C, which should not do a user agent override.
11232 {
11233 FrameNavigateParamsCapturer params_capturer(root);
11234 EXPECT_TRUE(NavigateToURL(shell(), url_c));
11235 params_capturer.Wait();
11236 EXPECT_FALSE(params_capturer.is_overriding_user_agent());
11237 EXPECT_NE(user_agent_override,
11238 EvalJs(shell()->web_contents(), "navigator.userAgent"));
11239 }
11240
11241 // B should be stored in the back-forward cache again.
11242 EXPECT_TRUE(rfh_b->IsInBackForwardCache());
11243
11244 // 6) Go back to B. RenderFrameHost of B should not be restored from the
11245 // back-forward cache, and "is_overriding_user_agent" is set to false
11246 // correctly.
11247 {
11248 FrameNavigateParamsCapturer params_capturer(root);
11249 RenderFrameDeletedObserver delete_observer(rfh_b);
11250 controller.GoBack();
11251 params_capturer.Wait();
11252 delete_observer.WaitUntilDeleted();
11253 EXPECT_FALSE(params_capturer.is_overriding_user_agent());
11254 EXPECT_NE(user_agent_override,
11255 EvalJs(shell()->web_contents(), "navigator.userAgent"));
11256 ExpectNotRestored(
11257 {BackForwardCacheMetrics::NotRestoredReason::kUserAgentOverrideDiffers},
11258 {}, {}, {}, FROM_HERE);
11259 }
11260}
11261
11262IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
11263 RestoreWhenUserAgentOverrideDiffers) {
11264 ASSERT_TRUE(embedded_test_server()->Start());
11265
11266 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
11267 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
11268 NavigationControllerImpl& controller = web_contents()->GetController();
11269 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
11270 ->GetFrameTree()
11271 ->root();
11272
11273 // Enable user agent override for future navigations.
11274 const std::string user_agent_override_1 = "foo";
11275 UserAgentInjector injector(shell()->web_contents(), user_agent_override_1);
11276
11277 // 1) Start a new navigation to A with user agent override.
11278 {
11279 FrameNavigateParamsCapturer params_capturer(root);
11280 EXPECT_TRUE(NavigateToURL(shell(), url_a));
11281 params_capturer.Wait();
11282 EXPECT_TRUE(params_capturer.is_overriding_user_agent());
11283 EXPECT_EQ(user_agent_override_1,
11284 EvalJs(shell()->web_contents(), "navigator.userAgent"));
11285 }
11286
11287 RenderFrameHostImpl* rfh_a = current_frame_host();
11288
11289 // 2) Navigate to another page.
11290 EXPECT_TRUE(NavigateToURL(shell(), url_b));
11291
11292 // A should be stored in the back-forward cache.
11293 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
11294
11295 // Change the user agent override string.
11296 const std::string user_agent_override_2 = "bar";
11297 injector.set_user_agent_override(user_agent_override_2);
11298
11299 // 3) Go back to A, which should restore the page saved in the back-forward
11300 // cache and use the old user agent.
11301 // TODO(https://crbug.com/1194880): This should use the new UA override.
11302 {
11303 FrameNavigateParamsCapturer params_capturer(root);
11304 controller.GoBack();
11305 params_capturer.Wait();
11306 EXPECT_TRUE(params_capturer.is_overriding_user_agent());
11307 EXPECT_EQ(user_agent_override_1,
11308 EvalJs(shell()->web_contents(), "navigator.userAgent"));
11309 EXPECT_EQ(rfh_a, current_frame_host());
11310 ExpectRestored(FROM_HERE);
11311 }
11312
11313 // 4) Navigate to another page, which should use the new user agent. Note that
11314 // we didn't do this in step 2 instead because the UA override change during
11315 // navigation would trigger a RendererPreferences to the active page (page A).
11316 {
11317 FrameNavigateParamsCapturer params_capturer(root);
11318 EXPECT_TRUE(NavigateToURL(shell(), url_b));
11319 params_capturer.Wait();
11320 EXPECT_TRUE(params_capturer.is_overriding_user_agent());
11321 EXPECT_EQ(user_agent_override_2,
11322 EvalJs(shell()->web_contents(), "navigator.userAgent"));
11323 }
11324}
11325
Alexander Timin8aeee642021-05-12 08:39:3311326IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
11327 WebContentsDestroyedWhileRestoringThePageFromBFCache) {
11328 ASSERT_TRUE(embedded_test_server()->Start());
11329
11330 Shell* shell = CreateBrowser();
11331
11332 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
11333 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
11334
11335 // 1) Navigate to A.
11336 EXPECT_TRUE(NavigateToURL(shell, url_a));
11337
11338 // 2) Navigate to another page.
11339 EXPECT_TRUE(NavigateToURL(shell, url_b));
11340
11341 // 3) Start navigating back.
11342 TestNavigationManager nav_manager(shell->web_contents(), url_a);
11343 shell->web_contents()->GetController().GoBack();
David Bokan377fb3e2021-06-09 16:19:5711344 nav_manager.WaitForFirstYieldAfterDidStartNavigation();
Alexander Timin8aeee642021-05-12 08:39:3311345
11346 testing::NiceMock<MockWebContentsObserver> observer(shell->web_contents());
11347 EXPECT_CALL(observer, DidFinishNavigation(_))
11348 .WillOnce(testing::Invoke([](NavigationHandle* handle) {
11349 EXPECT_FALSE(handle->HasCommitted());
11350 EXPECT_TRUE(handle->IsServedFromBackForwardCache());
11351 // This call checks that |rfh_restored_from_back_forward_cache| is not
11352 // deleted and the virtual |GetRoutingID| does not crash.
11353 EXPECT_TRUE(NavigationRequest::From(handle)
11354 ->rfh_restored_from_back_forward_cache()
11355 ->GetRoutingID());
11356 }));
11357
11358 shell->Close();
11359}
11360
Vasilii Sukhanov6b98a592021-08-27 14:40:3211361// Fails under address-sanitizer. http://crbug.com/1243159
11362#if defined(ADDRESS_SANITIZER)
11363#define MAYBE_DoNotCacheIfMediaSessionPlaybackStateChanged \
11364 DISABLED_DoNotCacheIfMediaSessionPlaybackStateChanged
11365#else
11366#define MAYBE_DoNotCacheIfMediaSessionPlaybackStateChanged \
11367 DoNotCacheIfMediaSessionPlaybackStateChanged
11368#endif
Hajime Hoshiafd7a0c2021-08-24 10:44:1411369IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
Vasilii Sukhanov6b98a592021-08-27 14:40:3211370 MAYBE_DoNotCacheIfMediaSessionPlaybackStateChanged) {
Hajime Hoshic52208f2021-04-14 13:22:4111371 ASSERT_TRUE(embedded_test_server()->Start());
11372
Michael Ershov9805fbc2021-08-25 12:28:5011373 // 1) Navigate to a page using MediaSession.
11374 EXPECT_TRUE(NavigateToURL(
11375 shell(), embedded_test_server()->GetURL("a.com", "/title1.html")));
11376 RenderFrameHost* rfh_a = shell()->web_contents()->GetMainFrame();
11377 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
11378 EXPECT_TRUE(ExecJs(rfh_a, R"(
11379 navigator.mediaSession.metadata = new MediaMetadata({
11380 artwork: [
11381 {src: "test_image.jpg", sizes: "1x1", type: "image/jpeg"},
11382 {src: "test_image.jpg", sizes: "10x10", type: "image/jpeg"}
11383 ]
11384 });
11385 )"));
Hajime Hoshic52208f2021-04-14 13:22:4111386
Michael Ershov9805fbc2021-08-25 12:28:5011387 // 2) Navigate away.
11388 EXPECT_TRUE(NavigateToURL(
11389 shell(), embedded_test_server()->GetURL("b.com", "/title1.html")));
Hajime Hoshic52208f2021-04-14 13:22:4111390
Michael Ershov9805fbc2021-08-25 12:28:5011391 // 3) Go back.
11392 web_contents()->GetController().GoBack();
11393 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
Hajime Hoshic52208f2021-04-14 13:22:4111394
Michael Ershov9805fbc2021-08-25 12:28:5011395 // The page is restored since the playback state is not changed.
11396 ExpectRestored(FROM_HERE);
Hajime Hoshic52208f2021-04-14 13:22:4111397
Michael Ershov9805fbc2021-08-25 12:28:5011398 // 4) Modify the playback state of the media session.
11399 EXPECT_TRUE(ExecJs(rfh_a, R"(
11400 navigator.mediaSession.playbackState = 'playing';
11401 )"));
Hajime Hoshic52208f2021-04-14 13:22:4111402
Michael Ershov9805fbc2021-08-25 12:28:5011403 // 5) Navigate away.
11404 EXPECT_TRUE(NavigateToURL(
11405 shell(), embedded_test_server()->GetURL("b.com", "/title1.html")));
Hajime Hoshic52208f2021-04-14 13:22:4111406
Michael Ershov9805fbc2021-08-25 12:28:5011407 // 6) Go back.
11408 web_contents()->GetController().GoBack();
11409 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
Hajime Hoshic52208f2021-04-14 13:22:4111410
Michael Ershov9805fbc2021-08-25 12:28:5011411 // The page is not restored due to the playback.
11412 auto reason = BackForwardCacheDisable::DisabledReason(
11413 BackForwardCacheDisable::DisabledReasonId::kMediaSession);
11414 ExpectNotRestored({BackForwardCacheMetrics::NotRestoredReason::
11415 kDisableForRenderFrameHostCalled},
11416 {}, {}, {reason}, FROM_HERE);
Hajime Hoshic52208f2021-04-14 13:22:4111417}
11418
Dave Tapuskadfff7382021-04-23 19:46:4111419// Test if the delegate doesn't support BFCache that the reason is
11420// recorded correctly.
11421IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
11422 DelegateDoesNotSupportBackForwardCache) {
11423 // Set the delegate to null to force the default behavior.
11424 web_contents()->SetDelegate(nullptr);
11425
11426 ASSERT_TRUE(embedded_test_server()->Start());
11427 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
11428 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
11429
11430 EXPECT_TRUE(NavigateToURL(shell(), url_a));
11431 // BackForwardCache is empty.
11432 RenderFrameHostImpl* rfh_a = current_frame_host();
11433 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
11434
11435 EXPECT_TRUE(NavigateToURL(shell(), url_b));
11436 // BackForwardCache contains only rfh_a.
11437 RenderFrameHostImpl* rfh_b = current_frame_host();
11438 RenderFrameDeletedObserver delete_observer_rfh_b(rfh_b);
11439
11440 web_contents()->GetController().GoToOffset(-1);
11441 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
11442 ExpectNotRestored({BackForwardCacheMetrics::NotRestoredReason::
11443 kBackForwardCacheDisabledForDelegate},
11444 {}, {}, {}, FROM_HERE);
11445}
11446
kouheif9bd57412021-04-29 06:56:5711447class BackForwardCacheOptInBrowserTest : public BackForwardCacheBrowserTest {
11448 protected:
11449 void SetUpCommandLine(base::CommandLine* command_line) override {
11450 EnableFeatureAndSetParams(features::kBackForwardCache,
11451 "opt_in_header_required", "true");
11452 BackForwardCacheBrowserTest::SetUpCommandLine(command_line);
11453 }
11454};
11455
kouhei4d6e80d2021-04-30 03:41:0911456IN_PROC_BROWSER_TEST_F(BackForwardCacheOptInBrowserTest, NoCacheWithoutHeader) {
kouheif9bd57412021-04-29 06:56:5711457 ASSERT_TRUE(embedded_test_server()->Start());
11458 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
11459 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
11460
11461 // 1) Navigate to A.
11462 EXPECT_TRUE(NavigateToURL(shell(), url_a));
kouheif9bd57412021-04-29 06:56:5711463
11464 // 2) Navigate to B.
11465 EXPECT_TRUE(NavigateToURL(shell(), url_b));
kouheif9bd57412021-04-29 06:56:5711466
11467 // 3) Go back.
11468 web_contents()->GetController().GoBack();
11469 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
11470
11471 ExpectNotRestored({BackForwardCacheMetrics::NotRestoredReason::
11472 kOptInUnloadHeaderNotPresent},
11473 {}, {}, {}, FROM_HERE);
11474}
11475
kouheif9bd57412021-04-29 06:56:5711476IN_PROC_BROWSER_TEST_F(BackForwardCacheOptInBrowserTest,
11477 CacheIfHeaderIsPresent) {
kouheif9bd57412021-04-29 06:56:5711478 ASSERT_TRUE(embedded_test_server()->Start());
kouhei73c931322021-04-30 05:33:0911479 GURL url_a(embedded_test_server()->GetURL("a.com",
11480 "/set-header?"
11481 "BFCache-Opt-In: unload"));
kouheif9bd57412021-04-29 06:56:5711482 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
11483
11484 // 1) Navigate to A.
kouhei73c931322021-04-30 05:33:0911485 EXPECT_TRUE(NavigateToURL(shell(), url_a));
kouheif9bd57412021-04-29 06:56:5711486
11487 // 2) Navigate to B.
11488 EXPECT_TRUE(NavigateToURL(shell(), url_b));
kouheif9bd57412021-04-29 06:56:5711489
11490 // 3) Go back.
11491 web_contents()->GetController().GoBack();
11492 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
11493
11494 ExpectRestored(FROM_HERE);
11495}
11496
11497IN_PROC_BROWSER_TEST_F(BackForwardCacheOptInBrowserTest,
kouhei4d6e80d2021-04-30 03:41:0911498 NoCacheIfHeaderOnlyPresentOnDestinationPage) {
kouheif9bd57412021-04-29 06:56:5711499 ASSERT_TRUE(embedded_test_server()->Start());
11500
11501 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
kouhei73c931322021-04-30 05:33:0911502 GURL url_b(embedded_test_server()->GetURL("b.com",
11503 "/set-header?"
11504 "BFCache-Opt-In: unload"));
kouheif9bd57412021-04-29 06:56:5711505
11506 // 1) Navigate to A.
11507 EXPECT_TRUE(NavigateToURL(shell(), url_a));
kouheif9bd57412021-04-29 06:56:5711508
11509 // 2) Navigate to B.
kouhei73c931322021-04-30 05:33:0911510 EXPECT_TRUE(NavigateToURL(shell(), url_b));
kouheif9bd57412021-04-29 06:56:5711511
11512 // 3) Go back. - A doesn't have header so it shouldn't be cached.
11513 web_contents()->GetController().GoBack();
11514 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
11515
11516 ExpectNotRestored({BackForwardCacheMetrics::NotRestoredReason::
11517 kOptInUnloadHeaderNotPresent},
11518 {}, {}, {}, FROM_HERE);
11519
11520 // 4) Go forward. - B has the header, so it should be cached.
11521 web_contents()->GetController().GoForward();
11522 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
11523
11524 ExpectRestored(FROM_HERE);
11525}
11526
kouheib3517d7d2021-05-19 07:48:5611527class BackForwardCacheUnloadStrategyBrowserTest
11528 : public BackForwardCacheBrowserTest,
11529 public testing::WithParamInterface<std::string> {
11530 protected:
11531 void SetUpCommandLine(base::CommandLine* command_line) override {
Minoru Chikamune1a0a99dc2021-06-09 15:39:5011532 unload_support_ = GetParam();
kouheib3517d7d2021-05-19 07:48:5611533 BackForwardCacheBrowserTest::SetUpCommandLine(command_line);
11534 }
11535
11536 void InstallUnloadHandlerOnSubFrame() {
11537 TestNavigationObserver navigation_observer(shell()->web_contents(), 1);
11538 EXPECT_TRUE(ExecJs(current_frame_host(), R"(
11539 const iframeElement = document.createElement("iframe");
11540 iframeElement.src = "%s";
11541 document.body.appendChild(iframeElement);
11542 )"));
11543 navigation_observer.Wait();
11544 RenderFrameHostImpl* subframe_render_frame_host =
11545 current_frame_host()->child_at(0)->current_frame_host();
11546 EXPECT_TRUE(
11547 ExecJs(subframe_render_frame_host, "window.onunload = () => 42;"));
11548 }
11549};
11550
11551INSTANTIATE_TEST_SUITE_P(All,
11552 BackForwardCacheUnloadStrategyBrowserTest,
Minoru Chikamune75b51fd2021-09-02 15:29:0211553 testing::Values("always",
11554 "opt_in_header_required",
11555 "no"));
kouheib3517d7d2021-05-19 07:48:5611556
11557IN_PROC_BROWSER_TEST_P(BackForwardCacheUnloadStrategyBrowserTest,
11558 UnloadHandlerPresentWithOptInHeader) {
11559 ASSERT_TRUE(embedded_test_server()->Start());
11560
11561 GURL url_a(embedded_test_server()->GetURL("a.com",
11562 "/set-header?"
11563 "BFCache-Opt-In: unload"));
11564 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
11565
11566 // 1) Navigate to A.
11567 EXPECT_TRUE(NavigateToURL(shell(), url_a));
11568 EXPECT_TRUE(ExecJs(current_frame_host(), "window.onunload = () => 42;"));
11569
11570 // 2) Navigate to B.
11571 EXPECT_TRUE(NavigateToURL(shell(), url_b));
11572
11573 // 3) Go back.
11574 web_contents()->GetController().GoBack();
11575 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
11576
Minoru Chikamune75b51fd2021-09-02 15:29:0211577 if (GetParam() == "always" || GetParam() == "opt_in_header_required") {
11578 ExpectRestored(FROM_HERE);
11579 } else {
11580 ExpectNotRestored({BackForwardCacheMetrics::NotRestoredReason::
11581 kUnloadHandlerExistsInMainFrame},
11582 {}, {}, {}, FROM_HERE);
11583 }
kouheib3517d7d2021-05-19 07:48:5611584
11585 // 4) Go forward.
11586 web_contents()->GetController().GoForward();
11587 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
11588
11589 ExpectRestored(FROM_HERE);
11590}
11591
11592IN_PROC_BROWSER_TEST_P(BackForwardCacheUnloadStrategyBrowserTest,
11593 UnloadHandlerPresentWithoutOptInHeader) {
11594 ASSERT_TRUE(embedded_test_server()->Start());
11595
11596 GURL url_a(embedded_test_server()->GetURL("a.com", "/unload.html"));
11597 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
11598
11599 // 1) Navigate to A.
11600 EXPECT_TRUE(NavigateToURL(shell(), url_a));
11601
11602 // 2) Navigate to B.
11603 EXPECT_TRUE(NavigateToURL(shell(), url_b));
11604
11605 // 3) Go back.
11606 web_contents()->GetController().GoBack();
11607 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
11608
11609 if (GetParam() == "always") {
11610 ExpectRestored(FROM_HERE);
Minoru Chikamune75b51fd2021-09-02 15:29:0211611 } else if (GetParam() == "opt_in_header_required") {
kouheib3517d7d2021-05-19 07:48:5611612 ExpectNotRestored({BackForwardCacheMetrics::NotRestoredReason::
11613 kOptInUnloadHeaderNotPresent},
11614 {}, {}, {}, FROM_HERE);
Minoru Chikamune75b51fd2021-09-02 15:29:0211615 } else {
11616 ExpectNotRestored({BackForwardCacheMetrics::NotRestoredReason::
11617 kUnloadHandlerExistsInMainFrame},
11618 {}, {}, {}, FROM_HERE);
kouheib3517d7d2021-05-19 07:48:5611619 }
11620
11621 // 4) Go forward.
11622 web_contents()->GetController().GoForward();
11623 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
11624
11625 ExpectRestored(FROM_HERE);
11626}
11627
11628IN_PROC_BROWSER_TEST_P(BackForwardCacheUnloadStrategyBrowserTest,
11629 UnloadHandlerPresentInSubFrameWithOptInHeader) {
11630 ASSERT_TRUE(embedded_test_server()->Start());
11631
11632 GURL url_a(embedded_test_server()->GetURL("a.com",
11633 "/set-header?"
11634 "BFCache-Opt-In: unload"));
11635 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
11636
11637 // 1) Navigate to A.
11638 EXPECT_TRUE(NavigateToURL(shell(), url_a));
11639 InstallUnloadHandlerOnSubFrame();
11640
11641 // 2) Navigate to B.
11642 EXPECT_TRUE(NavigateToURL(shell(), url_b));
11643
11644 // 3) Go back.
11645 web_contents()->GetController().GoBack();
11646 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
11647
Minoru Chikamune75b51fd2021-09-02 15:29:0211648 if (GetParam() == "always" || GetParam() == "opt_in_header_required") {
11649 ExpectRestored(FROM_HERE);
11650 } else {
11651 ASSERT_EQ("no", GetParam());
11652 ExpectNotRestored({BackForwardCacheMetrics::NotRestoredReason::
11653 kUnloadHandlerExistsInSubFrame},
11654 {}, {}, {}, FROM_HERE);
11655 }
kouheib3517d7d2021-05-19 07:48:5611656
11657 // 4) Go forward.
11658 web_contents()->GetController().GoForward();
11659 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
11660
11661 ExpectRestored(FROM_HERE);
11662}
11663
11664IN_PROC_BROWSER_TEST_P(BackForwardCacheUnloadStrategyBrowserTest,
11665 UnloadHandlerPresentInSubFrameWithoutOptInHeader) {
11666 ASSERT_TRUE(embedded_test_server()->Start());
11667
11668 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
11669 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
11670
11671 // 1) Navigate to A.
11672 EXPECT_TRUE(NavigateToURL(shell(), url_a));
11673 InstallUnloadHandlerOnSubFrame();
11674
11675 // 2) Navigate to B.
11676 EXPECT_TRUE(NavigateToURL(shell(), url_b));
11677
11678 // 3) Go back.
11679 web_contents()->GetController().GoBack();
11680 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
11681
11682 if (GetParam() == "always") {
11683 ExpectRestored(FROM_HERE);
11684 } else {
11685 ExpectNotRestored({BackForwardCacheMetrics::NotRestoredReason::
11686 kUnloadHandlerExistsInSubFrame},
11687 {}, {}, {}, FROM_HERE);
11688 }
11689
11690 // 4) Go forward.
11691 web_contents()->GetController().GoForward();
11692 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
11693
11694 ExpectRestored(FROM_HERE);
11695}
11696
David Bokan377fb3e2021-06-09 16:19:5711697IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, NoThrottlesOnCacheRestore) {
11698 ASSERT_TRUE(embedded_test_server()->Start());
11699 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
11700 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
11701
11702 // 1) Navigate to A.
11703 ASSERT_TRUE(NavigateToURL(shell(), url_a));
11704 RenderFrameHostImpl* rfh_a = current_frame_host();
11705 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
11706
11707 bool did_register_throttles = false;
11708
11709 // This will track for each navigation whether we attempted to register
11710 // NavigationThrottles.
11711 content::ShellContentBrowserClient::Get()
11712 ->set_create_throttles_for_navigation_callback(base::BindLambdaForTesting(
11713 [&did_register_throttles](content::NavigationHandle* handle)
11714 -> std::vector<std::unique_ptr<content::NavigationThrottle>> {
11715 did_register_throttles = true;
11716 return std::vector<std::unique_ptr<content::NavigationThrottle>>();
11717 }));
11718
11719 // 2) Navigate to B.
11720 ASSERT_TRUE(NavigateToURL(shell(), url_b));
11721 RenderFrameHostImpl* rfh_b = current_frame_host();
11722 RenderFrameDeletedObserver delete_observer_rfh_b(rfh_b);
11723 ASSERT_FALSE(delete_observer_rfh_a.deleted());
11724 ASSERT_TRUE(rfh_a->IsInBackForwardCache());
11725 EXPECT_TRUE(did_register_throttles);
11726 did_register_throttles = false;
11727
11728 // 3) Go back to A which is in the BackForward cache and will be restored via
11729 // an IsPageActivation navigation. Ensure that we did not register
11730 // NavigationThrottles for this navigation since we already ran their checks
11731 // when we navigated to A in step 1.
11732 web_contents()->GetController().GoBack();
11733 ASSERT_TRUE(WaitForLoadStop(shell()->web_contents()));
11734 EXPECT_FALSE(did_register_throttles);
11735
11736 ExpectRestored(FROM_HERE);
11737}
11738
Yuzu Saijob50355932021-07-14 06:16:2711739class BackForwardCacheBrowserTestAllowCacheControlNoStore
11740 : public BackForwardCacheBrowserTest {
11741 protected:
11742 void SetUpCommandLine(base::CommandLine* command_line) override {
11743 EnableFeatureAndSetParams(features::kBackForwardCache, "", "");
Yuzu Saijoc4d269cc2021-07-15 07:32:2411744 EnableFeatureAndSetParams(kCacheControlNoStoreEnterBackForwardCache, "",
11745 "");
Yuzu Saijob50355932021-07-14 06:16:2711746 BackForwardCacheBrowserTest::SetUpCommandLine(command_line);
11747 }
11748};
11749
Lingqi Chi6748cd592021-07-22 03:48:4411750// TODO(https://crbug.com/1231849): flaky on Cast Linux.
11751#if defined(OS_LINUX)
11752#define MAYBE_PagesWithCacheControlNoStoreEnterBfcacheAndEvicted \
11753 DISABLED_PagesWithCacheControlNoStoreEnterBfcacheAndEvicted
11754#else
11755#define MAYBE_PagesWithCacheControlNoStoreEnterBfcacheAndEvicted \
11756 PagesWithCacheControlNoStoreEnterBfcacheAndEvicted
11757#endif
11758
Yuzu Saijob50355932021-07-14 06:16:2711759// Test that a page with cache-control:no-store enters bfcache with the flag on,
11760// but does not get restored and gets evicted.
Lingqi Chi6748cd592021-07-22 03:48:4411761IN_PROC_BROWSER_TEST_F(
11762 BackForwardCacheBrowserTestAllowCacheControlNoStore,
11763 MAYBE_PagesWithCacheControlNoStoreEnterBfcacheAndEvicted) {
Yuzu Saijob50355932021-07-14 06:16:2711764 net::test_server::ControllableHttpResponse response(embedded_test_server(),
11765 "/main_document");
11766 net::test_server::ControllableHttpResponse response2(embedded_test_server(),
11767 "/main_document");
11768 ASSERT_TRUE(embedded_test_server()->Start());
11769
11770 GURL url_a(embedded_test_server()->GetURL("a.com", "/main_document"));
11771 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
11772
11773 // 1) Load the document and specify no-store for the main resource.
11774 TestNavigationObserver observer(web_contents());
11775 shell()->LoadURL(url_a);
11776 RenderFrameHostImplWrapper rfh_a(current_frame_host());
11777 response.WaitForRequest();
11778 response.Send(kResponseWithNoCache);
11779 response.Done();
11780 observer.Wait();
11781
11782 // 2) Navigate away. |rfh_a| should enter the bfcache.
11783 EXPECT_TRUE(NavigateToURL(shell(), url_b));
11784 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
11785
11786 // 3) Go back. |rfh_a| should be evicted upon restoration.
11787 TestNavigationObserver observer2(web_contents());
11788 web_contents()->GetController().GoBack();
11789 response2.WaitForRequest();
11790 response2.Send(kResponseWithNoCache);
11791 response2.Done();
11792 observer2.Wait();
11793
11794 ExpectNotRestored(
11795 {BackForwardCacheMetrics::NotRestoredReason::kCacheControlNoStore}, {},
11796 {}, {}, FROM_HERE);
11797}
11798
Christian Dullweber5c5a42a2021-07-15 09:16:1411799#if BUILDFLAG(IS_CHROMECAST)
11800#define MAYBE_PagesWithCacheControlNoStoreCookieModifiedThroughJavaScript \
11801 DISABLED_PagesWithCacheControlNoStoreCookieModifiedThroughJavaScript
11802#else
11803#define MAYBE_PagesWithCacheControlNoStoreCookieModifiedThroughJavaScript \
11804 PagesWithCacheControlNoStoreCookieModifiedThroughJavaScript
11805#endif
11806
Yuzu Saijob50355932021-07-14 06:16:2711807// Test that a page with cache-control:no-store enters bfcache with the flag on,
11808// and if a cookie is modified while it is in bfcache via JavaScript, gets
11809// evicted with cookie modified marked.
11810IN_PROC_BROWSER_TEST_F(
11811 BackForwardCacheBrowserTestAllowCacheControlNoStore,
Christian Dullweber5c5a42a2021-07-15 09:16:1411812 MAYBE_PagesWithCacheControlNoStoreCookieModifiedThroughJavaScript) {
Yuzu Saijob50355932021-07-14 06:16:2711813 net::test_server::ControllableHttpResponse response(embedded_test_server(),
11814 "/main_document");
11815 net::test_server::ControllableHttpResponse response2(embedded_test_server(),
11816 "/main_document");
11817 ASSERT_TRUE(embedded_test_server()->Start());
11818
11819 GURL url_a(embedded_test_server()->GetURL("a.com", "/main_document"));
11820 GURL url_a_2(embedded_test_server()->GetURL("a.com", "/title1.html"));
11821 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
11822
11823 Shell* tab_to_be_bfcached = shell();
11824 Shell* tab_to_modify_cookie = CreateBrowser();
11825
11826 // 1) Load the document and specify no-store for the main resource.
11827 TestNavigationObserver observer(tab_to_be_bfcached->web_contents());
11828 tab_to_be_bfcached->LoadURL(url_a);
11829 RenderFrameHostImplWrapper rfh_a(current_frame_host());
11830 response.WaitForRequest();
11831 response.Send(kResponseWithNoCache);
11832 response.Done();
11833 observer.Wait();
11834
11835 // 2) Set a normal cookie from JavaScript.
11836 EXPECT_TRUE(ExecJs(tab_to_be_bfcached, "document.cookie='foo=bar'"));
11837 EXPECT_EQ("foo=bar", EvalJs(tab_to_be_bfcached, "document.cookie"));
11838
11839 // 3) Navigate away. |rfh_a| should enter bfcache.
11840 EXPECT_TRUE(NavigateToURL(tab_to_be_bfcached, url_b));
11841 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
11842
11843 // 4) Navigate to a.com in |tab_to_modify_cookie| and modify cookie from
11844 // JavaScript.
11845 EXPECT_TRUE(NavigateToURL(tab_to_modify_cookie, url_a_2));
11846 EXPECT_EQ("foo=bar", EvalJs(tab_to_modify_cookie, "document.cookie"));
11847 EXPECT_TRUE(ExecJs(tab_to_modify_cookie, "document.cookie='foo=baz'"));
11848 EXPECT_EQ("foo=baz", EvalJs(tab_to_modify_cookie, "document.cookie"));
11849
11850 // 5) Go back. |rfh_a| should be evicted upon restoration.
11851 TestNavigationObserver observer2(tab_to_be_bfcached->web_contents());
11852 tab_to_be_bfcached->web_contents()->GetController().GoBack();
11853 response2.WaitForRequest();
11854 response2.Send(kResponseWithNoCache);
11855 response2.Done();
11856 observer2.Wait();
11857
11858 EXPECT_EQ("foo=baz", EvalJs(tab_to_be_bfcached, "document.cookie"));
11859 ExpectNotRestored({BackForwardCacheMetrics::NotRestoredReason::
11860 kCacheControlNoStoreCookieModified},
11861 {}, {}, {}, FROM_HERE);
11862}
11863
Christian Dullweber5c5a42a2021-07-15 09:16:1411864// Disabled due to flakiness on Cast Audio Linux https://crbug.com/1229182
11865#if BUILDFLAG(IS_CHROMECAST)
11866#define MAYBE_PagesWithCacheControlNoStoreCookieModifiedBackTwice \
11867 DISABLED_PagesWithCacheControlNoStoreCookieModifiedBackTwice
11868#else
11869#define MAYBE_PagesWithCacheControlNoStoreCookieModifiedBackTwice \
11870 PagesWithCacheControlNoStoreCookieModifiedBackTwice
11871#endif
11872
Yuzu Saijob50355932021-07-14 06:16:2711873// Test that a page with cache-control:no-store enters bfcache with the flag on,
11874// and if a cookie is modified, it gets evicted with cookie changed, but if
11875// navigated away again and navigated back, it gets evicted without cookie
11876// change marked.
Christian Dullweber5c5a42a2021-07-15 09:16:1411877IN_PROC_BROWSER_TEST_F(
11878 BackForwardCacheBrowserTestAllowCacheControlNoStore,
11879 MAYBE_PagesWithCacheControlNoStoreCookieModifiedBackTwice) {
Yuzu Saijob50355932021-07-14 06:16:2711880 net::test_server::ControllableHttpResponse response(embedded_test_server(),
11881 "/main_document");
11882 net::test_server::ControllableHttpResponse response2(embedded_test_server(),
11883 "/main_document");
11884 net::test_server::ControllableHttpResponse response3(embedded_test_server(),
11885 "/main_document");
11886 ASSERT_TRUE(embedded_test_server()->Start());
11887
11888 GURL url_a(embedded_test_server()->GetURL("a.com", "/main_document"));
11889 GURL url_a_2(embedded_test_server()->GetURL("a.com", "/title1.html"));
11890 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
11891
11892 Shell* tab_to_be_bfcached = shell();
11893 Shell* tab_to_modify_cookie = CreateBrowser();
11894
11895 // 1) Load the document and specify no-store for the main resource.
11896 TestNavigationObserver observer(tab_to_be_bfcached->web_contents());
11897 tab_to_be_bfcached->LoadURL(url_a);
11898 RenderFrameHostImplWrapper rfh_a(current_frame_host());
11899 response.WaitForRequest();
11900 response.Send(kResponseWithNoCache);
11901 response.Done();
11902 observer.Wait();
11903
11904 // 2) Set a normal cookie from JavaScript.
11905 EXPECT_TRUE(ExecJs(tab_to_be_bfcached, "document.cookie='foo=bar'"));
11906 EXPECT_EQ("foo=bar", EvalJs(tab_to_be_bfcached, "document.cookie"));
11907
11908 // 3) Navigate away. |rfh_a| should enter bfcache.
11909 EXPECT_TRUE(NavigateToURL(tab_to_be_bfcached, url_b));
11910 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
11911
11912 // 4) Navigate to a.com in |tab_to_modify_cookie| and modify cookie from
11913 // JavaScript.
11914 EXPECT_TRUE(NavigateToURL(tab_to_modify_cookie, url_a_2));
11915 EXPECT_EQ("foo=bar", EvalJs(tab_to_modify_cookie, "document.cookie"));
11916 EXPECT_TRUE(ExecJs(tab_to_modify_cookie, "document.cookie='foo=baz'"));
11917 EXPECT_EQ("foo=baz", EvalJs(tab_to_modify_cookie, "document.cookie"));
11918
11919 // 5) Go back. |rfh_a| should be evicted upon restoration.
11920 TestNavigationObserver observer2(tab_to_be_bfcached->web_contents());
11921 tab_to_be_bfcached->web_contents()->GetController().GoBack();
11922 response2.WaitForRequest();
11923 response2.Send(kResponseWithNoCache);
11924 response2.Done();
11925 observer2.Wait();
11926
11927 EXPECT_EQ("foo=baz", EvalJs(tab_to_be_bfcached, "document.cookie"));
11928 ExpectNotRestored({BackForwardCacheMetrics::NotRestoredReason::
11929 kCacheControlNoStoreCookieModified},
11930 {}, {}, {}, FROM_HERE);
11931 RenderFrameHostImplWrapper rfh_a_2(current_frame_host());
11932
11933 // 6) Navigate away to b.com. |rfh_a_2| should enter bfcache again.
11934 EXPECT_TRUE(NavigateToURL(tab_to_be_bfcached, url_b));
11935 EXPECT_TRUE(rfh_a_2->IsInBackForwardCache());
11936
11937 // 7) Navigate back to a.com. This time the cookie change has to be reset and
11938 // gets evicted with a different reason.
11939 TestNavigationObserver observer3(tab_to_be_bfcached->web_contents());
11940 tab_to_be_bfcached->web_contents()->GetController().GoBack();
11941 response3.WaitForRequest();
11942 response3.Send(kResponseWithNoCache);
11943 response3.Done();
11944 observer3.Wait();
11945 ExpectNotRestored(
11946 {BackForwardCacheMetrics::NotRestoredReason::kCacheControlNoStore}, {},
11947 {}, {}, FROM_HERE);
11948}
11949
Christian Dullweber5c5a42a2021-07-15 09:16:1411950// Disabled due to flakiness on Cast Audio Linux https://crbug.com/1229182
11951#if BUILDFLAG(IS_CHROMECAST)
11952#define MAYBE_PagesWithCacheControlNoStoreCookieModifiedThroughJavaScriptOnDifferentDomain \
11953 DISABLED_PagesWithCacheControlNoStoreCookieModifiedThroughJavaScriptOnDifferentDomain
11954#else
11955#define MAYBE_PagesWithCacheControlNoStoreCookieModifiedThroughJavaScriptOnDifferentDomain \
11956 PagesWithCacheControlNoStoreCookieModifiedThroughJavaScriptOnDifferentDomain
11957#endif
11958
Yuzu Saijob50355932021-07-14 06:16:2711959// Test that a page with cache-control:no-store enters bfcache with the flag on,
11960// and even if a cookie is modified on a different domain than the entry, the
11961// entry is not marked as cookie modified.
11962IN_PROC_BROWSER_TEST_F(
11963 BackForwardCacheBrowserTestAllowCacheControlNoStore,
Christian Dullweber5c5a42a2021-07-15 09:16:1411964 MAYBE_PagesWithCacheControlNoStoreCookieModifiedThroughJavaScriptOnDifferentDomain) {
Yuzu Saijob50355932021-07-14 06:16:2711965 net::test_server::ControllableHttpResponse response(embedded_test_server(),
11966 "/main_document");
11967 net::test_server::ControllableHttpResponse response2(embedded_test_server(),
11968 "/main_document");
11969 ASSERT_TRUE(embedded_test_server()->Start());
11970
11971 GURL url_a(embedded_test_server()->GetURL("a.com", "/main_document"));
11972 GURL url_a_2(embedded_test_server()->GetURL("a.com", "/title1.html"));
11973 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
11974
11975 Shell* tab_to_be_bfcached = shell();
11976 Shell* tab_to_modify_cookie = CreateBrowser();
11977
11978 // 1) Load the document and specify no-store for the main resource.
11979 TestNavigationObserver observer(tab_to_be_bfcached->web_contents());
11980 tab_to_be_bfcached->LoadURL(url_a);
11981 RenderFrameHostImplWrapper rfh_a(current_frame_host());
11982 response.WaitForRequest();
11983 response.Send(kResponseWithNoCache);
11984 response.Done();
11985 observer.Wait();
11986
11987 // 2) Set a normal cookie from JavaScript.
11988 EXPECT_TRUE(ExecJs(tab_to_be_bfcached, "document.cookie='foo=bar'"));
11989 EXPECT_EQ("foo=bar", EvalJs(tab_to_be_bfcached, "document.cookie"));
11990
11991 // 3) Navigate away. |rfh_a| should enter bfcache.
11992 EXPECT_TRUE(NavigateToURL(tab_to_be_bfcached, url_b));
11993 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
11994
11995 // 4) Navigate to b.com in |tab_to_modify_cookie| and modify cookie from
11996 // JavaScript.
11997 EXPECT_TRUE(NavigateToURL(tab_to_modify_cookie, url_b));
11998 EXPECT_TRUE(ExecJs(tab_to_modify_cookie, "document.cookie='foo=baz'"));
11999 EXPECT_EQ("foo=baz", EvalJs(tab_to_modify_cookie, "document.cookie"));
12000
12001 // 5) Go back. |rfh_a| should be evicted upon restoration.
12002 TestNavigationObserver observer2(tab_to_be_bfcached->web_contents());
12003 tab_to_be_bfcached->web_contents()->GetController().GoBack();
12004 response2.WaitForRequest();
12005 response2.Send(kResponseWithNoCache);
12006 response2.Done();
12007 observer2.Wait();
12008 EXPECT_EQ("foo=bar", EvalJs(tab_to_be_bfcached, "document.cookie"));
12009
12010 ExpectNotRestored(
12011 {BackForwardCacheMetrics::NotRestoredReason::kCacheControlNoStore}, {},
12012 {}, {}, FROM_HERE);
12013}
12014
12015namespace {
12016const char kResponseWithNoCacheWithCookie[] =
12017 "HTTP/1.1 200 OK\r\n"
12018 "Content-Type: text/html; charset=utf-8\r\n"
12019 "Set-Cookie: foo=bar\r\n"
12020 "Cache-Control: no-store\r\n"
12021 "\r\n"
12022 "The server speaks HTTP!";
12023
12024const char kResponseWithNoCacheWithHTTPOnlyCookie[] =
12025 "HTTP/1.1 200 OK\r\n"
12026 "Content-Type: text/html; charset=utf-8\r\n"
12027 "Set-Cookie: foo=bar; Secure; HttpOnly;\r\n"
12028 "Cache-Control: no-store\r\n"
12029 "\r\n"
12030 "The server speaks HTTP!";
12031
12032const char kResponseWithNoCacheWithHTTPOnlyCookie2[] =
12033 "HTTP/1.1 200 OK\r\n"
12034 "Content-Type: text/html; charset=utf-8\r\n"
12035 "Set-Cookie: foo=baz; Secure; HttpOnly;\r\n"
12036 "Cache-Control: no-store\r\n"
12037 "\r\n"
12038 "The server speaks HTTP!";
12039} // namespace
12040
Christian Dullweber5c5a42a2021-07-15 09:16:1412041// Disabled due to flakiness on Cast Audio Linux https://crbug.com/1229182
12042#if BUILDFLAG(IS_CHROMECAST)
12043#define MAYBE_PagesWithCacheControlNoStoreSetFromResponseHeader \
12044 DISABLED_PagesWithCacheControlNoStoreSetFromResponseHeader
12045#else
12046#define MAYBE_PagesWithCacheControlNoStoreSetFromResponseHeader \
12047 PagesWithCacheControlNoStoreSetFromResponseHeader
12048#endif
12049
Yuzu Saijob50355932021-07-14 06:16:2712050// Test that a page with cache-control:no-store enters bfcache with the flag on,
12051// and if a cookie is modified while it is in bfcache via response header, gets
12052// evicted with cookie modified marked.
Christian Dullweber5c5a42a2021-07-15 09:16:1412053IN_PROC_BROWSER_TEST_F(
12054 BackForwardCacheBrowserTestAllowCacheControlNoStore,
12055 MAYBE_PagesWithCacheControlNoStoreSetFromResponseHeader) {
Yuzu Saijob50355932021-07-14 06:16:2712056 net::test_server::ControllableHttpResponse response(embedded_test_server(),
12057 "/main_document");
12058 net::test_server::ControllableHttpResponse response2(embedded_test_server(),
12059 "/main_document");
12060 ASSERT_TRUE(embedded_test_server()->Start());
12061
12062 GURL url_a(embedded_test_server()->GetURL("a.com", "/main_document"));
12063 GURL url_a_2(embedded_test_server()->GetURL("a.com", "/title1.html"));
12064 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
12065
12066 Shell* tab_to_be_bfcached = shell();
12067 Shell* tab_to_modify_cookie = CreateBrowser();
12068
12069 // 1) Load the document and specify no-store for the main resource.
12070 TestNavigationObserver observer(tab_to_be_bfcached->web_contents());
12071 tab_to_be_bfcached->LoadURL(url_a);
12072 RenderFrameHostImplWrapper rfh_a(current_frame_host());
12073 response.WaitForRequest();
12074 response.Send(kResponseWithNoCacheWithCookie);
12075 response.Done();
12076 observer.Wait();
12077 EXPECT_EQ("foo=bar", EvalJs(tab_to_be_bfcached, "document.cookie"));
12078
12079 // 2) Navigate away. |rfh_a| should enter bfcache.
12080 EXPECT_TRUE(NavigateToURL(tab_to_be_bfcached, url_b));
12081 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
12082
12083 // 3) Navigate to a.com in |tab_to_modify_cookie| and modify cookie from
12084 // JavaScript.
12085 EXPECT_TRUE(NavigateToURL(tab_to_modify_cookie, url_a_2));
12086 EXPECT_EQ("foo=bar", EvalJs(tab_to_modify_cookie, "document.cookie"));
12087 EXPECT_TRUE(ExecJs(tab_to_modify_cookie, "document.cookie='foo=baz'"));
12088 EXPECT_EQ("foo=baz", EvalJs(tab_to_modify_cookie, "document.cookie"));
12089
12090 // 4) Go back. |rfh_a| should be evicted upon restoration.
12091 TestNavigationObserver observer2(tab_to_be_bfcached->web_contents());
12092 tab_to_be_bfcached->web_contents()->GetController().GoBack();
12093 response2.WaitForRequest();
12094 // Send the response without the cookie header to avoid overwriting the
12095 // cookie.
12096 response2.Send(kResponseWithNoCache);
12097 response2.Done();
12098 observer2.Wait();
12099 EXPECT_EQ("foo=baz", EvalJs(tab_to_be_bfcached, "document.cookie"));
12100 ExpectNotRestored({BackForwardCacheMetrics::NotRestoredReason::
12101 kCacheControlNoStoreCookieModified},
12102 {}, {}, {}, FROM_HERE);
12103}
12104
Christian Dullweber5c5a42a2021-07-15 09:16:1412105// Disabled due to flakiness on Cast Audio Linux https://crbug.com/1229182
12106#if BUILDFLAG(IS_CHROMECAST)
12107#define MAYBE_PagesWithCacheControlNoStoreSetFromResponseHeaderHTTPOnlyCookie \
12108 DISABLED_PagesWithCacheControlNoStoreSetFromResponseHeaderHTTPOnlyCookie
12109#else
12110#define MAYBE_PagesWithCacheControlNoStoreSetFromResponseHeaderHTTPOnlyCookie \
12111 PagesWithCacheControlNoStoreSetFromResponseHeaderHTTPOnlyCookie
12112#endif
12113
Yuzu Saijob50355932021-07-14 06:16:2712114// Test that a page with cache-control:no-store enters bfcache with the flag on,
12115// and if HTTPOnly cookie is modified while it is in bfcache, gets evicted with
12116// HTTPOnly cookie modified marked.
12117IN_PROC_BROWSER_TEST_F(
12118 BackForwardCacheBrowserTestAllowCacheControlNoStore,
Christian Dullweber5c5a42a2021-07-15 09:16:1412119 MAYBE_PagesWithCacheControlNoStoreSetFromResponseHeaderHTTPOnlyCookie) {
Yuzu Saijob50355932021-07-14 06:16:2712120 // HTTPOnly cookie can be only set over HTTPS.
12121 CreateHttpsServer();
12122 net::test_server::ControllableHttpResponse response(https_server(),
12123 "/main_document");
12124 net::test_server::ControllableHttpResponse response2(https_server(),
12125 "/main_document2");
12126 net::test_server::ControllableHttpResponse response3(https_server(),
12127 "/main_document");
12128 ASSERT_TRUE(https_server()->Start());
12129
12130 GURL url_a(https_server()->GetURL("a.com", "/main_document"));
12131 GURL url_a_2(https_server()->GetURL("a.com", "/main_document2"));
12132 GURL url_b(https_server()->GetURL("b.com", "/title1.html"));
12133
12134 Shell* tab_to_be_bfcached = shell();
12135 Shell* tab_to_modify_cookie = CreateBrowser();
12136
12137 // 1) Load the document and specify no-store for the main resource.
12138 TestNavigationObserver observer(tab_to_be_bfcached->web_contents());
12139 tab_to_be_bfcached->LoadURL(url_a);
12140 RenderFrameHostImplWrapper rfh_a(current_frame_host());
12141 response.WaitForRequest();
12142 response.Send(kResponseWithNoCacheWithHTTPOnlyCookie);
12143 response.Done();
12144 observer.Wait();
12145 // HTTPOnly cookie should not be accessible from JavaScript.
12146 EXPECT_EQ("", EvalJs(tab_to_be_bfcached, "document.cookie"));
12147
12148 // 2) Navigate away. |rfh_a| should enter bfcache.
12149 EXPECT_TRUE(NavigateToURL(tab_to_be_bfcached, url_b));
12150 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
12151
12152 // 3) Navigate to a.com in |tab_to_modify_cookie| and modify HTTPOnly cookie
12153 // from the response.
12154 TestNavigationObserver observer2(tab_to_modify_cookie->web_contents());
12155 tab_to_modify_cookie->LoadURL(url_a_2);
12156 response2.WaitForRequest();
12157 response2.Send(kResponseWithNoCacheWithHTTPOnlyCookie2);
12158 response2.Done();
12159 observer2.Wait();
12160
12161 // 4) Go back. |rfh_a| should be evicted upon restoration.
12162 TestNavigationObserver observer3(tab_to_be_bfcached->web_contents());
12163 tab_to_be_bfcached->web_contents()->GetController().GoBack();
12164 response3.WaitForRequest();
12165 response3.Send(kResponseWithNoCacheWithHTTPOnlyCookie);
12166 response3.Done();
12167 observer3.Wait();
12168 ExpectNotRestored({BackForwardCacheMetrics::NotRestoredReason::
12169 kCacheControlNoStoreHTTPOnlyCookieModified},
12170 {}, {}, {}, FROM_HERE);
12171}
12172
Christian Dullweber5c5a42a2021-07-15 09:16:1412173// Disabled due to flakiness on Cast Audio Linux https://crbug.com/1229182
12174#if BUILDFLAG(IS_CHROMECAST)
12175#define MAYBE_PagesWithCacheControlNoStoreHTTPOnlyCookieModifiedBackTwice \
12176 DISABLED_PagesWithCacheControlNoStoreHTTPOnlyCookieModifiedBackTwice
12177#else
12178#define MAYBE_PagesWithCacheControlNoStoreHTTPOnlyCookieModifiedBackTwice \
12179 PagesWithCacheControlNoStoreHTTPOnlyCookieModifiedBackTwice
12180#endif
12181
Yuzu Saijob50355932021-07-14 06:16:2712182// Test that a page with cache-control:no-store enters bfcache with the flag on,
12183// and if a HTTPOnly cookie is modified, it gets evicted with cookie changed,
12184// but if navigated away again and navigated back, it gets evicted without
12185// HTTPOnly cookie change marked.
12186IN_PROC_BROWSER_TEST_F(
12187 BackForwardCacheBrowserTestAllowCacheControlNoStore,
Christian Dullweber5c5a42a2021-07-15 09:16:1412188 MAYBE_PagesWithCacheControlNoStoreHTTPOnlyCookieModifiedBackTwice) {
Yuzu Saijob50355932021-07-14 06:16:2712189 CreateHttpsServer();
12190 net::test_server::ControllableHttpResponse response(https_server(),
12191 "/main_document");
12192 net::test_server::ControllableHttpResponse response2(https_server(),
12193 "/main_document2");
12194 net::test_server::ControllableHttpResponse response3(https_server(),
12195 "/main_document");
12196 net::test_server::ControllableHttpResponse response4(https_server(),
12197 "/main_document");
12198 ASSERT_TRUE(https_server()->Start());
12199
12200 GURL url_a(https_server()->GetURL("a.com", "/main_document"));
12201 GURL url_a_2(https_server()->GetURL("a.com", "/main_document2"));
12202 GURL url_b(https_server()->GetURL("b.com", "/title1.html"));
12203
12204 Shell* tab_to_be_bfcached = shell();
12205 Shell* tab_to_modify_cookie = CreateBrowser();
12206
12207 // 1) Load the document and specify no-store for the main resource.
12208 TestNavigationObserver observer(tab_to_be_bfcached->web_contents());
12209 tab_to_be_bfcached->LoadURL(url_a);
12210 RenderFrameHostImplWrapper rfh_a(current_frame_host());
12211 response.WaitForRequest();
12212 response.Send(kResponseWithNoCacheWithHTTPOnlyCookie);
12213 response.Done();
12214 observer.Wait();
12215
12216 // 2) Navigate away. |rfh_a| should enter bfcache.
12217 EXPECT_TRUE(NavigateToURL(tab_to_be_bfcached, url_b));
12218 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
12219
12220 // 3) Navigate to a.com in |tab_to_modify_cookie| and modify cookie from
12221 // response header.
12222 TestNavigationObserver observer2(tab_to_modify_cookie->web_contents());
12223 tab_to_modify_cookie->LoadURL(url_a_2);
12224 response2.WaitForRequest();
12225 response2.Send(kResponseWithNoCacheWithHTTPOnlyCookie2);
12226 response2.Done();
12227 observer2.Wait();
12228
12229 // 4) Go back. |rfh_a| should be evicted upon restoration.
12230 TestNavigationObserver observer3(tab_to_be_bfcached->web_contents());
12231 tab_to_be_bfcached->web_contents()->GetController().GoBack();
12232 response3.WaitForRequest();
12233 response3.Send(kResponseWithNoCache);
12234 response3.Done();
12235 observer3.Wait();
12236
12237 ExpectNotRestored({BackForwardCacheMetrics::NotRestoredReason::
12238 kCacheControlNoStoreHTTPOnlyCookieModified},
12239 {}, {}, {}, FROM_HERE);
12240 RenderFrameHostImplWrapper rfh_a_2(current_frame_host());
12241
12242 // 5) Navigate away to b.com. |rfh_a_2| should enter bfcache again.
12243 EXPECT_TRUE(NavigateToURL(tab_to_be_bfcached, url_b));
12244 EXPECT_TRUE(rfh_a_2->IsInBackForwardCache());
12245
12246 // 6) Navigate back to a.com. This time the cookie change has to be reset and
12247 // gets evicted with a different reason.
12248 TestNavigationObserver observer4(tab_to_be_bfcached->web_contents());
12249 tab_to_be_bfcached->web_contents()->GetController().GoBack();
12250 response4.WaitForRequest();
12251 response4.Send(kResponseWithNoCache);
12252 response4.Done();
12253 observer4.Wait();
12254 ExpectNotRestored(
12255 {BackForwardCacheMetrics::NotRestoredReason::kCacheControlNoStore}, {},
12256 {}, {}, FROM_HERE);
12257}
12258
Yuzu Saijod231b622021-07-14 11:19:4112259class BackForwardCacheBrowserTestRestoreCacheControlNoStoreUnlessCookieChange
12260 : public BackForwardCacheBrowserTest {
12261 protected:
12262 void SetUpCommandLine(base::CommandLine* command_line) override {
12263 EnableFeatureAndSetParams(features::kBackForwardCache, "", "");
Yuzu Saijoc4d269cc2021-07-15 07:32:2412264 EnableFeatureAndSetParams(kCacheControlNoStoreEnterBackForwardCache, "",
12265 "");
Yuzu Saijod231b622021-07-14 11:19:4112266 EnableFeatureAndSetParams(
12267 kCacheControlNoStoreRestoreFromBackForwardCacheUnlessCookieChange, "",
12268 "");
12269 BackForwardCacheBrowserTest::SetUpCommandLine(command_line);
12270 }
12271};
12272
Lingqi Chi6748cd592021-07-22 03:48:4412273// TODO(https://crbug.com/1231849): flaky on Cast Linux.
12274#if defined(OS_LINUX)
12275#define MAYBE_PagesWithCacheControlNoStoreRestoreFromBackForwardCache \
12276 DISABLED_PagesWithCacheControlNoStoreRestoreFromBackForwardCache
12277#else
12278#define MAYBE_PagesWithCacheControlNoStoreRestoreFromBackForwardCache \
12279 PagesWithCacheControlNoStoreRestoreFromBackForwardCache
12280#endif
12281
Yuzu Saijod231b622021-07-14 11:19:4112282// Test that a page with cache-control:no-store enters bfcache with the flag on,
12283// and gets restored if cookies do not change.
12284IN_PROC_BROWSER_TEST_F(
12285 BackForwardCacheBrowserTestRestoreCacheControlNoStoreUnlessCookieChange,
Lingqi Chi6748cd592021-07-22 03:48:4412286 MAYBE_PagesWithCacheControlNoStoreRestoreFromBackForwardCache) {
Yuzu Saijod231b622021-07-14 11:19:4112287 net::test_server::ControllableHttpResponse response(embedded_test_server(),
12288 "/main_document");
12289 net::test_server::ControllableHttpResponse response2(embedded_test_server(),
12290 "/main_document");
12291 ASSERT_TRUE(embedded_test_server()->Start());
12292
12293 GURL url_a(embedded_test_server()->GetURL("a.com", "/main_document"));
12294 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
12295
12296 // 1) Load the document and specify no-store for the main resource.
12297 TestNavigationObserver observer(web_contents());
12298 shell()->LoadURL(url_a);
12299 RenderFrameHostImplWrapper rfh_a(current_frame_host());
12300 response.WaitForRequest();
12301 response.Send(kResponseWithNoCache);
12302 response.Done();
12303 observer.Wait();
12304
12305 // 2) Navigate away. |rfh_a| should enter the bfcache.
12306 EXPECT_TRUE(NavigateToURL(shell(), url_b));
12307 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
12308
12309 // 3) Go back. |rfh_a| should be restored.
12310 web_contents()->GetController().GoBack();
12311 EXPECT_TRUE(WaitForLoadStop(web_contents()));
12312 ExpectRestored(FROM_HERE);
12313}
12314
Sergey Poromova8e40dba2021-07-16 10:23:4612315// Flaky on Cast: crbug.com/1229182
12316#if BUILDFLAG(IS_CHROMECAST)
12317#define MAYBE_PagesWithCacheControlNoStoreEvictedIfCookieChange \
12318 DISABLED_PagesWithCacheControlNoStoreEvictedIfCookieChange
12319#else
12320#define MAYBE_PagesWithCacheControlNoStoreEvictedIfCookieChange \
12321 PagesWithCacheControlNoStoreEvictedIfCookieChange
12322#endif
Yuzu Saijod231b622021-07-14 11:19:4112323// Test that a page with cache-control:no-store enters bfcache with the flag on,
12324// but gets evicted if cookies change.
12325IN_PROC_BROWSER_TEST_F(
12326 BackForwardCacheBrowserTestRestoreCacheControlNoStoreUnlessCookieChange,
Sergey Poromova8e40dba2021-07-16 10:23:4612327 MAYBE_PagesWithCacheControlNoStoreEvictedIfCookieChange) {
Yuzu Saijod231b622021-07-14 11:19:4112328 net::test_server::ControllableHttpResponse response(embedded_test_server(),
12329 "/main_document");
12330 net::test_server::ControllableHttpResponse response2(embedded_test_server(),
12331 "/main_document");
12332 ASSERT_TRUE(embedded_test_server()->Start());
12333
12334 GURL url_a(embedded_test_server()->GetURL("a.com", "/main_document"));
12335 GURL url_a_2(embedded_test_server()->GetURL("a.com", "/title1.html"));
12336 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
12337
12338 Shell* tab_to_be_bfcached = shell();
12339 Shell* tab_to_modify_cookie = CreateBrowser();
12340
12341 // 1) Load the document and specify no-store for the main resource.
12342 TestNavigationObserver observer(tab_to_be_bfcached->web_contents());
12343 tab_to_be_bfcached->LoadURL(url_a);
12344 RenderFrameHostImplWrapper rfh_a(current_frame_host());
12345 response.WaitForRequest();
12346 response.Send(kResponseWithNoCache);
12347 response.Done();
12348 observer.Wait();
12349
12350 // 2) Set a normal cookie from JavaScript.
12351 EXPECT_TRUE(ExecJs(tab_to_be_bfcached, "document.cookie='foo=bar'"));
12352 EXPECT_EQ("foo=bar", EvalJs(tab_to_be_bfcached, "document.cookie"));
12353
12354 // 3) Navigate away. |rfh_a| should enter bfcache.
12355 EXPECT_TRUE(NavigateToURL(tab_to_be_bfcached, url_b));
12356 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
12357
12358 // 4) Navigate to a.com in |tab_to_modify_cookie| and modify cookie from
12359 // JavaScript.
12360 EXPECT_TRUE(NavigateToURL(tab_to_modify_cookie, url_a_2));
12361 EXPECT_EQ("foo=bar", EvalJs(tab_to_modify_cookie, "document.cookie"));
12362 EXPECT_TRUE(ExecJs(tab_to_modify_cookie, "document.cookie='foo=baz'"));
12363 EXPECT_EQ("foo=baz", EvalJs(tab_to_modify_cookie, "document.cookie"));
12364
12365 // 5) Go back. |rfh_a| should be evicted upon restoration.
12366 TestNavigationObserver observer2(tab_to_be_bfcached->web_contents());
12367 tab_to_be_bfcached->web_contents()->GetController().GoBack();
12368 response2.WaitForRequest();
12369 response2.Send(kResponseWithNoCache);
12370 response2.Done();
12371 observer2.Wait();
12372
12373 EXPECT_EQ("foo=baz", EvalJs(tab_to_be_bfcached, "document.cookie"));
12374 ExpectNotRestored({BackForwardCacheMetrics::NotRestoredReason::
12375 kCacheControlNoStoreCookieModified},
12376 {}, {}, {}, FROM_HERE);
12377}
12378
Adithya Srinivasan7fe5ce662021-06-04 21:36:0412379namespace {
12380enum class SubframeType { SameSite, CrossSite };
12381}
12382
12383class BackForwardCacheEvictionDueToSubframeNavigationBrowserTest
12384 : public BackForwardCacheBrowserTest,
12385 public ::testing::WithParamInterface<SubframeType> {
12386 public:
12387 // Provides meaningful param names instead of /0 and /1.
12388 static std::string DescribeParams(
12389 const ::testing::TestParamInfo<ParamType>& info) {
12390 switch (info.param) {
12391 case SubframeType::SameSite:
12392 return "SameSite";
12393 case SubframeType::CrossSite:
12394 return "CrossSite";
12395 }
12396 }
12397};
12398
12399IN_PROC_BROWSER_TEST_P(
12400 BackForwardCacheEvictionDueToSubframeNavigationBrowserTest,
12401 SubframePendingCommitShouldPreventCache) {
12402 ASSERT_TRUE(embedded_test_server()->Start());
12403 GURL a_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
12404 bool use_cross_origin_subframe = GetParam() == SubframeType::CrossSite;
12405 GURL subframe_url = embedded_test_server()->GetURL(
12406 use_cross_origin_subframe ? "b.com" : "a.com", "/title1.html");
12407
12408 IsolateOriginsForTesting(embedded_test_server(), web_contents(),
12409 {"a.com", "b.com"});
12410
12411 // 1) Navigate to a.com.
12412 EXPECT_TRUE(NavigateToURL(shell(), a_url));
12413 RenderFrameHostImpl* main_frame = current_frame_host();
12414
12415 // 2) Add subframe and wait for empty document to commit.
12416 CreateSubframe(web_contents(), "child", GURL(""), true);
12417
12418 CommitMessageDelayer commit_message_delayer(
12419 web_contents(), subframe_url,
12420 base::BindLambdaForTesting([&](RenderFrameHost*) {
12421 // 5) Test that page cannot be stored in bfcache when subframe is
12422 // pending commit.
12423 BackForwardCacheCanStoreDocumentResult can_store_result =
12424 web_contents()
12425 ->GetController()
12426 .GetBackForwardCache()
12427 .CanStorePageNow(static_cast<RenderFrameHostImpl*>(main_frame));
12428 EXPECT_TRUE(can_store_result.HasNotStoredReason(
12429 BackForwardCacheMetrics::NotRestoredReason::kSubframeIsNavigating));
12430 }));
12431
12432 // 3) Start navigation in subframe to |subframe_url|.
12433 EXPECT_TRUE(ExecJs(
12434 main_frame,
12435 JsReplace("document.querySelector('#child').src = $1;", subframe_url)));
12436 // 4) Wait until subframe navigation is pending commit.
12437 commit_message_delayer.Wait();
12438}
12439
12440INSTANTIATE_TEST_SUITE_P(
12441 All,
12442 BackForwardCacheEvictionDueToSubframeNavigationBrowserTest,
12443 ::testing::Values(SubframeType::SameSite, SubframeType::CrossSite),
12444 &BackForwardCacheEvictionDueToSubframeNavigationBrowserTest::
12445 DescribeParams);
12446
Khushalc5eaf222021-06-30 20:15:4812447// Tests that a back navigation from a crashed page has the process state
12448// tracked correctly by WebContentsImpl.
12449IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
12450 BackNavigationFromCrashedPage) {
12451 ASSERT_TRUE(embedded_test_server()->Start());
12452 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
12453 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
12454 url::Origin origin_a = url::Origin::Create(url_a);
12455 url::Origin origin_b = url::Origin::Create(url_b);
12456
12457 // 1) Navigate to A.
12458 EXPECT_TRUE(NavigateToURL(shell(), url_a));
12459 RenderFrameHostImpl* rfh_a = current_frame_host();
12460 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
12461 EXPECT_FALSE(web_contents()->IsCrashed());
12462
12463 // 2) Navigate to B.
12464 EXPECT_TRUE(NavigateToURL(shell(), url_b));
12465 RenderFrameHostImpl* rfh_b = current_frame_host();
12466 RenderFrameDeletedObserver delete_observer_rfh_b(rfh_b);
12467 EXPECT_FALSE(delete_observer_rfh_a.deleted());
12468 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
12469 EXPECT_EQ(rfh_a->GetVisibilityState(), PageVisibilityState::kHidden);
12470 EXPECT_EQ(origin_a, rfh_a->GetLastCommittedOrigin());
12471 EXPECT_EQ(origin_b, rfh_b->GetLastCommittedOrigin());
12472 EXPECT_FALSE(rfh_b->IsInBackForwardCache());
12473 EXPECT_EQ(rfh_b->GetVisibilityState(), PageVisibilityState::kVisible);
12474 EXPECT_FALSE(web_contents()->IsCrashed());
12475
12476 // 3) Crash B.
12477 CrashTab(web_contents());
12478 EXPECT_TRUE(web_contents()->IsCrashed());
12479 EXPECT_TRUE(delete_observer_rfh_b.deleted());
12480
12481 // 4) Go back to A.
12482 web_contents()->GetController().GoBack();
12483 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
12484
12485 EXPECT_FALSE(delete_observer_rfh_a.deleted());
12486 EXPECT_EQ(origin_a, rfh_a->GetLastCommittedOrigin());
12487 EXPECT_EQ(rfh_a, current_frame_host());
12488 EXPECT_FALSE(rfh_a->IsInBackForwardCache());
12489 EXPECT_EQ(rfh_a->GetVisibilityState(), PageVisibilityState::kVisible);
12490 EXPECT_FALSE(web_contents()->IsCrashed());
12491
12492 ExpectRestored(FROM_HERE);
12493}
12494
Arthur Sonzogni620cec62018-12-13 13:08:5712495} // namespace content