Avi Drissman | 4e1b7bc3 | 2022-09-15 14:03:50 | [diff] [blame] | 1 | // Copyright 2013 The Chromium Authors |
danakj | c492bf8 | 2020-09-09 20:02:44 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | #ifndef CONTENT_BROWSER_RENDERER_HOST_NAVIGATION_CONTROLLER_IMPL_H_ |
| 6 | #define CONTENT_BROWSER_RENDERER_HOST_NAVIGATION_CONTROLLER_IMPL_H_ |
| 7 | |
| 8 | #include <stddef.h> |
| 9 | #include <stdint.h> |
| 10 | |
| 11 | #include <memory> |
Arthur Sonzogni | c686e8f | 2024-01-11 08:36:37 | [diff] [blame] | 12 | #include <optional> |
danakj | c492bf8 | 2020-09-09 20:02:44 | [diff] [blame] | 13 | #include <set> |
| 14 | #include <string> |
| 15 | #include <vector> |
| 16 | |
Avi Drissman | adac2199 | 2023-01-11 23:46:39 | [diff] [blame] | 17 | #include "base/functional/callback.h" |
danakj | c492bf8 | 2020-09-09 20:02:44 | [diff] [blame] | 18 | #include "base/gtest_prod_util.h" |
Keishi Hattori | 0e45c02 | 2021-11-27 09:25:52 | [diff] [blame] | 19 | #include "base/memory/raw_ptr.h" |
Ali Hijazi | d87307d | 2022-11-07 20:15:03 | [diff] [blame] | 20 | #include "base/memory/raw_ref.h" |
danakj | c492bf8 | 2020-09-09 20:02:44 | [diff] [blame] | 21 | #include "base/memory/weak_ptr.h" |
danakj | c492bf8 | 2020-09-09 20:02:44 | [diff] [blame] | 22 | #include "base/time/time.h" |
| 23 | #include "build/build_config.h" |
| 24 | #include "content/browser/renderer_host/back_forward_cache_impl.h" |
| 25 | #include "content/browser/renderer_host/navigation_controller_delegate.h" |
| 26 | #include "content/browser/renderer_host/navigation_entry_impl.h" |
Miyoung Shin | 3299cbf | 2022-11-22 01:41:10 | [diff] [blame] | 27 | #include "content/browser/renderer_host/navigation_type.h" |
danakj | c492bf8 | 2020-09-09 20:02:44 | [diff] [blame] | 28 | #include "content/browser/ssl/ssl_manager.h" |
Lei Zhang | 7ab31375 | 2021-11-17 01:26:00 | [diff] [blame] | 29 | #include "content/common/content_export.h" |
arthursonzogni | 73fe321 | 2020-11-17 13:24:07 | [diff] [blame] | 30 | #include "content/common/navigation_client.mojom-forward.h" |
danakj | c492bf8 | 2020-09-09 20:02:44 | [diff] [blame] | 31 | #include "content/public/browser/navigation_controller.h" |
danakj | c492bf8 | 2020-09-09 20:02:44 | [diff] [blame] | 32 | #include "content/public/browser/reload_type.h" |
| 33 | #include "mojo/public/cpp/bindings/pending_associated_remote.h" |
W. James MacLean | 443ef3e | 2024-07-16 13:42:34 | [diff] [blame] | 34 | #include "net/storage_access_api/status.h" |
Antonio Sartori | 2f763d9d | 2021-04-21 10:04:14 | [diff] [blame] | 35 | #include "services/network/public/mojom/source_location.mojom-forward.h" |
Yoav Weiss | 8c57395 | 2022-11-17 17:35:13 | [diff] [blame] | 36 | #include "third_party/blink/public/common/scheduler/task_attribution_id.h" |
Chris Hamilton | 83272dc | 2021-02-23 00:24:02 | [diff] [blame] | 37 | #include "third_party/blink/public/common/tokens/tokens.h" |
Domenic Denicola | cd30f5f8 | 2022-03-16 21:48:01 | [diff] [blame] | 38 | #include "third_party/blink/public/mojom/navigation/navigation_api_history_entry_arrays.mojom-forward.h" |
Yao Xiao | 720ef9d6 | 2022-12-09 05:18:29 | [diff] [blame] | 39 | #include "third_party/blink/public/mojom/navigation/navigation_initiator_activation_and_ad_status.mojom.h" |
Minggang Wang | b9f3fa9 | 2021-07-01 15:30:31 | [diff] [blame] | 40 | #include "third_party/blink/public/mojom/navigation/navigation_params.mojom-forward.h" |
| 41 | |
| 42 | namespace blink { |
| 43 | struct NavigationDownloadPolicy; |
| 44 | } // namespace blink |
danakj | c492bf8 | 2020-09-09 20:02:44 | [diff] [blame] | 45 | |
danakj | c492bf8 | 2020-09-09 20:02:44 | [diff] [blame] | 46 | namespace content { |
Carlos Caballero | 40b0efd | 2021-01-26 11:55:00 | [diff] [blame] | 47 | class FrameTree; |
danakj | c492bf8 | 2020-09-09 20:02:44 | [diff] [blame] | 48 | class FrameTreeNode; |
William Liu | 055a354 | 2023-04-02 17:21:19 | [diff] [blame] | 49 | class NavigationEntryScreenshotCache; |
danakj | c492bf8 | 2020-09-09 20:02:44 | [diff] [blame] | 50 | class NavigationRequest; |
| 51 | class RenderFrameHostImpl; |
| 52 | class SiteInstance; |
| 53 | struct LoadCommittedDetails; |
| 54 | |
Matt Falkenhagen | 91a8043 | 2021-07-05 03:32:44 | [diff] [blame] | 55 | // NavigationControllerImpl is 1:1 with FrameTree. See comments on the base |
| 56 | // class. |
danakj | c492bf8 | 2020-09-09 20:02:44 | [diff] [blame] | 57 | class CONTENT_EXPORT NavigationControllerImpl : public NavigationController { |
| 58 | public: |
| 59 | // This tracks one NavigationRequest navigating to a pending NavigationEntry. |
| 60 | // In some cases, several NavigationRequests are referencing the same pending |
| 61 | // NavigationEntry. For instance: |
| 62 | // - A reload requested while a reload is already in progress. |
| 63 | // - An history navigation causing several subframes to navigate. |
| 64 | // |
| 65 | // When no NavigationRequests are referencing the pending NavigationEntry |
| 66 | // anymore, it should be discarded to avoid a URL spoof. |
| 67 | // |
| 68 | // The deletion is not always immediate, because it is not possible to delete |
| 69 | // the entry while requesting a navigation to it at the same time. In this |
| 70 | // case, the deletion happens later, when returning from the function. |
| 71 | // |
| 72 | // If the pending NavigationEntry is discarded before the PendingEntryRef(s), |
| 73 | // then removing the last associated PendingEntryRef is a no-op. It is a no-op |
| 74 | // forever, even if the entry becomes the pending NavigationEntry again in the |
| 75 | // meantime. Rather than track the NavigationRequest or pending entry |
| 76 | // explicitly, this ref class simply goes into a set that gets cleared with |
| 77 | // each change to the pending entry |
| 78 | class PendingEntryRef { |
| 79 | public: |
| 80 | explicit PendingEntryRef( |
| 81 | base::WeakPtr<NavigationControllerImpl> controller); |
Peter Boström | 828b902 | 2021-09-21 02:28:43 | [diff] [blame] | 82 | |
| 83 | PendingEntryRef(const PendingEntryRef&) = delete; |
| 84 | PendingEntryRef& operator=(const PendingEntryRef&) = delete; |
| 85 | |
danakj | c492bf8 | 2020-09-09 20:02:44 | [diff] [blame] | 86 | ~PendingEntryRef(); |
| 87 | |
| 88 | private: |
| 89 | base::WeakPtr<NavigationControllerImpl> controller_; |
danakj | c492bf8 | 2020-09-09 20:02:44 | [diff] [blame] | 90 | }; |
| 91 | |
Carlos Caballero | 40b0efd | 2021-01-26 11:55:00 | [diff] [blame] | 92 | NavigationControllerImpl(BrowserContext* browser_context, |
| 93 | FrameTree& frame_tree, |
| 94 | NavigationControllerDelegate* delegate); |
Peter Boström | 9b03653 | 2021-10-28 23:37:28 | [diff] [blame] | 95 | |
| 96 | NavigationControllerImpl(const NavigationControllerImpl&) = delete; |
| 97 | NavigationControllerImpl& operator=(const NavigationControllerImpl&) = delete; |
| 98 | |
danakj | c492bf8 | 2020-09-09 20:02:44 | [diff] [blame] | 99 | ~NavigationControllerImpl() override; |
| 100 | |
| 101 | // NavigationController implementation: |
danakj | c492bf8 | 2020-09-09 20:02:44 | [diff] [blame] | 102 | BrowserContext* GetBrowserContext() override; |
| 103 | void Restore(int selected_navigation, |
| 104 | RestoreType type, |
| 105 | std::vector<std::unique_ptr<NavigationEntry>>* entries) override; |
| 106 | NavigationEntryImpl* GetActiveEntry() override; |
| 107 | NavigationEntryImpl* GetVisibleEntry() override; |
| 108 | int GetCurrentEntryIndex() override; |
| 109 | NavigationEntryImpl* GetLastCommittedEntry() override; |
Elad Alon | 32044f53 | 2025-03-04 22:16:03 | [diff] [blame] | 110 | const NavigationEntryImpl* GetLastCommittedEntry() const override; |
danakj | c492bf8 | 2020-09-09 20:02:44 | [diff] [blame] | 111 | int GetLastCommittedEntryIndex() override; |
| 112 | bool CanViewSource() override; |
| 113 | int GetEntryCount() override; |
| 114 | NavigationEntryImpl* GetEntryAtIndex(int index) override; |
| 115 | NavigationEntryImpl* GetEntryAtOffset(int offset) override; |
| 116 | void DiscardNonCommittedEntries() override; |
| 117 | NavigationEntryImpl* GetPendingEntry() override; |
| 118 | int GetPendingEntryIndex() override; |
Harkiran Bolaria | ba823e4 | 2021-05-21 18:30:36 | [diff] [blame] | 119 | base::WeakPtr<NavigationHandle> LoadURL( |
| 120 | const GURL& url, |
| 121 | const Referrer& referrer, |
| 122 | ui::PageTransition type, |
| 123 | const std::string& extra_headers) override; |
| 124 | base::WeakPtr<NavigationHandle> LoadURLWithParams( |
| 125 | const LoadURLParams& params) override; |
danakj | c492bf8 | 2020-09-09 20:02:44 | [diff] [blame] | 126 | void LoadIfNecessary() override; |
Charlie Reis | 4c53a96 | 2023-06-21 23:17:53 | [diff] [blame] | 127 | void LoadOriginalRequestURL() override; |
Kevin McNee | ccca617 | 2021-10-19 17:11:14 | [diff] [blame] | 128 | base::WeakPtr<NavigationHandle> LoadPostCommitErrorPage( |
| 129 | RenderFrameHost* render_frame_host, |
| 130 | const GURL& url, |
Lei Zhang | a477083 | 2023-07-19 18:02:36 | [diff] [blame] | 131 | const std::string& error_page_html) override; |
Xiaochen Zhou | 9088e64 | 2025-07-07 15:08:10 | [diff] [blame] | 132 | void NavigateFrameToErrorPage(RenderFrameHost* render_frame_host, |
| 133 | const GURL& url, |
| 134 | const std::string& error_page_html) override; |
danakj | c492bf8 | 2020-09-09 20:02:44 | [diff] [blame] | 135 | bool CanGoBack() override; |
| 136 | bool CanGoForward() override; |
| 137 | bool CanGoToOffset(int offset) override; |
Andrew Verge | 9a71fa2 | 2025-08-21 18:43:16 | [diff] [blame] | 138 | bool ShouldEnableBackButton() override; |
| 139 | bool ShouldEnableForwardButton() override; |
David Bokan | b8e0df0 | 2025-05-14 22:03:48 | [diff] [blame] | 140 | WeakNavigationHandleVector GoBack() override; |
| 141 | WeakNavigationHandleVector GoForward() override; |
| 142 | WeakNavigationHandleVector GoToIndex(int index) override; |
danakj | c492bf8 | 2020-09-09 20:02:44 | [diff] [blame] | 143 | void GoToOffset(int offset) override; |
| 144 | bool RemoveEntryAtIndex(int index) override; |
| 145 | void PruneForwardEntries() override; |
| 146 | const SessionStorageNamespaceMap& GetSessionStorageNamespaceMap() override; |
| 147 | SessionStorageNamespace* GetDefaultSessionStorageNamespace() override; |
| 148 | bool NeedsReload() override; |
| 149 | void SetNeedsReload() override; |
| 150 | void CancelPendingReload() override; |
| 151 | void ContinuePendingReload() override; |
| 152 | bool IsInitialNavigation() override; |
| 153 | bool IsInitialBlankNavigation() override; |
| 154 | void Reload(ReloadType reload_type, bool check_for_repost) override; |
| 155 | void NotifyEntryChanged(NavigationEntry* entry) override; |
| 156 | void CopyStateFrom(NavigationController* source, bool needs_reload) override; |
danakj | c492bf8 | 2020-09-09 20:02:44 | [diff] [blame] | 157 | bool CanPruneAllButLastCommitted() override; |
| 158 | void PruneAllButLastCommitted() override; |
| 159 | void DeleteNavigationEntries( |
| 160 | const DeletionPredicate& deletionPredicate) override; |
danakj | c492bf8 | 2020-09-09 20:02:44 | [diff] [blame] | 161 | BackForwardCacheImpl& GetBackForwardCache() override; |
| 162 | |
Rakina Zata Amni | a4e2722 | 2021-12-22 01:05:00 | [diff] [blame] | 163 | // Discards the pending entry if any. If this is caused by a navigation |
| 164 | // committing a new entry, `commit_details` will contain the committed |
| 165 | // navigation's details. |
| 166 | void DiscardNonCommittedEntriesWithCommitDetails( |
| 167 | LoadCommittedDetails* commit_details); |
| 168 | |
Rakina Zata Amni | afd3c658 | 2021-11-30 06:19:17 | [diff] [blame] | 169 | // Creates the initial NavigationEntry for the NavigationController when its |
| 170 | // FrameTree is being initialized. See NavigationEntry::IsInitialEntry() on |
| 171 | // what this means. |
| 172 | void CreateInitialEntry(); |
| 173 | |
William Liu | 055a354 | 2023-04-02 17:21:19 | [diff] [blame] | 174 | // Gets the `NavigationEntryScreenshotCache` for this `NavigationController`. |
| 175 | // Due to MPArch there can be multiple `FrameTree`s within a single tab. This |
| 176 | // should only be called for the primary FrameTree. This cache is |
| 177 | // lazy-initialized when this method is first called. |
| 178 | NavigationEntryScreenshotCache* GetNavigationEntryScreenshotCache(); |
| 179 | |
danakj | c492bf8 | 2020-09-09 20:02:44 | [diff] [blame] | 180 | // Starts a navigation in a newly created subframe as part of a history |
| 181 | // navigation. Returns true if the history navigation could start, false |
| 182 | // otherwise. If this returns false, the caller should do a regular |
| 183 | // navigation to the default src URL for the frame instead. |
| 184 | bool StartHistoryNavigationInNewSubframe( |
| 185 | RenderFrameHostImpl* render_frame_host, |
Hiroshige Hayashizaki | 5466bfe8 | 2023-05-17 00:34:33 | [diff] [blame] | 186 | mojo::PendingAssociatedRemote<mojom::NavigationClient>* navigation_client, |
| 187 | blink::LocalFrameToken initiator_frame_token, |
Charlie Reis | f4d51f40 | 2025-05-23 18:00:49 | [diff] [blame] | 188 | int initiator_process_id, |
| 189 | base::TimeTicks actual_navigation_start); |
danakj | c492bf8 | 2020-09-09 20:02:44 | [diff] [blame] | 190 | |
| 191 | // Reloads the |frame_tree_node| and returns true. In some rare cases, there |
| 192 | // is no history related to the frame, nothing happens and this returns false. |
| 193 | bool ReloadFrame(FrameTreeNode* frame_tree_node); |
| 194 | |
Nate Chapin | 45f62058 | 2021-09-30 17:45:43 | [diff] [blame] | 195 | // Navigates to the specified offset from the "current entry" and marks the |
| 196 | // navigations as initiated by the renderer. |
Nate Chapin | bf682fa3 | 2022-09-26 22:41:20 | [diff] [blame] | 197 | // |initiator_rfh| is the frame that requested the navigation. |
Yoav Weiss | a7449c3b | 2022-11-22 15:15:14 | [diff] [blame] | 198 | // |soft_navigation_heuristics_task_id| is the task in the renderer that |
Yoav Weiss | 8c57395 | 2022-11-17 17:35:13 | [diff] [blame] | 199 | // initiated this call (if any). |
Charlie Reis | f4d51f40 | 2025-05-23 18:00:49 | [diff] [blame] | 200 | // |actual_navigation_start| is the time the navigation began, for metrics. |
Arthur Sonzogni | c686e8f | 2024-01-11 08:36:37 | [diff] [blame] | 201 | void GoToOffsetFromRenderer(int offset, |
| 202 | RenderFrameHostImpl* initiator_rfh, |
| 203 | std::optional<blink::scheduler::TaskAttributionId> |
Charlie Reis | f4d51f40 | 2025-05-23 18:00:49 | [diff] [blame] | 204 | soft_navigation_heuristics_task_id, |
| 205 | base::TimeTicks actual_navigation_start); |
Nate Chapin | 45f62058 | 2021-09-30 17:45:43 | [diff] [blame] | 206 | |
William Liu | 62ae26c | 2024-08-08 14:28:16 | [diff] [blame] | 207 | // A variation of `NavigationController::GoToIndex()`, that also returns all |
| 208 | // the created `NavigationRequest`s. If no navigation request is created, the |
| 209 | // vector is empty. |
| 210 | std::vector<base::WeakPtr<NavigationRequest>> GoToIndexAndReturnAllRequests( |
William Liu | ec04e38 | 2024-05-23 18:03:27 | [diff] [blame] | 211 | int index); |
| 212 | |
Xiaohan Wang | 7f8052e0 | 2022-01-14 18:44:28 | [diff] [blame] | 213 | #if BUILDFLAG(IS_ANDROID) |
Nate Chapin | 45f62058 | 2021-09-30 17:45:43 | [diff] [blame] | 214 | // The difference between (Can)GoToOffsetWithSkipping and |
| 215 | // (Can)GoToOffset/(Can)GoToOffsetInSandboxedFrame is that this respects the |
| 216 | // history manipulation intervention and will exclude skippable entries. |
| 217 | // These should only be used for browser-initiated navigaitons. |
WangHui | 74286d5 | 2021-03-31 16:17:15 | [diff] [blame] | 218 | bool CanGoToOffsetWithSkipping(int offset); |
| 219 | void GoToOffsetWithSkipping(int offset); |
| 220 | #endif |
danakj | c492bf8 | 2020-09-09 20:02:44 | [diff] [blame] | 221 | |
| 222 | // Called when a document requests a navigation through a |
| 223 | // RenderFrameProxyHost. |
| 224 | void NavigateFromFrameProxy( |
| 225 | RenderFrameHostImpl* render_frame_host, |
| 226 | const GURL& url, |
Chris Hamilton | 83272dc | 2021-02-23 00:24:02 | [diff] [blame] | 227 | const blink::LocalFrameToken* initiator_frame_token, |
Antonio Sartori | 9a82f6f3 | 2020-12-14 09:22:45 | [diff] [blame] | 228 | int initiator_process_id, |
Arthur Sonzogni | c686e8f | 2024-01-11 08:36:37 | [diff] [blame] | 229 | const std::optional<url::Origin>& initiator_origin, |
| 230 | const std::optional<GURL>& initiator_base_url, |
danakj | c492bf8 | 2020-09-09 20:02:44 | [diff] [blame] | 231 | bool is_renderer_initiated, |
| 232 | SiteInstance* source_site_instance, |
| 233 | const Referrer& referrer, |
| 234 | ui::PageTransition page_transition, |
| 235 | bool should_replace_current_entry, |
Yeunjoo Choi | 3df791a | 2021-02-17 07:07:25 | [diff] [blame] | 236 | blink::NavigationDownloadPolicy download_policy, |
danakj | c492bf8 | 2020-09-09 20:02:44 | [diff] [blame] | 237 | const std::string& method, |
| 238 | scoped_refptr<network::ResourceRequestBody> post_body, |
| 239 | const std::string& extra_headers, |
Antonio Sartori | 2f763d9d | 2021-04-21 10:04:14 | [diff] [blame] | 240 | network::mojom::SourceLocationPtr source_location, |
danakj | c492bf8 | 2020-09-09 20:02:44 | [diff] [blame] | 241 | scoped_refptr<network::SharedURLLoaderFactory> blob_url_loader_factory, |
jongdeok.kim | 5de823b3 | 2022-06-14 04:37:50 | [diff] [blame] | 242 | bool is_form_submission, |
Arthur Sonzogni | c686e8f | 2024-01-11 08:36:37 | [diff] [blame] | 243 | const std::optional<blink::Impression>& impression, |
Yao Xiao | 720ef9d6 | 2022-12-09 05:18:29 | [diff] [blame] | 244 | blink::mojom::NavigationInitiatorActivationAndAdStatus |
| 245 | initiator_activation_and_ad_status, |
Charlie Reis | e1d9b818 | 2025-04-02 04:32:12 | [diff] [blame] | 246 | base::TimeTicks actual_navigation_start_time, |
Nan Lin | 944e9b4e | 2022-04-12 13:51:22 | [diff] [blame] | 247 | base::TimeTicks navigation_start_time, |
Garrett Tanzer | 405f340 | 2022-07-21 20:12:49 | [diff] [blame] | 248 | bool is_embedder_initiated_fenced_frame_navigation = false, |
Garrett Tanzer | bb8db41 | 2022-09-27 21:59:46 | [diff] [blame] | 249 | bool is_unfenced_top_navigation = false, |
Sergey Poromov | dd557c1 | 2023-03-01 11:28:45 | [diff] [blame] | 250 | bool force_new_browsing_instance = false, |
Camillia Smith Barnes | 6a64396 | 2023-03-03 00:28:58 | [diff] [blame] | 251 | bool is_container_initiated = false, |
Kevin McNee | 6455638a | 2024-06-27 22:05:03 | [diff] [blame] | 252 | bool has_rel_opener = false, |
W. James MacLean | 443ef3e | 2024-07-16 13:42:34 | [diff] [blame] | 253 | net::StorageAccessApiStatus storage_access_api_status = |
| 254 | net::StorageAccessApiStatus::kNone, |
Arthur Sonzogni | c686e8f | 2024-01-11 08:36:37 | [diff] [blame] | 255 | std::optional<std::u16string> embedder_shared_storage_context = |
| 256 | std::nullopt); |
danakj | c492bf8 | 2020-09-09 20:02:44 | [diff] [blame] | 257 | |
Domenic Denicola | cc094fb | 2022-03-16 23:40:57 | [diff] [blame] | 258 | // Navigates to the history entry associated with the given navigation API |
| 259 | // |key|. Searches |entries_| for a FrameNavigationEntry associated with |
Nate Chapin | bf682fa3 | 2022-09-26 22:41:20 | [diff] [blame] | 260 | // |initiator_rfh|'s FrameTreeNode that has |key| as its navigation API key. |
| 261 | // Searches back from the current index, then forward, so if there are |
| 262 | // multiple entries with the same key, the nearest to current should be |
| 263 | // selected. Stops searching in the current direction if it finds a |
| 264 | // NavigationEntry without a FrameNavigationEntry for |initiator_rfh|'s |
| 265 | // FrameTreeNode, or if the FrameNavigationEntry doesn't match origin or site |
| 266 | // instance. |
Nate Chapin | fbfe5af | 2021-06-10 17:22:08 | [diff] [blame] | 267 | // |
| 268 | // If no matching entry is found, the navigation is dropped. The renderer |
| 269 | // should only send the navigation to the browser if it believes the entry is |
| 270 | // in |entries_|, but it might be wrong (if the entry was dropped from |
| 271 | // |entries_|, or due to a race condition) or compromised. |
| 272 | // If a matching entry is found, navigate to that entry and proceed like any |
| 273 | // other history navigation. |
Yoav Weiss | a7449c3b | 2022-11-22 15:15:14 | [diff] [blame] | 274 | // |soft_navigation_heuristics_task_id|: The task in the renderer that |
| 275 | // initiated this call (if any). |
Charlie Reis | f4d51f40 | 2025-05-23 18:00:49 | [diff] [blame] | 276 | // |actual_navigation_start| is the time the navigation began, for metrics. |
Yoav Weiss | a7449c3b | 2022-11-22 15:15:14 | [diff] [blame] | 277 | void NavigateToNavigationApiKey( |
| 278 | RenderFrameHostImpl* initiator_rfh, |
Arthur Sonzogni | c686e8f | 2024-01-11 08:36:37 | [diff] [blame] | 279 | std::optional<blink::scheduler::TaskAttributionId> |
Yoav Weiss | a7449c3b | 2022-11-22 15:15:14 | [diff] [blame] | 280 | soft_navigation_heuristics_task_id, |
Charlie Reis | f4d51f40 | 2025-05-23 18:00:49 | [diff] [blame] | 281 | const std::string& key, |
| 282 | base::TimeTicks actual_navigation_start); |
Nate Chapin | fbfe5af | 2021-06-10 17:22:08 | [diff] [blame] | 283 | |
danakj | c492bf8 | 2020-09-09 20:02:44 | [diff] [blame] | 284 | // Whether this is the initial navigation in an unmodified new tab. In this |
| 285 | // case, we know there is no content displayed in the page. |
| 286 | bool IsUnmodifiedBlankTab(); |
| 287 | |
Dave Tapuska | 2cf1f53 | 2022-08-10 15:30:49 | [diff] [blame] | 288 | // The session storage namespace that all child `blink::WebView`s associated |
| 289 | // with `partition_config` should use. |
Aaron Colwell | 78b4bde | 2021-03-16 16:16:09 | [diff] [blame] | 290 | SessionStorageNamespace* GetSessionStorageNamespace( |
Alex Moshchuk | 8015afcf | 2022-01-31 22:59:25 | [diff] [blame] | 291 | const StoragePartitionConfig& partition_config); |
danakj | c492bf8 | 2020-09-09 20:02:44 | [diff] [blame] | 292 | |
| 293 | // Returns the index of the specified entry, or -1 if entry is not contained |
| 294 | // in this NavigationController. |
| 295 | int GetIndexOfEntry(const NavigationEntryImpl* entry) const; |
| 296 | |
| 297 | // Return the index of the entry with the given unique id, or -1 if not found. |
| 298 | int GetEntryIndexWithUniqueID(int nav_entry_id) const; |
| 299 | |
Kevin McNee | 3b3a5619 | 2023-03-17 14:40:59 | [diff] [blame] | 300 | // Returns the index that would be used by `GoBack`. This respects skippable |
| 301 | // entries. Returns nullopt if no unskippable back entry exists. |
Arthur Sonzogni | c686e8f | 2024-01-11 08:36:37 | [diff] [blame] | 302 | std::optional<int> GetIndexForGoBack(); |
Kevin McNee | 3b3a5619 | 2023-03-17 14:40:59 | [diff] [blame] | 303 | // Returns the index that would be used by `GoForward`. This respects |
| 304 | // skippable entries. Returns nullopt if no forward entry exists. |
Arthur Sonzogni | c686e8f | 2024-01-11 08:36:37 | [diff] [blame] | 305 | std::optional<int> GetIndexForGoForward(); |
Kevin McNee | 3b3a5619 | 2023-03-17 14:40:59 | [diff] [blame] | 306 | |
danakj | c492bf8 | 2020-09-09 20:02:44 | [diff] [blame] | 307 | // Return the entry with the given unique id, or null if not found. |
| 308 | NavigationEntryImpl* GetEntryWithUniqueID(int nav_entry_id) const; |
Adithya Srinivasan | 9b0c99c | 2021-08-10 15:19:45 | [diff] [blame] | 309 | // Same as above method, but also includes the pending entry in the search |
| 310 | // space. |
| 311 | NavigationEntryImpl* GetEntryWithUniqueIDIncludingPending( |
| 312 | int nav_entry_id) const; |
danakj | c492bf8 | 2020-09-09 20:02:44 | [diff] [blame] | 313 | |
| 314 | NavigationControllerDelegate* delegate() const { return delegate_; } |
| 315 | |
| 316 | // These values are persisted to logs. Entries should not be renumbered and |
| 317 | // numeric values should never be reused. |
| 318 | enum class NeedsReloadType { |
| 319 | kRequestedByClient = 0, |
| 320 | kRestoreSession = 1, |
| 321 | kCopyStateFrom = 2, |
| 322 | kCrashedSubframe = 3, |
| 323 | kMaxValue = kCrashedSubframe |
| 324 | }; |
| 325 | |
| 326 | // Request a reload to happen when activated. Same as the public |
| 327 | // SetNeedsReload(), but takes in a |type| which specifies why the reload is |
| 328 | // being requested. |
| 329 | void SetNeedsReload(NeedsReloadType type); |
| 330 | |
danakj | c492bf8 | 2020-09-09 20:02:44 | [diff] [blame] | 331 | // For use by WebContentsImpl ------------------------------------------------ |
| 332 | |
Alex Moshchuk | e26f2d8 | 2021-07-21 23:21:00 | [diff] [blame] | 333 | // Visit all FrameNavigationEntries as well as all frame trees and register |
W. James MacLean | c07dc41b | 2022-07-25 18:52:16 | [diff] [blame] | 334 | // any instances of |origin| as having the default isolation state with their |
| 335 | // respective BrowsingInstances. This is important when |origin| is seen with |
| 336 | // an OriginAgentCluster header, so that we only accept such requests in |
| 337 | // BrowsingInstances that haven't seen it before. |
| 338 | void RegisterExistingOriginAsHavingDefaultIsolation( |
| 339 | const url::Origin& origin); |
danakj | c492bf8 | 2020-09-09 20:02:44 | [diff] [blame] | 340 | |
| 341 | // Allow renderer-initiated navigations to create a pending entry when the |
| 342 | // provisional load starts. |
| 343 | void SetPendingEntry(std::unique_ptr<NavigationEntryImpl> entry); |
| 344 | |
| 345 | // Handles updating the navigation state after the renderer has navigated. |
| 346 | // This is used by the WebContentsImpl. |
| 347 | // |
| 348 | // If a new entry is created, it will return true and will have filled the |
| 349 | // given details structure and broadcast the NOTIFY_NAV_ENTRY_COMMITTED |
| 350 | // notification. The caller can then use the details without worrying about |
| 351 | // listening for the notification. |
| 352 | // |
| 353 | // In the case that nothing has changed, the details structure is undefined |
| 354 | // and it will return false. |
| 355 | // |
Nate Chapin | c7019dd7d | 2021-06-25 18:29:25 | [diff] [blame] | 356 | // |was_on_initial_empty_document| indicates whether the document being |
| 357 | // navigated away from was an initial empty document. |
| 358 | // |
Shivani Sharma | eef521b | 2024-01-18 13:03:56 | [diff] [blame] | 359 | // |previous_document_had_history_intervention_activation| is true if the |
| 360 | // previous document had a user activation that is being honored for the |
| 361 | // history manipulation intervention (i.e., a new user activation is needed |
| 362 | // after same-document back/forward navigations). |
| 363 | // See RFHI::honor_sticky_activation_for_history_intervention_ for details. |
| 364 | // This is used for a new renderer-initiated navigation to decide if the page |
| 365 | // that initiated the navigation should be skipped on back/forward button. |
| 366 | bool RendererDidNavigate( |
| 367 | RenderFrameHostImpl* rfh, |
| 368 | const mojom::DidCommitProvisionalLoadParams& params, |
| 369 | LoadCommittedDetails* details, |
| 370 | bool is_same_document_navigation, |
| 371 | bool was_on_initial_empty_document, |
| 372 | bool previous_document_had_history_intervention_activation, |
| 373 | NavigationRequest* navigation_request); |
danakj | c492bf8 | 2020-09-09 20:02:44 | [diff] [blame] | 374 | |
| 375 | // Notifies us that we just became active. This is used by the WebContentsImpl |
| 376 | // so that we know to load URLs that were pending as "lazy" loads. |
| 377 | void SetActive(bool is_active); |
| 378 | |
Alex Moshchuk | 8015afcf | 2022-01-31 22:59:25 | [diff] [blame] | 379 | // Sets the SessionStorageNamespace for the given |partition_config|. This is |
danakj | c492bf8 | 2020-09-09 20:02:44 | [diff] [blame] | 380 | // used during initialization of a new NavigationController to allow |
| 381 | // pre-population of the SessionStorageNamespace objects. Session restore, |
danakj | f26536bf | 2020-09-10 00:46:13 | [diff] [blame] | 382 | // prerendering, and the implementation of window.open() are the primary users |
danakj | c492bf8 | 2020-09-09 20:02:44 | [diff] [blame] | 383 | // of this API. |
| 384 | // |
| 385 | // Calling this function when a SessionStorageNamespace has already been |
| 386 | // associated with a |partition_id| will CHECK() fail. |
| 387 | void SetSessionStorageNamespace( |
Alex Moshchuk | 8015afcf | 2022-01-31 22:59:25 | [diff] [blame] | 388 | const StoragePartitionConfig& partition_config, |
danakj | c492bf8 | 2020-09-09 20:02:44 | [diff] [blame] | 389 | SessionStorageNamespace* session_storage_namespace); |
| 390 | |
| 391 | // Random data --------------------------------------------------------------- |
| 392 | |
Ali Hijazi | d87307d | 2022-11-07 20:15:03 | [diff] [blame] | 393 | FrameTree& frame_tree() { return *frame_tree_; } |
Carlos Caballero | ede6f8c | 2021-01-28 11:01:50 | [diff] [blame] | 394 | |
danakj | c492bf8 | 2020-09-09 20:02:44 | [diff] [blame] | 395 | SSLManager* ssl_manager() { return &ssl_manager_; } |
| 396 | |
| 397 | // Maximum number of entries before we start removing entries from the front. |
| 398 | static void set_max_entry_count_for_testing(size_t max_entry_count) { |
| 399 | max_entry_count_for_testing_ = max_entry_count; |
| 400 | } |
| 401 | static size_t max_entry_count(); |
| 402 | |
| 403 | void SetGetTimestampCallbackForTest( |
| 404 | const base::RepeatingCallback<base::Time()>& get_timestamp_callback); |
| 405 | |
| 406 | // Discards only the pending entry. |was_failure| should be set if the pending |
| 407 | // entry is being discarded because it failed to load. |
| 408 | void DiscardPendingEntry(bool was_failure); |
| 409 | |
| 410 | // Sets a flag on the pending NavigationEntryImpl instance if any that the |
| 411 | // navigation failed due to an SSL error. |
| 412 | void SetPendingNavigationSSLError(bool error); |
| 413 | |
| 414 | // Returns true if the string corresponds to a valid data URL, false |
| 415 | // otherwise. |
Xiaohan Wang | 7f8052e0 | 2022-01-14 18:44:28 | [diff] [blame] | 416 | #if BUILDFLAG(IS_ANDROID) |
danakj | c492bf8 | 2020-09-09 20:02:44 | [diff] [blame] | 417 | static bool ValidateDataURLAsString( |
| 418 | const scoped_refptr<const base::RefCountedString>& data_url_as_string); |
| 419 | #endif |
| 420 | |
| 421 | // Invoked when a user activation occurs within the page, so that relevant |
| 422 | // entries can be updated as needed. |
| 423 | void NotifyUserActivation(); |
| 424 | |
| 425 | // Tracks a new association between the current pending entry and a |
| 426 | // NavigationRequest. Callers are responsible for only calling this for |
| 427 | // requests corresponding to the current pending entry. |
| 428 | std::unique_ptr<PendingEntryRef> ReferencePendingEntry(); |
| 429 | |
Carlos Caballero | ede6f8c | 2021-01-28 11:01:50 | [diff] [blame] | 430 | // Another page accessed the initial empty main document, which means it |
| 431 | // is no longer safe to display a pending URL without risking a URL spoof. |
| 432 | void DidAccessInitialMainDocument(); |
| 433 | |
| 434 | // The state for the page changed and should be updated in session history. |
| 435 | void UpdateStateForFrame(RenderFrameHostImpl* render_frame_host, |
| 436 | const blink::PageState& page_state); |
| 437 | |
Hayato Ito | 303654c | 2021-06-30 09:07:54 | [diff] [blame] | 438 | // Like NavigationController::CreateNavigationEntry, but takes an extra |
Sharon Yang | 242ef82 | 2023-05-15 21:07:32 | [diff] [blame] | 439 | // argument, |source_process_site_url|. |
Julie Jeongeun Kim | 5b9aff7 | 2022-05-02 02:10:17 | [diff] [blame] | 440 | // `rewrite_virtual_urls` is true when it needs to rewrite virtual urls |
| 441 | // (e.g., for outermost frames). |
danakj | c492bf8 | 2020-09-09 20:02:44 | [diff] [blame] | 442 | static std::unique_ptr<NavigationEntryImpl> CreateNavigationEntry( |
| 443 | const GURL& url, |
| 444 | Referrer referrer, |
Arthur Sonzogni | c686e8f | 2024-01-11 08:36:37 | [diff] [blame] | 445 | std::optional<url::Origin> initiator_origin, |
| 446 | std::optional<GURL> initiator_base_url, |
| 447 | std::optional<GURL> source_process_site_url, |
danakj | c492bf8 | 2020-09-09 20:02:44 | [diff] [blame] | 448 | ui::PageTransition transition, |
| 449 | bool is_renderer_initiated, |
| 450 | const std::string& extra_headers, |
| 451 | BrowserContext* browser_context, |
Julie Jeongeun Kim | 5b9aff7 | 2022-05-02 02:10:17 | [diff] [blame] | 452 | scoped_refptr<network::SharedURLLoaderFactory> blob_url_loader_factory, |
| 453 | bool rewrite_virtual_urls); |
danakj | c492bf8 | 2020-09-09 20:02:44 | [diff] [blame] | 454 | |
Nate Chapin | 97d2f54 | 2022-02-18 01:34:55 | [diff] [blame] | 455 | // Called just before sending the commit to the renderer, or when restoring |
| 456 | // from back/forward cache. Walks the session history entries for the relevant |
| 457 | // FrameTreeNode, forward and backward from the pending entry. All contiguous |
| 458 | // and same-origin FrameNavigationEntries are serialized and returned. |
| 459 | // |request| may be nullptr when getting entries for an iframe that is being |
| 460 | // restored for back/forward cache (in that case, the iframe itself is not |
| 461 | // navigated, so there is no NavigationRequest). |
Domenic Denicola | cd30f5f8 | 2022-03-16 21:48:01 | [diff] [blame] | 462 | blink::mojom::NavigationApiHistoryEntryArraysPtr |
| 463 | GetNavigationApiHistoryEntryVectors(FrameTreeNode* node, |
| 464 | NavigationRequest* request); |
Nate Chapin | d1fe361 | 2021-04-16 20:45:57 | [diff] [blame] | 465 | |
Domenic Denicola | cc094fb | 2022-03-16 23:40:57 | [diff] [blame] | 466 | // The window.navigation API exposes the urls of some non-current same-origin |
Nate Chapin | 63db0d1 | 2022-01-20 22:03:30 | [diff] [blame] | 467 | // FrameNavigationEntries to the renderer. This helper checks whether the |
| 468 | // given ReferrerPolicy makes an attempt to hide a page's URL (e.g., in |
Domenic Denicola | cc094fb | 2022-03-16 23:40:57 | [diff] [blame] | 469 | // referrer headers) and thus whether the URL should be hidden from navigation |
| 470 | // API history entries as well. |
| 471 | static bool ShouldProtectUrlInNavigationApi( |
Nate Chapin | 63db0d1 | 2022-01-20 22:03:30 | [diff] [blame] | 472 | network::mojom::ReferrerPolicy referrer_policy); |
| 473 | |
Chris Bookholt | 27faf8d | 2022-01-20 01:03:33 | [diff] [blame] | 474 | // Returns whether the last NavigationEntry encountered a post-commit error. |
Chris Bookholt | e47eb30a | 2022-01-21 17:25:35 | [diff] [blame] | 475 | bool has_post_commit_error_entry() const { |
| 476 | return entry_replaced_by_post_commit_error_ != nullptr; |
| 477 | } |
Chris Bookholt | 27faf8d | 2022-01-20 01:03:33 | [diff] [blame] | 478 | |
Rakina Zata Amni | 148dcad7 | 2022-06-08 14:53:50 | [diff] [blame] | 479 | // Whether the current call stack includes NavigateToPendingEntry, to avoid |
| 480 | // re-entrant calls to NavigateToPendingEntry. |
Alison Gale | 770f3fc | 2024-04-27 00:39:58 | [diff] [blame] | 481 | // TODO(crbug.com/40841494): Don't expose this once we figure out the |
Rakina Zata Amni | 148dcad7 | 2022-06-08 14:53:50 | [diff] [blame] | 482 | // root cause for the navigation re-entrancy case in the linked bug. |
| 483 | bool in_navigate_to_pending_entry() const { |
| 484 | return in_navigate_to_pending_entry_; |
| 485 | } |
| 486 | |
Minoru Chikamune | 646eba4 | 2025-04-14 01:25:03 | [diff] [blame] | 487 | // This flag is set from RenderFrameHostImpl::SendBeforeUnload() to |
| 488 | // investigate whether kAvoidUnnecessaryBeforeUnloadCheckSync feature is safe |
| 489 | // to enable or not (see: https://crbug.com/40361673, |
| 490 | // https://crbug.com/396998476). |
| 491 | void set_can_be_in_navigate_to_pending_entry( |
| 492 | const bool can_be_in_navigate_to_pending_entry) { |
| 493 | can_be_in_navigate_to_pending_entry_ = can_be_in_navigate_to_pending_entry; |
| 494 | } |
| 495 | |
Ian Vollick | 5c344c5 | 2022-08-29 19:31:33 | [diff] [blame] | 496 | // Whether to maintain a session history with just one entry. |
| 497 | // |
| 498 | // This returns true for a prerendering page and for fenced frames. |
| 499 | // `frame_tree_node` is checked to see if it belongs to a frame tree for |
| 500 | // prerendering or for a fenced frame. |
| 501 | // Explainer: |
| 502 | // https://github.com/jeremyroman/alternate-loading-modes/blob/main/browsing-context.md#session-history) |
Ian Vollick | 5c344c5 | 2022-08-29 19:31:33 | [diff] [blame] | 503 | bool ShouldMaintainTrivialSessionHistory( |
| 504 | const FrameTreeNode* frame_tree_node) const; |
| 505 | |
Julie Jeongeun Kim | 0e24224 | 2022-11-30 10:45:09 | [diff] [blame] | 506 | // Called when the referrer policy changes. It updates whether to protect the |
| 507 | // url in the navigation API. |
| 508 | void DidChangeReferrerPolicy(FrameTreeNode* node, |
| 509 | network::mojom::ReferrerPolicy referrer_policy); |
| 510 | |
William Liu | 2b6336bc | 2023-09-07 14:42:39 | [diff] [blame] | 511 | base::WeakPtr<NavigationControllerImpl> GetWeakPtr() { |
| 512 | return weak_factory_.GetWeakPtr(); |
| 513 | } |
| 514 | |
danakj | c492bf8 | 2020-09-09 20:02:44 | [diff] [blame] | 515 | private: |
| 516 | friend class RestoreHelper; |
| 517 | |
| 518 | FRIEND_TEST_ALL_PREFIXES(TimeSmoother, Basic); |
| 519 | FRIEND_TEST_ALL_PREFIXES(TimeSmoother, SingleDuplicate); |
| 520 | FRIEND_TEST_ALL_PREFIXES(TimeSmoother, ManyDuplicates); |
| 521 | FRIEND_TEST_ALL_PREFIXES(TimeSmoother, ClockBackwardsJump); |
Rakina Zata Amni | 2635778 | 2020-12-03 11:45:01 | [diff] [blame] | 522 | FRIEND_TEST_ALL_PREFIXES(NavigationControllerBrowserTest, PostThenReload); |
| 523 | FRIEND_TEST_ALL_PREFIXES(NavigationControllerBrowserTest, |
danakj | c492bf8 | 2020-09-09 20:02:44 | [diff] [blame] | 524 | PostThenReplaceStateThenReload); |
Rakina Zata Amni | 2635778 | 2020-12-03 11:45:01 | [diff] [blame] | 525 | FRIEND_TEST_ALL_PREFIXES(NavigationControllerBrowserTest, |
Rakina Zata Amni | d80835a | 2020-12-09 10:29:07 | [diff] [blame] | 526 | PostThenPushStateThenReloadThenHistory); |
Rakina Zata Amni | 2635778 | 2020-12-03 11:45:01 | [diff] [blame] | 527 | FRIEND_TEST_ALL_PREFIXES(NavigationControllerBrowserTest, |
Rakina Zata Amni | d80835a | 2020-12-09 10:29:07 | [diff] [blame] | 528 | PostThenFragmentNavigationThenReloadThenHistory); |
| 529 | FRIEND_TEST_ALL_PREFIXES( |
| 530 | NavigationControllerBrowserTest, |
| 531 | PostThenBrowserInitiatedFragmentNavigationThenReload); |
| 532 | FRIEND_TEST_ALL_PREFIXES(NavigationControllerBrowserTest, PostSubframe); |
Wang Hui | 96ab101 | 2022-10-11 02:05:49 | [diff] [blame] | 533 | FRIEND_TEST_ALL_PREFIXES(NavigationControllerBrowserTest, |
| 534 | ResetPendingLoadTypeWhenCancelPendingReload); |
WangHui | 74286d5 | 2021-03-31 16:17:15 | [diff] [blame] | 535 | FRIEND_TEST_ALL_PREFIXES(NavigationControllerDisableHistoryIntervention, |
| 536 | GoToOffsetWithSkippingDisableHistoryIntervention); |
| 537 | FRIEND_TEST_ALL_PREFIXES(NavigationControllerHistoryInterventionBrowserTest, |
| 538 | GoToOffsetWithSkippingEnableHistoryIntervention); |
| 539 | FRIEND_TEST_ALL_PREFIXES(NavigationControllerHistoryInterventionBrowserTest, |
| 540 | SetSkipOnBackForwardDoSkipForGoToOffsetWithSkipping); |
| 541 | FRIEND_TEST_ALL_PREFIXES(NavigationControllerHistoryInterventionBrowserTest, |
| 542 | SetSkipOnBackForwardDoNotSkipForGoToOffset); |
danakj | c492bf8 | 2020-09-09 20:02:44 | [diff] [blame] | 543 | |
| 544 | // Defines possible actions that are returned by |
| 545 | // DetermineActionForHistoryNavigation(). |
| 546 | enum class HistoryNavigationAction { |
| 547 | kStopLooking, |
| 548 | kKeepLooking, |
| 549 | kSameDocument, |
| 550 | kDifferentDocument, |
| 551 | }; |
| 552 | |
Nate Chapin | 9eb16be7 | 2022-09-23 22:54:31 | [diff] [blame] | 553 | enum class Direction { kForward, kBack }; |
| 554 | |
danakj | c492bf8 | 2020-09-09 20:02:44 | [diff] [blame] | 555 | // Helper class to smooth out runs of duplicate timestamps while still |
| 556 | // allowing time to jump backwards. |
| 557 | class CONTENT_EXPORT TimeSmoother { |
| 558 | public: |
| 559 | // Returns |t| with possibly some time added on. |
| 560 | base::Time GetSmoothedTime(base::Time t); |
| 561 | |
| 562 | private: |
| 563 | // |low_water_mark_| is the first time in a sequence of adjusted |
| 564 | // times and |high_water_mark_| is the last. |
| 565 | base::Time low_water_mark_; |
| 566 | base::Time high_water_mark_; |
| 567 | }; |
| 568 | |
| 569 | // The repost dialog is suppressed during testing. However, it should be shown |
| 570 | // in some tests. This allows a test to elect to allow the repost dialog to |
| 571 | // show for a scoped duration. |
| 572 | class CONTENT_EXPORT ScopedShowRepostDialogForTesting { |
| 573 | public: |
| 574 | ScopedShowRepostDialogForTesting(); |
| 575 | ~ScopedShowRepostDialogForTesting(); |
| 576 | |
| 577 | ScopedShowRepostDialogForTesting(const ScopedShowRepostDialogForTesting&) = |
| 578 | delete; |
| 579 | ScopedShowRepostDialogForTesting& operator=( |
| 580 | const ScopedShowRepostDialogForTesting&) = delete; |
| 581 | |
| 582 | private: |
| 583 | const bool was_disallowed_; |
| 584 | }; |
| 585 | |
Charlie Reis | d3e4fef | 2025-05-20 02:04:17 | [diff] [blame] | 586 | // Navigations to pending entries do not support re-entrancy due to a risk of |
| 587 | // use-after-free, and the pending entry itself should not be deleted during |
| 588 | // such a navigation. Create one of these scoped objects around calls to |
| 589 | // `Navigator::Navigate` when a pending entry is used, to safely crash rather |
| 590 | // than risk memory errors if re-entrancy or an unexpected deletion occurs. |
| 591 | // See https://crbug.com/40353566 for details. |
| 592 | class ScopedPendingEntryReentrancyGuard { |
| 593 | public: |
| 594 | explicit ScopedPendingEntryReentrancyGuard( |
| 595 | base::SafeRef<NavigationControllerImpl> controller); |
| 596 | ~ScopedPendingEntryReentrancyGuard(); |
| 597 | |
| 598 | private: |
| 599 | base::SafeRef<NavigationControllerImpl> controller_; |
| 600 | std::unique_ptr<NavigationControllerImpl::PendingEntryRef> |
| 601 | pending_entry_ref_; |
| 602 | }; |
| 603 | |
Nate Chapin | 9eb16be7 | 2022-09-23 22:54:31 | [diff] [blame] | 604 | // Records which navigation API keys are associated with live frames. |
| 605 | // On destruction, does a final pass to filter out any keys that are still |
| 606 | // present in |entries_|, then sends the removed navigation API keys to the |
| 607 | // renderer so that the navigation API can fire dispose events for the |
| 608 | // entries associated with those keys. |
| 609 | class RemovedEntriesTracker { |
| 610 | public: |
| 611 | explicit RemovedEntriesTracker( |
| 612 | base::SafeRef<NavigationControllerImpl> controller); |
| 613 | ~RemovedEntriesTracker(); |
| 614 | |
| 615 | private: |
| 616 | // Walk both directions from the last committed entry to find the navigation |
| 617 | // API keys of any FNEs that could be known by currently live documents. |
| 618 | // These FNEs are contiguous, so the walk can stop for a given frame when it |
| 619 | // reaches an FNE whose API key is no longer known to the current document. |
| 620 | void PopulateKeySet(Direction direction); |
| 621 | base::SafeRef<NavigationControllerImpl> controller_; |
| 622 | // Preprocessed maps used in PopulateKeySet(), mapping frame names |
| 623 | // to their respective FrameTreeNodes, and FrameTreeNode ids to their |
| 624 | // current document sequences numbers. |
Ali Hijazi | 60a72b0a | 2024-09-30 17:58:53 | [diff] [blame] | 625 | std::map<std::string, raw_ptr<FrameTreeNode, CtnExperimental>> |
| 626 | names_to_nodes_; |
Avi Drissman | bd15364 | 2024-09-03 18:58:05 | [diff] [blame] | 627 | std::map<FrameTreeNodeId, int64_t> frame_tree_node_id_to_doc_seq_nos_; |
Nate Chapin | 9eb16be7 | 2022-09-23 22:54:31 | [diff] [blame] | 628 | |
| 629 | // The output of PopulateKeySet(), which maps FrameTreeNode ids to the keys |
| 630 | // that frame knows about in the renderer. Used in the destructor. |
Avi Drissman | bd15364 | 2024-09-03 18:58:05 | [diff] [blame] | 631 | std::map<FrameTreeNodeId, std::set<std::string>> |
| 632 | frame_tree_node_id_to_keys_; |
Nate Chapin | 9eb16be7 | 2022-09-23 22:54:31 | [diff] [blame] | 633 | }; |
| 634 | |
William Liu | 62ae26c | 2024-08-08 14:28:16 | [diff] [blame] | 635 | // Navigates in session history to the given index. Returns all the created |
| 636 | // `NavigationRequest`s. If no request was created, the returned vector is |
| 637 | // empty. |
Nate Chapin | bf682fa3 | 2022-09-26 22:41:20 | [diff] [blame] | 638 | // |initiator_rfh| is nullptr for browser-initiated navigations. |
Yoav Weiss | a7449c3b | 2022-11-22 15:15:14 | [diff] [blame] | 639 | // |soft_navigation_heuristics_task_id|: The task in the renderer that |
Yoav Weiss | 8c57395 | 2022-11-17 17:35:13 | [diff] [blame] | 640 | // initiated this call (if any). |
Nate Chapin | bf682fa3 | 2022-09-26 22:41:20 | [diff] [blame] | 641 | // If this navigation originated from the navigation API, |navigation_api_key| |
| 642 | // will be set and indicate the navigation api key that |initiator_rfh| |
| 643 | // asked to be navigated to. |
Charlie Reis | f4d51f40 | 2025-05-23 18:00:49 | [diff] [blame] | 644 | // |actual_navigation_start| is the time the navigation began, for metrics. |
William Liu | 62ae26c | 2024-08-08 14:28:16 | [diff] [blame] | 645 | std::vector<base::WeakPtr<NavigationRequest>> GoToIndex( |
William Liu | ec04e38 | 2024-05-23 18:03:27 | [diff] [blame] | 646 | int index, |
| 647 | RenderFrameHostImpl* initiator_rfh, |
| 648 | std::optional<blink::scheduler::TaskAttributionId> |
| 649 | soft_navigation_heuristics_task_id, |
Charlie Reis | f4d51f40 | 2025-05-23 18:00:49 | [diff] [blame] | 650 | const std::string* navigation_api_key, |
| 651 | base::TimeTicks actual_navigation_start); |
danakj | c492bf8 | 2020-09-09 20:02:44 | [diff] [blame] | 652 | |
William Liu | ec04e38 | 2024-05-23 18:03:27 | [diff] [blame] | 653 | // Starts a navigation to an already existing pending NavigationEntry. Returns |
William Liu | 62ae26c | 2024-08-08 14:28:16 | [diff] [blame] | 654 | // all the created `NavigationRequest`s. If no request was created, the |
| 655 | // returned vector is empty. |
Nate Chapin | bf682fa3 | 2022-09-26 22:41:20 | [diff] [blame] | 656 | // |initiator_rfh| is nullptr for browser-initiated navigations. |
| 657 | // If this navigation originated from the navigation API, |navigation_api_key| |
| 658 | // will be set and indicate the navigation api key that |initiator_rfh| |
| 659 | // asked to be navigated to. |
Yoav Weiss | a7449c3b | 2022-11-22 15:15:14 | [diff] [blame] | 660 | // |soft_navigation_heuristics_task_id|: The task in the renderer that |
Yoav Weiss | 8c57395 | 2022-11-17 17:35:13 | [diff] [blame] | 661 | // initiated this call (if any). |
Charlie Reis | f4d51f40 | 2025-05-23 18:00:49 | [diff] [blame] | 662 | // |actual_navigation_start| is the time the navigation began, for metrics. |
William Liu | 62ae26c | 2024-08-08 14:28:16 | [diff] [blame] | 663 | std::vector<base::WeakPtr<NavigationRequest>> NavigateToExistingPendingEntry( |
Yoav Weiss | 8c57395 | 2022-11-17 17:35:13 | [diff] [blame] | 664 | ReloadType reload_type, |
| 665 | RenderFrameHostImpl* initiator_rfh, |
Arthur Sonzogni | c686e8f | 2024-01-11 08:36:37 | [diff] [blame] | 666 | std::optional<blink::scheduler::TaskAttributionId> |
Yoav Weiss | 8c57395 | 2022-11-17 17:35:13 | [diff] [blame] | 667 | soft_navigation_heuristics_task_id, |
Charlie Reis | f4d51f40 | 2025-05-23 18:00:49 | [diff] [blame] | 668 | const std::string* navigation_api_key, |
| 669 | base::TimeTicks actual_navigation_start); |
danakj | c492bf8 | 2020-09-09 20:02:44 | [diff] [blame] | 670 | |
| 671 | // Helper function used by FindFramesToNavigate to determine the appropriate |
| 672 | // action to take for a particular frame while navigating to |
| 673 | // |pending_entry_|. |
| 674 | HistoryNavigationAction DetermineActionForHistoryNavigation( |
| 675 | FrameTreeNode* frame, |
| 676 | ReloadType reload_type); |
| 677 | |
| 678 | // Recursively identifies which frames need to be navigated for a navigation |
| 679 | // to |pending_entry_|, starting at |frame| and exploring its children. |
| 680 | // |same_document_loads| and |different_document_loads| will be filled with |
| 681 | // the NavigationRequests needed to navigate to |pending_entry_|. |
Charlie Reis | f4d51f40 | 2025-05-23 18:00:49 | [diff] [blame] | 682 | // |actual_navigation_start| is the time the navigation began, for metrics. |
Yoav Weiss | a7449c3b | 2022-11-22 15:15:14 | [diff] [blame] | 683 | // |soft_navigation_heuristics_task_id|: The task in the renderer that |
Yoav Weiss | 8c57395 | 2022-11-17 17:35:13 | [diff] [blame] | 684 | // initiated this call (if any). |
danakj | c492bf8 | 2020-09-09 20:02:44 | [diff] [blame] | 685 | void FindFramesToNavigate( |
| 686 | FrameTreeNode* frame, |
| 687 | ReloadType reload_type, |
Arthur Sonzogni | c686e8f | 2024-01-11 08:36:37 | [diff] [blame] | 688 | const std::optional<blink::LocalFrameToken>& initiator_frame_token, |
Hiroshige Hayashizaki | 5466bfe8 | 2023-05-17 00:34:33 | [diff] [blame] | 689 | int initiator_process_id, |
Arthur Sonzogni | c686e8f | 2024-01-11 08:36:37 | [diff] [blame] | 690 | std::optional<blink::scheduler::TaskAttributionId> |
Yoav Weiss | 8c57395 | 2022-11-17 17:35:13 | [diff] [blame] | 691 | soft_navigation_heuristics_task_id, |
Charlie Reis | f4d51f40 | 2025-05-23 18:00:49 | [diff] [blame] | 692 | base::TimeTicks actual_navigation_start, |
danakj | c492bf8 | 2020-09-09 20:02:44 | [diff] [blame] | 693 | std::vector<std::unique_ptr<NavigationRequest>>* same_document_loads, |
| 694 | std::vector<std::unique_ptr<NavigationRequest>>* |
| 695 | different_document_loads); |
| 696 | |
| 697 | // Starts a new navigation based on |load_params|, that doesn't correspond to |
danakj | f26536bf | 2020-09-10 00:46:13 | [diff] [blame] | 698 | // an existing NavigationEntry. |
Charlie Reis | f4d51f40 | 2025-05-23 18:00:49 | [diff] [blame] | 699 | // |actual_navigation_start| is the time the navigation began, for metrics. |
Harkiran Bolaria | ba823e4 | 2021-05-21 18:30:36 | [diff] [blame] | 700 | base::WeakPtr<NavigationHandle> NavigateWithoutEntry( |
Charlie Reis | f4d51f40 | 2025-05-23 18:00:49 | [diff] [blame] | 701 | const LoadURLParams& load_params, |
| 702 | base::TimeTicks actual_navigation_start); |
danakj | c492bf8 | 2020-09-09 20:02:44 | [diff] [blame] | 703 | |
| 704 | // Handles a navigation to a renderer-debug URL. |
| 705 | void HandleRendererDebugURL(FrameTreeNode* frame_tree_node, const GURL& url); |
| 706 | |
| 707 | // Creates and returns a NavigationEntry based on |load_params| for a |
| 708 | // navigation in |node|. |
| 709 | // |override_user_agent|, |should_replace_current_entry| and |
| 710 | // |has_user_gesture| will override the values from |load_params|. The same |
| 711 | // values should be passed to CreateNavigationRequestFromLoadParams. |
| 712 | std::unique_ptr<NavigationEntryImpl> CreateNavigationEntryFromLoadParams( |
| 713 | FrameTreeNode* node, |
| 714 | const LoadURLParams& load_params, |
| 715 | bool override_user_agent, |
| 716 | bool should_replace_current_entry, |
| 717 | bool has_user_gesture); |
| 718 | |
| 719 | // Creates and returns a NavigationRequest based on |load_params| for a |
| 720 | // new navigation in |node|. |
| 721 | // Will return nullptr if the parameters are invalid and the navigation cannot |
| 722 | // start. |
| 723 | // |override_user_agent|, |should_replace_current_entry| and |
| 724 | // |has_user_gesture| will override the values from |load_params|. The same |
| 725 | // values should be passed to CreateNavigationEntryFromLoadParams. |
| 726 | // TODO(clamy): Remove the dependency on NavigationEntry and |
| 727 | // FrameNavigationEntry. |
| 728 | std::unique_ptr<NavigationRequest> CreateNavigationRequestFromLoadParams( |
| 729 | FrameTreeNode* node, |
| 730 | const LoadURLParams& load_params, |
| 731 | bool override_user_agent, |
| 732 | bool should_replace_current_entry, |
| 733 | bool has_user_gesture, |
Antonio Sartori | 2f763d9d | 2021-04-21 10:04:14 | [diff] [blame] | 734 | network::mojom::SourceLocationPtr source_location, |
danakj | c492bf8 | 2020-09-09 20:02:44 | [diff] [blame] | 735 | ReloadType reload_type, |
| 736 | NavigationEntryImpl* entry, |
Tsuyoshi Horo | 167ca643 | 2022-03-09 05:16:39 | [diff] [blame] | 737 | FrameNavigationEntry* frame_entry, |
Charlie Reis | e1d9b818 | 2025-04-02 04:32:12 | [diff] [blame] | 738 | base::TimeTicks actual_navigation_start_time, |
Nan Lin | 944e9b4e | 2022-04-12 13:51:22 | [diff] [blame] | 739 | base::TimeTicks navigation_start_time, |
Garrett Tanzer | 405f340 | 2022-07-21 20:12:49 | [diff] [blame] | 740 | bool is_embedder_initiated_fenced_frame_navigation = false, |
Sergey Poromov | dd557c1 | 2023-03-01 11:28:45 | [diff] [blame] | 741 | bool is_unfenced_top_navigation = false, |
Camillia Smith Barnes | 6a64396 | 2023-03-03 00:28:58 | [diff] [blame] | 742 | bool is_container_initiated = false, |
W. James MacLean | 443ef3e | 2024-07-16 13:42:34 | [diff] [blame] | 743 | net::StorageAccessApiStatus storage_access_api_status = |
| 744 | net::StorageAccessApiStatus::kNone, |
Arthur Sonzogni | c686e8f | 2024-01-11 08:36:37 | [diff] [blame] | 745 | std::optional<std::u16string> embedder_shared_storage_context = |
| 746 | std::nullopt); |
danakj | c492bf8 | 2020-09-09 20:02:44 | [diff] [blame] | 747 | |
| 748 | // Creates and returns a NavigationRequest for a navigation to |entry|. Will |
| 749 | // return nullptr if the parameters are invalid and the navigation cannot |
| 750 | // start. |
Yoav Weiss | a7449c3b | 2022-11-22 15:15:14 | [diff] [blame] | 751 | // |soft_navigation_heuristics_task_id|: The task in the renderer that |
Yoav Weiss | 8c57395 | 2022-11-17 17:35:13 | [diff] [blame] | 752 | // initiated this call (if any). |
danakj | c492bf8 | 2020-09-09 20:02:44 | [diff] [blame] | 753 | // TODO(clamy): Ensure this is only called for navigations to existing |
| 754 | // NavigationEntries. |
| 755 | std::unique_ptr<NavigationRequest> CreateNavigationRequestFromEntry( |
| 756 | FrameTreeNode* frame_tree_node, |
| 757 | NavigationEntryImpl* entry, |
| 758 | FrameNavigationEntry* frame_entry, |
| 759 | ReloadType reload_type, |
| 760 | bool is_same_document_history_load, |
Nate Chapin | 45f62058 | 2021-09-30 17:45:43 | [diff] [blame] | 761 | bool is_history_navigation_in_new_child_frame, |
Arthur Sonzogni | c686e8f | 2024-01-11 08:36:37 | [diff] [blame] | 762 | const std::optional<blink::LocalFrameToken>& initiator_frame_token, |
Hiroshige Hayashizaki | 5466bfe8 | 2023-05-17 00:34:33 | [diff] [blame] | 763 | int initiator_process_id, |
Charlie Reis | f4d51f40 | 2025-05-23 18:00:49 | [diff] [blame] | 764 | base::TimeTicks actual_navigation_start, |
Arthur Sonzogni | c686e8f | 2024-01-11 08:36:37 | [diff] [blame] | 765 | std::optional<blink::scheduler::TaskAttributionId> |
| 766 | soft_navigation_heuristics_task_id = std::nullopt); |
danakj | c492bf8 | 2020-09-09 20:02:44 | [diff] [blame] | 767 | |
| 768 | // Returns whether there is a pending NavigationEntry whose unique ID matches |
| 769 | // the given NavigationRequest's pending_nav_entry_id. |
| 770 | bool PendingEntryMatchesRequest(NavigationRequest* request) const; |
| 771 | |
| 772 | // Classifies the given renderer navigation (see the NavigationType enum). |
| 773 | NavigationType ClassifyNavigation( |
| 774 | RenderFrameHostImpl* rfh, |
Rakina Zata Amni | f6950d55 | 2020-11-24 03:26:10 | [diff] [blame] | 775 | const mojom::DidCommitProvisionalLoadParams& params, |
Rakina Zata Amni | 2322f4f8 | 2022-01-24 13:24:24 | [diff] [blame] | 776 | NavigationRequest* navigation_request); |
danakj | c492bf8 | 2020-09-09 20:02:44 | [diff] [blame] | 777 | |
| 778 | // Handlers for the different types of navigation types. They will actually |
| 779 | // handle the navigations corresponding to the different NavClasses above. |
| 780 | // They will NOT broadcast the commit notification, that should be handled by |
| 781 | // the caller. |
| 782 | // |
| 783 | // RendererDidNavigateAutoSubframe is special, it may not actually change |
| 784 | // anything if some random subframe is loaded. It will return true if anything |
| 785 | // changed, or false if not. |
| 786 | // |
Charlie Reis | c0f17d2d | 2021-01-12 18:52:49 | [diff] [blame] | 787 | // The NewEntry and NewSubframe functions take in |replace_entry| to pass to |
danakj | c492bf8 | 2020-09-09 20:02:44 | [diff] [blame] | 788 | // InsertOrReplaceEntry, in case the newly created NavigationEntry is meant to |
| 789 | // replace the current one (e.g., for location.replace or successful loads |
| 790 | // after net errors), in contrast to updating a NavigationEntry in place |
| 791 | // (e.g., for history.replaceState). |
Charlie Reis | c0f17d2d | 2021-01-12 18:52:49 | [diff] [blame] | 792 | void RendererDidNavigateToNewEntry( |
danakj | c492bf8 | 2020-09-09 20:02:44 | [diff] [blame] | 793 | RenderFrameHostImpl* rfh, |
arthursonzogni | 73fe321 | 2020-11-17 13:24:07 | [diff] [blame] | 794 | const mojom::DidCommitProvisionalLoadParams& params, |
danakj | c492bf8 | 2020-09-09 20:02:44 | [diff] [blame] | 795 | bool is_same_document, |
| 796 | bool replace_entry, |
Shivani Sharma | eef521b | 2024-01-18 13:03:56 | [diff] [blame] | 797 | bool previous_document_had_history_intervention_activation, |
Rakina Zata Amni | a4e2722 | 2021-12-22 01:05:00 | [diff] [blame] | 798 | NavigationRequest* request, |
| 799 | LoadCommittedDetails* details); |
Charlie Reis | c0f17d2d | 2021-01-12 18:52:49 | [diff] [blame] | 800 | void RendererDidNavigateToExistingEntry( |
danakj | c492bf8 | 2020-09-09 20:02:44 | [diff] [blame] | 801 | RenderFrameHostImpl* rfh, |
arthursonzogni | 73fe321 | 2020-11-17 13:24:07 | [diff] [blame] | 802 | const mojom::DidCommitProvisionalLoadParams& params, |
danakj | c492bf8 | 2020-09-09 20:02:44 | [diff] [blame] | 803 | bool is_same_document, |
| 804 | bool was_restored, |
| 805 | NavigationRequest* request, |
Rakina Zata Amni | a4e2722 | 2021-12-22 01:05:00 | [diff] [blame] | 806 | bool keep_pending_entry, |
| 807 | LoadCommittedDetails* details); |
danakj | c492bf8 | 2020-09-09 20:02:44 | [diff] [blame] | 808 | void RendererDidNavigateNewSubframe( |
| 809 | RenderFrameHostImpl* rfh, |
arthursonzogni | 73fe321 | 2020-11-17 13:24:07 | [diff] [blame] | 810 | const mojom::DidCommitProvisionalLoadParams& params, |
danakj | c492bf8 | 2020-09-09 20:02:44 | [diff] [blame] | 811 | bool is_same_document, |
| 812 | bool replace_entry, |
Shivani Sharma | eef521b | 2024-01-18 13:03:56 | [diff] [blame] | 813 | bool previous_document_had_history_intervention_activation, |
Rakina Zata Amni | a4e2722 | 2021-12-22 01:05:00 | [diff] [blame] | 814 | NavigationRequest* request, |
| 815 | LoadCommittedDetails* details); |
danakj | c492bf8 | 2020-09-09 20:02:44 | [diff] [blame] | 816 | bool RendererDidNavigateAutoSubframe( |
| 817 | RenderFrameHostImpl* rfh, |
arthursonzogni | 73fe321 | 2020-11-17 13:24:07 | [diff] [blame] | 818 | const mojom::DidCommitProvisionalLoadParams& params, |
Antonio Sartori | 78a749f | 2020-11-30 12:03:39 | [diff] [blame] | 819 | bool is_same_document, |
Nate Chapin | c7019dd7d | 2021-06-25 18:29:25 | [diff] [blame] | 820 | bool was_on_initial_empty_document, |
Rakina Zata Amni | a4e2722 | 2021-12-22 01:05:00 | [diff] [blame] | 821 | NavigationRequest* request, |
| 822 | LoadCommittedDetails* details); |
danakj | c492bf8 | 2020-09-09 20:02:44 | [diff] [blame] | 823 | |
| 824 | // Allows the derived class to issue notifications that a load has been |
| 825 | // committed. This will fill in the active entry to the details structure. |
| 826 | void NotifyNavigationEntryCommitted(LoadCommittedDetails* details); |
| 827 | |
| 828 | // Updates the virtual URL of an entry to match a new URL, for cases where |
| 829 | // the real renderer URL is derived from the virtual URL, like view-source: |
| 830 | void UpdateVirtualURLToURL(NavigationEntryImpl* entry, const GURL& new_url); |
| 831 | |
| 832 | // Invoked after session/tab restore or cloning a tab. Resets the transition |
| 833 | // type of the entries, updates the max page id and creates the active |
| 834 | // contents. |
| 835 | void FinishRestore(int selected_index, RestoreType type); |
| 836 | |
| 837 | // Inserts a new entry or replaces the current entry with a new one, removing |
| 838 | // all entries after it. The new entry will become the active one. |
| 839 | // If |was_post_commit_error_| is set, the last committed entry will be saved, |
| 840 | // the new entry will replace it, and on any navigation away from the new |
| 841 | // entry or on reloads, the old one will replace |entry|. |
| 842 | void InsertOrReplaceEntry(std::unique_ptr<NavigationEntryImpl> entry, |
| 843 | bool replace, |
Dave Tapuska | 87696ae | 2021-11-18 18:48:31 | [diff] [blame] | 844 | bool was_post_commit_error, |
Rakina Zata Amni | a4e2722 | 2021-12-22 01:05:00 | [diff] [blame] | 845 | bool is_in_fenced_frame_tree, |
| 846 | LoadCommittedDetails* details); |
danakj | c492bf8 | 2020-09-09 20:02:44 | [diff] [blame] | 847 | |
| 848 | // Removes the entry at |index|, as long as it is not the current entry. |
| 849 | void RemoveEntryAtIndexInternal(int index); |
| 850 | |
| 851 | // If we have the maximum number of entries, remove the oldest entry that is |
| 852 | // marked to be skipped on back/forward button, in preparation to add another. |
| 853 | // If no entry is skippable, then the oldest entry will be pruned. |
| 854 | void PruneOldestSkippableEntryIfFull(); |
| 855 | |
| 856 | // Removes all entries except the last committed entry. If there is a new |
| 857 | // pending navigation it is preserved. In contrast to |
| 858 | // PruneAllButLastCommitted() this does not update the session history of the |
Dave Tapuska | 2cf1f53 | 2022-08-10 15:30:49 | [diff] [blame] | 859 | // `blink::WebView`. Callers must ensure that `CanPruneAllButLastCommitted` |
| 860 | // returns true before calling this. |
danakj | c492bf8 | 2020-09-09 20:02:44 | [diff] [blame] | 861 | void PruneAllButLastCommittedInternal(); |
| 862 | |
| 863 | // Inserts up to |max_index| entries from |source| into this. This does NOT |
| 864 | // adjust any of the members that reference entries_ |
| 865 | // (last_committed_entry_index_ or pending_entry_index_) |
| 866 | void InsertEntriesFrom(NavigationControllerImpl* source, int max_index); |
| 867 | |
| 868 | // Returns the navigation index that differs from the current entry by the |
| 869 | // specified |offset|. The index returned is not guaranteed to be valid. |
WangHui | 74286d5 | 2021-03-31 16:17:15 | [diff] [blame] | 870 | // This does not account for skippable entries or the history manipulation |
| 871 | // intervention. |
danakj | c492bf8 | 2020-09-09 20:02:44 | [diff] [blame] | 872 | int GetIndexForOffset(int offset); |
| 873 | |
| 874 | // History Manipulation intervention: |
| 875 | // The previous document that started this navigation needs to be skipped in |
| 876 | // subsequent back/forward UI navigations if it never received any user |
| 877 | // gesture. This is to intervene against pages that manipulate the history |
| 878 | // such that the user is not able to go back to the last site they interacted |
| 879 | // with (crbug.com/907167). |
| 880 | // Note that this function must be called before the new navigation entry is |
| 881 | // inserted in |entries_| to make sure UKM reports the URL of the document |
| 882 | // adding the entry. |
| 883 | void SetShouldSkipOnBackForwardUIIfNeeded( |
danakj | c492bf8 | 2020-09-09 20:02:44 | [diff] [blame] | 884 | bool replace_entry, |
Shivani Sharma | eef521b | 2024-01-18 13:03:56 | [diff] [blame] | 885 | bool previous_document_had_history_intervention_activation, |
danakj | c492bf8 | 2020-09-09 20:02:44 | [diff] [blame] | 886 | bool is_renderer_initiated, |
| 887 | ukm::SourceId previous_page_load_ukm_source_id); |
| 888 | |
| 889 | // This function sets all same document entries with the same value |
| 890 | // of skippable flag. This is to avoid back button abuse by inserting |
| 891 | // multiple history entries and also to help valid cases where a user gesture |
| 892 | // on the document should apply to all same document history entries and none |
| 893 | // should be skipped. All entries belonging to the same document as the entry |
| 894 | // at |reference_index| will get their skippable flag set to |skippable|. |
| 895 | void SetSkippableForSameDocumentEntries(int reference_index, bool skippable); |
| 896 | |
| 897 | // Called when one PendingEntryRef is deleted. When all of the refs for the |
| 898 | // current pending entry have been deleted, this automatically discards the |
| 899 | // pending NavigationEntry. |
| 900 | void PendingEntryRefDeleted(PendingEntryRef* ref); |
| 901 | |
Titouan Rigoudy | 6ec7040 | 2021-02-02 15:42:19 | [diff] [blame] | 902 | // Computes the policy container policies to be stored in the |
| 903 | // FrameNavigationEntry by RendererDidNavigate. |
| 904 | std::unique_ptr<PolicyContainerPolicies> |
| 905 | ComputePolicyContainerPoliciesForFrameEntry(RenderFrameHostImpl* rfh, |
| 906 | bool is_same_document, |
Antonio Sartori | b8addf6 | 2024-09-16 07:59:21 | [diff] [blame] | 907 | bool navigation_encountered_error, |
Rakina Zata Amni | afd3c658 | 2021-11-30 06:19:17 | [diff] [blame] | 908 | const GURL& url); |
Antonio Sartori | 78a749f | 2020-11-30 12:03:39 | [diff] [blame] | 909 | |
Rakina Zata Amni | 3460d38 | 2021-10-29 00:43:37 | [diff] [blame] | 910 | // Adds details from a committed navigation to `entry` and the |
| 911 | // FrameNavigationEntry corresponding to `rfh`. |
| 912 | void UpdateNavigationEntryDetails( |
| 913 | NavigationEntryImpl* entry, |
| 914 | RenderFrameHostImpl* rfh, |
| 915 | const mojom::DidCommitProvisionalLoadParams& params, |
| 916 | NavigationRequest* request, |
| 917 | NavigationEntryImpl::UpdatePolicy update_policy, |
Rakina Zata Amni | a4e2722 | 2021-12-22 01:05:00 | [diff] [blame] | 918 | bool is_new_entry, |
| 919 | LoadCommittedDetails* commit_details); |
Rakina Zata Amni | 3460d38 | 2021-10-29 00:43:37 | [diff] [blame] | 920 | |
Charlie Reis | 99b2eba2 | 2025-01-31 19:18:57 | [diff] [blame] | 921 | // Broadcasts this controller's session history index and length to all |
| 922 | // renderers involved in rendering the current page. The index is |
Hayato Ito | 2c8c08d0 | 2021-06-23 03:38:43 | [diff] [blame] | 923 | // GetLastCommittedEntryIndex() and length is GetEntryCount(). |
Charlie Reis | 99b2eba2 | 2025-01-31 19:18:57 | [diff] [blame] | 924 | void BroadcastHistoryIndexAndLength(); |
Carlos Caballero | ede6f8c | 2021-01-28 11:01:50 | [diff] [blame] | 925 | |
Domenic Denicola | cd30f5f8 | 2022-03-16 21:48:01 | [diff] [blame] | 926 | // Used by PopulateNavigationApiHistoryEntryVectors to initialize a single |
Nate Chapin | a2c881f5 | 2023-11-07 17:02:09 | [diff] [blame] | 927 | // vector. `last_index_checked` is an out parameter that indicates the last |
| 928 | // entry index walked in `direction` before stopping. |
Domenic Denicola | cd30f5f8 | 2022-03-16 21:48:01 | [diff] [blame] | 929 | std::vector<blink::mojom::NavigationApiHistoryEntryPtr> |
| 930 | PopulateSingleNavigationApiHistoryEntryVector( |
| 931 | Direction direction, |
| 932 | int entry_index, |
| 933 | const url::Origin& pending_origin, |
| 934 | FrameTreeNode* node, |
| 935 | SiteInstance* site_instance, |
| 936 | int64_t pending_item_sequence_number, |
Nate Chapin | a2c881f5 | 2023-11-07 17:02:09 | [diff] [blame] | 937 | int64_t pending_document_sequence_number, |
| 938 | int& last_index_checked); |
Domenic Denicola | cc094fb | 2022-03-16 23:40:57 | [diff] [blame] | 939 | // Helper for NavigateToNavigationApiKey(). Ensures that we only navigate to |
Nate Chapin | fbfe5af | 2021-06-10 17:22:08 | [diff] [blame] | 940 | // |target_entry| if it matches |current_entry|'s origin and site instance, as |
Domenic Denicola | cc094fb | 2022-03-16 23:40:57 | [diff] [blame] | 941 | // well as having |navigation_api_key| as its key. |
| 942 | HistoryNavigationAction ShouldNavigateToEntryForNavigationApiKey( |
Nate Chapin | fbfe5af | 2021-06-10 17:22:08 | [diff] [blame] | 943 | FrameNavigationEntry* current_entry, |
| 944 | FrameNavigationEntry* target_entry, |
Domenic Denicola | cc094fb | 2022-03-16 23:40:57 | [diff] [blame] | 945 | const std::string& navigation_api_key); |
Nate Chapin | d1fe361 | 2021-04-16 20:45:57 | [diff] [blame] | 946 | |
Minoru Chikamune | 646eba4 | 2025-04-14 01:25:03 | [diff] [blame] | 947 | // When navigation starts, the `can_be_in_navigate_to_pending_entry` flag has |
| 948 | // to be false. This is because kAvoidUnnecessaryBeforeUnloadCheckSync feature |
| 949 | // will stop using PostTask for the legacy beforeunload code in the near |
| 950 | // future. When kAvoidUnnecessaryBeforeUnloadCheckSync is enabled, |
| 951 | // `RenderFrameHostImpl::ProcessBeforeUnloadCompletedFromFrame()` and |
| 952 | // `Navigator::BeforeUnloadCompleted()` can run in the scope of |
| 953 | // `in_navigate_to_pending_entry_` == true, and it might end up crashing on |
| 954 | // CHECK(!in_navigate_to_pending_entry_). |
| 955 | void CheckPotentialNavigationReentrancy(); |
| 956 | |
Andrew Verge | 754c70a | 2025-04-17 17:19:19 | [diff] [blame] | 957 | // Creates a NavigationRequest to use for browser-initiated error page |
| 958 | // navigations. When the request is started, it will navigate the |
| 959 | // FrameTreeNode corresponding to |render_frame_host_impl| to an error page, |
| 960 | // with |url| as the URL and |error_page_html| as the content. If |
| 961 | // |is_post_commit_error_page| is true, the entire NavigationEntry will be |
| 962 | // temporarily replaced when the navigation completes, otherwise it will be |
| 963 | // fully replaced. See |NavigationController::LoadPostCommitErrorPage()| and |
| 964 | // |NavigationControllerImpl::NavigateFrameToErrorPage()| for more details on |
| 965 | // this distinction. |
| 966 | std::unique_ptr<NavigationRequest> CreateNavigationRequestForErrorPage( |
| 967 | RenderFrameHostImpl* render_frame_host_impl, |
| 968 | const GURL& url, |
| 969 | const std::string& error_page_html, |
| 970 | bool is_post_commit_error_page); |
| 971 | |
Emmanuel Arias Soto | 9e15965 | 2025-05-16 07:53:55 | [diff] [blame] | 972 | // Finds the target FrameTreeNode for navigation. Returns the node specified |
| 973 | // by |params| via ID or name, or the root node if none specified. |
| 974 | FrameTreeNode* GetTargetFrameTreeNodeForNavigation( |
| 975 | const LoadURLParams& params); |
| 976 | |
danakj | c492bf8 | 2020-09-09 20:02:44 | [diff] [blame] | 977 | // --------------------------------------------------------------------------- |
| 978 | |
Carlos Caballero | 40b0efd | 2021-01-26 11:55:00 | [diff] [blame] | 979 | // The FrameTree this instance belongs to. Each FrameTree gets its own |
| 980 | // NavigationController. |
Ali Hijazi | d87307d | 2022-11-07 20:15:03 | [diff] [blame] | 981 | const raw_ref<FrameTree> frame_tree_; |
Carlos Caballero | 40b0efd | 2021-01-26 11:55:00 | [diff] [blame] | 982 | |
danakj | c492bf8 | 2020-09-09 20:02:44 | [diff] [blame] | 983 | // The user browser context associated with this controller. |
Keishi Hattori | 0e45c02 | 2021-11-27 09:25:52 | [diff] [blame] | 984 | const raw_ptr<BrowserContext> browser_context_; |
danakj | c492bf8 | 2020-09-09 20:02:44 | [diff] [blame] | 985 | |
| 986 | // List of |NavigationEntry|s for this controller. |
| 987 | std::vector<std::unique_ptr<NavigationEntryImpl>> entries_; |
| 988 | |
| 989 | // An entry we haven't gotten a response for yet. This will be discarded |
| 990 | // when we navigate again. It's used only so we know what the currently |
| 991 | // displayed tab is. |
| 992 | // |
| 993 | // This may refer to an item in the entries_ list if the pending_entry_index_ |
| 994 | // != -1, or it may be its own entry that should be deleted. Be careful with |
| 995 | // the memory management. |
Paul Semel | 7e51469e | 2022-07-12 12:16:33 | [diff] [blame] | 996 | raw_ptr<NavigationEntryImpl> pending_entry_ = nullptr; |
danakj | c492bf8 | 2020-09-09 20:02:44 | [diff] [blame] | 997 | |
| 998 | // This keeps track of the NavigationRequests associated with the pending |
| 999 | // NavigationEntry. When all of them have been deleted, or have stopped |
| 1000 | // loading, the pending NavigationEntry can be discarded. |
| 1001 | // |
| 1002 | // This is meant to avoid a class of URL spoofs where the navigation is |
| 1003 | // canceled, but the stale pending NavigationEntry is left in place. |
Ali Hijazi | 133b2d9 | 2024-02-09 14:01:52 | [diff] [blame] | 1004 | std::set<raw_ptr<PendingEntryRef, SetExperimental>> pending_entry_refs_; |
danakj | c492bf8 | 2020-09-09 20:02:44 | [diff] [blame] | 1005 | |
| 1006 | // If a new entry fails loading, details about it are temporarily held here |
| 1007 | // until the error page is shown (or 0 otherwise). |
| 1008 | // |
| 1009 | // TODO(avi): We need a better way to handle the connection between failed |
| 1010 | // loads and the subsequent load of the error page. This current approach has |
| 1011 | // issues: 1. This might hang around longer than we'd like if there is no |
| 1012 | // error page loaded, and 2. This doesn't work very well for frames. |
| 1013 | // http://crbug.com/474261 |
| 1014 | int failed_pending_entry_id_ = 0; |
| 1015 | |
| 1016 | // The index of the currently visible entry. |
| 1017 | int last_committed_entry_index_ = -1; |
| 1018 | |
| 1019 | // The index of the pending entry if it is in entries_, or -1 if |
| 1020 | // pending_entry_ is a new entry (created by LoadURL). |
| 1021 | int pending_entry_index_ = -1; |
| 1022 | |
danakj | f26536bf | 2020-09-10 00:46:13 | [diff] [blame] | 1023 | // The delegate associated with the controller. Possibly null during |
danakj | c492bf8 | 2020-09-09 20:02:44 | [diff] [blame] | 1024 | // setup. |
Keishi Hattori | 0e45c02 | 2021-11-27 09:25:52 | [diff] [blame] | 1025 | raw_ptr<NavigationControllerDelegate> delegate_; |
danakj | c492bf8 | 2020-09-09 20:02:44 | [diff] [blame] | 1026 | |
| 1027 | // Manages the SSL security UI. |
| 1028 | SSLManager ssl_manager_; |
| 1029 | |
| 1030 | // Whether we need to be reloaded when made active. |
| 1031 | bool needs_reload_ = false; |
| 1032 | |
| 1033 | // Source of when |needs_reload_| is set. Only valid when |needs_reload_| |
| 1034 | // is set. |
| 1035 | NeedsReloadType needs_reload_type_ = NeedsReloadType::kRequestedByClient; |
| 1036 | |
| 1037 | // Whether this is the initial navigation. |
| 1038 | // Becomes false when initial navigation commits. |
| 1039 | bool is_initial_navigation_ = true; |
| 1040 | |
| 1041 | // Prevent unsafe re-entrant calls to NavigateToPendingEntry. |
| 1042 | bool in_navigate_to_pending_entry_ = false; |
| 1043 | |
Minoru Chikamune | 646eba4 | 2025-04-14 01:25:03 | [diff] [blame] | 1044 | // A flag to investigate whether kAvoidUnnecessaryBeforeUnloadCheckSync |
| 1045 | // feature is safe to enable or not (see: https://crbug.com/40361673, |
| 1046 | // https://crbug.com/396998476). |
| 1047 | // |
| 1048 | // This flag is true if the above `in_navigate_to_pending_entry_` flag is true |
| 1049 | // when RenderFrameHostImpl::SendBeforeUnload() runs, and on top of that, when |
| 1050 | // we intend to continue navigation synchronously without posting a task when |
| 1051 | // the kAvoidUnnecessaryBeforeUnloadCheckSync feature is enabled in either |
| 1052 | // kWithSendBeforeUnload or kWithoutSendBeforeUnload mode. |
| 1053 | bool can_be_in_navigate_to_pending_entry_ = false; |
| 1054 | |
danakj | c492bf8 | 2020-09-09 20:02:44 | [diff] [blame] | 1055 | // Used to find the appropriate SessionStorageNamespace for the storage |
| 1056 | // partition of a NavigationEntry. |
| 1057 | // |
| 1058 | // A NavigationController may contain NavigationEntries that correspond to |
| 1059 | // different StoragePartitions. Even though they are part of the same |
| 1060 | // NavigationController, only entries in the same StoragePartition may |
| 1061 | // share session storage state with one another. |
| 1062 | SessionStorageNamespaceMap session_storage_namespace_map_; |
| 1063 | |
danakj | c492bf8 | 2020-09-09 20:02:44 | [diff] [blame] | 1064 | // The maximum number of entries that a navigation controller can store. |
| 1065 | static size_t max_entry_count_for_testing_; |
| 1066 | |
| 1067 | // If a repost is pending, its type (RELOAD or RELOAD_BYPASSING_CACHE), |
| 1068 | // NO_RELOAD otherwise. |
| 1069 | ReloadType pending_reload_ = ReloadType::NONE; |
| 1070 | |
| 1071 | // Used to get timestamps for newly-created navigation entries. |
| 1072 | base::RepeatingCallback<base::Time()> get_timestamp_callback_; |
| 1073 | |
| 1074 | // Used to smooth out timestamps from |get_timestamp_callback_|. |
| 1075 | // Without this, whenever there is a run of redirects or |
| 1076 | // code-generated navigations, those navigations may occur within |
| 1077 | // the timer resolution, leading to things sometimes showing up in |
| 1078 | // the wrong order in the history view. |
| 1079 | TimeSmoother time_smoother_; |
| 1080 | |
| 1081 | // BackForwardCache: |
| 1082 | // |
| 1083 | // Stores frozen RenderFrameHost. Restores them on history navigation. |
| 1084 | // See BackForwardCache class documentation. |
| 1085 | BackForwardCacheImpl back_forward_cache_; |
| 1086 | |
William Liu | 055a354 | 2023-04-02 17:21:19 | [diff] [blame] | 1087 | // Stores captured screenshots for this `NavigationController`. The |
| 1088 | // screenshots are used to present the user with the previews of the |
| 1089 | // previously visited pages when the back/forward navigations occur. |
| 1090 | std::unique_ptr<NavigationEntryScreenshotCache> nav_entry_screenshot_cache_; |
| 1091 | |
danakj | c492bf8 | 2020-09-09 20:02:44 | [diff] [blame] | 1092 | // Holds the entry that was committed at the time an error page was triggered |
| 1093 | // due to a call to LoadPostCommitErrorPage. The error entry will take its |
| 1094 | // place until the user navigates again, at which point it will go back into |
| 1095 | // the entry list instead of the error entry. Set to nullptr if there is no |
| 1096 | // post commit error entry. Note that this entry must always correspond to the |
| 1097 | // last committed entry index, and that there can be only a single post-commit |
| 1098 | // error page entry in its place in entries_. This ensures that its spot in |
| 1099 | // entries_ cannot go away (e.g., due to PruneForwardEntries) and that it can |
| 1100 | // go back into place after any subsequent commit. |
| 1101 | std::unique_ptr<NavigationEntryImpl> entry_replaced_by_post_commit_error_; |
| 1102 | |
| 1103 | // NOTE: This must be the last member. |
| 1104 | base::WeakPtrFactory<NavigationControllerImpl> weak_factory_{this}; |
danakj | c492bf8 | 2020-09-09 20:02:44 | [diff] [blame] | 1105 | }; |
| 1106 | |
| 1107 | } // namespace content |
| 1108 | |
| 1109 | #endif // CONTENT_BROWSER_RENDERER_HOST_NAVIGATION_CONTROLLER_IMPL_H_ |