mirror of
https://github.com/lexmount/moli.git
synced 2026-10-06 08:00:59 +00:00
fix(navigation): reload idle initial-empty iframe documents
This commit is contained in:
@@ -260,7 +260,7 @@ fn navigate_location_object_with_source_element_and_child_navigate_event<'s>(
|
||||
if matches!(kind, LocationNavigationKind::Reload)
|
||||
&& matches!(
|
||||
navigation_reload_admission(scope, owner),
|
||||
NavigationReloadAdmission::NoCommittedHistoryItem
|
||||
NavigationReloadAdmission::PendingInitialAttributeNavigation
|
||||
)
|
||||
{
|
||||
return;
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
use super::navigation_window::child_browsing_context_handle_for_runtime_owner;
|
||||
use super::*;
|
||||
|
||||
/// Whether the current Document owns a committed session-history item that
|
||||
/// can be used as the source of a reload.
|
||||
///
|
||||
/// An initial-empty child Document is installed synchronously before its first
|
||||
/// real navigation and deliberately has no committed history item. Reloading
|
||||
/// it must therefore leave any deferred iframe attribute navigation alone.
|
||||
/// A deferred iframe attribute navigation still belongs to the initial empty
|
||||
/// Document. Reloading that Document must leave the pending attribute load
|
||||
/// alone; an ordinary initial about:blank iframe has an active history entry
|
||||
/// and can be reloaded.
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
pub(super) enum NavigationReloadAdmission {
|
||||
NoCommittedHistoryItem,
|
||||
PendingInitialAttributeNavigation,
|
||||
Admitted,
|
||||
}
|
||||
|
||||
@@ -23,8 +21,8 @@ pub(super) fn navigation_reload_admission<'s>(
|
||||
let Some(host_ptr) = context_host_ptr_from_global_bridge(scope) else {
|
||||
return NavigationReloadAdmission::Admitted;
|
||||
};
|
||||
if unsafe { &*host_ptr }.child_current_document_is_initial_empty(handle) {
|
||||
NavigationReloadAdmission::NoCommittedHistoryItem
|
||||
if unsafe { &*host_ptr }.child_initial_empty_has_pending_attribute_navigation(handle) {
|
||||
NavigationReloadAdmission::PendingInitialAttributeNavigation
|
||||
} else {
|
||||
NavigationReloadAdmission::Admitted
|
||||
}
|
||||
|
||||
@@ -254,10 +254,10 @@ pub(super) fn navigation_reload_callback<'s>(
|
||||
}
|
||||
if matches!(
|
||||
navigation_reload_admission(scope, owner),
|
||||
NavigationReloadAdmission::NoCommittedHistoryItem
|
||||
NavigationReloadAdmission::PendingInitialAttributeNavigation
|
||||
) {
|
||||
// Navigation API methods on an initial-empty Document return a
|
||||
// correctly-shaped result whose promises intentionally never settle.
|
||||
// Reloading the initial empty Document must not replace a deferred
|
||||
// iframe attribute navigation. Its result promises remain pending.
|
||||
rv.set(navigation_pending_result(scope).into());
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -836,6 +836,17 @@ impl JsContextHost {
|
||||
.is_some_and(crate::frame_owner_model::DocumentCreationKind::is_initial_empty)
|
||||
}
|
||||
|
||||
pub(crate) fn child_initial_empty_has_pending_attribute_navigation(
|
||||
&self,
|
||||
handle: DomHandle,
|
||||
) -> bool {
|
||||
self.child_current_document_is_initial_empty(handle)
|
||||
&& self
|
||||
.child_browsing_contexts
|
||||
.get(&handle)
|
||||
.is_some_and(|entry| entry.pending_attribute_bootstrap_commit())
|
||||
}
|
||||
|
||||
pub(crate) fn retire_child_frame_realm_materialization_request(
|
||||
&mut self,
|
||||
handle: DomHandle,
|
||||
|
||||
+46
-1
@@ -2260,8 +2260,49 @@ __domainAccessFrame.src = globalThis.__replacementDomainChildUrl;
|
||||
vec!["/replacement.html"]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn initial_empty_iframe_reload_uses_shared_no_history_admission() {
|
||||
fn initial_empty_iframe_reload_methods_replace_document_and_dispatch_load() {
|
||||
for reload in ["location.reload()", "history.go(0)", "navigation.reload()"] {
|
||||
let mut vm = new_storage_test_vm("https://initial-empty-reload.test/page.html");
|
||||
|
||||
vm.exec(
|
||||
&format!(
|
||||
r#"
|
||||
const frame = document.createElement('iframe');
|
||||
(document.body || document.documentElement || document).appendChild(frame);
|
||||
globalThis.__initialReloadFrame = frame;
|
||||
globalThis.__initialReloadDocument = frame.contentDocument;
|
||||
globalThis.__initialReloadLoads = 0;
|
||||
frame.onload = () => ++__initialReloadLoads;
|
||||
frame.contentWindow.{reload};
|
||||
"#
|
||||
),
|
||||
None,
|
||||
)
|
||||
.expect("initial-empty iframe reload should evaluate");
|
||||
assert!(
|
||||
vm.has_pending_child_navigation_commit_for_test(),
|
||||
"reloading an ordinary initial about:blank iframe must queue a navigation"
|
||||
);
|
||||
|
||||
vm.drain_pending_child_frame_work_for_test();
|
||||
assert_eq!(
|
||||
vm.eval(
|
||||
r#"[
|
||||
__initialReloadFrame.contentDocument !== __initialReloadDocument,
|
||||
__initialReloadLoads,
|
||||
__initialReloadFrame.contentWindow.location.href
|
||||
].join('|')"#,
|
||||
)
|
||||
.expect("initial-empty iframe reload result should evaluate"),
|
||||
"true|1|about:blank"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn initial_empty_iframe_reload_preserves_pending_attribute_navigation_result_shape() {
|
||||
let mut vm = new_storage_test_vm("https://initial-empty-reload.test/page.html");
|
||||
|
||||
let setup = vm
|
||||
@@ -2269,6 +2310,9 @@ fn initial_empty_iframe_reload_uses_shared_no_history_admission() {
|
||||
r#"
|
||||
(() => {
|
||||
const frame = document.createElement('iframe');
|
||||
frame.loading = 'lazy';
|
||||
frame.hidden = true;
|
||||
frame.src = '/pending-attribute-navigation.html';
|
||||
(document.body || document.documentElement || document).appendChild(frame);
|
||||
const child = frame.contentWindow;
|
||||
const log = [];
|
||||
@@ -2337,6 +2381,7 @@ fn initial_empty_iframe_reload_uses_shared_no_history_admission() {
|
||||
"about:blank"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn non_initial_about_blank_iframe_remains_reloadable() {
|
||||
let mut vm = new_storage_test_vm("https://non-initial-blank-reload.test/page.html");
|
||||
|
||||
Reference in New Issue
Block a user