Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/zabbix/zabbix.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore6
-rw-r--r--build/win32/project/Makefile_agent2
-rw-r--r--build/win32/project/Makefile_sender5
-rw-r--r--build/win32/project/Makefile_sender_dll5
-rw-r--r--configure.ac2
-rw-r--r--include/common.h23
-rw-r--r--include/dbcache.h2
-rw-r--r--include/sysinc.h4
-rw-r--r--include/zbxjson.h21
-rw-r--r--include/zbxserver.h2
-rw-r--r--src/libs/zbxalgo/hashset.c2
-rw-r--r--src/libs/zbxcommon/variant.c107
-rw-r--r--src/libs/zbxdbhigh/lld_macro.c27
-rw-r--r--src/libs/zbxjson/Makefile.am6
-rw-r--r--src/libs/zbxjson/json.c249
-rw-r--r--src/libs/zbxjson/json.h (renamed from tests/libs/zbxjson/jsonpath_next_test.h)15
-rw-r--r--src/libs/zbxjson/json_parser.c1
-rw-r--r--src/libs/zbxjson/json_parser.h7
-rw-r--r--src/libs/zbxjson/jsonpath.c2504
-rw-r--r--src/libs/zbxjson/jsonpath.h159
-rw-r--r--src/libs/zbxserver/expression.c7
-rw-r--r--src/zabbix_agent/Makefile.am2
-rw-r--r--src/zabbix_sender/Makefile.am4
-rw-r--r--src/zabbix_server/lld/lld.c9
-rw-r--r--src/zabbix_server/lld/lld_item.c7
-rw-r--r--src/zabbix_server/preprocessor/item_preproc.c61
-rw-r--r--src/zabbix_server/preprocessor/preproc_worker.c6
-rw-r--r--tests/Makefile.am4
-rw-r--r--tests/libs/zbxcommon/Makefile.am2
-rw-r--r--tests/libs/zbxcommon/zbx_variant_compare.c2
-rw-r--r--tests/libs/zbxcommon/zbx_variant_compare.yaml22
-rw-r--r--tests/libs/zbxhistory/Makefile.am2
-rw-r--r--tests/libs/zbxjson/Makefile.am64
-rw-r--r--tests/libs/zbxjson/jsonpath_next.c97
-rw-r--r--tests/libs/zbxjson/jsonpath_next.yaml265
-rw-r--r--tests/libs/zbxjson/jsonpath_next_test.c25
-rw-r--r--tests/libs/zbxjson/mock_json.c1
-rw-r--r--tests/libs/zbxjson/zbx_json_open_path.c (renamed from tests/libs/zbxjson/zbx_json_path_open.c)20
-rw-r--r--tests/libs/zbxjson/zbx_json_open_path.yaml (renamed from tests/libs/zbxjson/zbx_json_path_open.yaml)42
-rw-r--r--tests/libs/zbxjson/zbx_jsonpath_compile.c257
-rw-r--r--tests/libs/zbxjson/zbx_jsonpath_compile.yaml1024
-rw-r--r--tests/libs/zbxjson/zbx_jsonpath_query.c100
-rw-r--r--tests/libs/zbxjson/zbx_jsonpath_query.inc.yaml77
-rw-r--r--tests/libs/zbxjson/zbx_jsonpath_query.yaml711
-rw-r--r--tests/libs/zbxsysinfo/Makefile.am4
-rw-r--r--tests/libs/zbxsysinfo/common/Makefile.am1
-rw-r--r--tests/libs/zbxsysinfo/linux/Makefile.am1
-rw-r--r--tests/zabbix_server/preprocessor/Makefile.am3
-rw-r--r--tests/zabbix_server/preprocessor/zbx_item_preproc.yaml81
-rw-r--r--tests/zbxmockdata.c2
-rw-r--r--tests/zbxmockjson.c14
-rw-r--r--tests/zbxmockjson.h2
52 files changed, 5298 insertions, 770 deletions
diff --git a/.gitignore b/.gitignore
index d5d0e6131a8..0b0f6883213 100644
--- a/.gitignore
+++ b/.gitignore
@@ -126,10 +126,11 @@ tests/libs/zbxdbcache/zbx_vc_get_value
tests/libs/zbxdbcache/zbx_vc_get_values
tests/libs/zbxdbhigh/DBselect_uint64
tests/libs/zbxhistory/zbx_history_get_values
-tests/libs/zbxjson/zbx_json_path_open
-tests/libs/zbxjson/jsonpath_next
+tests/libs/zbxjson/zbx_json_open_path
tests/libs/zbxjson/zbx_json_decodevalue
tests/libs/zbxjson/zbx_json_decodevalue_dyn
+tests/libs/zbxjson/zbx_jsonpath_compile
+tests/libs/zbxjson/zbx_jsonpath_query
tests/libs/zbxprometheus/prometheus_filter_init
tests/libs/zbxprometheus/prometheus_parse_row
tests/libs/zbxprometheus/zbx_prometheus_pattern
@@ -146,6 +147,7 @@ tests/libs/zbxsysinfo/linux/NET_IF_TOTAL
tests/libs/zbxsysinfo/linux/SYSTEM_BOOTTIME
tests/libs/zbxsysinfo/linux/SYSTEM_CPU_INTR
tests/libs/zbxsysinfo/linux/SYSTEM_CPU_SWITCHES
+tests/libs/zbxsysinfo/linux/SYSTEM_HW_CHASSIS
tests/libs/zbxsysinfo/linux/VFS_FS_DISCOVERY
tests/libs/zbxsysinfo/linux/SYSTEM_HW_CHASSIS
tests/libs/zbxsysinfo/parse_item_key
diff --git a/build/win32/project/Makefile_agent b/build/win32/project/Makefile_agent
index 88f3f3f0f32..230f67177bc 100644
--- a/build/win32/project/Makefile_agent
+++ b/build/win32/project/Makefile_agent
@@ -41,6 +41,7 @@ OBJS = \
..\..\..\src\libs\zbxcommon\comms.o \
..\..\..\src\libs\zbxcommon\iprange.o \
..\..\..\src\libs\zbxcommon\misc.o \
+ ..\..\..\src\libs\zbxcommon\variant.o \
..\..\..\src\libs\zbxcommon\str.o \
..\..\..\src\libs\zbxcommon\xml.o \
..\..\..\src\libs\zbxcommon\zbxgetopt.o \
@@ -53,6 +54,7 @@ OBJS = \
..\..\..\src\libs\zbxcrypto\md5.o \
..\..\..\src\libs\zbxjson\json.o \
..\..\..\src\libs\zbxjson\json_parser.o \
+ ..\..\..\src\libs\zbxjson\jsonpath.o \
..\..\..\src\libs\zbxlog\log.o \
..\..\..\src\libs\zbxsys\mutexs.o \
..\..\..\src\libs\zbxsys\symbols.o \
diff --git a/build/win32/project/Makefile_sender b/build/win32/project/Makefile_sender
index acf754df55b..1d07cea9796 100644
--- a/build/win32/project/Makefile_sender
+++ b/build/win32/project/Makefile_sender
@@ -31,6 +31,7 @@ OBJS = \
..\..\..\src\libs\zbxcommon\comms.o \
..\..\..\src\libs\zbxcommon\iprange.o \
..\..\..\src\libs\zbxcommon\misc.o \
+ ..\..\..\src\libs\zbxcommon\variant.o \
..\..\..\src\libs\zbxcommon\str.o \
..\..\..\src\libs\zbxcommon\xml.o \
..\..\..\src\libs\zbxcommon\zbxgetopt.o \
@@ -41,11 +42,15 @@ OBJS = \
..\..\..\src\libs\zbxcrypto\md5.o \
..\..\..\src\libs\zbxjson\json.o \
..\..\..\src\libs\zbxjson\json_parser.o \
+ ..\..\..\src\libs\zbxjson\jsonpath.o \
..\..\..\src\libs\zbxlog\log.o \
..\..\..\src\libs\zbxsys\mutexs.o \
..\..\..\src\libs\zbxsys\symbols.o \
..\..\..\src\libs\zbxsys\threads.o \
..\..\..\src\libs\zbxwin32\fatal.o \
+ ..\..\..\src\libs\zbxalgo\algodefs.o \
+ ..\..\..\src\libs\zbxalgo\vector.o \
+ ..\..\..\src\libs\zbxregexp\zbxregexp.o \
..\..\..\src\zabbix_sender\zabbix_sender.o
LIBS = ws2_32.lib psapi.lib pdh.lib Wldap32.lib advapi32.lib uuid.lib Iphlpapi.lib user32.lib
diff --git a/build/win32/project/Makefile_sender_dll b/build/win32/project/Makefile_sender_dll
index 271ffc7a7f6..6cbb0b6697f 100644
--- a/build/win32/project/Makefile_sender_dll
+++ b/build/win32/project/Makefile_sender_dll
@@ -37,6 +37,7 @@ OBJS = \
..\..\..\src\libs\zbxcommon\comms.o \
..\..\..\src\libs\zbxcommon\iprange.o \
..\..\..\src\libs\zbxcommon\misc.o \
+ ..\..\..\src\libs\zbxcommon\variant.o \
..\..\..\src\libs\zbxcommon\str.o \
..\..\..\src\libs\zbxcommon\xml.o \
..\..\..\src\libs\zbxcommon\zbxgetopt.o \
@@ -47,11 +48,15 @@ OBJS = \
..\..\..\src\libs\zbxcrypto\md5.o \
..\..\..\src\libs\zbxjson\json.o \
..\..\..\src\libs\zbxjson\json_parser.o \
+ ..\..\..\src\libs\zbxjson\jsonpath.o \
..\..\..\src\libs\zbxlog\log.o \
..\..\..\src\libs\zbxsys\mutexs.o \
..\..\..\src\libs\zbxsys\symbols.o \
..\..\..\src\libs\zbxsys\threads.o \
..\..\..\src\libs\zbxwin32\fatal.o \
+ ..\..\..\src\libs\zbxalgo\algodefs.o \
+ ..\..\..\src\libs\zbxalgo\vector.o \
+ ..\..\..\src\libs\zbxregexp\zbxregexp.o \
..\..\..\src\zabbix_sender\win32\zabbix_sender.o
LIBS = ws2_32.lib psapi.lib pdh.lib Wldap32.lib advapi32.lib uuid.lib Iphlpapi.lib
diff --git a/configure.ac b/configure.ac
index a9258a770e6..01cc034c8f8 100644
--- a/configure.ac
+++ b/configure.ac
@@ -62,7 +62,7 @@ AC_CHECK_HEADERS(stdio.h stdlib.h string.h unistd.h netdb.h signal.h \
stdarg.h winsock2.h pdh.h psapi.h sys/sem.h sys/ipc.h sys/shm.h Winldap.h \
Winber.h lber.h ws2tcpip.h inttypes.h sys/file.h grp.h \
execinfo.h sys/systemcfg.h sys/mnttab.h mntent.h sys/times.h \
- dlfcn.h sys/utsname.h sys/un.h sys/protosw.h)
+ dlfcn.h sys/utsname.h sys/un.h sys/protosw.h stddef.h)
AC_CHECK_HEADERS(resolv.h, [], [], [
#ifdef HAVE_SYS_TYPES_H
# include <sys/types.h>
diff --git a/include/common.h b/include/common.h
index dcc2ce58c1a..a46b54210bc 100644
--- a/include/common.h
+++ b/include/common.h
@@ -1485,18 +1485,16 @@ int zbx_strmatch_condition(const char *value, const char *pattern, unsigned char
zbx_log_value_t *zbx_log_value_dup(const zbx_log_value_t *src);
-typedef void * zbx_variant_data_bin_t;
-
typedef union
{
- zbx_uint64_t ui64;
- double dbl;
+ zbx_uint64_t ui64;
+ double dbl;
/* null terminated string */
- char *str;
+ char *str;
/* length prefixed (4 bytes) binary data */
- zbx_variant_data_bin_t *bin;
+ void *bin;
}
zbx_variant_data_t;
@@ -1518,8 +1516,8 @@ void zbx_variant_set_none(zbx_variant_t *value);
void zbx_variant_set_str(zbx_variant_t *value, char *text);
void zbx_variant_set_dbl(zbx_variant_t *value, double dbl);
void zbx_variant_set_ui64(zbx_variant_t *value, zbx_uint64_t ui64);
-void zbx_variant_set_bin(zbx_variant_t *value, zbx_variant_data_bin_t *value_bin);
-void zbx_variant_set_variant(zbx_variant_t *value, const zbx_variant_t *source);
+void zbx_variant_set_bin(zbx_variant_t *value, void *value_bin);
+void zbx_variant_copy(zbx_variant_t *value, const zbx_variant_t *source);
int zbx_variant_set_numeric(zbx_variant_t *value, const char *text);
int zbx_variant_convert(zbx_variant_t *value, int type);
@@ -1527,12 +1525,13 @@ const char *zbx_get_variant_type_desc(unsigned char type);
const char *zbx_variant_value_desc(const zbx_variant_t *value);
const char *zbx_variant_type_desc(const zbx_variant_t *value);
-int zbx_validate_value_dbl(double value);
int zbx_variant_compare(const zbx_variant_t *value1, const zbx_variant_t *value2);
-zbx_variant_data_bin_t *zbx_variant_data_bin_copy(const zbx_variant_data_bin_t *bin);
-zbx_variant_data_bin_t *zbx_variant_data_bin_create(const void *data, zbx_uint32_t size);
-zbx_uint32_t zbx_variant_data_bin_get(const zbx_variant_data_bin_t *bin, void **data);
+void *zbx_variant_data_bin_copy(const void *bin);
+void *zbx_variant_data_bin_create(const void *data, zbx_uint32_t size);
+zbx_uint32_t zbx_variant_data_bin_get(const void *bin, void **data);
+
+int zbx_validate_value_dbl(double value);
void zbx_update_env(double time_now);
diff --git a/include/dbcache.h b/include/dbcache.h
index 76217bcddc4..98ab8e08372 100644
--- a/include/dbcache.h
+++ b/include/dbcache.h
@@ -938,7 +938,7 @@ zbx_lld_macro_path_t;
int zbx_lld_macro_paths_get(zbx_uint64_t lld_ruleid, zbx_vector_ptr_t *lld_macro_paths, char **error);
void zbx_lld_macro_path_free(zbx_lld_macro_path_t *lld_macro_path);
int zbx_lld_macro_value_by_name(const struct zbx_json_parse *jp_row, const zbx_vector_ptr_t *lld_macro_paths,
- const char *macro, char **value, size_t *value_alloc);
+ const char *macro, char **value);
int zbx_lld_macro_paths_compare(const void *d1, const void *d2);
void zbx_dc_get_item_tags_by_functionids(const zbx_uint64_t *functionids, size_t functionids_num, zbx_vector_ptr_t *host_tags);
diff --git a/include/sysinc.h b/include/sysinc.h
index fcf5ccf6f4b..a0beb02c0a3 100644
--- a/include/sysinc.h
+++ b/include/sysinc.h
@@ -420,4 +420,8 @@
# include <utmpx.h>
#endif
+#ifdef HAVE_STDDEF_H
+# include <stddef.h>
+#endif
+
#endif
diff --git a/include/zbxjson.h b/include/zbxjson.h
index 7b37f98b5ae..d220f23b8fa 100644
--- a/include/zbxjson.h
+++ b/include/zbxjson.h
@@ -220,8 +220,23 @@ const char *zbx_json_decodevalue(const char *p, char *string, size_t size, zbx_j
const char *zbx_json_decodevalue_dyn(const char *p, char **string, size_t *string_alloc, zbx_json_type_t *type);
void zbx_json_escape(char **string);
-int zbx_json_path_check(const char *path, char * error, size_t errlen);
-int zbx_json_path_open(const struct zbx_json_parse *jp, const char *path, struct zbx_json_parse *out);
-void zbx_json_value_dyn(const struct zbx_json_parse *jp, char **string, size_t *string_alloc);
+/* jsonpath support */
+
+typedef struct zbx_jsonpath_segment zbx_jsonpath_segment_t;
+
+typedef struct
+{
+ zbx_jsonpath_segment_t *segments;
+ int segments_num;
+ int segments_alloc;
+
+ /* set to 1 when jsonpath points at single location */
+ unsigned char definite;
+}
+zbx_jsonpath_t;
+
+void zbx_jsonpath_clear(zbx_jsonpath_t *jsonpath);
+int zbx_jsonpath_compile(const char *path, zbx_jsonpath_t *jsonpath);
+int zbx_jsonpath_query(const struct zbx_json_parse *jp, const char *path, char **output);
#endif /* ZABBIX_ZJSON_H */
diff --git a/include/zbxserver.h b/include/zbxserver.h
index c07cf2b0ea7..00874380ae4 100644
--- a/include/zbxserver.h
+++ b/include/zbxserver.h
@@ -77,8 +77,6 @@ void zbx_determine_items_in_expressions(zbx_vector_ptr_t *trigger_order, const z
#define ZBX_MACRO_SIMPLE (ZBX_MACRO_ANY | ZBX_TOKEN_SIMPLE_MACRO)
#define ZBX_MACRO_FUNC (ZBX_MACRO_ANY | ZBX_TOKEN_FUNC_MACRO)
-int zbx_lld_macro_value_by_name(const struct zbx_json_parse *jp_row, const zbx_vector_ptr_t *lld_macro_paths,
- const char *macro, char **value, size_t *value_alloc);
int substitute_lld_macros(char **data, const struct zbx_json_parse *jp_row, const zbx_vector_ptr_t *lld_macro_paths,
int flags, char *error, size_t max_error_len);
int substitute_key_macros(char **data, zbx_uint64_t *hostid, DC_ITEM *dc_item, const struct zbx_json_parse *jp_row,
diff --git a/src/libs/zbxalgo/hashset.c b/src/libs/zbxalgo/hashset.c
index 7eb5813b2b1..92c43ed78e8 100644
--- a/src/libs/zbxalgo/hashset.c
+++ b/src/libs/zbxalgo/hashset.c
@@ -17,8 +17,6 @@
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
**/
-#include <stddef.h>
-
#include "common.h"
#include "log.h"
diff --git a/src/libs/zbxcommon/variant.c b/src/libs/zbxcommon/variant.c
index 27230dd5edb..d7382e252b3 100644
--- a/src/libs/zbxcommon/variant.c
+++ b/src/libs/zbxcommon/variant.c
@@ -20,10 +20,10 @@
#include "common.h"
#include "zbxalgo.h"
-zbx_variant_data_bin_t *zbx_variant_data_bin_copy(const zbx_variant_data_bin_t *bin)
+void *zbx_variant_data_bin_copy(const void *bin)
{
zbx_uint32_t size;
- zbx_variant_data_bin_t *value_bin;
+ void *value_bin;
memcpy(&size, bin, sizeof(size));
value_bin = zbx_malloc(NULL, size + sizeof(size));
@@ -32,9 +32,9 @@ zbx_variant_data_bin_t *zbx_variant_data_bin_copy(const zbx_variant_data_bin_t *
return value_bin;
}
-zbx_variant_data_bin_t *zbx_variant_data_bin_create(const void *data, zbx_uint32_t size)
+void *zbx_variant_data_bin_create(const void *data, zbx_uint32_t size)
{
- zbx_variant_data_bin_t *value_bin;
+ void *value_bin;
value_bin = zbx_malloc(NULL, size + sizeof(size));
memcpy(value_bin, &size, sizeof(size));
@@ -43,13 +43,13 @@ zbx_variant_data_bin_t *zbx_variant_data_bin_create(const void *data, zbx_uint32
return value_bin;
}
-zbx_uint32_t zbx_variant_data_bin_get(const zbx_variant_data_bin_t *bin, void **data)
+zbx_uint32_t zbx_variant_data_bin_get(const void *bin, void **data)
{
zbx_uint32_t size;
memcpy(&size, bin, sizeof(zbx_uint32_t));
if (NULL != data)
- *data = ((char *)bin) + sizeof(size);
+ *data = ((unsigned char *)bin) + sizeof(size);
return size;
}
@@ -68,6 +68,18 @@ void zbx_variant_clear(zbx_variant_t *value)
value->type = ZBX_VARIANT_NONE;
}
+/******************************************************************************
+ * *
+ * Setter functions assign passed data and set corresponding variant *
+ * type. Note that for complex data it means the pointer is simply copied *
+ * instead of making a copy of the specified data. *
+ * *
+ * The contents of the destination value are not freed. When setting already *
+ * initialized variant it's safer to clear it beforehand, even if the variant *
+ * contains primitive value (numeric). *
+ * *
+ ******************************************************************************/
+
void zbx_variant_set_str(zbx_variant_t *value, char *text)
{
value->data.str = text;
@@ -91,13 +103,26 @@ void zbx_variant_set_none(zbx_variant_t *value)
value->type = ZBX_VARIANT_NONE;
}
-void zbx_variant_set_bin(zbx_variant_t *value, zbx_variant_data_bin_t *value_bin)
+void zbx_variant_set_bin(zbx_variant_t *value, void *value_bin)
{
value->data.bin = value_bin;
value->type = ZBX_VARIANT_BIN;
}
-void zbx_variant_set_variant(zbx_variant_t *value, const zbx_variant_t *source)
+/******************************************************************************
+ * *
+ * Function: zbx_variant_copy *
+ * *
+ * Purpose: copy variant contents from source to value *
+ * *
+ * Comments: String and binary data are cloned, which is different from *
+ * setters where only the pointers are copied. *
+ * The contents of the destination value are not freed. If copied *
+ * over already initialized variant it's safer to clear it *
+ * beforehand. *
+ * *
+ ******************************************************************************/
+void zbx_variant_copy(zbx_variant_t *value, const zbx_variant_t *source)
{
switch (source->type)
{
@@ -264,9 +289,8 @@ int zbx_variant_set_numeric(zbx_variant_t *value, const char *text)
const char *zbx_variant_value_desc(const zbx_variant_t *value)
{
- static char buffer[ZBX_MAX_UINT64_LEN + 1];
- int i, len;
- zbx_uint32_t size;
+ ZBX_THREAD_LOCAL static char buffer[ZBX_MAX_UINT64_LEN + 1];
+ zbx_uint32_t size, i, len;
switch (value->type)
{
@@ -342,7 +366,8 @@ int zbx_validate_value_dbl(double value)
* *
* Function: variant_compare_empty *
* *
- * Purpose: compares two variant values when at least one is empty *
+ * Purpose: compares two variant values when at least one is empty (having *
+ * type of ZBX_VARIANT_NONE) *
* *
******************************************************************************/
static int variant_compare_empty(const zbx_variant_t *value1, const zbx_variant_t *value2)
@@ -362,7 +387,7 @@ static int variant_compare_empty(const zbx_variant_t *value1, const zbx_variant_
* *
* Function: variant_compare_bin *
* *
- * Purpose: compares two variant values when at least one contains binary data*
+ * Purpose: compare two variant values when at least one contains binary data *
* *
******************************************************************************/
static int variant_compare_bin(const zbx_variant_t *value1, const zbx_variant_t *value2)
@@ -387,7 +412,7 @@ static int variant_compare_bin(const zbx_variant_t *value1, const zbx_variant_t
* *
* Function: variant_compare_str *
* *
- * Purpose: compares two variant values when at least one is string *
+ * Purpose: compare two variant values when at least one is string *
* *
******************************************************************************/
static int variant_compare_str(const zbx_variant_t *value1, const zbx_variant_t *value2)
@@ -402,8 +427,9 @@ static int variant_compare_str(const zbx_variant_t *value1, const zbx_variant_t
* *
* Function: variant_compare_dbl *
* *
- * Purpose: compares two variant values when at least one is double and the *
- * other is double or uint64 *
+ * Purpose: compare two variant values when at least one is double and the *
+ * other is double, uint64 or a string representing a valid double *
+ * value *
* *
******************************************************************************/
static int variant_compare_dbl(const zbx_variant_t *value1, const zbx_variant_t *value2)
@@ -418,6 +444,9 @@ static int variant_compare_dbl(const zbx_variant_t *value1, const zbx_variant_t
case ZBX_VARIANT_UI64:
value1_dbl = value1->data.ui64;
break;
+ case ZBX_VARIANT_STR:
+ value1_dbl = atof(value1->data.str);
+ break;
default:
THIS_SHOULD_NEVER_HAPPEN;
exit(EXIT_FAILURE);
@@ -431,6 +460,9 @@ static int variant_compare_dbl(const zbx_variant_t *value1, const zbx_variant_t
case ZBX_VARIANT_UI64:
value2_dbl = value2->data.ui64;
break;
+ case ZBX_VARIANT_STR:
+ value2_dbl = atof(value2->data.str);
+ break;
default:
THIS_SHOULD_NEVER_HAPPEN;
exit(EXIT_FAILURE);
@@ -440,6 +472,7 @@ static int variant_compare_dbl(const zbx_variant_t *value1, const zbx_variant_t
return 0;
ZBX_RETURN_IF_NOT_EQUAL(value1_dbl, value2_dbl);
+
THIS_SHOULD_NEVER_HAPPEN;
exit(EXIT_FAILURE);
}
@@ -448,7 +481,7 @@ static int variant_compare_dbl(const zbx_variant_t *value1, const zbx_variant_t
* *
* Function: variant_compare_ui64 *
* *
- * Purpose: compares two variant values when both are uint64 *
+ * Purpose: compare two variant values when both are uint64 *
* *
******************************************************************************/
static int variant_compare_ui64(const zbx_variant_t *value1, const zbx_variant_t *value2)
@@ -461,25 +494,25 @@ static int variant_compare_ui64(const zbx_variant_t *value1, const zbx_variant_t
* *
* Function: zbx_variant_compare *
* *
- * Purpose: compares two variant values *
+ * Purpose: compare two variant values *
* *
* Parameters: value1 - [IN] the first value *
* value2 - [IN] the second value *
* *
- * Return value: <0 - the first value is less than second *
- * >0 - the first value is greater than second *
+ * Return value: <0 - the first value is less than the second *
+ * >0 - the first value is greater than the second *
* 0 - the values are equal *
* *
- * Comments: The following priority is applied: *
- * 1) value of none type is always less than other types, two *
- * none types are equal *
- * 1) value of binary type is always greater than other types, two *
+ * Comments: The following comparison logic is applied: *
+ * 1) value of 'none' type is always less than other types, two *
+ * 'none' types are equal *
+ * 2) value of binary type is always greater than other types, two *
* binary types are compared by length and then by contents *
- * 2) if any of value is of string type, the other is converted to *
+ * 3) if both values have uint64 types, they are compared as is *
+ * 4) if both values can be converted to floating point values the *
+ * conversion is done and the result is compared *
+ * 5) if any of value is of string type, the other is converted to *
* string and both are compared *
- * 3) if any of value is of floating type, the other is converted *
- * to floating value and both are compared *
- * 4) only uin64 types are left, compare as uin64 *
* *
******************************************************************************/
int zbx_variant_compare(const zbx_variant_t *value1, const zbx_variant_t *value2)
@@ -490,17 +523,15 @@ int zbx_variant_compare(const zbx_variant_t *value1, const zbx_variant_t *value2
if (ZBX_VARIANT_BIN == value1->type || ZBX_VARIANT_BIN == value2->type)
return variant_compare_bin(value1, value2);
- if (ZBX_VARIANT_STR == value1->type || ZBX_VARIANT_STR == value2->type)
- return variant_compare_str(value1, value2);
+ if (ZBX_VARIANT_UI64 == value1->type && ZBX_VARIANT_UI64 == value2->type)
+ return variant_compare_ui64(value1, value2);
- if (ZBX_VARIANT_DBL == value1->type || ZBX_VARIANT_DBL == value2->type)
+ if ((ZBX_VARIANT_STR != value1->type || SUCCEED == is_double(value1->data.str)) &&
+ (ZBX_VARIANT_STR != value2->type || SUCCEED == is_double(value2->data.str)))
+ {
return variant_compare_dbl(value1, value2);
+ }
- if (ZBX_VARIANT_UI64 == value1->type && ZBX_VARIANT_UI64 == value2->type)
- return variant_compare_ui64(value1, value2);
-
- THIS_SHOULD_NEVER_HAPPEN;
- exit(EXIT_FAILURE);
+ /* at this point at least one of the values is string data, other can be uint64, floating or string */
+ return variant_compare_str(value1, value2);
}
-
-
diff --git a/src/libs/zbxdbhigh/lld_macro.c b/src/libs/zbxdbhigh/lld_macro.c
index 4c7445346e2..3ee2e7644ba 100644
--- a/src/libs/zbxdbhigh/lld_macro.c
+++ b/src/libs/zbxdbhigh/lld_macro.c
@@ -54,7 +54,6 @@ int zbx_lld_macro_paths_get(zbx_uint64_t lld_ruleid, zbx_vector_ptr_t *lld_macro
DB_ROW row;
zbx_lld_macro_path_t *lld_macro_path;
int ret = SUCCEED;
- char err[MAX_STRING_LEN];
zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
@@ -67,14 +66,18 @@ int zbx_lld_macro_paths_get(zbx_uint64_t lld_ruleid, zbx_vector_ptr_t *lld_macro
while (NULL != (row = DBfetch(result)))
{
- if (SUCCEED != (ret = zbx_json_path_check(row[1], err, sizeof(err))))
+ zbx_jsonpath_t path;
+
+ if (SUCCEED != (ret = zbx_jsonpath_compile(row[1], &path)))
{
- *error = zbx_dsprintf(*error, "Cannot process LLD macro \"%s\": %s.\n", row[0], err);
+ *error = zbx_dsprintf(*error, "Cannot process LLD macro \"%s\": %s.\n", row[0],
+ zbx_json_strerror());
break;
}
- lld_macro_path = (zbx_lld_macro_path_t *)zbx_malloc(NULL, sizeof(zbx_lld_macro_path_t));
+ zbx_jsonpath_clear(&path);
+ lld_macro_path = (zbx_lld_macro_path_t *)zbx_malloc(NULL, sizeof(zbx_lld_macro_path_t));
lld_macro_path->lld_macro = zbx_strdup(NULL, row[0]);
lld_macro_path->path = zbx_strdup(NULL, row[1]);
@@ -114,16 +117,14 @@ void zbx_lld_macro_path_free(zbx_lld_macro_path_t *lld_macro_path)
* lld_macro_paths - [IN] use json path to extract from jp_row *
* macro - [IN] LLD macro *
* value - [OUT] value extracted from jp_row *
- * value_alloc - [OUT] allocated memory size for value *
* *
******************************************************************************/
int zbx_lld_macro_value_by_name(const struct zbx_json_parse *jp_row, const zbx_vector_ptr_t *lld_macro_paths,
- const char *macro, char **value, size_t *value_alloc)
+ const char *macro, char **value)
{
zbx_lld_macro_path_t lld_macro_path_local, *lld_macro_path;
int index;
- struct zbx_json_parse jp_out;
- int ret;
+ size_t value_alloc = 0;
lld_macro_path_local.lld_macro = (char *)macro;
@@ -132,12 +133,12 @@ int zbx_lld_macro_value_by_name(const struct zbx_json_parse *jp_row, const zbx_v
{
lld_macro_path = (zbx_lld_macro_path_t *)lld_macro_paths->values[index];
- if (FAIL != (ret = zbx_json_path_open(jp_row, lld_macro_path->path, &jp_out)))
- zbx_json_value_dyn(&jp_out, value, value_alloc);
+ if (SUCCEED == zbx_jsonpath_query(jp_row, lld_macro_path->path, value) && NULL != *value)
+ return SUCCEED;
+
+ return FAIL;
}
else
- ret = zbx_json_value_by_name_dyn(jp_row, macro, value, value_alloc);
-
- return ret;
+ return zbx_json_value_by_name_dyn(jp_row, macro, value, &value_alloc);
}
diff --git a/src/libs/zbxjson/Makefile.am b/src/libs/zbxjson/Makefile.am
index facf5959937..721ac2e79d3 100644
--- a/src/libs/zbxjson/Makefile.am
+++ b/src/libs/zbxjson/Makefile.am
@@ -3,6 +3,6 @@
noinst_LIBRARIES = libzbxjson.a
libzbxjson_a_SOURCES = \
- json.c \
- json_parser.c \
- json_parser.h
+ json.c json.h \
+ json_parser.c json_parser.h \
+ jsonpath.c jsonpath.h
diff --git a/src/libs/zbxjson/json.c b/src/libs/zbxjson/json.c
index 21541f2dd39..d3785b0964d 100644
--- a/src/libs/zbxjson/json.c
+++ b/src/libs/zbxjson/json.c
@@ -20,6 +20,8 @@
#include "common.h"
#include "zbxjson.h"
#include "json_parser.h"
+#include "json.h"
+#include "jsonpath.h"
/******************************************************************************
* *
@@ -34,15 +36,14 @@
******************************************************************************/
#define ZBX_JSON_MAX_STRERROR 255
-static char zbx_json_strerror_message[ZBX_JSON_MAX_STRERROR];
+ZBX_THREAD_LOCAL static char zbx_json_strerror_message[ZBX_JSON_MAX_STRERROR];
const char *zbx_json_strerror(void)
{
return zbx_json_strerror_message;
}
-__zbx_attr_format_printf(1, 2)
-static void zbx_set_json_strerror(const char *fmt, ...)
+void zbx_set_json_strerror(const char *fmt, ...)
{
va_list args;
@@ -1212,186 +1213,71 @@ int zbx_json_count(const struct zbx_json_parse *jp)
return num;
}
-
-/*
- * limited JSONPath support
- */
-
-#define ZBX_JSONPATH_COMPONENT_DOT 0
-#define ZBX_JSONPATH_COMPONENT_BRACKET 1
-#define ZBX_JSONPATH_ARRAY_INDEX 2
-
-/******************************************************************************
- * *
- * Function: zbx_jsonpath_error *
- * *
- * Purpose: sets json error message and returns FAIL *
- * *
- * Comments: This function is used to return from json path parsing functions *
- * in the case of failure. *
- * *
- ******************************************************************************/
-static int zbx_jsonpath_error(const char *path)
-{
- zbx_set_json_strerror("unsupported character in json path starting with: \"%s\"", path);
- return FAIL;
-}
-
/******************************************************************************
* *
- * Function: jsonpath_next *
+ * Function: zbx_json_open_path *
* *
- * Purpose: returns next component of json path *
+ * Purpose: opens an object by definite json path *
* *
- * Parameters: path - [IN] the json path *
- * pnext - [IN/OUT] the reference to the next path component *
- * loc - [OUT] the location of the path component *
- * type - [OUT] json path component type, see ZBX_JSONPATH_ *
- * defines *
+ * Return value: SUCCESS - processed successfully *
+ * FAIL - an error occurred *
* *
- * Return value: SUCCEED - the json path component was parsed successfully *
- * FAIL - json path parsing error *
+ * Comments: Only direct path to single object in dot or bracket notation *
+ * is supported. *
* *
******************************************************************************/
-static int jsonpath_next(const char *path, const char **pnext, zbx_strloc_t *loc, int *type)
+int zbx_json_open_path(const struct zbx_json_parse *jp, const char *path, struct zbx_json_parse *out)
{
- const char *next = *pnext;
- size_t pos;
- char quotes;
+ int i, ret = FAIL;
+ struct zbx_json_parse object;
+ zbx_jsonpath_t jsonpath;
- if (NULL == next)
- {
- if ('$' != *path)
- return zbx_jsonpath_error(path);
+ object = *jp;
- next = path + 1;
- *pnext = next;
- }
+ if (FAIL == zbx_jsonpath_compile(path, &jsonpath))
+ return FAIL;
- /* process dot notation component */
- if (*next == '.')
+ if (0 == jsonpath.definite)
{
- if ('\0' == *(++next))
- return zbx_jsonpath_error(*pnext);
-
- loc->l = next - path;
-
- while (0 != isalnum(*next) || '_' == *next)
- next++;
-
- if ((pos = next - path) == loc->l)
- return zbx_jsonpath_error(*pnext);
-
- loc->r = pos - 1;
- *pnext = next;
- *type = ZBX_JSONPATH_COMPONENT_DOT;
-
- return SUCCEED;
+ zbx_set_json_strerror("cannot use indefinite path when opening sub element");
+ goto out;
}
- if ('[' != *next)
- return zbx_jsonpath_error(*pnext);
-
- SKIP_WHITESPACE_NEXT(next);
-
- /* process array index component */
- if (0 != isdigit(*next))
+ for (i = 0; i < jsonpath.segments_num; i++)
{
- for (pos = 1; 0 != isdigit(next[pos]); pos++)
- ;
+ const char *p;
+ zbx_jsonpath_segment_t *segment = &jsonpath.segments[i];
- loc->l = next - path;
- loc->r = loc->l + pos - 1;
-
- next += pos;
- *type = ZBX_JSONPATH_ARRAY_INDEX;
-
- SKIP_WHITESPACE(next);
- }
- else
- {
- loc->l = next - path + 1;
-
- for (quotes = *next++; quotes != *next; next++)
+ if (ZBX_JSONPATH_SEGMENT_MATCH_LIST != segment->type)
{
- if ('\0' == *next)
- return zbx_jsonpath_error(*pnext);
+ zbx_set_json_strerror("jsonpath segment %d is not a name or index", i + 1);
+ goto out;
}
- if ((pos = next - path) == loc->l)
- return zbx_jsonpath_error(*pnext);
-
- loc->r = pos - 1;
- *type = ZBX_JSONPATH_COMPONENT_BRACKET;
-
- SKIP_WHITESPACE_NEXT(next);
- }
-
- if (']' != *next++)
- return zbx_jsonpath_error(*pnext);
-
- *pnext = next;
-
- return SUCCEED;
-}
-
-/******************************************************************************
- * *
- * Function: zbx_json_path_open *
- * *
- * Purpose: opens an object by json path *
- * *
- * Return value: SUCCESS - processed successfully *
- * FAIL - an error occurred *
- * *
- * Comments: Only direct path to single object in dot or bracket notation *
- * is supported. *
- * *
- ******************************************************************************/
-int zbx_json_path_open(const struct zbx_json_parse *jp, const char *path, struct zbx_json_parse *out)
-{
- const char *p, *next = 0;
- char buffer[MAX_STRING_LEN];
- zbx_strloc_t loc;
- int type, index;
- struct zbx_json_parse object;
-
- object = *jp;
-
- do
- {
- if (FAIL == jsonpath_next(path, &next, &loc, &type))
- return FAIL;
-
- if (ZBX_JSONPATH_ARRAY_INDEX == type)
+ if (ZBX_JSONPATH_LIST_INDEX == segment->data.list.type)
{
+ int index;
+
if ('[' != *object.start)
- return FAIL;
+ goto out;
- if (FAIL == is_uint_n_range(path + loc.l, loc.r - loc.l + 1, &index, sizeof(index), 0,
- 0xFFFFFFFF))
- {
- return FAIL;
- }
+ memcpy(&index, segment->data.list.values->data, sizeof(int));
for (p = NULL; NULL != (p = zbx_json_next(&object, p)) && 0 != index; index--)
;
if (0 != index || NULL == p)
{
- zbx_set_json_strerror("array index out of bounds starting with json path: \"%s\"",
- path + loc.l);
- return FAIL;
+ zbx_set_json_strerror("array index out of bounds in jsonpath segment %d", i + 1);
+ goto out;
}
}
else
{
- zbx_strlcpy(buffer, path + loc.l, loc.r - loc.l + 2);
-
- if (NULL == (p = zbx_json_pair_by_name(&object, buffer)))
+ if (NULL == (p = zbx_json_pair_by_name(&object, (char *)&segment->data.list.values->data)))
{
- zbx_set_json_strerror("object not found starting with json path: \"%s\"", path + loc.l);
- return FAIL;
+ zbx_set_json_strerror("object not found in jsonpath segment %d", i + 1);
+ goto out;
}
}
@@ -1400,65 +1286,10 @@ int zbx_json_path_open(const struct zbx_json_parse *jp, const char *path, struct
if (NULL == (object.end = __zbx_json_rbracket(p)))
object.end = p + json_parse_value(p, NULL) - 1;
}
- while ('\0' != *next);
*out = object;
-
- return SUCCEED;
-}
-
-/******************************************************************************
- * *
- * Function: zbx_json_value_dyn *
- * *
- * Purpose: return json fragment or value located at json parse location *
- * *
- ******************************************************************************/
-void zbx_json_value_dyn(const struct zbx_json_parse *jp, char **string, size_t *string_alloc)
-{
- if (NULL == zbx_json_decodevalue_dyn(jp->start, string, string_alloc, NULL))
- {
- size_t len = jp->end - jp->start + 2;
-
- if (*string_alloc < len)
- *string = (char *)zbx_realloc(*string, len);
-
- zbx_strlcpy(*string, jp->start, len);
- }
-}
-
-/******************************************************************************
- * *
- * Function: zbx_json_path_check *
- * *
- * Purpose: validate json path string *
- * *
- * Parameters: path - [IN] the json path *
- * error - [OUT] the error message buffer *
- * errlen - [IN] the size of error message buffer *
- * *
- * Return value: SUCCEED - the json path component was parsed successfully *
- * FAIL - json path parsing error *
- * *
- ******************************************************************************/
-int zbx_json_path_check(const char *path, char * error, size_t errlen)
-{
- const char *next = NULL;
- zbx_strloc_t loc;
- int type;
-
- do
- {
- if (SUCCEED != jsonpath_next(path, &next, &loc, &type))
- {
- zbx_snprintf(error, errlen, "json path not valid: %s", zbx_json_strerror());
- return FAIL;
- }
- }
- while ('\0' != *next);
-
- return SUCCEED;
+ ret = SUCCEED;
+out:
+ zbx_jsonpath_clear(&jsonpath);
+ return ret;
}
-#ifdef HAVE_TESTS
-# include "../../../tests/libs/zbxjson/jsonpath_next_test.c"
-#endif
diff --git a/tests/libs/zbxjson/jsonpath_next_test.h b/src/libs/zbxjson/json.h
index cd824446165..81e02e2ee0b 100644
--- a/tests/libs/zbxjson/jsonpath_next_test.h
+++ b/src/libs/zbxjson/json.h
@@ -17,9 +17,18 @@
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
**/
-#ifndef JSONPATH_NEXT_TEST_H
-#define JSONPATH_NEXT_TEST_H
+#ifndef ZABBIX_JSON_H
+#define ZABBIX_JSON_H
-int zbx_jsonpath_next(const char *path, const char **pnext, zbx_strloc_t *loc, int *type);
+#define SKIP_WHITESPACE(src) \
+ while ('\0' != *(src) && NULL != strchr(ZBX_WHITESPACE, *(src))) (src)++
+
+/* can only be used on non empty string */
+#define SKIP_WHITESPACE_NEXT(src)\
+ (src)++; \
+ SKIP_WHITESPACE(src)
+
+void zbx_set_json_strerror(const char *fmt, ...) __zbx_attr_format_printf(1, 2);
+int zbx_json_open_path(const struct zbx_json_parse *jp, const char *path, struct zbx_json_parse *out);
#endif
diff --git a/src/libs/zbxjson/json_parser.c b/src/libs/zbxjson/json_parser.c
index f04a28d6c69..05c4cd88dc4 100644
--- a/src/libs/zbxjson/json_parser.c
+++ b/src/libs/zbxjson/json_parser.c
@@ -21,6 +21,7 @@
#include "zbxjson.h"
#include "json_parser.h"
+#include "json.h"
#include "log.h"
diff --git a/src/libs/zbxjson/json_parser.h b/src/libs/zbxjson/json_parser.h
index 2d7d28d7030..379d2b44258 100644
--- a/src/libs/zbxjson/json_parser.h
+++ b/src/libs/zbxjson/json_parser.h
@@ -20,13 +20,6 @@
#ifndef ZABBIX_JSON_PARSER_H
#define ZABBIX_JSON_PARSER_H
-#define SKIP_WHITESPACE(src) \
- while ('\0' != *(src) && NULL != strchr(ZBX_WHITESPACE, *(src))) (src)++
-
-#define SKIP_WHITESPACE_NEXT(src)\
- (src)++; \
- SKIP_WHITESPACE(src)
-
int zbx_json_validate(const char *start, char **error);
int json_parse_value(const char *start, char **error);
diff --git a/src/libs/zbxjson/jsonpath.c b/src/libs/zbxjson/jsonpath.c
new file mode 100644
index 00000000000..57003f95410
--- /dev/null
+++ b/src/libs/zbxjson/jsonpath.c
@@ -0,0 +1,2504 @@
+/*
+** Zabbix
+** Copyright (C) 2001-2019 Zabbix SIA
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+**/
+
+#include "common.h"
+#include "log.h"
+#include "zbxalgo.h"
+#include "zbxregexp.h"
+#include "zbxjson.h"
+#include "json.h"
+#include "json_parser.h"
+#include "jsonpath.h"
+
+#include "../zbxalgo/vectorimpl.h"
+
+ZBX_VECTOR_DECL(var, zbx_variant_t)
+ZBX_VECTOR_IMPL(var, zbx_variant_t)
+
+static int jsonpath_query_object(const struct zbx_json_parse *jp_root, const struct zbx_json_parse *jp,
+ const zbx_jsonpath_t *jsonpath, int path_depth, zbx_vector_str_t *objects);
+static int jsonpath_query_array(const struct zbx_json_parse *jp_root, const struct zbx_json_parse *jp,
+ const zbx_jsonpath_t *jsonpath, int path_depth, zbx_vector_str_t *objects);
+
+typedef struct
+{
+ zbx_jsonpath_token_group_t group;
+ int precedence;
+}
+zbx_jsonpath_token_def_t;
+
+/* define token groups and precedence */
+static zbx_jsonpath_token_def_t jsonpath_tokens[] = {
+ {0, 0},
+ {ZBX_JSONPATH_TOKEN_GROUP_OPERAND, 0}, /* ZBX_JSONPATH_TOKEN_PATH_ABSOLUTE */
+ {ZBX_JSONPATH_TOKEN_GROUP_OPERAND, 0}, /* ZBX_JSONPATH_TOKEN_PATH_RELATIVE */
+ {ZBX_JSONPATH_TOKEN_GROUP_OPERAND, 0}, /* ZBX_JSONPATH_TOKEN_CONST_STR */
+ {ZBX_JSONPATH_TOKEN_GROUP_OPERAND, 0}, /* ZBX_JSONPATH_TOKEN_CONST_NUM */
+ {ZBX_JSONPATH_TOKEN_GROUP_NONE, 0}, /* ZBX_JSONPATH_TOKEN_PAREN_LEFT */
+ {ZBX_JSONPATH_TOKEN_GROUP_NONE, 0}, /* ZBX_JSONPATH_TOKEN_PAREN_RIGHT */
+ {ZBX_JSONPATH_TOKEN_GROUP_OPERATOR2, 4}, /* ZBX_JSONPATH_TOKEN_OP_PLUS */
+ {ZBX_JSONPATH_TOKEN_GROUP_OPERATOR2, 4}, /* ZBX_JSONPATH_TOKEN_OP_MINUS */
+ {ZBX_JSONPATH_TOKEN_GROUP_OPERATOR2, 3}, /* ZBX_JSONPATH_TOKEN_OP_MULT */
+ {ZBX_JSONPATH_TOKEN_GROUP_OPERATOR2, 3}, /* ZBX_JSONPATH_TOKEN_OP_DIV */
+ {ZBX_JSONPATH_TOKEN_GROUP_OPERATOR2, 7}, /* ZBX_JSONPATH_TOKEN_OP_EQ */
+ {ZBX_JSONPATH_TOKEN_GROUP_OPERATOR2, 7}, /* ZBX_JSONPATH_TOKEN_OP_NE */
+ {ZBX_JSONPATH_TOKEN_GROUP_OPERATOR2, 6}, /* ZBX_JSONPATH_TOKEN_OP_GT */
+ {ZBX_JSONPATH_TOKEN_GROUP_OPERATOR2, 6}, /* ZBX_JSONPATH_TOKEN_OP_GE */
+ {ZBX_JSONPATH_TOKEN_GROUP_OPERATOR2, 6}, /* ZBX_JSONPATH_TOKEN_OP_LT */
+ {ZBX_JSONPATH_TOKEN_GROUP_OPERATOR2, 6}, /* ZBX_JSONPATH_TOKEN_OP_LE */
+ {ZBX_JSONPATH_TOKEN_GROUP_OPERATOR1, 2}, /* ZBX_JSONPATH_TOKEN_OP_NOT */
+ {ZBX_JSONPATH_TOKEN_GROUP_OPERATOR2, 11}, /* ZBX_JSONPATH_TOKEN_OP_AND */
+ {ZBX_JSONPATH_TOKEN_GROUP_OPERATOR2, 12}, /* ZBX_JSONPATH_TOKEN_OP_OR */
+ {ZBX_JSONPATH_TOKEN_GROUP_OPERATOR2, 7} /* ZBX_JSONPATH_TOKEN_OP_REGEXP */
+};
+
+static int jsonpath_token_precedence(int type)
+{
+ return jsonpath_tokens[type].precedence;
+}
+
+static int jsonpath_token_group(int type)
+{
+ return jsonpath_tokens[type].group;
+}
+
+/******************************************************************************
+ * *
+ * Function: zbx_jsonpath_error *
+ * *
+ * Purpose: set json error message and return FAIL *
+ * *
+ * Comments: This function is used to return from json path parsing functions *
+ * in the case of failure. *
+ * *
+ ******************************************************************************/
+static int zbx_jsonpath_error(const char *path)
+{
+ if ('\0' != *path)
+ zbx_set_json_strerror("unsupported construct in jsonpath starting with: \"%s\"", path);
+ else
+ zbx_set_json_strerror("jsonpath was unexpectedly terminated");
+
+ return FAIL;
+}
+
+/******************************************************************************
+ * *
+ * Function: jsonpath_strndup *
+ * *
+ ******************************************************************************/
+static char *jsonpath_strndup(const char *source, size_t len)
+{
+ char *str;
+
+ str = (char *)zbx_malloc(NULL, len + 1);
+ memcpy(str, source, len);
+ str[len] = '\0';
+
+ return str;
+}
+
+/******************************************************************************
+ * *
+ * Function: jsonpath_unquote *
+ * *
+ * Purpose: unquote single or double quoted string by stripping *
+ * leading/trailing quotes and unescaping backslash sequences *
+ * *
+ * Parameters: value - [OUT] the output value, must have at least len bytes *
+ * start - [IN] a single or double quoted string to unquote *
+ * len - [IN] the length of the input string *
+ * *
+ ******************************************************************************/
+static void jsonpath_unquote(char *value, const char *start, size_t len)
+{
+ const char *end = start + len - 1;
+
+ for (start++; start != end; start++)
+ {
+ if ('\\' == *start)
+ start++;
+
+ *value++ = *start;
+ }
+
+ *value = '\0';
+}
+
+/******************************************************************************
+ * *
+ * Function: jsonpath_unquote_dyn *
+ * *
+ * Purpose: unquote string stripping leading/trailing quotes and unescaping *
+ * backspace sequences *
+ * *
+ * Parameters: start - [IN] the string to unquote including leading and *
+ * trailing quotes *
+ * len - [IN] the length of the input string *
+ * *
+ * Return value: The unescaped string (must be freed by the caller). *
+ * *
+ ******************************************************************************/
+static char *jsonpath_unquote_dyn(const char *start, size_t len)
+{
+ char *value;
+
+ value = (char *)zbx_malloc(NULL, len + 1);
+ jsonpath_unquote(value, start, len);
+
+ return value;
+}
+
+/******************************************************************************
+ * *
+ * Function: jsonpath_list_create_item *
+ * *
+ * Purpose: create jsonpath list item of the specified size *
+ * *
+ ******************************************************************************/
+static zbx_jsonpath_list_node_t *jsonpath_list_create_node(size_t size)
+{
+ return (zbx_jsonpath_list_node_t *)zbx_malloc(NULL, offsetof(zbx_jsonpath_list_node_t, data) + size);
+}
+
+/******************************************************************************
+ * *
+ * Function: jsonpath_list_free *
+ * *
+ * Purpose: free jsonpath list *
+ * *
+ ******************************************************************************/
+static void jsonpath_list_free(zbx_jsonpath_list_node_t *list)
+{
+ zbx_jsonpath_list_node_t *item = list;
+
+ while (NULL != list)
+ {
+ item = list;
+ list = list->next;
+ zbx_free(item);
+ }
+}
+
+/******************************************************************************
+ * *
+ * Function: jsonpath_create_token *
+ * *
+ * Purpose: create jsonpath expression token *
+ * *
+ * Parameters: type - [IN] the token type *
+ * expression - [IN] the expression *
+ * loc - [IN] the token location in the expression *
+ * *
+ * Return value: The created token (must be freed by the caller). *
+ * *
+ ******************************************************************************/
+static zbx_jsonpath_token_t *jsonpath_create_token(int type, const char *expression, const zbx_strloc_t *loc)
+{
+ zbx_jsonpath_token_t *token;
+
+ token = (zbx_jsonpath_token_t *)zbx_malloc(NULL, sizeof(zbx_jsonpath_token_t));
+ token->type = type;
+
+ switch (token->type)
+ {
+ case ZBX_JSONPATH_TOKEN_CONST_STR:
+ token->data = jsonpath_unquote_dyn(expression + loc->l, loc->r - loc->l + 1);
+ break;
+ case ZBX_JSONPATH_TOKEN_PATH_ABSOLUTE:
+ case ZBX_JSONPATH_TOKEN_PATH_RELATIVE:
+ case ZBX_JSONPATH_TOKEN_CONST_NUM:
+ token->data = jsonpath_strndup(expression + loc->l, loc->r - loc->l + 1);
+ break;
+ default:
+ token->data = NULL;
+ }
+
+ return token;
+}
+
+/******************************************************************************
+ * *
+ * Function: jsonpath_token_free *
+ * *
+ ******************************************************************************/
+static void jsonpath_token_free(zbx_jsonpath_token_t *token)
+{
+ zbx_free(token->data);
+ zbx_free(token);
+}
+
+/******************************************************************************
+ * *
+ * Function: jsonpath_reserve *
+ * *
+ * Purpose: reserve space in jsonpath segments array for more segments *
+ * *
+ * Parameters: jsonpath - [IN] the jsonpath data *
+ * num - [IN] the number of segments to reserve *
+ * *
+ ******************************************************************************/
+static void jsonpath_reserve(zbx_jsonpath_t *jsonpath, int num)
+{
+ if (jsonpath->segments_num + num > jsonpath->segments_alloc)
+ {
+ int old_alloc = jsonpath->segments_alloc;
+
+ if (jsonpath->segments_alloc < num)
+ jsonpath->segments_alloc = jsonpath->segments_num + num;
+ else
+ jsonpath->segments_alloc *= 2;
+
+ jsonpath->segments = (zbx_jsonpath_segment_t *)zbx_realloc(jsonpath->segments,
+ sizeof(zbx_jsonpath_segment_t) * jsonpath->segments_alloc);
+
+ /* Initialize the memory allocated for new segments, as parser can set */
+ /* detached flag for the next segment, so the memory cannot be initialized */
+ /* when creating a segment. */
+ memset(jsonpath->segments + old_alloc, 0,
+ (jsonpath->segments_alloc - old_alloc) * sizeof(zbx_jsonpath_segment_t));
+ }
+}
+
+/******************************************************************************
+ * *
+ * Function: jsonpath_segment_clear *
+ * *
+ ******************************************************************************/
+static void jsonpath_segment_clear(zbx_jsonpath_segment_t *segment)
+{
+ switch (segment->type)
+ {
+ case ZBX_JSONPATH_SEGMENT_MATCH_LIST:
+ jsonpath_list_free(segment->data.list.values);
+ break;
+ case ZBX_JSONPATH_SEGMENT_MATCH_EXPRESSION:
+ zbx_vector_ptr_clear_ext(&segment->data.expression.tokens,
+ (zbx_clean_func_t)jsonpath_token_free);
+ zbx_vector_ptr_destroy(&segment->data.expression.tokens);
+ break;
+ default:
+ break;
+ }
+}
+
+/******************************************************************************
+ * *
+ * Function: jsonpath_next *
+ * *
+ * Purpose: find next component of json path *
+ * *
+ * Parameters: pnext - [IN/OUT] the reference to the next path component *
+ * *
+ * Return value: SUCCEED - the json path component was parsed successfully *
+ * FAIL - json path parsing error *
+ * *
+ ******************************************************************************/
+static int jsonpath_next(const char **pnext)
+{
+ const char *next = *pnext, *start;
+
+ /* process dot notation component */
+ if ('.' == *next)
+ {
+ if ('\0' == *(++next))
+ return zbx_jsonpath_error(*pnext);
+
+ if ('[' != *next)
+ {
+ start = next;
+
+ while (0 != isalnum((unsigned char)*next) || '_' == *next)
+ next++;
+
+ if (start == next)
+ return zbx_jsonpath_error(*pnext);
+
+ *pnext = next;
+ return SUCCEED;
+ }
+ }
+
+ if ('[' != *next)
+ return zbx_jsonpath_error(*pnext);
+
+ SKIP_WHITESPACE_NEXT(next);
+
+ /* process array index component */
+ if (0 != isdigit((unsigned char)*next))
+ {
+ size_t pos;
+
+ for (pos = 1; 0 != isdigit((unsigned char)next[pos]); pos++)
+ ;
+
+ next += pos;
+ SKIP_WHITESPACE(next);
+ }
+ else
+ {
+ char quotes;
+
+ if ('\'' != *next && '"' != *next)
+ return zbx_jsonpath_error(*pnext);
+
+ start = next;
+
+ for (quotes = *next++; quotes != *next; next++)
+ {
+ if ('\0' == *next)
+ return zbx_jsonpath_error(*pnext);
+ }
+
+ if (start == next)
+ return zbx_jsonpath_error(*pnext);
+
+ SKIP_WHITESPACE_NEXT(next);
+ }
+
+ if (']' != *next++)
+ return zbx_jsonpath_error(*pnext);
+
+ *pnext = next;
+ return SUCCEED;
+}
+
+/******************************************************************************
+ * *
+ * Function: jsonpath_parse_substring *
+ * *
+ * Purpose: parse single or double quoted substring *
+ * *
+ * Parameters: start - [IN] the substring start *
+ * len - [OUT] the substring length *
+ * *
+ * Return value: SUCCEED - the substring was parsed successfully *
+ * FAIL - otherwise *
+ * *
+ ******************************************************************************/
+static int jsonpath_parse_substring(const char *start, int *len)
+{
+ const char *ptr;
+ char quotes;
+
+ for (quotes = *start, ptr = start + 1; '\0' != *ptr; ptr++)
+ {
+ if (*ptr == quotes)
+ {
+ *len = ptr - start + 1;
+ return SUCCEED;
+ }
+
+ if ('\\' == *ptr)
+ {
+ if (quotes != ptr[1] && '\\' != ptr[1] )
+ return FAIL;
+ ptr++;
+ }
+ }
+
+ return FAIL;
+}
+
+/******************************************************************************
+ * *
+ * Function: jsonpath_parse_path *
+ * *
+ * Purpose: parse jsonpath reference *
+ * *
+ * Parameters: start - [IN] the jsonpath start *
+ * len - [OUT] the jsonpath length *
+ * *
+ * Return value: SUCCEED - the jsonpath was parsed successfully *
+ * FAIL - otherwise *
+ * *
+ * Comments: This function is used to parse jsonpath references used in *
+ * jsonpath filter expressions. *
+ * *
+ ******************************************************************************/
+static int jsonpath_parse_path(const char *start, int *len)
+{
+ const char *ptr = start + 1;
+
+ while ('[' == *ptr || '.' == *ptr)
+ {
+ if (FAIL == jsonpath_next(&ptr))
+ return FAIL;
+ }
+
+ *len = ptr - start;
+ return SUCCEED;
+}
+
+/******************************************************************************
+ * *
+ * Function: jsonpath_parse_number *
+ * *
+ * Purpose: parse number value *
+ * *
+ * Parameters: start - [IN] the number start *
+ * len - [OUT] the number length *
+ * *
+ * Return value: SUCCEED - the number was parsed successfully *
+ * FAIL - otherwise *
+ * *
+ ******************************************************************************/
+static int jsonpath_parse_number(const char *start, int *len)
+{
+ const char *ptr = start;
+ int size;
+
+ if ('-' == *ptr || '+' == *ptr)
+ ptr++;
+
+ if (FAIL == zbx_number_parse(ptr, &size))
+ return FAIL;
+
+ ptr += size;
+
+ if ('e' == *ptr || 'E' == *ptr)
+ {
+ ptr++;
+
+ if ('-' == *ptr || '+' == *ptr)
+ ptr++;
+
+ if (0 == isdigit((unsigned char)*ptr))
+ return FAIL;
+
+ while (0 != isdigit((unsigned char)*ptr))
+ ptr++;
+ }
+
+ *len = ptr - start;
+
+ return SUCCEED;
+}
+
+/******************************************************************************
+ * *
+ * Function: jsonpath_expression_next_token *
+ * *
+ * Purpose: get next token in jsonpath expression *
+ * *
+ * Parameters: exprsesion - [IN] the jsonpath expression *
+ * pos - [IN] the position of token in the expression *
+ * prev_group - [IN] the preceding token group, used to determine *
+ * token type based on context if necessary *
+ * type - [OUT] the token type *
+ * loc - [OUT] the token location in the expression *
+ * *
+ * Return value: SUCCEED - the token was parsed successfully *
+ * FAIL - otherwise *
+ * *
+ ******************************************************************************/
+static int jsonpath_expression_next_token(const char *expression, int pos, int prev_group,
+ zbx_jsonpath_token_type_t *type, zbx_strloc_t *loc)
+{
+ int len;
+ const char *ptr = expression + pos;
+
+ SKIP_WHITESPACE(ptr);
+ loc->l = ptr - expression;
+
+ switch (*ptr)
+ {
+ case '(':
+ *type = ZBX_JSONPATH_TOKEN_PAREN_LEFT;
+ loc->r = loc->l;
+ return SUCCEED;
+ case ')':
+ *type = ZBX_JSONPATH_TOKEN_PAREN_RIGHT;
+ loc->r = loc->l;
+ return SUCCEED;
+ case '+':
+ *type = ZBX_JSONPATH_TOKEN_OP_PLUS;
+ loc->r = loc->l;
+ return SUCCEED;
+ case '-':
+ if (ZBX_JSONPATH_TOKEN_GROUP_OPERAND == prev_group)
+ {
+ *type = ZBX_JSONPATH_TOKEN_OP_MINUS;
+ loc->r = loc->l;
+ return SUCCEED;
+ }
+ break;
+ case '/':
+ *type = ZBX_JSONPATH_TOKEN_OP_DIV;
+ loc->r = loc->l;
+ return SUCCEED;
+ case '*':
+ *type = ZBX_JSONPATH_TOKEN_OP_MULT;
+ loc->r = loc->l;
+ return SUCCEED;
+ case '!':
+ if ('=' == ptr[1])
+ {
+ *type = ZBX_JSONPATH_TOKEN_OP_NE;
+ loc->r = loc->l + 1;
+ return SUCCEED;
+ }
+ *type = ZBX_JSONPATH_TOKEN_OP_NOT;
+ loc->r = loc->l;
+ return SUCCEED;
+ case '=':
+ switch (ptr[1])
+ {
+ case '=':
+ *type = ZBX_JSONPATH_TOKEN_OP_EQ;
+ loc->r = loc->l + 1;
+ return SUCCEED;
+ case '~':
+ *type = ZBX_JSONPATH_TOKEN_OP_REGEXP;
+ loc->r = loc->l + 1;
+ return SUCCEED;
+ }
+ goto out;
+ case '<':
+ if ('=' == ptr[1])
+ {
+ *type = ZBX_JSONPATH_TOKEN_OP_LE;
+ loc->r = loc->l + 1;
+ return SUCCEED;
+ }
+ *type = ZBX_JSONPATH_TOKEN_OP_LT;
+ loc->r = loc->l;
+ return SUCCEED;
+ case '>':
+ if ('=' == ptr[1])
+ {
+ *type = ZBX_JSONPATH_TOKEN_OP_GE;
+ loc->r = loc->l + 1;
+ return SUCCEED;
+ }
+ *type = ZBX_JSONPATH_TOKEN_OP_GT;
+ loc->r = loc->l;
+ return SUCCEED;
+ case '|':
+ if ('|' == ptr[1])
+ {
+ *type = ZBX_JSONPATH_TOKEN_OP_OR;
+ loc->r = loc->l + 1;
+ return SUCCEED;
+ }
+ goto out;
+ case '&':
+ if ('&' == ptr[1])
+ {
+ *type = ZBX_JSONPATH_TOKEN_OP_AND;
+ loc->r = loc->l + 1;
+ return SUCCEED;
+ }
+ goto out;
+ case '@':
+ if (SUCCEED == jsonpath_parse_path(ptr, &len))
+ {
+ *type = ZBX_JSONPATH_TOKEN_PATH_RELATIVE;
+ loc->r = loc->l + len - 1;
+ return SUCCEED;
+ }
+ goto out;
+
+ case '$':
+ if (SUCCEED == jsonpath_parse_path(ptr, &len))
+ {
+ *type = ZBX_JSONPATH_TOKEN_PATH_ABSOLUTE;
+ loc->r = loc->l + len - 1;
+ return SUCCEED;
+ }
+ goto out;
+ case '\'':
+ case '"':
+ if (SUCCEED == jsonpath_parse_substring(ptr, &len))
+ {
+ *type = ZBX_JSONPATH_TOKEN_CONST_STR;
+ loc->r = loc->l + len - 1;
+ return SUCCEED;
+ }
+ goto out;
+ }
+
+ if ('-' == *ptr || 0 != isdigit((unsigned char)*ptr))
+ {
+ if (SUCCEED == jsonpath_parse_number(ptr, &len))
+ {
+ *type = ZBX_JSONPATH_TOKEN_CONST_NUM;
+ loc->r = loc->l + len - 1;
+ return SUCCEED;
+ }
+ }
+out:
+ return zbx_jsonpath_error(ptr);
+}
+
+/******************************************************************************
+ * *
+ * Function: jsonpath_parse_expression *
+ * *
+ * Purpose: parse jsonpath filter expression in format *
+ * *
+ * Parameters: expression - [IN] the expression, including opening and *
+ * closing parenthesis *
+ * jsonpath - [IN/OUT] the jsonpath *
+ * next - [OUT] a pointer to the next character after *
+ * parsed expression *
+ * *
+ * Return value: SUCCEED - the expression was parsed successfully *
+ * FAIL - otherwise *
+ * *
+ * Comments: This function uses shunting-yard algorithm to store parsed *
+ * tokens in postfix notation for evaluation. *
+ * *
+ * The following token precedence rules are enforced: *
+ * 1) binary operator must follow an operand *
+ * 2) operand must follow an operator *
+ * 3) unary operator must follow an operator *
+ * 4) ')' must follow an operand *
+ * *
+ ******************************************************************************/
+static int jsonpath_parse_expression(const char *expression, zbx_jsonpath_t *jsonpath, const char **next)
+{
+ int nesting = 1, ret = FAIL;
+ zbx_jsonpath_token_t *optoken;
+ zbx_vector_ptr_t output, operators;
+ zbx_strloc_t loc = {0, 0};
+ zbx_jsonpath_token_type_t token_type;
+ zbx_jsonpath_token_group_t prev_group = ZBX_JSONPATH_TOKEN_GROUP_NONE;
+
+ if ('(' != *expression)
+ return zbx_jsonpath_error(expression);
+
+ zbx_vector_ptr_create(&output);
+ zbx_vector_ptr_create(&operators);
+
+ while (SUCCEED == jsonpath_expression_next_token(expression, loc.r + 1, prev_group, &token_type, &loc))
+ {
+ switch (token_type)
+ {
+ case ZBX_JSONPATH_TOKEN_PAREN_LEFT:
+ nesting++;
+ break;
+
+ case ZBX_JSONPATH_TOKEN_PAREN_RIGHT:
+ if (ZBX_JSONPATH_TOKEN_GROUP_OPERAND != prev_group)
+ {
+ zbx_jsonpath_error(expression + loc.l);
+ goto out;
+ }
+
+ if (0 == --nesting)
+ {
+ *next = expression + loc.r + 1;
+ ret = SUCCEED;
+ goto out;
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (ZBX_JSONPATH_TOKEN_GROUP_OPERAND == jsonpath_token_group(token_type))
+ {
+ /* expression cannot have two consequent operands */
+ if (ZBX_JSONPATH_TOKEN_GROUP_OPERAND == prev_group)
+ {
+ zbx_jsonpath_error(expression + loc.l);
+ goto out;
+ }
+
+ zbx_vector_ptr_append(&output, jsonpath_create_token(token_type, expression, &loc));
+ prev_group = jsonpath_token_group(token_type);
+ continue;
+ }
+
+ if (ZBX_JSONPATH_TOKEN_GROUP_OPERATOR2 == jsonpath_token_group(token_type) ||
+ ZBX_JSONPATH_TOKEN_GROUP_OPERATOR1 == jsonpath_token_group(token_type))
+ {
+ /* binary operator must follow an operand */
+ if (ZBX_JSONPATH_TOKEN_GROUP_OPERATOR2 == jsonpath_token_group(token_type) &&
+ ZBX_JSONPATH_TOKEN_GROUP_OPERAND != prev_group)
+ {
+ zbx_jsonpath_error(expression + loc.l);
+ goto cleanup;
+ }
+
+ /* negation ! operator cannot follow an operand */
+ if (ZBX_JSONPATH_TOKEN_OP_NOT == token_type &&
+ ZBX_JSONPATH_TOKEN_GROUP_OPERAND == prev_group)
+ {
+ zbx_jsonpath_error(expression + loc.l);
+ goto cleanup;
+ }
+
+ for (; 0 < operators.values_num; operators.values_num--)
+ {
+ optoken = operators.values[operators.values_num - 1];
+
+ if (jsonpath_token_precedence(optoken->type) >
+ jsonpath_token_precedence(token_type))
+ {
+ break;
+ }
+
+ if (ZBX_JSONPATH_TOKEN_PAREN_LEFT == optoken->type)
+ break;
+
+ zbx_vector_ptr_append(&output, optoken);
+ }
+
+ zbx_vector_ptr_append(&operators, jsonpath_create_token(token_type, expression, &loc));
+ prev_group = jsonpath_token_group(token_type);
+ continue;
+ }
+
+ if (ZBX_JSONPATH_TOKEN_PAREN_LEFT == token_type)
+ {
+ zbx_vector_ptr_append(&operators, jsonpath_create_token(token_type, expression, &loc));
+ prev_group = ZBX_JSONPATH_TOKEN_GROUP_NONE;
+ continue;
+ }
+
+ if (ZBX_JSONPATH_TOKEN_PAREN_RIGHT == token_type)
+ {
+ /* right parenthesis must follow and operand or right parenthesis */
+ if (ZBX_JSONPATH_TOKEN_GROUP_OPERAND != prev_group)
+ {
+ zbx_jsonpath_error(expression + loc.l);
+ goto cleanup;
+ }
+
+ for (optoken = 0; 0 < operators.values_num; operators.values_num--)
+ {
+ optoken = operators.values[operators.values_num - 1];
+
+ if (ZBX_JSONPATH_TOKEN_PAREN_LEFT == optoken->type)
+ {
+ operators.values_num--;
+ break;
+ }
+
+ zbx_vector_ptr_append(&output, optoken);
+ }
+
+ if (NULL == optoken)
+ {
+ zbx_jsonpath_error(expression + loc.l);
+ goto cleanup;
+ }
+ jsonpath_token_free(optoken);
+
+ prev_group = ZBX_JSONPATH_TOKEN_GROUP_OPERAND;
+ continue;
+ }
+ }
+out:
+ if (SUCCEED == ret)
+ {
+ zbx_jsonpath_segment_t *segment;
+
+ for (optoken = 0; 0 < operators.values_num; operators.values_num--)
+ {
+ optoken = operators.values[operators.values_num - 1];
+
+ if (ZBX_JSONPATH_TOKEN_PAREN_LEFT == optoken->type)
+ {
+ zbx_set_json_strerror("mismatched () brackets in expression: %s", expression);
+ ret = FAIL;
+ goto cleanup;
+ }
+
+ zbx_vector_ptr_append(&output, optoken);
+ }
+
+ jsonpath_reserve(jsonpath, 1);
+ segment = &jsonpath->segments[jsonpath->segments_num++];
+ segment->type = ZBX_JSONPATH_SEGMENT_MATCH_EXPRESSION;
+ zbx_vector_ptr_create(&segment->data.expression.tokens);
+ zbx_vector_ptr_append_array(&segment->data.expression.tokens, output.values, output.values_num);
+
+ jsonpath->definite = 0;
+ }
+cleanup:
+ if (SUCCEED != ret)
+ {
+ zbx_vector_ptr_clear_ext(&operators, (zbx_clean_func_t)jsonpath_token_free);
+ zbx_vector_ptr_clear_ext(&output, (zbx_clean_func_t)jsonpath_token_free);
+ }
+
+ zbx_vector_ptr_destroy(&operators);
+ zbx_vector_ptr_destroy(&output);
+
+ return ret;
+}
+
+/******************************************************************************
+ * *
+ * Function: jsonpath_parse_names *
+ * *
+ * Purpose: parse a list of single or double quoted names, including trivial *
+ * case when a single name is used *
+ * *
+ * Parameters: list - [IN] the name list *
+ * jsonpath - [IN/OUT] the jsonpath *
+ * next - [OUT] a pointer to the next character after parsed *
+ * list *
+ * *
+ * Return value: SUCCEED - the list was parsed successfully *
+ * FAIL - otherwise *
+ * *
+ * Comments: In the trivial case (when list contains one name) the name is *
+ * stored into zbx_jsonpath_list_t:value field and later its *
+ * address is stored into zbx_jsonpath_list_t:values to reduce *
+ * allocations in trivial cases. *
+ * *
+ ******************************************************************************/
+static int jsonpath_parse_names(const char *list, zbx_jsonpath_t *jsonpath, const char **next)
+{
+ zbx_jsonpath_segment_t *segment;
+ int ret = FAIL, parsed_name = 0;
+ const char *end, *start = NULL;
+ zbx_jsonpath_list_node_t *head = NULL;
+
+ for (end = list; ']' != *end || NULL != start; end++)
+ {
+ switch (*end)
+ {
+ case '\'':
+ case '"':
+ if (NULL == start)
+ {
+ start = end;
+ }
+ else if (*start == *end)
+ {
+ zbx_jsonpath_list_node_t *node;
+
+ if (start + 1 == end)
+ {
+ ret = zbx_jsonpath_error(start);
+ goto out;
+ }
+
+ node = jsonpath_list_create_node(end - start + 1);
+ jsonpath_unquote(node->data, start, end - start + 1);
+ node->next = head;
+ head = node;
+ parsed_name = 1;
+ start = NULL;
+ }
+ break;
+ case '\\':
+ if (NULL == start || ('\\' != end[1] && *start != end[1]))
+ {
+ ret = zbx_jsonpath_error(end);
+ goto out;
+ }
+ end++;
+ break;
+ case ' ':
+ case '\t':
+ break;
+ case ',':
+ if (0 == parsed_name)
+ {
+ ret = zbx_jsonpath_error(end);
+ goto out;
+ }
+ parsed_name = 0;
+ break;
+ case '\0':
+ ret = zbx_jsonpath_error(end);
+ goto out;
+ default:
+ if (NULL == start)
+ {
+ ret = zbx_jsonpath_error(end);
+ goto out;
+ }
+ }
+ }
+
+ if (0 == parsed_name)
+ {
+ ret = zbx_jsonpath_error(end);
+ goto out;
+ }
+
+ segment = &jsonpath->segments[jsonpath->segments_num++];
+ segment->type = ZBX_JSONPATH_SEGMENT_MATCH_LIST;
+ segment->data.list.type = ZBX_JSONPATH_LIST_NAME;
+ segment->data.list.values = head;
+
+ if (NULL != head->next)
+ jsonpath->definite = 0;
+
+ head = NULL;
+ *next = end;
+ ret = SUCCEED;
+out:
+ if (NULL != head)
+ jsonpath_list_free(head);
+
+ return ret;
+}
+
+/******************************************************************************
+ * *
+ * Function: jsonpath_parse_indexes *
+ * *
+ * Purpose: parse a list of array indexes or range start:end values *
+ * case when a single name is used *
+ * *
+ * Parameters: list - [IN] the index list *
+ * jsonpath - [IN/OUT] the jsonpath *
+ * next - [OUT] a pointer to the next character after parsed *
+ * list *
+ * *
+ * Return value: SUCCEED - the list was parsed successfully *
+ * FAIL - otherwise *
+ * *
+ ******************************************************************************/
+static int jsonpath_parse_indexes(const char *list, zbx_jsonpath_t *jsonpath, const char **next)
+{
+ zbx_jsonpath_segment_t *segment;
+ const char *end, *start = NULL;
+ int ret = FAIL, type = ZBX_JSONPATH_SEGMENT_UNKNOWN;
+ unsigned int flags = 0, parsed_index = 0;
+ zbx_jsonpath_list_node_t *head = NULL, *node;
+
+ for (end = list; ; end++)
+ {
+ if (0 != isdigit((unsigned char)*end))
+ {
+ if (NULL == start)
+ start = end;
+ continue;
+ }
+
+ if ('-' == *end)
+ {
+ if (NULL != start)
+ {
+ ret = zbx_jsonpath_error(end);
+ goto out;
+ }
+ start = end;
+ continue;
+ }
+
+ if (NULL != start)
+ {
+ int value;
+
+ if ('-' == *start && end == start + 1)
+ {
+ ret = zbx_jsonpath_error(start);
+ goto out;
+ }
+
+ node = jsonpath_list_create_node(sizeof(int));
+ node->next = head;
+ head = node;
+ value = atoi(start);
+ memcpy(node->data, &value, sizeof(int));
+ start = NULL;
+ parsed_index = 1;
+ }
+
+ if (']' == *end)
+ {
+ if (ZBX_JSONPATH_SEGMENT_MATCH_RANGE != type)
+ {
+ if (0 == parsed_index)
+ {
+ ret = zbx_jsonpath_error(end);
+ goto out;
+ }
+ }
+ else
+ flags |= (parsed_index << 1);
+ break;
+ }
+
+ if (':' == *end)
+ {
+ if (ZBX_JSONPATH_SEGMENT_UNKNOWN != type)
+ {
+ ret = zbx_jsonpath_error(end);
+ goto out;
+ }
+ type = ZBX_JSONPATH_SEGMENT_MATCH_RANGE;
+ flags |= parsed_index;
+ parsed_index = 0;
+ }
+ else if (',' == *end)
+ {
+ if (ZBX_JSONPATH_SEGMENT_MATCH_RANGE == type || 0 == parsed_index)
+ {
+ ret = zbx_jsonpath_error(end);
+ goto out;
+ }
+ type = ZBX_JSONPATH_SEGMENT_MATCH_LIST;
+ parsed_index = 0;
+ }
+ else if (' ' != *end && '\t' != *end)
+ {
+ ret = zbx_jsonpath_error(end);
+ goto out;
+ }
+ }
+
+ segment = &jsonpath->segments[jsonpath->segments_num++];
+
+ if (ZBX_JSONPATH_SEGMENT_MATCH_RANGE == type)
+ {
+ node = head;
+
+ segment->type = ZBX_JSONPATH_SEGMENT_MATCH_RANGE;
+ segment->data.range.flags = flags;
+ if (0 != (flags & 0x02))
+ {
+ memcpy(&segment->data.range.end, node->data, sizeof(int));
+ node = node->next;
+ }
+ else
+ segment->data.range.end = 0;
+
+ if (0 != (flags & 0x01))
+ memcpy(&segment->data.range.start, node->data, sizeof(int));
+ else
+ segment->data.range.start = 0;
+
+ jsonpath->definite = 0;
+ }
+ else
+ {
+ segment->type = ZBX_JSONPATH_SEGMENT_MATCH_LIST;
+ segment->data.list.type = ZBX_JSONPATH_LIST_INDEX;
+ segment->data.list.values = head;
+
+ if (NULL != head->next)
+ jsonpath->definite = 0;
+
+ head = NULL;
+ }
+
+ *next = end;
+ ret = SUCCEED;
+out:
+ if (NULL != head)
+ jsonpath_list_free(head);
+
+ return ret;
+}
+
+/******************************************************************************
+ * *
+ * Function: jsonpath_parse_bracket_segment *
+ * *
+ * Purpose: parse jsonpath bracket notation segment *
+ * *
+ * Parameters: start - [IN] the segment start *
+ * jsonpath - [IN/OUT] the jsonpath *
+ * next - [OUT] a pointer to the next character after parsed *
+ * segment *
+ * *
+ * Return value: SUCCEED - the segment was parsed successfully *
+ * FAIL - otherwise *
+ * *
+ ******************************************************************************/
+static int jsonpath_parse_bracket_segment(const char *start, zbx_jsonpath_t *jsonpath, const char **next)
+{
+ const char *ptr = start;
+ int ret;
+
+ SKIP_WHITESPACE(ptr);
+
+ if ('?' == *ptr)
+ {
+ ret = jsonpath_parse_expression(ptr + 1, jsonpath, next);
+ }
+ else if ('*' == *ptr)
+ {
+ jsonpath->segments[jsonpath->segments_num++].type = ZBX_JSONPATH_SEGMENT_MATCH_ALL;
+ jsonpath->definite = 0;
+ *next = ptr + 1;
+ ret = SUCCEED;
+ }
+ else if ('\'' == *ptr || '"' == *ptr)
+ {
+ ret = jsonpath_parse_names(ptr, jsonpath, next);
+ }
+ else if (0 != isdigit((unsigned char)*ptr) || ':' == *ptr || '-' == *ptr)
+ {
+ ret = jsonpath_parse_indexes(ptr, jsonpath, next);
+ }
+ else
+ ret = zbx_jsonpath_error(ptr);
+
+ if (SUCCEED == ret)
+ {
+ ptr = *next;
+ SKIP_WHITESPACE(ptr);
+
+ if (']' != *ptr)
+ return zbx_jsonpath_error(ptr);
+
+ *next = ptr + 1;
+ }
+
+ return ret;
+}
+
+/******************************************************************************
+ * *
+ * Function: jsonpath_parse_dot_segment *
+ * *
+ * Purpose: parse jsonpath dot notation segment *
+ * *
+ * Parameters: start - [IN] the segment start *
+ * jsonpath - [IN/OUT] the jsonpath *
+ * next - [OUT] a pointer to the next character after parsed *
+ * segment *
+ * *
+ * Return value: SUCCEED - the segment was parsed successfully *
+ * FAIL - otherwise *
+ * *
+ ******************************************************************************/
+static int jsonpath_parse_dot_segment(const char *start, zbx_jsonpath_t *jsonpath, const char **next)
+{
+ zbx_jsonpath_segment_t *segment;
+ const char *ptr;
+ int len;
+
+ segment = &jsonpath->segments[jsonpath->segments_num];
+ jsonpath->segments_num++;
+
+ if ('*' == *start)
+ {
+ jsonpath->definite = 0;
+ segment->type = ZBX_JSONPATH_SEGMENT_MATCH_ALL;
+ *next = start + 1;
+ return SUCCEED;
+ }
+
+ for (ptr = start; 0 != isalnum((unsigned char)*ptr) || '_' == *ptr;)
+ ptr++;
+
+ if ('(' == *ptr)
+ {
+ const char *end = ptr + 1;
+
+ SKIP_WHITESPACE(end);
+ if (')' == *end)
+ {
+ if (ZBX_CONST_STRLEN("min") == ptr - start && 0 == strncmp(start, "min", ptr - start))
+ segment->data.function.type = ZBX_JSONPATH_FUNCTION_MIN;
+ else if (ZBX_CONST_STRLEN("max") == ptr - start && 0 == strncmp(start, "max", ptr - start))
+ segment->data.function.type = ZBX_JSONPATH_FUNCTION_MAX;
+ else if (ZBX_CONST_STRLEN("avg") == ptr - start && 0 == strncmp(start, "avg", ptr - start))
+ segment->data.function.type = ZBX_JSONPATH_FUNCTION_AVG;
+ else if (ZBX_CONST_STRLEN("length") == ptr - start && 0 == strncmp(start, "length", ptr - start))
+ segment->data.function.type = ZBX_JSONPATH_FUNCTION_LENGTH;
+ else if (ZBX_CONST_STRLEN("first") == ptr - start && 0 == strncmp(start, "first", ptr - start))
+ segment->data.function.type = ZBX_JSONPATH_FUNCTION_FIRST;
+ else if (ZBX_CONST_STRLEN("sum") == ptr - start && 0 == strncmp(start, "sum", ptr - start))
+ segment->data.function.type = ZBX_JSONPATH_FUNCTION_SUM;
+ else
+ return zbx_jsonpath_error(start);
+
+ segment->type = ZBX_JSONPATH_SEGMENT_FUNCTION;
+ *next = end + 1;
+ return SUCCEED;
+ }
+ }
+
+ if (0 < (len = ptr - start))
+ {
+ segment->type = ZBX_JSONPATH_SEGMENT_MATCH_LIST;
+ segment->data.list.type = ZBX_JSONPATH_LIST_NAME;
+ segment->data.list.values = jsonpath_list_create_node(len + 1);
+ zbx_strlcpy(segment->data.list.values->data, start, len + 1);
+ segment->data.list.values->next = NULL;
+ *next = start + len;
+ return SUCCEED;
+ }
+
+ return zbx_jsonpath_error(start);
+}
+
+/******************************************************************************
+ * *
+ * Function: jsonpath_pointer_to_jp *
+ * *
+ * Purpose: convert a pointer to an object/array/value in json data to *
+ * json parse structure *
+ * *
+ * Parameters: pnext - [IN] a pointer to object/array/value data *
+ * jp - [OUT] json parse data with start/end set *
+ * *
+ * Return value: SUCCEED - pointer was converted successfully *
+ * FAIL - otherwise *
+ * *
+ ******************************************************************************/
+static int jsonpath_pointer_to_jp(const char *pnext, struct zbx_json_parse *jp)
+{
+ if ('[' == *pnext || '{' == *pnext)
+ {
+ return zbx_json_brackets_open(pnext, jp);
+ }
+ else
+ {
+ jp->start = pnext;
+ jp->end = pnext + json_parse_value(pnext, NULL) - 1;
+ return SUCCEED;
+ }
+}
+
+/******************************************************************************
+ * *
+ * Function: jsonpath_query_contents *
+ * *
+ * Purpose: perform the rest of jsonpath query on json data *
+ * *
+ * Parameters: jp_root - [IN] the document root *
+ * pnext - [IN] a pointer to object/array/value in json data *
+ * jsonpath - [IN] the jsonpath *
+ * path_depth - [IN] the jsonpath segment to match *
+ * objects - [OUT] pointers to the matched objects in json *
+ * data *
+ * *
+ * Return value: SUCCEED - the data were queried successfully *
+ * FAIL - otherwise *
+ * *
+ ******************************************************************************/
+static int jsonpath_query_contents(const struct zbx_json_parse *jp_root, const char *pnext,
+ const zbx_jsonpath_t *jsonpath, int path_depth, zbx_vector_str_t *objects)
+{
+ struct zbx_json_parse jp_child;
+
+ switch (*pnext)
+ {
+ case '{':
+ if (FAIL == zbx_json_brackets_open(pnext, &jp_child))
+ return FAIL;
+
+ return jsonpath_query_object(jp_root, &jp_child, jsonpath, path_depth, objects);
+ case '[':
+ if (FAIL == zbx_json_brackets_open(pnext, &jp_child))
+ return FAIL;
+
+ return jsonpath_query_array(jp_root, &jp_child, jsonpath, path_depth, objects);
+ }
+ return SUCCEED;
+}
+
+/******************************************************************************
+ * *
+ * Function: jsonpath_query_next_segment *
+ * *
+ * Purpose: query next segment *
+ * *
+ * Parameters: jp_root - [IN] the document root *
+ * pnext - [IN] a pointer to object/array/value in json data *
+ * jsonpath - [IN] the jsonpath *
+ * path_depth - [IN] the jsonpath segment to match *
+ * objects - [OUT] pointers to the matched objects in json *
+ * data *
+ * *
+ * Return value: SUCCEED - the segment was queried successfully *
+ * FAIL - otherwise *
+ * *
+ ******************************************************************************/
+static int jsonpath_query_next_segment(const struct zbx_json_parse *jp_root, const char *pnext,
+ const zbx_jsonpath_t *jsonpath, int path_depth, zbx_vector_str_t *objects)
+{
+ /* check if jsonpath end has been reached, so we have found matching data */
+ /* (functions are processed afterwards) */
+ if (++path_depth == jsonpath->segments_num ||
+ ZBX_JSONPATH_SEGMENT_FUNCTION == jsonpath->segments[path_depth].type)
+ {
+ zbx_vector_str_append(objects, (char *)pnext);
+ return SUCCEED;
+ }
+
+ /* continue by matching found data against the rest of jsonpath segments */
+ return jsonpath_query_contents(jp_root, pnext, jsonpath, path_depth, objects);
+}
+
+/******************************************************************************
+ * *
+ * Function: jsonpath_match_name *
+ * *
+ * Purpose: match object value name against jsonpath segment name list *
+ * *
+ * Parameters: jp_root - [IN] the document root *
+ * pnext - [IN] a pointer to object value with the specified *
+ * name *
+ * jsonpath - [IN] the jsonpath *
+ * path_depth - [IN] the jsonpath segment to match *
+ * name - [IN] the object value name *
+ * objects - [OUT] pointers to the matched objects in json *
+ * data *
+ * *
+ * Return value: SUCCEED - no errors, failed match is not an error *
+ * FAIL - otherwise *
+ * *
+ ******************************************************************************/
+static int jsonpath_match_name(const struct zbx_json_parse *jp_root, const char *pnext,
+ const zbx_jsonpath_t *jsonpath, int path_depth, const char *name, zbx_vector_str_t *objects)
+{
+ zbx_jsonpath_segment_t *segment;
+ zbx_jsonpath_list_node_t *node;
+
+ segment = &jsonpath->segments[path_depth];
+
+ /* object contents can match only name list */
+ if (ZBX_JSONPATH_LIST_NAME != segment->data.list.type)
+ return SUCCEED;
+
+ for (node = segment->data.list.values; NULL != node; node = node->next)
+ {
+ if (0 == strcmp(name, node->data))
+ {
+ if (FAIL == jsonpath_query_next_segment(jp_root, pnext, jsonpath, path_depth, objects))
+ return FAIL;
+ break;
+ }
+ }
+
+ return SUCCEED;
+}
+
+/******************************************************************************
+ * *
+ * Function: jsonpath_extract_value *
+ * *
+ * Purpose: extract value from json data by the specified path *
+ * *
+ * Parameters: jp - [IN] the parent object *
+ * path - [IN] the jsonpath (definite) *
+ * value - [OUT] the extracted value *
+ * *
+ * Return value: SUCCEED - the value was extracted successfully *
+ * FAIL - in the case of errors or if there was no value to *
+ * extract *
+ * *
+ ******************************************************************************/
+static int jsonpath_extract_value(const struct zbx_json_parse *jp, const char *path, zbx_variant_t *value)
+{
+ struct zbx_json_parse jp_child;
+ char *data = NULL, *tmp_path = NULL;
+ size_t data_alloc = 0;
+ int ret = FAIL;
+
+ if ('@' == *path)
+ {
+ tmp_path = zbx_strdup(NULL, path);
+ *tmp_path = '$';
+ path = tmp_path;
+ }
+
+ if (FAIL == zbx_json_open_path(jp, path, &jp_child))
+ goto out;
+
+ if (NULL == zbx_json_decodevalue_dyn(jp_child.start, &data, &data_alloc, NULL))
+ {
+ size_t len = jp_child.end - jp_child.start + 2;
+
+ data = (char *)zbx_malloc(NULL, len);
+ zbx_strlcpy(data, jp_child.start, len);
+ }
+
+ zbx_variant_set_str(value, data);
+ ret = SUCCEED;
+out:
+ zbx_free(tmp_path);
+
+ return ret;
+}
+
+/******************************************************************************
+ * *
+ * Function: jsonpath_expression_to_str *
+ * *
+ * Purpose: convert jsonpath expression to text format *
+ * *
+ * Parameters: expression - [IN] the jsonpath exprssion *
+ * *
+ * Return value: The converted expression, must be freed by the caller. *
+ * *
+ * Comments: This function is used to include expression in error message. *
+ * *
+ ******************************************************************************/
+static char *jsonpath_expression_to_str(zbx_jsonpath_expression_t *expression)
+{
+ int i;
+ char *str = NULL;
+ size_t str_alloc = 0, str_offset = 0;
+
+ for (i = 0; i < expression->tokens.values_num; i++)
+ {
+ zbx_jsonpath_token_t *token = (zbx_jsonpath_token_t *)expression->tokens.values[i];
+
+ if (0 != i)
+ zbx_strcpy_alloc(&str, &str_alloc, &str_offset, ",");
+
+ switch (token->type)
+ {
+ case ZBX_JSONPATH_TOKEN_PATH_ABSOLUTE:
+ ZBX_FALLTHROUGH;
+ case ZBX_JSONPATH_TOKEN_PATH_RELATIVE:
+ ZBX_FALLTHROUGH;
+ case ZBX_JSONPATH_TOKEN_CONST_STR:
+ ZBX_FALLTHROUGH;
+ case ZBX_JSONPATH_TOKEN_CONST_NUM:
+ zbx_strcpy_alloc(&str, &str_alloc, &str_offset, token->data);
+ break;
+ case ZBX_JSONPATH_TOKEN_PAREN_LEFT:
+ zbx_strcpy_alloc(&str, &str_alloc, &str_offset, "(");
+ break;
+ case ZBX_JSONPATH_TOKEN_PAREN_RIGHT:
+ zbx_strcpy_alloc(&str, &str_alloc, &str_offset, ")");
+ break;
+ case ZBX_JSONPATH_TOKEN_OP_PLUS:
+ zbx_strcpy_alloc(&str, &str_alloc, &str_offset, "+");
+ break;
+ case ZBX_JSONPATH_TOKEN_OP_MINUS:
+ zbx_strcpy_alloc(&str, &str_alloc, &str_offset, "-");
+ break;
+ case ZBX_JSONPATH_TOKEN_OP_MULT:
+ zbx_strcpy_alloc(&str, &str_alloc, &str_offset, "*");
+ break;
+ case ZBX_JSONPATH_TOKEN_OP_DIV:
+ zbx_strcpy_alloc(&str, &str_alloc, &str_offset, "/");
+ break;
+ case ZBX_JSONPATH_TOKEN_OP_EQ:
+ zbx_strcpy_alloc(&str, &str_alloc, &str_offset, "==");
+ break;
+ case ZBX_JSONPATH_TOKEN_OP_NE:
+ zbx_strcpy_alloc(&str, &str_alloc, &str_offset, "!=");
+ break;
+ case ZBX_JSONPATH_TOKEN_OP_GT:
+ zbx_strcpy_alloc(&str, &str_alloc, &str_offset, ">");
+ break;
+ case ZBX_JSONPATH_TOKEN_OP_GE:
+ zbx_strcpy_alloc(&str, &str_alloc, &str_offset, ">=");
+ break;
+ case ZBX_JSONPATH_TOKEN_OP_LT:
+ zbx_strcpy_alloc(&str, &str_alloc, &str_offset, "<");
+ break;
+ case ZBX_JSONPATH_TOKEN_OP_LE:
+ zbx_strcpy_alloc(&str, &str_alloc, &str_offset, "<=");
+ break;
+ case ZBX_JSONPATH_TOKEN_OP_NOT:
+ zbx_strcpy_alloc(&str, &str_alloc, &str_offset, "!");
+ break;
+ case ZBX_JSONPATH_TOKEN_OP_AND:
+ zbx_strcpy_alloc(&str, &str_alloc, &str_offset, "&&");
+ break;
+ case ZBX_JSONPATH_TOKEN_OP_OR:
+ zbx_strcpy_alloc(&str, &str_alloc, &str_offset, "||");
+ break;
+ case ZBX_JSONPATH_TOKEN_OP_REGEXP:
+ zbx_strcpy_alloc(&str, &str_alloc, &str_offset, "=~");
+ break;
+ default:
+ zbx_strcpy_alloc(&str, &str_alloc, &str_offset, "?");
+ break;
+ }
+ }
+
+ return str;
+}
+
+/******************************************************************************
+ * *
+ * Function: jsonpath_set_expression_error *
+ * *
+ * Purpose: set jsonpath expression error message *
+ * *
+ * Parameters: expression - [IN] the jsonpath exprssion *
+ * *
+ * Comments: This function is used to set error message when expression *
+ * evaluation fails *
+ * *
+ ******************************************************************************/
+static void jsonpath_set_expression_error(zbx_jsonpath_expression_t *expression)
+{
+ char *text;
+
+ text = jsonpath_expression_to_str(expression);
+ zbx_set_json_strerror("invalid compiled expression: %s", text);
+ zbx_free(text);
+}
+
+/******************************************************************************
+ * *
+ * Function: jsonpath_variant_to_boolean *
+ * *
+ * Purpose: convert variant value to 'boolean' (1, 0) *
+ * *
+ * Parameters: value - [IN/OUT] the value *
+ * *
+ * Comments: This function is used to cast operand to boolean value for *
+ * boolean functions (and, or, negation). *
+ * *
+ ******************************************************************************/
+static void jsonpath_variant_to_boolean(zbx_variant_t *value)
+{
+ double res;
+
+ switch (value->type)
+ {
+ case ZBX_VARIANT_UI64:
+ res = (0 != value->data.ui64 ? 1 : 0);
+ break;
+ case ZBX_VARIANT_DBL:
+ res = (SUCCEED != zbx_double_compare(value->data.dbl, 0.0) ? 1 : 0);
+ break;
+ case ZBX_VARIANT_STR:
+ res = ('\0' != *value->data.str ? 1 : 0);
+ break;
+ case ZBX_VARIANT_NONE:
+ res = 0;
+ break;
+ default:
+ THIS_SHOULD_NEVER_HAPPEN;
+ res = 0;
+ break;
+ }
+
+ zbx_variant_clear(value);
+ zbx_variant_set_dbl(value, res);
+}
+
+/******************************************************************************
+ * *
+ * Function: jsonpath_regexp_match *
+ * *
+ * Purpose: match text against regular expression *
+ * *
+ * Parameters: text - [IN] the text to match *
+ * pattern - [IN] the regular expression *
+ * result - [OUT] 1.0 if match succeeded, 0.0 otherwise *
+ * *
+ * Return value: SUCCEED - regular expression match was performed *
+ * FAIL - regular expression error *
+ * *
+ ******************************************************************************/
+static int jsonpath_regexp_match(const char *text, const char *pattern, double *result)
+{
+ zbx_regexp_t *rxp;
+ const char *error = NULL;
+
+ if (FAIL == zbx_regexp_compile(pattern, &rxp, &error))
+ {
+ zbx_set_json_strerror("invalid regular expression in JSON path: %s", error);
+ return FAIL;
+ }
+ *result = (0 == zbx_regexp_match_precompiled(text, rxp) ? 1.0 : 0.0);
+ zbx_regexp_free(rxp);
+
+ return SUCCEED;
+}
+
+/******************************************************************************
+ * *
+ * Function: jsonpath_match_expression *
+ * *
+ * Purpose: match json array element/object value against jsonpath expression *
+ * *
+ * Parameters: jp_root - [IN] the document root *
+ * pnext - [IN] a pointer to array element/object value *
+ * jsonpath - [IN] the jsonpath *
+ * path_depth - [IN] the jsonpath segment to match *
+ * objects - [OUT] pointers to the matched objects in json *
+ * data *
+ * *
+ * Return value: SUCCEED - no errors, failed match is not an error *
+ * FAIL - otherwise *
+ * *
+ ******************************************************************************/
+static int jsonpath_match_expression(const struct zbx_json_parse *jp_root, const char *pnext,
+ const zbx_jsonpath_t *jsonpath, int path_depth, zbx_vector_str_t *objects)
+{
+ struct zbx_json_parse jp;
+ zbx_vector_var_t stack;
+ int i, ret = SUCCEED;
+ zbx_jsonpath_segment_t *segment;
+ zbx_variant_t value, *right;
+ double res;
+
+ if (SUCCEED != jsonpath_pointer_to_jp(pnext, &jp))
+ return FAIL;
+
+ zbx_vector_var_create(&stack);
+
+ segment = &jsonpath->segments[path_depth];
+
+ for (i = 0; i < segment->data.expression.tokens.values_num; i++)
+ {
+ zbx_variant_t *left;
+ zbx_jsonpath_token_t *token = (zbx_jsonpath_token_t *)segment->data.expression.tokens.values[i];
+
+ if (ZBX_JSONPATH_TOKEN_GROUP_OPERATOR2 == jsonpath_token_group(token->type))
+ {
+ if (2 > stack.values_num)
+ {
+ jsonpath_set_expression_error(&segment->data.expression);
+ ret = FAIL;
+ goto out;
+ }
+
+ left = &stack.values[stack.values_num - 2];
+ right = &stack.values[stack.values_num - 1];
+
+ switch (token->type)
+ {
+ case ZBX_JSONPATH_TOKEN_OP_PLUS:
+ zbx_variant_convert(left, ZBX_VARIANT_DBL);
+ zbx_variant_convert(right, ZBX_VARIANT_DBL);
+ left->data.dbl += right->data.dbl;
+ stack.values_num--;
+ break;
+ case ZBX_JSONPATH_TOKEN_OP_MINUS:
+ zbx_variant_convert(left, ZBX_VARIANT_DBL);
+ zbx_variant_convert(right, ZBX_VARIANT_DBL);
+ left->data.dbl -= right->data.dbl;
+ stack.values_num--;
+ break;
+ case ZBX_JSONPATH_TOKEN_OP_MULT:
+ zbx_variant_convert(left, ZBX_VARIANT_DBL);
+ zbx_variant_convert(right, ZBX_VARIANT_DBL);
+ left->data.dbl *= right->data.dbl;
+ stack.values_num--;
+ break;
+ case ZBX_JSONPATH_TOKEN_OP_DIV:
+ zbx_variant_convert(left, ZBX_VARIANT_DBL);
+ zbx_variant_convert(right, ZBX_VARIANT_DBL);
+ left->data.dbl /= right->data.dbl;
+ stack.values_num--;
+ break;
+ case ZBX_JSONPATH_TOKEN_OP_EQ:
+ res = (0 == zbx_variant_compare(left, right) ? 1.0 : 0.0);
+ zbx_variant_clear(left);
+ zbx_variant_clear(right);
+ zbx_variant_set_dbl(left, res);
+ stack.values_num--;
+ break;
+ case ZBX_JSONPATH_TOKEN_OP_NE:
+ res = (0 != zbx_variant_compare(left, right) ? 1.0 : 0.0);
+ zbx_variant_clear(left);
+ zbx_variant_clear(right);
+ zbx_variant_set_dbl(left, res);
+ stack.values_num--;
+ break;
+ case ZBX_JSONPATH_TOKEN_OP_GT:
+ res = (0 < zbx_variant_compare(left, right) ? 1.0 : 0.0);
+ zbx_variant_clear(left);
+ zbx_variant_clear(right);
+ zbx_variant_set_dbl(left, res);
+ stack.values_num--;
+ break;
+ case ZBX_JSONPATH_TOKEN_OP_GE:
+ res = (0 <= zbx_variant_compare(left, right) ? 1.0 : 0.0);
+ zbx_variant_clear(left);
+ zbx_variant_clear(right);
+ zbx_variant_set_dbl(left, res);
+ stack.values_num--;
+ break;
+ case ZBX_JSONPATH_TOKEN_OP_LT:
+ res = (0 > zbx_variant_compare(left, right) ? 1.0 : 0.0);
+ zbx_variant_clear(left);
+ zbx_variant_clear(right);
+ zbx_variant_set_dbl(left, res);
+ stack.values_num--;
+ break;
+ case ZBX_JSONPATH_TOKEN_OP_LE:
+ res = (0 >= zbx_variant_compare(left, right) ? 1.0 : 0.0);
+ zbx_variant_clear(left);
+ zbx_variant_clear(right);
+ zbx_variant_set_dbl(left, res);
+ stack.values_num--;
+ break;
+ case ZBX_JSONPATH_TOKEN_OP_AND:
+ jsonpath_variant_to_boolean(left);
+ jsonpath_variant_to_boolean(right);
+ if (SUCCEED != zbx_double_compare(left->data.dbl, 0.0) &&
+ SUCCEED != zbx_double_compare(right->data.dbl, 0.0))
+ {
+ res = 1.0;
+ }
+ else
+ res = 0.0;
+ zbx_variant_set_dbl(left, res);
+ zbx_variant_clear(right);
+ stack.values_num--;
+ break;
+ case ZBX_JSONPATH_TOKEN_OP_OR:
+ jsonpath_variant_to_boolean(left);
+ jsonpath_variant_to_boolean(right);
+ if (SUCCEED != zbx_double_compare(left->data.dbl, 0.0) ||
+ SUCCEED != zbx_double_compare(right->data.dbl, 0.0))
+ {
+ res = 1.0;
+ }
+ else
+ res = 0.0;
+ zbx_variant_set_dbl(left, res);
+ zbx_variant_clear(right);
+ stack.values_num--;
+ break;
+ case ZBX_JSONPATH_TOKEN_OP_REGEXP:
+ zbx_variant_convert(left, ZBX_VARIANT_STR);
+ zbx_variant_convert(right, ZBX_VARIANT_STR);
+ ret = jsonpath_regexp_match(left->data.str, right->data.str, &res);
+ zbx_variant_clear(left);
+ zbx_variant_clear(right);
+
+ if (FAIL == ret)
+ goto out;
+
+ zbx_variant_set_dbl(left, res);
+ stack.values_num--;
+ break;
+ default:
+ break;
+ }
+ continue;
+ }
+
+ switch (token->type)
+ {
+ case ZBX_JSONPATH_TOKEN_PATH_ABSOLUTE:
+ if (FAIL == jsonpath_extract_value(jp_root, token->data, &value))
+ zbx_variant_set_none(&value);
+ zbx_vector_var_append_ptr(&stack, &value);
+ break;
+ case ZBX_JSONPATH_TOKEN_PATH_RELATIVE:
+ /* relative path can be applied only to array or object */
+ if ('[' != *jp.start && '{' != *jp.start)
+ goto out;
+
+ if (FAIL == jsonpath_extract_value(&jp, token->data, &value))
+ zbx_variant_set_none(&value);
+ zbx_vector_var_append_ptr(&stack, &value);
+ break;
+ case ZBX_JSONPATH_TOKEN_CONST_STR:
+ zbx_variant_set_str(&value, zbx_strdup(NULL, token->data));
+ zbx_vector_var_append_ptr(&stack, &value);
+ break;
+ case ZBX_JSONPATH_TOKEN_CONST_NUM:
+ zbx_variant_set_dbl(&value, atof(token->data));
+ zbx_vector_var_append_ptr(&stack, &value);
+ break;
+ case ZBX_JSONPATH_TOKEN_OP_NOT:
+ if (1 > stack.values_num)
+ {
+ jsonpath_set_expression_error(&segment->data.expression);
+ ret = FAIL;
+ goto out;
+ }
+ right = &stack.values[stack.values_num - 1];
+ jsonpath_variant_to_boolean(right);
+ right->data.dbl = 1 - right->data.dbl;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (1 != stack.values_num)
+ {
+ jsonpath_set_expression_error(&segment->data.expression);
+ goto out;
+ }
+
+ jsonpath_variant_to_boolean(&stack.values[0]);
+ if (SUCCEED != zbx_double_compare(stack.values[0].data.dbl, 0.0))
+ ret = jsonpath_query_next_segment(jp_root, pnext, jsonpath, path_depth, objects);
+out:
+ for (i = 0; i < stack.values_num; i++)
+ zbx_variant_clear(&stack.values[i]);
+ zbx_vector_var_destroy(&stack);
+
+ return ret;
+}
+
+/******************************************************************************
+ * *
+ * Function: jsonpath_query_object *
+ * *
+ * Purpose: query object fields for jsonpath segment match *
+ * *
+ * Parameters: jp_root - [IN] the document root *
+ * jp - [IN] the json object to query *
+ * jsonpath - [IN] the jsonpath *
+ * path_depth - [IN] the jsonpath segment to match *
+ * objects - [OUT] pointers to the matched objects in json *
+ * data *
+ * *
+ * Return value: SUCCEED - the object was queried successfully *
+ * FAIL - otherwise *
+ * *
+ ******************************************************************************/
+static int jsonpath_query_object(const struct zbx_json_parse *jp_root, const struct zbx_json_parse *jp,
+ const zbx_jsonpath_t *jsonpath, int path_depth, zbx_vector_str_t *objects)
+{
+ const char *pnext = NULL;
+ char name[MAX_STRING_LEN];
+ zbx_jsonpath_segment_t *segment;
+ int ret = SUCCEED;
+
+ segment = &jsonpath->segments[path_depth];
+
+ while (NULL != (pnext = zbx_json_pair_next(jp, pnext, name, sizeof(name))) && SUCCEED == ret)
+ {
+ switch (segment->type)
+ {
+ case ZBX_JSONPATH_SEGMENT_MATCH_ALL:
+ ret = jsonpath_query_next_segment(jp_root, pnext, jsonpath, path_depth, objects);
+ break;
+ case ZBX_JSONPATH_SEGMENT_MATCH_LIST:
+ ret = jsonpath_match_name(jp_root, pnext, jsonpath, path_depth, name, objects);
+ break;
+ case ZBX_JSONPATH_SEGMENT_MATCH_EXPRESSION:
+ ret = jsonpath_match_expression(jp_root, pnext, jsonpath, path_depth, objects);
+ break;
+ default:
+ break;
+ }
+
+ if (1 == segment->detached)
+ ret = jsonpath_query_contents(jp_root, pnext, jsonpath, path_depth, objects);
+ }
+
+ return ret;
+}
+
+/******************************************************************************
+ * *
+ * Function: jsonpath_match_index *
+ * *
+ * Purpose: match array element against segment index list *
+ * *
+ * Parameters: jp_root - [IN] the document root *
+ * pnext - [IN] a pointer to an array element *
+ * jsonpath - [IN] the jsonpath *
+ * path_depth - [IN] the jsonpath segment to match *
+ * index - [IN] the array element index *
+ * elements_num - [IN] the total number of elements in array *
+ * objects - [OUT] pointers to the matched objects in json *
+ * data *
+ * *
+ * Return value: SUCCEED - no errors, failed match is not an error *
+ * FAIL - otherwise *
+ * *
+ ******************************************************************************/
+static int jsonpath_match_index(const struct zbx_json_parse *jp_root, const char *pnext,
+ const zbx_jsonpath_t *jsonpath, int path_depth, int index, int elements_num, zbx_vector_str_t *objects)
+{
+ zbx_jsonpath_segment_t *segment;
+ zbx_jsonpath_list_node_t *node;
+
+ segment = &jsonpath->segments[path_depth];
+
+ /* array contents can match only index list */
+ if (ZBX_JSONPATH_LIST_INDEX != segment->data.list.type)
+ return SUCCEED;
+
+ for (node = segment->data.list.values; NULL != node; node = node->next)
+ {
+ int query_index;
+
+ memcpy(&query_index, node->data, sizeof(query_index));
+
+ if ((query_index >= 0 && index == query_index) || index == elements_num + query_index)
+ {
+ if (FAIL == jsonpath_query_next_segment(jp_root, pnext, jsonpath, path_depth, objects))
+ return FAIL;
+ break;
+ }
+ }
+
+ return SUCCEED;
+}
+
+/******************************************************************************
+ * *
+ * Function: jsonpath_match_range *
+ * *
+ * Purpose: match array element against segment index range *
+ * *
+ * Parameters: jp_root - [IN] the document root *
+ * pnext - [IN] a pointer to an array element *
+ * jsonpath - [IN] the jsonpath *
+ * path_depth - [IN] the jsonpath segment to match *
+ * index - [IN] the array element index *
+ * elements_num - [IN] the total number of elements in array *
+ * objects - [OUT] pointers to the matched objects in json *
+ * data *
+ * *
+ * Return value: SUCCEED - no errors, failed match is not an error *
+ * FAIL - otherwise *
+ * *
+ ******************************************************************************/
+static int jsonpath_match_range(const struct zbx_json_parse *jp_root, const char *pnext,
+ const zbx_jsonpath_t *jsonpath, int path_depth, int index, int elements_num, zbx_vector_str_t *objects)
+{
+ int start_index, end_index;
+ zbx_jsonpath_segment_t *segment;
+
+ segment = &jsonpath->segments[path_depth];
+
+ start_index = (0 != (segment->data.range.flags & 0x01) ? segment->data.range.start : 0);
+ end_index = (0 != (segment->data.range.flags & 0x02) ? segment->data.range.end : elements_num);
+
+ if (0 > start_index)
+ start_index += elements_num;
+ if (0 > end_index)
+ end_index += elements_num;
+
+ if (start_index <= index && end_index > index)
+ {
+ if (FAIL == jsonpath_query_next_segment(jp_root, pnext, jsonpath, path_depth, objects))
+ return FAIL;
+ }
+
+ return SUCCEED;
+}
+
+/******************************************************************************
+ * *
+ * Function: jsonpath_query_array *
+ * *
+ * Purpose: query array elements for jsonpath segment match *
+ * *
+ * Parameters: jp_root - [IN] the document root *
+ * jp - [IN] the json array to query *
+ * jsonpath - [IN] the jsonpath *
+ * path_depth - [IN] the jsonpath segment to match *
+ * objects - [OUT] pointers to the matched objects in json *
+ * data *
+ * *
+ * Return value: SUCCEED - the array was queried successfully *
+ * FAIL - otherwise *
+ * *
+ ******************************************************************************/
+static int jsonpath_query_array(const struct zbx_json_parse *jp_root, const struct zbx_json_parse *jp,
+ const zbx_jsonpath_t *jsonpath, int path_depth, zbx_vector_str_t *objects)
+{
+ const char *pnext = NULL;
+ int index = 0, elements_num = 0, ret = SUCCEED;
+ zbx_jsonpath_segment_t *segment;
+
+ segment = &jsonpath->segments[path_depth];
+
+ while (NULL != (pnext = zbx_json_next(jp, pnext)))
+ elements_num++;
+
+ while (NULL != (pnext = zbx_json_next(jp, pnext)) && SUCCEED == ret)
+ {
+ switch (segment->type)
+ {
+ case ZBX_JSONPATH_SEGMENT_MATCH_ALL:
+ ret = jsonpath_query_next_segment(jp_root, pnext, jsonpath, path_depth, objects);
+ break;
+ case ZBX_JSONPATH_SEGMENT_MATCH_LIST:
+ ret = jsonpath_match_index(jp_root, pnext, jsonpath, path_depth, index,
+ elements_num, objects);
+ break;
+ case ZBX_JSONPATH_SEGMENT_MATCH_RANGE:
+ ret = jsonpath_match_range(jp_root, pnext, jsonpath, path_depth, index,
+ elements_num, objects);
+ break;
+ case ZBX_JSONPATH_SEGMENT_MATCH_EXPRESSION:
+ ret = jsonpath_match_expression(jp_root, pnext, jsonpath, path_depth, objects);
+ break;
+ default:
+ break;
+ }
+
+ if (1 == segment->detached)
+ ret = jsonpath_query_contents(jp_root, pnext, jsonpath, path_depth, objects);
+
+ index++;
+ }
+
+ return ret;
+}
+
+/******************************************************************************
+ * *
+ * Function: jsonpath_extract_element *
+ * *
+ * Purpose: extract JSON element value from data *
+ * *
+ * Parameters: ptr - [IN] pointer to the element to extract *
+ * element - [OUT] the extracted element *
+ * *
+ * Return value: SUCCEED - the element was extracted successfully *
+ * FAIL - the pointer was not pointing to a JSON element *
+ * *
+ * Comments: String value element is unquoted, other elements are copied as *
+ * is. *
+ * *
+ ******************************************************************************/
+static int jsonpath_extract_element(const char *ptr, char **element)
+{
+ size_t element_size = 0;
+
+ if (NULL == zbx_json_decodevalue_dyn(ptr, element, &element_size, NULL))
+ {
+ struct zbx_json_parse jp;
+
+ if (SUCCEED != zbx_json_brackets_open(ptr, &jp))
+ return FAIL;
+
+ *element = jsonpath_strndup(jp.start, jp.end - jp.start + 1);
+ }
+
+ return SUCCEED;
+}
+
+/******************************************************************************
+ * *
+ * Function: jsonpath_extract_numeric_value *
+ * *
+ * Purpose: extract numeric value from json data *
+ * *
+ * Parameters: ptr - [IN] pointer to the value to extract *
+ * value - [OUT] the extracted value *
+ * *
+ * Return value: SUCCEED - the value was extracted successfully *
+ * FAIL - the pointer was not pointing at numeric value *
+ * *
+ ******************************************************************************/
+static int jsonpath_extract_numeric_value(const char *ptr, double *value)
+{
+ char buffer[MAX_STRING_LEN];
+
+ if (('-' != *ptr && 0 == isdigit((unsigned char)*ptr)) ||
+ NULL == zbx_json_decodevalue(ptr, buffer, sizeof(buffer), NULL))
+ {
+ zbx_set_json_strerror("array value is not a number starting with: %s", ptr);
+ return FAIL;
+ }
+
+ *value = atof(buffer);
+ return SUCCEED;
+}
+
+/******************************************************************************
+ * *
+ * Function: jsonpath_apply_function *
+ * *
+ * Purpose: apply jsonpath function to the extracted object list *
+ * *
+ * Parameters: objects - [IN] pointers to the objects/arrays/values in *
+ * json data *
+ * type - [IN] the function type *
+ * definite_path - [IN] 1 - if the path is definite (pointing at *
+ * single object) *
+ * 0 - otherwise *
+ * output - [OUT] the output value *
+ * *
+ * Return value: SUCCEED - the function was applied successfully *
+ * FAIL - invalid input data for the function or internal *
+ * json error *
+ * *
+ ******************************************************************************/
+static int jsonpath_apply_function(const zbx_vector_str_t *objects, zbx_jsonpath_function_type_t type,
+ int definite_path, char **output)
+{
+ int i, ret = FAIL;
+ zbx_vector_str_t objects_tmp;
+ double result;
+
+ zbx_vector_str_create(&objects_tmp);
+
+ /* convert definite path result to object array if possible */
+ if (0 != definite_path)
+ {
+ const char *pnext;
+ struct zbx_json_parse jp;
+
+ if (0 == objects->values_num || '[' != *objects->values[0])
+ {
+ /* all functions can be applied only to arrays */
+ /* attempt to apply a function to non-array will fail */
+ zbx_set_json_strerror("cannot apply function to non-array JSON element");
+ goto out;
+ }
+
+ if (FAIL == zbx_json_brackets_open(objects->values[0], &jp))
+ goto out;
+
+ for (pnext = NULL; NULL != (pnext = zbx_json_next(&jp, pnext));)
+ zbx_vector_str_append(&objects_tmp, (char*)pnext);
+
+ objects = &objects_tmp;
+ }
+
+ if (ZBX_JSONPATH_FUNCTION_LENGTH == type)
+ {
+ *output = zbx_dsprintf(NULL, "%d", objects->values_num);
+ ret = SUCCEED;
+ goto out;
+ }
+
+ if (ZBX_JSONPATH_FUNCTION_FIRST == type)
+ {
+ if (0 < objects->values_num)
+ ret = jsonpath_extract_element(objects->values[0], output);
+ else
+ ret = SUCCEED;
+
+ goto out;
+ }
+
+ if (0 == objects->values_num)
+ {
+ zbx_set_json_strerror("cannot apply aggregation function to empty array");
+ goto out;
+ }
+
+ if (FAIL == jsonpath_extract_numeric_value(objects->values[0], &result))
+ goto out;
+
+ for (i = 1; i < objects->values_num; i++)
+ {
+ double value;
+
+ if (FAIL == jsonpath_extract_numeric_value(objects->values[i], &value))
+ goto out;
+
+ switch (type)
+ {
+ case ZBX_JSONPATH_FUNCTION_MIN:
+ if (value < result)
+ result = value;
+ break;
+ case ZBX_JSONPATH_FUNCTION_MAX:
+ if (value > result)
+ result = value;
+ break;
+ case ZBX_JSONPATH_FUNCTION_AVG:
+ case ZBX_JSONPATH_FUNCTION_SUM:
+ result += value;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (ZBX_JSONPATH_FUNCTION_AVG == type)
+ result /= objects->values_num;
+
+ *output = zbx_dsprintf(NULL, ZBX_FS_DBL, result);
+ del_zeros(*output);
+ ret = SUCCEED;
+out:
+ zbx_vector_str_destroy(&objects_tmp);
+
+ return ret;
+}
+
+/******************************************************************************
+ * *
+ * Function: jsonpath_apply_functions *
+ * *
+ * Purpose: apply jsonpath function to the extracted object list *
+ * *
+ * Parameters: jp_root - [IN] the document root *
+ * objects - [IN] pointers to the objects/arrays/values in json*
+ * data *
+ * jsonpath - [IN] the jsonpath *
+ * path_depth - [IN] the jsonpath segment to match *
+ * output - [OUT] the output value *
+ * *
+ * Return value: SUCCEED - the function was applied successfully *
+ * FAIL - invalid input data for the function or internal *
+ * json error *
+ * *
+ ******************************************************************************/
+static int jsonpath_apply_functions(const struct zbx_json_parse *jp_root, const zbx_vector_str_t *objects,
+ const zbx_jsonpath_t *jsonpath, int path_depth, char **output)
+{
+ int ret, clear_input_contents = 0, definite_path;
+ zbx_vector_str_t input;
+
+ zbx_vector_str_create(&input);
+
+ /* when functions are applied directly to the json document (at the start of the jsonpath ) */
+ /* it makes all document as input object */
+ if (0 == path_depth)
+ zbx_vector_str_append(&input, (char *)jp_root->start);
+ else
+ zbx_vector_str_append_array(&input, objects->values, objects->values_num);
+
+ definite_path = jsonpath->definite;
+
+ while (SUCCEED == (ret = jsonpath_apply_function(&input, jsonpath->segments[path_depth].data.function.type,
+ definite_path, output)))
+ {
+ if (++path_depth == jsonpath->segments_num)
+ break;
+
+ if (0 != clear_input_contents)
+ zbx_vector_str_clear_ext(&input, zbx_str_free);
+ else
+ zbx_vector_str_clear(&input);
+
+ zbx_vector_str_append(&input, *output);
+ *output = NULL;
+ clear_input_contents = 1;
+
+ /* functions return single value, so for the next functions path becomes definite */
+ definite_path = 1;
+ }
+
+ if (0 != clear_input_contents)
+ zbx_vector_str_clear_ext(&input, zbx_str_free);
+ zbx_vector_str_destroy(&input);
+
+ return ret;
+}
+
+/******************************************************************************
+ * *
+ * Function: jsonpath_format_query_result *
+ * *
+ * Purpose: format query result, depending on jsonpath type *
+ * *
+ * Parameters: objects - [IN] pointers to the objects/arrays/values in json *
+ * data *
+ * jsonpath - [IN] the jsonpath used to acquire result *
+ * output - [OUT] the output value *
+ * *
+ * Return value: SUCCEED - the result was formatted successfully *
+ * FAIL - invalid result data (internal json error) *
+ * *
+ ******************************************************************************/
+static int jsonpath_format_query_result(const zbx_vector_str_t *objects, zbx_jsonpath_t *jsonpath, char **output)
+{
+ size_t output_offset = 0, output_alloc;
+ int i;
+
+ if (0 == objects->values_num)
+ return SUCCEED;
+
+ if (1 == jsonpath->definite)
+ {
+ return jsonpath_extract_element(objects->values[0], output);
+ }
+
+ /* reserve 32 bytes per returned object plus array start/end [] and terminating zero */
+ output_alloc = objects->values_num * 32 + 3;
+ *output = (char *)zbx_malloc(NULL, output_alloc);
+
+ zbx_chrcpy_alloc(output, &output_alloc, &output_offset, '[');
+
+ for (i = 0; i < objects->values_num; i++)
+ {
+ struct zbx_json_parse jp;
+
+ if (FAIL == jsonpath_pointer_to_jp(objects->values[i], &jp))
+ {
+ zbx_set_json_strerror("cannot format query result, unrecognized json part starting with: %s",
+ objects->values[i]);
+ zbx_free(*output);
+ return FAIL;
+ }
+
+ if (0 != i)
+ zbx_chrcpy_alloc(output, &output_alloc, &output_offset, ',');
+
+ zbx_strncpy_alloc(output, &output_alloc, &output_offset, jp.start, jp.end - jp.start + 1);
+ }
+
+ zbx_chrcpy_alloc(output, &output_alloc, &output_offset, ']');
+
+ return SUCCEED;
+}
+
+/******************************************************************************
+ * *
+ * Function: zbx_jsonpath_clear *
+ * *
+ ******************************************************************************/
+void zbx_jsonpath_clear(zbx_jsonpath_t *jsonpath)
+{
+ int i;
+
+ for (i = 0; i < jsonpath->segments_num; i++)
+ jsonpath_segment_clear(&jsonpath->segments[i]);
+
+ zbx_free(jsonpath->segments);
+}
+
+/******************************************************************************
+ * *
+ * Function: zbx_jsonpath_compile *
+ * *
+ * Purpose: compile jsonpath to be used in queries *
+ * *
+ * Parameters: path - [IN] the path to parse *
+ * jsonpath - [IN/OUT] the compiled jsonpath *
+ * *
+ * Return value: SUCCEED - the segment was parsed successfully *
+ * FAIL - otherwise *
+ * *
+ ******************************************************************************/
+int zbx_jsonpath_compile(const char *path, zbx_jsonpath_t *jsonpath)
+{
+ int ret = FAIL;
+ const char *ptr = path, *next;
+ zbx_jsonpath_segment_type_t segment_type, last_segment_type = ZBX_JSONPATH_SEGMENT_UNKNOWN;
+ zbx_jsonpath_t jpquery;
+
+ if ('$' != *ptr || '\0' == ptr[1])
+ {
+ zbx_set_json_strerror("JSONPath query must start with the root object/element $.");
+ return FAIL;
+ }
+
+ memset(&jpquery, 0, sizeof(zbx_jsonpath_t));
+ jsonpath_reserve(&jpquery, 4);
+ jpquery.definite = 1;
+
+ for (ptr++; '\0' != *ptr; ptr = next)
+ {
+ char prefix;
+
+ jsonpath_reserve(&jpquery, 1);
+
+ if ('.' == (prefix = *ptr))
+ {
+ if ('.' == *(++ptr))
+ {
+ /* mark next segment as detached */
+ zbx_jsonpath_segment_t *segment = &jpquery.segments[jpquery.segments_num];
+
+ if (1 != segment->detached)
+ {
+ segment->detached = 1;
+ jpquery.definite = 0;
+ ptr++;
+ }
+ }
+
+ switch (*ptr)
+ {
+ case '[':
+ prefix = *ptr;
+ break;
+ case '\0':
+ case '.':
+ prefix = 0;
+ break;
+ }
+ }
+
+ switch (prefix)
+ {
+ case '.':
+ ret = jsonpath_parse_dot_segment(ptr, &jpquery, &next);
+ break;
+ case '[':
+ ret = jsonpath_parse_bracket_segment(ptr + 1, &jpquery, &next);
+ break;
+ default:
+ ret = zbx_jsonpath_error(ptr);
+ break;
+ }
+
+ if (SUCCEED != ret)
+ break;
+
+ /* function segments can followed only by function segments */
+ segment_type = jpquery.segments[jpquery.segments_num - 1].type;
+ if (ZBX_JSONPATH_SEGMENT_FUNCTION == last_segment_type && ZBX_JSONPATH_SEGMENT_FUNCTION != segment_type)
+ {
+ ret = zbx_jsonpath_error(ptr);
+ break;
+ }
+ last_segment_type = segment_type;
+ }
+
+ if (SUCCEED == ret && 0 == jpquery.segments_num)
+ ret = zbx_jsonpath_error(ptr);
+
+ if (SUCCEED == ret)
+ *jsonpath = jpquery;
+ else
+ zbx_jsonpath_clear(&jpquery);
+
+ return ret;
+}
+
+/******************************************************************************
+ * *
+ * Function: zbx_jsonpath_query *
+ * *
+ * Purpose: perform jsonpath query on the specified json data *
+ * *
+ * Parameters: jp - [IN] the json data *
+ * path - [IN] the jsonpath *
+ * output - [OUT] the output value *
+ * *
+ * Return value: SUCCEED - the query was performed successfully (empty result *
+ * being counted as successful query) *
+ * FAIL - otherwise *
+ * *
+ ******************************************************************************/
+int zbx_jsonpath_query(const struct zbx_json_parse *jp, const char *path, char **output)
+{
+ zbx_jsonpath_t jsonpath;
+ int path_depth = 0, ret = SUCCEED;
+ zbx_vector_str_t objects;
+
+ if (FAIL == zbx_jsonpath_compile(path, &jsonpath))
+ return FAIL;
+
+ zbx_vector_str_create(&objects);
+
+ if ('{' == *jp->start)
+ ret = jsonpath_query_object(jp, jp, &jsonpath, path_depth, &objects);
+ else if ('[' == *jp->start)
+ ret = jsonpath_query_array(jp, jp, &jsonpath, path_depth, &objects);
+
+ if (SUCCEED == ret)
+ {
+ path_depth = jsonpath.segments_num;
+ while (0 < path_depth && ZBX_JSONPATH_SEGMENT_FUNCTION == jsonpath.segments[path_depth - 1].type)
+ path_depth--;
+
+ if (path_depth < jsonpath.segments_num)
+ ret = jsonpath_apply_functions(jp, &objects, &jsonpath, path_depth, output);
+ else
+ ret = jsonpath_format_query_result(&objects, &jsonpath, output);
+ }
+
+ zbx_vector_str_destroy(&objects);
+ zbx_jsonpath_clear(&jsonpath);
+
+ return ret;
+}
diff --git a/src/libs/zbxjson/jsonpath.h b/src/libs/zbxjson/jsonpath.h
new file mode 100644
index 00000000000..450d4e4d3fb
--- /dev/null
+++ b/src/libs/zbxjson/jsonpath.h
@@ -0,0 +1,159 @@
+/*
+** Zabbix
+** Copyright (C) 2001-2019 Zabbix SIA
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+**/
+
+#ifndef ZABBIX_JSONPATH_H
+#define ZABBIX_JSONPATH_H
+
+#include "zbxalgo.h"
+
+typedef enum
+{
+ ZBX_JSONPATH_SEGMENT_UNKNOWN,
+ ZBX_JSONPATH_SEGMENT_MATCH_ALL,
+ ZBX_JSONPATH_SEGMENT_MATCH_LIST,
+ ZBX_JSONPATH_SEGMENT_MATCH_RANGE,
+ ZBX_JSONPATH_SEGMENT_MATCH_EXPRESSION,
+ ZBX_JSONPATH_SEGMENT_FUNCTION
+}
+zbx_jsonpath_segment_type_t;
+
+/* specifies if the match list contains object property names or array indices */
+typedef enum
+{
+ ZBX_JSONPATH_LIST_NAME = 1,
+ ZBX_JSONPATH_LIST_INDEX
+}
+zbx_jsonpath_list_type_t;
+
+typedef enum
+{
+ ZBX_JSONPATH_FUNCTION_MIN = 1,
+ ZBX_JSONPATH_FUNCTION_MAX,
+ ZBX_JSONPATH_FUNCTION_AVG,
+ ZBX_JSONPATH_FUNCTION_LENGTH,
+ ZBX_JSONPATH_FUNCTION_FIRST,
+ ZBX_JSONPATH_FUNCTION_SUM
+}
+zbx_jsonpath_function_type_t;
+
+typedef struct zbx_jsonpath_list_item
+{
+ struct zbx_jsonpath_list_item *next;
+ /* the structure is always over-allocated so that either int */
+ /* or a zero terminated string can be stored in data */
+ char data[1];
+}
+zbx_jsonpath_list_node_t;
+
+typedef struct
+{
+ zbx_jsonpath_list_node_t *values;
+ zbx_jsonpath_list_type_t type;
+}
+zbx_jsonpath_list_t;
+
+typedef struct
+{
+ int start;
+ int end;
+ unsigned int flags;
+}
+zbx_jsonpath_range_t;
+
+/* expression tokens in postfix notation */
+typedef struct
+{
+ zbx_vector_ptr_t tokens;
+}
+zbx_jsonpath_expression_t;
+
+typedef struct
+{
+ zbx_jsonpath_function_type_t type;
+}
+zbx_jsonpath_function_t;
+
+typedef union
+{
+ zbx_jsonpath_list_t list;
+ zbx_jsonpath_range_t range;
+ zbx_jsonpath_expression_t expression;
+ zbx_jsonpath_function_t function;
+}
+zbx_jsonpath_data_t;
+
+struct zbx_jsonpath_segment
+{
+ zbx_jsonpath_segment_type_t type;
+ zbx_jsonpath_data_t data;
+
+ /* set to 1 if the segment is 'detached' and can be anywhere in parent node tree */
+ unsigned char detached;
+};
+
+/* */
+/* Token groups: */
+/* operand - constant value, jsonpath reference, result of () evaluation */
+/* operator2 - binary operator (arithmetic or comparison) */
+/* operator1 - unary operator (negation !) */
+/* */
+typedef enum
+{
+ ZBX_JSONPATH_TOKEN_GROUP_NONE,
+ ZBX_JSONPATH_TOKEN_GROUP_OPERAND,
+ ZBX_JSONPATH_TOKEN_GROUP_OPERATOR2, /* binary operator */
+ ZBX_JSONPATH_TOKEN_GROUP_OPERATOR1 /* unary operator */
+}
+zbx_jsonpath_token_group_t;
+
+/* expression token types */
+typedef enum
+{
+ ZBX_JSONPATH_TOKEN_PATH_ABSOLUTE = 1,
+ ZBX_JSONPATH_TOKEN_PATH_RELATIVE,
+ ZBX_JSONPATH_TOKEN_CONST_STR,
+ ZBX_JSONPATH_TOKEN_CONST_NUM,
+ ZBX_JSONPATH_TOKEN_PAREN_LEFT,
+ ZBX_JSONPATH_TOKEN_PAREN_RIGHT,
+ ZBX_JSONPATH_TOKEN_OP_PLUS,
+ ZBX_JSONPATH_TOKEN_OP_MINUS,
+ ZBX_JSONPATH_TOKEN_OP_MULT,
+ ZBX_JSONPATH_TOKEN_OP_DIV,
+ ZBX_JSONPATH_TOKEN_OP_EQ,
+ ZBX_JSONPATH_TOKEN_OP_NE,
+ ZBX_JSONPATH_TOKEN_OP_GT,
+ ZBX_JSONPATH_TOKEN_OP_GE,
+ ZBX_JSONPATH_TOKEN_OP_LT,
+ ZBX_JSONPATH_TOKEN_OP_LE,
+ ZBX_JSONPATH_TOKEN_OP_NOT,
+ ZBX_JSONPATH_TOKEN_OP_AND,
+ ZBX_JSONPATH_TOKEN_OP_OR,
+ ZBX_JSONPATH_TOKEN_OP_REGEXP
+}
+zbx_jsonpath_token_type_t;
+
+typedef struct
+{
+ unsigned char type;
+ char *data;
+}
+zbx_jsonpath_token_t;
+
+
+#endif
diff --git a/src/libs/zbxserver/expression.c b/src/libs/zbxserver/expression.c
index 7e1d31bddd3..dc9bb1a74cf 100644
--- a/src/libs/zbxserver/expression.c
+++ b/src/libs/zbxserver/expression.c
@@ -5205,7 +5205,6 @@ static int process_lld_macro_token(char **data, zbx_token_t *token, int flags, c
{
char c, *replace_to = NULL;
int ret = SUCCEED, l ,r;
- size_t replace_to_alloc = 0;
if (ZBX_TOKEN_LLD_FUNC_MACRO == token->type)
{
@@ -5221,7 +5220,7 @@ static int process_lld_macro_token(char **data, zbx_token_t *token, int flags, c
c = (*data)[r + 1];
(*data)[r + 1] = '\0';
- if (SUCCEED != zbx_lld_macro_value_by_name(jp_row, lld_macro_paths, *data + l, &replace_to, &replace_to_alloc))
+ if (SUCCEED != zbx_lld_macro_value_by_name(jp_row, lld_macro_paths, *data + l, &replace_to))
{
zabbix_log(LOG_LEVEL_DEBUG, "cannot substitute macro \"%s\": not found in value set", *data + l);
@@ -5241,7 +5240,6 @@ static int process_lld_macro_token(char **data, zbx_token_t *token, int flags, c
if (ZBX_TOKEN_LLD_FUNC_MACRO == token->type)
{
- replace_to_alloc = 0;
if (SUCCEED != (zbx_calculate_macro_function(*data, &token->data.lld_func_macro, &replace_to)))
{
int len = token->data.lld_func_macro.func.r - token->data.lld_func_macro.func.l + 1;
@@ -5266,6 +5264,9 @@ static int process_lld_macro_token(char **data, zbx_token_t *token, int flags, c
{
if (SUCCEED == is_double_suffix(replace_to, ZBX_FLAG_DOUBLE_SUFFIX))
{
+ size_t replace_to_alloc;
+
+ replace_to_alloc = strlen(replace_to) + 1;
wrap_negative_double_suffix(&replace_to, &replace_to_alloc);
}
else
diff --git a/src/zabbix_agent/Makefile.am b/src/zabbix_agent/Makefile.am
index 32d58ef5de9..79945f77bc6 100644
--- a/src/zabbix_agent/Makefile.am
+++ b/src/zabbix_agent/Makefile.am
@@ -39,9 +39,9 @@ zabbix_agentd_LDADD = \
$(top_srcdir)/src/libs/zbxnix/libzbxnix.a \
$(top_srcdir)/src/libs/zbxcomms/libzbxcomms.a \
$(top_srcdir)/src/libs/zbxconf/libzbxconf.a \
+ $(top_srcdir)/src/libs/zbxjson/libzbxjson.a \
$(top_srcdir)/src/libs/zbxcommon/libzbxcommon.a \
$(top_srcdir)/src/libs/zbxcrypto/libzbxcrypto.a \
- $(top_srcdir)/src/libs/zbxjson/libzbxjson.a \
$(top_srcdir)/src/libs/zbxexec/libzbxexec.a \
$(top_srcdir)/src/libs/zbxcompress/libzbxcompress.a \
$(top_srcdir)/src/libs/zbxmodules/libzbxmodules.a \
diff --git a/src/zabbix_sender/Makefile.am b/src/zabbix_sender/Makefile.am
index 6d39308d8cf..c7395df0754 100644
--- a/src/zabbix_sender/Makefile.am
+++ b/src/zabbix_sender/Makefile.am
@@ -5,6 +5,9 @@ bin_PROGRAMS = zabbix_sender
zabbix_sender_SOURCES = zabbix_sender.c
zabbix_sender_LDADD = \
+ $(top_srcdir)/src/libs/zbxjson/libzbxjson.a \
+ $(top_srcdir)/src/libs/zbxalgo/libzbxalgo.a \
+ $(top_srcdir)/src/libs/zbxregexp/libzbxregexp.a \
$(top_srcdir)/src/libs/zbxcomms/libzbxcomms.a \
$(top_srcdir)/src/libs/zbxcommon/libzbxcommon.a \
$(top_srcdir)/src/libs/zbxlog/libzbxlog.a \
@@ -12,7 +15,6 @@ zabbix_sender_LDADD = \
$(top_srcdir)/src/libs/zbxnix/libzbxnix.a \
$(top_srcdir)/src/libs/zbxcrypto/libzbxcrypto.a \
$(top_srcdir)/src/libs/zbxconf/libzbxconf.a \
- $(top_srcdir)/src/libs/zbxjson/libzbxjson.a \
$(top_srcdir)/src/libs/zbxcompress/libzbxcompress.a
zabbix_sender_LDADD += @SENDER_LIBS@
diff --git a/src/zabbix_server/lld/lld.c b/src/zabbix_server/lld/lld.c
index 824028047bb..0f3348df142 100644
--- a/src/zabbix_server/lld/lld.c
+++ b/src/zabbix_server/lld/lld.c
@@ -224,11 +224,9 @@ static int filter_condition_match(const struct zbx_json_parse *jp_row, const zbx
const lld_condition_t *condition)
{
char *value = NULL;
- size_t value_alloc = 0;
int ret;
- if (SUCCEED == (ret = zbx_lld_macro_value_by_name(jp_row, lld_macro_paths, condition->macro, &value,
- &value_alloc)))
+ if (SUCCEED == (ret = zbx_lld_macro_value_by_name(jp_row, lld_macro_paths, condition->macro, &value)))
{
switch (regexp_match_ex(&condition->regexps, value, condition->regexp, ZBX_CASE_SENSITIVE))
{
@@ -480,7 +478,7 @@ static void lld_check_received_data_for_filter(lld_filter_t *filter, const struc
{
int i, index;
zbx_lld_macro_path_t lld_macro_path_local, *lld_macro_path;
- struct zbx_json_parse jp_out;
+ char *output = NULL;
for (i = 0; i < filter->conditions.values_num; i++)
{
@@ -493,12 +491,13 @@ static void lld_check_received_data_for_filter(lld_filter_t *filter, const struc
{
lld_macro_path = (zbx_lld_macro_path_t *)lld_macro_paths->values[index];
- if (FAIL == zbx_json_path_open(jp_row, lld_macro_path->path, &jp_out))
+ if (FAIL == zbx_jsonpath_query(jp_row, lld_macro_path->path, &output) || NULL == output)
{
*info = zbx_strdcatf(*info,
"Cannot accurately apply filter: no value received for macro \"%s\""
" json path '%s'.\n", lld_macro_path->lld_macro, lld_macro_path->path);
}
+ zbx_free(output);
continue;
}
diff --git a/src/zabbix_server/lld/lld_item.c b/src/zabbix_server/lld/lld_item.c
index cbbb08ebf11..bc5738c0e47 100644
--- a/src/zabbix_server/lld/lld_item.c
+++ b/src/zabbix_server/lld/lld_item.c
@@ -1347,6 +1347,7 @@ static int lld_items_preproc_step_validate(const zbx_lld_item_preproc_t * pp, zb
char param1[ITEM_PREPROC_PARAMS_LEN * ZBX_MAX_BYTES_IN_UTF8_CHAR + 1], *param2;
const char* regexp_err = NULL;
zbx_uint64_t value_ui64;
+ zbx_jsonpath_t jsonpath;
*err = '\0';
@@ -1354,7 +1355,6 @@ static int lld_items_preproc_step_validate(const zbx_lld_item_preproc_t * pp, zb
|| (SUCCEED == zbx_token_find(pp->params, 0, &token, ZBX_TOKEN_SEARCH_BASIC)
&& 0 != (token.type & ZBX_TOKEN_USER_MACRO)))
{
-
return SUCCEED;
}
@@ -1381,7 +1381,10 @@ static int lld_items_preproc_step_validate(const zbx_lld_item_preproc_t * pp, zb
case ZBX_PREPROC_JSONPATH:
/* break; is not missing here */
case ZBX_PREPROC_ERROR_FIELD_JSON:
- ret = zbx_json_path_check(pp->params, err, sizeof(err));
+ if (FAIL == (ret = zbx_jsonpath_compile(pp->params, &jsonpath)))
+ zbx_strlcpy(err, zbx_json_strerror(), sizeof(err));
+ else
+ zbx_jsonpath_clear(&jsonpath);
break;
case ZBX_PREPROC_XPATH:
/* break; is not missing here */
diff --git a/src/zabbix_server/preprocessor/item_preproc.c b/src/zabbix_server/preprocessor/item_preproc.c
index bae5fd0db44..83fb3a92170 100644
--- a/src/zabbix_server/preprocessor/item_preproc.c
+++ b/src/zabbix_server/preprocessor/item_preproc.c
@@ -171,7 +171,7 @@ int zbx_item_preproc_convert_value_to_numeric(zbx_variant_t *value_num, const zb
{
case ZBX_VARIANT_DBL:
case ZBX_VARIANT_UI64:
- zbx_variant_set_variant(value_num, value);
+ zbx_variant_copy(value_num, value);
ret = SUCCEED;
break;
case ZBX_VARIANT_STR:
@@ -390,7 +390,7 @@ static int item_preproc_delta(unsigned char value_type, zbx_variant_t *value, co
if (ZBX_VARIANT_NONE != history_value->type)
{
- zbx_variant_set_variant(value, &value_num);
+ zbx_variant_copy(value, &value_num);
if (ZBX_VARIANT_DBL == value->type || ZBX_VARIANT_DBL == history_value->type)
{
@@ -411,7 +411,7 @@ static int item_preproc_delta(unsigned char value_type, zbx_variant_t *value, co
*history_ts = *ts;
zbx_variant_clear(history_value);
- zbx_variant_set_variant(history_value, &value_num);
+ zbx_variant_copy(history_value, &value_num);
zbx_variant_clear(&value_num);
return SUCCEED;
@@ -911,20 +911,24 @@ static int item_preproc_regsub(zbx_variant_t *value, const char *params, char **
******************************************************************************/
static int item_preproc_jsonpath_op(zbx_variant_t *value, const char *params, char **errmsg)
{
- struct zbx_json_parse jp, jp_out;
+ struct zbx_json_parse jp;
char *data = NULL;
- size_t data_alloc = 0;
if (FAIL == item_preproc_convert_value(value, ZBX_VARIANT_STR, errmsg))
return FAIL;
- if (FAIL == zbx_json_open(value->data.str, &jp) || FAIL == zbx_json_path_open(&jp, params, &jp_out))
+ if (FAIL == zbx_json_open(value->data.str, &jp) || FAIL == zbx_jsonpath_query(&jp, params, &data))
{
*errmsg = zbx_strdup(*errmsg, zbx_json_strerror());
return FAIL;
}
- zbx_json_value_dyn(&jp_out, &data, &data_alloc);
+ if (NULL == data)
+ {
+ *errmsg = zbx_strdup(*errmsg, "no data matches the specified path");
+ return FAIL;
+ }
+
zbx_variant_clear(value);
zbx_variant_set_str(value, data);
@@ -1197,7 +1201,7 @@ static int item_preproc_validate_regex(const zbx_variant_t *value, const char *p
const char *errptr = NULL;
char *errmsg;
- zbx_variant_set_variant(&value_str, value);
+ zbx_variant_copy(&value_str, value);
if (FAIL == zbx_variant_convert(&value_str, ZBX_VARIANT_STR))
{
@@ -1253,7 +1257,7 @@ static int item_preproc_validate_not_regex(const zbx_variant_t *value, const cha
const char *errptr = NULL;
char *errmsg;
- zbx_variant_set_variant(&value_str, value);
+ zbx_variant_copy(&value_str, value);
if (FAIL == zbx_variant_convert(&value_str, ZBX_VARIANT_STR))
{
@@ -1311,18 +1315,10 @@ out:
static int item_preproc_get_error_from_json(const zbx_variant_t *value, const char *params, char **error)
{
zbx_variant_t value_str;
- char err[MAX_STRING_LEN];
int ret;
- struct zbx_json_parse jp, jp_out;
- size_t data_alloc = 0;
-
- if (FAIL == zbx_json_path_check(params, err, sizeof(err)))
- {
- *error = zbx_strdup(*error, err);
- return FAIL;
- }
+ struct zbx_json_parse jp;
- zbx_variant_set_variant(&value_str, value);
+ zbx_variant_copy(&value_str, value);
if (FAIL == (ret = item_preproc_convert_value(&value_str, ZBX_VARIANT_STR, error)))
{
@@ -1330,14 +1326,21 @@ static int item_preproc_get_error_from_json(const zbx_variant_t *value, const ch
goto out;
}
- if (FAIL == zbx_json_open(value->data.str, &jp) || FAIL == zbx_json_path_open(&jp, params, &jp_out))
+ if (FAIL == zbx_json_open(value->data.str, &jp))
goto out;
- zbx_json_value_dyn(&jp_out, error, &data_alloc);
+ if (FAIL == (ret = zbx_jsonpath_query(&jp, params, error)))
+ {
+ *error = zbx_strdup(NULL, zbx_json_strerror());
+ goto out;
+ }
- zbx_lrtrim(*error, " \t\n\r");
- if ('\0' == **error)
- zbx_free(*error);
+ if (NULL != *error)
+ {
+ zbx_lrtrim(*error, " \t\n\r");
+ if ('\0' == **error)
+ zbx_free(*error);
+ }
out:
zbx_variant_clear(&value_str);
@@ -1380,7 +1383,7 @@ static int item_preproc_get_error_from_xml(const zbx_variant_t *value, const cha
xmlErrorPtr pErr;
xmlBufferPtr xmlBufferLocal;
- zbx_variant_set_variant(&value_str, value);
+ zbx_variant_copy(&value_str, value);
if (FAIL == (ret = item_preproc_convert_value(&value_str, ZBX_VARIANT_STR, error)))
{
@@ -1473,7 +1476,7 @@ static int item_preproc_get_error_from_regex(const zbx_variant_t *value, const c
int ret;
char pattern[ITEM_PREPROC_PARAMS_LEN * ZBX_MAX_BYTES_IN_UTF8_CHAR + 1], *output;
- zbx_variant_set_variant(&value_str, value);
+ zbx_variant_copy(&value_str, value);
if (FAIL == (ret = item_preproc_convert_value(&value_str, ZBX_VARIANT_STR, error)))
{
@@ -1534,7 +1537,7 @@ static int item_preproc_throttle_value(zbx_variant_t *value, const zbx_timespec_
ret = zbx_variant_compare(value, history_value);
zbx_variant_clear(history_value);
- zbx_variant_set_variant(history_value, value);
+ zbx_variant_copy(history_value, value);
if (0 == ret)
zbx_variant_clear(value);
@@ -1576,7 +1579,7 @@ static int item_preproc_throttle_timed_value(zbx_variant_t *value, const zbx_tim
ret = zbx_variant_compare(value, history_value);
zbx_variant_clear(history_value);
- zbx_variant_set_variant(history_value, value);
+ zbx_variant_copy(history_value, value);
if (ZBX_VARIANT_NONE != history_value->type)
period = ts->sec - history_ts->sec;
@@ -1931,7 +1934,7 @@ int zbx_item_preproc_test(unsigned char value_type, zbx_variant_t *value, const
break;
}
- zbx_variant_set_variant(&results[i].value, value);
+ zbx_variant_copy(&results[i].value, value);
if (ZBX_VARIANT_NONE != history_value.type)
{
diff --git a/src/zabbix_server/preprocessor/preproc_worker.c b/src/zabbix_server/preprocessor/preproc_worker.c
index 2d09ba95414..a451b5b46b6 100644
--- a/src/zabbix_server/preprocessor/preproc_worker.c
+++ b/src/zabbix_server/preprocessor/preproc_worker.c
@@ -241,7 +241,7 @@ static int worker_item_preproc_execute(unsigned char value_type, zbx_variant_t *
/* result history is kept to report results of steps before failing step, */
/* which means it can be omitted for the last step. */
if (i != steps_num - 1)
- zbx_variant_set_variant(&results[i].value, value);
+ zbx_variant_copy(&results[i].value, value);
else
zbx_variant_set_none(&results[i].value);
}
@@ -302,7 +302,7 @@ static void worker_preprocess_value(zbx_ipc_socket_t *socket, zbx_ipc_message_t
zbx_preprocessor_unpack_task(&itemid, &value_type, &ts, &value, &history_in, &steps, &steps_num,
message->data);
- zbx_variant_set_variant(&value_start, &value);
+ zbx_variant_copy(&value_start, &value);
results = (zbx_preproc_result_t *)zbx_malloc(NULL, sizeof(zbx_preproc_result_t) * steps_num);
memset(results, 0, sizeof(zbx_preproc_result_t) * steps_num);
@@ -385,7 +385,7 @@ static void worker_test_value(zbx_ipc_socket_t *socket, zbx_ipc_message_t *messa
message->data);
zbx_variant_set_str(&value, value_str);
- zbx_variant_set_variant(&value_start, &value);
+ zbx_variant_copy(&value_start, &value);
results = (zbx_preproc_result_t *)zbx_malloc(NULL, sizeof(zbx_preproc_result_t) * steps_num);
memset(results, 0, sizeof(zbx_preproc_result_t) * steps_num);
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 2ed13192bc8..4d033c9ed96 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -26,4 +26,6 @@ libzbxmockdata_a_SOURCES = \
zbxmocktime.c \
zbxmockhelper.c \
zbxmockhelper.h \
- zbxmocklog.c
+ zbxmocklog.c \
+ zbxmockjson.c \
+ zbxmockjson.h
diff --git a/tests/libs/zbxcommon/Makefile.am b/tests/libs/zbxcommon/Makefile.am
index 55164349e3c..82c1d900edb 100644
--- a/tests/libs/zbxcommon/Makefile.am
+++ b/tests/libs/zbxcommon/Makefile.am
@@ -65,11 +65,11 @@ COMMON_LIB_FILES = \
$(top_srcdir)/src/libs/zbxcrypto/libzbxcrypto.a \
$(top_srcdir)/src/libs/zbxcomms/libzbxcomms.a \
$(top_srcdir)/src/libs/zbxcompress/libzbxcompress.a \
+ $(top_srcdir)/src/libs/zbxjson/libzbxjson.a \
$(top_srcdir)/src/libs/zbxcommon/libzbxcommon.a \
$(top_srcdir)/src/libs/zbxsys/libzbxsys.a \
$(top_srcdir)/src/libs/zbxcrypto/libzbxcrypto.a \
$(top_srcdir)/src/libs/zbxcommshigh/libzbxcommshigh.a \
- $(top_srcdir)/src/libs/zbxjson/libzbxjson.a \
$(top_srcdir)/src/libs/zbxhttp/libzbxhttp.a \
$(top_srcdir)/src/libs/zbxipcservice/libzbxipcservice.a \
$(top_srcdir)/src/libs/zbxexec/libzbxexec.a \
diff --git a/tests/libs/zbxcommon/zbx_variant_compare.c b/tests/libs/zbxcommon/zbx_variant_compare.c
index 4b51fc164e3..75cf7b10f64 100644
--- a/tests/libs/zbxcommon/zbx_variant_compare.c
+++ b/tests/libs/zbxcommon/zbx_variant_compare.c
@@ -67,7 +67,6 @@ static void mock_read_variant(const char *path, zbx_variant_t *variant)
return;
}
-
if (0 == strcmp(type, "ZBX_VARIANT_UI64"))
{
zbx_uint64_t value_ui64;
@@ -102,7 +101,6 @@ static void mock_read_variant(const char *path, zbx_variant_t *variant)
fail_msg("Invalid variant type: %s", type);
}
-
void zbx_mock_test_entry(void **state)
{
zbx_variant_t value1, value2;
diff --git a/tests/libs/zbxcommon/zbx_variant_compare.yaml b/tests/libs/zbxcommon/zbx_variant_compare.yaml
index b7d4f6e3c60..98e95c3eded 100644
--- a/tests/libs/zbxcommon/zbx_variant_compare.yaml
+++ b/tests/libs/zbxcommon/zbx_variant_compare.yaml
@@ -414,5 +414,27 @@ in:
value: 12 34 56 78 90
out:
return: less
+---
+test case: none < uint64
+in:
+ value1:
+ type: ZBX_VARIANT_NONE
+ value:
+ value2:
+ type: ZBX_VARIANT_UI64
+ value: 123
+out:
+ return: less
+---
+test case: uint64 > none
+in:
+ value1:
+ type: ZBX_VARIANT_UI64
+ value: 123
+ value2:
+ type: ZBX_VARIANT_NONE
+ value:
+out:
+ return: greater
...
diff --git a/tests/libs/zbxhistory/Makefile.am b/tests/libs/zbxhistory/Makefile.am
index 74d383f60f8..503b2b0f39d 100644
--- a/tests/libs/zbxhistory/Makefile.am
+++ b/tests/libs/zbxhistory/Makefile.am
@@ -18,6 +18,8 @@ HISTORY_LIBS = \
$(top_srcdir)/src/libs/zbxmemory/libzbxmemory.a \
$(top_srcdir)/src/libs/zbxhistory/libzbxhistory.a \
$(top_srcdir)/src/libs/zbxjson/libzbxjson.a \
+ $(top_srcdir)/src/libs/zbxregexp/libzbxregexp.a \
+ $(top_srcdir)/src/libs/zbxcommon/libzbxcommon.a \
$(top_srcdir)/src/libs/zbxdbhigh/libzbxdbhigh.a \
$(top_srcdir)/src/libs/zbxdb/libzbxdb.a \
$(top_srcdir)/tests/libzbxmockdata.a
diff --git a/tests/libs/zbxjson/Makefile.am b/tests/libs/zbxjson/Makefile.am
index e1d549a2e5b..f8b706d3d92 100644
--- a/tests/libs/zbxjson/Makefile.am
+++ b/tests/libs/zbxjson/Makefile.am
@@ -1,14 +1,16 @@
noinst_PROGRAMS = \
- jsonpath_next \
- zbx_json_path_open \
+ zbx_json_open_path \
zbx_json_decodevalue \
- zbx_json_decodevalue_dyn
+ zbx_json_decodevalue_dyn \
+ zbx_jsonpath_compile \
+ zbx_jsonpath_query
JSON_LIBS = \
$(top_srcdir)/tests/libzbxmocktest.a \
$(top_srcdir)/tests/libzbxmockdata.a \
$(top_srcdir)/src/libs/zbxjson/libzbxjson.a \
$(top_srcdir)/src/libs/zbxalgo/libzbxalgo.a \
+ $(top_srcdir)/src/libs/zbxregexp/libzbxregexp.a \
$(top_srcdir)/src/libs/zbxcommon/libzbxcommon.a \
$(top_srcdir)/src/libs/zbxcomms/libzbxcomms.a \
$(top_srcdir)/src/libs/zbxcompress/libzbxcompress.a \
@@ -21,35 +23,18 @@ JSON_LIBS = \
$(top_srcdir)/src/libs/zbxconf/libzbxconf.a \
$(top_srcdir)/tests/libzbxmockdata.a
-# jsonpath_next
-
-jsonpath_next_SOURCES = \
- jsonpath_next.c \
- ../../zbxmocktest.h
-
-jsonpath_next_LDADD = $(JSON_LIBS)
-
-if SERVER
-jsonpath_next_LDADD += @SERVER_LIBS@
-jsonpath_next_LDFLAGS = @SERVER_LDFLAGS@
-endif
-
-jsonpath_next_CFLAGS = -I@top_srcdir@/tests
-
-# zbx_json_path_open
-
-zbx_json_path_open_SOURCES = \
- zbx_json_path_open.c \
+zbx_json_open_path_SOURCES = \
+ zbx_json_open_path.c \
../../zbxmocktest.h
-zbx_json_path_open_LDADD = $(JSON_LIBS)
+zbx_json_open_path_LDADD = $(JSON_LIBS)
if SERVER
-zbx_json_path_open_LDADD += @SERVER_LIBS@
-zbx_json_path_open_LDFLAGS = @SERVER_LDFLAGS@
+zbx_json_open_path_LDADD += @SERVER_LIBS@
+zbx_json_open_path_LDFLAGS = @SERVER_LDFLAGS@
endif
-zbx_json_path_open_CFLAGS = -I@top_srcdir@/tests
+zbx_json_open_path_CFLAGS = -I@top_srcdir@/tests
# zbx_json_decodevalue
@@ -83,3 +68,30 @@ endif
zbx_json_decodevalue_dyn_CFLAGS = -I@top_srcdir@/tests
+zbx_jsonpath_compile_SOURCES = \
+ zbx_jsonpath_compile.c \
+ ../../zbxmocktest.h
+
+zbx_jsonpath_compile_LDADD = $(JSON_LIBS)
+
+if SERVER
+zbx_jsonpath_compile_LDADD += @SERVER_LIBS@
+zbx_jsonpath_compile_LDFLAGS = @SERVER_LDFLAGS@
+endif
+
+zbx_jsonpath_compile_CFLAGS = -I@top_srcdir@/tests
+
+# zbx_jsonpath_query
+
+zbx_jsonpath_query_SOURCES = \
+ zbx_jsonpath_query.c \
+ ../../zbxmocktest.h
+
+zbx_jsonpath_query_LDADD = $(JSON_LIBS)
+
+if SERVER
+zbx_jsonpath_query_LDADD += @SERVER_LIBS@
+zbx_jsonpath_query_LDFLAGS = @SERVER_LDFLAGS@
+endif
+
+zbx_jsonpath_query_CFLAGS = -I@top_srcdir@/tests
diff --git a/tests/libs/zbxjson/jsonpath_next.c b/tests/libs/zbxjson/jsonpath_next.c
deleted file mode 100644
index 435b9f3fbf0..00000000000
--- a/tests/libs/zbxjson/jsonpath_next.c
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
-** Zabbix
-** Copyright (C) 2001-2019 Zabbix SIA
-**
-** This program is free software; you can redistribute it and/or modify
-** it under the terms of the GNU General Public License as published by
-** the Free Software Foundation; either version 2 of the License, or
-** (at your option) any later version.
-**
-** This program is distributed in the hope that it will be useful,
-** but WITHOUT ANY WARRANTY; without even the implied warranty of
-** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-** GNU General Public License for more details.
-**
-** You should have received a copy of the GNU General Public License
-** along with this program; if not, write to the Free Software
-** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-**/
-
-#include "zbxmocktest.h"
-#include "zbxmockdata.h"
-#include "zbxmockassert.h"
-#include "zbxmockutil.h"
-
-#include "common.h"
-#include "zbxjson.h"
-#include "jsonpath_next_test.h"
-
-void zbx_mock_test_entry(void **state)
-{
- zbx_mock_handle_t components, component;
- const char *path, *next = NULL, *component_class, *component_value, *result;
- zbx_mock_error_t err;
- zbx_strloc_t loc;
- int type, ret;
- char *buffer;
-
- ZBX_UNUSED(state);
-
- path = zbx_mock_get_parameter_string("in.path");
- result = zbx_mock_get_parameter_string("out.result");
- components = zbx_mock_get_parameter_handle("out.components");
-
- buffer = zbx_malloc(NULL, strlen(path) + 1);
-
- while (1)
- {
- if (SUCCEED != (ret = zbx_jsonpath_next(path, &next, &loc, &type)))
- {
- zbx_mock_assert_str_eq("Return value", result, "fail");
- break;
- }
-
- if (ZBX_MOCK_SUCCESS != (err = zbx_mock_vector_element(components, &component)))
- {
- if (ZBX_MOCK_END_OF_VECTOR == err || ZBX_MOCK_NOT_A_VECTOR == err)
- fail_msg("Too many path components parsed");
- else
- fail_msg("Cannot get vector element: %s", zbx_mock_error_string(err));
- }
-
- component_class = zbx_mock_get_object_member_string(component, "class");
-
- switch (type)
- {
- case 0: /* ZBX_JSONPATH_COMPONENT_DOT */
- zbx_mock_assert_str_eq("Component class", component_class, "dot");
- break;
- case 1: /* ZBX_JSONPATH_COMPONENT_BRACKET */
- zbx_mock_assert_str_eq("Component class", component_class, "bracket");
- break;
- case 2: /* ZBX_JSONPATH_ARRAY_INDEX */
- zbx_mock_assert_str_eq("Component class", component_class, "index");
- break;
- }
-
- zbx_strlcpy(buffer, path + loc.l, loc.r - loc.l + 2);
-
- component_value = zbx_mock_get_object_member_string(component, "value");
- zbx_mock_assert_str_eq("Component value", component_value, buffer);
-
- if ('\0' == *next)
- {
- zbx_mock_assert_str_eq("Return value", result, "succeed");
- break;
- }
- }
-
- if (ZBX_MOCK_SUCCESS == (err = zbx_mock_vector_element(components, &component)))
- fail_msg("Too many path components parsed");
-
- if (ZBX_MOCK_END_OF_VECTOR != err && ZBX_MOCK_NOT_A_VECTOR != err)
- fail_msg("Cannot get vector element: %s", zbx_mock_error_string(err));
-
- zbx_free(buffer);
-}
-
diff --git a/tests/libs/zbxjson/jsonpath_next.yaml b/tests/libs/zbxjson/jsonpath_next.yaml
deleted file mode 100644
index 1a8e1b3d7d2..00000000000
--- a/tests/libs/zbxjson/jsonpath_next.yaml
+++ /dev/null
@@ -1,265 +0,0 @@
-# Invalid JSON paths
-
----
-test case: Invalid path "" - empty path
-in:
- path: ""
-out:
- result: fail
- components:
----
-test case: Invalid path "$" - only root node specified
-in:
- path: $
-out:
- result: fail
- components:
----
-test case: Invalid path "$." - missing dot notation member name
-in:
- path: $.
-out:
- result: fail
- components:
----
-test case: Invalid path "$['a'" - unclosed bracket notation bracket
-in:
- path: $['a'
-out:
- result: fail
- components:
----
-test case: Invalid path "$[a']" - unquoted bracket notation member name
-in:
- path: $[a']
-out:
- result: fail
- components:
----
-test case: Invalid path "$['']" - empty bracked notation member name
-in:
- path: $['']
-out:
- result: fail
- components:
----
-test case: Invalid path "$.a[]" - empty bracked notation member name
-in:
- path: $.a[]
-out:
- result: fail
- components:
- - class: dot
- value: a
----
-test case: Invalid path "$.a[1" - missing array index closing bracket
-in:
- path: $.a[1
-out:
- result: fail
- components:
- - class: dot
- value: a
----
-test case: Invalid path "$['a'][]" - empty bracked notation member name
-in:
- path: $['a'][]
-out:
- result: fail
- components:
- - class: bracket
- value: a
----
-test case: Invalid path "$['a'][1" - missing array index closing bracket
-in:
- path: $['a'][1
-out:
- result: fail
- components:
- - class: bracket
- value: a
----
-test case: Invalid path "$.a." - missing dot notation member name
-in:
- path: $.a.
-out:
- result: fail
- components:
- - class: dot
- value: a
----
-test case: Invalid path "$.['a']" - missing dot notation member name
-in:
- path: $.['a']
-out:
- result: fail
- components:
-
-# Valid JSON paths
-
----
-test case: Valid path "$.a" - get dot notation first level member
-in:
- path: $.a
-out:
- result: succeed
- components:
- - class: dot
- value: a
----
-test case: Valid path "$['a']" - get bracket notation (single quotes) first level member
-in:
- path: $['a']
-out:
- result: succeed
- components:
- - class: bracket
- value: a
----
-test case: Valid path "$[ 'a' ]" - get bracket notation first level member with spacing around member name
-in:
- path: $[ 'a' ]
-out:
- result: succeed
- components:
- - class: bracket
- value: a
----
-test case: Valid path '$["a"]' - get bracket notation (double quotes) first level member
-in:
- path: $["a"]
-out:
- result: succeed
- components:
- - class: bracket
- value: a
----
-test case: Valid path "$.a.b" - get dot notation second level member
-in:
- path: $.a.b
-out:
- result: succeed
- components:
- - class: dot
- value: a
- - class: dot
- value: b
----
-test case: Valid path "$['a'].b" - get mixed notation second level member
-in:
- path: $['a'].b
-out:
- result: succeed
- components:
- - class: bracket
- value: a
- - class: dot
- value: b
----
-test case: Valid path "$['a']['b']" - get bracket notation second level member
-in:
- path: $['a']['b']
-out:
- result: succeed
- components:
- - class: bracket
- value: a
- - class: bracket
- value: b
----
-test case: Valid path $.a['b'] - get mixed notation second level member
-in:
- path: $.a['b']
-out:
- result: succeed
- components:
- - class: dot
- value: a
- - class: bracket
- value: b
----
-test case: Valid path $.a[0] - get first array element
-in:
- path: $.a[0]
-out:
- result: succeed
- components:
- - class: dot
- value: a
- - class: index
- value: 0
----
-test case: Valid path $.a[0].b[1] - get array elements from mixed dot notation members and arrays
-in:
- path: $.a[0].b[1]
-out:
- result: succeed
- components:
- - class: dot
- value: a
- - class: index
- value: 0
- - class: dot
- value: b
- - class: index
- value: 1
----
-test case: Valid path $.a[1000] - get 1001th array element
-in:
- path: $.a[1000]
-out:
- result: succeed
- components:
- - class: dot
- value: a
- - class: index
- value: 1000
----
-test case: Valid path $.a[ 1 ] - get second array element with whitespace enclosing index
-in:
- path: $.a[ 1 ]
-out:
- result: succeed
- components:
- - class: dot
- value: a
- - class: index
- value: 1
----
-test case: Valid path $['a'][2] - get third array element of bracket notation first level member
-in:
- path: $['a'][2]
-out:
- result: succeed
- components:
- - class: bracket
- value: a
- - class: index
- value: 2
----
-test case: Valid path $['a'][2]['b'][3] - get array elements from mixed bracket notation members and arrays
-in:
- path: $['a'][2]['b'][3]
-out:
- result: succeed
- components:
- - class: bracket
- value: a
- - class: index
- value: 2
- - class: bracket
- value: b
- - class: index
- value: 3
----
-test case: Valid path $[1][2] - get nested array element
-in:
- path: $[1][2]
-out:
- result: succeed
- components:
- - class: index
- value: 1
- - class: index
- value: 2
-...
diff --git a/tests/libs/zbxjson/jsonpath_next_test.c b/tests/libs/zbxjson/jsonpath_next_test.c
deleted file mode 100644
index dfe70beb8d4..00000000000
--- a/tests/libs/zbxjson/jsonpath_next_test.c
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
-** Zabbix
-** Copyright (C) 2001-2019 Zabbix SIA
-**
-** This program is free software; you can redistribute it and/or modify
-** it under the terms of the GNU General Public License as published by
-** the Free Software Foundation; either version 2 of the License, or
-** (at your option) any later version.
-**
-** This program is distributed in the hope that it will be useful,
-** but WITHOUT ANY WARRANTY; without even the implied warranty of
-** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-** GNU General Public License for more details.
-**
-** You should have received a copy of the GNU General Public License
-** along with this program; if not, write to the Free Software
-** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-**/
-
-#include "jsonpath_next_test.h"
-
-int zbx_jsonpath_next(const char *path, const char **pnext, zbx_strloc_t *loc, int *type)
-{
- return jsonpath_next(path, pnext, loc, type);
-}
diff --git a/tests/libs/zbxjson/mock_json.c b/tests/libs/zbxjson/mock_json.c
index 56172b0b3ac..7bd2454a2d6 100644
--- a/tests/libs/zbxjson/mock_json.c
+++ b/tests/libs/zbxjson/mock_json.c
@@ -23,6 +23,7 @@
#include "common.h"
#include "zbxjson.h"
+#include "mock_json.h"
const char *zbx_mock_json_type_to_str(int type)
{
diff --git a/tests/libs/zbxjson/zbx_json_path_open.c b/tests/libs/zbxjson/zbx_json_open_path.c
index e65b491e819..6ef6e25cbf6 100644
--- a/tests/libs/zbxjson/zbx_json_path_open.c
+++ b/tests/libs/zbxjson/zbx_json_open_path.c
@@ -24,6 +24,21 @@
#include "common.h"
#include "zbxjson.h"
+#include "../../../src/libs/zbxjson/json.h"
+
+static void json_value_dyn(const struct zbx_json_parse *jp, char **string, size_t *string_alloc)
+{
+ if (NULL == zbx_json_decodevalue_dyn(jp->start, string, string_alloc, NULL))
+ {
+ size_t len = jp->end - jp->start + 2;
+
+ if (*string_alloc < len)
+ *string = (char *)zbx_realloc(*string, len);
+
+ zbx_strlcpy(*string, jp->start, len);
+ }
+}
+
void zbx_mock_test_entry(void **state)
{
@@ -42,8 +57,9 @@ void zbx_mock_test_entry(void **state)
ret = zbx_json_open(json, &jp);
zbx_mock_assert_result_eq("Invalid zbx_json_open() return value", SUCCEED, ret);
- if (FAIL == (ret = zbx_json_path_open(&jp, path, &jp_out)))
+ if (FAIL == (ret = zbx_json_open_path(&jp, path, &jp_out)))
{
+ printf("zbx_json_path_open() error: %s\n", zbx_json_strerror());
zbx_mock_assert_str_eq("Invalid zbx_json_path_open() return value", result, "fail");
return;
}
@@ -51,7 +67,7 @@ void zbx_mock_test_entry(void **state)
zbx_mock_assert_result_eq("Invalid zbx_json_path_open() return value", SUCCEED, ret);
zbx_mock_assert_str_eq("Invalid zbx_json_path_open() return value", result, "succeed");
- zbx_json_value_dyn(&jp_out, &buffer, &size);
+ json_value_dyn(&jp_out, &buffer, &size);
value = zbx_mock_get_parameter_string("out.value");
zbx_mock_assert_str_eq("Invalid value", value, buffer);
diff --git a/tests/libs/zbxjson/zbx_json_path_open.yaml b/tests/libs/zbxjson/zbx_json_open_path.yaml
index 5489806ee58..ea868f5490a 100644
--- a/tests/libs/zbxjson/zbx_json_path_open.yaml
+++ b/tests/libs/zbxjson/zbx_json_open_path.yaml
@@ -369,4 +369,46 @@ in:
out:
result: succeed
value: "𐀀𐀀𐀀𐀀"
+---
+test case: 'Invalid path $.*.b in {"a":{"b": [{"x":10}, 2, 3] }}'
+in:
+ json: '{"a":{"b": [{"x":10}, 2, 3] }}'
+ path: $.*.b
+out:
+ result: fail
+---
+test case: 'Invalid path $.a.b[?(@.x == "10")] in {"a":{"b": [{"x":10}, 2, 3] }}'
+in:
+ json: '{"a":{"b": [{"x":10}, 2, 3] }}'
+ path: $.a.b[?(@.x == "10")]
+out:
+ result: fail
+---
+test case: 'Invalid path $["a", "x"].b in {"a":{"b": [{"x":10}, 2, 3] }}'
+in:
+ json: '{"a":{"b": [{"x":10}, 2, 3] }}'
+ path: $['a', 'x'].b
+out:
+ result: fail
+---
+test case: 'Invalid path $.a.b[1,2] in {"a":{"b": [{"x":10}, 2, 3] }}'
+in:
+ json: '{"a":{"b": [{"x":10}, 2, 3] }}'
+ path: $.a.b[1,2]
+out:
+ result: fail
+---
+test case: 'Invalid path $.a.b.length() in {"a":{"b": [{"x":10}, 2, 3] }}'
+in:
+ json: '{"a":{"b": [{"x":10}, 2, 3] }}'
+ path: $.a.b.length()
+out:
+ result: fail
+---
+test case: 'Invalid path $..b in {"a":{"b": [{"x":10}, 2, 3] }}'
+in:
+ json: '{"a":{"b": [{"x":10}, 2, 3] }}'
+ path: $..b
+out:
+ result: fail
...
diff --git a/tests/libs/zbxjson/zbx_jsonpath_compile.c b/tests/libs/zbxjson/zbx_jsonpath_compile.c
new file mode 100644
index 00000000000..6cfe255d2aa
--- /dev/null
+++ b/tests/libs/zbxjson/zbx_jsonpath_compile.c
@@ -0,0 +1,257 @@
+/*
+** Zabbix
+** Copyright (C) 2001-2019 Zabbix SIA
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+**/
+
+#include "zbxmocktest.h"
+#include "zbxmockdata.h"
+#include "zbxmockassert.h"
+#include "zbxmockutil.h"
+
+#include "common.h"
+#include "zbxjson.h"
+
+#include "../../../src/libs/zbxjson/jsonpath.h"
+#include "../../../src/libs/zbxjson/json.h"
+
+static int mock_str_to_segment_type(const char *segment_type)
+{
+ if (0 == strcmp("ZBX_JSONPATH_SEGMENT_MATCH_ALL", segment_type))
+ return ZBX_JSONPATH_SEGMENT_MATCH_ALL;
+ if (0 == strcmp("ZBX_JSONPATH_SEGMENT_MATCH_LIST", segment_type))
+ return ZBX_JSONPATH_SEGMENT_MATCH_LIST;
+ if (0 == strcmp("ZBX_JSONPATH_SEGMENT_MATCH_SLICE", segment_type))
+ return ZBX_JSONPATH_SEGMENT_MATCH_RANGE;
+ if (0 == strcmp("ZBX_JSONPATH_SEGMENT_MATCH_EXPRESSION", segment_type))
+ return ZBX_JSONPATH_SEGMENT_MATCH_EXPRESSION;
+ if (0 == strcmp("ZBX_JSONPATH_SEGMENT_FUNCTION", segment_type))
+ return ZBX_JSONPATH_SEGMENT_FUNCTION;
+
+ fail_msg("Unknown jsonpath segment type: %s", segment_type);
+ return -1;
+}
+
+static void jsonpath_token_print(char **data, size_t *data_alloc, size_t *data_offset,
+ const zbx_jsonpath_token_t *token)
+{
+ switch (token->type)
+ {
+ case ZBX_JSONPATH_TOKEN_PATH_ABSOLUTE:
+ ZBX_FALLTHROUGH;
+ case ZBX_JSONPATH_TOKEN_PATH_RELATIVE:
+ ZBX_FALLTHROUGH;
+ case ZBX_JSONPATH_TOKEN_CONST_STR:
+ ZBX_FALLTHROUGH;
+ case ZBX_JSONPATH_TOKEN_CONST_NUM:
+ zbx_strcpy_alloc(data, data_alloc, data_offset, token->data);
+ break;
+ case ZBX_JSONPATH_TOKEN_PAREN_LEFT:
+ zbx_strcpy_alloc(data, data_alloc, data_offset, "(");
+ break;
+ case ZBX_JSONPATH_TOKEN_PAREN_RIGHT:
+ zbx_strcpy_alloc(data, data_alloc, data_offset, ")");
+ break;
+ case ZBX_JSONPATH_TOKEN_OP_PLUS:
+ zbx_strcpy_alloc(data, data_alloc, data_offset, "+");
+ break;
+ case ZBX_JSONPATH_TOKEN_OP_MINUS:
+ zbx_strcpy_alloc(data, data_alloc, data_offset, "-");
+ break;
+ case ZBX_JSONPATH_TOKEN_OP_MULT:
+ zbx_strcpy_alloc(data, data_alloc, data_offset, "*");
+ break;
+ case ZBX_JSONPATH_TOKEN_OP_DIV:
+ zbx_strcpy_alloc(data, data_alloc, data_offset, "/");
+ break;
+ case ZBX_JSONPATH_TOKEN_OP_EQ:
+ zbx_strcpy_alloc(data, data_alloc, data_offset, "==");
+ break;
+ case ZBX_JSONPATH_TOKEN_OP_NE:
+ zbx_strcpy_alloc(data, data_alloc, data_offset, "!=");
+ break;
+ case ZBX_JSONPATH_TOKEN_OP_GT:
+ zbx_strcpy_alloc(data, data_alloc, data_offset, ">");
+ break;
+ case ZBX_JSONPATH_TOKEN_OP_GE:
+ zbx_strcpy_alloc(data, data_alloc, data_offset, ">=");
+ break;
+ case ZBX_JSONPATH_TOKEN_OP_LT:
+ zbx_strcpy_alloc(data, data_alloc, data_offset, "<");
+ break;
+ case ZBX_JSONPATH_TOKEN_OP_LE:
+ zbx_strcpy_alloc(data, data_alloc, data_offset, "<=");
+ break;
+ case ZBX_JSONPATH_TOKEN_OP_NOT:
+ zbx_strcpy_alloc(data, data_alloc, data_offset, "!");
+ break;
+ case ZBX_JSONPATH_TOKEN_OP_AND:
+ zbx_strcpy_alloc(data, data_alloc, data_offset, "&&");
+ break;
+ case ZBX_JSONPATH_TOKEN_OP_OR:
+ zbx_strcpy_alloc(data, data_alloc, data_offset, "||");
+ break;
+ case ZBX_JSONPATH_TOKEN_OP_REGEXP:
+ zbx_strcpy_alloc(data, data_alloc, data_offset, "=~");
+ break;
+ default:
+ zbx_strcpy_alloc(data, data_alloc, data_offset, "?");
+ break;
+ }
+}
+
+static char *segment_data_to_str(const zbx_jsonpath_segment_t *segment)
+{
+ const char *functions[] = {"unknown", "min()", "max()", "avg()", "length()", "first()"};
+ char *data = NULL;
+ size_t data_alloc = 0, data_offset = 0;
+ int i;
+ zbx_jsonpath_list_node_t *node;
+ zbx_vector_ptr_t nodes;
+
+ switch (segment->type)
+ {
+ case ZBX_JSONPATH_SEGMENT_MATCH_ALL:
+ data = zbx_strdup(NULL, "*");
+ break;
+ case ZBX_JSONPATH_SEGMENT_MATCH_LIST:
+ zbx_vector_ptr_create(&nodes);
+
+ /* lists are kept in reverse order, invert it for clarity */
+ for (node = segment->data.list.values; NULL != node; node = node->next)
+ zbx_vector_ptr_append(&nodes, node);
+
+ for (i = nodes.values_num - 1; i >= 0; i--)
+ {
+ node = (zbx_jsonpath_list_node_t *)nodes.values[i];
+
+ if (ZBX_JSONPATH_LIST_NAME == segment->data.list.type)
+ {
+ zbx_snprintf_alloc(&data, &data_alloc, &data_offset, "\'%s'",
+ (char *)&node->data);
+ }
+ else
+ {
+ zbx_snprintf_alloc(&data, &data_alloc, &data_offset, "%d",
+ *(int *)&node->data);
+ }
+
+ if (0 != i)
+ zbx_chrcpy_alloc(&data, &data_alloc, &data_offset, ',');
+ }
+
+ zbx_vector_ptr_destroy(&nodes);
+ break;
+ case ZBX_JSONPATH_SEGMENT_MATCH_RANGE:
+ if (0 != (segment->data.range.flags & 0x01))
+ zbx_snprintf_alloc(&data, &data_alloc, &data_offset, "%d", segment->data.range.start);
+ zbx_chrcpy_alloc(&data, &data_alloc, &data_offset, ':');
+ if (0 != (segment->data.range.flags & 0x02))
+ zbx_snprintf_alloc(&data, &data_alloc, &data_offset, "%d", segment->data.range.end);
+ break;
+ case ZBX_JSONPATH_SEGMENT_MATCH_EXPRESSION:
+ for (i = 0; i < segment->data.expression.tokens.values_num; i++)
+ {
+ if (0 != i)
+ zbx_strcpy_alloc(&data, &data_alloc, &data_offset, " , ");
+
+ jsonpath_token_print(&data, &data_alloc, &data_offset,
+ segment->data.expression.tokens.values[i]);
+ }
+ break;
+ case ZBX_JSONPATH_SEGMENT_FUNCTION:
+ zbx_strcpy_alloc(&data, &data_alloc, &data_offset, functions[segment->data.function.type]);
+ break;
+ default:
+ data = zbx_strdup(NULL, "unknown");
+ break;
+ }
+
+ return data;
+}
+
+static void validate_segment(int index, const char *segment_type, const char *segment_data, int detached,
+ const zbx_jsonpath_segment_t *segment)
+{
+ int type;
+ char prefix[MAX_STRING_LEN];
+ char *data = NULL;
+
+ zbx_snprintf(prefix, sizeof(prefix), "jsonpath segment #%d type", index + 1);
+ type = mock_str_to_segment_type(segment_type);
+ zbx_mock_assert_int_eq(prefix, type, segment->type);
+
+ zbx_snprintf(prefix, sizeof(prefix), "jsonpath segment #%d detached", index + 1);
+ zbx_mock_assert_int_eq(prefix, detached, segment->detached);
+
+ data = segment_data_to_str(segment);
+ zbx_snprintf(prefix, sizeof(prefix), "jsonpath segment #%d data", index + 1);
+ zbx_mock_assert_str_eq(prefix, segment_data, data);
+ zbx_free(data);
+}
+
+void zbx_mock_test_entry(void **state)
+{
+ zbx_jsonpath_t jsonpath;
+ int returned_ret, expected_ret, index = 0;
+ zbx_mock_handle_t hsegments, hsegment, hdetached;
+ const char *segment_data, *segment_type, *value;
+
+ ZBX_UNUSED(state);
+
+ /* reset json error to check if compilation will set it */
+ zbx_set_json_strerror("%s", "");
+
+ returned_ret = zbx_jsonpath_compile(zbx_mock_get_parameter_string("in.path"), &jsonpath);
+
+ if (FAIL == returned_ret)
+ printf("zbx_jsonpath_compile() error: %s\n", zbx_json_strerror());
+
+ expected_ret = zbx_mock_str_to_return_code(zbx_mock_get_parameter_string("out.result"));
+ zbx_mock_assert_result_eq("zbx_jsonpath_compile() return value", expected_ret, returned_ret);
+
+ if (SUCCEED == returned_ret)
+ {
+ zbx_mock_assert_uint64_eq("jsonpath definite flag", zbx_mock_get_parameter_uint64("out.definite"),
+ jsonpath.definite);
+ hsegments = zbx_mock_get_parameter_handle("out.segments");
+
+ while (ZBX_MOCK_SUCCESS == zbx_mock_vector_element(hsegments, &hsegment))
+ {
+ int detached = 0;
+
+ zbx_mock_assert_int_ne("Too many path segments parsed", index, jsonpath.segments_num);
+
+ segment_type = zbx_mock_get_object_member_string(hsegment, "type");
+ segment_data = zbx_mock_get_object_member_string(hsegment, "data");
+
+ if (ZBX_MOCK_SUCCESS == zbx_mock_object_member(hsegment, "detached", &hdetached) &&
+ ZBX_MOCK_SUCCESS == zbx_mock_string(hdetached, &value))
+ {
+ detached = atoi(value);
+ }
+
+ validate_segment(index, segment_type, segment_data, detached, &jsonpath.segments[index]);
+ index++;
+ }
+
+ zbx_mock_assert_int_eq("Not enough path segments parsed", index, jsonpath.segments_num);
+
+ zbx_jsonpath_clear(&jsonpath);
+ }
+ else
+ zbx_mock_assert_str_ne("zbx_jsonpath_compile() error", "", zbx_json_strerror());
+}
diff --git a/tests/libs/zbxjson/zbx_jsonpath_compile.yaml b/tests/libs/zbxjson/zbx_jsonpath_compile.yaml
new file mode 100644
index 00000000000..ec6475ee824
--- /dev/null
+++ b/tests/libs/zbxjson/zbx_jsonpath_compile.yaml
@@ -0,0 +1,1024 @@
+# Invalid definite jsonpaths
+
+---
+test case: Compile fail ""
+in:
+ path: ""
+out:
+ result: FAIL
+---
+test case: Compile fail $
+in:
+ path: $
+out:
+ result: FAIL
+---
+test case: Compile fail "$."
+in:
+ path: $.
+out:
+ result: FAIL
+---
+test case: Compile fail "$['a'"
+in:
+ path: $['a'
+out:
+ result: FAIL
+---
+test case: Compile fail "$[a']"
+in:
+ path: $[a']
+out:
+ result: FAIL
+---
+test case: Compile fail "$['']"
+in:
+ path: $['']
+out:
+ result: FAIL
+---
+test case: Compile fail "$.a[]"
+in:
+ path: $.a[]
+out:
+ result: FAIL
+---
+test case: Compile fail "$.a[1"
+in:
+ path: $.a[1
+out:
+ result: FAIL
+---
+test case: Compile fail "$['a'][]"
+in:
+ path: $['a'][]
+out:
+ result: FAIL
+---
+test case: Compile fail "$['a'][1"
+in:
+ path: $['a'][1
+out:
+ result: FAIL
+---
+test case: Compile fail "$.a."
+in:
+ path: $.a.
+out:
+ result: FAIL
+---
+
+# Valid definite jsonpaths
+test case: Compile success "$.a"
+in:
+ path: $.a
+out:
+ result: SUCCEED
+ definite: 1
+ segments:
+ - type: ZBX_JSONPATH_SEGMENT_MATCH_LIST
+ data: "'a'"
+---
+test case: Compile success "$['a']"
+in:
+ path: $['a']
+out:
+ result: SUCCEED
+ definite: 1
+ segments:
+ - type: ZBX_JSONPATH_SEGMENT_MATCH_LIST
+ data: "'a'"
+---
+test case: Compile success "$[ 'a' ]"
+in:
+ path: $[ 'a' ]
+out:
+ result: SUCCEED
+ definite: 1
+ segments:
+ - type: ZBX_JSONPATH_SEGMENT_MATCH_LIST
+ data: "'a'"
+---
+test case: Compile success '$["a"]'
+in:
+ path: $["a"]
+out:
+ result: SUCCEED
+ definite: 1
+ segments:
+ - type: ZBX_JSONPATH_SEGMENT_MATCH_LIST
+ data: "'a'"
+---
+test case: Compile success "$.a.b"
+in:
+ path: $.a.b
+out:
+ result: SUCCEED
+ definite: 1
+ segments:
+ - type: ZBX_JSONPATH_SEGMENT_MATCH_LIST
+ data: "'a'"
+ - type: ZBX_JSONPATH_SEGMENT_MATCH_LIST
+ data: "'b'"
+---
+test case: Compile success "$['a'].b"
+in:
+ path: $['a'].b
+out:
+ result: SUCCEED
+ definite: 1
+ segments:
+ - type: ZBX_JSONPATH_SEGMENT_MATCH_LIST
+ data: "'a'"
+ - type: ZBX_JSONPATH_SEGMENT_MATCH_LIST
+ data: "'b'"
+---
+test case: Compile success "$['a']['b']"
+in:
+ path: $['a']['b']
+out:
+ result: SUCCEED
+ definite: 1
+ segments:
+ - type: ZBX_JSONPATH_SEGMENT_MATCH_LIST
+ data: "'a'"
+ - type: ZBX_JSONPATH_SEGMENT_MATCH_LIST
+ data: "'b'"
+---
+test case: Compile success $.a['b']
+in:
+ path: $.a['b']
+out:
+ result: SUCCEED
+ definite: 1
+ segments:
+ - type: ZBX_JSONPATH_SEGMENT_MATCH_LIST
+ data: "'a'"
+ - type: ZBX_JSONPATH_SEGMENT_MATCH_LIST
+ data: "'b'"
+---
+test case: Compile success $.a[0]
+in:
+ path: $.a[0]
+out:
+ result: SUCCEED
+ definite: 1
+ segments:
+ - type: ZBX_JSONPATH_SEGMENT_MATCH_LIST
+ data: "'a'"
+ - type: ZBX_JSONPATH_SEGMENT_MATCH_LIST
+ data: 0
+---
+test case: Compile success $[-1]
+in:
+ path: $[-1]
+out:
+ result: SUCCEED
+ definite: 1
+ segments:
+ - type: ZBX_JSONPATH_SEGMENT_MATCH_LIST
+ data: -1
+---
+test case: Compile success $.a[0].b[1]
+in:
+ path: $.a[0].b[1]
+out:
+ result: SUCCEED
+ definite: 1
+ segments:
+ - type: ZBX_JSONPATH_SEGMENT_MATCH_LIST
+ data: "'a'"
+ - type: ZBX_JSONPATH_SEGMENT_MATCH_LIST
+ data: 0
+ - type: ZBX_JSONPATH_SEGMENT_MATCH_LIST
+ data: "'b'"
+ - type: ZBX_JSONPATH_SEGMENT_MATCH_LIST
+ data: 1
+---
+test case: Compile success $.a[1000]
+in:
+ path: $.a[1000]
+out:
+ result: SUCCEED
+ definite: 1
+ segments:
+ - type: ZBX_JSONPATH_SEGMENT_MATCH_LIST
+ data: "'a'"
+ - type: ZBX_JSONPATH_SEGMENT_MATCH_LIST
+ data: 1000
+---
+test case: Compile success $.a[ 1 ]
+in:
+ path: $.a[ 1 ]
+out:
+ result: SUCCEED
+ definite: 1
+ segments:
+ - type: ZBX_JSONPATH_SEGMENT_MATCH_LIST
+ data: "'a'"
+ - type: ZBX_JSONPATH_SEGMENT_MATCH_LIST
+ data: 1
+---
+test case: Compile success $['a'][2]
+in:
+ path: $['a'][2]
+out:
+ result: SUCCEED
+ definite: 1
+ segments:
+ - type: ZBX_JSONPATH_SEGMENT_MATCH_LIST
+ data: "'a'"
+ - type: ZBX_JSONPATH_SEGMENT_MATCH_LIST
+ data: 2
+---
+test case: Compile success $['a'][2]['b'][3]
+in:
+ path: $['a'][2]['b'][3]
+out:
+ result: SUCCEED
+ definite: 1
+ segments:
+ - type: ZBX_JSONPATH_SEGMENT_MATCH_LIST
+ data: "'a'"
+ - type: ZBX_JSONPATH_SEGMENT_MATCH_LIST
+ data: 2
+ - type: ZBX_JSONPATH_SEGMENT_MATCH_LIST
+ data: "'b'"
+ - type: ZBX_JSONPATH_SEGMENT_MATCH_LIST
+ data: 3
+---
+test case: Compile success $[1][2]
+in:
+ path: $[1][2]
+out:
+ result: SUCCEED
+ definite: 1
+ segments:
+ - type: ZBX_JSONPATH_SEGMENT_MATCH_LIST
+ data: 1
+ - type: ZBX_JSONPATH_SEGMENT_MATCH_LIST
+ data: 2
+---
+test case: Compile success $.['a'].['b']
+in:
+ path: $.['a'].['b']
+out:
+ result: SUCCEED
+ definite: 1
+ segments:
+ - type: ZBX_JSONPATH_SEGMENT_MATCH_LIST
+ data: "'a'"
+ - type: ZBX_JSONPATH_SEGMENT_MATCH_LIST
+ data: "'b'"
+---
+# Invalid list based json filters
+
+test case: Compile fail $...a
+in:
+ path: $...a
+out:
+ result: FAIL
+---
+test case: 'Compile fail $.**.a'
+in:
+ path: '$.**.a'
+out:
+ result: FAIL
+---
+test case: Compile fail $[,1]
+in:
+ path: $[,1]
+out:
+ result: FAIL
+---
+test case: Compile fail $[1,]
+in:
+ path: $[1,]
+out:
+ result: FAIL
+---
+test case: Compile fail $[1,,2]
+in:
+ path: $[1,,2]
+out:
+ result: FAIL
+---
+test case: Compile fail $[1,*,2]
+in:
+ path: $[1,*,2]
+out:
+ result: FAIL
+---
+test case: Compile fail $[--1]
+in:
+ path: $[--1]
+out:
+ result: FAIL
+---
+test case: Compile fail $[a]
+in:
+ path: $[a]
+out:
+ result: FAIL
+---
+test case: Compile fail $[$a$]
+in:
+ path: $[$a$]
+out:
+ result: FAIL
+---
+test case: Compile fail $[,'a']
+in:
+ path: $[,'a']
+out:
+ result: FAIL
+---
+test case: Compile fail $['a',]
+in:
+ path: $['a',]
+out:
+ result: FAIL
+---
+test case: Compile fail $['a',,'b']
+in:
+ path: $['a',,2]
+out:
+ result: FAIL
+---
+test case: Compile fail $['a',*,'b']
+in:
+ path: $['a',*,2]
+out:
+ result: FAIL
+---
+test case: Compile fail $[--'a']
+in:
+ path: $[--'a']
+out:
+ result: FAIL
+---
+test case: Compile fail $[1,'a']
+in:
+ path: $[1,'a']
+out:
+ result: FAIL
+---
+test case: Compile fail $['a\a']
+in:
+ path: $['a\a']
+out:
+ result: FAIL
+---
+test case: Compile fail $['a\']
+in:
+ path: $['a\']
+out:
+ result: FAIL
+---
+test case: Compile fail $['a\"']
+in:
+ path: $['a\"']
+out:
+ result: FAIL
+---
+test case: Compile fail $['a\]
+in:
+ path: $['a\]
+out:
+ result: FAIL
+---
+test case: Compile fail $['a\
+in:
+ path: $['a\
+out:
+ result: FAIL
+---
+test case: Compile fail $["a\'"]
+in:
+ path: $["a\'"]
+out:
+ result: FAIL
+---
+# Valid list based json filters
+
+test case: Compile success $[ 1 ]
+in:
+ path: $[ 1 ]
+out:
+ result: SUCCEED
+ definite: 1
+ segments:
+ - type: ZBX_JSONPATH_SEGMENT_MATCH_LIST
+ data: 1
+---
+test case: Compile success $[1,2]
+in:
+ path: $[1,2]
+out:
+ result: SUCCEED
+ definite: 0
+ segments:
+ - type: ZBX_JSONPATH_SEGMENT_MATCH_LIST
+ data: 1,2
+---
+test case: Compile success $[ 1 , 2 ]
+in:
+ path: $[ 1 , 2 ]
+out:
+ result: SUCCEED
+ definite: 0
+ segments:
+ - type: ZBX_JSONPATH_SEGMENT_MATCH_LIST
+ data: 1,2
+---
+test case: Compile success $[ -1 ]
+in:
+ path: $[ -1 ]
+out:
+ result: SUCCEED
+ definite: 1
+ segments:
+ - type: ZBX_JSONPATH_SEGMENT_MATCH_LIST
+ data: -1
+---
+test case: Compile success $[ -1, 2, 3 ]
+in:
+ path: $[ -1, 2, 3 ]
+out:
+ result: SUCCEED
+ definite: 0
+ segments:
+ - type: ZBX_JSONPATH_SEGMENT_MATCH_LIST
+ data: -1,2,3
+---
+test case: Compile success $[ ' a ' ]
+in:
+ path: $[ ' a ' ]
+out:
+ result: SUCCEED
+ definite: 1
+ segments:
+ - type: ZBX_JSONPATH_SEGMENT_MATCH_LIST
+ data: "' a '"
+---
+test case: Compile success $[ ' a ', "b" ]
+in:
+ path: $[ ' a ', "b" ]
+out:
+ result: SUCCEED
+ definite: 0
+ segments:
+ - type: ZBX_JSONPATH_SEGMENT_MATCH_LIST
+ data: "' a ','b'"
+---
+test case: Compile success $['a \'b\' \\/']
+in:
+ path: $['a \'b\' \\/']
+out:
+ result: SUCCEED
+ definite: 1
+ segments:
+ - type: ZBX_JSONPATH_SEGMENT_MATCH_LIST
+ data: "'a 'b' \\/'"
+---
+test case: Compile success $["a \"b\""]
+in:
+ path: $["a \"b\""]
+out:
+ result: SUCCEED
+ definite: 1
+ segments:
+ - type: ZBX_JSONPATH_SEGMENT_MATCH_LIST
+ data: "'a \"b\"'"
+---
+test case: Compile success $.*.a
+in:
+ path: $.*.a
+out:
+ result: SUCCEED
+ definite: 0
+ segments:
+ - type: ZBX_JSONPATH_SEGMENT_MATCH_ALL
+ data: "*"
+ - type: ZBX_JSONPATH_SEGMENT_MATCH_LIST
+ data: "'a'"
+---
+test case: Compile success $.*
+in:
+ path: $.*
+out:
+ result: SUCCEED
+ definite: 0
+ segments:
+ - type: ZBX_JSONPATH_SEGMENT_MATCH_ALL
+ data: "*"
+---
+test case: Compile success $[*]
+in:
+ path: $[*]
+out:
+ result: SUCCEED
+ definite: 0
+ segments:
+ - type: ZBX_JSONPATH_SEGMENT_MATCH_ALL
+ data: "*"
+---
+test case: Compile success $..a.b..c
+in:
+ path: $..a.b..c
+out:
+ result: SUCCEED
+ definite: 0
+ segments:
+ - type: ZBX_JSONPATH_SEGMENT_MATCH_LIST
+ data: "'a'"
+ detached: 1
+ - type: ZBX_JSONPATH_SEGMENT_MATCH_LIST
+ data: "'b'"
+ - type: ZBX_JSONPATH_SEGMENT_MATCH_LIST
+ data: "'c'"
+ detached: 1
+---
+# Slice based json filters
+
+test case: Compile fail $[1:2:3]
+in:
+ path: $[1:2:3]
+out:
+ result: FAIL
+---
+test case: Compile success $[:]
+in:
+ path: "$[:]"
+out:
+ result: SUCCEED
+ definite: 0
+ segments:
+ - type: ZBX_JSONPATH_SEGMENT_MATCH_SLICE
+ data: ":"
+---
+test case: Compile success $[1:]
+in:
+ path: "$[1:]"
+out:
+ result: SUCCEED
+ definite: 0
+ segments:
+ - type: ZBX_JSONPATH_SEGMENT_MATCH_SLICE
+ data: "1:"
+---
+test case: Compile success $[:1]
+in:
+ path: "$[:1]"
+out:
+ result: SUCCEED
+ definite: 0
+ segments:
+ - type: ZBX_JSONPATH_SEGMENT_MATCH_SLICE
+ data: ":1"
+---
+test case: Compile success $[1:2]
+in:
+ path: "$[1:2]"
+out:
+ result: SUCCEED
+ definite: 0
+ segments:
+ - type: ZBX_JSONPATH_SEGMENT_MATCH_SLICE
+ data: "1:2"
+---
+test case: "Compile success $[-1:-1]"
+in:
+ path: "$[-1:-1]"
+out:
+ result: SUCCEED
+ definite: 0
+ segments:
+ - type: ZBX_JSONPATH_SEGMENT_MATCH_SLICE
+ data: "-1:-1"
+---
+test case: "Compile success $[ 1 : 2 ]"
+in:
+ path: "$[ 1 : 2 ]"
+out:
+ result: SUCCEED
+ definite: 0
+ segments:
+ - type: ZBX_JSONPATH_SEGMENT_MATCH_SLICE
+ data: "1:2"
+---
+test case: "Compile success $[ : 1 ]"
+in:
+ path: "$[ : 1 ]"
+out:
+ result: SUCCEED
+ definite: 0
+ segments:
+ - type: ZBX_JSONPATH_SEGMENT_MATCH_SLICE
+ data: ":1"
+---
+test case: "Compile success $[ 1 : ]"
+in:
+ path: "$[ 1 : ]"
+out:
+ result: SUCCEED
+ definite: 0
+ segments:
+ - type: ZBX_JSONPATH_SEGMENT_MATCH_SLICE
+ data: "1:"
+---
+test case: Compile fail $.min(
+in:
+ path: $.min(
+out:
+ result: FAIL
+---
+test case: Compile fail $.min(1)
+in:
+ path: $.min(1)
+out:
+ result: FAIL
+---
+test case: Compile fail $.div()
+in:
+ path: $.div()
+out:
+ result: FAIL
+---
+test case: Compile fail $.avg().data
+in:
+ path: $.avg().data
+out:
+ result: FAIL
+---
+test case: Compile fail $.len()
+in:
+ path: $.len()
+out:
+ result: FAIL
+---
+test case: Compile success $.min()
+in:
+ path: $.min()
+out:
+ result: SUCCEED
+ definite: 1
+ segments:
+ - type: ZBX_JSONPATH_SEGMENT_FUNCTION
+ data: "min()"
+---
+test case: Compile success $.max()
+in:
+ path: $.max()
+out:
+ result: SUCCEED
+ definite: 1
+ segments:
+ - type: ZBX_JSONPATH_SEGMENT_FUNCTION
+ data: "max()"
+---
+test case: Compile success $.avg()
+in:
+ path: $.avg()
+out:
+ result: SUCCEED
+ definite: 1
+ segments:
+ - type: ZBX_JSONPATH_SEGMENT_FUNCTION
+ data: "avg()"
+---
+test case: Compile success $.length()
+in:
+ path: $.length()
+out:
+ result: SUCCEED
+ definite: 1
+ segments:
+ - type: ZBX_JSONPATH_SEGMENT_FUNCTION
+ data: "length()"
+---
+test case: Compile success $.first().max()
+in:
+ path: $.first().max()
+out:
+ result: SUCCEED
+ definite: 1
+ segments:
+ - type: ZBX_JSONPATH_SEGMENT_FUNCTION
+ data: "first()"
+ - type: ZBX_JSONPATH_SEGMENT_FUNCTION
+ data: "max()"
+---
+test case: Compile fail $[?]
+in:
+ path: $[?]
+out:
+ result: FAIL
+---
+test case: Compile fail $[?(]
+in:
+ path: $[?(]
+out:
+ result: FAIL
+---
+test case: Compile fail $[?()]
+in:
+ path: $[?()]
+out:
+ result: FAIL
+---
+test case: Compile fail $[?(+)]
+in:
+ path: $[?(+)]
+out:
+ result: FAIL
+---
+test case: Compile fail $[?(==)]
+in:
+ path: $[?(==)]
+out:
+ result: FAIL
+---
+test case: Compile fail $[?(()]
+in:
+ path: $[?(()]
+out:
+ result: FAIL
+---
+test case: Compile fail $[?(+1)]
+in:
+ path: $[?(+1)]
+out:
+ result: FAIL
+---
+test case: Compile fail $[?(!)]
+in:
+ path: $[?(!)]
+out:
+ result: FAIL
+---
+test case: Compile fail $[?(a)]
+in:
+ path: $[?(a)]
+out:
+ result: FAIL
+---
+test case: Compile fail $[?(())]
+in:
+ path: $[?(())]
+out:
+ result: FAIL
+---
+test case: Compile fail $[?(1++1)]
+in:
+ path: $[?(1++1)]
+out:
+ result: FAIL
+---
+test case: Compile fail $[?(1 - - 1)]
+in:
+ path: $[?(1 - - 1)]
+out:
+ result: FAIL
+---
+test case: Compile fail $[?(1 + + 1)]
+in:
+ path: $[?(1 + + 1)]
+out:
+ result: FAIL
+---
+test case: Compile fail $[?((1+1)+)]
+in:
+ path: $[?((1+1)+)]
+out:
+ result: FAIL
+---
+test case: Compile fail $[?((1 + 1) + ())]
+in:
+ path: $[?((1 + 1) + ())]
+out:
+ result: FAIL
+---
+test case: Compile fail $[?(a + 1)]
+in:
+ path: $[?(a + 1)]
+out:
+ result: FAIL
+---
+test case: Compile fail $[?(1 + 'a)]
+in:
+ path: $[?(1 + 'a)]
+out:
+ result: FAIL
+---
+test case: Compile fail $[?($..b + 1)]
+in:
+ path: $[?($..b + 1)]
+out:
+ result: FAIL
+---
+test case: Compile fail $[?($['a])]
+in:
+ path: $[?($['a])]
+out:
+ result: FAIL
+---
+test case: Compile fail $[?($[1,2])]
+in:
+ path: $[?($[1,2])]
+out:
+ result: FAIL
+---
+test case: Compile fail $[?($.a.)]
+in:
+ path: $[?($.a.)]
+out:
+ result: FAIL
+---
+test case: Compile success $[?(1)]
+in:
+ path: $[?(1)]
+out:
+ result: SUCCEED
+ definite: 0
+ segments:
+ - type: ZBX_JSONPATH_SEGMENT_MATCH_EXPRESSION
+ data: "1"
+---
+test case: Compile success $[?(-1)]
+in:
+ path: $[?(-1)]
+out:
+ result: SUCCEED
+ definite: 0
+ segments:
+ - type: ZBX_JSONPATH_SEGMENT_MATCH_EXPRESSION
+ data: "-1"
+---
+test case: Compile success $[?($.a)]
+in:
+ path: $[?($.a)]
+out:
+ result: SUCCEED
+ definite: 0
+ segments:
+ - type: ZBX_JSONPATH_SEGMENT_MATCH_EXPRESSION
+ data: "$.a"
+---
+test case: Compile success $[?(@.b)]
+in:
+ path: $[?(@.b)]
+out:
+ result: SUCCEED
+ definite: 0
+ segments:
+ - type: ZBX_JSONPATH_SEGMENT_MATCH_EXPRESSION
+ data: "@.b"
+---
+test case: Compile success $[?(!1)]
+in:
+ path: $[?(!1)]
+out:
+ result: SUCCEED
+ definite: 0
+ segments:
+ - type: ZBX_JSONPATH_SEGMENT_MATCH_EXPRESSION
+ data: "1 , !"
+---
+test case: Compile success $[?(1 + 2)]
+in:
+ path: $[?(1 + 2)]
+out:
+ result: SUCCEED
+ definite: 0
+ segments:
+ - type: ZBX_JSONPATH_SEGMENT_MATCH_EXPRESSION
+ data: "1 , 2 , +"
+---
+test case: Compile success $[?(1 + 2 * 3)]
+in:
+ path: $[?(1 + 2 * 3)]
+out:
+ result: SUCCEED
+ definite: 0
+ segments:
+ - type: ZBX_JSONPATH_SEGMENT_MATCH_EXPRESSION
+ data: "1 , 2 , 3 , * , +"
+---
+test case: Compile success $[?(1 - 2 / 3)]
+in:
+ path: $[?(1 - 2 / 3)]
+out:
+ result: SUCCEED
+ definite: 0
+ segments:
+ - type: ZBX_JSONPATH_SEGMENT_MATCH_EXPRESSION
+ data: "1 , 2 , 3 , / , -"
+---
+test case: Compile success $[?((1 + 2) * 3)]
+in:
+ path: $[?((1 + 2) * 3)]
+out:
+ result: SUCCEED
+ definite: 0
+ segments:
+ - type: ZBX_JSONPATH_SEGMENT_MATCH_EXPRESSION
+ data: "1 , 2 , + , 3 , *"
+---
+test case: Compile success $[?($.a + 2 == 3)]
+in:
+ path: $[?($.a + 2 == 3)]
+out:
+ result: SUCCEED
+ definite: 0
+ segments:
+ - type: ZBX_JSONPATH_SEGMENT_MATCH_EXPRESSION
+ data: "$.a , 2 , + , 3 , =="
+---
+test case: Compile success $[?((1 + 2) * (3 - 4))]
+in:
+ path: $[?((1 + 2) * (3 - 4))]
+out:
+ result: SUCCEED
+ definite: 0
+ segments:
+ - type: ZBX_JSONPATH_SEGMENT_MATCH_EXPRESSION
+ data: "1 , 2 , + , 3 , 4 , - , *"
+---
+test case: Compile success $[?(1 == 2 || !3*5)]
+in:
+ path: $[?(1 == 2 || !3*5)]
+out:
+ result: SUCCEED
+ definite: 0
+ segments:
+ - type: ZBX_JSONPATH_SEGMENT_MATCH_EXPRESSION
+ data: "1 , 2 , == , 3 , ! , 5 , * , ||"
+---
+test case: Compile success $[?(1 == 2 || !(3*5))]
+in:
+ path: $[?(1 == 2 || !(3*5))]
+out:
+ result: SUCCEED
+ definite: 0
+ segments:
+ - type: ZBX_JSONPATH_SEGMENT_MATCH_EXPRESSION
+ data: "1 , 2 , == , 3 , 5 , * , ! , ||"
+---
+test case: Compile success $[?(1 == 2 * @.a)]
+in:
+ path: $[?(1 == 2 * @.a)]
+out:
+ result: SUCCEED
+ definite: 0
+ segments:
+ - type: ZBX_JSONPATH_SEGMENT_MATCH_EXPRESSION
+ data: "1 , 2 , @.a , * , =="
+---
+test case: Compile success $[?((1)+(2))]
+in:
+ path: $[?((1)+(2))]
+out:
+ result: SUCCEED
+ definite: 0
+ segments:
+ - type: ZBX_JSONPATH_SEGMENT_MATCH_EXPRESSION
+ data: "1 , 2 , +"
+---
+test case: Compile success $[?(1 + 2 - 3 + 4)]
+in:
+ path: $[?(1 + 2 - 3 + 4)]
+out:
+ result: SUCCEED
+ definite: 0
+ segments:
+ - type: ZBX_JSONPATH_SEGMENT_MATCH_EXPRESSION
+ data: "1 , 2 , + , 3 , - , 4 , +"
+---
+test case: Compile success $[?(1 == 2 == 3)]
+in:
+ path: $[?(1 == 2 == 3)]
+out:
+ result: SUCCEED
+ definite: 0
+ segments:
+ - type: ZBX_JSONPATH_SEGMENT_MATCH_EXPRESSION
+ data: "1 , 2 , == , 3 , =="
+---
+test case: Compile fail $[?(1 == 2 == 3]
+in:
+ path: $[?(1 == 2 == 3]
+out:
+ result: FAIL
+---
+test case: Compile success $..[?(@.id)]
+in:
+ path: $..[?(@.id)]
+out:
+ result: SUCCEED
+ definite: 0
+ segments:
+ - type: ZBX_JSONPATH_SEGMENT_MATCH_EXPRESSION
+ data: "@.id"
+ detached: 1
+...
diff --git a/tests/libs/zbxjson/zbx_jsonpath_query.c b/tests/libs/zbxjson/zbx_jsonpath_query.c
new file mode 100644
index 00000000000..10a7db13155
--- /dev/null
+++ b/tests/libs/zbxjson/zbx_jsonpath_query.c
@@ -0,0 +1,100 @@
+/*
+** Zabbix
+** Copyright (C) 2001-2019 Zabbix SIA
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+**/
+
+#include "zbxmocktest.h"
+#include "zbxmockdata.h"
+#include "zbxmockassert.h"
+#include "zbxmockutil.h"
+#include "zbxmockjson.h"
+
+#include "common.h"
+#include "zbxjson.h"
+#include "../../../src/libs/zbxjson/json.h"
+
+static void check_definite_path_result(zbx_mock_handle_t handle, const char *returned_output)
+{
+ const char *expected_output;
+ struct zbx_json_parse jp;
+
+ if (ZBX_MOCK_SUCCESS != zbx_mock_string(handle, &expected_output))
+ fail_msg("Invalid test case out.value parameter");
+
+ if (FAIL == zbx_json_open(expected_output, &jp))
+ zbx_mock_assert_str_eq("Definite query result", expected_output, returned_output);
+ else
+ zbx_mock_assert_json_eq("Indefinite query result", expected_output, returned_output);
+}
+
+static void check_indefinite_path_result(zbx_mock_handle_t handle, const char *returned_output)
+{
+ const char *expected_output;
+
+ if (ZBX_MOCK_SUCCESS != zbx_mock_string(handle, &expected_output))
+ fail_msg("Invalid test case out.values parameter");
+
+ zbx_mock_assert_json_eq("Indefinite query result", expected_output, returned_output);
+}
+
+void zbx_mock_test_entry(void **state)
+{
+ const char *data, *path;
+ struct zbx_json_parse jp;
+ char *output = NULL;
+ int expected_ret, returned_ret;
+ zbx_mock_handle_t handle;
+
+ ZBX_UNUSED(state);
+
+ /* reset json error to check if compilation will set it */
+ zbx_set_json_strerror("%s", "");
+
+ data = zbx_mock_get_parameter_string("in.data");
+ if (FAIL == zbx_json_open(data, &jp))
+ fail_msg("Invalid json data: %s", zbx_json_strerror());
+
+ path = zbx_mock_get_parameter_string("in.path");
+ returned_ret = zbx_jsonpath_query(&jp, path, &output);
+ expected_ret = zbx_mock_str_to_return_code(zbx_mock_get_parameter_string("out.return"));
+
+ if (FAIL == returned_ret)
+ printf("\tzbx_jsonpath_query() failed with: %s\n", zbx_json_strerror());
+
+ zbx_mock_assert_result_eq("zbx_jsonpath_query() return value", expected_ret, returned_ret);
+
+ if (SUCCEED == returned_ret)
+ {
+ printf("\tzbx_jsonpath_query() query result: %s\n", ZBX_NULL2EMPTY_STR(output));
+ if (ZBX_MOCK_SUCCESS == zbx_mock_parameter("out.value", &handle))
+ {
+ zbx_mock_assert_ptr_ne("Query result", NULL, output);
+ check_definite_path_result(handle, output);
+ }
+ else if (ZBX_MOCK_SUCCESS == zbx_mock_parameter("out.values", &handle))
+ {
+ zbx_mock_assert_ptr_ne("Query result", NULL, output);
+ check_indefinite_path_result(handle, output);
+ }
+ else
+ zbx_mock_assert_ptr_eq("Query result", NULL, output);
+ }
+ else
+ zbx_mock_assert_str_ne("tzbx_jsonpath_query() error", "", zbx_json_strerror());
+
+ zbx_free(output);
+}
diff --git a/tests/libs/zbxjson/zbx_jsonpath_query.inc.yaml b/tests/libs/zbxjson/zbx_jsonpath_query.inc.yaml
new file mode 100644
index 00000000000..456f49ebe28
--- /dev/null
+++ b/tests/libs/zbxjson/zbx_jsonpath_query.inc.yaml
@@ -0,0 +1,77 @@
+---
+|
+ {
+ "books": [
+ {
+ "category": "reference",
+ "author": "Nigel Rees",
+ "title": "Sayings of the Century",
+ "price": 8.95,
+ "id": 1
+ },
+ {
+ "category": "fiction",
+ "author": "Evelyn Waugh",
+ "title": "Sword of Honour",
+ "price": 12.99,
+ "id": 2
+ },
+ {
+ "category": "fiction",
+ "author": "Herman Melville",
+ "title": "Moby Dick",
+ "isbn": "0-553-21311-3",
+ "price": 8.99,
+ "id": 3
+ },
+ {
+ "category": "fiction",
+ "author": "J. R. R. Tolkien",
+ "title": "The Lord of the Rings",
+ "isbn": "0-395-19395-8",
+ "price": 22.99,
+ "id": 4
+ }
+ ],
+ "services": {
+ "delivery": {
+ "servicegroup": 1000,
+ "description": "Next day delivery in local town",
+ "active": true,
+ "price": 5
+ },
+ "bookbinding": {
+ "servicegroup": 1001,
+ "description": "Printing and assembling book in A5 format",
+ "active": true,
+ "price": 154.99
+ },
+ "restoration": {
+ "servicegroup": 1002,
+ "description": "Various restoration methods",
+ "active": false,
+ "methods": [
+ {
+ "description": "Checmical cleaning",
+ "price": 46
+ },
+ {
+ "description": "Pressing pages damaged by moisture",
+ "price": 24.5
+ },
+ {
+ "description": "Rebinding torn book",
+ "price": 99.49
+ }
+ ]
+ }
+ },
+ "filters": {
+ "price": 10,
+ "category": "fiction",
+ "no filters": "no \"filters\""
+ },
+ "closed message": "Store is closed",
+ "tags": ["a", "b", "c", "d", "e" ]
+ }
+...
diff --git a/tests/libs/zbxjson/zbx_jsonpath_query.yaml b/tests/libs/zbxjson/zbx_jsonpath_query.yaml
new file mode 100644
index 00000000000..25b1e8888fc
--- /dev/null
+++ b/tests/libs/zbxjson/zbx_jsonpath_query.yaml
@@ -0,0 +1,711 @@
+---
+test case: Query $[0] from ["a", "b"]
+in:
+ data: '["a", "b"]'
+ path: $[0]
+out:
+ return: SUCCEED
+ value: a
+---
+test case: Query $[4] from ["a", "b"]
+in:
+ data: '["a", "b"]'
+ path: $[4]
+out:
+ return: SUCCEED
+---
+test case: Query $[1] from ["a", "b"]
+in:
+ data: '["a", "b"]'
+ path: $[1]
+out:
+ return: SUCCEED
+ value: b
+---
+test case: Query $[2] from ["a", "b"]
+in:
+ data: '["a", "b"]'
+ path: $[2]
+out:
+ return: SUCCEED
+---
+test case: Query $[2].* from ["a", "b"]
+in:
+ data: '["a", "b"]'
+ path: $[2].*
+out:
+ return: SUCCEED
+---
+test case: Query $.filters.price
+include: &include zbx_jsonpath_query.inc.yaml
+in:
+ data: *include
+ path: $.filters.price
+out:
+ return: SUCCEED
+ value: 10
+---
+test case: Query $.filters.category
+include: &include zbx_jsonpath_query.inc.yaml
+in:
+ data: *include
+ path: $.filters.category
+out:
+ return: SUCCEED
+ value: fiction
+---
+test case: Query $.filters.id
+include: &include zbx_jsonpath_query.inc.yaml
+in:
+ data: *include
+ path: $.filters.id
+out:
+ return: SUCCEED
+---
+test case: Query $.books[1].title
+include: &include zbx_jsonpath_query.inc.yaml
+in:
+ data: *include
+ path: $.books[1].title
+out:
+ return: SUCCEED
+ value: Sword of Honour
+---
+test case: Query $['closed message']
+include: &include zbx_jsonpath_query.inc.yaml
+in:
+ data: *include
+ path: $['closed message']
+out:
+ return: SUCCEED
+ value: Store is closed
+---
+test case: Query $.books[-1].author
+include: &include zbx_jsonpath_query.inc.yaml
+in:
+ data: *include
+ path: $.books[-1].author
+out:
+ return: SUCCEED
+ value: J. R. R. Tolkien
+---
+test case: Query $.filters
+include: &include zbx_jsonpath_query.inc.yaml
+in:
+ data: *include
+ path: $.filters
+out:
+ return: SUCCEED
+ value: |
+ {
+ "price": 10,
+ "category": "fiction",
+ "no filters": "no \"filters\""
+ }
+---
+test case: Query $.books.length()
+include: &include zbx_jsonpath_query.inc.yaml
+in:
+ data: *include
+ path: $.books.length()
+out:
+ return: SUCCEED
+ value: 4
+---
+test case: Query $.tags[:]
+include: &include zbx_jsonpath_query.inc.yaml
+in:
+ data: *include
+ path: $.tags[:]
+out:
+ return: SUCCEED
+ value: '["a", "b", "c", "d", "e" ]'
+---
+test case: Query $.tags[2:]
+include: &include zbx_jsonpath_query.inc.yaml
+in:
+ data: *include
+ path: $.tags[2:]
+out:
+ return: SUCCEED
+ value: '["c", "d", "e" ]'
+---
+test case: Query $.tags[:2]
+include: &include zbx_jsonpath_query.inc.yaml
+in:
+ data: *include
+ path: $.tags[:2]
+out:
+ return: SUCCEED
+ value: '["a", "b"]'
+---
+test case: Query $.tags[1:4]
+include: &include zbx_jsonpath_query.inc.yaml
+in:
+ data: *include
+ path: $.tags[1:4]
+out:
+ return: SUCCEED
+ value: '["b", "c", "d"]'
+---
+test case: Query $.tags[-2:]
+include: &include zbx_jsonpath_query.inc.yaml
+in:
+ data: *include
+ path: $.tags[-2:]
+out:
+ return: SUCCEED
+ value: '["d", "e"]'
+---
+test case: Query $.tags[:-3]
+include: &include zbx_jsonpath_query.inc.yaml
+in:
+ data: *include
+ path: $.tags[:-3]
+out:
+ return: SUCCEED
+ value: '["a", "b"]'
+---
+test case: Query $.tags[:-3].length()
+include: &include zbx_jsonpath_query.inc.yaml
+in:
+ data: *include
+ path: $.tags[:-3].length()
+out:
+ return: SUCCEED
+ value: 2
+---
+test case: Query $.books[0, 2].title
+include: &include zbx_jsonpath_query.inc.yaml
+in:
+ data: *include
+ path: $.books[0, 2].title
+out:
+ return: SUCCEED
+ value: '["Sayings of the Century", "Moby Dick"]'
+---
+test case: Query $.books[1]['author', "title"]
+include: &include zbx_jsonpath_query.inc.yaml
+in:
+ data: *include
+ path: $.books[1]['author', "title"]
+out:
+ return: SUCCEED
+ value: '["Evelyn Waugh", "Sword of Honour"]'
+---
+test case: Query $..id
+include: &include zbx_jsonpath_query.inc.yaml
+in:
+ data: *include
+ path: $..id
+out:
+ return: SUCCEED
+ value: '[1, 2, 3, 4]'
+---
+test case: Query $.services..price
+include: &include zbx_jsonpath_query.inc.yaml
+in:
+ data: *include
+ path: $.services..price
+out:
+ return: SUCCEED
+ value: '[5, 154.99, 46, 24.5, 99.49]'
+---
+test case: Query $.books[?(@.id == 1 + 1)].title
+include: &include zbx_jsonpath_query.inc.yaml
+in:
+ data: *include
+ path: $.books[?(@.id == 1 + 1)].title
+out:
+ return: SUCCEED
+ value: '["Sword of Honour"]'
+---
+test case: Query $.books[?(@.id == 4 / 2)].title
+include: &include zbx_jsonpath_query.inc.yaml
+in:
+ data: *include
+ path: $.books[?(@.id == 4 / 2)].title
+out:
+ return: SUCCEED
+ value: '["Sword of Honour"]'
+---
+test case: Query $.books[?(@.id == 7 - 5)].title
+include: &include zbx_jsonpath_query.inc.yaml
+in:
+ data: *include
+ path: $.books[?(@.id == 7 - 5)].title
+out:
+ return: SUCCEED
+ value: '["Sword of Honour"]'
+---
+test case: Query $.books[?(@.id == 0.4 * 5)].title
+include: &include zbx_jsonpath_query.inc.yaml
+in:
+ data: *include
+ path: $.books[?(@.id == 0.4 * 5)].title
+out:
+ return: SUCCEED
+ value: '["Sword of Honour"]'
+---
+test case: Query $.books[?(@.id == 4 - 0.4 * 5)].title
+include: &include zbx_jsonpath_query.inc.yaml
+in:
+ data: *include
+ path: $.books[?(@.id == 4 - 0.4 * 5)].title
+out:
+ return: SUCCEED
+ value: '["Sword of Honour"]'
+---
+test case: Query $.books[?(@.id == -0.4 * 5 + 4)].title
+include: &include zbx_jsonpath_query.inc.yaml
+in:
+ data: *include
+ path: $.books[?(@.id == -0.4 * 5 + 4)].title
+out:
+ return: SUCCEED
+ value: '["Sword of Honour"]'
+---
+test case: Query $.books[?(@.id == 0.4 * (-5) + 4)].title
+include: &include zbx_jsonpath_query.inc.yaml
+in:
+ data: *include
+ path: $.books[?(@.id == 0.4 * (-5) + 4)].title
+out:
+ return: SUCCEED
+ value: '["Sword of Honour"]'
+---
+test case: Query $.books[?(@.id == 2 || @.id == 4)].title
+include: &include zbx_jsonpath_query.inc.yaml
+in:
+ data: *include
+ path: $.books[?(@.id == 2 || @.id == 4)].title
+out:
+ return: SUCCEED
+ value: '["Sword of Honour", "The Lord of the Rings"]'
+---
+test case: Query $.books[?(@.id == 2 && 2 * ((1 + 3) / 2 + 3) == 10)].title
+include: &include zbx_jsonpath_query.inc.yaml
+in:
+ data: *include
+ path: $.books[?(@.id == 2 && 2 * ((1 + 3) / 2 + 3) == 10)].title
+out:
+ return: SUCCEED
+ value: '["Sword of Honour"]'
+---
+test case: Query $.books[?(@.id == 2 == 1)].title
+include: &include zbx_jsonpath_query.inc.yaml
+in:
+ data: *include
+ path: $.books[?(@.id == 2 == 1)].title
+out:
+ return: SUCCEED
+ value: '["Sword of Honour"]'
+---
+test case: Query $.books[?(!(@.id == 2))].title
+include: &include zbx_jsonpath_query.inc.yaml
+in:
+ data: *include
+ path: $.books[?(!(@.id == 2))].title
+out:
+ return: SUCCEED
+ value: '["Sayings of the Century", "Moby Dick", "The Lord of the Rings"]'
+---
+test case: Query $.books[?(@.id != 2)].title
+include: &include zbx_jsonpath_query.inc.yaml
+in:
+ data: *include
+ path: $.books[?(@.id != 2)].title
+out:
+ return: SUCCEED
+ value: '["Sayings of the Century", "Moby Dick", "The Lord of the Rings"]'
+---
+test case: Query $.books[?(@.title =~ " of ")].title
+include: &include zbx_jsonpath_query.inc.yaml
+in:
+ data: *include
+ path: $.books[?(@.title =~ " of ")].title
+out:
+ return: SUCCEED
+ value: '["Sayings of the Century", "Sword of Honour", "The Lord of the Rings"]'
+---
+test case: Query $.books[?(@.price > 12.99)].title
+include: &include zbx_jsonpath_query.inc.yaml
+in:
+ data: *include
+ path: $.books[?(@.price > 12.99)].title
+out:
+ return: SUCCEED
+ value: '["The Lord of the Rings"]'
+---
+test case: Query $.books[?(@.price >= 12.99)].title
+include: &include zbx_jsonpath_query.inc.yaml
+in:
+ data: *include
+ path: $.books[?(@.price >= 12.99)].title
+out:
+ return: SUCCEED
+ value: '["Sword of Honour", "The Lord of the Rings"]'
+---
+test case: Query $.books[?(@.price < 12.99)].title
+include: &include zbx_jsonpath_query.inc.yaml
+in:
+ data: *include
+ path: $.books[?(@.price < 12.99)].title
+out:
+ return: SUCCEED
+ value: '["Sayings of the Century", "Moby Dick"]'
+---
+test case: Query $.books[?(@.price <= 12.99)].title
+include: &include zbx_jsonpath_query.inc.yaml
+in:
+ data: *include
+ path: $.books[?(@.price <= 12.99)].title
+out:
+ return: SUCCEED
+ value: '["Sayings of the Century", "Sword of Honour", "Moby Dick"]'
+---
+test case: Query $.books[?(@.author > "Herman Melville")].title
+include: &include zbx_jsonpath_query.inc.yaml
+in:
+ data: *include
+ path: $.books[?(@.author > "Herman Melville")].title
+out:
+ return: SUCCEED
+ value: '["Sayings of the Century", "The Lord of the Rings"]'
+---
+test case: Query $.books[?(@.author >= "Herman Melville")].title
+include: &include zbx_jsonpath_query.inc.yaml
+in:
+ data: *include
+ path: $.books[?(@.author >= "Herman Melville")].title
+out:
+ return: SUCCEED
+ value: '["Sayings of the Century", "Moby Dick", "The Lord of the Rings"]'
+---
+test case: Query $.books[?(@.author < "Herman Melville")].title
+include: &include zbx_jsonpath_query.inc.yaml
+in:
+ data: *include
+ path: $.books[?(@.author < "Herman Melville")].title
+out:
+ return: SUCCEED
+ value: '["Sword of Honour"]'
+---
+test case: Query $.books[?(@.author <= "Herman Melville")].title
+include: &include zbx_jsonpath_query.inc.yaml
+in:
+ data: *include
+ path: $.books[?(@.author <= "Herman Melville")].title
+out:
+ return: SUCCEED
+ value: '["Sword of Honour", "Moby Dick"]'
+---
+test case: Query $.books[?(@.price > $.filters.price)].title
+include: &include zbx_jsonpath_query.inc.yaml
+in:
+ data: *include
+ path: $.books[?(@.price > $.filters.price)].title
+out:
+ return: SUCCEED
+ value: '["Sword of Honour", "The Lord of the Rings"]'
+---
+test case: Query $.books[?(@.category == $.filters.category)].title
+include: &include zbx_jsonpath_query.inc.yaml
+in:
+ data: *include
+ path: $.books[?(@.category == $.filters.category)].title
+out:
+ return: SUCCEED
+ value: '["Sword of Honour","Moby Dick","The Lord of the Rings"]'
+---
+test case: Query $.books[?(@.category != $.filters.category)].title
+include: &include zbx_jsonpath_query.inc.yaml
+in:
+ data: *include
+ path: $.books[?(@.category != $.filters.category)].title
+out:
+ return: SUCCEED
+ value: '["Sayings of the Century"]'
+---
+test case: Query $..[?(@.id)]
+include: &include zbx_jsonpath_query.inc.yaml
+in:
+ data: *include
+ path: $..[?(@.id)]
+out:
+ return: SUCCEED
+ value: |
+ [
+ {
+ "category": "reference",
+ "author": "Nigel Rees",
+ "title": "Sayings of the Century",
+ "price": 8.95,
+ "id": 1
+ },
+ {
+ "category": "fiction",
+ "author": "Evelyn Waugh",
+ "title": "Sword of Honour",
+ "price": 12.99,
+ "id": 2
+ },
+ {
+ "category": "fiction",
+ "author": "Herman Melville",
+ "title": "Moby Dick",
+ "isbn": "0-553-21311-3",
+ "price": 8.99,
+ "id": 3
+ },
+ {
+ "category": "fiction",
+ "author": "J. R. R. Tolkien",
+ "title": "The Lord of the Rings",
+ "isbn": "0-395-19395-8",
+ "price": 22.99,
+ "id": 4
+ }
+ ]
+---
+test case: Query $.services..[?(@.price > 50)].description
+include: &include zbx_jsonpath_query.inc.yaml
+in:
+ data: *include
+ path: $.services..[?(@.price > 50)].description
+out:
+ return: SUCCEED
+ value: '["Printing and assembling book in A5 format", "Rebinding torn book"]'
+---
+test case: Query $..id.length()
+include: &include zbx_jsonpath_query.inc.yaml
+in:
+ data: *include
+ path: $..id.length()
+out:
+ return: SUCCEED
+ value: 4
+---
+test case: Query $.books[?(@.price >= 12.99)].length()
+include: &include zbx_jsonpath_query.inc.yaml
+in:
+ data: *include
+ path: $.books[?(@.price >= 12.99)].length()
+out:
+ return: SUCCEED
+ value: 2
+---
+test case: Query $.books[?(@.id == 2)].title.first()
+include: &include zbx_jsonpath_query.inc.yaml
+in:
+ data: *include
+ path: $.books[?(@.id == 2)].title.first()
+out:
+ return: SUCCEED
+ value: Sword of Honour
+---
+test case: Query $..tags.first().length()
+include: &include zbx_jsonpath_query.inc.yaml
+in:
+ data: *include
+ path: $..tags.first().length()
+out:
+ return: SUCCEED
+ value: 5
+---
+test case: Query $.length() from ["a", "b"]
+in:
+ data: '["a", "b"]'
+ path: $.length()
+out:
+ return: SUCCEED
+ value: 2
+---
+test case: Query $.first() from ["a", "b"]
+in:
+ data: '["a", "b"]'
+ path: $.first()
+out:
+ return: SUCCEED
+ value: a
+---
+test case: Query $.first().first() from [["a", "b"]]
+in:
+ data: '[["a", "b"]]'
+ path: $.first().first()
+out:
+ return: SUCCEED
+ value: a
+---
+test case: Query $.first().first().first() from [[["a", "b"]]]
+in:
+ data: '[[["a", "b"]]]'
+ path: $.first().first().first()
+out:
+ return: SUCCEED
+ value: a
+---
+test case: Query $.books[*].price.min()
+include: &include zbx_jsonpath_query.inc.yaml
+in:
+ data: *include
+ path: $.books[*].price.min()
+out:
+ return: SUCCEED
+ value: 8.95
+---
+test case: Query $..price.max()
+include: &include zbx_jsonpath_query.inc.yaml
+in:
+ data: *include
+ path: $..price.max()
+out:
+ return: SUCCEED
+ value: 154.99
+---
+test case: Query $.books[?(@.category == "fiction")].price.avg()
+include: &include zbx_jsonpath_query.inc.yaml
+in:
+ data: *include
+ path: $.books[?(@.category == "fiction")].price.avg()
+out:
+ return: SUCCEED
+ value: 14.99
+---
+test case: Query $.books[?(@.category == $.filters.xyz)].title
+include: &include zbx_jsonpath_query.inc.yaml
+in:
+ data: *include
+ path: $.books[?(@.category == $.filters.xyz)].title
+out:
+ return: SUCCEED
+---
+test case: Query $.filters['no filters']
+include: &include zbx_jsonpath_query.inc.yaml
+in:
+ data: *include
+ path: $.filters['no filters']
+out:
+ return: SUCCEED
+ value: no "filters"
+---
+test case: Query $.services[?(@.active=="true")].servicegroup
+include: &include zbx_jsonpath_query.inc.yaml
+in:
+ data: *include
+ path: $.services[?(@.active=="true")].servicegroup
+out:
+ return: SUCCEED
+ value: '[1000,1001]'
+---
+test case: Query $.services[?(@.active=="false")].servicegroup
+include: &include zbx_jsonpath_query.inc.yaml
+in:
+ data: *include
+ path: $.services[?(@.active=="false")].servicegroup
+out:
+ return: SUCCEED
+ value: '[1002]'
+---
+test case: Query $.books[?(@.title =~ "[a-z")].title
+include: &include zbx_jsonpath_query.inc.yaml
+in:
+ data: *include
+ path: $.books[?(@.title =~ "[a-z")].title
+out:
+ return: FAIL
+---
+test case: $..books[?(!@.isbn)]
+include: &include zbx_jsonpath_query.inc.yaml
+in:
+ data: *include
+ path: $..books[?(!@.isbn)]
+out:
+ return: SUCCEED
+ value: |
+ [
+ {
+ "category": "reference",
+ "author": "Nigel Rees",
+ "title": "Sayings of the Century",
+ "price": 8.95,
+ "id": 1
+ },
+ {
+ "category": "fiction",
+ "author": "Evelyn Waugh",
+ "title": "Sword of Honour",
+ "price": 12.99,
+ "id": 2
+ }
+ ]
+---
+test case: $..books[?(@.isbn)]
+include: &include zbx_jsonpath_query.inc.yaml
+in:
+ data: *include
+ path: $..books[?(@.isbn)]
+out:
+ return: SUCCEED
+ value: |
+ [
+ {
+ "category": "fiction",
+ "author": "Herman Melville",
+ "title": "Moby Dick",
+ "isbn": "0-553-21311-3",
+ "price": 8.99,
+ "id": 3
+ },
+ {
+ "category": "fiction",
+ "author": "J. R. R. Tolkien",
+ "title": "The Lord of the Rings",
+ "isbn": "0-395-19395-8",
+ "price": 22.99,
+ "id": 4
+ }
+ ]
+---
+test case: Query $.books[*].price.sum()
+include: &include zbx_jsonpath_query.inc.yaml
+in:
+ data: *include
+ path: $.books[*].price.sum()
+out:
+ return: SUCCEED
+ value: 53.92
+---
+test case: Query $[?(@.a)].id from [{"a":{"b":"c"}, "id":1}, {"x":{"y":"z"}, "id":2}]
+in:
+ data: '[{"a":{"b":"c"}, "id":1}, {"x":{"y":"z"}, "id":2}]'
+ path: $[?(@.a)].id
+out:
+ return: SUCCEED
+ values: '[1]'
+---
+test case: Query $[?(!@.a)].id from [{"a":{"b":"c"}, "id":1}, {"x":{"y":"z"}, "id":2}]
+in:
+ data: '[{"a":{"b":"c"}, "id":1}, {"x":{"y":"z"}, "id":2}]'
+ path: $[?(!@.a)].id
+out:
+ return: SUCCEED
+ values: '[2]'
+---
+test case: Query $[?(@.a)].id from [{"a":["b","c"], "id":1}, {"x":["y","z"], "id":2}]
+in:
+ data: '[{"a":["b","c"], "id":1}, {"x":["y","z"], "id":2}]'
+ path: $[?(@.a)].id
+out:
+ return: SUCCEED
+ values: '[1]'
+---
+test case: Query $[?(!@.a)].id from [{"a":["b","c"], "id":1}, {"x":["y","z"], "id":2}]
+in:
+ data: '[{"a":["b","c"], "id":1}, {"x":["y","z"], "id":2}]'
+ path: $[?(!@.a)].id
+out:
+ return: SUCCEED
+ values: '[2]'
+...
+
diff --git a/tests/libs/zbxsysinfo/Makefile.am b/tests/libs/zbxsysinfo/Makefile.am
index c1d29c7cd0e..09a946d78c3 100644
--- a/tests/libs/zbxsysinfo/Makefile.am
+++ b/tests/libs/zbxsysinfo/Makefile.am
@@ -58,6 +58,7 @@ parse_item_key_LDADD = \
$(top_srcdir)/src/libs/zbxsys/libzbxsys.a \
$(top_srcdir)/src/libs/zbxconf/libzbxconf.a \
$(top_srcdir)/src/libs/zbxmedia/libzbxmedia.a \
+ $(top_srcdir)/src/libs/zbxjson/libzbxjson.a \
$(top_srcdir)/src/libs/zbxcommon/libzbxcommon.a \
$(top_srcdir)/src/libs/zbxcrypto/libzbxcrypto.a \
$(top_srcdir)/src/libs/zbxcomms/libzbxcomms.a \
@@ -65,7 +66,6 @@ parse_item_key_LDADD = \
$(top_srcdir)/src/libs/zbxcommon/libzbxcommon.a \
$(top_srcdir)/src/libs/zbxcrypto/libzbxcrypto.a \
$(top_srcdir)/src/libs/zbxcommshigh/libzbxcommshigh.a \
- $(top_srcdir)/src/libs/zbxjson/libzbxjson.a \
$(top_srcdir)/src/libs/zbxhttp/libzbxhttp.a \
$(top_srcdir)/src/libs/zbxipcservice/libzbxipcservice.a \
$(top_srcdir)/src/libs/zbxexec/libzbxexec.a \
@@ -106,9 +106,9 @@ process_LDADD = \
$(top_srcdir)/src/libs/zbxcomms/libzbxcomms.a \
$(top_srcdir)/src/libs/zbxcompress/libzbxcompress.a \
$(top_srcdir)/src/libs/zbxconf/libzbxconf.a \
+ $(top_srcdir)/src/libs/zbxjson/libzbxjson.a \
$(top_srcdir)/src/libs/zbxcommon/libzbxcommon.a \
$(top_srcdir)/src/libs/zbxcrypto/libzbxcrypto.a \
- $(top_srcdir)/src/libs/zbxjson/libzbxjson.a \
$(top_srcdir)/src/libs/zbxexec/libzbxexec.a \
$(top_srcdir)/src/libs/zbxmodules/libzbxmodules.a \
$(top_srcdir)/src/zabbix_agent/libzbxagent.a \
diff --git a/tests/libs/zbxsysinfo/common/Makefile.am b/tests/libs/zbxsysinfo/common/Makefile.am
index 6315bf33f9e..2c0e9e7075c 100644
--- a/tests/libs/zbxsysinfo/common/Makefile.am
+++ b/tests/libs/zbxsysinfo/common/Makefile.am
@@ -26,6 +26,7 @@ COMMON_LIB_FILES = \
$(top_srcdir)/src/libs/zbxcomms/libzbxcomms.a \
$(top_srcdir)/src/libs/zbxcompress/libzbxcompress.a \
$(top_srcdir)/src/libs/zbxconf/libzbxconf.a \
+ $(top_srcdir)/src/libs/zbxjson/libzbxjson.a \
$(top_srcdir)/src/libs/zbxcommon/libzbxcommon.a \
$(top_srcdir)/src/libs/zbxcrypto/libzbxcrypto.a \
$(top_srcdir)/src/libs/zbxjson/libzbxjson.a \
diff --git a/tests/libs/zbxsysinfo/linux/Makefile.am b/tests/libs/zbxsysinfo/linux/Makefile.am
index 88f71778c4c..93ad477029f 100644
--- a/tests/libs/zbxsysinfo/linux/Makefile.am
+++ b/tests/libs/zbxsysinfo/linux/Makefile.am
@@ -34,6 +34,7 @@ COMMON_LIB_FILES = \
$(top_srcdir)/src/libs/zbxcomms/libzbxcomms.a \
$(top_srcdir)/src/libs/zbxcompress/libzbxcompress.a \
$(top_srcdir)/src/libs/zbxconf/libzbxconf.a \
+ $(top_srcdir)/src/libs/zbxjson/libzbxjson.a \
$(top_srcdir)/src/libs/zbxcommon/libzbxcommon.a \
$(top_srcdir)/src/libs/zbxcrypto/libzbxcrypto.a \
$(top_srcdir)/src/libs/zbxjson/libzbxjson.a \
diff --git a/tests/zabbix_server/preprocessor/Makefile.am b/tests/zabbix_server/preprocessor/Makefile.am
index 032f2cbd215..b1fc815ae02 100644
--- a/tests/zabbix_server/preprocessor/Makefile.am
+++ b/tests/zabbix_server/preprocessor/Makefile.am
@@ -1,5 +1,5 @@
if SERVER
-SERVER_tests = zbx_item_preproc
+SERVER_tests = zbx_item_preproc
if HAVE_LIBXML2
SERVER_tests += item_preproc_xpath
@@ -53,4 +53,5 @@ item_preproc_xpath_LDADD += @SERVER_LIBS@
item_preproc_xpath_LDFLAGS = @SERVER_LDFLAGS@
item_preproc_xpath_CFLAGS = -I@top_srcdir@/tests @LIBXML2_CFLAGS@
+
endif
diff --git a/tests/zabbix_server/preprocessor/zbx_item_preproc.yaml b/tests/zabbix_server/preprocessor/zbx_item_preproc.yaml
index 8efec2282de..af39eec592b 100644
--- a/tests/zabbix_server/preprocessor/zbx_item_preproc.yaml
+++ b/tests/zabbix_server/preprocessor/zbx_item_preproc.yaml
@@ -983,6 +983,87 @@ out:
return: SUCCEED
value: 2
---
+test case: jsonpath7
+in:
+ value:
+ value_type: ITEM_VALUE_TYPE_STR
+ time: 2017-10-29 03:15:00 +03:00
+ data: |-
+ {"a":{"b c":["one", "two", "three"]}}
+ step:
+ type: ZBX_PREPROC_JSONPATH
+ params: $.a['b c']
+out:
+ return: SUCCEED
+ value: '["one", "two", "three"]'
+---
+test case: jsonpath8
+in:
+ value:
+ value_type: ITEM_VALUE_TYPE_STR
+ time: 2017-10-29 03:15:00 +03:00
+ data: |-
+ {"a":{"b c":["one", "two \"2\"", 3]}}
+ step:
+ type: ZBX_PREPROC_JSONPATH
+ params: $.a['b c'][1]
+out:
+ return: SUCCEED
+ value: two "2"
+---
+test case: jsonpath9
+in:
+ value:
+ value_type: ITEM_VALUE_TYPE_STR
+ time: 2017-10-29 03:15:00 +03:00
+ data: |-
+ {"a":{"b c":["one", "two \"2\"", 3]}}
+ step:
+ type: ZBX_PREPROC_JSONPATH
+ params: $.a['b c'][2]
+out:
+ return: SUCCEED
+ value: 3
+---
+test case: jsonpath10
+in:
+ value:
+ value_type: ITEM_VALUE_TYPE_STR
+ time: 2017-10-29 03:15:00 +03:00
+ data: |-
+ {"a":{"b":[1, 2, 3]}}
+ step:
+ type: ZBX_PREPROC_JSONPATH
+ params: $.a['b'][3]
+out:
+ return: FAIL
+---
+test case: jsonpath11
+in:
+ value:
+ value_type: ITEM_VALUE_TYPE_STR
+ time: 2017-10-29 03:15:00 +03:00
+ data: |-
+ {"a":{"b":[1, 2, 3]}}
+ step:
+ type: ZBX_PREPROC_JSONPATH
+ params: $.a['b'][
+out:
+ return: FAIL
+---
+test case: jsonpath12
+in:
+ value:
+ value_type: ITEM_VALUE_TYPE_STR
+ time: 2017-10-29 03:15:00 +03:00
+ data: |-
+ {"a":{"b":[1, 2, 3]}}
+ step:
+ type: ZBX_PREPROC_JSONPATH
+ params: $.a['b][3]
+out:
+ return: FAIL
+---
test case: validate_range(1, 5, 10)
in:
value:
diff --git a/tests/zbxmockdata.c b/tests/zbxmockdata.c
index a7f627905d1..cf369ec593e 100644
--- a/tests/zbxmockdata.c
+++ b/tests/zbxmockdata.c
@@ -162,6 +162,8 @@ static int zbx_yaml_include(yaml_document_t *dst_doc, yaml_node_pair_t *dst, con
if (-1 != (index = zbx_yaml_add_node(dst_doc, &doc, src_root)))
dst->value = index;
}
+ else
+ printf("Cannot parse include file '%s'\n", filename);
__real_fclose(fp);
diff --git a/tests/zbxmockjson.c b/tests/zbxmockjson.c
index fda1e0f0ccf..9f7233f9f69 100644
--- a/tests/zbxmockjson.c
+++ b/tests/zbxmockjson.c
@@ -24,6 +24,7 @@
#include "zbxmocktest.h"
#include "zbxmockdata.h"
#include "zbxmockassert.h"
+#include "zbxmockjson.h"
#define _FAIL(file, line, prefix, message, ...) \
\
@@ -112,7 +113,7 @@ static void json_flatten_object(struct zbx_json_parse *jp, const char *prefix, z
{
const char *pnext = NULL;
char *path = NULL, key[MAX_STRING_LEN];
- size_t path_alloc = 0, path_offset = 0;
+ size_t path_alloc = 0, path_offset;
while (NULL != (pnext = zbx_json_pair_next(jp, pnext, key, sizeof(key))))
{
@@ -129,10 +130,9 @@ static void json_flatten_object(struct zbx_json_parse *jp, const char *prefix, z
static void json_flatten_array(struct zbx_json_parse *jp, const char *parent, zbx_vector_ptr_pair_t *props)
{
- const char *pnext;
- char *path, *value = NULL;
- int index = 0;
-
+ const char *pnext;
+ char *path, *value = NULL;
+ int index = 0;
for (pnext = NULL; NULL != (pnext = zbx_json_next(jp, pnext));)
{
@@ -243,14 +243,14 @@ void __zbx_mock_assert_json_eq(const char *file, int line, const char *prefix_ms
_FAIL(file, line, prefix_msg, "Did not expect key \"%s\"", pair_returned->first);
}
- for (i = 0; i < props_expected.values_num; i++)
+ for (i = 0; i < props_expected.values_num; i++)
{
zbx_free(props_expected.values[i].first);
zbx_free(props_expected.values[i].second);
}
zbx_vector_ptr_pair_destroy(&props_expected);
- for (i = 0; i < props_returned.values_num; i++)
+ for (i = 0; i < props_returned.values_num; i++)
{
zbx_free(props_returned.values[i].first);
zbx_free(props_returned.values[i].second);
diff --git a/tests/zbxmockjson.h b/tests/zbxmockjson.h
index 9e4d4045fb8..ae3e248ac52 100644
--- a/tests/zbxmockjson.h
+++ b/tests/zbxmockjson.h
@@ -26,4 +26,4 @@ void __zbx_mock_assert_json_eq(const char *file, int line, const char *prefix_ms
#define zbx_mock_assert_json_eq(prefix_msg, expected_value, returned_value) \
__zbx_mock_assert_json_eq(__FILE__, __LINE__, prefix_msg, expected_value, returned_value)
-#endif /* BUILD_TESTS_ZBXMOCKDB_H_ */
+#endif