xml.c: Update deprecated libxml2 API usage.

Two functions are deprecated as of libxml2 2.12:

  * xmlSubstituteEntitiesDefault
  * xmlParseMemory

So we update those with supported API.

Additionally, `res_calendar_caldav` has been updated to use libxml2's
xmlreader API instead of the SAX2 API which has always felt a little
hacky (see deleted comment block in `res_calendar_caldav.c`).

The xmlreader API has been around since libxml2 2.5.0 which was
released in 2003.

Fixes #725
pull/724/head
Sean Bright 12 months ago
parent c3d2f32852
commit 21e3f84e56

@ -99,9 +99,7 @@ struct ast_xml_doc *ast_xml_open(char *filename)
return NULL; return NULL;
} }
xmlSubstituteEntitiesDefault(1); doc = xmlReadFile(filename, NULL, XML_PARSE_RECOVER | XML_PARSE_NOENT);
doc = xmlReadFile(filename, NULL, XML_PARSE_RECOVER);
if (!doc) { if (!doc) {
return NULL; return NULL;
} }
@ -505,9 +503,7 @@ struct ast_xslt_doc *ast_xslt_open(char *filename)
xsltStylesheet *xslt; xsltStylesheet *xslt;
xmlDoc *xml; xmlDoc *xml;
xmlSubstituteEntitiesDefault(1); xml = xmlReadFile(filename, NULL, XML_PARSE_RECOVER | XML_PARSE_NOENT);
xml = xmlReadFile(filename, NULL, XML_PARSE_RECOVER);
if (!xml) { if (!xml) {
return NULL; return NULL;
} }
@ -535,9 +531,8 @@ struct ast_xslt_doc *ast_xslt_read_memory(char *buffer, size_t size)
return NULL; return NULL;
} }
xmlSubstituteEntitiesDefault(1); doc = xmlReadMemory(buffer, (int) size, NULL, NULL, XML_PARSE_RECOVER | XML_PARSE_NOENT);
if (!doc) {
if (!(doc = xmlParseMemory(buffer, (int) size))) {
return NULL; return NULL;
} }

