Skip to content

Commit 896441c

Browse files
committed
LibWeb+LibWebView: Send targeted session history entry updates
Avoid sending a complete session history snapshot when Navigation.updateCurrentEntry() changes Navigation API state or when History.scrollRestoration changes the current entry. Instead, send two typed messages identifying the entry using its navigable ID and existing Navigation API key. Apply the changes directly to the UI process's canonical TraversableSessionHistory, including copies stored in nested histories and the WebContent-known history. This replaces full WebContent-produced snapshots for these two cases with targeted UI-process entry updates, moving us toward the UI-owned session history model required for site isolation.
1 parent 04bfdaf commit 896441c

15 files changed

Lines changed: 211 additions & 4 deletions

Libraries/LibWeb/HTML/History.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,11 @@ WebIDL::ExceptionOr<void> History::set_scroll_restoration(Bindings::ScrollRestor
269269
break;
270270
}
271271

272+
if (this_relevant_global_object.associated_document().page().client().should_report_session_history_updates()) {
273+
auto navigable = this_relevant_global_object.navigable();
274+
this_relevant_global_object.associated_document().page().client().page_did_update_session_history_entry_scroll_restoration_mode(navigable->id(), active_session_history_entry->navigation_api_key(), active_session_history_entry->scroll_restoration_mode());
275+
}
276+
272277
return {};
273278
}
274279

Libraries/LibWeb/HTML/Navigation.cpp

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ GC_DEFINE_ALLOCATOR(NavigationAPIMethodTracker);
3838

3939
static Bindings::NavigationResult navigation_api_method_tracker_derived_result(GC::Ref<NavigationAPIMethodTracker> api_method_tracker);
4040

