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