Ver Fonte

LibWeb: Support [de]serialization for Error objects

Idan Horowitz há 1 ano atrás
pai
commit
1d24e08934

+ 2 - 0
Tests/LibWeb/Text/expected/HTML/StructuredClone-object-primitives.txt

@@ -6,5 +6,7 @@ This is a String object
 9007199254740991
 9007199254740991
 1692748800000
 1692748800000
 /abc/gimsuy
 /abc/gimsuy
+Error
+URIError: hello
 [object ArrayBuffer]
 [object ArrayBuffer]
 ERROR: DataCloneError: Cannot serialize Symbol
 ERROR: DataCloneError: Cannot serialize Symbol

+ 2 - 0
Tests/LibWeb/Text/input/HTML/StructuredClone-object-primitives.html

@@ -9,6 +9,8 @@
         println(structuredClone(BigInt("0x1fffffffffffff")));
         println(structuredClone(BigInt("0x1fffffffffffff")));
         println(structuredClone(Date.UTC(2023, 7, 23)));
         println(structuredClone(Date.UTC(2023, 7, 23)));
         println(structuredClone(/abc/gimsuy));
         println(structuredClone(/abc/gimsuy));
+        println(structuredClone(new Error()));
+        println(structuredClone(new URIError("hello")));
 
 
         {
         {
             let arrayBuffer = new ArrayBuffer(6);
             let arrayBuffer = new ArrayBuffer(6);

+ 82 - 1
Userland/Libraries/LibWeb/HTML/StructuredSerialize.cpp

@@ -85,12 +85,32 @@ enum ValueTag {
 
 
     ArrayBufferView,
     ArrayBufferView,
 
 
+    ErrorObject,
+
     // TODO: Define many more types
     // TODO: Define many more types
 
 
     // This tag or higher are understood to be errors
     // This tag or higher are understood to be errors
     ValueTagMax,
     ValueTagMax,
 };
 };
 
 
+enum ErrorType {
+    Error,
+#define __JS_ENUMERATE(ClassName, snake_name, PrototypeName, ConstructorName, ArrayType) \
+    ClassName,
+    JS_ENUMERATE_NATIVE_ERRORS
+#undef __JS_ENUMERATE
+};
+
+static ErrorType error_name_to_type(String const& name)
+{
+#define __JS_ENUMERATE(ClassName, snake_name, PrototypeName, ConstructorName, ArrayType) \
+    if (name == #ClassName##sv)                                                          \
+        return ErrorType::ClassName;
+    JS_ENUMERATE_NATIVE_ERRORS
+#undef __JS_ENUMERATE
+    return Error;
+}
+
 // Serializing and deserializing are each two passes:
 // Serializing and deserializing are each two passes:
 // 1. Fill up the memory with all the values, but without translating references
 // 1. Fill up the memory with all the values, but without translating references
 // 2. Translate all the references into the appropriate form
 // 2. Translate all the references into the appropriate form
@@ -215,7 +235,36 @@ public:
             TRY(serialize_viewed_array_buffer(m_serialized, static_cast<JS::DataView&>(value.as_object())));
             TRY(serialize_viewed_array_buffer(m_serialized, static_cast<JS::DataView&>(value.as_object())));
         }
         }
 
 
-        // 15 - 24: FIXME: Serialize other data types
+        // 17. Otherwise, if value has an [[ErrorData]] internal slot and value is not a platform object, then:
+        else if (value.is_object() && is<JS::Error>(value.as_object()) && !is<Bindings::PlatformObject>(value.as_object())) {
+            // 1. Let name be ? Get(value, "name").
+            auto name_property = TRY(value.as_object().get(m_vm.names.name));
+
+            // FIXME: Spec bug - https://github.com/whatwg/html/issues/9923
+            // MISSING STEP: Set name to ? ToString(name).
+            auto name = TRY(name_property.to_string(m_vm));
+
+            // 2. If name is not one of "Error", "EvalError", "RangeError", "ReferenceError", "SyntaxError", "TypeError", or "URIError", then set name to "Error".
+            auto type = error_name_to_type(name);
+
+            // 3. Let valueMessageDesc be ? value.[[GetOwnProperty]]("message").
+            auto value_message_descriptor = TRY(value.as_object().internal_get_own_property(m_vm.names.message));
+
+            // 4. Let message be undefined if IsDataDescriptor(valueMessageDesc) is false, and ? ToString(valueMessageDesc.[[Value]]) otherwise.
+            Optional<String> message;
+            if (value_message_descriptor.has_value() && value_message_descriptor->is_data_descriptor())
+                message = TRY(value_message_descriptor->value->to_string(m_vm));
+
+            // 5. Set serialized to { [[Type]]: "Error", [[Name]]: name, [[Message]]: message }.
+            // FIXME: 6. User agents should attach a serialized representation of any interesting accompanying data which are not yet specified, notably the stack property, to serialized.
+            m_serialized.append(ValueTag::ErrorObject);
+            m_serialized.append(type);
+            m_serialized.append(message.has_value());
+            if (message.has_value())
+                TRY(serialize_string(m_serialized, *message));
+        }
+
+        // 15, 16, 18 - 24: FIXME: Serialize other data types
         else {
         else {
             return throw_completion(WebIDL::DataCloneError::create(*m_vm.current_realm(), "Unsupported type"_fly_string));
             return throw_completion(WebIDL::DataCloneError::create(*m_vm.current_realm(), "Unsupported type"_fly_string));
         }
         }
@@ -501,6 +550,38 @@ public:
                 }
                 }
                 break;
                 break;
             }
             }
+            case ValueTag::ErrorObject: {
+                auto& realm = *m_vm.current_realm();
+                auto type = static_cast<ErrorType>(m_vector[position++]);
+                auto has_message = static_cast<bool>(m_vector[position++]);
+                if (has_message) {
+                    auto message = TRY(deserialize_string(m_vm, m_vector, position));
+                    switch (type) {
+                    case ErrorType::Error:
+                        m_memory.append(JS::Error::create(realm, message));
+                        break;
+#define __JS_ENUMERATE(ClassName, snake_name, PrototypeName, ConstructorName, ArrayType) \
+    case ErrorType::ClassName:                                                           \
+        m_memory.append(JS::ClassName::create(realm, message));                          \
+        break;
+                        JS_ENUMERATE_NATIVE_ERRORS
+#undef __JS_ENUMERATE
+                    }
+                } else {
+                    switch (type) {
+                    case ErrorType::Error:
+                        m_memory.append(JS::Error::create(realm));
+                        break;
+#define __JS_ENUMERATE(ClassName, snake_name, PrototypeName, ConstructorName, ArrayType) \
+    case ErrorType::ClassName:                                                           \
+        m_memory.append(JS::ClassName::create(realm));                                   \
+        break;
+                        JS_ENUMERATE_NATIVE_ERRORS
+#undef __JS_ENUMERATE
+                    }
+                }
+                break;
+            }
             default:
             default:
                 m_error = "Unsupported type"_fly_string;
                 m_error = "Unsupported type"_fly_string;
                 break;
                 break;