[jsonrpc-glib] message: support NULL in JSONRPC_MESSAGE_PUT_VARIANT()



commit 99898fd95210257f220e0e78446a402bdc6f443d
Author: Christian Hergert <chergert redhat com>
Date:   Tue Dec 21 13:08:00 2021 -0800

    message: support NULL in JSONRPC_MESSAGE_PUT_VARIANT()
    
    This instead places a <mav nothing> if we get a NULL variant so that the
    serialized form looks closer to what is expected (ie: key is there, but no
    value to unwrap).
    
    This unblocks https://gitlab.gnome.org/GNOME/gnome-builder/-/merge_requests/433

 src/jsonrpc-message.c | 61 ++++++++++++++++++++++++++++++++++++++-------------
 tests/test-message.c  | 51 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 97 insertions(+), 15 deletions(-)
---
diff --git a/src/jsonrpc-message.c b/src/jsonrpc-message.c
index 9c236a3..3c58856 100644
--- a/src/jsonrpc-message.c
+++ b/src/jsonrpc-message.c
@@ -90,13 +90,7 @@ jsonrpc_message_build_object (GVariantBuilder *builder,
   if (!keyptr || keyptr->magic.bytes[0] == '}')
     EXIT;
 
-  if (IS_PUT_VARIANT (keyptr))
-    {
-      g_variant_builder_add (builder, "v", ((JsonrpcMessagePutVariant *)keyptr)->val);
-      EXIT;
-    }
-
-  g_variant_builder_open (builder, G_VARIANT_TYPE ("{sv}"));
+  g_assert (!IS_PUT_VARIANT (keyptr));
 
   /*
    * Either this is a string wrapped in JSONRPC_MESSAGE_PUT_STRING() or
@@ -107,13 +101,13 @@ jsonrpc_message_build_object (GVariantBuilder *builder,
   else
     key = (const char *)keyptr;
 
-  g_variant_builder_add (builder, "s", key);
-
   /*
    * Now try to read the value for the key/val pair.
    */
   valptr = va_arg (*args, gpointer);
 
+  g_variant_builder_open (builder, G_VARIANT_TYPE ("{sv}"));
+  g_variant_builder_add (builder, "s", key);
   g_variant_builder_open (builder, G_VARIANT_TYPE ("v"));
 
   switch (valptr->magic.bytes[0])
@@ -123,12 +117,32 @@ jsonrpc_message_build_object (GVariantBuilder *builder,
       /*
        * Peek ahead if a possible GVariant will be injected
        */
-      if (IS_PUT_VARIANT ((JsonrpcMessageAny *)param))
-        g_variant_builder_open (builder, G_VARIANT_TYPE ("v"));
+      if (IS_PUT_VARIANT ((JsonrpcMessageAny *)param) &&
+          ((JsonrpcMessagePutVariant *)param)->val != NULL)
+        {
+          if (g_variant_is_of_type (((JsonrpcMessagePutVariant *)param)->val, G_VARIANT_TYPE_VARDICT))
+            {
+              g_variant_builder_add (builder, "v", ((JsonrpcMessagePutVariant *)param)->val);
+            }
+          else
+            {
+              g_warning ("Attempt to add variant of type %s but expected a{sv}",
+                         g_variant_get_type_string (((JsonrpcMessagePutVariant *)param)->val));
+              g_variant_builder_open (builder, G_VARIANT_TYPE ("mav"));
+            }
+        }
+      else if (IS_PUT_VARIANT ((JsonrpcMessageAny *)param))
+        {
+          g_variant_builder_open (builder, G_VARIANT_TYPE ("mav"));
+          g_variant_builder_close (builder);
+        }
       else
-        g_variant_builder_open (builder, G_VARIANT_TYPE ("a{sv}"));
-      jsonrpc_message_build_object (builder, param, args);
-      g_variant_builder_close (builder);
+        {
+          g_variant_builder_open (builder, G_VARIANT_TYPE ("a{sv}"));
+          jsonrpc_message_build_object (builder, param, args);
+          g_variant_builder_close (builder);
+        }
+
       break;
 
     case '[':
@@ -379,7 +393,24 @@ jsonrpc_message_parse_object (GVariantDict *dict,
         }
     }
   else if (IS_GET_VARIANT (valptr))
-    ret = !!(*((JsonrpcMessageGetVariant *)valptr)->variantptr = g_variant_dict_lookup_value (dict, key, 
NULL));
+    {
+      GVariant *lookup = g_variant_dict_lookup_value (dict, key, NULL);
+      GVariant *child = NULL;
+
+      if (lookup != NULL &&
+          g_variant_is_of_type (lookup, G_VARIANT_TYPE_VARIANT) &&
+          g_variant_n_children (lookup) == 1 &&
+          (child = g_variant_get_child_value (lookup, 0)) &&
+          g_variant_is_of_type (child, G_VARIANT_TYPE ("a{sv}")))
+        *((JsonrpcMessageGetVariant *)valptr)->variantptr = g_steal_pointer (&child);
+      else
+        *((JsonrpcMessageGetVariant *)valptr)->variantptr = g_steal_pointer (&lookup);
+
+      ret = !!(*((JsonrpcMessageGetVariant *)valptr)->variantptr);
+
+      g_clear_pointer (&lookup, g_variant_unref);
+      g_clear_pointer (&child, g_variant_unref);
+    }
   else if (IS_GET_STRING (valptr))
     {
       g_autoptr(GVariant) v = g_variant_dict_lookup_value (dict, key, NULL);
diff --git a/tests/test-message.c b/tests/test-message.c
index 7497ee2..0c4fbf4 100644
--- a/tests/test-message.c
+++ b/tests/test-message.c
@@ -299,6 +299,55 @@ test_null_strv (void)
   g_assert_null (get_ar_from_v);
 }
 
+static void
+test_putv_null (void)
+{
+  g_autoptr(GVariant) src = NULL;
+  g_autoptr(GVariant) dst = NULL;
+  GVariantDict dict;
+
+  src = JSONRPC_MESSAGE_NEW ("key", "{", JSONRPC_MESSAGE_PUT_VARIANT (NULL), "}");
+  g_assert_nonnull (src);
+
+  g_variant_dict_init (&dict, NULL);
+  g_variant_dict_insert (&dict, "key", "mav", NULL);
+  dst = g_variant_dict_end (&dict);
+
+  g_assert_nonnull (dst);
+  g_assert_true (g_variant_equal (dst, src));
+}
+
+static void
+test_putv_nonnull (void)
+{
+  g_autoptr(GVariant) src = NULL;
+  g_autoptr(GVariant) dst = NULL;
+  g_autoptr(GVariant) child = NULL;
+  g_autoptr(GVariant) child2 = NULL;
+  GVariantDict cdict;
+  GVariantDict dict;
+
+  g_variant_dict_init (&cdict, NULL);
+  g_variant_dict_insert (&cdict, "hello", "s", "world");
+  child = g_variant_take_ref (g_variant_dict_end (&cdict));
+
+  src = JSONRPC_MESSAGE_NEW ("key", "{", JSONRPC_MESSAGE_PUT_VARIANT (child), "}");
+  g_assert_nonnull (src);
+
+  g_variant_dict_init (&dict, NULL);
+  g_variant_dict_insert (&dict, "key", "v", child);
+  dst = g_variant_take_ref (g_variant_dict_end (&dict));
+  g_assert_nonnull (dst);
+
+  g_assert_false (g_variant_is_floating (src));
+  g_assert_false (g_variant_is_floating (dst));
+  g_assert_false (g_variant_is_floating (child));
+  g_assert_true (g_variant_equal (dst, src));
+
+  JSONRPC_MESSAGE_PARSE (src, "key", JSONRPC_MESSAGE_GET_VARIANT (&child2));
+  g_assert_true (g_variant_equal (child, child2));
+}
+
 gint
 main (gint argc,
       gchar *argv[])
@@ -316,5 +365,7 @@ main (gint argc,
   g_test_add_func ("/Jsonrpc/Message/null_string", test_null_string);
   g_test_add_func ("/Jsonrpc/Message/strv", test_strv);
   g_test_add_func ("/Jsonrpc/Message/null_strv", test_null_strv);
+  g_test_add_func ("/Jsonrpc/Message/putv_null", test_putv_null);
+  g_test_add_func ("/Jsonrpc/Message/putv_nonnull", test_putv_nonnull);
   return g_test_run ();
 }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]