blob: 33235a046e68cd51427c3389508e32be50963b32 [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 Vaskoc43c8ab2021-03-05 13:32:44 +010046 struct ly_set node_when; /**< set of nodes with "when" conditions */
Michal Vasko49c39d82020-11-06 17:20:27 +010047 struct ly_set node_types; /**< set of nodes validated with LY_EINCOMPLETE result */
48 struct ly_set meta_types; /**< set of metadata validated with LY_EINCOMPLETE result */
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\".",
Radek Krejci422afb12021-03-04 16:38:16 +010085 (int)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 Krejci422afb12021-03-04 16:38:16 +0100100 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)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\".",
Radek Krejci422afb12021-03-04 16:38:16 +0100109 ns->uri, (int)xmlctx->prefix_len, xmlctx->prefix, xmlctx->prefix_len ? ":" : "",
110 (int)xmlctx->name_len, 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 Krejci422afb12021-03-04 16:38:16 +0100161 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)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 Vasko12d809c2021-03-03 16:34:32 +0100225 /* remember parent count */
226 parents_count = xmlctx->elements.count;
227
Michal Vaskob36053d2020-03-26 15:49:30 +0100228 while (xmlctx->status == LYXML_ELEMENT) {
Michal Vasko44685da2020-03-17 15:38:06 +0100229 /* find key definition */
230 for (i = 0; i < key_set.count; ++i) {
231 snode = (const struct lysc_node *)key_set.objs[i];
Michal Vaskob36053d2020-03-26 15:49:30 +0100232 if (!ly_strncmp(snode->name, xmlctx->name, xmlctx->name_len)) {
Michal Vasko44685da2020-03-17 15:38:06 +0100233 break;
234 }
235 }
Michal Vaskob36053d2020-03-26 15:49:30 +0100236 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100237
238 /* skip attributes */
239 while (xmlctx->status == LYXML_ATTRIBUTE) {
Michal Vaskob36053d2020-03-26 15:49:30 +0100240 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
241 assert(xmlctx->status == LYXML_ATTR_CONTENT);
242 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100243 }
244
Michal Vaskob36053d2020-03-26 15:49:30 +0100245 assert(xmlctx->status == LYXML_ELEM_CONTENT);
246 if (i < key_set.count) {
247 /* validate the value */
Michal Vasko713148b2020-11-12 13:10:13 +0100248 r = _lys_value_validate(NULL, snode, xmlctx->value, xmlctx->value_len, LY_PREF_XML, &xmlctx->ns);
Michal Vaskob36053d2020-03-26 15:49:30 +0100249 if (!r) {
250 /* key with a valid value, remove from the set */
251 ly_set_rm_index(&key_set, i, NULL);
Michal Vasko44685da2020-03-17 15:38:06 +0100252 }
253 }
254
Michal Vaskob36053d2020-03-26 15:49:30 +0100255 /* parser next */
256 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100257
Michal Vaskob36053d2020-03-26 15:49:30 +0100258 /* skip any children, resursively */
Michal Vasko12d809c2021-03-03 16:34:32 +0100259 while (xmlctx->status == LYXML_ELEMENT) {
260 while (parents_count < xmlctx->elements.count) {
261 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
262 }
263 assert(xmlctx->status == LYXML_ELEM_CLOSE);
Michal Vaskob36053d2020-03-26 15:49:30 +0100264 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
265 }
266
267 /* parser next, but do not parse closing element of the list because it would remove its namespaces */
268 assert(xmlctx->status == LYXML_ELEM_CLOSE);
269 LY_CHECK_GOTO(ret = lyxml_ctx_peek(xmlctx, &next), cleanup);
270 if (next != LYXML_ELEM_CLOSE) {
271 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
272 }
Michal Vasko44685da2020-03-17 15:38:06 +0100273 }
274
275 if (key_set.count) {
Michal Vaskob36053d2020-03-26 15:49:30 +0100276 /* some keys are missing/did not validate */
Michal Vasko44685da2020-03-17 15:38:06 +0100277 ret = LY_ENOT;
Michal Vasko44685da2020-03-17 15:38:06 +0100278 }
279
280cleanup:
281 ly_set_erase(&key_set, NULL);
282 return ret;
283}
284
Michal Vasko1bf09392020-03-27 12:38:10 +0100285static LY_ERR
286lydxml_data_skip(struct lyxml_ctx *xmlctx)
287{
288 uint32_t parents_count;
289
290 /* remember current number of parents */
291 parents_count = xmlctx->elements.count;
292
293 /* skip after the content */
294 while (xmlctx->status != LYXML_ELEM_CONTENT) {
295 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
296 }
297 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
298
299 /* skip all children elements, recursively, if any */
300 while (parents_count < xmlctx->elements.count) {
301 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
302 }
303
304 /* close element */
305 assert(xmlctx->status == LYXML_ELEM_CLOSE);
306 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
307
308 return LY_SUCCESS;
309}
310
311static LY_ERR
Radek Krejci1798aae2020-07-14 13:26:06 +0200312lydxml_data_check_opaq(struct lyd_xml_ctx *lydctx, const struct lysc_node **snode)
Michal Vasko1bf09392020-03-27 12:38:10 +0100313{
314 LY_ERR ret = LY_SUCCESS;
315 enum LYXML_PARSER_STATUS prev_status;
Michal Vasko63f3d842020-07-08 10:10:14 +0200316 const char *prev_current, *pname, *pprefix;
Michal Vasko1bf09392020-03-27 12:38:10 +0100317 size_t pprefix_len, pname_len;
318 struct lyxml_ctx *xmlctx = lydctx->xmlctx;
319
Michal Vaskoe0665742021-02-11 11:08:44 +0100320 if ((lydctx->parse_opts & LYD_PARSE_OPAQ) && ((*snode)->nodetype & (LYD_NODE_TERM | LYS_LIST))) {
Michal Vasko1bf09392020-03-27 12:38:10 +0100321 /* backup parser */
322 prev_status = xmlctx->status;
323 pprefix = xmlctx->prefix;
324 pprefix_len = xmlctx->prefix_len;
325 pname = xmlctx->name;
326 pname_len = xmlctx->name_len;
Michal Vasko63f3d842020-07-08 10:10:14 +0200327 prev_current = xmlctx->in->current;
Michal Vasko1bf09392020-03-27 12:38:10 +0100328 if ((xmlctx->status == LYXML_ELEM_CONTENT) && xmlctx->dynamic) {
329 /* it was backed up, do not free */
330 xmlctx->dynamic = 0;
331 }
332
333 /* skip attributes */
334 while (xmlctx->status == LYXML_ATTRIBUTE) {
335 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), restore);
336 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), restore);
337 }
338
339 if ((*snode)->nodetype & LYD_NODE_TERM) {
340 /* value may not be valid in which case we parse it as an opaque node */
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200341 if (_lys_value_validate(NULL, *snode, xmlctx->value, xmlctx->value_len, LY_PREF_XML, &xmlctx->ns)) {
Michal Vasko1bf09392020-03-27 12:38:10 +0100342 *snode = NULL;
343 }
344 } else {
345 /* skip content */
346 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), restore);
347
348 if (lydxml_check_list(xmlctx, *snode)) {
349 /* invalid list, parse as opaque if it missing/has invalid some keys */
350 *snode = NULL;
351 }
352 }
353
354restore:
355 /* restore parser */
356 if (xmlctx->dynamic) {
357 free((char *)xmlctx->value);
358 }
359 xmlctx->status = prev_status;
360 xmlctx->prefix = pprefix;
361 xmlctx->prefix_len = pprefix_len;
362 xmlctx->name = pname;
363 xmlctx->name_len = pname_len;
Michal Vasko63f3d842020-07-08 10:10:14 +0200364 xmlctx->in->current = prev_current;
Michal Vasko1bf09392020-03-27 12:38:10 +0100365 }
366
367 return ret;
368}
369
Radek Krejcie7b95092019-05-15 11:03:07 +0200370/**
Michal Vaskoa5da3292020-08-12 13:10:50 +0200371 * @brief Parse XML subtree.
Radek Krejcie7b95092019-05-15 11:03:07 +0200372 *
Michal Vaskob36053d2020-03-26 15:49:30 +0100373 * @param[in] lydctx XML YANG data parser context.
Michal Vaskoe0665742021-02-11 11:08:44 +0100374 * @param[in,out] parent Parent node where the children are inserted. NULL in case of parsing top-level elements.
375 * @param[in,out] first_p Pointer to the first (@p parent or top-level) child. In case there were already some siblings,
376 * this may point to a previously existing node.
377 * @param[in,out] parsed Optional set to add all the parsed siblings into.
Michal Vasko9b368d32020-02-14 13:53:31 +0100378 * @return LY_ERR value.
Radek Krejcie7b95092019-05-15 11:03:07 +0200379 */
380static LY_ERR
Michal Vaskoe0665742021-02-11 11:08:44 +0100381lydxml_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 +0200382{
Michal Vaskob36053d2020-03-26 15:49:30 +0100383 LY_ERR ret = LY_SUCCESS;
Michal Vasko27c4dce2021-03-04 15:50:50 +0100384 const char *prefix, *name, *val;
Michal Vasko1bf09392020-03-27 12:38:10 +0100385 size_t prefix_len, name_len;
Michal Vaskob36053d2020-03-26 15:49:30 +0100386 struct lyxml_ctx *xmlctx;
387 const struct ly_ctx *ctx;
Radek Krejcie7b95092019-05-15 11:03:07 +0200388 const struct lyxml_ns *ns;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200389 struct lyd_meta *meta = NULL;
390 struct lyd_attr *attr = NULL;
Radek Krejcie7b95092019-05-15 11:03:07 +0200391 const struct lysc_node *snode;
392 struct lys_module *mod;
Michal Vasko1bf09392020-03-27 12:38:10 +0100393 uint32_t prev_opts;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200394 struct lyd_node *node = NULL, *anchor;
Michal Vaskofc2cd072021-02-24 13:17:17 +0100395 void *val_prefix_data = NULL;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100396 LY_PREFIX_FORMAT format;
Radek Krejci1deb5be2020-08-26 16:43:36 +0200397 uint32_t getnext_opts;
Radek Krejcie7b95092019-05-15 11:03:07 +0200398
Michal Vaskoe0665742021-02-11 11:08:44 +0100399 assert(parent || first_p);
400
Michal Vaskob36053d2020-03-26 15:49:30 +0100401 xmlctx = lydctx->xmlctx;
402 ctx = xmlctx->ctx;
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100403 getnext_opts = lydctx->int_opts & LYD_INTOPT_REPLY ? LYS_GETNEXT_OUTPUT : 0;
Michal Vasko6f4cbb62020-02-28 11:15:47 +0100404
Michal Vaskoa5da3292020-08-12 13:10:50 +0200405 assert(xmlctx->status == LYXML_ELEMENT);
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200406
Michal Vaskoa5da3292020-08-12 13:10:50 +0200407 /* remember element prefix and name */
408 prefix = xmlctx->prefix;
409 prefix_len = xmlctx->prefix_len;
410 name = xmlctx->name;
411 name_len = xmlctx->name_len;
412
413 /* get the element module */
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200414 ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200415 if (!ns) {
Radek Krejci422afb12021-03-04 16:38:16 +0100416 LOGVAL(ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)prefix_len, prefix);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200417 ret = LY_EVALID;
418 goto error;
419 }
420 mod = ly_ctx_get_module_implemented_ns(ctx, ns->uri);
421 if (!mod) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100422 if (lydctx->parse_opts & LYD_PARSE_STRICT) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100423 LOGVAL(ctx, LYVE_REFERENCE, "No module with namespace \"%s\" in the context.", ns->uri);
Michal Vasko90932a92020-02-12 14:33:03 +0100424 ret = LY_EVALID;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200425 goto error;
Radek Krejcie7b95092019-05-15 11:03:07 +0200426 }
Michal Vaskoe0665742021-02-11 11:08:44 +0100427 if (!(lydctx->parse_opts & LYD_PARSE_OPAQ)) {
Michal Vaskoa5da3292020-08-12 13:10:50 +0200428 /* skip element with children */
429 LY_CHECK_GOTO(ret = lydxml_data_skip(xmlctx), error);
430 return LY_SUCCESS;
Radek Krejcie7b95092019-05-15 11:03:07 +0200431 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200432 }
433
Michal Vaskoa5da3292020-08-12 13:10:50 +0200434 /* parser next */
435 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
Michal Vasko90932a92020-02-12 14:33:03 +0100436
Michal Vaskoa5da3292020-08-12 13:10:50 +0200437 /* get the schema node */
438 snode = NULL;
439 if (mod && (!parent || parent->schema)) {
Radek Krejcif16e2542021-02-17 15:39:23 +0100440 if (!parent && lydctx->ext) {
441 snode = lys_find_ext_instance_node(lydctx->ext, mod, name, name_len, 0, getnext_opts);
442 } else {
443 snode = lys_find_child(parent ? parent->schema : NULL, mod, name, name_len, 0, getnext_opts);
444 }
Michal Vaskoa5da3292020-08-12 13:10:50 +0200445 if (!snode) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100446 if (lydctx->parse_opts & LYD_PARSE_STRICT) {
447 if (parent) {
Radek Krejci422afb12021-03-04 16:38:16 +0100448 LOGVAL(ctx, LYVE_REFERENCE, "Node \"%.*s\" not found as a child of \"%s\" node.",
449 (int)name_len, name, parent->schema->name);
Radek Krejcif16e2542021-02-17 15:39:23 +0100450 } else if (lydctx->ext) {
451 if (lydctx->ext->argument) {
Radek Krejci422afb12021-03-04 16:38:16 +0100452 LOGVAL(ctx, LYVE_REFERENCE, "Node \"%.*s\" not found in the \"%s\" %s extension instance.",
453 (int)name_len, name, lydctx->ext->argument, lydctx->ext->def->name);
Radek Krejcif16e2542021-02-17 15:39:23 +0100454 } else {
Radek Krejci422afb12021-03-04 16:38:16 +0100455 LOGVAL(ctx, LYVE_REFERENCE, "Node \"%.*s\" not found in the %s extension instance.",
456 (int)name_len, name, lydctx->ext->def->name);
Radek Krejcif16e2542021-02-17 15:39:23 +0100457 }
Michal Vaskoe0665742021-02-11 11:08:44 +0100458 } else {
Radek Krejci422afb12021-03-04 16:38:16 +0100459 LOGVAL(ctx, LYVE_REFERENCE, "Node \"%.*s\" not found in the \"%s\" module.",
460 (int)name_len, name, mod->name);
Michal Vaskoe0665742021-02-11 11:08:44 +0100461 }
Michal Vaskoa5da3292020-08-12 13:10:50 +0200462 ret = LY_EVALID;
463 goto error;
Michal Vaskoe0665742021-02-11 11:08:44 +0100464 } else if (!(lydctx->parse_opts & LYD_PARSE_OPAQ)) {
Michal Vaskoa5da3292020-08-12 13:10:50 +0200465 /* skip element with children */
466 LY_CHECK_GOTO(ret = lydxml_data_skip(xmlctx), error);
467 return LY_SUCCESS;
468 }
469 } else {
470 /* check that schema node is valid and can be used */
471 LY_CHECK_GOTO(ret = lyd_parser_check_schema((struct lyd_ctx *)lydctx, snode), error);
472 LY_CHECK_GOTO(ret = lydxml_data_check_opaq(lydctx, &snode), error);
473 }
474 }
475
476 /* create metadata/attributes */
477 if (xmlctx->status == LYXML_ATTRIBUTE) {
478 if (snode) {
Michal Vaskofeca4fb2020-10-05 08:58:40 +0200479 ret = lydxml_metadata(lydctx, &meta);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200480 LY_CHECK_GOTO(ret, error);
481 } else {
Michal Vaskoe0665742021-02-11 11:08:44 +0100482 assert(lydctx->parse_opts & LYD_PARSE_OPAQ);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200483 ret = lydxml_attrs(xmlctx, &attr);
484 LY_CHECK_GOTO(ret, error);
485 }
486 }
487
488 assert(xmlctx->status == LYXML_ELEM_CONTENT);
489 if (!snode) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100490 assert(lydctx->parse_opts & LYD_PARSE_OPAQ);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200491
492 if (xmlctx->ws_only) {
493 /* ignore WS-only value */
Radek IÅ¡a017270d2021-02-16 10:26:15 +0100494 if (xmlctx->dynamic) {
495 free((char *) xmlctx->value);
496 }
497 xmlctx->dynamic = 0;
498 xmlctx->value = "";
Michal Vaskoa5da3292020-08-12 13:10:50 +0200499 xmlctx->value_len = 0;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100500 format = LY_PREF_XML;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200501 } else {
502 /* get value prefixes */
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100503 ret = ly_store_prefix_data(xmlctx->ctx, xmlctx->value, xmlctx->value_len, LY_PREF_XML,
504 &xmlctx->ns, &format, &val_prefix_data);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200505 LY_CHECK_GOTO(ret, error);
506 }
507
508 /* create node */
Michal Vasko501af032020-11-11 20:27:44 +0100509 ret = lyd_create_opaq(ctx, name, name_len, prefix, prefix_len, ns->uri, strlen(ns->uri), xmlctx->value,
510 xmlctx->value_len, &xmlctx->dynamic, format, val_prefix_data, LYD_HINT_DATA, &node);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200511 LY_CHECK_GOTO(ret, error);
512
513 /* parser next */
514 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
515
516 /* process children */
517 while (xmlctx->status == LYXML_ELEMENT) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100518 ret = lydxml_subtree_r(lydctx, node, lyd_node_child_p(node), NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200519 LY_CHECK_GOTO(ret, error);
520 }
521 } else if (snode->nodetype & LYD_NODE_TERM) {
522 /* create node */
Michal Vasko22df3f02020-08-24 13:29:22 +0200523 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 +0200524 &xmlctx->dynamic, LY_PREF_XML, &xmlctx->ns, LYD_HINT_DATA, &node), error);
Radek Krejciddace2c2021-01-08 11:30:56 +0100525 LOG_LOCSET(snode, node, NULL, NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200526
527 if (parent && (node->schema->flags & LYS_KEY)) {
528 /* check the key order, the anchor must never be a key */
Michal Vaskoe0665742021-02-11 11:08:44 +0100529 anchor = lyd_insert_get_next_anchor(lyd_child(parent), node);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200530 if (anchor && (anchor->schema->flags & LYS_KEY)) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100531 if (lydctx->parse_opts & LYD_PARSE_STRICT) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100532 LOGVAL(ctx, LYVE_DATA, "Invalid position of the key \"%s\" in a list.", node->schema->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200533 ret = LY_EVALID;
534 goto error;
535 } else {
536 LOGWRN(ctx, "Invalid position of the key \"%s\" in a list.", node->schema->name);
537 }
538 }
539 }
540
541 /* parser next */
542 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
543
544 /* no children expected */
545 if (xmlctx->status == LYXML_ELEMENT) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100546 LOGVAL(ctx, LYVE_SYNTAX, "Child element \"%.*s\" inside a terminal node \"%s\" found.",
Radek Krejci422afb12021-03-04 16:38:16 +0100547 (int)xmlctx->name_len, xmlctx->name, snode->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200548 ret = LY_EVALID;
549 goto error;
550 }
551 } else if (snode->nodetype & LYD_NODE_INNER) {
552 if (!xmlctx->ws_only) {
553 /* value in inner node */
Radek Krejci2efc45b2020-12-22 16:25:44 +0100554 LOGVAL(ctx, LYVE_SYNTAX, "Text value \"%.*s\" inside an inner node \"%s\" found.",
Radek Krejci422afb12021-03-04 16:38:16 +0100555 (int)xmlctx->value_len, xmlctx->value, snode->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200556 ret = LY_EVALID;
557 goto error;
558 }
559
560 /* create node */
561 ret = lyd_create_inner(snode, &node);
562 LY_CHECK_GOTO(ret, error);
563
Radek Krejciddace2c2021-01-08 11:30:56 +0100564 LOG_LOCSET(snode, node, NULL, NULL);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100565
Michal Vaskoa5da3292020-08-12 13:10:50 +0200566 /* parser next */
567 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
568
569 /* process children */
570 while (xmlctx->status == LYXML_ELEMENT) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100571 ret = lydxml_subtree_r(lydctx, node, lyd_node_child_p(node), NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200572 LY_CHECK_GOTO(ret, error);
573 }
574
575 if (snode->nodetype == LYS_LIST) {
576 /* check all keys exist */
577 LY_CHECK_GOTO(ret = lyd_parse_check_keys(node), error);
578 }
579
Michal Vaskoe0665742021-02-11 11:08:44 +0100580 if (!(lydctx->parse_opts & LYD_PARSE_ONLY)) {
Michal Vaskoa5da3292020-08-12 13:10:50 +0200581 /* new node validation, autodelete CANNOT occur, all nodes are new */
Michal Vaskoe0665742021-02-11 11:08:44 +0100582 ret = lyd_validate_new(lyd_node_child_p(node), snode, NULL, NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200583 LY_CHECK_GOTO(ret, error);
584
585 /* add any missing default children */
Michal Vaskoc43c8ab2021-03-05 13:32:44 +0100586 ret = lyd_new_implicit_r(node, lyd_node_child_p(node), NULL, NULL, &lydctx->node_when, &lydctx->node_types,
Michal Vaskoe0665742021-02-11 11:08:44 +0100587 (lydctx->val_opts & LYD_VALIDATE_NO_STATE) ? LYD_IMPLICIT_NO_STATE : 0, NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200588 LY_CHECK_GOTO(ret, error);
589 }
590
591 if (snode->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) {
592 /* rememeber the RPC/action/notification */
593 lydctx->op_node = node;
594 }
595 } else if (snode->nodetype & LYD_NODE_ANY) {
Michal Vasko27c4dce2021-03-04 15:50:50 +0100596 if ((snode->nodetype == LYS_ANYDATA) && !xmlctx->ws_only) {
597 /* value in anydata node, we expect a tree */
598 LOGVAL(ctx, LYVE_SYNTAX, "Text value \"%.*s\" inside an anydata node \"%s\" found.",
Radek Krejci422afb12021-03-04 16:38:16 +0100599 (int)xmlctx->value_len < 20 ? xmlctx->value_len : 20, xmlctx->value, snode->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200600 ret = LY_EVALID;
601 goto error;
602 }
603
Michal Vasko27c4dce2021-03-04 15:50:50 +0100604 if (!xmlctx->ws_only) {
605 /* use an arbitrary text value for anyxml */
606 lydict_insert(xmlctx->ctx, xmlctx->value, xmlctx->value_len, &val);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200607
Michal Vasko27c4dce2021-03-04 15:50:50 +0100608 /* parser next */
609 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
610
611 /* create node */
612 ret = lyd_create_any(snode, val, LYD_ANYDATA_STRING, 1, &node);
613 LY_CHECK_GOTO(ret, error);
614 } else {
615 /* parser next */
616 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
617
618 /* parse any data tree with correct options */
619 prev_opts = lydctx->parse_opts;
620 lydctx->parse_opts &= ~LYD_PARSE_STRICT;
621 lydctx->parse_opts |= LYD_PARSE_OPAQ;
622 anchor = NULL;
623 while (xmlctx->status == LYXML_ELEMENT) {
624 ret = lydxml_subtree_r(lydctx, NULL, &anchor, NULL);
625 LY_CHECK_ERR_GOTO(ret, lydctx->parse_opts = prev_opts, error);
626 }
627 lydctx->parse_opts = prev_opts;
628
629 /* create node */
630 ret = lyd_create_any(snode, anchor, LYD_ANYDATA_DATATREE, 1, &node);
631 LY_CHECK_GOTO(ret, error);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200632 }
Michal Vaskoa5da3292020-08-12 13:10:50 +0200633 }
634 assert(node);
635
636 /* add/correct flags */
637 if (snode) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100638 lyd_parse_set_data_flags(node, &lydctx->node_when, &meta, lydctx->parse_opts);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200639 }
640
641 /* parser next */
642 assert(xmlctx->status == LYXML_ELEM_CLOSE);
643 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
644
645 /* add metadata/attributes */
646 if (snode) {
Michal Vasko871a0252020-11-11 18:35:24 +0100647 lyd_insert_meta(node, meta, 0);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200648 } else {
649 lyd_insert_attr(node, attr);
650 }
651
652 /* insert, keep first pointer correct */
Michal Vaskoe0665742021-02-11 11:08:44 +0100653 lyd_insert_node(parent, first_p, node);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200654 while (!parent && (*first_p)->prev->next) {
655 *first_p = (*first_p)->prev;
656 }
657
Michal Vaskoe0665742021-02-11 11:08:44 +0100658 /* rememeber a successfully parsed node */
659 if (parsed) {
660 ly_set_add(parsed, node, 1, NULL);
661 }
662
Radek Krejciddace2c2021-01-08 11:30:56 +0100663 LOG_LOCBACK(node ? 1 : 0, node ? 1 : 0, 0, 0);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200664 return LY_SUCCESS;
665
666error:
Radek Krejciddace2c2021-01-08 11:30:56 +0100667 LOG_LOCBACK(node ? 1 : 0, node ? 1 : 0, 0, 0);
Michal Vasko3a41dff2020-07-15 14:30:28 +0200668 lyd_free_meta_siblings(meta);
Radek Krejci011e4aa2020-09-04 15:22:31 +0200669 lyd_free_attr_siblings(ctx, attr);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200670 lyd_free_tree(node);
Radek Krejcie7b95092019-05-15 11:03:07 +0200671 return ret;
672}
673
Michal Vaskoe0665742021-02-11 11:08:44 +0100674/**
675 * @brief Parse a specific XML element into an opaque node.
676 *
677 * @param[in] xmlctx XML parser context.
678 * @param[in] name Name of the element.
679 * @param[in] uri URI of the element.
680 * @param[in] value Whether a value is expected in the element.
681 * @param[out] evnp Parsed envelope (opaque node).
682 * @return LY_SUCCESS on success.
683 * @return LY_ENOT if the specified element did not match.
684 * @return LY_ERR value on error.
685 */
Michal Vasko1bf09392020-03-27 12:38:10 +0100686static LY_ERR
Michal Vaskoe0665742021-02-11 11:08:44 +0100687lydxml_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 +0100688{
Michal Vaskoe0665742021-02-11 11:08:44 +0100689 LY_ERR rc = LY_SUCCESS;
690 const struct lyxml_ns *ns;
Radek Krejci1798aae2020-07-14 13:26:06 +0200691 struct lyd_attr *attr = NULL;
Michal Vasko1bf09392020-03-27 12:38:10 +0100692 const char *prefix;
693 size_t prefix_len;
694
Michal Vasko1bf09392020-03-27 12:38:10 +0100695 assert(xmlctx->status == LYXML_ELEMENT);
696 if (ly_strncmp(name, xmlctx->name, xmlctx->name_len)) {
697 /* not the expected element */
Michal Vaskoe0665742021-02-11 11:08:44 +0100698 return LY_ENOT;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100699 }
700
701 prefix = xmlctx->prefix;
702 prefix_len = xmlctx->prefix_len;
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200703 ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100704 if (!ns) {
Radek Krejci422afb12021-03-04 16:38:16 +0100705 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)prefix_len, prefix);
Michal Vaskoe0665742021-02-11 11:08:44 +0100706 return LY_EVALID;
707 } else if (strcmp(ns->uri, uri)) {
708 /* different namespace */
709 return LY_ENOT;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100710 }
711
712 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
713
714 /* create attributes */
715 if (xmlctx->status == LYXML_ATTRIBUTE) {
716 LY_CHECK_RET(lydxml_attrs(xmlctx, &attr));
717 }
718
Michal Vaskoe0665742021-02-11 11:08:44 +0100719 assert(xmlctx->status == LYXML_ELEM_CONTENT);
720 if (!value && !xmlctx->ws_only) {
721 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected value \"%.*s\" in the \"%s\" element.",
Radek Krejci422afb12021-03-04 16:38:16 +0100722 (int)xmlctx->value_len, xmlctx->value, name);
Michal Vaskoe0665742021-02-11 11:08:44 +0100723 rc = LY_EVALID;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100724 goto cleanup;
Michal Vaskoe0665742021-02-11 11:08:44 +0100725 }
Michal Vaskoa8edff02020-03-27 14:47:01 +0100726
727 /* create node */
Michal Vaskoe0665742021-02-11 11:08:44 +0100728 rc = lyd_create_opaq(xmlctx->ctx, name, strlen(name), prefix, prefix_len, uri, strlen(uri), xmlctx->value,
729 xmlctx->ws_only ? 0 : xmlctx->value_len, NULL, LY_PREF_XML, NULL, 0, envp);
730 LY_CHECK_GOTO(rc, cleanup);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100731
732 /* assign atributes */
Michal Vaskoe0665742021-02-11 11:08:44 +0100733 ((struct lyd_node_opaq *)(*envp))->attr = attr;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100734 attr = NULL;
735
Michal Vaskoe0665742021-02-11 11:08:44 +0100736 /* parser next element */
737 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100738
Michal Vaskoe0665742021-02-11 11:08:44 +0100739cleanup:
740 lyd_free_attr_siblings(xmlctx->ctx, attr);
741 if (rc) {
742 lyd_free_tree(*envp);
743 *envp = NULL;
744 }
745 return rc;
746}
747
748/**
749 * @brief Parse all expected non-data XML elements of a NETCONF rpc message.
750 *
751 * @param[in] xmlctx XML parser context.
752 * @param[out] evnp Parsed envelope(s) (opaque node).
753 * @param[out] int_opts Internal options for parsing the rest of YANG data.
754 * @param[out] close_elem Number of parsed opened elements that need to be closed.
755 * @return LY_SUCCESS on success.
756 * @return LY_ERR value on error.
757 */
758static LY_ERR
759lydxml_env_netconf_rpc(struct lyxml_ctx *xmlctx, struct lyd_node **envp, uint32_t *int_opts, uint32_t *close_elem)
760{
761 LY_ERR rc = LY_SUCCESS, r;
762 struct lyd_node *child;
763
764 assert(envp && !*envp);
765
766 /* parse "rpc" */
767 r = lydxml_envelope(xmlctx, "rpc", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, envp);
Michal Vaskoe0665742021-02-11 11:08:44 +0100768 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
769
770 /* parse "action", if any */
771 r = lydxml_envelope(xmlctx, "action", "urn:ietf:params:xml:ns:yang:1", 0, &child);
772 if (r == LY_SUCCESS) {
773 /* insert */
774 lyd_insert_node(*envp, NULL, child);
775
776 /* NETCONF action */
777 *int_opts = LYD_INTOPT_NO_SIBLINGS | LYD_INTOPT_ACTION;
778 *close_elem = 2;
779 } else if (r == LY_ENOT) {
780 /* NETCONF RPC */
781 *int_opts = LYD_INTOPT_NO_SIBLINGS | LYD_INTOPT_RPC;
782 *close_elem = 1;
783 } else {
784 rc = r;
785 goto cleanup;
786 }
787
788cleanup:
789 if (rc) {
790 lyd_free_tree(*envp);
791 *envp = NULL;
792 }
793 return rc;
794}
795
796/**
797 * @brief Parse all expected non-data XML elements of a NETCONF notification message.
798 *
799 * @param[in] xmlctx XML parser context.
800 * @param[out] evnp Parsed envelope(s) (opaque node).
801 * @param[out] int_opts Internal options for parsing the rest of YANG data.
802 * @param[out] close_elem Number of parsed opened elements that need to be closed.
803 * @return LY_SUCCESS on success.
804 * @return LY_ERR value on error.
805 */
806static LY_ERR
807lydxml_env_netconf_notif(struct lyxml_ctx *xmlctx, struct lyd_node **envp, uint32_t *int_opts, uint32_t *close_elem)
808{
809 LY_ERR rc = LY_SUCCESS, r;
810 struct lyd_node *child;
811
812 assert(envp && !*envp);
813
814 /* parse "notification" */
815 r = lydxml_envelope(xmlctx, "notification", "urn:ietf:params:xml:ns:netconf:notification:1.0", 0, envp);
Michal Vaskoe0665742021-02-11 11:08:44 +0100816 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
817
818 /* parse "eventTime" */
819 r = lydxml_envelope(xmlctx, "eventTime", "urn:ietf:params:xml:ns:netconf:notification:1.0", 1, &child);
820 if (r == LY_ENOT) {
Radek Krejci422afb12021-03-04 16:38:16 +0100821 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unexpected element \"%.*s\" instead of \"eventTime\".",
822 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +0100823 r = LY_EVALID;
824 }
825 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
826
827 /* insert */
828 lyd_insert_node(*envp, NULL, child);
829
830 /* validate value */
831 /* TODO validate child->value as yang:date-and-time */
832
833 /* finish child parsing */
Michal Vaskoa8edff02020-03-27 14:47:01 +0100834 if (xmlctx->status != LYXML_ELEM_CLOSE) {
835 assert(xmlctx->status == LYXML_ELEMENT);
Michal Vaskoe0665742021-02-11 11:08:44 +0100836 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"eventTime\".",
Radek Krejci422afb12021-03-04 16:38:16 +0100837 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +0100838 rc = LY_EVALID;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100839 goto cleanup;
840 }
Michal Vaskoe0665742021-02-11 11:08:44 +0100841 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
842
843 /* NETCONF notification */
844 *int_opts = LYD_INTOPT_NO_SIBLINGS | LYD_INTOPT_NOTIF;
845 *close_elem = 1;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100846
847cleanup:
Michal Vaskoe0665742021-02-11 11:08:44 +0100848 if (rc) {
Michal Vaskoa8edff02020-03-27 14:47:01 +0100849 lyd_free_tree(*envp);
Michal Vaskoe0665742021-02-11 11:08:44 +0100850 *envp = NULL;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100851 }
Michal Vaskoe0665742021-02-11 11:08:44 +0100852 return rc;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100853}
Michal Vasko79135ae2020-12-16 10:08:35 +0100854
Michal Vaskoe0665742021-02-11 11:08:44 +0100855/**
856 * @brief Parse an XML element as an opaque node subtree.
857 *
858 * @param[in] xmlctx XML parser context.
859 * @param[in] parent Parent to append nodes to.
860 * @return LY_ERR value.
861 */
862static LY_ERR
863lydxml_opaq_r(struct lyxml_ctx *xmlctx, struct lyd_node *parent)
Michal Vaskoa8edff02020-03-27 14:47:01 +0100864{
Michal Vaskoe0665742021-02-11 11:08:44 +0100865 LY_ERR rc = LY_SUCCESS;
866 const struct lyxml_ns *ns;
867 struct lyd_attr *attr = NULL;
868 struct lyd_node *child = NULL;
869 const char *name, *prefix;
870 size_t name_len, prefix_len;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100871
Michal Vaskoe0665742021-02-11 11:08:44 +0100872 assert(xmlctx->status == LYXML_ELEMENT);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100873
Michal Vaskoe0665742021-02-11 11:08:44 +0100874 name = xmlctx->name;
875 name_len = xmlctx->name_len;
876 prefix = xmlctx->prefix;
877 prefix_len = xmlctx->prefix_len;
878 ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
879 if (!ns) {
Radek Krejci422afb12021-03-04 16:38:16 +0100880 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)prefix_len, prefix);
Michal Vaskoe0665742021-02-11 11:08:44 +0100881 return LY_EVALID;
882 }
Michal Vaskoa8edff02020-03-27 14:47:01 +0100883
Michal Vaskoe0665742021-02-11 11:08:44 +0100884 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
Michal Vaskoa8edff02020-03-27 14:47:01 +0100885
Michal Vaskoe0665742021-02-11 11:08:44 +0100886 /* create attributes */
887 if (xmlctx->status == LYXML_ATTRIBUTE) {
888 LY_CHECK_RET(lydxml_attrs(xmlctx, &attr));
889 }
890
891 /* create node */
892 assert(xmlctx->status == LYXML_ELEM_CONTENT);
893 rc = lyd_create_opaq(xmlctx->ctx, name, name_len, prefix, prefix_len, ns->uri, strlen(ns->uri), xmlctx->value,
894 xmlctx->ws_only ? 0 : xmlctx->value_len, NULL, LY_PREF_XML, NULL, 0, &child);
895 LY_CHECK_GOTO(rc, cleanup);
896
897 /* assign atributes */
898 ((struct lyd_node_opaq *)child)->attr = attr;
899 attr = NULL;
900
901 /* parser next element */
902 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
903
904 /* parse all the descendants */
905 while (xmlctx->status == LYXML_ELEMENT) {
906 rc = lydxml_opaq_r(xmlctx, child);
907 LY_CHECK_GOTO(rc, cleanup);
908 }
909
910 /* insert */
911 lyd_insert_node(parent, NULL, child);
912
913cleanup:
914 lyd_free_attr_siblings(xmlctx->ctx, attr);
915 if (rc) {
916 lyd_free_tree(child);
917 }
918 return rc;
919}
920
921/**
922 * @brief Parse all expected non-data XML elements of the error-info element in NETCONF rpc-reply message.
923 *
924 * @param[in] xmlctx XML parser context.
925 * @param[in] parent Parent to append nodes to.
926 * @return LY_ERR value.
927 */
928static LY_ERR
929lydxml_env_netconf_rpc_reply_error_info(struct lyxml_ctx *xmlctx, struct lyd_node *parent)
930{
931 LY_ERR r;
932 struct lyd_node *child, *iter;
933 const struct lyxml_ns *ns;
934 ly_bool no_dup;
935
936 /* there must be some child */
937 if (xmlctx->status == LYXML_ELEM_CLOSE) {
938 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Missing child elements of \"error-info\".");
939 return LY_EVALID;
940 }
941
942 while (xmlctx->status == LYXML_ELEMENT) {
943 child = NULL;
944
945 /*
946 * session-id
947 */
948 r = lydxml_envelope(xmlctx, "session-id", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
949 if (r == LY_SUCCESS) {
950 no_dup = 1;
951 goto check_child;
952 } else if (r != LY_ENOT) {
953 goto error;
954 }
955
956 /*
957 * bad-attribute
958 */
959 r = lydxml_envelope(xmlctx, "bad-attribute", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
960 if (r == LY_SUCCESS) {
961 no_dup = 1;
962 goto check_child;
963 } else if (r != LY_ENOT) {
964 goto error;
965 }
966
967 /*
968 * bad-element
969 */
970 r = lydxml_envelope(xmlctx, "bad-element", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
971 if (r == LY_SUCCESS) {
972 no_dup = 1;
973 goto check_child;
974 } else if (r != LY_ENOT) {
975 goto error;
976 }
977
978 /*
979 * bad-namespace
980 */
981 r = lydxml_envelope(xmlctx, "bad-namespace", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
982 if (r == LY_SUCCESS) {
983 no_dup = 1;
984 goto check_child;
985 } else if (r != LY_ENOT) {
986 goto error;
987 }
988
989 if (r == LY_ENOT) {
990 assert(xmlctx->status == LYXML_ELEMENT);
991
992 /* learn namespace */
993 ns = lyxml_ns_get(&xmlctx->ns, xmlctx->prefix, xmlctx->prefix_len);
994 if (!ns) {
Radek Krejci422afb12021-03-04 16:38:16 +0100995 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)xmlctx->prefix_len, xmlctx->prefix);
Michal Vaskoe0665742021-02-11 11:08:44 +0100996 r = LY_EVALID;
997 goto error;
998 } else if (!strcmp(ns->uri, "urn:ietf:params:xml:ns:netconf:base:1.0")) {
999 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"error-info\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001000 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001001 r = LY_EVALID;
1002 goto error;
1003 }
1004
1005 /* custom elements */
1006 r = lydxml_opaq_r(xmlctx, parent);
1007 LY_CHECK_GOTO(r, error);
1008
1009 no_dup = 0;
1010 }
1011
1012check_child:
1013 /* check for duplicates */
1014 if (no_dup) {
1015 LY_LIST_FOR(lyd_child(parent), iter) {
1016 if ((((struct lyd_node_opaq *)iter)->name.name == ((struct lyd_node_opaq *)child)->name.name) &&
1017 (((struct lyd_node_opaq *)iter)->name.module_ns == ((struct lyd_node_opaq *)child)->name.module_ns)) {
1018 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Duplicate element \"%s\" in \"error-info\".",
1019 ((struct lyd_node_opaq *)child)->name.name);
1020 r = LY_EVALID;
1021 goto error;
1022 }
1023 }
1024 }
1025
1026 /* finish child parsing */
1027 if (xmlctx->status != LYXML_ELEM_CLOSE) {
1028 assert(xmlctx->status == LYXML_ELEMENT);
1029 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"error-info\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001030 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001031 r = LY_EVALID;
1032 goto error;
1033 }
1034 LY_CHECK_GOTO(r = lyxml_ctx_next(xmlctx), error);
1035
1036 /* insert */
1037 lyd_insert_node(parent, NULL, child);
1038 }
1039
1040 return LY_SUCCESS;
1041
1042error:
1043 lyd_free_tree(child);
1044 return r;
1045}
1046
1047/**
1048 * @brief Parse all expected non-data XML elements of the rpc-error element in NETCONF rpc-reply message.
1049 *
1050 * @param[in] xmlctx XML parser context.
1051 * @param[in] parent Parent to append nodes to.
1052 * @return LY_ERR value.
1053 */
1054static LY_ERR
1055lydxml_env_netconf_rpc_reply_error(struct lyxml_ctx *xmlctx, struct lyd_node *parent)
1056{
1057 LY_ERR r;
1058 struct lyd_node *child, *iter;
1059 const char *val;
1060 ly_bool no_dup;
1061
1062 /* there must be some child */
1063 if (xmlctx->status == LYXML_ELEM_CLOSE) {
1064 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Missing child elements of \"rpc-error\".");
1065 return LY_EVALID;
1066 }
1067
1068 while (xmlctx->status == LYXML_ELEMENT) {
1069 child = NULL;
1070
1071 /*
1072 * error-type
1073 */
1074 r = lydxml_envelope(xmlctx, "error-type", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1075 if (r == LY_SUCCESS) {
1076 val = ((struct lyd_node_opaq *)child)->value;
1077 if (strcmp(val, "transport") && strcmp(val, "rpc") && strcmp(val, "protocol") && strcmp(val, "application")) {
1078 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Invalid value \"%s\" of element \"%s\".", val,
1079 ((struct lyd_node_opaq *)child)->name.name);
1080 r = LY_EVALID;
1081 goto error;
1082 }
1083
1084 no_dup = 1;
1085 goto check_child;
1086 } else if (r != LY_ENOT) {
1087 goto error;
1088 }
1089
1090 /*
1091 * error-tag
1092 */
1093 r = lydxml_envelope(xmlctx, "error-tag", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1094 if (r == LY_SUCCESS) {
1095 val = ((struct lyd_node_opaq *)child)->value;
1096 if (strcmp(val, "in-use") && strcmp(val, "invalid-value") && strcmp(val, "too-big") &&
1097 strcmp(val, "missing-attribute") && strcmp(val, "bad-attribute") &&
1098 strcmp(val, "unknown-attribute") && strcmp(val, "missing-element") && strcmp(val, "bad-element") &&
1099 strcmp(val, "unknown-element") && strcmp(val, "unknown-namespace") && strcmp(val, "access-denied") &&
1100 strcmp(val, "lock-denied") && strcmp(val, "resource-denied") && strcmp(val, "rollback-failed") &&
1101 strcmp(val, "data-exists") && strcmp(val, "data-missing") && strcmp(val, "operation-not-supported") &&
1102 strcmp(val, "operation-failed") && strcmp(val, "malformed-message")) {
1103 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Invalid value \"%s\" of element \"%s\".", val,
1104 ((struct lyd_node_opaq *)child)->name.name);
1105 r = LY_EVALID;
1106 goto error;
1107 }
1108
1109 no_dup = 1;
1110 goto check_child;
1111 } else if (r != LY_ENOT) {
1112 goto error;
1113 }
1114
1115 /*
1116 * error-severity
1117 */
1118 r = lydxml_envelope(xmlctx, "error-severity", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1119 if (r == LY_SUCCESS) {
1120 val = ((struct lyd_node_opaq *)child)->value;
1121 if (strcmp(val, "error") && strcmp(val, "warning")) {
1122 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Invalid value \"%s\" of element \"%s\".", val,
1123 ((struct lyd_node_opaq *)child)->name.name);
1124 r = LY_EVALID;
1125 goto error;
1126 }
1127
1128 no_dup = 1;
1129 goto check_child;
1130 } else if (r != LY_ENOT) {
1131 goto error;
1132 }
1133
1134 /*
1135 * error-app-tag
1136 */
1137 r = lydxml_envelope(xmlctx, "error-app-tag", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1138 if (r == LY_SUCCESS) {
1139 no_dup = 1;
1140 goto check_child;
1141 } else if (r != LY_ENOT) {
1142 goto error;
1143 }
1144
1145 /*
1146 * error-path
1147 */
1148 r = lydxml_envelope(xmlctx, "error-path", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1149 if (r == LY_SUCCESS) {
1150 no_dup = 1;
1151 goto check_child;
1152 } else if (r != LY_ENOT) {
1153 goto error;
1154 }
1155
1156 /*
1157 * error-message
1158 */
1159 r = lydxml_envelope(xmlctx, "error-message", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1160 if (r == LY_SUCCESS) {
1161 no_dup = 1;
1162 goto check_child;
1163 } else if (r != LY_ENOT) {
1164 goto error;
1165 }
1166
1167 /* error-info */
1168 r = lydxml_envelope(xmlctx, "error-info", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, &child);
1169 if (r == LY_SUCCESS) {
1170 /* parse all the descendants */
1171 LY_CHECK_GOTO(r = lydxml_env_netconf_rpc_reply_error_info(xmlctx, child), error);
1172
1173 no_dup = 0;
1174 goto check_child;
1175 } else if (r != LY_ENOT) {
1176 goto error;
1177 }
1178
1179 if (r == LY_ENOT) {
1180 assert(xmlctx->status == LYXML_ELEMENT);
1181 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"rpc-error\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001182 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001183 r = LY_EVALID;
1184 goto error;
1185 }
1186
1187check_child:
1188 /* check for duplicates */
1189 if (no_dup) {
1190 LY_LIST_FOR(lyd_child(parent), iter) {
1191 if ((((struct lyd_node_opaq *)iter)->name.name == ((struct lyd_node_opaq *)child)->name.name) &&
1192 (((struct lyd_node_opaq *)iter)->name.module_ns == ((struct lyd_node_opaq *)child)->name.module_ns)) {
1193 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Duplicate element \"%s\" in \"rpc-error\".",
1194 ((struct lyd_node_opaq *)child)->name.name);
1195 r = LY_EVALID;
1196 goto error;
1197 }
1198 }
1199 }
1200
1201 /* finish child parsing */
1202 if (xmlctx->status != LYXML_ELEM_CLOSE) {
1203 assert(xmlctx->status == LYXML_ELEMENT);
1204 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"rpc-error\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001205 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001206 r = LY_EVALID;
1207 goto error;
1208 }
1209 LY_CHECK_GOTO(r = lyxml_ctx_next(xmlctx), error);
1210
1211 /* insert */
1212 lyd_insert_node(parent, NULL, child);
1213 }
1214
1215 return LY_SUCCESS;
1216
1217error:
1218 lyd_free_tree(child);
1219 return r;
1220}
1221
1222/**
1223 * @brief Parse all expected non-data XML elements of a NETCONF rpc-reply message.
1224 *
1225 * @param[in] xmlctx XML parser context.
1226 * @param[out] evnp Parsed envelope(s) (opaque node).
1227 * @param[out] int_opts Internal options for parsing the rest of YANG data.
1228 * @param[out] close_elem Number of parsed opened elements that need to be closed.
1229 * @return LY_SUCCESS on success.
1230 * @return LY_ERR value on error.
1231 */
1232static LY_ERR
1233lydxml_env_netconf_reply(struct lyxml_ctx *xmlctx, struct lyd_node **envp, uint32_t *int_opts, uint32_t *close_elem)
1234{
1235 LY_ERR rc = LY_SUCCESS, r;
1236 struct lyd_node *child = NULL;
1237 const char *parsed_elem = NULL;
1238
1239 assert(envp && !*envp);
1240
1241 /* parse "rpc-reply" */
1242 r = lydxml_envelope(xmlctx, "rpc-reply", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, envp);
Michal Vaskoe0665742021-02-11 11:08:44 +01001243 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
1244
1245 /* there must be some child */
1246 if (xmlctx->status == LYXML_ELEM_CLOSE) {
1247 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Missing child elements of \"rpc-reply\".");
1248 rc = LY_EVALID;
Michal Vaskocf770e22020-08-12 13:21:43 +02001249 goto cleanup;
Michal Vaskoa8edff02020-03-27 14:47:01 +01001250 }
1251
Michal Vaskoe0665742021-02-11 11:08:44 +01001252 /* try to parse "ok" */
1253 r = lydxml_envelope(xmlctx, "ok", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, &child);
1254 if (r == LY_SUCCESS) {
1255 /* insert */
1256 lyd_insert_node(*envp, NULL, child);
1257
1258 /* finish child parsing */
1259 if (xmlctx->status != LYXML_ELEM_CLOSE) {
1260 assert(xmlctx->status == LYXML_ELEMENT);
1261 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"ok\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001262 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001263 rc = LY_EVALID;
1264 goto cleanup;
1265 }
1266 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
1267
1268 /* success */
1269 parsed_elem = "ok";
1270 goto finish;
1271 } else if (r != LY_ENOT) {
1272 rc = r;
1273 goto cleanup;
Michal Vasko2552ea32020-12-08 15:32:34 +01001274 }
1275
Michal Vaskoe0665742021-02-11 11:08:44 +01001276 /* try to parse all "rpc-error" elements */
1277 while (xmlctx->status == LYXML_ELEMENT) {
1278 r = lydxml_envelope(xmlctx, "rpc-error", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, &child);
1279 if (r == LY_ENOT) {
1280 break;
1281 } else if (r) {
1282 rc = r;
1283 goto cleanup;
1284 }
1285
1286 /* insert */
1287 lyd_insert_node(*envp, NULL, child);
1288
1289 /* parse all children of "rpc-error" */
1290 LY_CHECK_GOTO(rc = lydxml_env_netconf_rpc_reply_error(xmlctx, child), cleanup);
1291
1292 /* finish child parsing */
1293 assert(xmlctx->status == LYXML_ELEM_CLOSE);
1294 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
1295
1296 parsed_elem = "rpc-error";
Michal Vasko2552ea32020-12-08 15:32:34 +01001297 }
Michal Vaskoe0665742021-02-11 11:08:44 +01001298
1299finish:
1300 if (parsed_elem) {
1301 /* NETCONF rpc-reply with no data */
1302 if (xmlctx->status != LYXML_ELEM_CLOSE) {
1303 assert(xmlctx->status == LYXML_ELEMENT);
1304 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected sibling element \"%.*s\" of \"%s\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001305 (int)xmlctx->name_len, xmlctx->name, parsed_elem);
Michal Vaskoe0665742021-02-11 11:08:44 +01001306 rc = LY_EVALID;
1307 goto cleanup;
1308 }
1309 }
1310
1311 /* NETCONF rpc-reply */
1312 *int_opts = LYD_INTOPT_NO_SIBLINGS | LYD_INTOPT_REPLY;
1313 *close_elem = 1;
1314
1315cleanup:
1316 if (rc) {
1317 lyd_free_tree(*envp);
1318 *envp = NULL;
1319 }
1320 return rc;
1321}
1322
Michal Vasko2552ea32020-12-08 15:32:34 +01001323LY_ERR
Radek Krejcif16e2542021-02-17 15:39:23 +01001324lyd_parse_xml(const struct ly_ctx *ctx, const struct lysc_ext_instance *ext, struct lyd_node *parent,
1325 struct lyd_node **first_p, struct ly_in *in, uint32_t parse_opts, uint32_t val_opts, enum lyd_type data_type,
1326 struct lyd_node **envp, struct ly_set *parsed, struct lyd_ctx **lydctx_p)
Michal Vasko2552ea32020-12-08 15:32:34 +01001327{
Michal Vaskoe0665742021-02-11 11:08:44 +01001328 LY_ERR rc = LY_SUCCESS;
1329 struct lyd_xml_ctx *lydctx;
1330 uint32_t i, int_opts, close_elem = 0;
1331 ly_bool parsed_data_nodes = 0;
Michal Vasko2552ea32020-12-08 15:32:34 +01001332
Michal Vaskoe0665742021-02-11 11:08:44 +01001333 assert(ctx && in && lydctx_p);
1334 assert(!(parse_opts & ~LYD_PARSE_OPTS_MASK));
1335 assert(!(val_opts & ~LYD_VALIDATE_OPTS_MASK));
Michal Vasko2552ea32020-12-08 15:32:34 +01001336
Michal Vaskoe0665742021-02-11 11:08:44 +01001337 /* init context */
1338 lydctx = calloc(1, sizeof *lydctx);
1339 LY_CHECK_ERR_RET(!lydctx, LOGMEM(ctx), LY_EMEM);
1340 LY_CHECK_GOTO(rc = lyxml_ctx_new(ctx, in, &lydctx->xmlctx), cleanup);
1341 lydctx->parse_opts = parse_opts;
1342 lydctx->val_opts = val_opts;
1343 lydctx->free = lyd_xml_ctx_free;
Radek Krejcif16e2542021-02-17 15:39:23 +01001344 lydctx->ext = ext;
Michal Vasko2552ea32020-12-08 15:32:34 +01001345
Michal Vaskoe0665742021-02-11 11:08:44 +01001346 switch (data_type) {
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001347 case LYD_TYPE_DATA_YANG:
Michal Vaskoe0665742021-02-11 11:08:44 +01001348 int_opts = LYD_INTOPT_WITH_SIBLINGS;
1349 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001350 case LYD_TYPE_RPC_YANG:
Michal Vaskoe0665742021-02-11 11:08:44 +01001351 int_opts = LYD_INTOPT_RPC | LYD_INTOPT_ACTION | LYD_INTOPT_NO_SIBLINGS;
1352 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001353 case LYD_TYPE_NOTIF_YANG:
Michal Vaskoe0665742021-02-11 11:08:44 +01001354 int_opts = LYD_INTOPT_NOTIF | LYD_INTOPT_NO_SIBLINGS;
1355 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001356 case LYD_TYPE_REPLY_YANG:
Michal Vaskoe0665742021-02-11 11:08:44 +01001357 int_opts = LYD_INTOPT_REPLY | LYD_INTOPT_NO_SIBLINGS;
1358 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001359 case LYD_TYPE_RPC_NETCONF:
Michal Vaskoe0665742021-02-11 11:08:44 +01001360 assert(!parent);
1361 LY_CHECK_GOTO(rc = lydxml_env_netconf_rpc(lydctx->xmlctx, envp, &int_opts, &close_elem), cleanup);
1362 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001363 case LYD_TYPE_NOTIF_NETCONF:
1364 assert(!parent);
1365 LY_CHECK_GOTO(rc = lydxml_env_netconf_notif(lydctx->xmlctx, envp, &int_opts, &close_elem), cleanup);
1366 break;
1367 case LYD_TYPE_REPLY_NETCONF:
Michal Vaskoe0665742021-02-11 11:08:44 +01001368 assert(parent);
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001369 LY_CHECK_GOTO(rc = lydxml_env_netconf_reply(lydctx->xmlctx, envp, &int_opts, &close_elem), cleanup);
Michal Vaskoe0665742021-02-11 11:08:44 +01001370 break;
1371 }
1372 lydctx->int_opts = int_opts;
1373
1374 /* find the operation node if it exists already */
1375 LY_CHECK_GOTO(rc = lyd_parser_find_operation(parent, int_opts, &lydctx->op_node), cleanup);
1376
1377 /* parse XML data */
1378 while (lydctx->xmlctx->status == LYXML_ELEMENT) {
1379 LY_CHECK_GOTO(rc = lydxml_subtree_r(lydctx, parent, first_p, parsed), cleanup);
1380 parsed_data_nodes = 1;
1381
1382 if (!(int_opts & LYD_INTOPT_WITH_SIBLINGS)) {
1383 break;
1384 }
Michal Vasko2552ea32020-12-08 15:32:34 +01001385 }
1386
Michal Vaskoe0665742021-02-11 11:08:44 +01001387 /* close all opened elements */
1388 for (i = 0; i < close_elem; ++i) {
1389 if (lydctx->xmlctx->status != LYXML_ELEM_CLOSE) {
1390 assert(lydctx->xmlctx->status == LYXML_ELEMENT);
Radek Krejci422afb12021-03-04 16:38:16 +01001391 LOGVAL(lydctx->xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\".",
1392 (int)lydctx->xmlctx->name_len, lydctx->xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001393 rc = LY_EVALID;
1394 goto cleanup;
1395 }
1396
1397 LY_CHECK_GOTO(rc = lyxml_ctx_next(lydctx->xmlctx), cleanup);
Michal Vasko4189c0f2020-08-13 09:05:22 +02001398 }
Michal Vaskoe0665742021-02-11 11:08:44 +01001399
1400 /* check final state */
1401 if ((int_opts & LYD_INTOPT_NO_SIBLINGS) && (lydctx->xmlctx->status == LYXML_ELEMENT)) {
1402 LOGVAL(ctx, LYVE_SYNTAX, "Unexpected sibling node.");
1403 rc = LY_EVALID;
1404 goto cleanup;
1405 }
1406 if ((int_opts & (LYD_INTOPT_RPC | LYD_INTOPT_NOTIF | LYD_INTOPT_REPLY)) && !lydctx->op_node) {
1407 LOGVAL(ctx, LYVE_DATA, "Missing the operation node.");
1408 rc = LY_EVALID;
1409 goto cleanup;
1410 }
1411
1412 if (!parsed_data_nodes) {
1413 /* no data nodes were parsed */
1414 lydctx->op_node = NULL;
Michal Vaskoa8edff02020-03-27 14:47:01 +01001415 }
1416
1417cleanup:
Michal Vaskoe0665742021-02-11 11:08:44 +01001418 /* there should be no unres stored if validation should be skipped */
1419 assert(!(parse_opts & LYD_PARSE_ONLY) || (!lydctx->node_types.count && !lydctx->meta_types.count &&
1420 !lydctx->node_when.count));
1421
1422 if (rc) {
1423 lyd_xml_ctx_free((struct lyd_ctx *)lydctx);
1424 } else {
1425 *lydctx_p = (struct lyd_ctx *)lydctx;
1426
1427 /* the XML context is no more needed, freeing it also stops logging line numbers which would be confusing now */
1428 lyxml_ctx_free(lydctx->xmlctx);
1429 lydctx->xmlctx = NULL;
Michal Vasko1ce933a2020-03-30 12:38:22 +02001430 }
Michal Vaskoe0665742021-02-11 11:08:44 +01001431 return rc;
Michal Vasko1ce933a2020-03-30 12:38:22 +02001432}