blob: f5bfc150b3a13978b6f9129fb2c879962005833a [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
Michal Vaskoe0665742021-02-11 11:08:44 +0100322 if ((lydctx->parse_opts & LYD_PARSE_OPAQ) && ((*snode)->nodetype & (LYD_NODE_TERM | LYS_LIST))) {
Michal Vasko1bf09392020-03-27 12:38:10 +0100323 /* backup parser */
324 prev_status = xmlctx->status;
325 pprefix = xmlctx->prefix;
326 pprefix_len = xmlctx->prefix_len;
327 pname = xmlctx->name;
328 pname_len = xmlctx->name_len;
Michal Vasko63f3d842020-07-08 10:10:14 +0200329 prev_current = xmlctx->in->current;
Michal Vasko1bf09392020-03-27 12:38:10 +0100330 if ((xmlctx->status == LYXML_ELEM_CONTENT) && xmlctx->dynamic) {
331 /* it was backed up, do not free */
332 xmlctx->dynamic = 0;
333 }
334
335 /* skip attributes */
336 while (xmlctx->status == LYXML_ATTRIBUTE) {
337 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), restore);
338 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), restore);
339 }
340
341 if ((*snode)->nodetype & LYD_NODE_TERM) {
342 /* value may not be valid in which case we parse it as an opaque node */
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200343 if (_lys_value_validate(NULL, *snode, xmlctx->value, xmlctx->value_len, LY_PREF_XML, &xmlctx->ns)) {
Michal Vasko1bf09392020-03-27 12:38:10 +0100344 *snode = NULL;
345 }
346 } else {
347 /* skip content */
348 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), restore);
349
350 if (lydxml_check_list(xmlctx, *snode)) {
351 /* invalid list, parse as opaque if it missing/has invalid some keys */
352 *snode = NULL;
353 }
354 }
355
356restore:
357 /* restore parser */
358 if (xmlctx->dynamic) {
359 free((char *)xmlctx->value);
360 }
361 xmlctx->status = prev_status;
362 xmlctx->prefix = pprefix;
363 xmlctx->prefix_len = pprefix_len;
364 xmlctx->name = pname;
365 xmlctx->name_len = pname_len;
Michal Vasko63f3d842020-07-08 10:10:14 +0200366 xmlctx->in->current = prev_current;
Michal Vasko1bf09392020-03-27 12:38:10 +0100367 }
368
369 return ret;
370}
371
Radek Krejcie7b95092019-05-15 11:03:07 +0200372/**
Michal Vaskoa5da3292020-08-12 13:10:50 +0200373 * @brief Parse XML subtree.
Radek Krejcie7b95092019-05-15 11:03:07 +0200374 *
Michal Vaskob36053d2020-03-26 15:49:30 +0100375 * @param[in] lydctx XML YANG data parser context.
Michal Vaskoe0665742021-02-11 11:08:44 +0100376 * @param[in,out] parent Parent node where the children are inserted. NULL in case of parsing top-level elements.
377 * @param[in,out] first_p Pointer to the first (@p parent or top-level) child. In case there were already some siblings,
378 * this may point to a previously existing node.
379 * @param[in,out] parsed Optional set to add all the parsed siblings into.
Michal Vasko9b368d32020-02-14 13:53:31 +0100380 * @return LY_ERR value.
Radek Krejcie7b95092019-05-15 11:03:07 +0200381 */
382static LY_ERR
Michal Vaskoe0665742021-02-11 11:08:44 +0100383lydxml_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 +0200384{
Michal Vaskob36053d2020-03-26 15:49:30 +0100385 LY_ERR ret = LY_SUCCESS;
Michal Vasko27c4dce2021-03-04 15:50:50 +0100386 const char *prefix, *name, *val;
Michal Vasko1bf09392020-03-27 12:38:10 +0100387 size_t prefix_len, name_len;
Michal Vaskob36053d2020-03-26 15:49:30 +0100388 struct lyxml_ctx *xmlctx;
389 const struct ly_ctx *ctx;
Radek Krejcie7b95092019-05-15 11:03:07 +0200390 const struct lyxml_ns *ns;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200391 struct lyd_meta *meta = NULL;
392 struct lyd_attr *attr = NULL;
Radek Krejcie7b95092019-05-15 11:03:07 +0200393 const struct lysc_node *snode;
394 struct lys_module *mod;
Michal Vasko1bf09392020-03-27 12:38:10 +0100395 uint32_t prev_opts;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200396 struct lyd_node *node = NULL, *anchor;
Michal Vaskofc2cd072021-02-24 13:17:17 +0100397 void *val_prefix_data = NULL;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100398 LY_PREFIX_FORMAT format;
Radek Krejci1deb5be2020-08-26 16:43:36 +0200399 uint32_t getnext_opts;
Radek Krejcie7b95092019-05-15 11:03:07 +0200400
Michal Vaskoe0665742021-02-11 11:08:44 +0100401 assert(parent || first_p);
402
Michal Vaskob36053d2020-03-26 15:49:30 +0100403 xmlctx = lydctx->xmlctx;
404 ctx = xmlctx->ctx;
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100405 getnext_opts = lydctx->int_opts & LYD_INTOPT_REPLY ? LYS_GETNEXT_OUTPUT : 0;
Michal Vasko6f4cbb62020-02-28 11:15:47 +0100406
Michal Vaskoa5da3292020-08-12 13:10:50 +0200407 assert(xmlctx->status == LYXML_ELEMENT);
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200408
Michal Vaskoa5da3292020-08-12 13:10:50 +0200409 /* remember element prefix and name */
410 prefix = xmlctx->prefix;
411 prefix_len = xmlctx->prefix_len;
412 name = xmlctx->name;
413 name_len = xmlctx->name_len;
414
415 /* get the element module */
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200416 ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200417 if (!ns) {
Radek Krejci422afb12021-03-04 16:38:16 +0100418 LOGVAL(ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)prefix_len, prefix);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200419 ret = LY_EVALID;
420 goto error;
421 }
422 mod = ly_ctx_get_module_implemented_ns(ctx, ns->uri);
423 if (!mod) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100424 if (lydctx->parse_opts & LYD_PARSE_STRICT) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100425 LOGVAL(ctx, LYVE_REFERENCE, "No module with namespace \"%s\" in the context.", ns->uri);
Michal Vasko90932a92020-02-12 14:33:03 +0100426 ret = LY_EVALID;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200427 goto error;
Radek Krejcie7b95092019-05-15 11:03:07 +0200428 }
Michal Vaskoe0665742021-02-11 11:08:44 +0100429 if (!(lydctx->parse_opts & LYD_PARSE_OPAQ)) {
Michal Vaskoa5da3292020-08-12 13:10:50 +0200430 /* skip element with children */
431 LY_CHECK_GOTO(ret = lydxml_data_skip(xmlctx), error);
432 return LY_SUCCESS;
Radek Krejcie7b95092019-05-15 11:03:07 +0200433 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200434 }
435
Michal Vaskoa5da3292020-08-12 13:10:50 +0200436 /* parser next */
437 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
Michal Vasko90932a92020-02-12 14:33:03 +0100438
Michal Vaskoa5da3292020-08-12 13:10:50 +0200439 /* get the schema node */
440 snode = NULL;
441 if (mod && (!parent || parent->schema)) {
Radek Krejcif16e2542021-02-17 15:39:23 +0100442 if (!parent && lydctx->ext) {
Radek Krejciba05eab2021-03-10 13:19:29 +0100443 snode = lysc_ext_find_node(lydctx->ext, mod, name, name_len, 0, getnext_opts);
Radek Krejcif16e2542021-02-17 15:39:23 +0100444 } else {
445 snode = lys_find_child(parent ? parent->schema : NULL, mod, name, name_len, 0, getnext_opts);
446 }
Michal Vaskoa5da3292020-08-12 13:10:50 +0200447 if (!snode) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100448 if (lydctx->parse_opts & LYD_PARSE_STRICT) {
449 if (parent) {
Radek Krejci422afb12021-03-04 16:38:16 +0100450 LOGVAL(ctx, LYVE_REFERENCE, "Node \"%.*s\" not found as a child of \"%s\" node.",
451 (int)name_len, name, parent->schema->name);
Radek Krejcif16e2542021-02-17 15:39:23 +0100452 } else if (lydctx->ext) {
453 if (lydctx->ext->argument) {
Radek Krejci422afb12021-03-04 16:38:16 +0100454 LOGVAL(ctx, LYVE_REFERENCE, "Node \"%.*s\" not found in the \"%s\" %s extension instance.",
455 (int)name_len, name, lydctx->ext->argument, lydctx->ext->def->name);
Radek Krejcif16e2542021-02-17 15:39:23 +0100456 } else {
Radek Krejci422afb12021-03-04 16:38:16 +0100457 LOGVAL(ctx, LYVE_REFERENCE, "Node \"%.*s\" not found in the %s extension instance.",
458 (int)name_len, name, lydctx->ext->def->name);
Radek Krejcif16e2542021-02-17 15:39:23 +0100459 }
Michal Vaskoe0665742021-02-11 11:08:44 +0100460 } else {
Radek Krejci422afb12021-03-04 16:38:16 +0100461 LOGVAL(ctx, LYVE_REFERENCE, "Node \"%.*s\" not found in the \"%s\" module.",
462 (int)name_len, name, mod->name);
Michal Vaskoe0665742021-02-11 11:08:44 +0100463 }
Michal Vaskoa5da3292020-08-12 13:10:50 +0200464 ret = LY_EVALID;
465 goto error;
Michal Vaskoe0665742021-02-11 11:08:44 +0100466 } else if (!(lydctx->parse_opts & LYD_PARSE_OPAQ)) {
Michal Vaskoa5da3292020-08-12 13:10:50 +0200467 /* skip element with children */
468 LY_CHECK_GOTO(ret = lydxml_data_skip(xmlctx), error);
469 return LY_SUCCESS;
470 }
471 } else {
472 /* check that schema node is valid and can be used */
473 LY_CHECK_GOTO(ret = lyd_parser_check_schema((struct lyd_ctx *)lydctx, snode), error);
474 LY_CHECK_GOTO(ret = lydxml_data_check_opaq(lydctx, &snode), error);
475 }
476 }
477
478 /* create metadata/attributes */
479 if (xmlctx->status == LYXML_ATTRIBUTE) {
480 if (snode) {
Michal Vaskofeca4fb2020-10-05 08:58:40 +0200481 ret = lydxml_metadata(lydctx, &meta);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200482 LY_CHECK_GOTO(ret, error);
483 } else {
Michal Vaskoe0665742021-02-11 11:08:44 +0100484 assert(lydctx->parse_opts & LYD_PARSE_OPAQ);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200485 ret = lydxml_attrs(xmlctx, &attr);
486 LY_CHECK_GOTO(ret, error);
487 }
488 }
489
490 assert(xmlctx->status == LYXML_ELEM_CONTENT);
491 if (!snode) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100492 assert(lydctx->parse_opts & LYD_PARSE_OPAQ);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200493
494 if (xmlctx->ws_only) {
495 /* ignore WS-only value */
Radek IÅ¡a017270d2021-02-16 10:26:15 +0100496 if (xmlctx->dynamic) {
497 free((char *) xmlctx->value);
498 }
499 xmlctx->dynamic = 0;
500 xmlctx->value = "";
Michal Vaskoa5da3292020-08-12 13:10:50 +0200501 xmlctx->value_len = 0;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100502 format = LY_PREF_XML;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200503 } else {
504 /* get value prefixes */
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100505 ret = ly_store_prefix_data(xmlctx->ctx, xmlctx->value, xmlctx->value_len, LY_PREF_XML,
506 &xmlctx->ns, &format, &val_prefix_data);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200507 LY_CHECK_GOTO(ret, error);
508 }
509
510 /* create node */
Michal Vasko501af032020-11-11 20:27:44 +0100511 ret = lyd_create_opaq(ctx, name, name_len, prefix, prefix_len, ns->uri, strlen(ns->uri), xmlctx->value,
512 xmlctx->value_len, &xmlctx->dynamic, format, val_prefix_data, LYD_HINT_DATA, &node);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200513 LY_CHECK_GOTO(ret, error);
514
515 /* parser next */
516 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
517
518 /* process children */
519 while (xmlctx->status == LYXML_ELEMENT) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100520 ret = lydxml_subtree_r(lydctx, node, lyd_node_child_p(node), NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200521 LY_CHECK_GOTO(ret, error);
522 }
523 } else if (snode->nodetype & LYD_NODE_TERM) {
524 /* create node */
Michal Vasko22df3f02020-08-24 13:29:22 +0200525 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 +0200526 &xmlctx->dynamic, LY_PREF_XML, &xmlctx->ns, LYD_HINT_DATA, &node), error);
Radek Krejciddace2c2021-01-08 11:30:56 +0100527 LOG_LOCSET(snode, node, NULL, NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200528
529 if (parent && (node->schema->flags & LYS_KEY)) {
530 /* check the key order, the anchor must never be a key */
Michal Vaskoe0665742021-02-11 11:08:44 +0100531 anchor = lyd_insert_get_next_anchor(lyd_child(parent), node);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200532 if (anchor && (anchor->schema->flags & LYS_KEY)) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100533 if (lydctx->parse_opts & LYD_PARSE_STRICT) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100534 LOGVAL(ctx, LYVE_DATA, "Invalid position of the key \"%s\" in a list.", node->schema->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200535 ret = LY_EVALID;
536 goto error;
537 } else {
538 LOGWRN(ctx, "Invalid position of the key \"%s\" in a list.", node->schema->name);
539 }
540 }
541 }
542
543 /* parser next */
544 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
545
546 /* no children expected */
547 if (xmlctx->status == LYXML_ELEMENT) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100548 LOGVAL(ctx, LYVE_SYNTAX, "Child element \"%.*s\" inside a terminal node \"%s\" found.",
Radek Krejci422afb12021-03-04 16:38:16 +0100549 (int)xmlctx->name_len, xmlctx->name, snode->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200550 ret = LY_EVALID;
551 goto error;
552 }
553 } else if (snode->nodetype & LYD_NODE_INNER) {
554 if (!xmlctx->ws_only) {
555 /* value in inner node */
Radek Krejci2efc45b2020-12-22 16:25:44 +0100556 LOGVAL(ctx, LYVE_SYNTAX, "Text value \"%.*s\" inside an inner node \"%s\" found.",
Radek Krejci422afb12021-03-04 16:38:16 +0100557 (int)xmlctx->value_len, xmlctx->value, snode->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200558 ret = LY_EVALID;
559 goto error;
560 }
561
562 /* create node */
563 ret = lyd_create_inner(snode, &node);
564 LY_CHECK_GOTO(ret, error);
565
Radek Krejciddace2c2021-01-08 11:30:56 +0100566 LOG_LOCSET(snode, node, NULL, NULL);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100567
Michal Vaskoa5da3292020-08-12 13:10:50 +0200568 /* parser next */
569 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
570
571 /* process children */
572 while (xmlctx->status == LYXML_ELEMENT) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100573 ret = lydxml_subtree_r(lydctx, node, lyd_node_child_p(node), NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200574 LY_CHECK_GOTO(ret, error);
575 }
576
577 if (snode->nodetype == LYS_LIST) {
578 /* check all keys exist */
579 LY_CHECK_GOTO(ret = lyd_parse_check_keys(node), error);
580 }
581
Michal Vaskoe0665742021-02-11 11:08:44 +0100582 if (!(lydctx->parse_opts & LYD_PARSE_ONLY)) {
Michal Vaskoa5da3292020-08-12 13:10:50 +0200583 /* new node validation, autodelete CANNOT occur, all nodes are new */
Michal Vaskoe0665742021-02-11 11:08:44 +0100584 ret = lyd_validate_new(lyd_node_child_p(node), snode, NULL, NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200585 LY_CHECK_GOTO(ret, error);
586
587 /* add any missing default children */
Michal Vaskoc43c8ab2021-03-05 13:32:44 +0100588 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 +0100589 (lydctx->val_opts & LYD_VALIDATE_NO_STATE) ? LYD_IMPLICIT_NO_STATE : 0, NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200590 LY_CHECK_GOTO(ret, error);
591 }
592
593 if (snode->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) {
594 /* rememeber the RPC/action/notification */
595 lydctx->op_node = node;
596 }
597 } else if (snode->nodetype & LYD_NODE_ANY) {
Michal Vasko27c4dce2021-03-04 15:50:50 +0100598 if ((snode->nodetype == LYS_ANYDATA) && !xmlctx->ws_only) {
599 /* value in anydata node, we expect a tree */
600 LOGVAL(ctx, LYVE_SYNTAX, "Text value \"%.*s\" inside an anydata node \"%s\" found.",
Radek Krejci422afb12021-03-04 16:38:16 +0100601 (int)xmlctx->value_len < 20 ? xmlctx->value_len : 20, xmlctx->value, snode->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200602 ret = LY_EVALID;
603 goto error;
604 }
605
Michal Vasko27c4dce2021-03-04 15:50:50 +0100606 if (!xmlctx->ws_only) {
607 /* use an arbitrary text value for anyxml */
608 lydict_insert(xmlctx->ctx, xmlctx->value, xmlctx->value_len, &val);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200609
Michal Vasko27c4dce2021-03-04 15:50:50 +0100610 /* parser next */
611 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
612
613 /* create node */
614 ret = lyd_create_any(snode, val, LYD_ANYDATA_STRING, 1, &node);
615 LY_CHECK_GOTO(ret, error);
616 } else {
617 /* parser next */
618 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
619
620 /* parse any data tree with correct options */
621 prev_opts = lydctx->parse_opts;
622 lydctx->parse_opts &= ~LYD_PARSE_STRICT;
623 lydctx->parse_opts |= LYD_PARSE_OPAQ;
624 anchor = NULL;
625 while (xmlctx->status == LYXML_ELEMENT) {
626 ret = lydxml_subtree_r(lydctx, NULL, &anchor, NULL);
627 LY_CHECK_ERR_GOTO(ret, lydctx->parse_opts = prev_opts, error);
628 }
629 lydctx->parse_opts = prev_opts;
630
631 /* create node */
632 ret = lyd_create_any(snode, anchor, LYD_ANYDATA_DATATREE, 1, &node);
633 LY_CHECK_GOTO(ret, error);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200634 }
Michal Vaskoa5da3292020-08-12 13:10:50 +0200635 }
636 assert(node);
637
638 /* add/correct flags */
639 if (snode) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100640 lyd_parse_set_data_flags(node, &lydctx->node_when, &meta, lydctx->parse_opts);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200641 }
642
643 /* parser next */
644 assert(xmlctx->status == LYXML_ELEM_CLOSE);
645 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
646
647 /* add metadata/attributes */
648 if (snode) {
Michal Vasko871a0252020-11-11 18:35:24 +0100649 lyd_insert_meta(node, meta, 0);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200650 } else {
651 lyd_insert_attr(node, attr);
652 }
653
654 /* insert, keep first pointer correct */
Michal Vaskoe0665742021-02-11 11:08:44 +0100655 lyd_insert_node(parent, first_p, node);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200656 while (!parent && (*first_p)->prev->next) {
657 *first_p = (*first_p)->prev;
658 }
659
Michal Vaskoe0665742021-02-11 11:08:44 +0100660 /* rememeber a successfully parsed node */
661 if (parsed) {
662 ly_set_add(parsed, node, 1, NULL);
663 }
664
Radek Krejciddace2c2021-01-08 11:30:56 +0100665 LOG_LOCBACK(node ? 1 : 0, node ? 1 : 0, 0, 0);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200666 return LY_SUCCESS;
667
668error:
Radek Krejciddace2c2021-01-08 11:30:56 +0100669 LOG_LOCBACK(node ? 1 : 0, node ? 1 : 0, 0, 0);
Michal Vasko3a41dff2020-07-15 14:30:28 +0200670 lyd_free_meta_siblings(meta);
Radek Krejci011e4aa2020-09-04 15:22:31 +0200671 lyd_free_attr_siblings(ctx, attr);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200672 lyd_free_tree(node);
Radek Krejcie7b95092019-05-15 11:03:07 +0200673 return ret;
674}
675
Michal Vaskoe0665742021-02-11 11:08:44 +0100676/**
677 * @brief Parse a specific XML element into an opaque node.
678 *
679 * @param[in] xmlctx XML parser context.
680 * @param[in] name Name of the element.
681 * @param[in] uri URI of the element.
682 * @param[in] value Whether a value is expected in the element.
683 * @param[out] evnp Parsed envelope (opaque node).
684 * @return LY_SUCCESS on success.
685 * @return LY_ENOT if the specified element did not match.
686 * @return LY_ERR value on error.
687 */
Michal Vasko1bf09392020-03-27 12:38:10 +0100688static LY_ERR
Michal Vaskoe0665742021-02-11 11:08:44 +0100689lydxml_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 +0100690{
Michal Vaskoe0665742021-02-11 11:08:44 +0100691 LY_ERR rc = LY_SUCCESS;
692 const struct lyxml_ns *ns;
Radek Krejci1798aae2020-07-14 13:26:06 +0200693 struct lyd_attr *attr = NULL;
Michal Vasko1bf09392020-03-27 12:38:10 +0100694 const char *prefix;
695 size_t prefix_len;
696
Michal Vasko1bf09392020-03-27 12:38:10 +0100697 assert(xmlctx->status == LYXML_ELEMENT);
698 if (ly_strncmp(name, xmlctx->name, xmlctx->name_len)) {
699 /* not the expected element */
Michal Vaskoe0665742021-02-11 11:08:44 +0100700 return LY_ENOT;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100701 }
702
703 prefix = xmlctx->prefix;
704 prefix_len = xmlctx->prefix_len;
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200705 ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100706 if (!ns) {
Radek Krejci422afb12021-03-04 16:38:16 +0100707 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)prefix_len, prefix);
Michal Vaskoe0665742021-02-11 11:08:44 +0100708 return LY_EVALID;
709 } else if (strcmp(ns->uri, uri)) {
710 /* different namespace */
711 return LY_ENOT;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100712 }
713
714 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
715
716 /* create attributes */
717 if (xmlctx->status == LYXML_ATTRIBUTE) {
718 LY_CHECK_RET(lydxml_attrs(xmlctx, &attr));
719 }
720
Michal Vaskoe0665742021-02-11 11:08:44 +0100721 assert(xmlctx->status == LYXML_ELEM_CONTENT);
722 if (!value && !xmlctx->ws_only) {
723 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected value \"%.*s\" in the \"%s\" element.",
Radek Krejci422afb12021-03-04 16:38:16 +0100724 (int)xmlctx->value_len, xmlctx->value, name);
Michal Vaskoe0665742021-02-11 11:08:44 +0100725 rc = LY_EVALID;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100726 goto cleanup;
Michal Vaskoe0665742021-02-11 11:08:44 +0100727 }
Michal Vaskoa8edff02020-03-27 14:47:01 +0100728
729 /* create node */
Michal Vaskoe0665742021-02-11 11:08:44 +0100730 rc = lyd_create_opaq(xmlctx->ctx, name, strlen(name), prefix, prefix_len, uri, strlen(uri), xmlctx->value,
731 xmlctx->ws_only ? 0 : xmlctx->value_len, NULL, LY_PREF_XML, NULL, 0, envp);
732 LY_CHECK_GOTO(rc, cleanup);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100733
734 /* assign atributes */
Michal Vaskoe0665742021-02-11 11:08:44 +0100735 ((struct lyd_node_opaq *)(*envp))->attr = attr;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100736 attr = NULL;
737
Michal Vaskoe0665742021-02-11 11:08:44 +0100738 /* parser next element */
739 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100740
Michal Vaskoe0665742021-02-11 11:08:44 +0100741cleanup:
742 lyd_free_attr_siblings(xmlctx->ctx, attr);
743 if (rc) {
744 lyd_free_tree(*envp);
745 *envp = NULL;
746 }
747 return rc;
748}
749
750/**
751 * @brief Parse all expected non-data XML elements of a NETCONF rpc message.
752 *
753 * @param[in] xmlctx XML parser context.
754 * @param[out] evnp Parsed envelope(s) (opaque node).
755 * @param[out] int_opts Internal options for parsing the rest of YANG data.
756 * @param[out] close_elem Number of parsed opened elements that need to be closed.
757 * @return LY_SUCCESS on success.
758 * @return LY_ERR value on error.
759 */
760static LY_ERR
761lydxml_env_netconf_rpc(struct lyxml_ctx *xmlctx, struct lyd_node **envp, uint32_t *int_opts, uint32_t *close_elem)
762{
763 LY_ERR rc = LY_SUCCESS, r;
764 struct lyd_node *child;
765
766 assert(envp && !*envp);
767
768 /* parse "rpc" */
769 r = lydxml_envelope(xmlctx, "rpc", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, envp);
Michal Vaskoe0665742021-02-11 11:08:44 +0100770 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
771
772 /* parse "action", if any */
773 r = lydxml_envelope(xmlctx, "action", "urn:ietf:params:xml:ns:yang:1", 0, &child);
774 if (r == LY_SUCCESS) {
775 /* insert */
776 lyd_insert_node(*envp, NULL, child);
777
778 /* NETCONF action */
779 *int_opts = LYD_INTOPT_NO_SIBLINGS | LYD_INTOPT_ACTION;
780 *close_elem = 2;
781 } else if (r == LY_ENOT) {
782 /* NETCONF RPC */
783 *int_opts = LYD_INTOPT_NO_SIBLINGS | LYD_INTOPT_RPC;
784 *close_elem = 1;
785 } else {
786 rc = r;
787 goto cleanup;
788 }
789
790cleanup:
791 if (rc) {
792 lyd_free_tree(*envp);
793 *envp = NULL;
794 }
795 return rc;
796}
797
798/**
799 * @brief Parse all expected non-data XML elements of a NETCONF notification message.
800 *
801 * @param[in] xmlctx XML parser context.
802 * @param[out] evnp Parsed envelope(s) (opaque node).
803 * @param[out] int_opts Internal options for parsing the rest of YANG data.
804 * @param[out] close_elem Number of parsed opened elements that need to be closed.
805 * @return LY_SUCCESS on success.
806 * @return LY_ERR value on error.
807 */
808static LY_ERR
809lydxml_env_netconf_notif(struct lyxml_ctx *xmlctx, struct lyd_node **envp, uint32_t *int_opts, uint32_t *close_elem)
810{
811 LY_ERR rc = LY_SUCCESS, r;
812 struct lyd_node *child;
813
814 assert(envp && !*envp);
815
816 /* parse "notification" */
817 r = lydxml_envelope(xmlctx, "notification", "urn:ietf:params:xml:ns:netconf:notification:1.0", 0, envp);
Michal Vaskoe0665742021-02-11 11:08:44 +0100818 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
819
820 /* parse "eventTime" */
821 r = lydxml_envelope(xmlctx, "eventTime", "urn:ietf:params:xml:ns:netconf:notification:1.0", 1, &child);
822 if (r == LY_ENOT) {
Radek Krejci422afb12021-03-04 16:38:16 +0100823 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unexpected element \"%.*s\" instead of \"eventTime\".",
824 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +0100825 r = LY_EVALID;
826 }
827 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
828
829 /* insert */
830 lyd_insert_node(*envp, NULL, child);
831
832 /* validate value */
833 /* TODO validate child->value as yang:date-and-time */
834
835 /* finish child parsing */
Michal Vaskoa8edff02020-03-27 14:47:01 +0100836 if (xmlctx->status != LYXML_ELEM_CLOSE) {
837 assert(xmlctx->status == LYXML_ELEMENT);
Michal Vaskoe0665742021-02-11 11:08:44 +0100838 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"eventTime\".",
Radek Krejci422afb12021-03-04 16:38:16 +0100839 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +0100840 rc = LY_EVALID;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100841 goto cleanup;
842 }
Michal Vaskoe0665742021-02-11 11:08:44 +0100843 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
844
845 /* NETCONF notification */
846 *int_opts = LYD_INTOPT_NO_SIBLINGS | LYD_INTOPT_NOTIF;
847 *close_elem = 1;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100848
849cleanup:
Michal Vaskoe0665742021-02-11 11:08:44 +0100850 if (rc) {
Michal Vaskoa8edff02020-03-27 14:47:01 +0100851 lyd_free_tree(*envp);
Michal Vaskoe0665742021-02-11 11:08:44 +0100852 *envp = NULL;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100853 }
Michal Vaskoe0665742021-02-11 11:08:44 +0100854 return rc;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100855}
Michal Vasko79135ae2020-12-16 10:08:35 +0100856
Michal Vaskoe0665742021-02-11 11:08:44 +0100857/**
858 * @brief Parse an XML element as an opaque node subtree.
859 *
860 * @param[in] xmlctx XML parser context.
861 * @param[in] parent Parent to append nodes to.
862 * @return LY_ERR value.
863 */
864static LY_ERR
865lydxml_opaq_r(struct lyxml_ctx *xmlctx, struct lyd_node *parent)
Michal Vaskoa8edff02020-03-27 14:47:01 +0100866{
Michal Vaskoe0665742021-02-11 11:08:44 +0100867 LY_ERR rc = LY_SUCCESS;
868 const struct lyxml_ns *ns;
869 struct lyd_attr *attr = NULL;
870 struct lyd_node *child = NULL;
871 const char *name, *prefix;
872 size_t name_len, prefix_len;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100873
Michal Vaskoe0665742021-02-11 11:08:44 +0100874 assert(xmlctx->status == LYXML_ELEMENT);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100875
Michal Vaskoe0665742021-02-11 11:08:44 +0100876 name = xmlctx->name;
877 name_len = xmlctx->name_len;
878 prefix = xmlctx->prefix;
879 prefix_len = xmlctx->prefix_len;
880 ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
881 if (!ns) {
Radek Krejci422afb12021-03-04 16:38:16 +0100882 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)prefix_len, prefix);
Michal Vaskoe0665742021-02-11 11:08:44 +0100883 return LY_EVALID;
884 }
Michal Vaskoa8edff02020-03-27 14:47:01 +0100885
Michal Vaskoe0665742021-02-11 11:08:44 +0100886 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
Michal Vaskoa8edff02020-03-27 14:47:01 +0100887
Michal Vaskoe0665742021-02-11 11:08:44 +0100888 /* create attributes */
889 if (xmlctx->status == LYXML_ATTRIBUTE) {
890 LY_CHECK_RET(lydxml_attrs(xmlctx, &attr));
891 }
892
893 /* create node */
894 assert(xmlctx->status == LYXML_ELEM_CONTENT);
895 rc = lyd_create_opaq(xmlctx->ctx, name, name_len, prefix, prefix_len, ns->uri, strlen(ns->uri), xmlctx->value,
896 xmlctx->ws_only ? 0 : xmlctx->value_len, NULL, LY_PREF_XML, NULL, 0, &child);
897 LY_CHECK_GOTO(rc, cleanup);
898
899 /* assign atributes */
900 ((struct lyd_node_opaq *)child)->attr = attr;
901 attr = NULL;
902
903 /* parser next element */
904 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
905
906 /* parse all the descendants */
907 while (xmlctx->status == LYXML_ELEMENT) {
908 rc = lydxml_opaq_r(xmlctx, child);
909 LY_CHECK_GOTO(rc, cleanup);
910 }
911
912 /* insert */
913 lyd_insert_node(parent, NULL, child);
914
915cleanup:
916 lyd_free_attr_siblings(xmlctx->ctx, attr);
917 if (rc) {
918 lyd_free_tree(child);
919 }
920 return rc;
921}
922
923/**
924 * @brief Parse all expected non-data XML elements of the error-info element in NETCONF rpc-reply message.
925 *
926 * @param[in] xmlctx XML parser context.
927 * @param[in] parent Parent to append nodes to.
928 * @return LY_ERR value.
929 */
930static LY_ERR
931lydxml_env_netconf_rpc_reply_error_info(struct lyxml_ctx *xmlctx, struct lyd_node *parent)
932{
933 LY_ERR r;
934 struct lyd_node *child, *iter;
935 const struct lyxml_ns *ns;
936 ly_bool no_dup;
937
938 /* there must be some child */
939 if (xmlctx->status == LYXML_ELEM_CLOSE) {
940 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Missing child elements of \"error-info\".");
941 return LY_EVALID;
942 }
943
944 while (xmlctx->status == LYXML_ELEMENT) {
945 child = NULL;
946
947 /*
948 * session-id
949 */
950 r = lydxml_envelope(xmlctx, "session-id", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
951 if (r == LY_SUCCESS) {
952 no_dup = 1;
953 goto check_child;
954 } else if (r != LY_ENOT) {
955 goto error;
956 }
957
958 /*
959 * bad-attribute
960 */
961 r = lydxml_envelope(xmlctx, "bad-attribute", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
962 if (r == LY_SUCCESS) {
963 no_dup = 1;
964 goto check_child;
965 } else if (r != LY_ENOT) {
966 goto error;
967 }
968
969 /*
970 * bad-element
971 */
972 r = lydxml_envelope(xmlctx, "bad-element", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
973 if (r == LY_SUCCESS) {
974 no_dup = 1;
975 goto check_child;
976 } else if (r != LY_ENOT) {
977 goto error;
978 }
979
980 /*
981 * bad-namespace
982 */
983 r = lydxml_envelope(xmlctx, "bad-namespace", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
984 if (r == LY_SUCCESS) {
985 no_dup = 1;
986 goto check_child;
987 } else if (r != LY_ENOT) {
988 goto error;
989 }
990
991 if (r == LY_ENOT) {
992 assert(xmlctx->status == LYXML_ELEMENT);
993
994 /* learn namespace */
995 ns = lyxml_ns_get(&xmlctx->ns, xmlctx->prefix, xmlctx->prefix_len);
996 if (!ns) {
Radek Krejci422afb12021-03-04 16:38:16 +0100997 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)xmlctx->prefix_len, xmlctx->prefix);
Michal Vaskoe0665742021-02-11 11:08:44 +0100998 r = LY_EVALID;
999 goto error;
1000 } else if (!strcmp(ns->uri, "urn:ietf:params:xml:ns:netconf:base:1.0")) {
1001 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"error-info\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001002 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001003 r = LY_EVALID;
1004 goto error;
1005 }
1006
1007 /* custom elements */
1008 r = lydxml_opaq_r(xmlctx, parent);
1009 LY_CHECK_GOTO(r, error);
1010
1011 no_dup = 0;
1012 }
1013
1014check_child:
1015 /* check for duplicates */
1016 if (no_dup) {
1017 LY_LIST_FOR(lyd_child(parent), iter) {
1018 if ((((struct lyd_node_opaq *)iter)->name.name == ((struct lyd_node_opaq *)child)->name.name) &&
1019 (((struct lyd_node_opaq *)iter)->name.module_ns == ((struct lyd_node_opaq *)child)->name.module_ns)) {
1020 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Duplicate element \"%s\" in \"error-info\".",
1021 ((struct lyd_node_opaq *)child)->name.name);
1022 r = LY_EVALID;
1023 goto error;
1024 }
1025 }
1026 }
1027
1028 /* finish child parsing */
1029 if (xmlctx->status != LYXML_ELEM_CLOSE) {
1030 assert(xmlctx->status == LYXML_ELEMENT);
1031 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"error-info\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001032 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001033 r = LY_EVALID;
1034 goto error;
1035 }
1036 LY_CHECK_GOTO(r = lyxml_ctx_next(xmlctx), error);
1037
1038 /* insert */
1039 lyd_insert_node(parent, NULL, child);
1040 }
1041
1042 return LY_SUCCESS;
1043
1044error:
1045 lyd_free_tree(child);
1046 return r;
1047}
1048
1049/**
1050 * @brief Parse all expected non-data XML elements of the rpc-error element in NETCONF rpc-reply message.
1051 *
1052 * @param[in] xmlctx XML parser context.
1053 * @param[in] parent Parent to append nodes to.
1054 * @return LY_ERR value.
1055 */
1056static LY_ERR
1057lydxml_env_netconf_rpc_reply_error(struct lyxml_ctx *xmlctx, struct lyd_node *parent)
1058{
1059 LY_ERR r;
1060 struct lyd_node *child, *iter;
1061 const char *val;
1062 ly_bool no_dup;
1063
1064 /* there must be some child */
1065 if (xmlctx->status == LYXML_ELEM_CLOSE) {
1066 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Missing child elements of \"rpc-error\".");
1067 return LY_EVALID;
1068 }
1069
1070 while (xmlctx->status == LYXML_ELEMENT) {
1071 child = NULL;
1072
1073 /*
1074 * error-type
1075 */
1076 r = lydxml_envelope(xmlctx, "error-type", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1077 if (r == LY_SUCCESS) {
1078 val = ((struct lyd_node_opaq *)child)->value;
1079 if (strcmp(val, "transport") && strcmp(val, "rpc") && strcmp(val, "protocol") && strcmp(val, "application")) {
1080 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Invalid value \"%s\" of element \"%s\".", val,
1081 ((struct lyd_node_opaq *)child)->name.name);
1082 r = LY_EVALID;
1083 goto error;
1084 }
1085
1086 no_dup = 1;
1087 goto check_child;
1088 } else if (r != LY_ENOT) {
1089 goto error;
1090 }
1091
1092 /*
1093 * error-tag
1094 */
1095 r = lydxml_envelope(xmlctx, "error-tag", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1096 if (r == LY_SUCCESS) {
1097 val = ((struct lyd_node_opaq *)child)->value;
1098 if (strcmp(val, "in-use") && strcmp(val, "invalid-value") && strcmp(val, "too-big") &&
1099 strcmp(val, "missing-attribute") && strcmp(val, "bad-attribute") &&
1100 strcmp(val, "unknown-attribute") && strcmp(val, "missing-element") && strcmp(val, "bad-element") &&
1101 strcmp(val, "unknown-element") && strcmp(val, "unknown-namespace") && strcmp(val, "access-denied") &&
1102 strcmp(val, "lock-denied") && strcmp(val, "resource-denied") && strcmp(val, "rollback-failed") &&
1103 strcmp(val, "data-exists") && strcmp(val, "data-missing") && strcmp(val, "operation-not-supported") &&
1104 strcmp(val, "operation-failed") && strcmp(val, "malformed-message")) {
1105 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Invalid value \"%s\" of element \"%s\".", val,
1106 ((struct lyd_node_opaq *)child)->name.name);
1107 r = LY_EVALID;
1108 goto error;
1109 }
1110
1111 no_dup = 1;
1112 goto check_child;
1113 } else if (r != LY_ENOT) {
1114 goto error;
1115 }
1116
1117 /*
1118 * error-severity
1119 */
1120 r = lydxml_envelope(xmlctx, "error-severity", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1121 if (r == LY_SUCCESS) {
1122 val = ((struct lyd_node_opaq *)child)->value;
1123 if (strcmp(val, "error") && strcmp(val, "warning")) {
1124 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Invalid value \"%s\" of element \"%s\".", val,
1125 ((struct lyd_node_opaq *)child)->name.name);
1126 r = LY_EVALID;
1127 goto error;
1128 }
1129
1130 no_dup = 1;
1131 goto check_child;
1132 } else if (r != LY_ENOT) {
1133 goto error;
1134 }
1135
1136 /*
1137 * error-app-tag
1138 */
1139 r = lydxml_envelope(xmlctx, "error-app-tag", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1140 if (r == LY_SUCCESS) {
1141 no_dup = 1;
1142 goto check_child;
1143 } else if (r != LY_ENOT) {
1144 goto error;
1145 }
1146
1147 /*
1148 * error-path
1149 */
1150 r = lydxml_envelope(xmlctx, "error-path", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1151 if (r == LY_SUCCESS) {
1152 no_dup = 1;
1153 goto check_child;
1154 } else if (r != LY_ENOT) {
1155 goto error;
1156 }
1157
1158 /*
1159 * error-message
1160 */
1161 r = lydxml_envelope(xmlctx, "error-message", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1162 if (r == LY_SUCCESS) {
1163 no_dup = 1;
1164 goto check_child;
1165 } else if (r != LY_ENOT) {
1166 goto error;
1167 }
1168
1169 /* error-info */
1170 r = lydxml_envelope(xmlctx, "error-info", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, &child);
1171 if (r == LY_SUCCESS) {
1172 /* parse all the descendants */
1173 LY_CHECK_GOTO(r = lydxml_env_netconf_rpc_reply_error_info(xmlctx, child), error);
1174
1175 no_dup = 0;
1176 goto check_child;
1177 } else if (r != LY_ENOT) {
1178 goto error;
1179 }
1180
1181 if (r == LY_ENOT) {
1182 assert(xmlctx->status == LYXML_ELEMENT);
1183 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"rpc-error\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001184 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001185 r = LY_EVALID;
1186 goto error;
1187 }
1188
1189check_child:
1190 /* check for duplicates */
1191 if (no_dup) {
1192 LY_LIST_FOR(lyd_child(parent), iter) {
1193 if ((((struct lyd_node_opaq *)iter)->name.name == ((struct lyd_node_opaq *)child)->name.name) &&
1194 (((struct lyd_node_opaq *)iter)->name.module_ns == ((struct lyd_node_opaq *)child)->name.module_ns)) {
1195 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Duplicate element \"%s\" in \"rpc-error\".",
1196 ((struct lyd_node_opaq *)child)->name.name);
1197 r = LY_EVALID;
1198 goto error;
1199 }
1200 }
1201 }
1202
1203 /* finish child parsing */
1204 if (xmlctx->status != LYXML_ELEM_CLOSE) {
1205 assert(xmlctx->status == LYXML_ELEMENT);
1206 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"rpc-error\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001207 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001208 r = LY_EVALID;
1209 goto error;
1210 }
1211 LY_CHECK_GOTO(r = lyxml_ctx_next(xmlctx), error);
1212
1213 /* insert */
1214 lyd_insert_node(parent, NULL, child);
1215 }
1216
1217 return LY_SUCCESS;
1218
1219error:
1220 lyd_free_tree(child);
1221 return r;
1222}
1223
1224/**
1225 * @brief Parse all expected non-data XML elements of a NETCONF rpc-reply message.
1226 *
1227 * @param[in] xmlctx XML parser context.
1228 * @param[out] evnp Parsed envelope(s) (opaque node).
1229 * @param[out] int_opts Internal options for parsing the rest of YANG data.
1230 * @param[out] close_elem Number of parsed opened elements that need to be closed.
1231 * @return LY_SUCCESS on success.
1232 * @return LY_ERR value on error.
1233 */
1234static LY_ERR
1235lydxml_env_netconf_reply(struct lyxml_ctx *xmlctx, struct lyd_node **envp, uint32_t *int_opts, uint32_t *close_elem)
1236{
1237 LY_ERR rc = LY_SUCCESS, r;
1238 struct lyd_node *child = NULL;
1239 const char *parsed_elem = NULL;
1240
1241 assert(envp && !*envp);
1242
1243 /* parse "rpc-reply" */
1244 r = lydxml_envelope(xmlctx, "rpc-reply", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, envp);
Michal Vaskoe0665742021-02-11 11:08:44 +01001245 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
1246
1247 /* there must be some child */
1248 if (xmlctx->status == LYXML_ELEM_CLOSE) {
1249 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Missing child elements of \"rpc-reply\".");
1250 rc = LY_EVALID;
Michal Vaskocf770e22020-08-12 13:21:43 +02001251 goto cleanup;
Michal Vaskoa8edff02020-03-27 14:47:01 +01001252 }
1253
Michal Vaskoe0665742021-02-11 11:08:44 +01001254 /* try to parse "ok" */
1255 r = lydxml_envelope(xmlctx, "ok", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, &child);
1256 if (r == LY_SUCCESS) {
1257 /* insert */
1258 lyd_insert_node(*envp, NULL, child);
1259
1260 /* finish child parsing */
1261 if (xmlctx->status != LYXML_ELEM_CLOSE) {
1262 assert(xmlctx->status == LYXML_ELEMENT);
1263 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"ok\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001264 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001265 rc = LY_EVALID;
1266 goto cleanup;
1267 }
1268 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
1269
1270 /* success */
1271 parsed_elem = "ok";
1272 goto finish;
1273 } else if (r != LY_ENOT) {
1274 rc = r;
1275 goto cleanup;
Michal Vasko2552ea32020-12-08 15:32:34 +01001276 }
1277
Michal Vaskoe0665742021-02-11 11:08:44 +01001278 /* try to parse all "rpc-error" elements */
1279 while (xmlctx->status == LYXML_ELEMENT) {
1280 r = lydxml_envelope(xmlctx, "rpc-error", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, &child);
1281 if (r == LY_ENOT) {
1282 break;
1283 } else if (r) {
1284 rc = r;
1285 goto cleanup;
1286 }
1287
1288 /* insert */
1289 lyd_insert_node(*envp, NULL, child);
1290
1291 /* parse all children of "rpc-error" */
1292 LY_CHECK_GOTO(rc = lydxml_env_netconf_rpc_reply_error(xmlctx, child), cleanup);
1293
1294 /* finish child parsing */
1295 assert(xmlctx->status == LYXML_ELEM_CLOSE);
1296 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
1297
1298 parsed_elem = "rpc-error";
Michal Vasko2552ea32020-12-08 15:32:34 +01001299 }
Michal Vaskoe0665742021-02-11 11:08:44 +01001300
1301finish:
1302 if (parsed_elem) {
1303 /* NETCONF rpc-reply with no data */
1304 if (xmlctx->status != LYXML_ELEM_CLOSE) {
1305 assert(xmlctx->status == LYXML_ELEMENT);
1306 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected sibling element \"%.*s\" of \"%s\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001307 (int)xmlctx->name_len, xmlctx->name, parsed_elem);
Michal Vaskoe0665742021-02-11 11:08:44 +01001308 rc = LY_EVALID;
1309 goto cleanup;
1310 }
1311 }
1312
1313 /* NETCONF rpc-reply */
1314 *int_opts = LYD_INTOPT_NO_SIBLINGS | LYD_INTOPT_REPLY;
1315 *close_elem = 1;
1316
1317cleanup:
1318 if (rc) {
1319 lyd_free_tree(*envp);
1320 *envp = NULL;
1321 }
1322 return rc;
1323}
1324
Michal Vasko2552ea32020-12-08 15:32:34 +01001325LY_ERR
Radek Krejcif16e2542021-02-17 15:39:23 +01001326lyd_parse_xml(const struct ly_ctx *ctx, const struct lysc_ext_instance *ext, struct lyd_node *parent,
1327 struct lyd_node **first_p, struct ly_in *in, uint32_t parse_opts, uint32_t val_opts, enum lyd_type data_type,
1328 struct lyd_node **envp, struct ly_set *parsed, struct lyd_ctx **lydctx_p)
Michal Vasko2552ea32020-12-08 15:32:34 +01001329{
Michal Vaskoe0665742021-02-11 11:08:44 +01001330 LY_ERR rc = LY_SUCCESS;
1331 struct lyd_xml_ctx *lydctx;
1332 uint32_t i, int_opts, close_elem = 0;
1333 ly_bool parsed_data_nodes = 0;
Michal Vasko2552ea32020-12-08 15:32:34 +01001334
Michal Vaskoe0665742021-02-11 11:08:44 +01001335 assert(ctx && in && lydctx_p);
1336 assert(!(parse_opts & ~LYD_PARSE_OPTS_MASK));
1337 assert(!(val_opts & ~LYD_VALIDATE_OPTS_MASK));
Michal Vasko2552ea32020-12-08 15:32:34 +01001338
Michal Vaskoe0665742021-02-11 11:08:44 +01001339 /* init context */
1340 lydctx = calloc(1, sizeof *lydctx);
1341 LY_CHECK_ERR_RET(!lydctx, LOGMEM(ctx), LY_EMEM);
1342 LY_CHECK_GOTO(rc = lyxml_ctx_new(ctx, in, &lydctx->xmlctx), cleanup);
1343 lydctx->parse_opts = parse_opts;
1344 lydctx->val_opts = val_opts;
1345 lydctx->free = lyd_xml_ctx_free;
Radek Krejcif16e2542021-02-17 15:39:23 +01001346 lydctx->ext = ext;
Michal Vasko2552ea32020-12-08 15:32:34 +01001347
Michal Vaskoe0665742021-02-11 11:08:44 +01001348 switch (data_type) {
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001349 case LYD_TYPE_DATA_YANG:
Michal Vaskoe0665742021-02-11 11:08:44 +01001350 int_opts = LYD_INTOPT_WITH_SIBLINGS;
1351 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001352 case LYD_TYPE_RPC_YANG:
Michal Vaskoe0665742021-02-11 11:08:44 +01001353 int_opts = LYD_INTOPT_RPC | LYD_INTOPT_ACTION | LYD_INTOPT_NO_SIBLINGS;
1354 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001355 case LYD_TYPE_NOTIF_YANG:
Michal Vaskoe0665742021-02-11 11:08:44 +01001356 int_opts = LYD_INTOPT_NOTIF | LYD_INTOPT_NO_SIBLINGS;
1357 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001358 case LYD_TYPE_REPLY_YANG:
Michal Vaskoe0665742021-02-11 11:08:44 +01001359 int_opts = LYD_INTOPT_REPLY | LYD_INTOPT_NO_SIBLINGS;
1360 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001361 case LYD_TYPE_RPC_NETCONF:
Michal Vaskoe0665742021-02-11 11:08:44 +01001362 assert(!parent);
1363 LY_CHECK_GOTO(rc = lydxml_env_netconf_rpc(lydctx->xmlctx, envp, &int_opts, &close_elem), cleanup);
1364 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001365 case LYD_TYPE_NOTIF_NETCONF:
1366 assert(!parent);
1367 LY_CHECK_GOTO(rc = lydxml_env_netconf_notif(lydctx->xmlctx, envp, &int_opts, &close_elem), cleanup);
1368 break;
1369 case LYD_TYPE_REPLY_NETCONF:
Michal Vaskoe0665742021-02-11 11:08:44 +01001370 assert(parent);
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001371 LY_CHECK_GOTO(rc = lydxml_env_netconf_reply(lydctx->xmlctx, envp, &int_opts, &close_elem), cleanup);
Michal Vaskoe0665742021-02-11 11:08:44 +01001372 break;
1373 }
1374 lydctx->int_opts = int_opts;
1375
1376 /* find the operation node if it exists already */
1377 LY_CHECK_GOTO(rc = lyd_parser_find_operation(parent, int_opts, &lydctx->op_node), cleanup);
1378
1379 /* parse XML data */
1380 while (lydctx->xmlctx->status == LYXML_ELEMENT) {
1381 LY_CHECK_GOTO(rc = lydxml_subtree_r(lydctx, parent, first_p, parsed), cleanup);
1382 parsed_data_nodes = 1;
1383
1384 if (!(int_opts & LYD_INTOPT_WITH_SIBLINGS)) {
1385 break;
1386 }
Michal Vasko2552ea32020-12-08 15:32:34 +01001387 }
1388
Michal Vaskoe0665742021-02-11 11:08:44 +01001389 /* close all opened elements */
1390 for (i = 0; i < close_elem; ++i) {
1391 if (lydctx->xmlctx->status != LYXML_ELEM_CLOSE) {
1392 assert(lydctx->xmlctx->status == LYXML_ELEMENT);
Radek Krejci422afb12021-03-04 16:38:16 +01001393 LOGVAL(lydctx->xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\".",
1394 (int)lydctx->xmlctx->name_len, lydctx->xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001395 rc = LY_EVALID;
1396 goto cleanup;
1397 }
1398
1399 LY_CHECK_GOTO(rc = lyxml_ctx_next(lydctx->xmlctx), cleanup);
Michal Vasko4189c0f2020-08-13 09:05:22 +02001400 }
Michal Vaskoe0665742021-02-11 11:08:44 +01001401
1402 /* check final state */
1403 if ((int_opts & LYD_INTOPT_NO_SIBLINGS) && (lydctx->xmlctx->status == LYXML_ELEMENT)) {
1404 LOGVAL(ctx, LYVE_SYNTAX, "Unexpected sibling node.");
1405 rc = LY_EVALID;
1406 goto cleanup;
1407 }
1408 if ((int_opts & (LYD_INTOPT_RPC | LYD_INTOPT_NOTIF | LYD_INTOPT_REPLY)) && !lydctx->op_node) {
1409 LOGVAL(ctx, LYVE_DATA, "Missing the operation node.");
1410 rc = LY_EVALID;
1411 goto cleanup;
1412 }
1413
1414 if (!parsed_data_nodes) {
1415 /* no data nodes were parsed */
1416 lydctx->op_node = NULL;
Michal Vaskoa8edff02020-03-27 14:47:01 +01001417 }
1418
1419cleanup:
Michal Vaskoe0665742021-02-11 11:08:44 +01001420 /* there should be no unres stored if validation should be skipped */
1421 assert(!(parse_opts & LYD_PARSE_ONLY) || (!lydctx->node_types.count && !lydctx->meta_types.count &&
1422 !lydctx->node_when.count));
1423
1424 if (rc) {
1425 lyd_xml_ctx_free((struct lyd_ctx *)lydctx);
1426 } else {
1427 *lydctx_p = (struct lyd_ctx *)lydctx;
1428
1429 /* the XML context is no more needed, freeing it also stops logging line numbers which would be confusing now */
1430 lyxml_ctx_free(lydctx->xmlctx);
1431 lydctx->xmlctx = NULL;
Michal Vasko1ce933a2020-03-30 12:38:22 +02001432 }
Michal Vaskoe0665742021-02-11 11:08:44 +01001433 return rc;
Michal Vasko1ce933a2020-03-30 12:38:22 +02001434}