blob: dc899de041e4ad54344fae99c5d72799da712166 [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 Krejci47fab892020-11-05 17:02:41 +010027#include "tree_data.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 */
Michal Vasko49c39d82020-11-06 17:20:27 +010044 struct ly_set node_types; /**< set of nodes validated with LY_EINCOMPLETE result */
45 struct ly_set meta_types; /**< set of metadata validated with LY_EINCOMPLETE result */
46 struct ly_set node_when; /**< set of nodes with "when" conditions */
Radek Krejci1798aae2020-07-14 13:26:06 +020047 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;
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100218 while ((snode = lys_getnext(snode, list, NULL, 0)) && (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 Vasko7b1ad1a2020-11-02 15:41:27 +0100390 getnext_opts = 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\".",
Michal Vasko69730152020-10-09 16:30:07 +0200404 prefix_len, prefix);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200405 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.",
Michal Vasko69730152020-10-09 16:30:07 +0200412 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.",
Michal Vasko69730152020-10-09 16:30:07 +0200433 name_len, name, mod->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200434 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,
Michal Vasko69730152020-10-09 16:30:07 +0200476 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 Vasko69730152020-10-09 16:30:07 +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.",
Michal Vasko69730152020-10-09 16:30:07 +0200498 node->schema->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200499 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.",
Michal Vasko69730152020-10-09 16:30:07 +0200513 xmlctx->name_len, xmlctx->name, snode->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200514 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.",
Michal Vasko69730152020-10-09 16:30:07 +0200521 xmlctx->value_len, xmlctx->value, snode->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200522 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 */
Michal Vasko49c39d82020-11-06 17:20:27 +0100550 ret = lyd_new_implicit_r(node, lyd_node_children_p(node), NULL, NULL, &lydctx->node_types, &lydctx->node_when,
Michal Vasko69730152020-10-09 16:30:07 +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.",
Michal Vasko69730152020-10-09 16:30:07 +0200563 xmlctx->value_len, xmlctx->value, snode->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200564 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) {
Michal Vasko49c39d82020-11-06 17:20:27 +0100590 lyd_parse_set_data_flags(node, &lydctx->node_when, &meta, lydctx->parse_options);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200591 }
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 Vasko49c39d82020-11-06 17:20:27 +0100643 /* there should be no unres stored if validation should be skipped */
644 assert(!(parse_options & LYD_PARSE_ONLY) || (!lydctx->node_types.count && !lydctx->meta_types.count &&
645 !lydctx->node_when.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\".",
Michal Vasko69730152020-10-09 16:30:07 +0200679 prefix_len, prefix);
Michal Vasko1bf09392020-03-27 12:38:10 +0100680 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.",
Michal Vasko69730152020-10-09 16:30:07 +0200695 xmlctx->value_len, xmlctx->value, name);
Michal Vasko1bf09392020-03-27 12:38:10 +0100696 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\".",
Michal Vasko69730152020-10-09 16:30:07 +0200748 tree->schema->name);
Michal Vaskocf770e22020-08-12 13:21:43 +0200749 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\".",
Michal Vasko69730152020-10-09 16:30:07 +0200758 lydctx.xmlctx->name_len, lydctx.xmlctx->name);
Michal Vasko1bf09392020-03-27 12:38:10 +0100759 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.",
Michal Vasko69730152020-10-09 16:30:07 +0200763 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\".",
Michal Vasko69730152020-10-09 16:30:07 +0200773 lydctx.xmlctx->name_len, lydctx.xmlctx->name);
Michal Vasko1bf09392020-03-27 12:38:10 +0100774 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.",
Michal Vasko69730152020-10-09 16:30:07 +0200778 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 */
Michal Vasko49c39d82020-11-06 17:20:27 +0100805 assert(!lydctx.node_types.count && !lydctx.meta_types.count && !lydctx.node_when.count);
Michal Vasko1bf09392020-03-27 12:38:10 +0100806 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",
Michal Vasko69730152020-10-09 16:30:07 +0200829 envp), cleanup);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100830
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\".",
Michal Vasko69730152020-10-09 16:30:07 +0200848 prefix_len, prefix);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100849 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\".",
Michal Vasko69730152020-10-09 16:30:07 +0200853 ns->uri);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100854 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\".",
Michal Vasko69730152020-10-09 16:30:07 +0200891 xmlctx->name_len, xmlctx->name);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100892 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\".",
Michal Vasko69730152020-10-09 16:30:07 +0200931 tree->schema->name);
Michal Vaskocf770e22020-08-12 13:21:43 +0200932 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\".",
Michal Vasko69730152020-10-09 16:30:07 +0200941 lydctx.xmlctx->name_len, lydctx.xmlctx->name);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100942 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 */
Michal Vasko49c39d82020-11-06 17:20:27 +0100963 assert(!lydctx.node_types.count && !lydctx.meta_types.count && !lydctx.node_when.count);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100964 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),
Michal Vasko69730152020-10-09 16:30:07 +02001002 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 Vasko69730152020-10-09 16:30:07 +02001015 "Unexpected sibling element \"%.*s\" of \"rpc-reply\".", lydctx.xmlctx->name_len, lydctx.xmlctx->name);
Michal Vasko1ce933a2020-03-30 12:38:22 +02001016 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 */
Michal Vasko49c39d82020-11-06 17:20:27 +01001037 assert(!lydctx.node_types.count && !lydctx.meta_types.count && !lydctx.node_when.count);
Michal Vasko1ce933a2020-03-30 12:38:22 +02001038 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}