blob: 8647e69252d86e09f9af44719cdc23d3253e7937 [file] [log] [blame]
Radek Krejcie7b95092019-05-15 11:03:07 +02001/**
2 * @file parser_xml.c
3 * @author Radek Krejci <rkrejci@cesnet.cz>
4 * @brief XML data parser for libyang
5 *
6 * Copyright (c) 2019 CESNET, z.s.p.o.
7 *
8 * This source code is licensed under BSD 3-Clause License (the "License").
9 * You may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * https://opensource.org/licenses/BSD-3-Clause
13 */
14
Michal Vasko69730152020-10-09 16:30:07 +020015#include <assert.h>
Radek Krejcie7b95092019-05-15 11:03:07 +020016#include <stdint.h>
17#include <stdlib.h>
18#include <string.h>
19
Radek Krejci535ea9f2020-05-29 16:01:05 +020020#include "common.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020021#include "context.h"
Michal Vaskoafac7822020-10-20 14:22:26 +020022#include "in_internal.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020023#include "log.h"
Radek Krejci7931b192020-06-25 17:05:03 +020024#include "parser_data.h"
25#include "parser_internal.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020026#include "set.h"
Radek Krejci535ea9f2020-05-29 16:01:05 +020027#include "tree.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020028#include "tree_data_internal.h"
29#include "tree_schema.h"
Michal Vaskocde73ac2019-11-14 16:10:27 +010030#include "validation.h"
Radek Krejci535ea9f2020-05-29 16:01:05 +020031#include "xml.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020032
33/**
Michal Vaskob36053d2020-03-26 15:49:30 +010034 * @brief Internal context for XML YANG data parser.
Radek Krejci1798aae2020-07-14 13:26:06 +020035 *
36 * Note that the structure maps to the lyd_ctx which is common for all the data parsers
Radek Krejcie7b95092019-05-15 11:03:07 +020037 */
38struct lyd_xml_ctx {
Radek Krejci1798aae2020-07-14 13:26:06 +020039 uint32_t parse_options; /**< various @ref dataparseroptions. */
40 uint32_t validate_options; /**< various @ref datavalidationoptions. */
41 uint32_t int_opts; /**< internal data parser options */
42 uint32_t path_len; /**< used bytes in the path buffer */
43 char path[LYD_PARSER_BUFSIZE]; /**< buffer for the generated path */
44 struct ly_set unres_node_type; /**< set of nodes validated with LY_EINCOMPLETE result */
45 struct ly_set unres_meta_type; /**< set of metadata validated with LY_EINCOMPLETE result */
46 struct ly_set when_check; /**< set of nodes with "when" conditions */
47 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 +020048
Radek Krejci1798aae2020-07-14 13:26:06 +020049 /* callbacks */
50 lyd_ctx_free_clb free; /* destructor */
Radek Krejci1798aae2020-07-14 13:26:06 +020051
52 struct lyxml_ctx *xmlctx; /**< XML context */
Radek Krejcie7b95092019-05-15 11:03:07 +020053};
54
Radek Krejci1798aae2020-07-14 13:26:06 +020055void
56lyd_xml_ctx_free(struct lyd_ctx *lydctx)
57{
58 struct lyd_xml_ctx *ctx = (struct lyd_xml_ctx *)lydctx;
59
60 lyd_ctx_free(lydctx);
61 lyxml_ctx_free(ctx->xmlctx);
62 free(ctx);
63}
64
Radek Krejcie7b95092019-05-15 11:03:07 +020065static LY_ERR
Michal Vaskofeca4fb2020-10-05 08:58:40 +020066lydxml_metadata(struct lyd_xml_ctx *lydctx, struct lyd_meta **meta)
Radek Krejcie7b95092019-05-15 11:03:07 +020067{
Michal Vaskob36053d2020-03-26 15:49:30 +010068 LY_ERR ret = LY_EVALID;
Radek Krejci28681fa2019-09-06 13:08:45 +020069 const struct lyxml_ns *ns;
70 struct lys_module *mod;
Michal Vaskob36053d2020-03-26 15:49:30 +010071 const char *name;
72 size_t name_len;
Radek Krejci1798aae2020-07-14 13:26:06 +020073 struct lyxml_ctx *xmlctx = lydctx->xmlctx;
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 */
Radek Krejci1798aae2020-07-14 13:26:06 +020081 if (lydctx->parse_options & LYD_PARSE_STRICT) {
Michal Vasko52927e22020-03-16 17:26:14 +010082 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Missing mandatory prefix for XML metadata \"%.*s\".",
Michal Vasko69730152020-10-09 16:30:07 +020083 xmlctx->name_len, xmlctx->name);
Michal Vaskob36053d2020-03-26 15:49:30 +010084 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 Vaskoc8a230d2020-08-14 12:17:10 +020095 ns = lyxml_ns_get(&xmlctx->ns, 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 Vasko69730152020-10-09 16:30:07 +020099 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 */
Radek Krejci1798aae2020-07-14 13:26:06 +0200105 if (lydctx->parse_options & LYD_PARSE_STRICT) {
Michal Vasko52927e22020-03-16 17:26:14 +0100106 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE,
Michal Vasko69730152020-10-09 16:30:07 +0200107 "Unknown (or not implemented) YANG module with namespace \"%s\" for metadata \"%.*s%s%.*s\".",
108 ns->uri, xmlctx->prefix_len, xmlctx->prefix, xmlctx->prefix_len ? ":" : "", xmlctx->name_len,
109 xmlctx->name);
Michal Vaskob36053d2020-03-26 15:49:30 +0100110 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 */
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200122 ret = lyd_parser_create_meta((struct lyd_ctx *)lydctx, NULL, meta, mod, name, name_len, xmlctx->value,
Michal Vaskofeca4fb2020-10-05 08:58:40 +0200123 xmlctx->value_len, &xmlctx->dynamic, LY_PREF_XML, &xmlctx->ns, LYD_HINT_DATA);
Radek Krejci1798aae2020-07-14 13:26:06 +0200124 LY_CHECK_GOTO(ret, cleanup);
Michal Vaskob36053d2020-03-26 15:49:30 +0100125
126 /* next attribute */
127 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Radek Krejcie7b95092019-05-15 11:03:07 +0200128 }
Michal Vasko52927e22020-03-16 17:26:14 +0100129
Radek Krejci28681fa2019-09-06 13:08:45 +0200130 ret = LY_SUCCESS;
Radek Krejcie7b95092019-05-15 11:03:07 +0200131
132cleanup:
Michal Vaskob36053d2020-03-26 15:49:30 +0100133 if (ret) {
Michal Vasko3a41dff2020-07-15 14:30:28 +0200134 lyd_free_meta_siblings(*meta);
Michal Vaskob36053d2020-03-26 15:49:30 +0100135 *meta = NULL;
Radek Krejci38d85362019-09-05 16:26:38 +0200136 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200137 return ret;
138}
139
Michal Vasko52927e22020-03-16 17:26:14 +0100140static LY_ERR
Radek Krejci1798aae2020-07-14 13:26:06 +0200141lydxml_attrs(struct lyxml_ctx *xmlctx, struct lyd_attr **attr)
Michal Vasko52927e22020-03-16 17:26:14 +0100142{
143 LY_ERR ret = LY_SUCCESS;
144 const struct lyxml_ns *ns;
145 struct ly_prefix *val_prefs;
Radek Krejci1798aae2020-07-14 13:26:06 +0200146 struct lyd_attr *attr2;
Michal Vaskob36053d2020-03-26 15:49:30 +0100147 const char *name, *prefix;
148 size_t name_len, prefix_len;
Michal Vasko52927e22020-03-16 17:26:14 +0100149
150 assert(attr);
Michal Vaskob36053d2020-03-26 15:49:30 +0100151 *attr = NULL;
Michal Vasko52927e22020-03-16 17:26:14 +0100152
Michal Vaskob36053d2020-03-26 15:49:30 +0100153 while (xmlctx->status == LYXML_ATTRIBUTE) {
Michal Vasko52927e22020-03-16 17:26:14 +0100154 ns = NULL;
Michal Vaskob36053d2020-03-26 15:49:30 +0100155 if (xmlctx->prefix_len) {
Michal Vasko52927e22020-03-16 17:26:14 +0100156 /* get namespace of the attribute */
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200157 ns = lyxml_ns_get(&xmlctx->ns, xmlctx->prefix, xmlctx->prefix_len);
Michal Vasko52927e22020-03-16 17:26:14 +0100158 if (!ns) {
159 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".",
Michal Vasko69730152020-10-09 16:30:07 +0200160 xmlctx->prefix_len, xmlctx->prefix);
Michal Vasko52927e22020-03-16 17:26:14 +0100161 ret = LY_EVALID;
162 goto cleanup;
163 }
164 }
165
166 if (*attr) {
167 attr2 = *attr;
168 } else {
169 attr2 = NULL;
170 }
171
Michal Vaskob36053d2020-03-26 15:49:30 +0100172 /* remember attr prefix, name, and get its content */
173 prefix = xmlctx->prefix;
174 prefix_len = xmlctx->prefix_len;
175 name = xmlctx->name;
176 name_len = xmlctx->name_len;
177 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
178 assert(xmlctx->status == LYXML_ATTR_CONTENT);
179
Michal Vasko52927e22020-03-16 17:26:14 +0100180 /* get value prefixes */
Michal Vaskob36053d2020-03-26 15:49:30 +0100181 LY_CHECK_GOTO(ret = lyxml_get_prefixes(xmlctx, xmlctx->value, xmlctx->value_len, &val_prefs), cleanup);
Michal Vasko52927e22020-03-16 17:26:14 +0100182
183 /* attr2 is always changed to the created attribute */
Radek Krejci1798aae2020-07-14 13:26:06 +0200184 ret = lyd_create_attr(NULL, &attr2, xmlctx->ctx, name, name_len, xmlctx->value, xmlctx->value_len,
Michal Vasko69730152020-10-09 16:30:07 +0200185 &xmlctx->dynamic, LYD_XML, 0, val_prefs, prefix, prefix_len,
186 ns ? ns->uri : NULL, ns ? strlen(ns->uri) : 0);
Michal Vasko52927e22020-03-16 17:26:14 +0100187 LY_CHECK_GOTO(ret, cleanup);
188
189 if (!*attr) {
190 *attr = attr2;
191 }
Michal Vaskob36053d2020-03-26 15:49:30 +0100192
193 /* next attribute */
194 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko52927e22020-03-16 17:26:14 +0100195 }
196
197cleanup:
Michal Vaskob36053d2020-03-26 15:49:30 +0100198 if (ret) {
Radek Krejci011e4aa2020-09-04 15:22:31 +0200199 lyd_free_attr_siblings(xmlctx->ctx, *attr);
Michal Vaskob36053d2020-03-26 15:49:30 +0100200 *attr = NULL;
Michal Vasko52927e22020-03-16 17:26:14 +0100201 }
Michal Vasko52927e22020-03-16 17:26:14 +0100202 return ret;
203}
204
Michal Vasko44685da2020-03-17 15:38:06 +0100205static LY_ERR
Michal Vaskob36053d2020-03-26 15:49:30 +0100206lydxml_check_list(struct lyxml_ctx *xmlctx, const struct lysc_node *list)
Michal Vasko44685da2020-03-17 15:38:06 +0100207{
Michal Vaskob36053d2020-03-26 15:49:30 +0100208 LY_ERR ret = LY_SUCCESS, r;
209 enum LYXML_PARSER_STATUS next;
Michal Vasko44685da2020-03-17 15:38:06 +0100210 struct ly_set key_set = {0};
211 const struct lysc_node *snode;
Michal Vaskob36053d2020-03-26 15:49:30 +0100212 uint32_t i, parents_count;
Michal Vasko44685da2020-03-17 15:38:06 +0100213
214 assert(list && (list->nodetype == LYS_LIST));
215
216 /* get all keys into a set (keys do not have if-features or anything) */
217 snode = NULL;
218 while ((snode = lys_getnext(snode, list, NULL, LYS_GETNEXT_NOSTATECHECK)) && (snode->flags & LYS_KEY)) {
Radek Krejci3d92e442020-10-12 12:48:13 +0200219 ret = ly_set_add(&key_set, (void *)snode, 1, NULL);
Radek Krejciba03a5a2020-08-27 14:40:41 +0200220 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100221 }
222
Michal Vaskob36053d2020-03-26 15:49:30 +0100223 while (xmlctx->status == LYXML_ELEMENT) {
Michal Vasko44685da2020-03-17 15:38:06 +0100224 /* find key definition */
225 for (i = 0; i < key_set.count; ++i) {
226 snode = (const struct lysc_node *)key_set.objs[i];
Michal Vaskob36053d2020-03-26 15:49:30 +0100227 if (!ly_strncmp(snode->name, xmlctx->name, xmlctx->name_len)) {
Michal Vasko44685da2020-03-17 15:38:06 +0100228 break;
229 }
230 }
Michal Vaskob36053d2020-03-26 15:49:30 +0100231 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100232
233 /* skip attributes */
234 while (xmlctx->status == LYXML_ATTRIBUTE) {
Michal Vaskob36053d2020-03-26 15:49:30 +0100235 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
236 assert(xmlctx->status == LYXML_ATTR_CONTENT);
237 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100238 }
239
Michal Vaskob36053d2020-03-26 15:49:30 +0100240 assert(xmlctx->status == LYXML_ELEM_CONTENT);
241 if (i < key_set.count) {
242 /* validate the value */
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200243 r = _lys_value_validate(NULL, snode, xmlctx->value, xmlctx->value_len, LY_PREF_XML, xmlctx);
Michal Vaskob36053d2020-03-26 15:49:30 +0100244 if (!r) {
245 /* key with a valid value, remove from the set */
246 ly_set_rm_index(&key_set, i, NULL);
Michal Vasko44685da2020-03-17 15:38:06 +0100247 }
248 }
249
Michal Vaskob36053d2020-03-26 15:49:30 +0100250 /* parser next */
251 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100252
Michal Vaskob36053d2020-03-26 15:49:30 +0100253 /* skip any children, resursively */
254 parents_count = xmlctx->elements.count;
255 while ((parents_count < xmlctx->elements.count) || (xmlctx->status == LYXML_ELEMENT)) {
256 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
257 }
258
259 /* parser next, but do not parse closing element of the list because it would remove its namespaces */
260 assert(xmlctx->status == LYXML_ELEM_CLOSE);
261 LY_CHECK_GOTO(ret = lyxml_ctx_peek(xmlctx, &next), cleanup);
262 if (next != LYXML_ELEM_CLOSE) {
263 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
264 }
Michal Vasko44685da2020-03-17 15:38:06 +0100265 }
266
267 if (key_set.count) {
Michal Vaskob36053d2020-03-26 15:49:30 +0100268 /* some keys are missing/did not validate */
Michal Vasko44685da2020-03-17 15:38:06 +0100269 ret = LY_ENOT;
Michal Vasko44685da2020-03-17 15:38:06 +0100270 }
271
272cleanup:
273 ly_set_erase(&key_set, NULL);
274 return ret;
275}
276
Michal Vasko1bf09392020-03-27 12:38:10 +0100277static LY_ERR
278lydxml_data_skip(struct lyxml_ctx *xmlctx)
279{
280 uint32_t parents_count;
281
282 /* remember current number of parents */
283 parents_count = xmlctx->elements.count;
284
285 /* skip after the content */
286 while (xmlctx->status != LYXML_ELEM_CONTENT) {
287 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
288 }
289 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
290
291 /* skip all children elements, recursively, if any */
292 while (parents_count < xmlctx->elements.count) {
293 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
294 }
295
296 /* close element */
297 assert(xmlctx->status == LYXML_ELEM_CLOSE);
298 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
299
300 return LY_SUCCESS;
301}
302
303static LY_ERR
Radek Krejci1798aae2020-07-14 13:26:06 +0200304lydxml_data_check_opaq(struct lyd_xml_ctx *lydctx, const struct lysc_node **snode)
Michal Vasko1bf09392020-03-27 12:38:10 +0100305{
306 LY_ERR ret = LY_SUCCESS;
307 enum LYXML_PARSER_STATUS prev_status;
Michal Vasko63f3d842020-07-08 10:10:14 +0200308 const char *prev_current, *pname, *pprefix;
Michal Vasko1bf09392020-03-27 12:38:10 +0100309 size_t pprefix_len, pname_len;
310 struct lyxml_ctx *xmlctx = lydctx->xmlctx;
311
Radek Krejci1798aae2020-07-14 13:26:06 +0200312 if ((lydctx->parse_options & LYD_PARSE_OPAQ) && ((*snode)->nodetype & (LYD_NODE_TERM | LYS_LIST))) {
Michal Vasko1bf09392020-03-27 12:38:10 +0100313 /* backup parser */
314 prev_status = xmlctx->status;
315 pprefix = xmlctx->prefix;
316 pprefix_len = xmlctx->prefix_len;
317 pname = xmlctx->name;
318 pname_len = xmlctx->name_len;
Michal Vasko63f3d842020-07-08 10:10:14 +0200319 prev_current = xmlctx->in->current;
Michal Vasko1bf09392020-03-27 12:38:10 +0100320 if ((xmlctx->status == LYXML_ELEM_CONTENT) && xmlctx->dynamic) {
321 /* it was backed up, do not free */
322 xmlctx->dynamic = 0;
323 }
324
325 /* skip attributes */
326 while (xmlctx->status == LYXML_ATTRIBUTE) {
327 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), restore);
328 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), restore);
329 }
330
331 if ((*snode)->nodetype & LYD_NODE_TERM) {
332 /* value may not be valid in which case we parse it as an opaque node */
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200333 if (_lys_value_validate(NULL, *snode, xmlctx->value, xmlctx->value_len, LY_PREF_XML, &xmlctx->ns)) {
Michal Vasko1bf09392020-03-27 12:38:10 +0100334 *snode = NULL;
335 }
336 } else {
337 /* skip content */
338 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), restore);
339
340 if (lydxml_check_list(xmlctx, *snode)) {
341 /* invalid list, parse as opaque if it missing/has invalid some keys */
342 *snode = NULL;
343 }
344 }
345
346restore:
347 /* restore parser */
348 if (xmlctx->dynamic) {
349 free((char *)xmlctx->value);
350 }
351 xmlctx->status = prev_status;
352 xmlctx->prefix = pprefix;
353 xmlctx->prefix_len = pprefix_len;
354 xmlctx->name = pname;
355 xmlctx->name_len = pname_len;
Michal Vasko63f3d842020-07-08 10:10:14 +0200356 xmlctx->in->current = prev_current;
Michal Vasko1bf09392020-03-27 12:38:10 +0100357 }
358
359 return ret;
360}
361
Radek Krejcie7b95092019-05-15 11:03:07 +0200362/**
Michal Vaskoa5da3292020-08-12 13:10:50 +0200363 * @brief Parse XML subtree.
Radek Krejcie7b95092019-05-15 11:03:07 +0200364 *
Michal Vaskob36053d2020-03-26 15:49:30 +0100365 * @param[in] lydctx XML YANG data parser context.
Radek Krejcie7b95092019-05-15 11:03:07 +0200366 * @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 +0200367 * @param[out] node Resulting list of the parsed nodes.
Michal Vasko9b368d32020-02-14 13:53:31 +0100368 * @return LY_ERR value.
Radek Krejcie7b95092019-05-15 11:03:07 +0200369 */
370static LY_ERR
Michal Vaskoa5da3292020-08-12 13:10:50 +0200371lydxml_subtree_r(struct lyd_xml_ctx *lydctx, struct lyd_node_inner *parent, struct lyd_node **first_p)
Radek Krejcie7b95092019-05-15 11:03:07 +0200372{
Michal Vaskob36053d2020-03-26 15:49:30 +0100373 LY_ERR ret = LY_SUCCESS;
Michal Vasko1bf09392020-03-27 12:38:10 +0100374 const char *prefix, *name;
375 size_t prefix_len, name_len;
Michal Vaskob36053d2020-03-26 15:49:30 +0100376 struct lyxml_ctx *xmlctx;
377 const struct ly_ctx *ctx;
Radek Krejcie7b95092019-05-15 11:03:07 +0200378 const struct lyxml_ns *ns;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200379 struct lyd_meta *meta = NULL;
380 struct lyd_attr *attr = NULL;
Radek Krejcie7b95092019-05-15 11:03:07 +0200381 const struct lysc_node *snode;
382 struct lys_module *mod;
Michal Vasko1bf09392020-03-27 12:38:10 +0100383 uint32_t prev_opts;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200384 struct lyd_node *node = NULL, *anchor;
Michal Vasko52927e22020-03-16 17:26:14 +0100385 struct ly_prefix *val_prefs;
Radek Krejci1deb5be2020-08-26 16:43:36 +0200386 uint32_t getnext_opts;
Radek Krejcie7b95092019-05-15 11:03:07 +0200387
Michal Vaskob36053d2020-03-26 15:49:30 +0100388 xmlctx = lydctx->xmlctx;
389 ctx = xmlctx->ctx;
Michal Vasko1ce933a2020-03-30 12:38:22 +0200390 /* leave if-feature check for validation */
391 getnext_opts = LYS_GETNEXT_NOSTATECHECK | (lydctx->int_opts & LYD_INTOPT_REPLY ? LYS_GETNEXT_OUTPUT : 0);
Michal Vasko6f4cbb62020-02-28 11:15:47 +0100392
Michal Vaskoa5da3292020-08-12 13:10:50 +0200393 assert(xmlctx->status == LYXML_ELEMENT);
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200394
Michal Vaskoa5da3292020-08-12 13:10:50 +0200395 /* remember element prefix and name */
396 prefix = xmlctx->prefix;
397 prefix_len = xmlctx->prefix_len;
398 name = xmlctx->name;
399 name_len = xmlctx->name_len;
400
401 /* get the element module */
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200402 ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200403 if (!ns) {
404 LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".",
Michal Vasko69730152020-10-09 16:30:07 +0200405 prefix_len, prefix);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200406 ret = LY_EVALID;
407 goto error;
408 }
409 mod = ly_ctx_get_module_implemented_ns(ctx, ns->uri);
410 if (!mod) {
411 if (lydctx->parse_options & LYD_PARSE_STRICT) {
412 LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "No module with namespace \"%s\" in the context.",
Michal Vasko69730152020-10-09 16:30:07 +0200413 ns->uri);
Michal Vasko90932a92020-02-12 14:33:03 +0100414 ret = LY_EVALID;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200415 goto error;
Radek Krejcie7b95092019-05-15 11:03:07 +0200416 }
Michal Vaskoa5da3292020-08-12 13:10:50 +0200417 if (!(lydctx->parse_options & LYD_PARSE_OPAQ)) {
418 /* skip element with children */
419 LY_CHECK_GOTO(ret = lydxml_data_skip(xmlctx), error);
420 return LY_SUCCESS;
Radek Krejcie7b95092019-05-15 11:03:07 +0200421 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200422 }
423
Michal Vaskoa5da3292020-08-12 13:10:50 +0200424 /* parser next */
425 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
Michal Vasko90932a92020-02-12 14:33:03 +0100426
Michal Vaskoa5da3292020-08-12 13:10:50 +0200427 /* get the schema node */
428 snode = NULL;
429 if (mod && (!parent || parent->schema)) {
430 snode = lys_find_child(parent ? parent->schema : NULL, mod, name, name_len, 0, getnext_opts);
431 if (!snode) {
432 if (lydctx->parse_options & LYD_PARSE_STRICT) {
433 LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Element \"%.*s\" not found in the \"%s\" module.",
Michal Vasko69730152020-10-09 16:30:07 +0200434 name_len, name, mod->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200435 ret = LY_EVALID;
436 goto error;
437 } else if (!(lydctx->parse_options & LYD_PARSE_OPAQ)) {
438 /* skip element with children */
439 LY_CHECK_GOTO(ret = lydxml_data_skip(xmlctx), error);
440 return LY_SUCCESS;
441 }
442 } else {
443 /* check that schema node is valid and can be used */
444 LY_CHECK_GOTO(ret = lyd_parser_check_schema((struct lyd_ctx *)lydctx, snode), error);
445 LY_CHECK_GOTO(ret = lydxml_data_check_opaq(lydctx, &snode), error);
446 }
447 }
448
449 /* create metadata/attributes */
450 if (xmlctx->status == LYXML_ATTRIBUTE) {
451 if (snode) {
Michal Vaskofeca4fb2020-10-05 08:58:40 +0200452 ret = lydxml_metadata(lydctx, &meta);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200453 LY_CHECK_GOTO(ret, error);
454 } else {
455 assert(lydctx->parse_options & LYD_PARSE_OPAQ);
456 ret = lydxml_attrs(xmlctx, &attr);
457 LY_CHECK_GOTO(ret, error);
458 }
459 }
460
461 assert(xmlctx->status == LYXML_ELEM_CONTENT);
462 if (!snode) {
463 assert(lydctx->parse_options & LYD_PARSE_OPAQ);
464
465 if (xmlctx->ws_only) {
466 /* ignore WS-only value */
467 xmlctx->value_len = 0;
468 val_prefs = NULL;
469 } else {
470 /* get value prefixes */
471 ret = lyxml_get_prefixes(xmlctx, xmlctx->value, xmlctx->value_len, &val_prefs);
472 LY_CHECK_GOTO(ret, error);
473 }
474
475 /* create node */
Michal Vaskofeca4fb2020-10-05 08:58:40 +0200476 ret = lyd_create_opaq(ctx, name, name_len, xmlctx->value, xmlctx->value_len, &xmlctx->dynamic, LYD_XML,
Michal Vasko69730152020-10-09 16:30:07 +0200477 LYD_HINT_DATA, val_prefs, prefix, prefix_len, ns->uri, strlen(ns->uri), &node);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200478 LY_CHECK_GOTO(ret, error);
479
480 /* parser next */
481 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
482
483 /* process children */
484 while (xmlctx->status == LYXML_ELEMENT) {
485 ret = lydxml_subtree_r(lydctx, (struct lyd_node_inner *)node, lyd_node_children_p(node));
486 LY_CHECK_GOTO(ret, error);
487 }
488 } else if (snode->nodetype & LYD_NODE_TERM) {
489 /* create node */
Michal Vasko22df3f02020-08-24 13:29:22 +0200490 LY_CHECK_GOTO(ret = lyd_parser_create_term((struct lyd_ctx *)lydctx, snode, xmlctx->value, xmlctx->value_len,
Michal Vasko69730152020-10-09 16:30:07 +0200491 &xmlctx->dynamic, LY_PREF_XML, &xmlctx->ns, LYD_HINT_DATA, &node), error);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200492
493 if (parent && (node->schema->flags & LYS_KEY)) {
494 /* check the key order, the anchor must never be a key */
495 anchor = lyd_insert_get_next_anchor(parent->child, node);
496 if (anchor && (anchor->schema->flags & LYS_KEY)) {
497 if (lydctx->parse_options & LYD_PARSE_STRICT) {
498 LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_DATA, "Invalid position of the key \"%s\" in a list.",
Michal Vasko69730152020-10-09 16:30:07 +0200499 node->schema->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200500 ret = LY_EVALID;
501 goto error;
502 } else {
503 LOGWRN(ctx, "Invalid position of the key \"%s\" in a list.", node->schema->name);
504 }
505 }
506 }
507
508 /* parser next */
509 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
510
511 /* no children expected */
512 if (xmlctx->status == LYXML_ELEMENT) {
513 LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_SYNTAX, "Child element \"%.*s\" inside a terminal node \"%s\" found.",
Michal Vasko69730152020-10-09 16:30:07 +0200514 xmlctx->name_len, xmlctx->name, snode->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200515 ret = LY_EVALID;
516 goto error;
517 }
518 } else if (snode->nodetype & LYD_NODE_INNER) {
519 if (!xmlctx->ws_only) {
520 /* value in inner node */
521 LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_SYNTAX, "Text value \"%.*s\" inside an inner node \"%s\" found.",
Michal Vasko69730152020-10-09 16:30:07 +0200522 xmlctx->value_len, xmlctx->value, snode->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200523 ret = LY_EVALID;
524 goto error;
525 }
526
527 /* create node */
528 ret = lyd_create_inner(snode, &node);
529 LY_CHECK_GOTO(ret, error);
530
531 /* parser next */
532 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
533
534 /* process children */
535 while (xmlctx->status == LYXML_ELEMENT) {
536 ret = lydxml_subtree_r(lydctx, (struct lyd_node_inner *)node, lyd_node_children_p(node));
537 LY_CHECK_GOTO(ret, error);
538 }
539
540 if (snode->nodetype == LYS_LIST) {
541 /* check all keys exist */
542 LY_CHECK_GOTO(ret = lyd_parse_check_keys(node), error);
543 }
544
545 if (!(lydctx->parse_options & LYD_PARSE_ONLY)) {
546 /* new node validation, autodelete CANNOT occur, all nodes are new */
547 ret = lyd_validate_new(lyd_node_children_p(node), snode, NULL, NULL);
548 LY_CHECK_GOTO(ret, error);
549
550 /* add any missing default children */
551 ret = lyd_new_implicit_r(node, lyd_node_children_p(node), NULL, NULL, &lydctx->unres_node_type, &lydctx->when_check,
Michal Vasko69730152020-10-09 16:30:07 +0200552 (lydctx->validate_options & LYD_VALIDATE_NO_STATE) ? LYD_IMPLICIT_NO_STATE : 0, NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200553 LY_CHECK_GOTO(ret, error);
554 }
555
556 if (snode->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) {
557 /* rememeber the RPC/action/notification */
558 lydctx->op_node = node;
559 }
560 } else if (snode->nodetype & LYD_NODE_ANY) {
561 if (!xmlctx->ws_only) {
562 /* value in inner node */
563 LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_SYNTAX, "Text value \"%.*s\" inside an any node \"%s\" found.",
Michal Vasko69730152020-10-09 16:30:07 +0200564 xmlctx->value_len, xmlctx->value, snode->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200565 ret = LY_EVALID;
566 goto error;
567 }
568
569 /* parser next */
570 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
571
572 /* parse any data tree with correct options */
573 prev_opts = lydctx->parse_options;
574 lydctx->parse_options &= ~LYD_PARSE_STRICT;
575 lydctx->parse_options |= LYD_PARSE_OPAQ;
576 anchor = NULL;
577 while (xmlctx->status == LYXML_ELEMENT) {
578 ret = lydxml_subtree_r(lydctx, NULL, &anchor);
579 LY_CHECK_ERR_GOTO(ret, lydctx->parse_options = prev_opts, error);
580 }
581 lydctx->parse_options = prev_opts;
582
583 /* create node */
584 ret = lyd_create_any(snode, anchor, LYD_ANYDATA_DATATREE, &node);
585 LY_CHECK_GOTO(ret, error);
586 }
587 assert(node);
588
589 /* add/correct flags */
590 if (snode) {
591 lyd_parse_set_data_flags(node, &lydctx->when_check, &meta, lydctx->parse_options);
592 }
593
594 /* parser next */
595 assert(xmlctx->status == LYXML_ELEM_CLOSE);
596 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
597
598 /* add metadata/attributes */
599 if (snode) {
600 lyd_insert_meta(node, meta);
601 } else {
602 lyd_insert_attr(node, attr);
603 }
604
605 /* insert, keep first pointer correct */
606 lyd_insert_node((struct lyd_node *)parent, first_p, node);
607 while (!parent && (*first_p)->prev->next) {
608 *first_p = (*first_p)->prev;
609 }
610
611 return LY_SUCCESS;
612
613error:
Michal Vasko3a41dff2020-07-15 14:30:28 +0200614 lyd_free_meta_siblings(meta);
Radek Krejci011e4aa2020-09-04 15:22:31 +0200615 lyd_free_attr_siblings(ctx, attr);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200616 lyd_free_tree(node);
Radek Krejcie7b95092019-05-15 11:03:07 +0200617 return ret;
618}
619
620LY_ERR
Radek Krejci1deb5be2020-08-26 16:43:36 +0200621lyd_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 +0200622 struct lyd_node **tree_p, struct lyd_ctx **lydctx_p)
Radek Krejcie7b95092019-05-15 11:03:07 +0200623{
Radek Krejci18a57d92019-07-25 14:01:42 +0200624 LY_ERR ret = LY_SUCCESS;
Radek Krejci1798aae2020-07-14 13:26:06 +0200625 struct lyd_xml_ctx *lydctx;
Radek Krejcie7b95092019-05-15 11:03:07 +0200626
Radek Krejci7931b192020-06-25 17:05:03 +0200627 assert(!(parse_options & ~LYD_PARSE_OPTS_MASK));
628 assert(!(validate_options & ~LYD_VALIDATE_OPTS_MASK));
629
Radek Krejci1798aae2020-07-14 13:26:06 +0200630 /* init context */
631 lydctx = calloc(1, sizeof *lydctx);
632 LY_CHECK_ERR_RET(!lydctx, LOGMEM(ctx), LY_EMEM);
633 LY_CHECK_GOTO(ret = lyxml_ctx_new(ctx, in, &lydctx->xmlctx), cleanup);
634 lydctx->parse_options = parse_options;
635 lydctx->validate_options = validate_options;
636 lydctx->free = lyd_xml_ctx_free;
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200637
Michal Vaskob1b5c262020-03-05 14:29:47 +0100638 /* parse XML data */
Michal Vaskoa5da3292020-08-12 13:10:50 +0200639 while (lydctx->xmlctx->status == LYXML_ELEMENT) {
640 LY_CHECK_GOTO(ret = lydxml_subtree_r(lydctx, NULL, tree_p), cleanup);
641 }
Michal Vaskocde73ac2019-11-14 16:10:27 +0100642
Michal Vaskocde73ac2019-11-14 16:10:27 +0100643cleanup:
Michal Vasko9b368d32020-02-14 13:53:31 +0100644 /* there should be no unresolved types stored */
Michal Vasko69730152020-10-09 16:30:07 +0200645 assert(!(parse_options & LYD_PARSE_ONLY) || (!lydctx->unres_node_type.count && !lydctx->unres_meta_type.count &&
646 !lydctx->when_check.count));
Michal Vasko9b368d32020-02-14 13:53:31 +0100647
Michal Vasko9f96a052020-03-10 09:41:45 +0100648 if (ret) {
Radek Krejci1798aae2020-07-14 13:26:06 +0200649 lyd_xml_ctx_free((struct lyd_ctx *)lydctx);
650 lyd_free_all(*tree_p);
651 *tree_p = NULL;
652 } else {
653 *lydctx_p = (struct lyd_ctx *)lydctx;
Michal Vasko9f96a052020-03-10 09:41:45 +0100654 }
655 return ret;
656}
Michal Vasko1bf09392020-03-27 12:38:10 +0100657
658static LY_ERR
659lydxml_envelope(struct lyxml_ctx *xmlctx, const char *name, const char *uri, struct lyd_node **envp)
660{
661 LY_ERR ret = LY_SUCCESS;
662 const struct lyxml_ns *ns = NULL;
Radek Krejci1798aae2020-07-14 13:26:06 +0200663 struct lyd_attr *attr = NULL;
Michal Vasko1bf09392020-03-27 12:38:10 +0100664 const char *prefix;
665 size_t prefix_len;
666
667 *envp = NULL;
668
669 assert(xmlctx->status == LYXML_ELEMENT);
670 if (ly_strncmp(name, xmlctx->name, xmlctx->name_len)) {
671 /* not the expected element */
672 return LY_SUCCESS;
673 }
674
675 prefix = xmlctx->prefix;
676 prefix_len = xmlctx->prefix_len;
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200677 ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
Michal Vasko1bf09392020-03-27 12:38:10 +0100678 if (!ns) {
679 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".",
Michal Vasko69730152020-10-09 16:30:07 +0200680 prefix_len, prefix);
Michal Vasko1bf09392020-03-27 12:38:10 +0100681 return LY_EVALID;
682 } else if (strcmp(ns->uri, uri)) {
683 /* different namespace */
684 return LY_SUCCESS;
685 }
686
687 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
688
689 /* create attributes */
690 if (xmlctx->status == LYXML_ATTRIBUTE) {
691 LY_CHECK_RET(lydxml_attrs(xmlctx, &attr));
692 }
693
694 if (!xmlctx->ws_only) {
695 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_SYNTAX, "Unexpected value \"%.*s\" in the \"%s\" element.",
Michal Vasko69730152020-10-09 16:30:07 +0200696 xmlctx->value_len, xmlctx->value, name);
Michal Vasko1bf09392020-03-27 12:38:10 +0100697 ret = LY_EVALID;
698 goto cleanup;
699 }
700
701 /* parser next element */
702 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
703
704 /* create node */
Michal Vaskofeca4fb2020-10-05 08:58:40 +0200705 ret = lyd_create_opaq(xmlctx->ctx, name, strlen(name), "", 0, NULL, LYD_XML, LYD_NODEHINT_ENVELOPE, NULL, prefix,
706 prefix_len, uri, strlen(uri), envp);
Michal Vasko1bf09392020-03-27 12:38:10 +0100707 LY_CHECK_GOTO(ret, cleanup);
708
709 /* assign atributes */
710 ((struct lyd_node_opaq *)(*envp))->attr = attr;
711 attr = NULL;
712
713cleanup:
Radek Krejci011e4aa2020-09-04 15:22:31 +0200714 lyd_free_attr_siblings(xmlctx->ctx, attr);
Michal Vasko1bf09392020-03-27 12:38:10 +0100715 return ret;
716}
717
718LY_ERR
Radek Krejci1798aae2020-07-14 13:26:06 +0200719lyd_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 +0100720{
721 LY_ERR ret = LY_SUCCESS;
722 struct lyd_xml_ctx lydctx = {0};
723 struct lyd_node *rpc_e = NULL, *act_e = NULL;
Radek Krejci1798aae2020-07-14 13:26:06 +0200724 struct lyd_node *tree = NULL;
Michal Vasko1bf09392020-03-27 12:38:10 +0100725
726 /* init */
Michal Vasko63f3d842020-07-08 10:10:14 +0200727 LY_CHECK_GOTO(ret = lyxml_ctx_new(ctx, in, &lydctx.xmlctx), cleanup);
Radek Krejci1798aae2020-07-14 13:26:06 +0200728 lydctx.parse_options = LYD_PARSE_ONLY | LYD_PARSE_STRICT;
Michal Vasko1bf09392020-03-27 12:38:10 +0100729 lydctx.int_opts = LYD_INTOPT_RPC;
Michal Vasko1bf09392020-03-27 12:38:10 +0100730
731 /* parse "rpc", if any */
732 LY_CHECK_GOTO(ret = lydxml_envelope(lydctx.xmlctx, "rpc", "urn:ietf:params:xml:ns:netconf:base:1.0", &rpc_e), cleanup);
733
734 if (rpc_e) {
735 /* parse "action", if any */
736 LY_CHECK_GOTO(ret = lydxml_envelope(lydctx.xmlctx, "action", "urn:ietf:params:xml:ns:yang:1", &act_e), cleanup);
737 }
738
739 /* parse the rest of data normally */
Michal Vaskocf770e22020-08-12 13:21:43 +0200740 LY_CHECK_GOTO(ret = lydxml_subtree_r(&lydctx, NULL, &tree), cleanup);
Michal Vasko1bf09392020-03-27 12:38:10 +0100741
Michal Vaskocf770e22020-08-12 13:21:43 +0200742 /* make sure we have parsed some operation and it is the only subtree */
Radek Krejci1798aae2020-07-14 13:26:06 +0200743 if (!lydctx.op_node) {
Michal Vasko1bf09392020-03-27 12:38:10 +0100744 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_DATA, "Missing the \"rpc\"/\"action\" node.");
745 ret = LY_EVALID;
746 goto cleanup;
Michal Vaskocf770e22020-08-12 13:21:43 +0200747 } else if (lydctx.xmlctx->status == LYXML_ELEMENT) {
748 LOGVAL(ctx, LY_VLOG_LINE, &lydctx.xmlctx->line, LYVE_SYNTAX, "Unexpected sibling element of \"%s\".",
Michal Vasko69730152020-10-09 16:30:07 +0200749 tree->schema->name);
Michal Vaskocf770e22020-08-12 13:21:43 +0200750 ret = LY_EVALID;
751 goto cleanup;
Michal Vasko1bf09392020-03-27 12:38:10 +0100752 }
753
754 /* finish XML parsing and check operation type */
755 if (act_e) {
756 if (lydctx.xmlctx->status != LYXML_ELEM_CLOSE) {
757 assert(lydctx.xmlctx->status == LYXML_ELEMENT);
758 LOGVAL(ctx, LY_VLOG_LINE, &lydctx.xmlctx->line, LYVE_SYNTAX, "Unexpected sibling element \"%.*s\" of \"action\".",
Michal Vasko69730152020-10-09 16:30:07 +0200759 lydctx.xmlctx->name_len, lydctx.xmlctx->name);
Michal Vasko1bf09392020-03-27 12:38:10 +0100760 ret = LY_EVALID;
761 goto cleanup;
Radek Krejci1798aae2020-07-14 13:26:06 +0200762 } else if (lydctx.op_node->schema->nodetype != LYS_ACTION) {
763 LOGVAL(ctx, LY_VLOG_LYD, lydctx.op_node, LYVE_DATA, "Unexpected %s element, an \"action\" expected.",
Michal Vasko69730152020-10-09 16:30:07 +0200764 lys_nodetype2str(lydctx.op_node->schema->nodetype));
Michal Vasko1bf09392020-03-27 12:38:10 +0100765 ret = LY_EVALID;
766 goto cleanup;
767 }
768 LY_CHECK_GOTO(ret = lyxml_ctx_next(lydctx.xmlctx), cleanup);
769 }
770 if (rpc_e) {
771 if (lydctx.xmlctx->status != LYXML_ELEM_CLOSE) {
772 assert(lydctx.xmlctx->status == LYXML_ELEMENT);
773 LOGVAL(ctx, LY_VLOG_LINE, &lydctx.xmlctx->line, LYVE_SYNTAX, "Unexpected sibling element \"%.*s\" of \"rpc\".",
Michal Vasko69730152020-10-09 16:30:07 +0200774 lydctx.xmlctx->name_len, lydctx.xmlctx->name);
Michal Vasko1bf09392020-03-27 12:38:10 +0100775 ret = LY_EVALID;
776 goto cleanup;
Radek Krejci1798aae2020-07-14 13:26:06 +0200777 } else if (!act_e && (lydctx.op_node->schema->nodetype != LYS_RPC)) {
778 LOGVAL(ctx, LY_VLOG_LYD, lydctx.op_node, LYVE_DATA, "Unexpected %s element, an \"rpc\" expected.",
Michal Vasko69730152020-10-09 16:30:07 +0200779 lys_nodetype2str(lydctx.op_node->schema->nodetype));
Michal Vasko1bf09392020-03-27 12:38:10 +0100780 ret = LY_EVALID;
781 goto cleanup;
782 }
783 LY_CHECK_GOTO(ret = lyxml_ctx_next(lydctx.xmlctx), cleanup);
784 }
785
Radek Krejci1798aae2020-07-14 13:26:06 +0200786 if (op_p) {
787 *op_p = lydctx.op_node;
Michal Vaskocc048b22020-03-27 15:52:38 +0100788 }
Radek Krejci1798aae2020-07-14 13:26:06 +0200789 assert(tree);
Michal Vasko1bf09392020-03-27 12:38:10 +0100790 if (act_e) {
791 /* connect to the action */
Michal Vasko4189c0f2020-08-13 09:05:22 +0200792 lyd_insert_node(act_e, NULL, tree);
793 tree = act_e;
Michal Vasko1bf09392020-03-27 12:38:10 +0100794 }
795 if (rpc_e) {
796 /* connect to the rpc */
Michal Vasko4189c0f2020-08-13 09:05:22 +0200797 lyd_insert_node(rpc_e, NULL, tree);
798 tree = rpc_e;
799 }
800 if (tree_p) {
801 *tree_p = tree;
Michal Vasko1bf09392020-03-27 12:38:10 +0100802 }
803
804cleanup:
805 /* we have used parse_only flag */
806 assert(!lydctx.unres_node_type.count && !lydctx.unres_meta_type.count && !lydctx.when_check.count);
807 lyxml_ctx_free(lydctx.xmlctx);
808 if (ret) {
Radek Krejci1798aae2020-07-14 13:26:06 +0200809 lyd_free_all(tree);
Michal Vasko1bf09392020-03-27 12:38:10 +0100810 lyd_free_tree(act_e);
811 lyd_free_tree(rpc_e);
Michal Vasko1bf09392020-03-27 12:38:10 +0100812 }
813 return ret;
814}
Michal Vaskoa8edff02020-03-27 14:47:01 +0100815
816static LY_ERR
817lydxml_notif_envelope(struct lyxml_ctx *xmlctx, struct lyd_node **envp)
818{
819 LY_ERR ret = LY_SUCCESS;
820 const struct lyxml_ns *ns = NULL;
Radek Krejci1798aae2020-07-14 13:26:06 +0200821 struct lyd_attr *attr = NULL;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100822 struct lyd_node *et;
823 const char *prefix;
824 size_t prefix_len;
825
826 *envp = NULL;
827
828 /* container envelope */
829 LY_CHECK_GOTO(ret = lydxml_envelope(xmlctx, "notification", "urn:ietf:params:xml:ns:netconf:notification:1.0",
Michal Vasko69730152020-10-09 16:30:07 +0200830 envp), cleanup);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100831
832 /* no envelope, fine */
833 if (!*envp) {
834 goto cleanup;
835 }
836
837 /* child "eventTime" */
838 if ((xmlctx->status != LYXML_ELEMENT) || ly_strncmp("eventTime", xmlctx->name, xmlctx->name_len)) {
839 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Missing the \"eventTime\" element.");
840 ret = LY_EVALID;
841 goto cleanup;
842 }
843
844 prefix = xmlctx->prefix;
845 prefix_len = xmlctx->prefix_len;
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200846 ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100847 if (!ns) {
848 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".",
Michal Vasko69730152020-10-09 16:30:07 +0200849 prefix_len, prefix);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100850 ret = LY_EVALID;
851 goto cleanup;
852 } else if (strcmp(ns->uri, "urn:ietf:params:xml:ns:netconf:notification:1.0")) {
853 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Invalid namespace \"%s\" of \"eventTime\".",
Michal Vasko69730152020-10-09 16:30:07 +0200854 ns->uri);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100855 ret = LY_EVALID;
856 goto cleanup;
857 }
858
859 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
860
861 /* create attributes */
862 if (xmlctx->status == LYXML_ATTRIBUTE) {
863 LY_CHECK_RET(lydxml_attrs(xmlctx, &attr));
864 }
865
866 /* validate value */
867 /* TODO */
868 /*if (!xmlctx->ws_only) {
869 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_SYNTAX, "Unexpected value \"%.*s\" in the \"%s\" element.",
870 xmlctx->value_len, xmlctx->value, name);
871 ret = LY_EVALID;
872 goto cleanup;
873 }*/
874
875 /* create node */
Michal Vaskofeca4fb2020-10-05 08:58:40 +0200876 ret = lyd_create_opaq(xmlctx->ctx, "eventTime", 9, xmlctx->value, xmlctx->value_len, NULL, LYD_XML,
877 LYD_NODEHINT_ENVELOPE, NULL, prefix, prefix_len, ns->uri, strlen(ns->uri), &et);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100878 LY_CHECK_GOTO(ret, cleanup);
879
880 /* assign atributes */
881 ((struct lyd_node_opaq *)et)->attr = attr;
882 attr = NULL;
883
884 /* insert */
885 lyd_insert_node(*envp, NULL, et);
886
887 /* finish parsing */
888 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
889 if (xmlctx->status != LYXML_ELEM_CLOSE) {
890 assert(xmlctx->status == LYXML_ELEMENT);
891 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_SYNTAX, "Unexpected sibling element \"%.*s\" of \"eventTime\".",
Michal Vasko69730152020-10-09 16:30:07 +0200892 xmlctx->name_len, xmlctx->name);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100893 ret = LY_EVALID;
894 goto cleanup;
895 }
896 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
897
898cleanup:
899 if (ret) {
900 lyd_free_tree(*envp);
Radek Krejci011e4aa2020-09-04 15:22:31 +0200901 lyd_free_attr_siblings(xmlctx->ctx, attr);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100902 }
903 return ret;
904}
905
906LY_ERR
Radek Krejci1798aae2020-07-14 13:26:06 +0200907lyd_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 +0100908{
909 LY_ERR ret = LY_SUCCESS;
910 struct lyd_xml_ctx lydctx = {0};
911 struct lyd_node *ntf_e = NULL;
Radek Krejci1798aae2020-07-14 13:26:06 +0200912 struct lyd_node *tree = NULL;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100913
914 /* init */
Michal Vasko63f3d842020-07-08 10:10:14 +0200915 LY_CHECK_GOTO(ret = lyxml_ctx_new(ctx, in, &lydctx.xmlctx), cleanup);
Radek Krejci1798aae2020-07-14 13:26:06 +0200916 lydctx.parse_options = LYD_PARSE_ONLY | LYD_PARSE_STRICT;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100917 lydctx.int_opts = LYD_INTOPT_NOTIF;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100918
919 /* parse "notification" and "eventTime", if present */
920 LY_CHECK_GOTO(ret = lydxml_notif_envelope(lydctx.xmlctx, &ntf_e), cleanup);
921
922 /* parse the rest of data normally */
Michal Vaskocf770e22020-08-12 13:21:43 +0200923 LY_CHECK_GOTO(ret = lydxml_subtree_r(&lydctx, NULL, &tree), cleanup);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100924
925 /* make sure we have parsed some notification */
Radek Krejci1798aae2020-07-14 13:26:06 +0200926 if (!lydctx.op_node) {
Michal Vaskoa8edff02020-03-27 14:47:01 +0100927 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_DATA, "Missing the \"notification\" node.");
928 ret = LY_EVALID;
929 goto cleanup;
Michal Vaskocf770e22020-08-12 13:21:43 +0200930 } else if (lydctx.xmlctx->status == LYXML_ELEMENT) {
931 LOGVAL(ctx, LY_VLOG_LINE, &lydctx.xmlctx->line, LYVE_SYNTAX, "Unexpected sibling element of \"%s\".",
Michal Vasko69730152020-10-09 16:30:07 +0200932 tree->schema->name);
Michal Vaskocf770e22020-08-12 13:21:43 +0200933 ret = LY_EVALID;
934 goto cleanup;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100935 }
936
937 /* finish XML parsing */
938 if (ntf_e) {
939 if (lydctx.xmlctx->status != LYXML_ELEM_CLOSE) {
940 assert(lydctx.xmlctx->status == LYXML_ELEMENT);
941 LOGVAL(ctx, LY_VLOG_LINE, &lydctx.xmlctx->line, LYVE_SYNTAX, "Unexpected sibling element \"%.*s\" of \"notification\".",
Michal Vasko69730152020-10-09 16:30:07 +0200942 lydctx.xmlctx->name_len, lydctx.xmlctx->name);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100943 ret = LY_EVALID;
944 goto cleanup;
945 }
946 LY_CHECK_GOTO(ret = lyxml_ctx_next(lydctx.xmlctx), cleanup);
947 }
948
Radek Krejci1798aae2020-07-14 13:26:06 +0200949 if (ntf_p) {
950 *ntf_p = lydctx.op_node;
Michal Vaskocc048b22020-03-27 15:52:38 +0100951 }
Radek Krejci1798aae2020-07-14 13:26:06 +0200952 assert(tree);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100953 if (ntf_e) {
954 /* connect to the notification */
Michal Vasko4189c0f2020-08-13 09:05:22 +0200955 lyd_insert_node(ntf_e, NULL, tree);
956 tree = ntf_e;
957 }
958 if (tree_p) {
959 *tree_p = tree;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100960 }
961
962cleanup:
963 /* we have used parse_only flag */
964 assert(!lydctx.unres_node_type.count && !lydctx.unres_meta_type.count && !lydctx.when_check.count);
965 lyxml_ctx_free(lydctx.xmlctx);
966 if (ret) {
Radek Krejci1798aae2020-07-14 13:26:06 +0200967 lyd_free_all(tree);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100968 lyd_free_tree(ntf_e);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100969 }
970 return ret;
971}
Michal Vasko1ce933a2020-03-30 12:38:22 +0200972
973LY_ERR
Radek Krejci1798aae2020-07-14 13:26:06 +0200974lyd_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 +0200975{
976 LY_ERR ret = LY_SUCCESS;
977 struct lyd_xml_ctx lydctx = {0};
Michal Vasko4189c0f2020-08-13 09:05:22 +0200978 struct lyd_node *rpcr_e = NULL, *tree, *req_op, *rep_op = NULL;
Michal Vasko1ce933a2020-03-30 12:38:22 +0200979
980 /* init */
Michal Vaskob7be7a82020-08-20 09:09:04 +0200981 LY_CHECK_GOTO(ret = lyxml_ctx_new(LYD_CTX(request), in, &lydctx.xmlctx), cleanup);
Radek Krejci1798aae2020-07-14 13:26:06 +0200982 lydctx.parse_options = LYD_PARSE_ONLY | LYD_PARSE_STRICT;
Michal Vasko1ce933a2020-03-30 12:38:22 +0200983 lydctx.int_opts = LYD_INTOPT_REPLY;
Michal Vasko1ce933a2020-03-30 12:38:22 +0200984
985 /* find request OP */
Michal Vasko56daf732020-08-10 10:57:18 +0200986 LYD_TREE_DFS_BEGIN((struct lyd_node *)request, req_op) {
Michal Vasko1ce933a2020-03-30 12:38:22 +0200987 if (req_op->schema->nodetype & (LYS_RPC | LYS_ACTION)) {
988 break;
989 }
Michal Vasko56daf732020-08-10 10:57:18 +0200990 LYD_TREE_DFS_END(request, req_op);
Michal Vasko1ce933a2020-03-30 12:38:22 +0200991 }
992 if (!(req_op->schema->nodetype & (LYS_RPC | LYS_ACTION))) {
Michal Vaskob7be7a82020-08-20 09:09:04 +0200993 LOGERR(LYD_CTX(request), LY_EINVAL, "No RPC/action in the request found.");
Michal Vasko1ce933a2020-03-30 12:38:22 +0200994 ret = LY_EINVAL;
995 goto cleanup;
996 }
997
998 /* duplicate request OP with parents */
Michal Vasko3a41dff2020-07-15 14:30:28 +0200999 LY_CHECK_GOTO(ret = lyd_dup_single(req_op, NULL, LYD_DUP_WITH_PARENTS, &rep_op), cleanup);
Michal Vasko1ce933a2020-03-30 12:38:22 +02001000
1001 /* parse "rpc-reply", if any */
Michal Vasko3a41dff2020-07-15 14:30:28 +02001002 LY_CHECK_GOTO(ret = lydxml_envelope(lydctx.xmlctx, "rpc-reply", "urn:ietf:params:xml:ns:netconf:base:1.0", &rpcr_e),
Michal Vasko69730152020-10-09 16:30:07 +02001003 cleanup);
Michal Vasko1ce933a2020-03-30 12:38:22 +02001004
1005 /* parse the rest of data normally but connect them to the duplicated operation */
Michal Vaskoa5da3292020-08-12 13:10:50 +02001006 while (lydctx.xmlctx->status == LYXML_ELEMENT) {
1007 ret = lydxml_subtree_r(&lydctx, (struct lyd_node_inner *)rep_op, lyd_node_children_p(rep_op));
1008 LY_CHECK_GOTO(ret, cleanup);
1009 }
Michal Vasko1ce933a2020-03-30 12:38:22 +02001010
1011 /* finish XML parsing and check operation type */
1012 if (rpcr_e) {
1013 if (lydctx.xmlctx->status != LYXML_ELEM_CLOSE) {
1014 assert(lydctx.xmlctx->status == LYXML_ELEMENT);
Michal Vaskob7be7a82020-08-20 09:09:04 +02001015 LOGVAL(LYD_CTX(request), LY_VLOG_LINE, &lydctx.xmlctx->line, LYVE_SYNTAX,
Michal Vasko69730152020-10-09 16:30:07 +02001016 "Unexpected sibling element \"%.*s\" of \"rpc-reply\".", lydctx.xmlctx->name_len, lydctx.xmlctx->name);
Michal Vasko1ce933a2020-03-30 12:38:22 +02001017 ret = LY_EVALID;
1018 goto cleanup;
1019 }
1020 LY_CHECK_GOTO(ret = lyxml_ctx_next(lydctx.xmlctx), cleanup);
1021 }
1022
Radek Krejci1798aae2020-07-14 13:26:06 +02001023 if (op_p) {
1024 *op_p = rep_op;
Michal Vasko1ce933a2020-03-30 12:38:22 +02001025 }
Radek Krejcia1c1e542020-09-29 16:06:52 +02001026 for (tree = rep_op; tree->parent; tree = lyd_parent(tree)) {}
Michal Vasko1ce933a2020-03-30 12:38:22 +02001027 if (rpcr_e) {
1028 /* connect to the operation */
Michal Vasko4189c0f2020-08-13 09:05:22 +02001029 lyd_insert_node(rpcr_e, NULL, tree);
1030 tree = rpcr_e;
1031 }
1032 if (tree_p) {
1033 *tree_p = tree;
Michal Vasko1ce933a2020-03-30 12:38:22 +02001034 }
1035
1036cleanup:
1037 /* we have used parse_only flag */
1038 assert(!lydctx.unres_node_type.count && !lydctx.unres_meta_type.count && !lydctx.when_check.count);
1039 lyxml_ctx_free(lydctx.xmlctx);
1040 if (ret) {
1041 lyd_free_all(rep_op);
1042 lyd_free_tree(rpcr_e);
1043 }
1044 return ret;
1045}