blob: 3e46ad49f88e7768bef5d305766a00400291bf6a [file] [log] [blame]
Radek Krejcie7b95092019-05-15 11:03:07 +02001/**
2 * @file parser_xml.c
3 * @author Radek Krejci <rkrejci@cesnet.cz>
4 * @brief XML data parser for libyang
5 *
6 * Copyright (c) 2019 CESNET, z.s.p.o.
7 *
8 * This source code is licensed under BSD 3-Clause License (the "License").
9 * You may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * https://opensource.org/licenses/BSD-3-Clause
13 */
14
Michal Vasko69730152020-10-09 16:30:07 +020015#include <assert.h>
Radek Krejcie7b95092019-05-15 11:03:07 +020016#include <stdint.h>
17#include <stdlib.h>
18#include <string.h>
19
Radek Krejci535ea9f2020-05-29 16:01:05 +020020#include "common.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020021#include "context.h"
Radek Krejci77114102021-03-10 15:21:57 +010022#include "dict.h"
Michal Vaskoafac7822020-10-20 14:22:26 +020023#include "in_internal.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020024#include "log.h"
Radek Krejci7931b192020-06-25 17:05:03 +020025#include "parser_data.h"
26#include "parser_internal.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020027#include "set.h"
Radek Krejci77114102021-03-10 15:21:57 +010028#include "tree.h"
Radek Krejci47fab892020-11-05 17:02:41 +010029#include "tree_data.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020030#include "tree_data_internal.h"
31#include "tree_schema.h"
Radek Krejci77114102021-03-10 15:21:57 +010032#include "tree_schema_internal.h"
Michal Vaskocde73ac2019-11-14 16:10:27 +010033#include "validation.h"
Radek Krejci535ea9f2020-05-29 16:01:05 +020034#include "xml.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020035
Radek Krejci1798aae2020-07-14 13:26:06 +020036void
37lyd_xml_ctx_free(struct lyd_ctx *lydctx)
38{
39 struct lyd_xml_ctx *ctx = (struct lyd_xml_ctx *)lydctx;
40
41 lyd_ctx_free(lydctx);
42 lyxml_ctx_free(ctx->xmlctx);
43 free(ctx);
44}
45
Michal Vasko45791ad2021-06-17 08:45:03 +020046/**
47 * @brief Parse and create XML metadata.
48 *
49 * @param[in] lydctx XML data parser context.
50 * @param[in] parent_exts Extension instances of the parent node.
51 * @param[out] meta List of created metadata instances.
52 * @return LY_ERR value.
53 */
Radek Krejcie7b95092019-05-15 11:03:07 +020054static LY_ERR
Michal Vasko45791ad2021-06-17 08:45:03 +020055lydxml_metadata(struct lyd_xml_ctx *lydctx, struct lysc_ext_instance *parent_exts, struct lyd_meta **meta)
Radek Krejcie7b95092019-05-15 11:03:07 +020056{
aPiecek1c4da362021-04-29 14:26:34 +020057 LY_ERR ret = LY_SUCCESS;
Radek Krejci28681fa2019-09-06 13:08:45 +020058 const struct lyxml_ns *ns;
59 struct lys_module *mod;
Michal Vaskob36053d2020-03-26 15:49:30 +010060 const char *name;
61 size_t name_len;
Michal Vasko45791ad2021-06-17 08:45:03 +020062 LY_ARRAY_COUNT_TYPE u;
63 ly_bool filter_attrs = 0;
Radek Krejci1798aae2020-07-14 13:26:06 +020064 struct lyxml_ctx *xmlctx = lydctx->xmlctx;
Radek Krejci28681fa2019-09-06 13:08:45 +020065
Michal Vaskob36053d2020-03-26 15:49:30 +010066 *meta = NULL;
Radek Krejci28681fa2019-09-06 13:08:45 +020067
Michal Vasko45791ad2021-06-17 08:45:03 +020068 /* check for NETCONF filter unqualified attributes */
69 LY_ARRAY_FOR(parent_exts, u) {
70 if (!strcmp(parent_exts[u].def->name, "get-filter-element-attributes") &&
71 !strcmp(parent_exts[u].def->module->name, "ietf-netconf")) {
72 filter_attrs = 1;
73 break;
74 }
75 }
76
Michal Vaskob36053d2020-03-26 15:49:30 +010077 while (xmlctx->status == LYXML_ATTRIBUTE) {
78 if (!xmlctx->prefix_len) {
Michal Vasko45791ad2021-06-17 08:45:03 +020079 /* in XML all attributes must be prefixed except NETCONF filter ones marked by an extension */
80 if (filter_attrs && (!ly_strncmp("type", xmlctx->name, xmlctx->name_len) ||
81 !ly_strncmp("select", xmlctx->name, xmlctx->name_len))) {
82 mod = ly_ctx_get_module_implemented(xmlctx->ctx, "ietf-netconf");
83 if (!mod) {
84 LOGVAL(xmlctx->ctx, LYVE_REFERENCE,
85 "Missing (or not implemented) YANG module \"ietf-netconf\" for special filter attributes.");
86 ret = LY_ENOTFOUND;
87 goto cleanup;
88 }
89 goto create_meta;
90 }
91
Michal Vaskoe0665742021-02-11 11:08:44 +010092 if (lydctx->parse_opts & LYD_PARSE_STRICT) {
Radek Krejci2efc45b2020-12-22 16:25:44 +010093 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Missing mandatory prefix for XML metadata \"%.*s\".",
Radek Krejci422afb12021-03-04 16:38:16 +010094 (int)xmlctx->name_len, xmlctx->name);
Michal Vasko45791ad2021-06-17 08:45:03 +020095 ret = LY_EVALID;
Michal Vaskob36053d2020-03-26 15:49:30 +010096 goto cleanup;
Radek Krejci28681fa2019-09-06 13:08:45 +020097 }
Michal Vaskob36053d2020-03-26 15:49:30 +010098
Michal Vasko45791ad2021-06-17 08:45:03 +020099 /* skip attr */
Michal Vaskob36053d2020-03-26 15:49:30 +0100100 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
101 assert(xmlctx->status == LYXML_ATTR_CONTENT);
102 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Radek Krejci28681fa2019-09-06 13:08:45 +0200103 continue;
104 }
105
106 /* get namespace of the attribute to find its annotation definition */
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200107 ns = lyxml_ns_get(&xmlctx->ns, xmlctx->prefix, xmlctx->prefix_len);
Radek Krejci28681fa2019-09-06 13:08:45 +0200108 if (!ns) {
Michal Vasko52927e22020-03-16 17:26:14 +0100109 /* unknown namespace, XML error */
Radek Krejci422afb12021-03-04 16:38:16 +0100110 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)xmlctx->prefix_len, xmlctx->prefix);
Michal Vasko45791ad2021-06-17 08:45:03 +0200111 ret = LY_ENOTFOUND;
Radek Krejci28681fa2019-09-06 13:08:45 +0200112 goto cleanup;
113 }
Michal Vasko45791ad2021-06-17 08:45:03 +0200114
115 /* get the module with metadata definition */
Michal Vasko52927e22020-03-16 17:26:14 +0100116 mod = ly_ctx_get_module_implemented_ns(xmlctx->ctx, ns->uri);
Radek Krejci28681fa2019-09-06 13:08:45 +0200117 if (!mod) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100118 if (lydctx->parse_opts & LYD_PARSE_STRICT) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100119 LOGVAL(xmlctx->ctx, LYVE_REFERENCE,
Michal Vasko69730152020-10-09 16:30:07 +0200120 "Unknown (or not implemented) YANG module with namespace \"%s\" for metadata \"%.*s%s%.*s\".",
Radek Krejci422afb12021-03-04 16:38:16 +0100121 ns->uri, (int)xmlctx->prefix_len, xmlctx->prefix, xmlctx->prefix_len ? ":" : "",
122 (int)xmlctx->name_len, xmlctx->name);
Michal Vasko45791ad2021-06-17 08:45:03 +0200123 ret = LY_ENOTFOUND;
Michal Vaskob36053d2020-03-26 15:49:30 +0100124 goto cleanup;
Radek Krejci28681fa2019-09-06 13:08:45 +0200125 }
Michal Vasko45791ad2021-06-17 08:45:03 +0200126
127 /* skip attr */
128 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
129 assert(xmlctx->status == LYXML_ATTR_CONTENT);
130 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
131 continue;
Radek Krejci28681fa2019-09-06 13:08:45 +0200132 }
133
Michal Vasko45791ad2021-06-17 08:45:03 +0200134create_meta:
Michal Vasko60ea6352020-06-29 13:39:39 +0200135 /* remember meta name and get its content */
Michal Vaskob36053d2020-03-26 15:49:30 +0100136 name = xmlctx->name;
137 name_len = xmlctx->name_len;
138 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
139 assert(xmlctx->status == LYXML_ATTR_CONTENT);
140
141 /* create metadata */
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200142 ret = lyd_parser_create_meta((struct lyd_ctx *)lydctx, NULL, meta, mod, name, name_len, xmlctx->value,
Radek Krejci8df109d2021-04-23 12:19:08 +0200143 xmlctx->value_len, &xmlctx->dynamic, LY_VALUE_XML, &xmlctx->ns, LYD_HINT_DATA);
Radek Krejci1798aae2020-07-14 13:26:06 +0200144 LY_CHECK_GOTO(ret, cleanup);
Michal Vaskob36053d2020-03-26 15:49:30 +0100145
146 /* next attribute */
147 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Radek Krejcie7b95092019-05-15 11:03:07 +0200148 }
Michal Vasko52927e22020-03-16 17:26:14 +0100149
Radek Krejcie7b95092019-05-15 11:03:07 +0200150cleanup:
Michal Vaskob36053d2020-03-26 15:49:30 +0100151 if (ret) {
Michal Vasko3a41dff2020-07-15 14:30:28 +0200152 lyd_free_meta_siblings(*meta);
Michal Vaskob36053d2020-03-26 15:49:30 +0100153 *meta = NULL;
Radek Krejci38d85362019-09-05 16:26:38 +0200154 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200155 return ret;
156}
157
Michal Vasko52927e22020-03-16 17:26:14 +0100158static LY_ERR
Radek Krejci1798aae2020-07-14 13:26:06 +0200159lydxml_attrs(struct lyxml_ctx *xmlctx, struct lyd_attr **attr)
Michal Vasko52927e22020-03-16 17:26:14 +0100160{
161 LY_ERR ret = LY_SUCCESS;
162 const struct lyxml_ns *ns;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100163 void *val_prefix_data;
Radek Krejci8df109d2021-04-23 12:19:08 +0200164 LY_VALUE_FORMAT format;
Radek Krejci1798aae2020-07-14 13:26:06 +0200165 struct lyd_attr *attr2;
Michal Vaskob36053d2020-03-26 15:49:30 +0100166 const char *name, *prefix;
167 size_t name_len, prefix_len;
Michal Vasko52927e22020-03-16 17:26:14 +0100168
169 assert(attr);
Michal Vaskob36053d2020-03-26 15:49:30 +0100170 *attr = NULL;
Michal Vasko52927e22020-03-16 17:26:14 +0100171
Michal Vaskob36053d2020-03-26 15:49:30 +0100172 while (xmlctx->status == LYXML_ATTRIBUTE) {
Michal Vasko52927e22020-03-16 17:26:14 +0100173 ns = NULL;
Michal Vaskob36053d2020-03-26 15:49:30 +0100174 if (xmlctx->prefix_len) {
Michal Vasko52927e22020-03-16 17:26:14 +0100175 /* get namespace of the attribute */
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200176 ns = lyxml_ns_get(&xmlctx->ns, xmlctx->prefix, xmlctx->prefix_len);
Michal Vasko52927e22020-03-16 17:26:14 +0100177 if (!ns) {
Radek Krejci422afb12021-03-04 16:38:16 +0100178 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)xmlctx->prefix_len, xmlctx->prefix);
Michal Vasko52927e22020-03-16 17:26:14 +0100179 ret = LY_EVALID;
180 goto cleanup;
181 }
182 }
183
184 if (*attr) {
185 attr2 = *attr;
186 } else {
187 attr2 = NULL;
188 }
189
Michal Vaskob36053d2020-03-26 15:49:30 +0100190 /* remember attr prefix, name, and get its content */
191 prefix = xmlctx->prefix;
192 prefix_len = xmlctx->prefix_len;
193 name = xmlctx->name;
194 name_len = xmlctx->name_len;
195 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
196 assert(xmlctx->status == LYXML_ATTR_CONTENT);
197
Michal Vasko52927e22020-03-16 17:26:14 +0100198 /* get value prefixes */
Michal Vaskofc2cd072021-02-24 13:17:17 +0100199 val_prefix_data = NULL;
Radek Krejci8df109d2021-04-23 12:19:08 +0200200 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 +0100201 &xmlctx->ns, &format, &val_prefix_data), cleanup);
Michal Vasko52927e22020-03-16 17:26:14 +0100202
203 /* attr2 is always changed to the created attribute */
Michal Vasko501af032020-11-11 20:27:44 +0100204 ret = lyd_create_attr(NULL, &attr2, xmlctx->ctx, name, name_len, prefix, prefix_len, ns ? ns->uri : NULL,
205 ns ? strlen(ns->uri) : 0, xmlctx->value, xmlctx->value_len, &xmlctx->dynamic, format, val_prefix_data, 0);
Michal Vasko52927e22020-03-16 17:26:14 +0100206 LY_CHECK_GOTO(ret, cleanup);
207
208 if (!*attr) {
209 *attr = attr2;
210 }
Michal Vaskob36053d2020-03-26 15:49:30 +0100211
212 /* next attribute */
213 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko52927e22020-03-16 17:26:14 +0100214 }
215
216cleanup:
Michal Vaskob36053d2020-03-26 15:49:30 +0100217 if (ret) {
Radek Krejci011e4aa2020-09-04 15:22:31 +0200218 lyd_free_attr_siblings(xmlctx->ctx, *attr);
Michal Vaskob36053d2020-03-26 15:49:30 +0100219 *attr = NULL;
Michal Vasko52927e22020-03-16 17:26:14 +0100220 }
Michal Vasko52927e22020-03-16 17:26:14 +0100221 return ret;
222}
223
Michal Vasko44685da2020-03-17 15:38:06 +0100224static LY_ERR
Michal Vaskob36053d2020-03-26 15:49:30 +0100225lydxml_check_list(struct lyxml_ctx *xmlctx, const struct lysc_node *list)
Michal Vasko44685da2020-03-17 15:38:06 +0100226{
Michal Vaskob36053d2020-03-26 15:49:30 +0100227 LY_ERR ret = LY_SUCCESS, r;
228 enum LYXML_PARSER_STATUS next;
Michal Vasko44685da2020-03-17 15:38:06 +0100229 struct ly_set key_set = {0};
230 const struct lysc_node *snode;
Michal Vaskob36053d2020-03-26 15:49:30 +0100231 uint32_t i, parents_count;
Michal Vasko44685da2020-03-17 15:38:06 +0100232
233 assert(list && (list->nodetype == LYS_LIST));
234
235 /* get all keys into a set (keys do not have if-features or anything) */
236 snode = NULL;
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100237 while ((snode = lys_getnext(snode, list, NULL, 0)) && (snode->flags & LYS_KEY)) {
Radek Krejci3d92e442020-10-12 12:48:13 +0200238 ret = ly_set_add(&key_set, (void *)snode, 1, NULL);
Radek Krejciba03a5a2020-08-27 14:40:41 +0200239 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100240 }
241
Michal Vasko12d809c2021-03-03 16:34:32 +0100242 /* remember parent count */
243 parents_count = xmlctx->elements.count;
244
Michal Vaskob36053d2020-03-26 15:49:30 +0100245 while (xmlctx->status == LYXML_ELEMENT) {
Michal Vasko44685da2020-03-17 15:38:06 +0100246 /* find key definition */
247 for (i = 0; i < key_set.count; ++i) {
248 snode = (const struct lysc_node *)key_set.objs[i];
Michal Vaskob36053d2020-03-26 15:49:30 +0100249 if (!ly_strncmp(snode->name, xmlctx->name, xmlctx->name_len)) {
Michal Vasko44685da2020-03-17 15:38:06 +0100250 break;
251 }
252 }
Michal Vaskob36053d2020-03-26 15:49:30 +0100253 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100254
255 /* skip attributes */
256 while (xmlctx->status == LYXML_ATTRIBUTE) {
Michal Vaskob36053d2020-03-26 15:49:30 +0100257 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
258 assert(xmlctx->status == LYXML_ATTR_CONTENT);
259 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100260 }
261
Michal Vaskob36053d2020-03-26 15:49:30 +0100262 assert(xmlctx->status == LYXML_ELEM_CONTENT);
263 if (i < key_set.count) {
264 /* validate the value */
Radek Krejci8df109d2021-04-23 12:19:08 +0200265 r = lys_value_validate(NULL, snode, xmlctx->value, xmlctx->value_len, LY_VALUE_XML, &xmlctx->ns);
Michal Vaskob36053d2020-03-26 15:49:30 +0100266 if (!r) {
267 /* key with a valid value, remove from the set */
268 ly_set_rm_index(&key_set, i, NULL);
Michal Vasko44685da2020-03-17 15:38:06 +0100269 }
270 }
271
Michal Vaskob36053d2020-03-26 15:49:30 +0100272 /* parser next */
273 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100274
Michal Vaskob36053d2020-03-26 15:49:30 +0100275 /* skip any children, resursively */
Michal Vasko12d809c2021-03-03 16:34:32 +0100276 while (xmlctx->status == LYXML_ELEMENT) {
277 while (parents_count < xmlctx->elements.count) {
278 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
279 }
280 assert(xmlctx->status == LYXML_ELEM_CLOSE);
Michal Vaskob36053d2020-03-26 15:49:30 +0100281 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
282 }
283
284 /* parser next, but do not parse closing element of the list because it would remove its namespaces */
285 assert(xmlctx->status == LYXML_ELEM_CLOSE);
286 LY_CHECK_GOTO(ret = lyxml_ctx_peek(xmlctx, &next), cleanup);
287 if (next != LYXML_ELEM_CLOSE) {
288 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
289 }
Michal Vasko44685da2020-03-17 15:38:06 +0100290 }
291
292 if (key_set.count) {
Michal Vaskob36053d2020-03-26 15:49:30 +0100293 /* some keys are missing/did not validate */
Michal Vasko44685da2020-03-17 15:38:06 +0100294 ret = LY_ENOT;
Michal Vasko44685da2020-03-17 15:38:06 +0100295 }
296
297cleanup:
298 ly_set_erase(&key_set, NULL);
299 return ret;
300}
301
Michal Vasko5c24ed12021-06-09 09:27:32 +0200302/**
303 * @brief Skip an element with all its descendants.
304 *
305 * @param[in] xmlctx XML parser context.
306 * @return LY_ERR value.
307 */
Michal Vasko1bf09392020-03-27 12:38:10 +0100308static LY_ERR
309lydxml_data_skip(struct lyxml_ctx *xmlctx)
310{
311 uint32_t parents_count;
312
313 /* remember current number of parents */
314 parents_count = xmlctx->elements.count;
aPiecek9cdb9e62021-05-18 09:46:20 +0200315 assert(parents_count);
Michal Vasko1bf09392020-03-27 12:38:10 +0100316
317 /* skip after the content */
318 while (xmlctx->status != LYXML_ELEM_CONTENT) {
319 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
320 }
321 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
322
323 /* skip all children elements, recursively, if any */
aPiecek9cdb9e62021-05-18 09:46:20 +0200324 while (parents_count <= xmlctx->elements.count) {
Michal Vasko1bf09392020-03-27 12:38:10 +0100325 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
326 }
327
328 /* close element */
329 assert(xmlctx->status == LYXML_ELEM_CLOSE);
330 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
331
332 return LY_SUCCESS;
333}
334
Michal Vasko5c24ed12021-06-09 09:27:32 +0200335/**
336 * @brief Check that the current element can be parsed as a data node.
337 *
338 * @param[in] lydctx XML data parser context.
339 * @param[in,out] snode Found schema node, set to NULL if data node cannot be created.
340 * @return LY_ERR value.
341 */
Michal Vasko1bf09392020-03-27 12:38:10 +0100342static LY_ERR
Radek Krejci1798aae2020-07-14 13:26:06 +0200343lydxml_data_check_opaq(struct lyd_xml_ctx *lydctx, const struct lysc_node **snode)
Michal Vasko1bf09392020-03-27 12:38:10 +0100344{
345 LY_ERR ret = LY_SUCCESS;
Michal Vaskoda8fbbf2021-06-16 11:44:44 +0200346 struct lyxml_ctx *xmlctx = lydctx->xmlctx, pxmlctx;
Michal Vasko1bf09392020-03-27 12:38:10 +0100347
Radek IÅ¡a3930fd72021-03-08 10:48:40 +0100348 if (!(lydctx->parse_opts & LYD_PARSE_OPAQ)) {
349 /* only checks specific to opaque nodes */
350 return LY_SUCCESS;
351 }
352
Michal Vasko13854662021-06-09 09:27:50 +0200353 if (!((*snode)->nodetype & (LYD_NODE_TERM | LYD_NODE_INNER))) {
354 /* nothing to check */
355 return LY_SUCCESS;
356 }
Michal Vasko1bf09392020-03-27 12:38:10 +0100357
Michal Vaskoda8fbbf2021-06-16 11:44:44 +0200358 assert(xmlctx->elements.count);
359
Michal Vasko13854662021-06-09 09:27:50 +0200360 /* backup parser */
Michal Vaskoda8fbbf2021-06-16 11:44:44 +0200361 LY_CHECK_RET(lyxml_ctx_backup(xmlctx, &pxmlctx));
Michal Vasko1bf09392020-03-27 12:38:10 +0100362
Michal Vasko13854662021-06-09 09:27:50 +0200363 /* skip attributes */
364 while (xmlctx->status == LYXML_ATTRIBUTE) {
365 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), restore);
366 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), restore);
367 }
Michal Vasko1bf09392020-03-27 12:38:10 +0100368
Michal Vasko13854662021-06-09 09:27:50 +0200369 if ((*snode)->nodetype & LYD_NODE_TERM) {
370 /* value may not be valid in which case we parse it as an opaque node */
371 if (lys_value_validate(NULL, *snode, xmlctx->value, xmlctx->value_len, LY_VALUE_XML, &xmlctx->ns)) {
Michal Vaskod0237d42021-07-12 14:49:46 +0200372 LOGVRB("Parsing opaque term node \"%s\" with invalid value \"%.*s\".", (*snode)->name, xmlctx->value_len,
373 xmlctx->value);
Michal Vasko13854662021-06-09 09:27:50 +0200374 *snode = NULL;
Michal Vasko1bf09392020-03-27 12:38:10 +0100375 }
Michal Vasko13854662021-06-09 09:27:50 +0200376 } else if ((*snode)->nodetype == LYS_LIST) {
377 /* skip content */
378 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), restore);
Michal Vasko1bf09392020-03-27 12:38:10 +0100379
Michal Vasko13854662021-06-09 09:27:50 +0200380 if (lydxml_check_list(xmlctx, *snode)) {
381 /* invalid list, parse as opaque if it missing/has invalid some keys */
Michal Vaskod0237d42021-07-12 14:49:46 +0200382 LOGVRB("Parsing opaque list node \"%s\" with missing/invalid keys.", (*snode)->name);
Michal Vasko13854662021-06-09 09:27:50 +0200383 *snode = NULL;
Michal Vasko1bf09392020-03-27 12:38:10 +0100384 }
Michal Vasko13854662021-06-09 09:27:50 +0200385 } else {
Radek IÅ¡a3930fd72021-03-08 10:48:40 +0100386 /* if there is a non-WS value, it cannot be parsed as an inner node */
387 assert(xmlctx->status == LYXML_ELEM_CONTENT);
388 if (!xmlctx->ws_only) {
389 *snode = NULL;
390 }
Michal Vasko1bf09392020-03-27 12:38:10 +0100391 }
392
Michal Vasko13854662021-06-09 09:27:50 +0200393restore:
394 /* restore parser */
Michal Vaskoda8fbbf2021-06-16 11:44:44 +0200395 lyxml_ctx_restore(xmlctx, &pxmlctx);
Michal Vasko1bf09392020-03-27 12:38:10 +0100396 return ret;
397}
398
Radek Krejcie7b95092019-05-15 11:03:07 +0200399/**
Michal Vaskoa5da3292020-08-12 13:10:50 +0200400 * @brief Parse XML subtree.
Radek Krejcie7b95092019-05-15 11:03:07 +0200401 *
Michal Vaskob36053d2020-03-26 15:49:30 +0100402 * @param[in] lydctx XML YANG data parser context.
Michal Vaskoe0665742021-02-11 11:08:44 +0100403 * @param[in,out] parent Parent node where the children are inserted. NULL in case of parsing top-level elements.
404 * @param[in,out] first_p Pointer to the first (@p parent or top-level) child. In case there were already some siblings,
405 * this may point to a previously existing node.
406 * @param[in,out] parsed Optional set to add all the parsed siblings into.
Michal Vasko9b368d32020-02-14 13:53:31 +0100407 * @return LY_ERR value.
Radek Krejcie7b95092019-05-15 11:03:07 +0200408 */
409static LY_ERR
Michal Vaskoe0665742021-02-11 11:08:44 +0100410lydxml_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 +0200411{
Michal Vaskob36053d2020-03-26 15:49:30 +0100412 LY_ERR ret = LY_SUCCESS;
Michal Vasko27c4dce2021-03-04 15:50:50 +0100413 const char *prefix, *name, *val;
Michal Vasko1bf09392020-03-27 12:38:10 +0100414 size_t prefix_len, name_len;
Michal Vaskob36053d2020-03-26 15:49:30 +0100415 struct lyxml_ctx *xmlctx;
416 const struct ly_ctx *ctx;
Radek Krejcie7b95092019-05-15 11:03:07 +0200417 const struct lyxml_ns *ns;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200418 struct lyd_meta *meta = NULL;
419 struct lyd_attr *attr = NULL;
Radek Krejcie7b95092019-05-15 11:03:07 +0200420 const struct lysc_node *snode;
421 struct lys_module *mod;
Michal Vaskoa98e3ea2021-06-03 09:13:33 +0200422 uint32_t prev_parse_opts, prev_int_opts;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200423 struct lyd_node *node = NULL, *anchor;
Michal Vaskofc2cd072021-02-24 13:17:17 +0100424 void *val_prefix_data = NULL;
Radek Krejci8df109d2021-04-23 12:19:08 +0200425 LY_VALUE_FORMAT format;
Radek Krejci1deb5be2020-08-26 16:43:36 +0200426 uint32_t getnext_opts;
Radek Krejcie7b95092019-05-15 11:03:07 +0200427
Michal Vaskoe0665742021-02-11 11:08:44 +0100428 assert(parent || first_p);
429
Michal Vaskob36053d2020-03-26 15:49:30 +0100430 xmlctx = lydctx->xmlctx;
431 ctx = xmlctx->ctx;
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100432 getnext_opts = lydctx->int_opts & LYD_INTOPT_REPLY ? LYS_GETNEXT_OUTPUT : 0;
Michal Vasko6f4cbb62020-02-28 11:15:47 +0100433
Michal Vaskoa5da3292020-08-12 13:10:50 +0200434 assert(xmlctx->status == LYXML_ELEMENT);
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200435
Michal Vaskoa5da3292020-08-12 13:10:50 +0200436 /* remember element prefix and name */
437 prefix = xmlctx->prefix;
438 prefix_len = xmlctx->prefix_len;
439 name = xmlctx->name;
440 name_len = xmlctx->name_len;
441
442 /* get the element module */
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200443 ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200444 if (!ns) {
Radek Krejci422afb12021-03-04 16:38:16 +0100445 LOGVAL(ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)prefix_len, prefix);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200446 ret = LY_EVALID;
447 goto error;
448 }
449 mod = ly_ctx_get_module_implemented_ns(ctx, ns->uri);
450 if (!mod) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100451 if (lydctx->parse_opts & LYD_PARSE_STRICT) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100452 LOGVAL(ctx, LYVE_REFERENCE, "No module with namespace \"%s\" in the context.", ns->uri);
Michal Vasko90932a92020-02-12 14:33:03 +0100453 ret = LY_EVALID;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200454 goto error;
Radek Krejcie7b95092019-05-15 11:03:07 +0200455 }
Michal Vaskoe0665742021-02-11 11:08:44 +0100456 if (!(lydctx->parse_opts & LYD_PARSE_OPAQ)) {
Michal Vaskoa5da3292020-08-12 13:10:50 +0200457 /* skip element with children */
458 LY_CHECK_GOTO(ret = lydxml_data_skip(xmlctx), error);
459 return LY_SUCCESS;
Radek Krejcie7b95092019-05-15 11:03:07 +0200460 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200461 }
462
Michal Vaskoa5da3292020-08-12 13:10:50 +0200463 /* parser next */
464 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
Michal Vasko90932a92020-02-12 14:33:03 +0100465
Michal Vaskoa5da3292020-08-12 13:10:50 +0200466 /* get the schema node */
467 snode = NULL;
468 if (mod && (!parent || parent->schema)) {
Radek Krejcif16e2542021-02-17 15:39:23 +0100469 if (!parent && lydctx->ext) {
Radek Krejciba05eab2021-03-10 13:19:29 +0100470 snode = lysc_ext_find_node(lydctx->ext, mod, name, name_len, 0, getnext_opts);
Radek Krejcif16e2542021-02-17 15:39:23 +0100471 } else {
472 snode = lys_find_child(parent ? parent->schema : NULL, mod, name, name_len, 0, getnext_opts);
473 }
Michal Vaskoa5da3292020-08-12 13:10:50 +0200474 if (!snode) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100475 if (lydctx->parse_opts & LYD_PARSE_STRICT) {
476 if (parent) {
Radek Krejci422afb12021-03-04 16:38:16 +0100477 LOGVAL(ctx, LYVE_REFERENCE, "Node \"%.*s\" not found as a child of \"%s\" node.",
478 (int)name_len, name, parent->schema->name);
Radek Krejcif16e2542021-02-17 15:39:23 +0100479 } else if (lydctx->ext) {
480 if (lydctx->ext->argument) {
Radek Krejci422afb12021-03-04 16:38:16 +0100481 LOGVAL(ctx, LYVE_REFERENCE, "Node \"%.*s\" not found in the \"%s\" %s extension instance.",
482 (int)name_len, name, lydctx->ext->argument, lydctx->ext->def->name);
Radek Krejcif16e2542021-02-17 15:39:23 +0100483 } else {
Radek Krejci422afb12021-03-04 16:38:16 +0100484 LOGVAL(ctx, LYVE_REFERENCE, "Node \"%.*s\" not found in the %s extension instance.",
485 (int)name_len, name, lydctx->ext->def->name);
Radek Krejcif16e2542021-02-17 15:39:23 +0100486 }
Michal Vaskoe0665742021-02-11 11:08:44 +0100487 } else {
Radek Krejci422afb12021-03-04 16:38:16 +0100488 LOGVAL(ctx, LYVE_REFERENCE, "Node \"%.*s\" not found in the \"%s\" module.",
489 (int)name_len, name, mod->name);
Michal Vaskoe0665742021-02-11 11:08:44 +0100490 }
Michal Vaskoa5da3292020-08-12 13:10:50 +0200491 ret = LY_EVALID;
492 goto error;
Michal Vaskoe0665742021-02-11 11:08:44 +0100493 } else if (!(lydctx->parse_opts & LYD_PARSE_OPAQ)) {
Michal Vaskod0237d42021-07-12 14:49:46 +0200494 LOGVRB("Skipping parsing of unkown node \"%.*s\".", name_len, name);
495
Michal Vaskoa5da3292020-08-12 13:10:50 +0200496 /* skip element with children */
497 LY_CHECK_GOTO(ret = lydxml_data_skip(xmlctx), error);
498 return LY_SUCCESS;
499 }
500 } else {
501 /* check that schema node is valid and can be used */
502 LY_CHECK_GOTO(ret = lyd_parser_check_schema((struct lyd_ctx *)lydctx, snode), error);
503 LY_CHECK_GOTO(ret = lydxml_data_check_opaq(lydctx, &snode), error);
504 }
505 }
506
507 /* create metadata/attributes */
508 if (xmlctx->status == LYXML_ATTRIBUTE) {
509 if (snode) {
Michal Vasko45791ad2021-06-17 08:45:03 +0200510 ret = lydxml_metadata(lydctx, snode->exts, &meta);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200511 LY_CHECK_GOTO(ret, error);
512 } else {
Michal Vaskoe0665742021-02-11 11:08:44 +0100513 assert(lydctx->parse_opts & LYD_PARSE_OPAQ);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200514 ret = lydxml_attrs(xmlctx, &attr);
515 LY_CHECK_GOTO(ret, error);
516 }
517 }
518
519 assert(xmlctx->status == LYXML_ELEM_CONTENT);
520 if (!snode) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100521 assert(lydctx->parse_opts & LYD_PARSE_OPAQ);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200522
523 if (xmlctx->ws_only) {
524 /* ignore WS-only value */
Radek IÅ¡a017270d2021-02-16 10:26:15 +0100525 if (xmlctx->dynamic) {
526 free((char *) xmlctx->value);
527 }
528 xmlctx->dynamic = 0;
529 xmlctx->value = "";
Michal Vaskoa5da3292020-08-12 13:10:50 +0200530 xmlctx->value_len = 0;
Radek Krejci8df109d2021-04-23 12:19:08 +0200531 format = LY_VALUE_XML;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200532 } else {
533 /* get value prefixes */
Radek Krejci8df109d2021-04-23 12:19:08 +0200534 ret = ly_store_prefix_data(xmlctx->ctx, xmlctx->value, xmlctx->value_len, LY_VALUE_XML,
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100535 &xmlctx->ns, &format, &val_prefix_data);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200536 LY_CHECK_GOTO(ret, error);
537 }
538
Michal Vaskoda8fbbf2021-06-16 11:44:44 +0200539 /* get NS again, it may have been backed up and restored */
540 ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
541 assert(ns);
542
Michal Vaskoa5da3292020-08-12 13:10:50 +0200543 /* create node */
Michal Vasko501af032020-11-11 20:27:44 +0100544 ret = lyd_create_opaq(ctx, name, name_len, prefix, prefix_len, ns->uri, strlen(ns->uri), xmlctx->value,
545 xmlctx->value_len, &xmlctx->dynamic, format, val_prefix_data, LYD_HINT_DATA, &node);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200546 LY_CHECK_GOTO(ret, error);
547
548 /* parser next */
549 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
550
551 /* process children */
552 while (xmlctx->status == LYXML_ELEMENT) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100553 ret = lydxml_subtree_r(lydctx, node, lyd_node_child_p(node), NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200554 LY_CHECK_GOTO(ret, error);
555 }
556 } else if (snode->nodetype & LYD_NODE_TERM) {
557 /* create node */
Michal Vasko22df3f02020-08-24 13:29:22 +0200558 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 +0200559 &xmlctx->dynamic, LY_VALUE_XML, &xmlctx->ns, LYD_HINT_DATA, &node), error);
Radek Krejciddace2c2021-01-08 11:30:56 +0100560 LOG_LOCSET(snode, node, NULL, NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200561
562 if (parent && (node->schema->flags & LYS_KEY)) {
563 /* check the key order, the anchor must never be a key */
Michal Vaskoe0665742021-02-11 11:08:44 +0100564 anchor = lyd_insert_get_next_anchor(lyd_child(parent), node);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200565 if (anchor && (anchor->schema->flags & LYS_KEY)) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100566 if (lydctx->parse_opts & LYD_PARSE_STRICT) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100567 LOGVAL(ctx, LYVE_DATA, "Invalid position of the key \"%s\" in a list.", node->schema->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200568 ret = LY_EVALID;
569 goto error;
570 } else {
571 LOGWRN(ctx, "Invalid position of the key \"%s\" in a list.", node->schema->name);
572 }
573 }
574 }
575
576 /* parser next */
577 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
578
579 /* no children expected */
580 if (xmlctx->status == LYXML_ELEMENT) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100581 LOGVAL(ctx, LYVE_SYNTAX, "Child element \"%.*s\" inside a terminal node \"%s\" found.",
Radek Krejci422afb12021-03-04 16:38:16 +0100582 (int)xmlctx->name_len, xmlctx->name, snode->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200583 ret = LY_EVALID;
584 goto error;
585 }
586 } else if (snode->nodetype & LYD_NODE_INNER) {
587 if (!xmlctx->ws_only) {
588 /* value in inner node */
Radek Krejci2efc45b2020-12-22 16:25:44 +0100589 LOGVAL(ctx, LYVE_SYNTAX, "Text value \"%.*s\" inside an inner node \"%s\" found.",
Radek Krejci422afb12021-03-04 16:38:16 +0100590 (int)xmlctx->value_len, xmlctx->value, snode->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200591 ret = LY_EVALID;
592 goto error;
593 }
594
595 /* create node */
596 ret = lyd_create_inner(snode, &node);
597 LY_CHECK_GOTO(ret, error);
598
Radek Krejciddace2c2021-01-08 11:30:56 +0100599 LOG_LOCSET(snode, node, NULL, NULL);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100600
Michal Vaskoa5da3292020-08-12 13:10:50 +0200601 /* parser next */
602 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
603
604 /* process children */
605 while (xmlctx->status == LYXML_ELEMENT) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100606 ret = lydxml_subtree_r(lydctx, node, lyd_node_child_p(node), NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200607 LY_CHECK_GOTO(ret, error);
608 }
609
610 if (snode->nodetype == LYS_LIST) {
611 /* check all keys exist */
612 LY_CHECK_GOTO(ret = lyd_parse_check_keys(node), error);
613 }
614
Michal Vaskoe0665742021-02-11 11:08:44 +0100615 if (!(lydctx->parse_opts & LYD_PARSE_ONLY)) {
Michal Vaskoa5da3292020-08-12 13:10:50 +0200616 /* new node validation, autodelete CANNOT occur, all nodes are new */
Michal Vaskoe0665742021-02-11 11:08:44 +0100617 ret = lyd_validate_new(lyd_node_child_p(node), snode, NULL, NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200618 LY_CHECK_GOTO(ret, error);
619
620 /* add any missing default children */
Radek Krejci4f2e3e52021-03-30 14:20:28 +0200621 ret = lyd_new_implicit_r(node, lyd_node_child_p(node), NULL, NULL, &lydctx->node_when, &lydctx->node_exts,
622 &lydctx->node_types, (lydctx->val_opts & LYD_VALIDATE_NO_STATE) ? LYD_IMPLICIT_NO_STATE : 0, NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200623 LY_CHECK_GOTO(ret, error);
624 }
625
626 if (snode->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) {
627 /* rememeber the RPC/action/notification */
628 lydctx->op_node = node;
629 }
630 } else if (snode->nodetype & LYD_NODE_ANY) {
Michal Vasko27c4dce2021-03-04 15:50:50 +0100631 if ((snode->nodetype == LYS_ANYDATA) && !xmlctx->ws_only) {
632 /* value in anydata node, we expect a tree */
633 LOGVAL(ctx, LYVE_SYNTAX, "Text value \"%.*s\" inside an anydata node \"%s\" found.",
Radek Krejci422afb12021-03-04 16:38:16 +0100634 (int)xmlctx->value_len < 20 ? xmlctx->value_len : 20, xmlctx->value, snode->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200635 ret = LY_EVALID;
636 goto error;
637 }
638
Michal Vasko27c4dce2021-03-04 15:50:50 +0100639 if (!xmlctx->ws_only) {
640 /* use an arbitrary text value for anyxml */
641 lydict_insert(xmlctx->ctx, xmlctx->value, xmlctx->value_len, &val);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200642
Michal Vasko27c4dce2021-03-04 15:50:50 +0100643 /* parser next */
644 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
645
646 /* create node */
647 ret = lyd_create_any(snode, val, LYD_ANYDATA_STRING, 1, &node);
648 LY_CHECK_GOTO(ret, error);
649 } else {
650 /* parser next */
651 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
652
Michal Vaskoa98e3ea2021-06-03 09:13:33 +0200653 /* update options so that generic data can be parsed */
654 prev_parse_opts = lydctx->parse_opts;
Michal Vasko27c4dce2021-03-04 15:50:50 +0100655 lydctx->parse_opts &= ~LYD_PARSE_STRICT;
656 lydctx->parse_opts |= LYD_PARSE_OPAQ;
Michal Vaskoa98e3ea2021-06-03 09:13:33 +0200657 prev_int_opts = lydctx->int_opts;
Michal Vasko02ed9d82021-07-15 14:58:04 +0200658 lydctx->int_opts |= LYD_INTOPT_ANY | LYD_INTOPT_WITH_SIBLINGS;
Michal Vaskoa98e3ea2021-06-03 09:13:33 +0200659
660 /* parse any data tree */
Michal Vasko27c4dce2021-03-04 15:50:50 +0100661 anchor = NULL;
662 while (xmlctx->status == LYXML_ELEMENT) {
663 ret = lydxml_subtree_r(lydctx, NULL, &anchor, NULL);
Michal Vaskoa98e3ea2021-06-03 09:13:33 +0200664 if (ret) {
665 break;
666 }
Michal Vasko27c4dce2021-03-04 15:50:50 +0100667 }
Michal Vaskoa98e3ea2021-06-03 09:13:33 +0200668
669 /* restore options */
670 lydctx->parse_opts = prev_parse_opts;
671 lydctx->int_opts = prev_int_opts;
672
673 LY_CHECK_GOTO(ret, error);
Michal Vasko27c4dce2021-03-04 15:50:50 +0100674
675 /* create node */
676 ret = lyd_create_any(snode, anchor, LYD_ANYDATA_DATATREE, 1, &node);
677 LY_CHECK_GOTO(ret, error);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200678 }
Michal Vaskoa5da3292020-08-12 13:10:50 +0200679 }
680 assert(node);
681
682 /* add/correct flags */
683 if (snode) {
Radek Krejci4f2e3e52021-03-30 14:20:28 +0200684 lyd_parse_set_data_flags(node, &lydctx->node_when, &lydctx->node_exts, &meta, lydctx->parse_opts);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200685 }
686
687 /* parser next */
688 assert(xmlctx->status == LYXML_ELEM_CLOSE);
689 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
690
691 /* add metadata/attributes */
692 if (snode) {
Michal Vasko871a0252020-11-11 18:35:24 +0100693 lyd_insert_meta(node, meta, 0);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200694 } else {
695 lyd_insert_attr(node, attr);
696 }
697
698 /* insert, keep first pointer correct */
Michal Vaskoe0665742021-02-11 11:08:44 +0100699 lyd_insert_node(parent, first_p, node);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200700 while (!parent && (*first_p)->prev->next) {
701 *first_p = (*first_p)->prev;
702 }
703
Michal Vaskoe0665742021-02-11 11:08:44 +0100704 /* rememeber a successfully parsed node */
705 if (parsed) {
706 ly_set_add(parsed, node, 1, NULL);
707 }
708
Radek Krejciddace2c2021-01-08 11:30:56 +0100709 LOG_LOCBACK(node ? 1 : 0, node ? 1 : 0, 0, 0);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200710 return LY_SUCCESS;
711
712error:
Radek Krejciddace2c2021-01-08 11:30:56 +0100713 LOG_LOCBACK(node ? 1 : 0, node ? 1 : 0, 0, 0);
Michal Vasko3a41dff2020-07-15 14:30:28 +0200714 lyd_free_meta_siblings(meta);
Radek Krejci011e4aa2020-09-04 15:22:31 +0200715 lyd_free_attr_siblings(ctx, attr);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200716 lyd_free_tree(node);
Radek Krejcie7b95092019-05-15 11:03:07 +0200717 return ret;
718}
719
Michal Vaskoe0665742021-02-11 11:08:44 +0100720/**
721 * @brief Parse a specific XML element into an opaque node.
722 *
723 * @param[in] xmlctx XML parser context.
724 * @param[in] name Name of the element.
725 * @param[in] uri URI of the element.
726 * @param[in] value Whether a value is expected in the element.
727 * @param[out] evnp Parsed envelope (opaque node).
728 * @return LY_SUCCESS on success.
729 * @return LY_ENOT if the specified element did not match.
730 * @return LY_ERR value on error.
731 */
Michal Vasko1bf09392020-03-27 12:38:10 +0100732static LY_ERR
Michal Vaskoe0665742021-02-11 11:08:44 +0100733lydxml_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 +0100734{
Michal Vaskoe0665742021-02-11 11:08:44 +0100735 LY_ERR rc = LY_SUCCESS;
736 const struct lyxml_ns *ns;
Radek Krejci1798aae2020-07-14 13:26:06 +0200737 struct lyd_attr *attr = NULL;
Michal Vasko1bf09392020-03-27 12:38:10 +0100738 const char *prefix;
739 size_t prefix_len;
740
Michal Vasko1bf09392020-03-27 12:38:10 +0100741 assert(xmlctx->status == LYXML_ELEMENT);
742 if (ly_strncmp(name, xmlctx->name, xmlctx->name_len)) {
743 /* not the expected element */
Michal Vaskoe0665742021-02-11 11:08:44 +0100744 return LY_ENOT;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100745 }
746
747 prefix = xmlctx->prefix;
748 prefix_len = xmlctx->prefix_len;
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200749 ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100750 if (!ns) {
Radek Krejci422afb12021-03-04 16:38:16 +0100751 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)prefix_len, prefix);
Michal Vaskoe0665742021-02-11 11:08:44 +0100752 return LY_EVALID;
753 } else if (strcmp(ns->uri, uri)) {
754 /* different namespace */
755 return LY_ENOT;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100756 }
757
758 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
759
760 /* create attributes */
761 if (xmlctx->status == LYXML_ATTRIBUTE) {
762 LY_CHECK_RET(lydxml_attrs(xmlctx, &attr));
763 }
764
Michal Vaskoe0665742021-02-11 11:08:44 +0100765 assert(xmlctx->status == LYXML_ELEM_CONTENT);
766 if (!value && !xmlctx->ws_only) {
767 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected value \"%.*s\" in the \"%s\" element.",
Radek Krejci422afb12021-03-04 16:38:16 +0100768 (int)xmlctx->value_len, xmlctx->value, name);
Michal Vaskoe0665742021-02-11 11:08:44 +0100769 rc = LY_EVALID;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100770 goto cleanup;
Michal Vaskoe0665742021-02-11 11:08:44 +0100771 }
Michal Vaskoa8edff02020-03-27 14:47:01 +0100772
773 /* create node */
Michal Vaskoe0665742021-02-11 11:08:44 +0100774 rc = lyd_create_opaq(xmlctx->ctx, name, strlen(name), prefix, prefix_len, uri, strlen(uri), xmlctx->value,
Radek Krejci8df109d2021-04-23 12:19:08 +0200775 xmlctx->ws_only ? 0 : xmlctx->value_len, NULL, LY_VALUE_XML, NULL, 0, envp);
Michal Vaskoe0665742021-02-11 11:08:44 +0100776 LY_CHECK_GOTO(rc, cleanup);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100777
778 /* assign atributes */
Michal Vaskoe0665742021-02-11 11:08:44 +0100779 ((struct lyd_node_opaq *)(*envp))->attr = attr;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100780 attr = NULL;
781
Michal Vaskoe0665742021-02-11 11:08:44 +0100782 /* parser next element */
783 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100784
Michal Vaskoe0665742021-02-11 11:08:44 +0100785cleanup:
786 lyd_free_attr_siblings(xmlctx->ctx, attr);
787 if (rc) {
788 lyd_free_tree(*envp);
789 *envp = NULL;
790 }
791 return rc;
792}
793
794/**
795 * @brief Parse all expected non-data XML elements of a NETCONF rpc message.
796 *
797 * @param[in] xmlctx XML parser context.
798 * @param[out] evnp Parsed envelope(s) (opaque node).
799 * @param[out] int_opts Internal options for parsing the rest of YANG data.
800 * @param[out] close_elem Number of parsed opened elements that need to be closed.
801 * @return LY_SUCCESS on success.
802 * @return LY_ERR value on error.
803 */
804static LY_ERR
805lydxml_env_netconf_rpc(struct lyxml_ctx *xmlctx, struct lyd_node **envp, uint32_t *int_opts, uint32_t *close_elem)
806{
807 LY_ERR rc = LY_SUCCESS, r;
808 struct lyd_node *child;
809
810 assert(envp && !*envp);
811
812 /* parse "rpc" */
813 r = lydxml_envelope(xmlctx, "rpc", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, envp);
Michal Vaskoe0665742021-02-11 11:08:44 +0100814 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
815
816 /* parse "action", if any */
817 r = lydxml_envelope(xmlctx, "action", "urn:ietf:params:xml:ns:yang:1", 0, &child);
818 if (r == LY_SUCCESS) {
819 /* insert */
820 lyd_insert_node(*envp, NULL, child);
821
822 /* NETCONF action */
823 *int_opts = LYD_INTOPT_NO_SIBLINGS | LYD_INTOPT_ACTION;
824 *close_elem = 2;
825 } else if (r == LY_ENOT) {
826 /* NETCONF RPC */
827 *int_opts = LYD_INTOPT_NO_SIBLINGS | LYD_INTOPT_RPC;
828 *close_elem = 1;
829 } else {
830 rc = r;
831 goto cleanup;
832 }
833
834cleanup:
835 if (rc) {
836 lyd_free_tree(*envp);
837 *envp = NULL;
838 }
839 return rc;
840}
841
842/**
843 * @brief Parse all expected non-data XML elements of a NETCONF notification message.
844 *
845 * @param[in] xmlctx XML parser context.
846 * @param[out] evnp Parsed envelope(s) (opaque node).
847 * @param[out] int_opts Internal options for parsing the rest of YANG data.
848 * @param[out] close_elem Number of parsed opened elements that need to be closed.
849 * @return LY_SUCCESS on success.
850 * @return LY_ERR value on error.
851 */
852static LY_ERR
853lydxml_env_netconf_notif(struct lyxml_ctx *xmlctx, struct lyd_node **envp, uint32_t *int_opts, uint32_t *close_elem)
854{
855 LY_ERR rc = LY_SUCCESS, r;
856 struct lyd_node *child;
857
858 assert(envp && !*envp);
859
860 /* parse "notification" */
861 r = lydxml_envelope(xmlctx, "notification", "urn:ietf:params:xml:ns:netconf:notification:1.0", 0, envp);
Michal Vaskoe0665742021-02-11 11:08:44 +0100862 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
863
864 /* parse "eventTime" */
865 r = lydxml_envelope(xmlctx, "eventTime", "urn:ietf:params:xml:ns:netconf:notification:1.0", 1, &child);
866 if (r == LY_ENOT) {
Radek Krejci422afb12021-03-04 16:38:16 +0100867 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unexpected element \"%.*s\" instead of \"eventTime\".",
868 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +0100869 r = LY_EVALID;
870 }
871 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
872
873 /* insert */
874 lyd_insert_node(*envp, NULL, child);
875
876 /* validate value */
877 /* TODO validate child->value as yang:date-and-time */
878
879 /* finish child parsing */
Michal Vaskoa8edff02020-03-27 14:47:01 +0100880 if (xmlctx->status != LYXML_ELEM_CLOSE) {
881 assert(xmlctx->status == LYXML_ELEMENT);
Michal Vaskoe0665742021-02-11 11:08:44 +0100882 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"eventTime\".",
Radek Krejci422afb12021-03-04 16:38:16 +0100883 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +0100884 rc = LY_EVALID;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100885 goto cleanup;
886 }
Michal Vaskoe0665742021-02-11 11:08:44 +0100887 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
888
889 /* NETCONF notification */
890 *int_opts = LYD_INTOPT_NO_SIBLINGS | LYD_INTOPT_NOTIF;
891 *close_elem = 1;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100892
893cleanup:
Michal Vaskoe0665742021-02-11 11:08:44 +0100894 if (rc) {
Michal Vaskoa8edff02020-03-27 14:47:01 +0100895 lyd_free_tree(*envp);
Michal Vaskoe0665742021-02-11 11:08:44 +0100896 *envp = NULL;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100897 }
Michal Vaskoe0665742021-02-11 11:08:44 +0100898 return rc;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100899}
Michal Vasko79135ae2020-12-16 10:08:35 +0100900
Michal Vaskoe0665742021-02-11 11:08:44 +0100901/**
902 * @brief Parse an XML element as an opaque node subtree.
903 *
904 * @param[in] xmlctx XML parser context.
905 * @param[in] parent Parent to append nodes to.
906 * @return LY_ERR value.
907 */
908static LY_ERR
909lydxml_opaq_r(struct lyxml_ctx *xmlctx, struct lyd_node *parent)
Michal Vaskoa8edff02020-03-27 14:47:01 +0100910{
Michal Vaskoe0665742021-02-11 11:08:44 +0100911 LY_ERR rc = LY_SUCCESS;
912 const struct lyxml_ns *ns;
913 struct lyd_attr *attr = NULL;
914 struct lyd_node *child = NULL;
915 const char *name, *prefix;
916 size_t name_len, prefix_len;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100917
Michal Vaskoe0665742021-02-11 11:08:44 +0100918 assert(xmlctx->status == LYXML_ELEMENT);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100919
Michal Vaskoe0665742021-02-11 11:08:44 +0100920 name = xmlctx->name;
921 name_len = xmlctx->name_len;
922 prefix = xmlctx->prefix;
923 prefix_len = xmlctx->prefix_len;
924 ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
925 if (!ns) {
Radek Krejci422afb12021-03-04 16:38:16 +0100926 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)prefix_len, prefix);
Michal Vaskoe0665742021-02-11 11:08:44 +0100927 return LY_EVALID;
928 }
Michal Vaskoa8edff02020-03-27 14:47:01 +0100929
Michal Vaskoe0665742021-02-11 11:08:44 +0100930 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
Michal Vaskoa8edff02020-03-27 14:47:01 +0100931
Michal Vaskoe0665742021-02-11 11:08:44 +0100932 /* create attributes */
933 if (xmlctx->status == LYXML_ATTRIBUTE) {
934 LY_CHECK_RET(lydxml_attrs(xmlctx, &attr));
935 }
936
937 /* create node */
938 assert(xmlctx->status == LYXML_ELEM_CONTENT);
939 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 +0200940 xmlctx->ws_only ? 0 : xmlctx->value_len, NULL, LY_VALUE_XML, NULL, 0, &child);
Michal Vaskoe0665742021-02-11 11:08:44 +0100941 LY_CHECK_GOTO(rc, cleanup);
942
943 /* assign atributes */
944 ((struct lyd_node_opaq *)child)->attr = attr;
945 attr = NULL;
946
947 /* parser next element */
948 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
949
950 /* parse all the descendants */
951 while (xmlctx->status == LYXML_ELEMENT) {
952 rc = lydxml_opaq_r(xmlctx, child);
953 LY_CHECK_GOTO(rc, cleanup);
954 }
955
956 /* insert */
957 lyd_insert_node(parent, NULL, child);
958
959cleanup:
960 lyd_free_attr_siblings(xmlctx->ctx, attr);
961 if (rc) {
962 lyd_free_tree(child);
963 }
964 return rc;
965}
966
967/**
968 * @brief Parse all expected non-data XML elements of the error-info element in NETCONF rpc-reply message.
969 *
970 * @param[in] xmlctx XML parser context.
971 * @param[in] parent Parent to append nodes to.
972 * @return LY_ERR value.
973 */
974static LY_ERR
975lydxml_env_netconf_rpc_reply_error_info(struct lyxml_ctx *xmlctx, struct lyd_node *parent)
976{
977 LY_ERR r;
978 struct lyd_node *child, *iter;
979 const struct lyxml_ns *ns;
980 ly_bool no_dup;
981
982 /* there must be some child */
983 if (xmlctx->status == LYXML_ELEM_CLOSE) {
984 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Missing child elements of \"error-info\".");
985 return LY_EVALID;
986 }
987
988 while (xmlctx->status == LYXML_ELEMENT) {
989 child = NULL;
990
991 /*
992 * session-id
993 */
994 r = lydxml_envelope(xmlctx, "session-id", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
995 if (r == LY_SUCCESS) {
996 no_dup = 1;
997 goto check_child;
998 } else if (r != LY_ENOT) {
999 goto error;
1000 }
1001
1002 /*
1003 * bad-attribute
1004 */
1005 r = lydxml_envelope(xmlctx, "bad-attribute", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1006 if (r == LY_SUCCESS) {
1007 no_dup = 1;
1008 goto check_child;
1009 } else if (r != LY_ENOT) {
1010 goto error;
1011 }
1012
1013 /*
1014 * bad-element
1015 */
1016 r = lydxml_envelope(xmlctx, "bad-element", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1017 if (r == LY_SUCCESS) {
1018 no_dup = 1;
1019 goto check_child;
1020 } else if (r != LY_ENOT) {
1021 goto error;
1022 }
1023
1024 /*
1025 * bad-namespace
1026 */
1027 r = lydxml_envelope(xmlctx, "bad-namespace", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1028 if (r == LY_SUCCESS) {
1029 no_dup = 1;
1030 goto check_child;
1031 } else if (r != LY_ENOT) {
1032 goto error;
1033 }
1034
1035 if (r == LY_ENOT) {
1036 assert(xmlctx->status == LYXML_ELEMENT);
1037
1038 /* learn namespace */
1039 ns = lyxml_ns_get(&xmlctx->ns, xmlctx->prefix, xmlctx->prefix_len);
1040 if (!ns) {
Radek Krejci422afb12021-03-04 16:38:16 +01001041 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)xmlctx->prefix_len, xmlctx->prefix);
Michal Vaskoe0665742021-02-11 11:08:44 +01001042 r = LY_EVALID;
1043 goto error;
1044 } else if (!strcmp(ns->uri, "urn:ietf:params:xml:ns:netconf:base:1.0")) {
1045 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"error-info\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001046 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001047 r = LY_EVALID;
1048 goto error;
1049 }
1050
1051 /* custom elements */
1052 r = lydxml_opaq_r(xmlctx, parent);
1053 LY_CHECK_GOTO(r, error);
1054
1055 no_dup = 0;
1056 }
1057
1058check_child:
1059 /* check for duplicates */
1060 if (no_dup) {
1061 LY_LIST_FOR(lyd_child(parent), iter) {
1062 if ((((struct lyd_node_opaq *)iter)->name.name == ((struct lyd_node_opaq *)child)->name.name) &&
1063 (((struct lyd_node_opaq *)iter)->name.module_ns == ((struct lyd_node_opaq *)child)->name.module_ns)) {
1064 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Duplicate element \"%s\" in \"error-info\".",
1065 ((struct lyd_node_opaq *)child)->name.name);
1066 r = LY_EVALID;
1067 goto error;
1068 }
1069 }
1070 }
1071
1072 /* finish child parsing */
1073 if (xmlctx->status != LYXML_ELEM_CLOSE) {
1074 assert(xmlctx->status == LYXML_ELEMENT);
1075 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"error-info\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001076 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001077 r = LY_EVALID;
1078 goto error;
1079 }
1080 LY_CHECK_GOTO(r = lyxml_ctx_next(xmlctx), error);
1081
1082 /* insert */
1083 lyd_insert_node(parent, NULL, child);
1084 }
1085
1086 return LY_SUCCESS;
1087
1088error:
1089 lyd_free_tree(child);
1090 return r;
1091}
1092
1093/**
1094 * @brief Parse all expected non-data XML elements of the rpc-error element in NETCONF rpc-reply message.
1095 *
1096 * @param[in] xmlctx XML parser context.
1097 * @param[in] parent Parent to append nodes to.
1098 * @return LY_ERR value.
1099 */
1100static LY_ERR
1101lydxml_env_netconf_rpc_reply_error(struct lyxml_ctx *xmlctx, struct lyd_node *parent)
1102{
1103 LY_ERR r;
1104 struct lyd_node *child, *iter;
1105 const char *val;
1106 ly_bool no_dup;
1107
1108 /* there must be some child */
1109 if (xmlctx->status == LYXML_ELEM_CLOSE) {
1110 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Missing child elements of \"rpc-error\".");
1111 return LY_EVALID;
1112 }
1113
1114 while (xmlctx->status == LYXML_ELEMENT) {
1115 child = NULL;
1116
1117 /*
1118 * error-type
1119 */
1120 r = lydxml_envelope(xmlctx, "error-type", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1121 if (r == LY_SUCCESS) {
1122 val = ((struct lyd_node_opaq *)child)->value;
1123 if (strcmp(val, "transport") && strcmp(val, "rpc") && strcmp(val, "protocol") && strcmp(val, "application")) {
1124 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Invalid value \"%s\" of element \"%s\".", val,
1125 ((struct lyd_node_opaq *)child)->name.name);
1126 r = LY_EVALID;
1127 goto error;
1128 }
1129
1130 no_dup = 1;
1131 goto check_child;
1132 } else if (r != LY_ENOT) {
1133 goto error;
1134 }
1135
1136 /*
1137 * error-tag
1138 */
1139 r = lydxml_envelope(xmlctx, "error-tag", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1140 if (r == LY_SUCCESS) {
1141 val = ((struct lyd_node_opaq *)child)->value;
1142 if (strcmp(val, "in-use") && strcmp(val, "invalid-value") && strcmp(val, "too-big") &&
1143 strcmp(val, "missing-attribute") && strcmp(val, "bad-attribute") &&
1144 strcmp(val, "unknown-attribute") && strcmp(val, "missing-element") && strcmp(val, "bad-element") &&
1145 strcmp(val, "unknown-element") && strcmp(val, "unknown-namespace") && strcmp(val, "access-denied") &&
1146 strcmp(val, "lock-denied") && strcmp(val, "resource-denied") && strcmp(val, "rollback-failed") &&
1147 strcmp(val, "data-exists") && strcmp(val, "data-missing") && strcmp(val, "operation-not-supported") &&
1148 strcmp(val, "operation-failed") && strcmp(val, "malformed-message")) {
1149 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Invalid value \"%s\" of element \"%s\".", val,
1150 ((struct lyd_node_opaq *)child)->name.name);
1151 r = LY_EVALID;
1152 goto error;
1153 }
1154
1155 no_dup = 1;
1156 goto check_child;
1157 } else if (r != LY_ENOT) {
1158 goto error;
1159 }
1160
1161 /*
1162 * error-severity
1163 */
1164 r = lydxml_envelope(xmlctx, "error-severity", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1165 if (r == LY_SUCCESS) {
1166 val = ((struct lyd_node_opaq *)child)->value;
1167 if (strcmp(val, "error") && strcmp(val, "warning")) {
1168 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Invalid value \"%s\" of element \"%s\".", val,
1169 ((struct lyd_node_opaq *)child)->name.name);
1170 r = LY_EVALID;
1171 goto error;
1172 }
1173
1174 no_dup = 1;
1175 goto check_child;
1176 } else if (r != LY_ENOT) {
1177 goto error;
1178 }
1179
1180 /*
1181 * error-app-tag
1182 */
1183 r = lydxml_envelope(xmlctx, "error-app-tag", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1184 if (r == LY_SUCCESS) {
1185 no_dup = 1;
1186 goto check_child;
1187 } else if (r != LY_ENOT) {
1188 goto error;
1189 }
1190
1191 /*
1192 * error-path
1193 */
1194 r = lydxml_envelope(xmlctx, "error-path", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1195 if (r == LY_SUCCESS) {
1196 no_dup = 1;
1197 goto check_child;
1198 } else if (r != LY_ENOT) {
1199 goto error;
1200 }
1201
1202 /*
1203 * error-message
1204 */
1205 r = lydxml_envelope(xmlctx, "error-message", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1206 if (r == LY_SUCCESS) {
1207 no_dup = 1;
1208 goto check_child;
1209 } else if (r != LY_ENOT) {
1210 goto error;
1211 }
1212
1213 /* error-info */
1214 r = lydxml_envelope(xmlctx, "error-info", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, &child);
1215 if (r == LY_SUCCESS) {
1216 /* parse all the descendants */
1217 LY_CHECK_GOTO(r = lydxml_env_netconf_rpc_reply_error_info(xmlctx, child), error);
1218
1219 no_dup = 0;
1220 goto check_child;
1221 } else if (r != LY_ENOT) {
1222 goto error;
1223 }
1224
1225 if (r == LY_ENOT) {
1226 assert(xmlctx->status == LYXML_ELEMENT);
1227 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"rpc-error\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001228 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001229 r = LY_EVALID;
1230 goto error;
1231 }
1232
1233check_child:
1234 /* check for duplicates */
1235 if (no_dup) {
1236 LY_LIST_FOR(lyd_child(parent), iter) {
1237 if ((((struct lyd_node_opaq *)iter)->name.name == ((struct lyd_node_opaq *)child)->name.name) &&
1238 (((struct lyd_node_opaq *)iter)->name.module_ns == ((struct lyd_node_opaq *)child)->name.module_ns)) {
1239 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Duplicate element \"%s\" in \"rpc-error\".",
1240 ((struct lyd_node_opaq *)child)->name.name);
1241 r = LY_EVALID;
1242 goto error;
1243 }
1244 }
1245 }
1246
1247 /* finish child parsing */
1248 if (xmlctx->status != LYXML_ELEM_CLOSE) {
1249 assert(xmlctx->status == LYXML_ELEMENT);
1250 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"rpc-error\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001251 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001252 r = LY_EVALID;
1253 goto error;
1254 }
1255 LY_CHECK_GOTO(r = lyxml_ctx_next(xmlctx), error);
1256
1257 /* insert */
1258 lyd_insert_node(parent, NULL, child);
1259 }
1260
1261 return LY_SUCCESS;
1262
1263error:
1264 lyd_free_tree(child);
1265 return r;
1266}
1267
1268/**
1269 * @brief Parse all expected non-data XML elements of a NETCONF rpc-reply message.
1270 *
1271 * @param[in] xmlctx XML parser context.
1272 * @param[out] evnp Parsed envelope(s) (opaque node).
1273 * @param[out] int_opts Internal options for parsing the rest of YANG data.
1274 * @param[out] close_elem Number of parsed opened elements that need to be closed.
1275 * @return LY_SUCCESS on success.
1276 * @return LY_ERR value on error.
1277 */
1278static LY_ERR
1279lydxml_env_netconf_reply(struct lyxml_ctx *xmlctx, struct lyd_node **envp, uint32_t *int_opts, uint32_t *close_elem)
1280{
1281 LY_ERR rc = LY_SUCCESS, r;
1282 struct lyd_node *child = NULL;
1283 const char *parsed_elem = NULL;
1284
1285 assert(envp && !*envp);
1286
1287 /* parse "rpc-reply" */
1288 r = lydxml_envelope(xmlctx, "rpc-reply", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, envp);
Michal Vaskoe0665742021-02-11 11:08:44 +01001289 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
1290
1291 /* there must be some child */
1292 if (xmlctx->status == LYXML_ELEM_CLOSE) {
1293 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Missing child elements of \"rpc-reply\".");
1294 rc = LY_EVALID;
Michal Vaskocf770e22020-08-12 13:21:43 +02001295 goto cleanup;
Michal Vaskoa8edff02020-03-27 14:47:01 +01001296 }
1297
Michal Vaskoe0665742021-02-11 11:08:44 +01001298 /* try to parse "ok" */
1299 r = lydxml_envelope(xmlctx, "ok", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, &child);
1300 if (r == LY_SUCCESS) {
1301 /* insert */
1302 lyd_insert_node(*envp, NULL, child);
1303
1304 /* finish child parsing */
1305 if (xmlctx->status != LYXML_ELEM_CLOSE) {
1306 assert(xmlctx->status == LYXML_ELEMENT);
1307 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"ok\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001308 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001309 rc = LY_EVALID;
1310 goto cleanup;
1311 }
1312 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
1313
1314 /* success */
1315 parsed_elem = "ok";
1316 goto finish;
1317 } else if (r != LY_ENOT) {
1318 rc = r;
1319 goto cleanup;
Michal Vasko2552ea32020-12-08 15:32:34 +01001320 }
1321
Michal Vaskoe0665742021-02-11 11:08:44 +01001322 /* try to parse all "rpc-error" elements */
1323 while (xmlctx->status == LYXML_ELEMENT) {
1324 r = lydxml_envelope(xmlctx, "rpc-error", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, &child);
1325 if (r == LY_ENOT) {
1326 break;
1327 } else if (r) {
1328 rc = r;
1329 goto cleanup;
1330 }
1331
1332 /* insert */
1333 lyd_insert_node(*envp, NULL, child);
1334
1335 /* parse all children of "rpc-error" */
1336 LY_CHECK_GOTO(rc = lydxml_env_netconf_rpc_reply_error(xmlctx, child), cleanup);
1337
1338 /* finish child parsing */
1339 assert(xmlctx->status == LYXML_ELEM_CLOSE);
1340 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
1341
1342 parsed_elem = "rpc-error";
Michal Vasko2552ea32020-12-08 15:32:34 +01001343 }
Michal Vaskoe0665742021-02-11 11:08:44 +01001344
1345finish:
1346 if (parsed_elem) {
1347 /* NETCONF rpc-reply with no data */
1348 if (xmlctx->status != LYXML_ELEM_CLOSE) {
1349 assert(xmlctx->status == LYXML_ELEMENT);
1350 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected sibling element \"%.*s\" of \"%s\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001351 (int)xmlctx->name_len, xmlctx->name, parsed_elem);
Michal Vaskoe0665742021-02-11 11:08:44 +01001352 rc = LY_EVALID;
1353 goto cleanup;
1354 }
1355 }
1356
1357 /* NETCONF rpc-reply */
Michal Vasko1d991fd2021-07-09 13:14:40 +02001358 *int_opts = LYD_INTOPT_WITH_SIBLINGS | LYD_INTOPT_REPLY;
Michal Vaskoe0665742021-02-11 11:08:44 +01001359 *close_elem = 1;
1360
1361cleanup:
1362 if (rc) {
1363 lyd_free_tree(*envp);
1364 *envp = NULL;
1365 }
1366 return rc;
1367}
1368
Michal Vasko2552ea32020-12-08 15:32:34 +01001369LY_ERR
Radek Krejcif16e2542021-02-17 15:39:23 +01001370lyd_parse_xml(const struct ly_ctx *ctx, const struct lysc_ext_instance *ext, struct lyd_node *parent,
1371 struct lyd_node **first_p, struct ly_in *in, uint32_t parse_opts, uint32_t val_opts, enum lyd_type data_type,
1372 struct lyd_node **envp, struct ly_set *parsed, struct lyd_ctx **lydctx_p)
Michal Vasko2552ea32020-12-08 15:32:34 +01001373{
Michal Vaskoe0665742021-02-11 11:08:44 +01001374 LY_ERR rc = LY_SUCCESS;
1375 struct lyd_xml_ctx *lydctx;
Michal Vasko2ca9f9e2021-07-02 09:21:36 +02001376 uint32_t i, int_opts = 0, close_elem = 0;
Michal Vaskoe0665742021-02-11 11:08:44 +01001377 ly_bool parsed_data_nodes = 0;
Michal Vasko2552ea32020-12-08 15:32:34 +01001378
Michal Vaskoe0665742021-02-11 11:08:44 +01001379 assert(ctx && in && lydctx_p);
1380 assert(!(parse_opts & ~LYD_PARSE_OPTS_MASK));
1381 assert(!(val_opts & ~LYD_VALIDATE_OPTS_MASK));
Michal Vasko2552ea32020-12-08 15:32:34 +01001382
Michal Vaskoe0665742021-02-11 11:08:44 +01001383 /* init context */
1384 lydctx = calloc(1, sizeof *lydctx);
1385 LY_CHECK_ERR_RET(!lydctx, LOGMEM(ctx), LY_EMEM);
1386 LY_CHECK_GOTO(rc = lyxml_ctx_new(ctx, in, &lydctx->xmlctx), cleanup);
1387 lydctx->parse_opts = parse_opts;
1388 lydctx->val_opts = val_opts;
1389 lydctx->free = lyd_xml_ctx_free;
Radek Krejcif16e2542021-02-17 15:39:23 +01001390 lydctx->ext = ext;
Michal Vasko2552ea32020-12-08 15:32:34 +01001391
Michal Vaskoe0665742021-02-11 11:08:44 +01001392 switch (data_type) {
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001393 case LYD_TYPE_DATA_YANG:
Michal Vaskoe0665742021-02-11 11:08:44 +01001394 int_opts = LYD_INTOPT_WITH_SIBLINGS;
1395 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001396 case LYD_TYPE_RPC_YANG:
Michal Vaskoe0665742021-02-11 11:08:44 +01001397 int_opts = LYD_INTOPT_RPC | LYD_INTOPT_ACTION | LYD_INTOPT_NO_SIBLINGS;
1398 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001399 case LYD_TYPE_NOTIF_YANG:
Michal Vaskoe0665742021-02-11 11:08:44 +01001400 int_opts = LYD_INTOPT_NOTIF | LYD_INTOPT_NO_SIBLINGS;
1401 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001402 case LYD_TYPE_REPLY_YANG:
Michal Vaskoe0665742021-02-11 11:08:44 +01001403 int_opts = LYD_INTOPT_REPLY | LYD_INTOPT_NO_SIBLINGS;
1404 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001405 case LYD_TYPE_RPC_NETCONF:
Michal Vaskoe0665742021-02-11 11:08:44 +01001406 assert(!parent);
1407 LY_CHECK_GOTO(rc = lydxml_env_netconf_rpc(lydctx->xmlctx, envp, &int_opts, &close_elem), cleanup);
1408 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001409 case LYD_TYPE_NOTIF_NETCONF:
1410 assert(!parent);
1411 LY_CHECK_GOTO(rc = lydxml_env_netconf_notif(lydctx->xmlctx, envp, &int_opts, &close_elem), cleanup);
1412 break;
1413 case LYD_TYPE_REPLY_NETCONF:
Michal Vaskoe0665742021-02-11 11:08:44 +01001414 assert(parent);
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001415 LY_CHECK_GOTO(rc = lydxml_env_netconf_reply(lydctx->xmlctx, envp, &int_opts, &close_elem), cleanup);
Michal Vaskoe0665742021-02-11 11:08:44 +01001416 break;
1417 }
1418 lydctx->int_opts = int_opts;
1419
1420 /* find the operation node if it exists already */
1421 LY_CHECK_GOTO(rc = lyd_parser_find_operation(parent, int_opts, &lydctx->op_node), cleanup);
1422
1423 /* parse XML data */
1424 while (lydctx->xmlctx->status == LYXML_ELEMENT) {
1425 LY_CHECK_GOTO(rc = lydxml_subtree_r(lydctx, parent, first_p, parsed), cleanup);
1426 parsed_data_nodes = 1;
1427
1428 if (!(int_opts & LYD_INTOPT_WITH_SIBLINGS)) {
1429 break;
1430 }
Michal Vasko2552ea32020-12-08 15:32:34 +01001431 }
1432
Michal Vaskoe0665742021-02-11 11:08:44 +01001433 /* close all opened elements */
1434 for (i = 0; i < close_elem; ++i) {
1435 if (lydctx->xmlctx->status != LYXML_ELEM_CLOSE) {
1436 assert(lydctx->xmlctx->status == LYXML_ELEMENT);
Radek Krejci422afb12021-03-04 16:38:16 +01001437 LOGVAL(lydctx->xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\".",
1438 (int)lydctx->xmlctx->name_len, lydctx->xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001439 rc = LY_EVALID;
1440 goto cleanup;
1441 }
1442
1443 LY_CHECK_GOTO(rc = lyxml_ctx_next(lydctx->xmlctx), cleanup);
Michal Vasko4189c0f2020-08-13 09:05:22 +02001444 }
Michal Vaskoe0665742021-02-11 11:08:44 +01001445
1446 /* check final state */
1447 if ((int_opts & LYD_INTOPT_NO_SIBLINGS) && (lydctx->xmlctx->status == LYXML_ELEMENT)) {
1448 LOGVAL(ctx, LYVE_SYNTAX, "Unexpected sibling node.");
1449 rc = LY_EVALID;
1450 goto cleanup;
1451 }
1452 if ((int_opts & (LYD_INTOPT_RPC | LYD_INTOPT_NOTIF | LYD_INTOPT_REPLY)) && !lydctx->op_node) {
1453 LOGVAL(ctx, LYVE_DATA, "Missing the operation node.");
1454 rc = LY_EVALID;
1455 goto cleanup;
1456 }
1457
1458 if (!parsed_data_nodes) {
1459 /* no data nodes were parsed */
1460 lydctx->op_node = NULL;
Michal Vaskoa8edff02020-03-27 14:47:01 +01001461 }
1462
1463cleanup:
Michal Vaskoe0665742021-02-11 11:08:44 +01001464 /* there should be no unres stored if validation should be skipped */
1465 assert(!(parse_opts & LYD_PARSE_ONLY) || (!lydctx->node_types.count && !lydctx->meta_types.count &&
Radek Krejci4f2e3e52021-03-30 14:20:28 +02001466 !lydctx->node_when.count && !lydctx->node_exts.count));
Michal Vaskoe0665742021-02-11 11:08:44 +01001467
1468 if (rc) {
1469 lyd_xml_ctx_free((struct lyd_ctx *)lydctx);
1470 } else {
1471 *lydctx_p = (struct lyd_ctx *)lydctx;
1472
1473 /* the XML context is no more needed, freeing it also stops logging line numbers which would be confusing now */
1474 lyxml_ctx_free(lydctx->xmlctx);
1475 lydctx->xmlctx = NULL;
Michal Vasko1ce933a2020-03-30 12:38:22 +02001476 }
Michal Vaskoe0665742021-02-11 11:08:44 +01001477 return rc;
Michal Vasko1ce933a2020-03-30 12:38:22 +02001478}