1 // Copyright 2018 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <memory>
6 #include <unordered_map>
7
8 #include "base/callback_forward.h"
9 #include "base/callback_helpers.h"
10 #include "base/command_line.h"
11 #include "base/hash/hash.h"
12 #include "base/location.h"
13 #include "base/metrics/metrics_hashes.h"
14 #include "base/optional.h"
15 #include "base/run_loop.h"
16 #include "base/strings/string_piece_forward.h"
17 #include "base/system/sys_info.h"
18 #include "base/task/common/task_annotator.h"
19 #include "base/task/post_task.h"
20 #include "base/test/bind.h"
21 #include "base/test/scoped_feature_list.h"
22 #include "base/test/test_mock_time_task_runner.h"
23 #include "base/test/test_timeouts.h"
24 #include "base/threading/thread_restrictions.h"
25 #include "base/threading/thread_task_runner_handle.h"
26 #include "base/time/time.h"
27 #include "base/trace_event/trace_log.h"
28 #include "build/build_config.h"
29 #include "components/network_session_configurator/common/network_switches.h"
30 #include "components/ukm/test_ukm_recorder.h"
31 #include "content/browser/bad_message.h"
32 #include "content/browser/generic_sensor/sensor_provider_proxy_impl.h"
33 #include "content/browser/presentation/presentation_test_utils.h"
34 #include "content/browser/renderer_host/back_forward_cache_impl.h"
35 #include "content/browser/renderer_host/frame_tree_node.h"
36 #include "content/browser/renderer_host/page_lifecycle_state_manager.h"
37 #include "content/browser/renderer_host/render_frame_host_impl.h"
38 #include "content/browser/renderer_host/should_swap_browsing_instance.h"
39 #include "content/browser/web_contents/file_chooser_impl.h"
40 #include "content/browser/web_contents/web_contents_impl.h"
41 #include "content/common/content_navigation_policy.h"
42 #include "content/common/render_accessibility.mojom.h"
43 #include "content/public/browser/back_forward_cache.h"
44 #include "content/public/browser/frame_service_base.h"
45 #include "content/public/browser/global_routing_id.h"
46 #include "content/public/browser/idle_manager.h"
47 #include "content/public/browser/navigation_handle.h"
48 #include "content/public/browser/render_frame_host.h"
49 #include "content/public/browser/site_isolation_policy.h"
50 #include "content/public/browser/web_contents.h"
51 #include "content/public/browser/web_contents_observer.h"
52 #include "content/public/common/content_features.h"
53 #include "content/public/common/content_switches.h"
54 #include "content/public/test/back_forward_cache_util.h"
55 #include "content/public/test/browser_test.h"
56 #include "content/public/test/browser_test_utils.h"
57 #include "content/public/test/content_browser_test.h"
58 #include "content/public/test/content_browser_test_utils.h"
59 #include "content/public/test/idle_test_utils.h"
60 #include "content/public/test/navigation_handle_observer.h"
61 #include "content/public/test/test_navigation_observer.h"
62 #include "content/public/test/test_navigation_throttle.h"
63 #include "content/public/test/test_navigation_throttle_inserter.h"
64 #include "content/public/test/test_utils.h"
65 #include "content/public/test/text_input_test_utils.h"
66 #include "content/public/test/url_loader_interceptor.h"
67 #include "content/shell/browser/shell.h"
68 #include "content/shell/browser/shell_javascript_dialog_manager.h"
69 #include "content/test/content_browser_test_utils_internal.h"
70 #include "content/test/echo.test-mojom.h"
71 #include "media/base/media_switches.h"
72 #include "mojo/public/cpp/bindings/message.h"
73 #include "mojo/public/cpp/bindings/pending_remote.h"
74 #include "mojo/public/cpp/bindings/remote.h"
75 #include "net/base/filename_util.h"
76 #include "net/dns/mock_host_resolver.h"
77 #include "net/test/embedded_test_server/controllable_http_response.h"
78 #include "net/test/embedded_test_server/embedded_test_server.h"
79 #include "net/test/spawned_test_server/spawned_test_server.h"
80 #include "net/test/test_data_directory.h"
81 #include "services/device/public/cpp/test/fake_sensor_and_provider.h"
82 #include "services/device/public/cpp/test/scoped_geolocation_overrider.h"
83 #include "services/device/public/mojom/vibration_manager.mojom.h"
84 #include "services/service_manager/public/cpp/interface_provider.h"
85 #include "testing/gmock/include/gmock/gmock.h"
86 #include "third_party/blink/public/common/features.h"
87 #include "third_party/blink/public/common/scheduler/web_scheduler_tracked_feature.h"
88 #include "third_party/blink/public/mojom/app_banner/app_banner.mojom.h"
89
90 using testing::_;
91 using testing::Each;
92 using testing::ElementsAre;
93 using testing::Not;
94 using testing::UnorderedElementsAreArray;
95
96 namespace content {
97
98 namespace {
99
100 const char kDisabledReasonForTest[] = "DisabledByBackForwardCacheBrowserTest";
101 const char kSameSiteNavigationDidSwapHistogramName[] =
102 "BackForwardCache.ProactiveSameSiteBISwap.SameSiteNavigationDidSwap";
103 const char kEligibilityDuringCommitHistogramName[] =
104 "BackForwardCache.ProactiveSameSiteBISwap.EligibilityDuringCommit";
105 const char kUnloadRunsAfterCommitHistogramName[] =
106 "BackForwardCache.ProactiveSameSiteBISwap.UnloadRunsAfterCommit";
107
108 // hash for std::unordered_map.
109 struct FeatureHash {
operator ()content::__anon0a6381310111::FeatureHash110 size_t operator()(base::Feature feature) const {
111 return base::FastHash(feature.name);
112 }
113 };
114
115 // compare operator for std::unordered_map.
116 struct FeatureEqualOperator {
operator ()content::__anon0a6381310111::FeatureEqualOperator117 bool operator()(base::Feature feature1, base::Feature feature2) const {
118 return std::strcmp(feature1.name, feature2.name) == 0;
119 }
120 };
121
122 // Test about the BackForwardCache.
123 class BackForwardCacheBrowserTest : public ContentBrowserTest,
124 public WebContentsObserver {
125 public:
~BackForwardCacheBrowserTest()126 ~BackForwardCacheBrowserTest() override {
127 if (fail_for_unexpected_messages_while_cached_) {
128 ExpectTotalCount(
129 "BackForwardCache.UnexpectedRendererToBrowserMessage.InterfaceName",
130 0);
131 }
132 }
133
134 protected:
135 using UkmMetrics = ukm::TestUkmRecorder::HumanReadableUkmMetrics;
136
137 // Disables checking metrics that are recorded recardless of the domains. By
138 // default, this class' Expect* function checks the metrics both for the
139 // specific domain and for all domains at the same time. In the case when the
140 // test results need to be different, call this function.
DisableCheckingMetricsForAllSites()141 void DisableCheckingMetricsForAllSites() { check_all_sites_ = false; }
142
SetUpCommandLine(base::CommandLine * command_line)143 void SetUpCommandLine(base::CommandLine* command_line) override {
144 base::CommandLine::ForCurrentProcess()->AppendSwitch(
145 switches::kUseFakeUIForMediaStream);
146 base::CommandLine::ForCurrentProcess()->AppendSwitch(
147 switches::kIgnoreCertificateErrors);
148 base::CommandLine::ForCurrentProcess()->AppendSwitch(
149 switches::kEnableExperimentalWebPlatformFeatures);
150 // TODO(sreejakshetty): Initialize ScopedFeatureLists from test constructor.
151 EnableFeatureAndSetParams(features::kBackForwardCache,
152 "TimeToLiveInBackForwardCacheInSeconds", "3600");
153 EnableFeatureAndSetParams(features::kBackForwardCache,
154 "message_handling_when_cached", "log");
155 EnableFeatureAndSetParams(
156 features::kBackForwardCache, "enable_same_site",
157 same_site_back_forward_cache_enabled_ ? "true" : "false");
158 EnableFeatureAndSetParams(
159 features::kBackForwardCache, "skip_same_site_if_unload_exists",
160 skip_same_site_if_unload_exists_ ? "true" : "false");
161 EnableFeatureAndSetParams(
162 blink::features::kLogUnexpectedIPCPostedToBackForwardCachedDocuments,
163 "delay_before_tracking_ms", "0");
164 #if defined(OS_ANDROID)
165 EnableFeatureAndSetParams(features::kBackForwardCache,
166 "process_binding_strength", "NORMAL");
167 #endif
168 SetupFeaturesAndParameters();
169
170 command_line->AppendSwitchASCII(
171 switches::kAutoplayPolicy,
172 switches::autoplay::kNoUserGestureRequiredPolicy);
173 command_line->AppendSwitchASCII(switches::kEnableBlinkFeatures, "WakeLock");
174 ContentBrowserTest::SetUpCommandLine(command_line);
175 }
176
SetupFeaturesAndParameters()177 void SetupFeaturesAndParameters() {
178 std::vector<base::test::ScopedFeatureList::FeatureAndParams>
179 enabled_features;
180
181 for (auto feature_param = features_with_params_.begin();
182 feature_param != features_with_params_.end(); feature_param++) {
183 enabled_features.push_back({feature_param->first, feature_param->second});
184 }
185
186 feature_list_.InitWithFeaturesAndParameters(enabled_features,
187 disabled_features_);
188 }
189
EnableFeatureAndSetParams(base::Feature feature,std::string param_name,std::string param_value)190 void EnableFeatureAndSetParams(base::Feature feature,
191 std::string param_name,
192 std::string param_value) {
193 features_with_params_[feature][param_name] = param_value;
194 }
195
DisableFeature(base::Feature feature)196 void DisableFeature(base::Feature feature) {
197 disabled_features_.push_back(feature);
198 }
199
SetUpOnMainThread()200 void SetUpOnMainThread() override {
201 host_resolver()->AddRule("*", "127.0.0.1");
202 // TestAutoSetUkmRecorder's constructor requires a sequenced context.
203 ukm_recorder_ = std::make_unique<ukm::TestAutoSetUkmRecorder>();
204 ContentBrowserTest::SetUpOnMainThread();
205 }
206
TearDownOnMainThread()207 void TearDownOnMainThread() override {
208 ukm_recorder_.reset();
209 ContentBrowserTest::TearDownOnMainThread();
210 }
211
web_contents() const212 WebContentsImpl* web_contents() const {
213 return static_cast<WebContentsImpl*>(shell()->web_contents());
214 }
215
current_frame_host()216 RenderFrameHostImpl* current_frame_host() {
217 return web_contents()->GetFrameTree()->root()->current_frame_host();
218 }
219
render_frame_host_manager()220 RenderFrameHostManager* render_frame_host_manager() {
221 return web_contents()->GetFrameTree()->root()->render_manager();
222 }
223
DepictFrameTree(FrameTreeNode * node)224 std::string DepictFrameTree(FrameTreeNode* node) {
225 return visualizer_.DepictFrameTree(node);
226 }
227
HistogramContainsIntValue(base::HistogramBase::Sample sample,std::vector<base::Bucket> histogram_values)228 bool HistogramContainsIntValue(base::HistogramBase::Sample sample,
229 std::vector<base::Bucket> histogram_values) {
230 auto it = std::find_if(histogram_values.begin(), histogram_values.end(),
231 [sample](const base::Bucket& bucket) {
232 return bucket.min == static_cast<int>(sample);
233 });
234 return it != histogram_values.end();
235 }
236
ExpectOutcome(BackForwardCacheMetrics::HistoryNavigationOutcome outcome,base::Location location)237 void ExpectOutcome(BackForwardCacheMetrics::HistoryNavigationOutcome outcome,
238 base::Location location) {
239 base::HistogramBase::Sample sample = base::HistogramBase::Sample(outcome);
240 AddSampleToBuckets(&expected_outcomes_, sample);
241
242 EXPECT_THAT(histogram_tester_.GetAllSamples(
243 "BackForwardCache.HistoryNavigationOutcome"),
244 UnorderedElementsAreArray(expected_outcomes_))
245 << location.ToString();
246
247 if (!check_all_sites_)
248 return;
249
250 EXPECT_THAT(histogram_tester_.GetAllSamples(
251 "BackForwardCache.AllSites.HistoryNavigationOutcome"),
252 UnorderedElementsAreArray(expected_outcomes_))
253 << location.ToString();
254
255 std::string is_served_from_bfcache =
256 "BackForwardCache.IsServedFromBackForwardCache";
257 bool ukm_outcome =
258 outcome == BackForwardCacheMetrics::HistoryNavigationOutcome::kRestored;
259 expected_ukm_outcomes_.push_back(
260 {{is_served_from_bfcache, static_cast<int64_t>(ukm_outcome)}});
261 EXPECT_THAT(ukm_recorder_->GetMetrics("HistoryNavigation",
262 {is_served_from_bfcache}),
263 expected_ukm_outcomes_)
264 << location.ToString();
265 }
266
ExpectOutcomeDidNotChange(base::Location location)267 void ExpectOutcomeDidNotChange(base::Location location) {
268 EXPECT_EQ(expected_outcomes_,
269 histogram_tester_.GetAllSamples(
270 "BackForwardCache.HistoryNavigationOutcome"))
271 << location.ToString();
272
273 if (!check_all_sites_)
274 return;
275
276 EXPECT_EQ(expected_outcomes_,
277 histogram_tester_.GetAllSamples(
278 "BackForwardCache.AllSites.HistoryNavigationOutcome"))
279 << location.ToString();
280
281 std::string is_served_from_bfcache =
282 "BackForwardCache.IsServedFromBackForwardCache";
283 EXPECT_THAT(ukm_recorder_->GetMetrics("HistoryNavigation",
284 {is_served_from_bfcache}),
285 expected_ukm_outcomes_)
286 << location.ToString();
287 }
288
ExpectNotRestored(std::vector<BackForwardCacheMetrics::NotRestoredReason> reasons,base::Location location)289 void ExpectNotRestored(
290 std::vector<BackForwardCacheMetrics::NotRestoredReason> reasons,
291 base::Location location) {
292 uint64_t not_restored_reasons_bits = 0;
293 for (BackForwardCacheMetrics::NotRestoredReason reason : reasons) {
294 base::HistogramBase::Sample sample = base::HistogramBase::Sample(reason);
295 AddSampleToBuckets(&expected_not_restored_, sample);
296 not_restored_reasons_bits |= 1ull << static_cast<int>(reason);
297 }
298
299 EXPECT_THAT(histogram_tester_.GetAllSamples(
300 "BackForwardCache.HistoryNavigationOutcome."
301 "NotRestoredReason"),
302 UnorderedElementsAreArray(expected_not_restored_))
303 << location.ToString();
304
305 if (!check_all_sites_)
306 return;
307
308 EXPECT_THAT(histogram_tester_.GetAllSamples(
309 "BackForwardCache.AllSites.HistoryNavigationOutcome."
310 "NotRestoredReason"),
311 UnorderedElementsAreArray(expected_not_restored_))
312 << location.ToString();
313
314 std::string not_restored_reasons = "BackForwardCache.NotRestoredReasons";
315 expected_ukm_not_restored_reasons_.push_back(
316 {{not_restored_reasons, not_restored_reasons_bits}});
317 EXPECT_THAT(
318 ukm_recorder_->GetMetrics("HistoryNavigation", {not_restored_reasons}),
319 expected_ukm_not_restored_reasons_)
320 << location.ToString();
321 }
322
ExpectNotRestoredDidNotChange(base::Location location)323 void ExpectNotRestoredDidNotChange(base::Location location) {
324 EXPECT_EQ(expected_not_restored_,
325 histogram_tester_.GetAllSamples(
326 "BackForwardCache.HistoryNavigationOutcome."
327 "NotRestoredReason"))
328 << location.ToString();
329
330 std::string not_restored_reasons = "BackForwardCache.NotRestoredReasons";
331
332 if (!check_all_sites_)
333 return;
334
335 EXPECT_EQ(expected_not_restored_,
336 histogram_tester_.GetAllSamples(
337 "BackForwardCache.AllSites.HistoryNavigationOutcome."
338 "NotRestoredReason"))
339 << location.ToString();
340
341 EXPECT_THAT(
342 ukm_recorder_->GetMetrics("HistoryNavigation", {not_restored_reasons}),
343 expected_ukm_not_restored_reasons_)
344 << location.ToString();
345 }
346
ExpectBlocklistedFeature(blink::scheduler::WebSchedulerTrackedFeature feature,base::Location location)347 void ExpectBlocklistedFeature(
348 blink::scheduler::WebSchedulerTrackedFeature feature,
349 base::Location location) {
350 ExpectBlocklistedFeatures({feature}, location);
351 }
352
ExpectBlocklistedFeatures(std::vector<blink::scheduler::WebSchedulerTrackedFeature> features,base::Location location)353 void ExpectBlocklistedFeatures(
354 std::vector<blink::scheduler::WebSchedulerTrackedFeature> features,
355 base::Location location) {
356 for (auto feature : features) {
357 base::HistogramBase::Sample sample = base::HistogramBase::Sample(feature);
358 AddSampleToBuckets(&expected_blocklisted_features_, sample);
359 }
360
361 EXPECT_THAT(histogram_tester_.GetAllSamples(
362 "BackForwardCache.HistoryNavigationOutcome."
363 "BlocklistedFeature"),
364 UnorderedElementsAreArray(expected_blocklisted_features_))
365 << location.ToString();
366
367 if (!check_all_sites_)
368 return;
369
370 EXPECT_THAT(histogram_tester_.GetAllSamples(
371 "BackForwardCache.AllSites.HistoryNavigationOutcome."
372 "BlocklistedFeature"),
373 UnorderedElementsAreArray(expected_blocklisted_features_))
374 << location.ToString();
375 }
376
ExpectDisabledWithReason(const std::string & reason,base::Location location)377 void ExpectDisabledWithReason(const std::string& reason,
378 base::Location location) {
379 base::HistogramBase::Sample sample =
380 base::HistogramBase::Sample(base::HashMetricName(reason));
381 AddSampleToBuckets(&expected_disabled_reasons_, sample);
382
383 EXPECT_THAT(histogram_tester_.GetAllSamples(
384 "BackForwardCache.HistoryNavigationOutcome."
385 "DisabledForRenderFrameHostReason"),
386 UnorderedElementsAreArray(expected_disabled_reasons_))
387 << location.ToString();
388 }
389
ExpectBrowsingInstanceNotSwappedReason(ShouldSwapBrowsingInstance reason,base::Location location)390 void ExpectBrowsingInstanceNotSwappedReason(ShouldSwapBrowsingInstance reason,
391 base::Location location) {
392 base::HistogramBase::Sample sample = base::HistogramBase::Sample(reason);
393 AddSampleToBuckets(&expected_browsing_instance_not_swapped_reasons_,
394 sample);
395
396 EXPECT_THAT(histogram_tester_.GetAllSamples(
397 "BackForwardCache.HistoryNavigationOutcome."
398 "BrowsingInstanceNotSwappedReason"),
399 UnorderedElementsAreArray(
400 expected_browsing_instance_not_swapped_reasons_))
401 << location.ToString();
402
403 if (!check_all_sites_)
404 return;
405
406 EXPECT_THAT(histogram_tester_.GetAllSamples(
407 "BackForwardCache.AllSites.HistoryNavigationOutcome."
408 "BrowsingInstanceNotSwappedReason"),
409 UnorderedElementsAreArray(
410 expected_browsing_instance_not_swapped_reasons_))
411 << location.ToString();
412 }
413
ExpectEvictedAfterCommitted(std::vector<BackForwardCacheMetrics::EvictedAfterDocumentRestoredReason> reasons,base::Location location)414 void ExpectEvictedAfterCommitted(
415 std::vector<BackForwardCacheMetrics::EvictedAfterDocumentRestoredReason>
416 reasons,
417 base::Location location) {
418 for (BackForwardCacheMetrics::EvictedAfterDocumentRestoredReason reason :
419 reasons) {
420 base::HistogramBase::Sample sample = base::HistogramBase::Sample(reason);
421 AddSampleToBuckets(&expected_eviction_after_committing_, sample);
422 }
423
424 EXPECT_THAT(histogram_tester_.GetAllSamples(
425 "BackForwardCache.EvictedAfterDocumentRestoredReason"),
426 UnorderedElementsAreArray(expected_eviction_after_committing_))
427 << location.ToString();
428 if (!check_all_sites_)
429 return;
430
431 EXPECT_THAT(
432 histogram_tester_.GetAllSamples(
433 "BackForwardCache.AllSites.EvictedAfterDocumentRestoredReason"),
434 UnorderedElementsAreArray(expected_eviction_after_committing_))
435 << location.ToString();
436 }
437
EvictByJavaScript(RenderFrameHostImpl * rfh)438 void EvictByJavaScript(RenderFrameHostImpl* rfh) {
439 // Run JavaScript on a page in the back-forward cache. The page should be
440 // evicted. As the frame is deleted, ExecJs returns false without executing.
441 // Run without user gesture to prevent UpdateUserActivationState message
442 // being sent back to browser.
443 EXPECT_FALSE(
444 ExecJs(rfh, "console.log('hi');", EXECUTE_SCRIPT_NO_USER_GESTURE));
445 }
446
StartRecordingEvents(RenderFrameHostImpl * rfh)447 void StartRecordingEvents(RenderFrameHostImpl* rfh) {
448 EXPECT_TRUE(ExecJs(rfh, R"(
449 window.testObservedEvents = [];
450 let event_list = [
451 'visibilitychange',
452 'pagehide',
453 'pageshow',
454 'freeze',
455 'resume',
456 'unload',
457 ];
458 for (event_name of event_list) {
459 let result = event_name;
460 window.addEventListener(event_name, event => {
461 if (event.persisted)
462 result += '.persisted';
463 window.testObservedEvents.push('window.' + result);
464 });
465 document.addEventListener(event_name,
466 () => window.testObservedEvents.push('document.' + result));
467 }
468 )"));
469 }
470
MatchEventList(RenderFrameHostImpl * rfh,base::ListValue list,base::Location location=base::Location::Current ())471 void MatchEventList(RenderFrameHostImpl* rfh,
472 base::ListValue list,
473 base::Location location = base::Location::Current()) {
474 EXPECT_EQ(list, EvalJs(rfh, "window.testObservedEvents"))
475 << location.ToString();
476 }
477
478 // Creates a minimal HTTPS server, accessible through https_server().
479 // Returns a pointer to the server.
CreateHttpsServer()480 net::EmbeddedTestServer* CreateHttpsServer() {
481 https_server_ = std::make_unique<net::EmbeddedTestServer>(
482 net::EmbeddedTestServer::TYPE_HTTPS);
483 https_server_->AddDefaultHandlers(GetTestDataFilePath());
484 https_server_->SetSSLConfig(net::EmbeddedTestServer::CERT_OK);
485 return https_server();
486 }
487
https_server()488 net::EmbeddedTestServer* https_server() { return https_server_.get(); }
489
ExpectTotalCount(base::StringPiece name,base::HistogramBase::Count count)490 void ExpectTotalCount(base::StringPiece name,
491 base::HistogramBase::Count count) {
492 histogram_tester_.ExpectTotalCount(name, count);
493 }
494
495 template <typename T>
ExpectBucketCount(base::StringPiece name,T sample,base::HistogramBase::Count expected_count)496 void ExpectBucketCount(base::StringPiece name,
497 T sample,
498 base::HistogramBase::Count expected_count) {
499 histogram_tester_.ExpectBucketCount(name, sample, expected_count);
500 }
501
502 template <typename T>
ExpectUniqueSample(base::StringPiece name,T sample,base::HistogramBase::Count expected_count)503 void ExpectUniqueSample(base::StringPiece name,
504 T sample,
505 base::HistogramBase::Count expected_count) {
506 histogram_tester_.ExpectUniqueSample(name, sample, expected_count);
507 }
508
509 // Do not fail this test if a message from a renderer arrives at the browser
510 // for a cached page.
DoNotFailForUnexpectedMessagesWhileCached()511 void DoNotFailForUnexpectedMessagesWhileCached() {
512 fail_for_unexpected_messages_while_cached_ = false;
513 }
514
515 base::HistogramTester histogram_tester_;
516
517 protected:
518 bool same_site_back_forward_cache_enabled_ = true;
519 bool skip_same_site_if_unload_exists_ = false;
520
521 private:
AddSampleToBuckets(std::vector<base::Bucket> * buckets,base::HistogramBase::Sample sample)522 void AddSampleToBuckets(std::vector<base::Bucket>* buckets,
523 base::HistogramBase::Sample sample) {
524 auto it = std::find_if(
525 buckets->begin(), buckets->end(),
526 [sample](const base::Bucket& bucket) { return bucket.min == sample; });
527 if (it == buckets->end()) {
528 buckets->push_back(base::Bucket(sample, 1));
529 } else {
530 it->count++;
531 }
532 }
533
534 base::test::ScopedFeatureList feature_list_;
535
536 FrameTreeVisualizer visualizer_;
537 std::vector<base::Bucket> expected_outcomes_;
538 std::vector<base::Bucket> expected_not_restored_;
539 std::vector<base::Bucket> expected_blocklisted_features_;
540 std::vector<base::Bucket> expected_disabled_reasons_;
541 std::vector<base::Bucket> expected_browsing_instance_not_swapped_reasons_;
542 std::vector<base::Bucket> expected_eviction_after_committing_;
543 std::unique_ptr<net::EmbeddedTestServer> https_server_;
544 std::unordered_map<base::Feature,
545 std::map<std::string, std::string>,
546 FeatureHash,
547 FeatureEqualOperator>
548 features_with_params_;
549 std::vector<base::Feature> disabled_features_;
550
551 std::vector<UkmMetrics> expected_ukm_outcomes_;
552 std::vector<UkmMetrics> expected_ukm_not_restored_reasons_;
553 std::unique_ptr<ukm::TestAutoSetUkmRecorder> ukm_recorder_;
554
555 // Indicates whether metrics for all sites regardless of the domains are
556 // checked or not.
557 bool check_all_sites_ = true;
558 // Whether we should fail the test if a message arrived at the browser from a
559 // renderer for a bfcached page.
560 bool fail_for_unexpected_messages_while_cached_ = true;
561 };
562
563 // Match RenderFrameHostImpl* that are in the BackForwardCache.
564 MATCHER(InBackForwardCache, "") {
565 return arg->IsInBackForwardCache();
566 }
567
568 // Match RenderFrameDeleteObserver* which observed deletion of the RenderFrame.
569 MATCHER(Deleted, "") {
570 return arg->deleted();
571 }
572
573 // Helper function to pass an initializer list to the EXPECT_THAT macro. This is
574 // indeed the identity function.
Elements(std::initializer_list<RenderFrameHostImpl * > t)575 std::initializer_list<RenderFrameHostImpl*> Elements(
576 std::initializer_list<RenderFrameHostImpl*> t) {
577 return t;
578 }
579
580 // Execute a custom callback when navigation is ready to commit. This is
581 // useful for simulating race conditions happening when a page enters the
582 // BackForwardCache and receive inflight messages sent when it wasn't frozen
583 // yet.
584 class ReadyToCommitNavigationCallback : public WebContentsObserver {
585 public:
ReadyToCommitNavigationCallback(WebContents * content,base::OnceCallback<void (NavigationHandle *)> callback)586 ReadyToCommitNavigationCallback(
587 WebContents* content,
588 base::OnceCallback<void(NavigationHandle*)> callback)
589 : WebContentsObserver(content), callback_(std::move(callback)) {}
590
591 private:
592 // WebContentsObserver:
ReadyToCommitNavigation(NavigationHandle * navigation_handle)593 void ReadyToCommitNavigation(NavigationHandle* navigation_handle) override {
594 if (callback_)
595 std::move(callback_).Run(navigation_handle);
596 }
597
598 base::OnceCallback<void(NavigationHandle*)> callback_;
599
600 DISALLOW_COPY_AND_ASSIGN(ReadyToCommitNavigationCallback);
601 };
602
603 class FirstVisuallyNonEmptyPaintObserver : public WebContentsObserver {
604 public:
FirstVisuallyNonEmptyPaintObserver(WebContents * contents)605 explicit FirstVisuallyNonEmptyPaintObserver(WebContents* contents)
606 : WebContentsObserver(contents) {}
DidFirstVisuallyNonEmptyPaint()607 void DidFirstVisuallyNonEmptyPaint() override {
608 if (observed_)
609 return;
610 observed_ = true;
611 run_loop_.Quit();
612 }
613
did_fire() const614 bool did_fire() const { return observed_; }
615
Wait()616 void Wait() { run_loop_.Run(); }
617
618 private:
619 bool observed_ = false;
620 base::RunLoop run_loop_{base::RunLoop::Type::kNestableTasksAllowed};
621 };
622
WaitForFirstVisuallyNonEmptyPaint(WebContents * contents)623 void WaitForFirstVisuallyNonEmptyPaint(WebContents* contents) {
624 if (contents->CompletedFirstVisuallyNonEmptyPaint())
625 return;
626 FirstVisuallyNonEmptyPaintObserver observer(contents);
627 observer.Wait();
628 }
629
630 class ThemeColorObserver : public WebContentsObserver {
631 public:
ThemeColorObserver(WebContents * contents)632 explicit ThemeColorObserver(WebContents* contents)
633 : WebContentsObserver(contents) {}
DidChangeThemeColor()634 void DidChangeThemeColor() override { observed_ = true; }
635
did_fire() const636 bool did_fire() const { return observed_; }
637
638 private:
639 bool observed_ = false;
640 };
641
642 class DOMContentLoadedObserver : public WebContentsObserver {
643 public:
DOMContentLoadedObserver(RenderFrameHostImpl * render_frame_host)644 explicit DOMContentLoadedObserver(RenderFrameHostImpl* render_frame_host)
645 : WebContentsObserver(
646 WebContents::FromRenderFrameHost(render_frame_host)),
647 render_frame_host_(render_frame_host) {}
648
DOMContentLoaded(RenderFrameHost * render_frame_host)649 void DOMContentLoaded(RenderFrameHost* render_frame_host) override {
650 if (render_frame_host_ == render_frame_host)
651 run_loop_.Quit();
652 }
653
Wait()654 void Wait() {
655 if (render_frame_host_->IsDOMContentLoaded())
656 run_loop_.Quit();
657 run_loop_.Run();
658 }
659
660 private:
661 RenderFrameHostImpl* render_frame_host_;
662 base::RunLoop run_loop_;
663 };
664
WaitForDOMContentLoaded(RenderFrameHostImpl * rfh)665 void WaitForDOMContentLoaded(RenderFrameHostImpl* rfh) {
666 DOMContentLoadedObserver observer(rfh);
667 observer.Wait();
668 }
669
670 class PageLifecycleStateManagerTestDelegate
671 : public PageLifecycleStateManager::TestDelegate {
672 public:
PageLifecycleStateManagerTestDelegate(PageLifecycleStateManager * manager)673 explicit PageLifecycleStateManagerTestDelegate(
674 PageLifecycleStateManager* manager)
675 : manager_(manager) {
676 manager->SetDelegateForTesting(this);
677 }
678
~PageLifecycleStateManagerTestDelegate()679 ~PageLifecycleStateManagerTestDelegate() override {
680 manager_->SetDelegateForTesting(nullptr);
681 }
682
WaitForInBackForwardCacheAck()683 void WaitForInBackForwardCacheAck() {
684 if (manager_->last_acknowledged_state().is_in_back_forward_cache) {
685 return;
686 }
687 base::RunLoop loop;
688 store_in_back_forward_cache_ack_received_ = loop.QuitClosure();
689 loop.Run();
690 }
691
OnStoreInBackForwardCacheSent(base::OnceClosure cb)692 void OnStoreInBackForwardCacheSent(base::OnceClosure cb) {
693 store_in_back_forward_cache_sent_ = std::move(cb);
694 }
695
OnRestoreFromBackForwardCacheSent(base::OnceClosure cb)696 void OnRestoreFromBackForwardCacheSent(base::OnceClosure cb) {
697 restore_from_back_forward_cache_sent_ = std::move(cb);
698 }
699
700 private:
OnLastAcknowledgedStateChanged(const blink::mojom::PageLifecycleState & old_state,const blink::mojom::PageLifecycleState & new_state)701 void OnLastAcknowledgedStateChanged(
702 const blink::mojom::PageLifecycleState& old_state,
703 const blink::mojom::PageLifecycleState& new_state) override {
704 if (store_in_back_forward_cache_ack_received_ &&
705 new_state.is_in_back_forward_cache)
706 std::move(store_in_back_forward_cache_ack_received_).Run();
707 }
708
OnUpdateSentToRenderer(const blink::mojom::PageLifecycleState & new_state)709 void OnUpdateSentToRenderer(
710 const blink::mojom::PageLifecycleState& new_state) override {
711 if (store_in_back_forward_cache_sent_ &&
712 new_state.is_in_back_forward_cache) {
713 std::move(store_in_back_forward_cache_sent_).Run();
714 }
715
716 if (restore_from_back_forward_cache_sent_ &&
717 !new_state.is_in_back_forward_cache) {
718 std::move(restore_from_back_forward_cache_sent_).Run();
719 }
720 }
721
722 PageLifecycleStateManager* const manager_;
723 base::OnceClosure store_in_back_forward_cache_sent_;
724 base::OnceClosure store_in_back_forward_cache_ack_received_;
725 base::OnceClosure restore_from_back_forward_cache_sent_;
726 };
727
728 class FakeIdleTimeProvider : public IdleManager::IdleTimeProvider {
729 public:
730 FakeIdleTimeProvider() = default;
731 ~FakeIdleTimeProvider() override = default;
732 FakeIdleTimeProvider(const FakeIdleTimeProvider&) = delete;
733 FakeIdleTimeProvider& operator=(const FakeIdleTimeProvider&) = delete;
734
CalculateIdleTime()735 base::TimeDelta CalculateIdleTime() override {
736 return base::TimeDelta::FromSeconds(0);
737 }
738
CheckIdleStateIsLocked()739 bool CheckIdleStateIsLocked() override { return false; }
740 };
741
742 } // namespace
743
744 // Navigate from A to B and go back.
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,Basic)745 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, Basic) {
746 ASSERT_TRUE(embedded_test_server()->Start());
747 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
748 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
749 url::Origin origin_a = url::Origin::Create(url_a);
750 url::Origin origin_b = url::Origin::Create(url_b);
751
752 // 1) Navigate to A.
753 EXPECT_TRUE(NavigateToURL(shell(), url_a));
754 RenderFrameHostImpl* rfh_a = current_frame_host();
755 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
756
757 // 2) Navigate to B.
758 EXPECT_TRUE(NavigateToURL(shell(), url_b));
759 RenderFrameHostImpl* rfh_b = current_frame_host();
760 RenderFrameDeletedObserver delete_observer_rfh_b(rfh_b);
761 EXPECT_FALSE(delete_observer_rfh_a.deleted());
762 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
763 EXPECT_EQ(rfh_a->GetVisibilityState(), PageVisibilityState::kHidden);
764 EXPECT_EQ(origin_a, rfh_a->GetLastCommittedOrigin());
765 EXPECT_EQ(origin_b, rfh_b->GetLastCommittedOrigin());
766 EXPECT_FALSE(rfh_b->IsInBackForwardCache());
767 EXPECT_EQ(rfh_b->GetVisibilityState(), PageVisibilityState::kVisible);
768
769 // 3) Go back to A.
770 web_contents()->GetController().GoBack();
771 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
772 EXPECT_FALSE(delete_observer_rfh_a.deleted());
773 EXPECT_FALSE(delete_observer_rfh_b.deleted());
774 EXPECT_EQ(origin_a, rfh_a->GetLastCommittedOrigin());
775 EXPECT_EQ(origin_b, rfh_b->GetLastCommittedOrigin());
776 EXPECT_EQ(rfh_a, current_frame_host());
777 EXPECT_FALSE(rfh_a->IsInBackForwardCache());
778 EXPECT_EQ(rfh_a->GetVisibilityState(), PageVisibilityState::kVisible);
779 EXPECT_TRUE(rfh_b->IsInBackForwardCache());
780 EXPECT_EQ(rfh_b->GetVisibilityState(), PageVisibilityState::kHidden);
781
782 ExpectOutcome(BackForwardCacheMetrics::HistoryNavigationOutcome::kRestored,
783 FROM_HERE);
784 }
785
786 // Navigate from A to B and go back.
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,BasicDocumentInitiated)787 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, BasicDocumentInitiated) {
788 ASSERT_TRUE(embedded_test_server()->Start());
789 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
790 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
791
792 // 1) Navigate to A.
793 EXPECT_TRUE(NavigateToURL(shell(), url_a));
794 RenderFrameHostImpl* rfh_a = current_frame_host();
795 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
796
797 // 2) Navigate to B.
798 EXPECT_TRUE(ExecJs(shell(), JsReplace("location = $1;", url_b.spec())));
799 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
800 RenderFrameHostImpl* rfh_b = current_frame_host();
801 RenderFrameDeletedObserver delete_observer_rfh_b(rfh_b);
802 EXPECT_FALSE(delete_observer_rfh_a.deleted());
803 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
804 EXPECT_FALSE(rfh_b->IsInBackForwardCache());
805
806 // The two pages are using different BrowsingInstances.
807 EXPECT_FALSE(rfh_a->GetSiteInstance()->IsRelatedSiteInstance(
808 rfh_b->GetSiteInstance()));
809
810 // 3) Go back to A.
811 EXPECT_TRUE(ExecJs(shell(), "history.back();"));
812 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
813 EXPECT_FALSE(delete_observer_rfh_a.deleted());
814 EXPECT_FALSE(delete_observer_rfh_b.deleted());
815 EXPECT_EQ(rfh_a, current_frame_host());
816 EXPECT_FALSE(rfh_a->IsInBackForwardCache());
817 EXPECT_TRUE(rfh_b->IsInBackForwardCache());
818
819 ExpectOutcome(BackForwardCacheMetrics::HistoryNavigationOutcome::kRestored,
820 FROM_HERE);
821 }
822
823 // Navigate from back and forward repeatedly.
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,NavigateBackForwardRepeatedly)824 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
825 NavigateBackForwardRepeatedly) {
826 // Do not check for unexpected messages because the input task queue is not
827 // currently frozen, causing flakes in this test: crbug.com/1099395.
828 DoNotFailForUnexpectedMessagesWhileCached();
829 ASSERT_TRUE(embedded_test_server()->Start());
830 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
831 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
832
833 // 1) Navigate to A.
834 EXPECT_TRUE(NavigateToURL(shell(), url_a));
835 RenderFrameHostImpl* rfh_a = current_frame_host();
836 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
837
838 // 2) Navigate to B.
839 EXPECT_TRUE(NavigateToURL(shell(), url_b));
840 RenderFrameHostImpl* rfh_b = current_frame_host();
841 RenderFrameDeletedObserver delete_observer_rfh_b(rfh_b);
842 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
843 EXPECT_FALSE(rfh_b->IsInBackForwardCache());
844
845 // 3) Go back to A.
846 web_contents()->GetController().GoBack();
847 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
848
849 EXPECT_EQ(rfh_a, current_frame_host());
850 EXPECT_FALSE(rfh_a->IsInBackForwardCache());
851 EXPECT_TRUE(rfh_b->IsInBackForwardCache());
852
853 ExpectOutcome(BackForwardCacheMetrics::HistoryNavigationOutcome::kRestored,
854 FROM_HERE);
855
856 // 4) Go forward to B.
857 web_contents()->GetController().GoForward();
858 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
859
860 EXPECT_EQ(rfh_b, current_frame_host());
861 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
862 EXPECT_FALSE(rfh_b->IsInBackForwardCache());
863
864 ExpectOutcome(BackForwardCacheMetrics::HistoryNavigationOutcome::kRestored,
865 FROM_HERE);
866
867 // 5) Go back to A.
868 web_contents()->GetController().GoBack();
869 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
870
871 EXPECT_EQ(rfh_a, current_frame_host());
872 EXPECT_FALSE(rfh_a->IsInBackForwardCache());
873 EXPECT_TRUE(rfh_b->IsInBackForwardCache());
874
875 ExpectOutcome(BackForwardCacheMetrics::HistoryNavigationOutcome::kRestored,
876 FROM_HERE);
877
878 // 6) Go forward to B.
879 web_contents()->GetController().GoForward();
880 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
881
882 EXPECT_EQ(rfh_b, current_frame_host());
883 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
884 EXPECT_FALSE(rfh_b->IsInBackForwardCache());
885
886 EXPECT_FALSE(delete_observer_rfh_a.deleted());
887 EXPECT_FALSE(delete_observer_rfh_b.deleted());
888
889 ExpectOutcome(BackForwardCacheMetrics::HistoryNavigationOutcome::kRestored,
890 FROM_HERE);
891 }
892
893 // The current page can't enter the BackForwardCache if another page can script
894 // it. This can happen when one document opens a popup using window.open() for
895 // instance. It prevents the BackForwardCache from being used.
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,WindowOpen)896 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, WindowOpen) {
897 // This test assumes cross-site navigation staying in the same
898 // BrowsingInstance to use a different SiteInstance. Otherwise, it will
899 // timeout at step 2).
900 if (!SiteIsolationPolicy::UseDedicatedProcessesForAllSites())
901 return;
902
903 ASSERT_TRUE(embedded_test_server()->Start());
904 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
905 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
906
907 // 1) Navigate to A and open a popup.
908 EXPECT_TRUE(NavigateToURL(shell(), url_a));
909 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
910 RenderFrameHostImpl* rfh_a = current_frame_host();
911 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
912 EXPECT_EQ(1u, rfh_a->GetSiteInstance()->GetRelatedActiveContentsCount());
913 Shell* popup = OpenPopup(rfh_a, url_a, "");
914 EXPECT_EQ(2u, rfh_a->GetSiteInstance()->GetRelatedActiveContentsCount());
915
916 // 2) Navigate to B. The previous document can't enter the BackForwardCache,
917 // because of the popup.
918 EXPECT_TRUE(ExecJs(rfh_a, JsReplace("location = $1;", url_b.spec())));
919 delete_observer_rfh_a.WaitUntilDeleted();
920 RenderFrameHostImpl* rfh_b = current_frame_host();
921 EXPECT_EQ(2u, rfh_b->GetSiteInstance()->GetRelatedActiveContentsCount());
922
923 // 3) Go back to A. The previous document can't enter the BackForwardCache,
924 // because of the popup.
925 RenderFrameDeletedObserver delete_observer_rfh_b(rfh_b);
926 EXPECT_TRUE(ExecJs(rfh_b, "history.back();"));
927 delete_observer_rfh_b.WaitUntilDeleted();
928
929 // 4) Make the popup drop the window.opener connection. It happens when the
930 // user does an omnibox-initiated navigation, which happens in a new
931 // BrowsingInstance.
932 RenderFrameHostImpl* rfh_a_new = current_frame_host();
933 EXPECT_EQ(2u, rfh_a_new->GetSiteInstance()->GetRelatedActiveContentsCount());
934 EXPECT_TRUE(NavigateToURL(popup, url_b));
935 EXPECT_EQ(1u, rfh_a_new->GetSiteInstance()->GetRelatedActiveContentsCount());
936
937 // 5) Navigate to B again. As the scripting relationship with the popup is
938 // now severed, the current page (|rfh_a_new|) can enter back-forward cache.
939 RenderFrameDeletedObserver delete_observer_rfh_a_new(rfh_a_new);
940 EXPECT_TRUE(ExecJs(rfh_a_new, JsReplace("location = $1;", url_b.spec())));
941 EXPECT_TRUE(WaitForLoadStop(web_contents()));
942 EXPECT_FALSE(delete_observer_rfh_a_new.deleted());
943 EXPECT_TRUE(rfh_a_new->IsInBackForwardCache());
944
945 // 6) Go back to A. The current document can finally enter the
946 // BackForwardCache, because it is alone in its BrowsingInstance and has never
947 // been related to any other document.
948 RenderFrameHostImpl* rfh_b_new = current_frame_host();
949 RenderFrameDeletedObserver delete_observer_rfh_b_new(rfh_b_new);
950 EXPECT_TRUE(ExecJs(rfh_b_new, "history.back();"));
951 EXPECT_TRUE(WaitForLoadStop(web_contents()));
952 EXPECT_FALSE(delete_observer_rfh_b_new.deleted());
953 EXPECT_TRUE(rfh_b_new->IsInBackForwardCache());
954 }
955
956 // Navigate from A(B) to C and go back.
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,BasicIframe)957 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, BasicIframe) {
958 ASSERT_TRUE(embedded_test_server()->Start());
959 GURL url_a(embedded_test_server()->GetURL(
960 "a.com", "/cross_site_iframe_factory.html?a(b)"));
961 GURL url_c(embedded_test_server()->GetURL("c.com", "/title1.html"));
962
963 // 1) Navigate to A(B).
964 EXPECT_TRUE(NavigateToURL(shell(), url_a));
965 RenderFrameHostImpl* rfh_a = current_frame_host();
966 RenderFrameHostImpl* rfh_b = rfh_a->child_at(0)->current_frame_host();
967 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
968 RenderFrameDeletedObserver delete_observer_rfh_b(rfh_b);
969
970 // 2) Navigate to C.
971 EXPECT_TRUE(NavigateToURL(shell(), url_c));
972 RenderFrameHostImpl* rfh_c = current_frame_host();
973 RenderFrameDeletedObserver delete_observer_rfh_c(rfh_c);
974 EXPECT_FALSE(delete_observer_rfh_a.deleted());
975 EXPECT_FALSE(delete_observer_rfh_b.deleted());
976 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
977 EXPECT_TRUE(rfh_b->IsInBackForwardCache());
978 EXPECT_FALSE(rfh_c->IsInBackForwardCache());
979
980 // 3) Go back to A(B).
981 web_contents()->GetController().GoBack();
982 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
983 EXPECT_FALSE(delete_observer_rfh_a.deleted());
984 EXPECT_FALSE(delete_observer_rfh_b.deleted());
985 EXPECT_FALSE(delete_observer_rfh_c.deleted());
986 EXPECT_EQ(rfh_a, current_frame_host());
987 EXPECT_FALSE(rfh_a->IsInBackForwardCache());
988 EXPECT_FALSE(rfh_b->IsInBackForwardCache());
989 EXPECT_TRUE(rfh_c->IsInBackForwardCache());
990
991 ExpectOutcome(BackForwardCacheMetrics::HistoryNavigationOutcome::kRestored,
992 FROM_HERE);
993 }
994
995 // Ensure flushing the BackForwardCache works properly.
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,BackForwardCacheFlush)996 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, BackForwardCacheFlush) {
997 ASSERT_TRUE(embedded_test_server()->Start());
998 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
999 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
1000
1001 // 1) Navigate to A.
1002 EXPECT_TRUE(NavigateToURL(shell(), url_a));
1003 RenderFrameHostImpl* rfh_a = current_frame_host();
1004 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
1005
1006 // 2) Navigate to B.
1007 EXPECT_TRUE(NavigateToURL(shell(), url_b));
1008 RenderFrameHostImpl* rfh_b = current_frame_host();
1009 RenderFrameDeletedObserver delete_observer_rfh_b(rfh_b);
1010 EXPECT_FALSE(delete_observer_rfh_a.deleted());
1011
1012 // 3) Flush A.
1013 web_contents()->GetController().GetBackForwardCache().Flush();
1014 delete_observer_rfh_a.WaitUntilDeleted();
1015 EXPECT_FALSE(delete_observer_rfh_b.deleted());
1016
1017 // 4) Go back to a new A.
1018 web_contents()->GetController().GoBack();
1019 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
1020 EXPECT_FALSE(delete_observer_rfh_b.deleted());
1021
1022 // 5) Flush B.
1023 web_contents()->GetController().GetBackForwardCache().Flush();
1024 delete_observer_rfh_b.WaitUntilDeleted();
1025 }
1026
1027 // Check the visible URL in the omnibox is properly updated when restoring a
1028 // document from the BackForwardCache.
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,VisibleURL)1029 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, VisibleURL) {
1030 ASSERT_TRUE(embedded_test_server()->Start());
1031 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
1032 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
1033
1034 // 1) Go to A.
1035 EXPECT_TRUE(NavigateToURL(shell(), url_a));
1036
1037 // 2) Go to B.
1038 EXPECT_TRUE(NavigateToURL(shell(), url_b));
1039
1040 // 3) Go back to A.
1041 web_contents()->GetController().GoBack();
1042 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
1043 EXPECT_EQ(url_a, web_contents()->GetVisibleURL());
1044
1045 // 4) Go forward to B.
1046 web_contents()->GetController().GoForward();
1047 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
1048 EXPECT_EQ(url_b, web_contents()->GetVisibleURL());
1049 }
1050
1051 // Test only 1 document is kept in the at a time BackForwardCache.
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,CacheSizeLimitedToOneDocumentPerTab)1052 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
1053 CacheSizeLimitedToOneDocumentPerTab) {
1054 ASSERT_TRUE(embedded_test_server()->Start());
1055 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
1056 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
1057 GURL url_c(embedded_test_server()->GetURL("c.com", "/title1.html"));
1058
1059 EXPECT_TRUE(NavigateToURL(shell(), url_a));
1060 // BackForwardCache is empty.
1061 RenderFrameHostImpl* rfh_a = current_frame_host();
1062 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
1063
1064 EXPECT_TRUE(NavigateToURL(shell(), url_b));
1065 // BackForwardCache contains only rfh_a.
1066 RenderFrameHostImpl* rfh_b = current_frame_host();
1067 RenderFrameDeletedObserver delete_observer_rfh_b(rfh_b);
1068
1069 EXPECT_TRUE(NavigateToURL(shell(), url_c));
1070 // BackForwardCache contains only rfh_b.
1071 delete_observer_rfh_a.WaitUntilDeleted();
1072 EXPECT_FALSE(delete_observer_rfh_b.deleted());
1073
1074 // If/when the cache size is increased, this can be tested iteratively, see
1075 // deleted code in: https://crrev.com/c/1782902.
1076
1077 web_contents()->GetController().GoToOffset(-2);
1078 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
1079 ExpectOutcome(BackForwardCacheMetrics::HistoryNavigationOutcome::kNotRestored,
1080 FROM_HERE);
1081 ExpectNotRestored({BackForwardCacheMetrics::NotRestoredReason::kCacheLimit},
1082 FROM_HERE);
1083 }
1084
1085 class HighCacheSizeBackForwardCacheBrowserTest
1086 : public BackForwardCacheBrowserTest {
1087 protected:
SetUpCommandLine(base::CommandLine * command_line)1088 void SetUpCommandLine(base::CommandLine* command_line) override {
1089 EnableFeatureAndSetParams(features::kBackForwardCache, "cache_size",
1090 base::NumberToString(kBackForwardCacheSize));
1091 BackForwardCacheBrowserTest::SetUpCommandLine(command_line);
1092 }
1093
1094 // The number of document the BackForwardCache can hold per tab.
1095 const size_t kBackForwardCacheSize = 10;
1096 };
1097
1098 // Test documents are evicted from the BackForwardCache at some point.
IN_PROC_BROWSER_TEST_F(HighCacheSizeBackForwardCacheBrowserTest,CacheEvictionWithIncreasedCacheSize)1099 IN_PROC_BROWSER_TEST_F(HighCacheSizeBackForwardCacheBrowserTest,
1100 CacheEvictionWithIncreasedCacheSize) {
1101 ASSERT_TRUE(embedded_test_server()->Start());
1102
1103 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
1104 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
1105
1106 EXPECT_TRUE(NavigateToURL(shell(), url_a)); // BackForwardCache size is 0.
1107 RenderFrameHostImpl* rfh_a = current_frame_host();
1108 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
1109
1110 EXPECT_TRUE(NavigateToURL(shell(), url_b)); // BackForwardCache size is 1.
1111 RenderFrameHostImpl* rfh_b = current_frame_host();
1112 RenderFrameDeletedObserver delete_observer_rfh_b(rfh_b);
1113
1114 for (size_t i = 2; i < kBackForwardCacheSize; ++i) {
1115 EXPECT_TRUE(NavigateToURL(shell(), i % 2 ? url_b : url_a));
1116 // After |i+1| navigations, |i| documents went into the BackForwardCache.
1117 // When |i| is greater than the BackForwardCache size limit, they are
1118 // evicted:
1119 EXPECT_EQ(i >= kBackForwardCacheSize + 1, delete_observer_rfh_a.deleted());
1120 EXPECT_EQ(i >= kBackForwardCacheSize + 2, delete_observer_rfh_b.deleted());
1121 }
1122 }
1123
1124 // Similar to BackForwardCacheBrowserTest.SubframeSurviveCache*
1125 // Test case: a1(b2) -> c3 -> a1(b2)
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,SubframeSurviveCache1)1126 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, SubframeSurviveCache1) {
1127 ASSERT_TRUE(embedded_test_server()->Start());
1128 GURL url_a(embedded_test_server()->GetURL(
1129 "a.com", "/cross_site_iframe_factory.html?a(b)"));
1130 GURL url_c(embedded_test_server()->GetURL("c.com", "/title1.html"));
1131
1132 std::vector<RenderFrameDeletedObserver*> rfh_observer;
1133
1134 // 1) Navigate to a1(b2).
1135 EXPECT_TRUE(NavigateToURL(shell(), url_a));
1136 RenderFrameHostImpl* a1 = current_frame_host();
1137 RenderFrameHostImpl* b2 = a1->child_at(0)->current_frame_host();
1138 RenderFrameDeletedObserver a1_observer(a1), b2_observer(b2);
1139 rfh_observer.insert(rfh_observer.end(), {&a1_observer, &b2_observer});
1140 EXPECT_TRUE(ExecJs(b2, "window.alive = 'I am alive';"));
1141
1142 // 2) Navigate to c3.
1143 EXPECT_TRUE(NavigateToURL(shell(), url_c));
1144 RenderFrameHostImpl* c3 = current_frame_host();
1145 RenderFrameDeletedObserver c3_observer(c3);
1146 rfh_observer.push_back(&c3_observer);
1147 ASSERT_THAT(rfh_observer, Each(Not(Deleted())));
1148 EXPECT_THAT(Elements({a1, b2}), Each(InBackForwardCache()));
1149 EXPECT_THAT(c3, Not(InBackForwardCache()));
1150
1151 // 3) Go back to a1(b2).
1152 web_contents()->GetController().GoBack();
1153 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
1154 ASSERT_THAT(rfh_observer, Each(Not(Deleted())));
1155 EXPECT_THAT(Elements({a1, b2}), Each(Not(InBackForwardCache())));
1156 EXPECT_THAT(c3, InBackForwardCache());
1157
1158 // Even after a new IPC round trip with the renderer, b2 must still be alive.
1159 EXPECT_EQ("I am alive", EvalJs(b2, "window.alive"));
1160 EXPECT_FALSE(b2_observer.deleted());
1161
1162 ExpectOutcome(BackForwardCacheMetrics::HistoryNavigationOutcome::kRestored,
1163 FROM_HERE);
1164 }
1165
1166 // Similar to BackForwardCacheBrowserTest.SubframeSurviveCache*
1167 // Test case: a1(b2) -> b3 -> a1(b2).
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,SubframeSurviveCache2)1168 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, SubframeSurviveCache2) {
1169 ASSERT_TRUE(embedded_test_server()->Start());
1170 GURL url_a(embedded_test_server()->GetURL(
1171 "a.com", "/cross_site_iframe_factory.html?a(b)"));
1172 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
1173
1174 std::vector<RenderFrameDeletedObserver*> rfh_observer;
1175
1176 // 1) Navigate to a1(b2).
1177 EXPECT_TRUE(NavigateToURL(shell(), url_a));
1178 RenderFrameHostImpl* a1 = current_frame_host();
1179 RenderFrameHostImpl* b2 = a1->child_at(0)->current_frame_host();
1180 RenderFrameDeletedObserver a1_observer(a1), b2_observer(b2);
1181 rfh_observer.insert(rfh_observer.end(), {&a1_observer, &b2_observer});
1182 EXPECT_TRUE(ExecJs(b2, "window.alive = 'I am alive';"));
1183
1184 // 2) Navigate to b3.
1185 EXPECT_TRUE(NavigateToURL(shell(), url_b));
1186 RenderFrameHostImpl* b3 = current_frame_host();
1187 RenderFrameDeletedObserver b3_observer(b3);
1188 rfh_observer.push_back(&b3_observer);
1189 ASSERT_THAT(rfh_observer, Each(Not(Deleted())));
1190 EXPECT_THAT(Elements({a1, b2}), Each(InBackForwardCache()));
1191 EXPECT_THAT(b3, Not(InBackForwardCache()));
1192
1193 // 3) Go back to a1(b2).
1194 web_contents()->GetController().GoBack();
1195 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
1196 ASSERT_THAT(rfh_observer, Each(Not(Deleted())));
1197 EXPECT_EQ(a1, current_frame_host());
1198 EXPECT_THAT(Elements({a1, b2}), Each(Not(InBackForwardCache())));
1199 EXPECT_THAT(b3, InBackForwardCache());
1200
1201 // Even after a new IPC round trip with the renderer, b2 must still be alive.
1202 EXPECT_EQ("I am alive", EvalJs(b2, "window.alive"));
1203 EXPECT_FALSE(b2_observer.deleted());
1204
1205 ExpectOutcome(BackForwardCacheMetrics::HistoryNavigationOutcome::kRestored,
1206 FROM_HERE);
1207 }
1208
1209 // Similar to BackForwardCacheBrowserTest.tSubframeSurviveCache*
1210 // Test case: a1(b2) -> b3(a4) -> a1(b2) -> b3(a4)
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,SubframeSurviveCache3)1211 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, SubframeSurviveCache3) {
1212 ASSERT_TRUE(embedded_test_server()->Start());
1213 GURL url_a(embedded_test_server()->GetURL(
1214 "a.com", "/cross_site_iframe_factory.html?a(b)"));
1215 GURL url_b(embedded_test_server()->GetURL(
1216 "b.com", "/cross_site_iframe_factory.html?b(a)"));
1217
1218 std::vector<RenderFrameDeletedObserver*> rfh_observer;
1219
1220 // 1) Navigate to a1(b2).
1221 EXPECT_TRUE(NavigateToURL(shell(), url_a));
1222 RenderFrameHostImpl* a1 = current_frame_host();
1223 RenderFrameHostImpl* b2 = a1->child_at(0)->current_frame_host();
1224 RenderFrameDeletedObserver a1_observer(a1), b2_observer(b2);
1225 rfh_observer.insert(rfh_observer.end(), {&a1_observer, &b2_observer});
1226 EXPECT_TRUE(ExecJs(b2, "window.alive = 'I am alive';"));
1227
1228 // 2) Navigate to b3(a4)
1229 EXPECT_TRUE(NavigateToURL(shell(), url_b));
1230 RenderFrameHostImpl* b3 = current_frame_host();
1231 RenderFrameHostImpl* a4 = b3->child_at(0)->current_frame_host();
1232 RenderFrameDeletedObserver b3_observer(b3), a4_observer(a4);
1233 rfh_observer.insert(rfh_observer.end(), {&b3_observer, &a4_observer});
1234 ASSERT_THAT(rfh_observer, Each(Not(Deleted())));
1235 EXPECT_THAT(Elements({a1, b2}), Each(InBackForwardCache()));
1236 EXPECT_THAT(Elements({b3, a4}), Each(Not(InBackForwardCache())));
1237 EXPECT_TRUE(ExecJs(a4, "window.alive = 'I am alive';"));
1238
1239 // 3) Go back to a1(b2).
1240 web_contents()->GetController().GoBack();
1241 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
1242 ASSERT_THAT(rfh_observer, Each(Not(Deleted())));
1243 EXPECT_EQ(a1, current_frame_host());
1244 EXPECT_THAT(Elements({a1, b2}), Each(Not(InBackForwardCache())));
1245 EXPECT_THAT(Elements({b3, a4}), Each(InBackForwardCache()));
1246
1247 // Even after a new IPC round trip with the renderer, b2 must still be alive.
1248 EXPECT_EQ("I am alive", EvalJs(b2, "window.alive"));
1249 EXPECT_FALSE(b2_observer.deleted());
1250
1251 ExpectOutcome(BackForwardCacheMetrics::HistoryNavigationOutcome::kRestored,
1252 FROM_HERE);
1253
1254 // 4) Go forward to b3(a4).
1255 web_contents()->GetController().GoForward();
1256 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
1257 ASSERT_THAT(rfh_observer, Each(Not(Deleted())));
1258 EXPECT_EQ(b3, current_frame_host());
1259 EXPECT_THAT(Elements({a1, b2}), Each(InBackForwardCache()));
1260 EXPECT_THAT(Elements({b3, a4}), Each(Not(InBackForwardCache())));
1261
1262 // Even after a new IPC round trip with the renderer, a4 must still be alive.
1263 EXPECT_EQ("I am alive", EvalJs(a4, "window.alive"));
1264 EXPECT_FALSE(a4_observer.deleted());
1265
1266 ExpectOutcome(BackForwardCacheMetrics::HistoryNavigationOutcome::kRestored,
1267 FROM_HERE);
1268 }
1269
1270 // Similar to BackForwardCacheBrowserTest.SubframeSurviveCache*
1271 // Test case: a1(b2) -> b3 -> a4 -> b5 -> a1(b2).
IN_PROC_BROWSER_TEST_F(HighCacheSizeBackForwardCacheBrowserTest,SubframeSurviveCache4)1272 IN_PROC_BROWSER_TEST_F(HighCacheSizeBackForwardCacheBrowserTest,
1273 SubframeSurviveCache4) {
1274 ASSERT_TRUE(embedded_test_server()->Start());
1275 GURL url_ab(embedded_test_server()->GetURL(
1276 "a.com", "/cross_site_iframe_factory.html?a(b)"));
1277 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
1278 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
1279
1280 std::vector<RenderFrameDeletedObserver*> rfh_observer;
1281
1282 // 1) Navigate to a1(b2).
1283 EXPECT_TRUE(NavigateToURL(shell(), url_ab));
1284 RenderFrameHostImpl* a1 = current_frame_host();
1285 RenderFrameHostImpl* b2 = a1->child_at(0)->current_frame_host();
1286 RenderFrameDeletedObserver a1_observer(a1), b2_observer(b2);
1287 rfh_observer.insert(rfh_observer.end(), {&a1_observer, &b2_observer});
1288 EXPECT_TRUE(ExecJs(b2, "window.alive = 'I am alive';"));
1289
1290 // 2) Navigate to b3.
1291 EXPECT_TRUE(NavigateToURL(shell(), url_b));
1292 RenderFrameHostImpl* b3 = current_frame_host();
1293 RenderFrameDeletedObserver b3_observer(b3);
1294 rfh_observer.push_back(&b3_observer);
1295 ASSERT_THAT(rfh_observer, Each(Not(Deleted())));
1296 EXPECT_THAT(Elements({a1, b2}), Each(InBackForwardCache()));
1297 EXPECT_THAT(b3, Not(InBackForwardCache()));
1298
1299 // 3) Navigate to a4.
1300 EXPECT_TRUE(NavigateToURL(shell(), url_a));
1301 RenderFrameHostImpl* a4 = current_frame_host();
1302 RenderFrameDeletedObserver a4_observer(a4);
1303 rfh_observer.push_back(&a4_observer);
1304 ASSERT_THAT(rfh_observer, Each(Not(Deleted())));
1305
1306 // 4) Navigate to b5
1307 EXPECT_TRUE(NavigateToURL(shell(), url_b));
1308 RenderFrameHostImpl* b5 = current_frame_host();
1309 RenderFrameDeletedObserver b5_observer(b5);
1310 rfh_observer.push_back(&b5_observer);
1311 ASSERT_THAT(rfh_observer, Each(Not(Deleted())));
1312 EXPECT_THAT(Elements({a1, b2, b3, a4}), Each(InBackForwardCache()));
1313 EXPECT_THAT(b5, Not(InBackForwardCache()));
1314
1315 // 3) Go back to a1(b2).
1316 web_contents()->GetController().GoToOffset(-3);
1317 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
1318 EXPECT_EQ(a1, current_frame_host());
1319 ASSERT_THAT(rfh_observer, Each(Not(Deleted())));
1320 EXPECT_THAT(Elements({b3, a4, b5}), Each(InBackForwardCache()));
1321 EXPECT_THAT(Elements({a1, b2}), Each(Not(InBackForwardCache())));
1322
1323 // Even after a new IPC round trip with the renderer, b2 must still be alive.
1324 EXPECT_EQ("I am alive", EvalJs(b2, "window.alive"));
1325 EXPECT_FALSE(b2_observer.deleted());
1326 }
1327
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,NavigationsAreFullyCommitted)1328 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
1329 NavigationsAreFullyCommitted) {
1330 ASSERT_TRUE(embedded_test_server()->Start());
1331
1332 // During a navigation, the document being navigated *away from* can either be
1333 // deleted or stored into the BackForwardCache. The document being navigated
1334 // *to* can either be new or restored from the BackForwardCache.
1335 //
1336 // This test covers every combination:
1337 //
1338 // 1. Navigate to a cacheable page (()->A)
1339 // 2. Navigate to an uncacheable page (A->B)
1340 // 3. Go Back to a cached page (B->A)
1341 // 4. Navigate to a cacheable page (A->C)
1342 // 5. Go Back to a cached page (C->A)
1343 //
1344 // +-+-------+----------------+---------------+
1345 // |#|nav | curr_document | dest_document |
1346 // +-+-------+----------------+---------------|
1347 // |1|(()->A)| N/A | new |
1348 // |2|(A->B) | cached | new |
1349 // |3|(B->A) | deleted | restored |
1350 // |4|(A->C) | cached | new |
1351 // |5|(C->A) | cached | restored |
1352 // +-+-------+----------------+---------------+
1353 //
1354 // As part of these navigations we check that LastCommittedURL was updated,
1355 // to verify that the frame wasn't simply swapped in without actually
1356 // committing.
1357
1358 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
1359 GURL url_b(embedded_test_server()->GetURL(
1360 "b.com", "/back_forward_cache/page_with_dedicated_worker.html"));
1361 GURL url_c(embedded_test_server()->GetURL("c.com", "/title1.html"));
1362
1363 // 1. Navigate to a cacheable page (A).
1364 EXPECT_TRUE(NavigateToURL(shell(), url_a));
1365 RenderFrameHostImpl* rfh_a = current_frame_host();
1366 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
1367
1368 // 2. Navigate from a cacheable page to an uncacheable page (A->B).
1369 EXPECT_TRUE(NavigateToURL(shell(), url_b));
1370 EXPECT_EQ(web_contents()->GetLastCommittedURL(), url_b);
1371 RenderFrameHostImpl* rfh_b = current_frame_host();
1372 RenderFrameDeletedObserver delete_observer_rfh_b(rfh_b);
1373
1374 // Page A should be in the cache.
1375 EXPECT_FALSE(delete_observer_rfh_a.deleted());
1376 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
1377
1378 // 3. Navigate from an uncacheable to a cached page page (B->A).
1379 web_contents()->GetController().GoBack();
1380 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
1381 EXPECT_EQ(web_contents()->GetLastCommittedURL(), url_a);
1382
1383 // Page B should be deleted (not cached).
1384 delete_observer_rfh_b.WaitUntilDeleted();
1385
1386 ExpectOutcome(BackForwardCacheMetrics::HistoryNavigationOutcome::kRestored,
1387 FROM_HERE);
1388
1389 // 4. Navigate from a cacheable page to a cacheable page (A->C).
1390 EXPECT_TRUE(NavigateToURL(shell(), url_c));
1391 EXPECT_EQ(web_contents()->GetLastCommittedURL(), url_c);
1392 RenderFrameHostImpl* rfh_c = current_frame_host();
1393 RenderFrameDeletedObserver delete_observer_rfh_c(rfh_c);
1394
1395 // Page A should be in the cache.
1396 EXPECT_FALSE(delete_observer_rfh_a.deleted());
1397 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
1398
1399 // 5. Navigate from a cacheable page to a cached page (C->A).
1400 web_contents()->GetController().GoBack();
1401 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
1402 EXPECT_EQ(web_contents()->GetLastCommittedURL(), url_a);
1403
1404 // Page C should be in the cache.
1405 EXPECT_FALSE(delete_observer_rfh_c.deleted());
1406 EXPECT_TRUE(rfh_c->IsInBackForwardCache());
1407
1408 ExpectOutcome(BackForwardCacheMetrics::HistoryNavigationOutcome::kRestored,
1409 FROM_HERE);
1410 }
1411
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,ProxiesAreStoredAndRestored)1412 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
1413 ProxiesAreStoredAndRestored) {
1414 // This test makes assumption about where iframe processes live.
1415 if (!AreAllSitesIsolatedForTesting())
1416 return;
1417
1418 ASSERT_TRUE(embedded_test_server()->Start());
1419
1420 // During a navigation, the document being navigated *away from* can either be
1421 // deleted or stored into the BackForwardCache. The document being navigated
1422 // *to* can either be new or restored from the BackForwardCache.
1423 //
1424 // This test covers every combination:
1425 //
1426 // 1. Navigate to a cacheable page (()->A)
1427 // 2. Navigate to an uncacheable page (A->B)
1428 // 3. Go Back to a cached page (B->A)
1429 // 4. Navigate to a cacheable page (A->C)
1430 // 5. Go Back to a cached page (C->A)
1431 //
1432 // +-+-------+----------------+---------------+
1433 // |#|nav | curr_document | dest_document |
1434 // +-+-------+----------------+---------------|
1435 // |1|(()->A)| N/A | new |
1436 // |2|(A->B) | cached | new |
1437 // |3|(B->A) | deleted | restored |
1438 // |4|(A->C) | cached | new |
1439 // |5|(C->A) | cached | restored |
1440 // +-+-------+----------------+---------------+
1441 //
1442 // We use pages with cross process iframes to verify that proxy storage and
1443 // retrieval works well in every possible combination.
1444
1445 GURL url_a(embedded_test_server()->GetURL(
1446 "a.com", "/cross_site_iframe_factory.html?a(i,j)"));
1447 GURL url_b(embedded_test_server()->GetURL(
1448 "b.com", "/back_forward_cache/page_with_dedicated_worker.html"));
1449 GURL url_c(embedded_test_server()->GetURL(
1450 "c.com", "/cross_site_iframe_factory.html?c(k,l,m)"));
1451
1452 NavigationControllerImpl& controller = web_contents()->GetController();
1453 BackForwardCacheImpl& cache = controller.GetBackForwardCache();
1454
1455 // 1. Navigate to a cacheable page (A).
1456 EXPECT_TRUE(NavigateToURL(shell(), url_a));
1457 EXPECT_EQ(2u, render_frame_host_manager()->GetProxyCount());
1458 RenderFrameHostImpl* rfh_a = current_frame_host();
1459 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
1460 std::string frame_tree_a = DepictFrameTree(rfh_a->frame_tree_node());
1461
1462 // 2. Navigate from a cacheable page to an uncacheable page (A->B).
1463 EXPECT_TRUE(NavigateToURL(shell(), url_b));
1464 EXPECT_EQ(0u, render_frame_host_manager()->GetProxyCount());
1465 RenderFrameHostImpl* rfh_b = current_frame_host();
1466 RenderFrameDeletedObserver delete_observer_rfh_b(rfh_b);
1467
1468 // Page A should be in the cache.
1469 EXPECT_FALSE(delete_observer_rfh_a.deleted());
1470 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
1471
1472 // Verify proxies are stored as well.
1473 auto* cached_entry = cache.GetEntry(rfh_a->nav_entry_id());
1474 EXPECT_EQ(2u, cached_entry->proxy_hosts.size());
1475
1476 // 3. Navigate from an uncacheable to a cached page page (B->A).
1477 web_contents()->GetController().GoBack();
1478 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
1479 // Note: We still have a transition proxy that will be used to perform the
1480 // frame swap. It gets deleted with rfh_b below.
1481 EXPECT_EQ(3u, render_frame_host_manager()->GetProxyCount());
1482
1483 // Page B should be deleted (not cached).
1484 delete_observer_rfh_b.WaitUntilDeleted();
1485 EXPECT_EQ(2u, render_frame_host_manager()->GetProxyCount());
1486
1487 // Page A should still have the correct frame tree.
1488 EXPECT_EQ(frame_tree_a,
1489 DepictFrameTree(current_frame_host()->frame_tree_node()));
1490
1491 // 4. Navigate from a cacheable page to a cacheable page (A->C).
1492 EXPECT_TRUE(NavigateToURL(shell(), url_c));
1493 EXPECT_EQ(3u, render_frame_host_manager()->GetProxyCount());
1494 RenderFrameHostImpl* rfh_c = current_frame_host();
1495 RenderFrameDeletedObserver delete_observer_rfh_c(rfh_c);
1496
1497 // Page A should be in the cache.
1498 EXPECT_FALSE(delete_observer_rfh_a.deleted());
1499 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
1500
1501 // Verify proxies are stored as well.
1502 cached_entry = cache.GetEntry(rfh_a->nav_entry_id());
1503 EXPECT_EQ(2u, cached_entry->proxy_hosts.size());
1504
1505 // 5. Navigate from a cacheable page to a cached page (C->A).
1506 web_contents()->GetController().GoBack();
1507 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
1508 EXPECT_EQ(2u, render_frame_host_manager()->GetProxyCount());
1509
1510 // Page A should still have the correct frame tree.
1511 EXPECT_EQ(frame_tree_a,
1512 DepictFrameTree(current_frame_host()->frame_tree_node()));
1513
1514 // Page C should be in the cache.
1515 EXPECT_FALSE(delete_observer_rfh_c.deleted());
1516 EXPECT_TRUE(rfh_c->IsInBackForwardCache());
1517
1518 // Verify proxies are stored as well.
1519 cached_entry = cache.GetEntry(rfh_c->nav_entry_id());
1520 EXPECT_EQ(3u, cached_entry->proxy_hosts.size());
1521 }
1522
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,RestoredProxiesAreFunctional)1523 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
1524 RestoredProxiesAreFunctional) {
1525 // This test makes assumption about where iframe processes live.
1526 if (!AreAllSitesIsolatedForTesting())
1527 return;
1528
1529 ASSERT_TRUE(embedded_test_server()->Start());
1530
1531 // Page A is cacheable, while page B is not.
1532 GURL url_a(embedded_test_server()->GetURL(
1533 "a.com", "/cross_site_iframe_factory.html?a(z)"));
1534 GURL url_b(embedded_test_server()->GetURL(
1535 "b.com", "/back_forward_cache/page_with_dedicated_worker.html"));
1536 GURL test_url(embedded_test_server()->GetURL("c.com", "/title1.html"));
1537
1538 NavigationControllerImpl& controller = web_contents()->GetController();
1539
1540 // 1. Navigate to a cacheable page (A).
1541 EXPECT_TRUE(NavigateToURL(shell(), url_a));
1542 RenderFrameHostImpl* rfh_a = current_frame_host();
1543
1544 // 2. Navigate from a cacheable page to an uncacheable page (A->B).
1545 EXPECT_TRUE(NavigateToURL(shell(), url_b));
1546
1547 // 3. Navigate from an uncacheable to a cached page page (B->A).
1548 // This restores the top frame's proxy in the z.com (iframe's) process.
1549 web_contents()->GetController().GoBack();
1550 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
1551
1552 // 4. Verify that the main frame's z.com proxy is still functional.
1553 RenderFrameHostImpl* iframe =
1554 rfh_a->frame_tree_node()->child_at(0)->current_frame_host();
1555 EXPECT_TRUE(ExecJs(iframe, "top.location.href = '" + test_url.spec() + "';"));
1556 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
1557
1558 // We expect to have navigated through the proxy.
1559 EXPECT_EQ(test_url, controller.GetLastCommittedEntry()->GetURL());
1560 }
1561
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,PageWithDedicatedWorkerNotCached)1562 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
1563 PageWithDedicatedWorkerNotCached) {
1564 ASSERT_TRUE(embedded_test_server()->Start());
1565
1566 EXPECT_TRUE(NavigateToURL(
1567 shell(),
1568 embedded_test_server()->GetURL(
1569 "a.com", "/back_forward_cache/page_with_dedicated_worker.html")));
1570 RenderFrameDeletedObserver delete_observer_rfh_a(current_frame_host());
1571
1572 // Navigate away.
1573 EXPECT_TRUE(NavigateToURL(
1574 shell(), embedded_test_server()->GetURL("b.com", "/title1.html")));
1575
1576 // The page with the unsupported feature should be deleted (not cached).
1577 delete_observer_rfh_a.WaitUntilDeleted();
1578 }
1579
1580 // TODO(https://crbug.com/154571): Shared workers are not available on Android.
1581 #if defined(OS_ANDROID)
1582 #define MAYBE_PageWithSharedWorkerNotCached \
1583 DISABLED_PageWithSharedWorkerNotCached
1584 #else
1585 #define MAYBE_PageWithSharedWorkerNotCached PageWithSharedWorkerNotCached
1586 #endif
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,MAYBE_PageWithSharedWorkerNotCached)1587 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
1588 MAYBE_PageWithSharedWorkerNotCached) {
1589 ASSERT_TRUE(embedded_test_server()->Start());
1590
1591 EXPECT_TRUE(NavigateToURL(
1592 shell(),
1593 embedded_test_server()->GetURL(
1594 "a.com", "/back_forward_cache/page_with_shared_worker.html")));
1595 RenderFrameDeletedObserver delete_observer_rfh_a(current_frame_host());
1596
1597 // Navigate away.
1598 EXPECT_TRUE(NavigateToURL(
1599 shell(), embedded_test_server()->GetURL("b.com", "/title1.html")));
1600
1601 // The page with the unsupported feature should be deleted (not cached).
1602 delete_observer_rfh_a.WaitUntilDeleted();
1603
1604 // Go back.
1605 web_contents()->GetController().GoBack();
1606 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
1607 ExpectNotRestored(
1608 {BackForwardCacheMetrics::NotRestoredReason::kBlocklistedFeatures},
1609 FROM_HERE);
1610 ExpectBlocklistedFeature(
1611 blink::scheduler::WebSchedulerTrackedFeature::kSharedWorker, FROM_HERE);
1612 }
1613
1614 #if defined(OS_MAC) || defined(OS_LINUX) || defined(OS_CHROMEOS)
1615 // Flaky: https://crbug.com/1076594 on Mac
1616 // Flaky: https://crbug.com/1102571 on Linux Ozone
1617 #define MAYBE_SubframeWithDisallowedFeatureNotCached \
1618 DISABLED_SubframeWithDisallowedFeatureNotCached
1619 #else
1620 #define MAYBE_SubframeWithDisallowedFeatureNotCached \
1621 SubframeWithDisallowedFeatureNotCached
1622 #endif
1623
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,MAYBE_SubframeWithDisallowedFeatureNotCached)1624 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
1625 MAYBE_SubframeWithDisallowedFeatureNotCached) {
1626 ASSERT_TRUE(embedded_test_server()->Start());
1627
1628 // Navigate to a page with an iframe that contains a dedicated worker.
1629 EXPECT_TRUE(NavigateToURL(
1630 shell(),
1631 embedded_test_server()->GetURL(
1632 "a.com", "/back_forward_cache/dedicated_worker_in_subframe.html")));
1633 RenderFrameDeletedObserver delete_rfh_a(current_frame_host());
1634
1635 // Navigate away.
1636 EXPECT_TRUE(NavigateToURL(
1637 shell(), embedded_test_server()->GetURL("b.com", "/title1.html")));
1638
1639 // The page with the unsupported feature should be deleted (not cached).
1640 delete_rfh_a.WaitUntilDeleted();
1641
1642 // Go back.
1643 web_contents()->GetController().GoBack();
1644 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
1645 ExpectNotRestored(
1646 {BackForwardCacheMetrics::NotRestoredReason::kBlocklistedFeatures},
1647 FROM_HERE);
1648 ExpectBlocklistedFeature(
1649 blink::scheduler::WebSchedulerTrackedFeature::kDedicatedWorkerOrWorklet,
1650 FROM_HERE);
1651 }
1652
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,SubframeWithOngoingNavigationNotCached)1653 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
1654 SubframeWithOngoingNavigationNotCached) {
1655 net::test_server::ControllableHttpResponse response(embedded_test_server(),
1656 "/hung");
1657 ASSERT_TRUE(embedded_test_server()->Start());
1658
1659 // Navigate to a page with an iframe.
1660 TestNavigationObserver navigation_observer1(web_contents());
1661 GURL main_url(embedded_test_server()->GetURL(
1662 "a.com", "/back_forward_cache/page_with_hung_iframe.html"));
1663 shell()->LoadURL(main_url);
1664 navigation_observer1.WaitForNavigationFinished();
1665
1666 RenderFrameHostImpl* main_frame = current_frame_host();
1667 RenderFrameDeletedObserver frame_deleted_observer(main_frame);
1668 response.WaitForRequest();
1669
1670 // Navigate away.
1671 TestNavigationObserver navigation_observer2(web_contents());
1672 shell()->LoadURL(embedded_test_server()->GetURL("b.com", "/title1.html"));
1673 navigation_observer2.WaitForNavigationFinished();
1674
1675 // The page with the unsupported feature should be deleted (not cached).
1676 frame_deleted_observer.WaitUntilDeleted();
1677 }
1678
1679 // Check that unload event handlers are not dispatched when the page goes
1680 // into BackForwardCache.
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,ConfirmUnloadEventNotFired)1681 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
1682 ConfirmUnloadEventNotFired) {
1683 ASSERT_TRUE(embedded_test_server()->Start());
1684 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
1685 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
1686
1687 // 1) Navigate to A.
1688 EXPECT_TRUE(NavigateToURL(shell(), url_a));
1689 RenderFrameHostImpl* rfh_a = current_frame_host();
1690 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
1691
1692 // 2) Set unload handler and check the title.
1693 EXPECT_TRUE(ExecJs(rfh_a,
1694 "document.title = 'loaded!';"
1695 "window.addEventListener('unload', () => {"
1696 " document.title = 'unloaded!';"
1697 "});"));
1698 {
1699 base::string16 title_when_loaded = base::UTF8ToUTF16("loaded!");
1700 TitleWatcher title_watcher(web_contents(), title_when_loaded);
1701 EXPECT_EQ(title_watcher.WaitAndGetTitle(), title_when_loaded);
1702 }
1703
1704 // 3) Navigate to B.
1705 EXPECT_TRUE(NavigateToURL(shell(), url_b));
1706 RenderFrameHostImpl* rfh_b = current_frame_host();
1707 RenderFrameDeletedObserver delete_observer_rfh_b(rfh_b);
1708 EXPECT_FALSE(delete_observer_rfh_a.deleted());
1709 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
1710 EXPECT_FALSE(rfh_b->IsInBackForwardCache());
1711
1712 // 4) Go back to A and check the title again.
1713 web_contents()->GetController().GoBack();
1714 EXPECT_TRUE(WaitForLoadStop(web_contents()));
1715 EXPECT_FALSE(delete_observer_rfh_a.deleted());
1716 EXPECT_FALSE(delete_observer_rfh_b.deleted());
1717 EXPECT_EQ(rfh_a, current_frame_host());
1718 EXPECT_TRUE(rfh_b->IsInBackForwardCache());
1719 {
1720 base::string16 title_when_loaded = base::UTF8ToUTF16("loaded!");
1721 TitleWatcher title_watcher(web_contents(), title_when_loaded);
1722 EXPECT_EQ(title_watcher.WaitAndGetTitle(), title_when_loaded);
1723 }
1724 }
1725
1726 // Flaky on Linux: https://crbug.com/1054194
1727 #if defined(OS_LINUX) || defined(OS_CHROMEOS)
1728 #define MAYBE_DoesNotCacheIfRecordingAudio DISABLED_DoesNotCacheIfRecordingAudio
1729 #else
1730 #define MAYBE_DoesNotCacheIfRecordingAudio DoesNotCacheIfRecordingAudio
1731 #endif
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,MAYBE_DoesNotCacheIfRecordingAudio)1732 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
1733 MAYBE_DoesNotCacheIfRecordingAudio) {
1734 ASSERT_TRUE(embedded_test_server()->Start());
1735
1736 BackForwardCacheDisabledTester tester;
1737
1738 // Navigate to an empty page.
1739 GURL url(embedded_test_server()->GetURL("/title1.html"));
1740 EXPECT_TRUE(NavigateToURL(shell(), url));
1741 int process_id = current_frame_host()->GetProcess()->GetID();
1742 int routing_id = current_frame_host()->GetRoutingID();
1743
1744 // Request for audio recording.
1745 EXPECT_EQ("success", EvalJs(current_frame_host(), R"(
1746 new Promise(resolve => {
1747 navigator.mediaDevices.getUserMedia({audio: true})
1748 .then(m => { resolve("success"); })
1749 .catch(() => { resolve("error"); });
1750 });
1751 )"));
1752
1753 RenderFrameDeletedObserver deleted(current_frame_host());
1754
1755 // 2) Navigate away.
1756 shell()->LoadURL(embedded_test_server()->GetURL("b.com", "/title1.html"));
1757
1758 // The page was still recording audio when we navigated away, so it shouldn't
1759 // have been cached.
1760 deleted.WaitUntilDeleted();
1761
1762 // 3) Go back. Note that the reason for kWasGrantedMediaAccess occurs after
1763 // MediaDevicesDispatcherHost is called, hence, both are reasons for the page
1764 // not being restored.
1765 web_contents()->GetController().GoBack();
1766 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
1767 ExpectNotRestored(
1768 {BackForwardCacheMetrics::NotRestoredReason::kWasGrantedMediaAccess,
1769 BackForwardCacheMetrics::NotRestoredReason::
1770 kDisableForRenderFrameHostCalled},
1771 FROM_HERE);
1772 EXPECT_TRUE(tester.IsDisabledForFrameWithReason(
1773 process_id, routing_id, "MediaDevicesDispatcherHost"));
1774 }
1775
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,DoesNotCacheIfSubframeRecordingAudio)1776 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
1777 DoesNotCacheIfSubframeRecordingAudio) {
1778 ASSERT_TRUE(embedded_test_server()->Start());
1779
1780 BackForwardCacheDisabledTester tester;
1781
1782 // Navigate to a page with an iframe.
1783 GURL url(embedded_test_server()->GetURL("/page_with_iframe.html"));
1784 EXPECT_TRUE(NavigateToURL(shell(), url));
1785 RenderFrameHostImpl* rfh = current_frame_host();
1786 int process_id =
1787 rfh->child_at(0)->current_frame_host()->GetProcess()->GetID();
1788 int routing_id = rfh->child_at(0)->current_frame_host()->GetRoutingID();
1789
1790 // Request for audio recording from the subframe.
1791 EXPECT_EQ("success", EvalJs(rfh->child_at(0)->current_frame_host(), R"(
1792 new Promise(resolve => {
1793 navigator.mediaDevices.getUserMedia({audio: true})
1794 .then(m => { resolve("success"); })
1795 .catch(() => { resolve("error"); });
1796 });
1797 )"));
1798
1799 RenderFrameDeletedObserver deleted(current_frame_host());
1800
1801 // 2) Navigate away.
1802 shell()->LoadURL(embedded_test_server()->GetURL("b.com", "/title1.html"));
1803
1804 // The page was still recording audio when we navigated away, so it shouldn't
1805 // have been cached.
1806 deleted.WaitUntilDeleted();
1807
1808 // 3) Go back. Note that the reason for kWasGrantedMediaAccess occurs after
1809 // MediaDevicesDispatcherHost is called, hence, both are reasons for the page
1810 // not being restored.
1811 web_contents()->GetController().GoBack();
1812 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
1813 ExpectNotRestored(
1814 {BackForwardCacheMetrics::NotRestoredReason::kWasGrantedMediaAccess,
1815 BackForwardCacheMetrics::NotRestoredReason::
1816 kDisableForRenderFrameHostCalled},
1817 FROM_HERE);
1818 EXPECT_TRUE(tester.IsDisabledForFrameWithReason(
1819 process_id, routing_id, "MediaDevicesDispatcherHost"));
1820 }
1821
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,DoesNotCacheIfMediaDeviceSubscribed)1822 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
1823 DoesNotCacheIfMediaDeviceSubscribed) {
1824 ASSERT_TRUE(embedded_test_server()->Start());
1825
1826 BackForwardCacheDisabledTester tester;
1827
1828 // Navigate to a page with an iframe.
1829 GURL url(embedded_test_server()->GetURL("/page_with_iframe.html"));
1830 EXPECT_TRUE(NavigateToURL(shell(), url));
1831 RenderFrameHostImpl* rfh = current_frame_host();
1832 int process_id =
1833 rfh->child_at(0)->current_frame_host()->GetProcess()->GetID();
1834 int routing_id = rfh->child_at(0)->current_frame_host()->GetRoutingID();
1835
1836 EXPECT_EQ("success", EvalJs(rfh->child_at(0)->current_frame_host(), R"(
1837 new Promise(resolve => {
1838 navigator.mediaDevices.addEventListener('devicechange', function(event){});
1839 resolve("success");
1840 });
1841 )"));
1842
1843 RenderFrameDeletedObserver deleted(current_frame_host());
1844
1845 // 2) Navigate away.
1846 shell()->LoadURL(embedded_test_server()->GetURL("b.com", "/title1.html"));
1847
1848 // The page was subscribed to media devices when we navigated away, so it
1849 // shouldn't have been cached.
1850 deleted.WaitUntilDeleted();
1851
1852 // 3) Go back.
1853 web_contents()->GetController().GoBack();
1854 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
1855 ExpectNotRestored({BackForwardCacheMetrics::NotRestoredReason::
1856 kDisableForRenderFrameHostCalled},
1857 FROM_HERE);
1858 EXPECT_TRUE(tester.IsDisabledForFrameWithReason(
1859 process_id, routing_id, "MediaDevicesDispatcherHost"));
1860 }
1861
1862 // TODO(https://crbug.com/1075936) disabled due to flakiness
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,DISABLED_DoesNotCacheIfMainFrameStillLoading)1863 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
1864 DISABLED_DoesNotCacheIfMainFrameStillLoading) {
1865 net::test_server::ControllableHttpResponse response(embedded_test_server(),
1866 "/main_document");
1867 ASSERT_TRUE(embedded_test_server()->Start());
1868
1869 // 1) Navigate to a page that doesn't finish loading.
1870 GURL url(embedded_test_server()->GetURL("a.com", "/main_document"));
1871 TestNavigationManager navigation_manager(shell()->web_contents(), url);
1872 shell()->LoadURL(url);
1873
1874 // The navigation starts.
1875 EXPECT_TRUE(navigation_manager.WaitForRequestStart());
1876 navigation_manager.ResumeNavigation();
1877
1878 // The server sends the first part of the response and waits.
1879 response.WaitForRequest();
1880 response.Send(
1881 "HTTP/1.1 200 OK\r\n"
1882 "Content-Type: text/html; charset=utf-8\r\n"
1883 "\r\n"
1884 "<html><body> ... ");
1885
1886 // The navigation finishes while the body is still loading.
1887 navigation_manager.WaitForNavigationFinished();
1888 RenderFrameDeletedObserver delete_observer_rfh_a(current_frame_host());
1889
1890 // 2) Navigate away.
1891 shell()->LoadURL(embedded_test_server()->GetURL("b.com", "/title1.html"));
1892
1893 // The page was still loading when we navigated away, so it shouldn't have
1894 // been cached.
1895 delete_observer_rfh_a.WaitUntilDeleted();
1896
1897 // 3) Go back.
1898 web_contents()->GetController().GoBack();
1899 EXPECT_FALSE(WaitForLoadStop(shell()->web_contents()));
1900 ExpectNotRestored({BackForwardCacheMetrics::NotRestoredReason::kLoading},
1901 FROM_HERE);
1902 }
1903
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,DoesNotCacheIfImageStillLoading)1904 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
1905 DoesNotCacheIfImageStillLoading) {
1906 ASSERT_TRUE(embedded_test_server()->Start());
1907
1908 // 1) Navigate to a page with an image that loads forever.
1909 GURL url(embedded_test_server()->GetURL("a.com",
1910 "/infinitely_loading_image.html"));
1911 TestNavigationManager navigation_manager(shell()->web_contents(), url);
1912 shell()->LoadURL(url);
1913
1914 // The navigation finishes while the image is still loading.
1915 navigation_manager.WaitForNavigationFinished();
1916 // Wait for the document to load DOM to ensure that kLoading is not
1917 // one of the reasons why the document wasn't cached.
1918 WaitForDOMContentLoaded(current_frame_host());
1919
1920 RenderFrameDeletedObserver delete_observer_rfh_a(current_frame_host());
1921
1922 // 2) Navigate away.
1923 shell()->LoadURL(embedded_test_server()->GetURL("b.com", "/title1.html"));
1924
1925 // The page was still loading when we navigated away, so it shouldn't have
1926 // been cached.
1927 delete_observer_rfh_a.WaitUntilDeleted();
1928
1929 // 3) Go back.
1930 TestNavigationManager navigation_manager_back(shell()->web_contents(), url);
1931 web_contents()->GetController().GoBack();
1932 navigation_manager_back.WaitForNavigationFinished();
1933 ExpectNotRestored(
1934 {BackForwardCacheMetrics::NotRestoredReason::kBlocklistedFeatures},
1935 FROM_HERE);
1936 ExpectBlocklistedFeature(blink::scheduler::WebSchedulerTrackedFeature::
1937 kOutstandingNetworkRequestOthers,
1938 FROM_HERE);
1939 }
1940
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,DoesNotCacheLoadingSubframe)1941 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
1942 DoesNotCacheLoadingSubframe) {
1943 net::test_server::ControllableHttpResponse response(embedded_test_server(),
1944 "/controlled");
1945 ASSERT_TRUE(embedded_test_server()->Start());
1946
1947 // 1) Navigate to a page with an iframe that loads forever.
1948 GURL url(embedded_test_server()->GetURL(
1949 "a.com", "/back_forward_cache/controllable_subframe.html"));
1950 TestNavigationManager navigation_manager(shell()->web_contents(), url);
1951 shell()->LoadURL(url);
1952
1953 // The navigation finishes while the iframe is still loading.
1954 navigation_manager.WaitForNavigationFinished();
1955
1956 // Wait for the iframe request to arrive, and leave it hanging with no
1957 // response.
1958 response.WaitForRequest();
1959
1960 RenderFrameHostImpl* rfh_a = current_frame_host();
1961 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
1962
1963 // 2) Navigate away.
1964 shell()->LoadURL(embedded_test_server()->GetURL("b.com", "/title1.html"));
1965 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
1966
1967 // The page should not have been added to cache, since it had a subframe that
1968 // was still loading at the time it was navigated away from.
1969 delete_observer_rfh_a.WaitUntilDeleted();
1970
1971 // 3) Go back.
1972 web_contents()->GetController().GoBack();
1973 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
1974 ExpectNotRestored(
1975 {
1976 BackForwardCacheMetrics::NotRestoredReason::kLoading,
1977 BackForwardCacheMetrics::NotRestoredReason::kSubframeIsNavigating,
1978 },
1979 FROM_HERE);
1980 }
1981
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,DoesNotCacheLoadingSubframeOfSubframe)1982 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
1983 DoesNotCacheLoadingSubframeOfSubframe) {
1984 net::test_server::ControllableHttpResponse response(embedded_test_server(),
1985 "/controlled");
1986 ASSERT_TRUE(embedded_test_server()->Start());
1987
1988 // 1) Navigate to a page with an iframe that contains yet another iframe, that
1989 // hangs while loading.
1990 GURL url(embedded_test_server()->GetURL(
1991 "a.com", "/back_forward_cache/controllable_subframe_of_subframe.html"));
1992 TestNavigationManager navigation_manager(shell()->web_contents(), url);
1993 shell()->LoadURL(url);
1994
1995 // The navigation finishes while the iframe within an iframe is still loading.
1996 navigation_manager.WaitForNavigationFinished();
1997
1998 // Wait for the innermost iframe request to arrive, and leave it hanging with
1999 // no response.
2000 response.WaitForRequest();
2001
2002 RenderFrameHostImpl* rfh_a = current_frame_host();
2003 RenderFrameDeletedObserver delete_rfh_a(rfh_a);
2004
2005 // 2) Navigate away.
2006 shell()->LoadURL(embedded_test_server()->GetURL("b.com", "/title1.html"));
2007 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
2008
2009 // The page should not have been added to the cache, since it had an iframe
2010 // that was still loading at the time it was navigated away from.
2011 delete_rfh_a.WaitUntilDeleted();
2012
2013 // 3) Go back.
2014 web_contents()->GetController().GoBack();
2015 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
2016 ExpectNotRestored(
2017 {
2018 BackForwardCacheMetrics::NotRestoredReason::kLoading,
2019 BackForwardCacheMetrics::NotRestoredReason::kSubframeIsNavigating,
2020 },
2021 FROM_HERE);
2022 }
2023
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,CacheIfWebGL)2024 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, CacheIfWebGL) {
2025 ASSERT_TRUE(embedded_test_server()->Start());
2026
2027 // 1) Navigate to a page with WebGL usage
2028 GURL url(embedded_test_server()->GetURL(
2029 "example.com", "/back_forward_cache/page_with_webgl.html"));
2030 EXPECT_TRUE(NavigateToURL(shell(), url));
2031
2032 // 2) Navigate away.
2033 EXPECT_TRUE(NavigateToURL(
2034 shell(), embedded_test_server()->GetURL("b.com", "/title1.html")));
2035
2036 // The page had an active WebGL context when we navigated away,
2037 // but it should be cached.
2038
2039 // 3) Go back.
2040 web_contents()->GetController().GoBack();
2041 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
2042 ExpectOutcome(BackForwardCacheMetrics::HistoryNavigationOutcome::kRestored,
2043 FROM_HERE);
2044 }
2045
2046 // Since blink::mojom::HidService binder is not added in
2047 // content/browser/browser_interface_binders.cc for Android, this test is not
2048 // applicable for this OS.
2049 #if !defined(OS_ANDROID)
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,DoesNotCacheIfWebHID)2050 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, DoesNotCacheIfWebHID) {
2051 ASSERT_TRUE(embedded_test_server()->Start());
2052
2053 // 1) Navigate to an empty page.
2054 GURL url(embedded_test_server()->GetURL("/title1.html"));
2055 EXPECT_TRUE(NavigateToURL(shell(), url));
2056
2057 // Request for HID devices.
2058 EXPECT_EQ("success", EvalJs(current_frame_host(), R"(
2059 new Promise(resolve => {
2060 navigator.hid.getDevices()
2061 .then(m => { resolve("success"); })
2062 .catch(() => { resolve("error"); });
2063 });
2064 )"));
2065
2066 RenderFrameDeletedObserver deleted(current_frame_host());
2067
2068 // 2) Navigate away.
2069 shell()->LoadURL(embedded_test_server()->GetURL("b.com", "/title1.html"));
2070
2071 // The page uses WebHID so it should be deleted.
2072 deleted.WaitUntilDeleted();
2073
2074 // 3) Go back.
2075 web_contents()->GetController().GoBack();
2076 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
2077 ExpectNotRestored(
2078 {BackForwardCacheMetrics::NotRestoredReason::kBlocklistedFeatures},
2079 FROM_HERE);
2080 ExpectBlocklistedFeature(
2081 blink::scheduler::WebSchedulerTrackedFeature::kWebHID, FROM_HERE);
2082 }
2083 #endif // !defined(OS_ANDROID)
2084
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,DoesNotCacheIfAcquiredWakeLock)2085 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
2086 DoesNotCacheIfAcquiredWakeLock) {
2087 ASSERT_TRUE(CreateHttpsServer()->Start());
2088
2089 // 1) Navigate to a page with WakeLock usage.
2090 GURL url(https_server()->GetURL("a.com", "/back_forward_cache/empty.html"));
2091 EXPECT_TRUE(NavigateToURL(shell(), url));
2092
2093 RenderFrameHostImpl* rfh_a = current_frame_host();
2094 RenderFrameDeletedObserver deleted(current_frame_host());
2095
2096 // Acquire WakeLock.
2097 EXPECT_EQ("DONE", EvalJs(rfh_a, R"(
2098 new Promise(async resolve => {
2099 try {
2100 await navigator.wakeLock.request('screen');
2101 resolve('DONE');
2102 } catch (error) {
2103 resolve('error: request failed');
2104 }
2105 });
2106 )"));
2107
2108 // 2) Navigate away.
2109 shell()->LoadURL(https_server()->GetURL("b.com", "/title1.html"));
2110
2111 // The page uses WakeLock so it should be deleted.
2112 deleted.WaitUntilDeleted();
2113
2114 // 3) Go back to the page with WakeLock.
2115 web_contents()->GetController().GoBack();
2116 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
2117 ExpectNotRestored(
2118 {BackForwardCacheMetrics::NotRestoredReason::kBlocklistedFeatures},
2119 FROM_HERE);
2120 ExpectBlocklistedFeature(
2121 blink::scheduler::WebSchedulerTrackedFeature::kWakeLock, FROM_HERE);
2122 }
2123
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,CacheIfReleasedWakeLock)2124 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, CacheIfReleasedWakeLock) {
2125 ASSERT_TRUE(CreateHttpsServer()->Start());
2126
2127 // 1) Navigate to a page with WakeLock usage.
2128 GURL url(https_server()->GetURL("a.com", "/back_forward_cache/empty.html"));
2129 EXPECT_TRUE(NavigateToURL(shell(), url));
2130 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
2131 RenderFrameHostImpl* rfh_a = current_frame_host();
2132 // Acquire and release WakeLock.
2133 EXPECT_EQ("DONE", EvalJs(rfh_a, R"(
2134 new Promise(async resolve => {
2135 try {
2136 const lock = await navigator.wakeLock.request('screen');
2137 await lock.release();
2138 resolve('DONE');
2139 } catch (error) {
2140 resolve('error: request failed');
2141 }
2142 });
2143 )"));
2144
2145 // 2) Navigate away.
2146 shell()->LoadURL(https_server()->GetURL("b.com", "/title1.html"));
2147 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
2148 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
2149
2150 // 3) Go back to the page with WakeLock.
2151 web_contents()->GetController().GoBack();
2152 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
2153 EXPECT_EQ(current_frame_host(), rfh_a);
2154
2155 // This time the page is restored from cache because WakeLock is released.
2156 ExpectOutcome(BackForwardCacheMetrics::HistoryNavigationOutcome::kRestored,
2157 FROM_HERE);
2158 }
2159
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,DoesNotCacheIfAnyWakeLockHeld)2160 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
2161 DoesNotCacheIfAnyWakeLockHeld) {
2162 ASSERT_TRUE(CreateHttpsServer()->Start());
2163
2164 // 1) Navigate to a page with WakeLock usage.
2165 GURL url(https_server()->GetURL("/back_forward_cache/empty.html"));
2166 EXPECT_TRUE(NavigateToURL(shell(), url));
2167 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
2168 RenderFrameHostImpl* rfh_a = current_frame_host();
2169 // Acquire and release WakeLock.
2170 EXPECT_EQ("DONE", EvalJs(rfh_a, R"(
2171 new Promise(async resolve => {
2172 try {
2173 const lock1 = await navigator.wakeLock.request('screen');
2174 const lock2 = await navigator.wakeLock.request('screen');
2175 await lock1.release();
2176 resolve('DONE');
2177 } catch (error) {
2178 resolve('error: request failed');
2179 }
2180 });
2181 )"));
2182
2183 // 2) Navigate away.
2184 shell()->LoadURL(https_server()->GetURL("b.com", "/title1.html"));
2185 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
2186
2187 // 3) Go back to the page with WakeLock.
2188 web_contents()->GetController().GoBack();
2189 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
2190
2191 ExpectNotRestored(
2192 {BackForwardCacheMetrics::NotRestoredReason::kBlocklistedFeatures},
2193 FROM_HERE);
2194 ExpectBlocklistedFeature(
2195 blink::scheduler::WebSchedulerTrackedFeature::kWakeLock, FROM_HERE);
2196 }
2197
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,DoesNotCacheIfWebFileSystem)2198 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
2199 DoesNotCacheIfWebFileSystem) {
2200 ASSERT_TRUE(embedded_test_server()->Start());
2201
2202 // 1) Navigate to a page with WebFileSystem usage.
2203 GURL url(embedded_test_server()->GetURL("/fileapi/request_test.html"));
2204 EXPECT_TRUE(NavigateToURL(shell(), url));
2205 RenderFrameHostImpl* rfh_a = current_frame_host();
2206 RenderFrameDeletedObserver deleted(rfh_a);
2207
2208 // 2) Navigate away.
2209 shell()->LoadURL(embedded_test_server()->GetURL("b.com", "/title1.html"));
2210 // The page uses WebFilesystem so it should be deleted.
2211 deleted.WaitUntilDeleted();
2212
2213 // 3) Go back to the page with WebFileSystem.
2214 web_contents()->GetController().GoBack();
2215 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
2216 ExpectNotRestored(
2217 {BackForwardCacheMetrics::NotRestoredReason::kBlocklistedFeatures},
2218 FROM_HERE);
2219 ExpectBlocklistedFeature(
2220 blink::scheduler::WebSchedulerTrackedFeature::kWebFileSystem, FROM_HERE);
2221 }
2222
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,DoesNotCacheIfHttpError)2223 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, DoesNotCacheIfHttpError) {
2224 ASSERT_TRUE(embedded_test_server()->Start());
2225
2226 GURL error_url(embedded_test_server()->GetURL("a.com", "/page404.html"));
2227 GURL url(embedded_test_server()->GetURL("b.com", "/title1.html"));
2228
2229 // Navigate to an error page.
2230 EXPECT_TRUE(NavigateToURL(shell(), error_url));
2231 EXPECT_EQ(net::HTTP_NOT_FOUND, current_frame_host()->last_http_status_code());
2232 RenderFrameDeletedObserver delete_rfh_a(current_frame_host());
2233
2234 // Navigate away.
2235 EXPECT_TRUE(NavigateToURL(shell(), url));
2236
2237 // The page did not return 200 (OK), so it shouldn't have been cached.
2238 delete_rfh_a.WaitUntilDeleted();
2239
2240 // Go back.
2241 web_contents()->GetController().GoBack();
2242 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
2243 ExpectNotRestored(
2244 {BackForwardCacheMetrics::NotRestoredReason::kHTTPStatusNotOK},
2245 FROM_HERE);
2246 }
2247
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,DoesNotCacheIdleManager)2248 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, DoesNotCacheIdleManager) {
2249 ASSERT_TRUE(embedded_test_server()->Start());
2250
2251 // 1) Navigate to a page and start using the IdleManager class.
2252 GURL url(embedded_test_server()->GetURL("/title1.html"));
2253 EXPECT_TRUE(NavigateToURL(shell(), url));
2254 RenderFrameHostImpl* rfh_a = current_frame_host();
2255 RenderFrameDeletedObserver deleted(rfh_a);
2256
2257 content::IdleManagerHelper::SetIdleTimeProviderForTest(
2258 rfh_a, std::make_unique<FakeIdleTimeProvider>());
2259
2260 EXPECT_TRUE(ExecJs(rfh_a, R"(
2261 new Promise(async resolve => {
2262 let idleDetector = new IdleDetector();
2263 idleDetector.start();
2264 resolve();
2265 });
2266 )"));
2267
2268 // 2) Navigate away.
2269 shell()->LoadURL(embedded_test_server()->GetURL("b.com", "/title1.html"));
2270
2271 // The page uses IdleManager so it should be deleted.
2272 deleted.WaitUntilDeleted();
2273
2274 // 3) Go back and make sure the IdleManager page wasn't in the cache.
2275 web_contents()->GetController().GoBack();
2276 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
2277 ExpectNotRestored(
2278 {BackForwardCacheMetrics::NotRestoredReason::kBlocklistedFeatures},
2279 FROM_HERE);
2280 ExpectBlocklistedFeature(
2281 blink::scheduler::WebSchedulerTrackedFeature::kIdleManager, FROM_HERE);
2282 }
2283
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,DoesNotCacheSMSService)2284 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, DoesNotCacheSMSService) {
2285 ASSERT_TRUE(embedded_test_server()->Start());
2286
2287 // 1) Navigate to a page and start using the SMSService.
2288 GURL url(embedded_test_server()->GetURL("/title1.html"));
2289 EXPECT_TRUE(NavigateToURL(shell(), url));
2290 RenderFrameHostImpl* rfh_a = current_frame_host();
2291 RenderFrameDeletedObserver rfh_a_deleted(rfh_a);
2292
2293 EXPECT_TRUE(ExecJs(rfh_a, R"(
2294 new Promise(async resolve => {
2295 await navigator.credentials.get({otp: {transport: ["sms"]}});
2296 resolve();
2297 });
2298 )"));
2299
2300 // 2) Navigate away.
2301 EXPECT_TRUE(NavigateToURL(
2302 shell(), embedded_test_server()->GetURL("b.com", "/title1.html")));
2303
2304 // The page uses SMSService so it should be deleted.
2305 rfh_a_deleted.WaitUntilDeleted();
2306
2307 // 3) Go back and make sure the SMSService page wasn't in the cache.
2308 web_contents()->GetController().GoBack();
2309 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
2310
2311 // Note that on certain linux tests, there is occasionally a not restored
2312 // reason of kDisableForRenderFrameHostCalled. This is due to the javascript
2313 // navigator.credentials.get, which will call on authentication code for linux
2314 // but not other operating systems. The authenticator code explicitly invokes
2315 // kDisableForRenderFrameHostCalled. This causes flakiness if we check against
2316 // all not restored reasons. As a result, we only check for the blocklist
2317 // reason.
2318 ExpectBlocklistedFeature(
2319 blink::scheduler::WebSchedulerTrackedFeature::kWebOTPService, FROM_HERE);
2320 }
2321
2322 // crbug.com/1090223
2323 #if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_MAC)
2324 #define MAYBE_DoesNotCachePaymentManager DISABLED_DoesNotCachePaymentManager
2325 #else
2326 #define MAYBE_DoesNotCachePaymentManager DoesNotCachePaymentManager
2327 #endif
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,MAYBE_DoesNotCachePaymentManager)2328 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
2329 MAYBE_DoesNotCachePaymentManager) {
2330 ASSERT_TRUE(CreateHttpsServer()->Start());
2331
2332 // 1) Navigate to a page which includes PaymentManager functionality. Note
2333 // that service workers are used, and therefore we use https server instead of
2334 // embedded_server()
2335 EXPECT_TRUE(NavigateToURL(
2336 shell(), https_server()->GetURL(
2337 "a.com", "/payments/payment_app_invocation.html")));
2338 RenderFrameHostImpl* rfh_a = current_frame_host();
2339 RenderFrameDeletedObserver rfh_a_deleted(rfh_a);
2340
2341 // Execute functionality that calls PaymentManager.
2342 EXPECT_TRUE(ExecJs(rfh_a, R"(
2343 new Promise(async resolve => {
2344 registerPaymentApp();
2345 resolve();
2346 });
2347 )"));
2348
2349 // 2) Navigate away.
2350 EXPECT_TRUE(
2351 NavigateToURL(shell(), https_server()->GetURL("b.com", "/title1.html")));
2352
2353 // The page uses PaymentManager so it should be deleted.
2354 rfh_a_deleted.WaitUntilDeleted();
2355
2356 // 3) Go back.
2357 web_contents()->GetController().GoBack();
2358 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
2359 ExpectNotRestored(
2360 {BackForwardCacheMetrics::NotRestoredReason::kBlocklistedFeatures},
2361 FROM_HERE);
2362
2363 // Note that on Mac10.10, there is occasionally blocklisting for network
2364 // requests (kOutstandingNetworkRequestOthers). This causes flakiness if we
2365 // check against all blocklisted features. As a result, we only check for the
2366 // blocklist we care about.
2367 base::HistogramBase::Sample sample = base::HistogramBase::Sample(
2368 blink::scheduler::WebSchedulerTrackedFeature::kPaymentManager);
2369 std::vector<base::Bucket> blocklist_values = histogram_tester_.GetAllSamples(
2370 "BackForwardCache.HistoryNavigationOutcome."
2371 "BlocklistedFeature");
2372 auto it = std::find_if(
2373 blocklist_values.begin(), blocklist_values.end(),
2374 [sample](const base::Bucket& bucket) { return bucket.min == sample; });
2375 EXPECT_TRUE(it != blocklist_values.end());
2376
2377 std::vector<base::Bucket> all_sites_blocklist_values =
2378 histogram_tester_.GetAllSamples(
2379 "BackForwardCache.AllSites.HistoryNavigationOutcome."
2380 "BlocklistedFeature");
2381
2382 auto all_sites_it = std::find_if(
2383 all_sites_blocklist_values.begin(), all_sites_blocklist_values.end(),
2384 [sample](const base::Bucket& bucket) { return bucket.min == sample; });
2385 EXPECT_TRUE(all_sites_it != all_sites_blocklist_values.end());
2386 }
2387
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,DoesNotCacheOnKeyboardLock)2388 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
2389 DoesNotCacheOnKeyboardLock) {
2390 ASSERT_TRUE(embedded_test_server()->Start());
2391
2392 // 1) Navigate to a page and start using the IdleManager class.
2393 GURL url(embedded_test_server()->GetURL("/title1.html"));
2394 EXPECT_TRUE(NavigateToURL(shell(), url));
2395 RenderFrameHostImpl* rfh_a = current_frame_host();
2396 RenderFrameDeletedObserver rfh_a_deleted(rfh_a);
2397
2398 EXPECT_TRUE(ExecJs(rfh_a, R"(
2399 new Promise(resolve => {
2400 navigator.keyboard.lock();
2401 resolve();
2402 });
2403 )"));
2404
2405 // 2) Navigate away.
2406 EXPECT_TRUE(NavigateToURL(
2407 shell(), embedded_test_server()->GetURL("b.com", "/title1.html")));
2408
2409 // The page uses IdleManager so it should be deleted.
2410 rfh_a_deleted.WaitUntilDeleted();
2411
2412 // 3) Go back and make sure the IdleManager page wasn't in the cache.
2413 web_contents()->GetController().GoBack();
2414 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
2415 ExpectNotRestored(
2416 {BackForwardCacheMetrics::NotRestoredReason::kBlocklistedFeatures},
2417 FROM_HERE);
2418 ExpectBlocklistedFeature(
2419 blink::scheduler::WebSchedulerTrackedFeature::kKeyboardLock, FROM_HERE);
2420 }
2421
2422 // Tests which blocklisted features are tracked in the metrics when we used
2423 // blocklisted features (sticky and non-sticky) and do a browser-initiated
2424 // cross-site navigation.
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,BlocklistedFeaturesTracking_CrossSite_BrowserInitiated)2425 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
2426 BlocklistedFeaturesTracking_CrossSite_BrowserInitiated) {
2427 ASSERT_TRUE(CreateHttpsServer()->Start());
2428 GURL url_a(https_server()->GetURL("a.com", "/title1.html"));
2429 GURL url_b(https_server()->GetURL("b.com", "/title2.html"));
2430 // 1) Navigate to a page.
2431 EXPECT_TRUE(NavigateToURL(shell(), url_a));
2432 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
2433
2434 RenderFrameHostImpl* rfh_a = current_frame_host();
2435 scoped_refptr<SiteInstanceImpl> site_instance_a =
2436 static_cast<SiteInstanceImpl*>(rfh_a->GetSiteInstance());
2437 RenderFrameDeletedObserver rfh_a_deleted(rfh_a);
2438
2439 // 2) Use WebRTC (non-sticky) and KeyboardLock (sticky) blocklisted features.
2440 EXPECT_TRUE(ExecJs(rfh_a, "new RTCPeerConnection()"));
2441 EXPECT_TRUE(ExecJs(rfh_a, R"(
2442 new Promise(resolve => {
2443 navigator.keyboard.lock();
2444 resolve();
2445 });
2446 )"));
2447
2448 // 3) Navigate cross-site, browser-initiated.
2449 EXPECT_TRUE(NavigateToURL(shell(), url_b));
2450 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
2451
2452 // The previous page won't get into the back-forward cache because of the
2453 // blocklisted features. Because we used sticky blocklisted features, we will
2454 // not do a proactive BrowsingInstance swap, however the RFH will still change
2455 // and get deleted.
2456 rfh_a_deleted.WaitUntilDeleted();
2457 EXPECT_FALSE(site_instance_a->IsRelatedSiteInstance(
2458 web_contents()->GetMainFrame()->GetSiteInstance()));
2459
2460 // 4) Go back.
2461 web_contents()->GetController().GoBack();
2462 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
2463
2464 ExpectNotRestored(
2465 {BackForwardCacheMetrics::NotRestoredReason::kBlocklistedFeatures},
2466 FROM_HERE);
2467 // All features (sticky and non-sticky) will be tracked, because they're
2468 // tracked in RenderFrameHostManager::UnloadOldFrame.
2469 ExpectBlocklistedFeatures(
2470 {blink::scheduler::WebSchedulerTrackedFeature::kWebRTC,
2471 blink::scheduler::WebSchedulerTrackedFeature::kKeyboardLock},
2472 FROM_HERE);
2473 }
2474
2475 // Tests which blocklisted features are tracked in the metrics when we used
2476 // blocklisted features (sticky and non-sticky) and do a renderer-initiated
2477 // cross-site navigation.
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,BlocklistedFeaturesTracking_CrossSite_RendererInitiated)2478 IN_PROC_BROWSER_TEST_F(
2479 BackForwardCacheBrowserTest,
2480 BlocklistedFeaturesTracking_CrossSite_RendererInitiated) {
2481 ASSERT_TRUE(CreateHttpsServer()->Start());
2482 GURL url_a(https_server()->GetURL("a.com", "/title1.html"));
2483 GURL url_b(https_server()->GetURL("b.com", "/title2.html"));
2484
2485 // 1) Navigate to a page.
2486 EXPECT_TRUE(NavigateToURL(shell(), url_a));
2487 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
2488
2489 RenderFrameHostImpl* rfh_a = current_frame_host();
2490 scoped_refptr<SiteInstanceImpl> site_instance_a =
2491 static_cast<SiteInstanceImpl*>(rfh_a->GetSiteInstance());
2492
2493 // 2) Use WebRTC (non-sticky) and KeyboardLock (sticky) blocklisted
2494 // features.
2495 EXPECT_TRUE(ExecJs(rfh_a, "new RTCPeerConnection()"));
2496 EXPECT_TRUE(ExecJs(rfh_a, R"(
2497 new Promise(resolve => {
2498 navigator.keyboard.lock();
2499 resolve();
2500 });
2501 )"));
2502
2503 // 3) Navigate cross-site, renderer-inititated.
2504 EXPECT_TRUE(ExecJs(shell(), JsReplace("location = $1;", url_b.spec())));
2505 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
2506 // The previous page won't get into the back-forward cache because of the
2507 // blocklisted features. Because we used sticky blocklisted features, we will
2508 // not do a proactive BrowsingInstance swap.
2509 EXPECT_TRUE(site_instance_a->IsRelatedSiteInstance(
2510 web_contents()->GetMainFrame()->GetSiteInstance()));
2511
2512 // 4) Go back.
2513 web_contents()->GetController().GoBack();
2514 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
2515
2516 if (AreAllSitesIsolatedForTesting()) {
2517 ExpectNotRestored(
2518 {BackForwardCacheMetrics::NotRestoredReason::
2519 kRelatedActiveContentsExist,
2520 BackForwardCacheMetrics::NotRestoredReason::kBlocklistedFeatures},
2521 FROM_HERE);
2522 // All features (sticky and non-sticky) will be tracked, because they're
2523 // tracked in RenderFrameHostManager::UnloadOldFrame.
2524 ExpectBlocklistedFeatures(
2525 {blink::scheduler::WebSchedulerTrackedFeature::kWebRTC,
2526 blink::scheduler::WebSchedulerTrackedFeature::kKeyboardLock},
2527 FROM_HERE);
2528 ExpectBrowsingInstanceNotSwappedReason(
2529 ShouldSwapBrowsingInstance::kNo_NotNeededForBackForwardCache,
2530 FROM_HERE);
2531
2532 web_contents()->GetController().GoForward();
2533 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
2534
2535 ExpectBrowsingInstanceNotSwappedReason(
2536 ShouldSwapBrowsingInstance::kNo_AlreadyHasMatchingBrowsingInstance,
2537 FROM_HERE);
2538
2539 web_contents()->GetController().GoBack();
2540 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
2541
2542 ExpectBrowsingInstanceNotSwappedReason(
2543 ShouldSwapBrowsingInstance::kNo_AlreadyHasMatchingBrowsingInstance,
2544 FROM_HERE);
2545 } else {
2546 ExpectNotRestored(
2547 {BackForwardCacheMetrics::NotRestoredReason::kBlocklistedFeatures,
2548 BackForwardCacheMetrics::NotRestoredReason::
2549 kRenderFrameHostReused_CrossSite},
2550 FROM_HERE);
2551 // Non-sticky reasons are not recorded here.
2552 ExpectBlocklistedFeatures(
2553 {blink::scheduler::WebSchedulerTrackedFeature::kKeyboardLock},
2554 FROM_HERE);
2555 }
2556 }
2557
2558 // Tests which blocklisted features are tracked in the metrics when we used
2559 // blocklisted features (sticky and non-sticky) and do a same-site navigation.
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,BlocklistedFeaturesTracking_SameSite)2560 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
2561 BlocklistedFeaturesTracking_SameSite) {
2562 ASSERT_TRUE(CreateHttpsServer()->Start());
2563
2564 ASSERT_TRUE(CreateHttpsServer()->Start());
2565 GURL url_1(https_server()->GetURL("/title1.html"));
2566 GURL url_2(https_server()->GetURL("/title2.html"));
2567
2568 // 1) Navigate to a page.
2569 EXPECT_TRUE(NavigateToURL(shell(), url_1));
2570 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
2571
2572 RenderFrameHostImpl* rfh_1 = current_frame_host();
2573 scoped_refptr<SiteInstanceImpl> site_instance_1 =
2574 static_cast<SiteInstanceImpl*>(rfh_1->GetSiteInstance());
2575
2576 // 2) Use WebRTC (non-sticky) and KeyboardLock (sticky) blocklisted features.
2577 EXPECT_TRUE(ExecJs(rfh_1, "new RTCPeerConnection()"));
2578 EXPECT_TRUE(ExecJs(rfh_1, R"(
2579 new Promise(resolve => {
2580 navigator.keyboard.lock();
2581 resolve();
2582 });
2583 )"));
2584
2585 // 3) Navigate same-site.
2586 EXPECT_TRUE(NavigateToURL(shell(), url_2));
2587 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
2588
2589 // Because we used sticky blocklisted features, we will not do a proactive
2590 // BrowsingInstance swap.
2591 EXPECT_TRUE(site_instance_1->IsRelatedSiteInstance(
2592 web_contents()->GetMainFrame()->GetSiteInstance()));
2593
2594 // 4) Go back.
2595 web_contents()->GetController().GoBack();
2596 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
2597
2598 ExpectNotRestored(
2599 {BackForwardCacheMetrics::NotRestoredReason::
2600 kRenderFrameHostReused_SameSite,
2601 BackForwardCacheMetrics::NotRestoredReason::kBlocklistedFeatures},
2602 FROM_HERE);
2603 // Non-sticky reasons are not recorded here.
2604 ExpectBlocklistedFeatures(
2605 {blink::scheduler::WebSchedulerTrackedFeature::kKeyboardLock}, FROM_HERE);
2606 }
2607
2608 // Tests which blocklisted features are tracked in the metrics when we used a
2609 // non-sticky blocklisted feature and do a browser-initiated cross-site
2610 // navigation.
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,BlocklistedFeaturesTracking_CrossSite_BrowserInitiated_NonSticky)2611 IN_PROC_BROWSER_TEST_F(
2612 BackForwardCacheBrowserTest,
2613 BlocklistedFeaturesTracking_CrossSite_BrowserInitiated_NonSticky) {
2614 ASSERT_TRUE(CreateHttpsServer()->Start());
2615
2616 // 1) Navigate to an empty page.
2617 GURL url_a(https_server()->GetURL("a.com", "/title1.html"));
2618 GURL url_b(https_server()->GetURL("b.com", "/title2.html"));
2619 EXPECT_TRUE(NavigateToURL(shell(), url_a));
2620 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
2621
2622 RenderFrameHostImpl* rfh_a = current_frame_host();
2623 // 2) Use WebRTC (a non-sticky blocklisted feature).
2624 EXPECT_TRUE(ExecJs(rfh_a, "new RTCPeerConnection()"));
2625 scoped_refptr<SiteInstanceImpl> site_instance_a =
2626 static_cast<SiteInstanceImpl*>(
2627 web_contents()->GetMainFrame()->GetSiteInstance());
2628
2629 // 3) Navigate cross-site, browser-initiated.
2630 // The previous page won't get into the back-forward cache because of the
2631 // blocklisted feature.
2632 EXPECT_TRUE(NavigateToURL(shell(), url_b));
2633 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
2634 // Because we only used non-sticky blocklisted features, we will still do a
2635 // proactive BrowsingInstance swap.
2636 EXPECT_FALSE(site_instance_a->IsRelatedSiteInstance(
2637 web_contents()->GetMainFrame()->GetSiteInstance()));
2638
2639 // 4) Go back.
2640 web_contents()->GetController().GoBack();
2641 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
2642
2643 // Because the RenderFrameHostManager changed, the blocklisted features will
2644 // be tracked in RenderFrameHostManager::UnloadOldFrame.
2645 ExpectNotRestored(
2646 {BackForwardCacheMetrics::NotRestoredReason::kBlocklistedFeatures},
2647 FROM_HERE);
2648 ExpectBlocklistedFeature(
2649 blink::scheduler::WebSchedulerTrackedFeature::kWebRTC, FROM_HERE);
2650 }
2651
2652 // Tests which blocklisted features are tracked in the metrics when we used a
2653 // non-sticky blocklisted feature and do a renderer-initiated cross-site
2654 // navigation.
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,BlocklistedFeaturesTracking_CrossSite_RendererInitiated_NonSticky)2655 IN_PROC_BROWSER_TEST_F(
2656 BackForwardCacheBrowserTest,
2657 BlocklistedFeaturesTracking_CrossSite_RendererInitiated_NonSticky) {
2658 ASSERT_TRUE(CreateHttpsServer()->Start());
2659
2660 // 1) Navigate to an empty page.
2661 GURL url_a(https_server()->GetURL("a.com", "/title1.html"));
2662 GURL url_b(https_server()->GetURL("b.com", "/title1.html"));
2663 EXPECT_TRUE(NavigateToURL(shell(), url_a));
2664 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
2665
2666 RenderFrameHostImpl* rfh_a = current_frame_host();
2667 // 2) Use WebRTC (a non-sticky blocklisted feature).
2668 EXPECT_TRUE(ExecJs(rfh_a, "new RTCPeerConnection()"));
2669 scoped_refptr<SiteInstanceImpl> site_instance_a =
2670 static_cast<SiteInstanceImpl*>(
2671 web_contents()->GetMainFrame()->GetSiteInstance());
2672
2673 // 3) Navigate cross-site, renderer-inititated.
2674 // The previous page won't get into the back-forward cache because of the
2675 // blocklisted feature.
2676 EXPECT_TRUE(ExecJs(shell(), JsReplace("location = $1;", url_b.spec())));
2677 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
2678 // Because we only used non-sticky blocklisted features, we will still do a
2679 // proactive BrowsingInstance swap.
2680 EXPECT_FALSE(site_instance_a->IsRelatedSiteInstance(
2681 web_contents()->GetMainFrame()->GetSiteInstance()));
2682
2683 // 4) Go back.
2684 web_contents()->GetController().GoBack();
2685 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
2686
2687 // Because the RenderFrameHostManager changed, the blocklisted features will
2688 // be tracked in RenderFrameHostManager::UnloadOldFrame.
2689 ExpectNotRestored(
2690 {BackForwardCacheMetrics::NotRestoredReason::kBlocklistedFeatures},
2691 FROM_HERE);
2692 ExpectBlocklistedFeature(
2693 blink::scheduler::WebSchedulerTrackedFeature::kWebRTC, FROM_HERE);
2694 }
2695
2696 // Tests which blocklisted features are tracked in the metrics when we used a
2697 // non-sticky blocklisted feature and do a same-site navigation.
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,BlocklistedFeaturesTracking_SameSite_NonSticky)2698 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
2699 BlocklistedFeaturesTracking_SameSite_NonSticky) {
2700 ASSERT_TRUE(CreateHttpsServer()->Start());
2701
2702 // 1) Navigate to an empty page.
2703 GURL url_1(https_server()->GetURL("/title1.html"));
2704 GURL url_2(https_server()->GetURL("/title2.html"));
2705 EXPECT_TRUE(NavigateToURL(shell(), url_1));
2706 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
2707
2708 RenderFrameHostImpl* rfh_1 = current_frame_host();
2709 // 2) Use WebRTC (a non-sticky blocklisted feature).
2710 EXPECT_TRUE(ExecJs(rfh_1, "new RTCPeerConnection()"));
2711 scoped_refptr<SiteInstanceImpl> site_instance_1 =
2712 static_cast<SiteInstanceImpl*>(
2713 web_contents()->GetMainFrame()->GetSiteInstance());
2714
2715 // 3) Navigate same-site.
2716 // The previous page won't get into the back-forward cache because of the
2717 // blocklisted feature.
2718 EXPECT_TRUE(NavigateToURL(shell(), url_2));
2719 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
2720 // Because we only used non-sticky blocklisted features, we will still do a
2721 // proactive BrowsingInstance swap.
2722 EXPECT_FALSE(site_instance_1->IsRelatedSiteInstance(
2723 web_contents()->GetMainFrame()->GetSiteInstance()));
2724
2725 // 4) Go back.
2726 web_contents()->GetController().GoBack();
2727 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
2728
2729 // Because the RenderFrameHostManager changed, the blocklisted features will
2730 // be tracked in RenderFrameHostManager::UnloadOldFrame.
2731 ExpectNotRestored(
2732 {BackForwardCacheMetrics::NotRestoredReason::kBlocklistedFeatures},
2733 FROM_HERE);
2734 ExpectBlocklistedFeature(
2735 blink::scheduler::WebSchedulerTrackedFeature::kWebRTC, FROM_HERE);
2736 }
2737
2738 // Flaky on Android, see crbug.com/1135601.
2739 #if defined(OS_ANDROID)
2740 #define MAYBE_LogIpcPostedToCachedFrame DISABLED_LogIpcPostedToCachedFrame
2741 #else
2742 #define MAYBE_LogIpcPostedToCachedFrame LogIpcPostedToCachedFrame
2743 #endif
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,MAYBE_LogIpcPostedToCachedFrame)2744 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
2745 MAYBE_LogIpcPostedToCachedFrame) {
2746 ASSERT_TRUE(embedded_test_server()->Start());
2747
2748 // 1) Navigate to a page.
2749 GURL url(embedded_test_server()->GetURL("/title1.html"));
2750 EXPECT_TRUE(NavigateToURL(shell(), url));
2751 RenderFrameHostImpl* rfh_a = current_frame_host();
2752
2753 // 2) Navigate away. The first page should be in the cache.
2754 EXPECT_TRUE(NavigateToURL(
2755 shell(), embedded_test_server()->GetURL("b.com", "/title1.html")));
2756
2757 // 3) Post IPC tasks to the page, testing both mojo remote and associated
2758 // remote objects.
2759
2760 // Send a message via an associated interface - which will post a task with an
2761 // IPC hash and will be routed to the per-thread task queue.
2762 base::RunLoop run_loop;
2763 rfh_a->RequestTextSurroundingSelection(
2764 base::BindOnce(
2765 [](base::RepeatingClosure quit_closure, const base::string16& str,
2766 uint32_t num, uint32_t num2) { quit_closure.Run(); },
2767 run_loop.QuitClosure()),
2768 1);
2769 run_loop.Run();
2770
2771 // Post a non-associated interface. Will be routed to a frame-specific task
2772 // queue with IPC set in SimpleWatcher.
2773 base::RunLoop run_loop2;
2774 rfh_a->GetHighPriorityLocalFrame()->DispatchBeforeUnload(
2775 false,
2776 base::BindOnce([](base::RepeatingClosure quit_closure, bool proceed,
2777 base::TimeTicks start_time,
2778 base::TimeTicks end_time) { quit_closure.Run(); },
2779 run_loop2.QuitClosure()));
2780 run_loop2.Run();
2781
2782 // 4) Check the histogram.
2783 std::vector<base::HistogramBase::Sample> samples = {
2784 base::HistogramBase::Sample(
2785 base::TaskAnnotator::ScopedSetIpcHash::MD5HashMetricName(
2786 "blink.mojom.HighPriorityLocalFrame")),
2787 base::HistogramBase::Sample(
2788 base::TaskAnnotator::ScopedSetIpcHash::MD5HashMetricName(
2789 "blink.mojom.LocalFrame"))};
2790
2791 for (base::HistogramBase::Sample sample : samples) {
2792 FetchHistogramsFromChildProcesses();
2793 EXPECT_TRUE(HistogramContainsIntValue(
2794 sample, histogram_tester_.GetAllSamples(
2795 "BackForwardCache.Experimental."
2796 "UnexpectedIPCMessagePostedToCachedFrame.MethodHash")));
2797 }
2798 }
2799
2800 class MockAppBannerService : public blink::mojom::AppBannerService {
2801 public:
2802 MockAppBannerService() = default;
2803 ~MockAppBannerService() override = default;
2804
Bind(mojo::ScopedMessagePipeHandle handle)2805 void Bind(mojo::ScopedMessagePipeHandle handle) {
2806 receiver_.Bind(mojo::PendingReceiver<blink::mojom::AppBannerService>(
2807 std::move(handle)));
2808 }
2809
controller()2810 mojo::Remote<blink::mojom::AppBannerController>& controller() {
2811 return controller_;
2812 }
2813
OnBannerPromptRequested(bool)2814 void OnBannerPromptRequested(bool) {}
2815
SendBannerPromptRequest()2816 void SendBannerPromptRequest() {
2817 blink::mojom::AppBannerController* controller_ptr = controller_.get();
2818 base::OnceCallback<void(bool)> callback = base::BindOnce(
2819 &MockAppBannerService::OnBannerPromptRequested, base::Unretained(this));
2820 controller_ptr->BannerPromptRequest(
2821 receiver_.BindNewPipeAndPassRemote(),
2822 event_.BindNewPipeAndPassReceiver(), {"web"},
2823 base::BindOnce(&MockAppBannerService::OnBannerPromptReply,
2824 base::Unretained(this), std::move(callback)));
2825 }
2826
OnBannerPromptReply(base::OnceCallback<void (bool)> callback,blink::mojom::AppBannerPromptReply reply)2827 void OnBannerPromptReply(base::OnceCallback<void(bool)> callback,
2828 blink::mojom::AppBannerPromptReply reply) {
2829 std::move(callback).Run(reply ==
2830 blink::mojom::AppBannerPromptReply::CANCEL);
2831 }
2832
2833 // blink::mojom::AppBannerService:
DisplayAppBanner()2834 void DisplayAppBanner() override {}
2835
2836 private:
2837 mojo::Receiver<blink::mojom::AppBannerService> receiver_{this};
2838 mojo::Remote<blink::mojom::AppBannerEvent> event_;
2839 mojo::Remote<blink::mojom::AppBannerController> controller_;
2840
2841 DISALLOW_COPY_AND_ASSIGN(MockAppBannerService);
2842 };
2843
2844 class BackForwardCacheBrowserTestWithAppBanner
2845 : public BackForwardCacheBrowserTest {
2846 protected:
SetUpOnMainThread()2847 void SetUpOnMainThread() override {
2848 web_contents()->GetMainFrame()->GetRemoteInterfaces()->GetInterface(
2849 mock_app_banner_service_.controller().BindNewPipeAndPassReceiver());
2850 BackForwardCacheBrowserTest::SetUpOnMainThread();
2851 }
2852
SendBannerPromptRequest()2853 void SendBannerPromptRequest() {
2854 mock_app_banner_service_.SendBannerPromptRequest();
2855 }
2856
2857 private:
2858 MockAppBannerService mock_app_banner_service_;
2859 };
2860
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTestWithAppBanner,DoesNotCacheIfAppBanner)2861 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTestWithAppBanner,
2862 DoesNotCacheIfAppBanner) {
2863 ASSERT_TRUE(embedded_test_server()->Start());
2864
2865 // 1) Navigate to A and request a PWA app banner.
2866 EXPECT_TRUE(NavigateToURL(
2867 shell(), embedded_test_server()->GetURL("a.com", "/title1.html")));
2868 SendBannerPromptRequest();
2869 RenderFrameDeletedObserver delete_observer_rfh(current_frame_host());
2870
2871 // 2) Navigate away. Page A requested a PWA app banner, and thus not cached.
2872 EXPECT_TRUE(NavigateToURL(
2873 shell(), embedded_test_server()->GetURL("b.com", "/title1.html")));
2874 delete_observer_rfh.WaitUntilDeleted();
2875
2876 // 3) Go back to A.
2877 web_contents()->GetController().GoBack();
2878 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
2879 ExpectNotRestored(
2880 {BackForwardCacheMetrics::NotRestoredReason::kBlocklistedFeatures},
2881 FROM_HERE);
2882 ExpectBlocklistedFeature(
2883 blink::scheduler::WebSchedulerTrackedFeature::kAppBanner, FROM_HERE);
2884 }
2885
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,DoesNotCacheIfWebDatabase)2886 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, DoesNotCacheIfWebDatabase) {
2887 ASSERT_TRUE(embedded_test_server()->Start());
2888
2889 // 1) Navigate to a page with WebDatabase usage.
2890 GURL url(embedded_test_server()->GetURL("/simple_database.html"));
2891 EXPECT_TRUE(NavigateToURL(shell(), url));
2892 RenderFrameHostImpl* rfh_a = current_frame_host();
2893 RenderFrameDeletedObserver deleted(rfh_a);
2894
2895 // 2) Navigate away.
2896 shell()->LoadURL(embedded_test_server()->GetURL("b.com", "/title1.html"));
2897 // The page uses WebDatabase so it should be deleted.
2898 deleted.WaitUntilDeleted();
2899
2900 // 3) Go back to the page with WebDatabase.
2901 web_contents()->GetController().GoBack();
2902 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
2903 ExpectNotRestored(
2904 {BackForwardCacheMetrics::NotRestoredReason::kBlocklistedFeatures},
2905 FROM_HERE);
2906 ExpectBlocklistedFeature(
2907 blink::scheduler::WebSchedulerTrackedFeature::kWebDatabase, FROM_HERE);
2908 }
2909
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,DoesNotCacheIfPageUnreachable)2910 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
2911 DoesNotCacheIfPageUnreachable) {
2912 ASSERT_TRUE(embedded_test_server()->Start());
2913
2914 GURL error_url(embedded_test_server()->GetURL("a.com", "/empty.html"));
2915 GURL url(embedded_test_server()->GetURL("b.com", "/title1.html"));
2916
2917 std::unique_ptr<URLLoaderInterceptor> url_interceptor =
2918 URLLoaderInterceptor::SetupRequestFailForURL(error_url,
2919 net::ERR_DNS_TIMED_OUT);
2920
2921 // Start with a successful navigation to a document.
2922 EXPECT_TRUE(NavigateToURL(shell(), url));
2923 EXPECT_EQ(net::HTTP_OK, current_frame_host()->last_http_status_code());
2924
2925 // Navigate to an error page.
2926 NavigationHandleObserver observer(shell()->web_contents(), error_url);
2927 EXPECT_FALSE(NavigateToURL(shell(), error_url));
2928 EXPECT_TRUE(observer.is_error());
2929 EXPECT_EQ(net::ERR_DNS_TIMED_OUT, observer.net_error_code());
2930 EXPECT_EQ(
2931 GURL(kUnreachableWebDataURL),
2932 shell()->web_contents()->GetMainFrame()->GetSiteInstance()->GetSiteURL());
2933 EXPECT_EQ(net::OK, current_frame_host()->last_http_status_code());
2934
2935 RenderFrameDeletedObserver delete_rfh_a(current_frame_host());
2936
2937 // Navigate away.
2938 EXPECT_TRUE(NavigateToURL(shell(), url));
2939
2940 // The page had a networking error, so it shouldn't have been cached.
2941 delete_rfh_a.WaitUntilDeleted();
2942
2943 // Go back.
2944 web_contents()->GetController().GoBack();
2945 EXPECT_FALSE(WaitForLoadStop(shell()->web_contents()));
2946 ExpectNotRestored(
2947 {BackForwardCacheMetrics::NotRestoredReason::kHTTPStatusNotOK},
2948 FROM_HERE);
2949 }
2950
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,DisableBackforwardCacheForTesting)2951 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
2952 DisableBackforwardCacheForTesting) {
2953 ASSERT_TRUE(embedded_test_server()->Start());
2954
2955 // Disable the BackForwardCache.
2956 web_contents()->GetController().GetBackForwardCache().DisableForTesting(
2957 BackForwardCacheImpl::TEST_ASSUMES_NO_CACHING);
2958
2959 // Navigate to a page that would normally be cacheable.
2960 EXPECT_TRUE(NavigateToURL(
2961 shell(), embedded_test_server()->GetURL("a.com", "/title1.html")));
2962 RenderFrameDeletedObserver delete_observer_rfh_a(current_frame_host());
2963
2964 // Navigate away.
2965 EXPECT_TRUE(NavigateToURL(
2966 shell(), embedded_test_server()->GetURL("b.com", "/title1.html")));
2967
2968 // The page should be deleted (not cached).
2969 delete_observer_rfh_a.WaitUntilDeleted();
2970 }
2971
2972 // Navigate from A to B, then cause JavaScript execution on A, then go back.
2973 // Test the RenderFrameHost in the cache is evicted by JavaScript.
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,EvictionOnJavaScriptExecution)2974 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
2975 EvictionOnJavaScriptExecution) {
2976 ASSERT_TRUE(embedded_test_server()->Start());
2977 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
2978 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
2979
2980 // 1) Navigate to A.
2981 EXPECT_TRUE(NavigateToURL(shell(), url_a));
2982 RenderFrameHostImpl* rfh_a = current_frame_host();
2983 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
2984
2985 // 2) Navigate to B.
2986 EXPECT_TRUE(NavigateToURL(shell(), url_b));
2987 RenderFrameHostImpl* rfh_b = current_frame_host();
2988 RenderFrameDeletedObserver delete_observer_rfh_b(rfh_b);
2989
2990 EXPECT_FALSE(delete_observer_rfh_a.deleted());
2991 EXPECT_FALSE(delete_observer_rfh_b.deleted());
2992 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
2993 EXPECT_FALSE(rfh_b->IsInBackForwardCache());
2994
2995 // 3) Execute JavaScript on A.
2996 EvictByJavaScript(rfh_a);
2997
2998 // RenderFrameHost A is evicted from the BackForwardCache:
2999 delete_observer_rfh_a.WaitUntilDeleted();
3000
3001 // 4) Go back to A.
3002 web_contents()->GetController().GoBack();
3003 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
3004 ExpectOutcome(BackForwardCacheMetrics::HistoryNavigationOutcome::kNotRestored,
3005 FROM_HERE);
3006 ExpectNotRestored(
3007 {BackForwardCacheMetrics::NotRestoredReason::kJavaScriptExecution},
3008 FROM_HERE);
3009 }
3010
3011 // Similar to BackForwardCacheBrowserTest.EvictionOnJavaScriptExecution.
3012 // Test case: A(B) -> C -> JS on B -> A(B)
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,EvictionOnJavaScriptExecutionIframe)3013 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
3014 EvictionOnJavaScriptExecutionIframe) {
3015 ASSERT_TRUE(embedded_test_server()->Start());
3016 GURL url_a(embedded_test_server()->GetURL(
3017 "a.com", "/cross_site_iframe_factory.html?a(b)"));
3018 GURL url_c(embedded_test_server()->GetURL("c.com", "/title1.html"));
3019
3020 // 1) Navigate to A(B).
3021 EXPECT_TRUE(NavigateToURL(shell(), url_a));
3022 RenderFrameHostImpl* rfh_a = current_frame_host();
3023 RenderFrameHostImpl* rfh_b = rfh_a->child_at(0)->current_frame_host();
3024 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
3025 RenderFrameDeletedObserver delete_observer_rfh_b(rfh_b);
3026
3027 // 2) Navigate to C.
3028 EXPECT_TRUE(NavigateToURL(shell(), url_c));
3029 RenderFrameHostImpl* rfh_c = current_frame_host();
3030 RenderFrameDeletedObserver delete_observer_rfh_c(rfh_c);
3031
3032 EXPECT_FALSE(delete_observer_rfh_a.deleted());
3033 EXPECT_FALSE(delete_observer_rfh_b.deleted());
3034 EXPECT_FALSE(delete_observer_rfh_c.deleted());
3035 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
3036 EXPECT_TRUE(rfh_b->IsInBackForwardCache());
3037 EXPECT_FALSE(rfh_c->IsInBackForwardCache());
3038
3039 // 3) Execute JavaScript on B.
3040 //
3041 EvictByJavaScript(rfh_b);
3042
3043 // The A(B) page is evicted. So A and B are removed:
3044 delete_observer_rfh_a.WaitUntilDeleted();
3045 delete_observer_rfh_b.WaitUntilDeleted();
3046
3047 // 4) Go back to A(B).
3048 web_contents()->GetController().GoBack();
3049 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
3050 ExpectOutcome(BackForwardCacheMetrics::HistoryNavigationOutcome::kNotRestored,
3051 FROM_HERE);
3052 ExpectNotRestored(
3053 {BackForwardCacheMetrics::NotRestoredReason::kJavaScriptExecution},
3054 FROM_HERE);
3055 }
3056
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,EvictionOnJavaScriptExecutionInAnotherWorld)3057 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
3058 EvictionOnJavaScriptExecutionInAnotherWorld) {
3059 ASSERT_TRUE(embedded_test_server()->Start());
3060 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
3061 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
3062
3063 // 1) Navigate to A.
3064 EXPECT_TRUE(NavigateToURL(shell(), url_a));
3065 RenderFrameHostImpl* rfh_a = current_frame_host();
3066 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
3067
3068 // 2) Execute JavaScript on A in a new world. This ensures a new world.
3069 const int32_t kNewWorldId = content::ISOLATED_WORLD_ID_CONTENT_END + 1;
3070 EXPECT_TRUE(ExecJs(rfh_a, "console.log('hi');",
3071 EXECUTE_SCRIPT_DEFAULT_OPTIONS, kNewWorldId));
3072
3073 // 3) Navigate to B.
3074 EXPECT_TRUE(NavigateToURL(shell(), url_b));
3075 RenderFrameHostImpl* rfh_b = current_frame_host();
3076 RenderFrameDeletedObserver delete_observer_rfh_b(rfh_b);
3077
3078 EXPECT_FALSE(delete_observer_rfh_a.deleted());
3079 EXPECT_FALSE(delete_observer_rfh_b.deleted());
3080 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
3081 EXPECT_FALSE(rfh_b->IsInBackForwardCache());
3082
3083 // 4) Execute JavaScript on A in the new world.
3084 EXPECT_FALSE(ExecJs(rfh_a, "console.log('hi');",
3085 EXECUTE_SCRIPT_DEFAULT_OPTIONS, kNewWorldId));
3086
3087 // RenderFrameHost A is evicted from the BackForwardCache:
3088 delete_observer_rfh_a.WaitUntilDeleted();
3089
3090 // 5) Go back to A.
3091 web_contents()->GetController().GoBack();
3092 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
3093 ExpectOutcome(BackForwardCacheMetrics::HistoryNavigationOutcome::kNotRestored,
3094 FROM_HERE);
3095 ExpectNotRestored(
3096 {BackForwardCacheMetrics::NotRestoredReason::kJavaScriptExecution},
3097 FROM_HERE);
3098 }
3099
3100 // Similar to BackForwardCacheBrowserTest.EvictionOnJavaScriptExecution, but
3101 // cause the race condition of eviction and restoring.
3102 //
3103 // ┌───────┐ ┌────────┐
3104 // │Browser│ │Renderer│
3105 // └───┬───┘ └───┬────┘
3106 // (Store to the bfcache) │
3107 // │ Freeze │
3108 // │────────────────────────>│
3109 // │ │
3110 // (Restore from the bfcache) │
3111 // │──┐ │
3112 // │ │ │
3113 // │EvictFromBackForwardCache│
3114 // │<────────────────────────│
3115 // │ │ │
3116 // │ │ Resume │
3117 // │ └─────────────────────>│
3118 // ┌───┴───┐ ┌───┴────┐
3119 // │Browser│ │Renderer│
3120 // └───────┘ └────────┘
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,EvictionOnJavaScriptExecutionRace)3121 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
3122 EvictionOnJavaScriptExecutionRace) {
3123 ASSERT_TRUE(embedded_test_server()->Start());
3124 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
3125 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
3126
3127 // 1) Navigate to A.
3128 EXPECT_TRUE(NavigateToURL(shell(), url_a));
3129 RenderFrameHostImpl* rfh_a = current_frame_host();
3130 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
3131 EXPECT_TRUE(ExecJs(rfh_a, "window.foo = 'initial document'"));
3132
3133 // 2) Navigate to B.
3134 EXPECT_TRUE(NavigateToURL(shell(), url_b));
3135 RenderFrameHostImpl* rfh_b = current_frame_host();
3136 RenderFrameDeletedObserver delete_observer_rfh_b(rfh_b);
3137
3138 EXPECT_FALSE(delete_observer_rfh_a.deleted());
3139 EXPECT_FALSE(delete_observer_rfh_b.deleted());
3140 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
3141 EXPECT_FALSE(rfh_b->IsInBackForwardCache());
3142
3143 // 3) Execute JavaScript on A when restoring A.
3144 // Execute JavaScript after committing but before swapping happens on the
3145 // renderer.
3146 ReadyToCommitNavigationCallback host_changed_callback(
3147 web_contents(),
3148 base::BindOnce(
3149 [](RenderFrameHostImpl* rfh_a,
3150 RenderFrameDeletedObserver* delete_observer_rfh_a,
3151 NavigationHandle* navigation_handle) {
3152 ASSERT_FALSE(delete_observer_rfh_a->deleted());
3153 EXPECT_EQ(rfh_a, navigation_handle->GetRenderFrameHost());
3154 rfh_a->ExecuteJavaScriptForTests(
3155 base::UTF8ToUTF16("console.log('hi');"), base::NullCallback());
3156 },
3157 rfh_a, &delete_observer_rfh_a));
3158
3159 // Wait for two navigations to finish. The first one is the BackForwardCache
3160 // navigation, the other is the reload caused by the eviction.
3161 //
3162 // 1. BFcache navigation start.
3163 // 2. BFcache navigation commit & finish.
3164 // 3. Evict & reload start.
3165 // 4. Reload commit.
3166 // 5. Reload finish.
3167 //
3168 // Each item is a single task.
3169 TestNavigationObserver observer(web_contents(),
3170 2 /* number of navigations */);
3171 observer.set_wait_event(
3172 TestNavigationObserver::WaitEvent::kNavigationFinished);
3173 web_contents()->GetController().GoBack();
3174 observer.WaitForNavigationFinished();
3175
3176 // A is not destroyed. A is reloaded instead.
3177 EXPECT_FALSE(delete_observer_rfh_a.deleted());
3178 EXPECT_FALSE(delete_observer_rfh_b.deleted());
3179 EXPECT_FALSE(rfh_a->IsInBackForwardCache());
3180 EXPECT_TRUE(rfh_b->IsInBackForwardCache());
3181 EXPECT_NE("initial document", EvalJs(rfh_a, "window.foo"));
3182
3183 ExpectOutcome(BackForwardCacheMetrics::HistoryNavigationOutcome::kRestored,
3184 FROM_HERE);
3185 ExpectEvictedAfterCommitted(
3186 {
3187 BackForwardCacheMetrics::EvictedAfterDocumentRestoredReason::
3188 kRestored,
3189 BackForwardCacheMetrics::EvictedAfterDocumentRestoredReason::
3190 kByJavaScript,
3191 },
3192 FROM_HERE);
3193 }
3194
3195 // Tests the events are fired when going back from the cache.
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,Events)3196 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, Events) {
3197 ASSERT_TRUE(embedded_test_server()->Start());
3198 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
3199 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
3200
3201 // 1) Navigate to A.
3202 EXPECT_TRUE(NavigateToURL(shell(), url_a));
3203 RenderFrameHostImpl* rfh_a = current_frame_host();
3204 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
3205 StartRecordingEvents(rfh_a);
3206
3207 // 2) Navigate to B.
3208 EXPECT_TRUE(NavigateToURL(shell(), url_b));
3209 RenderFrameHostImpl* rfh_b = current_frame_host();
3210 RenderFrameDeletedObserver delete_observer_rfh_b(rfh_b);
3211
3212 EXPECT_FALSE(delete_observer_rfh_a.deleted());
3213 EXPECT_FALSE(delete_observer_rfh_b.deleted());
3214 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
3215 EXPECT_FALSE(rfh_b->IsInBackForwardCache());
3216 // TODO(yuzus): Post message to the frozen page, and make sure that the
3217 // messages arrive after the page visibility events, not before them.
3218
3219 // 3) Go back to A. Confirm that expected events are fired.
3220 web_contents()->GetController().GoBack();
3221 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
3222 EXPECT_FALSE(delete_observer_rfh_a.deleted());
3223 EXPECT_FALSE(delete_observer_rfh_b.deleted());
3224 EXPECT_EQ(rfh_a, current_frame_host());
3225 // visibilitychange events are added twice per each because it is fired for
3226 // both window and document.
3227 MatchEventList(
3228 rfh_a,
3229 ListValueOf("window.pagehide.persisted", "document.visibilitychange",
3230 "window.visibilitychange", "document.freeze",
3231 "document.resume", "document.visibilitychange",
3232 "window.visibilitychange", "window.pageshow.persisted"));
3233 }
3234
3235 // Tests the events are fired for subframes when going back from the cache.
3236 // Test case: a(b) -> c -> a(b)
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,EventsForSubframes)3237 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, EventsForSubframes) {
3238 ASSERT_TRUE(embedded_test_server()->Start());
3239 GURL url_a(embedded_test_server()->GetURL(
3240 "a.com", "/cross_site_iframe_factory.html?a(b)"));
3241 GURL url_c(embedded_test_server()->GetURL("c.com", "/title1.html"));
3242
3243 // 1) Navigate to A(B).
3244 EXPECT_TRUE(NavigateToURL(shell(), url_a));
3245 RenderFrameHostImpl* rfh_a = current_frame_host();
3246 RenderFrameHostImpl* rfh_b = rfh_a->child_at(0)->current_frame_host();
3247 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
3248 RenderFrameDeletedObserver delete_observer_rfh_b(rfh_b);
3249 StartRecordingEvents(rfh_a);
3250 StartRecordingEvents(rfh_b);
3251
3252 // 2) Navigate to C.
3253 EXPECT_TRUE(NavigateToURL(shell(), url_c));
3254 RenderFrameHostImpl* rfh_c = current_frame_host();
3255 RenderFrameDeletedObserver delete_observer_rfh_c(rfh_c);
3256 EXPECT_FALSE(delete_observer_rfh_a.deleted());
3257 EXPECT_FALSE(delete_observer_rfh_b.deleted());
3258 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
3259 EXPECT_TRUE(rfh_b->IsInBackForwardCache());
3260 EXPECT_FALSE(rfh_c->IsInBackForwardCache());
3261 // TODO(yuzus): Post message to the frozen page, and make sure that the
3262 // messages arrive after the page visibility events, not before them.
3263
3264 // 3) Go back to A(B). Confirm that expected events are fired on the subframe.
3265 web_contents()->GetController().GoBack();
3266 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
3267 EXPECT_FALSE(delete_observer_rfh_a.deleted());
3268 EXPECT_FALSE(delete_observer_rfh_b.deleted());
3269 EXPECT_FALSE(delete_observer_rfh_c.deleted());
3270 EXPECT_EQ(rfh_a, current_frame_host());
3271 EXPECT_FALSE(rfh_a->IsInBackForwardCache());
3272 EXPECT_FALSE(rfh_b->IsInBackForwardCache());
3273 EXPECT_TRUE(rfh_c->IsInBackForwardCache());
3274 // visibilitychange events are added twice per each because it is fired for
3275 // both window and document.
3276 MatchEventList(
3277 rfh_a,
3278 ListValueOf("window.pagehide.persisted", "document.visibilitychange",
3279 "window.visibilitychange", "document.freeze",
3280 "document.resume", "document.visibilitychange",
3281 "window.visibilitychange", "window.pageshow.persisted"));
3282 MatchEventList(
3283 rfh_b,
3284 ListValueOf("window.pagehide.persisted", "document.visibilitychange",
3285 "window.visibilitychange", "document.freeze",
3286 "document.resume", "document.visibilitychange",
3287 "window.visibilitychange", "window.pageshow.persisted"));
3288 }
3289
3290 // Tests the events are fired when going back from the cache.
3291 // Same as: BackForwardCacheBrowserTest.Events, but with a document-initiated
3292 // navigation. This is a regression test for https://crbug.com/1000324
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,EventsAfterDocumentInitiatedNavigation)3293 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
3294 EventsAfterDocumentInitiatedNavigation) {
3295 ASSERT_TRUE(embedded_test_server()->Start());
3296 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
3297 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
3298
3299 // 1) Navigate to A.
3300 EXPECT_TRUE(NavigateToURL(shell(), url_a));
3301 RenderFrameHostImpl* rfh_a = current_frame_host();
3302 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
3303 StartRecordingEvents(rfh_a);
3304
3305 // 2) Navigate to B.
3306 EXPECT_TRUE(ExecJs(shell(), JsReplace("location = $1;", url_b.spec())));
3307 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
3308 RenderFrameHostImpl* rfh_b = current_frame_host();
3309 RenderFrameDeletedObserver delete_observer_rfh_b(rfh_b);
3310
3311 EXPECT_FALSE(delete_observer_rfh_a.deleted());
3312 EXPECT_FALSE(delete_observer_rfh_b.deleted());
3313 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
3314 EXPECT_FALSE(rfh_b->IsInBackForwardCache());
3315 // TODO(yuzus): Post message to the frozen page, and make sure that the
3316 // messages arrive after the page visibility events, not before them.
3317
3318 // 3) Go back to A. Confirm that expected events are fired.
3319 web_contents()->GetController().GoBack();
3320 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
3321 EXPECT_FALSE(delete_observer_rfh_a.deleted());
3322 EXPECT_FALSE(delete_observer_rfh_b.deleted());
3323 EXPECT_EQ(rfh_a, current_frame_host());
3324 // visibilitychange events are added twice per each because it is fired for
3325 // both window and document.
3326 MatchEventList(
3327 rfh_a,
3328 ListValueOf("window.pagehide.persisted", "document.visibilitychange",
3329 "window.visibilitychange", "document.freeze",
3330 "document.resume", "document.visibilitychange",
3331 "window.visibilitychange", "window.pageshow.persisted"));
3332 }
3333
3334 // Track the events dispatched when a page is deemed ineligible for back-forward
3335 // cache after we've dispatched the 'pagehide' event with persisted set to true.
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,EventsForPageIneligibleAfterPagehidePersisted)3336 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
3337 EventsForPageIneligibleAfterPagehidePersisted) {
3338 ASSERT_TRUE(CreateHttpsServer()->Start());
3339 GURL url_1(https_server()->GetURL("a.com", "/title1.html"));
3340 GURL url_2(https_server()->GetURL("a.com", "/title2.html"));
3341
3342 // 1) Navigate to |url_1|.
3343 EXPECT_TRUE(NavigateToURL(shell(), url_1));
3344 RenderFrameHostImpl* rfh_1 = current_frame_host();
3345 RenderFrameDeletedObserver delete_observer_rfh_1(rfh_1);
3346 // 2) Use WebRTC (a non-sticky blocklisted feature), so that we would still do
3347 // a RFH swap on same-site navigation and fire the 'pagehide' event during
3348 // commit of the new page with 'persisted' set to true, but the page will not
3349 // be eligible for back-forward cache after commit.
3350 EXPECT_TRUE(ExecJs(rfh_1, "new RTCPeerConnection()"));
3351
3352 EXPECT_TRUE(ExecJs(rfh_1, R"(
3353 window.onpagehide = (e) => {
3354 if (e.persisted) {
3355 window.domAutomationController.send('pagehide.persisted');
3356 }
3357 }
3358 document.onvisibilitychange = () => {
3359 if (document.visibilityState == 'hidden') {
3360 window.domAutomationController.send('visibilitychange.hidden');
3361 }
3362 }
3363 window.onunload = () => {
3364 window.domAutomationController.send('unload');
3365 }
3366 )"));
3367
3368 DOMMessageQueue dom_message_queue(shell()->web_contents());
3369 // 3) Navigate to |url_2|.
3370 EXPECT_TRUE(NavigateToURL(shell(), url_2));
3371 // |rfh_1| will not get into the back-forward cache and eventually get deleted
3372 // because it uses a blocklisted feature.
3373 delete_observer_rfh_1.WaitUntilDeleted();
3374
3375 // Only the pagehide and visibilitychange events will be dispatched.
3376 int num_messages_received = 0;
3377 std::string expected_messages[] = {"\"pagehide.persisted\"",
3378 "\"visibilitychange.hidden\""};
3379 std::string message;
3380 while (dom_message_queue.PopMessage(&message)) {
3381 EXPECT_EQ(expected_messages[num_messages_received], message);
3382 num_messages_received++;
3383 }
3384 EXPECT_EQ(num_messages_received, 2);
3385 }
3386
3387 // Track the events dispatched when a page is deemed ineligible for back-forward
3388 // cache before we've dispatched the pagehide event on it.
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,EventsForPageIneligibleBeforePagehide)3389 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
3390 EventsForPageIneligibleBeforePagehide) {
3391 ASSERT_TRUE(CreateHttpsServer()->Start());
3392 GURL url_1(https_server()->GetURL("a.com", "/title1.html"));
3393 GURL url_2(https_server()->GetURL("b.com", "/title2.html"));
3394
3395 // 1) Navigate to |url_1|.
3396 EXPECT_TRUE(NavigateToURL(shell(), url_1));
3397 RenderFrameHostImpl* rfh_1 = current_frame_host();
3398 RenderFrameDeletedObserver delete_observer_rfh_1(rfh_1);
3399 // 2) Use keyboard lock (a sticky blocklisted feature), so that the page is
3400 // known to be ineligible for bfcache at commit time, before we dispatch the
3401 // pagehide event.
3402 EXPECT_TRUE(ExecJs(rfh_1, R"(
3403 new Promise(resolve => {
3404 navigator.keyboard.lock();
3405 resolve();
3406 });
3407 )"));
3408
3409 EXPECT_TRUE(ExecJs(rfh_1, R"(
3410 window.onpagehide = (e) => {
3411 if (!e.persisted) {
3412 window.domAutomationController.send('pagehide.not_persisted');
3413 }
3414 }
3415 document.onvisibilitychange = () => {
3416 if (document.visibilityState == 'hidden') {
3417 window.domAutomationController.send('visibilitychange.hidden');
3418 }
3419 }
3420 window.onunload = () => {
3421 window.domAutomationController.send('unload');
3422 }
3423 )"));
3424
3425 DOMMessageQueue dom_message_queue(shell()->web_contents());
3426 // 3) Navigate to |url_2|.
3427 EXPECT_TRUE(NavigateToURL(shell(), url_2));
3428 // |rfh_1| will not get into the back-forward cache and eventually get deleted
3429 // because it uses a blocklisted feature.
3430 delete_observer_rfh_1.WaitUntilDeleted();
3431
3432 // "pagehide", "visibilitychange", and "unload" events will be dispatched.
3433 int num_messages_received = 0;
3434 std::string expected_messages[] = {"\"pagehide.not_persisted\"",
3435 "\"visibilitychange.hidden\"",
3436 "\"unload\""};
3437 std::string message;
3438 while (dom_message_queue.PopMessage(&message)) {
3439 EXPECT_EQ(expected_messages[num_messages_received], message);
3440 num_messages_received++;
3441 }
3442 EXPECT_EQ(num_messages_received, 3);
3443 }
3444
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,EvictPageWithInfiniteLoop)3445 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, EvictPageWithInfiniteLoop) {
3446 ASSERT_TRUE(embedded_test_server()->Start());
3447 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
3448 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
3449
3450 // 1) Navigate to A.
3451 EXPECT_TRUE(NavigateToURL(shell(), url_a));
3452 RenderFrameHostImpl* rfh_a = current_frame_host();
3453
3454 ExecuteScriptAsync(rfh_a, R"(
3455 let i = 0;
3456 while (true) { i++; }
3457 )");
3458
3459 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
3460 RenderProcessHost* process = rfh_a->GetProcess();
3461 RenderProcessHostWatcher destruction_observer(
3462 process, RenderProcessHostWatcher::WATCH_FOR_HOST_DESTRUCTION);
3463
3464 // 2) Navigate to B.
3465 EXPECT_TRUE(NavigateToURL(shell(), url_b));
3466 RenderFrameHostImpl* rfh_b = current_frame_host();
3467 RenderFrameDeletedObserver delete_observer_rfh_b(rfh_b);
3468
3469 // rfh_a should be destroyed (not kept in the cache).
3470 destruction_observer.Wait();
3471 delete_observer_rfh_a.WaitUntilDeleted();
3472
3473 // rfh_b should still be the current frame.
3474 EXPECT_EQ(current_frame_host(), rfh_b);
3475 EXPECT_FALSE(delete_observer_rfh_b.deleted());
3476
3477 // 3) Go back to A.
3478 web_contents()->GetController().GoBack();
3479 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
3480 ExpectOutcome(BackForwardCacheMetrics::HistoryNavigationOutcome::kNotRestored,
3481 FROM_HERE);
3482 ExpectNotRestored(
3483 {BackForwardCacheMetrics::NotRestoredReason::kTimeoutPuttingInCache},
3484 FROM_HERE);
3485 }
3486
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,NavigationCancelledAtWillStartRequest)3487 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
3488 NavigationCancelledAtWillStartRequest) {
3489 ASSERT_TRUE(embedded_test_server()->Start());
3490 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
3491 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
3492
3493 // 1) Navigate to A.
3494 EXPECT_TRUE(NavigateToURL(shell(), url_a));
3495 RenderFrameHostImpl* rfh_a = current_frame_host();
3496 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
3497
3498 // 2) Navigate to B.
3499 EXPECT_TRUE(NavigateToURL(shell(), url_b));
3500 RenderFrameHostImpl* rfh_b = current_frame_host();
3501 EXPECT_FALSE(delete_observer_rfh_a.deleted());
3502 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
3503
3504 // Cancel all navigation attempts.
3505 content::TestNavigationThrottleInserter throttle_inserter(
3506 shell()->web_contents(),
3507 base::BindLambdaForTesting(
3508 [&](NavigationHandle* handle) -> std::unique_ptr<NavigationThrottle> {
3509 auto throttle = std::make_unique<TestNavigationThrottle>(handle);
3510 throttle->SetResponse(TestNavigationThrottle::WILL_START_REQUEST,
3511 TestNavigationThrottle::SYNCHRONOUS,
3512 NavigationThrottle::CANCEL_AND_IGNORE);
3513 return throttle;
3514 }));
3515
3516 // 3) Go back to A, which will be cancelled by the NavigationThrottle.
3517 web_contents()->GetController().GoBack();
3518 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
3519
3520 // We should still be showing page B.
3521 EXPECT_EQ(rfh_b, current_frame_host());
3522 }
3523
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,NavigationCancelledAtWillProcessResponse)3524 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
3525 NavigationCancelledAtWillProcessResponse) {
3526 ASSERT_TRUE(embedded_test_server()->Start());
3527 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
3528 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
3529
3530 // 1) Navigate to A.
3531 EXPECT_TRUE(NavigateToURL(shell(), url_a));
3532 RenderFrameHostImpl* rfh_a = current_frame_host();
3533 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
3534
3535 // 2) Navigate to B.
3536 EXPECT_TRUE(NavigateToURL(shell(), url_b));
3537 RenderFrameHostImpl* rfh_b = current_frame_host();
3538 EXPECT_FALSE(delete_observer_rfh_a.deleted());
3539 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
3540
3541 // Cancel all navigation attempts.
3542 content::TestNavigationThrottleInserter throttle_inserter(
3543 shell()->web_contents(),
3544 base::BindLambdaForTesting(
3545 [&](NavigationHandle* handle) -> std::unique_ptr<NavigationThrottle> {
3546 auto throttle = std::make_unique<TestNavigationThrottle>(handle);
3547 throttle->SetResponse(TestNavigationThrottle::WILL_PROCESS_RESPONSE,
3548 TestNavigationThrottle::SYNCHRONOUS,
3549 NavigationThrottle::CANCEL_AND_IGNORE);
3550 return throttle;
3551 }));
3552
3553 // 3) Go back to A, which will be cancelled by the NavigationThrottle.
3554 web_contents()->GetController().GoBack();
3555 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
3556
3557 // We should still be showing page B.
3558 EXPECT_EQ(rfh_b, current_frame_host());
3559 }
3560
3561 // Test the race condition where a document is evicted from the BackForwardCache
3562 // while it is in the middle of being restored.
3563 //
3564 // ┌───────┐ ┌────────┐
3565 // │Browser│ │Renderer│
3566 // └───┬───┘ └───┬────┘
3567 // (Freeze & store the cache) │
3568 // │────────────────────────>│
3569 // │ │
3570 // (Navigate to cached document) │
3571 // │──┐ │
3572 // │ │ │
3573 // │EvictFromBackForwardCache│
3574 // │<────────────────────────│
3575 // │ │ │
3576 // │ x Navigation cancelled │
3577 // │ and reissued │
3578 // ┌───┴───┐ ┌───┴────┐
3579 // │Browser│ │Renderer│
3580 // └───────┘ └────────┘
3581 //
3582 // When the eviction occurs, the in flight NavigationRequest to the cached
3583 // document should be reissued (cancelled and replaced by a normal navigation).
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,ReissuesNavigationIfEvictedDuringNavigation)3584 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
3585 ReissuesNavigationIfEvictedDuringNavigation) {
3586 ASSERT_TRUE(embedded_test_server()->Start());
3587 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
3588 GURL url_b(embedded_test_server()->GetURL("b.com", "/title2.html"));
3589
3590 // 1) Navigate to page A.
3591 EXPECT_TRUE(NavigateToURL(shell(), url_a));
3592 RenderFrameHostImpl* rfh_a = current_frame_host();
3593 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
3594
3595 // 2) Navigate to page B.
3596 EXPECT_TRUE(NavigateToURL(shell(), url_b));
3597 RenderFrameHostImpl* rfh_b = current_frame_host();
3598 RenderFrameDeletedObserver delete_observer_rfh_b(rfh_b);
3599 EXPECT_FALSE(delete_observer_rfh_a.deleted());
3600 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
3601 EXPECT_NE(rfh_a, rfh_b);
3602
3603 // 3) Start navigation to page A, and cause the document to be evicted during
3604 // the navigation.
3605 TestNavigationManager navigation_manager(shell()->web_contents(), url_a);
3606 web_contents()->GetController().GoBack();
3607
3608 EXPECT_TRUE(navigation_manager.WaitForRequestStart());
3609 // Try to execute javascript, this will cause the document we are restoring to
3610 // get evicted from the cache.
3611 EvictByJavaScript(rfh_a);
3612
3613 // The navigation should get reissued, and ultimately finish.
3614 navigation_manager.WaitForNavigationFinished();
3615
3616 // rfh_a should have been deleted, and page A navigated to normally.
3617 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
3618 delete_observer_rfh_a.WaitUntilDeleted();
3619 RenderFrameHostImpl* rfh_a2 = current_frame_host();
3620 EXPECT_NE(rfh_a2, rfh_b);
3621 EXPECT_EQ(rfh_a2->GetLastCommittedURL(), url_a);
3622
3623 ExpectOutcome(BackForwardCacheMetrics::HistoryNavigationOutcome::kNotRestored,
3624 FROM_HERE);
3625 ExpectNotRestored(
3626 {BackForwardCacheMetrics::NotRestoredReason::kJavaScriptExecution},
3627 FROM_HERE);
3628 }
3629
3630 // Same test as above, but with eviction happening before URL loader starts a
3631 // response.
3632 // Flaky on most platforms (see crbug.com/1136683)
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,DISABLED_ReissuesNavigationIfEvictedDuringNavigation_BeforeResponse)3633 IN_PROC_BROWSER_TEST_F(
3634 BackForwardCacheBrowserTest,
3635 DISABLED_ReissuesNavigationIfEvictedDuringNavigation_BeforeResponse) {
3636 ASSERT_TRUE(embedded_test_server()->Start());
3637 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
3638 GURL url_b(embedded_test_server()->GetURL("b.com", "/title2.html"));
3639
3640 // 1) Navigate to page A.
3641 EXPECT_TRUE(NavigateToURL(shell(), url_a));
3642 RenderFrameHostImpl* rfh_a = current_frame_host();
3643 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
3644
3645 // 2) Navigate to page B.
3646 EXPECT_TRUE(NavigateToURL(shell(), url_b));
3647 RenderFrameHostImpl* rfh_b = current_frame_host();
3648 RenderFrameDeletedObserver delete_observer_rfh_b(rfh_b);
3649 EXPECT_FALSE(delete_observer_rfh_a.deleted());
3650 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
3651 EXPECT_NE(rfh_a, rfh_b);
3652
3653 // 3) Start navigation to page A, and cause the document to be evicted during
3654 // the navigation immediately before navigation makes any meaningful progress.
3655 web_contents()->GetController().GoBack();
3656 EvictByJavaScript(rfh_a);
3657
3658 // rfh_a should have been deleted, and page A navigated to normally.
3659 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
3660 delete_observer_rfh_a.WaitUntilDeleted();
3661 RenderFrameHostImpl* rfh_a2 = current_frame_host();
3662 EXPECT_NE(rfh_a2, rfh_b);
3663 EXPECT_EQ(rfh_a2->GetLastCommittedURL(), url_a);
3664
3665 ExpectOutcome(BackForwardCacheMetrics::HistoryNavigationOutcome::kNotRestored,
3666 FROM_HERE);
3667 ExpectNotRestored(
3668 {BackForwardCacheMetrics::NotRestoredReason::kJavaScriptExecution},
3669 FROM_HERE);
3670 }
3671
3672 // Similar to ReissuesNavigationIfEvictedDuringNavigation, except that
3673 // BackForwardCache::Flush is the source of the eviction.
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,FlushCacheDuringNavigationToCachedPage)3674 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
3675 FlushCacheDuringNavigationToCachedPage) {
3676 ASSERT_TRUE(embedded_test_server()->Start());
3677 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
3678 GURL url_b(embedded_test_server()->GetURL("b.com", "/title2.html"));
3679
3680 // 1) Navigate to page A.
3681 EXPECT_TRUE(NavigateToURL(shell(), url_a));
3682 RenderFrameHostImpl* rfh_a1 = current_frame_host();
3683 RenderFrameDeletedObserver delete_observer_rfh_a1(rfh_a1);
3684
3685 // 2) Navigate to page B.
3686 EXPECT_TRUE(NavigateToURL(shell(), url_b));
3687 RenderFrameHostImpl* rfh_b2 = current_frame_host();
3688 RenderFrameDeletedObserver delete_observer_rfh_b2(rfh_b2);
3689 EXPECT_FALSE(delete_observer_rfh_a1.deleted());
3690 EXPECT_TRUE(rfh_a1->IsInBackForwardCache());
3691 EXPECT_NE(rfh_a1, rfh_b2);
3692
3693 // 3) Start navigation to page A, and flush the cache during the navigation.
3694 TestNavigationManager navigation_manager(shell()->web_contents(), url_a);
3695 web_contents()->GetController().GoBack();
3696
3697 EXPECT_TRUE(navigation_manager.WaitForRequestStart());
3698
3699 // Flush the cache, which contains the document being navigated to.
3700 web_contents()->GetController().GetBackForwardCache().Flush();
3701
3702 // The navigation should get canceled, then reissued; ultimately resulting in
3703 // a successful navigation using a new RenderFrameHost.
3704 navigation_manager.WaitForNavigationFinished();
3705
3706 // rfh_a should have been deleted, and page A navigated to normally.
3707 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
3708 delete_observer_rfh_a1.WaitUntilDeleted();
3709 EXPECT_TRUE(rfh_b2->IsInBackForwardCache());
3710 RenderFrameHostImpl* rfh_a3 = current_frame_host();
3711 EXPECT_EQ(rfh_a3->GetLastCommittedURL(), url_a);
3712 }
3713
3714 // Test that if the renderer process crashes while a document is in the
3715 // BackForwardCache, it gets evicted.
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,EvictsFromCacheIfRendererProcessCrashes)3716 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
3717 EvictsFromCacheIfRendererProcessCrashes) {
3718 ASSERT_TRUE(embedded_test_server()->Start());
3719 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
3720 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
3721
3722 // 1) Navigate to A.
3723 EXPECT_TRUE(NavigateToURL(shell(), url_a));
3724 RenderFrameHostImpl* rfh_a = current_frame_host();
3725 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
3726
3727 // 2) Navigate to B.
3728 EXPECT_TRUE(NavigateToURL(shell(), url_b));
3729 RenderFrameHostImpl* rfh_b = current_frame_host();
3730 RenderFrameDeletedObserver delete_observer_rfh_b(rfh_b);
3731
3732 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
3733 EXPECT_FALSE(delete_observer_rfh_a.deleted());
3734
3735 // 3) Crash A's renderer process while it is in the cache.
3736 RenderProcessHost* process = rfh_a->GetProcess();
3737 RenderProcessHostWatcher crash_observer(
3738 process, RenderProcessHostWatcher::WATCH_FOR_HOST_DESTRUCTION);
3739 rfh_a->GetProcess()->Shutdown(0);
3740
3741 // The cached RenderFrameHost should be destroyed (not kept in the cache).
3742 crash_observer.Wait();
3743 delete_observer_rfh_a.WaitUntilDeleted();
3744
3745 // rfh_b should still be the current frame.
3746 EXPECT_EQ(current_frame_host(), rfh_b);
3747 EXPECT_FALSE(delete_observer_rfh_b.deleted());
3748
3749 // 4) Go back to A.
3750 web_contents()->GetController().GoBack();
3751 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
3752 ExpectOutcome(BackForwardCacheMetrics::HistoryNavigationOutcome::kNotRestored,
3753 FROM_HERE);
3754 ExpectNotRestored(
3755 {BackForwardCacheMetrics::NotRestoredReason::kRendererProcessKilled},
3756 FROM_HERE);
3757 }
3758
3759 // The test is simulating a race condition. The scheduler tracked features are
3760 // updated during the "freeze" event in a way that would have prevented the
3761 // document from entering the BackForwardCache in the first place.
3762 //
3763 // TODO(https://crbug.com/996267): The document should be evicted.
3764 //
3765 // ┌───────┐ ┌────────┐
3766 // │browser│ │renderer│
3767 // └───┬───┘ └────┬───┘
3768 // (enter cache) │
3769 // │ Freeze() │
3770 // │─────────────────────────────>│
3771 // │ (onfreeze)
3772 // │OnSchedulerTrackedFeaturesUsed│
3773 // │<─────────────────────────────│
3774 // │ (frozen)
3775 // │ │
3776 // ┌───┴───┐ ┌────┴───┐
3777 // │browser│ │renderer│
3778 // └───────┘ └────────┘
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,SchedulerTrackedFeaturesUpdatedWhileStoring)3779 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
3780 SchedulerTrackedFeaturesUpdatedWhileStoring) {
3781 ASSERT_TRUE(embedded_test_server()->Start());
3782
3783 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
3784 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
3785
3786 // 1) Navigate to A.
3787 EXPECT_TRUE(NavigateToURL(shell(), url_a));
3788 RenderFrameHostImpl* rfh_a = current_frame_host();
3789 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
3790
3791 // When the page will enter the BackForwardCache, just before being frozen,
3792 // use a feature that would have been prevented the document from being
3793 // cached.
3794 EXPECT_TRUE(ExecJs(rfh_a, R"(
3795 document.addEventListener('freeze', event => {
3796 new RTCPeerConnection();
3797 });
3798 )"));
3799
3800 // 2) Navigate to B.
3801 EXPECT_TRUE(NavigateToURL(shell(), url_b));
3802
3803 // rfh_a should be evicted from the cache and destroyed.
3804 delete_observer_rfh_a.WaitUntilDeleted();
3805 }
3806
3807 // A fetch request starts during the "freeze" event. The current behavior is to
3808 // send the request anyway. However evicting the page from the BackForwardCache
3809 // might be a better behavior.
3810 //
3811 // ┌───────┐┌────────┐ ┌───────────────┐
3812 // │browser││renderer│ │network service│
3813 // └───┬───┘└───┬────┘ └───────┬───────┘
3814 // │Freeze()│ │
3815 // │───────>│ │
3816 // │ (onfreeze) │
3817 // │ │CreateLoaderAndStart│
3818 // │ │───────────────────>│
3819 // │ (frozen) │
3820 // ┌───┴───┐┌───┴────┐ ┌───────┴───────┐
3821 // │browser││renderer│ │network service│
3822 // └───────┘└────────┘ └───────────────┘
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,FetchWhileStoring)3823 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, FetchWhileStoring) {
3824 net::test_server::ControllableHttpResponse fetch_response(
3825 embedded_test_server(), "/fetch");
3826 ASSERT_TRUE(embedded_test_server()->Start());
3827
3828 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
3829 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
3830
3831 // 1) Navigate to A.
3832 EXPECT_TRUE(NavigateToURL(shell(), url_a));
3833 RenderFrameHostImpl* rfh_a = current_frame_host();
3834 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
3835
3836 // Use "fetch" immediately before being frozen.
3837 EXPECT_TRUE(ExecJs(rfh_a, R"(
3838 document.addEventListener('freeze', event => {
3839 my_fetch = fetch('/fetch', { keepalive: true});
3840 });
3841 )"));
3842
3843 // 2) Navigate to B.
3844 EXPECT_TRUE(NavigateToURL(shell(), url_b));
3845
3846 fetch_response.WaitForRequest();
3847 fetch_response.Send(net::HTTP_OK, "text/html", "TheResponse");
3848 fetch_response.Done();
3849
3850 // 3) Go back to A.
3851 web_contents()->GetController().GoBack();
3852 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
3853 delete_observer_rfh_a.WaitUntilDeleted();
3854 }
3855
3856 class BackForwardCacheBrowserTestWithUnfreezableLoading
3857 : public BackForwardCacheBrowserTest {
3858 public:
3859 BackForwardCacheBrowserTestWithUnfreezableLoading() = default;
3860 ~BackForwardCacheBrowserTestWithUnfreezableLoading() override = default;
3861
3862 protected:
SetUpCommandLine(base::CommandLine * command_line)3863 void SetUpCommandLine(base::CommandLine* command_line) override {
3864 EnableFeatureAndSetParams(blink::features::kLoadingTasksUnfreezable,
3865 "max_buffered_bytes",
3866 base::NumberToString(kMaxBufferedBytes));
3867 EnableFeatureAndSetParams(
3868 blink::features::kLoadingTasksUnfreezable,
3869 "grace_period_to_finish_loading_in_seconds",
3870 base::NumberToString(kGracePeriodToFinishLoading.InSeconds()));
3871 BackForwardCacheBrowserTest::SetUpCommandLine(command_line);
3872 }
3873
3874 // Navigates to a page at |page_url| with an img element with src set to
3875 // "image.png".
NavigateToPageWithImage(const GURL & page_url)3876 RenderFrameHostImpl* NavigateToPageWithImage(const GURL& page_url) {
3877 EXPECT_TRUE(NavigateToURL(shell(), page_url));
3878 RenderFrameHostImpl* rfh = current_frame_host();
3879 // Wait for the document to load DOM to ensure that kLoading is not
3880 // one of the reasons why the document wasn't cached.
3881 WaitForDOMContentLoaded(rfh);
3882
3883 EXPECT_TRUE(ExecJs(rfh, R"(
3884 var image = document.createElement("img");
3885 image.src = "image.png";
3886 document.body.appendChild(image);
3887
3888 var image_load_status = new Promise((resolve, reject) => {
3889 image.onload = () => { resolve("loaded"); }
3890 image.onerror = () => { resolve("error"); }
3891 });
3892 )"));
3893 return rfh;
3894 }
3895
3896 const int kMaxBufferedBytes = 7000;
3897 const base::TimeDelta kGracePeriodToFinishLoading =
3898 base::TimeDelta::FromSeconds(5);
3899 };
3900
3901 // When loading task is unfreezable with the feature flag
3902 // kLoadingTaskUnfreezable, a page will keep processing the in-flight network
3903 // requests while the page is frozen in BackForwardCache.
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTestWithUnfreezableLoading,FetchWhileStoring)3904 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTestWithUnfreezableLoading,
3905 FetchWhileStoring) {
3906 net::test_server::ControllableHttpResponse fetch_response(
3907 embedded_test_server(), "/fetch");
3908 ASSERT_TRUE(embedded_test_server()->Start());
3909
3910 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
3911 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
3912
3913 // 1) Navigate to A.
3914 EXPECT_TRUE(NavigateToURL(shell(), url_a));
3915 RenderFrameHostImpl* rfh_a = current_frame_host();
3916 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
3917
3918 // Use "fetch" immediately before being frozen.
3919 EXPECT_TRUE(ExecJs(rfh_a, R"(
3920 document.addEventListener('freeze', event => {
3921 my_fetch = fetch('/fetch', { keepalive: true});
3922 });
3923 )"));
3924
3925 // 2) Navigate to B.
3926 EXPECT_TRUE(NavigateToURL(shell(), url_b));
3927
3928 fetch_response.WaitForRequest();
3929 fetch_response.Send(net::HTTP_OK, "text/html", "TheResponse");
3930 fetch_response.Done();
3931 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
3932 EXPECT_FALSE(delete_observer_rfh_a.deleted());
3933
3934 // 3) Go back to A.
3935 web_contents()->GetController().GoBack();
3936 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
3937 ExpectOutcome(BackForwardCacheMetrics::HistoryNavigationOutcome::kRestored,
3938 FROM_HERE);
3939 }
3940
3941 // Tests the case when the header was received before the page is frozen,
3942 // but parts of the response body is received when the page is frozen.
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTestWithUnfreezableLoading,PageWithDrainedDatapipeRequestsShouldBeEvicted)3943 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTestWithUnfreezableLoading,
3944 PageWithDrainedDatapipeRequestsShouldBeEvicted) {
3945 net::test_server::ControllableHttpResponse fetch_response(
3946 embedded_test_server(), "/fetch");
3947 ASSERT_TRUE(embedded_test_server()->Start());
3948
3949 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
3950 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
3951
3952 // 1) Navigate to A.
3953 EXPECT_TRUE(NavigateToURL(shell(), url_a));
3954 RenderFrameHostImpl* rfh_a = current_frame_host();
3955 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
3956
3957 // Call fetch before navigating away.
3958 EXPECT_TRUE(ExecJs(rfh_a, R"(
3959 var fetch_response_promise = my_fetch = fetch('/fetch').then(response => {
3960 return response.text();
3961 });
3962 )"));
3963 // Send response header and a piece of the body before navigating away.
3964 fetch_response.WaitForRequest();
3965 fetch_response.Send(net::HTTP_OK, "text/plain");
3966 fetch_response.Send("body");
3967
3968 // 2) Navigate to B.
3969 EXPECT_TRUE(NavigateToURL(shell(), url_b));
3970
3971 delete_observer_rfh_a.WaitUntilDeleted();
3972
3973 // 3) Go back to A.
3974 web_contents()->GetController().GoBack();
3975 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
3976 ExpectOutcome(BackForwardCacheMetrics::HistoryNavigationOutcome::kNotRestored,
3977 FROM_HERE);
3978 ExpectNotRestored({BackForwardCacheMetrics::NotRestoredReason::
3979 kNetworkRequestDatapipeDrained},
3980 FROM_HERE);
3981 }
3982
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTestWithUnfreezableLoading,ImageStillLoading_ResponseStartedWhileFrozen)3983 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTestWithUnfreezableLoading,
3984 ImageStillLoading_ResponseStartedWhileFrozen) {
3985 net::test_server::ControllableHttpResponse image_response(
3986 embedded_test_server(), "/image.png");
3987 ASSERT_TRUE(embedded_test_server()->Start());
3988
3989 // 1) Navigate to a page with an image with src == "image.png".
3990 RenderFrameHostImpl* rfh_1 = NavigateToPageWithImage(
3991 embedded_test_server()->GetURL("a.com", "/title1.html"));
3992 image_response.WaitForRequest();
3993
3994 // 2) Navigate away.
3995 EXPECT_TRUE(NavigateToURL(
3996 shell(), embedded_test_server()->GetURL("b.com", "/title2.html")));
3997 // The page was still loading when we navigated away, but it's still eligible
3998 // for back-forward cache.
3999 EXPECT_TRUE(rfh_1->IsInBackForwardCache());
4000
4001 // Start sending the image body while in the back-forward cache.
4002 image_response.Send(net::HTTP_OK, "image/png");
4003 image_response.Send("image_body");
4004 image_response.Done();
4005
4006 // 3) Go back to the first page. We should restore the page from the
4007 // back-forward cache.
4008 web_contents()->GetController().GoBack();
4009 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
4010 ExpectOutcome(BackForwardCacheMetrics::HistoryNavigationOutcome::kRestored,
4011 FROM_HERE);
4012
4013 // Wait until the deferred body is processed. Since it's not a valid image
4014 // value, we'll get the "error" event.
4015 EXPECT_EQ("error", EvalJs(rfh_1, "image_load_status"));
4016 }
4017
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTestWithUnfreezableLoading,ImageStillLoading_ResponseStartedWhileFrozen_ExceedsBytesLimit)4018 IN_PROC_BROWSER_TEST_F(
4019 BackForwardCacheBrowserTestWithUnfreezableLoading,
4020 ImageStillLoading_ResponseStartedWhileFrozen_ExceedsBytesLimit) {
4021 net::test_server::ControllableHttpResponse image_response(
4022 embedded_test_server(), "/image.png");
4023 ASSERT_TRUE(embedded_test_server()->Start());
4024
4025 // 1) Navigate to a page with an image with src == "image.png".
4026 RenderFrameHostImpl* rfh_1 = NavigateToPageWithImage(
4027 embedded_test_server()->GetURL("a.com", "/title1.html"));
4028
4029 // Wait for the image request, but don't send anything yet.
4030 image_response.WaitForRequest();
4031
4032 // 2) Navigate away.
4033 EXPECT_TRUE(NavigateToURL(
4034 shell(), embedded_test_server()->GetURL("b.com", "/title2.html")));
4035 // The page was still loading when we navigated away, but it's still eligible
4036 // for back-forward cache.
4037 EXPECT_TRUE(rfh_1->IsInBackForwardCache());
4038
4039 RenderFrameDeletedObserver delete_observer(rfh_1);
4040 // Start sending the image response while in the back-forward cache.
4041 image_response.Send(net::HTTP_OK, "image/png");
4042 std::string body(kMaxBufferedBytes + 1, '*');
4043 image_response.Send(body);
4044 image_response.Done();
4045 delete_observer.WaitUntilDeleted();
4046
4047 // 3) Go back to the first page. We should not restore the page from the
4048 // back-forward cache.
4049 web_contents()->GetController().GoBack();
4050 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
4051 ExpectOutcome(BackForwardCacheMetrics::HistoryNavigationOutcome::kNotRestored,
4052 FROM_HERE);
4053 ExpectNotRestored(
4054 {BackForwardCacheMetrics::NotRestoredReason::kNetworkExceedsBufferLimit},
4055 FROM_HERE);
4056 }
4057
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTestWithUnfreezableLoading,ImageStillLoading_ResponseStartedWhileFrozen_Timeout)4058 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTestWithUnfreezableLoading,
4059 ImageStillLoading_ResponseStartedWhileFrozen_Timeout) {
4060 net::test_server::ControllableHttpResponse image_response(
4061 embedded_test_server(), "/image.png");
4062 ASSERT_TRUE(embedded_test_server()->Start());
4063
4064 // 1) Navigate to a page with an image with src == "image.png".
4065 RenderFrameHostImpl* rfh_1 = NavigateToPageWithImage(
4066 embedded_test_server()->GetURL("a.com", "/title1.html"));
4067
4068 // Wait for the image request, but don't send anything yet.
4069 image_response.WaitForRequest();
4070
4071 // 2) Navigate away.
4072 EXPECT_TRUE(NavigateToURL(
4073 shell(), embedded_test_server()->GetURL("b.com", "/title2.html")));
4074 // The page was still loading when we navigated away, but it's still eligible
4075 // for back-forward cache.
4076 EXPECT_TRUE(rfh_1->IsInBackForwardCache());
4077
4078 RenderFrameDeletedObserver delete_observer(rfh_1);
4079 // Start sending the image response while in the back-forward cache, but never
4080 // finish the request. Eventually the page will get deleted due to network
4081 // request timeout.
4082 image_response.Send(net::HTTP_OK, "image/png");
4083 std::string body(kMaxBufferedBytes + 1, '*');
4084 delete_observer.WaitUntilDeleted();
4085
4086 // 3) Go back to the first page. We should not restore the page from the
4087 // back-forward cache.
4088 web_contents()->GetController().GoBack();
4089 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
4090 ExpectOutcome(BackForwardCacheMetrics::HistoryNavigationOutcome::kNotRestored,
4091 FROM_HERE);
4092 ExpectNotRestored(
4093 {BackForwardCacheMetrics::NotRestoredReason::kNetworkRequestTimeout},
4094 FROM_HERE);
4095 }
4096
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTestWithUnfreezableLoading,ImageStillLoading_ResponseStartedBeforeFreezing_ExceedsBytesLimit)4097 IN_PROC_BROWSER_TEST_F(
4098 BackForwardCacheBrowserTestWithUnfreezableLoading,
4099 ImageStillLoading_ResponseStartedBeforeFreezing_ExceedsBytesLimit) {
4100 net::test_server::ControllableHttpResponse image_response(
4101 embedded_test_server(), "/image.png");
4102 ASSERT_TRUE(embedded_test_server()->Start());
4103
4104 // 1) Navigate to a page with an image with src == "image.png".
4105 RenderFrameHostImpl* rfh_1 = NavigateToPageWithImage(
4106 embedded_test_server()->GetURL("a.com", "/title1.html"));
4107
4108 // Start sending response before the page gets in the back-forward cache.
4109 image_response.WaitForRequest();
4110 image_response.Send(net::HTTP_OK, "image/png");
4111 image_response.Send(" ");
4112 // Run some script to ensure the renderer processed its pending tasks.
4113 EXPECT_TRUE(ExecJs(rfh_1, "var foo = 42;"));
4114
4115 // 2) Navigate away.
4116 EXPECT_TRUE(NavigateToURL(
4117 shell(), embedded_test_server()->GetURL("b.com", "/title2.html")));
4118 // The page was still loading when we navigated away, but it's still eligible
4119 // for back-forward cache.
4120 EXPECT_TRUE(rfh_1->IsInBackForwardCache());
4121
4122 // Send the image response body while in the back-forward cache.
4123 RenderFrameDeletedObserver delete_observer(rfh_1);
4124 std::string body(kMaxBufferedBytes + 1, '*');
4125 image_response.Send(body);
4126 image_response.Done();
4127 delete_observer.WaitUntilDeleted();
4128
4129 // 3) Go back to the first page. We should not restore the page from the
4130 // back-forward cache.
4131 web_contents()->GetController().GoBack();
4132 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
4133 ExpectOutcome(BackForwardCacheMetrics::HistoryNavigationOutcome::kNotRestored,
4134 FROM_HERE);
4135 ExpectNotRestored(
4136 {BackForwardCacheMetrics::NotRestoredReason::kNetworkExceedsBufferLimit},
4137 FROM_HERE);
4138 }
4139
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTestWithUnfreezableLoading,TimeoutNotTriggeredAfterDone)4140 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTestWithUnfreezableLoading,
4141 TimeoutNotTriggeredAfterDone) {
4142 net::test_server::ControllableHttpResponse image_response(
4143 embedded_test_server(), "/image.png");
4144 ASSERT_TRUE(embedded_test_server()->Start());
4145 // 1) Navigate to a page with an image with src == "image.png".
4146 RenderFrameHostImpl* rfh_1 = NavigateToPageWithImage(
4147 embedded_test_server()->GetURL("a.com", "/title1.html"));
4148
4149 // Wait for the image request, but don't send anything yet.
4150 image_response.WaitForRequest();
4151
4152 // 2) Navigate away.
4153 EXPECT_TRUE(NavigateToURL(
4154 shell(), embedded_test_server()->GetURL("b.com", "/title2.html")));
4155 // The page was still loading when we navigated away, but it's still eligible
4156 // for back-forward cache.
4157 EXPECT_TRUE(rfh_1->IsInBackForwardCache());
4158
4159 RenderFrameDeletedObserver delete_observer(rfh_1);
4160 // Start sending the image response while in the back-forward cache and finish
4161 // the request before the active request timeout hits.
4162 image_response.Send(net::HTTP_OK, "image/png");
4163 image_response.Send(" ");
4164 image_response.Done();
4165
4166 // Make sure enough time passed to trigger network request eviction if the
4167 // load above didn't finish.
4168 base::RunLoop run_loop;
4169 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
4170 FROM_HERE, run_loop.QuitClosure(),
4171 kGracePeriodToFinishLoading + base::TimeDelta::FromSeconds(1));
4172 run_loop.Run();
4173
4174 // Ensure that the page is still in bfcache.
4175 EXPECT_FALSE(delete_observer.deleted());
4176 EXPECT_TRUE(rfh_1->IsInBackForwardCache());
4177
4178 // 3) Go back to the first page. We should restore the page from the
4179 // back-forward cache.
4180 web_contents()->GetController().GoBack();
4181 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
4182 ExpectOutcome(BackForwardCacheMetrics::HistoryNavigationOutcome::kRestored,
4183 FROM_HERE);
4184 }
4185
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTestWithUnfreezableLoading,TimeoutNotTriggeredAfterDone_ResponseStartedBeforeFreezing)4186 IN_PROC_BROWSER_TEST_F(
4187 BackForwardCacheBrowserTestWithUnfreezableLoading,
4188 TimeoutNotTriggeredAfterDone_ResponseStartedBeforeFreezing) {
4189 net::test_server::ControllableHttpResponse image_response(
4190 embedded_test_server(), "/image.png");
4191 ASSERT_TRUE(embedded_test_server()->Start());
4192 // 1) Navigate to a page with an image with src == "image.png".
4193 RenderFrameHostImpl* rfh_1 = NavigateToPageWithImage(
4194 embedded_test_server()->GetURL("a.com", "/title1.html"));
4195
4196 // Start sending response before the page gets in the back-forward cache.
4197 image_response.WaitForRequest();
4198 image_response.Send(net::HTTP_OK, "image/png");
4199 image_response.Send(" ");
4200
4201 // 2) Navigate away.
4202 EXPECT_TRUE(NavigateToURL(
4203 shell(), embedded_test_server()->GetURL("b.com", "/title2.html")));
4204 // The page was still loading when we navigated away, but it's still eligible
4205 // for back-forward cache.
4206 EXPECT_TRUE(rfh_1->IsInBackForwardCache());
4207
4208 RenderFrameDeletedObserver delete_observer(rfh_1);
4209 // Finish the request before the active request timeout hits.
4210 image_response.Done();
4211
4212 // Make sure enough time passed to trigger network request eviction if the
4213 // load above didn't finish.
4214 base::RunLoop run_loop;
4215 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
4216 FROM_HERE, run_loop.QuitClosure(),
4217 kGracePeriodToFinishLoading + base::TimeDelta::FromSeconds(1));
4218 run_loop.Run();
4219
4220 // Ensure that the page is still in bfcache.
4221 EXPECT_FALSE(delete_observer.deleted());
4222 EXPECT_TRUE(rfh_1->IsInBackForwardCache());
4223
4224 // 3) Go back to the first page. We should restore the page from the
4225 // back-forward cache.
4226 web_contents()->GetController().GoBack();
4227 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
4228 ExpectOutcome(BackForwardCacheMetrics::HistoryNavigationOutcome::kRestored,
4229 FROM_HERE);
4230 }
4231
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTestWithUnfreezableLoading,ImageStillLoading_ResponseStartedBeforeFreezing)4232 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTestWithUnfreezableLoading,
4233 ImageStillLoading_ResponseStartedBeforeFreezing) {
4234 net::test_server::ControllableHttpResponse image_response(
4235 embedded_test_server(), "/image.png");
4236 ASSERT_TRUE(embedded_test_server()->Start());
4237
4238 // 1) Navigate to a page with an image with src == "image.png".
4239 RenderFrameHostImpl* rfh_1 = NavigateToPageWithImage(
4240 embedded_test_server()->GetURL("a.com", "/title1.html"));
4241
4242 // Start sending response before the page gets in the back-forward cache.
4243 image_response.WaitForRequest();
4244 image_response.Send(net::HTTP_OK, "image/png");
4245 image_response.Send(" ");
4246 // Run some script to ensure the renderer processed its pending tasks.
4247 EXPECT_TRUE(ExecJs(rfh_1, "var foo = 42;"));
4248
4249 // 2) Navigate away.
4250 EXPECT_TRUE(NavigateToURL(
4251 shell(), embedded_test_server()->GetURL("b.com", "/title2.html")));
4252 // The page was still loading when we navigated away, but it's still eligible
4253 // for back-forward cache.
4254 EXPECT_TRUE(rfh_1->IsInBackForwardCache());
4255
4256 // Send body while in the back-forward cache.
4257 image_response.Send("image_body");
4258 image_response.Done();
4259
4260 // 3) Go back to the first page. We should restore the page from the
4261 // back-forward cache.
4262 web_contents()->GetController().GoBack();
4263 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
4264 ExpectOutcome(BackForwardCacheMetrics::HistoryNavigationOutcome::kRestored,
4265 FROM_HERE);
4266
4267 // Wait until the deferred body is processed. Since it's not a valid image
4268 // value, we'll get the "error" event.
4269 EXPECT_EQ("error", EvalJs(rfh_1, "image_load_status"));
4270 }
4271
4272 // Disabled on Android, since we have problems starting up the websocket test
4273 // server in the host
4274 #if defined(OS_ANDROID)
4275 #define MAYBE_WebSocketNotCached DISABLED_WebSocketNotCached
4276 #else
4277 #define MAYBE_WebSocketNotCached WebSocketNotCached
4278 #endif
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,MAYBE_WebSocketNotCached)4279 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, MAYBE_WebSocketNotCached) {
4280 net::SpawnedTestServer ws_server(net::SpawnedTestServer::TYPE_WS,
4281 net::GetWebSocketTestDataDirectory());
4282 ASSERT_TRUE(ws_server.Start());
4283
4284 ASSERT_TRUE(embedded_test_server()->Start());
4285
4286 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
4287 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
4288
4289 // 1) Navigate to A.
4290 ASSERT_TRUE(NavigateToURL(shell(), url_a));
4291 RenderFrameHostImpl* rfh_a = current_frame_host();
4292 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
4293
4294 // Open a WebSocket.
4295 const char script[] = R"(
4296 new Promise(resolve => {
4297 const socket = new WebSocket($1);
4298 socket.addEventListener('open', () => resolve());
4299 });)";
4300 ASSERT_TRUE(ExecJs(
4301 rfh_a, JsReplace(script, ws_server.GetURL("echo-with-no-extension"))));
4302
4303 // 2) Navigate to B.
4304 ASSERT_TRUE(NavigateToURL(shell(), url_b));
4305
4306 // Confirm A is evicted.
4307 delete_observer_rfh_a.WaitUntilDeleted();
4308 }
4309
4310 // Only HTTP/HTTPS main document can enter the BackForwardCache.
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,CacheHTTPDocumentOnly)4311 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, CacheHTTPDocumentOnly) {
4312 ASSERT_TRUE(embedded_test_server()->Start());
4313 ASSERT_TRUE(CreateHttpsServer()->Start());
4314
4315 GURL http_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
4316 GURL https_url(https_server()->GetURL("a.com", "/title1.html"));
4317 GURL file_url = net::FilePathToFileURL(GetTestFilePath("", "title1.html"));
4318 GURL data_url = GURL("data:text/html,");
4319 GURL blank_url = GURL(url::kAboutBlankURL);
4320 GURL webui_url = GetWebUIURL("gpu");
4321
4322 enum { STORED, DELETED };
4323 struct {
4324 int expectation;
4325 GURL url;
4326 } test_cases[] = {
4327 // Only document with HTTP/HTTPS URLs are allowed to enter the
4328 // BackForwardCache.
4329 {STORED, http_url},
4330 {STORED, https_url},
4331
4332 // Others aren't allowed.
4333 {DELETED, file_url},
4334 {DELETED, data_url},
4335 {DELETED, webui_url},
4336 {DELETED, blank_url},
4337 };
4338
4339 char hostname[] = "a.unique";
4340 for (auto& test_case : test_cases) {
4341 SCOPED_TRACE(testing::Message()
4342 << std::endl
4343 << "expectation = " << test_case.expectation << std::endl
4344 << "url = " << test_case.url << std::endl);
4345
4346 // 1) Navigate to.
4347 EXPECT_TRUE(NavigateToURL(shell(), test_case.url));
4348 RenderFrameHostImpl* rfh = current_frame_host();
4349 RenderFrameDeletedObserver delete_observer(rfh);
4350
4351 // 2) Navigate away.
4352 hostname[0]++;
4353 GURL reset_url(embedded_test_server()->GetURL(hostname, "/title1.html"));
4354 EXPECT_TRUE(NavigateToURL(shell(), reset_url));
4355
4356 if (test_case.expectation == STORED) {
4357 EXPECT_FALSE(delete_observer.deleted());
4358 EXPECT_TRUE(rfh->IsInBackForwardCache());
4359 continue;
4360 }
4361
4362 // On Android, navigations to about:blank keeps the same RenderFrameHost.
4363 // Obviously, it can't enter the BackForwardCache, because it is still used
4364 // to display the current document.
4365 if (test_case.url == blank_url &&
4366 !SiteIsolationPolicy::UseDedicatedProcessesForAllSites()) {
4367 EXPECT_FALSE(delete_observer.deleted());
4368 EXPECT_FALSE(rfh->IsInBackForwardCache());
4369 EXPECT_EQ(rfh, current_frame_host());
4370 continue;
4371 }
4372
4373 delete_observer.WaitUntilDeleted();
4374 }
4375 }
4376
4377 namespace {
4378
RegisterServiceWorker(RenderFrameHostImpl * rfh)4379 void RegisterServiceWorker(RenderFrameHostImpl* rfh) {
4380 EXPECT_EQ("success", EvalJs(rfh, R"(
4381 let controller_changed_promise = new Promise(resolve_controller_change => {
4382 navigator.serviceWorker.oncontrollerchange = resolve_controller_change;
4383 });
4384
4385 new Promise(async resolve => {
4386 try {
4387 await navigator.serviceWorker.register(
4388 "./service-worker.js", {scope: "./"})
4389 } catch (e) {
4390 resolve("error: registration has failed");
4391 }
4392
4393 await controller_changed_promise;
4394
4395 if (navigator.serviceWorker.controller) {
4396 resolve("success");
4397 } else {
4398 resolve("error: not controlled by service worker");
4399 }
4400 });
4401 )"));
4402 }
4403
4404 // Returns a unique script for each request, to test service worker update.
RequestHandlerForUpdateWorker(const net::test_server::HttpRequest & request)4405 std::unique_ptr<net::test_server::HttpResponse> RequestHandlerForUpdateWorker(
4406 const net::test_server::HttpRequest& request) {
4407 if (request.relative_url != "/back_forward_cache/service-worker.js")
4408 return std::unique_ptr<net::test_server::HttpResponse>();
4409 static int counter = 0;
4410 auto http_response = std::make_unique<net::test_server::BasicHttpResponse>();
4411 http_response->set_code(net::HTTP_OK);
4412 const char script[] = R"(
4413 // counter = $1
4414 self.addEventListener('activate', function(event) {
4415 event.waitUntil(self.clients.claim());
4416 });
4417 )";
4418 http_response->set_content(JsReplace(script, counter++));
4419 http_response->set_content_type("text/javascript");
4420 http_response->AddCustomHeader("Cache-Control",
4421 "no-cache, no-store, must-revalidate");
4422 return http_response;
4423 }
4424
4425 } // namespace
4426
4427 class BackForwardCacheBrowserTestWithVibration
4428 : public BackForwardCacheBrowserTest,
4429 public device::mojom::VibrationManager {
4430 public:
BackForwardCacheBrowserTestWithVibration()4431 BackForwardCacheBrowserTestWithVibration() {
4432 OverrideVibrationManagerBinderForTesting(base::BindRepeating(
4433 &BackForwardCacheBrowserTestWithVibration::BindVibrationManager,
4434 base::Unretained(this)));
4435 }
4436
~BackForwardCacheBrowserTestWithVibration()4437 ~BackForwardCacheBrowserTestWithVibration() override {
4438 OverrideVibrationManagerBinderForTesting(base::NullCallback());
4439 }
4440
BindVibrationManager(mojo::PendingReceiver<device::mojom::VibrationManager> receiver)4441 void BindVibrationManager(
4442 mojo::PendingReceiver<device::mojom::VibrationManager> receiver) {
4443 receiver_.Bind(std::move(receiver));
4444 }
4445
TriggerVibrate(RenderFrameHostImpl * rfh,int duration,base::OnceClosure vibrate_done)4446 bool TriggerVibrate(RenderFrameHostImpl* rfh,
4447 int duration,
4448 base::OnceClosure vibrate_done) {
4449 vibrate_done_ = std::move(vibrate_done);
4450 bool result;
4451 std::string script = "domAutomationController.send(navigator.vibrate(" +
4452 base::NumberToString(duration) + "))";
4453 EXPECT_TRUE(ExecuteScriptAndExtractBool(rfh, script, &result));
4454 return result;
4455 }
4456
TriggerShortVibrationSequence(RenderFrameHostImpl * rfh,base::OnceClosure vibrate_done)4457 bool TriggerShortVibrationSequence(RenderFrameHostImpl* rfh,
4458 base::OnceClosure vibrate_done) {
4459 vibrate_done_ = std::move(vibrate_done);
4460 bool result;
4461 std::string script =
4462 "domAutomationController.send(navigator.vibrate([10] * 1000))";
4463 EXPECT_TRUE(ExecuteScriptAndExtractBool(rfh, script, &result));
4464 return result;
4465 }
4466
IsCancelled()4467 bool IsCancelled() { return cancelled_; }
4468
4469 private:
4470 // device::mojom::VibrationManager:
Vibrate(int64_t milliseconds,VibrateCallback callback)4471 void Vibrate(int64_t milliseconds, VibrateCallback callback) override {
4472 cancelled_ = false;
4473 std::move(callback).Run();
4474 std::move(vibrate_done_).Run();
4475 }
4476
Cancel(CancelCallback callback)4477 void Cancel(CancelCallback callback) override {
4478 cancelled_ = true;
4479 std::move(callback).Run();
4480 }
4481
4482 bool cancelled_ = false;
4483 base::OnceClosure vibrate_done_;
4484 mojo::Receiver<device::mojom::VibrationManager> receiver_{this};
4485 };
4486
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTestWithVibration,VibrationStopsAfterEnteringCache)4487 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTestWithVibration,
4488 VibrationStopsAfterEnteringCache) {
4489 ASSERT_TRUE(embedded_test_server()->Start());
4490
4491 // 1) Navigate to a page with a long vibration.
4492 GURL url(embedded_test_server()->GetURL("a.com", "/title1.html"));
4493 EXPECT_TRUE(NavigateToURL(shell(), url));
4494 base::RunLoop run_loop;
4495 RenderFrameHostImpl* rfh_a = current_frame_host();
4496 ASSERT_TRUE(TriggerVibrate(rfh_a, 10000, run_loop.QuitClosure()));
4497 EXPECT_FALSE(IsCancelled());
4498
4499 // 2) Navigate away and expect the vibration to be canceled.
4500 EXPECT_TRUE(NavigateToURL(
4501 shell(), embedded_test_server()->GetURL("b.com", "/title1.html")));
4502 EXPECT_NE(current_frame_host(), rfh_a);
4503 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
4504 EXPECT_TRUE(IsCancelled());
4505
4506 // 3) Go back to A.
4507 web_contents()->GetController().GoBack();
4508 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
4509 ExpectOutcome(BackForwardCacheMetrics::HistoryNavigationOutcome::kRestored,
4510 FROM_HERE);
4511 }
4512
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTestWithVibration,ShortVibrationSequenceStopsAfterEnteringCache)4513 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTestWithVibration,
4514 ShortVibrationSequenceStopsAfterEnteringCache) {
4515 ASSERT_TRUE(embedded_test_server()->Start());
4516
4517 // 1) Navigate to a page with a long vibration.
4518 GURL url(embedded_test_server()->GetURL("a.com", "/title1.html"));
4519 EXPECT_TRUE(NavigateToURL(shell(), url));
4520 base::RunLoop run_loop;
4521 RenderFrameHostImpl* rfh_a = current_frame_host();
4522 ASSERT_TRUE(TriggerShortVibrationSequence(rfh_a, run_loop.QuitClosure()));
4523 EXPECT_FALSE(IsCancelled());
4524
4525 // 2) Navigate away and expect the vibration to be canceled.
4526 EXPECT_TRUE(NavigateToURL(
4527 shell(), embedded_test_server()->GetURL("b.com", "/title1.html")));
4528 EXPECT_NE(current_frame_host(), rfh_a);
4529 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
4530 EXPECT_TRUE(IsCancelled());
4531
4532 // 3) Go back to A.
4533 web_contents()->GetController().GoBack();
4534 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
4535 ExpectOutcome(BackForwardCacheMetrics::HistoryNavigationOutcome::kRestored,
4536 FROM_HERE);
4537 }
4538
4539 class BackForwardCacheBrowserTestWithServiceWorkerEnabled
4540 : public BackForwardCacheBrowserTest {
4541 public:
BackForwardCacheBrowserTestWithServiceWorkerEnabled()4542 BackForwardCacheBrowserTestWithServiceWorkerEnabled() {}
~BackForwardCacheBrowserTestWithServiceWorkerEnabled()4543 ~BackForwardCacheBrowserTestWithServiceWorkerEnabled() override {}
4544
4545 protected:
SetUpCommandLine(base::CommandLine * command_line)4546 void SetUpCommandLine(base::CommandLine* command_line) override {
4547 EnableFeatureAndSetParams(features::kBackForwardCache,
4548 "service_worker_supported", "true");
4549 BackForwardCacheBrowserTest::SetUpCommandLine(command_line);
4550 }
4551 };
4552
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTestWithServiceWorkerEnabled,CachedPagesWithServiceWorkers)4553 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTestWithServiceWorkerEnabled,
4554 CachedPagesWithServiceWorkers) {
4555 CreateHttpsServer();
4556 SetupCrossSiteRedirector(https_server());
4557 ASSERT_TRUE(https_server()->Start());
4558
4559 // 1) Navigate to A.
4560 EXPECT_TRUE(NavigateToURL(
4561 shell(),
4562 https_server()->GetURL("a.com", "/back_forward_cache/empty.html")));
4563
4564 // Register a service worker.
4565 RegisterServiceWorker(current_frame_host());
4566
4567 RenderFrameHostImpl* rfh_a = current_frame_host();
4568 RenderFrameDeletedObserver deleted(rfh_a);
4569
4570 // 2) Navigate away.
4571 EXPECT_TRUE(
4572 NavigateToURL(shell(), https_server()->GetURL("b.com", "/title1.html")));
4573
4574 EXPECT_FALSE(deleted.deleted());
4575 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
4576
4577 // 3) Go back to A. The navigation should be served from the cache.
4578 web_contents()->GetController().GoBack();
4579 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
4580 EXPECT_FALSE(deleted.deleted());
4581 EXPECT_EQ(rfh_a, current_frame_host());
4582 }
4583
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTestWithServiceWorkerEnabled,EvictIfCacheBlocksServiceWorkerVersionActivation)4584 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTestWithServiceWorkerEnabled,
4585 EvictIfCacheBlocksServiceWorkerVersionActivation) {
4586 CreateHttpsServer();
4587 https_server()->RegisterRequestHandler(
4588 base::BindRepeating(&RequestHandlerForUpdateWorker));
4589 SetupCrossSiteRedirector(https_server());
4590 ASSERT_TRUE(https_server()->Start());
4591 Shell* tab_x = shell();
4592 Shell* tab_y = CreateBrowser();
4593 // 1) Navigate to A in tab X.
4594 EXPECT_TRUE(NavigateToURL(
4595 tab_x,
4596 https_server()->GetURL("a.com", "/back_forward_cache/empty.html")));
4597 // 2) Register a service worker.
4598 RegisterServiceWorker(current_frame_host());
4599
4600 RenderFrameHostImpl* rfh_a = current_frame_host();
4601 RenderFrameDeletedObserver deleted(rfh_a);
4602 // 3) Navigate away to B in tab X.
4603 EXPECT_TRUE(
4604 NavigateToURL(tab_x, https_server()->GetURL("b.com", "/title1.html")));
4605 EXPECT_FALSE(deleted.deleted());
4606 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
4607 // 4) Navigate to A in tab Y.
4608 EXPECT_TRUE(NavigateToURL(
4609 tab_y,
4610 https_server()->GetURL("a.com", "/back_forward_cache/empty.html")));
4611 // 5) Close tab Y to activate a service worker version.
4612 // This should evict |rfh_a| from the cache.
4613 tab_y->Close();
4614 deleted.WaitUntilDeleted();
4615 // 6) Navigate to A in tab X.
4616 tab_x->web_contents()->GetController().GoBack();
4617 EXPECT_TRUE(WaitForLoadStop(tab_x->web_contents()));
4618 ExpectOutcome(BackForwardCacheMetrics::HistoryNavigationOutcome::kNotRestored,
4619 FROM_HERE);
4620 ExpectNotRestored(
4621 {
4622 BackForwardCacheMetrics::NotRestoredReason::
4623 kServiceWorkerVersionActivation,
4624 },
4625 FROM_HERE);
4626 }
4627
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTestWithServiceWorkerEnabled,EvictWithPostMessageToCachedClient)4628 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTestWithServiceWorkerEnabled,
4629 EvictWithPostMessageToCachedClient) {
4630 net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS);
4631 https_server.RegisterRequestHandler(
4632 base::BindRepeating(&RequestHandlerForUpdateWorker));
4633 https_server.AddDefaultHandlers(GetTestDataFilePath());
4634 https_server.SetSSLConfig(net::EmbeddedTestServer::CERT_OK);
4635 SetupCrossSiteRedirector(&https_server);
4636 ASSERT_TRUE(https_server.Start());
4637 Shell* tab_to_execute_service_worker = shell();
4638 Shell* tab_to_be_bfcached = CreateBrowser();
4639
4640 // Observe the new WebContents to trace the navigtion ID.
4641 WebContentsObserver::Observe(tab_to_be_bfcached->web_contents());
4642
4643 // 1) Navigate to A in |tab_to_execute_service_worker|.
4644 EXPECT_TRUE(NavigateToURL(
4645 tab_to_execute_service_worker,
4646 https_server.GetURL(
4647 "a.com", "/back_forward_cache/service_worker_post_message.html")));
4648
4649 // 2) Register a service worker.
4650 EXPECT_EQ("DONE", EvalJs(tab_to_execute_service_worker,
4651 "register('service_worker_post_message.js')"));
4652
4653 // 3) Navigate to A in |tab_to_be_bfcached|.
4654 EXPECT_TRUE(NavigateToURL(
4655 tab_to_be_bfcached,
4656 https_server.GetURL(
4657 "a.com", "/back_forward_cache/service_worker_post_message.html")));
4658 const std::string script_to_store =
4659 "executeCommandOnServiceWorker('StoreClients')";
4660 EXPECT_EQ("DONE", EvalJs(tab_to_execute_service_worker, script_to_store));
4661 RenderFrameHostImpl* rfh =
4662 static_cast<WebContentsImpl*>(tab_to_be_bfcached->web_contents())
4663 ->GetFrameTree()
4664 ->root()
4665 ->current_frame_host();
4666 RenderFrameDeletedObserver deleted_observer_rfh(rfh);
4667
4668 // 4) Navigate away to B in |tab_to_be_bfcached|.
4669 EXPECT_TRUE(NavigateToURL(tab_to_be_bfcached,
4670 https_server.GetURL("b.com", "/title1.html")));
4671 EXPECT_FALSE(deleted_observer_rfh.deleted());
4672 EXPECT_TRUE(rfh->IsInBackForwardCache());
4673
4674 // 5) Trigger client.postMessage via |tab_to_execute_service_worker|. Cache in
4675 // |tab_to_be_bfcached| will be evicted.
4676 const std::string script_to_post_message =
4677 "executeCommandOnServiceWorker('PostMessageToStoredClients')";
4678 EXPECT_EQ("DONE",
4679 EvalJs(tab_to_execute_service_worker, script_to_post_message));
4680 deleted_observer_rfh.WaitUntilDeleted();
4681
4682 // 6) Go back to A in |tab_to_be_bfcached|.
4683 tab_to_be_bfcached->web_contents()->GetController().GoBack();
4684 EXPECT_TRUE(WaitForLoadStop(tab_to_be_bfcached->web_contents()));
4685 ExpectOutcome(BackForwardCacheMetrics::HistoryNavigationOutcome::kNotRestored,
4686 FROM_HERE);
4687 ExpectNotRestored(
4688 {BackForwardCacheMetrics::NotRestoredReason::kServiceWorkerPostMessage},
4689 FROM_HERE);
4690 }
4691
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTestWithServiceWorkerEnabled,EvictOnServiceWorkerClaim)4692 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTestWithServiceWorkerEnabled,
4693 EvictOnServiceWorkerClaim) {
4694 net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS);
4695 https_server.RegisterRequestHandler(
4696 base::BindRepeating(&RequestHandlerForUpdateWorker));
4697 https_server.AddDefaultHandlers(GetTestDataFilePath());
4698 https_server.SetSSLConfig(net::EmbeddedTestServer::CERT_OK);
4699 SetupCrossSiteRedirector(&https_server);
4700 ASSERT_TRUE(https_server.Start());
4701
4702 Shell* tab_to_be_bfcached = shell();
4703 Shell* tab_to_execute_service_worker = CreateBrowser();
4704
4705 // 1) Navigate to A in |tab_to_be_bfcached|.
4706 EXPECT_TRUE(NavigateToURL(
4707 tab_to_be_bfcached,
4708 https_server.GetURL(
4709 "a.com", "/back_forward_cache/service_worker_registration.html")));
4710 RenderFrameHostImpl* rfh_a = current_frame_host();
4711 RenderFrameDeletedObserver deleted(rfh_a);
4712
4713 // 2) Navigate away to B in |tab_to_be_bfcached|.
4714 EXPECT_TRUE(NavigateToURL(tab_to_be_bfcached,
4715 https_server.GetURL("b.com", "/title1.html")));
4716 EXPECT_FALSE(deleted.deleted());
4717 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
4718
4719 // 3) Navigate to A in |tab_to_execute_service_worker|.
4720 EXPECT_TRUE(NavigateToURL(
4721 tab_to_execute_service_worker,
4722 https_server.GetURL(
4723 "a.com", "/back_forward_cache/service_worker_registration.html")));
4724
4725 // 4) Register a service worker for |tab_to_execute_service_worker|.
4726 EXPECT_EQ("DONE", EvalJs(tab_to_execute_service_worker,
4727 "register('service_worker_registration.js')"));
4728
4729 // 5) The service worker calls clients.claim(). |rfh_a| would normally be
4730 // claimed but because it's in bfcache, it is evicted from the cache.
4731 EXPECT_EQ("DONE", EvalJs(tab_to_execute_service_worker, "claim()"));
4732
4733 // 6) Navigate to A in |tab_to_be_bfcached|.
4734 tab_to_be_bfcached->web_contents()->GetController().GoBack();
4735 EXPECT_TRUE(WaitForLoadStop(tab_to_be_bfcached->web_contents()));
4736 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
4737 EXPECT_TRUE(deleted.deleted());
4738 ExpectOutcome(BackForwardCacheMetrics::HistoryNavigationOutcome::kNotRestored,
4739 FROM_HERE);
4740 ExpectNotRestored(
4741 {BackForwardCacheMetrics::NotRestoredReason::kServiceWorkerClaim},
4742 FROM_HERE);
4743 }
4744
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,CachePagesWithBeacon)4745 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, CachePagesWithBeacon) {
4746 constexpr char kKeepalivePath[] = "/keepalive";
4747
4748 net::test_server::ControllableHttpResponse keepalive(embedded_test_server(),
4749 kKeepalivePath);
4750 ASSERT_TRUE(embedded_test_server()->Start());
4751
4752 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
4753 GURL url_ping(embedded_test_server()->GetURL("a.com", kKeepalivePath));
4754
4755 // 1) Navigate to A.
4756 EXPECT_TRUE(NavigateToURL(shell(), url_a));
4757 RenderFrameHostImpl* rfh_a = current_frame_host();
4758 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
4759
4760 EXPECT_TRUE(
4761 ExecJs(shell(), JsReplace(R"(navigator.sendBeacon($1, "");)", url_ping)));
4762
4763 // 2) Navigate to B.
4764 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
4765 EXPECT_TRUE(NavigateToURL(shell(), url_b));
4766
4767 // Ensure that the keepalive request is sent.
4768 keepalive.WaitForRequest();
4769 // Don't actually send the response.
4770
4771 // Page A should be in the cache.
4772 EXPECT_FALSE(delete_observer_rfh_a.deleted());
4773 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
4774 }
4775
4776 // Regression test for https://crbug.com/993337.
4777 //
4778 // A note about sharing BrowsingInstances and the BackForwardCache:
4779 //
4780 // We should never keep around more than one main frame that belongs to the same
4781 // BrowsingInstance. When swapping two pages, when one is stored in the
4782 // back-forward cache or one is restored from it, the current code expects the
4783 // two to live in different BrowsingInstances.
4784 //
4785 // History navigation can recreate a page with the same BrowsingInstance as the
4786 // one stored in the back-forward cache. This case must to be handled. When it
4787 // happens, the back-forward cache page is evicted.
4788 //
4789 // Since cache eviction is asynchronous, it's is possible for two main frames
4790 // belonging to the same BrowsingInstance to be alive for a brief period of time
4791 // (the new page being navigated to, and a page in the cache, until it is
4792 // destroyed asynchronously via eviction).
4793 //
4794 // The test below tests that the brief period of time where two main frames are
4795 // alive in the same BrowsingInstance does not cause anything to blow up.
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,NavigateToTwoPagesOnSameSite)4796 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
4797 NavigateToTwoPagesOnSameSite) {
4798 ASSERT_TRUE(embedded_test_server()->Start());
4799 GURL url_a1(embedded_test_server()->GetURL("a.com", "/title1.html"));
4800 GURL url_a2(embedded_test_server()->GetURL("a.com", "/title2.html"));
4801 GURL url_b3(embedded_test_server()->GetURL("b.com", "/title1.html"));
4802
4803 // 1) Navigate to A1.
4804 EXPECT_TRUE(NavigateToURL(shell(), url_a1));
4805
4806 // 2) Navigate to A2.
4807 EXPECT_TRUE(NavigateToURL(shell(), url_a2));
4808 RenderFrameHostImpl* rfh_a2 = current_frame_host();
4809 RenderFrameDeletedObserver delete_rfh_a2(current_frame_host());
4810
4811 // 3) Navigate to B3.
4812 EXPECT_TRUE(NavigateToURL(shell(), url_b3));
4813 EXPECT_TRUE(rfh_a2->IsInBackForwardCache());
4814 RenderFrameHostImpl* rfh_b3 = current_frame_host();
4815
4816 // 4) Do a history navigation back to A1.
4817 web_contents()->GetController().GoToIndex(0);
4818 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
4819 EXPECT_TRUE(rfh_b3->IsInBackForwardCache());
4820
4821 // Note that the frame for A1 gets created before A2 is deleted from the
4822 // cache, so there will be a brief period where two the main frames (A1 and
4823 // A2) are alive in the same BrowsingInstance/SiteInstance, at the same time.
4824 // That is the scenario this test is covering. This used to cause a CHECK,
4825 // because the two main frames shared a single RenderViewHost (no longer the
4826 // case after https://crrev.com/c/1833616).
4827
4828 // A2 should be evicted from the cache and asynchronously deleted, due to the
4829 // cache size limit (B3 took its place in the cache).
4830 delete_rfh_a2.WaitUntilDeleted();
4831 }
4832
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,NavigateToTwoPagesOnSameSiteWithSubframes)4833 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
4834 NavigateToTwoPagesOnSameSiteWithSubframes) {
4835 ASSERT_TRUE(embedded_test_server()->Start());
4836 // This test covers the same scenario as NavigateToTwoPagesOnSameSite, except
4837 // the pages contain subframes:
4838 // A1(B) -> A2(B(C)) -> D3 -> A1(B)
4839 //
4840 // The subframes shouldn't make a difference, so the expected behavior is the
4841 // same as NavigateToTwoPagesOnSameSite.
4842 GURL url_a1(embedded_test_server()->GetURL(
4843 "a.com", "/cross_site_iframe_factory.html?a(b)"));
4844 GURL url_a2(embedded_test_server()->GetURL(
4845 "a.com", "/cross_site_iframe_factory.html?a(b(c))"));
4846 GURL url_d3(embedded_test_server()->GetURL("d.com", "/title1.html"));
4847
4848 // 1) Navigate to A1(B).
4849 EXPECT_TRUE(NavigateToURL(shell(), url_a1));
4850
4851 // 2) Navigate to A2(B(C)).
4852 EXPECT_TRUE(NavigateToURL(shell(), url_a2));
4853 RenderFrameHostImpl* rfh_a2 = current_frame_host();
4854 RenderFrameDeletedObserver delete_rfh_a2(current_frame_host());
4855
4856 // 3) Navigate to D3.
4857 EXPECT_TRUE(NavigateToURL(shell(), url_d3));
4858 EXPECT_TRUE(rfh_a2->IsInBackForwardCache());
4859 RenderFrameHostImpl* rfh_d3 = current_frame_host();
4860
4861 // 4) Do a history navigation back to A1(B).
4862 web_contents()->GetController().GoToIndex(0);
4863 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
4864
4865 // D3 takes A2(B(C))'s place in the cache.
4866 EXPECT_TRUE(rfh_d3->IsInBackForwardCache());
4867 delete_rfh_a2.WaitUntilDeleted();
4868 }
4869
4870 class BackForwardCacheBrowserTestWithSameSiteDisabled
4871 : public BackForwardCacheBrowserTest {
4872 public:
4873 BackForwardCacheBrowserTestWithSameSiteDisabled() = default;
4874 ~BackForwardCacheBrowserTestWithSameSiteDisabled() override = default;
4875
4876 protected:
SetUpCommandLine(base::CommandLine * command_line)4877 void SetUpCommandLine(base::CommandLine* command_line) override {
4878 same_site_back_forward_cache_enabled_ = false;
4879 DisableFeature(features::kProactivelySwapBrowsingInstance);
4880 BackForwardCacheBrowserTest::SetUpCommandLine(command_line);
4881 }
4882 };
4883
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTestWithSameSiteDisabled,ConflictingBrowsingInstances)4884 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTestWithSameSiteDisabled,
4885 ConflictingBrowsingInstances) {
4886 // This test assumes navigation from A1 to A2 will not switch
4887 // BrowsingInstances, which is not true when either BackForwardCache or
4888 // ProactivelySwapBrowsingInstance is enabled on same-site navigations.
4889 DCHECK(!CanSameSiteMainFrameNavigationsChangeSiteInstances());
4890 ASSERT_TRUE(embedded_test_server()->Start());
4891 GURL url_a1(embedded_test_server()->GetURL("a.com", "/title1.html"));
4892 GURL url_a2(embedded_test_server()->GetURL("a.com", "/title2.html"));
4893 GURL url_b3(embedded_test_server()->GetURL("b.com", "/title1.html"));
4894
4895 // 1) Navigate to A1.
4896 EXPECT_TRUE(NavigateToURL(shell(), url_a1));
4897
4898 // 2) Navigate to A2.
4899 EXPECT_TRUE(NavigateToURL(shell(), url_a2));
4900 RenderFrameHostImpl* rfh_a2 = current_frame_host();
4901 RenderFrameDeletedObserver delete_rfh_a2(current_frame_host());
4902
4903 // 3) Navigate to B3.
4904 EXPECT_TRUE(NavigateToURL(shell(), url_b3));
4905 EXPECT_TRUE(rfh_a2->IsInBackForwardCache());
4906 RenderFrameHostImpl* rfh_b3 = current_frame_host();
4907 // Make B3 ineligible for caching, so that navigating doesn't evict A2
4908 // due to the cache size limit.
4909 content::BackForwardCache::DisableForRenderFrameHost(
4910 rfh_b3, "BackForwardCacheBrowserTest");
4911
4912 // 4) Do a history navigation back to A1. At this point, A1 is going to have
4913 // the same BrowsingInstance as A2. This should cause A2 to get
4914 // evicted from the BackForwardCache due to its conflicting BrowsingInstance.
4915 web_contents()->GetController().GoToIndex(0);
4916 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
4917 EXPECT_EQ(current_frame_host()->GetLastCommittedURL(), url_a1);
4918 delete_rfh_a2.WaitUntilDeleted();
4919
4920 ExpectOutcome(BackForwardCacheMetrics::HistoryNavigationOutcome::kNotRestored,
4921 FROM_HERE);
4922 ExpectNotRestored(
4923 {
4924 BackForwardCacheMetrics::NotRestoredReason::
4925 kRenderFrameHostReused_SameSite,
4926 },
4927 FROM_HERE);
4928
4929 // 5) Go to A2.
4930 web_contents()->GetController().GoForward();
4931 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
4932
4933 ExpectOutcome(BackForwardCacheMetrics::HistoryNavigationOutcome::kNotRestored,
4934 FROM_HERE);
4935 ExpectNotRestored(
4936 {
4937 BackForwardCacheMetrics::NotRestoredReason::
4938 kConflictingBrowsingInstance,
4939 },
4940 FROM_HERE);
4941 }
4942
4943 // When same-site bfcache is disabled, we should not cache on same-site
4944 // navigations.
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTestWithSameSiteDisabled,DoesNotCacheOnSameSiteNavigation)4945 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTestWithSameSiteDisabled,
4946 DoesNotCacheOnSameSiteNavigation) {
4947 ASSERT_TRUE(embedded_test_server()->Start());
4948 GURL url_a1(embedded_test_server()->GetURL("a.com", "/title1.html"));
4949 GURL url_a2(embedded_test_server()->GetURL("a.com", "/title2.html"));
4950 GURL url_a3(
4951 embedded_test_server()->GetURL("subdomain.a.com", "/title3.html"));
4952
4953 // 1) Navigate to A1.
4954 EXPECT_TRUE(NavigateToURL(shell(), url_a1));
4955 RenderFrameHostImpl* rfh_a1 = current_frame_host();
4956 RenderFrameDeletedObserver delete_rfh_a1(rfh_a1);
4957 int browsing_instance_id = rfh_a1->GetSiteInstance()->GetBrowsingInstanceId();
4958
4959 // 2) Navigate same-site and same-origin to A2.
4960 EXPECT_TRUE(NavigateToURL(shell(), url_a2));
4961 RenderFrameHostImpl* rfh_a2 = current_frame_host();
4962 // The BrowsingInstance shouldn't have changed.
4963 EXPECT_EQ(browsing_instance_id,
4964 rfh_a2->GetSiteInstance()->GetBrowsingInstanceId());
4965 // The previous page should not be cached.
4966 EXPECT_FALSE(rfh_a1->IsInBackForwardCache());
4967
4968 // 2) Navigate same-site but cross-origin to A3.
4969 EXPECT_TRUE(NavigateToURL(shell(), url_a3));
4970 RenderFrameHostImpl* rfh_a3 = current_frame_host();
4971 // The BrowsingInstance shouldn't have changed.
4972 EXPECT_EQ(browsing_instance_id,
4973 rfh_a3->GetSiteInstance()->GetBrowsingInstanceId());
4974 // The previous page should not be cached.
4975 EXPECT_FALSE(rfh_a2->IsInBackForwardCache());
4976 }
4977
4978 // Check that during a same-RenderFrameHost cross-document navigation, the
4979 // disabled reasons is still tracked.
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTestWithSameSiteDisabled,DisableForRenderFrameHostPersistsAcrossNavigations)4980 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTestWithSameSiteDisabled,
4981 DisableForRenderFrameHostPersistsAcrossNavigations) {
4982 // This test assumes navigation from A1 to A2 will not switch
4983 // RenderFrameHosts which is not true when BackForwardCache,
4984 // ProactivelySwapBrowsingInstance or RenderDocument is enabled on same-site
4985 // main frame navigations.
4986 DCHECK(!CanSameSiteMainFrameNavigationsChangeRenderFrameHosts());
4987 ASSERT_TRUE(embedded_test_server()->Start());
4988 GURL url_a1(embedded_test_server()->GetURL("a.com", "/title1.html"));
4989 GURL url_a2(embedded_test_server()->GetURL("a.com", "/title2.html"));
4990 GURL url_b3(embedded_test_server()->GetURL("b.com", "/title1.html"));
4991
4992 // 1) Navigate to A1.
4993 EXPECT_TRUE(NavigateToURL(shell(), url_a1));
4994 RenderFrameHostImpl* rfh_a1 = current_frame_host();
4995 RenderFrameDeletedObserver deleted_observer_rfh_a1(rfh_a1);
4996 // Disable back-forward cache for A.
4997 BackForwardCache::DisableForRenderFrameHost(rfh_a1, kDisabledReasonForTest);
4998
4999 // 2) Navigate to A2.
5000 EXPECT_TRUE(NavigateToURL(shell(), url_a2));
5001 EXPECT_FALSE(deleted_observer_rfh_a1.deleted());
5002 EXPECT_EQ(rfh_a1, current_frame_host());
5003
5004 // 3) Navigate to B3.
5005 EXPECT_TRUE(NavigateToURL(shell(), url_b3));
5006 deleted_observer_rfh_a1.WaitUntilDeleted();
5007
5008 // 4) Go back to A2.
5009 web_contents()->GetController().GoBack();
5010 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
5011 ExpectDisabledWithReason(kDisabledReasonForTest, FROM_HERE);
5012 ExpectNotRestored({BackForwardCacheMetrics::NotRestoredReason::
5013 kDisableForRenderFrameHostCalled},
5014 FROM_HERE);
5015 }
5016
5017 // The BackForwardCache caches same-website navigations.
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,SameSiteNavigationCaching)5018 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, SameSiteNavigationCaching) {
5019 ASSERT_TRUE(embedded_test_server()->Start());
5020 GURL url_a1(embedded_test_server()->GetURL("a.com", "/title1.html"));
5021 GURL url_a2(embedded_test_server()->GetURL("a.com", "/title2.html"));
5022
5023 // 1) Navigate to A1.
5024 EXPECT_TRUE(NavigateToURL(shell(), url_a1));
5025 RenderFrameHostImpl* rfh_a1 = current_frame_host();
5026 RenderFrameDeletedObserver delete_rfh_a1(rfh_a1);
5027 int browsing_instance_id = rfh_a1->GetSiteInstance()->GetBrowsingInstanceId();
5028
5029 // 2) Navigate to A2.
5030 EXPECT_TRUE(NavigateToURL(shell(), url_a2));
5031 RenderFrameHostImpl* rfh_a2 = current_frame_host();
5032 EXPECT_NE(browsing_instance_id,
5033 rfh_a2->GetSiteInstance()->GetBrowsingInstanceId());
5034 EXPECT_TRUE(rfh_a1->IsInBackForwardCache());
5035 EXPECT_NE(rfh_a1, rfh_a2);
5036 }
5037
IN_PROC_BROWSER_TEST_F(HighCacheSizeBackForwardCacheBrowserTest,CanCacheMultiplesPagesOnSameDomain)5038 IN_PROC_BROWSER_TEST_F(HighCacheSizeBackForwardCacheBrowserTest,
5039 CanCacheMultiplesPagesOnSameDomain) {
5040 ASSERT_TRUE(embedded_test_server()->Start());
5041 GURL url_a1(embedded_test_server()->GetURL("a.com", "/title1.html"));
5042 GURL url_b2(embedded_test_server()->GetURL("b.com", "/title1.html"));
5043 GURL url_a3(embedded_test_server()->GetURL("a.com", "/title2.html"));
5044 GURL url_b4(embedded_test_server()->GetURL("b.com", "/title2.html"));
5045
5046 // 1) Navigate to A1.
5047 EXPECT_TRUE(NavigateToURL(shell(), url_a1));
5048 RenderFrameHostImpl* rfh_a1 = current_frame_host();
5049
5050 // 2) Navigate to B2.
5051 EXPECT_TRUE(NavigateToURL(shell(), url_b2));
5052 RenderFrameHostImpl* rfh_b2 = current_frame_host();
5053 EXPECT_TRUE(rfh_a1->IsInBackForwardCache());
5054
5055 // 3) Navigate to A3.
5056 EXPECT_TRUE(NavigateToURL(shell(), url_a3));
5057 RenderFrameHostImpl* rfh_a3 = current_frame_host();
5058 EXPECT_TRUE(rfh_a1->IsInBackForwardCache());
5059 EXPECT_TRUE(rfh_b2->IsInBackForwardCache());
5060 // A1 and A3 shouldn't be treated as the same site instance.
5061 EXPECT_NE(rfh_a1->GetSiteInstance(), rfh_a3->GetSiteInstance());
5062
5063 // 4) Navigate to B4.
5064 // Make sure we can store A1 and A3 in the cache at the same time.
5065 EXPECT_TRUE(NavigateToURL(shell(), url_b4));
5066 RenderFrameHostImpl* rfh_b4 = current_frame_host();
5067 EXPECT_TRUE(rfh_a1->IsInBackForwardCache());
5068 EXPECT_TRUE(rfh_b2->IsInBackForwardCache());
5069 EXPECT_TRUE(rfh_a3->IsInBackForwardCache());
5070
5071 // 5) Go back to A3.
5072 // Make sure we can restore A3, while A1 remains in the cache.
5073 web_contents()->GetController().GoBack();
5074 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
5075 EXPECT_TRUE(rfh_a1->IsInBackForwardCache());
5076 EXPECT_TRUE(rfh_b2->IsInBackForwardCache());
5077 EXPECT_TRUE(rfh_b4->IsInBackForwardCache());
5078 EXPECT_EQ(rfh_a3, current_frame_host());
5079 // B2 and B4 shouldn't be treated as the same site instance.
5080 EXPECT_NE(rfh_b2->GetSiteInstance(), rfh_b4->GetSiteInstance());
5081
5082 // 6) Do a history navigation back to A1.
5083 // Make sure we can restore A1, while coming from A3.
5084 web_contents()->GetController().GoToIndex(0);
5085 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
5086 EXPECT_TRUE(rfh_b2->IsInBackForwardCache());
5087 EXPECT_TRUE(rfh_b4->IsInBackForwardCache());
5088 EXPECT_TRUE(rfh_a3->IsInBackForwardCache());
5089 EXPECT_EQ(rfh_a1, current_frame_host());
5090 }
5091
5092 class BackForwardCacheBrowserTestSkipSameSiteUnload
5093 : public BackForwardCacheBrowserTest {
5094 public:
5095 BackForwardCacheBrowserTestSkipSameSiteUnload() = default;
5096 ~BackForwardCacheBrowserTestSkipSameSiteUnload() override = default;
5097
5098 protected:
SetUpCommandLine(base::CommandLine * command_line)5099 void SetUpCommandLine(base::CommandLine* command_line) override {
5100 skip_same_site_if_unload_exists_ = true;
5101 BackForwardCacheBrowserTest::SetUpCommandLine(command_line);
5102 }
5103 };
5104
5105 // We won't cache pages with unload handler on same-site navigations when
5106 // skip_same_site_if_unload_exists is set to true.
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTestSkipSameSiteUnload,SameSiteNavigationFromPageWithUnload)5107 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTestSkipSameSiteUnload,
5108 SameSiteNavigationFromPageWithUnload) {
5109 ASSERT_TRUE(embedded_test_server()->Start());
5110 GURL url_a1(embedded_test_server()->GetURL("a.com", "/title1.html"));
5111 GURL url_a2(embedded_test_server()->GetURL("a.com", "/title2.html"));
5112
5113 // 1) Navigate to A1 and add an unload handler.
5114 EXPECT_TRUE(NavigateToURL(shell(), url_a1));
5115 // We won't do a proactive BrowsingInstance swap for the initial navigation.
5116 // The initial navigation is a same-site navigation iff site isolation is on,
5117 // so we will track it as "same-site navigation but we did not swap BIs" in
5118 // that case.
5119 int initial_same_site_false_bucket_count =
5120 AreAllSitesIsolatedForTesting() ? 1 : 0;
5121 ExpectUniqueSample(kSameSiteNavigationDidSwapHistogramName, false,
5122 initial_same_site_false_bucket_count);
5123
5124 RenderFrameHostImpl* rfh_a1 = current_frame_host();
5125 EXPECT_TRUE(ExecJs(rfh_a1, "window.onunload = () => {} "));
5126
5127 // 2) Navigate to A2.
5128 EXPECT_TRUE(NavigateToURL(shell(), url_a2));
5129 RenderFrameHostImpl* rfh_a2 = current_frame_host();
5130 // We should not swap RFHs and A1 should not be in the back-forward cache.
5131 EXPECT_EQ(rfh_a1, rfh_a2);
5132 EXPECT_FALSE(rfh_a1->IsInBackForwardCache());
5133
5134 // We didn't do a BrowsingInstance swap for the navigation, so we should not
5135 // record any metrics related to same-site BrowsingInstance swaps, except for
5136 // the one that tracks the fact that we didn't do a same-site proactive
5137 // BrowsingInstance swap.
5138 ExpectUniqueSample(kSameSiteNavigationDidSwapHistogramName, false,
5139 initial_same_site_false_bucket_count + 1);
5140 ExpectTotalCount(kUnloadRunsAfterCommitHistogramName, 0);
5141 ExpectTotalCount(kEligibilityDuringCommitHistogramName, 0);
5142 }
5143
5144 // We won't cache pages with an unload handler in a same-SiteInstance subframe
5145 // on same-site navigations when skip_same_site_if_unload_exists is set to true.
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTestSkipSameSiteUnload,SameSiteNavigationFromPageWithUnloadInSameSiteSubframe)5146 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTestSkipSameSiteUnload,
5147 SameSiteNavigationFromPageWithUnloadInSameSiteSubframe) {
5148 ASSERT_TRUE(embedded_test_server()->Start());
5149 GURL url_a1(embedded_test_server()->GetURL(
5150 "a.com", "/cross_site_iframe_factory.html?a(b(a))"));
5151 GURL url_a2(embedded_test_server()->GetURL("a.com", "/title2.html"));
5152
5153 // 1) Navigate to A1 and add an unload handler to a.com subframe.
5154 EXPECT_TRUE(NavigateToURL(shell(), url_a1));
5155 RenderFrameHostImpl* rfh_a_main = current_frame_host();
5156 RenderFrameHostImpl* rfh_b = rfh_a_main->child_at(0)->current_frame_host();
5157 RenderFrameHostImpl* rfh_a_subframe =
5158 rfh_b->child_at(0)->current_frame_host();
5159 EXPECT_TRUE(ExecJs(rfh_a_subframe, "window.onunload = () => {} "));
5160
5161 // 2) Navigate to A2.
5162 EXPECT_TRUE(NavigateToURL(shell(), url_a2));
5163 RenderFrameHostImpl* rfh_a2 = current_frame_host();
5164 // We should not swap RFHs and A1 should not be in the back-forward cache.
5165 EXPECT_EQ(rfh_a_main, rfh_a2);
5166 EXPECT_FALSE(rfh_a_main->IsInBackForwardCache());
5167 }
5168
5169 // We won't cache pages with an unload handler in a cross-site subframe on
5170 // same-site navigations when skip_same_site_if_unload_exists is set to true
5171 // iff the cross-site subframe is in the same SiteInstance as the mainframe.
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTestSkipSameSiteUnload,SameSiteNavigationFromPageWithUnloadInCrossSiteSubframe)5172 IN_PROC_BROWSER_TEST_F(
5173 BackForwardCacheBrowserTestSkipSameSiteUnload,
5174 SameSiteNavigationFromPageWithUnloadInCrossSiteSubframe) {
5175 ASSERT_TRUE(embedded_test_server()->Start());
5176 GURL url_a1(embedded_test_server()->GetURL(
5177 "a.com", "/cross_site_iframe_factory.html?a(b)"));
5178 GURL url_a2(embedded_test_server()->GetURL("a.com", "/title2.html"));
5179
5180 // 1) Navigate to A1 and add an unload handler to b.com subframe.
5181 EXPECT_TRUE(NavigateToURL(shell(), url_a1));
5182 RenderFrameHostImpl* rfh_a1 = current_frame_host();
5183 RenderFrameHostImpl* rfh_b = rfh_a1->child_at(0)->current_frame_host();
5184 EXPECT_TRUE(ExecJs(rfh_b, "window.onunload = () => {} "));
5185 EXPECT_EQ(AreAllSitesIsolatedForTesting(),
5186 rfh_a1->GetSiteInstance() != rfh_b->GetSiteInstance());
5187
5188 // 2) Navigate to A2.
5189 EXPECT_TRUE(NavigateToURL(shell(), url_a2));
5190 RenderFrameHostImpl* rfh_a2 = current_frame_host();
5191 if (AreAllSitesIsolatedForTesting()) {
5192 // We should swap RFH & BIs and A1 should be in the back-forward cache.
5193 EXPECT_NE(rfh_a1, rfh_a2);
5194 EXPECT_FALSE(rfh_a1->GetSiteInstance()->IsRelatedSiteInstance(
5195 rfh_a2->GetSiteInstance()));
5196 EXPECT_TRUE(rfh_a1->IsInBackForwardCache());
5197 } else {
5198 // We should not swap RFHs and A1 should not be in the back-forward cache.
5199 EXPECT_EQ(rfh_a1, rfh_a2);
5200 EXPECT_FALSE(rfh_a1->IsInBackForwardCache());
5201 }
5202 }
5203
5204 // We will cache pages with unload handler on cross-site navigations even when
5205 // skip_same_site_if_unload_exists is set to true.
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTestSkipSameSiteUnload,CrossSiteNavigationFromPageWithUnload)5206 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTestSkipSameSiteUnload,
5207 CrossSiteNavigationFromPageWithUnload) {
5208 ASSERT_TRUE(embedded_test_server()->Start());
5209 GURL url_a1(embedded_test_server()->GetURL("a.com", "/title1.html"));
5210 GURL url_a2(embedded_test_server()->GetURL("b.com", "/title2.html"));
5211
5212 // 1) Navigate to A and add an unload handler.
5213 EXPECT_TRUE(NavigateToURL(shell(), url_a1));
5214 RenderFrameHostImpl* rfh_a = current_frame_host();
5215 EXPECT_TRUE(ExecJs(rfh_a, "window.onunload = () => {} "));
5216
5217 // 2) Navigate to B.
5218 EXPECT_TRUE(NavigateToURL(shell(), url_a2));
5219 RenderFrameHostImpl* rfh_b = current_frame_host();
5220 // We should swap RFHs and A should be in the back-forward cache.
5221 EXPECT_NE(rfh_a, rfh_b);
5222 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
5223 }
5224
5225 // We will cache pages with unload handler on same-site navigations when
5226 // skip_same_site_if_unload_exists is set to false.
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,SameSiteNavigationFromPageWithUnload)5227 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
5228 SameSiteNavigationFromPageWithUnload) {
5229 ASSERT_TRUE(embedded_test_server()->Start());
5230 GURL url_a1(embedded_test_server()->GetURL("a.com", "/title1.html"));
5231 GURL url_a2(embedded_test_server()->GetURL("a.com", "/title2.html"));
5232
5233 // 1) Navigate to A1 and add an unload handler.
5234 EXPECT_TRUE(NavigateToURL(shell(), url_a1));
5235 RenderFrameHostImpl* rfh_a1 = current_frame_host();
5236 EXPECT_TRUE(ExecJs(rfh_a1, "window.onunload = () => {} "));
5237 // We won't do a proactive BrowsingInstance swap for the initial navigation.
5238 // The initial navigation is a same-site navigation iff site isolation is on,
5239 // so we will track it as "same-site navigation but we did not swap BIs" in
5240 // that case.
5241 int initial_same_site_false_bucket_count =
5242 AreAllSitesIsolatedForTesting() ? 1 : 0;
5243 ExpectUniqueSample(kSameSiteNavigationDidSwapHistogramName, false,
5244 initial_same_site_false_bucket_count);
5245
5246 // 2) Navigate to A2.
5247 EXPECT_TRUE(NavigateToURL(shell(), url_a2));
5248 RenderFrameHostImpl* rfh_a2 = current_frame_host();
5249 // We should swap RFHs and A1 should be in the back-forward cache.
5250 EXPECT_NE(rfh_a1, rfh_a2);
5251 EXPECT_TRUE(rfh_a1->IsInBackForwardCache());
5252
5253 // We did a same-site BrowsingInstance swap for the navigation, so we should
5254 // record metrics related to same-site BrowsingInstance swaps.
5255 ExpectBucketCount(kSameSiteNavigationDidSwapHistogramName, true, 1);
5256 ExpectBucketCount(kSameSiteNavigationDidSwapHistogramName, false,
5257 initial_same_site_false_bucket_count);
5258 // We have an unload handler on A1, but it will not be run as the page is
5259 // stored in the back-forward cache.
5260 ExpectUniqueSample(kUnloadRunsAfterCommitHistogramName, false, 1);
5261 // The page is still eligible for back forward cache during commit, so
5262 // we should note it as such in the metrics.
5263 ExpectUniqueSample(kEligibilityDuringCommitHistogramName, true, 1);
5264 }
5265
5266 // Sub-frame doesn't transition from LifecycleState::kInBackForwardCache to
5267 // LifecycleState::kRunningUnloadHandlers even when the sub-frame having unload
5268 // handlers is being evicted from BackForwardCache.
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,SubframeWithUnloadHandler)5269 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, SubframeWithUnloadHandler) {
5270 ASSERT_TRUE(embedded_test_server()->Start());
5271 GURL main_url(embedded_test_server()->GetURL(
5272 "a.com", "/cross_site_iframe_factory.html?a.com(a.com)"));
5273 GURL child_url = embedded_test_server()->GetURL(
5274 "a.com", "/cross_site_iframe_factory.html?a.com()");
5275 GURL url_2(embedded_test_server()->GetURL("a.com", "/title1.html"));
5276
5277 // 1) Navigate to |main_url|.
5278 EXPECT_TRUE(NavigateToURL(shell(), main_url));
5279 RenderFrameHostImpl* main_rfh = current_frame_host();
5280 ASSERT_EQ(1U, main_rfh->child_count());
5281 RenderFrameHostImpl* child_rfh = main_rfh->child_at(0)->current_frame_host();
5282 RenderFrameDeletedObserver main_rfh_observer(main_rfh),
5283 child_rfh_observer(child_rfh);
5284
5285 // 2) Add an unload handler to the child RFH.
5286 EXPECT_TRUE(ExecJs(child_rfh, "window.onunload = () => {} "));
5287
5288 // 3) Navigate to |url_2|.
5289 EXPECT_TRUE(NavigateToURL(shell(), url_2));
5290
5291 // 4) The previous main RFH and child RFH should be in the back-forward
5292 // cache.
5293 EXPECT_FALSE(main_rfh_observer.deleted());
5294 EXPECT_FALSE(child_rfh_observer.deleted());
5295 EXPECT_TRUE(main_rfh->IsInBackForwardCache());
5296 EXPECT_TRUE(child_rfh->IsInBackForwardCache());
5297
5298 // Destruction of bfcached page happens after shutdown and it should not
5299 // trigger unload handlers and be destroyed directly.
5300 }
5301
5302 class GeolocationBackForwardCacheBrowserTest
5303 : public BackForwardCacheBrowserTest {
5304 protected:
GeolocationBackForwardCacheBrowserTest()5305 GeolocationBackForwardCacheBrowserTest() : geo_override_(0.0, 0.0) {}
5306
SetUpCommandLine(base::CommandLine * command_line)5307 void SetUpCommandLine(base::CommandLine* command_line) override {
5308 EnableFeatureAndSetParams(features::kBackForwardCache,
5309 "geolocation_supported", "true");
5310
5311 BackForwardCacheBrowserTest::SetUpCommandLine(command_line);
5312 }
5313
5314 device::ScopedGeolocationOverrider geo_override_;
5315 };
5316
5317 // Test that a page which has queried geolocation in the past, but have no
5318 // active geolocation query, can be bfcached.
IN_PROC_BROWSER_TEST_F(GeolocationBackForwardCacheBrowserTest,CacheAfterGeolocationRequest)5319 IN_PROC_BROWSER_TEST_F(GeolocationBackForwardCacheBrowserTest,
5320 CacheAfterGeolocationRequest) {
5321 ASSERT_TRUE(embedded_test_server()->Start());
5322 GURL url_a(embedded_test_server()->GetURL("/title1.html"));
5323 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
5324
5325 // 1) Navigate to A.
5326 EXPECT_TRUE(NavigateToURL(shell(), url_a));
5327 RenderFrameHostImpl* rfh_a = current_frame_host();
5328
5329 // Query current position, and wait for the query to complete.
5330 EXPECT_EQ("received", EvalJs(rfh_a, R"(
5331 new Promise(resolve => {
5332 navigator.geolocation.getCurrentPosition(() => resolve('received'));
5333 });
5334 )"));
5335
5336 RenderFrameDeletedObserver deleted(rfh_a);
5337
5338 // 2) Navigate away.
5339 EXPECT_TRUE(NavigateToURL(shell(), url_b));
5340
5341 // The page has no inflight geolocation request when we navigated away,
5342 // so it should have been cached.
5343 EXPECT_FALSE(deleted.deleted());
5344 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
5345 }
5346
5347 // Test that a page which has an inflight geolocation query can be bfcached,
5348 // and verify that the page does not observe any geolocation while the page
5349 // was inside bfcache.
5350 // The test is flaky on multiple platforms: crbug.com/1033270
IN_PROC_BROWSER_TEST_F(GeolocationBackForwardCacheBrowserTest,DISABLED_CancelGeolocationRequestInFlight)5351 IN_PROC_BROWSER_TEST_F(GeolocationBackForwardCacheBrowserTest,
5352 DISABLED_CancelGeolocationRequestInFlight) {
5353 ASSERT_TRUE(embedded_test_server()->Start());
5354 GURL url_a(embedded_test_server()->GetURL("/title1.html"));
5355 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
5356
5357 // 1) Navigate to A.
5358 EXPECT_TRUE(NavigateToURL(shell(), url_a));
5359 RenderFrameHostImpl* rfh_a = current_frame_host();
5360
5361 // Continuously query current geolocation.
5362 EXPECT_TRUE(ExecJs(rfh_a, R"(
5363 window.longitude_log = [];
5364 window.err_log = [];
5365 window.wait_for_first_position = new Promise(resolve => {
5366 navigator.geolocation.watchPosition(
5367 pos => {
5368 window.longitude_log.push(pos.coords.longitude);
5369 resolve("resolved");
5370 },
5371 err => window.err_log.push(err)
5372 );
5373 })
5374 )"));
5375 geo_override_.UpdateLocation(0.0, 0.0);
5376 EXPECT_EQ("resolved", EvalJs(rfh_a, "window.wait_for_first_position"));
5377
5378 // Pause resolving Geoposition queries to keep the request inflight.
5379 geo_override_.Pause();
5380 geo_override_.UpdateLocation(1.0, 1.0);
5381 EXPECT_EQ(1u, geo_override_.GetGeolocationInstanceCount());
5382
5383 // 2) Navigate away.
5384 base::RunLoop loop_until_close;
5385 geo_override_.SetGeolocationCloseCallback(loop_until_close.QuitClosure());
5386
5387 RenderFrameDeletedObserver deleted(rfh_a);
5388 EXPECT_TRUE(NavigateToURL(shell(), url_b));
5389
5390 loop_until_close.Run();
5391
5392 // The page has no inflight geolocation request when we navigated away,
5393 // so it should have been cached.
5394 EXPECT_FALSE(deleted.deleted());
5395 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
5396
5397 // Resume resolving Geoposition queries.
5398 geo_override_.Resume();
5399
5400 // We update the location while the page is BFCached, but this location should
5401 // not be observed.
5402 geo_override_.UpdateLocation(2.0, 2.0);
5403
5404 // 3) Navigate back to A.
5405
5406 // The location when navigated back can be observed
5407 geo_override_.UpdateLocation(3.0, 3.0);
5408
5409 web_contents()->GetController().GoBack();
5410 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
5411 EXPECT_EQ(rfh_a, current_frame_host());
5412 EXPECT_FALSE(rfh_a->IsInBackForwardCache());
5413
5414 // Wait for an update after the user navigates back to A.
5415 EXPECT_EQ("resolved", EvalJs(rfh_a, R"(
5416 window.wait_for_position_after_resume = new Promise(resolve => {
5417 navigator.geolocation.watchPosition(
5418 pos => {
5419 window.longitude_log.push(pos.coords.longitude);
5420 resolve("resolved");
5421 },
5422 err => window.err_log.push(err)
5423 );
5424 })
5425 )"));
5426
5427 EXPECT_LE(0, EvalJs(rfh_a, "longitude_log.indexOf(0.0)").ExtractInt())
5428 << "Geoposition before the page is put into BFCache should be visible";
5429 EXPECT_EQ(-1, EvalJs(rfh_a, "longitude_log.indexOf(1.0)").ExtractInt())
5430 << "Geoposition while the page is put into BFCache should be invisible";
5431 EXPECT_EQ(-1, EvalJs(rfh_a, "longitude_log.indexOf(2.0)").ExtractInt())
5432 << "Geoposition while the page is put into BFCache should be invisible";
5433 EXPECT_LT(0, EvalJs(rfh_a, "longitude_log.indexOf(3.0)").ExtractInt())
5434 << "Geoposition when the page is restored from BFCache should be visible";
5435 EXPECT_EQ(0, EvalJs(rfh_a, "err_log.length"))
5436 << "watchPosition API should have reported no errors";
5437 }
5438
5439 // Test that documents are evicted correctly from BackForwardCache after time to
5440 // live.
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,TimedEviction)5441 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, TimedEviction) {
5442 // Inject mock time task runner to be used in the eviction timer, so we can,
5443 // check for the functionality we are interested before and after the time to
5444 // live. We don't replace ThreadTaskRunnerHandle::Get to ensure that it
5445 // doesn't affect other unrelated callsites.
5446 scoped_refptr<base::TestMockTimeTaskRunner> task_runner =
5447 base::MakeRefCounted<base::TestMockTimeTaskRunner>();
5448
5449 web_contents()->GetController().GetBackForwardCache().SetTaskRunnerForTesting(
5450 task_runner);
5451
5452 base::TimeDelta time_to_live_in_back_forward_cache =
5453 BackForwardCacheImpl::GetTimeToLiveInBackForwardCache();
5454 // This should match the value we set in EnableFeatureAndSetParams.
5455 EXPECT_EQ(time_to_live_in_back_forward_cache,
5456 base::TimeDelta::FromSeconds(3600));
5457
5458 base::TimeDelta delta = base::TimeDelta::FromMilliseconds(1);
5459
5460 ASSERT_TRUE(embedded_test_server()->Start());
5461 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
5462 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
5463
5464 // 1) Navigate to A.
5465 EXPECT_TRUE(NavigateToURL(shell(), url_a));
5466 RenderFrameHostImpl* rfh_a = current_frame_host();
5467 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
5468
5469 // 2) Navigate to B.
5470 EXPECT_TRUE(NavigateToURL(shell(), url_b));
5471 RenderFrameHostImpl* rfh_b = current_frame_host();
5472
5473 // 3) Fast forward to just before eviction is due.
5474 task_runner->FastForwardBy(time_to_live_in_back_forward_cache - delta);
5475
5476 // 4) Confirm A is still in BackForwardCache.
5477 ASSERT_FALSE(delete_observer_rfh_a.deleted());
5478 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
5479
5480 // 5) Fast forward to when eviction is due.
5481 task_runner->FastForwardBy(delta);
5482
5483 // 6) Confirm A is evicted.
5484 delete_observer_rfh_a.WaitUntilDeleted();
5485 EXPECT_EQ(current_frame_host(), rfh_b);
5486
5487 // 7) Go back to A.
5488 web_contents()->GetController().GoBack();
5489 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
5490 ExpectNotRestored({BackForwardCacheMetrics::NotRestoredReason::kTimeout},
5491 FROM_HERE);
5492 }
5493
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,DisableBackForwardCachePreventsDocumentsFromBeingCached)5494 IN_PROC_BROWSER_TEST_F(
5495 BackForwardCacheBrowserTest,
5496 DisableBackForwardCachePreventsDocumentsFromBeingCached) {
5497 ASSERT_TRUE(embedded_test_server()->Start());
5498 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
5499 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
5500 url::Origin origin_a = url::Origin::Create(url_a);
5501 url::Origin origin_b = url::Origin::Create(url_b);
5502
5503 // 1) Navigate to A.
5504 EXPECT_TRUE(NavigateToURL(shell(), url_a));
5505 RenderFrameHostImpl* rfh_a = current_frame_host();
5506 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
5507 BackForwardCache::DisableForRenderFrameHost(rfh_a, kDisabledReasonForTest);
5508
5509 // 2) Navigate to B.
5510 EXPECT_TRUE(NavigateToURL(shell(), url_b));
5511 delete_observer_rfh_a.WaitUntilDeleted();
5512
5513 // 3) Go back to A.
5514 web_contents()->GetController().GoBack();
5515 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
5516 ExpectDisabledWithReason(kDisabledReasonForTest, FROM_HERE);
5517 ExpectNotRestored({BackForwardCacheMetrics::NotRestoredReason::
5518 kDisableForRenderFrameHostCalled},
5519 FROM_HERE);
5520 }
5521
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,DisableBackForwardIsNoOpIfRfhIsGone)5522 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
5523 DisableBackForwardIsNoOpIfRfhIsGone) {
5524 ASSERT_TRUE(embedded_test_server()->Start());
5525 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
5526 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
5527 url::Origin origin_a = url::Origin::Create(url_a);
5528 url::Origin origin_b = url::Origin::Create(url_b);
5529
5530 // 1) Navigate to A.
5531 EXPECT_TRUE(NavigateToURL(shell(), url_a));
5532 RenderFrameHostImpl* rfh_a = current_frame_host();
5533 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
5534 GlobalFrameRoutingId rfh_a_id = rfh_a->GetGlobalFrameRoutingId();
5535 BackForwardCache::DisableForRenderFrameHost(rfh_a_id, kDisabledReasonForTest);
5536
5537 // 2) Navigate to B.
5538 EXPECT_TRUE(NavigateToURL(shell(), url_b));
5539 delete_observer_rfh_a.WaitUntilDeleted();
5540
5541 // This should not die
5542 BackForwardCache::DisableForRenderFrameHost(rfh_a_id, kDisabledReasonForTest);
5543
5544 // 3) Go back to A.
5545 web_contents()->GetController().GoBack();
5546 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
5547 ExpectDisabledWithReason(kDisabledReasonForTest, FROM_HERE);
5548 ExpectNotRestored({BackForwardCacheMetrics::NotRestoredReason::
5549 kDisableForRenderFrameHostCalled},
5550 FROM_HERE);
5551 }
5552
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,DisableBackForwardCacheIframe)5553 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
5554 DisableBackForwardCacheIframe) {
5555 ASSERT_TRUE(embedded_test_server()->Start());
5556 GURL url_a(embedded_test_server()->GetURL(
5557 "a.com", "/cross_site_iframe_factory.html?a(b)"));
5558 GURL url_c(embedded_test_server()->GetURL("b.com", "/title1.html"));
5559
5560 // 1) Navigate to A.
5561 EXPECT_TRUE(NavigateToURL(shell(), url_a));
5562 RenderFrameHostImpl* rfh_a = current_frame_host();
5563 RenderFrameHostImpl* rfh_b = rfh_a->child_at(0)->current_frame_host();
5564 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
5565 RenderFrameDeletedObserver delete_observer_rfh_b(rfh_b);
5566
5567 BackForwardCache::DisableForRenderFrameHost(rfh_b, kDisabledReasonForTest);
5568
5569 // 2) Navigate to C. A and B are deleted.
5570 EXPECT_TRUE(NavigateToURL(shell(), url_c));
5571 delete_observer_rfh_a.WaitUntilDeleted();
5572 delete_observer_rfh_b.WaitUntilDeleted();
5573
5574 // 3) Go back to A.
5575 web_contents()->GetController().GoBack();
5576 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
5577 ExpectNotRestored({BackForwardCacheMetrics::NotRestoredReason::
5578 kDisableForRenderFrameHostCalled},
5579 FROM_HERE);
5580 }
5581
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,DisableBackForwardEvictsIfAlreadyInCache)5582 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
5583 DisableBackForwardEvictsIfAlreadyInCache) {
5584 ASSERT_TRUE(embedded_test_server()->Start());
5585 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
5586 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
5587 url::Origin origin_a = url::Origin::Create(url_a);
5588 url::Origin origin_b = url::Origin::Create(url_b);
5589
5590 // 1) Navigate to A.
5591 EXPECT_TRUE(NavigateToURL(shell(), url_a));
5592 RenderFrameHostImpl* rfh_a = current_frame_host();
5593 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
5594
5595 // 2) Navigate to B.
5596 EXPECT_TRUE(NavigateToURL(shell(), url_b));
5597 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
5598 EXPECT_FALSE(rfh_a->is_evicted_from_back_forward_cache());
5599
5600 BackForwardCache::DisableForRenderFrameHost(rfh_a, kDisabledReasonForTest);
5601
5602 delete_observer_rfh_a.WaitUntilDeleted();
5603
5604 // 3) Go back to A.
5605 web_contents()->GetController().GoBack();
5606 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
5607 ExpectDisabledWithReason(kDisabledReasonForTest, FROM_HERE);
5608 ExpectNotRestored({BackForwardCacheMetrics::NotRestoredReason::
5609 kDisableForRenderFrameHostCalled},
5610 FROM_HERE);
5611 }
5612
5613 // Confirm that same-document navigation and not history-navigation does not
5614 // record metrics.
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,MetricsNotRecorded)5615 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, MetricsNotRecorded) {
5616 ASSERT_TRUE(embedded_test_server()->Start());
5617 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
5618 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
5619 GURL url_b2(embedded_test_server()->GetURL("b.com", "/title1.html#2"));
5620
5621 // 1) Navigate to A.
5622 EXPECT_TRUE(NavigateToURL(shell(), url_a));
5623 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
5624
5625 // 2) Navigate to B.
5626 EXPECT_TRUE(NavigateToURL(shell(), url_b));
5627 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
5628
5629 // 3) Navigate to B#2 (same document navigation).
5630 EXPECT_TRUE(NavigateToURLFromRenderer(shell(), url_b2));
5631
5632 // 4) Go back to B.
5633 web_contents()->GetController().GoBack();
5634 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
5635 ExpectOutcomeDidNotChange(FROM_HERE);
5636
5637 // 5) Navigate to A.
5638 EXPECT_TRUE(NavigateToURL(shell(), url_a));
5639 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
5640 ExpectOutcomeDidNotChange(FROM_HERE);
5641 }
5642
5643 // Test for functionality of domain specific controls in back-forward cache.
5644 class BackForwardCacheBrowserTestWithDomainControlEnabled
5645 : public BackForwardCacheBrowserTest {
5646 protected:
SetUpCommandLine(base::CommandLine * command_line)5647 void SetUpCommandLine(base::CommandLine* command_line) override {
5648 // Sets the allowed websites for testing, additionally adding the params
5649 // used by BackForwardCacheBrowserTest.
5650 std::string allowed_websites =
5651 "https://a.allowed/back_forward_cache/, "
5652 "https://b.allowed/back_forward_cache/allowed_path.html";
5653 EnableFeatureAndSetParams(features::kBackForwardCache, "allowed_websites",
5654 allowed_websites);
5655
5656 BackForwardCacheBrowserTest::SetUpCommandLine(command_line);
5657 }
5658 };
5659
5660 // Check the RenderFrameHost allowed to enter the BackForwardCache are the ones
5661 // matching with the "allowed_websites" feature params.
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTestWithDomainControlEnabled,CachePagesWithMatchedURLs)5662 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTestWithDomainControlEnabled,
5663 CachePagesWithMatchedURLs) {
5664 ASSERT_TRUE(embedded_test_server()->Start());
5665 GURL url_a(embedded_test_server()->GetURL(
5666 "a.allowed", "/back_forward_cache/allowed_path.html"));
5667 GURL url_b(embedded_test_server()->GetURL(
5668 "b.allowed", "/back_forward_cache/allowed_path.html?query=bar"));
5669
5670 // 1) Navigate to A.
5671 EXPECT_TRUE(NavigateToURL(shell(), url_a));
5672 RenderFrameHostImpl* rfh_a = current_frame_host();
5673 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
5674
5675 // 2) Navigate to B.
5676 EXPECT_TRUE(NavigateToURL(shell(), url_b));
5677 RenderFrameHostImpl* rfh_b = current_frame_host();
5678 RenderFrameDeletedObserver delete_observer_rfh_b(rfh_b);
5679
5680 // 3) Check if rfh_a is stored in back-forward cache, since it matches to
5681 // the list of allowed urls, it should be stored.
5682 EXPECT_FALSE(delete_observer_rfh_a.deleted());
5683 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
5684
5685 // 4) Now go back to the last stored page, which in our case should be A.
5686 web_contents()->GetController().GoBack();
5687 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
5688 EXPECT_EQ(rfh_a, current_frame_host());
5689
5690 // 5) Check if rfh_b is stored in back-forward cache, since it matches to
5691 // the list of allowed urls, it should be stored.
5692 EXPECT_FALSE(delete_observer_rfh_b.deleted());
5693 EXPECT_TRUE(rfh_b->IsInBackForwardCache());
5694 }
5695
5696 // We don't want to allow websites which doesn't match "allowed_websites" of
5697 // feature params to be stored in back-forward cache.
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTestWithDomainControlEnabled,DoNotCachePagesWithUnMatchedURLs)5698 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTestWithDomainControlEnabled,
5699 DoNotCachePagesWithUnMatchedURLs) {
5700 DisableCheckingMetricsForAllSites();
5701
5702 ASSERT_TRUE(embedded_test_server()->Start());
5703 GURL url_a(embedded_test_server()->GetURL(
5704 "a.disallowed", "/back_forward_cache/disallowed_path.html"));
5705 GURL url_b(embedded_test_server()->GetURL(
5706 "b.allowed", "/back_forward_cache/disallowed_path.html"));
5707 GURL url_c(embedded_test_server()->GetURL(
5708 "c.disallowed", "/back_forward_cache/disallowed_path.html"));
5709
5710 // 1) Navigate to A.
5711 EXPECT_TRUE(NavigateToURL(shell(), url_a));
5712 RenderFrameHostImpl* rfh_a = current_frame_host();
5713 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
5714
5715 // 2) Navigate to B.
5716 EXPECT_TRUE(NavigateToURL(shell(), url_b));
5717 RenderFrameHostImpl* rfh_b = current_frame_host();
5718 RenderFrameDeletedObserver delete_observer_rfh_b(rfh_b);
5719
5720 // 3) Since url of A doesn't match to the the list of allowed urls it should
5721 // not be stored in back-forward cache.
5722 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
5723 delete_observer_rfh_a.WaitUntilDeleted();
5724
5725 // 4) Navigate to C.
5726 EXPECT_TRUE(NavigateToURL(shell(), url_c));
5727
5728 // 5) Since url of B doesn't match to the the list of allowed urls it should
5729 // not be stored in back-forward cache.
5730 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
5731 delete_observer_rfh_b.WaitUntilDeleted();
5732
5733 // 6) Go back to B.
5734 web_contents()->GetController().GoBack();
5735 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
5736
5737 // Nothing is recorded when the domain does not match.
5738 ExpectOutcomeDidNotChange(FROM_HERE);
5739 ExpectNotRestoredDidNotChange(FROM_HERE);
5740 }
5741
5742 // Check that if WebPreferences was changed while a page was bfcached, it will
5743 // get up-to-date WebPreferences when it was restored.
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,WebPreferences)5744 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, WebPreferences) {
5745 ASSERT_TRUE(embedded_test_server()->Start());
5746 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
5747 GURL url_b(embedded_test_server()->GetURL("b.com", "/title2.html"));
5748
5749 // 1) Navigate to A.
5750 EXPECT_TRUE(NavigateToURL(shell(), url_a));
5751 RenderFrameHostImpl* rfh_a = current_frame_host();
5752 int browsing_instance_id = rfh_a->GetSiteInstance()->GetBrowsingInstanceId();
5753
5754 // A should prefer light color scheme (which is the default).
5755 bool matches_light;
5756 ASSERT_TRUE(ExecuteScriptAndExtractBool(
5757 web_contents(),
5758 "window.domAutomationController.send(window."
5759 "matchMedia('(prefers-color-scheme: light)').matches)",
5760 &matches_light));
5761 EXPECT_TRUE(matches_light);
5762
5763 // 2) Navigate to B. A should be stored in the back-forward cache.
5764 EXPECT_TRUE(NavigateToURL(shell(), url_b));
5765 RenderFrameHostImpl* rfh_b = current_frame_host();
5766 EXPECT_NE(browsing_instance_id,
5767 rfh_b->GetSiteInstance()->GetBrowsingInstanceId());
5768 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
5769 EXPECT_NE(rfh_a, rfh_b);
5770
5771 blink::web_pref::WebPreferences prefs =
5772 web_contents()->GetOrCreateWebPreferences();
5773 prefs.preferred_color_scheme = blink::mojom::PreferredColorScheme::kDark;
5774 web_contents()->SetWebPreferences(prefs);
5775
5776 // 3) Set WebPreferences to prefer dark color scheme.
5777 bool b_matches_dark;
5778 ASSERT_TRUE(ExecuteScriptAndExtractBool(
5779 web_contents(),
5780 "window.domAutomationController.send(window."
5781 "matchMedia('(prefers-color-scheme: dark)').matches)",
5782 &b_matches_dark));
5783 EXPECT_TRUE(b_matches_dark);
5784 // 4) Go back to A, which should also prefer the dark color scheme now.
5785 web_contents()->GetController().GoBack();
5786 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
5787 EXPECT_EQ(rfh_a, current_frame_host());
5788
5789 bool a_matches_dark;
5790 ASSERT_TRUE(ExecuteScriptAndExtractBool(
5791 web_contents(),
5792 "window.domAutomationController.send(window."
5793 "matchMedia('(prefers-color-scheme: dark)').matches)",
5794 &a_matches_dark));
5795 EXPECT_TRUE(a_matches_dark);
5796 }
5797
5798 // Check the BackForwardCache is disabled when there is a nested WebContents
5799 // inside a page.
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,NestedWebContents)5800 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, NestedWebContents) {
5801 // 1) Navigate to a page.
5802 ASSERT_TRUE(embedded_test_server()->Start());
5803 GURL url(embedded_test_server()->GetURL("a.com", "/page_with_iframe.html"));
5804
5805 EXPECT_TRUE(NavigateToURL(shell(), url));
5806
5807 RenderFrameHostImpl* rfh_a = current_frame_host();
5808 RenderFrameHostImpl* child = rfh_a->child_at(0)->current_frame_host();
5809 EXPECT_TRUE(child);
5810
5811 // Create and attach an inner WebContents.
5812 CreateAndAttachInnerContents(child);
5813 RenderFrameDeletedObserver deleted(rfh_a);
5814
5815 // 2) Navigate away.
5816 shell()->LoadURL(embedded_test_server()->GetURL("b.com", "/title1.html"));
5817 // The page has an inner WebContents so it should be deleted.
5818 deleted.WaitUntilDeleted();
5819
5820 // 3) Go back to the page with an inner WebContents.
5821 web_contents()->GetController().GoBack();
5822 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
5823 ExpectNotRestored(
5824 {BackForwardCacheMetrics::NotRestoredReason::kHaveInnerContents},
5825 FROM_HERE);
5826 }
5827
5828 // Check the BackForwardCache is disabled when the WebUSB feature is used.
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,WebUSB)5829 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, WebUSB) {
5830 // WebUSB requires HTTPS.
5831 ASSERT_TRUE(CreateHttpsServer()->Start());
5832
5833 // Main document.
5834 {
5835 content::BackForwardCacheDisabledTester tester;
5836 GURL url(https_server()->GetURL("a.com", "/title1.html"));
5837
5838 EXPECT_TRUE(NavigateToURL(shell(), url));
5839
5840 EXPECT_FALSE(current_frame_host()->IsBackForwardCacheDisabled());
5841 EXPECT_EQ("Found 0 devices", content::EvalJs(current_frame_host(), R"(
5842 new Promise(async resolve => {
5843 let devices = await navigator.usb.getDevices();
5844 resolve("Found " + devices.length + " devices");
5845 });
5846 )"));
5847 EXPECT_TRUE(current_frame_host()->IsBackForwardCacheDisabled());
5848 EXPECT_TRUE(tester.IsDisabledForFrameWithReason(
5849 current_frame_host()->GetProcess()->GetID(),
5850 current_frame_host()->GetRoutingID(), "WebUSB"));
5851 }
5852
5853 // Nested document.
5854 {
5855 content::BackForwardCacheDisabledTester tester;
5856 GURL url(https_server()->GetURL("c.com",
5857 "/cross_site_iframe_factory.html?c(d)"));
5858 EXPECT_TRUE(NavigateToURL(shell(), url));
5859 RenderFrameHostImpl* rfh_c = current_frame_host();
5860 RenderFrameHostImpl* rfh_d = rfh_c->child_at(0)->current_frame_host();
5861
5862 EXPECT_FALSE(rfh_c->IsBackForwardCacheDisabled());
5863 EXPECT_FALSE(rfh_d->IsBackForwardCacheDisabled());
5864 EXPECT_EQ("Found 0 devices", content::EvalJs(rfh_c, R"(
5865 new Promise(async resolve => {
5866 let devices = await navigator.usb.getDevices();
5867 resolve("Found " + devices.length + " devices");
5868 });
5869 )"));
5870 EXPECT_TRUE(rfh_c->IsBackForwardCacheDisabled());
5871 EXPECT_FALSE(rfh_d->IsBackForwardCacheDisabled());
5872 EXPECT_TRUE(tester.IsDisabledForFrameWithReason(
5873 rfh_c->GetProcess()->GetID(), rfh_c->GetRoutingID(), "WebUSB"));
5874 }
5875
5876 // Worker.
5877 {
5878 content::BackForwardCacheDisabledTester tester;
5879 GURL url(https_server()->GetURL("e.com", "/title1.html"));
5880 EXPECT_TRUE(NavigateToURL(shell(), url));
5881 EXPECT_FALSE(current_frame_host()->IsBackForwardCacheDisabled());
5882 EXPECT_EQ("Found 0 devices", content::EvalJs(current_frame_host(), R"(
5883 new Promise(async resolve => {
5884 const worker = new Worker("/back_forward_cache/webusb/worker.js");
5885 worker.onmessage = message => resolve(message.data);
5886 worker.postMessage("Run");
5887 });
5888 )"));
5889 EXPECT_TRUE(current_frame_host()->IsBackForwardCacheDisabled());
5890 EXPECT_TRUE(tester.IsDisabledForFrameWithReason(
5891 current_frame_host()->GetProcess()->GetID(),
5892 current_frame_host()->GetRoutingID(), "WebUSB"));
5893 }
5894
5895 // Nested worker.
5896 {
5897 content::BackForwardCacheDisabledTester tester;
5898 GURL url(https_server()->GetURL("f.com", "/title1.html"));
5899 EXPECT_TRUE(NavigateToURL(shell(), url));
5900 EXPECT_FALSE(current_frame_host()->IsBackForwardCacheDisabled());
5901 EXPECT_EQ("Found 0 devices", content::EvalJs(current_frame_host(), R"(
5902 new Promise(async resolve => {
5903 const worker = new Worker(
5904 "/back_forward_cache/webusb/nested-worker.js");
5905 worker.onmessage = message => resolve(message.data);
5906 worker.postMessage("Run");
5907 });
5908 )"));
5909 EXPECT_TRUE(current_frame_host()->IsBackForwardCacheDisabled());
5910 EXPECT_TRUE(tester.IsDisabledForFrameWithReason(
5911 current_frame_host()->GetProcess()->GetID(),
5912 current_frame_host()->GetRoutingID(), "WebUSB"));
5913 }
5914 }
5915
5916 #if !defined(OS_ANDROID)
5917 // Check that the back-forward cache is disabled when the Serial API is used.
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,Serial)5918 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, Serial) {
5919 // Serial API requires HTTPS.
5920 ASSERT_TRUE(CreateHttpsServer()->Start());
5921
5922 // Main document.
5923 {
5924 content::BackForwardCacheDisabledTester tester;
5925 GURL url(https_server()->GetURL("a.com", "/title1.html"));
5926
5927 EXPECT_TRUE(NavigateToURL(shell(), url));
5928
5929 EXPECT_FALSE(current_frame_host()->IsBackForwardCacheDisabled());
5930 EXPECT_EQ("Found 0 ports", content::EvalJs(current_frame_host(), R"(
5931 new Promise(async resolve => {
5932 let ports = await navigator.serial.getPorts();
5933 resolve("Found " + ports.length + " ports");
5934 });
5935 )"));
5936 EXPECT_TRUE(current_frame_host()->IsBackForwardCacheDisabled());
5937 EXPECT_TRUE(tester.IsDisabledForFrameWithReason(
5938 current_frame_host()->GetProcess()->GetID(),
5939 current_frame_host()->GetRoutingID(), "Serial"));
5940 }
5941
5942 // Nested document.
5943 {
5944 content::BackForwardCacheDisabledTester tester;
5945 GURL url(https_server()->GetURL("c.com",
5946 "/cross_site_iframe_factory.html?c(d)"));
5947 EXPECT_TRUE(NavigateToURL(shell(), url));
5948 RenderFrameHostImpl* rfh_c = current_frame_host();
5949 RenderFrameHostImpl* rfh_d = rfh_c->child_at(0)->current_frame_host();
5950
5951 EXPECT_FALSE(rfh_c->IsBackForwardCacheDisabled());
5952 EXPECT_FALSE(rfh_d->IsBackForwardCacheDisabled());
5953 EXPECT_EQ("Found 0 ports", content::EvalJs(rfh_c, R"(
5954 new Promise(async resolve => {
5955 let ports = await navigator.serial.getPorts();
5956 resolve("Found " + ports.length + " ports");
5957 });
5958 )"));
5959 EXPECT_TRUE(rfh_c->IsBackForwardCacheDisabled());
5960 EXPECT_FALSE(rfh_d->IsBackForwardCacheDisabled());
5961 EXPECT_TRUE(tester.IsDisabledForFrameWithReason(
5962 rfh_c->GetProcess()->GetID(), rfh_c->GetRoutingID(), "Serial"));
5963 }
5964
5965 // Worker.
5966 {
5967 content::BackForwardCacheDisabledTester tester;
5968 GURL url(https_server()->GetURL("e.com", "/title1.html"));
5969 EXPECT_TRUE(NavigateToURL(shell(), url));
5970 EXPECT_FALSE(current_frame_host()->IsBackForwardCacheDisabled());
5971 EXPECT_EQ("Found 0 ports", content::EvalJs(current_frame_host(), R"(
5972 new Promise(async resolve => {
5973 const worker = new Worker("/back_forward_cache/serial/worker.js");
5974 worker.onmessage = message => resolve(message.data);
5975 worker.postMessage("Run");
5976 });
5977 )"));
5978 EXPECT_TRUE(current_frame_host()->IsBackForwardCacheDisabled());
5979 EXPECT_TRUE(tester.IsDisabledForFrameWithReason(
5980 current_frame_host()->GetProcess()->GetID(),
5981 current_frame_host()->GetRoutingID(), "Serial"));
5982 }
5983
5984 // Nested worker.
5985 {
5986 content::BackForwardCacheDisabledTester tester;
5987 GURL url(https_server()->GetURL("f.com", "/title1.html"));
5988 EXPECT_TRUE(NavigateToURL(shell(), url));
5989 EXPECT_FALSE(current_frame_host()->IsBackForwardCacheDisabled());
5990 EXPECT_EQ("Found 0 ports", content::EvalJs(current_frame_host(), R"(
5991 new Promise(async resolve => {
5992 const worker = new Worker(
5993 "/back_forward_cache/serial/nested-worker.js");
5994 worker.onmessage = message => resolve(message.data);
5995 worker.postMessage("Run");
5996 });
5997 )"));
5998 EXPECT_TRUE(current_frame_host()->IsBackForwardCacheDisabled());
5999 EXPECT_TRUE(tester.IsDisabledForFrameWithReason(
6000 current_frame_host()->GetProcess()->GetID(),
6001 current_frame_host()->GetRoutingID(), "Serial"));
6002 }
6003 }
6004 #endif
6005
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,Encoding)6006 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, Encoding) {
6007 ASSERT_TRUE(embedded_test_server()->Start());
6008 GURL url_a(embedded_test_server()->GetURL(
6009 "a.com", "/back_forward_cache/charset_windows-1250.html"));
6010 GURL url_b(embedded_test_server()->GetURL(
6011 "b.com", "/back_forward_cache/charset_utf-8.html"));
6012 url::Origin origin_a = url::Origin::Create(url_a);
6013 url::Origin origin_b = url::Origin::Create(url_b);
6014
6015 EXPECT_TRUE(NavigateToURL(shell(), url_a));
6016 RenderFrameHostImpl* rfh_a = current_frame_host();
6017 EXPECT_EQ(web_contents()->GetEncoding(), "windows-1250");
6018
6019 EXPECT_TRUE(NavigateToURL(shell(), url_b));
6020 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
6021 EXPECT_EQ(web_contents()->GetEncoding(), "UTF-8");
6022
6023 web_contents()->GetController().GoBack();
6024 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
6025 EXPECT_EQ(web_contents()->GetEncoding(), "windows-1250");
6026 }
6027
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,RestoreWhilePendingCommit)6028 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, RestoreWhilePendingCommit) {
6029 net::test_server::ControllableHttpResponse response(embedded_test_server(),
6030 "/main_document");
6031 ASSERT_TRUE(embedded_test_server()->Start());
6032 GURL url1(embedded_test_server()->GetURL("a.com", "/title1.html"));
6033 GURL url2(embedded_test_server()->GetURL("b.com", "/title2.html"));
6034 GURL url3(embedded_test_server()->GetURL("c.com", "/main_document"));
6035
6036 // Load a page and navigate away from it, so it is stored in the back-forward
6037 // cache.
6038 EXPECT_TRUE(NavigateToURL(shell(), url1));
6039 RenderFrameHost* rfh1 = current_frame_host();
6040 EXPECT_TRUE(NavigateToURL(shell(), url2));
6041
6042 // Try to navigate to a new page, but leave it in a pending state.
6043 shell()->LoadURL(url3);
6044 response.WaitForRequest();
6045
6046 // Navigate back and restore page from the cache, cancelling the previous
6047 // navigation.
6048 web_contents()->GetController().GoBack();
6049 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
6050 EXPECT_EQ(rfh1, current_frame_host());
6051 }
6052
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,DoesNotCacheCrossSiteHttpPost)6053 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
6054 DoesNotCacheCrossSiteHttpPost) {
6055 SetupCrossSiteRedirector(embedded_test_server());
6056 ASSERT_TRUE(embedded_test_server()->Start());
6057
6058 // Note we do a cross-site post because same-site navigations of any kind
6059 // aren't cached currently.
6060 GURL form_url(embedded_test_server()->GetURL(
6061 "a.com", "/form_that_posts_cross_site.html"));
6062 GURL redirect_target_url(embedded_test_server()->GetURL("x.com", "/echoall"));
6063 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
6064
6065 // Navigate to the page with form that posts via 307 redirection to
6066 // |redirect_target_url| (cross-site from |form_url|).
6067 EXPECT_TRUE(NavigateToURL(shell(), form_url));
6068
6069 // Submit the form.
6070 TestNavigationObserver form_post_observer(shell()->web_contents(), 1);
6071 EXPECT_TRUE(ExecJs(shell(), "document.getElementById('text-form').submit()"));
6072 form_post_observer.Wait();
6073
6074 // Verify that we arrived at the expected, redirected location.
6075 EXPECT_EQ(redirect_target_url,
6076 shell()->web_contents()->GetLastCommittedURL());
6077 RenderFrameDeletedObserver delete_observer_rfh(current_frame_host());
6078
6079 // Navigate away. |redirect_target_url|'s page should not be cached.
6080 EXPECT_TRUE(NavigateToURL(shell(), url_b));
6081 delete_observer_rfh.WaitUntilDeleted();
6082 }
6083
6084 namespace {
6085
6086 const char kResponseWithNoCache[] =
6087 "HTTP/1.1 200 OK\r\n"
6088 "Content-Type: text/html; charset=utf-8\r\n"
6089 "Cache-Control: no-store\r\n"
6090 "\r\n"
6091 "The server speaks HTTP!";
6092
6093 } // namespace
6094
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,MainFrameWithNoStoreNotCached)6095 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
6096 MainFrameWithNoStoreNotCached) {
6097 net::test_server::ControllableHttpResponse response(embedded_test_server(),
6098 "/main_document");
6099 ASSERT_TRUE(embedded_test_server()->Start());
6100
6101 GURL url_a(embedded_test_server()->GetURL("a.com", "/main_document"));
6102 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
6103
6104 // 1. Load the document and specify no-store for the main resource.
6105 TestNavigationObserver observer(web_contents());
6106 shell()->LoadURL(url_a);
6107 response.WaitForRequest();
6108 response.Send(kResponseWithNoCache);
6109 response.Done();
6110 observer.Wait();
6111
6112 // 2. Navigate away and expect frame to be deleted.
6113 RenderFrameDeletedObserver delete_observer_rfh_a(current_frame_host());
6114 EXPECT_TRUE(NavigateToURL(shell(), url_b));
6115 delete_observer_rfh_a.WaitUntilDeleted();
6116 }
6117
6118 // Disabled for being flaky. See crbug.com/1116190.
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,DISABLED_SubframeWithNoStoreCached)6119 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
6120 DISABLED_SubframeWithNoStoreCached) {
6121 // iframe will try to load title1.html.
6122 net::test_server::ControllableHttpResponse response(embedded_test_server(),
6123 "/title1.html");
6124 ASSERT_TRUE(embedded_test_server()->Start());
6125
6126 GURL url_a(embedded_test_server()->GetURL("a.com", "/page_with_iframe.html"));
6127 GURL url_b(embedded_test_server()->GetURL("b.com", "/title2.html"));
6128
6129 // 1) Load the document and specify no-store for the main resource.
6130 TestNavigationObserver observer(web_contents());
6131 shell()->LoadURL(url_a);
6132 response.WaitForRequest();
6133 response.Send(kResponseWithNoCache);
6134 response.Done();
6135 observer.Wait();
6136 RenderFrameHostImpl* rfh_a = current_frame_host();
6137 RenderFrameDeletedObserver delete_observer_rfh_a(current_frame_host());
6138
6139 // 2) Navigate away.
6140 EXPECT_TRUE(NavigateToURL(shell(), url_b));
6141
6142 // 3) Navigate back and expect everything to be restored.
6143 web_contents()->GetController().GoBack();
6144 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
6145 EXPECT_FALSE(delete_observer_rfh_a.deleted());
6146 EXPECT_EQ(rfh_a, current_frame_host());
6147 }
6148
6149 // On windows, the expected value is off by ~20ms. In order to get the
6150 // feature out to canary, the test is disabled for WIN.
6151 // TODO(crbug.com/1022191): Fix this for Win.
6152 #if defined(OS_WIN)
6153 #define MAYBE_NavigationStart DISABLED_NavigationStart
6154 #else
6155 #define MAYBE_NavigationStart NavigationStart
6156 #endif
6157 // Make sure we are exposing the duration between back navigation's
6158 // navigationStart and the page's original navigationStart through pageshow
6159 // event's timeStamp, and that we aren't modifying
6160 // performance.timing.navigationStart.
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,MAYBE_NavigationStart)6161 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, MAYBE_NavigationStart) {
6162 ASSERT_TRUE(embedded_test_server()->Start());
6163 GURL url_a(embedded_test_server()->GetURL(
6164 "a.com", "/back_forward_cache/record_navigation_start_time_stamp.html"));
6165 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
6166
6167 // 1) Navigate to A.
6168 EXPECT_TRUE(NavigateToURL(shell(), url_a));
6169 RenderFrameHostImpl* rfh_a = current_frame_host();
6170 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
6171
6172 double initial_page_show_time_stamp =
6173 EvalJs(shell(), "window.initialPageShowTimeStamp").ExtractDouble();
6174 EXPECT_EQ(initial_page_show_time_stamp,
6175 EvalJs(shell(), "window.latestPageShowTimeStamp"));
6176 double initial_navigation_start =
6177 EvalJs(shell(), "window.initialNavigationStart").ExtractDouble();
6178
6179 // 2) Navigate to B. A should be in the back forward cache.
6180 EXPECT_TRUE(NavigateToURL(shell(), url_b));
6181 EXPECT_FALSE(delete_observer_rfh_a.deleted());
6182 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
6183
6184 // 3) Navigate back and expect everything to be restored.
6185 NavigationHandleObserver observer(web_contents(), url_a);
6186 base::TimeTicks time_before_navigation = base::TimeTicks::Now();
6187 double js_time_before_navigation =
6188 EvalJs(shell(), "performance.now()").ExtractDouble();
6189 web_contents()->GetController().GoBack();
6190 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
6191 base::TimeTicks time_after_navigation = base::TimeTicks::Now();
6192 double js_time_after_navigation =
6193 EvalJs(shell(), "performance.now()").ExtractDouble();
6194
6195 // The navigation start time should be between the time we saved just before
6196 // calling GoBack() and the time we saved just after calling GoBack().
6197 base::TimeTicks back_navigation_start = observer.navigation_start();
6198 EXPECT_LT(time_before_navigation, back_navigation_start);
6199 EXPECT_GT(time_after_navigation, back_navigation_start);
6200
6201 // Check JS values. window.initialNavigationStart should not change.
6202 EXPECT_EQ(initial_navigation_start,
6203 EvalJs(shell(), "window.initialNavigationStart"));
6204 // performance.timing.navigationStart should not change.
6205 EXPECT_EQ(initial_navigation_start,
6206 EvalJs(shell(), "performance.timing.navigationStart"));
6207 // window.initialPageShowTimeStamp should not change.
6208 EXPECT_EQ(initial_page_show_time_stamp,
6209 EvalJs(shell(), "window.initialPageShowTimeStamp"));
6210 // window.latestPageShowTimeStamp should be updated with the timestamp of the
6211 // last pageshow event, which occurs after the page is restored. This should
6212 // be greater than the initial pageshow event's timestamp.
6213 double latest_page_show_time_stamp =
6214 EvalJs(shell(), "window.latestPageShowTimeStamp").ExtractDouble();
6215 EXPECT_LT(initial_page_show_time_stamp, latest_page_show_time_stamp);
6216
6217 // |latest_page_show_time_stamp| should be the duration between initial
6218 // navigation start and |back_navigation_start|. Note that since
6219 // performance.timing.navigationStart returns a 64-bit integer instead of
6220 // double, we might be losing somewhere between 0 to 1 milliseconds of
6221 // precision, hence the usage of EXPECT_NEAR.
6222 EXPECT_NEAR(
6223 (back_navigation_start - base::TimeTicks::UnixEpoch()).InMillisecondsF(),
6224 latest_page_show_time_stamp + initial_navigation_start, 1.0);
6225 // Expect that the back navigation start value calculated from the JS results
6226 // are between time taken before & after navigation, just like
6227 // |before_navigation_start|.
6228 EXPECT_LT(js_time_before_navigation, latest_page_show_time_stamp);
6229 EXPECT_GT(js_time_after_navigation, latest_page_show_time_stamp);
6230 }
6231
6232 // Do a same document navigation and make sure we do not fire the
6233 // DidFirstVisuallyNonEmptyPaint again
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,DoesNotFireDidFirstVisuallyNonEmptyPaintForSameDocumentNavigation)6234 IN_PROC_BROWSER_TEST_F(
6235 BackForwardCacheBrowserTest,
6236 DoesNotFireDidFirstVisuallyNonEmptyPaintForSameDocumentNavigation) {
6237 ASSERT_TRUE(embedded_test_server()->Start());
6238 GURL url_a_1(embedded_test_server()->GetURL(
6239 "a.com", "/accessibility/html/a-name.html"));
6240 GURL url_a_2(embedded_test_server()->GetURL(
6241 "a.com", "/accessibility/html/a-name.html#id"));
6242
6243 EXPECT_TRUE(NavigateToURL(shell(), url_a_1));
6244 WaitForFirstVisuallyNonEmptyPaint(shell()->web_contents());
6245
6246 FirstVisuallyNonEmptyPaintObserver observer(web_contents());
6247 EXPECT_TRUE(NavigateToURL(shell(), url_a_2));
6248 // Make sure the bfcache restore code does not fire the event during commit
6249 // navigation.
6250 EXPECT_FALSE(observer.did_fire());
6251 EXPECT_TRUE(web_contents()->CompletedFirstVisuallyNonEmptyPaint());
6252 }
6253
6254 // Make sure we fire DidFirstVisuallyNonEmptyPaint when restoring from bf-cache.
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,FiresDidFirstVisuallyNonEmptyPaintWhenRestoredFromCache)6255 IN_PROC_BROWSER_TEST_F(
6256 BackForwardCacheBrowserTest,
6257 FiresDidFirstVisuallyNonEmptyPaintWhenRestoredFromCache) {
6258 ASSERT_TRUE(embedded_test_server()->Start());
6259 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
6260 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
6261
6262 // 1) Navigate to A.
6263 EXPECT_TRUE(NavigateToURL(shell(), url_a));
6264 WaitForFirstVisuallyNonEmptyPaint(shell()->web_contents());
6265 RenderFrameHostImpl* rfh_a = current_frame_host();
6266 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
6267
6268 // 2) Navigate to B.
6269 EXPECT_TRUE(NavigateToURL(shell(), url_b));
6270 ASSERT_FALSE(delete_observer_rfh_a.deleted());
6271 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
6272 WaitForFirstVisuallyNonEmptyPaint(shell()->web_contents());
6273
6274 // 3) Navigate to back to A.
6275 FirstVisuallyNonEmptyPaintObserver observer(web_contents());
6276 web_contents()->GetController().GoBack();
6277 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
6278 // Make sure the bfcache restore code does fire the event during commit
6279 // navigation.
6280 EXPECT_TRUE(web_contents()->CompletedFirstVisuallyNonEmptyPaint());
6281 EXPECT_TRUE(observer.did_fire());
6282 }
6283
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,SetsThemeColorWhenRestoredFromCache)6284 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
6285 SetsThemeColorWhenRestoredFromCache) {
6286 ASSERT_TRUE(embedded_test_server()->Start());
6287 GURL url_a(embedded_test_server()->GetURL("a.com", "/theme_color.html"));
6288 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
6289
6290 EXPECT_TRUE(NavigateToURL(shell(), url_a));
6291 WaitForFirstVisuallyNonEmptyPaint(web_contents());
6292 RenderFrameHostImpl* rfh_a = current_frame_host();
6293 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
6294 EXPECT_EQ(web_contents()->GetThemeColor(), 0xFFFF0000u);
6295
6296 EXPECT_TRUE(NavigateToURL(shell(), url_b));
6297 WaitForFirstVisuallyNonEmptyPaint(web_contents());
6298 ASSERT_FALSE(delete_observer_rfh_a.deleted());
6299 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
6300 EXPECT_EQ(web_contents()->GetThemeColor(), base::nullopt);
6301
6302 ThemeColorObserver observer(web_contents());
6303 web_contents()->GetController().GoBack();
6304 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
6305 EXPECT_TRUE(observer.did_fire());
6306 EXPECT_EQ(web_contents()->GetThemeColor(), 0xFFFF0000u);
6307 }
6308
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,ContentsMimeTypeWhenRestoredFromCache)6309 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
6310 ContentsMimeTypeWhenRestoredFromCache) {
6311 ASSERT_TRUE(embedded_test_server()->Start());
6312 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
6313 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
6314
6315 // Navigate to A.
6316 EXPECT_TRUE(NavigateToURL(shell(), url_a));
6317 RenderFrameHostImpl* rfh_a = current_frame_host();
6318 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
6319 EXPECT_EQ(web_contents()->GetContentsMimeType(), "text/html");
6320
6321 // Navigate to B.
6322 EXPECT_TRUE(NavigateToURL(shell(), url_b));
6323 ASSERT_FALSE(delete_observer_rfh_a.deleted());
6324 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
6325
6326 // Go back to A, which restores A from bfcache. ContentsMimeType should be
6327 // restored as well.
6328 web_contents()->GetController().GoBack();
6329 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
6330 EXPECT_EQ(rfh_a, current_frame_host());
6331 ExpectOutcome(BackForwardCacheMetrics::HistoryNavigationOutcome::kRestored,
6332 FROM_HERE);
6333 EXPECT_EQ(web_contents()->GetContentsMimeType(), "text/html");
6334 }
6335
6336 // Check that an audio suspends when the page goes to the cache and can resume
6337 // after restored.
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,AudioSuspendAndResume)6338 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, AudioSuspendAndResume) {
6339 ASSERT_TRUE(embedded_test_server()->Start());
6340 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
6341 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
6342
6343 // 1) Navigate to A.
6344 EXPECT_TRUE(NavigateToURL(shell(), url_a));
6345 RenderFrameHostImpl* rfh_a = current_frame_host();
6346 EXPECT_TRUE(ExecJs(rfh_a, R"(
6347 var audio = document.createElement('audio');
6348 document.body.appendChild(audio);
6349
6350 audio.testObserverEvents = [];
6351 let event_list = [
6352 'canplaythrough',
6353 'pause',
6354 'play',
6355 'error',
6356 ];
6357 for (event_name of event_list) {
6358 let result = event_name;
6359 audio.addEventListener(event_name, event => {
6360 document.title = result;
6361 audio.testObserverEvents.push(result);
6362 });
6363 }
6364
6365 audio.src = 'media/bear-opus.ogg';
6366
6367 var timeOnFrozen = 0.0;
6368 audio.addEventListener('pause', () => {
6369 timeOnFrozen = audio.currentTime;
6370 });
6371 )"));
6372
6373 // Load the media.
6374 {
6375 TitleWatcher title_watcher(shell()->web_contents(),
6376 base::ASCIIToUTF16("canplaythrough"));
6377 title_watcher.AlsoWaitForTitle(base::ASCIIToUTF16("error"));
6378 EXPECT_EQ(base::ASCIIToUTF16("canplaythrough"),
6379 title_watcher.WaitAndGetTitle());
6380 }
6381
6382 EXPECT_TRUE(ExecJs(rfh_a, R"(
6383 new Promise(async resolve => {
6384 audio.play();
6385 while (audio.currentTime === 0)
6386 await new Promise(r => setTimeout(r, 1));
6387 resolve();
6388 });
6389 )"));
6390
6391 // 2) Navigate to B.
6392 EXPECT_TRUE(NavigateToURL(shell(), url_b));
6393 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
6394
6395 // 3) Navigate back to A.
6396 web_contents()->GetController().GoBack();
6397 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
6398 EXPECT_EQ(rfh_a, current_frame_host());
6399
6400 // Check that the media position is not changed when the page is in cache.
6401 double duration1 = EvalJs(rfh_a, "timeOnFrozen;").ExtractDouble();
6402 double duration2 = EvalJs(rfh_a, "audio.currentTime;").ExtractDouble();
6403 EXPECT_LE(0.0, duration2 - duration1);
6404 EXPECT_GT(0.01, duration2 - duration1);
6405
6406 // Resume the media.
6407 EXPECT_TRUE(ExecJs(rfh_a, "audio.play();"));
6408
6409 // Confirm that the media pauses automatically when going to the cache.
6410 // TODO(hajimehoshi): Confirm that this media automatically resumes if
6411 // autoplay attribute exists.
6412 EXPECT_EQ(ListValueOf("canplaythrough", "play", "pause", "play"),
6413 EvalJs(rfh_a, "audio.testObserverEvents"));
6414 }
6415
6416 // Check that a video suspends when the page goes to the cache and can resume
6417 // after restored.
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,VideoSuspendAndResume)6418 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, VideoSuspendAndResume) {
6419 ASSERT_TRUE(embedded_test_server()->Start());
6420 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
6421 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
6422
6423 // 1) Navigate to A.
6424 EXPECT_TRUE(NavigateToURL(shell(), url_a));
6425 RenderFrameHostImpl* rfh_a = current_frame_host();
6426 EXPECT_TRUE(ExecJs(rfh_a, R"(
6427 var video = document.createElement('video');
6428 document.body.appendChild(video);
6429
6430 video.testObserverEvents = [];
6431 let event_list = [
6432 'canplaythrough',
6433 'pause',
6434 'play',
6435 'error',
6436 ];
6437 for (event_name of event_list) {
6438 let result = event_name;
6439 video.addEventListener(event_name, event => {
6440 document.title = result;
6441 video.testObserverEvents.push(result);
6442 });
6443 }
6444
6445 video.src = 'media/bear.webm';
6446
6447 var timeOnFrozen = 0.0;
6448 video.addEventListener('pause', () => {
6449 timeOnFrozen = video.currentTime;
6450 });
6451 )"));
6452
6453 // Load the media.
6454 {
6455 TitleWatcher title_watcher(shell()->web_contents(),
6456 base::ASCIIToUTF16("canplaythrough"));
6457 title_watcher.AlsoWaitForTitle(base::ASCIIToUTF16("error"));
6458 EXPECT_EQ(base::ASCIIToUTF16("canplaythrough"),
6459 title_watcher.WaitAndGetTitle());
6460 }
6461
6462 EXPECT_TRUE(ExecJs(rfh_a, R"(
6463 new Promise(async resolve => {
6464 video.play();
6465 while (video.currentTime == 0)
6466 await new Promise(r => setTimeout(r, 1));
6467 resolve();
6468 });
6469 )"));
6470
6471 // 2) Navigate to B.
6472 EXPECT_TRUE(NavigateToURL(shell(), url_b));
6473 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
6474
6475 // 3) Navigate back to A.
6476 web_contents()->GetController().GoBack();
6477 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
6478 EXPECT_EQ(rfh_a, current_frame_host());
6479
6480 // Check that the media position is not changed when the page is in cache.
6481 double duration1 = EvalJs(rfh_a, "timeOnFrozen;").ExtractDouble();
6482 double duration2 = EvalJs(rfh_a, "video.currentTime;").ExtractDouble();
6483 EXPECT_LE(0.0, duration2 - duration1);
6484 EXPECT_GT(0.02, duration2 - duration1);
6485
6486 // Resume the media.
6487 EXPECT_TRUE(ExecJs(rfh_a, "video.play();"));
6488
6489 // Confirm that the media pauses automatically when going to the cache.
6490 // TODO(hajimehoshi): Confirm that this media automatically resumes if
6491 // autoplay attribute exists.
6492 EXPECT_EQ(ListValueOf("canplaythrough", "play", "pause", "play"),
6493 EvalJs(rfh_a, "video.testObserverEvents"));
6494 }
6495
6496 class SensorBackForwardCacheBrowserTest : public BackForwardCacheBrowserTest {
6497 protected:
SensorBackForwardCacheBrowserTest()6498 SensorBackForwardCacheBrowserTest() {
6499 SensorProviderProxyImpl::OverrideSensorProviderBinderForTesting(
6500 base::BindRepeating(
6501 &SensorBackForwardCacheBrowserTest::BindSensorProvider,
6502 base::Unretained(this)));
6503 }
6504
~SensorBackForwardCacheBrowserTest()6505 ~SensorBackForwardCacheBrowserTest() override {
6506 SensorProviderProxyImpl::OverrideSensorProviderBinderForTesting(
6507 base::NullCallback());
6508 }
6509
SetUpOnMainThread()6510 void SetUpOnMainThread() override {
6511 provider_ = std::make_unique<device::FakeSensorProvider>();
6512 provider_->SetAccelerometerData(1.0, 2.0, 3.0);
6513
6514 BackForwardCacheBrowserTest::SetUpOnMainThread();
6515 }
6516
6517 std::unique_ptr<device::FakeSensorProvider> provider_;
6518
6519 private:
BindSensorProvider(mojo::PendingReceiver<device::mojom::SensorProvider> receiver)6520 void BindSensorProvider(
6521 mojo::PendingReceiver<device::mojom::SensorProvider> receiver) {
6522 provider_->Bind(std::move(receiver));
6523 }
6524 };
6525
IN_PROC_BROWSER_TEST_F(SensorBackForwardCacheBrowserTest,AccelerometerNotCached)6526 IN_PROC_BROWSER_TEST_F(SensorBackForwardCacheBrowserTest,
6527 AccelerometerNotCached) {
6528 ASSERT_TRUE(embedded_test_server()->Start());
6529 GURL url_a(embedded_test_server()->GetURL("/title1.html"));
6530 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
6531
6532 // 1) Navigate to A.
6533 ASSERT_TRUE(NavigateToURL(shell(), url_a));
6534 RenderFrameHostImpl* rfh_a = current_frame_host();
6535 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
6536
6537 EXPECT_TRUE(ExecJs(rfh_a, R"(
6538 new Promise(resolve => {
6539 const sensor = new Accelerometer();
6540 sensor.addEventListener('reading', () => { resolve(); });
6541 sensor.start();
6542 })
6543 )"));
6544
6545 // 2) Navigate to B.
6546 ASSERT_TRUE(NavigateToURL(shell(), url_b));
6547
6548 // - Page A should not be in the cache.
6549 delete_observer_rfh_a.WaitUntilDeleted();
6550
6551 // 3) Go back.
6552 web_contents()->GetController().GoBack();
6553 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
6554 ExpectNotRestored(
6555 {BackForwardCacheMetrics::NotRestoredReason::kBlocklistedFeatures},
6556 FROM_HERE);
6557 }
6558
IN_PROC_BROWSER_TEST_F(SensorBackForwardCacheBrowserTest,OrientationCached)6559 IN_PROC_BROWSER_TEST_F(SensorBackForwardCacheBrowserTest, OrientationCached) {
6560 ASSERT_TRUE(embedded_test_server()->Start());
6561 GURL url_a(embedded_test_server()->GetURL("/title1.html"));
6562 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
6563
6564 // 1) Navigate to A.
6565 ASSERT_TRUE(NavigateToURL(shell(), url_a));
6566 RenderFrameHostImpl* rfh_a = current_frame_host();
6567 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
6568
6569 EXPECT_TRUE(ExecJs(rfh_a, R"(
6570 new Promise(resolve => {
6571 window.addEventListener("deviceorientation", () => { resolve(); }, true)
6572 })
6573 )"));
6574
6575 // 2) Navigate to B.
6576 ASSERT_TRUE(NavigateToURL(shell(), url_b));
6577
6578 EXPECT_FALSE(delete_observer_rfh_a.deleted());
6579 EXPECT_THAT(rfh_a, InBackForwardCache());
6580 }
6581
6582 // Tests that the orientation sensor's events are not delivered to a page in the
6583 // back-forward cache.
6584 //
6585 // This sets some JS functions in the pages to enable the sensors, capture and
6586 // validate the events. The a-page should only receive events with alpha=0, the
6587 // b-page is allowed to receive any alpha value. The test captures 3 events in
6588 // the a-page, then navigates to the b-page and changes the reading to have
6589 // alpha=1. While on the b-page it captures 3 more events. If the a-page is
6590 // still receiving events it should receive one or more of these. Finally it
6591 // resets the reasing back to have alpha=0 and navigates back to the a-page and
6592 // catpures 3 more events and verifies that all events on the a-page have
6593 // alpha=1.
6594 // Flaky on Mac and Linux ASAN/TSAN. https://crbug.com/1029238
6595 #if defined(OS_MAC) || \
6596 ((defined(OS_LINUX) || defined(OS_CHROMEOS)) && \
6597 (defined(ADDRESS_SANITIZER) || defined(THREAD_SANITIZER)))
6598 #define MAYBE_SensorPausedWhileCached DISABLED_SensorPausedWhileCached
6599 #else
6600 #define MAYBE_SensorPausedWhileCached SensorPausedWhileCached
6601 #endif
IN_PROC_BROWSER_TEST_F(SensorBackForwardCacheBrowserTest,MAYBE_SensorPausedWhileCached)6602 IN_PROC_BROWSER_TEST_F(SensorBackForwardCacheBrowserTest,
6603 MAYBE_SensorPausedWhileCached) {
6604 ASSERT_TRUE(CreateHttpsServer()->Start());
6605 GURL url_a(https_server()->GetURL("a.com", "/title1.html"));
6606 GURL url_b(https_server()->GetURL("b.com", "/title1.html"));
6607
6608 provider_->SetRelativeOrientationSensorData(0, 0, 0);
6609
6610 // JS to cause a page to listen to, capture and validate orientation events.
6611 const std::string sensor_js = R"(
6612 // Collects events that have happened so far.
6613 var events = [];
6614 // If set, will be called by handleEvent.
6615 var pendingResolve = null;
6616
6617 // Handles one event, pushing it to |events| and calling |pendingResolve| if
6618 // set.
6619 function handleEvent(event) {
6620 events.push(event);
6621 if (pendingResolve !== null) {
6622 pendingResolve('event');
6623 pendingResolve = null;
6624 }
6625 }
6626
6627 // Returns a promise that will resolve when the events array has at least
6628 // |eventCountMin| elements. Returns the number of elements.
6629 function waitForEventsPromise(eventCountMin) {
6630 if (events.length >= eventCountMin) {
6631 return Promise.resolve(events.length);
6632 }
6633 return new Promise(resolve => {
6634 pendingResolve = resolve;
6635 }).then(() => waitForEventsPromise(eventCountMin));
6636 }
6637
6638 // Pretty print an orientation event.
6639 function eventToString(event) {
6640 return `${event.alpha} ${event.beta} ${event.gamma}`;
6641 }
6642
6643 // Ensure that that |expectedAlpha| matches the alpha of all events.
6644 function validateEvents(expectedAlpha = null) {
6645 if (expectedAlpha !== null) {
6646 let count = 0;
6647 for (event of events) {
6648 count++;
6649 if (Math.abs(event.alpha - expectedAlpha) > 0.01) {
6650 return `fail - ${count}/${events.length}: ` +
6651 `${expectedAlpha} != ${event.alpha} (${eventToString(event)})`;
6652 }
6653 }
6654 }
6655 return 'pass';
6656 }
6657
6658 window.addEventListener('deviceorientation', handleEvent);
6659 )";
6660
6661 // 1) Navigate to A.
6662 ASSERT_TRUE(NavigateToURL(shell(), url_a));
6663 ASSERT_TRUE(WaitForLoadStop(shell()->web_contents()));
6664 RenderFrameHostImpl* rfh_a = current_frame_host();
6665 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
6666
6667 ASSERT_TRUE(ExecJs(rfh_a, sensor_js));
6668
6669 // Collect 3 orientation events.
6670 ASSERT_EQ(1, EvalJs(rfh_a, "waitForEventsPromise(1)"));
6671 provider_->UpdateRelativeOrientationSensorData(0, 0, 0.2);
6672 ASSERT_EQ(2, EvalJs(rfh_a, "waitForEventsPromise(2)"));
6673 provider_->UpdateRelativeOrientationSensorData(0, 0, 0.4);
6674 ASSERT_EQ(3, EvalJs(rfh_a, "waitForEventsPromise(3)"));
6675 // We should have 3 events with alpha=0.
6676 ASSERT_EQ("pass", EvalJs(rfh_a, "validateEvents(0)"));
6677
6678 // 2) Navigate to B.
6679 ASSERT_TRUE(NavigateToURL(shell(), url_b));
6680 ASSERT_TRUE(WaitForLoadStop(shell()->web_contents()));
6681 RenderFrameHostImpl* rfh_b = current_frame_host();
6682
6683 ASSERT_FALSE(delete_observer_rfh_a.deleted());
6684 ASSERT_THAT(rfh_a, InBackForwardCache());
6685 ASSERT_NE(rfh_a, rfh_b);
6686
6687 ASSERT_TRUE(ExecJs(rfh_b, sensor_js));
6688
6689 // Collect 3 orientation events.
6690 provider_->SetRelativeOrientationSensorData(1, 0, 0);
6691 ASSERT_EQ(1, EvalJs(rfh_b, "waitForEventsPromise(1)"));
6692 provider_->UpdateRelativeOrientationSensorData(1, 0, 0.2);
6693 ASSERT_EQ(2, EvalJs(rfh_b, "waitForEventsPromise(2)"));
6694 provider_->UpdateRelativeOrientationSensorData(1, 0, 0.4);
6695 ASSERT_EQ(3, EvalJs(rfh_b, "waitForEventsPromise(3)"));
6696 // We should have 3 events with alpha=1.
6697 ASSERT_EQ("pass", EvalJs(rfh_b, "validateEvents()"));
6698
6699 // 3) Go back to A.
6700 provider_->UpdateRelativeOrientationSensorData(0, 0, 0);
6701 web_contents()->GetController().GoBack();
6702 ASSERT_TRUE(WaitForLoadStop(shell()->web_contents()));
6703 ASSERT_EQ(rfh_a, current_frame_host());
6704
6705 // Collect 3 orientation events.
6706 provider_->UpdateRelativeOrientationSensorData(0, 0, 0);
6707 // There are 2 processes so, it's possible that more events crept in. So we
6708 // capture how many there are at this point and uses to wait for at least 3
6709 // more.
6710 int count = EvalJs(rfh_a, "waitForEventsPromise(4)").ExtractInt();
6711 provider_->UpdateRelativeOrientationSensorData(0, 0, 0.2);
6712 count++;
6713 ASSERT_EQ(count, EvalJs(rfh_a, base::StringPrintf("waitForEventsPromise(%d)",
6714 count)));
6715 provider_->UpdateRelativeOrientationSensorData(0, 0, 0.4);
6716 count++;
6717 ASSERT_EQ(count, EvalJs(rfh_a, base::StringPrintf("waitForEventsPromise(%d)",
6718 count)));
6719
6720 // We should have the earlier 3 plus another 3 events with alpha=0.
6721 ASSERT_EQ("pass", EvalJs(rfh_a, "validateEvents(0)"));
6722 }
6723
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,AllowedFeaturesForSubframesDoNotEvict)6724 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
6725 AllowedFeaturesForSubframesDoNotEvict) {
6726 // The main purpose of this test is to check that when a state of a subframe
6727 // is updated, CanStoreDocument is still called for the main frame - otherwise
6728 // we would always evict the document, even when the feature is allowed as
6729 // CanStoreDocument always returns false for non-main frames.
6730
6731 ASSERT_TRUE(embedded_test_server()->Start());
6732 GURL url_a(embedded_test_server()->GetURL(
6733 "a.com", "/cross_site_iframe_factory.html?a(b)"));
6734 GURL url_c(embedded_test_server()->GetURL("c.com", "/title1.html"));
6735
6736 // 1) Navigate to A.
6737 ASSERT_TRUE(NavigateToURL(shell(), url_a));
6738 RenderFrameHostImpl* rfh_a = current_frame_host();
6739 RenderFrameHostImpl* rfh_b = rfh_a->child_at(0)->current_frame_host();
6740 RenderFrameDeletedObserver delete_observer_rfh_b(rfh_b);
6741
6742 // 2) Navigate to C.
6743 ASSERT_TRUE(NavigateToURL(shell(), url_c));
6744
6745 // 3) No-op feature update on a subframe while in cache, should be no-op.
6746 ASSERT_FALSE(delete_observer_rfh_b.deleted());
6747 static_cast<blink::mojom::LocalFrameHost*>(rfh_b)
6748 ->DidChangeActiveSchedulerTrackedFeatures(0);
6749
6750 // 4) Go back.
6751 web_contents()->GetController().GoBack();
6752 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
6753 EXPECT_EQ(current_frame_host(), rfh_a);
6754
6755 ExpectOutcome(BackForwardCacheMetrics::HistoryNavigationOutcome::kRestored,
6756 FROM_HERE);
6757 }
6758
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,IsInactiveAndDisallowReactivationIsNoopWhenActive)6759 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
6760 IsInactiveAndDisallowReactivationIsNoopWhenActive) {
6761 ASSERT_TRUE(embedded_test_server()->Start());
6762 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
6763 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
6764
6765 // 1) Navigate to A.
6766 EXPECT_TRUE(NavigateToURL(shell(), url_a));
6767 EXPECT_FALSE(current_frame_host()->IsInactiveAndDisallowReactivation());
6768
6769 // 2) Navigate to B.
6770 EXPECT_TRUE(NavigateToURL(shell(), url_b));
6771
6772 // 3) Go back to A.
6773 web_contents()->GetController().GoBack();
6774 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
6775 ExpectOutcome(BackForwardCacheMetrics::HistoryNavigationOutcome::kRestored,
6776 FROM_HERE);
6777 }
6778
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,IsInactiveAndDisallowReactivationDoesEvictForCachedFrames)6779 IN_PROC_BROWSER_TEST_F(
6780 BackForwardCacheBrowserTest,
6781 IsInactiveAndDisallowReactivationDoesEvictForCachedFrames) {
6782 ASSERT_TRUE(embedded_test_server()->Start());
6783 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
6784 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
6785
6786 // 1) Navigate to A.
6787 EXPECT_TRUE(NavigateToURL(shell(), url_a));
6788 RenderFrameDeletedObserver delete_observer_rfh_a(current_frame_host());
6789 RenderFrameHostImpl* rfh_a = current_frame_host();
6790
6791 // 2) Navigate to B.
6792 EXPECT_TRUE(NavigateToURL(shell(), url_b));
6793 EXPECT_TRUE(rfh_a->IsInactiveAndDisallowReactivation());
6794
6795 // 3) Go back to A.
6796 web_contents()->GetController().GoBack();
6797 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
6798 ExpectNotRestored(
6799 {BackForwardCacheMetrics::NotRestoredReason::kIgnoreEventAndEvict},
6800 FROM_HERE);
6801 }
6802
6803 // Test for functionality of memory controls in back-forward cache for low
6804 // memory devices.
6805 class BackForwardCacheBrowserTestForLowMemoryDevices
6806 : public BackForwardCacheBrowserTest {
6807 protected:
SetUpCommandLine(base::CommandLine * command_line)6808 void SetUpCommandLine(base::CommandLine* command_line) override {
6809 // Set the value of memory threshold more than the physical memory and check
6810 // if back-forward cache is disabled or not.
6811 std::string memory_threshold =
6812 base::NumberToString(base::SysInfo::AmountOfPhysicalMemoryMB() + 1);
6813 EnableFeatureAndSetParams(features::kBackForwardCacheMemoryControl,
6814 "memory_threshold_for_back_forward_cache_in_mb",
6815 memory_threshold);
6816
6817 BackForwardCacheBrowserTest::SetUpCommandLine(command_line);
6818 }
6819 };
6820
6821 // Navigate from A to B and go back.
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTestForLowMemoryDevices,DisableBFCacheForLowEndDevices)6822 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTestForLowMemoryDevices,
6823 DisableBFCacheForLowEndDevices) {
6824 ASSERT_TRUE(embedded_test_server()->Start());
6825 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
6826 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
6827
6828 // Ensure that the trial starts inactive.
6829 EXPECT_FALSE(base::FieldTrialList::IsTrialActive(
6830 base::FeatureList::GetFieldTrial(features::kBackForwardCache)
6831 ->trial_name()));
6832
6833 EXPECT_FALSE(IsBackForwardCacheEnabled());
6834
6835 // Ensure that we do not activate the trial when querying bfcache status,
6836 // which is protected by low-memory setting.
6837 EXPECT_FALSE(base::FieldTrialList::IsTrialActive(
6838 base::FeatureList::GetFieldTrial(features::kBackForwardCache)
6839 ->trial_name()));
6840
6841 // 1) Navigate to A.
6842 EXPECT_TRUE(NavigateToURL(shell(), url_a));
6843 RenderFrameHostImpl* rfh_a = current_frame_host();
6844 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
6845
6846 // 2) Navigate to B.
6847 EXPECT_TRUE(NavigateToURL(shell(), url_b));
6848
6849 // 3) A shouldn't be stored in back-forward cache because the physical
6850 // memory is less than the memory threshold.
6851 delete_observer_rfh_a.WaitUntilDeleted();
6852
6853 // Nothing is recorded when the memory is less than the threshold value.
6854 ExpectOutcomeDidNotChange(FROM_HERE);
6855 ExpectNotRestoredDidNotChange(FROM_HERE);
6856
6857 // Ensure that the trial still hasn't been activated.
6858 EXPECT_FALSE(base::FieldTrialList::IsTrialActive(
6859 base::FeatureList::GetFieldTrial(features::kBackForwardCache)
6860 ->trial_name()));
6861 }
6862
6863 // Test for functionality of memory controls in back-forward cache for high
6864 // memory devices.
6865 class BackForwardCacheBrowserTestForHighMemoryDevices
6866 : public BackForwardCacheBrowserTest {
6867 protected:
SetUpCommandLine(base::CommandLine * command_line)6868 void SetUpCommandLine(base::CommandLine* command_line) override {
6869 // Set the value of memory threshold less than the physical memory and check
6870 // if back-forward cache is enabled or not.
6871 std::string memory_threshold =
6872 base::NumberToString(base::SysInfo::AmountOfPhysicalMemoryMB() - 1);
6873 EnableFeatureAndSetParams(features::kBackForwardCacheMemoryControl,
6874 "memory_threshold_for_back_forward_cache_in_mb",
6875 memory_threshold);
6876
6877 BackForwardCacheBrowserTest::SetUpCommandLine(command_line);
6878 }
6879 };
6880
6881 // Navigate from A to B and go back.
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTestForHighMemoryDevices,EnableBFCacheForHighMemoryDevices)6882 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTestForHighMemoryDevices,
6883 EnableBFCacheForHighMemoryDevices) {
6884 ASSERT_TRUE(embedded_test_server()->Start());
6885 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
6886 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
6887
6888 // 1) Navigate to A.
6889 EXPECT_TRUE(NavigateToURL(shell(), url_a));
6890 RenderFrameHostImpl* rfh_a = current_frame_host();
6891
6892 // 2) Navigate to B.
6893 EXPECT_TRUE(NavigateToURL(shell(), url_b));
6894
6895 // 3) A should be stored in back-forward cache because the physical memory is
6896 // greater than the memory threshold.
6897 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
6898 }
6899
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,EvictingDocumentsInRelatedSiteInstancesDoesNotRestartNavigation)6900 IN_PROC_BROWSER_TEST_F(
6901 BackForwardCacheBrowserTest,
6902 EvictingDocumentsInRelatedSiteInstancesDoesNotRestartNavigation) {
6903 ASSERT_TRUE(embedded_test_server()->Start());
6904 GURL url_a1(embedded_test_server()->GetURL("a.com", "/title1.html#part1"));
6905 GURL url_a2(embedded_test_server()->GetURL("a.com", "/title1.html#part2"));
6906 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
6907
6908 // 1) Navigate to A1.
6909 EXPECT_TRUE(NavigateToURL(shell(), url_a1));
6910
6911 // 2) Navigate to A2.
6912 EXPECT_TRUE(NavigateToURL(shell(), url_a2));
6913
6914 // 3) Navigate to B.
6915 EXPECT_TRUE(NavigateToURL(shell(), url_b));
6916
6917 // 4) Go back to A2, but do not wait for the navigation to commit.
6918 web_contents()->GetController().GoBack();
6919
6920 // 5) Go back to A1.
6921 // This will attempt to evict A2 from the cache because
6922 // their navigation entries have related site instances, while a navigation
6923 // to A2 is in flight. Ensure that we do not try to restart it as it should
6924 // be superseded by a navigation to A1.
6925 web_contents()->GetController().GoBack();
6926 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
6927 EXPECT_EQ(url_a1, web_contents()->GetURL());
6928 }
6929
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,RTCPeerConnectionNotCached)6930 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
6931 RTCPeerConnectionNotCached) {
6932 ASSERT_TRUE(embedded_test_server()->Start());
6933 GURL url_a(embedded_test_server()->GetURL("/title1.html"));
6934 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
6935
6936 // 1) Navigate to A.
6937 ASSERT_TRUE(NavigateToURL(shell(), url_a));
6938 RenderFrameHostImpl* rfh_a = current_frame_host();
6939 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
6940
6941 EXPECT_TRUE(ExecJs(rfh_a, "new RTCPeerConnection()"));
6942
6943 // 2) Navigate to B.
6944 ASSERT_TRUE(NavigateToURL(shell(), url_b));
6945
6946 // - Page A should not be in the cache.
6947 delete_observer_rfh_a.WaitUntilDeleted();
6948
6949 // 3) Go back.
6950 web_contents()->GetController().GoBack();
6951 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
6952 ExpectNotRestored(
6953 {BackForwardCacheMetrics::NotRestoredReason::kBlocklistedFeatures},
6954 FROM_HERE);
6955 ExpectBlocklistedFeature(
6956 blink::scheduler::WebSchedulerTrackedFeature::kWebRTC, FROM_HERE);
6957 }
6958
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,WebLocksNotCached)6959 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, WebLocksNotCached) {
6960 ASSERT_TRUE(embedded_test_server()->Start());
6961 GURL url_a(embedded_test_server()->GetURL("/title1.html"));
6962 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
6963
6964 // 1) Navigate to A.
6965 ASSERT_TRUE(NavigateToURL(shell(), url_a));
6966 RenderFrameHostImpl* rfh_a = current_frame_host();
6967 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
6968
6969 // Wait for the page to acquire a lock and ensure that it continues to do so.
6970 EXPECT_TRUE(ExecJs(rfh_a, R"(
6971 const never_resolved = new Promise(resolve => {});
6972 new Promise(continue_test => {
6973 navigator.locks.request('test', async () => {
6974 continue_test();
6975 await never_resolved;
6976 });
6977 })
6978 )"));
6979
6980 // 2) Navigate to B.
6981 ASSERT_TRUE(NavigateToURL(shell(), url_b));
6982
6983 // - Page A should not be in the cache.
6984 delete_observer_rfh_a.WaitUntilDeleted();
6985
6986 // 3) Go back.
6987 web_contents()->GetController().GoBack();
6988 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
6989 ExpectNotRestored(
6990 {BackForwardCacheMetrics::NotRestoredReason::kBlocklistedFeatures},
6991 FROM_HERE);
6992 ExpectBlocklistedFeature(
6993 blink::scheduler::WebSchedulerTrackedFeature::kWebLocks, FROM_HERE);
6994 }
6995
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,CanUseCacheWhenNavigatingAwayToErrorPage)6996 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
6997 CanUseCacheWhenNavigatingAwayToErrorPage) {
6998 ASSERT_TRUE(embedded_test_server()->Start());
6999
7000 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
7001 GURL error_url(embedded_test_server()->GetURL("b.com", "/empty.html"));
7002 auto url_interceptor = URLLoaderInterceptor::SetupRequestFailForURL(
7003 error_url, net::ERR_DNS_TIMED_OUT);
7004
7005 // 1) Navigate to A.
7006 EXPECT_TRUE(NavigateToURL(shell(), url_a));
7007 RenderFrameHostImpl* rfh_a = current_frame_host();
7008
7009 // 2) Navigate to an error page and expect the old page to be stored in
7010 // bfcache.
7011 EXPECT_FALSE(NavigateToURL(shell(), error_url));
7012 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
7013
7014 // 3) Navigate back and expect the page to be restored from bfcache.
7015 web_contents()->GetController().GoBack();
7016 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
7017 }
7018
7019 // Start an inifite dialogs in JS, yielding after each. The first dialog should
7020 // be dismissed by navigation. The later dialogs should be handled gracefully
7021 // and not appear while in BFCache. Finally, when the page comes out of BFCache,
7022 // dialogs should appear again.
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,CanUseCacheWhenPageAlertsInTimeoutLoop)7023 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
7024 CanUseCacheWhenPageAlertsInTimeoutLoop) {
7025 ASSERT_TRUE(embedded_test_server()->Start());
7026
7027 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
7028 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
7029
7030 // Navigate to A.
7031 EXPECT_TRUE(NavigateToURL(shell(), url_a));
7032 RenderFrameHostImpl* rfh_a = current_frame_host();
7033 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
7034
7035 AppModalDialogWaiter dialog_waiter(shell());
7036
7037 EXPECT_TRUE(ExecJs(rfh_a, R"(
7038 function alertLoop() {
7039 setTimeout(alertLoop, 0);
7040 window.alert("alert");
7041 }
7042 // Don't block this script.
7043 setTimeout(alertLoop, 0);
7044 )"));
7045
7046 dialog_waiter.Wait();
7047
7048 // Navigate to B.
7049 ASSERT_TRUE(NavigateToURL(shell(), url_b));
7050 RenderFrameHostImpl* rfh_b = current_frame_host();
7051
7052 ASSERT_FALSE(delete_observer_rfh_a.deleted());
7053 ASSERT_THAT(rfh_a, InBackForwardCache());
7054 ASSERT_NE(rfh_a, rfh_b);
7055
7056 dialog_waiter.Restart();
7057
7058 // Go back.
7059 web_contents()->GetController().GoBack();
7060 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
7061 EXPECT_EQ(rfh_a, current_frame_host());
7062 EXPECT_FALSE(rfh_a->IsInBackForwardCache());
7063
7064 // The page should still be requesting dialogs in a loop. Wait for one to be
7065 // requested.
7066 dialog_waiter.Wait();
7067 }
7068
7069 // UnloadOldFrame will clear all dialogs. We test that further requests for
7070 // dialogs coming from JS do not result in the creation of a dialog. This test
7071 // posts some dialog creation JS to the render from inside the
7072 // CommitNavigationCallback task. This JS is then able to post a task back to
7073 // the renders to show a dialog. By the time this task runs, we the
7074 // RenderFrameHostImpl's is_active() should be false.
7075 //
7076 // This test is not perfect, it can pass simply because the renderer thread does
7077 // not run the JS in time. Ideally it would block until the renderer posts the
7078 // request for a dialog but it's possible to do that without creating a nested
7079 // message loop and if we do that, we risk processing the dialog request.
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,DialogsCancelledAndSuppressedWhenCached)7080 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
7081 DialogsCancelledAndSuppressedWhenCached) {
7082 ASSERT_TRUE(embedded_test_server()->Start());
7083
7084 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
7085 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
7086
7087 // Navigate to A.
7088 EXPECT_TRUE(NavigateToURL(shell(), url_a));
7089 RenderFrameHostImpl* rfh_a = current_frame_host();
7090 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
7091
7092 // Let's us know whether the following callback ran. Not strictly necessary
7093 // since it really should run.
7094 bool posted_dialog_js = false;
7095 // Create a callback that will be called during the DidCommitNavigation task.
7096 WillEnterBackForwardCacheCallbackForTesting
7097 will_enter_back_forward_cache_callback =
7098 base::BindLambdaForTesting([&]() {
7099 // Post a dialog, it should not result in a dialog being created.
7100 ExecuteScriptAsync(rfh_a, R"(window.alert("alert");)");
7101 posted_dialog_js = true;
7102 });
7103 rfh_a->render_view_host()->SetWillEnterBackForwardCacheCallbackForTesting(
7104 will_enter_back_forward_cache_callback);
7105
7106 AppModalDialogWaiter dialog_waiter(shell());
7107
7108 // Try show another dialog. It should work.
7109 ExecuteScriptAsync(rfh_a, R"(window.alert("alert");)");
7110 dialog_waiter.Wait();
7111
7112 dialog_waiter.Restart();
7113
7114 // Navigate to B.
7115 ASSERT_TRUE(NavigateToURL(shell(), url_b));
7116 RenderFrameHostImpl* rfh_b = current_frame_host();
7117
7118 ASSERT_FALSE(delete_observer_rfh_a.deleted());
7119 ASSERT_THAT(rfh_a, InBackForwardCache());
7120 ASSERT_NE(rfh_a, rfh_b);
7121 // Test that the JS was run and that it didn't result in a dialog.
7122 ASSERT_TRUE(posted_dialog_js);
7123 ASSERT_FALSE(dialog_waiter.WasDialogRequestedCallbackCalled());
7124
7125 // Go back.
7126 web_contents()->GetController().GoBack();
7127 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
7128
7129 EXPECT_EQ(rfh_a, current_frame_host());
7130 EXPECT_FALSE(rfh_a->IsInBackForwardCache());
7131
7132 // Try show another dialog. It should work.
7133 ExecuteScriptAsync(rfh_a, R"(window.alert("alert");)");
7134 dialog_waiter.Wait();
7135 }
7136
7137 namespace {
7138
7139 class ExecJsInDidFinishNavigation : public WebContentsObserver {
7140 public:
ExecJsInDidFinishNavigation(WebContents * web_contents)7141 ExecJsInDidFinishNavigation(WebContents* web_contents)
7142 : WebContentsObserver(web_contents) {}
7143
DidFinishNavigation(NavigationHandle * navigation_handle)7144 void DidFinishNavigation(NavigationHandle* navigation_handle) override {
7145 if (!navigation_handle->IsInMainFrame() ||
7146 !navigation_handle->HasCommitted() ||
7147 navigation_handle->IsSameDocument()) {
7148 return;
7149 }
7150
7151 ExecuteScriptAsync(navigation_handle->GetRenderFrameHost(),
7152 "var foo = 42;");
7153 }
7154 };
7155
7156 } // namespace
7157
7158 // This test checks that the message posted from DidFinishNavigation
7159 // (ExecuteScriptAsync) is received after the message restoring the page from
7160 // the back-forward cache (PageMsg_RestorePageFromBackForwardCache).
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,MessageFromDidFinishNavigation)7161 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
7162 MessageFromDidFinishNavigation) {
7163 ASSERT_TRUE(embedded_test_server()->Start());
7164 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
7165 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
7166
7167 // 1) Navigate to A.
7168 EXPECT_TRUE(NavigateToURL(shell(), url_a));
7169 RenderFrameHostImpl* rfh_a = current_frame_host();
7170 EXPECT_TRUE(ExecJs(rfh_a, "window.alive = 'I am alive';"));
7171
7172 // 2) Navigate to B.
7173 EXPECT_TRUE(NavigateToURL(shell(), url_b));
7174
7175 ExecJsInDidFinishNavigation observer(shell()->web_contents());
7176
7177 // 3) Go back to A. Expect the page to be restored from the cache.
7178 web_contents()->GetController().GoBack();
7179 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
7180 EXPECT_EQ("I am alive", EvalJs(rfh_a, "window.alive"));
7181
7182 // Make sure that the javascript execution requested from DidFinishNavigation
7183 // did not result in eviction. If the document was evicted, the document
7184 // would be reloaded - check that it didn't happen and the tab is not
7185 // loading.
7186 EXPECT_FALSE(web_contents()->IsLoading());
7187
7188 EXPECT_EQ(rfh_a, current_frame_host());
7189 }
7190
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,WebMidiNotCached)7191 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, WebMidiNotCached) {
7192 ASSERT_TRUE(embedded_test_server()->Start());
7193 GURL url_a(embedded_test_server()->GetURL("/title1.html"));
7194 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
7195
7196 // 1) Navigate to A.
7197 ASSERT_TRUE(NavigateToURL(shell(), url_a));
7198 RenderFrameHostImpl* rfh_a = current_frame_host();
7199 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
7200
7201 // - Wait until requestMIDIAccess() promise is resolved.
7202 EXPECT_TRUE(ExecJs(rfh_a, "navigator.requestMIDIAccess()"));
7203
7204 // 2) Navigate to B.
7205 ASSERT_TRUE(NavigateToURL(shell(), url_b));
7206
7207 // - Page A should not be in the cache.
7208 delete_observer_rfh_a.WaitUntilDeleted();
7209
7210 // 3) Go back.
7211 web_contents()->GetController().GoBack();
7212 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
7213 ExpectNotRestored(
7214 {BackForwardCacheMetrics::NotRestoredReason::kBlocklistedFeatures},
7215 FROM_HERE);
7216 ExpectBlocklistedFeature(
7217 blink::scheduler::WebSchedulerTrackedFeature::kRequestedMIDIPermission,
7218 FROM_HERE);
7219 }
7220
7221 #if defined(OS_ANDROID)
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,ChildImportanceTestForBackForwardCachedPagesTest)7222 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
7223 ChildImportanceTestForBackForwardCachedPagesTest) {
7224 web_contents()->SetMainFrameImportance(ChildProcessImportance::MODERATE);
7225
7226 ASSERT_TRUE(embedded_test_server()->Start());
7227 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
7228 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
7229
7230 // 1) Navigate to A.
7231 EXPECT_TRUE(NavigateToURL(shell(), url_a));
7232 RenderFrameHostImpl* rfh_a = current_frame_host();
7233 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
7234
7235 // 2) Navigate to B.
7236 EXPECT_TRUE(NavigateToURL(shell(), url_b));
7237 ASSERT_FALSE(delete_observer_rfh_a.deleted());
7238
7239 // 3) Verify the importance of page after entering back-forward cache to be
7240 // "NORMAL".
7241 EXPECT_EQ(ChildProcessImportance::NORMAL,
7242 rfh_a->GetProcess()->GetEffectiveImportance());
7243
7244 // 4) Go back to A.
7245 web_contents()->GetController().GoBack();
7246 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
7247
7248 // 5) Verify the importance was restored correctly after page leaves
7249 // back-forward cache.
7250 EXPECT_EQ(ChildProcessImportance::MODERATE,
7251 rfh_a->GetProcess()->GetEffectiveImportance());
7252 }
7253 #endif
7254
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,PresentationConnectionClosed)7255 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
7256 PresentationConnectionClosed) {
7257 ASSERT_TRUE(CreateHttpsServer()->Start());
7258 GURL url_a(https_server()->GetURL(
7259 "a.com", "/back_forward_cache/presentation_controller.html"));
7260
7261 // Navigate to A (presentation controller page).
7262 ASSERT_TRUE(NavigateToURL(shell(), url_a));
7263 auto* rfh_a = current_frame_host();
7264 // Start a presentation connection in A.
7265 MockPresentationServiceDelegate mock_presentation_service_delegate;
7266 auto& presentation_service = rfh_a->GetPresentationServiceForTesting();
7267 presentation_service.SetControllerDelegateForTesting(
7268 &mock_presentation_service_delegate);
7269 EXPECT_CALL(mock_presentation_service_delegate, StartPresentation(_, _, _));
7270 EXPECT_TRUE(ExecJs(rfh_a, "presentationRequest.start().then(setConnection)"));
7271
7272 // Send a mock connection to the renderer.
7273 MockPresentationConnection mock_controller_connection;
7274 mojo::Receiver<PresentationConnection> controller_connection_receiver(
7275 &mock_controller_connection);
7276 mojo::Remote<PresentationConnection> receiver_connection;
7277 const std::string presentation_connection_id = "foo";
7278 presentation_service.OnStartPresentationSucceeded(
7279 presentation_service.start_presentation_request_id_,
7280 PresentationConnectionResult::New(
7281 blink::mojom::PresentationInfo::New(GURL("fake-url"),
7282 presentation_connection_id),
7283 controller_connection_receiver.BindNewPipeAndPassRemote(),
7284 receiver_connection.BindNewPipeAndPassReceiver()));
7285
7286 // Navigate to B, make sure that the connection started in A is closed.
7287 GURL url_b(https_server()->GetURL("b.com", "/title1.html"));
7288 EXPECT_CALL(
7289 mock_controller_connection,
7290 DidClose(blink::mojom::PresentationConnectionCloseReason::WENT_AWAY));
7291 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
7292 ASSERT_TRUE(NavigateToURL(shell(), url_b));
7293 EXPECT_FALSE(delete_observer_rfh_a.deleted());
7294 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
7295
7296 // Navigate back to A. Ensure that connection state has been updated
7297 // accordingly.
7298 web_contents()->GetController().GoBack();
7299 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
7300 EXPECT_FALSE(rfh_a->IsInBackForwardCache());
7301 EXPECT_EQ(presentation_connection_id, EvalJs(rfh_a, "connection.id"));
7302 EXPECT_EQ("closed", EvalJs(rfh_a, "connection.state"));
7303 EXPECT_TRUE(EvalJs(rfh_a, "connectionClosed").ExtractBool());
7304
7305 // Try to start another connection, should successfully reach the browser side
7306 // PresentationServiceDelegate.
7307 EXPECT_CALL(mock_presentation_service_delegate,
7308 ReconnectPresentation(_, presentation_connection_id, _, _));
7309 EXPECT_TRUE(ExecJs(rfh_a, "presentationRequest.reconnect(connection.id)"));
7310 base::RunLoop().RunUntilIdle();
7311
7312 // Reset |presentation_service|'s controller delegate so that it won't try to
7313 // call Reset() on it on destruction time.
7314 presentation_service.OnDelegateDestroyed();
7315 }
7316
7317 namespace {
7318
7319 // Subclass of FrameServiceBase for test.
7320 class EchoImpl final : public FrameServiceBase<mojom::Echo> {
7321 public:
EchoImpl(RenderFrameHost * render_frame_host,mojo::PendingReceiver<mojom::Echo> receiver,bool * deleted)7322 EchoImpl(RenderFrameHost* render_frame_host,
7323 mojo::PendingReceiver<mojom::Echo> receiver,
7324 bool* deleted)
7325 : FrameServiceBase(render_frame_host, std::move(receiver)),
7326 deleted_(deleted) {}
~EchoImpl()7327 ~EchoImpl() final { *deleted_ = true; }
7328
7329 // mojom::Echo implementation
EchoString(const std::string & input,EchoStringCallback callback)7330 void EchoString(const std::string& input, EchoStringCallback callback) final {
7331 std::move(callback).Run(input);
7332 }
7333
7334 private:
7335 bool* deleted_;
7336 };
7337
7338 } // namespace
7339
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,FrameServiceBase)7340 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, FrameServiceBase) {
7341 ASSERT_TRUE(embedded_test_server()->Start());
7342 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
7343 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
7344
7345 // 1) Navigate to A.
7346 ASSERT_TRUE(NavigateToURL(shell(), url_a));
7347 RenderFrameHostImpl* rfh_a = current_frame_host();
7348 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
7349
7350 mojo::Remote<mojom::Echo> echo_remote;
7351 bool echo_deleted = false;
7352 new EchoImpl(rfh_a, echo_remote.BindNewPipeAndPassReceiver(), &echo_deleted);
7353
7354 // 2) Navigate to B.
7355 ASSERT_TRUE(NavigateToURL(shell(), url_b));
7356
7357 // - Page A should be in the cache.
7358 ASSERT_FALSE(delete_observer_rfh_a.deleted());
7359 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
7360 EXPECT_FALSE(echo_deleted);
7361
7362 // 3) Go back.
7363 web_contents()->GetController().GoBack();
7364 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
7365 EXPECT_FALSE(echo_deleted);
7366
7367 // 4) Prevent caching and navigate to B.
7368 BackForwardCache::DisableForRenderFrameHost(rfh_a, "test");
7369 ASSERT_TRUE(NavigateToURL(shell(), url_b));
7370 delete_observer_rfh_a.WaitUntilDeleted();
7371 EXPECT_TRUE(echo_deleted);
7372 }
7373
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,OutstandingFetchNotCached)7374 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, OutstandingFetchNotCached) {
7375 net::test_server::ControllableHttpResponse response(embedded_test_server(),
7376 "/fetch");
7377 ASSERT_TRUE(embedded_test_server()->Start());
7378
7379 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
7380 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
7381
7382 // 1) Navigate to A.
7383 EXPECT_TRUE(NavigateToURL(shell(), url_a));
7384 RenderFrameHostImpl* rfh_a = current_frame_host();
7385 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
7386 // Ensure that there are no lingering requests from page load itself.
7387 EXPECT_FALSE(rfh_a->scheduler_tracked_features() &
7388 (1ull << static_cast<size_t>(
7389 blink::scheduler::WebSchedulerTrackedFeature::
7390 kOutstandingNetworkRequestFetch)));
7391
7392 // 2) Create a fetch() request.
7393 EXPECT_TRUE(ExecJs(rfh_a, "fetch('/fetch');"));
7394 response.WaitForRequest();
7395
7396 // 3) Navigate to B.
7397 ASSERT_TRUE(NavigateToURL(shell(), url_b));
7398
7399 // 4) Go back.
7400 web_contents()->GetController().GoBack();
7401 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
7402
7403 ExpectNotRestored(
7404 {BackForwardCacheMetrics::NotRestoredReason::kBlocklistedFeatures},
7405 FROM_HERE);
7406 ExpectBlocklistedFeature(blink::scheduler::WebSchedulerTrackedFeature::
7407 kOutstandingNetworkRequestFetch,
7408 FROM_HERE);
7409 }
7410
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,OutstandingXHRNotCached)7411 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, OutstandingXHRNotCached) {
7412 net::test_server::ControllableHttpResponse response(embedded_test_server(),
7413 "/xhr");
7414 ASSERT_TRUE(embedded_test_server()->Start());
7415
7416 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
7417 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
7418
7419 // 1) Navigate to A.
7420 EXPECT_TRUE(NavigateToURL(shell(), url_a));
7421 RenderFrameHostImpl* rfh_a = current_frame_host();
7422 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
7423 // Ensure that there are no lingering requests from page load itself.
7424 EXPECT_FALSE(rfh_a->scheduler_tracked_features() &
7425 (1ull << static_cast<size_t>(
7426 blink::scheduler::WebSchedulerTrackedFeature::
7427 kOutstandingNetworkRequestXHR)));
7428
7429 // 2) Create a XMLHttpRequest.
7430 EXPECT_TRUE(ExecJs(rfh_a, R"(
7431 var req = new XMLHttpRequest();
7432 req.open("GET", "/xhr");
7433 req.send();
7434 )"));
7435 response.WaitForRequest();
7436
7437 // 3) Navigate to B.
7438 ASSERT_TRUE(NavigateToURL(shell(), url_b));
7439
7440 // 4) Go back.
7441 web_contents()->GetController().GoBack();
7442 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
7443
7444 ExpectNotRestored(
7445 {BackForwardCacheMetrics::NotRestoredReason::kBlocklistedFeatures},
7446 FROM_HERE);
7447 ExpectBlocklistedFeature(blink::scheduler::WebSchedulerTrackedFeature::
7448 kOutstandingNetworkRequestXHR,
7449 FROM_HERE);
7450 }
7451
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,NotFetchedScriptNotCached)7452 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, NotFetchedScriptNotCached) {
7453 net::test_server::ControllableHttpResponse response(
7454 embedded_test_server(),
7455 "/back_forward_cache/script-which-does-not-exist.js");
7456 ASSERT_TRUE(embedded_test_server()->Start());
7457
7458 GURL url_a(embedded_test_server()->GetURL(
7459 "a.com", "/back_forward_cache/page_with_nonexistent_script.html"));
7460 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
7461
7462 // 1) Navigate to A.
7463 TestNavigationObserver navigation_observer1(web_contents());
7464 shell()->LoadURL(url_a);
7465 navigation_observer1.WaitForNavigationFinished();
7466 response.WaitForRequest();
7467
7468 RenderFrameHostImpl* rfh_a = current_frame_host();
7469 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
7470
7471 // 2) Navigate to B.
7472 TestNavigationObserver navigation_observer2(web_contents());
7473 shell()->LoadURL(url_b);
7474 navigation_observer2.WaitForNavigationFinished();
7475
7476 delete_observer_rfh_a.WaitUntilDeleted();
7477
7478 // 3) Go back.
7479 web_contents()->GetController().GoBack();
7480 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
7481
7482 ExpectNotRestored(
7483 {BackForwardCacheMetrics::NotRestoredReason::kBlocklistedFeatures},
7484 FROM_HERE);
7485 ExpectBlocklistedFeature(blink::scheduler::WebSchedulerTrackedFeature::
7486 kOutstandingNetworkRequestOthers,
7487 FROM_HERE);
7488 }
7489
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,PageshowMetrics)7490 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, PageshowMetrics) {
7491 ASSERT_TRUE(embedded_test_server()->Start());
7492
7493 const char kHistogramName[] =
7494 "BackForwardCache.MainFrameHasPageshowListenersOnRestore";
7495
7496 const GURL url1(embedded_test_server()->GetURL("a.com", "/title1.html"));
7497 const GURL url2(embedded_test_server()->GetURL("b.com", "/title1.html"));
7498
7499 // 1) Navigate to the page.
7500 EXPECT_TRUE(NavigateToURL(shell(), url1));
7501 EXPECT_TRUE(ExecJs(current_frame_host(), R"(
7502 window.foo = 42;
7503 )"));
7504
7505 // 2) Navigate away and back.
7506 EXPECT_TRUE(NavigateToURL(shell(), url2));
7507 web_contents()->GetController().GoBack();
7508 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
7509
7510 // As we don't get an explicit ACK when the page is restored (yet), force
7511 // a round-trip to the renderer to effectively flush the queue.
7512 EXPECT_EQ(42, EvalJs(current_frame_host(), "window.foo"));
7513
7514 // Expect the back-forward restore without pageshow to be detected.
7515 content::FetchHistogramsFromChildProcesses();
7516 EXPECT_THAT(histogram_tester_.GetAllSamples(kHistogramName),
7517 ElementsAre(base::Bucket(0, 1)));
7518
7519 EXPECT_TRUE(ExecJs(current_frame_host(), R"(
7520 window.addEventListener("pageshow", () => {});
7521 )"));
7522
7523 // 3) Navigate away and back (again).
7524 EXPECT_TRUE(NavigateToURL(shell(), url2));
7525 web_contents()->GetController().GoBack();
7526 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
7527
7528 // As we don't get an explicit ACK when the page is restored (yet), force
7529 // a round-trip to the renderer to effectively flush the queue.
7530 EXPECT_EQ(42, EvalJs(current_frame_host(), "window.foo"));
7531
7532 // Expect the back-forward restore with pageshow to be detected.
7533 content::FetchHistogramsFromChildProcesses();
7534 EXPECT_THAT(histogram_tester_.GetAllSamples(kHistogramName),
7535 ElementsAre(base::Bucket(0, 1), base::Bucket(1, 1)));
7536 }
7537
7538 // Navigate from A(B) to C and check IsCurrent status for RenderFrameHost A
7539 // and B before and after entering back-forward cache.
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,CheckIsCurrent)7540 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, CheckIsCurrent) {
7541 ASSERT_TRUE(embedded_test_server()->Start());
7542 GURL url_a(embedded_test_server()->GetURL(
7543 "a.com", "/cross_site_iframe_factory.html?a(b)"));
7544 GURL url_c(embedded_test_server()->GetURL("c.com", "/title1.html"));
7545
7546 // 1) Navigate to A(B).
7547 EXPECT_TRUE(NavigateToURL(shell(), url_a));
7548 RenderFrameHostImpl* rfh_a = current_frame_host();
7549 RenderFrameHostImpl* rfh_b = rfh_a->child_at(0)->current_frame_host();
7550
7551 EXPECT_TRUE(rfh_a->IsCurrent());
7552 EXPECT_TRUE(rfh_b->IsCurrent());
7553
7554 // 2) Navigate to C.
7555 EXPECT_TRUE(NavigateToURL(shell(), url_c));
7556 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
7557 EXPECT_TRUE(rfh_b->IsInBackForwardCache());
7558
7559 EXPECT_FALSE(rfh_a->IsCurrent());
7560 EXPECT_FALSE(rfh_b->IsCurrent());
7561 }
7562
7563 // Test that LifecycleState is updated correctly when page enters and restores
7564 // back from BackForwardCache.
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,CheckLifecycleStateTransition)7565 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
7566 CheckLifecycleStateTransition) {
7567 ASSERT_TRUE(embedded_test_server()->Start());
7568 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
7569 GURL url_b(embedded_test_server()->GetURL("b.com", "/title2.html"));
7570
7571 // 1) Navigate to A and check the LifecycleState of A.
7572 EXPECT_TRUE(NavigateToURL(shell(), url_a));
7573 RenderFrameHostImpl* rfh_a = current_frame_host();
7574 EXPECT_EQ(RenderFrameHostImpl::LifecycleState::kActive,
7575 rfh_a->lifecycle_state());
7576
7577 // 2) Navigate to B, now A enters BackForwardCache. Check the LifecycleState
7578 // of both RenderFrameHost A and B.
7579 EXPECT_TRUE(NavigateToURL(shell(), url_b));
7580 RenderFrameHostImpl* rfh_b = current_frame_host();
7581 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
7582 EXPECT_EQ(RenderFrameHostImpl::LifecycleState::kInBackForwardCache,
7583 rfh_a->lifecycle_state());
7584 EXPECT_EQ(RenderFrameHostImpl::LifecycleState::kActive,
7585 rfh_b->lifecycle_state());
7586
7587 // 3) Go back to A and check again the LifecycleState of both RenderFrameHost
7588 // A and B.
7589 web_contents()->GetController().GoBack();
7590 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
7591 EXPECT_EQ(RenderFrameHostImpl::LifecycleState::kActive,
7592 rfh_a->lifecycle_state());
7593 EXPECT_TRUE(rfh_b->IsInBackForwardCache());
7594 EXPECT_EQ(RenderFrameHostImpl::LifecycleState::kInBackForwardCache,
7595 rfh_b->lifecycle_state());
7596 }
7597
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,DoesNotCacheIfSpeechRecognitionIsStarted)7598 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
7599 DoesNotCacheIfSpeechRecognitionIsStarted) {
7600 ASSERT_TRUE(embedded_test_server()->Start());
7601 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
7602 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
7603
7604 // 1) Navigate to url_a.
7605 EXPECT_TRUE(NavigateToURL(shell(), url_a));
7606 RenderFrameHostImpl* rfh_a = current_frame_host();
7607 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
7608
7609 // 2) Start SpeechRecognition.
7610 EXPECT_TRUE(ExecJs(rfh_a, R"(
7611 new Promise(async resolve => {
7612 var r = new webkitSpeechRecognition();
7613 r.start();
7614 resolve();
7615 });
7616 )"));
7617
7618 // 3) Navigate away.
7619 EXPECT_TRUE(NavigateToURL(shell(), url_b));
7620
7621 // 4) The page uses SpeechRecognition so it should be deleted.
7622 delete_observer_rfh_a.WaitUntilDeleted();
7623
7624 // 5) Go back to the page with SpeechRecognition.
7625 web_contents()->GetController().GoBack();
7626 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
7627 ExpectNotRestored(
7628 {BackForwardCacheMetrics::NotRestoredReason::kBlocklistedFeatures},
7629 FROM_HERE);
7630 ExpectBlocklistedFeature(
7631 blink::scheduler::WebSchedulerTrackedFeature::kSpeechRecognizer,
7632 FROM_HERE);
7633 }
7634
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,CanCacheIfSpeechRecognitionIsNotStarted)7635 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
7636 CanCacheIfSpeechRecognitionIsNotStarted) {
7637 ASSERT_TRUE(embedded_test_server()->Start());
7638 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
7639 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
7640
7641 // 1) Navigate to url_a.
7642 EXPECT_TRUE(NavigateToURL(shell(), url_a));
7643 RenderFrameHostImpl* rfh_a = current_frame_host();
7644 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
7645
7646 // 2) Initialise SpeechRecognition but don't start it yet.
7647 EXPECT_TRUE(ExecJs(rfh_a, R"(
7648 new Promise(async resolve => {
7649 var r = new webkitSpeechRecognition();
7650 resolve();
7651 });
7652 )"));
7653
7654 // 3) Navigate away.
7655 EXPECT_TRUE(NavigateToURL(shell(), url_b));
7656
7657 // 4) The page didn't start using SpeechRecognition so it shouldn't be deleted
7658 // and enter BackForwardCache.
7659 EXPECT_FALSE(delete_observer_rfh_a.deleted());
7660 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
7661
7662 // 5) Go back to the page with SpeechRecognition.
7663 web_contents()->GetController().GoBack();
7664 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
7665 EXPECT_EQ(rfh_a, current_frame_host());
7666
7667 ExpectOutcome(BackForwardCacheMetrics::HistoryNavigationOutcome::kRestored,
7668 FROM_HERE);
7669 }
7670
7671 // This test is not important for Chrome OS if TTS is called in content. For
7672 // more details refer (content/browser/speech/tts_platform_impl.cc).
7673 #if defined(OS_CHROMEOS)
7674 #define MAYBE_DoesNotCacheIfUsingSpeechSynthesis \
7675 DISABLED_DoesNotCacheIfUsingSpeechSynthesis
7676 #else
7677 #define MAYBE_DoesNotCacheIfUsingSpeechSynthesis \
7678 DoesNotCacheIfUsingSpeechSynthesis
7679 #endif // defined(OS_CHROMEOS)
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,MAYBE_DoesNotCacheIfUsingSpeechSynthesis)7680 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
7681 MAYBE_DoesNotCacheIfUsingSpeechSynthesis) {
7682 ASSERT_TRUE(embedded_test_server()->Start());
7683 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
7684 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
7685
7686 // 1) Navigate to a page and start using SpeechSynthesis.
7687 EXPECT_TRUE(NavigateToURL(shell(), url_a));
7688 RenderFrameHostImpl* rfh_a = current_frame_host();
7689 RenderFrameDeletedObserver rhf_a_deleted(rfh_a);
7690
7691 EXPECT_TRUE(ExecJs(rfh_a, R"(
7692 new Promise(async resolve => {
7693 var u = new SpeechSynthesisUtterance(" ");
7694 speechSynthesis.speak(u);
7695 resolve();
7696 });
7697 )"));
7698
7699 // 2) Navigate away.
7700 EXPECT_TRUE(NavigateToURL(shell(), url_b));
7701
7702 // The page uses SpeechSynthesis so it should be deleted.
7703 rhf_a_deleted.WaitUntilDeleted();
7704
7705 // 3) Go back to the page with SpeechSynthesis.
7706 web_contents()->GetController().GoBack();
7707 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
7708 ExpectNotRestored(
7709 {BackForwardCacheMetrics::NotRestoredReason::kBlocklistedFeatures},
7710 FROM_HERE);
7711 ExpectBlocklistedFeature(
7712 blink::scheduler::WebSchedulerTrackedFeature::kSpeechSynthesis,
7713 FROM_HERE);
7714 }
7715
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,DoesNotCacheIfRunFileChooserIsInvoked)7716 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
7717 DoesNotCacheIfRunFileChooserIsInvoked) {
7718 ASSERT_TRUE(embedded_test_server()->Start());
7719 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
7720 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
7721
7722 // 1) Navigate to url_a and open file chooser.
7723 EXPECT_TRUE(NavigateToURL(shell(), url_a));
7724 RenderFrameHostImpl* rfh_a = current_frame_host();
7725 RenderFrameDeletedObserver deleted_rfh_a(rfh_a);
7726 content::BackForwardCacheDisabledTester tester;
7727
7728 // 2) Bind FileChooser to RenderFrameHost.
7729 mojo::Remote<blink::mojom::FileChooser> chooser =
7730 FileChooserImpl::CreateBoundForTesting(rfh_a);
7731
7732 auto quit_run_loop = [](base::OnceClosure callback,
7733 blink::mojom::FileChooserResultPtr result) {
7734 std::move(callback).Run();
7735 };
7736
7737 // 3) Run OpenFileChooser and wait till its run.
7738 base::RunLoop run_loop;
7739 chooser->OpenFileChooser(
7740 blink::mojom::FileChooserParams::New(),
7741 base::BindOnce(quit_run_loop, run_loop.QuitClosure()));
7742 run_loop.Run();
7743
7744 // 4) rfh_a should be disabled for BackForwardCache after opening file
7745 // chooser.
7746 EXPECT_TRUE(rfh_a->IsBackForwardCacheDisabled());
7747 EXPECT_TRUE(tester.IsDisabledForFrameWithReason(
7748 rfh_a->GetProcess()->GetID(), rfh_a->GetRoutingID(), "FileChooser"));
7749
7750 // 5) Navigate to B having the file chooser open.
7751 EXPECT_TRUE(NavigateToURL(shell(), url_b));
7752
7753 // The page uses FileChooser so it should be deleted.
7754 deleted_rfh_a.WaitUntilDeleted();
7755
7756 // 6) Go back to the page with FileChooser.
7757 web_contents()->GetController().GoBack();
7758 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
7759 ExpectOutcome(BackForwardCacheMetrics::HistoryNavigationOutcome::kNotRestored,
7760 FROM_HERE);
7761 }
7762
7763 // RenderFrameHostImpl::coep_reporter() must be preserved when doing a back
7764 // navigation using the BackForwardCache.
7765 // Regression test for https://crbug.com/1102285.
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,CoepReporter)7766 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, CoepReporter) {
7767 ASSERT_TRUE(CreateHttpsServer()->Start());
7768 GURL url_a(https_server()->GetURL("a.com",
7769 "/set-header?"
7770 "Cross-Origin-Embedder-Policy-Report-Only: "
7771 "same-origin; report-to%3d\"a\""));
7772 GURL url_b(https_server()->GetURL("b.com", "/title1.html"));
7773
7774 // Navigate to a document that set RenderFrameHostImpl::coep_reporter().
7775 EXPECT_TRUE(NavigateToURL(shell(), url_a));
7776 RenderFrameHostImpl* rfh_a = current_frame_host();
7777 EXPECT_TRUE(rfh_a->coep_reporter());
7778
7779 // Navigate away and back using the BackForwardCache. The
7780 // RenderFrameHostImpl::coep_reporter() must still be there.
7781 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
7782 EXPECT_TRUE(NavigateToURL(shell(), url_b));
7783 web_contents()->GetController().GoBack();
7784 EXPECT_TRUE(WaitForLoadStop(web_contents()));
7785 EXPECT_FALSE(delete_observer_rfh_a.deleted());
7786 EXPECT_EQ(rfh_a, current_frame_host());
7787
7788 EXPECT_TRUE(rfh_a->coep_reporter());
7789 }
7790
7791 // RenderFrameHostImpl::coop_reporter() must be preserved when doing a back
7792 // navigation using the BackForwardCache.
7793 // Regression test for https://crbug.com/1102285.
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,CoopReporter)7794 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, CoopReporter) {
7795 ASSERT_TRUE(CreateHttpsServer()->Start());
7796 GURL url_a(https_server()->GetURL("a.com",
7797 "/set-header?"
7798 "Cross-Origin-Opener-Policy-Report-Only: "
7799 "same-origin; report-to%3d\"a\""));
7800 GURL url_b(https_server()->GetURL("b.com", "/title1.html"));
7801
7802 // Navigate to a document that set RenderFrameHostImpl::coop_reporter().
7803 EXPECT_TRUE(NavigateToURL(shell(), url_a));
7804 RenderFrameHostImpl* rfh_a = current_frame_host();
7805 EXPECT_TRUE(rfh_a->coop_reporter());
7806
7807 // Navigate away and back using the BackForwardCache. The
7808 // RenderFrameHostImpl::coop_reporter() must still be there.
7809 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
7810 EXPECT_TRUE(NavigateToURL(shell(), url_b));
7811 web_contents()->GetController().GoBack();
7812 EXPECT_TRUE(WaitForLoadStop(web_contents()));
7813 EXPECT_FALSE(delete_observer_rfh_a.deleted());
7814 EXPECT_EQ(rfh_a, current_frame_host());
7815
7816 EXPECT_TRUE(rfh_a->coop_reporter());
7817 }
7818
7819 namespace {
7820
7821 class EchoFakeWithFilter final : public mojom::Echo {
7822 public:
EchoFakeWithFilter(mojo::PendingReceiver<mojom::Echo> receiver,std::unique_ptr<mojo::MessageFilter> filter)7823 explicit EchoFakeWithFilter(mojo::PendingReceiver<mojom::Echo> receiver,
7824 std::unique_ptr<mojo::MessageFilter> filter)
7825 : receiver_(this, std::move(receiver)) {
7826 receiver_.SetFilter(std::move(filter));
7827 }
7828 ~EchoFakeWithFilter() override = default;
7829
7830 // mojom::Echo implementation
EchoString(const std::string & input,EchoStringCallback callback)7831 void EchoString(const std::string& input,
7832 EchoStringCallback callback) override {
7833 std::move(callback).Run(input);
7834 }
7835
7836 private:
7837 mojo::Receiver<mojom::Echo> receiver_;
7838 };
7839
7840 } // namespace
7841
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,MessageReceivedOnAssociatedInterfaceWhileCached)7842 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
7843 MessageReceivedOnAssociatedInterfaceWhileCached) {
7844 DoNotFailForUnexpectedMessagesWhileCached();
7845 ASSERT_TRUE(embedded_test_server()->Start());
7846 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
7847 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
7848
7849 // 1) Navigate to A.
7850 EXPECT_TRUE(NavigateToURL(shell(), url_a));
7851 RenderFrameHostImpl* rfh_a = current_frame_host();
7852 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
7853 PageLifecycleStateManagerTestDelegate delegate(
7854 rfh_a->render_view_host()->GetPageLifecycleStateManager());
7855
7856 // 2) Navigate to B.
7857 EXPECT_TRUE(NavigateToURL(shell(), url_b));
7858 delegate.WaitForInBackForwardCacheAck();
7859 ASSERT_FALSE(delete_observer_rfh_a.deleted());
7860 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
7861
7862 mojo::Remote<mojom::Echo> remote;
7863 EchoFakeWithFilter echo(
7864 remote.BindNewPipeAndPassReceiver(),
7865 rfh_a->CreateMessageFilterForAssociatedReceiver(mojom::Echo::Name_));
7866
7867 base::RunLoop loop;
7868 remote->EchoString(
7869 "", base::BindLambdaForTesting([&](const std::string&) { loop.Quit(); }));
7870 loop.Run();
7871
7872 ExpectBucketCount(
7873 "BackForwardCache.UnexpectedRendererToBrowserMessage.InterfaceName",
7874 base::HistogramBase::Sample(
7875 static_cast<int32_t>(base::HashMetricName(mojom::Echo::Name_))),
7876 1);
7877 }
7878
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,MessageReceivedOnAssociatedInterfaceWhileCachedForProcessWithNonCachedPages)7879 IN_PROC_BROWSER_TEST_F(
7880 BackForwardCacheBrowserTest,
7881 MessageReceivedOnAssociatedInterfaceWhileCachedForProcessWithNonCachedPages) {
7882 ASSERT_TRUE(embedded_test_server()->Start());
7883 GURL url_a(embedded_test_server()->GetURL("/title1.html"));
7884 GURL url_b(embedded_test_server()->GetURL("/title2.html"));
7885
7886 // 1) Navigate to A.
7887 EXPECT_TRUE(NavigateToURL(shell(), url_a));
7888 RenderFrameHostImpl* rfh_a = current_frame_host();
7889 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
7890 PageLifecycleStateManagerTestDelegate delegate(
7891 rfh_a->render_view_host()->GetPageLifecycleStateManager());
7892
7893 // 2) Navigate to B.
7894 EXPECT_TRUE(NavigateToURL(shell(), url_b));
7895 delegate.WaitForInBackForwardCacheAck();
7896 RenderFrameHostImpl* rfh_b = current_frame_host();
7897 ASSERT_FALSE(delete_observer_rfh_a.deleted());
7898 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
7899 // Make sure both pages are on the same process (they are same site so they
7900 // should).
7901 ASSERT_EQ(rfh_a->GetProcess(), rfh_b->GetProcess());
7902
7903 mojo::Remote<mojom::Echo> remote;
7904 EchoFakeWithFilter echo(
7905 remote.BindNewPipeAndPassReceiver(),
7906 rfh_a->CreateMessageFilterForAssociatedReceiver(mojom::Echo::Name_));
7907
7908 remote->EchoString("", base::NullCallback());
7909 // Give the killing a chance to run. (We do not expect a kill but need to
7910 // "wait" for it to not happen)
7911 base::RunLoop().RunUntilIdle();
7912
7913 // 3) Go back to A.
7914 web_contents()->GetController().GoBack();
7915 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
7916
7917 ExpectOutcome(BackForwardCacheMetrics::HistoryNavigationOutcome::kRestored,
7918 FROM_HERE);
7919 }
7920
IN_PROC_BROWSER_TEST_F(HighCacheSizeBackForwardCacheBrowserTest,MessageReceivedOnAssociatedInterfaceForProcessWithMultipleCachedPages)7921 IN_PROC_BROWSER_TEST_F(
7922 HighCacheSizeBackForwardCacheBrowserTest,
7923 MessageReceivedOnAssociatedInterfaceForProcessWithMultipleCachedPages) {
7924 DoNotFailForUnexpectedMessagesWhileCached();
7925 ASSERT_TRUE(embedded_test_server()->Start());
7926 GURL url_a_1(embedded_test_server()->GetURL("a.com", "/title1.html"));
7927 GURL url_a_2(embedded_test_server()->GetURL("a.com", "/title2.html"));
7928 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
7929
7930 // Get url_a_1 and url_a_2 into the cache.
7931 EXPECT_TRUE(NavigateToURL(shell(), url_a_1));
7932 RenderFrameHostImpl* rfh_a_1 = current_frame_host();
7933 RenderFrameDeletedObserver delete_observer_rfh_a_1(rfh_a_1);
7934
7935 EXPECT_TRUE(NavigateToURL(shell(), url_a_2));
7936 RenderFrameHostImpl* rfh_a_2 = current_frame_host();
7937 RenderFrameDeletedObserver delete_observer_rfh_a_2(rfh_a_2);
7938
7939 EXPECT_TRUE(NavigateToURL(shell(), url_b));
7940 RenderFrameHostImpl* rfh_b = current_frame_host();
7941 RenderFrameDeletedObserver delete_observer_rfh_b(rfh_b);
7942
7943 ASSERT_FALSE(delete_observer_rfh_a_1.deleted());
7944 ASSERT_FALSE(delete_observer_rfh_a_2.deleted());
7945 EXPECT_TRUE(rfh_a_1->IsInBackForwardCache());
7946 EXPECT_TRUE(rfh_a_2->IsInBackForwardCache());
7947 ASSERT_EQ(rfh_a_1->GetProcess(), rfh_a_2->GetProcess());
7948
7949 mojo::Remote<mojom::Echo> remote;
7950 EchoFakeWithFilter echo(
7951 remote.BindNewPipeAndPassReceiver(),
7952 rfh_a_1->CreateMessageFilterForAssociatedReceiver(mojom::Echo::Name_));
7953
7954 base::RunLoop loop;
7955 remote->EchoString(
7956 "", base::BindLambdaForTesting([&](const std::string&) { loop.Quit(); }));
7957 loop.Run();
7958
7959 ExpectBucketCount(
7960 "BackForwardCache.UnexpectedRendererToBrowserMessage.InterfaceName",
7961 base::HistogramBase::Sample(
7962 static_cast<int32_t>(base::HashMetricName(mojom::Echo::Name_))),
7963 1);
7964
7965 EXPECT_FALSE(delete_observer_rfh_b.deleted());
7966 }
7967
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,MessageReceivedOnAssociatedInterfaceWhileFreezing)7968 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
7969 MessageReceivedOnAssociatedInterfaceWhileFreezing) {
7970 ASSERT_TRUE(embedded_test_server()->Start());
7971 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
7972 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
7973 url::Origin origin_a = url::Origin::Create(url_a);
7974 url::Origin origin_b = url::Origin::Create(url_b);
7975
7976 // 1) Navigate to A.
7977 EXPECT_TRUE(NavigateToURL(shell(), url_a));
7978 RenderFrameHostImpl* rfh_a = current_frame_host();
7979 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
7980 PageLifecycleStateManagerTestDelegate delegate(
7981 rfh_a->render_view_host()->GetPageLifecycleStateManager());
7982
7983 mojo::Remote<mojom::Echo> remote;
7984 EchoFakeWithFilter echo(
7985 remote.BindNewPipeAndPassReceiver(),
7986 rfh_a->CreateMessageFilterForAssociatedReceiver(mojom::Echo::Name_));
7987
7988 delegate.OnStoreInBackForwardCacheSent(base::BindLambdaForTesting(
7989 [&]() { remote->EchoString("", base::NullCallback()); }));
7990
7991 delegate.OnRestoreFromBackForwardCacheSent(base::BindLambdaForTesting(
7992 [&]() { remote->EchoString("", base::NullCallback()); }));
7993
7994 // 2) Navigate to B.
7995 EXPECT_TRUE(NavigateToURL(shell(), url_b));
7996
7997 // 3) Go back to A.
7998 web_contents()->GetController().GoBack();
7999 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
8000
8001 ExpectOutcome(BackForwardCacheMetrics::HistoryNavigationOutcome::kRestored,
8002 FROM_HERE);
8003 }
8004
8005 // Tests that if a page is already ineligible to be saved in the back-forward
8006 // cache at navigation time, we shouldn't try to proactively swap
8007 // BrowsingInstances.
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,ShouldNotSwapBrowsingInstanceWhenPageWillNotBeCached)8008 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
8009 ShouldNotSwapBrowsingInstanceWhenPageWillNotBeCached) {
8010 ASSERT_TRUE(embedded_test_server()->Start());
8011 GURL url_1(embedded_test_server()->GetURL("/title1.html"));
8012 GURL url_2(embedded_test_server()->GetURL("/title2.html"));
8013 GURL url_3(embedded_test_server()->GetURL("/title3.html"));
8014
8015 // 1) Navigate to |url_1| .
8016 EXPECT_TRUE(NavigateToURL(shell(), url_1));
8017 RenderFrameHostImpl* rfh_1 = current_frame_host();
8018 scoped_refptr<SiteInstanceImpl> site_instance_1 =
8019 static_cast<SiteInstanceImpl*>(rfh_1->GetSiteInstance());
8020
8021 // 2) Navigate to |url_2|.
8022 EXPECT_TRUE(NavigateToURL(shell(), url_2));
8023 RenderFrameHostImpl* rfh_2 = current_frame_host();
8024 RenderFrameDeletedObserver rfh_2_deleted_observer(rfh_2);
8025 scoped_refptr<SiteInstanceImpl> site_instance_2 =
8026 static_cast<SiteInstanceImpl*>(rfh_2->GetSiteInstance());
8027
8028 // |rfh_1| should get into the back-forward cache.
8029 EXPECT_TRUE(rfh_1->IsInBackForwardCache());
8030 // Check that title1.html and title2.html are in different BrowsingInstances.
8031 EXPECT_FALSE(site_instance_1->IsRelatedSiteInstance(site_instance_2.get()));
8032
8033 // Disable the BackForwardCache for |rfh_2|.
8034 BackForwardCache::DisableForRenderFrameHost(rfh_2->GetGlobalFrameRoutingId(),
8035 kDisabledReasonForTest);
8036
8037 // 3) Navigate to |url_3|.
8038 EXPECT_TRUE(NavigateToURL(shell(), url_3));
8039 RenderFrameHostImpl* rfh_3 = current_frame_host();
8040 scoped_refptr<SiteInstanceImpl> site_instance_3 =
8041 static_cast<SiteInstanceImpl*>(rfh_3->GetSiteInstance());
8042
8043 // Check that |url_2| and |url_3| are reusing the same SiteInstance (and
8044 // BrowsingInstance).
8045 EXPECT_EQ(site_instance_2, site_instance_3);
8046 if (rfh_2 != rfh_3) {
8047 // If we aren't reusing the RenderFrameHost then |rfh_2| will eventually
8048 // get deleted because it's not saved in the back-forward cache.
8049 rfh_2_deleted_observer.WaitUntilDeleted();
8050 }
8051 }
8052
8053 // Tests that pagehide and visibilitychange handlers of the old RFH are run for
8054 // bfcached pages.
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,PagehideAndVisibilitychangeRuns)8055 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
8056 PagehideAndVisibilitychangeRuns) {
8057 ASSERT_TRUE(embedded_test_server()->Start());
8058 GURL url_1(embedded_test_server()->GetURL("a.com", "/title1.html"));
8059 GURL url_2(embedded_test_server()->GetURL("b.com", "/title2.html"));
8060 GURL url_3(embedded_test_server()->GetURL("a.com", "/title2.html"));
8061 WebContentsImpl* web_contents =
8062 static_cast<WebContentsImpl*>(shell()->web_contents());
8063
8064 // 1) Navigate to |url_1|.
8065 EXPECT_TRUE(NavigateToURL(shell(), url_1));
8066 RenderFrameHostImpl* main_frame_1 = web_contents->GetMainFrame();
8067
8068 // Create a pagehide handler that sets item "pagehide_storage" and a
8069 // visibilitychange handler that sets item "visibilitychange_storage" in
8070 // localStorage.
8071 EXPECT_TRUE(ExecJs(main_frame_1,
8072 R"(
8073 localStorage.setItem('pagehide_storage', 'not_dispatched');
8074 var dispatched_pagehide = false;
8075 window.onpagehide = function(e) {
8076 if (dispatched_pagehide) {
8077 // We shouldn't dispatch pagehide more than once.
8078 localStorage.setItem('pagehide_storage', 'dispatched_more_than_once');
8079 } else if (!e.persisted) {
8080 localStorage.setItem('pagehide_storage', 'wrong_persisted');
8081 } else {
8082 localStorage.setItem('pagehide_storage', 'dispatched_once');
8083 }
8084 dispatched_pagehide = true;
8085 }
8086 localStorage.setItem('visibilitychange_storage', 'not_dispatched');
8087 var dispatched_visibilitychange = false;
8088 document.onvisibilitychange = function(e) {
8089 if (dispatched_visibilitychange) {
8090 // We shouldn't dispatch visibilitychange more than once.
8091 localStorage.setItem('visibilitychange_storage',
8092 'dispatched_more_than_once');
8093 } else if (document.visibilityState != 'hidden') {
8094 // We should dispatch the event when the visibilityState is 'hidden'.
8095 localStorage.setItem('visibilitychange_storage', 'not_hidden');
8096 } else {
8097 localStorage.setItem('visibilitychange_storage', 'dispatched_once');
8098 }
8099 dispatched_visibilitychange = true;
8100 }
8101 )"));
8102
8103 // 2) Navigate cross-site to |url_2|. We need to navigate cross-site to make
8104 // sure we won't run pagehide and visibilitychange during new page's commit,
8105 // which is tested in ProactivelySwapBrowsingInstancesSameSiteTest.
8106 EXPECT_TRUE(NavigateToURL(shell(), url_2));
8107
8108 // |main_frame_1| should be in the back-forward cache.
8109 EXPECT_TRUE(main_frame_1->IsInBackForwardCache());
8110
8111 // 3) Navigate to |url_3| which is same-origin with |url_1|, so we can check
8112 // the localStorage values.
8113 EXPECT_TRUE(NavigateToURL(shell(), url_3));
8114 RenderFrameHostImpl* main_frame_3 = web_contents->GetMainFrame();
8115
8116 // Check that the value for 'pagehide_storage' and 'visibilitychange_storage'
8117 // are set correctly.
8118 EXPECT_EQ("dispatched_once",
8119 EvalJs(main_frame_3, "localStorage.getItem('pagehide_storage')"));
8120 EXPECT_EQ(
8121 "dispatched_once",
8122 EvalJs(main_frame_3, "localStorage.getItem('visibilitychange_storage')"));
8123 }
8124
8125 // Tests that pagehide handlers of the old RFH are run for bfcached pages even
8126 // if the page is already hidden (and visibilitychange won't run).
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,PagehideRunsWhenPageIsHidden)8127 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
8128 PagehideRunsWhenPageIsHidden) {
8129 ASSERT_TRUE(embedded_test_server()->Start());
8130 GURL url_1(embedded_test_server()->GetURL("a.com", "/title1.html"));
8131 GURL url_2(embedded_test_server()->GetURL("b.com", "/title2.html"));
8132 GURL url_3(embedded_test_server()->GetURL("a.com", "/title2.html"));
8133 WebContentsImpl* web_contents =
8134 static_cast<WebContentsImpl*>(shell()->web_contents());
8135
8136 // 1) Navigate to |url_1| and hide the tab.
8137 EXPECT_TRUE(NavigateToURL(shell(), url_1));
8138 RenderFrameHostImpl* main_frame_1 = web_contents->GetMainFrame();
8139 // We need to set it to Visibility::VISIBLE first in case this is the first
8140 // time the visibility is updated.
8141 web_contents->UpdateWebContentsVisibility(Visibility::VISIBLE);
8142 web_contents->UpdateWebContentsVisibility(Visibility::HIDDEN);
8143 EXPECT_EQ(Visibility::HIDDEN, web_contents->GetVisibility());
8144
8145 // Create a pagehide handler that sets item "pagehide_storage" and a
8146 // visibilitychange handler that sets item "visibilitychange_storage" in
8147 // localStorage.
8148 EXPECT_TRUE(ExecJs(main_frame_1,
8149 R"(
8150 localStorage.setItem('pagehide_storage', 'not_dispatched');
8151 var dispatched_pagehide = false;
8152 window.onpagehide = function(e) {
8153 if (dispatched_pagehide) {
8154 // We shouldn't dispatch pagehide more than once.
8155 localStorage.setItem('pagehide_storage', 'dispatched_more_than_once');
8156 } else if (!e.persisted) {
8157 localStorage.setItem('pagehide_storage', 'wrong_persisted');
8158 } else {
8159 localStorage.setItem('pagehide_storage', 'dispatched_once');
8160 }
8161 dispatched_pagehide = true;
8162 }
8163 localStorage.setItem('visibilitychange_storage', 'not_dispatched');
8164 document.onvisibilitychange = function(e) {
8165 localStorage.setItem('visibilitychange_storage',
8166 'should_not_be_dispatched');
8167 }
8168 )"));
8169 // |visibilitychange_storage| should be set to its initial correct value.
8170 EXPECT_EQ(
8171 "not_dispatched",
8172 EvalJs(main_frame_1, "localStorage.getItem('visibilitychange_storage')"));
8173
8174 // 2) Navigate cross-site to |url_2|. We need to navigate cross-site to make
8175 // sure we won't run pagehide and visibilitychange during new page's commit,
8176 // which is tested in ProactivelySwapBrowsingInstancesSameSiteTest.
8177 EXPECT_TRUE(NavigateToURL(shell(), url_2));
8178
8179 // |main_frame_1| should be in the back-forward cache.
8180 EXPECT_TRUE(main_frame_1->IsInBackForwardCache());
8181
8182 // 3) Navigate to |url_3| which is same-origin with |url_1|, so we can check
8183 // the localStorage values.
8184 EXPECT_TRUE(NavigateToURL(shell(), url_3));
8185 RenderFrameHostImpl* main_frame_3 = web_contents->GetMainFrame();
8186
8187 // Check that the value for 'pagehide_storage' and 'visibilitychange_storage'
8188 // are set correctly.
8189 EXPECT_EQ("dispatched_once",
8190 EvalJs(main_frame_3, "localStorage.getItem('pagehide_storage')"));
8191 EXPECT_EQ(
8192 "not_dispatched",
8193 EvalJs(main_frame_3, "localStorage.getItem('visibilitychange_storage')"));
8194 }
8195
8196 // Test histogram values related to same-site navigations when a page became
8197 // ineligible for back-forward cache in between navigation start and commit.
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,ProactiveSameSiteBISwapHistogramsEligibilityChanged)8198 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
8199 ProactiveSameSiteBISwapHistogramsEligibilityChanged) {
8200 ASSERT_TRUE(embedded_test_server()->Start());
8201 GURL url_a1(embedded_test_server()->GetURL("a.com", "/title1.html"));
8202 GURL url_a2(embedded_test_server()->GetURL("a.com", "/title2.html"));
8203
8204 // 1) Navigate to A1.
8205 EXPECT_TRUE(NavigateToURL(shell(), url_a1));
8206 RenderFrameHostImpl* rfh_a1 = current_frame_host();
8207 RenderFrameDeletedObserver rfh_a1_deleted_observer(rfh_a1);
8208 // We didn't do a proactive BrowsingInstance swap. The initial navigation is a
8209 // same-site navigation iff site isolation is on, so we will track it as
8210 // "same-site navigation but we did not swap BIs" in that case.
8211 int initial_same_site_false_bucket_count =
8212 AreAllSitesIsolatedForTesting() ? 1 : 0;
8213 ExpectUniqueSample(kSameSiteNavigationDidSwapHistogramName, false,
8214 initial_same_site_false_bucket_count);
8215
8216 // 2) Make A1 ineligible for bfcache just before committing the next
8217 // navigation.
8218 ReadyToCommitNavigationCallback disable_rfh_a1_callback(
8219 web_contents(),
8220 base::BindOnce(
8221 [](RenderFrameHostImpl* rfh_a1, NavigationHandle* navigation_handle) {
8222 BackForwardCache::DisableForRenderFrameHost(
8223 rfh_a1->GetGlobalFrameRoutingId(), kDisabledReasonForTest);
8224 },
8225 rfh_a1));
8226
8227 // 3) Navigate to A2.
8228 EXPECT_TRUE(NavigateToURL(shell(), url_a2));
8229 RenderFrameHostImpl* rfh_a2 = current_frame_host();
8230
8231 // We should swap RFHs because A1 was eligible when the navigation started,
8232 // but A1 should not end up in the back-forward cache because it became
8233 // ineligible just before committing.
8234 EXPECT_NE(rfh_a1, rfh_a2);
8235 // |rfh_a1| should eventually get deleted.
8236 rfh_a1_deleted_observer.WaitUntilDeleted();
8237
8238 // We did a same-site BrowsingInstance swap for the navigation, so we should
8239 // record metrics related to same-site BrowsingInstance swaps.
8240 ExpectBucketCount(kSameSiteNavigationDidSwapHistogramName, true, 1);
8241 ExpectBucketCount(kSameSiteNavigationDidSwapHistogramName, false,
8242 initial_same_site_false_bucket_count);
8243 // We don't have an unload handler on A1 so no unload handlers will run after
8244 // commit.
8245 ExpectUniqueSample(kUnloadRunsAfterCommitHistogramName, false, 1);
8246 // A1 was no longer eligible for back forward cache during commit, so we
8247 // should note it as such in the metrics.
8248 ExpectUniqueSample(kEligibilityDuringCommitHistogramName, false, 1);
8249 }
8250
8251 // Tests that we're getting the correct TextInputState and focus updates when a
8252 // page enters the back-forward cache and when it gets restored.
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,TextInputStateUpdated)8253 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, TextInputStateUpdated) {
8254 ASSERT_TRUE(embedded_test_server()->Start());
8255 GURL url_1(embedded_test_server()->GetURL("a.com", "/title1.html"));
8256 GURL url_2(embedded_test_server()->GetURL("b.com", "/title2.html"));
8257
8258 // 1) Navigate to |url_1| and add a text input with "foo" as the value.
8259 EXPECT_TRUE(NavigateToURL(shell(), url_1));
8260 RenderFrameHostImpl* rfh_1 = current_frame_host();
8261 EXPECT_TRUE(ExecJs(rfh_1,
8262 "document.title='bfcached';"
8263 "var input = document.createElement('input');"
8264 "input.setAttribute('type', 'text');"
8265 "input.setAttribute('value', 'foo');"
8266 "document.body.appendChild(input);"
8267 "var focusCount = 0;"
8268 "var blurCount = 0;"
8269 "input.onfocus = () => { focusCount++;};"
8270 "input.onblur = () => { blurCount++; };"));
8271
8272 {
8273 TextInputManagerTypeObserver type_observer(web_contents(),
8274 ui::TEXT_INPUT_TYPE_TEXT);
8275 TextInputManagerValueObserver value_observer(web_contents(), "foo");
8276 // 2) Press tab key to focus the <input>, and verify the type & value.
8277 SimulateKeyPress(web_contents(), ui::DomKey::TAB, ui::DomCode::TAB,
8278 ui::VKEY_TAB, false, false, false, false);
8279 type_observer.Wait();
8280 value_observer.Wait();
8281
8282 EXPECT_EQ(rfh_1, web_contents()->GetFocusedFrame());
8283 EXPECT_EQ(EvalJs(rfh_1, "focusCount").ExtractInt(), 1);
8284 EXPECT_EQ(EvalJs(rfh_1, "blurCount").ExtractInt(), 0);
8285 }
8286
8287 {
8288 TextInputManagerTester tester(web_contents());
8289 TextInputManagerValueObserver value_observer(web_contents(), "A");
8290 // 3) Press the "A" key to change the text input value. This should notify
8291 // the browser that the text input value has changed.
8292 SimulateKeyPress(web_contents(), ui::DomKey::FromCharacter('A'),
8293 ui::DomCode::US_A, ui::VKEY_A, false, false, false, false);
8294 value_observer.Wait();
8295
8296 EXPECT_EQ(rfh_1, web_contents()->GetFocusedFrame());
8297 EXPECT_EQ(EvalJs(rfh_1, "focusCount").ExtractInt(), 1);
8298 EXPECT_EQ(EvalJs(rfh_1, "blurCount").ExtractInt(), 0);
8299 }
8300
8301 {
8302 TextInputManagerTypeObserver type_observer(web_contents(),
8303 ui::TEXT_INPUT_TYPE_NONE);
8304 // 4) Navigating to |url_2| should reset type to TEXT_INPUT_TYPE_NONE.
8305 EXPECT_TRUE(NavigateToURL(shell(), url_2));
8306 type_observer.Wait();
8307 // |rfh_1| should get into the back-forward cache.
8308 EXPECT_TRUE(rfh_1->IsInBackForwardCache());
8309 EXPECT_EQ(current_frame_host(), web_contents()->GetFocusedFrame());
8310 EXPECT_NE(rfh_1, web_contents()->GetFocusedFrame());
8311 }
8312
8313 {
8314 // 5) Navigating back to |url_1|, we shouldn't restore the focus to the
8315 // text input, but |rfh_1| will be focused again as we will restore focus
8316 // to main frame after navigation.
8317 web_contents()->GetController().GoBack();
8318 EXPECT_TRUE(WaitForLoadStop(web_contents()));
8319
8320 EXPECT_EQ(rfh_1, web_contents()->GetFocusedFrame());
8321 EXPECT_EQ(EvalJs(rfh_1, "focusCount").ExtractInt(), 1);
8322 EXPECT_EQ(EvalJs(rfh_1, "blurCount").ExtractInt(), 1);
8323 }
8324
8325 {
8326 TextInputManagerTypeObserver type_observer(web_contents(),
8327 ui::TEXT_INPUT_TYPE_TEXT);
8328 TextInputManagerValueObserver value_observer(web_contents(), "A");
8329 // 6) Press tab key to focus the <input> again. Note that we need to press
8330 // the tab key twice here, because the last "tab focus" point was the
8331 // <input> element. The first tab key press would focus on the UI/url bar,
8332 // then the second tab key would go back to the <input>.
8333 SimulateKeyPress(web_contents(), ui::DomKey::TAB, ui::DomCode::TAB,
8334 ui::VKEY_TAB, false, false, false, false);
8335 SimulateKeyPress(web_contents(), ui::DomKey::TAB, ui::DomCode::TAB,
8336 ui::VKEY_TAB, false, false, false, false);
8337 type_observer.Wait();
8338 value_observer.Wait();
8339
8340 EXPECT_EQ(rfh_1, web_contents()->GetFocusedFrame());
8341 EXPECT_EQ(EvalJs(rfh_1, "focusCount").ExtractInt(), 2);
8342 EXPECT_EQ(EvalJs(rfh_1, "blurCount").ExtractInt(), 1);
8343 }
8344 }
8345
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,SubframeTextInputStateUpdated)8346 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
8347 SubframeTextInputStateUpdated) {
8348 ASSERT_TRUE(embedded_test_server()->Start());
8349 GURL url_1(embedded_test_server()->GetURL(
8350 "a.com", "/cross_site_iframe_factory.html?a(b(a))"));
8351 GURL url_2(embedded_test_server()->GetURL("b.com", "/title2.html"));
8352
8353 // 1) Navigate to |url_1| and add a text input with "foo" as the value in the
8354 // a.com subframe.
8355 EXPECT_TRUE(NavigateToURL(shell(), url_1));
8356 RenderFrameHostImpl* rfh_a = current_frame_host();
8357 RenderFrameHostImpl* rfh_b = rfh_a->child_at(0)->current_frame_host();
8358 RenderFrameHostImpl* rfh_subframe_a =
8359 rfh_b->child_at(0)->current_frame_host();
8360 EXPECT_TRUE(ExecJs(rfh_subframe_a,
8361 "var input = document.createElement('input');"
8362 "input.setAttribute('type', 'text');"
8363 "input.setAttribute('value', 'foo');"
8364 "document.body.appendChild(input);"
8365 "var focusCount = 0;"
8366 "var blurCount = 0;"
8367 "input.onfocus = () => { focusCount++;};"
8368 "input.onblur = () => { blurCount++; };"));
8369
8370 {
8371 TextInputManagerTypeObserver type_observer(web_contents(),
8372 ui::TEXT_INPUT_TYPE_TEXT);
8373 TextInputManagerValueObserver value_observer(web_contents(), "foo");
8374 // 2) Press tab key to focus the <input>, and verify the type & value.
8375 SimulateKeyPress(web_contents(), ui::DomKey::TAB, ui::DomCode::TAB,
8376 ui::VKEY_TAB, false, false, false, false);
8377 type_observer.Wait();
8378 value_observer.Wait();
8379
8380 EXPECT_EQ(rfh_subframe_a, web_contents()->GetFocusedFrame());
8381 EXPECT_EQ(EvalJs(rfh_subframe_a, "focusCount").ExtractInt(), 1);
8382 EXPECT_EQ(EvalJs(rfh_subframe_a, "blurCount").ExtractInt(), 0);
8383 }
8384
8385 {
8386 TextInputManagerTester tester(web_contents());
8387 TextInputManagerValueObserver value_observer(web_contents(), "A");
8388 // 3) Press the "A" key to change the text input value. This should notify
8389 // the browser that the text input value has changed.
8390 SimulateKeyPress(web_contents(), ui::DomKey::FromCharacter('A'),
8391 ui::DomCode::US_A, ui::VKEY_A, false, false, false, false);
8392 value_observer.Wait();
8393
8394 EXPECT_EQ(rfh_subframe_a, web_contents()->GetFocusedFrame());
8395 EXPECT_EQ(EvalJs(rfh_subframe_a, "focusCount").ExtractInt(), 1);
8396 EXPECT_EQ(EvalJs(rfh_subframe_a, "blurCount").ExtractInt(), 0);
8397 }
8398
8399 {
8400 TextInputManagerTypeObserver type_observer(web_contents(),
8401 ui::TEXT_INPUT_TYPE_NONE);
8402 // 4) Navigating to |url_2| should reset type to TEXT_INPUT_TYPE_NONE and
8403 // changed focus to the new page's main frame.
8404 EXPECT_TRUE(NavigateToURL(shell(), url_2));
8405 type_observer.Wait();
8406
8407 // |rfh_a| and its subframes should get into the back-forward cache.
8408 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
8409 EXPECT_TRUE(rfh_b->IsInBackForwardCache());
8410 EXPECT_TRUE(rfh_subframe_a->IsInBackForwardCache());
8411 EXPECT_EQ(current_frame_host(), web_contents()->GetFocusedFrame());
8412 }
8413
8414 {
8415 // 5) Navigating back to |url_1|, we shouldn't restore the focus to the
8416 // text input in the subframe (we will focus on the main frame |rfh_a|
8417 // instead).
8418 web_contents()->GetController().GoBack();
8419 EXPECT_TRUE(WaitForLoadStop(web_contents()));
8420
8421 EXPECT_EQ(rfh_a, web_contents()->GetFocusedFrame());
8422 EXPECT_EQ(EvalJs(rfh_subframe_a, "focusCount").ExtractInt(), 1);
8423 EXPECT_EQ(EvalJs(rfh_subframe_a, "blurCount").ExtractInt(), 1);
8424 }
8425
8426 {
8427 TextInputManagerTypeObserver type_observer(web_contents(),
8428 ui::TEXT_INPUT_TYPE_TEXT);
8429 TextInputManagerValueObserver value_observer(web_contents(), "A");
8430 // 6) Press tab key to focus the <input> again.
8431 SimulateKeyPress(web_contents(), ui::DomKey::TAB, ui::DomCode::TAB,
8432 ui::VKEY_TAB, false, false, false, false);
8433 type_observer.Wait();
8434 value_observer.Wait();
8435
8436 EXPECT_EQ(rfh_subframe_a, web_contents()->GetFocusedFrame());
8437 EXPECT_EQ(EvalJs(rfh_subframe_a, "focusCount").ExtractInt(), 2);
8438 EXPECT_EQ(EvalJs(rfh_subframe_a, "blurCount").ExtractInt(), 1);
8439 }
8440 }
8441
8442 // We should try to reuse process on same-site renderer-initiated navigations.
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,RendererInitiatedSameSiteNavigationReusesProcess)8443 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
8444 RendererInitiatedSameSiteNavigationReusesProcess) {
8445 ASSERT_TRUE(embedded_test_server()->Start());
8446 GURL url_1(embedded_test_server()->GetURL("/title1.html"));
8447 GURL url_2(embedded_test_server()->GetURL("/title2.html"));
8448
8449 // Navigate to title1.html.
8450 EXPECT_TRUE(NavigateToURL(shell(), url_1));
8451 scoped_refptr<SiteInstanceImpl> site_instance_1 =
8452 web_contents()->GetMainFrame()->GetSiteInstance();
8453 // Navigate to title2.html. The navigation is document/renderer initiated.
8454 EXPECT_TRUE(NavigateToURLFromRenderer(shell(), url_2));
8455 scoped_refptr<SiteInstanceImpl> site_instance_2 =
8456 web_contents()->GetMainFrame()->GetSiteInstance();
8457
8458 // Check that title1.html and title2.html are in different BrowsingInstances
8459 // but have the same renderer process.
8460 EXPECT_FALSE(site_instance_1->IsRelatedSiteInstance(site_instance_2.get()));
8461 EXPECT_EQ(site_instance_1->GetProcess(), site_instance_2->GetProcess());
8462 }
8463
8464 // We should try to reuse process on same-site browser-initiated navigations.
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,BrowserInitiatedSameSiteNavigationReusesProcess)8465 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
8466 BrowserInitiatedSameSiteNavigationReusesProcess) {
8467 ASSERT_TRUE(embedded_test_server()->Start());
8468 GURL url_1(embedded_test_server()->GetURL("/title1.html"));
8469 GURL url_2(embedded_test_server()->GetURL("/title2.html"));
8470
8471 // 1) Navigate to title1.html.
8472 EXPECT_TRUE(NavigateToURL(shell(), url_1));
8473 scoped_refptr<SiteInstanceImpl> site_instance_1 =
8474 web_contents()->GetMainFrame()->GetSiteInstance();
8475 // 2) Navigate to title2.html. The navigation is browser initiated.
8476 EXPECT_TRUE(NavigateToURL(shell(), url_2));
8477 scoped_refptr<SiteInstanceImpl> site_instance_2 =
8478 web_contents()->GetMainFrame()->GetSiteInstance();
8479
8480 // Check that title1.html and title2.html are in different BrowsingInstances
8481 // but have the same renderer process.
8482 EXPECT_FALSE(site_instance_1->IsRelatedSiteInstance(site_instance_2.get()));
8483 EXPECT_EQ(site_instance_1->GetProcess(), site_instance_2->GetProcess());
8484
8485 // 3) Do a back navigation to title1.html.
8486 web_contents()->GetController().GoBack();
8487 EXPECT_TRUE(WaitForLoadStop(web_contents()));
8488 EXPECT_EQ(web_contents()->GetLastCommittedURL(), url_1);
8489 scoped_refptr<SiteInstanceImpl> site_instance_1_history_nav =
8490 web_contents()->GetMainFrame()->GetSiteInstance();
8491
8492 // We will reuse the SiteInstance and renderer process of |site_instance_1|.
8493 EXPECT_EQ(site_instance_1_history_nav, site_instance_1);
8494 EXPECT_EQ(site_instance_1_history_nav->GetProcess(),
8495 site_instance_1->GetProcess());
8496 }
8497
8498 // We should not try to reuse process on cross-site navigations.
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,CrossSiteNavigationDoesNotReuseProcess)8499 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
8500 CrossSiteNavigationDoesNotReuseProcess) {
8501 ASSERT_TRUE(embedded_test_server()->Start());
8502 GURL a1_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
8503 GURL b_url(embedded_test_server()->GetURL("b.com", "/title1.html"));
8504 GURL a2_url(embedded_test_server()->GetURL("a.com", "/title2.html"));
8505
8506 // Navigate to A1.
8507 EXPECT_TRUE(NavigateToURL(shell(), a1_url));
8508 scoped_refptr<SiteInstanceImpl> a1_site_instance =
8509 web_contents()->GetMainFrame()->GetSiteInstance();
8510 // Navigate to B. The navigation is browser initiated.
8511 EXPECT_TRUE(NavigateToURL(shell(), b_url));
8512 scoped_refptr<SiteInstanceImpl> b_site_instance =
8513 web_contents()->GetMainFrame()->GetSiteInstance();
8514
8515 // Check that A1 and B are in different BrowsingInstances and renderer
8516 // processes.
8517 EXPECT_FALSE(a1_site_instance->IsRelatedSiteInstance(b_site_instance.get()));
8518 EXPECT_NE(a1_site_instance->GetProcess(), b_site_instance->GetProcess());
8519
8520 // Navigate to A2. The navigation is renderer-initiated.
8521 EXPECT_TRUE(NavigateToURLFromRenderer(shell(), a2_url));
8522 scoped_refptr<SiteInstanceImpl> a2_site_instance =
8523 web_contents()->GetMainFrame()->GetSiteInstance();
8524
8525 // Check that B and A2 are in different BrowsingInstances and renderer
8526 // processes.
8527 EXPECT_FALSE(b_site_instance->IsRelatedSiteInstance(a2_site_instance.get()));
8528 EXPECT_NE(b_site_instance->GetProcess(), a2_site_instance->GetProcess());
8529 }
8530
8531 // Tests that the history value saved in the renderer is updated correctly when
8532 // a page gets restored from the back-forward cache through browser-initiated
8533 // navigation.
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,RendererHistory_BrowserInitiated)8534 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
8535 RendererHistory_BrowserInitiated) {
8536 ASSERT_TRUE(embedded_test_server()->Start());
8537 GURL url1(embedded_test_server()->GetURL(
8538 "a.com", "/cross_site_iframe_factory.html?a(b)"));
8539 GURL url2(embedded_test_server()->GetURL("a.com", "/title1.html"));
8540
8541 // 1) Go to |url1|, then |url2|. Both pages should have script to save the
8542 // history.length value when getting restored from the back-forward cache.
8543 EXPECT_TRUE(NavigateToURL(shell(), url1));
8544 FrameTreeNode* root = web_contents()->GetFrameTree()->root();
8545 FrameTreeNode* subframe = root->child_at(0);
8546
8547 std::string restore_time_length_saver_script =
8548 "var resumeLength = -1;"
8549 "var pageshowLength = -1;"
8550 "document.onresume = () => {"
8551 " resumeLength = history.length;"
8552 "};"
8553 "window.onpageshow = () => {"
8554 " pageshowLength = history.length;"
8555 "};";
8556 EXPECT_TRUE(ExecJs(root, restore_time_length_saver_script));
8557 EXPECT_TRUE(ExecJs(subframe, restore_time_length_saver_script));
8558 // We should have one history entry.
8559 EXPECT_EQ(EvalJs(root, "history.length").ExtractInt(), 1);
8560 EXPECT_EQ(EvalJs(subframe, "history.length").ExtractInt(), 1);
8561
8562 EXPECT_TRUE(NavigateToURL(shell(), url2));
8563 EXPECT_TRUE(ExecJs(root, restore_time_length_saver_script));
8564 // We should have two history entries.
8565 EXPECT_EQ(EvalJs(root, "history.length").ExtractInt(), 2);
8566
8567 // 2) Go back to |url1|, browser-initiated.
8568 web_contents()->GetController().GoBack();
8569 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
8570 EXPECT_EQ(web_contents()->GetLastCommittedURL(), url1);
8571
8572 // We should still have two history entries, and recorded the correct length
8573 // when the 'resume' and 'pageshow' events were dispatched.
8574 EXPECT_EQ(EvalJs(root, "history.length").ExtractInt(), 2);
8575 EXPECT_EQ(EvalJs(root, "resumeLength").ExtractInt(), 2);
8576 EXPECT_EQ(EvalJs(root, "pageshowLength").ExtractInt(), 2);
8577 EXPECT_EQ(EvalJs(subframe, "history.length").ExtractInt(), 2);
8578 EXPECT_EQ(EvalJs(subframe, "resumeLength").ExtractInt(), 2);
8579 EXPECT_EQ(EvalJs(subframe, "pageshowLength").ExtractInt(), 2);
8580
8581 // 3) Go forward to |url2|, browser-initiated.
8582 web_contents()->GetController().GoForward();
8583 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
8584 EXPECT_EQ(web_contents()->GetLastCommittedURL(), url2);
8585
8586 // We should still have two history entries, and recorded the correct length
8587 // when the 'resume' and 'pageshow' events were dispatched.
8588 EXPECT_EQ(EvalJs(root, "history.length").ExtractInt(), 2);
8589 EXPECT_EQ(EvalJs(root, "resumeLength").ExtractInt(), 2);
8590 EXPECT_EQ(EvalJs(root, "pageshowLength").ExtractInt(), 2);
8591 }
8592
8593 // Tests that the history value saved in the renderer is updated correctly when
8594 // a page gets restored from the back-forward cache through renderer-initiated
8595 // navigation.
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,RendererHistory_RendererInitiated)8596 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
8597 RendererHistory_RendererInitiated) {
8598 ASSERT_TRUE(embedded_test_server()->Start());
8599
8600 GURL url1(embedded_test_server()->GetURL(
8601 "a.com", "/cross_site_iframe_factory.html?a(b)"));
8602 GURL url2(embedded_test_server()->GetURL("a.com", "/title1.html"));
8603
8604 // 1) Go to |url1|, then |url2|. Both pages should have script to save the
8605 // history.length value when getting restored from the back-forward cache.
8606 EXPECT_TRUE(NavigateToURL(shell(), url1));
8607 FrameTreeNode* root = web_contents()->GetFrameTree()->root();
8608 FrameTreeNode* subframe = root->child_at(0);
8609
8610 std::string restore_time_length_saver_script =
8611 "var resumeLength = -1;"
8612 "var pageshowLength = -1;"
8613 "document.onresume = () => {"
8614 " resumeLength = history.length;"
8615 "};"
8616 "window.onpageshow = () => {"
8617 " pageshowLength = history.length;"
8618 "};";
8619 EXPECT_TRUE(ExecJs(root, restore_time_length_saver_script));
8620 EXPECT_TRUE(ExecJs(subframe, restore_time_length_saver_script));
8621 // We should have one history entry.
8622 EXPECT_EQ(EvalJs(root, "history.length").ExtractInt(), 1);
8623 EXPECT_EQ(EvalJs(subframe, "history.length").ExtractInt(), 1);
8624
8625 EXPECT_TRUE(NavigateToURL(shell(), url2));
8626 EXPECT_TRUE(ExecJs(root, restore_time_length_saver_script));
8627 // We should have two history entries.
8628 EXPECT_EQ(EvalJs(root, "history.length").ExtractInt(), 2);
8629
8630 // 2) Go back to |url1|, renderer-initiated.
8631 EXPECT_TRUE(ExecJs(root, "history.back()"));
8632 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
8633 EXPECT_EQ(web_contents()->GetLastCommittedURL(), url1);
8634
8635 // We should still have two history entries, and recorded the correct length
8636 // when the 'resume' and 'pageshow' events were dispatched.
8637 EXPECT_EQ(EvalJs(root, "history.length").ExtractInt(), 2);
8638 EXPECT_EQ(EvalJs(root, "resumeLength").ExtractInt(), 2);
8639 EXPECT_EQ(EvalJs(root, "pageshowLength").ExtractInt(), 2);
8640 EXPECT_EQ(EvalJs(subframe, "history.length").ExtractInt(), 2);
8641 EXPECT_EQ(EvalJs(subframe, "resumeLength").ExtractInt(), 2);
8642 EXPECT_EQ(EvalJs(subframe, "pageshowLength").ExtractInt(), 2);
8643
8644 // 3) Go forward to |url2|, renderer-initiated.
8645 EXPECT_TRUE(ExecJs(root, "history.forward()"));
8646 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
8647
8648 EXPECT_EQ(web_contents()->GetLastCommittedURL(), url2);
8649
8650 // We should still have two history entries, and recorded the correct length
8651 // when the 'resume' and 'pageshow' events were dispatched.
8652 EXPECT_EQ(EvalJs(root, "history.length").ExtractInt(), 2);
8653 EXPECT_EQ(EvalJs(root, "resumeLength").ExtractInt(), 2);
8654 EXPECT_EQ(EvalJs(root, "pageshowLength").ExtractInt(), 2);
8655 }
8656
8657 // This observer keeps tracks whether a given RenderViewHost is deleted or not
8658 // to avoid accessing it and causing use-after-free condition.
8659 class RenderViewHostDeletedObserver : public WebContentsObserver {
8660 public:
RenderViewHostDeletedObserver(RenderViewHost * rvh)8661 explicit RenderViewHostDeletedObserver(RenderViewHost* rvh)
8662 : WebContentsObserver(WebContents::FromRenderViewHost(rvh)),
8663 render_view_host_(rvh),
8664 deleted_(false) {}
8665
RenderViewDeleted(RenderViewHost * render_view_host)8666 void RenderViewDeleted(RenderViewHost* render_view_host) override {
8667 if (render_view_host_ == render_view_host)
8668 deleted_ = true;
8669 }
8670
deleted() const8671 bool deleted() const { return deleted_; }
8672
8673 private:
8674 RenderViewHost* render_view_host_;
8675 bool deleted_;
8676 };
8677
8678 // Tests that RenderViewHost is deleted on eviction along with
8679 // RenderProcessHost.
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,RenderViewHostDeletedOnEviction)8680 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
8681 RenderViewHostDeletedOnEviction) {
8682 ASSERT_TRUE(embedded_test_server()->Start());
8683 GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
8684 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
8685
8686 NavigationControllerImpl& controller = web_contents()->GetController();
8687 BackForwardCacheImpl& cache = controller.GetBackForwardCache();
8688
8689 // 1) Navigate to A.
8690 EXPECT_TRUE(NavigateToURL(shell(), url_a));
8691 RenderFrameHostImpl* rfh_a = current_frame_host();
8692 RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
8693 RenderViewHostDeletedObserver delete_observer_rvh_a(
8694 rfh_a->GetRenderViewHost());
8695
8696 RenderProcessHost* process = rfh_a->GetProcess();
8697 RenderProcessHostWatcher destruction_observer(
8698 process, RenderProcessHostWatcher::WATCH_FOR_HOST_DESTRUCTION);
8699 cache.Flush();
8700
8701 // 2) Navigate to B. A should be stored in cache, count of entries should
8702 // be 1.
8703 EXPECT_TRUE(NavigateToURL(shell(), url_b));
8704 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
8705 EXPECT_EQ(1u, cache.GetEntries().size());
8706
8707 // 3) Initiate eviction of rfh_a from BackForwardCache. Entries should be 0.
8708 // RenderViewHost, RenderProcessHost and RenderFrameHost should all be
8709 // deleted.
8710 EXPECT_TRUE(rfh_a->IsInactiveAndDisallowReactivation());
8711 destruction_observer.Wait();
8712 ASSERT_TRUE(delete_observer_rvh_a.deleted());
8713 delete_observer_rfh_a.WaitUntilDeleted();
8714 EXPECT_EQ(0u, cache.GetEntries().size());
8715 }
8716
8717 // Tests that cross-process sub-frame's RenderViewHost is deleted on root
8718 // RenderFrameHost eviction from BackForwardCache along with its
8719 // RenderProcessHost.
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,CrossProcessSubFrameRenderViewHostDeletedOnEviction)8720 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
8721 CrossProcessSubFrameRenderViewHostDeletedOnEviction) {
8722 ASSERT_TRUE(embedded_test_server()->Start());
8723 GURL url_a(embedded_test_server()->GetURL(
8724 "a.com", "/cross_site_iframe_factory.html?a(b)"));
8725 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
8726
8727 // 1) Navigate to A.
8728 EXPECT_TRUE(NavigateToURL(shell(), url_a));
8729 RenderFrameHostImpl* a1 = current_frame_host();
8730 RenderFrameHostImpl* b1 = a1->child_at(0)->current_frame_host();
8731 RenderFrameDeletedObserver delete_observer_rfh_b1(b1);
8732
8733 RenderViewHostDeletedObserver delete_observer_rvh_b1(b1->GetRenderViewHost());
8734
8735 RenderProcessHost* process = b1->GetProcess();
8736 RenderProcessHostWatcher destruction_observer(
8737 process, RenderProcessHostWatcher::WATCH_FOR_HOST_DESTRUCTION);
8738
8739 // 2) Navigate to URL B.
8740 EXPECT_TRUE(NavigateToURL(shell(), url_b));
8741 EXPECT_TRUE(a1->IsInBackForwardCache());
8742
8743 // 3) Initiate eviction of rfh a1 from BackForwardCache. RenderViewHost,
8744 // RenderProcessHost and RenderFrameHost of sub-frame b1 should all be deleted
8745 // on eviction.
8746 EXPECT_TRUE(a1->IsInactiveAndDisallowReactivation());
8747 destruction_observer.Wait();
8748 ASSERT_TRUE(delete_observer_rvh_b1.deleted());
8749 delete_observer_rfh_b1.WaitUntilDeleted();
8750 }
8751
8752 // Tests that same-process sub-frame's RenderViewHost is deleted on root
8753 // RenderFrameHost eviction from BackForwardCache along with its
8754 // RenderProcessHost.
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,SameProcessSubFrameRenderViewHostDeletedOnEviction)8755 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
8756 SameProcessSubFrameRenderViewHostDeletedOnEviction) {
8757 ASSERT_TRUE(embedded_test_server()->Start());
8758 GURL url_a(embedded_test_server()->GetURL(
8759 "a.com", "/cross_site_iframe_factory.html?a(a)"));
8760 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
8761
8762 // 1) Navigate to A.
8763 EXPECT_TRUE(NavigateToURL(shell(), url_a));
8764 RenderFrameHostImpl* a1 = current_frame_host();
8765 RenderFrameHostImpl* a2 = a1->child_at(0)->current_frame_host();
8766 RenderFrameDeletedObserver delete_observer_rfh_a2(a2);
8767
8768 RenderViewHostDeletedObserver delete_observer_rvh_a2(a2->GetRenderViewHost());
8769
8770 RenderProcessHost* process = a2->GetProcess();
8771 RenderProcessHostWatcher destruction_observer(
8772 process, RenderProcessHostWatcher::WATCH_FOR_HOST_DESTRUCTION);
8773
8774 // 2) Navigate to URL B.
8775 EXPECT_TRUE(NavigateToURL(shell(), url_b));
8776 EXPECT_TRUE(a1->IsInBackForwardCache());
8777
8778 // 3) Initiate eviction of rfh a1 from BackForwardCache. RenderViewHost,
8779 // RenderProcessHost and RenderFrameHost of sub-frame a2 should all be
8780 // deleted.
8781 EXPECT_TRUE(a1->IsInactiveAndDisallowReactivation());
8782 destruction_observer.Wait();
8783 ASSERT_TRUE(delete_observer_rvh_a2.deleted());
8784 delete_observer_rfh_a2.WaitUntilDeleted();
8785 }
8786
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,MainDocumentCSPHeadersAreRestored)8787 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
8788 MainDocumentCSPHeadersAreRestored) {
8789 ASSERT_TRUE(embedded_test_server()->Start());
8790
8791 GURL url_a(embedded_test_server()->GetURL(
8792 "a.com",
8793 "/set-header?"
8794 "Content-Security-Policy: frame-src 'none'"));
8795 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
8796
8797 // 1) Navigate to A, which should set CSP.
8798 EXPECT_TRUE(NavigateToURL(shell(), url_a));
8799 RenderFrameHostImpl* rfh_a = current_frame_host();
8800
8801 // Check that CSP was set.
8802 {
8803 const std::vector<network::mojom::ContentSecurityPolicyHeader>& root_csp =
8804 current_frame_host()
8805 ->frame_tree_node()
8806 ->current_replication_state()
8807 .accumulated_csp_headers;
8808 EXPECT_EQ(1u, root_csp.size());
8809 EXPECT_EQ("frame-src 'none'", root_csp[0].header_value);
8810 }
8811
8812 // 2) Navigate to B.
8813 EXPECT_TRUE(NavigateToURL(shell(), url_b));
8814
8815 // 3) Navigate back and expect that the CSP headers are present on the main
8816 // frame.
8817 web_contents()->GetController().GoBack();
8818 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
8819 EXPECT_EQ(rfh_a, current_frame_host());
8820 ExpectOutcome(BackForwardCacheMetrics::HistoryNavigationOutcome::kRestored,
8821 FROM_HERE);
8822
8823 // Check that CSP was restored.
8824 {
8825 const std::vector<network::mojom::ContentSecurityPolicyHeader>& root_csp =
8826 current_frame_host()
8827 ->frame_tree_node()
8828 ->current_replication_state()
8829 .accumulated_csp_headers;
8830 EXPECT_EQ(1u, root_csp.size());
8831 EXPECT_EQ("frame-src 'none'", root_csp[0].header_value);
8832 }
8833 }
8834
8835 // Sandboxed documents are not cached because we don't properly restore sandbox
8836 // flags at the moment.
8837 // TODO(altimin, carlscab): Remove this after sandbox flags will move to RFH /
8838 // BrowsingInstanceFrameState.
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,SandboxedFramesNotCached)8839 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, SandboxedFramesNotCached) {
8840 ASSERT_TRUE(embedded_test_server()->Start());
8841
8842 GURL url_a(
8843 embedded_test_server()->GetURL("a.com",
8844 "/set-header?"
8845 "Content-Security-Policy: sandbox"));
8846 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
8847
8848 // 1) Navigate to A, which should set CSP.
8849 EXPECT_TRUE(NavigateToURL(shell(), url_a));
8850
8851 // Check that CSP was set.
8852 {
8853 const std::vector<network::mojom::ContentSecurityPolicyHeader>& root_csp =
8854 current_frame_host()
8855 ->frame_tree_node()
8856 ->current_replication_state()
8857 .accumulated_csp_headers;
8858 EXPECT_EQ(1u, root_csp.size());
8859 EXPECT_EQ("sandbox", root_csp[0].header_value);
8860 }
8861
8862 // 2) Navigate to B.
8863 EXPECT_TRUE(NavigateToURL(shell(), url_b));
8864
8865 // 3) Navigate back and expect that the page wasn't restored from bfcache.
8866 web_contents()->GetController().GoBack();
8867 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
8868 ExpectNotRestored(
8869 {BackForwardCacheMetrics::NotRestoredReason::kFrameTreeNodeStateReset},
8870 FROM_HERE);
8871 }
8872
8873 class BackForwardCacheBrowserTestWithFileSystemAPISupported
8874 : public BackForwardCacheBrowserTest {
8875 protected:
SetUpCommandLine(base::CommandLine * command_line)8876 void SetUpCommandLine(base::CommandLine* command_line) override {
8877 EnableFeatureAndSetParams(features::kBackForwardCache,
8878 "file_system_api_supported", "true");
8879 BackForwardCacheBrowserTest::SetUpCommandLine(command_line);
8880 }
8881 };
8882
IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTestWithFileSystemAPISupported,DISABLED_CacheWithFileSystemAPI)8883 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTestWithFileSystemAPISupported,
8884 DISABLED_CacheWithFileSystemAPI) {
8885 ASSERT_TRUE(embedded_test_server()->Start());
8886 GURL url_a(embedded_test_server()->GetURL("/fileapi/request_test.html"));
8887 GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
8888
8889 // 1) Navigate to a page with WebFileSystem usage.
8890 EXPECT_TRUE(NavigateToURL(shell(), url_a));
8891 RenderFrameHostImpl* rfh_a = current_frame_host();
8892 RenderFrameDeletedObserver deleted(rfh_a);
8893
8894 // 2) Navigate away.
8895 EXPECT_TRUE(NavigateToURL(shell(), url_b));
8896 EXPECT_FALSE(deleted.deleted());
8897 EXPECT_TRUE(rfh_a->IsInBackForwardCache());
8898
8899 // 3) Go back to the page with WebFileSystem.
8900 web_contents()->GetController().GoBack();
8901 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
8902 EXPECT_EQ(rfh_a, current_frame_host());
8903 ExpectOutcome(BackForwardCacheMetrics::HistoryNavigationOutcome::kRestored,
8904 FROM_HERE);
8905 }
8906
8907 } // namespace content
8908