Site Isolation: Cross-Site iframe history.back() Support
e12ff02
Source/WebCore/loader/NavigationScheduler.cpp
-ScheduledHistoryNavigation::ScheduledHistoryNavigation(int historySteps)
- : ScheduledNavigation(0, lockHistory, lockBackForwardList, false, true)
- , m_historySteps(historySteps)
- , m_historyItem(page.backForward().itemAtIndex(historySteps))
-{ }
+ScheduledHistoryNavigation::ScheduledHistoryNavigation(int historySteps)
+ : ScheduledNavigation(0, lockHistory, lockBackForwardList, false, true)
+ , m_historySteps(historySteps)
+{ /* HistoryItem lookup deferred; lazy via targetHistoryItem() */ }
void ScheduledHistoryNavigation::fire(LocalFrame& frame)
{
+ if (frame.settings().useUIProcessForBackForwardItemLoading()) {
+ frame.loader().client().dispatchGoToBackForwardItemAtIndex(m_historySteps);
+ return;
+ }
auto* historyItem = targetHistoryItem();
...
}
Source/WebKit/UIProcess/WebPageProxy.cpp
+void WebPageProxy::goToBackForwardItemAtIndex(int32_t index, FrameIdentifier frameID)
+{
+ auto* item = m_backForwardList->itemAtIndex(index);
+ if (!item)
+ return;
+ updateFrameIdentifierForBackForwardItem(*item, frameID);
+ goToBackForwardItem(*item);
+}
Source/WebCore/loader/FrameLoader.cpp
+void FrameLoader::setPendingAsyncBackForwardNavigation()
+{
+ m_asyncBackForwardNavigationState = AsyncBackForwardNavigationState::Pending;
+}
+void FrameLoader::cancelPendingAsyncBackForwardNavigation()
+{
+ if (m_asyncBackForwardNavigationState == AsyncBackForwardNavigationState::Pending)
+ m_asyncBackForwardNavigationState = AsyncBackForwardNavigationState::Cancelled;
+}
WebKit's Site Isolation model places cross-site iframes in separate WebProcess instances, while the UIProcess holds the authoritative back-forward list (WebBackForwardList). Previously, NavigationScheduler in the WebProcess would eagerly resolve a HistoryItem via a sync IPC at schedule time, then call page->goToItem() directly — bypassing the UIProcess-driven path that correctly resolves per-frame state for multi-process navigations. This broke history.back() and history.go(n) for cross-site iframes under Site Isolation.
The fix makes HistoryItem lookup lazy: the WebProcess sends only a step count to the UIProcess via a new async GoToBackForwardItemAtIndex IPC message. The UIProcess resolves the correct HistoryItem and child frame state, then initiates navigation from there. A tri-state async navigation state machine (None → Pending → Cancelled) is added to FrameLoader to track traversal lifecycle. A subtle complication: spec-compliant same-document navigations (fragment changes, pushState) must not cancel in-flight traversals, so when they insert a new back-forward entry, the pending step count is adjusted.
Before (broken for cross-site frames):
history.back() → sync IPC resolveHistoryItem(step) → page->goToItem()
After (new async path):
history.back() → async IPC GoToBackForwardItemAtIndex(step)
└─► UIProcess: itemAtIndex(step) → goToBackForwardItem()
FrameLoader state:
[None] ──► setPending() ──► [Pending] ──► fragment/new load ──► [Cancelled]
Significance
This is a significant architectural shift in cross-process back-forward navigation, eliminating sync IPCs from the scheduling path. The new async model correctly resolves per-frame state but introduces complexity at the intersection of navigation scheduling and the back-forward list — a historically sensitive area for both correctness and security.
Audit directions
Aaa Aaaaaaaaa Aaaaaaa Aa Aaaaaaaaaaa Aaaaaaaa Aaaaaaaaa Aaaa Aaaaaaaaaa Aaaaaaa Aaa Aaaaa Aaa Aaaaaaaaaa Aaa Aaaaa Aaaaaaaaaaa Aa Aaa Aaaaaaaaaa Aaaaa Aaaaa a Aaaaaaaaa Aa Aaaaaaa Aaaaaaa Aaaaa Aa Aaaaaaaaaa Aaaaaa Aaa Aaaaaaaaaa Aaaaaaaaaa Aaa Aaaaaaaaaaa Aaaaaaaaaaaaa Aaaaaaaaaaa Aa Aa Aaaaaaaaaa Aaaa a Aaaaaa Aaaaa Aaaaa Aaa Aaaaaaaaa Aa Aaaaaaa Aaa Aaaaa Aaaaaaaaaaaa Aaaaaaaaaaa Aaaaaaaa Aaaa Aaaaaaaaaaa Aaa Aaa Aaa Aaaaaaa Aaaaa Aaaa a Aaaa Aaaaa Aaaa Aaa Aaaaaaaaaa Aaaaaaa a Aaaaaaaa Aaaa a a Aaaaaaaaaaa Aaaaaaaaaa Aaa Aaaaaa Aaaaaaaaa Aaaa Aaaaaaa Aa Aaaaaaaaaaaaaa Aaaaaaaaaaaaaaa Aaaaaa Aa Aaaaaaaaaaaaaaa Aaaaaaa Aaaaaaaaaaaaa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaaaaaaaaa Aaaaaaaaaaa Aa Aaaaaaaa a Aaaaaaaaa Aaaaaaaaaa Aaaaa Aaaaa a Aaaaaaaaaa Aaaaaa Aa Aaaaaaa Aaaaaaaaaa Aa Aaa Aaaaa Aaaaaa