mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-07-29 12:19:54 +00:00
LibWeb: Use enum for serialization and reimplement interface exposure
Our currently implementation of structured serialization has a design flaw, where if the serialized/transferred type was not used in the destination realm, it would not be seen as exposed and thus we would not re-create the type on the other side. This is very common, for example, transferring a MessagePort to a just inserted iframe, or the just inserted iframe transferring a MessagePort to it's parent. This is what Google reCAPTCHA does. This flaw occurred due to relying on lazily populated HashMaps of constructors, namespaces and interfaces. This commit changes it so that per-type "is exposed" implementations are generated. Since it no longer relies on interface name strings, this commit changes serializable types to indicate their type with an enum, in line with how transferrable types indicate their type. This makes Google reCAPTCHA work on https://www.google.com/recaptcha/api2/demo It currently doesn't work on non-Google origins due to a separate same-origin policy bug.
This commit is contained in:
parent
d6b9bd306c
commit
d08d6b08d3
Notes:
github-actions[bot]
2025-07-15 13:21:14 +00:00
Author: https://github.com/Lubrsi
Commit: d08d6b08d3
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/5443
Reviewed-by: https://github.com/trflynn89 ✅
25 changed files with 356 additions and 130 deletions
|
@ -24,11 +24,6 @@ void Intrinsics::visit_edges(JS::Cell::Visitor& visitor)
|
||||||
visitor.visit(m_realm);
|
visitor.visit(m_realm);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Intrinsics::is_exposed(StringView name) const
|
|
||||||
{
|
|
||||||
return m_constructors.contains(name) || m_prototypes.contains(name) || m_namespaces.contains(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
Intrinsics& host_defined_intrinsics(JS::Realm& realm)
|
Intrinsics& host_defined_intrinsics(JS::Realm& realm)
|
||||||
{
|
{
|
||||||
ASSERT(realm.host_defined());
|
ASSERT(realm.host_defined());
|
||||||
|
|
|
@ -66,7 +66,8 @@ public:
|
||||||
return *m_constructors.find(class_name)->value;
|
return *m_constructors.find(class_name)->value;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_exposed(StringView name) const;
|
template<typename PrototypeType>
|
||||||
|
bool is_interface_exposed(JS::Realm&) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
virtual void visit_edges(JS::Cell::Visitor&) override;
|
virtual void visit_edges(JS::Cell::Visitor&) override;
|
||||||
|
|
|
@ -16,7 +16,7 @@ class Serializable {
|
||||||
public:
|
public:
|
||||||
virtual ~Serializable() = default;
|
virtual ~Serializable() = default;
|
||||||
|
|
||||||
virtual StringView interface_name() const = 0;
|
virtual HTML::SerializeType serialize_type() const = 0;
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/structured-data.html#serialization-steps
|
// https://html.spec.whatwg.org/multipage/structured-data.html#serialization-steps
|
||||||
virtual WebIDL::ExceptionOr<void> serialization_steps(HTML::SerializationRecord&, bool for_storage, HTML::SerializationMemory&) = 0;
|
virtual WebIDL::ExceptionOr<void> serialization_steps(HTML::SerializationRecord&, bool for_storage, HTML::SerializationMemory&) = 0;
|
||||||
|
|
|
@ -47,7 +47,7 @@ public:
|
||||||
InternalKeyData const& handle() const { return m_key_data; }
|
InternalKeyData const& handle() const { return m_key_data; }
|
||||||
String algorithm_name() const;
|
String algorithm_name() const;
|
||||||
|
|
||||||
virtual StringView interface_name() const override { return "CryptoKey"sv; }
|
virtual HTML::SerializeType serialize_type() const override { return HTML::SerializeType::CryptoKey; }
|
||||||
virtual WebIDL::ExceptionOr<void> serialization_steps(HTML::SerializationRecord& record, bool for_storage, HTML::SerializationMemory&) override;
|
virtual WebIDL::ExceptionOr<void> serialization_steps(HTML::SerializationRecord& record, bool for_storage, HTML::SerializationMemory&) override;
|
||||||
virtual WebIDL::ExceptionOr<void> deserialization_steps(ReadonlySpan<u32> const& record, size_t& position, HTML::DeserializationMemory&) override;
|
virtual WebIDL::ExceptionOr<void> deserialization_steps(ReadonlySpan<u32> const& record, size_t& position, HTML::DeserializationMemory&) override;
|
||||||
|
|
||||||
|
|
|
@ -56,7 +56,7 @@ public:
|
||||||
|
|
||||||
GC::Ref<Streams::ReadableStream> get_stream();
|
GC::Ref<Streams::ReadableStream> get_stream();
|
||||||
|
|
||||||
virtual StringView interface_name() const override { return "Blob"sv; }
|
virtual HTML::SerializeType serialize_type() const override { return HTML::SerializeType::Blob; }
|
||||||
|
|
||||||
virtual WebIDL::ExceptionOr<void> serialization_steps(HTML::SerializationRecord& record, bool for_storage, HTML::SerializationMemory&) override;
|
virtual WebIDL::ExceptionOr<void> serialization_steps(HTML::SerializationRecord& record, bool for_storage, HTML::SerializationMemory&) override;
|
||||||
virtual WebIDL::ExceptionOr<void> deserialization_steps(ReadonlySpan<u32> const& record, size_t& position, HTML::DeserializationMemory&) override;
|
virtual WebIDL::ExceptionOr<void> deserialization_steps(ReadonlySpan<u32> const& record, size_t& position, HTML::DeserializationMemory&) override;
|
||||||
|
|
|
@ -30,7 +30,7 @@ public:
|
||||||
// https://w3c.github.io/FileAPI/#dfn-lastModified
|
// https://w3c.github.io/FileAPI/#dfn-lastModified
|
||||||
i64 last_modified() const { return m_last_modified; }
|
i64 last_modified() const { return m_last_modified; }
|
||||||
|
|
||||||
virtual StringView interface_name() const override { return "File"sv; }
|
virtual HTML::SerializeType serialize_type() const override { return HTML::SerializeType::File; }
|
||||||
|
|
||||||
virtual WebIDL::ExceptionOr<void> serialization_steps(HTML::SerializationRecord& record, bool for_storage, HTML::SerializationMemory&) override;
|
virtual WebIDL::ExceptionOr<void> serialization_steps(HTML::SerializationRecord& record, bool for_storage, HTML::SerializationMemory&) override;
|
||||||
virtual WebIDL::ExceptionOr<void> deserialization_steps(ReadonlySpan<u32> const&, size_t& position, HTML::DeserializationMemory&) override;
|
virtual WebIDL::ExceptionOr<void> deserialization_steps(ReadonlySpan<u32> const&, size_t& position, HTML::DeserializationMemory&) override;
|
||||||
|
|
|
@ -45,7 +45,7 @@ public:
|
||||||
|
|
||||||
virtual Optional<JS::Value> item_value(size_t index) const override;
|
virtual Optional<JS::Value> item_value(size_t index) const override;
|
||||||
|
|
||||||
virtual StringView interface_name() const override { return "FileList"sv; }
|
virtual HTML::SerializeType serialize_type() const override { return HTML::SerializeType::FileList; }
|
||||||
virtual WebIDL::ExceptionOr<void> serialization_steps(HTML::SerializationRecord& serialized, bool for_storage, HTML::SerializationMemory&) override;
|
virtual WebIDL::ExceptionOr<void> serialization_steps(HTML::SerializationRecord& serialized, bool for_storage, HTML::SerializationMemory&) override;
|
||||||
virtual WebIDL::ExceptionOr<void> deserialization_steps(ReadonlySpan<u32> const& serialized, size_t& position, HTML::DeserializationMemory&) override;
|
virtual WebIDL::ExceptionOr<void> deserialization_steps(ReadonlySpan<u32> const& serialized, size_t& position, HTML::DeserializationMemory&) override;
|
||||||
|
|
||||||
|
|
|
@ -69,7 +69,7 @@ public:
|
||||||
|
|
||||||
WebIDL::ExceptionOr<GC::Ref<DOMMatrix>> set_matrix_value(String const& transform_list);
|
WebIDL::ExceptionOr<GC::Ref<DOMMatrix>> set_matrix_value(String const& transform_list);
|
||||||
|
|
||||||
virtual StringView interface_name() const override { return "DOMMatrix"sv; }
|
virtual HTML::SerializeType serialize_type() const override { return HTML::SerializeType::DOMMatrix; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
DOMMatrix(JS::Realm&, double m11, double m12, double m21, double m22, double m41, double m42);
|
DOMMatrix(JS::Realm&, double m11, double m12, double m21, double m22, double m41, double m42);
|
||||||
|
|
|
@ -115,7 +115,7 @@ public:
|
||||||
|
|
||||||
WebIDL::ExceptionOr<String> to_string() const;
|
WebIDL::ExceptionOr<String> to_string() const;
|
||||||
|
|
||||||
virtual StringView interface_name() const override { return "DOMMatrixReadOnly"sv; }
|
virtual HTML::SerializeType serialize_type() const override { return HTML::SerializeType::DOMMatrixReadOnly; }
|
||||||
virtual WebIDL::ExceptionOr<void> serialization_steps(HTML::SerializationRecord&, bool for_storage, HTML::SerializationMemory&) override;
|
virtual WebIDL::ExceptionOr<void> serialization_steps(HTML::SerializationRecord&, bool for_storage, HTML::SerializationMemory&) override;
|
||||||
virtual WebIDL::ExceptionOr<void> deserialization_steps(ReadonlySpan<u32> const& record, size_t& position, HTML::DeserializationMemory&) override;
|
virtual WebIDL::ExceptionOr<void> deserialization_steps(ReadonlySpan<u32> const& record, size_t& position, HTML::DeserializationMemory&) override;
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,7 @@ public:
|
||||||
void set_z(double z) { m_z = z; }
|
void set_z(double z) { m_z = z; }
|
||||||
void set_w(double w) { m_w = w; }
|
void set_w(double w) { m_w = w; }
|
||||||
|
|
||||||
virtual StringView interface_name() const override { return "DOMPoint"sv; }
|
virtual HTML::SerializeType serialize_type() const override { return HTML::SerializeType::DOMPoint; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
DOMPoint(JS::Realm&, double x, double y, double z, double w);
|
DOMPoint(JS::Realm&, double x, double y, double z, double w);
|
||||||
|
|
|
@ -44,7 +44,7 @@ public:
|
||||||
|
|
||||||
WebIDL::ExceptionOr<GC::Ref<DOMPoint>> matrix_transform(DOMMatrixInit&) const;
|
WebIDL::ExceptionOr<GC::Ref<DOMPoint>> matrix_transform(DOMMatrixInit&) const;
|
||||||
|
|
||||||
virtual StringView interface_name() const override { return "DOMPointReadOnly"sv; }
|
virtual HTML::SerializeType serialize_type() const override { return HTML::SerializeType::DOMPointReadOnly; }
|
||||||
virtual WebIDL::ExceptionOr<void> serialization_steps(HTML::SerializationRecord&, bool for_storage, HTML::SerializationMemory&) override;
|
virtual WebIDL::ExceptionOr<void> serialization_steps(HTML::SerializationRecord&, bool for_storage, HTML::SerializationMemory&) override;
|
||||||
virtual WebIDL::ExceptionOr<void> deserialization_steps(ReadonlySpan<u32> const&, size_t& position, HTML::DeserializationMemory&) override;
|
virtual WebIDL::ExceptionOr<void> deserialization_steps(ReadonlySpan<u32> const&, size_t& position, HTML::DeserializationMemory&) override;
|
||||||
|
|
||||||
|
|
|
@ -44,7 +44,7 @@ public:
|
||||||
|
|
||||||
GC::Ref<DOMRect> get_bounds() const;
|
GC::Ref<DOMRect> get_bounds() const;
|
||||||
|
|
||||||
virtual StringView interface_name() const override { return "DOMQuad"sv; }
|
virtual HTML::SerializeType serialize_type() const override { return HTML::SerializeType::DOMQuad; }
|
||||||
virtual WebIDL::ExceptionOr<void> serialization_steps(HTML::SerializationRecord&, bool for_storage, HTML::SerializationMemory&) override;
|
virtual WebIDL::ExceptionOr<void> serialization_steps(HTML::SerializationRecord&, bool for_storage, HTML::SerializationMemory&) override;
|
||||||
virtual WebIDL::ExceptionOr<void> deserialization_steps(ReadonlySpan<u32> const&, size_t& position, HTML::DeserializationMemory&) override;
|
virtual WebIDL::ExceptionOr<void> deserialization_steps(ReadonlySpan<u32> const&, size_t& position, HTML::DeserializationMemory&) override;
|
||||||
|
|
||||||
|
|
|
@ -33,7 +33,7 @@ public:
|
||||||
void set_width(double width) { m_rect.set_width(width); }
|
void set_width(double width) { m_rect.set_width(width); }
|
||||||
void set_height(double height) { m_rect.set_height(height); }
|
void set_height(double height) { m_rect.set_height(height); }
|
||||||
|
|
||||||
virtual StringView interface_name() const override { return "DOMRect"sv; }
|
virtual HTML::SerializeType serialize_type() const override { return HTML::SerializeType::DOMRect; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
DOMRect(JS::Realm&, double x, double y, double width, double height);
|
DOMRect(JS::Realm&, double x, double y, double width, double height);
|
||||||
|
|
|
@ -69,7 +69,7 @@ public:
|
||||||
return min(x(), x() + width());
|
return min(x(), x() + width());
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual StringView interface_name() const override { return "DOMRectReadOnly"sv; }
|
virtual HTML::SerializeType serialize_type() const override { return HTML::SerializeType::DOMRectReadOnly; }
|
||||||
virtual WebIDL::ExceptionOr<void> serialization_steps(HTML::SerializationRecord&, bool for_storage, HTML::SerializationMemory&) override;
|
virtual WebIDL::ExceptionOr<void> serialization_steps(HTML::SerializationRecord&, bool for_storage, HTML::SerializationMemory&) override;
|
||||||
virtual WebIDL::ExceptionOr<void> deserialization_steps(ReadonlySpan<u32> const&, size_t& position, HTML::DeserializationMemory&) override;
|
virtual WebIDL::ExceptionOr<void> deserialization_steps(ReadonlySpan<u32> const&, size_t& position, HTML::DeserializationMemory&) override;
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,7 @@ public:
|
||||||
virtual ~ImageBitmap() override = default;
|
virtual ~ImageBitmap() override = default;
|
||||||
|
|
||||||
// ^Web::Bindings::Serializable
|
// ^Web::Bindings::Serializable
|
||||||
virtual StringView interface_name() const override { return "ImageBitmap"sv; }
|
virtual HTML::SerializeType serialize_type() const override { return HTML::SerializeType::ImageBitmap; }
|
||||||
virtual WebIDL::ExceptionOr<void> serialization_steps(HTML::SerializationRecord&, bool for_storage, HTML::SerializationMemory&) override;
|
virtual WebIDL::ExceptionOr<void> serialization_steps(HTML::SerializationRecord&, bool for_storage, HTML::SerializationMemory&) override;
|
||||||
virtual WebIDL::ExceptionOr<void> deserialization_steps(ReadonlySpan<u32> const&, size_t& position, HTML::DeserializationMemory&) override;
|
virtual WebIDL::ExceptionOr<void> deserialization_steps(ReadonlySpan<u32> const&, size_t& position, HTML::DeserializationMemory&) override;
|
||||||
|
|
||||||
|
|
|
@ -46,7 +46,7 @@ public:
|
||||||
|
|
||||||
Bindings::PredefinedColorSpace color_space() const { return m_color_space; }
|
Bindings::PredefinedColorSpace color_space() const { return m_color_space; }
|
||||||
|
|
||||||
virtual StringView interface_name() const override { return "ImageData"sv; }
|
virtual HTML::SerializeType serialize_type() const override { return HTML::SerializeType::ImageData; }
|
||||||
virtual WebIDL::ExceptionOr<void> serialization_steps(SerializationRecord& serialized, bool for_storage, SerializationMemory&) override;
|
virtual WebIDL::ExceptionOr<void> serialization_steps(SerializationRecord& serialized, bool for_storage, SerializationMemory&) override;
|
||||||
virtual WebIDL::ExceptionOr<void> deserialization_steps(ReadonlySpan<u32> const& serialized, size_t& position, DeserializationMemory&) override;
|
virtual WebIDL::ExceptionOr<void> deserialization_steps(ReadonlySpan<u32> const& serialized, size_t& position, DeserializationMemory&) override;
|
||||||
|
|
||||||
|
|
|
@ -31,10 +31,25 @@
|
||||||
#include <LibJS/Runtime/StringObject.h>
|
#include <LibJS/Runtime/StringObject.h>
|
||||||
#include <LibJS/Runtime/TypedArray.h>
|
#include <LibJS/Runtime/TypedArray.h>
|
||||||
#include <LibJS/Runtime/VM.h>
|
#include <LibJS/Runtime/VM.h>
|
||||||
|
#include <LibWeb/Bindings/DOMExceptionPrototype.h>
|
||||||
|
#include <LibWeb/Bindings/DOMMatrixPrototype.h>
|
||||||
|
#include <LibWeb/Bindings/DOMMatrixReadOnlyPrototype.h>
|
||||||
|
#include <LibWeb/Bindings/DOMPointPrototype.h>
|
||||||
|
#include <LibWeb/Bindings/DOMPointReadOnlyPrototype.h>
|
||||||
|
#include <LibWeb/Bindings/DOMQuadPrototype.h>
|
||||||
|
#include <LibWeb/Bindings/DOMRectPrototype.h>
|
||||||
|
#include <LibWeb/Bindings/DOMRectReadOnlyPrototype.h>
|
||||||
#include <LibWeb/Bindings/ExceptionOrUtils.h>
|
#include <LibWeb/Bindings/ExceptionOrUtils.h>
|
||||||
|
#include <LibWeb/Bindings/FileListPrototype.h>
|
||||||
|
#include <LibWeb/Bindings/FilePrototype.h>
|
||||||
|
#include <LibWeb/Bindings/ImageBitmapPrototype.h>
|
||||||
#include <LibWeb/Bindings/Intrinsics.h>
|
#include <LibWeb/Bindings/Intrinsics.h>
|
||||||
|
#include <LibWeb/Bindings/MessagePortPrototype.h>
|
||||||
|
#include <LibWeb/Bindings/ReadableStreamPrototype.h>
|
||||||
#include <LibWeb/Bindings/Serializable.h>
|
#include <LibWeb/Bindings/Serializable.h>
|
||||||
#include <LibWeb/Bindings/Transferable.h>
|
#include <LibWeb/Bindings/Transferable.h>
|
||||||
|
#include <LibWeb/Bindings/TransformStreamPrototype.h>
|
||||||
|
#include <LibWeb/Bindings/WritableStreamPrototype.h>
|
||||||
#include <LibWeb/Crypto/CryptoKey.h>
|
#include <LibWeb/Crypto/CryptoKey.h>
|
||||||
#include <LibWeb/FileAPI/Blob.h>
|
#include <LibWeb/FileAPI/Blob.h>
|
||||||
#include <LibWeb/FileAPI/File.h>
|
#include <LibWeb/FileAPI/File.h>
|
||||||
|
@ -46,6 +61,7 @@
|
||||||
#include <LibWeb/Geometry/DOMQuad.h>
|
#include <LibWeb/Geometry/DOMQuad.h>
|
||||||
#include <LibWeb/Geometry/DOMRect.h>
|
#include <LibWeb/Geometry/DOMRect.h>
|
||||||
#include <LibWeb/Geometry/DOMRectReadOnly.h>
|
#include <LibWeb/Geometry/DOMRectReadOnly.h>
|
||||||
|
#include <LibWeb/HTML/ImageBitmap.h>
|
||||||
#include <LibWeb/HTML/ImageData.h>
|
#include <LibWeb/HTML/ImageData.h>
|
||||||
#include <LibWeb/HTML/MessagePort.h>
|
#include <LibWeb/HTML/MessagePort.h>
|
||||||
#include <LibWeb/HTML/StructuredSerialize.h>
|
#include <LibWeb/HTML/StructuredSerialize.h>
|
||||||
|
@ -327,7 +343,7 @@ public:
|
||||||
// 2. Let typeString be the identifier of the primary interface of value.
|
// 2. Let typeString be the identifier of the primary interface of value.
|
||||||
// 3. Set serialized to { [[Type]]: typeString }.
|
// 3. Set serialized to { [[Type]]: typeString }.
|
||||||
serialize_enum(m_serialized, ValueTag::SerializableObject);
|
serialize_enum(m_serialized, ValueTag::SerializableObject);
|
||||||
TRY(serialize_string(m_vm, m_serialized, serializable.interface_name()));
|
serialize_enum(m_serialized, serializable.serialize_type());
|
||||||
|
|
||||||
// 4. Set deep to true
|
// 4. Set deep to true
|
||||||
deep = true;
|
deep = true;
|
||||||
|
@ -960,9 +976,9 @@ public:
|
||||||
|
|
||||||
auto& realm = *m_vm.current_realm();
|
auto& realm = *m_vm.current_realm();
|
||||||
// 1. Let interfaceName be serialized.[[Type]].
|
// 1. Let interfaceName be serialized.[[Type]].
|
||||||
auto interface_name = TRY(deserialize_string(m_vm, m_serialized, m_position));
|
auto interface_name = deserialize_primitive_type<SerializeType>(m_serialized, m_position);
|
||||||
// 2. If the interface identified by interfaceName is not exposed in targetRealm, then throw a "DataCloneError" DOMException.
|
// 2. If the interface identified by interfaceName is not exposed in targetRealm, then throw a "DataCloneError" DOMException.
|
||||||
if (!is_interface_exposed_on_target_realm(interface_name, realm))
|
if (!is_serializable_interface_exposed_on_target_realm(interface_name, realm))
|
||||||
return WebIDL::DataCloneError::create(realm, "Unsupported type"_string);
|
return WebIDL::DataCloneError::create(realm, "Unsupported type"_string);
|
||||||
|
|
||||||
// 3. Set value to a new instance of the interface identified by interfaceName, created in targetRealm.
|
// 3. Set value to a new instance of the interface identified by interfaceName, created in targetRealm.
|
||||||
|
@ -1047,44 +1063,82 @@ private:
|
||||||
GC::RootVector<JS::Value> m_memory; // Index -> JS value
|
GC::RootVector<JS::Value> m_memory; // Index -> JS value
|
||||||
size_t m_position { 0 };
|
size_t m_position { 0 };
|
||||||
|
|
||||||
static GC::Ref<Bindings::PlatformObject> create_serialized_type(StringView interface_name, JS::Realm& realm)
|
static bool is_serializable_interface_exposed_on_target_realm(SerializeType name, JS::Realm& realm)
|
||||||
{
|
|
||||||
if (interface_name == "Blob"sv)
|
|
||||||
return FileAPI::Blob::create(realm);
|
|
||||||
if (interface_name == "File"sv)
|
|
||||||
return FileAPI::File::create(realm);
|
|
||||||
if (interface_name == "FileList"sv)
|
|
||||||
return FileAPI::FileList::create(realm);
|
|
||||||
if (interface_name == "DOMException"sv)
|
|
||||||
return WebIDL::DOMException::create(realm);
|
|
||||||
if (interface_name == "DOMMatrixReadOnly"sv)
|
|
||||||
return Geometry::DOMMatrixReadOnly::create(realm);
|
|
||||||
if (interface_name == "DOMMatrix"sv)
|
|
||||||
return Geometry::DOMMatrix::create(realm);
|
|
||||||
if (interface_name == "DOMPointReadOnly"sv)
|
|
||||||
return Geometry::DOMPointReadOnly::create(realm);
|
|
||||||
if (interface_name == "DOMPoint"sv)
|
|
||||||
return Geometry::DOMPoint::create(realm);
|
|
||||||
if (interface_name == "DOMRectReadOnly"sv)
|
|
||||||
return Geometry::DOMRectReadOnly::create(realm);
|
|
||||||
if (interface_name == "DOMRect"sv)
|
|
||||||
return Geometry::DOMRect::create(realm);
|
|
||||||
if (interface_name == "CryptoKey"sv)
|
|
||||||
return Crypto::CryptoKey::create(realm);
|
|
||||||
if (interface_name == "DOMQuad"sv)
|
|
||||||
return Geometry::DOMQuad::create(realm);
|
|
||||||
if (interface_name == "ImageData"sv)
|
|
||||||
return ImageData::create(realm);
|
|
||||||
|
|
||||||
VERIFY_NOT_REACHED();
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME: Consolidate this function with the similar is_interface_exposed_on_target_realm() used when transferring objects.
|
|
||||||
// Also, the name parameter would be better off being the interface name (as a string) so that we don't need a switch statement.
|
|
||||||
static bool is_interface_exposed_on_target_realm(StringView interface_name, JS::Realm& realm)
|
|
||||||
{
|
{
|
||||||
auto const& intrinsics = Bindings::host_defined_intrinsics(realm);
|
auto const& intrinsics = Bindings::host_defined_intrinsics(realm);
|
||||||
return intrinsics.is_exposed(interface_name);
|
switch (name) {
|
||||||
|
case SerializeType::Blob:
|
||||||
|
return intrinsics.is_interface_exposed<Bindings::BlobPrototype>(realm);
|
||||||
|
case SerializeType::File:
|
||||||
|
return intrinsics.is_interface_exposed<Bindings::FilePrototype>(realm);
|
||||||
|
case SerializeType::FileList:
|
||||||
|
return intrinsics.is_interface_exposed<Bindings::FileListPrototype>(realm);
|
||||||
|
case SerializeType::DOMException:
|
||||||
|
return intrinsics.is_interface_exposed<Bindings::DOMExceptionPrototype>(realm);
|
||||||
|
case SerializeType::DOMMatrixReadOnly:
|
||||||
|
return intrinsics.is_interface_exposed<Bindings::DOMMatrixReadOnlyPrototype>(realm);
|
||||||
|
case SerializeType::DOMMatrix:
|
||||||
|
return intrinsics.is_interface_exposed<Bindings::DOMMatrixPrototype>(realm);
|
||||||
|
case SerializeType::DOMPointReadOnly:
|
||||||
|
return intrinsics.is_interface_exposed<Bindings::DOMPointReadOnlyPrototype>(realm);
|
||||||
|
case SerializeType::DOMPoint:
|
||||||
|
return intrinsics.is_interface_exposed<Bindings::DOMPointPrototype>(realm);
|
||||||
|
case SerializeType::DOMRectReadOnly:
|
||||||
|
return intrinsics.is_interface_exposed<Bindings::DOMRectReadOnlyPrototype>(realm);
|
||||||
|
case SerializeType::DOMRect:
|
||||||
|
return intrinsics.is_interface_exposed<Bindings::DOMRectPrototype>(realm);
|
||||||
|
case SerializeType::CryptoKey:
|
||||||
|
return intrinsics.is_interface_exposed<Bindings::CryptoKeyPrototype>(realm);
|
||||||
|
case SerializeType::DOMQuad:
|
||||||
|
return intrinsics.is_interface_exposed<Bindings::DOMQuadPrototype>(realm);
|
||||||
|
case SerializeType::ImageData:
|
||||||
|
return intrinsics.is_interface_exposed<Bindings::ImageDataPrototype>(realm);
|
||||||
|
case SerializeType::ImageBitmap:
|
||||||
|
return intrinsics.is_interface_exposed<Bindings::ImageBitmapPrototype>(realm);
|
||||||
|
case SerializeType::Unknown:
|
||||||
|
dbgln("Unknown interface type for serialization: {}", to_underlying(name));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
VERIFY_NOT_REACHED();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static GC::Ref<Bindings::PlatformObject> create_serialized_type(SerializeType serialize_type, JS::Realm& realm)
|
||||||
|
{
|
||||||
|
switch (serialize_type) {
|
||||||
|
case SerializeType::Blob:
|
||||||
|
return FileAPI::Blob::create(realm);
|
||||||
|
case SerializeType::File:
|
||||||
|
return FileAPI::File::create(realm);
|
||||||
|
case SerializeType::FileList:
|
||||||
|
return FileAPI::FileList::create(realm);
|
||||||
|
case SerializeType::DOMException:
|
||||||
|
return WebIDL::DOMException::create(realm);
|
||||||
|
case SerializeType::DOMMatrixReadOnly:
|
||||||
|
return Geometry::DOMMatrixReadOnly::create(realm);
|
||||||
|
case SerializeType::DOMMatrix:
|
||||||
|
return Geometry::DOMMatrix::create(realm);
|
||||||
|
case SerializeType::DOMPointReadOnly:
|
||||||
|
return Geometry::DOMPointReadOnly::create(realm);
|
||||||
|
case SerializeType::DOMPoint:
|
||||||
|
return Geometry::DOMPoint::create(realm);
|
||||||
|
case SerializeType::DOMRectReadOnly:
|
||||||
|
return Geometry::DOMRectReadOnly::create(realm);
|
||||||
|
case SerializeType::DOMRect:
|
||||||
|
return Geometry::DOMRect::create(realm);
|
||||||
|
case SerializeType::CryptoKey:
|
||||||
|
return Crypto::CryptoKey::create(realm);
|
||||||
|
case SerializeType::DOMQuad:
|
||||||
|
return Geometry::DOMQuad::create(realm);
|
||||||
|
case SerializeType::ImageData:
|
||||||
|
return ImageData::create(realm);
|
||||||
|
case SerializeType::ImageBitmap:
|
||||||
|
return ImageBitmap::create(realm);
|
||||||
|
case SerializeType::Unknown:
|
||||||
|
default:
|
||||||
|
VERIFY_NOT_REACHED();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1290,18 +1344,18 @@ WebIDL::ExceptionOr<SerializedTransferRecord> structured_serialize_with_transfer
|
||||||
return SerializedTransferRecord { .serialized = move(serialized), .transfer_data_holders = move(transfer_data_holders) };
|
return SerializedTransferRecord { .serialized = move(serialized), .transfer_data_holders = move(transfer_data_holders) };
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool is_interface_exposed_on_target_realm(TransferType name, JS::Realm& realm)
|
static bool is_transferable_interface_exposed_on_target_realm(TransferType name, JS::Realm& realm)
|
||||||
{
|
{
|
||||||
auto const& intrinsics = Bindings::host_defined_intrinsics(realm);
|
auto const& intrinsics = Bindings::host_defined_intrinsics(realm);
|
||||||
switch (name) {
|
switch (name) {
|
||||||
case TransferType::MessagePort:
|
case TransferType::MessagePort:
|
||||||
return intrinsics.is_exposed("MessagePort"sv);
|
return intrinsics.is_interface_exposed<Bindings::MessagePortPrototype>(realm);
|
||||||
case TransferType::ReadableStream:
|
case TransferType::ReadableStream:
|
||||||
return intrinsics.is_exposed("ReadableStream"sv);
|
return intrinsics.is_interface_exposed<Bindings::ReadableStreamPrototype>(realm);
|
||||||
case TransferType::WritableStream:
|
case TransferType::WritableStream:
|
||||||
return intrinsics.is_exposed("WritableStream"sv);
|
return intrinsics.is_interface_exposed<Bindings::WritableStreamPrototype>(realm);
|
||||||
case TransferType::TransformStream:
|
case TransferType::TransformStream:
|
||||||
return intrinsics.is_exposed("TransformStream"sv);
|
return intrinsics.is_interface_exposed<Bindings::TransformStreamPrototype>(realm);
|
||||||
case TransferType::Unknown:
|
case TransferType::Unknown:
|
||||||
dbgln("Unknown interface type for transfer: {}", to_underlying(name));
|
dbgln("Unknown interface type for transfer: {}", to_underlying(name));
|
||||||
break;
|
break;
|
||||||
|
@ -1398,7 +1452,7 @@ WebIDL::ExceptionOr<DeserializedTransferRecord> structured_deserialize_with_tran
|
||||||
else {
|
else {
|
||||||
// 1. Let interfaceName be transferDataHolder.[[Type]].
|
// 1. Let interfaceName be transferDataHolder.[[Type]].
|
||||||
// 2. If the interface identified by interfaceName is not exposed in targetRealm, then throw a "DataCloneError" DOMException.
|
// 2. If the interface identified by interfaceName is not exposed in targetRealm, then throw a "DataCloneError" DOMException.
|
||||||
if (!is_interface_exposed_on_target_realm(type, target_realm))
|
if (!is_transferable_interface_exposed_on_target_realm(type, target_realm))
|
||||||
return WebIDL::DataCloneError::create(target_realm, "Unknown type transferred"_string);
|
return WebIDL::DataCloneError::create(target_realm, "Unknown type transferred"_string);
|
||||||
|
|
||||||
// 3. Set value to a new instance of the interface identified by interfaceName, created in targetRealm.
|
// 3. Set value to a new instance of the interface identified by interfaceName, created in targetRealm.
|
||||||
|
|
|
@ -44,16 +44,6 @@ struct DeserializedRecord {
|
||||||
size_t position;
|
size_t position;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class TransferType : u8 {
|
|
||||||
Unknown = 0,
|
|
||||||
MessagePort = 1,
|
|
||||||
ArrayBuffer = 2,
|
|
||||||
ResizableArrayBuffer = 3,
|
|
||||||
ReadableStream = 4,
|
|
||||||
WritableStream = 5,
|
|
||||||
TransformStream = 6,
|
|
||||||
};
|
|
||||||
|
|
||||||
WebIDL::ExceptionOr<SerializationRecord> structured_serialize(JS::VM& vm, JS::Value);
|
WebIDL::ExceptionOr<SerializationRecord> structured_serialize(JS::VM& vm, JS::Value);
|
||||||
WebIDL::ExceptionOr<SerializationRecord> structured_serialize_for_storage(JS::VM& vm, JS::Value);
|
WebIDL::ExceptionOr<SerializationRecord> structured_serialize_for_storage(JS::VM& vm, JS::Value);
|
||||||
WebIDL::ExceptionOr<SerializationRecord> structured_serialize_internal(JS::VM& vm, JS::Value, bool for_storage, SerializationMemory&);
|
WebIDL::ExceptionOr<SerializationRecord> structured_serialize_internal(JS::VM& vm, JS::Value, bool for_storage, SerializationMemory&);
|
||||||
|
|
|
@ -17,4 +17,32 @@ using DeserializationMemory = GC::RootVector<JS::Value>;
|
||||||
using SerializationRecord = Vector<u32>;
|
using SerializationRecord = Vector<u32>;
|
||||||
using SerializationMemory = HashMap<GC::Root<JS::Value>, u32>;
|
using SerializationMemory = HashMap<GC::Root<JS::Value>, u32>;
|
||||||
|
|
||||||
|
enum class SerializeType : u8 {
|
||||||
|
Unknown = 0,
|
||||||
|
DOMException = 1,
|
||||||
|
DOMRectReadOnly = 2,
|
||||||
|
DOMRect = 3,
|
||||||
|
Blob = 4,
|
||||||
|
ImageBitmap = 5,
|
||||||
|
CryptoKey = 6,
|
||||||
|
File = 7,
|
||||||
|
FileList = 8,
|
||||||
|
DOMMatrixReadOnly = 9,
|
||||||
|
DOMMatrix = 10,
|
||||||
|
DOMPointReadOnly = 11,
|
||||||
|
DOMPoint = 12,
|
||||||
|
DOMQuad = 13,
|
||||||
|
ImageData = 14,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class TransferType : u8 {
|
||||||
|
Unknown = 0,
|
||||||
|
MessagePort = 1,
|
||||||
|
ArrayBuffer = 2,
|
||||||
|
ResizableArrayBuffer = 3,
|
||||||
|
ReadableStream = 4,
|
||||||
|
WritableStream = 5,
|
||||||
|
TransformStream = 6,
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -111,7 +111,7 @@ public:
|
||||||
FlyString const& message() const { return m_message; }
|
FlyString const& message() const { return m_message; }
|
||||||
u16 code() const { return get_legacy_code_for_name(m_name); }
|
u16 code() const { return get_legacy_code_for_name(m_name); }
|
||||||
|
|
||||||
virtual StringView interface_name() const override { return "DOMException"sv; }
|
virtual HTML::SerializeType serialize_type() const override { return HTML::SerializeType::DOMException; }
|
||||||
|
|
||||||
virtual ExceptionOr<void> serialization_steps(HTML::SerializationRecord& record, bool for_storage, HTML::SerializationMemory&) override;
|
virtual ExceptionOr<void> serialization_steps(HTML::SerializationRecord& record, bool for_storage, HTML::SerializationMemory&) override;
|
||||||
virtual ExceptionOr<void> deserialization_steps(ReadonlySpan<u32> const& record, size_t& position, HTML::DeserializationMemory&) override;
|
virtual ExceptionOr<void> deserialization_steps(ReadonlySpan<u32> const& record, size_t& position, HTML::DeserializationMemory&) override;
|
||||||
|
|
|
@ -76,7 +76,11 @@ static ErrorOr<void> generate_intrinsic_definitions(StringView output_path, Inte
|
||||||
generator.append(R"~~~(
|
generator.append(R"~~~(
|
||||||
#include <LibGC/DeferGC.h>
|
#include <LibGC/DeferGC.h>
|
||||||
#include <LibJS/Runtime/Object.h>
|
#include <LibJS/Runtime/Object.h>
|
||||||
#include <LibWeb/Bindings/Intrinsics.h>)~~~");
|
#include <LibWeb/Bindings/Intrinsics.h>
|
||||||
|
#include <LibWeb/HTML/Window.h>
|
||||||
|
#include <LibWeb/HTML/DedicatedWorkerGlobalScope.h>
|
||||||
|
#include <LibWeb/HTML/SharedWorkerGlobalScope.h>
|
||||||
|
#include <LibWeb/HTML/ShadowRealmGlobalScope.h>)~~~");
|
||||||
|
|
||||||
for (auto& interface : interface_sets.intrinsics) {
|
for (auto& interface : interface_sets.intrinsics) {
|
||||||
auto gen = generator.fork();
|
auto gen = generator.fork();
|
||||||
|
@ -134,11 +138,77 @@ void Intrinsics::create_web_namespace<@namespace_class@>(JS::Realm& realm)
|
||||||
)~~~");
|
)~~~");
|
||||||
};
|
};
|
||||||
|
|
||||||
auto add_interface = [](SourceGenerator& gen, StringView name, StringView prototype_class, StringView constructor_class, Optional<LegacyConstructor> const& legacy_constructor, StringView named_properties_class) {
|
auto add_interface = [](SourceGenerator& gen, InterfaceSets const& interface_sets, StringView name, StringView prototype_class, StringView constructor_class, Optional<LegacyConstructor> const& legacy_constructor, StringView named_properties_class) {
|
||||||
gen.set("interface_name", name);
|
gen.set("interface_name", name);
|
||||||
gen.set("prototype_class", prototype_class);
|
gen.set("prototype_class", prototype_class);
|
||||||
gen.set("constructor_class", constructor_class);
|
gen.set("constructor_class", constructor_class);
|
||||||
|
|
||||||
|
// https://webidl.spec.whatwg.org/#dfn-exposed
|
||||||
|
// An interface, callback interface, namespace, or member construct is exposed in a given realm realm if the
|
||||||
|
// following steps return true:
|
||||||
|
// FIXME: Make this compatible with the non-interface types.
|
||||||
|
gen.append(R"~~~(
|
||||||
|
template<>
|
||||||
|
bool Intrinsics::is_interface_exposed<@prototype_class@>(JS::Realm& realm) const
|
||||||
|
{
|
||||||
|
[[maybe_unused]] auto& global_object = realm.global_object();
|
||||||
|
)~~~");
|
||||||
|
|
||||||
|
// 1. If construct’s exposure set is not *, and realm.[[GlobalObject]] does not implement an interface that is in construct’s exposure set, then return false.
|
||||||
|
auto window_exposed_iterator = interface_sets.window_exposed.find_if([&name](IDL::Interface const& interface) {
|
||||||
|
return interface.name == name;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (window_exposed_iterator != interface_sets.window_exposed.end()) {
|
||||||
|
gen.append(R"~~~(
|
||||||
|
if (is<HTML::Window>(global_object))
|
||||||
|
return true;
|
||||||
|
)~~~");
|
||||||
|
}
|
||||||
|
|
||||||
|
auto dedicated_worker_exposed_iterator = interface_sets.dedicated_worker_exposed.find_if([&name](IDL::Interface const& interface) {
|
||||||
|
return interface.name == name;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (dedicated_worker_exposed_iterator != interface_sets.dedicated_worker_exposed.end()) {
|
||||||
|
gen.append(R"~~~(
|
||||||
|
if (is<HTML::DedicatedWorkerGlobalScope>(global_object))
|
||||||
|
return true;
|
||||||
|
)~~~");
|
||||||
|
}
|
||||||
|
|
||||||
|
auto shared_worker_exposed_iterator = interface_sets.shared_worker_exposed.find_if([&name](IDL::Interface const& interface) {
|
||||||
|
return interface.name == name;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (shared_worker_exposed_iterator != interface_sets.shared_worker_exposed.end()) {
|
||||||
|
gen.append(R"~~~(
|
||||||
|
if (is<HTML::SharedWorkerGlobalScope>(global_object))
|
||||||
|
return true;
|
||||||
|
)~~~");
|
||||||
|
}
|
||||||
|
|
||||||
|
auto shadow_realm_exposed_iterator = interface_sets.shadow_realm_exposed.find_if([&name](IDL::Interface const& interface) {
|
||||||
|
return interface.name == name;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (shadow_realm_exposed_iterator != interface_sets.shadow_realm_exposed.end()) {
|
||||||
|
gen.append(R"~~~(
|
||||||
|
if (is<HTML::ShadowRealmGlobalScope>(global_object))
|
||||||
|
return true;
|
||||||
|
)~~~");
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: 2. If realm’s settings object is not a secure context, and construct is conditionally exposed on
|
||||||
|
// [SecureContext], then return false.
|
||||||
|
// FIXME: 3. If realm’s settings object’s cross-origin isolated capability is false, and construct is
|
||||||
|
// conditionally exposed on [CrossOriginIsolated], then return false.
|
||||||
|
|
||||||
|
gen.append(R"~~~(
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
)~~~");
|
||||||
|
|
||||||
gen.append(R"~~~(
|
gen.append(R"~~~(
|
||||||
template<>
|
template<>
|
||||||
void Intrinsics::create_web_prototype_and_constructor<@prototype_class@>(JS::Realm& realm)
|
void Intrinsics::create_web_prototype_and_constructor<@prototype_class@>(JS::Realm& realm)
|
||||||
|
@ -188,7 +258,7 @@ void Intrinsics::create_web_prototype_and_constructor<@prototype_class@>(JS::Rea
|
||||||
if (interface.is_namespace)
|
if (interface.is_namespace)
|
||||||
add_namespace(gen, interface.name, interface.namespace_class);
|
add_namespace(gen, interface.name, interface.namespace_class);
|
||||||
else
|
else
|
||||||
add_interface(gen, interface.namespaced_name, interface.prototype_class, interface.constructor_class, lookup_legacy_constructor(interface), named_properties_class);
|
add_interface(gen, interface_sets, interface.namespaced_name, interface.prototype_class, interface.constructor_class, lookup_legacy_constructor(interface), named_properties_class);
|
||||||
}
|
}
|
||||||
|
|
||||||
generator.append(R"~~~(
|
generator.append(R"~~~(
|
||||||
|
|
|
@ -41,9 +41,6 @@ Text/input/wpt-import/html/syntax/parsing/html5lib_tests16.html
|
||||||
Text/input/wpt-import/html/syntax/parsing/html5lib_tests19.html
|
Text/input/wpt-import/html/syntax/parsing/html5lib_tests19.html
|
||||||
Text/input/wpt-import/html/syntax/parsing/html5lib_tests5.html
|
Text/input/wpt-import/html/syntax/parsing/html5lib_tests5.html
|
||||||
|
|
||||||
; Unknown, imported as skipped in #2148
|
|
||||||
Text/input/wpt-import/html/infrastructure/safe-passing-of-structured-data/structuredclone_0.html
|
|
||||||
|
|
||||||
; Flaky, apparently due to font loading
|
; Flaky, apparently due to font loading
|
||||||
Text/input/wpt-import/css/css-flexbox/flex-item-compressible-001.html
|
Text/input/wpt-import/css/css-flexbox/flex-item-compressible-001.html
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
iframe received an object: Error
|
||||||
|
iframe received an object: [object DOMRectReadOnly]
|
||||||
|
iframe received an object: [object DOMRect]
|
||||||
|
iframe received an object: [object Blob]
|
||||||
|
iframe received an object: [object ImageBitmap]
|
||||||
|
iframe received an object: [object CryptoKey]
|
||||||
|
iframe received an object: [object File]
|
||||||
|
iframe received an object: [object FileList]
|
||||||
|
iframe received an object: matrix(1, 2, 3, 4, 5, 6)
|
||||||
|
iframe received an object: matrix(6, 5, 4, 3, 2, 1)
|
||||||
|
iframe received an object: [object DOMPointReadOnly]
|
||||||
|
iframe received an object: [object DOMPoint]
|
||||||
|
iframe received an object: [object DOMQuad]
|
||||||
|
iframe received an object: [object ImageData]
|
||||||
|
iframe received an object: [object MessagePort]
|
||||||
|
iframe received an object: [object ArrayBuffer]
|
||||||
|
iframe received an object: [object ArrayBuffer]
|
||||||
|
iframe received an object: [object ReadableStream]
|
||||||
|
iframe received an object: [object WritableStream]
|
||||||
|
iframe received an object: [object TransformStream]
|
|
@ -1,15 +1,9 @@
|
||||||
Summary
|
|
||||||
|
|
||||||
Harness status: OK
|
Harness status: OK
|
||||||
|
|
||||||
Rerun
|
|
||||||
|
|
||||||
Found 41 tests
|
Found 41 tests
|
||||||
|
|
||||||
36 Pass
|
41 Pass
|
||||||
5 Fail
|
Pass Primitive string is cloned
|
||||||
Details
|
|
||||||
Result Test Name MessagePass Primitive string is cloned
|
|
||||||
Pass Primitive integer is cloned
|
Pass Primitive integer is cloned
|
||||||
Pass Primitive floating point is cloned
|
Pass Primitive floating point is cloned
|
||||||
Pass Primitive floating point (negative) is cloned
|
Pass Primitive floating point (negative) is cloned
|
||||||
|
@ -27,13 +21,13 @@ Pass Object properties are cloned
|
||||||
Pass Prototype chains are not walked.
|
Pass Prototype chains are not walked.
|
||||||
Pass Property descriptors of Objects are not cloned
|
Pass Property descriptors of Objects are not cloned
|
||||||
Pass Cycles are preserved in Objects
|
Pass Cycles are preserved in Objects
|
||||||
Fail Identity of duplicates is preserved
|
Pass Identity of duplicates is preserved
|
||||||
Pass Property order is preserved
|
Pass Property order is preserved
|
||||||
Pass Enumerable properties of Arrays are cloned
|
Pass Enumerable properties of Arrays are cloned
|
||||||
Pass Property descriptors of Arrays are not cloned
|
Pass Property descriptors of Arrays are not cloned
|
||||||
Pass Cycles are preserved in Arrays
|
Pass Cycles are preserved in Arrays
|
||||||
Fail ImageData object can be cloned Cannot serialize platform objects
|
Pass ImageData object can be cloned
|
||||||
Fail ImageData expandos are not cloned Cannot serialize platform objects
|
Pass ImageData expandos are not cloned
|
||||||
Pass Window objects cannot be cloned
|
Pass Window objects cannot be cloned
|
||||||
Pass Document objects cannot be cloned
|
Pass Document objects cannot be cloned
|
||||||
Pass Empty Error objects can be cloned
|
Pass Empty Error objects can be cloned
|
||||||
|
@ -48,5 +42,5 @@ Pass URIError objects from other realms are treated as URIError
|
||||||
Pass Cloning a modified Error
|
Pass Cloning a modified Error
|
||||||
Pass Error.message: getter is ignored when cloning
|
Pass Error.message: getter is ignored when cloning
|
||||||
Pass Error.message: undefined property is stringified
|
Pass Error.message: undefined property is stringified
|
||||||
Fail DOMException objects can be cloned Cannot serialize platform objects
|
Pass DOMException objects can be cloned
|
||||||
Fail DOMException objects created by the UA can be cloned Cannot serialize platform objects
|
Pass DOMException objects created by the UA can be cloned
|
|
@ -0,0 +1,77 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<iframe id="testframe"></iframe>
|
||||||
|
<script src="include.js"></script>
|
||||||
|
<script>
|
||||||
|
asyncTest((done) => {
|
||||||
|
const testframe = document.getElementById("testframe");
|
||||||
|
const canvas = document.createElement("canvas");
|
||||||
|
|
||||||
|
window.onmessage = messageEvent => {
|
||||||
|
if (messageEvent.data === "done") {
|
||||||
|
done();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
println(messageEvent.data);
|
||||||
|
};
|
||||||
|
|
||||||
|
testframe.onload = () => {
|
||||||
|
canvas.toBlob(async (canvasBlob) => {
|
||||||
|
const imageBitmap = await createImageBitmap(canvasBlob);
|
||||||
|
const aesGcm128bitKey = await crypto.subtle.generateKey({ name: "AES-GCM", length: 128 }, true, ["encrypt"]);
|
||||||
|
const input = document.createElement("input");
|
||||||
|
input.type = "file";
|
||||||
|
|
||||||
|
const serializableTypes = [
|
||||||
|
new DOMException(),
|
||||||
|
new DOMRectReadOnly(),
|
||||||
|
new DOMRect(),
|
||||||
|
new Blob([""], { type: "text/plain" }),
|
||||||
|
imageBitmap,
|
||||||
|
aesGcm128bitKey,
|
||||||
|
new File([""], "test.txt"),
|
||||||
|
input.files,
|
||||||
|
new DOMMatrixReadOnly([1, 2, 3, 4, 5, 6]),
|
||||||
|
new DOMMatrix([6, 5, 4, 3, 2, 1]),
|
||||||
|
new DOMPointReadOnly(),
|
||||||
|
new DOMPoint(),
|
||||||
|
new DOMQuad(),
|
||||||
|
new ImageData(1, 1),
|
||||||
|
];
|
||||||
|
|
||||||
|
const messageChannel = new MessageChannel();
|
||||||
|
|
||||||
|
const transferableTypes = [
|
||||||
|
messageChannel.port2,
|
||||||
|
new ArrayBuffer(1),
|
||||||
|
new ArrayBuffer(1, { maxByteLength: 2 }),
|
||||||
|
new ReadableStream(),
|
||||||
|
new WritableStream(),
|
||||||
|
new TransformStream(),
|
||||||
|
];
|
||||||
|
|
||||||
|
for (const serializableType of serializableTypes) {
|
||||||
|
testframe.contentWindow.postMessage(serializableType);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const transferableType of transferableTypes) {
|
||||||
|
testframe.contentWindow.postMessage(transferableType, { transfer: [ transferableType ] });
|
||||||
|
}
|
||||||
|
|
||||||
|
testframe.contentWindow.postMessage("done");
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
testframe.srcdoc = `
|
||||||
|
\u003cscript\u003e
|
||||||
|
window.onmessage = messageEvent => {
|
||||||
|
if (messageEvent.data === "done") {
|
||||||
|
window.parent.postMessage("done");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
window.parent.postMessage("iframe received an object: " + messageEvent.data);
|
||||||
|
};
|
||||||
|
\u003c/script\u003e`
|
||||||
|
});
|
||||||
|
</script>
|
Loading…
Add table
Add a link
Reference in a new issue