blob: fcfc8f9c74a437850fbb41f60eec568f094b09e7 [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
Michal Vasko69730152020-10-09 16:30:07 +020015#include <assert.h>
Radek Krejcie7b95092019-05-15 11:03:07 +020016#include <stdint.h>
17#include <stdlib.h>
18#include <string.h>
19
Radek Krejci535ea9f2020-05-29 16:01:05 +020020#include "common.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020021#include "context.h"
Radek Krejci77114102021-03-10 15:21:57 +010022#include "dict.h"
Michal Vaskoafac7822020-10-20 14:22:26 +020023#include "in_internal.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020024#include "log.h"
Radek Krejci7931b192020-06-25 17:05:03 +020025#include "parser_data.h"
26#include "parser_internal.h"
tadeas-vintrlikbf8aa6e2021-11-03 13:07:34 +010027#include "plugins_exts.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020028#include "set.h"
Radek Krejci77114102021-03-10 15:21:57 +010029#include "tree.h"
Radek Krejci47fab892020-11-05 17:02:41 +010030#include "tree_data.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020031#include "tree_data_internal.h"
32#include "tree_schema.h"
Radek Krejci77114102021-03-10 15:21:57 +010033#include "tree_schema_internal.h"
Michal Vaskocde73ac2019-11-14 16:10:27 +010034#include "validation.h"
Radek Krejci535ea9f2020-05-29 16:01:05 +020035#include "xml.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020036
Radek Krejci1798aae2020-07-14 13:26:06 +020037void
38lyd_xml_ctx_free(struct lyd_ctx *lydctx)
39{
40 struct lyd_xml_ctx *ctx = (struct lyd_xml_ctx *)lydctx;
41
42 lyd_ctx_free(lydctx);
43 lyxml_ctx_free(ctx->xmlctx);
44 free(ctx);
45}
46
Michal Vasko45791ad2021-06-17 08:45:03 +020047/**
48 * @brief Parse and create XML metadata.
49 *
50 * @param[in] lydctx XML data parser context.
51 * @param[in] parent_exts Extension instances of the parent node.
52 * @param[out] meta List of created metadata instances.
53 * @return LY_ERR value.
54 */
Radek Krejcie7b95092019-05-15 11:03:07 +020055static LY_ERR
Michal Vasko45791ad2021-06-17 08:45:03 +020056lydxml_metadata(struct lyd_xml_ctx *lydctx, struct lysc_ext_instance *parent_exts, struct lyd_meta **meta)
Radek Krejcie7b95092019-05-15 11:03:07 +020057{
aPiecek1c4da362021-04-29 14:26:34 +020058 LY_ERR ret = LY_SUCCESS;
Radek Krejci28681fa2019-09-06 13:08:45 +020059 const struct lyxml_ns *ns;
60 struct lys_module *mod;
Michal Vaskob36053d2020-03-26 15:49:30 +010061 const char *name;
62 size_t name_len;
Michal Vasko45791ad2021-06-17 08:45:03 +020063 LY_ARRAY_COUNT_TYPE u;
64 ly_bool filter_attrs = 0;
Radek Krejci1798aae2020-07-14 13:26:06 +020065 struct lyxml_ctx *xmlctx = lydctx->xmlctx;
Radek Krejci28681fa2019-09-06 13:08:45 +020066
Michal Vaskob36053d2020-03-26 15:49:30 +010067 *meta = NULL;
Radek Krejci28681fa2019-09-06 13:08:45 +020068
Michal Vasko45791ad2021-06-17 08:45:03 +020069 /* check for NETCONF filter unqualified attributes */
70 LY_ARRAY_FOR(parent_exts, u) {
71 if (!strcmp(parent_exts[u].def->name, "get-filter-element-attributes") &&
72 !strcmp(parent_exts[u].def->module->name, "ietf-netconf")) {
73 filter_attrs = 1;
74 break;
75 }
76 }
77
Michal Vaskob36053d2020-03-26 15:49:30 +010078 while (xmlctx->status == LYXML_ATTRIBUTE) {
79 if (!xmlctx->prefix_len) {
Michal Vasko45791ad2021-06-17 08:45:03 +020080 /* in XML all attributes must be prefixed except NETCONF filter ones marked by an extension */
81 if (filter_attrs && (!ly_strncmp("type", xmlctx->name, xmlctx->name_len) ||
82 !ly_strncmp("select", xmlctx->name, xmlctx->name_len))) {
83 mod = ly_ctx_get_module_implemented(xmlctx->ctx, "ietf-netconf");
84 if (!mod) {
85 LOGVAL(xmlctx->ctx, LYVE_REFERENCE,
86 "Missing (or not implemented) YANG module \"ietf-netconf\" for special filter attributes.");
87 ret = LY_ENOTFOUND;
88 goto cleanup;
89 }
90 goto create_meta;
91 }
92
Michal Vaskoe0665742021-02-11 11:08:44 +010093 if (lydctx->parse_opts & LYD_PARSE_STRICT) {
Radek Krejci2efc45b2020-12-22 16:25:44 +010094 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Missing mandatory prefix for XML metadata \"%.*s\".",
Radek Krejci422afb12021-03-04 16:38:16 +010095 (int)xmlctx->name_len, xmlctx->name);
Michal Vasko45791ad2021-06-17 08:45:03 +020096 ret = LY_EVALID;
Michal Vaskob36053d2020-03-26 15:49:30 +010097 goto cleanup;
Radek Krejci28681fa2019-09-06 13:08:45 +020098 }
Michal Vaskob36053d2020-03-26 15:49:30 +010099
Michal Vasko45791ad2021-06-17 08:45:03 +0200100 /* skip attr */
Michal Vaskob36053d2020-03-26 15:49:30 +0100101 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
102 assert(xmlctx->status == LYXML_ATTR_CONTENT);
103 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Radek Krejci28681fa2019-09-06 13:08:45 +0200104 continue;
105 }
106
107 /* get namespace of the attribute to find its annotation definition */
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200108 ns = lyxml_ns_get(&xmlctx->ns, xmlctx->prefix, xmlctx->prefix_len);
Radek Krejci28681fa2019-09-06 13:08:45 +0200109 if (!ns) {
Michal Vasko52927e22020-03-16 17:26:14 +0100110 /* unknown namespace, XML error */
Radek Krejci422afb12021-03-04 16:38:16 +0100111 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)xmlctx->prefix_len, xmlctx->prefix);
Michal Vasko45791ad2021-06-17 08:45:03 +0200112 ret = LY_ENOTFOUND;
Radek Krejci28681fa2019-09-06 13:08:45 +0200113 goto cleanup;
114 }
Michal Vasko45791ad2021-06-17 08:45:03 +0200115
116 /* get the module with metadata definition */
Michal Vasko52927e22020-03-16 17:26:14 +0100117 mod = ly_ctx_get_module_implemented_ns(xmlctx->ctx, ns->uri);
Radek Krejci28681fa2019-09-06 13:08:45 +0200118 if (!mod) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100119 if (lydctx->parse_opts & LYD_PARSE_STRICT) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100120 LOGVAL(xmlctx->ctx, LYVE_REFERENCE,
Michal Vasko69730152020-10-09 16:30:07 +0200121 "Unknown (or not implemented) YANG module with namespace \"%s\" for metadata \"%.*s%s%.*s\".",
Radek Krejci422afb12021-03-04 16:38:16 +0100122 ns->uri, (int)xmlctx->prefix_len, xmlctx->prefix, xmlctx->prefix_len ? ":" : "",
123 (int)xmlctx->name_len, xmlctx->name);
Michal Vasko45791ad2021-06-17 08:45:03 +0200124 ret = LY_ENOTFOUND;
Michal Vaskob36053d2020-03-26 15:49:30 +0100125 goto cleanup;
Radek Krejci28681fa2019-09-06 13:08:45 +0200126 }
Michal Vasko45791ad2021-06-17 08:45:03 +0200127
128 /* skip attr */
129 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
130 assert(xmlctx->status == LYXML_ATTR_CONTENT);
131 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
132 continue;
Radek Krejci28681fa2019-09-06 13:08:45 +0200133 }
134
Michal Vasko45791ad2021-06-17 08:45:03 +0200135create_meta:
Michal Vasko60ea6352020-06-29 13:39:39 +0200136 /* remember meta name and get its content */
Michal Vaskob36053d2020-03-26 15:49:30 +0100137 name = xmlctx->name;
138 name_len = xmlctx->name_len;
139 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
140 assert(xmlctx->status == LYXML_ATTR_CONTENT);
141
142 /* create metadata */
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200143 ret = lyd_parser_create_meta((struct lyd_ctx *)lydctx, NULL, meta, mod, name, name_len, xmlctx->value,
Radek Krejci8df109d2021-04-23 12:19:08 +0200144 xmlctx->value_len, &xmlctx->dynamic, LY_VALUE_XML, &xmlctx->ns, LYD_HINT_DATA);
Radek Krejci1798aae2020-07-14 13:26:06 +0200145 LY_CHECK_GOTO(ret, cleanup);
Michal Vaskob36053d2020-03-26 15:49:30 +0100146
147 /* next attribute */
148 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Radek Krejcie7b95092019-05-15 11:03:07 +0200149 }
Michal Vasko52927e22020-03-16 17:26:14 +0100150
Radek Krejcie7b95092019-05-15 11:03:07 +0200151cleanup:
Michal Vaskob36053d2020-03-26 15:49:30 +0100152 if (ret) {
Michal Vasko3a41dff2020-07-15 14:30:28 +0200153 lyd_free_meta_siblings(*meta);
Michal Vaskob36053d2020-03-26 15:49:30 +0100154 *meta = NULL;
Radek Krejci38d85362019-09-05 16:26:38 +0200155 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200156 return ret;
157}
158
Michal Vasko52927e22020-03-16 17:26:14 +0100159static LY_ERR
Radek Krejci1798aae2020-07-14 13:26:06 +0200160lydxml_attrs(struct lyxml_ctx *xmlctx, struct lyd_attr **attr)
Michal Vasko52927e22020-03-16 17:26:14 +0100161{
162 LY_ERR ret = LY_SUCCESS;
163 const struct lyxml_ns *ns;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100164 void *val_prefix_data;
Radek Krejci8df109d2021-04-23 12:19:08 +0200165 LY_VALUE_FORMAT format;
Radek Krejci1798aae2020-07-14 13:26:06 +0200166 struct lyd_attr *attr2;
Michal Vaskob36053d2020-03-26 15:49:30 +0100167 const char *name, *prefix;
168 size_t name_len, prefix_len;
Michal Vasko52927e22020-03-16 17:26:14 +0100169
170 assert(attr);
Michal Vaskob36053d2020-03-26 15:49:30 +0100171 *attr = NULL;
Michal Vasko52927e22020-03-16 17:26:14 +0100172
Michal Vaskob36053d2020-03-26 15:49:30 +0100173 while (xmlctx->status == LYXML_ATTRIBUTE) {
Michal Vasko52927e22020-03-16 17:26:14 +0100174 if (*attr) {
175 attr2 = *attr;
176 } else {
177 attr2 = NULL;
178 }
179
Michal Vaskob36053d2020-03-26 15:49:30 +0100180 /* remember attr prefix, name, and get its content */
181 prefix = xmlctx->prefix;
182 prefix_len = xmlctx->prefix_len;
183 name = xmlctx->name;
184 name_len = xmlctx->name_len;
185 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
186 assert(xmlctx->status == LYXML_ATTR_CONTENT);
187
Michal Vaskoe137fc42021-07-22 11:53:13 +0200188 /* handle special "xml" attribute prefix */
189 if ((prefix_len == 3) && !strncmp(prefix, "xml", 3)) {
190 name = prefix;
191 name_len += 1 + prefix_len;
192 prefix = NULL;
193 prefix_len = 0;
194 }
195
196 /* find namespace of the attribute, if any */
197 ns = NULL;
198 if (prefix_len) {
199 ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
200 if (!ns) {
201 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)prefix_len, prefix);
202 ret = LY_EVALID;
203 goto cleanup;
204 }
205 }
206
Michal Vasko52927e22020-03-16 17:26:14 +0100207 /* get value prefixes */
Michal Vaskofc2cd072021-02-24 13:17:17 +0100208 val_prefix_data = NULL;
Radek Krejci8df109d2021-04-23 12:19:08 +0200209 LY_CHECK_GOTO(ret = ly_store_prefix_data(xmlctx->ctx, xmlctx->value, xmlctx->value_len, LY_VALUE_XML,
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100210 &xmlctx->ns, &format, &val_prefix_data), cleanup);
Michal Vasko52927e22020-03-16 17:26:14 +0100211
212 /* attr2 is always changed to the created attribute */
Michal Vasko501af032020-11-11 20:27:44 +0100213 ret = lyd_create_attr(NULL, &attr2, xmlctx->ctx, name, name_len, prefix, prefix_len, ns ? ns->uri : NULL,
Michal Vasko8589d0a2022-02-01 13:15:08 +0100214 ns ? strlen(ns->uri) : 0, xmlctx->value, xmlctx->value_len, &xmlctx->dynamic, format, val_prefix_data,
215 LYD_HINT_DATA);
Michal Vasko52927e22020-03-16 17:26:14 +0100216 LY_CHECK_GOTO(ret, cleanup);
217
218 if (!*attr) {
219 *attr = attr2;
220 }
Michal Vaskob36053d2020-03-26 15:49:30 +0100221
222 /* next attribute */
223 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko52927e22020-03-16 17:26:14 +0100224 }
225
226cleanup:
Michal Vaskob36053d2020-03-26 15:49:30 +0100227 if (ret) {
Radek Krejci011e4aa2020-09-04 15:22:31 +0200228 lyd_free_attr_siblings(xmlctx->ctx, *attr);
Michal Vaskob36053d2020-03-26 15:49:30 +0100229 *attr = NULL;
Michal Vasko52927e22020-03-16 17:26:14 +0100230 }
Michal Vasko52927e22020-03-16 17:26:14 +0100231 return ret;
232}
233
Michal Vasko44685da2020-03-17 15:38:06 +0100234static LY_ERR
Michal Vaskob36053d2020-03-26 15:49:30 +0100235lydxml_check_list(struct lyxml_ctx *xmlctx, const struct lysc_node *list)
Michal Vasko44685da2020-03-17 15:38:06 +0100236{
Michal Vaskob36053d2020-03-26 15:49:30 +0100237 LY_ERR ret = LY_SUCCESS, r;
238 enum LYXML_PARSER_STATUS next;
Michal Vasko44685da2020-03-17 15:38:06 +0100239 struct ly_set key_set = {0};
240 const struct lysc_node *snode;
Michal Vaskob36053d2020-03-26 15:49:30 +0100241 uint32_t i, parents_count;
Michal Vasko44685da2020-03-17 15:38:06 +0100242
243 assert(list && (list->nodetype == LYS_LIST));
244
245 /* get all keys into a set (keys do not have if-features or anything) */
246 snode = NULL;
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100247 while ((snode = lys_getnext(snode, list, NULL, 0)) && (snode->flags & LYS_KEY)) {
Radek Krejci3d92e442020-10-12 12:48:13 +0200248 ret = ly_set_add(&key_set, (void *)snode, 1, NULL);
Radek Krejciba03a5a2020-08-27 14:40:41 +0200249 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100250 }
251
Michal Vasko12d809c2021-03-03 16:34:32 +0100252 /* remember parent count */
253 parents_count = xmlctx->elements.count;
254
Michal Vaskob36053d2020-03-26 15:49:30 +0100255 while (xmlctx->status == LYXML_ELEMENT) {
Michal Vasko44685da2020-03-17 15:38:06 +0100256 /* find key definition */
257 for (i = 0; i < key_set.count; ++i) {
258 snode = (const struct lysc_node *)key_set.objs[i];
Michal Vaskob36053d2020-03-26 15:49:30 +0100259 if (!ly_strncmp(snode->name, xmlctx->name, xmlctx->name_len)) {
Michal Vasko44685da2020-03-17 15:38:06 +0100260 break;
261 }
262 }
Michal Vaskob36053d2020-03-26 15:49:30 +0100263 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100264
265 /* skip attributes */
266 while (xmlctx->status == LYXML_ATTRIBUTE) {
Michal Vaskob36053d2020-03-26 15:49:30 +0100267 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
268 assert(xmlctx->status == LYXML_ATTR_CONTENT);
269 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100270 }
271
Michal Vaskob36053d2020-03-26 15:49:30 +0100272 assert(xmlctx->status == LYXML_ELEM_CONTENT);
273 if (i < key_set.count) {
274 /* validate the value */
Radek Krejci8df109d2021-04-23 12:19:08 +0200275 r = lys_value_validate(NULL, snode, xmlctx->value, xmlctx->value_len, LY_VALUE_XML, &xmlctx->ns);
Michal Vaskob36053d2020-03-26 15:49:30 +0100276 if (!r) {
277 /* key with a valid value, remove from the set */
278 ly_set_rm_index(&key_set, i, NULL);
Michal Vasko44685da2020-03-17 15:38:06 +0100279 }
280 }
281
Michal Vaskob36053d2020-03-26 15:49:30 +0100282 /* parser next */
283 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100284
Michal Vaskob36053d2020-03-26 15:49:30 +0100285 /* skip any children, resursively */
Michal Vasko12d809c2021-03-03 16:34:32 +0100286 while (xmlctx->status == LYXML_ELEMENT) {
287 while (parents_count < xmlctx->elements.count) {
288 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
289 }
290 assert(xmlctx->status == LYXML_ELEM_CLOSE);
Michal Vaskob36053d2020-03-26 15:49:30 +0100291 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
292 }
293
294 /* parser next, but do not parse closing element of the list because it would remove its namespaces */
295 assert(xmlctx->status == LYXML_ELEM_CLOSE);
296 LY_CHECK_GOTO(ret = lyxml_ctx_peek(xmlctx, &next), cleanup);
297 if (next != LYXML_ELEM_CLOSE) {
298 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
299 }
Michal Vasko44685da2020-03-17 15:38:06 +0100300 }
301
302 if (key_set.count) {
Michal Vaskob36053d2020-03-26 15:49:30 +0100303 /* some keys are missing/did not validate */
Michal Vasko44685da2020-03-17 15:38:06 +0100304 ret = LY_ENOT;
Michal Vasko44685da2020-03-17 15:38:06 +0100305 }
306
307cleanup:
308 ly_set_erase(&key_set, NULL);
309 return ret;
310}
311
Michal Vasko5c24ed12021-06-09 09:27:32 +0200312/**
313 * @brief Skip an element with all its descendants.
314 *
315 * @param[in] xmlctx XML parser context.
316 * @return LY_ERR value.
317 */
Michal Vasko1bf09392020-03-27 12:38:10 +0100318static LY_ERR
319lydxml_data_skip(struct lyxml_ctx *xmlctx)
320{
321 uint32_t parents_count;
322
323 /* remember current number of parents */
324 parents_count = xmlctx->elements.count;
aPiecek9cdb9e62021-05-18 09:46:20 +0200325 assert(parents_count);
Michal Vasko1bf09392020-03-27 12:38:10 +0100326
327 /* skip after the content */
328 while (xmlctx->status != LYXML_ELEM_CONTENT) {
329 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
330 }
331 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
332
333 /* skip all children elements, recursively, if any */
aPiecek9cdb9e62021-05-18 09:46:20 +0200334 while (parents_count <= xmlctx->elements.count) {
Michal Vasko1bf09392020-03-27 12:38:10 +0100335 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
336 }
337
338 /* close element */
339 assert(xmlctx->status == LYXML_ELEM_CLOSE);
340 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
341
342 return LY_SUCCESS;
343}
344
Michal Vasko5c24ed12021-06-09 09:27:32 +0200345/**
346 * @brief Check that the current element can be parsed as a data node.
347 *
348 * @param[in] lydctx XML data parser context.
349 * @param[in,out] snode Found schema node, set to NULL if data node cannot be created.
350 * @return LY_ERR value.
351 */
Michal Vasko1bf09392020-03-27 12:38:10 +0100352static LY_ERR
Radek Krejci1798aae2020-07-14 13:26:06 +0200353lydxml_data_check_opaq(struct lyd_xml_ctx *lydctx, const struct lysc_node **snode)
Michal Vasko1bf09392020-03-27 12:38:10 +0100354{
355 LY_ERR ret = LY_SUCCESS;
Michal Vaskoda8fbbf2021-06-16 11:44:44 +0200356 struct lyxml_ctx *xmlctx = lydctx->xmlctx, pxmlctx;
Michal Vasko1bf09392020-03-27 12:38:10 +0100357
Radek IÅ¡a3930fd72021-03-08 10:48:40 +0100358 if (!(lydctx->parse_opts & LYD_PARSE_OPAQ)) {
359 /* only checks specific to opaque nodes */
360 return LY_SUCCESS;
361 }
362
Michal Vasko13854662021-06-09 09:27:50 +0200363 if (!((*snode)->nodetype & (LYD_NODE_TERM | LYD_NODE_INNER))) {
364 /* nothing to check */
365 return LY_SUCCESS;
366 }
Michal Vasko1bf09392020-03-27 12:38:10 +0100367
Michal Vaskoda8fbbf2021-06-16 11:44:44 +0200368 assert(xmlctx->elements.count);
369
Michal Vasko13854662021-06-09 09:27:50 +0200370 /* backup parser */
Michal Vaskoda8fbbf2021-06-16 11:44:44 +0200371 LY_CHECK_RET(lyxml_ctx_backup(xmlctx, &pxmlctx));
Michal Vasko1bf09392020-03-27 12:38:10 +0100372
Michal Vasko13854662021-06-09 09:27:50 +0200373 /* skip attributes */
374 while (xmlctx->status == LYXML_ATTRIBUTE) {
375 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), restore);
376 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), restore);
377 }
Michal Vasko1bf09392020-03-27 12:38:10 +0100378
Michal Vasko13854662021-06-09 09:27:50 +0200379 if ((*snode)->nodetype & LYD_NODE_TERM) {
380 /* value may not be valid in which case we parse it as an opaque node */
381 if (lys_value_validate(NULL, *snode, xmlctx->value, xmlctx->value_len, LY_VALUE_XML, &xmlctx->ns)) {
Michal Vaskod0237d42021-07-12 14:49:46 +0200382 LOGVRB("Parsing opaque term node \"%s\" with invalid value \"%.*s\".", (*snode)->name, xmlctx->value_len,
383 xmlctx->value);
Michal Vasko13854662021-06-09 09:27:50 +0200384 *snode = NULL;
Michal Vasko1bf09392020-03-27 12:38:10 +0100385 }
Michal Vasko13854662021-06-09 09:27:50 +0200386 } else if ((*snode)->nodetype == LYS_LIST) {
387 /* skip content */
388 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), restore);
Michal Vasko1bf09392020-03-27 12:38:10 +0100389
Michal Vasko13854662021-06-09 09:27:50 +0200390 if (lydxml_check_list(xmlctx, *snode)) {
391 /* invalid list, parse as opaque if it missing/has invalid some keys */
Michal Vaskod0237d42021-07-12 14:49:46 +0200392 LOGVRB("Parsing opaque list node \"%s\" with missing/invalid keys.", (*snode)->name);
Michal Vasko13854662021-06-09 09:27:50 +0200393 *snode = NULL;
Michal Vasko1bf09392020-03-27 12:38:10 +0100394 }
Michal Vasko13854662021-06-09 09:27:50 +0200395 } else {
Radek IÅ¡a3930fd72021-03-08 10:48:40 +0100396 /* if there is a non-WS value, it cannot be parsed as an inner node */
397 assert(xmlctx->status == LYXML_ELEM_CONTENT);
398 if (!xmlctx->ws_only) {
399 *snode = NULL;
400 }
Michal Vasko1bf09392020-03-27 12:38:10 +0100401 }
402
Michal Vasko13854662021-06-09 09:27:50 +0200403restore:
404 /* restore parser */
Michal Vaskoda8fbbf2021-06-16 11:44:44 +0200405 lyxml_ctx_restore(xmlctx, &pxmlctx);
Michal Vasko1bf09392020-03-27 12:38:10 +0100406 return ret;
407}
408
Radek Krejcie7b95092019-05-15 11:03:07 +0200409/**
Michal Vaskoa5da3292020-08-12 13:10:50 +0200410 * @brief Parse XML subtree.
Radek Krejcie7b95092019-05-15 11:03:07 +0200411 *
Michal Vaskob36053d2020-03-26 15:49:30 +0100412 * @param[in] lydctx XML YANG data parser context.
Michal Vaskoe0665742021-02-11 11:08:44 +0100413 * @param[in,out] parent Parent node where the children are inserted. NULL in case of parsing top-level elements.
414 * @param[in,out] first_p Pointer to the first (@p parent or top-level) child. In case there were already some siblings,
415 * this may point to a previously existing node.
416 * @param[in,out] parsed Optional set to add all the parsed siblings into.
Michal Vasko9b368d32020-02-14 13:53:31 +0100417 * @return LY_ERR value.
Radek Krejcie7b95092019-05-15 11:03:07 +0200418 */
419static LY_ERR
Michal Vaskoe0665742021-02-11 11:08:44 +0100420lydxml_subtree_r(struct lyd_xml_ctx *lydctx, struct lyd_node *parent, struct lyd_node **first_p, struct ly_set *parsed)
Radek Krejcie7b95092019-05-15 11:03:07 +0200421{
tadeas-vintrlikbf8aa6e2021-11-03 13:07:34 +0100422 LY_ERR ret = LY_SUCCESS, r;
423 LY_ARRAY_COUNT_TYPE u;
424
425 lyplg_ext_data_parse_clb ext_parse;
Michal Vasko27c4dce2021-03-04 15:50:50 +0100426 const char *prefix, *name, *val;
Michal Vasko1bf09392020-03-27 12:38:10 +0100427 size_t prefix_len, name_len;
Michal Vaskob36053d2020-03-26 15:49:30 +0100428 struct lyxml_ctx *xmlctx;
429 const struct ly_ctx *ctx;
Radek Krejcie7b95092019-05-15 11:03:07 +0200430 const struct lyxml_ns *ns;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200431 struct lyd_meta *meta = NULL;
432 struct lyd_attr *attr = NULL;
Radek Krejcie7b95092019-05-15 11:03:07 +0200433 const struct lysc_node *snode;
434 struct lys_module *mod;
Michal Vaskoa98e3ea2021-06-03 09:13:33 +0200435 uint32_t prev_parse_opts, prev_int_opts;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200436 struct lyd_node *node = NULL, *anchor;
Michal Vaskofc2cd072021-02-24 13:17:17 +0100437 void *val_prefix_data = NULL;
tadeas-vintrlikbf8aa6e2021-11-03 13:07:34 +0100438 struct lysc_ext_instance *exts = NULL;
Radek Krejci8df109d2021-04-23 12:19:08 +0200439 LY_VALUE_FORMAT format;
Radek Krejci1deb5be2020-08-26 16:43:36 +0200440 uint32_t getnext_opts;
Radek Krejcie7b95092019-05-15 11:03:07 +0200441
Michal Vaskoe0665742021-02-11 11:08:44 +0100442 assert(parent || first_p);
443
Michal Vaskob36053d2020-03-26 15:49:30 +0100444 xmlctx = lydctx->xmlctx;
445 ctx = xmlctx->ctx;
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100446 getnext_opts = lydctx->int_opts & LYD_INTOPT_REPLY ? LYS_GETNEXT_OUTPUT : 0;
Michal Vasko6f4cbb62020-02-28 11:15:47 +0100447
Michal Vaskoa5da3292020-08-12 13:10:50 +0200448 assert(xmlctx->status == LYXML_ELEMENT);
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200449
Michal Vaskoa5da3292020-08-12 13:10:50 +0200450 /* remember element prefix and name */
451 prefix = xmlctx->prefix;
452 prefix_len = xmlctx->prefix_len;
453 name = xmlctx->name;
454 name_len = xmlctx->name_len;
455
456 /* get the element module */
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200457 ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200458 if (!ns) {
Radek Krejci422afb12021-03-04 16:38:16 +0100459 LOGVAL(ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)prefix_len, prefix);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200460 ret = LY_EVALID;
461 goto error;
462 }
463 mod = ly_ctx_get_module_implemented_ns(ctx, ns->uri);
464 if (!mod) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100465 if (lydctx->parse_opts & LYD_PARSE_STRICT) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100466 LOGVAL(ctx, LYVE_REFERENCE, "No module with namespace \"%s\" in the context.", ns->uri);
Michal Vasko90932a92020-02-12 14:33:03 +0100467 ret = LY_EVALID;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200468 goto error;
Radek Krejcie7b95092019-05-15 11:03:07 +0200469 }
Michal Vaskoe0665742021-02-11 11:08:44 +0100470 if (!(lydctx->parse_opts & LYD_PARSE_OPAQ)) {
Michal Vaskoa5da3292020-08-12 13:10:50 +0200471 /* skip element with children */
472 LY_CHECK_GOTO(ret = lydxml_data_skip(xmlctx), error);
473 return LY_SUCCESS;
Radek Krejcie7b95092019-05-15 11:03:07 +0200474 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200475 }
476
Michal Vaskoa5da3292020-08-12 13:10:50 +0200477 /* parser next */
478 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
Michal Vasko90932a92020-02-12 14:33:03 +0100479
Michal Vaskoa5da3292020-08-12 13:10:50 +0200480 /* get the schema node */
481 snode = NULL;
Michal Vasko81008a52021-07-21 16:06:12 +0200482 if (mod) {
Radek Krejcif16e2542021-02-17 15:39:23 +0100483 if (!parent && lydctx->ext) {
Radek Krejciba05eab2021-03-10 13:19:29 +0100484 snode = lysc_ext_find_node(lydctx->ext, mod, name, name_len, 0, getnext_opts);
Radek Krejcif16e2542021-02-17 15:39:23 +0100485 } else {
486 snode = lys_find_child(parent ? parent->schema : NULL, mod, name, name_len, 0, getnext_opts);
487 }
Michal Vaskoa5da3292020-08-12 13:10:50 +0200488 if (!snode) {
tadeas-vintrlikbf8aa6e2021-11-03 13:07:34 +0100489 /* Check if data of an extension */
490 if (parent && parent->schema) {
491 exts = parent->schema->exts;
492 }
493 LY_ARRAY_FOR(exts, u) {
494 ext_parse = exts[u].def->plugin->parse;
495 r = ext_parse(xmlctx->in, LYD_XML, &exts[u], parent, lydctx->parse_opts,
496 lydctx->val_opts);
497 if (r == LY_SUCCESS) {
498 /* Data was from this module*/
499 return LY_SUCCESS;
500 } else if (r != LY_ENOT) {
501 /* Error while parsing */
502 }
503 /* Data was not from this module */
504 }
Michal Vaskoe0665742021-02-11 11:08:44 +0100505 if (lydctx->parse_opts & LYD_PARSE_STRICT) {
506 if (parent) {
Radek Krejci422afb12021-03-04 16:38:16 +0100507 LOGVAL(ctx, LYVE_REFERENCE, "Node \"%.*s\" not found as a child of \"%s\" node.",
508 (int)name_len, name, parent->schema->name);
Radek Krejcif16e2542021-02-17 15:39:23 +0100509 } else if (lydctx->ext) {
510 if (lydctx->ext->argument) {
Radek Krejci422afb12021-03-04 16:38:16 +0100511 LOGVAL(ctx, LYVE_REFERENCE, "Node \"%.*s\" not found in the \"%s\" %s extension instance.",
512 (int)name_len, name, lydctx->ext->argument, lydctx->ext->def->name);
Radek Krejcif16e2542021-02-17 15:39:23 +0100513 } else {
Radek Krejci422afb12021-03-04 16:38:16 +0100514 LOGVAL(ctx, LYVE_REFERENCE, "Node \"%.*s\" not found in the %s extension instance.",
515 (int)name_len, name, lydctx->ext->def->name);
Radek Krejcif16e2542021-02-17 15:39:23 +0100516 }
Michal Vaskoe0665742021-02-11 11:08:44 +0100517 } else {
Radek Krejci422afb12021-03-04 16:38:16 +0100518 LOGVAL(ctx, LYVE_REFERENCE, "Node \"%.*s\" not found in the \"%s\" module.",
519 (int)name_len, name, mod->name);
Michal Vaskoe0665742021-02-11 11:08:44 +0100520 }
Michal Vaskoa5da3292020-08-12 13:10:50 +0200521 ret = LY_EVALID;
522 goto error;
Michal Vaskoe0665742021-02-11 11:08:44 +0100523 } else if (!(lydctx->parse_opts & LYD_PARSE_OPAQ)) {
Michal Vaskod4f82492022-01-05 12:06:51 +0100524 LOGVRB("Skipping parsing of unknown node \"%.*s\".", name_len, name);
Michal Vaskod0237d42021-07-12 14:49:46 +0200525
Michal Vaskoa5da3292020-08-12 13:10:50 +0200526 /* skip element with children */
527 LY_CHECK_GOTO(ret = lydxml_data_skip(xmlctx), error);
528 return LY_SUCCESS;
529 }
530 } else {
531 /* check that schema node is valid and can be used */
532 LY_CHECK_GOTO(ret = lyd_parser_check_schema((struct lyd_ctx *)lydctx, snode), error);
533 LY_CHECK_GOTO(ret = lydxml_data_check_opaq(lydctx, &snode), error);
534 }
535 }
536
537 /* create metadata/attributes */
538 if (xmlctx->status == LYXML_ATTRIBUTE) {
539 if (snode) {
Michal Vasko45791ad2021-06-17 08:45:03 +0200540 ret = lydxml_metadata(lydctx, snode->exts, &meta);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200541 LY_CHECK_GOTO(ret, error);
542 } else {
Michal Vaskoe0665742021-02-11 11:08:44 +0100543 assert(lydctx->parse_opts & LYD_PARSE_OPAQ);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200544 ret = lydxml_attrs(xmlctx, &attr);
545 LY_CHECK_GOTO(ret, error);
546 }
547 }
548
549 assert(xmlctx->status == LYXML_ELEM_CONTENT);
550 if (!snode) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100551 assert(lydctx->parse_opts & LYD_PARSE_OPAQ);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200552
553 if (xmlctx->ws_only) {
554 /* ignore WS-only value */
Radek IÅ¡a017270d2021-02-16 10:26:15 +0100555 if (xmlctx->dynamic) {
556 free((char *) xmlctx->value);
557 }
558 xmlctx->dynamic = 0;
559 xmlctx->value = "";
Michal Vaskoa5da3292020-08-12 13:10:50 +0200560 xmlctx->value_len = 0;
Radek Krejci8df109d2021-04-23 12:19:08 +0200561 format = LY_VALUE_XML;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200562 } else {
563 /* get value prefixes */
Radek Krejci8df109d2021-04-23 12:19:08 +0200564 ret = ly_store_prefix_data(xmlctx->ctx, xmlctx->value, xmlctx->value_len, LY_VALUE_XML,
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100565 &xmlctx->ns, &format, &val_prefix_data);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200566 LY_CHECK_GOTO(ret, error);
567 }
568
Michal Vaskoda8fbbf2021-06-16 11:44:44 +0200569 /* get NS again, it may have been backed up and restored */
570 ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
571 assert(ns);
572
Michal Vaskoa5da3292020-08-12 13:10:50 +0200573 /* create node */
Michal Vasko501af032020-11-11 20:27:44 +0100574 ret = lyd_create_opaq(ctx, name, name_len, prefix, prefix_len, ns->uri, strlen(ns->uri), xmlctx->value,
575 xmlctx->value_len, &xmlctx->dynamic, format, val_prefix_data, LYD_HINT_DATA, &node);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200576 LY_CHECK_GOTO(ret, error);
577
578 /* parser next */
579 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
580
581 /* process children */
582 while (xmlctx->status == LYXML_ELEMENT) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100583 ret = lydxml_subtree_r(lydctx, node, lyd_node_child_p(node), NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200584 LY_CHECK_GOTO(ret, error);
585 }
586 } else if (snode->nodetype & LYD_NODE_TERM) {
587 /* create node */
Michal Vasko22df3f02020-08-24 13:29:22 +0200588 LY_CHECK_GOTO(ret = lyd_parser_create_term((struct lyd_ctx *)lydctx, snode, xmlctx->value, xmlctx->value_len,
Radek Krejci8df109d2021-04-23 12:19:08 +0200589 &xmlctx->dynamic, LY_VALUE_XML, &xmlctx->ns, LYD_HINT_DATA, &node), error);
Radek Krejciddace2c2021-01-08 11:30:56 +0100590 LOG_LOCSET(snode, node, NULL, NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200591
592 if (parent && (node->schema->flags & LYS_KEY)) {
593 /* check the key order, the anchor must never be a key */
Michal Vaskoe0665742021-02-11 11:08:44 +0100594 anchor = lyd_insert_get_next_anchor(lyd_child(parent), node);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200595 if (anchor && (anchor->schema->flags & LYS_KEY)) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100596 if (lydctx->parse_opts & LYD_PARSE_STRICT) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100597 LOGVAL(ctx, LYVE_DATA, "Invalid position of the key \"%s\" in a list.", node->schema->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200598 ret = LY_EVALID;
599 goto error;
600 } else {
601 LOGWRN(ctx, "Invalid position of the key \"%s\" in a list.", node->schema->name);
602 }
603 }
604 }
605
606 /* parser next */
607 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
608
609 /* no children expected */
610 if (xmlctx->status == LYXML_ELEMENT) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100611 LOGVAL(ctx, LYVE_SYNTAX, "Child element \"%.*s\" inside a terminal node \"%s\" found.",
Radek Krejci422afb12021-03-04 16:38:16 +0100612 (int)xmlctx->name_len, xmlctx->name, snode->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200613 ret = LY_EVALID;
614 goto error;
615 }
616 } else if (snode->nodetype & LYD_NODE_INNER) {
617 if (!xmlctx->ws_only) {
618 /* value in inner node */
Radek Krejci2efc45b2020-12-22 16:25:44 +0100619 LOGVAL(ctx, LYVE_SYNTAX, "Text value \"%.*s\" inside an inner node \"%s\" found.",
Radek Krejci422afb12021-03-04 16:38:16 +0100620 (int)xmlctx->value_len, xmlctx->value, snode->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200621 ret = LY_EVALID;
622 goto error;
623 }
624
625 /* create node */
626 ret = lyd_create_inner(snode, &node);
627 LY_CHECK_GOTO(ret, error);
628
Radek Krejciddace2c2021-01-08 11:30:56 +0100629 LOG_LOCSET(snode, node, NULL, NULL);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100630
Michal Vaskoa5da3292020-08-12 13:10:50 +0200631 /* parser next */
632 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
633
634 /* process children */
635 while (xmlctx->status == LYXML_ELEMENT) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100636 ret = lydxml_subtree_r(lydctx, node, lyd_node_child_p(node), NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200637 LY_CHECK_GOTO(ret, error);
638 }
639
640 if (snode->nodetype == LYS_LIST) {
641 /* check all keys exist */
642 LY_CHECK_GOTO(ret = lyd_parse_check_keys(node), error);
643 }
644
Michal Vaskoe0665742021-02-11 11:08:44 +0100645 if (!(lydctx->parse_opts & LYD_PARSE_ONLY)) {
Michal Vaskoa5da3292020-08-12 13:10:50 +0200646 /* new node validation, autodelete CANNOT occur, all nodes are new */
Michal Vaskoe0665742021-02-11 11:08:44 +0100647 ret = lyd_validate_new(lyd_node_child_p(node), snode, NULL, NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200648 LY_CHECK_GOTO(ret, error);
649
650 /* add any missing default children */
Radek Krejci4f2e3e52021-03-30 14:20:28 +0200651 ret = lyd_new_implicit_r(node, lyd_node_child_p(node), NULL, NULL, &lydctx->node_when, &lydctx->node_exts,
652 &lydctx->node_types, (lydctx->val_opts & LYD_VALIDATE_NO_STATE) ? LYD_IMPLICIT_NO_STATE : 0, NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200653 LY_CHECK_GOTO(ret, error);
654 }
655
656 if (snode->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) {
657 /* rememeber the RPC/action/notification */
658 lydctx->op_node = node;
659 }
660 } else if (snode->nodetype & LYD_NODE_ANY) {
Michal Vasko27c4dce2021-03-04 15:50:50 +0100661 if ((snode->nodetype == LYS_ANYDATA) && !xmlctx->ws_only) {
662 /* value in anydata node, we expect a tree */
663 LOGVAL(ctx, LYVE_SYNTAX, "Text value \"%.*s\" inside an anydata node \"%s\" found.",
Radek Krejci422afb12021-03-04 16:38:16 +0100664 (int)xmlctx->value_len < 20 ? xmlctx->value_len : 20, xmlctx->value, snode->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200665 ret = LY_EVALID;
666 goto error;
667 }
668
Michal Vasko27c4dce2021-03-04 15:50:50 +0100669 if (!xmlctx->ws_only) {
670 /* use an arbitrary text value for anyxml */
671 lydict_insert(xmlctx->ctx, xmlctx->value, xmlctx->value_len, &val);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200672
Michal Vasko27c4dce2021-03-04 15:50:50 +0100673 /* parser next */
674 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
675
676 /* create node */
677 ret = lyd_create_any(snode, val, LYD_ANYDATA_STRING, 1, &node);
678 LY_CHECK_GOTO(ret, error);
679 } else {
680 /* parser next */
681 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
682
Michal Vaskoa98e3ea2021-06-03 09:13:33 +0200683 /* update options so that generic data can be parsed */
684 prev_parse_opts = lydctx->parse_opts;
Michal Vasko27c4dce2021-03-04 15:50:50 +0100685 lydctx->parse_opts &= ~LYD_PARSE_STRICT;
686 lydctx->parse_opts |= LYD_PARSE_OPAQ;
Michal Vaskoa98e3ea2021-06-03 09:13:33 +0200687 prev_int_opts = lydctx->int_opts;
Michal Vasko02ed9d82021-07-15 14:58:04 +0200688 lydctx->int_opts |= LYD_INTOPT_ANY | LYD_INTOPT_WITH_SIBLINGS;
Michal Vaskoa98e3ea2021-06-03 09:13:33 +0200689
690 /* parse any data tree */
Michal Vasko27c4dce2021-03-04 15:50:50 +0100691 anchor = NULL;
692 while (xmlctx->status == LYXML_ELEMENT) {
693 ret = lydxml_subtree_r(lydctx, NULL, &anchor, NULL);
Michal Vaskoa98e3ea2021-06-03 09:13:33 +0200694 if (ret) {
695 break;
696 }
Michal Vasko27c4dce2021-03-04 15:50:50 +0100697 }
Michal Vaskoa98e3ea2021-06-03 09:13:33 +0200698
699 /* restore options */
700 lydctx->parse_opts = prev_parse_opts;
701 lydctx->int_opts = prev_int_opts;
702
703 LY_CHECK_GOTO(ret, error);
Michal Vasko27c4dce2021-03-04 15:50:50 +0100704
705 /* create node */
706 ret = lyd_create_any(snode, anchor, LYD_ANYDATA_DATATREE, 1, &node);
707 LY_CHECK_GOTO(ret, error);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200708 }
Michal Vaskoa5da3292020-08-12 13:10:50 +0200709 }
710 assert(node);
711
712 /* add/correct flags */
713 if (snode) {
Radek Krejci4f2e3e52021-03-30 14:20:28 +0200714 lyd_parse_set_data_flags(node, &lydctx->node_when, &lydctx->node_exts, &meta, lydctx->parse_opts);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200715 }
716
717 /* parser next */
718 assert(xmlctx->status == LYXML_ELEM_CLOSE);
719 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
720
721 /* add metadata/attributes */
722 if (snode) {
Michal Vasko871a0252020-11-11 18:35:24 +0100723 lyd_insert_meta(node, meta, 0);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200724 } else {
725 lyd_insert_attr(node, attr);
726 }
727
728 /* insert, keep first pointer correct */
Michal Vasko6ee6f432021-07-16 09:49:14 +0200729 lyd_insert_node(parent, first_p, node, lydctx->parse_opts & LYD_PARSE_ORDERED ? 1 : 0);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200730 while (!parent && (*first_p)->prev->next) {
731 *first_p = (*first_p)->prev;
732 }
733
Michal Vaskoe0665742021-02-11 11:08:44 +0100734 /* rememeber a successfully parsed node */
735 if (parsed) {
736 ly_set_add(parsed, node, 1, NULL);
737 }
738
Radek Krejciddace2c2021-01-08 11:30:56 +0100739 LOG_LOCBACK(node ? 1 : 0, node ? 1 : 0, 0, 0);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200740 return LY_SUCCESS;
741
742error:
Radek Krejciddace2c2021-01-08 11:30:56 +0100743 LOG_LOCBACK(node ? 1 : 0, node ? 1 : 0, 0, 0);
Michal Vasko3a41dff2020-07-15 14:30:28 +0200744 lyd_free_meta_siblings(meta);
Radek Krejci011e4aa2020-09-04 15:22:31 +0200745 lyd_free_attr_siblings(ctx, attr);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200746 lyd_free_tree(node);
Radek Krejcie7b95092019-05-15 11:03:07 +0200747 return ret;
748}
749
Michal Vaskoe0665742021-02-11 11:08:44 +0100750/**
751 * @brief Parse a specific XML element into an opaque node.
752 *
753 * @param[in] xmlctx XML parser context.
754 * @param[in] name Name of the element.
755 * @param[in] uri URI of the element.
756 * @param[in] value Whether a value is expected in the element.
757 * @param[out] evnp Parsed envelope (opaque node).
758 * @return LY_SUCCESS on success.
759 * @return LY_ENOT if the specified element did not match.
760 * @return LY_ERR value on error.
761 */
Michal Vasko1bf09392020-03-27 12:38:10 +0100762static LY_ERR
Michal Vaskoe0665742021-02-11 11:08:44 +0100763lydxml_envelope(struct lyxml_ctx *xmlctx, const char *name, const char *uri, ly_bool value, struct lyd_node **envp)
Michal Vasko1bf09392020-03-27 12:38:10 +0100764{
Michal Vaskoe0665742021-02-11 11:08:44 +0100765 LY_ERR rc = LY_SUCCESS;
766 const struct lyxml_ns *ns;
Radek Krejci1798aae2020-07-14 13:26:06 +0200767 struct lyd_attr *attr = NULL;
Michal Vasko1bf09392020-03-27 12:38:10 +0100768 const char *prefix;
769 size_t prefix_len;
770
Michal Vasko1bf09392020-03-27 12:38:10 +0100771 assert(xmlctx->status == LYXML_ELEMENT);
772 if (ly_strncmp(name, xmlctx->name, xmlctx->name_len)) {
773 /* not the expected element */
Michal Vaskoe0665742021-02-11 11:08:44 +0100774 return LY_ENOT;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100775 }
776
777 prefix = xmlctx->prefix;
778 prefix_len = xmlctx->prefix_len;
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200779 ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100780 if (!ns) {
Radek Krejci422afb12021-03-04 16:38:16 +0100781 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)prefix_len, prefix);
Michal Vaskoe0665742021-02-11 11:08:44 +0100782 return LY_EVALID;
783 } else if (strcmp(ns->uri, uri)) {
784 /* different namespace */
785 return LY_ENOT;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100786 }
787
788 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
789
790 /* create attributes */
791 if (xmlctx->status == LYXML_ATTRIBUTE) {
792 LY_CHECK_RET(lydxml_attrs(xmlctx, &attr));
793 }
794
Michal Vaskoe0665742021-02-11 11:08:44 +0100795 assert(xmlctx->status == LYXML_ELEM_CONTENT);
796 if (!value && !xmlctx->ws_only) {
797 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected value \"%.*s\" in the \"%s\" element.",
Radek Krejci422afb12021-03-04 16:38:16 +0100798 (int)xmlctx->value_len, xmlctx->value, name);
Michal Vaskoe0665742021-02-11 11:08:44 +0100799 rc = LY_EVALID;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100800 goto cleanup;
Michal Vaskoe0665742021-02-11 11:08:44 +0100801 }
Michal Vaskoa8edff02020-03-27 14:47:01 +0100802
803 /* create node */
Michal Vaskoe0665742021-02-11 11:08:44 +0100804 rc = lyd_create_opaq(xmlctx->ctx, name, strlen(name), prefix, prefix_len, uri, strlen(uri), xmlctx->value,
Radek Krejci8df109d2021-04-23 12:19:08 +0200805 xmlctx->ws_only ? 0 : xmlctx->value_len, NULL, LY_VALUE_XML, NULL, 0, envp);
Michal Vaskoe0665742021-02-11 11:08:44 +0100806 LY_CHECK_GOTO(rc, cleanup);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100807
808 /* assign atributes */
Michal Vaskoe0665742021-02-11 11:08:44 +0100809 ((struct lyd_node_opaq *)(*envp))->attr = attr;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100810 attr = NULL;
811
Michal Vaskoe0665742021-02-11 11:08:44 +0100812 /* parser next element */
813 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100814
Michal Vaskoe0665742021-02-11 11:08:44 +0100815cleanup:
816 lyd_free_attr_siblings(xmlctx->ctx, attr);
817 if (rc) {
818 lyd_free_tree(*envp);
819 *envp = NULL;
820 }
821 return rc;
822}
823
824/**
825 * @brief Parse all expected non-data XML elements of a NETCONF rpc message.
826 *
827 * @param[in] xmlctx XML parser context.
828 * @param[out] evnp Parsed envelope(s) (opaque node).
829 * @param[out] int_opts Internal options for parsing the rest of YANG data.
830 * @param[out] close_elem Number of parsed opened elements that need to be closed.
831 * @return LY_SUCCESS on success.
832 * @return LY_ERR value on error.
833 */
834static LY_ERR
835lydxml_env_netconf_rpc(struct lyxml_ctx *xmlctx, struct lyd_node **envp, uint32_t *int_opts, uint32_t *close_elem)
836{
837 LY_ERR rc = LY_SUCCESS, r;
838 struct lyd_node *child;
839
840 assert(envp && !*envp);
841
842 /* parse "rpc" */
843 r = lydxml_envelope(xmlctx, "rpc", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, envp);
Michal Vaskoe0665742021-02-11 11:08:44 +0100844 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
845
846 /* parse "action", if any */
847 r = lydxml_envelope(xmlctx, "action", "urn:ietf:params:xml:ns:yang:1", 0, &child);
848 if (r == LY_SUCCESS) {
849 /* insert */
Michal Vasko6ee6f432021-07-16 09:49:14 +0200850 lyd_insert_node(*envp, NULL, child, 0);
Michal Vaskoe0665742021-02-11 11:08:44 +0100851
852 /* NETCONF action */
853 *int_opts = LYD_INTOPT_NO_SIBLINGS | LYD_INTOPT_ACTION;
854 *close_elem = 2;
855 } else if (r == LY_ENOT) {
856 /* NETCONF RPC */
857 *int_opts = LYD_INTOPT_NO_SIBLINGS | LYD_INTOPT_RPC;
858 *close_elem = 1;
859 } else {
860 rc = r;
861 goto cleanup;
862 }
863
864cleanup:
865 if (rc) {
866 lyd_free_tree(*envp);
867 *envp = NULL;
868 }
869 return rc;
870}
871
872/**
873 * @brief Parse all expected non-data XML elements of a NETCONF notification message.
874 *
875 * @param[in] xmlctx XML parser context.
876 * @param[out] evnp Parsed envelope(s) (opaque node).
877 * @param[out] int_opts Internal options for parsing the rest of YANG data.
878 * @param[out] close_elem Number of parsed opened elements that need to be closed.
879 * @return LY_SUCCESS on success.
880 * @return LY_ERR value on error.
881 */
882static LY_ERR
883lydxml_env_netconf_notif(struct lyxml_ctx *xmlctx, struct lyd_node **envp, uint32_t *int_opts, uint32_t *close_elem)
884{
885 LY_ERR rc = LY_SUCCESS, r;
886 struct lyd_node *child;
887
888 assert(envp && !*envp);
889
890 /* parse "notification" */
891 r = lydxml_envelope(xmlctx, "notification", "urn:ietf:params:xml:ns:netconf:notification:1.0", 0, envp);
Michal Vaskoe0665742021-02-11 11:08:44 +0100892 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
893
894 /* parse "eventTime" */
895 r = lydxml_envelope(xmlctx, "eventTime", "urn:ietf:params:xml:ns:netconf:notification:1.0", 1, &child);
896 if (r == LY_ENOT) {
Radek Krejci422afb12021-03-04 16:38:16 +0100897 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unexpected element \"%.*s\" instead of \"eventTime\".",
898 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +0100899 r = LY_EVALID;
900 }
901 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
902
903 /* insert */
Michal Vasko6ee6f432021-07-16 09:49:14 +0200904 lyd_insert_node(*envp, NULL, child, 0);
Michal Vaskoe0665742021-02-11 11:08:44 +0100905
906 /* validate value */
907 /* TODO validate child->value as yang:date-and-time */
908
909 /* finish child parsing */
Michal Vaskoa8edff02020-03-27 14:47:01 +0100910 if (xmlctx->status != LYXML_ELEM_CLOSE) {
911 assert(xmlctx->status == LYXML_ELEMENT);
Michal Vaskoe0665742021-02-11 11:08:44 +0100912 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"eventTime\".",
Radek Krejci422afb12021-03-04 16:38:16 +0100913 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +0100914 rc = LY_EVALID;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100915 goto cleanup;
916 }
Michal Vaskoe0665742021-02-11 11:08:44 +0100917 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
918
919 /* NETCONF notification */
920 *int_opts = LYD_INTOPT_NO_SIBLINGS | LYD_INTOPT_NOTIF;
921 *close_elem = 1;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100922
923cleanup:
Michal Vaskoe0665742021-02-11 11:08:44 +0100924 if (rc) {
Michal Vaskoa8edff02020-03-27 14:47:01 +0100925 lyd_free_tree(*envp);
Michal Vaskoe0665742021-02-11 11:08:44 +0100926 *envp = NULL;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100927 }
Michal Vaskoe0665742021-02-11 11:08:44 +0100928 return rc;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100929}
Michal Vasko79135ae2020-12-16 10:08:35 +0100930
Michal Vaskoe0665742021-02-11 11:08:44 +0100931/**
932 * @brief Parse an XML element as an opaque node subtree.
933 *
934 * @param[in] xmlctx XML parser context.
935 * @param[in] parent Parent to append nodes to.
936 * @return LY_ERR value.
937 */
938static LY_ERR
939lydxml_opaq_r(struct lyxml_ctx *xmlctx, struct lyd_node *parent)
Michal Vaskoa8edff02020-03-27 14:47:01 +0100940{
Michal Vaskoe0665742021-02-11 11:08:44 +0100941 LY_ERR rc = LY_SUCCESS;
942 const struct lyxml_ns *ns;
943 struct lyd_attr *attr = NULL;
944 struct lyd_node *child = NULL;
945 const char *name, *prefix;
946 size_t name_len, prefix_len;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100947
Michal Vaskoe0665742021-02-11 11:08:44 +0100948 assert(xmlctx->status == LYXML_ELEMENT);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100949
Michal Vaskoe0665742021-02-11 11:08:44 +0100950 name = xmlctx->name;
951 name_len = xmlctx->name_len;
952 prefix = xmlctx->prefix;
953 prefix_len = xmlctx->prefix_len;
954 ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
955 if (!ns) {
Radek Krejci422afb12021-03-04 16:38:16 +0100956 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)prefix_len, prefix);
Michal Vaskoe0665742021-02-11 11:08:44 +0100957 return LY_EVALID;
958 }
Michal Vaskoa8edff02020-03-27 14:47:01 +0100959
Michal Vaskoe0665742021-02-11 11:08:44 +0100960 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
Michal Vaskoa8edff02020-03-27 14:47:01 +0100961
Michal Vaskoe0665742021-02-11 11:08:44 +0100962 /* create attributes */
963 if (xmlctx->status == LYXML_ATTRIBUTE) {
964 LY_CHECK_RET(lydxml_attrs(xmlctx, &attr));
965 }
966
967 /* create node */
968 assert(xmlctx->status == LYXML_ELEM_CONTENT);
969 rc = lyd_create_opaq(xmlctx->ctx, name, name_len, prefix, prefix_len, ns->uri, strlen(ns->uri), xmlctx->value,
Radek Krejci8df109d2021-04-23 12:19:08 +0200970 xmlctx->ws_only ? 0 : xmlctx->value_len, NULL, LY_VALUE_XML, NULL, 0, &child);
Michal Vaskoe0665742021-02-11 11:08:44 +0100971 LY_CHECK_GOTO(rc, cleanup);
972
973 /* assign atributes */
974 ((struct lyd_node_opaq *)child)->attr = attr;
975 attr = NULL;
976
977 /* parser next element */
978 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
979
980 /* parse all the descendants */
981 while (xmlctx->status == LYXML_ELEMENT) {
982 rc = lydxml_opaq_r(xmlctx, child);
983 LY_CHECK_GOTO(rc, cleanup);
984 }
985
986 /* insert */
Michal Vasko6ee6f432021-07-16 09:49:14 +0200987 lyd_insert_node(parent, NULL, child, 1);
Michal Vaskoe0665742021-02-11 11:08:44 +0100988
989cleanup:
990 lyd_free_attr_siblings(xmlctx->ctx, attr);
991 if (rc) {
992 lyd_free_tree(child);
993 }
994 return rc;
995}
996
997/**
998 * @brief Parse all expected non-data XML elements of the error-info element in NETCONF rpc-reply message.
999 *
1000 * @param[in] xmlctx XML parser context.
1001 * @param[in] parent Parent to append nodes to.
1002 * @return LY_ERR value.
1003 */
1004static LY_ERR
1005lydxml_env_netconf_rpc_reply_error_info(struct lyxml_ctx *xmlctx, struct lyd_node *parent)
1006{
1007 LY_ERR r;
1008 struct lyd_node *child, *iter;
1009 const struct lyxml_ns *ns;
1010 ly_bool no_dup;
1011
1012 /* there must be some child */
1013 if (xmlctx->status == LYXML_ELEM_CLOSE) {
1014 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Missing child elements of \"error-info\".");
1015 return LY_EVALID;
1016 }
1017
1018 while (xmlctx->status == LYXML_ELEMENT) {
1019 child = NULL;
1020
1021 /*
1022 * session-id
1023 */
1024 r = lydxml_envelope(xmlctx, "session-id", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1025 if (r == LY_SUCCESS) {
1026 no_dup = 1;
1027 goto check_child;
1028 } else if (r != LY_ENOT) {
1029 goto error;
1030 }
1031
1032 /*
1033 * bad-attribute
1034 */
1035 r = lydxml_envelope(xmlctx, "bad-attribute", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1036 if (r == LY_SUCCESS) {
1037 no_dup = 1;
1038 goto check_child;
1039 } else if (r != LY_ENOT) {
1040 goto error;
1041 }
1042
1043 /*
1044 * bad-element
1045 */
1046 r = lydxml_envelope(xmlctx, "bad-element", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1047 if (r == LY_SUCCESS) {
1048 no_dup = 1;
1049 goto check_child;
1050 } else if (r != LY_ENOT) {
1051 goto error;
1052 }
1053
1054 /*
1055 * bad-namespace
1056 */
1057 r = lydxml_envelope(xmlctx, "bad-namespace", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1058 if (r == LY_SUCCESS) {
1059 no_dup = 1;
1060 goto check_child;
1061 } else if (r != LY_ENOT) {
1062 goto error;
1063 }
1064
1065 if (r == LY_ENOT) {
1066 assert(xmlctx->status == LYXML_ELEMENT);
1067
1068 /* learn namespace */
1069 ns = lyxml_ns_get(&xmlctx->ns, xmlctx->prefix, xmlctx->prefix_len);
1070 if (!ns) {
Radek Krejci422afb12021-03-04 16:38:16 +01001071 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)xmlctx->prefix_len, xmlctx->prefix);
Michal Vaskoe0665742021-02-11 11:08:44 +01001072 r = LY_EVALID;
1073 goto error;
1074 } else if (!strcmp(ns->uri, "urn:ietf:params:xml:ns:netconf:base:1.0")) {
1075 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"error-info\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001076 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001077 r = LY_EVALID;
1078 goto error;
1079 }
1080
1081 /* custom elements */
1082 r = lydxml_opaq_r(xmlctx, parent);
1083 LY_CHECK_GOTO(r, error);
Michal Vaskoe5ff3672022-01-10 10:12:30 +01001084 continue;
Michal Vaskoe0665742021-02-11 11:08:44 +01001085 }
1086
1087check_child:
1088 /* check for duplicates */
1089 if (no_dup) {
1090 LY_LIST_FOR(lyd_child(parent), iter) {
1091 if ((((struct lyd_node_opaq *)iter)->name.name == ((struct lyd_node_opaq *)child)->name.name) &&
1092 (((struct lyd_node_opaq *)iter)->name.module_ns == ((struct lyd_node_opaq *)child)->name.module_ns)) {
1093 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Duplicate element \"%s\" in \"error-info\".",
1094 ((struct lyd_node_opaq *)child)->name.name);
1095 r = LY_EVALID;
1096 goto error;
1097 }
1098 }
1099 }
1100
1101 /* finish child parsing */
1102 if (xmlctx->status != LYXML_ELEM_CLOSE) {
1103 assert(xmlctx->status == LYXML_ELEMENT);
1104 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"error-info\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001105 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001106 r = LY_EVALID;
1107 goto error;
1108 }
1109 LY_CHECK_GOTO(r = lyxml_ctx_next(xmlctx), error);
1110
1111 /* insert */
Michal Vasko6ee6f432021-07-16 09:49:14 +02001112 lyd_insert_node(parent, NULL, child, 1);
Michal Vaskoe0665742021-02-11 11:08:44 +01001113 }
1114
1115 return LY_SUCCESS;
1116
1117error:
1118 lyd_free_tree(child);
1119 return r;
1120}
1121
1122/**
1123 * @brief Parse all expected non-data XML elements of the rpc-error element in NETCONF rpc-reply message.
1124 *
1125 * @param[in] xmlctx XML parser context.
1126 * @param[in] parent Parent to append nodes to.
1127 * @return LY_ERR value.
1128 */
1129static LY_ERR
1130lydxml_env_netconf_rpc_reply_error(struct lyxml_ctx *xmlctx, struct lyd_node *parent)
1131{
1132 LY_ERR r;
1133 struct lyd_node *child, *iter;
1134 const char *val;
1135 ly_bool no_dup;
1136
1137 /* there must be some child */
1138 if (xmlctx->status == LYXML_ELEM_CLOSE) {
1139 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Missing child elements of \"rpc-error\".");
1140 return LY_EVALID;
1141 }
1142
1143 while (xmlctx->status == LYXML_ELEMENT) {
1144 child = NULL;
1145
1146 /*
1147 * error-type
1148 */
1149 r = lydxml_envelope(xmlctx, "error-type", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1150 if (r == LY_SUCCESS) {
1151 val = ((struct lyd_node_opaq *)child)->value;
1152 if (strcmp(val, "transport") && strcmp(val, "rpc") && strcmp(val, "protocol") && strcmp(val, "application")) {
1153 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Invalid value \"%s\" of element \"%s\".", val,
1154 ((struct lyd_node_opaq *)child)->name.name);
1155 r = LY_EVALID;
1156 goto error;
1157 }
1158
1159 no_dup = 1;
1160 goto check_child;
1161 } else if (r != LY_ENOT) {
1162 goto error;
1163 }
1164
1165 /*
1166 * error-tag
1167 */
1168 r = lydxml_envelope(xmlctx, "error-tag", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1169 if (r == LY_SUCCESS) {
1170 val = ((struct lyd_node_opaq *)child)->value;
1171 if (strcmp(val, "in-use") && strcmp(val, "invalid-value") && strcmp(val, "too-big") &&
1172 strcmp(val, "missing-attribute") && strcmp(val, "bad-attribute") &&
1173 strcmp(val, "unknown-attribute") && strcmp(val, "missing-element") && strcmp(val, "bad-element") &&
1174 strcmp(val, "unknown-element") && strcmp(val, "unknown-namespace") && strcmp(val, "access-denied") &&
1175 strcmp(val, "lock-denied") && strcmp(val, "resource-denied") && strcmp(val, "rollback-failed") &&
1176 strcmp(val, "data-exists") && strcmp(val, "data-missing") && strcmp(val, "operation-not-supported") &&
1177 strcmp(val, "operation-failed") && strcmp(val, "malformed-message")) {
1178 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Invalid value \"%s\" of element \"%s\".", val,
1179 ((struct lyd_node_opaq *)child)->name.name);
1180 r = LY_EVALID;
1181 goto error;
1182 }
1183
1184 no_dup = 1;
1185 goto check_child;
1186 } else if (r != LY_ENOT) {
1187 goto error;
1188 }
1189
1190 /*
1191 * error-severity
1192 */
1193 r = lydxml_envelope(xmlctx, "error-severity", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1194 if (r == LY_SUCCESS) {
1195 val = ((struct lyd_node_opaq *)child)->value;
1196 if (strcmp(val, "error") && strcmp(val, "warning")) {
1197 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Invalid value \"%s\" of element \"%s\".", val,
1198 ((struct lyd_node_opaq *)child)->name.name);
1199 r = LY_EVALID;
1200 goto error;
1201 }
1202
1203 no_dup = 1;
1204 goto check_child;
1205 } else if (r != LY_ENOT) {
1206 goto error;
1207 }
1208
1209 /*
1210 * error-app-tag
1211 */
1212 r = lydxml_envelope(xmlctx, "error-app-tag", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1213 if (r == LY_SUCCESS) {
1214 no_dup = 1;
1215 goto check_child;
1216 } else if (r != LY_ENOT) {
1217 goto error;
1218 }
1219
1220 /*
1221 * error-path
1222 */
1223 r = lydxml_envelope(xmlctx, "error-path", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1224 if (r == LY_SUCCESS) {
1225 no_dup = 1;
1226 goto check_child;
1227 } else if (r != LY_ENOT) {
1228 goto error;
1229 }
1230
1231 /*
1232 * error-message
1233 */
1234 r = lydxml_envelope(xmlctx, "error-message", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1235 if (r == LY_SUCCESS) {
1236 no_dup = 1;
1237 goto check_child;
1238 } else if (r != LY_ENOT) {
1239 goto error;
1240 }
1241
1242 /* error-info */
1243 r = lydxml_envelope(xmlctx, "error-info", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, &child);
1244 if (r == LY_SUCCESS) {
1245 /* parse all the descendants */
1246 LY_CHECK_GOTO(r = lydxml_env_netconf_rpc_reply_error_info(xmlctx, child), error);
1247
1248 no_dup = 0;
1249 goto check_child;
1250 } else if (r != LY_ENOT) {
1251 goto error;
1252 }
1253
1254 if (r == LY_ENOT) {
1255 assert(xmlctx->status == LYXML_ELEMENT);
1256 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"rpc-error\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001257 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001258 r = LY_EVALID;
1259 goto error;
1260 }
1261
1262check_child:
1263 /* check for duplicates */
1264 if (no_dup) {
1265 LY_LIST_FOR(lyd_child(parent), iter) {
1266 if ((((struct lyd_node_opaq *)iter)->name.name == ((struct lyd_node_opaq *)child)->name.name) &&
1267 (((struct lyd_node_opaq *)iter)->name.module_ns == ((struct lyd_node_opaq *)child)->name.module_ns)) {
1268 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Duplicate element \"%s\" in \"rpc-error\".",
1269 ((struct lyd_node_opaq *)child)->name.name);
1270 r = LY_EVALID;
1271 goto error;
1272 }
1273 }
1274 }
1275
1276 /* finish child parsing */
1277 if (xmlctx->status != LYXML_ELEM_CLOSE) {
1278 assert(xmlctx->status == LYXML_ELEMENT);
1279 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"rpc-error\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001280 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001281 r = LY_EVALID;
1282 goto error;
1283 }
1284 LY_CHECK_GOTO(r = lyxml_ctx_next(xmlctx), error);
1285
1286 /* insert */
Michal Vasko6ee6f432021-07-16 09:49:14 +02001287 lyd_insert_node(parent, NULL, child, 1);
Michal Vaskoe0665742021-02-11 11:08:44 +01001288 }
1289
1290 return LY_SUCCESS;
1291
1292error:
1293 lyd_free_tree(child);
1294 return r;
1295}
1296
1297/**
1298 * @brief Parse all expected non-data XML elements of a NETCONF rpc-reply message.
1299 *
1300 * @param[in] xmlctx XML parser context.
1301 * @param[out] evnp Parsed envelope(s) (opaque node).
1302 * @param[out] int_opts Internal options for parsing the rest of YANG data.
1303 * @param[out] close_elem Number of parsed opened elements that need to be closed.
1304 * @return LY_SUCCESS on success.
1305 * @return LY_ERR value on error.
1306 */
1307static LY_ERR
1308lydxml_env_netconf_reply(struct lyxml_ctx *xmlctx, struct lyd_node **envp, uint32_t *int_opts, uint32_t *close_elem)
1309{
1310 LY_ERR rc = LY_SUCCESS, r;
1311 struct lyd_node *child = NULL;
1312 const char *parsed_elem = NULL;
1313
1314 assert(envp && !*envp);
1315
1316 /* parse "rpc-reply" */
1317 r = lydxml_envelope(xmlctx, "rpc-reply", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, envp);
Michal Vaskoe0665742021-02-11 11:08:44 +01001318 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
1319
1320 /* there must be some child */
1321 if (xmlctx->status == LYXML_ELEM_CLOSE) {
1322 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Missing child elements of \"rpc-reply\".");
1323 rc = LY_EVALID;
Michal Vaskocf770e22020-08-12 13:21:43 +02001324 goto cleanup;
Michal Vaskoa8edff02020-03-27 14:47:01 +01001325 }
1326
Michal Vaskoe0665742021-02-11 11:08:44 +01001327 /* try to parse "ok" */
1328 r = lydxml_envelope(xmlctx, "ok", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, &child);
1329 if (r == LY_SUCCESS) {
1330 /* insert */
Michal Vasko6ee6f432021-07-16 09:49:14 +02001331 lyd_insert_node(*envp, NULL, child, 1);
Michal Vaskoe0665742021-02-11 11:08:44 +01001332
1333 /* finish child parsing */
1334 if (xmlctx->status != LYXML_ELEM_CLOSE) {
1335 assert(xmlctx->status == LYXML_ELEMENT);
1336 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"ok\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001337 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001338 rc = LY_EVALID;
1339 goto cleanup;
1340 }
1341 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
1342
1343 /* success */
1344 parsed_elem = "ok";
1345 goto finish;
1346 } else if (r != LY_ENOT) {
1347 rc = r;
1348 goto cleanup;
Michal Vasko2552ea32020-12-08 15:32:34 +01001349 }
1350
Michal Vaskoe0665742021-02-11 11:08:44 +01001351 /* try to parse all "rpc-error" elements */
1352 while (xmlctx->status == LYXML_ELEMENT) {
1353 r = lydxml_envelope(xmlctx, "rpc-error", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, &child);
1354 if (r == LY_ENOT) {
1355 break;
1356 } else if (r) {
1357 rc = r;
1358 goto cleanup;
1359 }
1360
1361 /* insert */
Michal Vasko6ee6f432021-07-16 09:49:14 +02001362 lyd_insert_node(*envp, NULL, child, 1);
Michal Vaskoe0665742021-02-11 11:08:44 +01001363
1364 /* parse all children of "rpc-error" */
1365 LY_CHECK_GOTO(rc = lydxml_env_netconf_rpc_reply_error(xmlctx, child), cleanup);
1366
1367 /* finish child parsing */
1368 assert(xmlctx->status == LYXML_ELEM_CLOSE);
1369 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
1370
1371 parsed_elem = "rpc-error";
Michal Vasko2552ea32020-12-08 15:32:34 +01001372 }
Michal Vaskoe0665742021-02-11 11:08:44 +01001373
1374finish:
1375 if (parsed_elem) {
1376 /* NETCONF rpc-reply with no data */
1377 if (xmlctx->status != LYXML_ELEM_CLOSE) {
1378 assert(xmlctx->status == LYXML_ELEMENT);
1379 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected sibling element \"%.*s\" of \"%s\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001380 (int)xmlctx->name_len, xmlctx->name, parsed_elem);
Michal Vaskoe0665742021-02-11 11:08:44 +01001381 rc = LY_EVALID;
1382 goto cleanup;
1383 }
1384 }
1385
1386 /* NETCONF rpc-reply */
Michal Vasko1d991fd2021-07-09 13:14:40 +02001387 *int_opts = LYD_INTOPT_WITH_SIBLINGS | LYD_INTOPT_REPLY;
Michal Vaskoe0665742021-02-11 11:08:44 +01001388 *close_elem = 1;
1389
1390cleanup:
1391 if (rc) {
1392 lyd_free_tree(*envp);
1393 *envp = NULL;
1394 }
1395 return rc;
1396}
1397
Michal Vasko2552ea32020-12-08 15:32:34 +01001398LY_ERR
Radek Krejcif16e2542021-02-17 15:39:23 +01001399lyd_parse_xml(const struct ly_ctx *ctx, const struct lysc_ext_instance *ext, struct lyd_node *parent,
1400 struct lyd_node **first_p, struct ly_in *in, uint32_t parse_opts, uint32_t val_opts, enum lyd_type data_type,
1401 struct lyd_node **envp, struct ly_set *parsed, struct lyd_ctx **lydctx_p)
Michal Vasko2552ea32020-12-08 15:32:34 +01001402{
Michal Vaskoe0665742021-02-11 11:08:44 +01001403 LY_ERR rc = LY_SUCCESS;
1404 struct lyd_xml_ctx *lydctx;
Michal Vasko2ca9f9e2021-07-02 09:21:36 +02001405 uint32_t i, int_opts = 0, close_elem = 0;
Michal Vaskoe0665742021-02-11 11:08:44 +01001406 ly_bool parsed_data_nodes = 0;
Michal Vasko2552ea32020-12-08 15:32:34 +01001407
Michal Vaskoe0665742021-02-11 11:08:44 +01001408 assert(ctx && in && lydctx_p);
1409 assert(!(parse_opts & ~LYD_PARSE_OPTS_MASK));
1410 assert(!(val_opts & ~LYD_VALIDATE_OPTS_MASK));
Michal Vasko2552ea32020-12-08 15:32:34 +01001411
Michal Vaskoe0665742021-02-11 11:08:44 +01001412 /* init context */
1413 lydctx = calloc(1, sizeof *lydctx);
1414 LY_CHECK_ERR_RET(!lydctx, LOGMEM(ctx), LY_EMEM);
1415 LY_CHECK_GOTO(rc = lyxml_ctx_new(ctx, in, &lydctx->xmlctx), cleanup);
1416 lydctx->parse_opts = parse_opts;
1417 lydctx->val_opts = val_opts;
1418 lydctx->free = lyd_xml_ctx_free;
Radek Krejcif16e2542021-02-17 15:39:23 +01001419 lydctx->ext = ext;
Michal Vasko2552ea32020-12-08 15:32:34 +01001420
Michal Vaskoe0665742021-02-11 11:08:44 +01001421 switch (data_type) {
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001422 case LYD_TYPE_DATA_YANG:
Michal Vaskoe0665742021-02-11 11:08:44 +01001423 int_opts = LYD_INTOPT_WITH_SIBLINGS;
1424 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001425 case LYD_TYPE_RPC_YANG:
Michal Vaskoe0665742021-02-11 11:08:44 +01001426 int_opts = LYD_INTOPT_RPC | LYD_INTOPT_ACTION | LYD_INTOPT_NO_SIBLINGS;
1427 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001428 case LYD_TYPE_NOTIF_YANG:
Michal Vaskoe0665742021-02-11 11:08:44 +01001429 int_opts = LYD_INTOPT_NOTIF | LYD_INTOPT_NO_SIBLINGS;
1430 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001431 case LYD_TYPE_REPLY_YANG:
Michal Vaskoe0665742021-02-11 11:08:44 +01001432 int_opts = LYD_INTOPT_REPLY | LYD_INTOPT_NO_SIBLINGS;
1433 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001434 case LYD_TYPE_RPC_NETCONF:
Michal Vaskoe0665742021-02-11 11:08:44 +01001435 assert(!parent);
1436 LY_CHECK_GOTO(rc = lydxml_env_netconf_rpc(lydctx->xmlctx, envp, &int_opts, &close_elem), cleanup);
1437 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001438 case LYD_TYPE_NOTIF_NETCONF:
1439 assert(!parent);
1440 LY_CHECK_GOTO(rc = lydxml_env_netconf_notif(lydctx->xmlctx, envp, &int_opts, &close_elem), cleanup);
1441 break;
1442 case LYD_TYPE_REPLY_NETCONF:
Michal Vaskoe0665742021-02-11 11:08:44 +01001443 assert(parent);
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001444 LY_CHECK_GOTO(rc = lydxml_env_netconf_reply(lydctx->xmlctx, envp, &int_opts, &close_elem), cleanup);
Michal Vaskoe0665742021-02-11 11:08:44 +01001445 break;
1446 }
1447 lydctx->int_opts = int_opts;
1448
1449 /* find the operation node if it exists already */
1450 LY_CHECK_GOTO(rc = lyd_parser_find_operation(parent, int_opts, &lydctx->op_node), cleanup);
1451
1452 /* parse XML data */
1453 while (lydctx->xmlctx->status == LYXML_ELEMENT) {
1454 LY_CHECK_GOTO(rc = lydxml_subtree_r(lydctx, parent, first_p, parsed), cleanup);
1455 parsed_data_nodes = 1;
1456
1457 if (!(int_opts & LYD_INTOPT_WITH_SIBLINGS)) {
1458 break;
1459 }
Michal Vasko2552ea32020-12-08 15:32:34 +01001460 }
1461
Michal Vaskoe0665742021-02-11 11:08:44 +01001462 /* close all opened elements */
1463 for (i = 0; i < close_elem; ++i) {
1464 if (lydctx->xmlctx->status != LYXML_ELEM_CLOSE) {
1465 assert(lydctx->xmlctx->status == LYXML_ELEMENT);
Radek Krejci422afb12021-03-04 16:38:16 +01001466 LOGVAL(lydctx->xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\".",
1467 (int)lydctx->xmlctx->name_len, lydctx->xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001468 rc = LY_EVALID;
1469 goto cleanup;
1470 }
1471
1472 LY_CHECK_GOTO(rc = lyxml_ctx_next(lydctx->xmlctx), cleanup);
Michal Vasko4189c0f2020-08-13 09:05:22 +02001473 }
Michal Vaskoe0665742021-02-11 11:08:44 +01001474
1475 /* check final state */
1476 if ((int_opts & LYD_INTOPT_NO_SIBLINGS) && (lydctx->xmlctx->status == LYXML_ELEMENT)) {
1477 LOGVAL(ctx, LYVE_SYNTAX, "Unexpected sibling node.");
1478 rc = LY_EVALID;
1479 goto cleanup;
1480 }
Michal Vaskoe601aaa2022-01-03 11:35:13 +01001481 if ((int_opts & (LYD_INTOPT_RPC | LYD_INTOPT_ACTION | LYD_INTOPT_NOTIF | LYD_INTOPT_REPLY)) && !lydctx->op_node) {
Michal Vaskoe0665742021-02-11 11:08:44 +01001482 LOGVAL(ctx, LYVE_DATA, "Missing the operation node.");
1483 rc = LY_EVALID;
1484 goto cleanup;
1485 }
1486
1487 if (!parsed_data_nodes) {
1488 /* no data nodes were parsed */
1489 lydctx->op_node = NULL;
Michal Vaskoa8edff02020-03-27 14:47:01 +01001490 }
1491
1492cleanup:
Michal Vaskoe0665742021-02-11 11:08:44 +01001493 /* there should be no unres stored if validation should be skipped */
1494 assert(!(parse_opts & LYD_PARSE_ONLY) || (!lydctx->node_types.count && !lydctx->meta_types.count &&
Radek Krejci4f2e3e52021-03-30 14:20:28 +02001495 !lydctx->node_when.count && !lydctx->node_exts.count));
Michal Vaskoe0665742021-02-11 11:08:44 +01001496
1497 if (rc) {
1498 lyd_xml_ctx_free((struct lyd_ctx *)lydctx);
1499 } else {
1500 *lydctx_p = (struct lyd_ctx *)lydctx;
1501
1502 /* the XML context is no more needed, freeing it also stops logging line numbers which would be confusing now */
1503 lyxml_ctx_free(lydctx->xmlctx);
1504 lydctx->xmlctx = NULL;
Michal Vasko1ce933a2020-03-30 12:38:22 +02001505 }
Michal Vaskoe0665742021-02-11 11:08:44 +01001506 return rc;
Michal Vasko1ce933a2020-03-30 12:38:22 +02001507}