Merge branch 'collectd-4.10' into collectd-5.3
[collectd.git] / src / curl_xml.c
index fc02859..356219a 100644 (file)
@@ -28,6 +28,7 @@
 #include <libxml/parser.h>
 #include <libxml/tree.h>
 #include <libxml/xpath.h>
+#include <libxml/xpathInternals.h>
 
 #include <curl/curl.h>
 
@@ -58,6 +59,14 @@ struct cx_xpath_s /* {{{ */
 typedef struct cx_xpath_s cx_xpath_t;
 /* }}} */
 
+struct cx_namespace_s /* {{{ */
+{
+  char *prefix;
+  char *url;
+};
+typedef struct cx_namespace_s cx_namespace_t;
+/* }}} */
+
 struct cx_s /* {{{ */
 {
   char *instance;
@@ -73,6 +82,9 @@ struct cx_s /* {{{ */
   char *post_body;
   struct curl_slist *headers;
 
+  cx_namespace_t *namespaces;
+  size_t namespaces_num;
+
   CURL *curl;
   char curl_errbuf[CURL_ERROR_SIZE];
   char *buffer;
@@ -162,6 +174,7 @@ static void cx_list_free (llist_t *list) /* {{{ */
 static void cx_free (void *arg) /* {{{ */
 {
   cx_t *db;
+  size_t i;
 
   DEBUG ("curl_xml plugin: cx_free (arg = %p);", arg);
 
@@ -189,6 +202,13 @@ static void cx_free (void *arg) /* {{{ */
   sfree (db->post_body);
   curl_slist_free_all (db->headers);
 
+  for (i = 0; i < db->namespaces_num; i++)
+  {
+    sfree (db->namespaces[i].prefix);
+    sfree (db->namespaces[i].url);
+  }
+  sfree (db->namespaces);
+
   sfree (db);
 } /* }}} void cx_free */
 
@@ -245,7 +265,8 @@ static xmlXPathObjectPtr cx_evaluate_xpath (xmlXPathContextPtr xpath_ctx, /* {{{
 
 static int cx_if_not_text_node (xmlNodePtr node) /* {{{ */
 {
-  if (node->type == XML_TEXT_NODE || node->type == XML_ATTRIBUTE_NODE)
+  if (node->type == XML_TEXT_NODE || node->type == XML_ATTRIBUTE_NODE ||
+      node->type == XML_ELEMENT_NODE)
     return (0);
 
   WARNING ("curl_xml plugin: "
@@ -362,7 +383,7 @@ static int cx_handle_instance_xpath (xmlXPathContextPtr xpath_ctx, /* {{{ */
   memset (vl->type_instance, 0, sizeof (vl->type_instance));
 
   /* If the base xpath returns more than one block, the result is assumed to be
-   * a table. The `Instnce' option is not optional in this case. Check for the
+   * a table. The `Instance' option is not optional in this case. Check for the
    * condition and inform the user. */
   if (is_table && (vl->type_instance == NULL))
   {
@@ -540,6 +561,7 @@ static int cx_parse_stats_xml(xmlChar* xml, cx_t *db) /* {{{ */
   int status;
   xmlDocPtr doc;
   xmlXPathContextPtr xpath_ctx;
+  size_t i;
 
   /* Load the XML */
   doc = xmlParseDoc(xml);
@@ -557,6 +579,22 @@ static int cx_parse_stats_xml(xmlChar* xml, cx_t *db) /* {{{ */
     return (-1);
   }
 
+  for (i = 0; i < db->namespaces_num; i++)
+  {
+    cx_namespace_t const *ns = db->namespaces + i;
+    status = xmlXPathRegisterNs (xpath_ctx,
+        BAD_CAST ns->prefix, BAD_CAST ns->url);
+    if (status != 0)
+    {
+      ERROR ("curl_xml plugin: "
+          "unable to register NS with prefix=\"%s\" and href=\"%s\"\n",
+          ns->prefix, ns->url);
+      xmlXPathFreeContext(xpath_ctx);
+      xmlFreeDoc (doc);
+      return (status);
+    }
+  }
+
   status = cx_handle_parsed_xml (doc, xpath_ctx, db);
   /* Cleanup */
   xmlXPathFreeContext(xpath_ctx);
@@ -570,6 +608,7 @@ static int cx_curl_perform (cx_t *db, CURL *curl) /* {{{ */
   long rc;
   char *ptr;
   char *url;
+  url = db->url;
 
   db->buffer_fill = 0; 
   status = curl_easy_perform (curl);
@@ -746,6 +785,46 @@ static int cx_config_add_xpath (cx_t *db, /* {{{ */
   return (status);
 } /* }}} int cx_config_add_xpath */
 
+static int cx_config_add_namespace (cx_t *db, /* {{{ */
+    oconfig_item_t *ci)
+{
+  cx_namespace_t *ns;
+
+  if ((ci->values_num != 2)
+      || (ci->values[0].type != OCONFIG_TYPE_STRING)
+      || (ci->values[1].type != OCONFIG_TYPE_STRING))
+  {
+    WARNING ("curl_xml plugin: The `Namespace' option "
+             "needs exactly two string arguments.");
+    return (EINVAL);
+  }
+
+  ns = realloc (db->namespaces, sizeof (*db->namespaces)
+      * (db->namespaces_num + 1));
+  if (ns == NULL)
+  {
+    ERROR ("curl_xml plugin: realloc failed.");
+    return (ENOMEM);
+  }
+  db->namespaces = ns;
+  ns = db->namespaces + db->namespaces_num;
+  memset (ns, 0, sizeof (*ns));
+
+  ns->prefix = strdup (ci->values[0].value.string);
+  ns->url = strdup (ci->values[1].value.string);
+
+  if ((ns->prefix == NULL) || (ns->url == NULL))
+  {
+    sfree (ns->prefix);
+    sfree (ns->url);
+    ERROR ("curl_xml plugin: strdup failed.");
+    return (ENOMEM);
+  }
+
+  db->namespaces_num++;
+  return (0);
+} /* }}} int cx_config_add_namespace */
+
 /* Initialize db->curl */
 static int cx_init_curl (cx_t *db) /* {{{ */
 {
@@ -860,6 +939,8 @@ static int cx_config_add_url (oconfig_item_t *ci) /* {{{ */
       status = cx_config_append_string ("Header", &db->headers, child);
     else if (strcasecmp ("Post", child->key) == 0)
       status = cf_util_get_string (child, &db->post_body);
+    else if (strcasecmp ("Namespace", child->key) == 0)
+      status = cx_config_add_namespace (db, child);
     else
     {
       WARNING ("curl_xml plugin: Option `%s' not allowed here.", child->key);