blob: a827ab74e9949acd3f59201810a3847796609030 [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;
Michal Vaskoda8fbbf2021-06-16 11:44:44 +0200333 struct lyxml_ctx *xmlctx = lydctx->xmlctx, pxmlctx;
Michal Vasko1bf09392020-03-27 12:38:10 +0100334
Radek IÅ¡a3930fd72021-03-08 10:48:40 +0100335 if (!(lydctx->parse_opts & LYD_PARSE_OPAQ)) {
336 /* only checks specific to opaque nodes */
337 return LY_SUCCESS;
338 }
339
Michal Vasko13854662021-06-09 09:27:50 +0200340 if (!((*snode)->nodetype & (LYD_NODE_TERM | LYD_NODE_INNER))) {
341 /* nothing to check */
342 return LY_SUCCESS;
343 }
Michal Vasko1bf09392020-03-27 12:38:10 +0100344
Michal Vaskoda8fbbf2021-06-16 11:44:44 +0200345 assert(xmlctx->elements.count);
346
Michal Vasko13854662021-06-09 09:27:50 +0200347 /* backup parser */
Michal Vaskoda8fbbf2021-06-16 11:44:44 +0200348 LY_CHECK_RET(lyxml_ctx_backup(xmlctx, &pxmlctx));
Michal Vasko1bf09392020-03-27 12:38:10 +0100349
Michal Vasko13854662021-06-09 09:27:50 +0200350 /* skip attributes */
351 while (xmlctx->status == LYXML_ATTRIBUTE) {
352 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), restore);
353 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), restore);
354 }
Michal Vasko1bf09392020-03-27 12:38:10 +0100355
Michal Vasko13854662021-06-09 09:27:50 +0200356 if ((*snode)->nodetype & LYD_NODE_TERM) {
357 /* value may not be valid in which case we parse it as an opaque node */
358 if (lys_value_validate(NULL, *snode, xmlctx->value, xmlctx->value_len, LY_VALUE_XML, &xmlctx->ns)) {
359 *snode = NULL;
Michal Vasko1bf09392020-03-27 12:38:10 +0100360 }
Michal Vasko13854662021-06-09 09:27:50 +0200361 } else if ((*snode)->nodetype == LYS_LIST) {
362 /* skip content */
363 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), restore);
Michal Vasko1bf09392020-03-27 12:38:10 +0100364
Michal Vasko13854662021-06-09 09:27:50 +0200365 if (lydxml_check_list(xmlctx, *snode)) {
366 /* invalid list, parse as opaque if it missing/has invalid some keys */
367 *snode = NULL;
Michal Vasko1bf09392020-03-27 12:38:10 +0100368 }
Michal Vasko13854662021-06-09 09:27:50 +0200369 } else {
Radek IÅ¡a3930fd72021-03-08 10:48:40 +0100370 /* if there is a non-WS value, it cannot be parsed as an inner node */
371 assert(xmlctx->status == LYXML_ELEM_CONTENT);
372 if (!xmlctx->ws_only) {
373 *snode = NULL;
374 }
Michal Vasko1bf09392020-03-27 12:38:10 +0100375 }
376
Michal Vasko13854662021-06-09 09:27:50 +0200377restore:
378 /* restore parser */
Michal Vaskoda8fbbf2021-06-16 11:44:44 +0200379 lyxml_ctx_restore(xmlctx, &pxmlctx);
Michal Vasko1bf09392020-03-27 12:38:10 +0100380 return ret;
381}
382
Radek Krejcie7b95092019-05-15 11:03:07 +0200383/**
Michal Vaskoa5da3292020-08-12 13:10:50 +0200384 * @brief Parse XML subtree.
Radek Krejcie7b95092019-05-15 11:03:07 +0200385 *
Michal Vaskob36053d2020-03-26 15:49:30 +0100386 * @param[in] lydctx XML YANG data parser context.
Michal Vaskoe0665742021-02-11 11:08:44 +0100387 * @param[in,out] parent Parent node where the children are inserted. NULL in case of parsing top-level elements.
388 * @param[in,out] first_p Pointer to the first (@p parent or top-level) child. In case there were already some siblings,
389 * this may point to a previously existing node.
390 * @param[in,out] parsed Optional set to add all the parsed siblings into.
Michal Vasko9b368d32020-02-14 13:53:31 +0100391 * @return LY_ERR value.
Radek Krejcie7b95092019-05-15 11:03:07 +0200392 */
393static LY_ERR
Michal Vaskoe0665742021-02-11 11:08:44 +0100394lydxml_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 +0200395{
Michal Vaskob36053d2020-03-26 15:49:30 +0100396 LY_ERR ret = LY_SUCCESS;
Michal Vasko27c4dce2021-03-04 15:50:50 +0100397 const char *prefix, *name, *val;
Michal Vasko1bf09392020-03-27 12:38:10 +0100398 size_t prefix_len, name_len;
Michal Vaskob36053d2020-03-26 15:49:30 +0100399 struct lyxml_ctx *xmlctx;
400 const struct ly_ctx *ctx;
Radek Krejcie7b95092019-05-15 11:03:07 +0200401 const struct lyxml_ns *ns;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200402 struct lyd_meta *meta = NULL;
403 struct lyd_attr *attr = NULL;
Radek Krejcie7b95092019-05-15 11:03:07 +0200404 const struct lysc_node *snode;
405 struct lys_module *mod;
Michal Vaskoa98e3ea2021-06-03 09:13:33 +0200406 uint32_t prev_parse_opts, prev_int_opts;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200407 struct lyd_node *node = NULL, *anchor;
Michal Vaskofc2cd072021-02-24 13:17:17 +0100408 void *val_prefix_data = NULL;
Radek Krejci8df109d2021-04-23 12:19:08 +0200409 LY_VALUE_FORMAT format;
Radek Krejci1deb5be2020-08-26 16:43:36 +0200410 uint32_t getnext_opts;
Radek Krejcie7b95092019-05-15 11:03:07 +0200411
Michal Vaskoe0665742021-02-11 11:08:44 +0100412 assert(parent || first_p);
413
Michal Vaskob36053d2020-03-26 15:49:30 +0100414 xmlctx = lydctx->xmlctx;
415 ctx = xmlctx->ctx;
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100416 getnext_opts = lydctx->int_opts & LYD_INTOPT_REPLY ? LYS_GETNEXT_OUTPUT : 0;
Michal Vasko6f4cbb62020-02-28 11:15:47 +0100417
Michal Vaskoa5da3292020-08-12 13:10:50 +0200418 assert(xmlctx->status == LYXML_ELEMENT);
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200419
Michal Vaskoa5da3292020-08-12 13:10:50 +0200420 /* remember element prefix and name */
421 prefix = xmlctx->prefix;
422 prefix_len = xmlctx->prefix_len;
423 name = xmlctx->name;
424 name_len = xmlctx->name_len;
425
426 /* get the element module */
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200427 ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200428 if (!ns) {
Radek Krejci422afb12021-03-04 16:38:16 +0100429 LOGVAL(ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)prefix_len, prefix);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200430 ret = LY_EVALID;
431 goto error;
432 }
433 mod = ly_ctx_get_module_implemented_ns(ctx, ns->uri);
434 if (!mod) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100435 if (lydctx->parse_opts & LYD_PARSE_STRICT) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100436 LOGVAL(ctx, LYVE_REFERENCE, "No module with namespace \"%s\" in the context.", ns->uri);
Michal Vasko90932a92020-02-12 14:33:03 +0100437 ret = LY_EVALID;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200438 goto error;
Radek Krejcie7b95092019-05-15 11:03:07 +0200439 }
Michal Vaskoe0665742021-02-11 11:08:44 +0100440 if (!(lydctx->parse_opts & LYD_PARSE_OPAQ)) {
Michal Vaskoa5da3292020-08-12 13:10:50 +0200441 /* skip element with children */
442 LY_CHECK_GOTO(ret = lydxml_data_skip(xmlctx), error);
443 return LY_SUCCESS;
Radek Krejcie7b95092019-05-15 11:03:07 +0200444 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200445 }
446
Michal Vaskoa5da3292020-08-12 13:10:50 +0200447 /* parser next */
448 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
Michal Vasko90932a92020-02-12 14:33:03 +0100449
Michal Vaskoa5da3292020-08-12 13:10:50 +0200450 /* get the schema node */
451 snode = NULL;
452 if (mod && (!parent || parent->schema)) {
Radek Krejcif16e2542021-02-17 15:39:23 +0100453 if (!parent && lydctx->ext) {
Radek Krejciba05eab2021-03-10 13:19:29 +0100454 snode = lysc_ext_find_node(lydctx->ext, mod, name, name_len, 0, getnext_opts);
Radek Krejcif16e2542021-02-17 15:39:23 +0100455 } else {
456 snode = lys_find_child(parent ? parent->schema : NULL, mod, name, name_len, 0, getnext_opts);
457 }
Michal Vaskoa5da3292020-08-12 13:10:50 +0200458 if (!snode) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100459 if (lydctx->parse_opts & LYD_PARSE_STRICT) {
460 if (parent) {
Radek Krejci422afb12021-03-04 16:38:16 +0100461 LOGVAL(ctx, LYVE_REFERENCE, "Node \"%.*s\" not found as a child of \"%s\" node.",
462 (int)name_len, name, parent->schema->name);
Radek Krejcif16e2542021-02-17 15:39:23 +0100463 } else if (lydctx->ext) {
464 if (lydctx->ext->argument) {
Radek Krejci422afb12021-03-04 16:38:16 +0100465 LOGVAL(ctx, LYVE_REFERENCE, "Node \"%.*s\" not found in the \"%s\" %s extension instance.",
466 (int)name_len, name, lydctx->ext->argument, lydctx->ext->def->name);
Radek Krejcif16e2542021-02-17 15:39:23 +0100467 } else {
Radek Krejci422afb12021-03-04 16:38:16 +0100468 LOGVAL(ctx, LYVE_REFERENCE, "Node \"%.*s\" not found in the %s extension instance.",
469 (int)name_len, name, lydctx->ext->def->name);
Radek Krejcif16e2542021-02-17 15:39:23 +0100470 }
Michal Vaskoe0665742021-02-11 11:08:44 +0100471 } else {
Radek Krejci422afb12021-03-04 16:38:16 +0100472 LOGVAL(ctx, LYVE_REFERENCE, "Node \"%.*s\" not found in the \"%s\" module.",
473 (int)name_len, name, mod->name);
Michal Vaskoe0665742021-02-11 11:08:44 +0100474 }
Michal Vaskoa5da3292020-08-12 13:10:50 +0200475 ret = LY_EVALID;
476 goto error;
Michal Vaskoe0665742021-02-11 11:08:44 +0100477 } else if (!(lydctx->parse_opts & LYD_PARSE_OPAQ)) {
Michal Vaskoa5da3292020-08-12 13:10:50 +0200478 /* skip element with children */
479 LY_CHECK_GOTO(ret = lydxml_data_skip(xmlctx), error);
480 return LY_SUCCESS;
481 }
482 } else {
483 /* check that schema node is valid and can be used */
484 LY_CHECK_GOTO(ret = lyd_parser_check_schema((struct lyd_ctx *)lydctx, snode), error);
485 LY_CHECK_GOTO(ret = lydxml_data_check_opaq(lydctx, &snode), error);
486 }
487 }
488
489 /* create metadata/attributes */
490 if (xmlctx->status == LYXML_ATTRIBUTE) {
491 if (snode) {
Michal Vaskofeca4fb2020-10-05 08:58:40 +0200492 ret = lydxml_metadata(lydctx, &meta);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200493 LY_CHECK_GOTO(ret, error);
494 } else {
Michal Vaskoe0665742021-02-11 11:08:44 +0100495 assert(lydctx->parse_opts & LYD_PARSE_OPAQ);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200496 ret = lydxml_attrs(xmlctx, &attr);
497 LY_CHECK_GOTO(ret, error);
498 }
499 }
500
501 assert(xmlctx->status == LYXML_ELEM_CONTENT);
502 if (!snode) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100503 assert(lydctx->parse_opts & LYD_PARSE_OPAQ);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200504
505 if (xmlctx->ws_only) {
506 /* ignore WS-only value */
Radek IÅ¡a017270d2021-02-16 10:26:15 +0100507 if (xmlctx->dynamic) {
508 free((char *) xmlctx->value);
509 }
510 xmlctx->dynamic = 0;
511 xmlctx->value = "";
Michal Vaskoa5da3292020-08-12 13:10:50 +0200512 xmlctx->value_len = 0;
Radek Krejci8df109d2021-04-23 12:19:08 +0200513 format = LY_VALUE_XML;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200514 } else {
515 /* get value prefixes */
Radek Krejci8df109d2021-04-23 12:19:08 +0200516 ret = ly_store_prefix_data(xmlctx->ctx, xmlctx->value, xmlctx->value_len, LY_VALUE_XML,
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100517 &xmlctx->ns, &format, &val_prefix_data);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200518 LY_CHECK_GOTO(ret, error);
519 }
520
Michal Vaskoda8fbbf2021-06-16 11:44:44 +0200521 /* get NS again, it may have been backed up and restored */
522 ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
523 assert(ns);
524
Michal Vaskoa5da3292020-08-12 13:10:50 +0200525 /* create node */
Michal Vasko501af032020-11-11 20:27:44 +0100526 ret = lyd_create_opaq(ctx, name, name_len, prefix, prefix_len, ns->uri, strlen(ns->uri), xmlctx->value,
527 xmlctx->value_len, &xmlctx->dynamic, format, val_prefix_data, LYD_HINT_DATA, &node);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200528 LY_CHECK_GOTO(ret, error);
529
530 /* parser next */
531 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
532
533 /* process children */
534 while (xmlctx->status == LYXML_ELEMENT) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100535 ret = lydxml_subtree_r(lydctx, node, lyd_node_child_p(node), NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200536 LY_CHECK_GOTO(ret, error);
537 }
538 } else if (snode->nodetype & LYD_NODE_TERM) {
539 /* create node */
Michal Vasko22df3f02020-08-24 13:29:22 +0200540 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 +0200541 &xmlctx->dynamic, LY_VALUE_XML, &xmlctx->ns, LYD_HINT_DATA, &node), error);
Radek Krejciddace2c2021-01-08 11:30:56 +0100542 LOG_LOCSET(snode, node, NULL, NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200543
544 if (parent && (node->schema->flags & LYS_KEY)) {
545 /* check the key order, the anchor must never be a key */
Michal Vaskoe0665742021-02-11 11:08:44 +0100546 anchor = lyd_insert_get_next_anchor(lyd_child(parent), node);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200547 if (anchor && (anchor->schema->flags & LYS_KEY)) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100548 if (lydctx->parse_opts & LYD_PARSE_STRICT) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100549 LOGVAL(ctx, LYVE_DATA, "Invalid position of the key \"%s\" in a list.", node->schema->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200550 ret = LY_EVALID;
551 goto error;
552 } else {
553 LOGWRN(ctx, "Invalid position of the key \"%s\" in a list.", node->schema->name);
554 }
555 }
556 }
557
558 /* parser next */
559 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
560
561 /* no children expected */
562 if (xmlctx->status == LYXML_ELEMENT) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100563 LOGVAL(ctx, LYVE_SYNTAX, "Child element \"%.*s\" inside a terminal node \"%s\" found.",
Radek Krejci422afb12021-03-04 16:38:16 +0100564 (int)xmlctx->name_len, xmlctx->name, snode->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200565 ret = LY_EVALID;
566 goto error;
567 }
568 } else if (snode->nodetype & LYD_NODE_INNER) {
569 if (!xmlctx->ws_only) {
570 /* value in inner node */
Radek Krejci2efc45b2020-12-22 16:25:44 +0100571 LOGVAL(ctx, LYVE_SYNTAX, "Text value \"%.*s\" inside an inner node \"%s\" found.",
Radek Krejci422afb12021-03-04 16:38:16 +0100572 (int)xmlctx->value_len, xmlctx->value, snode->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200573 ret = LY_EVALID;
574 goto error;
575 }
576
577 /* create node */
578 ret = lyd_create_inner(snode, &node);
579 LY_CHECK_GOTO(ret, error);
580
Radek Krejciddace2c2021-01-08 11:30:56 +0100581 LOG_LOCSET(snode, node, NULL, NULL);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100582
Michal Vaskoa5da3292020-08-12 13:10:50 +0200583 /* parser next */
584 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
585
586 /* process children */
587 while (xmlctx->status == LYXML_ELEMENT) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100588 ret = lydxml_subtree_r(lydctx, node, lyd_node_child_p(node), NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200589 LY_CHECK_GOTO(ret, error);
590 }
591
592 if (snode->nodetype == LYS_LIST) {
593 /* check all keys exist */
594 LY_CHECK_GOTO(ret = lyd_parse_check_keys(node), error);
595 }
596
Michal Vaskoe0665742021-02-11 11:08:44 +0100597 if (!(lydctx->parse_opts & LYD_PARSE_ONLY)) {
Michal Vaskoa5da3292020-08-12 13:10:50 +0200598 /* new node validation, autodelete CANNOT occur, all nodes are new */
Michal Vaskoe0665742021-02-11 11:08:44 +0100599 ret = lyd_validate_new(lyd_node_child_p(node), snode, NULL, NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200600 LY_CHECK_GOTO(ret, error);
601
602 /* add any missing default children */
Radek Krejci4f2e3e52021-03-30 14:20:28 +0200603 ret = lyd_new_implicit_r(node, lyd_node_child_p(node), NULL, NULL, &lydctx->node_when, &lydctx->node_exts,
604 &lydctx->node_types, (lydctx->val_opts & LYD_VALIDATE_NO_STATE) ? LYD_IMPLICIT_NO_STATE : 0, NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200605 LY_CHECK_GOTO(ret, error);
606 }
607
608 if (snode->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) {
609 /* rememeber the RPC/action/notification */
610 lydctx->op_node = node;
611 }
612 } else if (snode->nodetype & LYD_NODE_ANY) {
Michal Vasko27c4dce2021-03-04 15:50:50 +0100613 if ((snode->nodetype == LYS_ANYDATA) && !xmlctx->ws_only) {
614 /* value in anydata node, we expect a tree */
615 LOGVAL(ctx, LYVE_SYNTAX, "Text value \"%.*s\" inside an anydata node \"%s\" found.",
Radek Krejci422afb12021-03-04 16:38:16 +0100616 (int)xmlctx->value_len < 20 ? xmlctx->value_len : 20, xmlctx->value, snode->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200617 ret = LY_EVALID;
618 goto error;
619 }
620
Michal Vasko27c4dce2021-03-04 15:50:50 +0100621 if (!xmlctx->ws_only) {
622 /* use an arbitrary text value for anyxml */
623 lydict_insert(xmlctx->ctx, xmlctx->value, xmlctx->value_len, &val);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200624
Michal Vasko27c4dce2021-03-04 15:50:50 +0100625 /* parser next */
626 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
627
628 /* create node */
629 ret = lyd_create_any(snode, val, LYD_ANYDATA_STRING, 1, &node);
630 LY_CHECK_GOTO(ret, error);
631 } else {
632 /* parser next */
633 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
634
Michal Vaskoa98e3ea2021-06-03 09:13:33 +0200635 /* update options so that generic data can be parsed */
636 prev_parse_opts = lydctx->parse_opts;
Michal Vasko27c4dce2021-03-04 15:50:50 +0100637 lydctx->parse_opts &= ~LYD_PARSE_STRICT;
638 lydctx->parse_opts |= LYD_PARSE_OPAQ;
Michal Vaskoa98e3ea2021-06-03 09:13:33 +0200639 prev_int_opts = lydctx->int_opts;
640 lydctx->int_opts |= LYD_INTOPT_RPC | LYD_INTOPT_ACTION | LYD_INTOPT_NOTIF;
641
642 /* parse any data tree */
Michal Vasko27c4dce2021-03-04 15:50:50 +0100643 anchor = NULL;
644 while (xmlctx->status == LYXML_ELEMENT) {
645 ret = lydxml_subtree_r(lydctx, NULL, &anchor, NULL);
Michal Vaskoa98e3ea2021-06-03 09:13:33 +0200646 if (ret) {
647 break;
648 }
Michal Vasko27c4dce2021-03-04 15:50:50 +0100649 }
Michal Vaskoa98e3ea2021-06-03 09:13:33 +0200650
651 /* restore options */
652 lydctx->parse_opts = prev_parse_opts;
653 lydctx->int_opts = prev_int_opts;
654
655 LY_CHECK_GOTO(ret, error);
Michal Vasko27c4dce2021-03-04 15:50:50 +0100656
657 /* create node */
658 ret = lyd_create_any(snode, anchor, LYD_ANYDATA_DATATREE, 1, &node);
659 LY_CHECK_GOTO(ret, error);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200660 }
Michal Vaskoa5da3292020-08-12 13:10:50 +0200661 }
662 assert(node);
663
664 /* add/correct flags */
665 if (snode) {
Radek Krejci4f2e3e52021-03-30 14:20:28 +0200666 lyd_parse_set_data_flags(node, &lydctx->node_when, &lydctx->node_exts, &meta, lydctx->parse_opts);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200667 }
668
669 /* parser next */
670 assert(xmlctx->status == LYXML_ELEM_CLOSE);
671 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
672
673 /* add metadata/attributes */
674 if (snode) {
Michal Vasko871a0252020-11-11 18:35:24 +0100675 lyd_insert_meta(node, meta, 0);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200676 } else {
677 lyd_insert_attr(node, attr);
678 }
679
680 /* insert, keep first pointer correct */
Michal Vaskoe0665742021-02-11 11:08:44 +0100681 lyd_insert_node(parent, first_p, node);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200682 while (!parent && (*first_p)->prev->next) {
683 *first_p = (*first_p)->prev;
684 }
685
Michal Vaskoe0665742021-02-11 11:08:44 +0100686 /* rememeber a successfully parsed node */
687 if (parsed) {
688 ly_set_add(parsed, node, 1, NULL);
689 }
690
Radek Krejciddace2c2021-01-08 11:30:56 +0100691 LOG_LOCBACK(node ? 1 : 0, node ? 1 : 0, 0, 0);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200692 return LY_SUCCESS;
693
694error:
Radek Krejciddace2c2021-01-08 11:30:56 +0100695 LOG_LOCBACK(node ? 1 : 0, node ? 1 : 0, 0, 0);
Michal Vasko3a41dff2020-07-15 14:30:28 +0200696 lyd_free_meta_siblings(meta);
Radek Krejci011e4aa2020-09-04 15:22:31 +0200697 lyd_free_attr_siblings(ctx, attr);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200698 lyd_free_tree(node);
Radek Krejcie7b95092019-05-15 11:03:07 +0200699 return ret;
700}
701
Michal Vaskoe0665742021-02-11 11:08:44 +0100702/**
703 * @brief Parse a specific XML element into an opaque node.
704 *
705 * @param[in] xmlctx XML parser context.
706 * @param[in] name Name of the element.
707 * @param[in] uri URI of the element.
708 * @param[in] value Whether a value is expected in the element.
709 * @param[out] evnp Parsed envelope (opaque node).
710 * @return LY_SUCCESS on success.
711 * @return LY_ENOT if the specified element did not match.
712 * @return LY_ERR value on error.
713 */
Michal Vasko1bf09392020-03-27 12:38:10 +0100714static LY_ERR
Michal Vaskoe0665742021-02-11 11:08:44 +0100715lydxml_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 +0100716{
Michal Vaskoe0665742021-02-11 11:08:44 +0100717 LY_ERR rc = LY_SUCCESS;
718 const struct lyxml_ns *ns;
Radek Krejci1798aae2020-07-14 13:26:06 +0200719 struct lyd_attr *attr = NULL;
Michal Vasko1bf09392020-03-27 12:38:10 +0100720 const char *prefix;
721 size_t prefix_len;
722
Michal Vasko1bf09392020-03-27 12:38:10 +0100723 assert(xmlctx->status == LYXML_ELEMENT);
724 if (ly_strncmp(name, xmlctx->name, xmlctx->name_len)) {
725 /* not the expected element */
Michal Vaskoe0665742021-02-11 11:08:44 +0100726 return LY_ENOT;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100727 }
728
729 prefix = xmlctx->prefix;
730 prefix_len = xmlctx->prefix_len;
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200731 ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100732 if (!ns) {
Radek Krejci422afb12021-03-04 16:38:16 +0100733 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)prefix_len, prefix);
Michal Vaskoe0665742021-02-11 11:08:44 +0100734 return LY_EVALID;
735 } else if (strcmp(ns->uri, uri)) {
736 /* different namespace */
737 return LY_ENOT;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100738 }
739
740 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
741
742 /* create attributes */
743 if (xmlctx->status == LYXML_ATTRIBUTE) {
744 LY_CHECK_RET(lydxml_attrs(xmlctx, &attr));
745 }
746
Michal Vaskoe0665742021-02-11 11:08:44 +0100747 assert(xmlctx->status == LYXML_ELEM_CONTENT);
748 if (!value && !xmlctx->ws_only) {
749 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected value \"%.*s\" in the \"%s\" element.",
Radek Krejci422afb12021-03-04 16:38:16 +0100750 (int)xmlctx->value_len, xmlctx->value, name);
Michal Vaskoe0665742021-02-11 11:08:44 +0100751 rc = LY_EVALID;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100752 goto cleanup;
Michal Vaskoe0665742021-02-11 11:08:44 +0100753 }
Michal Vaskoa8edff02020-03-27 14:47:01 +0100754
755 /* create node */
Michal Vaskoe0665742021-02-11 11:08:44 +0100756 rc = lyd_create_opaq(xmlctx->ctx, name, strlen(name), prefix, prefix_len, uri, strlen(uri), xmlctx->value,
Radek Krejci8df109d2021-04-23 12:19:08 +0200757 xmlctx->ws_only ? 0 : xmlctx->value_len, NULL, LY_VALUE_XML, NULL, 0, envp);
Michal Vaskoe0665742021-02-11 11:08:44 +0100758 LY_CHECK_GOTO(rc, cleanup);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100759
760 /* assign atributes */
Michal Vaskoe0665742021-02-11 11:08:44 +0100761 ((struct lyd_node_opaq *)(*envp))->attr = attr;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100762 attr = NULL;
763
Michal Vaskoe0665742021-02-11 11:08:44 +0100764 /* parser next element */
765 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100766
Michal Vaskoe0665742021-02-11 11:08:44 +0100767cleanup:
768 lyd_free_attr_siblings(xmlctx->ctx, attr);
769 if (rc) {
770 lyd_free_tree(*envp);
771 *envp = NULL;
772 }
773 return rc;
774}
775
776/**
777 * @brief Parse all expected non-data XML elements of a NETCONF rpc message.
778 *
779 * @param[in] xmlctx XML parser context.
780 * @param[out] evnp Parsed envelope(s) (opaque node).
781 * @param[out] int_opts Internal options for parsing the rest of YANG data.
782 * @param[out] close_elem Number of parsed opened elements that need to be closed.
783 * @return LY_SUCCESS on success.
784 * @return LY_ERR value on error.
785 */
786static LY_ERR
787lydxml_env_netconf_rpc(struct lyxml_ctx *xmlctx, struct lyd_node **envp, uint32_t *int_opts, uint32_t *close_elem)
788{
789 LY_ERR rc = LY_SUCCESS, r;
790 struct lyd_node *child;
791
792 assert(envp && !*envp);
793
794 /* parse "rpc" */
795 r = lydxml_envelope(xmlctx, "rpc", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, envp);
Michal Vaskoe0665742021-02-11 11:08:44 +0100796 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
797
798 /* parse "action", if any */
799 r = lydxml_envelope(xmlctx, "action", "urn:ietf:params:xml:ns:yang:1", 0, &child);
800 if (r == LY_SUCCESS) {
801 /* insert */
802 lyd_insert_node(*envp, NULL, child);
803
804 /* NETCONF action */
805 *int_opts = LYD_INTOPT_NO_SIBLINGS | LYD_INTOPT_ACTION;
806 *close_elem = 2;
807 } else if (r == LY_ENOT) {
808 /* NETCONF RPC */
809 *int_opts = LYD_INTOPT_NO_SIBLINGS | LYD_INTOPT_RPC;
810 *close_elem = 1;
811 } else {
812 rc = r;
813 goto cleanup;
814 }
815
816cleanup:
817 if (rc) {
818 lyd_free_tree(*envp);
819 *envp = NULL;
820 }
821 return rc;
822}
823
824/**
825 * @brief Parse all expected non-data XML elements of a NETCONF notification message.
826 *
827 * @param[in] xmlctx XML parser context.
828 * @param[out] evnp Parsed envelope(s) (opaque node).
829 * @param[out] int_opts Internal options for parsing the rest of YANG data.
830 * @param[out] close_elem Number of parsed opened elements that need to be closed.
831 * @return LY_SUCCESS on success.
832 * @return LY_ERR value on error.
833 */
834static LY_ERR
835lydxml_env_netconf_notif(struct lyxml_ctx *xmlctx, struct lyd_node **envp, uint32_t *int_opts, uint32_t *close_elem)
836{
837 LY_ERR rc = LY_SUCCESS, r;
838 struct lyd_node *child;
839
840 assert(envp && !*envp);
841
842 /* parse "notification" */
843 r = lydxml_envelope(xmlctx, "notification", "urn:ietf:params:xml:ns:netconf:notification:1.0", 0, envp);
Michal Vaskoe0665742021-02-11 11:08:44 +0100844 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
845
846 /* parse "eventTime" */
847 r = lydxml_envelope(xmlctx, "eventTime", "urn:ietf:params:xml:ns:netconf:notification:1.0", 1, &child);
848 if (r == LY_ENOT) {
Radek Krejci422afb12021-03-04 16:38:16 +0100849 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unexpected element \"%.*s\" instead of \"eventTime\".",
850 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +0100851 r = LY_EVALID;
852 }
853 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
854
855 /* insert */
856 lyd_insert_node(*envp, NULL, child);
857
858 /* validate value */
859 /* TODO validate child->value as yang:date-and-time */
860
861 /* finish child parsing */
Michal Vaskoa8edff02020-03-27 14:47:01 +0100862 if (xmlctx->status != LYXML_ELEM_CLOSE) {
863 assert(xmlctx->status == LYXML_ELEMENT);
Michal Vaskoe0665742021-02-11 11:08:44 +0100864 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"eventTime\".",
Radek Krejci422afb12021-03-04 16:38:16 +0100865 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +0100866 rc = LY_EVALID;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100867 goto cleanup;
868 }
Michal Vaskoe0665742021-02-11 11:08:44 +0100869 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
870
871 /* NETCONF notification */
872 *int_opts = LYD_INTOPT_NO_SIBLINGS | LYD_INTOPT_NOTIF;
873 *close_elem = 1;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100874
875cleanup:
Michal Vaskoe0665742021-02-11 11:08:44 +0100876 if (rc) {
Michal Vaskoa8edff02020-03-27 14:47:01 +0100877 lyd_free_tree(*envp);
Michal Vaskoe0665742021-02-11 11:08:44 +0100878 *envp = NULL;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100879 }
Michal Vaskoe0665742021-02-11 11:08:44 +0100880 return rc;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100881}
Michal Vasko79135ae2020-12-16 10:08:35 +0100882
Michal Vaskoe0665742021-02-11 11:08:44 +0100883/**
884 * @brief Parse an XML element as an opaque node subtree.
885 *
886 * @param[in] xmlctx XML parser context.
887 * @param[in] parent Parent to append nodes to.
888 * @return LY_ERR value.
889 */
890static LY_ERR
891lydxml_opaq_r(struct lyxml_ctx *xmlctx, struct lyd_node *parent)
Michal Vaskoa8edff02020-03-27 14:47:01 +0100892{
Michal Vaskoe0665742021-02-11 11:08:44 +0100893 LY_ERR rc = LY_SUCCESS;
894 const struct lyxml_ns *ns;
895 struct lyd_attr *attr = NULL;
896 struct lyd_node *child = NULL;
897 const char *name, *prefix;
898 size_t name_len, prefix_len;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100899
Michal Vaskoe0665742021-02-11 11:08:44 +0100900 assert(xmlctx->status == LYXML_ELEMENT);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100901
Michal Vaskoe0665742021-02-11 11:08:44 +0100902 name = xmlctx->name;
903 name_len = xmlctx->name_len;
904 prefix = xmlctx->prefix;
905 prefix_len = xmlctx->prefix_len;
906 ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
907 if (!ns) {
Radek Krejci422afb12021-03-04 16:38:16 +0100908 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)prefix_len, prefix);
Michal Vaskoe0665742021-02-11 11:08:44 +0100909 return LY_EVALID;
910 }
Michal Vaskoa8edff02020-03-27 14:47:01 +0100911
Michal Vaskoe0665742021-02-11 11:08:44 +0100912 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
Michal Vaskoa8edff02020-03-27 14:47:01 +0100913
Michal Vaskoe0665742021-02-11 11:08:44 +0100914 /* create attributes */
915 if (xmlctx->status == LYXML_ATTRIBUTE) {
916 LY_CHECK_RET(lydxml_attrs(xmlctx, &attr));
917 }
918
919 /* create node */
920 assert(xmlctx->status == LYXML_ELEM_CONTENT);
921 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 +0200922 xmlctx->ws_only ? 0 : xmlctx->value_len, NULL, LY_VALUE_XML, NULL, 0, &child);
Michal Vaskoe0665742021-02-11 11:08:44 +0100923 LY_CHECK_GOTO(rc, cleanup);
924
925 /* assign atributes */
926 ((struct lyd_node_opaq *)child)->attr = attr;
927 attr = NULL;
928
929 /* parser next element */
930 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
931
932 /* parse all the descendants */
933 while (xmlctx->status == LYXML_ELEMENT) {
934 rc = lydxml_opaq_r(xmlctx, child);
935 LY_CHECK_GOTO(rc, cleanup);
936 }
937
938 /* insert */
939 lyd_insert_node(parent, NULL, child);
940
941cleanup:
942 lyd_free_attr_siblings(xmlctx->ctx, attr);
943 if (rc) {
944 lyd_free_tree(child);
945 }
946 return rc;
947}
948
949/**
950 * @brief Parse all expected non-data XML elements of the error-info element in NETCONF rpc-reply message.
951 *
952 * @param[in] xmlctx XML parser context.
953 * @param[in] parent Parent to append nodes to.
954 * @return LY_ERR value.
955 */
956static LY_ERR
957lydxml_env_netconf_rpc_reply_error_info(struct lyxml_ctx *xmlctx, struct lyd_node *parent)
958{
959 LY_ERR r;
960 struct lyd_node *child, *iter;
961 const struct lyxml_ns *ns;
962 ly_bool no_dup;
963
964 /* there must be some child */
965 if (xmlctx->status == LYXML_ELEM_CLOSE) {
966 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Missing child elements of \"error-info\".");
967 return LY_EVALID;
968 }
969
970 while (xmlctx->status == LYXML_ELEMENT) {
971 child = NULL;
972
973 /*
974 * session-id
975 */
976 r = lydxml_envelope(xmlctx, "session-id", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
977 if (r == LY_SUCCESS) {
978 no_dup = 1;
979 goto check_child;
980 } else if (r != LY_ENOT) {
981 goto error;
982 }
983
984 /*
985 * bad-attribute
986 */
987 r = lydxml_envelope(xmlctx, "bad-attribute", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
988 if (r == LY_SUCCESS) {
989 no_dup = 1;
990 goto check_child;
991 } else if (r != LY_ENOT) {
992 goto error;
993 }
994
995 /*
996 * bad-element
997 */
998 r = lydxml_envelope(xmlctx, "bad-element", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
999 if (r == LY_SUCCESS) {
1000 no_dup = 1;
1001 goto check_child;
1002 } else if (r != LY_ENOT) {
1003 goto error;
1004 }
1005
1006 /*
1007 * bad-namespace
1008 */
1009 r = lydxml_envelope(xmlctx, "bad-namespace", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1010 if (r == LY_SUCCESS) {
1011 no_dup = 1;
1012 goto check_child;
1013 } else if (r != LY_ENOT) {
1014 goto error;
1015 }
1016
1017 if (r == LY_ENOT) {
1018 assert(xmlctx->status == LYXML_ELEMENT);
1019
1020 /* learn namespace */
1021 ns = lyxml_ns_get(&xmlctx->ns, xmlctx->prefix, xmlctx->prefix_len);
1022 if (!ns) {
Radek Krejci422afb12021-03-04 16:38:16 +01001023 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)xmlctx->prefix_len, xmlctx->prefix);
Michal Vaskoe0665742021-02-11 11:08:44 +01001024 r = LY_EVALID;
1025 goto error;
1026 } else if (!strcmp(ns->uri, "urn:ietf:params:xml:ns:netconf:base:1.0")) {
1027 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"error-info\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001028 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001029 r = LY_EVALID;
1030 goto error;
1031 }
1032
1033 /* custom elements */
1034 r = lydxml_opaq_r(xmlctx, parent);
1035 LY_CHECK_GOTO(r, error);
1036
1037 no_dup = 0;
1038 }
1039
1040check_child:
1041 /* check for duplicates */
1042 if (no_dup) {
1043 LY_LIST_FOR(lyd_child(parent), iter) {
1044 if ((((struct lyd_node_opaq *)iter)->name.name == ((struct lyd_node_opaq *)child)->name.name) &&
1045 (((struct lyd_node_opaq *)iter)->name.module_ns == ((struct lyd_node_opaq *)child)->name.module_ns)) {
1046 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Duplicate element \"%s\" in \"error-info\".",
1047 ((struct lyd_node_opaq *)child)->name.name);
1048 r = LY_EVALID;
1049 goto error;
1050 }
1051 }
1052 }
1053
1054 /* finish child parsing */
1055 if (xmlctx->status != LYXML_ELEM_CLOSE) {
1056 assert(xmlctx->status == LYXML_ELEMENT);
1057 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"error-info\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001058 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001059 r = LY_EVALID;
1060 goto error;
1061 }
1062 LY_CHECK_GOTO(r = lyxml_ctx_next(xmlctx), error);
1063
1064 /* insert */
1065 lyd_insert_node(parent, NULL, child);
1066 }
1067
1068 return LY_SUCCESS;
1069
1070error:
1071 lyd_free_tree(child);
1072 return r;
1073}
1074
1075/**
1076 * @brief Parse all expected non-data XML elements of the rpc-error element in NETCONF rpc-reply message.
1077 *
1078 * @param[in] xmlctx XML parser context.
1079 * @param[in] parent Parent to append nodes to.
1080 * @return LY_ERR value.
1081 */
1082static LY_ERR
1083lydxml_env_netconf_rpc_reply_error(struct lyxml_ctx *xmlctx, struct lyd_node *parent)
1084{
1085 LY_ERR r;
1086 struct lyd_node *child, *iter;
1087 const char *val;
1088 ly_bool no_dup;
1089
1090 /* there must be some child */
1091 if (xmlctx->status == LYXML_ELEM_CLOSE) {
1092 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Missing child elements of \"rpc-error\".");
1093 return LY_EVALID;
1094 }
1095
1096 while (xmlctx->status == LYXML_ELEMENT) {
1097 child = NULL;
1098
1099 /*
1100 * error-type
1101 */
1102 r = lydxml_envelope(xmlctx, "error-type", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1103 if (r == LY_SUCCESS) {
1104 val = ((struct lyd_node_opaq *)child)->value;
1105 if (strcmp(val, "transport") && strcmp(val, "rpc") && strcmp(val, "protocol") && strcmp(val, "application")) {
1106 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Invalid value \"%s\" of element \"%s\".", val,
1107 ((struct lyd_node_opaq *)child)->name.name);
1108 r = LY_EVALID;
1109 goto error;
1110 }
1111
1112 no_dup = 1;
1113 goto check_child;
1114 } else if (r != LY_ENOT) {
1115 goto error;
1116 }
1117
1118 /*
1119 * error-tag
1120 */
1121 r = lydxml_envelope(xmlctx, "error-tag", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1122 if (r == LY_SUCCESS) {
1123 val = ((struct lyd_node_opaq *)child)->value;
1124 if (strcmp(val, "in-use") && strcmp(val, "invalid-value") && strcmp(val, "too-big") &&
1125 strcmp(val, "missing-attribute") && strcmp(val, "bad-attribute") &&
1126 strcmp(val, "unknown-attribute") && strcmp(val, "missing-element") && strcmp(val, "bad-element") &&
1127 strcmp(val, "unknown-element") && strcmp(val, "unknown-namespace") && strcmp(val, "access-denied") &&
1128 strcmp(val, "lock-denied") && strcmp(val, "resource-denied") && strcmp(val, "rollback-failed") &&
1129 strcmp(val, "data-exists") && strcmp(val, "data-missing") && strcmp(val, "operation-not-supported") &&
1130 strcmp(val, "operation-failed") && strcmp(val, "malformed-message")) {
1131 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Invalid value \"%s\" of element \"%s\".", val,
1132 ((struct lyd_node_opaq *)child)->name.name);
1133 r = LY_EVALID;
1134 goto error;
1135 }
1136
1137 no_dup = 1;
1138 goto check_child;
1139 } else if (r != LY_ENOT) {
1140 goto error;
1141 }
1142
1143 /*
1144 * error-severity
1145 */
1146 r = lydxml_envelope(xmlctx, "error-severity", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1147 if (r == LY_SUCCESS) {
1148 val = ((struct lyd_node_opaq *)child)->value;
1149 if (strcmp(val, "error") && strcmp(val, "warning")) {
1150 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Invalid value \"%s\" of element \"%s\".", val,
1151 ((struct lyd_node_opaq *)child)->name.name);
1152 r = LY_EVALID;
1153 goto error;
1154 }
1155
1156 no_dup = 1;
1157 goto check_child;
1158 } else if (r != LY_ENOT) {
1159 goto error;
1160 }
1161
1162 /*
1163 * error-app-tag
1164 */
1165 r = lydxml_envelope(xmlctx, "error-app-tag", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1166 if (r == LY_SUCCESS) {
1167 no_dup = 1;
1168 goto check_child;
1169 } else if (r != LY_ENOT) {
1170 goto error;
1171 }
1172
1173 /*
1174 * error-path
1175 */
1176 r = lydxml_envelope(xmlctx, "error-path", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1177 if (r == LY_SUCCESS) {
1178 no_dup = 1;
1179 goto check_child;
1180 } else if (r != LY_ENOT) {
1181 goto error;
1182 }
1183
1184 /*
1185 * error-message
1186 */
1187 r = lydxml_envelope(xmlctx, "error-message", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1188 if (r == LY_SUCCESS) {
1189 no_dup = 1;
1190 goto check_child;
1191 } else if (r != LY_ENOT) {
1192 goto error;
1193 }
1194
1195 /* error-info */
1196 r = lydxml_envelope(xmlctx, "error-info", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, &child);
1197 if (r == LY_SUCCESS) {
1198 /* parse all the descendants */
1199 LY_CHECK_GOTO(r = lydxml_env_netconf_rpc_reply_error_info(xmlctx, child), error);
1200
1201 no_dup = 0;
1202 goto check_child;
1203 } else if (r != LY_ENOT) {
1204 goto error;
1205 }
1206
1207 if (r == LY_ENOT) {
1208 assert(xmlctx->status == LYXML_ELEMENT);
1209 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"rpc-error\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001210 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001211 r = LY_EVALID;
1212 goto error;
1213 }
1214
1215check_child:
1216 /* check for duplicates */
1217 if (no_dup) {
1218 LY_LIST_FOR(lyd_child(parent), iter) {
1219 if ((((struct lyd_node_opaq *)iter)->name.name == ((struct lyd_node_opaq *)child)->name.name) &&
1220 (((struct lyd_node_opaq *)iter)->name.module_ns == ((struct lyd_node_opaq *)child)->name.module_ns)) {
1221 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Duplicate element \"%s\" in \"rpc-error\".",
1222 ((struct lyd_node_opaq *)child)->name.name);
1223 r = LY_EVALID;
1224 goto error;
1225 }
1226 }
1227 }
1228
1229 /* finish child parsing */
1230 if (xmlctx->status != LYXML_ELEM_CLOSE) {
1231 assert(xmlctx->status == LYXML_ELEMENT);
1232 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"rpc-error\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001233 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001234 r = LY_EVALID;
1235 goto error;
1236 }
1237 LY_CHECK_GOTO(r = lyxml_ctx_next(xmlctx), error);
1238
1239 /* insert */
1240 lyd_insert_node(parent, NULL, child);
1241 }
1242
1243 return LY_SUCCESS;
1244
1245error:
1246 lyd_free_tree(child);
1247 return r;
1248}
1249
1250/**
1251 * @brief Parse all expected non-data XML elements of a NETCONF rpc-reply message.
1252 *
1253 * @param[in] xmlctx XML parser context.
1254 * @param[out] evnp Parsed envelope(s) (opaque node).
1255 * @param[out] int_opts Internal options for parsing the rest of YANG data.
1256 * @param[out] close_elem Number of parsed opened elements that need to be closed.
1257 * @return LY_SUCCESS on success.
1258 * @return LY_ERR value on error.
1259 */
1260static LY_ERR
1261lydxml_env_netconf_reply(struct lyxml_ctx *xmlctx, struct lyd_node **envp, uint32_t *int_opts, uint32_t *close_elem)
1262{
1263 LY_ERR rc = LY_SUCCESS, r;
1264 struct lyd_node *child = NULL;
1265 const char *parsed_elem = NULL;
1266
1267 assert(envp && !*envp);
1268
1269 /* parse "rpc-reply" */
1270 r = lydxml_envelope(xmlctx, "rpc-reply", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, envp);
Michal Vaskoe0665742021-02-11 11:08:44 +01001271 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
1272
1273 /* there must be some child */
1274 if (xmlctx->status == LYXML_ELEM_CLOSE) {
1275 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Missing child elements of \"rpc-reply\".");
1276 rc = LY_EVALID;
Michal Vaskocf770e22020-08-12 13:21:43 +02001277 goto cleanup;
Michal Vaskoa8edff02020-03-27 14:47:01 +01001278 }
1279
Michal Vaskoe0665742021-02-11 11:08:44 +01001280 /* try to parse "ok" */
1281 r = lydxml_envelope(xmlctx, "ok", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, &child);
1282 if (r == LY_SUCCESS) {
1283 /* insert */
1284 lyd_insert_node(*envp, NULL, child);
1285
1286 /* finish child parsing */
1287 if (xmlctx->status != LYXML_ELEM_CLOSE) {
1288 assert(xmlctx->status == LYXML_ELEMENT);
1289 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"ok\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001290 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001291 rc = LY_EVALID;
1292 goto cleanup;
1293 }
1294 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
1295
1296 /* success */
1297 parsed_elem = "ok";
1298 goto finish;
1299 } else if (r != LY_ENOT) {
1300 rc = r;
1301 goto cleanup;
Michal Vasko2552ea32020-12-08 15:32:34 +01001302 }
1303
Michal Vaskoe0665742021-02-11 11:08:44 +01001304 /* try to parse all "rpc-error" elements */
1305 while (xmlctx->status == LYXML_ELEMENT) {
1306 r = lydxml_envelope(xmlctx, "rpc-error", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, &child);
1307 if (r == LY_ENOT) {
1308 break;
1309 } else if (r) {
1310 rc = r;
1311 goto cleanup;
1312 }
1313
1314 /* insert */
1315 lyd_insert_node(*envp, NULL, child);
1316
1317 /* parse all children of "rpc-error" */
1318 LY_CHECK_GOTO(rc = lydxml_env_netconf_rpc_reply_error(xmlctx, child), cleanup);
1319
1320 /* finish child parsing */
1321 assert(xmlctx->status == LYXML_ELEM_CLOSE);
1322 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
1323
1324 parsed_elem = "rpc-error";
Michal Vasko2552ea32020-12-08 15:32:34 +01001325 }
Michal Vaskoe0665742021-02-11 11:08:44 +01001326
1327finish:
1328 if (parsed_elem) {
1329 /* NETCONF rpc-reply with no data */
1330 if (xmlctx->status != LYXML_ELEM_CLOSE) {
1331 assert(xmlctx->status == LYXML_ELEMENT);
1332 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected sibling element \"%.*s\" of \"%s\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001333 (int)xmlctx->name_len, xmlctx->name, parsed_elem);
Michal Vaskoe0665742021-02-11 11:08:44 +01001334 rc = LY_EVALID;
1335 goto cleanup;
1336 }
1337 }
1338
1339 /* NETCONF rpc-reply */
1340 *int_opts = LYD_INTOPT_NO_SIBLINGS | LYD_INTOPT_REPLY;
1341 *close_elem = 1;
1342
1343cleanup:
1344 if (rc) {
1345 lyd_free_tree(*envp);
1346 *envp = NULL;
1347 }
1348 return rc;
1349}
1350
Michal Vasko2552ea32020-12-08 15:32:34 +01001351LY_ERR
Radek Krejcif16e2542021-02-17 15:39:23 +01001352lyd_parse_xml(const struct ly_ctx *ctx, const struct lysc_ext_instance *ext, struct lyd_node *parent,
1353 struct lyd_node **first_p, struct ly_in *in, uint32_t parse_opts, uint32_t val_opts, enum lyd_type data_type,
1354 struct lyd_node **envp, struct ly_set *parsed, struct lyd_ctx **lydctx_p)
Michal Vasko2552ea32020-12-08 15:32:34 +01001355{
Michal Vaskoe0665742021-02-11 11:08:44 +01001356 LY_ERR rc = LY_SUCCESS;
1357 struct lyd_xml_ctx *lydctx;
1358 uint32_t i, int_opts, close_elem = 0;
1359 ly_bool parsed_data_nodes = 0;
Michal Vasko2552ea32020-12-08 15:32:34 +01001360
Michal Vaskoe0665742021-02-11 11:08:44 +01001361 assert(ctx && in && lydctx_p);
1362 assert(!(parse_opts & ~LYD_PARSE_OPTS_MASK));
1363 assert(!(val_opts & ~LYD_VALIDATE_OPTS_MASK));
Michal Vasko2552ea32020-12-08 15:32:34 +01001364
Michal Vaskoe0665742021-02-11 11:08:44 +01001365 /* init context */
1366 lydctx = calloc(1, sizeof *lydctx);
1367 LY_CHECK_ERR_RET(!lydctx, LOGMEM(ctx), LY_EMEM);
1368 LY_CHECK_GOTO(rc = lyxml_ctx_new(ctx, in, &lydctx->xmlctx), cleanup);
1369 lydctx->parse_opts = parse_opts;
1370 lydctx->val_opts = val_opts;
1371 lydctx->free = lyd_xml_ctx_free;
Radek Krejcif16e2542021-02-17 15:39:23 +01001372 lydctx->ext = ext;
Michal Vasko2552ea32020-12-08 15:32:34 +01001373
Michal Vaskoe0665742021-02-11 11:08:44 +01001374 switch (data_type) {
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001375 case LYD_TYPE_DATA_YANG:
Michal Vaskoe0665742021-02-11 11:08:44 +01001376 int_opts = LYD_INTOPT_WITH_SIBLINGS;
1377 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001378 case LYD_TYPE_RPC_YANG:
Michal Vaskoe0665742021-02-11 11:08:44 +01001379 int_opts = LYD_INTOPT_RPC | LYD_INTOPT_ACTION | LYD_INTOPT_NO_SIBLINGS;
1380 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001381 case LYD_TYPE_NOTIF_YANG:
Michal Vaskoe0665742021-02-11 11:08:44 +01001382 int_opts = LYD_INTOPT_NOTIF | LYD_INTOPT_NO_SIBLINGS;
1383 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001384 case LYD_TYPE_REPLY_YANG:
Michal Vaskoe0665742021-02-11 11:08:44 +01001385 int_opts = LYD_INTOPT_REPLY | LYD_INTOPT_NO_SIBLINGS;
1386 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001387 case LYD_TYPE_RPC_NETCONF:
Michal Vaskoe0665742021-02-11 11:08:44 +01001388 assert(!parent);
1389 LY_CHECK_GOTO(rc = lydxml_env_netconf_rpc(lydctx->xmlctx, envp, &int_opts, &close_elem), cleanup);
1390 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001391 case LYD_TYPE_NOTIF_NETCONF:
1392 assert(!parent);
1393 LY_CHECK_GOTO(rc = lydxml_env_netconf_notif(lydctx->xmlctx, envp, &int_opts, &close_elem), cleanup);
1394 break;
1395 case LYD_TYPE_REPLY_NETCONF:
Michal Vaskoe0665742021-02-11 11:08:44 +01001396 assert(parent);
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001397 LY_CHECK_GOTO(rc = lydxml_env_netconf_reply(lydctx->xmlctx, envp, &int_opts, &close_elem), cleanup);
Michal Vaskoe0665742021-02-11 11:08:44 +01001398 break;
1399 }
1400 lydctx->int_opts = int_opts;
1401
1402 /* find the operation node if it exists already */
1403 LY_CHECK_GOTO(rc = lyd_parser_find_operation(parent, int_opts, &lydctx->op_node), cleanup);
1404
1405 /* parse XML data */
1406 while (lydctx->xmlctx->status == LYXML_ELEMENT) {
1407 LY_CHECK_GOTO(rc = lydxml_subtree_r(lydctx, parent, first_p, parsed), cleanup);
1408 parsed_data_nodes = 1;
1409
1410 if (!(int_opts & LYD_INTOPT_WITH_SIBLINGS)) {
1411 break;
1412 }
Michal Vasko2552ea32020-12-08 15:32:34 +01001413 }
1414
Michal Vaskoe0665742021-02-11 11:08:44 +01001415 /* close all opened elements */
1416 for (i = 0; i < close_elem; ++i) {
1417 if (lydctx->xmlctx->status != LYXML_ELEM_CLOSE) {
1418 assert(lydctx->xmlctx->status == LYXML_ELEMENT);
Radek Krejci422afb12021-03-04 16:38:16 +01001419 LOGVAL(lydctx->xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\".",
1420 (int)lydctx->xmlctx->name_len, lydctx->xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001421 rc = LY_EVALID;
1422 goto cleanup;
1423 }
1424
1425 LY_CHECK_GOTO(rc = lyxml_ctx_next(lydctx->xmlctx), cleanup);
Michal Vasko4189c0f2020-08-13 09:05:22 +02001426 }
Michal Vaskoe0665742021-02-11 11:08:44 +01001427
1428 /* check final state */
1429 if ((int_opts & LYD_INTOPT_NO_SIBLINGS) && (lydctx->xmlctx->status == LYXML_ELEMENT)) {
1430 LOGVAL(ctx, LYVE_SYNTAX, "Unexpected sibling node.");
1431 rc = LY_EVALID;
1432 goto cleanup;
1433 }
1434 if ((int_opts & (LYD_INTOPT_RPC | LYD_INTOPT_NOTIF | LYD_INTOPT_REPLY)) && !lydctx->op_node) {
1435 LOGVAL(ctx, LYVE_DATA, "Missing the operation node.");
1436 rc = LY_EVALID;
1437 goto cleanup;
1438 }
1439
1440 if (!parsed_data_nodes) {
1441 /* no data nodes were parsed */
1442 lydctx->op_node = NULL;
Michal Vaskoa8edff02020-03-27 14:47:01 +01001443 }
1444
1445cleanup:
Michal Vaskoe0665742021-02-11 11:08:44 +01001446 /* there should be no unres stored if validation should be skipped */
1447 assert(!(parse_opts & LYD_PARSE_ONLY) || (!lydctx->node_types.count && !lydctx->meta_types.count &&
Radek Krejci4f2e3e52021-03-30 14:20:28 +02001448 !lydctx->node_when.count && !lydctx->node_exts.count));
Michal Vaskoe0665742021-02-11 11:08:44 +01001449
1450 if (rc) {
1451 lyd_xml_ctx_free((struct lyd_ctx *)lydctx);
1452 } else {
1453 *lydctx_p = (struct lyd_ctx *)lydctx;
1454
1455 /* the XML context is no more needed, freeing it also stops logging line numbers which would be confusing now */
1456 lyxml_ctx_free(lydctx->xmlctx);
1457 lydctx->xmlctx = NULL;
Michal Vasko1ce933a2020-03-30 12:38:22 +02001458 }
Michal Vaskoe0665742021-02-11 11:08:44 +01001459 return rc;
Michal Vasko1ce933a2020-03-30 12:38:22 +02001460}