blob: e7f3bbb7af972a11f557661cf08eba7fb8790794 [file] [log] [blame]
Radek Krejcie7b95092019-05-15 11:03:07 +02001/**
2 * @file parser_xml.c
3 * @author Radek Krejci <rkrejci@cesnet.cz>
4 * @brief XML data parser for libyang
5 *
6 * Copyright (c) 2019 CESNET, z.s.p.o.
7 *
8 * This source code is licensed under BSD 3-Clause License (the "License").
9 * You may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * https://opensource.org/licenses/BSD-3-Clause
13 */
14
Michal Vasko69730152020-10-09 16:30:07 +020015#include <assert.h>
Radek Krejcie7b95092019-05-15 11:03:07 +020016#include <stdint.h>
17#include <stdlib.h>
18#include <string.h>
19
Radek Krejci535ea9f2020-05-29 16:01:05 +020020#include "common.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020021#include "context.h"
Radek Krejci77114102021-03-10 15:21:57 +010022#include "dict.h"
Michal Vaskoafac7822020-10-20 14:22:26 +020023#include "in_internal.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020024#include "log.h"
Radek Krejci7931b192020-06-25 17:05:03 +020025#include "parser_data.h"
26#include "parser_internal.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020027#include "set.h"
Radek Krejci77114102021-03-10 15:21:57 +010028#include "tree.h"
Radek Krejci47fab892020-11-05 17:02:41 +010029#include "tree_data.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020030#include "tree_data_internal.h"
31#include "tree_schema.h"
Radek Krejci77114102021-03-10 15:21:57 +010032#include "tree_schema_internal.h"
Michal Vaskocde73ac2019-11-14 16:10:27 +010033#include "validation.h"
Radek Krejci535ea9f2020-05-29 16:01:05 +020034#include "xml.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020035
36/**
Michal Vaskob36053d2020-03-26 15:49:30 +010037 * @brief Internal context for XML YANG data parser.
Radek Krejci1798aae2020-07-14 13:26:06 +020038 *
Radek Krejci4f2e3e52021-03-30 14:20:28 +020039 * Note that the structure maps to the ::lyd_ctx which is common for all the data parsers
Radek Krejcie7b95092019-05-15 11:03:07 +020040 */
41struct lyd_xml_ctx {
Radek Krejcif16e2542021-02-17 15:39:23 +010042 const struct lysc_ext_instance *ext; /**< extension instance possibly changing document root context of the data being parsed */
Michal Vaskoe0665742021-02-11 11:08:44 +010043 uint32_t parse_opts; /**< various @ref dataparseroptions. */
44 uint32_t val_opts; /**< various @ref datavalidationoptions. */
Radek Krejci1798aae2020-07-14 13:26:06 +020045 uint32_t int_opts; /**< internal data parser options */
46 uint32_t path_len; /**< used bytes in the path buffer */
47 char path[LYD_PARSER_BUFSIZE]; /**< buffer for the generated path */
Michal Vaskoc43c8ab2021-03-05 13:32:44 +010048 struct ly_set node_when; /**< set of nodes with "when" conditions */
Radek Krejci4f2e3e52021-03-30 14:20:28 +020049 struct ly_set node_exts; /**< set of nodes and extensions connected with a plugin providing own validation callback */
Michal Vasko49c39d82020-11-06 17:20:27 +010050 struct ly_set node_types; /**< set of nodes validated with LY_EINCOMPLETE result */
51 struct ly_set meta_types; /**< set of metadata validated with LY_EINCOMPLETE result */
Radek Krejci1798aae2020-07-14 13:26:06 +020052 struct lyd_node *op_node; /**< if an RPC/action/notification is being parsed, store the pointer to it */
Radek Krejcie7b95092019-05-15 11:03:07 +020053
Radek Krejci1798aae2020-07-14 13:26:06 +020054 /* callbacks */
55 lyd_ctx_free_clb free; /* destructor */
Radek Krejci1798aae2020-07-14 13:26:06 +020056
57 struct lyxml_ctx *xmlctx; /**< XML context */
Radek Krejcie7b95092019-05-15 11:03:07 +020058};
59
Radek Krejci1798aae2020-07-14 13:26:06 +020060void
61lyd_xml_ctx_free(struct lyd_ctx *lydctx)
62{
63 struct lyd_xml_ctx *ctx = (struct lyd_xml_ctx *)lydctx;
64
65 lyd_ctx_free(lydctx);
66 lyxml_ctx_free(ctx->xmlctx);
67 free(ctx);
68}
69
Radek Krejcie7b95092019-05-15 11:03:07 +020070static LY_ERR
Michal Vaskofeca4fb2020-10-05 08:58:40 +020071lydxml_metadata(struct lyd_xml_ctx *lydctx, struct lyd_meta **meta)
Radek Krejcie7b95092019-05-15 11:03:07 +020072{
Michal Vaskob36053d2020-03-26 15:49:30 +010073 LY_ERR ret = LY_EVALID;
Radek Krejci28681fa2019-09-06 13:08:45 +020074 const struct lyxml_ns *ns;
75 struct lys_module *mod;
Michal Vaskob36053d2020-03-26 15:49:30 +010076 const char *name;
77 size_t name_len;
Radek Krejci1798aae2020-07-14 13:26:06 +020078 struct lyxml_ctx *xmlctx = lydctx->xmlctx;
Radek Krejci28681fa2019-09-06 13:08:45 +020079
Michal Vaskob36053d2020-03-26 15:49:30 +010080 *meta = NULL;
Radek Krejci28681fa2019-09-06 13:08:45 +020081
Michal Vaskob36053d2020-03-26 15:49:30 +010082 while (xmlctx->status == LYXML_ATTRIBUTE) {
83 if (!xmlctx->prefix_len) {
Radek Krejci28681fa2019-09-06 13:08:45 +020084 /* in XML, all attributes must be prefixed
85 * TODO exception for NETCONF filters which are supposed to map to the ietf-netconf without prefix */
Michal Vaskoe0665742021-02-11 11:08:44 +010086 if (lydctx->parse_opts & LYD_PARSE_STRICT) {
Radek Krejci2efc45b2020-12-22 16:25:44 +010087 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Missing mandatory prefix for XML metadata \"%.*s\".",
Radek Krejci422afb12021-03-04 16:38:16 +010088 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskob36053d2020-03-26 15:49:30 +010089 goto cleanup;
Radek Krejci28681fa2019-09-06 13:08:45 +020090 }
Michal Vaskob36053d2020-03-26 15:49:30 +010091
Radek Krejci28681fa2019-09-06 13:08:45 +020092skip_attr:
Michal Vaskob36053d2020-03-26 15:49:30 +010093 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
94 assert(xmlctx->status == LYXML_ATTR_CONTENT);
95 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Radek Krejci28681fa2019-09-06 13:08:45 +020096 continue;
97 }
98
99 /* get namespace of the attribute to find its annotation definition */
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200100 ns = lyxml_ns_get(&xmlctx->ns, xmlctx->prefix, xmlctx->prefix_len);
Radek Krejci28681fa2019-09-06 13:08:45 +0200101 if (!ns) {
Michal Vasko52927e22020-03-16 17:26:14 +0100102 /* unknown namespace, XML error */
Radek Krejci422afb12021-03-04 16:38:16 +0100103 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)xmlctx->prefix_len, xmlctx->prefix);
Radek Krejci28681fa2019-09-06 13:08:45 +0200104 goto cleanup;
105 }
Michal Vasko52927e22020-03-16 17:26:14 +0100106 mod = ly_ctx_get_module_implemented_ns(xmlctx->ctx, ns->uri);
Radek Krejci28681fa2019-09-06 13:08:45 +0200107 if (!mod) {
108 /* module is not implemented or not present in the schema */
Michal Vaskoe0665742021-02-11 11:08:44 +0100109 if (lydctx->parse_opts & LYD_PARSE_STRICT) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100110 LOGVAL(xmlctx->ctx, LYVE_REFERENCE,
Michal Vasko69730152020-10-09 16:30:07 +0200111 "Unknown (or not implemented) YANG module with namespace \"%s\" for metadata \"%.*s%s%.*s\".",
Radek Krejci422afb12021-03-04 16:38:16 +0100112 ns->uri, (int)xmlctx->prefix_len, xmlctx->prefix, xmlctx->prefix_len ? ":" : "",
113 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskob36053d2020-03-26 15:49:30 +0100114 goto cleanup;
Radek Krejci28681fa2019-09-06 13:08:45 +0200115 }
116 goto skip_attr;
117 }
118
Michal Vasko60ea6352020-06-29 13:39:39 +0200119 /* remember meta name and get its content */
Michal Vaskob36053d2020-03-26 15:49:30 +0100120 name = xmlctx->name;
121 name_len = xmlctx->name_len;
122 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
123 assert(xmlctx->status == LYXML_ATTR_CONTENT);
124
125 /* create metadata */
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200126 ret = lyd_parser_create_meta((struct lyd_ctx *)lydctx, NULL, meta, mod, name, name_len, xmlctx->value,
Radek Krejci8df109d2021-04-23 12:19:08 +0200127 xmlctx->value_len, &xmlctx->dynamic, LY_VALUE_XML, &xmlctx->ns, LYD_HINT_DATA);
Radek Krejci1798aae2020-07-14 13:26:06 +0200128 LY_CHECK_GOTO(ret, cleanup);
Michal Vaskob36053d2020-03-26 15:49:30 +0100129
130 /* next attribute */
131 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Radek Krejcie7b95092019-05-15 11:03:07 +0200132 }
Michal Vasko52927e22020-03-16 17:26:14 +0100133
Radek Krejci28681fa2019-09-06 13:08:45 +0200134 ret = LY_SUCCESS;
Radek Krejcie7b95092019-05-15 11:03:07 +0200135
136cleanup:
Michal Vaskob36053d2020-03-26 15:49:30 +0100137 if (ret) {
Michal Vasko3a41dff2020-07-15 14:30:28 +0200138 lyd_free_meta_siblings(*meta);
Michal Vaskob36053d2020-03-26 15:49:30 +0100139 *meta = NULL;
Radek Krejci38d85362019-09-05 16:26:38 +0200140 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200141 return ret;
142}
143
Michal Vasko52927e22020-03-16 17:26:14 +0100144static LY_ERR
Radek Krejci1798aae2020-07-14 13:26:06 +0200145lydxml_attrs(struct lyxml_ctx *xmlctx, struct lyd_attr **attr)
Michal Vasko52927e22020-03-16 17:26:14 +0100146{
147 LY_ERR ret = LY_SUCCESS;
148 const struct lyxml_ns *ns;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100149 void *val_prefix_data;
Radek Krejci8df109d2021-04-23 12:19:08 +0200150 LY_VALUE_FORMAT format;
Radek Krejci1798aae2020-07-14 13:26:06 +0200151 struct lyd_attr *attr2;
Michal Vaskob36053d2020-03-26 15:49:30 +0100152 const char *name, *prefix;
153 size_t name_len, prefix_len;
Michal Vasko52927e22020-03-16 17:26:14 +0100154
155 assert(attr);
Michal Vaskob36053d2020-03-26 15:49:30 +0100156 *attr = NULL;
Michal Vasko52927e22020-03-16 17:26:14 +0100157
Michal Vaskob36053d2020-03-26 15:49:30 +0100158 while (xmlctx->status == LYXML_ATTRIBUTE) {
Michal Vasko52927e22020-03-16 17:26:14 +0100159 ns = NULL;
Michal Vaskob36053d2020-03-26 15:49:30 +0100160 if (xmlctx->prefix_len) {
Michal Vasko52927e22020-03-16 17:26:14 +0100161 /* get namespace of the attribute */
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200162 ns = lyxml_ns_get(&xmlctx->ns, xmlctx->prefix, xmlctx->prefix_len);
Michal Vasko52927e22020-03-16 17:26:14 +0100163 if (!ns) {
Radek Krejci422afb12021-03-04 16:38:16 +0100164 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)xmlctx->prefix_len, xmlctx->prefix);
Michal Vasko52927e22020-03-16 17:26:14 +0100165 ret = LY_EVALID;
166 goto cleanup;
167 }
168 }
169
170 if (*attr) {
171 attr2 = *attr;
172 } else {
173 attr2 = NULL;
174 }
175
Michal Vaskob36053d2020-03-26 15:49:30 +0100176 /* remember attr prefix, name, and get its content */
177 prefix = xmlctx->prefix;
178 prefix_len = xmlctx->prefix_len;
179 name = xmlctx->name;
180 name_len = xmlctx->name_len;
181 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
182 assert(xmlctx->status == LYXML_ATTR_CONTENT);
183
Michal Vasko52927e22020-03-16 17:26:14 +0100184 /* get value prefixes */
Michal Vaskofc2cd072021-02-24 13:17:17 +0100185 val_prefix_data = NULL;
Radek Krejci8df109d2021-04-23 12:19:08 +0200186 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 +0100187 &xmlctx->ns, &format, &val_prefix_data), cleanup);
Michal Vasko52927e22020-03-16 17:26:14 +0100188
189 /* attr2 is always changed to the created attribute */
Michal Vasko501af032020-11-11 20:27:44 +0100190 ret = lyd_create_attr(NULL, &attr2, xmlctx->ctx, name, name_len, prefix, prefix_len, ns ? ns->uri : NULL,
191 ns ? strlen(ns->uri) : 0, xmlctx->value, xmlctx->value_len, &xmlctx->dynamic, format, val_prefix_data, 0);
Michal Vasko52927e22020-03-16 17:26:14 +0100192 LY_CHECK_GOTO(ret, cleanup);
193
194 if (!*attr) {
195 *attr = attr2;
196 }
Michal Vaskob36053d2020-03-26 15:49:30 +0100197
198 /* next attribute */
199 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko52927e22020-03-16 17:26:14 +0100200 }
201
202cleanup:
Michal Vaskob36053d2020-03-26 15:49:30 +0100203 if (ret) {
Radek Krejci011e4aa2020-09-04 15:22:31 +0200204 lyd_free_attr_siblings(xmlctx->ctx, *attr);
Michal Vaskob36053d2020-03-26 15:49:30 +0100205 *attr = NULL;
Michal Vasko52927e22020-03-16 17:26:14 +0100206 }
Michal Vasko52927e22020-03-16 17:26:14 +0100207 return ret;
208}
209
Michal Vasko44685da2020-03-17 15:38:06 +0100210static LY_ERR
Michal Vaskob36053d2020-03-26 15:49:30 +0100211lydxml_check_list(struct lyxml_ctx *xmlctx, const struct lysc_node *list)
Michal Vasko44685da2020-03-17 15:38:06 +0100212{
Michal Vaskob36053d2020-03-26 15:49:30 +0100213 LY_ERR ret = LY_SUCCESS, r;
214 enum LYXML_PARSER_STATUS next;
Michal Vasko44685da2020-03-17 15:38:06 +0100215 struct ly_set key_set = {0};
216 const struct lysc_node *snode;
Michal Vaskob36053d2020-03-26 15:49:30 +0100217 uint32_t i, parents_count;
Michal Vasko44685da2020-03-17 15:38:06 +0100218
219 assert(list && (list->nodetype == LYS_LIST));
220
221 /* get all keys into a set (keys do not have if-features or anything) */
222 snode = NULL;
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100223 while ((snode = lys_getnext(snode, list, NULL, 0)) && (snode->flags & LYS_KEY)) {
Radek Krejci3d92e442020-10-12 12:48:13 +0200224 ret = ly_set_add(&key_set, (void *)snode, 1, NULL);
Radek Krejciba03a5a2020-08-27 14:40:41 +0200225 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100226 }
227
Michal Vasko12d809c2021-03-03 16:34:32 +0100228 /* remember parent count */
229 parents_count = xmlctx->elements.count;
230
Michal Vaskob36053d2020-03-26 15:49:30 +0100231 while (xmlctx->status == LYXML_ELEMENT) {
Michal Vasko44685da2020-03-17 15:38:06 +0100232 /* find key definition */
233 for (i = 0; i < key_set.count; ++i) {
234 snode = (const struct lysc_node *)key_set.objs[i];
Michal Vaskob36053d2020-03-26 15:49:30 +0100235 if (!ly_strncmp(snode->name, xmlctx->name, xmlctx->name_len)) {
Michal Vasko44685da2020-03-17 15:38:06 +0100236 break;
237 }
238 }
Michal Vaskob36053d2020-03-26 15:49:30 +0100239 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100240
241 /* skip attributes */
242 while (xmlctx->status == LYXML_ATTRIBUTE) {
Michal Vaskob36053d2020-03-26 15:49:30 +0100243 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
244 assert(xmlctx->status == LYXML_ATTR_CONTENT);
245 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100246 }
247
Michal Vaskob36053d2020-03-26 15:49:30 +0100248 assert(xmlctx->status == LYXML_ELEM_CONTENT);
249 if (i < key_set.count) {
250 /* validate the value */
Radek Krejci8df109d2021-04-23 12:19:08 +0200251 r = lys_value_validate(NULL, snode, xmlctx->value, xmlctx->value_len, LY_VALUE_XML, &xmlctx->ns);
Michal Vaskob36053d2020-03-26 15:49:30 +0100252 if (!r) {
253 /* key with a valid value, remove from the set */
254 ly_set_rm_index(&key_set, i, NULL);
Michal Vasko44685da2020-03-17 15:38:06 +0100255 }
256 }
257
Michal Vaskob36053d2020-03-26 15:49:30 +0100258 /* parser next */
259 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100260
Michal Vaskob36053d2020-03-26 15:49:30 +0100261 /* skip any children, resursively */
Michal Vasko12d809c2021-03-03 16:34:32 +0100262 while (xmlctx->status == LYXML_ELEMENT) {
263 while (parents_count < xmlctx->elements.count) {
264 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
265 }
266 assert(xmlctx->status == LYXML_ELEM_CLOSE);
Michal Vaskob36053d2020-03-26 15:49:30 +0100267 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
268 }
269
270 /* parser next, but do not parse closing element of the list because it would remove its namespaces */
271 assert(xmlctx->status == LYXML_ELEM_CLOSE);
272 LY_CHECK_GOTO(ret = lyxml_ctx_peek(xmlctx, &next), cleanup);
273 if (next != LYXML_ELEM_CLOSE) {
274 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
275 }
Michal Vasko44685da2020-03-17 15:38:06 +0100276 }
277
278 if (key_set.count) {
Michal Vaskob36053d2020-03-26 15:49:30 +0100279 /* some keys are missing/did not validate */
Michal Vasko44685da2020-03-17 15:38:06 +0100280 ret = LY_ENOT;
Michal Vasko44685da2020-03-17 15:38:06 +0100281 }
282
283cleanup:
284 ly_set_erase(&key_set, NULL);
285 return ret;
286}
287
Michal Vasko1bf09392020-03-27 12:38:10 +0100288static LY_ERR
289lydxml_data_skip(struct lyxml_ctx *xmlctx)
290{
291 uint32_t parents_count;
292
293 /* remember current number of parents */
294 parents_count = xmlctx->elements.count;
295
296 /* skip after the content */
297 while (xmlctx->status != LYXML_ELEM_CONTENT) {
298 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
299 }
300 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
301
302 /* skip all children elements, recursively, if any */
303 while (parents_count < xmlctx->elements.count) {
304 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
305 }
306
307 /* close element */
308 assert(xmlctx->status == LYXML_ELEM_CLOSE);
309 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
310
311 return LY_SUCCESS;
312}
313
314static LY_ERR
Radek Krejci1798aae2020-07-14 13:26:06 +0200315lydxml_data_check_opaq(struct lyd_xml_ctx *lydctx, const struct lysc_node **snode)
Michal Vasko1bf09392020-03-27 12:38:10 +0100316{
317 LY_ERR ret = LY_SUCCESS;
318 enum LYXML_PARSER_STATUS prev_status;
Michal Vasko63f3d842020-07-08 10:10:14 +0200319 const char *prev_current, *pname, *pprefix;
Michal Vasko1bf09392020-03-27 12:38:10 +0100320 size_t pprefix_len, pname_len;
321 struct lyxml_ctx *xmlctx = lydctx->xmlctx;
322
Radek IÅ¡a3930fd72021-03-08 10:48:40 +0100323 if (!(lydctx->parse_opts & LYD_PARSE_OPAQ)) {
324 /* only checks specific to opaque nodes */
325 return LY_SUCCESS;
326 }
327
328 if ((*snode)->nodetype & (LYD_NODE_TERM | LYS_LIST)) {
Michal Vasko1bf09392020-03-27 12:38:10 +0100329 /* backup parser */
330 prev_status = xmlctx->status;
331 pprefix = xmlctx->prefix;
332 pprefix_len = xmlctx->prefix_len;
333 pname = xmlctx->name;
334 pname_len = xmlctx->name_len;
Michal Vasko63f3d842020-07-08 10:10:14 +0200335 prev_current = xmlctx->in->current;
Michal Vasko1bf09392020-03-27 12:38:10 +0100336 if ((xmlctx->status == LYXML_ELEM_CONTENT) && xmlctx->dynamic) {
337 /* it was backed up, do not free */
338 xmlctx->dynamic = 0;
339 }
340
341 /* skip attributes */
342 while (xmlctx->status == LYXML_ATTRIBUTE) {
343 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), restore);
344 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), restore);
345 }
346
347 if ((*snode)->nodetype & LYD_NODE_TERM) {
348 /* value may not be valid in which case we parse it as an opaque node */
Radek Krejci8df109d2021-04-23 12:19:08 +0200349 if (lys_value_validate(NULL, *snode, xmlctx->value, xmlctx->value_len, LY_VALUE_XML, &xmlctx->ns)) {
Michal Vasko1bf09392020-03-27 12:38:10 +0100350 *snode = NULL;
351 }
352 } else {
353 /* skip content */
354 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), restore);
355
356 if (lydxml_check_list(xmlctx, *snode)) {
357 /* invalid list, parse as opaque if it missing/has invalid some keys */
358 *snode = NULL;
359 }
360 }
361
362restore:
363 /* restore parser */
364 if (xmlctx->dynamic) {
365 free((char *)xmlctx->value);
366 }
367 xmlctx->status = prev_status;
368 xmlctx->prefix = pprefix;
369 xmlctx->prefix_len = pprefix_len;
370 xmlctx->name = pname;
371 xmlctx->name_len = pname_len;
Michal Vasko63f3d842020-07-08 10:10:14 +0200372 xmlctx->in->current = prev_current;
Radek IÅ¡a3930fd72021-03-08 10:48:40 +0100373 } else if ((*snode)->nodetype & LYD_NODE_INNER) {
374 /* if there is a non-WS value, it cannot be parsed as an inner node */
375 assert(xmlctx->status == LYXML_ELEM_CONTENT);
376 if (!xmlctx->ws_only) {
377 *snode = NULL;
378 }
379
Michal Vasko1bf09392020-03-27 12:38:10 +0100380 }
381
382 return ret;
383}
384
Radek Krejcie7b95092019-05-15 11:03:07 +0200385/**
Michal Vaskoa5da3292020-08-12 13:10:50 +0200386 * @brief Parse XML subtree.
Radek Krejcie7b95092019-05-15 11:03:07 +0200387 *
Michal Vaskob36053d2020-03-26 15:49:30 +0100388 * @param[in] lydctx XML YANG data parser context.
Michal Vaskoe0665742021-02-11 11:08:44 +0100389 * @param[in,out] parent Parent node where the children are inserted. NULL in case of parsing top-level elements.
390 * @param[in,out] first_p Pointer to the first (@p parent or top-level) child. In case there were already some siblings,
391 * this may point to a previously existing node.
392 * @param[in,out] parsed Optional set to add all the parsed siblings into.
Michal Vasko9b368d32020-02-14 13:53:31 +0100393 * @return LY_ERR value.
Radek Krejcie7b95092019-05-15 11:03:07 +0200394 */
395static LY_ERR
Michal Vaskoe0665742021-02-11 11:08:44 +0100396lydxml_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 +0200397{
Michal Vaskob36053d2020-03-26 15:49:30 +0100398 LY_ERR ret = LY_SUCCESS;
Michal Vasko27c4dce2021-03-04 15:50:50 +0100399 const char *prefix, *name, *val;
Michal Vasko1bf09392020-03-27 12:38:10 +0100400 size_t prefix_len, name_len;
Michal Vaskob36053d2020-03-26 15:49:30 +0100401 struct lyxml_ctx *xmlctx;
402 const struct ly_ctx *ctx;
Radek Krejcie7b95092019-05-15 11:03:07 +0200403 const struct lyxml_ns *ns;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200404 struct lyd_meta *meta = NULL;
405 struct lyd_attr *attr = NULL;
Radek Krejcie7b95092019-05-15 11:03:07 +0200406 const struct lysc_node *snode;
407 struct lys_module *mod;
Michal Vasko1bf09392020-03-27 12:38:10 +0100408 uint32_t prev_opts;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200409 struct lyd_node *node = NULL, *anchor;
Michal Vaskofc2cd072021-02-24 13:17:17 +0100410 void *val_prefix_data = NULL;
Radek Krejci8df109d2021-04-23 12:19:08 +0200411 LY_VALUE_FORMAT format;
Radek Krejci1deb5be2020-08-26 16:43:36 +0200412 uint32_t getnext_opts;
Radek Krejcie7b95092019-05-15 11:03:07 +0200413
Michal Vaskoe0665742021-02-11 11:08:44 +0100414 assert(parent || first_p);
415
Michal Vaskob36053d2020-03-26 15:49:30 +0100416 xmlctx = lydctx->xmlctx;
417 ctx = xmlctx->ctx;
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100418 getnext_opts = lydctx->int_opts & LYD_INTOPT_REPLY ? LYS_GETNEXT_OUTPUT : 0;
Michal Vasko6f4cbb62020-02-28 11:15:47 +0100419
Michal Vaskoa5da3292020-08-12 13:10:50 +0200420 assert(xmlctx->status == LYXML_ELEMENT);
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200421
Michal Vaskoa5da3292020-08-12 13:10:50 +0200422 /* remember element prefix and name */
423 prefix = xmlctx->prefix;
424 prefix_len = xmlctx->prefix_len;
425 name = xmlctx->name;
426 name_len = xmlctx->name_len;
427
428 /* get the element module */
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200429 ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200430 if (!ns) {
Radek Krejci422afb12021-03-04 16:38:16 +0100431 LOGVAL(ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)prefix_len, prefix);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200432 ret = LY_EVALID;
433 goto error;
434 }
435 mod = ly_ctx_get_module_implemented_ns(ctx, ns->uri);
436 if (!mod) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100437 if (lydctx->parse_opts & LYD_PARSE_STRICT) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100438 LOGVAL(ctx, LYVE_REFERENCE, "No module with namespace \"%s\" in the context.", ns->uri);
Michal Vasko90932a92020-02-12 14:33:03 +0100439 ret = LY_EVALID;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200440 goto error;
Radek Krejcie7b95092019-05-15 11:03:07 +0200441 }
Michal Vaskoe0665742021-02-11 11:08:44 +0100442 if (!(lydctx->parse_opts & LYD_PARSE_OPAQ)) {
Michal Vaskoa5da3292020-08-12 13:10:50 +0200443 /* skip element with children */
444 LY_CHECK_GOTO(ret = lydxml_data_skip(xmlctx), error);
445 return LY_SUCCESS;
Radek Krejcie7b95092019-05-15 11:03:07 +0200446 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200447 }
448
Michal Vaskoa5da3292020-08-12 13:10:50 +0200449 /* parser next */
450 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
Michal Vasko90932a92020-02-12 14:33:03 +0100451
Michal Vaskoa5da3292020-08-12 13:10:50 +0200452 /* get the schema node */
453 snode = NULL;
454 if (mod && (!parent || parent->schema)) {
Radek Krejcif16e2542021-02-17 15:39:23 +0100455 if (!parent && lydctx->ext) {
Radek Krejciba05eab2021-03-10 13:19:29 +0100456 snode = lysc_ext_find_node(lydctx->ext, mod, name, name_len, 0, getnext_opts);
Radek Krejcif16e2542021-02-17 15:39:23 +0100457 } else {
458 snode = lys_find_child(parent ? parent->schema : NULL, mod, name, name_len, 0, getnext_opts);
459 }
Michal Vaskoa5da3292020-08-12 13:10:50 +0200460 if (!snode) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100461 if (lydctx->parse_opts & LYD_PARSE_STRICT) {
462 if (parent) {
Radek Krejci422afb12021-03-04 16:38:16 +0100463 LOGVAL(ctx, LYVE_REFERENCE, "Node \"%.*s\" not found as a child of \"%s\" node.",
464 (int)name_len, name, parent->schema->name);
Radek Krejcif16e2542021-02-17 15:39:23 +0100465 } else if (lydctx->ext) {
466 if (lydctx->ext->argument) {
Radek Krejci422afb12021-03-04 16:38:16 +0100467 LOGVAL(ctx, LYVE_REFERENCE, "Node \"%.*s\" not found in the \"%s\" %s extension instance.",
468 (int)name_len, name, lydctx->ext->argument, lydctx->ext->def->name);
Radek Krejcif16e2542021-02-17 15:39:23 +0100469 } else {
Radek Krejci422afb12021-03-04 16:38:16 +0100470 LOGVAL(ctx, LYVE_REFERENCE, "Node \"%.*s\" not found in the %s extension instance.",
471 (int)name_len, name, lydctx->ext->def->name);
Radek Krejcif16e2542021-02-17 15:39:23 +0100472 }
Michal Vaskoe0665742021-02-11 11:08:44 +0100473 } else {
Radek Krejci422afb12021-03-04 16:38:16 +0100474 LOGVAL(ctx, LYVE_REFERENCE, "Node \"%.*s\" not found in the \"%s\" module.",
475 (int)name_len, name, mod->name);
Michal Vaskoe0665742021-02-11 11:08:44 +0100476 }
Michal Vaskoa5da3292020-08-12 13:10:50 +0200477 ret = LY_EVALID;
478 goto error;
Michal Vaskoe0665742021-02-11 11:08:44 +0100479 } else if (!(lydctx->parse_opts & LYD_PARSE_OPAQ)) {
Michal Vaskoa5da3292020-08-12 13:10:50 +0200480 /* skip element with children */
481 LY_CHECK_GOTO(ret = lydxml_data_skip(xmlctx), error);
482 return LY_SUCCESS;
483 }
484 } else {
485 /* check that schema node is valid and can be used */
486 LY_CHECK_GOTO(ret = lyd_parser_check_schema((struct lyd_ctx *)lydctx, snode), error);
487 LY_CHECK_GOTO(ret = lydxml_data_check_opaq(lydctx, &snode), error);
488 }
489 }
490
491 /* create metadata/attributes */
492 if (xmlctx->status == LYXML_ATTRIBUTE) {
493 if (snode) {
Michal Vaskofeca4fb2020-10-05 08:58:40 +0200494 ret = lydxml_metadata(lydctx, &meta);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200495 LY_CHECK_GOTO(ret, error);
496 } else {
Michal Vaskoe0665742021-02-11 11:08:44 +0100497 assert(lydctx->parse_opts & LYD_PARSE_OPAQ);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200498 ret = lydxml_attrs(xmlctx, &attr);
499 LY_CHECK_GOTO(ret, error);
500 }
501 }
502
503 assert(xmlctx->status == LYXML_ELEM_CONTENT);
504 if (!snode) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100505 assert(lydctx->parse_opts & LYD_PARSE_OPAQ);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200506
507 if (xmlctx->ws_only) {
508 /* ignore WS-only value */
Radek IÅ¡a017270d2021-02-16 10:26:15 +0100509 if (xmlctx->dynamic) {
510 free((char *) xmlctx->value);
511 }
512 xmlctx->dynamic = 0;
513 xmlctx->value = "";
Michal Vaskoa5da3292020-08-12 13:10:50 +0200514 xmlctx->value_len = 0;
Radek Krejci8df109d2021-04-23 12:19:08 +0200515 format = LY_VALUE_XML;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200516 } else {
517 /* get value prefixes */
Radek Krejci8df109d2021-04-23 12:19:08 +0200518 ret = ly_store_prefix_data(xmlctx->ctx, xmlctx->value, xmlctx->value_len, LY_VALUE_XML,
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100519 &xmlctx->ns, &format, &val_prefix_data);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200520 LY_CHECK_GOTO(ret, error);
521 }
522
523 /* create node */
Michal Vasko501af032020-11-11 20:27:44 +0100524 ret = lyd_create_opaq(ctx, name, name_len, prefix, prefix_len, ns->uri, strlen(ns->uri), xmlctx->value,
525 xmlctx->value_len, &xmlctx->dynamic, format, val_prefix_data, LYD_HINT_DATA, &node);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200526 LY_CHECK_GOTO(ret, error);
527
528 /* parser next */
529 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
530
531 /* process children */
532 while (xmlctx->status == LYXML_ELEMENT) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100533 ret = lydxml_subtree_r(lydctx, node, lyd_node_child_p(node), NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200534 LY_CHECK_GOTO(ret, error);
535 }
536 } else if (snode->nodetype & LYD_NODE_TERM) {
537 /* create node */
Michal Vasko22df3f02020-08-24 13:29:22 +0200538 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 +0200539 &xmlctx->dynamic, LY_VALUE_XML, &xmlctx->ns, LYD_HINT_DATA, &node), error);
Radek Krejciddace2c2021-01-08 11:30:56 +0100540 LOG_LOCSET(snode, node, NULL, NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200541
542 if (parent && (node->schema->flags & LYS_KEY)) {
543 /* check the key order, the anchor must never be a key */
Michal Vaskoe0665742021-02-11 11:08:44 +0100544 anchor = lyd_insert_get_next_anchor(lyd_child(parent), node);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200545 if (anchor && (anchor->schema->flags & LYS_KEY)) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100546 if (lydctx->parse_opts & LYD_PARSE_STRICT) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100547 LOGVAL(ctx, LYVE_DATA, "Invalid position of the key \"%s\" in a list.", node->schema->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200548 ret = LY_EVALID;
549 goto error;
550 } else {
551 LOGWRN(ctx, "Invalid position of the key \"%s\" in a list.", node->schema->name);
552 }
553 }
554 }
555
556 /* parser next */
557 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
558
559 /* no children expected */
560 if (xmlctx->status == LYXML_ELEMENT) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100561 LOGVAL(ctx, LYVE_SYNTAX, "Child element \"%.*s\" inside a terminal node \"%s\" found.",
Radek Krejci422afb12021-03-04 16:38:16 +0100562 (int)xmlctx->name_len, xmlctx->name, snode->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200563 ret = LY_EVALID;
564 goto error;
565 }
566 } else if (snode->nodetype & LYD_NODE_INNER) {
567 if (!xmlctx->ws_only) {
568 /* value in inner node */
Radek Krejci2efc45b2020-12-22 16:25:44 +0100569 LOGVAL(ctx, LYVE_SYNTAX, "Text value \"%.*s\" inside an inner node \"%s\" found.",
Radek Krejci422afb12021-03-04 16:38:16 +0100570 (int)xmlctx->value_len, xmlctx->value, snode->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200571 ret = LY_EVALID;
572 goto error;
573 }
574
575 /* create node */
576 ret = lyd_create_inner(snode, &node);
577 LY_CHECK_GOTO(ret, error);
578
Radek Krejciddace2c2021-01-08 11:30:56 +0100579 LOG_LOCSET(snode, node, NULL, NULL);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100580
Michal Vaskoa5da3292020-08-12 13:10:50 +0200581 /* parser next */
582 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
583
584 /* process children */
585 while (xmlctx->status == LYXML_ELEMENT) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100586 ret = lydxml_subtree_r(lydctx, node, lyd_node_child_p(node), NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200587 LY_CHECK_GOTO(ret, error);
588 }
589
590 if (snode->nodetype == LYS_LIST) {
591 /* check all keys exist */
592 LY_CHECK_GOTO(ret = lyd_parse_check_keys(node), error);
593 }
594
Michal Vaskoe0665742021-02-11 11:08:44 +0100595 if (!(lydctx->parse_opts & LYD_PARSE_ONLY)) {
Michal Vaskoa5da3292020-08-12 13:10:50 +0200596 /* new node validation, autodelete CANNOT occur, all nodes are new */
Michal Vaskoe0665742021-02-11 11:08:44 +0100597 ret = lyd_validate_new(lyd_node_child_p(node), snode, NULL, NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200598 LY_CHECK_GOTO(ret, error);
599
600 /* add any missing default children */
Radek Krejci4f2e3e52021-03-30 14:20:28 +0200601 ret = lyd_new_implicit_r(node, lyd_node_child_p(node), NULL, NULL, &lydctx->node_when, &lydctx->node_exts,
602 &lydctx->node_types, (lydctx->val_opts & LYD_VALIDATE_NO_STATE) ? LYD_IMPLICIT_NO_STATE : 0, NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200603 LY_CHECK_GOTO(ret, error);
604 }
605
606 if (snode->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) {
607 /* rememeber the RPC/action/notification */
608 lydctx->op_node = node;
609 }
610 } else if (snode->nodetype & LYD_NODE_ANY) {
Michal Vasko27c4dce2021-03-04 15:50:50 +0100611 if ((snode->nodetype == LYS_ANYDATA) && !xmlctx->ws_only) {
612 /* value in anydata node, we expect a tree */
613 LOGVAL(ctx, LYVE_SYNTAX, "Text value \"%.*s\" inside an anydata node \"%s\" found.",
Radek Krejci422afb12021-03-04 16:38:16 +0100614 (int)xmlctx->value_len < 20 ? xmlctx->value_len : 20, xmlctx->value, snode->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200615 ret = LY_EVALID;
616 goto error;
617 }
618
Michal Vasko27c4dce2021-03-04 15:50:50 +0100619 if (!xmlctx->ws_only) {
620 /* use an arbitrary text value for anyxml */
621 lydict_insert(xmlctx->ctx, xmlctx->value, xmlctx->value_len, &val);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200622
Michal Vasko27c4dce2021-03-04 15:50:50 +0100623 /* parser next */
624 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
625
626 /* create node */
627 ret = lyd_create_any(snode, val, LYD_ANYDATA_STRING, 1, &node);
628 LY_CHECK_GOTO(ret, error);
629 } else {
630 /* parser next */
631 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
632
633 /* parse any data tree with correct options */
634 prev_opts = lydctx->parse_opts;
635 lydctx->parse_opts &= ~LYD_PARSE_STRICT;
636 lydctx->parse_opts |= LYD_PARSE_OPAQ;
637 anchor = NULL;
638 while (xmlctx->status == LYXML_ELEMENT) {
639 ret = lydxml_subtree_r(lydctx, NULL, &anchor, NULL);
640 LY_CHECK_ERR_GOTO(ret, lydctx->parse_opts = prev_opts, error);
641 }
642 lydctx->parse_opts = prev_opts;
643
644 /* create node */
645 ret = lyd_create_any(snode, anchor, LYD_ANYDATA_DATATREE, 1, &node);
646 LY_CHECK_GOTO(ret, error);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200647 }
Michal Vaskoa5da3292020-08-12 13:10:50 +0200648 }
649 assert(node);
650
651 /* add/correct flags */
652 if (snode) {
Radek Krejci4f2e3e52021-03-30 14:20:28 +0200653 lyd_parse_set_data_flags(node, &lydctx->node_when, &lydctx->node_exts, &meta, lydctx->parse_opts);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200654 }
655
656 /* parser next */
657 assert(xmlctx->status == LYXML_ELEM_CLOSE);
658 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
659
660 /* add metadata/attributes */
661 if (snode) {
Michal Vasko871a0252020-11-11 18:35:24 +0100662 lyd_insert_meta(node, meta, 0);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200663 } else {
664 lyd_insert_attr(node, attr);
665 }
666
667 /* insert, keep first pointer correct */
Michal Vaskoe0665742021-02-11 11:08:44 +0100668 lyd_insert_node(parent, first_p, node);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200669 while (!parent && (*first_p)->prev->next) {
670 *first_p = (*first_p)->prev;
671 }
672
Michal Vaskoe0665742021-02-11 11:08:44 +0100673 /* rememeber a successfully parsed node */
674 if (parsed) {
675 ly_set_add(parsed, node, 1, NULL);
676 }
677
Radek Krejciddace2c2021-01-08 11:30:56 +0100678 LOG_LOCBACK(node ? 1 : 0, node ? 1 : 0, 0, 0);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200679 return LY_SUCCESS;
680
681error:
Radek Krejciddace2c2021-01-08 11:30:56 +0100682 LOG_LOCBACK(node ? 1 : 0, node ? 1 : 0, 0, 0);
Michal Vasko3a41dff2020-07-15 14:30:28 +0200683 lyd_free_meta_siblings(meta);
Radek Krejci011e4aa2020-09-04 15:22:31 +0200684 lyd_free_attr_siblings(ctx, attr);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200685 lyd_free_tree(node);
Radek Krejcie7b95092019-05-15 11:03:07 +0200686 return ret;
687}
688
Michal Vaskoe0665742021-02-11 11:08:44 +0100689/**
690 * @brief Parse a specific XML element into an opaque node.
691 *
692 * @param[in] xmlctx XML parser context.
693 * @param[in] name Name of the element.
694 * @param[in] uri URI of the element.
695 * @param[in] value Whether a value is expected in the element.
696 * @param[out] evnp Parsed envelope (opaque node).
697 * @return LY_SUCCESS on success.
698 * @return LY_ENOT if the specified element did not match.
699 * @return LY_ERR value on error.
700 */
Michal Vasko1bf09392020-03-27 12:38:10 +0100701static LY_ERR
Michal Vaskoe0665742021-02-11 11:08:44 +0100702lydxml_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 +0100703{
Michal Vaskoe0665742021-02-11 11:08:44 +0100704 LY_ERR rc = LY_SUCCESS;
705 const struct lyxml_ns *ns;
Radek Krejci1798aae2020-07-14 13:26:06 +0200706 struct lyd_attr *attr = NULL;
Michal Vasko1bf09392020-03-27 12:38:10 +0100707 const char *prefix;
708 size_t prefix_len;
709
Michal Vasko1bf09392020-03-27 12:38:10 +0100710 assert(xmlctx->status == LYXML_ELEMENT);
711 if (ly_strncmp(name, xmlctx->name, xmlctx->name_len)) {
712 /* not the expected element */
Michal Vaskoe0665742021-02-11 11:08:44 +0100713 return LY_ENOT;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100714 }
715
716 prefix = xmlctx->prefix;
717 prefix_len = xmlctx->prefix_len;
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200718 ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100719 if (!ns) {
Radek Krejci422afb12021-03-04 16:38:16 +0100720 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)prefix_len, prefix);
Michal Vaskoe0665742021-02-11 11:08:44 +0100721 return LY_EVALID;
722 } else if (strcmp(ns->uri, uri)) {
723 /* different namespace */
724 return LY_ENOT;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100725 }
726
727 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
728
729 /* create attributes */
730 if (xmlctx->status == LYXML_ATTRIBUTE) {
731 LY_CHECK_RET(lydxml_attrs(xmlctx, &attr));
732 }
733
Michal Vaskoe0665742021-02-11 11:08:44 +0100734 assert(xmlctx->status == LYXML_ELEM_CONTENT);
735 if (!value && !xmlctx->ws_only) {
736 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected value \"%.*s\" in the \"%s\" element.",
Radek Krejci422afb12021-03-04 16:38:16 +0100737 (int)xmlctx->value_len, xmlctx->value, name);
Michal Vaskoe0665742021-02-11 11:08:44 +0100738 rc = LY_EVALID;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100739 goto cleanup;
Michal Vaskoe0665742021-02-11 11:08:44 +0100740 }
Michal Vaskoa8edff02020-03-27 14:47:01 +0100741
742 /* create node */
Michal Vaskoe0665742021-02-11 11:08:44 +0100743 rc = lyd_create_opaq(xmlctx->ctx, name, strlen(name), prefix, prefix_len, uri, strlen(uri), xmlctx->value,
Radek Krejci8df109d2021-04-23 12:19:08 +0200744 xmlctx->ws_only ? 0 : xmlctx->value_len, NULL, LY_VALUE_XML, NULL, 0, envp);
Michal Vaskoe0665742021-02-11 11:08:44 +0100745 LY_CHECK_GOTO(rc, cleanup);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100746
747 /* assign atributes */
Michal Vaskoe0665742021-02-11 11:08:44 +0100748 ((struct lyd_node_opaq *)(*envp))->attr = attr;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100749 attr = NULL;
750
Michal Vaskoe0665742021-02-11 11:08:44 +0100751 /* parser next element */
752 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100753
Michal Vaskoe0665742021-02-11 11:08:44 +0100754cleanup:
755 lyd_free_attr_siblings(xmlctx->ctx, attr);
756 if (rc) {
757 lyd_free_tree(*envp);
758 *envp = NULL;
759 }
760 return rc;
761}
762
763/**
764 * @brief Parse all expected non-data XML elements of a NETCONF rpc message.
765 *
766 * @param[in] xmlctx XML parser context.
767 * @param[out] evnp Parsed envelope(s) (opaque node).
768 * @param[out] int_opts Internal options for parsing the rest of YANG data.
769 * @param[out] close_elem Number of parsed opened elements that need to be closed.
770 * @return LY_SUCCESS on success.
771 * @return LY_ERR value on error.
772 */
773static LY_ERR
774lydxml_env_netconf_rpc(struct lyxml_ctx *xmlctx, struct lyd_node **envp, uint32_t *int_opts, uint32_t *close_elem)
775{
776 LY_ERR rc = LY_SUCCESS, r;
777 struct lyd_node *child;
778
779 assert(envp && !*envp);
780
781 /* parse "rpc" */
782 r = lydxml_envelope(xmlctx, "rpc", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, envp);
Michal Vaskoe0665742021-02-11 11:08:44 +0100783 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
784
785 /* parse "action", if any */
786 r = lydxml_envelope(xmlctx, "action", "urn:ietf:params:xml:ns:yang:1", 0, &child);
787 if (r == LY_SUCCESS) {
788 /* insert */
789 lyd_insert_node(*envp, NULL, child);
790
791 /* NETCONF action */
792 *int_opts = LYD_INTOPT_NO_SIBLINGS | LYD_INTOPT_ACTION;
793 *close_elem = 2;
794 } else if (r == LY_ENOT) {
795 /* NETCONF RPC */
796 *int_opts = LYD_INTOPT_NO_SIBLINGS | LYD_INTOPT_RPC;
797 *close_elem = 1;
798 } else {
799 rc = r;
800 goto cleanup;
801 }
802
803cleanup:
804 if (rc) {
805 lyd_free_tree(*envp);
806 *envp = NULL;
807 }
808 return rc;
809}
810
811/**
812 * @brief Parse all expected non-data XML elements of a NETCONF notification message.
813 *
814 * @param[in] xmlctx XML parser context.
815 * @param[out] evnp Parsed envelope(s) (opaque node).
816 * @param[out] int_opts Internal options for parsing the rest of YANG data.
817 * @param[out] close_elem Number of parsed opened elements that need to be closed.
818 * @return LY_SUCCESS on success.
819 * @return LY_ERR value on error.
820 */
821static LY_ERR
822lydxml_env_netconf_notif(struct lyxml_ctx *xmlctx, struct lyd_node **envp, uint32_t *int_opts, uint32_t *close_elem)
823{
824 LY_ERR rc = LY_SUCCESS, r;
825 struct lyd_node *child;
826
827 assert(envp && !*envp);
828
829 /* parse "notification" */
830 r = lydxml_envelope(xmlctx, "notification", "urn:ietf:params:xml:ns:netconf:notification:1.0", 0, envp);
Michal Vaskoe0665742021-02-11 11:08:44 +0100831 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
832
833 /* parse "eventTime" */
834 r = lydxml_envelope(xmlctx, "eventTime", "urn:ietf:params:xml:ns:netconf:notification:1.0", 1, &child);
835 if (r == LY_ENOT) {
Radek Krejci422afb12021-03-04 16:38:16 +0100836 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unexpected element \"%.*s\" instead of \"eventTime\".",
837 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +0100838 r = LY_EVALID;
839 }
840 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
841
842 /* insert */
843 lyd_insert_node(*envp, NULL, child);
844
845 /* validate value */
846 /* TODO validate child->value as yang:date-and-time */
847
848 /* finish child parsing */
Michal Vaskoa8edff02020-03-27 14:47:01 +0100849 if (xmlctx->status != LYXML_ELEM_CLOSE) {
850 assert(xmlctx->status == LYXML_ELEMENT);
Michal Vaskoe0665742021-02-11 11:08:44 +0100851 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"eventTime\".",
Radek Krejci422afb12021-03-04 16:38:16 +0100852 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +0100853 rc = LY_EVALID;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100854 goto cleanup;
855 }
Michal Vaskoe0665742021-02-11 11:08:44 +0100856 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
857
858 /* NETCONF notification */
859 *int_opts = LYD_INTOPT_NO_SIBLINGS | LYD_INTOPT_NOTIF;
860 *close_elem = 1;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100861
862cleanup:
Michal Vaskoe0665742021-02-11 11:08:44 +0100863 if (rc) {
Michal Vaskoa8edff02020-03-27 14:47:01 +0100864 lyd_free_tree(*envp);
Michal Vaskoe0665742021-02-11 11:08:44 +0100865 *envp = NULL;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100866 }
Michal Vaskoe0665742021-02-11 11:08:44 +0100867 return rc;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100868}
Michal Vasko79135ae2020-12-16 10:08:35 +0100869
Michal Vaskoe0665742021-02-11 11:08:44 +0100870/**
871 * @brief Parse an XML element as an opaque node subtree.
872 *
873 * @param[in] xmlctx XML parser context.
874 * @param[in] parent Parent to append nodes to.
875 * @return LY_ERR value.
876 */
877static LY_ERR
878lydxml_opaq_r(struct lyxml_ctx *xmlctx, struct lyd_node *parent)
Michal Vaskoa8edff02020-03-27 14:47:01 +0100879{
Michal Vaskoe0665742021-02-11 11:08:44 +0100880 LY_ERR rc = LY_SUCCESS;
881 const struct lyxml_ns *ns;
882 struct lyd_attr *attr = NULL;
883 struct lyd_node *child = NULL;
884 const char *name, *prefix;
885 size_t name_len, prefix_len;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100886
Michal Vaskoe0665742021-02-11 11:08:44 +0100887 assert(xmlctx->status == LYXML_ELEMENT);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100888
Michal Vaskoe0665742021-02-11 11:08:44 +0100889 name = xmlctx->name;
890 name_len = xmlctx->name_len;
891 prefix = xmlctx->prefix;
892 prefix_len = xmlctx->prefix_len;
893 ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
894 if (!ns) {
Radek Krejci422afb12021-03-04 16:38:16 +0100895 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)prefix_len, prefix);
Michal Vaskoe0665742021-02-11 11:08:44 +0100896 return LY_EVALID;
897 }
Michal Vaskoa8edff02020-03-27 14:47:01 +0100898
Michal Vaskoe0665742021-02-11 11:08:44 +0100899 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
Michal Vaskoa8edff02020-03-27 14:47:01 +0100900
Michal Vaskoe0665742021-02-11 11:08:44 +0100901 /* create attributes */
902 if (xmlctx->status == LYXML_ATTRIBUTE) {
903 LY_CHECK_RET(lydxml_attrs(xmlctx, &attr));
904 }
905
906 /* create node */
907 assert(xmlctx->status == LYXML_ELEM_CONTENT);
908 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 +0200909 xmlctx->ws_only ? 0 : xmlctx->value_len, NULL, LY_VALUE_XML, NULL, 0, &child);
Michal Vaskoe0665742021-02-11 11:08:44 +0100910 LY_CHECK_GOTO(rc, cleanup);
911
912 /* assign atributes */
913 ((struct lyd_node_opaq *)child)->attr = attr;
914 attr = NULL;
915
916 /* parser next element */
917 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
918
919 /* parse all the descendants */
920 while (xmlctx->status == LYXML_ELEMENT) {
921 rc = lydxml_opaq_r(xmlctx, child);
922 LY_CHECK_GOTO(rc, cleanup);
923 }
924
925 /* insert */
926 lyd_insert_node(parent, NULL, child);
927
928cleanup:
929 lyd_free_attr_siblings(xmlctx->ctx, attr);
930 if (rc) {
931 lyd_free_tree(child);
932 }
933 return rc;
934}
935
936/**
937 * @brief Parse all expected non-data XML elements of the error-info element in NETCONF rpc-reply message.
938 *
939 * @param[in] xmlctx XML parser context.
940 * @param[in] parent Parent to append nodes to.
941 * @return LY_ERR value.
942 */
943static LY_ERR
944lydxml_env_netconf_rpc_reply_error_info(struct lyxml_ctx *xmlctx, struct lyd_node *parent)
945{
946 LY_ERR r;
947 struct lyd_node *child, *iter;
948 const struct lyxml_ns *ns;
949 ly_bool no_dup;
950
951 /* there must be some child */
952 if (xmlctx->status == LYXML_ELEM_CLOSE) {
953 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Missing child elements of \"error-info\".");
954 return LY_EVALID;
955 }
956
957 while (xmlctx->status == LYXML_ELEMENT) {
958 child = NULL;
959
960 /*
961 * session-id
962 */
963 r = lydxml_envelope(xmlctx, "session-id", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
964 if (r == LY_SUCCESS) {
965 no_dup = 1;
966 goto check_child;
967 } else if (r != LY_ENOT) {
968 goto error;
969 }
970
971 /*
972 * bad-attribute
973 */
974 r = lydxml_envelope(xmlctx, "bad-attribute", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
975 if (r == LY_SUCCESS) {
976 no_dup = 1;
977 goto check_child;
978 } else if (r != LY_ENOT) {
979 goto error;
980 }
981
982 /*
983 * bad-element
984 */
985 r = lydxml_envelope(xmlctx, "bad-element", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
986 if (r == LY_SUCCESS) {
987 no_dup = 1;
988 goto check_child;
989 } else if (r != LY_ENOT) {
990 goto error;
991 }
992
993 /*
994 * bad-namespace
995 */
996 r = lydxml_envelope(xmlctx, "bad-namespace", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
997 if (r == LY_SUCCESS) {
998 no_dup = 1;
999 goto check_child;
1000 } else if (r != LY_ENOT) {
1001 goto error;
1002 }
1003
1004 if (r == LY_ENOT) {
1005 assert(xmlctx->status == LYXML_ELEMENT);
1006
1007 /* learn namespace */
1008 ns = lyxml_ns_get(&xmlctx->ns, xmlctx->prefix, xmlctx->prefix_len);
1009 if (!ns) {
Radek Krejci422afb12021-03-04 16:38:16 +01001010 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)xmlctx->prefix_len, xmlctx->prefix);
Michal Vaskoe0665742021-02-11 11:08:44 +01001011 r = LY_EVALID;
1012 goto error;
1013 } else if (!strcmp(ns->uri, "urn:ietf:params:xml:ns:netconf:base:1.0")) {
1014 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"error-info\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001015 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001016 r = LY_EVALID;
1017 goto error;
1018 }
1019
1020 /* custom elements */
1021 r = lydxml_opaq_r(xmlctx, parent);
1022 LY_CHECK_GOTO(r, error);
1023
1024 no_dup = 0;
1025 }
1026
1027check_child:
1028 /* check for duplicates */
1029 if (no_dup) {
1030 LY_LIST_FOR(lyd_child(parent), iter) {
1031 if ((((struct lyd_node_opaq *)iter)->name.name == ((struct lyd_node_opaq *)child)->name.name) &&
1032 (((struct lyd_node_opaq *)iter)->name.module_ns == ((struct lyd_node_opaq *)child)->name.module_ns)) {
1033 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Duplicate element \"%s\" in \"error-info\".",
1034 ((struct lyd_node_opaq *)child)->name.name);
1035 r = LY_EVALID;
1036 goto error;
1037 }
1038 }
1039 }
1040
1041 /* finish child parsing */
1042 if (xmlctx->status != LYXML_ELEM_CLOSE) {
1043 assert(xmlctx->status == LYXML_ELEMENT);
1044 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"error-info\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001045 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001046 r = LY_EVALID;
1047 goto error;
1048 }
1049 LY_CHECK_GOTO(r = lyxml_ctx_next(xmlctx), error);
1050
1051 /* insert */
1052 lyd_insert_node(parent, NULL, child);
1053 }
1054
1055 return LY_SUCCESS;
1056
1057error:
1058 lyd_free_tree(child);
1059 return r;
1060}
1061
1062/**
1063 * @brief Parse all expected non-data XML elements of the rpc-error element in NETCONF rpc-reply message.
1064 *
1065 * @param[in] xmlctx XML parser context.
1066 * @param[in] parent Parent to append nodes to.
1067 * @return LY_ERR value.
1068 */
1069static LY_ERR
1070lydxml_env_netconf_rpc_reply_error(struct lyxml_ctx *xmlctx, struct lyd_node *parent)
1071{
1072 LY_ERR r;
1073 struct lyd_node *child, *iter;
1074 const char *val;
1075 ly_bool no_dup;
1076
1077 /* there must be some child */
1078 if (xmlctx->status == LYXML_ELEM_CLOSE) {
1079 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Missing child elements of \"rpc-error\".");
1080 return LY_EVALID;
1081 }
1082
1083 while (xmlctx->status == LYXML_ELEMENT) {
1084 child = NULL;
1085
1086 /*
1087 * error-type
1088 */
1089 r = lydxml_envelope(xmlctx, "error-type", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1090 if (r == LY_SUCCESS) {
1091 val = ((struct lyd_node_opaq *)child)->value;
1092 if (strcmp(val, "transport") && strcmp(val, "rpc") && strcmp(val, "protocol") && strcmp(val, "application")) {
1093 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Invalid value \"%s\" of element \"%s\".", val,
1094 ((struct lyd_node_opaq *)child)->name.name);
1095 r = LY_EVALID;
1096 goto error;
1097 }
1098
1099 no_dup = 1;
1100 goto check_child;
1101 } else if (r != LY_ENOT) {
1102 goto error;
1103 }
1104
1105 /*
1106 * error-tag
1107 */
1108 r = lydxml_envelope(xmlctx, "error-tag", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1109 if (r == LY_SUCCESS) {
1110 val = ((struct lyd_node_opaq *)child)->value;
1111 if (strcmp(val, "in-use") && strcmp(val, "invalid-value") && strcmp(val, "too-big") &&
1112 strcmp(val, "missing-attribute") && strcmp(val, "bad-attribute") &&
1113 strcmp(val, "unknown-attribute") && strcmp(val, "missing-element") && strcmp(val, "bad-element") &&
1114 strcmp(val, "unknown-element") && strcmp(val, "unknown-namespace") && strcmp(val, "access-denied") &&
1115 strcmp(val, "lock-denied") && strcmp(val, "resource-denied") && strcmp(val, "rollback-failed") &&
1116 strcmp(val, "data-exists") && strcmp(val, "data-missing") && strcmp(val, "operation-not-supported") &&
1117 strcmp(val, "operation-failed") && strcmp(val, "malformed-message")) {
1118 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Invalid value \"%s\" of element \"%s\".", val,
1119 ((struct lyd_node_opaq *)child)->name.name);
1120 r = LY_EVALID;
1121 goto error;
1122 }
1123
1124 no_dup = 1;
1125 goto check_child;
1126 } else if (r != LY_ENOT) {
1127 goto error;
1128 }
1129
1130 /*
1131 * error-severity
1132 */
1133 r = lydxml_envelope(xmlctx, "error-severity", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1134 if (r == LY_SUCCESS) {
1135 val = ((struct lyd_node_opaq *)child)->value;
1136 if (strcmp(val, "error") && strcmp(val, "warning")) {
1137 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Invalid value \"%s\" of element \"%s\".", val,
1138 ((struct lyd_node_opaq *)child)->name.name);
1139 r = LY_EVALID;
1140 goto error;
1141 }
1142
1143 no_dup = 1;
1144 goto check_child;
1145 } else if (r != LY_ENOT) {
1146 goto error;
1147 }
1148
1149 /*
1150 * error-app-tag
1151 */
1152 r = lydxml_envelope(xmlctx, "error-app-tag", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1153 if (r == LY_SUCCESS) {
1154 no_dup = 1;
1155 goto check_child;
1156 } else if (r != LY_ENOT) {
1157 goto error;
1158 }
1159
1160 /*
1161 * error-path
1162 */
1163 r = lydxml_envelope(xmlctx, "error-path", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1164 if (r == LY_SUCCESS) {
1165 no_dup = 1;
1166 goto check_child;
1167 } else if (r != LY_ENOT) {
1168 goto error;
1169 }
1170
1171 /*
1172 * error-message
1173 */
1174 r = lydxml_envelope(xmlctx, "error-message", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1175 if (r == LY_SUCCESS) {
1176 no_dup = 1;
1177 goto check_child;
1178 } else if (r != LY_ENOT) {
1179 goto error;
1180 }
1181
1182 /* error-info */
1183 r = lydxml_envelope(xmlctx, "error-info", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, &child);
1184 if (r == LY_SUCCESS) {
1185 /* parse all the descendants */
1186 LY_CHECK_GOTO(r = lydxml_env_netconf_rpc_reply_error_info(xmlctx, child), error);
1187
1188 no_dup = 0;
1189 goto check_child;
1190 } else if (r != LY_ENOT) {
1191 goto error;
1192 }
1193
1194 if (r == LY_ENOT) {
1195 assert(xmlctx->status == LYXML_ELEMENT);
1196 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"rpc-error\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001197 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001198 r = LY_EVALID;
1199 goto error;
1200 }
1201
1202check_child:
1203 /* check for duplicates */
1204 if (no_dup) {
1205 LY_LIST_FOR(lyd_child(parent), iter) {
1206 if ((((struct lyd_node_opaq *)iter)->name.name == ((struct lyd_node_opaq *)child)->name.name) &&
1207 (((struct lyd_node_opaq *)iter)->name.module_ns == ((struct lyd_node_opaq *)child)->name.module_ns)) {
1208 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Duplicate element \"%s\" in \"rpc-error\".",
1209 ((struct lyd_node_opaq *)child)->name.name);
1210 r = LY_EVALID;
1211 goto error;
1212 }
1213 }
1214 }
1215
1216 /* finish child parsing */
1217 if (xmlctx->status != LYXML_ELEM_CLOSE) {
1218 assert(xmlctx->status == LYXML_ELEMENT);
1219 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"rpc-error\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001220 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001221 r = LY_EVALID;
1222 goto error;
1223 }
1224 LY_CHECK_GOTO(r = lyxml_ctx_next(xmlctx), error);
1225
1226 /* insert */
1227 lyd_insert_node(parent, NULL, child);
1228 }
1229
1230 return LY_SUCCESS;
1231
1232error:
1233 lyd_free_tree(child);
1234 return r;
1235}
1236
1237/**
1238 * @brief Parse all expected non-data XML elements of a NETCONF rpc-reply message.
1239 *
1240 * @param[in] xmlctx XML parser context.
1241 * @param[out] evnp Parsed envelope(s) (opaque node).
1242 * @param[out] int_opts Internal options for parsing the rest of YANG data.
1243 * @param[out] close_elem Number of parsed opened elements that need to be closed.
1244 * @return LY_SUCCESS on success.
1245 * @return LY_ERR value on error.
1246 */
1247static LY_ERR
1248lydxml_env_netconf_reply(struct lyxml_ctx *xmlctx, struct lyd_node **envp, uint32_t *int_opts, uint32_t *close_elem)
1249{
1250 LY_ERR rc = LY_SUCCESS, r;
1251 struct lyd_node *child = NULL;
1252 const char *parsed_elem = NULL;
1253
1254 assert(envp && !*envp);
1255
1256 /* parse "rpc-reply" */
1257 r = lydxml_envelope(xmlctx, "rpc-reply", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, envp);
Michal Vaskoe0665742021-02-11 11:08:44 +01001258 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
1259
1260 /* there must be some child */
1261 if (xmlctx->status == LYXML_ELEM_CLOSE) {
1262 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Missing child elements of \"rpc-reply\".");
1263 rc = LY_EVALID;
Michal Vaskocf770e22020-08-12 13:21:43 +02001264 goto cleanup;
Michal Vaskoa8edff02020-03-27 14:47:01 +01001265 }
1266
Michal Vaskoe0665742021-02-11 11:08:44 +01001267 /* try to parse "ok" */
1268 r = lydxml_envelope(xmlctx, "ok", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, &child);
1269 if (r == LY_SUCCESS) {
1270 /* insert */
1271 lyd_insert_node(*envp, NULL, child);
1272
1273 /* finish child parsing */
1274 if (xmlctx->status != LYXML_ELEM_CLOSE) {
1275 assert(xmlctx->status == LYXML_ELEMENT);
1276 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"ok\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001277 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001278 rc = LY_EVALID;
1279 goto cleanup;
1280 }
1281 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
1282
1283 /* success */
1284 parsed_elem = "ok";
1285 goto finish;
1286 } else if (r != LY_ENOT) {
1287 rc = r;
1288 goto cleanup;
Michal Vasko2552ea32020-12-08 15:32:34 +01001289 }
1290
Michal Vaskoe0665742021-02-11 11:08:44 +01001291 /* try to parse all "rpc-error" elements */
1292 while (xmlctx->status == LYXML_ELEMENT) {
1293 r = lydxml_envelope(xmlctx, "rpc-error", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, &child);
1294 if (r == LY_ENOT) {
1295 break;
1296 } else if (r) {
1297 rc = r;
1298 goto cleanup;
1299 }
1300
1301 /* insert */
1302 lyd_insert_node(*envp, NULL, child);
1303
1304 /* parse all children of "rpc-error" */
1305 LY_CHECK_GOTO(rc = lydxml_env_netconf_rpc_reply_error(xmlctx, child), cleanup);
1306
1307 /* finish child parsing */
1308 assert(xmlctx->status == LYXML_ELEM_CLOSE);
1309 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
1310
1311 parsed_elem = "rpc-error";
Michal Vasko2552ea32020-12-08 15:32:34 +01001312 }
Michal Vaskoe0665742021-02-11 11:08:44 +01001313
1314finish:
1315 if (parsed_elem) {
1316 /* NETCONF rpc-reply with no data */
1317 if (xmlctx->status != LYXML_ELEM_CLOSE) {
1318 assert(xmlctx->status == LYXML_ELEMENT);
1319 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected sibling element \"%.*s\" of \"%s\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001320 (int)xmlctx->name_len, xmlctx->name, parsed_elem);
Michal Vaskoe0665742021-02-11 11:08:44 +01001321 rc = LY_EVALID;
1322 goto cleanup;
1323 }
1324 }
1325
1326 /* NETCONF rpc-reply */
1327 *int_opts = LYD_INTOPT_NO_SIBLINGS | LYD_INTOPT_REPLY;
1328 *close_elem = 1;
1329
1330cleanup:
1331 if (rc) {
1332 lyd_free_tree(*envp);
1333 *envp = NULL;
1334 }
1335 return rc;
1336}
1337
Michal Vasko2552ea32020-12-08 15:32:34 +01001338LY_ERR
Radek Krejcif16e2542021-02-17 15:39:23 +01001339lyd_parse_xml(const struct ly_ctx *ctx, const struct lysc_ext_instance *ext, struct lyd_node *parent,
1340 struct lyd_node **first_p, struct ly_in *in, uint32_t parse_opts, uint32_t val_opts, enum lyd_type data_type,
1341 struct lyd_node **envp, struct ly_set *parsed, struct lyd_ctx **lydctx_p)
Michal Vasko2552ea32020-12-08 15:32:34 +01001342{
Michal Vaskoe0665742021-02-11 11:08:44 +01001343 LY_ERR rc = LY_SUCCESS;
1344 struct lyd_xml_ctx *lydctx;
1345 uint32_t i, int_opts, close_elem = 0;
1346 ly_bool parsed_data_nodes = 0;
Michal Vasko2552ea32020-12-08 15:32:34 +01001347
Michal Vaskoe0665742021-02-11 11:08:44 +01001348 assert(ctx && in && lydctx_p);
1349 assert(!(parse_opts & ~LYD_PARSE_OPTS_MASK));
1350 assert(!(val_opts & ~LYD_VALIDATE_OPTS_MASK));
Michal Vasko2552ea32020-12-08 15:32:34 +01001351
Michal Vaskoe0665742021-02-11 11:08:44 +01001352 /* init context */
1353 lydctx = calloc(1, sizeof *lydctx);
1354 LY_CHECK_ERR_RET(!lydctx, LOGMEM(ctx), LY_EMEM);
1355 LY_CHECK_GOTO(rc = lyxml_ctx_new(ctx, in, &lydctx->xmlctx), cleanup);
1356 lydctx->parse_opts = parse_opts;
1357 lydctx->val_opts = val_opts;
1358 lydctx->free = lyd_xml_ctx_free;
Radek Krejcif16e2542021-02-17 15:39:23 +01001359 lydctx->ext = ext;
Michal Vasko2552ea32020-12-08 15:32:34 +01001360
Michal Vaskoe0665742021-02-11 11:08:44 +01001361 switch (data_type) {
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001362 case LYD_TYPE_DATA_YANG:
Michal Vaskoe0665742021-02-11 11:08:44 +01001363 int_opts = LYD_INTOPT_WITH_SIBLINGS;
1364 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001365 case LYD_TYPE_RPC_YANG:
Michal Vaskoe0665742021-02-11 11:08:44 +01001366 int_opts = LYD_INTOPT_RPC | LYD_INTOPT_ACTION | LYD_INTOPT_NO_SIBLINGS;
1367 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001368 case LYD_TYPE_NOTIF_YANG:
Michal Vaskoe0665742021-02-11 11:08:44 +01001369 int_opts = LYD_INTOPT_NOTIF | LYD_INTOPT_NO_SIBLINGS;
1370 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001371 case LYD_TYPE_REPLY_YANG:
Michal Vaskoe0665742021-02-11 11:08:44 +01001372 int_opts = LYD_INTOPT_REPLY | LYD_INTOPT_NO_SIBLINGS;
1373 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001374 case LYD_TYPE_RPC_NETCONF:
Michal Vaskoe0665742021-02-11 11:08:44 +01001375 assert(!parent);
1376 LY_CHECK_GOTO(rc = lydxml_env_netconf_rpc(lydctx->xmlctx, envp, &int_opts, &close_elem), cleanup);
1377 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001378 case LYD_TYPE_NOTIF_NETCONF:
1379 assert(!parent);
1380 LY_CHECK_GOTO(rc = lydxml_env_netconf_notif(lydctx->xmlctx, envp, &int_opts, &close_elem), cleanup);
1381 break;
1382 case LYD_TYPE_REPLY_NETCONF:
Michal Vaskoe0665742021-02-11 11:08:44 +01001383 assert(parent);
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001384 LY_CHECK_GOTO(rc = lydxml_env_netconf_reply(lydctx->xmlctx, envp, &int_opts, &close_elem), cleanup);
Michal Vaskoe0665742021-02-11 11:08:44 +01001385 break;
1386 }
1387 lydctx->int_opts = int_opts;
1388
1389 /* find the operation node if it exists already */
1390 LY_CHECK_GOTO(rc = lyd_parser_find_operation(parent, int_opts, &lydctx->op_node), cleanup);
1391
1392 /* parse XML data */
1393 while (lydctx->xmlctx->status == LYXML_ELEMENT) {
1394 LY_CHECK_GOTO(rc = lydxml_subtree_r(lydctx, parent, first_p, parsed), cleanup);
1395 parsed_data_nodes = 1;
1396
1397 if (!(int_opts & LYD_INTOPT_WITH_SIBLINGS)) {
1398 break;
1399 }
Michal Vasko2552ea32020-12-08 15:32:34 +01001400 }
1401
Michal Vaskoe0665742021-02-11 11:08:44 +01001402 /* close all opened elements */
1403 for (i = 0; i < close_elem; ++i) {
1404 if (lydctx->xmlctx->status != LYXML_ELEM_CLOSE) {
1405 assert(lydctx->xmlctx->status == LYXML_ELEMENT);
Radek Krejci422afb12021-03-04 16:38:16 +01001406 LOGVAL(lydctx->xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\".",
1407 (int)lydctx->xmlctx->name_len, lydctx->xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001408 rc = LY_EVALID;
1409 goto cleanup;
1410 }
1411
1412 LY_CHECK_GOTO(rc = lyxml_ctx_next(lydctx->xmlctx), cleanup);
Michal Vasko4189c0f2020-08-13 09:05:22 +02001413 }
Michal Vaskoe0665742021-02-11 11:08:44 +01001414
1415 /* check final state */
1416 if ((int_opts & LYD_INTOPT_NO_SIBLINGS) && (lydctx->xmlctx->status == LYXML_ELEMENT)) {
1417 LOGVAL(ctx, LYVE_SYNTAX, "Unexpected sibling node.");
1418 rc = LY_EVALID;
1419 goto cleanup;
1420 }
1421 if ((int_opts & (LYD_INTOPT_RPC | LYD_INTOPT_NOTIF | LYD_INTOPT_REPLY)) && !lydctx->op_node) {
1422 LOGVAL(ctx, LYVE_DATA, "Missing the operation node.");
1423 rc = LY_EVALID;
1424 goto cleanup;
1425 }
1426
1427 if (!parsed_data_nodes) {
1428 /* no data nodes were parsed */
1429 lydctx->op_node = NULL;
Michal Vaskoa8edff02020-03-27 14:47:01 +01001430 }
1431
1432cleanup:
Michal Vaskoe0665742021-02-11 11:08:44 +01001433 /* there should be no unres stored if validation should be skipped */
1434 assert(!(parse_opts & LYD_PARSE_ONLY) || (!lydctx->node_types.count && !lydctx->meta_types.count &&
Radek Krejci4f2e3e52021-03-30 14:20:28 +02001435 !lydctx->node_when.count && !lydctx->node_exts.count));
Michal Vaskoe0665742021-02-11 11:08:44 +01001436
1437 if (rc) {
1438 lyd_xml_ctx_free((struct lyd_ctx *)lydctx);
1439 } else {
1440 *lydctx_p = (struct lyd_ctx *)lydctx;
1441
1442 /* the XML context is no more needed, freeing it also stops logging line numbers which would be confusing now */
1443 lyxml_ctx_free(lydctx->xmlctx);
1444 lydctx->xmlctx = NULL;
Michal Vasko1ce933a2020-03-30 12:38:22 +02001445 }
Michal Vaskoe0665742021-02-11 11:08:44 +01001446 return rc;
Michal Vasko1ce933a2020-03-30 12:38:22 +02001447}