diff --git a/Userland/Libraries/LibWeb/HTML/Location.cpp b/Userland/Libraries/LibWeb/HTML/Location.cpp
index 714b69414a..180590bf87 100644
--- a/Userland/Libraries/LibWeb/HTML/Location.cpp
+++ b/Userland/Libraries/LibWeb/HTML/Location.cpp
@@ -16,6 +16,7 @@
#include
#include
#include
+#include
#include
#include
@@ -58,6 +59,18 @@ JS::GCPtr Location::relevant_document() const
return browsing_context ? browsing_context->active_document() : nullptr;
}
+static Bindings::NavigationHistoryBehavior to_navigation_history_behavior(HistoryHandlingBehavior b)
+{
+ switch (b) {
+ case HistoryHandlingBehavior::Push:
+ return Bindings::NavigationHistoryBehavior::Push;
+ case HistoryHandlingBehavior::Replace:
+ return Bindings::NavigationHistoryBehavior::Replace;
+ default:
+ return Bindings::NavigationHistoryBehavior::Auto;
+ }
+}
+
// https://html.spec.whatwg.org/multipage/nav-history-apis.html#location-object-navigate
WebIDL::ExceptionOr Location::navigate(AK::URL url, HistoryHandlingBehavior history_handling)
{
@@ -73,7 +86,7 @@ WebIDL::ExceptionOr Location::navigate(AK::URL url, HistoryHandlingBehavio
}
// 4. Navigate navigable to url using sourceDocument, with exceptionsEnabled set to true and historyHandling set to historyHandling.
- TRY(navigable->navigate(url, source_document, {}, nullptr, true, history_handling));
+ TRY(navigable->navigate(url, source_document, {}, nullptr, true, to_navigation_history_behavior(history_handling)));
return {};
}
diff --git a/Userland/Libraries/LibWeb/HTML/Navigable.cpp b/Userland/Libraries/LibWeb/HTML/Navigable.cpp
index 3dfadd84a9..677c480679 100644
--- a/Userland/Libraries/LibWeb/HTML/Navigable.cpp
+++ b/Userland/Libraries/LibWeb/HTML/Navigable.cpp
@@ -14,12 +14,18 @@
#include
#include
#include
+#include
#include
+#include
#include
+#include
+#include
#include
+#include
#include
#include
#include
+#include
namespace Web::HTML {
@@ -798,9 +804,11 @@ WebIDL::ExceptionOr Navigable::populate_session_history_entry_document(JS:
// 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 history handling behavior historyHandling (default "push"),
-// an optional string cspNavigationType (default "other"),
-// and an optional referrer policy referrerPolicy (default the empty string):
+// 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),
+// and an optional user navigation involvement userInvolvement (default "none"):
// https://html.spec.whatwg.org/multipage/browsing-the-web.html#navigate
WebIDL::ExceptionOr Navigable::navigate(
@@ -809,49 +817,73 @@ WebIDL::ExceptionOr Navigable::navigate(
Variant document_resource,
JS::GCPtr response,
bool exceptions_enabled,
- HistoryHandlingBehavior history_handling,
- CSPNavigationType csp_navigation_type,
- ReferrerPolicy::ReferrerPolicy referrer_policy)
+ Bindings::NavigationHistoryBehavior history_handling,
+ Optional navigation_api_state,
+ Optional&> form_data_entry_list,
+ ReferrerPolicy::ReferrerPolicy referrer_policy,
+ UserNaviagationInvolvement user_involvement)
{
- // 1. Let sourceSnapshotParams be the result of snapshotting source snapshot params given sourceDocument.
+ auto& active_document = *this->active_document();
+ auto& realm = active_document.realm();
+ auto& vm = this->vm();
+
+ // 1. Let cspNavigationType be "form-submission" if formDataEntryList is non-null; otherwise "other".
+ auto csp_navigation_type = form_data_entry_list.has_value() ? CSPNavigationType::FormSubmission : CSPNavigationType::Other;
+
+ // 2. Let sourceSnapshotParams be the result of snapshotting source snapshot params given sourceDocument.
auto source_snapshot_params = source_document->snapshot_source_snapshot_params();
- // 2. Let initiatorOriginSnapshot be sourceDocument's origin.
+ // 3. Let initiatorOriginSnapshot be sourceDocument's origin.
auto initiator_origin_snapshot = source_document->origin();
- // FIXME: 3. If sourceDocument's node navigable is not allowed by sandboxing to navigate navigable given and sourceSnapshotParams, then:
- if constexpr (false) {
+ // 4. Let initiatorBaseURLSnapshot be sourceDocument's document base URL.
+ auto initiator_base_url_snapshot = source_document->base_url();
+
+ // 5. If sourceDocument's node navigable is not allowed by sandboxing to navigate navigable given and sourceSnapshotParams, then:
+ if (!source_document->navigable()->allowed_by_sandboxing_to_navigate(*this, source_snapshot_params)) {
// 1. If exceptionsEnabled is true, then throw a "SecurityError" DOMException.
if (exceptions_enabled) {
- return WebIDL::SecurityError::create(*vm().current_realm(), "Source document's node navigable is not allowed to navigate"sv);
+ return WebIDL::SecurityError::create(realm, "Source document's node navigable is not allowed to navigate"sv);
}
// 2 Return.
return {};
}
- // 4. Let navigationId be the result of generating a random UUID.
- String navigation_id = TRY_OR_THROW_OOM(vm(), Crypto::generate_random_uuid());
+ // 6. Let navigationId be the result of generating a random UUID.
+ String navigation_id = TRY_OR_THROW_OOM(vm, Crypto::generate_random_uuid());
- // FIXME: 5. If the surrounding agent is equal to navigable's active document's relevant agent, then continue these steps.
+ // FIXME: 7. 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.
- // FIXME: 6. If navigable's active document's unload counter is greater than 0,
- // then invoke WebDriver BiDi navigation failed with a WebDriver BiDi navigation status whose id is navigationId,
- // status is "canceled", and url is url, and return.
-
- // 7. If any of the following are true:
- // - url equals navigable's active document's URL;
- // - url's scheme is "javascript"; or
- // - navigable's active document's is initial about:blank is true
- if (url.equals(active_document()->url())
- || url.scheme() == "javascript"sv
- || active_document()->is_initial_about_blank()) {
- // then set historyHandling to "replace".
- history_handling = HistoryHandlingBehavior::Replace;
+ // 8. If navigable's active document's unload counter is greater than 0,
+ // then invoke WebDriver BiDi navigation failed with a WebDriver BiDi navigation status whose id is navigationId,
+ // status is "canceled", and url is url, and return.
+ if (active_document.unload_counter() > 0) {
+ // FIXME: invoke WebDriver BiDi navigation failed with a WebDriver BiDi navigation status whose id is navigationId,
+ // status is "canceled", and url is url
+ return {};
}
- // 8. If all of the following are true:
+ // 9. If historyHandling is "auto", then:
+ if (history_handling == Bindings::NavigationHistoryBehavior::Auto) {
+ // FIXME: Fix spec typo targetNavigable --> navigable
+ // 1. If url equals navigable's active document's URL,
+ // and initiatorOriginSnapshot is same origin with targetNavigable's active document's origin,
+ // then set historyHandling to "replace".
+ if (url == active_document.url() && initiator_origin_snapshot.is_same_origin(active_document.origin()))
+ history_handling = Bindings::NavigationHistoryBehavior::Replace;
+
+ // 2. Otherwise, set historyHandling to "push".
+ else
+ history_handling = Bindings::NavigationHistoryBehavior::Push;
+ }
+
+ // 10. If the navigation must be a replace given url and navigable's active document, then set historyHandling to "replace".
+ if (navigation_must_be_a_replace(url, active_document))
+ history_handling = Bindings::NavigationHistoryBehavior::Replace;
+
+ // 11. If all of the following are true:
// - documentResource is null;
// - response is null;
// - url equals navigable's active session history entry's URL with exclude fragments set to true; and
@@ -861,25 +893,25 @@ WebIDL::ExceptionOr Navigable::navigate(
&& url.equals(active_session_history_entry()->url, AK::URL::ExcludeFragment::Yes)
&& url.fragment().has_value()) {
// 1. Navigate to a fragment given navigable, url, historyHandling, and navigationId.
- TRY(navigate_to_a_fragment(url, history_handling, navigation_id));
+ TRY(navigate_to_a_fragment(url, to_history_handling_behavior(history_handling), navigation_id));
// 2. Return.
return {};
}
- // 9. If navigable's parent is non-null, then set navigable's is delaying load events to true.
- if (parent() != nullptr) {
+ // 12. If navigable's parent is non-null, then set navigable's is delaying load events to true.
+ if (parent() != nullptr)
set_delaying_load_events(true);
- }
- // 10. Let targetBrowsingContext be navigable's active browsing context.
+ // 13. Let targetBrowsingContext be navigable's active browsing context.
[[maybe_unused]] auto target_browsing_context = active_browsing_context();
- // FIXME: 11. Let targetSnapshotParams be the result of snapshotting target snapshot params given navigable.
+ // 14. Let targetSnapshotParams be the result of snapshotting target snapshot params given navigable.
+ [[maybe_unused]] auto target_snapshot_params = snapshot_target_snapshot_params();
- // FIXME: 12. Invoke WebDriver BiDi navigation started with targetBrowsingContext, and a new WebDriver BiDi navigation status whose id is navigationId, url is url, and status is "pending".
+ // 15. Invoke WebDriver BiDi navigation started with targetBrowsingContext, and a new WebDriver BiDi navigation status whose id is navigationId, url is url, and status is "pending".
- // 13. If navigable's ongoing navigation is "traversal", then:
+ // 16. If navigable's ongoing navigation is "traversal", then:
if (ongoing_navigation().has()) {
// FIXME: 1. Invoke WebDriver BiDi navigation failed with targetBrowsingContext and a new WebDriver BiDi navigation status whose id is navigationId, status is "canceled", and url is url.
@@ -887,22 +919,53 @@ WebIDL::ExceptionOr Navigable::navigate(
return {};
}
- // 14. Set navigable's ongoing navigation to navigationId.
+ // 17. Set navigable's ongoing navigation to navigationId.
m_ongoing_navigation = navigation_id;
- // 15. If url's scheme is "javascript", then:
+ // 18. If url's scheme is "javascript", then:
if (url.scheme() == "javascript"sv) {
// 1. 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, and cspNavigationType.
queue_global_task(Task::Source::NavigationAndTraversal, *active_window(), [this, url, history_handling, initiator_origin_snapshot, csp_navigation_type] {
- (void)navigate_to_a_javascript_url(url, history_handling, initiator_origin_snapshot, csp_navigation_type);
+ (void)navigate_to_a_javascript_url(url, to_history_handling_behavior(history_handling), initiator_origin_snapshot, csp_navigation_type);
});
// 2. Return.
return {};
}
- // 16. In parallel, run these steps:
- Platform::EventLoopPlugin::the().deferred_invoke([this, source_snapshot_params = move(source_snapshot_params), document_resource, url, navigation_id, referrer_policy, initiator_origin_snapshot, response, history_handling] {
+ // 19. 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:
+ if (user_involvement != UserNaviagationInvolvement::BrowserUI && active_document.origin().is_same_origin_domain(source_document->origin()) && !active_document.is_initial_about_blank() && Fetch::Infrastructure::is_fetch_scheme(url.scheme())) {
+ // 1. Let navigation be navigable's active window's navigation API.
+ auto navigation = active_window()->navigation();
+
+ // 2. Let entryListForFiring be formDataEntryList if documentResource is a POST resource; otherwise, null.
+ auto entry_list_for_firing = [&]() -> Optional&> {
+ if (document_resource.has())
+ return form_data_entry_list;
+ return {};
+ }();
+
+ // 3. Let navigationAPIStateForFiring be navigationAPIState if navigationAPIState is not null;
+ // otherwise, StructuredSerializeForStorage(undefined).
+ auto navigation_api_state_for_firing = navigation_api_state.value_or(MUST(structured_serialize_for_storage(vm, JS::js_undefined())));
+
+ // FIXME: 4. 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,
+ // formDataEntryList set to entryListForFiring, destinationURL set to url, and navigationAPIState set to navigationAPIStateForFiring.
+ (void)navigation;
+ (void)entry_list_for_firing;
+ (void)navigation_api_state_for_firing;
+
+ // FIXME: 5. If continue is false, then return.
+ }
+
+ // 20. In parallel, run these steps:
+ Platform::EventLoopPlugin::the().deferred_invoke([this, source_snapshot_params = move(source_snapshot_params), document_resource, url, navigation_id, referrer_policy, initiator_origin_snapshot, response, history_handling, initiator_base_url_snapshot] {
// FIXME: 1. Let unloadPromptCanceled be the result of checking if unloading is user-canceled for navigable's active document's inclusive descendant navigables.
// FIXME: 2. If unloadPromptCanceled is true, or navigable's ongoing navigation is no longer navigationId, then:
@@ -915,8 +978,8 @@ WebIDL::ExceptionOr Navigable::navigate(
// 3. Queue a global task on the navigation and traversal task source given navigable's active window to abort navigable's active document.
queue_global_task(Task::Source::NavigationAndTraversal, *active_window(), [this] {
- VERIFY(active_document());
- active_document()->abort();
+ VERIFY(this->active_document());
+ this->active_document()->abort();
});
// 4. Let documentState be a new document state with
@@ -926,21 +989,21 @@ WebIDL::ExceptionOr Navigable::navigate(
// navigable target name: navigable's target name
JS::NonnullGCPtr document_state = *heap().allocate_without_realm();
document_state->set_request_referrer_policy(referrer_policy);
- document_state->set_resource(document_resource);
document_state->set_initiator_origin(initiator_origin_snapshot);
+ document_state->set_resource(document_resource);
document_state->set_navigable_target_name(target_name());
- // 5. If url is about:blank, then set documentState's origin to documentState's initiator origin.
- if (url == "about:blank"sv) {
+ // 5. If url matches about:blank or is about:srcdoc, then set documentState's origin to documentState's initiator origin.
+ // FIXME: should this say "matches about:srcdoc"
+ if (url_matches_about_blank(url) || url == "about:srcdoc"sv) {
+ // 1. Set documentState's origin to initiatorOriginSnapshot.
document_state->set_origin(document_state->initiator_origin());
+
+ // 2. Set documentState's about base URL to initiatorBaseURLSnapshot.
+ document_state->set_about_base_url(initiator_base_url_snapshot);
}
- // 6. Otherwise, if url is about:srcdoc, then set documentState's origin to navigable's parent's active document's origin.
- else if (url == "about:srcdoc"sv) {
- document_state->set_origin(parent()->active_document()->origin());
- }
-
- // 7. Let historyEntry be a new session history entry, with its URL set to url and its document state set to documentState.
+ // 6. Let historyEntry be a new session history entry, with its URL set to url and its document state set to documentState.
JS::NonnullGCPtr history_entry = *heap().allocate_without_realm();
history_entry->url = url;
history_entry->document_state = document_state;
@@ -957,62 +1020,8 @@ WebIDL::ExceptionOr Navigable::navigate(
// targetSnapshotParams, navigationId, navigationParams, cspNavigationType, with allowPOST
// set to true and completionSteps set to the following step:
populate_session_history_entry_document(history_entry, navigation_params, navigation_id, source_snapshot_params, true, [this, history_entry, history_handling, navigation_id] {
- traversable_navigable()->append_session_history_traversal_steps([this, history_entry, history_handling, navigation_id] {
- // https://html.spec.whatwg.org/multipage/browsing-the-web.html#finalize-a-cross-document-navigation
-
- // 1. FIXME: Assert: this is running on navigable's traversable navigable's session history traversal queue.
-
- // 2. Set navigable's is delaying load events to false.
- set_delaying_load_events(false);
-
- // 3. If historyEntry's document is null, then return.
- if (!history_entry->document_state->document())
- return;
-
- // 4. FIXME: 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.
-
- // 5. Let entryToReplace be navigable's active session history entry if historyHandling is "replace", otherwise null.
- auto entry_to_replace = history_handling == HistoryHandlingBehavior::Replace ? active_session_history_entry() : nullptr;
-
- // 6. Let traversable be navigable's traversable navigable.
- auto traversable = traversable_navigable();
-
- // 7. Let targetStep be null.
- int target_step;
-
- // 8. Let targetEntries be the result of getting session history entries for navigable.
- auto& target_entries = get_session_history_entries();
-
- // 9. If entryToReplace is null, then:
- if (entry_to_replace == nullptr) {
- // FIXME: 1. Clear the forward session history of traversable.
- traversable->clear_the_forward_session_history();
-
- // 2. Set targetStep to traversable's current session history step + 1.
- target_step = traversable->current_session_history_step() + 1;
-
- // 3. Set historyEntry's step to targetStep.
- history_entry->step = target_step;
-
- // 4. Append historyEntry to targetEntries.
- target_entries.append(move(history_entry));
- } else {
- // 1. Replace entryToReplace with historyEntry in targetEntries.
- *(target_entries.find(*entry_to_replace)) = history_entry;
-
- // 2. Set historyEntry's step to entryToReplace's step.
- history_entry->step = entry_to_replace->step;
-
- // 3. Set targetStep to traversable's current session history step.
- target_step = traversable->current_session_history_step();
- }
-
- // 10. Apply the history step targetStep to traversable.
- traversable->apply_the_history_step(target_step);
+ traversable_navigable()->append_session_history_traversal_steps([this, history_entry, history_handling] {
+ finalize_a_cross_document_navigation(*this, to_history_handling_behavior(history_handling), history_entry);
});
}).release_value_but_fixme_should_propagate_errors();
});
@@ -1113,4 +1122,142 @@ bool navigation_must_be_a_replace(AK::URL const& url, DOM::Document const& docum
return url.scheme() == "javascript"sv || document.is_initial_about_blank();
}
+// https://html.spec.whatwg.org/multipage/browsing-the-web.html#allowed-to-navigate
+bool Navigable::allowed_by_sandboxing_to_navigate(Navigable const& target, SourceSnapshotParams const& source_snapshot_params)
+{
+ auto& source = *this;
+
+ auto is_ancestor_of = [](Navigable const& a, Navigable const& b) {
+ for (auto parent = b.parent(); parent; parent = parent->parent()) {
+ if (parent.ptr() == &a)
+ return true;
+ }
+ return false;
+ };
+
+ // 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:
+
+ // 1. If source is target, then return true.
+ if (&source == &target)
+ return true;
+
+ // 2. If source is an ancestor of target, then return true.
+ if (is_ancestor_of(source, target))
+ return true;
+
+ // 3. If target is an ancestor of source, then:
+ if (is_ancestor_of(target, source)) {
+
+ // 1. If target is not a top-level traversable, then return true.
+ if (!target.is_top_level_traversable())
+ return true;
+
+ // 2. 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 (source_snapshot_params.has_transient_activation && has_flag(source_snapshot_params.sandboxing_flags, SandboxingFlagSet::SandboxedTopLevelNavigationWithUserActivation))
+ return false;
+
+ // 3. 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.
+ if (!source_snapshot_params.has_transient_activation && has_flag(source_snapshot_params.sandboxing_flags, SandboxingFlagSet::SandboxedTopLevelNavigationWithoutUserActivation))
+ return false;
+
+ // 4. Return true.
+ return true;
+ }
+
+ // 4. If target is a top-level traversable:
+ if (target.is_top_level_traversable()) {
+ // FIXME: 1. If source is the one permitted sandboxed navigator of target, then return true.
+
+ // 2. If sourceSnapshotParams's sandboxing flags's sandboxed navigation browsing context flag is set, then return false.
+ if (has_flag(source_snapshot_params.sandboxing_flags, SandboxingFlagSet::SandboxedNavigation))
+ return false;
+
+ // 3. Return true.
+ return true;
+ }
+
+ // 5. If sourceSnapshotParams's sandboxing flags's sandboxed navigation browsing context flag is set, then return false.
+ // 6. Return true.
+ return !has_flag(source_snapshot_params.sandboxing_flags, SandboxingFlagSet::SandboxedNavigation);
+}
+
+// https://html.spec.whatwg.org/multipage/browsing-the-web.html#snapshotting-target-snapshot-params
+TargetSnapshotParams Navigable::snapshot_target_snapshot_params()
+{
+ // 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.
+
+ return { determine_the_creation_sandboxing_flags(*active_browsing_context(), container()) };
+}
+
+// https://html.spec.whatwg.org/multipage/browsing-the-web.html#finalize-a-cross-document-navigation
+void finalize_a_cross_document_navigation(JS::NonnullGCPtr navigable, HistoryHandlingBehavior history_handling, JS::NonnullGCPtr history_entry)
+{
+ // 1. FIXME: Assert: this is running on navigable's traversable navigable's session history traversal queue.
+
+ // 2. Set navigable's is delaying load events to false.
+ navigable->set_delaying_load_events(false);
+
+ // 3. If historyEntry's document is null, then return.
+ if (!history_entry->document_state->document())
+ return;
+
+ // 4. 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.
+ if (navigable->parent() == nullptr && history_entry->document_state->document()->browsing_context()->opener_browsing_context() != nullptr && history_entry->document_state->document()->origin() != navigable->active_document()->origin())
+ history_entry->document_state->set_navigable_target_name(String {});
+
+ // 5. Let entryToReplace be navigable's active session history entry if historyHandling is "replace", otherwise null.
+ auto entry_to_replace = history_handling == HistoryHandlingBehavior::Replace ? navigable->active_session_history_entry() : nullptr;
+
+ // 6. Let traversable be navigable's traversable navigable.
+ auto traversable = navigable->traversable_navigable();
+
+ // 7. Let targetStep be null.
+ int target_step;
+
+ // 8. Let targetEntries be the result of getting session history entries for navigable.
+ auto& target_entries = navigable->get_session_history_entries();
+
+ // 9. If entryToReplace is null, then:
+ if (entry_to_replace == nullptr) {
+ // 1. Clear the forward session history of traversable.
+ traversable->clear_the_forward_session_history();
+
+ // 2. Set targetStep to traversable's current session history step + 1.
+ target_step = traversable->current_session_history_step() + 1;
+
+ // 3. Set historyEntry's step to targetStep.
+ history_entry->step = target_step;
+
+ // 4. Append historyEntry to targetEntries.
+ target_entries.append(history_entry);
+ } else {
+ // 1. Replace entryToReplace with historyEntry in targetEntries.
+ *(target_entries.find(*entry_to_replace)) = history_entry;
+
+ // 2. Set historyEntry's step to entryToReplace's step.
+ history_entry->step = entry_to_replace->step;
+
+ // 3. 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.
+ if (history_entry->document_state->origin().has_value() && entry_to_replace->document_state->origin().has_value() && history_entry->document_state->origin()->is_same_origin(*entry_to_replace->document_state->origin())) {
+ history_entry->navigation_api_key = entry_to_replace->navigation_api_key;
+ }
+
+ // 4. Set targetStep to traversable's current session history step.
+ target_step = traversable->current_session_history_step();
+ }
+
+ // FIXME: 10. Apply the push/replace history step targetStep to traversable.
+ traversable->apply_the_history_step(target_step);
+}
+
}
diff --git a/Userland/Libraries/LibWeb/HTML/Navigable.h b/Userland/Libraries/LibWeb/HTML/Navigable.h
index 3468303f94..7195256fa6 100644
--- a/Userland/Libraries/LibWeb/HTML/Navigable.h
+++ b/Userland/Libraries/LibWeb/HTML/Navigable.h
@@ -9,12 +9,16 @@
#include
#include
+#include
#include
#include
#include
#include
+#include
#include
+#include
#include
+#include
namespace Web::HTML {
@@ -23,6 +27,18 @@ enum class CSPNavigationType {
FormSubmission,
};
+// https://html.spec.whatwg.org/multipage/browsing-the-web.html#user-navigation-involvement
+enum class UserNaviagationInvolvement {
+ BrowserUI,
+ Activation,
+ None,
+};
+
+// https://html.spec.whatwg.org/multipage/browsing-the-web.html#target-snapshot-params
+struct TargetSnapshotParams {
+ SandboxingFlagSet sandboxing_flags {};
+};
+
// https://html.spec.whatwg.org/multipage/document-sequences.html#navigable
class Navigable : public JS::Cell {
JS_CELL(Navigable, JS::Cell);
@@ -97,9 +113,11 @@ public:
Variant document_resource = Empty {},
JS::GCPtr = nullptr,
bool exceptions_enabled = false,
- HistoryHandlingBehavior = HistoryHandlingBehavior::Push,
- CSPNavigationType csp_navigation_type = CSPNavigationType::Other,
- ReferrerPolicy::ReferrerPolicy = ReferrerPolicy::ReferrerPolicy::EmptyString);
+ Bindings::NavigationHistoryBehavior = Bindings::NavigationHistoryBehavior::Auto,
+ Optional navigation_api_state = {},
+ Optional&> form_data_entry_list = {},
+ ReferrerPolicy::ReferrerPolicy = ReferrerPolicy::ReferrerPolicy::EmptyString,
+ UserNaviagationInvolvement = UserNaviagationInvolvement::None);
WebIDL::ExceptionOr navigate_to_a_fragment(AK::URL const&, HistoryHandlingBehavior, String navigation_id);
@@ -116,6 +134,9 @@ protected:
Variant m_ongoing_navigation;
private:
+ bool allowed_by_sandboxing_to_navigate(Navigable const& target, SourceSnapshotParams const&);
+ TargetSnapshotParams snapshot_target_snapshot_params();
+
// https://html.spec.whatwg.org/multipage/document-sequences.html#nav-id
String m_id;
@@ -139,5 +160,6 @@ private:
};
bool navigation_must_be_a_replace(AK::URL const& url, DOM::Document const& document);
+void finalize_a_cross_document_navigation(JS::NonnullGCPtr, HistoryHandlingBehavior, JS::NonnullGCPtr);
}