@ -36,8 +36,7 @@
#include <ne_request.h> #include <ne_request.h>
#include <ne_auth.h> #include <ne_auth.h>
#include <ne_redirect.h> #include <ne_redirect.h>
#include <libxml/xmlmemory.h> #include <libxml/xmlreader.h>
#include <libxml/parser.h>
#include "asterisk/module.h" #include "asterisk/module.h"
#include "asterisk/channel.h" #include "asterisk/channel.h"
@ -129,7 +128,11 @@ static int auth_credentials(void *userdata, const char *realm, int attempts, cha
static int debug_response_handler(void *userdata, ne_request *req, const ne_status *st) static int debug_response_handler(void *userdata, ne_request *req, const ne_status *st)
{ {
if (st->code < 200 || st->code > 299) { if (st->code < 200 || st->code > 299) {
ast_debug(1, "Unexpected response from server, %d: %s\n", st->code, st->reason_phrase); if (st->code == 401) {
ast_debug(1, "Got a 401 from the server but we expect this to happen when authenticating, %d: %s\n", st->code, st->reason_phrase);
} else {
ast_debug(1, "Unexpected response from server, %d: %s\n", st->code, st->reason_phrase);
}
return 0; return 0;
} }
return 1; return 1;
@ -482,14 +485,12 @@ struct xmlstate {
static const xmlChar *caldav_node_localname = BAD_CAST "calendar-data"; static const xmlChar *caldav_node_localname = BAD_CAST "calendar-data";
static const xmlChar *caldav_node_nsuri = BAD_CAST "urn:ietf:params:xml:ns:caldav"; static const xmlChar *caldav_node_nsuri = BAD_CAST "urn:ietf:params:xml:ns:caldav";
static void handle_start_element(void *data, static void handle_start_element(xmlTextReaderPtr reader, struct xmlstate *state)
const xmlChar *localname, const xmlChar *prefix, const xmlChar *uri,
int nb_namespaces, const xmlChar **namespaces,
int nb_attributes, int nb_defaulted, const xmlChar **attributes)
{ {
struct xmlstate *state = data; const xmlChar *localname = xmlTextReaderConstLocalName(reader);
const xmlChar *uri = xmlTextReaderConstNamespaceUri(reader);
if (xmlStrcmp(localname, caldav_node_localname) || xmlStrcmp(uri, caldav_node_nsuri)) { if (!xmlStrEqual(localname, caldav_node_localname) || !xmlStrEqual(uri, caldav_node_nsuri)) {
return; return;
} }
@ -497,16 +498,16 @@ static void handle_start_element(void *data,
ast_str_reset(state->cdata); ast_str_reset(state->cdata);
} }
static void handle_end_element(void *data, static void handle_end_element(xmlTextReaderPtr reader, struct xmlstate *state)
const xmlChar *localname, const xmlChar *prefix, const xmlChar *uri)
{ {
struct xmlstate *state = data;
struct icaltimetype start, end; struct icaltimetype start, end;
icaltimezone *utc = icaltimezone_get_utc_timezone(); icaltimezone *utc = icaltimezone_get_utc_timezone();
icalcomponent *iter; icalcomponent *iter;
icalcomponent *comp; icalcomponent *comp;
const xmlChar *localname = xmlTextReaderConstLocalName(reader);
const xmlChar *uri = xmlTextReaderConstNamespaceUri(reader);
if (xmlStrcmp(localname, caldav_node_localname) || xmlStrcmp(uri, caldav_node_nsuri)) { if (!xmlStrEqual(localname, caldav_node_localname) || !xmlStrEqual(uri, caldav_node_nsuri)) {
return; return;
} }
@ -530,18 +531,39 @@ static void handle_end_element(void *data,
icalcomponent_free(comp); icalcomponent_free(comp);
} }
static void handle_characters(void *data, const xmlChar *ch, int len) static void handle_characters(xmlTextReaderPtr reader, struct xmlstate *state)
{ {
struct xmlstate *state = data; xmlChar *text;
xmlChar *tmp;
if (!state->in_caldata) { if (!state->in_caldata) {
return; return;
} }
tmp = xmlStrndup(ch, len); text = xmlTextReaderValue(reader);
ast_str_append(&state->cdata, 0, "%s", (char *)tmp); if (text) {
xmlFree(tmp); ast_str_append(&state->cdata, 0, "%s", text);
xmlFree(text);
}
}
static void parse_error_handler(void *arg, const char *msg,
xmlParserSeverities severity, xmlTextReaderLocatorPtr locator)
{
switch (severity) {
case XML_PARSER_SEVERITY_VALIDITY_WARNING:
case XML_PARSER_SEVERITY_WARNING:
ast_log(LOG_WARNING, "While parsing CalDAV response at line %d: %s\n",
xmlTextReaderLocatorLineNumber(locator),
msg);
break;
case XML_PARSER_SEVERITY_VALIDITY_ERROR:
case XML_PARSER_SEVERITY_ERROR:
default:
ast_log(LOG_ERROR, "While parsing CalDAV response at line %d: %s\n",
xmlTextReaderLocatorLineNumber(locator),
msg);
break;
}
} }
static int update_caldav(struct caldav_pvt *pvt) static int update_caldav(struct caldav_pvt *pvt)
@ -549,7 +571,7 @@ static int update_caldav(struct caldav_pvt *pvt)
struct timeval now = ast_tvnow(); struct timeval now = ast_tvnow();
time_t start, end; time_t start, end;
struct ast_str *response; struct ast_str *response;
xmlSAXHandler saxHandler; xmlTextReaderPtr reader;
struct xmlstate state = { struct xmlstate state = {
.in_caldata = 0, .in_caldata = 0,
.pvt = pvt .pvt = pvt
@ -569,26 +591,39 @@ static int update_caldav(struct caldav_pvt *pvt)
state.start = start; state.start = start;
state.end = end; state.end = end;
/* reader = xmlReaderForMemory(
* We want SAX2, so you assume that we want to call xmlSAXVersion() here, and ast_str_buffer(response),
* that certainly seems like the right thing to do, but the default SAX ast_str_strlen(response),
* handling functions assume that the 'data' pointer is going to be a NULL,
* xmlParserCtxtPtr, not a user data pointer, so we have to make sure that we NULL,
* are only calling the handlers that we control. 0);
*
* So instead we hack things up a bit, clearing the struct and then assigning if (reader) {
* the magic number manually. int res;
*
* There may be a cleaner way to do this, but frankly the libxml2 docs are xmlTextReaderSetErrorHandler(reader, parse_error_handler, NULL);
* pretty sparse.
*/ res = xmlTextReaderRead(reader);
memset(&saxHandler, 0, sizeof(saxHandler)); while (res == 1) {
saxHandler.initialized = XML_SAX2_MAGIC; int node_type = xmlTextReaderNodeType(reader);
saxHandler.startElementNs = handle_start_element; switch (node_type) {
saxHandler.endElementNs = handle_end_element; case XML_READER_TYPE_ELEMENT:
saxHandler.characters = handle_characters; handle_start_element(reader, &state);
break;
xmlSAXUserParseMemory(&saxHandler, &state, ast_str_buffer(response), ast_str_strlen(response)); case XML_READER_TYPE_END_ELEMENT:
handle_end_element(reader, &state);
break;
case XML_READER_TYPE_TEXT:
case XML_READER_TYPE_CDATA:
handle_characters(reader, &state);
break;
default:
break;
}
res = xmlTextReaderRead(reader);
}
xmlFreeTextReader(reader);
}
ast_calendar_merge_events(pvt->owner, pvt->events); ast_calendar_merge_events(pvt->owner, pvt->events);

Loading…
Cancel
Save