]> granicus.if.org Git - json-c/commitdiff
Add a json_object_from_fd_ex() function, to allow the max nesting depth to be specified.
authorEric Haszlakiewicz <erh+git@nimenees.com>
Sun, 10 Nov 2019 05:12:27 +0000 (00:12 -0500)
committerEric Haszlakiewicz <erh+git@nimenees.com>
Sun, 10 Nov 2019 05:14:44 +0000 (00:14 -0500)
json_util.c
json_util.h
tests/Makefile.am
tests/test_util_file.c
tests/test_util_file.expected
tests/valid_nested.json [new file with mode: 0644]

index ad7704a945881f420e58ec8a7dbf425f34850da3..a72ab41e7e364149e738e8712c4d05f91adf0ec2 100644 (file)
@@ -82,6 +82,10 @@ void _json_c_set_last_err(const char *err_fmt, ...)
 }
 
 struct json_object* json_object_from_fd(int fd)
+{
+       return json_object_from_fd_ex(fd, -1);
+}
+struct json_object* json_object_from_fd_ex(int fd, int in_depth)
 {
   struct printbuf *pb;
   struct json_object *obj;
@@ -92,17 +96,35 @@ struct json_object* json_object_from_fd(int fd)
     _json_c_set_last_err("json_object_from_file: printbuf_new failed\n");
     return NULL;
   }
+
+       int depth = JSON_TOKENER_DEFAULT_DEPTH;
+       if (in_depth != -1)
+               depth = in_depth;
+       json_tokener *tok = json_tokener_new_ex(depth);
+       if (!tok)
+       {
+               _json_c_set_last_err("json_object_from_fd: unable to allocate json_tokener(depth=%d): %s\n", depth, strerror(errno));
+               printbuf_free(pb);
+               return NULL;
+       }
+
   while((ret = read(fd, buf, JSON_FILE_BUF_SIZE)) > 0) {
     printbuf_memappend(pb, buf, ret);
   }
   if(ret < 0) {
     _json_c_set_last_err("json_object_from_fd: error reading fd %d: %s\n", fd, strerror(errno));
+       json_tokener_free(tok);
     printbuf_free(pb);
     return NULL;
   }
-  obj = json_tokener_parse(pb->buf);
-  printbuf_free(pb);
-  return obj;
+
+       obj = json_tokener_parse_ex(tok, pb->buf, printbuf_length(pb));
+       if (obj == NULL)
+               _json_c_set_last_err("json_tokener_parse_ex failed: %s\n", json_tokener_error_desc(json_tokener_get_error(tok)));
+
+       json_tokener_free(tok);
+       printbuf_free(pb);
+       return obj;
 }
 
 struct json_object* json_object_from_file(const char *filename)
index 70a7d56c0fde1e758e90c65c8ee6aec37c617856..96208093b00333ce3492ca2750cf8cc4ec1a7eeb 100644 (file)
@@ -50,8 +50,20 @@ JSON_EXPORT struct json_object* json_object_from_file(const char *filename);
  * Note, that the fd must be readable at the actual position, i.e.
  * use lseek(fd, 0, SEEK_SET) before.
  *
+ * The depth argument specifies the maximum object depth to pass to
+ * json_tokener_new_ex().  When depth == -1, JSON_TOKENER_DEFAULT_DEPTH
+ * is used instead.
+ *
  * Returns NULL on failure.  See json_util_get_last_err() for details.
  */
