blob: a61ca39edc11a0430793657b5e84b90a37951f14 [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
Michal Vasko45791ad2021-06-17 08:45:03 +020070/**
71 * @brief Parse and create XML metadata.
72 *
73 * @param[in] lydctx XML data parser context.
74 * @param[in] parent_exts Extension instances of the parent node.
75 * @param[out] meta List of created metadata instances.
76 * @return LY_ERR value.
77 */
Radek Krejcie7b95092019-05-15 11:03:07 +020078static LY_ERR
Michal Vasko45791ad2021-06-17 08:45:03 +020079lydxml_metadata(struct lyd_xml_ctx *lydctx, struct lysc_ext_instance *parent_exts, struct lyd_meta **meta)
Radek Krejcie7b95092019-05-15 11:03:07 +020080{
aPiecek1c4da362021-04-29 14:26:34 +020081 LY_ERR ret = LY_SUCCESS;
Radek Krejci28681fa2019-09-06 13:08:45 +020082 const struct lyxml_ns *ns;
83 struct lys_module *mod;
Michal Vaskob36053d2020-03-26 15:49:30 +010084 const char *name;
85 size_t name_len;
Michal Vasko45791ad2021-06-17 08:45:03 +020086 LY_ARRAY_COUNT_TYPE u;
87 ly_bool filter_attrs = 0;
Radek Krejci1798aae2020-07-14 13:26:06 +020088 struct lyxml_ctx *xmlctx = lydctx->xmlctx;
Radek Krejci28681fa2019-09-06 13:08:45 +020089
Michal Vaskob36053d2020-03-26 15:49:30 +010090 *meta = NULL;
Radek Krejci28681fa2019-09-06 13:08:45 +020091
Michal Vasko45791ad2021-06-17 08:45:03 +020092 /* check for NETCONF filter unqualified attributes */
93 LY_ARRAY_FOR(parent_exts, u) {
94 if (!strcmp(parent_exts[u].def->name, "get-filter-element-attributes") &&
95 !strcmp(parent_exts[u].def->module->name, "ietf-netconf")) {
96 filter_attrs = 1;
97 break;
98 }
99 }
100
Michal Vaskob36053d2020-03-26 15:49:30 +0100101 while (xmlctx->status == LYXML_ATTRIBUTE) {
102 if (!xmlctx->prefix_len) {
Michal Vasko45791ad2021-06-17 08:45:03 +0200103 /* in XML all attributes must be prefixed except NETCONF filter ones marked by an extension */
104 if (filter_attrs && (!ly_strncmp("type", xmlctx->name, xmlctx->name_len) ||
105 !ly_strncmp("select", xmlctx->name, xmlctx->name_len))) {
106 mod = ly_ctx_get_module_implemented(xmlctx->ctx, "ietf-netconf");
107 if (!mod) {
108 LOGVAL(xmlctx->ctx, LYVE_REFERENCE,
109 "Missing (or not implemented) YANG module \"ietf-netconf\" for special filter attributes.");
110 ret = LY_ENOTFOUND;
111 goto cleanup;
112 }
113 goto create_meta;
114 }
115
Michal Vaskoe0665742021-02-11 11:08:44 +0100116 if (lydctx->parse_opts & LYD_PARSE_STRICT) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100117 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Missing mandatory prefix for XML metadata \"%.*s\".",
Radek Krejci422afb12021-03-04 16:38:16 +0100118 (int)xmlctx->name_len, xmlctx->name);
Michal Vasko45791ad2021-06-17 08:45:03 +0200119 ret = LY_EVALID;
Michal Vaskob36053d2020-03-26 15:49:30 +0100120 goto cleanup;
Radek Krejci28681fa2019-09-06 13:08:45 +0200121 }
Michal Vaskob36053d2020-03-26 15:49:30 +0100122
Michal Vasko45791ad2021-06-17 08:45:03 +0200123 /* skip attr */
Michal Vaskob36053d2020-03-26 15:49:30 +0100124 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
125 assert(xmlctx->status == LYXML_ATTR_CONTENT);
126 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Radek Krejci28681fa2019-09-06 13:08:45 +0200127 continue;
128 }
129
130 /* get namespace of the attribute to find its annotation definition */
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200131 ns = lyxml_ns_get(&xmlctx->ns, xmlctx->prefix, xmlctx->prefix_len);
Radek Krejci28681fa2019-09-06 13:08:45 +0200132 if (!ns) {
Michal Vasko52927e22020-03-16 17:26:14 +0100133 /* unknown namespace, XML error */
Radek Krejci422afb12021-03-04 16:38:16 +0100134 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)xmlctx->prefix_len, xmlctx->prefix);
Michal Vasko45791ad2021-06-17 08:45:03 +0200135 ret = LY_ENOTFOUND;
Radek Krejci28681fa2019-09-06 13:08:45 +0200136 goto cleanup;
137 }
Michal Vasko45791ad2021-06-17 08:45:03 +0200138
139 /* get the module with metadata definition */
Michal Vasko52927e22020-03-16 17:26:14 +0100140 mod = ly_ctx_get_module_implemented_ns(xmlctx->ctx, ns->uri);
Radek Krejci28681fa2019-09-06 13:08:45 +0200141 if (!mod) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100142 if (lydctx->parse_opts & LYD_PARSE_STRICT) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100143 LOGVAL(xmlctx->ctx, LYVE_REFERENCE,
Michal Vasko69730152020-10-09 16:30:07 +0200144 "Unknown (or not implemented) YANG module with namespace \"%s\" for metadata \"%.*s%s%.*s\".",
Radek Krejci422afb12021-03-04 16:38:16 +0100145 ns->uri, (int)xmlctx->prefix_len, xmlctx->prefix, xmlctx->prefix_len ? ":" : "",
146 (int)xmlctx->name_len, xmlctx->name);
Michal Vasko45791ad2021-06-17 08:45:03 +0200147 ret = LY_ENOTFOUND;
Michal Vaskob36053d2020-03-26 15:49:30 +0100148 goto cleanup;
Radek Krejci28681fa2019-09-06 13:08:45 +0200149 }
Michal Vasko45791ad2021-06-17 08:45:03 +0200150
151 /* skip attr */
152 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
153 assert(xmlctx->status == LYXML_ATTR_CONTENT);
154 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
155 continue;
Radek Krejci28681fa2019-09-06 13:08:45 +0200156 }
157
Michal Vasko45791ad2021-06-17 08:45:03 +0200158create_meta:
Michal Vasko60ea6352020-06-29 13:39:39 +0200159 /* remember meta name and get its content */
Michal Vaskob36053d2020-03-26 15:49:30 +0100160 name = xmlctx->name;
161 name_len = xmlctx->name_len;
162 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
163 assert(xmlctx->status == LYXML_ATTR_CONTENT);
164
165 /* create metadata */
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200166 ret = lyd_parser_create_meta((struct lyd_ctx *)lydctx, NULL, meta, mod, name, name_len, xmlctx->value,
Radek Krejci8df109d2021-04-23 12:19:08 +0200167 xmlctx->value_len, &xmlctx->dynamic, LY_VALUE_XML, &xmlctx->ns, LYD_HINT_DATA);
Radek Krejci1798aae2020-07-14 13:26:06 +0200168 LY_CHECK_GOTO(ret, cleanup);
Michal Vaskob36053d2020-03-26 15:49:30 +0100169
170 /* next attribute */
171 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Radek Krejcie7b95092019-05-15 11:03:07 +0200172 }
Michal Vasko52927e22020-03-16 17:26:14 +0100173
Radek Krejcie7b95092019-05-15 11:03:07 +0200174cleanup:
Michal Vaskob36053d2020-03-26 15:49:30 +0100175 if (ret) {
Michal Vasko3a41dff2020-07-15 14:30:28 +0200176 lyd_free_meta_siblings(*meta);
Michal Vaskob36053d2020-03-26 15:49:30 +0100177 *meta = NULL;
Radek Krejci38d85362019-09-05 16:26:38 +0200178 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200179 return ret;
180}
181
Michal Vasko52927e22020-03-16 17:26:14 +0100182static LY_ERR
Radek Krejci1798aae2020-07-14 13:26:06 +0200183lydxml_attrs(struct lyxml_ctx *xmlctx, struct lyd_attr **attr)
Michal Vasko52927e22020-03-16 17:26:14 +0100184{
185 LY_ERR ret = LY_SUCCESS;
186 const struct lyxml_ns *ns;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100187 void *val_prefix_data;
Radek Krejci8df109d2021-04-23 12:19:08 +0200188 LY_VALUE_FORMAT format;
Radek Krejci1798aae2020-07-14 13:26:06 +0200189 struct lyd_attr *attr2;
Michal Vaskob36053d2020-03-26 15:49:30 +0100190 const char *name, *prefix;
191 size_t name_len, prefix_len;
Michal Vasko52927e22020-03-16 17:26:14 +0100192
193 assert(attr);
Michal Vaskob36053d2020-03-26 15:49:30 +0100194 *attr = NULL;
Michal Vasko52927e22020-03-16 17:26:14 +0100195
Michal Vaskob36053d2020-03-26 15:49:30 +0100196 while (xmlctx->status == LYXML_ATTRIBUTE) {
Michal Vasko52927e22020-03-16 17:26:14 +0100197 ns = NULL;
Michal Vaskob36053d2020-03-26 15:49:30 +0100198 if (xmlctx->prefix_len) {
Michal Vasko52927e22020-03-16 17:26:14 +0100199 /* get namespace of the attribute */
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200200 ns = lyxml_ns_get(&xmlctx->ns, xmlctx->prefix, xmlctx->prefix_len);
Michal Vasko52927e22020-03-16 17:26:14 +0100201 if (!ns) {
Radek Krejci422afb12021-03-04 16:38:16 +0100202 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)xmlctx->prefix_len, xmlctx->prefix);
Michal Vasko52927e22020-03-16 17:26:14 +0100203 ret = LY_EVALID;
204 goto cleanup;
205 }
206 }
207
208 if (*attr) {
209 attr2 = *attr;
210 } else {
211 attr2 = NULL;
212 }
213
Michal Vaskob36053d2020-03-26 15:49:30 +0100214 /* remember attr prefix, name, and get its content */
215 prefix = xmlctx->prefix;
216 prefix_len = xmlctx->prefix_len;
217 name = xmlctx->name;
218 name_len = xmlctx->name_len;
219 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
220 assert(xmlctx->status == LYXML_ATTR_CONTENT);
221
Michal Vasko52927e22020-03-16 17:26:14 +0100222 /* get value prefixes */
Michal Vaskofc2cd072021-02-24 13:17:17 +0100223 val_prefix_data = NULL;
Radek Krejci8df109d2021-04-23 12:19:08 +0200224 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 +0100225 &xmlctx->ns, &format, &val_prefix_data), cleanup);
Michal Vasko52927e22020-03-16 17:26:14 +0100226
227 /* attr2 is always changed to the created attribute */
Michal Vasko501af032020-11-11 20:27:44 +0100228 ret = lyd_create_attr(NULL, &attr2, xmlctx->ctx, name, name_len, prefix, prefix_len, ns ? ns->uri : NULL,
229 ns ? strlen(ns->uri) : 0, xmlctx->value, xmlctx->value_len, &xmlctx->dynamic, format, val_prefix_data, 0);
Michal Vasko52927e22020-03-16 17:26:14 +0100230 LY_CHECK_GOTO(ret, cleanup);
231
232 if (!*attr) {
233 *attr = attr2;
234 }
Michal Vaskob36053d2020-03-26 15:49:30 +0100235
236 /* next attribute */
237 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko52927e22020-03-16 17:26:14 +0100238 }
239
240cleanup:
Michal Vaskob36053d2020-03-26 15:49:30 +0100241 if (ret) {
Radek Krejci011e4aa2020-09-04 15:22:31 +0200242 lyd_free_attr_siblings(xmlctx->ctx, *attr);
Michal Vaskob36053d2020-03-26 15:49:30 +0100243 *attr = NULL;
Michal Vasko52927e22020-03-16 17:26:14 +0100244 }
Michal Vasko52927e22020-03-16 17:26:14 +0100245 return ret;
246}
247
Michal Vasko44685da2020-03-17 15:38:06 +0100248static LY_ERR
Michal Vaskob36053d2020-03-26 15:49:30 +0100249lydxml_check_list(struct lyxml_ctx *xmlctx, const struct lysc_node *list)
Michal Vasko44685da2020-03-17 15:38:06 +0100250{
Michal Vaskob36053d2020-03-26 15:49:30 +0100251 LY_ERR ret = LY_SUCCESS, r;
252 enum LYXML_PARSER_STATUS next;
Michal Vasko44685da2020-03-17 15:38:06 +0100253 struct ly_set key_set = {0};
254 const struct lysc_node *snode;
Michal Vaskob36053d2020-03-26 15:49:30 +0100255 uint32_t i, parents_count;
Michal Vasko44685da2020-03-17 15:38:06 +0100256
257 assert(list && (list->nodetype == LYS_LIST));
258
259 /* get all keys into a set (keys do not have if-features or anything) */
260 snode = NULL;
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100261 while ((snode = lys_getnext(snode, list, NULL, 0)) && (snode->flags & LYS_KEY)) {
Radek Krejci3d92e442020-10-12 12:48:13 +0200262 ret = ly_set_add(&key_set, (void *)snode, 1, NULL);
Radek Krejciba03a5a2020-08-27 14:40:41 +0200263 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100264 }
265
Michal Vasko12d809c2021-03-03 16:34:32 +0100266 /* remember parent count */
267 parents_count = xmlctx->elements.count;
268
Michal Vaskob36053d2020-03-26 15:49:30 +0100269 while (xmlctx->status == LYXML_ELEMENT) {
Michal Vasko44685da2020-03-17 15:38:06 +0100270 /* find key definition */
271 for (i = 0; i < key_set.count; ++i) {
272 snode = (const struct lysc_node *)key_set.objs[i];
Michal Vaskob36053d2020-03-26 15:49:30 +0100273 if (!ly_strncmp(snode->name, xmlctx->name, xmlctx->name_len)) {
Michal Vasko44685da2020-03-17 15:38:06 +0100274 break;
275 }
276 }
Michal Vaskob36053d2020-03-26 15:49:30 +0100277 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100278
279 /* skip attributes */
280 while (xmlctx->status == LYXML_ATTRIBUTE) {
Michal Vaskob36053d2020-03-26 15:49:30 +0100281 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
282 assert(xmlctx->status == LYXML_ATTR_CONTENT);
283 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100284 }
285
Michal Vaskob36053d2020-03-26 15:49:30 +0100286 assert(xmlctx->status == LYXML_ELEM_CONTENT);
287 if (i < key_set.count) {
288 /* validate the value */
Radek Krejci8df109d2021-04-23 12:19:08 +0200289 r = lys_value_validate(NULL, snode, xmlctx->value, xmlctx->value_len, LY_VALUE_XML, &xmlctx->ns);
Michal Vaskob36053d2020-03-26 15:49:30 +0100290 if (!r) {
291 /* key with a valid value, remove from the set */
292 ly_set_rm_index(&key_set, i, NULL);
Michal Vasko44685da2020-03-17 15:38:06 +0100293 }
294 }
295
Michal Vaskob36053d2020-03-26 15:49:30 +0100296 /* parser next */
297 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100298
Michal Vaskob36053d2020-03-26 15:49:30 +0100299 /* skip any children, resursively */
Michal Vasko12d809c2021-03-03 16:34:32 +0100300 while (xmlctx->status == LYXML_ELEMENT) {
301 while (parents_count < xmlctx->elements.count) {
302 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
303 }
304 assert(xmlctx->status == LYXML_ELEM_CLOSE);
Michal Vaskob36053d2020-03-26 15:49:30 +0100305 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
306 }
307
308 /* parser next, but do not parse closing element of the list because it would remove its namespaces */
309 assert(xmlctx->status == LYXML_ELEM_CLOSE);
310 LY_CHECK_GOTO(ret = lyxml_ctx_peek(xmlctx, &next), cleanup);
311 if (next != LYXML_ELEM_CLOSE) {
312 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
313 }
Michal Vasko44685da2020-03-17 15:38:06 +0100314 }
315
316 if (key_set.count) {
Michal Vaskob36053d2020-03-26 15:49:30 +0100317 /* some keys are missing/did not validate */
Michal Vasko44685da2020-03-17 15:38:06 +0100318 ret = LY_ENOT;
Michal Vasko44685da2020-03-17 15:38:06 +0100319 }
320
321cleanup:
322 ly_set_erase(&key_set, NULL);
323 return ret;
324}
325
Michal Vasko5c24ed12021-06-09 09:27:32 +0200326/**
327 * @brief Skip an element with all its descendants.
328 *
329 * @param[in] xmlctx XML parser context.
330 * @return LY_ERR value.
331 */
Michal Vasko1bf09392020-03-27 12:38:10 +0100332static LY_ERR
333lydxml_data_skip(struct lyxml_ctx *xmlctx)
334{
335 uint32_t parents_count;
336
337 /* remember current number of parents */
338 parents_count = xmlctx->elements.count;
aPiecek9cdb9e62021-05-18 09:46:20 +0200339 assert(parents_count);
Michal Vasko1bf09392020-03-27 12:38:10 +0100340
341 /* skip after the content */
342 while (xmlctx->status != LYXML_ELEM_CONTENT) {
343 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
344 }
345 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
346
347 /* skip all children elements, recursively, if any */
aPiecek9cdb9e62021-05-18 09:46:20 +0200348 while (parents_count <= xmlctx->elements.count) {
Michal Vasko1bf09392020-03-27 12:38:10 +0100349 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
350 }
351
352 /* close element */
353 assert(xmlctx->status == LYXML_ELEM_CLOSE);
354 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
355
356 return LY_SUCCESS;
357}
358
Michal Vasko5c24ed12021-06-09 09:27:32 +0200359/**
360 * @brief Check that the current element can be parsed as a data node.
361 *
362 * @param[in] lydctx XML data parser context.
363 * @param[in,out] snode Found schema node, set to NULL if data node cannot be created.
364 * @return LY_ERR value.
365 */
Michal Vasko1bf09392020-03-27 12:38:10 +0100366static LY_ERR
Radek Krejci1798aae2020-07-14 13:26:06 +0200367lydxml_data_check_opaq(struct lyd_xml_ctx *lydctx, const struct lysc_node **snode)
Michal Vasko1bf09392020-03-27 12:38:10 +0100368{
369 LY_ERR ret = LY_SUCCESS;
Michal Vaskoda8fbbf2021-06-16 11:44:44 +0200370 struct lyxml_ctx *xmlctx = lydctx->xmlctx, pxmlctx;
Michal Vasko1bf09392020-03-27 12:38:10 +0100371
Radek IÅ¡a3930fd72021-03-08 10:48:40 +0100372 if (!(lydctx->parse_opts & LYD_PARSE_OPAQ)) {
373 /* only checks specific to opaque nodes */
374 return LY_SUCCESS;
375 }
376
Michal Vasko13854662021-06-09 09:27:50 +0200377 if (!((*snode)->nodetype & (LYD_NODE_TERM | LYD_NODE_INNER))) {
378 /* nothing to check */
379 return LY_SUCCESS;
380 }
Michal Vasko1bf09392020-03-27 12:38:10 +0100381
Michal Vaskoda8fbbf2021-06-16 11:44:44 +0200382 assert(xmlctx->elements.count);
383
Michal Vasko13854662021-06-09 09:27:50 +0200384 /* backup parser */
Michal Vaskoda8fbbf2021-06-16 11:44:44 +0200385 LY_CHECK_RET(lyxml_ctx_backup(xmlctx, &pxmlctx));
Michal Vasko1bf09392020-03-27 12:38:10 +0100386
Michal Vasko13854662021-06-09 09:27:50 +0200387 /* skip attributes */
388 while (xmlctx->status == LYXML_ATTRIBUTE) {
389 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), restore);
390 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), restore);
391 }
Michal Vasko1bf09392020-03-27 12:38:10 +0100392
Michal Vasko13854662021-06-09 09:27:50 +0200393 if ((*snode)->nodetype & LYD_NODE_TERM) {
394 /* value may not be valid in which case we parse it as an opaque node */
395 if (lys_value_validate(NULL, *snode, xmlctx->value, xmlctx->value_len, LY_VALUE_XML, &xmlctx->ns)) {
Michal Vaskod0237d42021-07-12 14:49:46 +0200396 LOGVRB("Parsing opaque term node \"%s\" with invalid value \"%.*s\".", (*snode)->name, xmlctx->value_len,
397 xmlctx->value);
Michal Vasko13854662021-06-09 09:27:50 +0200398 *snode = NULL;
Michal Vasko1bf09392020-03-27 12:38:10 +0100399 }
Michal Vasko13854662021-06-09 09:27:50 +0200400 } else if ((*snode)->nodetype == LYS_LIST) {
401 /* skip content */
402 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), restore);
Michal Vasko1bf09392020-03-27 12:38:10 +0100403
Michal Vasko13854662021-06-09 09:27:50 +0200404 if (lydxml_check_list(xmlctx, *snode)) {
405 /* invalid list, parse as opaque if it missing/has invalid some keys */
Michal Vaskod0237d42021-07-12 14:49:46 +0200406 LOGVRB("Parsing opaque list node \"%s\" with missing/invalid keys.", (*snode)->name);
Michal Vasko13854662021-06-09 09:27:50 +0200407 *snode = NULL;
Michal Vasko1bf09392020-03-27 12:38:10 +0100408 }
Michal Vasko13854662021-06-09 09:27:50 +0200409 } else {
Radek IÅ¡a3930fd72021-03-08 10:48:40 +0100410 /* if there is a non-WS value, it cannot be parsed as an inner node */
411 assert(xmlctx->status == LYXML_ELEM_CONTENT);
412 if (!xmlctx->ws_only) {
413 *snode = NULL;
414 }
Michal Vasko1bf09392020-03-27 12:38:10 +0100415 }
416
Michal Vasko13854662021-06-09 09:27:50 +0200417restore:
418 /* restore parser */
Michal Vaskoda8fbbf2021-06-16 11:44:44 +0200419 lyxml_ctx_restore(xmlctx, &pxmlctx);
Michal Vasko1bf09392020-03-27 12:38:10 +0100420 return ret;
421}
422
Radek Krejcie7b95092019-05-15 11:03:07 +0200423/**
Michal Vaskoa5da3292020-08-12 13:10:50 +0200424 * @brief Parse XML subtree.
Radek Krejcie7b95092019-05-15 11:03:07 +0200425 *
Michal Vaskob36053d2020-03-26 15:49:30 +0100426 * @param[in] lydctx XML YANG data parser context.
Michal Vaskoe0665742021-02-11 11:08:44 +0100427 * @param[in,out] parent Parent node where the children are inserted. NULL in case of parsing top-level elements.
428 * @param[in,out] first_p Pointer to the first (@p parent or top-level) child. In case there were already some siblings,
429 * this may point to a previously existing node.
430 * @param[in,out] parsed Optional set to add all the parsed siblings into.
Michal Vasko9b368d32020-02-14 13:53:31 +0100431 * @return LY_ERR value.
Radek Krejcie7b95092019-05-15 11:03:07 +0200432 */
433static LY_ERR
Michal Vaskoe0665742021-02-11 11:08:44 +0100434lydxml_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 +0200435{
Michal Vaskob36053d2020-03-26 15:49:30 +0100436 LY_ERR ret = LY_SUCCESS;
Michal Vasko27c4dce2021-03-04 15:50:50 +0100437 const char *prefix, *name, *val;
Michal Vasko1bf09392020-03-27 12:38:10 +0100438 size_t prefix_len, name_len;
Michal Vaskob36053d2020-03-26 15:49:30 +0100439 struct lyxml_ctx *xmlctx;
440 const struct ly_ctx *ctx;
Radek Krejcie7b95092019-05-15 11:03:07 +0200441 const struct lyxml_ns *ns;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200442 struct lyd_meta *meta = NULL;
443 struct lyd_attr *attr = NULL;
Radek Krejcie7b95092019-05-15 11:03:07 +0200444 const struct lysc_node *snode;
445 struct lys_module *mod;
Michal Vaskoa98e3ea2021-06-03 09:13:33 +0200446 uint32_t prev_parse_opts, prev_int_opts;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200447 struct lyd_node *node = NULL, *anchor;
Michal Vaskofc2cd072021-02-24 13:17:17 +0100448 void *val_prefix_data = NULL;
Radek Krejci8df109d2021-04-23 12:19:08 +0200449 LY_VALUE_FORMAT format;
Radek Krejci1deb5be2020-08-26 16:43:36 +0200450 uint32_t getnext_opts;
Radek Krejcie7b95092019-05-15 11:03:07 +0200451
Michal Vaskoe0665742021-02-11 11:08:44 +0100452 assert(parent || first_p);
453
Michal Vaskob36053d2020-03-26 15:49:30 +0100454 xmlctx = lydctx->xmlctx;
455 ctx = xmlctx->ctx;
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100456 getnext_opts = lydctx->int_opts & LYD_INTOPT_REPLY ? LYS_GETNEXT_OUTPUT : 0;
Michal Vasko6f4cbb62020-02-28 11:15:47 +0100457
Michal Vaskoa5da3292020-08-12 13:10:50 +0200458 assert(xmlctx->status == LYXML_ELEMENT);
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200459
Michal Vaskoa5da3292020-08-12 13:10:50 +0200460 /* remember element prefix and name */
461 prefix = xmlctx->prefix;
462 prefix_len = xmlctx->prefix_len;
463 name = xmlctx->name;
464 name_len = xmlctx->name_len;
465
466 /* get the element module */
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200467 ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200468 if (!ns) {
Radek Krejci422afb12021-03-04 16:38:16 +0100469 LOGVAL(ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)prefix_len, prefix);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200470 ret = LY_EVALID;
471 goto error;
472 }
473 mod = ly_ctx_get_module_implemented_ns(ctx, ns->uri);
474 if (!mod) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100475 if (lydctx->parse_opts & LYD_PARSE_STRICT) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100476 LOGVAL(ctx, LYVE_REFERENCE, "No module with namespace \"%s\" in the context.", ns->uri);
Michal Vasko90932a92020-02-12 14:33:03 +0100477 ret = LY_EVALID;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200478 goto error;
Radek Krejcie7b95092019-05-15 11:03:07 +0200479 }
Michal Vaskoe0665742021-02-11 11:08:44 +0100480 if (!(lydctx->parse_opts & LYD_PARSE_OPAQ)) {
Michal Vaskoa5da3292020-08-12 13:10:50 +0200481 /* skip element with children */
482 LY_CHECK_GOTO(ret = lydxml_data_skip(xmlctx), error);
483 return LY_SUCCESS;
Radek Krejcie7b95092019-05-15 11:03:07 +0200484 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200485 }
486
Michal Vaskoa5da3292020-08-12 13:10:50 +0200487 /* parser next */
488 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
Michal Vasko90932a92020-02-12 14:33:03 +0100489
Michal Vaskoa5da3292020-08-12 13:10:50 +0200490 /* get the schema node */
491 snode = NULL;
492 if (mod && (!parent || parent->schema)) {
Radek Krejcif16e2542021-02-17 15:39:23 +0100493 if (!parent && lydctx->ext) {
Radek Krejciba05eab2021-03-10 13:19:29 +0100494 snode = lysc_ext_find_node(lydctx->ext, mod, name, name_len, 0, getnext_opts);
Radek Krejcif16e2542021-02-17 15:39:23 +0100495 } else {
496 snode = lys_find_child(parent ? parent->schema : NULL, mod, name, name_len, 0, getnext_opts);
497 }
Michal Vaskoa5da3292020-08-12 13:10:50 +0200498 if (!snode) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100499 if (lydctx->parse_opts & LYD_PARSE_STRICT) {
500 if (parent) {
Radek Krejci422afb12021-03-04 16:38:16 +0100501 LOGVAL(ctx, LYVE_REFERENCE, "Node \"%.*s\" not found as a child of \"%s\" node.",
502 (int)name_len, name, parent->schema->name);
Radek Krejcif16e2542021-02-17 15:39:23 +0100503 } else if (lydctx->ext) {
504 if (lydctx->ext->argument) {
Radek Krejci422afb12021-03-04 16:38:16 +0100505 LOGVAL(ctx, LYVE_REFERENCE, "Node \"%.*s\" not found in the \"%s\" %s extension instance.",
506 (int)name_len, name, lydctx->ext->argument, lydctx->ext->def->name);
Radek Krejcif16e2542021-02-17 15:39:23 +0100507 } else {
Radek Krejci422afb12021-03-04 16:38:16 +0100508 LOGVAL(ctx, LYVE_REFERENCE, "Node \"%.*s\" not found in the %s extension instance.",
509 (int)name_len, name, lydctx->ext->def->name);
Radek Krejcif16e2542021-02-17 15:39:23 +0100510 }
Michal Vaskoe0665742021-02-11 11:08:44 +0100511 } else {
Radek Krejci422afb12021-03-04 16:38:16 +0100512 LOGVAL(ctx, LYVE_REFERENCE, "Node \"%.*s\" not found in the \"%s\" module.",
513 (int)name_len, name, mod->name);
Michal Vaskoe0665742021-02-11 11:08:44 +0100514 }
Michal Vaskoa5da3292020-08-12 13:10:50 +0200515 ret = LY_EVALID;
516 goto error;
Michal Vaskoe0665742021-02-11 11:08:44 +0100517 } else if (!(lydctx->parse_opts & LYD_PARSE_OPAQ)) {
Michal Vaskod0237d42021-07-12 14:49:46 +0200518 LOGVRB("Skipping parsing of unkown node \"%.*s\".", name_len, name);
519
Michal Vaskoa5da3292020-08-12 13:10:50 +0200520 /* skip element with children */
521 LY_CHECK_GOTO(ret = lydxml_data_skip(xmlctx), error);
522 return LY_SUCCESS;
523 }
524 } else {
525 /* check that schema node is valid and can be used */
526 LY_CHECK_GOTO(ret = lyd_parser_check_schema((struct lyd_ctx *)lydctx, snode), error);
527 LY_CHECK_GOTO(ret = lydxml_data_check_opaq(lydctx, &snode), error);
528 }
529 }
530
531 /* create metadata/attributes */
532 if (xmlctx->status == LYXML_ATTRIBUTE) {
533 if (snode) {
Michal Vasko45791ad2021-06-17 08:45:03 +0200534 ret = lydxml_metadata(lydctx, snode->exts, &meta);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200535 LY_CHECK_GOTO(ret, error);
536 } else {
Michal Vaskoe0665742021-02-11 11:08:44 +0100537 assert(lydctx->parse_opts & LYD_PARSE_OPAQ);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200538 ret = lydxml_attrs(xmlctx, &attr);
539 LY_CHECK_GOTO(ret, error);
540 }
541 }
542
543 assert(xmlctx->status == LYXML_ELEM_CONTENT);
544 if (!snode) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100545 assert(lydctx->parse_opts & LYD_PARSE_OPAQ);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200546
547 if (xmlctx->ws_only) {
548 /* ignore WS-only value */
Radek IÅ¡a017270d2021-02-16 10:26:15 +0100549 if (xmlctx->dynamic) {
550 free((char *) xmlctx->value);
551 }
552 xmlctx->dynamic = 0;
553 xmlctx->value = "";
Michal Vaskoa5da3292020-08-12 13:10:50 +0200554 xmlctx->value_len = 0;
Radek Krejci8df109d2021-04-23 12:19:08 +0200555 format = LY_VALUE_XML;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200556 } else {
557 /* get value prefixes */
Radek Krejci8df109d2021-04-23 12:19:08 +0200558 ret = ly_store_prefix_data(xmlctx->ctx, xmlctx->value, xmlctx->value_len, LY_VALUE_XML,
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100559 &xmlctx->ns, &format, &val_prefix_data);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200560 LY_CHECK_GOTO(ret, error);
561 }
562
Michal Vaskoda8fbbf2021-06-16 11:44:44 +0200563 /* get NS again, it may have been backed up and restored */
564 ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
565 assert(ns);
566
Michal Vaskoa5da3292020-08-12 13:10:50 +0200567 /* create node */
Michal Vasko501af032020-11-11 20:27:44 +0100568 ret = lyd_create_opaq(ctx, name, name_len, prefix, prefix_len, ns->uri, strlen(ns->uri), xmlctx->value,
569 xmlctx->value_len, &xmlctx->dynamic, format, val_prefix_data, LYD_HINT_DATA, &node);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200570 LY_CHECK_GOTO(ret, error);
571
572 /* parser next */
573 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
574
575 /* process children */
576 while (xmlctx->status == LYXML_ELEMENT) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100577 ret = lydxml_subtree_r(lydctx, node, lyd_node_child_p(node), NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200578 LY_CHECK_GOTO(ret, error);
579 }
580 } else if (snode->nodetype & LYD_NODE_TERM) {
581 /* create node */
Michal Vasko22df3f02020-08-24 13:29:22 +0200582 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 +0200583 &xmlctx->dynamic, LY_VALUE_XML, &xmlctx->ns, LYD_HINT_DATA, &node), error);
Radek Krejciddace2c2021-01-08 11:30:56 +0100584 LOG_LOCSET(snode, node, NULL, NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200585
586 if (parent && (node->schema->flags & LYS_KEY)) {
587 /* check the key order, the anchor must never be a key */
Michal Vaskoe0665742021-02-11 11:08:44 +0100588 anchor = lyd_insert_get_next_anchor(lyd_child(parent), node);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200589 if (anchor && (anchor->schema->flags & LYS_KEY)) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100590 if (lydctx->parse_opts & LYD_PARSE_STRICT) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100591 LOGVAL(ctx, LYVE_DATA, "Invalid position of the key \"%s\" in a list.", node->schema->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200592 ret = LY_EVALID;
593 goto error;
594 } else {
595 LOGWRN(ctx, "Invalid position of the key \"%s\" in a list.", node->schema->name);
596 }
597 }
598 }
599
600 /* parser next */
601 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
602
603 /* no children expected */
604 if (xmlctx->status == LYXML_ELEMENT) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100605 LOGVAL(ctx, LYVE_SYNTAX, "Child element \"%.*s\" inside a terminal node \"%s\" found.",
Radek Krejci422afb12021-03-04 16:38:16 +0100606 (int)xmlctx->name_len, xmlctx->name, snode->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200607 ret = LY_EVALID;
608 goto error;
609 }
610 } else if (snode->nodetype & LYD_NODE_INNER) {
611 if (!xmlctx->ws_only) {
612 /* value in inner node */
Radek Krejci2efc45b2020-12-22 16:25:44 +0100613 LOGVAL(ctx, LYVE_SYNTAX, "Text value \"%.*s\" inside an inner node \"%s\" found.",
Radek Krejci422afb12021-03-04 16:38:16 +0100614 (int)xmlctx->value_len, xmlctx->value, snode->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200615 ret = LY_EVALID;
616 goto error;
617 }
618
619 /* create node */
620 ret = lyd_create_inner(snode, &node);
621 LY_CHECK_GOTO(ret, error);
622
Radek Krejciddace2c2021-01-08 11:30:56 +0100623 LOG_LOCSET(snode, node, NULL, NULL);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100624
Michal Vaskoa5da3292020-08-12 13:10:50 +0200625 /* parser next */
626 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
627
628 /* process children */
629 while (xmlctx->status == LYXML_ELEMENT) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100630 ret = lydxml_subtree_r(lydctx, node, lyd_node_child_p(node), NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200631 LY_CHECK_GOTO(ret, error);
632 }
633
634 if (snode->nodetype == LYS_LIST) {
635 /* check all keys exist */
636 LY_CHECK_GOTO(ret = lyd_parse_check_keys(node), error);
637 }
638
Michal Vaskoe0665742021-02-11 11:08:44 +0100639 if (!(lydctx->parse_opts & LYD_PARSE_ONLY)) {
Michal Vaskoa5da3292020-08-12 13:10:50 +0200640 /* new node validation, autodelete CANNOT occur, all nodes are new */
Michal Vaskoe0665742021-02-11 11:08:44 +0100641 ret = lyd_validate_new(lyd_node_child_p(node), snode, NULL, NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200642 LY_CHECK_GOTO(ret, error);
643
644 /* add any missing default children */
Radek Krejci4f2e3e52021-03-30 14:20:28 +0200645 ret = lyd_new_implicit_r(node, lyd_node_child_p(node), NULL, NULL, &lydctx->node_when, &lydctx->node_exts,
646 &lydctx->node_types, (lydctx->val_opts & LYD_VALIDATE_NO_STATE) ? LYD_IMPLICIT_NO_STATE : 0, NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200647 LY_CHECK_GOTO(ret, error);
648 }
649
650 if (snode->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) {
651 /* rememeber the RPC/action/notification */
652 lydctx->op_node = node;
653 }
654 } else if (snode->nodetype & LYD_NODE_ANY) {
Michal Vasko27c4dce2021-03-04 15:50:50 +0100655 if ((snode->nodetype == LYS_ANYDATA) && !xmlctx->ws_only) {
656 /* value in anydata node, we expect a tree */
657 LOGVAL(ctx, LYVE_SYNTAX, "Text value \"%.*s\" inside an anydata node \"%s\" found.",
Radek Krejci422afb12021-03-04 16:38:16 +0100658 (int)xmlctx->value_len < 20 ? xmlctx->value_len : 20, xmlctx->value, snode->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200659 ret = LY_EVALID;
660 goto error;
661 }
662
Michal Vasko27c4dce2021-03-04 15:50:50 +0100663 if (!xmlctx->ws_only) {
664 /* use an arbitrary text value for anyxml */
665 lydict_insert(xmlctx->ctx, xmlctx->value, xmlctx->value_len, &val);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200666
Michal Vasko27c4dce2021-03-04 15:50:50 +0100667 /* parser next */
668 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
669
670 /* create node */
671 ret = lyd_create_any(snode, val, LYD_ANYDATA_STRING, 1, &node);
672 LY_CHECK_GOTO(ret, error);
673 } else {
674 /* parser next */
675 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
676
Michal Vaskoa98e3ea2021-06-03 09:13:33 +0200677 /* update options so that generic data can be parsed */
678 prev_parse_opts = lydctx->parse_opts;
Michal Vasko27c4dce2021-03-04 15:50:50 +0100679 lydctx->parse_opts &= ~LYD_PARSE_STRICT;
680 lydctx->parse_opts |= LYD_PARSE_OPAQ;
Michal Vaskoa98e3ea2021-06-03 09:13:33 +0200681 prev_int_opts = lydctx->int_opts;
682 lydctx->int_opts |= LYD_INTOPT_RPC | LYD_INTOPT_ACTION | LYD_INTOPT_NOTIF;
683
684 /* parse any data tree */
Michal Vasko27c4dce2021-03-04 15:50:50 +0100685 anchor = NULL;
686 while (xmlctx->status == LYXML_ELEMENT) {
687 ret = lydxml_subtree_r(lydctx, NULL, &anchor, NULL);
Michal Vaskoa98e3ea2021-06-03 09:13:33 +0200688 if (ret) {
689 break;
690 }
Michal Vasko27c4dce2021-03-04 15:50:50 +0100691 }
Michal Vaskoa98e3ea2021-06-03 09:13:33 +0200692
693 /* restore options */
694 lydctx->parse_opts = prev_parse_opts;
695 lydctx->int_opts = prev_int_opts;
696
697 LY_CHECK_GOTO(ret, error);
Michal Vasko27c4dce2021-03-04 15:50:50 +0100698
699 /* create node */
700 ret = lyd_create_any(snode, anchor, LYD_ANYDATA_DATATREE, 1, &node);
701 LY_CHECK_GOTO(ret, error);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200702 }
Michal Vaskoa5da3292020-08-12 13:10:50 +0200703 }
704 assert(node);
705
706 /* add/correct flags */
707 if (snode) {
Radek Krejci4f2e3e52021-03-30 14:20:28 +0200708 lyd_parse_set_data_flags(node, &lydctx->node_when, &lydctx->node_exts, &meta, lydctx->parse_opts);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200709 }
710
711 /* parser next */
712 assert(xmlctx->status == LYXML_ELEM_CLOSE);
713 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
714
715 /* add metadata/attributes */
716 if (snode) {
Michal Vasko871a0252020-11-11 18:35:24 +0100717 lyd_insert_meta(node, meta, 0);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200718 } else {
719 lyd_insert_attr(node, attr);
720 }
721
722 /* insert, keep first pointer correct */
Michal Vaskoe0665742021-02-11 11:08:44 +0100723 lyd_insert_node(parent, first_p, node);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200724 while (!parent && (*first_p)->prev->next) {
725 *first_p = (*first_p)->prev;
726 }
727
Michal Vaskoe0665742021-02-11 11:08:44 +0100728 /* rememeber a successfully parsed node */
729 if (parsed) {
730 ly_set_add(parsed, node, 1, NULL);
731 }
732
Radek Krejciddace2c2021-01-08 11:30:56 +0100733 LOG_LOCBACK(node ? 1 : 0, node ? 1 : 0, 0, 0);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200734 return LY_SUCCESS;
735
736error:
Radek Krejciddace2c2021-01-08 11:30:56 +0100737 LOG_LOCBACK(node ? 1 : 0, node ? 1 : 0, 0, 0);
Michal Vasko3a41dff2020-07-15 14:30:28 +0200738 lyd_free_meta_siblings(meta);
Radek Krejci011e4aa2020-09-04 15:22:31 +0200739 lyd_free_attr_siblings(ctx, attr);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200740 lyd_free_tree(node);
Radek Krejcie7b95092019-05-15 11:03:07 +0200741 return ret;
742}
743
Michal Vaskoe0665742021-02-11 11:08:44 +0100744/**
745 * @brief Parse a specific XML element into an opaque node.
746 *
747 * @param[in] xmlctx XML parser context.
748 * @param[in] name Name of the element.
749 * @param[in] uri URI of the element.
750 * @param[in] value Whether a value is expected in the element.
751 * @param[out] evnp Parsed envelope (opaque node).
752 * @return LY_SUCCESS on success.
753 * @return LY_ENOT if the specified element did not match.
754 * @return LY_ERR value on error.
755 */
Michal Vasko1bf09392020-03-27 12:38:10 +0100756static LY_ERR
Michal Vaskoe0665742021-02-11 11:08:44 +0100757lydxml_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 +0100758{
Michal Vaskoe0665742021-02-11 11:08:44 +0100759 LY_ERR rc = LY_SUCCESS;
760 const struct lyxml_ns *ns;
Radek Krejci1798aae2020-07-14 13:26:06 +0200761 struct lyd_attr *attr = NULL;
Michal Vasko1bf09392020-03-27 12:38:10 +0100762 const char *prefix;
763 size_t prefix_len;
764
Michal Vasko1bf09392020-03-27 12:38:10 +0100765 assert(xmlctx->status == LYXML_ELEMENT);
766 if (ly_strncmp(name, xmlctx->name, xmlctx->name_len)) {
767 /* not the expected element */
Michal Vaskoe0665742021-02-11 11:08:44 +0100768 return LY_ENOT;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100769 }
770
771 prefix = xmlctx->prefix;
772 prefix_len = xmlctx->prefix_len;
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200773 ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100774 if (!ns) {
Radek Krejci422afb12021-03-04 16:38:16 +0100775 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)prefix_len, prefix);
Michal Vaskoe0665742021-02-11 11:08:44 +0100776 return LY_EVALID;
777 } else if (strcmp(ns->uri, uri)) {
778 /* different namespace */
779 return LY_ENOT;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100780 }
781
782 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
783
784 /* create attributes */
785 if (xmlctx->status == LYXML_ATTRIBUTE) {
786 LY_CHECK_RET(lydxml_attrs(xmlctx, &attr));
787 }
788
Michal Vaskoe0665742021-02-11 11:08:44 +0100789 assert(xmlctx->status == LYXML_ELEM_CONTENT);
790 if (!value && !xmlctx->ws_only) {
791 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected value \"%.*s\" in the \"%s\" element.",
Radek Krejci422afb12021-03-04 16:38:16 +0100792 (int)xmlctx->value_len, xmlctx->value, name);
Michal Vaskoe0665742021-02-11 11:08:44 +0100793 rc = LY_EVALID;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100794 goto cleanup;
Michal Vaskoe0665742021-02-11 11:08:44 +0100795 }
Michal Vaskoa8edff02020-03-27 14:47:01 +0100796
797 /* create node */
Michal Vaskoe0665742021-02-11 11:08:44 +0100798 rc = lyd_create_opaq(xmlctx->ctx, name, strlen(name), prefix, prefix_len, uri, strlen(uri), xmlctx->value,
Radek Krejci8df109d2021-04-23 12:19:08 +0200799 xmlctx->ws_only ? 0 : xmlctx->value_len, NULL, LY_VALUE_XML, NULL, 0, envp);
Michal Vaskoe0665742021-02-11 11:08:44 +0100800 LY_CHECK_GOTO(rc, cleanup);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100801
802 /* assign atributes */
Michal Vaskoe0665742021-02-11 11:08:44 +0100803 ((struct lyd_node_opaq *)(*envp))->attr = attr;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100804 attr = NULL;
805
Michal Vaskoe0665742021-02-11 11:08:44 +0100806 /* parser next element */
807 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100808
Michal Vaskoe0665742021-02-11 11:08:44 +0100809cleanup:
810 lyd_free_attr_siblings(xmlctx->ctx, attr);
811 if (rc) {
812 lyd_free_tree(*envp);
813 *envp = NULL;
814 }
815 return rc;
816}
817
818/**
819 * @brief Parse all expected non-data XML elements of a NETCONF rpc message.
820 *
821 * @param[in] xmlctx XML parser context.
822 * @param[out] evnp Parsed envelope(s) (opaque node).
823 * @param[out] int_opts Internal options for parsing the rest of YANG data.
824 * @param[out] close_elem Number of parsed opened elements that need to be closed.
825 * @return LY_SUCCESS on success.
826 * @return LY_ERR value on error.
827 */
828static LY_ERR
829lydxml_env_netconf_rpc(struct lyxml_ctx *xmlctx, struct lyd_node **envp, uint32_t *int_opts, uint32_t *close_elem)
830{
831 LY_ERR rc = LY_SUCCESS, r;
832 struct lyd_node *child;
833
834 assert(envp && !*envp);
835
836 /* parse "rpc" */
837 r = lydxml_envelope(xmlctx, "rpc", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, envp);
Michal Vaskoe0665742021-02-11 11:08:44 +0100838 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
839
840 /* parse "action", if any */
841 r = lydxml_envelope(xmlctx, "action", "urn:ietf:params:xml:ns:yang:1", 0, &child);
842 if (r == LY_SUCCESS) {
843 /* insert */
844 lyd_insert_node(*envp, NULL, child);
845
846 /* NETCONF action */
847 *int_opts = LYD_INTOPT_NO_SIBLINGS | LYD_INTOPT_ACTION;
848 *close_elem = 2;
849 } else if (r == LY_ENOT) {
850 /* NETCONF RPC */
851 *int_opts = LYD_INTOPT_NO_SIBLINGS | LYD_INTOPT_RPC;
852 *close_elem = 1;
853 } else {
854 rc = r;
855 goto cleanup;
856 }
857
858cleanup:
859 if (rc) {
860 lyd_free_tree(*envp);
861 *envp = NULL;
862 }
863 return rc;
864}
865
866/**
867 * @brief Parse all expected non-data XML elements of a NETCONF notification message.
868 *
869 * @param[in] xmlctx XML parser context.
870 * @param[out] evnp Parsed envelope(s) (opaque node).
871 * @param[out] int_opts Internal options for parsing the rest of YANG data.
872 * @param[out] close_elem Number of parsed opened elements that need to be closed.
873 * @return LY_SUCCESS on success.
874 * @return LY_ERR value on error.
875 */
876static LY_ERR
877lydxml_env_netconf_notif(struct lyxml_ctx *xmlctx, struct lyd_node **envp, uint32_t *int_opts, uint32_t *close_elem)
878{
879 LY_ERR rc = LY_SUCCESS, r;
880 struct lyd_node *child;
881
882 assert(envp && !*envp);
883
884 /* parse "notification" */
885 r = lydxml_envelope(xmlctx, "notification", "urn:ietf:params:xml:ns:netconf:notification:1.0", 0, envp);
Michal Vaskoe0665742021-02-11 11:08:44 +0100886 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
887
888 /* parse "eventTime" */
889 r = lydxml_envelope(xmlctx, "eventTime", "urn:ietf:params:xml:ns:netconf:notification:1.0", 1, &child);
890 if (r == LY_ENOT) {
Radek Krejci422afb12021-03-04 16:38:16 +0100891 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unexpected element \"%.*s\" instead of \"eventTime\".",
892 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +0100893 r = LY_EVALID;
894 }
895 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
896
897 /* insert */
898 lyd_insert_node(*envp, NULL, child);
899
900 /* validate value */
901 /* TODO validate child->value as yang:date-and-time */
902
903 /* finish child parsing */
Michal Vaskoa8edff02020-03-27 14:47:01 +0100904 if (xmlctx->status != LYXML_ELEM_CLOSE) {
905 assert(xmlctx->status == LYXML_ELEMENT);
Michal Vaskoe0665742021-02-11 11:08:44 +0100906 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"eventTime\".",
Radek Krejci422afb12021-03-04 16:38:16 +0100907 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +0100908 rc = LY_EVALID;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100909 goto cleanup;
910 }
Michal Vaskoe0665742021-02-11 11:08:44 +0100911 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
912
913 /* NETCONF notification */
914 *int_opts = LYD_INTOPT_NO_SIBLINGS | LYD_INTOPT_NOTIF;
915 *close_elem = 1;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100916
917cleanup:
Michal Vaskoe0665742021-02-11 11:08:44 +0100918 if (rc) {
Michal Vaskoa8edff02020-03-27 14:47:01 +0100919 lyd_free_tree(*envp);
Michal Vaskoe0665742021-02-11 11:08:44 +0100920 *envp = NULL;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100921 }
Michal Vaskoe0665742021-02-11 11:08:44 +0100922 return rc;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100923}
Michal Vasko79135ae2020-12-16 10:08:35 +0100924
Michal Vaskoe0665742021-02-11 11:08:44 +0100925/**
926 * @brief Parse an XML element as an opaque node subtree.
927 *
928 * @param[in] xmlctx XML parser context.
929 * @param[in] parent Parent to append nodes to.
930 * @return LY_ERR value.
931 */
932static LY_ERR
933lydxml_opaq_r(struct lyxml_ctx *xmlctx, struct lyd_node *parent)
Michal Vaskoa8edff02020-03-27 14:47:01 +0100934{
Michal Vaskoe0665742021-02-11 11:08:44 +0100935 LY_ERR rc = LY_SUCCESS;
936 const struct lyxml_ns *ns;
937 struct lyd_attr *attr = NULL;
938 struct lyd_node *child = NULL;
939 const char *name, *prefix;
940 size_t name_len, prefix_len;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100941
Michal Vaskoe0665742021-02-11 11:08:44 +0100942 assert(xmlctx->status == LYXML_ELEMENT);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100943
Michal Vaskoe0665742021-02-11 11:08:44 +0100944 name = xmlctx->name;
945 name_len = xmlctx->name_len;
946 prefix = xmlctx->prefix;
947 prefix_len = xmlctx->prefix_len;
948 ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
949 if (!ns) {
Radek Krejci422afb12021-03-04 16:38:16 +0100950 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)prefix_len, prefix);
Michal Vaskoe0665742021-02-11 11:08:44 +0100951 return LY_EVALID;
952 }
Michal Vaskoa8edff02020-03-27 14:47:01 +0100953
Michal Vaskoe0665742021-02-11 11:08:44 +0100954 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
Michal Vaskoa8edff02020-03-27 14:47:01 +0100955
Michal Vaskoe0665742021-02-11 11:08:44 +0100956 /* create attributes */
957 if (xmlctx->status == LYXML_ATTRIBUTE) {
958 LY_CHECK_RET(lydxml_attrs(xmlctx, &attr));
959 }
960
961 /* create node */
962 assert(xmlctx->status == LYXML_ELEM_CONTENT);
963 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 +0200964 xmlctx->ws_only ? 0 : xmlctx->value_len, NULL, LY_VALUE_XML, NULL, 0, &child);
Michal Vaskoe0665742021-02-11 11:08:44 +0100965 LY_CHECK_GOTO(rc, cleanup);
966
967 /* assign atributes */
968 ((struct lyd_node_opaq *)child)->attr = attr;
969 attr = NULL;
970
971 /* parser next element */
972 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
973
974 /* parse all the descendants */
975 while (xmlctx->status == LYXML_ELEMENT) {
976 rc = lydxml_opaq_r(xmlctx, child);
977 LY_CHECK_GOTO(rc, cleanup);
978 }
979
980 /* insert */
981 lyd_insert_node(parent, NULL, child);
982
983cleanup:
984 lyd_free_attr_siblings(xmlctx->ctx, attr);
985 if (rc) {
986 lyd_free_tree(child);
987 }
988 return rc;
989}
990
991/**
992 * @brief Parse all expected non-data XML elements of the error-info element in NETCONF rpc-reply message.
993 *
994 * @param[in] xmlctx XML parser context.
995 * @param[in] parent Parent to append nodes to.
996 * @return LY_ERR value.
997 */
998static LY_ERR
999lydxml_env_netconf_rpc_reply_error_info(struct lyxml_ctx *xmlctx, struct lyd_node *parent)
1000{
1001 LY_ERR r;
1002 struct lyd_node *child, *iter;
1003 const struct lyxml_ns *ns;
1004 ly_bool no_dup;
1005
1006 /* there must be some child */
1007 if (xmlctx->status == LYXML_ELEM_CLOSE) {
1008 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Missing child elements of \"error-info\".");
1009 return LY_EVALID;
1010 }
1011
1012 while (xmlctx->status == LYXML_ELEMENT) {
1013 child = NULL;
1014
1015 /*
1016 * session-id
1017 */
1018 r = lydxml_envelope(xmlctx, "session-id", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1019 if (r == LY_SUCCESS) {
1020 no_dup = 1;
1021 goto check_child;
1022 } else if (r != LY_ENOT) {
1023 goto error;
1024 }
1025
1026 /*
1027 * bad-attribute
1028 */
1029 r = lydxml_envelope(xmlctx, "bad-attribute", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1030 if (r == LY_SUCCESS) {
1031 no_dup = 1;
1032 goto check_child;
1033 } else if (r != LY_ENOT) {
1034 goto error;
1035 }
1036
1037 /*
1038 * bad-element
1039 */
1040 r = lydxml_envelope(xmlctx, "bad-element", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1041 if (r == LY_SUCCESS) {
1042 no_dup = 1;
1043 goto check_child;
1044 } else if (r != LY_ENOT) {
1045 goto error;
1046 }
1047
1048 /*
1049 * bad-namespace
1050 */
1051 r = lydxml_envelope(xmlctx, "bad-namespace", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1052 if (r == LY_SUCCESS) {
1053 no_dup = 1;
1054 goto check_child;
1055 } else if (r != LY_ENOT) {
1056 goto error;
1057 }
1058
1059 if (r == LY_ENOT) {
1060 assert(xmlctx->status == LYXML_ELEMENT);
1061
1062 /* learn namespace */
1063 ns = lyxml_ns_get(&xmlctx->ns, xmlctx->prefix, xmlctx->prefix_len);
1064 if (!ns) {
Radek Krejci422afb12021-03-04 16:38:16 +01001065 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)xmlctx->prefix_len, xmlctx->prefix);
Michal Vaskoe0665742021-02-11 11:08:44 +01001066 r = LY_EVALID;
1067 goto error;
1068 } else if (!strcmp(ns->uri, "urn:ietf:params:xml:ns:netconf:base:1.0")) {
1069 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"error-info\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001070 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001071 r = LY_EVALID;
1072 goto error;
1073 }
1074
1075 /* custom elements */
1076 r = lydxml_opaq_r(xmlctx, parent);
1077 LY_CHECK_GOTO(r, error);
1078
1079 no_dup = 0;
1080 }
1081
1082check_child:
1083 /* check for duplicates */
1084 if (no_dup) {
1085 LY_LIST_FOR(lyd_child(parent), iter) {
1086 if ((((struct lyd_node_opaq *)iter)->name.name == ((struct lyd_node_opaq *)child)->name.name) &&
1087 (((struct lyd_node_opaq *)iter)->name.module_ns == ((struct lyd_node_opaq *)child)->name.module_ns)) {
1088 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Duplicate element \"%s\" in \"error-info\".",
1089 ((struct lyd_node_opaq *)child)->name.name);
1090 r = LY_EVALID;
1091 goto error;
1092 }
1093 }
1094 }
1095
1096 /* finish child parsing */
1097 if (xmlctx->status != LYXML_ELEM_CLOSE) {
1098 assert(xmlctx->status == LYXML_ELEMENT);
1099 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"error-info\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001100 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001101 r = LY_EVALID;
1102 goto error;
1103 }
1104 LY_CHECK_GOTO(r = lyxml_ctx_next(xmlctx), error);
1105
1106 /* insert */
1107 lyd_insert_node(parent, NULL, child);
1108 }
1109
1110 return LY_SUCCESS;
1111
1112error:
1113 lyd_free_tree(child);
1114 return r;
1115}
1116
1117/**
1118 * @brief Parse all expected non-data XML elements of the rpc-error element in NETCONF rpc-reply message.
1119 *
1120 * @param[in] xmlctx XML parser context.
1121 * @param[in] parent Parent to append nodes to.
1122 * @return LY_ERR value.
1123 */
1124static LY_ERR
1125lydxml_env_netconf_rpc_reply_error(struct lyxml_ctx *xmlctx, struct lyd_node *parent)
1126{
1127 LY_ERR r;
1128 struct lyd_node *child, *iter;
1129 const char *val;
1130 ly_bool no_dup;
1131
1132 /* there must be some child */
1133 if (xmlctx->status == LYXML_ELEM_CLOSE) {
1134 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Missing child elements of \"rpc-error\".");
1135 return LY_EVALID;
1136 }
1137
1138 while (xmlctx->status == LYXML_ELEMENT) {
1139 child = NULL;
1140
1141 /*
1142 * error-type
1143 */
1144 r = lydxml_envelope(xmlctx, "error-type", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1145 if (r == LY_SUCCESS) {
1146 val = ((struct lyd_node_opaq *)child)->value;
1147 if (strcmp(val, "transport") && strcmp(val, "rpc") && strcmp(val, "protocol") && strcmp(val, "application")) {
1148 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Invalid value \"%s\" of element \"%s\".", val,
1149 ((struct lyd_node_opaq *)child)->name.name);
1150 r = LY_EVALID;
1151 goto error;
1152 }
1153
1154 no_dup = 1;
1155 goto check_child;
1156 } else if (r != LY_ENOT) {
1157 goto error;
1158 }
1159
1160 /*
1161 * error-tag
1162 */
1163 r = lydxml_envelope(xmlctx, "error-tag", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1164 if (r == LY_SUCCESS) {
1165 val = ((struct lyd_node_opaq *)child)->value;
1166 if (strcmp(val, "in-use") && strcmp(val, "invalid-value") && strcmp(val, "too-big") &&
1167 strcmp(val, "missing-attribute") && strcmp(val, "bad-attribute") &&
1168 strcmp(val, "unknown-attribute") && strcmp(val, "missing-element") && strcmp(val, "bad-element") &&
1169 strcmp(val, "unknown-element") && strcmp(val, "unknown-namespace") && strcmp(val, "access-denied") &&
1170 strcmp(val, "lock-denied") && strcmp(val, "resource-denied") && strcmp(val, "rollback-failed") &&
1171 strcmp(val, "data-exists") && strcmp(val, "data-missing") && strcmp(val, "operation-not-supported") &&
1172 strcmp(val, "operation-failed") && strcmp(val, "malformed-message")) {
1173 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Invalid value \"%s\" of element \"%s\".", val,
1174 ((struct lyd_node_opaq *)child)->name.name);
1175 r = LY_EVALID;
1176 goto error;
1177 }
1178
1179 no_dup = 1;
1180 goto check_child;
1181 } else if (r != LY_ENOT) {
1182 goto error;
1183 }
1184
1185 /*
1186 * error-severity
1187 */
1188 r = lydxml_envelope(xmlctx, "error-severity", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1189 if (r == LY_SUCCESS) {
1190 val = ((struct lyd_node_opaq *)child)->value;
1191 if (strcmp(val, "error") && strcmp(val, "warning")) {
1192 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Invalid value \"%s\" of element \"%s\".", val,
1193 ((struct lyd_node_opaq *)child)->name.name);
1194 r = LY_EVALID;
1195 goto error;
1196 }
1197
1198 no_dup = 1;
1199 goto check_child;
1200 } else if (r != LY_ENOT) {
1201 goto error;
1202 }
1203
1204 /*
1205 * error-app-tag
1206 */
1207 r = lydxml_envelope(xmlctx, "error-app-tag", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1208 if (r == LY_SUCCESS) {
1209 no_dup = 1;
1210 goto check_child;
1211 } else if (r != LY_ENOT) {
1212 goto error;
1213 }
1214
1215 /*
1216 * error-path
1217 */
1218 r = lydxml_envelope(xmlctx, "error-path", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1219 if (r == LY_SUCCESS) {
1220 no_dup = 1;
1221 goto check_child;
1222 } else if (r != LY_ENOT) {
1223 goto error;
1224 }
1225
1226 /*
1227 * error-message
1228 */
1229 r = lydxml_envelope(xmlctx, "error-message", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1230 if (r == LY_SUCCESS) {
1231 no_dup = 1;
1232 goto check_child;
1233 } else if (r != LY_ENOT) {
1234 goto error;
1235 }
1236
1237 /* error-info */
1238 r = lydxml_envelope(xmlctx, "error-info", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, &child);
1239 if (r == LY_SUCCESS) {
1240 /* parse all the descendants */
1241 LY_CHECK_GOTO(r = lydxml_env_netconf_rpc_reply_error_info(xmlctx, child), error);
1242
1243 no_dup = 0;
1244 goto check_child;
1245 } else if (r != LY_ENOT) {
1246 goto error;
1247 }
1248
1249 if (r == LY_ENOT) {
1250 assert(xmlctx->status == LYXML_ELEMENT);
1251 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"rpc-error\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001252 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001253 r = LY_EVALID;
1254 goto error;
1255 }
1256
1257check_child:
1258 /* check for duplicates */
1259 if (no_dup) {
1260 LY_LIST_FOR(lyd_child(parent), iter) {
1261 if ((((struct lyd_node_opaq *)iter)->name.name == ((struct lyd_node_opaq *)child)->name.name) &&
1262 (((struct lyd_node_opaq *)iter)->name.module_ns == ((struct lyd_node_opaq *)child)->name.module_ns)) {
1263 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Duplicate element \"%s\" in \"rpc-error\".",
1264 ((struct lyd_node_opaq *)child)->name.name);
1265 r = LY_EVALID;
1266 goto error;
1267 }
1268 }
1269 }
1270
1271 /* finish child parsing */
1272 if (xmlctx->status != LYXML_ELEM_CLOSE) {
1273 assert(xmlctx->status == LYXML_ELEMENT);
1274 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"rpc-error\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001275 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001276 r = LY_EVALID;
1277 goto error;
1278 }
1279 LY_CHECK_GOTO(r = lyxml_ctx_next(xmlctx), error);
1280
1281 /* insert */
1282 lyd_insert_node(parent, NULL, child);
1283 }
1284
1285 return LY_SUCCESS;
1286
1287error:
1288 lyd_free_tree(child);
1289 return r;
1290}
1291
1292/**
1293 * @brief Parse all expected non-data XML elements of a NETCONF rpc-reply message.
1294 *
1295 * @param[in] xmlctx XML parser context.
1296 * @param[out] evnp Parsed envelope(s) (opaque node).
1297 * @param[out] int_opts Internal options for parsing the rest of YANG data.
1298 * @param[out] close_elem Number of parsed opened elements that need to be closed.
1299 * @return LY_SUCCESS on success.
1300 * @return LY_ERR value on error.
1301 */
1302static LY_ERR
1303lydxml_env_netconf_reply(struct lyxml_ctx *xmlctx, struct lyd_node **envp, uint32_t *int_opts, uint32_t *close_elem)
1304{
1305 LY_ERR rc = LY_SUCCESS, r;
1306 struct lyd_node *child = NULL;
1307 const char *parsed_elem = NULL;
1308
1309 assert(envp && !*envp);
1310
1311 /* parse "rpc-reply" */
1312 r = lydxml_envelope(xmlctx, "rpc-reply", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, envp);
Michal Vaskoe0665742021-02-11 11:08:44 +01001313 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
1314
1315 /* there must be some child */
1316 if (xmlctx->status == LYXML_ELEM_CLOSE) {
1317 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Missing child elements of \"rpc-reply\".");
1318 rc = LY_EVALID;
Michal Vaskocf770e22020-08-12 13:21:43 +02001319 goto cleanup;
Michal Vaskoa8edff02020-03-27 14:47:01 +01001320 }
1321
Michal Vaskoe0665742021-02-11 11:08:44 +01001322 /* try to parse "ok" */
1323 r = lydxml_envelope(xmlctx, "ok", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, &child);
1324 if (r == LY_SUCCESS) {
1325 /* insert */
1326 lyd_insert_node(*envp, NULL, child);
1327
1328 /* finish child parsing */
1329 if (xmlctx->status != LYXML_ELEM_CLOSE) {
1330 assert(xmlctx->status == LYXML_ELEMENT);
1331 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"ok\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001332 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001333 rc = LY_EVALID;
1334 goto cleanup;
1335 }
1336 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
1337
1338 /* success */
1339 parsed_elem = "ok";
1340 goto finish;
1341 } else if (r != LY_ENOT) {
1342 rc = r;
1343 goto cleanup;
Michal Vasko2552ea32020-12-08 15:32:34 +01001344 }
1345
Michal Vaskoe0665742021-02-11 11:08:44 +01001346 /* try to parse all "rpc-error" elements */
1347 while (xmlctx->status == LYXML_ELEMENT) {
1348 r = lydxml_envelope(xmlctx, "rpc-error", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, &child);
1349 if (r == LY_ENOT) {
1350 break;
1351 } else if (r) {
1352 rc = r;
1353 goto cleanup;
1354 }
1355
1356 /* insert */
1357 lyd_insert_node(*envp, NULL, child);
1358
1359 /* parse all children of "rpc-error" */
1360 LY_CHECK_GOTO(rc = lydxml_env_netconf_rpc_reply_error(xmlctx, child), cleanup);
1361
1362 /* finish child parsing */
1363 assert(xmlctx->status == LYXML_ELEM_CLOSE);
1364 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
1365
1366 parsed_elem = "rpc-error";
Michal Vasko2552ea32020-12-08 15:32:34 +01001367 }
Michal Vaskoe0665742021-02-11 11:08:44 +01001368
1369finish:
1370 if (parsed_elem) {
1371 /* NETCONF rpc-reply with no data */
1372 if (xmlctx->status != LYXML_ELEM_CLOSE) {
1373 assert(xmlctx->status == LYXML_ELEMENT);
1374 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected sibling element \"%.*s\" of \"%s\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001375 (int)xmlctx->name_len, xmlctx->name, parsed_elem);
Michal Vaskoe0665742021-02-11 11:08:44 +01001376 rc = LY_EVALID;
1377 goto cleanup;
1378 }
1379 }
1380
1381 /* NETCONF rpc-reply */
Michal Vasko1d991fd2021-07-09 13:14:40 +02001382 *int_opts = LYD_INTOPT_WITH_SIBLINGS | LYD_INTOPT_REPLY;
Michal Vaskoe0665742021-02-11 11:08:44 +01001383 *close_elem = 1;
1384
1385cleanup:
1386 if (rc) {
1387 lyd_free_tree(*envp);
1388 *envp = NULL;
1389 }
1390 return rc;
1391}
1392
Michal Vasko2552ea32020-12-08 15:32:34 +01001393LY_ERR
Radek Krejcif16e2542021-02-17 15:39:23 +01001394lyd_parse_xml(const struct ly_ctx *ctx, const struct lysc_ext_instance *ext, struct lyd_node *parent,
1395 struct lyd_node **first_p, struct ly_in *in, uint32_t parse_opts, uint32_t val_opts, enum lyd_type data_type,
1396 struct lyd_node **envp, struct ly_set *parsed, struct lyd_ctx **lydctx_p)
Michal Vasko2552ea32020-12-08 15:32:34 +01001397{
Michal Vaskoe0665742021-02-11 11:08:44 +01001398 LY_ERR rc = LY_SUCCESS;
1399 struct lyd_xml_ctx *lydctx;
Michal Vasko2ca9f9e2021-07-02 09:21:36 +02001400 uint32_t i, int_opts = 0, close_elem = 0;
Michal Vaskoe0665742021-02-11 11:08:44 +01001401 ly_bool parsed_data_nodes = 0;
Michal Vasko2552ea32020-12-08 15:32:34 +01001402
Michal Vaskoe0665742021-02-11 11:08:44 +01001403 assert(ctx && in && lydctx_p);
1404 assert(!(parse_opts & ~LYD_PARSE_OPTS_MASK));
1405 assert(!(val_opts & ~LYD_VALIDATE_OPTS_MASK));
Michal Vasko2552ea32020-12-08 15:32:34 +01001406
Michal Vaskoe0665742021-02-11 11:08:44 +01001407 /* init context */
1408 lydctx = calloc(1, sizeof *lydctx);
1409 LY_CHECK_ERR_RET(!lydctx, LOGMEM(ctx), LY_EMEM);
1410 LY_CHECK_GOTO(rc = lyxml_ctx_new(ctx, in, &lydctx->xmlctx), cleanup);
1411 lydctx->parse_opts = parse_opts;
1412 lydctx->val_opts = val_opts;
1413 lydctx->free = lyd_xml_ctx_free;
Radek Krejcif16e2542021-02-17 15:39:23 +01001414 lydctx->ext = ext;
Michal Vasko2552ea32020-12-08 15:32:34 +01001415
Michal Vaskoe0665742021-02-11 11:08:44 +01001416 switch (data_type) {
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001417 case LYD_TYPE_DATA_YANG:
Michal Vaskoe0665742021-02-11 11:08:44 +01001418 int_opts = LYD_INTOPT_WITH_SIBLINGS;
1419 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001420 case LYD_TYPE_RPC_YANG:
Michal Vaskoe0665742021-02-11 11:08:44 +01001421 int_opts = LYD_INTOPT_RPC | LYD_INTOPT_ACTION | LYD_INTOPT_NO_SIBLINGS;
1422 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001423 case LYD_TYPE_NOTIF_YANG:
Michal Vaskoe0665742021-02-11 11:08:44 +01001424 int_opts = LYD_INTOPT_NOTIF | LYD_INTOPT_NO_SIBLINGS;
1425 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001426 case LYD_TYPE_REPLY_YANG:
Michal Vaskoe0665742021-02-11 11:08:44 +01001427 int_opts = LYD_INTOPT_REPLY | LYD_INTOPT_NO_SIBLINGS;
1428 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001429 case LYD_TYPE_RPC_NETCONF:
Michal Vaskoe0665742021-02-11 11:08:44 +01001430 assert(!parent);
1431 LY_CHECK_GOTO(rc = lydxml_env_netconf_rpc(lydctx->xmlctx, envp, &int_opts, &close_elem), cleanup);
1432 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001433 case LYD_TYPE_NOTIF_NETCONF:
1434 assert(!parent);
1435 LY_CHECK_GOTO(rc = lydxml_env_netconf_notif(lydctx->xmlctx, envp, &int_opts, &close_elem), cleanup);
1436 break;
1437 case LYD_TYPE_REPLY_NETCONF:
Michal Vaskoe0665742021-02-11 11:08:44 +01001438 assert(parent);
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001439 LY_CHECK_GOTO(rc = lydxml_env_netconf_reply(lydctx->xmlctx, envp, &int_opts, &close_elem), cleanup);
Michal Vaskoe0665742021-02-11 11:08:44 +01001440 break;
1441 }
1442 lydctx->int_opts = int_opts;
1443
1444 /* find the operation node if it exists already */
1445 LY_CHECK_GOTO(rc = lyd_parser_find_operation(parent, int_opts, &lydctx->op_node), cleanup);
1446
1447 /* parse XML data */
1448 while (lydctx->xmlctx->status == LYXML_ELEMENT) {
1449 LY_CHECK_GOTO(rc = lydxml_subtree_r(lydctx, parent, first_p, parsed), cleanup);
1450 parsed_data_nodes = 1;
1451
1452 if (!(int_opts & LYD_INTOPT_WITH_SIBLINGS)) {
1453 break;
1454 }
Michal Vasko2552ea32020-12-08 15:32:34 +01001455 }
1456
Michal Vaskoe0665742021-02-11 11:08:44 +01001457 /* close all opened elements */
1458 for (i = 0; i < close_elem; ++i) {
1459 if (lydctx->xmlctx->status != LYXML_ELEM_CLOSE) {
1460 assert(lydctx->xmlctx->status == LYXML_ELEMENT);
Radek Krejci422afb12021-03-04 16:38:16 +01001461 LOGVAL(lydctx->xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\".",
1462 (int)lydctx->xmlctx->name_len, lydctx->xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001463 rc = LY_EVALID;
1464 goto cleanup;
1465 }
1466
1467 LY_CHECK_GOTO(rc = lyxml_ctx_next(lydctx->xmlctx), cleanup);
Michal Vasko4189c0f2020-08-13 09:05:22 +02001468 }
Michal Vaskoe0665742021-02-11 11:08:44 +01001469
1470 /* check final state */
1471 if ((int_opts & LYD_INTOPT_NO_SIBLINGS) && (lydctx->xmlctx->status == LYXML_ELEMENT)) {
1472 LOGVAL(ctx, LYVE_SYNTAX, "Unexpected sibling node.");
1473 rc = LY_EVALID;
1474 goto cleanup;
1475 }
1476 if ((int_opts & (LYD_INTOPT_RPC | LYD_INTOPT_NOTIF | LYD_INTOPT_REPLY)) && !lydctx->op_node) {
1477 LOGVAL(ctx, LYVE_DATA, "Missing the operation node.");
1478 rc = LY_EVALID;
1479 goto cleanup;
1480 }
1481
1482 if (!parsed_data_nodes) {
1483 /* no data nodes were parsed */
1484 lydctx->op_node = NULL;
Michal Vaskoa8edff02020-03-27 14:47:01 +01001485 }
1486
1487cleanup:
Michal Vaskoe0665742021-02-11 11:08:44 +01001488 /* there should be no unres stored if validation should be skipped */
1489 assert(!(parse_opts & LYD_PARSE_ONLY) || (!lydctx->node_types.count && !lydctx->meta_types.count &&
Radek Krejci4f2e3e52021-03-30 14:20:28 +02001490 !lydctx->node_when.count && !lydctx->node_exts.count));
Michal Vaskoe0665742021-02-11 11:08:44 +01001491
1492 if (rc) {
1493 lyd_xml_ctx_free((struct lyd_ctx *)lydctx);
1494 } else {
1495 *lydctx_p = (struct lyd_ctx *)lydctx;
1496
1497 /* the XML context is no more needed, freeing it also stops logging line numbers which would be confusing now */
1498 lyxml_ctx_free(lydctx->xmlctx);
1499 lydctx->xmlctx = NULL;
Michal Vasko1ce933a2020-03-30 12:38:22 +02001500 }
Michal Vaskoe0665742021-02-11 11:08:44 +01001501 return rc;
Michal Vasko1ce933a2020-03-30 12:38:22 +02001502}