X-Git-Url: https://git.octo.it/?a=blobdiff_plain;f=src%2Fcurl_xml.c;h=356219a2c92a346360b72a4745adc9bb29664347;hb=affac33e83584e7538c358e3bd0a587d0c692bc3;hp=46e0d490967456156863413912fe234deeb5abda;hpb=499cbd1605850e0feca405fb2579064d330eea8f;p=collectd.git diff --git a/src/curl_xml.c b/src/curl_xml.c index 46e0d490..356219a2 100644 --- a/src/curl_xml.c +++ b/src/curl_xml.c @@ -28,6 +28,7 @@ #include #include #include +#include #include @@ -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; @@ -70,6 +79,11 @@ struct cx_s /* {{{ */ _Bool verify_peer; _Bool verify_host; char *cacert; + char *post_body; + struct curl_slist *headers; + + cx_namespace_t *namespaces; + size_t namespaces_num; CURL *curl; char curl_errbuf[CURL_ERROR_SIZE]; @@ -160,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); @@ -184,10 +199,35 @@ static void cx_free (void *arg) /* {{{ */ sfree (db->pass); sfree (db->credentials); sfree (db->cacert); + 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 */ +static int cx_config_append_string (const char *name, struct curl_slist **dest, /* {{{ */ + oconfig_item_t *ci) +{ + if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING)) + { + WARNING ("curl_xml plugin: `%s' needs exactly one string argument.", name); + return (-1); + } + + *dest = curl_slist_append(*dest, ci->values[0].value.string); + if (*dest == NULL) + return (-1); + + return (0); +} /* }}} int cx_config_append_string */ + static int cx_check_type (const data_set_t *ds, cx_xpath_t *xpath) /* {{{ */ { if (!ds) @@ -225,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: " @@ -342,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)) { @@ -365,7 +406,7 @@ static int cx_handle_instance_xpath (xmlXPathContextPtr xpath_ctx, /* {{{ */ instance_node = instance_node_obj->nodesetval; tmp_size = (instance_node) ? instance_node->nodeNr : 0; - if ( (tmp_size == 0) && (is_table) ) + if (tmp_size <= 0) { WARNING ("curl_xml plugin: " "relative xpath expression for 'InstanceFrom' \"%s\" doesn't match " @@ -520,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); @@ -537,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); @@ -550,9 +608,16 @@ 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); + if (status != CURLE_OK) + { + ERROR ("curl_xml plugin: curl_easy_perform failed with status %i: %s (%s)", + status, db->curl_errbuf, url); + return (-1); + } curl_easy_getinfo(curl, CURLINFO_EFFECTIVE_URL, &url); curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &rc); @@ -565,13 +630,6 @@ static int cx_curl_perform (cx_t *db, CURL *curl) /* {{{ */ return (-1); } - if (status != 0) - { - ERROR ("curl_xml plugin: curl_easy_perform failed with status %i: %s (%s)", - status, db->curl_errbuf, url); - return (-1); - } - ptr = db->buffer; status = cx_parse_stats_xml(BAD_CAST ptr, db); @@ -727,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) /* {{{ */ { @@ -737,7 +835,7 @@ static int cx_init_curl (cx_t *db) /* {{{ */ return (-1); } - curl_easy_setopt (db->curl, CURLOPT_NOSIGNAL, 1); + curl_easy_setopt (db->curl, CURLOPT_NOSIGNAL, 1L); curl_easy_setopt (db->curl, CURLOPT_WRITEFUNCTION, cx_curl_callback); curl_easy_setopt (db->curl, CURLOPT_WRITEDATA, db); curl_easy_setopt (db->curl, CURLOPT_USERAGENT, @@ -770,6 +868,10 @@ static int cx_init_curl (cx_t *db) /* {{{ */ db->verify_host ? 2L : 0L); if (db->cacert != NULL) curl_easy_setopt (db->curl, CURLOPT_CAINFO, db->cacert); + if (db->headers != NULL) + curl_easy_setopt (db->curl, CURLOPT_HTTPHEADER, db->headers); + if (db->post_body != NULL) + curl_easy_setopt (db->curl, CURLOPT_POSTFIELDS, db->post_body); return (0); } /* }}} int cx_init_curl */ @@ -833,6 +935,12 @@ static int cx_config_add_url (oconfig_item_t *ci) /* {{{ */ status = cf_util_get_string (child, &db->cacert); else if (strcasecmp ("xpath", child->key) == 0) status = cx_config_add_xpath (db, child); + else if (strcasecmp ("Header", child->key) == 0) + 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);