diff --git a/experiments/WebScene.NativeEngine.Probe/native/webscene_v8_runtime_cache_and_frames.inc b/experiments/WebScene.NativeEngine.Probe/native/webscene_v8_runtime_cache_and_frames.inc index 211c9f2d..03f954dd 100644 --- a/experiments/WebScene.NativeEngine.Probe/native/webscene_v8_runtime_cache_and_frames.inc +++ b/experiments/WebScene.NativeEngine.Probe/native/webscene_v8_runtime_cache_and_frames.inc @@ -2194,7 +2194,8 @@ auto* candidate = document.find_by_native_id(iterator->first); auto stale = candidate == nullptr || !is_connected(*candidate); if (!stale) { - const auto candidate_source = candidate->attributes.find("src"); + const auto candidate_source = candidate->attributes.find( + "data-webscene-remote-attempt"); stale = candidate_source == candidate->attributes.end() || candidate_source->second != iterator->second.source || current_iframe_navigation_generation(candidate->id) @@ -2362,7 +2363,8 @@ { const auto known = pending_frame_preparations.find(frame.id); if (known == pending_frame_preparations.end()) return {}; - const auto source = frame.attributes.find("src"); + const auto source = frame.attributes.find( + "data-webscene-remote-attempt"); if (source == frame.attributes.end() || source->second != known->second.source || current_iframe_navigation_generation(frame.id) @@ -2772,19 +2774,24 @@ && source != frame.attributes.end()) { std::string html; std::string resolved_name; + const auto attempted = frame.attributes.find( + "data-webscene-remote-attempt"); + const auto& requested = attempted == frame.attributes.end() + ? source->second : attempted->second; if (!load_text_resource( - source->second, + requested, {}, WEBSCENE_RESOURCE_DOCUMENT, html, resolved_name)) { frame.attributes["data-webscene-remote-result"] = "failed"; frame_last_error_value = "Unable to load iframe document: " - + source->second; + + requested; ++frame_script_error_count; return frame_hydration_result::failed; } - frame.attributes["src"] = std::move(resolved_name); + frame.attributes["data-webscene-remote-attempt"] = + std::move(resolved_name); frame.attributes["object-html"] = std::move(html); frame.attributes["data-webscene-remote-result"] = "loaded"; } @@ -2804,10 +2811,15 @@ } const auto frame_source = frame.attributes.find("src"); const auto parent_base = effective_document_base(css_cascade_root_for_node(frame)); - const auto frame_navigation_address = frame_source != frame.attributes.end() - && !frame_source->second.empty() - ? resolve_resource_url(frame_source->second, parent_base) - : parent_base; + const auto remote_attempt = frame.attributes.find( + "data-webscene-remote-attempt"); + const auto frame_navigation_address = + remote_attempt != frame.attributes.end() + ? remote_attempt->second + : frame_source != frame.attributes.end() + && !frame_source->second.empty() + ? resolve_resource_url(frame_source->second, parent_base) + : parent_base; // Commit the replacement origin before creating its realm. The // outgoing realm remains authoritative throughout beforeunload and // unload, and the new realm cannot inherit access from reflected src. @@ -2835,9 +2847,10 @@ ? std::string{} : html.substr(open, close - open + 1U); }; - frame_base_address = frame_source != frame.attributes.end() - && (frame_source->second.starts_with("http://") - || frame_source->second.starts_with("https://")) + frame_base_address = remote_attempt != frame.attributes.end() + || (frame_source != frame.attributes.end() + && (frame_source->second.starts_with("http://") + || frame_source->second.starts_with("https://"))) ? frame_navigation_address : parent_base; const auto base_opening = opening_tag("base"); diff --git a/experiments/WebScene.NativeEngine.Probe/native/webscene_v8_runtime_dom_core.inc b/experiments/WebScene.NativeEngine.Probe/native/webscene_v8_runtime_dom_core.inc index f063dd49..97eae64e 100644 --- a/experiments/WebScene.NativeEngine.Probe/native/webscene_v8_runtime_dom_core.inc +++ b/experiments/WebScene.NativeEngine.Probe/native/webscene_v8_runtime_dom_core.inc @@ -3051,11 +3051,10 @@ || resolved.starts_with("https://") || resolved.starts_with("file://")) { node.attributes["data-webscene-remote-attempt"] = resolved; - node.attributes["src"] = resolved; if (prefetch_iframe_documents) { start_resource_prefetch( resolved, - {}, + resolved, WEBSCENE_RESOURCE_DOCUMENT); start_frame_preparation(node, resolved); node.attributes["data-webscene-remote-result"] = "pending"; @@ -3068,6 +3067,8 @@ WEBSCENE_RESOURCE_DOCUMENT, html, resolved_name)) { + node.attributes["data-webscene-remote-attempt"] = + std::move(resolved_name); node.attributes["object-html"] = std::move(html); node.attributes["data-webscene-remote-result"] = "loaded"; } else { diff --git a/experiments/WebScene.NativeEngine.Probe/tests/native_v8_runtime_resource_tests.inc b/experiments/WebScene.NativeEngine.Probe/tests/native_v8_runtime_resource_tests.inc index 4f224efb..892c1699 100644 --- a/experiments/WebScene.NativeEngine.Probe/tests/native_v8_runtime_resource_tests.inc +++ b/experiments/WebScene.NativeEngine.Probe/tests/native_v8_runtime_resource_tests.inc @@ -312,7 +312,7 @@ void test_same_origin_iframe_navigation_document_replacement() complete:false, error:null, beforeunload:0, pagehide:0, visibilitychange:0, unload:0, order:[], synchronous:true, eventShape:true, vetoPreserved:false, - reentrantBlocked:false, reentrantUnloadBlocked:false, + reentrantBlocked:false, reentrantUnloadBlocked:false, observedSource:null, visibilityHidden:false, lifecycleIdentity:true, taskRan:false, allowedLoaded:false, stableProxy:false }; @@ -414,7 +414,8 @@ void test_same_origin_iframe_navigation_document_replacement() && state.pagehide === 1 && state.visibilitychange === 1 && state.unload === 1; - state.reentrantUnloadBlocked = frame.getAttribute('src') + state.observedSource = frame.getAttribute('src'); + state.reentrantUnloadBlocked = state.observedSource === './fake.html?id=allowed' && state.order.join(',') === 'beforeunload,pagehide,visibilitychange,unload'; @@ -461,7 +462,9 @@ void test_same_origin_iframe_navigation_document_replacement() "iframe-beforeunload-result-detail.js")); require(server.requests.load(std::memory_order_relaxed) == requests_before_unload_ordering + 2, - "reentrant unload navigation admitted an unexpected resource request"); + "reentrant unload navigation admitted an unexpected resource request: before=" + + std::to_string(requests_before_unload_ordering) + " after=" + + std::to_string(server.requests.load(std::memory_order_relaxed))); const auto requests_before_detach_unload = server.requests.load( std::memory_order_relaxed); execute(engine, R"JS(