Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/parser_data.h
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,10 @@ struct ly_in;
format according to RFC 7951 based on their type. Using this
option the validation can be softened to accept boolean and
number type values enclosed in quotes. */
#define LYD_PARSE_ANYDATA_STRICT 0x10000000 /**< Apply strict parsing (::LYD_PARSE_STRICT) also to anydata
content. By default, unknown elements in anydata are parsed
as opaque nodes. With this flag, an error is raised for any unknown
elements within anydata/anyxml subtrees. */
#define LYD_PARSE_OPTS_MASK 0xFFFF0000 /**< Mask for all the LYD_PARSE_ options. */

/** @} dataparseroptions */
Expand Down
6 changes: 5 additions & 1 deletion src/parser_json.c
Original file line number Diff line number Diff line change
Expand Up @@ -1310,7 +1310,11 @@ lydjson_parse_any(struct lyd_json_ctx *lydctx, const struct lysc_node *snode, st

/* parse any data tree with correct options, first backup the current options and then make the parser
* process data as opaq nodes */
lydctx->parse_opts &= ~LYD_PARSE_STRICT;
if (lydctx->parse_opts & LYD_PARSE_ANYDATA_STRICT) {
lydctx->parse_opts |= LYD_PARSE_STRICT;
} else {
lydctx->parse_opts &= ~LYD_PARSE_STRICT;
}
lydctx->parse_opts |= LYD_PARSE_OPAQ | (ext ? LYD_PARSE_ONLY : 0);
lydctx->int_opts |= LYD_INTOPT_ANY | LYD_INTOPT_WITH_SIBLINGS;
lydctx->any_schema = snode;
Expand Down
8 changes: 6 additions & 2 deletions src/parser_xml.c
Original file line number Diff line number Diff line change
Expand Up @@ -954,8 +954,12 @@ lydxml_subtree_any(struct lyd_xml_ctx *lydctx, const struct lysc_node *snode, co
r = lyxml_ctx_next(xmlctx);
LY_CHECK_ERR_GOTO(r, rc = r, cleanup);

/* update options so that generic data can be parsed */
lydctx->parse_opts &= ~LYD_PARSE_STRICT;
if (lydctx->parse_opts & LYD_PARSE_ANYDATA_STRICT) {
lydctx->parse_opts |= LYD_PARSE_STRICT;
} else {
/* update options so that generic data can be parsed */
lydctx->parse_opts &= ~LYD_PARSE_STRICT;
}
lydctx->parse_opts |= LYD_PARSE_OPAQ | (ext ? LYD_PARSE_ONLY : 0);
lydctx->int_opts |= LYD_INTOPT_ANY | LYD_INTOPT_WITH_SIBLINGS;

Expand Down
30 changes: 30 additions & 0 deletions tests/utests/data/test_parser_json.c
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,35 @@ test_anydata(void **state)
assert_null(tree);
}

static void
test_anydata_strict_validation(void **state)
{
const char *data_without_schema;
const char *data_invalid;
const char *data_valid;
struct lyd_node *tree;

// no shcema defiend for "x" in the parsing context
data_without_schema = "{\"a:any\":{\"x:element1\":{\"element2\":\"/a:some/a:path\",\"list\":[{},{\"key\":\"a\"}]}}}";

PARSER_CHECK_ERROR(data_without_schema, LYD_PARSE_ANYDATA_STRICT, LYD_VALIDATE_PRESENT, tree, LY_EVALID,
"No module named \"x\" in the context.", "/a:any", 1);

data_invalid = "{\"a:any\":{\"a:fooA\":{\"element2\":\"/a:some/a:path\",\"list\":[{},{\"key\":\"a\"}]}}}";

PARSER_CHECK_ERROR(data_invalid, LYD_PARSE_ANYDATA_STRICT, LYD_VALIDATE_PRESENT, tree, LY_EVALID,
"Node \"fooA\" not found in the \"a\" module.", "/a:any", 1);

data_valid = "{\"a:any\":{\"foo\":\"default-val\"}}";
CHECK_PARSE_LYD(data_valid, 0, LYD_VALIDATE_PRESENT, tree);
assert_non_null(tree);
tree = tree->next;
CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_STATUS_CURR | LYS_CONFIG_R | LYS_SET_CONFIG, 1, "any",
1, LYS_ANYDATA, 0, 0, NULL, 0);
CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_SIBLINGS, data_valid);
lyd_free_all(tree);
}

