blob: 276ccc1c93e64094c30ac3849dee958dde75e8a6 [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"
Radek Krejcie7b95092019-05-15 11:03:07 +020027#include "set.h"
Radek Krejci77114102021-03-10 15:21:57 +010028#include "tree.h"
Radek Krejci47fab892020-11-05 17:02:41 +010029#include "tree_data.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020030#include "tree_data_internal.h"
31#include "tree_schema.h"
Radek Krejci77114102021-03-10 15:21:57 +010032#include "tree_schema_internal.h"
Michal Vaskocde73ac2019-11-14 16:10:27 +010033#include "validation.h"
Radek Krejci535ea9f2020-05-29 16:01:05 +020034#include "xml.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020035
Radek Krejci1798aae2020-07-14 13:26:06 +020036void
37lyd_xml_ctx_free(struct lyd_ctx *lydctx)
38{
39 struct lyd_xml_ctx *ctx = (struct lyd_xml_ctx *)lydctx;
40
41 lyd_ctx_free(lydctx);
42 lyxml_ctx_free(ctx->xmlctx);
43 free(ctx);
44}
45
Michal Vasko45791ad2021-06-17 08:45:03 +020046/**
47 * @brief Parse and create XML metadata.
48 *
49 * @param[in] lydctx XML data parser context.
50 * @param[in] parent_exts Extension instances of the parent node.
51 * @param[out] meta List of created metadata instances.
52 * @return LY_ERR value.
53 */
Radek Krejcie7b95092019-05-15 11:03:07 +020054static LY_ERR
Michal Vasko45791ad2021-06-17 08:45:03 +020055lydxml_metadata(struct lyd_xml_ctx *lydctx, struct lysc_ext_instance *parent_exts, struct lyd_meta **meta)
Radek Krejcie7b95092019-05-15 11:03:07 +020056{
aPiecek1c4da362021-04-29 14:26:34 +020057 LY_ERR ret = LY_SUCCESS;
Radek Krejci28681fa2019-09-06 13:08:45 +020058 const struct lyxml_ns *ns;
59 struct lys_module *mod;
Michal Vaskob36053d2020-03-26 15:49:30 +010060 const char *name;
61 size_t name_len;
Michal Vasko45791ad2021-06-17 08:45:03 +020062 LY_ARRAY_COUNT_TYPE u;
63 ly_bool filter_attrs = 0;
Radek Krejci1798aae2020-07-14 13:26:06 +020064 struct lyxml_ctx *xmlctx = lydctx->xmlctx;
Radek Krejci28681fa2019-09-06 13:08:45 +020065
Michal Vaskob36053d2020-03-26 15:49:30 +010066 *meta = NULL;
Radek Krejci28681fa2019-09-06 13:08:45 +020067
Michal Vasko45791ad2021-06-17 08:45:03 +020068 /* check for NETCONF filter unqualified attributes */
69 LY_ARRAY_FOR(parent_exts, u) {
70 if (!strcmp(parent_exts[u].def->name, "get-filter-element-attributes") &&
71 !strcmp(parent_exts[u].def->module->name, "ietf-netconf")) {
72 filter_attrs = 1;
73 break;
74 }
75 }
76
Michal Vaskob36053d2020-03-26 15:49:30 +010077 while (xmlctx->status == LYXML_ATTRIBUTE) {
78 if (!xmlctx->prefix_len) {
Michal Vasko45791ad2021-06-17 08:45:03 +020079 /* in XML all attributes must be prefixed except NETCONF filter ones marked by an extension */
80 if (filter_attrs && (!ly_strncmp("type", xmlctx->name, xmlctx->name_len) ||
81 !ly_strncmp("select", xmlctx->name, xmlctx->name_len))) {
82 mod = ly_ctx_get_module_implemented(xmlctx->ctx, "ietf-netconf");
83 if (!mod) {
84 LOGVAL(xmlctx->ctx, LYVE_REFERENCE,
85 "Missing (or not implemented) YANG module \"ietf-netconf\" for special filter attributes.");
86 ret = LY_ENOTFOUND;
87 goto cleanup;
88 }
89 goto create_meta;
90 }
91
Michal Vaskoe0665742021-02-11 11:08:44 +010092 if (lydctx->parse_opts & LYD_PARSE_STRICT) {
Radek Krejci2efc45b2020-12-22 16:25:44 +010093 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Missing mandatory prefix for XML metadata \"%.*s\".",
Radek Krejci422afb12021-03-04 16:38:16 +010094 (int)xmlctx->name_len, xmlctx->name);
Michal Vasko45791ad2021-06-17 08:45:03 +020095 ret = LY_EVALID;
Michal Vaskob36053d2020-03-26 15:49:30 +010096 goto cleanup;
Radek Krejci28681fa2019-09-06 13:08:45 +020097 }
Michal Vaskob36053d2020-03-26 15:49:30 +010098
Michal Vasko45791ad2021-06-17 08:45:03 +020099 /* skip attr */
Michal Vaskob36053d2020-03-26 15:49:30 +0100100 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
101 assert(xmlctx->status == LYXML_ATTR_CONTENT);
102 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Radek Krejci28681fa2019-09-06 13:08:45 +0200103 continue;
104 }
105
106 /* get namespace of the attribute to find its annotation definition */
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200107 ns = lyxml_ns_get(&xmlctx->ns, xmlctx->prefix, xmlctx->prefix_len);
Radek Krejci28681fa2019-09-06 13:08:45 +0200108 if (!ns) {
Michal Vasko52927e22020-03-16 17:26:14 +0100109 /* unknown namespace, XML error */
Radek Krejci422afb12021-03-04 16:38:16 +0100110 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)xmlctx->prefix_len, xmlctx->prefix);
Michal Vasko45791ad2021-06-17 08:45:03 +0200111 ret = LY_ENOTFOUND;
Radek Krejci28681fa2019-09-06 13:08:45 +0200112 goto cleanup;
113 }
Michal Vasko45791ad2021-06-17 08:45:03 +0200114
115 /* get the module with metadata definition */
Michal Vasko52927e22020-03-16 17:26:14 +0100116 mod = ly_ctx_get_module_implemented_ns(xmlctx->ctx, ns->uri);
Radek Krejci28681fa2019-09-06 13:08:45 +0200117 if (!mod) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100118 if (lydctx->parse_opts & LYD_PARSE_STRICT) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100119 LOGVAL(xmlctx->ctx, LYVE_REFERENCE,
Michal Vasko69730152020-10-09 16:30:07 +0200120 "Unknown (or not implemented) YANG module with namespace \"%s\" for metadata \"%.*s%s%.*s\".",
Radek Krejci422afb12021-03-04 16:38:16 +0100121 ns->uri, (int)xmlctx->prefix_len, xmlctx->prefix, xmlctx->prefix_len ? ":" : "",
122 (int)xmlctx->name_len, xmlctx->name);
Michal Vasko45791ad2021-06-17 08:45:03 +0200123 ret = LY_ENOTFOUND;
Michal Vaskob36053d2020-03-26 15:49:30 +0100124 goto cleanup;
Radek Krejci28681fa2019-09-06 13:08:45 +0200125 }
Michal Vasko45791ad2021-06-17 08:45:03 +0200126
127 /* skip attr */
128 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
129 assert(xmlctx->status == LYXML_ATTR_CONTENT);
130 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
131 continue;
Radek Krejci28681fa2019-09-06 13:08:45 +0200132 }
133
Michal Vasko45791ad2021-06-17 08:45:03 +0200134create_meta:
Michal Vasko60ea6352020-06-29 13:39:39 +0200135 /* remember meta name and get its content */
Michal Vaskob36053d2020-03-26 15:49:30 +0100136 name = xmlctx->name;
137 name_len = xmlctx->name_len;
138 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
139 assert(xmlctx->status == LYXML_ATTR_CONTENT);
140
141 /* create metadata */
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200142 ret = lyd_parser_create_meta((struct lyd_ctx *)lydctx, NULL, meta, mod, name, name_len, xmlctx->value,
Radek Krejci8df109d2021-04-23 12:19:08 +0200143 xmlctx->value_len, &xmlctx->dynamic, LY_VALUE_XML, &xmlctx->ns, LYD_HINT_DATA);
Radek Krejci1798aae2020-07-14 13:26:06 +0200144 LY_CHECK_GOTO(ret, cleanup);
Michal Vaskob36053d2020-03-26 15:49:30 +0100145
146 /* next attribute */
147 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Radek Krejcie7b95092019-05-15 11:03:07 +0200148 }
Michal Vasko52927e22020-03-16 17:26:14 +0100149
Radek Krejcie7b95092019-05-15 11:03:07 +0200150cleanup:
Michal Vaskob36053d2020-03-26 15:49:30 +0100151 if (ret) {
Michal Vasko3a41dff2020-07-15 14:30:28 +0200152 lyd_free_meta_siblings(*meta);
Michal Vaskob36053d2020-03-26 15:49:30 +0100153 *meta = NULL;
Radek Krejci38d85362019-09-05 16:26:38 +0200154 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200155 return ret;
156}
157
Michal Vasko52927e22020-03-16 17:26:14 +0100158static LY_ERR
Radek Krejci1798aae2020-07-14 13:26:06 +0200159lydxml_attrs(struct lyxml_ctx *xmlctx, struct lyd_attr **attr)
Michal Vasko52927e22020-03-16 17:26:14 +0100160{
161 LY_ERR ret = LY_SUCCESS;
162 const struct lyxml_ns *ns;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100163 void *val_prefix_data;
Radek Krejci8df109d2021-04-23 12:19:08 +0200164 LY_VALUE_FORMAT format;
Radek Krejci1798aae2020-07-14 13:26:06 +0200165 struct lyd_attr *attr2;
Michal Vaskob36053d2020-03-26 15:49:30 +0100166 const char *name, *prefix;
167 size_t name_len, prefix_len;
Michal Vasko52927e22020-03-16 17:26:14 +0100168
169 assert(attr);
Michal Vaskob36053d2020-03-26 15:49:30 +0100170 *attr = NULL;
Michal Vasko52927e22020-03-16 17:26:14 +0100171
Michal Vaskob36053d2020-03-26 15:49:30 +0100172 while (xmlctx->status == LYXML_ATTRIBUTE) {
Michal Vasko52927e22020-03-16 17:26:14 +0100173 if (*attr) {
174 attr2 = *attr;
175 } else {
176 attr2 = NULL;
177 }
178
Michal Vaskob36053d2020-03-26 15:49:30 +0100179 /* remember attr prefix, name, and get its content */
180 prefix = xmlctx->prefix;
181 prefix_len = xmlctx->prefix_len;
182 name = xmlctx->name;
183 name_len = xmlctx->name_len;
184 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
185 assert(xmlctx->status == LYXML_ATTR_CONTENT);
186
Michal Vaskoe137fc42021-07-22 11:53:13 +0200187 /* handle special "xml" attribute prefix */
188 if ((prefix_len == 3) && !strncmp(prefix, "xml", 3)) {
189 name = prefix;
190 name_len += 1 + prefix_len;
191 prefix = NULL;
192 prefix_len = 0;
193 }
194
195 /* find namespace of the attribute, if any */
196 ns = NULL;
197 if (prefix_len) {
198 ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
199 if (!ns) {
200 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)prefix_len, prefix);
201 ret = LY_EVALID;
202 goto cleanup;
203 }
204 }
205
Michal Vasko52927e22020-03-16 17:26:14 +0100206 /* get value prefixes */
Michal Vaskofc2cd072021-02-24 13:17:17 +0100207 val_prefix_data = NULL;
Radek Krejci8df109d2021-04-23 12:19:08 +0200208 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 +0100209 &xmlctx->ns, &format, &val_prefix_data), cleanup);
Michal Vasko52927e22020-03-16 17:26:14 +0100210
211 /* attr2 is always changed to the created attribute */
Michal Vasko501af032020-11-11 20:27:44 +0100212 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 +0100213 ns ? strlen(ns->uri) : 0, xmlctx->value, xmlctx->value_len, &xmlctx->dynamic, format, val_prefix_data,
214 LYD_HINT_DATA);
Michal Vasko52927e22020-03-16 17:26:14 +0100215 LY_CHECK_GOTO(ret, cleanup);
216
217 if (!*attr) {
218 *attr = attr2;
219 }
Michal Vaskob36053d2020-03-26 15:49:30 +0100220
221 /* next attribute */
222 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko52927e22020-03-16 17:26:14 +0100223 }
224
225cleanup:
Michal Vaskob36053d2020-03-26 15:49:30 +0100226 if (ret) {
Radek Krejci011e4aa2020-09-04 15:22:31 +0200227 lyd_free_attr_siblings(xmlctx->ctx, *attr);
Michal Vaskob36053d2020-03-26 15:49:30 +0100228 *attr = NULL;
Michal Vasko52927e22020-03-16 17:26:14 +0100229 }
Michal Vasko52927e22020-03-16 17:26:14 +0100230 return ret;
231}
232
Michal Vasko44685da2020-03-17 15:38:06 +0100233static LY_ERR
Michal Vaskob36053d2020-03-26 15:49:30 +0100234lydxml_check_list(struct lyxml_ctx *xmlctx, const struct lysc_node *list)
Michal Vasko44685da2020-03-17 15:38:06 +0100235{
Michal Vaskob36053d2020-03-26 15:49:30 +0100236 LY_ERR ret = LY_SUCCESS, r;
237 enum LYXML_PARSER_STATUS next;
Michal Vasko44685da2020-03-17 15:38:06 +0100238 struct ly_set key_set = {0};
239 const struct lysc_node *snode;
Michal Vaskob36053d2020-03-26 15:49:30 +0100240 uint32_t i, parents_count;
Michal Vasko44685da2020-03-17 15:38:06 +0100241
242 assert(list && (list->nodetype == LYS_LIST));
243
244 /* get all keys into a set (keys do not have if-features or anything) */
245 snode = NULL;
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100246 while ((snode = lys_getnext(snode, list, NULL, 0)) && (snode->flags & LYS_KEY)) {
Radek Krejci3d92e442020-10-12 12:48:13 +0200247 ret = ly_set_add(&key_set, (void *)snode, 1, NULL);
Radek Krejciba03a5a2020-08-27 14:40:41 +0200248 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100249 }
250
Michal Vasko12d809c2021-03-03 16:34:32 +0100251 /* remember parent count */
252 parents_count = xmlctx->elements.count;
253
Michal Vaskob36053d2020-03-26 15:49:30 +0100254 while (xmlctx->status == LYXML_ELEMENT) {
Michal Vasko44685da2020-03-17 15:38:06 +0100255 /* find key definition */
256 for (i = 0; i < key_set.count; ++i) {
257 snode = (const struct lysc_node *)key_set.objs[i];
Michal Vaskob36053d2020-03-26 15:49:30 +0100258 if (!ly_strncmp(snode->name, xmlctx->name, xmlctx->name_len)) {
Michal Vasko44685da2020-03-17 15:38:06 +0100259 break;
260 }
261 }
Michal Vaskob36053d2020-03-26 15:49:30 +0100262 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100263
264 /* skip attributes */
265 while (xmlctx->status == LYXML_ATTRIBUTE) {
Michal Vaskob36053d2020-03-26 15:49:30 +0100266 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
267 assert(xmlctx->status == LYXML_ATTR_CONTENT);
268 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100269 }
270
Michal Vaskob36053d2020-03-26 15:49:30 +0100271 assert(xmlctx->status == LYXML_ELEM_CONTENT);
272 if (i < key_set.count) {
273 /* validate the value */
Radek Krejci8df109d2021-04-23 12:19:08 +0200274 r = lys_value_validate(NULL, snode, xmlctx->value, xmlctx->value_len, LY_VALUE_XML, &xmlctx->ns);
Michal Vaskob36053d2020-03-26 15:49:30 +0100275 if (!r) {
276 /* key with a valid value, remove from the set */
277 ly_set_rm_index(&key_set, i, NULL);
Michal Vasko44685da2020-03-17 15:38:06 +0100278 }
279 }
280
Michal Vaskob36053d2020-03-26 15:49:30 +0100281 /* parser next */
282 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100283
Michal Vaskob36053d2020-03-26 15:49:30 +0100284 /* skip any children, resursively */
Michal Vasko12d809c2021-03-03 16:34:32 +0100285 while (xmlctx->status == LYXML_ELEMENT) {
286 while (parents_count < xmlctx->elements.count) {
287 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
288 }
289 assert(xmlctx->status == LYXML_ELEM_CLOSE);
Michal Vaskob36053d2020-03-26 15:49:30 +0100290 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
291 }
292
293 /* parser next, but do not parse closing element of the list because it would remove its namespaces */
294 assert(xmlctx->status == LYXML_ELEM_CLOSE);
295 LY_CHECK_GOTO(ret = lyxml_ctx_peek(xmlctx, &next), cleanup);
296 if (next != LYXML_ELEM_CLOSE) {
297 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
298 }
Michal Vasko44685da2020-03-17 15:38:06 +0100299 }
300
301 if (key_set.count) {
Michal Vaskob36053d2020-03-26 15:49:30 +0100302 /* some keys are missing/did not validate */
Michal Vasko44685da2020-03-17 15:38:06 +0100303 ret = LY_ENOT;
Michal Vasko44685da2020-03-17 15:38:06 +0100304 }
305
306cleanup:
307 ly_set_erase(&key_set, NULL);
308 return ret;
309}
310
Michal Vasko5c24ed12021-06-09 09:27:32 +0200311/**
312 * @brief Skip an element with all its descendants.
313 *
314 * @param[in] xmlctx XML parser context.
315 * @return LY_ERR value.
316 */
Michal Vasko1bf09392020-03-27 12:38:10 +0100317static LY_ERR
318lydxml_data_skip(struct lyxml_ctx *xmlctx)
319{
320 uint32_t parents_count;
321
322 /* remember current number of parents */
323 parents_count = xmlctx->elements.count;
aPiecek9cdb9e62021-05-18 09:46:20 +0200324 assert(parents_count);
Michal Vasko1bf09392020-03-27 12:38:10 +0100325
326 /* skip after the content */
327 while (xmlctx->status != LYXML_ELEM_CONTENT) {
328 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
329 }
330 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
331
332 /* skip all children elements, recursively, if any */
aPiecek9cdb9e62021-05-18 09:46:20 +0200333 while (parents_count <= xmlctx->elements.count) {
Michal Vasko1bf09392020-03-27 12:38:10 +0100334 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
335 }
336
337 /* close element */
338 assert(xmlctx->status == LYXML_ELEM_CLOSE);
339 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
340
341 return LY_SUCCESS;
342}
343
Michal Vasko5c24ed12021-06-09 09:27:32 +0200344/**
345 * @brief Check that the current element can be parsed as a data node.
346 *
347 * @param[in] lydctx XML data parser context.
348 * @param[in,out] snode Found schema node, set to NULL if data node cannot be created.
349 * @return LY_ERR value.
350 */
Michal Vasko1bf09392020-03-27 12:38:10 +0100351static LY_ERR
Radek Krejci1798aae2020-07-14 13:26:06 +0200352lydxml_data_check_opaq(struct lyd_xml_ctx *lydctx, const struct lysc_node **snode)
Michal Vasko1bf09392020-03-27 12:38:10 +0100353{
354 LY_ERR ret = LY_SUCCESS;
Michal Vaskoda8fbbf2021-06-16 11:44:44 +0200355 struct lyxml_ctx *xmlctx = lydctx->xmlctx, pxmlctx;
Michal Vasko1bf09392020-03-27 12:38:10 +0100356
Radek IÅ¡a3930fd72021-03-08 10:48:40 +0100357 if (!(lydctx->parse_opts & LYD_PARSE_OPAQ)) {
358 /* only checks specific to opaque nodes */
359 return LY_SUCCESS;
360 }
361
Michal Vasko13854662021-06-09 09:27:50 +0200362 if (!((*snode)->nodetype & (LYD_NODE_TERM | LYD_NODE_INNER))) {
363 /* nothing to check */
364 return LY_SUCCESS;
365 }
Michal Vasko1bf09392020-03-27 12:38:10 +0100366
Michal Vaskoda8fbbf2021-06-16 11:44:44 +0200367 assert(xmlctx->elements.count);
368
Michal Vasko13854662021-06-09 09:27:50 +0200369 /* backup parser */
Michal Vaskoda8fbbf2021-06-16 11:44:44 +0200370 LY_CHECK_RET(lyxml_ctx_backup(xmlctx, &pxmlctx));
Michal Vasko1bf09392020-03-27 12:38:10 +0100371
Michal Vasko13854662021-06-09 09:27:50 +0200372 /* skip attributes */
373 while (xmlctx->status == LYXML_ATTRIBUTE) {
374 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), restore);
375 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), restore);
376 }
Michal Vasko1bf09392020-03-27 12:38:10 +0100377
Michal Vasko13854662021-06-09 09:27:50 +0200378 if ((*snode)->nodetype & LYD_NODE_TERM) {
379 /* value may not be valid in which case we parse it as an opaque node */
380 if (lys_value_validate(NULL, *snode, xmlctx->value, xmlctx->value_len, LY_VALUE_XML, &xmlctx->ns)) {
Michal Vaskod0237d42021-07-12 14:49:46 +0200381 LOGVRB("Parsing opaque term node \"%s\" with invalid value \"%.*s\".", (*snode)->name, xmlctx->value_len,
382 xmlctx->value);
Michal Vasko13854662021-06-09 09:27:50 +0200383 *snode = NULL;
Michal Vasko1bf09392020-03-27 12:38:10 +0100384 }
Michal Vasko13854662021-06-09 09:27:50 +0200385 } else if ((*snode)->nodetype == LYS_LIST) {
386 /* skip content */
387 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), restore);
Michal Vasko1bf09392020-03-27 12:38:10 +0100388
Michal Vasko13854662021-06-09 09:27:50 +0200389 if (lydxml_check_list(xmlctx, *snode)) {
390 /* invalid list, parse as opaque if it missing/has invalid some keys */
Michal Vaskod0237d42021-07-12 14:49:46 +0200391 LOGVRB("Parsing opaque list node \"%s\" with missing/invalid keys.", (*snode)->name);
Michal Vasko13854662021-06-09 09:27:50 +0200392 *snode = NULL;
Michal Vasko1bf09392020-03-27 12:38:10 +0100393 }
Michal Vasko13854662021-06-09 09:27:50 +0200394 } else {
Radek IÅ¡a3930fd72021-03-08 10:48:40 +0100395 /* if there is a non-WS value, it cannot be parsed as an inner node */
396 assert(xmlctx->status == LYXML_ELEM_CONTENT);
397 if (!xmlctx->ws_only) {
398 *snode = NULL;
399 }
Michal Vasko1bf09392020-03-27 12:38:10 +0100400 }
401
Michal Vasko13854662021-06-09 09:27:50 +0200402restore:
403 /* restore parser */
Michal Vaskoda8fbbf2021-06-16 11:44:44 +0200404 lyxml_ctx_restore(xmlctx, &pxmlctx);
Michal Vasko1bf09392020-03-27 12:38:10 +0100405 return ret;
406}
407
Radek Krejcie7b95092019-05-15 11:03:07 +0200408/**
Michal Vaskoa5da3292020-08-12 13:10:50 +0200409 * @brief Parse XML subtree.
Radek Krejcie7b95092019-05-15 11:03:07 +0200410 *
Michal Vaskob36053d2020-03-26 15:49:30 +0100411 * @param[in] lydctx XML YANG data parser context.
Michal Vaskoe0665742021-02-11 11:08:44 +0100412 * @param[in,out] parent Parent node where the children are inserted. NULL in case of parsing top-level elements.
413 * @param[in,out] first_p Pointer to the first (@p parent or top-level) child. In case there were already some siblings,
414 * this may point to a previously existing node.
415 * @param[in,out] parsed Optional set to add all the parsed siblings into.
Michal Vasko9b368d32020-02-14 13:53:31 +0100416 * @return LY_ERR value.
Radek Krejcie7b95092019-05-15 11:03:07 +0200417 */
418static LY_ERR
Michal Vaskoe0665742021-02-11 11:08:44 +0100419lydxml_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 +0200420{
Michal Vaskob36053d2020-03-26 15:49:30 +0100421 LY_ERR ret = LY_SUCCESS;
Michal Vasko27c4dce2021-03-04 15:50:50 +0100422 const char *prefix, *name, *val;
Michal Vasko1bf09392020-03-27 12:38:10 +0100423 size_t prefix_len, name_len;
Michal Vaskob36053d2020-03-26 15:49:30 +0100424 struct lyxml_ctx *xmlctx;
425 const struct ly_ctx *ctx;
Radek Krejcie7b95092019-05-15 11:03:07 +0200426 const struct lyxml_ns *ns;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200427 struct lyd_meta *meta = NULL;
428 struct lyd_attr *attr = NULL;
Radek Krejcie7b95092019-05-15 11:03:07 +0200429 const struct lysc_node *snode;
430 struct lys_module *mod;
Michal Vaskoa98e3ea2021-06-03 09:13:33 +0200431 uint32_t prev_parse_opts, prev_int_opts;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200432 struct lyd_node *node = NULL, *anchor;
Michal Vaskofc2cd072021-02-24 13:17:17 +0100433 void *val_prefix_data = NULL;
Radek Krejci8df109d2021-04-23 12:19:08 +0200434 LY_VALUE_FORMAT format;
Radek Krejci1deb5be2020-08-26 16:43:36 +0200435 uint32_t getnext_opts;
Radek Krejcie7b95092019-05-15 11:03:07 +0200436
Michal Vaskoe0665742021-02-11 11:08:44 +0100437 assert(parent || first_p);
438
Michal Vaskob36053d2020-03-26 15:49:30 +0100439 xmlctx = lydctx->xmlctx;
440 ctx = xmlctx->ctx;
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100441 getnext_opts = lydctx->int_opts & LYD_INTOPT_REPLY ? LYS_GETNEXT_OUTPUT : 0;
Michal Vasko6f4cbb62020-02-28 11:15:47 +0100442
Michal Vaskoa5da3292020-08-12 13:10:50 +0200443 assert(xmlctx->status == LYXML_ELEMENT);
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200444
Michal Vaskoa5da3292020-08-12 13:10:50 +0200445 /* remember element prefix and name */
446 prefix = xmlctx->prefix;
447 prefix_len = xmlctx->prefix_len;
448 name = xmlctx->name;
449 name_len = xmlctx->name_len;
450
451 /* get the element module */
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200452 ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200453 if (!ns) {
Radek Krejci422afb12021-03-04 16:38:16 +0100454 LOGVAL(ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)prefix_len, prefix);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200455 ret = LY_EVALID;
456 goto error;
457 }
458 mod = ly_ctx_get_module_implemented_ns(ctx, ns->uri);
459 if (!mod) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100460 if (lydctx->parse_opts & LYD_PARSE_STRICT) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100461 LOGVAL(ctx, LYVE_REFERENCE, "No module with namespace \"%s\" in the context.", ns->uri);
Michal Vasko90932a92020-02-12 14:33:03 +0100462 ret = LY_EVALID;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200463 goto error;
Radek Krejcie7b95092019-05-15 11:03:07 +0200464 }
Michal Vaskoe0665742021-02-11 11:08:44 +0100465 if (!(lydctx->parse_opts & LYD_PARSE_OPAQ)) {
Michal Vaskoa5da3292020-08-12 13:10:50 +0200466 /* skip element with children */
467 LY_CHECK_GOTO(ret = lydxml_data_skip(xmlctx), error);
468 return LY_SUCCESS;
Radek Krejcie7b95092019-05-15 11:03:07 +0200469 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200470 }
471
Michal Vaskoa5da3292020-08-12 13:10:50 +0200472 /* parser next */
473 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
Michal Vasko90932a92020-02-12 14:33:03 +0100474
Michal Vaskoa5da3292020-08-12 13:10:50 +0200475 /* get the schema node */
476 snode = NULL;
Michal Vasko81008a52021-07-21 16:06:12 +0200477 if (mod) {
Radek Krejcif16e2542021-02-17 15:39:23 +0100478 if (!parent && lydctx->ext) {
Radek Krejciba05eab2021-03-10 13:19:29 +0100479 snode = lysc_ext_find_node(lydctx->ext, mod, name, name_len, 0, getnext_opts);
Radek Krejcif16e2542021-02-17 15:39:23 +0100480 } else {
481 snode = lys_find_child(parent ? parent->schema : NULL, mod, name, name_len, 0, getnext_opts);
482 }
Michal Vaskoa5da3292020-08-12 13:10:50 +0200483 if (!snode) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100484 if (lydctx->parse_opts & LYD_PARSE_STRICT) {
485 if (parent) {
Radek Krejci422afb12021-03-04 16:38:16 +0100486 LOGVAL(ctx, LYVE_REFERENCE, "Node \"%.*s\" not found as a child of \"%s\" node.",
487 (int)name_len, name, parent->schema->name);
Radek Krejcif16e2542021-02-17 15:39:23 +0100488 } else if (lydctx->ext) {
489 if (lydctx->ext->argument) {
Radek Krejci422afb12021-03-04 16:38:16 +0100490 LOGVAL(ctx, LYVE_REFERENCE, "Node \"%.*s\" not found in the \"%s\" %s extension instance.",
491 (int)name_len, name, lydctx->ext->argument, lydctx->ext->def->name);
Radek Krejcif16e2542021-02-17 15:39:23 +0100492 } else {
Radek Krejci422afb12021-03-04 16:38:16 +0100493 LOGVAL(ctx, LYVE_REFERENCE, "Node \"%.*s\" not found in the %s extension instance.",
494 (int)name_len, name, lydctx->ext->def->name);
Radek Krejcif16e2542021-02-17 15:39:23 +0100495 }
Michal Vaskoe0665742021-02-11 11:08:44 +0100496 } else {
Radek Krejci422afb12021-03-04 16:38:16 +0100497 LOGVAL(ctx, LYVE_REFERENCE, "Node \"%.*s\" not found in the \"%s\" module.",
498 (int)name_len, name, mod->name);
Michal Vaskoe0665742021-02-11 11:08:44 +0100499 }
Michal Vaskoa5da3292020-08-12 13:10:50 +0200500 ret = LY_EVALID;
501 goto error;
Michal Vaskoe0665742021-02-11 11:08:44 +0100502 } else if (!(lydctx->parse_opts & LYD_PARSE_OPAQ)) {
Michal Vaskod4f82492022-01-05 12:06:51 +0100503 LOGVRB("Skipping parsing of unknown node \"%.*s\".", name_len, name);
Michal Vaskod0237d42021-07-12 14:49:46 +0200504
Michal Vaskoa5da3292020-08-12 13:10:50 +0200505 /* skip element with children */
506 LY_CHECK_GOTO(ret = lydxml_data_skip(xmlctx), error);
507 return LY_SUCCESS;
508 }
509 } else {
510 /* check that schema node is valid and can be used */
511 LY_CHECK_GOTO(ret = lyd_parser_check_schema((struct lyd_ctx *)lydctx, snode), error);
512 LY_CHECK_GOTO(ret = lydxml_data_check_opaq(lydctx, &snode), error);
513 }
514 }
515
516 /* create metadata/attributes */
517 if (xmlctx->status == LYXML_ATTRIBUTE) {
518 if (snode) {
Michal Vasko45791ad2021-06-17 08:45:03 +0200519 ret = lydxml_metadata(lydctx, snode->exts, &meta);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200520 LY_CHECK_GOTO(ret, error);
521 } else {
Michal Vaskoe0665742021-02-11 11:08:44 +0100522 assert(lydctx->parse_opts & LYD_PARSE_OPAQ);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200523 ret = lydxml_attrs(xmlctx, &attr);
524 LY_CHECK_GOTO(ret, error);
525 }
526 }
527
528 assert(xmlctx->status == LYXML_ELEM_CONTENT);
529 if (!snode) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100530 assert(lydctx->parse_opts & LYD_PARSE_OPAQ);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200531
532 if (xmlctx->ws_only) {
533 /* ignore WS-only value */
Radek IÅ¡a017270d2021-02-16 10:26:15 +0100534 if (xmlctx->dynamic) {
535 free((char *) xmlctx->value);
536 }
537 xmlctx->dynamic = 0;
538 xmlctx->value = "";
Michal Vaskoa5da3292020-08-12 13:10:50 +0200539 xmlctx->value_len = 0;
Radek Krejci8df109d2021-04-23 12:19:08 +0200540 format = LY_VALUE_XML;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200541 } else {
542 /* get value prefixes */
Radek Krejci8df109d2021-04-23 12:19:08 +0200543 ret = ly_store_prefix_data(xmlctx->ctx, xmlctx->value, xmlctx->value_len, LY_VALUE_XML,
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100544 &xmlctx->ns, &format, &val_prefix_data);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200545 LY_CHECK_GOTO(ret, error);
546 }
547
Michal Vaskoda8fbbf2021-06-16 11:44:44 +0200548 /* get NS again, it may have been backed up and restored */
549 ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
550 assert(ns);
551
Michal Vaskoa5da3292020-08-12 13:10:50 +0200552 /* create node */
Michal Vasko501af032020-11-11 20:27:44 +0100553 ret = lyd_create_opaq(ctx, name, name_len, prefix, prefix_len, ns->uri, strlen(ns->uri), xmlctx->value,
554 xmlctx->value_len, &xmlctx->dynamic, format, val_prefix_data, LYD_HINT_DATA, &node);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200555 LY_CHECK_GOTO(ret, error);
556
557 /* parser next */
558 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
559
560 /* process children */
561 while (xmlctx->status == LYXML_ELEMENT) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100562 ret = lydxml_subtree_r(lydctx, node, lyd_node_child_p(node), NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200563 LY_CHECK_GOTO(ret, error);
564 }
565 } else if (snode->nodetype & LYD_NODE_TERM) {
566 /* create node */
Michal Vasko22df3f02020-08-24 13:29:22 +0200567 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 +0200568 &xmlctx->dynamic, LY_VALUE_XML, &xmlctx->ns, LYD_HINT_DATA, &node), error);
Radek Krejciddace2c2021-01-08 11:30:56 +0100569 LOG_LOCSET(snode, node, NULL, NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200570
571 if (parent && (node->schema->flags & LYS_KEY)) {
572 /* check the key order, the anchor must never be a key */
Michal Vaskoe0665742021-02-11 11:08:44 +0100573 anchor = lyd_insert_get_next_anchor(lyd_child(parent), node);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200574 if (anchor && (anchor->schema->flags & LYS_KEY)) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100575 if (lydctx->parse_opts & LYD_PARSE_STRICT) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100576 LOGVAL(ctx, LYVE_DATA, "Invalid position of the key \"%s\" in a list.", node->schema->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200577 ret = LY_EVALID;
578 goto error;
579 } else {
580 LOGWRN(ctx, "Invalid position of the key \"%s\" in a list.", node->schema->name);
581 }
582 }
583 }
584
585 /* parser next */
586 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
587
588 /* no children expected */
589 if (xmlctx->status == LYXML_ELEMENT) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100590 LOGVAL(ctx, LYVE_SYNTAX, "Child element \"%.*s\" inside a terminal node \"%s\" found.",
Radek Krejci422afb12021-03-04 16:38:16 +0100591 (int)xmlctx->name_len, xmlctx->name, snode->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200592 ret = LY_EVALID;
593 goto error;
594 }
595 } else if (snode->nodetype & LYD_NODE_INNER) {
596 if (!xmlctx->ws_only) {
597 /* value in inner node */
Radek Krejci2efc45b2020-12-22 16:25:44 +0100598 LOGVAL(ctx, LYVE_SYNTAX, "Text value \"%.*s\" inside an inner node \"%s\" found.",
Radek Krejci422afb12021-03-04 16:38:16 +0100599 (int)xmlctx->value_len, xmlctx->value, snode->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200600 ret = LY_EVALID;
601 goto error;
602 }
603
604 /* create node */
605 ret = lyd_create_inner(snode, &node);
606 LY_CHECK_GOTO(ret, error);
607
Radek Krejciddace2c2021-01-08 11:30:56 +0100608 LOG_LOCSET(snode, node, NULL, NULL);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100609
Michal Vaskoa5da3292020-08-12 13:10:50 +0200610 /* parser next */
611 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
612
613 /* process children */
614 while (xmlctx->status == LYXML_ELEMENT) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100615 ret = lydxml_subtree_r(lydctx, node, lyd_node_child_p(node), NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200616 LY_CHECK_GOTO(ret, error);
617 }
618
619 if (snode->nodetype == LYS_LIST) {
620 /* check all keys exist */
621 LY_CHECK_GOTO(ret = lyd_parse_check_keys(node), error);
622 }
623
Michal Vaskoe0665742021-02-11 11:08:44 +0100624 if (!(lydctx->parse_opts & LYD_PARSE_ONLY)) {
Michal Vaskoa5da3292020-08-12 13:10:50 +0200625 /* new node validation, autodelete CANNOT occur, all nodes are new */
Michal Vaskoe0665742021-02-11 11:08:44 +0100626 ret = lyd_validate_new(lyd_node_child_p(node), snode, NULL, NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200627 LY_CHECK_GOTO(ret, error);
628
629 /* add any missing default children */
Radek Krejci4f2e3e52021-03-30 14:20:28 +0200630 ret = lyd_new_implicit_r(node, lyd_node_child_p(node), NULL, NULL, &lydctx->node_when, &lydctx->node_exts,
631 &lydctx->node_types, (lydctx->val_opts & LYD_VALIDATE_NO_STATE) ? LYD_IMPLICIT_NO_STATE : 0, NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200632 LY_CHECK_GOTO(ret, error);
633 }
634
635 if (snode->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) {
636 /* rememeber the RPC/action/notification */
637 lydctx->op_node = node;
638 }
639 } else if (snode->nodetype & LYD_NODE_ANY) {
Michal Vasko27c4dce2021-03-04 15:50:50 +0100640 if ((snode->nodetype == LYS_ANYDATA) && !xmlctx->ws_only) {
641 /* value in anydata node, we expect a tree */
642 LOGVAL(ctx, LYVE_SYNTAX, "Text value \"%.*s\" inside an anydata node \"%s\" found.",
Radek Krejci422afb12021-03-04 16:38:16 +0100643 (int)xmlctx->value_len < 20 ? xmlctx->value_len : 20, xmlctx->value, snode->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200644 ret = LY_EVALID;
645 goto error;
646 }
647
Michal Vasko27c4dce2021-03-04 15:50:50 +0100648 if (!xmlctx->ws_only) {
649 /* use an arbitrary text value for anyxml */
650 lydict_insert(xmlctx->ctx, xmlctx->value, xmlctx->value_len, &val);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200651
Michal Vasko27c4dce2021-03-04 15:50:50 +0100652 /* parser next */
653 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
654
655 /* create node */
656 ret = lyd_create_any(snode, val, LYD_ANYDATA_STRING, 1, &node);
657 LY_CHECK_GOTO(ret, error);
658 } else {
659 /* parser next */
660 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
661
Michal Vaskoa98e3ea2021-06-03 09:13:33 +0200662 /* update options so that generic data can be parsed */
663 prev_parse_opts = lydctx->parse_opts;
Michal Vasko27c4dce2021-03-04 15:50:50 +0100664 lydctx->parse_opts &= ~LYD_PARSE_STRICT;
665 lydctx->parse_opts |= LYD_PARSE_OPAQ;
Michal Vaskoa98e3ea2021-06-03 09:13:33 +0200666 prev_int_opts = lydctx->int_opts;
Michal Vasko02ed9d82021-07-15 14:58:04 +0200667 lydctx->int_opts |= LYD_INTOPT_ANY | LYD_INTOPT_WITH_SIBLINGS;
Michal Vaskoa98e3ea2021-06-03 09:13:33 +0200668
669 /* parse any data tree */
Michal Vasko27c4dce2021-03-04 15:50:50 +0100670 anchor = NULL;
671 while (xmlctx->status == LYXML_ELEMENT) {
672 ret = lydxml_subtree_r(lydctx, NULL, &anchor, NULL);
Michal Vaskoa98e3ea2021-06-03 09:13:33 +0200673 if (ret) {
674 break;
675 }
Michal Vasko27c4dce2021-03-04 15:50:50 +0100676 }
Michal Vaskoa98e3ea2021-06-03 09:13:33 +0200677
678 /* restore options */
679 lydctx->parse_opts = prev_parse_opts;
680 lydctx->int_opts = prev_int_opts;
681
682 LY_CHECK_GOTO(ret, error);
Michal Vasko27c4dce2021-03-04 15:50:50 +0100683
684 /* create node */
685 ret = lyd_create_any(snode, anchor, LYD_ANYDATA_DATATREE, 1, &node);
686 LY_CHECK_GOTO(ret, error);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200687 }
Michal Vaskoa5da3292020-08-12 13:10:50 +0200688 }
689 assert(node);
690
691 /* add/correct flags */
692 if (snode) {
Radek Krejci4f2e3e52021-03-30 14:20:28 +0200693 lyd_parse_set_data_flags(node, &lydctx->node_when, &lydctx->node_exts, &meta, lydctx->parse_opts);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200694 }
695
696 /* parser next */
697 assert(xmlctx->status == LYXML_ELEM_CLOSE);
698 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
699
700 /* add metadata/attributes */
701 if (snode) {
Michal Vasko871a0252020-11-11 18:35:24 +0100702 lyd_insert_meta(node, meta, 0);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200703 } else {
704 lyd_insert_attr(node, attr);
705 }
706
707 /* insert, keep first pointer correct */
Michal Vasko6ee6f432021-07-16 09:49:14 +0200708 lyd_insert_node(parent, first_p, node, lydctx->parse_opts & LYD_PARSE_ORDERED ? 1 : 0);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200709 while (!parent && (*first_p)->prev->next) {
710 *first_p = (*first_p)->prev;
711 }
712
Michal Vaskoe0665742021-02-11 11:08:44 +0100713 /* rememeber a successfully parsed node */
714 if (parsed) {
715 ly_set_add(parsed, node, 1, NULL);
716 }
717
Radek Krejciddace2c2021-01-08 11:30:56 +0100718 LOG_LOCBACK(node ? 1 : 0, node ? 1 : 0, 0, 0);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200719 return LY_SUCCESS;
720
721error:
Radek Krejciddace2c2021-01-08 11:30:56 +0100722 LOG_LOCBACK(node ? 1 : 0, node ? 1 : 0, 0, 0);
Michal Vasko3a41dff2020-07-15 14:30:28 +0200723 lyd_free_meta_siblings(meta);
Radek Krejci011e4aa2020-09-04 15:22:31 +0200724 lyd_free_attr_siblings(ctx, attr);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200725 lyd_free_tree(node);
Radek Krejcie7b95092019-05-15 11:03:07 +0200726 return ret;
727}
728
Michal Vaskoe0665742021-02-11 11:08:44 +0100729/**
730 * @brief Parse a specific XML element into an opaque node.
731 *
732 * @param[in] xmlctx XML parser context.
733 * @param[in] name Name of the element.
734 * @param[in] uri URI of the element.
735 * @param[in] value Whether a value is expected in the element.
736 * @param[out] evnp Parsed envelope (opaque node).
737 * @return LY_SUCCESS on success.
738 * @return LY_ENOT if the specified element did not match.
739 * @return LY_ERR value on error.
740 */
Michal Vasko1bf09392020-03-27 12:38:10 +0100741static LY_ERR
Michal Vaskoe0665742021-02-11 11:08:44 +0100742lydxml_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 +0100743{
Michal Vaskoe0665742021-02-11 11:08:44 +0100744 LY_ERR rc = LY_SUCCESS;
745 const struct lyxml_ns *ns;
Radek Krejci1798aae2020-07-14 13:26:06 +0200746 struct lyd_attr *attr = NULL;
Michal Vasko1bf09392020-03-27 12:38:10 +0100747 const char *prefix;
748 size_t prefix_len;
749
Michal Vasko1bf09392020-03-27 12:38:10 +0100750 assert(xmlctx->status == LYXML_ELEMENT);
751 if (ly_strncmp(name, xmlctx->name, xmlctx->name_len)) {
752 /* not the expected element */
Michal Vaskoe0665742021-02-11 11:08:44 +0100753 return LY_ENOT;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100754 }
755
756 prefix = xmlctx->prefix;
757 prefix_len = xmlctx->prefix_len;
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200758 ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100759 if (!ns) {
Radek Krejci422afb12021-03-04 16:38:16 +0100760 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)prefix_len, prefix);
Michal Vaskoe0665742021-02-11 11:08:44 +0100761 return LY_EVALID;
762 } else if (strcmp(ns->uri, uri)) {
763 /* different namespace */
764 return LY_ENOT;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100765 }
766
767 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
768
769 /* create attributes */
770 if (xmlctx->status == LYXML_ATTRIBUTE) {
771 LY_CHECK_RET(lydxml_attrs(xmlctx, &attr));
772 }
773
Michal Vaskoe0665742021-02-11 11:08:44 +0100774 assert(xmlctx->status == LYXML_ELEM_CONTENT);
775 if (!value && !xmlctx->ws_only) {
776 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected value \"%.*s\" in the \"%s\" element.",
Radek Krejci422afb12021-03-04 16:38:16 +0100777 (int)xmlctx->value_len, xmlctx->value, name);
Michal Vaskoe0665742021-02-11 11:08:44 +0100778 rc = LY_EVALID;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100779 goto cleanup;
Michal Vaskoe0665742021-02-11 11:08:44 +0100780 }
Michal Vaskoa8edff02020-03-27 14:47:01 +0100781
782 /* create node */
Michal Vaskoe0665742021-02-11 11:08:44 +0100783 rc = lyd_create_opaq(xmlctx->ctx, name, strlen(name), prefix, prefix_len, uri, strlen(uri), xmlctx->value,
Radek Krejci8df109d2021-04-23 12:19:08 +0200784 xmlctx->ws_only ? 0 : xmlctx->value_len, NULL, LY_VALUE_XML, NULL, 0, envp);
Michal Vaskoe0665742021-02-11 11:08:44 +0100785 LY_CHECK_GOTO(rc, cleanup);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100786
787 /* assign atributes */
Michal Vaskoe0665742021-02-11 11:08:44 +0100788 ((struct lyd_node_opaq *)(*envp))->attr = attr;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100789 attr = NULL;
790
Michal Vaskoe0665742021-02-11 11:08:44 +0100791 /* parser next element */
792 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100793
Michal Vaskoe0665742021-02-11 11:08:44 +0100794cleanup:
795 lyd_free_attr_siblings(xmlctx->ctx, attr);
796 if (rc) {
797 lyd_free_tree(*envp);
798 *envp = NULL;
799 }
800 return rc;
801}
802
803/**
804 * @brief Parse all expected non-data XML elements of a NETCONF rpc message.
805 *
806 * @param[in] xmlctx XML parser context.
807 * @param[out] evnp Parsed envelope(s) (opaque node).
808 * @param[out] int_opts Internal options for parsing the rest of YANG data.
809 * @param[out] close_elem Number of parsed opened elements that need to be closed.
810 * @return LY_SUCCESS on success.
811 * @return LY_ERR value on error.
812 */
813static LY_ERR
814lydxml_env_netconf_rpc(struct lyxml_ctx *xmlctx, struct lyd_node **envp, uint32_t *int_opts, uint32_t *close_elem)
815{
816 LY_ERR rc = LY_SUCCESS, r;
817 struct lyd_node *child;
818
819 assert(envp && !*envp);
820
821 /* parse "rpc" */
822 r = lydxml_envelope(xmlctx, "rpc", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, envp);
Michal Vaskoe0665742021-02-11 11:08:44 +0100823 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
824
825 /* parse "action", if any */
826 r = lydxml_envelope(xmlctx, "action", "urn:ietf:params:xml:ns:yang:1", 0, &child);
827 if (r == LY_SUCCESS) {
828 /* insert */
Michal Vasko6ee6f432021-07-16 09:49:14 +0200829 lyd_insert_node(*envp, NULL, child, 0);
Michal Vaskoe0665742021-02-11 11:08:44 +0100830
831 /* NETCONF action */
832 *int_opts = LYD_INTOPT_NO_SIBLINGS | LYD_INTOPT_ACTION;
833 *close_elem = 2;
834 } else if (r == LY_ENOT) {
835 /* NETCONF RPC */
836 *int_opts = LYD_INTOPT_NO_SIBLINGS | LYD_INTOPT_RPC;
837 *close_elem = 1;
838 } else {
839 rc = r;
840 goto cleanup;
841 }
842
843cleanup:
844 if (rc) {
845 lyd_free_tree(*envp);
846 *envp = NULL;
847 }
848 return rc;
849}
850
851/**
852 * @brief Parse all expected non-data XML elements of a NETCONF notification message.
853 *
854 * @param[in] xmlctx XML parser context.
855 * @param[out] evnp Parsed envelope(s) (opaque node).
856 * @param[out] int_opts Internal options for parsing the rest of YANG data.
857 * @param[out] close_elem Number of parsed opened elements that need to be closed.
858 * @return LY_SUCCESS on success.
859 * @return LY_ERR value on error.
860 */
861static LY_ERR
862lydxml_env_netconf_notif(struct lyxml_ctx *xmlctx, struct lyd_node **envp, uint32_t *int_opts, uint32_t *close_elem)
863{
864 LY_ERR rc = LY_SUCCESS, r;
865 struct lyd_node *child;
866
867 assert(envp && !*envp);
868
869 /* parse "notification" */
870 r = lydxml_envelope(xmlctx, "notification", "urn:ietf:params:xml:ns:netconf:notification:1.0", 0, envp);
Michal Vaskoe0665742021-02-11 11:08:44 +0100871 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
872
873 /* parse "eventTime" */
874 r = lydxml_envelope(xmlctx, "eventTime", "urn:ietf:params:xml:ns:netconf:notification:1.0", 1, &child);
875 if (r == LY_ENOT) {
Radek Krejci422afb12021-03-04 16:38:16 +0100876 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unexpected element \"%.*s\" instead of \"eventTime\".",
877 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +0100878 r = LY_EVALID;
879 }
880 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
881
882 /* insert */
Michal Vasko6ee6f432021-07-16 09:49:14 +0200883 lyd_insert_node(*envp, NULL, child, 0);
Michal Vaskoe0665742021-02-11 11:08:44 +0100884
885 /* validate value */
886 /* TODO validate child->value as yang:date-and-time */
887
888 /* finish child parsing */
Michal Vaskoa8edff02020-03-27 14:47:01 +0100889 if (xmlctx->status != LYXML_ELEM_CLOSE) {
890 assert(xmlctx->status == LYXML_ELEMENT);
Michal Vaskoe0665742021-02-11 11:08:44 +0100891 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"eventTime\".",
Radek Krejci422afb12021-03-04 16:38:16 +0100892 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +0100893 rc = LY_EVALID;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100894 goto cleanup;
895 }
Michal Vaskoe0665742021-02-11 11:08:44 +0100896 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
897
898 /* NETCONF notification */
899 *int_opts = LYD_INTOPT_NO_SIBLINGS | LYD_INTOPT_NOTIF;
900 *close_elem = 1;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100901
902cleanup:
Michal Vaskoe0665742021-02-11 11:08:44 +0100903 if (rc) {
Michal Vaskoa8edff02020-03-27 14:47:01 +0100904 lyd_free_tree(*envp);
Michal Vaskoe0665742021-02-11 11:08:44 +0100905 *envp = NULL;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100906 }
Michal Vaskoe0665742021-02-11 11:08:44 +0100907 return rc;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100908}
Michal Vasko79135ae2020-12-16 10:08:35 +0100909
Michal Vaskoe0665742021-02-11 11:08:44 +0100910/**
911 * @brief Parse an XML element as an opaque node subtree.
912 *
913 * @param[in] xmlctx XML parser context.
914 * @param[in] parent Parent to append nodes to.
915 * @return LY_ERR value.
916 */
917static LY_ERR
918lydxml_opaq_r(struct lyxml_ctx *xmlctx, struct lyd_node *parent)
Michal Vaskoa8edff02020-03-27 14:47:01 +0100919{
Michal Vaskoe0665742021-02-11 11:08:44 +0100920 LY_ERR rc = LY_SUCCESS;
921 const struct lyxml_ns *ns;
922 struct lyd_attr *attr = NULL;
923 struct lyd_node *child = NULL;
924 const char *name, *prefix;
925 size_t name_len, prefix_len;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100926
Michal Vaskoe0665742021-02-11 11:08:44 +0100927 assert(xmlctx->status == LYXML_ELEMENT);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100928
Michal Vaskoe0665742021-02-11 11:08:44 +0100929 name = xmlctx->name;
930 name_len = xmlctx->name_len;
931 prefix = xmlctx->prefix;
932 prefix_len = xmlctx->prefix_len;
933 ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
934 if (!ns) {
Radek Krejci422afb12021-03-04 16:38:16 +0100935 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)prefix_len, prefix);
Michal Vaskoe0665742021-02-11 11:08:44 +0100936 return LY_EVALID;
937 }
Michal Vaskoa8edff02020-03-27 14:47:01 +0100938
Michal Vaskoe0665742021-02-11 11:08:44 +0100939 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
Michal Vaskoa8edff02020-03-27 14:47:01 +0100940
Michal Vaskoe0665742021-02-11 11:08:44 +0100941 /* create attributes */
942 if (xmlctx->status == LYXML_ATTRIBUTE) {
943 LY_CHECK_RET(lydxml_attrs(xmlctx, &attr));
944 }
945
946 /* create node */
947 assert(xmlctx->status == LYXML_ELEM_CONTENT);
948 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 +0200949 xmlctx->ws_only ? 0 : xmlctx->value_len, NULL, LY_VALUE_XML, NULL, 0, &child);
Michal Vaskoe0665742021-02-11 11:08:44 +0100950 LY_CHECK_GOTO(rc, cleanup);
951
952 /* assign atributes */
953 ((struct lyd_node_opaq *)child)->attr = attr;
954 attr = NULL;
955
956 /* parser next element */
957 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
958
959 /* parse all the descendants */
960 while (xmlctx->status == LYXML_ELEMENT) {
961 rc = lydxml_opaq_r(xmlctx, child);
962 LY_CHECK_GOTO(rc, cleanup);
963 }
964
965 /* insert */
Michal Vasko6ee6f432021-07-16 09:49:14 +0200966 lyd_insert_node(parent, NULL, child, 1);
Michal Vaskoe0665742021-02-11 11:08:44 +0100967
968cleanup:
969 lyd_free_attr_siblings(xmlctx->ctx, attr);
970 if (rc) {
971 lyd_free_tree(child);
972 }
973 return rc;
974}
975
976/**
977 * @brief Parse all expected non-data XML elements of the error-info element in NETCONF rpc-reply message.
978 *
979 * @param[in] xmlctx XML parser context.
980 * @param[in] parent Parent to append nodes to.
981 * @return LY_ERR value.
982 */
983static LY_ERR
984lydxml_env_netconf_rpc_reply_error_info(struct lyxml_ctx *xmlctx, struct lyd_node *parent)
985{
986 LY_ERR r;
987 struct lyd_node *child, *iter;
988 const struct lyxml_ns *ns;
989 ly_bool no_dup;
990
991 /* there must be some child */
992 if (xmlctx->status == LYXML_ELEM_CLOSE) {
993 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Missing child elements of \"error-info\".");
994 return LY_EVALID;
995 }
996
997 while (xmlctx->status == LYXML_ELEMENT) {
998 child = NULL;
999
1000 /*
1001 * session-id
1002 */
1003 r = lydxml_envelope(xmlctx, "session-id", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1004 if (r == LY_SUCCESS) {
1005 no_dup = 1;
1006 goto check_child;
1007 } else if (r != LY_ENOT) {
1008 goto error;
1009 }
1010
1011 /*
1012 * bad-attribute
1013 */
1014 r = lydxml_envelope(xmlctx, "bad-attribute", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1015 if (r == LY_SUCCESS) {
1016 no_dup = 1;
1017 goto check_child;
1018 } else if (r != LY_ENOT) {
1019 goto error;
1020 }
1021
1022 /*
1023 * bad-element
1024 */
1025 r = lydxml_envelope(xmlctx, "bad-element", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1026 if (r == LY_SUCCESS) {
1027 no_dup = 1;
1028 goto check_child;
1029 } else if (r != LY_ENOT) {
1030 goto error;
1031 }
1032
1033 /*
1034 * bad-namespace
1035 */
1036 r = lydxml_envelope(xmlctx, "bad-namespace", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1037 if (r == LY_SUCCESS) {
1038 no_dup = 1;
1039 goto check_child;
1040 } else if (r != LY_ENOT) {
1041 goto error;
1042 }
1043
1044 if (r == LY_ENOT) {
1045 assert(xmlctx->status == LYXML_ELEMENT);
1046
1047 /* learn namespace */
1048 ns = lyxml_ns_get(&xmlctx->ns, xmlctx->prefix, xmlctx->prefix_len);
1049 if (!ns) {
Radek Krejci422afb12021-03-04 16:38:16 +01001050 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)xmlctx->prefix_len, xmlctx->prefix);
Michal Vaskoe0665742021-02-11 11:08:44 +01001051 r = LY_EVALID;
1052 goto error;
1053 } else if (!strcmp(ns->uri, "urn:ietf:params:xml:ns:netconf:base:1.0")) {
1054 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"error-info\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001055 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001056 r = LY_EVALID;
1057 goto error;
1058 }
1059
1060 /* custom elements */
1061 r = lydxml_opaq_r(xmlctx, parent);
1062 LY_CHECK_GOTO(r, error);
Michal Vaskoe5ff3672022-01-10 10:12:30 +01001063 continue;
Michal Vaskoe0665742021-02-11 11:08:44 +01001064 }
1065
1066check_child:
1067 /* check for duplicates */
1068 if (no_dup) {
1069 LY_LIST_FOR(lyd_child(parent), iter) {
1070 if ((((struct lyd_node_opaq *)iter)->name.name == ((struct lyd_node_opaq *)child)->name.name) &&
1071 (((struct lyd_node_opaq *)iter)->name.module_ns == ((struct lyd_node_opaq *)child)->name.module_ns)) {
1072 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Duplicate element \"%s\" in \"error-info\".",
1073 ((struct lyd_node_opaq *)child)->name.name);
1074 r = LY_EVALID;
1075 goto error;
1076 }
1077 }
1078 }
1079
1080 /* finish child parsing */
1081 if (xmlctx->status != LYXML_ELEM_CLOSE) {
1082 assert(xmlctx->status == LYXML_ELEMENT);
1083 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"error-info\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001084 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001085 r = LY_EVALID;
1086 goto error;
1087 }
1088 LY_CHECK_GOTO(r = lyxml_ctx_next(xmlctx), error);
1089
1090 /* insert */
Michal Vasko6ee6f432021-07-16 09:49:14 +02001091 lyd_insert_node(parent, NULL, child, 1);
Michal Vaskoe0665742021-02-11 11:08:44 +01001092 }
1093
1094 return LY_SUCCESS;
1095
1096error:
1097 lyd_free_tree(child);
1098 return r;
1099}
1100
1101/**
1102 * @brief Parse all expected non-data XML elements of the rpc-error element in NETCONF rpc-reply message.
1103 *
1104 * @param[in] xmlctx XML parser context.
1105 * @param[in] parent Parent to append nodes to.
1106 * @return LY_ERR value.
1107 */
1108static LY_ERR
1109lydxml_env_netconf_rpc_reply_error(struct lyxml_ctx *xmlctx, struct lyd_node *parent)
1110{
1111 LY_ERR r;
1112 struct lyd_node *child, *iter;
1113 const char *val;
1114 ly_bool no_dup;
1115
1116 /* there must be some child */
1117 if (xmlctx->status == LYXML_ELEM_CLOSE) {
1118 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Missing child elements of \"rpc-error\".");
1119 return LY_EVALID;
1120 }
1121
1122 while (xmlctx->status == LYXML_ELEMENT) {
1123 child = NULL;
1124
1125 /*
1126 * error-type
1127 */
1128 r = lydxml_envelope(xmlctx, "error-type", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1129 if (r == LY_SUCCESS) {
1130 val = ((struct lyd_node_opaq *)child)->value;
1131 if (strcmp(val, "transport") && strcmp(val, "rpc") && strcmp(val, "protocol") && strcmp(val, "application")) {
1132 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Invalid value \"%s\" of element \"%s\".", val,
1133 ((struct lyd_node_opaq *)child)->name.name);
1134 r = LY_EVALID;
1135 goto error;
1136 }
1137
1138 no_dup = 1;
1139 goto check_child;
1140 } else if (r != LY_ENOT) {
1141 goto error;
1142 }
1143
1144 /*
1145 * error-tag
1146 */
1147 r = lydxml_envelope(xmlctx, "error-tag", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1148 if (r == LY_SUCCESS) {
1149 val = ((struct lyd_node_opaq *)child)->value;
1150 if (strcmp(val, "in-use") && strcmp(val, "invalid-value") && strcmp(val, "too-big") &&
1151 strcmp(val, "missing-attribute") && strcmp(val, "bad-attribute") &&
1152 strcmp(val, "unknown-attribute") && strcmp(val, "missing-element") && strcmp(val, "bad-element") &&
1153 strcmp(val, "unknown-element") && strcmp(val, "unknown-namespace") && strcmp(val, "access-denied") &&
1154 strcmp(val, "lock-denied") && strcmp(val, "resource-denied") && strcmp(val, "rollback-failed") &&
1155 strcmp(val, "data-exists") && strcmp(val, "data-missing") && strcmp(val, "operation-not-supported") &&
1156 strcmp(val, "operation-failed") && strcmp(val, "malformed-message")) {
1157 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Invalid value \"%s\" of element \"%s\".", val,
1158 ((struct lyd_node_opaq *)child)->name.name);
1159 r = LY_EVALID;
1160 goto error;
1161 }
1162
1163 no_dup = 1;
1164 goto check_child;
1165 } else if (r != LY_ENOT) {
1166 goto error;
1167 }
1168
1169 /*
1170 * error-severity
1171 */
1172 r = lydxml_envelope(xmlctx, "error-severity", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1173 if (r == LY_SUCCESS) {
1174 val = ((struct lyd_node_opaq *)child)->value;
1175 if (strcmp(val, "error") && strcmp(val, "warning")) {
1176 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Invalid value \"%s\" of element \"%s\".", val,
1177 ((struct lyd_node_opaq *)child)->name.name);
1178 r = LY_EVALID;
1179 goto error;
1180 }
1181
1182 no_dup = 1;
1183 goto check_child;
1184 } else if (r != LY_ENOT) {
1185 goto error;
1186 }
1187
1188 /*
1189 * error-app-tag
1190 */
1191 r = lydxml_envelope(xmlctx, "error-app-tag", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1192 if (r == LY_SUCCESS) {
1193 no_dup = 1;
1194 goto check_child;
1195 } else if (r != LY_ENOT) {
1196 goto error;
1197 }
1198
1199 /*
1200 * error-path
1201 */
1202 r = lydxml_envelope(xmlctx, "error-path", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1203 if (r == LY_SUCCESS) {
1204 no_dup = 1;
1205 goto check_child;
1206 } else if (r != LY_ENOT) {
1207 goto error;
1208 }
1209
1210 /*
1211 * error-message
1212 */
1213 r = lydxml_envelope(xmlctx, "error-message", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1214 if (r == LY_SUCCESS) {
1215 no_dup = 1;
1216 goto check_child;
1217 } else if (r != LY_ENOT) {
1218 goto error;
1219 }
1220
1221 /* error-info */
1222 r = lydxml_envelope(xmlctx, "error-info", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, &child);
1223 if (r == LY_SUCCESS) {
1224 /* parse all the descendants */
1225 LY_CHECK_GOTO(r = lydxml_env_netconf_rpc_reply_error_info(xmlctx, child), error);
1226
1227 no_dup = 0;
1228 goto check_child;
1229 } else if (r != LY_ENOT) {
1230 goto error;
1231 }
1232
1233 if (r == LY_ENOT) {
1234 assert(xmlctx->status == LYXML_ELEMENT);
1235 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"rpc-error\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001236 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001237 r = LY_EVALID;
1238 goto error;
1239 }
1240
1241check_child:
1242 /* check for duplicates */
1243 if (no_dup) {
1244 LY_LIST_FOR(lyd_child(parent), iter) {
1245 if ((((struct lyd_node_opaq *)iter)->name.name == ((struct lyd_node_opaq *)child)->name.name) &&
1246 (((struct lyd_node_opaq *)iter)->name.module_ns == ((struct lyd_node_opaq *)child)->name.module_ns)) {
1247 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Duplicate element \"%s\" in \"rpc-error\".",
1248 ((struct lyd_node_opaq *)child)->name.name);
1249 r = LY_EVALID;
1250 goto error;
1251 }
1252 }
1253 }
1254
1255 /* finish child parsing */
1256 if (xmlctx->status != LYXML_ELEM_CLOSE) {
1257 assert(xmlctx->status == LYXML_ELEMENT);
1258 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"rpc-error\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001259 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001260 r = LY_EVALID;
1261 goto error;
1262 }
1263 LY_CHECK_GOTO(r = lyxml_ctx_next(xmlctx), error);
1264
1265 /* insert */
Michal Vasko6ee6f432021-07-16 09:49:14 +02001266 lyd_insert_node(parent, NULL, child, 1);
Michal Vaskoe0665742021-02-11 11:08:44 +01001267 }
1268
1269 return LY_SUCCESS;
1270
1271error:
1272 lyd_free_tree(child);
1273 return r;
1274}
1275
1276/**
1277 * @brief Parse all expected non-data XML elements of a NETCONF rpc-reply message.
1278 *
1279 * @param[in] xmlctx XML parser context.
1280 * @param[out] evnp Parsed envelope(s) (opaque node).
1281 * @param[out] int_opts Internal options for parsing the rest of YANG data.
1282 * @param[out] close_elem Number of parsed opened elements that need to be closed.
1283 * @return LY_SUCCESS on success.
1284 * @return LY_ERR value on error.
1285 */
1286static LY_ERR
1287lydxml_env_netconf_reply(struct lyxml_ctx *xmlctx, struct lyd_node **envp, uint32_t *int_opts, uint32_t *close_elem)
1288{
1289 LY_ERR rc = LY_SUCCESS, r;
1290 struct lyd_node *child = NULL;
1291 const char *parsed_elem = NULL;
1292
1293 assert(envp && !*envp);
1294
1295 /* parse "rpc-reply" */
1296 r = lydxml_envelope(xmlctx, "rpc-reply", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, envp);
Michal Vaskoe0665742021-02-11 11:08:44 +01001297 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
1298
1299 /* there must be some child */
1300 if (xmlctx->status == LYXML_ELEM_CLOSE) {
1301 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Missing child elements of \"rpc-reply\".");
1302 rc = LY_EVALID;
Michal Vaskocf770e22020-08-12 13:21:43 +02001303 goto cleanup;
Michal Vaskoa8edff02020-03-27 14:47:01 +01001304 }
1305
Michal Vaskoe0665742021-02-11 11:08:44 +01001306 /* try to parse "ok" */
1307 r = lydxml_envelope(xmlctx, "ok", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, &child);
1308 if (r == LY_SUCCESS) {
1309 /* insert */
Michal Vasko6ee6f432021-07-16 09:49:14 +02001310 lyd_insert_node(*envp, NULL, child, 1);
Michal Vaskoe0665742021-02-11 11:08:44 +01001311
1312 /* finish child parsing */
1313 if (xmlctx->status != LYXML_ELEM_CLOSE) {
1314 assert(xmlctx->status == LYXML_ELEMENT);
1315 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"ok\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001316 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001317 rc = LY_EVALID;
1318 goto cleanup;
1319 }
1320 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
1321
1322 /* success */
1323 parsed_elem = "ok";
1324 goto finish;
1325 } else if (r != LY_ENOT) {
1326 rc = r;
1327 goto cleanup;
Michal Vasko2552ea32020-12-08 15:32:34 +01001328 }
1329
Michal Vaskoe0665742021-02-11 11:08:44 +01001330 /* try to parse all "rpc-error" elements */
1331 while (xmlctx->status == LYXML_ELEMENT) {
1332 r = lydxml_envelope(xmlctx, "rpc-error", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, &child);
1333 if (r == LY_ENOT) {
1334 break;
1335 } else if (r) {
1336 rc = r;
1337 goto cleanup;
1338 }
1339
1340 /* insert */
Michal Vasko6ee6f432021-07-16 09:49:14 +02001341 lyd_insert_node(*envp, NULL, child, 1);
Michal Vaskoe0665742021-02-11 11:08:44 +01001342
1343 /* parse all children of "rpc-error" */
1344 LY_CHECK_GOTO(rc = lydxml_env_netconf_rpc_reply_error(xmlctx, child), cleanup);
1345
1346 /* finish child parsing */
1347 assert(xmlctx->status == LYXML_ELEM_CLOSE);
1348 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
1349
1350 parsed_elem = "rpc-error";
Michal Vasko2552ea32020-12-08 15:32:34 +01001351 }
Michal Vaskoe0665742021-02-11 11:08:44 +01001352
1353finish:
1354 if (parsed_elem) {
1355 /* NETCONF rpc-reply with no data */
1356 if (xmlctx->status != LYXML_ELEM_CLOSE) {
1357 assert(xmlctx->status == LYXML_ELEMENT);
1358 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected sibling element \"%.*s\" of \"%s\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001359 (int)xmlctx->name_len, xmlctx->name, parsed_elem);
Michal Vaskoe0665742021-02-11 11:08:44 +01001360 rc = LY_EVALID;
1361 goto cleanup;
1362 }
1363 }
1364
1365 /* NETCONF rpc-reply */
Michal Vasko1d991fd2021-07-09 13:14:40 +02001366 *int_opts = LYD_INTOPT_WITH_SIBLINGS | LYD_INTOPT_REPLY;
Michal Vaskoe0665742021-02-11 11:08:44 +01001367 *close_elem = 1;
1368
1369cleanup:
1370 if (rc) {
1371 lyd_free_tree(*envp);
1372 *envp = NULL;
1373 }
1374 return rc;
1375}
1376
Michal Vasko2552ea32020-12-08 15:32:34 +01001377LY_ERR
Radek Krejcif16e2542021-02-17 15:39:23 +01001378lyd_parse_xml(const struct ly_ctx *ctx, const struct lysc_ext_instance *ext, struct lyd_node *parent,
1379 struct lyd_node **first_p, struct ly_in *in, uint32_t parse_opts, uint32_t val_opts, enum lyd_type data_type,
1380 struct lyd_node **envp, struct ly_set *parsed, struct lyd_ctx **lydctx_p)
Michal Vasko2552ea32020-12-08 15:32:34 +01001381{
Michal Vaskoe0665742021-02-11 11:08:44 +01001382 LY_ERR rc = LY_SUCCESS;
1383 struct lyd_xml_ctx *lydctx;
Michal Vasko2ca9f9e2021-07-02 09:21:36 +02001384 uint32_t i, int_opts = 0, close_elem = 0;
Michal Vaskoe0665742021-02-11 11:08:44 +01001385 ly_bool parsed_data_nodes = 0;
Michal Vasko2552ea32020-12-08 15:32:34 +01001386
Michal Vaskoe0665742021-02-11 11:08:44 +01001387 assert(ctx && in && lydctx_p);
1388 assert(!(parse_opts & ~LYD_PARSE_OPTS_MASK));
1389 assert(!(val_opts & ~LYD_VALIDATE_OPTS_MASK));
Michal Vasko2552ea32020-12-08 15:32:34 +01001390
Michal Vaskoe0665742021-02-11 11:08:44 +01001391 /* init context */
1392 lydctx = calloc(1, sizeof *lydctx);
1393 LY_CHECK_ERR_RET(!lydctx, LOGMEM(ctx), LY_EMEM);
1394 LY_CHECK_GOTO(rc = lyxml_ctx_new(ctx, in, &lydctx->xmlctx), cleanup);
1395 lydctx->parse_opts = parse_opts;
1396 lydctx->val_opts = val_opts;
1397 lydctx->free = lyd_xml_ctx_free;
Radek Krejcif16e2542021-02-17 15:39:23 +01001398 lydctx->ext = ext;
Michal Vasko2552ea32020-12-08 15:32:34 +01001399
Michal Vaskoe0665742021-02-11 11:08:44 +01001400 switch (data_type) {
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001401 case LYD_TYPE_DATA_YANG:
Michal Vaskoe0665742021-02-11 11:08:44 +01001402 int_opts = LYD_INTOPT_WITH_SIBLINGS;
1403 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001404 case LYD_TYPE_RPC_YANG:
Michal Vaskoe0665742021-02-11 11:08:44 +01001405 int_opts = LYD_INTOPT_RPC | LYD_INTOPT_ACTION | LYD_INTOPT_NO_SIBLINGS;
1406 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001407 case LYD_TYPE_NOTIF_YANG:
Michal Vaskoe0665742021-02-11 11:08:44 +01001408 int_opts = LYD_INTOPT_NOTIF | LYD_INTOPT_NO_SIBLINGS;
1409 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001410 case LYD_TYPE_REPLY_YANG:
Michal Vaskoe0665742021-02-11 11:08:44 +01001411 int_opts = LYD_INTOPT_REPLY | LYD_INTOPT_NO_SIBLINGS;
1412 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001413 case LYD_TYPE_RPC_NETCONF:
Michal Vaskoe0665742021-02-11 11:08:44 +01001414 assert(!parent);
1415 LY_CHECK_GOTO(rc = lydxml_env_netconf_rpc(lydctx->xmlctx, envp, &int_opts, &close_elem), cleanup);
1416 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001417 case LYD_TYPE_NOTIF_NETCONF:
1418 assert(!parent);
1419 LY_CHECK_GOTO(rc = lydxml_env_netconf_notif(lydctx->xmlctx, envp, &int_opts, &close_elem), cleanup);
1420 break;
1421 case LYD_TYPE_REPLY_NETCONF:
Michal Vaskoe0665742021-02-11 11:08:44 +01001422 assert(parent);
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001423 LY_CHECK_GOTO(rc = lydxml_env_netconf_reply(lydctx->xmlctx, envp, &int_opts, &close_elem), cleanup);
Michal Vaskoe0665742021-02-11 11:08:44 +01001424 break;
1425 }
1426 lydctx->int_opts = int_opts;
1427
1428 /* find the operation node if it exists already */
1429 LY_CHECK_GOTO(rc = lyd_parser_find_operation(parent, int_opts, &lydctx->op_node), cleanup);
1430
1431 /* parse XML data */
1432 while (lydctx->xmlctx->status == LYXML_ELEMENT) {
1433 LY_CHECK_GOTO(rc = lydxml_subtree_r(lydctx, parent, first_p, parsed), cleanup);
1434 parsed_data_nodes = 1;
1435
1436 if (!(int_opts & LYD_INTOPT_WITH_SIBLINGS)) {
1437 break;
1438 }
Michal Vasko2552ea32020-12-08 15:32:34 +01001439 }
1440
Michal Vaskoe0665742021-02-11 11:08:44 +01001441 /* close all opened elements */
1442 for (i = 0; i < close_elem; ++i) {
1443 if (lydctx->xmlctx->status != LYXML_ELEM_CLOSE) {
1444 assert(lydctx->xmlctx->status == LYXML_ELEMENT);
Radek Krejci422afb12021-03-04 16:38:16 +01001445 LOGVAL(lydctx->xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\".",
1446 (int)lydctx->xmlctx->name_len, lydctx->xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001447 rc = LY_EVALID;
1448 goto cleanup;
1449 }
1450
1451 LY_CHECK_GOTO(rc = lyxml_ctx_next(lydctx->xmlctx), cleanup);
Michal Vasko4189c0f2020-08-13 09:05:22 +02001452 }
Michal Vaskoe0665742021-02-11 11:08:44 +01001453
1454 /* check final state */
1455 if ((int_opts & LYD_INTOPT_NO_SIBLINGS) && (lydctx->xmlctx->status == LYXML_ELEMENT)) {
1456 LOGVAL(ctx, LYVE_SYNTAX, "Unexpected sibling node.");
1457 rc = LY_EVALID;
1458 goto cleanup;
1459 }
Michal Vaskoe601aaa2022-01-03 11:35:13 +01001460 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 +01001461 LOGVAL(ctx, LYVE_DATA, "Missing the operation node.");
1462 rc = LY_EVALID;
1463 goto cleanup;
1464 }
1465
1466 if (!parsed_data_nodes) {
1467 /* no data nodes were parsed */
1468 lydctx->op_node = NULL;
Michal Vaskoa8edff02020-03-27 14:47:01 +01001469 }
1470
1471cleanup:
Michal Vaskoe0665742021-02-11 11:08:44 +01001472 /* there should be no unres stored if validation should be skipped */
1473 assert(!(parse_opts & LYD_PARSE_ONLY) || (!lydctx->node_types.count && !lydctx->meta_types.count &&
Radek Krejci4f2e3e52021-03-30 14:20:28 +02001474 !lydctx->node_when.count && !lydctx->node_exts.count));
Michal Vaskoe0665742021-02-11 11:08:44 +01001475
1476 if (rc) {
1477 lyd_xml_ctx_free((struct lyd_ctx *)lydctx);
1478 } else {
1479 *lydctx_p = (struct lyd_ctx *)lydctx;
1480
1481 /* the XML context is no more needed, freeing it also stops logging line numbers which would be confusing now */
1482 lyxml_ctx_free(lydctx->xmlctx);
1483 lydctx->xmlctx = NULL;
Michal Vasko1ce933a2020-03-30 12:38:22 +02001484 }
Michal Vaskoe0665742021-02-11 11:08:44 +01001485 return rc;
Michal Vasko1ce933a2020-03-30 12:38:22 +02001486}