From 52f262be5b819ac3dfe77a64bd4b81b105ca2f26 Mon Sep 17 00:00:00 2001 From: Georgios Koutsoumpakis Date: Mon, 10 Oct 2022 15:47:34 +0200 Subject: [PATCH] StructError to include the full path When investigating the reason that a large XML failed the validation, looking at only the NodeName might not be enough since there can be too many elements with the same name, for example `address`. At the same time, while the error message contains the actual value, so it could be used to identify where the issue lies, it may not be possible to log since that might contain sensitive data. For that reason a new field is added in StructError that contains the full path to the node that fails the validation. This is reported in reverse order for easier string concatenation. For example: `child1len; i++) { free(errArr->data[i].message); free(errArr->data[i].node); + free(errArr->data[i].path); } free(errArr->data); } @@ -147,6 +149,7 @@ static void simpleStructErrorCallback(void* ctx, xmlErrorPtr p) { struct simpleXmlError sErr; sErr.message = calloc(GO_ERR_INIT, sizeof(char)); sErr.node = calloc(GO_ERR_INIT, sizeof(char)); + sErr.path = calloc(GO_ERR_INIT, sizeof(char)); sErr.type = VALIDATION_ERROR; sErr.code = p->code; @@ -168,6 +171,35 @@ static void simpleStructErrorCallback(void* ctx, xmlErrorPtr p) { sErr.node = malloc(cpyLen); snprintf(sErr.node, cpyLen, "%s", (((xmlNodePtr)p->node)->name)); } + + int pathLen = GO_ERR_INIT; + if (cpyLen > pathLen) { + free(sErr.path); + pathLen = cpyLen *2; + sErr.path = malloc(pathLen); + } + + cpyLen = snprintf(sErr.path, pathLen, "%s", sErr.node); + xmlNodePtr node = (xmlNodePtr)p->node; + node = node->parent; + while (node != NULL && node->name != NULL) { + int offset = cpyLen; + int limit = pathLen - offset; + + cpyLen = cpyLen + snprintf(sErr.path+offset, limit, "<%s", node->name); + if (cpyLen > pathLen) { + pathLen += cpyLen; + limit = pathLen - offset; + + char* newPath = malloc(pathLen); + cpyLen = snprintf(newPath, offset + 1, "%s", sErr.path); + cpyLen = cpyLen + snprintf(newPath + offset, limit, "<%s", node->name); + + free(sErr.path); + sErr.path = newPath; + } + node = node->parent; + } } if (sErrArr->len >= sErrArr->cap) { sErrArr->cap = sErrArr->cap * 2; @@ -304,6 +336,7 @@ static errArray cValidate(const xmlDocPtr doc, const xmlSchemaPtr schema) { struct simpleXmlError simpleError; simpleError.message = calloc(GO_ERR_INIT, sizeof(char)); simpleError.node = calloc(GO_ERR_INIT, sizeof(char)); + simpleError.path = calloc(GO_ERR_INIT, sizeof(char)); if (schema == NULL) { simpleError.type = LIBXML2_ERROR; @@ -338,6 +371,7 @@ static errArray cValidate(const xmlDocPtr doc, const xmlSchemaPtr schema) { } else { free(simpleError.node); free(simpleError.message); + free(simpleError.path); } } } @@ -357,6 +391,7 @@ static errArray cValidateBuf(const void* goXmlSource, struct simpleXmlError simpleError; simpleError.message = calloc(GO_ERR_INIT, sizeof(char)); simpleError.node = calloc(GO_ERR_INIT, sizeof(char)); + simpleError.path = calloc(GO_ERR_INIT, sizeof(char)); struct xmlParserResult parserResult = cParseDoc(goXmlSource, goXmlSourceLen, xmlParserOptions); @@ -387,6 +422,7 @@ static errArray cValidateBuf(const void* goXmlSource, } free(simpleError.node); free(simpleError.message); + free(simpleError.path); freeErrArray(&errArr); free(parserResult.errorStr); @@ -476,7 +512,8 @@ func handleErrArray(errSlice []C.struct_simpleXmlError) ValidationError { Message: strings.Trim(C.GoString(errSlice[i].message), "\n"), Level: int(errSlice[i].level), Line: int(errSlice[i].line), - NodeName: C.GoString(errSlice[i].node)} + NodeName: C.GoString(errSlice[i].node), + Path: C.GoString(errSlice[i].path)} } return ve