static void
test_anyxml(void **state)
{
Expand Down Expand Up @@ -1031,6 +1060,7 @@ main(void)
UTEST(test_leaf, setup),
UTEST(test_leaflist, setup),
UTEST(test_anydata, setup),
UTEST(test_anydata_strict_validation, setup),
UTEST(test_anyxml, setup),
UTEST(test_list, setup),
UTEST(test_container, setup),
Expand Down
56 changes: 56 additions & 0 deletions tests/utests/data/test_parser_xml.c
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,61 @@ test_anydata(void **state)
lyd_free_all(tree);
}

static void
test_anydata_strict_validation(void **state)
{
const char *data_without_schema;
const char *data_invalid;
const char *data_valid;
char *str;
struct lyd_node *tree;

// no shcema defiend for "urn:tests:no:schema" in the parsing context
data_without_schema = "<any xmlns=\"urn:tests:a\">\n"
" <x:element1 xmlns:x=\"urn:tests:no:schema\">\n"
" <x:element2>default-val</x:element2>\n"
" </x:element1>\n"
"</any>\n";

PARSER_CHECK_ERROR(data_without_schema, LYD_PARSE_ANYDATA_STRICT, LYD_VALIDATE_PRESENT, tree, LY_EVALID,
"No module with namespace \"urn:tests:no:schema\" in the context.", "/a:any", 3);

// anydata value are based on "module a" defined in the setup function and loaded into the parsing context.
// However, the value passed in the anydata subtree is not defined in "module a".
data_invalid = "<any xmlns=\"urn:tests:a\">\n"
" <element1>default-val</element1>\n"
"</any>\n";

PARSER_CHECK_ERROR(data_invalid, LYD_PARSE_ANYDATA_STRICT, LYD_VALIDATE_PRESENT, tree, LY_EVALID,
"Node \"element1\" not found in the \"a\" module.", "/a:any", 2);

// anydata value are based on "module a" defined in the setup function and loaded into the parsing context
data_valid = "<any xmlns=\"urn:tests:a\">\n"
" <foo>default-val</foo>\n"
"</any>\n";

CHECK_PARSE_LYD(data_valid, LYD_PARSE_ANYDATA_STRICT, LYD_VALIDATE_PRESENT, tree);
assert_non_null(tree);
tree = tree->next;
CHECK_LYSC_NODE(tree->schema, NULL, 0, LYS_CONFIG_R | LYS_STATUS_CURR | LYS_SET_CONFIG, 1, "any",
1, LYS_ANYDATA, 0, 0, NULL, 0);

const char *data_expected =
"<any xmlns=\"urn:tests:a\">\n"
" <foo>default-val</foo>\n"
"</any>\n";

CHECK_LYD_STRING(tree, LYD_PRINT_SIBLINGS, data_expected);

assert_int_equal(LY_SUCCESS, lyd_any_value_str(tree, &str));
lyd_free_all(tree);

assert_int_equal(LY_SUCCESS, lyd_new_path2(NULL, UTEST_LYCTX, "/a:any", str, strlen(str), LYD_ANYDATA_XML, 0, &tree, NULL));
free(str);
CHECK_LYD_STRING(tree, LYD_PRINT_SIBLINGS, data_expected);
lyd_free_all(tree);
}

