blob: a50ee054f32a8e562b77c91847581c7d4236ba03 [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
Radek Krejcie7b95092019-05-15 11:03:07 +020015#include <stdint.h>
16#include <stdlib.h>
17#include <string.h>
Michal Vasko9b368d32020-02-14 13:53:31 +010018#include <assert.h>
Radek Krejcie7b95092019-05-15 11:03:07 +020019
Radek Krejci535ea9f2020-05-29 16:01:05 +020020#include "common.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020021#include "context.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020022#include "log.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020023#include "set.h"
Radek Krejci535ea9f2020-05-29 16:01:05 +020024#include "tree.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020025#include "tree_data_internal.h"
26#include "tree_schema.h"
Michal Vaskocde73ac2019-11-14 16:10:27 +010027#include "validation.h"
Radek Krejci535ea9f2020-05-29 16:01:05 +020028#include "xml.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020029
30/**
Michal Vaskob36053d2020-03-26 15:49:30 +010031 * @brief Internal context for XML YANG data parser.
Radek Krejcie7b95092019-05-15 11:03:07 +020032 */
33struct lyd_xml_ctx {
Michal Vaskob36053d2020-03-26 15:49:30 +010034 struct lyxml_ctx *xmlctx; /**< XML context */
Radek Krejcie7b95092019-05-15 11:03:07 +020035
Michal Vasko52927e22020-03-16 17:26:14 +010036 uint32_t options; /**< various @ref dataparseroptions. */
Michal Vasko1bf09392020-03-27 12:38:10 +010037 uint32_t int_opts; /**< internal data parser options */
Michal Vasko52927e22020-03-16 17:26:14 +010038 uint32_t path_len; /**< used bytes in the path buffer */
Radek Krejcie7b95092019-05-15 11:03:07 +020039#define LYD_PARSER_BUFSIZE 4078
40 char path[LYD_PARSER_BUFSIZE]; /**< buffer for the generated path */
Michal Vasko52927e22020-03-16 17:26:14 +010041 struct ly_set unres_node_type; /**< set of nodes validated with LY_EINCOMPLETE result */
42 struct ly_set unres_meta_type; /**< set of metadata validated with LY_EINCOMPLETE result */
Michal Vaskoecd62de2019-11-13 12:35:11 +010043 struct ly_set when_check; /**< set of nodes with "when" conditions */
Michal Vasko1bf09392020-03-27 12:38:10 +010044 struct lyd_node *op_ntf; /**< if an RPC/action/notification is being parsed, store the pointer to it */
Radek Krejcie7b95092019-05-15 11:03:07 +020045};
46
47/**
Michal Vaskob36053d2020-03-26 15:49:30 +010048 * @brief XML-parser's implementation of ly_type_resolve_prefix() callback to provide mapping between prefixes used
49 * in the values to the schema via XML namespaces.
Radek Krejciaca74032019-06-04 08:53:06 +020050 */
51static const struct lys_module *
Michal Vasko52927e22020-03-16 17:26:14 +010052lydxml_resolve_prefix(const struct ly_ctx *ctx, const char *prefix, size_t prefix_len, void *parser)
Radek Krejciaca74032019-06-04 08:53:06 +020053{
54 const struct lyxml_ns *ns;
Michal Vaskob36053d2020-03-26 15:49:30 +010055 struct lyxml_ctx *xmlctx = (struct lyxml_ctx *)parser;
Radek Krejciaca74032019-06-04 08:53:06 +020056
57 ns = lyxml_ns_get(xmlctx, prefix, prefix_len);
58 if (!ns) {
59 return NULL;
60 }
61
62 return ly_ctx_get_module_implemented_ns(ctx, ns->uri);
63}
64
Radek Krejcie7b95092019-05-15 11:03:07 +020065static LY_ERR
Michal Vasko60ea6352020-06-29 13:39:39 +020066lydxml_metadata(struct lyxml_ctx *xmlctx, const struct lysc_node *sparent, int strict, struct ly_set *unres_meta_type,
Michal Vaskob36053d2020-03-26 15:49:30 +010067 struct lyd_meta **meta)
Radek Krejcie7b95092019-05-15 11:03:07 +020068{
Michal Vaskob36053d2020-03-26 15:49:30 +010069 LY_ERR ret = LY_EVALID;
Radek Krejci28681fa2019-09-06 13:08:45 +020070 const struct lyxml_ns *ns;
71 struct lys_module *mod;
Michal Vaskob36053d2020-03-26 15:49:30 +010072 const char *name;
73 size_t name_len;
Radek Krejci28681fa2019-09-06 13:08:45 +020074
Michal Vaskob36053d2020-03-26 15:49:30 +010075 *meta = NULL;
Radek Krejci28681fa2019-09-06 13:08:45 +020076
Michal Vaskob36053d2020-03-26 15:49:30 +010077 while (xmlctx->status == LYXML_ATTRIBUTE) {
78 if (!xmlctx->prefix_len) {
Radek Krejci28681fa2019-09-06 13:08:45 +020079 /* in XML, all attributes must be prefixed
80 * TODO exception for NETCONF filters which are supposed to map to the ietf-netconf without prefix */
Michal Vasko52927e22020-03-16 17:26:14 +010081 if (strict) {
82 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Missing mandatory prefix for XML metadata \"%.*s\".",
Michal Vaskob36053d2020-03-26 15:49:30 +010083 xmlctx->name_len, xmlctx->name);
84 goto cleanup;
Radek Krejci28681fa2019-09-06 13:08:45 +020085 }
Michal Vaskob36053d2020-03-26 15:49:30 +010086
Radek Krejci28681fa2019-09-06 13:08:45 +020087skip_attr:
Michal Vaskob36053d2020-03-26 15:49:30 +010088 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
89 assert(xmlctx->status == LYXML_ATTR_CONTENT);
90 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Radek Krejci28681fa2019-09-06 13:08:45 +020091 continue;
92 }
93
94 /* get namespace of the attribute to find its annotation definition */
Michal Vaskob36053d2020-03-26 15:49:30 +010095 ns = lyxml_ns_get(xmlctx, xmlctx->prefix, xmlctx->prefix_len);
Radek Krejci28681fa2019-09-06 13:08:45 +020096 if (!ns) {
Michal Vasko52927e22020-03-16 17:26:14 +010097 /* unknown namespace, XML error */
98 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".",
Michal Vaskob36053d2020-03-26 15:49:30 +010099 xmlctx->prefix_len, xmlctx->prefix);
Radek Krejci28681fa2019-09-06 13:08:45 +0200100 goto cleanup;
101 }
Michal Vasko52927e22020-03-16 17:26:14 +0100102 mod = ly_ctx_get_module_implemented_ns(xmlctx->ctx, ns->uri);
Radek Krejci28681fa2019-09-06 13:08:45 +0200103 if (!mod) {
104 /* module is not implemented or not present in the schema */
Michal Vasko52927e22020-03-16 17:26:14 +0100105 if (strict) {
106 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE,
Michal Vasko9f96a052020-03-10 09:41:45 +0100107 "Unknown (or not implemented) YANG module with namespace \"%s\" for metadata \"%.*s%s%.*s\".",
Michal Vaskob36053d2020-03-26 15:49:30 +0100108 ns->uri, xmlctx->prefix_len, xmlctx->prefix, xmlctx->prefix_len ? ":" : "", xmlctx->name_len,
109 xmlctx->name);
110 goto cleanup;
Radek Krejci28681fa2019-09-06 13:08:45 +0200111 }
112 goto skip_attr;
113 }
114
Michal Vasko60ea6352020-06-29 13:39:39 +0200115 /* remember meta name and get its content */
Michal Vaskob36053d2020-03-26 15:49:30 +0100116 name = xmlctx->name;
117 name_len = xmlctx->name_len;
118 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
119 assert(xmlctx->status == LYXML_ATTR_CONTENT);
120
121 /* create metadata */
122 ret = lyd_create_meta(NULL, meta, mod, name, name_len, xmlctx->value, xmlctx->value_len, &xmlctx->dynamic,
123 lydxml_resolve_prefix, xmlctx, LYD_XML, sparent);
124 if (ret == LY_EINCOMPLETE) {
Michal Vasko60ea6352020-06-29 13:39:39 +0200125 if (unres_meta_type) {
126 ly_set_add(unres_meta_type, *meta, LY_SET_OPT_USEASLIST);
Michal Vasko52927e22020-03-16 17:26:14 +0100127 }
Michal Vaskob36053d2020-03-26 15:49:30 +0100128 } else if (ret) {
Radek Krejci28681fa2019-09-06 13:08:45 +0200129 goto cleanup;
130 }
Michal Vaskob36053d2020-03-26 15:49:30 +0100131
132 /* next attribute */
133 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Radek Krejcie7b95092019-05-15 11:03:07 +0200134 }
Michal Vasko52927e22020-03-16 17:26:14 +0100135
Radek Krejci28681fa2019-09-06 13:08:45 +0200136 ret = LY_SUCCESS;
Radek Krejcie7b95092019-05-15 11:03:07 +0200137
138cleanup:
Michal Vaskob36053d2020-03-26 15:49:30 +0100139 if (ret) {
140 lyd_free_meta(xmlctx->ctx, *meta, 1);
141 *meta = NULL;
Radek Krejci38d85362019-09-05 16:26:38 +0200142 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200143 return ret;
144}
145
Michal Vasko52927e22020-03-16 17:26:14 +0100146static LY_ERR
Michal Vaskob36053d2020-03-26 15:49:30 +0100147lydxml_attrs(struct lyxml_ctx *xmlctx, struct ly_attr **attr)
Michal Vasko52927e22020-03-16 17:26:14 +0100148{
149 LY_ERR ret = LY_SUCCESS;
150 const struct lyxml_ns *ns;
151 struct ly_prefix *val_prefs;
152 struct ly_attr *attr2;
Michal Vaskob36053d2020-03-26 15:49:30 +0100153 const char *name, *prefix;
154 size_t name_len, prefix_len;
Michal Vasko52927e22020-03-16 17:26:14 +0100155
156 assert(attr);
Michal Vaskob36053d2020-03-26 15:49:30 +0100157 *attr = NULL;
Michal Vasko52927e22020-03-16 17:26:14 +0100158
Michal Vaskob36053d2020-03-26 15:49:30 +0100159 while (xmlctx->status == LYXML_ATTRIBUTE) {
Michal Vasko52927e22020-03-16 17:26:14 +0100160 ns = NULL;
Michal Vaskob36053d2020-03-26 15:49:30 +0100161 if (xmlctx->prefix_len) {
Michal Vasko52927e22020-03-16 17:26:14 +0100162 /* get namespace of the attribute */
Michal Vaskob36053d2020-03-26 15:49:30 +0100163 ns = lyxml_ns_get(xmlctx, xmlctx->prefix, xmlctx->prefix_len);
Michal Vasko52927e22020-03-16 17:26:14 +0100164 if (!ns) {
165 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".",
Michal Vaskob36053d2020-03-26 15:49:30 +0100166 xmlctx->prefix_len, xmlctx->prefix);
Michal Vasko52927e22020-03-16 17:26:14 +0100167 ret = LY_EVALID;
168 goto cleanup;
169 }
170 }
171
172 if (*attr) {
173 attr2 = *attr;
174 } else {
175 attr2 = NULL;
176 }
177
Michal Vaskob36053d2020-03-26 15:49:30 +0100178 /* remember attr prefix, name, and get its content */
179 prefix = xmlctx->prefix;
180 prefix_len = xmlctx->prefix_len;
181 name = xmlctx->name;
182 name_len = xmlctx->name_len;
183 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
184 assert(xmlctx->status == LYXML_ATTR_CONTENT);
185
Michal Vasko52927e22020-03-16 17:26:14 +0100186 /* get value prefixes */
Michal Vaskob36053d2020-03-26 15:49:30 +0100187 LY_CHECK_GOTO(ret = lyxml_get_prefixes(xmlctx, xmlctx->value, xmlctx->value_len, &val_prefs), cleanup);
Michal Vasko52927e22020-03-16 17:26:14 +0100188
189 /* attr2 is always changed to the created attribute */
Michal Vaskob36053d2020-03-26 15:49:30 +0100190 ret = ly_create_attr(NULL, &attr2, xmlctx->ctx, name, name_len, xmlctx->value, xmlctx->value_len,
191 &xmlctx->dynamic, LYD_XML, val_prefs, prefix, prefix_len, ns ? ns->uri : NULL);
Michal Vasko52927e22020-03-16 17:26:14 +0100192 LY_CHECK_GOTO(ret, cleanup);
193
194 if (!*attr) {
195 *attr = attr2;
196 }
Michal Vaskob36053d2020-03-26 15:49:30 +0100197
198 /* next attribute */
199 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko52927e22020-03-16 17:26:14 +0100200 }
201
202cleanup:
Michal Vaskob36053d2020-03-26 15:49:30 +0100203 if (ret) {
204 ly_free_attr(xmlctx->ctx, *attr, 1);
205 *attr = NULL;
Michal Vasko52927e22020-03-16 17:26:14 +0100206 }
Michal Vasko52927e22020-03-16 17:26:14 +0100207 return ret;
208}
209
Michal Vasko44685da2020-03-17 15:38:06 +0100210static LY_ERR
Michal Vaskob36053d2020-03-26 15:49:30 +0100211lydxml_check_list(struct lyxml_ctx *xmlctx, const struct lysc_node *list)
Michal Vasko44685da2020-03-17 15:38:06 +0100212{
Michal Vaskob36053d2020-03-26 15:49:30 +0100213 LY_ERR ret = LY_SUCCESS, r;
214 enum LYXML_PARSER_STATUS next;
Michal Vasko44685da2020-03-17 15:38:06 +0100215 struct ly_set key_set = {0};
216 const struct lysc_node *snode;
Michal Vaskob36053d2020-03-26 15:49:30 +0100217 uint32_t i, parents_count;
Michal Vasko44685da2020-03-17 15:38:06 +0100218
219 assert(list && (list->nodetype == LYS_LIST));
220
221 /* get all keys into a set (keys do not have if-features or anything) */
222 snode = NULL;
223 while ((snode = lys_getnext(snode, list, NULL, LYS_GETNEXT_NOSTATECHECK)) && (snode->flags & LYS_KEY)) {
224 ly_set_add(&key_set, (void *)snode, LY_SET_OPT_USEASLIST);
225 }
226
Michal Vaskob36053d2020-03-26 15:49:30 +0100227 while (xmlctx->status == LYXML_ELEMENT) {
Michal Vasko44685da2020-03-17 15:38:06 +0100228 /* find key definition */
229 for (i = 0; i < key_set.count; ++i) {
230 snode = (const struct lysc_node *)key_set.objs[i];
Michal Vaskob36053d2020-03-26 15:49:30 +0100231 if (!ly_strncmp(snode->name, xmlctx->name, xmlctx->name_len)) {
Michal Vasko44685da2020-03-17 15:38:06 +0100232 break;
233 }
234 }
Michal Vaskob36053d2020-03-26 15:49:30 +0100235 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100236
237 /* skip attributes */
238 while (xmlctx->status == LYXML_ATTRIBUTE) {
Michal Vaskob36053d2020-03-26 15:49:30 +0100239 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
240 assert(xmlctx->status == LYXML_ATTR_CONTENT);
241 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100242 }
243
Michal Vaskob36053d2020-03-26 15:49:30 +0100244 assert(xmlctx->status == LYXML_ELEM_CONTENT);
245 if (i < key_set.count) {
246 /* validate the value */
247 r = lys_value_validate(NULL, snode, xmlctx->value, xmlctx->value_len, lydxml_resolve_prefix, xmlctx, LYD_XML);
248 if (!r) {
249 /* key with a valid value, remove from the set */
250 ly_set_rm_index(&key_set, i, NULL);
Michal Vasko44685da2020-03-17 15:38:06 +0100251 }
252 }
253
Michal Vaskob36053d2020-03-26 15:49:30 +0100254 /* parser next */
255 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100256
Michal Vaskob36053d2020-03-26 15:49:30 +0100257 /* skip any children, resursively */
258 parents_count = xmlctx->elements.count;
259 while ((parents_count < xmlctx->elements.count) || (xmlctx->status == LYXML_ELEMENT)) {
260 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
261 }
262
263 /* parser next, but do not parse closing element of the list because it would remove its namespaces */
264 assert(xmlctx->status == LYXML_ELEM_CLOSE);
265 LY_CHECK_GOTO(ret = lyxml_ctx_peek(xmlctx, &next), cleanup);
266 if (next != LYXML_ELEM_CLOSE) {
267 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
268 }
Michal Vasko44685da2020-03-17 15:38:06 +0100269 }
270
271 if (key_set.count) {
Michal Vaskob36053d2020-03-26 15:49:30 +0100272 /* some keys are missing/did not validate */
Michal Vasko44685da2020-03-17 15:38:06 +0100273 ret = LY_ENOT;
Michal Vasko44685da2020-03-17 15:38:06 +0100274 }
275
276cleanup:
277 ly_set_erase(&key_set, NULL);
278 return ret;
279}
280
Michal Vasko1bf09392020-03-27 12:38:10 +0100281static LY_ERR
282lydxml_data_skip(struct lyxml_ctx *xmlctx)
283{
284 uint32_t parents_count;
285
286 /* remember current number of parents */
287 parents_count = xmlctx->elements.count;
288
289 /* skip after the content */
290 while (xmlctx->status != LYXML_ELEM_CONTENT) {
291 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
292 }
293 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
294
295 /* skip all children elements, recursively, if any */
296 while (parents_count < xmlctx->elements.count) {
297 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
298 }
299
300 /* close element */
301 assert(xmlctx->status == LYXML_ELEM_CLOSE);
302 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
303
304 return LY_SUCCESS;
305}
306
307static LY_ERR
308lydxml_data_check_schema(struct lyd_xml_ctx *lydctx, const struct lysc_node **snode)
309{
310 LY_ERR ret = LY_SUCCESS;
311 enum LYXML_PARSER_STATUS prev_status;
312 const char *prev_input, *pname, *pprefix;
313 size_t pprefix_len, pname_len;
314 struct lyxml_ctx *xmlctx = lydctx->xmlctx;
315
316 if ((lydctx->options & LYD_OPT_NO_STATE) && ((*snode)->flags & LYS_CONFIG_R)) {
Michal Vaskocb7526d2020-03-30 15:08:26 +0200317 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LY_VCODE_INNODE, "state", (*snode)->name);
Michal Vasko1bf09392020-03-27 12:38:10 +0100318 return LY_EVALID;
319 }
320
321 if ((*snode)->nodetype & (LYS_RPC | LYS_ACTION)) {
322 if (lydctx->int_opts & LYD_INTOPT_RPC) {
323 if (lydctx->op_ntf) {
324 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_DATA, "Unexpected %s element \"%s\", %s \"%s\" already parsed.",
325 lys_nodetype2str((*snode)->nodetype), (*snode)->name,
326 lys_nodetype2str(lydctx->op_ntf->schema->nodetype), lydctx->op_ntf->schema->name);
327 return LY_EVALID;
328 }
329 } else {
330 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_DATA, "Unexpected %s element \"%s\".",
331 lys_nodetype2str((*snode)->nodetype), (*snode)->name);
332 return LY_EVALID;
333 }
334 } else if ((*snode)->nodetype == LYS_NOTIF) {
335 if (lydctx->int_opts & LYD_INTOPT_NOTIF) {
336 if (lydctx->op_ntf) {
337 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_DATA, "Unexpected %s element \"%s\", %s \"%s\" already parsed.",
338 lys_nodetype2str((*snode)->nodetype), (*snode)->name,
339 lys_nodetype2str(lydctx->op_ntf->schema->nodetype), lydctx->op_ntf->schema->name);
340 return LY_EVALID;
341 }
342 } else {
343 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_DATA, "Unexpected %s element \"%s\".",
344 lys_nodetype2str((*snode)->nodetype), (*snode)->name);
345 return LY_EVALID;
346 }
347 }
348
349 if ((lydctx->options & LYD_OPT_OPAQ) && ((*snode)->nodetype & (LYD_NODE_TERM | LYS_LIST))) {
350 /* backup parser */
351 prev_status = xmlctx->status;
352 pprefix = xmlctx->prefix;
353 pprefix_len = xmlctx->prefix_len;
354 pname = xmlctx->name;
355 pname_len = xmlctx->name_len;
356 prev_input = xmlctx->input;
357 if ((xmlctx->status == LYXML_ELEM_CONTENT) && xmlctx->dynamic) {
358 /* it was backed up, do not free */
359 xmlctx->dynamic = 0;
360 }
361
362 /* skip attributes */
363 while (xmlctx->status == LYXML_ATTRIBUTE) {
364 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), restore);
365 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), restore);
366 }
367
368 if ((*snode)->nodetype & LYD_NODE_TERM) {
369 /* value may not be valid in which case we parse it as an opaque node */
370 if (lys_value_validate(NULL, *snode, xmlctx->value, xmlctx->value_len, lydxml_resolve_prefix, xmlctx, LYD_XML)) {
371 *snode = NULL;
372 }
373 } else {
374 /* skip content */
375 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), restore);
376
377 if (lydxml_check_list(xmlctx, *snode)) {
378 /* invalid list, parse as opaque if it missing/has invalid some keys */
379 *snode = NULL;
380 }
381 }
382
383restore:
384 /* restore parser */
385 if (xmlctx->dynamic) {
386 free((char *)xmlctx->value);
387 }
388 xmlctx->status = prev_status;
389 xmlctx->prefix = pprefix;
390 xmlctx->prefix_len = pprefix_len;
391 xmlctx->name = pname;
392 xmlctx->name_len = pname_len;
393 xmlctx->input = prev_input;
394 }
395
396 return ret;
397}
398
Radek Krejcie7b95092019-05-15 11:03:07 +0200399/**
Michal Vasko9f96a052020-03-10 09:41:45 +0100400 * @brief Parse XML elements as YANG data node children the specified parent node.
Radek Krejcie7b95092019-05-15 11:03:07 +0200401 *
Michal Vaskob36053d2020-03-26 15:49:30 +0100402 * @param[in] lydctx XML YANG data parser context.
Radek Krejcie7b95092019-05-15 11:03:07 +0200403 * @param[in] parent Parent node where the children are inserted. NULL in case of parsing top-level elements.
Radek Krejcie7b95092019-05-15 11:03:07 +0200404 * @param[out] node Resulting list of the parsed nodes.
Michal Vasko9b368d32020-02-14 13:53:31 +0100405 * @return LY_ERR value.
Radek Krejcie7b95092019-05-15 11:03:07 +0200406 */
407static LY_ERR
Michal Vasko1bf09392020-03-27 12:38:10 +0100408lydxml_data_r(struct lyd_xml_ctx *lydctx, struct lyd_node_inner *parent, struct lyd_node **first)
Radek Krejcie7b95092019-05-15 11:03:07 +0200409{
Michal Vaskob36053d2020-03-26 15:49:30 +0100410 LY_ERR ret = LY_SUCCESS;
Michal Vasko1bf09392020-03-27 12:38:10 +0100411 const char *prefix, *name;
412 size_t prefix_len, name_len;
Michal Vaskob36053d2020-03-26 15:49:30 +0100413 struct lyxml_ctx *xmlctx;
414 const struct ly_ctx *ctx;
Radek Krejcie7b95092019-05-15 11:03:07 +0200415 const struct lyxml_ns *ns;
Michal Vasko5ab0d5c2020-06-29 11:48:05 +0200416 struct lyd_meta *meta = NULL, *m;
417 struct ly_attr *attr = NULL, *a;
Radek Krejcie7b95092019-05-15 11:03:07 +0200418 const struct lysc_node *snode;
419 struct lys_module *mod;
Michal Vasko1bf09392020-03-27 12:38:10 +0100420 uint32_t prev_opts;
Michal Vasko52927e22020-03-16 17:26:14 +0100421 struct lyd_node *cur = NULL, *anchor;
422 struct ly_prefix *val_prefs;
Michal Vasko1ce933a2020-03-30 12:38:22 +0200423 int getnext_opts;
Radek Krejcie7b95092019-05-15 11:03:07 +0200424
Michal Vaskob36053d2020-03-26 15:49:30 +0100425 xmlctx = lydctx->xmlctx;
426 ctx = xmlctx->ctx;
Michal Vasko1ce933a2020-03-30 12:38:22 +0200427 /* leave if-feature check for validation */
428 getnext_opts = LYS_GETNEXT_NOSTATECHECK | (lydctx->int_opts & LYD_INTOPT_REPLY ? LYS_GETNEXT_OUTPUT : 0);
Michal Vasko6f4cbb62020-02-28 11:15:47 +0100429
Michal Vaskob36053d2020-03-26 15:49:30 +0100430 while (xmlctx->status == LYXML_ELEMENT) {
431 /* remember element prefix and name */
432 prefix = xmlctx->prefix;
433 prefix_len = xmlctx->prefix_len;
434 name = xmlctx->name;
435 name_len = xmlctx->name_len;
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200436
Michal Vaskob36053d2020-03-26 15:49:30 +0100437 /* get the element module */
438 ns = lyxml_ns_get(xmlctx, prefix, prefix_len);
Radek Krejcie7b95092019-05-15 11:03:07 +0200439 if (!ns) {
Michal Vaskob36053d2020-03-26 15:49:30 +0100440 LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".",
441 prefix_len, prefix);
Michal Vasko90932a92020-02-12 14:33:03 +0100442 ret = LY_EVALID;
443 goto cleanup;
Radek Krejcie7b95092019-05-15 11:03:07 +0200444 }
Michal Vaskob36053d2020-03-26 15:49:30 +0100445 mod = ly_ctx_get_module_implemented_ns(ctx, ns->uri);
Michal Vaskoaa7f4fa2020-06-22 10:03:53 +0200446 if (!mod) {
447 if (lydctx->options & LYD_OPT_STRICT) {
448 LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "No module with namespace \"%s\" in the context.",
449 ns->uri);
450 ret = LY_EVALID;
451 goto cleanup;
452 }
Michal Vasko2acb5a62020-06-23 13:23:53 +0200453 if (!(lydctx->options & LYD_OPT_OPAQ)) {
454 /* skip element with children */
455 LY_CHECK_GOTO(ret = lydxml_data_skip(xmlctx), cleanup);
456 continue;
457 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200458 }
Michal Vasko52927e22020-03-16 17:26:14 +0100459
Michal Vasko1bf09392020-03-27 12:38:10 +0100460 /* parser next */
461 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
462
Michal Vaskob36053d2020-03-26 15:49:30 +0100463 /* get the schema node */
Michal Vasko52927e22020-03-16 17:26:14 +0100464 snode = NULL;
465 if (mod && (!parent || parent->schema)) {
Michal Vasko1ce933a2020-03-30 12:38:22 +0200466 snode = lys_find_child(parent ? parent->schema : NULL, mod, name, name_len, 0, getnext_opts);
Michal Vaskob36053d2020-03-26 15:49:30 +0100467 if (!snode) {
468 if (lydctx->options & LYD_OPT_STRICT) {
469 LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Element \"%.*s\" not found in the \"%s\" module.",
470 name_len, name, mod->name);
471 ret = LY_EVALID;
472 goto cleanup;
473 } else if (!(lydctx->options & LYD_OPT_OPAQ)) {
Michal Vasko1bf09392020-03-27 12:38:10 +0100474 /* skip element with children */
475 LY_CHECK_GOTO(ret = lydxml_data_skip(xmlctx), cleanup);
Michal Vaskob36053d2020-03-26 15:49:30 +0100476 continue;
477 }
Michal Vaskob36053d2020-03-26 15:49:30 +0100478 } else {
Michal Vasko1bf09392020-03-27 12:38:10 +0100479 /* check that schema node is valid and can be used */
480 LY_CHECK_GOTO(ret = lydxml_data_check_schema(lydctx, &snode), cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100481 }
482 }
483
Michal Vaskob36053d2020-03-26 15:49:30 +0100484 /* create metadata/attributes */
485 if (xmlctx->status == LYXML_ATTRIBUTE) {
Michal Vasko52927e22020-03-16 17:26:14 +0100486 if (snode) {
Michal Vaskob36053d2020-03-26 15:49:30 +0100487 ret = lydxml_metadata(xmlctx, snode, lydctx->options & LYD_OPT_STRICT, &lydctx->unres_meta_type, &meta);
Michal Vasko52927e22020-03-16 17:26:14 +0100488 LY_CHECK_GOTO(ret, cleanup);
489 } else {
Michal Vaskob36053d2020-03-26 15:49:30 +0100490 assert(lydctx->options & LYD_OPT_OPAQ);
491 ret = lydxml_attrs(xmlctx, &attr);
492 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko52927e22020-03-16 17:26:14 +0100493 }
Michal Vasko8d544252020-03-02 10:19:52 +0100494 }
495
Michal Vaskob36053d2020-03-26 15:49:30 +0100496 assert(xmlctx->status == LYXML_ELEM_CONTENT);
Michal Vasko52927e22020-03-16 17:26:14 +0100497 if (!snode) {
Michal Vaskob36053d2020-03-26 15:49:30 +0100498 assert(lydctx->options & LYD_OPT_OPAQ);
Michal Vasko52927e22020-03-16 17:26:14 +0100499
Michal Vaskob36053d2020-03-26 15:49:30 +0100500 if (xmlctx->ws_only) {
501 /* ignore WS-only value */
502 xmlctx->value_len = 0;
503 val_prefs = NULL;
Michal Vasko52927e22020-03-16 17:26:14 +0100504 } else {
Michal Vaskob36053d2020-03-26 15:49:30 +0100505 /* get value prefixes */
506 ret = lyxml_get_prefixes(xmlctx, xmlctx->value, xmlctx->value_len, &val_prefs);
Michal Vasko52927e22020-03-16 17:26:14 +0100507 LY_CHECK_GOTO(ret, cleanup);
Radek Krejcie7b95092019-05-15 11:03:07 +0200508 }
Michal Vasko90932a92020-02-12 14:33:03 +0100509
510 /* create node */
Michal Vaskob36053d2020-03-26 15:49:30 +0100511 ret = lyd_create_opaq(ctx, name, name_len, xmlctx->value, xmlctx->value_len, &xmlctx->dynamic, LYD_XML,
512 val_prefs, prefix, prefix_len, ns->uri, &cur);
513 LY_CHECK_GOTO(ret, cleanup);
514
515 /* parser next */
516 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
517
518 /* process children */
519 if (xmlctx->status == LYXML_ELEMENT) {
Michal Vasko1bf09392020-03-27 12:38:10 +0100520 ret = lydxml_data_r(lydctx, (struct lyd_node_inner *)cur, lyd_node_children_p(cur));
Michal Vaskob36053d2020-03-26 15:49:30 +0100521 LY_CHECK_GOTO(ret, cleanup);
522 }
523 } else if (snode->nodetype & LYD_NODE_TERM) {
524 /* create node */
525 ret = lyd_create_term(snode, xmlctx->value, xmlctx->value_len, &xmlctx->dynamic, lydxml_resolve_prefix,
526 xmlctx, LYD_XML, &cur);
Radek Krejcie553e6d2019-06-07 15:33:18 +0200527 if (ret == LY_EINCOMPLETE) {
Michal Vaskob36053d2020-03-26 15:49:30 +0100528 if (!(lydctx->options & LYD_OPT_PARSE_ONLY)) {
529 ly_set_add(&lydctx->unres_node_type, cur, LY_SET_OPT_USEASLIST);
Michal Vasko9b368d32020-02-14 13:53:31 +0100530 }
Radek Krejcie553e6d2019-06-07 15:33:18 +0200531 } else if (ret) {
Radek Krejcie553e6d2019-06-07 15:33:18 +0200532 goto cleanup;
533 }
Michal Vasko9b368d32020-02-14 13:53:31 +0100534
535 if (parent && (cur->schema->flags & LYS_KEY)) {
536 /* check the key order, the anchor must always be the last child */
Michal Vasko52927e22020-03-16 17:26:14 +0100537 anchor = lyd_get_prev_key_anchor(parent->child, cur->schema);
538 if ((!anchor && parent->child) || (anchor && anchor->next)) {
Michal Vaskob36053d2020-03-26 15:49:30 +0100539 if (lydctx->options & LYD_OPT_STRICT) {
540 LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_DATA, "Invalid position of the key \"%s\" in a list.",
Michal Vasko9b368d32020-02-14 13:53:31 +0100541 cur->schema->name);
542 ret = LY_EVALID;
543 goto cleanup;
544 } else {
Michal Vaskob36053d2020-03-26 15:49:30 +0100545 LOGWRN(ctx, "Invalid position of the key \"%s\" in a list.", cur->schema->name);
Michal Vasko9b368d32020-02-14 13:53:31 +0100546 }
547 }
548 }
Michal Vaskob36053d2020-03-26 15:49:30 +0100549
550 /* parser next */
551 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
552
553 /* no children expected */
554 if (xmlctx->status == LYXML_ELEMENT) {
Michal Vasko1bf09392020-03-27 12:38:10 +0100555 LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_SYNTAX, "Child element \"%.*s\" inside a terminal node \"%s\" found.",
556 xmlctx->name_len, xmlctx->name, snode->name);
Michal Vasko44685da2020-03-17 15:38:06 +0100557 ret = LY_EVALID;
558 goto cleanup;
Michal Vaskob36053d2020-03-26 15:49:30 +0100559 }
560 } else if (snode->nodetype & LYD_NODE_INNER) {
561 if (!xmlctx->ws_only) {
562 /* value in inner node */
Michal Vasko1bf09392020-03-27 12:38:10 +0100563 LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_SYNTAX, "Text value \"%.*s\" inside an inner node \"%s\" found.",
564 xmlctx->value_len, xmlctx->value, snode->name);
Michal Vaskob36053d2020-03-26 15:49:30 +0100565 ret = LY_EVALID;
566 goto cleanup;
Radek Krejcie7b95092019-05-15 11:03:07 +0200567 }
Michal Vasko90932a92020-02-12 14:33:03 +0100568
569 /* create node */
570 ret = lyd_create_inner(snode, &cur);
571 LY_CHECK_GOTO(ret, cleanup);
572
Michal Vaskob36053d2020-03-26 15:49:30 +0100573 /* parser next */
574 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
575
Radek Krejciee4cab22019-07-17 17:07:47 +0200576 /* process children */
Michal Vaskob36053d2020-03-26 15:49:30 +0100577 if (xmlctx->status == LYXML_ELEMENT) {
Michal Vasko1bf09392020-03-27 12:38:10 +0100578 ret = lydxml_data_r(lydctx, (struct lyd_node_inner *)cur, lyd_node_children_p(cur));
Michal Vasko9f96a052020-03-10 09:41:45 +0100579 LY_CHECK_GOTO(ret, cleanup);
580 }
581
582 if (snode->nodetype == LYS_LIST) {
583 /* check all keys exist */
Michal Vasko44685da2020-03-17 15:38:06 +0100584 LY_CHECK_GOTO(ret = lyd_parse_check_keys(cur), cleanup);
Radek Krejcie7b95092019-05-15 11:03:07 +0200585 }
Michal Vasko9b368d32020-02-14 13:53:31 +0100586
Michal Vaskob36053d2020-03-26 15:49:30 +0100587 if (!(lydctx->options & LYD_OPT_PARSE_ONLY)) {
Michal Vaskob1b5c262020-03-05 14:29:47 +0100588 /* new node validation, autodelete CANNOT occur, all nodes are new */
589 ret = lyd_validate_new(lyd_node_children_p(cur), snode, NULL);
590 LY_CHECK_GOTO(ret, cleanup);
591
Michal Vasko9b368d32020-02-14 13:53:31 +0100592 /* add any missing default children */
Michal Vaskob1b5c262020-03-05 14:29:47 +0100593 ret = lyd_validate_defaults_r((struct lyd_node_inner *)cur, lyd_node_children_p(cur), NULL, NULL,
Michal Vaskob36053d2020-03-26 15:49:30 +0100594 &lydctx->unres_node_type, &lydctx->when_check, lydctx->options);
Michal Vasko9b368d32020-02-14 13:53:31 +0100595 LY_CHECK_GOTO(ret, cleanup);
596 }
597
Michal Vasko9b368d32020-02-14 13:53:31 +0100598 if (snode->nodetype == LYS_LIST) {
Michal Vasko1bf09392020-03-27 12:38:10 +0100599 /* hash now that all keys should be parsed, rehash for key-less list */
Michal Vasko9b368d32020-02-14 13:53:31 +0100600 lyd_hash(cur);
Michal Vasko1bf09392020-03-27 12:38:10 +0100601 } else if (snode->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) {
602 /* rememeber the RPC/action/notification */
603 lydctx->op_ntf = cur;
Michal Vasko9b368d32020-02-14 13:53:31 +0100604 }
Radek Krejciee4cab22019-07-17 17:07:47 +0200605 } else if (snode->nodetype & LYD_NODE_ANY) {
Michal Vaskob36053d2020-03-26 15:49:30 +0100606 if (!xmlctx->ws_only) {
607 /* value in inner node */
Michal Vasko1bf09392020-03-27 12:38:10 +0100608 LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_SYNTAX, "Text value \"%.*s\" inside an any node \"%s\" found.",
609 xmlctx->value_len, xmlctx->value, snode->name);
Michal Vaskob36053d2020-03-26 15:49:30 +0100610 ret = LY_EVALID;
611 goto cleanup;
Radek Krejciee4cab22019-07-17 17:07:47 +0200612 }
Michal Vasko90932a92020-02-12 14:33:03 +0100613
Michal Vaskob36053d2020-03-26 15:49:30 +0100614 /* parser next */
615 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
616
Michal Vasko52927e22020-03-16 17:26:14 +0100617 /* parse any data tree with correct options */
Michal Vaskob36053d2020-03-26 15:49:30 +0100618 prev_opts = lydctx->options;
619 lydctx->options &= ~LYD_OPT_STRICT;
620 lydctx->options |= LYD_OPT_OPAQ;
Michal Vasko52927e22020-03-16 17:26:14 +0100621 anchor = NULL;
Michal Vasko1bf09392020-03-27 12:38:10 +0100622 ret = lydxml_data_r(lydctx, NULL, &anchor);
Michal Vaskob36053d2020-03-26 15:49:30 +0100623 lydctx->options = prev_opts;
Michal Vasko52927e22020-03-16 17:26:14 +0100624 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko90932a92020-02-12 14:33:03 +0100625
626 /* create node */
Michal Vasko52927e22020-03-16 17:26:14 +0100627 ret = lyd_create_any(snode, anchor, LYD_ANYDATA_DATATREE, &cur);
628 LY_CHECK_GOTO(ret, cleanup);
Radek Krejcie7b95092019-05-15 11:03:07 +0200629 }
Michal Vasko1bf09392020-03-27 12:38:10 +0100630 assert(cur);
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200631
Michal Vasko1bf09392020-03-27 12:38:10 +0100632 /* add/correct flags */
Michal Vasko52927e22020-03-16 17:26:14 +0100633 if (snode) {
Michal Vasko60ea6352020-06-29 13:39:39 +0200634 lyd_parse_set_data_flags(cur, &lydctx->when_check, &meta, lydctx->options);
Michal Vasko8d544252020-03-02 10:19:52 +0100635 }
636
Michal Vasko52927e22020-03-16 17:26:14 +0100637 /* add metadata/attributes */
638 if (snode) {
Michal Vasko5ab0d5c2020-06-29 11:48:05 +0200639 LY_LIST_FOR(meta, m) {
640 m->parent = cur;
641 }
Michal Vasko52927e22020-03-16 17:26:14 +0100642 cur->meta = meta;
643 meta = NULL;
644 } else {
645 assert(!cur->schema);
Michal Vasko5ab0d5c2020-06-29 11:48:05 +0200646 LY_LIST_FOR(attr, a) {
647 a->parent = (struct lyd_node_opaq *)cur;
648 }
Michal Vasko52927e22020-03-16 17:26:14 +0100649 ((struct lyd_node_opaq *)cur)->attr = attr;
650 attr = NULL;
651 }
Radek Krejcib6f7ae52019-07-19 10:31:42 +0200652
Michal Vasko90932a92020-02-12 14:33:03 +0100653 /* insert */
Michal Vaskob1b5c262020-03-05 14:29:47 +0100654 lyd_insert_node((struct lyd_node *)parent, first, cur);
Michal Vasko90932a92020-02-12 14:33:03 +0100655 cur = NULL;
Michal Vaskob36053d2020-03-26 15:49:30 +0100656
657 /* parser next */
658 assert(xmlctx->status == LYXML_ELEM_CLOSE);
659 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Radek Krejcie7b95092019-05-15 11:03:07 +0200660 }
661
Michal Vasko90932a92020-02-12 14:33:03 +0100662 /* success */
663 ret = LY_SUCCESS;
664
Radek Krejcie7b95092019-05-15 11:03:07 +0200665cleanup:
Michal Vaskob36053d2020-03-26 15:49:30 +0100666 lyd_free_meta(ctx, meta, 1);
667 ly_free_attr(ctx, attr, 1);
Michal Vasko90932a92020-02-12 14:33:03 +0100668 lyd_free_tree(cur);
Michal Vaskob1b5c262020-03-05 14:29:47 +0100669 if (ret && *first) {
670 lyd_free_siblings(*first);
671 *first = NULL;
Michal Vasko90932a92020-02-12 14:33:03 +0100672 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200673 return ret;
674}
675
676LY_ERR
Michal Vasko1bf09392020-03-27 12:38:10 +0100677lyd_parse_xml_data(const struct ly_ctx *ctx, const char *data, int options, struct lyd_node **tree)
Radek Krejcie7b95092019-05-15 11:03:07 +0200678{
Radek Krejci18a57d92019-07-25 14:01:42 +0200679 LY_ERR ret = LY_SUCCESS;
Michal Vaskob36053d2020-03-26 15:49:30 +0100680 struct lyd_xml_ctx lydctx = {0};
Michal Vaskob1b5c262020-03-05 14:29:47 +0100681 uint32_t i = 0;
682 const struct lys_module *mod;
683 struct lyd_node *first, *next, **first2;
Radek Krejcie7b95092019-05-15 11:03:07 +0200684
Michal Vaskob36053d2020-03-26 15:49:30 +0100685 /* init context and tree */
686 LY_CHECK_GOTO(ret = lyxml_ctx_new(ctx, data, &lydctx.xmlctx), cleanup);
687 lydctx.options = options;
Michal Vaskob1b5c262020-03-05 14:29:47 +0100688 *tree = NULL;
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200689
Michal Vaskob1b5c262020-03-05 14:29:47 +0100690 /* parse XML data */
Michal Vasko1bf09392020-03-27 12:38:10 +0100691 LY_CHECK_GOTO(ret = lydxml_data_r(&lydctx, NULL, tree), cleanup);
Michal Vaskocde73ac2019-11-14 16:10:27 +0100692
Michal Vasko9b368d32020-02-14 13:53:31 +0100693 if (!(options & LYD_OPT_PARSE_ONLY)) {
Michal Vaskob1b5c262020-03-05 14:29:47 +0100694 next = *tree;
695 while (1) {
696 if (options & LYD_VALOPT_DATA_ONLY) {
697 mod = lyd_data_next_module(&next, &first);
698 } else {
699 mod = lyd_mod_next_module(next, NULL, 0, ctx, &i, &first);
700 }
701 if (!mod) {
702 break;
703 }
704 if (first == *tree) {
705 /* make sure first2 changes are carried to tree */
706 first2 = tree;
707 } else {
708 first2 = &first;
709 }
Michal Vasko9b368d32020-02-14 13:53:31 +0100710
Michal Vaskob1b5c262020-03-05 14:29:47 +0100711 /* validate new top-level nodes, autodelete CANNOT occur, all nodes are new */
Michal Vasko1bf09392020-03-27 12:38:10 +0100712 LY_CHECK_GOTO(ret = lyd_validate_new(first2, NULL, mod), cleanup);
Michal Vasko9b368d32020-02-14 13:53:31 +0100713
Michal Vaskob1b5c262020-03-05 14:29:47 +0100714 /* add all top-level defaults for this module */
Michal Vaskob36053d2020-03-26 15:49:30 +0100715 ret = lyd_validate_defaults_r(NULL, first2, NULL, mod, &lydctx.unres_node_type, &lydctx.when_check,
Michal Vasko52927e22020-03-16 17:26:14 +0100716 options & LYD_VALOPT_MASK);
Michal Vaskob1b5c262020-03-05 14:29:47 +0100717 LY_CHECK_GOTO(ret, cleanup);
718
719 /* finish incompletely validated terminal values/attributes and when conditions */
Michal Vaskob36053d2020-03-26 15:49:30 +0100720 ret = lyd_validate_unres(tree, &lydctx.when_check, &lydctx.unres_node_type, &lydctx.unres_meta_type, LYD_XML,
721 lydxml_resolve_prefix, lydctx.xmlctx);
Michal Vaskob1b5c262020-03-05 14:29:47 +0100722 LY_CHECK_GOTO(ret, cleanup);
723
724 /* perform final validation that assumes the data tree is final */
Michal Vaskofea12c62020-03-30 11:00:15 +0200725 LY_CHECK_GOTO(ret = lyd_validate_final_r(*first2, NULL, mod, options & LYD_VALOPT_MASK), cleanup);
Michal Vaskob1b5c262020-03-05 14:29:47 +0100726 }
Michal Vaskocde73ac2019-11-14 16:10:27 +0100727 }
728
Michal Vaskocde73ac2019-11-14 16:10:27 +0100729cleanup:
Michal Vasko9b368d32020-02-14 13:53:31 +0100730 /* there should be no unresolved types stored */
Michal Vaskob36053d2020-03-26 15:49:30 +0100731 assert(!(options & LYD_OPT_PARSE_ONLY) || (!lydctx.unres_node_type.count && !lydctx.unres_meta_type.count
732 && !lydctx.when_check.count));
Michal Vasko9b368d32020-02-14 13:53:31 +0100733
Michal Vaskob36053d2020-03-26 15:49:30 +0100734 ly_set_erase(&lydctx.unres_node_type, NULL);
735 ly_set_erase(&lydctx.unres_meta_type, NULL);
736 ly_set_erase(&lydctx.when_check, NULL);
737 lyxml_ctx_free(lydctx.xmlctx);
Michal Vasko9f96a052020-03-10 09:41:45 +0100738 if (ret) {
739 lyd_free_all(*tree);
740 *tree = NULL;
741 }
742 return ret;
743}
Michal Vasko1bf09392020-03-27 12:38:10 +0100744
745static LY_ERR
746lydxml_envelope(struct lyxml_ctx *xmlctx, const char *name, const char *uri, struct lyd_node **envp)
747{
748 LY_ERR ret = LY_SUCCESS;
749 const struct lyxml_ns *ns = NULL;
750 struct ly_attr *attr = NULL;
751 const char *prefix;
752 size_t prefix_len;
753
754 *envp = NULL;
755
756 assert(xmlctx->status == LYXML_ELEMENT);
757 if (ly_strncmp(name, xmlctx->name, xmlctx->name_len)) {
758 /* not the expected element */
759 return LY_SUCCESS;
760 }
761
762 prefix = xmlctx->prefix;
763 prefix_len = xmlctx->prefix_len;
764 ns = lyxml_ns_get(xmlctx, prefix, prefix_len);
765 if (!ns) {
766 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".",
767 prefix_len, prefix);
768 return LY_EVALID;
769 } else if (strcmp(ns->uri, uri)) {
770 /* different namespace */
771 return LY_SUCCESS;
772 }
773
774 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
775
776 /* create attributes */
777 if (xmlctx->status == LYXML_ATTRIBUTE) {
778 LY_CHECK_RET(lydxml_attrs(xmlctx, &attr));
779 }
780
781 if (!xmlctx->ws_only) {
782 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_SYNTAX, "Unexpected value \"%.*s\" in the \"%s\" element.",
783 xmlctx->value_len, xmlctx->value, name);
784 ret = LY_EVALID;
785 goto cleanup;
786 }
787
788 /* parser next element */
789 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
790
791 /* create node */
792 ret = lyd_create_opaq(xmlctx->ctx, name, strlen(name), "", 0, NULL, LYD_XML, NULL, prefix, prefix_len, uri, envp);
793 LY_CHECK_GOTO(ret, cleanup);
794
795 /* assign atributes */
796 ((struct lyd_node_opaq *)(*envp))->attr = attr;
797 attr = NULL;
798
799cleanup:
800 ly_free_attr(xmlctx->ctx, attr, 1);
801 return ret;
802}
803
804LY_ERR
805lyd_parse_xml_rpc(const struct ly_ctx *ctx, const char *data, struct lyd_node **tree, struct lyd_node **op)
806{
807 LY_ERR ret = LY_SUCCESS;
808 struct lyd_xml_ctx lydctx = {0};
809 struct lyd_node *rpc_e = NULL, *act_e = NULL;
810
811 /* init */
812 LY_CHECK_GOTO(ret = lyxml_ctx_new(ctx, data, &lydctx.xmlctx), cleanup);
813 lydctx.options = LYD_OPT_PARSE_ONLY | LYD_OPT_STRICT;
814 lydctx.int_opts = LYD_INTOPT_RPC;
815 *tree = NULL;
Michal Vaskocc048b22020-03-27 15:52:38 +0100816 if (op) {
817 *op = NULL;
818 }
Michal Vasko1bf09392020-03-27 12:38:10 +0100819
820 /* parse "rpc", if any */
821 LY_CHECK_GOTO(ret = lydxml_envelope(lydctx.xmlctx, "rpc", "urn:ietf:params:xml:ns:netconf:base:1.0", &rpc_e), cleanup);
822
823 if (rpc_e) {
824 /* parse "action", if any */
825 LY_CHECK_GOTO(ret = lydxml_envelope(lydctx.xmlctx, "action", "urn:ietf:params:xml:ns:yang:1", &act_e), cleanup);
826 }
827
828 /* parse the rest of data normally */
829 LY_CHECK_GOTO(ret = lydxml_data_r(&lydctx, NULL, tree), cleanup);
830
831 /* make sure we have parsed some operation */
832 if (!lydctx.op_ntf) {
833 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_DATA, "Missing the \"rpc\"/\"action\" node.");
834 ret = LY_EVALID;
835 goto cleanup;
836 }
837
838 /* finish XML parsing and check operation type */
839 if (act_e) {
840 if (lydctx.xmlctx->status != LYXML_ELEM_CLOSE) {
841 assert(lydctx.xmlctx->status == LYXML_ELEMENT);
842 LOGVAL(ctx, LY_VLOG_LINE, &lydctx.xmlctx->line, LYVE_SYNTAX, "Unexpected sibling element \"%.*s\" of \"action\".",
843 lydctx.xmlctx->name_len, lydctx.xmlctx->name);
844 ret = LY_EVALID;
845 goto cleanup;
846 } else if (lydctx.op_ntf->schema->nodetype != LYS_ACTION) {
847 LOGVAL(ctx, LY_VLOG_LYD, lydctx.op_ntf, LYVE_DATA, "Unexpected %s element, an \"action\" expected.",
848 lys_nodetype2str(lydctx.op_ntf->schema->nodetype));
849 ret = LY_EVALID;
850 goto cleanup;
851 }
852 LY_CHECK_GOTO(ret = lyxml_ctx_next(lydctx.xmlctx), cleanup);
853 }
854 if (rpc_e) {
855 if (lydctx.xmlctx->status != LYXML_ELEM_CLOSE) {
856 assert(lydctx.xmlctx->status == LYXML_ELEMENT);
857 LOGVAL(ctx, LY_VLOG_LINE, &lydctx.xmlctx->line, LYVE_SYNTAX, "Unexpected sibling element \"%.*s\" of \"rpc\".",
858 lydctx.xmlctx->name_len, lydctx.xmlctx->name);
859 ret = LY_EVALID;
860 goto cleanup;
861 } else if (!act_e && (lydctx.op_ntf->schema->nodetype != LYS_RPC)) {
862 LOGVAL(ctx, LY_VLOG_LYD, lydctx.op_ntf, LYVE_DATA, "Unexpected %s element, an \"rpc\" expected.",
863 lys_nodetype2str(lydctx.op_ntf->schema->nodetype));
864 ret = LY_EVALID;
865 goto cleanup;
866 }
867 LY_CHECK_GOTO(ret = lyxml_ctx_next(lydctx.xmlctx), cleanup);
868 }
869
Michal Vaskocc048b22020-03-27 15:52:38 +0100870 if (op) {
871 *op = lydctx.op_ntf;
872 }
Michal Vasko1bf09392020-03-27 12:38:10 +0100873 assert(*tree);
874 if (act_e) {
875 /* connect to the action */
876 lyd_insert_node(act_e, NULL, *tree);
877 *tree = act_e;
878 }
879 if (rpc_e) {
880 /* connect to the rpc */
881 lyd_insert_node(rpc_e, NULL, *tree);
882 *tree = rpc_e;
883 }
884
885cleanup:
886 /* we have used parse_only flag */
887 assert(!lydctx.unres_node_type.count && !lydctx.unres_meta_type.count && !lydctx.when_check.count);
888 lyxml_ctx_free(lydctx.xmlctx);
889 if (ret) {
890 lyd_free_all(*tree);
891 lyd_free_tree(act_e);
892 lyd_free_tree(rpc_e);
893 *tree = NULL;
Michal Vasko1bf09392020-03-27 12:38:10 +0100894 }
895 return ret;
896}
Michal Vaskoa8edff02020-03-27 14:47:01 +0100897
898static LY_ERR
899lydxml_notif_envelope(struct lyxml_ctx *xmlctx, struct lyd_node **envp)
900{
901 LY_ERR ret = LY_SUCCESS;
902 const struct lyxml_ns *ns = NULL;
903 struct ly_attr *attr = NULL;
904 struct lyd_node *et;
905 const char *prefix;
906 size_t prefix_len;
907
908 *envp = NULL;
909
910 /* container envelope */
911 LY_CHECK_GOTO(ret = lydxml_envelope(xmlctx, "notification", "urn:ietf:params:xml:ns:netconf:notification:1.0",
912 envp), cleanup);
913
914 /* no envelope, fine */
915 if (!*envp) {
916 goto cleanup;
917 }
918
919 /* child "eventTime" */
920 if ((xmlctx->status != LYXML_ELEMENT) || ly_strncmp("eventTime", xmlctx->name, xmlctx->name_len)) {
921 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Missing the \"eventTime\" element.");
922 ret = LY_EVALID;
923 goto cleanup;
924 }
925
926 prefix = xmlctx->prefix;
927 prefix_len = xmlctx->prefix_len;
928 ns = lyxml_ns_get(xmlctx, prefix, prefix_len);
929 if (!ns) {
930 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".",
931 prefix_len, prefix);
932 ret = LY_EVALID;
933 goto cleanup;
934 } else if (strcmp(ns->uri, "urn:ietf:params:xml:ns:netconf:notification:1.0")) {
935 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Invalid namespace \"%s\" of \"eventTime\".",
936 ns->uri);
937 ret = LY_EVALID;
938 goto cleanup;
939 }
940
941 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
942
943 /* create attributes */
944 if (xmlctx->status == LYXML_ATTRIBUTE) {
945 LY_CHECK_RET(lydxml_attrs(xmlctx, &attr));
946 }
947
948 /* validate value */
949 /* TODO */
950 /*if (!xmlctx->ws_only) {
951 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_SYNTAX, "Unexpected value \"%.*s\" in the \"%s\" element.",
952 xmlctx->value_len, xmlctx->value, name);
953 ret = LY_EVALID;
954 goto cleanup;
955 }*/
956
957 /* create node */
958 ret = lyd_create_opaq(xmlctx->ctx, "eventTime", 9, xmlctx->value, xmlctx->value_len, NULL, LYD_XML, NULL,
959 prefix, prefix_len, ns->uri, &et);
960 LY_CHECK_GOTO(ret, cleanup);
961
962 /* assign atributes */
963 ((struct lyd_node_opaq *)et)->attr = attr;
964 attr = NULL;
965
966 /* insert */
967 lyd_insert_node(*envp, NULL, et);
968
969 /* finish parsing */
970 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
971 if (xmlctx->status != LYXML_ELEM_CLOSE) {
972 assert(xmlctx->status == LYXML_ELEMENT);
973 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_SYNTAX, "Unexpected sibling element \"%.*s\" of \"eventTime\".",
974 xmlctx->name_len, xmlctx->name);
975 ret = LY_EVALID;
976 goto cleanup;
977 }
978 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
979
980cleanup:
981 if (ret) {
982 lyd_free_tree(*envp);
983 ly_free_attr(xmlctx->ctx, attr, 1);
984 }
985 return ret;
986}
987
988LY_ERR
989lyd_parse_xml_notif(const struct ly_ctx *ctx, const char *data, struct lyd_node **tree, struct lyd_node **ntf)
990{
991 LY_ERR ret = LY_SUCCESS;
992 struct lyd_xml_ctx lydctx = {0};
993 struct lyd_node *ntf_e = NULL;
994
995 /* init */
996 LY_CHECK_GOTO(ret = lyxml_ctx_new(ctx, data, &lydctx.xmlctx), cleanup);
997 lydctx.options = LYD_OPT_PARSE_ONLY | LYD_OPT_STRICT;
998 lydctx.int_opts = LYD_INTOPT_NOTIF;
999 *tree = NULL;
Michal Vaskocc048b22020-03-27 15:52:38 +01001000 if (ntf) {
1001 *ntf = NULL;
1002 }
Michal Vaskoa8edff02020-03-27 14:47:01 +01001003
1004 /* parse "notification" and "eventTime", if present */
1005 LY_CHECK_GOTO(ret = lydxml_notif_envelope(lydctx.xmlctx, &ntf_e), cleanup);
1006
1007 /* parse the rest of data normally */
1008 LY_CHECK_GOTO(ret = lydxml_data_r(&lydctx, NULL, tree), cleanup);
1009
1010 /* make sure we have parsed some notification */
1011 if (!lydctx.op_ntf) {
1012 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_DATA, "Missing the \"notification\" node.");
1013 ret = LY_EVALID;
1014 goto cleanup;
1015 }
1016
1017 /* finish XML parsing */
1018 if (ntf_e) {
1019 if (lydctx.xmlctx->status != LYXML_ELEM_CLOSE) {
1020 assert(lydctx.xmlctx->status == LYXML_ELEMENT);
1021 LOGVAL(ctx, LY_VLOG_LINE, &lydctx.xmlctx->line, LYVE_SYNTAX, "Unexpected sibling element \"%.*s\" of \"notification\".",
1022 lydctx.xmlctx->name_len, lydctx.xmlctx->name);
1023 ret = LY_EVALID;
1024 goto cleanup;
1025 }
1026 LY_CHECK_GOTO(ret = lyxml_ctx_next(lydctx.xmlctx), cleanup);
1027 }
1028
Michal Vaskocc048b22020-03-27 15:52:38 +01001029 if (ntf) {
1030 *ntf = lydctx.op_ntf;
1031 }
Michal Vaskoa8edff02020-03-27 14:47:01 +01001032 assert(*tree);
1033 if (ntf_e) {
1034 /* connect to the notification */
1035 lyd_insert_node(ntf_e, NULL, *tree);
1036 *tree = ntf_e;
1037 }
1038
1039cleanup:
1040 /* we have used parse_only flag */
1041 assert(!lydctx.unres_node_type.count && !lydctx.unres_meta_type.count && !lydctx.when_check.count);
1042 lyxml_ctx_free(lydctx.xmlctx);
1043 if (ret) {
1044 lyd_free_all(*tree);
1045 lyd_free_tree(ntf_e);
1046 *tree = NULL;
Michal Vaskoa8edff02020-03-27 14:47:01 +01001047 }
1048 return ret;
1049}
Michal Vasko1ce933a2020-03-30 12:38:22 +02001050
1051LY_ERR
1052lyd_parse_xml_reply(const struct lyd_node *request, const char *data, struct lyd_node **tree, struct lyd_node **op)
1053{
1054 LY_ERR ret = LY_SUCCESS;
1055 struct lyd_xml_ctx lydctx = {0};
1056 struct lyd_node *rpcr_e = NULL, *iter, *req_op, *rep_op;
1057
1058 /* init */
1059 LY_CHECK_GOTO(ret = lyxml_ctx_new(LYD_NODE_CTX(request), data, &lydctx.xmlctx), cleanup);
1060 lydctx.options = LYD_OPT_PARSE_ONLY | LYD_OPT_STRICT;
1061 lydctx.int_opts = LYD_INTOPT_REPLY;
1062 *tree = NULL;
1063 if (op) {
1064 *op = NULL;
1065 }
1066
1067 /* find request OP */
1068 LYD_TREE_DFS_BEGIN((struct lyd_node *)request, iter, req_op) {
1069 if (req_op->schema->nodetype & (LYS_RPC | LYS_ACTION)) {
1070 break;
1071 }
1072 LYD_TREE_DFS_END(request, iter, req_op);
1073 }
1074 if (!(req_op->schema->nodetype & (LYS_RPC | LYS_ACTION))) {
1075 LOGERR(LYD_NODE_CTX(request), LY_EINVAL, "No RPC/action in the request found.");
1076 ret = LY_EINVAL;
1077 goto cleanup;
1078 }
1079
1080 /* duplicate request OP with parents */
1081 rep_op = lyd_dup(req_op, NULL, LYD_DUP_WITH_PARENTS);
1082 LY_CHECK_ERR_GOTO(!rep_op, ret = LY_EMEM, cleanup);
1083
1084 /* parse "rpc-reply", if any */
1085 LY_CHECK_GOTO(ret = lydxml_envelope(lydctx.xmlctx, "rpc-reply", "urn:ietf:params:xml:ns:netconf:base:1.0", &rpcr_e), cleanup);
1086
1087 /* parse the rest of data normally but connect them to the duplicated operation */
1088 LY_CHECK_GOTO(ret = lydxml_data_r(&lydctx, (struct lyd_node_inner *)rep_op, lyd_node_children_p(rep_op)), cleanup);
1089
1090 /* finish XML parsing and check operation type */
1091 if (rpcr_e) {
1092 if (lydctx.xmlctx->status != LYXML_ELEM_CLOSE) {
1093 assert(lydctx.xmlctx->status == LYXML_ELEMENT);
1094 LOGVAL(LYD_NODE_CTX(request), LY_VLOG_LINE, &lydctx.xmlctx->line, LYVE_SYNTAX,
1095 "Unexpected sibling element \"%.*s\" of \"rpc-reply\".", lydctx.xmlctx->name_len, lydctx.xmlctx->name);
1096 ret = LY_EVALID;
1097 goto cleanup;
1098 }
1099 LY_CHECK_GOTO(ret = lyxml_ctx_next(lydctx.xmlctx), cleanup);
1100 }
1101
1102 if (op) {
1103 *op = rep_op;
1104 }
1105 for (iter = rep_op; iter->parent; iter = (struct lyd_node *)iter->parent);
1106 *tree = iter;
1107 if (rpcr_e) {
1108 /* connect to the operation */
1109 lyd_insert_node(rpcr_e, NULL, *tree);
1110 *tree = rpcr_e;
1111 }
1112
1113cleanup:
1114 /* we have used parse_only flag */
1115 assert(!lydctx.unres_node_type.count && !lydctx.unres_meta_type.count && !lydctx.when_check.count);
1116 lyxml_ctx_free(lydctx.xmlctx);
1117 if (ret) {
1118 lyd_free_all(rep_op);
1119 lyd_free_tree(rpcr_e);
1120 }
1121 return ret;
1122}