41-
static void report_session_history_update_for_navigation_api_state_change(DOM::Document& document)
41+
static void report_navigation_api_state_update(DOM::Document& document, SessionHistoryEntry const& entry)
4242
{
4343
auto navigable = document.navigable();
4444
if (!navigable)
@@ -48,8 +48,7 @@ static void report_session_history_update_for_navigation_api_state_change(DOM::D
4848
if (!traversable->page().client().should_report_session_history_updates())
4949
return;
5050

51-
auto session_history_snapshot = traversable->create_session_history_snapshot();
52-
traversable->page().client().page_did_update_session_history(session_history_snapshot.top_level_session_history_entries, session_history_snapshot.used_session_history_steps, session_history_snapshot.current_used_step_index);
51+
traversable->page().client().page_did_update_session_history_entry_navigation_api_state(navigable->id(), entry.navigation_api_key(), entry.navigation_api_state());
5352
}
5453

5554
NavigationAPIMethodTracker::NavigationAPIMethodTracker(GC::Ref<Navigation> navigation,
@@ -161,7 +160,7 @@ WebIDL::ExceptionOr<void> Navigation::update_current_entry(Bindings::NavigationU
161160
// NB: The UI-process session history mirror needs to observe updateCurrentEntry() state changes so restored
162161
// WebContent processes can reconstruct Navigation API state from the authoritative UI-owned history.
163162
auto& document = as<HTML::Window>(relevant_global_object(*this)).associated_document();
164-
report_session_history_update_for_navigation_api_state_change(document);
163+
report_navigation_api_state_update(document, current->session_history_entry());
165164

166165
// 5. Fire an event named currententrychange at this using NavigationCurrentEntryChangeEvent,
167166
// with its navigationType attribute initialized to null and its from initialized to current.

Libraries/LibWeb/Page/Page.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -583,6 +583,8 @@ class PageClient : public JS::Cell {
583583
virtual void page_did_close_top_level_traversable() { }
584584
virtual bool should_report_session_history_updates() const { return true; }
585585
virtual void page_did_update_session_history([[maybe_unused]] Vector<HTML::SessionHistoryEntryDescriptor> const& entries, [[maybe_unused]] Vector<i32> const& used_steps, [[maybe_unused]] size_t current_used_step_index) { }
586+
virtual void page_did_update_session_history_entry_navigation_api_state([[maybe_unused]] HTML::CrossProcessId navigable_id, [[maybe_unused]] Utf16String const& navigation_api_key, [[maybe_unused]] HTML::StorageSerializationRecord const& navigation_api_state) { }
587+
virtual void page_did_update_session_history_entry_scroll_restoration_mode([[maybe_unused]] HTML::CrossProcessId navigable_id, [[maybe_unused]] Utf16String const& navigation_api_key, [[maybe_unused]] HTML::ScrollRestorationMode scroll_restoration_mode) { }
586588
virtual String page_did_request_ui_process_session_history_for_testing() { return "{}"_string; }
587589
virtual String page_did_update_session_history_and_request_ui_process_session_history_for_testing([[maybe_unused]] Vector<HTML::SessionHistoryEntryDescriptor> const& entries, [[maybe_unused]] Vector<i32> const& used_steps, [[maybe_unused]] size_t current_used_step_index) { return "{}"_string; }
588590
virtual bool page_did_request_traverse_the_history_by_delta([[maybe_unused]] int delta, [[maybe_unused]] HistoryTraversalPrecheck history_traversal_precheck) { return false; }

Libraries/LibWebView/CanonicalNavigable.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,13 @@ WebContentClient& CanonicalNavigable::reporting_client() const
2828
return *m_reporting_client;
2929
}
3030

31+
bool CanonicalNavigable::is_hosted_by(WebContentClient const& client, u64 page_id) const
32+
{
33+
if (m_host_locality == HostLocality::Remote)
34+
return m_remote_client.ptr() == &client && m_remote_page_id == page_id;
35+
return m_reporting_client.ptr() == &client && m_reporting_page_id == page_id;
36+
}
37+
3138
// https://html.spec.whatwg.org/multipage/document-sequences.html#nav-top
3239
CanonicalTraversable& CanonicalNavigable::top_level_traversable()
3340
{

Libraries/LibWebView/CanonicalNavigable.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ class WEBVIEW_API CanonicalNavigable
6868
IterationDecision for_each_in_subtree(Function<IterationDecision(CanonicalNavigable const&)> const&) const;
6969

7070
bool has_remote_host() const { return m_host_locality == HostLocality::Remote && m_remote_client && m_remote_page_id != 0; }
71+
bool is_hosted_by(WebContentClient const&, u64 page_id) const;
7172
WebContentClient& remote_host_client() const;
7273
u64 remote_host_page_id() const { return m_remote_page_id; }
7374

Libraries/LibWebView/CanonicalTraversable.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,24 @@ WebContentSessionHistoryUpdateDecision CanonicalTraversable::did_receive_web_con
264264
};
265265
}
266266

267+
bool CanonicalTraversable::update_session_history_entry_navigation_api_state(CanonicalNavigable const& navigable, Utf16String const& navigation_api_key, Web::HTML::StorageSerializationRecord navigation_api_state)
268+
{
269+
VERIFY(&navigable.top_level_traversable() == this);
270+
271+
if (&navigable == this)
272+
return m_session_history.update_top_level_navigation_api_state(navigation_api_key, move(navigation_api_state));
273+
return m_session_history.update_nested_navigation_api_state(navigable.id(), navigation_api_key, move(navigation_api_state));
274+
}
275+
276+
bool CanonicalTraversable::update_session_history_entry_scroll_restoration_mode(CanonicalNavigable const& navigable, Utf16String const& navigation_api_key, Web::HTML::ScrollRestorationMode scroll_restoration_mode)
277+
{
278+
VERIFY(&navigable.top_level_traversable() == this);
279+
280+
if (&navigable == this)
281+
return m_session_history.update_top_level_scroll_restoration_mode(navigation_api_key, scroll_restoration_mode);
282+
return m_session_history.update_nested_scroll_restoration_mode(navigable.id(), navigation_api_key, scroll_restoration_mode);
283+
}
284+
267285
WebContentSessionHistoryUpdateResult CanonicalTraversable::update_session_history_from_web_content(Vector<Web::HTML::SessionHistoryEntryDescriptor> entries, Vector<i32> used_steps, size_t current_used_step_index, bool pending_step_after_fallback_load_was_restored, bool seed_web_content_on_invalid_snapshot, URL::URL const& current_url)
268286
{
269287
auto update_result = m_session_history.update_from_web_content(move(entries), move(used_steps), current_used_step_index);

Libraries/LibWebView/CanonicalTraversable.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,8 @@ class WEBVIEW_API CanonicalTraversable final
235235
void prepare_to_seed_web_content_session_history_from_ui_process();
236236
WebContentSessionHistoryUpdateDecision did_receive_web_content_session_history_update(Vector<Web::HTML::SessionHistoryEntryDescriptor>, Vector<i32> used_steps, size_t current_used_step_index, URL::URL const& current_url);
237237
WebContentSessionHistoryUpdateDecision did_receive_web_content_session_history_update_for_testing(Vector<Web::HTML::SessionHistoryEntryDescriptor>, Vector<i32> used_steps, size_t current_used_step_index, URL::URL const& current_url);
238+
bool update_session_history_entry_navigation_api_state(CanonicalNavigable const&, Utf16String const& navigation_api_key, Web::HTML::StorageSerializationRecord navigation_api_state);
239+
bool update_session_history_entry_scroll_restoration_mode(CanonicalNavigable const&, Utf16String const& navigation_api_key, Web::HTML::ScrollRestorationMode scroll_restoration_mode);
238240
WebContentSessionHistorySeedAckResult did_receive_web_content_session_history_seed_ack(bool accepted, Vector<Web::HTML::SessionHistoryEntryDescriptor>, Vector<i32> used_steps, size_t current_used_step_index, URL::URL const& current_url);
239241
NavigationStartResult did_start_navigation(URL::URL const&, Web::HTML::DocumentResource, bool is_redirect, Web::Bindings::NavigationHistoryBehavior, bool is_showing_crash_page);
240242
NavigationCancelResult did_cancel_navigation(URL::URL const&, bool has_webdriver_pending_navigation);

Libraries/LibWebView/SessionHistory.cpp

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -484,6 +484,85 @@ void TraversableSessionHistory::clear_current_entry_reload_pending()
484484
m_entries[*current_top_level_entry_index].document_state.reload_pending = false;
485485
}
486486

487+
template<typename UpdateEntry>
488+
static bool update_session_history_entry_by_navigation_api_key(Vector<TraversableSessionHistory::Entry>& entries, Utf16String const& navigation_api_key, UpdateEntry const& update_entry)
489+
{
490+
auto did_update = false;
491+
for (auto& entry : entries) {
492+
if (entry.navigation_api_key == navigation_api_key) {
493+
update_entry(entry);
494+
did_update = true;
495+
}
496+
}
497+
return did_update;
498+
}
499+
500+
template<typename UpdateEntry>
501+
static bool update_nested_session_history_entries_by_navigation_api_key(Vector<TraversableSessionHistory::Entry>& entries, Web::HTML::CrossProcessId navigable_id, Utf16String const& navigation_api_key, UpdateEntry const& update_entry)
502+
{
503+
auto did_update = false;
504+
for (auto& entry : entries) {
505+
for (auto& nested_history : entry.document_state.nested_histories) {
506+
if (nested_history.id == navigable_id)
507+
did_update |= update_session_history_entry_by_navigation_api_key(nested_history.entries, navigation_api_key, update_entry);
508+
did_update |= update_nested_session_history_entries_by_navigation_api_key(nested_history.entries, navigable_id, navigation_api_key, update_entry);
509+
}
510+
}
511+
return did_update;
512+
}
513+
514+
template<typename UpdateEntry>
515+
static bool update_top_level_session_history_entries_by_navigation_api_key(Vector<TraversableSessionHistory::Entry>& entries, Vector<TraversableSessionHistory::Entry>& web_content_known_entries, Utf16String const& navigation_api_key, UpdateEntry const& update_entry)
516+
{
517+
auto did_update = update_session_history_entry_by_navigation_api_key(entries, navigation_api_key, update_entry);
518+
if (!did_update)
519+
return false;
520+
521+
update_session_history_entry_by_navigation_api_key(web_content_known_entries, navigation_api_key, update_entry);
522+
523+
return true;
524+
}
525+
526+
template<typename UpdateEntry>
527+
static bool update_nested_session_history_entries_by_navigation_api_key(Vector<TraversableSessionHistory::Entry>& entries, Vector<TraversableSessionHistory::Entry>& web_content_known_entries, Web::HTML::CrossProcessId nested_history_id, Utf16String const& navigation_api_key, UpdateEntry const& update_entry)
528+
{
529+
auto did_update = update_nested_session_history_entries_by_navigation_api_key(entries, nested_history_id, navigation_api_key, update_entry);
530+
if (!did_update)
531+
return false;
532+
533+
update_nested_session_history_entries_by_navigation_api_key(web_content_known_entries, nested_history_id, navigation_api_key, update_entry);
534+
535+
return true;
536+
}
537+
538+
bool TraversableSessionHistory::update_top_level_navigation_api_state(Utf16String const& navigation_api_key, Web::HTML::StorageSerializationRecord navigation_api_state)
539+
{
540+
return update_top_level_session_history_entries_by_navigation_api_key(m_entries, m_web_content_known_entries, navigation_api_key, [&](Entry& entry) {
541+
entry.navigation_api_state = navigation_api_state;
542+
});
543+
}
544+
545+
bool TraversableSessionHistory::update_nested_navigation_api_state(Web::HTML::CrossProcessId nested_history_id, Utf16String const& navigation_api_key, Web::HTML::StorageSerializationRecord navigation_api_state)
546+
{
547+
return update_nested_session_history_entries_by_navigation_api_key(m_entries, m_web_content_known_entries, nested_history_id, navigation_api_key, [&](Entry& entry) {
548+
entry.navigation_api_state = navigation_api_state;
549+
});
550+
}
551+
552+
bool TraversableSessionHistory::update_top_level_scroll_restoration_mode(Utf16String const& navigation_api_key, Web::HTML::ScrollRestorationMode scroll_restoration_mode)
553+
{
554+
return update_top_level_session_history_entries_by_navigation_api_key(m_entries, m_web_content_known_entries, navigation_api_key, [&](Entry& entry) {
555+
entry.scroll_restoration_mode = scroll_restoration_mode;
556+
});
557+
}
558+
559+
bool TraversableSessionHistory::update_nested_scroll_restoration_mode(Web::HTML::CrossProcessId nested_history_id, Utf16String const& navigation_api_key, Web::HTML::ScrollRestorationMode scroll_restoration_mode)
560+
{
561+
return update_nested_session_history_entries_by_navigation_api_key(m_entries, m_web_content_known_entries, nested_history_id, navigation_api_key, [&](Entry& entry) {
562+
entry.scroll_restoration_mode = scroll_restoration_mode;
563+
});
564+
}
565+
487566
Optional<size_t> TraversableSessionHistory::current_top_level_entry_index() const
488567
{
489568
if (!m_current_used_step_index.has_value())

Libraries/LibWebView/SessionHistory.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,10 @@ class WEBVIEW_API TraversableSessionHistory {
5959
void replace_current_entry(URL::URL, Web::HTML::CrossProcessId document_state_id, Web::HTML::DocumentResource);
6060
void mark_current_entry_reload_pending();
6161
void clear_current_entry_reload_pending();
62+
bool update_top_level_navigation_api_state(Utf16String const& navigation_api_key, Web::HTML::StorageSerializationRecord navigation_api_state);
63+
bool update_nested_navigation_api_state(Web::HTML::CrossProcessId nested_history_id, Utf16String const& navigation_api_key, Web::HTML::StorageSerializationRecord navigation_api_state);
64+
bool update_top_level_scroll_restoration_mode(Utf16String const& navigation_api_key, Web::HTML::ScrollRestorationMode scroll_restoration_mode);
65+
bool update_nested_scroll_restoration_mode(Web::HTML::CrossProcessId nested_history_id, Utf16String const& navigation_api_key, Web::HTML::ScrollRestorationMode scroll_restoration_mode);
6266
UpdateResult update_from_web_content(Vector<Entry> entries, Vector<i32> used_steps, size_t current_used_step_index);
6367
[[nodiscard]] bool did_seed_web_content_from_ui_process(Vector<Entry> entries, Vector<i32> used_steps, size_t current_used_step_index);
6468
void did_seed_web_content_from_ui_process(size_t current_top_level_entry_index);

Libraries/LibWebView/WebContentClient.cpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,22 @@ CanonicalNavigable* WebContentClient::navigable_for_page(u64 page_id)
276276
return nullptr;
277277
}
278278

279+
Optional<CanonicalNavigable&> WebContentClient::hosted_navigable_for_page(u64 page_id, Web::HTML::CrossProcessId navigable_id)
280+
{
281+
auto* page_host = navigable_for_page(page_id);
282+
if (!page_host)
283+
return {};
284+
285+
auto navigable = page_host->top_level_traversable().find(navigable_id);
286+
if (!navigable.has_value())
287+
return {};
288+
289+
if (&*navigable == page_host || navigable->is_hosted_by(*this, page_id))
290+
return *navigable;
291+
292+
return {};
293+
}
294+
279295
Optional<CanonicalNavigable&> WebContentClient::child_frame(u64 page_id, Web::HTML::CrossProcessId frame_id)
280296
{
281297
auto* host = navigable_for_page(page_id);
@@ -1803,6 +1819,22 @@ void WebContentClient::did_update_session_history(u64 page_id, Vector<Web::HTML:
18031819
view->did_update_session_history({}, move(entries), move(used_steps), current_used_step_index);
18041820
}
18051821

1822+
void WebContentClient::did_update_session_history_entry_navigation_api_state(u64 page_id, Web::HTML::CrossProcessId navigable_id, Utf16String navigation_api_key, Web::HTML::StorageSerializationRecord navigation_api_state)
1823+
{
1824+
auto navigable = hosted_navigable_for_page(page_id, navigable_id);
1825+
if (!navigable.has_value())
1826+
return;
1827+
navigable->top_level_traversable().update_session_history_entry_navigation_api_state(*navigable, navigation_api_key, move(navigation_api_state));
1828+
}
1829+
1830+
void WebContentClient::did_update_session_history_entry_scroll_restoration_mode(u64 page_id, Web::HTML::CrossProcessId navigable_id, Utf16String navigation_api_key, Web::HTML::ScrollRestorationMode scroll_restoration_mode)
1831+
{
1832+
auto navigable = hosted_navigable_for_page(page_id, navigable_id);
1833+
if (!navigable.has_value())
1834+
return;
1835+
navigable->top_level_traversable().update_session_history_entry_scroll_restoration_mode(*navigable, navigation_api_key, scroll_restoration_mode);
1836+
}
1837+
18061838
Messages::WebContentClient::DidRequestUiProcessSessionHistoryForTestingResponse WebContentClient::did_request_ui_process_session_history_for_testing(u64 page_id)
18071839
{
18081840
if (auto view = view_for_page_id(page_id); view.has_value())

0 commit comments

Comments
 (0)