LibWeb: Use StructuredSerializeWithTransfer in window.postMessage()

And update tests to transfer message a message port between iframes.
This commit is contained in:
Andrew Kaster 2023-12-12 13:41:03 -07:00 committed by Andrew Kaster
parent 84ac6a454f
commit ec11743fae
3 changed files with 68 additions and 18 deletions

View file

@ -32,6 +32,9 @@ Message 1 data: undefined
Message 1 origin: file://
Message 1 lastEventId:
Message 1 source: [object Window]
Message 1 ports:
Message 1 ports === ports: true
Message 1 Object.isFrozen(ports): true
Message 1 source === window: true
Message 1 source === iframe.contentWindow: false
Message 1 source === blobIframe.contentWindow: false
@ -39,6 +42,9 @@ Message 2 data: null
Message 2 origin: file://
Message 2 lastEventId:
Message 2 source: [object Window]
Message 2 ports:
Message 2 ports === ports: true
Message 2 Object.isFrozen(ports): true
Message 2 source === window: true
Message 2 source === iframe.contentWindow: false
Message 2 source === blobIframe.contentWindow: false
@ -46,6 +52,9 @@ Message 3 data: true
Message 3 origin: file://
Message 3 lastEventId:
Message 3 source: [object Window]
Message 3 ports:
Message 3 ports === ports: true
Message 3 Object.isFrozen(ports): true
Message 3 source === window: true
Message 3 source === iframe.contentWindow: false
Message 3 source === blobIframe.contentWindow: false
@ -53,6 +62,9 @@ Message 4 data: false
Message 4 origin: file://
Message 4 lastEventId:
Message 4 source: [object Window]
Message 4 ports:
Message 4 ports === ports: true
Message 4 Object.isFrozen(ports): true
Message 4 source === window: true
Message 4 source === iframe.contentWindow: false
Message 4 source === blobIframe.contentWindow: false
@ -60,6 +72,9 @@ Message 5 data: 123
Message 5 origin: file://
Message 5 lastEventId:
Message 5 source: [object Window]
Message 5 ports:
Message 5 ports === ports: true
Message 5 Object.isFrozen(ports): true
Message 5 source === window: true
Message 5 source === iframe.contentWindow: false
Message 5 source === blobIframe.contentWindow: false
@ -67,6 +82,9 @@ Message 6 data: 123.456
Message 6 origin: file://
Message 6 lastEventId:
Message 6 source: [object Window]
Message 6 ports:
Message 6 ports === ports: true
Message 6 Object.isFrozen(ports): true
Message 6 source === window: true
Message 6 source === iframe.contentWindow: false
Message 6 source === blobIframe.contentWindow: false
@ -74,6 +92,9 @@ Message 7 data: 9007199254740991
Message 7 origin: file://
Message 7 lastEventId:
Message 7 source: [object Window]
Message 7 ports:
Message 7 ports === ports: true
Message 7 Object.isFrozen(ports): true
Message 7 source === window: true
Message 7 source === iframe.contentWindow: false
Message 7 source === blobIframe.contentWindow: false
@ -81,20 +102,39 @@ Message 8 data: This is a string
Message 8 origin: file://
Message 8 lastEventId:
Message 8 source: [object Window]
Message 8 ports:
Message 8 ports === ports: true
Message 8 Object.isFrozen(ports): true
Message 8 source === window: true
Message 8 source === iframe.contentWindow: false
Message 8 source === blobIframe.contentWindow: false
Message 9 data: I am from another ~planet~ iframe
Message 9 data: [object Object]
Message 9 origin: file://
Message 9 lastEventId:
Message 9 source: [object Window]
Message 9 source === window: false
Message 9 source === iframe.contentWindow: true
Message 9 ports: [object MessagePort]
Message 9 ports === ports: true
Message 9 Object.isFrozen(ports): true
Message 9 source === window: true
Message 9 source === iframe.contentWindow: false
Message 9 source === blobIframe.contentWindow: false
Message 10 data: All done :^)
Message 10 data: I am from another ~planet~ iframe
Message 10 origin: file://
Message 10 lastEventId:
Message 10 source: [object Window]
Message 10 ports:
Message 10 ports === ports: true
Message 10 Object.isFrozen(ports): true
Message 10 source === window: false
Message 10 source === iframe.contentWindow: false
Message 10 source === blobIframe.contentWindow: true
Message 10 source === iframe.contentWindow: true
Message 10 source === blobIframe.contentWindow: false
Message 11 data: All done :^)
Message 11 origin: file://
Message 11 lastEventId:
Message 11 source: [object Window]
Message 11 ports:
Message 11 ports === ports: true
Message 11 Object.isFrozen(ports): true
Message 11 source === window: false
Message 11 source === iframe.contentWindow: false
Message 11 source === blobIframe.contentWindow: true

View file