static void
test_anyxml(void **state)
{
Expand Down Expand Up @@ -1042,6 +1097,7 @@ main(void)
const struct CMUnitTest tests[] = {
UTEST(test_leaf, setup),
UTEST(test_anydata, setup),
UTEST(test_anydata_strict_validation, setup),
UTEST(test_anyxml, setup),
UTEST(test_list, setup),
UTEST(test_container, setup),
Expand Down
35 changes: 21 additions & 14 deletions tools/lint/cmd_data.c
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,9 @@ cmd_data_help(void)
" is supposed to contain the source 'nc-rpc' operation of the reply.\n"
" -k, --ext-inst <name>\n"
" Name of extension instance in format:\n"
" <module-name>:<extension-name>:<argument>\n");
" <module-name>:<extension-name>:<argument>\n"
" -A, --anydata-strict\n"
" Enable strict parsing of anydata content\n");
cmd_data_help_format();
cmd_data_help_in_format();
printf(" -o OUTFILE, --output=OUTFILE\n"
Expand All @@ -161,19 +163,20 @@ cmd_data_opt(struct yl_opt *yo, const char *cmdline, char ***posv, int *posc)
int rc = 0, argc = 0;
int opt, opt_index;
struct option options[] = {
{"defaults", required_argument, NULL, 'd'},
{"present", no_argument, NULL, 'e'},
{"format", required_argument, NULL, 'f'},
{"in-format", required_argument, NULL, 'F'},
{"help", no_argument, NULL, 'h'},
{"merge", no_argument, NULL, 'm'},
{"output", required_argument, NULL, 'o'},
{"operational", required_argument, NULL, 'O'},
{"reply-rpc", required_argument, NULL, 'R'},
{"not-strict", no_argument, NULL, 'n'},
{"type", required_argument, NULL, 't'},
{"xpath", required_argument, NULL, 'x'},
{"ext-inst", required_argument, NULL, 'k'},
{"defaults", required_argument, NULL, 'd'},
{"present", no_argument, NULL, 'e'},
{"format", required_argument, NULL, 'f'},
{"in-format", required_argument, NULL, 'F'},
{"help", no_argument, NULL, 'h'},
{"merge", no_argument, NULL, 'm'},
{"output", required_argument, NULL, 'o'},
{"operational", required_argument, NULL, 'O'},
{"reply-rpc", required_argument, NULL, 'R'},
{"not-strict", no_argument, NULL, 'n'},
{"anydata-strict", no_argument , NULL, 'A'},
{"type", required_argument, NULL, 't'},
{"xpath", required_argument, NULL, 'x'},
{"ext-inst", required_argument, NULL, 'k'},
{NULL, 0, NULL, 0}
};

Expand Down Expand Up @@ -242,6 +245,10 @@ cmd_data_opt(struct yl_opt *yo, const char *cmdline, char ***posv, int *posc)
case 'n': /* --not-strict */
yo->data_parse_options &= ~LYD_PARSE_STRICT;
break;
case 'A': /* --anydata-strict */
yo->data_parse_options |= LYD_PARSE_ANYDATA_STRICT;
break;

case 't': /* --type */
if (data_type_set) {
YLMSG_E("The data type (-t) cannot be set multiple times.");
Expand Down
10 changes: 9 additions & 1 deletion tools/lint/main_ni.c
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,9 @@ help(int shortout)
" Do not require strict data parsing (silently skip unknown data),\n"
" has no effect for schemas.\n\n");

printf(" -A, --anydata-strict\n"
" Enable strict parsing of anydata content.\n\n");

printf(" -e, --present Validate only with the schema modules whose data actually\n"
" exist in the provided input data files. Takes effect only\n"
" with the 'data' or 'config' TYPEs. Used to avoid requiring\n"
Expand Down Expand Up @@ -486,6 +489,7 @@ process_args(int argc, char *argv[], struct yl_opt *yo, struct ly_ctx **ctx)
{"submodule", required_argument, NULL, 's'},
{"ext-data", required_argument, NULL, 'x'},
{"not-strict", no_argument, NULL, 'n'},
{"anydata-strict", no_argument, NULL, 'A'},
{"present", no_argument, NULL, 'e'},
{"type", required_argument, NULL, 't'},
{"default", required_argument, NULL, 'd'},
Expand All @@ -511,7 +515,7 @@ process_args(int argc, char *argv[], struct yl_opt *yo, struct ly_ctx **ctx)
yo->line_length = 0;

opterr = 0;
while ((opt = getopt_long(argc, argv, "hvVQf:I:p:DF:iP:qs:neE:t:d:lL:o:O:R:myY:XJx:G:k:", options, &opt_index)) != -1) {
while ((opt = getopt_long(argc, argv, "hvVQf:I:p:DF:iP:qs:neEA:t:d:lL:o:O:R:myY:XJx:G:k:", options, &opt_index)) != -1) {
switch (opt) {
case 'h': /* --help */
help(0);
Expand Down Expand Up @@ -604,6 +608,10 @@ process_args(int argc, char *argv[], struct yl_opt *yo, struct ly_ctx **ctx)
yo->data_parse_options &= ~LYD_PARSE_STRICT;
break;

case 'A': /* --anydata-strict */
yo->data_parse_options |= LYD_PARSE_ANYDATA_STRICT;
break;

case 'e': /* --present */
yo->data_validate_options |= LYD_VALIDATE_PRESENT;
break;
Expand Down