| // 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 "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 "base/types/expected.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/frame/back_forward_cache_controller.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); | 
 |  | 
 | // Feature to allow exposing cross-origin subframes' NotRestoredReasons. | 
 | BASE_FEATURE(kAllowCrossOriginNotRestoredReasons, | 
 |              "AllowCrossOriginNotRestoredReasons", | 
 |              base::FEATURE_DISABLED_BY_DEFAULT); | 
 |  | 
 | CONTENT_EXPORT BASE_DECLARE_FEATURE(kBackForwardCacheSize); | 
 | CONTENT_EXPORT extern const base::FeatureParam<int> | 
 |     kBackForwardCacheSizeCacheSize; | 
 | CONTENT_EXPORT extern const base::FeatureParam<int> | 
 |     kBackForwardCacheSizeForegroundCacheSize; | 
 |  | 
 | // When a prioritized BFCache entry needs to be evicted, it will be kept | 
 | // in the cache instead. Only the latest prioritized entry outside the limit | 
 | // will be handled in this way. | 
 | BASE_FEATURE(kBackForwardCachePrioritizedEntry, | 
 |              "BackForwardCachePrioritizedEntry", | 
 |              base::FEATURE_DISABLED_BY_DEFAULT); | 
 |  | 
 | // Controls the interaction between back/forward cache and | 
 | // unload. When enabled, pages with unload handlers may enter the | 
 | // cache. | 
 | BASE_FEATURE(kBackForwardCacheUnloadAllowed, | 
 |              "BackForwardCacheUnloadAllowed", | 
 | #if BUILDFLAG(IS_ANDROID) | 
 |              base::FEATURE_ENABLED_BY_DEFAULT | 
 | #else | 
 |              base::FEATURE_DISABLED_BY_DEFAULT | 
 | #endif | 
 | ); | 
 |  | 
 | // 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( | 
 |       BackForwardCacheCanStoreDocumentResultWithTree&& other); | 
 |   ~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 | 
 | //    `GetPriority()` 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. [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. [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: | 
 |     explicit Entry(std::unique_ptr<StoredPage> stored_page); | 
 |     ~Entry(); | 
 |  | 
 |     void WriteIntoTrace(perfetto::TracedValue context); | 
 |  | 
 |     // 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); | 
 |     } | 
 |  | 
 |     void SetViewTransitionState( | 
 |         std::optional<blink::ViewTransitionState> view_transition_state) { | 
 |       stored_page_->SetViewTransitionState(std::move(view_transition_state)); | 
 |     } | 
 |  | 
 |     // 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; | 
 |  | 
 |     std::unique_ptr<StoredPage> stored_page_; | 
 |   }; | 
 |  | 
 |   explicit BackForwardCacheImpl(BrowserContext* browser_context); | 
 |  | 
 |   BackForwardCacheImpl(const BackForwardCacheImpl&) = delete; | 
 |   BackForwardCacheImpl& operator=(const BackForwardCacheImpl&) = delete; | 
 |  | 
 |   ~BackForwardCacheImpl() override; | 
 |  | 
 |   // Returns where back/forward cache is allowed for pages with unload handlers. | 
 |   static bool IsUnloadAllowed(); | 
 |  | 
 |   // 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. | 
 |   // Note that the returned result will not include non-sticky features if the | 
 |   // browser has not received an IPC ACK from the renderer. See also the | 
 |   // comments for |RequestedFeatures|. If you always want to include non-sticky | 
 |   // features, use GetCompleteBackForwardCacheEligibilityForReporting() instead. | 
 |   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 and GetCompleteBackForwardCacheEligibilityForReporting() below, we | 
 |   // won't check for properties of |render_frame_host| that might change in the | 
 |   // future such as usage of certain APIs (non-sticky features), 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); | 
 |  | 
 |   // This will return all the reasons present at the point of calling that could | 
 |   // block back/forward cache, including both sticky and non-sticky features, | 
 |   // regardless of the IPC ack status (unlike | 
 |   // GetCurrentBackForwardCacheEligibility()). Note that non-sticky features | 
 |   // might get cleaned in pagehide handlers and might not block back/forward | 
 |   // cache, and this result will include them anyway. | 
 |   BackForwardCacheCanStoreDocumentResultWithTree | 
 |   GetCompleteBackForwardCacheEligibilityForReporting( | 
 |       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(); | 
 |  | 
 |   enum GetEntryFailureCase { | 
 |     // No matched BFCache entry is found. | 
 |     kEntryNotFound, | 
 |     // BFCache entry is found, but it was evicted before the `GetOrEvictEntry()` | 
 |     // call. | 
 |     kEntryEvictedBefore, | 
 |     // BFCache entry is found and not evicted, but it's no longer eligible for | 
 |     // BFCache, and gets evicted in the `GetOrEvictEntry()` call. | 
 |     kEntryIneligibleAndEvicted, | 
 |   }; | 
 |  | 
 |   // Returns a pointer to a cached BackForwardCache entry matching | 
 |   // `navigation_entry_id`. | 
 |   // Returns nullptr if no matching entry is found or if the entry is evicted. | 
 |   // If the returned entry is null, this method will also return a | 
 |   // `BackForwardCacheImpl::GetEntryResult`, which contains information about | 
 |   // whether it's because a matching entry was found or the entry was evicted. | 
 |  | 
 |   // 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. | 
 |  | 
 |   // WARNING: Calling this method may result in the eviction of the BFCache | 
 |   // entry if it is no longer eligible for the BFCache but has not been evicted | 
 |   // yet. If the eviction is triggered while there is an ongoing BFCache | 
 |   // restore, the caller must discard the NavigationRequest that is about to | 
 |   // commit the restore, otherwise the NavigationRequest may try to access the | 
 |   // RenderFrameHost after it has been deleted. | 
 |   base::expected<BackForwardCacheImpl::Entry*, | 
 |                  BackForwardCacheImpl::GetEntryFailureCase> | 
 |   GetOrEvictEntry(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(); | 
 |  | 
 |   // This enum indicates if the method is called from a "Cache-Control: | 
 |   // no-store" context, i.e. the page's same-origin main document has | 
 |   // "Cache-Control: no-store" header. | 
 |   enum CacheControlNoStoreContext { | 
 |     kInCCNSContext, | 
 |     kNotInCCNSContext, | 
 |   }; | 
 |  | 
 |   // 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. | 
 |   // The return value may vary depending on if the main frame of the cached page | 
 |   // has "Cache-Control: no-store" header. | 
 |   base::TimeDelta GetTimeToLiveInBackForwardCache( | 
 |       CacheControlNoStoreContext ccns_context); | 
 |  | 
 |   // Gets the maximum number of entries the BackForwardCache can hold per tab. | 
 |   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(); | 
 |   std::list<Entry*> GetEntriesForRenderViewHostImpl( | 
 |       const RenderViewHostImpl* rvhi) const; | 
 |  | 
 |   // BackForwardCache overrides: | 
 |   void Flush() override; | 
 |   void Flush(NotRestoredReason reason) override; | 
 |   size_t Prune(size_t limit, NotRestoredReason reason) override; | 
 |   void SetEmbedderSuppliedCacheSize( | 
 |       size_t embedder_supplied_cache_size) override; | 
 |   void SetEmbedderSuppliedTimeToLive( | 
 |       base::TimeDelta embedder_supplied_time_to_live) override; | 
 |   void DisableForTesting(DisableForTestingReason reason) override; | 
 |  | 
 |   // Evict all entries from the BackForwardCache that match the removal filter. | 
 |   void Flush( | 
 |       const StoragePartition::StorageKeyMatcherFunction& storage_key_filter); | 
 |  | 
 |   // Evict all entries from the BackForwardCache that were loaded with | 
 |   // "Cache-Control: no-store" header and match the removal filter. | 
 |   void FlushCacheControlNoStoreEntries( | 
 |       const StoragePartition::StorageKeyMatcherFunction& storage_key_filter); | 
 |  | 
 |   // RenderProcessHostInternalObserver methods | 
 |   void RenderProcessPriorityChanged(RenderProcessHostImpl* host) override; | 
 |  | 
 |   // Returns true if we are managing the cache size using foreground and | 
 |   // background limits (if finch parameter "foreground_cache_size" > 0). | 
 |   bool UsingForegroundBackgroundCacheSizeLimit(); | 
 |  | 
 |   // Returns true if one of the BFCache entries has a matching | 
 |   // RFH/RFPH/RVH with the same SIG ID/RVH ID. | 
 |   // TODO(crbug.com/354382462): Remove these once the bug is fixed. | 
 |   bool IsRenderFrameHostWithSIGInBackForwardCacheForDebugging( | 
 |       SiteInstanceGroupId site_instance_group_id); | 
 |   bool IsRenderFrameProxyHostWithSIGInBackForwardCacheForDebugging( | 
 |       SiteInstanceGroupId site_instance_group_id); | 
 |   bool IsRenderViewHostWithMapIdInBackForwardCacheForDebugging( | 
 |       const RenderViewHostImpl& rvh); | 
 |  | 
 |   bool IsRelatedSiteInstanceInBackForwardCacheForDebugging( | 
 |       SiteInstance& site_instance); | 
 |  | 
 |   // 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); | 
 |  | 
 |   bool should_allow_storing_pages_with_cache_control_no_store() { | 
 |     return should_allow_storing_pages_with_cache_control_no_store_; | 
 |   } | 
 |  | 
 |   // Returns true if there is a BFCached entry that sufficiently matches the | 
 |   // navigation that just committed in `committing_rfh` with initiator origin | 
 |   // `initiator_origin`, such that the entry could have been used (the URL, | 
 |   // origin, initiator origin, and security properties are the same, and if | 
 |   // `require_no_subframes` is used, has no subframes). This is | 
 |   // called in response to new non-reload/session-restore cross-document | 
 |   // navigation commits. | 
 |   bool HasPotentiallyMatchingEntry( | 
 |       const RenderFrameHostImpl& committing_rfh, | 
 |       const std::optional<url::Origin>& initiator_origin, | 
 |       bool require_no_subframes) const; | 
 |  | 
 |  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); | 
 |  | 
 |   // This enum indicates what features to include when recording | 
 |   // NotRestoredReasons. | 
 |   enum RequestedFeatures { | 
 |     // Report only sticky reasons. | 
 |     kOnlySticky, | 
 |     // If the entry has received an IPC ack from the renderer, report all the | 
 |     // reasons. Otherwise only include sticky features, because non-sticky | 
 |     // features might be removed by the renderer when the browser signals it is | 
 |     // about to put the page into BFCache. | 
 |     kAllIfAcked, | 
 |     // Regardless of the ack status, report all the reasons. | 
 |     kAll, | 
 |   }; | 
 |  | 
 |   // 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. | 
 |   // |requested_features| controls whether we include non-sticky reasons in the | 
 |   // result. | 
 |   BackForwardCacheCanStoreDocumentResultWithTree PopulateReasonsForPage( | 
 |       RenderFrameHostImpl* rfh, | 
 |       BackForwardCacheCanStoreDocumentResult& flattened_result, | 
 |       RequestedFeatures requested_features); | 
 |  | 
 |   // 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. | 
 |   size_t GetForegroundedEntriesCacheSize(); | 
 |  | 
 |   // Enforces a limit on the number of entries. Which entries are counted | 
 |   // towards the limit depends on the values of `reason`. | 
 |   // If it's `kForegroundCacheLimit`, it only considers entries that are | 
 |   // associated with a foregrounded process. Otherwise all entries are | 
 |   // considered. | 
 |   // If it's | 
 |   // `kCacheLimitPrunedOnModerateMemoryPressure` or | 
 |   // `kCacheLimitPrunedOnCriticalMemoryPressure`, it means the enforcement is | 
 |   // triggered by the `Prune()` method. | 
 |   // This method returns the number of entries in the BFCache. | 
 |   size_t EnforceCacheSizeLimitInternal( | 
 |       size_t limit, | 
 |       BackForwardCacheMetrics::NotRestoredReason reason); | 
 |  | 
 |   // 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); | 
 |  | 
 |   static BlockListedFeatures GetAllowedFeatures( | 
 |       RequestedFeatures requested_features, | 
 |       CacheControlNoStoreContext ccns_context); | 
 |  | 
 |   static BlockListedFeatures GetDisallowedFeatures( | 
 |       RequestedFeatures requested_features, | 
 |       CacheControlNoStoreContext ccns_context); | 
 |  | 
 |   // 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_; | 
 |   // The iterator pointing at the entry that was supposed to be evicted, but | 
 |   // since it's a prioritized entry, it will be specially kept in the entry | 
 |   // list. | 
 |   std::list<std::unique_ptr<Entry>>::iterator prioritized_entry_ = | 
 |       entries_.end(); | 
 |  | 
 |   // 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_; | 
 |  | 
 |   // Whether the BackForwardCache has been enabled for pages loaded with | 
 |   // "Cache-Control: no-store" header. | 
 |   bool should_allow_storing_pages_with_cache_control_no_store_; | 
 |  | 
 |   // Only used in tests. Whether the BackforwardCache 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 base::flat_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 base::flat_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 base::flat_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, | 
 |                              RequestedFeatures requested_features); | 
 |  | 
 |     // 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) {} | 
 |       const raw_ptr<RenderFrameHostImpl> rfh_to_be_evicted; | 
 |       raw_ptr<const BackForwardCacheCanStoreDocumentResult> reasons; | 
 |     }; | 
 |  | 
 |     NotRestoredReasonBuilder(RenderFrameHostImpl* root_rfh, | 
 |                              RequestedFeatures requested_features, | 
 |                              std::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, | 
 |         RequestedFeatures requested_features); | 
 |  | 
 |     // 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, | 
 |         RequestedFeatures requested_features); | 
 |  | 
 |    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_; | 
 |     // See |RequestedFeatures|. | 
 |     const RequestedFeatures requested_features_; | 
 |     // 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). | 
 |     std::optional<EvictionInfo> eviction_info_; | 
 |   }; | 
 |  | 
 |   std::optional<size_t> embedder_supplied_cache_size_; | 
 |   std::optional<base::TimeDelta> embedder_supplied_time_to_live_; | 
 |  | 
 |   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_; | 
 |   } | 
 |  | 
 |   // The blocking details map for this subtree's root document. | 
 |   const BackForwardCacheCanStoreDocumentResult::BlockingDetailsMap& | 
 |   GetBlockingDetailsMap() const { | 
 |     return document_result_.blocking_details_map(); | 
 |   } | 
 |  | 
 |   // Populate NotRestoredReasons mojom struct based on the existing tree of | 
 |   // reason to report to the renderer. | 
 |   // This should be called only when the root document is outermost main | 
 |   // document. | 
 |   // We have access to attributes of cross-origin iframes that are children of | 
 |   // same-origin iframes. This method's purpose is to ensure that we only return | 
 |   // the information that should be exposed based on origin. (i.e. we only | 
 |   // include information iframes that are direct children of same-origin | 
 |   // frames). | 
 |   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, CrossOriginAllMasked); | 
 |   FRIEND_TEST_ALL_PREFIXES(BackForwardCacheImplTestExposeCrossOrigin, | 
 |                            FirstCrossOriginReachable); | 
 |   FRIEND_TEST_ALL_PREFIXES(BackForwardCacheImplTestExposeCrossOrigin, | 
 |                            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. | 
 |   // TODO(crbug.com/41491384): Add "masked" when UA internal reasons such as | 
 |   // memory pressure and browsing instance not swapped are blocking as well. | 
 |   blink::mojom::BackForwardCacheNotRestoredReasonsPtr | 
 |   GetWebExposedNotRestoredReasonsInternal(int& index); | 
 |  | 
 |   // Returns if any cross-origin iframe in the tree is blocking and is not | 
 |   // a randomly selected iframe (i.e. does not have "masked" as its reason). | 
 |   // If this is true, we need to add "masked" to main frame's reasons. | 
 |   // |index| is the random index of the cross-origin iframe that we decided to | 
 |   // report from all the reachable cross-origin iframes. | 
 |   bool HasUnexposedCrossOriginBlockingIframe(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_; | 
 |   // Whether or not the root document of this tree is the outermoust main | 
 |   // frame's document. | 
 |   const bool is_root_outermost_main_frame_; | 
 |   // The id, name and src attribute of the frame owner of this subtree's root | 
 |   // document. | 
 |   const std::optional<std::string> id_; | 
 |   const std::optional<std::string> name_; | 
 |   const std::optional<std::string> src_; | 
 |   // See |GetUrl| | 
 |   const GURL url_; | 
 | }; | 
 |  | 
 | }  // namespace content | 
 |  | 
 | #endif  // CONTENT_BROWSER_RENDERER_HOST_BACK_FORWARD_CACHE_IMPL_H_ |