blob: 317b190a431ac92d515da4d1e76805b57378e229 [file] [log] [blame] [view]
Charlie Reis358d23a2020-06-15 23:20:521# Session History
2
3A browser's session history keeps track of the navigations in each tab, to
4support back/forward navigations and session restore. This is in contrast to
5"history" (e.g., `chrome://history`), which tracks the main frame URLs the user
6has visited in any tab for the lifetime of a profile.
7
8Chromium tracks the session history of each tab in NavigationController, using a
9list of NavigationEntry objects to represent the joint session history items.
10Each frame creates _session history items_ as it navigates. A _joint session
11history item_ contains the state of each frame of a page at a given point in
12time, including things like URL, partially entered form data, scroll position,
13etc. Each NavigationEntry uses a tree of FrameNavigationEntries to track this
14state.
15
16[TOC]
17
18
19## Pruning Forward Navigations
20
21If the user goes back and then commits a new navigation, this essentially forks
22the joint session history. However, joint session history is tracked as a list
23and not as a tree, so the previous forward history is "pruned" and forgotten.
24This pruning is performed for all new navigations, unless they commit with
25replacement.
26
27
28## Subframe Navigations
29
30When the first commit occurs within a new subframe of a document, it becomes
31part of the existing joint session history item (which we refer to as an "auto
32subframe navigation"). The user can't go back to the state before the frame
33committed. Any subsequent navigations in the subframe create new joint session
34history items (which we refer to as "manual subframe navigations"), such that
35clicking back goes back within the subframe.
36
37
38## Navigating with Replacement
39
40Some types of navigations can replace the previously committed joint session
41history item for a frame, rather than creating a new item. These include:
42
43 * `location.replace` (which is usually cross-document, unless it is a fragment
44 navigation)
45 * `history.replaceState` (which is always same-document)
46 * Client redirects
47 * The first non-blank URL after the initial empty document (unless the frame
48 was explicitly created with `about:blank` as the URL).
49
50
51## Identifying Same- and Cross-Document Navigations
52
53Each FrameNavigationEntry contains both an _item sequence number_ (ISN) and a
54_document sequence number_ (DSN). Same-document navigations create a new session
55history item without changing the document, and thus have a new ISN but the same
56DSN. Cross-document navigations create a new ISN and DSN. NavigationController
57uses these ISNs and DSNs when deciding which frames need to be navigated during
58a session history navigation, using a recursive frame tree walk in
59`FindFramesToNavigate`.
60
61
62## Classifying Navigations
63
64Much of the complexity in NavigationController comes from the bookkeeping needed
65to track the various types of navigations as they commit (e.g., same-document vs
66cross-document, main frame vs subframe, with or without replacement, etc). These
67types may lead to different outcomes for whether a new NavigationEntry is
68created, whether an existing one is updated vs replaced, and what events are
69exposed to observers. This is handled by `ClassifyNavigation`, which determines
70which `RendererDidNavigate` helper methods are used when a navigation commits.
71
72
73## Persistence
74
75The joint session history of a tab is persisted so that tabs can be restored
76(e.g., between Chromium restarts, after closing a tab, or on another device).
77This requires serializing the state in each NavigationEntry and its tree of
78FrameNavigationEntries, using a PageState object and other metadata.
W. James MacLean4aeb4b02023-03-08 20:48:5779See [Modifying Session History Serialization](modifying_session_history_serialization.md)
80for how to safely add new values to be saved and restored.
Charlie Reis358d23a2020-06-15 23:20:5281
82Not everything in NavigationEntry is persisted. All data members of
83NavigationEntryImpl and FrameNavigationEntry should be documented with whether
84they are preserved after commit and whether they need to be persisted.
85
86Note that the session history of a tab can also be cloned when duplicating a
87tab, or when doing a back/forward/reload navigation in a new tab (such as when
88middle-clicking the back/forward/reload button). This involves direct clones of
89NavigationEntries rather than persisting and restoring.
90
91## Invariants
92
93 * The `pending_entry_index_` is either -1 or an index into `entries_`. If
94 `pending_entry_` is defined and `pending_entry_index_` is -1, then it is a
95 new navigation. If `pending_entry_index_` is a valid index into `entries_`,
96 then `pending_entry_` must point to that entry and it is a session history
97 navigation.
98 * Newly created tabs have NavigationControllers with `is_initial_navigation_`
99 set to true. They can have `last_committed_entry_index_` defined before the
100 first commit, however, when session history is cloned from another tab. (In
101 this case, `pending_entry_index_` indicates which entry is going to be
102 restored during the initial navigation.)
103 * Every FrameNavigationEntry that has committed in the current session (as
104 opposed to those that have been restored) must have a SiteInstance.
105 * A renderer process can only update FrameNavigationEntries belonging to a
106 SiteInstance in that process. This especially includes attacker-controlled
107 data like PageState, which could be dangerous to load into a different
108 site's process.
109 * Any cross-SiteInstance navigation should result in a new NavigationEntry
110 with replacement, rather than updating an existing NavigationEntry.
111
112
113## Caveats
114
115 * Not every NavigationRequest has a pending NavigationEntry. For example,
116 subframe navigations do not, and renderer-initiated main frame navigations
117 may clear an existing browser-initiated pending NavigationEntry (using
118 PendingEntryRef) without replacing it with a new one.
Charlie Reis358d23a2020-06-15 23:20:52119 * Some subframe documents may not have a corresponding FrameNavigationEntry
120 after commit (e.g., see [issue 608402](https://crbug.com/608402)).