From: Eric Haszlakiewicz Date: Sun, 10 Nov 2019 05:12:27 +0000 (-0500) Subject: Add a json_object_from_fd_ex() function, to allow the max nesting depth to be specified. X-Git-Tag: json-c-0.14-20200419~83 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=baed9983b30b46cf6685a061632bbc42cec0ce8d;p=json-c Add a json_object_from_fd_ex() function, to allow the max nesting depth to be specified. --- diff --git a/json_util.c b/json_util.c index ad7704a..a72ab41 100644 --- a/json_util.c +++ b/json_util.c @@ -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) diff --git a/json_util.h b/json_util.h index 70a7d56..9620809 100644 --- a/json_util.h +++ b/json_util.h @@ -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); /** diff --git a/tests/Makefile.am b/tests/Makefile.am index a41aabc..e39fb3c 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -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 diff --git a/tests/test_util_file.c b/tests/test_util_file.c index 5a8a8a0..9aaab23 100644 --- a/tests/test_util_file.c +++ b/tests/test_util_file.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -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); } diff --git a/tests/test_util_file.expected b/tests/test_util_file.expected index f64a5a5..8d87535 100644 --- a/tests/test_util_file.expected +++ b/tests/test_util_file.expected @@ -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 index 0000000..3e1a0cf --- /dev/null +++ b/tests/valid_nested.json @@ -0,0 +1 @@ +{"foo":123, "obj2": { "obj3": { "obj4": { "foo": 999 } } } }