From ae8d048b6c6e783a2c14d78d63cb9247374ca09d Mon Sep 17 00:00:00 2001 From: Nathan Whitaker <17734409+nathanwhit@users.noreply.github.com> Date: Mon, 5 Aug 2024 18:42:26 +0200 Subject: fix(node): Fix node IPC serialization for objects with undefined values (#24894) We were serializing `{ a: undefined }` to `{ a: null }` instead of `{}` --- ext/node/ops/ipc.rs | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) (limited to 'ext/node/ops') diff --git a/ext/node/ops/ipc.rs b/ext/node/ops/ipc.rs index 4849a5c6c..7cfab65a4 100644 --- a/ext/node/ops/ipc.rs +++ b/ext/node/ops/ipc.rs @@ -90,8 +90,14 @@ mod impl_ { let str = deno_core::serde_v8::to_utf8(value.try_into().unwrap(), scope); ser.serialize_str(&str) } else if value.is_string_object() { - let str = - deno_core::serde_v8::to_utf8(value.to_string(scope).unwrap(), scope); + let str = deno_core::serde_v8::to_utf8( + value.to_string(scope).ok_or_else(|| { + S::Error::custom(deno_core::error::generic_error( + "toString on string object failed", + )) + })?, + scope, + ); ser.serialize_str(&str) } else if value.is_boolean() { ser.serialize_bool(value.is_true()) @@ -99,7 +105,7 @@ mod impl_ { ser.serialize_bool(value.boolean_value(scope)) } else if value.is_array() { use serde::ser::SerializeSeq; - let array = v8::Local::::try_from(value).unwrap(); + let array = value.cast::(); let length = array.length(); let mut seq = ser.serialize_seq(Some(length as usize))?; for i in 0..length { @@ -111,13 +117,13 @@ mod impl_ { } else if value.is_object() { use serde::ser::SerializeMap; if value.is_array_buffer_view() { - let buffer = v8::Local::::try_from(value).unwrap(); + let buffer = value.cast::(); let mut buf = vec![0u8; buffer.byte_length()]; let copied = buffer.copy_contents(&mut buf); - assert_eq!(copied, buf.len()); + debug_assert_eq!(copied, buf.len()); return ser.serialize_bytes(&buf); } - let object = value.to_object(scope).unwrap(); + let object = value.cast::(); // node uses `JSON.stringify`, so to match its behavior (and allow serializing custom objects) // we need to respect the `toJSON` method if it exists. let to_json_key = v8::String::new_from_utf8( @@ -128,8 +134,7 @@ mod impl_ { .unwrap() .into(); if let Some(to_json) = object.get(scope, to_json_key) { - if to_json.is_function() { - let to_json = v8::Local::::try_from(to_json).unwrap(); + if let Ok(to_json) = to_json.try_cast::() { let json_value = to_json.call(scope, object.into(), &[]).unwrap(); return serialize_v8_value(scope, json_value, ser); } @@ -149,6 +154,9 @@ mod impl_ { let key = keys.get_index(scope, i).unwrap(); let key_str = key.to_rust_string_lossy(scope); let value = object.get(scope, key).unwrap(); + if value.is_undefined() { + continue; + } map.serialize_entry( &key_str, &SerializeWrapper(RefCell::new(scope), value), @@ -157,9 +165,10 @@ mod impl_ { map.end() } else { // TODO(nathanwhit): better error message - Err(S::Error::custom(deno_core::error::type_error( - "Unsupported type", - ))) + Err(S::Error::custom(deno_core::error::type_error(format!( + "Unsupported type: {}", + value.type_repr() + )))) } } @@ -869,6 +878,7 @@ mod impl_ { r#"{ a: "field", toJSON() { return "custom"; } }"#, "\"custom\"", ), + (r#"{ a: undefined, b: 1 }"#, "{\"b\":1}"), ]; for (input, expect) in cases { -- cgit v1.2.3