blob: bddd17fb500050c84ddbab5c4f32c1024a288914 [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;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100145 void *val_prefix_data;
146 LY_PREFIX_FORMAT format;
Radek Krejci1798aae2020-07-14 13:26:06 +0200147 struct lyd_attr *attr2;
Michal Vaskob36053d2020-03-26 15:49:30 +0100148 const char *name, *prefix;
149 size_t name_len, prefix_len;
Michal Vasko52927e22020-03-16 17:26:14 +0100150
151 assert(attr);
Michal Vaskob36053d2020-03-26 15:49:30 +0100152 *attr = NULL;
Michal Vasko52927e22020-03-16 17:26:14 +0100153
Michal Vaskob36053d2020-03-26 15:49:30 +0100154 while (xmlctx->status == LYXML_ATTRIBUTE) {
Michal Vasko52927e22020-03-16 17:26:14 +0100155 ns = NULL;
Michal Vaskob36053d2020-03-26 15:49:30 +0100156 if (xmlctx->prefix_len) {
Michal Vasko52927e22020-03-16 17:26:14 +0100157 /* get namespace of the attribute */
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200158 ns = lyxml_ns_get(&xmlctx->ns, xmlctx->prefix, xmlctx->prefix_len);
Michal Vasko52927e22020-03-16 17:26:14 +0100159 if (!ns) {
160 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".",
Michal Vasko69730152020-10-09 16:30:07 +0200161 xmlctx->prefix_len, xmlctx->prefix);
Michal Vasko52927e22020-03-16 17:26:14 +0100162 ret = LY_EVALID;
163 goto cleanup;
164 }
165 }
166
167 if (*attr) {
168 attr2 = *attr;
169 } else {
170 attr2 = NULL;
171 }
172
Michal Vaskob36053d2020-03-26 15:49:30 +0100173 /* remember attr prefix, name, and get its content */
174 prefix = xmlctx->prefix;
175 prefix_len = xmlctx->prefix_len;
176 name = xmlctx->name;
177 name_len = xmlctx->name_len;
178 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
179 assert(xmlctx->status == LYXML_ATTR_CONTENT);
180
Michal Vasko52927e22020-03-16 17:26:14 +0100181 /* get value prefixes */
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100182 LY_CHECK_GOTO(ret = ly_store_prefix_data(xmlctx->ctx, xmlctx->value, xmlctx->value_len, LY_PREF_XML,
183 &xmlctx->ns, &format, &val_prefix_data), cleanup);
Michal Vasko52927e22020-03-16 17:26:14 +0100184
185 /* attr2 is always changed to the created attribute */
Michal Vasko501af032020-11-11 20:27:44 +0100186 ret = lyd_create_attr(NULL, &attr2, xmlctx->ctx, name, name_len, prefix, prefix_len, ns ? ns->uri : NULL,
187 ns ? strlen(ns->uri) : 0, xmlctx->value, xmlctx->value_len, &xmlctx->dynamic, format, val_prefix_data, 0);
Michal Vasko52927e22020-03-16 17:26:14 +0100188 LY_CHECK_GOTO(ret, cleanup);
189
190 if (!*attr) {
191 *attr = attr2;
192 }
Michal Vaskob36053d2020-03-26 15:49:30 +0100193
194 /* next attribute */
195 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko52927e22020-03-16 17:26:14 +0100196 }
197
198cleanup:
Michal Vaskob36053d2020-03-26 15:49:30 +0100199 if (ret) {
Radek Krejci011e4aa2020-09-04 15:22:31 +0200200 lyd_free_attr_siblings(xmlctx->ctx, *attr);
Michal Vaskob36053d2020-03-26 15:49:30 +0100201 *attr = NULL;
Michal Vasko52927e22020-03-16 17:26:14 +0100202 }
Michal Vasko52927e22020-03-16 17:26:14 +0100203 return ret;
204}
205
Michal Vasko44685da2020-03-17 15:38:06 +0100206static LY_ERR
Michal Vaskob36053d2020-03-26 15:49:30 +0100207lydxml_check_list(struct lyxml_ctx *xmlctx, const struct lysc_node *list)
Michal Vasko44685da2020-03-17 15:38:06 +0100208{
Michal Vaskob36053d2020-03-26 15:49:30 +0100209 LY_ERR ret = LY_SUCCESS, r;
210 enum LYXML_PARSER_STATUS next;
Michal Vasko44685da2020-03-17 15:38:06 +0100211 struct ly_set key_set = {0};
212 const struct lysc_node *snode;
Michal Vaskob36053d2020-03-26 15:49:30 +0100213 uint32_t i, parents_count;
Michal Vasko44685da2020-03-17 15:38:06 +0100214
215 assert(list && (list->nodetype == LYS_LIST));
216
217 /* get all keys into a set (keys do not have if-features or anything) */
218 snode = NULL;
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100219 while ((snode = lys_getnext(snode, list, NULL, 0)) && (snode->flags & LYS_KEY)) {
Radek Krejci3d92e442020-10-12 12:48:13 +0200220 ret = ly_set_add(&key_set, (void *)snode, 1, NULL);
Radek Krejciba03a5a2020-08-27 14:40:41 +0200221 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100222 }
223
Michal Vaskob36053d2020-03-26 15:49:30 +0100224 while (xmlctx->status == LYXML_ELEMENT) {
Michal Vasko44685da2020-03-17 15:38:06 +0100225 /* find key definition */
226 for (i = 0; i < key_set.count; ++i) {
227 snode = (const struct lysc_node *)key_set.objs[i];
Michal Vaskob36053d2020-03-26 15:49:30 +0100228 if (!ly_strncmp(snode->name, xmlctx->name, xmlctx->name_len)) {
Michal Vasko44685da2020-03-17 15:38:06 +0100229 break;
230 }
231 }
Michal Vaskob36053d2020-03-26 15:49:30 +0100232 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100233
234 /* skip attributes */
235 while (xmlctx->status == LYXML_ATTRIBUTE) {
Michal Vaskob36053d2020-03-26 15:49:30 +0100236 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
237 assert(xmlctx->status == LYXML_ATTR_CONTENT);
238 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100239 }
240
Michal Vaskob36053d2020-03-26 15:49:30 +0100241 assert(xmlctx->status == LYXML_ELEM_CONTENT);
242 if (i < key_set.count) {
243 /* validate the value */
Michal Vasko713148b2020-11-12 13:10:13 +0100244 r = _lys_value_validate(NULL, snode, xmlctx->value, xmlctx->value_len, LY_PREF_XML, &xmlctx->ns);
Michal Vaskob36053d2020-03-26 15:49:30 +0100245 if (!r) {
246 /* key with a valid value, remove from the set */
247 ly_set_rm_index(&key_set, i, NULL);
Michal Vasko44685da2020-03-17 15:38:06 +0100248 }
249 }
250
Michal Vaskob36053d2020-03-26 15:49:30 +0100251 /* parser next */
252 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100253
Michal Vaskob36053d2020-03-26 15:49:30 +0100254 /* skip any children, resursively */
255 parents_count = xmlctx->elements.count;
256 while ((parents_count < xmlctx->elements.count) || (xmlctx->status == LYXML_ELEMENT)) {
257 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
258 }
259
260 /* parser next, but do not parse closing element of the list because it would remove its namespaces */
261 assert(xmlctx->status == LYXML_ELEM_CLOSE);
262 LY_CHECK_GOTO(ret = lyxml_ctx_peek(xmlctx, &next), cleanup);
263 if (next != LYXML_ELEM_CLOSE) {
264 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
265 }
Michal Vasko44685da2020-03-17 15:38:06 +0100266 }
267
268 if (key_set.count) {
Michal Vaskob36053d2020-03-26 15:49:30 +0100269 /* some keys are missing/did not validate */
Michal Vasko44685da2020-03-17 15:38:06 +0100270 ret = LY_ENOT;
Michal Vasko44685da2020-03-17 15:38:06 +0100271 }
272
273cleanup:
274 ly_set_erase(&key_set, NULL);
275 return ret;
276}
277
Michal Vasko1bf09392020-03-27 12:38:10 +0100278static LY_ERR
279lydxml_data_skip(struct lyxml_ctx *xmlctx)
280{
281 uint32_t parents_count;
282
283 /* remember current number of parents */
284 parents_count = xmlctx->elements.count;
285
286 /* skip after the content */
287 while (xmlctx->status != LYXML_ELEM_CONTENT) {
288 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
289 }
290 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
291
292 /* skip all children elements, recursively, if any */
293 while (parents_count < xmlctx->elements.count) {
294 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
295 }
296
297 /* close element */
298 assert(xmlctx->status == LYXML_ELEM_CLOSE);
299 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
300
301 return LY_SUCCESS;
302}
303
304static LY_ERR
Radek Krejci1798aae2020-07-14 13:26:06 +0200305lydxml_data_check_opaq(struct lyd_xml_ctx *lydctx, const struct lysc_node **snode)
Michal Vasko1bf09392020-03-27 12:38:10 +0100306{
307 LY_ERR ret = LY_SUCCESS;
308 enum LYXML_PARSER_STATUS prev_status;
Michal Vasko63f3d842020-07-08 10:10:14 +0200309 const char *prev_current, *pname, *pprefix;
Michal Vasko1bf09392020-03-27 12:38:10 +0100310 size_t pprefix_len, pname_len;
311 struct lyxml_ctx *xmlctx = lydctx->xmlctx;
312
Radek Krejci1798aae2020-07-14 13:26:06 +0200313 if ((lydctx->parse_options & LYD_PARSE_OPAQ) && ((*snode)->nodetype & (LYD_NODE_TERM | LYS_LIST))) {
Michal Vasko1bf09392020-03-27 12:38:10 +0100314 /* backup parser */
315 prev_status = xmlctx->status;
316 pprefix = xmlctx->prefix;
317 pprefix_len = xmlctx->prefix_len;
318 pname = xmlctx->name;
319 pname_len = xmlctx->name_len;
Michal Vasko63f3d842020-07-08 10:10:14 +0200320 prev_current = xmlctx->in->current;
Michal Vasko1bf09392020-03-27 12:38:10 +0100321 if ((xmlctx->status == LYXML_ELEM_CONTENT) && xmlctx->dynamic) {
322 /* it was backed up, do not free */
323 xmlctx->dynamic = 0;
324 }
325
326 /* skip attributes */
327 while (xmlctx->status == LYXML_ATTRIBUTE) {
328 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), restore);
329 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), restore);
330 }
331
332 if ((*snode)->nodetype & LYD_NODE_TERM) {
333 /* value may not be valid in which case we parse it as an opaque node */
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200334 if (_lys_value_validate(NULL, *snode, xmlctx->value, xmlctx->value_len, LY_PREF_XML, &xmlctx->ns)) {
Michal Vasko1bf09392020-03-27 12:38:10 +0100335 *snode = NULL;
336 }
337 } else {
338 /* skip content */
339 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), restore);
340
341 if (lydxml_check_list(xmlctx, *snode)) {
342 /* invalid list, parse as opaque if it missing/has invalid some keys */
343 *snode = NULL;
344 }
345 }
346
347restore:
348 /* restore parser */
349 if (xmlctx->dynamic) {
350 free((char *)xmlctx->value);
351 }
352 xmlctx->status = prev_status;
353 xmlctx->prefix = pprefix;
354 xmlctx->prefix_len = pprefix_len;
355 xmlctx->name = pname;
356 xmlctx->name_len = pname_len;
Michal Vasko63f3d842020-07-08 10:10:14 +0200357 xmlctx->in->current = prev_current;
Michal Vasko1bf09392020-03-27 12:38:10 +0100358 }
359
360 return ret;
361}
362
Radek Krejcie7b95092019-05-15 11:03:07 +0200363/**
Michal Vaskoa5da3292020-08-12 13:10:50 +0200364 * @brief Parse XML subtree.
Radek Krejcie7b95092019-05-15 11:03:07 +0200365 *
Michal Vaskob36053d2020-03-26 15:49:30 +0100366 * @param[in] lydctx XML YANG data parser context.
Radek Krejcie7b95092019-05-15 11:03:07 +0200367 * @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 +0200368 * @param[out] node Resulting list of the parsed nodes.
Michal Vasko9b368d32020-02-14 13:53:31 +0100369 * @return LY_ERR value.
Radek Krejcie7b95092019-05-15 11:03:07 +0200370 */
371static LY_ERR
Michal Vaskoa5da3292020-08-12 13:10:50 +0200372lydxml_subtree_r(struct lyd_xml_ctx *lydctx, struct lyd_node_inner *parent, struct lyd_node **first_p)
Radek Krejcie7b95092019-05-15 11:03:07 +0200373{
Michal Vaskob36053d2020-03-26 15:49:30 +0100374 LY_ERR ret = LY_SUCCESS;
Michal Vasko1bf09392020-03-27 12:38:10 +0100375 const char *prefix, *name;
376 size_t prefix_len, name_len;
Michal Vaskob36053d2020-03-26 15:49:30 +0100377 struct lyxml_ctx *xmlctx;
378 const struct ly_ctx *ctx;
Radek Krejcie7b95092019-05-15 11:03:07 +0200379 const struct lyxml_ns *ns;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200380 struct lyd_meta *meta = NULL;
381 struct lyd_attr *attr = NULL;
Radek Krejcie7b95092019-05-15 11:03:07 +0200382 const struct lysc_node *snode;
383 struct lys_module *mod;
Michal Vasko1bf09392020-03-27 12:38:10 +0100384 uint32_t prev_opts;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200385 struct lyd_node *node = NULL, *anchor;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100386 void *val_prefix_data;
387 LY_PREFIX_FORMAT format;
Radek Krejci1deb5be2020-08-26 16:43:36 +0200388 uint32_t getnext_opts;
Radek Krejcie7b95092019-05-15 11:03:07 +0200389
Michal Vaskob36053d2020-03-26 15:49:30 +0100390 xmlctx = lydctx->xmlctx;
391 ctx = xmlctx->ctx;
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100392 getnext_opts = lydctx->int_opts & LYD_INTOPT_REPLY ? LYS_GETNEXT_OUTPUT : 0;
Michal Vasko6f4cbb62020-02-28 11:15:47 +0100393
Michal Vaskoa5da3292020-08-12 13:10:50 +0200394 assert(xmlctx->status == LYXML_ELEMENT);
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200395
Michal Vaskoa5da3292020-08-12 13:10:50 +0200396 /* remember element prefix and name */
397 prefix = xmlctx->prefix;
398 prefix_len = xmlctx->prefix_len;
399 name = xmlctx->name;
400 name_len = xmlctx->name_len;
401
402 /* get the element module */
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200403 ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200404 if (!ns) {
405 LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".",
Michal Vasko69730152020-10-09 16:30:07 +0200406 prefix_len, prefix);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200407 ret = LY_EVALID;
408 goto error;
409 }
410 mod = ly_ctx_get_module_implemented_ns(ctx, ns->uri);
411 if (!mod) {
412 if (lydctx->parse_options & LYD_PARSE_STRICT) {
413 LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "No module with namespace \"%s\" in the context.",
Michal Vasko69730152020-10-09 16:30:07 +0200414 ns->uri);
Michal Vasko90932a92020-02-12 14:33:03 +0100415 ret = LY_EVALID;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200416 goto error;
Radek Krejcie7b95092019-05-15 11:03:07 +0200417 }
Michal Vaskoa5da3292020-08-12 13:10:50 +0200418 if (!(lydctx->parse_options & LYD_PARSE_OPAQ)) {
419 /* skip element with children */
420 LY_CHECK_GOTO(ret = lydxml_data_skip(xmlctx), error);
421 return LY_SUCCESS;
Radek Krejcie7b95092019-05-15 11:03:07 +0200422 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200423 }
424
Michal Vaskoa5da3292020-08-12 13:10:50 +0200425 /* parser next */
426 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
Michal Vasko90932a92020-02-12 14:33:03 +0100427
Michal Vaskoa5da3292020-08-12 13:10:50 +0200428 /* get the schema node */
429 snode = NULL;
430 if (mod && (!parent || parent->schema)) {
431 snode = lys_find_child(parent ? parent->schema : NULL, mod, name, name_len, 0, getnext_opts);
432 if (!snode) {
433 if (lydctx->parse_options & LYD_PARSE_STRICT) {
434 LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Element \"%.*s\" not found in the \"%s\" module.",
Michal Vasko69730152020-10-09 16:30:07 +0200435 name_len, name, mod->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200436 ret = LY_EVALID;
437 goto error;
438 } else if (!(lydctx->parse_options & LYD_PARSE_OPAQ)) {
439 /* skip element with children */
440 LY_CHECK_GOTO(ret = lydxml_data_skip(xmlctx), error);
441 return LY_SUCCESS;
442 }
443 } else {
444 /* check that schema node is valid and can be used */
445 LY_CHECK_GOTO(ret = lyd_parser_check_schema((struct lyd_ctx *)lydctx, snode), error);
446 LY_CHECK_GOTO(ret = lydxml_data_check_opaq(lydctx, &snode), error);
447 }
448 }
449
450 /* create metadata/attributes */
451 if (xmlctx->status == LYXML_ATTRIBUTE) {
452 if (snode) {
Michal Vaskofeca4fb2020-10-05 08:58:40 +0200453 ret = lydxml_metadata(lydctx, &meta);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200454 LY_CHECK_GOTO(ret, error);
455 } else {
456 assert(lydctx->parse_options & LYD_PARSE_OPAQ);
457 ret = lydxml_attrs(xmlctx, &attr);
458 LY_CHECK_GOTO(ret, error);
459 }
460 }
461
462 assert(xmlctx->status == LYXML_ELEM_CONTENT);
463 if (!snode) {
464 assert(lydctx->parse_options & LYD_PARSE_OPAQ);
465
466 if (xmlctx->ws_only) {
467 /* ignore WS-only value */
468 xmlctx->value_len = 0;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100469 val_prefix_data = NULL;
470 format = LY_PREF_XML;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200471 } else {
472 /* get value prefixes */
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100473 ret = ly_store_prefix_data(xmlctx->ctx, xmlctx->value, xmlctx->value_len, LY_PREF_XML,
474 &xmlctx->ns, &format, &val_prefix_data);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200475 LY_CHECK_GOTO(ret, error);
476 }
477
478 /* create node */
Michal Vasko501af032020-11-11 20:27:44 +0100479 ret = lyd_create_opaq(ctx, name, name_len, prefix, prefix_len, ns->uri, strlen(ns->uri), xmlctx->value,
480 xmlctx->value_len, &xmlctx->dynamic, format, val_prefix_data, LYD_HINT_DATA, &node);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200481 LY_CHECK_GOTO(ret, error);
482
483 /* parser next */
484 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
485
486 /* process children */
487 while (xmlctx->status == LYXML_ELEMENT) {
488 ret = lydxml_subtree_r(lydctx, (struct lyd_node_inner *)node, lyd_node_children_p(node));
489 LY_CHECK_GOTO(ret, error);
490 }
491 } else if (snode->nodetype & LYD_NODE_TERM) {
492 /* create node */
Michal Vasko22df3f02020-08-24 13:29:22 +0200493 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 +0200494 &xmlctx->dynamic, LY_PREF_XML, &xmlctx->ns, LYD_HINT_DATA, &node), error);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200495
496 if (parent && (node->schema->flags & LYS_KEY)) {
497 /* check the key order, the anchor must never be a key */
498 anchor = lyd_insert_get_next_anchor(parent->child, node);
499 if (anchor && (anchor->schema->flags & LYS_KEY)) {
500 if (lydctx->parse_options & LYD_PARSE_STRICT) {
501 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 +0200502 node->schema->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200503 ret = LY_EVALID;
504 goto error;
505 } else {
506 LOGWRN(ctx, "Invalid position of the key \"%s\" in a list.", node->schema->name);
507 }
508 }
509 }
510
511 /* parser next */
512 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
513
514 /* no children expected */
515 if (xmlctx->status == LYXML_ELEMENT) {
516 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 +0200517 xmlctx->name_len, xmlctx->name, snode->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200518 ret = LY_EVALID;
519 goto error;
520 }
521 } else if (snode->nodetype & LYD_NODE_INNER) {
522 if (!xmlctx->ws_only) {
523 /* value in inner node */
524 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 +0200525 xmlctx->value_len, xmlctx->value, snode->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200526 ret = LY_EVALID;
527 goto error;
528 }
529
530 /* create node */
531 ret = lyd_create_inner(snode, &node);
532 LY_CHECK_GOTO(ret, error);
533
534 /* parser next */
535 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
536
537 /* process children */
538 while (xmlctx->status == LYXML_ELEMENT) {
539 ret = lydxml_subtree_r(lydctx, (struct lyd_node_inner *)node, lyd_node_children_p(node));
540 LY_CHECK_GOTO(ret, error);
541 }
542
543 if (snode->nodetype == LYS_LIST) {
544 /* check all keys exist */
545 LY_CHECK_GOTO(ret = lyd_parse_check_keys(node), error);
546 }
547
548 if (!(lydctx->parse_options & LYD_PARSE_ONLY)) {
549 /* new node validation, autodelete CANNOT occur, all nodes are new */
550 ret = lyd_validate_new(lyd_node_children_p(node), snode, NULL, NULL);
551 LY_CHECK_GOTO(ret, error);
552
553 /* add any missing default children */
Michal Vasko49c39d82020-11-06 17:20:27 +0100554 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 +0200555 (lydctx->validate_options & LYD_VALIDATE_NO_STATE) ? LYD_IMPLICIT_NO_STATE : 0, NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200556 LY_CHECK_GOTO(ret, error);
557 }
558
559 if (snode->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) {
560 /* rememeber the RPC/action/notification */
561 lydctx->op_node = node;
562 }
563 } else if (snode->nodetype & LYD_NODE_ANY) {
564 if (!xmlctx->ws_only) {
565 /* value in inner node */
566 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 +0200567 xmlctx->value_len, xmlctx->value, snode->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200568 ret = LY_EVALID;
569 goto error;
570 }
571
572 /* parser next */
573 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
574
575 /* parse any data tree with correct options */
576 prev_opts = lydctx->parse_options;
577 lydctx->parse_options &= ~LYD_PARSE_STRICT;
578 lydctx->parse_options |= LYD_PARSE_OPAQ;
579 anchor = NULL;
580 while (xmlctx->status == LYXML_ELEMENT) {
581 ret = lydxml_subtree_r(lydctx, NULL, &anchor);
582 LY_CHECK_ERR_GOTO(ret, lydctx->parse_options = prev_opts, error);
583 }
584 lydctx->parse_options = prev_opts;
585
586 /* create node */
Michal Vasko366a4a12020-12-04 16:23:57 +0100587 ret = lyd_create_any(snode, anchor, LYD_ANYDATA_DATATREE, 1, &node);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200588 LY_CHECK_GOTO(ret, error);
589 }
590 assert(node);
591
592 /* add/correct flags */
593 if (snode) {
Michal Vasko49c39d82020-11-06 17:20:27 +0100594 lyd_parse_set_data_flags(node, &lydctx->node_when, &meta, lydctx->parse_options);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200595 }
596
597 /* parser next */
598 assert(xmlctx->status == LYXML_ELEM_CLOSE);
599 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
600
601 /* add metadata/attributes */
602 if (snode) {
Michal Vasko871a0252020-11-11 18:35:24 +0100603 lyd_insert_meta(node, meta, 0);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200604 } else {
605 lyd_insert_attr(node, attr);
606 }
607
608 /* insert, keep first pointer correct */
609 lyd_insert_node((struct lyd_node *)parent, first_p, node);
610 while (!parent && (*first_p)->prev->next) {
611 *first_p = (*first_p)->prev;
612 }
613
614 return LY_SUCCESS;
615
616error:
Michal Vasko3a41dff2020-07-15 14:30:28 +0200617 lyd_free_meta_siblings(meta);
Radek Krejci011e4aa2020-09-04 15:22:31 +0200618 lyd_free_attr_siblings(ctx, attr);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200619 lyd_free_tree(node);
Radek Krejcie7b95092019-05-15 11:03:07 +0200620 return ret;
621}
622
623LY_ERR
Radek Krejci1deb5be2020-08-26 16:43:36 +0200624lyd_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 +0200625 struct lyd_node **tree_p, struct lyd_ctx **lydctx_p)
Radek Krejcie7b95092019-05-15 11:03:07 +0200626{
Radek Krejci18a57d92019-07-25 14:01:42 +0200627 LY_ERR ret = LY_SUCCESS;
Radek Krejci1798aae2020-07-14 13:26:06 +0200628 struct lyd_xml_ctx *lydctx;
Radek Krejcie7b95092019-05-15 11:03:07 +0200629
Radek Krejci7931b192020-06-25 17:05:03 +0200630 assert(!(parse_options & ~LYD_PARSE_OPTS_MASK));
631 assert(!(validate_options & ~LYD_VALIDATE_OPTS_MASK));
632
Radek Krejci1798aae2020-07-14 13:26:06 +0200633 /* init context */
634 lydctx = calloc(1, sizeof *lydctx);
635 LY_CHECK_ERR_RET(!lydctx, LOGMEM(ctx), LY_EMEM);
636 LY_CHECK_GOTO(ret = lyxml_ctx_new(ctx, in, &lydctx->xmlctx), cleanup);
637 lydctx->parse_options = parse_options;
638 lydctx->validate_options = validate_options;
639 lydctx->free = lyd_xml_ctx_free;
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200640
Michal Vaskob1b5c262020-03-05 14:29:47 +0100641 /* parse XML data */
Michal Vaskoa5da3292020-08-12 13:10:50 +0200642 while (lydctx->xmlctx->status == LYXML_ELEMENT) {
643 LY_CHECK_GOTO(ret = lydxml_subtree_r(lydctx, NULL, tree_p), cleanup);
644 }
Michal Vaskocde73ac2019-11-14 16:10:27 +0100645
Michal Vaskocde73ac2019-11-14 16:10:27 +0100646cleanup:
Michal Vasko49c39d82020-11-06 17:20:27 +0100647 /* there should be no unres stored if validation should be skipped */
648 assert(!(parse_options & LYD_PARSE_ONLY) || (!lydctx->node_types.count && !lydctx->meta_types.count &&
649 !lydctx->node_when.count));
Michal Vasko9b368d32020-02-14 13:53:31 +0100650
Michal Vasko9f96a052020-03-10 09:41:45 +0100651 if (ret) {
Radek Krejci1798aae2020-07-14 13:26:06 +0200652 lyd_xml_ctx_free((struct lyd_ctx *)lydctx);
653 lyd_free_all(*tree_p);
654 *tree_p = NULL;
655 } else {
656 *lydctx_p = (struct lyd_ctx *)lydctx;
Michal Vasko9f96a052020-03-10 09:41:45 +0100657 }
658 return ret;
659}
Michal Vasko1bf09392020-03-27 12:38:10 +0100660
661static LY_ERR
662lydxml_envelope(struct lyxml_ctx *xmlctx, const char *name, const char *uri, struct lyd_node **envp)
663{
664 LY_ERR ret = LY_SUCCESS;
665 const struct lyxml_ns *ns = NULL;
Radek Krejci1798aae2020-07-14 13:26:06 +0200666 struct lyd_attr *attr = NULL;
Michal Vasko1bf09392020-03-27 12:38:10 +0100667 const char *prefix;
668 size_t prefix_len;
669
670 *envp = NULL;
671
672 assert(xmlctx->status == LYXML_ELEMENT);
673 if (ly_strncmp(name, xmlctx->name, xmlctx->name_len)) {
674 /* not the expected element */
675 return LY_SUCCESS;
676 }
677
678 prefix = xmlctx->prefix;
679 prefix_len = xmlctx->prefix_len;
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200680 ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
Michal Vasko1bf09392020-03-27 12:38:10 +0100681 if (!ns) {
682 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".",
Michal Vasko69730152020-10-09 16:30:07 +0200683 prefix_len, prefix);
Michal Vasko1bf09392020-03-27 12:38:10 +0100684 return LY_EVALID;
685 } else if (strcmp(ns->uri, uri)) {
686 /* different namespace */
687 return LY_SUCCESS;
688 }
689
690 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
691
692 /* create attributes */
693 if (xmlctx->status == LYXML_ATTRIBUTE) {
694 LY_CHECK_RET(lydxml_attrs(xmlctx, &attr));
695 }
696
697 if (!xmlctx->ws_only) {
698 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_SYNTAX, "Unexpected value \"%.*s\" in the \"%s\" element.",
Michal Vasko69730152020-10-09 16:30:07 +0200699 xmlctx->value_len, xmlctx->value, name);
Michal Vasko1bf09392020-03-27 12:38:10 +0100700 ret = LY_EVALID;
701 goto cleanup;
702 }
703
704 /* parser next element */
705 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
706
707 /* create node */
Michal Vasko501af032020-11-11 20:27:44 +0100708 ret = lyd_create_opaq(xmlctx->ctx, name, strlen(name), prefix, prefix_len, uri, strlen(uri), "", 0, NULL,
709 LY_PREF_XML, NULL, LYD_NODEHINT_ENVELOPE, envp);
Michal Vasko1bf09392020-03-27 12:38:10 +0100710 LY_CHECK_GOTO(ret, cleanup);
711
712 /* assign atributes */
713 ((struct lyd_node_opaq *)(*envp))->attr = attr;
714 attr = NULL;
715
716cleanup:
Radek Krejci011e4aa2020-09-04 15:22:31 +0200717 lyd_free_attr_siblings(xmlctx->ctx, attr);
Michal Vasko1bf09392020-03-27 12:38:10 +0100718 return ret;
719}
720
721LY_ERR
Radek Krejci1798aae2020-07-14 13:26:06 +0200722lyd_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 +0100723{
724 LY_ERR ret = LY_SUCCESS;
725 struct lyd_xml_ctx lydctx = {0};
726 struct lyd_node *rpc_e = NULL, *act_e = NULL;
Radek Krejci1798aae2020-07-14 13:26:06 +0200727 struct lyd_node *tree = NULL;
Michal Vasko1bf09392020-03-27 12:38:10 +0100728
729 /* init */
Michal Vasko63f3d842020-07-08 10:10:14 +0200730 LY_CHECK_GOTO(ret = lyxml_ctx_new(ctx, in, &lydctx.xmlctx), cleanup);
Radek Krejci1798aae2020-07-14 13:26:06 +0200731 lydctx.parse_options = LYD_PARSE_ONLY | LYD_PARSE_STRICT;
Michal Vasko1bf09392020-03-27 12:38:10 +0100732 lydctx.int_opts = LYD_INTOPT_RPC;
Michal Vasko1bf09392020-03-27 12:38:10 +0100733
734 /* parse "rpc", if any */
735 LY_CHECK_GOTO(ret = lydxml_envelope(lydctx.xmlctx, "rpc", "urn:ietf:params:xml:ns:netconf:base:1.0", &rpc_e), cleanup);
736
737 if (rpc_e) {
738 /* parse "action", if any */
739 LY_CHECK_GOTO(ret = lydxml_envelope(lydctx.xmlctx, "action", "urn:ietf:params:xml:ns:yang:1", &act_e), cleanup);
740 }
741
742 /* parse the rest of data normally */
Michal Vaskocf770e22020-08-12 13:21:43 +0200743 LY_CHECK_GOTO(ret = lydxml_subtree_r(&lydctx, NULL, &tree), cleanup);
Michal Vasko1bf09392020-03-27 12:38:10 +0100744
Michal Vaskocf770e22020-08-12 13:21:43 +0200745 /* make sure we have parsed some operation and it is the only subtree */
Radek Krejci1798aae2020-07-14 13:26:06 +0200746 if (!lydctx.op_node) {
Michal Vasko1bf09392020-03-27 12:38:10 +0100747 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_DATA, "Missing the \"rpc\"/\"action\" node.");
748 ret = LY_EVALID;
749 goto cleanup;
Michal Vaskocf770e22020-08-12 13:21:43 +0200750 } else if (lydctx.xmlctx->status == LYXML_ELEMENT) {
751 LOGVAL(ctx, LY_VLOG_LINE, &lydctx.xmlctx->line, LYVE_SYNTAX, "Unexpected sibling element of \"%s\".",
Michal Vasko69730152020-10-09 16:30:07 +0200752 tree->schema->name);
Michal Vaskocf770e22020-08-12 13:21:43 +0200753 ret = LY_EVALID;
754 goto cleanup;
Michal Vasko1bf09392020-03-27 12:38:10 +0100755 }
756
757 /* finish XML parsing and check operation type */
758 if (act_e) {
759 if (lydctx.xmlctx->status != LYXML_ELEM_CLOSE) {
760 assert(lydctx.xmlctx->status == LYXML_ELEMENT);
761 LOGVAL(ctx, LY_VLOG_LINE, &lydctx.xmlctx->line, LYVE_SYNTAX, "Unexpected sibling element \"%.*s\" of \"action\".",
Michal Vasko69730152020-10-09 16:30:07 +0200762 lydctx.xmlctx->name_len, lydctx.xmlctx->name);
Michal Vasko1bf09392020-03-27 12:38:10 +0100763 ret = LY_EVALID;
764 goto cleanup;
Radek Krejci1798aae2020-07-14 13:26:06 +0200765 } else if (lydctx.op_node->schema->nodetype != LYS_ACTION) {
766 LOGVAL(ctx, LY_VLOG_LYD, lydctx.op_node, LYVE_DATA, "Unexpected %s element, an \"action\" expected.",
Michal Vasko69730152020-10-09 16:30:07 +0200767 lys_nodetype2str(lydctx.op_node->schema->nodetype));
Michal Vasko1bf09392020-03-27 12:38:10 +0100768 ret = LY_EVALID;
769 goto cleanup;
770 }
771 LY_CHECK_GOTO(ret = lyxml_ctx_next(lydctx.xmlctx), cleanup);
772 }
773 if (rpc_e) {
774 if (lydctx.xmlctx->status != LYXML_ELEM_CLOSE) {
775 assert(lydctx.xmlctx->status == LYXML_ELEMENT);
776 LOGVAL(ctx, LY_VLOG_LINE, &lydctx.xmlctx->line, LYVE_SYNTAX, "Unexpected sibling element \"%.*s\" of \"rpc\".",
Michal Vasko69730152020-10-09 16:30:07 +0200777 lydctx.xmlctx->name_len, lydctx.xmlctx->name);
Michal Vasko1bf09392020-03-27 12:38:10 +0100778 ret = LY_EVALID;
779 goto cleanup;
Radek Krejci1798aae2020-07-14 13:26:06 +0200780 } else if (!act_e && (lydctx.op_node->schema->nodetype != LYS_RPC)) {
781 LOGVAL(ctx, LY_VLOG_LYD, lydctx.op_node, LYVE_DATA, "Unexpected %s element, an \"rpc\" expected.",
Michal Vasko69730152020-10-09 16:30:07 +0200782 lys_nodetype2str(lydctx.op_node->schema->nodetype));
Michal Vasko1bf09392020-03-27 12:38:10 +0100783 ret = LY_EVALID;
784 goto cleanup;
785 }
786 LY_CHECK_GOTO(ret = lyxml_ctx_next(lydctx.xmlctx), cleanup);
787 }
788
Radek Krejci1798aae2020-07-14 13:26:06 +0200789 if (op_p) {
790 *op_p = lydctx.op_node;
Michal Vaskocc048b22020-03-27 15:52:38 +0100791 }
Radek Krejci1798aae2020-07-14 13:26:06 +0200792 assert(tree);
Michal Vasko1bf09392020-03-27 12:38:10 +0100793 if (act_e) {
794 /* connect to the action */
Michal Vasko4189c0f2020-08-13 09:05:22 +0200795 lyd_insert_node(act_e, NULL, tree);
796 tree = act_e;
Michal Vasko1bf09392020-03-27 12:38:10 +0100797 }
798 if (rpc_e) {
799 /* connect to the rpc */
Michal Vasko4189c0f2020-08-13 09:05:22 +0200800 lyd_insert_node(rpc_e, NULL, tree);
801 tree = rpc_e;
802 }
803 if (tree_p) {
804 *tree_p = tree;
Michal Vasko1bf09392020-03-27 12:38:10 +0100805 }
806
807cleanup:
808 /* we have used parse_only flag */
Michal Vasko49c39d82020-11-06 17:20:27 +0100809 assert(!lydctx.node_types.count && !lydctx.meta_types.count && !lydctx.node_when.count);
Michal Vasko1bf09392020-03-27 12:38:10 +0100810 lyxml_ctx_free(lydctx.xmlctx);
811 if (ret) {
Radek Krejci1798aae2020-07-14 13:26:06 +0200812 lyd_free_all(tree);
Michal Vasko1bf09392020-03-27 12:38:10 +0100813 lyd_free_tree(act_e);
814 lyd_free_tree(rpc_e);
Michal Vasko1bf09392020-03-27 12:38:10 +0100815 }
816 return ret;
817}
Michal Vaskoa8edff02020-03-27 14:47:01 +0100818
819static LY_ERR
820lydxml_notif_envelope(struct lyxml_ctx *xmlctx, struct lyd_node **envp)
821{
822 LY_ERR ret = LY_SUCCESS;
823 const struct lyxml_ns *ns = NULL;
Radek Krejci1798aae2020-07-14 13:26:06 +0200824 struct lyd_attr *attr = NULL;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100825 struct lyd_node *et;
826 const char *prefix;
827 size_t prefix_len;
828
829 *envp = NULL;
830
831 /* container envelope */
832 LY_CHECK_GOTO(ret = lydxml_envelope(xmlctx, "notification", "urn:ietf:params:xml:ns:netconf:notification:1.0",
Michal Vasko69730152020-10-09 16:30:07 +0200833 envp), cleanup);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100834
835 /* no envelope, fine */
836 if (!*envp) {
837 goto cleanup;
838 }
839
840 /* child "eventTime" */
841 if ((xmlctx->status != LYXML_ELEMENT) || ly_strncmp("eventTime", xmlctx->name, xmlctx->name_len)) {
842 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Missing the \"eventTime\" element.");
843 ret = LY_EVALID;
844 goto cleanup;
845 }
846
847 prefix = xmlctx->prefix;
848 prefix_len = xmlctx->prefix_len;
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200849 ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100850 if (!ns) {
851 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".",
Michal Vasko69730152020-10-09 16:30:07 +0200852 prefix_len, prefix);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100853 ret = LY_EVALID;
854 goto cleanup;
855 } else if (strcmp(ns->uri, "urn:ietf:params:xml:ns:netconf:notification:1.0")) {
856 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Invalid namespace \"%s\" of \"eventTime\".",
Michal Vasko69730152020-10-09 16:30:07 +0200857 ns->uri);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100858 ret = LY_EVALID;
859 goto cleanup;
860 }
861
862 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
863
864 /* create attributes */
865 if (xmlctx->status == LYXML_ATTRIBUTE) {
866 LY_CHECK_RET(lydxml_attrs(xmlctx, &attr));
867 }
868
869 /* validate value */
870 /* TODO */
871 /*if (!xmlctx->ws_only) {
872 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_SYNTAX, "Unexpected value \"%.*s\" in the \"%s\" element.",
873 xmlctx->value_len, xmlctx->value, name);
874 ret = LY_EVALID;
875 goto cleanup;
876 }*/
877
878 /* create node */
Radek Krejcif13b87b2020-12-01 22:02:17 +0100879 ret = lyd_create_opaq(xmlctx->ctx, "eventTime", ly_strlen_const("eventTime"), prefix, prefix_len,
880 ns->uri, strlen(ns->uri), xmlctx->value, xmlctx->value_len, NULL, LY_PREF_XML, NULL, LYD_NODEHINT_ENVELOPE, &et);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100881 LY_CHECK_GOTO(ret, cleanup);
882
883 /* assign atributes */
884 ((struct lyd_node_opaq *)et)->attr = attr;
885 attr = NULL;
886
887 /* insert */
888 lyd_insert_node(*envp, NULL, et);
889
890 /* finish parsing */
891 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
892 if (xmlctx->status != LYXML_ELEM_CLOSE) {
893 assert(xmlctx->status == LYXML_ELEMENT);
894 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_SYNTAX, "Unexpected sibling element \"%.*s\" of \"eventTime\".",
Michal Vasko69730152020-10-09 16:30:07 +0200895 xmlctx->name_len, xmlctx->name);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100896 ret = LY_EVALID;
897 goto cleanup;
898 }
899 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
900
901cleanup:
902 if (ret) {
903 lyd_free_tree(*envp);
Radek Krejci011e4aa2020-09-04 15:22:31 +0200904 lyd_free_attr_siblings(xmlctx->ctx, attr);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100905 }
906 return ret;
907}
908
909LY_ERR
Radek Krejci1798aae2020-07-14 13:26:06 +0200910lyd_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 +0100911{
912 LY_ERR ret = LY_SUCCESS;
913 struct lyd_xml_ctx lydctx = {0};
914 struct lyd_node *ntf_e = NULL;
Radek Krejci1798aae2020-07-14 13:26:06 +0200915 struct lyd_node *tree = NULL;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100916
917 /* init */
Michal Vasko63f3d842020-07-08 10:10:14 +0200918 LY_CHECK_GOTO(ret = lyxml_ctx_new(ctx, in, &lydctx.xmlctx), cleanup);
Radek Krejci1798aae2020-07-14 13:26:06 +0200919 lydctx.parse_options = LYD_PARSE_ONLY | LYD_PARSE_STRICT;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100920 lydctx.int_opts = LYD_INTOPT_NOTIF;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100921
922 /* parse "notification" and "eventTime", if present */
923 LY_CHECK_GOTO(ret = lydxml_notif_envelope(lydctx.xmlctx, &ntf_e), cleanup);
924
925 /* parse the rest of data normally */
Michal Vaskocf770e22020-08-12 13:21:43 +0200926 LY_CHECK_GOTO(ret = lydxml_subtree_r(&lydctx, NULL, &tree), cleanup);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100927
928 /* make sure we have parsed some notification */
Radek Krejci1798aae2020-07-14 13:26:06 +0200929 if (!lydctx.op_node) {
Michal Vaskoa8edff02020-03-27 14:47:01 +0100930 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_DATA, "Missing the \"notification\" node.");
931 ret = LY_EVALID;
932 goto cleanup;
Michal Vaskocf770e22020-08-12 13:21:43 +0200933 } else if (lydctx.xmlctx->status == LYXML_ELEMENT) {
934 LOGVAL(ctx, LY_VLOG_LINE, &lydctx.xmlctx->line, LYVE_SYNTAX, "Unexpected sibling element of \"%s\".",
Michal Vasko69730152020-10-09 16:30:07 +0200935 tree->schema->name);
Michal Vaskocf770e22020-08-12 13:21:43 +0200936 ret = LY_EVALID;
937 goto cleanup;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100938 }
939
940 /* finish XML parsing */
941 if (ntf_e) {
942 if (lydctx.xmlctx->status != LYXML_ELEM_CLOSE) {
943 assert(lydctx.xmlctx->status == LYXML_ELEMENT);
944 LOGVAL(ctx, LY_VLOG_LINE, &lydctx.xmlctx->line, LYVE_SYNTAX, "Unexpected sibling element \"%.*s\" of \"notification\".",
Michal Vasko69730152020-10-09 16:30:07 +0200945 lydctx.xmlctx->name_len, lydctx.xmlctx->name);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100946 ret = LY_EVALID;
947 goto cleanup;
948 }
949 LY_CHECK_GOTO(ret = lyxml_ctx_next(lydctx.xmlctx), cleanup);
950 }
951
Radek Krejci1798aae2020-07-14 13:26:06 +0200952 if (ntf_p) {
953 *ntf_p = lydctx.op_node;
Michal Vaskocc048b22020-03-27 15:52:38 +0100954 }
Radek Krejci1798aae2020-07-14 13:26:06 +0200955 assert(tree);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100956 if (ntf_e) {
957 /* connect to the notification */
Michal Vasko4189c0f2020-08-13 09:05:22 +0200958 lyd_insert_node(ntf_e, NULL, tree);
959 tree = ntf_e;
960 }
961 if (tree_p) {
962 *tree_p = tree;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100963 }
964
965cleanup:
966 /* we have used parse_only flag */
Michal Vasko49c39d82020-11-06 17:20:27 +0100967 assert(!lydctx.node_types.count && !lydctx.meta_types.count && !lydctx.node_when.count);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100968 lyxml_ctx_free(lydctx.xmlctx);
969 if (ret) {
Radek Krejci1798aae2020-07-14 13:26:06 +0200970 lyd_free_all(tree);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100971 lyd_free_tree(ntf_e);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100972 }
973 return ret;
974}
Michal Vasko1ce933a2020-03-30 12:38:22 +0200975
976LY_ERR
Radek Krejci1798aae2020-07-14 13:26:06 +0200977lyd_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 +0200978{
979 LY_ERR ret = LY_SUCCESS;
980 struct lyd_xml_ctx lydctx = {0};
Michal Vasko4189c0f2020-08-13 09:05:22 +0200981 struct lyd_node *rpcr_e = NULL, *tree, *req_op, *rep_op = NULL;
Michal Vasko1ce933a2020-03-30 12:38:22 +0200982
983 /* init */
Michal Vaskob7be7a82020-08-20 09:09:04 +0200984 LY_CHECK_GOTO(ret = lyxml_ctx_new(LYD_CTX(request), in, &lydctx.xmlctx), cleanup);
Radek Krejci1798aae2020-07-14 13:26:06 +0200985 lydctx.parse_options = LYD_PARSE_ONLY | LYD_PARSE_STRICT;
Michal Vasko1ce933a2020-03-30 12:38:22 +0200986 lydctx.int_opts = LYD_INTOPT_REPLY;
Michal Vasko1ce933a2020-03-30 12:38:22 +0200987
988 /* find request OP */
Michal Vasko56daf732020-08-10 10:57:18 +0200989 LYD_TREE_DFS_BEGIN((struct lyd_node *)request, req_op) {
Michal Vasko1ce933a2020-03-30 12:38:22 +0200990 if (req_op->schema->nodetype & (LYS_RPC | LYS_ACTION)) {
991 break;
992 }
Michal Vasko56daf732020-08-10 10:57:18 +0200993 LYD_TREE_DFS_END(request, req_op);
Michal Vasko1ce933a2020-03-30 12:38:22 +0200994 }
995 if (!(req_op->schema->nodetype & (LYS_RPC | LYS_ACTION))) {
Michal Vaskob7be7a82020-08-20 09:09:04 +0200996 LOGERR(LYD_CTX(request), LY_EINVAL, "No RPC/action in the request found.");
Michal Vasko1ce933a2020-03-30 12:38:22 +0200997 ret = LY_EINVAL;
998 goto cleanup;
999 }
1000
1001 /* duplicate request OP with parents */
Michal Vasko3a41dff2020-07-15 14:30:28 +02001002 LY_CHECK_GOTO(ret = lyd_dup_single(req_op, NULL, LYD_DUP_WITH_PARENTS, &rep_op), cleanup);
Michal Vasko1ce933a2020-03-30 12:38:22 +02001003
1004 /* parse "rpc-reply", if any */
Michal Vasko3a41dff2020-07-15 14:30:28 +02001005 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 +02001006 cleanup);
Michal Vasko1ce933a2020-03-30 12:38:22 +02001007
1008 /* parse the rest of data normally but connect them to the duplicated operation */
Michal Vaskoa5da3292020-08-12 13:10:50 +02001009 while (lydctx.xmlctx->status == LYXML_ELEMENT) {
1010 ret = lydxml_subtree_r(&lydctx, (struct lyd_node_inner *)rep_op, lyd_node_children_p(rep_op));
1011 LY_CHECK_GOTO(ret, cleanup);
1012 }
Michal Vasko1ce933a2020-03-30 12:38:22 +02001013
1014 /* finish XML parsing and check operation type */
1015 if (rpcr_e) {
1016 if (lydctx.xmlctx->status != LYXML_ELEM_CLOSE) {
1017 assert(lydctx.xmlctx->status == LYXML_ELEMENT);
Michal Vaskob7be7a82020-08-20 09:09:04 +02001018 LOGVAL(LYD_CTX(request), LY_VLOG_LINE, &lydctx.xmlctx->line, LYVE_SYNTAX,
Michal Vasko69730152020-10-09 16:30:07 +02001019 "Unexpected sibling element \"%.*s\" of \"rpc-reply\".", lydctx.xmlctx->name_len, lydctx.xmlctx->name);
Michal Vasko1ce933a2020-03-30 12:38:22 +02001020 ret = LY_EVALID;
1021 goto cleanup;
1022 }
1023 LY_CHECK_GOTO(ret = lyxml_ctx_next(lydctx.xmlctx), cleanup);
1024 }
1025
Radek Krejci1798aae2020-07-14 13:26:06 +02001026 if (op_p) {
1027 *op_p = rep_op;
Michal Vasko1ce933a2020-03-30 12:38:22 +02001028 }
Radek Krejcia1c1e542020-09-29 16:06:52 +02001029 for (tree = rep_op; tree->parent; tree = lyd_parent(tree)) {}
Michal Vasko1ce933a2020-03-30 12:38:22 +02001030 if (rpcr_e) {
1031 /* connect to the operation */
Michal Vasko4189c0f2020-08-13 09:05:22 +02001032 lyd_insert_node(rpcr_e, NULL, tree);
1033 tree = rpcr_e;
1034 }
1035 if (tree_p) {
1036 *tree_p = tree;
Michal Vasko1ce933a2020-03-30 12:38:22 +02001037 }
1038
1039cleanup:
1040 /* we have used parse_only flag */
Michal Vasko49c39d82020-11-06 17:20:27 +01001041 assert(!lydctx.node_types.count && !lydctx.meta_types.count && !lydctx.node_when.count);
Michal Vasko1ce933a2020-03-30 12:38:22 +02001042 lyxml_ctx_free(lydctx.xmlctx);
1043 if (ret) {
1044 lyd_free_all(rep_op);
1045 lyd_free_tree(rpcr_e);
1046 }
1047 return ret;
1048}