Living Standard — Last Updated 10 September 2025
Welcome to the dragon's maw. Navigation, session history, and the traversal through that session history are some of the most complex parts of this standard.
The basic concept may not seem so difficult:
The user is looking at a navigable that is presenting its active document. They navigate it to another URL.
The browser fetches the given URL from the network, using it to populate a new session history entry
with a newly-created
Document
.
The browser updates the navigable's active session history entry to the newly-populated one, and thus updates the active document that it is showing to the user.
At some point later, the user presses the browser back button to go back to the previous session history entry.
The browser looks at the URL stored in that session history entry, and uses it to re-fetch and populate that entry's document.
The browser again updates the navigable's active session history entry.
You can see some of the intertwined complexity peeking through here, in how traversal can cause a navigation (i.e., a network fetch to a stored URL), and how a navigation necessarily needs to interface with the session history list to ensure that when it finishes the user is looking at the right thing. But the real problems come in with the various edge cases and interacting web platform features:
Child navigables (e.g., those contained in
iframe
s) can also navigate and traverse, but those navigations need to be
linearized into a single session history list
since the user only has a single back/forward interface for the entire traversable
navigable (e.g., browser tab).
Since the user can traverse back more than a single step in the session history (e.g., by holding down their back button), they can end up traversing multiple navigables at the same time when child navigables are involved. This needs to be synchronized across all of the involved navigables, which might involve multiple event loops or even agent clusters.
During navigation, servers can respond with 204 or 205 status codes or with `Content-Disposition: attachment
` headers, which cause
navigation to abort and the navigable to stay on its original active document. (This is much worse if it happens during a traversal-initiated
navigation!)
Various other HTTP headers, such as `Location
`,
`Refresh
`, `X-Frame-Options
`, and those for Content Security Policy,
contribute to either the fetching
process, or the Document
-creation
process, or both. The `Cross-Origin-Opener-Policy
` header even contributes
to the browsing
context selection and creation process!
Some navigations (namely fragment navigations and single-page app navigations) are synchronous, meaning that JavaScript code expects to observe the navigation's results instantly. This then needs to be synchronized with the view of the session history that all other navigables in the tree see, which can be subject to race conditions and necessitate resolving conflicting views of the session history.
The platform has accumulated various exciting navigation-related features that need
special-casing, such as javascript:
URLs, srcdoc
iframe
s, and the beforeunload
event.
In what follows, we have attempted to guide the reader through these complexities by appropriately cordoning them off into labeled sections and algorithms, and giving appropriate words of introduction where possible. Nevertheless, if you wish to truly understand navigation and session history, the usual advice will be invaluable.
A session history entry is a struct with the following items:
step, a non-negative integer or "pending
", initially "pending
".
URL, a URL
document state, a document state.
classic history API state, which is serialized state, initially StructuredSerializeForStorage(null).
navigation API state, which is a serialized state, initially StructuredSerializeForStorage(undefined).
navigation API key, which is a string, initially set to the result of generating a random UUID.
navigation API ID, which is a string, initially set to the result of generating a random UUID.
scroll restoration mode, a scroll
restoration mode, initially "auto
".
scroll position data, which is scroll position data for the document's restorable scrollable regions.
persisted user state, which is implementation-defined, initially null
For example, some user agents might want to persist the values of form controls.
User agents that persist the value of form controls are encouraged to also
persist their directionality (the value of the element's dir
attribute). This prevents values from being displayed incorrectly after a history traversal
when the user had originally entered the values with an explicit, non-default
directionality.
To get a session history entry's document, return its document state's document.
Serialized state is a serialization (via StructuredSerializeForStorage) of an object representing a user interface state. We sometimes informally refer to "state objects", which are the objects representing user interface state supplied by the author, or alternately the objects created by deserializing (via StructuredDeserialize) serialized state.
Pages can add serialized state to the session history. These are then deserialized and returned to the script when the user (or script) goes back in the history, thus enabling authors to use the "navigation" metaphor even in one-page applications.
Serialized state is intended to be used for two main purposes: first, storing a
preparsed description of the state in the URL so that in the simple case an author
doesn't have to do the parsing (though one would still need the parsing for handling URLs passed around by users, so it's only a minor optimization). Second, so
that the author can store state that one wouldn't store in the URL because it only applies to the
current Document
instance and it would have to be reconstructed if a new
Document
were opened.
An example of the latter would be something like keeping track of the precise coordinate from
which a popup div
was made to animate, so that if the user goes back, it can be made
to animate to the same location. Or alternatively, it could be used to keep a pointer into a
cache of data that would be fetched from the server based on the information in the
URL, so that when going back and forward, the information doesn't have to be fetched
again.
A scroll restoration mode indicates whether the user agent should restore the persisted scroll position (if any) when traversing to an entry. A scroll restoration mode is one of the following:
auto
"manual
"Document state holds state inside a session history entry regarding
how to present and, if necessary, recreate, a Document
. It has:
A document, a Document
or null,
initially null.
When a history entry is active, it has a
Document
in its document state. However,
when a Document
is not fully active, it's possible for it to be
destroyed to free resources. In such cases, this
document item will be nulled out. The URL and other data in the session history entry and document state is then used to bring a new
Document
into being to take the place of the original, in the case where the user
agent finds itself having to traverse to the entry.
If the Document
is not destroyed, then during history
traversal, it can be reactivated. The cache
in which browsers store such Document
s is often called a back-forward
cache, or bfcache (or perhaps "blazingly fast" cache).
A history policy container, a policy container or null, initially null.
A request referrer, which is "no-referrer
", "client
", or a URL, initially
"client
".
A request referrer policy, which is a referrer policy, initially the default referrer policy.
The request referrer policy is distinct from the history policy container's referrer policy. The former is used for fetches of this document, whereas the latter controls fetches by this document.
An initiator origin, which is an origin or null, initially null.
An origin, which is an origin or null, initially null.
This is the origin that we set "about:
"-schemed
Document
s' origin to. We store it
here because it is also used when restoring these Document
s during traversal,
since they are reconstructed locally without visiting the network. It is also used to compare
the origin before and after the session history entry is repopulated. If the origins change, the navigable target name is cleared.
An about base URL, which is a URL or null, initially null.
This will be populated only for "about:
"-schemed
Document
s and will be the fallback base URL for those
Document
s. It is a snapshot of the initiator Document
's document
base URL.
Nested histories, a list of nested histories, initially an empty list.
A resource, a string, POST resource or null, initially null.
A string is treated as HTML. It's used to store the source of an iframe
srcdoc
document.
A reload pending boolean, initially false.
An ever populated boolean, initially false.
A navigable target name string, initially the empty string.
A not restored reasons, a not restored reasons or null, initially null.
User agents may destroy a document and its descendants given the documents of document
states with non-null documents, as long as
the Document
is not fully active.
Apart from that restriction, this standard does not specify when user agents should destroy the document stored in a document state, versus keeping it cached.
A POST resource has:
A request body, a byte sequence or failure.
This is only ever accessed in parallel, so it doesn't need to be stored in memory. However, it must return the same byte sequence each time. If this isn't possible due to resources changing on disk, or if resources can no longer be accessed, then this must be set to failure.
A request
content-type, which is `application/x-www-form-urlencoded
`,
`multipart/form-data
`, or `text/plain
`.
A nested history has:
An id, a unique internal value.
This is used to associate the nested history with a navigable.
Entries, a list of session history entries.
This will later contain ways to identify a child navigable across reloads.
Several contiguous entries in a session history can share the same document state. This can occur when the initial entry is
reached via normal navigation, and the following entry is added
via history.pushState()
. Or it can occur via navigation to a fragment.
All entries that share the same document state (and that are therefore merely different states of one particular document) are contiguous by construction.
A Document
has a latest entry, a session history entry or
null.
This is the entry that was most recently represented by a given
Document
. A single Document
can represent many session history entries over time, as many contiguous session history entries can share the same document state as explained above.
To maintain a single source of truth, all modifications to a traversable navigable's session history entries need to be synchronized. This is especially important due to how session history is influenced by all of the descendant navigables, and thus by multiple event loops. To accomplish this, we use the session history traversal parallel queue structure.
A session history traversal parallel queue is very similar to a parallel queue. It has an algorithm set, an ordered set.
The items in a session history traversal parallel queue's algorithm set are either algorithm steps, or synchronous navigation steps, which are a particular brand of algorithm steps involving a target navigable (a navigable).
To append session history traversal steps to a traversable navigable traversable given algorithm steps steps, append steps to traversable's session history traversal queue's algorithm set.
To append session history synchronous navigation steps involving a navigable targetNavigable to a traversable navigable traversable given algorithm steps steps, append steps as synchronous navigation steps targeting target navigable targetNavigable to traversable's session history traversal queue's algorithm set.
To start a new session history traversal parallel queue:
Let sessionHistoryTraversalQueue be a new session history traversal parallel queue.
Run the following steps in parallel:
While true:
If sessionHistoryTraversalQueue's algorithm set is empty, then continue.
Let steps be the result of dequeuing from sessionHistoryTraversalQueue's algorithm set.
Run steps.
Return sessionHistoryTraversalQueue.
This section contains a miscellaneous grab-bag of operations that we perform throughout the standard when manipulating session history. The best way to get a sense of what they do is to look at their call sites.
To get session history entries of a navigable navigable:
Let traversable be navigable's traversable navigable.
Assert: this is running within traversable's session history traversal queue.
If navigable is traversable, return traversable's session history entries.
Let docStates be an empty ordered set of document states.
For each entry of traversable's session history entries, append entry's document state to docStates.
For each docState of docStates:
For each nestedHistory of docState's nested histories:
Assert: this step is not reached.
To get session history entries for the navigation API of a navigable navigable given an integer targetStep:
Let rawEntries be the result of getting session history entries for navigable.
Let entriesForNavigationAPI be a new empty list.
Let startingIndex be the index of the session history entry in rawEntries who has the greatest step less than or equal to targetStep.
See this example to understand why it's the greatest step less than or equal to targetStep.
Append rawEntries[startingIndex] to entriesForNavigationAPI.
Let startingOrigin be rawEntries[startingIndex]'s document state's origin.
Let i be startingIndex − 1.
While i > 0:
If rawEntries[i]'s document state's origin is not same origin with startingOrigin, then break.
Prepend rawEntries[i] to entriesForNavigationAPI.
Set i to i − 1.
Set i to startingIndex + 1.
While i < rawEntries's size:
If rawEntries[i]'s document state's origin is not same origin with startingOrigin, then break.
Append rawEntries[i] to entriesForNavigationAPI.
Set i to i + 1.
Return entriesForNavigationAPI.
To clear the forward session history of a traversable navigable navigable:
Assert: this is running within navigable's session history traversal queue.
Let step be the navigable's current session history step.
Let entryLists be the ordered set « navigable's session history entries ».
For each entryList of entryLists:
Remove every session history entry from entryList that has a step greater than step.
For each entry of entryList:
For each nestedHistory of entry's document state's nested histories, append nestedHistory's entries list to entryLists.
To get all used history steps that are part of traversable navigable traversable:
Assert: this is running within traversable's session history traversal queue.
Let steps be an empty ordered set of non-negative integers.
Let entryLists be the ordered set « traversable's session history entries ».
For each entryList of entryLists:
For each entry of entryList:
For each nestedHistory of entry's document state's nested histories, append nestedHistory's entries list to entryLists.
Return steps, sorted.
Certain actions cause a navigable to navigate to a new resource.
For example, following a hyperlink,
form submission, and the window.open()
and location.assign()
methods can all cause navigation.
Before we can jump into the navigation algorithm itself, we need to establish several important structures that it uses.
The source snapshot params struct is used to capture data from a
Document
initiating a navigation. It is snapshotted at the beginning of a navigation
and used throughout the navigation's lifetime. It has the following items:
To snapshot source snapshot params
given a Document
-or-null sourceDocument:
If sourceDocument is null, then return a new source snapshot params with
This only occurs in the case of a browser UI-initiated navigation.
Return a new source snapshot params with
The target snapshot params struct is used to capture data from a navigable being navigated. Like source snapshot params, it is snapshotted at the beginning of a navigation and used throughout the navigation's lifetime. It has the following items:
To snapshot target snapshot params given a navigable targetNavigable, return a new target snapshot params with sandboxing flags set to the result of determining the creation sandboxing flags given targetNavigable's active browsing context and targetNavigable's container.
Much of the navigation process is concerned with determining how to create a new
Document
, which ultimately happens in the create and initialize a Document
object
algorithm. The parameters to that algorithm are tracked via a navigation params
struct, which has the following items:
Document
, once it has been createdDocument
Document
Document
Document
Document
NavigationTimingType
used for creating the navigation timing entry for the new Document
Document
's about base URLDocument
Once a navigation params struct is created, this standard does not mutate any of its items. They are only passed onward to other algorithms.
A navigation ID is a UUID string generated during navigation. It is used to interface with the WebDriver BiDi specification as well as to track the ongoing navigation. [WEBDRIVERBIDI]
After Document
creation, the relevant traversable navigable's session history gets updated. The
NavigationHistoryBehavior
enumeration is used to indicate the desired type of session
history update to the navigate algorithm. It is one of the following:
push
"replace
"auto
"push
" or "replace
". Usually it becomes "push
", but under certain circumstances it becomes "replace
" instead.A history handling behavior is a NavigationHistoryBehavior
that is
either "push
" or "replace
", i.e., that has been resolved away from
any initial "auto
" value.
The navigation must be a replace, given a URL url and a
Document
document, if any of the following are true:
url's scheme is "javascript
"; or
document's is initial about:blank
is true.
Other cases that often, but not always, force a "replace
" navigation are:
if the Document
is not completely loaded; or
Various parts of the platform track whether a user is involved in a navigation. A user navigation involvement is one of the following:
browser UI
"activation
"none
"For convenience at certain call sites, the user navigation
involvement for an Event
event is defined as follows:
Assert: this algorithm is being called as part of an activation behavior definition.
If event's isTrusted
is initialized
to true, then return "activation
".
Return "none
".
To navigate a navigable navigable to a
URL url using an optional Document
-or-null sourceDocument (default null), with an optional POST
resource, string, or null documentResource (default null), an optional response-or-null response (default null), an optional boolean exceptionsEnabled (default false), an optional
NavigationHistoryBehavior
historyHandling (default "auto
"), an optional serialized
state-or-null navigationAPIState (default null), an optional entry list or
null formDataEntryList (default null), an optional referrer policy
referrerPolicy (default the empty
string), an optional user navigation involvement userInvolvement (default "none
"), an optional Element
sourceElement (default null), and an
optional boolean initialInsertion (default
false):
Let cspNavigationType be "form-submission
" if
formDataEntryList is non-null; otherwise "other
".
Let sourceSnapshotParams be the result of snapshotting source snapshot params given sourceDocument.
Let initiatorOriginSnapshot be a new opaque origin.
Let initiatorBaseURLSnapshot be about:blank
.
If sourceDocument is null:
Assert: userInvolvement is
"browser UI
".
If url's scheme is "javascript
", then set initiatorOriginSnapshot to
navigable's active document's origin.
Otherwise:
Assert: userInvolvement is not "browser UI
".
If sourceDocument's node navigable is not allowed by sandboxing to navigate navigable given sourceSnapshotParams:
If exceptionsEnabled is true, then throw a
"SecurityError
" DOMException
.
Return.
Set initiatorOriginSnapshot to sourceDocument's origin.
Set initiatorBaseURLSnapshot to sourceDocument's document base URL.
Let navigationId be the result of generating a random UUID. [WEBCRYPTO]
If the surrounding agent is equal to navigable's active document's relevant agent, then continue these steps. Otherwise, queue a global task on the navigation and traversal task source given navigable's active window to continue these steps.
We do this because we are about to look at a lot of properties of navigable's active document, which are in theory only accessible over in the appropriate event loop. (But, we do not want to unconditionally queue a task, since — for example — same-event-loop fragment navigations need to take effect synchronously.)
Another implementation strategy would be to replicate the relevant information across event loops, or into a canonical "browser process", so that it can be consulted without queueing a task. This could give different results than what we specify here in edge cases, where the relevant properties have changed over in the target event loop but not yet been replicated. Further testing is needed to determine which of these strategies best matches browser behavior, in such racy edge cases.
If navigable's active document's
unload counter is greater than 0, then invoke WebDriver BiDi navigation
failed with navigable and a WebDriver BiDi navigation status whose
id is navigationId, status is "canceled
", and url is url, and return.
Let container be navigable's container.
If container is an iframe
element and will lazy load
element steps given container returns true, then stop
intersection-observing a lazy loading element container and set
container's lazy load resumption steps to null.
If the navigation must be a replace given url and
navigable's active document, then set
historyHandling to "replace
".
If navigable's parent is non-null, then set
navigable's is delaying load
events to
true.
Let targetSnapshotParams be the result of snapshotting target snapshot params given navigable.
Invoke WebDriver BiDi navigation started with navigable and a new
WebDriver BiDi navigation status whose id
is navigationId, status is "pending
", and url is url.
If navigable's ongoing navigation is "traversal
", then:
Invoke WebDriver BiDi navigation failed with navigable and a new
WebDriver BiDi navigation status whose id is navigationId, status is "canceled
", and url is url.
Return.
Any attempts to navigate a navigable that is currently traversing are ignored.
Set the ongoing navigation for navigable to navigationId.
This will have the effect of aborting other ongoing navigations of navigable, since at certain points during navigation changes to the ongoing navigation will cause further work to be abandoned.
If url's scheme is "javascript
", then:
Queue a global task on the navigation and traversal task
source given navigable's active window to
navigate to a javascript:
URL given navigable,
url, historyHandling, sourceSnapshotParams,
initiatorOriginSnapshot, userInvolvement,
cspNavigationType, and initialInsertion.
Return.
If all of the following are true:
userInvolvement is not "browser
UI
";
navigable's active document's origin is same origin-domain with sourceDocument's origin;
navigable's active document's is
initial about:blank
is false; and
url's scheme is a fetch scheme,
then:
Let navigation be navigable's active window's navigation API.
Let entryListForFiring be formDataEntryList if documentResource is a POST resource; otherwise, null.
Let navigationAPIStateForFiring be navigationAPIState if navigationAPIState is not null; otherwise, StructuredSerializeForStorage(undefined).
Let continue be the result of firing a push/replace/reload navigate
event at navigation with navigationType set to historyHandling,
isSameDocument set to false, userInvolvement set to
userInvolvement, sourceElement set
to sourceElement, formDataEntryList set to
entryListForFiring, destinationURL
set to url, and navigationAPIState set to
navigationAPIStateForFiring.
If continue is false, then return.
It is possible for navigations with userInvolvement of "browser UI
" or initiated by a cross origin-domain sourceDocument to fire navigate
events, if they go through the earlier navigate to a fragment path.
If sourceDocument is navigable's container document, then reserve deferred fetch quota for navigable's container given url's origin.
In parallel, run these steps:
Let unloadPromptCanceled be the result of checking if unloading is canceled for navigable's active document's inclusive descendant navigables.
If unloadPromptCanceled is not "continue
", or
navigable's ongoing navigation is no longer
navigationId:
Invoke WebDriver BiDi navigation failed with navigable and a
new WebDriver BiDi navigation status whose id is navigationId, status is "canceled
", and url is url.
Abort these steps.
Queue a global task on the navigation and traversal task source given navigable's active window to abort a document and its descendants given navigable's active document.
If url matches about:blank
or
is about:srcdoc
, then:
Set documentState's origin to initiatorOriginSnapshot.
Set documentState's about base URL to initiatorBaseURLSnapshot.
Let historyEntry be a new session history entry, with its URL set to url and its document state set to documentState.
Let navigationParams be null.
If response is non-null:
Let sourcePolicyContainer be a clone of the sourceDocument's policy container, if sourceDocument is not null; otherwise null.
Let policyContainer be the result of determining navigation params policy container given response's URL, null, sourcePolicyContainer, navigable's container document's policy container, and null.
Let finalSandboxFlags be the union of targetSnapshotParams's sandboxing flags and policyContainer's CSP list's CSP-derived sandboxing flags.
Let responseOrigin be the result of determining the origin given response's URL, finalSandboxFlags, and documentState's initiator origin.
Let coop be a new opener policy.
Let coopEnforcementResult be a new opener policy enforcement result with
Set navigationParams to a new navigation params, with
navigate
"Attempt to populate the history entry's document for historyEntry,
given navigable, "navigate
", sourceSnapshotParams,
targetSnapshotParams, userInvolvement, navigationId,
navigationParams, cspNavigationType, with allowPOST set to true and completionSteps set to the following
step:
Append session history traversal steps to navigable's traversable to finalize a cross-document navigation given navigable, historyHandling, userInvolvement, and historyEntry.
Although the usual cross-document navigation case will first foray into populating a session history entry with a
Document
, all navigations that don't get aborted will ultimately end up calling into
one of the below algorithms.
To finalize a cross-document navigation given a navigable navigable, a history handling behavior historyHandling, a user navigation involvement userInvolvement, and a session history entry historyEntry:
Assert: this is running on navigable's traversable navigable's session history traversal queue.
Set navigable's is delaying load
events to false.
If historyEntry's document is null, then return.
This means that attempting to populate the history entry's document ended up not creating a document, as a result of e.g., the navigation being canceled by a subsequent navigation, a 204 No Content response, etc.
If all of the following are true:
navigable's parent is null;
historyEntry's document's browsing context is not an auxiliary browsing context whose opener browsing context is non-null; and
historyEntry's document's origin is not navigable's active document's origin,
then set historyEntry's document state's navigable target name to the empty string.
Let entryToReplace be navigable's active session history entry if
historyHandling is "replace
",
otherwise null.
Let traversable be navigable's traversable navigable.
Let targetStep be null.
Let targetEntries be the result of getting session history entries for navigable.
If entryToReplace is null, then:
Clear the forward session history of traversable.
Set targetStep to traversable's current session history step + 1.
Set historyEntry's step to targetStep.
Append historyEntry to targetEntries.
Otherwise:
Replace entryToReplace with historyEntry in targetEntries.
If historyEntry's document state's origin is same origin with entryToReplace's document state's origin, then set historyEntry's navigation API key to entryToReplace's navigation API key.
Set targetStep to traversable's current session history step.
Apply the push/replace history step targetStep to traversable given historyHandling and userInvolvement.
javascript:
URL special casejavascript:
URLs have a dedicated label
on the issue tracker documenting various problems with their specification.
To navigate to a javascript:
URL, given a navigable
targetNavigable, a URL url, a history handling
behavior historyHandling, a source snapshot params
sourceSnapshotParams, an origin initiatorOrigin, a user
navigation involvement userInvolvement, a string
cspNavigationType, and a boolean initialInsertion:
Set the ongoing navigation for targetNavigable to null.
If initiatorOrigin is not same origin-domain with targetNavigable's active document's origin, then return.
Let request be a new request whose URL is url and whose policy container is sourceSnapshotParams's source policy container.
This is a synthetic request solely for plumbing into the next step. It will never hit the network.
If the result of should navigation request of type be blocked by Content Security
Policy? given request and cspNavigationType is "Blocked
", then return. [CSP]
Let newDocument be the result of evaluating a javascript:
URL given targetNavigable,
url, initiatorOrigin, and userInvolvement.
If newDocument is null:
If initialInsertion is true and targetNavigable's active document's is initial
about:blank
is true, then run the iframe load event steps
given targetNavigable's container.
Return.
In this case, some JavaScript code was executed, but no new
Document
was created, so we will not perform a navigation.
Let entryToReplace be targetNavigable's active session history entry.
Let oldDocState be entryToReplace's document state.
Let documentState be a new document state with
Let historyEntry be a new session history entry, with
For the URL, we do not use
url, i.e. the actual javascript:
URL that
the navigate algorithm was called with. This means javascript:
URLs are never stored in session history, and so can never be
traversed to.
Append session history traversal steps to targetNavigable's traversable to finalize a cross-document navigation with targetNavigable, historyHandling, userInvolvement, and historyEntry.
To evaluate a javascript:
URL given a navigable
targetNavigable, a URL url, an origin
newDocumentOrigin, and a user navigation involvement
userInvolvement:
Let urlString be the result of running the URL serializer on url.
Let encodedScriptSource be the result of removing the leading "javascript:
" from urlString.
Let scriptSource be the UTF-8 decoding of the percent-decoding of encodedScriptSource.
Let settings be targetNavigable's active document's relevant settings object.
Let baseURL be settings's API base URL.
Let script be the result of creating a classic script given scriptSource, settings, baseURL, and the default script fetch options.
Let evaluationStatus be the result of running the classic script script.
Let result be null.
If evaluationStatus is a normal completion, and evaluationStatus.[[Value]] is a String, then set result to evaluationStatus.[[Value]].
Otherwise, return null.
Let response be a new response with
Content-Type
`, `text/html;charset=utf-8
`) »The encoding to UTF-8 means that unpaired surrogates will not roundtrip, once the HTML parser decodes the response body.
Let policyContainer be targetNavigable's active document's policy container.
Let finalSandboxFlags be policyContainer's CSP list's CSP-derived sandboxing flags.
Let coop be targetNavigable's active document's opener policy.
Let coopEnforcementResult be a new opener policy enforcement result with
Let navigationParams be a new navigation params, with
Document
to be null; is that correct?navigate
"Return the result of loading an HTML document given navigationParams.
To navigate to a fragment given a navigable
navigable, a URL url, a history handling behavior
historyHandling, a user navigation involvement userInvolvement,
an Element
-or-null sourceElement, a serialized state-or-null
navigationAPIState, and a navigation ID navigationId:
Let navigation be navigable's active window's navigation API.
Let destinationNavigationAPIState be navigable's active session history entry's navigation API state.
If navigationAPIState is not null, then set destinationNavigationAPIState to navigationAPIState.
Let continue be the result of firing a push/replace/reload navigate
event at
navigation with navigationType set to
historyHandling, isSameDocument set
to true, userInvolvement set to
userInvolvement, sourceElement set
to sourceElement, destinationURL
set to url, and navigationAPIState set to
destinationNavigationAPIState.
If continue is false, then return.
Let historyEntry be a new session history entry, with
For navigations performed with navigation.navigate()
, the value provided by the state
option is used for the new navigation API state. (This will set it to the
serialization of undefined, if no value is provided for that option.) For other fragment
navigations, including user-initiated ones, the navigation API state is carried over from the previous
entry.
The classic history API state is never carried over.
Let entryToReplace be navigable's active session history entry if
historyHandling is "replace
",
otherwise null.
Let history be navigable's active document's history object.
Let scriptHistoryIndex be history's index.
Let scriptHistoryLength be history's length.
If historyHandling is "push
",
then:
Set history's state to null.
Increment scriptHistoryIndex.
Set scriptHistoryLength to scriptHistoryIndex + 1.
Set navigable's active document's URL to url.
Set navigable's active session history entry to historyEntry.
Update document for history step application given navigable's active document, historyEntry, true, scriptHistoryIndex, scriptHistoryLength, and historyHandling.
This algorithm will be called twice as a result of a single fragment
navigation: once synchronously, where best-guess values scriptHistoryIndex and
scriptHistoryLength are set, history.state
is nulled out, and various events are fired; and once asynchronously, where the final values for
index and length are set, history.state
remains
untouched, and no events are fired.
Scroll to the fragment given navigable's active document.
If the scrolling fails because the Document
is new and the
relevant ID has not yet been parsed, then the second
asynchronous call to update document for history step application will take
care of scrolling.
Let traversable be navigable's traversable navigable.
Append the following session history synchronous navigation steps involving navigable to traversable:
Finalize a same-document navigation given traversable, navigable, historyEntry, entryToReplace, historyHandling, and userInvolvement.
Invoke WebDriver BiDi fragment navigated with navigable and a
new WebDriver BiDi navigation status whose id is navigationId, url is url, and status is "complete
".
To finalize a same-document navigation given a traversable navigable traversable, a navigable targetNavigable, a session history entry targetEntry, a session history entry-or-null entryToReplace, a history handling behavior historyHandling, and a user navigation involvement userInvolvement:
This is used by both fragment navigations and by the URL and history update steps, which are the only synchronous updates to session history. By virtue of being synchronous, those algorithms are performed outside of the top-level traversable's session history traversal queue. This puts them out of sync with the top-level traversable's current session history step, so this algorithm is used to resolve conflicts due to race conditions.
Assert: this is running on traversable's session history traversal queue.
If targetNavigable's active session history entry is not targetEntry, then return.
Let targetStep be null.
Let targetEntries be the result of getting session history entries for targetNavigable.
If entryToReplace is null, then:
Clear the forward session history of traversable.
Set targetStep to traversable's current session history step + 1.
Set targetEntry's step to targetStep.
Append targetEntry to targetEntries.
Otherwise:
Replace entryToReplace with targetEntry in targetEntries.
Set targetStep to traversable's current session history step.
Apply the push/replace history step targetStep to traversable given historyHandling and userInvolvement.
This is done even for "replace
" navigations, as it resolves race
conditions across multiple synchronous navigations.
The input to attempt to create a non-fetch scheme document is the non-fetch scheme navigation params struct. It is a lightweight version of navigation params which only carries parameters relevant to the non-fetch scheme navigation case. It has the following items:
an origin possibly for use in a user-facing prompt to confirm the invocation of an external software package
This differs slightly from a document state's initiator origin in that a non-fetch scheme navigation params's initiator origin follows redirects up to the last fetch scheme URL in a redirect chain that ends in a non-fetch scheme URL.
NavigationTimingType
used for creating the navigation timing entry for the new Document
(if one is
created)Document
(if one is created)If url is to be handled using a mechanism that does not affect navigable, e.g., because url's scheme is handled externally, then:
Hand-off to external software given url, navigable, navigationParams's target snapshot sandboxing flags, navigationParams's source snapshot has transient activation, and navigationParams's initiator origin.
Return null.
Handle url by displaying some sort of inline content, e.g., an error message because the specified scheme is not one of the supported protocols, or an inline prompt to allow the user to select a registered handler for the given scheme. Return the result of displaying the inline content given navigable, navigationParams's id, navigationParams's navigation timing type, and navigationParams's user involvement.
In the case of a registered handler being used, navigate will be invoked with a new URL.
To hand-off to external software given a URL or response resource, a navigable navigable, a sandboxing flag set sandboxFlags, a boolean hasTransientActivation, and an origin initiatorOrigin, user agents should:
If all of the following are true:
navigable is not a top-level traversable;
sandboxFlags has its sandboxed custom protocols navigation browsing context flag set; and
sandboxFlags has its sandboxed top-level navigation with user activation browsing context flag set, or hasTransientActivation is false,
then return without invoking the external software package.
Navigation inside an iframe toward external software can be seen by users as a
new popup or a new top-level navigation. That's why its is allowed in sandboxed
iframe
only when one of allow-popups
, allow-top-navigation
, allow-top-navigation-by-user-activation
,
or allow-top-navigation-to-custom-protocols
is specified.
Perform the appropriate handoff of resource while attempting to mitigate the risk that this is an attempt to exploit the target software. For example, user agents could prompt the user to confirm that initiatorOrigin is to be allowed to invoke the external software in question. In particular, if hasTransientActivation is false, then the user agent should not invoke the external software package without prior user confirmation.
For example, there could be a vulnerability in the target software's URL handler which a hostile page would attempt to exploit by tricking a user into clicking a link.
A couple of scenarios can intervene early in the navigation process and put the whole thing to a halt. This can be especially exciting when multiple navigables are navigating at the same time, due to a session history traversal.
A navigable source is allowed by sandboxing to navigate a second navigable target, given a source snapshot params sourceSnapshotParams, if the following steps return true:
If source is target, then return true.
If source is an ancestor of target, then return true.
If target is an ancestor of source, then:
If target is not a top-level traversable, then return true.
If sourceSnapshotParams's has transient activation is true, and sourceSnapshotParams's sandboxing flags's sandboxed top-level navigation with user activation browsing context flag is set, then return false.
If sourceSnapshotParams's has transient activation is false, and sourceSnapshotParams's sandboxing flags's sandboxed top-level navigation without user activation browsing context flag is set, then return false.
Return true.
If target is a top-level traversable:
If source is the one permitted sandboxed navigator of target, then return true.
If sourceSnapshotParams's sandboxing flags's sandboxed navigation browsing context flag is set, then return false.
Return true.
If sourceSnapshotParams's sandboxing flags's sandboxed navigation browsing context flag is set, then return false.
Return true.
To check if unloading is canceled for a list of navigables navigablesThatNeedBeforeUnload, given an optional
traversable navigable traversable, an optional integer
targetStep, and an optional user navigation involvement
userInvolvementForNavigateEvent, run these steps. They return "canceled-by-beforeunload
", "canceled-by-navigate
", or
"continue
".
Let documentsToFireBeforeunload be the active document of each item in navigablesThatNeedBeforeUnload.
Let unloadPromptShown be false.
Let finalStatus be "continue
".
If traversable was given, then:
Assert: targetStep and userInvolvementForNavigateEvent were given.
Let targetEntry be the result of getting the target history entry given traversable and targetStep.
If targetEntry is not traversable's current session history entry, and targetEntry's document state's origin is the same as traversable's current session history entry's document state's origin, then:
In this case, we're going to fire the navigate
event
for traversable here. Because under some circumstances it might be
canceled, we need to do this separately from other traversal navigate
events, which happen later.
Additionally, because we want beforeunload
events
to fire before navigate
events, this means we need to
fire beforeunload
for traversable here
(if applicable), instead of doing it as part of the below loop over
documentsToFireBeforeunload.
Let eventsFired be false.
Let needsBeforeunload be true if navigablesThatNeedBeforeUnload contains traversable; otherwise false.
If needsBeforeunload is true, then remove traversable's active document from documentsToFireBeforeunload.
Queue a global task on the navigation and traversal task source given traversable's active window to perform the following steps:
If needsBeforeunload is true, then:
Let (unloadPromptShownForThisDocument,
unloadPromptCanceledByThisDocument) be the result of running the steps
to fire beforeunload
given
traversable's active document and
false.
If unloadPromptShownForThisDocument is true, then set unloadPromptShown to true.
If unloadPromptCanceledByThisDocument is true, then set
finalStatus to "canceled-by-beforeunload
".
If finalStatus is "canceled-by-beforeunload
", then
abort these steps.
Let navigation be traversable's active window's navigation API.
Let navigateEventResult be the result of firing a traverse navigate
event at navigation given targetEntry and
userInvolvementForNavigateEvent.
If navigateEventResult is false, then set finalStatus to
"canceled-by-navigate
".
Set eventsFired to true.
Wait until eventsFired is true.
If finalStatus is not "continue
", then return
finalStatus.
Let totalTasks be the size of documentsToFireBeforeunload.
Let completedTasks be 0.
For each document of documentsToFireBeforeunload, queue a global task on the navigation and traversal task source given document's relevant global object to run the steps:
Let (unloadPromptShownForThisDocument,
unloadPromptCanceledByThisDocument) be the result of running the steps to fire
beforeunload
given document and
unloadPromptShown.
If unloadPromptShownForThisDocument is true, then set unloadPromptShown to true.
If unloadPromptCanceledByThisDocument is true, then set
finalStatus to "canceled-by-beforeunload
".
Increment completedTasks.
Wait for completedTasks to be totalTasks.
Return finalStatus.
The steps to fire beforeunload
given a
Document
document and a boolean unloadPromptShown are:
Let unloadPromptCanceled be false.
Increase the document's unload counter by 1.
Increase document's relevant agent's event loop's termination nesting level by 1.
Let eventFiringResult be the result of firing
an event named beforeunload
at
document's relevant global object, using BeforeUnloadEvent
,
with the cancelable
attribute initialized to
true.
Decrease document's relevant agent's event loop's termination nesting level by 1.
If all of the following are true:
unloadPromptShown is false;
document's active sandboxing flag set does not have its sandboxed modals flag set;
document's relevant global object has sticky activation;
eventFiringResult is false, or the returnValue
attribute of event is
not the empty string; and
showing an unload prompt is unlikely to be annoying, deceptive, or pointless,
then:
Set unloadPromptShown to true.
Let userPromptHandler be the result of WebDriver BiDi user prompt
opened with document's relevant global object,
"beforeunload
", and "".
If userPromptHandler is "dismiss
", then set
unloadPromptCanceled to true.
If userPromptHandler is "none
", then:
Ask the user to confirm that they wish to unload the document, and pause while waiting for the user's response.
The message shown to the user is not customizable, but instead determined by
the user agent. In particular, the actual value of the returnValue
attribute is ignored.
If the user did not confirm the page navigation, then set unloadPromptCanceled to true.
Invoke WebDriver BiDi user prompt closed with document's
relevant global object, "beforeunload
", and true
if unloadPromptCanceled is false or false otherwise.
Decrease document's unload counter by 1.
Return (unloadPromptShown, unloadPromptCanceled).
To set the ongoing navigation for a navigable navigable to newValue:
If navigable's ongoing navigation is equal to newValue, then return.
Inform the navigation API about aborting navigation given navigable.
Set navigable's ongoing navigation to newValue.
To reload a navigable navigable given an optional
serialized state-or-null navigationAPIState (default null) and an
optional user navigation involvement userInvolvement (default "none
"):
If userInvolvement is not "browser UI
",
then:
Let navigation be navigable's active window's navigation API.
Let destinationNavigationAPIState be navigable's active session history entry's navigation API state.
If navigationAPIState is not null, then set destinationNavigationAPIState to navigationAPIState.
Let continue be the result of firing a push/replace/reload navigate
event at navigation with navigationType set to "reload
", isSameDocument set to false, userInvolvement set to
userInvolvement, destinationURL
set to navigable's active session history
entry's URL, and navigationAPIState set to
destinationNavigationAPIState.
If continue is false, then return.
Set navigable's active session history entry's document state's reload pending to true.
Let traversable be navigable's traversable navigable.
Append the following session history traversal steps to traversable:
Apply the reload history step to traversable given userInvolvement.
To traverse the history by a delta given a traversable navigable
traversable, an integer delta, and an optional Document
sourceDocument:
Let sourceSnapshotParams and initiatorToCheck be null.
Let userInvolvement be "browser
UI
".
If sourceDocument is given, then:
Set sourceSnapshotParams to the result of snapshotting source snapshot params given sourceDocument.
Set initiatorToCheck to sourceDocument's node navigable.
Set userInvolvement to "none
".
Append the following session history traversal steps to traversable:
Let allSteps be the result of getting all used history steps for traversable.
Let currentStepIndex be the index of traversable's current session history step within allSteps.
Let targetStepIndex be currentStepIndex plus delta.
If allSteps[targetStepIndex] does not exist, then abort these steps.
Apply the traverse history step allSteps[targetStepIndex] to traversable, given sourceSnapshotParams, initiatorToCheck, and userInvolvement.
Apart from the navigate algorithm, session
history entries can be pushed or replaced via one more mechanism, the URL and
history update steps. The most well-known callers of these steps are the history.replaceState()
and history.pushState()
APIs, but various other parts of the
standard also need to perform updates to the active
history entry, and they use these steps to do so.
The URL and history update steps, given a Document
document, a URL newURL, an optional serialized
state-or-null serializedData (default
null), and an optional history handling behavior historyHandling (default "replace
"), are:
Let navigable be document's node navigable.
Let activeEntry be navigable's active session history entry.
Let newEntry be a new session history entry, with
If document's is initial about:blank
is true, then set
historyHandling to "replace
".
This means that pushState()
on an
initial about:blank
Document
behaves as a replaceState()
call.
Let entryToReplace be activeEntry if historyHandling is
"replace
", otherwise null.
If historyHandling is "push
",
then:
Increment document's history object's index.
Set document's history object's length to its index + 1.
These are temporary best-guess values for immediate synchronous access.
If serializedData is not null, then restore the history object state given document and newEntry.
Set the URL given document to newURL.
Since this is neither a navigation nor a history traversal, it does not cause a hashchange
event to be fired.
Set document's latest entry to newEntry.
Set navigable's active session history entry to newEntry.
Update the navigation API entries for a same-document navigation given document's relevant global object's navigation API, newEntry, and historyHandling.
Let traversable be navigable's traversable navigable.
Append the following session history synchronous navigation steps involving navigable to traversable:
Finalize a same-document navigation given traversable,
navigable, newEntry, entryToReplace,
historyHandling, and "none
".
Invoke WebDriver BiDi history updated with navigable.
Although both fragment navigation and the
URL and history update steps perform synchronous history updates, only fragment
navigation contains a synchronous call to update document for history step
application. The URL and history update steps instead perform a few select
updates inside the above algorithm, omitting others. This is somewhat of an unfortunate
historical accident, and generally leads to web-developer sadness about the
inconsistency. For example, this means that popstate
events
fire for fragment navigations, but not for history.pushState()
calls.
As explained in the overview, both navigation and traversal involve creating a session history entry and then attempting to populate its document member, so that it can be presented inside the navigable.
This involves either: using an already-given
response; using the srcdoc resource stored in
the session history entry; or fetching. The process has several failure modes, which can either result in
doing nothing (leaving the navigable on its currently-active Document
) or can result in populating the
session history entry with an error
document.
To attempt to populate the history entry's document for a session history
entry entry, given a navigable navigable, a
NavigationTimingType
navTimingType, a source snapshot params
sourceSnapshotParams, a target snapshot params
targetSnapshotParams, a user navigation involvement
userInvolvement, an optional navigation ID-or-null navigationId
(default null), an optional navigation params-or-null navigationParams
(default null), an optional string cspNavigationType (default "other
"), an optional boolean allowPOST (default false), and optional
algorithm steps completionSteps (default an empty
algorithm):
Assert: this is running in parallel.
Assert: if navigationParams is non-null, then navigationParams's response is non-null.
Let documentResource be entry's document state's resource.
If navigationParams is null, then:
If documentResource is a string, then set navigationParams to the result of creating navigation params from a srcdoc resource given entry, navigable, targetSnapshotParams, userInvolvement, navigationId, and navTimingType.
Otherwise, if all of the following are true:
entry's URL's scheme is a fetch scheme; and
documentResource is null, or allowPOST is true and documentResource's request body is not failure,
then set navigationParams to the result of creating navigation params by fetching given entry, navigable, sourceSnapshotParams, targetSnapshotParams, cspNavigationType, userInvolvement, navigationId, and navTimingType.
Otherwise, if entry's URL's scheme is not a fetch scheme, then set navigationParams to a new non-fetch scheme navigation params, with