blob: 570d6b3d04a3c900ca5ca01c0811ab93d5d40d35 [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
36/**
Michal Vaskob36053d2020-03-26 15:49:30 +010037 * @brief Internal context for XML YANG data parser.
Radek Krejci1798aae2020-07-14 13:26:06 +020038 *
Radek Krejci4f2e3e52021-03-30 14:20:28 +020039 * Note that the structure maps to the ::lyd_ctx which is common for all the data parsers
Radek Krejcie7b95092019-05-15 11:03:07 +020040 */
41struct lyd_xml_ctx {
Radek Krejcif16e2542021-02-17 15:39:23 +010042 const struct lysc_ext_instance *ext; /**< extension instance possibly changing document root context of the data being parsed */
Michal Vaskoe0665742021-02-11 11:08:44 +010043 uint32_t parse_opts; /**< various @ref dataparseroptions. */
44 uint32_t val_opts; /**< various @ref datavalidationoptions. */
Radek Krejci1798aae2020-07-14 13:26:06 +020045 uint32_t int_opts; /**< internal data parser options */
46 uint32_t path_len; /**< used bytes in the path buffer */
47 char path[LYD_PARSER_BUFSIZE]; /**< buffer for the generated path */
Michal Vaskoc43c8ab2021-03-05 13:32:44 +010048 struct ly_set node_when; /**< set of nodes with "when" conditions */
Radek Krejci4f2e3e52021-03-30 14:20:28 +020049 struct ly_set node_exts; /**< set of nodes and extensions connected with a plugin providing own validation callback */
Michal Vasko49c39d82020-11-06 17:20:27 +010050 struct ly_set node_types; /**< set of nodes validated with LY_EINCOMPLETE result */
51 struct ly_set meta_types; /**< set of metadata validated with LY_EINCOMPLETE result */
Radek Krejci1798aae2020-07-14 13:26:06 +020052 struct lyd_node *op_node; /**< if an RPC/action/notification is being parsed, store the pointer to it */
Radek Krejcie7b95092019-05-15 11:03:07 +020053
Radek Krejci1798aae2020-07-14 13:26:06 +020054 /* callbacks */
55 lyd_ctx_free_clb free; /* destructor */
Radek Krejci1798aae2020-07-14 13:26:06 +020056
57 struct lyxml_ctx *xmlctx; /**< XML context */
Radek Krejcie7b95092019-05-15 11:03:07 +020058};
59
Radek Krejci1798aae2020-07-14 13:26:06 +020060void
61lyd_xml_ctx_free(struct lyd_ctx *lydctx)
62{
63 struct lyd_xml_ctx *ctx = (struct lyd_xml_ctx *)lydctx;
64
65 lyd_ctx_free(lydctx);
66 lyxml_ctx_free(ctx->xmlctx);
67 free(ctx);
68}
69
Radek Krejcie7b95092019-05-15 11:03:07 +020070static LY_ERR
Michal Vaskofeca4fb2020-10-05 08:58:40 +020071lydxml_metadata(struct lyd_xml_ctx *lydctx, struct lyd_meta **meta)
Radek Krejcie7b95092019-05-15 11:03:07 +020072{
aPiecek1c4da362021-04-29 14:26:34 +020073 LY_ERR ret = LY_SUCCESS;
Radek Krejci28681fa2019-09-06 13:08:45 +020074 const struct lyxml_ns *ns;
75 struct lys_module *mod;
Michal Vaskob36053d2020-03-26 15:49:30 +010076 const char *name;
77 size_t name_len;
Radek Krejci1798aae2020-07-14 13:26:06 +020078 struct lyxml_ctx *xmlctx = lydctx->xmlctx;
Radek Krejci28681fa2019-09-06 13:08:45 +020079
Michal Vaskob36053d2020-03-26 15:49:30 +010080 *meta = NULL;
Radek Krejci28681fa2019-09-06 13:08:45 +020081
Michal Vaskob36053d2020-03-26 15:49:30 +010082 while (xmlctx->status == LYXML_ATTRIBUTE) {
83 if (!xmlctx->prefix_len) {
Radek Krejci28681fa2019-09-06 13:08:45 +020084 /* in XML, all attributes must be prefixed
85 * TODO exception for NETCONF filters which are supposed to map to the ietf-netconf without prefix */
Michal Vaskoe0665742021-02-11 11:08:44 +010086 if (lydctx->parse_opts & LYD_PARSE_STRICT) {
aPiecek1c4da362021-04-29 14:26:34 +020087 ret = LY_EVALID;
Radek Krejci2efc45b2020-12-22 16:25:44 +010088 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Missing mandatory prefix for XML metadata \"%.*s\".",
Radek Krejci422afb12021-03-04 16:38:16 +010089 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskob36053d2020-03-26 15:49:30 +010090 goto cleanup;
Radek Krejci28681fa2019-09-06 13:08:45 +020091 }
Michal Vaskob36053d2020-03-26 15:49:30 +010092
Radek Krejci28681fa2019-09-06 13:08:45 +020093skip_attr:
Michal Vaskob36053d2020-03-26 15:49:30 +010094 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
95 assert(xmlctx->status == LYXML_ATTR_CONTENT);
96 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Radek Krejci28681fa2019-09-06 13:08:45 +020097 continue;
98 }
99
100 /* get namespace of the attribute to find its annotation definition */
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200101 ns = lyxml_ns_get(&xmlctx->ns, xmlctx->prefix, xmlctx->prefix_len);
Radek Krejci28681fa2019-09-06 13:08:45 +0200102 if (!ns) {
aPiecek1c4da362021-04-29 14:26:34 +0200103 ret = LY_ENOTFOUND;
Michal Vasko52927e22020-03-16 17:26:14 +0100104 /* unknown namespace, XML error */
Radek Krejci422afb12021-03-04 16:38:16 +0100105 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)xmlctx->prefix_len, xmlctx->prefix);
Radek Krejci28681fa2019-09-06 13:08:45 +0200106 goto cleanup;
107 }
Michal Vasko52927e22020-03-16 17:26:14 +0100108 mod = ly_ctx_get_module_implemented_ns(xmlctx->ctx, ns->uri);
Radek Krejci28681fa2019-09-06 13:08:45 +0200109 if (!mod) {
110 /* module is not implemented or not present in the schema */
Michal Vaskoe0665742021-02-11 11:08:44 +0100111 if (lydctx->parse_opts & LYD_PARSE_STRICT) {
aPiecek1c4da362021-04-29 14:26:34 +0200112 ret = LY_ENOTFOUND;
Radek Krejci2efc45b2020-12-22 16:25:44 +0100113 LOGVAL(xmlctx->ctx, LYVE_REFERENCE,
Michal Vasko69730152020-10-09 16:30:07 +0200114 "Unknown (or not implemented) YANG module with namespace \"%s\" for metadata \"%.*s%s%.*s\".",
Radek Krejci422afb12021-03-04 16:38:16 +0100115 ns->uri, (int)xmlctx->prefix_len, xmlctx->prefix, xmlctx->prefix_len ? ":" : "",
116 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskob36053d2020-03-26 15:49:30 +0100117 goto cleanup;
Radek Krejci28681fa2019-09-06 13:08:45 +0200118 }
119 goto skip_attr;
120 }
121
Michal Vasko60ea6352020-06-29 13:39:39 +0200122 /* remember meta name and get its content */
Michal Vaskob36053d2020-03-26 15:49:30 +0100123 name = xmlctx->name;
124 name_len = xmlctx->name_len;
125 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
126 assert(xmlctx->status == LYXML_ATTR_CONTENT);
127
128 /* create metadata */
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200129 ret = lyd_parser_create_meta((struct lyd_ctx *)lydctx, NULL, meta, mod, name, name_len, xmlctx->value,
Radek Krejci8df109d2021-04-23 12:19:08 +0200130 xmlctx->value_len, &xmlctx->dynamic, LY_VALUE_XML, &xmlctx->ns, LYD_HINT_DATA);
Radek Krejci1798aae2020-07-14 13:26:06 +0200131 LY_CHECK_GOTO(ret, cleanup);
Michal Vaskob36053d2020-03-26 15:49:30 +0100132
133 /* next attribute */
134 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Radek Krejcie7b95092019-05-15 11:03:07 +0200135 }
Michal Vasko52927e22020-03-16 17:26:14 +0100136
Radek Krejcie7b95092019-05-15 11:03:07 +0200137cleanup:
Michal Vaskob36053d2020-03-26 15:49:30 +0100138 if (ret) {
Michal Vasko3a41dff2020-07-15 14:30:28 +0200139 lyd_free_meta_siblings(*meta);
Michal Vaskob36053d2020-03-26 15:49:30 +0100140 *meta = NULL;
Radek Krejci38d85362019-09-05 16:26:38 +0200141 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200142 return ret;
143}
144
Michal Vasko52927e22020-03-16 17:26:14 +0100145static LY_ERR
Radek Krejci1798aae2020-07-14 13:26:06 +0200146lydxml_attrs(struct lyxml_ctx *xmlctx, struct lyd_attr **attr)
Michal Vasko52927e22020-03-16 17:26:14 +0100147{
148 LY_ERR ret = LY_SUCCESS;
149 const struct lyxml_ns *ns;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100150 void *val_prefix_data;
Radek Krejci8df109d2021-04-23 12:19:08 +0200151 LY_VALUE_FORMAT format;
Radek Krejci1798aae2020-07-14 13:26:06 +0200152 struct lyd_attr *attr2;
Michal Vaskob36053d2020-03-26 15:49:30 +0100153 const char *name, *prefix;
154 size_t name_len, prefix_len;
Michal Vasko52927e22020-03-16 17:26:14 +0100155
156 assert(attr);
Michal Vaskob36053d2020-03-26 15:49:30 +0100157 *attr = NULL;
Michal Vasko52927e22020-03-16 17:26:14 +0100158
Michal Vaskob36053d2020-03-26 15:49:30 +0100159 while (xmlctx->status == LYXML_ATTRIBUTE) {
Michal Vasko52927e22020-03-16 17:26:14 +0100160 ns = NULL;
Michal Vaskob36053d2020-03-26 15:49:30 +0100161 if (xmlctx->prefix_len) {
Michal Vasko52927e22020-03-16 17:26:14 +0100162 /* get namespace of the attribute */
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200163 ns = lyxml_ns_get(&xmlctx->ns, xmlctx->prefix, xmlctx->prefix_len);
Michal Vasko52927e22020-03-16 17:26:14 +0100164 if (!ns) {
Radek Krejci422afb12021-03-04 16:38:16 +0100165 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)xmlctx->prefix_len, xmlctx->prefix);
Michal Vasko52927e22020-03-16 17:26:14 +0100166 ret = LY_EVALID;
167 goto cleanup;
168 }
169 }
170
171 if (*attr) {
172 attr2 = *attr;
173 } else {
174 attr2 = NULL;
175 }
176
Michal Vaskob36053d2020-03-26 15:49:30 +0100177 /* remember attr prefix, name, and get its content */
178 prefix = xmlctx->prefix;
179 prefix_len = xmlctx->prefix_len;
180 name = xmlctx->name;
181 name_len = xmlctx->name_len;
182 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
183 assert(xmlctx->status == LYXML_ATTR_CONTENT);
184
Michal Vasko52927e22020-03-16 17:26:14 +0100185 /* get value prefixes */
Michal Vaskofc2cd072021-02-24 13:17:17 +0100186 val_prefix_data = NULL;
Radek Krejci8df109d2021-04-23 12:19:08 +0200187 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 +0100188 &xmlctx->ns, &format, &val_prefix_data), cleanup);
Michal Vasko52927e22020-03-16 17:26:14 +0100189
190 /* attr2 is always changed to the created attribute */
Michal Vasko501af032020-11-11 20:27:44 +0100191 ret = lyd_create_attr(NULL, &attr2, xmlctx->ctx, name, name_len, prefix, prefix_len, ns ? ns->uri : NULL,
192 ns ? strlen(ns->uri) : 0, xmlctx->value, xmlctx->value_len, &xmlctx->dynamic, format, val_prefix_data, 0);
Michal Vasko52927e22020-03-16 17:26:14 +0100193 LY_CHECK_GOTO(ret, cleanup);
194
195 if (!*attr) {
196 *attr = attr2;
197 }
Michal Vaskob36053d2020-03-26 15:49:30 +0100198
199 /* next attribute */
200 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko52927e22020-03-16 17:26:14 +0100201 }
202
203cleanup:
Michal Vaskob36053d2020-03-26 15:49:30 +0100204 if (ret) {
Radek Krejci011e4aa2020-09-04 15:22:31 +0200205 lyd_free_attr_siblings(xmlctx->ctx, *attr);
Michal Vaskob36053d2020-03-26 15:49:30 +0100206 *attr = NULL;
Michal Vasko52927e22020-03-16 17:26:14 +0100207 }
Michal Vasko52927e22020-03-16 17:26:14 +0100208 return ret;
209}
210
Michal Vasko44685da2020-03-17 15:38:06 +0100211static LY_ERR
Michal Vaskob36053d2020-03-26 15:49:30 +0100212lydxml_check_list(struct lyxml_ctx *xmlctx, const struct lysc_node *list)
Michal Vasko44685da2020-03-17 15:38:06 +0100213{
Michal Vaskob36053d2020-03-26 15:49:30 +0100214 LY_ERR ret = LY_SUCCESS, r;
215 enum LYXML_PARSER_STATUS next;
Michal Vasko44685da2020-03-17 15:38:06 +0100216 struct ly_set key_set = {0};
217 const struct lysc_node *snode;
Michal Vaskob36053d2020-03-26 15:49:30 +0100218 uint32_t i, parents_count;
Michal Vasko44685da2020-03-17 15:38:06 +0100219
220 assert(list && (list->nodetype == LYS_LIST));
221
222 /* get all keys into a set (keys do not have if-features or anything) */
223 snode = NULL;
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100224 while ((snode = lys_getnext(snode, list, NULL, 0)) && (snode->flags & LYS_KEY)) {
Radek Krejci3d92e442020-10-12 12:48:13 +0200225 ret = ly_set_add(&key_set, (void *)snode, 1, NULL);
Radek Krejciba03a5a2020-08-27 14:40:41 +0200226 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100227 }
228
Michal Vasko12d809c2021-03-03 16:34:32 +0100229 /* remember parent count */
230 parents_count = xmlctx->elements.count;
231
Michal Vaskob36053d2020-03-26 15:49:30 +0100232 while (xmlctx->status == LYXML_ELEMENT) {
Michal Vasko44685da2020-03-17 15:38:06 +0100233 /* find key definition */
234 for (i = 0; i < key_set.count; ++i) {
235 snode = (const struct lysc_node *)key_set.objs[i];
Michal Vaskob36053d2020-03-26 15:49:30 +0100236 if (!ly_strncmp(snode->name, xmlctx->name, xmlctx->name_len)) {
Michal Vasko44685da2020-03-17 15:38:06 +0100237 break;
238 }
239 }
Michal Vaskob36053d2020-03-26 15:49:30 +0100240 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100241
242 /* skip attributes */
243 while (xmlctx->status == LYXML_ATTRIBUTE) {
Michal Vaskob36053d2020-03-26 15:49:30 +0100244 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
245 assert(xmlctx->status == LYXML_ATTR_CONTENT);
246 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100247 }
248
Michal Vaskob36053d2020-03-26 15:49:30 +0100249 assert(xmlctx->status == LYXML_ELEM_CONTENT);
250 if (i < key_set.count) {
251 /* validate the value */
Radek Krejci8df109d2021-04-23 12:19:08 +0200252 r = lys_value_validate(NULL, snode, xmlctx->value, xmlctx->value_len, LY_VALUE_XML, &xmlctx->ns);
Michal Vaskob36053d2020-03-26 15:49:30 +0100253 if (!r) {
254 /* key with a valid value, remove from the set */
255 ly_set_rm_index(&key_set, i, NULL);
Michal Vasko44685da2020-03-17 15:38:06 +0100256 }
257 }
258
Michal Vaskob36053d2020-03-26 15:49:30 +0100259 /* parser next */
260 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100261
Michal Vaskob36053d2020-03-26 15:49:30 +0100262 /* skip any children, resursively */
Michal Vasko12d809c2021-03-03 16:34:32 +0100263 while (xmlctx->status == LYXML_ELEMENT) {
264 while (parents_count < xmlctx->elements.count) {
265 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
266 }
267 assert(xmlctx->status == LYXML_ELEM_CLOSE);
Michal Vaskob36053d2020-03-26 15:49:30 +0100268 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
269 }
270
271 /* parser next, but do not parse closing element of the list because it would remove its namespaces */
272 assert(xmlctx->status == LYXML_ELEM_CLOSE);
273 LY_CHECK_GOTO(ret = lyxml_ctx_peek(xmlctx, &next), cleanup);
274 if (next != LYXML_ELEM_CLOSE) {
275 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
276 }
Michal Vasko44685da2020-03-17 15:38:06 +0100277 }
278
279 if (key_set.count) {
Michal Vaskob36053d2020-03-26 15:49:30 +0100280 /* some keys are missing/did not validate */
Michal Vasko44685da2020-03-17 15:38:06 +0100281 ret = LY_ENOT;
Michal Vasko44685da2020-03-17 15:38:06 +0100282 }
283
284cleanup:
285 ly_set_erase(&key_set, NULL);
286 return ret;
287}
288
Michal Vasko5c24ed12021-06-09 09:27:32 +0200289/**
290 * @brief Skip an element with all its descendants.
291 *
292 * @param[in] xmlctx XML parser context.
293 * @return LY_ERR value.
294 */
Michal Vasko1bf09392020-03-27 12:38:10 +0100295static LY_ERR
296lydxml_data_skip(struct lyxml_ctx *xmlctx)
297{
298 uint32_t parents_count;
299
300 /* remember current number of parents */
301 parents_count = xmlctx->elements.count;
aPiecek9cdb9e62021-05-18 09:46:20 +0200302 assert(parents_count);
Michal Vasko1bf09392020-03-27 12:38:10 +0100303
304 /* skip after the content */
305 while (xmlctx->status != LYXML_ELEM_CONTENT) {
306 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
307 }
308 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
309
310 /* skip all children elements, recursively, if any */
aPiecek9cdb9e62021-05-18 09:46:20 +0200311 while (parents_count <= xmlctx->elements.count) {
Michal Vasko1bf09392020-03-27 12:38:10 +0100312 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
313 }
314
315 /* close element */
316 assert(xmlctx->status == LYXML_ELEM_CLOSE);
317 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
318
319 return LY_SUCCESS;
320}
321
Michal Vasko5c24ed12021-06-09 09:27:32 +0200322/**
323 * @brief Check that the current element can be parsed as a data node.
324 *
325 * @param[in] lydctx XML data parser context.
326 * @param[in,out] snode Found schema node, set to NULL if data node cannot be created.
327 * @return LY_ERR value.
328 */
Michal Vasko1bf09392020-03-27 12:38:10 +0100329static LY_ERR
Radek Krejci1798aae2020-07-14 13:26:06 +0200330lydxml_data_check_opaq(struct lyd_xml_ctx *lydctx, const struct lysc_node **snode)
Michal Vasko1bf09392020-03-27 12:38:10 +0100331{
332 LY_ERR ret = LY_SUCCESS;
333 enum LYXML_PARSER_STATUS prev_status;
Michal Vasko63f3d842020-07-08 10:10:14 +0200334 const char *prev_current, *pname, *pprefix;
Michal Vasko1bf09392020-03-27 12:38:10 +0100335 size_t pprefix_len, pname_len;
336 struct lyxml_ctx *xmlctx = lydctx->xmlctx;
337
Radek IÅ¡a3930fd72021-03-08 10:48:40 +0100338 if (!(lydctx->parse_opts & LYD_PARSE_OPAQ)) {
339 /* only checks specific to opaque nodes */
340 return LY_SUCCESS;
341 }
342
Michal Vasko13854662021-06-09 09:27:50 +0200343 if (!((*snode)->nodetype & (LYD_NODE_TERM | LYD_NODE_INNER))) {
344 /* nothing to check */
345 return LY_SUCCESS;
346 }
Michal Vasko1bf09392020-03-27 12:38:10 +0100347
Michal Vasko13854662021-06-09 09:27:50 +0200348 /* backup parser */
349 prev_status = xmlctx->status;
350 pprefix = xmlctx->prefix;
351 pprefix_len = xmlctx->prefix_len;
352 pname = xmlctx->name;
353 pname_len = xmlctx->name_len;
354 prev_current = xmlctx->in->current;
355 if ((xmlctx->status == LYXML_ELEM_CONTENT) && xmlctx->dynamic) {
356 /* it was backed up, do not free */
357 xmlctx->dynamic = 0;
358 }
Michal Vasko1bf09392020-03-27 12:38:10 +0100359
Michal Vasko13854662021-06-09 09:27:50 +0200360 /* skip attributes */
361 while (xmlctx->status == LYXML_ATTRIBUTE) {
362 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), restore);
363 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), restore);
364 }
Michal Vasko1bf09392020-03-27 12:38:10 +0100365
Michal Vasko13854662021-06-09 09:27:50 +0200366 if ((*snode)->nodetype & LYD_NODE_TERM) {
367 /* value may not be valid in which case we parse it as an opaque node */
368 if (lys_value_validate(NULL, *snode, xmlctx->value, xmlctx->value_len, LY_VALUE_XML, &xmlctx->ns)) {
369 *snode = NULL;
Michal Vasko1bf09392020-03-27 12:38:10 +0100370 }
Michal Vasko13854662021-06-09 09:27:50 +0200371 } else if ((*snode)->nodetype == LYS_LIST) {
372 /* skip content */
373 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), restore);
Michal Vasko1bf09392020-03-27 12:38:10 +0100374
Michal Vasko13854662021-06-09 09:27:50 +0200375 if (lydxml_check_list(xmlctx, *snode)) {
376 /* invalid list, parse as opaque if it missing/has invalid some keys */
377 *snode = NULL;
Michal Vasko1bf09392020-03-27 12:38:10 +0100378 }
Michal Vasko13854662021-06-09 09:27:50 +0200379 } else {
Radek IÅ¡a3930fd72021-03-08 10:48:40 +0100380 /* if there is a non-WS value, it cannot be parsed as an inner node */
381 assert(xmlctx->status == LYXML_ELEM_CONTENT);
382 if (!xmlctx->ws_only) {
383 *snode = NULL;
384 }
Michal Vasko1bf09392020-03-27 12:38:10 +0100385 }
386
Michal Vasko13854662021-06-09 09:27:50 +0200387restore:
388 /* restore parser */
389 if (xmlctx->dynamic) {
390 free((char *)xmlctx->value);
391 }
392 xmlctx->status = prev_status;
393 xmlctx->prefix = pprefix;
394 xmlctx->prefix_len = pprefix_len;
395 xmlctx->name = pname;
396 xmlctx->name_len = pname_len;
397 xmlctx->in->current = prev_current;
398
Michal Vasko1bf09392020-03-27 12:38:10 +0100399 return ret;
400}
401
Radek Krejcie7b95092019-05-15 11:03:07 +0200402/**
Michal Vaskoa5da3292020-08-12 13:10:50 +0200403 * @brief Parse XML subtree.
Radek Krejcie7b95092019-05-15 11:03:07 +0200404 *
Michal Vaskob36053d2020-03-26 15:49:30 +0100405 * @param[in] lydctx XML YANG data parser context.
Michal Vaskoe0665742021-02-11 11:08:44 +0100406 * @param[in,out] parent Parent node where the children are inserted. NULL in case of parsing top-level elements.
407 * @param[in,out] first_p Pointer to the first (@p parent or top-level) child. In case there were already some siblings,
408 * this may point to a previously existing node.
409 * @param[in,out] parsed Optional set to add all the parsed siblings into.
Michal Vasko9b368d32020-02-14 13:53:31 +0100410 * @return LY_ERR value.
Radek Krejcie7b95092019-05-15 11:03:07 +0200411 */
412static LY_ERR
Michal Vaskoe0665742021-02-11 11:08:44 +0100413lydxml_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 +0200414{
Michal Vaskob36053d2020-03-26 15:49:30 +0100415 LY_ERR ret = LY_SUCCESS;
Michal Vasko27c4dce2021-03-04 15:50:50 +0100416 const char *prefix, *name, *val;
Michal Vasko1bf09392020-03-27 12:38:10 +0100417 size_t prefix_len, name_len;
Michal Vaskob36053d2020-03-26 15:49:30 +0100418 struct lyxml_ctx *xmlctx;
419 const struct ly_ctx *ctx;
Radek Krejcie7b95092019-05-15 11:03:07 +0200420 const struct lyxml_ns *ns;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200421 struct lyd_meta *meta = NULL;
422 struct lyd_attr *attr = NULL;
Radek Krejcie7b95092019-05-15 11:03:07 +0200423 const struct lysc_node *snode;
424 struct lys_module *mod;
Michal Vaskoa98e3ea2021-06-03 09:13:33 +0200425 uint32_t prev_parse_opts, prev_int_opts;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200426 struct lyd_node *node = NULL, *anchor;
Michal Vaskofc2cd072021-02-24 13:17:17 +0100427 void *val_prefix_data = NULL;
Radek Krejci8df109d2021-04-23 12:19:08 +0200428 LY_VALUE_FORMAT format;
Radek Krejci1deb5be2020-08-26 16:43:36 +0200429 uint32_t getnext_opts;
Radek Krejcie7b95092019-05-15 11:03:07 +0200430
Michal Vaskoe0665742021-02-11 11:08:44 +0100431 assert(parent || first_p);
432
Michal Vaskob36053d2020-03-26 15:49:30 +0100433 xmlctx = lydctx->xmlctx;
434 ctx = xmlctx->ctx;
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100435 getnext_opts = lydctx->int_opts & LYD_INTOPT_REPLY ? LYS_GETNEXT_OUTPUT : 0;
Michal Vasko6f4cbb62020-02-28 11:15:47 +0100436
Michal Vaskoa5da3292020-08-12 13:10:50 +0200437 assert(xmlctx->status == LYXML_ELEMENT);
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200438
Michal Vaskoa5da3292020-08-12 13:10:50 +0200439 /* remember element prefix and name */
440 prefix = xmlctx->prefix;
441 prefix_len = xmlctx->prefix_len;
442 name = xmlctx->name;
443 name_len = xmlctx->name_len;
444
445 /* get the element module */
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200446 ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200447 if (!ns) {
Radek Krejci422afb12021-03-04 16:38:16 +0100448 LOGVAL(ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)prefix_len, prefix);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200449 ret = LY_EVALID;
450 goto error;
451 }
452 mod = ly_ctx_get_module_implemented_ns(ctx, ns->uri);
453 if (!mod) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100454 if (lydctx->parse_opts & LYD_PARSE_STRICT) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100455 LOGVAL(ctx, LYVE_REFERENCE, "No module with namespace \"%s\" in the context.", ns->uri);
Michal Vasko90932a92020-02-12 14:33:03 +0100456 ret = LY_EVALID;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200457 goto error;
Radek Krejcie7b95092019-05-15 11:03:07 +0200458 }
Michal Vaskoe0665742021-02-11 11:08:44 +0100459 if (!(lydctx->parse_opts & LYD_PARSE_OPAQ)) {
Michal Vaskoa5da3292020-08-12 13:10:50 +0200460 /* skip element with children */
461 LY_CHECK_GOTO(ret = lydxml_data_skip(xmlctx), error);
462 return LY_SUCCESS;
Radek Krejcie7b95092019-05-15 11:03:07 +0200463 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200464 }
465
Michal Vaskoa5da3292020-08-12 13:10:50 +0200466 /* parser next */
467 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
Michal Vasko90932a92020-02-12 14:33:03 +0100468
Michal Vaskoa5da3292020-08-12 13:10:50 +0200469 /* get the schema node */
470 snode = NULL;
471 if (mod && (!parent || parent->schema)) {
Radek Krejcif16e2542021-02-17 15:39:23 +0100472 if (!parent && lydctx->ext) {
Radek Krejciba05eab2021-03-10 13:19:29 +0100473 snode = lysc_ext_find_node(lydctx->ext, mod, name, name_len, 0, getnext_opts);
Radek Krejcif16e2542021-02-17 15:39:23 +0100474 } else {
475 snode = lys_find_child(parent ? parent->schema : NULL, mod, name, name_len, 0, getnext_opts);
476 }
Michal Vaskoa5da3292020-08-12 13:10:50 +0200477 if (!snode) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100478 if (lydctx->parse_opts & LYD_PARSE_STRICT) {
479 if (parent) {
Radek Krejci422afb12021-03-04 16:38:16 +0100480 LOGVAL(ctx, LYVE_REFERENCE, "Node \"%.*s\" not found as a child of \"%s\" node.",
481 (int)name_len, name, parent->schema->name);
Radek Krejcif16e2542021-02-17 15:39:23 +0100482 } else if (lydctx->ext) {
483 if (lydctx->ext->argument) {
Radek Krejci422afb12021-03-04 16:38:16 +0100484 LOGVAL(ctx, LYVE_REFERENCE, "Node \"%.*s\" not found in the \"%s\" %s extension instance.",
485 (int)name_len, name, lydctx->ext->argument, lydctx->ext->def->name);
Radek Krejcif16e2542021-02-17 15:39:23 +0100486 } else {
Radek Krejci422afb12021-03-04 16:38:16 +0100487 LOGVAL(ctx, LYVE_REFERENCE, "Node \"%.*s\" not found in the %s extension instance.",
488 (int)name_len, name, lydctx->ext->def->name);
Radek Krejcif16e2542021-02-17 15:39:23 +0100489 }
Michal Vaskoe0665742021-02-11 11:08:44 +0100490 } else {
Radek Krejci422afb12021-03-04 16:38:16 +0100491 LOGVAL(ctx, LYVE_REFERENCE, "Node \"%.*s\" not found in the \"%s\" module.",
492 (int)name_len, name, mod->name);
Michal Vaskoe0665742021-02-11 11:08:44 +0100493 }
Michal Vaskoa5da3292020-08-12 13:10:50 +0200494 ret = LY_EVALID;
495 goto error;
Michal Vaskoe0665742021-02-11 11:08:44 +0100496 } else if (!(lydctx->parse_opts & LYD_PARSE_OPAQ)) {
Michal Vaskoa5da3292020-08-12 13:10:50 +0200497 /* skip element with children */
498 LY_CHECK_GOTO(ret = lydxml_data_skip(xmlctx), error);
499 return LY_SUCCESS;
500 }
501 } else {
502 /* check that schema node is valid and can be used */
503 LY_CHECK_GOTO(ret = lyd_parser_check_schema((struct lyd_ctx *)lydctx, snode), error);
504 LY_CHECK_GOTO(ret = lydxml_data_check_opaq(lydctx, &snode), error);
505 }
506 }
507
508 /* create metadata/attributes */
509 if (xmlctx->status == LYXML_ATTRIBUTE) {
510 if (snode) {
Michal Vaskofeca4fb2020-10-05 08:58:40 +0200511 ret = lydxml_metadata(lydctx, &meta);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200512 LY_CHECK_GOTO(ret, error);
513 } else {
Michal Vaskoe0665742021-02-11 11:08:44 +0100514 assert(lydctx->parse_opts & LYD_PARSE_OPAQ);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200515 ret = lydxml_attrs(xmlctx, &attr);
516 LY_CHECK_GOTO(ret, error);
517 }
518 }
519
520 assert(xmlctx->status == LYXML_ELEM_CONTENT);
521 if (!snode) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100522 assert(lydctx->parse_opts & LYD_PARSE_OPAQ);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200523
524 if (xmlctx->ws_only) {
525 /* ignore WS-only value */
Radek IÅ¡a017270d2021-02-16 10:26:15 +0100526 if (xmlctx->dynamic) {
527 free((char *) xmlctx->value);
528 }
529 xmlctx->dynamic = 0;
530 xmlctx->value = "";
Michal Vaskoa5da3292020-08-12 13:10:50 +0200531 xmlctx->value_len = 0;
Radek Krejci8df109d2021-04-23 12:19:08 +0200532 format = LY_VALUE_XML;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200533 } else {
534 /* get value prefixes */
Radek Krejci8df109d2021-04-23 12:19:08 +0200535 ret = ly_store_prefix_data(xmlctx->ctx, xmlctx->value, xmlctx->value_len, LY_VALUE_XML,
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100536 &xmlctx->ns, &format, &val_prefix_data);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200537 LY_CHECK_GOTO(ret, error);
538 }
539
540 /* create node */
Michal Vasko501af032020-11-11 20:27:44 +0100541 ret = lyd_create_opaq(ctx, name, name_len, prefix, prefix_len, ns->uri, strlen(ns->uri), xmlctx->value,
542 xmlctx->value_len, &xmlctx->dynamic, format, val_prefix_data, LYD_HINT_DATA, &node);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200543 LY_CHECK_GOTO(ret, error);
544
545 /* parser next */
546 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
547
548 /* process children */
549 while (xmlctx->status == LYXML_ELEMENT) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100550 ret = lydxml_subtree_r(lydctx, node, lyd_node_child_p(node), NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200551 LY_CHECK_GOTO(ret, error);
552 }
553 } else if (snode->nodetype & LYD_NODE_TERM) {
554 /* create node */
Michal Vasko22df3f02020-08-24 13:29:22 +0200555 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 +0200556 &xmlctx->dynamic, LY_VALUE_XML, &xmlctx->ns, LYD_HINT_DATA, &node), error);
Radek Krejciddace2c2021-01-08 11:30:56 +0100557 LOG_LOCSET(snode, node, NULL, NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200558
559 if (parent && (node->schema->flags & LYS_KEY)) {
560 /* check the key order, the anchor must never be a key */
Michal Vaskoe0665742021-02-11 11:08:44 +0100561 anchor = lyd_insert_get_next_anchor(lyd_child(parent), node);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200562 if (anchor && (anchor->schema->flags & LYS_KEY)) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100563 if (lydctx->parse_opts & LYD_PARSE_STRICT) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100564 LOGVAL(ctx, LYVE_DATA, "Invalid position of the key \"%s\" in a list.", node->schema->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200565 ret = LY_EVALID;
566 goto error;
567 } else {
568 LOGWRN(ctx, "Invalid position of the key \"%s\" in a list.", node->schema->name);
569 }
570 }
571 }
572
573 /* parser next */
574 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
575
576 /* no children expected */
577 if (xmlctx->status == LYXML_ELEMENT) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100578 LOGVAL(ctx, LYVE_SYNTAX, "Child element \"%.*s\" inside a terminal node \"%s\" found.",
Radek Krejci422afb12021-03-04 16:38:16 +0100579 (int)xmlctx->name_len, xmlctx->name, snode->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200580 ret = LY_EVALID;
581 goto error;
582 }
583 } else if (snode->nodetype & LYD_NODE_INNER) {
584 if (!xmlctx->ws_only) {
585 /* value in inner node */
Radek Krejci2efc45b2020-12-22 16:25:44 +0100586 LOGVAL(ctx, LYVE_SYNTAX, "Text value \"%.*s\" inside an inner node \"%s\" found.",
Radek Krejci422afb12021-03-04 16:38:16 +0100587 (int)xmlctx->value_len, xmlctx->value, snode->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200588 ret = LY_EVALID;
589 goto error;
590 }
591
592 /* create node */
593 ret = lyd_create_inner(snode, &node);
594 LY_CHECK_GOTO(ret, error);
595
Radek Krejciddace2c2021-01-08 11:30:56 +0100596 LOG_LOCSET(snode, node, NULL, NULL);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100597
Michal Vaskoa5da3292020-08-12 13:10:50 +0200598 /* parser next */
599 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
600
601 /* process children */
602 while (xmlctx->status == LYXML_ELEMENT) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100603 ret = lydxml_subtree_r(lydctx, node, lyd_node_child_p(node), NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200604 LY_CHECK_GOTO(ret, error);
605 }
606
607 if (snode->nodetype == LYS_LIST) {
608 /* check all keys exist */
609 LY_CHECK_GOTO(ret = lyd_parse_check_keys(node), error);
610 }
611
Michal Vaskoe0665742021-02-11 11:08:44 +0100612 if (!(lydctx->parse_opts & LYD_PARSE_ONLY)) {
Michal Vaskoa5da3292020-08-12 13:10:50 +0200613 /* new node validation, autodelete CANNOT occur, all nodes are new */
Michal Vaskoe0665742021-02-11 11:08:44 +0100614 ret = lyd_validate_new(lyd_node_child_p(node), snode, NULL, NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200615 LY_CHECK_GOTO(ret, error);
616
617 /* add any missing default children */
Radek Krejci4f2e3e52021-03-30 14:20:28 +0200618 ret = lyd_new_implicit_r(node, lyd_node_child_p(node), NULL, NULL, &lydctx->node_when, &lydctx->node_exts,
619 &lydctx->node_types, (lydctx->val_opts & LYD_VALIDATE_NO_STATE) ? LYD_IMPLICIT_NO_STATE : 0, NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200620 LY_CHECK_GOTO(ret, error);
621 }
622
623 if (snode->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) {
624 /* rememeber the RPC/action/notification */
625 lydctx->op_node = node;
626 }
627 } else if (snode->nodetype & LYD_NODE_ANY) {
Michal Vasko27c4dce2021-03-04 15:50:50 +0100628 if ((snode->nodetype == LYS_ANYDATA) && !xmlctx->ws_only) {
629 /* value in anydata node, we expect a tree */
630 LOGVAL(ctx, LYVE_SYNTAX, "Text value \"%.*s\" inside an anydata node \"%s\" found.",
Radek Krejci422afb12021-03-04 16:38:16 +0100631 (int)xmlctx->value_len < 20 ? xmlctx->value_len : 20, xmlctx->value, snode->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200632 ret = LY_EVALID;
633 goto error;
634 }
635
Michal Vasko27c4dce2021-03-04 15:50:50 +0100636 if (!xmlctx->ws_only) {
637 /* use an arbitrary text value for anyxml */
638 lydict_insert(xmlctx->ctx, xmlctx->value, xmlctx->value_len, &val);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200639
Michal Vasko27c4dce2021-03-04 15:50:50 +0100640 /* parser next */
641 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
642
643 /* create node */
644 ret = lyd_create_any(snode, val, LYD_ANYDATA_STRING, 1, &node);
645 LY_CHECK_GOTO(ret, error);
646 } else {
647 /* parser next */
648 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
649
Michal Vaskoa98e3ea2021-06-03 09:13:33 +0200650 /* update options so that generic data can be parsed */
651 prev_parse_opts = lydctx->parse_opts;
Michal Vasko27c4dce2021-03-04 15:50:50 +0100652 lydctx->parse_opts &= ~LYD_PARSE_STRICT;
653 lydctx->parse_opts |= LYD_PARSE_OPAQ;
Michal Vaskoa98e3ea2021-06-03 09:13:33 +0200654 prev_int_opts = lydctx->int_opts;
655 lydctx->int_opts |= LYD_INTOPT_RPC | LYD_INTOPT_ACTION | LYD_INTOPT_NOTIF;
656
657 /* parse any data tree */
Michal Vasko27c4dce2021-03-04 15:50:50 +0100658 anchor = NULL;
659 while (xmlctx->status == LYXML_ELEMENT) {
660 ret = lydxml_subtree_r(lydctx, NULL, &anchor, NULL);
Michal Vaskoa98e3ea2021-06-03 09:13:33 +0200661 if (ret) {
662 break;
663 }
Michal Vasko27c4dce2021-03-04 15:50:50 +0100664 }
Michal Vaskoa98e3ea2021-06-03 09:13:33 +0200665
666 /* restore options */
667 lydctx->parse_opts = prev_parse_opts;
668 lydctx->int_opts = prev_int_opts;
669
670 LY_CHECK_GOTO(ret, error);
Michal Vasko27c4dce2021-03-04 15:50:50 +0100671
672 /* create node */
673 ret = lyd_create_any(snode, anchor, LYD_ANYDATA_DATATREE, 1, &node);
674 LY_CHECK_GOTO(ret, error);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200675 }
Michal Vaskoa5da3292020-08-12 13:10:50 +0200676 }
677 assert(node);
678
679 /* add/correct flags */
680 if (snode) {
Radek Krejci4f2e3e52021-03-30 14:20:28 +0200681 lyd_parse_set_data_flags(node, &lydctx->node_when, &lydctx->node_exts, &meta, lydctx->parse_opts);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200682 }
683
684 /* parser next */
685 assert(xmlctx->status == LYXML_ELEM_CLOSE);
686 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
687
688 /* add metadata/attributes */
689 if (snode) {
Michal Vasko871a0252020-11-11 18:35:24 +0100690 lyd_insert_meta(node, meta, 0);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200691 } else {
692 lyd_insert_attr(node, attr);
693 }
694
695 /* insert, keep first pointer correct */
Michal Vaskoe0665742021-02-11 11:08:44 +0100696 lyd_insert_node(parent, first_p, node);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200697 while (!parent && (*first_p)->prev->next) {
698 *first_p = (*first_p)->prev;
699 }
700
Michal Vaskoe0665742021-02-11 11:08:44 +0100701 /* rememeber a successfully parsed node */
702 if (parsed) {
703 ly_set_add(parsed, node, 1, NULL);
704 }
705
Radek Krejciddace2c2021-01-08 11:30:56 +0100706 LOG_LOCBACK(node ? 1 : 0, node ? 1 : 0, 0, 0);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200707 return LY_SUCCESS;
708
709error:
Radek Krejciddace2c2021-01-08 11:30:56 +0100710 LOG_LOCBACK(node ? 1 : 0, node ? 1 : 0, 0, 0);
Michal Vasko3a41dff2020-07-15 14:30:28 +0200711 lyd_free_meta_siblings(meta);
Radek Krejci011e4aa2020-09-04 15:22:31 +0200712 lyd_free_attr_siblings(ctx, attr);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200713 lyd_free_tree(node);
Radek Krejcie7b95092019-05-15 11:03:07 +0200714 return ret;
715}
716
Michal Vaskoe0665742021-02-11 11:08:44 +0100717/**
718 * @brief Parse a specific XML element into an opaque node.
719 *
720 * @param[in] xmlctx XML parser context.
721 * @param[in] name Name of the element.
722 * @param[in] uri URI of the element.
723 * @param[in] value Whether a value is expected in the element.
724 * @param[out] evnp Parsed envelope (opaque node).
725 * @return LY_SUCCESS on success.
726 * @return LY_ENOT if the specified element did not match.
727 * @return LY_ERR value on error.
728 */
Michal Vasko1bf09392020-03-27 12:38:10 +0100729static LY_ERR
Michal Vaskoe0665742021-02-11 11:08:44 +0100730lydxml_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 +0100731{
Michal Vaskoe0665742021-02-11 11:08:44 +0100732 LY_ERR rc = LY_SUCCESS;
733 const struct lyxml_ns *ns;
Radek Krejci1798aae2020-07-14 13:26:06 +0200734 struct lyd_attr *attr = NULL;
Michal Vasko1bf09392020-03-27 12:38:10 +0100735 const char *prefix;
736 size_t prefix_len;
737
Michal Vasko1bf09392020-03-27 12:38:10 +0100738 assert(xmlctx->status == LYXML_ELEMENT);
739 if (ly_strncmp(name, xmlctx->name, xmlctx->name_len)) {
740 /* not the expected element */
Michal Vaskoe0665742021-02-11 11:08:44 +0100741 return LY_ENOT;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100742 }
743
744 prefix = xmlctx->prefix;
745 prefix_len = xmlctx->prefix_len;
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200746 ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100747 if (!ns) {
Radek Krejci422afb12021-03-04 16:38:16 +0100748 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)prefix_len, prefix);
Michal Vaskoe0665742021-02-11 11:08:44 +0100749 return LY_EVALID;
750 } else if (strcmp(ns->uri, uri)) {
751 /* different namespace */
752 return LY_ENOT;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100753 }
754
755 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
756
757 /* create attributes */
758 if (xmlctx->status == LYXML_ATTRIBUTE) {
759 LY_CHECK_RET(lydxml_attrs(xmlctx, &attr));
760 }
761
Michal Vaskoe0665742021-02-11 11:08:44 +0100762 assert(xmlctx->status == LYXML_ELEM_CONTENT);
763 if (!value && !xmlctx->ws_only) {
764 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected value \"%.*s\" in the \"%s\" element.",
Radek Krejci422afb12021-03-04 16:38:16 +0100765 (int)xmlctx->value_len, xmlctx->value, name);
Michal Vaskoe0665742021-02-11 11:08:44 +0100766 rc = LY_EVALID;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100767 goto cleanup;
Michal Vaskoe0665742021-02-11 11:08:44 +0100768 }
Michal Vaskoa8edff02020-03-27 14:47:01 +0100769
770 /* create node */
Michal Vaskoe0665742021-02-11 11:08:44 +0100771 rc = lyd_create_opaq(xmlctx->ctx, name, strlen(name), prefix, prefix_len, uri, strlen(uri), xmlctx->value,
Radek Krejci8df109d2021-04-23 12:19:08 +0200772 xmlctx->ws_only ? 0 : xmlctx->value_len, NULL, LY_VALUE_XML, NULL, 0, envp);
Michal Vaskoe0665742021-02-11 11:08:44 +0100773 LY_CHECK_GOTO(rc, cleanup);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100774
775 /* assign atributes */
Michal Vaskoe0665742021-02-11 11:08:44 +0100776 ((struct lyd_node_opaq *)(*envp))->attr = attr;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100777 attr = NULL;
778
Michal Vaskoe0665742021-02-11 11:08:44 +0100779 /* parser next element */
780 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100781
Michal Vaskoe0665742021-02-11 11:08:44 +0100782cleanup:
783 lyd_free_attr_siblings(xmlctx->ctx, attr);
784 if (rc) {
785 lyd_free_tree(*envp);
786 *envp = NULL;
787 }
788 return rc;
789}
790
791/**
792 * @brief Parse all expected non-data XML elements of a NETCONF rpc message.
793 *
794 * @param[in] xmlctx XML parser context.
795 * @param[out] evnp Parsed envelope(s) (opaque node).
796 * @param[out] int_opts Internal options for parsing the rest of YANG data.
797 * @param[out] close_elem Number of parsed opened elements that need to be closed.
798 * @return LY_SUCCESS on success.
799 * @return LY_ERR value on error.
800 */
801static LY_ERR
802lydxml_env_netconf_rpc(struct lyxml_ctx *xmlctx, struct lyd_node **envp, uint32_t *int_opts, uint32_t *close_elem)
803{
804 LY_ERR rc = LY_SUCCESS, r;
805 struct lyd_node *child;
806
807 assert(envp && !*envp);
808
809 /* parse "rpc" */
810 r = lydxml_envelope(xmlctx, "rpc", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, envp);
Michal Vaskoe0665742021-02-11 11:08:44 +0100811 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
812
813 /* parse "action", if any */
814 r = lydxml_envelope(xmlctx, "action", "urn:ietf:params:xml:ns:yang:1", 0, &child);
815 if (r == LY_SUCCESS) {
816 /* insert */
817 lyd_insert_node(*envp, NULL, child);
818
819 /* NETCONF action */
820 *int_opts = LYD_INTOPT_NO_SIBLINGS | LYD_INTOPT_ACTION;
821 *close_elem = 2;
822 } else if (r == LY_ENOT) {
823 /* NETCONF RPC */
824 *int_opts = LYD_INTOPT_NO_SIBLINGS | LYD_INTOPT_RPC;
825 *close_elem = 1;
826 } else {
827 rc = r;
828 goto cleanup;
829 }
830
831cleanup:
832 if (rc) {
833 lyd_free_tree(*envp);
834 *envp = NULL;
835 }
836 return rc;
837}
838
839/**
840 * @brief Parse all expected non-data XML elements of a NETCONF notification message.
841 *
842 * @param[in] xmlctx XML parser context.
843 * @param[out] evnp Parsed envelope(s) (opaque node).
844 * @param[out] int_opts Internal options for parsing the rest of YANG data.
845 * @param[out] close_elem Number of parsed opened elements that need to be closed.
846 * @return LY_SUCCESS on success.
847 * @return LY_ERR value on error.
848 */
849static LY_ERR
850lydxml_env_netconf_notif(struct lyxml_ctx *xmlctx, struct lyd_node **envp, uint32_t *int_opts, uint32_t *close_elem)
851{
852 LY_ERR rc = LY_SUCCESS, r;
853 struct lyd_node *child;
854
855 assert(envp && !*envp);
856
857 /* parse "notification" */
858 r = lydxml_envelope(xmlctx, "notification", "urn:ietf:params:xml:ns:netconf:notification:1.0", 0, envp);
Michal Vaskoe0665742021-02-11 11:08:44 +0100859 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
860
861 /* parse "eventTime" */
862 r = lydxml_envelope(xmlctx, "eventTime", "urn:ietf:params:xml:ns:netconf:notification:1.0", 1, &child);
863 if (r == LY_ENOT) {
Radek Krejci422afb12021-03-04 16:38:16 +0100864 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unexpected element \"%.*s\" instead of \"eventTime\".",
865 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +0100866 r = LY_EVALID;
867 }
868 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
869
870 /* insert */
871 lyd_insert_node(*envp, NULL, child);
872
873 /* validate value */
874 /* TODO validate child->value as yang:date-and-time */
875
876 /* finish child parsing */
Michal Vaskoa8edff02020-03-27 14:47:01 +0100877 if (xmlctx->status != LYXML_ELEM_CLOSE) {
878 assert(xmlctx->status == LYXML_ELEMENT);
Michal Vaskoe0665742021-02-11 11:08:44 +0100879 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"eventTime\".",
Radek Krejci422afb12021-03-04 16:38:16 +0100880 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +0100881 rc = LY_EVALID;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100882 goto cleanup;
883 }
Michal Vaskoe0665742021-02-11 11:08:44 +0100884 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
885
886 /* NETCONF notification */
887 *int_opts = LYD_INTOPT_NO_SIBLINGS | LYD_INTOPT_NOTIF;
888 *close_elem = 1;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100889
890cleanup:
Michal Vaskoe0665742021-02-11 11:08:44 +0100891 if (rc) {
Michal Vaskoa8edff02020-03-27 14:47:01 +0100892 lyd_free_tree(*envp);
Michal Vaskoe0665742021-02-11 11:08:44 +0100893 *envp = NULL;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100894 }
Michal Vaskoe0665742021-02-11 11:08:44 +0100895 return rc;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100896}
Michal Vasko79135ae2020-12-16 10:08:35 +0100897
Michal Vaskoe0665742021-02-11 11:08:44 +0100898/**
899 * @brief Parse an XML element as an opaque node subtree.
900 *
901 * @param[in] xmlctx XML parser context.
902 * @param[in] parent Parent to append nodes to.
903 * @return LY_ERR value.
904 */
905static LY_ERR
906lydxml_opaq_r(struct lyxml_ctx *xmlctx, struct lyd_node *parent)
Michal Vaskoa8edff02020-03-27 14:47:01 +0100907{
Michal Vaskoe0665742021-02-11 11:08:44 +0100908 LY_ERR rc = LY_SUCCESS;
909 const struct lyxml_ns *ns;
910 struct lyd_attr *attr = NULL;
911 struct lyd_node *child = NULL;
912 const char *name, *prefix;
913 size_t name_len, prefix_len;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100914
Michal Vaskoe0665742021-02-11 11:08:44 +0100915 assert(xmlctx->status == LYXML_ELEMENT);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100916
Michal Vaskoe0665742021-02-11 11:08:44 +0100917 name = xmlctx->name;
918 name_len = xmlctx->name_len;
919 prefix = xmlctx->prefix;
920 prefix_len = xmlctx->prefix_len;
921 ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
922 if (!ns) {
Radek Krejci422afb12021-03-04 16:38:16 +0100923 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)prefix_len, prefix);
Michal Vaskoe0665742021-02-11 11:08:44 +0100924 return LY_EVALID;
925 }
Michal Vaskoa8edff02020-03-27 14:47:01 +0100926
Michal Vaskoe0665742021-02-11 11:08:44 +0100927 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
Michal Vaskoa8edff02020-03-27 14:47:01 +0100928
Michal Vaskoe0665742021-02-11 11:08:44 +0100929 /* create attributes */
930 if (xmlctx->status == LYXML_ATTRIBUTE) {
931 LY_CHECK_RET(lydxml_attrs(xmlctx, &attr));
932 }
933
934 /* create node */
935 assert(xmlctx->status == LYXML_ELEM_CONTENT);
936 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 +0200937 xmlctx->ws_only ? 0 : xmlctx->value_len, NULL, LY_VALUE_XML, NULL, 0, &child);
Michal Vaskoe0665742021-02-11 11:08:44 +0100938 LY_CHECK_GOTO(rc, cleanup);
939
940 /* assign atributes */
941 ((struct lyd_node_opaq *)child)->attr = attr;
942 attr = NULL;
943
944 /* parser next element */
945 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
946
947 /* parse all the descendants */
948 while (xmlctx->status == LYXML_ELEMENT) {
949 rc = lydxml_opaq_r(xmlctx, child);
950 LY_CHECK_GOTO(rc, cleanup);
951 }
952
953 /* insert */
954 lyd_insert_node(parent, NULL, child);
955
956cleanup:
957 lyd_free_attr_siblings(xmlctx->ctx, attr);
958 if (rc) {
959 lyd_free_tree(child);
960 }
961 return rc;
962}
963
964/**
965 * @brief Parse all expected non-data XML elements of the error-info element in NETCONF rpc-reply message.
966 *
967 * @param[in] xmlctx XML parser context.
968 * @param[in] parent Parent to append nodes to.
969 * @return LY_ERR value.
970 */
971static LY_ERR
972lydxml_env_netconf_rpc_reply_error_info(struct lyxml_ctx *xmlctx, struct lyd_node *parent)
973{
974 LY_ERR r;
975 struct lyd_node *child, *iter;
976 const struct lyxml_ns *ns;
977 ly_bool no_dup;
978
979 /* there must be some child */
980 if (xmlctx->status == LYXML_ELEM_CLOSE) {
981 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Missing child elements of \"error-info\".");
982 return LY_EVALID;
983 }
984
985 while (xmlctx->status == LYXML_ELEMENT) {
986 child = NULL;
987
988 /*
989 * session-id
990 */
991 r = lydxml_envelope(xmlctx, "session-id", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
992 if (r == LY_SUCCESS) {
993 no_dup = 1;
994 goto check_child;
995 } else if (r != LY_ENOT) {
996 goto error;
997 }
998
999 /*
1000 * bad-attribute
1001 */
1002 r = lydxml_envelope(xmlctx, "bad-attribute", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1003 if (r == LY_SUCCESS) {
1004 no_dup = 1;
1005 goto check_child;
1006 } else if (r != LY_ENOT) {
1007 goto error;
1008 }
1009
1010 /*
1011 * bad-element
1012 */
1013 r = lydxml_envelope(xmlctx, "bad-element", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1014 if (r == LY_SUCCESS) {
1015 no_dup = 1;
1016 goto check_child;
1017 } else if (r != LY_ENOT) {
1018 goto error;
1019 }
1020
1021 /*
1022 * bad-namespace
1023 */
1024 r = lydxml_envelope(xmlctx, "bad-namespace", "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 if (r == LY_ENOT) {
1033 assert(xmlctx->status == LYXML_ELEMENT);
1034
1035 /* learn namespace */
1036 ns = lyxml_ns_get(&xmlctx->ns, xmlctx->prefix, xmlctx->prefix_len);
1037 if (!ns) {
Radek Krejci422afb12021-03-04 16:38:16 +01001038 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)xmlctx->prefix_len, xmlctx->prefix);
Michal Vaskoe0665742021-02-11 11:08:44 +01001039 r = LY_EVALID;
1040 goto error;
1041 } else if (!strcmp(ns->uri, "urn:ietf:params:xml:ns:netconf:base:1.0")) {
1042 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"error-info\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001043 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001044 r = LY_EVALID;
1045 goto error;
1046 }
1047
1048 /* custom elements */
1049 r = lydxml_opaq_r(xmlctx, parent);
1050 LY_CHECK_GOTO(r, error);
1051
1052 no_dup = 0;
1053 }
1054
1055check_child:
1056 /* check for duplicates */
1057 if (no_dup) {
1058 LY_LIST_FOR(lyd_child(parent), iter) {
1059 if ((((struct lyd_node_opaq *)iter)->name.name == ((struct lyd_node_opaq *)child)->name.name) &&
1060 (((struct lyd_node_opaq *)iter)->name.module_ns == ((struct lyd_node_opaq *)child)->name.module_ns)) {
1061 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Duplicate element \"%s\" in \"error-info\".",
1062 ((struct lyd_node_opaq *)child)->name.name);
1063 r = LY_EVALID;
1064 goto error;
1065 }
1066 }
1067 }
1068
1069 /* finish child parsing */
1070 if (xmlctx->status != LYXML_ELEM_CLOSE) {
1071 assert(xmlctx->status == LYXML_ELEMENT);
1072 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"error-info\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001073 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001074 r = LY_EVALID;
1075 goto error;
1076 }
1077 LY_CHECK_GOTO(r = lyxml_ctx_next(xmlctx), error);
1078
1079 /* insert */
1080 lyd_insert_node(parent, NULL, child);
1081 }
1082
1083 return LY_SUCCESS;
1084
1085error:
1086 lyd_free_tree(child);
1087 return r;
1088}
1089
1090/**
1091 * @brief Parse all expected non-data XML elements of the rpc-error element in NETCONF rpc-reply message.
1092 *
1093 * @param[in] xmlctx XML parser context.
1094 * @param[in] parent Parent to append nodes to.
1095 * @return LY_ERR value.
1096 */
1097static LY_ERR
1098lydxml_env_netconf_rpc_reply_error(struct lyxml_ctx *xmlctx, struct lyd_node *parent)
1099{
1100 LY_ERR r;
1101 struct lyd_node *child, *iter;
1102 const char *val;
1103 ly_bool no_dup;
1104
1105 /* there must be some child */
1106 if (xmlctx->status == LYXML_ELEM_CLOSE) {
1107 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Missing child elements of \"rpc-error\".");
1108 return LY_EVALID;
1109 }
1110
1111 while (xmlctx->status == LYXML_ELEMENT) {
1112 child = NULL;
1113
1114 /*
1115 * error-type
1116 */
1117 r = lydxml_envelope(xmlctx, "error-type", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1118 if (r == LY_SUCCESS) {
1119 val = ((struct lyd_node_opaq *)child)->value;
1120 if (strcmp(val, "transport") && strcmp(val, "rpc") && strcmp(val, "protocol") && strcmp(val, "application")) {
1121 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Invalid value \"%s\" of element \"%s\".", val,
1122 ((struct lyd_node_opaq *)child)->name.name);
1123 r = LY_EVALID;
1124 goto error;
1125 }
1126
1127 no_dup = 1;
1128 goto check_child;
1129 } else if (r != LY_ENOT) {
1130 goto error;
1131 }
1132
1133 /*
1134 * error-tag
1135 */
1136 r = lydxml_envelope(xmlctx, "error-tag", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1137 if (r == LY_SUCCESS) {
1138 val = ((struct lyd_node_opaq *)child)->value;
1139 if (strcmp(val, "in-use") && strcmp(val, "invalid-value") && strcmp(val, "too-big") &&
1140 strcmp(val, "missing-attribute") && strcmp(val, "bad-attribute") &&
1141 strcmp(val, "unknown-attribute") && strcmp(val, "missing-element") && strcmp(val, "bad-element") &&
1142 strcmp(val, "unknown-element") && strcmp(val, "unknown-namespace") && strcmp(val, "access-denied") &&
1143 strcmp(val, "lock-denied") && strcmp(val, "resource-denied") && strcmp(val, "rollback-failed") &&
1144 strcmp(val, "data-exists") && strcmp(val, "data-missing") && strcmp(val, "operation-not-supported") &&
1145 strcmp(val, "operation-failed") && strcmp(val, "malformed-message")) {
1146 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Invalid value \"%s\" of element \"%s\".", val,
1147 ((struct lyd_node_opaq *)child)->name.name);
1148 r = LY_EVALID;
1149 goto error;
1150 }
1151
1152 no_dup = 1;
1153 goto check_child;
1154 } else if (r != LY_ENOT) {
1155 goto error;
1156 }
1157
1158 /*
1159 * error-severity
1160 */
1161 r = lydxml_envelope(xmlctx, "error-severity", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1162 if (r == LY_SUCCESS) {
1163 val = ((struct lyd_node_opaq *)child)->value;
1164 if (strcmp(val, "error") && strcmp(val, "warning")) {
1165 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Invalid value \"%s\" of element \"%s\".", val,
1166 ((struct lyd_node_opaq *)child)->name.name);
1167 r = LY_EVALID;
1168 goto error;
1169 }
1170
1171 no_dup = 1;
1172 goto check_child;
1173 } else if (r != LY_ENOT) {
1174 goto error;
1175 }
1176
1177 /*
1178 * error-app-tag
1179 */
1180 r = lydxml_envelope(xmlctx, "error-app-tag", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1181 if (r == LY_SUCCESS) {
1182 no_dup = 1;
1183 goto check_child;
1184 } else if (r != LY_ENOT) {
1185 goto error;
1186 }
1187
1188 /*
1189 * error-path
1190 */
1191 r = lydxml_envelope(xmlctx, "error-path", "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-message
1201 */
1202 r = lydxml_envelope(xmlctx, "error-message", "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 /* error-info */
1211 r = lydxml_envelope(xmlctx, "error-info", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, &child);
1212 if (r == LY_SUCCESS) {
1213 /* parse all the descendants */
1214 LY_CHECK_GOTO(r = lydxml_env_netconf_rpc_reply_error_info(xmlctx, child), error);
1215
1216 no_dup = 0;
1217 goto check_child;
1218 } else if (r != LY_ENOT) {
1219 goto error;
1220 }
1221
1222 if (r == LY_ENOT) {
1223 assert(xmlctx->status == LYXML_ELEMENT);
1224 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"rpc-error\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001225 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001226 r = LY_EVALID;
1227 goto error;
1228 }
1229
1230check_child:
1231 /* check for duplicates */
1232 if (no_dup) {
1233 LY_LIST_FOR(lyd_child(parent), iter) {
1234 if ((((struct lyd_node_opaq *)iter)->name.name == ((struct lyd_node_opaq *)child)->name.name) &&
1235 (((struct lyd_node_opaq *)iter)->name.module_ns == ((struct lyd_node_opaq *)child)->name.module_ns)) {
1236 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Duplicate element \"%s\" in \"rpc-error\".",
1237 ((struct lyd_node_opaq *)child)->name.name);
1238 r = LY_EVALID;
1239 goto error;
1240 }
1241 }
1242 }
1243
1244 /* finish child parsing */
1245 if (xmlctx->status != LYXML_ELEM_CLOSE) {
1246 assert(xmlctx->status == LYXML_ELEMENT);
1247 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"rpc-error\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001248 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001249 r = LY_EVALID;
1250 goto error;
1251 }
1252 LY_CHECK_GOTO(r = lyxml_ctx_next(xmlctx), error);
1253
1254 /* insert */
1255 lyd_insert_node(parent, NULL, child);
1256 }
1257
1258 return LY_SUCCESS;
1259
1260error:
1261 lyd_free_tree(child);
1262 return r;
1263}
1264
1265/**
1266 * @brief Parse all expected non-data XML elements of a NETCONF rpc-reply message.
1267 *
1268 * @param[in] xmlctx XML parser context.
1269 * @param[out] evnp Parsed envelope(s) (opaque node).
1270 * @param[out] int_opts Internal options for parsing the rest of YANG data.
1271 * @param[out] close_elem Number of parsed opened elements that need to be closed.
1272 * @return LY_SUCCESS on success.
1273 * @return LY_ERR value on error.
1274 */
1275static LY_ERR
1276lydxml_env_netconf_reply(struct lyxml_ctx *xmlctx, struct lyd_node **envp, uint32_t *int_opts, uint32_t *close_elem)
1277{
1278 LY_ERR rc = LY_SUCCESS, r;
1279 struct lyd_node *child = NULL;
1280 const char *parsed_elem = NULL;
1281
1282 assert(envp && !*envp);
1283
1284 /* parse "rpc-reply" */
1285 r = lydxml_envelope(xmlctx, "rpc-reply", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, envp);
Michal Vaskoe0665742021-02-11 11:08:44 +01001286 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
1287
1288 /* there must be some child */
1289 if (xmlctx->status == LYXML_ELEM_CLOSE) {
1290 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Missing child elements of \"rpc-reply\".");
1291 rc = LY_EVALID;
Michal Vaskocf770e22020-08-12 13:21:43 +02001292 goto cleanup;
Michal Vaskoa8edff02020-03-27 14:47:01 +01001293 }
1294
Michal Vaskoe0665742021-02-11 11:08:44 +01001295 /* try to parse "ok" */
1296 r = lydxml_envelope(xmlctx, "ok", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, &child);
1297 if (r == LY_SUCCESS) {
1298 /* insert */
1299 lyd_insert_node(*envp, NULL, child);
1300
1301 /* finish child parsing */
1302 if (xmlctx->status != LYXML_ELEM_CLOSE) {
1303 assert(xmlctx->status == LYXML_ELEMENT);
1304 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"ok\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001305 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001306 rc = LY_EVALID;
1307 goto cleanup;
1308 }
1309 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
1310
1311 /* success */
1312 parsed_elem = "ok";
1313 goto finish;
1314 } else if (r != LY_ENOT) {
1315 rc = r;
1316 goto cleanup;
Michal Vasko2552ea32020-12-08 15:32:34 +01001317 }
1318
Michal Vaskoe0665742021-02-11 11:08:44 +01001319 /* try to parse all "rpc-error" elements */
1320 while (xmlctx->status == LYXML_ELEMENT) {
1321 r = lydxml_envelope(xmlctx, "rpc-error", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, &child);
1322 if (r == LY_ENOT) {
1323 break;
1324 } else if (r) {
1325 rc = r;
1326 goto cleanup;
1327 }
1328
1329 /* insert */
1330 lyd_insert_node(*envp, NULL, child);
1331
1332 /* parse all children of "rpc-error" */
1333 LY_CHECK_GOTO(rc = lydxml_env_netconf_rpc_reply_error(xmlctx, child), cleanup);
1334
1335 /* finish child parsing */
1336 assert(xmlctx->status == LYXML_ELEM_CLOSE);
1337 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
1338
1339 parsed_elem = "rpc-error";
Michal Vasko2552ea32020-12-08 15:32:34 +01001340 }
Michal Vaskoe0665742021-02-11 11:08:44 +01001341
1342finish:
1343 if (parsed_elem) {
1344 /* NETCONF rpc-reply with no data */
1345 if (xmlctx->status != LYXML_ELEM_CLOSE) {
1346 assert(xmlctx->status == LYXML_ELEMENT);
1347 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected sibling element \"%.*s\" of \"%s\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001348 (int)xmlctx->name_len, xmlctx->name, parsed_elem);
Michal Vaskoe0665742021-02-11 11:08:44 +01001349 rc = LY_EVALID;
1350 goto cleanup;
1351 }
1352 }
1353
1354 /* NETCONF rpc-reply */
1355 *int_opts = LYD_INTOPT_NO_SIBLINGS | LYD_INTOPT_REPLY;
1356 *close_elem = 1;
1357
1358cleanup:
1359 if (rc) {
1360 lyd_free_tree(*envp);
1361 *envp = NULL;
1362 }
1363 return rc;
1364}
1365
Michal Vasko2552ea32020-12-08 15:32:34 +01001366LY_ERR
Radek Krejcif16e2542021-02-17 15:39:23 +01001367lyd_parse_xml(const struct ly_ctx *ctx, const struct lysc_ext_instance *ext, struct lyd_node *parent,
1368 struct lyd_node **first_p, struct ly_in *in, uint32_t parse_opts, uint32_t val_opts, enum lyd_type data_type,
1369 struct lyd_node **envp, struct ly_set *parsed, struct lyd_ctx **lydctx_p)
Michal Vasko2552ea32020-12-08 15:32:34 +01001370{
Michal Vaskoe0665742021-02-11 11:08:44 +01001371 LY_ERR rc = LY_SUCCESS;
1372 struct lyd_xml_ctx *lydctx;
1373 uint32_t i, int_opts, close_elem = 0;
1374 ly_bool parsed_data_nodes = 0;
Michal Vasko2552ea32020-12-08 15:32:34 +01001375
Michal Vaskoe0665742021-02-11 11:08:44 +01001376 assert(ctx && in && lydctx_p);
1377 assert(!(parse_opts & ~LYD_PARSE_OPTS_MASK));
1378 assert(!(val_opts & ~LYD_VALIDATE_OPTS_MASK));
Michal Vasko2552ea32020-12-08 15:32:34 +01001379
Michal Vaskoe0665742021-02-11 11:08:44 +01001380 /* init context */
1381 lydctx = calloc(1, sizeof *lydctx);
1382 LY_CHECK_ERR_RET(!lydctx, LOGMEM(ctx), LY_EMEM);
1383 LY_CHECK_GOTO(rc = lyxml_ctx_new(ctx, in, &lydctx->xmlctx), cleanup);
1384 lydctx->parse_opts = parse_opts;
1385 lydctx->val_opts = val_opts;
1386 lydctx->free = lyd_xml_ctx_free;
Radek Krejcif16e2542021-02-17 15:39:23 +01001387 lydctx->ext = ext;
Michal Vasko2552ea32020-12-08 15:32:34 +01001388
Michal Vaskoe0665742021-02-11 11:08:44 +01001389 switch (data_type) {
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001390 case LYD_TYPE_DATA_YANG:
Michal Vaskoe0665742021-02-11 11:08:44 +01001391 int_opts = LYD_INTOPT_WITH_SIBLINGS;
1392 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001393 case LYD_TYPE_RPC_YANG:
Michal Vaskoe0665742021-02-11 11:08:44 +01001394 int_opts = LYD_INTOPT_RPC | LYD_INTOPT_ACTION | LYD_INTOPT_NO_SIBLINGS;
1395 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001396 case LYD_TYPE_NOTIF_YANG:
Michal Vaskoe0665742021-02-11 11:08:44 +01001397 int_opts = LYD_INTOPT_NOTIF | LYD_INTOPT_NO_SIBLINGS;
1398 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001399 case LYD_TYPE_REPLY_YANG:
Michal Vaskoe0665742021-02-11 11:08:44 +01001400 int_opts = LYD_INTOPT_REPLY | LYD_INTOPT_NO_SIBLINGS;
1401 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001402 case LYD_TYPE_RPC_NETCONF:
Michal Vaskoe0665742021-02-11 11:08:44 +01001403 assert(!parent);
1404 LY_CHECK_GOTO(rc = lydxml_env_netconf_rpc(lydctx->xmlctx, envp, &int_opts, &close_elem), cleanup);
1405 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001406 case LYD_TYPE_NOTIF_NETCONF:
1407 assert(!parent);
1408 LY_CHECK_GOTO(rc = lydxml_env_netconf_notif(lydctx->xmlctx, envp, &int_opts, &close_elem), cleanup);
1409 break;
1410 case LYD_TYPE_REPLY_NETCONF:
Michal Vaskoe0665742021-02-11 11:08:44 +01001411 assert(parent);
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001412 LY_CHECK_GOTO(rc = lydxml_env_netconf_reply(lydctx->xmlctx, envp, &int_opts, &close_elem), cleanup);
Michal Vaskoe0665742021-02-11 11:08:44 +01001413 break;
1414 }
1415 lydctx->int_opts = int_opts;
1416
1417 /* find the operation node if it exists already */
1418 LY_CHECK_GOTO(rc = lyd_parser_find_operation(parent, int_opts, &lydctx->op_node), cleanup);
1419
1420 /* parse XML data */
1421 while (lydctx->xmlctx->status == LYXML_ELEMENT) {
1422 LY_CHECK_GOTO(rc = lydxml_subtree_r(lydctx, parent, first_p, parsed), cleanup);
1423 parsed_data_nodes = 1;
1424
1425 if (!(int_opts & LYD_INTOPT_WITH_SIBLINGS)) {
1426 break;
1427 }
Michal Vasko2552ea32020-12-08 15:32:34 +01001428 }
1429
Michal Vaskoe0665742021-02-11 11:08:44 +01001430 /* close all opened elements */
1431 for (i = 0; i < close_elem; ++i) {
1432 if (lydctx->xmlctx->status != LYXML_ELEM_CLOSE) {
1433 assert(lydctx->xmlctx->status == LYXML_ELEMENT);
Radek Krejci422afb12021-03-04 16:38:16 +01001434 LOGVAL(lydctx->xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\".",
1435 (int)lydctx->xmlctx->name_len, lydctx->xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001436 rc = LY_EVALID;
1437 goto cleanup;
1438 }
1439
1440 LY_CHECK_GOTO(rc = lyxml_ctx_next(lydctx->xmlctx), cleanup);
Michal Vasko4189c0f2020-08-13 09:05:22 +02001441 }
Michal Vaskoe0665742021-02-11 11:08:44 +01001442
1443 /* check final state */
1444 if ((int_opts & LYD_INTOPT_NO_SIBLINGS) && (lydctx->xmlctx->status == LYXML_ELEMENT)) {
1445 LOGVAL(ctx, LYVE_SYNTAX, "Unexpected sibling node.");
1446 rc = LY_EVALID;
1447 goto cleanup;
1448 }
1449 if ((int_opts & (LYD_INTOPT_RPC | LYD_INTOPT_NOTIF | LYD_INTOPT_REPLY)) && !lydctx->op_node) {
1450 LOGVAL(ctx, LYVE_DATA, "Missing the operation node.");
1451 rc = LY_EVALID;
1452 goto cleanup;
1453 }
1454
1455 if (!parsed_data_nodes) {
1456 /* no data nodes were parsed */
1457 lydctx->op_node = NULL;
Michal Vaskoa8edff02020-03-27 14:47:01 +01001458 }
1459
1460cleanup:
Michal Vaskoe0665742021-02-11 11:08:44 +01001461 /* there should be no unres stored if validation should be skipped */
1462 assert(!(parse_opts & LYD_PARSE_ONLY) || (!lydctx->node_types.count && !lydctx->meta_types.count &&
Radek Krejci4f2e3e52021-03-30 14:20:28 +02001463 !lydctx->node_when.count && !lydctx->node_exts.count));
Michal Vaskoe0665742021-02-11 11:08:44 +01001464
1465 if (rc) {
1466 lyd_xml_ctx_free((struct lyd_ctx *)lydctx);
1467 } else {
1468 *lydctx_p = (struct lyd_ctx *)lydctx;
1469
1470 /* the XML context is no more needed, freeing it also stops logging line numbers which would be confusing now */
1471 lyxml_ctx_free(lydctx->xmlctx);
1472 lydctx->xmlctx = NULL;
Michal Vasko1ce933a2020-03-30 12:38:22 +02001473 }
Michal Vaskoe0665742021-02-11 11:08:44 +01001474 return rc;
Michal Vasko1ce933a2020-03-30 12:38:22 +02001475}