* Replaced compile option VALIDATE_STATE_XML with runtime option CLICON_VALIDATE_STATE_XML.

* XML childvec Compile error
This commit is contained in:
Olof hagsand 2020-03-04 11:46:30 +01:00
parent 0f54899ae4
commit cdcffa768f
5 changed files with 72 additions and 65 deletions

View file

@ -45,6 +45,7 @@ Expected: Early March 2020
* Added `clixon-stats` state for clixon XML and memory statistics. * Added `clixon-stats` state for clixon XML and memory statistics.
* Added: CLICON_CLI_BUF_START and CLICON_CLI_BUF_THRESHOLD so you can change the start and * Added: CLICON_CLI_BUF_START and CLICON_CLI_BUF_THRESHOLD so you can change the start and
threshold of quadratic and linear growth of CLIgen buffers (cbuf:s) threshold of quadratic and linear growth of CLIgen buffers (cbuf:s)
* Added: CLICON_VALIDATE_STATE_XML for controling validation of user state XML
* JSON parse error messages change from ` on line x: syntax error,..` to `json_parse: line x: syntax error` * JSON parse error messages change from ` on line x: syntax error,..` to `json_parse: line x: syntax error`
* Unknown-element error message is more descriptive, eg from `namespace is: urn:example:clixon` to: `Failed to find YANG spec of XML node: x with parent: xp in namespace urn:example:clixon`. * Unknown-element error message is more descriptive, eg from `namespace is: urn:example:clixon` to: `Failed to find YANG spec of XML node: x with parent: xp in namespace urn:example:clixon`.
* C-API parse and validation API more capable * C-API parse and validation API more capable
@ -66,6 +67,7 @@ Expected: Early March 2020
### Minor changes ### Minor changes
* Replaced compile option `VALIDATE_STATE_XML` with runtime option `CLICON_VALIDATE_STATE_XML`.
* Memory footprint * Memory footprint
* Do not autopopulate namespace cache, instead use on-demand, see `xml2ns()`. * Do not autopopulate namespace cache, instead use on-demand, see `xml2ns()`.
* Set CBUF start level to 256 (`CLICON_CLI_BUF_START` option) * Set CBUF start level to 256 (`CLICON_CLI_BUF_START` option)

View file

