]> git.ipfire.org Git - thirdparty/libvirt.git/commitdiff
json: cope with older yajl semantics
authorEric Blake <eblake@redhat.com>
Mon, 22 Jun 2015 20:18:32 +0000 (14:18 -0600)
committerMichal Privoznik <mprivozn@redhat.com>
Thu, 25 Jun 2015 07:11:15 +0000 (09:11 +0200)
Commit ceb496e5 fails on RHEL 6, with yajl 1.0.7, because that
version of yajl returns yajl_status_insufficient_data when the
parser is waiting for the rest of a token (this enum value was
dropped in yajl 2, so we have to wrap it).  It also exposes a
problem where older yajl silently ignores trailing garbage after
a successful parse, so this patch works around that by changing
the testsuite.  Another more invasive patch can add tighter
semantics to json parsing, but this is sufficient for a minimal
clean backport.

While touching this, fix up our error message cleanup. Yajl
documents that error messages produced by yajl_get_error()
MUST be cleaned with yajl_free_error(); this is certainly
true if we were to pass non-NULL allocator callbacks during
yajl_alloc(), but probably harmless in our usage of passing
NULL.  But better safe than sorry.

* src/util/virjson.c (virJSONValueFromString): Allow different
error code.  Use canonical cleanup of error message.
(VIR_YAJL_STATUS_OK): New helper macro.
* tests/jsontest.c (mymain): Wrap text to avoid difference in
trailing garbage handling

Signed-off-by: Eric Blake <eblake@redhat.com>
src/util/virjson.c
tests/jsontest.c

index 29e2c39636f506e8c0c3c330cdf0ee2f01821c4c..4257b30e69d0de7a6c9ac7df8c5dd1ee507ae041 100644 (file)
 
 # ifdef WITH_YAJL2
 #  define yajl_size_t size_t
+#  define VIR_YAJL_STATUS_OK(status) ((status) == yajl_status_ok)
 # else
 #  define yajl_size_t unsigned int
 #  define yajl_complete_parse yajl_parse_complete
+#  define VIR_YAJL_STATUS_OK(status) \
+    ((status) == yajl_status_ok || (status) == yajl_status_insufficient_data)
 # endif
 
 #endif
@@ -1590,6 +1593,8 @@ virJSONValueFromString(const char *jsonstring)
     yajl_handle hand;
     virJSONParser parser = { NULL, NULL, 0 };
     virJSONValuePtr ret = NULL;
+    int rc;
+    size_t len = strlen(jsonstring);
 # ifndef WITH_YAJL2
     yajl_parser_config cfg = { 1, 1 };
 # endif
@@ -1611,9 +1616,8 @@ virJSONValueFromString(const char *jsonstring)
         goto cleanup;
     }
 
-    if (yajl_parse(hand,
-                   (const unsigned char *)jsonstring,
-                   strlen(jsonstring)) != yajl_status_ok ||
+    rc = yajl_parse(hand, (const unsigned char *)jsonstring, len);
+    if (!VIR_YAJL_STATUS_OK(rc) ||
         yajl_complete_parse(hand) != yajl_status_ok) {
         unsigned char *errstr = yajl_get_error(hand, 1,
                                                (const unsigned char*)jsonstring,
@@ -1622,7 +1626,7 @@ virJSONValueFromString(const char *jsonstring)
         virReportError(VIR_ERR_INTERNAL_ERROR,
                        _("cannot parse json %s: %s"),
                        jsonstring, (const char*) errstr);
-        VIR_FREE(errstr);
+        yajl_free_error(hand, errstr);
         virJSONValueFree(parser.head);
         goto cleanup;
     }
index 34a07ee264cbe5f14828d94433f8371f32334d8a..8ac09708337a2683b6491e7820ac8b6320fca859 100644 (file)
@@ -416,7 +416,7 @@ mymain(void)
     DO_TEST_PARSE("boolean", "true");
     DO_TEST_PARSE("null", "null");
     DO_TEST_PARSE_FAIL("incomplete keyword", "tr");
-    DO_TEST_PARSE_FAIL("overdone keyword", "truest");
+    DO_TEST_PARSE_FAIL("overdone keyword", "[ truest ]");
     DO_TEST_PARSE_FAIL("unknown keyword", "huh");
 
     DO_TEST_PARSE_FAIL("object with numeric keys", "{ 1:1, 2:1, 3:2 }");