blob: 0b90d68fac37e9da6a2034222283b2a676e37691 [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)) {
396 *snode = NULL;
Michal Vasko1bf09392020-03-27 12:38:10 +0100397 }
Michal Vasko13854662021-06-09 09:27:50 +0200398 } else if ((*snode)->nodetype == LYS_LIST) {
399 /* skip content */
400 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), restore);
Michal Vasko1bf09392020-03-27 12:38:10 +0100401
Michal Vasko13854662021-06-09 09:27:50 +0200402 if (lydxml_check_list(xmlctx, *snode)) {
403 /* invalid list, parse as opaque if it missing/has invalid some keys */
404 *snode = NULL;
Michal Vasko1bf09392020-03-27 12:38:10 +0100405 }
Michal Vasko13854662021-06-09 09:27:50 +0200406 } else {
Radek IÅ¡a3930fd72021-03-08 10:48:40 +0100407 /* if there is a non-WS value, it cannot be parsed as an inner node */
408 assert(xmlctx->status == LYXML_ELEM_CONTENT);
409 if (!xmlctx->ws_only) {
410 *snode = NULL;
411 }
Michal Vasko1bf09392020-03-27 12:38:10 +0100412 }
413
Michal Vasko13854662021-06-09 09:27:50 +0200414restore:
415 /* restore parser */
Michal Vaskoda8fbbf2021-06-16 11:44:44 +0200416 lyxml_ctx_restore(xmlctx, &pxmlctx);
Michal Vasko1bf09392020-03-27 12:38:10 +0100417 return ret;
418}
419
Radek Krejcie7b95092019-05-15 11:03:07 +0200420/**
Michal Vaskoa5da3292020-08-12 13:10:50 +0200421 * @brief Parse XML subtree.
Radek Krejcie7b95092019-05-15 11:03:07 +0200422 *
Michal Vaskob36053d2020-03-26 15:49:30 +0100423 * @param[in] lydctx XML YANG data parser context.
Michal Vaskoe0665742021-02-11 11:08:44 +0100424 * @param[in,out] parent Parent node where the children are inserted. NULL in case of parsing top-level elements.
425 * @param[in,out] first_p Pointer to the first (@p parent or top-level) child. In case there were already some siblings,
426 * this may point to a previously existing node.
427 * @param[in,out] parsed Optional set to add all the parsed siblings into.
Michal Vasko9b368d32020-02-14 13:53:31 +0100428 * @return LY_ERR value.
Radek Krejcie7b95092019-05-15 11:03:07 +0200429 */
430static LY_ERR
Michal Vaskoe0665742021-02-11 11:08:44 +0100431lydxml_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 +0200432{
Michal Vaskob36053d2020-03-26 15:49:30 +0100433 LY_ERR ret = LY_SUCCESS;
Michal Vasko27c4dce2021-03-04 15:50:50 +0100434 const char *prefix, *name, *val;
Michal Vasko1bf09392020-03-27 12:38:10 +0100435 size_t prefix_len, name_len;
Michal Vaskob36053d2020-03-26 15:49:30 +0100436 struct lyxml_ctx *xmlctx;
437 const struct ly_ctx *ctx;
Radek Krejcie7b95092019-05-15 11:03:07 +0200438 const struct lyxml_ns *ns;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200439 struct lyd_meta *meta = NULL;
440 struct lyd_attr *attr = NULL;
Radek Krejcie7b95092019-05-15 11:03:07 +0200441 const struct lysc_node *snode;
442 struct lys_module *mod;
Michal Vaskoa98e3ea2021-06-03 09:13:33 +0200443 uint32_t prev_parse_opts, prev_int_opts;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200444 struct lyd_node *node = NULL, *anchor;
Michal Vaskofc2cd072021-02-24 13:17:17 +0100445 void *val_prefix_data = NULL;
Radek Krejci8df109d2021-04-23 12:19:08 +0200446 LY_VALUE_FORMAT format;
Radek Krejci1deb5be2020-08-26 16:43:36 +0200447 uint32_t getnext_opts;
Radek Krejcie7b95092019-05-15 11:03:07 +0200448
Michal Vaskoe0665742021-02-11 11:08:44 +0100449 assert(parent || first_p);
450
Michal Vaskob36053d2020-03-26 15:49:30 +0100451 xmlctx = lydctx->xmlctx;
452 ctx = xmlctx->ctx;
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100453 getnext_opts = lydctx->int_opts & LYD_INTOPT_REPLY ? LYS_GETNEXT_OUTPUT : 0;
Michal Vasko6f4cbb62020-02-28 11:15:47 +0100454
Michal Vaskoa5da3292020-08-12 13:10:50 +0200455 assert(xmlctx->status == LYXML_ELEMENT);
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200456
Michal Vaskoa5da3292020-08-12 13:10:50 +0200457 /* remember element prefix and name */
458 prefix = xmlctx->prefix;
459 prefix_len = xmlctx->prefix_len;
460 name = xmlctx->name;
461 name_len = xmlctx->name_len;
462
463 /* get the element module */
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200464 ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200465 if (!ns) {
Radek Krejci422afb12021-03-04 16:38:16 +0100466 LOGVAL(ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)prefix_len, prefix);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200467 ret = LY_EVALID;
468 goto error;
469 }
470 mod = ly_ctx_get_module_implemented_ns(ctx, ns->uri);
471 if (!mod) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100472 if (lydctx->parse_opts & LYD_PARSE_STRICT) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100473 LOGVAL(ctx, LYVE_REFERENCE, "No module with namespace \"%s\" in the context.", ns->uri);
Michal Vasko90932a92020-02-12 14:33:03 +0100474 ret = LY_EVALID;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200475 goto error;
Radek Krejcie7b95092019-05-15 11:03:07 +0200476 }
Michal Vaskoe0665742021-02-11 11:08:44 +0100477 if (!(lydctx->parse_opts & LYD_PARSE_OPAQ)) {
Michal Vaskoa5da3292020-08-12 13:10:50 +0200478 /* skip element with children */
479 LY_CHECK_GOTO(ret = lydxml_data_skip(xmlctx), error);
480 return LY_SUCCESS;
Radek Krejcie7b95092019-05-15 11:03:07 +0200481 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200482 }
483
Michal Vaskoa5da3292020-08-12 13:10:50 +0200484 /* parser next */
485 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
Michal Vasko90932a92020-02-12 14:33:03 +0100486
Michal Vaskoa5da3292020-08-12 13:10:50 +0200487 /* get the schema node */
488 snode = NULL;
489 if (mod && (!parent || parent->schema)) {
Radek Krejcif16e2542021-02-17 15:39:23 +0100490 if (!parent && lydctx->ext) {
Radek Krejciba05eab2021-03-10 13:19:29 +0100491 snode = lysc_ext_find_node(lydctx->ext, mod, name, name_len, 0, getnext_opts);
Radek Krejcif16e2542021-02-17 15:39:23 +0100492 } else {
493 snode = lys_find_child(parent ? parent->schema : NULL, mod, name, name_len, 0, getnext_opts);
494 }
Michal Vaskoa5da3292020-08-12 13:10:50 +0200495 if (!snode) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100496 if (lydctx->parse_opts & LYD_PARSE_STRICT) {
497 if (parent) {
Radek Krejci422afb12021-03-04 16:38:16 +0100498 LOGVAL(ctx, LYVE_REFERENCE, "Node \"%.*s\" not found as a child of \"%s\" node.",
499 (int)name_len, name, parent->schema->name);
Radek Krejcif16e2542021-02-17 15:39:23 +0100500 } else if (lydctx->ext) {
501 if (lydctx->ext->argument) {
Radek Krejci422afb12021-03-04 16:38:16 +0100502 LOGVAL(ctx, LYVE_REFERENCE, "Node \"%.*s\" not found in the \"%s\" %s extension instance.",
503 (int)name_len, name, lydctx->ext->argument, lydctx->ext->def->name);
Radek Krejcif16e2542021-02-17 15:39:23 +0100504 } else {
Radek Krejci422afb12021-03-04 16:38:16 +0100505 LOGVAL(ctx, LYVE_REFERENCE, "Node \"%.*s\" not found in the %s extension instance.",
506 (int)name_len, name, lydctx->ext->def->name);
Radek Krejcif16e2542021-02-17 15:39:23 +0100507 }
Michal Vaskoe0665742021-02-11 11:08:44 +0100508 } else {
Radek Krejci422afb12021-03-04 16:38:16 +0100509 LOGVAL(ctx, LYVE_REFERENCE, "Node \"%.*s\" not found in the \"%s\" module.",
510 (int)name_len, name, mod->name);
Michal Vaskoe0665742021-02-11 11:08:44 +0100511 }
Michal Vaskoa5da3292020-08-12 13:10:50 +0200512 ret = LY_EVALID;
513 goto error;
Michal Vaskoe0665742021-02-11 11:08:44 +0100514 } else if (!(lydctx->parse_opts & LYD_PARSE_OPAQ)) {
Michal Vaskoa5da3292020-08-12 13:10:50 +0200515 /* skip element with children */
516 LY_CHECK_GOTO(ret = lydxml_data_skip(xmlctx), error);
517 return LY_SUCCESS;
518 }
519 } else {
520 /* check that schema node is valid and can be used */
521 LY_CHECK_GOTO(ret = lyd_parser_check_schema((struct lyd_ctx *)lydctx, snode), error);
522 LY_CHECK_GOTO(ret = lydxml_data_check_opaq(lydctx, &snode), error);
523 }
524 }
525
526 /* create metadata/attributes */
527 if (xmlctx->status == LYXML_ATTRIBUTE) {
528 if (snode) {
Michal Vasko45791ad2021-06-17 08:45:03 +0200529 ret = lydxml_metadata(lydctx, snode->exts, &meta);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200530 LY_CHECK_GOTO(ret, error);
531 } else {
Michal Vaskoe0665742021-02-11 11:08:44 +0100532 assert(lydctx->parse_opts & LYD_PARSE_OPAQ);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200533 ret = lydxml_attrs(xmlctx, &attr);
534 LY_CHECK_GOTO(ret, error);
535 }
536 }
537
538 assert(xmlctx->status == LYXML_ELEM_CONTENT);
539 if (!snode) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100540 assert(lydctx->parse_opts & LYD_PARSE_OPAQ);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200541
542 if (xmlctx->ws_only) {
543 /* ignore WS-only value */
Radek IÅ¡a017270d2021-02-16 10:26:15 +0100544 if (xmlctx->dynamic) {
545 free((char *) xmlctx->value);
546 }
547 xmlctx->dynamic = 0;
548 xmlctx->value = "";
Michal Vaskoa5da3292020-08-12 13:10:50 +0200549 xmlctx->value_len = 0;
Radek Krejci8df109d2021-04-23 12:19:08 +0200550 format = LY_VALUE_XML;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200551 } else {
552 /* get value prefixes */
Radek Krejci8df109d2021-04-23 12:19:08 +0200553 ret = ly_store_prefix_data(xmlctx->ctx, xmlctx->value, xmlctx->value_len, LY_VALUE_XML,
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100554 &xmlctx->ns, &format, &val_prefix_data);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200555 LY_CHECK_GOTO(ret, error);
556 }
557
Michal Vaskoda8fbbf2021-06-16 11:44:44 +0200558 /* get NS again, it may have been backed up and restored */
559 ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
560 assert(ns);
561
Michal Vaskoa5da3292020-08-12 13:10:50 +0200562 /* create node */
Michal Vasko501af032020-11-11 20:27:44 +0100563 ret = lyd_create_opaq(ctx, name, name_len, prefix, prefix_len, ns->uri, strlen(ns->uri), xmlctx->value,
564 xmlctx->value_len, &xmlctx->dynamic, format, val_prefix_data, LYD_HINT_DATA, &node);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200565 LY_CHECK_GOTO(ret, error);
566
567 /* parser next */
568 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
569
570 /* process children */
571 while (xmlctx->status == LYXML_ELEMENT) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100572 ret = lydxml_subtree_r(lydctx, node, lyd_node_child_p(node), NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200573 LY_CHECK_GOTO(ret, error);
574 }
575 } else if (snode->nodetype & LYD_NODE_TERM) {
576 /* create node */
Michal Vasko22df3f02020-08-24 13:29:22 +0200577 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 +0200578 &xmlctx->dynamic, LY_VALUE_XML, &xmlctx->ns, LYD_HINT_DATA, &node), error);
Radek Krejciddace2c2021-01-08 11:30:56 +0100579 LOG_LOCSET(snode, node, NULL, NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200580
581 if (parent && (node->schema->flags & LYS_KEY)) {
582 /* check the key order, the anchor must never be a key */
Michal Vaskoe0665742021-02-11 11:08:44 +0100583 anchor = lyd_insert_get_next_anchor(lyd_child(parent), node);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200584 if (anchor && (anchor->schema->flags & LYS_KEY)) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100585 if (lydctx->parse_opts & LYD_PARSE_STRICT) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100586 LOGVAL(ctx, LYVE_DATA, "Invalid position of the key \"%s\" in a list.", node->schema->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200587 ret = LY_EVALID;
588 goto error;
589 } else {
590 LOGWRN(ctx, "Invalid position of the key \"%s\" in a list.", node->schema->name);
591 }
592 }
593 }
594
595 /* parser next */
596 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
597
598 /* no children expected */
599 if (xmlctx->status == LYXML_ELEMENT) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100600 LOGVAL(ctx, LYVE_SYNTAX, "Child element \"%.*s\" inside a terminal node \"%s\" found.",
Radek Krejci422afb12021-03-04 16:38:16 +0100601 (int)xmlctx->name_len, xmlctx->name, snode->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200602 ret = LY_EVALID;
603 goto error;
604 }
605 } else if (snode->nodetype & LYD_NODE_INNER) {
606 if (!xmlctx->ws_only) {
607 /* value in inner node */
Radek Krejci2efc45b2020-12-22 16:25:44 +0100608 LOGVAL(ctx, LYVE_SYNTAX, "Text value \"%.*s\" inside an inner node \"%s\" found.",
Radek Krejci422afb12021-03-04 16:38:16 +0100609 (int)xmlctx->value_len, xmlctx->value, snode->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200610 ret = LY_EVALID;
611 goto error;
612 }
613
614 /* create node */
615 ret = lyd_create_inner(snode, &node);
616 LY_CHECK_GOTO(ret, error);
617
Radek Krejciddace2c2021-01-08 11:30:56 +0100618 LOG_LOCSET(snode, node, NULL, NULL);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100619
Michal Vaskoa5da3292020-08-12 13:10:50 +0200620 /* parser next */
621 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
622
623 /* process children */
624 while (xmlctx->status == LYXML_ELEMENT) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100625 ret = lydxml_subtree_r(lydctx, node, lyd_node_child_p(node), NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200626 LY_CHECK_GOTO(ret, error);
627 }
628
629 if (snode->nodetype == LYS_LIST) {
630 /* check all keys exist */
631 LY_CHECK_GOTO(ret = lyd_parse_check_keys(node), error);
632 }
633
Michal Vaskoe0665742021-02-11 11:08:44 +0100634 if (!(lydctx->parse_opts & LYD_PARSE_ONLY)) {
Michal Vaskoa5da3292020-08-12 13:10:50 +0200635 /* new node validation, autodelete CANNOT occur, all nodes are new */
Michal Vaskoe0665742021-02-11 11:08:44 +0100636 ret = lyd_validate_new(lyd_node_child_p(node), snode, NULL, NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200637 LY_CHECK_GOTO(ret, error);
638
639 /* add any missing default children */
Radek Krejci4f2e3e52021-03-30 14:20:28 +0200640 ret = lyd_new_implicit_r(node, lyd_node_child_p(node), NULL, NULL, &lydctx->node_when, &lydctx->node_exts,
641 &lydctx->node_types, (lydctx->val_opts & LYD_VALIDATE_NO_STATE) ? LYD_IMPLICIT_NO_STATE : 0, NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200642 LY_CHECK_GOTO(ret, error);
643 }
644
645 if (snode->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) {
646 /* rememeber the RPC/action/notification */
647 lydctx->op_node = node;
648 }
649 } else if (snode->nodetype & LYD_NODE_ANY) {
Michal Vasko27c4dce2021-03-04 15:50:50 +0100650 if ((snode->nodetype == LYS_ANYDATA) && !xmlctx->ws_only) {
651 /* value in anydata node, we expect a tree */
652 LOGVAL(ctx, LYVE_SYNTAX, "Text value \"%.*s\" inside an anydata node \"%s\" found.",
Radek Krejci422afb12021-03-04 16:38:16 +0100653 (int)xmlctx->value_len < 20 ? xmlctx->value_len : 20, xmlctx->value, snode->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200654 ret = LY_EVALID;
655 goto error;
656 }
657
Michal Vasko27c4dce2021-03-04 15:50:50 +0100658 if (!xmlctx->ws_only) {
659 /* use an arbitrary text value for anyxml */
660 lydict_insert(xmlctx->ctx, xmlctx->value, xmlctx->value_len, &val);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200661
Michal Vasko27c4dce2021-03-04 15:50:50 +0100662 /* parser next */
663 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
664
665 /* create node */
666 ret = lyd_create_any(snode, val, LYD_ANYDATA_STRING, 1, &node);
667 LY_CHECK_GOTO(ret, error);
668 } else {
669 /* parser next */
670 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
671
Michal Vaskoa98e3ea2021-06-03 09:13:33 +0200672 /* update options so that generic data can be parsed */
673 prev_parse_opts = lydctx->parse_opts;
Michal Vasko27c4dce2021-03-04 15:50:50 +0100674 lydctx->parse_opts &= ~LYD_PARSE_STRICT;
675 lydctx->parse_opts |= LYD_PARSE_OPAQ;
Michal Vaskoa98e3ea2021-06-03 09:13:33 +0200676 prev_int_opts = lydctx->int_opts;
677 lydctx->int_opts |= LYD_INTOPT_RPC | LYD_INTOPT_ACTION | LYD_INTOPT_NOTIF;
678
679 /* parse any data tree */
Michal Vasko27c4dce2021-03-04 15:50:50 +0100680 anchor = NULL;
681 while (xmlctx->status == LYXML_ELEMENT) {
682 ret = lydxml_subtree_r(lydctx, NULL, &anchor, NULL);
Michal Vaskoa98e3ea2021-06-03 09:13:33 +0200683 if (ret) {
684 break;
685 }
Michal Vasko27c4dce2021-03-04 15:50:50 +0100686 }
Michal Vaskoa98e3ea2021-06-03 09:13:33 +0200687
688 /* restore options */
689 lydctx->parse_opts = prev_parse_opts;
690 lydctx->int_opts = prev_int_opts;
691
692 LY_CHECK_GOTO(ret, error);
Michal Vasko27c4dce2021-03-04 15:50:50 +0100693
694 /* create node */
695 ret = lyd_create_any(snode, anchor, LYD_ANYDATA_DATATREE, 1, &node);
696 LY_CHECK_GOTO(ret, error);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200697 }
Michal Vaskoa5da3292020-08-12 13:10:50 +0200698 }
699 assert(node);
700
701 /* add/correct flags */
702 if (snode) {
Radek Krejci4f2e3e52021-03-30 14:20:28 +0200703 lyd_parse_set_data_flags(node, &lydctx->node_when, &lydctx->node_exts, &meta, lydctx->parse_opts);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200704 }
705
706 /* parser next */
707 assert(xmlctx->status == LYXML_ELEM_CLOSE);
708 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
709
710 /* add metadata/attributes */
711 if (snode) {
Michal Vasko871a0252020-11-11 18:35:24 +0100712 lyd_insert_meta(node, meta, 0);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200713 } else {
714 lyd_insert_attr(node, attr);
715 }
716
717 /* insert, keep first pointer correct */
Michal Vaskoe0665742021-02-11 11:08:44 +0100718 lyd_insert_node(parent, first_p, node);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200719 while (!parent && (*first_p)->prev->next) {
720 *first_p = (*first_p)->prev;
721 }
722
Michal Vaskoe0665742021-02-11 11:08:44 +0100723 /* rememeber a successfully parsed node */
724 if (parsed) {
725 ly_set_add(parsed, node, 1, NULL);
726 }
727
Radek Krejciddace2c2021-01-08 11:30:56 +0100728 LOG_LOCBACK(node ? 1 : 0, node ? 1 : 0, 0, 0);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200729 return LY_SUCCESS;
730
731error:
Radek Krejciddace2c2021-01-08 11:30:56 +0100732 LOG_LOCBACK(node ? 1 : 0, node ? 1 : 0, 0, 0);
Michal Vasko3a41dff2020-07-15 14:30:28 +0200733 lyd_free_meta_siblings(meta);
Radek Krejci011e4aa2020-09-04 15:22:31 +0200734 lyd_free_attr_siblings(ctx, attr);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200735 lyd_free_tree(node);
Radek Krejcie7b95092019-05-15 11:03:07 +0200736 return ret;
737}
738
Michal Vaskoe0665742021-02-11 11:08:44 +0100739/**
740 * @brief Parse a specific XML element into an opaque node.
741 *
742 * @param[in] xmlctx XML parser context.
743 * @param[in] name Name of the element.
744 * @param[in] uri URI of the element.
745 * @param[in] value Whether a value is expected in the element.
746 * @param[out] evnp Parsed envelope (opaque node).
747 * @return LY_SUCCESS on success.
748 * @return LY_ENOT if the specified element did not match.
749 * @return LY_ERR value on error.
750 */
Michal Vasko1bf09392020-03-27 12:38:10 +0100751static LY_ERR
Michal Vaskoe0665742021-02-11 11:08:44 +0100752lydxml_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 +0100753{
Michal Vaskoe0665742021-02-11 11:08:44 +0100754 LY_ERR rc = LY_SUCCESS;
755 const struct lyxml_ns *ns;
Radek Krejci1798aae2020-07-14 13:26:06 +0200756 struct lyd_attr *attr = NULL;
Michal Vasko1bf09392020-03-27 12:38:10 +0100757 const char *prefix;
758 size_t prefix_len;
759
Michal Vasko1bf09392020-03-27 12:38:10 +0100760 assert(xmlctx->status == LYXML_ELEMENT);
761 if (ly_strncmp(name, xmlctx->name, xmlctx->name_len)) {
762 /* not the expected element */
Michal Vaskoe0665742021-02-11 11:08:44 +0100763 return LY_ENOT;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100764 }
765
766 prefix = xmlctx->prefix;
767 prefix_len = xmlctx->prefix_len;
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200768 ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100769 if (!ns) {
Radek Krejci422afb12021-03-04 16:38:16 +0100770 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)prefix_len, prefix);
Michal Vaskoe0665742021-02-11 11:08:44 +0100771 return LY_EVALID;
772 } else if (strcmp(ns->uri, uri)) {
773 /* different namespace */
774 return LY_ENOT;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100775 }
776
777 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
778
779 /* create attributes */
780 if (xmlctx->status == LYXML_ATTRIBUTE) {
781 LY_CHECK_RET(lydxml_attrs(xmlctx, &attr));
782 }
783
Michal Vaskoe0665742021-02-11 11:08:44 +0100784 assert(xmlctx->status == LYXML_ELEM_CONTENT);
785 if (!value && !xmlctx->ws_only) {
786 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected value \"%.*s\" in the \"%s\" element.",
Radek Krejci422afb12021-03-04 16:38:16 +0100787 (int)xmlctx->value_len, xmlctx->value, name);
Michal Vaskoe0665742021-02-11 11:08:44 +0100788 rc = LY_EVALID;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100789 goto cleanup;
Michal Vaskoe0665742021-02-11 11:08:44 +0100790 }
Michal Vaskoa8edff02020-03-27 14:47:01 +0100791
792 /* create node */
Michal Vaskoe0665742021-02-11 11:08:44 +0100793 rc = lyd_create_opaq(xmlctx->ctx, name, strlen(name), prefix, prefix_len, uri, strlen(uri), xmlctx->value,
Radek Krejci8df109d2021-04-23 12:19:08 +0200794 xmlctx->ws_only ? 0 : xmlctx->value_len, NULL, LY_VALUE_XML, NULL, 0, envp);
Michal Vaskoe0665742021-02-11 11:08:44 +0100795 LY_CHECK_GOTO(rc, cleanup);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100796
797 /* assign atributes */
Michal Vaskoe0665742021-02-11 11:08:44 +0100798 ((struct lyd_node_opaq *)(*envp))->attr = attr;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100799 attr = NULL;
800
Michal Vaskoe0665742021-02-11 11:08:44 +0100801 /* parser next element */
802 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100803
Michal Vaskoe0665742021-02-11 11:08:44 +0100804cleanup:
805 lyd_free_attr_siblings(xmlctx->ctx, attr);
806 if (rc) {
807 lyd_free_tree(*envp);
808 *envp = NULL;
809 }
810 return rc;
811}
812
813/**
814 * @brief Parse all expected non-data XML elements of a NETCONF rpc message.
815 *
816 * @param[in] xmlctx XML parser context.
817 * @param[out] evnp Parsed envelope(s) (opaque node).
818 * @param[out] int_opts Internal options for parsing the rest of YANG data.
819 * @param[out] close_elem Number of parsed opened elements that need to be closed.
820 * @return LY_SUCCESS on success.
821 * @return LY_ERR value on error.
822 */
823static LY_ERR
824lydxml_env_netconf_rpc(struct lyxml_ctx *xmlctx, struct lyd_node **envp, uint32_t *int_opts, uint32_t *close_elem)
825{
826 LY_ERR rc = LY_SUCCESS, r;
827 struct lyd_node *child;
828
829 assert(envp && !*envp);
830
831 /* parse "rpc" */
832 r = lydxml_envelope(xmlctx, "rpc", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, envp);
Michal Vaskoe0665742021-02-11 11:08:44 +0100833 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
834
835 /* parse "action", if any */
836 r = lydxml_envelope(xmlctx, "action", "urn:ietf:params:xml:ns:yang:1", 0, &child);
837 if (r == LY_SUCCESS) {
838 /* insert */
839 lyd_insert_node(*envp, NULL, child);
840
841 /* NETCONF action */
842 *int_opts = LYD_INTOPT_NO_SIBLINGS | LYD_INTOPT_ACTION;
843 *close_elem = 2;
844 } else if (r == LY_ENOT) {
845 /* NETCONF RPC */
846 *int_opts = LYD_INTOPT_NO_SIBLINGS | LYD_INTOPT_RPC;
847 *close_elem = 1;
848 } else {
849 rc = r;
850 goto cleanup;
851 }
852
853cleanup:
854 if (rc) {
855 lyd_free_tree(*envp);
856 *envp = NULL;
857 }
858 return rc;
859}
860
861/**
862 * @brief Parse all expected non-data XML elements of a NETCONF notification message.
863 *
864 * @param[in] xmlctx XML parser context.
865 * @param[out] evnp Parsed envelope(s) (opaque node).
866 * @param[out] int_opts Internal options for parsing the rest of YANG data.
867 * @param[out] close_elem Number of parsed opened elements that need to be closed.
868 * @return LY_SUCCESS on success.
869 * @return LY_ERR value on error.
870 */
871static LY_ERR
872lydxml_env_netconf_notif(struct lyxml_ctx *xmlctx, struct lyd_node **envp, uint32_t *int_opts, uint32_t *close_elem)
873{
874 LY_ERR rc = LY_SUCCESS, r;
875 struct lyd_node *child;
876
877 assert(envp && !*envp);
878
879 /* parse "notification" */
880 r = lydxml_envelope(xmlctx, "notification", "urn:ietf:params:xml:ns:netconf:notification:1.0", 0, envp);
Michal Vaskoe0665742021-02-11 11:08:44 +0100881 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
882
883 /* parse "eventTime" */
884 r = lydxml_envelope(xmlctx, "eventTime", "urn:ietf:params:xml:ns:netconf:notification:1.0", 1, &child);
885 if (r == LY_ENOT) {
Radek Krejci422afb12021-03-04 16:38:16 +0100886 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unexpected element \"%.*s\" instead of \"eventTime\".",
887 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +0100888 r = LY_EVALID;
889 }
890 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
891
892 /* insert */
893 lyd_insert_node(*envp, NULL, child);
894
895 /* validate value */
896 /* TODO validate child->value as yang:date-and-time */
897
898 /* finish child parsing */
Michal Vaskoa8edff02020-03-27 14:47:01 +0100899 if (xmlctx->status != LYXML_ELEM_CLOSE) {
900 assert(xmlctx->status == LYXML_ELEMENT);
Michal Vaskoe0665742021-02-11 11:08:44 +0100901 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"eventTime\".",
Radek Krejci422afb12021-03-04 16:38:16 +0100902 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +0100903 rc = LY_EVALID;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100904 goto cleanup;
905 }
Michal Vaskoe0665742021-02-11 11:08:44 +0100906 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
907
908 /* NETCONF notification */
909 *int_opts = LYD_INTOPT_NO_SIBLINGS | LYD_INTOPT_NOTIF;
910 *close_elem = 1;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100911
912cleanup:
Michal Vaskoe0665742021-02-11 11:08:44 +0100913 if (rc) {
Michal Vaskoa8edff02020-03-27 14:47:01 +0100914 lyd_free_tree(*envp);
Michal Vaskoe0665742021-02-11 11:08:44 +0100915 *envp = NULL;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100916 }
Michal Vaskoe0665742021-02-11 11:08:44 +0100917 return rc;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100918}
Michal Vasko79135ae2020-12-16 10:08:35 +0100919
Michal Vaskoe0665742021-02-11 11:08:44 +0100920/**
921 * @brief Parse an XML element as an opaque node subtree.
922 *
923 * @param[in] xmlctx XML parser context.
924 * @param[in] parent Parent to append nodes to.
925 * @return LY_ERR value.
926 */
927static LY_ERR
928lydxml_opaq_r(struct lyxml_ctx *xmlctx, struct lyd_node *parent)
Michal Vaskoa8edff02020-03-27 14:47:01 +0100929{
Michal Vaskoe0665742021-02-11 11:08:44 +0100930 LY_ERR rc = LY_SUCCESS;
931 const struct lyxml_ns *ns;
932 struct lyd_attr *attr = NULL;
933 struct lyd_node *child = NULL;
934 const char *name, *prefix;
935 size_t name_len, prefix_len;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100936
Michal Vaskoe0665742021-02-11 11:08:44 +0100937 assert(xmlctx->status == LYXML_ELEMENT);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100938
Michal Vaskoe0665742021-02-11 11:08:44 +0100939 name = xmlctx->name;
940 name_len = xmlctx->name_len;
941 prefix = xmlctx->prefix;
942 prefix_len = xmlctx->prefix_len;
943 ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
944 if (!ns) {
Radek Krejci422afb12021-03-04 16:38:16 +0100945 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)prefix_len, prefix);
Michal Vaskoe0665742021-02-11 11:08:44 +0100946 return LY_EVALID;
947 }
Michal Vaskoa8edff02020-03-27 14:47:01 +0100948
Michal Vaskoe0665742021-02-11 11:08:44 +0100949 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
Michal Vaskoa8edff02020-03-27 14:47:01 +0100950
Michal Vaskoe0665742021-02-11 11:08:44 +0100951 /* create attributes */
952 if (xmlctx->status == LYXML_ATTRIBUTE) {
953 LY_CHECK_RET(lydxml_attrs(xmlctx, &attr));
954 }
955
956 /* create node */
957 assert(xmlctx->status == LYXML_ELEM_CONTENT);
958 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 +0200959 xmlctx->ws_only ? 0 : xmlctx->value_len, NULL, LY_VALUE_XML, NULL, 0, &child);
Michal Vaskoe0665742021-02-11 11:08:44 +0100960 LY_CHECK_GOTO(rc, cleanup);
961
962 /* assign atributes */
963 ((struct lyd_node_opaq *)child)->attr = attr;
964 attr = NULL;
965
966 /* parser next element */
967 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
968
969 /* parse all the descendants */
970 while (xmlctx->status == LYXML_ELEMENT) {
971 rc = lydxml_opaq_r(xmlctx, child);
972 LY_CHECK_GOTO(rc, cleanup);
973 }
974
975 /* insert */
976 lyd_insert_node(parent, NULL, child);
977
978cleanup:
979 lyd_free_attr_siblings(xmlctx->ctx, attr);
980 if (rc) {
981 lyd_free_tree(child);
982 }
983 return rc;
984}
985
986/**
987 * @brief Parse all expected non-data XML elements of the error-info element in NETCONF rpc-reply message.
988 *
989 * @param[in] xmlctx XML parser context.
990 * @param[in] parent Parent to append nodes to.
991 * @return LY_ERR value.
992 */
993static LY_ERR
994lydxml_env_netconf_rpc_reply_error_info(struct lyxml_ctx *xmlctx, struct lyd_node *parent)
995{
996 LY_ERR r;
997 struct lyd_node *child, *iter;
998 const struct lyxml_ns *ns;
999 ly_bool no_dup;
1000
1001 /* there must be some child */
1002 if (xmlctx->status == LYXML_ELEM_CLOSE) {
1003 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Missing child elements of \"error-info\".");
1004 return LY_EVALID;
1005 }
1006
1007 while (xmlctx->status == LYXML_ELEMENT) {
1008 child = NULL;
1009
1010 /*
1011 * session-id
1012 */
1013 r = lydxml_envelope(xmlctx, "session-id", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1014 if (r == LY_SUCCESS) {
1015 no_dup = 1;
1016 goto check_child;
1017 } else if (r != LY_ENOT) {
1018 goto error;
1019 }
1020
1021 /*
1022 * bad-attribute
1023 */
1024 r = lydxml_envelope(xmlctx, "bad-attribute", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1025 if (r == LY_SUCCESS) {
1026 no_dup = 1;
1027 goto check_child;
1028 } else if (r != LY_ENOT) {
1029 goto error;
1030 }
1031
1032 /*
1033 * bad-element
1034 */
1035 r = lydxml_envelope(xmlctx, "bad-element", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1036 if (r == LY_SUCCESS) {
1037 no_dup = 1;
1038 goto check_child;
1039 } else if (r != LY_ENOT) {
1040 goto error;
1041 }
1042
1043 /*
1044 * bad-namespace
1045 */
1046 r = lydxml_envelope(xmlctx, "bad-namespace", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1047 if (r == LY_SUCCESS) {
1048 no_dup = 1;
1049 goto check_child;
1050 } else if (r != LY_ENOT) {
1051 goto error;
1052 }
1053
1054 if (r == LY_ENOT) {
1055 assert(xmlctx->status == LYXML_ELEMENT);
1056
1057 /* learn namespace */
1058 ns = lyxml_ns_get(&xmlctx->ns, xmlctx->prefix, xmlctx->prefix_len);
1059 if (!ns) {
Radek Krejci422afb12021-03-04 16:38:16 +01001060 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)xmlctx->prefix_len, xmlctx->prefix);
Michal Vaskoe0665742021-02-11 11:08:44 +01001061 r = LY_EVALID;
1062 goto error;
1063 } else if (!strcmp(ns->uri, "urn:ietf:params:xml:ns:netconf:base:1.0")) {
1064 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"error-info\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001065 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001066 r = LY_EVALID;
1067 goto error;
1068 }
1069
1070 /* custom elements */
1071 r = lydxml_opaq_r(xmlctx, parent);
1072 LY_CHECK_GOTO(r, error);
1073
1074 no_dup = 0;
1075 }
1076
1077check_child:
1078 /* check for duplicates */
1079 if (no_dup) {
1080 LY_LIST_FOR(lyd_child(parent), iter) {
1081 if ((((struct lyd_node_opaq *)iter)->name.name == ((struct lyd_node_opaq *)child)->name.name) &&
1082 (((struct lyd_node_opaq *)iter)->name.module_ns == ((struct lyd_node_opaq *)child)->name.module_ns)) {
1083 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Duplicate element \"%s\" in \"error-info\".",
1084 ((struct lyd_node_opaq *)child)->name.name);
1085 r = LY_EVALID;
1086 goto error;
1087 }
1088 }
1089 }
1090
1091 /* finish child parsing */
1092 if (xmlctx->status != LYXML_ELEM_CLOSE) {
1093 assert(xmlctx->status == LYXML_ELEMENT);
1094 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"error-info\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001095 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001096 r = LY_EVALID;
1097 goto error;
1098 }
1099 LY_CHECK_GOTO(r = lyxml_ctx_next(xmlctx), error);
1100
1101 /* insert */
1102 lyd_insert_node(parent, NULL, child);
1103 }
1104
1105 return LY_SUCCESS;
1106
1107error:
1108 lyd_free_tree(child);
1109 return r;
1110}
1111
1112/**
1113 * @brief Parse all expected non-data XML elements of the rpc-error element in NETCONF rpc-reply message.
1114 *
1115 * @param[in] xmlctx XML parser context.
1116 * @param[in] parent Parent to append nodes to.
1117 * @return LY_ERR value.
1118 */
1119static LY_ERR
1120lydxml_env_netconf_rpc_reply_error(struct lyxml_ctx *xmlctx, struct lyd_node *parent)
1121{
1122 LY_ERR r;
1123 struct lyd_node *child, *iter;
1124 const char *val;
1125 ly_bool no_dup;
1126
1127 /* there must be some child */
1128 if (xmlctx->status == LYXML_ELEM_CLOSE) {
1129 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Missing child elements of \"rpc-error\".");
1130 return LY_EVALID;
1131 }
1132
1133 while (xmlctx->status == LYXML_ELEMENT) {
1134 child = NULL;
1135
1136 /*
1137 * error-type
1138 */
1139 r = lydxml_envelope(xmlctx, "error-type", "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, "transport") && strcmp(val, "rpc") && strcmp(val, "protocol") && strcmp(val, "application")) {
1143 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Invalid value \"%s\" of element \"%s\".", val,
1144 ((struct lyd_node_opaq *)child)->name.name);
1145 r = LY_EVALID;
1146 goto error;
1147 }
1148
1149 no_dup = 1;
1150 goto check_child;
1151 } else if (r != LY_ENOT) {
1152 goto error;
1153 }
1154
1155 /*
1156 * error-tag
1157 */
1158 r = lydxml_envelope(xmlctx, "error-tag", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1159 if (r == LY_SUCCESS) {
1160 val = ((struct lyd_node_opaq *)child)->value;
1161 if (strcmp(val, "in-use") && strcmp(val, "invalid-value") && strcmp(val, "too-big") &&
1162 strcmp(val, "missing-attribute") && strcmp(val, "bad-attribute") &&
1163 strcmp(val, "unknown-attribute") && strcmp(val, "missing-element") && strcmp(val, "bad-element") &&
1164 strcmp(val, "unknown-element") && strcmp(val, "unknown-namespace") && strcmp(val, "access-denied") &&
1165 strcmp(val, "lock-denied") && strcmp(val, "resource-denied") && strcmp(val, "rollback-failed") &&
1166 strcmp(val, "data-exists") && strcmp(val, "data-missing") && strcmp(val, "operation-not-supported") &&
1167 strcmp(val, "operation-failed") && strcmp(val, "malformed-message")) {
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-severity
1182 */
1183 r = lydxml_envelope(xmlctx, "error-severity", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1184 if (r == LY_SUCCESS) {
1185 val = ((struct lyd_node_opaq *)child)->value;
1186 if (strcmp(val, "error") && strcmp(val, "warning")) {
1187 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Invalid value \"%s\" of element \"%s\".", val,
1188 ((struct lyd_node_opaq *)child)->name.name);
1189 r = LY_EVALID;
1190 goto error;
1191 }
1192
1193 no_dup = 1;
1194 goto check_child;
1195 } else if (r != LY_ENOT) {
1196 goto error;
1197 }
1198
1199 /*
1200 * error-app-tag
1201 */
1202 r = lydxml_envelope(xmlctx, "error-app-tag", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1203 if (r == LY_SUCCESS) {
1204 no_dup = 1;
1205 goto check_child;
1206 } else if (r != LY_ENOT) {
1207 goto error;
1208 }
1209
1210 /*
1211 * error-path
1212 */
1213 r = lydxml_envelope(xmlctx, "error-path", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1214 if (r == LY_SUCCESS) {
1215 no_dup = 1;
1216 goto check_child;
1217 } else if (r != LY_ENOT) {
1218 goto error;
1219 }
1220
1221 /*
1222 * error-message
1223 */
1224 r = lydxml_envelope(xmlctx, "error-message", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1225 if (r == LY_SUCCESS) {
1226 no_dup = 1;
1227 goto check_child;
1228 } else if (r != LY_ENOT) {
1229 goto error;
1230 }
1231
1232 /* error-info */
1233 r = lydxml_envelope(xmlctx, "error-info", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, &child);
1234 if (r == LY_SUCCESS) {
1235 /* parse all the descendants */
1236 LY_CHECK_GOTO(r = lydxml_env_netconf_rpc_reply_error_info(xmlctx, child), error);
1237
1238 no_dup = 0;
1239 goto check_child;
1240 } else if (r != LY_ENOT) {
1241 goto error;
1242 }
1243
1244 if (r == LY_ENOT) {
1245 assert(xmlctx->status == LYXML_ELEMENT);
1246 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"rpc-error\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001247 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001248 r = LY_EVALID;
1249 goto error;
1250 }
1251
1252check_child:
1253 /* check for duplicates */
1254 if (no_dup) {
1255 LY_LIST_FOR(lyd_child(parent), iter) {
1256 if ((((struct lyd_node_opaq *)iter)->name.name == ((struct lyd_node_opaq *)child)->name.name) &&
1257 (((struct lyd_node_opaq *)iter)->name.module_ns == ((struct lyd_node_opaq *)child)->name.module_ns)) {
1258 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Duplicate element \"%s\" in \"rpc-error\".",
1259 ((struct lyd_node_opaq *)child)->name.name);
1260 r = LY_EVALID;
1261 goto error;
1262 }
1263 }
1264 }
1265
1266 /* finish child parsing */
1267 if (xmlctx->status != LYXML_ELEM_CLOSE) {
1268 assert(xmlctx->status == LYXML_ELEMENT);
1269 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"rpc-error\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001270 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001271 r = LY_EVALID;
1272 goto error;
1273 }
1274 LY_CHECK_GOTO(r = lyxml_ctx_next(xmlctx), error);
1275
1276 /* insert */
1277 lyd_insert_node(parent, NULL, child);
1278 }
1279
1280 return LY_SUCCESS;
1281
1282error:
1283 lyd_free_tree(child);
1284 return r;
1285}
1286
1287/**
1288 * @brief Parse all expected non-data XML elements of a NETCONF rpc-reply message.
1289 *
1290 * @param[in] xmlctx XML parser context.
1291 * @param[out] evnp Parsed envelope(s) (opaque node).
1292 * @param[out] int_opts Internal options for parsing the rest of YANG data.
1293 * @param[out] close_elem Number of parsed opened elements that need to be closed.
1294 * @return LY_SUCCESS on success.
1295 * @return LY_ERR value on error.
1296 */
1297static LY_ERR
1298lydxml_env_netconf_reply(struct lyxml_ctx *xmlctx, struct lyd_node **envp, uint32_t *int_opts, uint32_t *close_elem)
1299{
1300 LY_ERR rc = LY_SUCCESS, r;
1301 struct lyd_node *child = NULL;
1302 const char *parsed_elem = NULL;
1303
1304 assert(envp && !*envp);
1305
1306 /* parse "rpc-reply" */
1307 r = lydxml_envelope(xmlctx, "rpc-reply", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, envp);
Michal Vaskoe0665742021-02-11 11:08:44 +01001308 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
1309
1310 /* there must be some child */
1311 if (xmlctx->status == LYXML_ELEM_CLOSE) {
1312 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Missing child elements of \"rpc-reply\".");
1313 rc = LY_EVALID;
Michal Vaskocf770e22020-08-12 13:21:43 +02001314 goto cleanup;
Michal Vaskoa8edff02020-03-27 14:47:01 +01001315 }
1316
Michal Vaskoe0665742021-02-11 11:08:44 +01001317 /* try to parse "ok" */
1318 r = lydxml_envelope(xmlctx, "ok", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, &child);
1319 if (r == LY_SUCCESS) {
1320 /* insert */
1321 lyd_insert_node(*envp, NULL, child);
1322
1323 /* finish child parsing */
1324 if (xmlctx->status != LYXML_ELEM_CLOSE) {
1325 assert(xmlctx->status == LYXML_ELEMENT);
1326 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"ok\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001327 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001328 rc = LY_EVALID;
1329 goto cleanup;
1330 }
1331 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
1332
1333 /* success */
1334 parsed_elem = "ok";
1335 goto finish;
1336 } else if (r != LY_ENOT) {
1337 rc = r;
1338 goto cleanup;
Michal Vasko2552ea32020-12-08 15:32:34 +01001339 }
1340
Michal Vaskoe0665742021-02-11 11:08:44 +01001341 /* try to parse all "rpc-error" elements */
1342 while (xmlctx->status == LYXML_ELEMENT) {
1343 r = lydxml_envelope(xmlctx, "rpc-error", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, &child);
1344 if (r == LY_ENOT) {
1345 break;
1346 } else if (r) {
1347 rc = r;
1348 goto cleanup;
1349 }
1350
1351 /* insert */
1352 lyd_insert_node(*envp, NULL, child);
1353
1354 /* parse all children of "rpc-error" */
1355 LY_CHECK_GOTO(rc = lydxml_env_netconf_rpc_reply_error(xmlctx, child), cleanup);
1356
1357 /* finish child parsing */
1358 assert(xmlctx->status == LYXML_ELEM_CLOSE);
1359 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
1360
1361 parsed_elem = "rpc-error";
Michal Vasko2552ea32020-12-08 15:32:34 +01001362 }
Michal Vaskoe0665742021-02-11 11:08:44 +01001363
1364finish:
1365 if (parsed_elem) {
1366 /* NETCONF rpc-reply with no data */
1367 if (xmlctx->status != LYXML_ELEM_CLOSE) {
1368 assert(xmlctx->status == LYXML_ELEMENT);
1369 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected sibling element \"%.*s\" of \"%s\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001370 (int)xmlctx->name_len, xmlctx->name, parsed_elem);
Michal Vaskoe0665742021-02-11 11:08:44 +01001371 rc = LY_EVALID;
1372 goto cleanup;
1373 }
1374 }
1375
1376 /* NETCONF rpc-reply */
Michal Vasko1d991fd2021-07-09 13:14:40 +02001377 *int_opts = LYD_INTOPT_WITH_SIBLINGS | LYD_INTOPT_REPLY;
Michal Vaskoe0665742021-02-11 11:08:44 +01001378 *close_elem = 1;
1379
1380cleanup:
1381 if (rc) {
1382 lyd_free_tree(*envp);
1383 *envp = NULL;
1384 }
1385 return rc;
1386}
1387
Michal Vasko2552ea32020-12-08 15:32:34 +01001388LY_ERR
Radek Krejcif16e2542021-02-17 15:39:23 +01001389lyd_parse_xml(const struct ly_ctx *ctx, const struct lysc_ext_instance *ext, struct lyd_node *parent,
1390 struct lyd_node **first_p, struct ly_in *in, uint32_t parse_opts, uint32_t val_opts, enum lyd_type data_type,
1391 struct lyd_node **envp, struct ly_set *parsed, struct lyd_ctx **lydctx_p)
Michal Vasko2552ea32020-12-08 15:32:34 +01001392{
Michal Vaskoe0665742021-02-11 11:08:44 +01001393 LY_ERR rc = LY_SUCCESS;
1394 struct lyd_xml_ctx *lydctx;
Michal Vasko2ca9f9e2021-07-02 09:21:36 +02001395 uint32_t i, int_opts = 0, close_elem = 0;
Michal Vaskoe0665742021-02-11 11:08:44 +01001396 ly_bool parsed_data_nodes = 0;
Michal Vasko2552ea32020-12-08 15:32:34 +01001397
Michal Vaskoe0665742021-02-11 11:08:44 +01001398 assert(ctx && in && lydctx_p);
1399 assert(!(parse_opts & ~LYD_PARSE_OPTS_MASK));
1400 assert(!(val_opts & ~LYD_VALIDATE_OPTS_MASK));
Michal Vasko2552ea32020-12-08 15:32:34 +01001401
Michal Vaskoe0665742021-02-11 11:08:44 +01001402 /* init context */
1403 lydctx = calloc(1, sizeof *lydctx);
1404 LY_CHECK_ERR_RET(!lydctx, LOGMEM(ctx), LY_EMEM);
1405 LY_CHECK_GOTO(rc = lyxml_ctx_new(ctx, in, &lydctx->xmlctx), cleanup);
1406 lydctx->parse_opts = parse_opts;
1407 lydctx->val_opts = val_opts;
1408 lydctx->free = lyd_xml_ctx_free;
Radek Krejcif16e2542021-02-17 15:39:23 +01001409 lydctx->ext = ext;
Michal Vasko2552ea32020-12-08 15:32:34 +01001410
Michal Vaskoe0665742021-02-11 11:08:44 +01001411 switch (data_type) {
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001412 case LYD_TYPE_DATA_YANG:
Michal Vaskoe0665742021-02-11 11:08:44 +01001413 int_opts = LYD_INTOPT_WITH_SIBLINGS;
1414 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001415 case LYD_TYPE_RPC_YANG:
Michal Vaskoe0665742021-02-11 11:08:44 +01001416 int_opts = LYD_INTOPT_RPC | LYD_INTOPT_ACTION | LYD_INTOPT_NO_SIBLINGS;
1417 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001418 case LYD_TYPE_NOTIF_YANG:
Michal Vaskoe0665742021-02-11 11:08:44 +01001419 int_opts = LYD_INTOPT_NOTIF | LYD_INTOPT_NO_SIBLINGS;
1420 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001421 case LYD_TYPE_REPLY_YANG:
Michal Vaskoe0665742021-02-11 11:08:44 +01001422 int_opts = LYD_INTOPT_REPLY | LYD_INTOPT_NO_SIBLINGS;
1423 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001424 case LYD_TYPE_RPC_NETCONF:
Michal Vaskoe0665742021-02-11 11:08:44 +01001425 assert(!parent);
1426 LY_CHECK_GOTO(rc = lydxml_env_netconf_rpc(lydctx->xmlctx, envp, &int_opts, &close_elem), cleanup);
1427 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001428 case LYD_TYPE_NOTIF_NETCONF:
1429 assert(!parent);
1430 LY_CHECK_GOTO(rc = lydxml_env_netconf_notif(lydctx->xmlctx, envp, &int_opts, &close_elem), cleanup);
1431 break;
1432 case LYD_TYPE_REPLY_NETCONF:
Michal Vaskoe0665742021-02-11 11:08:44 +01001433 assert(parent);
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001434 LY_CHECK_GOTO(rc = lydxml_env_netconf_reply(lydctx->xmlctx, envp, &int_opts, &close_elem), cleanup);
Michal Vaskoe0665742021-02-11 11:08:44 +01001435 break;
1436 }
1437 lydctx->int_opts = int_opts;
1438
1439 /* find the operation node if it exists already */
1440 LY_CHECK_GOTO(rc = lyd_parser_find_operation(parent, int_opts, &lydctx->op_node), cleanup);
1441
1442 /* parse XML data */
1443 while (lydctx->xmlctx->status == LYXML_ELEMENT) {
1444 LY_CHECK_GOTO(rc = lydxml_subtree_r(lydctx, parent, first_p, parsed), cleanup);
1445 parsed_data_nodes = 1;
1446
1447 if (!(int_opts & LYD_INTOPT_WITH_SIBLINGS)) {
1448 break;
1449 }
Michal Vasko2552ea32020-12-08 15:32:34 +01001450 }
1451
Michal Vaskoe0665742021-02-11 11:08:44 +01001452 /* close all opened elements */
1453 for (i = 0; i < close_elem; ++i) {
1454 if (lydctx->xmlctx->status != LYXML_ELEM_CLOSE) {
1455 assert(lydctx->xmlctx->status == LYXML_ELEMENT);
Radek Krejci422afb12021-03-04 16:38:16 +01001456 LOGVAL(lydctx->xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\".",
1457 (int)lydctx->xmlctx->name_len, lydctx->xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001458 rc = LY_EVALID;
1459 goto cleanup;
1460 }
1461
1462 LY_CHECK_GOTO(rc = lyxml_ctx_next(lydctx->xmlctx), cleanup);
Michal Vasko4189c0f2020-08-13 09:05:22 +02001463 }
Michal Vaskoe0665742021-02-11 11:08:44 +01001464
1465 /* check final state */
1466 if ((int_opts & LYD_INTOPT_NO_SIBLINGS) && (lydctx->xmlctx->status == LYXML_ELEMENT)) {
1467 LOGVAL(ctx, LYVE_SYNTAX, "Unexpected sibling node.");
1468 rc = LY_EVALID;
1469 goto cleanup;
1470 }
1471 if ((int_opts & (LYD_INTOPT_RPC | LYD_INTOPT_NOTIF | LYD_INTOPT_REPLY)) && !lydctx->op_node) {
1472 LOGVAL(ctx, LYVE_DATA, "Missing the operation node.");
1473 rc = LY_EVALID;
1474 goto cleanup;
1475 }
1476
1477 if (!parsed_data_nodes) {
1478 /* no data nodes were parsed */
1479 lydctx->op_node = NULL;
Michal Vaskoa8edff02020-03-27 14:47:01 +01001480 }
1481
1482cleanup:
Michal Vaskoe0665742021-02-11 11:08:44 +01001483 /* there should be no unres stored if validation should be skipped */
1484 assert(!(parse_opts & LYD_PARSE_ONLY) || (!lydctx->node_types.count && !lydctx->meta_types.count &&
Radek Krejci4f2e3e52021-03-30 14:20:28 +02001485 !lydctx->node_when.count && !lydctx->node_exts.count));
Michal Vaskoe0665742021-02-11 11:08:44 +01001486
1487 if (rc) {
1488 lyd_xml_ctx_free((struct lyd_ctx *)lydctx);
1489 } else {
1490 *lydctx_p = (struct lyd_ctx *)lydctx;
1491
1492 /* the XML context is no more needed, freeing it also stops logging line numbers which would be confusing now */
1493 lyxml_ctx_free(lydctx->xmlctx);
1494 lydctx->xmlctx = NULL;
Michal Vasko1ce933a2020-03-30 12:38:22 +02001495 }
Michal Vaskoe0665742021-02-11 11:08:44 +01001496 return rc;
Michal Vasko1ce933a2020-03-30 12:38:22 +02001497}