LibWeb: Implement legacy-clone of session storage shed on window.open
When a new window is opened via window.open() with an opener (non-null), the session storage must be cloned from the opener's storage shed into the new window's storage shed. This implements the legacy-clone a traversable storage shed algorithm from the Storage spec.
This commit is contained in:
parent
93bbdf1f55
commit
437c8b1d19
10 changed files with 112 additions and 1 deletions
|
|
@ -125,7 +125,11 @@ GC::Ref<TraversableNavigable> 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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<u64> quota)
|
||||
: StorageBottle(quota)
|
||||
|
|
|
|||
|
|
@ -4,9 +4,11 @@
|
|||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <AK/TypeCasts.h>
|
||||
#include <LibGC/Heap.h>
|
||||
#include <LibWeb/HTML/Scripting/Environments.h>
|
||||
#include <LibWeb/HTML/Window.h>
|
||||
#include <LibWeb/StorageAPI/StorageBottle.h>
|
||||
#include <LibWeb/StorageAPI/StorageShed.h>
|
||||
|
||||
namespace Web::StorageAPI {
|
||||
|
|
@ -38,4 +40,28 @@ GC::Ptr<StorageShelf> 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> 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<SessionStorageBottle>(new_shelf_bottle).copy_map_from(static_cast<SessionStorageBottle const&>(shelf_bottle));
|
||||
|
||||
// 3. Set B’s storage shed[key] to newShelf.
|
||||
m_data.set(key, new_shelf);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ public:
|
|||
static GC::Ref<StorageShed> create(GC::Heap& heap) { return heap.allocate<StorageShed>(); }
|
||||
|
||||
GC::Ptr<StorageShelf> obtain_a_storage_shelf(HTML::EnvironmentSettingsObject&, StorageType);
|
||||
void legacy_clone(StorageShed const&, GC::Ref<Page>);
|
||||
|
||||
virtual void visit_edges(GC::Cell::Visitor& visitor) override;
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>WebStorage Test: sessionStorage - second page</title>
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
|
||||
var storage = window.sessionStorage;
|
||||
|
||||
var assertions = [];
|
||||
|
||||
assertions.push({
|
||||
actual: storage.getItem("FOO"),
|
||||
expected: "BAR",
|
||||
message: "storage.getItem('FOO')"
|
||||
});
|
||||
|
||||
storage.setItem("FOO", "BAR-NEWWINDOW");
|
||||
|
||||
assertions.push({
|
||||
actual: storage.getItem("FOO"),
|
||||
expected: "BAR-NEWWINDOW",
|
||||
message: "value for FOO after changing"
|
||||
});
|
||||
assertions.push({
|
||||
actual: window.opener.sessionStorage.getItem("FOO"),
|
||||
expected: "BAR",
|
||||
message: "value for FOO in my opening window"
|
||||
});
|
||||
assertions.push({
|
||||
actual: storage.getItem("BAZ"),
|
||||
expected: null,
|
||||
message: "value for BAZ set after window.open(), is not set in new window"
|
||||
});
|
||||
|
||||
window.opener.postMessage(assertions, '*');
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<!doctype html>
|
||||
<meta charset=utf-8>
|
||||
|
||||
<script src="../resources/testharness.js"></script>
|
||||
<script src="../resources/testharnessreport.js"></script>
|
||||
|
||||
<div id=log></div>
|
||||
<script src="../webstorage/storage_session_window_open.window.js"></script>
|
||||
|
|
@ -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");
|
||||
Loading…
Reference in a new issue