blob: bf8e635cb2c6284812afddebe2642b7d35933818 [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 */
Michal Vasko1ce933a2020-03-30 12:38:22 +020035#define LYD_INTOPT_REPLY 0x04 /**< RPC/action reply is being parsed */
Michal Vasko1bf09392020-03-27 12:38:10 +010036
Radek Krejcie7b95092019-05-15 11:03:07 +020037/**
Michal Vaskob36053d2020-03-26 15:49:30 +010038 * @brief Internal context for XML YANG data parser.
Radek Krejcie7b95092019-05-15 11:03:07 +020039 */
40struct lyd_xml_ctx {
Michal Vaskob36053d2020-03-26 15:49:30 +010041 struct lyxml_ctx *xmlctx; /**< XML context */
Radek Krejcie7b95092019-05-15 11:03:07 +020042
Michal Vasko52927e22020-03-16 17:26:14 +010043 uint32_t options; /**< various @ref dataparseroptions. */
Michal Vasko1bf09392020-03-27 12:38:10 +010044 uint32_t int_opts; /**< internal data parser options */
Michal Vasko52927e22020-03-16 17:26:14 +010045 uint32_t path_len; /**< used bytes in the path buffer */
Radek Krejcie7b95092019-05-15 11:03:07 +020046#define LYD_PARSER_BUFSIZE 4078
47 char path[LYD_PARSER_BUFSIZE]; /**< buffer for the generated path */
Michal Vasko52927e22020-03-16 17:26:14 +010048 struct ly_set unres_node_type; /**< set of nodes validated with LY_EINCOMPLETE result */
49 struct ly_set unres_meta_type; /**< set of metadata validated with LY_EINCOMPLETE result */
Michal Vaskoecd62de2019-11-13 12:35:11 +010050 struct ly_set when_check; /**< set of nodes with "when" conditions */
Michal Vasko1bf09392020-03-27 12:38:10 +010051 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 +020052};
53
54/**
Michal Vaskob36053d2020-03-26 15:49:30 +010055 * @brief XML-parser's implementation of ly_type_resolve_prefix() callback to provide mapping between prefixes used
56 * in the values to the schema via XML namespaces.
Radek Krejciaca74032019-06-04 08:53:06 +020057 */
58static const struct lys_module *
Michal Vasko52927e22020-03-16 17:26:14 +010059lydxml_resolve_prefix(const struct ly_ctx *ctx, const char *prefix, size_t prefix_len, void *parser)
Radek Krejciaca74032019-06-04 08:53:06 +020060{
61 const struct lyxml_ns *ns;
Michal Vaskob36053d2020-03-26 15:49:30 +010062 struct lyxml_ctx *xmlctx = (struct lyxml_ctx *)parser;
Radek Krejciaca74032019-06-04 08:53:06 +020063
64 ns = lyxml_ns_get(xmlctx, prefix, prefix_len);
65 if (!ns) {
66 return NULL;
67 }
68
69 return ly_ctx_get_module_implemented_ns(ctx, ns->uri);
70}
71
Radek Krejcie7b95092019-05-15 11:03:07 +020072static LY_ERR
Michal Vaskob36053d2020-03-26 15:49:30 +010073lydxml_metadata(struct lyxml_ctx *xmlctx, const struct lysc_node *sparent, int strict, struct ly_set *type_meta_check,
74 struct lyd_meta **meta)
Radek Krejcie7b95092019-05-15 11:03:07 +020075{
Michal Vaskob36053d2020-03-26 15:49:30 +010076 LY_ERR ret = LY_EVALID;
Radek Krejci28681fa2019-09-06 13:08:45 +020077 const struct lyxml_ns *ns;
78 struct lys_module *mod;
Michal Vaskob36053d2020-03-26 15:49:30 +010079 const char *name;
80 size_t name_len;
Radek Krejci28681fa2019-09-06 13:08:45 +020081
Michal Vaskob36053d2020-03-26 15:49:30 +010082 *meta = NULL;
Radek Krejci28681fa2019-09-06 13:08:45 +020083
Michal Vaskob36053d2020-03-26 15:49:30 +010084 while (xmlctx->status == LYXML_ATTRIBUTE) {
85 if (!xmlctx->prefix_len) {
Radek Krejci28681fa2019-09-06 13:08:45 +020086 /* in XML, all attributes must be prefixed
87 * TODO exception for NETCONF filters which are supposed to map to the ietf-netconf without prefix */
Michal Vasko52927e22020-03-16 17:26:14 +010088 if (strict) {
89 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Missing mandatory prefix for XML metadata \"%.*s\".",
Michal Vaskob36053d2020-03-26 15:49:30 +010090 xmlctx->name_len, xmlctx->name);
91 goto cleanup;
Radek Krejci28681fa2019-09-06 13:08:45 +020092 }
Michal Vaskob36053d2020-03-26 15:49:30 +010093
Radek Krejci28681fa2019-09-06 13:08:45 +020094skip_attr:
Michal Vaskob36053d2020-03-26 15:49:30 +010095 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
96 assert(xmlctx->status == LYXML_ATTR_CONTENT);
97 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Radek Krejci28681fa2019-09-06 13:08:45 +020098 continue;
99 }
100
101 /* get namespace of the attribute to find its annotation definition */
Michal Vaskob36053d2020-03-26 15:49:30 +0100102 ns = lyxml_ns_get(xmlctx, xmlctx->prefix, xmlctx->prefix_len);
Radek Krejci28681fa2019-09-06 13:08:45 +0200103 if (!ns) {
Michal Vasko52927e22020-03-16 17:26:14 +0100104 /* unknown namespace, XML error */
105 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".",
Michal Vaskob36053d2020-03-26 15:49:30 +0100106 xmlctx->prefix_len, xmlctx->prefix);
Radek Krejci28681fa2019-09-06 13:08:45 +0200107 goto cleanup;
108 }
Michal Vasko52927e22020-03-16 17:26:14 +0100109 mod = ly_ctx_get_module_implemented_ns(xmlctx->ctx, ns->uri);
Radek Krejci28681fa2019-09-06 13:08:45 +0200110 if (!mod) {
111 /* module is not implemented or not present in the schema */
Michal Vasko52927e22020-03-16 17:26:14 +0100112 if (strict) {
113 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE,
Michal Vasko9f96a052020-03-10 09:41:45 +0100114 "Unknown (or not implemented) YANG module with namespace \"%s\" for metadata \"%.*s%s%.*s\".",
Michal Vaskob36053d2020-03-26 15:49:30 +0100115 ns->uri, xmlctx->prefix_len, xmlctx->prefix, xmlctx->prefix_len ? ":" : "", xmlctx->name_len,
116 xmlctx->name);
117 goto cleanup;
Radek Krejci28681fa2019-09-06 13:08:45 +0200118 }
119 goto skip_attr;
120 }
121
Michal Vaskob36053d2020-03-26 15:49:30 +0100122 /* remember attr name and get its content */
123 name = xmlctx->name;
124 name_len = xmlctx->name_len;
125 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
126 assert(xmlctx->status == LYXML_ATTR_CONTENT);
127
128 /* create metadata */
129 ret = lyd_create_meta(NULL, meta, mod, name, name_len, xmlctx->value, xmlctx->value_len, &xmlctx->dynamic,
130 lydxml_resolve_prefix, xmlctx, LYD_XML, sparent);
131 if (ret == LY_EINCOMPLETE) {
Michal Vasko52927e22020-03-16 17:26:14 +0100132 if (type_meta_check) {
133 ly_set_add(type_meta_check, meta, LY_SET_OPT_USEASLIST);
134 }
Michal Vaskob36053d2020-03-26 15:49:30 +0100135 } else if (ret) {
Radek Krejci28681fa2019-09-06 13:08:45 +0200136 goto cleanup;
137 }
Michal Vaskob36053d2020-03-26 15:49:30 +0100138
139 /* next attribute */
140 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Radek Krejcie7b95092019-05-15 11:03:07 +0200141 }
Michal Vasko52927e22020-03-16 17:26:14 +0100142
Radek Krejci28681fa2019-09-06 13:08:45 +0200143 ret = LY_SUCCESS;
Radek Krejcie7b95092019-05-15 11:03:07 +0200144
145cleanup:
Michal Vaskob36053d2020-03-26 15:49:30 +0100146 if (ret) {
147 lyd_free_meta(xmlctx->ctx, *meta, 1);
148 *meta = NULL;
Radek Krejci38d85362019-09-05 16:26:38 +0200149 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200150 return ret;
151}
152
Michal Vasko52927e22020-03-16 17:26:14 +0100153static LY_ERR
Michal Vaskob36053d2020-03-26 15:49:30 +0100154lydxml_attrs(struct lyxml_ctx *xmlctx, struct ly_attr **attr)
Michal Vasko52927e22020-03-16 17:26:14 +0100155{
156 LY_ERR ret = LY_SUCCESS;
157 const struct lyxml_ns *ns;
158 struct ly_prefix *val_prefs;
159 struct ly_attr *attr2;
Michal Vaskob36053d2020-03-26 15:49:30 +0100160 const char *name, *prefix;
161 size_t name_len, prefix_len;
Michal Vasko52927e22020-03-16 17:26:14 +0100162
163 assert(attr);
Michal Vaskob36053d2020-03-26 15:49:30 +0100164 *attr = NULL;
Michal Vasko52927e22020-03-16 17:26:14 +0100165
Michal Vaskob36053d2020-03-26 15:49:30 +0100166 while (xmlctx->status == LYXML_ATTRIBUTE) {
Michal Vasko52927e22020-03-16 17:26:14 +0100167 ns = NULL;
Michal Vaskob36053d2020-03-26 15:49:30 +0100168 if (xmlctx->prefix_len) {
Michal Vasko52927e22020-03-16 17:26:14 +0100169 /* get namespace of the attribute */
Michal Vaskob36053d2020-03-26 15:49:30 +0100170 ns = lyxml_ns_get(xmlctx, xmlctx->prefix, xmlctx->prefix_len);
Michal Vasko52927e22020-03-16 17:26:14 +0100171 if (!ns) {
172 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".",
Michal Vaskob36053d2020-03-26 15:49:30 +0100173 xmlctx->prefix_len, xmlctx->prefix);
Michal Vasko52927e22020-03-16 17:26:14 +0100174 ret = LY_EVALID;
175 goto cleanup;
176 }
177 }
178
179 if (*attr) {
180 attr2 = *attr;
181 } else {
182 attr2 = NULL;
183 }
184
Michal Vaskob36053d2020-03-26 15:49:30 +0100185 /* remember attr prefix, name, and get its content */
186 prefix = xmlctx->prefix;
187 prefix_len = xmlctx->prefix_len;
188 name = xmlctx->name;
189 name_len = xmlctx->name_len;
190 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
191 assert(xmlctx->status == LYXML_ATTR_CONTENT);
192
Michal Vasko52927e22020-03-16 17:26:14 +0100193 /* get value prefixes */
Michal Vaskob36053d2020-03-26 15:49:30 +0100194 LY_CHECK_GOTO(ret = lyxml_get_prefixes(xmlctx, xmlctx->value, xmlctx->value_len, &val_prefs), cleanup);
Michal Vasko52927e22020-03-16 17:26:14 +0100195
196 /* attr2 is always changed to the created attribute */
Michal Vaskob36053d2020-03-26 15:49:30 +0100197 ret = ly_create_attr(NULL, &attr2, xmlctx->ctx, name, name_len, xmlctx->value, xmlctx->value_len,
198 &xmlctx->dynamic, LYD_XML, val_prefs, prefix, prefix_len, ns ? ns->uri : NULL);
Michal Vasko52927e22020-03-16 17:26:14 +0100199 LY_CHECK_GOTO(ret, cleanup);
200
201 if (!*attr) {
202 *attr = attr2;
203 }
Michal Vaskob36053d2020-03-26 15:49:30 +0100204
205 /* next attribute */
206 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko52927e22020-03-16 17:26:14 +0100207 }
208
209cleanup:
Michal Vaskob36053d2020-03-26 15:49:30 +0100210 if (ret) {
211 ly_free_attr(xmlctx->ctx, *attr, 1);
212 *attr = NULL;
Michal Vasko52927e22020-03-16 17:26:14 +0100213 }
Michal Vasko52927e22020-03-16 17:26:14 +0100214 return ret;
215}
216
Michal Vasko44685da2020-03-17 15:38:06 +0100217static LY_ERR
Michal Vaskob36053d2020-03-26 15:49:30 +0100218lydxml_check_list(struct lyxml_ctx *xmlctx, const struct lysc_node *list)
Michal Vasko44685da2020-03-17 15:38:06 +0100219{
Michal Vaskob36053d2020-03-26 15:49:30 +0100220 LY_ERR ret = LY_SUCCESS, r;
221 enum LYXML_PARSER_STATUS next;
Michal Vasko44685da2020-03-17 15:38:06 +0100222 struct ly_set key_set = {0};
223 const struct lysc_node *snode;
Michal Vaskob36053d2020-03-26 15:49:30 +0100224 uint32_t i, parents_count;
Michal Vasko44685da2020-03-17 15:38:06 +0100225
226 assert(list && (list->nodetype == LYS_LIST));
227
228 /* get all keys into a set (keys do not have if-features or anything) */
229 snode = NULL;
230 while ((snode = lys_getnext(snode, list, NULL, LYS_GETNEXT_NOSTATECHECK)) && (snode->flags & LYS_KEY)) {
231 ly_set_add(&key_set, (void *)snode, LY_SET_OPT_USEASLIST);
232 }
233
Michal Vaskob36053d2020-03-26 15:49:30 +0100234 while (xmlctx->status == LYXML_ELEMENT) {
Michal Vasko44685da2020-03-17 15:38:06 +0100235 /* find key definition */
236 for (i = 0; i < key_set.count; ++i) {
237 snode = (const struct lysc_node *)key_set.objs[i];
Michal Vaskob36053d2020-03-26 15:49:30 +0100238 if (!ly_strncmp(snode->name, xmlctx->name, xmlctx->name_len)) {
Michal Vasko44685da2020-03-17 15:38:06 +0100239 break;
240 }
241 }
Michal Vaskob36053d2020-03-26 15:49:30 +0100242 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100243
244 /* skip attributes */
245 while (xmlctx->status == LYXML_ATTRIBUTE) {
Michal Vaskob36053d2020-03-26 15:49:30 +0100246 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
247 assert(xmlctx->status == LYXML_ATTR_CONTENT);
248 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100249 }
250
Michal Vaskob36053d2020-03-26 15:49:30 +0100251 assert(xmlctx->status == LYXML_ELEM_CONTENT);
252 if (i < key_set.count) {
253 /* validate the value */
254 r = lys_value_validate(NULL, snode, xmlctx->value, xmlctx->value_len, lydxml_resolve_prefix, xmlctx, LYD_XML);
255 if (!r) {
256 /* key with a valid value, remove from the set */
257 ly_set_rm_index(&key_set, i, NULL);
Michal Vasko44685da2020-03-17 15:38:06 +0100258 }
259 }
260
Michal Vaskob36053d2020-03-26 15:49:30 +0100261 /* parser next */
262 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100263
Michal Vaskob36053d2020-03-26 15:49:30 +0100264 /* skip any children, resursively */
265 parents_count = xmlctx->elements.count;
266 while ((parents_count < xmlctx->elements.count) || (xmlctx->status == LYXML_ELEMENT)) {
267 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
268 }
269
270 /* parser next, but do not parse closing element of the list because it would remove its namespaces */
271 assert(xmlctx->status == LYXML_ELEM_CLOSE);
272 LY_CHECK_GOTO(ret = lyxml_ctx_peek(xmlctx, &next), cleanup);
273 if (next != LYXML_ELEM_CLOSE) {
274 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
275 }
Michal Vasko44685da2020-03-17 15:38:06 +0100276 }
277
278 if (key_set.count) {
Michal Vaskob36053d2020-03-26 15:49:30 +0100279 /* some keys are missing/did not validate */
Michal Vasko44685da2020-03-17 15:38:06 +0100280 ret = LY_ENOT;
Michal Vasko44685da2020-03-17 15:38:06 +0100281 }
282
283cleanup:
284 ly_set_erase(&key_set, NULL);
285 return ret;
286}
287
Michal Vasko1bf09392020-03-27 12:38:10 +0100288static LY_ERR
289lydxml_data_skip(struct lyxml_ctx *xmlctx)
290{
291 uint32_t parents_count;
292
293 /* remember current number of parents */
294 parents_count = xmlctx->elements.count;
295
296 /* skip after the content */
297 while (xmlctx->status != LYXML_ELEM_CONTENT) {
298 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
299 }
300 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
301
302 /* skip all children elements, recursively, if any */
303 while (parents_count < xmlctx->elements.count) {
304 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
305 }
306
307 /* close element */
308 assert(xmlctx->status == LYXML_ELEM_CLOSE);
309 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
310
311 return LY_SUCCESS;
312}
313
314static LY_ERR
315lydxml_data_check_schema(struct lyd_xml_ctx *lydctx, const struct lysc_node **snode)
316{
317 LY_ERR ret = LY_SUCCESS;
318 enum LYXML_PARSER_STATUS prev_status;
319 const char *prev_input, *pname, *pprefix;
320 size_t pprefix_len, pname_len;
321 struct lyxml_ctx *xmlctx = lydctx->xmlctx;
322
323 if ((lydctx->options & LYD_OPT_NO_STATE) && ((*snode)->flags & LYS_CONFIG_R)) {
Michal Vaskocb7526d2020-03-30 15:08:26 +0200324 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LY_VCODE_INNODE, "state", (*snode)->name);
Michal Vasko1bf09392020-03-27 12:38:10 +0100325 return LY_EVALID;
326 }
327
328 if ((*snode)->nodetype & (LYS_RPC | LYS_ACTION)) {
329 if (lydctx->int_opts & LYD_INTOPT_RPC) {
330 if (lydctx->op_ntf) {
331 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_DATA, "Unexpected %s element \"%s\", %s \"%s\" already parsed.",
332 lys_nodetype2str((*snode)->nodetype), (*snode)->name,
333 lys_nodetype2str(lydctx->op_ntf->schema->nodetype), lydctx->op_ntf->schema->name);
334 return LY_EVALID;
335 }
336 } else {
337 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_DATA, "Unexpected %s element \"%s\".",
338 lys_nodetype2str((*snode)->nodetype), (*snode)->name);
339 return LY_EVALID;
340 }
341 } else if ((*snode)->nodetype == LYS_NOTIF) {
342 if (lydctx->int_opts & LYD_INTOPT_NOTIF) {
343 if (lydctx->op_ntf) {
344 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_DATA, "Unexpected %s element \"%s\", %s \"%s\" already parsed.",
345 lys_nodetype2str((*snode)->nodetype), (*snode)->name,
346 lys_nodetype2str(lydctx->op_ntf->schema->nodetype), lydctx->op_ntf->schema->name);
347 return LY_EVALID;
348 }
349 } else {
350 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_DATA, "Unexpected %s element \"%s\".",
351 lys_nodetype2str((*snode)->nodetype), (*snode)->name);
352 return LY_EVALID;
353 }
354 }
355
356 if ((lydctx->options & LYD_OPT_OPAQ) && ((*snode)->nodetype & (LYD_NODE_TERM | LYS_LIST))) {
357 /* backup parser */
358 prev_status = xmlctx->status;
359 pprefix = xmlctx->prefix;
360 pprefix_len = xmlctx->prefix_len;
361 pname = xmlctx->name;
362 pname_len = xmlctx->name_len;
363 prev_input = xmlctx->input;
364 if ((xmlctx->status == LYXML_ELEM_CONTENT) && xmlctx->dynamic) {
365 /* it was backed up, do not free */
366 xmlctx->dynamic = 0;
367 }
368
369 /* skip attributes */
370 while (xmlctx->status == LYXML_ATTRIBUTE) {
371 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), restore);
372 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), restore);
373 }
374
375 if ((*snode)->nodetype & LYD_NODE_TERM) {
376 /* value may not be valid in which case we parse it as an opaque node */
377 if (lys_value_validate(NULL, *snode, xmlctx->value, xmlctx->value_len, lydxml_resolve_prefix, xmlctx, LYD_XML)) {
378 *snode = NULL;
379 }
380 } else {
381 /* skip content */
382 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), restore);
383
384 if (lydxml_check_list(xmlctx, *snode)) {
385 /* invalid list, parse as opaque if it missing/has invalid some keys */
386 *snode = NULL;
387 }
388 }
389
390restore:
391 /* restore parser */
392 if (xmlctx->dynamic) {
393 free((char *)xmlctx->value);
394 }
395 xmlctx->status = prev_status;
396 xmlctx->prefix = pprefix;
397 xmlctx->prefix_len = pprefix_len;
398 xmlctx->name = pname;
399 xmlctx->name_len = pname_len;
400 xmlctx->input = prev_input;
401 }
402
403 return ret;
404}
405
406static void
407lydxml_data_flags(struct lyd_xml_ctx *lydctx, struct lyd_node *node, struct lyd_meta **meta)
408{
409 struct lyd_meta *meta2, *prev_meta = NULL;
410
411 if (!(node->schema->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) && node->schema->when) {
412 if (lydctx->options & LYD_OPT_TRUSTED) {
413 /* just set it to true */
414 node->flags |= LYD_WHEN_TRUE;
415 } else {
416 /* remember we need to evaluate this node's when */
417 ly_set_add(&lydctx->when_check, node, LY_SET_OPT_USEASLIST);
418 }
419 }
420
421 if (lydctx->options & LYD_OPT_TRUSTED) {
422 /* node is valid */
423 node->flags &= ~LYD_NEW;
424 }
425
426 LY_LIST_FOR(*meta, meta2) {
427 if (!strcmp(meta2->name, "default") && !strcmp(meta2->annotation->module->name, "ietf-netconf-with-defaults")
428 && meta2->value.boolean) {
429 /* node is default according to the metadata */
430 node->flags |= LYD_DEFAULT;
431
432 /* delete the metadata */
433 if (prev_meta) {
434 prev_meta->next = meta2->next;
435 } else {
436 *meta = (*meta)->next;
437 }
438 lyd_free_meta(lydctx->xmlctx->ctx, meta2, 0);
439 break;
440 }
441
442 prev_meta = meta2;
443 }
444}
445
Radek Krejcie7b95092019-05-15 11:03:07 +0200446/**
Michal Vasko9f96a052020-03-10 09:41:45 +0100447 * @brief Parse XML elements as YANG data node children the specified parent node.
Radek Krejcie7b95092019-05-15 11:03:07 +0200448 *
Michal Vaskob36053d2020-03-26 15:49:30 +0100449 * @param[in] lydctx XML YANG data parser context.
Radek Krejcie7b95092019-05-15 11:03:07 +0200450 * @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 +0200451 * @param[out] node Resulting list of the parsed nodes.
Michal Vasko9b368d32020-02-14 13:53:31 +0100452 * @return LY_ERR value.
Radek Krejcie7b95092019-05-15 11:03:07 +0200453 */
454static LY_ERR
Michal Vasko1bf09392020-03-27 12:38:10 +0100455lydxml_data_r(struct lyd_xml_ctx *lydctx, struct lyd_node_inner *parent, struct lyd_node **first)
Radek Krejcie7b95092019-05-15 11:03:07 +0200456{
Michal Vaskob36053d2020-03-26 15:49:30 +0100457 LY_ERR ret = LY_SUCCESS;
Michal Vasko1bf09392020-03-27 12:38:10 +0100458 const char *prefix, *name;
459 size_t prefix_len, name_len;
Michal Vaskob36053d2020-03-26 15:49:30 +0100460 struct lyxml_ctx *xmlctx;
461 const struct ly_ctx *ctx;
Radek Krejcie7b95092019-05-15 11:03:07 +0200462 const struct lyxml_ns *ns;
Michal Vasko1bf09392020-03-27 12:38:10 +0100463 struct lyd_meta *meta = NULL;
Michal Vasko52927e22020-03-16 17:26:14 +0100464 struct ly_attr *attr = NULL;
Radek Krejcie7b95092019-05-15 11:03:07 +0200465 const struct lysc_node *snode;
466 struct lys_module *mod;
Michal Vasko1bf09392020-03-27 12:38:10 +0100467 uint32_t prev_opts;
Michal Vasko52927e22020-03-16 17:26:14 +0100468 struct lyd_node *cur = NULL, *anchor;
469 struct ly_prefix *val_prefs;
Michal Vasko1ce933a2020-03-30 12:38:22 +0200470 int getnext_opts;
Radek Krejcie7b95092019-05-15 11:03:07 +0200471
Michal Vaskob36053d2020-03-26 15:49:30 +0100472 xmlctx = lydctx->xmlctx;
473 ctx = xmlctx->ctx;
Michal Vasko1ce933a2020-03-30 12:38:22 +0200474 /* leave if-feature check for validation */
475 getnext_opts = LYS_GETNEXT_NOSTATECHECK | (lydctx->int_opts & LYD_INTOPT_REPLY ? LYS_GETNEXT_OUTPUT : 0);
Michal Vasko6f4cbb62020-02-28 11:15:47 +0100476
Michal Vaskob36053d2020-03-26 15:49:30 +0100477 while (xmlctx->status == LYXML_ELEMENT) {
478 /* remember element prefix and name */
479 prefix = xmlctx->prefix;
480 prefix_len = xmlctx->prefix_len;
481 name = xmlctx->name;
482 name_len = xmlctx->name_len;
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200483
Michal Vaskob36053d2020-03-26 15:49:30 +0100484 /* get the element module */
485 ns = lyxml_ns_get(xmlctx, prefix, prefix_len);
Radek Krejcie7b95092019-05-15 11:03:07 +0200486 if (!ns) {
Michal Vaskob36053d2020-03-26 15:49:30 +0100487 LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".",
488 prefix_len, prefix);
Michal Vasko90932a92020-02-12 14:33:03 +0100489 ret = LY_EVALID;
490 goto cleanup;
Radek Krejcie7b95092019-05-15 11:03:07 +0200491 }
Michal Vaskob36053d2020-03-26 15:49:30 +0100492 mod = ly_ctx_get_module_implemented_ns(ctx, ns->uri);
493 if (!mod && (lydctx->options & LYD_OPT_STRICT)) {
494 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 +0100495 ret = LY_EVALID;
496 goto cleanup;
Radek Krejcie7b95092019-05-15 11:03:07 +0200497 }
Michal Vasko52927e22020-03-16 17:26:14 +0100498
Michal Vasko1bf09392020-03-27 12:38:10 +0100499 /* parser next */
500 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
501
Michal Vaskob36053d2020-03-26 15:49:30 +0100502 /* get the schema node */
Michal Vasko52927e22020-03-16 17:26:14 +0100503 snode = NULL;
504 if (mod && (!parent || parent->schema)) {
Michal Vasko1ce933a2020-03-30 12:38:22 +0200505 snode = lys_find_child(parent ? parent->schema : NULL, mod, name, name_len, 0, getnext_opts);
Michal Vaskob36053d2020-03-26 15:49:30 +0100506 if (!snode) {
507 if (lydctx->options & LYD_OPT_STRICT) {
508 LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Element \"%.*s\" not found in the \"%s\" module.",
509 name_len, name, mod->name);
510 ret = LY_EVALID;
511 goto cleanup;
512 } else if (!(lydctx->options & LYD_OPT_OPAQ)) {
Michal Vasko1bf09392020-03-27 12:38:10 +0100513 /* skip element with children */
514 LY_CHECK_GOTO(ret = lydxml_data_skip(xmlctx), cleanup);
Michal Vaskob36053d2020-03-26 15:49:30 +0100515 continue;
516 }
Michal Vaskob36053d2020-03-26 15:49:30 +0100517 } else {
Michal Vasko1bf09392020-03-27 12:38:10 +0100518 /* check that schema node is valid and can be used */
519 LY_CHECK_GOTO(ret = lydxml_data_check_schema(lydctx, &snode), cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100520 }
521 }
522
Michal Vaskob36053d2020-03-26 15:49:30 +0100523 /* create metadata/attributes */
524 if (xmlctx->status == LYXML_ATTRIBUTE) {
Michal Vasko52927e22020-03-16 17:26:14 +0100525 if (snode) {
Michal Vaskob36053d2020-03-26 15:49:30 +0100526 ret = lydxml_metadata(xmlctx, snode, lydctx->options & LYD_OPT_STRICT, &lydctx->unres_meta_type, &meta);
Michal Vasko52927e22020-03-16 17:26:14 +0100527 LY_CHECK_GOTO(ret, cleanup);
528 } else {
Michal Vaskob36053d2020-03-26 15:49:30 +0100529 assert(lydctx->options & LYD_OPT_OPAQ);
530 ret = lydxml_attrs(xmlctx, &attr);
531 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko52927e22020-03-16 17:26:14 +0100532 }
Michal Vasko8d544252020-03-02 10:19:52 +0100533 }
534
Michal Vaskob36053d2020-03-26 15:49:30 +0100535 assert(xmlctx->status == LYXML_ELEM_CONTENT);
Michal Vasko52927e22020-03-16 17:26:14 +0100536 if (!snode) {
Michal Vaskob36053d2020-03-26 15:49:30 +0100537 assert(lydctx->options & LYD_OPT_OPAQ);
Michal Vasko52927e22020-03-16 17:26:14 +0100538
Michal Vaskob36053d2020-03-26 15:49:30 +0100539 if (xmlctx->ws_only) {
540 /* ignore WS-only value */
541 xmlctx->value_len = 0;
542 val_prefs = NULL;
Michal Vasko52927e22020-03-16 17:26:14 +0100543 } else {
Michal Vaskob36053d2020-03-26 15:49:30 +0100544 /* get value prefixes */
545 ret = lyxml_get_prefixes(xmlctx, xmlctx->value, xmlctx->value_len, &val_prefs);
Michal Vasko52927e22020-03-16 17:26:14 +0100546 LY_CHECK_GOTO(ret, cleanup);
Radek Krejcie7b95092019-05-15 11:03:07 +0200547 }
Michal Vasko90932a92020-02-12 14:33:03 +0100548
549 /* create node */
Michal Vaskob36053d2020-03-26 15:49:30 +0100550 ret = lyd_create_opaq(ctx, name, name_len, xmlctx->value, xmlctx->value_len, &xmlctx->dynamic, LYD_XML,
551 val_prefs, prefix, prefix_len, ns->uri, &cur);
552 LY_CHECK_GOTO(ret, cleanup);
553
554 /* parser next */
555 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
556
557 /* process children */
558 if (xmlctx->status == LYXML_ELEMENT) {
Michal Vasko1bf09392020-03-27 12:38:10 +0100559 ret = lydxml_data_r(lydctx, (struct lyd_node_inner *)cur, lyd_node_children_p(cur));
Michal Vaskob36053d2020-03-26 15:49:30 +0100560 LY_CHECK_GOTO(ret, cleanup);
561 }
562 } else if (snode->nodetype & LYD_NODE_TERM) {
563 /* create node */
564 ret = lyd_create_term(snode, xmlctx->value, xmlctx->value_len, &xmlctx->dynamic, lydxml_resolve_prefix,
565 xmlctx, LYD_XML, &cur);
Radek Krejcie553e6d2019-06-07 15:33:18 +0200566 if (ret == LY_EINCOMPLETE) {
Michal Vaskob36053d2020-03-26 15:49:30 +0100567 if (!(lydctx->options & LYD_OPT_PARSE_ONLY)) {
568 ly_set_add(&lydctx->unres_node_type, cur, LY_SET_OPT_USEASLIST);
Michal Vasko9b368d32020-02-14 13:53:31 +0100569 }
Radek Krejcie553e6d2019-06-07 15:33:18 +0200570 } else if (ret) {
Radek Krejcie553e6d2019-06-07 15:33:18 +0200571 goto cleanup;
572 }
Michal Vasko9b368d32020-02-14 13:53:31 +0100573
574 if (parent && (cur->schema->flags & LYS_KEY)) {
575 /* check the key order, the anchor must always be the last child */
Michal Vasko52927e22020-03-16 17:26:14 +0100576 anchor = lyd_get_prev_key_anchor(parent->child, cur->schema);
577 if ((!anchor && parent->child) || (anchor && anchor->next)) {
Michal Vaskob36053d2020-03-26 15:49:30 +0100578 if (lydctx->options & LYD_OPT_STRICT) {
579 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 +0100580 cur->schema->name);
581 ret = LY_EVALID;
582 goto cleanup;
583 } else {
Michal Vaskob36053d2020-03-26 15:49:30 +0100584 LOGWRN(ctx, "Invalid position of the key \"%s\" in a list.", cur->schema->name);
Michal Vasko9b368d32020-02-14 13:53:31 +0100585 }
586 }
587 }
Michal Vaskob36053d2020-03-26 15:49:30 +0100588
589 /* parser next */
590 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
591
592 /* no children expected */
593 if (xmlctx->status == LYXML_ELEMENT) {
Michal Vasko1bf09392020-03-27 12:38:10 +0100594 LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_SYNTAX, "Child element \"%.*s\" inside a terminal node \"%s\" found.",
595 xmlctx->name_len, xmlctx->name, snode->name);
Michal Vasko44685da2020-03-17 15:38:06 +0100596 ret = LY_EVALID;
597 goto cleanup;
Michal Vaskob36053d2020-03-26 15:49:30 +0100598 }
599 } else if (snode->nodetype & LYD_NODE_INNER) {
600 if (!xmlctx->ws_only) {
601 /* value in inner node */
Michal Vasko1bf09392020-03-27 12:38:10 +0100602 LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_SYNTAX, "Text value \"%.*s\" inside an inner node \"%s\" found.",
603 xmlctx->value_len, xmlctx->value, snode->name);
Michal Vaskob36053d2020-03-26 15:49:30 +0100604 ret = LY_EVALID;
605 goto cleanup;
Radek Krejcie7b95092019-05-15 11:03:07 +0200606 }
Michal Vasko90932a92020-02-12 14:33:03 +0100607
608 /* create node */
609 ret = lyd_create_inner(snode, &cur);
610 LY_CHECK_GOTO(ret, cleanup);
611
Michal Vaskob36053d2020-03-26 15:49:30 +0100612 /* parser next */
613 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
614
Radek Krejciee4cab22019-07-17 17:07:47 +0200615 /* process children */
Michal Vaskob36053d2020-03-26 15:49:30 +0100616 if (xmlctx->status == LYXML_ELEMENT) {
Michal Vasko1bf09392020-03-27 12:38:10 +0100617 ret = lydxml_data_r(lydctx, (struct lyd_node_inner *)cur, lyd_node_children_p(cur));
Michal Vasko9f96a052020-03-10 09:41:45 +0100618 LY_CHECK_GOTO(ret, cleanup);
619 }
620
621 if (snode->nodetype == LYS_LIST) {
622 /* check all keys exist */
Michal Vasko44685da2020-03-17 15:38:06 +0100623 LY_CHECK_GOTO(ret = lyd_parse_check_keys(cur), cleanup);
Radek Krejcie7b95092019-05-15 11:03:07 +0200624 }
Michal Vasko9b368d32020-02-14 13:53:31 +0100625
Michal Vaskob36053d2020-03-26 15:49:30 +0100626 if (!(lydctx->options & LYD_OPT_PARSE_ONLY)) {
Michal Vaskob1b5c262020-03-05 14:29:47 +0100627 /* new node validation, autodelete CANNOT occur, all nodes are new */
628 ret = lyd_validate_new(lyd_node_children_p(cur), snode, NULL);
629 LY_CHECK_GOTO(ret, cleanup);
630
Michal Vasko9b368d32020-02-14 13:53:31 +0100631 /* add any missing default children */
Michal Vaskob1b5c262020-03-05 14:29:47 +0100632 ret = lyd_validate_defaults_r((struct lyd_node_inner *)cur, lyd_node_children_p(cur), NULL, NULL,
Michal Vaskob36053d2020-03-26 15:49:30 +0100633 &lydctx->unres_node_type, &lydctx->when_check, lydctx->options);
Michal Vasko9b368d32020-02-14 13:53:31 +0100634 LY_CHECK_GOTO(ret, cleanup);
635 }
636
Michal Vasko9b368d32020-02-14 13:53:31 +0100637 if (snode->nodetype == LYS_LIST) {
Michal Vasko1bf09392020-03-27 12:38:10 +0100638 /* hash now that all keys should be parsed, rehash for key-less list */
Michal Vasko9b368d32020-02-14 13:53:31 +0100639 lyd_hash(cur);
Michal Vasko1bf09392020-03-27 12:38:10 +0100640 } else if (snode->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) {
641 /* rememeber the RPC/action/notification */
642 lydctx->op_ntf = cur;
Michal Vasko9b368d32020-02-14 13:53:31 +0100643 }
Radek Krejciee4cab22019-07-17 17:07:47 +0200644 } else if (snode->nodetype & LYD_NODE_ANY) {
Michal Vaskob36053d2020-03-26 15:49:30 +0100645 if (!xmlctx->ws_only) {
646 /* value in inner node */
Michal Vasko1bf09392020-03-27 12:38:10 +0100647 LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_SYNTAX, "Text value \"%.*s\" inside an any node \"%s\" found.",
648 xmlctx->value_len, xmlctx->value, snode->name);
Michal Vaskob36053d2020-03-26 15:49:30 +0100649 ret = LY_EVALID;
650 goto cleanup;
Radek Krejciee4cab22019-07-17 17:07:47 +0200651 }
Michal Vasko90932a92020-02-12 14:33:03 +0100652
Michal Vaskob36053d2020-03-26 15:49:30 +0100653 /* parser next */
654 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
655
Michal Vasko52927e22020-03-16 17:26:14 +0100656 /* parse any data tree with correct options */
Michal Vaskob36053d2020-03-26 15:49:30 +0100657 prev_opts = lydctx->options;
658 lydctx->options &= ~LYD_OPT_STRICT;
659 lydctx->options |= LYD_OPT_OPAQ;
Michal Vasko52927e22020-03-16 17:26:14 +0100660 anchor = NULL;
Michal Vasko1bf09392020-03-27 12:38:10 +0100661 ret = lydxml_data_r(lydctx, NULL, &anchor);
Michal Vaskob36053d2020-03-26 15:49:30 +0100662 lydctx->options = prev_opts;
Michal Vasko52927e22020-03-16 17:26:14 +0100663 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko90932a92020-02-12 14:33:03 +0100664
665 /* create node */
Michal Vasko52927e22020-03-16 17:26:14 +0100666 ret = lyd_create_any(snode, anchor, LYD_ANYDATA_DATATREE, &cur);
667 LY_CHECK_GOTO(ret, cleanup);
Radek Krejcie7b95092019-05-15 11:03:07 +0200668 }
Michal Vasko1bf09392020-03-27 12:38:10 +0100669 assert(cur);
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200670
Michal Vasko1bf09392020-03-27 12:38:10 +0100671 /* add/correct flags */
Michal Vasko52927e22020-03-16 17:26:14 +0100672 if (snode) {
Michal Vasko1bf09392020-03-27 12:38:10 +0100673 lydxml_data_flags(lydctx, cur, &meta);
Michal Vasko8d544252020-03-02 10:19:52 +0100674 }
675
Michal Vasko52927e22020-03-16 17:26:14 +0100676 /* add metadata/attributes */
677 if (snode) {
678 cur->meta = meta;
679 meta = NULL;
680 } else {
681 assert(!cur->schema);
682 ((struct lyd_node_opaq *)cur)->attr = attr;
683 attr = NULL;
684 }
Radek Krejcib6f7ae52019-07-19 10:31:42 +0200685
Michal Vasko90932a92020-02-12 14:33:03 +0100686 /* insert */
Michal Vaskob1b5c262020-03-05 14:29:47 +0100687 lyd_insert_node((struct lyd_node *)parent, first, cur);
Michal Vasko90932a92020-02-12 14:33:03 +0100688 cur = NULL;
Michal Vaskob36053d2020-03-26 15:49:30 +0100689
690 /* parser next */
691 assert(xmlctx->status == LYXML_ELEM_CLOSE);
692 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Radek Krejcie7b95092019-05-15 11:03:07 +0200693 }
694
Michal Vasko90932a92020-02-12 14:33:03 +0100695 /* success */
696 ret = LY_SUCCESS;
697
Radek Krejcie7b95092019-05-15 11:03:07 +0200698cleanup:
Michal Vaskob36053d2020-03-26 15:49:30 +0100699 lyd_free_meta(ctx, meta, 1);
700 ly_free_attr(ctx, attr, 1);
Michal Vasko90932a92020-02-12 14:33:03 +0100701 lyd_free_tree(cur);
Michal Vaskob1b5c262020-03-05 14:29:47 +0100702 if (ret && *first) {
703 lyd_free_siblings(*first);
704 *first = NULL;
Michal Vasko90932a92020-02-12 14:33:03 +0100705 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200706 return ret;
707}
708
709LY_ERR
Michal Vasko1bf09392020-03-27 12:38:10 +0100710lyd_parse_xml_data(const struct ly_ctx *ctx, const char *data, int options, struct lyd_node **tree)
Radek Krejcie7b95092019-05-15 11:03:07 +0200711{
Radek Krejci18a57d92019-07-25 14:01:42 +0200712 LY_ERR ret = LY_SUCCESS;
Michal Vaskob36053d2020-03-26 15:49:30 +0100713 struct lyd_xml_ctx lydctx = {0};
Michal Vaskob1b5c262020-03-05 14:29:47 +0100714 uint32_t i = 0;
715 const struct lys_module *mod;
716 struct lyd_node *first, *next, **first2;
Radek Krejcie7b95092019-05-15 11:03:07 +0200717
Michal Vaskob36053d2020-03-26 15:49:30 +0100718 /* init context and tree */
719 LY_CHECK_GOTO(ret = lyxml_ctx_new(ctx, data, &lydctx.xmlctx), cleanup);
720 lydctx.options = options;
Michal Vaskob1b5c262020-03-05 14:29:47 +0100721 *tree = NULL;
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200722
Michal Vaskob1b5c262020-03-05 14:29:47 +0100723 /* parse XML data */
Michal Vasko1bf09392020-03-27 12:38:10 +0100724 LY_CHECK_GOTO(ret = lydxml_data_r(&lydctx, NULL, tree), cleanup);
Michal Vaskocde73ac2019-11-14 16:10:27 +0100725
Michal Vasko9b368d32020-02-14 13:53:31 +0100726 if (!(options & LYD_OPT_PARSE_ONLY)) {
Michal Vaskob1b5c262020-03-05 14:29:47 +0100727 next = *tree;
728 while (1) {
729 if (options & LYD_VALOPT_DATA_ONLY) {
730 mod = lyd_data_next_module(&next, &first);
731 } else {
732 mod = lyd_mod_next_module(next, NULL, 0, ctx, &i, &first);
733 }
734 if (!mod) {
735 break;
736 }
737 if (first == *tree) {
738 /* make sure first2 changes are carried to tree */
739 first2 = tree;
740 } else {
741 first2 = &first;
742 }
Michal Vasko9b368d32020-02-14 13:53:31 +0100743
Michal Vaskob1b5c262020-03-05 14:29:47 +0100744 /* validate new top-level nodes, autodelete CANNOT occur, all nodes are new */
Michal Vasko1bf09392020-03-27 12:38:10 +0100745 LY_CHECK_GOTO(ret = lyd_validate_new(first2, NULL, mod), cleanup);
Michal Vasko9b368d32020-02-14 13:53:31 +0100746
Michal Vaskob1b5c262020-03-05 14:29:47 +0100747 /* add all top-level defaults for this module */
Michal Vaskob36053d2020-03-26 15:49:30 +0100748 ret = lyd_validate_defaults_r(NULL, first2, NULL, mod, &lydctx.unres_node_type, &lydctx.when_check,
Michal Vasko52927e22020-03-16 17:26:14 +0100749 options & LYD_VALOPT_MASK);
Michal Vaskob1b5c262020-03-05 14:29:47 +0100750 LY_CHECK_GOTO(ret, cleanup);
751
752 /* finish incompletely validated terminal values/attributes and when conditions */
Michal Vaskob36053d2020-03-26 15:49:30 +0100753 ret = lyd_validate_unres(tree, &lydctx.when_check, &lydctx.unres_node_type, &lydctx.unres_meta_type, LYD_XML,
754 lydxml_resolve_prefix, lydctx.xmlctx);
Michal Vaskob1b5c262020-03-05 14:29:47 +0100755 LY_CHECK_GOTO(ret, cleanup);
756
757 /* perform final validation that assumes the data tree is final */
Michal Vaskofea12c62020-03-30 11:00:15 +0200758 LY_CHECK_GOTO(ret = lyd_validate_final_r(*first2, NULL, mod, options & LYD_VALOPT_MASK), cleanup);
Michal Vaskob1b5c262020-03-05 14:29:47 +0100759 }
Michal Vaskocde73ac2019-11-14 16:10:27 +0100760 }
761
Michal Vaskocde73ac2019-11-14 16:10:27 +0100762cleanup:
Michal Vasko9b368d32020-02-14 13:53:31 +0100763 /* there should be no unresolved types stored */
Michal Vaskob36053d2020-03-26 15:49:30 +0100764 assert(!(options & LYD_OPT_PARSE_ONLY) || (!lydctx.unres_node_type.count && !lydctx.unres_meta_type.count
765 && !lydctx.when_check.count));
Michal Vasko9b368d32020-02-14 13:53:31 +0100766
Michal Vaskob36053d2020-03-26 15:49:30 +0100767 ly_set_erase(&lydctx.unres_node_type, NULL);
768 ly_set_erase(&lydctx.unres_meta_type, NULL);
769 ly_set_erase(&lydctx.when_check, NULL);
770 lyxml_ctx_free(lydctx.xmlctx);
Michal Vasko9f96a052020-03-10 09:41:45 +0100771 if (ret) {
772 lyd_free_all(*tree);
773 *tree = NULL;
774 }
775 return ret;
776}
Michal Vasko1bf09392020-03-27 12:38:10 +0100777
778static LY_ERR
779lydxml_envelope(struct lyxml_ctx *xmlctx, const char *name, const char *uri, struct lyd_node **envp)
780{
781 LY_ERR ret = LY_SUCCESS;
782 const struct lyxml_ns *ns = NULL;
783 struct ly_attr *attr = NULL;
784 const char *prefix;
785 size_t prefix_len;
786
787 *envp = NULL;
788
789 assert(xmlctx->status == LYXML_ELEMENT);
790 if (ly_strncmp(name, xmlctx->name, xmlctx->name_len)) {
791 /* not the expected element */
792 return LY_SUCCESS;
793 }
794
795 prefix = xmlctx->prefix;
796 prefix_len = xmlctx->prefix_len;
797 ns = lyxml_ns_get(xmlctx, prefix, prefix_len);
798 if (!ns) {
799 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".",
800 prefix_len, prefix);
801 return LY_EVALID;
802 } else if (strcmp(ns->uri, uri)) {
803 /* different namespace */
804 return LY_SUCCESS;
805 }
806
807 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
808
809 /* create attributes */
810 if (xmlctx->status == LYXML_ATTRIBUTE) {
811 LY_CHECK_RET(lydxml_attrs(xmlctx, &attr));
812 }
813
814 if (!xmlctx->ws_only) {
815 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_SYNTAX, "Unexpected value \"%.*s\" in the \"%s\" element.",
816 xmlctx->value_len, xmlctx->value, name);
817 ret = LY_EVALID;
818 goto cleanup;
819 }
820
821 /* parser next element */
822 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
823
824 /* create node */
825 ret = lyd_create_opaq(xmlctx->ctx, name, strlen(name), "", 0, NULL, LYD_XML, NULL, prefix, prefix_len, uri, envp);
826 LY_CHECK_GOTO(ret, cleanup);
827
828 /* assign atributes */
829 ((struct lyd_node_opaq *)(*envp))->attr = attr;
830 attr = NULL;
831
832cleanup:
833 ly_free_attr(xmlctx->ctx, attr, 1);
834 return ret;
835}
836
837LY_ERR
838lyd_parse_xml_rpc(const struct ly_ctx *ctx, const char *data, struct lyd_node **tree, struct lyd_node **op)
839{
840 LY_ERR ret = LY_SUCCESS;
841 struct lyd_xml_ctx lydctx = {0};
842 struct lyd_node *rpc_e = NULL, *act_e = NULL;
843
844 /* init */
845 LY_CHECK_GOTO(ret = lyxml_ctx_new(ctx, data, &lydctx.xmlctx), cleanup);
846 lydctx.options = LYD_OPT_PARSE_ONLY | LYD_OPT_STRICT;
847 lydctx.int_opts = LYD_INTOPT_RPC;
848 *tree = NULL;
Michal Vaskocc048b22020-03-27 15:52:38 +0100849 if (op) {
850 *op = NULL;
851 }
Michal Vasko1bf09392020-03-27 12:38:10 +0100852
853 /* parse "rpc", if any */
854 LY_CHECK_GOTO(ret = lydxml_envelope(lydctx.xmlctx, "rpc", "urn:ietf:params:xml:ns:netconf:base:1.0", &rpc_e), cleanup);
855
856 if (rpc_e) {
857 /* parse "action", if any */
858 LY_CHECK_GOTO(ret = lydxml_envelope(lydctx.xmlctx, "action", "urn:ietf:params:xml:ns:yang:1", &act_e), cleanup);
859 }
860
861 /* parse the rest of data normally */
862 LY_CHECK_GOTO(ret = lydxml_data_r(&lydctx, NULL, tree), cleanup);
863
864 /* make sure we have parsed some operation */
865 if (!lydctx.op_ntf) {
866 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_DATA, "Missing the \"rpc\"/\"action\" node.");
867 ret = LY_EVALID;
868 goto cleanup;
869 }
870
871 /* finish XML parsing and check operation type */
872 if (act_e) {
873 if (lydctx.xmlctx->status != LYXML_ELEM_CLOSE) {
874 assert(lydctx.xmlctx->status == LYXML_ELEMENT);
875 LOGVAL(ctx, LY_VLOG_LINE, &lydctx.xmlctx->line, LYVE_SYNTAX, "Unexpected sibling element \"%.*s\" of \"action\".",
876 lydctx.xmlctx->name_len, lydctx.xmlctx->name);
877 ret = LY_EVALID;
878 goto cleanup;
879 } else if (lydctx.op_ntf->schema->nodetype != LYS_ACTION) {
880 LOGVAL(ctx, LY_VLOG_LYD, lydctx.op_ntf, LYVE_DATA, "Unexpected %s element, an \"action\" expected.",
881 lys_nodetype2str(lydctx.op_ntf->schema->nodetype));
882 ret = LY_EVALID;
883 goto cleanup;
884 }
885 LY_CHECK_GOTO(ret = lyxml_ctx_next(lydctx.xmlctx), cleanup);
886 }
887 if (rpc_e) {
888 if (lydctx.xmlctx->status != LYXML_ELEM_CLOSE) {
889 assert(lydctx.xmlctx->status == LYXML_ELEMENT);
890 LOGVAL(ctx, LY_VLOG_LINE, &lydctx.xmlctx->line, LYVE_SYNTAX, "Unexpected sibling element \"%.*s\" of \"rpc\".",
891 lydctx.xmlctx->name_len, lydctx.xmlctx->name);
892 ret = LY_EVALID;
893 goto cleanup;
894 } else if (!act_e && (lydctx.op_ntf->schema->nodetype != LYS_RPC)) {
895 LOGVAL(ctx, LY_VLOG_LYD, lydctx.op_ntf, LYVE_DATA, "Unexpected %s element, an \"rpc\" expected.",
896 lys_nodetype2str(lydctx.op_ntf->schema->nodetype));
897 ret = LY_EVALID;
898 goto cleanup;
899 }
900 LY_CHECK_GOTO(ret = lyxml_ctx_next(lydctx.xmlctx), cleanup);
901 }
902
Michal Vaskocc048b22020-03-27 15:52:38 +0100903 if (op) {
904 *op = lydctx.op_ntf;
905 }
Michal Vasko1bf09392020-03-27 12:38:10 +0100906 assert(*tree);
907 if (act_e) {
908 /* connect to the action */
909 lyd_insert_node(act_e, NULL, *tree);
910 *tree = act_e;
911 }
912 if (rpc_e) {
913 /* connect to the rpc */
914 lyd_insert_node(rpc_e, NULL, *tree);
915 *tree = rpc_e;
916 }
917
918cleanup:
919 /* we have used parse_only flag */
920 assert(!lydctx.unres_node_type.count && !lydctx.unres_meta_type.count && !lydctx.when_check.count);
921 lyxml_ctx_free(lydctx.xmlctx);
922 if (ret) {
923 lyd_free_all(*tree);
924 lyd_free_tree(act_e);
925 lyd_free_tree(rpc_e);
926 *tree = NULL;
Michal Vasko1bf09392020-03-27 12:38:10 +0100927 }
928 return ret;
929}
Michal Vaskoa8edff02020-03-27 14:47:01 +0100930
931static LY_ERR
932lydxml_notif_envelope(struct lyxml_ctx *xmlctx, struct lyd_node **envp)
933{
934 LY_ERR ret = LY_SUCCESS;
935 const struct lyxml_ns *ns = NULL;
936 struct ly_attr *attr = NULL;
937 struct lyd_node *et;
938 const char *prefix;
939 size_t prefix_len;
940
941 *envp = NULL;
942
943 /* container envelope */
944 LY_CHECK_GOTO(ret = lydxml_envelope(xmlctx, "notification", "urn:ietf:params:xml:ns:netconf:notification:1.0",
945 envp), cleanup);
946
947 /* no envelope, fine */
948 if (!*envp) {
949 goto cleanup;
950 }
951
952 /* child "eventTime" */
953 if ((xmlctx->status != LYXML_ELEMENT) || ly_strncmp("eventTime", xmlctx->name, xmlctx->name_len)) {
954 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Missing the \"eventTime\" element.");
955 ret = LY_EVALID;
956 goto cleanup;
957 }
958
959 prefix = xmlctx->prefix;
960 prefix_len = xmlctx->prefix_len;
961 ns = lyxml_ns_get(xmlctx, prefix, prefix_len);
962 if (!ns) {
963 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".",
964 prefix_len, prefix);
965 ret = LY_EVALID;
966 goto cleanup;
967 } else if (strcmp(ns->uri, "urn:ietf:params:xml:ns:netconf:notification:1.0")) {
968 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Invalid namespace \"%s\" of \"eventTime\".",
969 ns->uri);
970 ret = LY_EVALID;
971 goto cleanup;
972 }
973
974 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
975
976 /* create attributes */
977 if (xmlctx->status == LYXML_ATTRIBUTE) {
978 LY_CHECK_RET(lydxml_attrs(xmlctx, &attr));
979 }
980
981 /* validate value */
982 /* TODO */
983 /*if (!xmlctx->ws_only) {
984 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_SYNTAX, "Unexpected value \"%.*s\" in the \"%s\" element.",
985 xmlctx->value_len, xmlctx->value, name);
986 ret = LY_EVALID;
987 goto cleanup;
988 }*/
989
990 /* create node */
991 ret = lyd_create_opaq(xmlctx->ctx, "eventTime", 9, xmlctx->value, xmlctx->value_len, NULL, LYD_XML, NULL,
992 prefix, prefix_len, ns->uri, &et);
993 LY_CHECK_GOTO(ret, cleanup);
994
995 /* assign atributes */
996 ((struct lyd_node_opaq *)et)->attr = attr;
997 attr = NULL;
998
999 /* insert */
1000 lyd_insert_node(*envp, NULL, et);
1001
1002 /* finish parsing */
1003 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
1004 if (xmlctx->status != LYXML_ELEM_CLOSE) {
1005 assert(xmlctx->status == LYXML_ELEMENT);
1006 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_SYNTAX, "Unexpected sibling element \"%.*s\" of \"eventTime\".",
1007 xmlctx->name_len, xmlctx->name);
1008 ret = LY_EVALID;
1009 goto cleanup;
1010 }
1011 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
1012
1013cleanup:
1014 if (ret) {
1015 lyd_free_tree(*envp);
1016 ly_free_attr(xmlctx->ctx, attr, 1);
1017 }
1018 return ret;
1019}
1020
1021LY_ERR
1022lyd_parse_xml_notif(const struct ly_ctx *ctx, const char *data, struct lyd_node **tree, struct lyd_node **ntf)
1023{
1024 LY_ERR ret = LY_SUCCESS;
1025 struct lyd_xml_ctx lydctx = {0};
1026 struct lyd_node *ntf_e = NULL;
1027
1028 /* init */
1029 LY_CHECK_GOTO(ret = lyxml_ctx_new(ctx, data, &lydctx.xmlctx), cleanup);
1030 lydctx.options = LYD_OPT_PARSE_ONLY | LYD_OPT_STRICT;
1031 lydctx.int_opts = LYD_INTOPT_NOTIF;
1032 *tree = NULL;
Michal Vaskocc048b22020-03-27 15:52:38 +01001033 if (ntf) {
1034 *ntf = NULL;
1035 }
Michal Vaskoa8edff02020-03-27 14:47:01 +01001036
1037 /* parse "notification" and "eventTime", if present */
1038 LY_CHECK_GOTO(ret = lydxml_notif_envelope(lydctx.xmlctx, &ntf_e), cleanup);
1039
1040 /* parse the rest of data normally */
1041 LY_CHECK_GOTO(ret = lydxml_data_r(&lydctx, NULL, tree), cleanup);
1042
1043 /* make sure we have parsed some notification */
1044 if (!lydctx.op_ntf) {
1045 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_DATA, "Missing the \"notification\" node.");
1046 ret = LY_EVALID;
1047 goto cleanup;
1048 }
1049
1050 /* finish XML parsing */
1051 if (ntf_e) {
1052 if (lydctx.xmlctx->status != LYXML_ELEM_CLOSE) {
1053 assert(lydctx.xmlctx->status == LYXML_ELEMENT);
1054 LOGVAL(ctx, LY_VLOG_LINE, &lydctx.xmlctx->line, LYVE_SYNTAX, "Unexpected sibling element \"%.*s\" of \"notification\".",
1055 lydctx.xmlctx->name_len, lydctx.xmlctx->name);
1056 ret = LY_EVALID;
1057 goto cleanup;
1058 }
1059 LY_CHECK_GOTO(ret = lyxml_ctx_next(lydctx.xmlctx), cleanup);
1060 }
1061
Michal Vaskocc048b22020-03-27 15:52:38 +01001062 if (ntf) {
1063 *ntf = lydctx.op_ntf;
1064 }
Michal Vaskoa8edff02020-03-27 14:47:01 +01001065 assert(*tree);
1066 if (ntf_e) {
1067 /* connect to the notification */
1068 lyd_insert_node(ntf_e, NULL, *tree);
1069 *tree = ntf_e;
1070 }
1071
1072cleanup:
1073 /* we have used parse_only flag */
1074 assert(!lydctx.unres_node_type.count && !lydctx.unres_meta_type.count && !lydctx.when_check.count);
1075 lyxml_ctx_free(lydctx.xmlctx);
1076 if (ret) {
1077 lyd_free_all(*tree);
1078 lyd_free_tree(ntf_e);
1079 *tree = NULL;
Michal Vaskoa8edff02020-03-27 14:47:01 +01001080 }
1081 return ret;
1082}
Michal Vasko1ce933a2020-03-30 12:38:22 +02001083
1084LY_ERR
1085lyd_parse_xml_reply(const struct lyd_node *request, const char *data, struct lyd_node **tree, struct lyd_node **op)
1086{
1087 LY_ERR ret = LY_SUCCESS;
1088 struct lyd_xml_ctx lydctx = {0};
1089 struct lyd_node *rpcr_e = NULL, *iter, *req_op, *rep_op;
1090
1091 /* init */
1092 LY_CHECK_GOTO(ret = lyxml_ctx_new(LYD_NODE_CTX(request), data, &lydctx.xmlctx), cleanup);
1093 lydctx.options = LYD_OPT_PARSE_ONLY | LYD_OPT_STRICT;
1094 lydctx.int_opts = LYD_INTOPT_REPLY;
1095 *tree = NULL;
1096 if (op) {
1097 *op = NULL;
1098 }
1099
1100 /* find request OP */
1101 LYD_TREE_DFS_BEGIN((struct lyd_node *)request, iter, req_op) {
1102 if (req_op->schema->nodetype & (LYS_RPC | LYS_ACTION)) {
1103 break;
1104 }
1105 LYD_TREE_DFS_END(request, iter, req_op);
1106 }
1107 if (!(req_op->schema->nodetype & (LYS_RPC | LYS_ACTION))) {
1108 LOGERR(LYD_NODE_CTX(request), LY_EINVAL, "No RPC/action in the request found.");
1109 ret = LY_EINVAL;
1110 goto cleanup;
1111 }
1112
1113 /* duplicate request OP with parents */
1114 rep_op = lyd_dup(req_op, NULL, LYD_DUP_WITH_PARENTS);
1115 LY_CHECK_ERR_GOTO(!rep_op, ret = LY_EMEM, cleanup);
1116
1117 /* parse "rpc-reply", if any */
1118 LY_CHECK_GOTO(ret = lydxml_envelope(lydctx.xmlctx, "rpc-reply", "urn:ietf:params:xml:ns:netconf:base:1.0", &rpcr_e), cleanup);
1119
1120 /* parse the rest of data normally but connect them to the duplicated operation */
1121 LY_CHECK_GOTO(ret = lydxml_data_r(&lydctx, (struct lyd_node_inner *)rep_op, lyd_node_children_p(rep_op)), cleanup);
1122
1123 /* finish XML parsing and check operation type */
1124 if (rpcr_e) {
1125 if (lydctx.xmlctx->status != LYXML_ELEM_CLOSE) {
1126 assert(lydctx.xmlctx->status == LYXML_ELEMENT);
1127 LOGVAL(LYD_NODE_CTX(request), LY_VLOG_LINE, &lydctx.xmlctx->line, LYVE_SYNTAX,
1128 "Unexpected sibling element \"%.*s\" of \"rpc-reply\".", lydctx.xmlctx->name_len, lydctx.xmlctx->name);
1129 ret = LY_EVALID;
1130 goto cleanup;
1131 }
1132 LY_CHECK_GOTO(ret = lyxml_ctx_next(lydctx.xmlctx), cleanup);
1133 }
1134
1135 if (op) {
1136 *op = rep_op;
1137 }
1138 for (iter = rep_op; iter->parent; iter = (struct lyd_node *)iter->parent);
1139 *tree = iter;
1140 if (rpcr_e) {
1141 /* connect to the operation */
1142 lyd_insert_node(rpcr_e, NULL, *tree);
1143 *tree = rpcr_e;
1144 }
1145
1146cleanup:
1147 /* we have used parse_only flag */
1148 assert(!lydctx.unres_node_type.count && !lydctx.unres_meta_type.count && !lydctx.when_check.count);
1149 lyxml_ctx_free(lydctx.xmlctx);
1150 if (ret) {
1151 lyd_free_all(rep_op);
1152 lyd_free_tree(rpcr_e);
1153 }
1154 return ret;
1155}