blob: ffca41fcd4396d60ec834287e4d576a6b5d4bb16 [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 */
50 ly_resolve_prefix_clb resolve_prefix;
51
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 +020065/**
Michal Vaskob36053d2020-03-26 15:49:30 +010066 * @brief XML-parser's implementation of ly_type_resolve_prefix() callback to provide mapping between prefixes used
67 * in the values to the schema via XML namespaces.
Radek Krejciaca74032019-06-04 08:53:06 +020068 */
69static const struct lys_module *
Michal Vasko52927e22020-03-16 17:26:14 +010070lydxml_resolve_prefix(const struct ly_ctx *ctx, const char *prefix, size_t prefix_len, void *parser)
Radek Krejciaca74032019-06-04 08:53:06 +020071{
72 const struct lyxml_ns *ns;
Michal Vaskob36053d2020-03-26 15:49:30 +010073 struct lyxml_ctx *xmlctx = (struct lyxml_ctx *)parser;
Radek Krejciaca74032019-06-04 08:53:06 +020074
75 ns = lyxml_ns_get(xmlctx, prefix, prefix_len);
76 if (!ns) {
77 return NULL;
78 }
79
80 return ly_ctx_get_module_implemented_ns(ctx, ns->uri);
81}
82
Radek Krejcie7b95092019-05-15 11:03:07 +020083static LY_ERR
Radek Krejci1798aae2020-07-14 13:26:06 +020084lydxml_metadata(struct lyd_xml_ctx *lydctx, const struct lysc_node *sparent, struct lyd_meta **meta)
Radek Krejcie7b95092019-05-15 11:03:07 +020085{
Michal Vaskob36053d2020-03-26 15:49:30 +010086 LY_ERR ret = LY_EVALID;
Radek Krejci28681fa2019-09-06 13:08:45 +020087 const struct lyxml_ns *ns;
88 struct lys_module *mod;
Michal Vaskob36053d2020-03-26 15:49:30 +010089 const char *name;
90 size_t name_len;
Radek Krejci1798aae2020-07-14 13:26:06 +020091 struct lyxml_ctx *xmlctx = lydctx->xmlctx;
Radek Krejci28681fa2019-09-06 13:08:45 +020092
Michal Vaskob36053d2020-03-26 15:49:30 +010093 *meta = NULL;
Radek Krejci28681fa2019-09-06 13:08:45 +020094
Michal Vaskob36053d2020-03-26 15:49:30 +010095 while (xmlctx->status == LYXML_ATTRIBUTE) {
96 if (!xmlctx->prefix_len) {
Radek Krejci28681fa2019-09-06 13:08:45 +020097 /* in XML, all attributes must be prefixed
98 * TODO exception for NETCONF filters which are supposed to map to the ietf-netconf without prefix */
Radek Krejci1798aae2020-07-14 13:26:06 +020099 if (lydctx->parse_options & LYD_PARSE_STRICT) {
Michal Vasko52927e22020-03-16 17:26:14 +0100100 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Missing mandatory prefix for XML metadata \"%.*s\".",
Michal Vaskob36053d2020-03-26 15:49:30 +0100101 xmlctx->name_len, xmlctx->name);
102 goto cleanup;
Radek Krejci28681fa2019-09-06 13:08:45 +0200103 }
Michal Vaskob36053d2020-03-26 15:49:30 +0100104
Radek Krejci28681fa2019-09-06 13:08:45 +0200105skip_attr:
Michal Vaskob36053d2020-03-26 15:49:30 +0100106 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
107 assert(xmlctx->status == LYXML_ATTR_CONTENT);
108 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Radek Krejci28681fa2019-09-06 13:08:45 +0200109 continue;
110 }
111
112 /* get namespace of the attribute to find its annotation definition */
Michal Vaskob36053d2020-03-26 15:49:30 +0100113 ns = lyxml_ns_get(xmlctx, xmlctx->prefix, xmlctx->prefix_len);
Radek Krejci28681fa2019-09-06 13:08:45 +0200114 if (!ns) {
Michal Vasko52927e22020-03-16 17:26:14 +0100115 /* unknown namespace, XML error */
116 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".",
Michal Vaskob36053d2020-03-26 15:49:30 +0100117 xmlctx->prefix_len, xmlctx->prefix);
Radek Krejci28681fa2019-09-06 13:08:45 +0200118 goto cleanup;
119 }
Michal Vasko52927e22020-03-16 17:26:14 +0100120 mod = ly_ctx_get_module_implemented_ns(xmlctx->ctx, ns->uri);
Radek Krejci28681fa2019-09-06 13:08:45 +0200121 if (!mod) {
122 /* module is not implemented or not present in the schema */
Radek Krejci1798aae2020-07-14 13:26:06 +0200123 if (lydctx->parse_options & LYD_PARSE_STRICT) {
Michal Vasko52927e22020-03-16 17:26:14 +0100124 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE,
Michal Vasko9f96a052020-03-10 09:41:45 +0100125 "Unknown (or not implemented) YANG module with namespace \"%s\" for metadata \"%.*s%s%.*s\".",
Michal Vaskob36053d2020-03-26 15:49:30 +0100126 ns->uri, xmlctx->prefix_len, xmlctx->prefix, xmlctx->prefix_len ? ":" : "", xmlctx->name_len,
127 xmlctx->name);
128 goto cleanup;
Radek Krejci28681fa2019-09-06 13:08:45 +0200129 }
130 goto skip_attr;
131 }
132
Michal Vasko60ea6352020-06-29 13:39:39 +0200133 /* remember meta name and get its content */
Michal Vaskob36053d2020-03-26 15:49:30 +0100134 name = xmlctx->name;
135 name_len = xmlctx->name_len;
136 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
137 assert(xmlctx->status == LYXML_ATTR_CONTENT);
138
139 /* create metadata */
Radek Krejci1798aae2020-07-14 13:26:06 +0200140 ret = lyd_parser_create_meta((struct lyd_ctx*)lydctx, NULL, meta, mod, name, name_len, xmlctx->value, xmlctx->value_len,
141 &xmlctx->dynamic, 0, lydxml_resolve_prefix, xmlctx, LYD_XML, sparent);
142 LY_CHECK_GOTO(ret, cleanup);
Michal Vaskob36053d2020-03-26 15:49:30 +0100143
144 /* next attribute */
145 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Radek Krejcie7b95092019-05-15 11:03:07 +0200146 }
Michal Vasko52927e22020-03-16 17:26:14 +0100147
Radek Krejci28681fa2019-09-06 13:08:45 +0200148 ret = LY_SUCCESS;
Radek Krejcie7b95092019-05-15 11:03:07 +0200149
150cleanup:
Michal Vaskob36053d2020-03-26 15:49:30 +0100151 if (ret) {
Michal Vasko3a41dff2020-07-15 14:30:28 +0200152 lyd_free_meta_siblings(*meta);
Michal Vaskob36053d2020-03-26 15:49:30 +0100153 *meta = NULL;
Radek Krejci38d85362019-09-05 16:26:38 +0200154 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200155 return ret;
156}
157
Michal Vasko52927e22020-03-16 17:26:14 +0100158static LY_ERR
Radek Krejci1798aae2020-07-14 13:26:06 +0200159lydxml_attrs(struct lyxml_ctx *xmlctx, struct lyd_attr **attr)
Michal Vasko52927e22020-03-16 17:26:14 +0100160{
161 LY_ERR ret = LY_SUCCESS;
162 const struct lyxml_ns *ns;
163 struct ly_prefix *val_prefs;
Radek Krejci1798aae2020-07-14 13:26:06 +0200164 struct lyd_attr *attr2;
Michal Vaskob36053d2020-03-26 15:49:30 +0100165 const char *name, *prefix;
166 size_t name_len, prefix_len;
Michal Vasko52927e22020-03-16 17:26:14 +0100167
168 assert(attr);
Michal Vaskob36053d2020-03-26 15:49:30 +0100169 *attr = NULL;
Michal Vasko52927e22020-03-16 17:26:14 +0100170
Michal Vaskob36053d2020-03-26 15:49:30 +0100171 while (xmlctx->status == LYXML_ATTRIBUTE) {
Michal Vasko52927e22020-03-16 17:26:14 +0100172 ns = NULL;
Michal Vaskob36053d2020-03-26 15:49:30 +0100173 if (xmlctx->prefix_len) {
Michal Vasko52927e22020-03-16 17:26:14 +0100174 /* get namespace of the attribute */
Michal Vaskob36053d2020-03-26 15:49:30 +0100175 ns = lyxml_ns_get(xmlctx, xmlctx->prefix, xmlctx->prefix_len);
Michal Vasko52927e22020-03-16 17:26:14 +0100176 if (!ns) {
177 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".",
Michal Vaskob36053d2020-03-26 15:49:30 +0100178 xmlctx->prefix_len, xmlctx->prefix);
Michal Vasko52927e22020-03-16 17:26:14 +0100179 ret = LY_EVALID;
180 goto cleanup;
181 }
182 }
183
184 if (*attr) {
185 attr2 = *attr;
186 } else {
187 attr2 = NULL;
188 }
189
Michal Vaskob36053d2020-03-26 15:49:30 +0100190 /* remember attr prefix, name, and get its content */
191 prefix = xmlctx->prefix;
192 prefix_len = xmlctx->prefix_len;
193 name = xmlctx->name;
194 name_len = xmlctx->name_len;
195 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
196 assert(xmlctx->status == LYXML_ATTR_CONTENT);
197
Michal Vasko52927e22020-03-16 17:26:14 +0100198 /* get value prefixes */
Michal Vaskob36053d2020-03-26 15:49:30 +0100199 LY_CHECK_GOTO(ret = lyxml_get_prefixes(xmlctx, xmlctx->value, xmlctx->value_len, &val_prefs), cleanup);
Michal Vasko52927e22020-03-16 17:26:14 +0100200
201 /* attr2 is always changed to the created attribute */
Radek Krejci1798aae2020-07-14 13:26:06 +0200202 ret = lyd_create_attr(NULL, &attr2, xmlctx->ctx, name, name_len, xmlctx->value, xmlctx->value_len,
203 &xmlctx->dynamic, 0, LYD_XML, val_prefs, prefix, prefix_len,
204 ns ? ns->uri : NULL, ns ? strlen(ns->uri) : 0);
Michal Vasko52927e22020-03-16 17:26:14 +0100205 LY_CHECK_GOTO(ret, cleanup);
206
207 if (!*attr) {
208 *attr = attr2;
209 }
Michal Vaskob36053d2020-03-26 15:49:30 +0100210
211 /* next attribute */
212 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko52927e22020-03-16 17:26:14 +0100213 }
214
215cleanup:
Michal Vaskob36053d2020-03-26 15:49:30 +0100216 if (ret) {
Michal Vasko3a41dff2020-07-15 14:30:28 +0200217 ly_free_attr_siblings(xmlctx->ctx, *attr);
Michal Vaskob36053d2020-03-26 15:49:30 +0100218 *attr = NULL;
Michal Vasko52927e22020-03-16 17:26:14 +0100219 }
Michal Vasko52927e22020-03-16 17:26:14 +0100220 return ret;
221}
222
Michal Vasko44685da2020-03-17 15:38:06 +0100223static LY_ERR
Michal Vaskob36053d2020-03-26 15:49:30 +0100224lydxml_check_list(struct lyxml_ctx *xmlctx, const struct lysc_node *list)
Michal Vasko44685da2020-03-17 15:38:06 +0100225{
Michal Vaskob36053d2020-03-26 15:49:30 +0100226 LY_ERR ret = LY_SUCCESS, r;
227 enum LYXML_PARSER_STATUS next;
Michal Vasko44685da2020-03-17 15:38:06 +0100228 struct ly_set key_set = {0};
229 const struct lysc_node *snode;
Michal Vaskob36053d2020-03-26 15:49:30 +0100230 uint32_t i, parents_count;
Michal Vasko44685da2020-03-17 15:38:06 +0100231
232 assert(list && (list->nodetype == LYS_LIST));
233
234 /* get all keys into a set (keys do not have if-features or anything) */
235 snode = NULL;
236 while ((snode = lys_getnext(snode, list, NULL, LYS_GETNEXT_NOSTATECHECK)) && (snode->flags & LYS_KEY)) {
237 ly_set_add(&key_set, (void *)snode, LY_SET_OPT_USEASLIST);
238 }
239
Michal Vaskob36053d2020-03-26 15:49:30 +0100240 while (xmlctx->status == LYXML_ELEMENT) {
Michal Vasko44685da2020-03-17 15:38:06 +0100241 /* find key definition */
242 for (i = 0; i < key_set.count; ++i) {
243 snode = (const struct lysc_node *)key_set.objs[i];
Michal Vaskob36053d2020-03-26 15:49:30 +0100244 if (!ly_strncmp(snode->name, xmlctx->name, xmlctx->name_len)) {
Michal Vasko44685da2020-03-17 15:38:06 +0100245 break;
246 }
247 }
Michal Vaskob36053d2020-03-26 15:49:30 +0100248 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100249
250 /* skip attributes */
251 while (xmlctx->status == LYXML_ATTRIBUTE) {
Michal Vaskob36053d2020-03-26 15:49:30 +0100252 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
253 assert(xmlctx->status == LYXML_ATTR_CONTENT);
254 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100255 }
256
Michal Vaskob36053d2020-03-26 15:49:30 +0100257 assert(xmlctx->status == LYXML_ELEM_CONTENT);
258 if (i < key_set.count) {
259 /* validate the value */
Michal Vaskof937cfe2020-08-03 16:07:12 +0200260 r = _lys_value_validate(NULL, snode, xmlctx->value, xmlctx->value_len, lydxml_resolve_prefix, xmlctx, LYD_XML);
Michal Vaskob36053d2020-03-26 15:49:30 +0100261 if (!r) {
262 /* key with a valid value, remove from the set */
263 ly_set_rm_index(&key_set, i, NULL);
Michal Vasko44685da2020-03-17 15:38:06 +0100264 }
265 }
266
Michal Vaskob36053d2020-03-26 15:49:30 +0100267 /* parser next */
268 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100269
Michal Vaskob36053d2020-03-26 15:49:30 +0100270 /* skip any children, resursively */
271 parents_count = xmlctx->elements.count;
272 while ((parents_count < xmlctx->elements.count) || (xmlctx->status == LYXML_ELEMENT)) {
273 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
274 }
275
276 /* parser next, but do not parse closing element of the list because it would remove its namespaces */
277 assert(xmlctx->status == LYXML_ELEM_CLOSE);
278 LY_CHECK_GOTO(ret = lyxml_ctx_peek(xmlctx, &next), cleanup);
279 if (next != LYXML_ELEM_CLOSE) {
280 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
281 }
Michal Vasko44685da2020-03-17 15:38:06 +0100282 }
283
284 if (key_set.count) {
Michal Vaskob36053d2020-03-26 15:49:30 +0100285 /* some keys are missing/did not validate */
Michal Vasko44685da2020-03-17 15:38:06 +0100286 ret = LY_ENOT;
Michal Vasko44685da2020-03-17 15:38:06 +0100287 }
288
289cleanup:
290 ly_set_erase(&key_set, NULL);
291 return ret;
292}
293
Michal Vasko1bf09392020-03-27 12:38:10 +0100294static LY_ERR
295lydxml_data_skip(struct lyxml_ctx *xmlctx)
296{
297 uint32_t parents_count;
298
299 /* remember current number of parents */
300 parents_count = xmlctx->elements.count;
301
302 /* skip after the content */
303 while (xmlctx->status != LYXML_ELEM_CONTENT) {
304 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
305 }
306 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
307
308 /* skip all children elements, recursively, if any */
309 while (parents_count < xmlctx->elements.count) {
310 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
311 }
312
313 /* close element */
314 assert(xmlctx->status == LYXML_ELEM_CLOSE);
315 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
316
317 return LY_SUCCESS;
318}
319
320static LY_ERR
Radek Krejci1798aae2020-07-14 13:26:06 +0200321lydxml_data_check_opaq(struct lyd_xml_ctx *lydctx, const struct lysc_node **snode)
Michal Vasko1bf09392020-03-27 12:38:10 +0100322{
323 LY_ERR ret = LY_SUCCESS;
324 enum LYXML_PARSER_STATUS prev_status;
Michal Vasko63f3d842020-07-08 10:10:14 +0200325 const char *prev_current, *pname, *pprefix;
Michal Vasko1bf09392020-03-27 12:38:10 +0100326 size_t pprefix_len, pname_len;
327 struct lyxml_ctx *xmlctx = lydctx->xmlctx;
328
Radek Krejci1798aae2020-07-14 13:26:06 +0200329 if ((lydctx->parse_options & LYD_PARSE_OPAQ) && ((*snode)->nodetype & (LYD_NODE_TERM | LYS_LIST))) {
Michal Vasko1bf09392020-03-27 12:38:10 +0100330 /* backup parser */
331 prev_status = xmlctx->status;
332 pprefix = xmlctx->prefix;
333 pprefix_len = xmlctx->prefix_len;
334 pname = xmlctx->name;
335 pname_len = xmlctx->name_len;
Michal Vasko63f3d842020-07-08 10:10:14 +0200336 prev_current = xmlctx->in->current;
Michal Vasko1bf09392020-03-27 12:38:10 +0100337 if ((xmlctx->status == LYXML_ELEM_CONTENT) && xmlctx->dynamic) {
338 /* it was backed up, do not free */
339 xmlctx->dynamic = 0;
340 }
341
342 /* skip attributes */
343 while (xmlctx->status == LYXML_ATTRIBUTE) {
344 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), restore);
345 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), restore);
346 }
347
348 if ((*snode)->nodetype & LYD_NODE_TERM) {
349 /* value may not be valid in which case we parse it as an opaque node */
Michal Vaskof937cfe2020-08-03 16:07:12 +0200350 if (_lys_value_validate(NULL, *snode, xmlctx->value, xmlctx->value_len, lydxml_resolve_prefix, xmlctx, LYD_XML)) {
Michal Vasko1bf09392020-03-27 12:38:10 +0100351 *snode = NULL;
352 }
353 } else {
354 /* skip content */
355 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), restore);
356
357 if (lydxml_check_list(xmlctx, *snode)) {
358 /* invalid list, parse as opaque if it missing/has invalid some keys */
359 *snode = NULL;
360 }
361 }
362
363restore:
364 /* restore parser */
365 if (xmlctx->dynamic) {
366 free((char *)xmlctx->value);
367 }
368 xmlctx->status = prev_status;
369 xmlctx->prefix = pprefix;
370 xmlctx->prefix_len = pprefix_len;
371 xmlctx->name = pname;
372 xmlctx->name_len = pname_len;
Michal Vasko63f3d842020-07-08 10:10:14 +0200373 xmlctx->in->current = prev_current;
Michal Vasko1bf09392020-03-27 12:38:10 +0100374 }
375
376 return ret;
377}
378
Radek Krejcie7b95092019-05-15 11:03:07 +0200379/**
Michal Vasko9f96a052020-03-10 09:41:45 +0100380 * @brief Parse XML elements as YANG data node children the specified parent node.
Radek Krejcie7b95092019-05-15 11:03:07 +0200381 *
Michal Vaskob36053d2020-03-26 15:49:30 +0100382 * @param[in] lydctx XML YANG data parser context.
Radek Krejcie7b95092019-05-15 11:03:07 +0200383 * @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 +0200384 * @param[out] node Resulting list of the parsed nodes.
Michal Vasko9b368d32020-02-14 13:53:31 +0100385 * @return LY_ERR value.
Radek Krejcie7b95092019-05-15 11:03:07 +0200386 */
387static LY_ERR
Michal Vasko1bf09392020-03-27 12:38:10 +0100388lydxml_data_r(struct lyd_xml_ctx *lydctx, struct lyd_node_inner *parent, struct lyd_node **first)
Radek Krejcie7b95092019-05-15 11:03:07 +0200389{
Michal Vaskob36053d2020-03-26 15:49:30 +0100390 LY_ERR ret = LY_SUCCESS;
Michal Vasko1bf09392020-03-27 12:38:10 +0100391 const char *prefix, *name;
392 size_t prefix_len, name_len;
Michal Vaskob36053d2020-03-26 15:49:30 +0100393 struct lyxml_ctx *xmlctx;
394 const struct ly_ctx *ctx;
Radek Krejcie7b95092019-05-15 11:03:07 +0200395 const struct lyxml_ns *ns;
Michal Vasko5ab0d5c2020-06-29 11:48:05 +0200396 struct lyd_meta *meta = NULL, *m;
Radek Krejci1798aae2020-07-14 13:26:06 +0200397 struct lyd_attr *attr = NULL, *a;
Radek Krejcie7b95092019-05-15 11:03:07 +0200398 const struct lysc_node *snode;
399 struct lys_module *mod;
Michal Vasko1bf09392020-03-27 12:38:10 +0100400 uint32_t prev_opts;
Michal Vasko52927e22020-03-16 17:26:14 +0100401 struct lyd_node *cur = NULL, *anchor;
402 struct ly_prefix *val_prefs;
Michal Vasko1ce933a2020-03-30 12:38:22 +0200403 int getnext_opts;
Radek Krejcie7b95092019-05-15 11:03:07 +0200404
Michal Vaskob36053d2020-03-26 15:49:30 +0100405 xmlctx = lydctx->xmlctx;
406 ctx = xmlctx->ctx;
Michal Vasko1ce933a2020-03-30 12:38:22 +0200407 /* leave if-feature check for validation */
408 getnext_opts = LYS_GETNEXT_NOSTATECHECK | (lydctx->int_opts & LYD_INTOPT_REPLY ? LYS_GETNEXT_OUTPUT : 0);
Michal Vasko6f4cbb62020-02-28 11:15:47 +0100409
Michal Vaskob36053d2020-03-26 15:49:30 +0100410 while (xmlctx->status == LYXML_ELEMENT) {
411 /* remember element prefix and name */
412 prefix = xmlctx->prefix;
413 prefix_len = xmlctx->prefix_len;
414 name = xmlctx->name;
415 name_len = xmlctx->name_len;
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200416
Michal Vaskob36053d2020-03-26 15:49:30 +0100417 /* get the element module */
418 ns = lyxml_ns_get(xmlctx, prefix, prefix_len);
Radek Krejcie7b95092019-05-15 11:03:07 +0200419 if (!ns) {
Michal Vaskob36053d2020-03-26 15:49:30 +0100420 LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".",
421 prefix_len, prefix);
Michal Vasko90932a92020-02-12 14:33:03 +0100422 ret = LY_EVALID;
423 goto cleanup;
Radek Krejcie7b95092019-05-15 11:03:07 +0200424 }
Michal Vaskob36053d2020-03-26 15:49:30 +0100425 mod = ly_ctx_get_module_implemented_ns(ctx, ns->uri);
Michal Vaskoaa7f4fa2020-06-22 10:03:53 +0200426 if (!mod) {
Radek Krejci1798aae2020-07-14 13:26:06 +0200427 if (lydctx->parse_options & LYD_PARSE_STRICT) {
Michal Vaskoaa7f4fa2020-06-22 10:03:53 +0200428 LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "No module with namespace \"%s\" in the context.",
429 ns->uri);
430 ret = LY_EVALID;
431 goto cleanup;
432 }
Radek Krejci1798aae2020-07-14 13:26:06 +0200433 if (!(lydctx->parse_options & LYD_PARSE_OPAQ)) {
Michal Vasko2acb5a62020-06-23 13:23:53 +0200434 /* skip element with children */
435 LY_CHECK_GOTO(ret = lydxml_data_skip(xmlctx), cleanup);
436 continue;
437 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200438 }
Michal Vasko52927e22020-03-16 17:26:14 +0100439
Michal Vasko1bf09392020-03-27 12:38:10 +0100440 /* parser next */
441 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
442
Michal Vaskob36053d2020-03-26 15:49:30 +0100443 /* get the schema node */
Michal Vasko52927e22020-03-16 17:26:14 +0100444 snode = NULL;
445 if (mod && (!parent || parent->schema)) {
Michal Vasko1ce933a2020-03-30 12:38:22 +0200446 snode = lys_find_child(parent ? parent->schema : NULL, mod, name, name_len, 0, getnext_opts);
Michal Vaskob36053d2020-03-26 15:49:30 +0100447 if (!snode) {
Radek Krejci1798aae2020-07-14 13:26:06 +0200448 if (lydctx->parse_options & LYD_PARSE_STRICT) {
Michal Vaskob36053d2020-03-26 15:49:30 +0100449 LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Element \"%.*s\" not found in the \"%s\" module.",
450 name_len, name, mod->name);
451 ret = LY_EVALID;
452 goto cleanup;
Radek Krejci1798aae2020-07-14 13:26:06 +0200453 } else if (!(lydctx->parse_options & LYD_PARSE_OPAQ)) {
Michal Vasko1bf09392020-03-27 12:38:10 +0100454 /* skip element with children */
455 LY_CHECK_GOTO(ret = lydxml_data_skip(xmlctx), cleanup);
Michal Vaskob36053d2020-03-26 15:49:30 +0100456 continue;
457 }
Michal Vaskob36053d2020-03-26 15:49:30 +0100458 } else {
Michal Vasko1bf09392020-03-27 12:38:10 +0100459 /* check that schema node is valid and can be used */
Radek Krejci1798aae2020-07-14 13:26:06 +0200460 LY_CHECK_GOTO(ret = lyd_parser_check_schema((struct lyd_ctx *)lydctx, snode), cleanup);
461 LY_CHECK_GOTO(ret = lydxml_data_check_opaq(lydctx, &snode), cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100462 }
463 }
464
Michal Vaskob36053d2020-03-26 15:49:30 +0100465 /* create metadata/attributes */
466 if (xmlctx->status == LYXML_ATTRIBUTE) {
Michal Vasko52927e22020-03-16 17:26:14 +0100467 if (snode) {
Radek Krejci1798aae2020-07-14 13:26:06 +0200468 ret = lydxml_metadata(lydctx, snode, &meta);
Michal Vasko52927e22020-03-16 17:26:14 +0100469 LY_CHECK_GOTO(ret, cleanup);
470 } else {
Radek Krejci1798aae2020-07-14 13:26:06 +0200471 assert(lydctx->parse_options & LYD_PARSE_OPAQ);
Michal Vaskob36053d2020-03-26 15:49:30 +0100472 ret = lydxml_attrs(xmlctx, &attr);
473 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko52927e22020-03-16 17:26:14 +0100474 }
Michal Vasko8d544252020-03-02 10:19:52 +0100475 }
476
Michal Vaskob36053d2020-03-26 15:49:30 +0100477 assert(xmlctx->status == LYXML_ELEM_CONTENT);
Michal Vasko52927e22020-03-16 17:26:14 +0100478 if (!snode) {
Radek Krejci1798aae2020-07-14 13:26:06 +0200479 assert(lydctx->parse_options & LYD_PARSE_OPAQ);
Michal Vasko52927e22020-03-16 17:26:14 +0100480
Michal Vaskob36053d2020-03-26 15:49:30 +0100481 if (xmlctx->ws_only) {
482 /* ignore WS-only value */
483 xmlctx->value_len = 0;
484 val_prefs = NULL;
Michal Vasko52927e22020-03-16 17:26:14 +0100485 } else {
Michal Vaskob36053d2020-03-26 15:49:30 +0100486 /* get value prefixes */
487 ret = lyxml_get_prefixes(xmlctx, xmlctx->value, xmlctx->value_len, &val_prefs);
Michal Vasko52927e22020-03-16 17:26:14 +0100488 LY_CHECK_GOTO(ret, cleanup);
Radek Krejcie7b95092019-05-15 11:03:07 +0200489 }
Michal Vasko90932a92020-02-12 14:33:03 +0100490
491 /* create node */
Radek Krejci1798aae2020-07-14 13:26:06 +0200492 ret = lyd_create_opaq(ctx, name, name_len, xmlctx->value, xmlctx->value_len, &xmlctx->dynamic, 0, LYD_XML,
493 val_prefs, prefix, prefix_len, ns->uri, strlen(ns->uri), &cur);
Michal Vaskob36053d2020-03-26 15:49:30 +0100494 LY_CHECK_GOTO(ret, cleanup);
495
496 /* parser next */
497 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
498
499 /* process children */
500 if (xmlctx->status == LYXML_ELEMENT) {
Michal Vasko1bf09392020-03-27 12:38:10 +0100501 ret = lydxml_data_r(lydctx, (struct lyd_node_inner *)cur, lyd_node_children_p(cur));
Michal Vaskob36053d2020-03-26 15:49:30 +0100502 LY_CHECK_GOTO(ret, cleanup);
503 }
504 } else if (snode->nodetype & LYD_NODE_TERM) {
505 /* create node */
Radek Krejci1798aae2020-07-14 13:26:06 +0200506 LY_CHECK_GOTO(ret = lyd_parser_create_term((struct lyd_ctx*)lydctx, snode, xmlctx->value, xmlctx->value_len, &xmlctx->dynamic, 0,
507 lydxml_resolve_prefix, xmlctx, LYD_XML, &cur), cleanup);
Michal Vasko9b368d32020-02-14 13:53:31 +0100508
509 if (parent && (cur->schema->flags & LYS_KEY)) {
Michal Vaskob104f112020-07-17 09:54:54 +0200510 /* check the key order, the anchor must never be a key */
511 anchor = lyd_insert_get_next_anchor(parent->child, cur);
512 if (anchor && (anchor->schema->flags & LYS_KEY)) {
Radek Krejci1798aae2020-07-14 13:26:06 +0200513 if (lydctx->parse_options & LYD_PARSE_STRICT) {
Michal Vaskob36053d2020-03-26 15:49:30 +0100514 LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_DATA, "Invalid position of the key \"%s\" in a list.",
Michal Vasko9b368d32020-02-14 13:53:31 +0100515 cur->schema->name);
516 ret = LY_EVALID;
517 goto cleanup;
518 } else {
Michal Vaskob36053d2020-03-26 15:49:30 +0100519 LOGWRN(ctx, "Invalid position of the key \"%s\" in a list.", cur->schema->name);
Michal Vasko9b368d32020-02-14 13:53:31 +0100520 }
521 }
522 }
Michal Vaskob36053d2020-03-26 15:49:30 +0100523
524 /* parser next */
525 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
526
527 /* no children expected */
528 if (xmlctx->status == LYXML_ELEMENT) {
Michal Vasko1bf09392020-03-27 12:38:10 +0100529 LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_SYNTAX, "Child element \"%.*s\" inside a terminal node \"%s\" found.",
530 xmlctx->name_len, xmlctx->name, snode->name);
Michal Vasko44685da2020-03-17 15:38:06 +0100531 ret = LY_EVALID;
532 goto cleanup;
Michal Vaskob36053d2020-03-26 15:49:30 +0100533 }
534 } else if (snode->nodetype & LYD_NODE_INNER) {
535 if (!xmlctx->ws_only) {
536 /* value in inner node */
Michal Vasko1bf09392020-03-27 12:38:10 +0100537 LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_SYNTAX, "Text value \"%.*s\" inside an inner node \"%s\" found.",
538 xmlctx->value_len, xmlctx->value, snode->name);
Michal Vaskob36053d2020-03-26 15:49:30 +0100539 ret = LY_EVALID;
540 goto cleanup;
Radek Krejcie7b95092019-05-15 11:03:07 +0200541 }
Michal Vasko90932a92020-02-12 14:33:03 +0100542
543 /* create node */
544 ret = lyd_create_inner(snode, &cur);
545 LY_CHECK_GOTO(ret, cleanup);
546
Michal Vaskob36053d2020-03-26 15:49:30 +0100547 /* parser next */
548 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
549
Radek Krejciee4cab22019-07-17 17:07:47 +0200550 /* process children */
Michal Vaskob36053d2020-03-26 15:49:30 +0100551 if (xmlctx->status == LYXML_ELEMENT) {
Michal Vasko1bf09392020-03-27 12:38:10 +0100552 ret = lydxml_data_r(lydctx, (struct lyd_node_inner *)cur, lyd_node_children_p(cur));
Michal Vasko9f96a052020-03-10 09:41:45 +0100553 LY_CHECK_GOTO(ret, cleanup);
554 }
555
556 if (snode->nodetype == LYS_LIST) {
557 /* check all keys exist */
Michal Vasko44685da2020-03-17 15:38:06 +0100558 LY_CHECK_GOTO(ret = lyd_parse_check_keys(cur), cleanup);
Radek Krejcie7b95092019-05-15 11:03:07 +0200559 }
Michal Vasko9b368d32020-02-14 13:53:31 +0100560
Radek Krejci1798aae2020-07-14 13:26:06 +0200561 if (!(lydctx->parse_options & LYD_PARSE_ONLY)) {
Michal Vaskob1b5c262020-03-05 14:29:47 +0100562 /* new node validation, autodelete CANNOT occur, all nodes are new */
Michal Vasko8104fd42020-07-13 11:09:51 +0200563 ret = lyd_validate_new(lyd_node_children_p(cur), snode, NULL, NULL);
Michal Vaskob1b5c262020-03-05 14:29:47 +0100564 LY_CHECK_GOTO(ret, cleanup);
565
Michal Vasko9b368d32020-02-14 13:53:31 +0100566 /* add any missing default children */
Radek Krejci1798aae2020-07-14 13:26:06 +0200567 ret = lyd_new_implicit_r(cur, lyd_node_children_p(cur), NULL, NULL, &lydctx->unres_node_type, &lydctx->when_check,
568 (lydctx->validate_options & LYD_VALIDATE_NO_STATE) ? LYD_IMPLICIT_NO_STATE : 0, NULL);
Michal Vasko9b368d32020-02-14 13:53:31 +0100569 LY_CHECK_GOTO(ret, cleanup);
570 }
571
Michal Vasko751cb4d2020-07-14 12:25:28 +0200572 if (snode->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) {
Michal Vasko1bf09392020-03-27 12:38:10 +0100573 /* rememeber the RPC/action/notification */
Radek Krejci1798aae2020-07-14 13:26:06 +0200574 lydctx->op_node = cur;
Michal Vasko9b368d32020-02-14 13:53:31 +0100575 }
Radek Krejciee4cab22019-07-17 17:07:47 +0200576 } else if (snode->nodetype & LYD_NODE_ANY) {
Michal Vaskob36053d2020-03-26 15:49:30 +0100577 if (!xmlctx->ws_only) {
578 /* value in inner node */
Michal Vasko1bf09392020-03-27 12:38:10 +0100579 LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_SYNTAX, "Text value \"%.*s\" inside an any node \"%s\" found.",
580 xmlctx->value_len, xmlctx->value, snode->name);
Michal Vaskob36053d2020-03-26 15:49:30 +0100581 ret = LY_EVALID;
582 goto cleanup;
Radek Krejciee4cab22019-07-17 17:07:47 +0200583 }
Michal Vasko90932a92020-02-12 14:33:03 +0100584
Michal Vaskob36053d2020-03-26 15:49:30 +0100585 /* parser next */
586 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
587
Michal Vasko52927e22020-03-16 17:26:14 +0100588 /* parse any data tree with correct options */
Radek Krejci1798aae2020-07-14 13:26:06 +0200589 prev_opts = lydctx->parse_options;
590 lydctx->parse_options &= ~LYD_PARSE_STRICT;
591 lydctx->parse_options |= LYD_PARSE_OPAQ;
Michal Vasko52927e22020-03-16 17:26:14 +0100592 anchor = NULL;
Michal Vasko1bf09392020-03-27 12:38:10 +0100593 ret = lydxml_data_r(lydctx, NULL, &anchor);
Radek Krejci1798aae2020-07-14 13:26:06 +0200594 lydctx->parse_options = prev_opts;
Michal Vasko52927e22020-03-16 17:26:14 +0100595 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko90932a92020-02-12 14:33:03 +0100596
597 /* create node */
Michal Vasko52927e22020-03-16 17:26:14 +0100598 ret = lyd_create_any(snode, anchor, LYD_ANYDATA_DATATREE, &cur);
599 LY_CHECK_GOTO(ret, cleanup);
Radek Krejcie7b95092019-05-15 11:03:07 +0200600 }
Michal Vasko1bf09392020-03-27 12:38:10 +0100601 assert(cur);
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200602
Michal Vasko1bf09392020-03-27 12:38:10 +0100603 /* add/correct flags */
Michal Vasko52927e22020-03-16 17:26:14 +0100604 if (snode) {
Radek Krejci1798aae2020-07-14 13:26:06 +0200605 lyd_parse_set_data_flags(cur, &lydctx->when_check, &meta, lydctx->parse_options);
Michal Vasko8d544252020-03-02 10:19:52 +0100606 }
607
Michal Vasko52927e22020-03-16 17:26:14 +0100608 /* add metadata/attributes */
609 if (snode) {
Michal Vasko5ab0d5c2020-06-29 11:48:05 +0200610 LY_LIST_FOR(meta, m) {
611 m->parent = cur;
612 }
Michal Vasko52927e22020-03-16 17:26:14 +0100613 cur->meta = meta;
614 meta = NULL;
615 } else {
616 assert(!cur->schema);
Michal Vasko5ab0d5c2020-06-29 11:48:05 +0200617 LY_LIST_FOR(attr, a) {
618 a->parent = (struct lyd_node_opaq *)cur;
619 }
Michal Vasko52927e22020-03-16 17:26:14 +0100620 ((struct lyd_node_opaq *)cur)->attr = attr;
621 attr = NULL;
622 }
Radek Krejcib6f7ae52019-07-19 10:31:42 +0200623
Michal Vaskob104f112020-07-17 09:54:54 +0200624 /* insert, keep first pointer correct */
Michal Vaskob1b5c262020-03-05 14:29:47 +0100625 lyd_insert_node((struct lyd_node *)parent, first, cur);
Michal Vaskob104f112020-07-17 09:54:54 +0200626 while (!parent && (*first)->prev->next) {
627 *first = (*first)->prev;
628 }
Michal Vasko90932a92020-02-12 14:33:03 +0100629 cur = NULL;
Michal Vaskob36053d2020-03-26 15:49:30 +0100630
631 /* parser next */
632 assert(xmlctx->status == LYXML_ELEM_CLOSE);
633 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Radek Krejcie7b95092019-05-15 11:03:07 +0200634 }
635
Michal Vasko90932a92020-02-12 14:33:03 +0100636 /* success */
637 ret = LY_SUCCESS;
638
Radek Krejcie7b95092019-05-15 11:03:07 +0200639cleanup:
Michal Vasko3a41dff2020-07-15 14:30:28 +0200640 lyd_free_meta_siblings(meta);
641 ly_free_attr_siblings(ctx, attr);
Michal Vasko90932a92020-02-12 14:33:03 +0100642 lyd_free_tree(cur);
Michal Vaskob1b5c262020-03-05 14:29:47 +0100643 if (ret && *first) {
644 lyd_free_siblings(*first);
645 *first = NULL;
Michal Vasko90932a92020-02-12 14:33:03 +0100646 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200647 return ret;
648}
649
650LY_ERR
Radek Krejci1798aae2020-07-14 13:26:06 +0200651lyd_parse_xml_data(const struct ly_ctx *ctx, struct ly_in *in, int parse_options, int validate_options, struct lyd_node **tree_p, struct lyd_ctx **lydctx_p)
Radek Krejcie7b95092019-05-15 11:03:07 +0200652{
Radek Krejci18a57d92019-07-25 14:01:42 +0200653 LY_ERR ret = LY_SUCCESS;
Radek Krejci1798aae2020-07-14 13:26:06 +0200654 struct lyd_xml_ctx *lydctx;
Radek Krejcie7b95092019-05-15 11:03:07 +0200655
Radek Krejci7931b192020-06-25 17:05:03 +0200656 assert(!(parse_options & ~LYD_PARSE_OPTS_MASK));
657 assert(!(validate_options & ~LYD_VALIDATE_OPTS_MASK));
658
Radek Krejci1798aae2020-07-14 13:26:06 +0200659 /* init context */
660 lydctx = calloc(1, sizeof *lydctx);
661 LY_CHECK_ERR_RET(!lydctx, LOGMEM(ctx), LY_EMEM);
662 LY_CHECK_GOTO(ret = lyxml_ctx_new(ctx, in, &lydctx->xmlctx), cleanup);
663 lydctx->parse_options = parse_options;
664 lydctx->validate_options = validate_options;
665 lydctx->free = lyd_xml_ctx_free;
666 lydctx->resolve_prefix = lydxml_resolve_prefix;
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200667
Michal Vaskob1b5c262020-03-05 14:29:47 +0100668 /* parse XML data */
Radek Krejci1798aae2020-07-14 13:26:06 +0200669 LY_CHECK_GOTO(ret = lydxml_data_r(lydctx, NULL, tree_p), cleanup);
Michal Vaskocde73ac2019-11-14 16:10:27 +0100670
Michal Vaskocde73ac2019-11-14 16:10:27 +0100671cleanup:
Michal Vasko9b368d32020-02-14 13:53:31 +0100672 /* there should be no unresolved types stored */
Radek Krejci1798aae2020-07-14 13:26:06 +0200673 assert(!(parse_options & LYD_PARSE_ONLY) || (!lydctx->unres_node_type.count && !lydctx->unres_meta_type.count
674 && !lydctx->when_check.count));
Michal Vasko9b368d32020-02-14 13:53:31 +0100675
Michal Vasko9f96a052020-03-10 09:41:45 +0100676 if (ret) {
Radek Krejci1798aae2020-07-14 13:26:06 +0200677 lyd_xml_ctx_free((struct lyd_ctx *)lydctx);
678 lyd_free_all(*tree_p);
679 *tree_p = NULL;
680 } else {
681 *lydctx_p = (struct lyd_ctx *)lydctx;
Michal Vasko9f96a052020-03-10 09:41:45 +0100682 }
683 return ret;
684}
Michal Vasko1bf09392020-03-27 12:38:10 +0100685
686static LY_ERR
687lydxml_envelope(struct lyxml_ctx *xmlctx, const char *name, const char *uri, struct lyd_node **envp)
688{
689 LY_ERR ret = LY_SUCCESS;
690 const struct lyxml_ns *ns = NULL;
Radek Krejci1798aae2020-07-14 13:26:06 +0200691 struct lyd_attr *attr = NULL;
Michal Vasko1bf09392020-03-27 12:38:10 +0100692 const char *prefix;
693 size_t prefix_len;
694
695 *envp = NULL;
696
697 assert(xmlctx->status == LYXML_ELEMENT);
698 if (ly_strncmp(name, xmlctx->name, xmlctx->name_len)) {
699 /* not the expected element */
700 return LY_SUCCESS;
701 }
702
703 prefix = xmlctx->prefix;
704 prefix_len = xmlctx->prefix_len;
705 ns = lyxml_ns_get(xmlctx, prefix, prefix_len);
706 if (!ns) {
707 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".",
708 prefix_len, prefix);
709 return LY_EVALID;
710 } else if (strcmp(ns->uri, uri)) {
711 /* different namespace */
712 return LY_SUCCESS;
713 }
714
715 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
716
717 /* create attributes */
718 if (xmlctx->status == LYXML_ATTRIBUTE) {
719 LY_CHECK_RET(lydxml_attrs(xmlctx, &attr));
720 }
721
722 if (!xmlctx->ws_only) {
723 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_SYNTAX, "Unexpected value \"%.*s\" in the \"%s\" element.",
724 xmlctx->value_len, xmlctx->value, name);
725 ret = LY_EVALID;
726 goto cleanup;
727 }
728
729 /* parser next element */
730 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
731
732 /* create node */
Radek Krejci1798aae2020-07-14 13:26:06 +0200733 ret = lyd_create_opaq(xmlctx->ctx, name, strlen(name), "", 0, NULL, 0, LYD_XML, NULL, prefix, prefix_len,
734 uri, strlen(uri), envp);
Michal Vasko1bf09392020-03-27 12:38:10 +0100735 LY_CHECK_GOTO(ret, cleanup);
736
737 /* assign atributes */
738 ((struct lyd_node_opaq *)(*envp))->attr = attr;
739 attr = NULL;
740
741cleanup:
Michal Vasko3a41dff2020-07-15 14:30:28 +0200742 ly_free_attr_siblings(xmlctx->ctx, attr);
Michal Vasko1bf09392020-03-27 12:38:10 +0100743 return ret;
744}
745
746LY_ERR
Radek Krejci1798aae2020-07-14 13:26:06 +0200747lyd_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 +0100748{
749 LY_ERR ret = LY_SUCCESS;
750 struct lyd_xml_ctx lydctx = {0};
751 struct lyd_node *rpc_e = NULL, *act_e = NULL;
Radek Krejci1798aae2020-07-14 13:26:06 +0200752 struct lyd_node *tree = NULL;
Michal Vasko1bf09392020-03-27 12:38:10 +0100753
754 /* init */
Michal Vasko63f3d842020-07-08 10:10:14 +0200755 LY_CHECK_GOTO(ret = lyxml_ctx_new(ctx, in, &lydctx.xmlctx), cleanup);
Radek Krejci1798aae2020-07-14 13:26:06 +0200756 lydctx.parse_options = LYD_PARSE_ONLY | LYD_PARSE_STRICT;
Michal Vasko1bf09392020-03-27 12:38:10 +0100757 lydctx.int_opts = LYD_INTOPT_RPC;
Michal Vasko1bf09392020-03-27 12:38:10 +0100758
759 /* parse "rpc", if any */
760 LY_CHECK_GOTO(ret = lydxml_envelope(lydctx.xmlctx, "rpc", "urn:ietf:params:xml:ns:netconf:base:1.0", &rpc_e), cleanup);
761
762 if (rpc_e) {
763 /* parse "action", if any */
764 LY_CHECK_GOTO(ret = lydxml_envelope(lydctx.xmlctx, "action", "urn:ietf:params:xml:ns:yang:1", &act_e), cleanup);
765 }
766
767 /* parse the rest of data normally */
Radek Krejci1798aae2020-07-14 13:26:06 +0200768 LY_CHECK_GOTO(ret = lydxml_data_r(&lydctx, NULL, &tree), cleanup);
Michal Vasko1bf09392020-03-27 12:38:10 +0100769
770 /* make sure we have parsed some operation */
Radek Krejci1798aae2020-07-14 13:26:06 +0200771 if (!lydctx.op_node) {
Michal Vasko1bf09392020-03-27 12:38:10 +0100772 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_DATA, "Missing the \"rpc\"/\"action\" node.");
773 ret = LY_EVALID;
774 goto cleanup;
775 }
776
777 /* finish XML parsing and check operation type */
778 if (act_e) {
779 if (lydctx.xmlctx->status != LYXML_ELEM_CLOSE) {
780 assert(lydctx.xmlctx->status == LYXML_ELEMENT);
781 LOGVAL(ctx, LY_VLOG_LINE, &lydctx.xmlctx->line, LYVE_SYNTAX, "Unexpected sibling element \"%.*s\" of \"action\".",
782 lydctx.xmlctx->name_len, lydctx.xmlctx->name);
783 ret = LY_EVALID;
784 goto cleanup;
Radek Krejci1798aae2020-07-14 13:26:06 +0200785 } else if (lydctx.op_node->schema->nodetype != LYS_ACTION) {
786 LOGVAL(ctx, LY_VLOG_LYD, lydctx.op_node, LYVE_DATA, "Unexpected %s element, an \"action\" expected.",
787 lys_nodetype2str(lydctx.op_node->schema->nodetype));
Michal Vasko1bf09392020-03-27 12:38:10 +0100788 ret = LY_EVALID;
789 goto cleanup;
790 }
791 LY_CHECK_GOTO(ret = lyxml_ctx_next(lydctx.xmlctx), cleanup);
792 }
793 if (rpc_e) {
794 if (lydctx.xmlctx->status != LYXML_ELEM_CLOSE) {
795 assert(lydctx.xmlctx->status == LYXML_ELEMENT);
796 LOGVAL(ctx, LY_VLOG_LINE, &lydctx.xmlctx->line, LYVE_SYNTAX, "Unexpected sibling element \"%.*s\" of \"rpc\".",
797 lydctx.xmlctx->name_len, lydctx.xmlctx->name);
798 ret = LY_EVALID;
799 goto cleanup;
Radek Krejci1798aae2020-07-14 13:26:06 +0200800 } else if (!act_e && (lydctx.op_node->schema->nodetype != LYS_RPC)) {
801 LOGVAL(ctx, LY_VLOG_LYD, lydctx.op_node, LYVE_DATA, "Unexpected %s element, an \"rpc\" expected.",
802 lys_nodetype2str(lydctx.op_node->schema->nodetype));
Michal Vasko1bf09392020-03-27 12:38:10 +0100803 ret = LY_EVALID;
804 goto cleanup;
805 }
806 LY_CHECK_GOTO(ret = lyxml_ctx_next(lydctx.xmlctx), cleanup);
807 }
808
Radek Krejci1798aae2020-07-14 13:26:06 +0200809 if (op_p) {
810 *op_p = lydctx.op_node;
Michal Vaskocc048b22020-03-27 15:52:38 +0100811 }
Radek Krejci1798aae2020-07-14 13:26:06 +0200812 assert(tree);
813 if (tree_p) {
814 *tree_p = tree;
815 }
Michal Vasko1bf09392020-03-27 12:38:10 +0100816 if (act_e) {
817 /* connect to the action */
Radek Krejci1798aae2020-07-14 13:26:06 +0200818 lyd_insert_node(act_e, NULL, *tree_p);
819 if (tree_p) {
820 *tree_p = act_e;
821 }
Michal Vasko1bf09392020-03-27 12:38:10 +0100822 }
823 if (rpc_e) {
824 /* connect to the rpc */
Radek Krejci1798aae2020-07-14 13:26:06 +0200825 lyd_insert_node(rpc_e, NULL, *tree_p);
826 if (tree_p) {
827 *tree_p = rpc_e;
828 }
Michal Vasko1bf09392020-03-27 12:38:10 +0100829 }
830
831cleanup:
832 /* we have used parse_only flag */
833 assert(!lydctx.unres_node_type.count && !lydctx.unres_meta_type.count && !lydctx.when_check.count);
834 lyxml_ctx_free(lydctx.xmlctx);
835 if (ret) {
Radek Krejci1798aae2020-07-14 13:26:06 +0200836 lyd_free_all(tree);
Michal Vasko1bf09392020-03-27 12:38:10 +0100837 lyd_free_tree(act_e);
838 lyd_free_tree(rpc_e);
Michal Vasko1bf09392020-03-27 12:38:10 +0100839 }
840 return ret;
841}
Michal Vaskoa8edff02020-03-27 14:47:01 +0100842
843static LY_ERR
844lydxml_notif_envelope(struct lyxml_ctx *xmlctx, struct lyd_node **envp)
845{
846 LY_ERR ret = LY_SUCCESS;
847 const struct lyxml_ns *ns = NULL;
Radek Krejci1798aae2020-07-14 13:26:06 +0200848 struct lyd_attr *attr = NULL;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100849 struct lyd_node *et;
850 const char *prefix;
851 size_t prefix_len;
852
853 *envp = NULL;
854
855 /* container envelope */
856 LY_CHECK_GOTO(ret = lydxml_envelope(xmlctx, "notification", "urn:ietf:params:xml:ns:netconf:notification:1.0",
857 envp), cleanup);
858
859 /* no envelope, fine */
860 if (!*envp) {
861 goto cleanup;
862 }
863
864 /* child "eventTime" */
865 if ((xmlctx->status != LYXML_ELEMENT) || ly_strncmp("eventTime", xmlctx->name, xmlctx->name_len)) {
866 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Missing the \"eventTime\" element.");
867 ret = LY_EVALID;
868 goto cleanup;
869 }
870
871 prefix = xmlctx->prefix;
872 prefix_len = xmlctx->prefix_len;
873 ns = lyxml_ns_get(xmlctx, prefix, prefix_len);
874 if (!ns) {
875 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".",
876 prefix_len, prefix);
877 ret = LY_EVALID;
878 goto cleanup;
879 } else if (strcmp(ns->uri, "urn:ietf:params:xml:ns:netconf:notification:1.0")) {
880 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Invalid namespace \"%s\" of \"eventTime\".",
881 ns->uri);
882 ret = LY_EVALID;
883 goto cleanup;
884 }
885
886 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
887
888 /* create attributes */
889 if (xmlctx->status == LYXML_ATTRIBUTE) {
890 LY_CHECK_RET(lydxml_attrs(xmlctx, &attr));
891 }
892
893 /* validate value */
894 /* TODO */
895 /*if (!xmlctx->ws_only) {
896 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_SYNTAX, "Unexpected value \"%.*s\" in the \"%s\" element.",
897 xmlctx->value_len, xmlctx->value, name);
898 ret = LY_EVALID;
899 goto cleanup;
900 }*/
901
902 /* create node */
Radek Krejci1798aae2020-07-14 13:26:06 +0200903 ret = lyd_create_opaq(xmlctx->ctx, "eventTime", 9, xmlctx->value, xmlctx->value_len, NULL, 0, LYD_XML, NULL,
904 prefix, prefix_len, ns->uri, strlen(ns->uri), &et);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100905 LY_CHECK_GOTO(ret, cleanup);
906
907 /* assign atributes */
908 ((struct lyd_node_opaq *)et)->attr = attr;
909 attr = NULL;
910
911 /* insert */
912 lyd_insert_node(*envp, NULL, et);
913
914 /* finish parsing */
915 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
916 if (xmlctx->status != LYXML_ELEM_CLOSE) {
917 assert(xmlctx->status == LYXML_ELEMENT);
918 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_SYNTAX, "Unexpected sibling element \"%.*s\" of \"eventTime\".",
919 xmlctx->name_len, xmlctx->name);
920 ret = LY_EVALID;
921 goto cleanup;
922 }
923 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
924
925cleanup:
926 if (ret) {
927 lyd_free_tree(*envp);
Michal Vasko3a41dff2020-07-15 14:30:28 +0200928 ly_free_attr_siblings(xmlctx->ctx, attr);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100929 }
930 return ret;
931}
932
933LY_ERR
Radek Krejci1798aae2020-07-14 13:26:06 +0200934lyd_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 +0100935{
936 LY_ERR ret = LY_SUCCESS;
937 struct lyd_xml_ctx lydctx = {0};
938 struct lyd_node *ntf_e = NULL;
Radek Krejci1798aae2020-07-14 13:26:06 +0200939 struct lyd_node *tree = NULL;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100940
941 /* init */
Michal Vasko63f3d842020-07-08 10:10:14 +0200942 LY_CHECK_GOTO(ret = lyxml_ctx_new(ctx, in, &lydctx.xmlctx), cleanup);
Radek Krejci1798aae2020-07-14 13:26:06 +0200943 lydctx.parse_options = LYD_PARSE_ONLY | LYD_PARSE_STRICT;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100944 lydctx.int_opts = LYD_INTOPT_NOTIF;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100945
946 /* parse "notification" and "eventTime", if present */
947 LY_CHECK_GOTO(ret = lydxml_notif_envelope(lydctx.xmlctx, &ntf_e), cleanup);
948
949 /* parse the rest of data normally */
Radek Krejci1798aae2020-07-14 13:26:06 +0200950 LY_CHECK_GOTO(ret = lydxml_data_r(&lydctx, NULL, &tree), cleanup);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100951
952 /* make sure we have parsed some notification */
Radek Krejci1798aae2020-07-14 13:26:06 +0200953 if (!lydctx.op_node) {
Michal Vaskoa8edff02020-03-27 14:47:01 +0100954 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_DATA, "Missing the \"notification\" node.");
955 ret = LY_EVALID;
956 goto cleanup;
957 }
958
959 /* finish XML parsing */
960 if (ntf_e) {
961 if (lydctx.xmlctx->status != LYXML_ELEM_CLOSE) {
962 assert(lydctx.xmlctx->status == LYXML_ELEMENT);
963 LOGVAL(ctx, LY_VLOG_LINE, &lydctx.xmlctx->line, LYVE_SYNTAX, "Unexpected sibling element \"%.*s\" of \"notification\".",
964 lydctx.xmlctx->name_len, lydctx.xmlctx->name);
965 ret = LY_EVALID;
966 goto cleanup;
967 }
968 LY_CHECK_GOTO(ret = lyxml_ctx_next(lydctx.xmlctx), cleanup);
969 }
970
Radek Krejci1798aae2020-07-14 13:26:06 +0200971 if (ntf_p) {
972 *ntf_p = lydctx.op_node;
Michal Vaskocc048b22020-03-27 15:52:38 +0100973 }
Radek Krejci1798aae2020-07-14 13:26:06 +0200974 assert(tree);
975 if (tree_p) {
976 *tree_p = tree;
977 }
Michal Vaskoa8edff02020-03-27 14:47:01 +0100978 if (ntf_e) {
979 /* connect to the notification */
Radek Krejci1798aae2020-07-14 13:26:06 +0200980 lyd_insert_node(ntf_e, NULL, *tree_p);
981 if (tree_p) {
982 *tree_p = ntf_e;
983 }
Michal Vaskoa8edff02020-03-27 14:47:01 +0100984 }
985
986cleanup:
987 /* we have used parse_only flag */
988 assert(!lydctx.unres_node_type.count && !lydctx.unres_meta_type.count && !lydctx.when_check.count);
989 lyxml_ctx_free(lydctx.xmlctx);
990 if (ret) {
Radek Krejci1798aae2020-07-14 13:26:06 +0200991 lyd_free_all(tree);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100992 lyd_free_tree(ntf_e);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100993 }
994 return ret;
995}
Michal Vasko1ce933a2020-03-30 12:38:22 +0200996
997LY_ERR
Radek Krejci1798aae2020-07-14 13:26:06 +0200998lyd_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 +0200999{
1000 LY_ERR ret = LY_SUCCESS;
1001 struct lyd_xml_ctx lydctx = {0};
Radek Krejcib1247842020-07-02 16:22:38 +02001002 struct lyd_node *rpcr_e = NULL, *iter, *req_op, *rep_op = NULL;
Michal Vasko1ce933a2020-03-30 12:38:22 +02001003
1004 /* init */
Michal Vasko63f3d842020-07-08 10:10:14 +02001005 LY_CHECK_GOTO(ret = lyxml_ctx_new(LYD_NODE_CTX(request), in, &lydctx.xmlctx), cleanup);
Radek Krejci1798aae2020-07-14 13:26:06 +02001006 lydctx.parse_options = LYD_PARSE_ONLY | LYD_PARSE_STRICT;
Michal Vasko1ce933a2020-03-30 12:38:22 +02001007 lydctx.int_opts = LYD_INTOPT_REPLY;
Michal Vasko1ce933a2020-03-30 12:38:22 +02001008
1009 /* find request OP */
Michal Vasko56daf732020-08-10 10:57:18 +02001010 LYD_TREE_DFS_BEGIN((struct lyd_node *)request, req_op) {
Michal Vasko1ce933a2020-03-30 12:38:22 +02001011 if (req_op->schema->nodetype & (LYS_RPC | LYS_ACTION)) {
1012 break;
1013 }
Michal Vasko56daf732020-08-10 10:57:18 +02001014 LYD_TREE_DFS_END(request, req_op);
Michal Vasko1ce933a2020-03-30 12:38:22 +02001015 }
1016 if (!(req_op->schema->nodetype & (LYS_RPC | LYS_ACTION))) {
1017 LOGERR(LYD_NODE_CTX(request), LY_EINVAL, "No RPC/action in the request found.");
1018 ret = LY_EINVAL;
1019 goto cleanup;
1020 }
1021
1022 /* duplicate request OP with parents */
Michal Vasko3a41dff2020-07-15 14:30:28 +02001023 LY_CHECK_GOTO(ret = lyd_dup_single(req_op, NULL, LYD_DUP_WITH_PARENTS, &rep_op), cleanup);
Michal Vasko1ce933a2020-03-30 12:38:22 +02001024
1025 /* parse "rpc-reply", if any */
Michal Vasko3a41dff2020-07-15 14:30:28 +02001026 LY_CHECK_GOTO(ret = lydxml_envelope(lydctx.xmlctx, "rpc-reply", "urn:ietf:params:xml:ns:netconf:base:1.0", &rpcr_e),
1027 cleanup);
Michal Vasko1ce933a2020-03-30 12:38:22 +02001028
1029 /* parse the rest of data normally but connect them to the duplicated operation */
1030 LY_CHECK_GOTO(ret = lydxml_data_r(&lydctx, (struct lyd_node_inner *)rep_op, lyd_node_children_p(rep_op)), cleanup);
1031
1032 /* finish XML parsing and check operation type */
1033 if (rpcr_e) {
1034 if (lydctx.xmlctx->status != LYXML_ELEM_CLOSE) {
1035 assert(lydctx.xmlctx->status == LYXML_ELEMENT);
1036 LOGVAL(LYD_NODE_CTX(request), LY_VLOG_LINE, &lydctx.xmlctx->line, LYVE_SYNTAX,
1037 "Unexpected sibling element \"%.*s\" of \"rpc-reply\".", lydctx.xmlctx->name_len, lydctx.xmlctx->name);
1038 ret = LY_EVALID;
1039 goto cleanup;
1040 }
1041 LY_CHECK_GOTO(ret = lyxml_ctx_next(lydctx.xmlctx), cleanup);
1042 }
1043
Radek Krejci1798aae2020-07-14 13:26:06 +02001044 if (op_p) {
1045 *op_p = rep_op;
Michal Vasko1ce933a2020-03-30 12:38:22 +02001046 }
1047 for (iter = rep_op; iter->parent; iter = (struct lyd_node *)iter->parent);
Radek Krejci1798aae2020-07-14 13:26:06 +02001048 if (tree_p) {
1049 *tree_p = iter;
1050 }
Michal Vasko1ce933a2020-03-30 12:38:22 +02001051 if (rpcr_e) {
1052 /* connect to the operation */
Radek Krejci1798aae2020-07-14 13:26:06 +02001053 lyd_insert_node(rpcr_e, NULL, *tree_p);
1054 if (tree_p) {
1055 *tree_p = rpcr_e;
1056 }
Michal Vasko1ce933a2020-03-30 12:38:22 +02001057 }
1058
1059cleanup:
1060 /* we have used parse_only flag */
1061 assert(!lydctx.unres_node_type.count && !lydctx.unres_meta_type.count && !lydctx.when_check.count);
1062 lyxml_ctx_free(lydctx.xmlctx);
1063 if (ret) {
1064 lyd_free_all(rep_op);
1065 lyd_free_tree(rpcr_e);
1066 }
1067 return ret;
1068}