blob: 40fda2fb12c969f99e0a40e441ea4118c538fc93 [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 */
Radek IÅ¡a017270d2021-02-16 10:26:15 +0100488 if (xmlctx->dynamic) {
489 free((char *) xmlctx->value);
490 }
491 xmlctx->dynamic = 0;
492 xmlctx->value = "";
Michal Vaskoa5da3292020-08-12 13:10:50 +0200493 xmlctx->value_len = 0;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100494 format = LY_PREF_XML;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200495 } else {
496 /* get value prefixes */
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100497 ret = ly_store_prefix_data(xmlctx->ctx, xmlctx->value, xmlctx->value_len, LY_PREF_XML,
498 &xmlctx->ns, &format, &val_prefix_data);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200499 LY_CHECK_GOTO(ret, error);
500 }
501
502 /* create node */
Michal Vasko501af032020-11-11 20:27:44 +0100503 ret = lyd_create_opaq(ctx, name, name_len, prefix, prefix_len, ns->uri, strlen(ns->uri), xmlctx->value,
504 xmlctx->value_len, &xmlctx->dynamic, format, val_prefix_data, LYD_HINT_DATA, &node);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200505 LY_CHECK_GOTO(ret, error);
506
507 /* parser next */
508 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
509
510 /* process children */
511 while (xmlctx->status == LYXML_ELEMENT) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100512 ret = lydxml_subtree_r(lydctx, node, lyd_node_child_p(node), NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200513 LY_CHECK_GOTO(ret, error);
514 }
515 } else if (snode->nodetype & LYD_NODE_TERM) {
516 /* create node */
Michal Vasko22df3f02020-08-24 13:29:22 +0200517 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 +0200518 &xmlctx->dynamic, LY_PREF_XML, &xmlctx->ns, LYD_HINT_DATA, &node), error);
Radek Krejciddace2c2021-01-08 11:30:56 +0100519 LOG_LOCSET(snode, node, NULL, NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200520
521 if (parent && (node->schema->flags & LYS_KEY)) {
522 /* check the key order, the anchor must never be a key */
Michal Vaskoe0665742021-02-11 11:08:44 +0100523 anchor = lyd_insert_get_next_anchor(lyd_child(parent), node);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200524 if (anchor && (anchor->schema->flags & LYS_KEY)) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100525 if (lydctx->parse_opts & LYD_PARSE_STRICT) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100526 LOGVAL(ctx, LYVE_DATA, "Invalid position of the key \"%s\" in a list.", node->schema->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200527 ret = LY_EVALID;
528 goto error;
529 } else {
530 LOGWRN(ctx, "Invalid position of the key \"%s\" in a list.", node->schema->name);
531 }
532 }
533 }
534
535 /* parser next */
536 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
537
538 /* no children expected */
539 if (xmlctx->status == LYXML_ELEMENT) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100540 LOGVAL(ctx, LYVE_SYNTAX, "Child element \"%.*s\" inside a terminal node \"%s\" found.",
Michal Vasko69730152020-10-09 16:30:07 +0200541 xmlctx->name_len, xmlctx->name, snode->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200542 ret = LY_EVALID;
543 goto error;
544 }
545 } else if (snode->nodetype & LYD_NODE_INNER) {
546 if (!xmlctx->ws_only) {
547 /* value in inner node */
Radek Krejci2efc45b2020-12-22 16:25:44 +0100548 LOGVAL(ctx, LYVE_SYNTAX, "Text value \"%.*s\" inside an inner node \"%s\" found.",
Michal Vasko69730152020-10-09 16:30:07 +0200549 xmlctx->value_len, xmlctx->value, snode->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200550 ret = LY_EVALID;
551 goto error;
552 }
553
554 /* create node */
555 ret = lyd_create_inner(snode, &node);
556 LY_CHECK_GOTO(ret, error);
557
Radek Krejciddace2c2021-01-08 11:30:56 +0100558 LOG_LOCSET(snode, node, NULL, NULL);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100559
Michal Vaskoa5da3292020-08-12 13:10:50 +0200560 /* parser next */
561 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
562
563 /* process children */
564 while (xmlctx->status == LYXML_ELEMENT) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100565 ret = lydxml_subtree_r(lydctx, node, lyd_node_child_p(node), NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200566 LY_CHECK_GOTO(ret, error);
567 }
568
569 if (snode->nodetype == LYS_LIST) {
570 /* check all keys exist */
571 LY_CHECK_GOTO(ret = lyd_parse_check_keys(node), error);
572 }
573
Michal Vaskoe0665742021-02-11 11:08:44 +0100574 if (!(lydctx->parse_opts & LYD_PARSE_ONLY)) {
Michal Vaskoa5da3292020-08-12 13:10:50 +0200575 /* new node validation, autodelete CANNOT occur, all nodes are new */
Michal Vaskoe0665742021-02-11 11:08:44 +0100576 ret = lyd_validate_new(lyd_node_child_p(node), snode, NULL, NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200577 LY_CHECK_GOTO(ret, error);
578
579 /* add any missing default children */
Michal Vaskoe0665742021-02-11 11:08:44 +0100580 ret = lyd_new_implicit_r(node, lyd_node_child_p(node), NULL, NULL, &lydctx->node_types, &lydctx->node_when,
581 (lydctx->val_opts & LYD_VALIDATE_NO_STATE) ? LYD_IMPLICIT_NO_STATE : 0, NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200582 LY_CHECK_GOTO(ret, error);
583 }
584
585 if (snode->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) {
586 /* rememeber the RPC/action/notification */
587 lydctx->op_node = node;
588 }
589 } else if (snode->nodetype & LYD_NODE_ANY) {
590 if (!xmlctx->ws_only) {
591 /* value in inner node */
Radek Krejci2efc45b2020-12-22 16:25:44 +0100592 LOGVAL(ctx, LYVE_SYNTAX, "Text value \"%.*s\" inside an any node \"%s\" found.",
Michal Vasko69730152020-10-09 16:30:07 +0200593 xmlctx->value_len, xmlctx->value, snode->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200594 ret = LY_EVALID;
595 goto error;
596 }
597
598 /* parser next */
599 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
600
601 /* parse any data tree with correct options */
Michal Vaskoe0665742021-02-11 11:08:44 +0100602 prev_opts = lydctx->parse_opts;
603 lydctx->parse_opts &= ~LYD_PARSE_STRICT;
604 lydctx->parse_opts |= LYD_PARSE_OPAQ;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200605 anchor = NULL;
606 while (xmlctx->status == LYXML_ELEMENT) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100607 ret = lydxml_subtree_r(lydctx, NULL, &anchor, NULL);
608 LY_CHECK_ERR_GOTO(ret, lydctx->parse_opts = prev_opts, error);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200609 }
Michal Vaskoe0665742021-02-11 11:08:44 +0100610 lydctx->parse_opts = prev_opts;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200611
612 /* create node */
Michal Vasko366a4a12020-12-04 16:23:57 +0100613 ret = lyd_create_any(snode, anchor, LYD_ANYDATA_DATATREE, 1, &node);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200614 LY_CHECK_GOTO(ret, error);
615 }
616 assert(node);
617
618 /* add/correct flags */
619 if (snode) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100620 lyd_parse_set_data_flags(node, &lydctx->node_when, &meta, lydctx->parse_opts);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200621 }
622
623 /* parser next */
624 assert(xmlctx->status == LYXML_ELEM_CLOSE);
625 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
626
627 /* add metadata/attributes */
628 if (snode) {
Michal Vasko871a0252020-11-11 18:35:24 +0100629 lyd_insert_meta(node, meta, 0);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200630 } else {
631 lyd_insert_attr(node, attr);
632 }
633
634 /* insert, keep first pointer correct */
Michal Vaskoe0665742021-02-11 11:08:44 +0100635 lyd_insert_node(parent, first_p, node);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200636 while (!parent && (*first_p)->prev->next) {
637 *first_p = (*first_p)->prev;
638 }
639
Michal Vaskoe0665742021-02-11 11:08:44 +0100640 /* rememeber a successfully parsed node */
641 if (parsed) {
642 ly_set_add(parsed, node, 1, NULL);
643 }
644
Radek Krejciddace2c2021-01-08 11:30:56 +0100645 LOG_LOCBACK(node ? 1 : 0, node ? 1 : 0, 0, 0);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200646 return LY_SUCCESS;
647
648error:
Radek Krejciddace2c2021-01-08 11:30:56 +0100649 LOG_LOCBACK(node ? 1 : 0, node ? 1 : 0, 0, 0);
Michal Vasko3a41dff2020-07-15 14:30:28 +0200650 lyd_free_meta_siblings(meta);
Radek Krejci011e4aa2020-09-04 15:22:31 +0200651 lyd_free_attr_siblings(ctx, attr);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200652 lyd_free_tree(node);
Radek Krejcie7b95092019-05-15 11:03:07 +0200653 return ret;
654}
655
Michal Vaskoe0665742021-02-11 11:08:44 +0100656/**
657 * @brief Parse a specific XML element into an opaque node.
658 *
659 * @param[in] xmlctx XML parser context.
660 * @param[in] name Name of the element.
661 * @param[in] uri URI of the element.
662 * @param[in] value Whether a value is expected in the element.
663 * @param[out] evnp Parsed envelope (opaque node).
664 * @return LY_SUCCESS on success.
665 * @return LY_ENOT if the specified element did not match.
666 * @return LY_ERR value on error.
667 */
Michal Vasko1bf09392020-03-27 12:38:10 +0100668static LY_ERR
Michal Vaskoe0665742021-02-11 11:08:44 +0100669lydxml_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 +0100670{
Michal Vaskoe0665742021-02-11 11:08:44 +0100671 LY_ERR rc = LY_SUCCESS;
672 const struct lyxml_ns *ns;
Radek Krejci1798aae2020-07-14 13:26:06 +0200673 struct lyd_attr *attr = NULL;
Michal Vasko1bf09392020-03-27 12:38:10 +0100674 const char *prefix;
675 size_t prefix_len;
676
Michal Vasko1bf09392020-03-27 12:38:10 +0100677 assert(xmlctx->status == LYXML_ELEMENT);
678 if (ly_strncmp(name, xmlctx->name, xmlctx->name_len)) {
679 /* not the expected element */
Michal Vaskoe0665742021-02-11 11:08:44 +0100680 return LY_ENOT;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100681 }
682
683 prefix = xmlctx->prefix;
684 prefix_len = xmlctx->prefix_len;
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200685 ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100686 if (!ns) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100687 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", prefix_len, prefix);
Michal Vaskoe0665742021-02-11 11:08:44 +0100688 return LY_EVALID;
689 } else if (strcmp(ns->uri, uri)) {
690 /* different namespace */
691 return LY_ENOT;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100692 }
693
694 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
695
696 /* create attributes */
697 if (xmlctx->status == LYXML_ATTRIBUTE) {
698 LY_CHECK_RET(lydxml_attrs(xmlctx, &attr));
699 }
700
Michal Vaskoe0665742021-02-11 11:08:44 +0100701 assert(xmlctx->status == LYXML_ELEM_CONTENT);
702 if (!value && !xmlctx->ws_only) {
703 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected value \"%.*s\" in the \"%s\" element.",
704 xmlctx->value_len, xmlctx->value, name);
705 rc = LY_EVALID;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100706 goto cleanup;
Michal Vaskoe0665742021-02-11 11:08:44 +0100707 }
Michal Vaskoa8edff02020-03-27 14:47:01 +0100708
709 /* create node */
Michal Vaskoe0665742021-02-11 11:08:44 +0100710 rc = lyd_create_opaq(xmlctx->ctx, name, strlen(name), prefix, prefix_len, uri, strlen(uri), xmlctx->value,
711 xmlctx->ws_only ? 0 : xmlctx->value_len, NULL, LY_PREF_XML, NULL, 0, envp);
712 LY_CHECK_GOTO(rc, cleanup);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100713
714 /* assign atributes */
Michal Vaskoe0665742021-02-11 11:08:44 +0100715 ((struct lyd_node_opaq *)(*envp))->attr = attr;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100716 attr = NULL;
717
Michal Vaskoe0665742021-02-11 11:08:44 +0100718 /* parser next element */
719 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100720
Michal Vaskoe0665742021-02-11 11:08:44 +0100721cleanup:
722 lyd_free_attr_siblings(xmlctx->ctx, attr);
723 if (rc) {
724 lyd_free_tree(*envp);
725 *envp = NULL;
726 }
727 return rc;
728}
729
730/**
731 * @brief Parse all expected non-data XML elements of a NETCONF rpc message.
732 *
733 * @param[in] xmlctx XML parser context.
734 * @param[out] evnp Parsed envelope(s) (opaque node).
735 * @param[out] int_opts Internal options for parsing the rest of YANG data.
736 * @param[out] close_elem Number of parsed opened elements that need to be closed.
737 * @return LY_SUCCESS on success.
738 * @return LY_ERR value on error.
739 */
740static LY_ERR
741lydxml_env_netconf_rpc(struct lyxml_ctx *xmlctx, struct lyd_node **envp, uint32_t *int_opts, uint32_t *close_elem)
742{
743 LY_ERR rc = LY_SUCCESS, r;
744 struct lyd_node *child;
745
746 assert(envp && !*envp);
747
748 /* parse "rpc" */
749 r = lydxml_envelope(xmlctx, "rpc", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, envp);
Michal Vaskoe0665742021-02-11 11:08:44 +0100750 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
751
752 /* parse "action", if any */
753 r = lydxml_envelope(xmlctx, "action", "urn:ietf:params:xml:ns:yang:1", 0, &child);
754 if (r == LY_SUCCESS) {
755 /* insert */
756 lyd_insert_node(*envp, NULL, child);
757
758 /* NETCONF action */
759 *int_opts = LYD_INTOPT_NO_SIBLINGS | LYD_INTOPT_ACTION;
760 *close_elem = 2;
761 } else if (r == LY_ENOT) {
762 /* NETCONF RPC */
763 *int_opts = LYD_INTOPT_NO_SIBLINGS | LYD_INTOPT_RPC;
764 *close_elem = 1;
765 } else {
766 rc = r;
767 goto cleanup;
768 }
769
770cleanup:
771 if (rc) {
772 lyd_free_tree(*envp);
773 *envp = NULL;
774 }
775 return rc;
776}
777
778/**
779 * @brief Parse all expected non-data XML elements of a NETCONF notification message.
780 *
781 * @param[in] xmlctx XML parser context.
782 * @param[out] evnp Parsed envelope(s) (opaque node).
783 * @param[out] int_opts Internal options for parsing the rest of YANG data.
784 * @param[out] close_elem Number of parsed opened elements that need to be closed.
785 * @return LY_SUCCESS on success.
786 * @return LY_ERR value on error.
787 */
788static LY_ERR
789lydxml_env_netconf_notif(struct lyxml_ctx *xmlctx, struct lyd_node **envp, uint32_t *int_opts, uint32_t *close_elem)
790{
791 LY_ERR rc = LY_SUCCESS, r;
792 struct lyd_node *child;
793
794 assert(envp && !*envp);
795
796 /* parse "notification" */
797 r = lydxml_envelope(xmlctx, "notification", "urn:ietf:params:xml:ns:netconf:notification:1.0", 0, envp);
Michal Vaskoe0665742021-02-11 11:08:44 +0100798 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
799
800 /* parse "eventTime" */
801 r = lydxml_envelope(xmlctx, "eventTime", "urn:ietf:params:xml:ns:netconf:notification:1.0", 1, &child);
802 if (r == LY_ENOT) {
803 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unexpected element \"%.*s\" instead of \"eventTime\".", xmlctx->name_len,
804 xmlctx->name);
805 r = LY_EVALID;
806 }
807 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
808
809 /* insert */
810 lyd_insert_node(*envp, NULL, child);
811
812 /* validate value */
813 /* TODO validate child->value as yang:date-and-time */
814
815 /* finish child parsing */
Michal Vaskoa8edff02020-03-27 14:47:01 +0100816 if (xmlctx->status != LYXML_ELEM_CLOSE) {
817 assert(xmlctx->status == LYXML_ELEMENT);
Michal Vaskoe0665742021-02-11 11:08:44 +0100818 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"eventTime\".",
Michal Vasko69730152020-10-09 16:30:07 +0200819 xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +0100820 rc = LY_EVALID;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100821 goto cleanup;
822 }
Michal Vaskoe0665742021-02-11 11:08:44 +0100823 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
824
825 /* NETCONF notification */
826 *int_opts = LYD_INTOPT_NO_SIBLINGS | LYD_INTOPT_NOTIF;
827 *close_elem = 1;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100828
829cleanup:
Michal Vaskoe0665742021-02-11 11:08:44 +0100830 if (rc) {
Michal Vaskoa8edff02020-03-27 14:47:01 +0100831 lyd_free_tree(*envp);
Michal Vaskoe0665742021-02-11 11:08:44 +0100832 *envp = NULL;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100833 }
Michal Vaskoe0665742021-02-11 11:08:44 +0100834 return rc;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100835}
Michal Vasko79135ae2020-12-16 10:08:35 +0100836
Michal Vaskoe0665742021-02-11 11:08:44 +0100837/**
838 * @brief Parse an XML element as an opaque node subtree.
839 *
840 * @param[in] xmlctx XML parser context.
841 * @param[in] parent Parent to append nodes to.
842 * @return LY_ERR value.
843 */
844static LY_ERR
845lydxml_opaq_r(struct lyxml_ctx *xmlctx, struct lyd_node *parent)
Michal Vaskoa8edff02020-03-27 14:47:01 +0100846{
Michal Vaskoe0665742021-02-11 11:08:44 +0100847 LY_ERR rc = LY_SUCCESS;
848 const struct lyxml_ns *ns;
849 struct lyd_attr *attr = NULL;
850 struct lyd_node *child = NULL;
851 const char *name, *prefix;
852 size_t name_len, prefix_len;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100853
Michal Vaskoe0665742021-02-11 11:08:44 +0100854 assert(xmlctx->status == LYXML_ELEMENT);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100855
Michal Vaskoe0665742021-02-11 11:08:44 +0100856 name = xmlctx->name;
857 name_len = xmlctx->name_len;
858 prefix = xmlctx->prefix;
859 prefix_len = xmlctx->prefix_len;
860 ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
861 if (!ns) {
862 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", prefix_len, prefix);
863 return LY_EVALID;
864 }
Michal Vaskoa8edff02020-03-27 14:47:01 +0100865
Michal Vaskoe0665742021-02-11 11:08:44 +0100866 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
Michal Vaskoa8edff02020-03-27 14:47:01 +0100867
Michal Vaskoe0665742021-02-11 11:08:44 +0100868 /* create attributes */
869 if (xmlctx->status == LYXML_ATTRIBUTE) {
870 LY_CHECK_RET(lydxml_attrs(xmlctx, &attr));
871 }
872
873 /* create node */
874 assert(xmlctx->status == LYXML_ELEM_CONTENT);
875 rc = lyd_create_opaq(xmlctx->ctx, name, name_len, prefix, prefix_len, ns->uri, strlen(ns->uri), xmlctx->value,
876 xmlctx->ws_only ? 0 : xmlctx->value_len, NULL, LY_PREF_XML, NULL, 0, &child);
877 LY_CHECK_GOTO(rc, cleanup);
878
879 /* assign atributes */
880 ((struct lyd_node_opaq *)child)->attr = attr;
881 attr = NULL;
882
883 /* parser next element */
884 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
885
886 /* parse all the descendants */
887 while (xmlctx->status == LYXML_ELEMENT) {
888 rc = lydxml_opaq_r(xmlctx, child);
889 LY_CHECK_GOTO(rc, cleanup);
890 }
891
892 /* insert */
893 lyd_insert_node(parent, NULL, child);
894
895cleanup:
896 lyd_free_attr_siblings(xmlctx->ctx, attr);
897 if (rc) {
898 lyd_free_tree(child);
899 }
900 return rc;
901}
902
903/**
904 * @brief Parse all expected non-data XML elements of the error-info element in NETCONF rpc-reply message.
905 *
906 * @param[in] xmlctx XML parser context.
907 * @param[in] parent Parent to append nodes to.
908 * @return LY_ERR value.
909 */
910static LY_ERR
911lydxml_env_netconf_rpc_reply_error_info(struct lyxml_ctx *xmlctx, struct lyd_node *parent)
912{
913 LY_ERR r;
914 struct lyd_node *child, *iter;
915 const struct lyxml_ns *ns;
916 ly_bool no_dup;
917
918 /* there must be some child */
919 if (xmlctx->status == LYXML_ELEM_CLOSE) {
920 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Missing child elements of \"error-info\".");
921 return LY_EVALID;
922 }
923
924 while (xmlctx->status == LYXML_ELEMENT) {
925 child = NULL;
926
927 /*
928 * session-id
929 */
930 r = lydxml_envelope(xmlctx, "session-id", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
931 if (r == LY_SUCCESS) {
932 no_dup = 1;
933 goto check_child;
934 } else if (r != LY_ENOT) {
935 goto error;
936 }
937
938 /*
939 * bad-attribute
940 */
941 r = lydxml_envelope(xmlctx, "bad-attribute", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
942 if (r == LY_SUCCESS) {
943 no_dup = 1;
944 goto check_child;
945 } else if (r != LY_ENOT) {
946 goto error;
947 }
948
949 /*
950 * bad-element
951 */
952 r = lydxml_envelope(xmlctx, "bad-element", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
953 if (r == LY_SUCCESS) {
954 no_dup = 1;
955 goto check_child;
956 } else if (r != LY_ENOT) {
957 goto error;
958 }
959
960 /*
961 * bad-namespace
962 */
963 r = lydxml_envelope(xmlctx, "bad-namespace", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
964 if (r == LY_SUCCESS) {
965 no_dup = 1;
966 goto check_child;
967 } else if (r != LY_ENOT) {
968 goto error;
969 }
970
971 if (r == LY_ENOT) {
972 assert(xmlctx->status == LYXML_ELEMENT);
973
974 /* learn namespace */
975 ns = lyxml_ns_get(&xmlctx->ns, xmlctx->prefix, xmlctx->prefix_len);
976 if (!ns) {
977 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", xmlctx->prefix_len, xmlctx->prefix);
978 r = LY_EVALID;
979 goto error;
980 } else if (!strcmp(ns->uri, "urn:ietf:params:xml:ns:netconf:base:1.0")) {
981 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"error-info\".",
Radek Krejci53875452021-02-16 13:44:51 +0100982 xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +0100983 r = LY_EVALID;
984 goto error;
985 }
986
987 /* custom elements */
988 r = lydxml_opaq_r(xmlctx, parent);
989 LY_CHECK_GOTO(r, error);
990
991 no_dup = 0;
992 }
993
994check_child:
995 /* check for duplicates */
996 if (no_dup) {
997 LY_LIST_FOR(lyd_child(parent), iter) {
998 if ((((struct lyd_node_opaq *)iter)->name.name == ((struct lyd_node_opaq *)child)->name.name) &&
999 (((struct lyd_node_opaq *)iter)->name.module_ns == ((struct lyd_node_opaq *)child)->name.module_ns)) {
1000 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Duplicate element \"%s\" in \"error-info\".",
1001 ((struct lyd_node_opaq *)child)->name.name);
1002 r = LY_EVALID;
1003 goto error;
1004 }
1005 }
1006 }
1007
1008 /* finish child parsing */
1009 if (xmlctx->status != LYXML_ELEM_CLOSE) {
1010 assert(xmlctx->status == LYXML_ELEMENT);
1011 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"error-info\".",
1012 xmlctx->name_len, xmlctx->name);
1013 r = LY_EVALID;
1014 goto error;
1015 }
1016 LY_CHECK_GOTO(r = lyxml_ctx_next(xmlctx), error);
1017
1018 /* insert */
1019 lyd_insert_node(parent, NULL, child);
1020 }
1021
1022 return LY_SUCCESS;
1023
1024error:
1025 lyd_free_tree(child);
1026 return r;
1027}
1028
1029/**
1030 * @brief Parse all expected non-data XML elements of the rpc-error element in NETCONF rpc-reply message.
1031 *
1032 * @param[in] xmlctx XML parser context.
1033 * @param[in] parent Parent to append nodes to.
1034 * @return LY_ERR value.
1035 */
1036static LY_ERR
1037lydxml_env_netconf_rpc_reply_error(struct lyxml_ctx *xmlctx, struct lyd_node *parent)
1038{
1039 LY_ERR r;
1040 struct lyd_node *child, *iter;
1041 const char *val;
1042 ly_bool no_dup;
1043
1044 /* there must be some child */
1045 if (xmlctx->status == LYXML_ELEM_CLOSE) {
1046 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Missing child elements of \"rpc-error\".");
1047 return LY_EVALID;
1048 }
1049
1050 while (xmlctx->status == LYXML_ELEMENT) {
1051 child = NULL;
1052
1053 /*
1054 * error-type
1055 */
1056 r = lydxml_envelope(xmlctx, "error-type", "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, "transport") && strcmp(val, "rpc") && strcmp(val, "protocol") && strcmp(val, "application")) {
1060 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Invalid value \"%s\" of element \"%s\".", val,
1061 ((struct lyd_node_opaq *)child)->name.name);
1062 r = LY_EVALID;
1063 goto error;
1064 }
1065
1066 no_dup = 1;
1067 goto check_child;
1068 } else if (r != LY_ENOT) {
1069 goto error;
1070 }
1071
1072 /*
1073 * error-tag
1074 */
1075 r = lydxml_envelope(xmlctx, "error-tag", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1076 if (r == LY_SUCCESS) {
1077 val = ((struct lyd_node_opaq *)child)->value;
1078 if (strcmp(val, "in-use") && strcmp(val, "invalid-value") && strcmp(val, "too-big") &&
1079 strcmp(val, "missing-attribute") && strcmp(val, "bad-attribute") &&
1080 strcmp(val, "unknown-attribute") && strcmp(val, "missing-element") && strcmp(val, "bad-element") &&
1081 strcmp(val, "unknown-element") && strcmp(val, "unknown-namespace") && strcmp(val, "access-denied") &&
1082 strcmp(val, "lock-denied") && strcmp(val, "resource-denied") && strcmp(val, "rollback-failed") &&
1083 strcmp(val, "data-exists") && strcmp(val, "data-missing") && strcmp(val, "operation-not-supported") &&
1084 strcmp(val, "operation-failed") && strcmp(val, "malformed-message")) {
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-severity
1099 */
1100 r = lydxml_envelope(xmlctx, "error-severity", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1101 if (r == LY_SUCCESS) {
1102 val = ((struct lyd_node_opaq *)child)->value;
1103 if (strcmp(val, "error") && strcmp(val, "warning")) {
1104 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Invalid value \"%s\" of element \"%s\".", val,
1105 ((struct lyd_node_opaq *)child)->name.name);
1106 r = LY_EVALID;
1107 goto error;
1108 }
1109
1110 no_dup = 1;
1111 goto check_child;
1112 } else if (r != LY_ENOT) {
1113 goto error;
1114 }
1115
1116 /*
1117 * error-app-tag
1118 */
1119 r = lydxml_envelope(xmlctx, "error-app-tag", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1120 if (r == LY_SUCCESS) {
1121 no_dup = 1;
1122 goto check_child;
1123 } else if (r != LY_ENOT) {
1124 goto error;
1125 }
1126
1127 /*
1128 * error-path
1129 */
1130 r = lydxml_envelope(xmlctx, "error-path", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1131 if (r == LY_SUCCESS) {
1132 no_dup = 1;
1133 goto check_child;
1134 } else if (r != LY_ENOT) {
1135 goto error;
1136 }
1137
1138 /*
1139 * error-message
1140 */
1141 r = lydxml_envelope(xmlctx, "error-message", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1142 if (r == LY_SUCCESS) {
1143 no_dup = 1;
1144 goto check_child;
1145 } else if (r != LY_ENOT) {
1146 goto error;
1147 }
1148
1149 /* error-info */
1150 r = lydxml_envelope(xmlctx, "error-info", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, &child);
1151 if (r == LY_SUCCESS) {
1152 /* parse all the descendants */
1153 LY_CHECK_GOTO(r = lydxml_env_netconf_rpc_reply_error_info(xmlctx, child), error);
1154
1155 no_dup = 0;
1156 goto check_child;
1157 } else if (r != LY_ENOT) {
1158 goto error;
1159 }
1160
1161 if (r == LY_ENOT) {
1162 assert(xmlctx->status == LYXML_ELEMENT);
1163 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"rpc-error\".",
1164 xmlctx->name_len, xmlctx->name);
1165 r = LY_EVALID;
1166 goto error;
1167 }
1168
1169check_child:
1170 /* check for duplicates */
1171 if (no_dup) {
1172 LY_LIST_FOR(lyd_child(parent), iter) {
1173 if ((((struct lyd_node_opaq *)iter)->name.name == ((struct lyd_node_opaq *)child)->name.name) &&
1174 (((struct lyd_node_opaq *)iter)->name.module_ns == ((struct lyd_node_opaq *)child)->name.module_ns)) {
1175 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Duplicate element \"%s\" in \"rpc-error\".",
1176 ((struct lyd_node_opaq *)child)->name.name);
1177 r = LY_EVALID;
1178 goto error;
1179 }
1180 }
1181 }
1182
1183 /* finish child parsing */
1184 if (xmlctx->status != LYXML_ELEM_CLOSE) {
1185 assert(xmlctx->status == LYXML_ELEMENT);
1186 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"rpc-error\".",
1187 xmlctx->name_len, xmlctx->name);
1188 r = LY_EVALID;
1189 goto error;
1190 }
1191 LY_CHECK_GOTO(r = lyxml_ctx_next(xmlctx), error);
1192
1193 /* insert */
1194 lyd_insert_node(parent, NULL, child);
1195 }
1196
1197 return LY_SUCCESS;
1198
1199error:
1200 lyd_free_tree(child);
1201 return r;
1202}
1203
1204/**
1205 * @brief Parse all expected non-data XML elements of a NETCONF rpc-reply message.
1206 *
1207 * @param[in] xmlctx XML parser context.
1208 * @param[out] evnp Parsed envelope(s) (opaque node).
1209 * @param[out] int_opts Internal options for parsing the rest of YANG data.
1210 * @param[out] close_elem Number of parsed opened elements that need to be closed.
1211 * @return LY_SUCCESS on success.
1212 * @return LY_ERR value on error.
1213 */
1214static LY_ERR
1215lydxml_env_netconf_reply(struct lyxml_ctx *xmlctx, struct lyd_node **envp, uint32_t *int_opts, uint32_t *close_elem)
1216{
1217 LY_ERR rc = LY_SUCCESS, r;
1218 struct lyd_node *child = NULL;
1219 const char *parsed_elem = NULL;
1220
1221 assert(envp && !*envp);
1222
1223 /* parse "rpc-reply" */
1224 r = lydxml_envelope(xmlctx, "rpc-reply", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, envp);
Michal Vaskoe0665742021-02-11 11:08:44 +01001225 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
1226
1227 /* there must be some child */
1228 if (xmlctx->status == LYXML_ELEM_CLOSE) {
1229 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Missing child elements of \"rpc-reply\".");
1230 rc = LY_EVALID;
Michal Vaskocf770e22020-08-12 13:21:43 +02001231 goto cleanup;
Michal Vaskoa8edff02020-03-27 14:47:01 +01001232 }
1233
Michal Vaskoe0665742021-02-11 11:08:44 +01001234 /* try to parse "ok" */
1235 r = lydxml_envelope(xmlctx, "ok", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, &child);
1236 if (r == LY_SUCCESS) {
1237 /* insert */
1238 lyd_insert_node(*envp, NULL, child);
1239
1240 /* finish child parsing */
1241 if (xmlctx->status != LYXML_ELEM_CLOSE) {
1242 assert(xmlctx->status == LYXML_ELEMENT);
1243 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"ok\".",
1244 xmlctx->name_len, xmlctx->name);
1245 rc = LY_EVALID;
1246 goto cleanup;
1247 }
1248 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
1249
1250 /* success */
1251 parsed_elem = "ok";
1252 goto finish;
1253 } else if (r != LY_ENOT) {
1254 rc = r;
1255 goto cleanup;
Michal Vasko2552ea32020-12-08 15:32:34 +01001256 }
1257
Michal Vaskoe0665742021-02-11 11:08:44 +01001258 /* try to parse all "rpc-error" elements */
1259 while (xmlctx->status == LYXML_ELEMENT) {
1260 r = lydxml_envelope(xmlctx, "rpc-error", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, &child);
1261 if (r == LY_ENOT) {
1262 break;
1263 } else if (r) {
1264 rc = r;
1265 goto cleanup;
1266 }
1267
1268 /* insert */
1269 lyd_insert_node(*envp, NULL, child);
1270
1271 /* parse all children of "rpc-error" */
1272 LY_CHECK_GOTO(rc = lydxml_env_netconf_rpc_reply_error(xmlctx, child), cleanup);
1273
1274 /* finish child parsing */
1275 assert(xmlctx->status == LYXML_ELEM_CLOSE);
1276 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
1277
1278 parsed_elem = "rpc-error";
Michal Vasko2552ea32020-12-08 15:32:34 +01001279 }
Michal Vaskoe0665742021-02-11 11:08:44 +01001280
1281finish:
1282 if (parsed_elem) {
1283 /* NETCONF rpc-reply with no data */
1284 if (xmlctx->status != LYXML_ELEM_CLOSE) {
1285 assert(xmlctx->status == LYXML_ELEMENT);
1286 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected sibling element \"%.*s\" of \"%s\".",
1287 xmlctx->name_len, xmlctx->name, parsed_elem);
1288 rc = LY_EVALID;
1289 goto cleanup;
1290 }
1291 }
1292
1293 /* NETCONF rpc-reply */
1294 *int_opts = LYD_INTOPT_NO_SIBLINGS | LYD_INTOPT_REPLY;
1295 *close_elem = 1;
1296
1297cleanup:
1298 if (rc) {
1299 lyd_free_tree(*envp);
1300 *envp = NULL;
1301 }
1302 return rc;
1303}
1304
Michal Vasko2552ea32020-12-08 15:32:34 +01001305LY_ERR
Radek Krejcif16e2542021-02-17 15:39:23 +01001306lyd_parse_xml(const struct ly_ctx *ctx, const struct lysc_ext_instance *ext, struct lyd_node *parent,
1307 struct lyd_node **first_p, struct ly_in *in, uint32_t parse_opts, uint32_t val_opts, enum lyd_type data_type,
1308 struct lyd_node **envp, struct ly_set *parsed, struct lyd_ctx **lydctx_p)
Michal Vasko2552ea32020-12-08 15:32:34 +01001309{
Michal Vaskoe0665742021-02-11 11:08:44 +01001310 LY_ERR rc = LY_SUCCESS;
1311 struct lyd_xml_ctx *lydctx;
1312 uint32_t i, int_opts, close_elem = 0;
1313 ly_bool parsed_data_nodes = 0;
Michal Vasko2552ea32020-12-08 15:32:34 +01001314
Michal Vaskoe0665742021-02-11 11:08:44 +01001315 assert(ctx && in && lydctx_p);
1316 assert(!(parse_opts & ~LYD_PARSE_OPTS_MASK));
1317 assert(!(val_opts & ~LYD_VALIDATE_OPTS_MASK));
Michal Vasko2552ea32020-12-08 15:32:34 +01001318
Michal Vaskoe0665742021-02-11 11:08:44 +01001319 /* init context */
1320 lydctx = calloc(1, sizeof *lydctx);
1321 LY_CHECK_ERR_RET(!lydctx, LOGMEM(ctx), LY_EMEM);
1322 LY_CHECK_GOTO(rc = lyxml_ctx_new(ctx, in, &lydctx->xmlctx), cleanup);
1323 lydctx->parse_opts = parse_opts;
1324 lydctx->val_opts = val_opts;
1325 lydctx->free = lyd_xml_ctx_free;
Radek Krejcif16e2542021-02-17 15:39:23 +01001326 lydctx->ext = ext;
Michal Vasko2552ea32020-12-08 15:32:34 +01001327
Michal Vaskoe0665742021-02-11 11:08:44 +01001328 switch (data_type) {
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001329 case LYD_TYPE_DATA_YANG:
Michal Vaskoe0665742021-02-11 11:08:44 +01001330 int_opts = LYD_INTOPT_WITH_SIBLINGS;
1331 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001332 case LYD_TYPE_RPC_YANG:
Michal Vaskoe0665742021-02-11 11:08:44 +01001333 int_opts = LYD_INTOPT_RPC | LYD_INTOPT_ACTION | LYD_INTOPT_NO_SIBLINGS;
1334 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001335 case LYD_TYPE_NOTIF_YANG:
Michal Vaskoe0665742021-02-11 11:08:44 +01001336 int_opts = LYD_INTOPT_NOTIF | LYD_INTOPT_NO_SIBLINGS;
1337 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001338 case LYD_TYPE_REPLY_YANG:
Michal Vaskoe0665742021-02-11 11:08:44 +01001339 int_opts = LYD_INTOPT_REPLY | LYD_INTOPT_NO_SIBLINGS;
1340 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001341 case LYD_TYPE_RPC_NETCONF:
Michal Vaskoe0665742021-02-11 11:08:44 +01001342 assert(!parent);
1343 LY_CHECK_GOTO(rc = lydxml_env_netconf_rpc(lydctx->xmlctx, envp, &int_opts, &close_elem), cleanup);
1344 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001345 case LYD_TYPE_NOTIF_NETCONF:
1346 assert(!parent);
1347 LY_CHECK_GOTO(rc = lydxml_env_netconf_notif(lydctx->xmlctx, envp, &int_opts, &close_elem), cleanup);
1348 break;
1349 case LYD_TYPE_REPLY_NETCONF:
Michal Vaskoe0665742021-02-11 11:08:44 +01001350 assert(parent);
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001351 LY_CHECK_GOTO(rc = lydxml_env_netconf_reply(lydctx->xmlctx, envp, &int_opts, &close_elem), cleanup);
Michal Vaskoe0665742021-02-11 11:08:44 +01001352 break;
1353 }
1354 lydctx->int_opts = int_opts;
1355
1356 /* find the operation node if it exists already */
1357 LY_CHECK_GOTO(rc = lyd_parser_find_operation(parent, int_opts, &lydctx->op_node), cleanup);
1358
1359 /* parse XML data */
1360 while (lydctx->xmlctx->status == LYXML_ELEMENT) {
1361 LY_CHECK_GOTO(rc = lydxml_subtree_r(lydctx, parent, first_p, parsed), cleanup);
1362 parsed_data_nodes = 1;
1363
1364 if (!(int_opts & LYD_INTOPT_WITH_SIBLINGS)) {
1365 break;
1366 }
Michal Vasko2552ea32020-12-08 15:32:34 +01001367 }
1368
Michal Vaskoe0665742021-02-11 11:08:44 +01001369 /* close all opened elements */
1370 for (i = 0; i < close_elem; ++i) {
1371 if (lydctx->xmlctx->status != LYXML_ELEM_CLOSE) {
1372 assert(lydctx->xmlctx->status == LYXML_ELEMENT);
1373 LOGVAL(lydctx->xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\".", lydctx->xmlctx->name_len,
1374 lydctx->xmlctx->name);
1375 rc = LY_EVALID;
1376 goto cleanup;
1377 }
1378
1379 LY_CHECK_GOTO(rc = lyxml_ctx_next(lydctx->xmlctx), cleanup);
Michal Vasko4189c0f2020-08-13 09:05:22 +02001380 }
Michal Vaskoe0665742021-02-11 11:08:44 +01001381
1382 /* check final state */
1383 if ((int_opts & LYD_INTOPT_NO_SIBLINGS) && (lydctx->xmlctx->status == LYXML_ELEMENT)) {
1384 LOGVAL(ctx, LYVE_SYNTAX, "Unexpected sibling node.");
1385 rc = LY_EVALID;
1386 goto cleanup;
1387 }
1388 if ((int_opts & (LYD_INTOPT_RPC | LYD_INTOPT_NOTIF | LYD_INTOPT_REPLY)) && !lydctx->op_node) {
1389 LOGVAL(ctx, LYVE_DATA, "Missing the operation node.");
1390 rc = LY_EVALID;
1391 goto cleanup;
1392 }
1393
1394 if (!parsed_data_nodes) {
1395 /* no data nodes were parsed */
1396 lydctx->op_node = NULL;
Michal Vaskoa8edff02020-03-27 14:47:01 +01001397 }
1398
1399cleanup:
Michal Vaskoe0665742021-02-11 11:08:44 +01001400 /* there should be no unres stored if validation should be skipped */
1401 assert(!(parse_opts & LYD_PARSE_ONLY) || (!lydctx->node_types.count && !lydctx->meta_types.count &&
1402 !lydctx->node_when.count));
1403
1404 if (rc) {
1405 lyd_xml_ctx_free((struct lyd_ctx *)lydctx);
1406 } else {
1407 *lydctx_p = (struct lyd_ctx *)lydctx;
1408
1409 /* the XML context is no more needed, freeing it also stops logging line numbers which would be confusing now */
1410 lyxml_ctx_free(lydctx->xmlctx);
1411 lydctx->xmlctx = NULL;
Michal Vasko1ce933a2020-03-30 12:38:22 +02001412 }
Michal Vaskoe0665742021-02-11 11:08:44 +01001413 return rc;
Michal Vasko1ce933a2020-03-30 12:38:22 +02001414}