diff --git a/apps/restconf/restconf_methods.c b/apps/restconf/restconf_methods.c
index 6cc87ce2..ed30ddda 100644
--- a/apps/restconf/restconf_methods.c
+++ b/apps/restconf/restconf_methods.c
@@ -229,6 +229,7 @@ match_list_keys(yang_stmt *y,
* @note restconf PUT is mapped to edit-config replace.
* @see RFC8040 Sec 4.5 PUT
+ * @see api_data_post
* @example
curl -X PUT -d '{"enabled":"false"}' http://127.0.0.1/restconf/data/interfaces/interface=eth1
*
@@ -287,6 +288,7 @@ api_data_put(clicon_handle h,
int ret;
char *namespace0;
char *dname;
+ int nullspec = 0;
clicon_debug(1, "%s api_path:\"%s\" data:\"%s\"",
__FUNCTION__, api_path0, data);
@@ -363,6 +365,7 @@ api_data_put(clicon_handle h,
goto ok;
}
}
+
/* The message-body MUST contain exactly one instance of the
* expected data resource.
*/
@@ -378,6 +381,15 @@ api_data_put(clicon_handle h,
goto ok;
}
xdata = xml_child_i(xdata0,0);
+#if 0
+ if (debug){
+ cbuf *ccc=cbuf_new();
+ if (clicon_xml2cbuf(ccc, xdata, 0, 0) < 0)
+ goto done;
+ clicon_debug(1, "%s DATA:%s", __FUNCTION__, cbuf_get(ccc));
+ cbuf_free(ccc);
+ }
+#endif
/* If the api-path (above) defines a module, then xdata must have a prefix
* and it match the module defined in api-path
* This does not apply if api-path is / (no module)
@@ -493,12 +505,15 @@ api_data_put(clicon_handle h,
xml_purge(xbot);
if (xml_addsub(xparent, xdata) < 0)
goto done;
+ nullspec = (xml_spec(xdata) == NULL);
/* xbot is already populated, resolve yang for added xdata too */
if (xml_apply0(xdata, CX_ELMNT, xml_spec_populate, yspec) < 0)
goto done;
- if (!parse_xml){
+ if (!parse_xml && nullspec){
/* json2xml decode could not be done above in json_parse,
- need to be done here instead */
+ * need to be done here instead
+ * UNLESS it is root resource, then json-parse has already done it
+ */
if ((ret = json2xml_decode(xdata, &xerr)) < 0)
goto done;
if (ret == 0){
diff --git a/apps/restconf/restconf_methods_post.c b/apps/restconf/restconf_methods_post.c
index d88bbc75..e50b25ec 100644
--- a/apps/restconf/restconf_methods_post.c
+++ b/apps/restconf/restconf_methods_post.c
@@ -96,6 +96,7 @@
and a "409 Conflict" status-line MUST be returned.
* @see RFC8040 Section 4.4
+ * @see api_data_put
*/
int
api_data_post(clicon_handle h,
@@ -262,7 +263,7 @@ api_data_post(clicon_handle h,
if (!parse_xml && nullspec){
/* json2xml decode may not have been done above in json_parse,
need to be done here instead
- UNLESS it is a root resource, then json-parse does right
+ UNLESS it is a root resource, then json-parse has already done it
*/
if ((ret = json2xml_decode(xdata, &xerr)) < 0)
goto done;
diff --git a/lib/src/clixon_datastore_write.c b/lib/src/clixon_datastore_write.c
index 56fd444a..7986b50d 100644
--- a/lib/src/clixon_datastore_write.c
+++ b/lib/src/clixon_datastore_write.c
@@ -175,6 +175,14 @@ text_modify(clicon_handle h,
goto done;
x1name = xml_name(x1);
if (yang_keyword_get(y0) == Y_LEAF_LIST || yang_keyword_get(y0) == Y_LEAF){
+ /* This is a check on no further elements as a sanity check for eg
+ * ab
+ */
+ if (xml_child_nr_type(x1, CX_ELMNT)){
+ if (netconf_unknown_element(cbret, "application", x1name, "Leaf contains sub-element") < 0)
+ goto done;
+ goto fail;
+ }
x1bstr = xml_body(x1);
switch(op){
case OP_CREATE:
diff --git a/lib/src/clixon_xml_map.c b/lib/src/clixon_xml_map.c
index 565f1943..afb18f09 100644
--- a/lib/src/clixon_xml_map.c
+++ b/lib/src/clixon_xml_map.c
@@ -382,8 +382,11 @@ validate_identityref(cxobj *xt,
}
/* Get idref value. Then see if this value is derived from ytype.
*/
- if ((node = xml_body(xt)) == NULL)
- return 0;
+ if ((node = xml_body(xt)) == NULL){ /* It may not be empty */
+ if (netconf_bad_element_xml(xret, "application", xml_name(xt), "Identityref should not be empty") < 0)
+ goto done;
+ goto fail;
+ }
if (nodeid_split(node, &prefix, &id) < 0)
goto done;
/* This is the type's base reference */
@@ -1238,7 +1241,6 @@ xml_yang_validate_list_key_only(clicon_handle h,
goto done;
}
-
/*! Validate a single XML node with yang specification for all (not only added) entries
* 1. Check leafrefs. Eg you delete a leaf and a leafref references it.
* @param[in] xt XML node to be validated
diff --git a/test/test_augment.sh b/test/test_augment.sh
index a5a61153..b7a11b69 100755
--- a/test/test_augment.sh
+++ b/test/test_augment.sh
@@ -28,6 +28,7 @@ cat < $cfg
$APPNAME/usr/local/var/$APPNAME/$APPNAME.sock/usr/local/var/$APPNAME/$APPNAME.pidfile
+ false1/usr/local/var/$APPNAMEtrue
@@ -152,11 +153,18 @@ if [ $BE -ne 0 ]; then
fi
new "start backend -s init -f $cfg"
start_backend -s init -f $cfg
-
- new "waiting"
- wait_backend
fi
+new "kill old restconf daemon"
+sudo pkill -u www-data clixon_restconf
+
+new "start restconf daemon"
+start_restconf -f $cfg
+
+new "waiting"
+wait_backend
+wait_restconf
+
# mandatory-leaf See RFC7950 Sec 7.17
new "netconf set interface with augmented type and mandatory leaf"
expecteof "$clixon_netconf -qf $cfg" 0 '
@@ -190,12 +198,19 @@ expecteof "$clixon_netconf -qf $cfg" 0 'mymod:you]]>]]>' "^]]>]]>$"
-new "netconf validate ok"
-expecteof "$clixon_netconf -qf $cfg" 0 "]]>]]>" '^]]>]]>$'
+new "netconf commit ok"
+expecteof "$clixon_netconf -qf $cfg" 0 "]]>]]>" '^]]>]]>$'
-new "discard"
-expecteof "$clixon_netconf -qf $cfg" 0 "]]>]]>" "^]]>]]>$"
+# restconf and augment
+new "restconf get augment"
+expectpart "$(curl -s -i -X GET http://localhost/restconf/data/ietf-interfaces:interfaces)" 0 'HTTP/1.1 200 OK
' '{"ietf-interfaces:interfaces":{"interface":\[{"name":"e1","type":"example-augment:some-new-iftype","example-augment:mandatory-leaf":"true","example-augment:port":80,"example-augment:lport":8080},{"name":"e2","type":"fddi","example-augment:mandatory-leaf":"true","example-augment:other":"ietf-interfaces:fddi","example-augment:port":80,"example-augment:lport":8080},{"name":"e3","type":"fddi","example-augment:mandatory-leaf":"true","example-augment:me":"you","example-augment:port":80,"example-augment:lport":8080}\]}}
'
+
+new "restconf get augment xml"
+expectpart "$(curl -s -i -X GET -H 'Accept: application/yang-data+xml' http://localhost/restconf/data/ietf-interfaces:interfaces)" 0 'HTTP/1.1 200 OK
' 'e1mymod:some-new-iftypetrue808080e2fdditrueif:fddi808080e3fdditruemymod:you808080'
+
+new "Kill restconf daemon"
+stop_restconf
if [ $BE -eq 0 ]; then
exit # BE
diff --git a/test/test_identity.sh b/test/test_identity.sh
index b8005d97..489567d4 100755
--- a/test/test_identity.sh
+++ b/test/test_identity.sh
@@ -1,5 +1,6 @@
#!/bin/bash
# Identity and identityref tests
+# Example from RFC7950 Sec 7.18 and 9.10
# Magic line must be first in script (see README.md)
s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi
@@ -21,6 +22,7 @@ cat < $cfg
example_backend.so$/usr/local/lib/$APPNAME/netconf/usr/local/lib/$APPNAME/restconf
+ false/usr/local/lib/$APPNAME/cli$APPNAME/usr/local/var/$APPNAME/$APPNAME.sock
@@ -148,11 +150,18 @@ if [ $BE -ne 0 ]; then
fi
new "start backend -s init -f $cfg"
start_backend -s init -f $cfg
-
- new "waiting"
- wait_backend
fi
+new "kill old restconf daemon"
+sudo pkill -u www-data clixon_restconf
+
+new "start restconf daemon"
+start_restconf -f $cfg
+
+new "waiting"
+wait_backend
+wait_restconf
+
new "Set crypto to aes"
expecteof "$clixon_netconf -qf $cfg" 0 'aes]]>]]>' '^]]>]]>$'
@@ -253,6 +262,54 @@ expectfn "$clixon_cli -1 -f $cfg -l o validate" 255 "Identityref validation fail
new "netconf discard-changes"
expecteof "$clixon_netconf -qf $cfg" 0 "]]>]]>" "^]]>]]>$"
+# restconf and identities:
+# 1. set identity in own module with restconf (PUT and POST), read it with restconf and netconf
+# 2. set identity in other module with restconf , read it with restconf and netconf
+# 3. set identity in other module with netconf, read it with restconf and netconf
+new "restconf add own identity"
+expectpart "$(curl -s -i -X PUT http://localhost/restconf/data/example:crypto -d '{"example:crypto":"example:aes"}')" 0 'HTTP/1.1 201 Created'
+
+new "restconf get own identity"
+expectpart "$(curl -s -i -X GET http://localhost/restconf/data/example:crypto)" 0 'HTTP/1.1 200 OK' '{"example:crypto":"aes"}'
+
+new "netconf get own identity as set by restconf"
+expecteof "$clixon_netconf -qf $cfg" 0 "]]>]]>" '^aes]]>]]>$'
+
+new "restconf delete identity"
+expectpart "$(curl -s -i -X DELETE http://localhost/restconf/data/example:crypto)" 0 "HTTP/1.1 204 No Content"
+
+# 2. set identity in other module with restconf , read it with restconf and netconf
+new "restconf add POST instead of PUT (should fail)"
+expectpart "$(curl -s -i -X POST http://localhost/restconf/data/example:crypto -d '{"example:crypto":"example-des:des3"}')" 0 'HTTP/1.1 400 Bad Request' '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"unknown-element","error-info":{"bad-element":"crypto"},"error-severity":"error","error-message":"Leaf contains sub-element"}}}'
+
+new "restconf add other (des) identity using POST"
+expectpart "$(curl -s -i -X POST http://localhost/restconf/data -d '{"example:crypto":"example-des:des3"}')" 0 'HTTP/1.1 201 Created' 'Location: http://localhost/restconf/data/example:crypto'
+
+new "restconf get other identity"
+expectpart "$(curl -s -i -X GET http://localhost/restconf/data/example:crypto)" 0 'HTTP/1.1 200 OK' '{"example:crypto":"example-des:des3"}'
+
+new "netconf get other identity"
+expecteof "$clixon_netconf -qf $cfg" 0 "]]>]]>" '^des:des3]]>]]>$'
+
+new "restconf delete identity"
+expectpart "$(curl -s -i -X DELETE http://localhost/restconf/data/example:crypto)" 0 "HTTP/1.1 204 No Content"
+
+# 3. set identity in other module with netconf, read it with restconf and netconf
+new "netconf set other identity"
+expecteof "$clixon_netconf -qf $cfg" 0 'des:des3]]>]]>' "^]]>]]>$"
+
+new "netconf commit"
+expecteof "$clixon_netconf -qf $cfg" 0 "]]>]]>" "^]]>]]>$"
+
+new "restconf get other identity (set by netconf)"
+expectpart "$(curl -s -i -X GET http://localhost/restconf/data/example:crypto)" 0 'HTTP/1.1 200 OK' '{"example:crypto":"example-des:des3"}'
+
+new "netconf get other identity"
+expecteof "$clixon_netconf -qf $cfg" 0 "]]>]]>" '^des:des3]]>]]>$'
+
+new "Kill restconf daemon"
+stop_restconf
+
if [ $BE -eq 0 ]; then
exit # BE
fi
diff --git a/test/test_netconf.sh b/test/test_netconf.sh
index 3ccd6c08..1ece0926 100755
--- a/test/test_netconf.sh
+++ b/test/test_netconf.sh
@@ -139,6 +139,7 @@ expecteof "$clixon_netconf -qf $cfg" 0 "]]>]]>" "^eth2ex:ethmerge]]>]]>' "^]]>]]>$"
+# Note, the type here is non-existant identityref, fails on validation
new "netconf edit ampersand encoding(<&): name:'eth&' type:'t<>'"
expecteof "$clixon_netconf -qf $cfg" 0 'eth&t<>]]>]]>' '^]]>]]>$'
@@ -201,6 +202,9 @@ expecteof "$clixon_netconf -qf $cfg" 0 '
new "netconf client-side rpc"
expecteof "$clixon_netconf -qf $cfg" 0 'val42]]>]]>' '^val42]]>]]>$'
+new "netconf extra leaf in leaf should fail"
+expecteof "$clixon_netconf -qf $cfg" 0 'e0e1]]>]]>' '^applicationunknown-elementnameerrorLeaf contains sub-element]]>]]>$'
+
if [ $BE -eq 0 ]; then
exit # BE
fi
diff --git a/test/test_restconf_jukebox.sh b/test/test_restconf_jukebox.sh
index 2429b6e3..f36c96d6 100755
--- a/test/test_restconf_jukebox.sh
+++ b/test/test_restconf_jukebox.sh
@@ -336,7 +336,6 @@ new "B.2.1. Add Data Resources again (conflict - not in RFC)"
expectpart "$(curl -s -i -X POST -H 'Content-Type: application/yang-data+xml' http://localhost/restconf/data/example-jukebox:jukebox/library/artist=Foo%20Fighters -d 'Wasting Light2011')" 0 "HTTP/1.1 409 Conflict"
new "4.5. PUT replace content"
-# XXX should be: jbox:alternative --> example-jukebox:alternative
expectpart "$(curl -s -i -X PUT -H 'Content-Type: application/yang-data+json' http://localhost/restconf/data/example-jukebox:jukebox/library/artist=Foo%20Fighters/album=Wasting%20Light -d '{"example-jukebox:album":[{"name":"Wasting Light","genre":"example-jukebox:alternative","year":2011}]}')" 0 "HTTP/1.1 204 No Content"
new "4.5. PUT replace content (xml encoding)"