blob: c4bfb53849eeaa7180cbbae1c6ebd005fa675646 [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 Vaskoa5da3292020-08-12 13:10:50 +0200380 * @brief Parse XML subtree.
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 Vaskoa5da3292020-08-12 13:10:50 +0200388lydxml_subtree_r(struct lyd_xml_ctx *lydctx, struct lyd_node_inner *parent, struct lyd_node **first_p)
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 Vaskoa5da3292020-08-12 13:10:50 +0200396 struct lyd_meta *meta = NULL;
397 struct lyd_attr *attr = NULL;
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 Vaskoa5da3292020-08-12 13:10:50 +0200401 struct lyd_node *node = NULL, *anchor;
Michal Vasko52927e22020-03-16 17:26:14 +0100402 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 Vaskoa5da3292020-08-12 13:10:50 +0200410 assert(xmlctx->status == LYXML_ELEMENT);
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200411
Michal Vaskoa5da3292020-08-12 13:10:50 +0200412 /* remember element prefix and name */
413 prefix = xmlctx->prefix;
414 prefix_len = xmlctx->prefix_len;
415 name = xmlctx->name;
416 name_len = xmlctx->name_len;
417
418 /* get the element module */
419 ns = lyxml_ns_get(xmlctx, prefix, prefix_len);
420 if (!ns) {
421 LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".",
422 prefix_len, prefix);
423 ret = LY_EVALID;
424 goto error;
425 }
426 mod = ly_ctx_get_module_implemented_ns(ctx, ns->uri);
427 if (!mod) {
428 if (lydctx->parse_options & LYD_PARSE_STRICT) {
429 LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "No module with namespace \"%s\" in the context.",
430 ns->uri);
Michal Vasko90932a92020-02-12 14:33:03 +0100431 ret = LY_EVALID;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200432 goto error;
Radek Krejcie7b95092019-05-15 11:03:07 +0200433 }
Michal Vaskoa5da3292020-08-12 13:10:50 +0200434 if (!(lydctx->parse_options & LYD_PARSE_OPAQ)) {
435 /* skip element with children */
436 LY_CHECK_GOTO(ret = lydxml_data_skip(xmlctx), error);
437 return LY_SUCCESS;
Radek Krejcie7b95092019-05-15 11:03:07 +0200438 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200439 }
440
Michal Vaskoa5da3292020-08-12 13:10:50 +0200441 /* parser next */
442 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
Michal Vasko90932a92020-02-12 14:33:03 +0100443
Michal Vaskoa5da3292020-08-12 13:10:50 +0200444 /* get the schema node */
445 snode = NULL;
446 if (mod && (!parent || parent->schema)) {
447 snode = lys_find_child(parent ? parent->schema : NULL, mod, name, name_len, 0, getnext_opts);
448 if (!snode) {
449 if (lydctx->parse_options & LYD_PARSE_STRICT) {
450 LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Element \"%.*s\" not found in the \"%s\" module.",
451 name_len, name, mod->name);
452 ret = LY_EVALID;
453 goto error;
454 } else if (!(lydctx->parse_options & LYD_PARSE_OPAQ)) {
455 /* skip element with children */
456 LY_CHECK_GOTO(ret = lydxml_data_skip(xmlctx), error);
457 return LY_SUCCESS;
458 }
459 } else {
460 /* check that schema node is valid and can be used */
461 LY_CHECK_GOTO(ret = lyd_parser_check_schema((struct lyd_ctx *)lydctx, snode), error);
462 LY_CHECK_GOTO(ret = lydxml_data_check_opaq(lydctx, &snode), error);
463 }
464 }
465
466 /* create metadata/attributes */
467 if (xmlctx->status == LYXML_ATTRIBUTE) {
468 if (snode) {
469 ret = lydxml_metadata(lydctx, snode, &meta);
470 LY_CHECK_GOTO(ret, error);
471 } else {
472 assert(lydctx->parse_options & LYD_PARSE_OPAQ);
473 ret = lydxml_attrs(xmlctx, &attr);
474 LY_CHECK_GOTO(ret, error);
475 }
476 }
477
478 assert(xmlctx->status == LYXML_ELEM_CONTENT);
479 if (!snode) {
480 assert(lydctx->parse_options & LYD_PARSE_OPAQ);
481
482 if (xmlctx->ws_only) {
483 /* ignore WS-only value */
484 xmlctx->value_len = 0;
485 val_prefs = NULL;
486 } else {
487 /* get value prefixes */
488 ret = lyxml_get_prefixes(xmlctx, xmlctx->value, xmlctx->value_len, &val_prefs);
489 LY_CHECK_GOTO(ret, error);
490 }
491
492 /* create node */
493 ret = lyd_create_opaq(ctx, name, name_len, xmlctx->value, xmlctx->value_len, &xmlctx->dynamic, 0, LYD_XML,
494 val_prefs, prefix, prefix_len, ns->uri, strlen(ns->uri), &node);
495 LY_CHECK_GOTO(ret, error);
496
497 /* parser next */
498 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
499
500 /* process children */
501 while (xmlctx->status == LYXML_ELEMENT) {
502 ret = lydxml_subtree_r(lydctx, (struct lyd_node_inner *)node, lyd_node_children_p(node));
503 LY_CHECK_GOTO(ret, error);
504 }
505 } else if (snode->nodetype & LYD_NODE_TERM) {
506 /* create node */
507 LY_CHECK_GOTO(ret = lyd_parser_create_term((struct lyd_ctx*)lydctx, snode, xmlctx->value, xmlctx->value_len,
508 &xmlctx->dynamic, 0, lydxml_resolve_prefix, xmlctx, LYD_XML, &node), error);
509
510 if (parent && (node->schema->flags & LYS_KEY)) {
511 /* check the key order, the anchor must never be a key */
512 anchor = lyd_insert_get_next_anchor(parent->child, node);
513 if (anchor && (anchor->schema->flags & LYS_KEY)) {
514 if (lydctx->parse_options & LYD_PARSE_STRICT) {
515 LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_DATA, "Invalid position of the key \"%s\" in a list.",
516 node->schema->name);
517 ret = LY_EVALID;
518 goto error;
519 } else {
520 LOGWRN(ctx, "Invalid position of the key \"%s\" in a list.", node->schema->name);
521 }
522 }
523 }
524
525 /* parser next */
526 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
527
528 /* no children expected */
529 if (xmlctx->status == LYXML_ELEMENT) {
530 LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_SYNTAX, "Child element \"%.*s\" inside a terminal node \"%s\" found.",
531 xmlctx->name_len, xmlctx->name, snode->name);
532 ret = LY_EVALID;
533 goto error;
534 }
535 } else if (snode->nodetype & LYD_NODE_INNER) {
536 if (!xmlctx->ws_only) {
537 /* value in inner node */
538 LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_SYNTAX, "Text value \"%.*s\" inside an inner node \"%s\" found.",
539 xmlctx->value_len, xmlctx->value, snode->name);
540 ret = LY_EVALID;
541 goto error;
542 }
543
544 /* create node */
545 ret = lyd_create_inner(snode, &node);
546 LY_CHECK_GOTO(ret, error);
547
548 /* parser next */
549 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
550
551 /* process children */
552 while (xmlctx->status == LYXML_ELEMENT) {
553 ret = lydxml_subtree_r(lydctx, (struct lyd_node_inner *)node, lyd_node_children_p(node));
554 LY_CHECK_GOTO(ret, error);
555 }
556
557 if (snode->nodetype == LYS_LIST) {
558 /* check all keys exist */
559 LY_CHECK_GOTO(ret = lyd_parse_check_keys(node), error);
560 }
561
562 if (!(lydctx->parse_options & LYD_PARSE_ONLY)) {
563 /* new node validation, autodelete CANNOT occur, all nodes are new */
564 ret = lyd_validate_new(lyd_node_children_p(node), snode, NULL, NULL);
565 LY_CHECK_GOTO(ret, error);
566
567 /* add any missing default children */
568 ret = lyd_new_implicit_r(node, lyd_node_children_p(node), NULL, NULL, &lydctx->unres_node_type, &lydctx->when_check,
569 (lydctx->validate_options & LYD_VALIDATE_NO_STATE) ? LYD_IMPLICIT_NO_STATE : 0, NULL);
570 LY_CHECK_GOTO(ret, error);
571 }
572
573 if (snode->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) {
574 /* rememeber the RPC/action/notification */
575 lydctx->op_node = node;
576 }
577 } else if (snode->nodetype & LYD_NODE_ANY) {
578 if (!xmlctx->ws_only) {
579 /* value in inner node */
580 LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_SYNTAX, "Text value \"%.*s\" inside an any node \"%s\" found.",
581 xmlctx->value_len, xmlctx->value, snode->name);
582 ret = LY_EVALID;
583 goto error;
584 }
585
586 /* parser next */
587 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
588
589 /* parse any data tree with correct options */
590 prev_opts = lydctx->parse_options;
591 lydctx->parse_options &= ~LYD_PARSE_STRICT;
592 lydctx->parse_options |= LYD_PARSE_OPAQ;
593 anchor = NULL;
594 while (xmlctx->status == LYXML_ELEMENT) {
595 ret = lydxml_subtree_r(lydctx, NULL, &anchor);
596 LY_CHECK_ERR_GOTO(ret, lydctx->parse_options = prev_opts, error);
597 }
598 lydctx->parse_options = prev_opts;
599
600 /* create node */
601 ret = lyd_create_any(snode, anchor, LYD_ANYDATA_DATATREE, &node);
602 LY_CHECK_GOTO(ret, error);
603 }
604 assert(node);
605
606 /* add/correct flags */
607 if (snode) {
608 lyd_parse_set_data_flags(node, &lydctx->when_check, &meta, lydctx->parse_options);
609 }
610
611 /* parser next */
612 assert(xmlctx->status == LYXML_ELEM_CLOSE);
613 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
614
615 /* add metadata/attributes */
616 if (snode) {
617 lyd_insert_meta(node, meta);
618 } else {
619 lyd_insert_attr(node, attr);
620 }
621
622 /* insert, keep first pointer correct */
623 lyd_insert_node((struct lyd_node *)parent, first_p, node);
624 while (!parent && (*first_p)->prev->next) {
625 *first_p = (*first_p)->prev;
626 }
627
628 return LY_SUCCESS;
629
630error:
Michal Vasko3a41dff2020-07-15 14:30:28 +0200631 lyd_free_meta_siblings(meta);
632 ly_free_attr_siblings(ctx, attr);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200633 lyd_free_tree(node);
Radek Krejcie7b95092019-05-15 11:03:07 +0200634 return ret;
635}
636
637LY_ERR
Michal Vaskoa5da3292020-08-12 13:10:50 +0200638lyd_parse_xml_data(const struct ly_ctx *ctx, struct ly_in *in, int parse_options, int validate_options,
639 struct lyd_node **tree_p, struct lyd_ctx **lydctx_p)
Radek Krejcie7b95092019-05-15 11:03:07 +0200640{
Radek Krejci18a57d92019-07-25 14:01:42 +0200641 LY_ERR ret = LY_SUCCESS;
Radek Krejci1798aae2020-07-14 13:26:06 +0200642 struct lyd_xml_ctx *lydctx;
Radek Krejcie7b95092019-05-15 11:03:07 +0200643
Radek Krejci7931b192020-06-25 17:05:03 +0200644 assert(!(parse_options & ~LYD_PARSE_OPTS_MASK));
645 assert(!(validate_options & ~LYD_VALIDATE_OPTS_MASK));
646
Radek Krejci1798aae2020-07-14 13:26:06 +0200647 /* init context */
648 lydctx = calloc(1, sizeof *lydctx);
649 LY_CHECK_ERR_RET(!lydctx, LOGMEM(ctx), LY_EMEM);
650 LY_CHECK_GOTO(ret = lyxml_ctx_new(ctx, in, &lydctx->xmlctx), cleanup);
651 lydctx->parse_options = parse_options;
652 lydctx->validate_options = validate_options;
653 lydctx->free = lyd_xml_ctx_free;
654 lydctx->resolve_prefix = lydxml_resolve_prefix;
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200655
Michal Vaskob1b5c262020-03-05 14:29:47 +0100656 /* parse XML data */
Michal Vaskoa5da3292020-08-12 13:10:50 +0200657 while (lydctx->xmlctx->status == LYXML_ELEMENT) {
658 LY_CHECK_GOTO(ret = lydxml_subtree_r(lydctx, NULL, tree_p), cleanup);
659 }
Michal Vaskocde73ac2019-11-14 16:10:27 +0100660
Michal Vaskocde73ac2019-11-14 16:10:27 +0100661cleanup:
Michal Vasko9b368d32020-02-14 13:53:31 +0100662 /* there should be no unresolved types stored */
Radek Krejci1798aae2020-07-14 13:26:06 +0200663 assert(!(parse_options & LYD_PARSE_ONLY) || (!lydctx->unres_node_type.count && !lydctx->unres_meta_type.count
664 && !lydctx->when_check.count));
Michal Vasko9b368d32020-02-14 13:53:31 +0100665
Michal Vasko9f96a052020-03-10 09:41:45 +0100666 if (ret) {
Radek Krejci1798aae2020-07-14 13:26:06 +0200667 lyd_xml_ctx_free((struct lyd_ctx *)lydctx);
668 lyd_free_all(*tree_p);
669 *tree_p = NULL;
670 } else {
671 *lydctx_p = (struct lyd_ctx *)lydctx;
Michal Vasko9f96a052020-03-10 09:41:45 +0100672 }
673 return ret;
674}
Michal Vasko1bf09392020-03-27 12:38:10 +0100675
676static LY_ERR
677lydxml_envelope(struct lyxml_ctx *xmlctx, const char *name, const char *uri, struct lyd_node **envp)
678{
679 LY_ERR ret = LY_SUCCESS;
680 const struct lyxml_ns *ns = NULL;
Radek Krejci1798aae2020-07-14 13:26:06 +0200681 struct lyd_attr *attr = NULL;
Michal Vasko1bf09392020-03-27 12:38:10 +0100682 const char *prefix;
683 size_t prefix_len;
684
685 *envp = NULL;
686
687 assert(xmlctx->status == LYXML_ELEMENT);
688 if (ly_strncmp(name, xmlctx->name, xmlctx->name_len)) {
689 /* not the expected element */
690 return LY_SUCCESS;
691 }
692
693 prefix = xmlctx->prefix;
694 prefix_len = xmlctx->prefix_len;
695 ns = lyxml_ns_get(xmlctx, prefix, prefix_len);
696 if (!ns) {
697 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".",
698 prefix_len, prefix);
699 return LY_EVALID;
700 } else if (strcmp(ns->uri, uri)) {
701 /* different namespace */
702 return LY_SUCCESS;
703 }
704
705 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
706
707 /* create attributes */
708 if (xmlctx->status == LYXML_ATTRIBUTE) {
709 LY_CHECK_RET(lydxml_attrs(xmlctx, &attr));
710 }
711
712 if (!xmlctx->ws_only) {
713 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_SYNTAX, "Unexpected value \"%.*s\" in the \"%s\" element.",
714 xmlctx->value_len, xmlctx->value, name);
715 ret = LY_EVALID;
716 goto cleanup;
717 }
718
719 /* parser next element */
720 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
721
722 /* create node */
Radek Krejci1798aae2020-07-14 13:26:06 +0200723 ret = lyd_create_opaq(xmlctx->ctx, name, strlen(name), "", 0, NULL, 0, LYD_XML, NULL, prefix, prefix_len,
724 uri, strlen(uri), envp);
Michal Vasko1bf09392020-03-27 12:38:10 +0100725 LY_CHECK_GOTO(ret, cleanup);
726
727 /* assign atributes */
728 ((struct lyd_node_opaq *)(*envp))->attr = attr;
729 attr = NULL;
730
731cleanup:
Michal Vasko3a41dff2020-07-15 14:30:28 +0200732 ly_free_attr_siblings(xmlctx->ctx, attr);
Michal Vasko1bf09392020-03-27 12:38:10 +0100733 return ret;
734}
735
736LY_ERR
Radek Krejci1798aae2020-07-14 13:26:06 +0200737lyd_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 +0100738{
739 LY_ERR ret = LY_SUCCESS;
740 struct lyd_xml_ctx lydctx = {0};
741 struct lyd_node *rpc_e = NULL, *act_e = NULL;
Radek Krejci1798aae2020-07-14 13:26:06 +0200742 struct lyd_node *tree = NULL;
Michal Vasko1bf09392020-03-27 12:38:10 +0100743
744 /* init */
Michal Vasko63f3d842020-07-08 10:10:14 +0200745 LY_CHECK_GOTO(ret = lyxml_ctx_new(ctx, in, &lydctx.xmlctx), cleanup);
Radek Krejci1798aae2020-07-14 13:26:06 +0200746 lydctx.parse_options = LYD_PARSE_ONLY | LYD_PARSE_STRICT;
Michal Vasko1bf09392020-03-27 12:38:10 +0100747 lydctx.int_opts = LYD_INTOPT_RPC;
Michal Vasko1bf09392020-03-27 12:38:10 +0100748
749 /* parse "rpc", if any */
750 LY_CHECK_GOTO(ret = lydxml_envelope(lydctx.xmlctx, "rpc", "urn:ietf:params:xml:ns:netconf:base:1.0", &rpc_e), cleanup);
751
752 if (rpc_e) {
753 /* parse "action", if any */
754 LY_CHECK_GOTO(ret = lydxml_envelope(lydctx.xmlctx, "action", "urn:ietf:params:xml:ns:yang:1", &act_e), cleanup);
755 }
756
757 /* parse the rest of data normally */
Michal Vaskocf770e22020-08-12 13:21:43 +0200758 LY_CHECK_GOTO(ret = lydxml_subtree_r(&lydctx, NULL, &tree), cleanup);
Michal Vasko1bf09392020-03-27 12:38:10 +0100759
Michal Vaskocf770e22020-08-12 13:21:43 +0200760 /* make sure we have parsed some operation and it is the only subtree */
Radek Krejci1798aae2020-07-14 13:26:06 +0200761 if (!lydctx.op_node) {
Michal Vasko1bf09392020-03-27 12:38:10 +0100762 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_DATA, "Missing the \"rpc\"/\"action\" node.");
763 ret = LY_EVALID;
764 goto cleanup;
Michal Vaskocf770e22020-08-12 13:21:43 +0200765 } else if (lydctx.xmlctx->status == LYXML_ELEMENT) {
766 LOGVAL(ctx, LY_VLOG_LINE, &lydctx.xmlctx->line, LYVE_SYNTAX, "Unexpected sibling element of \"%s\".",
767 tree->schema->name);
768 ret = LY_EVALID;
769 goto cleanup;
Michal Vasko1bf09392020-03-27 12:38:10 +0100770 }
771
772 /* finish XML parsing and check operation type */
773 if (act_e) {
774 if (lydctx.xmlctx->status != LYXML_ELEM_CLOSE) {
775 assert(lydctx.xmlctx->status == LYXML_ELEMENT);
776 LOGVAL(ctx, LY_VLOG_LINE, &lydctx.xmlctx->line, LYVE_SYNTAX, "Unexpected sibling element \"%.*s\" of \"action\".",
777 lydctx.xmlctx->name_len, lydctx.xmlctx->name);
778 ret = LY_EVALID;
779 goto cleanup;
Radek Krejci1798aae2020-07-14 13:26:06 +0200780 } else if (lydctx.op_node->schema->nodetype != LYS_ACTION) {
781 LOGVAL(ctx, LY_VLOG_LYD, lydctx.op_node, LYVE_DATA, "Unexpected %s element, an \"action\" expected.",
782 lys_nodetype2str(lydctx.op_node->schema->nodetype));
Michal Vasko1bf09392020-03-27 12:38:10 +0100783 ret = LY_EVALID;
784 goto cleanup;
785 }
786 LY_CHECK_GOTO(ret = lyxml_ctx_next(lydctx.xmlctx), cleanup);
787 }
788 if (rpc_e) {
789 if (lydctx.xmlctx->status != LYXML_ELEM_CLOSE) {
790 assert(lydctx.xmlctx->status == LYXML_ELEMENT);
791 LOGVAL(ctx, LY_VLOG_LINE, &lydctx.xmlctx->line, LYVE_SYNTAX, "Unexpected sibling element \"%.*s\" of \"rpc\".",
792 lydctx.xmlctx->name_len, lydctx.xmlctx->name);
793 ret = LY_EVALID;
794 goto cleanup;
Radek Krejci1798aae2020-07-14 13:26:06 +0200795 } else if (!act_e && (lydctx.op_node->schema->nodetype != LYS_RPC)) {
796 LOGVAL(ctx, LY_VLOG_LYD, lydctx.op_node, LYVE_DATA, "Unexpected %s element, an \"rpc\" expected.",
797 lys_nodetype2str(lydctx.op_node->schema->nodetype));
Michal Vasko1bf09392020-03-27 12:38:10 +0100798 ret = LY_EVALID;
799 goto cleanup;
800 }
801 LY_CHECK_GOTO(ret = lyxml_ctx_next(lydctx.xmlctx), cleanup);
802 }
803
Radek Krejci1798aae2020-07-14 13:26:06 +0200804 if (op_p) {
805 *op_p = lydctx.op_node;
Michal Vaskocc048b22020-03-27 15:52:38 +0100806 }
Radek Krejci1798aae2020-07-14 13:26:06 +0200807 assert(tree);
Michal Vasko1bf09392020-03-27 12:38:10 +0100808 if (act_e) {
809 /* connect to the action */
Michal Vasko4189c0f2020-08-13 09:05:22 +0200810 lyd_insert_node(act_e, NULL, tree);
811 tree = act_e;
Michal Vasko1bf09392020-03-27 12:38:10 +0100812 }
813 if (rpc_e) {
814 /* connect to the rpc */
Michal Vasko4189c0f2020-08-13 09:05:22 +0200815 lyd_insert_node(rpc_e, NULL, tree);
816 tree = rpc_e;
817 }
818 if (tree_p) {
819 *tree_p = tree;
Michal Vasko1bf09392020-03-27 12:38:10 +0100820 }
821
822cleanup:
823 /* we have used parse_only flag */
824 assert(!lydctx.unres_node_type.count && !lydctx.unres_meta_type.count && !lydctx.when_check.count);
825 lyxml_ctx_free(lydctx.xmlctx);
826 if (ret) {
Radek Krejci1798aae2020-07-14 13:26:06 +0200827 lyd_free_all(tree);
Michal Vasko1bf09392020-03-27 12:38:10 +0100828 lyd_free_tree(act_e);
829 lyd_free_tree(rpc_e);
Michal Vasko1bf09392020-03-27 12:38:10 +0100830 }
831 return ret;
832}
Michal Vaskoa8edff02020-03-27 14:47:01 +0100833
834static LY_ERR
835lydxml_notif_envelope(struct lyxml_ctx *xmlctx, struct lyd_node **envp)
836{
837 LY_ERR ret = LY_SUCCESS;
838 const struct lyxml_ns *ns = NULL;
Radek Krejci1798aae2020-07-14 13:26:06 +0200839 struct lyd_attr *attr = NULL;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100840 struct lyd_node *et;
841 const char *prefix;
842 size_t prefix_len;
843
844 *envp = NULL;
845
846 /* container envelope */
847 LY_CHECK_GOTO(ret = lydxml_envelope(xmlctx, "notification", "urn:ietf:params:xml:ns:netconf:notification:1.0",
848 envp), cleanup);
849
850 /* no envelope, fine */
851 if (!*envp) {
852 goto cleanup;
853 }
854
855 /* child "eventTime" */
856 if ((xmlctx->status != LYXML_ELEMENT) || ly_strncmp("eventTime", xmlctx->name, xmlctx->name_len)) {
857 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Missing the \"eventTime\" element.");
858 ret = LY_EVALID;
859 goto cleanup;
860 }
861
862 prefix = xmlctx->prefix;
863 prefix_len = xmlctx->prefix_len;
864 ns = lyxml_ns_get(xmlctx, prefix, prefix_len);
865 if (!ns) {
866 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".",
867 prefix_len, prefix);
868 ret = LY_EVALID;
869 goto cleanup;
870 } else if (strcmp(ns->uri, "urn:ietf:params:xml:ns:netconf:notification:1.0")) {
871 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Invalid namespace \"%s\" of \"eventTime\".",
872 ns->uri);
873 ret = LY_EVALID;
874 goto cleanup;
875 }
876
877 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
878
879 /* create attributes */
880 if (xmlctx->status == LYXML_ATTRIBUTE) {
881 LY_CHECK_RET(lydxml_attrs(xmlctx, &attr));
882 }
883
884 /* validate value */
885 /* TODO */
886 /*if (!xmlctx->ws_only) {
887 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_SYNTAX, "Unexpected value \"%.*s\" in the \"%s\" element.",
888 xmlctx->value_len, xmlctx->value, name);
889 ret = LY_EVALID;
890 goto cleanup;
891 }*/
892
893 /* create node */
Radek Krejci1798aae2020-07-14 13:26:06 +0200894 ret = lyd_create_opaq(xmlctx->ctx, "eventTime", 9, xmlctx->value, xmlctx->value_len, NULL, 0, LYD_XML, NULL,
895 prefix, prefix_len, ns->uri, strlen(ns->uri), &et);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100896 LY_CHECK_GOTO(ret, cleanup);
897
898 /* assign atributes */
899 ((struct lyd_node_opaq *)et)->attr = attr;
900 attr = NULL;
901
902 /* insert */
903 lyd_insert_node(*envp, NULL, et);
904
905 /* finish parsing */
906 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
907 if (xmlctx->status != LYXML_ELEM_CLOSE) {
908 assert(xmlctx->status == LYXML_ELEMENT);
909 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_SYNTAX, "Unexpected sibling element \"%.*s\" of \"eventTime\".",
910 xmlctx->name_len, xmlctx->name);
911 ret = LY_EVALID;
912 goto cleanup;
913 }
914 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
915
916cleanup:
917 if (ret) {
918 lyd_free_tree(*envp);
Michal Vasko3a41dff2020-07-15 14:30:28 +0200919 ly_free_attr_siblings(xmlctx->ctx, attr);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100920 }
921 return ret;
922}
923
924LY_ERR
Radek Krejci1798aae2020-07-14 13:26:06 +0200925lyd_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 +0100926{
927 LY_ERR ret = LY_SUCCESS;
928 struct lyd_xml_ctx lydctx = {0};
929 struct lyd_node *ntf_e = NULL;
Radek Krejci1798aae2020-07-14 13:26:06 +0200930 struct lyd_node *tree = NULL;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100931
932 /* init */
Michal Vasko63f3d842020-07-08 10:10:14 +0200933 LY_CHECK_GOTO(ret = lyxml_ctx_new(ctx, in, &lydctx.xmlctx), cleanup);
Radek Krejci1798aae2020-07-14 13:26:06 +0200934 lydctx.parse_options = LYD_PARSE_ONLY | LYD_PARSE_STRICT;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100935 lydctx.int_opts = LYD_INTOPT_NOTIF;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100936
937 /* parse "notification" and "eventTime", if present */
938 LY_CHECK_GOTO(ret = lydxml_notif_envelope(lydctx.xmlctx, &ntf_e), cleanup);
939
940 /* parse the rest of data normally */
Michal Vaskocf770e22020-08-12 13:21:43 +0200941 LY_CHECK_GOTO(ret = lydxml_subtree_r(&lydctx, NULL, &tree), cleanup);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100942
943 /* make sure we have parsed some notification */
Radek Krejci1798aae2020-07-14 13:26:06 +0200944 if (!lydctx.op_node) {
Michal Vaskoa8edff02020-03-27 14:47:01 +0100945 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_DATA, "Missing the \"notification\" node.");
946 ret = LY_EVALID;
947 goto cleanup;
Michal Vaskocf770e22020-08-12 13:21:43 +0200948 } else if (lydctx.xmlctx->status == LYXML_ELEMENT) {
949 LOGVAL(ctx, LY_VLOG_LINE, &lydctx.xmlctx->line, LYVE_SYNTAX, "Unexpected sibling element of \"%s\".",
950 tree->schema->name);
951 ret = LY_EVALID;
952 goto cleanup;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100953 }
954
955 /* finish XML parsing */
956 if (ntf_e) {
957 if (lydctx.xmlctx->status != LYXML_ELEM_CLOSE) {
958 assert(lydctx.xmlctx->status == LYXML_ELEMENT);
959 LOGVAL(ctx, LY_VLOG_LINE, &lydctx.xmlctx->line, LYVE_SYNTAX, "Unexpected sibling element \"%.*s\" of \"notification\".",
960 lydctx.xmlctx->name_len, lydctx.xmlctx->name);
961 ret = LY_EVALID;
962 goto cleanup;
963 }
964 LY_CHECK_GOTO(ret = lyxml_ctx_next(lydctx.xmlctx), cleanup);
965 }
966
Radek Krejci1798aae2020-07-14 13:26:06 +0200967 if (ntf_p) {
968 *ntf_p = lydctx.op_node;
Michal Vaskocc048b22020-03-27 15:52:38 +0100969 }
Radek Krejci1798aae2020-07-14 13:26:06 +0200970 assert(tree);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100971 if (ntf_e) {
972 /* connect to the notification */
Michal Vasko4189c0f2020-08-13 09:05:22 +0200973 lyd_insert_node(ntf_e, NULL, tree);
974 tree = ntf_e;
975 }
976 if (tree_p) {
977 *tree_p = tree;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100978 }
979
980cleanup:
981 /* we have used parse_only flag */
982 assert(!lydctx.unres_node_type.count && !lydctx.unres_meta_type.count && !lydctx.when_check.count);
983 lyxml_ctx_free(lydctx.xmlctx);
984 if (ret) {
Radek Krejci1798aae2020-07-14 13:26:06 +0200985 lyd_free_all(tree);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100986 lyd_free_tree(ntf_e);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100987 }
988 return ret;
989}
Michal Vasko1ce933a2020-03-30 12:38:22 +0200990
991LY_ERR
Radek Krejci1798aae2020-07-14 13:26:06 +0200992lyd_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 +0200993{
994 LY_ERR ret = LY_SUCCESS;
995 struct lyd_xml_ctx lydctx = {0};
Michal Vasko4189c0f2020-08-13 09:05:22 +0200996 struct lyd_node *rpcr_e = NULL, *tree, *req_op, *rep_op = NULL;
Michal Vasko1ce933a2020-03-30 12:38:22 +0200997
998 /* init */
Michal Vasko63f3d842020-07-08 10:10:14 +0200999 LY_CHECK_GOTO(ret = lyxml_ctx_new(LYD_NODE_CTX(request), in, &lydctx.xmlctx), cleanup);
Radek Krejci1798aae2020-07-14 13:26:06 +02001000 lydctx.parse_options = LYD_PARSE_ONLY | LYD_PARSE_STRICT;
Michal Vasko1ce933a2020-03-30 12:38:22 +02001001 lydctx.int_opts = LYD_INTOPT_REPLY;
Michal Vasko1ce933a2020-03-30 12:38:22 +02001002
1003 /* find request OP */
Michal Vasko56daf732020-08-10 10:57:18 +02001004 LYD_TREE_DFS_BEGIN((struct lyd_node *)request, req_op) {
Michal Vasko1ce933a2020-03-30 12:38:22 +02001005 if (req_op->schema->nodetype & (LYS_RPC | LYS_ACTION)) {
1006 break;
1007 }
Michal Vasko56daf732020-08-10 10:57:18 +02001008 LYD_TREE_DFS_END(request, req_op);
Michal Vasko1ce933a2020-03-30 12:38:22 +02001009 }
1010 if (!(req_op->schema->nodetype & (LYS_RPC | LYS_ACTION))) {
1011 LOGERR(LYD_NODE_CTX(request), LY_EINVAL, "No RPC/action in the request found.");
1012 ret = LY_EINVAL;
1013 goto cleanup;
1014 }
1015
1016 /* duplicate request OP with parents */
Michal Vasko3a41dff2020-07-15 14:30:28 +02001017 LY_CHECK_GOTO(ret = lyd_dup_single(req_op, NULL, LYD_DUP_WITH_PARENTS, &rep_op), cleanup);
Michal Vasko1ce933a2020-03-30 12:38:22 +02001018
1019 /* parse "rpc-reply", if any */
Michal Vasko3a41dff2020-07-15 14:30:28 +02001020 LY_CHECK_GOTO(ret = lydxml_envelope(lydctx.xmlctx, "rpc-reply", "urn:ietf:params:xml:ns:netconf:base:1.0", &rpcr_e),
1021 cleanup);
Michal Vasko1ce933a2020-03-30 12:38:22 +02001022
1023 /* parse the rest of data normally but connect them to the duplicated operation */
Michal Vaskoa5da3292020-08-12 13:10:50 +02001024 while (lydctx.xmlctx->status == LYXML_ELEMENT) {
1025 ret = lydxml_subtree_r(&lydctx, (struct lyd_node_inner *)rep_op, lyd_node_children_p(rep_op));
1026 LY_CHECK_GOTO(ret, cleanup);
1027 }
Michal Vasko1ce933a2020-03-30 12:38:22 +02001028
1029 /* finish XML parsing and check operation type */
1030 if (rpcr_e) {
1031 if (lydctx.xmlctx->status != LYXML_ELEM_CLOSE) {
1032 assert(lydctx.xmlctx->status == LYXML_ELEMENT);
1033 LOGVAL(LYD_NODE_CTX(request), LY_VLOG_LINE, &lydctx.xmlctx->line, LYVE_SYNTAX,
1034 "Unexpected sibling element \"%.*s\" of \"rpc-reply\".", lydctx.xmlctx->name_len, lydctx.xmlctx->name);
1035 ret = LY_EVALID;
1036 goto cleanup;
1037 }
1038 LY_CHECK_GOTO(ret = lyxml_ctx_next(lydctx.xmlctx), cleanup);
1039 }
1040
Radek Krejci1798aae2020-07-14 13:26:06 +02001041 if (op_p) {
1042 *op_p = rep_op;
Michal Vasko1ce933a2020-03-30 12:38:22 +02001043 }
Michal Vasko4189c0f2020-08-13 09:05:22 +02001044 for (tree = rep_op; tree->parent; tree = LYD_PARENT(tree));
Michal Vasko1ce933a2020-03-30 12:38:22 +02001045 if (rpcr_e) {
1046 /* connect to the operation */
Michal Vasko4189c0f2020-08-13 09:05:22 +02001047 lyd_insert_node(rpcr_e, NULL, tree);
1048 tree = rpcr_e;
1049 }
1050 if (tree_p) {
1051 *tree_p = tree;
Michal Vasko1ce933a2020-03-30 12:38:22 +02001052 }
1053
1054cleanup:
1055 /* we have used parse_only flag */
1056 assert(!lydctx.unres_node_type.count && !lydctx.unres_meta_type.count && !lydctx.when_check.count);
1057 lyxml_ctx_free(lydctx.xmlctx);
1058 if (ret) {
1059 lyd_free_all(rep_op);
1060 lyd_free_tree(rpcr_e);
1061 }
1062 return ret;
1063}