From 3901a55c383b8fa4418f6401b5d2769a65beeec7 Mon Sep 17 00:00:00 2001 From: Johannes Helmold Date: Thu, 25 Jul 2024 16:29:52 +0200 Subject: [PATCH 01/29] Add: Added functions used for the matching of CPEs to rules. Added a function to compare two version numbers / version strings with its helper functions. --- CMakeLists.txt | 4 +- util/CMakeLists.txt | 22 ++- util/cpeutils.c | 2 + util/versionutils.c | 340 ++++++++++++++++++++++++++++++++++++++ util/versionutils.h | 35 ++++ util/versionutils_tests.c | 83 ++++++++++ 6 files changed, 482 insertions(+), 4 deletions(-) create mode 100644 util/versionutils.c create mode 100644 util/versionutils.h create mode 100644 util/versionutils_tests.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 100da742..7cd13c3f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -230,8 +230,8 @@ if (BUILD_TESTS AND NOT SKIP_SRC) add_custom_target (tests DEPENDS array-test alivedetection-test boreas_error-test boreas_io-test cli-test cpeutils-test cvss-test ping-test sniffer-test util-test networking-test - passwordbasedauthentication-test xmlutils-test version-test osp-test - nvti-test hosts-test) + passwordbasedauthentication-test xmlutils-test version-test versionutils-test + osp-test nvti-test hosts-test) endif (BUILD_TESTS AND NOT SKIP_SRC) diff --git a/util/CMakeLists.txt b/util/CMakeLists.txt index 95c94235..385c6790 100644 --- a/util/CMakeLists.txt +++ b/util/CMakeLists.txt @@ -110,12 +110,12 @@ include_directories (${GLIB_INCLUDE_DIRS} ${GPGME_INCLUDE_DIRS} ${GCRYPT_INCLUDE ${LIBXML2_INCLUDE_DIRS}) set (FILES cpeutils.c passwordbasedauthentication.c compressutils.c fileutils.c gpgmeutils.c kb.c ldaputils.c - nvticache.c mqtt.c radiusutils.c serverutils.c sshutils.c uuidutils.c + nvticache.c mqtt.c radiusutils.c serverutils.c sshutils.c uuidutils.c versionutils.c xmlutils.c) set (HEADERS cpeutils.h passwordbasedauthentication.h authutils.h compressutils.h fileutils.h gpgmeutils.h kb.h ldaputils.h nvticache.h mqtt.h radiusutils.h serverutils.h sshutils.h - uuidutils.h xmlutils.h) + uuidutils.h versionutils.h xmlutils.h) if (BUILD_STATIC) add_library (gvm_util_static STATIC ${FILES}) @@ -179,6 +179,24 @@ if (BUILD_TESTS) add_custom_target (tests-cpeutils DEPENDS cpeutils-test) + add_executable (versionutils-test + EXCLUDE_FROM_ALL + versionutils_tests.c) + + add_test (versionutils-test versionutils-test) + + target_include_directories (versionutils-test PRIVATE ${CGREEN_INCLUDE_DIRS}) + + target_link_libraries (versionutils-test ${CGREEN_LIBRARIES} + ${GLIB_LDFLAGS} ${GIO_LDFLAGS} ${GPGME_LDFLAGS} ${ZLIB_LDFLAGS} + ${RADIUS_LDFLAGS} ${LIBSSH_LDFLAGS} ${GNUTLS_LDFLAGS} + ${GCRYPT_LDFLAGS} ${LDAP_LDFLAGS} ${REDIS_LDFLAGS} + ${LIBXML2_LDFLAGS} ${UUID_LDFLAGS} + ${LINKER_HARDENING_FLAGS}) + + add_custom_target (tests-versionutils + DEPENDS versionutils-test) + add_executable (xmlutils-test EXCLUDE_FROM_ALL xmlutils_tests.c) diff --git a/util/cpeutils.c b/util/cpeutils.c index 3cc988a1..a42a7261 100644 --- a/util/cpeutils.c +++ b/util/cpeutils.c @@ -11,6 +11,8 @@ * CPE or the CPE 2.3 formatted string binding of a CPE into a CPE struct * that corresponds to the WFN naming of a CPE. Further functions to convert * the CPE struct into the different bindings are provided. + * This file also contains a function that checks if one CPE (represented in a + * CPE struct) is a match for an other CPE (also represented in a CPE struct). */ #include "cpeutils.h" diff --git a/util/versionutils.c b/util/versionutils.c new file mode 100644 index 00000000..65814687 --- /dev/null +++ b/util/versionutils.c @@ -0,0 +1,340 @@ +/* SPDX-FileCopyrightText: 2009-2024 Greenbone AG + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +/** + * @file + * @brief Functions to handle version numbers / version strings. + * + * Up to now this library provides a function to compare two version numbers / + * two version strings to decide which version is the newer one. + */ + +#include "versionutils.h" + +#include +#include +#include +#include +#include + +#undef G_LOG_DOMAIN +/** + * @brief GLib logging domain. + */ +#define G_LOG_DOMAIN "libgvm util" + +/** + * @brief Compare two version strings representing a software version + * to decide which version is newer. + * + * @param[in] version1 The first version string to compare. + * @param[in] version2 The second version string to compare. + * + * @return Returns a value > 0 if version1 is newer than version2. + * Returns 0 if version1 is the same than version2. + * Returns a value between -1 and -4 if version2 is newer + * than version1. + * Returns -5 if the result is undefined. + */ +int +cmp_versions (const char *version1, const char *version2) +{ + char *ver1, *ver2; + char *part1, *part2; + int index1 = 0, index2 = 0; + int release_state1 = 0, release_state2 = 0; + int rs1, rs2; + + ver1 = prepare_version_string (version1); + ver2 = prepare_version_string (version2); + + printf ("\nPROTO: V1 %s", ver1); + printf ("\nPROTO: V2 %s", ver2); + + if (strcmp (ver1, ver2) == 0) + { + g_free (ver1); + g_free (ver2); + return (0); + } + + if ((release_state1 = get_release_state (ver1, index1))) + index1++; + if ((release_state2 = get_release_state (ver2, index2))) + index2++; + + printf ("\nPROTO: RS1 %d RS2 %d\n", release_state1, release_state2); + + part1 = get_part (ver1, index1); + part2 = get_part (ver2, index2); + while (part1 && part2) + { + if (strcmp (part1, part2) == 0) + { + index1++; + index2++; + g_free (part1); + g_free (part2); + part1 = get_part (ver1, index1); + part2 = get_part (ver2, index2); + continue; + } + else + break; + } + + if (part1 == NULL && part2 == NULL) + return (release_state2 - release_state1); + + if (is_text (part1) || is_text (part2)) + { + if (part1) + g_free (part1); + if (part2) + g_free (part2); + return (-5); // undefined + } + + rs1 = get_release_state (ver1, index1); + rs2 = get_release_state (ver2, index2); + + if ((rs1 && release_state1) || (rs2 && release_state2)) + return (-5); // undefined + + if (part1 == NULL) + { + g_free (part2); + if (rs2) + return (rs2 - release_state1); + else + return (-1); + } + + if (part2 == NULL) + { + g_free (part1); + if (rs1) + return (release_state2 - rs1); + else + return (1); + } + + int ret = -5; + + if (rs1 && rs2) + ret = rs2 -rs1; + + if (rs1) + ret = -1; + + if (rs2) + ret = 1; + + if (!rs1 && !rs2 && atoi (part1) < atoi (part2)) + ret = -1; + + if (!rs1 && !rs2 && atoi (part1) == atoi (part2)) + ret = 0; + + if (!rs1 && !rs2 && atoi (part1) > atoi (part2)) + ret = 1; + + g_free (part1); + g_free (part2); + g_free (ver1); + g_free (ver2); + return (ret); +} + +/** + * @brief Prepare the version string for comparison. + * + * @param[in] version The version string to generate the prepared + * version string from. + * + * @return Returns a prepared copy of the version string version. + */ +static char * +prepare_version_string (const char *version) +{ + char prep_version[1024]; + char *ver; + int index_v, index_pv; + gboolean is_digit; + + if (!version) + return (NULL); + + ver = g_strdup (version); + + /* set all characters to lowercase */ + char *c = ver; + for (; *c; c++) + *c = tolower (*c); + + index_v = index_pv = 0; + + is_digit = g_ascii_isdigit (ver[0]); + + while (index_v < (int) strlen (ver)) + { + if (ver[index_v] == '_' || ver[index_v] == '-' + || ver[index_v] == '+' || ver[index_v] == ':' + || ver[index_v] == '.') + { + if (index_pv > 0 && prep_version[index_pv-1] != '.') + { + prep_version[index_pv] = '.'; + index_pv++; + } + index_v++; + continue; + } + + if (is_digit != g_ascii_isdigit (ver[index_v])) + { + is_digit = !is_digit; + if (index_pv > 0 && prep_version[index_pv-1] != '.') + { + prep_version[index_pv] = '.'; + index_pv++; + } + } + + if (ver[index_v] == 'r') + { + if (strstr (ver + index_v, "releasecandidate") == + ver + index_v ) + { + prep_version [index_pv] = 'r'; + prep_version [index_pv + 1] = 'c'; + index_pv += 2; + index_v += 16; + continue; + } + if ((strstr (ver + index_v, "release-candidate") == + ver + index_v) || + (strstr (ver + index_v, "release_candidate") == + ver + index_v) ) + { + prep_version [index_pv] = 'r'; + prep_version [index_pv + 1] = 'c'; + index_pv += 2; + index_v += 17; + continue; + } + } + + prep_version[index_pv] = ver[index_v]; + index_v++; + index_pv++; + } + + prep_version[index_pv] = '\0'; + g_free (ver); + return (g_strdup(prep_version)); +} + +/** + * @brief Gets the release state of a specified part of the version string + * if any. + * + * @param[in] version The version string to get the release state from. + * @param[in] index The part of the version string to check. + * + * @return Returns 0 if there is no release state, returns 4 if the release + * state is "development" (dev), returns 3 if the state is "alpha", + * 2 if the state is beta and 1 if the state is release candidate (rc). + */ +static int +get_release_state (const char *version, int index) +{ + char *part; + int rel_stat = 0; + + part = get_part (version, index); + + if (part == NULL) + return (0); + + if (strcmp (part, "dev") == 0 || strcmp (part, "development") == 0) + rel_stat = 4; + if (strcmp (part, "alpha") == 0) + rel_stat = 3; + if (strcmp (part, "beta") == 0) + rel_stat = 2; + if (strcmp (part, "rc") == 0) + rel_stat = 1; + + g_free (part); + return (rel_stat); +} + +/** + * @brief Gets the part of the version string that is specified by index. + * + * @param[in] version The version string to get the part from. + * @param[in] index The part of the version string to return. + * + * @return Returns a copy of the specified part of the version string. + */ +static char * +get_part (const char *version, int index) +{ + int dot_count = 0; + int begin, end; + + for (begin = 0; begin < (int) strlen (version) && dot_count < index; begin++) + { + if (version[begin] == '.') + dot_count++; + } + + if (begin == (int) strlen(version)) + return (NULL); + + for (end = begin + 1; end < (int) strlen (version) && version[end] != '.'; end++); + + return (str_cpy ((char *) (version + begin), end - begin)); +} + +/** + * @brief Checks if a given part of the version string is plain text. + * + * @param[in] part The part of the version string to check. + * + * @return Returns TRUE if part contains only plain text, FALSE otherwise. + */ +static gboolean +is_text (const char *part) +{ + if (!part) + return (FALSE); + if (strcmp (part, "dev") == 0 || strcmp (part, "alpha") == 0 || + strcmp (part, "beta") == 0 || strcmp (part, "rc") == 0 ) + return (FALSE); + if (g_ascii_isdigit (*part)) + return (FALSE); + return (TRUE); +} + +/** + * @brief Copy size characters of a string to an newly allocated new string. + * + * @param[in] src The string the first size characters are to be copied + * from. + * @param[in] size The number of characters to copy. + * + * @return The copy of the first size characters of src as a new string. + */ +static char * +str_cpy (char *source, int size) +{ + char *result; + result = (char *) g_malloc (size + 1); + memset (result, 0, size + 1); + strncpy (result, source, size); + return (result); +} diff --git a/util/versionutils.h b/util/versionutils.h new file mode 100644 index 00000000..d3ac0d3e --- /dev/null +++ b/util/versionutils.h @@ -0,0 +1,35 @@ +/* SPDX-FileCopyrightText: 2009-2024 Greenbone AG + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +/** + * @file + * @brief Headers for version utils. + */ + +#ifndef _GVM_CPEUTILS_H +#define _GVM_CPEUTILS_H + +#include +#include + +int +cmp_versions (const char *, const char *); + +static char * +prepare_version_string (const char *); + +static int +get_release_state (const char *, int); + +static char * +get_part (const char *, int); + +static gboolean +is_text (const char *); + +static char * +str_cpy (char *, int); + +#endif diff --git a/util/versionutils_tests.c b/util/versionutils_tests.c new file mode 100644 index 00000000..1f842292 --- /dev/null +++ b/util/versionutils_tests.c @@ -0,0 +1,83 @@ +/* SPDX-FileCopyrightText: 2019-2023 Greenbone AG + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "versionutils.c" + +#include +#include + +Describe (versionutils); +BeforeEach (versionutils) +{ +} + +AfterEach (versionutils) +{ +} + +/* parse_entity */ + +Ensure (versionutils, cmp_versions) +{ + char *version1, *version2; + int result; + + version1 = "test"; + version2 = "test-1"; + result = cmp_versions (version1, version2); + assert_that (result, is_less_than (0)); + assert_that (result, is_greater_than (-5)); + + version1 = "beta-test-2"; + version2 = "test_1"; + result = cmp_versions (version1, version2); + assert_that (result, is_greater_than (0)); + + version1 = "beta-test-2"; + version2 = "test-2.beta"; + result = cmp_versions (version1, version2); + assert_that (result, is_equal_to (0)); + + version1 = "test-2.beta"; + version2 = "test-2.a"; + result = cmp_versions (version1, version2); + assert_that (result, is_equal_to (-5)); + + version1 = "test-2.beta"; + version2 = "test-2.1"; + result = cmp_versions (version1, version2); + assert_that (result, is_equal_to (-1)); + + version1 = "test-2.release_candidate"; + version2 = "test-2"; + result = cmp_versions (version1, version2); + assert_that (result, is_equal_to (-1)); + + version1 = "test-2.release_candidate2"; + version2 = "test-2.release_candidate1"; + result = cmp_versions (version1, version2); + assert_that (result, is_greater_than (0)); + + version1 = "test-2.release_candidatea"; + version2 = "test-2.release_candidateb"; + result = cmp_versions (version1, version2); + assert_that (result, is_equal_to (-5)); +} + +/* Test suite. */ +int +main (int argc, char **argv) +{ + TestSuite *suite; + + suite = create_test_suite (); + + add_test_with_context (suite, versionutils, cmp_versions); + + if (argc > 1) + return run_single_test (suite, argv[1], create_text_reporter ()); + + return run_test_suite (suite, create_text_reporter ()); +} From 65de60cb909310b0d954cb85de84d0b9205aeba9 Mon Sep 17 00:00:00 2001 From: Johannes Helmold Date: Thu, 25 Jul 2024 16:43:11 +0200 Subject: [PATCH 02/29] Amended some formatting. --- util/versionutils.c | 58 ++++++++++++++++++++++----------------------- 1 file changed, 28 insertions(+), 30 deletions(-) diff --git a/util/versionutils.c b/util/versionutils.c index 65814687..8c083671 100644 --- a/util/versionutils.c +++ b/util/versionutils.c @@ -75,8 +75,8 @@ cmp_versions (const char *version1, const char *version2) { index1++; index2++; - g_free (part1); - g_free (part2); + g_free (part1); + g_free (part2); part1 = get_part (ver1, index1); part2 = get_part (ver2, index2); continue; @@ -124,7 +124,7 @@ cmp_versions (const char *version1, const char *version2) int ret = -5; if (rs1 && rs2) - ret = rs2 -rs1; + ret = rs2 - rs1; if (rs1) ret = -1; @@ -180,11 +180,10 @@ prepare_version_string (const char *version) while (index_v < (int) strlen (ver)) { - if (ver[index_v] == '_' || ver[index_v] == '-' - || ver[index_v] == '+' || ver[index_v] == ':' - || ver[index_v] == '.') + if (ver[index_v] == '_' || ver[index_v] == '-' || ver[index_v] == '+' + || ver[index_v] == ':' || ver[index_v] == '.') { - if (index_pv > 0 && prep_version[index_pv-1] != '.') + if (index_pv > 0 && prep_version[index_pv - 1] != '.') { prep_version[index_pv] = '.'; index_pv++; @@ -196,7 +195,7 @@ prepare_version_string (const char *version) if (is_digit != g_ascii_isdigit (ver[index_v])) { is_digit = !is_digit; - if (index_pv > 0 && prep_version[index_pv-1] != '.') + if (index_pv > 0 && prep_version[index_pv - 1] != '.') { prep_version[index_pv] = '.'; index_pv++; @@ -205,25 +204,22 @@ prepare_version_string (const char *version) if (ver[index_v] == 'r') { - if (strstr (ver + index_v, "releasecandidate") == - ver + index_v ) + if (strstr (ver + index_v, "releasecandidate") == ver + index_v) { - prep_version [index_pv] = 'r'; - prep_version [index_pv + 1] = 'c'; - index_pv += 2; - index_v += 16; - continue; + prep_version[index_pv] = 'r'; + prep_version[index_pv + 1] = 'c'; + index_pv += 2; + index_v += 16; + continue; } - if ((strstr (ver + index_v, "release-candidate") == - ver + index_v) || - (strstr (ver + index_v, "release_candidate") == - ver + index_v) ) + if ((strstr (ver + index_v, "release-candidate") == ver + index_v) + || (strstr (ver + index_v, "release_candidate") == ver + index_v)) { - prep_version [index_pv] = 'r'; - prep_version [index_pv + 1] = 'c'; - index_pv += 2; - index_v += 17; - continue; + prep_version[index_pv] = 'r'; + prep_version[index_pv + 1] = 'c'; + index_pv += 2; + index_v += 17; + continue; } } @@ -234,7 +230,7 @@ prepare_version_string (const char *version) prep_version[index_pv] = '\0'; g_free (ver); - return (g_strdup(prep_version)); + return (g_strdup (prep_version)); } /** @@ -292,10 +288,12 @@ get_part (const char *version, int index) dot_count++; } - if (begin == (int) strlen(version)) + if (begin == (int) strlen (version)) return (NULL); - - for (end = begin + 1; end < (int) strlen (version) && version[end] != '.'; end++); + + for (end = begin + 1; end < (int) strlen (version) && version[end] != '.'; + end++) + ; return (str_cpy ((char *) (version + begin), end - begin)); } @@ -312,8 +310,8 @@ is_text (const char *part) { if (!part) return (FALSE); - if (strcmp (part, "dev") == 0 || strcmp (part, "alpha") == 0 || - strcmp (part, "beta") == 0 || strcmp (part, "rc") == 0 ) + if (strcmp (part, "dev") == 0 || strcmp (part, "alpha") == 0 + || strcmp (part, "beta") == 0 || strcmp (part, "rc") == 0) return (FALSE); if (g_ascii_isdigit (*part)) return (FALSE); From 1d61c2fd28410dc5bcea8a7105ba4da2b82f6319 Mon Sep 17 00:00:00 2001 From: Johannes Helmold Date: Fri, 26 Jul 2024 11:15:06 +0200 Subject: [PATCH 03/29] Removed some debug messages and added one test. --- util/versionutils.c | 5 ----- util/versionutils_tests.c | 5 +++++ 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/util/versionutils.c b/util/versionutils.c index 8c083671..fc5473c5 100644 --- a/util/versionutils.c +++ b/util/versionutils.c @@ -50,9 +50,6 @@ cmp_versions (const char *version1, const char *version2) ver1 = prepare_version_string (version1); ver2 = prepare_version_string (version2); - printf ("\nPROTO: V1 %s", ver1); - printf ("\nPROTO: V2 %s", ver2); - if (strcmp (ver1, ver2) == 0) { g_free (ver1); @@ -65,8 +62,6 @@ cmp_versions (const char *version1, const char *version2) if ((release_state2 = get_release_state (ver2, index2))) index2++; - printf ("\nPROTO: RS1 %d RS2 %d\n", release_state1, release_state2); - part1 = get_part (ver1, index1); part2 = get_part (ver2, index2); while (part1 && part2) diff --git a/util/versionutils_tests.c b/util/versionutils_tests.c index 1f842292..c7e0502b 100644 --- a/util/versionutils_tests.c +++ b/util/versionutils_tests.c @@ -64,6 +64,11 @@ Ensure (versionutils, cmp_versions) version2 = "test-2.release_candidateb"; result = cmp_versions (version1, version2); assert_that (result, is_equal_to (-5)); + + version1 = "2024-06-24"; + version2 = "2024-06-23"; + result = cmp_versions (version1, version2); + assert_that (result, is_greater_than (0)); } /* Test suite. */ From 1afbb254a0997366f969bcb7e95e7f4ad291abc2 Mon Sep 17 00:00:00 2001 From: Timo Pollmeier Date: Tue, 30 Jul 2024 13:57:23 +0200 Subject: [PATCH 04/29] Add: Incremental JSON "pull" parser utils Functions and data structures for incrementally parsing JSON streams are added. These can be used to parse large files while limiting the memory usage similar to the streaming parser for XML. --- CMakeLists.txt | 2 +- util/CMakeLists.txt | 25 +- util/jsonpull.c | 954 ++++++++++++++++++++++++++++++++++++++++++ util/jsonpull.h | 129 ++++++ util/jsonpull_tests.c | 505 ++++++++++++++++++++++ 5 files changed, 1611 insertions(+), 4 deletions(-) create mode 100644 util/jsonpull.c create mode 100644 util/jsonpull.h create mode 100644 util/jsonpull_tests.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 100da742..e9ad3b0d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -231,7 +231,7 @@ if (BUILD_TESTS AND NOT SKIP_SRC) DEPENDS array-test alivedetection-test boreas_error-test boreas_io-test cli-test cpeutils-test cvss-test ping-test sniffer-test util-test networking-test passwordbasedauthentication-test xmlutils-test version-test osp-test - nvti-test hosts-test) + nvti-test hosts-test jsonpull-test) endif (BUILD_TESTS AND NOT SKIP_SRC) diff --git a/util/CMakeLists.txt b/util/CMakeLists.txt index 95c94235..6b656306 100644 --- a/util/CMakeLists.txt +++ b/util/CMakeLists.txt @@ -42,6 +42,9 @@ pkg_check_modules (GPGME REQUIRED gpgme>=1.7.0) # for serverutils we need libgcrypt pkg_check_modules (GCRYPT REQUIRED libgcrypt) +# for json parsing we need cJSON +pkg_check_modules (CJSON REQUIRED libcjson>=1.7.14) + # for mqtt find_library(LIBPAHO paho-mqtt3c) message (STATUS "Looking for paho-mqtt3c ... ${LIBPAHO}") @@ -111,11 +114,11 @@ include_directories (${GLIB_INCLUDE_DIRS} ${GPGME_INCLUDE_DIRS} ${GCRYPT_INCLUDE set (FILES cpeutils.c passwordbasedauthentication.c compressutils.c fileutils.c gpgmeutils.c kb.c ldaputils.c nvticache.c mqtt.c radiusutils.c serverutils.c sshutils.c uuidutils.c - xmlutils.c) + xmlutils.c jsonpull.c) set (HEADERS cpeutils.h passwordbasedauthentication.h authutils.h compressutils.h fileutils.h gpgmeutils.h kb.h ldaputils.h nvticache.h mqtt.h radiusutils.h serverutils.h sshutils.h - uuidutils.h xmlutils.h) + uuidutils.h xmlutils.h jsonpull.h) if (BUILD_STATIC) add_library (gvm_util_static STATIC ${FILES}) @@ -137,13 +140,29 @@ if (BUILD_SHARED) ${RADIUS_LDFLAGS} ${LIBSSH_LDFLAGS} ${GNUTLS_LDFLAGS} ${GCRYPT_LDFLAGS} ${LDAP_LDFLAGS} ${REDIS_LDFLAGS} ${LIBXML2_LDFLAGS} ${UUID_LDFLAGS} - ${LINKER_HARDENING_FLAGS} ${CRYPT_LDFLAGS}) + ${LINKER_HARDENING_FLAGS} ${CRYPT_LDFLAGS} + ${CJSON_LDFLAGS}) endif (BUILD_SHARED) ## Tests if (BUILD_TESTS) + add_executable (jsonpull-test + EXCLUDE_FROM_ALL + jsonpull_tests.c) + + add_test (jsonpull-test jsonpull-test) + + target_include_directories (jsonpull-test PRIVATE ${CGREEN_INCLUDE_DIRS}) + + target_link_libraries (jsonpull-test ${CGREEN_LIBRARIES} + ${GLIB_LDFLAGS} ${CJSON_LDFLAGS}) + + add_custom_target (tests-jsonpull + DEPENDS jsonpull-test) + + add_executable (passwordbasedauthentication-test EXCLUDE_FROM_ALL passwordbasedauthentication_tests.c) diff --git a/util/jsonpull.c b/util/jsonpull.c new file mode 100644 index 00000000..a138db25 --- /dev/null +++ b/util/jsonpull.c @@ -0,0 +1,954 @@ +/* SPDX-FileCopyrightText: 2024 Greenbone AG + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "jsonpull.h" +#include "assert.h" + +#define GVM_JSON_CHAR_EOF -1 ///< End of file +#define GVM_JSON_CHAR_ERROR -2 ///< Error reading file +#define GVM_JSON_CHAR_UNDEFINED -3 ///< Undefined state + +/** + * @brief Creates a new JSON path element. + * + * @param[in] parent_type Type of the parent (array, object, none/root) + * @param[in] depth The depth in the document tree + * + * @return The newly allocated path element + */ +gvm_json_path_elem_t * +gvm_json_pull_path_elem_new (gvm_json_pull_container_type_t parent_type, + int depth) +{ + gvm_json_path_elem_t *new_elem = g_malloc0 (sizeof (gvm_json_path_elem_t)); + new_elem->parent_type = parent_type; + new_elem->depth = depth; + return new_elem; +} + +/** + * @brief Frees a JSON path element. + * + * @param[in] elem The element to free + */ +void +gvm_json_pull_path_elem_free (gvm_json_path_elem_t *elem) +{ + g_free (elem->key); + g_free (elem); +} + +/** + * @brief Initializes a JSON pull event data structure. + * + * @param[in] event The event structure to initialize + */ +void +gvm_json_pull_event_init (gvm_json_pull_event_t *event) +{ + memset (event, 0, sizeof(gvm_json_pull_event_t)); +} + +/** + * @brief Resets a JSON pull event data structure for reuse. + * + * @param[in] event The event structure to reset + */ +void +gvm_json_pull_event_reset (gvm_json_pull_event_t *event) +{ + cJSON_free (event->value); + memset (event, 0, sizeof(gvm_json_pull_event_t)); +} + +/** + * @brief Frees all data of JSON pull event data structure. + * + * @param[in] event The event structure to clean up + */ +void +gvm_json_pull_event_cleanup (gvm_json_pull_event_t *event) +{ + cJSON_free (event->value); + memset (event, 0, sizeof(gvm_json_pull_event_t)); +} + +/** + * @brief Initializes a JSON pull parser. + * + * @param[in] parser The parser data structure to initialize + * @param[in] input_stream The JSON input stream + * @param[in] parse_buffer_limit Maximum buffer size for parsing values + * @param[in] read_buffer_size Buffer size for reading from the stream + */ +void +gvm_json_pull_parser_init_full (gvm_json_pull_parser_t *parser, + FILE *input_stream, + size_t parse_buffer_limit, + size_t read_buffer_size) +{ + assert(parser); + assert (input_stream); + memset (parser, 0, sizeof(gvm_json_pull_parser_t)); + + if (parse_buffer_limit <= 0) + parse_buffer_limit = GVM_JSON_PULL_PARSE_BUFFER_LIMIT; + + if (read_buffer_size <= 0) + read_buffer_size = GVM_JSON_PULL_READ_BUFFER_SIZE; + + parser->input_stream = input_stream; + parser->path = g_queue_new (); + parser->expect = GVM_JSON_PULL_EXPECT_VALUE; + parser->parse_buffer_limit = parse_buffer_limit; + parser->parse_buffer = g_string_new (""); + parser->read_buffer_size = read_buffer_size; + parser->read_buffer = g_malloc0(read_buffer_size); + parser->last_read_char = GVM_JSON_CHAR_UNDEFINED; +} + +/** + * @brief Initializes a JSON pull parser with default buffer sizes. + * + * @param[in] parser The parser data structure to initialize + * @param[in] input_stream The JSON input stream + */ +void +gvm_json_pull_parser_init (gvm_json_pull_parser_t *parser, + FILE *input_stream) +{ + gvm_json_pull_parser_init_full (parser, input_stream, 0, 0); +} + +/** + * @brief Frees the data of a JSON pull parser. + * + * @param[in] parser The parser data structure to free the data of + */ +void +gvm_json_pull_parser_cleanup (gvm_json_pull_parser_t *parser) +{ + assert(parser); + g_queue_free_full (parser->path, + (GDestroyNotify) gvm_json_pull_path_elem_free); + g_string_free (parser->parse_buffer, TRUE); + g_free (parser->read_buffer); + memset (parser, 0, sizeof(gvm_json_pull_parser_t)); +} + +/** + * @brief Generates message for an error that occurred reading the JSON stream. + * + * @return The newly allocated error message + */ +static gchar * +gvm_json_read_stream_error_str () +{ + return g_strdup_printf ("error reading JSON stream: %s", strerror (errno)); +} + +/** + * @brief Checks if the parse buffer limit of a JSON pull parser is reached. + * + * @param[in] value_type The value type to include in the error message + * @param[in] parser The parser to check the parse buffer of + * @param[in] event Event data for error status and message if needed + * + * @return 0 if buffer size is okay, 1 if limit was reached + */ +static int +gvm_json_pull_check_parse_buffer_size (const char *value_type, + gvm_json_pull_parser_t *parser, + gvm_json_pull_event_t *event) +{ + if (parser->parse_buffer->len >= parser->parse_buffer_limit) + { + event->error_message + = g_strdup_printf ("%s exceeds size limit of %zu bytes", + value_type, + parser->parse_buffer_limit); + event->type = GVM_JSON_PULL_EVENT_ERROR; + return 1; + } + return 0; +} + +/** + * @brief Reads the next character in a pull parser input stream. + * + * @return The character code, GVM_JSON_CHAR_ERROR or GVM_JSON_CHAR_EOF. + */ +static int +gvm_json_pull_parser_next_char (gvm_json_pull_parser_t *parser) +{ + parser->read_pos++; + if (parser->read_pos < parser->last_read_size) + { + parser->last_read_char + = (unsigned char) parser->read_buffer[parser->read_pos]; + return parser->last_read_char; + } + else + { + parser->read_pos = 0; + parser->last_read_size = fread (parser->read_buffer, + 1, + parser->read_buffer_size, + parser->input_stream); + if (ferror (parser->input_stream)) + parser->last_read_char = GVM_JSON_CHAR_ERROR; + else if (parser->last_read_size <= 0) + parser->last_read_char = GVM_JSON_CHAR_EOF; + else + parser->last_read_char + = (unsigned char) parser->read_buffer[parser->read_pos]; + return parser->last_read_char; + } +} + +/** + * @brief Tries to parse the buffer content of a JSON pull parser. + * + * @param[in] parser The parser to use the parse buffer of + * @param[in] event Event set error of if necessary + * @param[in] value_name Name of the value for error message if needed + * @param[in] validate_func Function for validating the parsed value + * @param[out] cjson_value Return of the parsed cJSON object on success + * + * @return 0 success, 1 error + */ +static int +gvm_json_pull_parse_buffered (gvm_json_pull_parser_t *parser, + gvm_json_pull_event_t *event, + const char *value_name, + cJSON_bool (*validate_func)(const cJSON* const), + cJSON **cjson_value) +{ + cJSON* parsed_value = cJSON_Parse (parser->parse_buffer->str); + *cjson_value = NULL; + if (validate_func (parsed_value) == 0) + { + event->type = GVM_JSON_PULL_EVENT_ERROR; + event->error_message + = g_strdup_printf ("error parsing %s", value_name); + cJSON_free (parsed_value); + return 1; + } + *cjson_value = parsed_value; + return 0; +} + +/** + * @brief Handles error or EOF after reading a character in JSON pull parser. + * + * @param[in] parser Parser to get the last read character from + * @param[in] event Event data to set EOF or error status in + * @param[in] allow_eof Whether to allow EOF, generate error on EOF if FALSE + */ +static void +gvm_json_pull_handle_read_end (gvm_json_pull_parser_t *parser, + gvm_json_pull_event_t *event, + gboolean allow_eof) +{ + if (parser->last_read_char == GVM_JSON_CHAR_ERROR) + { + event->error_message = gvm_json_read_stream_error_str (); + event->type = GVM_JSON_PULL_EVENT_ERROR; + } + else if (allow_eof) + event->type = GVM_JSON_PULL_EVENT_EOF; + else + { + event->error_message = g_strdup ("unexpected EOF"); + event->type = GVM_JSON_PULL_EVENT_ERROR; + } +} + +/** + * @brief Skips whitespaces in the input stream of a JSON pull parser + * + * The parser will be at the first non-whitespace character on success. + * + * @param[in] parser Parser to skip the whitespaces in + * @param[in] event Event data to set EOF or error status in + * @param[in] allow_eof Whether to allow EOF, generate error on EOF if FALSE + * + * @return 1 if EOF was reached or an error occurred, 0 otherwise + */ +static int +gvm_json_pull_skip_space (gvm_json_pull_parser_t *parser, + gvm_json_pull_event_t *event, + gboolean allow_eof) +{ + while (g_ascii_isspace (parser->last_read_char)) + gvm_json_pull_parser_next_char (parser); + if (parser->last_read_char < 0) + { + gvm_json_pull_handle_read_end (parser, event, allow_eof); + return 1; + } + return 0; +} + +/** + * @brief Parses a string in a JSON pull parser. + * + * The parser is expected to be at the opening quote mark and will be at the + * character after the closing quote mark on success. + * + * @param[in] parser Parser to handle the string value in + * @param[in] event Event data to set EOF or error status in + * @param[out] cjson_value The cJSON value for the string on success + * + * @return 1 if an error occurred (including EOF), 0 otherwise + */ +static int +gvm_json_pull_parse_string (gvm_json_pull_parser_t *parser, + gvm_json_pull_event_t *event, + cJSON **cjson_value) +{ + gboolean escape_next_char = FALSE; + g_string_truncate (parser->parse_buffer, 0); + g_string_append_c (parser->parse_buffer, '"'); + while (gvm_json_pull_parser_next_char (parser) >= 0) + { + if (gvm_json_pull_check_parse_buffer_size ("string", parser, event)) + return 1; + g_string_append_c (parser->parse_buffer, parser->last_read_char); + if (escape_next_char) + escape_next_char = FALSE; + else if (parser->last_read_char == '\\') + escape_next_char = TRUE; + else if (parser->last_read_char == '"') + break; + } + + if (parser->last_read_char < 0) + { + gvm_json_pull_handle_read_end (parser, event, FALSE); + return 1; + } + + gvm_json_pull_parser_next_char (parser); + + return gvm_json_pull_parse_buffered (parser, + event, + "string", + cJSON_IsString, + cjson_value); +} + +/** + * @brief Parses a number in a JSON pull parser. + * + * The parser is expected to be at the first character of the number and will + * be at the first non-number character on success. + * + * @param[in] parser Parser to handle the number value in + * @param[in] event Event data to set EOF or error status in + * @param[out] cjson_value The cJSON value for the number on success. + * + * @return 1 if an error occurred, 0 otherwise + */ +static int +gvm_json_pull_parse_number (gvm_json_pull_parser_t *parser, + gvm_json_pull_event_t *event, + cJSON **cjson_value) +{ + g_string_truncate (parser->parse_buffer, 0); + g_string_append_c (parser->parse_buffer, parser->last_read_char); + while (gvm_json_pull_parser_next_char (parser) >= 0) + { + if (gvm_json_pull_check_parse_buffer_size ("number", parser, event)) + return 1; + if (g_ascii_isdigit (parser->last_read_char) + || parser->last_read_char == '.' + || parser->last_read_char == 'e' + || parser->last_read_char == '-' + || parser->last_read_char == '+') + g_string_append_c (parser->parse_buffer, parser->last_read_char); + else + break; + } + + if (parser->last_read_char == GVM_JSON_CHAR_ERROR) + { + event->error_message = gvm_json_read_stream_error_str (); + event->type = GVM_JSON_PULL_EVENT_ERROR; + return 1; + } + + return gvm_json_pull_parse_buffered (parser, + event, + "number", + cJSON_IsNumber, + cjson_value); +} + +/** + * @brief Parses a keyword value in a JSON pull parser. + * + * The parser is expected to be at the first character of the keyword and will + * be at the first character after the keyword on success. + * + * @param[in] parser Parser to handle the keyword value in + * @param[in] event Event data to set EOF or error status in + * @param[in] keyword The expected keyword, e.g. "null", "true", "false". + * + * @return 1 if an error occurred, 0 otherwise + */ +static int +gvm_json_pull_parse_keyword (gvm_json_pull_parser_t *parser, + gvm_json_pull_event_t *event, + const char *keyword) +{ + for (size_t i = 0; i < strlen(keyword); i++) + { + if (parser->last_read_char < 0) + { + gvm_json_pull_handle_read_end (parser, event, FALSE); + return 1; + } + else if (parser->last_read_char != keyword[i]) + { + event->type = GVM_JSON_PULL_EVENT_ERROR; + event->error_message + = g_strdup_printf ("misspelled keyword '%s'", keyword); + return 1; + } + gvm_json_pull_parser_next_char (parser); + } + return 0; +} + +#define PARSE_VALUE_NEXT_EXPECT \ + if (parser->path->length) \ + parser->expect = GVM_JSON_PULL_EXPECT_COMMA; \ + else \ + parser->expect = GVM_JSON_PULL_EXPECT_EOF; + +/** + * @brief Handles the case that an object key is expected in a JSON pull parser. + * + * This will continue the parsing until the value is expected, the end of the + * current object was reached or an error occurred. + * + * @param[in] parser Parser to process + * @param[in] event Event data to set error or end of object status in + * + * @return 1 if an error occurred, 0 otherwise + */ +static int +gvm_json_pull_parse_key (gvm_json_pull_parser_t *parser, + gvm_json_pull_event_t *event) +{ + if (gvm_json_pull_skip_space (parser, event, FALSE)) + return 1; + + cJSON *key_cjson = NULL; + gchar *key_str; + gvm_json_path_elem_t *path_elem; + + switch (parser->last_read_char) + { + case '"': + if (gvm_json_pull_parse_string (parser, event, &key_cjson)) + return 1; + key_str = g_strdup (key_cjson->valuestring); + cJSON_free (key_cjson); + + // Expect colon: + if (gvm_json_pull_skip_space (parser, event, FALSE)) + { + g_free (key_str); + return 1; + } + if (parser->last_read_char != ':') + { + event->type = GVM_JSON_PULL_EVENT_ERROR; + event->error_message = g_strdup_printf ("expected colon, got '%c'", parser->last_read_char); + g_free (key_str); + return 1; + } + gvm_json_pull_parser_next_char (parser); + + path_elem = g_queue_peek_tail (parser->path); + g_free (path_elem->key); + path_elem->key = key_str; + parser->expect = GVM_JSON_PULL_EXPECT_VALUE; + + break; + case '}': + path_elem = g_queue_peek_tail (parser->path); + if (path_elem == NULL + || path_elem->parent_type != GVM_JSON_PULL_CONTAINER_OBJECT) + { + event->type = GVM_JSON_PULL_EVENT_ERROR; + event->error_message = g_strdup ("unexpected closing curly brace"); + return 1; + } + event->type = GVM_JSON_PULL_EVENT_OBJECT_END; + event->value = NULL; + gvm_json_pull_path_elem_free (g_queue_pop_tail (parser->path)); + PARSE_VALUE_NEXT_EXPECT + gvm_json_pull_parser_next_char (parser); + break; + } + + return 0; +} + +/** + * @brief Handles the case that a comma is expected in a JSON pull parser. + * + * This will continue the parsing until a comma or the end of the + * current array/object was reached or an error occurred. + * + * @param[in] parser Parser to process + * @param[in] event Event data to set error or end of object status in + * + * @return 1 if an error occurred, 0 otherwise + */ +static int +gvm_json_pull_parse_comma (gvm_json_pull_parser_t *parser, + gvm_json_pull_event_t *event) +{ + if (gvm_json_pull_skip_space (parser, event, FALSE)) + return 1; + + gvm_json_path_elem_t *path_elem = NULL; + switch (parser->last_read_char) + { + case ',': + path_elem = g_queue_peek_tail (parser->path); + path_elem->index ++; + if (path_elem->parent_type == GVM_JSON_PULL_CONTAINER_OBJECT) + parser->expect = GVM_JSON_PULL_EXPECT_KEY; + else + parser->expect = GVM_JSON_PULL_EXPECT_VALUE; + gvm_json_pull_parser_next_char (parser); + break; + case ']': + path_elem = g_queue_peek_tail (parser->path); + if (path_elem == NULL + || path_elem->parent_type != GVM_JSON_PULL_CONTAINER_ARRAY) + { + event->type = GVM_JSON_PULL_EVENT_ERROR; + event->error_message = g_strdup ("unexpected closing square bracket"); + return 1; + } + event->type = GVM_JSON_PULL_EVENT_ARRAY_END; + event->value = NULL; + gvm_json_pull_path_elem_free (g_queue_pop_tail (parser->path)); + PARSE_VALUE_NEXT_EXPECT + gvm_json_pull_parser_next_char (parser); + break; + case '}': + path_elem = g_queue_peek_tail (parser->path); + if (path_elem == NULL + || path_elem->parent_type != GVM_JSON_PULL_CONTAINER_OBJECT) + { + event->type = GVM_JSON_PULL_EVENT_ERROR; + event->error_message = g_strdup ("unexpected closing curly brace"); + return 1; + } + event->type = GVM_JSON_PULL_EVENT_OBJECT_END; + event->value = NULL; + gvm_json_pull_path_elem_free (g_queue_pop_tail (parser->path)); + PARSE_VALUE_NEXT_EXPECT + gvm_json_pull_parser_next_char (parser); + break; + default: + event->error_message = g_strdup ("expected comma or end of container"); + event->type = GVM_JSON_PULL_EVENT_ERROR; + return 1; + } + return 0; +} + +/** + * @brief Handles the case that a value in a JSON pull parser. + * + * This will continue the parsing until a value or the end of the + * current array/object was parsed or an error occurred. + * + * @param[in] parser Parser to process + * @param[in] event Event data to set error or end of object status in + * + * @return 1 if an error occurred, 0 otherwise + */ +static int +gvm_json_pull_parse_value (gvm_json_pull_parser_t *parser, + gvm_json_pull_event_t *event) +{ + if (gvm_json_pull_skip_space (parser, event, FALSE)) + return 1; + + cJSON *cjson_value = NULL; + gvm_json_path_elem_t *path_elem = NULL; + + switch (parser->last_read_char) + { + case '"': + if (gvm_json_pull_parse_string (parser, event, &cjson_value)) + return 1; + event->type = GVM_JSON_PULL_EVENT_STRING; + event->value = cjson_value; + PARSE_VALUE_NEXT_EXPECT + break; + case 'n': + if (gvm_json_pull_parse_keyword (parser, event, "null")) + return 1; + event->type = GVM_JSON_PULL_EVENT_NULL; + event->value = cJSON_CreateNull (); + PARSE_VALUE_NEXT_EXPECT + break; + case 'f': + if (gvm_json_pull_parse_keyword (parser, event, "false")) + return 1; + event->type = GVM_JSON_PULL_EVENT_BOOLEAN; + event->value = cJSON_CreateFalse (); + PARSE_VALUE_NEXT_EXPECT + break; + case 't': + if (gvm_json_pull_parse_keyword (parser, event, "true")) + return 1; + event->type = GVM_JSON_PULL_EVENT_BOOLEAN; + event->value = cJSON_CreateTrue (); + PARSE_VALUE_NEXT_EXPECT + break; + case '[': + event->type = GVM_JSON_PULL_EVENT_ARRAY_START; + event->value = NULL; + parser->path_add + = gvm_json_pull_path_elem_new (GVM_JSON_PULL_CONTAINER_ARRAY, + parser->path->length); + parser->expect = GVM_JSON_PULL_EXPECT_VALUE; + gvm_json_pull_parser_next_char (parser); + break; + case ']': + path_elem = g_queue_peek_tail (parser->path); + if (path_elem == NULL + || path_elem->parent_type != GVM_JSON_PULL_CONTAINER_ARRAY) + { + event->type = GVM_JSON_PULL_EVENT_ERROR; + event->error_message = g_strdup ("unexpected closing square bracket"); + return 1; + } + event->type = GVM_JSON_PULL_EVENT_ARRAY_END; + event->value = NULL; + gvm_json_pull_path_elem_free (g_queue_pop_tail (parser->path)); + PARSE_VALUE_NEXT_EXPECT + gvm_json_pull_parser_next_char (parser); + break; + case '{': + event->type = GVM_JSON_PULL_EVENT_OBJECT_START; + event->value = NULL; + parser->path_add + = gvm_json_pull_path_elem_new (GVM_JSON_PULL_CONTAINER_OBJECT, + parser->path->length); + parser->expect = GVM_JSON_PULL_EXPECT_KEY; + gvm_json_pull_parser_next_char (parser); + break; + case '}': + path_elem = g_queue_peek_tail (parser->path); + if (path_elem == NULL + || path_elem->parent_type != GVM_JSON_PULL_CONTAINER_OBJECT) + { + event->type = GVM_JSON_PULL_EVENT_ERROR; + event->error_message = g_strdup ("unexpected closing curly brace"); + return 1; + } + event->type = GVM_JSON_PULL_EVENT_OBJECT_END; + event->value = NULL; + gvm_json_pull_path_elem_free (g_queue_pop_tail (parser->path)); + PARSE_VALUE_NEXT_EXPECT + gvm_json_pull_parser_next_char (parser); + break; + default: + if (g_ascii_isdigit (parser->last_read_char) + || parser->last_read_char == '-') + { + if (gvm_json_pull_parse_number (parser, event, &cjson_value)) + return 1; + event->type = GVM_JSON_PULL_EVENT_NUMBER; + event->value = cjson_value; + PARSE_VALUE_NEXT_EXPECT + } + else + { + event->type = GVM_JSON_PULL_EVENT_ERROR; + event->error_message = g_strdup ("unexpected character"); + return 1; + } + } + return 0; +} + +/** + * @brief Get the next event from a JSON pull parser. + * + * Note: This invalidates previous event data like the cJSON value. + * + * @param[in] parser The JSON pull parser to process until the next event + * @param[in] event Structure to store event data in. + */ +void +gvm_json_pull_parser_next (gvm_json_pull_parser_t *parser, + gvm_json_pull_event_t *event) +{ + assert (parser); + assert (event); + + gvm_json_pull_event_reset (event); + if (parser->last_read_char == GVM_JSON_CHAR_UNDEFINED) + { + // Handle first read of the stream + if (gvm_json_pull_parser_next_char (parser) < 0) + { + gvm_json_pull_handle_read_end (parser, event, TRUE); + return; + } + } + event->path = parser->path; + + // Delayed addition to path after a container start element + if (parser->path_add) + { + g_queue_push_tail (parser->path, parser->path_add); + parser->path_add = NULL; + } + + // Check for expected end of file + if (parser->expect == GVM_JSON_PULL_EXPECT_EOF) + { + if (gvm_json_pull_skip_space (parser, event, TRUE) == GVM_JSON_CHAR_ERROR) + return; + + if (parser->last_read_char != GVM_JSON_CHAR_EOF) + { + event->type = GVM_JSON_PULL_EVENT_ERROR; + event->error_message + = g_strdup_printf ("unexpected character at end of file (%d)", + parser->last_read_char); + return; + } + return; + } + + if (parser->expect == GVM_JSON_PULL_EXPECT_KEY) + { + if (gvm_json_pull_parse_key (parser, event)) + return; + } + + if (parser->expect == GVM_JSON_PULL_EXPECT_COMMA) + { + if (gvm_json_pull_parse_comma (parser, event)) + return; + } + + if (parser->expect == GVM_JSON_PULL_EXPECT_KEY) + { + if (gvm_json_pull_parse_key (parser, event)) + return; + } + + if (parser->expect == GVM_JSON_PULL_EXPECT_VALUE) + { + gvm_json_pull_parse_value (parser, event); + } +} + +/** + * @brief Expands the current array or object of a JSON pull parser. + * + * This should be called after an array or object start event. + * + * @param[in] parser Parser to get the current container element from + * @param[out] error_message Error message output + * + * @return The expanded container as a cJSON object if successful, else NULL + */ +cJSON * +gvm_json_pull_expand_container (gvm_json_pull_parser_t *parser, + gchar **error_message) +{ + gvm_json_path_elem_t *path_tail; + + int start_depth; + gboolean in_string, escape_next_char, in_expanded_container; + cJSON *expanded; + + g_string_truncate (parser->parse_buffer, 0); + + if (error_message) + *error_message = NULL; + + if (parser->path_add) + { + path_tail = parser->path_add; + g_queue_push_tail (parser->path, path_tail); + parser->path_add = NULL; + } + else + path_tail = g_queue_peek_tail (parser->path); + + if (path_tail + && path_tail->parent_type == GVM_JSON_PULL_CONTAINER_ARRAY) + g_string_append_c (parser->parse_buffer, '['); + else if (path_tail + && path_tail->parent_type == GVM_JSON_PULL_CONTAINER_OBJECT) + g_string_append_c (parser->parse_buffer, '{'); + else + { + if (error_message) + *error_message + = g_strdup ("can only expand after array or object start"); + return NULL; + } + + start_depth = path_tail->depth; + in_string = escape_next_char = FALSE; + in_expanded_container = TRUE; + + while (parser->last_read_char >= 0 && in_expanded_container) + { + if (parser->parse_buffer->len >= parser->parse_buffer_limit) + { + if (error_message) + *error_message + = g_strdup_printf ("container exceeds size limit of %zu bytes", + parser->parse_buffer_limit); + return NULL; + } + + g_string_append_c (parser->parse_buffer, parser->last_read_char); + + if (escape_next_char) + { + escape_next_char = FALSE; + } + else if (in_string) + { + escape_next_char = (parser->last_read_char == '\\'); + in_string = (parser->last_read_char != '"'); + } + else + { + switch (parser->last_read_char) + { + case '"': + in_string = TRUE; + break; + case '[': + path_tail + = gvm_json_pull_path_elem_new (GVM_JSON_PULL_CONTAINER_ARRAY, + parser->path->length); + g_queue_push_tail (parser->path, path_tail); + break; + case '{': + path_tail + = gvm_json_pull_path_elem_new (GVM_JSON_PULL_CONTAINER_OBJECT, + parser->path->length); + g_queue_push_tail (parser->path, path_tail); + break; + case ']': + path_tail = g_queue_pop_tail (parser->path); + if (path_tail->parent_type != GVM_JSON_PULL_CONTAINER_ARRAY) + { + if (error_message) + *error_message = g_strdup ("unexpected ']'"); + return NULL; + } + if (path_tail->depth == start_depth) + in_expanded_container = FALSE; + break; + case '}': + path_tail = g_queue_pop_tail (parser->path); + if (path_tail->parent_type != GVM_JSON_PULL_CONTAINER_OBJECT) + { + if (error_message) + *error_message = g_strdup ("unexpected '}'"); + return NULL; + } + if (path_tail->depth == start_depth) + in_expanded_container = FALSE; + break; + } + } + gvm_json_pull_parser_next_char (parser); + } + + if (parser->last_read_char == GVM_JSON_CHAR_ERROR) + { + if (error_message) + *error_message = gvm_json_read_stream_error_str (); + return NULL; + } + else if (in_expanded_container && parser->last_read_char == GVM_JSON_CHAR_EOF) + { + if (error_message) + *error_message = g_strdup ("unexpected EOF"); + return NULL; + } + + expanded = cJSON_Parse (parser->parse_buffer->str); + g_string_truncate (parser->parse_buffer, 0); + PARSE_VALUE_NEXT_EXPECT + + if (expanded == NULL && error_message) + *error_message = g_strdup ("could not parse expanded container"); + + return expanded; +} + +/** + * @brief Appends a string path element to a JSONPath string. + * + * @param[in] path_elem The path element to append + * @param[in] path_string The path string to append to + */ +static void +gvm_json_path_string_add_elem (gvm_json_path_elem_t *path_elem, + GString *path_string) +{ + if (path_elem->parent_type == GVM_JSON_PULL_CONTAINER_OBJECT) + { + char *point = path_elem->key; + g_string_append (path_string, "['"); + while (point && *point) + { + if (*point == '\\' || *point == '\'') + g_string_append_c (path_string, '\\'); + g_string_append_c (path_string, *point); + point ++; + } + g_string_append (path_string, "']"); + } + else + g_string_append_printf (path_string, "[%d]", path_elem->index); +} + +/** + * @brief Converts a path as used by a JSON pull parser to a JSONPath string. + * + * @param[in] path The path to convert + * + * @return Newly allocated string of the path in JSONPath bracket notation + */ +gchar * +gvm_json_path_to_string (GQueue *path) +{ + GString *path_string = g_string_new ("$"); + g_queue_foreach (path, + (GFunc) gvm_json_path_string_add_elem, + path_string); + return g_string_free (path_string, FALSE); +} + +#undef CASE_SPACES +#undef GVM_JSON_EOF +#undef GVM_JSON_ERROR \ No newline at end of file diff --git a/util/jsonpull.h b/util/jsonpull.h new file mode 100644 index 00000000..82850f2f --- /dev/null +++ b/util/jsonpull.h @@ -0,0 +1,129 @@ +/* SPDX-FileCopyrightText: 2024 Greenbone AG + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + + +#ifndef _GVM_JSONPULL_H +#define _GVM_JSONPULL_H + +#include +#include +#include + +/** + * @brief Type of container the parser is currently in + */ +typedef enum { + GVM_JSON_PULL_CONTAINER_NONE = 0, ///< No container / document root + GVM_JSON_PULL_CONTAINER_ARRAY, ///< Array + GVM_JSON_PULL_CONTAINER_OBJECT, ///< Object +} gvm_json_pull_container_type_t; + +/** + * @brief Path element types for the JSON pull parser. + */ +typedef struct gvm_json_path_elem { + gvm_json_pull_container_type_t parent_type; ///< parent container type + int index; ///< Index of the element within the parent + char *key; ///< Key if element is in an object + int depth; ///< Number of ancestor elements +} gvm_json_path_elem_t; + +/** + * @brief Event types for the JSON pull parser + */ +typedef enum { + GVM_JSON_PULL_EVENT_UNDEFINED = 0, + GVM_JSON_PULL_EVENT_ARRAY_START, + GVM_JSON_PULL_EVENT_ARRAY_END, + GVM_JSON_PULL_EVENT_OBJECT_START, + GVM_JSON_PULL_EVENT_OBJECT_END, + GVM_JSON_PULL_EVENT_STRING, + GVM_JSON_PULL_EVENT_NUMBER, + GVM_JSON_PULL_EVENT_BOOLEAN, + GVM_JSON_PULL_EVENT_NULL, + GVM_JSON_PULL_EVENT_EOF, + GVM_JSON_PULL_EVENT_ERROR, +} gvm_json_pull_event_type_t; + +/** + * @brief Event generated by the JSON pull parser. + */ +typedef struct { + gvm_json_pull_event_type_t type; ///< Type of event + GQueue *path; ///< Path to the event value + cJSON *value; ///< Value for non-container value events + gchar *error_message; ///< Error message, NULL on success +} gvm_json_pull_event_t; + +/** + * @brief Expected token state for the JSON pull parser + */ +typedef enum { + GVM_JSON_PULL_EXPECT_UNDEFINED = 0, ///< Undefined state + GVM_JSON_PULL_EXPECT_VALUE, ///< Expect start of a value + GVM_JSON_PULL_EXPECT_KEY, ///< Expect start of a key + GVM_JSON_PULL_EXPECT_COMMA, ///< Expect comma or container end brace + GVM_JSON_PULL_EXPECT_EOF ///< Expect end of file +} gvm_json_pull_expect_t; + +#define GVM_JSON_PULL_PARSE_BUFFER_LIMIT 10485760 + +#define GVM_JSON_PULL_READ_BUFFER_SIZE 4096 + +/** + * @brief A json pull parser + */ +typedef struct { + GQueue *path; ///< Path to the current value + gvm_json_path_elem_t *path_add; ///< Path elem to add in next step + gvm_json_pull_expect_t expect; ///< Current expected token + int keyword_pos; ///< Position in a keyword like "true" or "null" + FILE *input_stream; ///< Input stream + char *read_buffer; ///< Stream reading buffer + size_t read_buffer_size; ///< Size of the stream reading buffer + size_t last_read_size; ///< Size of last stream read + int last_read_char; ///< Character last read from stream + size_t read_pos; ///< Position in current read + GString *parse_buffer; ///< Buffer for parsing values and object keys + size_t parse_buffer_limit; ///< Maximum parse buffer size +} gvm_json_pull_parser_t; + +gvm_json_path_elem_t * +gvm_json_pull_path_elem_new (gvm_json_pull_container_type_t, int); + +void +gvm_json_pull_path_elem_free (gvm_json_path_elem_t *); + +void +gvm_json_pull_event_init (gvm_json_pull_event_t *); + +void +gvm_json_pull_event_reset (gvm_json_pull_event_t *); + +void +gvm_json_pull_event_cleanup (gvm_json_pull_event_t *); + +void +gvm_json_pull_parser_init_full (gvm_json_pull_parser_t *, FILE *, + size_t, size_t); + +void +gvm_json_pull_parser_init (gvm_json_pull_parser_t *, FILE *); + +void +gvm_json_pull_parser_cleanup (gvm_json_pull_parser_t *); + +void gvm_json_pull_parser_next(gvm_json_pull_parser_t*, + gvm_json_pull_event_t*); + +cJSON * +gvm_json_pull_expand_container (gvm_json_pull_parser_t *, + gchar **); + +gchar * +gvm_json_path_to_string (GQueue *path); + + +#endif /* _GVM_JSONPULL_H */ \ No newline at end of file diff --git a/util/jsonpull_tests.c b/util/jsonpull_tests.c new file mode 100644 index 00000000..edf1290e --- /dev/null +++ b/util/jsonpull_tests.c @@ -0,0 +1,505 @@ +/* SPDX-FileCopyrightText: 2019-2023 Greenbone AG + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "jsonpull.c" + +#include +#include + +Describe (jsonpull); +BeforeEach (jsonpull) +{ +} +AfterEach (jsonpull) +{ +} + + +/* + * Helper function to open a string as a read-only stream. + */ +static inline FILE * +fstropen_r (const char *str) +{ + return fmemopen ((void*)str, strlen(str), "r"); +} + +#define INIT_JSON_PARSER(json_string) \ + gvm_json_pull_event_t event; \ + gvm_json_pull_parser_t parser; \ + FILE *jsonstream; \ + jsonstream = fstropen_r (json_string); \ + gvm_json_pull_event_init (&event); \ + gvm_json_pull_parser_init_full (&parser, jsonstream, 0, 4); + +#define CLEANUP_JSON_PARSER \ + gvm_json_pull_event_cleanup (&event); \ + gvm_json_pull_parser_cleanup (&parser); \ + fclose (jsonstream); \ + +#define CHECK_PATH_EQUALS(expected_path_str) \ + path_str = gvm_json_path_to_string (event.path); \ + assert_that (path_str, is_equal_to_string (expected_path_str)); \ + g_free (path_str); + +Ensure (jsonpull, can_parse_false) +{ + INIT_JSON_PARSER ("false"); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_BOOLEAN)); + assert_that (cJSON_IsBool (event.value), is_true); + assert_that (cJSON_IsFalse (event.value), is_true); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_EOF)); + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, can_parse_true) +{ + INIT_JSON_PARSER ("true"); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_BOOLEAN)); + assert_that (cJSON_IsBool (event.value), is_true); + assert_that (cJSON_IsTrue (event.value), is_true); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_EOF)); + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, can_parse_null) +{ + INIT_JSON_PARSER ("null"); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_NULL)); + assert_that (cJSON_IsNull (event.value), is_true); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_EOF)); + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, can_parse_empty_strings) +{ + INIT_JSON_PARSER ("\"\"") + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_STRING)); + assert_that (event.value->valuestring, is_equal_to_string ("")); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_EOF)); + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, can_parse_strings_with_content) +{ + INIT_JSON_PARSER ("\n\"123\\tXYZ\\nÄöü\"\n") + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_STRING)); + assert_that (event.value->valuestring, + is_equal_to_string ("123\tXYZ\nÄöü")); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_EOF)); + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, can_parse_integer_numbers) +{ + INIT_JSON_PARSER ("-0987") + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_NUMBER)); + assert_that (event.value->valueint, is_equal_to (-987)); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_EOF)); + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, can_parse_floating_point_numbers) +{ + INIT_JSON_PARSER ("\t\n 1.2345e+4\n"); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_NUMBER)); + assert_that (event.value->valuedouble, is_equal_to (1.2345e+4)); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_EOF)); + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, can_parse_empty_arrays) +{ + INIT_JSON_PARSER ("[ ]"); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_START)); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_END)); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_EOF)); + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, can_parse_single_elem_arrays) +{ + gchar *path_str; + INIT_JSON_PARSER ("[ 123 ]"); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_START)); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_NUMBER)); + assert_that (event.value->valueint, is_equal_to (123)); + CHECK_PATH_EQUALS ("$[0]") + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_END)); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_EOF)); + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, can_parse_multiple_elem_arrays) +{ + gchar *path_str; + INIT_JSON_PARSER ("[123, \"ABC\", null]"); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_START)); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_NUMBER)); + assert_that (event.value->valueint, is_equal_to (123)); + CHECK_PATH_EQUALS ("$[0]") + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_STRING)); + assert_that (event.value->valuestring, is_equal_to_string ("ABC")); + CHECK_PATH_EQUALS ("$[1]") + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_NULL)); + CHECK_PATH_EQUALS ("$[2]") + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_END)); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_EOF)); + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, can_parse_empty_objects) +{ + INIT_JSON_PARSER ("{ }"); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_OBJECT_START)); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_OBJECT_END)); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_EOF)); + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, can_parse_single_elem_objects) +{ + gchar *path_str; + INIT_JSON_PARSER ("{ \"keyA\": \"valueA\" }"); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_OBJECT_START)); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_STRING)); + assert_that (event.value->valuestring, is_equal_to_string ("valueA")); + CHECK_PATH_EQUALS ("$['keyA']") + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_OBJECT_END)); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_EOF)); + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, can_parse_multiple_elem_objects) +{ + gchar *path_str; + INIT_JSON_PARSER ("{ \"keyA\": \"valueA\", \"keyB\":12345 }"); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_OBJECT_START)); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_STRING)); + assert_that (event.value->valuestring, is_equal_to_string ("valueA")); + CHECK_PATH_EQUALS ("$['keyA']") + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_NUMBER)); + assert_that (event.value->valueint, is_equal_to (12345)); + CHECK_PATH_EQUALS ("$['keyB']") + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_OBJECT_END)); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_EOF)); + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, can_parse_nested_containers) +{ + gchar *path_str; + INIT_JSON_PARSER ("[{\"A\":null, \"B\":{\"C\": [1,2]}, \"D\":\"3\"}, [4]]"); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_START)); + CHECK_PATH_EQUALS ("$") + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_OBJECT_START)); + CHECK_PATH_EQUALS ("$[0]") + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_NULL)); + CHECK_PATH_EQUALS ("$[0]['A']") + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_OBJECT_START)); + CHECK_PATH_EQUALS ("$[0]['B']") + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_START)); + CHECK_PATH_EQUALS ("$[0]['B']['C']") + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_NUMBER)); + assert_that (event.value->valueint, is_equal_to (1)); + CHECK_PATH_EQUALS ("$[0]['B']['C'][0]") + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_NUMBER)); + assert_that (event.value->valueint, is_equal_to (2)); + CHECK_PATH_EQUALS ("$[0]['B']['C'][1]") + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_END)); + CHECK_PATH_EQUALS ("$[0]['B']['C']") + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_OBJECT_END)); + CHECK_PATH_EQUALS ("$[0]['B']") + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_STRING)); + assert_that (event.value->valuestring, is_equal_to_string ("3")); + CHECK_PATH_EQUALS ("$[0]['D']") + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_OBJECT_END)); + CHECK_PATH_EQUALS ("$[0]") + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_START)); + CHECK_PATH_EQUALS ("$[1]") + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_NUMBER)); + assert_that (event.value->valueint, is_equal_to (4)); + CHECK_PATH_EQUALS ("$[1][0]") + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_END)); + CHECK_PATH_EQUALS ("$[1]") + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_END)); + CHECK_PATH_EQUALS ("$") + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_EOF)); + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, can_expand_arrays) +{ + gchar *path_str, *error_message; + cJSON *expanded, *child; + INIT_JSON_PARSER ("[[], [1], [2, [3]], [\"A\", \"\\\"B]\"]]"); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_START)); + CHECK_PATH_EQUALS ("$") + + // empty array + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_START)); + CHECK_PATH_EQUALS ("$[0]") + expanded = gvm_json_pull_expand_container (&parser, &error_message); + assert_that (error_message, is_equal_to_string (NULL)); + assert_that (expanded, is_not_null); + assert_that (cJSON_IsArray (expanded), is_true); + assert_that (expanded->child, is_null); + cJSON_free (expanded); + + // single-element array + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_START)); + CHECK_PATH_EQUALS ("$[1]") + expanded = gvm_json_pull_expand_container (&parser, &error_message); + assert_that (error_message, is_null); + assert_that (expanded, is_not_null); + assert_that (cJSON_IsArray (expanded), is_true); + child = expanded->child; + assert_that (child, is_not_null); + assert_that (cJSON_IsNumber(child), is_true); + assert_that (child->valueint, is_equal_to(1)); + child = child->next; + assert_that (child, is_null); + cJSON_free (expanded); + + // multi-element array + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_START)); + CHECK_PATH_EQUALS ("$[2]") + expanded = gvm_json_pull_expand_container (&parser, &error_message); + assert_that (error_message, is_null); + assert_that (expanded, is_not_null); + assert_that (cJSON_IsArray (expanded), is_true); + child = expanded->child; + assert_that (child, is_not_null); + assert_that (cJSON_IsNumber(child), is_true); + assert_that (child->valueint, is_equal_to(2)); + child = child->next; + assert_that (child, is_not_null); + assert_that (cJSON_IsArray(child), is_true); + assert_that (child->child->valueint, is_equal_to(3)); + cJSON_free (expanded); + + // string array + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_START)); + CHECK_PATH_EQUALS ("$[3]") + expanded = gvm_json_pull_expand_container (&parser, &error_message); + assert_that (error_message, is_null); + assert_that (expanded, is_not_null); + assert_that (cJSON_IsArray (expanded), is_true); + child = expanded->child; + assert_that (child, is_not_null); + assert_that (cJSON_IsString(child), is_true); + assert_that (child->valuestring, is_equal_to_string("A")); + child = child->next; + assert_that (child, is_not_null); + assert_that (cJSON_IsString(child), is_true); + assert_that (child->valuestring, is_equal_to_string("\"B]")); + cJSON_free (expanded); + + // array end and EOF + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_END)); + CHECK_PATH_EQUALS ("$") + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_EOF)); + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, can_expand_objects) +{ + gchar *path_str, *error_message; + cJSON *expanded, *child; + INIT_JSON_PARSER ("{\"A\":{}, \"B\": {\"C\": \"\\\"D}\", \"E\":123}}"); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_OBJECT_START)); + CHECK_PATH_EQUALS ("$") + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_OBJECT_START)); + CHECK_PATH_EQUALS ("$['A']") + expanded = gvm_json_pull_expand_container (&parser, &error_message); + assert_that (error_message, is_null); + assert_that (cJSON_IsObject (expanded), is_true); + assert_that (expanded->child, is_null); + cJSON_free (expanded); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_OBJECT_START)); + CHECK_PATH_EQUALS ("$['B']") + expanded = gvm_json_pull_expand_container (&parser, &error_message); + assert_that (error_message, is_null); + assert_that (cJSON_IsObject (expanded), is_true); + child = expanded->child; + assert_that (child, is_not_null); + assert_that (cJSON_IsString(child), is_true); + assert_that (child->string, is_equal_to_string ("C")); + assert_that (child->valuestring, is_equal_to_string ("\"D}")); + child = child->next; + assert_that (child, is_not_null); + assert_that (cJSON_IsNumber(child), is_true); + assert_that (child->string, is_equal_to_string ("E")); + assert_that (child->valueint, is_equal_to (123)); + cJSON_free (expanded); + + // object end and EOF + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_OBJECT_END)); + CHECK_PATH_EQUALS ("$") + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_EOF)); + CLEANUP_JSON_PARSER +} + + +int +main (int argc, char **argv) +{ + TestSuite *suite; + + suite = create_test_suite (); + + add_test_with_context (suite, jsonpull, can_parse_false); + add_test_with_context (suite, jsonpull, can_parse_true); + add_test_with_context (suite, jsonpull, can_parse_null); + + add_test_with_context (suite, jsonpull, can_parse_empty_strings); + add_test_with_context (suite, jsonpull, can_parse_strings_with_content); + + add_test_with_context (suite, jsonpull, can_parse_integer_numbers); + add_test_with_context (suite, jsonpull, can_parse_floating_point_numbers); + + add_test_with_context (suite, jsonpull, can_parse_empty_arrays); + add_test_with_context (suite, jsonpull, can_parse_single_elem_arrays); + add_test_with_context (suite, jsonpull, can_parse_multiple_elem_arrays); + + add_test_with_context (suite, jsonpull, can_parse_empty_objects); + add_test_with_context (suite, jsonpull, can_parse_single_elem_objects); + add_test_with_context (suite, jsonpull, can_parse_multiple_elem_objects); + add_test_with_context (suite, jsonpull, can_parse_nested_containers); + add_test_with_context (suite, jsonpull, can_expand_arrays); + add_test_with_context (suite, jsonpull, can_expand_objects); + + if (argc > 1) + return run_single_test (suite, argv[1], create_text_reporter ()); + return run_test_suite (suite, create_text_reporter ()); +} \ No newline at end of file From 4d5435eac6596e10217afc4d33c1312ae3fcbaf6 Mon Sep 17 00:00:00 2001 From: Timo Pollmeier Date: Wed, 31 Jul 2024 13:49:30 +0200 Subject: [PATCH 05/29] Add JSON string escaping, improve parser tests The function gvm_json_string_escape is added and used for escaping JSON paths. Some adjustments are made to the parser tests to improve coverage. --- util/jsonpull.c | 66 ++++++++++++++++++++++++++++++++++++------- util/jsonpull.h | 3 ++ util/jsonpull_tests.c | 48 +++++++++++++++++++++++++++++-- 3 files changed, 104 insertions(+), 13 deletions(-) diff --git a/util/jsonpull.c b/util/jsonpull.c index a138db25..6fb3e531 100644 --- a/util/jsonpull.c +++ b/util/jsonpull.c @@ -10,6 +10,59 @@ #define GVM_JSON_CHAR_ERROR -2 ///< Error reading file #define GVM_JSON_CHAR_UNDEFINED -3 ///< Undefined state +/** + * @brief Escapes a string according to the JSON or JSONPath standard + */ +gchar * +gvm_json_string_escape (const char *string, gboolean single_quote) +{ + gchar *point; + if (string == NULL) + return NULL; + + GString *escaped = g_string_sized_new (strlen (string)); + for (point = (char*)string; *point != 0; point++) + { + unsigned char character = *point;; + if ((character > 31) && (character != '\\') + && (single_quote || character != '\"') + && (!single_quote || character != '\'')) + { + g_string_append_c (escaped, character); + } + else + { + g_string_append_c (escaped, '\\'); + switch (*point) + { + case '\\': + case '\'': + case '\"': + g_string_append_c (escaped, *point); + break; + case '\b': + g_string_append_c (escaped, 'b'); + break; + case '\f': + g_string_append_c (escaped, 'f'); + break; + case '\n': + g_string_append_c (escaped, 'n'); + break; + case '\r': + g_string_append_c (escaped, 'r'); + break; + case '\t': + g_string_append_c (escaped, 't'); + break; + default: + g_string_append_printf (escaped, "u%04x", character); + } + } + } + return g_string_free (escaped, FALSE); +} + /** * @brief Creates a new JSON path element. * @@ -917,16 +970,9 @@ gvm_json_path_string_add_elem (gvm_json_path_elem_t *path_elem, { if (path_elem->parent_type == GVM_JSON_PULL_CONTAINER_OBJECT) { - char *point = path_elem->key; - g_string_append (path_string, "['"); - while (point && *point) - { - if (*point == '\\' || *point == '\'') - g_string_append_c (path_string, '\\'); - g_string_append_c (path_string, *point); - point ++; - } - g_string_append (path_string, "']"); + gchar *escaped_key = gvm_json_string_escape (path_elem->key, TRUE); + g_string_append_printf (path_string, "['%s']", escaped_key); + g_free (escaped_key); } else g_string_append_printf (path_string, "[%d]", path_elem->index); diff --git a/util/jsonpull.h b/util/jsonpull.h index 82850f2f..0e992adc 100644 --- a/util/jsonpull.h +++ b/util/jsonpull.h @@ -90,6 +90,9 @@ typedef struct { size_t parse_buffer_limit; ///< Maximum parse buffer size } gvm_json_pull_parser_t; +gchar * +gvm_json_string_escape (const char *, gboolean); + gvm_json_path_elem_t * gvm_json_pull_path_elem_new (gvm_json_pull_container_type_t, int); diff --git a/util/jsonpull_tests.c b/util/jsonpull_tests.c index edf1290e..e0b57d01 100644 --- a/util/jsonpull_tests.c +++ b/util/jsonpull_tests.c @@ -32,7 +32,7 @@ fstropen_r (const char *str) FILE *jsonstream; \ jsonstream = fstropen_r (json_string); \ gvm_json_pull_event_init (&event); \ - gvm_json_pull_parser_init_full (&parser, jsonstream, 0, 4); + gvm_json_pull_parser_init_full (&parser, jsonstream, 100, 4); #define CLEANUP_JSON_PARSER \ gvm_json_pull_event_cleanup (&event); \ @@ -44,6 +44,38 @@ fstropen_r (const char *str) assert_that (path_str, is_equal_to_string (expected_path_str)); \ g_free (path_str); +Ensure (jsonpull, can_json_escape_strings) +{ + const char *unescaped_string = "\"'Abc\\\b\f\n\r\t\001Äöü'\""; + const char *escaped_string_dq = "\\\"'Abc\\\\\\b\\f\\n\\r\\t\\u0001Äöü'\\\""; + const char *escaped_string_sq = "\"\\'Abc\\\\\\b\\f\\n\\r\\t\\u0001Äöü\\'\""; + + gchar *escaped_string = NULL; + escaped_string = gvm_json_string_escape (NULL, FALSE); + assert_that (escaped_string, is_null); + + escaped_string = gvm_json_string_escape (unescaped_string, FALSE); + assert_that (escaped_string, is_equal_to_string (escaped_string_dq)); + g_free (escaped_string); + + escaped_string = gvm_json_string_escape (unescaped_string, TRUE); + assert_that (escaped_string, is_equal_to_string (escaped_string_sq)); + g_free (escaped_string); +} + +Ensure (jsonpull, can_init_parser_with_defaults) +{ + gvm_json_pull_parser_t parser; + FILE *strfile = fstropen_r ("[]"); + + gvm_json_pull_parser_init (&parser, strfile); + assert_that (parser.input_stream, is_equal_to (strfile)); + assert_that (parser.parse_buffer_limit, + is_equal_to (GVM_JSON_PULL_PARSE_BUFFER_LIMIT)); + assert_that (parser.read_buffer_size, + is_equal_to (GVM_JSON_PULL_READ_BUFFER_SIZE)); +} + Ensure (jsonpull, can_parse_false) { INIT_JSON_PARSER ("false"); @@ -427,7 +459,8 @@ Ensure (jsonpull, can_expand_objects) { gchar *path_str, *error_message; cJSON *expanded, *child; - INIT_JSON_PARSER ("{\"A\":{}, \"B\": {\"C\": \"\\\"D}\", \"E\":123}}"); + INIT_JSON_PARSER ( + "{\"A\":{}, \"B\": {\"C\": \"\\\"D}\", \"E\":123, \"F\":{}}}"); gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_OBJECT_START)); @@ -458,6 +491,11 @@ Ensure (jsonpull, can_expand_objects) assert_that (cJSON_IsNumber(child), is_true); assert_that (child->string, is_equal_to_string ("E")); assert_that (child->valueint, is_equal_to (123)); + child = child->next; + assert_that (child, is_not_null); + assert_that (cJSON_IsObject(child), is_true); + assert_that (child->string, is_equal_to_string ("F")); + assert_that (child->child, is_null); cJSON_free (expanded); // object end and EOF @@ -478,6 +516,10 @@ main (int argc, char **argv) suite = create_test_suite (); + add_test_with_context (suite, jsonpull, can_json_escape_strings); + + add_test_with_context (suite, jsonpull, can_init_parser_with_defaults); + add_test_with_context (suite, jsonpull, can_parse_false); add_test_with_context (suite, jsonpull, can_parse_true); add_test_with_context (suite, jsonpull, can_parse_null); @@ -498,7 +540,7 @@ main (int argc, char **argv) add_test_with_context (suite, jsonpull, can_parse_nested_containers); add_test_with_context (suite, jsonpull, can_expand_arrays); add_test_with_context (suite, jsonpull, can_expand_objects); - + if (argc > 1) return run_single_test (suite, argv[1], create_text_reporter ()); return run_test_suite (suite, create_text_reporter ()); From 093fd05d960b0b1aee6bacdd8c7fde3402449b96 Mon Sep 17 00:00:00 2001 From: Timo Pollmeier Date: Thu, 1 Aug 2024 12:46:56 +0200 Subject: [PATCH 06/29] Improve JSON pull error handling, add error tests The handling of some error cases for the JSON pull parser has been fixed and error messages are now more consistent. Tests to check the error handling of the parser have been added. --- util/jsonpull.c | 57 ++-- util/jsonpull.h | 2 + util/jsonpull_tests.c | 699 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 727 insertions(+), 31 deletions(-) diff --git a/util/jsonpull.c b/util/jsonpull.c index 6fb3e531..99aa23bd 100644 --- a/util/jsonpull.c +++ b/util/jsonpull.c @@ -521,7 +521,7 @@ gvm_json_pull_parse_key (gvm_json_pull_parser_t *parser, if (parser->last_read_char != ':') { event->type = GVM_JSON_PULL_EVENT_ERROR; - event->error_message = g_strdup_printf ("expected colon, got '%c'", parser->last_read_char); + event->error_message = g_strdup_printf ("expected colon"); g_free (key_str); return 1; } @@ -534,20 +534,20 @@ gvm_json_pull_parse_key (gvm_json_pull_parser_t *parser, break; case '}': - path_elem = g_queue_peek_tail (parser->path); - if (path_elem == NULL - || path_elem->parent_type != GVM_JSON_PULL_CONTAINER_OBJECT) - { - event->type = GVM_JSON_PULL_EVENT_ERROR; - event->error_message = g_strdup ("unexpected closing curly brace"); - return 1; - } event->type = GVM_JSON_PULL_EVENT_OBJECT_END; event->value = NULL; gvm_json_pull_path_elem_free (g_queue_pop_tail (parser->path)); PARSE_VALUE_NEXT_EXPECT gvm_json_pull_parser_next_char (parser); break; + case ']': + event->type = GVM_JSON_PULL_EVENT_ERROR; + event->error_message = g_strdup ("unexpected closing square bracket"); + return 1; + default: + event->type = GVM_JSON_PULL_EVENT_ERROR; + event->error_message = g_strdup ("unexpected character"); + return 1; } return 0; @@ -706,19 +706,9 @@ gvm_json_pull_parse_value (gvm_json_pull_parser_t *parser, gvm_json_pull_parser_next_char (parser); break; case '}': - path_elem = g_queue_peek_tail (parser->path); - if (path_elem == NULL - || path_elem->parent_type != GVM_JSON_PULL_CONTAINER_OBJECT) - { - event->type = GVM_JSON_PULL_EVENT_ERROR; - event->error_message = g_strdup ("unexpected closing curly brace"); - return 1; - } - event->type = GVM_JSON_PULL_EVENT_OBJECT_END; - event->value = NULL; - gvm_json_pull_path_elem_free (g_queue_pop_tail (parser->path)); - PARSE_VALUE_NEXT_EXPECT - gvm_json_pull_parser_next_char (parser); + event->type = GVM_JSON_PULL_EVENT_ERROR; + event->error_message = g_strdup ("unexpected closing curly brace"); + return 1; break; default: if (g_ascii_isdigit (parser->last_read_char) @@ -777,10 +767,14 @@ gvm_json_pull_parser_next (gvm_json_pull_parser_t *parser, // Check for expected end of file if (parser->expect == GVM_JSON_PULL_EXPECT_EOF) { - if (gvm_json_pull_skip_space (parser, event, TRUE) == GVM_JSON_CHAR_ERROR) - return; + gvm_json_pull_skip_space (parser, event, TRUE); - if (parser->last_read_char != GVM_JSON_CHAR_EOF) + if (parser->last_read_char == GVM_JSON_CHAR_ERROR) + { + event->type = GVM_JSON_PULL_EVENT_ERROR; + event->error_message = gvm_json_read_stream_error_str (); + } + else if (parser->last_read_char != GVM_JSON_CHAR_EOF) { event->type = GVM_JSON_PULL_EVENT_ERROR; event->error_message @@ -829,7 +823,7 @@ cJSON * gvm_json_pull_expand_container (gvm_json_pull_parser_t *parser, gchar **error_message) { - gvm_json_path_elem_t *path_tail; + gvm_json_path_elem_t *path_tail = NULL; int start_depth; gboolean in_string, escape_next_char, in_expanded_container; @@ -840,14 +834,13 @@ gvm_json_pull_expand_container (gvm_json_pull_parser_t *parser, if (error_message) *error_message = NULL; + // require "path_add" to only allow expansion at start of container if (parser->path_add) { path_tail = parser->path_add; g_queue_push_tail (parser->path, path_tail); parser->path_add = NULL; } - else - path_tail = g_queue_peek_tail (parser->path); if (path_tail && path_tail->parent_type == GVM_JSON_PULL_CONTAINER_ARRAY) @@ -858,7 +851,7 @@ gvm_json_pull_expand_container (gvm_json_pull_parser_t *parser, else { if (error_message) - *error_message + *error_message = g_strdup ("can only expand after array or object start"); return NULL; } @@ -913,7 +906,8 @@ gvm_json_pull_expand_container (gvm_json_pull_parser_t *parser, if (path_tail->parent_type != GVM_JSON_PULL_CONTAINER_ARRAY) { if (error_message) - *error_message = g_strdup ("unexpected ']'"); + *error_message + = g_strdup ("unexpected closing square bracket"); return NULL; } if (path_tail->depth == start_depth) @@ -924,7 +918,8 @@ gvm_json_pull_expand_container (gvm_json_pull_parser_t *parser, if (path_tail->parent_type != GVM_JSON_PULL_CONTAINER_OBJECT) { if (error_message) - *error_message = g_strdup ("unexpected '}'"); + *error_message + = g_strdup ("unexpected closing curly brace"); return NULL; } if (path_tail->depth == start_depth) diff --git a/util/jsonpull.h b/util/jsonpull.h index 0e992adc..01e12aa1 100644 --- a/util/jsonpull.h +++ b/util/jsonpull.h @@ -7,6 +7,8 @@ #ifndef _GVM_JSONPULL_H #define _GVM_JSONPULL_H +#define _GNU_SOURCE + #include #include #include diff --git a/util/jsonpull_tests.c b/util/jsonpull_tests.c index e0b57d01..18056cd5 100644 --- a/util/jsonpull_tests.c +++ b/util/jsonpull_tests.c @@ -5,6 +5,7 @@ #include "jsonpull.c" +#include #include #include @@ -26,6 +27,21 @@ fstropen_r (const char *str) return fmemopen ((void*)str, strlen(str), "r"); } +static ssize_t +read_with_error_on_eof (void *stream_cookie, char *buf, size_t size) +{ + FILE *stream = stream_cookie; + ssize_t ret = fread (buf, 1, size, stream); + if (ret <= 0) + { + errno = EIO; + return -1; + } + else + return ret; +} + + #define INIT_JSON_PARSER(json_string) \ gvm_json_pull_event_t event; \ gvm_json_pull_parser_t parser; \ @@ -34,6 +50,20 @@ fstropen_r (const char *str) gvm_json_pull_event_init (&event); \ gvm_json_pull_parser_init_full (&parser, jsonstream, 100, 4); +#define INIT_READ_ERROR_JSON_PARSER(json_string) \ + gvm_json_pull_event_t event; \ + gvm_json_pull_parser_t parser; \ + FILE *jsonstream = fstropen_r (json_string); \ + cookie_io_functions_t io_functions = { \ + .read = read_with_error_on_eof, \ + .write = NULL, \ + .seek = NULL, \ + .close = NULL \ + }; \ + FILE *errorstream = fopencookie (jsonstream, "r", io_functions); \ + gvm_json_pull_event_init (&event); \ + gvm_json_pull_parser_init_full (&parser, errorstream, 100, 4); + #define CLEANUP_JSON_PARSER \ gvm_json_pull_event_cleanup (&event); \ gvm_json_pull_parser_cleanup (&parser); \ @@ -44,6 +74,9 @@ fstropen_r (const char *str) assert_that (path_str, is_equal_to_string (expected_path_str)); \ g_free (path_str); +#define JSON_READ_ERROR "error reading JSON stream: Input/output error" + + Ensure (jsonpull, can_json_escape_strings) { const char *unescaped_string = "\"'Abc\\\b\f\n\r\t\001Äöü'\""; @@ -508,6 +541,610 @@ Ensure (jsonpull, can_expand_objects) CLEANUP_JSON_PARSER } +Ensure (jsonpull, fails_for_read_error) +{ + INIT_READ_ERROR_JSON_PARSER ("123") + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); + assert_that (event.error_message, is_equal_to_string (JSON_READ_ERROR)); + gvm_json_pull_parser_cleanup (&parser); + gvm_json_pull_event_cleanup (&event); + fclose (jsonstream); +} + +Ensure (jsonpull, fails_for_misspelled_true) +{ + INIT_JSON_PARSER ("trxyz"); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); + assert_that (event.error_message, + is_equal_to_string ("misspelled keyword 'true'")); + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, fails_for_incomplete_true) +{ + INIT_JSON_PARSER ("tru"); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); + assert_that (event.error_message, + is_equal_to_string ("unexpected EOF")); + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, fails_for_misspelled_false) +{ + INIT_JSON_PARSER ("falxyz"); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); + assert_that (event.error_message, + is_equal_to_string ("misspelled keyword 'false'")); + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, fails_for_misspelled_null) +{ + INIT_JSON_PARSER ("nulx"); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); + assert_that (event.error_message, + is_equal_to_string ("misspelled keyword 'null'")); + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, fails_for_string_read_error) +{ + INIT_READ_ERROR_JSON_PARSER ("\"ABCDEFG\""); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); + assert_that (event.error_message, is_equal_to_string (JSON_READ_ERROR)); + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, fails_for_string_eof) +{ + INIT_JSON_PARSER ("\"no closing quote here"); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); + assert_that (event.error_message, + is_equal_to_string ("unexpected EOF")); + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, fails_for_overlong_string) +{ + INIT_JSON_PARSER ("\"This should be too long for a small parse buffer\""); + parser.parse_buffer_limit = 10; + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); + assert_that (event.error_message, + is_equal_to_string ("string exceeds size limit of 10 bytes")); + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, fails_for_invalid_string) +{ + INIT_JSON_PARSER ("\"This has an invalid escape sequence: \\x\""); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); + assert_that (event.error_message, + is_equal_to_string ("error parsing string")); + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, fails_for_number_read_error) +{ + INIT_READ_ERROR_JSON_PARSER ("12345.123456789"); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); + assert_that (event.error_message, is_equal_to_string (JSON_READ_ERROR)); + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, fails_for_overlong_number) +{ + INIT_READ_ERROR_JSON_PARSER ("12345.123456789"); + parser.parse_buffer_limit = 10; + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); + assert_that (event.error_message, + is_equal_to_string ("number exceeds size limit of 10 bytes")); + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, fails_for_invalid_number) +{ + INIT_JSON_PARSER ("-+e"); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); + assert_that (event.error_message, + is_equal_to_string ("error parsing number")); + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, fails_for_array_eof) +{ + INIT_JSON_PARSER ("["); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_START)); + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); + assert_that (event.error_message, + is_equal_to_string ("unexpected EOF")); + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, fails_for_array_eof_after_value) +{ + INIT_JSON_PARSER ("[123"); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_START)); + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_NUMBER)); + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); + assert_that (event.error_message, + is_equal_to_string ("unexpected EOF")); + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, fails_for_array_eof_after_comma) +{ + INIT_JSON_PARSER ("[123,"); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_START)); + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_NUMBER)); + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); + assert_that (event.error_message, + is_equal_to_string ("unexpected EOF")); + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, fails_for_array_read_error) +{ + INIT_READ_ERROR_JSON_PARSER ("[ "); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_START)); + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); + assert_that (event.error_message, is_equal_to_string (JSON_READ_ERROR)); + CLEANUP_JSON_PARSER +} + + +Ensure (jsonpull, fails_for_invalid_array_bracket) +{ + INIT_JSON_PARSER ("[}"); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_START)); + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); + assert_that (event.error_message, + is_equal_to_string ("unexpected closing curly brace")); + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, fails_for_invalid_array_bracket_after_value) +{ + INIT_JSON_PARSER ("[123}"); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_START)); + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_NUMBER)); + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); + assert_that (event.error_message, + is_equal_to_string ("unexpected closing curly brace")); + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, fails_for_invalid_array_other_char) +{ + INIT_JSON_PARSER ("[!"); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_START)); + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); + assert_that (event.error_message, + is_equal_to_string ("unexpected character")); + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, fails_for_invalid_array_other_char_after_value) +{ + INIT_JSON_PARSER ("[123!"); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_START)); + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_NUMBER)); + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); + assert_that (event.error_message, + is_equal_to_string ("expected comma or end of container")); + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, fails_for_object_key_eof) +{ + INIT_JSON_PARSER ("{"); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_OBJECT_START)); + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); + assert_that (event.error_message, + is_equal_to_string ("unexpected EOF")); + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, fails_for_object_key_read_error) +{ + INIT_READ_ERROR_JSON_PARSER ("{ "); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_OBJECT_START)); + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); + assert_that (event.error_message, is_equal_to_string (JSON_READ_ERROR)); + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, fails_for_object_key_invalid_string) +{ + INIT_JSON_PARSER ("{\"invalid escape:\\x\": 123}"); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_OBJECT_START)); + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); + assert_that (event.error_message, + is_equal_to_string ("error parsing string")); + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, fails_for_invalid_object_key_bracket) +{ + INIT_JSON_PARSER ("{]"); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_OBJECT_START)); + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); + assert_that (event.error_message, + is_equal_to_string ("unexpected closing square bracket")); + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, fails_for_invalid_object_key_other_char) +{ + INIT_JSON_PARSER ("{!"); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_OBJECT_START)); + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); + assert_that (event.error_message, + is_equal_to_string ("unexpected character")); + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, fails_for_object_colon_eof) +{ + INIT_JSON_PARSER ("{\"A\" "); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_OBJECT_START)); + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); + assert_that (event.error_message, + is_equal_to_string ("unexpected EOF")); + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, fails_for_object_colon_read_error) +{ + INIT_READ_ERROR_JSON_PARSER ("{\"A\" "); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_OBJECT_START)); + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); + assert_that (event.error_message, is_equal_to_string (JSON_READ_ERROR)); + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, fails_for_object_colon_other_char) +{ + INIT_JSON_PARSER ("{\"A\"!"); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_OBJECT_START)); + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); + assert_that (event.error_message, + is_equal_to_string ("expected colon")); + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, fails_for_object_value_eof) +{ + INIT_JSON_PARSER ("{\"A\": "); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_OBJECT_START)); + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); + assert_that (event.error_message, + is_equal_to_string ("unexpected EOF")); + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, fails_for_object_value_read_error) +{ + INIT_READ_ERROR_JSON_PARSER ("{\"A\": "); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_OBJECT_START)); + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); + assert_that (event.error_message, is_equal_to_string (JSON_READ_ERROR)); + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, fails_for_object_value_curly_brace) +{ + INIT_JSON_PARSER ("{\"A\": }"); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_OBJECT_START)); + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); + assert_that (event.error_message, + is_equal_to_string ("unexpected closing curly brace")); + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, fails_for_object_value_square_bracket) +{ + INIT_JSON_PARSER ("{\"A\": ]"); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_OBJECT_START)); + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); + assert_that (event.error_message, + is_equal_to_string ("unexpected closing square bracket")); + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, fails_for_object_eof_after_value) +{ + INIT_JSON_PARSER ("{\"A\": 123"); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_OBJECT_START)); + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_NUMBER)); + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); + assert_that (event.error_message, + is_equal_to_string ("unexpected EOF")); + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, fails_for_object_square_bracket_after_value) +{ + INIT_JSON_PARSER ("{\"A\": 123 ]"); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_OBJECT_START)); + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_NUMBER)); + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); + assert_that (event.error_message, + is_equal_to_string ("unexpected closing square bracket")); + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, fails_for_object_eof_after_comma) +{ + INIT_JSON_PARSER ("{\"A\": 123, "); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_OBJECT_START)); + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_NUMBER)); + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); + assert_that (event.error_message, + is_equal_to_string ("unexpected EOF")); + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, fails_for_read_error_after_doc_end) +{ + INIT_READ_ERROR_JSON_PARSER ("123 "); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_NUMBER)); + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); + assert_that (event.error_message, is_equal_to_string (JSON_READ_ERROR)); + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, fails_for_content_after_doc_end) +{ + INIT_JSON_PARSER ("123 456"); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_NUMBER)); + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); + assert_that (event.error_message, + is_equal_to_string ("unexpected character at end of file (52)")); + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, fails_for_expand_before_container) +{ + cJSON *cjson_value; + gchar *error_message; + INIT_JSON_PARSER ("[]"); + + cjson_value = gvm_json_pull_expand_container (&parser, &error_message); + assert_that (cjson_value, is_null); + assert_that (error_message, + is_equal_to_string ("can only expand after" + " array or object start")); + + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, fails_for_expand_after_value) +{ + cJSON *cjson_value; + gchar *error_message; + INIT_JSON_PARSER ("[123, 456]"); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_START)); + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_NUMBER)); + + cjson_value = gvm_json_pull_expand_container (&parser, &error_message); + assert_that (cjson_value, is_null); + assert_that (error_message, + is_equal_to_string ("can only expand after" + " array or object start")); + + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, fails_for_expand_invalid_content) +{ + cJSON *cjson_value; + gchar *error_message; + INIT_JSON_PARSER ("[invalid content]"); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_START)); + + cjson_value = gvm_json_pull_expand_container (&parser, &error_message); + assert_that (cjson_value, is_null); + assert_that (error_message, + is_equal_to_string ("could not parse expanded container")); + + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, fails_for_expand_overlong) +{ + cJSON *cjson_value; + gchar *error_message; + INIT_JSON_PARSER ("[1234567890.123456780]"); + parser.parse_buffer_limit = 10; + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_START)); + + cjson_value = gvm_json_pull_expand_container (&parser, &error_message); + assert_that (cjson_value, is_null); + assert_that (error_message, + is_equal_to_string ("container exceeds size limit of 10 bytes")); + + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, fails_for_expand_unexpected_curly_brace) +{ + cJSON *cjson_value; + gchar *error_message; + INIT_JSON_PARSER ("[ 123 }"); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_START)); + + cjson_value = gvm_json_pull_expand_container (&parser, &error_message); + assert_that (cjson_value, is_null); + assert_that (error_message, + is_equal_to_string ("unexpected closing curly brace")); + + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, fails_for_expand_unexpected_square_bracket) +{ + cJSON *cjson_value; + gchar *error_message; + INIT_JSON_PARSER ("{ \"A\": 123 ]"); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_OBJECT_START)); + + cjson_value = gvm_json_pull_expand_container (&parser, &error_message); + assert_that (cjson_value, is_null); + assert_that (error_message, + is_equal_to_string ("unexpected closing square bracket")); + + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, fails_for_expand_eof) +{ + cJSON *cjson_value; + gchar *error_message; + INIT_JSON_PARSER ("[ 123"); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_START)); + + cjson_value = gvm_json_pull_expand_container (&parser, &error_message); + assert_that (cjson_value, is_null); + assert_that (error_message, is_equal_to_string ("unexpected EOF")); + + CLEANUP_JSON_PARSER +} + +Ensure (jsonpull, fails_for_expand_read_error) +{ + cJSON *cjson_value; + gchar *error_message; + INIT_READ_ERROR_JSON_PARSER ("[ 123 "); + + gvm_json_pull_parser_next (&parser, &event); + assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_START)); + + cjson_value = gvm_json_pull_expand_container (&parser, &error_message); + assert_that (cjson_value, is_null); + assert_that (error_message, is_equal_to_string (JSON_READ_ERROR)); + + CLEANUP_JSON_PARSER +} + int main (int argc, char **argv) @@ -541,6 +1178,68 @@ main (int argc, char **argv) add_test_with_context (suite, jsonpull, can_expand_arrays); add_test_with_context (suite, jsonpull, can_expand_objects); + add_test_with_context (suite, jsonpull, fails_for_read_error); + + add_test_with_context (suite, jsonpull, fails_for_misspelled_true); + add_test_with_context (suite, jsonpull, fails_for_incomplete_true); + add_test_with_context (suite, jsonpull, fails_for_misspelled_false); + add_test_with_context (suite, jsonpull, fails_for_misspelled_null); + + add_test_with_context (suite, jsonpull, fails_for_string_eof); + add_test_with_context (suite, jsonpull, fails_for_string_read_error); + add_test_with_context (suite, jsonpull, fails_for_overlong_string); + add_test_with_context (suite, jsonpull, fails_for_invalid_string); + + add_test_with_context (suite, jsonpull, fails_for_number_read_error); + add_test_with_context (suite, jsonpull, fails_for_overlong_number); + add_test_with_context (suite, jsonpull, fails_for_invalid_number); + + add_test_with_context (suite, jsonpull, fails_for_array_eof); + add_test_with_context (suite, jsonpull, fails_for_array_eof_after_value); + add_test_with_context (suite, jsonpull, fails_for_array_eof_after_comma); + add_test_with_context (suite, jsonpull, fails_for_array_read_error); + add_test_with_context (suite, jsonpull, fails_for_invalid_array_bracket); + add_test_with_context (suite, jsonpull, + fails_for_invalid_array_bracket_after_value); + add_test_with_context (suite, jsonpull, fails_for_invalid_array_other_char); + add_test_with_context (suite, jsonpull, + fails_for_invalid_array_other_char_after_value); + + add_test_with_context (suite, jsonpull, fails_for_object_key_eof); + add_test_with_context (suite, jsonpull, fails_for_object_key_read_error); + add_test_with_context (suite, jsonpull, fails_for_object_key_invalid_string); + add_test_with_context (suite, jsonpull, fails_for_invalid_object_key_bracket); + add_test_with_context (suite, jsonpull, + fails_for_invalid_object_key_other_char); + + add_test_with_context (suite, jsonpull, fails_for_object_colon_eof); + add_test_with_context (suite, jsonpull, fails_for_object_colon_read_error); + add_test_with_context (suite, jsonpull, fails_for_object_colon_other_char); + + add_test_with_context (suite, jsonpull, fails_for_object_value_eof); + add_test_with_context (suite, jsonpull, fails_for_object_value_read_error); + add_test_with_context (suite, jsonpull, fails_for_object_value_curly_brace); + add_test_with_context (suite, jsonpull, + fails_for_object_value_square_bracket); + add_test_with_context (suite, jsonpull, fails_for_object_eof_after_value); + add_test_with_context (suite, jsonpull, fails_for_object_eof_after_comma); + add_test_with_context (suite, jsonpull, + fails_for_object_square_bracket_after_value); + + add_test_with_context (suite, jsonpull, fails_for_read_error_after_doc_end); + add_test_with_context (suite, jsonpull, fails_for_content_after_doc_end); + + add_test_with_context (suite, jsonpull, fails_for_expand_before_container); + add_test_with_context (suite, jsonpull, fails_for_expand_after_value); + add_test_with_context (suite, jsonpull, fails_for_expand_invalid_content); + add_test_with_context (suite, jsonpull, fails_for_expand_overlong); + add_test_with_context (suite, jsonpull, + fails_for_expand_unexpected_curly_brace); + add_test_with_context (suite, jsonpull, + fails_for_expand_unexpected_square_bracket); + add_test_with_context (suite, jsonpull, fails_for_expand_read_error); + add_test_with_context (suite, jsonpull, fails_for_expand_eof); + if (argc > 1) return run_single_test (suite, argv[1], create_text_reporter ()); return run_test_suite (suite, create_text_reporter ()); From 115e910aa8796063f9b93c6f645e5e05cac595d6 Mon Sep 17 00:00:00 2001 From: Timo Pollmeier Date: Thu, 1 Aug 2024 12:59:04 +0200 Subject: [PATCH 07/29] Fix formatting for JSON parser --- util/jsonpull.c | 253 +++++++++++++++++++----------------------- util/jsonpull.h | 71 ++++++------ util/jsonpull_tests.c | 149 +++++++++++-------------- 3 files changed, 215 insertions(+), 258 deletions(-) diff --git a/util/jsonpull.c b/util/jsonpull.c index 99aa23bd..a51458fd 100644 --- a/util/jsonpull.c +++ b/util/jsonpull.c @@ -4,11 +4,12 @@ */ #include "jsonpull.h" -#include "assert.h" -#define GVM_JSON_CHAR_EOF -1 ///< End of file -#define GVM_JSON_CHAR_ERROR -2 ///< Error reading file -#define GVM_JSON_CHAR_UNDEFINED -3 ///< Undefined state +#include + +#define GVM_JSON_CHAR_EOF -1 ///< End of file +#define GVM_JSON_CHAR_ERROR -2 ///< Error reading file +#define GVM_JSON_CHAR_UNDEFINED -3 ///< Undefined state /** * @brief Escapes a string according to the JSON or JSONPath standard @@ -21,10 +22,11 @@ gvm_json_string_escape (const char *string, gboolean single_quote) return NULL; GString *escaped = g_string_sized_new (strlen (string)); - for (point = (char*)string; *point != 0; point++) + for (point = (char *) string; *point != 0; point++) { - unsigned char character = *point;; - if ((character > 31) && (character != '\\') + unsigned char character = *point; + ; + if ((character > 31) && (character != '\\') && (single_quote || character != '\"') && (!single_quote || character != '\'')) { @@ -34,7 +36,7 @@ gvm_json_string_escape (const char *string, gboolean single_quote) { g_string_append_c (escaped, '\\'); switch (*point) - { + { case '\\': case '\'': case '\"': @@ -57,7 +59,7 @@ gvm_json_string_escape (const char *string, gboolean single_quote) break; default: g_string_append_printf (escaped, "u%04x", character); - } + } } } return g_string_free (escaped, FALSE); @@ -101,7 +103,7 @@ gvm_json_pull_path_elem_free (gvm_json_path_elem_t *elem) void gvm_json_pull_event_init (gvm_json_pull_event_t *event) { - memset (event, 0, sizeof(gvm_json_pull_event_t)); + memset (event, 0, sizeof (gvm_json_pull_event_t)); } /** @@ -113,7 +115,7 @@ void gvm_json_pull_event_reset (gvm_json_pull_event_t *event) { cJSON_free (event->value); - memset (event, 0, sizeof(gvm_json_pull_event_t)); + memset (event, 0, sizeof (gvm_json_pull_event_t)); } /** @@ -125,7 +127,7 @@ void gvm_json_pull_event_cleanup (gvm_json_pull_event_t *event) { cJSON_free (event->value); - memset (event, 0, sizeof(gvm_json_pull_event_t)); + memset (event, 0, sizeof (gvm_json_pull_event_t)); } /** @@ -138,17 +140,16 @@ gvm_json_pull_event_cleanup (gvm_json_pull_event_t *event) */ void gvm_json_pull_parser_init_full (gvm_json_pull_parser_t *parser, - FILE *input_stream, - size_t parse_buffer_limit, + FILE *input_stream, size_t parse_buffer_limit, size_t read_buffer_size) { - assert(parser); + assert (parser); assert (input_stream); - memset (parser, 0, sizeof(gvm_json_pull_parser_t)); + memset (parser, 0, sizeof (gvm_json_pull_parser_t)); if (parse_buffer_limit <= 0) parse_buffer_limit = GVM_JSON_PULL_PARSE_BUFFER_LIMIT; - + if (read_buffer_size <= 0) read_buffer_size = GVM_JSON_PULL_READ_BUFFER_SIZE; @@ -158,7 +159,7 @@ gvm_json_pull_parser_init_full (gvm_json_pull_parser_t *parser, parser->parse_buffer_limit = parse_buffer_limit; parser->parse_buffer = g_string_new (""); parser->read_buffer_size = read_buffer_size; - parser->read_buffer = g_malloc0(read_buffer_size); + parser->read_buffer = g_malloc0 (read_buffer_size); parser->last_read_char = GVM_JSON_CHAR_UNDEFINED; } @@ -169,8 +170,7 @@ gvm_json_pull_parser_init_full (gvm_json_pull_parser_t *parser, * @param[in] input_stream The JSON input stream */ void -gvm_json_pull_parser_init (gvm_json_pull_parser_t *parser, - FILE *input_stream) +gvm_json_pull_parser_init (gvm_json_pull_parser_t *parser, FILE *input_stream) { gvm_json_pull_parser_init_full (parser, input_stream, 0, 0); } @@ -183,12 +183,12 @@ gvm_json_pull_parser_init (gvm_json_pull_parser_t *parser, void gvm_json_pull_parser_cleanup (gvm_json_pull_parser_t *parser) { - assert(parser); + assert (parser); g_queue_free_full (parser->path, (GDestroyNotify) gvm_json_pull_path_elem_free); g_string_free (parser->parse_buffer, TRUE); g_free (parser->read_buffer); - memset (parser, 0, sizeof(gvm_json_pull_parser_t)); + memset (parser, 0, sizeof (gvm_json_pull_parser_t)); } /** @@ -218,10 +218,9 @@ gvm_json_pull_check_parse_buffer_size (const char *value_type, { if (parser->parse_buffer->len >= parser->parse_buffer_limit) { - event->error_message - = g_strdup_printf ("%s exceeds size limit of %zu bytes", - value_type, - parser->parse_buffer_limit); + event->error_message = + g_strdup_printf ("%s exceeds size limit of %zu bytes", value_type, + parser->parse_buffer_limit); event->type = GVM_JSON_PULL_EVENT_ERROR; return 1; } @@ -239,24 +238,22 @@ gvm_json_pull_parser_next_char (gvm_json_pull_parser_t *parser) parser->read_pos++; if (parser->read_pos < parser->last_read_size) { - parser->last_read_char - = (unsigned char) parser->read_buffer[parser->read_pos]; + parser->last_read_char = + (unsigned char) parser->read_buffer[parser->read_pos]; return parser->last_read_char; } else { parser->read_pos = 0; - parser->last_read_size = fread (parser->read_buffer, - 1, - parser->read_buffer_size, - parser->input_stream); + parser->last_read_size = fread ( + parser->read_buffer, 1, parser->read_buffer_size, parser->input_stream); if (ferror (parser->input_stream)) parser->last_read_char = GVM_JSON_CHAR_ERROR; else if (parser->last_read_size <= 0) parser->last_read_char = GVM_JSON_CHAR_EOF; else - parser->last_read_char - = (unsigned char) parser->read_buffer[parser->read_pos]; + parser->last_read_char = + (unsigned char) parser->read_buffer[parser->read_pos]; return parser->last_read_char; } } @@ -276,16 +273,15 @@ static int gvm_json_pull_parse_buffered (gvm_json_pull_parser_t *parser, gvm_json_pull_event_t *event, const char *value_name, - cJSON_bool (*validate_func)(const cJSON* const), + cJSON_bool (*validate_func) (const cJSON *const), cJSON **cjson_value) { - cJSON* parsed_value = cJSON_Parse (parser->parse_buffer->str); + cJSON *parsed_value = cJSON_Parse (parser->parse_buffer->str); *cjson_value = NULL; if (validate_func (parsed_value) == 0) { event->type = GVM_JSON_PULL_EVENT_ERROR; - event->error_message - = g_strdup_printf ("error parsing %s", value_name); + event->error_message = g_strdup_printf ("error parsing %s", value_name); cJSON_free (parsed_value); return 1; } @@ -302,8 +298,7 @@ gvm_json_pull_parse_buffered (gvm_json_pull_parser_t *parser, */ static void gvm_json_pull_handle_read_end (gvm_json_pull_parser_t *parser, - gvm_json_pull_event_t *event, - gboolean allow_eof) + gvm_json_pull_event_t *event, gboolean allow_eof) { if (parser->last_read_char == GVM_JSON_CHAR_ERROR) { @@ -332,8 +327,7 @@ gvm_json_pull_handle_read_end (gvm_json_pull_parser_t *parser, */ static int gvm_json_pull_skip_space (gvm_json_pull_parser_t *parser, - gvm_json_pull_event_t *event, - gboolean allow_eof) + gvm_json_pull_event_t *event, gboolean allow_eof) { while (g_ascii_isspace (parser->last_read_char)) gvm_json_pull_parser_next_char (parser); @@ -359,24 +353,23 @@ gvm_json_pull_skip_space (gvm_json_pull_parser_t *parser, */ static int gvm_json_pull_parse_string (gvm_json_pull_parser_t *parser, - gvm_json_pull_event_t *event, - cJSON **cjson_value) + gvm_json_pull_event_t *event, cJSON **cjson_value) { gboolean escape_next_char = FALSE; g_string_truncate (parser->parse_buffer, 0); g_string_append_c (parser->parse_buffer, '"'); while (gvm_json_pull_parser_next_char (parser) >= 0) - { - if (gvm_json_pull_check_parse_buffer_size ("string", parser, event)) - return 1; - g_string_append_c (parser->parse_buffer, parser->last_read_char); - if (escape_next_char) - escape_next_char = FALSE; - else if (parser->last_read_char == '\\') - escape_next_char = TRUE; - else if (parser->last_read_char == '"') - break; - } + { + if (gvm_json_pull_check_parse_buffer_size ("string", parser, event)) + return 1; + g_string_append_c (parser->parse_buffer, parser->last_read_char); + if (escape_next_char) + escape_next_char = FALSE; + else if (parser->last_read_char == '\\') + escape_next_char = TRUE; + else if (parser->last_read_char == '"') + break; + } if (parser->last_read_char < 0) { @@ -386,10 +379,7 @@ gvm_json_pull_parse_string (gvm_json_pull_parser_t *parser, gvm_json_pull_parser_next_char (parser); - return gvm_json_pull_parse_buffered (parser, - event, - "string", - cJSON_IsString, + return gvm_json_pull_parse_buffered (parser, event, "string", cJSON_IsString, cjson_value); } @@ -407,24 +397,21 @@ gvm_json_pull_parse_string (gvm_json_pull_parser_t *parser, */ static int gvm_json_pull_parse_number (gvm_json_pull_parser_t *parser, - gvm_json_pull_event_t *event, - cJSON **cjson_value) + gvm_json_pull_event_t *event, cJSON **cjson_value) { g_string_truncate (parser->parse_buffer, 0); g_string_append_c (parser->parse_buffer, parser->last_read_char); while (gvm_json_pull_parser_next_char (parser) >= 0) - { - if (gvm_json_pull_check_parse_buffer_size ("number", parser, event)) - return 1; - if (g_ascii_isdigit (parser->last_read_char) - || parser->last_read_char == '.' - || parser->last_read_char == 'e' - || parser->last_read_char == '-' - || parser->last_read_char == '+') - g_string_append_c (parser->parse_buffer, parser->last_read_char); - else - break; - } + { + if (gvm_json_pull_check_parse_buffer_size ("number", parser, event)) + return 1; + if (g_ascii_isdigit (parser->last_read_char) + || parser->last_read_char == '.' || parser->last_read_char == 'e' + || parser->last_read_char == '-' || parser->last_read_char == '+') + g_string_append_c (parser->parse_buffer, parser->last_read_char); + else + break; + } if (parser->last_read_char == GVM_JSON_CHAR_ERROR) { @@ -433,10 +420,7 @@ gvm_json_pull_parse_number (gvm_json_pull_parser_t *parser, return 1; } - return gvm_json_pull_parse_buffered (parser, - event, - "number", - cJSON_IsNumber, + return gvm_json_pull_parse_buffered (parser, event, "number", cJSON_IsNumber, cjson_value); } @@ -454,10 +438,9 @@ gvm_json_pull_parse_number (gvm_json_pull_parser_t *parser, */ static int gvm_json_pull_parse_keyword (gvm_json_pull_parser_t *parser, - gvm_json_pull_event_t *event, - const char *keyword) + gvm_json_pull_event_t *event, const char *keyword) { - for (size_t i = 0; i < strlen(keyword); i++) + for (size_t i = 0; i < strlen (keyword); i++) { if (parser->last_read_char < 0) { @@ -467,8 +450,8 @@ gvm_json_pull_parse_keyword (gvm_json_pull_parser_t *parser, else if (parser->last_read_char != keyword[i]) { event->type = GVM_JSON_PULL_EVENT_ERROR; - event->error_message - = g_strdup_printf ("misspelled keyword '%s'", keyword); + event->error_message = + g_strdup_printf ("misspelled keyword '%s'", keyword); return 1; } gvm_json_pull_parser_next_char (parser); @@ -476,10 +459,10 @@ gvm_json_pull_parse_keyword (gvm_json_pull_parser_t *parser, return 0; } -#define PARSE_VALUE_NEXT_EXPECT \ - if (parser->path->length) \ - parser->expect = GVM_JSON_PULL_EXPECT_COMMA; \ - else \ +#define PARSE_VALUE_NEXT_EXPECT \ + if (parser->path->length) \ + parser->expect = GVM_JSON_PULL_EXPECT_COMMA; \ + else \ parser->expect = GVM_JSON_PULL_EXPECT_EOF; /** @@ -505,7 +488,7 @@ gvm_json_pull_parse_key (gvm_json_pull_parser_t *parser, gvm_json_path_elem_t *path_elem; switch (parser->last_read_char) - { + { case '"': if (gvm_json_pull_parse_string (parser, event, &key_cjson)) return 1; @@ -531,7 +514,7 @@ gvm_json_pull_parse_key (gvm_json_pull_parser_t *parser, g_free (path_elem->key); path_elem->key = key_str; parser->expect = GVM_JSON_PULL_EXPECT_VALUE; - + break; case '}': event->type = GVM_JSON_PULL_EVENT_OBJECT_END; @@ -548,7 +531,7 @@ gvm_json_pull_parse_key (gvm_json_pull_parser_t *parser, event->type = GVM_JSON_PULL_EVENT_ERROR; event->error_message = g_strdup ("unexpected character"); return 1; - } + } return 0; } @@ -570,13 +553,13 @@ gvm_json_pull_parse_comma (gvm_json_pull_parser_t *parser, { if (gvm_json_pull_skip_space (parser, event, FALSE)) return 1; - + gvm_json_path_elem_t *path_elem = NULL; switch (parser->last_read_char) - { + { case ',': path_elem = g_queue_peek_tail (parser->path); - path_elem->index ++; + path_elem->index++; if (path_elem->parent_type == GVM_JSON_PULL_CONTAINER_OBJECT) parser->expect = GVM_JSON_PULL_EXPECT_KEY; else @@ -585,7 +568,7 @@ gvm_json_pull_parse_comma (gvm_json_pull_parser_t *parser, break; case ']': path_elem = g_queue_peek_tail (parser->path); - if (path_elem == NULL + if (path_elem == NULL || path_elem->parent_type != GVM_JSON_PULL_CONTAINER_ARRAY) { event->type = GVM_JSON_PULL_EVENT_ERROR; @@ -600,7 +583,7 @@ gvm_json_pull_parse_comma (gvm_json_pull_parser_t *parser, break; case '}': path_elem = g_queue_peek_tail (parser->path); - if (path_elem == NULL + if (path_elem == NULL || path_elem->parent_type != GVM_JSON_PULL_CONTAINER_OBJECT) { event->type = GVM_JSON_PULL_EVENT_ERROR; @@ -617,7 +600,7 @@ gvm_json_pull_parse_comma (gvm_json_pull_parser_t *parser, event->error_message = g_strdup ("expected comma or end of container"); event->type = GVM_JSON_PULL_EVENT_ERROR; return 1; - } + } return 0; } @@ -638,12 +621,12 @@ gvm_json_pull_parse_value (gvm_json_pull_parser_t *parser, { if (gvm_json_pull_skip_space (parser, event, FALSE)) return 1; - + cJSON *cjson_value = NULL; gvm_json_path_elem_t *path_elem = NULL; switch (parser->last_read_char) - { + { case '"': if (gvm_json_pull_parse_string (parser, event, &cjson_value)) return 1; @@ -675,15 +658,14 @@ gvm_json_pull_parse_value (gvm_json_pull_parser_t *parser, case '[': event->type = GVM_JSON_PULL_EVENT_ARRAY_START; event->value = NULL; - parser->path_add - = gvm_json_pull_path_elem_new (GVM_JSON_PULL_CONTAINER_ARRAY, - parser->path->length); + parser->path_add = gvm_json_pull_path_elem_new ( + GVM_JSON_PULL_CONTAINER_ARRAY, parser->path->length); parser->expect = GVM_JSON_PULL_EXPECT_VALUE; gvm_json_pull_parser_next_char (parser); break; case ']': path_elem = g_queue_peek_tail (parser->path); - if (path_elem == NULL + if (path_elem == NULL || path_elem->parent_type != GVM_JSON_PULL_CONTAINER_ARRAY) { event->type = GVM_JSON_PULL_EVENT_ERROR; @@ -699,9 +681,8 @@ gvm_json_pull_parse_value (gvm_json_pull_parser_t *parser, case '{': event->type = GVM_JSON_PULL_EVENT_OBJECT_START; event->value = NULL; - parser->path_add - = gvm_json_pull_path_elem_new (GVM_JSON_PULL_CONTAINER_OBJECT, - parser->path->length); + parser->path_add = gvm_json_pull_path_elem_new ( + GVM_JSON_PULL_CONTAINER_OBJECT, parser->path->length); parser->expect = GVM_JSON_PULL_EXPECT_KEY; gvm_json_pull_parser_next_char (parser); break; @@ -726,15 +707,15 @@ gvm_json_pull_parse_value (gvm_json_pull_parser_t *parser, event->error_message = g_strdup ("unexpected character"); return 1; } - } + } return 0; } /** * @brief Get the next event from a JSON pull parser. - * + * * Note: This invalidates previous event data like the cJSON value. - * + * * @param[in] parser The JSON pull parser to process until the next event * @param[in] event Structure to store event data in. */ @@ -763,7 +744,7 @@ gvm_json_pull_parser_next (gvm_json_pull_parser_t *parser, g_queue_push_tail (parser->path, parser->path_add); parser->path_add = NULL; } - + // Check for expected end of file if (parser->expect == GVM_JSON_PULL_EXPECT_EOF) { @@ -777,9 +758,8 @@ gvm_json_pull_parser_next (gvm_json_pull_parser_t *parser, else if (parser->last_read_char != GVM_JSON_CHAR_EOF) { event->type = GVM_JSON_PULL_EVENT_ERROR; - event->error_message - = g_strdup_printf ("unexpected character at end of file (%d)", - parser->last_read_char); + event->error_message = g_strdup_printf ( + "unexpected character at end of file (%d)", parser->last_read_char); return; } return; @@ -796,7 +776,7 @@ gvm_json_pull_parser_next (gvm_json_pull_parser_t *parser, if (gvm_json_pull_parse_comma (parser, event)) return; } - + if (parser->expect == GVM_JSON_PULL_EXPECT_KEY) { if (gvm_json_pull_parse_key (parser, event)) @@ -842,20 +822,19 @@ gvm_json_pull_expand_container (gvm_json_pull_parser_t *parser, parser->path_add = NULL; } - if (path_tail - && path_tail->parent_type == GVM_JSON_PULL_CONTAINER_ARRAY) + if (path_tail && path_tail->parent_type == GVM_JSON_PULL_CONTAINER_ARRAY) g_string_append_c (parser->parse_buffer, '['); - else if (path_tail + else if (path_tail && path_tail->parent_type == GVM_JSON_PULL_CONTAINER_OBJECT) g_string_append_c (parser->parse_buffer, '{'); else { if (error_message) - *error_message - = g_strdup ("can only expand after array or object start"); + *error_message = + g_strdup ("can only expand after array or object start"); return NULL; } - + start_depth = path_tail->depth; in_string = escape_next_char = FALSE; in_expanded_container = TRUE; @@ -865,14 +844,14 @@ gvm_json_pull_expand_container (gvm_json_pull_parser_t *parser, if (parser->parse_buffer->len >= parser->parse_buffer_limit) { if (error_message) - *error_message - = g_strdup_printf ("container exceeds size limit of %zu bytes", - parser->parse_buffer_limit); + *error_message = + g_strdup_printf ("container exceeds size limit of %zu bytes", + parser->parse_buffer_limit); return NULL; } - + g_string_append_c (parser->parse_buffer, parser->last_read_char); - + if (escape_next_char) { escape_next_char = FALSE; @@ -885,20 +864,18 @@ gvm_json_pull_expand_container (gvm_json_pull_parser_t *parser, else { switch (parser->last_read_char) - { + { case '"': in_string = TRUE; break; case '[': - path_tail - = gvm_json_pull_path_elem_new (GVM_JSON_PULL_CONTAINER_ARRAY, - parser->path->length); + path_tail = gvm_json_pull_path_elem_new ( + GVM_JSON_PULL_CONTAINER_ARRAY, parser->path->length); g_queue_push_tail (parser->path, path_tail); break; case '{': - path_tail - = gvm_json_pull_path_elem_new (GVM_JSON_PULL_CONTAINER_OBJECT, - parser->path->length); + path_tail = gvm_json_pull_path_elem_new ( + GVM_JSON_PULL_CONTAINER_OBJECT, parser->path->length); g_queue_push_tail (parser->path, path_tail); break; case ']': @@ -906,8 +883,8 @@ gvm_json_pull_expand_container (gvm_json_pull_parser_t *parser, if (path_tail->parent_type != GVM_JSON_PULL_CONTAINER_ARRAY) { if (error_message) - *error_message - = g_strdup ("unexpected closing square bracket"); + *error_message = + g_strdup ("unexpected closing square bracket"); return NULL; } if (path_tail->depth == start_depth) @@ -918,14 +895,14 @@ gvm_json_pull_expand_container (gvm_json_pull_parser_t *parser, if (path_tail->parent_type != GVM_JSON_PULL_CONTAINER_OBJECT) { if (error_message) - *error_message - = g_strdup ("unexpected closing curly brace"); + *error_message = + g_strdup ("unexpected closing curly brace"); return NULL; } if (path_tail->depth == start_depth) in_expanded_container = FALSE; break; - } + } } gvm_json_pull_parser_next_char (parser); } @@ -946,7 +923,7 @@ gvm_json_pull_expand_container (gvm_json_pull_parser_t *parser, expanded = cJSON_Parse (parser->parse_buffer->str); g_string_truncate (parser->parse_buffer, 0); PARSE_VALUE_NEXT_EXPECT - + if (expanded == NULL && error_message) *error_message = g_strdup ("could not parse expanded container"); @@ -984,9 +961,7 @@ gchar * gvm_json_path_to_string (GQueue *path) { GString *path_string = g_string_new ("$"); - g_queue_foreach (path, - (GFunc) gvm_json_path_string_add_elem, - path_string); + g_queue_foreach (path, (GFunc) gvm_json_path_string_add_elem, path_string); return g_string_free (path_string, FALSE); } diff --git a/util/jsonpull.h b/util/jsonpull.h index 01e12aa1..8d8343a0 100644 --- a/util/jsonpull.h +++ b/util/jsonpull.h @@ -3,7 +3,6 @@ * SPDX-License-Identifier: GPL-2.0-or-later */ - #ifndef _GVM_JSONPULL_H #define _GVM_JSONPULL_H @@ -16,26 +15,29 @@ /** * @brief Type of container the parser is currently in */ -typedef enum { - GVM_JSON_PULL_CONTAINER_NONE = 0, ///< No container / document root - GVM_JSON_PULL_CONTAINER_ARRAY, ///< Array - GVM_JSON_PULL_CONTAINER_OBJECT, ///< Object +typedef enum +{ + GVM_JSON_PULL_CONTAINER_NONE = 0, ///< No container / document root + GVM_JSON_PULL_CONTAINER_ARRAY, ///< Array + GVM_JSON_PULL_CONTAINER_OBJECT, ///< Object } gvm_json_pull_container_type_t; /** * @brief Path element types for the JSON pull parser. */ -typedef struct gvm_json_path_elem { +typedef struct gvm_json_path_elem +{ gvm_json_pull_container_type_t parent_type; ///< parent container type - int index; ///< Index of the element within the parent - char *key; ///< Key if element is in an object - int depth; ///< Number of ancestor elements + int index; ///< Index of the element within the parent + char *key; ///< Key if element is in an object + int depth; ///< Number of ancestor elements } gvm_json_path_elem_t; /** * @brief Event types for the JSON pull parser */ -typedef enum { +typedef enum +{ GVM_JSON_PULL_EVENT_UNDEFINED = 0, GVM_JSON_PULL_EVENT_ARRAY_START, GVM_JSON_PULL_EVENT_ARRAY_END, @@ -52,17 +54,19 @@ typedef enum { /** * @brief Event generated by the JSON pull parser. */ -typedef struct { - gvm_json_pull_event_type_t type; ///< Type of event - GQueue *path; ///< Path to the event value - cJSON *value; ///< Value for non-container value events - gchar *error_message; ///< Error message, NULL on success +typedef struct +{ + gvm_json_pull_event_type_t type; ///< Type of event + GQueue *path; ///< Path to the event value + cJSON *value; ///< Value for non-container value events + gchar *error_message; ///< Error message, NULL on success } gvm_json_pull_event_t; /** * @brief Expected token state for the JSON pull parser */ -typedef enum { +typedef enum +{ GVM_JSON_PULL_EXPECT_UNDEFINED = 0, ///< Undefined state GVM_JSON_PULL_EXPECT_VALUE, ///< Expect start of a value GVM_JSON_PULL_EXPECT_KEY, ///< Expect start of a key @@ -77,19 +81,20 @@ typedef enum { /** * @brief A json pull parser */ -typedef struct { - GQueue *path; ///< Path to the current value +typedef struct +{ + GQueue *path; ///< Path to the current value gvm_json_path_elem_t *path_add; ///< Path elem to add in next step gvm_json_pull_expect_t expect; ///< Current expected token - int keyword_pos; ///< Position in a keyword like "true" or "null" - FILE *input_stream; ///< Input stream - char *read_buffer; ///< Stream reading buffer - size_t read_buffer_size; ///< Size of the stream reading buffer - size_t last_read_size; ///< Size of last stream read - int last_read_char; ///< Character last read from stream - size_t read_pos; ///< Position in current read - GString *parse_buffer; ///< Buffer for parsing values and object keys - size_t parse_buffer_limit; ///< Maximum parse buffer size + int keyword_pos; ///< Position in a keyword like "true" or "null" + FILE *input_stream; ///< Input stream + char *read_buffer; ///< Stream reading buffer + size_t read_buffer_size; ///< Size of the stream reading buffer + size_t last_read_size; ///< Size of last stream read + int last_read_char; ///< Character last read from stream + size_t read_pos; ///< Position in current read + GString *parse_buffer; ///< Buffer for parsing values and object keys + size_t parse_buffer_limit; ///< Maximum parse buffer size } gvm_json_pull_parser_t; gchar * @@ -111,8 +116,8 @@ void gvm_json_pull_event_cleanup (gvm_json_pull_event_t *); void -gvm_json_pull_parser_init_full (gvm_json_pull_parser_t *, FILE *, - size_t, size_t); +gvm_json_pull_parser_init_full (gvm_json_pull_parser_t *, FILE *, size_t, + size_t); void gvm_json_pull_parser_init (gvm_json_pull_parser_t *, FILE *); @@ -120,15 +125,13 @@ gvm_json_pull_parser_init (gvm_json_pull_parser_t *, FILE *); void gvm_json_pull_parser_cleanup (gvm_json_pull_parser_t *); -void gvm_json_pull_parser_next(gvm_json_pull_parser_t*, - gvm_json_pull_event_t*); +void +gvm_json_pull_parser_next (gvm_json_pull_parser_t *, gvm_json_pull_event_t *); cJSON * -gvm_json_pull_expand_container (gvm_json_pull_parser_t *, - gchar **); +gvm_json_pull_expand_container (gvm_json_pull_parser_t *, gchar **); gchar * gvm_json_path_to_string (GQueue *path); - #endif /* _GVM_JSONPULL_H */ \ No newline at end of file diff --git a/util/jsonpull_tests.c b/util/jsonpull_tests.c index 18056cd5..808c4333 100644 --- a/util/jsonpull_tests.c +++ b/util/jsonpull_tests.c @@ -5,9 +5,9 @@ #include "jsonpull.c" -#include #include #include +#include Describe (jsonpull); BeforeEach (jsonpull) @@ -17,14 +17,13 @@ AfterEach (jsonpull) { } - /* * Helper function to open a string as a read-only stream. */ static inline FILE * fstropen_r (const char *str) { - return fmemopen ((void*)str, strlen(str), "r"); + return fmemopen ((void *) str, strlen (str), "r"); } static ssize_t @@ -41,42 +40,38 @@ read_with_error_on_eof (void *stream_cookie, char *buf, size_t size) return ret; } - -#define INIT_JSON_PARSER(json_string) \ - gvm_json_pull_event_t event; \ - gvm_json_pull_parser_t parser; \ - FILE *jsonstream; \ - jsonstream = fstropen_r (json_string); \ - gvm_json_pull_event_init (&event); \ +#define INIT_JSON_PARSER(json_string) \ + gvm_json_pull_event_t event; \ + gvm_json_pull_parser_t parser; \ + FILE *jsonstream; \ + jsonstream = fstropen_r (json_string); \ + gvm_json_pull_event_init (&event); \ gvm_json_pull_parser_init_full (&parser, jsonstream, 100, 4); -#define INIT_READ_ERROR_JSON_PARSER(json_string) \ - gvm_json_pull_event_t event; \ - gvm_json_pull_parser_t parser; \ - FILE *jsonstream = fstropen_r (json_string); \ - cookie_io_functions_t io_functions = { \ - .read = read_with_error_on_eof, \ - .write = NULL, \ - .seek = NULL, \ - .close = NULL \ - }; \ - FILE *errorstream = fopencookie (jsonstream, "r", io_functions); \ - gvm_json_pull_event_init (&event); \ +#define INIT_READ_ERROR_JSON_PARSER(json_string) \ + gvm_json_pull_event_t event; \ + gvm_json_pull_parser_t parser; \ + FILE *jsonstream = fstropen_r (json_string); \ + cookie_io_functions_t io_functions = {.read = read_with_error_on_eof, \ + .write = NULL, \ + .seek = NULL, \ + .close = NULL}; \ + FILE *errorstream = fopencookie (jsonstream, "r", io_functions); \ + gvm_json_pull_event_init (&event); \ gvm_json_pull_parser_init_full (&parser, errorstream, 100, 4); -#define CLEANUP_JSON_PARSER \ - gvm_json_pull_event_cleanup (&event); \ - gvm_json_pull_parser_cleanup (&parser); \ - fclose (jsonstream); \ +#define CLEANUP_JSON_PARSER \ + gvm_json_pull_event_cleanup (&event); \ + gvm_json_pull_parser_cleanup (&parser); \ + fclose (jsonstream); -#define CHECK_PATH_EQUALS(expected_path_str) \ - path_str = gvm_json_path_to_string (event.path); \ - assert_that (path_str, is_equal_to_string (expected_path_str)); \ +#define CHECK_PATH_EQUALS(expected_path_str) \ + path_str = gvm_json_path_to_string (event.path); \ + assert_that (path_str, is_equal_to_string (expected_path_str)); \ g_free (path_str); #define JSON_READ_ERROR "error reading JSON stream: Input/output error" - Ensure (jsonpull, can_json_escape_strings) { const char *unescaped_string = "\"'Abc\\\b\f\n\r\t\001Äöü'\""; @@ -100,7 +95,7 @@ Ensure (jsonpull, can_init_parser_with_defaults) { gvm_json_pull_parser_t parser; FILE *strfile = fstropen_r ("[]"); - + gvm_json_pull_parser_init (&parser, strfile); assert_that (parser.input_stream, is_equal_to (strfile)); assert_that (parser.parse_buffer_limit, @@ -154,7 +149,7 @@ Ensure (jsonpull, can_parse_empty_strings) { INIT_JSON_PARSER ("\"\"") - gvm_json_pull_parser_next (&parser, &event); + gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_STRING)); assert_that (event.value->valuestring, is_equal_to_string ("")); @@ -167,10 +162,9 @@ Ensure (jsonpull, can_parse_strings_with_content) { INIT_JSON_PARSER ("\n\"123\\tXYZ\\nÄöü\"\n") - gvm_json_pull_parser_next (&parser, &event); + gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_STRING)); - assert_that (event.value->valuestring, - is_equal_to_string ("123\tXYZ\nÄöü")); + assert_that (event.value->valuestring, is_equal_to_string ("123\tXYZ\nÄöü")); gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_EOF)); @@ -339,7 +333,7 @@ Ensure (jsonpull, can_parse_nested_containers) gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_START)); CHECK_PATH_EQUALS ("$") - + gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_OBJECT_START)); CHECK_PATH_EQUALS ("$[0]") @@ -369,7 +363,7 @@ Ensure (jsonpull, can_parse_nested_containers) gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_END)); CHECK_PATH_EQUALS ("$[0]['B']['C']") - + gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_OBJECT_END)); CHECK_PATH_EQUALS ("$[0]['B']") @@ -395,7 +389,7 @@ Ensure (jsonpull, can_parse_nested_containers) gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_END)); CHECK_PATH_EQUALS ("$[1]") - + gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_END)); CHECK_PATH_EQUALS ("$") @@ -436,12 +430,12 @@ Ensure (jsonpull, can_expand_arrays) assert_that (cJSON_IsArray (expanded), is_true); child = expanded->child; assert_that (child, is_not_null); - assert_that (cJSON_IsNumber(child), is_true); - assert_that (child->valueint, is_equal_to(1)); + assert_that (cJSON_IsNumber (child), is_true); + assert_that (child->valueint, is_equal_to (1)); child = child->next; assert_that (child, is_null); cJSON_free (expanded); - + // multi-element array gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_START)); @@ -452,14 +446,14 @@ Ensure (jsonpull, can_expand_arrays) assert_that (cJSON_IsArray (expanded), is_true); child = expanded->child; assert_that (child, is_not_null); - assert_that (cJSON_IsNumber(child), is_true); - assert_that (child->valueint, is_equal_to(2)); + assert_that (cJSON_IsNumber (child), is_true); + assert_that (child->valueint, is_equal_to (2)); child = child->next; assert_that (child, is_not_null); - assert_that (cJSON_IsArray(child), is_true); - assert_that (child->child->valueint, is_equal_to(3)); + assert_that (cJSON_IsArray (child), is_true); + assert_that (child->child->valueint, is_equal_to (3)); cJSON_free (expanded); - + // string array gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_START)); @@ -470,12 +464,12 @@ Ensure (jsonpull, can_expand_arrays) assert_that (cJSON_IsArray (expanded), is_true); child = expanded->child; assert_that (child, is_not_null); - assert_that (cJSON_IsString(child), is_true); - assert_that (child->valuestring, is_equal_to_string("A")); + assert_that (cJSON_IsString (child), is_true); + assert_that (child->valuestring, is_equal_to_string ("A")); child = child->next; assert_that (child, is_not_null); - assert_that (cJSON_IsString(child), is_true); - assert_that (child->valuestring, is_equal_to_string("\"B]")); + assert_that (cJSON_IsString (child), is_true); + assert_that (child->valuestring, is_equal_to_string ("\"B]")); cJSON_free (expanded); // array end and EOF @@ -498,7 +492,7 @@ Ensure (jsonpull, can_expand_objects) gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_OBJECT_START)); CHECK_PATH_EQUALS ("$") - + gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_OBJECT_START)); CHECK_PATH_EQUALS ("$['A']") @@ -516,17 +510,17 @@ Ensure (jsonpull, can_expand_objects) assert_that (cJSON_IsObject (expanded), is_true); child = expanded->child; assert_that (child, is_not_null); - assert_that (cJSON_IsString(child), is_true); + assert_that (cJSON_IsString (child), is_true); assert_that (child->string, is_equal_to_string ("C")); assert_that (child->valuestring, is_equal_to_string ("\"D}")); child = child->next; assert_that (child, is_not_null); - assert_that (cJSON_IsNumber(child), is_true); + assert_that (cJSON_IsNumber (child), is_true); assert_that (child->string, is_equal_to_string ("E")); assert_that (child->valueint, is_equal_to (123)); child = child->next; assert_that (child, is_not_null); - assert_that (cJSON_IsObject(child), is_true); + assert_that (cJSON_IsObject (child), is_true); assert_that (child->string, is_equal_to_string ("F")); assert_that (child->child, is_null); cJSON_free (expanded); @@ -570,8 +564,7 @@ Ensure (jsonpull, fails_for_incomplete_true) gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); - assert_that (event.error_message, - is_equal_to_string ("unexpected EOF")); + assert_that (event.error_message, is_equal_to_string ("unexpected EOF")); CLEANUP_JSON_PARSER } @@ -613,8 +606,7 @@ Ensure (jsonpull, fails_for_string_eof) gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); - assert_that (event.error_message, - is_equal_to_string ("unexpected EOF")); + assert_that (event.error_message, is_equal_to_string ("unexpected EOF")); CLEANUP_JSON_PARSER } @@ -682,8 +674,7 @@ Ensure (jsonpull, fails_for_array_eof) assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_START)); gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); - assert_that (event.error_message, - is_equal_to_string ("unexpected EOF")); + assert_that (event.error_message, is_equal_to_string ("unexpected EOF")); CLEANUP_JSON_PARSER } @@ -697,8 +688,7 @@ Ensure (jsonpull, fails_for_array_eof_after_value) assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_NUMBER)); gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); - assert_that (event.error_message, - is_equal_to_string ("unexpected EOF")); + assert_that (event.error_message, is_equal_to_string ("unexpected EOF")); CLEANUP_JSON_PARSER } @@ -712,8 +702,7 @@ Ensure (jsonpull, fails_for_array_eof_after_comma) assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_NUMBER)); gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); - assert_that (event.error_message, - is_equal_to_string ("unexpected EOF")); + assert_that (event.error_message, is_equal_to_string ("unexpected EOF")); CLEANUP_JSON_PARSER } @@ -729,7 +718,6 @@ Ensure (jsonpull, fails_for_array_read_error) CLEANUP_JSON_PARSER } - Ensure (jsonpull, fails_for_invalid_array_bracket) { INIT_JSON_PARSER ("[}"); @@ -794,8 +782,7 @@ Ensure (jsonpull, fails_for_object_key_eof) assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_OBJECT_START)); gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); - assert_that (event.error_message, - is_equal_to_string ("unexpected EOF")); + assert_that (event.error_message, is_equal_to_string ("unexpected EOF")); CLEANUP_JSON_PARSER } @@ -858,8 +845,7 @@ Ensure (jsonpull, fails_for_object_colon_eof) assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_OBJECT_START)); gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); - assert_that (event.error_message, - is_equal_to_string ("unexpected EOF")); + assert_that (event.error_message, is_equal_to_string ("unexpected EOF")); CLEANUP_JSON_PARSER } @@ -883,8 +869,7 @@ Ensure (jsonpull, fails_for_object_colon_other_char) assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_OBJECT_START)); gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); - assert_that (event.error_message, - is_equal_to_string ("expected colon")); + assert_that (event.error_message, is_equal_to_string ("expected colon")); CLEANUP_JSON_PARSER } @@ -896,8 +881,7 @@ Ensure (jsonpull, fails_for_object_value_eof) assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_OBJECT_START)); gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); - assert_that (event.error_message, - is_equal_to_string ("unexpected EOF")); + assert_that (event.error_message, is_equal_to_string ("unexpected EOF")); CLEANUP_JSON_PARSER } @@ -949,8 +933,7 @@ Ensure (jsonpull, fails_for_object_eof_after_value) assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_NUMBER)); gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); - assert_that (event.error_message, - is_equal_to_string ("unexpected EOF")); + assert_that (event.error_message, is_equal_to_string ("unexpected EOF")); CLEANUP_JSON_PARSER } @@ -979,8 +962,7 @@ Ensure (jsonpull, fails_for_object_eof_after_comma) assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_NUMBER)); gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); - assert_that (event.error_message, - is_equal_to_string ("unexpected EOF")); + assert_that (event.error_message, is_equal_to_string ("unexpected EOF")); CLEANUP_JSON_PARSER } @@ -1017,9 +999,8 @@ Ensure (jsonpull, fails_for_expand_before_container) cjson_value = gvm_json_pull_expand_container (&parser, &error_message); assert_that (cjson_value, is_null); - assert_that (error_message, - is_equal_to_string ("can only expand after" - " array or object start")); + assert_that (error_message, is_equal_to_string ("can only expand after" + " array or object start")); CLEANUP_JSON_PARSER } @@ -1037,9 +1018,8 @@ Ensure (jsonpull, fails_for_expand_after_value) cjson_value = gvm_json_pull_expand_container (&parser, &error_message); assert_that (cjson_value, is_null); - assert_that (error_message, - is_equal_to_string ("can only expand after" - " array or object start")); + assert_that (error_message, is_equal_to_string ("can only expand after" + " array or object start")); CLEANUP_JSON_PARSER } @@ -1145,7 +1125,6 @@ Ensure (jsonpull, fails_for_expand_read_error) CLEANUP_JSON_PARSER } - int main (int argc, char **argv) { @@ -1160,7 +1139,7 @@ main (int argc, char **argv) add_test_with_context (suite, jsonpull, can_parse_false); add_test_with_context (suite, jsonpull, can_parse_true); add_test_with_context (suite, jsonpull, can_parse_null); - + add_test_with_context (suite, jsonpull, can_parse_empty_strings); add_test_with_context (suite, jsonpull, can_parse_strings_with_content); From b702bb5a2f7014dc28cda036b6a7dbd3d53da558 Mon Sep 17 00:00:00 2001 From: Timo Pollmeier Date: Fri, 2 Aug 2024 09:11:28 +0200 Subject: [PATCH 08/29] Change PARSE_VALUE_NEXT_EXPECT macro to a function --- util/jsonpull.c | 36 ++++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/util/jsonpull.c b/util/jsonpull.c index a51458fd..48aaa237 100644 --- a/util/jsonpull.c +++ b/util/jsonpull.c @@ -459,11 +459,19 @@ gvm_json_pull_parse_keyword (gvm_json_pull_parser_t *parser, return 0; } -#define PARSE_VALUE_NEXT_EXPECT \ - if (parser->path->length) \ - parser->expect = GVM_JSON_PULL_EXPECT_COMMA; \ - else \ +/** + * @brief Updates the expectation for a JSON pull parser according to the path. + * + * @param[in] parser The parser to update. + */ +static void +parse_value_next_expect (gvm_json_pull_parser_t *parser) +{ + if (parser->path->length) + parser->expect = GVM_JSON_PULL_EXPECT_COMMA; + else parser->expect = GVM_JSON_PULL_EXPECT_EOF; +} /** * @brief Handles the case that an object key is expected in a JSON pull parser. @@ -520,7 +528,7 @@ gvm_json_pull_parse_key (gvm_json_pull_parser_t *parser, event->type = GVM_JSON_PULL_EVENT_OBJECT_END; event->value = NULL; gvm_json_pull_path_elem_free (g_queue_pop_tail (parser->path)); - PARSE_VALUE_NEXT_EXPECT + parse_value_next_expect (parser); gvm_json_pull_parser_next_char (parser); break; case ']': @@ -578,7 +586,7 @@ gvm_json_pull_parse_comma (gvm_json_pull_parser_t *parser, event->type = GVM_JSON_PULL_EVENT_ARRAY_END; event->value = NULL; gvm_json_pull_path_elem_free (g_queue_pop_tail (parser->path)); - PARSE_VALUE_NEXT_EXPECT + parse_value_next_expect (parser); gvm_json_pull_parser_next_char (parser); break; case '}': @@ -593,7 +601,7 @@ gvm_json_pull_parse_comma (gvm_json_pull_parser_t *parser, event->type = GVM_JSON_PULL_EVENT_OBJECT_END; event->value = NULL; gvm_json_pull_path_elem_free (g_queue_pop_tail (parser->path)); - PARSE_VALUE_NEXT_EXPECT + parse_value_next_expect (parser); gvm_json_pull_parser_next_char (parser); break; default: @@ -632,28 +640,28 @@ gvm_json_pull_parse_value (gvm_json_pull_parser_t *parser, return 1; event->type = GVM_JSON_PULL_EVENT_STRING; event->value = cjson_value; - PARSE_VALUE_NEXT_EXPECT + parse_value_next_expect (parser); break; case 'n': if (gvm_json_pull_parse_keyword (parser, event, "null")) return 1; event->type = GVM_JSON_PULL_EVENT_NULL; event->value = cJSON_CreateNull (); - PARSE_VALUE_NEXT_EXPECT + parse_value_next_expect (parser); break; case 'f': if (gvm_json_pull_parse_keyword (parser, event, "false")) return 1; event->type = GVM_JSON_PULL_EVENT_BOOLEAN; event->value = cJSON_CreateFalse (); - PARSE_VALUE_NEXT_EXPECT + parse_value_next_expect (parser); break; case 't': if (gvm_json_pull_parse_keyword (parser, event, "true")) return 1; event->type = GVM_JSON_PULL_EVENT_BOOLEAN; event->value = cJSON_CreateTrue (); - PARSE_VALUE_NEXT_EXPECT + parse_value_next_expect (parser); break; case '[': event->type = GVM_JSON_PULL_EVENT_ARRAY_START; @@ -675,7 +683,7 @@ gvm_json_pull_parse_value (gvm_json_pull_parser_t *parser, event->type = GVM_JSON_PULL_EVENT_ARRAY_END; event->value = NULL; gvm_json_pull_path_elem_free (g_queue_pop_tail (parser->path)); - PARSE_VALUE_NEXT_EXPECT + parse_value_next_expect (parser); gvm_json_pull_parser_next_char (parser); break; case '{': @@ -699,7 +707,7 @@ gvm_json_pull_parse_value (gvm_json_pull_parser_t *parser, return 1; event->type = GVM_JSON_PULL_EVENT_NUMBER; event->value = cjson_value; - PARSE_VALUE_NEXT_EXPECT + parse_value_next_expect (parser); } else { @@ -922,7 +930,7 @@ gvm_json_pull_expand_container (gvm_json_pull_parser_t *parser, expanded = cJSON_Parse (parser->parse_buffer->str); g_string_truncate (parser->parse_buffer, 0); - PARSE_VALUE_NEXT_EXPECT + parse_value_next_expect (parser); if (expanded == NULL && error_message) *error_message = g_strdup ("could not parse expanded container"); From ab408d90046ca4ef6c46c56e3a7796a327f04817 Mon Sep 17 00:00:00 2001 From: Timo Pollmeier Date: Fri, 2 Aug 2024 09:12:38 +0200 Subject: [PATCH 09/29] Add end of file newlines, remove extra #undefs --- util/jsonpull.c | 4 ---- util/jsonpull.h | 2 +- util/jsonpull_tests.c | 2 +- 3 files changed, 2 insertions(+), 6 deletions(-) diff --git a/util/jsonpull.c b/util/jsonpull.c index 48aaa237..71b2fe7d 100644 --- a/util/jsonpull.c +++ b/util/jsonpull.c @@ -972,7 +972,3 @@ gvm_json_path_to_string (GQueue *path) g_queue_foreach (path, (GFunc) gvm_json_path_string_add_elem, path_string); return g_string_free (path_string, FALSE); } - -#undef CASE_SPACES -#undef GVM_JSON_EOF -#undef GVM_JSON_ERROR \ No newline at end of file diff --git a/util/jsonpull.h b/util/jsonpull.h index 8d8343a0..0b057a49 100644 --- a/util/jsonpull.h +++ b/util/jsonpull.h @@ -134,4 +134,4 @@ gvm_json_pull_expand_container (gvm_json_pull_parser_t *, gchar **); gchar * gvm_json_path_to_string (GQueue *path); -#endif /* _GVM_JSONPULL_H */ \ No newline at end of file +#endif /* _GVM_JSONPULL_H */ diff --git a/util/jsonpull_tests.c b/util/jsonpull_tests.c index 808c4333..b8a3feed 100644 --- a/util/jsonpull_tests.c +++ b/util/jsonpull_tests.c @@ -1222,4 +1222,4 @@ main (int argc, char **argv) if (argc > 1) return run_single_test (suite, argv[1], create_text_reporter ()); return run_test_suite (suite, create_text_reporter ()); -} \ No newline at end of file +} From 65e9abf654a726cd5e151d4f76cdd2fd86a27563 Mon Sep 17 00:00:00 2001 From: Timo Pollmeier Date: Fri, 2 Aug 2024 09:17:23 +0200 Subject: [PATCH 10/29] Remove trailing space in doc comment --- util/jsonpull.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/jsonpull.c b/util/jsonpull.c index 71b2fe7d..4037b64e 100644 --- a/util/jsonpull.c +++ b/util/jsonpull.c @@ -461,7 +461,7 @@ gvm_json_pull_parse_keyword (gvm_json_pull_parser_t *parser, /** * @brief Updates the expectation for a JSON pull parser according to the path. - * + * * @param[in] parser The parser to update. */ static void From 49de1904dee24a64494fef23bdf33178a3548901 Mon Sep 17 00:00:00 2001 From: Timo Pollmeier Date: Fri, 2 Aug 2024 09:30:33 +0200 Subject: [PATCH 11/29] Add missing semicolons after macros in JSON parser --- util/jsonpull_tests.c | 192 +++++++++++++++++++++--------------------- 1 file changed, 96 insertions(+), 96 deletions(-) diff --git a/util/jsonpull_tests.c b/util/jsonpull_tests.c index b8a3feed..444f5a66 100644 --- a/util/jsonpull_tests.c +++ b/util/jsonpull_tests.c @@ -115,7 +115,7 @@ Ensure (jsonpull, can_parse_false) gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_EOF)); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, can_parse_true) @@ -129,7 +129,7 @@ Ensure (jsonpull, can_parse_true) gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_EOF)); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, can_parse_null) @@ -142,12 +142,12 @@ Ensure (jsonpull, can_parse_null) gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_EOF)); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, can_parse_empty_strings) { - INIT_JSON_PARSER ("\"\"") + INIT_JSON_PARSER ("\"\""); gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_STRING)); @@ -155,12 +155,12 @@ Ensure (jsonpull, can_parse_empty_strings) gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_EOF)); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, can_parse_strings_with_content) { - INIT_JSON_PARSER ("\n\"123\\tXYZ\\nÄöü\"\n") + INIT_JSON_PARSER ("\n\"123\\tXYZ\\nÄöü\"\n"); gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_STRING)); @@ -168,12 +168,12 @@ Ensure (jsonpull, can_parse_strings_with_content) gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_EOF)); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, can_parse_integer_numbers) { - INIT_JSON_PARSER ("-0987") + INIT_JSON_PARSER ("-0987"); gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_NUMBER)); @@ -181,7 +181,7 @@ Ensure (jsonpull, can_parse_integer_numbers) gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_EOF)); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, can_parse_floating_point_numbers) @@ -194,7 +194,7 @@ Ensure (jsonpull, can_parse_floating_point_numbers) gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_EOF)); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, can_parse_empty_arrays) @@ -209,7 +209,7 @@ Ensure (jsonpull, can_parse_empty_arrays) gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_EOF)); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, can_parse_single_elem_arrays) @@ -223,14 +223,14 @@ Ensure (jsonpull, can_parse_single_elem_arrays) gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_NUMBER)); assert_that (event.value->valueint, is_equal_to (123)); - CHECK_PATH_EQUALS ("$[0]") + CHECK_PATH_EQUALS ("$[0]"); gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_END)); gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_EOF)); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, can_parse_multiple_elem_arrays) @@ -244,23 +244,23 @@ Ensure (jsonpull, can_parse_multiple_elem_arrays) gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_NUMBER)); assert_that (event.value->valueint, is_equal_to (123)); - CHECK_PATH_EQUALS ("$[0]") + CHECK_PATH_EQUALS ("$[0]"); gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_STRING)); assert_that (event.value->valuestring, is_equal_to_string ("ABC")); - CHECK_PATH_EQUALS ("$[1]") + CHECK_PATH_EQUALS ("$[1]"); gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_NULL)); - CHECK_PATH_EQUALS ("$[2]") + CHECK_PATH_EQUALS ("$[2]"); gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_END)); gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_EOF)); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, can_parse_empty_objects) @@ -275,7 +275,7 @@ Ensure (jsonpull, can_parse_empty_objects) gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_EOF)); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, can_parse_single_elem_objects) @@ -289,14 +289,14 @@ Ensure (jsonpull, can_parse_single_elem_objects) gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_STRING)); assert_that (event.value->valuestring, is_equal_to_string ("valueA")); - CHECK_PATH_EQUALS ("$['keyA']") + CHECK_PATH_EQUALS ("$['keyA']"); gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_OBJECT_END)); gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_EOF)); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, can_parse_multiple_elem_objects) @@ -310,19 +310,19 @@ Ensure (jsonpull, can_parse_multiple_elem_objects) gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_STRING)); assert_that (event.value->valuestring, is_equal_to_string ("valueA")); - CHECK_PATH_EQUALS ("$['keyA']") + CHECK_PATH_EQUALS ("$['keyA']"); gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_NUMBER)); assert_that (event.value->valueint, is_equal_to (12345)); - CHECK_PATH_EQUALS ("$['keyB']") + CHECK_PATH_EQUALS ("$['keyB']"); gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_OBJECT_END)); gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_EOF)); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, can_parse_nested_containers) @@ -332,71 +332,71 @@ Ensure (jsonpull, can_parse_nested_containers) gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_START)); - CHECK_PATH_EQUALS ("$") + CHECK_PATH_EQUALS ("$"); gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_OBJECT_START)); - CHECK_PATH_EQUALS ("$[0]") + CHECK_PATH_EQUALS ("$[0]"); gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_NULL)); - CHECK_PATH_EQUALS ("$[0]['A']") + CHECK_PATH_EQUALS ("$[0]['A']"); gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_OBJECT_START)); - CHECK_PATH_EQUALS ("$[0]['B']") + CHECK_PATH_EQUALS ("$[0]['B']"); gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_START)); - CHECK_PATH_EQUALS ("$[0]['B']['C']") + CHECK_PATH_EQUALS ("$[0]['B']['C']"); gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_NUMBER)); assert_that (event.value->valueint, is_equal_to (1)); - CHECK_PATH_EQUALS ("$[0]['B']['C'][0]") + CHECK_PATH_EQUALS ("$[0]['B']['C'][0]"); gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_NUMBER)); assert_that (event.value->valueint, is_equal_to (2)); - CHECK_PATH_EQUALS ("$[0]['B']['C'][1]") + CHECK_PATH_EQUALS ("$[0]['B']['C'][1]"); gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_END)); - CHECK_PATH_EQUALS ("$[0]['B']['C']") + CHECK_PATH_EQUALS ("$[0]['B']['C']"); gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_OBJECT_END)); - CHECK_PATH_EQUALS ("$[0]['B']") + CHECK_PATH_EQUALS ("$[0]['B']"); gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_STRING)); assert_that (event.value->valuestring, is_equal_to_string ("3")); - CHECK_PATH_EQUALS ("$[0]['D']") + CHECK_PATH_EQUALS ("$[0]['D']"); gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_OBJECT_END)); - CHECK_PATH_EQUALS ("$[0]") + CHECK_PATH_EQUALS ("$[0]"); gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_START)); - CHECK_PATH_EQUALS ("$[1]") + CHECK_PATH_EQUALS ("$[1]"); gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_NUMBER)); assert_that (event.value->valueint, is_equal_to (4)); - CHECK_PATH_EQUALS ("$[1][0]") + CHECK_PATH_EQUALS ("$[1][0]"); gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_END)); - CHECK_PATH_EQUALS ("$[1]") + CHECK_PATH_EQUALS ("$[1]"); gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_END)); - CHECK_PATH_EQUALS ("$") + CHECK_PATH_EQUALS ("$"); gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_EOF)); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, can_expand_arrays) @@ -407,12 +407,12 @@ Ensure (jsonpull, can_expand_arrays) gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_START)); - CHECK_PATH_EQUALS ("$") + CHECK_PATH_EQUALS ("$"); // empty array gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_START)); - CHECK_PATH_EQUALS ("$[0]") + CHECK_PATH_EQUALS ("$[0]"); expanded = gvm_json_pull_expand_container (&parser, &error_message); assert_that (error_message, is_equal_to_string (NULL)); assert_that (expanded, is_not_null); @@ -423,7 +423,7 @@ Ensure (jsonpull, can_expand_arrays) // single-element array gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_START)); - CHECK_PATH_EQUALS ("$[1]") + CHECK_PATH_EQUALS ("$[1]"); expanded = gvm_json_pull_expand_container (&parser, &error_message); assert_that (error_message, is_null); assert_that (expanded, is_not_null); @@ -439,7 +439,7 @@ Ensure (jsonpull, can_expand_arrays) // multi-element array gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_START)); - CHECK_PATH_EQUALS ("$[2]") + CHECK_PATH_EQUALS ("$[2]"); expanded = gvm_json_pull_expand_container (&parser, &error_message); assert_that (error_message, is_null); assert_that (expanded, is_not_null); @@ -457,7 +457,7 @@ Ensure (jsonpull, can_expand_arrays) // string array gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_START)); - CHECK_PATH_EQUALS ("$[3]") + CHECK_PATH_EQUALS ("$[3]"); expanded = gvm_json_pull_expand_container (&parser, &error_message); assert_that (error_message, is_null); assert_that (expanded, is_not_null); @@ -475,11 +475,11 @@ Ensure (jsonpull, can_expand_arrays) // array end and EOF gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ARRAY_END)); - CHECK_PATH_EQUALS ("$") + CHECK_PATH_EQUALS ("$"); gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_EOF)); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, can_expand_objects) @@ -491,11 +491,11 @@ Ensure (jsonpull, can_expand_objects) gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_OBJECT_START)); - CHECK_PATH_EQUALS ("$") + CHECK_PATH_EQUALS ("$"); gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_OBJECT_START)); - CHECK_PATH_EQUALS ("$['A']") + CHECK_PATH_EQUALS ("$['A']"); expanded = gvm_json_pull_expand_container (&parser, &error_message); assert_that (error_message, is_null); assert_that (cJSON_IsObject (expanded), is_true); @@ -504,7 +504,7 @@ Ensure (jsonpull, can_expand_objects) gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_OBJECT_START)); - CHECK_PATH_EQUALS ("$['B']") + CHECK_PATH_EQUALS ("$['B']"); expanded = gvm_json_pull_expand_container (&parser, &error_message); assert_that (error_message, is_null); assert_that (cJSON_IsObject (expanded), is_true); @@ -528,16 +528,16 @@ Ensure (jsonpull, can_expand_objects) // object end and EOF gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_OBJECT_END)); - CHECK_PATH_EQUALS ("$") + CHECK_PATH_EQUALS ("$"); gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_EOF)); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, fails_for_read_error) { - INIT_READ_ERROR_JSON_PARSER ("123") + INIT_READ_ERROR_JSON_PARSER ("123"); gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); @@ -555,7 +555,7 @@ Ensure (jsonpull, fails_for_misspelled_true) assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); assert_that (event.error_message, is_equal_to_string ("misspelled keyword 'true'")); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, fails_for_incomplete_true) @@ -565,7 +565,7 @@ Ensure (jsonpull, fails_for_incomplete_true) gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); assert_that (event.error_message, is_equal_to_string ("unexpected EOF")); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, fails_for_misspelled_false) @@ -576,7 +576,7 @@ Ensure (jsonpull, fails_for_misspelled_false) assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); assert_that (event.error_message, is_equal_to_string ("misspelled keyword 'false'")); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, fails_for_misspelled_null) @@ -587,7 +587,7 @@ Ensure (jsonpull, fails_for_misspelled_null) assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); assert_that (event.error_message, is_equal_to_string ("misspelled keyword 'null'")); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, fails_for_string_read_error) @@ -597,7 +597,7 @@ Ensure (jsonpull, fails_for_string_read_error) gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); assert_that (event.error_message, is_equal_to_string (JSON_READ_ERROR)); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, fails_for_string_eof) @@ -607,7 +607,7 @@ Ensure (jsonpull, fails_for_string_eof) gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); assert_that (event.error_message, is_equal_to_string ("unexpected EOF")); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, fails_for_overlong_string) @@ -619,7 +619,7 @@ Ensure (jsonpull, fails_for_overlong_string) assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); assert_that (event.error_message, is_equal_to_string ("string exceeds size limit of 10 bytes")); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, fails_for_invalid_string) @@ -630,7 +630,7 @@ Ensure (jsonpull, fails_for_invalid_string) assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); assert_that (event.error_message, is_equal_to_string ("error parsing string")); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, fails_for_number_read_error) @@ -640,7 +640,7 @@ Ensure (jsonpull, fails_for_number_read_error) gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); assert_that (event.error_message, is_equal_to_string (JSON_READ_ERROR)); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, fails_for_overlong_number) @@ -652,7 +652,7 @@ Ensure (jsonpull, fails_for_overlong_number) assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); assert_that (event.error_message, is_equal_to_string ("number exceeds size limit of 10 bytes")); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, fails_for_invalid_number) @@ -663,7 +663,7 @@ Ensure (jsonpull, fails_for_invalid_number) assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); assert_that (event.error_message, is_equal_to_string ("error parsing number")); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, fails_for_array_eof) @@ -675,7 +675,7 @@ Ensure (jsonpull, fails_for_array_eof) gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); assert_that (event.error_message, is_equal_to_string ("unexpected EOF")); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, fails_for_array_eof_after_value) @@ -689,7 +689,7 @@ Ensure (jsonpull, fails_for_array_eof_after_value) gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); assert_that (event.error_message, is_equal_to_string ("unexpected EOF")); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, fails_for_array_eof_after_comma) @@ -703,7 +703,7 @@ Ensure (jsonpull, fails_for_array_eof_after_comma) gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); assert_that (event.error_message, is_equal_to_string ("unexpected EOF")); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, fails_for_array_read_error) @@ -715,7 +715,7 @@ Ensure (jsonpull, fails_for_array_read_error) gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); assert_that (event.error_message, is_equal_to_string (JSON_READ_ERROR)); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, fails_for_invalid_array_bracket) @@ -728,7 +728,7 @@ Ensure (jsonpull, fails_for_invalid_array_bracket) assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); assert_that (event.error_message, is_equal_to_string ("unexpected closing curly brace")); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, fails_for_invalid_array_bracket_after_value) @@ -743,7 +743,7 @@ Ensure (jsonpull, fails_for_invalid_array_bracket_after_value) assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); assert_that (event.error_message, is_equal_to_string ("unexpected closing curly brace")); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, fails_for_invalid_array_other_char) @@ -756,7 +756,7 @@ Ensure (jsonpull, fails_for_invalid_array_other_char) assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); assert_that (event.error_message, is_equal_to_string ("unexpected character")); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, fails_for_invalid_array_other_char_after_value) @@ -771,7 +771,7 @@ Ensure (jsonpull, fails_for_invalid_array_other_char_after_value) assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); assert_that (event.error_message, is_equal_to_string ("expected comma or end of container")); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, fails_for_object_key_eof) @@ -783,7 +783,7 @@ Ensure (jsonpull, fails_for_object_key_eof) gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); assert_that (event.error_message, is_equal_to_string ("unexpected EOF")); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, fails_for_object_key_read_error) @@ -795,7 +795,7 @@ Ensure (jsonpull, fails_for_object_key_read_error) gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); assert_that (event.error_message, is_equal_to_string (JSON_READ_ERROR)); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, fails_for_object_key_invalid_string) @@ -808,7 +808,7 @@ Ensure (jsonpull, fails_for_object_key_invalid_string) assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); assert_that (event.error_message, is_equal_to_string ("error parsing string")); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, fails_for_invalid_object_key_bracket) @@ -821,7 +821,7 @@ Ensure (jsonpull, fails_for_invalid_object_key_bracket) assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); assert_that (event.error_message, is_equal_to_string ("unexpected closing square bracket")); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, fails_for_invalid_object_key_other_char) @@ -834,7 +834,7 @@ Ensure (jsonpull, fails_for_invalid_object_key_other_char) assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); assert_that (event.error_message, is_equal_to_string ("unexpected character")); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, fails_for_object_colon_eof) @@ -846,7 +846,7 @@ Ensure (jsonpull, fails_for_object_colon_eof) gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); assert_that (event.error_message, is_equal_to_string ("unexpected EOF")); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, fails_for_object_colon_read_error) @@ -858,7 +858,7 @@ Ensure (jsonpull, fails_for_object_colon_read_error) gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); assert_that (event.error_message, is_equal_to_string (JSON_READ_ERROR)); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, fails_for_object_colon_other_char) @@ -870,7 +870,7 @@ Ensure (jsonpull, fails_for_object_colon_other_char) gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); assert_that (event.error_message, is_equal_to_string ("expected colon")); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, fails_for_object_value_eof) @@ -882,7 +882,7 @@ Ensure (jsonpull, fails_for_object_value_eof) gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); assert_that (event.error_message, is_equal_to_string ("unexpected EOF")); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, fails_for_object_value_read_error) @@ -894,7 +894,7 @@ Ensure (jsonpull, fails_for_object_value_read_error) gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); assert_that (event.error_message, is_equal_to_string (JSON_READ_ERROR)); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, fails_for_object_value_curly_brace) @@ -907,7 +907,7 @@ Ensure (jsonpull, fails_for_object_value_curly_brace) assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); assert_that (event.error_message, is_equal_to_string ("unexpected closing curly brace")); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, fails_for_object_value_square_bracket) @@ -920,7 +920,7 @@ Ensure (jsonpull, fails_for_object_value_square_bracket) assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); assert_that (event.error_message, is_equal_to_string ("unexpected closing square bracket")); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, fails_for_object_eof_after_value) @@ -934,7 +934,7 @@ Ensure (jsonpull, fails_for_object_eof_after_value) gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); assert_that (event.error_message, is_equal_to_string ("unexpected EOF")); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, fails_for_object_square_bracket_after_value) @@ -949,7 +949,7 @@ Ensure (jsonpull, fails_for_object_square_bracket_after_value) assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); assert_that (event.error_message, is_equal_to_string ("unexpected closing square bracket")); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, fails_for_object_eof_after_comma) @@ -963,7 +963,7 @@ Ensure (jsonpull, fails_for_object_eof_after_comma) gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); assert_that (event.error_message, is_equal_to_string ("unexpected EOF")); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, fails_for_read_error_after_doc_end) @@ -975,7 +975,7 @@ Ensure (jsonpull, fails_for_read_error_after_doc_end) gvm_json_pull_parser_next (&parser, &event); assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); assert_that (event.error_message, is_equal_to_string (JSON_READ_ERROR)); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, fails_for_content_after_doc_end) @@ -988,7 +988,7 @@ Ensure (jsonpull, fails_for_content_after_doc_end) assert_that (event.type, is_equal_to (GVM_JSON_PULL_EVENT_ERROR)); assert_that (event.error_message, is_equal_to_string ("unexpected character at end of file (52)")); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, fails_for_expand_before_container) @@ -1002,7 +1002,7 @@ Ensure (jsonpull, fails_for_expand_before_container) assert_that (error_message, is_equal_to_string ("can only expand after" " array or object start")); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, fails_for_expand_after_value) @@ -1021,7 +1021,7 @@ Ensure (jsonpull, fails_for_expand_after_value) assert_that (error_message, is_equal_to_string ("can only expand after" " array or object start")); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, fails_for_expand_invalid_content) @@ -1038,7 +1038,7 @@ Ensure (jsonpull, fails_for_expand_invalid_content) assert_that (error_message, is_equal_to_string ("could not parse expanded container")); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, fails_for_expand_overlong) @@ -1056,7 +1056,7 @@ Ensure (jsonpull, fails_for_expand_overlong) assert_that (error_message, is_equal_to_string ("container exceeds size limit of 10 bytes")); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, fails_for_expand_unexpected_curly_brace) @@ -1073,7 +1073,7 @@ Ensure (jsonpull, fails_for_expand_unexpected_curly_brace) assert_that (error_message, is_equal_to_string ("unexpected closing curly brace")); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, fails_for_expand_unexpected_square_bracket) @@ -1090,7 +1090,7 @@ Ensure (jsonpull, fails_for_expand_unexpected_square_bracket) assert_that (error_message, is_equal_to_string ("unexpected closing square bracket")); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, fails_for_expand_eof) @@ -1106,7 +1106,7 @@ Ensure (jsonpull, fails_for_expand_eof) assert_that (cjson_value, is_null); assert_that (error_message, is_equal_to_string ("unexpected EOF")); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } Ensure (jsonpull, fails_for_expand_read_error) @@ -1122,7 +1122,7 @@ Ensure (jsonpull, fails_for_expand_read_error) assert_that (cjson_value, is_null); assert_that (error_message, is_equal_to_string (JSON_READ_ERROR)); - CLEANUP_JSON_PARSER + CLEANUP_JSON_PARSER; } int From 4869beb93edd0d9dc23cc6db04b3b7e7e05b9123 Mon Sep 17 00:00:00 2001 From: Timo Pollmeier Date: Fri, 2 Aug 2024 12:34:00 +0200 Subject: [PATCH 12/29] Remove stray semicolon in jsonpull.c --- util/jsonpull.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/jsonpull.c b/util/jsonpull.c index 4037b64e..c8b51f86 100644 --- a/util/jsonpull.c +++ b/util/jsonpull.c @@ -25,7 +25,7 @@ gvm_json_string_escape (const char *string, gboolean single_quote) for (point = (char *) string; *point != 0; point++) { unsigned char character = *point; - ; + if ((character > 31) && (character != '\\') && (single_quote || character != '\"') && (!single_quote || character != '\'')) From 4f9d16c23174369e799b303b1deca8c6f849b57e Mon Sep 17 00:00:00 2001 From: Johannes Helmold <83279292+jhelmold@users.noreply.github.com> Date: Wed, 21 Aug 2024 09:32:26 +0200 Subject: [PATCH 13/29] Update util/jsonpull.c Co-authored-by: Matt Mundell <32057441+mattmundell@users.noreply.github.com> --- util/jsonpull.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/jsonpull.c b/util/jsonpull.c index c8b51f86..c2c83c98 100644 --- a/util/jsonpull.c +++ b/util/jsonpull.c @@ -613,7 +613,7 @@ gvm_json_pull_parse_comma (gvm_json_pull_parser_t *parser, } /** - * @brief Handles the case that a value in a JSON pull parser. + * @brief Handles the case that a value is expected in a JSON pull parser. * * This will continue the parsing until a value or the end of the * current array/object was parsed or an error occurred. From 1bc1415da50ede438db17bddb1c7588f7c8a4edc Mon Sep 17 00:00:00 2001 From: Ahmed Abdelsalam Date: Mon, 16 Sep 2024 11:09:55 +0200 Subject: [PATCH 14/29] Apply review comments --- util/jsonpull.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/util/jsonpull.c b/util/jsonpull.c index c2c83c98..03dddf42 100644 --- a/util/jsonpull.c +++ b/util/jsonpull.c @@ -13,6 +13,11 @@ /** * @brief Escapes a string according to the JSON or JSONPath standard + * + * @param[in] string The string to escape + * @param[in] single_quote Whether to escape single quotes + * + * @return The escaped string */ gchar * gvm_json_string_escape (const char *string, gboolean single_quote) @@ -27,8 +32,7 @@ gvm_json_string_escape (const char *string, gboolean single_quote) unsigned char character = *point; if ((character > 31) && (character != '\\') - && (single_quote || character != '\"') - && (!single_quote || character != '\'')) + && (single_quote ? (character != '\'') : (character != '\"'))) { g_string_append_c (escaped, character); } @@ -115,6 +119,8 @@ void gvm_json_pull_event_reset (gvm_json_pull_event_t *event) { cJSON_free (event->value); + if (event->error_message) + g_free (event->error_message); memset (event, 0, sizeof (gvm_json_pull_event_t)); } @@ -127,6 +133,8 @@ void gvm_json_pull_event_cleanup (gvm_json_pull_event_t *event) { cJSON_free (event->value); + if (event->error_message) + g_free (event->error_message); memset (event, 0, sizeof (gvm_json_pull_event_t)); } @@ -230,6 +238,8 @@ gvm_json_pull_check_parse_buffer_size (const char *value_type, /** * @brief Reads the next character in a pull parser input stream. * + * @param[in] parser The parser to read the next character from + * * @return The character code, GVM_JSON_CHAR_ERROR or GVM_JSON_CHAR_EOF. */ static int @@ -773,12 +783,6 @@ gvm_json_pull_parser_next (gvm_json_pull_parser_t *parser, return; } - if (parser->expect == GVM_JSON_PULL_EXPECT_KEY) - { - if (gvm_json_pull_parse_key (parser, event)) - return; - } - if (parser->expect == GVM_JSON_PULL_EXPECT_COMMA) { if (gvm_json_pull_parse_comma (parser, event)) From 73253627a16e89908d3083ce67adbf88b88853dc Mon Sep 17 00:00:00 2001 From: Johannes Helmold Date: Mon, 16 Sep 2024 14:25:18 +0200 Subject: [PATCH 15/29] Some smaller amendments. --- util/versionutils.c | 38 +++++++++++++++++++++++++++++++++++--- util/versionutils.h | 19 ++----------------- 2 files changed, 37 insertions(+), 20 deletions(-) diff --git a/util/versionutils.c b/util/versionutils.c index fc5473c5..98b38525 100644 --- a/util/versionutils.c +++ b/util/versionutils.c @@ -25,6 +25,21 @@ */ #define G_LOG_DOMAIN "libgvm util" +static gchar * +prepare_version_string (const char *); + +static int +get_release_state (const char *, int); + +static char * +get_part (const char *, int); + +static gboolean +is_text (const char *); + +static char * +str_cpy (char *, int); + /** * @brief Compare two version strings representing a software version * to decide which version is newer. @@ -50,6 +65,12 @@ cmp_versions (const char *version1, const char *version2) ver1 = prepare_version_string (version1); ver2 = prepare_version_string (version2); + if (ver1 == NULL || ver2 != NULL) + { + g_free (ver1); + g_free (ver2); + return (-5); + } if (strcmp (ver1, ver2) == 0) { g_free (ver1); @@ -151,17 +172,22 @@ cmp_versions (const char *version1, const char *version2) * * @return Returns a prepared copy of the version string version. */ -static char * +static gchar * prepare_version_string (const char *version) { - char prep_version[1024]; + char prep_version[2048]; char *ver; int index_v, index_pv; gboolean is_digit; + g_message ("PROTO: VERS %s", version); + if (!version) return (NULL); + if (strlen (version) > 1024) + return (NULL); + ver = g_strdup (version); /* set all characters to lowercase */ @@ -173,8 +199,14 @@ prepare_version_string (const char *version) is_digit = g_ascii_isdigit (ver[0]); - while (index_v < (int) strlen (ver)) + while (index_v < (int) strlen (ver) && index_pv < 2047) { + if (ver[index_v] == '\\') + { + index_v++; + continue; + } + if (ver[index_v] == '_' || ver[index_v] == '-' || ver[index_v] == '+' || ver[index_v] == ':' || ver[index_v] == '.') { diff --git a/util/versionutils.h b/util/versionutils.h index d3ac0d3e..d093189c 100644 --- a/util/versionutils.h +++ b/util/versionutils.h @@ -8,8 +8,8 @@ * @brief Headers for version utils. */ -#ifndef _GVM_CPEUTILS_H -#define _GVM_CPEUTILS_H +#ifndef _GVM_VERSIONUTILS_H +#define _GVM_VERSIONUTILS_H #include #include @@ -17,19 +17,4 @@ int cmp_versions (const char *, const char *); -static char * -prepare_version_string (const char *); - -static int -get_release_state (const char *, int); - -static char * -get_part (const char *, int); - -static gboolean -is_text (const char *); - -static char * -str_cpy (char *, int); - #endif From 9e5b689730fd9b599e2887b0dc83cb230f585913 Mon Sep 17 00:00:00 2001 From: Johannes Helmold Date: Mon, 16 Sep 2024 15:50:42 +0200 Subject: [PATCH 16/29] Fixed a small bug. --- util/versionutils.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/util/versionutils.c b/util/versionutils.c index 98b38525..6e65a496 100644 --- a/util/versionutils.c +++ b/util/versionutils.c @@ -65,7 +65,7 @@ cmp_versions (const char *version1, const char *version2) ver1 = prepare_version_string (version1); ver2 = prepare_version_string (version2); - if (ver1 == NULL || ver2 != NULL) + if (ver1 == NULL || ver2 == NULL) { g_free (ver1); g_free (ver2); @@ -180,8 +180,6 @@ prepare_version_string (const char *version) int index_v, index_pv; gboolean is_digit; - g_message ("PROTO: VERS %s", version); - if (!version) return (NULL); From 6c5f650653707bcb899e6f35730b22168ec1b45e Mon Sep 17 00:00:00 2001 From: Johannes Helmold Date: Mon, 16 Sep 2024 15:54:09 +0200 Subject: [PATCH 17/29] Amended some formatting. --- util/versionutils.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/versionutils.c b/util/versionutils.c index 6e65a496..d0a2eb60 100644 --- a/util/versionutils.c +++ b/util/versionutils.c @@ -202,7 +202,7 @@ prepare_version_string (const char *version) if (ver[index_v] == '\\') { index_v++; - continue; + continue; } if (ver[index_v] == '_' || ver[index_v] == '-' || ver[index_v] == '+' From 7d4369da7f4ff11f654d37ad2276ca7826d2b4a7 Mon Sep 17 00:00:00 2001 From: Greenbone Bot Date: Mon, 16 Sep 2024 15:11:48 +0000 Subject: [PATCH 18/29] Automated commit: change version from 22.11.0 -> 22.12.0 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 08d3ab72..ef5f266f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,7 +8,7 @@ message ("-- Configuring the Greenbone Vulnerability Management Libraries...") # VERSION: Always include major, minor and patch level. project (gvm-libs - VERSION 22.11.0 + VERSION 22.12.0 LANGUAGES C) if (POLICY CMP0005) From 4e29aae0190beca86df7e39705322fde17e85fa6 Mon Sep 17 00:00:00 2001 From: Robert Schardt Date: Tue, 17 Sep 2024 14:50:39 +0200 Subject: [PATCH 19/29] Fix: Fix issue DOS-290, by switching from libssh-gcrypt-dev to libgcrypt-dev and adding libssh-dev --- .github/install-dependencies.sh | 3 ++- INSTALL.md | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/install-dependencies.sh b/.github/install-dependencies.sh index aa30d053..e398d287 100755 --- a/.github/install-dependencies.sh +++ b/.github/install-dependencies.sh @@ -13,7 +13,8 @@ apt-get update && \ libgpgme-dev \ libgnutls28-dev \ uuid-dev \ - libssh-gcrypt-dev \ + libgcrypt-dev \ + libssh-dev \ libhiredis-dev \ libxml2-dev \ libpcap-dev \ diff --git a/INSTALL.md b/INSTALL.md index 59c17d2e..4d8f7f91 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -49,7 +49,8 @@ Install prerequisites on Debian GNU/Linux 'Bullseye' 11: libgpgme-dev \ libgnutls28-dev \ uuid-dev \ - libssh-gcrypt-dev \ + libgcrypt-dev \ + libssh-dev \ libhiredis-dev \ libxml2-dev \ libpcap-dev \ From be92502417152f9226f4404eb8d4ab0c21343ba8 Mon Sep 17 00:00:00 2001 From: Greenbone Bot Date: Tue, 17 Sep 2024 14:55:18 +0000 Subject: [PATCH 20/29] Automated commit: change version from 22.12.0 -> 22.12.1 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ef5f266f..b1fde48b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,7 +8,7 @@ message ("-- Configuring the Greenbone Vulnerability Management Libraries...") # VERSION: Always include major, minor and patch level. project (gvm-libs - VERSION 22.12.0 + VERSION 22.12.1 LANGUAGES C) if (POLICY CMP0005) From e971514f2a73b1c5a403f4207766c49c6761ba98 Mon Sep 17 00:00:00 2001 From: robert-schardt Date: Wed, 18 Sep 2024 14:05:43 +0200 Subject: [PATCH 21/29] Fix: Dynamically adapt to workflow file in openvas-scanner repo (#834) Co-authored-by: Robert Schardt --- .github/workflows/container.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/container.yml b/.github/workflows/container.yml index 749e36f1..34f67535 100644 --- a/.github/workflows/container.yml +++ b/.github/workflows/container.yml @@ -180,5 +180,5 @@ jobs: with: token: ${{ secrets.GREENBONE_BOT_TOKEN }} repository: ${{ matrix.repository }} - workflow: container.yml + workflow: ${{ matrix.repository == 'greenbone/openvas-scanner' && 'push-container.yml' || 'container.yml' }} ref: main From 6abe934039ad6f18a10c6e1589673316ad5dcf10 Mon Sep 17 00:00:00 2001 From: robert-schardt Date: Thu, 19 Sep 2024 14:52:47 +0200 Subject: [PATCH 22/29] Fix: Retry and Rename other workflow file for openvas-scanner, DEVOPS-1224 (#835) * Fix: Dynamically adapt to workflow file in openvas-scanner repo * Fix: See if control.yml is the correct workflow for triggering --------- Co-authored-by: Robert Schardt --- .github/workflows/container.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/container.yml b/.github/workflows/container.yml index 34f67535..bba5d6a9 100644 --- a/.github/workflows/container.yml +++ b/.github/workflows/container.yml @@ -180,5 +180,5 @@ jobs: with: token: ${{ secrets.GREENBONE_BOT_TOKEN }} repository: ${{ matrix.repository }} - workflow: ${{ matrix.repository == 'greenbone/openvas-scanner' && 'push-container.yml' || 'container.yml' }} + workflow: ${{ matrix.repository == 'greenbone/openvas-scanner' && 'control.yml' || 'container.yml' }} ref: main From a041b8b9939b3da373f3d438fd6ceddc45c0826d Mon Sep 17 00:00:00 2001 From: Johannes Helmold Date: Thu, 19 Sep 2024 17:17:02 +0200 Subject: [PATCH 23/29] Add: Added functions for the new CPE matching in CVE scans. --- CMakeLists.txt | 4 +- util/CMakeLists.txt | 28 +++---- util/cpeutils.c | 177 ++++++++++++++++++++++++++++++++++++++++++++ util/cpeutils.h | 76 ++++--------------- 4 files changed, 206 insertions(+), 79 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b1fde48b..bfcb3a8a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -230,8 +230,8 @@ if (BUILD_TESTS AND NOT SKIP_SRC) add_custom_target (tests DEPENDS array-test alivedetection-test boreas_error-test boreas_io-test cli-test cpeutils-test cvss-test ping-test sniffer-test util-test networking-test - passwordbasedauthentication-test xmlutils-test version-test osp-test - versionutils-test nvti-test hosts-test jsonpull-test) + passwordbasedauthentication-test xmlutils-test version-test versionutils-test + osp-test nvti-test hosts-test jsonpull-test) endif (BUILD_TESTS AND NOT SKIP_SRC) diff --git a/util/CMakeLists.txt b/util/CMakeLists.txt index c43d9de3..9110b249 100644 --- a/util/CMakeLists.txt +++ b/util/CMakeLists.txt @@ -114,11 +114,11 @@ include_directories (${GLIB_INCLUDE_DIRS} ${GPGME_INCLUDE_DIRS} ${GCRYPT_INCLUDE set (FILES cpeutils.c passwordbasedauthentication.c compressutils.c fileutils.c gpgmeutils.c kb.c ldaputils.c nvticache.c mqtt.c radiusutils.c serverutils.c sshutils.c uuidutils.c versionutils.c - xmlutils.c jsonpull.c) + xmlutils.c) set (HEADERS cpeutils.h passwordbasedauthentication.h authutils.h compressutils.h fileutils.h gpgmeutils.h kb.h ldaputils.h nvticache.h mqtt.h radiusutils.h serverutils.h sshutils.h - uuidutils.h xmlutils.h jsonpull.h versionutils.h) + uuidutils.h versionutils.h xmlutils.h) if (BUILD_STATIC) add_library (gvm_util_static STATIC ${FILES}) @@ -190,10 +190,10 @@ if (BUILD_TESTS) target_link_libraries (cpeutils-test ${CGREEN_LIBRARIES} ${GLIB_LDFLAGS} ${GIO_LDFLAGS} ${GPGME_LDFLAGS} ${ZLIB_LDFLAGS} - ${RADIUS_LDFLAGS} ${LIBSSH_LDFLAGS} ${GNUTLS_LDFLAGS} - ${GCRYPT_LDFLAGS} ${LDAP_LDFLAGS} ${REDIS_LDFLAGS} - ${LIBXML2_LDFLAGS} ${UUID_LDFLAGS} - ${LINKER_HARDENING_FLAGS}) + ${RADIUS_LDFLAGS} ${LIBSSH_LDFLAGS} ${GNUTLS_LDFLAGS} + ${GCRYPT_LDFLAGS} ${LDAP_LDFLAGS} ${REDIS_LDFLAGS} + ${LIBXML2_LDFLAGS} ${UUID_LDFLAGS} + ${LINKER_HARDENING_FLAGS}) add_custom_target (tests-cpeutils DEPENDS cpeutils-test) @@ -208,10 +208,10 @@ if (BUILD_TESTS) target_link_libraries (versionutils-test ${CGREEN_LIBRARIES} ${GLIB_LDFLAGS} ${GIO_LDFLAGS} ${GPGME_LDFLAGS} ${ZLIB_LDFLAGS} - ${RADIUS_LDFLAGS} ${LIBSSH_LDFLAGS} ${GNUTLS_LDFLAGS} - ${GCRYPT_LDFLAGS} ${LDAP_LDFLAGS} ${REDIS_LDFLAGS} - ${LIBXML2_LDFLAGS} ${UUID_LDFLAGS} - ${LINKER_HARDENING_FLAGS}) + ${RADIUS_LDFLAGS} ${LIBSSH_LDFLAGS} ${GNUTLS_LDFLAGS} + ${GCRYPT_LDFLAGS} ${LDAP_LDFLAGS} ${REDIS_LDFLAGS} + ${LIBXML2_LDFLAGS} ${UUID_LDFLAGS} + ${LINKER_HARDENING_FLAGS}) add_custom_target (tests-versionutils DEPENDS versionutils-test) @@ -226,10 +226,10 @@ if (BUILD_TESTS) target_link_libraries (xmlutils-test ${CGREEN_LIBRARIES} ${GLIB_LDFLAGS} ${GIO_LDFLAGS} ${GPGME_LDFLAGS} ${ZLIB_LDFLAGS} - ${RADIUS_LDFLAGS} ${LIBSSH_LDFLAGS} ${GNUTLS_LDFLAGS} - ${GCRYPT_LDFLAGS} ${LDAP_LDFLAGS} ${REDIS_LDFLAGS} - ${LIBXML2_LDFLAGS} ${UUID_LDFLAGS} - ${LINKER_HARDENING_FLAGS}) + ${RADIUS_LDFLAGS} ${LIBSSH_LDFLAGS} ${GNUTLS_LDFLAGS} + ${GCRYPT_LDFLAGS} ${LDAP_LDFLAGS} ${REDIS_LDFLAGS} + ${LIBXML2_LDFLAGS} ${UUID_LDFLAGS} + ${LINKER_HARDENING_FLAGS}) add_custom_target (tests-xmlutils DEPENDS xmlutils-test) diff --git a/util/cpeutils.c b/util/cpeutils.c index a42a7261..904ca321 100644 --- a/util/cpeutils.c +++ b/util/cpeutils.c @@ -29,6 +29,69 @@ */ #define G_LOG_DOMAIN "libgvm util" +static enum set_relation +compare_component (const char *, const char *); + +static enum set_relation +compare_strings (const char *, const char *); + +static int +count_escapes (const char *, int, int); + +static gboolean +is_even_wildcards (const char *, int); + +static gboolean +has_wildcards (const char *); + +static int +index_of (const char *, const char *, int); + +static gboolean +is_string (const char *); + +static char * +get_uri_component (const char *, int); + +static char * +decode_uri_component (const char *); + +static void +unpack_sixth_uri_component (const char *, cpe_struct_t *); + +static char * +get_fs_component (const char *, int); + +static char * +unbind_fs_component (char *); + +static char * +add_quoting (const char *); + +static char * +bind_cpe_component_for_uri (const char *); + +static char * +transform_for_uri (const char *); + +static char * +pack_sixth_uri_component (const cpe_struct_t *); + +static char * +bind_cpe_component_for_fs (const char *); + +static char * +process_quoted_chars (const char *); + +static void +trim_pct (char *); + +static void +get_code (char *, const char *); + +static void +str_cpy (char **, const char *, int); + /** * @brief Convert a URI CPE to a formatted string CPE. * @@ -49,6 +112,26 @@ uri_cpe_to_fs_cpe (const char *uri_cpe) return (fs_cpe); } +/** + * @brief Convert a URI CPE to a formatted string product. + * + * @param[in] uri_cpe A CPE v2.2-conformant URI. + * + * @return A formatted string product. + */ +char * +uri_cpe_to_fs_product (const char *uri_cpe) +{ + cpe_struct_t cpe; + char *fs_cpe; + + cpe_struct_init (&cpe); + uri_cpe_to_cpe_struct (uri_cpe, &cpe); + fs_cpe = cpe_struct_to_fs_product (&cpe); + cpe_struct_free (&cpe); + return (fs_cpe); +} + /** * @brief Convert a formatted string CPE to a URI CPE. * @@ -69,6 +152,26 @@ fs_cpe_to_uri_cpe (const char *fs_cpe) return (uri_cpe); } +/** + * @brief Convert a formatted string CPE to an URI product. + * + * @param[in] fs_cpe A formatted string CPE. + * + * @return An URI product. + */ +char * +fs_cpe_to_uri_product (const char *fs_cpe) +{ + cpe_struct_t cpe; + char *uri_cpe; + + cpe_struct_init (&cpe); + fs_cpe_to_cpe_struct (fs_cpe, &cpe); + uri_cpe = cpe_struct_to_uri_product (&cpe); + cpe_struct_free (&cpe); + return (uri_cpe); +} + /** * @brief Read a URI CPE into the CPE struct. * @@ -171,6 +274,44 @@ cpe_struct_to_uri_cpe (const cpe_struct_t *cpe) return (result); } +/** + * @brief Convert a CPE struct into a URI product. + * + * @param[in] cpe A pointer to the CPE struct. + * + * @return A CPE v2.2-conformant URI product. + */ +char * +cpe_struct_to_uri_product (const cpe_struct_t *cpe) +{ + GString *uri_cpe; + char *bind_cpe_component; + uri_cpe = g_string_new ("cpe:/"); + + bind_cpe_component = bind_cpe_component_for_uri (cpe->part); + if (bind_cpe_component) + { + g_string_append_printf (uri_cpe, "%s:", bind_cpe_component); + g_free (bind_cpe_component); + } + bind_cpe_component = bind_cpe_component_for_uri (cpe->vendor); + if (bind_cpe_component) + { + g_string_append_printf (uri_cpe, "%s:", bind_cpe_component); + g_free (bind_cpe_component); + } + bind_cpe_component = bind_cpe_component_for_uri (cpe->product); + if (bind_cpe_component) + { + g_string_append_printf (uri_cpe, "%s:", bind_cpe_component); + g_free (bind_cpe_component); + } + + char *result = g_string_free (uri_cpe, FALSE); + trim_pct (result); + return (result); +} + /** * @brief Read a formatted string CPE into the CPE struct. * @@ -301,6 +442,42 @@ cpe_struct_to_fs_cpe (const cpe_struct_t *cpe) return (g_string_free (fs_cpe, FALSE)); } +/** + * @brief Convert a CPE struct into a formatted string product. + * + * @param[in] cpe A pointer to the CPE struct. + * + * @return A formatted string product. + */ +char * +cpe_struct_to_fs_product (const cpe_struct_t *cpe) +{ + GString *fs_cpe; + char *bind_cpe_component; + + fs_cpe = g_string_new ("cpe:2.3:"); + + bind_cpe_component = bind_cpe_component_for_fs (cpe->part); + if (bind_cpe_component) + { + g_string_append_printf (fs_cpe, "%s:", bind_cpe_component); + g_free (bind_cpe_component); + } + bind_cpe_component = bind_cpe_component_for_fs (cpe->vendor); + if (bind_cpe_component) + { + g_string_append_printf (fs_cpe, "%s:", bind_cpe_component); + g_free (bind_cpe_component); + } + bind_cpe_component = bind_cpe_component_for_fs (cpe->product); + if (bind_cpe_component) + { + g_string_append_printf (fs_cpe, "%s:", bind_cpe_component); + g_free (bind_cpe_component); + } + return (g_string_free (fs_cpe, FALSE)); +} + /** * @brief Get the indexth component of a URI CPE. * diff --git a/util/cpeutils.h b/util/cpeutils.h index 2aabcb43..53297a55 100644 --- a/util/cpeutils.h +++ b/util/cpeutils.h @@ -37,53 +37,32 @@ typedef struct char * uri_cpe_to_fs_cpe (const char *); +char * +uri_cpe_to_fs_product (const char *); + char * fs_cpe_to_uri_cpe (const char *); +char * +fs_cpe_to_uri_product (const char *); + void uri_cpe_to_cpe_struct (const char *, cpe_struct_t *); char * cpe_struct_to_uri_cpe (const cpe_struct_t *); +char * +cpe_struct_to_uri_product (const cpe_struct_t *); + void fs_cpe_to_cpe_struct (const char *, cpe_struct_t *); char * cpe_struct_to_fs_cpe (const cpe_struct_t *); -static char * -get_uri_component (const char *, int); - -static char * -decode_uri_component (const char *); - -static void -unpack_sixth_uri_component (const char *, cpe_struct_t *); - -static char * -get_fs_component (const char *, int); - -static char * -unbind_fs_component (char *); - -static char * -add_quoting (const char *); - -static char * -bind_cpe_component_for_uri (const char *); - -static char * -transform_for_uri (const char *); - -static char * -pack_sixth_uri_component (const cpe_struct_t *); - -static char * -bind_cpe_component_for_fs (const char *); - -static char * -process_quoted_chars (const char *); +char * +cpe_struct_to_fs_product (const cpe_struct_t *); void cpe_struct_init (cpe_struct_t *); @@ -91,14 +70,8 @@ cpe_struct_init (cpe_struct_t *); void cpe_struct_free (cpe_struct_t *); -static void -trim_pct (char *); - -static void -get_code (char *, const char *); - -static void -str_cpy (char **, const char *, int); +gboolean +cpe_struct_match (cpe_struct_t source, cpe_struct_t target); enum set_relation { @@ -109,27 +82,4 @@ enum set_relation UNDEFINED }; -gboolean -cpe_struct_match (cpe_struct_t source, cpe_struct_t target); - -static enum set_relation -compare_component (const char *, const char *); - -static enum set_relation -compare_strings (const char *, const char *); - -static int -count_escapes (const char *, int, int); - -static gboolean -is_even_wildcards (const char *, int); - -static gboolean -has_wildcards (const char *); - -static int -index_of (const char *, const char *, int); - -static gboolean -is_string (const char *); #endif From 1bc955d056deccb1e597df8e27603b9faef95ea8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Jos=C3=A9=20Nicola?= Date: Thu, 19 Sep 2024 18:58:14 +0200 Subject: [PATCH 24/29] Fix CI dependency libssh (#836) --- .docker/prod-testing.Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.docker/prod-testing.Dockerfile b/.docker/prod-testing.Dockerfile index b0510ff6..f74d9dbc 100644 --- a/.docker/prod-testing.Dockerfile +++ b/.docker/prod-testing.Dockerfile @@ -21,7 +21,7 @@ RUN apt-get update && \ libgpgme11 \ libgnutls30 \ libuuid1 \ - libssh-gcrypt-4 \ + libssh-dev \ libhiredis1.1.0 \ libhiredis-dev \ libxml2 \ From 0397ba0d6f805301e23ada905041583e18ae4e43 Mon Sep 17 00:00:00 2001 From: Johannes Helmold Date: Fri, 20 Sep 2024 10:14:13 +0200 Subject: [PATCH 25/29] Added jsonpull.c and jsonpull.h to CMakeLists.txt. --- util/CMakeLists.txt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/util/CMakeLists.txt b/util/CMakeLists.txt index 9110b249..f352575c 100644 --- a/util/CMakeLists.txt +++ b/util/CMakeLists.txt @@ -112,12 +112,12 @@ endif (BUILD_WITH_LDAP) include_directories (${GLIB_INCLUDE_DIRS} ${GPGME_INCLUDE_DIRS} ${GCRYPT_INCLUDE_DIRS} ${LIBXML2_INCLUDE_DIRS}) -set (FILES cpeutils.c passwordbasedauthentication.c compressutils.c fileutils.c gpgmeutils.c kb.c ldaputils.c - nvticache.c mqtt.c radiusutils.c serverutils.c sshutils.c uuidutils.c versionutils.c +set (FILES cpeutils.c passwordbasedauthentication.c compressutils.c fileutils.c gpgmeutils.c jsonpull.c kb.c + ldaputils.c nvticache.c mqtt.c radiusutils.c serverutils.c sshutils.c uuidutils.c versionutils.c xmlutils.c) -set (HEADERS cpeutils.h passwordbasedauthentication.h authutils.h compressutils.h fileutils.h gpgmeutils.h kb.h - ldaputils.h nvticache.h mqtt.h radiusutils.h serverutils.h sshutils.h +set (HEADERS cpeutils.h passwordbasedauthentication.h authutils.h compressutils.h fileutils.h gpgmeutils.h + jsonpull.h kb.h ldaputils.h nvticache.h mqtt.h radiusutils.h serverutils.h sshutils.h uuidutils.h versionutils.h xmlutils.h) if (BUILD_STATIC) From 7a2e624fdfeea00d274edd7d5bc04933f484e8ab Mon Sep 17 00:00:00 2001 From: Greenbone Bot Date: Mon, 23 Sep 2024 11:39:00 +0000 Subject: [PATCH 26/29] Automated commit: change version from 22.12.1 -> 22.12.2 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index bfcb3a8a..8368928e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,7 +8,7 @@ message ("-- Configuring the Greenbone Vulnerability Management Libraries...") # VERSION: Always include major, minor and patch level. project (gvm-libs - VERSION 22.12.1 + VERSION 22.12.2 LANGUAGES C) if (POLICY CMP0005) From 86eb21e71ffd4c632511f065c4a12125429e66ba Mon Sep 17 00:00:00 2001 From: robert-schardt Date: Fri, 27 Sep 2024 07:35:42 +0200 Subject: [PATCH 27/29] Refactor container.yml (#838) * Refactor container.yml Refactor 'set IS_VERSION_TAG' into determine-tags-action composite action * Fix: determine-tags-action by adding shell attribute to steps * Refactor/Fix: Move docker setup to seperate composite action * Fix: setup-docker-action by adding secrets as inputs * Update: Merge container.yml and push.yml * Remove deprecated Actions and Workflows * Update: Remove stable, oldstable branches from CI trigger * Trigger CI * Change: Add base-image-label for oldstable and testing --------- Co-authored-by: Robert Schardt --- .github/workflows/container.yml | 184 -------------------------------- .github/workflows/push.yml | 78 +++++++++++++- 2 files changed, 75 insertions(+), 187 deletions(-) delete mode 100644 .github/workflows/container.yml diff --git a/.github/workflows/container.yml b/.github/workflows/container.yml deleted file mode 100644 index bba5d6a9..00000000 --- a/.github/workflows/container.yml +++ /dev/null @@ -1,184 +0,0 @@ -name: Container Image Builds - -on: - push: - branches: [main, stable, oldstable] - tags: ["v*"] - pull_request: - branches: [main, stable, oldstable] - workflow_dispatch: - -jobs: - production: - name: Production Images - runs-on: ubuntu-latest - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - name: "set IS_VERSION_TAG" - run: | - echo "IS_VERSION_TAG=${{ github.ref_type == 'tag' && startsWith(github.ref_name, 'v') }}" >> $GITHUB_ENV - # set defaults - echo "IS_LATEST_TAG=false" >> $GITHUB_ENV - - name: "set IS_LATEST_TAG" - if: ( env.IS_VERSION_TAG ) - run: | - # find the latest version that is not ourself - export LATEST_VERSION=$(git tag -l | grep -v '${{ github.ref_name }}' | sort -r --version-sort) - # get major minor patch versions - IFS='.' read -r latest_major latest_minor latest_patch << EOF - $LATEST_VERSION - EOF - IFS='.' read -r tag_major tag_minor tag_patch << EOF - ${{ github.ref_name }} - EOF - # remove leading v - latest_major=$(echo $latest_major | cut -c2-) - tag_major=$(echo $tag_major | cut -c2-) - echo "$tag_major >= $latest_major" - if [[ $tag_major -ge $latest_major && ($tag_minor -ne 0 || $tag_patch -ne 0) ]]; then - # set this tag to latest and stable - echo "IS_LATEST_TAG=true" >> $GITHUB_ENV - fi - - name: "Setup meta information debian:stable" - id: meta - uses: docker/metadata-action@v5 - with: - images: ${{ github.repository }} - labels: | - org.opencontainers.image.vendor=Greenbone - org.opencontainers.image.base.name=debian:stable-slim - flavor: latest=false # no auto latest container tag for git tags - tags: | - # when IS_LATEST_TAG is set create a stable and a latest tag - type=raw,value=latest,enable=${{ env.IS_LATEST_TAG }} - type=raw,value=stable,enable=${{ env.IS_LATEST_TAG }} - # if tag version is set than create a version tags - type=semver,pattern={{version}},enable=${{ env.IS_VERSION_TAG }} - type=semver,pattern={{major}}.{{minor}},enable=${{ env.IS_VERSION_TAG }} - type=semver,pattern={{major}},enable=${{ env.IS_VERSION_TAG }} - # if we are on the main branch set edge - type=edge,branch=main - # use branch-sha otherwise for pushes to branches other then main (will not be uploaded) - type=raw,value={{branch}}-{{sha}},enable=${{ github.ref_type == 'branch' && github.event_name == 'push' && github.ref_name != 'main' }} - # use pr-$PR_ID for pull requests (will not be uploaded) - type=ref,event=pr - - name: Set up QEMU - uses: docker/setup-qemu-action@v3 - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 - - name: Login to Docker Registry - if: github.event_name != 'pull_request' - uses: docker/login-action@v3 - with: - username: ${{ secrets.DOCKERHUB_USERNAME }} - password: ${{ secrets.DOCKERHUB_TOKEN }} - - name: Build and push Container image - uses: docker/build-push-action@v6 - with: - context: . - push: ${{ github.event_name != 'pull_request' && (github.ref_type == 'tag' || github.ref_name == 'main') }} - file: .docker/prod.Dockerfile - platforms: linux/amd64,linux/arm64 - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} - - - name: "Setup meta information debian:oldstable" - id: old_stable_meta - uses: docker/metadata-action@v5 - with: - images: ${{ github.repository }} - labels: | - org.opencontainers.image.vendor=Greenbone - org.opencontainers.image.base.name=debian:stable-slim - flavor: latest=false # no auto latest container tag for git tags - tags: | - # for the images provided for debian:oldstable we just provide - # oldstable on an new version or oldstable-edge when it is on main. - # oldstable-branch-sha on a branch - type=raw,value=oldstable,enable=${{ env.IS_LATEST_TAG }} - type=raw,value=oldstable-edge,enable=${{ github.ref_name == 'main' }} - type=raw,value=oldstable-{{branch}}-{{sha}},enable=${{ github.ref_type == 'branch' && github.event_name == 'push' && github.ref_name != 'main' }} - type=ref,event=pr - - name: Build and push Container image - uses: docker/build-push-action@v6 - with: - context: . - push: ${{ github.event_name != 'pull_request' && (github.ref_type == 'tag' || github.ref_name == 'main') }} - file: .docker/prod-oldstable.Dockerfile - platforms: linux/amd64,linux/arm64 - tags: ${{ steps.old_stable_meta.outputs.tags }} - labels: ${{ steps.old_stable_meta.outputs.labels }} - - - name: "Setup meta information debian:testing" - id: testing_meta - uses: docker/metadata-action@v5 - with: - images: ${{ github.repository }} - labels: | - org.opencontainers.image.vendor=Greenbone - org.opencontainers.image.base.name=debian:testing-slim - flavor: latest=false # no auto latest container tag for git tags - tags: | - # for the images provided for debian:testing we just provide - # testing on an new version or testing-edge when it is on main. - # testing-branch-sha on a branch - type=raw,value=testing,enable=${{ env.IS_LATEST_TAG }} - type=raw,value=testing-edge,enable=${{ github.ref_name == 'main' }} - type=raw,value=testing-{{branch}}-{{sha}},enable=${{ github.ref_type == 'branch' && github.event_name == 'push' && github.ref_name != 'main' }} - type=ref,event=pr - - name: Build and push Container image - uses: docker/build-push-action@v6 - with: - context: . - push: ${{ github.event_name != 'pull_request' && (github.ref_type == 'tag' || github.ref_name == 'main') }} - file: .docker/prod-testing.Dockerfile - platforms: linux/amd64,linux/arm64 - tags: ${{ steps.testing_meta.outputs.tags }} - labels: ${{ steps.testing_meta.outputs.labels }} - - # triggers projects that work with stable branches on a new stable tag - trigger-stable-projects: - needs: production - if: github.ref_type == 'tag' && startsWith(github.ref_name, 'v') - name: Trigger update container images in related projects for new tags - strategy: - fail-fast: false - matrix: - repository: ["greenbone/gvmd", "greenbone/gsad"] - runs-on: ubuntu-latest - steps: - - name: Trigger ${{ matrix.repository }} build container image build - uses: greenbone/actions/trigger-workflow@v3 - with: - token: ${{ secrets.GREENBONE_BOT_TOKEN }} - repository: ${{ matrix.repository }} - workflow: build-container.yml - ref: main - - name: Trigger ${{ matrix.repository }} container image build - uses: greenbone/actions/trigger-workflow@v3 - with: - token: ${{ secrets.GREENBONE_BOT_TOKEN }} - repository: ${{ matrix.repository }} - workflow: container.yml - ref: main - - trigger-related-projects: - needs: production - if: github.event_name != 'pull_request' - name: Trigger update container images in related projects - strategy: - fail-fast: false - matrix: - repository: - - "greenbone/openvas-scanner" - - "greenbone/boreas" - runs-on: ubuntu-latest - steps: - - name: Trigger main ${{ matrix.repository }} container image build - uses: greenbone/actions/trigger-workflow@v3 - with: - token: ${{ secrets.GREENBONE_BOT_TOKEN }} - repository: ${{ matrix.repository }} - workflow: ${{ matrix.repository == 'greenbone/openvas-scanner' && 'control.yml' || 'container.yml' }} - ref: main diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml index d9046280..6399e0bd 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -1,4 +1,4 @@ -name: Build and Push to Greenbone Registry +name: Build & Push to Greenbone Registry on: push: @@ -14,8 +14,8 @@ on: required: true jobs: - build: - name: Build and Push to Greenbone Registry + build-push-debian-stable-container: + name: Build and Push debian:stable to Greenbone Registry uses: greenbone/workflows/.github/workflows/container-build-push-2nd-gen.yml@main with: image-url: community/gvm-libs @@ -24,3 +24,75 @@ jobs: org.opencontainers.image.base.name=debian:stable-slim ref-name: ${{ inputs.ref-name }} secrets: inherit + + build-push-debian-oldstable-container: + name: Build and Push debian:oldstable to Greenbone Registry + uses: greenbone/workflows/.github/workflows/container-build-push-2nd-gen.yml@main + with: + build-docker-file: .docker/prod-oldstable.Dockerfile + image-url: community/gvm-libs + image-labels: | + org.opencontainers.image.vendor=Greenbone + org.opencontainers.image.base.name=debian:stable-slim + base-image-label: "oldstable" + ref-name: ${{ inputs.ref-name }} + secrets: inherit + + build-push-debian-testing-container: + name: Build and Push debian:testing to Greenbone Registry + uses: greenbone/workflows/.github/workflows/container-build-push-2nd-gen.yml@main + with: + build-docker-file: .docker/prod-testing.Dockerfile + image-url: community/gvm-li + image-labels: | + org.opencontainers.image.vendor=Greenbone + org.opencontainers.image.base.name=debian:stable-slim + base-image-label: "testing" + ref-name: ${{ inputs.ref-name }} + secrets: inherit + + # triggers projects that work with stable branches on a new stable tag + trigger-stable-projects: + needs: build-push-debian-stable-container + if: github.ref_type == 'tag' && startsWith(github.ref_name, 'v') + name: Trigger update container images in related projects for new tags + strategy: + fail-fast: false + matrix: + repository: ["greenbone/gvmd", "greenbone/gsad"] + runs-on: ubuntu-latest + steps: + - name: Trigger ${{ matrix.repository }} build container image build + uses: greenbone/actions/trigger-workflow@v3 + with: + token: ${{ secrets.GREENBONE_BOT_TOKEN }} + repository: ${{ matrix.repository }} + workflow: build-container.yml + ref: main + - name: Trigger ${{ matrix.repository }} container image build + uses: greenbone/actions/trigger-workflow@v3 + with: + token: ${{ secrets.GREENBONE_BOT_TOKEN }} + repository: ${{ matrix.repository }} + workflow: container.yml + ref: main + + trigger-related-projects: + needs: build-push-debian-stable-container + if: github.event_name != 'pull_request' + name: Trigger update container images in related projects + strategy: + fail-fast: false + matrix: + repository: + - "greenbone/openvas-scanner" + - "greenbone/boreas" + runs-on: ubuntu-latest + steps: + - name: Trigger main ${{ matrix.repository }} container image build + uses: greenbone/actions/trigger-workflow@v3 + with: + token: ${{ secrets.GREENBONE_BOT_TOKEN }} + repository: ${{ matrix.repository }} + workflow: ${{ matrix.repository == 'greenbone/openvas-scanner' && 'control.yml' || 'container.yml' }} + ref: main From 5212a8ec0cfbebfe4edd2659df0cd9e24aa49cd2 Mon Sep 17 00:00:00 2001 From: Arno Stiefvater Date: Mon, 7 Oct 2024 06:42:27 +0200 Subject: [PATCH 28/29] Remove devops (#839) --- .github/CODEOWNERS | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 90547ef0..3844eb25 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -2,5 +2,5 @@ * @greenbone/gvm-libs-maintainers # dev ops -.github/ @greenbone/devops @greenbone/gvm-libs-maintainers -.docker/ @greenbone/devops @greenbone/gvm-libs-maintainers +.github/ @greenbone/gvm-libs-maintainers +.docker/ @greenbone/gvm-libs-maintainers From 3a89a44a36cf6bfdd2e6458eb9ed5f4f3682f3a4 Mon Sep 17 00:00:00 2001 From: Robert Schardt Date: Tue, 8 Oct 2024 11:04:01 +0200 Subject: [PATCH 29/29] Fix typo in push.yml for testing image --- .github/workflows/push.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml index 6399e0bd..0966a460 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -43,7 +43,7 @@ jobs: uses: greenbone/workflows/.github/workflows/container-build-push-2nd-gen.yml@main with: build-docker-file: .docker/prod-testing.Dockerfile - image-url: community/gvm-li + image-url: community/gvm-libs image-labels: | org.opencontainers.image.vendor=Greenbone org.opencontainers.image.base.name=debian:stable-slim