blob: 3bf8de0e1e562b5591f2db12929b2a36d9bf5a5d [file] [log] [blame]
Radek Krejcie7b95092019-05-15 11:03:07 +02001/**
2 * @file parser_xml.c
3 * @author Radek Krejci <rkrejci@cesnet.cz>
4 * @brief XML data parser for libyang
5 *
6 * Copyright (c) 2019 CESNET, z.s.p.o.
7 *
8 * This source code is licensed under BSD 3-Clause License (the "License").
9 * You may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * https://opensource.org/licenses/BSD-3-Clause
13 */
14
Radek Krejcie7b95092019-05-15 11:03:07 +020015#include <stdint.h>
16#include <stdlib.h>
17#include <string.h>
Michal Vasko9b368d32020-02-14 13:53:31 +010018#include <assert.h>
Radek Krejcie7b95092019-05-15 11:03:07 +020019
Radek Krejci535ea9f2020-05-29 16:01:05 +020020#include "common.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020021#include "context.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020022#include "log.h"
Radek Krejci7931b192020-06-25 17:05:03 +020023#include "parser_data.h"
24#include "parser_internal.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020025#include "set.h"
Radek Krejci535ea9f2020-05-29 16:01:05 +020026#include "tree.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020027#include "tree_data_internal.h"
28#include "tree_schema.h"
Michal Vaskocde73ac2019-11-14 16:10:27 +010029#include "validation.h"
Radek Krejci535ea9f2020-05-29 16:01:05 +020030#include "xml.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020031
32/**
Michal Vaskob36053d2020-03-26 15:49:30 +010033 * @brief Internal context for XML YANG data parser.
Radek Krejci1798aae2020-07-14 13:26:06 +020034 *
35 * Note that the structure maps to the lyd_ctx which is common for all the data parsers
Radek Krejcie7b95092019-05-15 11:03:07 +020036 */
37struct lyd_xml_ctx {
Radek Krejci1798aae2020-07-14 13:26:06 +020038 uint32_t parse_options; /**< various @ref dataparseroptions. */
39 uint32_t validate_options; /**< various @ref datavalidationoptions. */
40 uint32_t int_opts; /**< internal data parser options */
41 uint32_t path_len; /**< used bytes in the path buffer */
42 char path[LYD_PARSER_BUFSIZE]; /**< buffer for the generated path */
43 struct ly_set unres_node_type; /**< set of nodes validated with LY_EINCOMPLETE result */
44 struct ly_set unres_meta_type; /**< set of metadata validated with LY_EINCOMPLETE result */
45 struct ly_set when_check; /**< set of nodes with "when" conditions */
46 struct lyd_node *op_node; /**< if an RPC/action/notification is being parsed, store the pointer to it */
Radek Krejcie7b95092019-05-15 11:03:07 +020047
Radek Krejci1798aae2020-07-14 13:26:06 +020048 /* callbacks */
49 lyd_ctx_free_clb free; /* destructor */
Radek Krejci1798aae2020-07-14 13:26:06 +020050
51 struct lyxml_ctx *xmlctx; /**< XML context */
Radek Krejcie7b95092019-05-15 11:03:07 +020052};
53
Radek Krejci1798aae2020-07-14 13:26:06 +020054void
55lyd_xml_ctx_free(struct lyd_ctx *lydctx)
56{
57 struct lyd_xml_ctx *ctx = (struct lyd_xml_ctx *)lydctx;
58
59 lyd_ctx_free(lydctx);
60 lyxml_ctx_free(ctx->xmlctx);
61 free(ctx);
62}
63
Radek Krejcie7b95092019-05-15 11:03:07 +020064static LY_ERR
Radek Krejci1798aae2020-07-14 13:26:06 +020065lydxml_metadata(struct lyd_xml_ctx *lydctx, const struct lysc_node *sparent, struct lyd_meta **meta)
Radek Krejcie7b95092019-05-15 11:03:07 +020066{
Michal Vaskob36053d2020-03-26 15:49:30 +010067 LY_ERR ret = LY_EVALID;
Radek Krejci28681fa2019-09-06 13:08:45 +020068 const struct lyxml_ns *ns;
69 struct lys_module *mod;
Michal Vaskob36053d2020-03-26 15:49:30 +010070 const char *name;
71 size_t name_len;
Radek Krejci1798aae2020-07-14 13:26:06 +020072 struct lyxml_ctx *xmlctx = lydctx->xmlctx;
Radek Krejci28681fa2019-09-06 13:08:45 +020073
Michal Vaskob36053d2020-03-26 15:49:30 +010074 *meta = NULL;
Radek Krejci28681fa2019-09-06 13:08:45 +020075
Michal Vaskob36053d2020-03-26 15:49:30 +010076 while (xmlctx->status == LYXML_ATTRIBUTE) {
77 if (!xmlctx->prefix_len) {
Radek Krejci28681fa2019-09-06 13:08:45 +020078 /* in XML, all attributes must be prefixed
79 * TODO exception for NETCONF filters which are supposed to map to the ietf-netconf without prefix */
Radek Krejci1798aae2020-07-14 13:26:06 +020080 if (lydctx->parse_options & LYD_PARSE_STRICT) {
Michal Vasko52927e22020-03-16 17:26:14 +010081 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Missing mandatory prefix for XML metadata \"%.*s\".",
Michal Vaskob36053d2020-03-26 15:49:30 +010082 xmlctx->name_len, xmlctx->name);
83 goto cleanup;
Radek Krejci28681fa2019-09-06 13:08:45 +020084 }
Michal Vaskob36053d2020-03-26 15:49:30 +010085
Radek Krejci28681fa2019-09-06 13:08:45 +020086skip_attr:
Michal Vaskob36053d2020-03-26 15:49:30 +010087 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
88 assert(xmlctx->status == LYXML_ATTR_CONTENT);
89 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Radek Krejci28681fa2019-09-06 13:08:45 +020090 continue;
91 }
92
93 /* get namespace of the attribute to find its annotation definition */
Michal Vaskoc8a230d2020-08-14 12:17:10 +020094 ns = lyxml_ns_get(&xmlctx->ns, xmlctx->prefix, xmlctx->prefix_len);
Radek Krejci28681fa2019-09-06 13:08:45 +020095 if (!ns) {
Michal Vasko52927e22020-03-16 17:26:14 +010096 /* unknown namespace, XML error */
97 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".",
Michal Vaskob36053d2020-03-26 15:49:30 +010098 xmlctx->prefix_len, xmlctx->prefix);
Radek Krejci28681fa2019-09-06 13:08:45 +020099 goto cleanup;
100 }
Michal Vasko52927e22020-03-16 17:26:14 +0100101 mod = ly_ctx_get_module_implemented_ns(xmlctx->ctx, ns->uri);
Radek Krejci28681fa2019-09-06 13:08:45 +0200102 if (!mod) {
103 /* module is not implemented or not present in the schema */
Radek Krejci1798aae2020-07-14 13:26:06 +0200104 if (lydctx->parse_options & LYD_PARSE_STRICT) {
Michal Vasko52927e22020-03-16 17:26:14 +0100105 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE,
Michal Vasko9f96a052020-03-10 09:41:45 +0100106 "Unknown (or not implemented) YANG module with namespace \"%s\" for metadata \"%.*s%s%.*s\".",
Michal Vaskob36053d2020-03-26 15:49:30 +0100107 ns->uri, xmlctx->prefix_len, xmlctx->prefix, xmlctx->prefix_len ? ":" : "", xmlctx->name_len,
108 xmlctx->name);
109 goto cleanup;
Radek Krejci28681fa2019-09-06 13:08:45 +0200110 }
111 goto skip_attr;
112 }
113
Michal Vasko60ea6352020-06-29 13:39:39 +0200114 /* remember meta name and get its content */
Michal Vaskob36053d2020-03-26 15:49:30 +0100115 name = xmlctx->name;
116 name_len = xmlctx->name_len;
117 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
118 assert(xmlctx->status == LYXML_ATTR_CONTENT);
119
120 /* create metadata */
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200121 ret = lyd_parser_create_meta((struct lyd_ctx *)lydctx, NULL, meta, mod, name, name_len, xmlctx->value,
122 xmlctx->value_len, &xmlctx->dynamic, 0, LY_PREF_XML, &xmlctx->ns, sparent);
Radek Krejci1798aae2020-07-14 13:26:06 +0200123 LY_CHECK_GOTO(ret, cleanup);
Michal Vaskob36053d2020-03-26 15:49:30 +0100124
125 /* next attribute */
126 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Radek Krejcie7b95092019-05-15 11:03:07 +0200127 }
Michal Vasko52927e22020-03-16 17:26:14 +0100128
Radek Krejci28681fa2019-09-06 13:08:45 +0200129 ret = LY_SUCCESS;
Radek Krejcie7b95092019-05-15 11:03:07 +0200130
131cleanup:
Michal Vaskob36053d2020-03-26 15:49:30 +0100132 if (ret) {
Michal Vasko3a41dff2020-07-15 14:30:28 +0200133 lyd_free_meta_siblings(*meta);
Michal Vaskob36053d2020-03-26 15:49:30 +0100134 *meta = NULL;
Radek Krejci38d85362019-09-05 16:26:38 +0200135 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200136 return ret;
137}
138
Michal Vasko52927e22020-03-16 17:26:14 +0100139static LY_ERR
Radek Krejci1798aae2020-07-14 13:26:06 +0200140lydxml_attrs(struct lyxml_ctx *xmlctx, struct lyd_attr **attr)
Michal Vasko52927e22020-03-16 17:26:14 +0100141{
142 LY_ERR ret = LY_SUCCESS;
143 const struct lyxml_ns *ns;
144 struct ly_prefix *val_prefs;
Radek Krejci1798aae2020-07-14 13:26:06 +0200145 struct lyd_attr *attr2;
Michal Vaskob36053d2020-03-26 15:49:30 +0100146 const char *name, *prefix;
147 size_t name_len, prefix_len;
Michal Vasko52927e22020-03-16 17:26:14 +0100148
149 assert(attr);
Michal Vaskob36053d2020-03-26 15:49:30 +0100150 *attr = NULL;
Michal Vasko52927e22020-03-16 17:26:14 +0100151
Michal Vaskob36053d2020-03-26 15:49:30 +0100152 while (xmlctx->status == LYXML_ATTRIBUTE) {
Michal Vasko52927e22020-03-16 17:26:14 +0100153 ns = NULL;
Michal Vaskob36053d2020-03-26 15:49:30 +0100154 if (xmlctx->prefix_len) {
Michal Vasko52927e22020-03-16 17:26:14 +0100155 /* get namespace of the attribute */
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200156 ns = lyxml_ns_get(&xmlctx->ns, xmlctx->prefix, xmlctx->prefix_len);
Michal Vasko52927e22020-03-16 17:26:14 +0100157 if (!ns) {
158 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".",
Michal Vaskob36053d2020-03-26 15:49:30 +0100159 xmlctx->prefix_len, xmlctx->prefix);
Michal Vasko52927e22020-03-16 17:26:14 +0100160 ret = LY_EVALID;
161 goto cleanup;
162 }
163 }
164
165 if (*attr) {
166 attr2 = *attr;
167 } else {
168 attr2 = NULL;
169 }
170
Michal Vaskob36053d2020-03-26 15:49:30 +0100171 /* remember attr prefix, name, and get its content */
172 prefix = xmlctx->prefix;
173 prefix_len = xmlctx->prefix_len;
174 name = xmlctx->name;
175 name_len = xmlctx->name_len;
176 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
177 assert(xmlctx->status == LYXML_ATTR_CONTENT);
178
Michal Vasko52927e22020-03-16 17:26:14 +0100179 /* get value prefixes */
Michal Vaskob36053d2020-03-26 15:49:30 +0100180 LY_CHECK_GOTO(ret = lyxml_get_prefixes(xmlctx, xmlctx->value, xmlctx->value_len, &val_prefs), cleanup);
Michal Vasko52927e22020-03-16 17:26:14 +0100181
182 /* attr2 is always changed to the created attribute */
Radek Krejci1798aae2020-07-14 13:26:06 +0200183 ret = lyd_create_attr(NULL, &attr2, xmlctx->ctx, name, name_len, xmlctx->value, xmlctx->value_len,
184 &xmlctx->dynamic, 0, LYD_XML, val_prefs, prefix, prefix_len,
185 ns ? ns->uri : NULL, ns ? strlen(ns->uri) : 0);
Michal Vasko52927e22020-03-16 17:26:14 +0100186 LY_CHECK_GOTO(ret, cleanup);
187
188 if (!*attr) {
189 *attr = attr2;
190 }
Michal Vaskob36053d2020-03-26 15:49:30 +0100191
192 /* next attribute */
193 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko52927e22020-03-16 17:26:14 +0100194 }
195
196cleanup:
Michal Vaskob36053d2020-03-26 15:49:30 +0100197 if (ret) {
Michal Vasko3a41dff2020-07-15 14:30:28 +0200198 ly_free_attr_siblings(xmlctx->ctx, *attr);
Michal Vaskob36053d2020-03-26 15:49:30 +0100199 *attr = NULL;
Michal Vasko52927e22020-03-16 17:26:14 +0100200 }
Michal Vasko52927e22020-03-16 17:26:14 +0100201 return ret;
202}
203
Michal Vasko44685da2020-03-17 15:38:06 +0100204static LY_ERR
Michal Vaskob36053d2020-03-26 15:49:30 +0100205lydxml_check_list(struct lyxml_ctx *xmlctx, const struct lysc_node *list)
Michal Vasko44685da2020-03-17 15:38:06 +0100206{
Michal Vaskob36053d2020-03-26 15:49:30 +0100207 LY_ERR ret = LY_SUCCESS, r;
208 enum LYXML_PARSER_STATUS next;
Michal Vasko44685da2020-03-17 15:38:06 +0100209 struct ly_set key_set = {0};
210 const struct lysc_node *snode;
Michal Vaskob36053d2020-03-26 15:49:30 +0100211 uint32_t i, parents_count;
Michal Vasko44685da2020-03-17 15:38:06 +0100212
213 assert(list && (list->nodetype == LYS_LIST));
214
215 /* get all keys into a set (keys do not have if-features or anything) */
216 snode = NULL;
217 while ((snode = lys_getnext(snode, list, NULL, LYS_GETNEXT_NOSTATECHECK)) && (snode->flags & LYS_KEY)) {
218 ly_set_add(&key_set, (void *)snode, LY_SET_OPT_USEASLIST);
219 }
220
Michal Vaskob36053d2020-03-26 15:49:30 +0100221 while (xmlctx->status == LYXML_ELEMENT) {
Michal Vasko44685da2020-03-17 15:38:06 +0100222 /* find key definition */
223 for (i = 0; i < key_set.count; ++i) {
224 snode = (const struct lysc_node *)key_set.objs[i];
Michal Vaskob36053d2020-03-26 15:49:30 +0100225 if (!ly_strncmp(snode->name, xmlctx->name, xmlctx->name_len)) {
Michal Vasko44685da2020-03-17 15:38:06 +0100226 break;
227 }
228 }
Michal Vaskob36053d2020-03-26 15:49:30 +0100229 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100230
231 /* skip attributes */
232 while (xmlctx->status == LYXML_ATTRIBUTE) {
Michal Vaskob36053d2020-03-26 15:49:30 +0100233 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
234 assert(xmlctx->status == LYXML_ATTR_CONTENT);
235 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100236 }
237
Michal Vaskob36053d2020-03-26 15:49:30 +0100238 assert(xmlctx->status == LYXML_ELEM_CONTENT);
239 if (i < key_set.count) {
240 /* validate the value */
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200241 r = _lys_value_validate(NULL, snode, xmlctx->value, xmlctx->value_len, LY_PREF_XML, xmlctx);
Michal Vaskob36053d2020-03-26 15:49:30 +0100242 if (!r) {
243 /* key with a valid value, remove from the set */
244 ly_set_rm_index(&key_set, i, NULL);
Michal Vasko44685da2020-03-17 15:38:06 +0100245 }
246 }
247
Michal Vaskob36053d2020-03-26 15:49:30 +0100248 /* parser next */
249 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100250
Michal Vaskob36053d2020-03-26 15:49:30 +0100251 /* skip any children, resursively */
252 parents_count = xmlctx->elements.count;
253 while ((parents_count < xmlctx->elements.count) || (xmlctx->status == LYXML_ELEMENT)) {
254 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
255 }
256
257 /* parser next, but do not parse closing element of the list because it would remove its namespaces */
258 assert(xmlctx->status == LYXML_ELEM_CLOSE);
259 LY_CHECK_GOTO(ret = lyxml_ctx_peek(xmlctx, &next), cleanup);
260 if (next != LYXML_ELEM_CLOSE) {
261 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
262 }
Michal Vasko44685da2020-03-17 15:38:06 +0100263 }
264
265 if (key_set.count) {
Michal Vaskob36053d2020-03-26 15:49:30 +0100266 /* some keys are missing/did not validate */
Michal Vasko44685da2020-03-17 15:38:06 +0100267 ret = LY_ENOT;
Michal Vasko44685da2020-03-17 15:38:06 +0100268 }
269
270cleanup:
271 ly_set_erase(&key_set, NULL);
272 return ret;
273}
274
Michal Vasko1bf09392020-03-27 12:38:10 +0100275static LY_ERR
276lydxml_data_skip(struct lyxml_ctx *xmlctx)
277{
278 uint32_t parents_count;
279
280 /* remember current number of parents */
281 parents_count = xmlctx->elements.count;
282
283 /* skip after the content */
284 while (xmlctx->status != LYXML_ELEM_CONTENT) {
285 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
286 }
287 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
288
289 /* skip all children elements, recursively, if any */
290 while (parents_count < xmlctx->elements.count) {
291 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
292 }
293
294 /* close element */
295 assert(xmlctx->status == LYXML_ELEM_CLOSE);
296 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
297
298 return LY_SUCCESS;
299}
300
301static LY_ERR
Radek Krejci1798aae2020-07-14 13:26:06 +0200302lydxml_data_check_opaq(struct lyd_xml_ctx *lydctx, const struct lysc_node **snode)
Michal Vasko1bf09392020-03-27 12:38:10 +0100303{
304 LY_ERR ret = LY_SUCCESS;
305 enum LYXML_PARSER_STATUS prev_status;
Michal Vasko63f3d842020-07-08 10:10:14 +0200306 const char *prev_current, *pname, *pprefix;
Michal Vasko1bf09392020-03-27 12:38:10 +0100307 size_t pprefix_len, pname_len;
308 struct lyxml_ctx *xmlctx = lydctx->xmlctx;
309
Radek Krejci1798aae2020-07-14 13:26:06 +0200310 if ((lydctx->parse_options & LYD_PARSE_OPAQ) && ((*snode)->nodetype & (LYD_NODE_TERM | LYS_LIST))) {
Michal Vasko1bf09392020-03-27 12:38:10 +0100311 /* backup parser */
312 prev_status = xmlctx->status;
313 pprefix = xmlctx->prefix;
314 pprefix_len = xmlctx->prefix_len;
315 pname = xmlctx->name;
316 pname_len = xmlctx->name_len;
Michal Vasko63f3d842020-07-08 10:10:14 +0200317 prev_current = xmlctx->in->current;
Michal Vasko1bf09392020-03-27 12:38:10 +0100318 if ((xmlctx->status == LYXML_ELEM_CONTENT) && xmlctx->dynamic) {
319 /* it was backed up, do not free */
320 xmlctx->dynamic = 0;
321 }
322
323 /* skip attributes */
324 while (xmlctx->status == LYXML_ATTRIBUTE) {
325 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), restore);
326 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), restore);
327 }
328
329 if ((*snode)->nodetype & LYD_NODE_TERM) {
330 /* value may not be valid in which case we parse it as an opaque node */
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200331 if (_lys_value_validate(NULL, *snode, xmlctx->value, xmlctx->value_len, LY_PREF_XML, &xmlctx->ns)) {
Michal Vasko1bf09392020-03-27 12:38:10 +0100332 *snode = NULL;
333 }
334 } else {
335 /* skip content */
336 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), restore);
337
338 if (lydxml_check_list(xmlctx, *snode)) {
339 /* invalid list, parse as opaque if it missing/has invalid some keys */
340 *snode = NULL;
341 }
342 }
343
344restore:
345 /* restore parser */
346 if (xmlctx->dynamic) {
347 free((char *)xmlctx->value);
348 }
349 xmlctx->status = prev_status;
350 xmlctx->prefix = pprefix;
351 xmlctx->prefix_len = pprefix_len;
352 xmlctx->name = pname;
353 xmlctx->name_len = pname_len;
Michal Vasko63f3d842020-07-08 10:10:14 +0200354 xmlctx->in->current = prev_current;
Michal Vasko1bf09392020-03-27 12:38:10 +0100355 }
356
357 return ret;
358}
359
Radek Krejcie7b95092019-05-15 11:03:07 +0200360/**
Michal Vaskoa5da3292020-08-12 13:10:50 +0200361 * @brief Parse XML subtree.
Radek Krejcie7b95092019-05-15 11:03:07 +0200362 *
Michal Vaskob36053d2020-03-26 15:49:30 +0100363 * @param[in] lydctx XML YANG data parser context.
Radek Krejcie7b95092019-05-15 11:03:07 +0200364 * @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 +0200365 * @param[out] node Resulting list of the parsed nodes.
Michal Vasko9b368d32020-02-14 13:53:31 +0100366 * @return LY_ERR value.
Radek Krejcie7b95092019-05-15 11:03:07 +0200367 */
368static LY_ERR
Michal Vaskoa5da3292020-08-12 13:10:50 +0200369lydxml_subtree_r(struct lyd_xml_ctx *lydctx, struct lyd_node_inner *parent, struct lyd_node **first_p)
Radek Krejcie7b95092019-05-15 11:03:07 +0200370{
Michal Vaskob36053d2020-03-26 15:49:30 +0100371 LY_ERR ret = LY_SUCCESS;
Michal Vasko1bf09392020-03-27 12:38:10 +0100372 const char *prefix, *name;
373 size_t prefix_len, name_len;
Michal Vaskob36053d2020-03-26 15:49:30 +0100374 struct lyxml_ctx *xmlctx;
375 const struct ly_ctx *ctx;
Radek Krejcie7b95092019-05-15 11:03:07 +0200376 const struct lyxml_ns *ns;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200377 struct lyd_meta *meta = NULL;
378 struct lyd_attr *attr = NULL;
Radek Krejcie7b95092019-05-15 11:03:07 +0200379 const struct lysc_node *snode;
380 struct lys_module *mod;
Michal Vasko1bf09392020-03-27 12:38:10 +0100381 uint32_t prev_opts;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200382 struct lyd_node *node = NULL, *anchor;
Michal Vasko52927e22020-03-16 17:26:14 +0100383 struct ly_prefix *val_prefs;
Michal Vasko1ce933a2020-03-30 12:38:22 +0200384 int getnext_opts;
Radek Krejcie7b95092019-05-15 11:03:07 +0200385
Michal Vaskob36053d2020-03-26 15:49:30 +0100386 xmlctx = lydctx->xmlctx;
387 ctx = xmlctx->ctx;
Michal Vasko1ce933a2020-03-30 12:38:22 +0200388 /* leave if-feature check for validation */
389 getnext_opts = LYS_GETNEXT_NOSTATECHECK | (lydctx->int_opts & LYD_INTOPT_REPLY ? LYS_GETNEXT_OUTPUT : 0);
Michal Vasko6f4cbb62020-02-28 11:15:47 +0100390
Michal Vaskoa5da3292020-08-12 13:10:50 +0200391 assert(xmlctx->status == LYXML_ELEMENT);
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200392
Michal Vaskoa5da3292020-08-12 13:10:50 +0200393 /* remember element prefix and name */
394 prefix = xmlctx->prefix;
395 prefix_len = xmlctx->prefix_len;
396 name = xmlctx->name;
397 name_len = xmlctx->name_len;
398
399 /* get the element module */
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200400 ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200401 if (!ns) {
402 LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".",
403 prefix_len, prefix);
404 ret = LY_EVALID;
405 goto error;
406 }
407 mod = ly_ctx_get_module_implemented_ns(ctx, ns->uri);
408 if (!mod) {
409 if (lydctx->parse_options & LYD_PARSE_STRICT) {
410 LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "No module with namespace \"%s\" in the context.",
411 ns->uri);
Michal Vasko90932a92020-02-12 14:33:03 +0100412 ret = LY_EVALID;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200413 goto error;
Radek Krejcie7b95092019-05-15 11:03:07 +0200414 }
Michal Vaskoa5da3292020-08-12 13:10:50 +0200415 if (!(lydctx->parse_options & LYD_PARSE_OPAQ)) {
416 /* skip element with children */
417 LY_CHECK_GOTO(ret = lydxml_data_skip(xmlctx), error);
418 return LY_SUCCESS;
Radek Krejcie7b95092019-05-15 11:03:07 +0200419 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200420 }
421
Michal Vaskoa5da3292020-08-12 13:10:50 +0200422 /* parser next */
423 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
Michal Vasko90932a92020-02-12 14:33:03 +0100424
Michal Vaskoa5da3292020-08-12 13:10:50 +0200425 /* get the schema node */
426 snode = NULL;
427 if (mod && (!parent || parent->schema)) {
428 snode = lys_find_child(parent ? parent->schema : NULL, mod, name, name_len, 0, getnext_opts);
429 if (!snode) {
430 if (lydctx->parse_options & LYD_PARSE_STRICT) {
431 LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Element \"%.*s\" not found in the \"%s\" module.",
432 name_len, name, mod->name);
433 ret = LY_EVALID;
434 goto error;
435 } else if (!(lydctx->parse_options & LYD_PARSE_OPAQ)) {
436 /* skip element with children */
437 LY_CHECK_GOTO(ret = lydxml_data_skip(xmlctx), error);
438 return LY_SUCCESS;
439 }
440 } else {
441 /* check that schema node is valid and can be used */
442 LY_CHECK_GOTO(ret = lyd_parser_check_schema((struct lyd_ctx *)lydctx, snode), error);
443 LY_CHECK_GOTO(ret = lydxml_data_check_opaq(lydctx, &snode), error);
444 }
445 }
446
447 /* create metadata/attributes */
448 if (xmlctx->status == LYXML_ATTRIBUTE) {
449 if (snode) {
450 ret = lydxml_metadata(lydctx, snode, &meta);
451 LY_CHECK_GOTO(ret, error);
452 } else {
453 assert(lydctx->parse_options & LYD_PARSE_OPAQ);
454 ret = lydxml_attrs(xmlctx, &attr);
455 LY_CHECK_GOTO(ret, error);
456 }
457 }
458
459 assert(xmlctx->status == LYXML_ELEM_CONTENT);
460 if (!snode) {
461 assert(lydctx->parse_options & LYD_PARSE_OPAQ);
462
463 if (xmlctx->ws_only) {
464 /* ignore WS-only value */
465 xmlctx->value_len = 0;
466 val_prefs = NULL;
467 } else {
468 /* get value prefixes */
469 ret = lyxml_get_prefixes(xmlctx, xmlctx->value, xmlctx->value_len, &val_prefs);
470 LY_CHECK_GOTO(ret, error);
471 }
472
473 /* create node */
474 ret = lyd_create_opaq(ctx, name, name_len, xmlctx->value, xmlctx->value_len, &xmlctx->dynamic, 0, LYD_XML,
475 val_prefs, prefix, prefix_len, ns->uri, strlen(ns->uri), &node);
476 LY_CHECK_GOTO(ret, error);
477
478 /* parser next */
479 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
480
481 /* process children */
482 while (xmlctx->status == LYXML_ELEMENT) {
483 ret = lydxml_subtree_r(lydctx, (struct lyd_node_inner *)node, lyd_node_children_p(node));
484 LY_CHECK_GOTO(ret, error);
485 }
486 } else if (snode->nodetype & LYD_NODE_TERM) {
487 /* create node */
488 LY_CHECK_GOTO(ret = lyd_parser_create_term((struct lyd_ctx*)lydctx, snode, xmlctx->value, xmlctx->value_len,
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200489 &xmlctx->dynamic, 0, LY_PREF_XML, &xmlctx->ns, &node), error);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200490
491 if (parent && (node->schema->flags & LYS_KEY)) {
492 /* check the key order, the anchor must never be a key */
493 anchor = lyd_insert_get_next_anchor(parent->child, node);
494 if (anchor && (anchor->schema->flags & LYS_KEY)) {
495 if (lydctx->parse_options & LYD_PARSE_STRICT) {
496 LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_DATA, "Invalid position of the key \"%s\" in a list.",
497 node->schema->name);
498 ret = LY_EVALID;
499 goto error;
500 } else {
501 LOGWRN(ctx, "Invalid position of the key \"%s\" in a list.", node->schema->name);
502 }
503 }
504 }
505
506 /* parser next */
507 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
508
509 /* no children expected */
510 if (xmlctx->status == LYXML_ELEMENT) {
511 LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_SYNTAX, "Child element \"%.*s\" inside a terminal node \"%s\" found.",
512 xmlctx->name_len, xmlctx->name, snode->name);
513 ret = LY_EVALID;
514 goto error;
515 }
516 } else if (snode->nodetype & LYD_NODE_INNER) {
517 if (!xmlctx->ws_only) {
518 /* value in inner node */
519 LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_SYNTAX, "Text value \"%.*s\" inside an inner node \"%s\" found.",
520 xmlctx->value_len, xmlctx->value, snode->name);
521 ret = LY_EVALID;
522 goto error;
523 }
524
525 /* create node */
526 ret = lyd_create_inner(snode, &node);
527 LY_CHECK_GOTO(ret, error);
528
529 /* parser next */
530 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
531
532 /* process children */
533 while (xmlctx->status == LYXML_ELEMENT) {
534 ret = lydxml_subtree_r(lydctx, (struct lyd_node_inner *)node, lyd_node_children_p(node));
535 LY_CHECK_GOTO(ret, error);
536 }
537
538 if (snode->nodetype == LYS_LIST) {
539 /* check all keys exist */
540 LY_CHECK_GOTO(ret = lyd_parse_check_keys(node), error);
541 }
542
543 if (!(lydctx->parse_options & LYD_PARSE_ONLY)) {
544 /* new node validation, autodelete CANNOT occur, all nodes are new */
545 ret = lyd_validate_new(lyd_node_children_p(node), snode, NULL, NULL);
546 LY_CHECK_GOTO(ret, error);
547
548 /* add any missing default children */
549 ret = lyd_new_implicit_r(node, lyd_node_children_p(node), NULL, NULL, &lydctx->unres_node_type, &lydctx->when_check,
550 (lydctx->validate_options & LYD_VALIDATE_NO_STATE) ? LYD_IMPLICIT_NO_STATE : 0, NULL);
551 LY_CHECK_GOTO(ret, error);
552 }
553
554 if (snode->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) {
555 /* rememeber the RPC/action/notification */
556 lydctx->op_node = node;
557 }
558 } else if (snode->nodetype & LYD_NODE_ANY) {
559 if (!xmlctx->ws_only) {
560 /* value in inner node */
561 LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_SYNTAX, "Text value \"%.*s\" inside an any node \"%s\" found.",
562 xmlctx->value_len, xmlctx->value, snode->name);
563 ret = LY_EVALID;
564 goto error;
565 }
566
567 /* parser next */
568 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
569
570 /* parse any data tree with correct options */
571 prev_opts = lydctx->parse_options;
572 lydctx->parse_options &= ~LYD_PARSE_STRICT;
573 lydctx->parse_options |= LYD_PARSE_OPAQ;
574 anchor = NULL;
575 while (xmlctx->status == LYXML_ELEMENT) {
576 ret = lydxml_subtree_r(lydctx, NULL, &anchor);
577 LY_CHECK_ERR_GOTO(ret, lydctx->parse_options = prev_opts, error);
578 }
579 lydctx->parse_options = prev_opts;
580
581 /* create node */
582 ret = lyd_create_any(snode, anchor, LYD_ANYDATA_DATATREE, &node);
583 LY_CHECK_GOTO(ret, error);
584 }
585 assert(node);
586
587 /* add/correct flags */
588 if (snode) {
589 lyd_parse_set_data_flags(node, &lydctx->when_check, &meta, lydctx->parse_options);
590 }
591
592 /* parser next */
593 assert(xmlctx->status == LYXML_ELEM_CLOSE);
594 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
595
596 /* add metadata/attributes */
597 if (snode) {
598 lyd_insert_meta(node, meta);
599 } else {
600 lyd_insert_attr(node, attr);
601 }
602
603 /* insert, keep first pointer correct */
604 lyd_insert_node((struct lyd_node *)parent, first_p, node);
605 while (!parent && (*first_p)->prev->next) {
606 *first_p = (*first_p)->prev;
607 }
608
609 return LY_SUCCESS;
610
611error:
Michal Vasko3a41dff2020-07-15 14:30:28 +0200612 lyd_free_meta_siblings(meta);
613 ly_free_attr_siblings(ctx, attr);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200614 lyd_free_tree(node);
Radek Krejcie7b95092019-05-15 11:03:07 +0200615 return ret;
616}
617
618LY_ERR
Michal Vaskoa5da3292020-08-12 13:10:50 +0200619lyd_parse_xml_data(const struct ly_ctx *ctx, struct ly_in *in, int parse_options, int validate_options,
620 struct lyd_node **tree_p, struct lyd_ctx **lydctx_p)
Radek Krejcie7b95092019-05-15 11:03:07 +0200621{
Radek Krejci18a57d92019-07-25 14:01:42 +0200622 LY_ERR ret = LY_SUCCESS;
Radek Krejci1798aae2020-07-14 13:26:06 +0200623 struct lyd_xml_ctx *lydctx;
Radek Krejcie7b95092019-05-15 11:03:07 +0200624
Radek Krejci7931b192020-06-25 17:05:03 +0200625 assert(!(parse_options & ~LYD_PARSE_OPTS_MASK));
626 assert(!(validate_options & ~LYD_VALIDATE_OPTS_MASK));
627
Radek Krejci1798aae2020-07-14 13:26:06 +0200628 /* init context */
629 lydctx = calloc(1, sizeof *lydctx);
630 LY_CHECK_ERR_RET(!lydctx, LOGMEM(ctx), LY_EMEM);
631 LY_CHECK_GOTO(ret = lyxml_ctx_new(ctx, in, &lydctx->xmlctx), cleanup);
632 lydctx->parse_options = parse_options;
633 lydctx->validate_options = validate_options;
634 lydctx->free = lyd_xml_ctx_free;
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200635
Michal Vaskob1b5c262020-03-05 14:29:47 +0100636 /* parse XML data */
Michal Vaskoa5da3292020-08-12 13:10:50 +0200637 while (lydctx->xmlctx->status == LYXML_ELEMENT) {
638 LY_CHECK_GOTO(ret = lydxml_subtree_r(lydctx, NULL, tree_p), cleanup);
639 }
Michal Vaskocde73ac2019-11-14 16:10:27 +0100640
Michal Vaskocde73ac2019-11-14 16:10:27 +0100641cleanup:
Michal Vasko9b368d32020-02-14 13:53:31 +0100642 /* there should be no unresolved types stored */
Radek Krejci1798aae2020-07-14 13:26:06 +0200643 assert(!(parse_options & LYD_PARSE_ONLY) || (!lydctx->unres_node_type.count && !lydctx->unres_meta_type.count
644 && !lydctx->when_check.count));
Michal Vasko9b368d32020-02-14 13:53:31 +0100645
Michal Vasko9f96a052020-03-10 09:41:45 +0100646 if (ret) {
Radek Krejci1798aae2020-07-14 13:26:06 +0200647 lyd_xml_ctx_free((struct lyd_ctx *)lydctx);
648 lyd_free_all(*tree_p);
649 *tree_p = NULL;
650 } else {
651 *lydctx_p = (struct lyd_ctx *)lydctx;
Michal Vasko9f96a052020-03-10 09:41:45 +0100652 }
653 return ret;
654}
Michal Vasko1bf09392020-03-27 12:38:10 +0100655
656static LY_ERR
657lydxml_envelope(struct lyxml_ctx *xmlctx, const char *name, const char *uri, struct lyd_node **envp)
658{
659 LY_ERR ret = LY_SUCCESS;
660 const struct lyxml_ns *ns = NULL;
Radek Krejci1798aae2020-07-14 13:26:06 +0200661 struct lyd_attr *attr = NULL;
Michal Vasko1bf09392020-03-27 12:38:10 +0100662 const char *prefix;
663 size_t prefix_len;
664
665 *envp = NULL;
666
667 assert(xmlctx->status == LYXML_ELEMENT);
668 if (ly_strncmp(name, xmlctx->name, xmlctx->name_len)) {
669 /* not the expected element */
670 return LY_SUCCESS;
671 }
672
673 prefix = xmlctx->prefix;
674 prefix_len = xmlctx->prefix_len;
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200675 ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
Michal Vasko1bf09392020-03-27 12:38:10 +0100676 if (!ns) {
677 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".",
678 prefix_len, prefix);
679 return LY_EVALID;
680 } else if (strcmp(ns->uri, uri)) {
681 /* different namespace */
682 return LY_SUCCESS;
683 }
684
685 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
686
687 /* create attributes */
688 if (xmlctx->status == LYXML_ATTRIBUTE) {
689 LY_CHECK_RET(lydxml_attrs(xmlctx, &attr));
690 }
691
692 if (!xmlctx->ws_only) {
693 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_SYNTAX, "Unexpected value \"%.*s\" in the \"%s\" element.",
694 xmlctx->value_len, xmlctx->value, name);
695 ret = LY_EVALID;
696 goto cleanup;
697 }
698
699 /* parser next element */
700 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
701
702 /* create node */
Radek Krejci1798aae2020-07-14 13:26:06 +0200703 ret = lyd_create_opaq(xmlctx->ctx, name, strlen(name), "", 0, NULL, 0, LYD_XML, NULL, prefix, prefix_len,
704 uri, strlen(uri), envp);
Michal Vasko1bf09392020-03-27 12:38:10 +0100705 LY_CHECK_GOTO(ret, cleanup);
706
707 /* assign atributes */
708 ((struct lyd_node_opaq *)(*envp))->attr = attr;
709 attr = NULL;
710
711cleanup:
Michal Vasko3a41dff2020-07-15 14:30:28 +0200712 ly_free_attr_siblings(xmlctx->ctx, attr);
Michal Vasko1bf09392020-03-27 12:38:10 +0100713 return ret;
714}
715
716LY_ERR
Radek Krejci1798aae2020-07-14 13:26:06 +0200717lyd_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 +0100718{
719 LY_ERR ret = LY_SUCCESS;
720 struct lyd_xml_ctx lydctx = {0};
721 struct lyd_node *rpc_e = NULL, *act_e = NULL;
Radek Krejci1798aae2020-07-14 13:26:06 +0200722 struct lyd_node *tree = NULL;
Michal Vasko1bf09392020-03-27 12:38:10 +0100723
724 /* init */
Michal Vasko63f3d842020-07-08 10:10:14 +0200725 LY_CHECK_GOTO(ret = lyxml_ctx_new(ctx, in, &lydctx.xmlctx), cleanup);
Radek Krejci1798aae2020-07-14 13:26:06 +0200726 lydctx.parse_options = LYD_PARSE_ONLY | LYD_PARSE_STRICT;
Michal Vasko1bf09392020-03-27 12:38:10 +0100727 lydctx.int_opts = LYD_INTOPT_RPC;
Michal Vasko1bf09392020-03-27 12:38:10 +0100728
729 /* parse "rpc", if any */
730 LY_CHECK_GOTO(ret = lydxml_envelope(lydctx.xmlctx, "rpc", "urn:ietf:params:xml:ns:netconf:base:1.0", &rpc_e), cleanup);
731
732 if (rpc_e) {
733 /* parse "action", if any */
734 LY_CHECK_GOTO(ret = lydxml_envelope(lydctx.xmlctx, "action", "urn:ietf:params:xml:ns:yang:1", &act_e), cleanup);
735 }
736
737 /* parse the rest of data normally */
Michal Vaskocf770e22020-08-12 13:21:43 +0200738 LY_CHECK_GOTO(ret = lydxml_subtree_r(&lydctx, NULL, &tree), cleanup);
Michal Vasko1bf09392020-03-27 12:38:10 +0100739
Michal Vaskocf770e22020-08-12 13:21:43 +0200740 /* make sure we have parsed some operation and it is the only subtree */
Radek Krejci1798aae2020-07-14 13:26:06 +0200741 if (!lydctx.op_node) {
Michal Vasko1bf09392020-03-27 12:38:10 +0100742 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_DATA, "Missing the \"rpc\"/\"action\" node.");
743 ret = LY_EVALID;
744 goto cleanup;
Michal Vaskocf770e22020-08-12 13:21:43 +0200745 } else if (lydctx.xmlctx->status == LYXML_ELEMENT) {
746 LOGVAL(ctx, LY_VLOG_LINE, &lydctx.xmlctx->line, LYVE_SYNTAX, "Unexpected sibling element of \"%s\".",
747 tree->schema->name);
748 ret = LY_EVALID;
749 goto cleanup;
Michal Vasko1bf09392020-03-27 12:38:10 +0100750 }
751
752 /* finish XML parsing and check operation type */
753 if (act_e) {
754 if (lydctx.xmlctx->status != LYXML_ELEM_CLOSE) {
755 assert(lydctx.xmlctx->status == LYXML_ELEMENT);
756 LOGVAL(ctx, LY_VLOG_LINE, &lydctx.xmlctx->line, LYVE_SYNTAX, "Unexpected sibling element \"%.*s\" of \"action\".",
757 lydctx.xmlctx->name_len, lydctx.xmlctx->name);
758 ret = LY_EVALID;
759 goto cleanup;
Radek Krejci1798aae2020-07-14 13:26:06 +0200760 } else if (lydctx.op_node->schema->nodetype != LYS_ACTION) {
761 LOGVAL(ctx, LY_VLOG_LYD, lydctx.op_node, LYVE_DATA, "Unexpected %s element, an \"action\" expected.",
762 lys_nodetype2str(lydctx.op_node->schema->nodetype));
Michal Vasko1bf09392020-03-27 12:38:10 +0100763 ret = LY_EVALID;
764 goto cleanup;
765 }
766 LY_CHECK_GOTO(ret = lyxml_ctx_next(lydctx.xmlctx), cleanup);
767 }
768 if (rpc_e) {
769 if (lydctx.xmlctx->status != LYXML_ELEM_CLOSE) {
770 assert(lydctx.xmlctx->status == LYXML_ELEMENT);
771 LOGVAL(ctx, LY_VLOG_LINE, &lydctx.xmlctx->line, LYVE_SYNTAX, "Unexpected sibling element \"%.*s\" of \"rpc\".",
772 lydctx.xmlctx->name_len, lydctx.xmlctx->name);
773 ret = LY_EVALID;
774 goto cleanup;
Radek Krejci1798aae2020-07-14 13:26:06 +0200775 } else if (!act_e && (lydctx.op_node->schema->nodetype != LYS_RPC)) {
776 LOGVAL(ctx, LY_VLOG_LYD, lydctx.op_node, LYVE_DATA, "Unexpected %s element, an \"rpc\" expected.",
777 lys_nodetype2str(lydctx.op_node->schema->nodetype));
Michal Vasko1bf09392020-03-27 12:38:10 +0100778 ret = LY_EVALID;
779 goto cleanup;
780 }
781 LY_CHECK_GOTO(ret = lyxml_ctx_next(lydctx.xmlctx), cleanup);
782 }
783
Radek Krejci1798aae2020-07-14 13:26:06 +0200784 if (op_p) {
785 *op_p = lydctx.op_node;
Michal Vaskocc048b22020-03-27 15:52:38 +0100786 }
Radek Krejci1798aae2020-07-14 13:26:06 +0200787 assert(tree);
Michal Vasko1bf09392020-03-27 12:38:10 +0100788 if (act_e) {
789 /* connect to the action */
Michal Vasko4189c0f2020-08-13 09:05:22 +0200790 lyd_insert_node(act_e, NULL, tree);
791 tree = act_e;
Michal Vasko1bf09392020-03-27 12:38:10 +0100792 }
793 if (rpc_e) {
794 /* connect to the rpc */
Michal Vasko4189c0f2020-08-13 09:05:22 +0200795 lyd_insert_node(rpc_e, NULL, tree);
796 tree = rpc_e;
797 }
798 if (tree_p) {
799 *tree_p = tree;
Michal Vasko1bf09392020-03-27 12:38:10 +0100800 }
801
802cleanup:
803 /* we have used parse_only flag */
804 assert(!lydctx.unres_node_type.count && !lydctx.unres_meta_type.count && !lydctx.when_check.count);
805 lyxml_ctx_free(lydctx.xmlctx);
806 if (ret) {
Radek Krejci1798aae2020-07-14 13:26:06 +0200807 lyd_free_all(tree);
Michal Vasko1bf09392020-03-27 12:38:10 +0100808 lyd_free_tree(act_e);
809 lyd_free_tree(rpc_e);
Michal Vasko1bf09392020-03-27 12:38:10 +0100810 }
811 return ret;
812}
Michal Vaskoa8edff02020-03-27 14:47:01 +0100813
814static LY_ERR
815lydxml_notif_envelope(struct lyxml_ctx *xmlctx, struct lyd_node **envp)
816{
817 LY_ERR ret = LY_SUCCESS;
818 const struct lyxml_ns *ns = NULL;
Radek Krejci1798aae2020-07-14 13:26:06 +0200819 struct lyd_attr *attr = NULL;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100820 struct lyd_node *et;
821 const char *prefix;
822 size_t prefix_len;
823
824 *envp = NULL;
825
826 /* container envelope */
827 LY_CHECK_GOTO(ret = lydxml_envelope(xmlctx, "notification", "urn:ietf:params:xml:ns:netconf:notification:1.0",
828 envp), cleanup);
829
830 /* no envelope, fine */
831 if (!*envp) {
832 goto cleanup;
833 }
834
835 /* child "eventTime" */
836 if ((xmlctx->status != LYXML_ELEMENT) || ly_strncmp("eventTime", xmlctx->name, xmlctx->name_len)) {
837 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Missing the \"eventTime\" element.");
838 ret = LY_EVALID;
839 goto cleanup;
840 }
841
842 prefix = xmlctx->prefix;
843 prefix_len = xmlctx->prefix_len;
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200844 ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100845 if (!ns) {
846 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".",
847 prefix_len, prefix);
848 ret = LY_EVALID;
849 goto cleanup;
850 } else if (strcmp(ns->uri, "urn:ietf:params:xml:ns:netconf:notification:1.0")) {
851 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Invalid namespace \"%s\" of \"eventTime\".",
852 ns->uri);
853 ret = LY_EVALID;
854 goto cleanup;
855 }
856
857 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
858
859 /* create attributes */
860 if (xmlctx->status == LYXML_ATTRIBUTE) {
861 LY_CHECK_RET(lydxml_attrs(xmlctx, &attr));
862 }
863
864 /* validate value */
865 /* TODO */
866 /*if (!xmlctx->ws_only) {
867 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_SYNTAX, "Unexpected value \"%.*s\" in the \"%s\" element.",
868 xmlctx->value_len, xmlctx->value, name);
869 ret = LY_EVALID;
870 goto cleanup;
871 }*/
872
873 /* create node */
Radek Krejci1798aae2020-07-14 13:26:06 +0200874 ret = lyd_create_opaq(xmlctx->ctx, "eventTime", 9, xmlctx->value, xmlctx->value_len, NULL, 0, LYD_XML, NULL,
875 prefix, prefix_len, ns->uri, strlen(ns->uri), &et);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100876 LY_CHECK_GOTO(ret, cleanup);
877
878 /* assign atributes */
879 ((struct lyd_node_opaq *)et)->attr = attr;
880 attr = NULL;
881
882 /* insert */
883 lyd_insert_node(*envp, NULL, et);
884
885 /* finish parsing */
886 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
887 if (xmlctx->status != LYXML_ELEM_CLOSE) {
888 assert(xmlctx->status == LYXML_ELEMENT);
889 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_SYNTAX, "Unexpected sibling element \"%.*s\" of \"eventTime\".",
890 xmlctx->name_len, xmlctx->name);
891 ret = LY_EVALID;
892 goto cleanup;
893 }
894 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
895
896cleanup:
897 if (ret) {
898 lyd_free_tree(*envp);
Michal Vasko3a41dff2020-07-15 14:30:28 +0200899 ly_free_attr_siblings(xmlctx->ctx, attr);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100900 }
901 return ret;
902}
903
904LY_ERR
Radek Krejci1798aae2020-07-14 13:26:06 +0200905lyd_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 +0100906{
907 LY_ERR ret = LY_SUCCESS;
908 struct lyd_xml_ctx lydctx = {0};
909 struct lyd_node *ntf_e = NULL;
Radek Krejci1798aae2020-07-14 13:26:06 +0200910 struct lyd_node *tree = NULL;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100911
912 /* init */
Michal Vasko63f3d842020-07-08 10:10:14 +0200913 LY_CHECK_GOTO(ret = lyxml_ctx_new(ctx, in, &lydctx.xmlctx), cleanup);
Radek Krejci1798aae2020-07-14 13:26:06 +0200914 lydctx.parse_options = LYD_PARSE_ONLY | LYD_PARSE_STRICT;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100915 lydctx.int_opts = LYD_INTOPT_NOTIF;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100916
917 /* parse "notification" and "eventTime", if present */
918 LY_CHECK_GOTO(ret = lydxml_notif_envelope(lydctx.xmlctx, &ntf_e), cleanup);
919
920 /* parse the rest of data normally */
Michal Vaskocf770e22020-08-12 13:21:43 +0200921 LY_CHECK_GOTO(ret = lydxml_subtree_r(&lydctx, NULL, &tree), cleanup);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100922
923 /* make sure we have parsed some notification */
Radek Krejci1798aae2020-07-14 13:26:06 +0200924 if (!lydctx.op_node) {
Michal Vaskoa8edff02020-03-27 14:47:01 +0100925 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_DATA, "Missing the \"notification\" node.");
926 ret = LY_EVALID;
927 goto cleanup;
Michal Vaskocf770e22020-08-12 13:21:43 +0200928 } else if (lydctx.xmlctx->status == LYXML_ELEMENT) {
929 LOGVAL(ctx, LY_VLOG_LINE, &lydctx.xmlctx->line, LYVE_SYNTAX, "Unexpected sibling element of \"%s\".",
930 tree->schema->name);
931 ret = LY_EVALID;
932 goto cleanup;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100933 }
934
935 /* finish XML parsing */
936 if (ntf_e) {
937 if (lydctx.xmlctx->status != LYXML_ELEM_CLOSE) {
938 assert(lydctx.xmlctx->status == LYXML_ELEMENT);
939 LOGVAL(ctx, LY_VLOG_LINE, &lydctx.xmlctx->line, LYVE_SYNTAX, "Unexpected sibling element \"%.*s\" of \"notification\".",
940 lydctx.xmlctx->name_len, lydctx.xmlctx->name);
941 ret = LY_EVALID;
942 goto cleanup;
943 }
944 LY_CHECK_GOTO(ret = lyxml_ctx_next(lydctx.xmlctx), cleanup);
945 }
946
Radek Krejci1798aae2020-07-14 13:26:06 +0200947 if (ntf_p) {
948 *ntf_p = lydctx.op_node;
Michal Vaskocc048b22020-03-27 15:52:38 +0100949 }
Radek Krejci1798aae2020-07-14 13:26:06 +0200950 assert(tree);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100951 if (ntf_e) {
952 /* connect to the notification */
Michal Vasko4189c0f2020-08-13 09:05:22 +0200953 lyd_insert_node(ntf_e, NULL, tree);
954 tree = ntf_e;
955 }
956 if (tree_p) {
957 *tree_p = tree;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100958 }
959
960cleanup:
961 /* we have used parse_only flag */
962 assert(!lydctx.unres_node_type.count && !lydctx.unres_meta_type.count && !lydctx.when_check.count);
963 lyxml_ctx_free(lydctx.xmlctx);
964 if (ret) {
Radek Krejci1798aae2020-07-14 13:26:06 +0200965 lyd_free_all(tree);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100966 lyd_free_tree(ntf_e);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100967 }
968 return ret;
969}
Michal Vasko1ce933a2020-03-30 12:38:22 +0200970
971LY_ERR
Radek Krejci1798aae2020-07-14 13:26:06 +0200972lyd_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 +0200973{
974 LY_ERR ret = LY_SUCCESS;
975 struct lyd_xml_ctx lydctx = {0};
Michal Vasko4189c0f2020-08-13 09:05:22 +0200976 struct lyd_node *rpcr_e = NULL, *tree, *req_op, *rep_op = NULL;
Michal Vasko1ce933a2020-03-30 12:38:22 +0200977
978 /* init */
Michal Vaskob7be7a82020-08-20 09:09:04 +0200979 LY_CHECK_GOTO(ret = lyxml_ctx_new(LYD_CTX(request), in, &lydctx.xmlctx), cleanup);
Radek Krejci1798aae2020-07-14 13:26:06 +0200980 lydctx.parse_options = LYD_PARSE_ONLY | LYD_PARSE_STRICT;
Michal Vasko1ce933a2020-03-30 12:38:22 +0200981 lydctx.int_opts = LYD_INTOPT_REPLY;
Michal Vasko1ce933a2020-03-30 12:38:22 +0200982
983 /* find request OP */
Michal Vasko56daf732020-08-10 10:57:18 +0200984 LYD_TREE_DFS_BEGIN((struct lyd_node *)request, req_op) {
Michal Vasko1ce933a2020-03-30 12:38:22 +0200985 if (req_op->schema->nodetype & (LYS_RPC | LYS_ACTION)) {
986 break;
987 }
Michal Vasko56daf732020-08-10 10:57:18 +0200988 LYD_TREE_DFS_END(request, req_op);
Michal Vasko1ce933a2020-03-30 12:38:22 +0200989 }
990 if (!(req_op->schema->nodetype & (LYS_RPC | LYS_ACTION))) {
Michal Vaskob7be7a82020-08-20 09:09:04 +0200991 LOGERR(LYD_CTX(request), LY_EINVAL, "No RPC/action in the request found.");
Michal Vasko1ce933a2020-03-30 12:38:22 +0200992 ret = LY_EINVAL;
993 goto cleanup;
994 }
995
996 /* duplicate request OP with parents */
Michal Vasko3a41dff2020-07-15 14:30:28 +0200997 LY_CHECK_GOTO(ret = lyd_dup_single(req_op, NULL, LYD_DUP_WITH_PARENTS, &rep_op), cleanup);
Michal Vasko1ce933a2020-03-30 12:38:22 +0200998
999 /* parse "rpc-reply", if any */
Michal Vasko3a41dff2020-07-15 14:30:28 +02001000 LY_CHECK_GOTO(ret = lydxml_envelope(lydctx.xmlctx, "rpc-reply", "urn:ietf:params:xml:ns:netconf:base:1.0", &rpcr_e),
1001 cleanup);
Michal Vasko1ce933a2020-03-30 12:38:22 +02001002
1003 /* parse the rest of data normally but connect them to the duplicated operation */
Michal Vaskoa5da3292020-08-12 13:10:50 +02001004 while (lydctx.xmlctx->status == LYXML_ELEMENT) {
1005 ret = lydxml_subtree_r(&lydctx, (struct lyd_node_inner *)rep_op, lyd_node_children_p(rep_op));
1006 LY_CHECK_GOTO(ret, cleanup);
1007 }
Michal Vasko1ce933a2020-03-30 12:38:22 +02001008
1009 /* finish XML parsing and check operation type */
1010 if (rpcr_e) {
1011 if (lydctx.xmlctx->status != LYXML_ELEM_CLOSE) {
1012 assert(lydctx.xmlctx->status == LYXML_ELEMENT);
Michal Vaskob7be7a82020-08-20 09:09:04 +02001013 LOGVAL(LYD_CTX(request), LY_VLOG_LINE, &lydctx.xmlctx->line, LYVE_SYNTAX,
Michal Vasko1ce933a2020-03-30 12:38:22 +02001014 "Unexpected sibling element \"%.*s\" of \"rpc-reply\".", lydctx.xmlctx->name_len, lydctx.xmlctx->name);
1015 ret = LY_EVALID;
1016 goto cleanup;
1017 }
1018 LY_CHECK_GOTO(ret = lyxml_ctx_next(lydctx.xmlctx), cleanup);
1019 }
1020
Radek Krejci1798aae2020-07-14 13:26:06 +02001021 if (op_p) {
1022 *op_p = rep_op;
Michal Vasko1ce933a2020-03-30 12:38:22 +02001023 }
Michal Vasko4189c0f2020-08-13 09:05:22 +02001024 for (tree = rep_op; tree->parent; tree = LYD_PARENT(tree));
Michal Vasko1ce933a2020-03-30 12:38:22 +02001025 if (rpcr_e) {
1026 /* connect to the operation */
Michal Vasko4189c0f2020-08-13 09:05:22 +02001027 lyd_insert_node(rpcr_e, NULL, tree);
1028 tree = rpcr_e;
1029 }
1030 if (tree_p) {
1031 *tree_p = tree;
Michal Vasko1ce933a2020-03-30 12:38:22 +02001032 }
1033
1034cleanup:
1035 /* we have used parse_only flag */
1036 assert(!lydctx.unres_node_type.count && !lydctx.unres_meta_type.count && !lydctx.when_check.count);
1037 lyxml_ctx_free(lydctx.xmlctx);
1038 if (ret) {
1039 lyd_free_all(rep_op);
1040 lyd_free_tree(rpcr_e);
1041 }
1042 return ret;
1043}