diff options
author | John-Mark Bell <jmb@pexip.com> | 2023-09-17 01:24:06 +0100 |
---|---|---|
committer | John-Mark Bell <jmb@pexip.com> | 2023-09-17 01:24:06 +0100 |
commit | b2e6055a302ce7bbd280071ad1a5983f99d24087 (patch) | |
tree | 239a47a59f97a465c93c0b499bb0bae4147fb069 | |
parent | f665a6162bb541252fa2778608279e9bbf262fa3 (diff) | |
download | libdom-b2e6055a302ce7bbd280071ad1a5983f99d24087.tar.gz libdom-b2e6055a302ce7bbd280071ad1a5983f99d24087.tar.bz2 |
xmlparser/libxml: abort on dom errors
Previously, we would carry on regardless, leaving inconsistent
tree structures in our wake. Instead, give up as soon as something
unexpected happens.
-rw-r--r-- | bindings/xml/libxml_xmlparser.c | 224 | ||||
-rw-r--r-- | bindings/xml/xmlerror.h | 4 |
2 files changed, 145 insertions, 83 deletions
diff --git a/bindings/xml/libxml_xmlparser.c b/bindings/xml/libxml_xmlparser.c index 8c876be..e4a6d80 100644 --- a/bindings/xml/libxml_xmlparser.c +++ b/bindings/xml/libxml_xmlparser.c @@ -36,21 +36,21 @@ static void xml_parser_end_element_ns(void *ctx, const xmlChar *localname, static dom_exception xml_parser_link_nodes(dom_xml_parser *parser, struct dom_node *dom, xmlNodePtr xml); -static void xml_parser_add_node(dom_xml_parser *parser, struct dom_node *parent, - xmlNodePtr child); -static void xml_parser_add_element_node(dom_xml_parser *parser, +static dom_exception xml_parser_add_node(dom_xml_parser *parser, struct dom_node *parent, xmlNodePtr child); -static void xml_parser_add_text_node(dom_xml_parser *parser, +static dom_exception xml_parser_add_element_node(dom_xml_parser *parser, struct dom_node *parent, xmlNodePtr child); -static void xml_parser_add_cdata_section(dom_xml_parser *parser, +static dom_exception xml_parser_add_text_node(dom_xml_parser *parser, struct dom_node *parent, xmlNodePtr child); -static void xml_parser_add_entity_reference(dom_xml_parser *parser, +static dom_exception xml_parser_add_cdata_section(dom_xml_parser *parser, struct dom_node *parent, xmlNodePtr child); -static void xml_parser_add_entity(dom_xml_parser *parser, +static dom_exception xml_parser_add_entity_reference(dom_xml_parser *parser, + struct dom_node *parent, xmlNodePtr child); +static dom_exception xml_parser_add_entity(dom_xml_parser *parser, struct dom_node *parent, xmlNodePtr child); -static void xml_parser_add_comment(dom_xml_parser *parser, +static dom_exception xml_parser_add_comment(dom_xml_parser *parser, struct dom_node *parent, xmlNodePtr child); -static void xml_parser_add_document_type(dom_xml_parser *parser, +static dom_exception xml_parser_add_document_type(dom_xml_parser *parser, struct dom_node *parent, xmlNodePtr child); static void xml_parser_internal_subset(void *ctx, const xmlChar *name, @@ -96,6 +96,8 @@ struct dom_xml_parser { dom_msg msg; /**< Informational message function */ void *mctx; /**< Pointer to client data */ + + dom_exception err; /**< Last DOM error, if any */ }; /** @@ -133,7 +135,7 @@ static xmlSAXHandler sax_handler = { ._private = NULL, .startElementNs = xml_parser_start_element_ns, .endElementNs = xml_parser_end_element_ns, - .serror = NULL + .serror = NULL, }; static void *dom_xml_alloc(void *ptr, size_t len, void *pw) @@ -231,6 +233,8 @@ dom_xml_parser *dom_xml_parser_create(const char *enc, const char *int_enc, parser->msg = msg; parser->mctx = mctx; + parser->err = DOM_NO_ERR; + return parser; } @@ -271,6 +275,10 @@ dom_xml_error dom_xml_parser_parse_chunk(dom_xml_parser *parser, return DOM_XML_EXTERNAL_ERR | err; } + if (parser->err != DOM_NO_ERR) { + return DOM_XML_DOM_ERR | parser->err; + } + return DOM_XML_OK; } @@ -293,6 +301,10 @@ dom_xml_error dom_xml_parser_completed(dom_xml_parser *parser) return DOM_XML_EXTERNAL_ERR | err; } + if (parser->err != DOM_NO_ERR) { + return DOM_XML_DOM_ERR | parser->err; + } + return DOM_XML_OK; } @@ -304,9 +316,11 @@ dom_xml_error dom_xml_parser_completed(dom_xml_parser *parser) void xml_parser_start_document(void *ctx) { dom_xml_parser *parser = (dom_xml_parser *) ctx; - dom_exception err; xmlErrorPtr xmlerr; + if (parser->err != DOM_NO_ERR) + return; + /* Invoke libxml2's default behaviour */ xmlSAX2StartDocument(parser->xml_ctx); xmlerr = xmlCtxtGetLastError(parser->xml_ctx); @@ -315,9 +329,10 @@ void xml_parser_start_document(void *ctx) } /* Link nodes together */ - err = xml_parser_link_nodes(parser, (struct dom_node *) parser->doc, + parser->err = xml_parser_link_nodes(parser, + (struct dom_node *) parser->doc, (xmlNodePtr) parser->xml_ctx->myDoc); - if (err != DOM_NO_ERR) { + if (parser->err != DOM_NO_ERR) { parser->msg(DOM_MSG_WARNING, parser->mctx, "Not able to link document nodes"); } @@ -333,9 +348,11 @@ void xml_parser_end_document(void *ctx) dom_xml_parser *parser = (dom_xml_parser *) ctx; xmlNodePtr node; xmlNodePtr n; - dom_exception err; xmlErrorPtr xmlerr; + if (parser->err != DOM_NO_ERR) + return; + /* Invoke libxml2's default behaviour */ xmlSAX2EndDocument(parser->xml_ctx); xmlerr = xmlCtxtGetLastError(parser->xml_ctx); @@ -354,13 +371,13 @@ void xml_parser_end_document(void *ctx) * children which occur after the last Element node in the list */ /* Get XML node */ - err = dom_node_get_user_data((struct dom_node *) parser->doc, + parser->err = dom_node_get_user_data((struct dom_node *) parser->doc, parser->udkey, (void **) (void *) &node); /* The return value from dom_node_get_user_data() is always * DOM_NO_ERR, but the returned "node" will be NULL if no user * data is found. */ - if (err != DOM_NO_ERR || node == NULL) { + if (parser->err != DOM_NO_ERR || node == NULL) { parser->msg(DOM_MSG_WARNING, parser->mctx, "Failed finding XML node"); return; @@ -382,8 +399,10 @@ void xml_parser_end_document(void *ctx) /* Now, mirror nodes in the DOM */ for (; n != NULL; n = n->next) { - xml_parser_add_node(parser, + parser->err = xml_parser_add_node(parser, (struct dom_node *) node->_private, n); + if (parser->err != DOM_NO_ERR) + return; } } @@ -413,6 +432,9 @@ void xml_parser_start_element_ns(void *ctx, const xmlChar *localname, xmlNodePtr parent = parser->xml_ctx->node; xmlErrorPtr xmlerr; + if (parser->err != DOM_NO_ERR) + return; + /* Invoke libxml2's default behaviour */ xmlSAX2StartElementNs(parser->xml_ctx, localname, prefix, URI, nb_namespaces, namespaces, nb_attributes, @@ -459,16 +481,18 @@ void xml_parser_start_element_ns(void *ctx, const xmlChar *localname, /* Now, mirror nodes in the DOM */ for (; n != parser->xml_ctx->node; n = n->next) { - xml_parser_add_node(parser, + parser->err = xml_parser_add_node(parser, (struct dom_node *) parent->_private, n); + if (parser->err != DOM_NO_ERR) + return; } } /* Mirror the created node and its attributes in the DOM */ - xml_parser_add_node(parser, (struct dom_node *) parent->_private, + parser->err = xml_parser_add_node(parser, + (struct dom_node *) parent->_private, parser->xml_ctx->node); - } /** @@ -487,6 +511,9 @@ void xml_parser_end_element_ns(void *ctx, const xmlChar *localname, xmlNodePtr n; xmlErrorPtr xmlerr; + if (parser->err != DOM_NO_ERR) + return; + /* Invoke libxml2's default behaviour */ xmlSAX2EndElementNs(parser->xml_ctx, localname, prefix, URI); xmlerr = xmlCtxtGetLastError(parser->xml_ctx); @@ -527,8 +554,10 @@ void xml_parser_end_element_ns(void *ctx, const xmlChar *localname, /* Now, mirror nodes in the DOM */ for (; n != NULL; n = n->next) { - xml_parser_add_node(parser, + parser->err = xml_parser_add_node(parser, (struct dom_node *) node->_private, n); + if (parser->err != DOM_NO_ERR) + return; } } @@ -567,9 +596,10 @@ dom_exception xml_parser_link_nodes(dom_xml_parser *parser, * \param parser The parser context * \param parent The parent DOM node * \param child The xmlNode to mirror in the DOM as a child of parent + * \return DOM_NO_ERR on success, appropriate error otherwise */ -void xml_parser_add_node(dom_xml_parser *parser, struct dom_node *parent, - xmlNodePtr child) +dom_exception xml_parser_add_node(dom_xml_parser *parser, + struct dom_node *parent, xmlNodePtr child) { static const char *node_types[] = { "THIS_IS_NOT_A_NODE", @@ -598,31 +628,26 @@ void xml_parser_add_node(dom_xml_parser *parser, struct dom_node *parent, switch (child->type) { case XML_ELEMENT_NODE: - xml_parser_add_element_node(parser, parent, child); - break; + return xml_parser_add_element_node(parser, parent, child); case XML_TEXT_NODE: - xml_parser_add_text_node(parser, parent, child); - break; + return xml_parser_add_text_node(parser, parent, child); case XML_CDATA_SECTION_NODE: - xml_parser_add_cdata_section(parser, parent, child); - break; + return xml_parser_add_cdata_section(parser, parent, child); case XML_ENTITY_REF_NODE: - xml_parser_add_entity_reference(parser, parent, child); - break; + return xml_parser_add_entity_reference(parser, parent, child); case XML_COMMENT_NODE: - xml_parser_add_comment(parser, parent, child); - break; + return xml_parser_add_comment(parser, parent, child); case XML_DTD_NODE: - xml_parser_add_document_type(parser, parent, child); - break; - case XML_ENTITY_DECL: - xml_parser_add_entity(parser, parent, child); - break; + return xml_parser_add_document_type(parser, parent, child); + case XML_ENTITY_DECL: + return xml_parser_add_entity(parser, parent, child); default: parser->msg(DOM_MSG_NOTICE, parser->mctx, "Unsupported node type: %s", node_types[child->type]); } + + return DOM_NO_ERR; } /** @@ -631,8 +656,9 @@ void xml_parser_add_node(dom_xml_parser *parser, struct dom_node *parent, * \param parser The parser context * \param parent The parent DOM node * \param child The xmlNode to mirror in the DOM as a child of parent + * \return DOM_NO_ERR on success, appropriate error otherwise */ -void xml_parser_add_element_node(dom_xml_parser *parser, +dom_exception xml_parser_add_element_node(dom_xml_parser *parser, struct dom_node *parent, xmlNodePtr child) { struct dom_element *el, *ins_el = NULL; @@ -650,7 +676,7 @@ void xml_parser_add_element_node(dom_xml_parser *parser, if (err != DOM_NO_ERR) { parser->msg(DOM_MSG_CRITICAL, parser->mctx, "No memory for tag name"); - return; + return err; } /* Create element node */ @@ -661,7 +687,7 @@ void xml_parser_add_element_node(dom_xml_parser *parser, parser->msg(DOM_MSG_CRITICAL, parser->mctx, "Failed creating element '%s'", child->name); - return; + return err; } /* No longer need tag name */ @@ -684,7 +710,7 @@ void xml_parser_add_element_node(dom_xml_parser *parser, if (err != DOM_NO_ERR) { parser->msg(DOM_MSG_CRITICAL, parser->mctx, "No memory for namespace"); - return; + return err; } /* QName is "prefix:localname", @@ -704,7 +730,7 @@ void xml_parser_add_element_node(dom_xml_parser *parser, dom_string_unref(namespace); parser->msg(DOM_MSG_CRITICAL, parser->mctx, "No memory for qname"); - return; + return err; } /* Create element node */ @@ -716,7 +742,7 @@ void xml_parser_add_element_node(dom_xml_parser *parser, parser->msg(DOM_MSG_CRITICAL, parser->mctx, "Failed creating element '%s'", qnamebuf); - return; + return err; } /* No longer need namespace / qname */ @@ -776,7 +802,7 @@ void xml_parser_add_element_node(dom_xml_parser *parser, if (err != DOM_NO_ERR) { parser->msg(DOM_MSG_CRITICAL, parser->mctx, "No memory for namespace"); - return; + goto cleanup; } /* QName is "prefix:localname", @@ -796,7 +822,7 @@ void xml_parser_add_element_node(dom_xml_parser *parser, dom_string_unref(namespace); parser->msg(DOM_MSG_CRITICAL, parser->mctx, "No memory for qname"); - return; + goto cleanup; } /* Create attribute */ @@ -808,7 +834,7 @@ void xml_parser_add_element_node(dom_xml_parser *parser, parser->msg(DOM_MSG_CRITICAL, parser->mctx, "Failed creating attribute \ '%s'", qnamebuf); - return; + goto cleanup; } /* No longer need namespace / qname */ @@ -818,8 +844,12 @@ void xml_parser_add_element_node(dom_xml_parser *parser, /* Clone subtree (attribute value) */ for (c = a->children; c != NULL; c = c->next) { - xml_parser_add_node(parser, + err = xml_parser_add_node(parser, (struct dom_node *) attr, c); + if (err != DOM_NO_ERR) { + dom_node_unref((struct dom_node *) attr); + goto cleanup; + } } /* Link nodes together */ @@ -885,14 +915,14 @@ void xml_parser_add_element_node(dom_xml_parser *parser, /* No longer interested in element node */ dom_node_unref((struct dom_node *) el); - return; + return DOM_NO_ERR; cleanup: /* No longer want node (any attributes attached to it * will be cleaned up with it) */ dom_node_unref((struct dom_node *) el); - return; + return err; } /** @@ -901,9 +931,10 @@ cleanup: * \param parser The parser context * \param parent The parent DOM node * \param child The xmlNode to mirror in the DOM as a child of parent + * \return DOM_NO_ERR on success, appropriate error otherwise */ -void xml_parser_add_text_node(dom_xml_parser *parser, struct dom_node *parent, - xmlNodePtr child) +dom_exception xml_parser_add_text_node(dom_xml_parser *parser, + struct dom_node *parent, xmlNodePtr child) { struct dom_text *text, *ins_text = NULL; dom_string *data; @@ -915,7 +946,7 @@ void xml_parser_add_text_node(dom_xml_parser *parser, struct dom_node *parent, if (err != DOM_NO_ERR) { parser->msg(DOM_MSG_CRITICAL, parser->mctx, "No memory for text node contents "); - return; + return err; } /* Create text node */ @@ -924,7 +955,7 @@ void xml_parser_add_text_node(dom_xml_parser *parser, struct dom_node *parent, dom_string_unref(data); parser->msg(DOM_MSG_CRITICAL, parser->mctx, "No memory for text node"); - return; + return err; } /* No longer need data */ @@ -937,7 +968,7 @@ void xml_parser_add_text_node(dom_xml_parser *parser, struct dom_node *parent, dom_node_unref((struct dom_node *) text); parser->msg(DOM_MSG_ERROR, parser->mctx, "Failed attaching text node"); - return; + return err; } /* We're not interested in the inserted text node */ @@ -949,11 +980,13 @@ void xml_parser_add_text_node(dom_xml_parser *parser, struct dom_node *parent, child); if (err != DOM_NO_ERR) { dom_node_unref((struct dom_node *) text); - return; + return err; } /* No longer interested in text node */ dom_node_unref((struct dom_node *) text); + + return DOM_NO_ERR; } /** @@ -962,8 +995,9 @@ void xml_parser_add_text_node(dom_xml_parser *parser, struct dom_node *parent, * \param parser The parser context * \param parent The parent DOM node * \param child The xmlNode to mirror in the DOM as a child of parent + * \return DOM_NO_ERR on success, appropriate error otherwise */ -void xml_parser_add_cdata_section(dom_xml_parser *parser, +dom_exception xml_parser_add_cdata_section(dom_xml_parser *parser, struct dom_node *parent, xmlNodePtr child) { struct dom_cdata_section *cdata, *ins_cdata = NULL; @@ -976,7 +1010,7 @@ void xml_parser_add_cdata_section(dom_xml_parser *parser, if (err != DOM_NO_ERR) { parser->msg(DOM_MSG_CRITICAL, parser->mctx, "No memory for cdata section contents"); - return; + return err; } /* Create cdata section */ @@ -985,7 +1019,7 @@ void xml_parser_add_cdata_section(dom_xml_parser *parser, dom_string_unref(data); parser->msg(DOM_MSG_CRITICAL, parser->mctx, "No memory for cdata section"); - return; + return err; } /* No longer need data */ @@ -998,7 +1032,7 @@ void xml_parser_add_cdata_section(dom_xml_parser *parser, dom_node_unref((struct dom_node *) cdata); parser->msg(DOM_MSG_ERROR, parser->mctx, "Failed attaching cdata section"); - return; + return err; } /* We're not interested in the inserted cdata section */ @@ -1010,11 +1044,13 @@ void xml_parser_add_cdata_section(dom_xml_parser *parser, child); if (err != DOM_NO_ERR) { dom_node_unref((struct dom_node *) cdata); - return; + return err; } /* No longer interested in cdata section */ dom_node_unref((struct dom_node *) cdata); + + return DOM_NO_ERR; } /** @@ -1023,8 +1059,9 @@ void xml_parser_add_cdata_section(dom_xml_parser *parser, * \param parser The parser context * \param parent The parent DOM node * \param child The xmlNode to mirror in the DOM as a child of parent + * \return DOM_NO_ERR on success, appropriate error otherwise */ -void xml_parser_add_entity_reference(dom_xml_parser *parser, +dom_exception xml_parser_add_entity_reference(dom_xml_parser *parser, struct dom_node *parent, xmlNodePtr child) { struct dom_entity_reference *entity, *ins_entity = NULL; @@ -1038,7 +1075,7 @@ void xml_parser_add_entity_reference(dom_xml_parser *parser, if (err != DOM_NO_ERR) { parser->msg(DOM_MSG_CRITICAL, parser->mctx, "No memory for entity reference name"); - return; + return err; } /* Create text node */ @@ -1048,7 +1085,7 @@ void xml_parser_add_entity_reference(dom_xml_parser *parser, dom_string_unref(name); parser->msg(DOM_MSG_CRITICAL, parser->mctx, "No memory for entity reference"); - return; + return err; } /* No longer need name */ @@ -1056,7 +1093,10 @@ void xml_parser_add_entity_reference(dom_xml_parser *parser, /* Mirror subtree (reference value) */ for (c = child->children; c != NULL; c = c->next) { - xml_parser_add_node(parser, (struct dom_node *) entity, c); + err = xml_parser_add_node(parser, + (struct dom_node *) entity, c); + if (err != DOM_NO_ERR) + return err; } /* Append entity reference to parent */ @@ -1066,7 +1106,7 @@ void xml_parser_add_entity_reference(dom_xml_parser *parser, dom_node_unref((struct dom_node *) entity); parser->msg(DOM_MSG_ERROR, parser->mctx, "Failed attaching entity reference"); - return; + return err; } /* We're not interested in the inserted entity reference */ @@ -1078,19 +1118,33 @@ void xml_parser_add_entity_reference(dom_xml_parser *parser, child); if (err != DOM_NO_ERR) { dom_node_unref((struct dom_node *) entity); - return; + return err; } /* No longer interested in entity reference */ dom_node_unref((struct dom_node *) entity); + + return DOM_NO_ERR; } -static void xml_parser_add_entity(dom_xml_parser *parser, - struct dom_node *parent, xmlNodePtr child) +/** + * Add an entity to the DOM + * + * \param parser The parser context + * \param parent The parent DOM node + * \param child The xmlNode to mirror in the DOM as a child of parent + * \return DOM_NO_ERR on success, appropriate error otherwise + */ +dom_exception xml_parser_add_entity(dom_xml_parser *parser, + struct dom_node *parent, xmlNodePtr child) { - UNUSED(parser); - UNUSED(parent); - UNUSED(child); + UNUSED(parser); + UNUSED(parent); + UNUSED(child); + + /** \todo implement */ + + return DOM_NO_ERR; } /** @@ -1099,9 +1153,10 @@ static void xml_parser_add_entity(dom_xml_parser *parser, * \param parser The parser context * \param parent The parent DOM node * \param child The xmlNode to mirror in the DOM as a child of parent + * \return DOM_NO_ERR on success, appropriate error otherwise */ -void xml_parser_add_comment(dom_xml_parser *parser, struct dom_node *parent, - xmlNodePtr child) +dom_exception xml_parser_add_comment(dom_xml_parser *parser, + struct dom_node *parent, xmlNodePtr child) { struct dom_comment *comment, *ins_comment = NULL; dom_string *data; @@ -1113,7 +1168,7 @@ void xml_parser_add_comment(dom_xml_parser *parser, struct dom_node *parent, if (err != DOM_NO_ERR) { parser->msg(DOM_MSG_CRITICAL, parser->mctx, "No memory for comment data"); - return; + return err; } /* Create comment */ @@ -1122,7 +1177,7 @@ void xml_parser_add_comment(dom_xml_parser *parser, struct dom_node *parent, dom_string_unref(data); parser->msg(DOM_MSG_CRITICAL, parser->mctx, "No memory for comment node"); - return; + return err; } /* No longer need data */ @@ -1135,7 +1190,7 @@ void xml_parser_add_comment(dom_xml_parser *parser, struct dom_node *parent, dom_node_unref((struct dom_node *) comment); parser->msg(DOM_MSG_CRITICAL, parser->mctx, "Failed attaching comment node"); - return; + return err; } /* We're not interested in the inserted comment */ @@ -1147,11 +1202,13 @@ void xml_parser_add_comment(dom_xml_parser *parser, struct dom_node *parent, child); if (err != DOM_NO_ERR) { dom_node_unref((struct dom_node *) comment); - return; + return err; } /* No longer interested in comment */ dom_node_unref((struct dom_node *) comment); + + return DOM_NO_ERR; } /** @@ -1160,8 +1217,9 @@ void xml_parser_add_comment(dom_xml_parser *parser, struct dom_node *parent, * \param parser The parser context * \param parent The parent DOM node * \param child The xmlNode to mirror in the DOM as a child of parent + * \return DOM_NO_ERR on success, appropriate error otherwise */ -void xml_parser_add_document_type(dom_xml_parser *parser, +dom_exception xml_parser_add_document_type(dom_xml_parser *parser, struct dom_node *parent, xmlNodePtr child) { xmlDtdPtr dtd = (xmlDtdPtr) child; @@ -1187,7 +1245,7 @@ void xml_parser_add_document_type(dom_xml_parser *parser, if (err != DOM_NO_ERR) { parser->msg(DOM_MSG_CRITICAL, parser->mctx, "Failed to create document type"); - return; + return err; } /* Add doctype to document */ @@ -1197,7 +1255,7 @@ void xml_parser_add_document_type(dom_xml_parser *parser, dom_node_unref((struct dom_node *) doctype); parser->msg(DOM_MSG_CRITICAL, parser->mctx, "Failed attaching doctype"); - return; + return err; } /* Not interested in inserted node */ @@ -1209,11 +1267,13 @@ void xml_parser_add_document_type(dom_xml_parser *parser, child); if (err != DOM_NO_ERR) { dom_node_unref((struct dom_node *) doctype); - return; + return err; } /* No longer interested in doctype */ dom_node_unref((struct dom_node *) doctype); + + return DOM_NO_ERR; } /* ------------------------------------------------------------------------*/ diff --git a/bindings/xml/xmlerror.h b/bindings/xml/xmlerror.h index 51f2c8b..a6cb905 100644 --- a/bindings/xml/xmlerror.h +++ b/bindings/xml/xmlerror.h @@ -13,7 +13,9 @@ typedef enum { DOM_XML_NOMEM = 1, - DOM_XML_EXTERNAL_ERR = (1<<16), + DOM_XML_EXTERNAL_ERR = (1<<16), + + DOM_XML_DOM_ERR = (1<<24), } dom_xml_error; #endif |