blob: 158bb6b938d36b1abf50238e4f4e3d4bc83cd770 [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"
Michal Vaskoafac7822020-10-20 14:22:26 +020022#include "in_internal.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020023#include "log.h"
Radek Krejci7931b192020-06-25 17:05:03 +020024#include "parser_data.h"
25#include "parser_internal.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020026#include "set.h"
Radek Krejci47fab892020-11-05 17:02:41 +010027#include "tree_data.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020028#include "tree_data_internal.h"
29#include "tree_schema.h"
Michal Vaskocde73ac2019-11-14 16:10:27 +010030#include "validation.h"
Radek Krejci535ea9f2020-05-29 16:01:05 +020031#include "xml.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020032
33/**
Michal Vaskob36053d2020-03-26 15:49:30 +010034 * @brief Internal context for XML YANG data parser.
Radek Krejci1798aae2020-07-14 13:26:06 +020035 *
36 * Note that the structure maps to the lyd_ctx which is common for all the data parsers
Radek Krejcie7b95092019-05-15 11:03:07 +020037 */
38struct lyd_xml_ctx {
Michal Vaskoe0665742021-02-11 11:08:44 +010039 uint32_t parse_opts; /**< various @ref dataparseroptions. */
40 uint32_t val_opts; /**< various @ref datavalidationoptions. */
Radek Krejci1798aae2020-07-14 13:26:06 +020041 uint32_t int_opts; /**< internal data parser options */
42 uint32_t path_len; /**< used bytes in the path buffer */
43 char path[LYD_PARSER_BUFSIZE]; /**< buffer for the generated path */
Michal Vasko49c39d82020-11-06 17:20:27 +010044 struct ly_set node_types; /**< set of nodes validated with LY_EINCOMPLETE result */
45 struct ly_set meta_types; /**< set of metadata validated with LY_EINCOMPLETE result */
46 struct ly_set node_when; /**< set of nodes with "when" conditions */
Radek Krejci1798aae2020-07-14 13:26:06 +020047 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 +020048
Radek Krejci1798aae2020-07-14 13:26:06 +020049 /* callbacks */
50 lyd_ctx_free_clb free; /* destructor */
Radek Krejci1798aae2020-07-14 13:26:06 +020051
52 struct lyxml_ctx *xmlctx; /**< XML context */
Radek Krejcie7b95092019-05-15 11:03:07 +020053};
54
Radek Krejci1798aae2020-07-14 13:26:06 +020055void
56lyd_xml_ctx_free(struct lyd_ctx *lydctx)
57{
58 struct lyd_xml_ctx *ctx = (struct lyd_xml_ctx *)lydctx;
59
60 lyd_ctx_free(lydctx);
61 lyxml_ctx_free(ctx->xmlctx);
62 free(ctx);
63}
64
Radek Krejcie7b95092019-05-15 11:03:07 +020065static LY_ERR
Michal Vaskofeca4fb2020-10-05 08:58:40 +020066lydxml_metadata(struct lyd_xml_ctx *lydctx, struct lyd_meta **meta)
Radek Krejcie7b95092019-05-15 11:03:07 +020067{
Michal Vaskob36053d2020-03-26 15:49:30 +010068 LY_ERR ret = LY_EVALID;
Radek Krejci28681fa2019-09-06 13:08:45 +020069 const struct lyxml_ns *ns;
70 struct lys_module *mod;
Michal Vaskob36053d2020-03-26 15:49:30 +010071 const char *name;
72 size_t name_len;
Radek Krejci1798aae2020-07-14 13:26:06 +020073 struct lyxml_ctx *xmlctx = lydctx->xmlctx;
Radek Krejci28681fa2019-09-06 13:08:45 +020074
Michal Vaskob36053d2020-03-26 15:49:30 +010075 *meta = NULL;
Radek Krejci28681fa2019-09-06 13:08:45 +020076
Michal Vaskob36053d2020-03-26 15:49:30 +010077 while (xmlctx->status == LYXML_ATTRIBUTE) {
78 if (!xmlctx->prefix_len) {
Radek Krejci28681fa2019-09-06 13:08:45 +020079 /* in XML, all attributes must be prefixed
80 * TODO exception for NETCONF filters which are supposed to map to the ietf-netconf without prefix */
Michal Vaskoe0665742021-02-11 11:08:44 +010081 if (lydctx->parse_opts & LYD_PARSE_STRICT) {
Radek Krejci2efc45b2020-12-22 16:25:44 +010082 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Missing mandatory prefix for XML metadata \"%.*s\".",
Michal Vasko69730152020-10-09 16:30:07 +020083 xmlctx->name_len, xmlctx->name);
Michal Vaskob36053d2020-03-26 15:49:30 +010084 goto cleanup;
Radek Krejci28681fa2019-09-06 13:08:45 +020085 }
Michal Vaskob36053d2020-03-26 15:49:30 +010086
Radek Krejci28681fa2019-09-06 13:08:45 +020087skip_attr:
Michal Vaskob36053d2020-03-26 15:49:30 +010088 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
89 assert(xmlctx->status == LYXML_ATTR_CONTENT);
90 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Radek Krejci28681fa2019-09-06 13:08:45 +020091 continue;
92 }
93
94 /* get namespace of the attribute to find its annotation definition */
Michal Vaskoc8a230d2020-08-14 12:17:10 +020095 ns = lyxml_ns_get(&xmlctx->ns, xmlctx->prefix, xmlctx->prefix_len);
Radek Krejci28681fa2019-09-06 13:08:45 +020096 if (!ns) {
Michal Vasko52927e22020-03-16 17:26:14 +010097 /* unknown namespace, XML error */
Radek Krejci2efc45b2020-12-22 16:25:44 +010098 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", xmlctx->prefix_len, xmlctx->prefix);
Radek Krejci28681fa2019-09-06 13:08:45 +020099 goto cleanup;
100 }
Michal Vasko52927e22020-03-16 17:26:14 +0100101 mod = ly_ctx_get_module_implemented_ns(xmlctx->ctx, ns->uri);
Radek Krejci28681fa2019-09-06 13:08:45 +0200102 if (!mod) {
103 /* module is not implemented or not present in the schema */
Michal Vaskoe0665742021-02-11 11:08:44 +0100104 if (lydctx->parse_opts & LYD_PARSE_STRICT) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100105 LOGVAL(xmlctx->ctx, LYVE_REFERENCE,
Michal Vasko69730152020-10-09 16:30:07 +0200106 "Unknown (or not implemented) YANG module with namespace \"%s\" for metadata \"%.*s%s%.*s\".",
107 ns->uri, xmlctx->prefix_len, xmlctx->prefix, xmlctx->prefix_len ? ":" : "", xmlctx->name_len,
108 xmlctx->name);
Michal Vaskob36053d2020-03-26 15:49:30 +0100109 goto cleanup;
Radek Krejci28681fa2019-09-06 13:08:45 +0200110 }
111 goto skip_attr;
112 }
113
Michal Vasko60ea6352020-06-29 13:39:39 +0200114 /* remember meta name and get its content */
Michal Vaskob36053d2020-03-26 15:49:30 +0100115 name = xmlctx->name;
116 name_len = xmlctx->name_len;
117 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
118 assert(xmlctx->status == LYXML_ATTR_CONTENT);
119
120 /* create metadata */
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200121 ret = lyd_parser_create_meta((struct lyd_ctx *)lydctx, NULL, meta, mod, name, name_len, xmlctx->value,
Michal Vaskofeca4fb2020-10-05 08:58:40 +0200122 xmlctx->value_len, &xmlctx->dynamic, LY_PREF_XML, &xmlctx->ns, LYD_HINT_DATA);
Radek Krejci1798aae2020-07-14 13:26:06 +0200123 LY_CHECK_GOTO(ret, cleanup);
Michal Vaskob36053d2020-03-26 15:49:30 +0100124
125 /* next attribute */
126 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Radek Krejcie7b95092019-05-15 11:03:07 +0200127 }
Michal Vasko52927e22020-03-16 17:26:14 +0100128
Radek Krejci28681fa2019-09-06 13:08:45 +0200129 ret = LY_SUCCESS;
Radek Krejcie7b95092019-05-15 11:03:07 +0200130
131cleanup:
Michal Vaskob36053d2020-03-26 15:49:30 +0100132 if (ret) {
Michal Vasko3a41dff2020-07-15 14:30:28 +0200133 lyd_free_meta_siblings(*meta);
Michal Vaskob36053d2020-03-26 15:49:30 +0100134 *meta = NULL;
Radek Krejci38d85362019-09-05 16:26:38 +0200135 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200136 return ret;
137}
138
Michal Vasko52927e22020-03-16 17:26:14 +0100139static LY_ERR
Radek Krejci1798aae2020-07-14 13:26:06 +0200140lydxml_attrs(struct lyxml_ctx *xmlctx, struct lyd_attr **attr)
Michal Vasko52927e22020-03-16 17:26:14 +0100141{
142 LY_ERR ret = LY_SUCCESS;
143 const struct lyxml_ns *ns;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100144 void *val_prefix_data;
145 LY_PREFIX_FORMAT format;
Radek Krejci1798aae2020-07-14 13:26:06 +0200146 struct lyd_attr *attr2;
Michal Vaskob36053d2020-03-26 15:49:30 +0100147 const char *name, *prefix;
148 size_t name_len, prefix_len;
Michal Vasko52927e22020-03-16 17:26:14 +0100149
150 assert(attr);
Michal Vaskob36053d2020-03-26 15:49:30 +0100151 *attr = NULL;
Michal Vasko52927e22020-03-16 17:26:14 +0100152
Michal Vaskob36053d2020-03-26 15:49:30 +0100153 while (xmlctx->status == LYXML_ATTRIBUTE) {
Michal Vasko52927e22020-03-16 17:26:14 +0100154 ns = NULL;
Michal Vaskob36053d2020-03-26 15:49:30 +0100155 if (xmlctx->prefix_len) {
Michal Vasko52927e22020-03-16 17:26:14 +0100156 /* get namespace of the attribute */
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200157 ns = lyxml_ns_get(&xmlctx->ns, xmlctx->prefix, xmlctx->prefix_len);
Michal Vasko52927e22020-03-16 17:26:14 +0100158 if (!ns) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100159 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", xmlctx->prefix_len, xmlctx->prefix);
Michal Vasko52927e22020-03-16 17:26:14 +0100160 ret = LY_EVALID;
161 goto cleanup;
162 }
163 }
164
165 if (*attr) {
166 attr2 = *attr;
167 } else {
168 attr2 = NULL;
169 }
170
Michal Vaskob36053d2020-03-26 15:49:30 +0100171 /* remember attr prefix, name, and get its content */
172 prefix = xmlctx->prefix;
173 prefix_len = xmlctx->prefix_len;
174 name = xmlctx->name;
175 name_len = xmlctx->name_len;
176 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
177 assert(xmlctx->status == LYXML_ATTR_CONTENT);
178
Michal Vasko52927e22020-03-16 17:26:14 +0100179 /* get value prefixes */
Michal Vaskofc2cd072021-02-24 13:17:17 +0100180 val_prefix_data = NULL;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100181 LY_CHECK_GOTO(ret = ly_store_prefix_data(xmlctx->ctx, xmlctx->value, xmlctx->value_len, LY_PREF_XML,
182 &xmlctx->ns, &format, &val_prefix_data), cleanup);
Michal Vasko52927e22020-03-16 17:26:14 +0100183
184 /* attr2 is always changed to the created attribute */
Michal Vasko501af032020-11-11 20:27:44 +0100185 ret = lyd_create_attr(NULL, &attr2, xmlctx->ctx, name, name_len, prefix, prefix_len, ns ? ns->uri : NULL,
186 ns ? strlen(ns->uri) : 0, xmlctx->value, xmlctx->value_len, &xmlctx->dynamic, format, val_prefix_data, 0);
Michal Vasko52927e22020-03-16 17:26:14 +0100187 LY_CHECK_GOTO(ret, cleanup);
188
189 if (!*attr) {
190 *attr = attr2;
191 }
Michal Vaskob36053d2020-03-26 15:49:30 +0100192
193 /* next attribute */
194 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko52927e22020-03-16 17:26:14 +0100195 }
196
197cleanup:
Michal Vaskob36053d2020-03-26 15:49:30 +0100198 if (ret) {
Radek Krejci011e4aa2020-09-04 15:22:31 +0200199 lyd_free_attr_siblings(xmlctx->ctx, *attr);
Michal Vaskob36053d2020-03-26 15:49:30 +0100200 *attr = NULL;
Michal Vasko52927e22020-03-16 17:26:14 +0100201 }
Michal Vasko52927e22020-03-16 17:26:14 +0100202 return ret;
203}
204
Michal Vasko44685da2020-03-17 15:38:06 +0100205static LY_ERR
Michal Vaskob36053d2020-03-26 15:49:30 +0100206lydxml_check_list(struct lyxml_ctx *xmlctx, const struct lysc_node *list)
Michal Vasko44685da2020-03-17 15:38:06 +0100207{
Michal Vaskob36053d2020-03-26 15:49:30 +0100208 LY_ERR ret = LY_SUCCESS, r;
209 enum LYXML_PARSER_STATUS next;
Michal Vasko44685da2020-03-17 15:38:06 +0100210 struct ly_set key_set = {0};
211 const struct lysc_node *snode;
Michal Vaskob36053d2020-03-26 15:49:30 +0100212 uint32_t i, parents_count;
Michal Vasko44685da2020-03-17 15:38:06 +0100213
214 assert(list && (list->nodetype == LYS_LIST));
215
216 /* get all keys into a set (keys do not have if-features or anything) */
217 snode = NULL;
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100218 while ((snode = lys_getnext(snode, list, NULL, 0)) && (snode->flags & LYS_KEY)) {
Radek Krejci3d92e442020-10-12 12:48:13 +0200219 ret = ly_set_add(&key_set, (void *)snode, 1, NULL);
Radek Krejciba03a5a2020-08-27 14:40:41 +0200220 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100221 }
222
Michal Vaskob36053d2020-03-26 15:49:30 +0100223 while (xmlctx->status == LYXML_ELEMENT) {
Michal Vasko44685da2020-03-17 15:38:06 +0100224 /* find key definition */
225 for (i = 0; i < key_set.count; ++i) {
226 snode = (const struct lysc_node *)key_set.objs[i];
Michal Vaskob36053d2020-03-26 15:49:30 +0100227 if (!ly_strncmp(snode->name, xmlctx->name, xmlctx->name_len)) {
Michal Vasko44685da2020-03-17 15:38:06 +0100228 break;
229 }
230 }
Michal Vaskob36053d2020-03-26 15:49:30 +0100231 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100232
233 /* skip attributes */
234 while (xmlctx->status == LYXML_ATTRIBUTE) {
Michal Vaskob36053d2020-03-26 15:49:30 +0100235 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
236 assert(xmlctx->status == LYXML_ATTR_CONTENT);
237 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100238 }
239
Michal Vaskob36053d2020-03-26 15:49:30 +0100240 assert(xmlctx->status == LYXML_ELEM_CONTENT);
241 if (i < key_set.count) {
242 /* validate the value */
Michal Vasko713148b2020-11-12 13:10:13 +0100243 r = _lys_value_validate(NULL, snode, xmlctx->value, xmlctx->value_len, LY_PREF_XML, &xmlctx->ns);
Michal Vaskob36053d2020-03-26 15:49:30 +0100244 if (!r) {
245 /* key with a valid value, remove from the set */
246 ly_set_rm_index(&key_set, i, NULL);
Michal Vasko44685da2020-03-17 15:38:06 +0100247 }
248 }
249
Michal Vaskob36053d2020-03-26 15:49:30 +0100250 /* parser next */
251 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100252
Michal Vaskob36053d2020-03-26 15:49:30 +0100253 /* skip any children, resursively */
254 parents_count = xmlctx->elements.count;
255 while ((parents_count < xmlctx->elements.count) || (xmlctx->status == LYXML_ELEMENT)) {
256 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
257 }
258
259 /* parser next, but do not parse closing element of the list because it would remove its namespaces */
260 assert(xmlctx->status == LYXML_ELEM_CLOSE);
261 LY_CHECK_GOTO(ret = lyxml_ctx_peek(xmlctx, &next), cleanup);
262 if (next != LYXML_ELEM_CLOSE) {
263 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
264 }
Michal Vasko44685da2020-03-17 15:38:06 +0100265 }
266
267 if (key_set.count) {
Michal Vaskob36053d2020-03-26 15:49:30 +0100268 /* some keys are missing/did not validate */
Michal Vasko44685da2020-03-17 15:38:06 +0100269 ret = LY_ENOT;
Michal Vasko44685da2020-03-17 15:38:06 +0100270 }
271
272cleanup:
273 ly_set_erase(&key_set, NULL);
274 return ret;
275}
276
Michal Vasko1bf09392020-03-27 12:38:10 +0100277static LY_ERR
278lydxml_data_skip(struct lyxml_ctx *xmlctx)
279{
280 uint32_t parents_count;
281
282 /* remember current number of parents */
283 parents_count = xmlctx->elements.count;
284
285 /* skip after the content */
286 while (xmlctx->status != LYXML_ELEM_CONTENT) {
287 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
288 }
289 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
290
291 /* skip all children elements, recursively, if any */
292 while (parents_count < xmlctx->elements.count) {
293 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
294 }
295
296 /* close element */
297 assert(xmlctx->status == LYXML_ELEM_CLOSE);
298 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
299
300 return LY_SUCCESS;
301}
302
303static LY_ERR
Radek Krejci1798aae2020-07-14 13:26:06 +0200304lydxml_data_check_opaq(struct lyd_xml_ctx *lydctx, const struct lysc_node **snode)
Michal Vasko1bf09392020-03-27 12:38:10 +0100305{
306 LY_ERR ret = LY_SUCCESS;
307 enum LYXML_PARSER_STATUS prev_status;
Michal Vasko63f3d842020-07-08 10:10:14 +0200308 const char *prev_current, *pname, *pprefix;
Michal Vasko1bf09392020-03-27 12:38:10 +0100309 size_t pprefix_len, pname_len;
310 struct lyxml_ctx *xmlctx = lydctx->xmlctx;
311
Michal Vaskoe0665742021-02-11 11:08:44 +0100312 if ((lydctx->parse_opts & LYD_PARSE_OPAQ) && ((*snode)->nodetype & (LYD_NODE_TERM | LYS_LIST))) {
Michal Vasko1bf09392020-03-27 12:38:10 +0100313 /* backup parser */
314 prev_status = xmlctx->status;
315 pprefix = xmlctx->prefix;
316 pprefix_len = xmlctx->prefix_len;
317 pname = xmlctx->name;
318 pname_len = xmlctx->name_len;
Michal Vasko63f3d842020-07-08 10:10:14 +0200319 prev_current = xmlctx->in->current;
Michal Vasko1bf09392020-03-27 12:38:10 +0100320 if ((xmlctx->status == LYXML_ELEM_CONTENT) && xmlctx->dynamic) {
321 /* it was backed up, do not free */
322 xmlctx->dynamic = 0;
323 }
324
325 /* skip attributes */
326 while (xmlctx->status == LYXML_ATTRIBUTE) {
327 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), restore);
328 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), restore);
329 }
330
331 if ((*snode)->nodetype & LYD_NODE_TERM) {
332 /* value may not be valid in which case we parse it as an opaque node */
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200333 if (_lys_value_validate(NULL, *snode, xmlctx->value, xmlctx->value_len, LY_PREF_XML, &xmlctx->ns)) {
Michal Vasko1bf09392020-03-27 12:38:10 +0100334 *snode = NULL;
335 }
336 } else {
337 /* skip content */
338 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), restore);
339
340 if (lydxml_check_list(xmlctx, *snode)) {
341 /* invalid list, parse as opaque if it missing/has invalid some keys */
342 *snode = NULL;
343 }
344 }
345
346restore:
347 /* restore parser */
348 if (xmlctx->dynamic) {
349 free((char *)xmlctx->value);
350 }
351 xmlctx->status = prev_status;
352 xmlctx->prefix = pprefix;
353 xmlctx->prefix_len = pprefix_len;
354 xmlctx->name = pname;
355 xmlctx->name_len = pname_len;
Michal Vasko63f3d842020-07-08 10:10:14 +0200356 xmlctx->in->current = prev_current;
Michal Vasko1bf09392020-03-27 12:38:10 +0100357 }
358
359 return ret;
360}
361
Radek Krejcie7b95092019-05-15 11:03:07 +0200362/**
Michal Vaskoa5da3292020-08-12 13:10:50 +0200363 * @brief Parse XML subtree.
Radek Krejcie7b95092019-05-15 11:03:07 +0200364 *
Michal Vaskob36053d2020-03-26 15:49:30 +0100365 * @param[in] lydctx XML YANG data parser context.
Michal Vaskoe0665742021-02-11 11:08:44 +0100366 * @param[in,out] parent Parent node where the children are inserted. NULL in case of parsing top-level elements.
367 * @param[in,out] first_p Pointer to the first (@p parent or top-level) child. In case there were already some siblings,
368 * this may point to a previously existing node.
369 * @param[in,out] parsed Optional set to add all the parsed siblings into.
Michal Vasko9b368d32020-02-14 13:53:31 +0100370 * @return LY_ERR value.
Radek Krejcie7b95092019-05-15 11:03:07 +0200371 */
372static LY_ERR
Michal Vaskoe0665742021-02-11 11:08:44 +0100373lydxml_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 +0200374{
Michal Vaskob36053d2020-03-26 15:49:30 +0100375 LY_ERR ret = LY_SUCCESS;
Michal Vasko1bf09392020-03-27 12:38:10 +0100376 const char *prefix, *name;
377 size_t prefix_len, name_len;
Michal Vaskob36053d2020-03-26 15:49:30 +0100378 struct lyxml_ctx *xmlctx;
379 const struct ly_ctx *ctx;
Radek Krejcie7b95092019-05-15 11:03:07 +0200380 const struct lyxml_ns *ns;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200381 struct lyd_meta *meta = NULL;
382 struct lyd_attr *attr = NULL;
Radek Krejcie7b95092019-05-15 11:03:07 +0200383 const struct lysc_node *snode;
384 struct lys_module *mod;
Michal Vasko1bf09392020-03-27 12:38:10 +0100385 uint32_t prev_opts;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200386 struct lyd_node *node = NULL, *anchor;
Michal Vaskofc2cd072021-02-24 13:17:17 +0100387 void *val_prefix_data = NULL;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100388 LY_PREFIX_FORMAT format;
Radek Krejci1deb5be2020-08-26 16:43:36 +0200389 uint32_t getnext_opts;
Radek Krejcie7b95092019-05-15 11:03:07 +0200390
Michal Vaskoe0665742021-02-11 11:08:44 +0100391 assert(parent || first_p);
392
Michal Vaskob36053d2020-03-26 15:49:30 +0100393 xmlctx = lydctx->xmlctx;
394 ctx = xmlctx->ctx;
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100395 getnext_opts = lydctx->int_opts & LYD_INTOPT_REPLY ? LYS_GETNEXT_OUTPUT : 0;
Michal Vasko6f4cbb62020-02-28 11:15:47 +0100396
Michal Vaskoa5da3292020-08-12 13:10:50 +0200397 assert(xmlctx->status == LYXML_ELEMENT);
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200398
Michal Vaskoa5da3292020-08-12 13:10:50 +0200399 /* remember element prefix and name */
400 prefix = xmlctx->prefix;
401 prefix_len = xmlctx->prefix_len;
402 name = xmlctx->name;
403 name_len = xmlctx->name_len;
404
405 /* get the element module */
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200406 ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200407 if (!ns) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100408 LOGVAL(ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", prefix_len, prefix);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200409 ret = LY_EVALID;
410 goto error;
411 }
412 mod = ly_ctx_get_module_implemented_ns(ctx, ns->uri);
413 if (!mod) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100414 if (lydctx->parse_opts & LYD_PARSE_STRICT) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100415 LOGVAL(ctx, LYVE_REFERENCE, "No module with namespace \"%s\" in the context.", ns->uri);
Michal Vasko90932a92020-02-12 14:33:03 +0100416 ret = LY_EVALID;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200417 goto error;
Radek Krejcie7b95092019-05-15 11:03:07 +0200418 }
Michal Vaskoe0665742021-02-11 11:08:44 +0100419 if (!(lydctx->parse_opts & LYD_PARSE_OPAQ)) {
Michal Vaskoa5da3292020-08-12 13:10:50 +0200420 /* skip element with children */
421 LY_CHECK_GOTO(ret = lydxml_data_skip(xmlctx), error);
422 return LY_SUCCESS;
Radek Krejcie7b95092019-05-15 11:03:07 +0200423 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200424 }
425
Michal Vaskoa5da3292020-08-12 13:10:50 +0200426 /* parser next */
427 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
Michal Vasko90932a92020-02-12 14:33:03 +0100428
Michal Vaskoa5da3292020-08-12 13:10:50 +0200429 /* get the schema node */
430 snode = NULL;
431 if (mod && (!parent || parent->schema)) {
432 snode = lys_find_child(parent ? parent->schema : NULL, mod, name, name_len, 0, getnext_opts);
433 if (!snode) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100434 if (lydctx->parse_opts & LYD_PARSE_STRICT) {
435 if (parent) {
436 LOGVAL(ctx, LYVE_REFERENCE, "Node \"%.*s\" not found as a child of \"%s\" node.", name_len, name,
437 parent->schema->name);
438 } else {
439 LOGVAL(ctx, LYVE_REFERENCE, "Node \"%.*s\" not found in the \"%s\" module.", name_len, name,
440 mod->name);
441 }
Michal Vaskoa5da3292020-08-12 13:10:50 +0200442 ret = LY_EVALID;
443 goto error;
Michal Vaskoe0665742021-02-11 11:08:44 +0100444 } else if (!(lydctx->parse_opts & LYD_PARSE_OPAQ)) {
Michal Vaskoa5da3292020-08-12 13:10:50 +0200445 /* skip element with children */
446 LY_CHECK_GOTO(ret = lydxml_data_skip(xmlctx), error);
447 return LY_SUCCESS;
448 }
449 } else {
450 /* check that schema node is valid and can be used */
451 LY_CHECK_GOTO(ret = lyd_parser_check_schema((struct lyd_ctx *)lydctx, snode), error);
452 LY_CHECK_GOTO(ret = lydxml_data_check_opaq(lydctx, &snode), error);
453 }
454 }
455
456 /* create metadata/attributes */
457 if (xmlctx->status == LYXML_ATTRIBUTE) {
458 if (snode) {
Michal Vaskofeca4fb2020-10-05 08:58:40 +0200459 ret = lydxml_metadata(lydctx, &meta);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200460 LY_CHECK_GOTO(ret, error);
461 } else {
Michal Vaskoe0665742021-02-11 11:08:44 +0100462 assert(lydctx->parse_opts & LYD_PARSE_OPAQ);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200463 ret = lydxml_attrs(xmlctx, &attr);
464 LY_CHECK_GOTO(ret, error);
465 }
466 }
467
468 assert(xmlctx->status == LYXML_ELEM_CONTENT);
469 if (!snode) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100470 assert(lydctx->parse_opts & LYD_PARSE_OPAQ);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200471
472 if (xmlctx->ws_only) {
473 /* ignore WS-only value */
474 xmlctx->value_len = 0;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100475 format = LY_PREF_XML;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200476 } else {
477 /* get value prefixes */
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100478 ret = ly_store_prefix_data(xmlctx->ctx, xmlctx->value, xmlctx->value_len, LY_PREF_XML,
479 &xmlctx->ns, &format, &val_prefix_data);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200480 LY_CHECK_GOTO(ret, error);
481 }
482
483 /* create node */
Michal Vasko501af032020-11-11 20:27:44 +0100484 ret = lyd_create_opaq(ctx, name, name_len, prefix, prefix_len, ns->uri, strlen(ns->uri), xmlctx->value,
485 xmlctx->value_len, &xmlctx->dynamic, format, val_prefix_data, LYD_HINT_DATA, &node);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200486 LY_CHECK_GOTO(ret, error);
487
488 /* parser next */
489 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
490
491 /* process children */
492 while (xmlctx->status == LYXML_ELEMENT) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100493 ret = lydxml_subtree_r(lydctx, node, lyd_node_child_p(node), NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200494 LY_CHECK_GOTO(ret, error);
495 }
496 } else if (snode->nodetype & LYD_NODE_TERM) {
497 /* create node */
Michal Vasko22df3f02020-08-24 13:29:22 +0200498 LY_CHECK_GOTO(ret = lyd_parser_create_term((struct lyd_ctx *)lydctx, snode, xmlctx->value, xmlctx->value_len,
Michal Vasko69730152020-10-09 16:30:07 +0200499 &xmlctx->dynamic, LY_PREF_XML, &xmlctx->ns, LYD_HINT_DATA, &node), error);
Radek Krejciddace2c2021-01-08 11:30:56 +0100500 LOG_LOCSET(snode, node, NULL, NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200501
502 if (parent && (node->schema->flags & LYS_KEY)) {
503 /* check the key order, the anchor must never be a key */
Michal Vaskoe0665742021-02-11 11:08:44 +0100504 anchor = lyd_insert_get_next_anchor(lyd_child(parent), node);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200505 if (anchor && (anchor->schema->flags & LYS_KEY)) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100506 if (lydctx->parse_opts & LYD_PARSE_STRICT) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100507 LOGVAL(ctx, LYVE_DATA, "Invalid position of the key \"%s\" in a list.", node->schema->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200508 ret = LY_EVALID;
509 goto error;
510 } else {
511 LOGWRN(ctx, "Invalid position of the key \"%s\" in a list.", node->schema->name);
512 }
513 }
514 }
515
516 /* parser next */
517 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
518
519 /* no children expected */
520 if (xmlctx->status == LYXML_ELEMENT) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100521 LOGVAL(ctx, LYVE_SYNTAX, "Child element \"%.*s\" inside a terminal node \"%s\" found.",
Michal Vasko69730152020-10-09 16:30:07 +0200522 xmlctx->name_len, xmlctx->name, snode->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200523 ret = LY_EVALID;
524 goto error;
525 }
526 } else if (snode->nodetype & LYD_NODE_INNER) {
527 if (!xmlctx->ws_only) {
528 /* value in inner node */
Radek Krejci2efc45b2020-12-22 16:25:44 +0100529 LOGVAL(ctx, LYVE_SYNTAX, "Text value \"%.*s\" inside an inner node \"%s\" found.",
Michal Vasko69730152020-10-09 16:30:07 +0200530 xmlctx->value_len, xmlctx->value, snode->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200531 ret = LY_EVALID;
532 goto error;
533 }
534
535 /* create node */
536 ret = lyd_create_inner(snode, &node);
537 LY_CHECK_GOTO(ret, error);
538
Radek Krejciddace2c2021-01-08 11:30:56 +0100539 LOG_LOCSET(snode, node, NULL, NULL);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100540
Michal Vaskoa5da3292020-08-12 13:10:50 +0200541 /* parser next */
542 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
543
544 /* process children */
545 while (xmlctx->status == LYXML_ELEMENT) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100546 ret = lydxml_subtree_r(lydctx, node, lyd_node_child_p(node), NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200547 LY_CHECK_GOTO(ret, error);
548 }
549
550 if (snode->nodetype == LYS_LIST) {
551 /* check all keys exist */
552 LY_CHECK_GOTO(ret = lyd_parse_check_keys(node), error);
553 }
554
Michal Vaskoe0665742021-02-11 11:08:44 +0100555 if (!(lydctx->parse_opts & LYD_PARSE_ONLY)) {
Michal Vaskoa5da3292020-08-12 13:10:50 +0200556 /* new node validation, autodelete CANNOT occur, all nodes are new */
Michal Vaskoe0665742021-02-11 11:08:44 +0100557 ret = lyd_validate_new(lyd_node_child_p(node), snode, NULL, NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200558 LY_CHECK_GOTO(ret, error);
559
560 /* add any missing default children */
Michal Vaskoe0665742021-02-11 11:08:44 +0100561 ret = lyd_new_implicit_r(node, lyd_node_child_p(node), NULL, NULL, &lydctx->node_types, &lydctx->node_when,
562 (lydctx->val_opts & LYD_VALIDATE_NO_STATE) ? LYD_IMPLICIT_NO_STATE : 0, NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200563 LY_CHECK_GOTO(ret, error);
564 }
565
566 if (snode->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) {
567 /* rememeber the RPC/action/notification */
568 lydctx->op_node = node;
569 }
570 } else if (snode->nodetype & LYD_NODE_ANY) {
571 if (!xmlctx->ws_only) {
572 /* value in inner node */
Radek Krejci2efc45b2020-12-22 16:25:44 +0100573 LOGVAL(ctx, LYVE_SYNTAX, "Text value \"%.*s\" inside an any node \"%s\" found.",
Michal Vasko69730152020-10-09 16:30:07 +0200574 xmlctx->value_len, xmlctx->value, snode->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200575 ret = LY_EVALID;
576 goto error;
577 }
578
579 /* parser next */
580 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
581
582 /* parse any data tree with correct options */
Michal Vaskoe0665742021-02-11 11:08:44 +0100583 prev_opts = lydctx->parse_opts;
584 lydctx->parse_opts &= ~LYD_PARSE_STRICT;
585 lydctx->parse_opts |= LYD_PARSE_OPAQ;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200586 anchor = NULL;
587 while (xmlctx->status == LYXML_ELEMENT) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100588 ret = lydxml_subtree_r(lydctx, NULL, &anchor, NULL);
589 LY_CHECK_ERR_GOTO(ret, lydctx->parse_opts = prev_opts, error);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200590 }
Michal Vaskoe0665742021-02-11 11:08:44 +0100591 lydctx->parse_opts = prev_opts;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200592
593 /* create node */
Michal Vasko366a4a12020-12-04 16:23:57 +0100594 ret = lyd_create_any(snode, anchor, LYD_ANYDATA_DATATREE, 1, &node);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200595 LY_CHECK_GOTO(ret, error);
596 }
597 assert(node);
598
599 /* add/correct flags */
600 if (snode) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100601 lyd_parse_set_data_flags(node, &lydctx->node_when, &meta, lydctx->parse_opts);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200602 }
603
604 /* parser next */
605 assert(xmlctx->status == LYXML_ELEM_CLOSE);
606 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
607
608 /* add metadata/attributes */
609 if (snode) {
Michal Vasko871a0252020-11-11 18:35:24 +0100610 lyd_insert_meta(node, meta, 0);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200611 } else {
612 lyd_insert_attr(node, attr);
613 }
614
615 /* insert, keep first pointer correct */
Michal Vaskoe0665742021-02-11 11:08:44 +0100616 lyd_insert_node(parent, first_p, node);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200617 while (!parent && (*first_p)->prev->next) {
618 *first_p = (*first_p)->prev;
619 }
620
Michal Vaskoe0665742021-02-11 11:08:44 +0100621 /* rememeber a successfully parsed node */
622 if (parsed) {
623 ly_set_add(parsed, node, 1, NULL);
624 }
625
Radek Krejciddace2c2021-01-08 11:30:56 +0100626 LOG_LOCBACK(node ? 1 : 0, node ? 1 : 0, 0, 0);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200627 return LY_SUCCESS;
628
629error:
Radek Krejciddace2c2021-01-08 11:30:56 +0100630 LOG_LOCBACK(node ? 1 : 0, node ? 1 : 0, 0, 0);
Michal Vasko3a41dff2020-07-15 14:30:28 +0200631 lyd_free_meta_siblings(meta);
Radek Krejci011e4aa2020-09-04 15:22:31 +0200632 lyd_free_attr_siblings(ctx, attr);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200633 lyd_free_tree(node);
Radek Krejcie7b95092019-05-15 11:03:07 +0200634 return ret;
635}
636
Michal Vaskoe0665742021-02-11 11:08:44 +0100637/**
638 * @brief Parse a specific XML element into an opaque node.
639 *
640 * @param[in] xmlctx XML parser context.
641 * @param[in] name Name of the element.
642 * @param[in] uri URI of the element.
643 * @param[in] value Whether a value is expected in the element.
644 * @param[out] evnp Parsed envelope (opaque node).
645 * @return LY_SUCCESS on success.
646 * @return LY_ENOT if the specified element did not match.
647 * @return LY_ERR value on error.
648 */
Michal Vasko1bf09392020-03-27 12:38:10 +0100649static LY_ERR
Michal Vaskoe0665742021-02-11 11:08:44 +0100650lydxml_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 +0100651{
Michal Vaskoe0665742021-02-11 11:08:44 +0100652 LY_ERR rc = LY_SUCCESS;
653 const struct lyxml_ns *ns;
Radek Krejci1798aae2020-07-14 13:26:06 +0200654 struct lyd_attr *attr = NULL;
Michal Vasko1bf09392020-03-27 12:38:10 +0100655 const char *prefix;
656 size_t prefix_len;
657
Michal Vasko1bf09392020-03-27 12:38:10 +0100658 assert(xmlctx->status == LYXML_ELEMENT);
659 if (ly_strncmp(name, xmlctx->name, xmlctx->name_len)) {
660 /* not the expected element */
Michal Vaskoe0665742021-02-11 11:08:44 +0100661 return LY_ENOT;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100662 }
663
664 prefix = xmlctx->prefix;
665 prefix_len = xmlctx->prefix_len;
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200666 ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100667 if (!ns) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100668 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", prefix_len, prefix);
Michal Vaskoe0665742021-02-11 11:08:44 +0100669 return LY_EVALID;
670 } else if (strcmp(ns->uri, uri)) {
671 /* different namespace */
672 return LY_ENOT;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100673 }
674
675 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
676
677 /* create attributes */
678 if (xmlctx->status == LYXML_ATTRIBUTE) {
679 LY_CHECK_RET(lydxml_attrs(xmlctx, &attr));
680 }
681
Michal Vaskoe0665742021-02-11 11:08:44 +0100682 assert(xmlctx->status == LYXML_ELEM_CONTENT);
683 if (!value && !xmlctx->ws_only) {
684 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected value \"%.*s\" in the \"%s\" element.",
685 xmlctx->value_len, xmlctx->value, name);
686 rc = LY_EVALID;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100687 goto cleanup;
Michal Vaskoe0665742021-02-11 11:08:44 +0100688 }
Michal Vaskoa8edff02020-03-27 14:47:01 +0100689
690 /* create node */
Michal Vaskoe0665742021-02-11 11:08:44 +0100691 rc = lyd_create_opaq(xmlctx->ctx, name, strlen(name), prefix, prefix_len, uri, strlen(uri), xmlctx->value,
692 xmlctx->ws_only ? 0 : xmlctx->value_len, NULL, LY_PREF_XML, NULL, 0, envp);
693 LY_CHECK_GOTO(rc, cleanup);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100694
695 /* assign atributes */
Michal Vaskoe0665742021-02-11 11:08:44 +0100696 ((struct lyd_node_opaq *)(*envp))->attr = attr;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100697 attr = NULL;
698
Michal Vaskoe0665742021-02-11 11:08:44 +0100699 /* parser next element */
700 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100701
Michal Vaskoe0665742021-02-11 11:08:44 +0100702cleanup:
703 lyd_free_attr_siblings(xmlctx->ctx, attr);
704 if (rc) {
705 lyd_free_tree(*envp);
706 *envp = NULL;
707 }
708 return rc;
709}
710
711/**
712 * @brief Parse all expected non-data XML elements of a NETCONF rpc message.
713 *
714 * @param[in] xmlctx XML parser context.
715 * @param[out] evnp Parsed envelope(s) (opaque node).
716 * @param[out] int_opts Internal options for parsing the rest of YANG data.
717 * @param[out] close_elem Number of parsed opened elements that need to be closed.
718 * @return LY_SUCCESS on success.
719 * @return LY_ERR value on error.
720 */
721static LY_ERR
722lydxml_env_netconf_rpc(struct lyxml_ctx *xmlctx, struct lyd_node **envp, uint32_t *int_opts, uint32_t *close_elem)
723{
724 LY_ERR rc = LY_SUCCESS, r;
725 struct lyd_node *child;
726
727 assert(envp && !*envp);
728
729 /* parse "rpc" */
730 r = lydxml_envelope(xmlctx, "rpc", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, envp);
Michal Vaskoe0665742021-02-11 11:08:44 +0100731 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
732
733 /* parse "action", if any */
734 r = lydxml_envelope(xmlctx, "action", "urn:ietf:params:xml:ns:yang:1", 0, &child);
735 if (r == LY_SUCCESS) {
736 /* insert */
737 lyd_insert_node(*envp, NULL, child);
738
739 /* NETCONF action */
740 *int_opts = LYD_INTOPT_NO_SIBLINGS | LYD_INTOPT_ACTION;
741 *close_elem = 2;
742 } else if (r == LY_ENOT) {
743 /* NETCONF RPC */
744 *int_opts = LYD_INTOPT_NO_SIBLINGS | LYD_INTOPT_RPC;
745 *close_elem = 1;
746 } else {
747 rc = r;
748 goto cleanup;
749 }
750
751cleanup:
752 if (rc) {
753 lyd_free_tree(*envp);
754 *envp = NULL;
755 }
756 return rc;
757}
758
759/**
760 * @brief Parse all expected non-data XML elements of a NETCONF notification message.
761 *
762 * @param[in] xmlctx XML parser context.
763 * @param[out] evnp Parsed envelope(s) (opaque node).
764 * @param[out] int_opts Internal options for parsing the rest of YANG data.
765 * @param[out] close_elem Number of parsed opened elements that need to be closed.
766 * @return LY_SUCCESS on success.
767 * @return LY_ERR value on error.
768 */
769static LY_ERR
770lydxml_env_netconf_notif(struct lyxml_ctx *xmlctx, struct lyd_node **envp, uint32_t *int_opts, uint32_t *close_elem)
771{
772 LY_ERR rc = LY_SUCCESS, r;
773 struct lyd_node *child;
774
775 assert(envp && !*envp);
776
777 /* parse "notification" */
778 r = lydxml_envelope(xmlctx, "notification", "urn:ietf:params:xml:ns:netconf:notification:1.0", 0, envp);
Michal Vaskoe0665742021-02-11 11:08:44 +0100779 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
780
781 /* parse "eventTime" */
782 r = lydxml_envelope(xmlctx, "eventTime", "urn:ietf:params:xml:ns:netconf:notification:1.0", 1, &child);
783 if (r == LY_ENOT) {
784 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unexpected element \"%.*s\" instead of \"eventTime\".", xmlctx->name_len,
785 xmlctx->name);
786 r = LY_EVALID;
787 }
788 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
789
790 /* insert */
791 lyd_insert_node(*envp, NULL, child);
792
793 /* validate value */
794 /* TODO validate child->value as yang:date-and-time */
795
796 /* finish child parsing */
Michal Vaskoa8edff02020-03-27 14:47:01 +0100797 if (xmlctx->status != LYXML_ELEM_CLOSE) {
798 assert(xmlctx->status == LYXML_ELEMENT);
Michal Vaskoe0665742021-02-11 11:08:44 +0100799 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"eventTime\".",
Michal Vasko69730152020-10-09 16:30:07 +0200800 xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +0100801 rc = LY_EVALID;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100802 goto cleanup;
803 }
Michal Vaskoe0665742021-02-11 11:08:44 +0100804 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
805
806 /* NETCONF notification */
807 *int_opts = LYD_INTOPT_NO_SIBLINGS | LYD_INTOPT_NOTIF;
808 *close_elem = 1;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100809
810cleanup:
Michal Vaskoe0665742021-02-11 11:08:44 +0100811 if (rc) {
Michal Vaskoa8edff02020-03-27 14:47:01 +0100812 lyd_free_tree(*envp);
Michal Vaskoe0665742021-02-11 11:08:44 +0100813 *envp = NULL;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100814 }
Michal Vaskoe0665742021-02-11 11:08:44 +0100815 return rc;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100816}
Michal Vasko79135ae2020-12-16 10:08:35 +0100817
Michal Vaskoe0665742021-02-11 11:08:44 +0100818/**
819 * @brief Parse an XML element as an opaque node subtree.
820 *
821 * @param[in] xmlctx XML parser context.
822 * @param[in] parent Parent to append nodes to.
823 * @return LY_ERR value.
824 */
825static LY_ERR
826lydxml_opaq_r(struct lyxml_ctx *xmlctx, struct lyd_node *parent)
Michal Vaskoa8edff02020-03-27 14:47:01 +0100827{
Michal Vaskoe0665742021-02-11 11:08:44 +0100828 LY_ERR rc = LY_SUCCESS;
829 const struct lyxml_ns *ns;
830 struct lyd_attr *attr = NULL;
831 struct lyd_node *child = NULL;
832 const char *name, *prefix;
833 size_t name_len, prefix_len;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100834
Michal Vaskoe0665742021-02-11 11:08:44 +0100835 assert(xmlctx->status == LYXML_ELEMENT);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100836
Michal Vaskoe0665742021-02-11 11:08:44 +0100837 name = xmlctx->name;
838 name_len = xmlctx->name_len;
839 prefix = xmlctx->prefix;
840 prefix_len = xmlctx->prefix_len;
841 ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
842 if (!ns) {
843 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", prefix_len, prefix);
844 return LY_EVALID;
845 }
Michal Vaskoa8edff02020-03-27 14:47:01 +0100846
Michal Vaskoe0665742021-02-11 11:08:44 +0100847 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
Michal Vaskoa8edff02020-03-27 14:47:01 +0100848
Michal Vaskoe0665742021-02-11 11:08:44 +0100849 /* create attributes */
850 if (xmlctx->status == LYXML_ATTRIBUTE) {
851 LY_CHECK_RET(lydxml_attrs(xmlctx, &attr));
852 }
853
854 /* create node */
855 assert(xmlctx->status == LYXML_ELEM_CONTENT);
856 rc = lyd_create_opaq(xmlctx->ctx, name, name_len, prefix, prefix_len, ns->uri, strlen(ns->uri), xmlctx->value,
857 xmlctx->ws_only ? 0 : xmlctx->value_len, NULL, LY_PREF_XML, NULL, 0, &child);
858 LY_CHECK_GOTO(rc, cleanup);
859
860 /* assign atributes */
861 ((struct lyd_node_opaq *)child)->attr = attr;
862 attr = NULL;
863
864 /* parser next element */
865 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
866
867 /* parse all the descendants */
868 while (xmlctx->status == LYXML_ELEMENT) {
869 rc = lydxml_opaq_r(xmlctx, child);
870 LY_CHECK_GOTO(rc, cleanup);
871 }
872
873 /* insert */
874 lyd_insert_node(parent, NULL, child);
875
876cleanup:
877 lyd_free_attr_siblings(xmlctx->ctx, attr);
878 if (rc) {
879 lyd_free_tree(child);
880 }
881 return rc;
882}
883
884/**
885 * @brief Parse all expected non-data XML elements of the error-info element in NETCONF rpc-reply message.
886 *
887 * @param[in] xmlctx XML parser context.
888 * @param[in] parent Parent to append nodes to.
889 * @return LY_ERR value.
890 */
891static LY_ERR
892lydxml_env_netconf_rpc_reply_error_info(struct lyxml_ctx *xmlctx, struct lyd_node *parent)
893{
894 LY_ERR r;
895 struct lyd_node *child, *iter;
896 const struct lyxml_ns *ns;
897 ly_bool no_dup;
898
899 /* there must be some child */
900 if (xmlctx->status == LYXML_ELEM_CLOSE) {
901 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Missing child elements of \"error-info\".");
902 return LY_EVALID;
903 }
904
905 while (xmlctx->status == LYXML_ELEMENT) {
906 child = NULL;
907
908 /*
909 * session-id
910 */
911 r = lydxml_envelope(xmlctx, "session-id", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
912 if (r == LY_SUCCESS) {
913 no_dup = 1;
914 goto check_child;
915 } else if (r != LY_ENOT) {
916 goto error;
917 }
918
919 /*
920 * bad-attribute
921 */
922 r = lydxml_envelope(xmlctx, "bad-attribute", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
923 if (r == LY_SUCCESS) {
924 no_dup = 1;
925 goto check_child;
926 } else if (r != LY_ENOT) {
927 goto error;
928 }
929
930 /*
931 * bad-element
932 */
933 r = lydxml_envelope(xmlctx, "bad-element", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
934 if (r == LY_SUCCESS) {
935 no_dup = 1;
936 goto check_child;
937 } else if (r != LY_ENOT) {
938 goto error;
939 }
940
941 /*
942 * bad-namespace
943 */
944 r = lydxml_envelope(xmlctx, "bad-namespace", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
945 if (r == LY_SUCCESS) {
946 no_dup = 1;
947 goto check_child;
948 } else if (r != LY_ENOT) {
949 goto error;
950 }
951
952 if (r == LY_ENOT) {
953 assert(xmlctx->status == LYXML_ELEMENT);
954
955 /* learn namespace */
956 ns = lyxml_ns_get(&xmlctx->ns, xmlctx->prefix, xmlctx->prefix_len);
957 if (!ns) {
958 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", xmlctx->prefix_len, xmlctx->prefix);
959 r = LY_EVALID;
960 goto error;
961 } else if (!strcmp(ns->uri, "urn:ietf:params:xml:ns:netconf:base:1.0")) {
962 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"error-info\".",
Radek Krejci53875452021-02-16 13:44:51 +0100963 xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +0100964 r = LY_EVALID;
965 goto error;
966 }
967
968 /* custom elements */
969 r = lydxml_opaq_r(xmlctx, parent);
970 LY_CHECK_GOTO(r, error);
971
972 no_dup = 0;
973 }
974
975check_child:
976 /* check for duplicates */
977 if (no_dup) {
978 LY_LIST_FOR(lyd_child(parent), iter) {
979 if ((((struct lyd_node_opaq *)iter)->name.name == ((struct lyd_node_opaq *)child)->name.name) &&
980 (((struct lyd_node_opaq *)iter)->name.module_ns == ((struct lyd_node_opaq *)child)->name.module_ns)) {
981 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Duplicate element \"%s\" in \"error-info\".",
982 ((struct lyd_node_opaq *)child)->name.name);
983 r = LY_EVALID;
984 goto error;
985 }
986 }
987 }
988
989 /* finish child parsing */
990 if (xmlctx->status != LYXML_ELEM_CLOSE) {
991 assert(xmlctx->status == LYXML_ELEMENT);
992 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"error-info\".",
993 xmlctx->name_len, xmlctx->name);
994 r = LY_EVALID;
995 goto error;
996 }
997 LY_CHECK_GOTO(r = lyxml_ctx_next(xmlctx), error);
998
999 /* insert */
1000 lyd_insert_node(parent, NULL, child);
1001 }
1002
1003 return LY_SUCCESS;
1004
1005error:
1006 lyd_free_tree(child);
1007 return r;
1008}
1009
1010/**
1011 * @brief Parse all expected non-data XML elements of the rpc-error element in NETCONF rpc-reply message.
1012 *
1013 * @param[in] xmlctx XML parser context.
1014 * @param[in] parent Parent to append nodes to.
1015 * @return LY_ERR value.
1016 */
1017static LY_ERR
1018lydxml_env_netconf_rpc_reply_error(struct lyxml_ctx *xmlctx, struct lyd_node *parent)
1019{
1020 LY_ERR r;
1021 struct lyd_node *child, *iter;
1022 const char *val;
1023 ly_bool no_dup;
1024
1025 /* there must be some child */
1026 if (xmlctx->status == LYXML_ELEM_CLOSE) {
1027 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Missing child elements of \"rpc-error\".");
1028 return LY_EVALID;
1029 }
1030
1031 while (xmlctx->status == LYXML_ELEMENT) {
1032 child = NULL;
1033
1034 /*
1035 * error-type
1036 */
1037 r = lydxml_envelope(xmlctx, "error-type", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1038 if (r == LY_SUCCESS) {
1039 val = ((struct lyd_node_opaq *)child)->value;
1040 if (strcmp(val, "transport") && strcmp(val, "rpc") && strcmp(val, "protocol") && strcmp(val, "application")) {
1041 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Invalid value \"%s\" of element \"%s\".", val,
1042 ((struct lyd_node_opaq *)child)->name.name);
1043 r = LY_EVALID;
1044 goto error;
1045 }
1046
1047 no_dup = 1;
1048 goto check_child;
1049 } else if (r != LY_ENOT) {
1050 goto error;
1051 }
1052
1053 /*
1054 * error-tag
1055 */
1056 r = lydxml_envelope(xmlctx, "error-tag", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1057 if (r == LY_SUCCESS) {
1058 val = ((struct lyd_node_opaq *)child)->value;
1059 if (strcmp(val, "in-use") && strcmp(val, "invalid-value") && strcmp(val, "too-big") &&
1060 strcmp(val, "missing-attribute") && strcmp(val, "bad-attribute") &&
1061 strcmp(val, "unknown-attribute") && strcmp(val, "missing-element") && strcmp(val, "bad-element") &&
1062 strcmp(val, "unknown-element") && strcmp(val, "unknown-namespace") && strcmp(val, "access-denied") &&
1063 strcmp(val, "lock-denied") && strcmp(val, "resource-denied") && strcmp(val, "rollback-failed") &&
1064 strcmp(val, "data-exists") && strcmp(val, "data-missing") && strcmp(val, "operation-not-supported") &&
1065 strcmp(val, "operation-failed") && strcmp(val, "malformed-message")) {
1066 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Invalid value \"%s\" of element \"%s\".", val,
1067 ((struct lyd_node_opaq *)child)->name.name);
1068 r = LY_EVALID;
1069 goto error;
1070 }
1071
1072 no_dup = 1;
1073 goto check_child;
1074 } else if (r != LY_ENOT) {
1075 goto error;
1076 }
1077
1078 /*
1079 * error-severity
1080 */
1081 r = lydxml_envelope(xmlctx, "error-severity", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1082 if (r == LY_SUCCESS) {
1083 val = ((struct lyd_node_opaq *)child)->value;
1084 if (strcmp(val, "error") && strcmp(val, "warning")) {
1085 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Invalid value \"%s\" of element \"%s\".", val,
1086 ((struct lyd_node_opaq *)child)->name.name);
1087 r = LY_EVALID;
1088 goto error;
1089 }
1090
1091 no_dup = 1;
1092 goto check_child;
1093 } else if (r != LY_ENOT) {
1094 goto error;
1095 }
1096
1097 /*
1098 * error-app-tag
1099 */
1100 r = lydxml_envelope(xmlctx, "error-app-tag", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1101 if (r == LY_SUCCESS) {
1102 no_dup = 1;
1103 goto check_child;
1104 } else if (r != LY_ENOT) {
1105 goto error;
1106 }
1107
1108 /*
1109 * error-path
1110 */
1111 r = lydxml_envelope(xmlctx, "error-path", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1112 if (r == LY_SUCCESS) {
1113 no_dup = 1;
1114 goto check_child;
1115 } else if (r != LY_ENOT) {
1116 goto error;
1117 }
1118
1119 /*
1120 * error-message
1121 */
1122 r = lydxml_envelope(xmlctx, "error-message", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1123 if (r == LY_SUCCESS) {
1124 no_dup = 1;
1125 goto check_child;
1126 } else if (r != LY_ENOT) {
1127 goto error;
1128 }
1129
1130 /* error-info */
1131 r = lydxml_envelope(xmlctx, "error-info", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, &child);
1132 if (r == LY_SUCCESS) {
1133 /* parse all the descendants */
1134 LY_CHECK_GOTO(r = lydxml_env_netconf_rpc_reply_error_info(xmlctx, child), error);
1135
1136 no_dup = 0;
1137 goto check_child;
1138 } else if (r != LY_ENOT) {
1139 goto error;
1140 }
1141
1142 if (r == LY_ENOT) {
1143 assert(xmlctx->status == LYXML_ELEMENT);
1144 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"rpc-error\".",
1145 xmlctx->name_len, xmlctx->name);
1146 r = LY_EVALID;
1147 goto error;
1148 }
1149
1150check_child:
1151 /* check for duplicates */
1152 if (no_dup) {
1153 LY_LIST_FOR(lyd_child(parent), iter) {
1154 if ((((struct lyd_node_opaq *)iter)->name.name == ((struct lyd_node_opaq *)child)->name.name) &&
1155 (((struct lyd_node_opaq *)iter)->name.module_ns == ((struct lyd_node_opaq *)child)->name.module_ns)) {
1156 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Duplicate element \"%s\" in \"rpc-error\".",
1157 ((struct lyd_node_opaq *)child)->name.name);
1158 r = LY_EVALID;
1159 goto error;
1160 }
1161 }
1162 }
1163
1164 /* finish child parsing */
1165 if (xmlctx->status != LYXML_ELEM_CLOSE) {
1166 assert(xmlctx->status == LYXML_ELEMENT);
1167 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"rpc-error\".",
1168 xmlctx->name_len, xmlctx->name);
1169 r = LY_EVALID;
1170 goto error;
1171 }
1172 LY_CHECK_GOTO(r = lyxml_ctx_next(xmlctx), error);
1173
1174 /* insert */
1175 lyd_insert_node(parent, NULL, child);
1176 }
1177
1178 return LY_SUCCESS;
1179
1180error:
1181 lyd_free_tree(child);
1182 return r;
1183}
1184
1185/**
1186 * @brief Parse all expected non-data XML elements of a NETCONF rpc-reply message.
1187 *
1188 * @param[in] xmlctx XML parser context.
1189 * @param[out] evnp Parsed envelope(s) (opaque node).
1190 * @param[out] int_opts Internal options for parsing the rest of YANG data.
1191 * @param[out] close_elem Number of parsed opened elements that need to be closed.
1192 * @return LY_SUCCESS on success.
1193 * @return LY_ERR value on error.
1194 */
1195static LY_ERR
1196lydxml_env_netconf_reply(struct lyxml_ctx *xmlctx, struct lyd_node **envp, uint32_t *int_opts, uint32_t *close_elem)
1197{
1198 LY_ERR rc = LY_SUCCESS, r;
1199 struct lyd_node *child = NULL;
1200 const char *parsed_elem = NULL;
1201
1202 assert(envp && !*envp);
1203
1204 /* parse "rpc-reply" */
1205 r = lydxml_envelope(xmlctx, "rpc-reply", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, envp);
Michal Vaskoe0665742021-02-11 11:08:44 +01001206 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
1207
1208 /* there must be some child */
1209 if (xmlctx->status == LYXML_ELEM_CLOSE) {
1210 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Missing child elements of \"rpc-reply\".");
1211 rc = LY_EVALID;
Michal Vaskocf770e22020-08-12 13:21:43 +02001212 goto cleanup;
Michal Vaskoa8edff02020-03-27 14:47:01 +01001213 }
1214
Michal Vaskoe0665742021-02-11 11:08:44 +01001215 /* try to parse "ok" */
1216 r = lydxml_envelope(xmlctx, "ok", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, &child);
1217 if (r == LY_SUCCESS) {
1218 /* insert */
1219 lyd_insert_node(*envp, NULL, child);
1220
1221 /* finish child parsing */
1222 if (xmlctx->status != LYXML_ELEM_CLOSE) {
1223 assert(xmlctx->status == LYXML_ELEMENT);
1224 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"ok\".",
1225 xmlctx->name_len, xmlctx->name);
1226 rc = LY_EVALID;
1227 goto cleanup;
1228 }
1229 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
1230
1231 /* success */
1232 parsed_elem = "ok";
1233 goto finish;
1234 } else if (r != LY_ENOT) {
1235 rc = r;
1236 goto cleanup;
Michal Vasko2552ea32020-12-08 15:32:34 +01001237 }
1238
Michal Vaskoe0665742021-02-11 11:08:44 +01001239 /* try to parse all "rpc-error" elements */
1240 while (xmlctx->status == LYXML_ELEMENT) {
1241 r = lydxml_envelope(xmlctx, "rpc-error", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, &child);
1242 if (r == LY_ENOT) {
1243 break;
1244 } else if (r) {
1245 rc = r;
1246 goto cleanup;
1247 }
1248
1249 /* insert */
1250 lyd_insert_node(*envp, NULL, child);
1251
1252 /* parse all children of "rpc-error" */
1253 LY_CHECK_GOTO(rc = lydxml_env_netconf_rpc_reply_error(xmlctx, child), cleanup);
1254
1255 /* finish child parsing */
1256 assert(xmlctx->status == LYXML_ELEM_CLOSE);
1257 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
1258
1259 parsed_elem = "rpc-error";
Michal Vasko2552ea32020-12-08 15:32:34 +01001260 }
Michal Vaskoe0665742021-02-11 11:08:44 +01001261
1262finish:
1263 if (parsed_elem) {
1264 /* NETCONF rpc-reply with no data */
1265 if (xmlctx->status != LYXML_ELEM_CLOSE) {
1266 assert(xmlctx->status == LYXML_ELEMENT);
1267 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected sibling element \"%.*s\" of \"%s\".",
1268 xmlctx->name_len, xmlctx->name, parsed_elem);
1269 rc = LY_EVALID;
1270 goto cleanup;
1271 }
1272 }
1273
1274 /* NETCONF rpc-reply */
1275 *int_opts = LYD_INTOPT_NO_SIBLINGS | LYD_INTOPT_REPLY;
1276 *close_elem = 1;
1277
1278cleanup:
1279 if (rc) {
1280 lyd_free_tree(*envp);
1281 *envp = NULL;
1282 }
1283 return rc;
1284}
1285
Michal Vasko2552ea32020-12-08 15:32:34 +01001286LY_ERR
Michal Vaskoe0665742021-02-11 11:08:44 +01001287lyd_parse_xml(const struct ly_ctx *ctx, struct lyd_node *parent, struct lyd_node **first_p, struct ly_in *in,
1288 uint32_t parse_opts, uint32_t val_opts, enum lyd_type data_type, struct lyd_node **envp, struct ly_set *parsed,
1289 struct lyd_ctx **lydctx_p)
Michal Vasko2552ea32020-12-08 15:32:34 +01001290{
Michal Vaskoe0665742021-02-11 11:08:44 +01001291 LY_ERR rc = LY_SUCCESS;
1292 struct lyd_xml_ctx *lydctx;
1293 uint32_t i, int_opts, close_elem = 0;
1294 ly_bool parsed_data_nodes = 0;
Michal Vasko2552ea32020-12-08 15:32:34 +01001295
Michal Vaskoe0665742021-02-11 11:08:44 +01001296 assert(ctx && in && lydctx_p);
1297 assert(!(parse_opts & ~LYD_PARSE_OPTS_MASK));
1298 assert(!(val_opts & ~LYD_VALIDATE_OPTS_MASK));
Michal Vasko2552ea32020-12-08 15:32:34 +01001299
Michal Vaskoe0665742021-02-11 11:08:44 +01001300 /* init context */
1301 lydctx = calloc(1, sizeof *lydctx);
1302 LY_CHECK_ERR_RET(!lydctx, LOGMEM(ctx), LY_EMEM);
1303 LY_CHECK_GOTO(rc = lyxml_ctx_new(ctx, in, &lydctx->xmlctx), cleanup);
1304 lydctx->parse_opts = parse_opts;
1305 lydctx->val_opts = val_opts;
1306 lydctx->free = lyd_xml_ctx_free;
Michal Vasko2552ea32020-12-08 15:32:34 +01001307
Michal Vaskoe0665742021-02-11 11:08:44 +01001308 switch (data_type) {
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001309 case LYD_TYPE_DATA_YANG:
Michal Vaskoe0665742021-02-11 11:08:44 +01001310 int_opts = LYD_INTOPT_WITH_SIBLINGS;
1311 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001312 case LYD_TYPE_RPC_YANG:
Michal Vaskoe0665742021-02-11 11:08:44 +01001313 int_opts = LYD_INTOPT_RPC | LYD_INTOPT_ACTION | LYD_INTOPT_NO_SIBLINGS;
1314 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001315 case LYD_TYPE_NOTIF_YANG:
Michal Vaskoe0665742021-02-11 11:08:44 +01001316 int_opts = LYD_INTOPT_NOTIF | LYD_INTOPT_NO_SIBLINGS;
1317 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001318 case LYD_TYPE_REPLY_YANG:
Michal Vaskoe0665742021-02-11 11:08:44 +01001319 int_opts = LYD_INTOPT_REPLY | LYD_INTOPT_NO_SIBLINGS;
1320 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001321 case LYD_TYPE_RPC_NETCONF:
Michal Vaskoe0665742021-02-11 11:08:44 +01001322 assert(!parent);
1323 LY_CHECK_GOTO(rc = lydxml_env_netconf_rpc(lydctx->xmlctx, envp, &int_opts, &close_elem), cleanup);
1324 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001325 case LYD_TYPE_NOTIF_NETCONF:
1326 assert(!parent);
1327 LY_CHECK_GOTO(rc = lydxml_env_netconf_notif(lydctx->xmlctx, envp, &int_opts, &close_elem), cleanup);
1328 break;
1329 case LYD_TYPE_REPLY_NETCONF:
Michal Vaskoe0665742021-02-11 11:08:44 +01001330 assert(parent);
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001331 LY_CHECK_GOTO(rc = lydxml_env_netconf_reply(lydctx->xmlctx, envp, &int_opts, &close_elem), cleanup);
Michal Vaskoe0665742021-02-11 11:08:44 +01001332 break;
1333 }
1334 lydctx->int_opts = int_opts;
1335
1336 /* find the operation node if it exists already */
1337 LY_CHECK_GOTO(rc = lyd_parser_find_operation(parent, int_opts, &lydctx->op_node), cleanup);
1338
1339 /* parse XML data */
1340 while (lydctx->xmlctx->status == LYXML_ELEMENT) {
1341 LY_CHECK_GOTO(rc = lydxml_subtree_r(lydctx, parent, first_p, parsed), cleanup);
1342 parsed_data_nodes = 1;
1343
1344 if (!(int_opts & LYD_INTOPT_WITH_SIBLINGS)) {
1345 break;
1346 }
Michal Vasko2552ea32020-12-08 15:32:34 +01001347 }
1348
Michal Vaskoe0665742021-02-11 11:08:44 +01001349 /* close all opened elements */
1350 for (i = 0; i < close_elem; ++i) {
1351 if (lydctx->xmlctx->status != LYXML_ELEM_CLOSE) {
1352 assert(lydctx->xmlctx->status == LYXML_ELEMENT);
1353 LOGVAL(lydctx->xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\".", lydctx->xmlctx->name_len,
1354 lydctx->xmlctx->name);
1355 rc = LY_EVALID;
1356 goto cleanup;
1357 }
1358
1359 LY_CHECK_GOTO(rc = lyxml_ctx_next(lydctx->xmlctx), cleanup);
Michal Vasko4189c0f2020-08-13 09:05:22 +02001360 }
Michal Vaskoe0665742021-02-11 11:08:44 +01001361
1362 /* check final state */
1363 if ((int_opts & LYD_INTOPT_NO_SIBLINGS) && (lydctx->xmlctx->status == LYXML_ELEMENT)) {
1364 LOGVAL(ctx, LYVE_SYNTAX, "Unexpected sibling node.");
1365 rc = LY_EVALID;
1366 goto cleanup;
1367 }
1368 if ((int_opts & (LYD_INTOPT_RPC | LYD_INTOPT_NOTIF | LYD_INTOPT_REPLY)) && !lydctx->op_node) {
1369 LOGVAL(ctx, LYVE_DATA, "Missing the operation node.");
1370 rc = LY_EVALID;
1371 goto cleanup;
1372 }
1373
1374 if (!parsed_data_nodes) {
1375 /* no data nodes were parsed */
1376 lydctx->op_node = NULL;
Michal Vaskoa8edff02020-03-27 14:47:01 +01001377 }
1378
1379cleanup:
Michal Vaskoe0665742021-02-11 11:08:44 +01001380 /* there should be no unres stored if validation should be skipped */
1381 assert(!(parse_opts & LYD_PARSE_ONLY) || (!lydctx->node_types.count && !lydctx->meta_types.count &&
1382 !lydctx->node_when.count));
1383
1384 if (rc) {
1385 lyd_xml_ctx_free((struct lyd_ctx *)lydctx);
1386 } else {
1387 *lydctx_p = (struct lyd_ctx *)lydctx;
1388
1389 /* the XML context is no more needed, freeing it also stops logging line numbers which would be confusing now */
1390 lyxml_ctx_free(lydctx->xmlctx);
1391 lydctx->xmlctx = NULL;
Michal Vasko1ce933a2020-03-30 12:38:22 +02001392 }
Michal Vaskoe0665742021-02-11 11:08:44 +01001393 return rc;
Michal Vasko1ce933a2020-03-30 12:38:22 +02001394}