blob: d685c74bc3eb8bd04669ba50a6aa526870972634 [file] [log] [blame]
Radek Krejcie7b95092019-05-15 11:03:07 +02001/**
2 * @file parser_xml.c
3 * @author Radek Krejci <rkrejci@cesnet.cz>
4 * @brief XML data parser for libyang
5 *
6 * Copyright (c) 2019 CESNET, z.s.p.o.
7 *
8 * This source code is licensed under BSD 3-Clause License (the "License").
9 * You may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * https://opensource.org/licenses/BSD-3-Clause
13 */
14
Michal Vasko69730152020-10-09 16:30:07 +020015#include <assert.h>
Radek Krejcie7b95092019-05-15 11:03:07 +020016#include <stdint.h>
17#include <stdlib.h>
18#include <string.h>
19
Radek Krejci535ea9f2020-05-29 16:01:05 +020020#include "common.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020021#include "context.h"
Radek Krejci77114102021-03-10 15:21:57 +010022#include "dict.h"
Michal Vaskoafac7822020-10-20 14:22:26 +020023#include "in_internal.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020024#include "log.h"
Radek Krejci7931b192020-06-25 17:05:03 +020025#include "parser_data.h"
26#include "parser_internal.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020027#include "set.h"
Radek Krejci77114102021-03-10 15:21:57 +010028#include "tree.h"
Radek Krejci47fab892020-11-05 17:02:41 +010029#include "tree_data.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020030#include "tree_data_internal.h"
31#include "tree_schema.h"
Radek Krejci77114102021-03-10 15:21:57 +010032#include "tree_schema_internal.h"
Michal Vaskocde73ac2019-11-14 16:10:27 +010033#include "validation.h"
Radek Krejci535ea9f2020-05-29 16:01:05 +020034#include "xml.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020035
36/**
Michal Vaskob36053d2020-03-26 15:49:30 +010037 * @brief Internal context for XML YANG data parser.
Radek Krejci1798aae2020-07-14 13:26:06 +020038 *
39 * Note that the structure maps to the lyd_ctx which is common for all the data parsers
Radek Krejcie7b95092019-05-15 11:03:07 +020040 */
41struct lyd_xml_ctx {
Radek Krejcif16e2542021-02-17 15:39:23 +010042 const struct lysc_ext_instance *ext; /**< extension instance possibly changing document root context of the data being parsed */
Michal Vaskoe0665742021-02-11 11:08:44 +010043 uint32_t parse_opts; /**< various @ref dataparseroptions. */
44 uint32_t val_opts; /**< various @ref datavalidationoptions. */
Radek Krejci1798aae2020-07-14 13:26:06 +020045 uint32_t int_opts; /**< internal data parser options */
46 uint32_t path_len; /**< used bytes in the path buffer */
47 char path[LYD_PARSER_BUFSIZE]; /**< buffer for the generated path */
Michal Vaskoc43c8ab2021-03-05 13:32:44 +010048 struct ly_set node_when; /**< set of nodes with "when" conditions */
Michal Vasko49c39d82020-11-06 17:20:27 +010049 struct ly_set node_types; /**< set of nodes validated with LY_EINCOMPLETE result */
50 struct ly_set meta_types; /**< set of metadata validated with LY_EINCOMPLETE result */
Radek Krejci1798aae2020-07-14 13:26:06 +020051 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 +020052
Radek Krejci1798aae2020-07-14 13:26:06 +020053 /* callbacks */
54 lyd_ctx_free_clb free; /* destructor */
Radek Krejci1798aae2020-07-14 13:26:06 +020055
56 struct lyxml_ctx *xmlctx; /**< XML context */
Radek Krejcie7b95092019-05-15 11:03:07 +020057};
58
Radek Krejci1798aae2020-07-14 13:26:06 +020059void
60lyd_xml_ctx_free(struct lyd_ctx *lydctx)
61{
62 struct lyd_xml_ctx *ctx = (struct lyd_xml_ctx *)lydctx;
63
64 lyd_ctx_free(lydctx);
65 lyxml_ctx_free(ctx->xmlctx);
66 free(ctx);
67}
68
Radek Krejcie7b95092019-05-15 11:03:07 +020069static LY_ERR
Michal Vaskofeca4fb2020-10-05 08:58:40 +020070lydxml_metadata(struct lyd_xml_ctx *lydctx, struct lyd_meta **meta)
Radek Krejcie7b95092019-05-15 11:03:07 +020071{
Michal Vaskob36053d2020-03-26 15:49:30 +010072 LY_ERR ret = LY_EVALID;
Radek Krejci28681fa2019-09-06 13:08:45 +020073 const struct lyxml_ns *ns;
74 struct lys_module *mod;
Michal Vaskob36053d2020-03-26 15:49:30 +010075 const char *name;
76 size_t name_len;
Radek Krejci1798aae2020-07-14 13:26:06 +020077 struct lyxml_ctx *xmlctx = lydctx->xmlctx;
Radek Krejci28681fa2019-09-06 13:08:45 +020078
Michal Vaskob36053d2020-03-26 15:49:30 +010079 *meta = NULL;
Radek Krejci28681fa2019-09-06 13:08:45 +020080
Michal Vaskob36053d2020-03-26 15:49:30 +010081 while (xmlctx->status == LYXML_ATTRIBUTE) {
82 if (!xmlctx->prefix_len) {
Radek Krejci28681fa2019-09-06 13:08:45 +020083 /* in XML, all attributes must be prefixed
84 * TODO exception for NETCONF filters which are supposed to map to the ietf-netconf without prefix */
Michal Vaskoe0665742021-02-11 11:08:44 +010085 if (lydctx->parse_opts & LYD_PARSE_STRICT) {
Radek Krejci2efc45b2020-12-22 16:25:44 +010086 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Missing mandatory prefix for XML metadata \"%.*s\".",
Radek Krejci422afb12021-03-04 16:38:16 +010087 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskob36053d2020-03-26 15:49:30 +010088 goto cleanup;
Radek Krejci28681fa2019-09-06 13:08:45 +020089 }
Michal Vaskob36053d2020-03-26 15:49:30 +010090
Radek Krejci28681fa2019-09-06 13:08:45 +020091skip_attr:
Michal Vaskob36053d2020-03-26 15:49:30 +010092 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
93 assert(xmlctx->status == LYXML_ATTR_CONTENT);
94 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Radek Krejci28681fa2019-09-06 13:08:45 +020095 continue;
96 }
97
98 /* get namespace of the attribute to find its annotation definition */
Michal Vaskoc8a230d2020-08-14 12:17:10 +020099 ns = lyxml_ns_get(&xmlctx->ns, xmlctx->prefix, xmlctx->prefix_len);
Radek Krejci28681fa2019-09-06 13:08:45 +0200100 if (!ns) {
Michal Vasko52927e22020-03-16 17:26:14 +0100101 /* unknown namespace, XML error */
Radek Krejci422afb12021-03-04 16:38:16 +0100102 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)xmlctx->prefix_len, xmlctx->prefix);
Radek Krejci28681fa2019-09-06 13:08:45 +0200103 goto cleanup;
104 }
Michal Vasko52927e22020-03-16 17:26:14 +0100105 mod = ly_ctx_get_module_implemented_ns(xmlctx->ctx, ns->uri);
Radek Krejci28681fa2019-09-06 13:08:45 +0200106 if (!mod) {
107 /* module is not implemented or not present in the schema */
Michal Vaskoe0665742021-02-11 11:08:44 +0100108 if (lydctx->parse_opts & LYD_PARSE_STRICT) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100109 LOGVAL(xmlctx->ctx, LYVE_REFERENCE,
Michal Vasko69730152020-10-09 16:30:07 +0200110 "Unknown (or not implemented) YANG module with namespace \"%s\" for metadata \"%.*s%s%.*s\".",
Radek Krejci422afb12021-03-04 16:38:16 +0100111 ns->uri, (int)xmlctx->prefix_len, xmlctx->prefix, xmlctx->prefix_len ? ":" : "",
112 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskob36053d2020-03-26 15:49:30 +0100113 goto cleanup;
Radek Krejci28681fa2019-09-06 13:08:45 +0200114 }
115 goto skip_attr;
116 }
117
Michal Vasko60ea6352020-06-29 13:39:39 +0200118 /* remember meta name and get its content */
Michal Vaskob36053d2020-03-26 15:49:30 +0100119 name = xmlctx->name;
120 name_len = xmlctx->name_len;
121 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
122 assert(xmlctx->status == LYXML_ATTR_CONTENT);
123
124 /* create metadata */
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200125 ret = lyd_parser_create_meta((struct lyd_ctx *)lydctx, NULL, meta, mod, name, name_len, xmlctx->value,
Michal Vaskofeca4fb2020-10-05 08:58:40 +0200126 xmlctx->value_len, &xmlctx->dynamic, LY_PREF_XML, &xmlctx->ns, LYD_HINT_DATA);
Radek Krejci1798aae2020-07-14 13:26:06 +0200127 LY_CHECK_GOTO(ret, cleanup);
Michal Vaskob36053d2020-03-26 15:49:30 +0100128
129 /* next attribute */
130 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Radek Krejcie7b95092019-05-15 11:03:07 +0200131 }
Michal Vasko52927e22020-03-16 17:26:14 +0100132
Radek Krejci28681fa2019-09-06 13:08:45 +0200133 ret = LY_SUCCESS;
Radek Krejcie7b95092019-05-15 11:03:07 +0200134
135cleanup:
Michal Vaskob36053d2020-03-26 15:49:30 +0100136 if (ret) {
Michal Vasko3a41dff2020-07-15 14:30:28 +0200137 lyd_free_meta_siblings(*meta);
Michal Vaskob36053d2020-03-26 15:49:30 +0100138 *meta = NULL;
Radek Krejci38d85362019-09-05 16:26:38 +0200139 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200140 return ret;
141}
142
Michal Vasko52927e22020-03-16 17:26:14 +0100143static LY_ERR
Radek Krejci1798aae2020-07-14 13:26:06 +0200144lydxml_attrs(struct lyxml_ctx *xmlctx, struct lyd_attr **attr)
Michal Vasko52927e22020-03-16 17:26:14 +0100145{
146 LY_ERR ret = LY_SUCCESS;
147 const struct lyxml_ns *ns;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100148 void *val_prefix_data;
149 LY_PREFIX_FORMAT format;
Radek Krejci1798aae2020-07-14 13:26:06 +0200150 struct lyd_attr *attr2;
Michal Vaskob36053d2020-03-26 15:49:30 +0100151 const char *name, *prefix;
152 size_t name_len, prefix_len;
Michal Vasko52927e22020-03-16 17:26:14 +0100153
154 assert(attr);
Michal Vaskob36053d2020-03-26 15:49:30 +0100155 *attr = NULL;
Michal Vasko52927e22020-03-16 17:26:14 +0100156
Michal Vaskob36053d2020-03-26 15:49:30 +0100157 while (xmlctx->status == LYXML_ATTRIBUTE) {
Michal Vasko52927e22020-03-16 17:26:14 +0100158 ns = NULL;
Michal Vaskob36053d2020-03-26 15:49:30 +0100159 if (xmlctx->prefix_len) {
Michal Vasko52927e22020-03-16 17:26:14 +0100160 /* get namespace of the attribute */
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200161 ns = lyxml_ns_get(&xmlctx->ns, xmlctx->prefix, xmlctx->prefix_len);
Michal Vasko52927e22020-03-16 17:26:14 +0100162 if (!ns) {
Radek Krejci422afb12021-03-04 16:38:16 +0100163 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)xmlctx->prefix_len, xmlctx->prefix);
Michal Vasko52927e22020-03-16 17:26:14 +0100164 ret = LY_EVALID;
165 goto cleanup;
166 }
167 }
168
169 if (*attr) {
170 attr2 = *attr;
171 } else {
172 attr2 = NULL;
173 }
174
Michal Vaskob36053d2020-03-26 15:49:30 +0100175 /* remember attr prefix, name, and get its content */
176 prefix = xmlctx->prefix;
177 prefix_len = xmlctx->prefix_len;
178 name = xmlctx->name;
179 name_len = xmlctx->name_len;
180 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
181 assert(xmlctx->status == LYXML_ATTR_CONTENT);
182
Michal Vasko52927e22020-03-16 17:26:14 +0100183 /* get value prefixes */
Michal Vaskofc2cd072021-02-24 13:17:17 +0100184 val_prefix_data = NULL;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100185 LY_CHECK_GOTO(ret = ly_store_prefix_data(xmlctx->ctx, xmlctx->value, xmlctx->value_len, LY_PREF_XML,
186 &xmlctx->ns, &format, &val_prefix_data), cleanup);
Michal Vasko52927e22020-03-16 17:26:14 +0100187
188 /* attr2 is always changed to the created attribute */
Michal Vasko501af032020-11-11 20:27:44 +0100189 ret = lyd_create_attr(NULL, &attr2, xmlctx->ctx, name, name_len, prefix, prefix_len, ns ? ns->uri : NULL,
190 ns ? strlen(ns->uri) : 0, xmlctx->value, xmlctx->value_len, &xmlctx->dynamic, format, val_prefix_data, 0);
Michal Vasko52927e22020-03-16 17:26:14 +0100191 LY_CHECK_GOTO(ret, cleanup);
192
193 if (!*attr) {
194 *attr = attr2;
195 }
Michal Vaskob36053d2020-03-26 15:49:30 +0100196
197 /* next attribute */
198 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko52927e22020-03-16 17:26:14 +0100199 }
200
201cleanup:
Michal Vaskob36053d2020-03-26 15:49:30 +0100202 if (ret) {
Radek Krejci011e4aa2020-09-04 15:22:31 +0200203 lyd_free_attr_siblings(xmlctx->ctx, *attr);
Michal Vaskob36053d2020-03-26 15:49:30 +0100204 *attr = NULL;
Michal Vasko52927e22020-03-16 17:26:14 +0100205 }
Michal Vasko52927e22020-03-16 17:26:14 +0100206 return ret;
207}
208
Michal Vasko44685da2020-03-17 15:38:06 +0100209static LY_ERR
Michal Vaskob36053d2020-03-26 15:49:30 +0100210lydxml_check_list(struct lyxml_ctx *xmlctx, const struct lysc_node *list)
Michal Vasko44685da2020-03-17 15:38:06 +0100211{
Michal Vaskob36053d2020-03-26 15:49:30 +0100212 LY_ERR ret = LY_SUCCESS, r;
213 enum LYXML_PARSER_STATUS next;
Michal Vasko44685da2020-03-17 15:38:06 +0100214 struct ly_set key_set = {0};
215 const struct lysc_node *snode;
Michal Vaskob36053d2020-03-26 15:49:30 +0100216 uint32_t i, parents_count;
Michal Vasko44685da2020-03-17 15:38:06 +0100217
218 assert(list && (list->nodetype == LYS_LIST));
219
220 /* get all keys into a set (keys do not have if-features or anything) */
221 snode = NULL;
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100222 while ((snode = lys_getnext(snode, list, NULL, 0)) && (snode->flags & LYS_KEY)) {
Radek Krejci3d92e442020-10-12 12:48:13 +0200223 ret = ly_set_add(&key_set, (void *)snode, 1, NULL);
Radek Krejciba03a5a2020-08-27 14:40:41 +0200224 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100225 }
226
Michal Vasko12d809c2021-03-03 16:34:32 +0100227 /* remember parent count */
228 parents_count = xmlctx->elements.count;
229
Michal Vaskob36053d2020-03-26 15:49:30 +0100230 while (xmlctx->status == LYXML_ELEMENT) {
Michal Vasko44685da2020-03-17 15:38:06 +0100231 /* find key definition */
232 for (i = 0; i < key_set.count; ++i) {
233 snode = (const struct lysc_node *)key_set.objs[i];
Michal Vaskob36053d2020-03-26 15:49:30 +0100234 if (!ly_strncmp(snode->name, xmlctx->name, xmlctx->name_len)) {
Michal Vasko44685da2020-03-17 15:38:06 +0100235 break;
236 }
237 }
Michal Vaskob36053d2020-03-26 15:49:30 +0100238 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100239
240 /* skip attributes */
241 while (xmlctx->status == LYXML_ATTRIBUTE) {
Michal Vaskob36053d2020-03-26 15:49:30 +0100242 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
243 assert(xmlctx->status == LYXML_ATTR_CONTENT);
244 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100245 }
246
Michal Vaskob36053d2020-03-26 15:49:30 +0100247 assert(xmlctx->status == LYXML_ELEM_CONTENT);
248 if (i < key_set.count) {
249 /* validate the value */
Michal Vasko713148b2020-11-12 13:10:13 +0100250 r = _lys_value_validate(NULL, snode, xmlctx->value, xmlctx->value_len, LY_PREF_XML, &xmlctx->ns);
Michal Vaskob36053d2020-03-26 15:49:30 +0100251 if (!r) {
252 /* key with a valid value, remove from the set */
253 ly_set_rm_index(&key_set, i, NULL);
Michal Vasko44685da2020-03-17 15:38:06 +0100254 }
255 }
256
Michal Vaskob36053d2020-03-26 15:49:30 +0100257 /* parser next */
258 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100259
Michal Vaskob36053d2020-03-26 15:49:30 +0100260 /* skip any children, resursively */
Michal Vasko12d809c2021-03-03 16:34:32 +0100261 while (xmlctx->status == LYXML_ELEMENT) {
262 while (parents_count < xmlctx->elements.count) {
263 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
264 }
265 assert(xmlctx->status == LYXML_ELEM_CLOSE);
Michal Vaskob36053d2020-03-26 15:49:30 +0100266 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
267 }
268
269 /* parser next, but do not parse closing element of the list because it would remove its namespaces */
270 assert(xmlctx->status == LYXML_ELEM_CLOSE);
271 LY_CHECK_GOTO(ret = lyxml_ctx_peek(xmlctx, &next), cleanup);
272 if (next != LYXML_ELEM_CLOSE) {
273 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
274 }
Michal Vasko44685da2020-03-17 15:38:06 +0100275 }
276
277 if (key_set.count) {
Michal Vaskob36053d2020-03-26 15:49:30 +0100278 /* some keys are missing/did not validate */
Michal Vasko44685da2020-03-17 15:38:06 +0100279 ret = LY_ENOT;
Michal Vasko44685da2020-03-17 15:38:06 +0100280 }
281
282cleanup:
283 ly_set_erase(&key_set, NULL);
284 return ret;
285}
286
Michal Vasko1bf09392020-03-27 12:38:10 +0100287static LY_ERR
288lydxml_data_skip(struct lyxml_ctx *xmlctx)
289{
290 uint32_t parents_count;
291
292 /* remember current number of parents */
293 parents_count = xmlctx->elements.count;
294
295 /* skip after the content */
296 while (xmlctx->status != LYXML_ELEM_CONTENT) {
297 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
298 }
299 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
300
301 /* skip all children elements, recursively, if any */
302 while (parents_count < xmlctx->elements.count) {
303 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
304 }
305
306 /* close element */
307 assert(xmlctx->status == LYXML_ELEM_CLOSE);
308 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
309
310 return LY_SUCCESS;
311}
312
313static LY_ERR
Radek Krejci1798aae2020-07-14 13:26:06 +0200314lydxml_data_check_opaq(struct lyd_xml_ctx *lydctx, const struct lysc_node **snode)
Michal Vasko1bf09392020-03-27 12:38:10 +0100315{
316 LY_ERR ret = LY_SUCCESS;
317 enum LYXML_PARSER_STATUS prev_status;
Michal Vasko63f3d842020-07-08 10:10:14 +0200318 const char *prev_current, *pname, *pprefix;
Michal Vasko1bf09392020-03-27 12:38:10 +0100319 size_t pprefix_len, pname_len;
320 struct lyxml_ctx *xmlctx = lydctx->xmlctx;
321
Radek IÅ¡a3930fd72021-03-08 10:48:40 +0100322 if (!(lydctx->parse_opts & LYD_PARSE_OPAQ)) {
323 /* only checks specific to opaque nodes */
324 return LY_SUCCESS;
325 }
326
327 if ((*snode)->nodetype & (LYD_NODE_TERM | LYS_LIST)) {
Michal Vasko1bf09392020-03-27 12:38:10 +0100328 /* backup parser */
329 prev_status = xmlctx->status;
330 pprefix = xmlctx->prefix;
331 pprefix_len = xmlctx->prefix_len;
332 pname = xmlctx->name;
333 pname_len = xmlctx->name_len;
Michal Vasko63f3d842020-07-08 10:10:14 +0200334 prev_current = xmlctx->in->current;
Michal Vasko1bf09392020-03-27 12:38:10 +0100335 if ((xmlctx->status == LYXML_ELEM_CONTENT) && xmlctx->dynamic) {
336 /* it was backed up, do not free */
337 xmlctx->dynamic = 0;
338 }
339
340 /* skip attributes */
341 while (xmlctx->status == LYXML_ATTRIBUTE) {
342 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), restore);
343 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), restore);
344 }
345
346 if ((*snode)->nodetype & LYD_NODE_TERM) {
347 /* value may not be valid in which case we parse it as an opaque node */
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200348 if (_lys_value_validate(NULL, *snode, xmlctx->value, xmlctx->value_len, LY_PREF_XML, &xmlctx->ns)) {
Michal Vasko1bf09392020-03-27 12:38:10 +0100349 *snode = NULL;
350 }
351 } else {
352 /* skip content */
353 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), restore);
354
355 if (lydxml_check_list(xmlctx, *snode)) {
356 /* invalid list, parse as opaque if it missing/has invalid some keys */
357 *snode = NULL;
358 }
359 }
360
361restore:
362 /* restore parser */
363 if (xmlctx->dynamic) {
364 free((char *)xmlctx->value);
365 }
366 xmlctx->status = prev_status;
367 xmlctx->prefix = pprefix;
368 xmlctx->prefix_len = pprefix_len;
369 xmlctx->name = pname;
370 xmlctx->name_len = pname_len;
Michal Vasko63f3d842020-07-08 10:10:14 +0200371 xmlctx->in->current = prev_current;
Radek IÅ¡a3930fd72021-03-08 10:48:40 +0100372 } else if ((*snode)->nodetype & LYD_NODE_INNER) {
373 /* if there is a non-WS value, it cannot be parsed as an inner node */
374 assert(xmlctx->status == LYXML_ELEM_CONTENT);
375 if (!xmlctx->ws_only) {
376 *snode = NULL;
377 }
378
Michal Vasko1bf09392020-03-27 12:38:10 +0100379 }
380
381 return ret;
382}
383
Radek Krejcie7b95092019-05-15 11:03:07 +0200384/**
Michal Vaskoa5da3292020-08-12 13:10:50 +0200385 * @brief Parse XML subtree.
Radek Krejcie7b95092019-05-15 11:03:07 +0200386 *
Michal Vaskob36053d2020-03-26 15:49:30 +0100387 * @param[in] lydctx XML YANG data parser context.
Michal Vaskoe0665742021-02-11 11:08:44 +0100388 * @param[in,out] parent Parent node where the children are inserted. NULL in case of parsing top-level elements.
389 * @param[in,out] first_p Pointer to the first (@p parent or top-level) child. In case there were already some siblings,
390 * this may point to a previously existing node.
391 * @param[in,out] parsed Optional set to add all the parsed siblings into.
Michal Vasko9b368d32020-02-14 13:53:31 +0100392 * @return LY_ERR value.
Radek Krejcie7b95092019-05-15 11:03:07 +0200393 */
394static LY_ERR
Michal Vaskoe0665742021-02-11 11:08:44 +0100395lydxml_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 +0200396{
Michal Vaskob36053d2020-03-26 15:49:30 +0100397 LY_ERR ret = LY_SUCCESS;
Michal Vasko27c4dce2021-03-04 15:50:50 +0100398 const char *prefix, *name, *val;
Michal Vasko1bf09392020-03-27 12:38:10 +0100399 size_t prefix_len, name_len;
Michal Vaskob36053d2020-03-26 15:49:30 +0100400 struct lyxml_ctx *xmlctx;
401 const struct ly_ctx *ctx;
Radek Krejcie7b95092019-05-15 11:03:07 +0200402 const struct lyxml_ns *ns;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200403 struct lyd_meta *meta = NULL;
404 struct lyd_attr *attr = NULL;
Radek Krejcie7b95092019-05-15 11:03:07 +0200405 const struct lysc_node *snode;
406 struct lys_module *mod;
Michal Vasko1bf09392020-03-27 12:38:10 +0100407 uint32_t prev_opts;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200408 struct lyd_node *node = NULL, *anchor;
Michal Vaskofc2cd072021-02-24 13:17:17 +0100409 void *val_prefix_data = NULL;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100410 LY_PREFIX_FORMAT format;
Radek Krejci1deb5be2020-08-26 16:43:36 +0200411 uint32_t getnext_opts;
Radek Krejcie7b95092019-05-15 11:03:07 +0200412
Michal Vaskoe0665742021-02-11 11:08:44 +0100413 assert(parent || first_p);
414
Michal Vaskob36053d2020-03-26 15:49:30 +0100415 xmlctx = lydctx->xmlctx;
416 ctx = xmlctx->ctx;
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100417 getnext_opts = lydctx->int_opts & LYD_INTOPT_REPLY ? LYS_GETNEXT_OUTPUT : 0;
Michal Vasko6f4cbb62020-02-28 11:15:47 +0100418
Michal Vaskoa5da3292020-08-12 13:10:50 +0200419 assert(xmlctx->status == LYXML_ELEMENT);
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200420
Michal Vaskoa5da3292020-08-12 13:10:50 +0200421 /* remember element prefix and name */
422 prefix = xmlctx->prefix;
423 prefix_len = xmlctx->prefix_len;
424 name = xmlctx->name;
425 name_len = xmlctx->name_len;
426
427 /* get the element module */
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200428 ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200429 if (!ns) {
Radek Krejci422afb12021-03-04 16:38:16 +0100430 LOGVAL(ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)prefix_len, prefix);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200431 ret = LY_EVALID;
432 goto error;
433 }
434 mod = ly_ctx_get_module_implemented_ns(ctx, ns->uri);
435 if (!mod) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100436 if (lydctx->parse_opts & LYD_PARSE_STRICT) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100437 LOGVAL(ctx, LYVE_REFERENCE, "No module with namespace \"%s\" in the context.", ns->uri);
Michal Vasko90932a92020-02-12 14:33:03 +0100438 ret = LY_EVALID;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200439 goto error;
Radek Krejcie7b95092019-05-15 11:03:07 +0200440 }
Michal Vaskoe0665742021-02-11 11:08:44 +0100441 if (!(lydctx->parse_opts & LYD_PARSE_OPAQ)) {
Michal Vaskoa5da3292020-08-12 13:10:50 +0200442 /* skip element with children */
443 LY_CHECK_GOTO(ret = lydxml_data_skip(xmlctx), error);
444 return LY_SUCCESS;
Radek Krejcie7b95092019-05-15 11:03:07 +0200445 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200446 }
447
Michal Vaskoa5da3292020-08-12 13:10:50 +0200448 /* parser next */
449 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
Michal Vasko90932a92020-02-12 14:33:03 +0100450
Michal Vaskoa5da3292020-08-12 13:10:50 +0200451 /* get the schema node */
452 snode = NULL;
453 if (mod && (!parent || parent->schema)) {
Radek Krejcif16e2542021-02-17 15:39:23 +0100454 if (!parent && lydctx->ext) {
Radek Krejciba05eab2021-03-10 13:19:29 +0100455 snode = lysc_ext_find_node(lydctx->ext, mod, name, name_len, 0, getnext_opts);
Radek Krejcif16e2542021-02-17 15:39:23 +0100456 } else {
457 snode = lys_find_child(parent ? parent->schema : NULL, mod, name, name_len, 0, getnext_opts);
458 }
Michal Vaskoa5da3292020-08-12 13:10:50 +0200459 if (!snode) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100460 if (lydctx->parse_opts & LYD_PARSE_STRICT) {
461 if (parent) {
Radek Krejci422afb12021-03-04 16:38:16 +0100462 LOGVAL(ctx, LYVE_REFERENCE, "Node \"%.*s\" not found as a child of \"%s\" node.",
463 (int)name_len, name, parent->schema->name);
Radek Krejcif16e2542021-02-17 15:39:23 +0100464 } else if (lydctx->ext) {
465 if (lydctx->ext->argument) {
Radek Krejci422afb12021-03-04 16:38:16 +0100466 LOGVAL(ctx, LYVE_REFERENCE, "Node \"%.*s\" not found in the \"%s\" %s extension instance.",
467 (int)name_len, name, lydctx->ext->argument, lydctx->ext->def->name);
Radek Krejcif16e2542021-02-17 15:39:23 +0100468 } else {
Radek Krejci422afb12021-03-04 16:38:16 +0100469 LOGVAL(ctx, LYVE_REFERENCE, "Node \"%.*s\" not found in the %s extension instance.",
470 (int)name_len, name, lydctx->ext->def->name);
Radek Krejcif16e2542021-02-17 15:39:23 +0100471 }
Michal Vaskoe0665742021-02-11 11:08:44 +0100472 } else {
Radek Krejci422afb12021-03-04 16:38:16 +0100473 LOGVAL(ctx, LYVE_REFERENCE, "Node \"%.*s\" not found in the \"%s\" module.",
474 (int)name_len, name, mod->name);
Michal Vaskoe0665742021-02-11 11:08:44 +0100475 }
Michal Vaskoa5da3292020-08-12 13:10:50 +0200476 ret = LY_EVALID;
477 goto error;
Michal Vaskoe0665742021-02-11 11:08:44 +0100478 } else if (!(lydctx->parse_opts & LYD_PARSE_OPAQ)) {
Michal Vaskoa5da3292020-08-12 13:10:50 +0200479 /* skip element with children */
480 LY_CHECK_GOTO(ret = lydxml_data_skip(xmlctx), error);
481 return LY_SUCCESS;
482 }
483 } else {
484 /* check that schema node is valid and can be used */
485 LY_CHECK_GOTO(ret = lyd_parser_check_schema((struct lyd_ctx *)lydctx, snode), error);
486 LY_CHECK_GOTO(ret = lydxml_data_check_opaq(lydctx, &snode), error);
487 }
488 }
489
490 /* create metadata/attributes */
491 if (xmlctx->status == LYXML_ATTRIBUTE) {
492 if (snode) {
Michal Vaskofeca4fb2020-10-05 08:58:40 +0200493 ret = lydxml_metadata(lydctx, &meta);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200494 LY_CHECK_GOTO(ret, error);
495 } else {
Michal Vaskoe0665742021-02-11 11:08:44 +0100496 assert(lydctx->parse_opts & LYD_PARSE_OPAQ);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200497 ret = lydxml_attrs(xmlctx, &attr);
498 LY_CHECK_GOTO(ret, error);
499 }
500 }
501
502 assert(xmlctx->status == LYXML_ELEM_CONTENT);
503 if (!snode) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100504 assert(lydctx->parse_opts & LYD_PARSE_OPAQ);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200505
506 if (xmlctx->ws_only) {
507 /* ignore WS-only value */
Radek IÅ¡a017270d2021-02-16 10:26:15 +0100508 if (xmlctx->dynamic) {
509 free((char *) xmlctx->value);
510 }
511 xmlctx->dynamic = 0;
512 xmlctx->value = "";
Michal Vaskoa5da3292020-08-12 13:10:50 +0200513 xmlctx->value_len = 0;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100514 format = LY_PREF_XML;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200515 } else {
516 /* get value prefixes */
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100517 ret = ly_store_prefix_data(xmlctx->ctx, xmlctx->value, xmlctx->value_len, LY_PREF_XML,
518 &xmlctx->ns, &format, &val_prefix_data);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200519 LY_CHECK_GOTO(ret, error);
520 }
521
522 /* create node */
Michal Vasko501af032020-11-11 20:27:44 +0100523 ret = lyd_create_opaq(ctx, name, name_len, prefix, prefix_len, ns->uri, strlen(ns->uri), xmlctx->value,
524 xmlctx->value_len, &xmlctx->dynamic, format, val_prefix_data, LYD_HINT_DATA, &node);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200525 LY_CHECK_GOTO(ret, error);
526
527 /* parser next */
528 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
529
530 /* process children */
531 while (xmlctx->status == LYXML_ELEMENT) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100532 ret = lydxml_subtree_r(lydctx, node, lyd_node_child_p(node), NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200533 LY_CHECK_GOTO(ret, error);
534 }
535 } else if (snode->nodetype & LYD_NODE_TERM) {
536 /* create node */
Michal Vasko22df3f02020-08-24 13:29:22 +0200537 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 +0200538 &xmlctx->dynamic, LY_PREF_XML, &xmlctx->ns, LYD_HINT_DATA, &node), error);
Radek Krejciddace2c2021-01-08 11:30:56 +0100539 LOG_LOCSET(snode, node, NULL, NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200540
541 if (parent && (node->schema->flags & LYS_KEY)) {
542 /* check the key order, the anchor must never be a key */
Michal Vaskoe0665742021-02-11 11:08:44 +0100543 anchor = lyd_insert_get_next_anchor(lyd_child(parent), node);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200544 if (anchor && (anchor->schema->flags & LYS_KEY)) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100545 if (lydctx->parse_opts & LYD_PARSE_STRICT) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100546 LOGVAL(ctx, LYVE_DATA, "Invalid position of the key \"%s\" in a list.", node->schema->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200547 ret = LY_EVALID;
548 goto error;
549 } else {
550 LOGWRN(ctx, "Invalid position of the key \"%s\" in a list.", node->schema->name);
551 }
552 }
553 }
554
555 /* parser next */
556 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
557
558 /* no children expected */
559 if (xmlctx->status == LYXML_ELEMENT) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100560 LOGVAL(ctx, LYVE_SYNTAX, "Child element \"%.*s\" inside a terminal node \"%s\" found.",
Radek Krejci422afb12021-03-04 16:38:16 +0100561 (int)xmlctx->name_len, xmlctx->name, snode->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200562 ret = LY_EVALID;
563 goto error;
564 }
565 } else if (snode->nodetype & LYD_NODE_INNER) {
566 if (!xmlctx->ws_only) {
567 /* value in inner node */
Radek Krejci2efc45b2020-12-22 16:25:44 +0100568 LOGVAL(ctx, LYVE_SYNTAX, "Text value \"%.*s\" inside an inner node \"%s\" found.",
Radek Krejci422afb12021-03-04 16:38:16 +0100569 (int)xmlctx->value_len, xmlctx->value, snode->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200570 ret = LY_EVALID;
571 goto error;
572 }
573
574 /* create node */
575 ret = lyd_create_inner(snode, &node);
576 LY_CHECK_GOTO(ret, error);
577
Radek Krejciddace2c2021-01-08 11:30:56 +0100578 LOG_LOCSET(snode, node, NULL, NULL);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100579
Michal Vaskoa5da3292020-08-12 13:10:50 +0200580 /* parser next */
581 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
582
583 /* process children */
584 while (xmlctx->status == LYXML_ELEMENT) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100585 ret = lydxml_subtree_r(lydctx, node, lyd_node_child_p(node), NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200586 LY_CHECK_GOTO(ret, error);
587 }
588
589 if (snode->nodetype == LYS_LIST) {
590 /* check all keys exist */
591 LY_CHECK_GOTO(ret = lyd_parse_check_keys(node), error);
592 }
593
Michal Vaskoe0665742021-02-11 11:08:44 +0100594 if (!(lydctx->parse_opts & LYD_PARSE_ONLY)) {
Michal Vaskoa5da3292020-08-12 13:10:50 +0200595 /* new node validation, autodelete CANNOT occur, all nodes are new */
Michal Vaskoe0665742021-02-11 11:08:44 +0100596 ret = lyd_validate_new(lyd_node_child_p(node), snode, NULL, NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200597 LY_CHECK_GOTO(ret, error);
598
599 /* add any missing default children */
Michal Vaskoc43c8ab2021-03-05 13:32:44 +0100600 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 +0100601 (lydctx->val_opts & LYD_VALIDATE_NO_STATE) ? LYD_IMPLICIT_NO_STATE : 0, NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200602 LY_CHECK_GOTO(ret, error);
603 }
604
605 if (snode->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) {
606 /* rememeber the RPC/action/notification */
607 lydctx->op_node = node;
608 }
609 } else if (snode->nodetype & LYD_NODE_ANY) {
Michal Vasko27c4dce2021-03-04 15:50:50 +0100610 if ((snode->nodetype == LYS_ANYDATA) && !xmlctx->ws_only) {
611 /* value in anydata node, we expect a tree */
612 LOGVAL(ctx, LYVE_SYNTAX, "Text value \"%.*s\" inside an anydata node \"%s\" found.",
Radek Krejci422afb12021-03-04 16:38:16 +0100613 (int)xmlctx->value_len < 20 ? xmlctx->value_len : 20, xmlctx->value, snode->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200614 ret = LY_EVALID;
615 goto error;
616 }
617
Michal Vasko27c4dce2021-03-04 15:50:50 +0100618 if (!xmlctx->ws_only) {
619 /* use an arbitrary text value for anyxml */
620 lydict_insert(xmlctx->ctx, xmlctx->value, xmlctx->value_len, &val);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200621
Michal Vasko27c4dce2021-03-04 15:50:50 +0100622 /* parser next */
623 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
624
625 /* create node */
626 ret = lyd_create_any(snode, val, LYD_ANYDATA_STRING, 1, &node);
627 LY_CHECK_GOTO(ret, error);
628 } else {
629 /* parser next */
630 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
631
632 /* parse any data tree with correct options */
633 prev_opts = lydctx->parse_opts;
634 lydctx->parse_opts &= ~LYD_PARSE_STRICT;
635 lydctx->parse_opts |= LYD_PARSE_OPAQ;
636 anchor = NULL;
637 while (xmlctx->status == LYXML_ELEMENT) {
638 ret = lydxml_subtree_r(lydctx, NULL, &anchor, NULL);
639 LY_CHECK_ERR_GOTO(ret, lydctx->parse_opts = prev_opts, error);
640 }
641 lydctx->parse_opts = prev_opts;
642
643 /* create node */
644 ret = lyd_create_any(snode, anchor, LYD_ANYDATA_DATATREE, 1, &node);
645 LY_CHECK_GOTO(ret, error);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200646 }
Michal Vaskoa5da3292020-08-12 13:10:50 +0200647 }
648 assert(node);
649
650 /* add/correct flags */
651 if (snode) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100652 lyd_parse_set_data_flags(node, &lydctx->node_when, &meta, lydctx->parse_opts);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200653 }
654
655 /* parser next */
656 assert(xmlctx->status == LYXML_ELEM_CLOSE);
657 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
658
659 /* add metadata/attributes */
660 if (snode) {
Michal Vasko871a0252020-11-11 18:35:24 +0100661 lyd_insert_meta(node, meta, 0);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200662 } else {
663 lyd_insert_attr(node, attr);
664 }
665
666 /* insert, keep first pointer correct */
Michal Vaskoe0665742021-02-11 11:08:44 +0100667 lyd_insert_node(parent, first_p, node);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200668 while (!parent && (*first_p)->prev->next) {
669 *first_p = (*first_p)->prev;
670 }
671
Michal Vaskoe0665742021-02-11 11:08:44 +0100672 /* rememeber a successfully parsed node */
673 if (parsed) {
674 ly_set_add(parsed, node, 1, NULL);
675 }
676
Radek Krejciddace2c2021-01-08 11:30:56 +0100677 LOG_LOCBACK(node ? 1 : 0, node ? 1 : 0, 0, 0);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200678 return LY_SUCCESS;
679
680error:
Radek Krejciddace2c2021-01-08 11:30:56 +0100681 LOG_LOCBACK(node ? 1 : 0, node ? 1 : 0, 0, 0);
Michal Vasko3a41dff2020-07-15 14:30:28 +0200682 lyd_free_meta_siblings(meta);
Radek Krejci011e4aa2020-09-04 15:22:31 +0200683 lyd_free_attr_siblings(ctx, attr);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200684 lyd_free_tree(node);
Radek Krejcie7b95092019-05-15 11:03:07 +0200685 return ret;
686}
687
Michal Vaskoe0665742021-02-11 11:08:44 +0100688/**
689 * @brief Parse a specific XML element into an opaque node.
690 *
691 * @param[in] xmlctx XML parser context.
692 * @param[in] name Name of the element.
693 * @param[in] uri URI of the element.
694 * @param[in] value Whether a value is expected in the element.
695 * @param[out] evnp Parsed envelope (opaque node).
696 * @return LY_SUCCESS on success.
697 * @return LY_ENOT if the specified element did not match.
698 * @return LY_ERR value on error.
699 */
Michal Vasko1bf09392020-03-27 12:38:10 +0100700static LY_ERR
Michal Vaskoe0665742021-02-11 11:08:44 +0100701lydxml_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 +0100702{
Michal Vaskoe0665742021-02-11 11:08:44 +0100703 LY_ERR rc = LY_SUCCESS;
704 const struct lyxml_ns *ns;
Radek Krejci1798aae2020-07-14 13:26:06 +0200705 struct lyd_attr *attr = NULL;
Michal Vasko1bf09392020-03-27 12:38:10 +0100706 const char *prefix;
707 size_t prefix_len;
708
Michal Vasko1bf09392020-03-27 12:38:10 +0100709 assert(xmlctx->status == LYXML_ELEMENT);
710 if (ly_strncmp(name, xmlctx->name, xmlctx->name_len)) {
711 /* not the expected element */
Michal Vaskoe0665742021-02-11 11:08:44 +0100712 return LY_ENOT;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100713 }
714
715 prefix = xmlctx->prefix;
716 prefix_len = xmlctx->prefix_len;
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200717 ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100718 if (!ns) {
Radek Krejci422afb12021-03-04 16:38:16 +0100719 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)prefix_len, prefix);
Michal Vaskoe0665742021-02-11 11:08:44 +0100720 return LY_EVALID;
721 } else if (strcmp(ns->uri, uri)) {
722 /* different namespace */
723 return LY_ENOT;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100724 }
725
726 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
727
728 /* create attributes */
729 if (xmlctx->status == LYXML_ATTRIBUTE) {
730 LY_CHECK_RET(lydxml_attrs(xmlctx, &attr));
731 }
732
Michal Vaskoe0665742021-02-11 11:08:44 +0100733 assert(xmlctx->status == LYXML_ELEM_CONTENT);
734 if (!value && !xmlctx->ws_only) {
735 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected value \"%.*s\" in the \"%s\" element.",
Radek Krejci422afb12021-03-04 16:38:16 +0100736 (int)xmlctx->value_len, xmlctx->value, name);
Michal Vaskoe0665742021-02-11 11:08:44 +0100737 rc = LY_EVALID;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100738 goto cleanup;
Michal Vaskoe0665742021-02-11 11:08:44 +0100739 }
Michal Vaskoa8edff02020-03-27 14:47:01 +0100740
741 /* create node */
Michal Vaskoe0665742021-02-11 11:08:44 +0100742 rc = lyd_create_opaq(xmlctx->ctx, name, strlen(name), prefix, prefix_len, uri, strlen(uri), xmlctx->value,
743 xmlctx->ws_only ? 0 : xmlctx->value_len, NULL, LY_PREF_XML, NULL, 0, envp);
744 LY_CHECK_GOTO(rc, cleanup);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100745
746 /* assign atributes */
Michal Vaskoe0665742021-02-11 11:08:44 +0100747 ((struct lyd_node_opaq *)(*envp))->attr = attr;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100748 attr = NULL;
749
Michal Vaskoe0665742021-02-11 11:08:44 +0100750 /* parser next element */
751 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100752
Michal Vaskoe0665742021-02-11 11:08:44 +0100753cleanup:
754 lyd_free_attr_siblings(xmlctx->ctx, attr);
755 if (rc) {
756 lyd_free_tree(*envp);
757 *envp = NULL;
758 }
759 return rc;
760}
761
762/**
763 * @brief Parse all expected non-data XML elements of a NETCONF rpc message.
764 *
765 * @param[in] xmlctx XML parser context.
766 * @param[out] evnp Parsed envelope(s) (opaque node).
767 * @param[out] int_opts Internal options for parsing the rest of YANG data.
768 * @param[out] close_elem Number of parsed opened elements that need to be closed.
769 * @return LY_SUCCESS on success.
770 * @return LY_ERR value on error.
771 */
772static LY_ERR
773lydxml_env_netconf_rpc(struct lyxml_ctx *xmlctx, struct lyd_node **envp, uint32_t *int_opts, uint32_t *close_elem)
774{
775 LY_ERR rc = LY_SUCCESS, r;
776 struct lyd_node *child;
777
778 assert(envp && !*envp);
779
780 /* parse "rpc" */
781 r = lydxml_envelope(xmlctx, "rpc", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, envp);
Michal Vaskoe0665742021-02-11 11:08:44 +0100782 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
783
784 /* parse "action", if any */
785 r = lydxml_envelope(xmlctx, "action", "urn:ietf:params:xml:ns:yang:1", 0, &child);
786 if (r == LY_SUCCESS) {
787 /* insert */
788 lyd_insert_node(*envp, NULL, child);
789
790 /* NETCONF action */
791 *int_opts = LYD_INTOPT_NO_SIBLINGS | LYD_INTOPT_ACTION;
792 *close_elem = 2;
793 } else if (r == LY_ENOT) {
794 /* NETCONF RPC */
795 *int_opts = LYD_INTOPT_NO_SIBLINGS | LYD_INTOPT_RPC;
796 *close_elem = 1;
797 } else {
798 rc = r;
799 goto cleanup;
800 }
801
802cleanup:
803 if (rc) {
804 lyd_free_tree(*envp);
805 *envp = NULL;
806 }
807 return rc;
808}
809
810/**
811 * @brief Parse all expected non-data XML elements of a NETCONF notification message.
812 *
813 * @param[in] xmlctx XML parser context.
814 * @param[out] evnp Parsed envelope(s) (opaque node).
815 * @param[out] int_opts Internal options for parsing the rest of YANG data.
816 * @param[out] close_elem Number of parsed opened elements that need to be closed.
817 * @return LY_SUCCESS on success.
818 * @return LY_ERR value on error.
819 */
820static LY_ERR
821lydxml_env_netconf_notif(struct lyxml_ctx *xmlctx, struct lyd_node **envp, uint32_t *int_opts, uint32_t *close_elem)
822{
823 LY_ERR rc = LY_SUCCESS, r;
824 struct lyd_node *child;
825
826 assert(envp && !*envp);
827
828 /* parse "notification" */
829 r = lydxml_envelope(xmlctx, "notification", "urn:ietf:params:xml:ns:netconf:notification:1.0", 0, envp);
Michal Vaskoe0665742021-02-11 11:08:44 +0100830 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
831
832 /* parse "eventTime" */
833 r = lydxml_envelope(xmlctx, "eventTime", "urn:ietf:params:xml:ns:netconf:notification:1.0", 1, &child);
834 if (r == LY_ENOT) {
Radek Krejci422afb12021-03-04 16:38:16 +0100835 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unexpected element \"%.*s\" instead of \"eventTime\".",
836 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +0100837 r = LY_EVALID;
838 }
839 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
840
841 /* insert */
842 lyd_insert_node(*envp, NULL, child);
843
844 /* validate value */
845 /* TODO validate child->value as yang:date-and-time */
846
847 /* finish child parsing */
Michal Vaskoa8edff02020-03-27 14:47:01 +0100848 if (xmlctx->status != LYXML_ELEM_CLOSE) {
849 assert(xmlctx->status == LYXML_ELEMENT);
Michal Vaskoe0665742021-02-11 11:08:44 +0100850 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"eventTime\".",
Radek Krejci422afb12021-03-04 16:38:16 +0100851 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +0100852 rc = LY_EVALID;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100853 goto cleanup;
854 }
Michal Vaskoe0665742021-02-11 11:08:44 +0100855 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
856
857 /* NETCONF notification */
858 *int_opts = LYD_INTOPT_NO_SIBLINGS | LYD_INTOPT_NOTIF;
859 *close_elem = 1;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100860
861cleanup:
Michal Vaskoe0665742021-02-11 11:08:44 +0100862 if (rc) {
Michal Vaskoa8edff02020-03-27 14:47:01 +0100863 lyd_free_tree(*envp);
Michal Vaskoe0665742021-02-11 11:08:44 +0100864 *envp = NULL;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100865 }
Michal Vaskoe0665742021-02-11 11:08:44 +0100866 return rc;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100867}
Michal Vasko79135ae2020-12-16 10:08:35 +0100868
Michal Vaskoe0665742021-02-11 11:08:44 +0100869/**
870 * @brief Parse an XML element as an opaque node subtree.
871 *
872 * @param[in] xmlctx XML parser context.
873 * @param[in] parent Parent to append nodes to.
874 * @return LY_ERR value.
875 */
876static LY_ERR
877lydxml_opaq_r(struct lyxml_ctx *xmlctx, struct lyd_node *parent)
Michal Vaskoa8edff02020-03-27 14:47:01 +0100878{
Michal Vaskoe0665742021-02-11 11:08:44 +0100879 LY_ERR rc = LY_SUCCESS;
880 const struct lyxml_ns *ns;
881 struct lyd_attr *attr = NULL;
882 struct lyd_node *child = NULL;
883 const char *name, *prefix;
884 size_t name_len, prefix_len;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100885
Michal Vaskoe0665742021-02-11 11:08:44 +0100886 assert(xmlctx->status == LYXML_ELEMENT);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100887
Michal Vaskoe0665742021-02-11 11:08:44 +0100888 name = xmlctx->name;
889 name_len = xmlctx->name_len;
890 prefix = xmlctx->prefix;
891 prefix_len = xmlctx->prefix_len;
892 ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
893 if (!ns) {
Radek Krejci422afb12021-03-04 16:38:16 +0100894 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)prefix_len, prefix);
Michal Vaskoe0665742021-02-11 11:08:44 +0100895 return LY_EVALID;
896 }
Michal Vaskoa8edff02020-03-27 14:47:01 +0100897
Michal Vaskoe0665742021-02-11 11:08:44 +0100898 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
Michal Vaskoa8edff02020-03-27 14:47:01 +0100899
Michal Vaskoe0665742021-02-11 11:08:44 +0100900 /* create attributes */
901 if (xmlctx->status == LYXML_ATTRIBUTE) {
902 LY_CHECK_RET(lydxml_attrs(xmlctx, &attr));
903 }
904
905 /* create node */
906 assert(xmlctx->status == LYXML_ELEM_CONTENT);
907 rc = lyd_create_opaq(xmlctx->ctx, name, name_len, prefix, prefix_len, ns->uri, strlen(ns->uri), xmlctx->value,
908 xmlctx->ws_only ? 0 : xmlctx->value_len, NULL, LY_PREF_XML, NULL, 0, &child);
909 LY_CHECK_GOTO(rc, cleanup);
910
911 /* assign atributes */
912 ((struct lyd_node_opaq *)child)->attr = attr;
913 attr = NULL;
914
915 /* parser next element */
916 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
917
918 /* parse all the descendants */
919 while (xmlctx->status == LYXML_ELEMENT) {
920 rc = lydxml_opaq_r(xmlctx, child);
921 LY_CHECK_GOTO(rc, cleanup);
922 }
923
924 /* insert */
925 lyd_insert_node(parent, NULL, child);
926
927cleanup:
928 lyd_free_attr_siblings(xmlctx->ctx, attr);
929 if (rc) {
930 lyd_free_tree(child);
931 }
932 return rc;
933}
934
935/**
936 * @brief Parse all expected non-data XML elements of the error-info element in NETCONF rpc-reply message.
937 *
938 * @param[in] xmlctx XML parser context.
939 * @param[in] parent Parent to append nodes to.
940 * @return LY_ERR value.
941 */
942static LY_ERR
943lydxml_env_netconf_rpc_reply_error_info(struct lyxml_ctx *xmlctx, struct lyd_node *parent)
944{
945 LY_ERR r;
946 struct lyd_node *child, *iter;
947 const struct lyxml_ns *ns;
948 ly_bool no_dup;
949
950 /* there must be some child */
951 if (xmlctx->status == LYXML_ELEM_CLOSE) {
952 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Missing child elements of \"error-info\".");
953 return LY_EVALID;
954 }
955
956 while (xmlctx->status == LYXML_ELEMENT) {
957 child = NULL;
958
959 /*
960 * session-id
961 */
962 r = lydxml_envelope(xmlctx, "session-id", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
963 if (r == LY_SUCCESS) {
964 no_dup = 1;
965 goto check_child;
966 } else if (r != LY_ENOT) {
967 goto error;
968 }
969
970 /*
971 * bad-attribute
972 */
973 r = lydxml_envelope(xmlctx, "bad-attribute", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
974 if (r == LY_SUCCESS) {
975 no_dup = 1;
976 goto check_child;
977 } else if (r != LY_ENOT) {
978 goto error;
979 }
980
981 /*
982 * bad-element
983 */
984 r = lydxml_envelope(xmlctx, "bad-element", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
985 if (r == LY_SUCCESS) {
986 no_dup = 1;
987 goto check_child;
988 } else if (r != LY_ENOT) {
989 goto error;
990 }
991
992 /*
993 * bad-namespace
994 */
995 r = lydxml_envelope(xmlctx, "bad-namespace", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
996 if (r == LY_SUCCESS) {
997 no_dup = 1;
998 goto check_child;
999 } else if (r != LY_ENOT) {
1000 goto error;
1001 }
1002
1003 if (r == LY_ENOT) {
1004 assert(xmlctx->status == LYXML_ELEMENT);
1005
1006 /* learn namespace */
1007 ns = lyxml_ns_get(&xmlctx->ns, xmlctx->prefix, xmlctx->prefix_len);
1008 if (!ns) {
Radek Krejci422afb12021-03-04 16:38:16 +01001009 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)xmlctx->prefix_len, xmlctx->prefix);
Michal Vaskoe0665742021-02-11 11:08:44 +01001010 r = LY_EVALID;
1011 goto error;
1012 } else if (!strcmp(ns->uri, "urn:ietf:params:xml:ns:netconf:base:1.0")) {
1013 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"error-info\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001014 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001015 r = LY_EVALID;
1016 goto error;
1017 }
1018
1019 /* custom elements */
1020 r = lydxml_opaq_r(xmlctx, parent);
1021 LY_CHECK_GOTO(r, error);
1022
1023 no_dup = 0;
1024 }
1025
1026check_child:
1027 /* check for duplicates */
1028 if (no_dup) {
1029 LY_LIST_FOR(lyd_child(parent), iter) {
1030 if ((((struct lyd_node_opaq *)iter)->name.name == ((struct lyd_node_opaq *)child)->name.name) &&
1031 (((struct lyd_node_opaq *)iter)->name.module_ns == ((struct lyd_node_opaq *)child)->name.module_ns)) {
1032 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Duplicate element \"%s\" in \"error-info\".",
1033 ((struct lyd_node_opaq *)child)->name.name);
1034 r = LY_EVALID;
1035 goto error;
1036 }
1037 }
1038 }
1039
1040 /* finish child parsing */
1041 if (xmlctx->status != LYXML_ELEM_CLOSE) {
1042 assert(xmlctx->status == LYXML_ELEMENT);
1043 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"error-info\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001044 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001045 r = LY_EVALID;
1046 goto error;
1047 }
1048 LY_CHECK_GOTO(r = lyxml_ctx_next(xmlctx), error);
1049
1050 /* insert */
1051 lyd_insert_node(parent, NULL, child);
1052 }
1053
1054 return LY_SUCCESS;
1055
1056error:
1057 lyd_free_tree(child);
1058 return r;
1059}
1060
1061/**
1062 * @brief Parse all expected non-data XML elements of the rpc-error element in NETCONF rpc-reply message.
1063 *
1064 * @param[in] xmlctx XML parser context.
1065 * @param[in] parent Parent to append nodes to.
1066 * @return LY_ERR value.
1067 */
1068static LY_ERR
1069lydxml_env_netconf_rpc_reply_error(struct lyxml_ctx *xmlctx, struct lyd_node *parent)
1070{
1071 LY_ERR r;
1072 struct lyd_node *child, *iter;
1073 const char *val;
1074 ly_bool no_dup;
1075
1076 /* there must be some child */
1077 if (xmlctx->status == LYXML_ELEM_CLOSE) {
1078 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Missing child elements of \"rpc-error\".");
1079 return LY_EVALID;
1080 }
1081
1082 while (xmlctx->status == LYXML_ELEMENT) {
1083 child = NULL;
1084
1085 /*
1086 * error-type
1087 */
1088 r = lydxml_envelope(xmlctx, "error-type", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1089 if (r == LY_SUCCESS) {
1090 val = ((struct lyd_node_opaq *)child)->value;
1091 if (strcmp(val, "transport") && strcmp(val, "rpc") && strcmp(val, "protocol") && strcmp(val, "application")) {
1092 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Invalid value \"%s\" of element \"%s\".", val,
1093 ((struct lyd_node_opaq *)child)->name.name);
1094 r = LY_EVALID;
1095 goto error;
1096 }
1097
1098 no_dup = 1;
1099 goto check_child;
1100 } else if (r != LY_ENOT) {
1101 goto error;
1102 }
1103
1104 /*
1105 * error-tag
1106 */
1107 r = lydxml_envelope(xmlctx, "error-tag", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1108 if (r == LY_SUCCESS) {
1109 val = ((struct lyd_node_opaq *)child)->value;
1110 if (strcmp(val, "in-use") && strcmp(val, "invalid-value") && strcmp(val, "too-big") &&
1111 strcmp(val, "missing-attribute") && strcmp(val, "bad-attribute") &&
1112 strcmp(val, "unknown-attribute") && strcmp(val, "missing-element") && strcmp(val, "bad-element") &&
1113 strcmp(val, "unknown-element") && strcmp(val, "unknown-namespace") && strcmp(val, "access-denied") &&
1114 strcmp(val, "lock-denied") && strcmp(val, "resource-denied") && strcmp(val, "rollback-failed") &&
1115 strcmp(val, "data-exists") && strcmp(val, "data-missing") && strcmp(val, "operation-not-supported") &&
1116 strcmp(val, "operation-failed") && strcmp(val, "malformed-message")) {
1117 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Invalid value \"%s\" of element \"%s\".", val,
1118 ((struct lyd_node_opaq *)child)->name.name);
1119 r = LY_EVALID;
1120 goto error;
1121 }
1122
1123 no_dup = 1;
1124 goto check_child;
1125 } else if (r != LY_ENOT) {
1126 goto error;
1127 }
1128
1129 /*
1130 * error-severity
1131 */
1132 r = lydxml_envelope(xmlctx, "error-severity", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1133 if (r == LY_SUCCESS) {
1134 val = ((struct lyd_node_opaq *)child)->value;
1135 if (strcmp(val, "error") && strcmp(val, "warning")) {
1136 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Invalid value \"%s\" of element \"%s\".", val,
1137 ((struct lyd_node_opaq *)child)->name.name);
1138 r = LY_EVALID;
1139 goto error;
1140 }
1141
1142 no_dup = 1;
1143 goto check_child;
1144 } else if (r != LY_ENOT) {
1145 goto error;
1146 }
1147
1148 /*
1149 * error-app-tag
1150 */
1151 r = lydxml_envelope(xmlctx, "error-app-tag", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1152 if (r == LY_SUCCESS) {
1153 no_dup = 1;
1154 goto check_child;
1155 } else if (r != LY_ENOT) {
1156 goto error;
1157 }
1158
1159 /*
1160 * error-path
1161 */
1162 r = lydxml_envelope(xmlctx, "error-path", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1163 if (r == LY_SUCCESS) {
1164 no_dup = 1;
1165 goto check_child;
1166 } else if (r != LY_ENOT) {
1167 goto error;
1168 }
1169
1170 /*
1171 * error-message
1172 */
1173 r = lydxml_envelope(xmlctx, "error-message", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1174 if (r == LY_SUCCESS) {
1175 no_dup = 1;
1176 goto check_child;
1177 } else if (r != LY_ENOT) {
1178 goto error;
1179 }
1180
1181 /* error-info */
1182 r = lydxml_envelope(xmlctx, "error-info", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, &child);
1183 if (r == LY_SUCCESS) {
1184 /* parse all the descendants */
1185 LY_CHECK_GOTO(r = lydxml_env_netconf_rpc_reply_error_info(xmlctx, child), error);
1186
1187 no_dup = 0;
1188 goto check_child;
1189 } else if (r != LY_ENOT) {
1190 goto error;
1191 }
1192
1193 if (r == LY_ENOT) {
1194 assert(xmlctx->status == LYXML_ELEMENT);
1195 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"rpc-error\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001196 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001197 r = LY_EVALID;
1198 goto error;
1199 }
1200
1201check_child:
1202 /* check for duplicates */
1203 if (no_dup) {
1204 LY_LIST_FOR(lyd_child(parent), iter) {
1205 if ((((struct lyd_node_opaq *)iter)->name.name == ((struct lyd_node_opaq *)child)->name.name) &&
1206 (((struct lyd_node_opaq *)iter)->name.module_ns == ((struct lyd_node_opaq *)child)->name.module_ns)) {
1207 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Duplicate element \"%s\" in \"rpc-error\".",
1208 ((struct lyd_node_opaq *)child)->name.name);
1209 r = LY_EVALID;
1210 goto error;
1211 }
1212 }
1213 }
1214
1215 /* finish child parsing */
1216 if (xmlctx->status != LYXML_ELEM_CLOSE) {
1217 assert(xmlctx->status == LYXML_ELEMENT);
1218 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"rpc-error\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001219 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001220 r = LY_EVALID;
1221 goto error;
1222 }
1223 LY_CHECK_GOTO(r = lyxml_ctx_next(xmlctx), error);
1224
1225 /* insert */
1226 lyd_insert_node(parent, NULL, child);
1227 }
1228
1229 return LY_SUCCESS;
1230
1231error:
1232 lyd_free_tree(child);
1233 return r;
1234}
1235
1236/**
1237 * @brief Parse all expected non-data XML elements of a NETCONF rpc-reply message.
1238 *
1239 * @param[in] xmlctx XML parser context.
1240 * @param[out] evnp Parsed envelope(s) (opaque node).
1241 * @param[out] int_opts Internal options for parsing the rest of YANG data.
1242 * @param[out] close_elem Number of parsed opened elements that need to be closed.
1243 * @return LY_SUCCESS on success.
1244 * @return LY_ERR value on error.
1245 */
1246static LY_ERR
1247lydxml_env_netconf_reply(struct lyxml_ctx *xmlctx, struct lyd_node **envp, uint32_t *int_opts, uint32_t *close_elem)
1248{
1249 LY_ERR rc = LY_SUCCESS, r;
1250 struct lyd_node *child = NULL;
1251 const char *parsed_elem = NULL;
1252
1253 assert(envp && !*envp);
1254
1255 /* parse "rpc-reply" */
1256 r = lydxml_envelope(xmlctx, "rpc-reply", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, envp);
Michal Vaskoe0665742021-02-11 11:08:44 +01001257 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
1258
1259 /* there must be some child */
1260 if (xmlctx->status == LYXML_ELEM_CLOSE) {
1261 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Missing child elements of \"rpc-reply\".");
1262 rc = LY_EVALID;
Michal Vaskocf770e22020-08-12 13:21:43 +02001263 goto cleanup;
Michal Vaskoa8edff02020-03-27 14:47:01 +01001264 }
1265
Michal Vaskoe0665742021-02-11 11:08:44 +01001266 /* try to parse "ok" */
1267 r = lydxml_envelope(xmlctx, "ok", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, &child);
1268 if (r == LY_SUCCESS) {
1269 /* insert */
1270 lyd_insert_node(*envp, NULL, child);
1271
1272 /* finish child parsing */
1273 if (xmlctx->status != LYXML_ELEM_CLOSE) {
1274 assert(xmlctx->status == LYXML_ELEMENT);
1275 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"ok\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001276 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001277 rc = LY_EVALID;
1278 goto cleanup;
1279 }
1280 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
1281
1282 /* success */
1283 parsed_elem = "ok";
1284 goto finish;
1285 } else if (r != LY_ENOT) {
1286 rc = r;
1287 goto cleanup;
Michal Vasko2552ea32020-12-08 15:32:34 +01001288 }
1289
Michal Vaskoe0665742021-02-11 11:08:44 +01001290 /* try to parse all "rpc-error" elements */
1291 while (xmlctx->status == LYXML_ELEMENT) {
1292 r = lydxml_envelope(xmlctx, "rpc-error", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, &child);
1293 if (r == LY_ENOT) {
1294 break;
1295 } else if (r) {
1296 rc = r;
1297 goto cleanup;
1298 }
1299
1300 /* insert */
1301 lyd_insert_node(*envp, NULL, child);
1302
1303 /* parse all children of "rpc-error" */
1304 LY_CHECK_GOTO(rc = lydxml_env_netconf_rpc_reply_error(xmlctx, child), cleanup);
1305
1306 /* finish child parsing */
1307 assert(xmlctx->status == LYXML_ELEM_CLOSE);
1308 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
1309
1310 parsed_elem = "rpc-error";
Michal Vasko2552ea32020-12-08 15:32:34 +01001311 }
Michal Vaskoe0665742021-02-11 11:08:44 +01001312
1313finish:
1314 if (parsed_elem) {
1315 /* NETCONF rpc-reply with no data */
1316 if (xmlctx->status != LYXML_ELEM_CLOSE) {
1317 assert(xmlctx->status == LYXML_ELEMENT);
1318 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected sibling element \"%.*s\" of \"%s\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001319 (int)xmlctx->name_len, xmlctx->name, parsed_elem);
Michal Vaskoe0665742021-02-11 11:08:44 +01001320 rc = LY_EVALID;
1321 goto cleanup;
1322 }
1323 }
1324
1325 /* NETCONF rpc-reply */
1326 *int_opts = LYD_INTOPT_NO_SIBLINGS | LYD_INTOPT_REPLY;
1327 *close_elem = 1;
1328
1329cleanup:
1330 if (rc) {
1331 lyd_free_tree(*envp);
1332 *envp = NULL;
1333 }
1334 return rc;
1335}
1336
Michal Vasko2552ea32020-12-08 15:32:34 +01001337LY_ERR
Radek Krejcif16e2542021-02-17 15:39:23 +01001338lyd_parse_xml(const struct ly_ctx *ctx, const struct lysc_ext_instance *ext, struct lyd_node *parent,
1339 struct lyd_node **first_p, struct ly_in *in, uint32_t parse_opts, uint32_t val_opts, enum lyd_type data_type,
1340 struct lyd_node **envp, struct ly_set *parsed, struct lyd_ctx **lydctx_p)
Michal Vasko2552ea32020-12-08 15:32:34 +01001341{
Michal Vaskoe0665742021-02-11 11:08:44 +01001342 LY_ERR rc = LY_SUCCESS;
1343 struct lyd_xml_ctx *lydctx;
1344 uint32_t i, int_opts, close_elem = 0;
1345 ly_bool parsed_data_nodes = 0;
Michal Vasko2552ea32020-12-08 15:32:34 +01001346
Michal Vaskoe0665742021-02-11 11:08:44 +01001347 assert(ctx && in && lydctx_p);
1348 assert(!(parse_opts & ~LYD_PARSE_OPTS_MASK));
1349 assert(!(val_opts & ~LYD_VALIDATE_OPTS_MASK));
Michal Vasko2552ea32020-12-08 15:32:34 +01001350
Michal Vaskoe0665742021-02-11 11:08:44 +01001351 /* init context */
1352 lydctx = calloc(1, sizeof *lydctx);
1353 LY_CHECK_ERR_RET(!lydctx, LOGMEM(ctx), LY_EMEM);
1354 LY_CHECK_GOTO(rc = lyxml_ctx_new(ctx, in, &lydctx->xmlctx), cleanup);
1355 lydctx->parse_opts = parse_opts;
1356 lydctx->val_opts = val_opts;
1357 lydctx->free = lyd_xml_ctx_free;
Radek Krejcif16e2542021-02-17 15:39:23 +01001358 lydctx->ext = ext;
Michal Vasko2552ea32020-12-08 15:32:34 +01001359
Michal Vaskoe0665742021-02-11 11:08:44 +01001360 switch (data_type) {
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001361 case LYD_TYPE_DATA_YANG:
Michal Vaskoe0665742021-02-11 11:08:44 +01001362 int_opts = LYD_INTOPT_WITH_SIBLINGS;
1363 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001364 case LYD_TYPE_RPC_YANG:
Michal Vaskoe0665742021-02-11 11:08:44 +01001365 int_opts = LYD_INTOPT_RPC | LYD_INTOPT_ACTION | LYD_INTOPT_NO_SIBLINGS;
1366 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001367 case LYD_TYPE_NOTIF_YANG:
Michal Vaskoe0665742021-02-11 11:08:44 +01001368 int_opts = LYD_INTOPT_NOTIF | LYD_INTOPT_NO_SIBLINGS;
1369 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001370 case LYD_TYPE_REPLY_YANG:
Michal Vaskoe0665742021-02-11 11:08:44 +01001371 int_opts = LYD_INTOPT_REPLY | LYD_INTOPT_NO_SIBLINGS;
1372 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001373 case LYD_TYPE_RPC_NETCONF:
Michal Vaskoe0665742021-02-11 11:08:44 +01001374 assert(!parent);
1375 LY_CHECK_GOTO(rc = lydxml_env_netconf_rpc(lydctx->xmlctx, envp, &int_opts, &close_elem), cleanup);
1376 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001377 case LYD_TYPE_NOTIF_NETCONF:
1378 assert(!parent);
1379 LY_CHECK_GOTO(rc = lydxml_env_netconf_notif(lydctx->xmlctx, envp, &int_opts, &close_elem), cleanup);
1380 break;
1381 case LYD_TYPE_REPLY_NETCONF:
Michal Vaskoe0665742021-02-11 11:08:44 +01001382 assert(parent);
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001383 LY_CHECK_GOTO(rc = lydxml_env_netconf_reply(lydctx->xmlctx, envp, &int_opts, &close_elem), cleanup);
Michal Vaskoe0665742021-02-11 11:08:44 +01001384 break;
1385 }
1386 lydctx->int_opts = int_opts;
1387
1388 /* find the operation node if it exists already */
1389 LY_CHECK_GOTO(rc = lyd_parser_find_operation(parent, int_opts, &lydctx->op_node), cleanup);
1390
1391 /* parse XML data */
1392 while (lydctx->xmlctx->status == LYXML_ELEMENT) {
1393 LY_CHECK_GOTO(rc = lydxml_subtree_r(lydctx, parent, first_p, parsed), cleanup);
1394 parsed_data_nodes = 1;
1395
1396 if (!(int_opts & LYD_INTOPT_WITH_SIBLINGS)) {
1397 break;
1398 }
Michal Vasko2552ea32020-12-08 15:32:34 +01001399 }
1400
Michal Vaskoe0665742021-02-11 11:08:44 +01001401 /* close all opened elements */
1402 for (i = 0; i < close_elem; ++i) {
1403 if (lydctx->xmlctx->status != LYXML_ELEM_CLOSE) {
1404 assert(lydctx->xmlctx->status == LYXML_ELEMENT);
Radek Krejci422afb12021-03-04 16:38:16 +01001405 LOGVAL(lydctx->xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\".",
1406 (int)lydctx->xmlctx->name_len, lydctx->xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001407 rc = LY_EVALID;
1408 goto cleanup;
1409 }
1410
1411 LY_CHECK_GOTO(rc = lyxml_ctx_next(lydctx->xmlctx), cleanup);
Michal Vasko4189c0f2020-08-13 09:05:22 +02001412 }
Michal Vaskoe0665742021-02-11 11:08:44 +01001413
1414 /* check final state */
1415 if ((int_opts & LYD_INTOPT_NO_SIBLINGS) && (lydctx->xmlctx->status == LYXML_ELEMENT)) {
1416 LOGVAL(ctx, LYVE_SYNTAX, "Unexpected sibling node.");
1417 rc = LY_EVALID;
1418 goto cleanup;
1419 }
1420 if ((int_opts & (LYD_INTOPT_RPC | LYD_INTOPT_NOTIF | LYD_INTOPT_REPLY)) && !lydctx->op_node) {
1421 LOGVAL(ctx, LYVE_DATA, "Missing the operation node.");
1422 rc = LY_EVALID;
1423 goto cleanup;
1424 }
1425
1426 if (!parsed_data_nodes) {
1427 /* no data nodes were parsed */
1428 lydctx->op_node = NULL;
Michal Vaskoa8edff02020-03-27 14:47:01 +01001429 }
1430
1431cleanup:
Michal Vaskoe0665742021-02-11 11:08:44 +01001432 /* there should be no unres stored if validation should be skipped */
1433 assert(!(parse_opts & LYD_PARSE_ONLY) || (!lydctx->node_types.count && !lydctx->meta_types.count &&
1434 !lydctx->node_when.count));
1435
1436 if (rc) {
1437 lyd_xml_ctx_free((struct lyd_ctx *)lydctx);
1438 } else {
1439 *lydctx_p = (struct lyd_ctx *)lydctx;
1440
1441 /* the XML context is no more needed, freeing it also stops logging line numbers which would be confusing now */
1442 lyxml_ctx_free(lydctx->xmlctx);
1443 lydctx->xmlctx = NULL;
Michal Vasko1ce933a2020-03-30 12:38:22 +02001444 }
Michal Vaskoe0665742021-02-11 11:08:44 +01001445 return rc;
Michal Vasko1ce933a2020-03-30 12:38:22 +02001446}