blob: d234048fd1f02b0f4eda86549b58d32b49e94297 [file] [log] [blame]
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CONTENT_BROWSER_RENDERER_HOST_BACK_FORWARD_CACHE_IMPL_H_
#define CONTENT_BROWSER_RENDERER_HOST_BACK_FORWARD_CACHE_IMPL_H_
#include <list>
#include <memory>
#include <set>
#include <unordered_set>
#include "base/feature_list.h"
#include "base/gtest_prod_util.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/raw_ref.h"
#include "base/memory/weak_ptr.h"
#include "base/task/single_thread_task_runner.h"
#include "base/time/time.h"
#include "content/browser/renderer_host/back_forward_cache_can_store_document_result.h"
#include "content/browser/renderer_host/back_forward_cache_metrics.h"
#include "content/browser/renderer_host/page_impl.h"
#include "content/browser/renderer_host/render_process_host_internal_observer.h"
#include "content/browser/renderer_host/stored_page.h"
#include "content/common/content_export.h"
#include "content/public/browser/back_forward_cache.h"
#include "content/public/browser/global_routing_id.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_process_host_observer.h"
#include "content/public/browser/site_instance.h"
#include "content/public/browser/storage_partition.h"
#include "content/public/common/content_features.h"
#include "net/cookies/canonical_cookie.h"
#include "services/network/public/mojom/cookie_manager.mojom.h"
#include "third_party/blink/public/mojom/back_forward_cache_not_restored_reasons.mojom.h"
#include "third_party/blink/public/mojom/page/page.mojom.h"
#include "third_party/perfetto/include/perfetto/tracing/traced_value_forward.h"
#include "url/gurl.h"
namespace content {
class RenderFrameHostImpl;
class SiteInstance;
// This feature is used to limit the scope of back-forward cache experiment
// without enabling it. To control the URLs list by using this feature by
// generating the metrics only for "allowed_websites" param. Mainly, to ensure
// that metrics from the control and experiment groups are consistent.
BASE_FEATURE(kRecordBackForwardCacheMetricsWithoutEnabling,
"RecordBackForwardCacheMetricsWithoutEnabling",
base::FEATURE_DISABLED_BY_DEFAULT);
// Removes the time limit for cached content. This is used on bots to identify
// accidentally passing tests.
BASE_FEATURE(kBackForwardCacheNoTimeEviction,
"BackForwardCacheNoTimeEviction",
base::FEATURE_DISABLED_BY_DEFAULT);
// Allows pages with cache-control:no-store to enter the back/forward cache.
// Feature params can specify whether pages with cache-control:no-store can be
// restored if cookies change / if HTTPOnly cookies change.
// TODO(crbug.com/1228611): Enable this feature.
BASE_FEATURE(kCacheControlNoStoreEnterBackForwardCache,
"CacheControlNoStoreEnterBackForwardCache",
base::FEATURE_DISABLED_BY_DEFAULT);
// Enables controlling the time to live for pages in the backforward cache.
// The time to live is defined by the param 'time_to_live_seconds'; if this
// param is not specified then this feature is ignored and the default is used.
BASE_FEATURE(kBackForwardCacheTimeToLiveControl,
"BackForwardCacheTimeToLiveControl",
base::FEATURE_DISABLED_BY_DEFAULT);
// Allows overriding the sizes of back/forward cache.
// Sizes set via this feature's parameters take precedence over others.
BASE_FEATURE(kBackForwardCacheSize,
"BackForwardCacheSize",
base::FEATURE_DISABLED_BY_DEFAULT);
// Combines a flattened list and a tree of the reasons why each document cannot
// enter the back/forward cache (might be empty if it can). The tree saves the
// reasons for each document in the tree (including those without the reasons)
// in a tree format, with each node corresponding to one document. The flattened
// list is the combination of all reasons for all documents in the tree.
// CONTENT_EXPORT is for exporting only for testing.
struct CONTENT_EXPORT BackForwardCacheCanStoreDocumentResultWithTree {
BackForwardCacheCanStoreDocumentResultWithTree(
BackForwardCacheCanStoreDocumentResult& flattened_reasons,
std::unique_ptr<BackForwardCacheCanStoreTreeResult> tree_reasons);
~BackForwardCacheCanStoreDocumentResultWithTree();
BackForwardCacheCanStoreDocumentResult flattened_reasons;
std::unique_ptr<BackForwardCacheCanStoreTreeResult> tree_reasons;
// The conditions for storing and restoring the pages are different in that
// pages with cache-control:no-store can enter back/forward cache depending on
// the experiment flag, but can never be restored.
bool CanStore() const { return flattened_reasons.CanStore(); }
bool CanRestore() const { return flattened_reasons.CanRestore(); }
};
// BackForwardCache:
//
// After the user navigates away from a document, the old one goes into the
// frozen state and is kept in this object. They can potentially be reused
// after an history navigation. Reusing a document means swapping it back with
// the current_frame_host.
//
//
// BackForwardCache Size & Pruning Logic:
//
// 1. `EnforceCacheSizeLimit()` is called to prune the cache size down on
// storing a new cache entry, or when the renderer process's
// `IsProcessBackgrounded()` state changes.
// A. [Android-only] The number of entries where `HasForegroundedProcess()`
// is true is pruned to `GetForegroundedEntriesCacheSize()`.
// B. Prunes to `GetCacheSize()` entries no matter what kinds of tabs
// BackForwardCache is in.
// C. When a `RenderFrameHost` enters BackForwardCache, it schedules a task
// in `RenderFrameHostImpl::StartBackForwardCacheEvictionTimer()` to
// evicts the outermost frame after
// `kDefaultTimeToLiveInBackForwardCacheInSeconds` seconds.
// 2. In `performance_manager::policies::BFCachePolicy`:
// A. (To Launch) [Desktop-only] On moderate memory pressure, the number of
// entries in a visible tab's cache is pruned to
// `ForegroundCacheSizeOnModeratePressure()`. The number in a non-visible
// tab is pruned to `BackgroundCacheSizeOnModeratePressure()`.
// B. (To Launch) [Desktop-only] On critical memory pressure, the cache is
// cleared.
class CONTENT_EXPORT BackForwardCacheImpl
: public BackForwardCache,
public RenderProcessHostInternalObserver,
public StoredPage::Delegate {
friend class BackForwardCacheCanStoreTreeResult;
friend class BackForwardCacheMetrics;
public:
enum MessageHandlingPolicyWhenCached {
kMessagePolicyNone,
kMessagePolicyLog,
kMessagePolicyDump,
};
static MessageHandlingPolicyWhenCached
GetChannelAssociatedMessageHandlingPolicy();
// BackForwardCache entry, consisting of the page and associated metadata.
class Entry : public ::network::mojom::CookieChangeListener {
public:
explicit Entry(std::unique_ptr<StoredPage> stored_page);
~Entry() override;
void WriteIntoTrace(perfetto::TracedValue context);
// Starts monitoring the cookie change in this entry.
void StartMonitoringCookieChange();
// Indicates whether or not all the |render_view_hosts| in this entry have
// received the acknowledgement from renderer that it finished running
// handlers.
bool AllRenderViewHostsReceivedAckFromRenderer();
std::unique_ptr<StoredPage> TakeStoredPage() {
return std::move(stored_page_);
}
void SetPageRestoreParams(
blink::mojom::PageRestoreParamsPtr page_restore_params) {
stored_page_->SetPageRestoreParams(std::move(page_restore_params));
}
void SetStoredPageDelegate(StoredPage::Delegate* delegate) {
stored_page_->SetDelegate(delegate);
}
// The main document being stored.
RenderFrameHostImpl* render_frame_host() {
return stored_page_->render_frame_host();
}
const StoredPage::RenderViewHostImplSafeRefSet& render_view_hosts() {
return stored_page_->render_view_hosts();
}
const StoredPage::RenderFrameProxyHostMap& proxy_hosts() const {
return stored_page_->proxy_hosts();
}
size_t proxy_hosts_size() { return stored_page_->proxy_hosts_size(); }
private:
friend class BackForwardCacheImpl;
// ::network::mojom::CookieChangeListener
void OnCookieChange(const net::CookieChangeInfo& change) override;
mojo::Receiver<::network::mojom::CookieChangeListener>
cookie_listener_receiver_{this};
struct CookieModified {
// Indicates whether or not cookie on the bfcache entry has been modified
// while the entry is in bfcache.
bool cookie_modified = false;
// Indicates whether or not HTTPOnly cookie on the bfcache entry
// has been modified while the entry is in bfcache.
bool http_only_cookie_modified = false;
};
// Only populated when |AllowStoringPagesWithCacheControlNoStore()| is true.
absl::optional<CookieModified> cookie_modified_;
std::unique_ptr<StoredPage> stored_page_;
};
BackForwardCacheImpl();
BackForwardCacheImpl(const BackForwardCacheImpl&) = delete;
BackForwardCacheImpl& operator=(const BackForwardCacheImpl&) = delete;
~BackForwardCacheImpl() override;
// Returns whether MediaSession's service is allowed for the BackForwardCache.
static bool IsMediaSessionServiceAllowed();
// Returns whether back/forward cache is enabled for screen reader users.
static bool IsScreenReaderAllowed();
// Log an unexpected message from the renderer. Doing it here so that it is
// grouped with other back/forward cache vlogging and e.g. will show up in
// test logs. `message_name` varies in each build however when a test failure
// occurs, it should be possible to recreate the build and find which message
// corresponds to this the value.
static void VlogUnexpectedRendererToBrowserMessage(
const char* interface_name_,
uint32_t message_name,
RenderFrameHostImpl* rfh);
// Returns the reasons (if any) why this document and its children cannot
// enter the back/forward cache. Depends on the |render_frame_host| and its
// children's state. Should only be called after we've navigated away from
// |render_frame_host|, which means nothing about the page can change (usage
// of blocklisted features, pending navigations, load state, etc.) anymore.
// Note that criteria for storing and restoring can be different, i.e.
// |CanStore()| and |CanRestore()| might give different results.
BackForwardCacheCanStoreDocumentResultWithTree
GetCurrentBackForwardCacheEligibility(RenderFrameHostImpl* render_frame_host);
// Whether a RenderFrameHost could be stored into the BackForwardCache at some
// point in the future. Different than GetCurrentBackForwardCacheEligibility()
// above, we won't check for properties of |render_frame_host| that might
// change in the future such as usage of certain APIs, loading state,
// existence of pending navigation requests, etc. This should be treated as a
// "best guess" on whether a page still has a chance to be stored in the
// back-forward cache later on, and should not be used as a final check before
// storing a page to the back-forward cache (for that, use
// GetCurrentBackForwardCacheEligibility() instead).
BackForwardCacheCanStoreDocumentResultWithTree
GetFutureBackForwardCacheEligibilityPotential(
RenderFrameHostImpl* render_frame_host);
// Moves the specified BackForwardCache entry into the BackForwardCache. It
// can be reused in a future history navigation by using RestoreEntry(). When
// the BackForwardCache is full, the least recently used document is evicted.
// Precondition: CanStoreDocument(*(entry->render_frame_host)).
void StoreEntry(std::unique_ptr<Entry> entry);
// Ensures that the cache is within its size limits. This should be called
// whenever events occur that could put the cache outside its limits. What
// those events are depends on the cache limit policy.
void EnforceCacheSizeLimit();
// Returns a pointer to a cached BackForwardCache entry matching
// |navigation_entry_id| if it exists in the BackForwardCache. Returns nullptr
// if no matching entry is found.
//
// Note: The returned pointer should be used temporarily only within the
// execution of a single task on the event loop. Beyond that, there is no
// guarantee the pointer will be valid, because the document may be
// removed/evicted from the cache.
Entry* GetEntry(int navigation_entry_id);
// During a history navigation, moves an entry out of the BackForwardCache
// knowing its |navigation_entry_id|. |page_restore_params| includes
// information that is needed by the entry's page after getting restored,
// which includes the latest history information (offset, length) and the
// timestamp corresponding to the start of the back-forward cached navigation,
// which would be communicated to the page to allow it to record the latency
// of this navigation.
std::unique_ptr<Entry> RestoreEntry(
int navigation_entry_id,
blink::mojom::PageRestoreParamsPtr page_restore_params);
// Evict all cached pages in the same BrowsingInstance as
// |site_instance|.
void EvictFramesInRelatedSiteInstances(SiteInstance* site_instance);
// Immediately deletes all frames in the cache. This should only be called
// when WebContents is being destroyed.
void Shutdown();
// Posts a task to destroy all frames in the BackForwardCache that have been
// marked as evicted.
void PostTaskToDestroyEvictedFrames();
// Storing frames in back-forward cache is not supported indefinitely
// due to potential privacy issues and memory leaks. Instead we are evicting
// the frame from the cache after the time to live, which can be controlled
// via experiment.
static base::TimeDelta GetTimeToLiveInBackForwardCache();
// Gets the maximum number of entries the BackForwardCache can hold per tab.
static size_t GetCacheSize();
// The back-forward cache is experimented on a limited set of URLs. This
// method returns true if the |url| matches one of those. URL not matching
// this won't enter the back-forward cache. This can still return true even
// when BackForwardCache is disabled for metrics purposes. It checks
// |IsHostPathAllowed| then |IsHostPathAllowed|
bool IsAllowed(const GURL& current_url);
// Returns true if the host and path are allowed according to the
// "allowed_websites" and "blocked_webites" parameters of
// |feature::kBackForwardCache|. An empty "allowed_websites" implies that all
// websites are allowed.
bool IsHostPathAllowed(const GURL& current_url);
// Returns true if query does not contain any of the parameters in
// "blocked_cgi_params" parameter of |feature::kBackForwardCache|. The
// comparison is done by splitting the query string on "&" and looking for
// exact matches in the list (parameter name and value). It does not consider
// URL escaping.
bool IsQueryAllowed(const GURL& current_url);
// Called just before commit for a navigation that's served out of the back
// forward cache. This method will disable eviction in renderers and invoke
// |done_callback| when they are ready for the navigation to be committed.
void WillCommitNavigationToCachedEntry(Entry& bfcache_entry,
base::OnceClosure done_callback);
// Returns the task runner that should be used by the eviction timer.
scoped_refptr<base::SingleThreadTaskRunner> GetTaskRunner() {
return task_runner_for_testing_
? task_runner_for_testing_
: base::SingleThreadTaskRunner::GetCurrentDefault();
}
// Inject task runner for precise timing control in browser tests.
void SetTaskRunnerForTesting(
scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
task_runner_for_testing_ = task_runner;
}
const std::list<std::unique_ptr<Entry>>& GetEntries();
// BackForwardCache overrides:
void Flush() override;
void Prune(size_t limit) override;
void DisableForTesting(DisableForTestingReason reason) override;
// RenderProcessHostInternalObserver methods
void RenderProcessBackgroundedChanged(RenderProcessHostImpl* host) override;
// Returns true if we are managing the cache size using foreground and
// background limits (if finch parameter "foreground_cache_size" > 0).
static bool UsingForegroundBackgroundCacheSizeLimit();
// Returns true if one of the BFCache entries has a matching
// BrowsingInstanceId/SiteInstanceId/RenderFrameProxyHost.
// TODO(https://crbug.com/1243541): Remove these once the bug is fixed.
bool IsBrowsingInstanceInBackForwardCacheForDebugging(
BrowsingInstanceId browsing_instance_id);
bool IsSiteInstanceInBackForwardCacheForDebugging(
SiteInstanceId site_instance_id);
bool IsProxyInBackForwardCacheForDebugging(RenderFrameProxyHost* proxy);
// StoredPage::Delegate overrides:
void RenderViewHostNoLongerStored(RenderViewHostImpl* rvh) override;
// Construct a tree of NotRestoredReasons for |rfh| without checking the
// eligibility of all the documents in the frame tree. This should be only
// used for evicting the back/forward cache entry where we know why the entry
// is not eligible and which document is causing it.
// This preserves the frame tree structure after eviction, because the actual
// page and frame tree is not kept around after eviction.
// |rfh| will be marked as having |eviction_reason| as not restored reasons.
static BackForwardCacheCanStoreDocumentResultWithTree
CreateEvictionBackForwardCacheCanStoreTreeResult(
RenderFrameHostImpl& rfh,
BackForwardCacheCanStoreDocumentResult& eviction_reason);
private:
// Destroys all evicted frames in the BackForwardCache.
void DestroyEvictedFrames();
// Populates the reasons that are only relevant for main documents such as
// browser settings, the main document's URL & HTTP status, etc.
void PopulateReasonsForMainDocument(
BackForwardCacheCanStoreDocumentResult& result,
RenderFrameHostImpl* render_frame_host);
// Populates the reasons why this |rfh| and its subframes cannot enter the
// back/forward cache in a flat list through |flattened_result| and as a tree
// through its return value.
// |include_non_sticky| controls whether we include non-sticky reasons in the
// result.
std::unique_ptr<BackForwardCacheCanStoreTreeResult> PopulateReasonsForPage(
RenderFrameHostImpl* rfh,
BackForwardCacheCanStoreDocumentResult& flattened_result,
bool include_non_sticky);
// Updates the result to include CacheControlNoStore reasons if the flag is
// on.
void UpdateCanStoreToIncludeCacheControlNoStore(
BackForwardCacheCanStoreDocumentResult& result,
RenderFrameHostImpl* render_frame_host);
// Return the matching entry which has |page|.
BackForwardCacheImpl::Entry* FindMatchingEntry(PageImpl& page);
void RenderViewHostNoLongerStoredInternal(RenderViewHostImpl* rvh);
// If non-zero, the cache may contain at most this many entries with involving
// foregrounded processes and the remaining space can only be used by entries
// with no foregrounded processes. We can be less strict on memory usage of
// background processes because Android will kill the process if memory
// becomes scarce.
static size_t GetForegroundedEntriesCacheSize();
// Enforces a limit on the number of entries. Which entries are counted
// towards the limit depends on the values of |foregrounded_only|. If it's
// true it only considers entries that are associated with a foregrounded
// process. Otherwise all entries are considered.
size_t EnforceCacheSizeLimitInternal(size_t limit, bool foregrounded_only);
// Updates |process_to_entry_map_| with processes from |entry|. These must
// be called after adding or removing an entry in |entries_|.
void AddProcessesForEntry(Entry& entry);
void RemoveProcessesForEntry(Entry& entry);
// Returns true if the flag is on for pages with cache-control:no-store to
// get restored from back/forward cache unless cookies change.
static bool AllowStoringPagesWithCacheControlNoStore();
enum RequestedFeatures { kAll, kOnlySticky };
static BlockListedFeatures GetAllowedFeatures(
RequestedFeatures requested_features);
static BlockListedFeatures GetDisallowedFeatures(
RequestedFeatures requested_features);
// Contains the set of stored Entries.
// Invariant:
// - Ordered from the most recently used to the last recently used.
// - Once the list is full, the least recently used document is evicted.
std::list<std::unique_ptr<Entry>> entries_;
// Keeps track of the observed RenderProcessHosts. This is populated
// from and kept in sync with |entries_|. The RenderProcessHosts are collected
// from each Entry's RenderViewHosts. Every RenderProcessHost in here is
// observed by |this|. Every RenderProcessHost in this is referenced by a
// RenderViewHost in the Entry and so will be valid.
std::multiset<RenderProcessHost*> observed_processes_;
// Only used in tests. Whether the BackforwardCached has been disabled for
// testing.
bool is_disabled_for_testing_ = false;
// Only used for tests. This task runner is used for precise injection in
// browser tests and for timing control.
scoped_refptr<base::SingleThreadTaskRunner> task_runner_for_testing_;
// To enter the back-forward cache, the main document URL's must match one of
// the field trial parameter "allowed_websites". This is represented here by a
// set of host and path prefix. When |allowed_urls_| is empty, it means there
// are no restrictions on URLs.
const std::map<std::string, // URL's host,
std::vector<std::string> // URL's path prefix
>
allowed_urls_;
// This is an emergency kill switch per url to stop BFCache. The data will be
// provided via the field trial parameter "blocked_websites".
// "blocked_websites" have priority over "allowed_websites". This is
// represented here by a set of host and path prefix.
const std::map<std::string, // URL's host,
std::vector<std::string> // URL's path prefix
>
blocked_urls_;
// Data provided from the "blocked_cgi_params" feature param. If any of these
// occur in the query of the URL then the page is not eligible for caching.
// See |IsQueryAllowed|.
const std::unordered_set<std::string> blocked_cgi_params_;
// Helper class to iterate through the frame tree in the page and populate the
// NotRestoredReasons.
class NotRestoredReasonBuilder {
public:
// Construct a tree of NotRestoredReasons by checking the eligibility of
// each frame in the frame tree rooted at |root_rfh|.
// |root_rfh| represents the root document of the page. |include_non_sticky|
// controls whether or not we should record non-sticky reasons in the tree.
NotRestoredReasonBuilder(RenderFrameHostImpl* root_rfh,
bool include_non_sticky);
// Struct for containing the RenderFrameHostImpl that is going to be
// evicted if applicable. |reasons| represent why |rfh_to_be_evicted| will
// be evicted.
struct EvictionInfo {
EvictionInfo(RenderFrameHostImpl& rfh,
BackForwardCacheCanStoreDocumentResult* reasons)
: rfh_to_be_evicted(&rfh), reasons(reasons) {}
RenderFrameHostImpl* const rfh_to_be_evicted;
const BackForwardCacheCanStoreDocumentResult* reasons;
};
NotRestoredReasonBuilder(RenderFrameHostImpl* root_rfh,
bool include_non_sticky,
absl::optional<EvictionInfo> eviction_info);
~NotRestoredReasonBuilder();
// Access the populated result.
BackForwardCacheCanStoreDocumentResult& GetFlattenedResult() {
// TODO(yuzus): Check that |flattened_result_| and the tree result match.
return flattened_result_;
}
std::unique_ptr<BackForwardCacheCanStoreTreeResult> GetTreeResult() {
return std::move(tree_result_);
}
// Populates `result` with the blocking reasons for this document. If
// "include_non_sticky" is true, it includes non-sticky reasons.
void PopulateReasonsForDocument(
BackForwardCacheCanStoreDocumentResult& result,
RenderFrameHostImpl* rfh,
bool include_non_sticky);
// Populates the sticky reasons for `rfh` without recursing into subframes.
// Sticky features can't be unregistered and remain active for the rest of
// the lifetime of the page.
void PopulateStickyReasonsForDocument(
BackForwardCacheCanStoreDocumentResult& result,
RenderFrameHostImpl* rfh);
// Populates the non-sticky reasons for `rfh` without recursing into
// subframes. Non-sticky reasons mean the reasons that may be resolved later
// such as when the page releases blocking resources in pagehide.
void PopulateNonStickyReasonsForDocument(
BackForwardCacheCanStoreDocumentResult& result,
RenderFrameHostImpl* rfh);
private:
// Populate NotRestoredReasons for the `rfh` by
// iterating the frame tree and populating NotRestoredReasons in
// |flattened_result_|.
std::unique_ptr<BackForwardCacheCanStoreTreeResult> PopulateReasons(
RenderFrameHostImpl* rfh);
// Root document of the tree.
const raw_ptr<RenderFrameHostImpl> root_rfh_;
// BackForwardCacheImpl instance to access eligibility check functions.
const raw_ref<BackForwardCacheImpl> bfcache_;
// Flattened list of NotRestoredReasons for the tree. This is empty at the
// start and has to be merged using |GetFlattenedResult()|.
BackForwardCacheCanStoreDocumentResult flattened_result_;
// Tree result of NotRestoredReasons. This is populated in the constructor.
std::unique_ptr<BackForwardCacheCanStoreTreeResult> tree_result_;
// If true, check both non-sticky reasons and sticky reasons. If false,
// check only sticky reasons.
const bool include_non_sticky_;
// Contains the information of the RenderFrameHost that causes eviction, if
// applicable. If set, the result returned by the builder will only contain
// the NotRestoredReason for the RenderFrameHost that causes eviction
// (instead of the reasons for the whole tree).
absl::optional<EvictionInfo> eviction_info_;
};
base::WeakPtrFactory<BackForwardCacheImpl> weak_factory_;
// For testing:
FRIEND_TEST_ALL_PREFIXES(BackForwardCacheMetricsTest, AllFeaturesCovered);
FRIEND_TEST_ALL_PREFIXES(BackForwardCacheActiveSizeTest, ActiveCacheSize);
FRIEND_TEST_ALL_PREFIXES(BackForwardCacheOverwriteSizeTest,
OverwrittenCacheSize);
FRIEND_TEST_ALL_PREFIXES(BackForwardCacheDefaultSizeTest, DefaultCacheSize);
};
// Allow external code to be notified when back-forward cache is disabled for a
// RenderFrameHost. This should be used only by the testing infrastructure which
// want to know the exact reason why the cache was disabled. There can be only
// one observer.
class CONTENT_EXPORT BackForwardCacheTestDelegate {
public:
BackForwardCacheTestDelegate();
virtual ~BackForwardCacheTestDelegate();
virtual void OnDisabledForFrameWithReason(
GlobalRenderFrameHostId id,
BackForwardCache::DisabledReason reason) = 0;
};
// Represents the reasons that a subtree cannot enter BFCache as a tree with a
// node for every document in the subtree, in frame tree order. It also includes
// documents that have no blocking reason.
class CONTENT_EXPORT BackForwardCacheCanStoreTreeResult {
public:
friend class BackForwardCacheImpl;
using ChildrenVector =
std::vector<std::unique_ptr<BackForwardCacheCanStoreTreeResult>>;
BackForwardCacheCanStoreTreeResult() = delete;
BackForwardCacheCanStoreTreeResult(BackForwardCacheCanStoreTreeResult&) =
delete;
BackForwardCacheCanStoreTreeResult& operator=(
BackForwardCacheCanStoreTreeResult&&) = delete;
~BackForwardCacheCanStoreTreeResult();
// Adds reasons of this subtree's root document to the tree result from
// |BackForwardCacheCanStoreDocumentResult|.
void AddReasonsToSubtreeRootFrom(
const BackForwardCacheCanStoreDocumentResult& result);
// The reasons for this subtree's root document.
const BackForwardCacheCanStoreDocumentResult& GetDocumentResult() const {
return document_result_;
}
// Populate NotRestoredReasons mojom struct based on the existing tree of
// reason to report to the renderer. This will only partially contain
// cross-origin reasons. See |GetWebExposedNotRestoredReasonsInternal()| for
// more explanation.
// This should be called only when the root document is outermost main
// document.
blink::mojom::BackForwardCacheNotRestoredReasonsPtr
GetWebExposedNotRestoredReasons();
// Flatten the tree and return a flattened list of not restored reasons that
// includes all the reasons in the tree.
const BackForwardCacheCanStoreDocumentResult FlattenTree();
// The children nodes. We can access the children nodes of this
// node/document from this vector.
const ChildrenVector& GetChildren() const { return children_; }
// Whether this subtree's root document's origin is the same origin with the
// origin of the page's root document origin. Returns false if this document
// is cross-origin.
bool IsSameOrigin() const { return is_same_origin_; }
// The URL of the document corresponding to this subtree's root document.
const GURL& GetUrl() const { return url_; }
// Creates and returns an empty tree.
static std::unique_ptr<BackForwardCacheCanStoreTreeResult> CreateEmptyTree(
RenderFrameHostImpl* rfh);
static std::unique_ptr<BackForwardCacheCanStoreTreeResult>
CreateEmptyTreeForNavigation(NavigationRequest* navigation);
private:
friend class BackForwardCacheImplTest;
FRIEND_TEST_ALL_PREFIXES(BackForwardCacheImplTest,
CrossOriginReachableFrameCount);
FRIEND_TEST_ALL_PREFIXES(BackForwardCacheImplTest, FirstCrossOriginReachable);
FRIEND_TEST_ALL_PREFIXES(BackForwardCacheImplTest,
SecondCrossOriginReachable);
// This constructor is for creating a tree for |rfh| as the subtree's root
// document's frame.
BackForwardCacheCanStoreTreeResult(
RenderFrameHostImpl* rfh,
const url::Origin& main_document_origin,
const GURL& url,
BackForwardCacheCanStoreDocumentResult& result_for_this_document);
// Creates an empty placeholder tree with the empty result.
BackForwardCacheCanStoreTreeResult(bool is_same_origin, const GURL& url);
// Helper function for |GetWebExposedNotRestoredReasons()|. |index| is the
// random index of the cross-origin iframe that we decided to report
// from all the reachable cross-origin iframes. We decrement this count
// every time we call this function, and report only when |index| is 0 so
// that reporting happens only for randomly picked one of such iframes.
blink::mojom::BackForwardCacheNotRestoredReasonsPtr
GetWebExposedNotRestoredReasonsInternal(int& index);
// Count the number of cross-origin frames that are direct children of
// same-origin frames, including the main frame, in the tree.
uint32_t GetCrossOriginReachableFrameCount();
void FlattenTreeHelper(
BackForwardCacheCanStoreDocumentResult* document_result);
void AppendChild(std::unique_ptr<BackForwardCacheCanStoreTreeResult> child);
// See |GetDocumentResult|
BackForwardCacheCanStoreDocumentResult document_result_;
// See |GetChildren|
ChildrenVector children_;
// See |IsSameOrigin|
const bool is_same_origin_;
// The id, name and src attribute of the frame owner of this subtree's root
// document.
// TODO(yuzus): Make them optional.
const std::string id_;
const std::string name_;
const std::string src_;
// See |GetUrl|
const GURL url_;
};
} // namespace content
#endif // CONTENT_BROWSER_RENDERER_HOST_BACK_FORWARD_CACHE_IMPL_H_