blob: 92ea5e188957dee9791a75ceeb124e43fd32ec98 [file] [log] [blame]
Radek Krejcie7b95092019-05-15 11:03:07 +02001/**
2 * @file parser_xml.c
3 * @author Radek Krejci <rkrejci@cesnet.cz>
4 * @brief XML data parser for libyang
5 *
6 * Copyright (c) 2019 CESNET, z.s.p.o.
7 *
8 * This source code is licensed under BSD 3-Clause License (the "License").
9 * You may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * https://opensource.org/licenses/BSD-3-Clause
13 */
14
15#include "common.h"
16
17#include <stdint.h>
18#include <stdlib.h>
19#include <string.h>
Michal Vasko9b368d32020-02-14 13:53:31 +010020#include <assert.h>
Radek Krejcie7b95092019-05-15 11:03:07 +020021
22#include "context.h"
23#include "dict.h"
24#include "log.h"
25#include "plugins_types.h"
26#include "set.h"
27#include "tree_data.h"
28#include "tree_data_internal.h"
29#include "tree_schema.h"
30#include "xml.h"
Michal Vaskocde73ac2019-11-14 16:10:27 +010031#include "validation.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020032
Michal Vasko1bf09392020-03-27 12:38:10 +010033#define LYD_INTOPT_RPC 0x01 /**< RPC/action invocation is being parsed */
34#define LYD_INTOPT_NOTIF 0x02 /**< notification is being parsed */
35
Radek Krejcie7b95092019-05-15 11:03:07 +020036/**
Michal Vaskob36053d2020-03-26 15:49:30 +010037 * @brief Internal context for XML YANG data parser.
Radek Krejcie7b95092019-05-15 11:03:07 +020038 */
39struct lyd_xml_ctx {
Michal Vaskob36053d2020-03-26 15:49:30 +010040 struct lyxml_ctx *xmlctx; /**< XML context */
Radek Krejcie7b95092019-05-15 11:03:07 +020041
Michal Vasko52927e22020-03-16 17:26:14 +010042 uint32_t options; /**< various @ref dataparseroptions. */
Michal Vasko1bf09392020-03-27 12:38:10 +010043 uint32_t int_opts; /**< internal data parser options */
Michal Vasko52927e22020-03-16 17:26:14 +010044 uint32_t path_len; /**< used bytes in the path buffer */
Radek Krejcie7b95092019-05-15 11:03:07 +020045#define LYD_PARSER_BUFSIZE 4078
46 char path[LYD_PARSER_BUFSIZE]; /**< buffer for the generated path */
Michal Vasko52927e22020-03-16 17:26:14 +010047 struct ly_set unres_node_type; /**< set of nodes validated with LY_EINCOMPLETE result */
48 struct ly_set unres_meta_type; /**< set of metadata validated with LY_EINCOMPLETE result */
Michal Vaskoecd62de2019-11-13 12:35:11 +010049 struct ly_set when_check; /**< set of nodes with "when" conditions */
Michal Vasko1bf09392020-03-27 12:38:10 +010050 struct lyd_node *op_ntf; /**< if an RPC/action/notification is being parsed, store the pointer to it */
Radek Krejcie7b95092019-05-15 11:03:07 +020051};
52
53/**
Michal Vaskob36053d2020-03-26 15:49:30 +010054 * @brief XML-parser's implementation of ly_type_resolve_prefix() callback to provide mapping between prefixes used
55 * in the values to the schema via XML namespaces.
Radek Krejciaca74032019-06-04 08:53:06 +020056 */
57static const struct lys_module *
Michal Vasko52927e22020-03-16 17:26:14 +010058lydxml_resolve_prefix(const struct ly_ctx *ctx, const char *prefix, size_t prefix_len, void *parser)
Radek Krejciaca74032019-06-04 08:53:06 +020059{
60 const struct lyxml_ns *ns;
Michal Vaskob36053d2020-03-26 15:49:30 +010061 struct lyxml_ctx *xmlctx = (struct lyxml_ctx *)parser;
Radek Krejciaca74032019-06-04 08:53:06 +020062
63 ns = lyxml_ns_get(xmlctx, prefix, prefix_len);
64 if (!ns) {
65 return NULL;
66 }
67
68 return ly_ctx_get_module_implemented_ns(ctx, ns->uri);
69}
70
Radek Krejcie7b95092019-05-15 11:03:07 +020071static LY_ERR
Michal Vaskob36053d2020-03-26 15:49:30 +010072lydxml_metadata(struct lyxml_ctx *xmlctx, const struct lysc_node *sparent, int strict, struct ly_set *type_meta_check,
73 struct lyd_meta **meta)
Radek Krejcie7b95092019-05-15 11:03:07 +020074{
Michal Vaskob36053d2020-03-26 15:49:30 +010075 LY_ERR ret = LY_EVALID;
Radek Krejci28681fa2019-09-06 13:08:45 +020076 const struct lyxml_ns *ns;
77 struct lys_module *mod;
Michal Vaskob36053d2020-03-26 15:49:30 +010078 const char *name;
79 size_t name_len;
Radek Krejci28681fa2019-09-06 13:08:45 +020080
Michal Vaskob36053d2020-03-26 15:49:30 +010081 *meta = NULL;
Radek Krejci28681fa2019-09-06 13:08:45 +020082
Michal Vaskob36053d2020-03-26 15:49:30 +010083 while (xmlctx->status == LYXML_ATTRIBUTE) {
84 if (!xmlctx->prefix_len) {
Radek Krejci28681fa2019-09-06 13:08:45 +020085 /* in XML, all attributes must be prefixed
86 * TODO exception for NETCONF filters which are supposed to map to the ietf-netconf without prefix */
Michal Vasko52927e22020-03-16 17:26:14 +010087 if (strict) {
88 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Missing mandatory prefix for XML metadata \"%.*s\".",
Michal Vaskob36053d2020-03-26 15:49:30 +010089 xmlctx->name_len, xmlctx->name);
90 goto cleanup;
Radek Krejci28681fa2019-09-06 13:08:45 +020091 }
Michal Vaskob36053d2020-03-26 15:49:30 +010092
Radek Krejci28681fa2019-09-06 13:08:45 +020093skip_attr:
Michal Vaskob36053d2020-03-26 15:49:30 +010094 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
95 assert(xmlctx->status == LYXML_ATTR_CONTENT);
96 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Radek Krejci28681fa2019-09-06 13:08:45 +020097 continue;
98 }
99
100 /* get namespace of the attribute to find its annotation definition */
Michal Vaskob36053d2020-03-26 15:49:30 +0100101 ns = lyxml_ns_get(xmlctx, xmlctx->prefix, xmlctx->prefix_len);
Radek Krejci28681fa2019-09-06 13:08:45 +0200102 if (!ns) {
Michal Vasko52927e22020-03-16 17:26:14 +0100103 /* unknown namespace, XML error */
104 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".",
Michal Vaskob36053d2020-03-26 15:49:30 +0100105 xmlctx->prefix_len, xmlctx->prefix);
Radek Krejci28681fa2019-09-06 13:08:45 +0200106 goto cleanup;
107 }
Michal Vasko52927e22020-03-16 17:26:14 +0100108 mod = ly_ctx_get_module_implemented_ns(xmlctx->ctx, ns->uri);
Radek Krejci28681fa2019-09-06 13:08:45 +0200109 if (!mod) {
110 /* module is not implemented or not present in the schema */
Michal Vasko52927e22020-03-16 17:26:14 +0100111 if (strict) {
112 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE,
Michal Vasko9f96a052020-03-10 09:41:45 +0100113 "Unknown (or not implemented) YANG module with namespace \"%s\" for metadata \"%.*s%s%.*s\".",
Michal Vaskob36053d2020-03-26 15:49:30 +0100114 ns->uri, xmlctx->prefix_len, xmlctx->prefix, xmlctx->prefix_len ? ":" : "", xmlctx->name_len,
115 xmlctx->name);
116 goto cleanup;
Radek Krejci28681fa2019-09-06 13:08:45 +0200117 }
118 goto skip_attr;
119 }
120
Michal Vaskob36053d2020-03-26 15:49:30 +0100121 /* remember attr name and get its content */
122 name = xmlctx->name;
123 name_len = xmlctx->name_len;
124 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
125 assert(xmlctx->status == LYXML_ATTR_CONTENT);
126
127 /* create metadata */
128 ret = lyd_create_meta(NULL, meta, mod, name, name_len, xmlctx->value, xmlctx->value_len, &xmlctx->dynamic,
129 lydxml_resolve_prefix, xmlctx, LYD_XML, sparent);
130 if (ret == LY_EINCOMPLETE) {
Michal Vasko52927e22020-03-16 17:26:14 +0100131 if (type_meta_check) {
132 ly_set_add(type_meta_check, meta, LY_SET_OPT_USEASLIST);
133 }
Michal Vaskob36053d2020-03-26 15:49:30 +0100134 } else if (ret) {
Radek Krejci28681fa2019-09-06 13:08:45 +0200135 goto cleanup;
136 }
Michal Vaskob36053d2020-03-26 15:49:30 +0100137
138 /* next attribute */
139 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Radek Krejcie7b95092019-05-15 11:03:07 +0200140 }
Michal Vasko52927e22020-03-16 17:26:14 +0100141
Radek Krejci28681fa2019-09-06 13:08:45 +0200142 ret = LY_SUCCESS;
Radek Krejcie7b95092019-05-15 11:03:07 +0200143
144cleanup:
Michal Vaskob36053d2020-03-26 15:49:30 +0100145 if (ret) {
146 lyd_free_meta(xmlctx->ctx, *meta, 1);
147 *meta = NULL;
Radek Krejci38d85362019-09-05 16:26:38 +0200148 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200149 return ret;
150}
151
Michal Vasko52927e22020-03-16 17:26:14 +0100152static LY_ERR
Michal Vaskob36053d2020-03-26 15:49:30 +0100153lydxml_attrs(struct lyxml_ctx *xmlctx, struct ly_attr **attr)
Michal Vasko52927e22020-03-16 17:26:14 +0100154{
155 LY_ERR ret = LY_SUCCESS;
156 const struct lyxml_ns *ns;
157 struct ly_prefix *val_prefs;
158 struct ly_attr *attr2;
Michal Vaskob36053d2020-03-26 15:49:30 +0100159 const char *name, *prefix;
160 size_t name_len, prefix_len;
Michal Vasko52927e22020-03-16 17:26:14 +0100161
162 assert(attr);
Michal Vaskob36053d2020-03-26 15:49:30 +0100163 *attr = NULL;
Michal Vasko52927e22020-03-16 17:26:14 +0100164
Michal Vaskob36053d2020-03-26 15:49:30 +0100165 while (xmlctx->status == LYXML_ATTRIBUTE) {
Michal Vasko52927e22020-03-16 17:26:14 +0100166 ns = NULL;
Michal Vaskob36053d2020-03-26 15:49:30 +0100167 if (xmlctx->prefix_len) {
Michal Vasko52927e22020-03-16 17:26:14 +0100168 /* get namespace of the attribute */
Michal Vaskob36053d2020-03-26 15:49:30 +0100169 ns = lyxml_ns_get(xmlctx, xmlctx->prefix, xmlctx->prefix_len);
Michal Vasko52927e22020-03-16 17:26:14 +0100170 if (!ns) {
171 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".",
Michal Vaskob36053d2020-03-26 15:49:30 +0100172 xmlctx->prefix_len, xmlctx->prefix);
Michal Vasko52927e22020-03-16 17:26:14 +0100173 ret = LY_EVALID;
174 goto cleanup;
175 }
176 }
177
178 if (*attr) {
179 attr2 = *attr;
180 } else {
181 attr2 = NULL;
182 }
183
Michal Vaskob36053d2020-03-26 15:49:30 +0100184 /* remember attr prefix, name, and get its content */
185 prefix = xmlctx->prefix;
186 prefix_len = xmlctx->prefix_len;
187 name = xmlctx->name;
188 name_len = xmlctx->name_len;
189 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
190 assert(xmlctx->status == LYXML_ATTR_CONTENT);
191
Michal Vasko52927e22020-03-16 17:26:14 +0100192 /* get value prefixes */
Michal Vaskob36053d2020-03-26 15:49:30 +0100193 LY_CHECK_GOTO(ret = lyxml_get_prefixes(xmlctx, xmlctx->value, xmlctx->value_len, &val_prefs), cleanup);
Michal Vasko52927e22020-03-16 17:26:14 +0100194
195 /* attr2 is always changed to the created attribute */
Michal Vaskob36053d2020-03-26 15:49:30 +0100196 ret = ly_create_attr(NULL, &attr2, xmlctx->ctx, name, name_len, xmlctx->value, xmlctx->value_len,
197 &xmlctx->dynamic, LYD_XML, val_prefs, prefix, prefix_len, ns ? ns->uri : NULL);
Michal Vasko52927e22020-03-16 17:26:14 +0100198 LY_CHECK_GOTO(ret, cleanup);
199
200 if (!*attr) {
201 *attr = attr2;
202 }
Michal Vaskob36053d2020-03-26 15:49:30 +0100203
204 /* next attribute */
205 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko52927e22020-03-16 17:26:14 +0100206 }
207
208cleanup:
Michal Vaskob36053d2020-03-26 15:49:30 +0100209 if (ret) {
210 ly_free_attr(xmlctx->ctx, *attr, 1);
211 *attr = NULL;
Michal Vasko52927e22020-03-16 17:26:14 +0100212 }
Michal Vasko52927e22020-03-16 17:26:14 +0100213 return ret;
214}
215
Michal Vasko44685da2020-03-17 15:38:06 +0100216static LY_ERR
Michal Vaskob36053d2020-03-26 15:49:30 +0100217lydxml_check_list(struct lyxml_ctx *xmlctx, const struct lysc_node *list)
Michal Vasko44685da2020-03-17 15:38:06 +0100218{
Michal Vaskob36053d2020-03-26 15:49:30 +0100219 LY_ERR ret = LY_SUCCESS, r;
220 enum LYXML_PARSER_STATUS next;
Michal Vasko44685da2020-03-17 15:38:06 +0100221 struct ly_set key_set = {0};
222 const struct lysc_node *snode;
Michal Vaskob36053d2020-03-26 15:49:30 +0100223 uint32_t i, parents_count;
Michal Vasko44685da2020-03-17 15:38:06 +0100224
225 assert(list && (list->nodetype == LYS_LIST));
226
227 /* get all keys into a set (keys do not have if-features or anything) */
228 snode = NULL;
229 while ((snode = lys_getnext(snode, list, NULL, LYS_GETNEXT_NOSTATECHECK)) && (snode->flags & LYS_KEY)) {
230 ly_set_add(&key_set, (void *)snode, LY_SET_OPT_USEASLIST);
231 }
232
Michal Vaskob36053d2020-03-26 15:49:30 +0100233 while (xmlctx->status == LYXML_ELEMENT) {
Michal Vasko44685da2020-03-17 15:38:06 +0100234 /* find key definition */
235 for (i = 0; i < key_set.count; ++i) {
236 snode = (const struct lysc_node *)key_set.objs[i];
Michal Vaskob36053d2020-03-26 15:49:30 +0100237 if (!ly_strncmp(snode->name, xmlctx->name, xmlctx->name_len)) {
Michal Vasko44685da2020-03-17 15:38:06 +0100238 break;
239 }
240 }
Michal Vaskob36053d2020-03-26 15:49:30 +0100241 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100242
243 /* skip attributes */
244 while (xmlctx->status == LYXML_ATTRIBUTE) {
Michal Vaskob36053d2020-03-26 15:49:30 +0100245 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
246 assert(xmlctx->status == LYXML_ATTR_CONTENT);
247 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100248 }
249
Michal Vaskob36053d2020-03-26 15:49:30 +0100250 assert(xmlctx->status == LYXML_ELEM_CONTENT);
251 if (i < key_set.count) {
252 /* validate the value */
253 r = lys_value_validate(NULL, snode, xmlctx->value, xmlctx->value_len, lydxml_resolve_prefix, xmlctx, LYD_XML);
254 if (!r) {
255 /* key with a valid value, remove from the set */
256 ly_set_rm_index(&key_set, i, NULL);
Michal Vasko44685da2020-03-17 15:38:06 +0100257 }
258 }
259
Michal Vaskob36053d2020-03-26 15:49:30 +0100260 /* parser next */
261 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100262
Michal Vaskob36053d2020-03-26 15:49:30 +0100263 /* skip any children, resursively */
264 parents_count = xmlctx->elements.count;
265 while ((parents_count < xmlctx->elements.count) || (xmlctx->status == LYXML_ELEMENT)) {
266 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
267 }
268
269 /* parser next, but do not parse closing element of the list because it would remove its namespaces */
270 assert(xmlctx->status == LYXML_ELEM_CLOSE);
271 LY_CHECK_GOTO(ret = lyxml_ctx_peek(xmlctx, &next), cleanup);
272 if (next != LYXML_ELEM_CLOSE) {
273 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
274 }
Michal Vasko44685da2020-03-17 15:38:06 +0100275 }
276
277 if (key_set.count) {
Michal Vaskob36053d2020-03-26 15:49:30 +0100278 /* some keys are missing/did not validate */
Michal Vasko44685da2020-03-17 15:38:06 +0100279 ret = LY_ENOT;
Michal Vasko44685da2020-03-17 15:38:06 +0100280 }
281
282cleanup:
283 ly_set_erase(&key_set, NULL);
284 return ret;
285}
286
Michal Vasko1bf09392020-03-27 12:38:10 +0100287static LY_ERR
288lydxml_data_skip(struct lyxml_ctx *xmlctx)
289{
290 uint32_t parents_count;
291
292 /* remember current number of parents */
293 parents_count = xmlctx->elements.count;
294
295 /* skip after the content */
296 while (xmlctx->status != LYXML_ELEM_CONTENT) {
297 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
298 }
299 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
300
301 /* skip all children elements, recursively, if any */
302 while (parents_count < xmlctx->elements.count) {
303 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
304 }
305
306 /* close element */
307 assert(xmlctx->status == LYXML_ELEM_CLOSE);
308 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
309
310 return LY_SUCCESS;
311}
312
313static LY_ERR
314lydxml_data_check_schema(struct lyd_xml_ctx *lydctx, const struct lysc_node **snode)
315{
316 LY_ERR ret = LY_SUCCESS;
317 enum LYXML_PARSER_STATUS prev_status;
318 const char *prev_input, *pname, *pprefix;
319 size_t pprefix_len, pname_len;
320 struct lyxml_ctx *xmlctx = lydctx->xmlctx;
321
322 if ((lydctx->options & LYD_OPT_NO_STATE) && ((*snode)->flags & LYS_CONFIG_R)) {
323 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LY_VCODE_INSTATE, (*snode)->name);
324 return LY_EVALID;
325 }
326
327 if ((*snode)->nodetype & (LYS_RPC | LYS_ACTION)) {
328 if (lydctx->int_opts & LYD_INTOPT_RPC) {
329 if (lydctx->op_ntf) {
330 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_DATA, "Unexpected %s element \"%s\", %s \"%s\" already parsed.",
331 lys_nodetype2str((*snode)->nodetype), (*snode)->name,
332 lys_nodetype2str(lydctx->op_ntf->schema->nodetype), lydctx->op_ntf->schema->name);
333 return LY_EVALID;
334 }
335 } else {
336 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_DATA, "Unexpected %s element \"%s\".",
337 lys_nodetype2str((*snode)->nodetype), (*snode)->name);
338 return LY_EVALID;
339 }
340 } else if ((*snode)->nodetype == LYS_NOTIF) {
341 if (lydctx->int_opts & LYD_INTOPT_NOTIF) {
342 if (lydctx->op_ntf) {
343 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_DATA, "Unexpected %s element \"%s\", %s \"%s\" already parsed.",
344 lys_nodetype2str((*snode)->nodetype), (*snode)->name,
345 lys_nodetype2str(lydctx->op_ntf->schema->nodetype), lydctx->op_ntf->schema->name);
346 return LY_EVALID;
347 }
348 } else {
349 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_DATA, "Unexpected %s element \"%s\".",
350 lys_nodetype2str((*snode)->nodetype), (*snode)->name);
351 return LY_EVALID;
352 }
353 }
354
355 if ((lydctx->options & LYD_OPT_OPAQ) && ((*snode)->nodetype & (LYD_NODE_TERM | LYS_LIST))) {
356 /* backup parser */
357 prev_status = xmlctx->status;
358 pprefix = xmlctx->prefix;
359 pprefix_len = xmlctx->prefix_len;
360 pname = xmlctx->name;
361 pname_len = xmlctx->name_len;
362 prev_input = xmlctx->input;
363 if ((xmlctx->status == LYXML_ELEM_CONTENT) && xmlctx->dynamic) {
364 /* it was backed up, do not free */
365 xmlctx->dynamic = 0;
366 }
367
368 /* skip attributes */
369 while (xmlctx->status == LYXML_ATTRIBUTE) {
370 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), restore);
371 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), restore);
372 }
373
374 if ((*snode)->nodetype & LYD_NODE_TERM) {
375 /* value may not be valid in which case we parse it as an opaque node */
376 if (lys_value_validate(NULL, *snode, xmlctx->value, xmlctx->value_len, lydxml_resolve_prefix, xmlctx, LYD_XML)) {
377 *snode = NULL;
378 }
379 } else {
380 /* skip content */
381 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), restore);
382
383 if (lydxml_check_list(xmlctx, *snode)) {
384 /* invalid list, parse as opaque if it missing/has invalid some keys */
385 *snode = NULL;
386 }
387 }
388
389restore:
390 /* restore parser */
391 if (xmlctx->dynamic) {
392 free((char *)xmlctx->value);
393 }
394 xmlctx->status = prev_status;
395 xmlctx->prefix = pprefix;
396 xmlctx->prefix_len = pprefix_len;
397 xmlctx->name = pname;
398 xmlctx->name_len = pname_len;
399 xmlctx->input = prev_input;
400 }
401
402 return ret;
403}
404
405static void
406lydxml_data_flags(struct lyd_xml_ctx *lydctx, struct lyd_node *node, struct lyd_meta **meta)
407{
408 struct lyd_meta *meta2, *prev_meta = NULL;
409
410 if (!(node->schema->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) && node->schema->when) {
411 if (lydctx->options & LYD_OPT_TRUSTED) {
412 /* just set it to true */
413 node->flags |= LYD_WHEN_TRUE;
414 } else {
415 /* remember we need to evaluate this node's when */
416 ly_set_add(&lydctx->when_check, node, LY_SET_OPT_USEASLIST);
417 }
418 }
419
420 if (lydctx->options & LYD_OPT_TRUSTED) {
421 /* node is valid */
422 node->flags &= ~LYD_NEW;
423 }
424
425 LY_LIST_FOR(*meta, meta2) {
426 if (!strcmp(meta2->name, "default") && !strcmp(meta2->annotation->module->name, "ietf-netconf-with-defaults")
427 && meta2->value.boolean) {
428 /* node is default according to the metadata */
429 node->flags |= LYD_DEFAULT;
430
431 /* delete the metadata */
432 if (prev_meta) {
433 prev_meta->next = meta2->next;
434 } else {
435 *meta = (*meta)->next;
436 }
437 lyd_free_meta(lydctx->xmlctx->ctx, meta2, 0);
438 break;
439 }
440
441 prev_meta = meta2;
442 }
443}
444
Radek Krejcie7b95092019-05-15 11:03:07 +0200445/**
Michal Vasko9f96a052020-03-10 09:41:45 +0100446 * @brief Parse XML elements as YANG data node children the specified parent node.
Radek Krejcie7b95092019-05-15 11:03:07 +0200447 *
Michal Vaskob36053d2020-03-26 15:49:30 +0100448 * @param[in] lydctx XML YANG data parser context.
Radek Krejcie7b95092019-05-15 11:03:07 +0200449 * @param[in] parent Parent node where the children are inserted. NULL in case of parsing top-level elements.
Radek Krejcie7b95092019-05-15 11:03:07 +0200450 * @param[out] node Resulting list of the parsed nodes.
Michal Vasko9b368d32020-02-14 13:53:31 +0100451 * @return LY_ERR value.
Radek Krejcie7b95092019-05-15 11:03:07 +0200452 */
453static LY_ERR
Michal Vasko1bf09392020-03-27 12:38:10 +0100454lydxml_data_r(struct lyd_xml_ctx *lydctx, struct lyd_node_inner *parent, struct lyd_node **first)
Radek Krejcie7b95092019-05-15 11:03:07 +0200455{
Michal Vaskob36053d2020-03-26 15:49:30 +0100456 LY_ERR ret = LY_SUCCESS;
Michal Vasko1bf09392020-03-27 12:38:10 +0100457 const char *prefix, *name;
458 size_t prefix_len, name_len;
Michal Vaskob36053d2020-03-26 15:49:30 +0100459 struct lyxml_ctx *xmlctx;
460 const struct ly_ctx *ctx;
Radek Krejcie7b95092019-05-15 11:03:07 +0200461 const struct lyxml_ns *ns;
Michal Vasko1bf09392020-03-27 12:38:10 +0100462 struct lyd_meta *meta = NULL;
Michal Vasko52927e22020-03-16 17:26:14 +0100463 struct ly_attr *attr = NULL;
Radek Krejcie7b95092019-05-15 11:03:07 +0200464 const struct lysc_node *snode;
465 struct lys_module *mod;
Michal Vasko1bf09392020-03-27 12:38:10 +0100466 uint32_t prev_opts;
Michal Vasko52927e22020-03-16 17:26:14 +0100467 struct lyd_node *cur = NULL, *anchor;
468 struct ly_prefix *val_prefs;
Radek Krejcie7b95092019-05-15 11:03:07 +0200469
Michal Vaskob36053d2020-03-26 15:49:30 +0100470 xmlctx = lydctx->xmlctx;
471 ctx = xmlctx->ctx;
Michal Vasko6f4cbb62020-02-28 11:15:47 +0100472
Michal Vaskob36053d2020-03-26 15:49:30 +0100473 while (xmlctx->status == LYXML_ELEMENT) {
474 /* remember element prefix and name */
475 prefix = xmlctx->prefix;
476 prefix_len = xmlctx->prefix_len;
477 name = xmlctx->name;
478 name_len = xmlctx->name_len;
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200479
Michal Vaskob36053d2020-03-26 15:49:30 +0100480 /* get the element module */
481 ns = lyxml_ns_get(xmlctx, prefix, prefix_len);
Radek Krejcie7b95092019-05-15 11:03:07 +0200482 if (!ns) {
Michal Vaskob36053d2020-03-26 15:49:30 +0100483 LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".",
484 prefix_len, prefix);
Michal Vasko90932a92020-02-12 14:33:03 +0100485 ret = LY_EVALID;
486 goto cleanup;
Radek Krejcie7b95092019-05-15 11:03:07 +0200487 }
Michal Vaskob36053d2020-03-26 15:49:30 +0100488 mod = ly_ctx_get_module_implemented_ns(ctx, ns->uri);
489 if (!mod && (lydctx->options & LYD_OPT_STRICT)) {
490 LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "No module with namespace \"%s\" in the context.", ns->uri);
Michal Vasko90932a92020-02-12 14:33:03 +0100491 ret = LY_EVALID;
492 goto cleanup;
Radek Krejcie7b95092019-05-15 11:03:07 +0200493 }
Michal Vasko52927e22020-03-16 17:26:14 +0100494
Michal Vasko1bf09392020-03-27 12:38:10 +0100495 /* parser next */
496 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
497
Michal Vaskob36053d2020-03-26 15:49:30 +0100498 /* get the schema node */
Michal Vasko52927e22020-03-16 17:26:14 +0100499 snode = NULL;
500 if (mod && (!parent || parent->schema)) {
501 /* leave if-feature check for validation */
502 snode = lys_find_child(parent ? parent->schema : NULL, mod, name, name_len, 0, LYS_GETNEXT_NOSTATECHECK);
Michal Vaskob36053d2020-03-26 15:49:30 +0100503 if (!snode) {
504 if (lydctx->options & LYD_OPT_STRICT) {
505 LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Element \"%.*s\" not found in the \"%s\" module.",
506 name_len, name, mod->name);
507 ret = LY_EVALID;
508 goto cleanup;
509 } else if (!(lydctx->options & LYD_OPT_OPAQ)) {
Michal Vasko1bf09392020-03-27 12:38:10 +0100510 /* skip element with children */
511 LY_CHECK_GOTO(ret = lydxml_data_skip(xmlctx), cleanup);
Michal Vaskob36053d2020-03-26 15:49:30 +0100512 continue;
513 }
Michal Vaskob36053d2020-03-26 15:49:30 +0100514 } else {
Michal Vasko1bf09392020-03-27 12:38:10 +0100515 /* check that schema node is valid and can be used */
516 LY_CHECK_GOTO(ret = lydxml_data_check_schema(lydctx, &snode), cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100517 }
518 }
519
Michal Vaskob36053d2020-03-26 15:49:30 +0100520 /* create metadata/attributes */
521 if (xmlctx->status == LYXML_ATTRIBUTE) {
Michal Vasko52927e22020-03-16 17:26:14 +0100522 if (snode) {
Michal Vaskob36053d2020-03-26 15:49:30 +0100523 ret = lydxml_metadata(xmlctx, snode, lydctx->options & LYD_OPT_STRICT, &lydctx->unres_meta_type, &meta);
Michal Vasko52927e22020-03-16 17:26:14 +0100524 LY_CHECK_GOTO(ret, cleanup);
525 } else {
Michal Vaskob36053d2020-03-26 15:49:30 +0100526 assert(lydctx->options & LYD_OPT_OPAQ);
527 ret = lydxml_attrs(xmlctx, &attr);
528 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko52927e22020-03-16 17:26:14 +0100529 }
Michal Vasko8d544252020-03-02 10:19:52 +0100530 }
531
Michal Vaskob36053d2020-03-26 15:49:30 +0100532 assert(xmlctx->status == LYXML_ELEM_CONTENT);
Michal Vasko52927e22020-03-16 17:26:14 +0100533 if (!snode) {
Michal Vaskob36053d2020-03-26 15:49:30 +0100534 assert(lydctx->options & LYD_OPT_OPAQ);
Michal Vasko52927e22020-03-16 17:26:14 +0100535
Michal Vaskob36053d2020-03-26 15:49:30 +0100536 if (xmlctx->ws_only) {
537 /* ignore WS-only value */
538 xmlctx->value_len = 0;
539 val_prefs = NULL;
Michal Vasko52927e22020-03-16 17:26:14 +0100540 } else {
Michal Vaskob36053d2020-03-26 15:49:30 +0100541 /* get value prefixes */
542 ret = lyxml_get_prefixes(xmlctx, xmlctx->value, xmlctx->value_len, &val_prefs);
Michal Vasko52927e22020-03-16 17:26:14 +0100543 LY_CHECK_GOTO(ret, cleanup);
Radek Krejcie7b95092019-05-15 11:03:07 +0200544 }
Michal Vasko90932a92020-02-12 14:33:03 +0100545
546 /* create node */
Michal Vaskob36053d2020-03-26 15:49:30 +0100547 ret = lyd_create_opaq(ctx, name, name_len, xmlctx->value, xmlctx->value_len, &xmlctx->dynamic, LYD_XML,
548 val_prefs, prefix, prefix_len, ns->uri, &cur);
549 LY_CHECK_GOTO(ret, cleanup);
550
551 /* parser next */
552 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
553
554 /* process children */
555 if (xmlctx->status == LYXML_ELEMENT) {
Michal Vasko1bf09392020-03-27 12:38:10 +0100556 ret = lydxml_data_r(lydctx, (struct lyd_node_inner *)cur, lyd_node_children_p(cur));
Michal Vaskob36053d2020-03-26 15:49:30 +0100557 LY_CHECK_GOTO(ret, cleanup);
558 }
559 } else if (snode->nodetype & LYD_NODE_TERM) {
560 /* create node */
561 ret = lyd_create_term(snode, xmlctx->value, xmlctx->value_len, &xmlctx->dynamic, lydxml_resolve_prefix,
562 xmlctx, LYD_XML, &cur);
Radek Krejcie553e6d2019-06-07 15:33:18 +0200563 if (ret == LY_EINCOMPLETE) {
Michal Vaskob36053d2020-03-26 15:49:30 +0100564 if (!(lydctx->options & LYD_OPT_PARSE_ONLY)) {
565 ly_set_add(&lydctx->unres_node_type, cur, LY_SET_OPT_USEASLIST);
Michal Vasko9b368d32020-02-14 13:53:31 +0100566 }
Radek Krejcie553e6d2019-06-07 15:33:18 +0200567 } else if (ret) {
Radek Krejcie553e6d2019-06-07 15:33:18 +0200568 goto cleanup;
569 }
Michal Vasko9b368d32020-02-14 13:53:31 +0100570
571 if (parent && (cur->schema->flags & LYS_KEY)) {
572 /* check the key order, the anchor must always be the last child */
Michal Vasko52927e22020-03-16 17:26:14 +0100573 anchor = lyd_get_prev_key_anchor(parent->child, cur->schema);
574 if ((!anchor && parent->child) || (anchor && anchor->next)) {
Michal Vaskob36053d2020-03-26 15:49:30 +0100575 if (lydctx->options & LYD_OPT_STRICT) {
576 LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_DATA, "Invalid position of the key \"%s\" in a list.",
Michal Vasko9b368d32020-02-14 13:53:31 +0100577 cur->schema->name);
578 ret = LY_EVALID;
579 goto cleanup;
580 } else {
Michal Vaskob36053d2020-03-26 15:49:30 +0100581 LOGWRN(ctx, "Invalid position of the key \"%s\" in a list.", cur->schema->name);
Michal Vasko9b368d32020-02-14 13:53:31 +0100582 }
583 }
584 }
Michal Vaskob36053d2020-03-26 15:49:30 +0100585
586 /* parser next */
587 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
588
589 /* no children expected */
590 if (xmlctx->status == LYXML_ELEMENT) {
Michal Vasko1bf09392020-03-27 12:38:10 +0100591 LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_SYNTAX, "Child element \"%.*s\" inside a terminal node \"%s\" found.",
592 xmlctx->name_len, xmlctx->name, snode->name);
Michal Vasko44685da2020-03-17 15:38:06 +0100593 ret = LY_EVALID;
594 goto cleanup;
Michal Vaskob36053d2020-03-26 15:49:30 +0100595 }
596 } else if (snode->nodetype & LYD_NODE_INNER) {
597 if (!xmlctx->ws_only) {
598 /* value in inner node */
Michal Vasko1bf09392020-03-27 12:38:10 +0100599 LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_SYNTAX, "Text value \"%.*s\" inside an inner node \"%s\" found.",
600 xmlctx->value_len, xmlctx->value, snode->name);
Michal Vaskob36053d2020-03-26 15:49:30 +0100601 ret = LY_EVALID;
602 goto cleanup;
Radek Krejcie7b95092019-05-15 11:03:07 +0200603 }
Michal Vasko90932a92020-02-12 14:33:03 +0100604
605 /* create node */
606 ret = lyd_create_inner(snode, &cur);
607 LY_CHECK_GOTO(ret, cleanup);
608
Michal Vaskob36053d2020-03-26 15:49:30 +0100609 /* parser next */
610 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
611
Radek Krejciee4cab22019-07-17 17:07:47 +0200612 /* process children */
Michal Vaskob36053d2020-03-26 15:49:30 +0100613 if (xmlctx->status == LYXML_ELEMENT) {
Michal Vasko1bf09392020-03-27 12:38:10 +0100614 ret = lydxml_data_r(lydctx, (struct lyd_node_inner *)cur, lyd_node_children_p(cur));
Michal Vasko9f96a052020-03-10 09:41:45 +0100615 LY_CHECK_GOTO(ret, cleanup);
616 }
617
618 if (snode->nodetype == LYS_LIST) {
619 /* check all keys exist */
Michal Vasko44685da2020-03-17 15:38:06 +0100620 LY_CHECK_GOTO(ret = lyd_parse_check_keys(cur), cleanup);
Radek Krejcie7b95092019-05-15 11:03:07 +0200621 }
Michal Vasko9b368d32020-02-14 13:53:31 +0100622
Michal Vaskob36053d2020-03-26 15:49:30 +0100623 if (!(lydctx->options & LYD_OPT_PARSE_ONLY)) {
Michal Vaskob1b5c262020-03-05 14:29:47 +0100624 /* new node validation, autodelete CANNOT occur, all nodes are new */
625 ret = lyd_validate_new(lyd_node_children_p(cur), snode, NULL);
626 LY_CHECK_GOTO(ret, cleanup);
627
Michal Vasko9b368d32020-02-14 13:53:31 +0100628 /* add any missing default children */
Michal Vaskob1b5c262020-03-05 14:29:47 +0100629 ret = lyd_validate_defaults_r((struct lyd_node_inner *)cur, lyd_node_children_p(cur), NULL, NULL,
Michal Vaskob36053d2020-03-26 15:49:30 +0100630 &lydctx->unres_node_type, &lydctx->when_check, lydctx->options);
Michal Vasko9b368d32020-02-14 13:53:31 +0100631 LY_CHECK_GOTO(ret, cleanup);
632 }
633
Michal Vasko9b368d32020-02-14 13:53:31 +0100634 if (snode->nodetype == LYS_LIST) {
Michal Vasko1bf09392020-03-27 12:38:10 +0100635 /* hash now that all keys should be parsed, rehash for key-less list */
Michal Vasko9b368d32020-02-14 13:53:31 +0100636 lyd_hash(cur);
Michal Vasko1bf09392020-03-27 12:38:10 +0100637 } else if (snode->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) {
638 /* rememeber the RPC/action/notification */
639 lydctx->op_ntf = cur;
Michal Vasko9b368d32020-02-14 13:53:31 +0100640 }
Radek Krejciee4cab22019-07-17 17:07:47 +0200641 } else if (snode->nodetype & LYD_NODE_ANY) {
Michal Vaskob36053d2020-03-26 15:49:30 +0100642 if (!xmlctx->ws_only) {
643 /* value in inner node */
Michal Vasko1bf09392020-03-27 12:38:10 +0100644 LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_SYNTAX, "Text value \"%.*s\" inside an any node \"%s\" found.",
645 xmlctx->value_len, xmlctx->value, snode->name);
Michal Vaskob36053d2020-03-26 15:49:30 +0100646 ret = LY_EVALID;
647 goto cleanup;
Radek Krejciee4cab22019-07-17 17:07:47 +0200648 }
Michal Vasko90932a92020-02-12 14:33:03 +0100649
Michal Vaskob36053d2020-03-26 15:49:30 +0100650 /* parser next */
651 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
652
Michal Vasko52927e22020-03-16 17:26:14 +0100653 /* parse any data tree with correct options */
Michal Vaskob36053d2020-03-26 15:49:30 +0100654 prev_opts = lydctx->options;
655 lydctx->options &= ~LYD_OPT_STRICT;
656 lydctx->options |= LYD_OPT_OPAQ;
Michal Vasko52927e22020-03-16 17:26:14 +0100657 anchor = NULL;
Michal Vasko1bf09392020-03-27 12:38:10 +0100658 ret = lydxml_data_r(lydctx, NULL, &anchor);
Michal Vaskob36053d2020-03-26 15:49:30 +0100659 lydctx->options = prev_opts;
Michal Vasko52927e22020-03-16 17:26:14 +0100660 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko90932a92020-02-12 14:33:03 +0100661
662 /* create node */
Michal Vasko52927e22020-03-16 17:26:14 +0100663 ret = lyd_create_any(snode, anchor, LYD_ANYDATA_DATATREE, &cur);
664 LY_CHECK_GOTO(ret, cleanup);
Radek Krejcie7b95092019-05-15 11:03:07 +0200665 }
Michal Vasko1bf09392020-03-27 12:38:10 +0100666 assert(cur);
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200667
Michal Vasko1bf09392020-03-27 12:38:10 +0100668 /* add/correct flags */
Michal Vasko52927e22020-03-16 17:26:14 +0100669 if (snode) {
Michal Vasko1bf09392020-03-27 12:38:10 +0100670 lydxml_data_flags(lydctx, cur, &meta);
Michal Vasko8d544252020-03-02 10:19:52 +0100671 }
672
Michal Vasko52927e22020-03-16 17:26:14 +0100673 /* add metadata/attributes */
674 if (snode) {
675 cur->meta = meta;
676 meta = NULL;
677 } else {
678 assert(!cur->schema);
679 ((struct lyd_node_opaq *)cur)->attr = attr;
680 attr = NULL;
681 }
Radek Krejcib6f7ae52019-07-19 10:31:42 +0200682
Michal Vasko90932a92020-02-12 14:33:03 +0100683 /* insert */
Michal Vaskob1b5c262020-03-05 14:29:47 +0100684 lyd_insert_node((struct lyd_node *)parent, first, cur);
Michal Vasko90932a92020-02-12 14:33:03 +0100685 cur = NULL;
Michal Vaskob36053d2020-03-26 15:49:30 +0100686
687 /* parser next */
688 assert(xmlctx->status == LYXML_ELEM_CLOSE);
689 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Radek Krejcie7b95092019-05-15 11:03:07 +0200690 }
691
Michal Vasko90932a92020-02-12 14:33:03 +0100692 /* success */
693 ret = LY_SUCCESS;
694
Radek Krejcie7b95092019-05-15 11:03:07 +0200695cleanup:
Michal Vaskob36053d2020-03-26 15:49:30 +0100696 lyd_free_meta(ctx, meta, 1);
697 ly_free_attr(ctx, attr, 1);
Michal Vasko90932a92020-02-12 14:33:03 +0100698 lyd_free_tree(cur);
Michal Vaskob1b5c262020-03-05 14:29:47 +0100699 if (ret && *first) {
700 lyd_free_siblings(*first);
701 *first = NULL;
Michal Vasko90932a92020-02-12 14:33:03 +0100702 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200703 return ret;
704}
705
706LY_ERR
Michal Vasko1bf09392020-03-27 12:38:10 +0100707lyd_parse_xml_data(const struct ly_ctx *ctx, const char *data, int options, struct lyd_node **tree)
Radek Krejcie7b95092019-05-15 11:03:07 +0200708{
Radek Krejci18a57d92019-07-25 14:01:42 +0200709 LY_ERR ret = LY_SUCCESS;
Michal Vaskob36053d2020-03-26 15:49:30 +0100710 struct lyd_xml_ctx lydctx = {0};
Michal Vaskob1b5c262020-03-05 14:29:47 +0100711 uint32_t i = 0;
712 const struct lys_module *mod;
713 struct lyd_node *first, *next, **first2;
Radek Krejcie7b95092019-05-15 11:03:07 +0200714
Michal Vaskob36053d2020-03-26 15:49:30 +0100715 /* init context and tree */
716 LY_CHECK_GOTO(ret = lyxml_ctx_new(ctx, data, &lydctx.xmlctx), cleanup);
717 lydctx.options = options;
Michal Vaskob1b5c262020-03-05 14:29:47 +0100718 *tree = NULL;
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200719
Michal Vaskob1b5c262020-03-05 14:29:47 +0100720 /* parse XML data */
Michal Vasko1bf09392020-03-27 12:38:10 +0100721 LY_CHECK_GOTO(ret = lydxml_data_r(&lydctx, NULL, tree), cleanup);
Michal Vaskocde73ac2019-11-14 16:10:27 +0100722
Michal Vasko9b368d32020-02-14 13:53:31 +0100723 if (!(options & LYD_OPT_PARSE_ONLY)) {
Michal Vaskob1b5c262020-03-05 14:29:47 +0100724 next = *tree;
725 while (1) {
726 if (options & LYD_VALOPT_DATA_ONLY) {
727 mod = lyd_data_next_module(&next, &first);
728 } else {
729 mod = lyd_mod_next_module(next, NULL, 0, ctx, &i, &first);
730 }
731 if (!mod) {
732 break;
733 }
734 if (first == *tree) {
735 /* make sure first2 changes are carried to tree */
736 first2 = tree;
737 } else {
738 first2 = &first;
739 }
Michal Vasko9b368d32020-02-14 13:53:31 +0100740
Michal Vaskob1b5c262020-03-05 14:29:47 +0100741 /* validate new top-level nodes, autodelete CANNOT occur, all nodes are new */
Michal Vasko1bf09392020-03-27 12:38:10 +0100742 LY_CHECK_GOTO(ret = lyd_validate_new(first2, NULL, mod), cleanup);
Michal Vasko9b368d32020-02-14 13:53:31 +0100743
Michal Vaskob1b5c262020-03-05 14:29:47 +0100744 /* add all top-level defaults for this module */
Michal Vaskob36053d2020-03-26 15:49:30 +0100745 ret = lyd_validate_defaults_r(NULL, first2, NULL, mod, &lydctx.unres_node_type, &lydctx.when_check,
Michal Vasko52927e22020-03-16 17:26:14 +0100746 options & LYD_VALOPT_MASK);
Michal Vaskob1b5c262020-03-05 14:29:47 +0100747 LY_CHECK_GOTO(ret, cleanup);
748
749 /* finish incompletely validated terminal values/attributes and when conditions */
Michal Vaskob36053d2020-03-26 15:49:30 +0100750 ret = lyd_validate_unres(tree, &lydctx.when_check, &lydctx.unres_node_type, &lydctx.unres_meta_type, LYD_XML,
751 lydxml_resolve_prefix, lydctx.xmlctx);
Michal Vaskob1b5c262020-03-05 14:29:47 +0100752 LY_CHECK_GOTO(ret, cleanup);
753
754 /* perform final validation that assumes the data tree is final */
Michal Vaskofea12c62020-03-30 11:00:15 +0200755 LY_CHECK_GOTO(ret = lyd_validate_final_r(*first2, NULL, mod, options & LYD_VALOPT_MASK), cleanup);
Michal Vaskob1b5c262020-03-05 14:29:47 +0100756 }
Michal Vaskocde73ac2019-11-14 16:10:27 +0100757 }
758
Michal Vaskocde73ac2019-11-14 16:10:27 +0100759cleanup:
Michal Vasko9b368d32020-02-14 13:53:31 +0100760 /* there should be no unresolved types stored */
Michal Vaskob36053d2020-03-26 15:49:30 +0100761 assert(!(options & LYD_OPT_PARSE_ONLY) || (!lydctx.unres_node_type.count && !lydctx.unres_meta_type.count
762 && !lydctx.when_check.count));
Michal Vasko9b368d32020-02-14 13:53:31 +0100763
Michal Vaskob36053d2020-03-26 15:49:30 +0100764 ly_set_erase(&lydctx.unres_node_type, NULL);
765 ly_set_erase(&lydctx.unres_meta_type, NULL);
766 ly_set_erase(&lydctx.when_check, NULL);
767 lyxml_ctx_free(lydctx.xmlctx);
Michal Vasko9f96a052020-03-10 09:41:45 +0100768 if (ret) {
769 lyd_free_all(*tree);
770 *tree = NULL;
771 }
772 return ret;
773}
Michal Vasko1bf09392020-03-27 12:38:10 +0100774
775static LY_ERR
776lydxml_envelope(struct lyxml_ctx *xmlctx, const char *name, const char *uri, struct lyd_node **envp)
777{
778 LY_ERR ret = LY_SUCCESS;
779 const struct lyxml_ns *ns = NULL;
780 struct ly_attr *attr = NULL;
781 const char *prefix;
782 size_t prefix_len;
783
784 *envp = NULL;
785
786 assert(xmlctx->status == LYXML_ELEMENT);
787 if (ly_strncmp(name, xmlctx->name, xmlctx->name_len)) {
788 /* not the expected element */
789 return LY_SUCCESS;
790 }
791
792 prefix = xmlctx->prefix;
793 prefix_len = xmlctx->prefix_len;
794 ns = lyxml_ns_get(xmlctx, prefix, prefix_len);
795 if (!ns) {
796 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".",
797 prefix_len, prefix);
798 return LY_EVALID;
799 } else if (strcmp(ns->uri, uri)) {
800 /* different namespace */
801 return LY_SUCCESS;
802 }
803
804 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
805
806 /* create attributes */
807 if (xmlctx->status == LYXML_ATTRIBUTE) {
808 LY_CHECK_RET(lydxml_attrs(xmlctx, &attr));
809 }
810
811 if (!xmlctx->ws_only) {
812 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_SYNTAX, "Unexpected value \"%.*s\" in the \"%s\" element.",
813 xmlctx->value_len, xmlctx->value, name);
814 ret = LY_EVALID;
815 goto cleanup;
816 }
817
818 /* parser next element */
819 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
820
821 /* create node */
822 ret = lyd_create_opaq(xmlctx->ctx, name, strlen(name), "", 0, NULL, LYD_XML, NULL, prefix, prefix_len, uri, envp);
823 LY_CHECK_GOTO(ret, cleanup);
824
825 /* assign atributes */
826 ((struct lyd_node_opaq *)(*envp))->attr = attr;
827 attr = NULL;
828
829cleanup:
830 ly_free_attr(xmlctx->ctx, attr, 1);
831 return ret;
832}
833
834LY_ERR
835lyd_parse_xml_rpc(const struct ly_ctx *ctx, const char *data, struct lyd_node **tree, struct lyd_node **op)
836{
837 LY_ERR ret = LY_SUCCESS;
838 struct lyd_xml_ctx lydctx = {0};
839 struct lyd_node *rpc_e = NULL, *act_e = NULL;
840
841 /* init */
842 LY_CHECK_GOTO(ret = lyxml_ctx_new(ctx, data, &lydctx.xmlctx), cleanup);
843 lydctx.options = LYD_OPT_PARSE_ONLY | LYD_OPT_STRICT;
844 lydctx.int_opts = LYD_INTOPT_RPC;
845 *tree = NULL;
Michal Vaskocc048b22020-03-27 15:52:38 +0100846 if (op) {
847 *op = NULL;
848 }
Michal Vasko1bf09392020-03-27 12:38:10 +0100849
850 /* parse "rpc", if any */
851 LY_CHECK_GOTO(ret = lydxml_envelope(lydctx.xmlctx, "rpc", "urn:ietf:params:xml:ns:netconf:base:1.0", &rpc_e), cleanup);
852
853 if (rpc_e) {
854 /* parse "action", if any */
855 LY_CHECK_GOTO(ret = lydxml_envelope(lydctx.xmlctx, "action", "urn:ietf:params:xml:ns:yang:1", &act_e), cleanup);
856 }
857
858 /* parse the rest of data normally */
859 LY_CHECK_GOTO(ret = lydxml_data_r(&lydctx, NULL, tree), cleanup);
860
861 /* make sure we have parsed some operation */
862 if (!lydctx.op_ntf) {
863 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_DATA, "Missing the \"rpc\"/\"action\" node.");
864 ret = LY_EVALID;
865 goto cleanup;
866 }
867
868 /* finish XML parsing and check operation type */
869 if (act_e) {
870 if (lydctx.xmlctx->status != LYXML_ELEM_CLOSE) {
871 assert(lydctx.xmlctx->status == LYXML_ELEMENT);
872 LOGVAL(ctx, LY_VLOG_LINE, &lydctx.xmlctx->line, LYVE_SYNTAX, "Unexpected sibling element \"%.*s\" of \"action\".",
873 lydctx.xmlctx->name_len, lydctx.xmlctx->name);
874 ret = LY_EVALID;
875 goto cleanup;
876 } else if (lydctx.op_ntf->schema->nodetype != LYS_ACTION) {
877 LOGVAL(ctx, LY_VLOG_LYD, lydctx.op_ntf, LYVE_DATA, "Unexpected %s element, an \"action\" expected.",
878 lys_nodetype2str(lydctx.op_ntf->schema->nodetype));
879 ret = LY_EVALID;
880 goto cleanup;
881 }
882 LY_CHECK_GOTO(ret = lyxml_ctx_next(lydctx.xmlctx), cleanup);
883 }
884 if (rpc_e) {
885 if (lydctx.xmlctx->status != LYXML_ELEM_CLOSE) {
886 assert(lydctx.xmlctx->status == LYXML_ELEMENT);
887 LOGVAL(ctx, LY_VLOG_LINE, &lydctx.xmlctx->line, LYVE_SYNTAX, "Unexpected sibling element \"%.*s\" of \"rpc\".",
888 lydctx.xmlctx->name_len, lydctx.xmlctx->name);
889 ret = LY_EVALID;
890 goto cleanup;
891 } else if (!act_e && (lydctx.op_ntf->schema->nodetype != LYS_RPC)) {
892 LOGVAL(ctx, LY_VLOG_LYD, lydctx.op_ntf, LYVE_DATA, "Unexpected %s element, an \"rpc\" expected.",
893 lys_nodetype2str(lydctx.op_ntf->schema->nodetype));
894 ret = LY_EVALID;
895 goto cleanup;
896 }
897 LY_CHECK_GOTO(ret = lyxml_ctx_next(lydctx.xmlctx), cleanup);
898 }
899
Michal Vaskocc048b22020-03-27 15:52:38 +0100900 if (op) {
901 *op = lydctx.op_ntf;
902 }
Michal Vasko1bf09392020-03-27 12:38:10 +0100903 assert(*tree);
904 if (act_e) {
905 /* connect to the action */
906 lyd_insert_node(act_e, NULL, *tree);
907 *tree = act_e;
908 }
909 if (rpc_e) {
910 /* connect to the rpc */
911 lyd_insert_node(rpc_e, NULL, *tree);
912 *tree = rpc_e;
913 }
914
915cleanup:
916 /* we have used parse_only flag */
917 assert(!lydctx.unres_node_type.count && !lydctx.unres_meta_type.count && !lydctx.when_check.count);
918 lyxml_ctx_free(lydctx.xmlctx);
919 if (ret) {
920 lyd_free_all(*tree);
921 lyd_free_tree(act_e);
922 lyd_free_tree(rpc_e);
923 *tree = NULL;
Michal Vasko1bf09392020-03-27 12:38:10 +0100924 }
925 return ret;
926}
Michal Vaskoa8edff02020-03-27 14:47:01 +0100927
928static LY_ERR
929lydxml_notif_envelope(struct lyxml_ctx *xmlctx, struct lyd_node **envp)
930{
931 LY_ERR ret = LY_SUCCESS;
932 const struct lyxml_ns *ns = NULL;
933 struct ly_attr *attr = NULL;
934 struct lyd_node *et;
935 const char *prefix;
936 size_t prefix_len;
937
938 *envp = NULL;
939
940 /* container envelope */
941 LY_CHECK_GOTO(ret = lydxml_envelope(xmlctx, "notification", "urn:ietf:params:xml:ns:netconf:notification:1.0",
942 envp), cleanup);
943
944 /* no envelope, fine */
945 if (!*envp) {
946 goto cleanup;
947 }
948
949 /* child "eventTime" */
950 if ((xmlctx->status != LYXML_ELEMENT) || ly_strncmp("eventTime", xmlctx->name, xmlctx->name_len)) {
951 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Missing the \"eventTime\" element.");
952 ret = LY_EVALID;
953 goto cleanup;
954 }
955
956 prefix = xmlctx->prefix;
957 prefix_len = xmlctx->prefix_len;
958 ns = lyxml_ns_get(xmlctx, prefix, prefix_len);
959 if (!ns) {
960 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".",
961 prefix_len, prefix);
962 ret = LY_EVALID;
963 goto cleanup;
964 } else if (strcmp(ns->uri, "urn:ietf:params:xml:ns:netconf:notification:1.0")) {
965 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Invalid namespace \"%s\" of \"eventTime\".",
966 ns->uri);
967 ret = LY_EVALID;
968 goto cleanup;
969 }
970
971 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
972
973 /* create attributes */
974 if (xmlctx->status == LYXML_ATTRIBUTE) {
975 LY_CHECK_RET(lydxml_attrs(xmlctx, &attr));
976 }
977
978 /* validate value */
979 /* TODO */
980 /*if (!xmlctx->ws_only) {
981 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_SYNTAX, "Unexpected value \"%.*s\" in the \"%s\" element.",
982 xmlctx->value_len, xmlctx->value, name);
983 ret = LY_EVALID;
984 goto cleanup;
985 }*/
986
987 /* create node */
988 ret = lyd_create_opaq(xmlctx->ctx, "eventTime", 9, xmlctx->value, xmlctx->value_len, NULL, LYD_XML, NULL,
989 prefix, prefix_len, ns->uri, &et);
990 LY_CHECK_GOTO(ret, cleanup);
991
992 /* assign atributes */
993 ((struct lyd_node_opaq *)et)->attr = attr;
994 attr = NULL;
995
996 /* insert */
997 lyd_insert_node(*envp, NULL, et);
998
999 /* finish parsing */
1000 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
1001 if (xmlctx->status != LYXML_ELEM_CLOSE) {
1002 assert(xmlctx->status == LYXML_ELEMENT);
1003 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_SYNTAX, "Unexpected sibling element \"%.*s\" of \"eventTime\".",
1004 xmlctx->name_len, xmlctx->name);
1005 ret = LY_EVALID;
1006 goto cleanup;
1007 }
1008 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
1009
1010cleanup:
1011 if (ret) {
1012 lyd_free_tree(*envp);
1013 ly_free_attr(xmlctx->ctx, attr, 1);
1014 }
1015 return ret;
1016}
1017
1018LY_ERR
1019lyd_parse_xml_notif(const struct ly_ctx *ctx, const char *data, struct lyd_node **tree, struct lyd_node **ntf)
1020{
1021 LY_ERR ret = LY_SUCCESS;
1022 struct lyd_xml_ctx lydctx = {0};
1023 struct lyd_node *ntf_e = NULL;
1024
1025 /* init */
1026 LY_CHECK_GOTO(ret = lyxml_ctx_new(ctx, data, &lydctx.xmlctx), cleanup);
1027 lydctx.options = LYD_OPT_PARSE_ONLY | LYD_OPT_STRICT;
1028 lydctx.int_opts = LYD_INTOPT_NOTIF;
1029 *tree = NULL;
Michal Vaskocc048b22020-03-27 15:52:38 +01001030 if (ntf) {
1031 *ntf = NULL;
1032 }
Michal Vaskoa8edff02020-03-27 14:47:01 +01001033
1034 /* parse "notification" and "eventTime", if present */
1035 LY_CHECK_GOTO(ret = lydxml_notif_envelope(lydctx.xmlctx, &ntf_e), cleanup);
1036
1037 /* parse the rest of data normally */
1038 LY_CHECK_GOTO(ret = lydxml_data_r(&lydctx, NULL, tree), cleanup);
1039
1040 /* make sure we have parsed some notification */
1041 if (!lydctx.op_ntf) {
1042 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_DATA, "Missing the \"notification\" node.");
1043 ret = LY_EVALID;
1044 goto cleanup;
1045 }
1046
1047 /* finish XML parsing */
1048 if (ntf_e) {
1049 if (lydctx.xmlctx->status != LYXML_ELEM_CLOSE) {
1050 assert(lydctx.xmlctx->status == LYXML_ELEMENT);
1051 LOGVAL(ctx, LY_VLOG_LINE, &lydctx.xmlctx->line, LYVE_SYNTAX, "Unexpected sibling element \"%.*s\" of \"notification\".",
1052 lydctx.xmlctx->name_len, lydctx.xmlctx->name);
1053 ret = LY_EVALID;
1054 goto cleanup;
1055 }
1056 LY_CHECK_GOTO(ret = lyxml_ctx_next(lydctx.xmlctx), cleanup);
1057 }
1058
Michal Vaskocc048b22020-03-27 15:52:38 +01001059 if (ntf) {
1060 *ntf = lydctx.op_ntf;
1061 }
Michal Vaskoa8edff02020-03-27 14:47:01 +01001062 assert(*tree);
1063 if (ntf_e) {
1064 /* connect to the notification */
1065 lyd_insert_node(ntf_e, NULL, *tree);
1066 *tree = ntf_e;
1067 }
1068
1069cleanup:
1070 /* we have used parse_only flag */
1071 assert(!lydctx.unres_node_type.count && !lydctx.unres_meta_type.count && !lydctx.when_check.count);
1072 lyxml_ctx_free(lydctx.xmlctx);
1073 if (ret) {
1074 lyd_free_all(*tree);
1075 lyd_free_tree(ntf_e);
1076 *tree = NULL;
Michal Vaskoa8edff02020-03-27 14:47:01 +01001077 }
1078 return ret;
1079}