@ -3,7 +3,7 @@
<body>
<script>
window.addEventListener('message', (event) => {
window.parent.postMessage(event.data, '*');
window.parent.postMessage(event.data, '*', event.ports);
});
</script>
<body>
@ -30,6 +30,9 @@
println(`Message ${messageCount} origin: ${messageEvent.origin}`);
println(`Message ${messageCount} lastEventId: ${messageEvent.lastEventId}`);
println(`Message ${messageCount} source: ${messageEvent.source}`);
println(`Message ${messageCount} ports: ${messageEvent.ports}`);
println(`Message ${messageCount} ports === ports: ${messageEvent.ports === messageEvent.ports}`);
println(`Message ${messageCount} Object.isFrozen(ports): ${Object.isFrozen(messageEvent.ports)}`);
println(`Message ${messageCount} source === window: ${messageEvent.source === window}`);
println(`Message ${messageCount} source === iframe.contentWindow: ${messageEvent.source === iframe.contentWindow}`);
println(`Message ${messageCount} source === blobIframe.contentWindow: ${messageEvent.source === blobIframe.contentWindow}`);
@ -55,6 +58,8 @@
window.postMessage("This is a string", "/");
window.postMessage("I shouldn't appear, I'm not same origin!", "https://serenityos.org");
iframe.contentWindow.postMessage("I am from another ~planet~ iframe", "*");
let channel = new MessageChannel();
window.postMessage({foo: [channel.port1]}, "*", [channel.port1]);
blobIframe.contentWindow.postMessage("All done :^)", iframeSrcdocBlobUrl);
try {

View file

@ -10,6 +10,7 @@
#include <AK/DeprecatedString.h>
#include <AK/GenericLexer.h>
#include <AK/Utf8View.h>
#include <LibIPC/File.h>
#include <LibJS/Runtime/AbstractOperations.h>
#include <LibJS/Runtime/Accessor.h>
#include <LibJS/Runtime/Completion.h>
@ -1062,11 +1063,10 @@ WebIDL::ExceptionOr<void> Window::window_post_message_steps(JS::Value message, W
}
// 6. Let transfer be options["transfer"].
// FIXME: This is currently unused.
auto& transfer = options.transfer;
// 7. Let serializeWithTransferResult be StructuredSerializeWithTransfer(message, transfer). Rethrow any exceptions.
// FIXME: Use StructuredSerializeWithTransfer instead of StructuredSerialize
auto serialize_with_transfer_result = TRY(structured_serialize(target_realm.vm(), message));
auto serialize_with_transfer_result = TRY(structured_serialize_with_transfer(target_realm.vm(), message, transfer));
// 8. Queue a global task on the posted message task source given targetWindow to run the following steps:
queue_global_task(Task::Source::PostedMessage, *this, [this, serialize_with_transfer_result = move(serialize_with_transfer_result), target_origin = move(target_origin), &incumbent_settings, &target_realm]() {
@ -1086,11 +1086,9 @@ WebIDL::ExceptionOr<void> Window::window_post_message_steps(JS::Value message, W
auto& source = verify_cast<WindowProxy>(incumbent_settings.realm().global_environment().global_this_value());
// 4. Let deserializeRecord be StructuredDeserializeWithTransfer(serializeWithTransferResult, targetRealm).
// FIXME: Use StructuredDeserializeWithTransfer instead of StructuredDeserialize
// FIXME: Don't use a temporary execution context here.
auto& settings_object = Bindings::host_defined_environment_settings_object(target_realm);
auto temporary_execution_context = TemporaryExecutionContext { settings_object };
auto deserialize_record_or_error = structured_deserialize(vm(), serialize_with_transfer_result, target_realm, Optional<HTML::DeserializationMemory> {});
auto deserialize_record_or_error = structured_deserialize_with_transfer(vm(), serialize_with_transfer_result);
// If this throws an exception, catch it, fire an event named messageerror at targetWindow, using MessageEvent,
// with the origin attribute initialized to origin and the source attribute initialized to source, and then return.
@ -1105,20 +1103,27 @@ WebIDL::ExceptionOr<void> Window::window_post_message_steps(JS::Value message, W
}
// 5. Let messageClone be deserializeRecord.[[Deserialized]].
// FIXME: Get this from deserializeRecord.[[Deserialized]] once it uses StructuredDeserializeWithTransfer instead of StructuredDeserialize.
auto message_clone = deserialize_record_or_error.release_value();
auto deserialize_record = deserialize_record_or_error.release_value();
auto message_clone = deserialize_record.deserialized;
// FIXME: 6. Let newPorts be a new frozen array consisting of all MessagePort objects in deserializeRecord.[[TransferredValues]],
// if any, maintaining their relative order.
// 6. Let newPorts be a new frozen array consisting of all MessagePort objects in deserializeRecord.[[TransferredValues]],
// if any, maintaining their relative order.
// FIXME: Use a FrozenArray
Vector<JS::Handle<JS::Object>> new_ports;
for (auto const& object : deserialize_record.transferred_values) {
if (is<HTML::MessagePort>(*object)) {
new_ports.append(object);
}
}
// 7. Fire an event named message at targetWindow, using MessageEvent, with the origin attribute initialized to origin,
// the source attribute initialized to source, the data attribute initialized to messageClone, and the ports attribute
// initialized to newPorts.
// FIXME: Set the ports attribute to newPorts.
MessageEventInit message_event_init {};
message_event_init.origin = MUST(String::from_deprecated_string(origin));
message_event_init.source = JS::make_handle(source);
message_event_init.data = message_clone;
message_event_init.ports = move(new_ports);
auto message_event = MessageEvent::create(target_realm, EventNames::message, message_event_init);
dispatch_event(message_event);