+JSON_EXPORT struct json_object* json_object_from_fd_ex(int fd, int depth);
+
+/**
+ * Create a JSON object from an already opened file descriptor, using
+ * the default maximum object depth. (JSON_TOKENER_DEFAULT_DEPTH)
+ *
+ * See json_object_from_fd_ex() for details.
+ */
 JSON_EXPORT struct json_object* json_object_from_fd(int fd);
 
 /**
index a41aabcd399a8ff2317dc4f72619870dbc5051e7..e39fb3ce38d3864794961b949aa9e85e7c9ad3f3 100644 (file)
@@ -36,6 +36,7 @@ EXTRA_DIST += $(TESTS)
 EXTRA_DIST += $(TESTS:.test=.expected)
 EXTRA_DIST += test-defs.sh
 EXTRA_DIST += valid.json
+EXTRA_DIST += valid_nested.json
 
 
 # Note: handled by test1.test
index 5a8a8a08692baaead28b7a36bcc1578359d96a37..9aaab238a4ffe68a507524c5e78bd21708d1467d 100644 (file)
@@ -5,6 +5,7 @@
 #include <stddef.h>
 #include <string.h>
 #include <fcntl.h>
+#include <limits.h>
 #include <unistd.h>
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -13,6 +14,7 @@
 #include "json_util.h"
 
 static void test_read_valid_with_fd(const char *testdir);
+static void test_read_valid_nested_with_fd(const char *testdir);
 static void test_read_nonexistant();
 static void test_read_closed(void);
 
@@ -129,6 +131,7 @@ int main(int argc, char **argv)
        testdir = argv[1];
 
        test_read_valid_with_fd(testdir);
+       test_read_valid_nested_with_fd(testdir);
        test_read_nonexistant();
        test_read_closed();
        test_write_to_file();
@@ -137,7 +140,8 @@ int main(int argc, char **argv)
 
 static void test_read_valid_with_fd(const char *testdir)
 {
-       const char *filename = "./valid.json";
+       char filename[PATH_MAX];
+       (void)snprintf(filename, sizeof(filename), "%s/valid.json", testdir);
 
        int d = open(filename, O_RDONLY, 0);
        if (d < 0)
@@ -150,8 +154,37 @@ static void test_read_valid_with_fd(const char *testdir)
        json_object *jso = json_object_from_fd(d);
        if (jso != NULL)
        {
-               printf("OK: json_object_from_fd(%s)=%s\n",
-                      filename, json_object_to_json_string(jso));
+               printf("OK: json_object_from_fd(valid.json)=%s\n",
+                      json_object_to_json_string(jso));
+               json_object_put(jso);
+       }
+       else
+       {
+               fprintf(stderr,
+                       "FAIL: unable to parse contents of %s: %s\n",
+                       filename, json_util_get_last_err());
+       }
+       close(d);
+}
+
+static void test_read_valid_nested_with_fd(const char *testdir)
+{
+       char filename[PATH_MAX];
+       (void)snprintf(filename, sizeof(filename), "%s/valid_nested.json", testdir);
+
+       int d = open(filename, O_RDONLY, 0);
+       if (d < 0)
+       {
+               fprintf(stderr,
+                       "FAIL: unable to open %s: %s\n",
+                       filename, strerror(errno));
+               exit(EXIT_FAILURE);
+       }
+       json_object *jso = json_object_from_fd_ex(d, 20);
+       if (jso != NULL)
+       {
+               printf("OK: json_object_from_fd_ex(valid_nested.json, 20)=%s\n",
+                      json_object_to_json_string(jso));
                json_object_put(jso);
        }
        else
@@ -160,6 +193,21 @@ static void test_read_valid_with_fd(const char *testdir)
                        "FAIL: unable to parse contents of %s: %s\n",
                        filename, json_util_get_last_err());
        }
+
+       (void)lseek(d, SEEK_SET, 0);
+
+       jso = json_object_from_fd_ex(d, 3);
+       if (jso != NULL)
+       {
+               printf("FAIL: json_object_from_fd_ex(%s, 3)=%s\n",
+                      filename, json_object_to_json_string(jso));
+               json_object_put(jso);
+       }
+       else
+       {
+               printf("OK: correctly unable to parse contents of valid_nested.json with low max depth: %s\n",
+                       json_util_get_last_err());
+       }
        close(d);
 }
 
index f64a5a500dc12957969744f2fafb5373c60c2e6e..8d87535bbd0b20c038d4b0de99cf8d3497bb386d 100644 (file)
@@ -1,4 +1,7 @@
-OK: json_object_from_fd(./valid.json)={ "foo": 123 }
+OK: json_object_from_fd(valid.json)={ "foo": 123 }
+OK: json_object_from_fd_ex(valid_nested.json, 20)={ "foo": 123, "obj2": { "obj3": { "obj4": { "foo": 999 } } } }
+OK: correctly unable to parse contents of valid_nested.json with low max depth: json_tokener_parse_ex failed: nesting too deep
+
 OK: json_object_from_file(./not_present.json) correctly returned NULL: json_object_from_file: error opening file ./not_present.json: ERRNO=ENOENT
 
 OK: json_object_from_fd(closed_fd), expecting NULL, EBADF, got:NULL, json_object_from_fd: error reading fd 10: ERRNO=EBADF
diff --git a/tests/valid_nested.json b/tests/valid_nested.json
new file mode 100644 (file)
index 0000000..3e1a0cf
--- /dev/null
@@ -0,0 +1 @@
+{"foo":123, "obj2": { "obj3": { "obj4": { "foo": 999 } } } }