diff --git a/Libraries/LibWeb/HTML/TraversableNavigable.cpp b/Libraries/LibWeb/HTML/TraversableNavigable.cpp index 50466d4af3..64dbad07ce 100644 --- a/Libraries/LibWeb/HTML/TraversableNavigable.cpp +++ b/Libraries/LibWeb/HTML/TraversableNavigable.cpp @@ -125,7 +125,11 @@ GC::Ref TraversableNavigable::create_a_new_top_level_trave traversable->m_session_history_entries.append(*initial_history_entry); traversable->set_has_session_history_entry_and_ready_for_navigation(); - // FIXME: 10. If opener is non-null, then legacy-clone a traversable storage shed given opener's top-level traversable and traversable. [STORAGE] + // 10. If opener is non-null, then legacy-clone a traversable storage shed given opener's top-level traversable and traversable. [STORAGE] + if (opener) { + auto opener_traversable = opener->top_level_traversable(); + traversable->storage_shed().legacy_clone(opener_traversable->storage_shed(), page); + } // 11. Append traversable to the user agent's top-level traversable set. user_agent_top_level_traversable_set().set(traversable); diff --git a/Libraries/LibWeb/StorageAPI/StorageBottle.cpp b/Libraries/LibWeb/StorageAPI/StorageBottle.cpp index 644c2b867c..c4189a3c60 100644 --- a/Libraries/LibWeb/StorageAPI/StorageBottle.cpp +++ b/Libraries/LibWeb/StorageAPI/StorageBottle.cpp @@ -183,4 +183,9 @@ void SessionStorageBottle::remove(String const& key) m_map.remove(key); } +void SessionStorageBottle::copy_map_from(SessionStorageBottle const& other) +{ + m_map = other.m_map; +} + } diff --git a/Libraries/LibWeb/StorageAPI/StorageBottle.h b/Libraries/LibWeb/StorageAPI/StorageBottle.h index 9451cf1f14..584b39f3c5 100644 --- a/Libraries/LibWeb/StorageAPI/StorageBottle.h +++ b/Libraries/LibWeb/StorageAPI/StorageBottle.h @@ -97,6 +97,8 @@ public: virtual void clear() override; virtual void remove(String const&) override; + void copy_map_from(SessionStorageBottle const&); + private: explicit SessionStorageBottle(Optional quota) : StorageBottle(quota) diff --git a/Libraries/LibWeb/StorageAPI/StorageShed.cpp b/Libraries/LibWeb/StorageAPI/StorageShed.cpp index 812abfcaad..d923e09997 100644 --- a/Libraries/LibWeb/StorageAPI/StorageShed.cpp +++ b/Libraries/LibWeb/StorageAPI/StorageShed.cpp @@ -4,9 +4,11 @@ * SPDX-License-Identifier: BSD-2-Clause */ +#include #include #include #include +#include #include namespace Web::StorageAPI { @@ -38,4 +40,28 @@ GC::Ptr StorageShed::obtain_a_storage_shelf(HTML::EnvironmentSetti }); } +// https://storage.spec.whatwg.org/#legacy-clone-a-traversable-storage-shed +// To legacy-clone a traversable storage shed, given a traversable navigable A and a traversable navigable B, run these steps: +void StorageShed::legacy_clone(StorageShed const& a_storage_shed, GC::Ref page) +{ + // 1. For each key → shelf of A’s storage shed: + for (auto const& [key, shelf] : a_storage_shed.m_data) { + + // 1. Let newShelf be the result of running create a storage shelf with "session". + auto new_shelf = StorageShelf::create(heap(), page, key, StorageType::Session); + + // 2. Set newShelf’s bucket map["default"]'s bottle map["sessionStorage"]'s map to a clone of shelf’s bucket map["default"]'s bottle map["sessionStorage"]'s map. + auto& shelf_bucket = *shelf->bucket_map().get("default"sv).value(); + auto& new_shelf_bucket = *new_shelf->bucket_map().get("default"sv).value(); + + auto const& shelf_bottle = *shelf_bucket.bottle_map()[to_underlying(StorageEndpointType::SessionStorage)]; + auto& new_shelf_bottle = *new_shelf_bucket.bottle_map()[to_underlying(StorageEndpointType::SessionStorage)]; + + as(new_shelf_bottle).copy_map_from(static_cast(shelf_bottle)); + + // 3. Set B’s storage shed[key] to newShelf. + m_data.set(key, new_shelf); + } +} + } diff --git a/Libraries/LibWeb/StorageAPI/StorageShed.h b/Libraries/LibWeb/StorageAPI/StorageShed.h index 9bcf643b04..41966960f9 100644 --- a/Libraries/LibWeb/StorageAPI/StorageShed.h +++ b/Libraries/LibWeb/StorageAPI/StorageShed.h @@ -25,6 +25,7 @@ public: static GC::Ref create(GC::Heap& heap) { return heap.allocate(); } GC::Ptr obtain_a_storage_shelf(HTML::EnvironmentSettingsObject&, StorageType); + void legacy_clone(StorageShed const&, GC::Ref); virtual void visit_edges(GC::Cell::Visitor& visitor) override; diff --git a/Tests/LibWeb/TestConfig.ini b/Tests/LibWeb/TestConfig.ini index f257414c04..40bce6b484 100644 --- a/Tests/LibWeb/TestConfig.ini +++ b/Tests/LibWeb/TestConfig.ini @@ -32,6 +32,7 @@ Text/input/wpt-import/html/syntax/parsing/unclosed-svg-script.html ; These tests require cross-origin iframe access to succeed. Text/input/wpt-import/webstorage/event_session_oldvalue.html Text/input/wpt-import/webstorage/event_session_storagearea.html +Text/input/wpt-import/webstorage/storage_session_window_open.window.html Text/input/navigation/navigation-navigate.html Text/input/navigation/location-reload-fetch.html Text/input/HTML/session-storage-event-fired-to-lazy-window.html diff --git a/Tests/LibWeb/Text/expected/wpt-import/webstorage/storage_session_window_open.window.txt b/Tests/LibWeb/Text/expected/wpt-import/webstorage/storage_session_window_open.window.txt new file mode 100644 index 0000000000..d6a98cbd25 --- /dev/null +++ b/Tests/LibWeb/Text/expected/wpt-import/webstorage/storage_session_window_open.window.txt @@ -0,0 +1,6 @@ +Harness status: OK + +Found 1 tests + +1 Pass +Pass A new window to make sure there is a copy of the previous window's sessionStorage, and that they diverge after a change \ No newline at end of file diff --git a/Tests/LibWeb/Text/input/wpt-import/webstorage/resources/storage_session_window_open_second.html b/Tests/LibWeb/Text/input/wpt-import/webstorage/resources/storage_session_window_open_second.html new file mode 100644 index 0000000000..2eeff0b865 --- /dev/null +++ b/Tests/LibWeb/Text/input/wpt-import/webstorage/resources/storage_session_window_open_second.html @@ -0,0 +1,41 @@ + + + +WebStorage Test: sessionStorage - second page + + + + + diff --git a/Tests/LibWeb/Text/input/wpt-import/webstorage/storage_session_window_open.window.html b/Tests/LibWeb/Text/input/wpt-import/webstorage/storage_session_window_open.window.html new file mode 100644 index 0000000000..a6d935f5b1 --- /dev/null +++ b/Tests/LibWeb/Text/input/wpt-import/webstorage/storage_session_window_open.window.html @@ -0,0 +1,8 @@ + + + + + + +
+ diff --git a/Tests/LibWeb/Text/input/wpt-import/webstorage/storage_session_window_open.window.js b/Tests/LibWeb/Text/input/wpt-import/webstorage/storage_session_window_open.window.js new file mode 100644 index 0000000000..83d4447017 --- /dev/null +++ b/Tests/LibWeb/Text/input/wpt-import/webstorage/storage_session_window_open.window.js @@ -0,0 +1,17 @@ +async_test(function(t) { + + var storage = window.sessionStorage; + storage.clear(); + + storage.setItem("FOO", "BAR"); + var win = window.open("resources/storage_session_window_open_second.html"); + storage.setItem("BAZ", "QUX"); + window.addEventListener('message', t.step_func(function(e) { + e.data.forEach(t.step_func(function(assertion) { + assert_equals(assertion.actual, assertion.expected, assertion.message); + })); + win.close(); + t.done(); + })); + +}, "A new window to make sure there is a copy of the previous window's sessionStorage, and that they diverge after a change");