Avi Drissman | 4e1b7bc3 | 2022-09-15 14:03:50 | [diff] [blame] | 1 | // Copyright 2018 The Chromium Authors |
Arthur Sonzogni | 620cec6 | 2018-12-13 13:08:57 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
Fergal Daly | f5a50ab | 2021-11-09 05:36:18 | [diff] [blame] | 5 | #include "content/browser/back_forward_cache_browsertest.h" |
| 6 | |
Fergal Daly | a7dcc35 | 2022-10-19 03:43:18 | [diff] [blame] | 7 | #include <climits> |
Arthur Sonzogni | c686e8f | 2024-01-11 08:36:37 | [diff] [blame] | 8 | #include <optional> |
Md Hasibul Hasan | a963a934 | 2024-04-03 10:15:14 | [diff] [blame] | 9 | #include <string_view> |
Ken Rockot | 05499cf | 2019-12-12 05:22:54 | [diff] [blame] | 10 | #include <unordered_map> |
| 11 | |
Arthur Sonzogni | 620cec6 | 2018-12-13 13:08:57 | [diff] [blame] | 12 | #include "base/command_line.h" |
Peter Kasting | 837e2ccb | 2022-09-07 14:13:17 | [diff] [blame] | 13 | #include "base/containers/contains.h" |
Avi Drissman | adac2199 | 2023-01-11 23:46:39 | [diff] [blame] | 14 | #include "base/functional/callback_helpers.h" |
Alexander Timin | 44ccede | 2020-01-23 09:00:34 | [diff] [blame] | 15 | #include "base/location.h" |
Keishi Hattori | 0e45c02 | 2021-11-27 09:25:52 | [diff] [blame] | 16 | #include "base/memory/raw_ptr.h" |
Fergal Daly | 5bc3a54 | 2023-03-10 06:12:16 | [diff] [blame] | 17 | #include "base/metrics/metrics_hashes.h" |
Carlos Caballero | 8b114db | 2020-08-13 08:57:03 | [diff] [blame] | 18 | #include "base/run_loop.h" |
Lei Zhang | 0a85e65a | 2025-05-23 19:22:06 | [diff] [blame] | 19 | #include "base/strings/string_number_conversions.h" |
[email protected] | 54eaf62 | 2019-11-25 12:36:03 | [diff] [blame] | 20 | #include "base/system/sys_info.h" |
Harkiran Bolaria | 875dd0d | 2020-09-15 18:10:46 | [diff] [blame] | 21 | #include "base/task/common/task_annotator.h" |
Sean Maher | 5b9af51f | 2022-11-21 15:32:47 | [diff] [blame] | 22 | #include "base/task/single_thread_task_runner.h" |
Guido Urdaneta | ef4e9194 | 2020-11-09 15:06:24 | [diff] [blame] | 23 | #include "base/test/bind.h" |
Ming-Ying Chung | a8e8a2e | 2022-08-16 06:04:50 | [diff] [blame] | 24 | #include "base/test/metrics/histogram_tester.h" |
Harkiran Bolaria | 12818bc | 2020-11-03 22:44:27 | [diff] [blame] | 25 | #include "base/test/test_timeouts.h" |
Carlos Caballero | 8b114db | 2020-08-13 08:57:03 | [diff] [blame] | 26 | #include "base/threading/thread_restrictions.h" |
arthursonzogni | 9cd87534 | 2019-09-04 14:53:46 | [diff] [blame] | 27 | #include "base/time/time.h" |
Carlos Caballero | 8b114db | 2020-08-13 08:57:03 | [diff] [blame] | 28 | #include "base/trace_event/trace_log.h" |
Rakina Zata Amni | 06343cc | 2019-10-11 01:33:23 | [diff] [blame] | 29 | #include "build/build_config.h" |
Christian Dullweber | 5c5a42a | 2021-07-15 09:16:14 | [diff] [blame] | 30 | #include "build/chromecast_buildflags.h" |
Ming-Ying Chung | a8e8a2e | 2022-08-16 06:04:50 | [diff] [blame] | 31 | #include "components/ukm/test_ukm_recorder.h" |
Carlos Caballero | 8b114db | 2020-08-13 08:57:03 | [diff] [blame] | 32 | #include "content/browser/bad_message.h" |
Adithya Srinivasan | 7fe5ce66 | 2021-06-04 21:36:04 | [diff] [blame] | 33 | #include "content/browser/renderer_host/back_forward_cache_can_store_document_result.h" |
Mingyu Lei | 8c1b911 | 2023-01-18 03:59:01 | [diff] [blame] | 34 | #include "content/browser/renderer_host/back_forward_cache_disable.h" |
danakj | 10f3237 | 2020-09-15 22:25:16 | [diff] [blame] | 35 | #include "content/browser/renderer_host/back_forward_cache_impl.h" |
| 36 | #include "content/browser/renderer_host/frame_tree_node.h" |
Mingyu Lei | 8c1b911 | 2023-01-18 03:59:01 | [diff] [blame] | 37 | #include "content/browser/renderer_host/render_frame_host_impl.h" |
Hajime Hoshi | 8fd675e0 | 2020-10-29 14:28:41 | [diff] [blame] | 38 | #include "content/browser/renderer_host/should_swap_browsing_instance.h" |
Arthur Sonzogni | 620cec6 | 2018-12-13 13:08:57 | [diff] [blame] | 39 | #include "content/browser/web_contents/web_contents_impl.h" |
[email protected] | ee8ae33 | 2020-01-29 03:49:45 | [diff] [blame] | 40 | #include "content/common/content_navigation_policy.h" |
Arthur Sonzogni | bdeca8e | 2023-09-11 08:32:12 | [diff] [blame] | 41 | #include "content/common/features.h" |
Carlos Caballero | b6b46648 | 2019-11-29 13:33:18 | [diff] [blame] | 42 | #include "content/public/browser/back_forward_cache.h" |
Daniel Cheng | 9fb887ff | 2021-10-01 20:27:38 | [diff] [blame] | 43 | #include "content/public/browser/document_service.h" |
Carlos Caballero | b6b46648 | 2019-11-29 13:33:18 | [diff] [blame] | 44 | #include "content/public/browser/global_routing_id.h" |
Carlos Caballero | 91fffb2 | 2019-10-29 15:24:30 | [diff] [blame] | 45 | #include "content/public/browser/web_contents.h" |
Arthur Sonzogni | 620cec6 | 2018-12-13 13:08:57 | [diff] [blame] | 46 | #include "content/public/common/content_features.h" |
Kouhei Ueno | 01b0f119 | 2019-08-14 05:28:07 | [diff] [blame] | 47 | #include "content/public/common/content_switches.h" |
Khushal | c5eaf22 | 2021-06-30 20:15:48 | [diff] [blame] | 48 | #include "content/public/common/result_codes.h" |
arthursonzogni | bec3127 | 2019-10-09 11:51:21 | [diff] [blame] | 49 | #include "content/public/test/back_forward_cache_util.h" |
Peter Kasting | 919ce65 | 2020-05-07 10:22:36 | [diff] [blame] | 50 | #include "content/public/test/browser_test.h" |
Arthur Sonzogni | 620cec6 | 2018-12-13 13:08:57 | [diff] [blame] | 51 | #include "content/public/test/browser_test_utils.h" |
Adithya Srinivasan | 7fe5ce66 | 2021-06-04 21:36:04 | [diff] [blame] | 52 | #include "content/public/test/commit_message_delayer.h" |
Arthur Sonzogni | 620cec6 | 2018-12-13 13:08:57 | [diff] [blame] | 53 | #include "content/public/test/content_browser_test_utils.h" |
Gyuyoung Kim | 940115f | 2021-11-05 02:25:35 | [diff] [blame] | 54 | #include "content/public/test/fenced_frame_test_util.h" |
Mohamed Abdelhalim | 462fff3 | 2019-08-13 14:13:42 | [diff] [blame] | 55 | #include "content/public/test/navigation_handle_observer.h" |
Hajime Hoshi | e9262d3 | 2019-08-28 07:40:23 | [diff] [blame] | 56 | #include "content/public/test/test_navigation_observer.h" |
Lowell Manners | 889189f | 2019-08-22 16:47:45 | [diff] [blame] | 57 | #include "content/public/test/test_navigation_throttle.h" |
| 58 | #include "content/public/test/test_navigation_throttle_inserter.h" |
Arthur Sonzogni | 620cec6 | 2018-12-13 13:08:57 | [diff] [blame] | 59 | #include "content/public/test/test_utils.h" |
Rakina Zata Amni | efcc293 | 2020-08-28 07:24:37 | [diff] [blame] | 60 | #include "content/public/test/text_input_test_utils.h" |
Fergal Daly | 7a05b426 | 2022-03-15 09:18:40 | [diff] [blame] | 61 | #include "content/public/test/url_loader_interceptor.h" |
Mustapha Jaber | 53892cc | 2024-01-05 01:13:33 | [diff] [blame] | 62 | #include "content/public/test/web_contents_observer_test_utils.h" |
Arthur Sonzogni | 620cec6 | 2018-12-13 13:08:57 | [diff] [blame] | 63 | #include "content/shell/browser/shell.h" |
Fergal Daly | 7991d936 | 2019-12-20 02:28:25 | [diff] [blame] | 64 | #include "content/shell/browser/shell_javascript_dialog_manager.h" |
Fergal Daly | 306fc3f | 2021-12-23 09:58:30 | [diff] [blame] | 65 | #include "content/test/content_browser_test_utils_internal.h" |
Hajime Hoshi | 925793e7 | 2019-11-26 07:58:55 | [diff] [blame] | 66 | #include "media/base/media_switches.h" |
Carlos Caballero | 8b114db | 2020-08-13 08:57:03 | [diff] [blame] | 67 | #include "mojo/public/cpp/bindings/message.h" |
| 68 | #include "mojo/public/cpp/bindings/pending_remote.h" |
| 69 | #include "mojo/public/cpp/bindings/remote.h" |
arthursonzogni | e385b7b | 2019-09-02 11:11:53 | [diff] [blame] | 70 | #include "net/base/filename_util.h" |
Arthur Sonzogni | 620cec6 | 2018-12-13 13:08:57 | [diff] [blame] | 71 | #include "net/dns/mock_host_resolver.h" |
Lowell Manners | b3b30c2 | 2019-07-26 11:31:41 | [diff] [blame] | 72 | #include "net/test/embedded_test_server/controllable_http_response.h" |
Arthur Sonzogni | 620cec6 | 2018-12-13 13:08:57 | [diff] [blame] | 73 | #include "net/test/embedded_test_server/embedded_test_server.h" |
Matt Menke | 7c824a7 | 2025-06-26 13:43:20 | [diff] [blame] | 74 | #include "net/test/embedded_test_server/install_default_websocket_handlers.h" |
Mingyu Lei | 8c1b911 | 2023-01-18 03:59:01 | [diff] [blame] | 75 | #include "services/metrics/public/cpp/ukm_recorder.h" |
| 76 | #include "services/metrics/public/cpp/ukm_source_id.h" |
Sandor Major | a9a29ad5 | 2025-02-20 16:00:14 | [diff] [blame] | 77 | #include "services/network/public/cpp/features.h" |
Yuzu Saijo | b0f001b2 | 2020-04-08 04:07:04 | [diff] [blame] | 78 | #include "services/service_manager/public/cpp/interface_provider.h" |
Sreeja Kamishetty | 92006e0 | 2021-02-05 05:18:11 | [diff] [blame] | 79 | #include "third_party/blink/public/common/device_memory/approximated_device_memory.h" |
Harkiran Bolaria | 875dd0d | 2020-09-15 18:10:46 | [diff] [blame] | 80 | #include "third_party/blink/public/common/features.h" |
Kurumi Muto | 863fd9a | 2024-02-06 11:51:32 | [diff] [blame] | 81 | #include "third_party/blink/public/common/features_generated.h" |
Lowell Manners | 5cd4de4 | 2019-06-13 11:12:22 | [diff] [blame] | 82 | #include "third_party/blink/public/common/scheduler/web_scheduler_tracked_feature.h" |
Stephen Chenney | 91a186b | 2021-03-23 10:42:01 | [diff] [blame] | 83 | #include "third_party/blink/public/common/switches.h" |
Kurumi Muto | 0cf1280 | 2024-02-21 08:36:42 | [diff] [blame] | 84 | #include "third_party/blink/public/mojom/back_forward_cache_not_restored_reasons.mojom.h" |
| 85 | #include "third_party/blink/public/mojom/frame/back_forward_cache_controller.mojom.h" |
Fergal Daly | 5bc3a54 | 2023-03-10 06:12:16 | [diff] [blame] | 86 | #include "third_party/blink/public/mojom/frame/frame.mojom.h" |
Chris Harrelson | d2fe06ad | 2022-07-11 21:36:23 | [diff] [blame] | 87 | #include "third_party/blink/public/mojom/render_accessibility.mojom.h" |
Kurumi Muto | 0cf1280 | 2024-02-21 08:36:42 | [diff] [blame] | 88 | #include "third_party/blink/public/mojom/script_source_location.mojom.h" |
Fergal Daly | f5a50ab | 2021-11-09 05:36:18 | [diff] [blame] | 89 | |
| 90 | // This file has too many tests. |
| 91 | // |
| 92 | // Before adding new tests to this file, consider if they will fit better into |
| 93 | // one of the other back_forward_cache_*_browsertest.cc files or if there are |
| 94 | // enough new tests to justify a new file. |
arthursonzogni | 2f84dd6 | 2019-06-05 09:47:12 | [diff] [blame] | 95 | |
Rakina Zata Amni | c7bc8263 | 2019-12-09 05:21:22 | [diff] [blame] | 96 | using testing::_; |
arthursonzogni | 2f84dd6 | 2019-06-05 09:47:12 | [diff] [blame] | 97 | using testing::Each; |
Hajime Hoshi | f9eba2b | 2019-10-02 08:27:42 | [diff] [blame] | 98 | using testing::ElementsAre; |
arthursonzogni | 2f84dd6 | 2019-06-05 09:47:12 | [diff] [blame] | 99 | using testing::Not; |
Hajime Hoshi | 5e86bc8 | 2019-11-26 05:41:12 | [diff] [blame] | 100 | using testing::UnorderedElementsAreArray; |
Arthur Sonzogni | 620cec6 | 2018-12-13 13:08:57 | [diff] [blame] | 101 | |
| 102 | namespace content { |
| 103 | |
Yuzu Saijo | dcabe56 | 2022-04-25 06:06:39 | [diff] [blame] | 104 | using NotRestoredReasons = |
| 105 | BackForwardCacheCanStoreDocumentResult::NotRestoredReasons; |
Riho Isawa | b1efe68f | 2021-12-20 01:54:07 | [diff] [blame] | 106 | using NotRestoredReason = BackForwardCacheMetrics::NotRestoredReason; |
| 107 | |
Fergal Daly | 2c7bc405 | 2021-12-23 14:42:22 | [diff] [blame] | 108 | EvalJsResult GetLocalStorage(RenderFrameHostImpl* rfh, std::string key) { |
| 109 | return EvalJs(rfh, JsReplace("localStorage.getItem($1)", key)); |
| 110 | } |
| 111 | |
Fergal Daly | 91e6288 | 2023-10-30 08:26:42 | [diff] [blame] | 112 | [[nodiscard]] bool WaitForLocalStorage(RenderFrameHostImpl* rfh, |
| 113 | std::string key, |
| 114 | std::string expected_value) { |
| 115 | auto value = EvalJs(rfh, JsReplace(R"( |
| 116 | new Promise((resolve) => { |
| 117 | let key = $1; |
| 118 | let expected_value = $2; |
| 119 | if (localStorage.getItem(key) == expected_value) { |
| 120 | resolve(localStorage.getItem(key)); |
| 121 | return; |
| 122 | } |
| 123 | let listener = window.addEventListener("storage", e => { |
| 124 | if (e.storageArea == localStorage && e.key == key |
| 125 | && e.newValue == expected_value) { |
| 126 | resolve(localStorage.getItem(key)); |
| 127 | removeEventListener("storage", listener); |
| 128 | return; |
| 129 | } |
| 130 | }); |
| 131 | }); |
| 132 | )", |
| 133 | key, expected_value)); |
| 134 | return value == expected_value; |
| 135 | } |
| 136 | |
Fergal Daly | f5a50ab | 2021-11-09 05:36:18 | [diff] [blame] | 137 | BackForwardCacheBrowserTest::BackForwardCacheBrowserTest() = default; |
| 138 | |
| 139 | BackForwardCacheBrowserTest::~BackForwardCacheBrowserTest() { |
| 140 | if (fail_for_unexpected_messages_while_cached_) { |
| 141 | // If this is triggered, see MojoInterfaceName in |
Kurumi Muto | 03d7175 | 2024-02-22 04:55:53 | [diff] [blame] | 142 | // tools/metrics/histograms/metadata/navigation/enums.xml for which values |
| 143 | // correspond which messages. |
Fergal Daly | 5bc3a54 | 2023-03-10 06:12:16 | [diff] [blame] | 144 | std::vector<base::Bucket> samples = histogram_tester().GetAllSamples( |
| 145 | "BackForwardCache.UnexpectedRendererToBrowserMessage." |
| 146 | "InterfaceName"); |
Alison Gale | 770f3fc | 2024-04-27 00:39:58 | [diff] [blame] | 147 | // TODO(crbug.com/40244391): Remove this. |
Fergal Daly | 5bc3a54 | 2023-03-10 06:12:16 | [diff] [blame] | 148 | // This bucket corresponds to the LocalFrameHost interface. It is known to |
| 149 | // be flaky due calls to `LocalFrameHost::DidFocusFrame()` after entering |
| 150 | // BFCache. So we ignore it for now by removing it if it's present until we |
| 151 | // can fix the root cause. |
Alison Gale | 81f4f2c7 | 2024-04-22 19:33:31 | [diff] [blame] | 152 | // TODO(crbug.com/40925798): Remove this. |
Fergal Daly | 70e679b0c | 2023-09-21 03:58:56 | [diff] [blame] | 153 | // As above but `LocalMainFrameHost::DidFirstVisuallyNonEmptyPaint()`. |
Fergal Daly | 5bc3a54 | 2023-03-10 06:12:16 | [diff] [blame] | 154 | std::erase_if(samples, [](base::Bucket bucket) { |
| 155 | return bucket.min == |
Ramon Cano Aparicio | 6797d4e | 2025-01-10 16:09:02 | [diff] [blame] | 156 | static_cast<base::HistogramBase::Sample32>(base::HashMetricName( |
Fergal Daly | 70e679b0c | 2023-09-21 03:58:56 | [diff] [blame] | 157 | blink::mojom::LocalFrameHost::Name_)) || |
| 158 | bucket.min == |
Ramon Cano Aparicio | 6797d4e | 2025-01-10 16:09:02 | [diff] [blame] | 159 | static_cast<base::HistogramBase::Sample32>(base::HashMetricName( |
Fergal Daly | 70e679b0c | 2023-09-21 03:58:56 | [diff] [blame] | 160 | blink::mojom::LocalMainFrameHost::Name_)); |
Fergal Daly | 5bc3a54 | 2023-03-10 06:12:16 | [diff] [blame] | 161 | }); |
| 162 | |
| 163 | EXPECT_THAT(samples, testing::ElementsAre()); |
Fergal Daly | f5a50ab | 2021-11-09 05:36:18 | [diff] [blame] | 164 | } |
| 165 | } |
Hajime Hoshi | 765845d6 | 2020-02-21 02:56:21 | [diff] [blame] | 166 | |
Yuzu Saijo | c347807 | 2022-03-24 06:15:26 | [diff] [blame] | 167 | void BackForwardCacheBrowserTest::NotifyNotRestoredReasons( |
| 168 | std::unique_ptr<BackForwardCacheCanStoreTreeResult> tree_result) { |
| 169 | tree_result_ = std::move(tree_result); |
| 170 | } |
| 171 | |
Fergal Daly | f5a50ab | 2021-11-09 05:36:18 | [diff] [blame] | 172 | void BackForwardCacheBrowserTest::SetUpCommandLine( |
| 173 | base::CommandLine* command_line) { |
Fergal Daly | f5a50ab | 2021-11-09 05:36:18 | [diff] [blame] | 174 | mock_cert_verifier_.SetUpCommandLine(command_line); |
Arthur Sonzogni | dc3d3b2a | 2021-08-06 13:13:23 | [diff] [blame] | 175 | |
Lei Zhang | a6aac9d | 2024-07-10 20:59:38 | [diff] [blame] | 176 | command_line->AppendSwitch(switches::kUseFakeUIForMediaStream); |
| 177 | command_line->AppendSwitch(switches::kEnableExperimentalWebPlatformFeatures); |
Fergal Daly | f5a50ab | 2021-11-09 05:36:18 | [diff] [blame] | 178 | // TODO(sreejakshetty): Initialize ScopedFeatureLists from test constructor. |
Ming-Ying Chung | 073e6f60 | 2023-01-26 02:47:40 | [diff] [blame] | 179 | EnableFeatureAndSetParams(features::kBackForwardCacheTimeToLiveControl, |
| 180 | "time_to_live_seconds", "3600"); |
Fergal Daly | 7fdacfb | 2022-10-21 13:23:06 | [diff] [blame] | 181 | // Entry to the cache can be slow during testing and cause flakiness. |
| 182 | DisableFeature(features::kBackForwardCacheEntryTimeout); |
Fergal Daly | f5a50ab | 2021-11-09 05:36:18 | [diff] [blame] | 183 | EnableFeatureAndSetParams(features::kBackForwardCache, |
| 184 | "message_handling_when_cached", "log"); |
| 185 | EnableFeatureAndSetParams( |
Fergal Daly | f5a50ab | 2021-11-09 05:36:18 | [diff] [blame] | 186 | blink::features::kLogUnexpectedIPCPostedToBackForwardCachedDocuments, |
| 187 | "delay_before_tracking_ms", "0"); |
Fergal Daly | a7dcc35 | 2022-10-19 03:43:18 | [diff] [blame] | 188 | // Allow unlimited network during tests. Override this if you want to test the |
| 189 | // network limiting. |
Fergal Daly | f5a50ab | 2021-11-09 05:36:18 | [diff] [blame] | 190 | EnableFeatureAndSetParams(blink::features::kLoadingTasksUnfreezable, |
| 191 | "max_buffered_bytes_per_process", |
Fergal Daly | a7dcc35 | 2022-10-19 03:43:18 | [diff] [blame] | 192 | base::NumberToString(INT_MAX)); |
| 193 | EnableFeatureAndSetParams(blink::features::kLoadingTasksUnfreezable, |
| 194 | "grace_period_to_finish_loading_in_seconds", |
| 195 | base::NumberToString(INT_MAX)); |
Fergal Daly | 25b5180 | 2022-11-28 06:01:24 | [diff] [blame] | 196 | // Enable capturing not-restored-reasons tree. |
| 197 | EnableFeatureAndSetParams( |
| 198 | blink::features::kBackForwardCacheSendNotRestoredReasons, "", ""); |
| 199 | |
Yuzu Saijo | f55ccb6 | 2023-04-06 04:52:22 | [diff] [blame] | 200 | // Do not trigger DumpWithoutCrashing() for JavaScript execution. |
| 201 | DisableFeature(blink::features::kBackForwardCacheDWCOnJavaScriptExecution); |
Xiaohan Wang | 1ecfd00 | 2022-01-19 22:33:10 | [diff] [blame] | 202 | #if BUILDFLAG(IS_ANDROID) |
| 203 | EnableFeatureAndSetParams(features::kBackForwardCache, |
| 204 | "process_binding_strength", "NORMAL"); |
[email protected] | 42e682e5 | 2019-12-05 04:13:46 | [diff] [blame] | 205 | #endif |
Sreeja Kamishetty | 92006e0 | 2021-02-05 05:18:11 | [diff] [blame] | 206 | // Allow BackForwardCache for all devices regardless of their memory. |
John Abd-El-Malek | 3c868c29 | 2021-02-19 20:00:09 | [diff] [blame] | 207 | DisableFeature(features::kBackForwardCacheMemoryControls); |
Fergal Daly | 7e9b4caa | 2025-07-17 13:56:09 | [diff] [blame] | 208 | // Many browser tests assume a cache size of 1. |
| 209 | EnableCacheSize(1, std::nullopt); |
Sreeja Kamishetty | 92006e0 | 2021-02-05 05:18:11 | [diff] [blame] | 210 | |
[email protected] | 54eaf62 | 2019-11-25 12:36:03 | [diff] [blame] | 211 | SetupFeaturesAndParameters(); |
Alexander Timin | 8304ddd94 | 2019-09-02 15:53:59 | [diff] [blame] | 212 | |
Hajime Hoshi | 925793e7 | 2019-11-26 07:58:55 | [diff] [blame] | 213 | command_line->AppendSwitchASCII( |
| 214 | switches::kAutoplayPolicy, |
| 215 | switches::autoplay::kNoUserGestureRequiredPolicy); |
Stephen Chenney | 91a186b | 2021-03-23 10:42:01 | [diff] [blame] | 216 | // Unfortunately needed for one test on slow bots, TextInputStateUpdated, |
| 217 | // where deferred commits delays input too much. |
| 218 | command_line->AppendSwitch(blink::switches::kAllowPreCommitInput); |
Fergal Daly | 7e9b4caa | 2025-07-17 13:56:09 | [diff] [blame] | 219 | ContentBrowserTest::SetUpCommandLine(command_line); |
Fergal Daly | f5a50ab | 2021-11-09 05:36:18 | [diff] [blame] | 220 | } |
| 221 | |
| 222 | void BackForwardCacheBrowserTest::SetUpInProcessBrowserTestFixture() { |
| 223 | ContentBrowserTest::SetUpInProcessBrowserTestFixture(); |
| 224 | mock_cert_verifier_.SetUpInProcessBrowserTestFixture(); |
| 225 | } |
| 226 | |
| 227 | void BackForwardCacheBrowserTest::TearDownInProcessBrowserTestFixture() { |
| 228 | ContentBrowserTest::TearDownInProcessBrowserTestFixture(); |
| 229 | mock_cert_verifier_.TearDownInProcessBrowserTestFixture(); |
| 230 | } |
| 231 | |
| 232 | void BackForwardCacheBrowserTest::SetupFeaturesAndParameters() { |
Daniel Cheng | 43a829c | 2022-10-14 00:16:36 | [diff] [blame] | 233 | std::vector<base::test::FeatureRefAndParams> enabled_features; |
Fergal Daly | f5a50ab | 2021-11-09 05:36:18 | [diff] [blame] | 234 | |
Daniel Cheng | c9ead4b | 2022-10-05 03:54:29 | [diff] [blame] | 235 | for (const auto& [feature_ref, params] : features_with_params_) { |
| 236 | enabled_features.emplace_back(*feature_ref, params); |
Arthur Sonzogni | dc3d3b2a | 2021-08-06 13:13:23 | [diff] [blame] | 237 | } |
| 238 | |
Fergal Daly | f5a50ab | 2021-11-09 05:36:18 | [diff] [blame] | 239 | feature_list_.InitWithFeaturesAndParameters(enabled_features, |
| 240 | disabled_features_); |
Fergal Daly | 432aa7c | 2022-06-14 07:30:54 | [diff] [blame] | 241 | vmodule_switches_.InitWithSwitches("back_forward_cache_impl=1"); |
Fergal Daly | f5a50ab | 2021-11-09 05:36:18 | [diff] [blame] | 242 | } |
Arthur Sonzogni | dc3d3b2a | 2021-08-06 13:13:23 | [diff] [blame] | 243 | |
Fergal Daly | f5a50ab | 2021-11-09 05:36:18 | [diff] [blame] | 244 | void BackForwardCacheBrowserTest::EnableFeatureAndSetParams( |
Daniel Cheng | c9ead4b | 2022-10-05 03:54:29 | [diff] [blame] | 245 | const base::Feature& feature, |
Fergal Daly | f5a50ab | 2021-11-09 05:36:18 | [diff] [blame] | 246 | std::string param_name, |
| 247 | std::string param_value) { |
Fergal Daly | 7e9b4caa | 2025-07-17 13:56:09 | [diff] [blame] | 248 | const auto& it = features_with_params_.find(feature); |
| 249 | if (it != features_with_params_.end()) { |
| 250 | // If the feature-param has been set already, do not update it. |
| 251 | if (it->second.contains(param_name)) { |
| 252 | return; |
| 253 | } |
| 254 | } |
Fergal Daly | f5a50ab | 2021-11-09 05:36:18 | [diff] [blame] | 255 | features_with_params_[feature][param_name] = param_value; |
| 256 | } |
Arthur Sonzogni | 620cec6 | 2018-12-13 13:08:57 | [diff] [blame] | 257 | |
Daniel Cheng | c9ead4b | 2022-10-05 03:54:29 | [diff] [blame] | 258 | void BackForwardCacheBrowserTest::DisableFeature(const base::Feature& feature) { |
Fergal Daly | 7e9b4caa | 2025-07-17 13:56:09 | [diff] [blame] | 259 | if (features_with_params_.contains(feature)) { |
| 260 | // If the feature has been explicitly enabled, ignore any subsequent |
| 261 | // disables. |
| 262 | return; |
| 263 | } |
Fergal Daly | f5a50ab | 2021-11-09 05:36:18 | [diff] [blame] | 264 | disabled_features_.push_back(feature); |
| 265 | } |
[email protected] | 54eaf62 | 2019-11-25 12:36:03 | [diff] [blame] | 266 | |
Fergal Daly | b125811 | 2025-07-15 03:00:51 | [diff] [blame] | 267 | void BackForwardCacheBrowserTest::EnableCacheSize( |
| 268 | std::optional<int> cache_size, |
| 269 | std::optional<int> foreground_cache_size) { |
| 270 | if (cache_size) { |
Fergal Daly | 7e9b4caa | 2025-07-17 13:56:09 | [diff] [blame] | 271 | EnableFeatureAndSetParams(content::kBackForwardCacheSize, |
| 272 | kBackForwardCacheSizeCacheSize.name, |
Fergal Daly | b125811 | 2025-07-15 03:00:51 | [diff] [blame] | 273 | base::NumberToString(cache_size.value())); |
| 274 | } |
| 275 | if (foreground_cache_size) { |
| 276 | EnableFeatureAndSetParams( |
Fergal Daly | 7e9b4caa | 2025-07-17 13:56:09 | [diff] [blame] | 277 | content::kBackForwardCacheSize, |
| 278 | kBackForwardCacheSizeForegroundCacheSize.name, |
Fergal Daly | b125811 | 2025-07-15 03:00:51 | [diff] [blame] | 279 | base::NumberToString(foreground_cache_size.value())); |
| 280 | } |
| 281 | } |
| 282 | |
Fergal Daly | f5a50ab | 2021-11-09 05:36:18 | [diff] [blame] | 283 | void BackForwardCacheBrowserTest::SetUpOnMainThread() { |
Matt Menke | 7c824a7 | 2025-06-26 13:43:20 | [diff] [blame] | 284 | // Set up WebSocket handlers, as a number of tests use them. |
Matt Menke | 21df5e7 | 2025-07-22 17:12:01 | [diff] [blame] | 285 | net::test_server::InstallDefaultWebSocketHandlers(embedded_test_server()); |
Matt Menke | 7c824a7 | 2025-06-26 13:43:20 | [diff] [blame] | 286 | |
Fergal Daly | f5a50ab | 2021-11-09 05:36:18 | [diff] [blame] | 287 | mock_cert_verifier_.mock_cert_verifier()->set_default_result(net::OK); |
| 288 | host_resolver()->AddRule("*", "127.0.0.1"); |
| 289 | // TestAutoSetUkmRecorder's constructor requires a sequenced context. |
| 290 | ukm_recorder_ = std::make_unique<ukm::TestAutoSetUkmRecorder>(); |
Ming-Ying Chung | a8e8a2e | 2022-08-16 06:04:50 | [diff] [blame] | 291 | histogram_tester_ = std::make_unique<base::HistogramTester>(); |
Fergal Daly | f5a50ab | 2021-11-09 05:36:18 | [diff] [blame] | 292 | ContentBrowserTest::SetUpOnMainThread(); |
| 293 | } |
| 294 | |
| 295 | void BackForwardCacheBrowserTest::TearDownOnMainThread() { |
| 296 | ukm_recorder_.reset(); |
| 297 | ContentBrowserTest::TearDownOnMainThread(); |
| 298 | } |
| 299 | |
| 300 | WebContentsImpl* BackForwardCacheBrowserTest::web_contents() const { |
| 301 | return static_cast<WebContentsImpl*>(shell()->web_contents()); |
| 302 | } |
| 303 | |
| 304 | RenderFrameHostImpl* BackForwardCacheBrowserTest::current_frame_host() { |
| 305 | return web_contents()->GetPrimaryFrameTree().root()->current_frame_host(); |
| 306 | } |
| 307 | |
| 308 | RenderFrameHostManager* |
| 309 | BackForwardCacheBrowserTest::render_frame_host_manager() { |
| 310 | return web_contents()->GetPrimaryFrameTree().root()->render_manager(); |
| 311 | } |
| 312 | |
| 313 | std::string BackForwardCacheBrowserTest::DepictFrameTree(FrameTreeNode* node) { |
| 314 | return visualizer_.DepictFrameTree(node); |
| 315 | } |
| 316 | |
| 317 | bool BackForwardCacheBrowserTest::HistogramContainsIntValue( |
Ramon Cano Aparicio | 6797d4e | 2025-01-10 16:09:02 | [diff] [blame] | 318 | base::HistogramBase::Sample32 sample, |
Fergal Daly | f5a50ab | 2021-11-09 05:36:18 | [diff] [blame] | 319 | std::vector<base::Bucket> histogram_values) { |
Peter Kasting | 837e2ccb | 2022-09-07 14:13:17 | [diff] [blame] | 320 | return base::Contains(histogram_values, static_cast<int>(sample), |
| 321 | &base::Bucket::min); |
Fergal Daly | f5a50ab | 2021-11-09 05:36:18 | [diff] [blame] | 322 | } |
| 323 | |
Fergal Daly | f5a50ab | 2021-11-09 05:36:18 | [diff] [blame] | 324 | void BackForwardCacheBrowserTest::EvictByJavaScript(RenderFrameHostImpl* rfh) { |
| 325 | // Run JavaScript on a page in the back-forward cache. The page should be |
| 326 | // evicted. As the frame is deleted, ExecJs returns false without executing. |
| 327 | // Run without user gesture to prevent UpdateUserActivationState message |
| 328 | // being sent back to browser. |
| 329 | EXPECT_FALSE( |
| 330 | ExecJs(rfh, "console.log('hi');", EXECUTE_SCRIPT_NO_USER_GESTURE)); |
| 331 | } |
Hajime Hoshi | 765845d6 | 2020-02-21 02:56:21 | [diff] [blame] | 332 | |
Fergal Daly | f5a50ab | 2021-11-09 05:36:18 | [diff] [blame] | 333 | void BackForwardCacheBrowserTest::StartRecordingEvents( |
| 334 | RenderFrameHostImpl* rfh) { |
| 335 | EXPECT_TRUE(ExecJs(rfh, R"( |
Yuzu Saijo | ecb779c | 2019-11-06 12:59:37 | [diff] [blame] | 336 | window.testObservedEvents = []; |
| 337 | let event_list = [ |
| 338 | 'visibilitychange', |
| 339 | 'pagehide', |
| 340 | 'pageshow', |
| 341 | 'freeze', |
| 342 | 'resume', |
| 343 | ]; |
| 344 | for (event_name of event_list) { |
| 345 | let result = event_name; |
| 346 | window.addEventListener(event_name, event => { |
| 347 | if (event.persisted) |
Alexander Timin | 44ccede | 2020-01-23 09:00:34 | [diff] [blame] | 348 | result += '.persisted'; |
| 349 | window.testObservedEvents.push('window.' + result); |
Yuzu Saijo | ecb779c | 2019-11-06 12:59:37 | [diff] [blame] | 350 | }); |
| 351 | document.addEventListener(event_name, |
Alexander Timin | 44ccede | 2020-01-23 09:00:34 | [diff] [blame] | 352 | () => window.testObservedEvents.push('document.' + result)); |
Yuzu Saijo | ecb779c | 2019-11-06 12:59:37 | [diff] [blame] | 353 | } |
| 354 | )")); |
Fergal Daly | f5a50ab | 2021-11-09 05:36:18 | [diff] [blame] | 355 | } |
Yuzu Saijo | ecb779c | 2019-11-06 12:59:37 | [diff] [blame] | 356 | |
Fergal Daly | f5a50ab | 2021-11-09 05:36:18 | [diff] [blame] | 357 | void BackForwardCacheBrowserTest::MatchEventList(RenderFrameHostImpl* rfh, |
Matt Menke | 0500b4f4 | 2022-06-28 17:06:58 | [diff] [blame] | 358 | base::Value list, |
Fergal Daly | f5a50ab | 2021-11-09 05:36:18 | [diff] [blame] | 359 | base::Location location) { |
| 360 | EXPECT_EQ(list, EvalJs(rfh, "window.testObservedEvents")) |
| 361 | << location.ToString(); |
| 362 | } |
Yuzu Saijo | ecb779c | 2019-11-06 12:59:37 | [diff] [blame] | 363 | |
Fergal Daly | 6b0db37e | 2022-06-27 05:41:03 | [diff] [blame] | 364 | // Creates a minimal HTTPS server, accessible through https_server(). |
| 365 | // Returns a pointer to the server. |
Fergal Daly | f5a50ab | 2021-11-09 05:36:18 | [diff] [blame] | 366 | net::EmbeddedTestServer* BackForwardCacheBrowserTest::CreateHttpsServer() { |
| 367 | https_server_ = std::make_unique<net::EmbeddedTestServer>( |
| 368 | net::EmbeddedTestServer::TYPE_HTTPS); |
| 369 | https_server_->AddDefaultHandlers(GetTestDataFilePath()); |
Fergal Daly | 6b0db37e | 2022-06-27 05:41:03 | [diff] [blame] | 370 | https_server_->SetSSLConfig(net::EmbeddedTestServer::CERT_TEST_NAMES); |
Fergal Daly | f5a50ab | 2021-11-09 05:36:18 | [diff] [blame] | 371 | return https_server(); |
| 372 | } |
Fergal Daly | 637c452 | 2019-11-22 00:21:31 | [diff] [blame] | 373 | |
Fergal Daly | f5a50ab | 2021-11-09 05:36:18 | [diff] [blame] | 374 | net::EmbeddedTestServer* BackForwardCacheBrowserTest::https_server() { |
| 375 | return https_server_.get(); |
| 376 | } |
Fergal Daly | 637c452 | 2019-11-22 00:21:31 | [diff] [blame] | 377 | |
Ming-Ying Chung | ee9b9ea | 2022-08-15 08:24:25 | [diff] [blame] | 378 | // Do not fail this test if a message from a renderer arrives at the browser |
| 379 | // for a cached page. |
Fergal Daly | f5a50ab | 2021-11-09 05:36:18 | [diff] [blame] | 380 | void BackForwardCacheBrowserTest::DoNotFailForUnexpectedMessagesWhileCached() { |
| 381 | fail_for_unexpected_messages_while_cached_ = false; |
| 382 | } |
Carlos Caballero | 0e2fff92 | 2020-09-15 12:52:19 | [diff] [blame] | 383 | |
Yuzu Saijo | 6ddce41 | 2021-08-17 05:09:15 | [diff] [blame] | 384 | // Navigates to a page at |page_url| with an img element with src set to |
| 385 | // "image.png". |
Fergal Daly | f5a50ab | 2021-11-09 05:36:18 | [diff] [blame] | 386 | RenderFrameHostImpl* BackForwardCacheBrowserTest::NavigateToPageWithImage( |
| 387 | const GURL& page_url) { |
| 388 | EXPECT_TRUE(NavigateToURL(shell(), page_url)); |
| 389 | RenderFrameHostImpl* rfh = current_frame_host(); |
| 390 | // Wait for the document to load DOM to ensure that kLoading is not |
| 391 | // one of the reasons why the document wasn't cached. |
Fergal Daly | c4d8b182 | 2022-02-14 08:00:27 | [diff] [blame] | 392 | EXPECT_TRUE(WaitForDOMContentLoaded(rfh)); |
Yuzu Saijo | 6ddce41 | 2021-08-17 05:09:15 | [diff] [blame] | 393 | |
Fergal Daly | f5a50ab | 2021-11-09 05:36:18 | [diff] [blame] | 394 | EXPECT_TRUE(ExecJs(rfh, R"( |
Yuzu Saijo | 6ddce41 | 2021-08-17 05:09:15 | [diff] [blame] | 395 | var image = document.createElement("img"); |
| 396 | image.src = "image.png"; |
| 397 | document.body.appendChild(image); |
| 398 | |
| 399 | var image_load_status = new Promise((resolve, reject) => { |
| 400 | image.onload = () => { resolve("loaded"); } |
| 401 | image.onerror = () => { resolve("error"); } |
| 402 | }); |
| 403 | )")); |
Fergal Daly | f5a50ab | 2021-11-09 05:36:18 | [diff] [blame] | 404 | return rfh; |
| 405 | } |
Yuzu Saijo | 6ddce41 | 2021-08-17 05:09:15 | [diff] [blame] | 406 | |
Fergal Daly | f5a50ab | 2021-11-09 05:36:18 | [diff] [blame] | 407 | void BackForwardCacheBrowserTest::AcquireKeyboardLock( |
| 408 | RenderFrameHostImpl* rfh) { |
Fergal Daly | 7434e71 | 2024-12-11 10:11:48 | [diff] [blame] | 409 | EXPECT_EQ(42, EvalJs(rfh, R"( |
Yuzu Saijo | ae15ed8 | 2021-10-14 07:03:10 | [diff] [blame] | 410 | new Promise(resolve => { |
| 411 | navigator.keyboard.lock(); |
Fergal Daly | 7434e71 | 2024-12-11 10:11:48 | [diff] [blame] | 412 | resolve(42); |
Yuzu Saijo | ae15ed8 | 2021-10-14 07:03:10 | [diff] [blame] | 413 | }); |
| 414 | )")); |
Fergal Daly | f5a50ab | 2021-11-09 05:36:18 | [diff] [blame] | 415 | } |
Yuzu Saijo | ae15ed8 | 2021-10-14 07:03:10 | [diff] [blame] | 416 | |
Fergal Daly | f5a50ab | 2021-11-09 05:36:18 | [diff] [blame] | 417 | void BackForwardCacheBrowserTest::ReleaseKeyboardLock( |
| 418 | RenderFrameHostImpl* rfh) { |
Fergal Daly | 7434e71 | 2024-12-11 10:11:48 | [diff] [blame] | 419 | EXPECT_EQ(42, EvalJs(rfh, R"( |
Yuzu Saijo | ae15ed8 | 2021-10-14 07:03:10 | [diff] [blame] | 420 | new Promise(resolve => { |
| 421 | navigator.keyboard.unlock(); |
Fergal Daly | 7434e71 | 2024-12-11 10:11:48 | [diff] [blame] | 422 | resolve(42); |
Yuzu Saijo | ae15ed8 | 2021-10-14 07:03:10 | [diff] [blame] | 423 | }); |
| 424 | )")); |
arthursonzogni | 2f84dd6 | 2019-06-05 09:47:12 | [diff] [blame] | 425 | } |
| 426 | |
Fergal Daly | 7a05b426 | 2022-03-15 09:18:40 | [diff] [blame] | 427 | void BackForwardCacheBrowserTest::NavigateAndBlock(GURL url, |
| 428 | int history_offset) { |
| 429 | // Block the navigation with an error. |
| 430 | std::unique_ptr<URLLoaderInterceptor> url_interceptor = |
| 431 | URLLoaderInterceptor::SetupRequestFailForURL(url, |
| 432 | net::ERR_BLOCKED_BY_CLIENT); |
Fergal Daly | 7a05b426 | 2022-03-15 09:18:40 | [diff] [blame] | 433 | if (history_offset) { |
| 434 | shell()->GoBackOrForward(history_offset); |
| 435 | } else { |
| 436 | shell()->LoadURL(url); |
| 437 | } |
Fergal Daly | a69d2ff | 2022-03-29 08:10:17 | [diff] [blame] | 438 | WaitForLoadStop(web_contents()); |
Fergal Daly | 7a05b426 | 2022-03-15 09:18:40 | [diff] [blame] | 439 | ASSERT_EQ(current_frame_host()->GetLastCommittedURL(), url); |
| 440 | ASSERT_TRUE(current_frame_host()->IsErrorDocument()); |
| 441 | } |
| 442 | |
Fergal Daly | 25b5180 | 2022-11-28 06:01:24 | [diff] [blame] | 443 | ReasonsMatcher BackForwardCacheBrowserTest::MatchesNotRestoredReasons( |
Arthur Sonzogni | c686e8f | 2024-01-11 08:36:37 | [diff] [blame] | 444 | const std::optional<testing::Matcher<std::string>>& id, |
| 445 | const std::optional<testing::Matcher<std::string>>& name, |
| 446 | const std::optional<testing::Matcher<std::string>>& src, |
Kurumi Muto | 576c0a0 | 2024-02-08 04:17:32 | [diff] [blame] | 447 | const std::vector<BlockingDetailsReasonsMatcher>& reasons, |
Arthur Sonzogni | c686e8f | 2024-01-11 08:36:37 | [diff] [blame] | 448 | const std::optional<SameOriginMatcher>& same_origin_details) { |
Alison Gale | 770f3fc | 2024-04-27 00:39:58 | [diff] [blame] | 449 | // TODO(crbug.com/41496143) Make this matcher display human-friendly messages. |
Fergal Daly | 25b5180 | 2022-11-28 06:01:24 | [diff] [blame] | 450 | return testing::Pointee(testing::AllOf( |
Yuzu Saijo | aa35fc8 | 2023-01-13 01:54:10 | [diff] [blame] | 451 | id.has_value() |
| 452 | ? testing::Field( |
| 453 | "id", &blink::mojom::BackForwardCacheNotRestoredReasons::id, |
| 454 | testing::Optional(id.value())) |
| 455 | : testing::Field( |
| 456 | "id", &blink::mojom::BackForwardCacheNotRestoredReasons::id, |
Arthur Sonzogni | c686e8f | 2024-01-11 08:36:37 | [diff] [blame] | 457 | std::optional<std::string>(std::nullopt)), |
Yuzu Saijo | aa35fc8 | 2023-01-13 01:54:10 | [diff] [blame] | 458 | name.has_value() |
| 459 | ? testing::Field( |
| 460 | "name", &blink::mojom::BackForwardCacheNotRestoredReasons::name, |
| 461 | testing::Optional(name.value())) |
| 462 | : testing::Field( |
| 463 | "name", &blink::mojom::BackForwardCacheNotRestoredReasons::name, |
Arthur Sonzogni | c686e8f | 2024-01-11 08:36:37 | [diff] [blame] | 464 | std::optional<std::string>(std::nullopt)), |
Yuzu Saijo | aa35fc8 | 2023-01-13 01:54:10 | [diff] [blame] | 465 | src.has_value() |
| 466 | ? testing::Field( |
| 467 | "src", &blink::mojom::BackForwardCacheNotRestoredReasons::src, |
| 468 | testing::Optional(src.value())) |
| 469 | : testing::Field( |
| 470 | "src", &blink::mojom::BackForwardCacheNotRestoredReasons::src, |
Arthur Sonzogni | c686e8f | 2024-01-11 08:36:37 | [diff] [blame] | 471 | std::optional<std::string>(std::nullopt)), |
rubberyuzu | 6211b1c8 | 2024-01-22 02:30:48 | [diff] [blame] | 472 | testing::Field("reasons", |
| 473 | &blink::mojom::BackForwardCacheNotRestoredReasons::reasons, |
| 474 | testing::UnorderedElementsAreArray(reasons)), |
Fergal Daly | 25b5180 | 2022-11-28 06:01:24 | [diff] [blame] | 475 | testing::Field( |
| 476 | "same_origin_details", |
| 477 | &blink::mojom::BackForwardCacheNotRestoredReasons:: |
| 478 | same_origin_details, |
Fergal Daly | 3107ca7 | 2022-11-28 06:32:28 | [diff] [blame] | 479 | same_origin_details.has_value() |
| 480 | ? same_origin_details.value() |
Fergal Daly | 25b5180 | 2022-11-28 06:01:24 | [diff] [blame] | 481 | : testing::Property( |
| 482 | "is_null", |
| 483 | &blink::mojom::SameOriginBfcacheNotRestoredDetailsPtr:: |
| 484 | is_null, |
| 485 | true)))); |
| 486 | } |
| 487 | |
| 488 | SameOriginMatcher BackForwardCacheBrowserTest::MatchesSameOriginDetails( |
Luke Gu | 990c227b | 2024-03-07 00:36:38 | [diff] [blame] | 489 | const testing::Matcher<GURL>& url, |
Fergal Daly | 25b5180 | 2022-11-28 06:01:24 | [diff] [blame] | 490 | const std::vector<ReasonsMatcher>& children) { |
Alison Gale | 770f3fc | 2024-04-27 00:39:58 | [diff] [blame] | 491 | // TODO(crbug.com/41496143) Make this matcher display human-friendly messages. |
Fergal Daly | 25b5180 | 2022-11-28 06:01:24 | [diff] [blame] | 492 | return testing::Pointee(testing::AllOf( |
| 493 | testing::Field( |
Fergal Daly | 25b5180 | 2022-11-28 06:01:24 | [diff] [blame] | 494 | "url", &blink::mojom::SameOriginBfcacheNotRestoredDetails::url, url), |
| 495 | testing::Field( |
Fergal Daly | 25b5180 | 2022-11-28 06:01:24 | [diff] [blame] | 496 | "children", |
| 497 | &blink::mojom::SameOriginBfcacheNotRestoredDetails::children, |
| 498 | testing::ElementsAreArray(children)))); |
| 499 | } |
| 500 | |
Kurumi Muto | 576c0a0 | 2024-02-08 04:17:32 | [diff] [blame] | 501 | BlockingDetailsReasonsMatcher |
| 502 | BackForwardCacheBrowserTest::MatchesDetailedReason( |
| 503 | const testing::Matcher<std::string>& name, |
Kurumi Muto | 0cf1280 | 2024-02-21 08:36:42 | [diff] [blame] | 504 | const std::optional<SourceLocationMatcher>& source) { |
Alison Gale | 770f3fc | 2024-04-27 00:39:58 | [diff] [blame] | 505 | // TODO(crbug.com/41496143) Make this matcher display human-friendly |
Kurumi Muto | 576c0a0 | 2024-02-08 04:17:32 | [diff] [blame] | 506 | // messages. |
| 507 | return testing::Pointee(testing::AllOf( |
| 508 | testing::Field("name", &blink::mojom::BFCacheBlockingDetailedReason::name, |
| 509 | name), |
| 510 | testing::Field( |
| 511 | "source", &blink::mojom::BFCacheBlockingDetailedReason::source, |
| 512 | source.has_value() |
| 513 | ? source.value() |
| 514 | : testing::Property( |
Kurumi Muto | 0cf1280 | 2024-02-21 08:36:42 | [diff] [blame] | 515 | "is_null", &blink::mojom::ScriptSourceLocationPtr::is_null, |
Kurumi Muto | 576c0a0 | 2024-02-08 04:17:32 | [diff] [blame] | 516 | true)))); |
| 517 | } |
| 518 | |
Kurumi Muto | 0cf1280 | 2024-02-21 08:36:42 | [diff] [blame] | 519 | BlockingDetailsMatcher BackForwardCacheBrowserTest::MatchesBlockingDetails( |
| 520 | const std::optional<SourceLocationMatcher>& source) { |
Alison Gale | 770f3fc | 2024-04-27 00:39:58 | [diff] [blame] | 521 | // TODO(crbug.com/41496143) Make this matcher display human-friendly messages. |
Kurumi Muto | 0cf1280 | 2024-02-21 08:36:42 | [diff] [blame] | 522 | return testing::Pointee(testing::Field( |
| 523 | "source", &blink::mojom::BlockingDetails::source, |
| 524 | source.has_value() |
| 525 | ? source.value() |
| 526 | : testing::Property("is_null", |
| 527 | &blink::mojom::ScriptSourceLocationPtr::is_null, |
| 528 | true))); |
| 529 | } |
| 530 | |
| 531 | SourceLocationMatcher BackForwardCacheBrowserTest::MatchesSourceLocation( |
Luke Gu | d2d21b84 | 2024-03-19 09:49:41 | [diff] [blame] | 532 | const testing::Matcher<GURL>& url, |
Kurumi Muto | 0cf1280 | 2024-02-21 08:36:42 | [diff] [blame] | 533 | const testing::Matcher<std::string>& function_name, |
Kurumi Muto | 576c0a0 | 2024-02-08 04:17:32 | [diff] [blame] | 534 | const testing::Matcher<uint64_t>& line_number, |
| 535 | const testing::Matcher<uint64_t>& column_number) { |
Alison Gale | 770f3fc | 2024-04-27 00:39:58 | [diff] [blame] | 536 | // TODO(crbug.com/41496143) Make this matcher display human-friendly |
Kurumi Muto | 576c0a0 | 2024-02-08 04:17:32 | [diff] [blame] | 537 | // messages. |
| 538 | return testing::Pointee(testing::AllOf( |
Kurumi Muto | 0cf1280 | 2024-02-21 08:36:42 | [diff] [blame] | 539 | testing::Field("url", &blink::mojom::ScriptSourceLocation::url, url), |
| 540 | testing::Field("function_name", |
| 541 | &blink::mojom::ScriptSourceLocation::function_name, |
| 542 | function_name), |
Kurumi Muto | 576c0a0 | 2024-02-08 04:17:32 | [diff] [blame] | 543 | testing::Field("line_number", |
Kurumi Muto | 0cf1280 | 2024-02-21 08:36:42 | [diff] [blame] | 544 | &blink::mojom::ScriptSourceLocation::line_number, |
Kurumi Muto | 576c0a0 | 2024-02-08 04:17:32 | [diff] [blame] | 545 | line_number), |
| 546 | testing::Field("column_number", |
Kurumi Muto | 0cf1280 | 2024-02-21 08:36:42 | [diff] [blame] | 547 | &blink::mojom::ScriptSourceLocation::column_number, |
rubberyuzu | 15d29d3 | 2023-07-28 05:22:24 | [diff] [blame] | 548 | column_number))); |
| 549 | } |
| 550 | |
Fergal Daly | 97c4e59 | 2023-02-28 10:27:33 | [diff] [blame] | 551 | void BackForwardCacheUnloadBrowserTest::SetUpCommandLine( |
| 552 | base::CommandLine* command_line) { |
| 553 | BackForwardCacheBrowserTest::SetUpCommandLine(command_line); |
| 554 | scoped_feature_list_.InitAndEnableFeature(kBackForwardCacheUnloadAllowed); |
| 555 | } |
| 556 | |
arthursonzogni | 2f84dd6 | 2019-06-05 09:47:12 | [diff] [blame] | 557 | std::initializer_list<RenderFrameHostImpl*> Elements( |
| 558 | std::initializer_list<RenderFrameHostImpl*> t) { |
| 559 | return t; |
| 560 | } |
| 561 | |
Alexander Timin | fa953bff | 2019-12-05 14:31:49 | [diff] [blame] | 562 | // Execute a custom callback when navigation is ready to commit. This is |
Hajime Hoshi | e9262d3 | 2019-08-28 07:40:23 | [diff] [blame] | 563 | // useful for simulating race conditions happening when a page enters the |
| 564 | // BackForwardCache and receive inflight messages sent when it wasn't frozen |
| 565 | // yet. |
Alexander Timin | fa953bff | 2019-12-05 14:31:49 | [diff] [blame] | 566 | class ReadyToCommitNavigationCallback : public WebContentsObserver { |
Hajime Hoshi | e9262d3 | 2019-08-28 07:40:23 | [diff] [blame] | 567 | public: |
Alexander Timin | fa953bff | 2019-12-05 14:31:49 | [diff] [blame] | 568 | ReadyToCommitNavigationCallback( |
Hajime Hoshi | e9262d3 | 2019-08-28 07:40:23 | [diff] [blame] | 569 | WebContents* content, |
Alexander Timin | fa953bff | 2019-12-05 14:31:49 | [diff] [blame] | 570 | base::OnceCallback<void(NavigationHandle*)> callback) |
Hajime Hoshi | e9262d3 | 2019-08-28 07:40:23 | [diff] [blame] | 571 | : WebContentsObserver(content), callback_(std::move(callback)) {} |
| 572 | |
Peter Boström | 9b03653 | 2021-10-28 23:37:28 | [diff] [blame] | 573 | ReadyToCommitNavigationCallback(const ReadyToCommitNavigationCallback&) = |
| 574 | delete; |
| 575 | ReadyToCommitNavigationCallback& operator=( |
| 576 | const ReadyToCommitNavigationCallback&) = delete; |
| 577 | |
Hajime Hoshi | e9262d3 | 2019-08-28 07:40:23 | [diff] [blame] | 578 | private: |
| 579 | // WebContentsObserver: |
Alexander Timin | fa953bff | 2019-12-05 14:31:49 | [diff] [blame] | 580 | void ReadyToCommitNavigation(NavigationHandle* navigation_handle) override { |
Hajime Hoshi | e9262d3 | 2019-08-28 07:40:23 | [diff] [blame] | 581 | if (callback_) |
Alexander Timin | fa953bff | 2019-12-05 14:31:49 | [diff] [blame] | 582 | std::move(callback_).Run(navigation_handle); |
Hajime Hoshi | e9262d3 | 2019-08-28 07:40:23 | [diff] [blame] | 583 | } |
| 584 | |
Alexander Timin | fa953bff | 2019-12-05 14:31:49 | [diff] [blame] | 585 | base::OnceCallback<void(NavigationHandle*)> callback_; |
Hajime Hoshi | e9262d3 | 2019-08-28 07:40:23 | [diff] [blame] | 586 | }; |
| 587 | |
Carlos Caballero | 91fffb2 | 2019-10-29 15:24:30 | [diff] [blame] | 588 | class FirstVisuallyNonEmptyPaintObserver : public WebContentsObserver { |
| 589 | public: |
| 590 | explicit FirstVisuallyNonEmptyPaintObserver(WebContents* contents) |
| 591 | : WebContentsObserver(contents) {} |
| 592 | void DidFirstVisuallyNonEmptyPaint() override { |
| 593 | if (observed_) |
| 594 | return; |
| 595 | observed_ = true; |
| 596 | run_loop_.Quit(); |
| 597 | } |
| 598 | |
| 599 | bool did_fire() const { return observed_; } |
| 600 | |
| 601 | void Wait() { run_loop_.Run(); } |
| 602 | |
| 603 | private: |
| 604 | bool observed_ = false; |
| 605 | base::RunLoop run_loop_{base::RunLoop::Type::kNestableTasksAllowed}; |
| 606 | }; |
| 607 | |
| 608 | void WaitForFirstVisuallyNonEmptyPaint(WebContents* contents) { |
| 609 | if (contents->CompletedFirstVisuallyNonEmptyPaint()) |
| 610 | return; |
| 611 | FirstVisuallyNonEmptyPaintObserver observer(contents); |
| 612 | observer.Wait(); |
| 613 | } |
| 614 | |
Carlos Caballero | 1215f88 | 2019-10-29 15:58:43 | [diff] [blame] | 615 | class ThemeColorObserver : public WebContentsObserver { |
| 616 | public: |
| 617 | explicit ThemeColorObserver(WebContents* contents) |
| 618 | : WebContentsObserver(contents) {} |
Fergal Daly | a4dde50d | 2022-10-14 07:29:25 | [diff] [blame] | 619 | |
| 620 | // Can only be called once. |
Fergal Daly | 15265650 | 2022-10-20 03:02:39 | [diff] [blame] | 621 | [[nodiscard]] bool WaitUntilThemeColorChange() { |
Fergal Daly | a4dde50d | 2022-10-14 07:29:25 | [diff] [blame] | 622 | CHECK(!loop_); |
| 623 | loop_ = std::make_unique<base::RunLoop>(); |
| 624 | if (observed_) { |
| 625 | return true; |
| 626 | } |
| 627 | loop_->Run(); |
| 628 | return observed_; |
| 629 | } |
| 630 | |
| 631 | void DidChangeThemeColor() override { |
| 632 | observed_ = true; |
| 633 | if (loop_) { |
| 634 | loop_->Quit(); |
| 635 | } |
| 636 | } |
Carlos Caballero | 1215f88 | 2019-10-29 15:58:43 | [diff] [blame] | 637 | |
| 638 | bool did_fire() const { return observed_; } |
| 639 | |
| 640 | private: |
Fergal Daly | a4dde50d | 2022-10-14 07:29:25 | [diff] [blame] | 641 | std::unique_ptr<base::RunLoop> loop_; |
Carlos Caballero | 1215f88 | 2019-10-29 15:58:43 | [diff] [blame] | 642 | bool observed_ = false; |
Carlos Caballero | 1215f88 | 2019-10-29 15:58:43 | [diff] [blame] | 643 | }; |
| 644 | |
Hajime Hoshi | a12414a | 2021-12-08 08:21:23 | [diff] [blame] | 645 | PageLifecycleStateManagerTestDelegate::PageLifecycleStateManagerTestDelegate( |
| 646 | PageLifecycleStateManager* manager) |
| 647 | : manager_(manager) { |
| 648 | manager->SetDelegateForTesting(this); |
| 649 | } |
| 650 | |
| 651 | PageLifecycleStateManagerTestDelegate:: |
| 652 | ~PageLifecycleStateManagerTestDelegate() { |
| 653 | if (manager_) |
| 654 | manager_->SetDelegateForTesting(nullptr); |
| 655 | } |
| 656 | |
Fergal Daly | 52ba1e1 | 2022-10-20 07:53:00 | [diff] [blame] | 657 | bool PageLifecycleStateManagerTestDelegate::WaitForInBackForwardCacheAck() { |
Hajime Hoshi | a12414a | 2021-12-08 08:21:23 | [diff] [blame] | 658 | DCHECK(manager_); |
| 659 | if (manager_->last_acknowledged_state().is_in_back_forward_cache) { |
Fergal Daly | 52ba1e1 | 2022-10-20 07:53:00 | [diff] [blame] | 660 | return true; |
Hajime Hoshi | a12414a | 2021-12-08 08:21:23 | [diff] [blame] | 661 | } |
| 662 | base::RunLoop loop; |
| 663 | store_in_back_forward_cache_ack_received_ = loop.QuitClosure(); |
| 664 | loop.Run(); |
Fergal Daly | 52ba1e1 | 2022-10-20 07:53:00 | [diff] [blame] | 665 | return manager_->last_acknowledged_state().is_in_back_forward_cache; |
Hajime Hoshi | a12414a | 2021-12-08 08:21:23 | [diff] [blame] | 666 | } |
| 667 | |
| 668 | void PageLifecycleStateManagerTestDelegate::OnStoreInBackForwardCacheSent( |
| 669 | base::OnceClosure cb) { |
| 670 | store_in_back_forward_cache_sent_ = std::move(cb); |
| 671 | } |
| 672 | |
| 673 | void PageLifecycleStateManagerTestDelegate::OnDisableJsEvictionSent( |
| 674 | base::OnceClosure cb) { |
| 675 | disable_eviction_sent_ = std::move(cb); |
| 676 | } |
| 677 | |
| 678 | void PageLifecycleStateManagerTestDelegate::OnRestoreFromBackForwardCacheSent( |
| 679 | base::OnceClosure cb) { |
| 680 | restore_from_back_forward_cache_sent_ = std::move(cb); |
| 681 | } |
| 682 | |
| 683 | void PageLifecycleStateManagerTestDelegate::OnLastAcknowledgedStateChanged( |
| 684 | const blink::mojom::PageLifecycleState& old_state, |
| 685 | const blink::mojom::PageLifecycleState& new_state) { |
| 686 | if (store_in_back_forward_cache_ack_received_ && |
| 687 | new_state.is_in_back_forward_cache) |
| 688 | std::move(store_in_back_forward_cache_ack_received_).Run(); |
| 689 | } |
| 690 | |
| 691 | void PageLifecycleStateManagerTestDelegate::OnUpdateSentToRenderer( |
| 692 | const blink::mojom::PageLifecycleState& new_state) { |
| 693 | if (store_in_back_forward_cache_sent_ && new_state.is_in_back_forward_cache) { |
| 694 | std::move(store_in_back_forward_cache_sent_).Run(); |
| 695 | } |
| 696 | |
| 697 | if (disable_eviction_sent_ && new_state.eviction_enabled == false) { |
| 698 | std::move(disable_eviction_sent_).Run(); |
| 699 | } |
| 700 | |
| 701 | if (restore_from_back_forward_cache_sent_ && |
| 702 | !new_state.is_in_back_forward_cache) { |
| 703 | std::move(restore_from_back_forward_cache_sent_).Run(); |
| 704 | } |
| 705 | } |
| 706 | |
| 707 | void PageLifecycleStateManagerTestDelegate::OnDeleted() { |
| 708 | manager_ = nullptr; |
| 709 | } |
| 710 | |
Arthur Sonzogni | 620cec6 | 2018-12-13 13:08:57 | [diff] [blame] | 711 | // Check the visible URL in the omnibox is properly updated when restoring a |
| 712 | // document from the BackForwardCache. |
| 713 | IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, VisibleURL) { |
| 714 | ASSERT_TRUE(embedded_test_server()->Start()); |
arthursonzogni | 72b6649 | 2019-11-04 12:24:33 | [diff] [blame] | 715 | GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html")); |
| 716 | GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html")); |
Arthur Sonzogni | 620cec6 | 2018-12-13 13:08:57 | [diff] [blame] | 717 | |
| 718 | // 1) Go to A. |
arthursonzogni | 2f84dd6 | 2019-06-05 09:47:12 | [diff] [blame] | 719 | EXPECT_TRUE(NavigateToURL(shell(), url_a)); |
Arthur Sonzogni | 620cec6 | 2018-12-13 13:08:57 | [diff] [blame] | 720 | |
| 721 | // 2) Go to B. |
arthursonzogni | 2f84dd6 | 2019-06-05 09:47:12 | [diff] [blame] | 722 | EXPECT_TRUE(NavigateToURL(shell(), url_b)); |
Arthur Sonzogni | 620cec6 | 2018-12-13 13:08:57 | [diff] [blame] | 723 | |
| 724 | // 3) Go back to A. |
Fergal Daly | 5495b0e | 2021-11-19 02:03:28 | [diff] [blame] | 725 | ASSERT_TRUE(HistoryGoBack(web_contents())); |
Arthur Sonzogni | 620cec6 | 2018-12-13 13:08:57 | [diff] [blame] | 726 | EXPECT_EQ(url_a, web_contents()->GetVisibleURL()); |
| 727 | |
| 728 | // 4) Go forward to B. |
Fergal Daly | 5495b0e | 2021-11-19 02:03:28 | [diff] [blame] | 729 | ASSERT_TRUE(HistoryGoForward(web_contents())); |
Arthur Sonzogni | 620cec6 | 2018-12-13 13:08:57 | [diff] [blame] | 730 | EXPECT_EQ(url_b, web_contents()->GetVisibleURL()); |
| 731 | } |
| 732 | |
Lowell Manners | 3c64d3a2 | 2019-09-06 10:52:33 | [diff] [blame] | 733 | // Test only 1 document is kept in the at a time BackForwardCache. |
| 734 | IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, |
| 735 | CacheSizeLimitedToOneDocumentPerTab) { |
Arthur Sonzogni | 620cec6 | 2018-12-13 13:08:57 | [diff] [blame] | 736 | ASSERT_TRUE(embedded_test_server()->Start()); |
arthursonzogni | 72b6649 | 2019-11-04 12:24:33 | [diff] [blame] | 737 | GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html")); |
| 738 | GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html")); |
| 739 | GURL url_c(embedded_test_server()->GetURL("c.com", "/title1.html")); |
Arthur Sonzogni | 620cec6 | 2018-12-13 13:08:57 | [diff] [blame] | 740 | |
Lowell Manners | 3c64d3a2 | 2019-09-06 10:52:33 | [diff] [blame] | 741 | EXPECT_TRUE(NavigateToURL(shell(), url_a)); |
| 742 | // BackForwardCache is empty. |
Arthur Sonzogni | 620cec6 | 2018-12-13 13:08:57 | [diff] [blame] | 743 | RenderFrameHostImpl* rfh_a = current_frame_host(); |
Hajime Hoshi | f53fa7ca | 2019-08-13 06:52:34 | [diff] [blame] | 744 | RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a); |
Arthur Sonzogni | 620cec6 | 2018-12-13 13:08:57 | [diff] [blame] | 745 | |
Lowell Manners | 3c64d3a2 | 2019-09-06 10:52:33 | [diff] [blame] | 746 | EXPECT_TRUE(NavigateToURL(shell(), url_b)); |
| 747 | // BackForwardCache contains only rfh_a. |
Arthur Sonzogni | 620cec6 | 2018-12-13 13:08:57 | [diff] [blame] | 748 | RenderFrameHostImpl* rfh_b = current_frame_host(); |
Hajime Hoshi | f53fa7ca | 2019-08-13 06:52:34 | [diff] [blame] | 749 | RenderFrameDeletedObserver delete_observer_rfh_b(rfh_b); |
Arthur Sonzogni | 620cec6 | 2018-12-13 13:08:57 | [diff] [blame] | 750 | |
Lowell Manners | 3c64d3a2 | 2019-09-06 10:52:33 | [diff] [blame] | 751 | EXPECT_TRUE(NavigateToURL(shell(), url_c)); |
| 752 | // BackForwardCache contains only rfh_b. |
| 753 | delete_observer_rfh_a.WaitUntilDeleted(); |
| 754 | EXPECT_FALSE(delete_observer_rfh_b.deleted()); |
Arthur Sonzogni | 620cec6 | 2018-12-13 13:08:57 | [diff] [blame] | 755 | |
Lowell Manners | 3c64d3a2 | 2019-09-06 10:52:33 | [diff] [blame] | 756 | // If/when the cache size is increased, this can be tested iteratively, see |
| 757 | // deleted code in: https://crrev.com/c/1782902. |
Hajime Hoshi | f9eba2b | 2019-10-02 08:27:42 | [diff] [blame] | 758 | |
Fergal Daly | 5495b0e | 2021-11-19 02:03:28 | [diff] [blame] | 759 | ASSERT_TRUE(HistoryGoToOffset(web_contents(), -2)); |
Hajime Hoshi | 15f6b501 | 2019-10-24 05:25:49 | [diff] [blame] | 760 | ExpectNotRestored({BackForwardCacheMetrics::NotRestoredReason::kCacheLimit}, |
Fergal Daly | 1336ac64 | 2021-09-14 15:13:11 | [diff] [blame] | 761 | {}, {}, {}, {}, FROM_HERE); |
Arthur Sonzogni | 620cec6 | 2018-12-13 13:08:57 | [diff] [blame] | 762 | } |
| 763 | |
Hajime Hoshi | ac6b854 | 2021-02-25 15:18:52 | [diff] [blame] | 764 | IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, ResponseHeaders) { |
| 765 | CreateHttpsServer(); |
| 766 | ASSERT_TRUE(https_server()->Start()); |
| 767 | |
Fergal Daly | 6b0db37e | 2022-06-27 05:41:03 | [diff] [blame] | 768 | GURL url_a(https_server()->GetURL("a.test", "/set-header?X-Foo: bar")); |
| 769 | GURL url_b(https_server()->GetURL("b.test", "/title1.html")); |
Hajime Hoshi | ac6b854 | 2021-02-25 15:18:52 | [diff] [blame] | 770 | |
| 771 | // 1) Navigate to A. |
| 772 | NavigationHandleObserver observer1(web_contents(), url_a); |
| 773 | EXPECT_TRUE(NavigateToURL(shell(), url_a)); |
| 774 | RenderFrameHostImpl* rfh_a = current_frame_host(); |
| 775 | RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a); |
| 776 | EXPECT_TRUE(observer1.has_committed()); |
| 777 | EXPECT_EQ("bar", observer1.GetNormalizedResponseHeader("x-foo")); |
| 778 | |
| 779 | // 2) Navigate to B. |
| 780 | NavigationHandleObserver observer2(web_contents(), url_b); |
| 781 | EXPECT_TRUE(NavigateToURL(shell(), url_b)); |
| 782 | RenderFrameHostImpl* rfh_b = current_frame_host(); |
| 783 | RenderFrameDeletedObserver delete_observer_rfh_b(rfh_b); |
| 784 | EXPECT_FALSE(delete_observer_rfh_a.deleted()); |
| 785 | EXPECT_TRUE(rfh_a->IsInBackForwardCache()); |
| 786 | EXPECT_FALSE(rfh_b->IsInBackForwardCache()); |
| 787 | EXPECT_TRUE(observer2.has_committed()); |
| 788 | |
| 789 | // 3) Go back to A. |
| 790 | NavigationHandleObserver observer3(web_contents(), url_a); |
Fergal Daly | 5495b0e | 2021-11-19 02:03:28 | [diff] [blame] | 791 | ASSERT_TRUE(HistoryGoBack(web_contents())); |
Hajime Hoshi | ac6b854 | 2021-02-25 15:18:52 | [diff] [blame] | 792 | EXPECT_FALSE(delete_observer_rfh_a.deleted()); |
| 793 | EXPECT_FALSE(delete_observer_rfh_b.deleted()); |
| 794 | EXPECT_EQ(rfh_a, current_frame_host()); |
| 795 | EXPECT_FALSE(rfh_a->IsInBackForwardCache()); |
| 796 | EXPECT_TRUE(rfh_b->IsInBackForwardCache()); |
| 797 | EXPECT_TRUE(observer3.has_committed()); |
| 798 | EXPECT_EQ("bar", observer3.GetNormalizedResponseHeader("x-foo")); |
| 799 | |
| 800 | ExpectRestored(FROM_HERE); |
| 801 | } |
| 802 | |
Fergal Daly | 973dc9e | 2021-11-19 09:38:17 | [diff] [blame] | 803 | void HighCacheSizeBackForwardCacheBrowserTest::SetUpCommandLine( |
| 804 | base::CommandLine* command_line) { |
Fergal Daly | b125811 | 2025-07-15 03:00:51 | [diff] [blame] | 805 | EnableCacheSize(kBackForwardCacheSize, std::nullopt); |
Fergal Daly | 973dc9e | 2021-11-19 09:38:17 | [diff] [blame] | 806 | BackForwardCacheBrowserTest::SetUpCommandLine(command_line); |
| 807 | } |
Rakina Zata Amni | 8d49da5 | 2020-11-06 09:23:10 | [diff] [blame] | 808 | |
| 809 | // Test documents are evicted from the BackForwardCache at some point. |
| 810 | IN_PROC_BROWSER_TEST_F(HighCacheSizeBackForwardCacheBrowserTest, |
kouhei | e8cd7ea5 | 2021-05-24 05:24:26 | [diff] [blame] | 811 | CacheEvictionWithIncreasedCacheSize) { |
Rakina Zata Amni | 8d49da5 | 2020-11-06 09:23:10 | [diff] [blame] | 812 | ASSERT_TRUE(embedded_test_server()->Start()); |
Lowell Manners | 9f1a549 | 2019-09-10 09:28:44 | [diff] [blame] | 813 | |
arthursonzogni | 72b6649 | 2019-11-04 12:24:33 | [diff] [blame] | 814 | GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html")); |
| 815 | GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html")); |
Lowell Manners | 9f1a549 | 2019-09-10 09:28:44 | [diff] [blame] | 816 | |
| 817 | EXPECT_TRUE(NavigateToURL(shell(), url_a)); // BackForwardCache size is 0. |
| 818 | RenderFrameHostImpl* rfh_a = current_frame_host(); |
| 819 | RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a); |
| 820 | |
| 821 | EXPECT_TRUE(NavigateToURL(shell(), url_b)); // BackForwardCache size is 1. |
| 822 | RenderFrameHostImpl* rfh_b = current_frame_host(); |
| 823 | RenderFrameDeletedObserver delete_observer_rfh_b(rfh_b); |
| 824 | |
Rakina Zata Amni | 8d49da5 | 2020-11-06 09:23:10 | [diff] [blame] | 825 | for (size_t i = 2; i < kBackForwardCacheSize; ++i) { |
Lowell Manners | 9f1a549 | 2019-09-10 09:28:44 | [diff] [blame] | 826 | EXPECT_TRUE(NavigateToURL(shell(), i % 2 ? url_b : url_a)); |
| 827 | // After |i+1| navigations, |i| documents went into the BackForwardCache. |
| 828 | // When |i| is greater than the BackForwardCache size limit, they are |
| 829 | // evicted: |
Rakina Zata Amni | 8d49da5 | 2020-11-06 09:23:10 | [diff] [blame] | 830 | EXPECT_EQ(i >= kBackForwardCacheSize + 1, delete_observer_rfh_a.deleted()); |
| 831 | EXPECT_EQ(i >= kBackForwardCacheSize + 2, delete_observer_rfh_b.deleted()); |
Lowell Manners | 9f1a549 | 2019-09-10 09:28:44 | [diff] [blame] | 832 | } |
| 833 | } |
| 834 | |
Rakina Zata Amni | 2eed632 | 2021-09-30 22:22:57 | [diff] [blame] | 835 | // Tests that evicting a page in between the time the back/forward cache |
| 836 | // NavigationRequest restore was created and when the NavigationRequest actually |
| 837 | // starts after finishing beforeunload won't result in a crash. |
| 838 | // See https://crbug.com/1218114. |
| 839 | IN_PROC_BROWSER_TEST_F(HighCacheSizeBackForwardCacheBrowserTest, |
| 840 | EvictedWhileWaitingForBeforeUnload) { |
| 841 | ASSERT_TRUE(embedded_test_server()->Start()); |
| 842 | GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html")); |
| 843 | GURL url_b(embedded_test_server()->GetURL("b.com", "/title2.html")); |
| 844 | GURL url_c(embedded_test_server()->GetURL("c.com", "/title3.html")); |
| 845 | |
| 846 | // 1) Navigate to A. |
| 847 | EXPECT_TRUE(NavigateToURL(shell(), url_a)); |
| 848 | RenderFrameHostImplWrapper rfh_a(current_frame_host()); |
Rakina Zata Amni | 2eed632 | 2021-09-30 22:22:57 | [diff] [blame] | 849 | |
| 850 | // 2) Navigate to B. |
| 851 | EXPECT_TRUE(NavigateToURL(shell(), url_b)); |
| 852 | RenderFrameHostImplWrapper rfh_b(current_frame_host()); |
Rakina Zata Amni | 2eed632 | 2021-09-30 22:22:57 | [diff] [blame] | 853 | EXPECT_TRUE(rfh_a->IsInBackForwardCache()); |
| 854 | |
| 855 | // 3) Navigate to C, which has a beforeunload handler that never finishes. |
| 856 | EXPECT_TRUE(NavigateToURL(shell(), url_c)); |
| 857 | RenderFrameHostImplWrapper rfh_c(current_frame_host()); |
| 858 | EXPECT_TRUE(ExecJs(rfh_c.get(), R"( |
| 859 | window.onbeforeunload = () => { |
| 860 | while (true) {} |
| 861 | } |
| 862 | )")); |
| 863 | // Both A & B are in the back/forward cache. |
| 864 | EXPECT_TRUE(rfh_a->IsInBackForwardCache()); |
| 865 | EXPECT_TRUE(rfh_b->IsInBackForwardCache()); |
| 866 | |
| 867 | // 4) Evict entry A. This will post a task that destroys all evicted entries |
| 868 | // when it runs (task #1). |
| 869 | DisableBFCacheForRFHForTesting(rfh_a->GetGlobalId()); |
| 870 | EXPECT_FALSE(rfh_a.IsDestroyed()); |
| 871 | EXPECT_TRUE(rfh_a->is_evicted_from_back_forward_cache()); |
| 872 | |
| 873 | // 5) Trigger a back navigation to B. This will create a BFCache restore |
| 874 | // navigation to B, but will wait for C's beforeunload handler to finish |
| 875 | // running before continuing. |
Mingyu Lei | 7956b8b | 2023-07-24 08:24:08 | [diff] [blame] | 876 | // The BFCache entry will be evicted before the back navigation completes, so |
| 877 | // the old navigation will be reset and a new navigation will be restarted. |
| 878 | // This observer is waiting for the two navigation requests to complete. |
| 879 | TestNavigationObserver observer(web_contents(), |
| 880 | /* expected_number_of_navigations= */ 2, |
| 881 | MessageLoopRunner::QuitMode::IMMEDIATE, |
| 882 | /* ignore_uncommitted_navigations= */ false); |
Rakina Zata Amni | 2eed632 | 2021-09-30 22:22:57 | [diff] [blame] | 883 | web_contents()->GetController().GoBack(); |
| 884 | |
| 885 | // 6) Post a task to run BeforeUnloadCompleted (task #2). This will continue |
| 886 | // the BFCache restore navigation to B from step 5, which is currently waiting |
| 887 | // for a BeforeUnloadCompleted call. |
Carlos Caballero | 15caeeb | 2021-10-27 09:57:55 | [diff] [blame] | 888 | FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root(); |
Sean Maher | 5b9af51f | 2022-11-21 15:32:47 | [diff] [blame] | 889 | base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask( |
Rakina Zata Amni | 2eed632 | 2021-09-30 22:22:57 | [diff] [blame] | 890 | FROM_HERE, base::BindLambdaForTesting([&]() { |
Charlie Reis | 9e20dd1 | 2025-01-02 20:11:53 | [diff] [blame] | 891 | root->navigator().BeforeUnloadCompleted( |
| 892 | root, /*proceed=*/true, base::TimeTicks::Now(), |
| 893 | /*for_legacy=*/false, /*showed_dialog=*/false); |
Rakina Zata Amni | 2eed632 | 2021-09-30 22:22:57 | [diff] [blame] | 894 | })); |
| 895 | |
| 896 | // 7) Evict entry B. This will post a task (task #3) to restart the navigation |
| 897 | // to B, and also another task (task #4) to destroy all evicted entries. |
| 898 | DisableBFCacheForRFHForTesting(rfh_b->GetGlobalId()); |
| 899 | EXPECT_FALSE(rfh_b.IsDestroyed()); |
| 900 | EXPECT_TRUE(rfh_b->is_evicted_from_back_forward_cache()); |
| 901 | |
| 902 | // 8) Wait until the back navigation to B finishes. This will run posted tasks |
| 903 | // in order. So: |
| 904 | // - Task #1 from step 4 will run and destroy all evicted entries. As both the |
| 905 | // entries for A & B have been evicted, they are both destroyed. |
| 906 | // - Task #2 from step 6 will run and continue the back/forward cache restore |
| 907 | // NavigationRequest to B. However, it would notice that the entry for B is |
| 908 | // now gone, and should handle it gracefully. |
| 909 | // - Task #3 from step 7 to restart navigation to B runs, and should create a |
| 910 | // NavigationRequest to replace the previous NavigationRequest to B. |
| 911 | // - Task #4 from step 7 to destroy evicted entries runs and won't destroy |
| 912 | // any entry since there's no longer any entry in the back/forward cache. |
Mingyu Lei | 7956b8b | 2023-07-24 08:24:08 | [diff] [blame] | 913 | observer.Wait(); |
Rakina Zata Amni | 2eed632 | 2021-09-30 22:22:57 | [diff] [blame] | 914 | EXPECT_EQ(web_contents()->GetLastCommittedURL(), url_b); |
| 915 | ExpectNotRestored({BackForwardCacheMetrics::NotRestoredReason:: |
| 916 | kDisableForRenderFrameHostCalled}, |
| 917 | {}, {}, {RenderFrameHostDisabledForTestingReason()}, {}, |
| 918 | FROM_HERE); |
| 919 | } |
| 920 | |
Lowell Manners | 2d0163e4 | 2019-07-30 09:24:30 | [diff] [blame] | 921 | IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, |
Alexander Timin | 26864e1 | 2019-10-18 02:00:06 | [diff] [blame] | 922 | SubframeWithOngoingNavigationNotCached) { |
| 923 | net::test_server::ControllableHttpResponse response(embedded_test_server(), |
| 924 | "/hung"); |
| 925 | ASSERT_TRUE(embedded_test_server()->Start()); |
| 926 | |
| 927 | // Navigate to a page with an iframe. |
| 928 | TestNavigationObserver navigation_observer1(web_contents()); |
| 929 | GURL main_url(embedded_test_server()->GetURL( |
| 930 | "a.com", "/back_forward_cache/page_with_hung_iframe.html")); |
| 931 | shell()->LoadURL(main_url); |
| 932 | navigation_observer1.WaitForNavigationFinished(); |
| 933 | |
| 934 | RenderFrameHostImpl* main_frame = current_frame_host(); |
| 935 | RenderFrameDeletedObserver frame_deleted_observer(main_frame); |
| 936 | response.WaitForRequest(); |
| 937 | |
| 938 | // Navigate away. |
| 939 | TestNavigationObserver navigation_observer2(web_contents()); |
| 940 | shell()->LoadURL(embedded_test_server()->GetURL("b.com", "/title1.html")); |
| 941 | navigation_observer2.WaitForNavigationFinished(); |
| 942 | |
| 943 | // The page with the unsupported feature should be deleted (not cached). |
| 944 | frame_deleted_observer.WaitUntilDeleted(); |
| 945 | } |
| 946 | |
arthursonzogni | e385b7b | 2019-09-02 11:11:53 | [diff] [blame] | 947 | // Only HTTP/HTTPS main document can enter the BackForwardCache. |
| 948 | IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, CacheHTTPDocumentOnly) { |
| 949 | ASSERT_TRUE(embedded_test_server()->Start()); |
Fergal Daly | 637c452 | 2019-11-22 00:21:31 | [diff] [blame] | 950 | ASSERT_TRUE(CreateHttpsServer()->Start()); |
arthursonzogni | e385b7b | 2019-09-02 11:11:53 | [diff] [blame] | 951 | |
Fergal Daly | 6b0db37e | 2022-06-27 05:41:03 | [diff] [blame] | 952 | GURL http_url(embedded_test_server()->GetURL("a.test", "/title1.html")); |
| 953 | GURL https_url(https_server()->GetURL("a.test", "/title1.html")); |
arthursonzogni | e385b7b | 2019-09-02 11:11:53 | [diff] [blame] | 954 | GURL file_url = net::FilePathToFileURL(GetTestFilePath("", "title1.html")); |
| 955 | GURL data_url = GURL("data:text/html,"); |
| 956 | GURL blank_url = GURL(url::kAboutBlankURL); |
| 957 | GURL webui_url = GetWebUIURL("gpu"); |
| 958 | |
| 959 | enum { STORED, DELETED }; |
| 960 | struct { |
| 961 | int expectation; |
| 962 | GURL url; |
| 963 | } test_cases[] = { |
| 964 | // Only document with HTTP/HTTPS URLs are allowed to enter the |
| 965 | // BackForwardCache. |
| 966 | {STORED, http_url}, |
| 967 | {STORED, https_url}, |
| 968 | |
| 969 | // Others aren't allowed. |
| 970 | {DELETED, file_url}, |
| 971 | {DELETED, data_url}, |
| 972 | {DELETED, webui_url}, |
| 973 | {DELETED, blank_url}, |
| 974 | }; |
| 975 | |
| 976 | char hostname[] = "a.unique"; |
| 977 | for (auto& test_case : test_cases) { |
| 978 | SCOPED_TRACE(testing::Message() |
| 979 | << std::endl |
| 980 | << "expectation = " << test_case.expectation << std::endl |
| 981 | << "url = " << test_case.url << std::endl); |
| 982 | |
| 983 | // 1) Navigate to. |
| 984 | EXPECT_TRUE(NavigateToURL(shell(), test_case.url)); |
Rakina Zata Amni | 348fe2b | 2021-07-09 05:28:52 | [diff] [blame] | 985 | RenderFrameHostImplWrapper rfh(current_frame_host()); |
arthursonzogni | e385b7b | 2019-09-02 11:11:53 | [diff] [blame] | 986 | |
| 987 | // 2) Navigate away. |
| 988 | hostname[0]++; |
| 989 | GURL reset_url(embedded_test_server()->GetURL(hostname, "/title1.html")); |
| 990 | EXPECT_TRUE(NavigateToURL(shell(), reset_url)); |
| 991 | |
| 992 | if (test_case.expectation == STORED) { |
Rakina Zata Amni | 348fe2b | 2021-07-09 05:28:52 | [diff] [blame] | 993 | EXPECT_FALSE(rfh.IsRenderFrameDeleted()); |
Hajime Hoshi | bbc509c | 2020-04-06 08:55:08 | [diff] [blame] | 994 | EXPECT_TRUE(rfh->IsInBackForwardCache()); |
arthursonzogni | e385b7b | 2019-09-02 11:11:53 | [diff] [blame] | 995 | continue; |
| 996 | } |
| 997 | |
Rakina Zata Amni | 348fe2b | 2021-07-09 05:28:52 | [diff] [blame] | 998 | if (rfh.get() == current_frame_host()) { |
| 999 | // If the RenderFrameHost is reused, it won't be deleted, so don't wait |
| 1000 | // for deletion. Just check that it's not saved in the back-forward cache. |
| 1001 | EXPECT_FALSE(rfh.IsRenderFrameDeleted()); |
Hajime Hoshi | bbc509c | 2020-04-06 08:55:08 | [diff] [blame] | 1002 | EXPECT_FALSE(rfh->IsInBackForwardCache()); |
arthursonzogni | e385b7b | 2019-09-02 11:11:53 | [diff] [blame] | 1003 | continue; |
| 1004 | } |
| 1005 | |
Rakina Zata Amni | 348fe2b | 2021-07-09 05:28:52 | [diff] [blame] | 1006 | // When the RenderFrameHost is not reused and it's not stored in the |
| 1007 | // back-forward cache, it will eventually be deleted. |
Fergal Daly | d52b14f | 2021-11-08 13:25:02 | [diff] [blame] | 1008 | ASSERT_TRUE(rfh.WaitUntilRenderFrameDeleted()); |
arthursonzogni | e385b7b | 2019-09-02 11:11:53 | [diff] [blame] | 1009 | } |
| 1010 | } |
| 1011 | |
arthursonzogni | 6c27c315 | 2019-09-12 08:00:57 | [diff] [blame] | 1012 | // Regression test for https://crbug.com/993337. |
Lowell Manners | cc67fc6 | 2019-10-18 10:21:47 | [diff] [blame] | 1013 | // |
| 1014 | // A note about sharing BrowsingInstances and the BackForwardCache: |
| 1015 | // |
| 1016 | // We should never keep around more than one main frame that belongs to the same |
| 1017 | // BrowsingInstance. When swapping two pages, when one is stored in the |
| 1018 | // back-forward cache or one is restored from it, the current code expects the |
| 1019 | // two to live in different BrowsingInstances. |
| 1020 | // |
| 1021 | // History navigation can recreate a page with the same BrowsingInstance as the |
| 1022 | // one stored in the back-forward cache. This case must to be handled. When it |
| 1023 | // happens, the back-forward cache page is evicted. |
| 1024 | // |
| 1025 | // Since cache eviction is asynchronous, it's is possible for two main frames |
| 1026 | // belonging to the same BrowsingInstance to be alive for a brief period of time |
| 1027 | // (the new page being navigated to, and a page in the cache, until it is |
| 1028 | // destroyed asynchronously via eviction). |
| 1029 | // |
| 1030 | // The test below tests that the brief period of time where two main frames are |
| 1031 | // alive in the same BrowsingInstance does not cause anything to blow up. |
Asami Doi | 5dd0f6b | 2021-08-23 08:27:04 | [diff] [blame] | 1032 | |
Mingyu Lei | 6ad77ef | 2023-05-23 07:13:23 | [diff] [blame] | 1033 | // TODO(crbug.com/1127979, crbug.com/1446206): Flaky on Linux, Windows and |
Ian Vollick | f5b8bdf | 2023-07-26 15:52:27 | [diff] [blame] | 1034 | // ChromeOS, iOS, and Mac. |
Brian Begnoche | 3db0d87 | 2023-07-24 17:48:33 | [diff] [blame] | 1035 | #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_WIN) || BUILDFLAG(IS_CHROMEOS) || \ |
Ian Vollick | f5b8bdf | 2023-07-26 15:52:27 | [diff] [blame] | 1036 | BUILDFLAG(IS_MAC) || BUILDFLAG(IS_IOS) |
Yuzu Saijo | 8ba605f | 2023-03-27 02:52:15 | [diff] [blame] | 1037 | #define MAYBE_NavigateToTwoPagesOnSameSite DISABLED_NavigateToTwoPagesOnSameSite |
| 1038 | #else |
| 1039 | #define MAYBE_NavigateToTwoPagesOnSameSite NavigateToTwoPagesOnSameSite |
| 1040 | #endif |
Lowell Manners | fa8d922 | 2019-09-05 09:47:03 | [diff] [blame] | 1041 | IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, |
Yuzu Saijo | 8ba605f | 2023-03-27 02:52:15 | [diff] [blame] | 1042 | MAYBE_NavigateToTwoPagesOnSameSite) { |
Lowell Manners | fa8d922 | 2019-09-05 09:47:03 | [diff] [blame] | 1043 | ASSERT_TRUE(embedded_test_server()->Start()); |
| 1044 | GURL url_a1(embedded_test_server()->GetURL("a.com", "/title1.html")); |
| 1045 | GURL url_a2(embedded_test_server()->GetURL("a.com", "/title2.html")); |
Lowell Manners | cc67fc6 | 2019-10-18 10:21:47 | [diff] [blame] | 1046 | GURL url_b3(embedded_test_server()->GetURL("b.com", "/title1.html")); |
Lowell Manners | fa8d922 | 2019-09-05 09:47:03 | [diff] [blame] | 1047 | |
| 1048 | // 1) Navigate to A1. |
| 1049 | EXPECT_TRUE(NavigateToURL(shell(), url_a1)); |
| 1050 | |
| 1051 | // 2) Navigate to A2. |
| 1052 | EXPECT_TRUE(NavigateToURL(shell(), url_a2)); |
| 1053 | RenderFrameHostImpl* rfh_a2 = current_frame_host(); |
arthursonzogni | 6c27c315 | 2019-09-12 08:00:57 | [diff] [blame] | 1054 | RenderFrameDeletedObserver delete_rfh_a2(current_frame_host()); |
Lowell Manners | fa8d922 | 2019-09-05 09:47:03 | [diff] [blame] | 1055 | |
Lowell Manners | cc67fc6 | 2019-10-18 10:21:47 | [diff] [blame] | 1056 | // 3) Navigate to B3. |
| 1057 | EXPECT_TRUE(NavigateToURL(shell(), url_b3)); |
Hajime Hoshi | bbc509c | 2020-04-06 08:55:08 | [diff] [blame] | 1058 | EXPECT_TRUE(rfh_a2->IsInBackForwardCache()); |
Lowell Manners | cc67fc6 | 2019-10-18 10:21:47 | [diff] [blame] | 1059 | RenderFrameHostImpl* rfh_b3 = current_frame_host(); |
Lowell Manners | fa8d922 | 2019-09-05 09:47:03 | [diff] [blame] | 1060 | |
| 1061 | // 4) Do a history navigation back to A1. |
Fergal Daly | 5495b0e | 2021-11-19 02:03:28 | [diff] [blame] | 1062 | ASSERT_TRUE(HistoryGoToIndex(web_contents(), 0)); |
Hajime Hoshi | bbc509c | 2020-04-06 08:55:08 | [diff] [blame] | 1063 | EXPECT_TRUE(rfh_b3->IsInBackForwardCache()); |
arthursonzogni | 6c27c315 | 2019-09-12 08:00:57 | [diff] [blame] | 1064 | |
Lowell Manners | cc67fc6 | 2019-10-18 10:21:47 | [diff] [blame] | 1065 | // Note that the frame for A1 gets created before A2 is deleted from the |
| 1066 | // cache, so there will be a brief period where two the main frames (A1 and |
| 1067 | // A2) are alive in the same BrowsingInstance/SiteInstance, at the same time. |
| 1068 | // That is the scenario this test is covering. This used to cause a CHECK, |
| 1069 | // because the two main frames shared a single RenderViewHost (no longer the |
| 1070 | // case after https://crrev.com/c/1833616). |
| 1071 | |
| 1072 | // A2 should be evicted from the cache and asynchronously deleted, due to the |
| 1073 | // cache size limit (B3 took its place in the cache). |
arthursonzogni | 6c27c315 | 2019-09-12 08:00:57 | [diff] [blame] | 1074 | delete_rfh_a2.WaitUntilDeleted(); |
Lowell Manners | fa8d922 | 2019-09-05 09:47:03 | [diff] [blame] | 1075 | } |
Kouhei Ueno | 7b6f3cd0 | 2019-09-09 04:48:50 | [diff] [blame] | 1076 | |
Lowell Manners | cc67fc6 | 2019-10-18 10:21:47 | [diff] [blame] | 1077 | IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, |
| 1078 | NavigateToTwoPagesOnSameSiteWithSubframes) { |
| 1079 | ASSERT_TRUE(embedded_test_server()->Start()); |
| 1080 | // This test covers the same scenario as NavigateToTwoPagesOnSameSite, except |
| 1081 | // the pages contain subframes: |
| 1082 | // A1(B) -> A2(B(C)) -> D3 -> A1(B) |
| 1083 | // |
| 1084 | // The subframes shouldn't make a difference, so the expected behavior is the |
| 1085 | // same as NavigateToTwoPagesOnSameSite. |
| 1086 | GURL url_a1(embedded_test_server()->GetURL( |
| 1087 | "a.com", "/cross_site_iframe_factory.html?a(b)")); |
| 1088 | GURL url_a2(embedded_test_server()->GetURL( |
| 1089 | "a.com", "/cross_site_iframe_factory.html?a(b(c))")); |
| 1090 | GURL url_d3(embedded_test_server()->GetURL("d.com", "/title1.html")); |
| 1091 | |
| 1092 | // 1) Navigate to A1(B). |
| 1093 | EXPECT_TRUE(NavigateToURL(shell(), url_a1)); |
| 1094 | |
| 1095 | // 2) Navigate to A2(B(C)). |
| 1096 | EXPECT_TRUE(NavigateToURL(shell(), url_a2)); |
| 1097 | RenderFrameHostImpl* rfh_a2 = current_frame_host(); |
| 1098 | RenderFrameDeletedObserver delete_rfh_a2(current_frame_host()); |
| 1099 | |
| 1100 | // 3) Navigate to D3. |
| 1101 | EXPECT_TRUE(NavigateToURL(shell(), url_d3)); |
Hajime Hoshi | bbc509c | 2020-04-06 08:55:08 | [diff] [blame] | 1102 | EXPECT_TRUE(rfh_a2->IsInBackForwardCache()); |
Lowell Manners | cc67fc6 | 2019-10-18 10:21:47 | [diff] [blame] | 1103 | RenderFrameHostImpl* rfh_d3 = current_frame_host(); |
| 1104 | |
| 1105 | // 4) Do a history navigation back to A1(B). |
Fergal Daly | 5495b0e | 2021-11-19 02:03:28 | [diff] [blame] | 1106 | ASSERT_TRUE(HistoryGoToIndex(web_contents(), 0)); |
Lowell Manners | cc67fc6 | 2019-10-18 10:21:47 | [diff] [blame] | 1107 | |
| 1108 | // D3 takes A2(B(C))'s place in the cache. |
Hajime Hoshi | bbc509c | 2020-04-06 08:55:08 | [diff] [blame] | 1109 | EXPECT_TRUE(rfh_d3->IsInBackForwardCache()); |
Lowell Manners | cc67fc6 | 2019-10-18 10:21:47 | [diff] [blame] | 1110 | delete_rfh_a2.WaitUntilDeleted(); |
| 1111 | } |
| 1112 | |
Sreeja Kamishetty | 299329ad | 2021-03-25 14:06:01 | [diff] [blame] | 1113 | // Sub-frame doesn't transition from LifecycleStateImpl::kInBackForwardCache to |
| 1114 | // LifecycleStateImpl::kRunningUnloadHandlers even when the sub-frame having |
| 1115 | // unload handlers is being evicted from BackForwardCache. |
Fergal Daly | 97c4e59 | 2023-02-28 10:27:33 | [diff] [blame] | 1116 | IN_PROC_BROWSER_TEST_F(BackForwardCacheUnloadBrowserTest, |
| 1117 | SubframeWithUnloadHandler) { |
Sreeja Kamishetty | 9bcdc97 | 2020-10-23 13:33:21 | [diff] [blame] | 1118 | ASSERT_TRUE(embedded_test_server()->Start()); |
| 1119 | GURL main_url(embedded_test_server()->GetURL( |
| 1120 | "a.com", "/cross_site_iframe_factory.html?a.com(a.com)")); |
| 1121 | GURL child_url = embedded_test_server()->GetURL( |
| 1122 | "a.com", "/cross_site_iframe_factory.html?a.com()"); |
| 1123 | GURL url_2(embedded_test_server()->GetURL("a.com", "/title1.html")); |
| 1124 | |
| 1125 | // 1) Navigate to |main_url|. |
| 1126 | EXPECT_TRUE(NavigateToURL(shell(), main_url)); |
| 1127 | RenderFrameHostImpl* main_rfh = current_frame_host(); |
| 1128 | ASSERT_EQ(1U, main_rfh->child_count()); |
| 1129 | RenderFrameHostImpl* child_rfh = main_rfh->child_at(0)->current_frame_host(); |
| 1130 | RenderFrameDeletedObserver main_rfh_observer(main_rfh), |
| 1131 | child_rfh_observer(child_rfh); |
| 1132 | |
| 1133 | // 2) Add an unload handler to the child RFH. |
| 1134 | EXPECT_TRUE(ExecJs(child_rfh, "window.onunload = () => {} ")); |
| 1135 | |
| 1136 | // 3) Navigate to |url_2|. |
| 1137 | EXPECT_TRUE(NavigateToURL(shell(), url_2)); |
| 1138 | |
| 1139 | // 4) The previous main RFH and child RFH should be in the back-forward |
| 1140 | // cache. |
| 1141 | EXPECT_FALSE(main_rfh_observer.deleted()); |
| 1142 | EXPECT_FALSE(child_rfh_observer.deleted()); |
| 1143 | EXPECT_TRUE(main_rfh->IsInBackForwardCache()); |
| 1144 | EXPECT_TRUE(child_rfh->IsInBackForwardCache()); |
| 1145 | |
| 1146 | // Destruction of bfcached page happens after shutdown and it should not |
| 1147 | // trigger unload handlers and be destroyed directly. |
| 1148 | } |
| 1149 | |
Carlos Caballero | 2380e02 | 2019-10-30 18:27:18 | [diff] [blame] | 1150 | // Do a same document navigation and make sure we do not fire the |
| 1151 | // DidFirstVisuallyNonEmptyPaint again |
Carlos Caballero | 91fffb2 | 2019-10-29 15:24:30 | [diff] [blame] | 1152 | IN_PROC_BROWSER_TEST_F( |
| 1153 | BackForwardCacheBrowserTest, |
Georg Neis | 0dce333 | 2024-12-13 01:51:18 | [diff] [blame] | 1154 | DoesNotFireDidFirstVisuallyNonEmptyPaintForSameDocumentNavigation) { |
Carlos Caballero | 91fffb2 | 2019-10-29 15:24:30 | [diff] [blame] | 1155 | ASSERT_TRUE(embedded_test_server()->Start()); |
arthursonzogni | 72b6649 | 2019-11-04 12:24:33 | [diff] [blame] | 1156 | GURL url_a_1(embedded_test_server()->GetURL( |
Carlos Caballero | 91fffb2 | 2019-10-29 15:24:30 | [diff] [blame] | 1157 | "a.com", "/accessibility/html/a-name.html")); |
arthursonzogni | 72b6649 | 2019-11-04 12:24:33 | [diff] [blame] | 1158 | GURL url_a_2(embedded_test_server()->GetURL( |
Carlos Caballero | 91fffb2 | 2019-10-29 15:24:30 | [diff] [blame] | 1159 | "a.com", "/accessibility/html/a-name.html#id")); |
Carlos Caballero | 91fffb2 | 2019-10-29 15:24:30 | [diff] [blame] | 1160 | |
| 1161 | EXPECT_TRUE(NavigateToURL(shell(), url_a_1)); |
| 1162 | WaitForFirstVisuallyNonEmptyPaint(shell()->web_contents()); |
Carlos Caballero | 91fffb2 | 2019-10-29 15:24:30 | [diff] [blame] | 1163 | |
| 1164 | FirstVisuallyNonEmptyPaintObserver observer(web_contents()); |
| 1165 | EXPECT_TRUE(NavigateToURL(shell(), url_a_2)); |
| 1166 | // Make sure the bfcache restore code does not fire the event during commit |
| 1167 | // navigation. |
| 1168 | EXPECT_FALSE(observer.did_fire()); |
Carlos Caballero | 2380e02 | 2019-10-30 18:27:18 | [diff] [blame] | 1169 | EXPECT_TRUE(web_contents()->CompletedFirstVisuallyNonEmptyPaint()); |
Carlos Caballero | 91fffb2 | 2019-10-29 15:24:30 | [diff] [blame] | 1170 | } |
| 1171 | |
| 1172 | // Make sure we fire DidFirstVisuallyNonEmptyPaint when restoring from bf-cache. |
Brian Begnoche | bc623f3 | 2024-02-27 17:46:19 | [diff] [blame] | 1173 | // TODO(crbug.com/327195951): Re-enable this test |
Georg Neis | 0dce333 | 2024-12-13 01:51:18 | [diff] [blame] | 1174 | #if BUILDFLAG(IS_ANDROID) |
Brian Begnoche | bc623f3 | 2024-02-27 17:46:19 | [diff] [blame] | 1175 | #define MAYBE_FiresDidFirstVisuallyNonEmptyPaintWhenRestoredFromCache \ |
| 1176 | DISABLED_FiresDidFirstVisuallyNonEmptyPaintWhenRestoredFromCache |
| 1177 | #else |
| 1178 | #define MAYBE_FiresDidFirstVisuallyNonEmptyPaintWhenRestoredFromCache \ |
| 1179 | FiresDidFirstVisuallyNonEmptyPaintWhenRestoredFromCache |
| 1180 | #endif |
Carlos Caballero | 91fffb2 | 2019-10-29 15:24:30 | [diff] [blame] | 1181 | IN_PROC_BROWSER_TEST_F( |
| 1182 | BackForwardCacheBrowserTest, |
Brian Begnoche | bc623f3 | 2024-02-27 17:46:19 | [diff] [blame] | 1183 | MAYBE_FiresDidFirstVisuallyNonEmptyPaintWhenRestoredFromCache) { |
Carlos Caballero | 91fffb2 | 2019-10-29 15:24:30 | [diff] [blame] | 1184 | ASSERT_TRUE(embedded_test_server()->Start()); |
arthursonzogni | 72b6649 | 2019-11-04 12:24:33 | [diff] [blame] | 1185 | GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html")); |
| 1186 | GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html")); |
Carlos Caballero | 91fffb2 | 2019-10-29 15:24:30 | [diff] [blame] | 1187 | |
| 1188 | // 1) Navigate to A. |
Fergal Daly | a4dde50d | 2022-10-14 07:29:25 | [diff] [blame] | 1189 | ASSERT_TRUE(NavigateToURL(shell(), url_a)); |
Carlos Caballero | 91fffb2 | 2019-10-29 15:24:30 | [diff] [blame] | 1190 | WaitForFirstVisuallyNonEmptyPaint(shell()->web_contents()); |
| 1191 | RenderFrameHostImpl* rfh_a = current_frame_host(); |
Carlos Caballero | ddf98dc | 2019-10-30 19:00:47 | [diff] [blame] | 1192 | RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a); |
Carlos Caballero | 91fffb2 | 2019-10-29 15:24:30 | [diff] [blame] | 1193 | |
| 1194 | // 2) Navigate to B. |
Fergal Daly | a4dde50d | 2022-10-14 07:29:25 | [diff] [blame] | 1195 | ASSERT_TRUE(NavigateToURL(shell(), url_b)); |
Carlos Caballero | ddf98dc | 2019-10-30 19:00:47 | [diff] [blame] | 1196 | ASSERT_FALSE(delete_observer_rfh_a.deleted()); |
Fergal Daly | a4dde50d | 2022-10-14 07:29:25 | [diff] [blame] | 1197 | ASSERT_TRUE(rfh_a->IsInBackForwardCache()); |
Carlos Caballero | 91fffb2 | 2019-10-29 15:24:30 | [diff] [blame] | 1198 | WaitForFirstVisuallyNonEmptyPaint(shell()->web_contents()); |
| 1199 | |
| 1200 | // 3) Navigate to back to A. |
| 1201 | FirstVisuallyNonEmptyPaintObserver observer(web_contents()); |
Fergal Daly | 5495b0e | 2021-11-19 02:03:28 | [diff] [blame] | 1202 | ASSERT_TRUE(HistoryGoBack(web_contents())); |
Carlos Caballero | 91fffb2 | 2019-10-29 15:24:30 | [diff] [blame] | 1203 | // Make sure the bfcache restore code does fire the event during commit |
| 1204 | // navigation. |
| 1205 | EXPECT_TRUE(web_contents()->CompletedFirstVisuallyNonEmptyPaint()); |
| 1206 | EXPECT_TRUE(observer.did_fire()); |
| 1207 | } |
Georg Neis | 0dce333 | 2024-12-13 01:51:18 | [diff] [blame] | 1208 | #if BUILDFLAG(IS_ANDROID) |
Takumi Fujimoto | 24fbc77f | 2024-03-22 06:42:08 | [diff] [blame] | 1209 | #define MAYBE_SetsThemeColorWhenRestoredFromCache \ |
| 1210 | DISABLED_SetsThemeColorWhenRestoredFromCache |
| 1211 | #else |
| 1212 | #define MAYBE_SetsThemeColorWhenRestoredFromCache \ |
| 1213 | SetsThemeColorWhenRestoredFromCache |
| 1214 | #endif |
Carlos Caballero | 1215f88 | 2019-10-29 15:58:43 | [diff] [blame] | 1215 | IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, |
Takumi Fujimoto | 24fbc77f | 2024-03-22 06:42:08 | [diff] [blame] | 1216 | MAYBE_SetsThemeColorWhenRestoredFromCache) { |
Carlos Caballero | 1215f88 | 2019-10-29 15:58:43 | [diff] [blame] | 1217 | ASSERT_TRUE(embedded_test_server()->Start()); |
arthursonzogni | 72b6649 | 2019-11-04 12:24:33 | [diff] [blame] | 1218 | GURL url_a(embedded_test_server()->GetURL("a.com", "/theme_color.html")); |
| 1219 | GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html")); |
Carlos Caballero | 1215f88 | 2019-10-29 15:58:43 | [diff] [blame] | 1220 | |
Fergal Daly | a4dde50d | 2022-10-14 07:29:25 | [diff] [blame] | 1221 | ASSERT_TRUE(NavigateToURL(shell(), url_a)); |
Carlos Caballero | 1215f88 | 2019-10-29 15:58:43 | [diff] [blame] | 1222 | WaitForFirstVisuallyNonEmptyPaint(web_contents()); |
Fergal Daly | a4dde50d | 2022-10-14 07:29:25 | [diff] [blame] | 1223 | RenderFrameHostImplWrapper rfh_a(current_frame_host()); |
Carlos Caballero | 1215f88 | 2019-10-29 15:58:43 | [diff] [blame] | 1224 | EXPECT_EQ(web_contents()->GetThemeColor(), 0xFFFF0000u); |
| 1225 | |
Fergal Daly | a4dde50d | 2022-10-14 07:29:25 | [diff] [blame] | 1226 | ASSERT_TRUE(NavigateToURL(shell(), url_b)); |
Carlos Caballero | 1215f88 | 2019-10-29 15:58:43 | [diff] [blame] | 1227 | WaitForFirstVisuallyNonEmptyPaint(web_contents()); |
Fergal Daly | a4dde50d | 2022-10-14 07:29:25 | [diff] [blame] | 1228 | ASSERT_TRUE(rfh_a->IsInBackForwardCache()); |
Arthur Sonzogni | c686e8f | 2024-01-11 08:36:37 | [diff] [blame] | 1229 | EXPECT_EQ(web_contents()->GetThemeColor(), std::nullopt); |
Carlos Caballero | 1215f88 | 2019-10-29 15:58:43 | [diff] [blame] | 1230 | |
| 1231 | ThemeColorObserver observer(web_contents()); |
Fergal Daly | 5495b0e | 2021-11-19 02:03:28 | [diff] [blame] | 1232 | ASSERT_TRUE(HistoryGoBack(web_contents())); |
Fergal Daly | a4dde50d | 2022-10-14 07:29:25 | [diff] [blame] | 1233 | ASSERT_TRUE(observer.WaitUntilThemeColorChange()); |
Carlos Caballero | 1215f88 | 2019-10-29 15:58:43 | [diff] [blame] | 1234 | EXPECT_EQ(web_contents()->GetThemeColor(), 0xFFFF0000u); |
| 1235 | } |
| 1236 | |
Yuzu Saijo | 40aa84e7 | 2020-05-28 07:18:28 | [diff] [blame] | 1237 | IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, |
| 1238 | ContentsMimeTypeWhenRestoredFromCache) { |
| 1239 | ASSERT_TRUE(embedded_test_server()->Start()); |
| 1240 | GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html")); |
| 1241 | GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html")); |
| 1242 | |
| 1243 | // Navigate to A. |
| 1244 | EXPECT_TRUE(NavigateToURL(shell(), url_a)); |
| 1245 | RenderFrameHostImpl* rfh_a = current_frame_host(); |
| 1246 | RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a); |
| 1247 | EXPECT_EQ(web_contents()->GetContentsMimeType(), "text/html"); |
| 1248 | |
| 1249 | // Navigate to B. |
| 1250 | EXPECT_TRUE(NavigateToURL(shell(), url_b)); |
| 1251 | ASSERT_FALSE(delete_observer_rfh_a.deleted()); |
| 1252 | EXPECT_TRUE(rfh_a->IsInBackForwardCache()); |
| 1253 | |
| 1254 | // Go back to A, which restores A from bfcache. ContentsMimeType should be |
| 1255 | // restored as well. |
Fergal Daly | 5495b0e | 2021-11-19 02:03:28 | [diff] [blame] | 1256 | ASSERT_TRUE(HistoryGoBack(web_contents())); |
Yuzu Saijo | 40aa84e7 | 2020-05-28 07:18:28 | [diff] [blame] | 1257 | EXPECT_EQ(rfh_a, current_frame_host()); |
Fergal Daly | 0983306 | 2021-02-09 07:10:00 | [diff] [blame] | 1258 | ExpectRestored(FROM_HERE); |
Yuzu Saijo | 40aa84e7 | 2020-05-28 07:18:28 | [diff] [blame] | 1259 | EXPECT_EQ(web_contents()->GetContentsMimeType(), "text/html"); |
| 1260 | } |
| 1261 | |
Sreeja Kamishetty | 92006e0 | 2021-02-05 05:18:11 | [diff] [blame] | 1262 | // Check BackForwardCache is enabled and works for devices with very low memory. |
| 1263 | // Navigate from A -> B and go back. |
| 1264 | IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, |
| 1265 | BackForwardCacheEnabledOnLowMemoryDevices) { |
| 1266 | // Set device physical memory to 10 MB. |
| 1267 | blink::ApproximatedDeviceMemory::SetPhysicalMemoryMBForTesting(10); |
| 1268 | ASSERT_TRUE(embedded_test_server()->Start()); |
| 1269 | GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html")); |
| 1270 | GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html")); |
| 1271 | |
| 1272 | // 1) Navigate to A. |
| 1273 | EXPECT_TRUE(NavigateToURL(shell(), url_a)); |
| 1274 | RenderFrameDeletedObserver delete_observer_rfh_a(current_frame_host()); |
| 1275 | RenderFrameHostImpl* rfh_a = current_frame_host(); |
| 1276 | |
| 1277 | // 2) Navigate to B. A should be in BackForwardCache. |
| 1278 | EXPECT_TRUE(NavigateToURL(shell(), url_b)); |
| 1279 | RenderFrameHostImpl* rfh_b = current_frame_host(); |
| 1280 | RenderFrameDeletedObserver delete_observer_rfh_b(rfh_b); |
| 1281 | EXPECT_FALSE(delete_observer_rfh_a.deleted()); |
| 1282 | EXPECT_TRUE(rfh_a->IsInBackForwardCache()); |
| 1283 | |
| 1284 | // 3) Go back to A. B should be in BackForwardCache. |
Fergal Daly | 5495b0e | 2021-11-19 02:03:28 | [diff] [blame] | 1285 | ASSERT_TRUE(HistoryGoBack(web_contents())); |
Sreeja Kamishetty | 92006e0 | 2021-02-05 05:18:11 | [diff] [blame] | 1286 | EXPECT_FALSE(delete_observer_rfh_b.deleted()); |
| 1287 | EXPECT_TRUE(rfh_b->IsInBackForwardCache()); |
| 1288 | } |
| 1289 | |
[email protected] | 54eaf62 | 2019-11-25 12:36:03 | [diff] [blame] | 1290 | // Test for functionality of memory controls in back-forward cache for low |
| 1291 | // memory devices. |
| 1292 | class BackForwardCacheBrowserTestForLowMemoryDevices |
| 1293 | : public BackForwardCacheBrowserTest { |
| 1294 | protected: |
| 1295 | void SetUpCommandLine(base::CommandLine* command_line) override { |
Sreeja Kamishetty | 92006e0 | 2021-02-05 05:18:11 | [diff] [blame] | 1296 | BackForwardCacheBrowserTest::SetUpCommandLine(command_line); |
| 1297 | |
[email protected] | 54eaf62 | 2019-11-25 12:36:03 | [diff] [blame] | 1298 | // Set the value of memory threshold more than the physical memory and check |
| 1299 | // if back-forward cache is disabled or not. |
François Doray | 9cee804 | 2025-08-15 19:02:55 | [diff] [blame] | 1300 | std::string memory_threshold = base::NumberToString( |
| 1301 | base::SysInfo::AmountOfPhysicalMemory().InMiB() + 1); |
Sreeja Kamishetty | 92006e0 | 2021-02-05 05:18:11 | [diff] [blame] | 1302 | scoped_feature_list_.InitWithFeaturesAndParameters( |
John Abd-El-Malek | 3c868c29 | 2021-02-19 20:00:09 | [diff] [blame] | 1303 | {{features::kBackForwardCacheMemoryControls, |
Sreeja Kamishetty | 92006e0 | 2021-02-05 05:18:11 | [diff] [blame] | 1304 | {{"memory_threshold_for_back_forward_cache_in_mb", |
Rakina Zata Amni | b6b7f7bf | 2021-02-12 10:25:39 | [diff] [blame] | 1305 | memory_threshold}}}, |
| 1306 | {blink::features::kLoadingTasksUnfreezable, {}}}, |
Sreeja Kamishetty | 92006e0 | 2021-02-05 05:18:11 | [diff] [blame] | 1307 | {}); |
[email protected] | 54eaf62 | 2019-11-25 12:36:03 | [diff] [blame] | 1308 | } |
Sreeja Kamishetty | 92006e0 | 2021-02-05 05:18:11 | [diff] [blame] | 1309 | |
| 1310 | private: |
| 1311 | base::test::ScopedFeatureList scoped_feature_list_; |
[email protected] | 54eaf62 | 2019-11-25 12:36:03 | [diff] [blame] | 1312 | }; |
| 1313 | |
Nathan Memmott | b2aa5665 | 2024-12-11 02:17:53 | [diff] [blame] | 1314 | // Ensure that the BackForwardCache trial is not activated as expected on |
Rakina Zata Amni | 454f5a90 | 2022-05-31 06:18:02 | [diff] [blame] | 1315 | // low-memory devices. |
[email protected] | 54eaf62 | 2019-11-25 12:36:03 | [diff] [blame] | 1316 | IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTestForLowMemoryDevices, |
| 1317 | DisableBFCacheForLowEndDevices) { |
[email protected] | 54eaf62 | 2019-11-25 12:36:03 | [diff] [blame] | 1318 | ASSERT_TRUE(embedded_test_server()->Start()); |
Alexander Timin | 3e88b8f | 2019-12-16 16:32:20 | [diff] [blame] | 1319 | GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html")); |
| 1320 | GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html")); |
[email protected] | 54eaf62 | 2019-11-25 12:36:03 | [diff] [blame] | 1321 | |
Nathan Memmott | b2aa5665 | 2024-12-11 02:17:53 | [diff] [blame] | 1322 | // Ensure that the BackForwardCache trial starts inactive. |
Alexander Timin | ddc4931 | 2020-02-28 15:24:19 | [diff] [blame] | 1323 | EXPECT_FALSE(base::FieldTrialList::IsTrialActive( |
| 1324 | base::FeatureList::GetFieldTrial(features::kBackForwardCache) |
| 1325 | ->trial_name())); |
| 1326 | |
| 1327 | EXPECT_FALSE(IsBackForwardCacheEnabled()); |
| 1328 | |
Rakina Zata Amni | 454f5a90 | 2022-05-31 06:18:02 | [diff] [blame] | 1329 | // Ensure that we do not activate the BackForwardCache trial when querying |
Nathan Memmott | b2aa5665 | 2024-12-11 02:17:53 | [diff] [blame] | 1330 | // bfcache status. |
Alexander Timin | ddc4931 | 2020-02-28 15:24:19 | [diff] [blame] | 1331 | EXPECT_FALSE(base::FieldTrialList::IsTrialActive( |
| 1332 | base::FeatureList::GetFieldTrial(features::kBackForwardCache) |
| 1333 | ->trial_name())); |
| 1334 | |
[email protected] | 54eaf62 | 2019-11-25 12:36:03 | [diff] [blame] | 1335 | // 1) Navigate to A. |
| 1336 | EXPECT_TRUE(NavigateToURL(shell(), url_a)); |
| 1337 | RenderFrameHostImpl* rfh_a = current_frame_host(); |
| 1338 | RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a); |
| 1339 | |
| 1340 | // 2) Navigate to B. |
| 1341 | EXPECT_TRUE(NavigateToURL(shell(), url_b)); |
| 1342 | |
| 1343 | // 3) A shouldn't be stored in back-forward cache because the physical |
| 1344 | // memory is less than the memory threshold. |
| 1345 | delete_observer_rfh_a.WaitUntilDeleted(); |
| 1346 | |
Rakina Zata Amni | 454f5a90 | 2022-05-31 06:18:02 | [diff] [blame] | 1347 | // 4) Go back to check the |
| 1348 | // NotRestoredReasons.kBackForwardCacheDisabledByLowMemory is recorded when |
| 1349 | // the memory is less than the threshold value. |
| 1350 | ASSERT_TRUE(HistoryGoBack(web_contents())); |
Alexander Timin | ddc4931 | 2020-02-28 15:24:19 | [diff] [blame] | 1351 | |
Rakina Zata Amni | 454f5a90 | 2022-05-31 06:18:02 | [diff] [blame] | 1352 | ExpectNotRestored( |
| 1353 | { |
| 1354 | BackForwardCacheMetrics::NotRestoredReason::kBackForwardCacheDisabled, |
| 1355 | BackForwardCacheMetrics::NotRestoredReason:: |
| 1356 | kBackForwardCacheDisabledByLowMemory, |
| 1357 | }, |
| 1358 | {}, {}, {}, {}, FROM_HERE); |
| 1359 | |
Nathan Memmott | b2aa5665 | 2024-12-11 02:17:53 | [diff] [blame] | 1360 | // Ensure that the BackForwardCache trial still hasn't been activated. |
Alexander Timin | ddc4931 | 2020-02-28 15:24:19 | [diff] [blame] | 1361 | EXPECT_FALSE(base::FieldTrialList::IsTrialActive( |
| 1362 | base::FeatureList::GetFieldTrial(features::kBackForwardCache) |
| 1363 | ->trial_name())); |
[email protected] | 54eaf62 | 2019-11-25 12:36:03 | [diff] [blame] | 1364 | } |
| 1365 | |
Rakina Zata Amni | b6b7f7bf | 2021-02-12 10:25:39 | [diff] [blame] | 1366 | // Trigger network reqeuests, then navigate from A to B, then go back. |
| 1367 | IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTestForLowMemoryDevices, |
Rakina Zata Amni | eaf87b7 | 2021-03-02 02:04:35 | [diff] [blame] | 1368 | DisableBFCacheForLowEndDevices_NetworkRequests) { |
Rakina Zata Amni | b6b7f7bf | 2021-02-12 10:25:39 | [diff] [blame] | 1369 | net::test_server::ControllableHttpResponse image_response( |
| 1370 | embedded_test_server(), "/image.png"); |
| 1371 | ASSERT_TRUE(embedded_test_server()->Start()); |
| 1372 | GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html")); |
| 1373 | GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html")); |
| 1374 | |
| 1375 | // Ensure that the trials starts inactive. |
| 1376 | EXPECT_FALSE(base::FieldTrialList::IsTrialActive( |
| 1377 | base::FeatureList::GetFieldTrial(features::kBackForwardCache) |
| 1378 | ->trial_name())); |
| 1379 | EXPECT_FALSE(base::FieldTrialList::IsTrialActive( |
| 1380 | base::FeatureList::GetFieldTrial( |
| 1381 | blink::features::kLoadingTasksUnfreezable) |
| 1382 | ->trial_name())); |
| 1383 | |
| 1384 | EXPECT_FALSE(IsBackForwardCacheEnabled()); |
| 1385 | |
| 1386 | // Ensure that we do not activate the trials for kBackForwardCache and |
| 1387 | // kLoadingTasksUnfreezable when querying bfcache or unfreezable loading tasks |
| 1388 | // status. |
| 1389 | EXPECT_FALSE(base::FieldTrialList::IsTrialActive( |
| 1390 | base::FeatureList::GetFieldTrial(features::kBackForwardCache) |
| 1391 | ->trial_name())); |
| 1392 | EXPECT_FALSE(base::FieldTrialList::IsTrialActive( |
| 1393 | base::FeatureList::GetFieldTrial( |
| 1394 | blink::features::kLoadingTasksUnfreezable) |
| 1395 | ->trial_name())); |
| 1396 | |
| 1397 | // 1) Navigate to A. |
| 1398 | EXPECT_TRUE(NavigateToURL(shell(), url_a)); |
| 1399 | RenderFrameHostImpl* rfh_a = current_frame_host(); |
| 1400 | RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a); |
| 1401 | |
| 1402 | // Request for an image and send a response to trigger loading code. This is |
| 1403 | // to ensure kLoadingTasksUnfreezable won't trigger bfcache activation. |
| 1404 | EXPECT_TRUE(ExecJs(rfh_a, R"( |
| 1405 | var image = document.createElement("img"); |
| 1406 | image.src = "image.png"; |
| 1407 | document.body.appendChild(image); |
| 1408 | )")); |
| 1409 | image_response.WaitForRequest(); |
| 1410 | image_response.Send(net::HTTP_OK, "image/png"); |
| 1411 | image_response.Send("image_body"); |
| 1412 | image_response.Done(); |
| 1413 | |
| 1414 | // 2) Navigate to B. |
| 1415 | EXPECT_TRUE(NavigateToURL(shell(), url_b)); |
| 1416 | |
| 1417 | // 3) A shouldn't be stored in back-forward cache because the physical |
| 1418 | // memory is less than the memory threshold. |
| 1419 | delete_observer_rfh_a.WaitUntilDeleted(); |
| 1420 | |
| 1421 | // Nothing is recorded when the memory is less than the threshold value. |
| 1422 | ExpectOutcomeDidNotChange(FROM_HERE); |
| 1423 | ExpectNotRestoredDidNotChange(FROM_HERE); |
| 1424 | |
| 1425 | // Ensure that the trials still haven't been activated. |
| 1426 | EXPECT_FALSE(base::FieldTrialList::IsTrialActive( |
| 1427 | base::FeatureList::GetFieldTrial(features::kBackForwardCache) |
| 1428 | ->trial_name())); |
| 1429 | EXPECT_FALSE(base::FieldTrialList::IsTrialActive( |
| 1430 | base::FeatureList::GetFieldTrial( |
| 1431 | blink::features::kLoadingTasksUnfreezable) |
| 1432 | ->trial_name())); |
| 1433 | } |
| 1434 | |
[email protected] | 54eaf62 | 2019-11-25 12:36:03 | [diff] [blame] | 1435 | // Test for functionality of memory controls in back-forward cache for high |
| 1436 | // memory devices. |
| 1437 | class BackForwardCacheBrowserTestForHighMemoryDevices |
| 1438 | : public BackForwardCacheBrowserTest { |
| 1439 | protected: |
| 1440 | void SetUpCommandLine(base::CommandLine* command_line) override { |
Rakina Zata Amni | 454f5a90 | 2022-05-31 06:18:02 | [diff] [blame] | 1441 | BackForwardCacheBrowserTest::SetUpCommandLine(command_line); |
| 1442 | |
[email protected] | 54eaf62 | 2019-11-25 12:36:03 | [diff] [blame] | 1443 | // Set the value of memory threshold less than the physical memory and check |
| 1444 | // if back-forward cache is enabled or not. |
François Doray | 9cee804 | 2025-08-15 19:02:55 | [diff] [blame] | 1445 | std::string memory_threshold = base::NumberToString( |
| 1446 | base::SysInfo::AmountOfPhysicalMemory().InMiB() - 1); |
Rakina Zata Amni | 454f5a90 | 2022-05-31 06:18:02 | [diff] [blame] | 1447 | scoped_feature_list_.InitWithFeaturesAndParameters( |
| 1448 | {{features::kBackForwardCacheMemoryControls, |
| 1449 | {{"memory_threshold_for_back_forward_cache_in_mb", |
| 1450 | memory_threshold}}}, |
Rakina Zata Amni | 454f5a90 | 2022-05-31 06:18:02 | [diff] [blame] | 1451 | {blink::features::kLoadingTasksUnfreezable, {}}}, |
| 1452 | {}); |
[email protected] | 54eaf62 | 2019-11-25 12:36:03 | [diff] [blame] | 1453 | } |
Rakina Zata Amni | 454f5a90 | 2022-05-31 06:18:02 | [diff] [blame] | 1454 | |
| 1455 | private: |
| 1456 | base::test::ScopedFeatureList scoped_feature_list_; |
[email protected] | 54eaf62 | 2019-11-25 12:36:03 | [diff] [blame] | 1457 | }; |
| 1458 | |
Nathan Memmott | b2aa5665 | 2024-12-11 02:17:53 | [diff] [blame] | 1459 | // Ensure that the BackForwardCache trial got activated as expected on |
| 1460 | // high-memory devices when the BackForwardCache feature is enabled. |
[email protected] | 54eaf62 | 2019-11-25 12:36:03 | [diff] [blame] | 1461 | IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTestForHighMemoryDevices, |
| 1462 | EnableBFCacheForHighMemoryDevices) { |
Nathan Memmott | b2aa5665 | 2024-12-11 02:17:53 | [diff] [blame] | 1463 | // Ensure that the BackForwardCache trial starts active on high-memory devices |
| 1464 | // when the BackForwardCache feature is enabled, because |
| 1465 | // IsBackForwardCacheEnabled() got queried already before the test starts. |
Rakina Zata Amni | 454f5a90 | 2022-05-31 06:18:02 | [diff] [blame] | 1466 | EXPECT_TRUE(base::FieldTrialList::IsTrialActive( |
| 1467 | base::FeatureList::GetFieldTrial(features::kBackForwardCache) |
| 1468 | ->trial_name())); |
Rakina Zata Amni | 454f5a90 | 2022-05-31 06:18:02 | [diff] [blame] | 1469 | |
| 1470 | EXPECT_TRUE(IsBackForwardCacheEnabled()); |
| 1471 | |
Nathan Memmott | b2aa5665 | 2024-12-11 02:17:53 | [diff] [blame] | 1472 | // Ensure that the BackForwardCache trial stays active after querying |
| 1473 | // IsBackForwardCacheEnabled(). |
Rakina Zata Amni | 454f5a90 | 2022-05-31 06:18:02 | [diff] [blame] | 1474 | EXPECT_TRUE(base::FieldTrialList::IsTrialActive( |
| 1475 | base::FeatureList::GetFieldTrial(features::kBackForwardCache) |
| 1476 | ->trial_name())); |
Rakina Zata Amni | 454f5a90 | 2022-05-31 06:18:02 | [diff] [blame] | 1477 | |
[email protected] | 54eaf62 | 2019-11-25 12:36:03 | [diff] [blame] | 1478 | ASSERT_TRUE(embedded_test_server()->Start()); |
Alexander Timin | 3e88b8f | 2019-12-16 16:32:20 | [diff] [blame] | 1479 | GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html")); |
| 1480 | GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html")); |
[email protected] | 54eaf62 | 2019-11-25 12:36:03 | [diff] [blame] | 1481 | |
| 1482 | // 1) Navigate to A. |
| 1483 | EXPECT_TRUE(NavigateToURL(shell(), url_a)); |
| 1484 | RenderFrameHostImpl* rfh_a = current_frame_host(); |
| 1485 | |
| 1486 | // 2) Navigate to B. |
| 1487 | EXPECT_TRUE(NavigateToURL(shell(), url_b)); |
| 1488 | |
| 1489 | // 3) A should be stored in back-forward cache because the physical memory is |
| 1490 | // greater than the memory threshold. |
Hajime Hoshi | bbc509c | 2020-04-06 08:55:08 | [diff] [blame] | 1491 | EXPECT_TRUE(rfh_a->IsInBackForwardCache()); |
Rakina Zata Amni | 454f5a90 | 2022-05-31 06:18:02 | [diff] [blame] | 1492 | |
Nathan Memmott | b2aa5665 | 2024-12-11 02:17:53 | [diff] [blame] | 1493 | // Ensure that the BackForwardCache trial stays active. |
Rakina Zata Amni | 454f5a90 | 2022-05-31 06:18:02 | [diff] [blame] | 1494 | EXPECT_TRUE(base::FieldTrialList::IsTrialActive( |
| 1495 | base::FeatureList::GetFieldTrial(features::kBackForwardCache) |
| 1496 | ->trial_name())); |
[email protected] | 54eaf62 | 2019-11-25 12:36:03 | [diff] [blame] | 1497 | } |
Alexander Timin | e92f165 | 2019-11-27 14:51:18 | [diff] [blame] | 1498 | |
Rakina Zata Amni | b6b7f7bf | 2021-02-12 10:25:39 | [diff] [blame] | 1499 | // Trigger network reqeuests, then navigate from A to B, then go back. |
| 1500 | IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTestForHighMemoryDevices, |
Rakina Zata Amni | eaf87b7 | 2021-03-02 02:04:35 | [diff] [blame] | 1501 | EnableBFCacheForHighMemoryDevices_NetworkRequests) { |
Rakina Zata Amni | b6b7f7bf | 2021-02-12 10:25:39 | [diff] [blame] | 1502 | net::test_server::ControllableHttpResponse image_response( |
| 1503 | embedded_test_server(), "/image.png"); |
| 1504 | ASSERT_TRUE(embedded_test_server()->Start()); |
| 1505 | GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html")); |
| 1506 | GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html")); |
| 1507 | |
| 1508 | // Ensure that back-forward cache flag is enabled and the trial is active. |
| 1509 | EXPECT_TRUE(IsBackForwardCacheEnabled()); |
| 1510 | EXPECT_TRUE(base::FieldTrialList::IsTrialActive( |
| 1511 | base::FeatureList::GetFieldTrial(features::kBackForwardCache) |
| 1512 | ->trial_name())); |
| 1513 | |
| 1514 | // Ensure that the LoadingTasksUnfreezable trials starts as inactive. |
| 1515 | EXPECT_FALSE(base::FieldTrialList::IsTrialActive( |
| 1516 | base::FeatureList::GetFieldTrial( |
| 1517 | blink::features::kLoadingTasksUnfreezable) |
| 1518 | ->trial_name())); |
| 1519 | |
| 1520 | // 1) Navigate to A. |
| 1521 | EXPECT_TRUE(NavigateToURL(shell(), url_a)); |
| 1522 | RenderFrameHostImpl* rfh_a = current_frame_host(); |
| 1523 | RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a); |
| 1524 | |
| 1525 | // Request for an image and send a response to trigger loading code. |
| 1526 | EXPECT_TRUE(ExecJs(rfh_a, R"( |
| 1527 | var image = document.createElement("img"); |
| 1528 | image.src = "image.png"; |
| 1529 | document.body.appendChild(image); |
| 1530 | )")); |
| 1531 | image_response.WaitForRequest(); |
| 1532 | image_response.Send(net::HTTP_OK, "image/png"); |
| 1533 | image_response.Send("image_body"); |
| 1534 | image_response.Done(); |
| 1535 | |
| 1536 | // The loading code activates the LoadingTasksUnfreezable trial. |
| 1537 | EXPECT_TRUE(base::FieldTrialList::IsTrialActive( |
| 1538 | base::FeatureList::GetFieldTrial( |
| 1539 | blink::features::kLoadingTasksUnfreezable) |
| 1540 | ->trial_name())); |
| 1541 | |
| 1542 | // 2) Navigate to B. |
| 1543 | EXPECT_TRUE(NavigateToURL(shell(), url_b)); |
| 1544 | |
| 1545 | // 3) A should be stored in back-forward cache because the physical memory is |
| 1546 | // greater than the memory threshold. |
| 1547 | EXPECT_TRUE(rfh_a->IsInBackForwardCache()); |
| 1548 | |
| 1549 | // Ensure that the trials stay activated. |
| 1550 | EXPECT_TRUE(base::FieldTrialList::IsTrialActive( |
| 1551 | base::FeatureList::GetFieldTrial(features::kBackForwardCache) |
| 1552 | ->trial_name())); |
| 1553 | EXPECT_TRUE(base::FieldTrialList::IsTrialActive( |
| 1554 | base::FeatureList::GetFieldTrial( |
| 1555 | blink::features::kLoadingTasksUnfreezable) |
| 1556 | ->trial_name())); |
| 1557 | } |
| 1558 | |
Rakina Zata Amni | 454f5a90 | 2022-05-31 06:18:02 | [diff] [blame] | 1559 | // Tests for high memory devices that have the BackForwardCache feature flag |
| 1560 | // disabled. |
| 1561 | class BackForwardCacheBrowserTestForHighMemoryDevicesWithBFCacheDisabled |
| 1562 | : public BackForwardCacheBrowserTest { |
| 1563 | protected: |
| 1564 | void SetUpCommandLine(base::CommandLine* command_line) override { |
| 1565 | BackForwardCacheBrowserTest::SetUpCommandLine(command_line); |
| 1566 | |
| 1567 | // Set the value of memory threshold less than the physical memory and check |
| 1568 | // if back-forward cache is enabled or not. |
François Doray | 9cee804 | 2025-08-15 19:02:55 | [diff] [blame] | 1569 | std::string memory_threshold = base::NumberToString( |
| 1570 | base::SysInfo::AmountOfPhysicalMemory().InMiB() - 1); |
Rakina Zata Amni | 454f5a90 | 2022-05-31 06:18:02 | [diff] [blame] | 1571 | scoped_feature_list_.InitWithFeaturesAndParameters( |
| 1572 | /*enabled_features=*/ |
| 1573 | {{features::kBackForwardCacheMemoryControls, |
| 1574 | {{"memory_threshold_for_back_forward_cache_in_mb", |
| 1575 | memory_threshold}}}, |
Rakina Zata Amni | 454f5a90 | 2022-05-31 06:18:02 | [diff] [blame] | 1576 | {blink::features::kLoadingTasksUnfreezable, {}}}, |
| 1577 | /*disabled_features=*/ |
| 1578 | {features::kBackForwardCache}); |
| 1579 | } |
| 1580 | |
| 1581 | private: |
| 1582 | base::test::ScopedFeatureList scoped_feature_list_; |
| 1583 | }; |
| 1584 | |
Rakina Zata Amni | 454f5a90 | 2022-05-31 06:18:02 | [diff] [blame] | 1585 | IN_PROC_BROWSER_TEST_F( |
| 1586 | BackForwardCacheBrowserTestForHighMemoryDevicesWithBFCacheDisabled, |
| 1587 | HighMemoryDevicesWithBFacheDisabled) { |
Rakina Zata Amni | 454f5a90 | 2022-05-31 06:18:02 | [diff] [blame] | 1588 | // Ensure that IsBackForwardCacheEnabled() returns false, because the |
| 1589 | // BackForwardCache feature is disabled. |
| 1590 | EXPECT_FALSE(IsBackForwardCacheEnabled()); |
| 1591 | |
Rakina Zata Amni | 454f5a90 | 2022-05-31 06:18:02 | [diff] [blame] | 1592 | ASSERT_TRUE(embedded_test_server()->Start()); |
| 1593 | GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html")); |
| 1594 | GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html")); |
| 1595 | |
| 1596 | // 1) Navigate to A. |
| 1597 | EXPECT_TRUE(NavigateToURL(shell(), url_a)); |
| 1598 | RenderFrameHostImpl* rfh_a = current_frame_host(); |
| 1599 | RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a); |
| 1600 | |
| 1601 | // 2) Navigate to B. |
| 1602 | EXPECT_TRUE(NavigateToURL(shell(), url_b)); |
| 1603 | |
| 1604 | // 3) A shouldn't be stored in back-forward cache because the BackForwardCache |
| 1605 | // feature is disabled. |
| 1606 | delete_observer_rfh_a.WaitUntilDeleted(); |
| 1607 | |
| 1608 | // 4) Go back to check that only kBackForwardCacheDisabled is recorded. |
| 1609 | ASSERT_TRUE(HistoryGoBack(web_contents())); |
| 1610 | |
| 1611 | ExpectNotRestored( |
| 1612 | { |
| 1613 | BackForwardCacheMetrics::NotRestoredReason::kBackForwardCacheDisabled, |
| 1614 | }, |
| 1615 | {}, {}, {}, {}, FROM_HERE); |
Rakina Zata Amni | 454f5a90 | 2022-05-31 06:18:02 | [diff] [blame] | 1616 | } |
| 1617 | |
Fergal Daly | 7991d936 | 2019-12-20 02:28:25 | [diff] [blame] | 1618 | // Start an inifite dialogs in JS, yielding after each. The first dialog should |
| 1619 | // be dismissed by navigation. The later dialogs should be handled gracefully |
| 1620 | // and not appear while in BFCache. Finally, when the page comes out of BFCache, |
| 1621 | // dialogs should appear again. |
| 1622 | IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, |
| 1623 | CanUseCacheWhenPageAlertsInTimeoutLoop) { |
| 1624 | ASSERT_TRUE(embedded_test_server()->Start()); |
| 1625 | |
| 1626 | GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html")); |
| 1627 | GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html")); |
| 1628 | |
| 1629 | // Navigate to A. |
| 1630 | EXPECT_TRUE(NavigateToURL(shell(), url_a)); |
| 1631 | RenderFrameHostImpl* rfh_a = current_frame_host(); |
| 1632 | RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a); |
| 1633 | |
Marko Ivanovich | 7e403fc | 2020-10-09 05:56:47 | [diff] [blame] | 1634 | AppModalDialogWaiter dialog_waiter(shell()); |
Fergal Daly | 7991d936 | 2019-12-20 02:28:25 | [diff] [blame] | 1635 | |
| 1636 | EXPECT_TRUE(ExecJs(rfh_a, R"( |
| 1637 | function alertLoop() { |
| 1638 | setTimeout(alertLoop, 0); |
| 1639 | window.alert("alert"); |
| 1640 | } |
| 1641 | // Don't block this script. |
| 1642 | setTimeout(alertLoop, 0); |
| 1643 | )")); |
| 1644 | |
Marko Ivanovich | 7e403fc | 2020-10-09 05:56:47 | [diff] [blame] | 1645 | dialog_waiter.Wait(); |
Fergal Daly | 7991d936 | 2019-12-20 02:28:25 | [diff] [blame] | 1646 | |
| 1647 | // Navigate to B. |
| 1648 | ASSERT_TRUE(NavigateToURL(shell(), url_b)); |
| 1649 | RenderFrameHostImpl* rfh_b = current_frame_host(); |
| 1650 | |
| 1651 | ASSERT_FALSE(delete_observer_rfh_a.deleted()); |
| 1652 | ASSERT_THAT(rfh_a, InBackForwardCache()); |
| 1653 | ASSERT_NE(rfh_a, rfh_b); |
| 1654 | |
Marko Ivanovich | 7e403fc | 2020-10-09 05:56:47 | [diff] [blame] | 1655 | dialog_waiter.Restart(); |
Fergal Daly | 7991d936 | 2019-12-20 02:28:25 | [diff] [blame] | 1656 | |
| 1657 | // Go back. |
Fergal Daly | 5495b0e | 2021-11-19 02:03:28 | [diff] [blame] | 1658 | ASSERT_TRUE(HistoryGoBack(web_contents())); |
Fergal Daly | 7991d936 | 2019-12-20 02:28:25 | [diff] [blame] | 1659 | EXPECT_EQ(rfh_a, current_frame_host()); |
Hajime Hoshi | bbc509c | 2020-04-06 08:55:08 | [diff] [blame] | 1660 | EXPECT_FALSE(rfh_a->IsInBackForwardCache()); |
Fergal Daly | 7991d936 | 2019-12-20 02:28:25 | [diff] [blame] | 1661 | |
| 1662 | // The page should still be requesting dialogs in a loop. Wait for one to be |
| 1663 | // requested. |
Marko Ivanovich | 7e403fc | 2020-10-09 05:56:47 | [diff] [blame] | 1664 | dialog_waiter.Wait(); |
Fergal Daly | 7991d936 | 2019-12-20 02:28:25 | [diff] [blame] | 1665 | } |
| 1666 | |
Nasko Oskov | 0f3cbb1 | 2020-01-07 17:52:14 | [diff] [blame] | 1667 | // UnloadOldFrame will clear all dialogs. We test that further requests for |
Fergal Daly | 7991d936 | 2019-12-20 02:28:25 | [diff] [blame] | 1668 | // dialogs coming from JS do not result in the creation of a dialog. This test |
| 1669 | // posts some dialog creation JS to the render from inside the |
| 1670 | // CommitNavigationCallback task. This JS is then able to post a task back to |
| 1671 | // the renders to show a dialog. By the time this task runs, we the |
| 1672 | // RenderFrameHostImpl's is_active() should be false. |
| 1673 | // |
| 1674 | // This test is not perfect, it can pass simply because the renderer thread does |
| 1675 | // not run the JS in time. Ideally it would block until the renderer posts the |
| 1676 | // request for a dialog but it's possible to do that without creating a nested |
| 1677 | // message loop and if we do that, we risk processing the dialog request. |
| 1678 | IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, |
| 1679 | DialogsCancelledAndSuppressedWhenCached) { |
| 1680 | ASSERT_TRUE(embedded_test_server()->Start()); |
| 1681 | |
| 1682 | GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html")); |
| 1683 | GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html")); |
| 1684 | |
| 1685 | // Navigate to A. |
| 1686 | EXPECT_TRUE(NavigateToURL(shell(), url_a)); |
| 1687 | RenderFrameHostImpl* rfh_a = current_frame_host(); |
| 1688 | RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a); |
| 1689 | |
| 1690 | // Let's us know whether the following callback ran. Not strictly necessary |
| 1691 | // since it really should run. |
| 1692 | bool posted_dialog_js = false; |
| 1693 | // Create a callback that will be called during the DidCommitNavigation task. |
| 1694 | WillEnterBackForwardCacheCallbackForTesting |
| 1695 | will_enter_back_forward_cache_callback = |
| 1696 | base::BindLambdaForTesting([&]() { |
| 1697 | // Post a dialog, it should not result in a dialog being created. |
| 1698 | ExecuteScriptAsync(rfh_a, R"(window.alert("alert");)"); |
| 1699 | posted_dialog_js = true; |
| 1700 | }); |
| 1701 | rfh_a->render_view_host()->SetWillEnterBackForwardCacheCallbackForTesting( |
| 1702 | will_enter_back_forward_cache_callback); |
| 1703 | |
Marko Ivanovich | 7e403fc | 2020-10-09 05:56:47 | [diff] [blame] | 1704 | AppModalDialogWaiter dialog_waiter(shell()); |
Fergal Daly | 7991d936 | 2019-12-20 02:28:25 | [diff] [blame] | 1705 | |
| 1706 | // Try show another dialog. It should work. |
| 1707 | ExecuteScriptAsync(rfh_a, R"(window.alert("alert");)"); |
Marko Ivanovich | 7e403fc | 2020-10-09 05:56:47 | [diff] [blame] | 1708 | dialog_waiter.Wait(); |
Fergal Daly | 7991d936 | 2019-12-20 02:28:25 | [diff] [blame] | 1709 | |
Marko Ivanovich | 7e403fc | 2020-10-09 05:56:47 | [diff] [blame] | 1710 | dialog_waiter.Restart(); |
Fergal Daly | 7991d936 | 2019-12-20 02:28:25 | [diff] [blame] | 1711 | |
| 1712 | // Navigate to B. |
| 1713 | ASSERT_TRUE(NavigateToURL(shell(), url_b)); |
| 1714 | RenderFrameHostImpl* rfh_b = current_frame_host(); |
| 1715 | |
| 1716 | ASSERT_FALSE(delete_observer_rfh_a.deleted()); |
| 1717 | ASSERT_THAT(rfh_a, InBackForwardCache()); |
| 1718 | ASSERT_NE(rfh_a, rfh_b); |
| 1719 | // Test that the JS was run and that it didn't result in a dialog. |
| 1720 | ASSERT_TRUE(posted_dialog_js); |
Marko Ivanovich | 7e403fc | 2020-10-09 05:56:47 | [diff] [blame] | 1721 | ASSERT_FALSE(dialog_waiter.WasDialogRequestedCallbackCalled()); |
Fergal Daly | 7991d936 | 2019-12-20 02:28:25 | [diff] [blame] | 1722 | |
| 1723 | // Go back. |
Fergal Daly | 5495b0e | 2021-11-19 02:03:28 | [diff] [blame] | 1724 | ASSERT_TRUE(HistoryGoBack(web_contents())); |
Fergal Daly | 7991d936 | 2019-12-20 02:28:25 | [diff] [blame] | 1725 | |
| 1726 | EXPECT_EQ(rfh_a, current_frame_host()); |
Hajime Hoshi | bbc509c | 2020-04-06 08:55:08 | [diff] [blame] | 1727 | EXPECT_FALSE(rfh_a->IsInBackForwardCache()); |
Fergal Daly | 7991d936 | 2019-12-20 02:28:25 | [diff] [blame] | 1728 | |
| 1729 | // Try show another dialog. It should work. |
| 1730 | ExecuteScriptAsync(rfh_a, R"(window.alert("alert");)"); |
Marko Ivanovich | 7e403fc | 2020-10-09 05:56:47 | [diff] [blame] | 1731 | dialog_waiter.Wait(); |
Fergal Daly | 7991d936 | 2019-12-20 02:28:25 | [diff] [blame] | 1732 | } |
| 1733 | |
Rakina Zata Amni | 6085813 | 2020-08-19 10:33:48 | [diff] [blame] | 1734 | // Tests that pagehide handlers of the old RFH are run for bfcached pages even |
| 1735 | // if the page is already hidden (and visibilitychange won't run). |
David Bertoni | 3aec0aaf | 2024-06-05 23:09:25 | [diff] [blame] | 1736 | // Disabled on Linux and Win because of flakiness, see crbug.com/40165901. |
David Bertoni | 3aec0aaf | 2024-06-05 23:09:25 | [diff] [blame] | 1737 | #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_WIN) |
| 1738 | #define MAYBE_PagehideRunsWhenPageIsHidden DISABLED_PagehideRunsWhenPageIsHidden |
| 1739 | #else |
| 1740 | #define MAYBE_PagehideRunsWhenPageIsHidden PagehideRunsWhenPageIsHidden |
| 1741 | #endif |
Rakina Zata Amni | 6085813 | 2020-08-19 10:33:48 | [diff] [blame] | 1742 | IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, |
David Bertoni | 3aec0aaf | 2024-06-05 23:09:25 | [diff] [blame] | 1743 | MAYBE_PagehideRunsWhenPageIsHidden) { |
Rakina Zata Amni | 6085813 | 2020-08-19 10:33:48 | [diff] [blame] | 1744 | ASSERT_TRUE(embedded_test_server()->Start()); |
| 1745 | GURL url_1(embedded_test_server()->GetURL("a.com", "/title1.html")); |
| 1746 | GURL url_2(embedded_test_server()->GetURL("b.com", "/title2.html")); |
| 1747 | GURL url_3(embedded_test_server()->GetURL("a.com", "/title2.html")); |
| 1748 | WebContentsImpl* web_contents = |
| 1749 | static_cast<WebContentsImpl*>(shell()->web_contents()); |
| 1750 | |
| 1751 | // 1) Navigate to |url_1| and hide the tab. |
| 1752 | EXPECT_TRUE(NavigateToURL(shell(), url_1)); |
Yuzu Saijo | da4f49f | 2022-10-17 06:57:01 | [diff] [blame] | 1753 | RenderFrameHostImplWrapper main_frame_1(web_contents->GetPrimaryMainFrame()); |
Rakina Zata Amni | 6085813 | 2020-08-19 10:33:48 | [diff] [blame] | 1754 | // We need to set it to Visibility::VISIBLE first in case this is the first |
| 1755 | // time the visibility is updated. |
| 1756 | web_contents->UpdateWebContentsVisibility(Visibility::VISIBLE); |
| 1757 | web_contents->UpdateWebContentsVisibility(Visibility::HIDDEN); |
| 1758 | EXPECT_EQ(Visibility::HIDDEN, web_contents->GetVisibility()); |
| 1759 | |
| 1760 | // Create a pagehide handler that sets item "pagehide_storage" and a |
| 1761 | // visibilitychange handler that sets item "visibilitychange_storage" in |
| 1762 | // localStorage. |
Yuzu Saijo | da4f49f | 2022-10-17 06:57:01 | [diff] [blame] | 1763 | EXPECT_TRUE(ExecJs(main_frame_1.get(), |
Rakina Zata Amni | 6085813 | 2020-08-19 10:33:48 | [diff] [blame] | 1764 | R"( |
| 1765 | localStorage.setItem('pagehide_storage', 'not_dispatched'); |
| 1766 | var dispatched_pagehide = false; |
| 1767 | window.onpagehide = function(e) { |
| 1768 | if (dispatched_pagehide) { |
| 1769 | // We shouldn't dispatch pagehide more than once. |
| 1770 | localStorage.setItem('pagehide_storage', 'dispatched_more_than_once'); |
| 1771 | } else if (!e.persisted) { |
| 1772 | localStorage.setItem('pagehide_storage', 'wrong_persisted'); |
| 1773 | } else { |
| 1774 | localStorage.setItem('pagehide_storage', 'dispatched_once'); |
| 1775 | } |
| 1776 | dispatched_pagehide = true; |
| 1777 | } |
| 1778 | localStorage.setItem('visibilitychange_storage', 'not_dispatched'); |
| 1779 | document.onvisibilitychange = function(e) { |
| 1780 | localStorage.setItem('visibilitychange_storage', |
| 1781 | 'should_not_be_dispatched'); |
| 1782 | } |
| 1783 | )")); |
| 1784 | // |visibilitychange_storage| should be set to its initial correct value. |
Fergal Daly | 2c7bc405 | 2021-12-23 14:42:22 | [diff] [blame] | 1785 | EXPECT_EQ("not_dispatched", |
Yuzu Saijo | da4f49f | 2022-10-17 06:57:01 | [diff] [blame] | 1786 | GetLocalStorage(main_frame_1.get(), "visibilitychange_storage")); |
Rakina Zata Amni | 6085813 | 2020-08-19 10:33:48 | [diff] [blame] | 1787 | |
| 1788 | // 2) Navigate cross-site to |url_2|. We need to navigate cross-site to make |
| 1789 | // sure we won't run pagehide and visibilitychange during new page's commit, |
| 1790 | // which is tested in ProactivelySwapBrowsingInstancesSameSiteTest. |
| 1791 | EXPECT_TRUE(NavigateToURL(shell(), url_2)); |
| 1792 | |
| 1793 | // |main_frame_1| should be in the back-forward cache. |
| 1794 | EXPECT_TRUE(main_frame_1->IsInBackForwardCache()); |
| 1795 | |
| 1796 | // 3) Navigate to |url_3| which is same-origin with |url_1|, so we can check |
| 1797 | // the localStorage values. |
| 1798 | EXPECT_TRUE(NavigateToURL(shell(), url_3)); |
Dave Tapuska | 327c06c9 | 2022-06-13 20:31:51 | [diff] [blame] | 1799 | RenderFrameHostImpl* main_frame_3 = web_contents->GetPrimaryMainFrame(); |
Rakina Zata Amni | 6085813 | 2020-08-19 10:33:48 | [diff] [blame] | 1800 | |
| 1801 | // Check that the value for 'pagehide_storage' and 'visibilitychange_storage' |
| 1802 | // are set correctly. |
Fergal Daly | 91e6288 | 2023-10-30 08:26:42 | [diff] [blame] | 1803 | EXPECT_TRUE( |
| 1804 | WaitForLocalStorage(main_frame_3, "pagehide_storage", "dispatched_once")); |
| 1805 | EXPECT_TRUE(WaitForLocalStorage(main_frame_3, "visibilitychange_storage", |
| 1806 | "not_dispatched")); |
Rakina Zata Amni | 6085813 | 2020-08-19 10:33:48 | [diff] [blame] | 1807 | } |
| 1808 | |
Rakina Zata Amni | efcc293 | 2020-08-28 07:24:37 | [diff] [blame] | 1809 | // Tests that we're getting the correct TextInputState and focus updates when a |
| 1810 | // page enters the back-forward cache and when it gets restored. |
Ivana Žužić | d514c14 | 2024-02-09 16:12:22 | [diff] [blame] | 1811 | // TODO(b/324570785): Re-enable the test for Android. |
Yoshisato Yanagisawa | 47effef | 2025-05-19 06:18:31 | [diff] [blame] | 1812 | #if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_MAC) |
Ivana Žužić | d514c14 | 2024-02-09 16:12:22 | [diff] [blame] | 1813 | #define MAYBE_TextInputStateUpdated DISABLED_TextInputStateUpdated |
| 1814 | #else |
| 1815 | #define MAYBE_TextInputStateUpdated TextInputStateUpdated |
| 1816 | #endif |
| 1817 | IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, |
| 1818 | MAYBE_TextInputStateUpdated) { |
Rakina Zata Amni | efcc293 | 2020-08-28 07:24:37 | [diff] [blame] | 1819 | ASSERT_TRUE(embedded_test_server()->Start()); |
| 1820 | GURL url_1(embedded_test_server()->GetURL("a.com", "/title1.html")); |
| 1821 | GURL url_2(embedded_test_server()->GetURL("b.com", "/title2.html")); |
| 1822 | |
| 1823 | // 1) Navigate to |url_1| and add a text input with "foo" as the value. |
| 1824 | EXPECT_TRUE(NavigateToURL(shell(), url_1)); |
Mustaq Ahmed | 17d4e67 | 2025-05-16 22:27:34 | [diff] [blame] | 1825 | SimulateEndOfPaintHoldingOnPrimaryMainFrame(web_contents()); |
Rakina Zata Amni | efcc293 | 2020-08-28 07:24:37 | [diff] [blame] | 1826 | RenderFrameHostImpl* rfh_1 = current_frame_host(); |
| 1827 | EXPECT_TRUE(ExecJs(rfh_1, |
| 1828 | "document.title='bfcached';" |
| 1829 | "var input = document.createElement('input');" |
| 1830 | "input.setAttribute('type', 'text');" |
| 1831 | "input.setAttribute('value', 'foo');" |
| 1832 | "document.body.appendChild(input);" |
| 1833 | "var focusCount = 0;" |
| 1834 | "var blurCount = 0;" |
| 1835 | "input.onfocus = () => { focusCount++;};" |
| 1836 | "input.onblur = () => { blurCount++; };")); |
| 1837 | |
| 1838 | { |
| 1839 | TextInputManagerTypeObserver type_observer(web_contents(), |
| 1840 | ui::TEXT_INPUT_TYPE_TEXT); |
| 1841 | TextInputManagerValueObserver value_observer(web_contents(), "foo"); |
| 1842 | // 2) Press tab key to focus the <input>, and verify the type & value. |
| 1843 | SimulateKeyPress(web_contents(), ui::DomKey::TAB, ui::DomCode::TAB, |
| 1844 | ui::VKEY_TAB, false, false, false, false); |
| 1845 | type_observer.Wait(); |
| 1846 | value_observer.Wait(); |
| 1847 | |
| 1848 | EXPECT_EQ(rfh_1, web_contents()->GetFocusedFrame()); |
| 1849 | EXPECT_EQ(EvalJs(rfh_1, "focusCount").ExtractInt(), 1); |
| 1850 | EXPECT_EQ(EvalJs(rfh_1, "blurCount").ExtractInt(), 0); |
| 1851 | } |
| 1852 | |
| 1853 | { |
| 1854 | TextInputManagerTester tester(web_contents()); |
| 1855 | TextInputManagerValueObserver value_observer(web_contents(), "A"); |
| 1856 | // 3) Press the "A" key to change the text input value. This should notify |
| 1857 | // the browser that the text input value has changed. |
| 1858 | SimulateKeyPress(web_contents(), ui::DomKey::FromCharacter('A'), |
| 1859 | ui::DomCode::US_A, ui::VKEY_A, false, false, false, false); |
| 1860 | value_observer.Wait(); |
| 1861 | |
| 1862 | EXPECT_EQ(rfh_1, web_contents()->GetFocusedFrame()); |
| 1863 | EXPECT_EQ(EvalJs(rfh_1, "focusCount").ExtractInt(), 1); |
| 1864 | EXPECT_EQ(EvalJs(rfh_1, "blurCount").ExtractInt(), 0); |
| 1865 | } |
| 1866 | |
| 1867 | { |
| 1868 | TextInputManagerTypeObserver type_observer(web_contents(), |
| 1869 | ui::TEXT_INPUT_TYPE_NONE); |
| 1870 | // 4) Navigating to |url_2| should reset type to TEXT_INPUT_TYPE_NONE. |
| 1871 | EXPECT_TRUE(NavigateToURL(shell(), url_2)); |
| 1872 | type_observer.Wait(); |
| 1873 | // |rfh_1| should get into the back-forward cache. |
| 1874 | EXPECT_TRUE(rfh_1->IsInBackForwardCache()); |
| 1875 | EXPECT_EQ(current_frame_host(), web_contents()->GetFocusedFrame()); |
| 1876 | EXPECT_NE(rfh_1, web_contents()->GetFocusedFrame()); |
| 1877 | } |
| 1878 | |
| 1879 | { |
| 1880 | // 5) Navigating back to |url_1|, we shouldn't restore the focus to the |
| 1881 | // text input, but |rfh_1| will be focused again as we will restore focus |
| 1882 | // to main frame after navigation. |
Fergal Daly | 5495b0e | 2021-11-19 02:03:28 | [diff] [blame] | 1883 | ASSERT_TRUE(HistoryGoBack(web_contents())); |
Rakina Zata Amni | efcc293 | 2020-08-28 07:24:37 | [diff] [blame] | 1884 | |
| 1885 | EXPECT_EQ(rfh_1, web_contents()->GetFocusedFrame()); |
| 1886 | EXPECT_EQ(EvalJs(rfh_1, "focusCount").ExtractInt(), 1); |
| 1887 | EXPECT_EQ(EvalJs(rfh_1, "blurCount").ExtractInt(), 1); |
| 1888 | } |
| 1889 | |
| 1890 | { |
| 1891 | TextInputManagerTypeObserver type_observer(web_contents(), |
| 1892 | ui::TEXT_INPUT_TYPE_TEXT); |
| 1893 | TextInputManagerValueObserver value_observer(web_contents(), "A"); |
| 1894 | // 6) Press tab key to focus the <input> again. Note that we need to press |
| 1895 | // the tab key twice here, because the last "tab focus" point was the |
| 1896 | // <input> element. The first tab key press would focus on the UI/url bar, |
| 1897 | // then the second tab key would go back to the <input>. |
| 1898 | SimulateKeyPress(web_contents(), ui::DomKey::TAB, ui::DomCode::TAB, |
| 1899 | ui::VKEY_TAB, false, false, false, false); |
| 1900 | SimulateKeyPress(web_contents(), ui::DomKey::TAB, ui::DomCode::TAB, |
| 1901 | ui::VKEY_TAB, false, false, false, false); |
| 1902 | type_observer.Wait(); |
| 1903 | value_observer.Wait(); |
| 1904 | |
| 1905 | EXPECT_EQ(rfh_1, web_contents()->GetFocusedFrame()); |
| 1906 | EXPECT_EQ(EvalJs(rfh_1, "focusCount").ExtractInt(), 2); |
| 1907 | EXPECT_EQ(EvalJs(rfh_1, "blurCount").ExtractInt(), 1); |
| 1908 | } |
| 1909 | } |
| 1910 | |
Rakina Zata Amni | 01721acd | 2023-12-05 19:38:31 | [diff] [blame] | 1911 | #if (BUILDFLAG(IS_MAC) || BUILDFLAG(IS_ANDROID)) |
Rakina Zata Amni | bebca3e | 2022-10-12 07:22:42 | [diff] [blame] | 1912 | #define MAYBE_SubframeTextInputStateUpdated DISABLED_SubframeTextInputStateUpdated |
| 1913 | #else |
| 1914 | #define MAYBE_SubframeTextInputStateUpdated SubframeTextInputStateUpdated |
| 1915 | #endif |
Rakina Zata Amni | efcc293 | 2020-08-28 07:24:37 | [diff] [blame] | 1916 | IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, |
Rakina Zata Amni | bebca3e | 2022-10-12 07:22:42 | [diff] [blame] | 1917 | MAYBE_SubframeTextInputStateUpdated) { |
Rakina Zata Amni | efcc293 | 2020-08-28 07:24:37 | [diff] [blame] | 1918 | ASSERT_TRUE(embedded_test_server()->Start()); |
| 1919 | GURL url_1(embedded_test_server()->GetURL( |
| 1920 | "a.com", "/cross_site_iframe_factory.html?a(b(a))")); |
| 1921 | GURL url_2(embedded_test_server()->GetURL("b.com", "/title2.html")); |
| 1922 | |
| 1923 | // 1) Navigate to |url_1| and add a text input with "foo" as the value in the |
| 1924 | // a.com subframe. |
| 1925 | EXPECT_TRUE(NavigateToURL(shell(), url_1)); |
Mustaq Ahmed | 17d4e67 | 2025-05-16 22:27:34 | [diff] [blame] | 1926 | SimulateEndOfPaintHoldingOnPrimaryMainFrame(web_contents()); |
Rakina Zata Amni | efcc293 | 2020-08-28 07:24:37 | [diff] [blame] | 1927 | RenderFrameHostImpl* rfh_a = current_frame_host(); |
| 1928 | RenderFrameHostImpl* rfh_b = rfh_a->child_at(0)->current_frame_host(); |
| 1929 | RenderFrameHostImpl* rfh_subframe_a = |
| 1930 | rfh_b->child_at(0)->current_frame_host(); |
| 1931 | EXPECT_TRUE(ExecJs(rfh_subframe_a, |
| 1932 | "var input = document.createElement('input');" |
| 1933 | "input.setAttribute('type', 'text');" |
| 1934 | "input.setAttribute('value', 'foo');" |
| 1935 | "document.body.appendChild(input);" |
| 1936 | "var focusCount = 0;" |
| 1937 | "var blurCount = 0;" |
| 1938 | "input.onfocus = () => { focusCount++;};" |
| 1939 | "input.onblur = () => { blurCount++; };")); |
| 1940 | |
| 1941 | { |
| 1942 | TextInputManagerTypeObserver type_observer(web_contents(), |
| 1943 | ui::TEXT_INPUT_TYPE_TEXT); |
| 1944 | TextInputManagerValueObserver value_observer(web_contents(), "foo"); |
| 1945 | // 2) Press tab key to focus the <input>, and verify the type & value. |
| 1946 | SimulateKeyPress(web_contents(), ui::DomKey::TAB, ui::DomCode::TAB, |
| 1947 | ui::VKEY_TAB, false, false, false, false); |
| 1948 | type_observer.Wait(); |
| 1949 | value_observer.Wait(); |
| 1950 | |
| 1951 | EXPECT_EQ(rfh_subframe_a, web_contents()->GetFocusedFrame()); |
| 1952 | EXPECT_EQ(EvalJs(rfh_subframe_a, "focusCount").ExtractInt(), 1); |
| 1953 | EXPECT_EQ(EvalJs(rfh_subframe_a, "blurCount").ExtractInt(), 0); |
| 1954 | } |
| 1955 | |
| 1956 | { |
| 1957 | TextInputManagerTester tester(web_contents()); |
| 1958 | TextInputManagerValueObserver value_observer(web_contents(), "A"); |
| 1959 | // 3) Press the "A" key to change the text input value. This should notify |
| 1960 | // the browser that the text input value has changed. |
| 1961 | SimulateKeyPress(web_contents(), ui::DomKey::FromCharacter('A'), |
| 1962 | ui::DomCode::US_A, ui::VKEY_A, false, false, false, false); |
| 1963 | value_observer.Wait(); |
| 1964 | |
| 1965 | EXPECT_EQ(rfh_subframe_a, web_contents()->GetFocusedFrame()); |
| 1966 | EXPECT_EQ(EvalJs(rfh_subframe_a, "focusCount").ExtractInt(), 1); |
| 1967 | EXPECT_EQ(EvalJs(rfh_subframe_a, "blurCount").ExtractInt(), 0); |
| 1968 | } |
| 1969 | |
| 1970 | { |
| 1971 | TextInputManagerTypeObserver type_observer(web_contents(), |
| 1972 | ui::TEXT_INPUT_TYPE_NONE); |
| 1973 | // 4) Navigating to |url_2| should reset type to TEXT_INPUT_TYPE_NONE and |
| 1974 | // changed focus to the new page's main frame. |
| 1975 | EXPECT_TRUE(NavigateToURL(shell(), url_2)); |
| 1976 | type_observer.Wait(); |
| 1977 | |
| 1978 | // |rfh_a| and its subframes should get into the back-forward cache. |
| 1979 | EXPECT_TRUE(rfh_a->IsInBackForwardCache()); |
| 1980 | EXPECT_TRUE(rfh_b->IsInBackForwardCache()); |
| 1981 | EXPECT_TRUE(rfh_subframe_a->IsInBackForwardCache()); |
Rakina Zata Amni | 53f91fb | 2022-10-10 18:58:48 | [diff] [blame] | 1982 | EXPECT_NE(rfh_subframe_a, web_contents()->GetFocusedFrame()); |
Rakina Zata Amni | efcc293 | 2020-08-28 07:24:37 | [diff] [blame] | 1983 | } |
| 1984 | |
| 1985 | { |
| 1986 | // 5) Navigating back to |url_1|, we shouldn't restore the focus to the |
| 1987 | // text input in the subframe (we will focus on the main frame |rfh_a| |
| 1988 | // instead). |
Fergal Daly | 5495b0e | 2021-11-19 02:03:28 | [diff] [blame] | 1989 | ASSERT_TRUE(HistoryGoBack(web_contents())); |
Rakina Zata Amni | efcc293 | 2020-08-28 07:24:37 | [diff] [blame] | 1990 | |
| 1991 | EXPECT_EQ(rfh_a, web_contents()->GetFocusedFrame()); |
| 1992 | EXPECT_EQ(EvalJs(rfh_subframe_a, "focusCount").ExtractInt(), 1); |
| 1993 | EXPECT_EQ(EvalJs(rfh_subframe_a, "blurCount").ExtractInt(), 1); |
| 1994 | } |
| 1995 | |
| 1996 | { |
| 1997 | TextInputManagerTypeObserver type_observer(web_contents(), |
| 1998 | ui::TEXT_INPUT_TYPE_TEXT); |
| 1999 | TextInputManagerValueObserver value_observer(web_contents(), "A"); |
| 2000 | // 6) Press tab key to focus the <input> again. |
| 2001 | SimulateKeyPress(web_contents(), ui::DomKey::TAB, ui::DomCode::TAB, |
| 2002 | ui::VKEY_TAB, false, false, false, false); |
| 2003 | type_observer.Wait(); |
| 2004 | value_observer.Wait(); |
| 2005 | |
| 2006 | EXPECT_EQ(rfh_subframe_a, web_contents()->GetFocusedFrame()); |
| 2007 | EXPECT_EQ(EvalJs(rfh_subframe_a, "focusCount").ExtractInt(), 2); |
| 2008 | EXPECT_EQ(EvalJs(rfh_subframe_a, "blurCount").ExtractInt(), 1); |
| 2009 | } |
| 2010 | } |
| 2011 | |
Rakina Zata Amni | cca4889e | 2021-09-28 23:25:55 | [diff] [blame] | 2012 | // Tests that trying to focus on a BFCached cross-site iframe won't crash. |
| 2013 | // See https://crbug.com/1250218. |
Alison Gale | 81f4f2c7 | 2024-04-22 19:33:31 | [diff] [blame] | 2014 | // TODO(crbug.com/40856039): Flaky on linux tsan |
Matt Wolenetz | 86173c4d7 | 2022-08-03 20:38:35 | [diff] [blame] | 2015 | #if BUILDFLAG(IS_LINUX) && defined(THREAD_SANITIZER) |
| 2016 | #define MAYBE_FocusSameSiteSubframeOnPagehide \ |
| 2017 | DISABLED_FocusSameSiteSubframeOnPagehide |
| 2018 | #else |
| 2019 | #define MAYBE_FocusSameSiteSubframeOnPagehide FocusSameSiteSubframeOnPagehide |
| 2020 | #endif |
Rakina Zata Amni | cca4889e | 2021-09-28 23:25:55 | [diff] [blame] | 2021 | IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, |
Matt Wolenetz | 86173c4d7 | 2022-08-03 20:38:35 | [diff] [blame] | 2022 | MAYBE_FocusSameSiteSubframeOnPagehide) { |
Rakina Zata Amni | cca4889e | 2021-09-28 23:25:55 | [diff] [blame] | 2023 | ASSERT_TRUE(embedded_test_server()->Start()); |
| 2024 | GURL main_url( |
| 2025 | embedded_test_server()->GetURL("a.com", "/page_with_iframe.html")); |
| 2026 | GURL main_url_2(embedded_test_server()->GetURL("b.com", "/title2.html")); |
| 2027 | |
| 2028 | // 1) Navigate to a page with a same-site iframe. |
| 2029 | EXPECT_TRUE(NavigateToURL(shell(), main_url)); |
| 2030 | RenderFrameHostImplWrapper rfh_1(current_frame_host()); |
| 2031 | EXPECT_EQ(rfh_1.get(), web_contents()->GetFocusedFrame()); |
| 2032 | |
| 2033 | // 2) Navigate away from the page while trying to focus the subframe on |
| 2034 | // pagehide. The DidFocusFrame IPC should arrive after the page gets into |
| 2035 | // BFCache and should be ignored by the browser. The focus after navigation |
| 2036 | // should go to the new main frame. |
| 2037 | EXPECT_TRUE(ExecJs(rfh_1.get(), R"( |
| 2038 | window.onpagehide = function(e) { |
| 2039 | document.getElementById("test_iframe").focus(); |
| 2040 | })")); |
| 2041 | EXPECT_TRUE(NavigateToURL(shell(), main_url_2)); |
| 2042 | EXPECT_TRUE(rfh_1->IsInBackForwardCache()); |
| 2043 | EXPECT_NE(rfh_1.get(), web_contents()->GetFocusedFrame()); |
| 2044 | EXPECT_EQ(current_frame_host(), web_contents()->GetFocusedFrame()); |
| 2045 | |
| 2046 | // 3) Navigate back to the page. The focus should be on the main frame. |
Fergal Daly | 5495b0e | 2021-11-19 02:03:28 | [diff] [blame] | 2047 | ASSERT_TRUE(HistoryGoBack(web_contents())); |
Rakina Zata Amni | cca4889e | 2021-09-28 23:25:55 | [diff] [blame] | 2048 | EXPECT_EQ(rfh_1.get(), web_contents()->GetFocusedFrame()); |
| 2049 | ExpectRestored(FROM_HERE); |
| 2050 | } |
| 2051 | |
| 2052 | // Tests that trying to focus on a BFCached cross-site iframe won't crash. |
| 2053 | // See https://crbug.com/1250218. |
| 2054 | IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, |
| 2055 | FocusCrossSiteSubframeOnPagehide) { |
| 2056 | ASSERT_TRUE(embedded_test_server()->Start()); |
| 2057 | GURL main_url(embedded_test_server()->GetURL( |
| 2058 | "a.com", "/cross_site_iframe_factory.html?a(b)")); |
| 2059 | GURL main_url_2(embedded_test_server()->GetURL("b.com", "/title2.html")); |
| 2060 | |
| 2061 | // 1) Navigate to a page with a cross-site iframe. |
| 2062 | EXPECT_TRUE(NavigateToURL(shell(), main_url)); |
| 2063 | RenderFrameHostImplWrapper rfh_1(current_frame_host()); |
| 2064 | EXPECT_EQ(rfh_1.get(), web_contents()->GetFocusedFrame()); |
| 2065 | |
| 2066 | // 2) Navigate away from the page while trying to focus the subframe on |
| 2067 | // pagehide. The DidFocusFrame IPC should arrive after the page gets into |
| 2068 | // BFCache and should be ignored by the browser. The focus after navigation |
| 2069 | // should go to the new main frame. |
| 2070 | EXPECT_TRUE(ExecJs(rfh_1.get(), R"( |
| 2071 | window.onpagehide = function(e) { |
| 2072 | document.getElementById("child-0").focus(); |
| 2073 | })")); |
| 2074 | EXPECT_TRUE(NavigateToURL(shell(), main_url_2)); |
| 2075 | EXPECT_TRUE(rfh_1->IsInBackForwardCache()); |
| 2076 | EXPECT_NE(rfh_1.get(), web_contents()->GetFocusedFrame()); |
| 2077 | |
| 2078 | // 3) Navigate back to the page. The focus should be on the original page's |
| 2079 | // main frame. |
Fergal Daly | 5495b0e | 2021-11-19 02:03:28 | [diff] [blame] | 2080 | ASSERT_TRUE(HistoryGoBack(web_contents())); |
Rakina Zata Amni | cca4889e | 2021-09-28 23:25:55 | [diff] [blame] | 2081 | EXPECT_EQ(rfh_1.get(), current_frame_host()); |
| 2082 | ExpectRestored(FROM_HERE); |
| 2083 | } |
| 2084 | |
Alexander Timin | 45b716c | 2020-11-06 01:40:31 | [diff] [blame] | 2085 | IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, |
| 2086 | MainDocumentCSPHeadersAreRestored) { |
| 2087 | ASSERT_TRUE(embedded_test_server()->Start()); |
| 2088 | |
| 2089 | GURL url_a(embedded_test_server()->GetURL( |
| 2090 | "a.com", |
| 2091 | "/set-header?" |
| 2092 | "Content-Security-Policy: frame-src 'none'")); |
| 2093 | GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html")); |
| 2094 | |
| 2095 | // 1) Navigate to A, which should set CSP. |
| 2096 | EXPECT_TRUE(NavigateToURL(shell(), url_a)); |
| 2097 | RenderFrameHostImpl* rfh_a = current_frame_host(); |
| 2098 | |
| 2099 | // Check that CSP was set. |
| 2100 | { |
Antonio Sartori | 8f5b7ee | 2021-01-29 13:00:54 | [diff] [blame] | 2101 | const std::vector<network::mojom::ContentSecurityPolicyPtr>& root_csp = |
| 2102 | current_frame_host() |
Antonio Sartori | f45b2fc | 2021-03-04 10:15:07 | [diff] [blame] | 2103 | ->policy_container_host() |
| 2104 | ->policies() |
| 2105 | .content_security_policies; |
Alexander Timin | 45b716c | 2020-11-06 01:40:31 | [diff] [blame] | 2106 | EXPECT_EQ(1u, root_csp.size()); |
Antonio Sartori | 8f5b7ee | 2021-01-29 13:00:54 | [diff] [blame] | 2107 | EXPECT_EQ("frame-src 'none'", root_csp[0]->header->header_value); |
Alexander Timin | 45b716c | 2020-11-06 01:40:31 | [diff] [blame] | 2108 | } |
| 2109 | |
| 2110 | // 2) Navigate to B. |
| 2111 | EXPECT_TRUE(NavigateToURL(shell(), url_b)); |
| 2112 | |
| 2113 | // 3) Navigate back and expect that the CSP headers are present on the main |
| 2114 | // frame. |
Fergal Daly | 5495b0e | 2021-11-19 02:03:28 | [diff] [blame] | 2115 | ASSERT_TRUE(HistoryGoBack(web_contents())); |
Alexander Timin | 45b716c | 2020-11-06 01:40:31 | [diff] [blame] | 2116 | EXPECT_EQ(rfh_a, current_frame_host()); |
Fergal Daly | 0983306 | 2021-02-09 07:10:00 | [diff] [blame] | 2117 | ExpectRestored(FROM_HERE); |
Alexander Timin | 45b716c | 2020-11-06 01:40:31 | [diff] [blame] | 2118 | |
| 2119 | // Check that CSP was restored. |
| 2120 | { |
Antonio Sartori | 8f5b7ee | 2021-01-29 13:00:54 | [diff] [blame] | 2121 | const std::vector<network::mojom::ContentSecurityPolicyPtr>& root_csp = |
| 2122 | current_frame_host() |
Antonio Sartori | f45b2fc | 2021-03-04 10:15:07 | [diff] [blame] | 2123 | ->policy_container_host() |
| 2124 | ->policies() |
| 2125 | .content_security_policies; |
Alexander Timin | 45b716c | 2020-11-06 01:40:31 | [diff] [blame] | 2126 | EXPECT_EQ(1u, root_csp.size()); |
Antonio Sartori | 8f5b7ee | 2021-01-29 13:00:54 | [diff] [blame] | 2127 | EXPECT_EQ("frame-src 'none'", root_csp[0]->header->header_value); |
Alexander Timin | 45b716c | 2020-11-06 01:40:31 | [diff] [blame] | 2128 | } |
| 2129 | } |
| 2130 | |
arthursonzogni | 76098e5 | 2020-11-25 14:18:45 | [diff] [blame] | 2131 | // Check that sandboxed documents are cached and won't lose their sandbox flags |
| 2132 | // after restoration. |
| 2133 | IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, CspSandbox) { |
Alexander Timin | 45b716c | 2020-11-06 01:40:31 | [diff] [blame] | 2134 | ASSERT_TRUE(embedded_test_server()->Start()); |
| 2135 | |
| 2136 | GURL url_a( |
| 2137 | embedded_test_server()->GetURL("a.com", |
| 2138 | "/set-header?" |
| 2139 | "Content-Security-Policy: sandbox")); |
| 2140 | GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html")); |
| 2141 | |
| 2142 | // 1) Navigate to A, which should set CSP. |
| 2143 | EXPECT_TRUE(NavigateToURL(shell(), url_a)); |
arthursonzogni | 76098e5 | 2020-11-25 14:18:45 | [diff] [blame] | 2144 | RenderFrameHostImpl* rfh_a = current_frame_host(); |
| 2145 | RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a); |
Alexander Timin | 45b716c | 2020-11-06 01:40:31 | [diff] [blame] | 2146 | { |
Antonio Sartori | 8f5b7ee | 2021-01-29 13:00:54 | [diff] [blame] | 2147 | const std::vector<network::mojom::ContentSecurityPolicyPtr>& root_csp = |
| 2148 | current_frame_host() |
Antonio Sartori | f45b2fc | 2021-03-04 10:15:07 | [diff] [blame] | 2149 | ->policy_container_host() |
| 2150 | ->policies() |
| 2151 | .content_security_policies; |
arthursonzogni | 76098e5 | 2020-11-25 14:18:45 | [diff] [blame] | 2152 | ASSERT_EQ(1u, root_csp.size()); |
Antonio Sartori | 8f5b7ee | 2021-01-29 13:00:54 | [diff] [blame] | 2153 | ASSERT_EQ("sandbox", root_csp[0]->header->header_value); |
arthursonzogni | 76098e5 | 2020-11-25 14:18:45 | [diff] [blame] | 2154 | ASSERT_EQ(network::mojom::WebSandboxFlags::kAll, |
| 2155 | current_frame_host()->active_sandbox_flags()); |
Lei Zhang | 05c13df | 2024-07-10 20:59:12 | [diff] [blame] | 2156 | } |
Alexander Timin | 45b716c | 2020-11-06 01:40:31 | [diff] [blame] | 2157 | |
arthursonzogni | 76098e5 | 2020-11-25 14:18:45 | [diff] [blame] | 2158 | // 2) Navigate to B. Expect the previous RenderFrameHost to enter the bfcache. |
Alexander Timin | 45b716c | 2020-11-06 01:40:31 | [diff] [blame] | 2159 | EXPECT_TRUE(NavigateToURL(shell(), url_b)); |
arthursonzogni | 76098e5 | 2020-11-25 14:18:45 | [diff] [blame] | 2160 | EXPECT_FALSE(delete_observer_rfh_a.deleted()); |
| 2161 | EXPECT_TRUE(rfh_a->IsInBackForwardCache()); |
| 2162 | { |
Antonio Sartori | 8f5b7ee | 2021-01-29 13:00:54 | [diff] [blame] | 2163 | const std::vector<network::mojom::ContentSecurityPolicyPtr>& root_csp = |
| 2164 | current_frame_host() |
Antonio Sartori | f45b2fc | 2021-03-04 10:15:07 | [diff] [blame] | 2165 | ->policy_container_host() |
| 2166 | ->policies() |
| 2167 | .content_security_policies; |
arthursonzogni | 76098e5 | 2020-11-25 14:18:45 | [diff] [blame] | 2168 | ASSERT_EQ(0u, root_csp.size()); |
| 2169 | ASSERT_EQ(network::mojom::WebSandboxFlags::kNone, |
| 2170 | current_frame_host()->active_sandbox_flags()); |
Lei Zhang | 05c13df | 2024-07-10 20:59:12 | [diff] [blame] | 2171 | } |
Alexander Timin | 45b716c | 2020-11-06 01:40:31 | [diff] [blame] | 2172 | |
arthursonzogni | 76098e5 | 2020-11-25 14:18:45 | [diff] [blame] | 2173 | // 3) Navigate back and expect the page to be restored, with the correct |
| 2174 | // CSP and sandbox flags. |
Fergal Daly | 5495b0e | 2021-11-19 02:03:28 | [diff] [blame] | 2175 | ASSERT_TRUE(HistoryGoBack(web_contents())); |
arthursonzogni | 76098e5 | 2020-11-25 14:18:45 | [diff] [blame] | 2176 | EXPECT_FALSE(delete_observer_rfh_a.deleted()); |
| 2177 | EXPECT_EQ(current_frame_host(), rfh_a); |
| 2178 | { |
Antonio Sartori | 8f5b7ee | 2021-01-29 13:00:54 | [diff] [blame] | 2179 | const std::vector<network::mojom::ContentSecurityPolicyPtr>& root_csp = |
| 2180 | current_frame_host() |
Antonio Sartori | f45b2fc | 2021-03-04 10:15:07 | [diff] [blame] | 2181 | ->policy_container_host() |
| 2182 | ->policies() |
| 2183 | .content_security_policies; |
arthursonzogni | 76098e5 | 2020-11-25 14:18:45 | [diff] [blame] | 2184 | ASSERT_EQ(1u, root_csp.size()); |
Antonio Sartori | 8f5b7ee | 2021-01-29 13:00:54 | [diff] [blame] | 2185 | ASSERT_EQ("sandbox", root_csp[0]->header->header_value); |
arthursonzogni | 76098e5 | 2020-11-25 14:18:45 | [diff] [blame] | 2186 | ASSERT_EQ(network::mojom::WebSandboxFlags::kAll, |
| 2187 | current_frame_host()->active_sandbox_flags()); |
Lei Zhang | 05c13df | 2024-07-10 20:59:12 | [diff] [blame] | 2188 | } |
Alexander Timin | 45b716c | 2020-11-06 01:40:31 | [diff] [blame] | 2189 | } |
| 2190 | |
Hajime Hoshi | c760650 | 2021-04-14 02:42:16 | [diff] [blame] | 2191 | // Check that about:blank is not cached. |
| 2192 | IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, AboutBlankWillNotBeCached) { |
| 2193 | ASSERT_TRUE(embedded_test_server()->Start()); |
| 2194 | |
| 2195 | // 1) Navigate to about:blank. |
| 2196 | GURL blank_url(url::kAboutBlankURL); |
| 2197 | EXPECT_TRUE(NavigateToURL(shell(), blank_url)); |
Rakina Zata Amni | 4cab082 | 2023-10-26 12:28:24 | [diff] [blame] | 2198 | RenderFrameHostImplWrapper rfh_blank(current_frame_host()); |
Hajime Hoshi | c760650 | 2021-04-14 02:42:16 | [diff] [blame] | 2199 | |
| 2200 | // 2) Navigate to a.com. |
| 2201 | GURL url_a(embedded_test_server()->GetURL("a.com", "/empty.html")); |
| 2202 | EXPECT_TRUE(NavigateToURL(shell(), url_a)); |
| 2203 | |
| 2204 | // 3) Navigate back to about:blank. |
Fergal Daly | 5495b0e | 2021-11-19 02:03:28 | [diff] [blame] | 2205 | ASSERT_TRUE(HistoryGoBack(web_contents())); |
Hajime Hoshi | c760650 | 2021-04-14 02:42:16 | [diff] [blame] | 2206 | |
| 2207 | // This about:blank document does not have a SiteInstance and then loading a |
| 2208 | // page on it doesn't swap the browsing instance. |
Rakina Zata Amni | 4cab082 | 2023-10-26 12:28:24 | [diff] [blame] | 2209 | |
| 2210 | if (ShouldCreateNewHostForAllFrames()) { |
| 2211 | EXPECT_TRUE(rfh_blank.WaitUntilRenderFrameDeleted()); |
| 2212 | ExpectNotRestored( |
| 2213 | { |
| 2214 | BackForwardCacheMetrics::NotRestoredReason::kHTTPStatusNotOK, |
| 2215 | BackForwardCacheMetrics::NotRestoredReason::kSchemeNotHTTPOrHTTPS, |
| 2216 | BackForwardCacheMetrics::NotRestoredReason:: |
| 2217 | kBrowsingInstanceNotSwapped, |
Rakina Zata Amni | 4cab082 | 2023-10-26 12:28:24 | [diff] [blame] | 2218 | }, |
| 2219 | {}, {ShouldSwapBrowsingInstance::kNo_DoesNotHaveSite}, {}, {}, |
| 2220 | FROM_HERE); |
| 2221 | |
| 2222 | } else { |
| 2223 | EXPECT_FALSE(rfh_blank->IsInBackForwardCache()); |
| 2224 | ExpectNotRestored( |
| 2225 | { |
| 2226 | BackForwardCacheMetrics::NotRestoredReason:: |
| 2227 | kBrowsingInstanceNotSwapped, |
| 2228 | }, |
| 2229 | {}, {ShouldSwapBrowsingInstance::kNo_DoesNotHaveSite}, {}, {}, |
| 2230 | FROM_HERE); |
| 2231 | } |
Hajime Hoshi | c760650 | 2021-04-14 02:42:16 | [diff] [blame] | 2232 | } |
| 2233 | |
Hajime Hoshi | c760650 | 2021-04-14 02:42:16 | [diff] [blame] | 2234 | // Check that browsing instances are not swapped when a navigation redirects |
| 2235 | // toward the last committed URL and the reasons are recorded correctly. |
| 2236 | IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, RedirectToSelf) { |
| 2237 | ASSERT_TRUE(embedded_test_server()->Start()); |
| 2238 | NavigationControllerImpl& controller = web_contents()->GetController(); |
| 2239 | |
| 2240 | // 1) Navigate to a.com/empty.html. |
| 2241 | GURL url_a(embedded_test_server()->GetURL("a.com", "/empty.html")); |
| 2242 | EXPECT_TRUE(NavigateToURL(shell(), url_a)); |
Rakina Zata Amni | 4cab082 | 2023-10-26 12:28:24 | [diff] [blame] | 2243 | RenderFrameHostImplWrapper rfh_a(current_frame_host()); |
Hajime Hoshi | c760650 | 2021-04-14 02:42:16 | [diff] [blame] | 2244 | EXPECT_EQ(1, controller.GetEntryCount()); |
| 2245 | EXPECT_EQ(url_a, controller.GetLastCommittedEntry()->GetURL()); |
| 2246 | |
| 2247 | // 2) Navigate to the same page by redirection. |
| 2248 | GURL url_a2(embedded_test_server()->GetURL( |
| 2249 | "a.com", "/server-redirect-301?" + url_a.spec())); |
| 2250 | EXPECT_TRUE(NavigateToURL(shell(), url_a2, url_a)); |
Rakina Zata Amni | 4cab082 | 2023-10-26 12:28:24 | [diff] [blame] | 2251 | RenderFrameHostImplWrapper rfh_b(current_frame_host()); |
Hajime Hoshi | c760650 | 2021-04-14 02:42:16 | [diff] [blame] | 2252 | EXPECT_EQ(2, controller.GetEntryCount()); |
| 2253 | |
Rakina Zata Amni | 4cab082 | 2023-10-26 12:28:24 | [diff] [blame] | 2254 | if (ShouldCreateNewHostForAllFrames()) { |
| 2255 | EXPECT_TRUE(rfh_a.WaitUntilRenderFrameDeleted()); |
| 2256 | } else { |
| 2257 | EXPECT_FALSE(rfh_a->IsInBackForwardCache()); |
| 2258 | EXPECT_TRUE(rfh_a->GetSiteInstance()->IsRelatedSiteInstance( |
| 2259 | rfh_b->GetSiteInstance())); |
| 2260 | } |
| 2261 | |
Hajime Hoshi | c760650 | 2021-04-14 02:42:16 | [diff] [blame] | 2262 | EXPECT_EQ(url_a, controller.GetLastCommittedEntry()->GetURL()); |
| 2263 | |
| 2264 | // 3) Navigate back to the previous page. |
Fergal Daly | 5495b0e | 2021-11-19 02:03:28 | [diff] [blame] | 2265 | ASSERT_TRUE(HistoryGoBack(web_contents())); |
Hajime Hoshi | c760650 | 2021-04-14 02:42:16 | [diff] [blame] | 2266 | EXPECT_EQ(2, controller.GetEntryCount()); |
| 2267 | EXPECT_EQ(url_a, controller.GetLastCommittedEntry()->GetURL()); |
| 2268 | |
Alison Gale | 81f4f2c7 | 2024-04-22 19:33:31 | [diff] [blame] | 2269 | // TODO(crbug.com/40760515): Investigate whether these navigation results are |
Hajime Hoshi | c760650 | 2021-04-14 02:42:16 | [diff] [blame] | 2270 | // expected. |
Hajime Hoshi | c760650 | 2021-04-14 02:42:16 | [diff] [blame] | 2271 | ExpectNotRestored( |
| 2272 | { |
| 2273 | BackForwardCacheMetrics::NotRestoredReason:: |
| 2274 | kBrowsingInstanceNotSwapped, |
| 2275 | }, |
Fergal Daly | 1336ac64 | 2021-09-14 15:13:11 | [diff] [blame] | 2276 | {}, {ShouldSwapBrowsingInstance::kNo_SameUrlNavigation}, {}, {}, |
| 2277 | FROM_HERE); |
Hajime Hoshi | c760650 | 2021-04-14 02:42:16 | [diff] [blame] | 2278 | } |
| 2279 | |
Hajime Hoshi | c760650 | 2021-04-14 02:42:16 | [diff] [blame] | 2280 | // Check that reloading doesn't affect the back-forward cache usage. |
| 2281 | IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, ReloadDoesntAffectCache) { |
| 2282 | ASSERT_TRUE(embedded_test_server()->Start()); |
| 2283 | NavigationControllerImpl& controller = web_contents()->GetController(); |
| 2284 | |
| 2285 | // 1) Navigate to a.com. |
| 2286 | GURL url_a(embedded_test_server()->GetURL("a.com", "/empty.html")); |
| 2287 | EXPECT_TRUE(NavigateToURL(shell(), url_a)); |
| 2288 | EXPECT_EQ(1, controller.GetEntryCount()); |
| 2289 | EXPECT_EQ(url_a, controller.GetLastCommittedEntry()->GetURL()); |
| 2290 | |
| 2291 | // 2) Navigate to b.com. |
| 2292 | GURL url_b(embedded_test_server()->GetURL("b.com", "/empty.html")); |
| 2293 | EXPECT_TRUE(NavigateToURL(shell(), url_b)); |
| 2294 | EXPECT_EQ(2, controller.GetEntryCount()); |
| 2295 | EXPECT_EQ(url_b, controller.GetLastCommittedEntry()->GetURL()); |
| 2296 | |
| 2297 | // 3) Go back to a.com and reload. |
Fergal Daly | 5495b0e | 2021-11-19 02:03:28 | [diff] [blame] | 2298 | ASSERT_TRUE(HistoryGoBack(web_contents())); |
Hajime Hoshi | c760650 | 2021-04-14 02:42:16 | [diff] [blame] | 2299 | EXPECT_EQ(2, controller.GetEntryCount()); |
| 2300 | EXPECT_EQ(url_a, controller.GetLastCommittedEntry()->GetURL()); |
| 2301 | |
| 2302 | ExpectRestored(FROM_HERE); |
| 2303 | |
| 2304 | // 4) Reload the tab. |
| 2305 | web_contents()->GetController().Reload(content::ReloadType::NORMAL, false); |
| 2306 | EXPECT_TRUE(WaitForLoadStop(web_contents())); |
| 2307 | EXPECT_EQ(2, controller.GetEntryCount()); |
| 2308 | EXPECT_EQ(url_a, controller.GetLastCommittedEntry()->GetURL()); |
| 2309 | |
| 2310 | // By reloading the tab, ShouldSwapBrowsingInstance:: |
| 2311 | // kNo_AlreadyHasMatchingBrowsingInstance is set once. This should be reset |
| 2312 | // when the navigation 4)'s commit finishes and should not prevent putting the |
| 2313 | // page into the back-forward cache. |
| 2314 | // |
Hajime Hoshi | 0761844 | 2021-04-21 08:38:00 | [diff] [blame] | 2315 | // Note that SetBrowsingInstanceSwapResult might not be called for every |
Hajime Hoshi | c760650 | 2021-04-14 02:42:16 | [diff] [blame] | 2316 | // navigation because we might not get to this point for some navigations, |
| 2317 | // e.g. if the navigation uses a pre-existing RenderFrameHost and SiteInstance |
| 2318 | // for navigation. |
| 2319 | // |
Alison Gale | 81f4f2c7 | 2024-04-22 19:33:31 | [diff] [blame] | 2320 | // TODO(crbug.com/40747698): Tie BrowsingInstanceSwapResult to |
Hajime Hoshi | 0761844 | 2021-04-21 08:38:00 | [diff] [blame] | 2321 | // NavigationRequest instead and move the SetBrowsingInstanceSwapResult call |
| 2322 | // for navigations to happen at commit time instead. |
Hajime Hoshi | c760650 | 2021-04-14 02:42:16 | [diff] [blame] | 2323 | |
| 2324 | // 5) Go forward to b.com and reload. |
Fergal Daly | 5495b0e | 2021-11-19 02:03:28 | [diff] [blame] | 2325 | ASSERT_TRUE(HistoryGoForward(web_contents())); |
Hajime Hoshi | c760650 | 2021-04-14 02:42:16 | [diff] [blame] | 2326 | EXPECT_EQ(2, controller.GetEntryCount()); |
| 2327 | EXPECT_EQ(url_b, controller.GetLastCommittedEntry()->GetURL()); |
| 2328 | |
| 2329 | // The page loaded at B) is correctly cached and restored. Reloading doesn't |
| 2330 | // affect the cache usage. |
| 2331 | ExpectRestored(FROM_HERE); |
| 2332 | |
| 2333 | // 6) Go back to a.com. |
Fergal Daly | 5495b0e | 2021-11-19 02:03:28 | [diff] [blame] | 2334 | ASSERT_TRUE(HistoryGoBack(web_contents())); |
Hajime Hoshi | c760650 | 2021-04-14 02:42:16 | [diff] [blame] | 2335 | EXPECT_EQ(2, controller.GetEntryCount()); |
| 2336 | EXPECT_EQ(url_a, controller.GetLastCommittedEntry()->GetURL()); |
| 2337 | |
| 2338 | // The page loaded at 3) is correctly cached and restored. Reloading doesn't |
| 2339 | // affect the cache usage. |
| 2340 | ExpectRestored(FROM_HERE); |
| 2341 | } |
| 2342 | |
Rakina Zata Amni | a655868 | 2021-03-05 04:10:57 | [diff] [blame] | 2343 | // Regression test for crbug.com/1183313. Checks that CommitNavigationParam's |
| 2344 | // |has_user_gesture| value reflects the gesture from the latest navigation |
| 2345 | // after the commit finished. |
| 2346 | IN_PROC_BROWSER_TEST_F( |
| 2347 | BackForwardCacheBrowserTest, |
| 2348 | SameDocumentNavAfterRestoringDocumentLoadedWithUserGesture) { |
| 2349 | ASSERT_TRUE(embedded_test_server()->Start()); |
| 2350 | |
| 2351 | GURL start_url(embedded_test_server()->GetURL("/title1.html")); |
| 2352 | GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html")); |
| 2353 | GURL url_a_foo(embedded_test_server()->GetURL("a.com", "/title1.html#foo")); |
| 2354 | GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html")); |
| 2355 | NavigationControllerImpl& controller = web_contents()->GetController(); |
| 2356 | FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents()) |
Carlos Caballero | 15caeeb | 2021-10-27 09:57:55 | [diff] [blame] | 2357 | ->GetPrimaryFrameTree() |
| 2358 | .root(); |
Rakina Zata Amni | a655868 | 2021-03-05 04:10:57 | [diff] [blame] | 2359 | |
| 2360 | // Initial navigation (so that we can initiate a navigation from renderer). |
| 2361 | EXPECT_TRUE(NavigateToURL(shell(), start_url)); |
| 2362 | |
| 2363 | // 1) Navigate to A with user gesture. |
| 2364 | { |
| 2365 | FrameNavigateParamsCapturer params_capturer(root); |
| 2366 | EXPECT_TRUE(NavigateToURLFromRenderer(shell(), url_a)); |
| 2367 | params_capturer.Wait(); |
| 2368 | EXPECT_TRUE(params_capturer.has_user_gesture()); |
Rakina Zata Amni | ff10975d | 2021-10-08 06:04:24 | [diff] [blame] | 2369 | EXPECT_TRUE(root->current_frame_host() |
Yao Xiao | d553b70 | 2022-12-08 02:20:47 | [diff] [blame] | 2370 | ->last_committed_common_params_has_user_gesture()); |
Rakina Zata Amni | a655868 | 2021-03-05 04:10:57 | [diff] [blame] | 2371 | } |
| 2372 | RenderFrameHostImpl* rfh_a = current_frame_host(); |
| 2373 | |
| 2374 | // 2) Navigate to B. A should be stored in the back-forward cache. |
| 2375 | EXPECT_TRUE(NavigateToURL(shell(), url_b)); |
| 2376 | EXPECT_TRUE(rfh_a->IsInBackForwardCache()); |
Rakina Zata Amni | ff10975d | 2021-10-08 06:04:24 | [diff] [blame] | 2377 | EXPECT_FALSE(root->current_frame_host() |
Yao Xiao | d553b70 | 2022-12-08 02:20:47 | [diff] [blame] | 2378 | ->last_committed_common_params_has_user_gesture()); |
Rakina Zata Amni | a655868 | 2021-03-05 04:10:57 | [diff] [blame] | 2379 | |
| 2380 | // 3) GoBack to A. RenderFrameHost of A should be restored from the |
| 2381 | // back-forward cache, and "has_user_gesture" is set to false correctly. |
| 2382 | // Note that since this is a back-forward cache restore we create the |
| 2383 | // DidCommitProvisionalLoadParams completely in the browser, so we got the |
| 2384 | // correct value from the latest navigation. However, we did not update the |
| 2385 | // renderer's navigation-related values, so the renderer's DocumentLoader |
| 2386 | // still thinks the last "gesture" value is "true", which will get corrected |
| 2387 | // on the next navigation. |
| 2388 | { |
| 2389 | FrameNavigateParamsCapturer params_capturer(root); |
| 2390 | controller.GoBack(); |
| 2391 | params_capturer.Wait(); |
| 2392 | EXPECT_TRUE(WaitForLoadStop(shell()->web_contents())); |
| 2393 | EXPECT_EQ(rfh_a, current_frame_host()); |
| 2394 | // The navigation doesn't have user gesture. |
| 2395 | EXPECT_FALSE(params_capturer.has_user_gesture()); |
Rakina Zata Amni | ff10975d | 2021-10-08 06:04:24 | [diff] [blame] | 2396 | EXPECT_FALSE(root->current_frame_host() |
Yao Xiao | d553b70 | 2022-12-08 02:20:47 | [diff] [blame] | 2397 | ->last_committed_common_params_has_user_gesture()); |
Rakina Zata Amni | a655868 | 2021-03-05 04:10:57 | [diff] [blame] | 2398 | } |
| 2399 | |
| 2400 | // 4) Same-document navigation to A#foo without user gesture. At this point |
| 2401 | // we will update the renderer's DocumentLoader's latest gesture value to |
| 2402 | // "no user gesture", and we'll get the correct gesture value in |
| 2403 | // DidCommitProvisionalLoadParams. |
| 2404 | { |
| 2405 | FrameNavigateParamsCapturer params_capturer(root); |
| 2406 | EXPECT_TRUE( |
| 2407 | NavigateToURLFromRendererWithoutUserGesture(shell(), url_a_foo)); |
| 2408 | params_capturer.Wait(); |
| 2409 | // The navigation doesn't have user gesture. |
| 2410 | EXPECT_FALSE(params_capturer.has_user_gesture()); |
Rakina Zata Amni | ff10975d | 2021-10-08 06:04:24 | [diff] [blame] | 2411 | EXPECT_FALSE(root->current_frame_host() |
Yao Xiao | d553b70 | 2022-12-08 02:20:47 | [diff] [blame] | 2412 | ->last_committed_common_params_has_user_gesture()); |
Rakina Zata Amni | a655868 | 2021-03-05 04:10:57 | [diff] [blame] | 2413 | } |
| 2414 | } |
| 2415 | |
Riho Isawa | b1efe68f | 2021-12-20 01:54:07 | [diff] [blame] | 2416 | testing::Matcher<BackForwardCacheCanStoreTreeResult> MatchesTreeResult( |
| 2417 | testing::Matcher<bool> same_origin, |
| 2418 | GURL url) { |
| 2419 | return testing::AllOf( |
| 2420 | testing::Property("IsSameOrigin", |
| 2421 | &BackForwardCacheCanStoreTreeResult::IsSameOrigin, |
| 2422 | same_origin), |
| 2423 | testing::Property("GetUrl", &BackForwardCacheCanStoreTreeResult::GetUrl, |
| 2424 | url)); |
| 2425 | } |
| 2426 | |
| 2427 | RenderFrameHostImpl* ChildFrame(RenderFrameHostImpl* rfh, int child_index) { |
| 2428 | return rfh->child_at(child_index)->current_frame_host(); |
| 2429 | } |
| 2430 | |
| 2431 | // Verifies that the reasons match those given and no others. |
Yuzu Saijo | c347807 | 2022-03-24 06:15:26 | [diff] [blame] | 2432 | testing::Matcher<BackForwardCacheCanStoreDocumentResult> |
| 2433 | BackForwardCacheBrowserTest::MatchesDocumentResult( |
Yuzu Saijo | dcabe56 | 2022-04-25 06:06:39 | [diff] [blame] | 2434 | testing::Matcher<NotRestoredReasons> not_stored, |
Riho Isawa | b1efe68f | 2021-12-20 01:54:07 | [diff] [blame] | 2435 | BlockListedFeatures block_listed) { |
| 2436 | return testing::AllOf( |
| 2437 | testing::Property( |
Yuzu Saijo | dcabe56 | 2022-04-25 06:06:39 | [diff] [blame] | 2438 | "not_restored_reasons", |
| 2439 | &BackForwardCacheCanStoreDocumentResult::not_restored_reasons, |
Riho Isawa | b1efe68f | 2021-12-20 01:54:07 | [diff] [blame] | 2440 | not_stored), |
| 2441 | testing::Property( |
| 2442 | "blocklisted_features", |
| 2443 | &BackForwardCacheCanStoreDocumentResult::blocklisted_features, |
| 2444 | block_listed), |
| 2445 | testing::Property( |
| 2446 | "disabled_reasons", |
| 2447 | &BackForwardCacheCanStoreDocumentResult::disabled_reasons, |
Mingyu Lei | 8c1b911 | 2023-01-18 03:59:01 | [diff] [blame] | 2448 | BackForwardCacheCanStoreDocumentResult::DisabledReasonsMap()), |
Riho Isawa | b1efe68f | 2021-12-20 01:54:07 | [diff] [blame] | 2449 | testing::Property( |
| 2450 | "disallow_activation_reasons", |
| 2451 | &BackForwardCacheCanStoreDocumentResult::disallow_activation_reasons, |
| 2452 | std::set<uint64_t>())); |
| 2453 | } |
| 2454 | |
| 2455 | // Check the contents of the BackForwardCacheCanStoreTreeResult of a page. |
Yuzu Saijo | c347807 | 2022-03-24 06:15:26 | [diff] [blame] | 2456 | IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, TreeResultFeatureUsage) { |
Riho Isawa | b1efe68f | 2021-12-20 01:54:07 | [diff] [blame] | 2457 | ASSERT_TRUE(embedded_test_server()->Start()); |
| 2458 | GURL url_a(embedded_test_server()->GetURL( |
| 2459 | "a.com", "/cross_site_iframe_factory.html?a(a, b, c)")); |
Fergal Daly | 306fc3f | 2021-12-23 09:58:30 | [diff] [blame] | 2460 | GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html")); |
Riho Isawa | b1efe68f | 2021-12-20 01:54:07 | [diff] [blame] | 2461 | |
| 2462 | // 1) Navigate to a(a, b, c). |
Fergal Daly | 306fc3f | 2021-12-23 09:58:30 | [diff] [blame] | 2463 | ASSERT_TRUE(NavigateToURL(shell(), url_a)); |
| 2464 | RenderFrameHostImplWrapper rfh(current_frame_host()); |
Riho Isawa | b1efe68f | 2021-12-20 01:54:07 | [diff] [blame] | 2465 | |
| 2466 | // 2) Add a blocking feature to the main frame A and the sub frame B. |
| 2467 | current_frame_host() |
| 2468 | ->UseDummyStickyBackForwardCacheDisablingFeatureForTesting(); |
| 2469 | current_frame_host() |
| 2470 | ->child_at(1) |
| 2471 | ->current_frame_host() |
| 2472 | ->UseDummyStickyBackForwardCacheDisablingFeatureForTesting(); |
| 2473 | |
Fergal Daly | 306fc3f | 2021-12-23 09:58:30 | [diff] [blame] | 2474 | GURL url_subframe_a = ChildFrame(rfh.get(), 0)->GetLastCommittedURL(); |
| 2475 | GURL url_subframe_b = ChildFrame(rfh.get(), 1)->GetLastCommittedURL(); |
| 2476 | GURL url_subframe_c = ChildFrame(rfh.get(), 2)->GetLastCommittedURL(); |
| 2477 | |
| 2478 | // 3) Initialize the reasons tree and navigate away to ensure that everything |
| 2479 | // from the old frame has been destroyed. |
Riho Isawa | b1efe68f | 2021-12-20 01:54:07 | [diff] [blame] | 2480 | BackForwardCacheCanStoreDocumentResultWithTree can_store_result = |
Yuzu Saijo | ef104a0 | 2022-05-13 17:04:28 | [diff] [blame] | 2481 | web_contents() |
| 2482 | ->GetController() |
| 2483 | .GetBackForwardCache() |
| 2484 | .GetCurrentBackForwardCacheEligibility(rfh.get()); |
Fergal Daly | 306fc3f | 2021-12-23 09:58:30 | [diff] [blame] | 2485 | ASSERT_TRUE(NavigateToURL(shell(), url_b)); |
| 2486 | ASSERT_TRUE(rfh.WaitUntilRenderFrameDeleted()); |
Riho Isawa | b1efe68f | 2021-12-20 01:54:07 | [diff] [blame] | 2487 | |
| 2488 | // 4) Check IsSameOrigin() and GetUrl(). |
| 2489 | // a |
| 2490 | EXPECT_THAT(*can_store_result.tree_reasons, |
| 2491 | MatchesTreeResult(/*same_origin=*/true, |
Fergal Daly | 306fc3f | 2021-12-23 09:58:30 | [diff] [blame] | 2492 | /*url=*/url_a)); |
Riho Isawa | b1efe68f | 2021-12-20 01:54:07 | [diff] [blame] | 2493 | // a->a |
Fergal Daly | 306fc3f | 2021-12-23 09:58:30 | [diff] [blame] | 2494 | EXPECT_THAT(*can_store_result.tree_reasons->GetChildren().at(0), |
| 2495 | MatchesTreeResult(/*same_origin=*/true, |
| 2496 | /*url=*/url_subframe_a)); |
Riho Isawa | b1efe68f | 2021-12-20 01:54:07 | [diff] [blame] | 2497 | // a->b |
Fergal Daly | 306fc3f | 2021-12-23 09:58:30 | [diff] [blame] | 2498 | EXPECT_THAT(*can_store_result.tree_reasons->GetChildren().at(1), |
| 2499 | MatchesTreeResult(/*same_origin=*/false, |
| 2500 | /*url=*/url_subframe_b)); |
Riho Isawa | b1efe68f | 2021-12-20 01:54:07 | [diff] [blame] | 2501 | // a->c |
Fergal Daly | 306fc3f | 2021-12-23 09:58:30 | [diff] [blame] | 2502 | EXPECT_THAT(*can_store_result.tree_reasons->GetChildren().at(2), |
| 2503 | MatchesTreeResult(/*same_origin=*/false, |
| 2504 | /*url=*/url_subframe_c)); |
Riho Isawa | b1efe68f | 2021-12-20 01:54:07 | [diff] [blame] | 2505 | |
| 2506 | // 5) Check that the blocking reasons match. |
| 2507 | // a |
| 2508 | EXPECT_THAT(can_store_result.tree_reasons->GetDocumentResult(), |
| 2509 | MatchesDocumentResult( |
Maksim Moskvitin | 13f5b97 | 2023-05-15 16:24:59 | [diff] [blame] | 2510 | NotRestoredReasons({NotRestoredReason::kBlocklistedFeatures}), |
Riho Isawa | b1efe68f | 2021-12-20 01:54:07 | [diff] [blame] | 2511 | BlockListedFeatures( |
Maksim Moskvitin | 13f5b97 | 2023-05-15 16:24:59 | [diff] [blame] | 2512 | {blink::scheduler::WebSchedulerTrackedFeature::kDummy}))); |
Riho Isawa | b1efe68f | 2021-12-20 01:54:07 | [diff] [blame] | 2513 | // a->a |
| 2514 | EXPECT_THAT( |
| 2515 | can_store_result.tree_reasons->GetChildren().at(0)->GetDocumentResult(), |
Yuzu Saijo | dcabe56 | 2022-04-25 06:06:39 | [diff] [blame] | 2516 | MatchesDocumentResult(NotRestoredReasons(), |
Riho Isawa | b1efe68f | 2021-12-20 01:54:07 | [diff] [blame] | 2517 | BlockListedFeatures(BlockListedFeatures()))); |
| 2518 | // a->b |
| 2519 | EXPECT_THAT( |
| 2520 | can_store_result.tree_reasons->GetChildren().at(1)->GetDocumentResult(), |
| 2521 | MatchesDocumentResult( |
Maksim Moskvitin | 13f5b97 | 2023-05-15 16:24:59 | [diff] [blame] | 2522 | NotRestoredReasons({NotRestoredReason::kBlocklistedFeatures}), |
Riho Isawa | b1efe68f | 2021-12-20 01:54:07 | [diff] [blame] | 2523 | BlockListedFeatures( |
Maksim Moskvitin | 13f5b97 | 2023-05-15 16:24:59 | [diff] [blame] | 2524 | {blink::scheduler::WebSchedulerTrackedFeature::kDummy}))); |
Riho Isawa | b1efe68f | 2021-12-20 01:54:07 | [diff] [blame] | 2525 | // a->c |
| 2526 | EXPECT_THAT( |
| 2527 | can_store_result.tree_reasons->GetChildren().at(2)->GetDocumentResult(), |
Yuzu Saijo | dcabe56 | 2022-04-25 06:06:39 | [diff] [blame] | 2528 | MatchesDocumentResult(NotRestoredReasons(), |
Riho Isawa | b1efe68f | 2021-12-20 01:54:07 | [diff] [blame] | 2529 | BlockListedFeatures(BlockListedFeatures()))); |
| 2530 | } |
| 2531 | |
Yuzu Saijo | c347807 | 2022-03-24 06:15:26 | [diff] [blame] | 2532 | // Check the contents of the BackForwardCacheCanStoreTreeResult of a page when |
| 2533 | // it is evicted. |
| 2534 | IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, |
| 2535 | TreeResultEvictionMainFrame) { |
| 2536 | ASSERT_TRUE(embedded_test_server()->Start()); |
| 2537 | GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html")); |
| 2538 | GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html")); |
| 2539 | |
| 2540 | // 1) Navigate to a. |
| 2541 | ASSERT_TRUE(NavigateToURL(shell(), url_a)); |
| 2542 | RenderFrameHostImplWrapper rfh_a(current_frame_host()); |
| 2543 | rfh_a->GetBackForwardCacheMetrics()->SetObserverForTesting(this); |
| 2544 | |
| 2545 | // 2) Navigate to B and evict A by JavaScript execution. |
| 2546 | ASSERT_TRUE(NavigateToURL(shell(), url_b)); |
| 2547 | EvictByJavaScript(rfh_a.get()); |
| 2548 | ASSERT_TRUE(rfh_a.WaitUntilRenderFrameDeleted()); |
| 2549 | |
| 2550 | // 3) Go back to A. |
| 2551 | ASSERT_TRUE(HistoryGoBack(web_contents())); |
| 2552 | ExpectNotRestored({NotRestoredReason::kJavaScriptExecution}, {}, {}, {}, {}, |
| 2553 | FROM_HERE); |
| 2554 | EXPECT_THAT(GetTreeResult()->GetDocumentResult(), |
| 2555 | MatchesDocumentResult( |
Maksim Moskvitin | 13f5b97 | 2023-05-15 16:24:59 | [diff] [blame] | 2556 | NotRestoredReasons({NotRestoredReason::kJavaScriptExecution}), |
Yuzu Saijo | c347807 | 2022-03-24 06:15:26 | [diff] [blame] | 2557 | BlockListedFeatures())); |
| 2558 | } |
| 2559 | |
| 2560 | // Check the contents of the BackForwardCacheCanStoreTreeResult of a page when |
| 2561 | // its subframe is evicted. |
| 2562 | IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, |
| 2563 | TreeResultEvictionSubFrame) { |
| 2564 | ASSERT_TRUE(embedded_test_server()->Start()); |
| 2565 | GURL url_a(embedded_test_server()->GetURL( |
| 2566 | "a.com", "/cross_site_iframe_factory.html?a(b)")); |
| 2567 | GURL url_c(embedded_test_server()->GetURL("c.com", "/title1.html")); |
| 2568 | |
| 2569 | // 1) Navigate to A. |
| 2570 | ASSERT_TRUE(NavigateToURL(shell(), url_a)); |
| 2571 | RenderFrameHostImplWrapper rfh_a(current_frame_host()); |
| 2572 | RenderFrameHostImplWrapper rfh_b( |
| 2573 | current_frame_host()->child_at(0)->current_frame_host()); |
| 2574 | rfh_a->GetBackForwardCacheMetrics()->SetObserverForTesting(this); |
| 2575 | |
| 2576 | // 2) Navigate to C and evict A's subframe B by JavaScript execution. |
| 2577 | ASSERT_TRUE(NavigateToURL(shell(), url_c)); |
| 2578 | EvictByJavaScript(rfh_b.get()); |
| 2579 | ASSERT_TRUE(rfh_a.WaitUntilRenderFrameDeleted()); |
| 2580 | |
| 2581 | // 3) Go back to A. |
| 2582 | ASSERT_TRUE(HistoryGoBack(web_contents())); |
| 2583 | ExpectNotRestored({NotRestoredReason::kJavaScriptExecution}, {}, {}, {}, {}, |
| 2584 | FROM_HERE); |
| 2585 | // Main frame result in the tree is empty. |
Yuzu Saijo | dcabe56 | 2022-04-25 06:06:39 | [diff] [blame] | 2586 | EXPECT_THAT( |
| 2587 | GetTreeResult()->GetDocumentResult(), |
| 2588 | MatchesDocumentResult(NotRestoredReasons(), BlockListedFeatures())); |
Yuzu Saijo | c347807 | 2022-03-24 06:15:26 | [diff] [blame] | 2589 | // Subframe result in the tree contains the reason. |
| 2590 | EXPECT_THAT(GetTreeResult()->GetChildren().at(0)->GetDocumentResult(), |
| 2591 | MatchesDocumentResult( |
Maksim Moskvitin | 13f5b97 | 2023-05-15 16:24:59 | [diff] [blame] | 2592 | NotRestoredReasons({NotRestoredReason::kJavaScriptExecution}), |
Yuzu Saijo | c347807 | 2022-03-24 06:15:26 | [diff] [blame] | 2593 | BlockListedFeatures())); |
| 2594 | } |
| 2595 | |
| 2596 | // Check the contents of the BackForwardCacheCanStoreTreeResult of a page when |
| 2597 | // its subframe's subframe is evicted. |
| 2598 | IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, |
| 2599 | TreeResultEvictionSubFramesSubframe) { |
| 2600 | ASSERT_TRUE(embedded_test_server()->Start()); |
| 2601 | GURL url_a(embedded_test_server()->GetURL( |
| 2602 | "a.com", "/cross_site_iframe_factory.html?a(b(c))")); |
| 2603 | GURL url_d(embedded_test_server()->GetURL("d.com", "/title1.html")); |
| 2604 | |
| 2605 | // 1) Navigate to A. |
| 2606 | ASSERT_TRUE(NavigateToURL(shell(), url_a)); |
| 2607 | RenderFrameHostImplWrapper rfh_a(current_frame_host()); |
| 2608 | RenderFrameHostImplWrapper rfh_c(current_frame_host() |
| 2609 | ->child_at(0) |
| 2610 | ->current_frame_host() |
| 2611 | ->child_at(0) |
| 2612 | ->current_frame_host()); |
| 2613 | rfh_a->GetBackForwardCacheMetrics()->SetObserverForTesting(this); |
| 2614 | |
| 2615 | // 2) Navigate to D and evict C by JavaScript execution. |
| 2616 | ASSERT_TRUE(NavigateToURL(shell(), url_d)); |
| 2617 | EvictByJavaScript(rfh_c.get()); |
| 2618 | ASSERT_TRUE(rfh_a.WaitUntilRenderFrameDeleted()); |
| 2619 | |
| 2620 | // 3) Go back to A. |
| 2621 | ASSERT_TRUE(HistoryGoBack(web_contents())); |
| 2622 | ExpectNotRestored({NotRestoredReason::kJavaScriptExecution}, {}, {}, {}, {}, |
| 2623 | FROM_HERE); |
| 2624 | // Main frame result in the tree is empty. |
Yuzu Saijo | dcabe56 | 2022-04-25 06:06:39 | [diff] [blame] | 2625 | EXPECT_THAT( |
| 2626 | GetTreeResult()->GetDocumentResult(), |
| 2627 | MatchesDocumentResult(NotRestoredReasons(), BlockListedFeatures())); |
Yuzu Saijo | c347807 | 2022-03-24 06:15:26 | [diff] [blame] | 2628 | // The first level subframe result in the tree is empty. |
Yuzu Saijo | dcabe56 | 2022-04-25 06:06:39 | [diff] [blame] | 2629 | EXPECT_THAT( |
| 2630 | GetTreeResult()->GetChildren().at(0)->GetDocumentResult(), |
| 2631 | MatchesDocumentResult(NotRestoredReasons(), BlockListedFeatures())); |
Yuzu Saijo | c347807 | 2022-03-24 06:15:26 | [diff] [blame] | 2632 | // The second level subframe result in the tree contains the reason. |
| 2633 | EXPECT_THAT(GetTreeResult() |
| 2634 | ->GetChildren() |
| 2635 | .at(0) |
| 2636 | ->GetChildren() |
| 2637 | .at(0) |
| 2638 | ->GetDocumentResult(), |
| 2639 | MatchesDocumentResult( |
Maksim Moskvitin | 13f5b97 | 2023-05-15 16:24:59 | [diff] [blame] | 2640 | NotRestoredReasons({NotRestoredReason::kJavaScriptExecution}), |
Yuzu Saijo | c347807 | 2022-03-24 06:15:26 | [diff] [blame] | 2641 | BlockListedFeatures())); |
| 2642 | } |
| 2643 | |
Yuzu Saijo | 7b7b9a7 | 2022-04-20 05:12:08 | [diff] [blame] | 2644 | void BackForwardCacheBrowserTest::InstallUnloadHandlerOnMainFrame() { |
| 2645 | EXPECT_TRUE(ExecJs(current_frame_host(), R"( |
Minoru Chikamune | 52d6dff | 2021-12-27 14:59:53 | [diff] [blame] | 2646 | localStorage["unload_run_count"] = 0; |
| 2647 | window.onunload = () => { |
| 2648 | localStorage["unload_run_count"] = |
| 2649 | 1 + parseInt(localStorage["unload_run_count"]); |
| 2650 | }; |
| 2651 | )")); |
Yuzu Saijo | 7b7b9a7 | 2022-04-20 05:12:08 | [diff] [blame] | 2652 | EXPECT_EQ("0", GetUnloadRunCount()); |
| 2653 | } |
Minoru Chikamune | 52d6dff | 2021-12-27 14:59:53 | [diff] [blame] | 2654 | |
Yuzu Saijo | 7b7b9a7 | 2022-04-20 05:12:08 | [diff] [blame] | 2655 | void BackForwardCacheBrowserTest::InstallUnloadHandlerOnSubFrame() { |
| 2656 | TestNavigationObserver navigation_observer(shell()->web_contents(), 1); |
| 2657 | EXPECT_TRUE(ExecJs(current_frame_host(), R"( |
kouhei | b3517d7d | 2021-05-19 07:48:56 | [diff] [blame] | 2658 | const iframeElement = document.createElement("iframe"); |
| 2659 | iframeElement.src = "%s"; |
| 2660 | document.body.appendChild(iframeElement); |
Minoru Chikamune | 52d6dff | 2021-12-27 14:59:53 | [diff] [blame] | 2661 | )")); |
Yuzu Saijo | 7b7b9a7 | 2022-04-20 05:12:08 | [diff] [blame] | 2662 | navigation_observer.Wait(); |
| 2663 | RenderFrameHostImpl* subframe_render_frame_host = |
| 2664 | current_frame_host()->child_at(0)->current_frame_host(); |
| 2665 | EXPECT_TRUE(ExecJs(subframe_render_frame_host, R"( |
Minoru Chikamune | 52d6dff | 2021-12-27 14:59:53 | [diff] [blame] | 2666 | localStorage["unload_run_count"] = 0; |
| 2667 | window.onunload = () => { |
| 2668 | localStorage["unload_run_count"] = |
| 2669 | 1 + parseInt(localStorage["unload_run_count"]); |
| 2670 | }; |
| 2671 | )")); |
Yuzu Saijo | 7b7b9a7 | 2022-04-20 05:12:08 | [diff] [blame] | 2672 | EXPECT_EQ("0", GetUnloadRunCount()); |
| 2673 | } |
Minoru Chikamune | 52d6dff | 2021-12-27 14:59:53 | [diff] [blame] | 2674 | |
Yuzu Saijo | 7b7b9a7 | 2022-04-20 05:12:08 | [diff] [blame] | 2675 | EvalJsResult BackForwardCacheBrowserTest::GetUnloadRunCount() { |
| 2676 | return GetLocalStorage(current_frame_host(), "unload_run_count"); |
| 2677 | } |
kouhei | b3517d7d | 2021-05-19 07:48:56 | [diff] [blame] | 2678 | |
Fergal Daly | 9909e09 | 2022-07-06 14:09:34 | [diff] [blame] | 2679 | bool BackForwardCacheBrowserTest::AddBlocklistedFeature(RenderFrameHost* rfh) { |
Ming-Ying Chung | 5a60c32 | 2022-09-29 04:09:31 | [diff] [blame] | 2680 | // Add kDummy as blocking feature. |
| 2681 | RenderFrameHostImplWrapper rfh_a(rfh); |
| 2682 | rfh_a->UseDummyStickyBackForwardCacheDisablingFeatureForTesting(); |
| 2683 | return true; |
Fergal Daly | 9909e09 | 2022-07-06 14:09:34 | [diff] [blame] | 2684 | } |
| 2685 | |
| 2686 | void BackForwardCacheBrowserTest::ExpectNotRestoredDueToBlocklistedFeature( |
| 2687 | base::Location location) { |
Ming-Ying Chung | 5a60c32 | 2022-09-29 04:09:31 | [diff] [blame] | 2688 | ExpectNotRestored({NotRestoredReason::kBlocklistedFeatures}, |
| 2689 | {blink::scheduler::WebSchedulerTrackedFeature::kDummy}, {}, |
| 2690 | {}, {}, location); |
Fergal Daly | 9909e09 | 2022-07-06 14:09:34 | [diff] [blame] | 2691 | } |
| 2692 | |
Ming-Ying Chung | a8e8a2e | 2022-08-16 06:04:50 | [diff] [blame] | 2693 | const ukm::TestAutoSetUkmRecorder& BackForwardCacheBrowserTest::ukm_recorder() { |
| 2694 | return *ukm_recorder_; |
| 2695 | } |
| 2696 | |
| 2697 | const base::HistogramTester& BackForwardCacheBrowserTest::histogram_tester() { |
| 2698 | return *histogram_tester_; |
Ming-Ying Chung | ee9b9ea | 2022-08-15 08:24:25 | [diff] [blame] | 2699 | } |
| 2700 | |
Fergal Daly | 97c4e59 | 2023-02-28 10:27:33 | [diff] [blame] | 2701 | // Ensure that psges with unload are only allowed to enter back/forward cache by |
| 2702 | // default on Android. |
| 2703 | IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, UnloadAllowedFlag) { |
| 2704 | #if BUILDFLAG(IS_ANDROID) |
| 2705 | ASSERT_TRUE(BackForwardCacheImpl::IsUnloadAllowed()); |
| 2706 | #else |
| 2707 | ASSERT_FALSE(BackForwardCacheImpl::IsUnloadAllowed()); |
| 2708 | #endif |
| 2709 | } |
| 2710 | |
Fergal Daly | 9909e09 | 2022-07-06 14:09:34 | [diff] [blame] | 2711 | IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, |
| 2712 | FrameWithBlocklistedFeatureNotCached) { |
| 2713 | ASSERT_TRUE(embedded_test_server()->Start()); |
| 2714 | |
| 2715 | // Navigate to a page that contains a blocklisted feature. |
| 2716 | EXPECT_TRUE(NavigateToURL( |
| 2717 | shell(), embedded_test_server()->GetURL("a.com", "/title1.html"))); |
| 2718 | |
| 2719 | RenderFrameHostWrapper rfh(current_frame_host()); |
| 2720 | |
| 2721 | ASSERT_TRUE(AddBlocklistedFeature(rfh.get())); |
| 2722 | |
| 2723 | // Navigate away. |
| 2724 | EXPECT_TRUE(NavigateToURL( |
| 2725 | shell(), embedded_test_server()->GetURL("b.com", "/title1.html"))); |
| 2726 | |
| 2727 | // The page with the unsupported feature should be deleted (not cached). |
| 2728 | ASSERT_TRUE(rfh.WaitUntilRenderFrameDeleted()); |
| 2729 | |
| 2730 | // Go back. |
| 2731 | ASSERT_TRUE(HistoryGoBack(web_contents())); |
| 2732 | ExpectNotRestoredDueToBlocklistedFeature(FROM_HERE); |
| 2733 | } |
| 2734 | |
| 2735 | IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, |
| 2736 | SubframeWithBlocklistedFeatureNotCached) { |
| 2737 | ASSERT_TRUE(embedded_test_server()->Start()); |
| 2738 | |
| 2739 | // Navigate to a page with an iframe that contains a blocklisted feature. |
| 2740 | EXPECT_TRUE(NavigateToURL( |
| 2741 | shell(), embedded_test_server()->GetURL( |
| 2742 | "a.com", "/cross_site_iframe_factory.html?a(b)"))); |
| 2743 | |
| 2744 | RenderFrameHostWrapper rfh( |
| 2745 | current_frame_host()->child_at(0)->current_frame_host()); |
| 2746 | |
| 2747 | ASSERT_TRUE(AddBlocklistedFeature(rfh.get())); |
| 2748 | |
| 2749 | // Navigate away. |
| 2750 | EXPECT_TRUE(NavigateToURL( |
| 2751 | shell(), embedded_test_server()->GetURL("b.com", "/title1.html"))); |
| 2752 | |
| 2753 | // The page with the unsupported feature should be deleted (not cached). |
| 2754 | ASSERT_TRUE(rfh.WaitUntilRenderFrameDeleted()); |
| 2755 | |
| 2756 | // Go back. |
| 2757 | ASSERT_TRUE(HistoryGoBack(web_contents())); |
| 2758 | ExpectNotRestoredDueToBlocklistedFeature(FROM_HERE); |
| 2759 | } |
| 2760 | |
Fergal Daly | 97c4e59 | 2023-02-28 10:27:33 | [diff] [blame] | 2761 | class BackForwardCacheBrowserUnloadHandlerTest |
| 2762 | : public BackForwardCacheBrowserTest, |
Kurumi Muto | b3137e8 | 2024-01-09 12:28:02 | [diff] [blame] | 2763 | public ::testing::WithParamInterface< |
Kurumi Muto | 863fd9a | 2024-02-06 11:51:32 | [diff] [blame] | 2764 | std::tuple<bool, bool, bool, TestFrameType>> { |
Fergal Daly | 97c4e59 | 2023-02-28 10:27:33 | [diff] [blame] | 2765 | public: |
| 2766 | void SetUpCommandLine(base::CommandLine* command_line) override { |
Fergal Daly | 97c4e59 | 2023-02-28 10:27:33 | [diff] [blame] | 2767 | if (IsUnloadAllowed()) { |
Kurumi Muto | b3137e8 | 2024-01-09 12:28:02 | [diff] [blame] | 2768 | EnableFeatureAndSetParams(kBackForwardCacheUnloadAllowed, "", ""); |
Fergal Daly | 97c4e59 | 2023-02-28 10:27:33 | [diff] [blame] | 2769 | } else { |
Kurumi Muto | b3137e8 | 2024-01-09 12:28:02 | [diff] [blame] | 2770 | DisableFeature(kBackForwardCacheUnloadAllowed); |
Fergal Daly | 97c4e59 | 2023-02-28 10:27:33 | [diff] [blame] | 2771 | } |
Kurumi Muto | b3137e8 | 2024-01-09 12:28:02 | [diff] [blame] | 2772 | if (IsUnloadBlocklisted()) { |
| 2773 | EnableFeatureAndSetParams(blink::features::kUnloadBlocklisted, "", ""); |
| 2774 | } else { |
| 2775 | DisableFeature(blink::features::kUnloadBlocklisted); |
| 2776 | } |
Kurumi Muto | 863fd9a | 2024-02-06 11:51:32 | [diff] [blame] | 2777 | if (IsUnloadDeprecationOptedOut()) { |
| 2778 | EnableFeatureAndSetParams(blink::features::kDeprecateUnloadOptOut, "", |
| 2779 | ""); |
| 2780 | } else { |
| 2781 | DisableFeature(blink::features::kDeprecateUnloadOptOut); |
| 2782 | } |
| 2783 | |
Kurumi Muto | b3137e8 | 2024-01-09 12:28:02 | [diff] [blame] | 2784 | BackForwardCacheBrowserTest::SetUpCommandLine(command_line); |
Fergal Daly | 97c4e59 | 2023-02-28 10:27:33 | [diff] [blame] | 2785 | } |
| 2786 | |
| 2787 | bool IsUnloadAllowed() { return std::get<0>(GetParam()); } |
Kurumi Muto | b3137e8 | 2024-01-09 12:28:02 | [diff] [blame] | 2788 | bool IsUnloadBlocklisted() { return std::get<1>(GetParam()); } |
Kurumi Muto | 863fd9a | 2024-02-06 11:51:32 | [diff] [blame] | 2789 | bool IsUnloadDeprecationOptedOut() { return std::get<2>(GetParam()); } |
Fergal Daly | 97c4e59 | 2023-02-28 10:27:33 | [diff] [blame] | 2790 | |
Kurumi Muto | 863fd9a | 2024-02-06 11:51:32 | [diff] [blame] | 2791 | TestFrameType GetTestFrameType() { return std::get<3>(GetParam()); } |
Fergal Daly | 97c4e59 | 2023-02-28 10:27:33 | [diff] [blame] | 2792 | |
| 2793 | private: |
| 2794 | base::test::ScopedFeatureList scoped_feature_list_; |
| 2795 | }; |
| 2796 | |
Kurumi Muto | 863fd9a | 2024-02-06 11:51:32 | [diff] [blame] | 2797 | // Ensure that unload handlers in main frames and subframes block caching, |
| 2798 | // depending on unload deprecation status and OS. |
Fergal Daly | 97c4e59 | 2023-02-28 10:27:33 | [diff] [blame] | 2799 | IN_PROC_BROWSER_TEST_P(BackForwardCacheBrowserUnloadHandlerTest, |
| 2800 | UnloadHandlerPresent) { |
kouhei | b3517d7d | 2021-05-19 07:48:56 | [diff] [blame] | 2801 | ASSERT_TRUE(embedded_test_server()->Start()); |
| 2802 | |
Minoru Chikamune | 52d6dff | 2021-12-27 14:59:53 | [diff] [blame] | 2803 | GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html")); |
| 2804 | GURL url_b(embedded_test_server()->GetURL("b.com", "/title2.html")); |
kouhei | b3517d7d | 2021-05-19 07:48:56 | [diff] [blame] | 2805 | |
| 2806 | // 1) Navigate to A. |
| 2807 | EXPECT_TRUE(NavigateToURL(shell(), url_a)); |
Fergal Daly | 97c4e59 | 2023-02-28 10:27:33 | [diff] [blame] | 2808 | |
Fergal Daly | fbb93e4 | 2025-02-03 07:01:07 | [diff] [blame] | 2809 | BackForwardCacheCanStoreDocumentResult::NotRestoredReasons |
Kurumi Muto | 863fd9a | 2024-02-06 11:51:32 | [diff] [blame] | 2810 | expected_blocking_reasons; |
| 2811 | std::vector<blink::scheduler::WebSchedulerTrackedFeature> |
| 2812 | expected_blocklisted_reason; |
| 2813 | if (IsUnloadBlocklisted()) { |
Fergal Daly | fbb93e4 | 2025-02-03 07:01:07 | [diff] [blame] | 2814 | expected_blocking_reasons.Put( |
Kurumi Muto | 863fd9a | 2024-02-06 11:51:32 | [diff] [blame] | 2815 | BackForwardCacheMetrics::NotRestoredReason::kBlocklistedFeatures); |
| 2816 | expected_blocklisted_reason.push_back( |
| 2817 | blink::scheduler::WebSchedulerTrackedFeature::kUnloadHandler); |
| 2818 | } |
Fergal Daly | 97c4e59 | 2023-02-28 10:27:33 | [diff] [blame] | 2819 | switch (GetTestFrameType()) { |
| 2820 | case content::TestFrameType::kMainFrame: |
| 2821 | InstallUnloadHandlerOnMainFrame(); |
Fergal Daly | fbb93e4 | 2025-02-03 07:01:07 | [diff] [blame] | 2822 | expected_blocking_reasons.Put(BackForwardCacheMetrics::NotRestoredReason:: |
| 2823 | kUnloadHandlerExistsInMainFrame); |
Fergal Daly | 97c4e59 | 2023-02-28 10:27:33 | [diff] [blame] | 2824 | break; |
| 2825 | case content::TestFrameType::kSubFrame: |
| 2826 | InstallUnloadHandlerOnSubFrame(); |
Fergal Daly | fbb93e4 | 2025-02-03 07:01:07 | [diff] [blame] | 2827 | expected_blocking_reasons.Put(BackForwardCacheMetrics::NotRestoredReason:: |
| 2828 | kUnloadHandlerExistsInSubFrame); |
Fergal Daly | 97c4e59 | 2023-02-28 10:27:33 | [diff] [blame] | 2829 | break; |
| 2830 | default: |
Peter Boström | fc7ddc18 | 2024-10-31 19:37:21 | [diff] [blame] | 2831 | NOTREACHED(); |
Fergal Daly | 97c4e59 | 2023-02-28 10:27:33 | [diff] [blame] | 2832 | } |
kouhei | b3517d7d | 2021-05-19 07:48:56 | [diff] [blame] | 2833 | |
| 2834 | // 2) Navigate to B. |
| 2835 | EXPECT_TRUE(NavigateToURL(shell(), url_b)); |
| 2836 | |
| 2837 | // 3) Go back. |
Fergal Daly | 5495b0e | 2021-11-19 02:03:28 | [diff] [blame] | 2838 | ASSERT_TRUE(HistoryGoBack(web_contents())); |
kouhei | b3517d7d | 2021-05-19 07:48:56 | [diff] [blame] | 2839 | |
Kurumi Muto | 863fd9a | 2024-02-06 11:51:32 | [diff] [blame] | 2840 | bool unload_never_blocks = IsUnloadAllowed(); |
| 2841 | bool unload_deprecated_and_not_opted_out = |
Sandor Major | a9a29ad5 | 2025-02-20 16:00:14 | [diff] [blame] | 2842 | (base::FeatureList::IsEnabled(network::features::kDeprecateUnload) && |
Kurumi Muto | 863fd9a | 2024-02-06 11:51:32 | [diff] [blame] | 2843 | !IsUnloadDeprecationOptedOut()); |
| 2844 | if (unload_never_blocks || unload_deprecated_and_not_opted_out) { |
Kurumi Muto | b3137e8 | 2024-01-09 12:28:02 | [diff] [blame] | 2845 | // Pages with unload handlers are eligible for bfcache only if it is |
Kurumi Muto | 863fd9a | 2024-02-06 11:51:32 | [diff] [blame] | 2846 | // specifically allowed (happens on Android). Also, when unload is |
| 2847 | // deprecated and `kDeprecateUnloadOptOut` doesn't override it, unload |
| 2848 | // handlers cannot be installed so there should be no blocker for BFCache. |
| 2849 | ExpectRestored(FROM_HERE); |
| 2850 | EXPECT_EQ("0", GetUnloadRunCount()); |
Minoru Chikamune | 75b51fd | 2021-09-02 15:29:02 | [diff] [blame] | 2851 | } else { |
Kurumi Muto | 863fd9a | 2024-02-06 11:51:32 | [diff] [blame] | 2852 | ExpectNotRestored(expected_blocking_reasons, expected_blocklisted_reason, |
| 2853 | {}, {}, {}, FROM_HERE); |
| 2854 | EXPECT_EQ("1", GetUnloadRunCount()); |
kouhei | b3517d7d | 2021-05-19 07:48:56 | [diff] [blame] | 2855 | } |
kouhei | b3517d7d | 2021-05-19 07:48:56 | [diff] [blame] | 2856 | } |
| 2857 | |
Kurumi Muto | 863fd9a | 2024-02-06 11:51:32 | [diff] [blame] | 2858 | // First param: whether unload is allowed or not. |
| 2859 | // Second one: whether unload is blocklisted or not. |
| 2860 | // Third one: whether it's opted out from unload deprecation or not. |
Fergal Daly | 97c4e59 | 2023-02-28 10:27:33 | [diff] [blame] | 2861 | INSTANTIATE_TEST_SUITE_P( |
| 2862 | All, |
| 2863 | BackForwardCacheBrowserUnloadHandlerTest, |
| 2864 | ::testing::Combine(::testing::Bool(), |
Kurumi Muto | b3137e8 | 2024-01-09 12:28:02 | [diff] [blame] | 2865 | ::testing::Bool(), |
Kurumi Muto | 863fd9a | 2024-02-06 11:51:32 | [diff] [blame] | 2866 | ::testing::Bool(), |
Fergal Daly | 97c4e59 | 2023-02-28 10:27:33 | [diff] [blame] | 2867 | ::testing::Values(TestFrameType::kMainFrame, |
| 2868 | TestFrameType::kSubFrame))); |
kouhei | b3517d7d | 2021-05-19 07:48:56 | [diff] [blame] | 2869 | |
Mingyu Lei | 8c1b911 | 2023-01-18 03:59:01 | [diff] [blame] | 2870 | IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, DisableForRenderFrameHost) { |
| 2871 | ASSERT_TRUE(embedded_test_server()->Start()); |
| 2872 | |
| 2873 | GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html")); |
| 2874 | GURL url_b(embedded_test_server()->GetURL("b.com", "/title2.html")); |
| 2875 | |
| 2876 | // 1) Navigate to A. |
| 2877 | EXPECT_TRUE(NavigateToURL(shell(), url_a)); |
| 2878 | RenderFrameHostWrapper rfh_wrapper_a(current_frame_host()); |
| 2879 | |
| 2880 | // 2) Navigate to B. |
| 2881 | EXPECT_TRUE(NavigateToURL(shell(), url_b)); |
| 2882 | RenderFrameHostWrapper rfh_wrapper_b(current_frame_host()); |
| 2883 | |
| 2884 | // Regardless of whether the source Id is set or not, it shouldn't affect the |
| 2885 | // result of the BFCache eviction. |
| 2886 | BackForwardCache::DisabledReason test_reason = |
| 2887 | BackForwardCacheDisable::DisabledReason( |
| 2888 | BackForwardCacheDisable::DisabledReasonId::kUnknown); |
| 2889 | |
| 2890 | // 3) Disable BFCache for A with UKM source Id and go back. |
| 2891 | BackForwardCache::DisableForRenderFrameHost( |
| 2892 | rfh_wrapper_a.get(), test_reason, ukm::UkmRecorder::GetNewSourceID()); |
| 2893 | ASSERT_TRUE(HistoryGoBack(web_contents())); |
| 2894 | ASSERT_TRUE(rfh_wrapper_a.WaitUntilRenderFrameDeleted()); |
| 2895 | // Page A should be evicted properly. |
| 2896 | ExpectNotRestored({BackForwardCacheMetrics::NotRestoredReason:: |
| 2897 | kDisableForRenderFrameHostCalled}, |
| 2898 | {}, {}, {test_reason}, {}, FROM_HERE); |
| 2899 | |
| 2900 | // 4) Disable BFCache for B without UKM source Id and go forward. |
| 2901 | BackForwardCache::DisableForRenderFrameHost(rfh_wrapper_b.get(), test_reason); |
| 2902 | ASSERT_TRUE(HistoryGoForward(web_contents())); |
| 2903 | ASSERT_TRUE(rfh_wrapper_b.WaitUntilRenderFrameDeleted()); |
| 2904 | // Page B should be evicted properly. |
| 2905 | ExpectNotRestored({BackForwardCacheMetrics::NotRestoredReason:: |
| 2906 | kDisableForRenderFrameHostCalled}, |
| 2907 | {}, {}, {test_reason}, {}, FROM_HERE); |
| 2908 | } |
| 2909 | |
Adithya Srinivasan | 7fe5ce66 | 2021-06-04 21:36:04 | [diff] [blame] | 2910 | namespace { |
| 2911 | enum class SubframeType { SameSite, CrossSite }; |
| 2912 | } |
| 2913 | |
| 2914 | class BackForwardCacheEvictionDueToSubframeNavigationBrowserTest |
| 2915 | : public BackForwardCacheBrowserTest, |
| 2916 | public ::testing::WithParamInterface<SubframeType> { |
| 2917 | public: |
| 2918 | // Provides meaningful param names instead of /0 and /1. |
| 2919 | static std::string DescribeParams( |
| 2920 | const ::testing::TestParamInfo<ParamType>& info) { |
| 2921 | switch (info.param) { |
| 2922 | case SubframeType::SameSite: |
| 2923 | return "SameSite"; |
| 2924 | case SubframeType::CrossSite: |
| 2925 | return "CrossSite"; |
| 2926 | } |
| 2927 | } |
Ming-Ying Chung | 71d0b8e7 | 2024-03-04 06:27:28 | [diff] [blame] | 2928 | |
| 2929 | protected: |
| 2930 | bool UseCrossOriginSubframe() const { |
| 2931 | return GetParam() == SubframeType::CrossSite; |
| 2932 | } |
Adithya Srinivasan | 7fe5ce66 | 2021-06-04 21:36:04 | [diff] [blame] | 2933 | }; |
| 2934 | |
| 2935 | IN_PROC_BROWSER_TEST_P( |
| 2936 | BackForwardCacheEvictionDueToSubframeNavigationBrowserTest, |
| 2937 | SubframePendingCommitShouldPreventCache) { |
| 2938 | ASSERT_TRUE(embedded_test_server()->Start()); |
| 2939 | GURL a_url(embedded_test_server()->GetURL("a.com", "/title1.html")); |
Adithya Srinivasan | 7fe5ce66 | 2021-06-04 21:36:04 | [diff] [blame] | 2940 | GURL subframe_url = embedded_test_server()->GetURL( |
Ming-Ying Chung | 71d0b8e7 | 2024-03-04 06:27:28 | [diff] [blame] | 2941 | UseCrossOriginSubframe() ? "b.com" : "a.com", "/title1.html"); |
Adithya Srinivasan | 7fe5ce66 | 2021-06-04 21:36:04 | [diff] [blame] | 2942 | |
| 2943 | IsolateOriginsForTesting(embedded_test_server(), web_contents(), |
Jose Dapena Paz | e744775 | 2023-09-20 12:11:12 | [diff] [blame] | 2944 | std::vector<std::string>{"a.com", "b.com"}); |
Adithya Srinivasan | 7fe5ce66 | 2021-06-04 21:36:04 | [diff] [blame] | 2945 | |
| 2946 | // 1) Navigate to a.com. |
| 2947 | EXPECT_TRUE(NavigateToURL(shell(), a_url)); |
| 2948 | RenderFrameHostImpl* main_frame = current_frame_host(); |
| 2949 | |
| 2950 | // 2) Add subframe and wait for empty document to commit. |
| 2951 | CreateSubframe(web_contents(), "child", GURL(""), true); |
| 2952 | |
| 2953 | CommitMessageDelayer commit_message_delayer( |
| 2954 | web_contents(), subframe_url, |
| 2955 | base::BindLambdaForTesting([&](RenderFrameHost*) { |
| 2956 | // 5) Test that page cannot be stored in bfcache when subframe is |
| 2957 | // pending commit. |
Riho Isawa | b1efe68f | 2021-12-20 01:54:07 | [diff] [blame] | 2958 | BackForwardCacheCanStoreDocumentResultWithTree can_store_result = |
Adithya Srinivasan | 7fe5ce66 | 2021-06-04 21:36:04 | [diff] [blame] | 2959 | web_contents() |
| 2960 | ->GetController() |
| 2961 | .GetBackForwardCache() |
Yuzu Saijo | ef104a0 | 2022-05-13 17:04:28 | [diff] [blame] | 2962 | .GetCurrentBackForwardCacheEligibility( |
| 2963 | static_cast<RenderFrameHostImpl*>(main_frame)); |
Yuzu Saijo | dcabe56 | 2022-04-25 06:06:39 | [diff] [blame] | 2964 | EXPECT_TRUE(can_store_result.flattened_reasons.HasNotRestoredReason( |
Adithya Srinivasan | 7fe5ce66 | 2021-06-04 21:36:04 | [diff] [blame] | 2965 | BackForwardCacheMetrics::NotRestoredReason::kSubframeIsNavigating)); |
| 2966 | })); |
| 2967 | |
| 2968 | // 3) Start navigation in subframe to |subframe_url|. |
Adithya Srinivasan | 9f27eb511 | 2023-04-19 20:28:45 | [diff] [blame] | 2969 | ExecuteScriptAsync( |
Adithya Srinivasan | 7fe5ce66 | 2021-06-04 21:36:04 | [diff] [blame] | 2970 | main_frame, |
Adithya Srinivasan | 9f27eb511 | 2023-04-19 20:28:45 | [diff] [blame] | 2971 | JsReplace("document.querySelector('#child').src = $1;", subframe_url)); |
Adithya Srinivasan | 7fe5ce66 | 2021-06-04 21:36:04 | [diff] [blame] | 2972 | // 4) Wait until subframe navigation is pending commit. |
| 2973 | commit_message_delayer.Wait(); |
| 2974 | } |
| 2975 | |
Ming-Ying Chung | 71d0b8e7 | 2024-03-04 06:27:28 | [diff] [blame] | 2976 | // Check that when the main frame gets BFCached while the subframe navigation |
| 2977 | // deferring NavigationThrottles has already ran, the issue that the subframe |
| 2978 | // navigation escapes the throttle deferral is addressed. |
| 2979 | IN_PROC_BROWSER_TEST_P( |
| 2980 | BackForwardCacheEvictionDueToSubframeNavigationBrowserTest, |
| 2981 | MainFrameCommitFirstAndSubframePendingCommitShouldBeEvicted) { |
| 2982 | ASSERT_TRUE(embedded_test_server()->Start()); |
| 2983 | // Prepare the main frame and the sub frame, where both of them are same-site. |
| 2984 | GURL main_url(embedded_test_server()->GetURL( |
| 2985 | "a.com", "/cross_site_iframe_factory.html?a(a)")); |
| 2986 | EXPECT_TRUE(NavigateToURL(shell(), main_url)); |
| 2987 | FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root(); |
| 2988 | FrameTreeNode* child = root->child_at(0); |
| 2989 | RenderFrameHostImplWrapper child_rfh(child->current_frame_host()); |
| 2990 | |
| 2991 | // Navigate both frames simultaneously. |
| 2992 | const std::string subframe_origin = |
| 2993 | UseCrossOriginSubframe() ? "b.com" : "a.com"; |
| 2994 | GURL new_url_1( |
| 2995 | embedded_test_server()->GetURL(subframe_origin, "/title1.html")); |
| 2996 | GURL new_url_2( |
| 2997 | embedded_test_server()->GetURL(subframe_origin, "/title2.html")); |
| 2998 | TestNavigationManager manager1(web_contents(), new_url_1); |
| 2999 | TestNavigationManager manager2(web_contents(), new_url_2); |
| 3000 | auto script = JsReplace("location = $1; frames[0].location = $2;", new_url_1, |
| 3001 | new_url_2); |
| 3002 | EXPECT_TRUE(ExecJs(web_contents(), script)); |
| 3003 | |
| 3004 | // Wait for main frame request, but don't commit it yet. This should create |
| 3005 | // a speculative RenderFrameHost. |
| 3006 | ASSERT_TRUE(manager1.WaitForRequestStart()); |
| 3007 | |
| 3008 | // Wait for subframe request, but don't commit it yet. |
| 3009 | ASSERT_TRUE(manager2.WaitForRequestStart()); |
| 3010 | |
| 3011 | // Now let the main frame commit. |
| 3012 | ASSERT_TRUE(manager1.WaitForNavigationFinished()); |
| 3013 | // Make sure the main frame is at the new URL. |
| 3014 | ASSERT_TRUE(root->current_frame_host()->IsRenderFrameLive()); |
| 3015 | ASSERT_EQ(new_url_1, root->current_frame_host()->GetLastCommittedURL()); |
| 3016 | |
| 3017 | // The subframe should be gone now: it should have been evicted from BFCache |
| 3018 | // because the subframe is still navigating; otherwise, this will cause a |
| 3019 | // crash. |
| 3020 | ASSERT_TRUE(manager2.WaitForNavigationFinished()); |
| 3021 | EXPECT_TRUE(child_rfh.IsDestroyed()); |
| 3022 | ASSERT_TRUE(HistoryGoBack(web_contents())); |
| 3023 | ExpectNotRestored( |
| 3024 | {BackForwardCacheMetrics::NotRestoredReason::kSubframeIsNavigating}, {}, |
| 3025 | {}, {}, {}, FROM_HERE); |
| 3026 | } |
| 3027 | |
Adithya Srinivasan | 7fe5ce66 | 2021-06-04 21:36:04 | [diff] [blame] | 3028 | INSTANTIATE_TEST_SUITE_P( |
| 3029 | All, |
| 3030 | BackForwardCacheEvictionDueToSubframeNavigationBrowserTest, |
| 3031 | ::testing::Values(SubframeType::SameSite, SubframeType::CrossSite), |
| 3032 | &BackForwardCacheEvictionDueToSubframeNavigationBrowserTest:: |
| 3033 | DescribeParams); |
| 3034 | |
murakinonoka | bb2a6c1 | 2024-01-18 05:49:05 | [diff] [blame] | 3035 | namespace { |
| 3036 | enum class SubframeNavigationType { WithoutURLLoader, WithURLLoader }; |
| 3037 | } |
| 3038 | |
Nathan Memmott | f54d81f | 2024-12-11 18:56:21 | [diff] [blame] | 3039 | // Test for pages which has subframe(s) with ongoing navigation(s). |
murakinonoka | bb2a6c1 | 2024-01-18 05:49:05 | [diff] [blame] | 3040 | class BackForwardCacheWithSubframeNavigationBrowserTest |
murakinonoka | 97a8f04 | 2024-01-10 09:17:07 | [diff] [blame] | 3041 | : public BackForwardCacheBrowserTest { |
| 3042 | protected: |
murakinonoka | bb2a6c1 | 2024-01-18 05:49:05 | [diff] [blame] | 3043 | void SetUpOnMainThread() override { |
| 3044 | BackForwardCacheBrowserTest::SetUpOnMainThread(); |
| 3045 | ASSERT_TRUE(embedded_test_server()->Start()); |
| 3046 | } |
| 3047 | |
murakinonoka | 97a8f04 | 2024-01-10 09:17:07 | [diff] [blame] | 3048 | void SetUpCommandLine(base::CommandLine* command_line) override { |
Fergal Daly | b125811 | 2025-07-15 03:00:51 | [diff] [blame] | 3049 | EnableCacheSize(2, std::nullopt); |
murakinonoka | 97a8f04 | 2024-01-10 09:17:07 | [diff] [blame] | 3050 | BackForwardCacheBrowserTest::SetUpCommandLine(command_line); |
| 3051 | } |
| 3052 | |
| 3053 | // Start a subframe navigation and pause it when we get the confirmation |
| 3054 | // dialog triggered by beforeunload event, which is before |
murakinonoka | bb2a6c1 | 2024-01-18 05:49:05 | [diff] [blame] | 3055 | // WillCommitWithoutUrlLoader or WillStartRequest. |
murakinonoka | 97a8f04 | 2024-01-10 09:17:07 | [diff] [blame] | 3056 | void NavigateSubframeAndPauseAtBeforeUnload( |
| 3057 | BeforeUnloadBlockingDelegate& beforeunload_pauser, |
| 3058 | RenderFrameHostImpl* sub_rfh, |
murakinonoka | bb2a6c1 | 2024-01-18 05:49:05 | [diff] [blame] | 3059 | const GURL& subframe_navigate_url, |
Tom Sepez | b55f2f1 | 2024-10-02 21:54:33 | [diff] [blame] | 3060 | std::string_view iframe_id) { |
murakinonoka | 97a8f04 | 2024-01-10 09:17:07 | [diff] [blame] | 3061 | ASSERT_TRUE(ExecJs(sub_rfh, R"( |
| 3062 | window.addEventListener('beforeunload', e => |
| 3063 | e.returnValue='blocked' |
| 3064 | );)")); |
| 3065 | |
| 3066 | // Start a subframe navigation which will trigger the beforeunload dialog |
| 3067 | // that pauses that navigation. Using `BeginNavigateIframeToURL` is |
| 3068 | // necessary here, since we pause this navigation on beforeunload event. So, |
| 3069 | // we don't want to wait for the navigation to finish. |
murakinonoka | bb2a6c1 | 2024-01-18 05:49:05 | [diff] [blame] | 3070 | BeginNavigateIframeToURL(web_contents(), iframe_id, subframe_navigate_url); |
murakinonoka | 97a8f04 | 2024-01-10 09:17:07 | [diff] [blame] | 3071 | beforeunload_pauser.Wait(); |
| 3072 | } |
| 3073 | |
| 3074 | // Start a subframe navigation and pause it before `DidCommitNavigation`. |
Rakina Zata Amni | c06ef3a4 | 2024-03-11 20:41:35 | [diff] [blame] | 3075 | void NavigateSubframeAndPauseAtDidCommit(FrameTreeNode* ftn, |
murakinonoka | 97a8f04 | 2024-01-10 09:17:07 | [diff] [blame] | 3076 | const GURL& subframe_navigate_url) { |
Jiacheng Guo | 4bdd0be | 2024-06-11 23:35:21 | [diff] [blame] | 3077 | // Enforce the creation of speculative RFH to correctly wait for |
| 3078 | // the commit event. |
| 3079 | SpeculativeRenderFrameHostObserver observer(web_contents(), |
| 3080 | subframe_navigate_url); |
murakinonoka | 97a8f04 | 2024-01-10 09:17:07 | [diff] [blame] | 3081 | // We have to pause a navigation before `DidCommitNavigation`, so we don't |
| 3082 | // want to wait for the navigation to finish. |
Rakina Zata Amni | c06ef3a4 | 2024-03-11 20:41:35 | [diff] [blame] | 3083 | ASSERT_TRUE(BeginNavigateToURLFromRenderer(ftn, subframe_navigate_url)); |
Jiacheng Guo | 02a0423a | 2024-06-20 02:03:56 | [diff] [blame] | 3084 | // Navigation without a URL loader shall always create the speculative RFH |
| 3085 | // immediately or never create one. |
| 3086 | // The same-site navigation to the subframe will not create a new |
| 3087 | // speculative RFH if render document is not enabled for subframes. |
| 3088 | if (subframe_navigate_url.SchemeIsHTTPOrHTTPS() && |
| 3089 | ShouldCreateNewRenderFrameHostOnSameSiteNavigation( |
| 3090 | /*is_main_frame=*/false, /*is_local_root=*/true)) { |
| 3091 | observer.Wait(); |
| 3092 | } |
murakinonoka | 97a8f04 | 2024-01-10 09:17:07 | [diff] [blame] | 3093 | |
Rakina Zata Amni | c06ef3a4 | 2024-03-11 20:41:35 | [diff] [blame] | 3094 | // Wait until the navigation is pending commit. Note that the navigation |
| 3095 | // might use a speculative RenderFrameHost, so use that if necessary. |
| 3096 | RenderFrameHostImpl* speculative_rfh = |
| 3097 | ftn->render_manager()->speculative_frame_host(); |
| 3098 | CommitNavigationPauser commit_pauser( |
| 3099 | speculative_rfh ? speculative_rfh : ftn->current_frame_host()); |
murakinonoka | 97a8f04 | 2024-01-10 09:17:07 | [diff] [blame] | 3100 | commit_pauser.WaitForCommitAndPause(); |
| 3101 | } |
| 3102 | |
murakinonoka | bb2a6c1 | 2024-01-18 05:49:05 | [diff] [blame] | 3103 | // Put a page which has a subframe with a navigation which hasn't reached the |
| 3104 | // "pending commit" stage nor sent a network request into BackForwardCache and |
| 3105 | // confirm the subframe navigation has been deferred. |
| 3106 | void BFCachePageWithSubframeNavigationBeforeDidStartNavigation( |
| 3107 | const GURL& main_frame_navigate_url, |
| 3108 | const GURL& subframe_navigate_url, |
murakinonoka | 97a8f04 | 2024-01-10 09:17:07 | [diff] [blame] | 3109 | RenderFrameHostImplWrapper& sub_rfh, |
| 3110 | TestNavigationManager& subframe_navigation_manager, |
Tom Sepez | b55f2f1 | 2024-10-02 21:54:33 | [diff] [blame] | 3111 | std::string_view iframe_id) { |
murakinonoka | 97a8f04 | 2024-01-10 09:17:07 | [diff] [blame] | 3112 | FrameTreeNode* child_ftn = |
| 3113 | web_contents()->GetPrimaryFrameTree().root()->child_at(0); |
| 3114 | { |
| 3115 | BeforeUnloadBlockingDelegate beforeunload_pauser(web_contents()); |
| 3116 | NavigateSubframeAndPauseAtBeforeUnload(beforeunload_pauser, sub_rfh.get(), |
murakinonoka | bb2a6c1 | 2024-01-18 05:49:05 | [diff] [blame] | 3117 | subframe_navigate_url, iframe_id); |
murakinonoka | 97a8f04 | 2024-01-10 09:17:07 | [diff] [blame] | 3118 | |
| 3119 | // Subframe navigation is ongoing, so `NavigateToURL` cannot be used since |
| 3120 | // this function waits for all frames including subframe to finish |
| 3121 | // loading. |
murakinonoka | bb2a6c1 | 2024-01-18 05:49:05 | [diff] [blame] | 3122 | ASSERT_TRUE(NavigateToURLFromRenderer(sub_rfh->GetMainFrame(), |
| 3123 | main_frame_navigate_url)); |
murakinonoka | 97a8f04 | 2024-01-10 09:17:07 | [diff] [blame] | 3124 | |
murakinonoka | bb2a6c1 | 2024-01-18 05:49:05 | [diff] [blame] | 3125 | // The subframe navigation hasn't reached the "pending commit" stage nor |
| 3126 | // sent a network request, so the page is eligible for BackForwardCache. |
murakinonoka | 97a8f04 | 2024-01-10 09:17:07 | [diff] [blame] | 3127 | EXPECT_TRUE(sub_rfh->GetMainFrame()->IsInBackForwardCache()); |
| 3128 | EXPECT_TRUE(sub_rfh->IsInBackForwardCache()); |
| 3129 | } |
| 3130 | web_contents()->SetDelegate(shell()); |
| 3131 | |
| 3132 | // Wait until the subframe navigation is deferred. |
| 3133 | ASSERT_TRUE( |
| 3134 | subframe_navigation_manager.WaitForFirstYieldAfterDidStartNavigation()); |
| 3135 | NavigationRequest* child_navigation = child_ftn->navigation_request(); |
| 3136 | ASSERT_NE(child_navigation, nullptr); |
| 3137 | EXPECT_TRUE(child_navigation->IsDeferredForTesting()); |
| 3138 | } |
| 3139 | }; |
| 3140 | |
murakinonoka | bb2a6c1 | 2024-01-18 05:49:05 | [diff] [blame] | 3141 | class BackForwardCacheWithSubframeNavigationWithParamBrowserTest |
| 3142 | : public BackForwardCacheWithSubframeNavigationBrowserTest, |
| 3143 | public ::testing::WithParamInterface<SubframeNavigationType> { |
| 3144 | public: |
| 3145 | // Provides meaningful param names instead of /0 and /1. |
| 3146 | static std::string DescribeParams( |
| 3147 | const ::testing::TestParamInfo<ParamType>& info) { |
| 3148 | switch (info.param) { |
| 3149 | case SubframeNavigationType::WithoutURLLoader: |
| 3150 | return "WithoutURLLoader"; |
| 3151 | case SubframeNavigationType::WithURLLoader: |
| 3152 | return "WithURLLoader"; |
| 3153 | } |
| 3154 | } |
| 3155 | }; |
| 3156 | |
murakinonoka | 97a8f04 | 2024-01-10 09:17:07 | [diff] [blame] | 3157 | // Confirm that BackForwardCache is blocked when there is only 1 navigation and |
| 3158 | // it's pending commit. |
murakinonoka | bb2a6c1 | 2024-01-18 05:49:05 | [diff] [blame] | 3159 | IN_PROC_BROWSER_TEST_P( |
| 3160 | BackForwardCacheWithSubframeNavigationWithParamBrowserTest, |
Jiacheng Guo | 02a0423a | 2024-06-20 02:03:56 | [diff] [blame] | 3161 | SubframeNavigationWithPendingCommitShouldPreventCache) { |
murakinonoka | 97a8f04 | 2024-01-10 09:17:07 | [diff] [blame] | 3162 | const GURL main_url(embedded_test_server()->GetURL( |
| 3163 | "a.com", "/cross_site_iframe_factory.html?a(b)")); |
| 3164 | const GURL subframe_url = embedded_test_server()->GetURL( |
| 3165 | "b.com", "/cross_site_iframe_factory.html?b()"); |
| 3166 | const GURL navigate_url( |
| 3167 | embedded_test_server()->GetURL("c.com", "/title1.html")); |
murakinonoka | bb2a6c1 | 2024-01-18 05:49:05 | [diff] [blame] | 3168 | const GURL subframe_navigate_url = |
| 3169 | GetParam() == SubframeNavigationType::WithURLLoader |
| 3170 | ? embedded_test_server()->GetURL("b.com", "/title1.html") |
| 3171 | : GURL("about:blank"); |
murakinonoka | 97a8f04 | 2024-01-10 09:17:07 | [diff] [blame] | 3172 | |
| 3173 | // Navigate to a page with a cross site iframe. |
| 3174 | ASSERT_TRUE(NavigateToURL(shell(), main_url)); |
Rakina Zata Amni | c06ef3a4 | 2024-03-11 20:41:35 | [diff] [blame] | 3175 | EXPECT_TRUE(WaitForLoadStop(shell()->web_contents())); |
| 3176 | |
murakinonoka | 97a8f04 | 2024-01-10 09:17:07 | [diff] [blame] | 3177 | RenderFrameHostImplWrapper main_rfh(current_frame_host()); |
Jiacheng Guo | 4bdd0be | 2024-06-11 23:35:21 | [diff] [blame] | 3178 | FrameTreeNode* child_node = main_rfh.get()->child_at(0); |
| 3179 | RenderFrameHostImplWrapper sub_rfh(child_node->current_frame_host()); |
murakinonoka | 97a8f04 | 2024-01-10 09:17:07 | [diff] [blame] | 3180 | |
| 3181 | // Pause subframe's navigation before `DidCommitNavigation`. |
Jiacheng Guo | 4bdd0be | 2024-06-11 23:35:21 | [diff] [blame] | 3182 | NavigateSubframeAndPauseAtDidCommit(child_node, subframe_navigate_url); |
murakinonoka | 97a8f04 | 2024-01-10 09:17:07 | [diff] [blame] | 3183 | |
| 3184 | // Subframe navigation is ongoing, so `NavigateToURL` cannot be used since |
| 3185 | // this function waits for all frames including subframe to finish loading. |
| 3186 | ASSERT_TRUE(NavigateToURLFromRenderer(main_rfh.get(), navigate_url)); |
| 3187 | |
| 3188 | // Subframe navigation has reached the "pending commit" stage, so the page is |
| 3189 | // not eligible for BackForwardCache. |
| 3190 | EXPECT_TRUE(main_rfh.WaitUntilRenderFrameDeleted()); |
| 3191 | EXPECT_TRUE(sub_rfh.WaitUntilRenderFrameDeleted()); |
| 3192 | |
| 3193 | // Navigate back. |
| 3194 | ASSERT_TRUE(HistoryGoBack(web_contents())); |
| 3195 | ExpectNotRestored({NotRestoredReason::kSubframeIsNavigating}, {}, {}, {}, {}, |
| 3196 | FROM_HERE); |
| 3197 | |
| 3198 | // Confirm that subframe's url didn't change. |
| 3199 | EXPECT_EQ(subframe_url, current_frame_host()->child_at(0)->current_url()); |
| 3200 | } |
| 3201 | |
| 3202 | // Confirm that BackForwardCache is blocked when there are 2 navigations, 1 not |
| 3203 | // pending commit yet, and 1 pending commit. |
| 3204 | IN_PROC_BROWSER_TEST_F( |
murakinonoka | bb2a6c1 | 2024-01-18 05:49:05 | [diff] [blame] | 3205 | BackForwardCacheWithSubframeNavigationBrowserTest, |
Jiacheng Guo | 02a0423a | 2024-06-20 02:03:56 | [diff] [blame] | 3206 | MultipleSubframeNavigationWithBeforeAndPendingCommitShouldPreventCache) { |
murakinonoka | 97a8f04 | 2024-01-10 09:17:07 | [diff] [blame] | 3207 | // This test relies on the main frame and the iframe to live in different |
| 3208 | // processes. This allows one renderer process to proceed a navigation while |
| 3209 | // the other renderer process is busy executing its beforeunload handler. |
| 3210 | if (!AreAllSitesIsolatedForTesting()) { |
| 3211 | GTEST_SKIP() << "Site isolation is not enabled!"; |
| 3212 | } |
murakinonoka | 97a8f04 | 2024-01-10 09:17:07 | [diff] [blame] | 3213 | const GURL main_url(embedded_test_server()->GetURL( |
| 3214 | "a.com", "/cross_site_iframe_factory.html?a(b,c)")); |
| 3215 | const GURL subframe_b_url = embedded_test_server()->GetURL( |
| 3216 | "b.com", "/cross_site_iframe_factory.html?b()"); |
| 3217 | const GURL subframe_c_url = embedded_test_server()->GetURL( |
| 3218 | "c.com", "/cross_site_iframe_factory.html?c()"); |
| 3219 | const GURL navigate_url( |
| 3220 | embedded_test_server()->GetURL("d.com", "/title1.html")); |
| 3221 | const GURL subframe_navigate_url = GURL("about:blank"); |
| 3222 | |
| 3223 | // Navigate to a page with two cross site iframes. |
| 3224 | ASSERT_TRUE(NavigateToURL(shell(), main_url)); |
| 3225 | RenderFrameHostImplWrapper main_rfh(current_frame_host()); |
| 3226 | RenderFrameHostImplWrapper sub_rfh_b( |
| 3227 | main_rfh.get()->child_at(0)->current_frame_host()); |
| 3228 | RenderFrameHostImplWrapper sub_rfh_c( |
| 3229 | main_rfh.get()->child_at(1)->current_frame_host()); |
| 3230 | |
| 3231 | { |
| 3232 | // The subframe_b itself does have a dialog-showing beforeunload handler. |
| 3233 | // Pause subframe_b's navigation when we get the confirmation dialog |
| 3234 | // triggered by beforeunload event. |
| 3235 | BeforeUnloadBlockingDelegate beforeunload_pauser(web_contents()); |
| 3236 | NavigateSubframeAndPauseAtBeforeUnload(beforeunload_pauser, sub_rfh_b.get(), |
| 3237 | subframe_navigate_url, |
| 3238 | /*iframe_id=*/"child-0"); |
| 3239 | |
| 3240 | // Pause subframe_c's navigation before `DidCommitNavigation`. |
Rakina Zata Amni | c06ef3a4 | 2024-03-11 20:41:35 | [diff] [blame] | 3241 | NavigateSubframeAndPauseAtDidCommit(main_rfh.get()->child_at(1), |
| 3242 | subframe_navigate_url); |
murakinonoka | 97a8f04 | 2024-01-10 09:17:07 | [diff] [blame] | 3243 | |
| 3244 | // Subframe navigation is ongoing, so `NavigateToURL` cannot be used since |
| 3245 | // this function waits for all frames including subframe to finish loading. |
| 3246 | ASSERT_TRUE(NavigateToURLFromRenderer(main_rfh.get(), navigate_url)); |
| 3247 | |
| 3248 | // The subframe_c's navigation already started committing, so the page is |
| 3249 | // not eligible for BackForwardCache. |
| 3250 | EXPECT_TRUE(main_rfh.WaitUntilRenderFrameDeleted()); |
| 3251 | EXPECT_TRUE(sub_rfh_b.WaitUntilRenderFrameDeleted()); |
| 3252 | EXPECT_TRUE(sub_rfh_c.WaitUntilRenderFrameDeleted()); |
| 3253 | } |
| 3254 | web_contents()->SetDelegate(shell()); |
| 3255 | |
| 3256 | // Navigate back. |
| 3257 | ASSERT_TRUE(HistoryGoBack(web_contents())); |
| 3258 | ExpectNotRestored({NotRestoredReason::kSubframeIsNavigating}, {}, {}, {}, {}, |
| 3259 | FROM_HERE); |
| 3260 | |
| 3261 | // Confirm that subframe's url didn't change. |
| 3262 | EXPECT_EQ(subframe_b_url, current_frame_host()->child_at(0)->current_url()); |
| 3263 | EXPECT_EQ(subframe_c_url, current_frame_host()->child_at(1)->current_url()); |
| 3264 | } |
| 3265 | |
murakinonoka | bb2a6c1 | 2024-01-18 05:49:05 | [diff] [blame] | 3266 | // Confirm that BackForwardCache is blocked when there are 2 navigations, 1 has |
| 3267 | // not sent a network request yet, and 1 has already sent request. |
murakinonoka | 97a8f04 | 2024-01-10 09:17:07 | [diff] [blame] | 3268 | IN_PROC_BROWSER_TEST_F( |
murakinonoka | bb2a6c1 | 2024-01-18 05:49:05 | [diff] [blame] | 3269 | BackForwardCacheWithSubframeNavigationBrowserTest, |
| 3270 | MultipleSubframeNavigationWithBeforeAndAfterSendingRequestShouldPreventCache) { |
| 3271 | // This test relies on the main frame and the iframe to live in different |
| 3272 | // processes. This allows one renderer process to proceed a navigation while |
| 3273 | // the other renderer process is busy executing its beforeunload handler. |
| 3274 | if (!AreAllSitesIsolatedForTesting()) { |
| 3275 | GTEST_SKIP() << "Site isolation is not enabled!"; |
| 3276 | } |
| 3277 | const GURL main_url(embedded_test_server()->GetURL( |
| 3278 | "a.com", "/cross_site_iframe_factory.html?a(b,c)")); |
| 3279 | const GURL subframe_b_url = embedded_test_server()->GetURL( |
| 3280 | "b.com", "/cross_site_iframe_factory.html?b()"); |
| 3281 | const GURL subframe_c_url = embedded_test_server()->GetURL( |
| 3282 | "c.com", "/cross_site_iframe_factory.html?c()"); |
| 3283 | const GURL navigate_url( |
| 3284 | embedded_test_server()->GetURL("d.com", "/title1.html")); |
| 3285 | const GURL subframe_b_navigate_url( |
| 3286 | embedded_test_server()->GetURL("b.com", "/title1.html")); |
| 3287 | const GURL subframe_c_navigate_url( |
| 3288 | embedded_test_server()->GetURL("c.com", "/title1.html")); |
| 3289 | |
| 3290 | // Navigate to a page with two cross site iframes. |
| 3291 | ASSERT_TRUE(NavigateToURL(shell(), main_url)); |
| 3292 | RenderFrameHostImplWrapper main_rfh(current_frame_host()); |
| 3293 | RenderFrameHostImplWrapper sub_rfh_b( |
| 3294 | main_rfh.get()->child_at(0)->current_frame_host()); |
| 3295 | RenderFrameHostImplWrapper sub_rfh_c( |
| 3296 | main_rfh.get()->child_at(1)->current_frame_host()); |
| 3297 | |
| 3298 | // Pause a subframe_b navigation on `WillStartRequest` before sending a |
| 3299 | // network request. |
| 3300 | TestNavigationManager subframe_b_navigation_manager(web_contents(), |
| 3301 | subframe_b_navigate_url); |
| 3302 | ASSERT_TRUE( |
| 3303 | BeginNavigateToURLFromRenderer(sub_rfh_b.get(), subframe_b_navigate_url)); |
| 3304 | ASSERT_TRUE(subframe_b_navigation_manager.WaitForRequestStart()); |
| 3305 | |
| 3306 | // Pause a subframe_c navigation on `WillProcessResponse` after sending a |
| 3307 | // network request. |
| 3308 | TestNavigationManager subframe_c_navigation_manager(web_contents(), |
| 3309 | subframe_c_navigate_url); |
| 3310 | ASSERT_TRUE( |
| 3311 | BeginNavigateToURLFromRenderer(sub_rfh_c.get(), subframe_c_navigate_url)); |
| 3312 | ASSERT_TRUE(subframe_c_navigation_manager.WaitForResponse()); |
| 3313 | |
| 3314 | // Subframe navigation is ongoing, so `NavigateToURL` cannot be used since |
| 3315 | // this function waits for all frames including subframe to finish loading. |
| 3316 | ASSERT_TRUE(NavigateToURLFromRenderer(main_rfh.get(), navigate_url)); |
| 3317 | |
| 3318 | // The subframe_c's navigation has already sent a network request, so the page |
| 3319 | // is not eligible for BackForwardCache. |
| 3320 | EXPECT_TRUE(main_rfh.WaitUntilRenderFrameDeleted()); |
| 3321 | EXPECT_TRUE(sub_rfh_b.WaitUntilRenderFrameDeleted()); |
| 3322 | EXPECT_TRUE(sub_rfh_c.WaitUntilRenderFrameDeleted()); |
| 3323 | EXPECT_TRUE(subframe_b_navigation_manager.WaitForNavigationFinished()); |
| 3324 | EXPECT_TRUE(subframe_c_navigation_manager.WaitForNavigationFinished()); |
| 3325 | EXPECT_FALSE(subframe_b_navigation_manager.was_committed()); |
| 3326 | EXPECT_FALSE(subframe_c_navigation_manager.was_committed()); |
| 3327 | |
| 3328 | // Navigate back. |
| 3329 | ASSERT_TRUE(HistoryGoBack(web_contents())); |
| 3330 | ExpectNotRestored({NotRestoredReason::kSubframeIsNavigating}, {}, {}, {}, {}, |
| 3331 | FROM_HERE); |
| 3332 | |
| 3333 | // Confirm that subframe's url didn't change. |
| 3334 | EXPECT_EQ(subframe_b_url, current_frame_host()->child_at(0)->current_url()); |
| 3335 | EXPECT_EQ(subframe_c_url, current_frame_host()->child_at(1)->current_url()); |
| 3336 | } |
| 3337 | |
| 3338 | // Confirm that subframe navigation which needs url loader that has already sent |
| 3339 | // a network request should block BackForwardCache. |
| 3340 | IN_PROC_BROWSER_TEST_F( |
| 3341 | BackForwardCacheWithSubframeNavigationBrowserTest, |
| 3342 | SubframeNavigationWithUrlLoaderAfterSendingRequestShouldPreventCache) { |
murakinonoka | 97a8f04 | 2024-01-10 09:17:07 | [diff] [blame] | 3343 | const GURL main_url(embedded_test_server()->GetURL( |
| 3344 | "a.com", "/cross_site_iframe_factory.html?a(b)")); |
| 3345 | const GURL subframe_url = embedded_test_server()->GetURL( |
| 3346 | "b.com", "/cross_site_iframe_factory.html?b()"); |
| 3347 | const GURL navigate_url( |
| 3348 | embedded_test_server()->GetURL("c.com", "/title1.html")); |
| 3349 | const GURL subframe_navigate_url( |
| 3350 | embedded_test_server()->GetURL("b.com", "/title2.html")); |
| 3351 | |
| 3352 | // Navigate to a page with a cross site iframe. |
| 3353 | ASSERT_TRUE(NavigateToURL(shell(), main_url)); |
| 3354 | RenderFrameHostImplWrapper main_rfh(current_frame_host()); |
| 3355 | RenderFrameHostImplWrapper sub_rfh( |
| 3356 | main_rfh.get()->child_at(0)->current_frame_host()); |
murakinonoka | 97a8f04 | 2024-01-10 09:17:07 | [diff] [blame] | 3357 | TestNavigationManager subframe_navigation_manager(web_contents(), |
| 3358 | subframe_navigate_url); |
| 3359 | ASSERT_TRUE( |
| 3360 | BeginNavigateToURLFromRenderer(sub_rfh.get(), subframe_navigate_url)); |
murakinonoka | bb2a6c1 | 2024-01-18 05:49:05 | [diff] [blame] | 3361 | |
| 3362 | // Pause the subframe navigation on `WillProcessResponse`. |
| 3363 | ASSERT_TRUE(subframe_navigation_manager.WaitForResponse()); |
murakinonoka | 97a8f04 | 2024-01-10 09:17:07 | [diff] [blame] | 3364 | |
| 3365 | // Subframe navigation is ongoing, so `NavigateToURL` cannot be used since |
| 3366 | // this function waits for all frames including subframe to finish loading. |
| 3367 | ASSERT_TRUE(NavigateToURLFromRenderer(main_rfh.get(), navigate_url)); |
| 3368 | |
murakinonoka | bb2a6c1 | 2024-01-18 05:49:05 | [diff] [blame] | 3369 | // Subframe navigation has already sent a network request, so the page is not |
| 3370 | // eligible for BackForwardCache. |
murakinonoka | 97a8f04 | 2024-01-10 09:17:07 | [diff] [blame] | 3371 | EXPECT_TRUE(main_rfh.WaitUntilRenderFrameDeleted()); |
| 3372 | EXPECT_TRUE(sub_rfh.WaitUntilRenderFrameDeleted()); |
| 3373 | EXPECT_FALSE(subframe_navigation_manager.was_committed()); |
| 3374 | |
| 3375 | // Navigate back. |
| 3376 | ASSERT_TRUE(HistoryGoBack(web_contents())); |
| 3377 | ExpectNotRestored({NotRestoredReason::kSubframeIsNavigating}, {}, {}, {}, {}, |
| 3378 | FROM_HERE); |
| 3379 | |
| 3380 | // Confirm that subframe's url didn't change. |
| 3381 | EXPECT_EQ(subframe_url, current_frame_host()->child_at(0)->current_url()); |
| 3382 | } |
| 3383 | |
murakinonoka | bb2a6c1 | 2024-01-18 05:49:05 | [diff] [blame] | 3384 | // Confirm that subframe navigation which needs url loader that hasn't sent a |
| 3385 | // network request should not block BackForwardCache. |
| 3386 | IN_PROC_BROWSER_TEST_F( |
| 3387 | BackForwardCacheWithSubframeNavigationBrowserTest, |
| 3388 | SubframeNavigationWithUrlLoaderBeforeSendingRequestShouldNotPreventCache) { |
| 3389 | // This test relies on the main frame and the iframe to live in different |
| 3390 | // processes. This allows one renderer process to proceed a navigation while |
| 3391 | // the other renderer process is busy executing its beforeunload handler. |
| 3392 | if (!AreAllSitesIsolatedForTesting()) { |
| 3393 | GTEST_SKIP() << "Site isolation is not enabled!"; |
| 3394 | } |
| 3395 | const GURL main_url(embedded_test_server()->GetURL( |
| 3396 | "a.com", "/cross_site_iframe_factory.html?a(b)")); |
| 3397 | const GURL subframe_url = embedded_test_server()->GetURL( |
| 3398 | "b.com", "/cross_site_iframe_factory.html?b()"); |
| 3399 | const GURL navigate_url( |
| 3400 | embedded_test_server()->GetURL("c.com", "/title1.html")); |
| 3401 | const GURL subframe_navigate_url( |
| 3402 | embedded_test_server()->GetURL("b.com", "/title1.html")); |
| 3403 | |
| 3404 | // Navigate to a page with a cross site iframe. |
| 3405 | ASSERT_TRUE(NavigateToURL(shell(), main_url)); |
| 3406 | RenderFrameHostImplWrapper main_rfh(current_frame_host()); |
| 3407 | RenderFrameHostImplWrapper sub_rfh( |
| 3408 | main_rfh.get()->child_at(0)->current_frame_host()); |
| 3409 | |
| 3410 | // Put a page which has a subframe with a URLLoader navigation which hasn't |
| 3411 | // sent a network request into BackForwardCache. The iframe itself |
| 3412 | // does have a dialog-showing beforeunload handler. |
| 3413 | TestNavigationManager subframe_navigation_manager(web_contents(), |
| 3414 | subframe_navigate_url); |
| 3415 | BFCachePageWithSubframeNavigationBeforeDidStartNavigation( |
| 3416 | navigate_url, subframe_navigate_url, sub_rfh, subframe_navigation_manager, |
| 3417 | /*iframe_id=*/"child-0"); |
| 3418 | |
| 3419 | // Navigate back. |
| 3420 | TestNavigationObserver back_load_observer(shell()->web_contents()); |
| 3421 | web_contents()->GetController().GoBack(); |
| 3422 | back_load_observer.WaitForNavigationFinished(); |
| 3423 | ASSERT_FALSE(main_rfh->IsInBackForwardCache()); |
| 3424 | |
| 3425 | // Wait until the resumed subframe navigation finishes. |
| 3426 | EXPECT_TRUE(subframe_navigation_manager.WaitForNavigationFinished()); |
| 3427 | EXPECT_TRUE(subframe_navigation_manager.was_successful()); |
| 3428 | EXPECT_EQ(subframe_navigate_url, |
| 3429 | current_frame_host()->child_at(0)->current_url()); |
| 3430 | } |
| 3431 | |
murakinonoka | 97a8f04 | 2024-01-10 09:17:07 | [diff] [blame] | 3432 | // Confirm that subframe no-url loader navigation (e.g., about:blank) in |
| 3433 | // bfcached page is deferred and then resumed when the page is navigated back. |
| 3434 | IN_PROC_BROWSER_TEST_F( |
murakinonoka | bb2a6c1 | 2024-01-18 05:49:05 | [diff] [blame] | 3435 | BackForwardCacheWithSubframeNavigationBrowserTest, |
murakinonoka | 97a8f04 | 2024-01-10 09:17:07 | [diff] [blame] | 3436 | SubframeNavigationWithoutUrlLoaderBeforeCommitShouldNotPreventCache) { |
| 3437 | // This test relies on the main frame and the iframe to live in different |
| 3438 | // processes. This allows one renderer process to proceed a navigation while |
| 3439 | // the other renderer process is busy executing its beforeunload handler. |
| 3440 | if (!AreAllSitesIsolatedForTesting()) { |
| 3441 | GTEST_SKIP() << "Site isolation is not enabled!"; |
| 3442 | } |
murakinonoka | 97a8f04 | 2024-01-10 09:17:07 | [diff] [blame] | 3443 | const GURL main_url(embedded_test_server()->GetURL( |
| 3444 | "a.com", "/cross_site_iframe_factory.html?a(b)")); |
| 3445 | const GURL navigate_url( |
| 3446 | embedded_test_server()->GetURL("c.com", "/title1.html")); |
| 3447 | const GURL subframe_navigate_url = GURL("about:blank"); |
| 3448 | |
| 3449 | // Navigate to a page with a cross site iframe. |
| 3450 | ASSERT_TRUE(NavigateToURL(shell(), main_url)); |
| 3451 | RenderFrameHostImplWrapper main_rfh(current_frame_host()); |
| 3452 | RenderFrameHostImplWrapper sub_rfh( |
| 3453 | main_rfh.get()->child_at(0)->current_frame_host()); |
| 3454 | |
| 3455 | // Put a page which has a subframe with a no-URLLoader navigation which hasn't |
| 3456 | // reached the "pending commit" stage into BackForwardCache. The iframe itself |
| 3457 | // does have a dialog-showing beforeunload handler. |
| 3458 | TestNavigationManager subframe_navigation_manager(web_contents(), |
| 3459 | subframe_navigate_url); |
murakinonoka | bb2a6c1 | 2024-01-18 05:49:05 | [diff] [blame] | 3460 | BFCachePageWithSubframeNavigationBeforeDidStartNavigation( |
| 3461 | navigate_url, subframe_navigate_url, sub_rfh, subframe_navigation_manager, |
murakinonoka | 97a8f04 | 2024-01-10 09:17:07 | [diff] [blame] | 3462 | /*iframe_id=*/"child-0"); |
| 3463 | |
| 3464 | // Navigate back. |
| 3465 | ASSERT_TRUE(HistoryGoBack(web_contents())); |
| 3466 | ASSERT_FALSE(main_rfh->IsInBackForwardCache()); |
| 3467 | |
| 3468 | // Confirm the deferred navigation was resumed and subframe's url changed. |
| 3469 | EXPECT_TRUE(subframe_navigation_manager.WaitForNavigationFinished()); |
| 3470 | EXPECT_TRUE(subframe_navigation_manager.was_successful()); |
| 3471 | EXPECT_EQ(subframe_navigate_url, |
| 3472 | current_frame_host()->child_at(0)->current_url()); |
| 3473 | } |
| 3474 | |
| 3475 | // Confirm that we don't resume a subframe navigation when an unrelated BFCached |
| 3476 | // page gets restored. |
murakinonoka | bb2a6c1 | 2024-01-18 05:49:05 | [diff] [blame] | 3477 | IN_PROC_BROWSER_TEST_P( |
| 3478 | BackForwardCacheWithSubframeNavigationWithParamBrowserTest, |
murakinonoka | 97a8f04 | 2024-01-10 09:17:07 | [diff] [blame] | 3479 | SubframeNavigationShouldNotBeResumedWhenUnrelatedPageRestored) { |
| 3480 | // This test relies on the main frame and the iframe to live in different |
| 3481 | // processes. This allows one renderer process to proceed a navigation while |
| 3482 | // the other renderer process is busy executing its beforeunload handler. |
| 3483 | if (!AreAllSitesIsolatedForTesting()) { |
| 3484 | GTEST_SKIP() << "Site isolation is not enabled!"; |
| 3485 | } |
murakinonoka | 97a8f04 | 2024-01-10 09:17:07 | [diff] [blame] | 3486 | const GURL main_url_a(embedded_test_server()->GetURL( |
| 3487 | "a.com", "/cross_site_iframe_factory.html?a(b)")); |
| 3488 | const GURL navigate_url_c( |
| 3489 | embedded_test_server()->GetURL("c.com", "/title1.html")); |
| 3490 | const GURL navigate_url_d( |
| 3491 | embedded_test_server()->GetURL("d.com", "/title1.html")); |
murakinonoka | bb2a6c1 | 2024-01-18 05:49:05 | [diff] [blame] | 3492 | const GURL subframe_navigate_url = |
| 3493 | GetParam() == SubframeNavigationType::WithURLLoader |
| 3494 | ? embedded_test_server()->GetURL("b.com", "/title1.html") |
| 3495 | : GURL("about:blank"); |
murakinonoka | 97a8f04 | 2024-01-10 09:17:07 | [diff] [blame] | 3496 | |
| 3497 | // Navigate to a page with a cross site iframe. |
| 3498 | ASSERT_TRUE(NavigateToURL(shell(), main_url_a)); |
| 3499 | RenderFrameHostImplWrapper main_rfh_a(current_frame_host()); |
| 3500 | RenderFrameHostImplWrapper sub_rfh_b( |
| 3501 | main_rfh_a.get()->child_at(0)->current_frame_host()); |
| 3502 | |
murakinonoka | bb2a6c1 | 2024-01-18 05:49:05 | [diff] [blame] | 3503 | // Put a page which has a subframe with a navigation which hasn't reached the |
| 3504 | // "pending commit" stage or sent a network request into BackForwardCache. |
murakinonoka | 97a8f04 | 2024-01-10 09:17:07 | [diff] [blame] | 3505 | TestNavigationManager subframe_navigation_manager(web_contents(), |
| 3506 | subframe_navigate_url); |
murakinonoka | bb2a6c1 | 2024-01-18 05:49:05 | [diff] [blame] | 3507 | BFCachePageWithSubframeNavigationBeforeDidStartNavigation( |
| 3508 | navigate_url_c, subframe_navigate_url, sub_rfh_b, |
| 3509 | subframe_navigation_manager, |
murakinonoka | 97a8f04 | 2024-01-10 09:17:07 | [diff] [blame] | 3510 | /*iframe_id=*/"child-0"); |
| 3511 | |
| 3512 | // Navigate away. |
| 3513 | // Currently, `main_rfh_a` is in BFCache and we are on `navigate_url_c`. Then, |
| 3514 | // we will navigate to `navigate_url_d` which will put `main_rfh_c` in |
| 3515 | // BFCache. |
| 3516 | RenderFrameHostImplWrapper main_rfh_c(current_frame_host()); |
| 3517 | ASSERT_TRUE(NavigateToURL(shell(), navigate_url_d)); |
| 3518 | ASSERT_TRUE(main_rfh_c->IsInBackForwardCache()); |
| 3519 | |
| 3520 | // Navigate back to `main_rfh_c` and restore that from BFCache, while |
| 3521 | // `main_rfh_a` is still in BFCache. |
| 3522 | ASSERT_TRUE(HistoryGoBack(web_contents())); |
| 3523 | ASSERT_EQ(main_rfh_c.get(), current_frame_host()); |
| 3524 | ASSERT_TRUE(main_rfh_a->IsInBackForwardCache()); |
| 3525 | |
| 3526 | // Confirm the subframe's deferred navigation is not committed. |
| 3527 | EXPECT_FALSE(subframe_navigation_manager.was_committed()); |
| 3528 | |
| 3529 | // Navigate back to `main_rfh_a`. |
murakinonoka | bb2a6c1 | 2024-01-18 05:49:05 | [diff] [blame] | 3530 | TestNavigationObserver back_load_observer(shell()->web_contents()); |
| 3531 | web_contents()->GetController().GoBack(); |
| 3532 | back_load_observer.WaitForNavigationFinished(); |
murakinonoka | 97a8f04 | 2024-01-10 09:17:07 | [diff] [blame] | 3533 | ASSERT_FALSE(main_rfh_a->IsInBackForwardCache()); |
| 3534 | |
| 3535 | // Confirm the deferred navigation was resumed and subframe's url changed. |
| 3536 | EXPECT_TRUE(subframe_navigation_manager.WaitForNavigationFinished()); |
| 3537 | EXPECT_TRUE(subframe_navigation_manager.was_successful()); |
| 3538 | EXPECT_EQ(subframe_navigate_url, |
| 3539 | current_frame_host()->child_at(0)->current_url()); |
| 3540 | } |
| 3541 | |
murakinonoka | bb2a6c1 | 2024-01-18 05:49:05 | [diff] [blame] | 3542 | // Evict the bfcached page which has a subframe with a deferred navigation and |
| 3543 | // confirm the subframe'url didn't change when the page is navigated back. |
| 3544 | IN_PROC_BROWSER_TEST_P( |
| 3545 | BackForwardCacheWithSubframeNavigationWithParamBrowserTest, |
| 3546 | EvictBFCachedPageWithDeferredSubframeNavigationBeforeCommit) { |
murakinonoka | 97a8f04 | 2024-01-10 09:17:07 | [diff] [blame] | 3547 | // This test relies on the main frame and the iframe to live in different |
| 3548 | // processes. This allows one renderer process to proceed a navigation while |
| 3549 | // the other renderer process is busy executing its beforeunload handler. |
| 3550 | if (!AreAllSitesIsolatedForTesting()) { |
| 3551 | GTEST_SKIP() << "Site isolation is not enabled!"; |
| 3552 | } |
murakinonoka | 97a8f04 | 2024-01-10 09:17:07 | [diff] [blame] | 3553 | const GURL main_url(embedded_test_server()->GetURL( |
| 3554 | "a.com", "/cross_site_iframe_factory.html?a(b)")); |
| 3555 | const GURL subframe_url = embedded_test_server()->GetURL( |
| 3556 | "b.com", "/cross_site_iframe_factory.html?b()"); |
| 3557 | const GURL navigate_url( |
| 3558 | embedded_test_server()->GetURL("c.com", "/title1.html")); |
murakinonoka | bb2a6c1 | 2024-01-18 05:49:05 | [diff] [blame] | 3559 | const GURL subframe_navigate_url = |
| 3560 | GetParam() == SubframeNavigationType::WithURLLoader |
| 3561 | ? embedded_test_server()->GetURL("b.com", "/title1.html") |
| 3562 | : GURL("about:blank"); |
murakinonoka | 97a8f04 | 2024-01-10 09:17:07 | [diff] [blame] | 3563 | |
| 3564 | // Navigate to a page with a cross site iframe. |
| 3565 | ASSERT_TRUE(NavigateToURL(shell(), main_url)); |
| 3566 | RenderFrameHostImplWrapper main_rfh(current_frame_host()); |
| 3567 | RenderFrameHostImplWrapper sub_rfh( |
| 3568 | main_rfh.get()->child_at(0)->current_frame_host()); |
| 3569 | |
murakinonoka | bb2a6c1 | 2024-01-18 05:49:05 | [diff] [blame] | 3570 | // Put a page which has a subframe with a navigation which hasn't reached the |
| 3571 | // "pending commit" stage or sent a network request into BackForwardCache. The |
| 3572 | // iframe itself does have a dialog-showing beforeunload handler. |
murakinonoka | 97a8f04 | 2024-01-10 09:17:07 | [diff] [blame] | 3573 | TestNavigationManager subframe_navigation_manager(web_contents(), |
| 3574 | subframe_navigate_url); |
murakinonoka | bb2a6c1 | 2024-01-18 05:49:05 | [diff] [blame] | 3575 | BFCachePageWithSubframeNavigationBeforeDidStartNavigation( |
| 3576 | navigate_url, subframe_navigate_url, sub_rfh, subframe_navigation_manager, |
murakinonoka | 97a8f04 | 2024-01-10 09:17:07 | [diff] [blame] | 3577 | /*iframe_id=*/"child-0"); |
| 3578 | |
| 3579 | // Flush the cache and evict the previously BFCached page. |
| 3580 | web_contents()->GetController().GetBackForwardCache().Flush(); |
| 3581 | ASSERT_TRUE(main_rfh.WaitUntilRenderFrameDeleted()); |
| 3582 | ASSERT_TRUE(sub_rfh.WaitUntilRenderFrameDeleted()); |
| 3583 | |
| 3584 | // Confirm the subframe's deferred navigation has finished and was not |
| 3585 | // committed. |
| 3586 | EXPECT_TRUE(subframe_navigation_manager.WaitForNavigationFinished()); |
| 3587 | EXPECT_FALSE(subframe_navigation_manager.was_committed()); |
| 3588 | |
| 3589 | // Navigate back. |
| 3590 | ASSERT_TRUE(HistoryGoBack(web_contents())); |
| 3591 | |
| 3592 | // Confirm that subframe's url didn't change. |
| 3593 | EXPECT_EQ(subframe_url, current_frame_host()->child_at(0)->current_url()); |
| 3594 | } |
| 3595 | |
murakinonoka | bb2a6c1 | 2024-01-18 05:49:05 | [diff] [blame] | 3596 | INSTANTIATE_TEST_SUITE_P( |
| 3597 | All, |
| 3598 | BackForwardCacheWithSubframeNavigationWithParamBrowserTest, |
| 3599 | ::testing::Values(SubframeNavigationType::WithoutURLLoader, |
| 3600 | SubframeNavigationType::WithURLLoader), |
| 3601 | &BackForwardCacheWithSubframeNavigationWithParamBrowserTest:: |
| 3602 | DescribeParams); |
| 3603 | |
Gyuyoung Kim | 940115f | 2021-11-05 02:25:35 | [diff] [blame] | 3604 | class BackForwardCacheFencedFrameBrowserTest |
| 3605 | : public BackForwardCacheBrowserTest { |
| 3606 | public: |
| 3607 | BackForwardCacheFencedFrameBrowserTest() = default; |
| 3608 | ~BackForwardCacheFencedFrameBrowserTest() override = default; |
| 3609 | BackForwardCacheFencedFrameBrowserTest( |
| 3610 | const BackForwardCacheFencedFrameBrowserTest&) = delete; |
| 3611 | |
| 3612 | BackForwardCacheFencedFrameBrowserTest& operator=( |
| 3613 | const BackForwardCacheFencedFrameBrowserTest&) = delete; |
| 3614 | |
| 3615 | void SetUpCommandLine(base::CommandLine* command_line) override { |
| 3616 | BackForwardCacheBrowserTest::SetUpCommandLine(command_line); |
| 3617 | fenced_frame_helper_ = std::make_unique<test::FencedFrameTestHelper>(); |
| 3618 | } |
| 3619 | |
| 3620 | test::FencedFrameTestHelper& fenced_frame_test_helper() { |
| 3621 | return *fenced_frame_helper_; |
| 3622 | } |
| 3623 | |
| 3624 | private: |
| 3625 | std::unique_ptr<test::FencedFrameTestHelper> fenced_frame_helper_; |
| 3626 | }; |
| 3627 | |
| 3628 | IN_PROC_BROWSER_TEST_F(BackForwardCacheFencedFrameBrowserTest, |
| 3629 | FencedFramePageNotStoredInBackForwardCache) { |
| 3630 | ASSERT_TRUE(embedded_test_server()->Start()); |
| 3631 | GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html")); |
Dominic Farolino | 667161a9 | 2021-11-20 19:29:02 | [diff] [blame] | 3632 | GURL url_b( |
| 3633 | embedded_test_server()->GetURL("b.com", "/fenced_frames/title1.html")); |
| 3634 | GURL url_c( |
| 3635 | embedded_test_server()->GetURL("c.com", "/fenced_frames/title1.html")); |
Gyuyoung Kim | 940115f | 2021-11-05 02:25:35 | [diff] [blame] | 3636 | |
| 3637 | // 1) Navigate to A. |
| 3638 | EXPECT_TRUE(NavigateToURL(shell(), url_a)); |
| 3639 | |
| 3640 | // 2) Create a fenced frame. |
| 3641 | content::RenderFrameHostImpl* fenced_frame_host = |
| 3642 | static_cast<content::RenderFrameHostImpl*>( |
| 3643 | fenced_frame_test_helper().CreateFencedFrame( |
Dave Tapuska | 327c06c9 | 2022-06-13 20:31:51 | [diff] [blame] | 3644 | web_contents()->GetPrimaryMainFrame(), url_b)); |
Gyuyoung Kim | 940115f | 2021-11-05 02:25:35 | [diff] [blame] | 3645 | RenderFrameHostWrapper fenced_frame_host_wrapper(fenced_frame_host); |
| 3646 | |
| 3647 | // 3) Navigate to C on the fenced frame host. |
| 3648 | fenced_frame_test_helper().NavigateFrameInFencedFrameTree(fenced_frame_host, |
| 3649 | url_c); |
| 3650 | EXPECT_TRUE(WaitForLoadStop(shell()->web_contents())); |
| 3651 | |
| 3652 | if (!fenced_frame_host_wrapper.IsRenderFrameDeleted()) |
| 3653 | EXPECT_FALSE(fenced_frame_host->IsInBackForwardCache()); |
| 3654 | } |
| 3655 | |
Yuzu Saijo | caba5be | 2021-11-30 11:35:55 | [diff] [blame] | 3656 | IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, |
| 3657 | RendererInitiatedNavigateToSameUrl) { |
| 3658 | ASSERT_TRUE(embedded_test_server()->Start()); |
| 3659 | GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html")); |
| 3660 | GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html")); |
| 3661 | |
| 3662 | // 1) Navigate to A. |
| 3663 | ASSERT_TRUE(NavigateToURL(shell(), url_a)); |
| 3664 | RenderFrameHostImplWrapper rfh_a(current_frame_host()); |
| 3665 | |
| 3666 | // 2) Navigate to B. |
| 3667 | ASSERT_TRUE(NavigateToURL(shell(), url_b)); |
| 3668 | RenderFrameHostImplWrapper rfh_b(current_frame_host()); |
| 3669 | |
| 3670 | // 3) Navigate to B again, renderer initiated. |
| 3671 | ASSERT_TRUE(NavigateToURLFromRenderer(rfh_b.get(), url_b)); |
Rakina Zata Amni | 4cab082 | 2023-10-26 12:28:24 | [diff] [blame] | 3672 | RenderFrameHostImplWrapper rfh_b2(current_frame_host()); |
| 3673 | |
| 3674 | // This is treated as replacement, and the previous B page did not get into |
| 3675 | // back/forward cache. |
| 3676 | if (ShouldCreateNewHostForAllFrames()) { |
| 3677 | EXPECT_TRUE(rfh_b.WaitUntilRenderFrameDeleted()); |
| 3678 | } else { |
| 3679 | EXPECT_FALSE(rfh_b->IsInBackForwardCache()); |
| 3680 | EXPECT_EQ(rfh_b.get(), rfh_b2.get()); |
| 3681 | } |
Yuzu Saijo | caba5be | 2021-11-30 11:35:55 | [diff] [blame] | 3682 | |
| 3683 | // 4) Go back. Make sure we go back to A instead of B and restore from |
| 3684 | // bfcache. |
| 3685 | ASSERT_TRUE(HistoryGoBack(shell()->web_contents())); |
| 3686 | EXPECT_EQ(current_frame_host(), rfh_a.get()); |
Rakina Zata Amni | 4cab082 | 2023-10-26 12:28:24 | [diff] [blame] | 3687 | EXPECT_TRUE(rfh_b2.get()->IsInBackForwardCache()); |
Yuzu Saijo | caba5be | 2021-11-30 11:35:55 | [diff] [blame] | 3688 | ExpectRestored(FROM_HERE); |
| 3689 | |
| 3690 | // 5) Go forward and restore from bfcache. |
| 3691 | ASSERT_TRUE(HistoryGoForward(shell()->web_contents())); |
Rakina Zata Amni | 4cab082 | 2023-10-26 12:28:24 | [diff] [blame] | 3692 | EXPECT_EQ(current_frame_host(), rfh_b2.get()); |
Yuzu Saijo | caba5be | 2021-11-30 11:35:55 | [diff] [blame] | 3693 | ExpectRestored(FROM_HERE); |
| 3694 | } |
| 3695 | |
Fergal Daly | f5a50ab | 2021-11-09 05:36:18 | [diff] [blame] | 3696 | // BEFORE ADDING A NEW TEST HERE |
| 3697 | // Read the note at the top about the other files you could add it to. |
Arthur Sonzogni | 620cec6 | 2018-12-13 13:08:57 | [diff] [blame] | 3698 | } // namespace content |