blob: d01fdcd8f44a210568b02defd0cd55ad0a421ffa [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 Krejcif16e2542021-02-17 15:39:23 +010026#include "plugins_exts.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020027#include "set.h"
Radek Krejci47fab892020-11-05 17:02:41 +010028#include "tree_data.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020029#include "tree_data_internal.h"
30#include "tree_schema.h"
Michal Vaskocde73ac2019-11-14 16:10:27 +010031#include "validation.h"
Radek Krejci535ea9f2020-05-29 16:01:05 +020032#include "xml.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020033
34/**
Michal Vaskob36053d2020-03-26 15:49:30 +010035 * @brief Internal context for XML YANG data parser.
Radek Krejci1798aae2020-07-14 13:26:06 +020036 *
37 * Note that the structure maps to the lyd_ctx which is common for all the data parsers
Radek Krejcie7b95092019-05-15 11:03:07 +020038 */
39struct lyd_xml_ctx {
Radek Krejcif16e2542021-02-17 15:39:23 +010040 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 +010041 uint32_t parse_opts; /**< various @ref dataparseroptions. */
42 uint32_t val_opts; /**< various @ref datavalidationoptions. */
Radek Krejci1798aae2020-07-14 13:26:06 +020043 uint32_t int_opts; /**< internal data parser options */
44 uint32_t path_len; /**< used bytes in the path buffer */
45 char path[LYD_PARSER_BUFSIZE]; /**< buffer for the generated path */
Michal Vasko49c39d82020-11-06 17:20:27 +010046 struct ly_set node_types; /**< set of nodes validated with LY_EINCOMPLETE result */
47 struct ly_set meta_types; /**< set of metadata validated with LY_EINCOMPLETE result */
48 struct ly_set node_when; /**< set of nodes with "when" conditions */
Radek Krejci1798aae2020-07-14 13:26:06 +020049 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 +020050
Radek Krejci1798aae2020-07-14 13:26:06 +020051 /* callbacks */
52 lyd_ctx_free_clb free; /* destructor */
Radek Krejci1798aae2020-07-14 13:26:06 +020053
54 struct lyxml_ctx *xmlctx; /**< XML context */
Radek Krejcie7b95092019-05-15 11:03:07 +020055};
56
Radek Krejci1798aae2020-07-14 13:26:06 +020057void
58lyd_xml_ctx_free(struct lyd_ctx *lydctx)
59{
60 struct lyd_xml_ctx *ctx = (struct lyd_xml_ctx *)lydctx;
61
62 lyd_ctx_free(lydctx);
63 lyxml_ctx_free(ctx->xmlctx);
64 free(ctx);
65}
66
Radek Krejcie7b95092019-05-15 11:03:07 +020067static LY_ERR
Michal Vaskofeca4fb2020-10-05 08:58:40 +020068lydxml_metadata(struct lyd_xml_ctx *lydctx, struct lyd_meta **meta)
Radek Krejcie7b95092019-05-15 11:03:07 +020069{
Michal Vaskob36053d2020-03-26 15:49:30 +010070 LY_ERR ret = LY_EVALID;
Radek Krejci28681fa2019-09-06 13:08:45 +020071 const struct lyxml_ns *ns;
72 struct lys_module *mod;
Michal Vaskob36053d2020-03-26 15:49:30 +010073 const char *name;
74 size_t name_len;
Radek Krejci1798aae2020-07-14 13:26:06 +020075 struct lyxml_ctx *xmlctx = lydctx->xmlctx;
Radek Krejci28681fa2019-09-06 13:08:45 +020076
Michal Vaskob36053d2020-03-26 15:49:30 +010077 *meta = NULL;
Radek Krejci28681fa2019-09-06 13:08:45 +020078
Michal Vaskob36053d2020-03-26 15:49:30 +010079 while (xmlctx->status == LYXML_ATTRIBUTE) {
80 if (!xmlctx->prefix_len) {
Radek Krejci28681fa2019-09-06 13:08:45 +020081 /* in XML, all attributes must be prefixed
82 * TODO exception for NETCONF filters which are supposed to map to the ietf-netconf without prefix */
Michal Vaskoe0665742021-02-11 11:08:44 +010083 if (lydctx->parse_opts & LYD_PARSE_STRICT) {
Radek Krejci2efc45b2020-12-22 16:25:44 +010084 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Missing mandatory prefix for XML metadata \"%.*s\".",
Michal Vasko69730152020-10-09 16:30:07 +020085 xmlctx->name_len, xmlctx->name);
Michal Vaskob36053d2020-03-26 15:49:30 +010086 goto cleanup;
Radek Krejci28681fa2019-09-06 13:08:45 +020087 }
Michal Vaskob36053d2020-03-26 15:49:30 +010088
Radek Krejci28681fa2019-09-06 13:08:45 +020089skip_attr:
Michal Vaskob36053d2020-03-26 15:49:30 +010090 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
91 assert(xmlctx->status == LYXML_ATTR_CONTENT);
92 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Radek Krejci28681fa2019-09-06 13:08:45 +020093 continue;
94 }
95
96 /* get namespace of the attribute to find its annotation definition */
Michal Vaskoc8a230d2020-08-14 12:17:10 +020097 ns = lyxml_ns_get(&xmlctx->ns, xmlctx->prefix, xmlctx->prefix_len);
Radek Krejci28681fa2019-09-06 13:08:45 +020098 if (!ns) {
Michal Vasko52927e22020-03-16 17:26:14 +010099 /* unknown namespace, XML error */
Radek Krejci2efc45b2020-12-22 16:25:44 +0100100 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", xmlctx->prefix_len, xmlctx->prefix);
Radek Krejci28681fa2019-09-06 13:08:45 +0200101 goto cleanup;
102 }
Michal Vasko52927e22020-03-16 17:26:14 +0100103 mod = ly_ctx_get_module_implemented_ns(xmlctx->ctx, ns->uri);
Radek Krejci28681fa2019-09-06 13:08:45 +0200104 if (!mod) {
105 /* module is not implemented or not present in the schema */
Michal Vaskoe0665742021-02-11 11:08:44 +0100106 if (lydctx->parse_opts & LYD_PARSE_STRICT) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100107 LOGVAL(xmlctx->ctx, LYVE_REFERENCE,
Michal Vasko69730152020-10-09 16:30:07 +0200108 "Unknown (or not implemented) YANG module with namespace \"%s\" for metadata \"%.*s%s%.*s\".",
109 ns->uri, xmlctx->prefix_len, xmlctx->prefix, xmlctx->prefix_len ? ":" : "", xmlctx->name_len,
110 xmlctx->name);
Michal Vaskob36053d2020-03-26 15:49:30 +0100111 goto cleanup;
Radek Krejci28681fa2019-09-06 13:08:45 +0200112 }
113 goto skip_attr;
114 }
115
Michal Vasko60ea6352020-06-29 13:39:39 +0200116 /* remember meta name and get its content */
Michal Vaskob36053d2020-03-26 15:49:30 +0100117 name = xmlctx->name;
118 name_len = xmlctx->name_len;
119 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
120 assert(xmlctx->status == LYXML_ATTR_CONTENT);
121
122 /* create metadata */
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200123 ret = lyd_parser_create_meta((struct lyd_ctx *)lydctx, NULL, meta, mod, name, name_len, xmlctx->value,
Michal Vaskofeca4fb2020-10-05 08:58:40 +0200124 xmlctx->value_len, &xmlctx->dynamic, LY_PREF_XML, &xmlctx->ns, LYD_HINT_DATA);
Radek Krejci1798aae2020-07-14 13:26:06 +0200125 LY_CHECK_GOTO(ret, cleanup);
Michal Vaskob36053d2020-03-26 15:49:30 +0100126
127 /* next attribute */
128 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Radek Krejcie7b95092019-05-15 11:03:07 +0200129 }
Michal Vasko52927e22020-03-16 17:26:14 +0100130
Radek Krejci28681fa2019-09-06 13:08:45 +0200131 ret = LY_SUCCESS;
Radek Krejcie7b95092019-05-15 11:03:07 +0200132
133cleanup:
Michal Vaskob36053d2020-03-26 15:49:30 +0100134 if (ret) {
Michal Vasko3a41dff2020-07-15 14:30:28 +0200135 lyd_free_meta_siblings(*meta);
Michal Vaskob36053d2020-03-26 15:49:30 +0100136 *meta = NULL;
Radek Krejci38d85362019-09-05 16:26:38 +0200137 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200138 return ret;
139}
140
Michal Vasko52927e22020-03-16 17:26:14 +0100141static LY_ERR
Radek Krejci1798aae2020-07-14 13:26:06 +0200142lydxml_attrs(struct lyxml_ctx *xmlctx, struct lyd_attr **attr)
Michal Vasko52927e22020-03-16 17:26:14 +0100143{
144 LY_ERR ret = LY_SUCCESS;
145 const struct lyxml_ns *ns;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100146 void *val_prefix_data;
147 LY_PREFIX_FORMAT format;
Radek Krejci1798aae2020-07-14 13:26:06 +0200148 struct lyd_attr *attr2;
Michal Vaskob36053d2020-03-26 15:49:30 +0100149 const char *name, *prefix;
150 size_t name_len, prefix_len;
Michal Vasko52927e22020-03-16 17:26:14 +0100151
152 assert(attr);
Michal Vaskob36053d2020-03-26 15:49:30 +0100153 *attr = NULL;
Michal Vasko52927e22020-03-16 17:26:14 +0100154
Michal Vaskob36053d2020-03-26 15:49:30 +0100155 while (xmlctx->status == LYXML_ATTRIBUTE) {
Michal Vasko52927e22020-03-16 17:26:14 +0100156 ns = NULL;
Michal Vaskob36053d2020-03-26 15:49:30 +0100157 if (xmlctx->prefix_len) {
Michal Vasko52927e22020-03-16 17:26:14 +0100158 /* get namespace of the attribute */
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200159 ns = lyxml_ns_get(&xmlctx->ns, xmlctx->prefix, xmlctx->prefix_len);
Michal Vasko52927e22020-03-16 17:26:14 +0100160 if (!ns) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100161 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", xmlctx->prefix_len, xmlctx->prefix);
Michal Vasko52927e22020-03-16 17:26:14 +0100162 ret = LY_EVALID;
163 goto cleanup;
164 }
165 }
166
167 if (*attr) {
168 attr2 = *attr;
169 } else {
170 attr2 = NULL;
171 }
172
Michal Vaskob36053d2020-03-26 15:49:30 +0100173 /* remember attr prefix, name, and get its content */
174 prefix = xmlctx->prefix;
175 prefix_len = xmlctx->prefix_len;
176 name = xmlctx->name;
177 name_len = xmlctx->name_len;
178 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
179 assert(xmlctx->status == LYXML_ATTR_CONTENT);
180
Michal Vasko52927e22020-03-16 17:26:14 +0100181 /* get value prefixes */
Michal Vaskofc2cd072021-02-24 13:17:17 +0100182 val_prefix_data = NULL;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100183 LY_CHECK_GOTO(ret = ly_store_prefix_data(xmlctx->ctx, xmlctx->value, xmlctx->value_len, LY_PREF_XML,
184 &xmlctx->ns, &format, &val_prefix_data), cleanup);
Michal Vasko52927e22020-03-16 17:26:14 +0100185
186 /* attr2 is always changed to the created attribute */
Michal Vasko501af032020-11-11 20:27:44 +0100187 ret = lyd_create_attr(NULL, &attr2, xmlctx->ctx, name, name_len, prefix, prefix_len, ns ? ns->uri : NULL,
188 ns ? strlen(ns->uri) : 0, xmlctx->value, xmlctx->value_len, &xmlctx->dynamic, format, val_prefix_data, 0);
Michal Vasko52927e22020-03-16 17:26:14 +0100189 LY_CHECK_GOTO(ret, cleanup);
190
191 if (!*attr) {
192 *attr = attr2;
193 }
Michal Vaskob36053d2020-03-26 15:49:30 +0100194
195 /* next attribute */
196 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko52927e22020-03-16 17:26:14 +0100197 }
198
199cleanup:
Michal Vaskob36053d2020-03-26 15:49:30 +0100200 if (ret) {
Radek Krejci011e4aa2020-09-04 15:22:31 +0200201 lyd_free_attr_siblings(xmlctx->ctx, *attr);
Michal Vaskob36053d2020-03-26 15:49:30 +0100202 *attr = NULL;
Michal Vasko52927e22020-03-16 17:26:14 +0100203 }
Michal Vasko52927e22020-03-16 17:26:14 +0100204 return ret;
205}
206
Michal Vasko44685da2020-03-17 15:38:06 +0100207static LY_ERR
Michal Vaskob36053d2020-03-26 15:49:30 +0100208lydxml_check_list(struct lyxml_ctx *xmlctx, const struct lysc_node *list)
Michal Vasko44685da2020-03-17 15:38:06 +0100209{
Michal Vaskob36053d2020-03-26 15:49:30 +0100210 LY_ERR ret = LY_SUCCESS, r;
211 enum LYXML_PARSER_STATUS next;
Michal Vasko44685da2020-03-17 15:38:06 +0100212 struct ly_set key_set = {0};
213 const struct lysc_node *snode;
Michal Vaskob36053d2020-03-26 15:49:30 +0100214 uint32_t i, parents_count;
Michal Vasko44685da2020-03-17 15:38:06 +0100215
216 assert(list && (list->nodetype == LYS_LIST));
217
218 /* get all keys into a set (keys do not have if-features or anything) */
219 snode = NULL;
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100220 while ((snode = lys_getnext(snode, list, NULL, 0)) && (snode->flags & LYS_KEY)) {
Radek Krejci3d92e442020-10-12 12:48:13 +0200221 ret = ly_set_add(&key_set, (void *)snode, 1, NULL);
Radek Krejciba03a5a2020-08-27 14:40:41 +0200222 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100223 }
224
Michal Vaskob36053d2020-03-26 15:49:30 +0100225 while (xmlctx->status == LYXML_ELEMENT) {
Michal Vasko44685da2020-03-17 15:38:06 +0100226 /* find key definition */
227 for (i = 0; i < key_set.count; ++i) {
228 snode = (const struct lysc_node *)key_set.objs[i];
Michal Vaskob36053d2020-03-26 15:49:30 +0100229 if (!ly_strncmp(snode->name, xmlctx->name, xmlctx->name_len)) {
Michal Vasko44685da2020-03-17 15:38:06 +0100230 break;
231 }
232 }
Michal Vaskob36053d2020-03-26 15:49:30 +0100233 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100234
235 /* skip attributes */
236 while (xmlctx->status == LYXML_ATTRIBUTE) {
Michal Vaskob36053d2020-03-26 15:49:30 +0100237 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
238 assert(xmlctx->status == LYXML_ATTR_CONTENT);
239 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100240 }
241
Michal Vaskob36053d2020-03-26 15:49:30 +0100242 assert(xmlctx->status == LYXML_ELEM_CONTENT);
243 if (i < key_set.count) {
244 /* validate the value */
Michal Vasko713148b2020-11-12 13:10:13 +0100245 r = _lys_value_validate(NULL, snode, xmlctx->value, xmlctx->value_len, LY_PREF_XML, &xmlctx->ns);
Michal Vaskob36053d2020-03-26 15:49:30 +0100246 if (!r) {
247 /* key with a valid value, remove from the set */
248 ly_set_rm_index(&key_set, i, NULL);
Michal Vasko44685da2020-03-17 15:38:06 +0100249 }
250 }
251
Michal Vaskob36053d2020-03-26 15:49:30 +0100252 /* parser next */
253 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100254
Michal Vaskob36053d2020-03-26 15:49:30 +0100255 /* skip any children, resursively */
256 parents_count = xmlctx->elements.count;
257 while ((parents_count < xmlctx->elements.count) || (xmlctx->status == LYXML_ELEMENT)) {
258 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
259 }
260
261 /* parser next, but do not parse closing element of the list because it would remove its namespaces */
262 assert(xmlctx->status == LYXML_ELEM_CLOSE);
263 LY_CHECK_GOTO(ret = lyxml_ctx_peek(xmlctx, &next), cleanup);
264 if (next != LYXML_ELEM_CLOSE) {
265 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
266 }
Michal Vasko44685da2020-03-17 15:38:06 +0100267 }
268
269 if (key_set.count) {
Michal Vaskob36053d2020-03-26 15:49:30 +0100270 /* some keys are missing/did not validate */
Michal Vasko44685da2020-03-17 15:38:06 +0100271 ret = LY_ENOT;
Michal Vasko44685da2020-03-17 15:38:06 +0100272 }
273
274cleanup:
275 ly_set_erase(&key_set, NULL);
276 return ret;
277}
278
Michal Vasko1bf09392020-03-27 12:38:10 +0100279static LY_ERR
280lydxml_data_skip(struct lyxml_ctx *xmlctx)
281{
282 uint32_t parents_count;
283
284 /* remember current number of parents */
285 parents_count = xmlctx->elements.count;
286
287 /* skip after the content */
288 while (xmlctx->status != LYXML_ELEM_CONTENT) {
289 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
290 }
291 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
292
293 /* skip all children elements, recursively, if any */
294 while (parents_count < xmlctx->elements.count) {
295 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
296 }
297
298 /* close element */
299 assert(xmlctx->status == LYXML_ELEM_CLOSE);
300 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
301
302 return LY_SUCCESS;
303}
304
305static LY_ERR
Radek Krejci1798aae2020-07-14 13:26:06 +0200306lydxml_data_check_opaq(struct lyd_xml_ctx *lydctx, const struct lysc_node **snode)
Michal Vasko1bf09392020-03-27 12:38:10 +0100307{
308 LY_ERR ret = LY_SUCCESS;
309 enum LYXML_PARSER_STATUS prev_status;
Michal Vasko63f3d842020-07-08 10:10:14 +0200310 const char *prev_current, *pname, *pprefix;
Michal Vasko1bf09392020-03-27 12:38:10 +0100311 size_t pprefix_len, pname_len;
312 struct lyxml_ctx *xmlctx = lydctx->xmlctx;
313
Michal Vaskoe0665742021-02-11 11:08:44 +0100314 if ((lydctx->parse_opts & LYD_PARSE_OPAQ) && ((*snode)->nodetype & (LYD_NODE_TERM | LYS_LIST))) {
Michal Vasko1bf09392020-03-27 12:38:10 +0100315 /* backup parser */
316 prev_status = xmlctx->status;
317 pprefix = xmlctx->prefix;
318 pprefix_len = xmlctx->prefix_len;
319 pname = xmlctx->name;
320 pname_len = xmlctx->name_len;
Michal Vasko63f3d842020-07-08 10:10:14 +0200321 prev_current = xmlctx->in->current;
Michal Vasko1bf09392020-03-27 12:38:10 +0100322 if ((xmlctx->status == LYXML_ELEM_CONTENT) && xmlctx->dynamic) {
323 /* it was backed up, do not free */
324 xmlctx->dynamic = 0;
325 }
326
327 /* skip attributes */
328 while (xmlctx->status == LYXML_ATTRIBUTE) {
329 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), restore);
330 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), restore);
331 }
332
333 if ((*snode)->nodetype & LYD_NODE_TERM) {
334 /* value may not be valid in which case we parse it as an opaque node */
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200335 if (_lys_value_validate(NULL, *snode, xmlctx->value, xmlctx->value_len, LY_PREF_XML, &xmlctx->ns)) {
Michal Vasko1bf09392020-03-27 12:38:10 +0100336 *snode = NULL;
337 }
338 } else {
339 /* skip content */
340 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), restore);
341
342 if (lydxml_check_list(xmlctx, *snode)) {
343 /* invalid list, parse as opaque if it missing/has invalid some keys */
344 *snode = NULL;
345 }
346 }
347
348restore:
349 /* restore parser */
350 if (xmlctx->dynamic) {
351 free((char *)xmlctx->value);
352 }
353 xmlctx->status = prev_status;
354 xmlctx->prefix = pprefix;
355 xmlctx->prefix_len = pprefix_len;
356 xmlctx->name = pname;
357 xmlctx->name_len = pname_len;
Michal Vasko63f3d842020-07-08 10:10:14 +0200358 xmlctx->in->current = prev_current;
Michal Vasko1bf09392020-03-27 12:38:10 +0100359 }
360
361 return ret;
362}
363
Radek Krejcie7b95092019-05-15 11:03:07 +0200364/**
Michal Vaskoa5da3292020-08-12 13:10:50 +0200365 * @brief Parse XML subtree.
Radek Krejcie7b95092019-05-15 11:03:07 +0200366 *
Michal Vaskob36053d2020-03-26 15:49:30 +0100367 * @param[in] lydctx XML YANG data parser context.
Michal Vaskoe0665742021-02-11 11:08:44 +0100368 * @param[in,out] parent Parent node where the children are inserted. NULL in case of parsing top-level elements.
369 * @param[in,out] first_p Pointer to the first (@p parent or top-level) child. In case there were already some siblings,
370 * this may point to a previously existing node.
371 * @param[in,out] parsed Optional set to add all the parsed siblings into.
Michal Vasko9b368d32020-02-14 13:53:31 +0100372 * @return LY_ERR value.
Radek Krejcie7b95092019-05-15 11:03:07 +0200373 */
374static LY_ERR
Michal Vaskoe0665742021-02-11 11:08:44 +0100375lydxml_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 +0200376{
Michal Vaskob36053d2020-03-26 15:49:30 +0100377 LY_ERR ret = LY_SUCCESS;
Michal Vasko1bf09392020-03-27 12:38:10 +0100378 const char *prefix, *name;
379 size_t prefix_len, name_len;
Michal Vaskob36053d2020-03-26 15:49:30 +0100380 struct lyxml_ctx *xmlctx;
381 const struct ly_ctx *ctx;
Radek Krejcie7b95092019-05-15 11:03:07 +0200382 const struct lyxml_ns *ns;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200383 struct lyd_meta *meta = NULL;
384 struct lyd_attr *attr = NULL;
Radek Krejcie7b95092019-05-15 11:03:07 +0200385 const struct lysc_node *snode;
386 struct lys_module *mod;
Michal Vasko1bf09392020-03-27 12:38:10 +0100387 uint32_t prev_opts;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200388 struct lyd_node *node = NULL, *anchor;
Michal Vaskofc2cd072021-02-24 13:17:17 +0100389 void *val_prefix_data = NULL;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100390 LY_PREFIX_FORMAT format;
Radek Krejci1deb5be2020-08-26 16:43:36 +0200391 uint32_t getnext_opts;
Radek Krejcie7b95092019-05-15 11:03:07 +0200392
Michal Vaskoe0665742021-02-11 11:08:44 +0100393 assert(parent || first_p);
394
Michal Vaskob36053d2020-03-26 15:49:30 +0100395 xmlctx = lydctx->xmlctx;
396 ctx = xmlctx->ctx;
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100397 getnext_opts = lydctx->int_opts & LYD_INTOPT_REPLY ? LYS_GETNEXT_OUTPUT : 0;
Michal Vasko6f4cbb62020-02-28 11:15:47 +0100398
Michal Vaskoa5da3292020-08-12 13:10:50 +0200399 assert(xmlctx->status == LYXML_ELEMENT);
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200400
Michal Vaskoa5da3292020-08-12 13:10:50 +0200401 /* remember element prefix and name */
402 prefix = xmlctx->prefix;
403 prefix_len = xmlctx->prefix_len;
404 name = xmlctx->name;
405 name_len = xmlctx->name_len;
406
407 /* get the element module */
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200408 ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200409 if (!ns) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100410 LOGVAL(ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", prefix_len, prefix);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200411 ret = LY_EVALID;
412 goto error;
413 }
414 mod = ly_ctx_get_module_implemented_ns(ctx, ns->uri);
415 if (!mod) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100416 if (lydctx->parse_opts & LYD_PARSE_STRICT) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100417 LOGVAL(ctx, LYVE_REFERENCE, "No module with namespace \"%s\" in the context.", ns->uri);
Michal Vasko90932a92020-02-12 14:33:03 +0100418 ret = LY_EVALID;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200419 goto error;
Radek Krejcie7b95092019-05-15 11:03:07 +0200420 }
Michal Vaskoe0665742021-02-11 11:08:44 +0100421 if (!(lydctx->parse_opts & LYD_PARSE_OPAQ)) {
Michal Vaskoa5da3292020-08-12 13:10:50 +0200422 /* skip element with children */
423 LY_CHECK_GOTO(ret = lydxml_data_skip(xmlctx), error);
424 return LY_SUCCESS;
Radek Krejcie7b95092019-05-15 11:03:07 +0200425 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200426 }
427
Michal Vaskoa5da3292020-08-12 13:10:50 +0200428 /* parser next */
429 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
Michal Vasko90932a92020-02-12 14:33:03 +0100430
Michal Vaskoa5da3292020-08-12 13:10:50 +0200431 /* get the schema node */
432 snode = NULL;
433 if (mod && (!parent || parent->schema)) {
Radek Krejcif16e2542021-02-17 15:39:23 +0100434 if (!parent && lydctx->ext) {
435 snode = lys_find_ext_instance_node(lydctx->ext, mod, name, name_len, 0, getnext_opts);
436 } else {
437 snode = lys_find_child(parent ? parent->schema : NULL, mod, name, name_len, 0, getnext_opts);
438 }
Michal Vaskoa5da3292020-08-12 13:10:50 +0200439 if (!snode) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100440 if (lydctx->parse_opts & LYD_PARSE_STRICT) {
441 if (parent) {
442 LOGVAL(ctx, LYVE_REFERENCE, "Node \"%.*s\" not found as a child of \"%s\" node.", name_len, name,
443 parent->schema->name);
Radek Krejcif16e2542021-02-17 15:39:23 +0100444 } else if (lydctx->ext) {
445 if (lydctx->ext->argument) {
446 LOGVAL(ctx, LYVE_REFERENCE, "Node \"%.*s\" not found in the \"%s\" %s extension instance.", name_len, name,
447 lydctx->ext->argument, lydctx->ext->def->name);
448 } else {
449 LOGVAL(ctx, LYVE_REFERENCE, "Node \"%.*s\" not found in the %s extension instance.", name_len, name,
450 lydctx->ext->def->name);
451 }
Michal Vaskoe0665742021-02-11 11:08:44 +0100452 } else {
453 LOGVAL(ctx, LYVE_REFERENCE, "Node \"%.*s\" not found in the \"%s\" module.", name_len, name,
454 mod->name);
455 }
Michal Vaskoa5da3292020-08-12 13:10:50 +0200456 ret = LY_EVALID;
457 goto error;
Michal Vaskoe0665742021-02-11 11:08:44 +0100458 } else if (!(lydctx->parse_opts & LYD_PARSE_OPAQ)) {
Michal Vaskoa5da3292020-08-12 13:10:50 +0200459 /* skip element with children */
460 LY_CHECK_GOTO(ret = lydxml_data_skip(xmlctx), error);
461 return LY_SUCCESS;
462 }
463 } else {
464 /* check that schema node is valid and can be used */
465 LY_CHECK_GOTO(ret = lyd_parser_check_schema((struct lyd_ctx *)lydctx, snode), error);
466 LY_CHECK_GOTO(ret = lydxml_data_check_opaq(lydctx, &snode), error);
467 }
468 }
469
470 /* create metadata/attributes */
471 if (xmlctx->status == LYXML_ATTRIBUTE) {
472 if (snode) {
Michal Vaskofeca4fb2020-10-05 08:58:40 +0200473 ret = lydxml_metadata(lydctx, &meta);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200474 LY_CHECK_GOTO(ret, error);
475 } else {
Michal Vaskoe0665742021-02-11 11:08:44 +0100476 assert(lydctx->parse_opts & LYD_PARSE_OPAQ);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200477 ret = lydxml_attrs(xmlctx, &attr);
478 LY_CHECK_GOTO(ret, error);
479 }
480 }
481
482 assert(xmlctx->status == LYXML_ELEM_CONTENT);
483 if (!snode) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100484 assert(lydctx->parse_opts & LYD_PARSE_OPAQ);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200485
486 if (xmlctx->ws_only) {
487 /* ignore WS-only value */
488 xmlctx->value_len = 0;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100489 format = LY_PREF_XML;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200490 } else {
491 /* get value prefixes */
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100492 ret = ly_store_prefix_data(xmlctx->ctx, xmlctx->value, xmlctx->value_len, LY_PREF_XML,
493 &xmlctx->ns, &format, &val_prefix_data);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200494 LY_CHECK_GOTO(ret, error);
495 }
496
497 /* create node */
Michal Vasko501af032020-11-11 20:27:44 +0100498 ret = lyd_create_opaq(ctx, name, name_len, prefix, prefix_len, ns->uri, strlen(ns->uri), xmlctx->value,
499 xmlctx->value_len, &xmlctx->dynamic, format, val_prefix_data, LYD_HINT_DATA, &node);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200500 LY_CHECK_GOTO(ret, error);
501
502 /* parser next */
503 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
504
505 /* process children */
506 while (xmlctx->status == LYXML_ELEMENT) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100507 ret = lydxml_subtree_r(lydctx, node, lyd_node_child_p(node), NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200508 LY_CHECK_GOTO(ret, error);
509 }
510 } else if (snode->nodetype & LYD_NODE_TERM) {
511 /* create node */
Michal Vasko22df3f02020-08-24 13:29:22 +0200512 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 +0200513 &xmlctx->dynamic, LY_PREF_XML, &xmlctx->ns, LYD_HINT_DATA, &node), error);
Radek Krejciddace2c2021-01-08 11:30:56 +0100514 LOG_LOCSET(snode, node, NULL, NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200515
516 if (parent && (node->schema->flags & LYS_KEY)) {
517 /* check the key order, the anchor must never be a key */
Michal Vaskoe0665742021-02-11 11:08:44 +0100518 anchor = lyd_insert_get_next_anchor(lyd_child(parent), node);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200519 if (anchor && (anchor->schema->flags & LYS_KEY)) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100520 if (lydctx->parse_opts & LYD_PARSE_STRICT) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100521 LOGVAL(ctx, LYVE_DATA, "Invalid position of the key \"%s\" in a list.", node->schema->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200522 ret = LY_EVALID;
523 goto error;
524 } else {
525 LOGWRN(ctx, "Invalid position of the key \"%s\" in a list.", node->schema->name);
526 }
527 }
528 }
529
530 /* parser next */
531 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
532
533 /* no children expected */
534 if (xmlctx->status == LYXML_ELEMENT) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100535 LOGVAL(ctx, LYVE_SYNTAX, "Child element \"%.*s\" inside a terminal node \"%s\" found.",
Michal Vasko69730152020-10-09 16:30:07 +0200536 xmlctx->name_len, xmlctx->name, snode->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200537 ret = LY_EVALID;
538 goto error;
539 }
540 } else if (snode->nodetype & LYD_NODE_INNER) {
541 if (!xmlctx->ws_only) {
542 /* value in inner node */
Radek Krejci2efc45b2020-12-22 16:25:44 +0100543 LOGVAL(ctx, LYVE_SYNTAX, "Text value \"%.*s\" inside an inner node \"%s\" found.",
Michal Vasko69730152020-10-09 16:30:07 +0200544 xmlctx->value_len, xmlctx->value, snode->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200545 ret = LY_EVALID;
546 goto error;
547 }
548
549 /* create node */
550 ret = lyd_create_inner(snode, &node);
551 LY_CHECK_GOTO(ret, error);
552
Radek Krejciddace2c2021-01-08 11:30:56 +0100553 LOG_LOCSET(snode, node, NULL, NULL);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100554
Michal Vaskoa5da3292020-08-12 13:10:50 +0200555 /* parser next */
556 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
557
558 /* process children */
559 while (xmlctx->status == LYXML_ELEMENT) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100560 ret = lydxml_subtree_r(lydctx, node, lyd_node_child_p(node), NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200561 LY_CHECK_GOTO(ret, error);
562 }
563
564 if (snode->nodetype == LYS_LIST) {
565 /* check all keys exist */
566 LY_CHECK_GOTO(ret = lyd_parse_check_keys(node), error);
567 }
568
Michal Vaskoe0665742021-02-11 11:08:44 +0100569 if (!(lydctx->parse_opts & LYD_PARSE_ONLY)) {
Michal Vaskoa5da3292020-08-12 13:10:50 +0200570 /* new node validation, autodelete CANNOT occur, all nodes are new */
Michal Vaskoe0665742021-02-11 11:08:44 +0100571 ret = lyd_validate_new(lyd_node_child_p(node), snode, NULL, NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200572 LY_CHECK_GOTO(ret, error);
573
574 /* add any missing default children */
Michal Vaskoe0665742021-02-11 11:08:44 +0100575 ret = lyd_new_implicit_r(node, lyd_node_child_p(node), NULL, NULL, &lydctx->node_types, &lydctx->node_when,
576 (lydctx->val_opts & LYD_VALIDATE_NO_STATE) ? LYD_IMPLICIT_NO_STATE : 0, NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200577 LY_CHECK_GOTO(ret, error);
578 }
579
580 if (snode->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) {
581 /* rememeber the RPC/action/notification */
582 lydctx->op_node = node;
583 }
584 } else if (snode->nodetype & LYD_NODE_ANY) {
585 if (!xmlctx->ws_only) {
586 /* value in inner node */
Radek Krejci2efc45b2020-12-22 16:25:44 +0100587 LOGVAL(ctx, LYVE_SYNTAX, "Text value \"%.*s\" inside an any node \"%s\" found.",
Michal Vasko69730152020-10-09 16:30:07 +0200588 xmlctx->value_len, xmlctx->value, snode->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200589 ret = LY_EVALID;
590 goto error;
591 }
592
593 /* parser next */
594 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
595
596 /* parse any data tree with correct options */
Michal Vaskoe0665742021-02-11 11:08:44 +0100597 prev_opts = lydctx->parse_opts;
598 lydctx->parse_opts &= ~LYD_PARSE_STRICT;
599 lydctx->parse_opts |= LYD_PARSE_OPAQ;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200600 anchor = NULL;
601 while (xmlctx->status == LYXML_ELEMENT) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100602 ret = lydxml_subtree_r(lydctx, NULL, &anchor, NULL);
603 LY_CHECK_ERR_GOTO(ret, lydctx->parse_opts = prev_opts, error);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200604 }
Michal Vaskoe0665742021-02-11 11:08:44 +0100605 lydctx->parse_opts = prev_opts;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200606
607 /* create node */
Michal Vasko366a4a12020-12-04 16:23:57 +0100608 ret = lyd_create_any(snode, anchor, LYD_ANYDATA_DATATREE, 1, &node);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200609 LY_CHECK_GOTO(ret, error);
610 }
611 assert(node);
612
613 /* add/correct flags */
614 if (snode) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100615 lyd_parse_set_data_flags(node, &lydctx->node_when, &meta, lydctx->parse_opts);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200616 }
617
618 /* parser next */
619 assert(xmlctx->status == LYXML_ELEM_CLOSE);
620 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
621
622 /* add metadata/attributes */
623 if (snode) {
Michal Vasko871a0252020-11-11 18:35:24 +0100624 lyd_insert_meta(node, meta, 0);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200625 } else {
626 lyd_insert_attr(node, attr);
627 }
628
629 /* insert, keep first pointer correct */
Michal Vaskoe0665742021-02-11 11:08:44 +0100630 lyd_insert_node(parent, first_p, node);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200631 while (!parent && (*first_p)->prev->next) {
632 *first_p = (*first_p)->prev;
633 }
634
Michal Vaskoe0665742021-02-11 11:08:44 +0100635 /* rememeber a successfully parsed node */
636 if (parsed) {
637 ly_set_add(parsed, node, 1, NULL);
638 }
639
Radek Krejciddace2c2021-01-08 11:30:56 +0100640 LOG_LOCBACK(node ? 1 : 0, node ? 1 : 0, 0, 0);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200641 return LY_SUCCESS;
642
643error:
Radek Krejciddace2c2021-01-08 11:30:56 +0100644 LOG_LOCBACK(node ? 1 : 0, node ? 1 : 0, 0, 0);
Michal Vasko3a41dff2020-07-15 14:30:28 +0200645 lyd_free_meta_siblings(meta);
Radek Krejci011e4aa2020-09-04 15:22:31 +0200646 lyd_free_attr_siblings(ctx, attr);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200647 lyd_free_tree(node);
Radek Krejcie7b95092019-05-15 11:03:07 +0200648 return ret;
649}
650
Michal Vaskoe0665742021-02-11 11:08:44 +0100651/**
652 * @brief Parse a specific XML element into an opaque node.
653 *
654 * @param[in] xmlctx XML parser context.
655 * @param[in] name Name of the element.
656 * @param[in] uri URI of the element.
657 * @param[in] value Whether a value is expected in the element.
658 * @param[out] evnp Parsed envelope (opaque node).
659 * @return LY_SUCCESS on success.
660 * @return LY_ENOT if the specified element did not match.
661 * @return LY_ERR value on error.
662 */
Michal Vasko1bf09392020-03-27 12:38:10 +0100663static LY_ERR
Michal Vaskoe0665742021-02-11 11:08:44 +0100664lydxml_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 +0100665{
Michal Vaskoe0665742021-02-11 11:08:44 +0100666 LY_ERR rc = LY_SUCCESS;
667 const struct lyxml_ns *ns;
Radek Krejci1798aae2020-07-14 13:26:06 +0200668 struct lyd_attr *attr = NULL;
Michal Vasko1bf09392020-03-27 12:38:10 +0100669 const char *prefix;
670 size_t prefix_len;
671
Michal Vasko1bf09392020-03-27 12:38:10 +0100672 assert(xmlctx->status == LYXML_ELEMENT);
673 if (ly_strncmp(name, xmlctx->name, xmlctx->name_len)) {
674 /* not the expected element */
Michal Vaskoe0665742021-02-11 11:08:44 +0100675 return LY_ENOT;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100676 }
677
678 prefix = xmlctx->prefix;
679 prefix_len = xmlctx->prefix_len;
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200680 ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100681 if (!ns) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100682 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", prefix_len, prefix);
Michal Vaskoe0665742021-02-11 11:08:44 +0100683 return LY_EVALID;
684 } else if (strcmp(ns->uri, uri)) {
685 /* different namespace */
686 return LY_ENOT;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100687 }
688
689 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
690
691 /* create attributes */
692 if (xmlctx->status == LYXML_ATTRIBUTE) {
693 LY_CHECK_RET(lydxml_attrs(xmlctx, &attr));
694 }
695
Michal Vaskoe0665742021-02-11 11:08:44 +0100696 assert(xmlctx->status == LYXML_ELEM_CONTENT);
697 if (!value && !xmlctx->ws_only) {
698 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected value \"%.*s\" in the \"%s\" element.",
699 xmlctx->value_len, xmlctx->value, name);
700 rc = LY_EVALID;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100701 goto cleanup;
Michal Vaskoe0665742021-02-11 11:08:44 +0100702 }
Michal Vaskoa8edff02020-03-27 14:47:01 +0100703
704 /* create node */
Michal Vaskoe0665742021-02-11 11:08:44 +0100705 rc = lyd_create_opaq(xmlctx->ctx, name, strlen(name), prefix, prefix_len, uri, strlen(uri), xmlctx->value,
706 xmlctx->ws_only ? 0 : xmlctx->value_len, NULL, LY_PREF_XML, NULL, 0, envp);
707 LY_CHECK_GOTO(rc, cleanup);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100708
709 /* assign atributes */
Michal Vaskoe0665742021-02-11 11:08:44 +0100710 ((struct lyd_node_opaq *)(*envp))->attr = attr;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100711 attr = NULL;
712
Michal Vaskoe0665742021-02-11 11:08:44 +0100713 /* parser next element */
714 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100715
Michal Vaskoe0665742021-02-11 11:08:44 +0100716cleanup:
717 lyd_free_attr_siblings(xmlctx->ctx, attr);
718 if (rc) {
719 lyd_free_tree(*envp);
720 *envp = NULL;
721 }
722 return rc;
723}
724
725/**
726 * @brief Parse all expected non-data XML elements of a NETCONF rpc message.
727 *
728 * @param[in] xmlctx XML parser context.
729 * @param[out] evnp Parsed envelope(s) (opaque node).
730 * @param[out] int_opts Internal options for parsing the rest of YANG data.
731 * @param[out] close_elem Number of parsed opened elements that need to be closed.
732 * @return LY_SUCCESS on success.
733 * @return LY_ERR value on error.
734 */
735static LY_ERR
736lydxml_env_netconf_rpc(struct lyxml_ctx *xmlctx, struct lyd_node **envp, uint32_t *int_opts, uint32_t *close_elem)
737{
738 LY_ERR rc = LY_SUCCESS, r;
739 struct lyd_node *child;
740
741 assert(envp && !*envp);
742
743 /* parse "rpc" */
744 r = lydxml_envelope(xmlctx, "rpc", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, envp);
Michal Vaskoe0665742021-02-11 11:08:44 +0100745 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
746
747 /* parse "action", if any */
748 r = lydxml_envelope(xmlctx, "action", "urn:ietf:params:xml:ns:yang:1", 0, &child);
749 if (r == LY_SUCCESS) {
750 /* insert */
751 lyd_insert_node(*envp, NULL, child);
752
753 /* NETCONF action */
754 *int_opts = LYD_INTOPT_NO_SIBLINGS | LYD_INTOPT_ACTION;
755 *close_elem = 2;
756 } else if (r == LY_ENOT) {
757 /* NETCONF RPC */
758 *int_opts = LYD_INTOPT_NO_SIBLINGS | LYD_INTOPT_RPC;
759 *close_elem = 1;
760 } else {
761 rc = r;
762 goto cleanup;
763 }
764
765cleanup:
766 if (rc) {
767 lyd_free_tree(*envp);
768 *envp = NULL;
769 }
770 return rc;
771}
772
773/**
774 * @brief Parse all expected non-data XML elements of a NETCONF notification message.
775 *
776 * @param[in] xmlctx XML parser context.
777 * @param[out] evnp Parsed envelope(s) (opaque node).
778 * @param[out] int_opts Internal options for parsing the rest of YANG data.
779 * @param[out] close_elem Number of parsed opened elements that need to be closed.
780 * @return LY_SUCCESS on success.
781 * @return LY_ERR value on error.
782 */
783static LY_ERR
784lydxml_env_netconf_notif(struct lyxml_ctx *xmlctx, struct lyd_node **envp, uint32_t *int_opts, uint32_t *close_elem)
785{
786 LY_ERR rc = LY_SUCCESS, r;
787 struct lyd_node *child;
788
789 assert(envp && !*envp);
790
791 /* parse "notification" */
792 r = lydxml_envelope(xmlctx, "notification", "urn:ietf:params:xml:ns:netconf:notification:1.0", 0, envp);
Michal Vaskoe0665742021-02-11 11:08:44 +0100793 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
794
795 /* parse "eventTime" */
796 r = lydxml_envelope(xmlctx, "eventTime", "urn:ietf:params:xml:ns:netconf:notification:1.0", 1, &child);
797 if (r == LY_ENOT) {
798 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unexpected element \"%.*s\" instead of \"eventTime\".", xmlctx->name_len,
799 xmlctx->name);
800 r = LY_EVALID;
801 }
802 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
803
804 /* insert */
805 lyd_insert_node(*envp, NULL, child);
806
807 /* validate value */
808 /* TODO validate child->value as yang:date-and-time */
809
810 /* finish child parsing */
Michal Vaskoa8edff02020-03-27 14:47:01 +0100811 if (xmlctx->status != LYXML_ELEM_CLOSE) {
812 assert(xmlctx->status == LYXML_ELEMENT);
Michal Vaskoe0665742021-02-11 11:08:44 +0100813 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"eventTime\".",
Michal Vasko69730152020-10-09 16:30:07 +0200814 xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +0100815 rc = LY_EVALID;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100816 goto cleanup;
817 }
Michal Vaskoe0665742021-02-11 11:08:44 +0100818 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
819
820 /* NETCONF notification */
821 *int_opts = LYD_INTOPT_NO_SIBLINGS | LYD_INTOPT_NOTIF;
822 *close_elem = 1;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100823
824cleanup:
Michal Vaskoe0665742021-02-11 11:08:44 +0100825 if (rc) {
Michal Vaskoa8edff02020-03-27 14:47:01 +0100826 lyd_free_tree(*envp);
Michal Vaskoe0665742021-02-11 11:08:44 +0100827 *envp = NULL;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100828 }
Michal Vaskoe0665742021-02-11 11:08:44 +0100829 return rc;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100830}
Michal Vasko79135ae2020-12-16 10:08:35 +0100831
Michal Vaskoe0665742021-02-11 11:08:44 +0100832/**
833 * @brief Parse an XML element as an opaque node subtree.
834 *
835 * @param[in] xmlctx XML parser context.
836 * @param[in] parent Parent to append nodes to.
837 * @return LY_ERR value.
838 */
839static LY_ERR
840lydxml_opaq_r(struct lyxml_ctx *xmlctx, struct lyd_node *parent)
Michal Vaskoa8edff02020-03-27 14:47:01 +0100841{
Michal Vaskoe0665742021-02-11 11:08:44 +0100842 LY_ERR rc = LY_SUCCESS;
843 const struct lyxml_ns *ns;
844 struct lyd_attr *attr = NULL;
845 struct lyd_node *child = NULL;
846 const char *name, *prefix;
847 size_t name_len, prefix_len;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100848
Michal Vaskoe0665742021-02-11 11:08:44 +0100849 assert(xmlctx->status == LYXML_ELEMENT);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100850
Michal Vaskoe0665742021-02-11 11:08:44 +0100851 name = xmlctx->name;
852 name_len = xmlctx->name_len;
853 prefix = xmlctx->prefix;
854 prefix_len = xmlctx->prefix_len;
855 ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
856 if (!ns) {
857 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", prefix_len, prefix);
858 return LY_EVALID;
859 }
Michal Vaskoa8edff02020-03-27 14:47:01 +0100860
Michal Vaskoe0665742021-02-11 11:08:44 +0100861 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
Michal Vaskoa8edff02020-03-27 14:47:01 +0100862
Michal Vaskoe0665742021-02-11 11:08:44 +0100863 /* create attributes */
864 if (xmlctx->status == LYXML_ATTRIBUTE) {
865 LY_CHECK_RET(lydxml_attrs(xmlctx, &attr));
866 }
867
868 /* create node */
869 assert(xmlctx->status == LYXML_ELEM_CONTENT);
870 rc = lyd_create_opaq(xmlctx->ctx, name, name_len, prefix, prefix_len, ns->uri, strlen(ns->uri), xmlctx->value,
871 xmlctx->ws_only ? 0 : xmlctx->value_len, NULL, LY_PREF_XML, NULL, 0, &child);
872 LY_CHECK_GOTO(rc, cleanup);
873
874 /* assign atributes */
875 ((struct lyd_node_opaq *)child)->attr = attr;
876 attr = NULL;
877
878 /* parser next element */
879 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
880
881 /* parse all the descendants */
882 while (xmlctx->status == LYXML_ELEMENT) {
883 rc = lydxml_opaq_r(xmlctx, child);
884 LY_CHECK_GOTO(rc, cleanup);
885 }
886
887 /* insert */
888 lyd_insert_node(parent, NULL, child);
889
890cleanup:
891 lyd_free_attr_siblings(xmlctx->ctx, attr);
892 if (rc) {
893 lyd_free_tree(child);
894 }
895 return rc;
896}
897
898/**
899 * @brief Parse all expected non-data XML elements of the error-info element in NETCONF rpc-reply message.
900 *
901 * @param[in] xmlctx XML parser context.
902 * @param[in] parent Parent to append nodes to.
903 * @return LY_ERR value.
904 */
905static LY_ERR
906lydxml_env_netconf_rpc_reply_error_info(struct lyxml_ctx *xmlctx, struct lyd_node *parent)
907{
908 LY_ERR r;
909 struct lyd_node *child, *iter;
910 const struct lyxml_ns *ns;
911 ly_bool no_dup;
912
913 /* there must be some child */
914 if (xmlctx->status == LYXML_ELEM_CLOSE) {
915 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Missing child elements of \"error-info\".");
916 return LY_EVALID;
917 }
918
919 while (xmlctx->status == LYXML_ELEMENT) {
920 child = NULL;
921
922 /*
923 * session-id
924 */
925 r = lydxml_envelope(xmlctx, "session-id", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
926 if (r == LY_SUCCESS) {
927 no_dup = 1;
928 goto check_child;
929 } else if (r != LY_ENOT) {
930 goto error;
931 }
932
933 /*
934 * bad-attribute
935 */
936 r = lydxml_envelope(xmlctx, "bad-attribute", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
937 if (r == LY_SUCCESS) {
938 no_dup = 1;
939 goto check_child;
940 } else if (r != LY_ENOT) {
941 goto error;
942 }
943
944 /*
945 * bad-element
946 */
947 r = lydxml_envelope(xmlctx, "bad-element", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
948 if (r == LY_SUCCESS) {
949 no_dup = 1;
950 goto check_child;
951 } else if (r != LY_ENOT) {
952 goto error;
953 }
954
955 /*
956 * bad-namespace
957 */
958 r = lydxml_envelope(xmlctx, "bad-namespace", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
959 if (r == LY_SUCCESS) {
960 no_dup = 1;
961 goto check_child;
962 } else if (r != LY_ENOT) {
963 goto error;
964 }
965
966 if (r == LY_ENOT) {
967 assert(xmlctx->status == LYXML_ELEMENT);
968
969 /* learn namespace */
970 ns = lyxml_ns_get(&xmlctx->ns, xmlctx->prefix, xmlctx->prefix_len);
971 if (!ns) {
972 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", xmlctx->prefix_len, xmlctx->prefix);
973 r = LY_EVALID;
974 goto error;
975 } else if (!strcmp(ns->uri, "urn:ietf:params:xml:ns:netconf:base:1.0")) {
976 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"error-info\".",
Radek Krejci53875452021-02-16 13:44:51 +0100977 xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +0100978 r = LY_EVALID;
979 goto error;
980 }
981
982 /* custom elements */
983 r = lydxml_opaq_r(xmlctx, parent);
984 LY_CHECK_GOTO(r, error);
985
986 no_dup = 0;
987 }
988
989check_child:
990 /* check for duplicates */
991 if (no_dup) {
992 LY_LIST_FOR(lyd_child(parent), iter) {
993 if ((((struct lyd_node_opaq *)iter)->name.name == ((struct lyd_node_opaq *)child)->name.name) &&
994 (((struct lyd_node_opaq *)iter)->name.module_ns == ((struct lyd_node_opaq *)child)->name.module_ns)) {
995 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Duplicate element \"%s\" in \"error-info\".",
996 ((struct lyd_node_opaq *)child)->name.name);
997 r = LY_EVALID;
998 goto error;
999 }
1000 }
1001 }
1002
1003 /* finish child parsing */
1004 if (xmlctx->status != LYXML_ELEM_CLOSE) {
1005 assert(xmlctx->status == LYXML_ELEMENT);
1006 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"error-info\".",
1007 xmlctx->name_len, xmlctx->name);
1008 r = LY_EVALID;
1009 goto error;
1010 }
1011 LY_CHECK_GOTO(r = lyxml_ctx_next(xmlctx), error);
1012
1013 /* insert */
1014 lyd_insert_node(parent, NULL, child);
1015 }
1016
1017 return LY_SUCCESS;
1018
1019error:
1020 lyd_free_tree(child);
1021 return r;
1022}
1023
1024/**
1025 * @brief Parse all expected non-data XML elements of the rpc-error element in NETCONF rpc-reply message.
1026 *
1027 * @param[in] xmlctx XML parser context.
1028 * @param[in] parent Parent to append nodes to.
1029 * @return LY_ERR value.
1030 */
1031static LY_ERR
1032lydxml_env_netconf_rpc_reply_error(struct lyxml_ctx *xmlctx, struct lyd_node *parent)
1033{
1034 LY_ERR r;
1035 struct lyd_node *child, *iter;
1036 const char *val;
1037 ly_bool no_dup;
1038
1039 /* there must be some child */
1040 if (xmlctx->status == LYXML_ELEM_CLOSE) {
1041 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Missing child elements of \"rpc-error\".");
1042 return LY_EVALID;
1043 }
1044
1045 while (xmlctx->status == LYXML_ELEMENT) {
1046 child = NULL;
1047
1048 /*
1049 * error-type
1050 */
1051 r = lydxml_envelope(xmlctx, "error-type", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1052 if (r == LY_SUCCESS) {
1053 val = ((struct lyd_node_opaq *)child)->value;
1054 if (strcmp(val, "transport") && strcmp(val, "rpc") && strcmp(val, "protocol") && strcmp(val, "application")) {
1055 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Invalid value \"%s\" of element \"%s\".", val,
1056 ((struct lyd_node_opaq *)child)->name.name);
1057 r = LY_EVALID;
1058 goto error;
1059 }
1060
1061 no_dup = 1;
1062 goto check_child;
1063 } else if (r != LY_ENOT) {
1064 goto error;
1065 }
1066
1067 /*
1068 * error-tag
1069 */
1070 r = lydxml_envelope(xmlctx, "error-tag", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1071 if (r == LY_SUCCESS) {
1072 val = ((struct lyd_node_opaq *)child)->value;
1073 if (strcmp(val, "in-use") && strcmp(val, "invalid-value") && strcmp(val, "too-big") &&
1074 strcmp(val, "missing-attribute") && strcmp(val, "bad-attribute") &&
1075 strcmp(val, "unknown-attribute") && strcmp(val, "missing-element") && strcmp(val, "bad-element") &&
1076 strcmp(val, "unknown-element") && strcmp(val, "unknown-namespace") && strcmp(val, "access-denied") &&
1077 strcmp(val, "lock-denied") && strcmp(val, "resource-denied") && strcmp(val, "rollback-failed") &&
1078 strcmp(val, "data-exists") && strcmp(val, "data-missing") && strcmp(val, "operation-not-supported") &&
1079 strcmp(val, "operation-failed") && strcmp(val, "malformed-message")) {
1080 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Invalid value \"%s\" of element \"%s\".", val,
1081 ((struct lyd_node_opaq *)child)->name.name);
1082 r = LY_EVALID;
1083 goto error;
1084 }
1085
1086 no_dup = 1;
1087 goto check_child;
1088 } else if (r != LY_ENOT) {
1089 goto error;
1090 }
1091
1092 /*
1093 * error-severity
1094 */
1095 r = lydxml_envelope(xmlctx, "error-severity", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1096 if (r == LY_SUCCESS) {
1097 val = ((struct lyd_node_opaq *)child)->value;
1098 if (strcmp(val, "error") && strcmp(val, "warning")) {
1099 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Invalid value \"%s\" of element \"%s\".", val,
1100 ((struct lyd_node_opaq *)child)->name.name);
1101 r = LY_EVALID;
1102 goto error;
1103 }
1104
1105 no_dup = 1;
1106 goto check_child;
1107 } else if (r != LY_ENOT) {
1108 goto error;
1109 }
1110
1111 /*
1112 * error-app-tag
1113 */
1114 r = lydxml_envelope(xmlctx, "error-app-tag", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1115 if (r == LY_SUCCESS) {
1116 no_dup = 1;
1117 goto check_child;
1118 } else if (r != LY_ENOT) {
1119 goto error;
1120 }
1121
1122 /*
1123 * error-path
1124 */
1125 r = lydxml_envelope(xmlctx, "error-path", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1126 if (r == LY_SUCCESS) {
1127 no_dup = 1;
1128 goto check_child;
1129 } else if (r != LY_ENOT) {
1130 goto error;
1131 }
1132
1133 /*
1134 * error-message
1135 */
1136 r = lydxml_envelope(xmlctx, "error-message", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1137 if (r == LY_SUCCESS) {
1138 no_dup = 1;
1139 goto check_child;
1140 } else if (r != LY_ENOT) {
1141 goto error;
1142 }
1143
1144 /* error-info */
1145 r = lydxml_envelope(xmlctx, "error-info", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, &child);
1146 if (r == LY_SUCCESS) {
1147 /* parse all the descendants */
1148 LY_CHECK_GOTO(r = lydxml_env_netconf_rpc_reply_error_info(xmlctx, child), error);
1149
1150 no_dup = 0;
1151 goto check_child;
1152 } else if (r != LY_ENOT) {
1153 goto error;
1154 }
1155
1156 if (r == LY_ENOT) {
1157 assert(xmlctx->status == LYXML_ELEMENT);
1158 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"rpc-error\".",
1159 xmlctx->name_len, xmlctx->name);
1160 r = LY_EVALID;
1161 goto error;
1162 }
1163
1164check_child:
1165 /* check for duplicates */
1166 if (no_dup) {
1167 LY_LIST_FOR(lyd_child(parent), iter) {
1168 if ((((struct lyd_node_opaq *)iter)->name.name == ((struct lyd_node_opaq *)child)->name.name) &&
1169 (((struct lyd_node_opaq *)iter)->name.module_ns == ((struct lyd_node_opaq *)child)->name.module_ns)) {
1170 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Duplicate element \"%s\" in \"rpc-error\".",
1171 ((struct lyd_node_opaq *)child)->name.name);
1172 r = LY_EVALID;
1173 goto error;
1174 }
1175 }
1176 }
1177
1178 /* finish child parsing */
1179 if (xmlctx->status != LYXML_ELEM_CLOSE) {
1180 assert(xmlctx->status == LYXML_ELEMENT);
1181 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"rpc-error\".",
1182 xmlctx->name_len, xmlctx->name);
1183 r = LY_EVALID;
1184 goto error;
1185 }
1186 LY_CHECK_GOTO(r = lyxml_ctx_next(xmlctx), error);
1187
1188 /* insert */
1189 lyd_insert_node(parent, NULL, child);
1190 }
1191
1192 return LY_SUCCESS;
1193
1194error:
1195 lyd_free_tree(child);
1196 return r;
1197}
1198
1199/**
1200 * @brief Parse all expected non-data XML elements of a NETCONF rpc-reply message.
1201 *
1202 * @param[in] xmlctx XML parser context.
1203 * @param[out] evnp Parsed envelope(s) (opaque node).
1204 * @param[out] int_opts Internal options for parsing the rest of YANG data.
1205 * @param[out] close_elem Number of parsed opened elements that need to be closed.
1206 * @return LY_SUCCESS on success.
1207 * @return LY_ERR value on error.
1208 */
1209static LY_ERR
1210lydxml_env_netconf_reply(struct lyxml_ctx *xmlctx, struct lyd_node **envp, uint32_t *int_opts, uint32_t *close_elem)
1211{
1212 LY_ERR rc = LY_SUCCESS, r;
1213 struct lyd_node *child = NULL;
1214 const char *parsed_elem = NULL;
1215
1216 assert(envp && !*envp);
1217
1218 /* parse "rpc-reply" */
1219 r = lydxml_envelope(xmlctx, "rpc-reply", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, envp);
Michal Vaskoe0665742021-02-11 11:08:44 +01001220 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
1221
1222 /* there must be some child */
1223 if (xmlctx->status == LYXML_ELEM_CLOSE) {
1224 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Missing child elements of \"rpc-reply\".");
1225 rc = LY_EVALID;
Michal Vaskocf770e22020-08-12 13:21:43 +02001226 goto cleanup;
Michal Vaskoa8edff02020-03-27 14:47:01 +01001227 }
1228
Michal Vaskoe0665742021-02-11 11:08:44 +01001229 /* try to parse "ok" */
1230 r = lydxml_envelope(xmlctx, "ok", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, &child);
1231 if (r == LY_SUCCESS) {
1232 /* insert */
1233 lyd_insert_node(*envp, NULL, child);
1234
1235 /* finish child parsing */
1236 if (xmlctx->status != LYXML_ELEM_CLOSE) {
1237 assert(xmlctx->status == LYXML_ELEMENT);
1238 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"ok\".",
1239 xmlctx->name_len, xmlctx->name);
1240 rc = LY_EVALID;
1241 goto cleanup;
1242 }
1243 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
1244
1245 /* success */
1246 parsed_elem = "ok";
1247 goto finish;
1248 } else if (r != LY_ENOT) {
1249 rc = r;
1250 goto cleanup;
Michal Vasko2552ea32020-12-08 15:32:34 +01001251 }
1252
Michal Vaskoe0665742021-02-11 11:08:44 +01001253 /* try to parse all "rpc-error" elements */
1254 while (xmlctx->status == LYXML_ELEMENT) {
1255 r = lydxml_envelope(xmlctx, "rpc-error", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, &child);
1256 if (r == LY_ENOT) {
1257 break;
1258 } else if (r) {
1259 rc = r;
1260 goto cleanup;
1261 }
1262
1263 /* insert */
1264 lyd_insert_node(*envp, NULL, child);
1265
1266 /* parse all children of "rpc-error" */
1267 LY_CHECK_GOTO(rc = lydxml_env_netconf_rpc_reply_error(xmlctx, child), cleanup);
1268
1269 /* finish child parsing */
1270 assert(xmlctx->status == LYXML_ELEM_CLOSE);
1271 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
1272
1273 parsed_elem = "rpc-error";
Michal Vasko2552ea32020-12-08 15:32:34 +01001274 }
Michal Vaskoe0665742021-02-11 11:08:44 +01001275
1276finish:
1277 if (parsed_elem) {
1278 /* NETCONF rpc-reply with no data */
1279 if (xmlctx->status != LYXML_ELEM_CLOSE) {
1280 assert(xmlctx->status == LYXML_ELEMENT);
1281 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected sibling element \"%.*s\" of \"%s\".",
1282 xmlctx->name_len, xmlctx->name, parsed_elem);
1283 rc = LY_EVALID;
1284 goto cleanup;
1285 }
1286 }
1287
1288 /* NETCONF rpc-reply */
1289 *int_opts = LYD_INTOPT_NO_SIBLINGS | LYD_INTOPT_REPLY;
1290 *close_elem = 1;
1291
1292cleanup:
1293 if (rc) {
1294 lyd_free_tree(*envp);
1295 *envp = NULL;
1296 }
1297 return rc;
1298}
1299
Michal Vasko2552ea32020-12-08 15:32:34 +01001300LY_ERR
Radek Krejcif16e2542021-02-17 15:39:23 +01001301lyd_parse_xml(const struct ly_ctx *ctx, const struct lysc_ext_instance *ext, struct lyd_node *parent,
1302 struct lyd_node **first_p, struct ly_in *in, uint32_t parse_opts, uint32_t val_opts, enum lyd_type data_type,
1303 struct lyd_node **envp, struct ly_set *parsed, struct lyd_ctx **lydctx_p)
Michal Vasko2552ea32020-12-08 15:32:34 +01001304{
Michal Vaskoe0665742021-02-11 11:08:44 +01001305 LY_ERR rc = LY_SUCCESS;
1306 struct lyd_xml_ctx *lydctx;
1307 uint32_t i, int_opts, close_elem = 0;
1308 ly_bool parsed_data_nodes = 0;
Michal Vasko2552ea32020-12-08 15:32:34 +01001309
Michal Vaskoe0665742021-02-11 11:08:44 +01001310 assert(ctx && in && lydctx_p);
1311 assert(!(parse_opts & ~LYD_PARSE_OPTS_MASK));
1312 assert(!(val_opts & ~LYD_VALIDATE_OPTS_MASK));
Michal Vasko2552ea32020-12-08 15:32:34 +01001313
Michal Vaskoe0665742021-02-11 11:08:44 +01001314 /* init context */
1315 lydctx = calloc(1, sizeof *lydctx);
1316 LY_CHECK_ERR_RET(!lydctx, LOGMEM(ctx), LY_EMEM);
1317 LY_CHECK_GOTO(rc = lyxml_ctx_new(ctx, in, &lydctx->xmlctx), cleanup);
1318 lydctx->parse_opts = parse_opts;
1319 lydctx->val_opts = val_opts;
1320 lydctx->free = lyd_xml_ctx_free;
Radek Krejcif16e2542021-02-17 15:39:23 +01001321 lydctx->ext = ext;
Michal Vasko2552ea32020-12-08 15:32:34 +01001322
Michal Vaskoe0665742021-02-11 11:08:44 +01001323 switch (data_type) {
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001324 case LYD_TYPE_DATA_YANG:
Michal Vaskoe0665742021-02-11 11:08:44 +01001325 int_opts = LYD_INTOPT_WITH_SIBLINGS;
1326 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001327 case LYD_TYPE_RPC_YANG:
Michal Vaskoe0665742021-02-11 11:08:44 +01001328 int_opts = LYD_INTOPT_RPC | LYD_INTOPT_ACTION | LYD_INTOPT_NO_SIBLINGS;
1329 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001330 case LYD_TYPE_NOTIF_YANG:
Michal Vaskoe0665742021-02-11 11:08:44 +01001331 int_opts = LYD_INTOPT_NOTIF | LYD_INTOPT_NO_SIBLINGS;
1332 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001333 case LYD_TYPE_REPLY_YANG:
Michal Vaskoe0665742021-02-11 11:08:44 +01001334 int_opts = LYD_INTOPT_REPLY | LYD_INTOPT_NO_SIBLINGS;
1335 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001336 case LYD_TYPE_RPC_NETCONF:
Michal Vaskoe0665742021-02-11 11:08:44 +01001337 assert(!parent);
1338 LY_CHECK_GOTO(rc = lydxml_env_netconf_rpc(lydctx->xmlctx, envp, &int_opts, &close_elem), cleanup);
1339 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001340 case LYD_TYPE_NOTIF_NETCONF:
1341 assert(!parent);
1342 LY_CHECK_GOTO(rc = lydxml_env_netconf_notif(lydctx->xmlctx, envp, &int_opts, &close_elem), cleanup);
1343 break;
1344 case LYD_TYPE_REPLY_NETCONF:
Michal Vaskoe0665742021-02-11 11:08:44 +01001345 assert(parent);
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001346 LY_CHECK_GOTO(rc = lydxml_env_netconf_reply(lydctx->xmlctx, envp, &int_opts, &close_elem), cleanup);
Michal Vaskoe0665742021-02-11 11:08:44 +01001347 break;
1348 }
1349 lydctx->int_opts = int_opts;
1350
1351 /* find the operation node if it exists already */
1352 LY_CHECK_GOTO(rc = lyd_parser_find_operation(parent, int_opts, &lydctx->op_node), cleanup);
1353
1354 /* parse XML data */
1355 while (lydctx->xmlctx->status == LYXML_ELEMENT) {
1356 LY_CHECK_GOTO(rc = lydxml_subtree_r(lydctx, parent, first_p, parsed), cleanup);
1357 parsed_data_nodes = 1;
1358
1359 if (!(int_opts & LYD_INTOPT_WITH_SIBLINGS)) {
1360 break;
1361 }
Michal Vasko2552ea32020-12-08 15:32:34 +01001362 }
1363
Michal Vaskoe0665742021-02-11 11:08:44 +01001364 /* close all opened elements */
1365 for (i = 0; i < close_elem; ++i) {
1366 if (lydctx->xmlctx->status != LYXML_ELEM_CLOSE) {
1367 assert(lydctx->xmlctx->status == LYXML_ELEMENT);
1368 LOGVAL(lydctx->xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\".", lydctx->xmlctx->name_len,
1369 lydctx->xmlctx->name);
1370 rc = LY_EVALID;
1371 goto cleanup;
1372 }
1373
1374 LY_CHECK_GOTO(rc = lyxml_ctx_next(lydctx->xmlctx), cleanup);
Michal Vasko4189c0f2020-08-13 09:05:22 +02001375 }
Michal Vaskoe0665742021-02-11 11:08:44 +01001376
1377 /* check final state */
1378 if ((int_opts & LYD_INTOPT_NO_SIBLINGS) && (lydctx->xmlctx->status == LYXML_ELEMENT)) {
1379 LOGVAL(ctx, LYVE_SYNTAX, "Unexpected sibling node.");
1380 rc = LY_EVALID;
1381 goto cleanup;
1382 }
1383 if ((int_opts & (LYD_INTOPT_RPC | LYD_INTOPT_NOTIF | LYD_INTOPT_REPLY)) && !lydctx->op_node) {
1384 LOGVAL(ctx, LYVE_DATA, "Missing the operation node.");
1385 rc = LY_EVALID;
1386 goto cleanup;
1387 }
1388
1389 if (!parsed_data_nodes) {
1390 /* no data nodes were parsed */
1391 lydctx->op_node = NULL;
Michal Vaskoa8edff02020-03-27 14:47:01 +01001392 }
1393
1394cleanup:
Michal Vaskoe0665742021-02-11 11:08:44 +01001395 /* there should be no unres stored if validation should be skipped */
1396 assert(!(parse_opts & LYD_PARSE_ONLY) || (!lydctx->node_types.count && !lydctx->meta_types.count &&
1397 !lydctx->node_when.count));
1398
1399 if (rc) {
1400 lyd_xml_ctx_free((struct lyd_ctx *)lydctx);
1401 } else {
1402 *lydctx_p = (struct lyd_ctx *)lydctx;
1403
1404 /* the XML context is no more needed, freeing it also stops logging line numbers which would be confusing now */
1405 lyxml_ctx_free(lydctx->xmlctx);
1406 lydctx->xmlctx = NULL;
Michal Vasko1ce933a2020-03-30 12:38:22 +02001407 }
Michal Vaskoe0665742021-02-11 11:08:44 +01001408 return rc;
Michal Vasko1ce933a2020-03-30 12:38:22 +02001409}