diff options
-rw-r--r-- | configure.ac | 8 | ||||
-rw-r--r-- | include/common.h | 4 | ||||
-rw-r--r-- | include/zbxjson.h | 1 | ||||
-rw-r--r-- | include/zbxserver.h | 1 | ||||
-rw-r--r-- | src/libs/zbxcommon/Makefile.am | 4 | ||||
-rw-r--r-- | src/libs/zbxcommon/xml.c | 569 | ||||
-rw-r--r-- | src/libs/zbxembed/Makefile.am | 12 | ||||
-rw-r--r-- | src/libs/zbxembed/embed.c | 4 | ||||
-rw-r--r-- | src/libs/zbxembed/xml.c | 198 | ||||
-rw-r--r-- | src/libs/zbxembed/xml.h | 25 | ||||
-rw-r--r-- | src/libs/zbxjson/json.c | 5 | ||||
-rw-r--r-- | src/libs/zbxserver/expression.c | 1 | ||||
-rw-r--r-- | src/zabbix_get/Makefile.am | 4 | ||||
-rw-r--r-- | src/zabbix_server/preprocessor/item_preproc.c | 148 |
14 files changed, 860 insertions, 124 deletions
diff --git a/configure.ac b/configure.ac index a8eae4b6c1a..bf80dfb27e2 100644 --- a/configure.ac +++ b/configure.ac @@ -1532,11 +1532,9 @@ if test "x$server" = "xyes" || test "x$proxy" = "xyes"; then have_libxml2="yes" fi fi - SERVER_LDFLAGS="$SERVER_LDFLAGS $LIBXML2_LDFLAGS" - SERVER_LIBS="$SERVER_LIBS $LIBXML2_LIBS" - - PROXY_LDFLAGS="$PROXY_LDFLAGS $LIBXML2_LDFLAGS" - PROXY_LIBS="$PROXY_LIBS $LIBXML2_LIBS" + + LDFLAGS="$LDFLAGS $LIBXML2_LDFLAGS" + LIBS="$LIBS $LIBXML2_LIBS" AC_SUBST(LIBXML2_CFLAGS) diff --git a/include/common.h b/include/common.h index 7d1be581183..a961f6827ae 100644 --- a/include/common.h +++ b/include/common.h @@ -1580,6 +1580,7 @@ char *zbx_expression_extract_constant(const char *src, const zbx_strloc_t *loc); #define ZBX_PREPROC_CSV_TO_JSON 24 #define ZBX_PREPROC_STR_REPLACE 25 #define ZBX_PREPROC_VALIDATE_NOT_SUPPORTED 26 +#define ZBX_PREPROC_XML_TO_JSON 27 /* custom on fail actions */ #define ZBX_PREPROC_FAIL_DEFAULT 0 @@ -1711,5 +1712,8 @@ typedef enum zbx_function_type_t; zbx_function_type_t zbx_get_function_type(const char *func); +int zbx_query_xpath(zbx_variant_t *value, const char *params, char **errmsg); +int zbx_xml_to_json(char *data, char **jstr, char **errmsg); +int zbx_json_to_xml(char *data, char **xstr, char **errmsg); #endif diff --git a/include/zbxjson.h b/include/zbxjson.h index 1edc6c42d1b..87db8a0a662 100644 --- a/include/zbxjson.h +++ b/include/zbxjson.h @@ -281,6 +281,7 @@ 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_open_path(const struct zbx_json_parse *jp, const char *path, struct zbx_json_parse *out); +zbx_json_type_t zbx_json_valuetype(const char *p); void zbx_json_log(const struct zbx_json_parse *jp, int loglevel); diff --git a/include/zbxserver.h b/include/zbxserver.h index 2c94a345bde..a246495d50a 100644 --- a/include/zbxserver.h +++ b/include/zbxserver.h @@ -108,5 +108,4 @@ void zbx_substitute_item_name_macros(DC_ITEM *dc_item, const char *name, char ** int substitute_macros_in_json_pairs(char **data, const struct zbx_json_parse *jp_row, const zbx_vector_ptr_t *lld_macro_paths, char *error, int maxerrlen); int xml_xpath_check(const char *xpath, char *error, size_t errlen); - #endif diff --git a/src/libs/zbxcommon/Makefile.am b/src/libs/zbxcommon/Makefile.am index 05aff9ef3e5..3e7e1c2282f 100644 --- a/src/libs/zbxcommon/Makefile.am +++ b/src/libs/zbxcommon/Makefile.am @@ -16,4 +16,6 @@ libzbxcommon_a_SOURCES = \ zbxgetopt.c \ time.c -libzbxcommon_a_CFLAGS = $(ICONV_CFLAGS) +libzbxcommon_a_CFLAGS = $(ICONV_CFLAGS) $(LIBXML2_CFLAGS) + + diff --git a/src/libs/zbxcommon/xml.c b/src/libs/zbxcommon/xml.c index 3ba41477a77..300e698cf63 100644 --- a/src/libs/zbxcommon/xml.c +++ b/src/libs/zbxcommon/xml.c @@ -18,6 +18,30 @@ **/ #include "common.h" +#include "zbxalgo.h" +#include "zbxjson.h" +/* LIBXML2 is used */ +#ifdef HAVE_LIBXML2 +# include <libxml/parser.h> +# include <libxml/tree.h> +# include <libxml/xpath.h> +#endif + +#define XML_TEXT_NAME "text" +#define XML_CDATA_NAME "cdata" +#define XML_TEXT_TAG "#text" +#define XML_JSON_TRUE 1 +#define XML_JSON_FALSE 0 + +typedef struct +{ + char * name; + char * value; + zbx_vector_str_t attributes; + zbx_vector_ptr_t chnodes; + int array; +} +zbx_xml_node_t; static char data_static[ZBX_MAX_B64_LEN]; @@ -230,3 +254,548 @@ void xml_escape_xpath(char **data) zbx_free(*data); *data = buffer; } + +/****************************************************************************** + * * + * Function: zbx_query_xpath * + * * + * Purpose: execute xpath query * + * * + * Parameters: value - [IN/OUT] the value to process * + * params - [IN] the operation parameters * + * errmsg - [OUT] error message * + * * + * Return value: SUCCEED - the value was processed successfully * + * FAIL - otherwise * + * * + ******************************************************************************/ +int zbx_query_xpath(zbx_variant_t *value, const char *params, char **errmsg) +{ +#ifndef HAVE_LIBXML2 + ZBX_UNUSED(value); + ZBX_UNUSED(params); + *errmsg = zbx_dsprintf(*errmsg, "Zabbix was compiled without libxml2 support"); + return FAIL; +#else + xmlDoc *doc = NULL; + xmlXPathContext *xpathCtx; + xmlXPathObject *xpathObj; + xmlNodeSetPtr nodeset; + xmlErrorPtr pErr; + xmlBufferPtr xmlBufferLocal; + int ret = FAIL, i; + char buffer[32], *ptr; + + if (NULL == (doc = xmlReadMemory(value->data.str, strlen(value->data.str), "noname.xml", NULL, 0))) + { + if (NULL != (pErr = xmlGetLastError())) + *errmsg = zbx_dsprintf(*errmsg, "cannot parse xml value: %s", pErr->message); + else + *errmsg = zbx_strdup(*errmsg, "cannot parse xml value"); + return FAIL; + } + + xpathCtx = xmlXPathNewContext(doc); + + if (NULL == (xpathObj = xmlXPathEvalExpression((xmlChar *)params, xpathCtx))) + { + pErr = xmlGetLastError(); + *errmsg = zbx_dsprintf(*errmsg, "cannot parse xpath: %s", pErr->message); + goto out; + } + + switch (xpathObj->type) + { + case XPATH_NODESET: + xmlBufferLocal = xmlBufferCreate(); + + if (0 == xmlXPathNodeSetIsEmpty(xpathObj->nodesetval)) + { + nodeset = xpathObj->nodesetval; + for (i = 0; i < nodeset->nodeNr; i++) + xmlNodeDump(xmlBufferLocal, doc, nodeset->nodeTab[i], 0, 0); + } + zbx_variant_clear(value); + zbx_variant_set_str(value, zbx_strdup(NULL, (const char *)xmlBufferLocal->content)); + + xmlBufferFree(xmlBufferLocal); + ret = SUCCEED; + break; + case XPATH_STRING: + zbx_variant_clear(value); + zbx_variant_set_str(value, zbx_strdup(NULL, (const char *)xpathObj->stringval)); + ret = SUCCEED; + break; + case XPATH_BOOLEAN: + zbx_variant_clear(value); + zbx_variant_set_str(value, zbx_dsprintf(NULL, "%d", xpathObj->boolval)); + ret = SUCCEED; + break; + case XPATH_NUMBER: + zbx_variant_clear(value); + zbx_snprintf(buffer, sizeof(buffer), ZBX_FS_DBL, xpathObj->floatval); + + /* check for nan/inf values - isnan(), isinf() is not supported by c89/90 */ + /* so simply check the if the result starts with digit (accounting for -inf) */ + if (*(ptr = buffer) == '-') + ptr++; + if (0 != isdigit(*ptr)) + { + del_zeros(buffer); + zbx_variant_set_str(value, zbx_strdup(NULL, buffer)); + ret = SUCCEED; + } + else + *errmsg = zbx_strdup(*errmsg, "Invalid numeric value"); + break; + default: + *errmsg = zbx_strdup(*errmsg, "Unknown result"); + break; + } +out: + if (NULL != xpathObj) + xmlXPathFreeObject(xpathObj); + + xmlXPathFreeContext(xpathCtx); + xmlFreeDoc(doc); + + return ret; +#endif +} + +/****************************************************************************** + * * + * Function: compare_xml_nodes_by_name * + * * + * Purpose: compare two xml nodes by name * + * * + * Comments: This function is used to sort xml nodes by name . * + * * + ******************************************************************************/ +static int compare_xml_nodes_by_name(const void *d1, const void *d2) +{ + zbx_xml_node_t *p1 = *(zbx_xml_node_t **)d1; + zbx_xml_node_t *p2 = *(zbx_xml_node_t **)d2; + int res; + + res = strcmp(p1->name, p2->name); + if (0 == res) + { + p1->array = XML_JSON_TRUE; + p2->array = XML_JSON_TRUE; + } + + return res; +} + + +static void zbx_xml_node_free(zbx_xml_node_t *node) +{ + zbx_vector_ptr_clear_ext(&node->chnodes, (zbx_clean_func_t)zbx_xml_node_free); + zbx_vector_ptr_destroy(&node->chnodes); + zbx_vector_str_clear_ext(&node->attributes, zbx_str_free); + zbx_vector_str_destroy(&node->attributes); + zbx_free(node->name); + zbx_free(node->value); + zbx_free(node); +} + +static void xml_to_vector(xmlNode *xml_node, zbx_vector_ptr_t *nodes) +{ + xmlChar *value; + xmlAttr *attr; + + for (;NULL != xml_node; xml_node = xml_node->next) + { + zbx_xml_node_t *node; + + node = (zbx_xml_node_t *)zbx_malloc(NULL, sizeof(zbx_xml_node_t)); + node->name = NULL; + if (0 != xml_node->name) + node->name = zbx_strdup(NULL,(char *)xml_node->name); + node->value = NULL; + node->array = XML_JSON_FALSE; + + zbx_vector_ptr_create(&node->chnodes); + zbx_vector_str_create(&node->attributes); + + switch (xml_node->type) + { + case XML_TEXT_NODE: + if (NULL == (value = xmlNodeGetContent(xml_node))) + break; + + node->value = zbx_strdup(NULL,(char *)value); + xmlFree(value); + break; + case XML_CDATA_SECTION_NODE: + if (NULL == (value = xmlNodeGetContent(xml_node))) + break; + node->value = zbx_strdup(NULL,(char *)value); + node->name = zbx_strdup(node->name, XML_CDATA_NAME); + xmlFree(value); + break; + case XML_ELEMENT_NODE: + for (attr = xml_node->properties; NULL != attr; attr = attr->next) + { + char *attr_name = NULL; + size_t attr_name_alloc = 0, attr_name_offset = 0; + + if (NULL == attr->name) + continue; + + zbx_snprintf_alloc(&attr_name, &attr_name_alloc, &attr_name_offset, "@%s", + attr->name); + value = xmlGetProp(xml_node, attr->name); + zbx_vector_str_append(&node->attributes, attr_name); + zbx_vector_str_append(&node->attributes, zbx_strdup(NULL, (char *)value)); + xmlFree(value); + + } + break; + default: + break; + + } + xml_to_vector(xml_node->children, &node->chnodes); + zbx_vector_ptr_append(nodes, node); + zbx_vector_ptr_sort(nodes, compare_xml_nodes_by_name); + } +} + +static int is_data(zbx_xml_node_t *node) +{ + if (0 == strcmp(XML_TEXT_NAME, node->name) || 0 == strcmp(XML_CDATA_NAME, node->name)) + return SUCCEED; + + return FAIL; +} + +static void vector_to_json(zbx_vector_ptr_t *nodes, struct zbx_json *json, char **text) +{ + int i, j; + int is_object; + int arr_cnt = 0; + char *arr_name = NULL; + char *tag, *out_text; + zbx_xml_node_t *node; + + *text = NULL; + for (i = 0; i < nodes->values_num; i++) + { + node = (zbx_xml_node_t *)nodes->values[i]; + + if ((XML_JSON_FALSE == node->array && 0 != arr_cnt) || (XML_JSON_TRUE == node->array && + NULL != arr_name && 0 != strcmp(arr_name, node->name))) + { + zbx_json_close(json); + arr_name = NULL; + arr_cnt = 0; + } + + if (XML_JSON_TRUE == node->array && 0 == arr_cnt) + { + zbx_json_addarray(json, node->name); + arr_name = node->name; + } + if (XML_JSON_TRUE == node->array) + arr_cnt++; + + is_object = XML_JSON_FALSE; + if (0 != node->chnodes.values_num) + { + zbx_xml_node_t *chnode; + + chnode = (zbx_xml_node_t*)node->chnodes.values[0]; + if (FAIL == is_data(chnode)) + is_object = XML_JSON_TRUE; + } + if (0 != node->attributes.values_num) + is_object = XML_JSON_TRUE; + + if (XML_JSON_TRUE == is_object) + { + tag = node->name; + if (0 != arr_cnt) + tag = NULL; + zbx_json_addobject(json, tag); + } + + for(j = 0; j < node->attributes.values_num; j+=2) + { + zbx_json_addstring(json, node->attributes.values[j], node->attributes.values[j + 1], + ZBX_JSON_TYPE_STRING); + } + + vector_to_json(&node->chnodes, json, &out_text); + + *text = node->value; + + if (NULL != out_text || (XML_JSON_FALSE == is_object && FAIL == is_data(node))) + { + tag = node->name; + if (0 != node->attributes.values_num) + tag = XML_TEXT_TAG; + else if (0 != arr_cnt) + tag = NULL; + zbx_json_addstring(json, tag, out_text, ZBX_JSON_TYPE_STRING); + } + + if (XML_JSON_TRUE == is_object) + { + zbx_json_close(json); + } + } + if (0 != arr_cnt) + zbx_json_close(json); +} + +/****************************************************************************** + * * + * Function: zbx_xml_to_json * + * * + * Purpose: convert XML format value to JSON format * + * * + * Parameters: data - [IN] the XML data to process * + * jstr - [OUT] the JSON output * + * errmsg - [OUT] error message * + * * + * Return value: SUCCEED - the value was processed successfully * + * FAIL - otherwise * + * * + ******************************************************************************/ +int zbx_xml_to_json(char *data, char **jstr, char **errmsg) +{ +#ifndef HAVE_LIBXML2 + ZBX_UNUSED(data); + ZBX_UNUSED(jstr); + *errmsg = zbx_dsprintf(*errmsg, "Zabbix was compiled without libxml2 support"); + return FAIL; +#else + struct zbx_json json; + xmlDoc *doc = NULL; + xmlErrorPtr pErr; + xmlNode *node; + int ret = FAIL; + zbx_vector_ptr_t nodes; + char* out; + + if (NULL == (doc = xmlReadMemory(data, strlen(data), "noname.xml", NULL, 0))) + { + if (NULL != (pErr = xmlGetLastError())) + *errmsg = zbx_dsprintf(*errmsg, "cannot parse xml value: %s", pErr->message); + else + *errmsg = zbx_strdup(*errmsg, "cannot parse xml value"); + goto exit; + } + + zbx_json_init(&json, ZBX_JSON_STAT_BUF_LEN); + + if (NULL == (node = xmlDocGetRootElement(doc))) + { + *errmsg = zbx_dsprintf(*errmsg, "Cannot parse XML root"); + goto clean; + } + + zbx_vector_ptr_create(&nodes); + + xml_to_vector(node, &nodes); + vector_to_json(&nodes, &json, &out); + *jstr = zbx_strdup(*jstr, json.buffer); + ret = SUCCEED; + + zbx_vector_ptr_clear_ext(&nodes, (zbx_clean_func_t)zbx_xml_node_free); + zbx_vector_ptr_destroy(&nodes); +clean: + xmlFreeDoc(doc); + zbx_json_free(&json); +exit: + return ret; +#endif +} + +static void json_to_node(struct zbx_json_parse *jp, xmlDoc *doc, xmlNode *parent_node, char *arr_name, int deep, + char **attr, char **attr_val, char **text) +{ + xmlNode *node; + const char *p = NULL, *p1 = NULL; + struct zbx_json_parse jp_data; + char name[MAX_STRING_LEN], value[MAX_STRING_LEN]; + char *attr_loc = NULL, *attr_val_loc = NULL, *text_loc = NULL, *array_loc; + int idx; + int set_attr, set_text; + char *pname, *pvalue; + zbx_json_type_t type; + + idx = 0; + pvalue = NULL; + do + { + set_attr = 0; + set_text = 0; + array_loc = NULL; + pname = NULL; + + if (NULL != (p = zbx_json_pair_next(jp, p, name, sizeof(name)))) + { + pname = name; + + if (NULL == zbx_json_decodevalue(p, value, sizeof(value), &type)) + type = zbx_json_valuetype(p); + else + pvalue = xml_escape_dyn(value); + if ('@' == name[0]) + set_attr = 1; + else if (0 == strcmp(name, XML_TEXT_TAG)) + set_text = 1; + } + else + { + p = p1; + if (NULL != (p = zbx_json_next_value(jp, p, value, sizeof(value), &type))) + { + pvalue = xml_escape_dyn(value); + } + else + { + p = p1; + if (NULL != (p = zbx_json_next(jp, p))) + type = zbx_json_valuetype(p); + } + } + p1 = p; + + if (0 != set_attr) + { + *attr = zbx_strdup(*attr, &name[1]); + if (NULL != pvalue) + *attr_val = zbx_strdup(*attr_val, pvalue); + } + else if (0 != set_text && NULL != pvalue) + { + *text = zbx_strdup(*text, pvalue); + } + else if (NULL != p) + { + pname = (NULL == arr_name) ? pname : arr_name; + node = NULL; + + if (ZBX_JSON_TYPE_ARRAY == type) + { + array_loc = name; + node = parent_node; + } + else if (ZBX_JSON_TYPE_OBJECT == type || ZBX_JSON_TYPE_UNKNOWN == type) + { + node = xmlNewDocNode(doc, NULL, (xmlChar *)pname, NULL); + } + else + node = xmlNewDocNode(doc, NULL, (xmlChar *)pname, (xmlChar *)pvalue); + + if (0 == deep) + { + if (0 < idx) + break; + if (node != NULL) + xmlDocSetRootElement(doc, node); + } + else + { + if (node != NULL && node != parent_node) + node = xmlAddChild(parent_node, node); + } + + if (SUCCEED == zbx_json_brackets_open(p, &jp_data)) + { + json_to_node(&jp_data, doc, node, array_loc, deep+1, &attr_loc, &attr_val_loc, + &text_loc); + } + } + + if (NULL != attr_loc) + xmlNewProp(node, (xmlChar *)attr_loc, (xmlChar *)attr_val_loc); + if (NULL != text_loc) + xmlNodeSetContent(node, (xmlChar *)text_loc); + + zbx_free(attr_loc); + zbx_free(attr_val_loc); + zbx_free(text_loc); + zbx_free(pvalue); + idx++; + } + while (NULL != p); +} + +/****************************************************************************** + * * + * Function: zbx_json_to_xml * + * * + * Purpose: convert JSON format value to XML format * + * * + * Parameters: data - [IN] the JSON data to process * + * jstr - [OUT] the XML output * + * errmsg - [OUT] error message * + * * + * Return value: SUCCEED - the value was processed successfully * + * FAIL - otherwise * + * * + ******************************************************************************/ +int zbx_json_to_xml(char *data, char **xstr, char **errmsg) +{ +#ifndef HAVE_LIBXML2 + ZBX_UNUSED(data); + ZBX_UNUSED(jstr); + *errmsg = zbx_dsprintf(*errmsg, "Zabbix was compiled without libxml2 support"); + return FAIL; +#else + struct zbx_json_parse jp; + char *attr = NULL, *attr_val = NULL, *text = NULL; + + xmlDoc *doc = NULL; + xmlErrorPtr pErr; + xmlChar *xmem; + int size, ret = FAIL; + + if (NULL == (doc = xmlNewDoc(BAD_CAST XML_DEFAULT_VERSION))) + { + if (NULL != (pErr = xmlGetLastError())) + *errmsg = zbx_dsprintf(*errmsg, "cannot parse xml value: %s", pErr->message); + else + *errmsg = zbx_strdup(*errmsg, "cannot parse xml value"); + goto exit; + } + + if (SUCCEED != zbx_json_open(data, &jp)) + { + *errmsg = zbx_strdup(*errmsg, zbx_json_strerror()); + goto clean; + } + + json_to_node(&jp, doc, NULL, NULL, 0, &attr, &attr_val, &text); + + xmlDocDumpMemory(doc, &xmem, &size); + + zbx_free(text); + zbx_free(attr_val); + zbx_free(attr); + + if (NULL == xmem) + { + if (NULL != (pErr = xmlGetLastError())) + *errmsg = zbx_dsprintf(*errmsg, "Cannot save XML: %s", pErr->message); + else + *errmsg = zbx_strdup(*errmsg, "Cannot save XML"); + + goto clean; + } + + *xstr = zbx_malloc(*xstr, (size_t)size + 1); + memcpy(*xstr, (const char *)xmem, (size_t)size + 1); + xmlFree(xmem); + ret = SUCCEED; +clean: + xmlFreeDoc(doc); +exit: + return ret; +#endif +} diff --git a/src/libs/zbxembed/Makefile.am b/src/libs/zbxembed/Makefile.am index da66f2a31ad..4ff5be9e05f 100644 --- a/src/libs/zbxembed/Makefile.am +++ b/src/libs/zbxembed/Makefile.am @@ -3,17 +3,19 @@ noinst_LIBRARIES = libzbxembed.a libzbxembed_a_SOURCES = \ + console.c \ + console.h \ duk_config.h \ duktape.c \ duktape.h \ embed.c \ embed.h \ + global.c \ + global.h \ httprequest.c \ httprequest.h \ + xml.c \ + xml.h \ zabbix.c \ - zabbix.h \ - console.c \ - console.h \ - global.c \ - global.h + zabbix.h diff --git a/src/libs/zbxembed/embed.c b/src/libs/zbxembed/embed.c index d93273efeaf..1a02cfb347e 100644 --- a/src/libs/zbxembed/embed.c +++ b/src/libs/zbxembed/embed.c @@ -26,6 +26,7 @@ #include "zabbix.h" #include "global.h" #include "console.h" +#include "xml.h" #include "duktape.h" @@ -230,6 +231,9 @@ int zbx_es_init_env(zbx_es_t *es, char **error) if (FAIL == zbx_es_init_httprequest(es, error)) goto out; + if (FAIL == zbx_es_init_xml(es, error)) + goto out; + es->env->timeout = ZBX_ES_TIMEOUT; ret = SUCCEED; out: diff --git a/src/libs/zbxembed/xml.c b/src/libs/zbxembed/xml.c new file mode 100644 index 00000000000..7cf3e6672aa --- /dev/null +++ b/src/libs/zbxembed/xml.c @@ -0,0 +1,198 @@ +/* +** Zabbix +** Copyright (C) 2001-2020 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 envied 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 "zbxembed.h" +#include "embed.h" +#include "duktape.h" +#include "xml.h" +#include "zbxserver.h" + +/****************************************************************************** + * * + * Function: es_xml_dtor * + * * + * Purpose: XML destructor * + * * + ******************************************************************************/ +static duk_ret_t es_xml_dtor(duk_context *ctx) +{ + ZBX_UNUSED(ctx); + + return 0; +} + +/****************************************************************************** + * * + * Function: es_xml_ctor * + * * + * Purpose: XML constructor * + * * + ******************************************************************************/ +static duk_ret_t es_xml_ctor(duk_context *ctx) +{ + if (!duk_is_constructor_call(ctx)) + return DUK_RET_TYPE_ERROR; + + duk_push_this(ctx); + + duk_push_c_function(ctx, es_xml_dtor, 1); + duk_set_finalizer(ctx, -2); + + return 0; +} + +/****************************************************************************** + * * + * Function: es_xml_query * + * * + * Purpose: XML.query method * + * * + ******************************************************************************/ +static duk_ret_t es_xml_query(duk_context *ctx) +{ + zbx_variant_t value; + int err_index = -1; + char *err = NULL; + + zbx_variant_set_str(&value, zbx_strdup(NULL, duk_to_string(ctx, 0))); + + if (FAIL == zbx_query_xpath(&value, duk_to_string(ctx, 1), &err)) + { + err_index = duk_push_error_object(ctx, DUK_RET_EVAL_ERROR, err); + goto out; + } + duk_push_string(ctx, value.data.str); + +out: + zbx_variant_clear(&value); + zbx_free(err); + + if (-1 != err_index) + return duk_throw(ctx); + + return 1; +} + +/****************************************************************************** + * * + * Function: es_xml_from_json * + * * + * Purpose: XML.fromJson method * + * * + ******************************************************************************/ +static duk_ret_t es_xml_from_json(duk_context *ctx) +{ + int err_index = -1; + char *str = NULL, *error = NULL; + + if (FAIL == zbx_json_to_xml((char *)duk_to_string(ctx, 0), &str, &error)) + { + err_index = duk_push_error_object(ctx, DUK_RET_EVAL_ERROR, error); + goto out; + } + duk_push_string(ctx, str); + +out: + zbx_free(str); + zbx_free(error); + + if (-1 != err_index) + return duk_throw(ctx); + + return 1; +} + +/****************************************************************************** + * * + * Function: es_xml_to_json * + * * + * Purpose: XML.toJson method * + * * + ******************************************************************************/ +static duk_ret_t es_xml_to_json(duk_context *ctx) +{ + int err_index = -1; + char *str = NULL, *error = NULL; + + if (FAIL == zbx_xml_to_json((char *)duk_to_string(ctx, 0), &str, &error)) + { + err_index = duk_push_error_object(ctx, DUK_RET_EVAL_ERROR, error); + goto out; + } + duk_push_string(ctx, str); + +out: + zbx_free(str); + zbx_free(error); + + if (-1 != err_index) + return duk_throw(ctx); + + return 1; +} + +static const duk_function_list_entry xml_methods[] = { + {"query", es_xml_query, 2}, + {"fromJson", es_xml_from_json, 1}, + {"toJson", es_xml_to_json, 1}, + {NULL, NULL, 0} +}; + + +static int es_xml_create_object(duk_context *ctx) +{ + duk_push_c_function(ctx, es_xml_ctor, 0); + duk_push_object(ctx); + + duk_put_function_list(ctx, -1, xml_methods); + + if (1 != duk_put_prop_string(ctx, -2, "prototype")) + return FAIL; + + duk_new(ctx, 0); + duk_put_global_string(ctx, "XML"); + + return SUCCEED; +} + +/****************************************************************************** + * * + * Function: zbx_es_init_xml * + * * + * Purpose: init XML object * + * * + ******************************************************************************/ +int zbx_es_init_xml(zbx_es_t *es, char **error) +{ + if (0 != setjmp(es->env->loc)) + { + *error = zbx_strdup(*error, es->env->error); + return FAIL; + } + + if (FAIL == es_xml_create_object(es->env->ctx)) + { + *error = zbx_strdup(*error, duk_safe_to_string(es->env->ctx, -1)); + duk_pop(es->env->ctx); + return FAIL; + } + + return SUCCEED; +} diff --git a/src/libs/zbxembed/xml.h b/src/libs/zbxembed/xml.h new file mode 100644 index 00000000000..69e996a41b6 --- /dev/null +++ b/src/libs/zbxembed/xml.h @@ -0,0 +1,25 @@ +/* +** Zabbix +** Copyright (C) 2001-2020 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_XML_H +#define ZABBIX_XML_H + +int zbx_es_init_xml(zbx_es_t *es, char **error); + +#endif diff --git a/src/libs/zbxjson/json.c b/src/libs/zbxjson/json.c index 8270512cf9c..aaeb2370092 100644 --- a/src/libs/zbxjson/json.c +++ b/src/libs/zbxjson/json.c @@ -1295,3 +1295,8 @@ out: zbx_jsonpath_clear(&jsonpath); return ret; } + +zbx_json_type_t zbx_json_valuetype(const char *p) +{ + return __zbx_json_type(p); +} diff --git a/src/libs/zbxserver/expression.c b/src/libs/zbxserver/expression.c index f85becfa150..90ae367a1ba 100644 --- a/src/libs/zbxserver/expression.c +++ b/src/libs/zbxserver/expression.c @@ -6832,3 +6832,4 @@ int substitute_key_macros_unmasked(char **data, zbx_uint64_t *hostid, DC_ITEM *d zbx_dc_set_macro_env(old_macro_env); return ret; } + diff --git a/src/zabbix_get/Makefile.am b/src/zabbix_get/Makefile.am index 8ced0057ccd..2fde76ca655 100644 --- a/src/zabbix_get/Makefile.am +++ b/src/zabbix_get/Makefile.am @@ -14,6 +14,10 @@ zabbix_get_LDADD = \ $(top_builddir)/src/libs/zbxnix/libzbxnix.a \ $(top_builddir)/src/libs/zbxconf/libzbxconf.a \ $(top_builddir)/src/libs/zbxcompress/libzbxcompress.a\ + $(top_builddir)/src/libs/zbxjson/libzbxjson.a \ + $(top_builddir)/src/libs/zbxalgo/libzbxalgo.a \ + $(top_builddir)/src/libs/zbxcommon/libzbxcommon.a \ + $(top_builddir)/src/libs/zbxregexp/libzbxregexp.a \ $(ZBXGET_LIBS) zabbix_get_LDFLAGS = $(ZBXGET_LDFLAGS) diff --git a/src/zabbix_server/preprocessor/item_preproc.c b/src/zabbix_server/preprocessor/item_preproc.c index 455eb640c92..2b9b0ddafcd 100644 --- a/src/zabbix_server/preprocessor/item_preproc.c +++ b/src/zabbix_server/preprocessor/item_preproc.c @@ -930,117 +930,6 @@ static int item_preproc_jsonpath(zbx_variant_t *value, const char *params, char /****************************************************************************** * * - * Function: item_preproc_xpath_op * - * * - * Purpose: execute xpath query * - * * - * Parameters: value - [IN/OUT] the value to process * - * params - [IN] the operation parameters * - * errmsg - [OUT] error message * - * * - * Return value: SUCCEED - the value was processed successfully * - * FAIL - otherwise * - * * - ******************************************************************************/ -static int item_preproc_xpath_op(zbx_variant_t *value, const char *params, char **errmsg) -{ -#ifndef HAVE_LIBXML2 - ZBX_UNUSED(value); - ZBX_UNUSED(params); - *errmsg = zbx_dsprintf(*errmsg, "Zabbix was compiled without libxml2 support"); - return FAIL; -#else - xmlDoc *doc = NULL; - xmlXPathContext *xpathCtx; - xmlXPathObject *xpathObj; - xmlNodeSetPtr nodeset; - xmlErrorPtr pErr; - xmlBufferPtr xmlBufferLocal; - int ret = FAIL, i; - char buffer[32], *ptr; - - if (FAIL == item_preproc_convert_value(value, ZBX_VARIANT_STR, errmsg)) - return FAIL; - - if (NULL == (doc = xmlReadMemory(value->data.str, strlen(value->data.str), "noname.xml", NULL, 0))) - { - if (NULL != (pErr = xmlGetLastError())) - *errmsg = zbx_dsprintf(*errmsg, "cannot parse xml value: %s", pErr->message); - else - *errmsg = zbx_strdup(*errmsg, "cannot parse xml value"); - return FAIL; - } - - xpathCtx = xmlXPathNewContext(doc); - - if (NULL == (xpathObj = xmlXPathEvalExpression((xmlChar *)params, xpathCtx))) - { - pErr = xmlGetLastError(); - *errmsg = zbx_dsprintf(*errmsg, "cannot parse xpath: %s", pErr->message); - goto out; - } - - switch (xpathObj->type) - { - case XPATH_NODESET: - xmlBufferLocal = xmlBufferCreate(); - - if (0 == xmlXPathNodeSetIsEmpty(xpathObj->nodesetval)) - { - nodeset = xpathObj->nodesetval; - for (i = 0; i < nodeset->nodeNr; i++) - xmlNodeDump(xmlBufferLocal, doc, nodeset->nodeTab[i], 0, 0); - } - zbx_variant_clear(value); - zbx_variant_set_str(value, zbx_strdup(NULL, (const char *)xmlBufferLocal->content)); - - xmlBufferFree(xmlBufferLocal); - ret = SUCCEED; - break; - case XPATH_STRING: - zbx_variant_clear(value); - zbx_variant_set_str(value, zbx_strdup(NULL, (const char *)xpathObj->stringval)); - ret = SUCCEED; - break; - case XPATH_BOOLEAN: - zbx_variant_clear(value); - zbx_variant_set_str(value, zbx_dsprintf(NULL, "%d", xpathObj->boolval)); - ret = SUCCEED; - break; - case XPATH_NUMBER: - zbx_variant_clear(value); - zbx_snprintf(buffer, sizeof(buffer), ZBX_FS_DBL, xpathObj->floatval); - - /* check for nan/inf values - isnan(), isinf() is not supported by c89/90 */ - /* so simply check the if the result starts with digit (accounting for -inf) */ - if (*(ptr = buffer) == '-') - ptr++; - if (0 != isdigit(*ptr)) - { - del_zeros(buffer); - zbx_variant_set_str(value, zbx_strdup(NULL, buffer)); - ret = SUCCEED; - } - else - *errmsg = zbx_strdup(*errmsg, "Invalid numeric value"); - break; - default: - *errmsg = zbx_strdup(*errmsg, "Unknown result"); - break; - } -out: - if (NULL != xpathObj) - xmlXPathFreeObject(xpathObj); - - xmlXPathFreeContext(xpathCtx); - xmlFreeDoc(doc); - - return ret; -#endif -} - -/****************************************************************************** - * * * Function: item_preproc_xpath * * * * Purpose: execute xpath query * @@ -1057,7 +946,10 @@ static int item_preproc_xpath(zbx_variant_t *value, const char *params, char **e { char *err = NULL; - if (SUCCEED == item_preproc_xpath_op(value, params, &err)) + if (FAIL == item_preproc_convert_value(value, ZBX_VARIANT_STR, errmsg)) + return FAIL; + + if (SUCCEED == zbx_query_xpath(value, params, &err)) return SUCCEED; *errmsg = zbx_dsprintf(*errmsg, "cannot extract XML value with xpath \"%s\": %s", params, err); @@ -2042,6 +1934,35 @@ out: /****************************************************************************** * * + * Function: item_preproc_xml_to_json * + * * + * Purpose: convert XML format value to JSON format * + * * + * Parameters: value - [IN/OUT] the value to process * + * errmsg - [OUT] error message * + * * + * Return value: SUCCEED - the value was processed successfully * + * FAIL - otherwise * + * * + ******************************************************************************/ +static int item_preproc_xml_to_json(zbx_variant_t *value, char **errmsg) +{ + char *json = NULL; + + if (FAIL == item_preproc_convert_value(value, ZBX_VARIANT_STR, errmsg)) + return FAIL; + + if (FAIL == zbx_xml_to_json(value->data.str, &json, errmsg)) + return FAIL; + + zbx_variant_clear(value); + zbx_variant_set_str(value, json); + + return SUCCEED; +} + +/****************************************************************************** + * * * Function: item_preproc_str_replace * * * * Purpose: replace substrings in string * @@ -2200,6 +2121,9 @@ int zbx_item_preproc(unsigned char value_type, zbx_variant_t *value, const zbx_t case ZBX_PREPROC_VALIDATE_NOT_SUPPORTED: ret = item_preproc_validate_notsupport(); break; + case ZBX_PREPROC_XML_TO_JSON: + ret = item_preproc_xml_to_json(value, error); + break; default: *error = zbx_dsprintf(*error, "unknown preprocessing operation"); ret = FAIL; |