Living
Standard
—
Last
Updated
10
11
March
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
sourceDocument
,
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
created
Document
Document
Document
Document
Document
NavigationTimingType
used
for
creating
the
navigation
timing
entry
for
the
new
Document
Document
's
about
base
URL
Document
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
a
Document
sourceDocument
,
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
"),
and
an
optional
Element
sourceElement
(default
null):
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 sourceDocument 's origin .
Let initiatorBaseURLSnapshot be sourceDocument 's document base URL .
If sourceDocument 's node navigable is not allowed by sandboxing to navigate navigable given sourceSnapshotParams , then:
If
exceptionsEnabled
is
true,
then
throw
a
"
SecurityError
"
DOMException
.
Return.
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
,
initiatorOriginSnapshot
,
userInvolvement
,
and
cspNavigationType
.
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.
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 true, or navigable 's ongoing navigation is no longer navigationId , 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
.
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 policyContainer be the result of determining navigation params policy container given response 's URL , null, a clone of the sourceDocument 's policy container , 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
case
javascript:
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
,
an
origin
initiatorOrigin
,
a
user
navigation
involvement
userInvolvement
,
and
a
string
cspNavigationType
:
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 .
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, then 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
peformed
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 document 's URL 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
To
create
navigation
params
from
a
srcdoc
resource
given
a
session
history
entry
entry
,
a
navigable
navigable
,
a
target
snapshot
params
targetSnapshotParams
,
a
user
navigation
involvement
userInvolvement
,
a
navigation
ID
-or-null
navigationId
,
and
a
NavigationTimingType
navTimingType
:
Let documentResource be entry 's document state 's resource .
Let response be a new response with
about:srcdoc
Content-Type
`,
`
text/html
`)
»
Let responseOrigin be the result of determining the origin given response 's URL , targetSnapshotParams 's sandboxing flags , and entry 's document state 's origin .
Let coop be a new opener policy .
Let coopEnforcementResult be a new opener policy enforcement result with
Let policyContainer be the result of determining navigation params policy container given response 's URL , entry 's document state 's history policy container , null, navigable 's container document 's policy container , and null.
Return a new navigation params , with
This algorithm mutates entry .
Assert : this is running in parallel .
Let documentResource be entry 's document state 's resource .
Let request be a new request , with
document
"
include
"
manual
"
navigate
"
If navigable is a top-level traversable , set request 's top-level navigation initiator origin to entry 's document state 's initiator origin
If documentResource is a POST resource , then:
Set
request
's
method
to
`
POST
`.
Set request 's body to documentResource 's request body .
Set
`
Content-Type
`
to
documentResource
's
request
content-type
in
request
's
header
list
.
If entry 's document state 's reload pending is true, then set request 's reload-navigation flag .
Otherwise, if entry 's document state 's ever populated is true, then set request 's history-navigation flag .
If sourceSnapshotParams 's has transient activation is true, then set request 's user-activation to true.
If navigable 's container is non-null:
If the navigable 's container has a browsing context scope origin , then set request 's origin to that browsing context scope origin .
Set request 's destination to navigable 's container 's local name .
If sourceSnapshotParams 's fetch client is navigable 's container document 's relevant settings object , then set request 's initiator type to navigable 's container 's local name .
This ensure that only container-initiated navigations are reported to resource timing.
Let response be null.
Let responseOrigin be null.
Let fetchController be null.
Let coopEnforcementResult be a new opener policy enforcement result , with
Let finalSandboxFlags be an empty sandboxing flag set .
Let responsePolicyContainer be null.
Let responseCOOP be a new opener policy .
Let locationURL be null.
Let currentURL be request 's current URL .
Let commitEarlyHints be null.
While true:
If request 's reserved client is not null and currentURL 's origin is not the same as request 's reserved client 's creation URL 's origin , then:
Run the environment discarding steps for request 's reserved client .
Set request 's reserved client to null.
Set commitEarlyHints to null.
Preloaded links from early hint headers remain in the preload cache after a same origin redirect, but get discarded when the redirect is cross-origin.
If request 's reserved client is null, then:
Let topLevelCreationURL be currentURL .
Let topLevelOrigin be null.
If navigable is not a top-level traversable , then:
Let parentEnvironment be navigable 's parent 's active document 's relevant settings object .
Set topLevelCreationURL to parentEnvironment 's top-level creation URL .
Set topLevelOrigin to parentEnvironment 's top-level origin .
Set request 's reserved client to a new environment whose id is a unique opaque string, target browsing context is navigable 's active browsing context , creation URL is currentURL , top-level creation URL is topLevelCreationURL , and top-level origin is topLevelOrigin .
The created environment's active service worker is set in the Handle Fetch algorithm during the fetch if the request URL matches a service worker registration. [SW]
If
the
result
of
should
navigation
request
of
type
be
blocked
by
Content
Security
Policy?
given
request
and
cspNavigationType
is
"
Blocked
",
then
set
response
to
a
network
error
and
break
.
[CSP]
Set response to null.
If fetchController is null, then set fetchController to the result of fetching request , with processEarlyHintsResponse set to processEarlyHintsResponse as defined below, processResponse set to processResponse as defined below, and useParallelQueue set to true.
Let processEarlyHintsResponse be the following algorithm given a response earlyResponse :
If commitEarlyHints is null, then set commitEarlyHints to the result of processing early hint headers given earlyResponse and request 's reserved client .
Let processResponse be the following algorithm given a response fetchedResponse :
Set response to fetchedResponse .
Otherwise, process the next manual redirect for fetchController .
This will result in calling the processResponse we supplied above, during our first iteration through the loop, and thus setting response .
Navigation
handles
redirects
manually
as
navigation
is
the
only
place
in
the
web
platform
that
cares
for
redirects
to
mailto:
URLs
and
such.
Wait until either response is non-null, or navigable 's ongoing navigation changes to no longer equal navigationId .
If the latter condition occurs, then abort fetchController , and return.
Otherwise, proceed onward.
If request 's body is null, then set entry 's document state 's resource to null.
Fetch unsets the body for particular redirects.
Set responsePolicyContainer to the result of creating a policy container from a fetch response given response and request 's reserved client .
Set finalSandboxFlags to the union of targetSnapshotParams 's sandboxing flags and responsePolicyContainer 's CSP list 's CSP-derived sandboxing flags .
Set responseOrigin to the result of determining the origin given response 's URL , finalSandboxFlags , and entry 's document state 's initiator origin .
If response is a redirect, then response 's URL will be the URL that led to the redirect to response 's location URL ; it will not be the location URL itself.
If navigable is a top-level traversable , then:
Set responseCOOP to the result of obtaining an opener policy given response and request 's reserved client .
Set coopEnforcementResult to the result of enforcing the response's opener policy given navigable 's active browsing context , response 's URL , responseOrigin , responseCOOP , coopEnforcementResult and request 's referrer .
If
finalSandboxFlags
is
not
empty
and
responseCOOP
's
value
is
not
"
unsafe-none
",
then
set
response
to
an
appropriate
network
error
and
break
.
This results in a network error as one cannot simultaneously provide a clean slate to a response using opener policy and sandbox the result of navigating to that response.
If response is not a network error , navigable is a child navigable , and the result of performing a cross-origin resource policy check with navigable 's container document 's origin , navigable 's container document 's relevant settings object , request 's destination , response , and true is blocked , then set response to a network error and break .
Here we're running the cross-origin resource policy check against the parent navigable rather than navigable itself. This is because we care about the same-originness of the embedded content against the parent context, not the navigation source.
Set locationURL to response 's location URL given currentURL 's fragment .
If locationURL is failure or null, then break .
Set entry 's classic history API state to StructuredSerializeForStorage (null).
Let oldDocState be entry 's document state .
Set entry 's document state to a new document state , with
For the navigation case, only entry referenced oldDocState , which was created early in the navigate algorithm . So for navigations, this is functionally just an update to entry 's document state . For the traversal case, it's possible adjacent session history entries also reference oldDocState , in which case they will continue doing so even after we've updated entry 's document state .
oldDocState 's history policy container is only ever non-null here in the traversal case, after we've populated it during a navigation to a URL that requires storing the policy container in history .
The setup is given by the following Jake diagram :
0 | 1 | 2 | 3 | |
---|---|---|---|---|
top
| /a | /a#foo | /a#bar | /b |
Also assume that the document state shared by the entries in steps 0, 1, and 2 has a null document , i.e., bfcache is not in play.
Now
consider
the
scenario
where
we
traverse
back
to
step
2,
but
this
time
when
fetching
/a
,
the
server
responds
with
a
`
Location
`
header
pointing
to
/c
.
That
is,
locationURL
points
to
/c
and
so
we
have
reached
this
step
instead
of
breaking
out
of
the
loop.
In this case, we replace the document state of the session history entry occupying step 2, but we do not replace the document state of the entries occupying steps 0 and 1. The resulting Jake diagram looks like this:
0 | 1 | 2 | 3 | |
---|---|---|---|---|
top
| /a | /a#foo | /c#bar | /b |
Note
that
we
perform
this
replacement
even
if
we
end
up
in
a
redirect
chain
back
to
the
original
URL,
for
example
if
/c
itself
had
a
`
Location
`
header
pointing
to
/a
.
Such
a
case
would
end
up
like
so:
0 | 1 | 2 | 3 | |
---|---|---|---|---|
top
| /a | /a#foo | /a#bar | /b |
If locationURL 's scheme is not an HTTP(S) scheme , then:
Set entry 's document state 's resource to null.
Break .
Set currentURL to locationURL .
Set entry 's URL to currentURL .
By the end of this loop we will be in one of these scenarios:
locationURL
is
failure,
because
of
an
unparseable
`
Location
`
header.
locationURL
is
null,
either
because
response
is
a
network
error
or
because
we
successfully
fetched
a
non-
network
error
HTTP(S)
response
with
no
`
Location
`
header.
If locationURL is a URL whose scheme is not a fetch scheme , then return a new non-fetch scheme navigation params , with
At this point, request 's current URL is the last URL in the redirect chain with a fetch scheme before redirecting to a non- fetch scheme URL . It is this URL 's origin that will be used as the initiator origin for navigations to non- fetch scheme URLs .
If any of the following are true:
response is a network error ;
locationURL is failure; or
locationURL is a URL whose scheme is a fetch scheme ,
then return null.
We allow redirects to non- fetch scheme URLs , but redirects to fetch scheme URLs that aren't HTTP(S) are treated like network errors.
Assert : locationURL is null and response is not a network error .
Let resultPolicyContainer be the result of determining navigation params policy container given response 's URL , entry 's document state 's history policy container , sourceSnapshotParams 's source policy container , null, and responsePolicyContainer .
If
navigable
's
container
is
an
iframe
,
and
response
's
timing
allow
passed
flag
is
set,
then
set
container
's
pending
resource-timing
start
time
to
null.
If
the
iframe
is
allowed
to
report
to
resource
timing,
we
don't
need
to
run
its
fallback
steps
as
the
normal
reporting
would
happen.
Return a new navigation params , with
An
element
has
a
browsing
context
scope
origin
if
its
Document
's
node
navigable
is
a
top-level
traversable
or
if
all
of
its
Document
's
ancestor
navigables
all
have
active
documents
whose
origins
are
the
same
origin
as
the
element's
node
document
's
origin
.
If
an
element
has
a
browsing
context
scope
origin
,
then
its
value
is
the
origin
of
the
element's
node
document
.
This definition is broken and needs investigation to see what it was intended to express: see issue #4703 .
To
load
a
document
given
navigation
params
navigationParams
,
source
snapshot
params
sourceSnapshotParams
,
and
origin
initiatorOrigin
,
perform
the
following
steps.
They
return
a
Document
or
null.
Let type be the computed type of navigationParams 's response .
If the user agent has been configured to process resources of the given type using some mechanism other than rendering the content in a navigable , then skip this step. Otherwise, if the type is one of the following types:
text/css
"
text/plain
"
text/vtt
"
multipart/x-mixed-replace
"
multipart/x-mixed-replace
document
,
given
navigationParams
,
sourceSnapshotParams
,
and
initiatorOrigin
.
application/pdf
"
text/pdf
"
Otherwise, proceed onward.
An
explicitly
supported
XML
MIME
type
is
an
XML
MIME
type
for
which
the
user
agent
is
configured
to
use
an
external
application
to
render
the
content,
or
for
which
the
user
agent
has
dedicated
processing
rules.
For
example,
a
web
browser
with
a
built-in
Atom
feed
viewer
would
be
said
to
explicitly
support
the
application/atom+xml
MIME
type.
An explicitly supported JSON MIME type is a JSON MIME type for which the user agent is configured to use an external application to render the content, or for which the user agent has dedicated processing rules.
In both cases, the external application or user agent will either display the content inline directly in navigationParams 's navigable , or hand it off to external software . Both happen in the steps below.
Otherwise, the document's type is such that the resource will not affect navigationParams 's navigable , e.g., because the resource is to be handed to an external application or because it is an unknown type that will be processed as a download . Hand-off to external software given navigationParams 's response , navigationParams 's navigable , navigationParams 's final sandboxing flag set , sourceSnapshotParams 's has transient activation , and initiatorOrigin .
Return null.
For
both
navigation
and
traversal,
once
we
have
an
idea
of
where
we
want
to
head
to
in
the
session
history,
much
of
the
work
comes
about
in
applying
that
notion
to
the
traversable
navigable
and
the
relevant
Document
.
For
navigations,
this
work
generally
occurs
toward
the
end
of
the
process;
for
traversals,
it
is
the
beginning.
Ensuring a traversable ends up at the right session history step is particularly complex, as it can involve coordinating across multiple navigable descendants of the traversable, populating them in parallel, and then synchronizing back up to ensure everyone has the same view of the result. This is further complicated by the existence of synchronous same-document navigations being mixed together with cross-document navigations, and how web pages have come to have certain relative timing expectations.
A changing navigable continuation state is used to store information during the apply the history step algorithm, allowing parts of the algorithm to continue only after other parts have finished. It is a struct with:
Document
Although all updates to the traversable navigable end up in the same apply the history step algorithm, each possible entry point comes along with some minor customizations:
To update for navigable creation/destruction given a traversable navigable traversable :
Let step be traversable 's current session history step .
Return
the
result
of
applying
the
history
step
step
to
traversable
given
false,
null,
null,
"
none
",
and
null.
To apply the push/replace history step given a non-negative integer step to a traversable navigable traversable , given a history handling behavior historyHandling and a user navigation involvement userInvolvement :
Return the result of applying the history step step to traversable given false, null, null, userInvolvement , and historyHandling .
Apply the push/replace history step never passes source snapshot params or an initiator navigable to apply the history step . This is because those checks are done earlier in the navigation algorithm.
To apply the reload history step to a traversable navigable traversable given user navigation involvement userInvolvement :
Let step be traversable 's current session history step .
Return
the
result
of
applying
the
history
step
step
to
traversable
given
true,
null,
null,
userInvolvement
,
and
"
reload
".
Apply
the
reload
history
step
never
passes
source
snapshot
params
or
an
initiator
navigable
to
apply
the
history
step
.
This
is
because
reloading
is
always
treated
as
if
it
were
done
by
the
navigable
itself,
even
in
cases
like
parent.location.reload()
.
To apply the traverse history step given a non-negative integer step to a traversable navigable traversable , with source snapshot params sourceSnapshotParams , navigable initiatorToCheck , and user navigation involvement userInvolvement :
Return
the
result
of
applying
the
history
step
step
to
traversable
given
true,
sourceSnapshotParams
,
initiatorToCheck
,
userInvolvement
,
and
"
traverse
".
Now for the algorithm itself.
To
apply
the
history
step
given
a
non-negative
integer
step
to
a
traversable
navigable
traversable
,
with
boolean
checkForCancelation
,
source
snapshot
params
-or-null
sourceSnapshotParams
,
navigable
-or-null
initiatorToCheck
,
user
navigation
involvement
userInvolvement
,
and
NavigationType
-or-null
navigationType
,
perform
the
following
steps.
They
return
"
initiator-disallowed
",
"
canceled-by-beforeunload
",
"
canceled-by-navigate
",
or
"
applied
".
Assert : This is running within traversable 's session history traversal queue .
Let targetStep be the result of getting the used step given traversable and step .
If initiatorToCheck is not null, then:
Assert : sourceSnapshotParams is not null.
For
each
navigable
of
get
all
navigables
whose
current
session
history
entry
will
change
or
reload
:
if
initiatorToCheck
is
not
allowed
by
sandboxing
to
navigate
navigable
given
sourceSnapshotParams
,
then
return
"
initiator-disallowed
".
Let navigablesCrossingDocuments be the result of getting all navigables that might experience a cross-document traversal given traversable and targetStep .
If
checkForCancelation
is
true,
and
the
result
of
checking
if
unloading
is
canceled
given
navigablesCrossingDocuments
,
traversable
,
targetStep
,
and
userInvolvement
is
not
"
continue
",
then
return
that
result.
Let changingNavigables be the result of get all navigables whose current session history entry will change or reload given traversable and targetStep .
Let nonchangingNavigablesThatStillNeedUpdates be the result of getting all navigables that only need history object length/index update given traversable and targetStep .
For each navigable of changingNavigables :
Let targetEntry be the result of getting the target history entry given navigable and targetStep .
Set navigable 's current session history entry to targetEntry .
Set
the
ongoing
navigation
for
navigable
to
"
traversal
".
Let totalChangeJobs be the size of changingNavigables .
Let completedChangeJobs be 0.
Let changingNavigableContinuations be an empty queue of changing navigable continuation states .
This queue is used to split the operations on changingNavigables into two parts. Specifically, changingNavigableContinuations holds data for the second part .
For each navigable of changingNavigables , queue a global task on the navigation and traversal task source of navigable 's active window to run the steps:
This set of steps are split into two parts to allow synchronous navigations to be processed before documents unload. State is stored in changingNavigableContinuations for the second part .
Let displayedEntry be navigable 's active session history entry .
Let targetEntry be navigable 's current session history entry .
Let changingNavigableContinuation be a changing navigable continuation state with:
If displayedEntry is targetEntry and targetEntry 's document state 's reload pending is false, then:
Set changingNavigableContinuation 's update-only to true.
Enqueue changingNavigableContinuation on changingNavigableContinuations .
Abort these steps.
This case occurs due to a synchronous navigation which already updated the active session history entry .
Switch on navigationType :
reload
"
Assert : targetEntry 's document state 's reload pending is true.
traverse
"
Assert : targetEntry 's document state 's ever populated is true.
replace
"
Assert : targetEntry 's step is displayedEntry 's step and targetEntry 's document state 's ever populated is false.
push
"
Assert : targetEntry 's step is displayedEntry 's step + 1 and targetEntry 's document state 's ever populated is false.
Let oldOrigin be targetEntry 's document state 's origin .
If targetEntry 's document is null, or targetEntry 's document state 's reload pending is true, then:
Let
navTimingType
be
"
back_forward
"
if
targetEntry
's
document
is
null;
otherwise
"
reload
".
Let targetSnapshotParams be the result of snapshotting target snapshot params given navigable .
Let potentiallyTargetSpecificSourceSnapshotParams be sourceSnapshotParams .
If potentiallyTargetSpecificSourceSnapshotParams is null, then set it to the result of snapshotting source snapshot params given navigable 's active document .
In this case there is no clear source of the traversal/reload. We treat this situation as if navigable navigated itself, but note that some properties of targetEntry 's original initiator are preserved in targetEntry 's document state , such as the initiator origin and referrer , which will appropriately influence the navigation.
Set targetEntry 's document state 's reload pending to false.
Let allowPOST be targetEntry 's document state 's reload pending .
In parallel , attempt to populate the history entry's document for targetEntry , given navigable , potentiallyTargetSpecificSourceSnapshotParams , targetSnapshotParams , userInvolvement , with allowPOST set to allowPOST and completionSteps set to queue a global task on the navigation and traversal task source given navigable 's active window to run afterDocumentPopulated .
Otherwise, run afterDocumentPopulated immediately .
In both cases, let afterDocumentPopulated be the following steps:
If targetEntry 's document is null, then set changingNavigableContinuation 's update-only to true.
This means we tried to populate the document, but were unable to do so, e.g. because of the server returning a 204.
These
kinds
of
failed
navigations
or
traversals
will
not
be
signaled
to
the
navigation
API
(e.g.,
through
the
promises
of
any
navigation
API
method
tracker
,
or
the
navigateerror
event).
Doing
so
would
leak
information
about
the
timing
of
responses
from
other
origins,
in
the
cross-origin
case,
and
providing
different
results
in
the
cross-origin
vs.
same-origin
cases
was
deemed
too
confusing.
However,
implementations
could
use
this
opportunity
to
clear
any
promise
handlers
for
the
navigation.transition.finished
promise,
as
they
are
guaranteed
at
this
point
to
never
run.
And,
they
might
wish
to
report
a
warning
to
the
console
if
any
part
of
the
navigation
API
initiated
these
navigations,
to
make
it
clear
to
the
web
developer
why
their
promises
will
never
settle
and
events
will
never
fire.
If targetEntry 's document 's origin is not oldOrigin , then set targetEntry 's classic history API state to StructuredSerializeForStorage (null).
This clears history state when the origin changed vs a previous load of targetEntry without a redirect occuring. This can happen due to a change in CSP sandbox headers.
If all of the following are true:
navigable 's parent is null;
targetEntry 's document 's browsing context is not an auxiliary browsing context whose opener browsing context is non-null; and
then set targetEntry 's document state 's navigable target name to the empty string.
Enqueue changingNavigableContinuation on changingNavigableContinuations .
The rest of this job runs later in this algorithm.
Let navigablesThatMustWaitBeforeHandlingSyncNavigation be an empty set .
While completedChangeJobs does not equal totalChangeJobs :
If traversable 's running nested apply history step is false, then:
Let changingNavigableContinuation be the result of dequeuing from changingNavigableContinuations .
If changingNavigableContinuation is nothing, then continue .
Let displayedDocument be changingNavigableContinuation 's displayed document .
Let targetEntry be changingNavigableContinuation 's target entry .
Let navigable be changingNavigableContinuation 's navigable .
Let ( scriptHistoryLength , scriptHistoryIndex ) be the result of getting the history object length and index given traversable and targetStep .
These values might have changed since they were last calculated.
Append navigable to navigablesThatMustWaitBeforeHandlingSyncNavigation .
Once a navigable has reached this point in traversal, additionally queued synchronous navigation steps are likely to be intended to occur after this traversal rather than before it, so they no longer jump the queue. More details can be found here .
Let entriesForNavigationAPI be the result of getting session history entries for the navigation API given navigable and targetStep .
If changingNavigableContinuation 's update-only is true, or targetEntry 's document is displayedDocument , then:
This is a same-document navigation: we proceed without unloading.
Set the ongoing navigation for navigable to null.
This allows new navigations of navigable to start, whereas during the traversal they were blocked.
Queue a global task on the navigation and traversal task source given navigable 's active window to perform afterPotentialUnloads .
Otherwise:
Assert : navigationType is not null.
Deactivate displayedDocument , given userInvolvement , targetEntry , navigationType , and afterPotentialUnloads .
In both cases, let afterPotentialUnloads be the following steps:
Let previousEntry be navigable 's active session history entry .
If changingNavigableContinuation 's update-only is false, then activate history entry targetEntry for navigable .
Let updateDocument be an algorithm step which performs update document for history step application given targetEntry 's document , targetEntry , changingNavigableContinuation 's update-only , scriptHistoryLength , scriptHistoryIndex , navigationType , entriesForNavigationAPI , and previousEntry .
If targetEntry 's document is equal to displayedDocument , then perform updateDocument .
Otherwise, queue a global task on the navigation and traversal task source given targetEntry 's document 's relevant global object to perform updateDocument .
Increment completedChangeJobs .
Let totalNonchangingJobs be the size of nonchangingNavigablesThatStillNeedUpdates .
This step onwards deliberately waits for all the previous operations to complete, as they include processing synchronous navigations which will also post tasks to update history length and index.
Let completedNonchangingJobs be 0.
Let ( scriptHistoryLength , scriptHistoryIndex ) be the result of getting the history object length and index given traversable and targetStep .
For each navigable of nonchangingNavigablesThatStillNeedUpdates , queue a global task on the navigation and traversal task source given navigable 's active window to run the steps:
Let document be navigable 's active document .
Set document 's history object 's index to scriptHistoryIndex .
Set document 's history object 's length to scriptHistoryLength .
Increment completedNonchangingJobs .
Wait for completedNonchangingJobs to equal totalNonchangingJobs .
Set traversable 's current session history step to targetStep .
Return
"
applied
".
To
deactivate
a
document
for
a
cross-document
navigation
given
a
Document
displayedDocument
,
a
user
navigation
involvement
userNavigationInvolvement
,
a
session
history
entry
targetEntry
,
a
NavigationType
navigationType
,
and
afterPotentialUnloads
,
which
is
an
algorithm
that
receives
no
arguments:
Let navigable be displayedDocument 's node navigable .
Let potentiallyTriggerViewTransition be false.
Let
isBrowserUINavigation
be
true
if
userNavigationInvolvement
is
"
browser
UI
";
otherwise
false.
Set potentiallyTriggerViewTransition to the result of calling can navigation trigger a cross-document view-transition? given displayedDocument , targetEntry 's document , navigationType , and isBrowserUINavigation .
If potentiallyTriggerViewTransition is false, then:
Let firePageSwapBeforeUnload be the following step:
Fire
the
pageswap
event
given
displayedDocument
,
targetEntry
,
navigationType
,
and
null.
Set the ongoing navigation for navigable to null.
This allows new navigations of navigable to start, whereas during the traversal they were blocked.
Unload a document and its descendants given displayedDocument , targetEntry 's document , afterPotentialUnloads , and firePageSwapBeforeUnload .
Otherwise, queue a global task on the navigation and traversal task source given navigable 's active window to run the steps:
Let proceedWithNavigationAfterViewTransitionCapture be the following step:
Append the following session history traversal steps to navigable 's traversable navigable :
Set the ongoing navigation for navigable to null.
This allows new navigations of navigable to start, whereas during the traversal they were blocked.
Unload a document and its descendants given displayedDocument , targetEntry 's document , and afterPotentialUnloads .
Let viewTransition be the result of setting up a cross-document view-transition given displayedDocument , targetEntry 's document , navigationType , and proceedWithNavigationAfterViewTransitionCapture .
Fire
the
pageswap
event
given
displayedDocument
,
targetEntry
,
navigationType
,
and
viewTransition
.
If viewTransition is null, then run proceedWithNavigationAfterViewTransitionCapture .
In the case where a view transition started, the view transitions algorithms are responsible for calling proceedWithNavigationAfterViewTransitionCapture .
To
fire
the
pageswap
event
given
a
Document
displayedDocument
,
a
session
history
entry
targetEntry
,
a
NavigationType
navigationType
,
and
a
ViewTransition
-or-null
viewTransition
:
Assert : this is running as part of a task queued on displayedDocument 's relevant agent 's event loop .
Let navigation be displayedDocument 's relevant global object 's navigation API .
Let activation be null.
If all of the following are true:
targetEntry 's document 's origin is same origin with displayedDocument 's origin ; and
targetEntry 's document 's was created via cross-origin redirects is false, or targetEntry 's document 's latest entry is not null,
then:
Let destinationEntry be determined by switching on navigationType :
reload
"
The current entry of navigation
traverse
"
The
NavigationHistoryEntry
in
navigation
's
entry
list
whose
session
history
entry
is
targetEntry
push
"
replace
"
A
new
NavigationHistoryEntry
in
displayedDocument
's
relevant
realm
with
its
session
history
entry
set
to
targetEntry
.
Set
activation
to
a
new
NavigationActivation
created
in
displayedDocument
's
relevant
realm
,
with
This
means
that
a
cross-origin
redirect
during
a
navigation
would
result
in
a
null
activation
in
the
old
document's
PageSwapEvent
,
unless
the
new
document
is
being
restored
from
bfcache
.
Fire
an
event
named
pageswap
at
displayedDocument
's
relevant
global
object
,
using
PageSwapEvent
with
its
activation
set
to
activation
,
and
its
viewTransition
set
to
viewTransition
.
To activate history entry session history entry entry for navigable navigable :
Save persisted state to the navigable 's active session history entry .
Let newDocument be entry 's document .
Assert
:
newDocument
's
is
initial
about:blank
is
false,
i.e.,
we
never
traverse
back
to
the
initial
about:blank
Document
because
it
always
gets
replaced
when
we
navigate
away
from
it.
Set navigable 's active session history entry to entry .
Make active newDocument .
To get the used step given a traversable navigable traversable , and a non-negative integer step , perform the following steps. They return a non-negative integer.
Let steps be the result of getting all used history steps within traversable .
Return the greatest item in steps that is less than or equal to step .
This caters for situations where there's no session history entry with step step , due to the removal of a navigable .
To get the history object length and index given a traversable navigable traversable , and a non-negative integer step , perform the following steps. They return a tuple of two non-negative integers.
Let steps be the result of getting all used history steps within traversable .
Let scriptHistoryLength be the size of steps .
Assert : steps contains step .
It is assumed that step has been adjusted by getting the used step .
Let scriptHistoryIndex be the index of step in steps .
Return ( scriptHistoryLength , scriptHistoryIndex ).
To get all navigables whose current session history entry will change or reload given a traversable navigable traversable , and a non-negative integer targetStep , perform the following steps. They return a list of navigables .
Let results be an empty list .
Let navigablesToCheck be « traversable ».
This list is extended in the loop below.
For each navigable of navigablesToCheck :
Let targetEntry be the result of getting the target history entry given navigable and targetStep .
If targetEntry is not navigable 's current session history entry or targetEntry 's document state 's reload pending is true, then append navigable to results .
If targetEntry 's document is navigable 's document , and targetEntry 's document state 's reload pending is false, then extend navigablesToCheck with the child navigables of navigable .
Adding child navigables to navigablesToCheck means those navigables will also be checked by this loop. Child navigables are only checked if the navigable 's active document will not change as part of this traversal.
Return results .
To get all navigables that only need history object length/index update given a traversable navigable traversable , and a non-negative integer targetStep , perform the following steps. They return a list of navigables .
Other navigables might not be impacted by the traversal. For example, if the response is a 204, the currently active document will remain. Additionally, going 'back' after a 204 will change the current session history entry , but the active session history entry will already be correct.
Let results be an empty list .
Let navigablesToCheck be « traversable ».
This list is extended in the loop below.
For each navigable of navigablesToCheck :
Let targetEntry be the result of getting the target history entry given navigable and targetStep .
If targetEntry is navigable 's current session history entry and targetEntry 's document state 's reload pending is false, then:
Append navigable to results .
Extend navigablesToCheck with navigable 's child navigables .
Adding child navigables to navigablesToCheck means those navigables will also be checked by this loop. child navigables are only checked if the navigable 's active document will not change as part of this traversal.
Return results .
To get the target history entry given a navigable navigable , and a non-negative integer step , perform the following steps. They return a session history entry .
Let entries be the result of getting session history entries for navigable .
Return the item in entries that has the greatest step less than or equal to step .
To see why getting the target history entry returns the entry with the greatest step less than or equal to the input step, consider the following Jake diagram :
0 | 1 | 2 | 3 | |
---|---|---|---|---|
top
| /t | /t#foo | ||
frames[0]
| /i-0-a | /i-0-b |
For
the
input
step
1,
the
target
history
entry
for
the
top
navigable
is
the
/t
entry,
whose
step
is
0,
while
the
target
history
entry
for
the
frames[0]
navigable
is
the
/i-0-b
entry,
whose
step
is
1:
0 | 1 | 2 | 3 | |
---|---|---|---|---|
top
| /t | /t#foo | ||
frames[0]
| /i-0-a | /i-0-b |
Similarly,
given
the
input
step
3
we
get
the
top
entry
whose
step
is
3,
and
the
frames[0]
entry
whose
step
is
1:
0 | 1 | 2 | 3 | |
---|---|---|---|---|
top
| /t | /t#foo | ||
frames[0]
| /i-0-a | /i-0-b |
To get all navigables that might experience a cross-document traversal given a traversable navigable traversable , and a non-negative integer targetStep , perform the following steps. They return a list of navigables .
From traversable 's session history traversal queue 's perspective, these documents are candidates for going cross-document during the traversal described by targetStep . They will not experience a cross-document traversal if the status code for their target document is HTTP 204 No Content.
Note that if a given navigable might experience a cross-document traversal, this algorithm will return navigable but not its child navigables . Those would end up unloaded , not traversed.
Let results be an empty list .
Let navigablesToCheck be « traversable ».
This list is extended in the loop below.
For each navigable of navigablesToCheck :
Let targetEntry be the result of getting the target history entry given navigable and targetStep .
If targetEntry 's document is not navigable 's document or targetEntry 's document state 's reload pending is true, then append navigable to results .
Although
navigable
's
active
history
entry
can
change
synchronously,
the
new
entry
will
always
have
the
same
Document
,
so
accessing
navigable
's
document
is
reliable.
Otherwise, extend navigablesToCheck with navigable 's child navigables .
Adding child navigables to navigablesToCheck means those navigables will also be checked by this loop. Child navigables are only checked if the navigable 's active document will not change as part of this traversal.
Return results .
To
update
document
for
history
step
application
given
a
Document
document
,
a
session
history
entry
entry
,
a
boolean
doNotReactivate
,
integers
scriptHistoryLength
and
scriptHistoryIndex
,
NavigationType
-or-null
navigationType
,
an
optional
list
of
session
history
entries
entriesForNavigationAPI
,
and
an
optional
session
history
entry
previousEntryForActivation
:
Let documentIsNew be true if document 's latest entry is null; otherwise false.
Let documentsEntryChanged be true if document 's latest entry is not entry ; otherwise false.
Set document 's history object 's index to scriptHistoryIndex .
Set document 's history object 's length to scriptHistoryLength .
Let navigation be history 's relevant global object 's navigation API .
If documentsEntryChanged is true, then:
Let oldURL be document 's latest entry 's URL .
Set document 's latest entry to entry .
Restore the history object state given document and entry .
If documentIsNew is false, then:
Assert : navigationType is not null.
Update the navigation API entries for a same-document navigation given navigation , entry , and navigationType .
Fire
an
event
named
popstate
at
document
's
relevant
global
object
,
using
PopStateEvent
,
with
the
state
attribute
initialized
to
document
's
history
object
's
state
and
hasUAVisualTransition
initialized
to
true
if
a
visual
transition,
to
display
a
cached
rendered
state
of
the
latest
entry
,
was
done
by
the
user
agent.
Restore persisted state given entry .
If
oldURL
's
fragment
is
not
equal
to
entry
's
URL
's
fragment
,
then
queue
a
global
task
on
the
DOM
manipulation
task
source
given
document
's
relevant
global
object
to
fire
an
event
named
hashchange
at
document
's
relevant
global
object
,
using
HashChangeEvent
,
with
the
oldURL
attribute
initialized
to
the
serialization
of
oldURL
and
the
newURL
attribute
initialized
to
the
serialization
of
entry
's
URL
.
Otherwise:
Assert : entriesForNavigationAPI is given.
Restore persisted state given entry .
Initialize the navigation API entries for a new document given navigation , entriesForNavigationAPI , and entry .
If all the following are true:
previousEntryForActivation is given;
navigationType is non-null; and
navigationType
is
"
reload
"
or
previousEntryForActivation
's
document
is
not
document
,
then:
If
navigation
's
activation
is
null,
then
set
navigation
's
activation
to
a
new
NavigationActivation
object
in
navigation
's
relevant
realm
.
Let previousEntryIndex be the result of getting the navigation API entry index of previousEntryForActivation within navigation .
If previousEntryIndex is non-negative, then set activation 's old entry to navigation 's entry list [ previousEntryIndex ].
Otherwise, if all the following are true:
navigationType
is
"
replace
";
previousEntryForActivation 's document state 's origin is same origin with document 's origin ; and
previousEntryForActivation
's
document
's
initial
about:blank
is
false,
then
set
activation
's
old
entry
to
a
new
NavigationHistoryEntry
in
navigation
's
relevant
realm
,
whose
session
history
entry
is
previousEntryForActivation
.
Set activation 's new entry to navigation 's current entry .
Set activation 's navigation type to navigationType .
If documentIsNew is true, then:
Try to scroll to the fragment for document .
At this point scripts may run for the newly-created document document .
Otherwise, if documentsEntryChanged is false and doNotReactivate is false, then:
Assert : entriesForNavigationAPI is given.
Reactivate document given entry and entriesForNavigationAPI .
documentsEntryChanged can be false for one of two reasons: either we are restoring from bfcache , or we are asynchronously finishing up a synchronous navigation which already synchronously set document 's latest entry . The doNotReactivate argument distinguishes between these two cases.
To
restore
the
history
object
state
given
Document
document
and
session
history
entry
entry
:
Let targetRealm be document 's relevant realm .
Let state be StructuredDeserialize ( entry 's classic history API state , targetRealm ). If this throws an exception, catch it and let state be null.
Set document 's history object 's state to state .
To
make
active
a
Document
document
:
Let window be document 's relevant global object .
Set
document
's
browsing
context
's
WindowProxy
's
[[Window]]
internal
slot
value
to
window
.
Set document 's visibility state to document 's node navigable 's traversable navigable 's system visibility state .
Queue
a
new
VisibilityStateEntry
whose
visibility
state
is
document
's
visibility
state
and
whose
timestamp
is
zero.
Set window 's relevant settings object 's execution ready flag .
To
reactivate
a
Document
document
given
a
session
history
entry
reactivatedEntry
and
a
list
of
session
history
entries
entriesForNavigationAPI
:
This algorithm updates document after it has come out of bfcache , i.e., after it has been made fully active again. Other specifications that want to watch for this change to the fully active state are encouraged to add steps into this algorithm, so that the ordering of events that happen in effect of the change is clear.
For
each
formControl
of
form
controls
in
document
with
an
autofill
field
name
of
"
off
",
invoke
the
reset
algorithm
for
formControl
.
If document 's suspended timer handles is not empty :
Assert : document 's suspension time is not zero.
Let suspendDuration be the current high resolution time minus document 's suspension time .
Let activeTimers be document 's relevant global object 's map of active timers .
For each handle in document 's suspended timer handles , if activeTimers [ handle ] exists , then increase activeTimers [ handle ] by suspendDuration .
Update the navigation API entries for reactivation given document 's relevant global object 's navigation API , entriesForNavigationAPI , and reactivatedEntry .
If
document
's
current
document
readiness
is
"
complete
",
and
document
's
page
showing
flag
is
false,
then:
Set document 's page showing flag to true.
Set document 's has been revealed to false.
Update
the
visibility
state
of
document
to
"
visible
".
Fire
a
page
transition
event
named
pageshow
at
document
's
relevant
global
object
with
true.
To
try
to
scroll
to
the
fragment
for
a
Document
document
,
perform
the
following
steps
in
parallel
:
Wait for an implementation-defined amount of time. (This is intended to allow the user agent to optimize the user experience in the face of performance concerns.)
Queue a global task on the navigation and traversal task source given document 's relevant global object to run these steps:
If document has no parser, or its parser has stopped parsing , or the user agent has reason to believe the user is no longer interested in scrolling to the fragment , then abort these steps.
Scroll to the fragment given document .
If document 's indicated part is still null, then try to scroll to the fragment for document .
To
make
document
unsalvageable
,
given
a
Document
document
and
a
string
reason
:
Let details be a new not restored reason details whose reason is reason .
Append details to document 's bfcache blocking details .
Set document 's salvageable state to false.
To
build
not
restored
reasons
for
document
state
given
Document
document
:
Let notRestoredReasonsForDocument be a new not restored reasons .
Set notRestoredReasonsForDocument 's URL to document 's URL .
Let container be document 's node navigable 's container .
If
container
is
an
iframe
element:
Let src be the empty string.
If
container
has
a
src
attribute:
Let
src
be
the
result
of
encoding-parsing-and-serializing
a
URL
given
container
's
src
attribute's
value,
relative
to
container
's
node
document
.
If
src
is
failure,
then
set
src
to
container
's
src
attribute's
value.
Set notRestoredReasonsForDocument 's src to src .
Set
notRestoredReasonsForDocument
's
id
to
container
's
id
attribute's
value,
or
the
empty
string
if
it
has
no
such
attribute.
Set
notRestoredReasonsForDocument
's
name
to
container
's
name
attribute's
value,
or
the
empty
string
if
it
has
no
such
attribute.
Set notRestoredReasonsForDocument 's reasons to a clone of document 's bfcache blocking details .
For each navigable of document 's document-tree child navigables :
Let childDocument be navigable 's active document .
Build not restored reasons for document state given childDocument .
Append childDocument 's not restored reasons to notRestoredReasonsForDocument 's children .
Set document 's node navigable 's active session history entry 's document state 's not restored reasons to notRestoredReasonsForDocument .
To build not restored reasons for a top-level traversable and its descendants given top-level traversable topLevelTraversable :
Build not restored reasons for document state given topLevelTraversable 's active document .
Let crossOriginDescendants be an empty list .
For each childNavigable of topLevelTraversable 's active document 's descendant navigables :
If childNavigable 's active document 's origin is not same origin with topLevelTraversable 's active document 's origin , then append childNavigable to crossOriginDescendants .
Let crossOriginDescendantsPreventsBfcache be false.
For each crossOriginNavigable of crossOriginDescendants :
Let reasonsForCrossOriginChild be crossOriginNavigable 's active document 's document state 's not restored reasons .
If reasonsForCrossOriginChild 's reasons is not empty, set crossOriginDescendantsPreventsBfcache to true.
Set reasonsForCrossOriginChild 's URL to null.
Set reasonsForCrossOriginChild 's reasons to null.
Set reasonsForCrossOriginChild 's children to null.
If
crossOriginDescendantsPreventsBfcache
is
true,
make
document
unsalvageable
given
topLevelTraversable
's
active
document
and
"
masked
".
A
Document
has
a
boolean
has
been
revealed
,
initially
false.
It
is
used
to
ensure
that
the
pagereveal
event
is
fired
once
for
each
activation
of
the
Document
(once
when
it's
rendered
initially,
and
once
for
each
reactivation
).
To
reveal
a
Document
document
:
If document 's has been revealed is true, then return.
Set document 's has been revealed to true.
Let transition be the result of resolving inbound cross-document view-transition for document .
Fire
an
event
named
pagereveal
at
document
's
relevant
global
object
,
using
PageRevealEvent
with
its
viewTransition
set
to
transition
.
If transition is not null, then:
Prepare to run script given document 's relevant settings object .
Activate transition .
Clean up after running script given document 's relevant settings object .
Activating a view transition might resolve/reject promises, so by wrapping the activation with prepare/cleanup we ensure those promises are handled before the next rendering step.
Though
pagereveal
is
guaranteed
to
be
fired
during
the
first
update
the
rendering
step
that
displays
an
up-to-date
version
of
the
page,
user
agents
are
free
to
display
a
cached
frame
of
the
page
before
firing
it.
This
prevents
the
presence
of
a
pagereveal
handler
from
delaying
the
presentation
of
such
cached
frame.
To
scroll
to
the
fragment
given
a
Document
document
:
If document 's indicated part is null, then set document 's target element to null.
Otherwise, if document 's indicated part is top of the document , then:
Set document 's target element to null.
Scroll to the beginning of the document for document . [CSSOMVIEW]
Return.
Otherwise:
Assert : document 's indicated part is an element.
Let target be document 's indicated part .
Set document 's target element to target .
Run the ancestor details revealing algorithm on target .
Run the
on target .Scroll target into view , with behavior set to "auto", block set to "start", and inline set to "nearest". [CSSOMVIEW]
Run
the
focusing
steps
for
target
,
with
the
Document
's
viewport
as
the
fallback
target
.
Move the sequential focus navigation starting point to target .
A
Document
's
indicated
part
is
the
one
that
its
URL
's
fragment
identifies,
or
null
if
the
fragment
does
not
identify
anything.
The
semantics
of
the
fragment
in
terms
of
mapping
it
to
a
node
is
defined
by
the
specification
that
defines
the
MIME
type
used
by
the
Document
(for
example,
the
processing
of
fragments
for
XML
MIME
types
is
the
responsibility
of
RFC7303).
[RFC7303]
There
is
also
a
target
element
for
each
Document
,
which
is
used
in
defining
the
:target
pseudo-class
and
is
updated
by
the
above
algorithm.
It
is
initially
null.
For an HTML document document , its indicated part is the result of selecting the indicated part given document and document 's URL .
To
select
the
indicated
part
given
a
Document
document
and
a
URL
url
:
If document 's URL does not equal url with exclude fragments set to true, then return null.
Let fragment be url 's fragment .
If fragment is the empty string, then return the special value top of the document .
Let potentialIndicatedElement be the result of finding a potential indicated element given document and fragment .
If potentialIndicatedElement is not null, then return potentialIndicatedElement .
Let fragmentBytes be the result of percent-decoding fragment .
Let decodedFragment be the result of running UTF-8 decode without BOM on fragmentBytes .
Set potentialIndicatedElement to the result of finding a potential indicated element given document and decodedFragment .
If potentialIndicatedElement is not null, then return potentialIndicatedElement .
If
decodedFragment
is
an
ASCII
case-insensitive
match
for
the
string
top
,
then
return
the
top
of
the
document
.
Return null.
To
find
a
potential
indicated
element
given
a
Document
document
and
a
string
fragment
,
run
these
steps:
If there is an element in the document tree whose root is document and that has an ID equal to fragment , then return the first such element in tree order .
If
there
is
an
a
element
in
the
document
tree
whose
root
is
document
that
has
a
name
attribute
whose
value
is
equal
to
fragment
,
then
return
the
first
such
element
in
tree
order
.
Return null.
To save persisted state to a session history entry entry :
Set the scroll position data of entry to contain the scroll positions for all of entry 's document 's restorable scrollable regions .
Optionally, update entry 's persisted user state to reflect any state that the user agent wishes to persist, such as the values of form fields.
To restore persisted state from a session history entry entry :
If
entry
's
scroll
restoration
mode
is
"
auto
",
and
entry
's
document
's
relevant
global
object
's
navigation
API
's
suppress
normal
scroll
restoration
during
ongoing
navigation
is
false,
then
restore
scroll
position
data
given
entry
.
The user agent not restoring scroll positions does not imply that scroll positions will be left at any particular value (e.g., (0,0)). The actual scroll position depends on the navigation type and the user agent's particular caching strategy. So web applications cannot assume any particular scroll position but rather are urged to set it to what they want it to be.
If
suppress
normal
scroll
restoration
during
ongoing
navigation
is
true,
then
restoring
scroll
position
data
might
still
happen
at
a
later
point,
as
part
of
finishing
the
relevant
NavigateEvent
,
or
via
a
navigateEvent.scroll()
method
call.
Optionally, update other aspects of entry 's document and its rendering, for instance values of form fields, that the user agent had previously recorded in entry 's persisted user state .
This
can
even
include
updating
the
dir
attribute
of
textarea
elements
or
input
elements
whose
type
attribute
is
in
the
Text
,
Search
,
Telephone
,
URL
,
or
Email
state,
if
the
persisted
state
includes
the
directionality
of
user
input
in
such
controls.
Restoring
the
value
of
form
controls
as
part
of
this
process
does
not
fire
any
input
or
change
events,
but
can
trigger
the
formStateRestoreCallback
of
form-associated
custom
elements
.
Each
Document
has
a
boolean
has
been
scrolled
by
the
user
,
initially
false.
If
the
user
scrolls
the
document,
the
user
agent
must
set
that
document's
has
been
scrolled
by
the
user
to
true.
The
restorable
scrollable
regions
of
a
Document
document
are
document
's
viewport
,
and
all
of
document
's
scrollable
regions
excepting
any
navigable
containers
.
Child
navigable
scroll
restoration
is
handled
as
part
of
state
restoration
for
the
session
history
entry
for
those
navigables
'
Document
s.
To restore scroll position data given a session history entry entry :
Let document be entry 's document .
If document 's has been scrolled by the user is true, then the user agent should return.
The user agent should attempt to use entry 's scroll position data to restore the scroll positions of entry 's document 's restorable scrollable regions . The user agent may continue to attempt to do so periodically, until document 's has been scrolled by the user becomes true.
This is formulated as an attempt , which is potentially repeated until success or until the user scrolls, due to the fact that relevant content indicated by the scroll position data might take some time to load from the network.
Scroll restoration might be affected by scroll anchoring. [CSSSCROLLANCHORING]