@ -1027,11 +1027,9 @@ from_client_get(clicon_handle h,
int32_t depth = -1; /* Nr of levels to print, -1 is all, 0 is none */ int32_t depth = -1; /* Nr of levels to print, -1 is all, 0 is none */
yang_stmt *yspec; yang_stmt *yspec;
int i; int i;
#ifdef VALIDATE_STATE_XML
cxobj *xerr = NULL; cxobj *xerr = NULL;
cxobj *xr; cxobj *xr;
cxobj *xb; cxobj *xb;
#endif
username = clicon_username_get(h); username = clicon_username_get(h);
if ((yspec = clicon_dbspec_yang(h)) == NULL){ if ((yspec = clicon_dbspec_yang(h)) == NULL){
@ -1081,21 +1079,22 @@ from_client_get(clicon_handle h,
/* If not only-state, then read running config /* If not only-state, then read running config
* Note xret can be pruned by nacm below and change name and * Note xret can be pruned by nacm below and change name and
* merged with state data, so zero-copy cant be used * merged with state data, so zero-copy cant be used
* Also, must use external namespace context here due to <filter stmt * Also, must use external namespace context here due to <filter> stmt
*/ */
#ifdef VALIDATE_STATE_XML if (clicon_option_bool(h, "CLICON_VALIDATE_STATE_XML")){
if (xmldb_get0(h, "running", nsc, NULL, 1, &xret, NULL) < 0) { if (xmldb_get0(h, "running", nsc, NULL, 1, &xret, NULL) < 0) {
if (netconf_operation_failed(cbret, "application", "read registry")< 0) if (netconf_operation_failed(cbret, "application", "read registry")< 0)
goto done; goto done;
goto ok; goto ok;
}
} }
#else else{
if (xmldb_get0(h, "running", nsc, xpath, 1, &xret, NULL) < 0) { if (xmldb_get0(h, "running", nsc, xpath, 1, &xret, NULL) < 0) {
if (netconf_operation_failed(cbret, "application", "read registry")< 0) if (netconf_operation_failed(cbret, "application", "read registry")< 0)
goto done; goto done;
goto ok; goto ok;
}
} }
#endif
/* If not only config, /* If not only config,
* get state data from plugins as defined by plugin_statedata(), if any * get state data from plugins as defined by plugin_statedata(), if any
*/ */
@ -1107,33 +1106,34 @@ from_client_get(clicon_handle h,
goto done; goto done;
goto ok; goto ok;
} }
#ifdef VALIDATE_STATE_XML if (clicon_option_bool(h, "CLICON_VALIDATE_STATE_XML")){
/* Check XML by validating it. return internal error with error cause /* Check XML by validating it. return internal error with error cause
* Primarily intended for user-supplied state-data. * Primarily intended for user-supplied state-data.
* The whole config tree must be present in case the state data references config data * The whole config tree must be present in case the state data references config data
*/ */
if ((ret = xml_yang_validate_all_top(h, xret, &xerr)) < 0) if ((ret = xml_yang_validate_all_top(h, xret, &xerr)) < 0)
goto done;
if (ret > 0 && (ret = xml_yang_validate_add(h, xret, &xerr)) < 0)
goto done;
if (ret == 0){
if (debug)
clicon_log_xml(LOG_DEBUG, xret, "VALIDATE_STATE");
if ((xr = xpath_first(xerr, NULL, "//error-tag")) != NULL &&
(xb = xml_body_get(xr))){
if (xml_value_set(xb, "operation-failed") < 0)
goto done;
}
if ((xr = xpath_first(xerr, NULL, "//error-message")) != NULL &&
(xb = xml_body_get(xr))){
if (xml_value_append(xb, " Internal error, state callback returned invalid XML") < 0)
goto done;
}
if (clicon_xml2cbuf(cbret, xerr, 0, 0, -1) < 0)
goto done; goto done;
goto ok; if (ret > 0 && (ret = xml_yang_validate_add(h, xret, &xerr)) < 0)
} goto done;
#endif /* VALIDATE_STATE_XML */ if (ret == 0){
if (debug)
clicon_log_xml(LOG_DEBUG, xret, "VALIDATE_STATE");
if ((xr = xpath_first(xerr, NULL, "//error-tag")) != NULL &&
(xb = xml_body_get(xr))){
if (xml_value_set(xb, "operation-failed") < 0)
goto done;
}
if ((xr = xpath_first(xerr, NULL, "//error-message")) != NULL &&
(xb = xml_body_get(xr))){
if (xml_value_append(xb, " Internal error, state callback returned invalid XML") < 0)
goto done;
}
if (clicon_xml2cbuf(cbret, xerr, 0, 0, -1) < 0)
goto done;
goto ok;
}
} /* CLICON_VALIDATE_STATE_XML */
if (content == CONTENT_NONCONFIG){ /* state only, all config should be removed now */ if (content == CONTENT_NONCONFIG){ /* state only, all config should be removed now */
/* Keep state data only, remove everything that is not config. Note that state data /* Keep state data only, remove everything that is not config. Note that state data
* may be a sub-part in a config tree, we need to traverse to find all * may be a sub-part in a config tree, we need to traverse to find all
@ -1197,10 +1197,8 @@ from_client_get(clicon_handle h,
retval = 0; retval = 0;
done: done:
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval); clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
#ifdef VALIDATE_STATE_XML
if (xerr) if (xerr)
xml_free(xerr); xml_free(xerr);
#endif
if (xpath) if (xpath)
free(xpath); free(xpath);
if (xnacm) if (xnacm)

View file

@ -78,17 +78,6 @@
*/ */
#define XML_EXPLICIT_INDEX #define XML_EXPLICIT_INDEX
/*! Validate user state callback content
* Users may register state callbacks using ca_statedata callback
* When this option is set, the XML returned from the callback is validated after merging with the running
* db. If it fails, an internal error is returned to the originating user.
* If the option is not set, the XML returned by the user is not validated.
* Note that enabling this option causes a large performance overhead for large lists, therefore it
* is recommended to enable it during development and debugging but disable it in production, until
* this has been resolved.
*/
#define VALIDATE_STATE_XML
/*! Treat <config> specially in a xmldb datastore. /*! Treat <config> specially in a xmldb datastore.
* config is treated as a "neutral" tag that does not have a yang spec. * config is treated as a "neutral" tag that does not have a yang spec.
* In particular when binding xml to yang, if <config> is encountered as top-of-tree, do not * In particular when binding xml to yang, if <config> is encountered as top-of-tree, do not

View file

@ -859,24 +859,24 @@ xml_child_each(cxobj *xparent,
* @note does not do anything with child, you may need to set its parent, etc * @note does not do anything with child, you may need to set its parent, etc
*/ */
static int static int
xml_child_append(cxobj *x, xml_child_append(cxobj *xp,
cxobj *xc) cxobj *xc)
{ {
if (!is_element(x)) if (!is_element(xp))
return 0; return 0;
x->x_childvec_len++; xp->x_childvec_len++;
if (x->x_childvec_len > x->x_childvec_max){ if (xp->x_childvec_len > xp->x_childvec_max){
if (x->x_childvec_len < XML_CHILDVEC_SIZE_THRESHOLD) if (xp->x_childvec_len < XML_CHILDVEC_SIZE_THRESHOLD)
x->x_childvec_max = x->x_childvec_max?2*x->x_childvec_max:XML_CHILDVEC_SIZE_START; xp->x_childvec_max = xp->x_childvec_max?2*xp->x_childvec_max:XML_CHILDVEC_SIZE_START;
else else
x->x_childvec_max += XML_CHILDVEC_SIZE_THRESHOLD; xp->x_childvec_max += XML_CHILDVEC_SIZE_THRESHOLD;
x->x_childvec = realloc(x->x_childvec, x->x_childvec_max*sizeof(cxobj*)); xp->x_childvec = realloc(xp->x_childvec, xp->x_childvec_max*sizeof(cxobj*));
if (x->x_childvec == NULL){ if (xp->x_childvec == NULL){
clicon_err(OE_XML, errno, "realloc"); clicon_err(OE_XML, errno, "realloc");
return -1; return -1;
} }
} }
x->x_childvec[x->x_childvec_len-1] = xc; xp->x_childvec[xp->x_childvec_len-1] = xc;
return 0; return 0;
} }
@ -896,7 +896,10 @@ xml_child_insert_pos(cxobj *xp,
return 0; return 0;
xp->x_childvec_len++; xp->x_childvec_len++;
if (xp->x_childvec_len > xp->x_childvec_max){ if (xp->x_childvec_len > xp->x_childvec_max){
xp->x_childvec_max = xp->x_childvec_max?2*xp->x_childvec_max:XML_CHILDVEC_MAX_DEFAULT; if (xp->x_childvec_len < XML_CHILDVEC_SIZE_THRESHOLD)
xp->x_childvec_max = xp->x_childvec_max?2*xp->x_childvec_max:XML_CHILDVEC_SIZE_START;
else
xp->x_childvec_max += XML_CHILDVEC_SIZE_THRESHOLD;
xp->x_childvec = realloc(xp->x_childvec, xp->x_childvec_max*sizeof(cxobj*)); xp->x_childvec = realloc(xp->x_childvec, xp->x_childvec_max*sizeof(cxobj*));
if (xp->x_childvec == NULL){ if (xp->x_childvec == NULL){
clicon_err(OE_XML, errno, "realloc"); clicon_err(OE_XML, errno, "realloc");

View file

@ -45,7 +45,8 @@ module clixon-config {
"Added: search index extension, "Added: search index extension,
Added: clixon-stats state for clixon XML and memory statistics. Added: clixon-stats state for clixon XML and memory statistics.
Added: CLICON_CLI_BUF_START and CLICON_CLI_BUF_THRESHOLD for quadratic and linear Added: CLICON_CLI_BUF_START and CLICON_CLI_BUF_THRESHOLD for quadratic and linear
growth of CLIgen buffers (cbuf:s)"; growth of CLIgen buffers (cbuf:s)
Added: CLICON_VALIDATE_STATE_XML for controling validation of user state XML";
} }
revision 2019-09-11 { revision 2019-09-11 {
description description
@ -575,6 +576,20 @@ module clixon-config {
If CLICON_XML_CHANGELOG is true, Clixon If CLICON_XML_CHANGELOG is true, Clixon
reads the module changelog from this file."; reads the module changelog from this file.";
} }
leaf CLICON_VALIDATE_STATE_XML {
type boolean;
default false;
description
"Validate user state callback content.
Users may register state callbacks using ca_statedata callback
When set, the XML returned from the callback is validated after merging with
the running db. If it fails, an internal error is returned to the originating
user.
If the option is not set, the XML returned by the user is not validated.
Note that enabling currently causes a large performance overhead for large
lists, therefore it is recommended to enable it during development and debugging
but disable it in production, until this has been resolved.";
}
leaf CLICON_STARTUP_MODE { leaf CLICON_STARTUP_MODE {
type startup_mode; type startup_mode;
description "Which method to boot/start clicon backend"; description "Which method to boot/start clicon backend";