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--configure.ac8
-rw-r--r--include/common.h4
-rw-r--r--include/zbxjson.h1
-rw-r--r--include/zbxserver.h1
-rw-r--r--src/libs/zbxcommon/Makefile.am4
-rw-r--r--src/libs/zbxcommon/xml.c569
-rw-r--r--src/libs/zbxembed/Makefile.am12
-rw-r--r--src/libs/zbxembed/embed.c4
-rw-r--r--src/libs/zbxembed/xml.c198
-rw-r--r--src/libs/zbxembed/xml.h25
-rw-r--r--src/libs/zbxjson/json.c5
-rw-r--r--src/libs/zbxserver/expression.c1
-rw-r--r--src/zabbix_get/Makefile.am4
-rw-r--r--src/zabbix_server/preprocessor/item_preproc.c148
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;