blob: c4f0229a3c7f6720ecd8aa1504cca6aff7b1c68a [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 Krejci7931b192020-06-25 17:05:03 +020023#include "parser_data.h"
24#include "parser_internal.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020025#include "set.h"
Radek Krejci535ea9f2020-05-29 16:01:05 +020026#include "tree.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020027#include "tree_data_internal.h"
28#include "tree_schema.h"
Michal Vaskocde73ac2019-11-14 16:10:27 +010029#include "validation.h"
Radek Krejci535ea9f2020-05-29 16:01:05 +020030#include "xml.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020031
32/**
Michal Vaskob36053d2020-03-26 15:49:30 +010033 * @brief Internal context for XML YANG data parser.
Radek Krejci1798aae2020-07-14 13:26:06 +020034 *
35 * Note that the structure maps to the lyd_ctx which is common for all the data parsers
Radek Krejcie7b95092019-05-15 11:03:07 +020036 */
37struct lyd_xml_ctx {
Radek Krejci1798aae2020-07-14 13:26:06 +020038 uint32_t parse_options; /**< various @ref dataparseroptions. */
39 uint32_t validate_options; /**< various @ref datavalidationoptions. */
40 uint32_t int_opts; /**< internal data parser options */
41 uint32_t path_len; /**< used bytes in the path buffer */
42 char path[LYD_PARSER_BUFSIZE]; /**< buffer for the generated path */
43 struct ly_set unres_node_type; /**< set of nodes validated with LY_EINCOMPLETE result */
44 struct ly_set unres_meta_type; /**< set of metadata validated with LY_EINCOMPLETE result */
45 struct ly_set when_check; /**< set of nodes with "when" conditions */
46 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 +020047
Radek Krejci1798aae2020-07-14 13:26:06 +020048 /* callbacks */
49 lyd_ctx_free_clb free; /* destructor */
Radek Krejci1798aae2020-07-14 13:26:06 +020050
51 struct lyxml_ctx *xmlctx; /**< XML context */
Radek Krejcie7b95092019-05-15 11:03:07 +020052};
53
Radek Krejci1798aae2020-07-14 13:26:06 +020054void
55lyd_xml_ctx_free(struct lyd_ctx *lydctx)
56{
57 struct lyd_xml_ctx *ctx = (struct lyd_xml_ctx *)lydctx;
58
59 lyd_ctx_free(lydctx);
60 lyxml_ctx_free(ctx->xmlctx);
61 free(ctx);
62}
63
Radek Krejcie7b95092019-05-15 11:03:07 +020064static LY_ERR
Michal Vaskofeca4fb2020-10-05 08:58:40 +020065lydxml_metadata(struct lyd_xml_ctx *lydctx, struct lyd_meta **meta)
Radek Krejcie7b95092019-05-15 11:03:07 +020066{
Michal Vaskob36053d2020-03-26 15:49:30 +010067 LY_ERR ret = LY_EVALID;
Radek Krejci28681fa2019-09-06 13:08:45 +020068 const struct lyxml_ns *ns;
69 struct lys_module *mod;
Michal Vaskob36053d2020-03-26 15:49:30 +010070 const char *name;
71 size_t name_len;
Radek Krejci1798aae2020-07-14 13:26:06 +020072 struct lyxml_ctx *xmlctx = lydctx->xmlctx;
Radek Krejci28681fa2019-09-06 13:08:45 +020073
Michal Vaskob36053d2020-03-26 15:49:30 +010074 *meta = NULL;
Radek Krejci28681fa2019-09-06 13:08:45 +020075
Michal Vaskob36053d2020-03-26 15:49:30 +010076 while (xmlctx->status == LYXML_ATTRIBUTE) {
77 if (!xmlctx->prefix_len) {
Radek Krejci28681fa2019-09-06 13:08:45 +020078 /* in XML, all attributes must be prefixed
79 * TODO exception for NETCONF filters which are supposed to map to the ietf-netconf without prefix */
Radek Krejci1798aae2020-07-14 13:26:06 +020080 if (lydctx->parse_options & LYD_PARSE_STRICT) {
Michal Vasko52927e22020-03-16 17:26:14 +010081 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Missing mandatory prefix for XML metadata \"%.*s\".",
Michal Vaskob36053d2020-03-26 15:49:30 +010082 xmlctx->name_len, xmlctx->name);
83 goto cleanup;
Radek Krejci28681fa2019-09-06 13:08:45 +020084 }
Michal Vaskob36053d2020-03-26 15:49:30 +010085
Radek Krejci28681fa2019-09-06 13:08:45 +020086skip_attr:
Michal Vaskob36053d2020-03-26 15:49:30 +010087 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
88 assert(xmlctx->status == LYXML_ATTR_CONTENT);
89 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Radek Krejci28681fa2019-09-06 13:08:45 +020090 continue;
91 }
92
93 /* get namespace of the attribute to find its annotation definition */
Michal Vaskoc8a230d2020-08-14 12:17:10 +020094 ns = lyxml_ns_get(&xmlctx->ns, xmlctx->prefix, xmlctx->prefix_len);
Radek Krejci28681fa2019-09-06 13:08:45 +020095 if (!ns) {
Michal Vasko52927e22020-03-16 17:26:14 +010096 /* unknown namespace, XML error */
97 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".",
Michal Vaskob36053d2020-03-26 15:49:30 +010098 xmlctx->prefix_len, xmlctx->prefix);
Radek Krejci28681fa2019-09-06 13:08:45 +020099 goto cleanup;
100 }
Michal Vasko52927e22020-03-16 17:26:14 +0100101 mod = ly_ctx_get_module_implemented_ns(xmlctx->ctx, ns->uri);
Radek Krejci28681fa2019-09-06 13:08:45 +0200102 if (!mod) {
103 /* module is not implemented or not present in the schema */
Radek Krejci1798aae2020-07-14 13:26:06 +0200104 if (lydctx->parse_options & LYD_PARSE_STRICT) {
Michal Vasko52927e22020-03-16 17:26:14 +0100105 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE,
Michal Vasko9f96a052020-03-10 09:41:45 +0100106 "Unknown (or not implemented) YANG module with namespace \"%s\" for metadata \"%.*s%s%.*s\".",
Michal Vaskob36053d2020-03-26 15:49:30 +0100107 ns->uri, xmlctx->prefix_len, xmlctx->prefix, xmlctx->prefix_len ? ":" : "", xmlctx->name_len,
108 xmlctx->name);
109 goto cleanup;
Radek Krejci28681fa2019-09-06 13:08:45 +0200110 }
111 goto skip_attr;
112 }
113
Michal Vasko60ea6352020-06-29 13:39:39 +0200114 /* remember meta name and get its content */
Michal Vaskob36053d2020-03-26 15:49:30 +0100115 name = xmlctx->name;
116 name_len = xmlctx->name_len;
117 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
118 assert(xmlctx->status == LYXML_ATTR_CONTENT);
119
120 /* create metadata */
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200121 ret = lyd_parser_create_meta((struct lyd_ctx *)lydctx, NULL, meta, mod, name, name_len, xmlctx->value,
Michal Vaskofeca4fb2020-10-05 08:58:40 +0200122 xmlctx->value_len, &xmlctx->dynamic, LY_PREF_XML, &xmlctx->ns, LYD_HINT_DATA);
Radek Krejci1798aae2020-07-14 13:26:06 +0200123 LY_CHECK_GOTO(ret, cleanup);
Michal Vaskob36053d2020-03-26 15:49:30 +0100124
125 /* next attribute */
126 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Radek Krejcie7b95092019-05-15 11:03:07 +0200127 }
Michal Vasko52927e22020-03-16 17:26:14 +0100128
Radek Krejci28681fa2019-09-06 13:08:45 +0200129 ret = LY_SUCCESS;
Radek Krejcie7b95092019-05-15 11:03:07 +0200130
131cleanup:
Michal Vaskob36053d2020-03-26 15:49:30 +0100132 if (ret) {
Michal Vasko3a41dff2020-07-15 14:30:28 +0200133 lyd_free_meta_siblings(*meta);
Michal Vaskob36053d2020-03-26 15:49:30 +0100134 *meta = NULL;
Radek Krejci38d85362019-09-05 16:26:38 +0200135 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200136 return ret;
137}
138
Michal Vasko52927e22020-03-16 17:26:14 +0100139static LY_ERR
Radek Krejci1798aae2020-07-14 13:26:06 +0200140lydxml_attrs(struct lyxml_ctx *xmlctx, struct lyd_attr **attr)
Michal Vasko52927e22020-03-16 17:26:14 +0100141{
142 LY_ERR ret = LY_SUCCESS;
143 const struct lyxml_ns *ns;
144 struct ly_prefix *val_prefs;
Radek Krejci1798aae2020-07-14 13:26:06 +0200145 struct lyd_attr *attr2;
Michal Vaskob36053d2020-03-26 15:49:30 +0100146 const char *name, *prefix;
147 size_t name_len, prefix_len;
Michal Vasko52927e22020-03-16 17:26:14 +0100148
149 assert(attr);
Michal Vaskob36053d2020-03-26 15:49:30 +0100150 *attr = NULL;
Michal Vasko52927e22020-03-16 17:26:14 +0100151
Michal Vaskob36053d2020-03-26 15:49:30 +0100152 while (xmlctx->status == LYXML_ATTRIBUTE) {
Michal Vasko52927e22020-03-16 17:26:14 +0100153 ns = NULL;
Michal Vaskob36053d2020-03-26 15:49:30 +0100154 if (xmlctx->prefix_len) {
Michal Vasko52927e22020-03-16 17:26:14 +0100155 /* get namespace of the attribute */
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200156 ns = lyxml_ns_get(&xmlctx->ns, xmlctx->prefix, xmlctx->prefix_len);
Michal Vasko52927e22020-03-16 17:26:14 +0100157 if (!ns) {
158 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".",
Michal Vaskob36053d2020-03-26 15:49:30 +0100159 xmlctx->prefix_len, xmlctx->prefix);
Michal Vasko52927e22020-03-16 17:26:14 +0100160 ret = LY_EVALID;
161 goto cleanup;
162 }
163 }
164
165 if (*attr) {
166 attr2 = *attr;
167 } else {
168 attr2 = NULL;
169 }
170
Michal Vaskob36053d2020-03-26 15:49:30 +0100171 /* remember attr prefix, name, and get its content */
172 prefix = xmlctx->prefix;
173 prefix_len = xmlctx->prefix_len;
174 name = xmlctx->name;
175 name_len = xmlctx->name_len;
176 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
177 assert(xmlctx->status == LYXML_ATTR_CONTENT);
178
Michal Vasko52927e22020-03-16 17:26:14 +0100179 /* get value prefixes */
Michal Vaskob36053d2020-03-26 15:49:30 +0100180 LY_CHECK_GOTO(ret = lyxml_get_prefixes(xmlctx, xmlctx->value, xmlctx->value_len, &val_prefs), cleanup);
Michal Vasko52927e22020-03-16 17:26:14 +0100181
182 /* attr2 is always changed to the created attribute */
Radek Krejci1798aae2020-07-14 13:26:06 +0200183 ret = lyd_create_attr(NULL, &attr2, xmlctx->ctx, name, name_len, xmlctx->value, xmlctx->value_len,
Michal Vaskofeca4fb2020-10-05 08:58:40 +0200184 &xmlctx->dynamic, LYD_XML, 0, val_prefs, prefix, prefix_len,
Radek Krejci1798aae2020-07-14 13:26:06 +0200185 ns ? ns->uri : NULL, ns ? strlen(ns->uri) : 0);
Michal Vasko52927e22020-03-16 17:26:14 +0100186 LY_CHECK_GOTO(ret, cleanup);
187
188 if (!*attr) {
189 *attr = attr2;
190 }
Michal Vaskob36053d2020-03-26 15:49:30 +0100191
192 /* next attribute */
193 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko52927e22020-03-16 17:26:14 +0100194 }
195
196cleanup:
Michal Vaskob36053d2020-03-26 15:49:30 +0100197 if (ret) {
Radek Krejci011e4aa2020-09-04 15:22:31 +0200198 lyd_free_attr_siblings(xmlctx->ctx, *attr);
Michal Vaskob36053d2020-03-26 15:49:30 +0100199 *attr = NULL;
Michal Vasko52927e22020-03-16 17:26:14 +0100200 }
Michal Vasko52927e22020-03-16 17:26:14 +0100201 return ret;
202}
203
Michal Vasko44685da2020-03-17 15:38:06 +0100204static LY_ERR
Michal Vaskob36053d2020-03-26 15:49:30 +0100205lydxml_check_list(struct lyxml_ctx *xmlctx, const struct lysc_node *list)
Michal Vasko44685da2020-03-17 15:38:06 +0100206{
Michal Vaskob36053d2020-03-26 15:49:30 +0100207 LY_ERR ret = LY_SUCCESS, r;
208 enum LYXML_PARSER_STATUS next;
Michal Vasko44685da2020-03-17 15:38:06 +0100209 struct ly_set key_set = {0};
210 const struct lysc_node *snode;
Michal Vaskob36053d2020-03-26 15:49:30 +0100211 uint32_t i, parents_count;
Michal Vasko44685da2020-03-17 15:38:06 +0100212
213 assert(list && (list->nodetype == LYS_LIST));
214
215 /* get all keys into a set (keys do not have if-features or anything) */
216 snode = NULL;
217 while ((snode = lys_getnext(snode, list, NULL, LYS_GETNEXT_NOSTATECHECK)) && (snode->flags & LYS_KEY)) {
Radek Krejciba03a5a2020-08-27 14:40:41 +0200218 ret = ly_set_add(&key_set, (void *)snode, LY_SET_OPT_USEASLIST, NULL);
219 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100220 }
221
Michal Vaskob36053d2020-03-26 15:49:30 +0100222 while (xmlctx->status == LYXML_ELEMENT) {
Michal Vasko44685da2020-03-17 15:38:06 +0100223 /* find key definition */
224 for (i = 0; i < key_set.count; ++i) {
225 snode = (const struct lysc_node *)key_set.objs[i];
Michal Vaskob36053d2020-03-26 15:49:30 +0100226 if (!ly_strncmp(snode->name, xmlctx->name, xmlctx->name_len)) {
Michal Vasko44685da2020-03-17 15:38:06 +0100227 break;
228 }
229 }
Michal Vaskob36053d2020-03-26 15:49:30 +0100230 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100231
232 /* skip attributes */
233 while (xmlctx->status == LYXML_ATTRIBUTE) {
Michal Vaskob36053d2020-03-26 15:49:30 +0100234 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
235 assert(xmlctx->status == LYXML_ATTR_CONTENT);
236 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100237 }
238
Michal Vaskob36053d2020-03-26 15:49:30 +0100239 assert(xmlctx->status == LYXML_ELEM_CONTENT);
240 if (i < key_set.count) {
241 /* validate the value */
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200242 r = _lys_value_validate(NULL, snode, xmlctx->value, xmlctx->value_len, LY_PREF_XML, xmlctx);
Michal Vaskob36053d2020-03-26 15:49:30 +0100243 if (!r) {
244 /* key with a valid value, remove from the set */
245 ly_set_rm_index(&key_set, i, NULL);
Michal Vasko44685da2020-03-17 15:38:06 +0100246 }
247 }
248
Michal Vaskob36053d2020-03-26 15:49:30 +0100249 /* parser next */
250 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100251
Michal Vaskob36053d2020-03-26 15:49:30 +0100252 /* skip any children, resursively */
253 parents_count = xmlctx->elements.count;
254 while ((parents_count < xmlctx->elements.count) || (xmlctx->status == LYXML_ELEMENT)) {
255 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
256 }
257
258 /* parser next, but do not parse closing element of the list because it would remove its namespaces */
259 assert(xmlctx->status == LYXML_ELEM_CLOSE);
260 LY_CHECK_GOTO(ret = lyxml_ctx_peek(xmlctx, &next), cleanup);
261 if (next != LYXML_ELEM_CLOSE) {
262 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
263 }
Michal Vasko44685da2020-03-17 15:38:06 +0100264 }
265
266 if (key_set.count) {
Michal Vaskob36053d2020-03-26 15:49:30 +0100267 /* some keys are missing/did not validate */
Michal Vasko44685da2020-03-17 15:38:06 +0100268 ret = LY_ENOT;
Michal Vasko44685da2020-03-17 15:38:06 +0100269 }
270
271cleanup:
272 ly_set_erase(&key_set, NULL);
273 return ret;
274}
275
Michal Vasko1bf09392020-03-27 12:38:10 +0100276static LY_ERR
277lydxml_data_skip(struct lyxml_ctx *xmlctx)
278{
279 uint32_t parents_count;
280
281 /* remember current number of parents */
282 parents_count = xmlctx->elements.count;
283
284 /* skip after the content */
285 while (xmlctx->status != LYXML_ELEM_CONTENT) {
286 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
287 }
288 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
289
290 /* skip all children elements, recursively, if any */
291 while (parents_count < xmlctx->elements.count) {
292 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
293 }
294
295 /* close element */
296 assert(xmlctx->status == LYXML_ELEM_CLOSE);
297 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
298
299 return LY_SUCCESS;
300}
301
302static LY_ERR
Radek Krejci1798aae2020-07-14 13:26:06 +0200303lydxml_data_check_opaq(struct lyd_xml_ctx *lydctx, const struct lysc_node **snode)
Michal Vasko1bf09392020-03-27 12:38:10 +0100304{
305 LY_ERR ret = LY_SUCCESS;
306 enum LYXML_PARSER_STATUS prev_status;
Michal Vasko63f3d842020-07-08 10:10:14 +0200307 const char *prev_current, *pname, *pprefix;
Michal Vasko1bf09392020-03-27 12:38:10 +0100308 size_t pprefix_len, pname_len;
309 struct lyxml_ctx *xmlctx = lydctx->xmlctx;
310
Radek Krejci1798aae2020-07-14 13:26:06 +0200311 if ((lydctx->parse_options & LYD_PARSE_OPAQ) && ((*snode)->nodetype & (LYD_NODE_TERM | LYS_LIST))) {
Michal Vasko1bf09392020-03-27 12:38:10 +0100312 /* backup parser */
313 prev_status = xmlctx->status;
314 pprefix = xmlctx->prefix;
315 pprefix_len = xmlctx->prefix_len;
316 pname = xmlctx->name;
317 pname_len = xmlctx->name_len;
Michal Vasko63f3d842020-07-08 10:10:14 +0200318 prev_current = xmlctx->in->current;
Michal Vasko1bf09392020-03-27 12:38:10 +0100319 if ((xmlctx->status == LYXML_ELEM_CONTENT) && xmlctx->dynamic) {
320 /* it was backed up, do not free */
321 xmlctx->dynamic = 0;
322 }
323
324 /* skip attributes */
325 while (xmlctx->status == LYXML_ATTRIBUTE) {
326 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), restore);
327 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), restore);
328 }
329
330 if ((*snode)->nodetype & LYD_NODE_TERM) {
331 /* value may not be valid in which case we parse it as an opaque node */
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200332 if (_lys_value_validate(NULL, *snode, xmlctx->value, xmlctx->value_len, LY_PREF_XML, &xmlctx->ns)) {
Michal Vasko1bf09392020-03-27 12:38:10 +0100333 *snode = NULL;
334 }
335 } else {
336 /* skip content */
337 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), restore);
338
339 if (lydxml_check_list(xmlctx, *snode)) {
340 /* invalid list, parse as opaque if it missing/has invalid some keys */
341 *snode = NULL;
342 }
343 }
344
345restore:
346 /* restore parser */
347 if (xmlctx->dynamic) {
348 free((char *)xmlctx->value);
349 }
350 xmlctx->status = prev_status;
351 xmlctx->prefix = pprefix;
352 xmlctx->prefix_len = pprefix_len;
353 xmlctx->name = pname;
354 xmlctx->name_len = pname_len;
Michal Vasko63f3d842020-07-08 10:10:14 +0200355 xmlctx->in->current = prev_current;
Michal Vasko1bf09392020-03-27 12:38:10 +0100356 }
357
358 return ret;
359}
360
Radek Krejcie7b95092019-05-15 11:03:07 +0200361/**
Michal Vaskoa5da3292020-08-12 13:10:50 +0200362 * @brief Parse XML subtree.
Radek Krejcie7b95092019-05-15 11:03:07 +0200363 *
Michal Vaskob36053d2020-03-26 15:49:30 +0100364 * @param[in] lydctx XML YANG data parser context.
Radek Krejcie7b95092019-05-15 11:03:07 +0200365 * @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 +0200366 * @param[out] node Resulting list of the parsed nodes.
Michal Vasko9b368d32020-02-14 13:53:31 +0100367 * @return LY_ERR value.
Radek Krejcie7b95092019-05-15 11:03:07 +0200368 */
369static LY_ERR
Michal Vaskoa5da3292020-08-12 13:10:50 +0200370lydxml_subtree_r(struct lyd_xml_ctx *lydctx, struct lyd_node_inner *parent, struct lyd_node **first_p)
Radek Krejcie7b95092019-05-15 11:03:07 +0200371{
Michal Vaskob36053d2020-03-26 15:49:30 +0100372 LY_ERR ret = LY_SUCCESS;
Michal Vasko1bf09392020-03-27 12:38:10 +0100373 const char *prefix, *name;
374 size_t prefix_len, name_len;
Michal Vaskob36053d2020-03-26 15:49:30 +0100375 struct lyxml_ctx *xmlctx;
376 const struct ly_ctx *ctx;
Radek Krejcie7b95092019-05-15 11:03:07 +0200377 const struct lyxml_ns *ns;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200378 struct lyd_meta *meta = NULL;
379 struct lyd_attr *attr = NULL;
Radek Krejcie7b95092019-05-15 11:03:07 +0200380 const struct lysc_node *snode;
381 struct lys_module *mod;
Michal Vasko1bf09392020-03-27 12:38:10 +0100382 uint32_t prev_opts;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200383 struct lyd_node *node = NULL, *anchor;
Michal Vasko52927e22020-03-16 17:26:14 +0100384 struct ly_prefix *val_prefs;
Radek Krejci1deb5be2020-08-26 16:43:36 +0200385 uint32_t getnext_opts;
Radek Krejcie7b95092019-05-15 11:03:07 +0200386
Michal Vaskob36053d2020-03-26 15:49:30 +0100387 xmlctx = lydctx->xmlctx;
388 ctx = xmlctx->ctx;
Michal Vasko1ce933a2020-03-30 12:38:22 +0200389 /* leave if-feature check for validation */
390 getnext_opts = LYS_GETNEXT_NOSTATECHECK | (lydctx->int_opts & LYD_INTOPT_REPLY ? LYS_GETNEXT_OUTPUT : 0);
Michal Vasko6f4cbb62020-02-28 11:15:47 +0100391
Michal Vaskoa5da3292020-08-12 13:10:50 +0200392 assert(xmlctx->status == LYXML_ELEMENT);
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200393
Michal Vaskoa5da3292020-08-12 13:10:50 +0200394 /* remember element prefix and name */
395 prefix = xmlctx->prefix;
396 prefix_len = xmlctx->prefix_len;
397 name = xmlctx->name;
398 name_len = xmlctx->name_len;
399
400 /* get the element module */
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200401 ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200402 if (!ns) {
403 LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".",
404 prefix_len, prefix);
405 ret = LY_EVALID;
406 goto error;
407 }
408 mod = ly_ctx_get_module_implemented_ns(ctx, ns->uri);
409 if (!mod) {
410 if (lydctx->parse_options & LYD_PARSE_STRICT) {
411 LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "No module with namespace \"%s\" in the context.",
412 ns->uri);
Michal Vasko90932a92020-02-12 14:33:03 +0100413 ret = LY_EVALID;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200414 goto error;
Radek Krejcie7b95092019-05-15 11:03:07 +0200415 }
Michal Vaskoa5da3292020-08-12 13:10:50 +0200416 if (!(lydctx->parse_options & LYD_PARSE_OPAQ)) {
417 /* skip element with children */
418 LY_CHECK_GOTO(ret = lydxml_data_skip(xmlctx), error);
419 return LY_SUCCESS;
Radek Krejcie7b95092019-05-15 11:03:07 +0200420 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200421 }
422
Michal Vaskoa5da3292020-08-12 13:10:50 +0200423 /* parser next */
424 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
Michal Vasko90932a92020-02-12 14:33:03 +0100425
Michal Vaskoa5da3292020-08-12 13:10:50 +0200426 /* get the schema node */
427 snode = NULL;
428 if (mod && (!parent || parent->schema)) {
429 snode = lys_find_child(parent ? parent->schema : NULL, mod, name, name_len, 0, getnext_opts);
430 if (!snode) {
431 if (lydctx->parse_options & LYD_PARSE_STRICT) {
432 LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Element \"%.*s\" not found in the \"%s\" module.",
433 name_len, name, mod->name);
434 ret = LY_EVALID;
435 goto error;
436 } else if (!(lydctx->parse_options & LYD_PARSE_OPAQ)) {
437 /* skip element with children */
438 LY_CHECK_GOTO(ret = lydxml_data_skip(xmlctx), error);
439 return LY_SUCCESS;
440 }
441 } else {
442 /* check that schema node is valid and can be used */
443 LY_CHECK_GOTO(ret = lyd_parser_check_schema((struct lyd_ctx *)lydctx, snode), error);
444 LY_CHECK_GOTO(ret = lydxml_data_check_opaq(lydctx, &snode), error);
445 }
446 }
447
448 /* create metadata/attributes */
449 if (xmlctx->status == LYXML_ATTRIBUTE) {
450 if (snode) {
Michal Vaskofeca4fb2020-10-05 08:58:40 +0200451 ret = lydxml_metadata(lydctx, &meta);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200452 LY_CHECK_GOTO(ret, error);
453 } else {
454 assert(lydctx->parse_options & LYD_PARSE_OPAQ);
455 ret = lydxml_attrs(xmlctx, &attr);
456 LY_CHECK_GOTO(ret, error);
457 }
458 }
459
460 assert(xmlctx->status == LYXML_ELEM_CONTENT);
461 if (!snode) {
462 assert(lydctx->parse_options & LYD_PARSE_OPAQ);
463
464 if (xmlctx->ws_only) {
465 /* ignore WS-only value */
466 xmlctx->value_len = 0;
467 val_prefs = NULL;
468 } else {
469 /* get value prefixes */
470 ret = lyxml_get_prefixes(xmlctx, xmlctx->value, xmlctx->value_len, &val_prefs);
471 LY_CHECK_GOTO(ret, error);
472 }
473
474 /* create node */
Michal Vaskofeca4fb2020-10-05 08:58:40 +0200475 ret = lyd_create_opaq(ctx, name, name_len, xmlctx->value, xmlctx->value_len, &xmlctx->dynamic, LYD_XML,
476 LYD_HINT_DATA, val_prefs, prefix, prefix_len, ns->uri, strlen(ns->uri), &node);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200477 LY_CHECK_GOTO(ret, error);
478
479 /* parser next */
480 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
481
482 /* process children */
483 while (xmlctx->status == LYXML_ELEMENT) {
484 ret = lydxml_subtree_r(lydctx, (struct lyd_node_inner *)node, lyd_node_children_p(node));
485 LY_CHECK_GOTO(ret, error);
486 }
487 } else if (snode->nodetype & LYD_NODE_TERM) {
488 /* create node */
Michal Vasko22df3f02020-08-24 13:29:22 +0200489 LY_CHECK_GOTO(ret = lyd_parser_create_term((struct lyd_ctx *)lydctx, snode, xmlctx->value, xmlctx->value_len,
Michal Vaskofeca4fb2020-10-05 08:58:40 +0200490 &xmlctx->dynamic, LY_PREF_XML, &xmlctx->ns, LYD_HINT_DATA, &node), error);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200491
492 if (parent && (node->schema->flags & LYS_KEY)) {
493 /* check the key order, the anchor must never be a key */
494 anchor = lyd_insert_get_next_anchor(parent->child, node);
495 if (anchor && (anchor->schema->flags & LYS_KEY)) {
496 if (lydctx->parse_options & LYD_PARSE_STRICT) {
497 LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_DATA, "Invalid position of the key \"%s\" in a list.",
498 node->schema->name);
499 ret = LY_EVALID;
500 goto error;
501 } else {
502 LOGWRN(ctx, "Invalid position of the key \"%s\" in a list.", node->schema->name);
503 }
504 }
505 }
506
507 /* parser next */
508 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
509
510 /* no children expected */
511 if (xmlctx->status == LYXML_ELEMENT) {
512 LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_SYNTAX, "Child element \"%.*s\" inside a terminal node \"%s\" found.",
513 xmlctx->name_len, xmlctx->name, snode->name);
514 ret = LY_EVALID;
515 goto error;
516 }
517 } else if (snode->nodetype & LYD_NODE_INNER) {
518 if (!xmlctx->ws_only) {
519 /* value in inner node */
520 LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_SYNTAX, "Text value \"%.*s\" inside an inner node \"%s\" found.",
521 xmlctx->value_len, xmlctx->value, snode->name);
522 ret = LY_EVALID;
523 goto error;
524 }
525
526 /* create node */
527 ret = lyd_create_inner(snode, &node);
528 LY_CHECK_GOTO(ret, error);
529
530 /* parser next */
531 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
532
533 /* process children */
534 while (xmlctx->status == LYXML_ELEMENT) {
535 ret = lydxml_subtree_r(lydctx, (struct lyd_node_inner *)node, lyd_node_children_p(node));
536 LY_CHECK_GOTO(ret, error);
537 }
538
539 if (snode->nodetype == LYS_LIST) {
540 /* check all keys exist */
541 LY_CHECK_GOTO(ret = lyd_parse_check_keys(node), error);
542 }
543
544 if (!(lydctx->parse_options & LYD_PARSE_ONLY)) {
545 /* new node validation, autodelete CANNOT occur, all nodes are new */
546 ret = lyd_validate_new(lyd_node_children_p(node), snode, NULL, NULL);
547 LY_CHECK_GOTO(ret, error);
548
549 /* add any missing default children */
550 ret = lyd_new_implicit_r(node, lyd_node_children_p(node), NULL, NULL, &lydctx->unres_node_type, &lydctx->when_check,
Radek Krejci0f969882020-08-21 16:56:47 +0200551 (lydctx->validate_options & LYD_VALIDATE_NO_STATE) ? LYD_IMPLICIT_NO_STATE : 0, NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200552 LY_CHECK_GOTO(ret, error);
553 }
554
555 if (snode->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) {
556 /* rememeber the RPC/action/notification */
557 lydctx->op_node = node;
558 }
559 } else if (snode->nodetype & LYD_NODE_ANY) {
560 if (!xmlctx->ws_only) {
561 /* value in inner node */
562 LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_SYNTAX, "Text value \"%.*s\" inside an any node \"%s\" found.",
563 xmlctx->value_len, xmlctx->value, snode->name);
564 ret = LY_EVALID;
565 goto error;
566 }
567
568 /* parser next */
569 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
570
571 /* parse any data tree with correct options */
572 prev_opts = lydctx->parse_options;
573 lydctx->parse_options &= ~LYD_PARSE_STRICT;
574 lydctx->parse_options |= LYD_PARSE_OPAQ;
575 anchor = NULL;
576 while (xmlctx->status == LYXML_ELEMENT) {
577 ret = lydxml_subtree_r(lydctx, NULL, &anchor);
578 LY_CHECK_ERR_GOTO(ret, lydctx->parse_options = prev_opts, error);
579 }
580 lydctx->parse_options = prev_opts;
581
582 /* create node */
583 ret = lyd_create_any(snode, anchor, LYD_ANYDATA_DATATREE, &node);
584 LY_CHECK_GOTO(ret, error);
585 }
586 assert(node);
587
588 /* add/correct flags */
589 if (snode) {
590 lyd_parse_set_data_flags(node, &lydctx->when_check, &meta, lydctx->parse_options);
591 }
592
593 /* parser next */
594 assert(xmlctx->status == LYXML_ELEM_CLOSE);
595 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
596
597 /* add metadata/attributes */
598 if (snode) {
599 lyd_insert_meta(node, meta);
600 } else {
601 lyd_insert_attr(node, attr);
602 }
603
604 /* insert, keep first pointer correct */
605 lyd_insert_node((struct lyd_node *)parent, first_p, node);
606 while (!parent && (*first_p)->prev->next) {
607 *first_p = (*first_p)->prev;
608 }
609
610 return LY_SUCCESS;
611
612error:
Michal Vasko3a41dff2020-07-15 14:30:28 +0200613 lyd_free_meta_siblings(meta);
Radek Krejci011e4aa2020-09-04 15:22:31 +0200614 lyd_free_attr_siblings(ctx, attr);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200615 lyd_free_tree(node);
Radek Krejcie7b95092019-05-15 11:03:07 +0200616 return ret;
617}
618
619LY_ERR
Radek Krejci1deb5be2020-08-26 16:43:36 +0200620lyd_parse_xml_data(const struct ly_ctx *ctx, struct ly_in *in, uint32_t parse_options, uint32_t validate_options,
Radek Krejci0f969882020-08-21 16:56:47 +0200621 struct lyd_node **tree_p, struct lyd_ctx **lydctx_p)
Radek Krejcie7b95092019-05-15 11:03:07 +0200622{
Radek Krejci18a57d92019-07-25 14:01:42 +0200623 LY_ERR ret = LY_SUCCESS;
Radek Krejci1798aae2020-07-14 13:26:06 +0200624 struct lyd_xml_ctx *lydctx;
Radek Krejcie7b95092019-05-15 11:03:07 +0200625
Radek Krejci7931b192020-06-25 17:05:03 +0200626 assert(!(parse_options & ~LYD_PARSE_OPTS_MASK));
627 assert(!(validate_options & ~LYD_VALIDATE_OPTS_MASK));
628
Radek Krejci1798aae2020-07-14 13:26:06 +0200629 /* init context */
630 lydctx = calloc(1, sizeof *lydctx);
631 LY_CHECK_ERR_RET(!lydctx, LOGMEM(ctx), LY_EMEM);
632 LY_CHECK_GOTO(ret = lyxml_ctx_new(ctx, in, &lydctx->xmlctx), cleanup);
633 lydctx->parse_options = parse_options;
634 lydctx->validate_options = validate_options;
635 lydctx->free = lyd_xml_ctx_free;
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200636
Michal Vaskob1b5c262020-03-05 14:29:47 +0100637 /* parse XML data */
Michal Vaskoa5da3292020-08-12 13:10:50 +0200638 while (lydctx->xmlctx->status == LYXML_ELEMENT) {
639 LY_CHECK_GOTO(ret = lydxml_subtree_r(lydctx, NULL, tree_p), cleanup);
640 }
Michal Vaskocde73ac2019-11-14 16:10:27 +0100641
Michal Vaskocde73ac2019-11-14 16:10:27 +0100642cleanup:
Michal Vasko9b368d32020-02-14 13:53:31 +0100643 /* there should be no unresolved types stored */
Radek Krejci1798aae2020-07-14 13:26:06 +0200644 assert(!(parse_options & LYD_PARSE_ONLY) || (!lydctx->unres_node_type.count && !lydctx->unres_meta_type.count
Radek Krejci0f969882020-08-21 16:56:47 +0200645 && !lydctx->when_check.count));
Michal Vasko9b368d32020-02-14 13:53:31 +0100646
Michal Vasko9f96a052020-03-10 09:41:45 +0100647 if (ret) {
Radek Krejci1798aae2020-07-14 13:26:06 +0200648 lyd_xml_ctx_free((struct lyd_ctx *)lydctx);
649 lyd_free_all(*tree_p);
650 *tree_p = NULL;
651 } else {
652 *lydctx_p = (struct lyd_ctx *)lydctx;
Michal Vasko9f96a052020-03-10 09:41:45 +0100653 }
654 return ret;
655}
Michal Vasko1bf09392020-03-27 12:38:10 +0100656
657static LY_ERR
658lydxml_envelope(struct lyxml_ctx *xmlctx, const char *name, const char *uri, struct lyd_node **envp)
659{
660 LY_ERR ret = LY_SUCCESS;
661 const struct lyxml_ns *ns = NULL;
Radek Krejci1798aae2020-07-14 13:26:06 +0200662 struct lyd_attr *attr = NULL;
Michal Vasko1bf09392020-03-27 12:38:10 +0100663 const char *prefix;
664 size_t prefix_len;
665
666 *envp = NULL;
667
668 assert(xmlctx->status == LYXML_ELEMENT);
669 if (ly_strncmp(name, xmlctx->name, xmlctx->name_len)) {
670 /* not the expected element */
671 return LY_SUCCESS;
672 }
673
674 prefix = xmlctx->prefix;
675 prefix_len = xmlctx->prefix_len;
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200676 ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
Michal Vasko1bf09392020-03-27 12:38:10 +0100677 if (!ns) {
678 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".",
679 prefix_len, prefix);
680 return LY_EVALID;
681 } else if (strcmp(ns->uri, uri)) {
682 /* different namespace */
683 return LY_SUCCESS;
684 }
685
686 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
687
688 /* create attributes */
689 if (xmlctx->status == LYXML_ATTRIBUTE) {
690 LY_CHECK_RET(lydxml_attrs(xmlctx, &attr));
691 }
692
693 if (!xmlctx->ws_only) {
694 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_SYNTAX, "Unexpected value \"%.*s\" in the \"%s\" element.",
695 xmlctx->value_len, xmlctx->value, name);
696 ret = LY_EVALID;
697 goto cleanup;
698 }
699
700 /* parser next element */
701 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
702
703 /* create node */
Michal Vaskofeca4fb2020-10-05 08:58:40 +0200704 ret = lyd_create_opaq(xmlctx->ctx, name, strlen(name), "", 0, NULL, LYD_XML, LYD_NODEHINT_ENVELOPE, NULL, prefix,
705 prefix_len, uri, strlen(uri), envp);
Michal Vasko1bf09392020-03-27 12:38:10 +0100706 LY_CHECK_GOTO(ret, cleanup);
707
708 /* assign atributes */
709 ((struct lyd_node_opaq *)(*envp))->attr = attr;
710 attr = NULL;
711
712cleanup:
Radek Krejci011e4aa2020-09-04 15:22:31 +0200713 lyd_free_attr_siblings(xmlctx->ctx, attr);
Michal Vasko1bf09392020-03-27 12:38:10 +0100714 return ret;
715}
716
717LY_ERR
Radek Krejci1798aae2020-07-14 13:26:06 +0200718lyd_parse_xml_rpc(const struct ly_ctx *ctx, struct ly_in *in, struct lyd_node **tree_p, struct lyd_node **op_p)
Michal Vasko1bf09392020-03-27 12:38:10 +0100719{
720 LY_ERR ret = LY_SUCCESS;
721 struct lyd_xml_ctx lydctx = {0};
722 struct lyd_node *rpc_e = NULL, *act_e = NULL;
Radek Krejci1798aae2020-07-14 13:26:06 +0200723 struct lyd_node *tree = NULL;
Michal Vasko1bf09392020-03-27 12:38:10 +0100724
725 /* init */
Michal Vasko63f3d842020-07-08 10:10:14 +0200726 LY_CHECK_GOTO(ret = lyxml_ctx_new(ctx, in, &lydctx.xmlctx), cleanup);
Radek Krejci1798aae2020-07-14 13:26:06 +0200727 lydctx.parse_options = LYD_PARSE_ONLY | LYD_PARSE_STRICT;
Michal Vasko1bf09392020-03-27 12:38:10 +0100728 lydctx.int_opts = LYD_INTOPT_RPC;
Michal Vasko1bf09392020-03-27 12:38:10 +0100729
730 /* parse "rpc", if any */
731 LY_CHECK_GOTO(ret = lydxml_envelope(lydctx.xmlctx, "rpc", "urn:ietf:params:xml:ns:netconf:base:1.0", &rpc_e), cleanup);
732
733 if (rpc_e) {
734 /* parse "action", if any */
735 LY_CHECK_GOTO(ret = lydxml_envelope(lydctx.xmlctx, "action", "urn:ietf:params:xml:ns:yang:1", &act_e), cleanup);
736 }
737
738 /* parse the rest of data normally */
Michal Vaskocf770e22020-08-12 13:21:43 +0200739 LY_CHECK_GOTO(ret = lydxml_subtree_r(&lydctx, NULL, &tree), cleanup);
Michal Vasko1bf09392020-03-27 12:38:10 +0100740
Michal Vaskocf770e22020-08-12 13:21:43 +0200741 /* make sure we have parsed some operation and it is the only subtree */
Radek Krejci1798aae2020-07-14 13:26:06 +0200742 if (!lydctx.op_node) {
Michal Vasko1bf09392020-03-27 12:38:10 +0100743 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_DATA, "Missing the \"rpc\"/\"action\" node.");
744 ret = LY_EVALID;
745 goto cleanup;
Michal Vaskocf770e22020-08-12 13:21:43 +0200746 } else if (lydctx.xmlctx->status == LYXML_ELEMENT) {
747 LOGVAL(ctx, LY_VLOG_LINE, &lydctx.xmlctx->line, LYVE_SYNTAX, "Unexpected sibling element of \"%s\".",
748 tree->schema->name);
749 ret = LY_EVALID;
750 goto cleanup;
Michal Vasko1bf09392020-03-27 12:38:10 +0100751 }
752
753 /* finish XML parsing and check operation type */
754 if (act_e) {
755 if (lydctx.xmlctx->status != LYXML_ELEM_CLOSE) {
756 assert(lydctx.xmlctx->status == LYXML_ELEMENT);
757 LOGVAL(ctx, LY_VLOG_LINE, &lydctx.xmlctx->line, LYVE_SYNTAX, "Unexpected sibling element \"%.*s\" of \"action\".",
758 lydctx.xmlctx->name_len, lydctx.xmlctx->name);
759 ret = LY_EVALID;
760 goto cleanup;
Radek Krejci1798aae2020-07-14 13:26:06 +0200761 } else if (lydctx.op_node->schema->nodetype != LYS_ACTION) {
762 LOGVAL(ctx, LY_VLOG_LYD, lydctx.op_node, LYVE_DATA, "Unexpected %s element, an \"action\" expected.",
763 lys_nodetype2str(lydctx.op_node->schema->nodetype));
Michal Vasko1bf09392020-03-27 12:38:10 +0100764 ret = LY_EVALID;
765 goto cleanup;
766 }
767 LY_CHECK_GOTO(ret = lyxml_ctx_next(lydctx.xmlctx), cleanup);
768 }
769 if (rpc_e) {
770 if (lydctx.xmlctx->status != LYXML_ELEM_CLOSE) {
771 assert(lydctx.xmlctx->status == LYXML_ELEMENT);
772 LOGVAL(ctx, LY_VLOG_LINE, &lydctx.xmlctx->line, LYVE_SYNTAX, "Unexpected sibling element \"%.*s\" of \"rpc\".",
773 lydctx.xmlctx->name_len, lydctx.xmlctx->name);
774 ret = LY_EVALID;
775 goto cleanup;
Radek Krejci1798aae2020-07-14 13:26:06 +0200776 } else if (!act_e && (lydctx.op_node->schema->nodetype != LYS_RPC)) {
777 LOGVAL(ctx, LY_VLOG_LYD, lydctx.op_node, LYVE_DATA, "Unexpected %s element, an \"rpc\" expected.",
778 lys_nodetype2str(lydctx.op_node->schema->nodetype));
Michal Vasko1bf09392020-03-27 12:38:10 +0100779 ret = LY_EVALID;
780 goto cleanup;
781 }
782 LY_CHECK_GOTO(ret = lyxml_ctx_next(lydctx.xmlctx), cleanup);
783 }
784
Radek Krejci1798aae2020-07-14 13:26:06 +0200785 if (op_p) {
786 *op_p = lydctx.op_node;
Michal Vaskocc048b22020-03-27 15:52:38 +0100787 }
Radek Krejci1798aae2020-07-14 13:26:06 +0200788 assert(tree);
Michal Vasko1bf09392020-03-27 12:38:10 +0100789 if (act_e) {
790 /* connect to the action */
Michal Vasko4189c0f2020-08-13 09:05:22 +0200791 lyd_insert_node(act_e, NULL, tree);
792 tree = act_e;
Michal Vasko1bf09392020-03-27 12:38:10 +0100793 }
794 if (rpc_e) {
795 /* connect to the rpc */
Michal Vasko4189c0f2020-08-13 09:05:22 +0200796 lyd_insert_node(rpc_e, NULL, tree);
797 tree = rpc_e;
798 }
799 if (tree_p) {
800 *tree_p = tree;
Michal Vasko1bf09392020-03-27 12:38:10 +0100801 }
802
803cleanup:
804 /* we have used parse_only flag */
805 assert(!lydctx.unres_node_type.count && !lydctx.unres_meta_type.count && !lydctx.when_check.count);
806 lyxml_ctx_free(lydctx.xmlctx);
807 if (ret) {
Radek Krejci1798aae2020-07-14 13:26:06 +0200808 lyd_free_all(tree);
Michal Vasko1bf09392020-03-27 12:38:10 +0100809 lyd_free_tree(act_e);
810 lyd_free_tree(rpc_e);
Michal Vasko1bf09392020-03-27 12:38:10 +0100811 }
812 return ret;
813}
Michal Vaskoa8edff02020-03-27 14:47:01 +0100814
815static LY_ERR
816lydxml_notif_envelope(struct lyxml_ctx *xmlctx, struct lyd_node **envp)
817{
818 LY_ERR ret = LY_SUCCESS;
819 const struct lyxml_ns *ns = NULL;
Radek Krejci1798aae2020-07-14 13:26:06 +0200820 struct lyd_attr *attr = NULL;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100821 struct lyd_node *et;
822 const char *prefix;
823 size_t prefix_len;
824
825 *envp = NULL;
826
827 /* container envelope */
828 LY_CHECK_GOTO(ret = lydxml_envelope(xmlctx, "notification", "urn:ietf:params:xml:ns:netconf:notification:1.0",
829 envp), cleanup);
830
831 /* no envelope, fine */
832 if (!*envp) {
833 goto cleanup;
834 }
835
836 /* child "eventTime" */
837 if ((xmlctx->status != LYXML_ELEMENT) || ly_strncmp("eventTime", xmlctx->name, xmlctx->name_len)) {
838 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Missing the \"eventTime\" element.");
839 ret = LY_EVALID;
840 goto cleanup;
841 }
842
843 prefix = xmlctx->prefix;
844 prefix_len = xmlctx->prefix_len;
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200845 ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100846 if (!ns) {
847 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".",
848 prefix_len, prefix);
849 ret = LY_EVALID;
850 goto cleanup;
851 } else if (strcmp(ns->uri, "urn:ietf:params:xml:ns:netconf:notification:1.0")) {
852 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Invalid namespace \"%s\" of \"eventTime\".",
853 ns->uri);
854 ret = LY_EVALID;
855 goto cleanup;
856 }
857
858 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
859
860 /* create attributes */
861 if (xmlctx->status == LYXML_ATTRIBUTE) {
862 LY_CHECK_RET(lydxml_attrs(xmlctx, &attr));
863 }
864
865 /* validate value */
866 /* TODO */
867 /*if (!xmlctx->ws_only) {
868 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_SYNTAX, "Unexpected value \"%.*s\" in the \"%s\" element.",
869 xmlctx->value_len, xmlctx->value, name);
870 ret = LY_EVALID;
871 goto cleanup;
872 }*/
873
874 /* create node */
Michal Vaskofeca4fb2020-10-05 08:58:40 +0200875 ret = lyd_create_opaq(xmlctx->ctx, "eventTime", 9, xmlctx->value, xmlctx->value_len, NULL, LYD_XML,
876 LYD_NODEHINT_ENVELOPE, NULL, prefix, prefix_len, ns->uri, strlen(ns->uri), &et);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100877 LY_CHECK_GOTO(ret, cleanup);
878
879 /* assign atributes */
880 ((struct lyd_node_opaq *)et)->attr = attr;
881 attr = NULL;
882
883 /* insert */
884 lyd_insert_node(*envp, NULL, et);
885
886 /* finish parsing */
887 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
888 if (xmlctx->status != LYXML_ELEM_CLOSE) {
889 assert(xmlctx->status == LYXML_ELEMENT);
890 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_SYNTAX, "Unexpected sibling element \"%.*s\" of \"eventTime\".",
891 xmlctx->name_len, xmlctx->name);
892 ret = LY_EVALID;
893 goto cleanup;
894 }
895 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
896
897cleanup:
898 if (ret) {
899 lyd_free_tree(*envp);
Radek Krejci011e4aa2020-09-04 15:22:31 +0200900 lyd_free_attr_siblings(xmlctx->ctx, attr);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100901 }
902 return ret;
903}
904
905LY_ERR
Radek Krejci1798aae2020-07-14 13:26:06 +0200906lyd_parse_xml_notif(const struct ly_ctx *ctx, struct ly_in *in, struct lyd_node **tree_p, struct lyd_node **ntf_p)
Michal Vaskoa8edff02020-03-27 14:47:01 +0100907{
908 LY_ERR ret = LY_SUCCESS;
909 struct lyd_xml_ctx lydctx = {0};
910 struct lyd_node *ntf_e = NULL;
Radek Krejci1798aae2020-07-14 13:26:06 +0200911 struct lyd_node *tree = NULL;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100912
913 /* init */
Michal Vasko63f3d842020-07-08 10:10:14 +0200914 LY_CHECK_GOTO(ret = lyxml_ctx_new(ctx, in, &lydctx.xmlctx), cleanup);
Radek Krejci1798aae2020-07-14 13:26:06 +0200915 lydctx.parse_options = LYD_PARSE_ONLY | LYD_PARSE_STRICT;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100916 lydctx.int_opts = LYD_INTOPT_NOTIF;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100917
918 /* parse "notification" and "eventTime", if present */
919 LY_CHECK_GOTO(ret = lydxml_notif_envelope(lydctx.xmlctx, &ntf_e), cleanup);
920
921 /* parse the rest of data normally */
Michal Vaskocf770e22020-08-12 13:21:43 +0200922 LY_CHECK_GOTO(ret = lydxml_subtree_r(&lydctx, NULL, &tree), cleanup);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100923
924 /* make sure we have parsed some notification */
Radek Krejci1798aae2020-07-14 13:26:06 +0200925 if (!lydctx.op_node) {
Michal Vaskoa8edff02020-03-27 14:47:01 +0100926 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_DATA, "Missing the \"notification\" node.");
927 ret = LY_EVALID;
928 goto cleanup;
Michal Vaskocf770e22020-08-12 13:21:43 +0200929 } else if (lydctx.xmlctx->status == LYXML_ELEMENT) {
930 LOGVAL(ctx, LY_VLOG_LINE, &lydctx.xmlctx->line, LYVE_SYNTAX, "Unexpected sibling element of \"%s\".",
931 tree->schema->name);
932 ret = LY_EVALID;
933 goto cleanup;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100934 }
935
936 /* finish XML parsing */
937 if (ntf_e) {
938 if (lydctx.xmlctx->status != LYXML_ELEM_CLOSE) {
939 assert(lydctx.xmlctx->status == LYXML_ELEMENT);
940 LOGVAL(ctx, LY_VLOG_LINE, &lydctx.xmlctx->line, LYVE_SYNTAX, "Unexpected sibling element \"%.*s\" of \"notification\".",
941 lydctx.xmlctx->name_len, lydctx.xmlctx->name);
942 ret = LY_EVALID;
943 goto cleanup;
944 }
945 LY_CHECK_GOTO(ret = lyxml_ctx_next(lydctx.xmlctx), cleanup);
946 }
947
Radek Krejci1798aae2020-07-14 13:26:06 +0200948 if (ntf_p) {
949 *ntf_p = lydctx.op_node;
Michal Vaskocc048b22020-03-27 15:52:38 +0100950 }
Radek Krejci1798aae2020-07-14 13:26:06 +0200951 assert(tree);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100952 if (ntf_e) {
953 /* connect to the notification */
Michal Vasko4189c0f2020-08-13 09:05:22 +0200954 lyd_insert_node(ntf_e, NULL, tree);
955 tree = ntf_e;
956 }
957 if (tree_p) {
958 *tree_p = tree;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100959 }
960
961cleanup:
962 /* we have used parse_only flag */
963 assert(!lydctx.unres_node_type.count && !lydctx.unres_meta_type.count && !lydctx.when_check.count);
964 lyxml_ctx_free(lydctx.xmlctx);
965 if (ret) {
Radek Krejci1798aae2020-07-14 13:26:06 +0200966 lyd_free_all(tree);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100967 lyd_free_tree(ntf_e);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100968 }
969 return ret;
970}
Michal Vasko1ce933a2020-03-30 12:38:22 +0200971
972LY_ERR
Radek Krejci1798aae2020-07-14 13:26:06 +0200973lyd_parse_xml_reply(const struct lyd_node *request, struct ly_in *in, struct lyd_node **tree_p, struct lyd_node **op_p)
Michal Vasko1ce933a2020-03-30 12:38:22 +0200974{
975 LY_ERR ret = LY_SUCCESS;
976 struct lyd_xml_ctx lydctx = {0};
Michal Vasko4189c0f2020-08-13 09:05:22 +0200977 struct lyd_node *rpcr_e = NULL, *tree, *req_op, *rep_op = NULL;
Michal Vasko1ce933a2020-03-30 12:38:22 +0200978
979 /* init */
Michal Vaskob7be7a82020-08-20 09:09:04 +0200980 LY_CHECK_GOTO(ret = lyxml_ctx_new(LYD_CTX(request), in, &lydctx.xmlctx), cleanup);
Radek Krejci1798aae2020-07-14 13:26:06 +0200981 lydctx.parse_options = LYD_PARSE_ONLY | LYD_PARSE_STRICT;
Michal Vasko1ce933a2020-03-30 12:38:22 +0200982 lydctx.int_opts = LYD_INTOPT_REPLY;
Michal Vasko1ce933a2020-03-30 12:38:22 +0200983
984 /* find request OP */
Michal Vasko56daf732020-08-10 10:57:18 +0200985 LYD_TREE_DFS_BEGIN((struct lyd_node *)request, req_op) {
Michal Vasko1ce933a2020-03-30 12:38:22 +0200986 if (req_op->schema->nodetype & (LYS_RPC | LYS_ACTION)) {
987 break;
988 }
Michal Vasko56daf732020-08-10 10:57:18 +0200989 LYD_TREE_DFS_END(request, req_op);
Michal Vasko1ce933a2020-03-30 12:38:22 +0200990 }
991 if (!(req_op->schema->nodetype & (LYS_RPC | LYS_ACTION))) {
Michal Vaskob7be7a82020-08-20 09:09:04 +0200992 LOGERR(LYD_CTX(request), LY_EINVAL, "No RPC/action in the request found.");
Michal Vasko1ce933a2020-03-30 12:38:22 +0200993 ret = LY_EINVAL;
994 goto cleanup;
995 }
996
997 /* duplicate request OP with parents */
Michal Vasko3a41dff2020-07-15 14:30:28 +0200998 LY_CHECK_GOTO(ret = lyd_dup_single(req_op, NULL, LYD_DUP_WITH_PARENTS, &rep_op), cleanup);
Michal Vasko1ce933a2020-03-30 12:38:22 +0200999
1000 /* parse "rpc-reply", if any */
Michal Vasko3a41dff2020-07-15 14:30:28 +02001001 LY_CHECK_GOTO(ret = lydxml_envelope(lydctx.xmlctx, "rpc-reply", "urn:ietf:params:xml:ns:netconf:base:1.0", &rpcr_e),
1002 cleanup);
Michal Vasko1ce933a2020-03-30 12:38:22 +02001003
1004 /* parse the rest of data normally but connect them to the duplicated operation */
Michal Vaskoa5da3292020-08-12 13:10:50 +02001005 while (lydctx.xmlctx->status == LYXML_ELEMENT) {
1006 ret = lydxml_subtree_r(&lydctx, (struct lyd_node_inner *)rep_op, lyd_node_children_p(rep_op));
1007 LY_CHECK_GOTO(ret, cleanup);
1008 }
Michal Vasko1ce933a2020-03-30 12:38:22 +02001009
1010 /* finish XML parsing and check operation type */
1011 if (rpcr_e) {
1012 if (lydctx.xmlctx->status != LYXML_ELEM_CLOSE) {
1013 assert(lydctx.xmlctx->status == LYXML_ELEMENT);
Michal Vaskob7be7a82020-08-20 09:09:04 +02001014 LOGVAL(LYD_CTX(request), LY_VLOG_LINE, &lydctx.xmlctx->line, LYVE_SYNTAX,
Michal Vasko1ce933a2020-03-30 12:38:22 +02001015 "Unexpected sibling element \"%.*s\" of \"rpc-reply\".", lydctx.xmlctx->name_len, lydctx.xmlctx->name);
1016 ret = LY_EVALID;
1017 goto cleanup;
1018 }
1019 LY_CHECK_GOTO(ret = lyxml_ctx_next(lydctx.xmlctx), cleanup);
1020 }
1021
Radek Krejci1798aae2020-07-14 13:26:06 +02001022 if (op_p) {
1023 *op_p = rep_op;
Michal Vasko1ce933a2020-03-30 12:38:22 +02001024 }
Radek Krejcia1c1e542020-09-29 16:06:52 +02001025 for (tree = rep_op; tree->parent; tree = lyd_parent(tree)) {}
Michal Vasko1ce933a2020-03-30 12:38:22 +02001026 if (rpcr_e) {
1027 /* connect to the operation */
Michal Vasko4189c0f2020-08-13 09:05:22 +02001028 lyd_insert_node(rpcr_e, NULL, tree);
1029 tree = rpcr_e;
1030 }
1031 if (tree_p) {
1032 *tree_p = tree;
Michal Vasko1ce933a2020-03-30 12:38:22 +02001033 }
1034
1035cleanup:
1036 /* we have used parse_only flag */
1037 assert(!lydctx.unres_node_type.count && !lydctx.unres_meta_type.count && !lydctx.when_check.count);
1038 lyxml_ctx_free(lydctx.xmlctx);
1039 if (ret) {
1040 lyd_free_all(rep_op);
1041 lyd_free_tree(rpcr_e);
1042 }
1043 return ret;
1044}