diff --git a/CHANGELOG.md b/CHANGELOG.md
index 20d401f9..f9bfcd38 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -69,6 +69,16 @@
### API changes on existing features (you may need to change your code)
+* RESTCONF strict namespace validation of data in POST and PUT.
+ * Accepted:
+ ```
+ curl -X PUT http://localhost/restconf/data/mod:a -d {"mod:a":"x"}
+ ```
+ * Not accepted (must prefix "a" with module):
+ ```
+ curl -X PUT http://localhost/restconf/data/mod:a -d {"a":"x"}
+ ```
+ * Undefine `RESTCONF_NS_DATA_CHECK` in include/clixon_custom.h to disable strict check.
* Many validation functions have changed error parameter from cbuf to xml tree.
* XML trees are more flexible for utility tools
* If you use these(mostly internal), you need to change the error function: `generic_validate, from_validate_common, xml_yang_validate_all_top, xml_yang_validate_all, xml_yang_validate_add, xml_yang_validate_rpc, xml_yang_validate_list_key_only`
diff --git a/apps/restconf/restconf_methods.c b/apps/restconf/restconf_methods.c
index b09da045..79571982 100644
--- a/apps/restconf/restconf_methods.c
+++ b/apps/restconf/restconf_methods.c
@@ -437,13 +437,17 @@ api_data_post(clicon_handle h,
{
int retval = -1;
enum operation_type op = OP_CREATE;
+ cxobj *xdata0 = NULL; /* Original -d data struct (including top symbol) */
+ cxobj *xdata; /* -d data (without top symbol)*/
int i;
- cxobj *xdata = NULL;
cbuf *cbx = NULL;
- cxobj *xtop = NULL; /* xpath root */
- cxobj *xbot = NULL;
- cxobj *x;
- yang_stmt *y = NULL;
+ cxobj *xtop = NULL; /* top of api-path */
+ cxobj *xbot = NULL; /* bottom of api-path */
+ yang_stmt *ybot = NULL; /* yang of xbot */
+#ifdef RESTCONF_NS_DATA_CHECK
+ yang_stmt *ymodapi = NULL; /* yang module of api-path (if any) */
+ yang_stmt *ymoddata = NULL; /* yang module of data (-d) */
+#endif
yang_stmt *yspec;
cxobj *xa;
cxobj *xret = NULL;
@@ -469,8 +473,12 @@ api_data_post(clicon_handle h,
/* Translate api_path to xtop/xbot */
xbot = xtop;
if (api_path){
- if ((ret = api_path2xml(api_path, yspec, xtop, YC_DATANODE, 1, &xbot, &y)) < 0)
+ if ((ret = api_path2xml(api_path, yspec, xtop, YC_DATANODE, 1, &xbot, &ybot)) < 0)
goto done;
+#ifdef RESTCONF_NS_DATA_CHECK
+ if (ybot)
+ ymodapi=ys_module(ybot);
+#endif
if (ret == 0){ /* validation failed */
if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0)
goto done;
@@ -486,7 +494,7 @@ api_data_post(clicon_handle h,
}
/* Parse input data as json or xml into xml */
if (parse_xml){
- if (xml_parse_string(data, NULL, &xdata) < 0){
+ if (xml_parse_string(data, NULL, &xdata0) < 0){
if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0)
goto done;
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
@@ -499,7 +507,7 @@ api_data_post(clicon_handle h,
}
}
else {
- if ((ret = json_parse_str(data, yspec, &xdata, &xerr)) < 0){
+ if ((ret = json_parse_str(data, yspec, &xdata0, &xerr)) < 0){
if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0)
goto done;
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
@@ -523,7 +531,7 @@ api_data_post(clicon_handle h,
/* 4.4.1: The message-body MUST contain exactly one instance of the
* expected data resource.
*/
- if (xml_child_nr(xdata) != 1){
+ if (xml_child_nr(xdata0) != 1){
if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0)
goto done;
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
@@ -534,15 +542,46 @@ api_data_post(clicon_handle h,
goto done;
goto ok;
}
- x = xml_child_i(xdata,0);
+ xdata = xml_child_i(xdata0,0);
+#ifdef RESTCONF_NS_DATA_CHECK
+ /* If the api-path (above) defines a module, then xdata must have a prefix
+ * and it match the module defined in api-path.
+ * In a POST, maybe there are cornercases where xdata (which is a child) and
+ * xbot (which is the parent) may have non-matching namespaces?
+ * This does not apply if api-path is / (no module)
+ */
+ if (ys_module_by_xml(yspec, xdata, &ymoddata) < 0)
+ goto done;
+ if (ymoddata && ymodapi){
+ if (ymoddata != ymodapi){
+ if (netconf_malformed_message_xml(&xerr, "Data is not prefixed with matching namespace") < 0)
+ goto done;
+ if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
+ clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
+ goto done;
+ }
+ if (debug){
+ cbuf *ccc=cbuf_new();
+ if (clicon_xml2cbuf(ccc, xe, 0, 0) < 0)
+ goto done;
+ clicon_debug(1, "%s XE:%s", __FUNCTION__, cbuf_get(ccc));
+ }
+
+ if (api_return_err(h, r, xe, pretty, use_xml) < 0)
+ goto done;
+ goto ok;
+ }
+ }
+#endif /* RESTCONF_NS_DATA_CHECK */
+
/* Add operation (create/replace) as attribute */
- if ((xa = xml_new("operation", x, NULL)) == NULL)
+ if ((xa = xml_new("operation", xdata, NULL)) == NULL)
goto done;
xml_type_set(xa, CX_ATTR);
if (xml_value_set(xa, xml_operation2str(op)) < 0)
goto done;
/* Replace xbot with x, ie bottom of api-path with data */
- if (xml_addsub(xbot, x) < 0)
+ if (xml_addsub(xbot, xdata) < 0)
goto done;
/* Create text buffer for transfer to backend */
if ((cbx = cbuf_new()) == NULL)
@@ -626,8 +665,8 @@ api_data_post(clicon_handle h,
xml_free(xretdis);
if (xtop)
xml_free(xtop);
- if (xdata)
- xml_free(xdata);
+ if (xdata0)
+ xml_free(xdata0);
if (cbx)
cbuf_free(cbx);
return retval;
@@ -745,10 +784,14 @@ api_data_put(clicon_handle h,
cxobj *xdata0 = NULL; /* Original -d data struct (including top symbol) */
cxobj *xdata; /* -d data (without top symbol)*/
cbuf *cbx = NULL;
- cxobj *xtop = NULL; /* xpath root */
- cxobj *xbot = NULL;
+ cxobj *xtop = NULL; /* top of api-path */
+ cxobj *xbot = NULL; /* bottom of api-path */
+ yang_stmt *ybot = NULL; /* yang of xbot */
+#ifdef RESTCONF_NS_DATA_CHECK
+ yang_stmt *ymodapi = NULL; /* yang module of api-path (if any) */
+ yang_stmt *ymoddata = NULL; /* yang module of data (-d) */
+#endif
cxobj *xparent;
- yang_stmt *y = NULL;
yang_stmt *yp; /* yang parent */
yang_stmt *yspec;
cxobj *xa;
@@ -778,8 +821,12 @@ api_data_put(clicon_handle h,
/* Translate api_path to xtop/xbot */
xbot = xtop;
if (api_path){
- if ((ret = api_path2xml(api_path, yspec, xtop, YC_DATANODE, 1, &xbot, &y)) < 0)
+ if ((ret = api_path2xml(api_path, yspec, xtop, YC_DATANODE, 1, &xbot, &ybot)) < 0)
goto done;
+#ifdef RESTCONF_NS_DATA_CHECK
+ if (ybot)
+ ymodapi=ys_module(ybot);
+#endif
if (ret == 0){ /* validation failed */
if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0)
goto done;
@@ -793,9 +840,10 @@ api_data_put(clicon_handle h,
goto ok;
}
}
+
/* Parse input data as json or xml into xml */
if (parse_xml){
- if (xml_parse_string(data, NULL, &xdata0) < 0){
+ if (xml_parse_string(data, yspec, &xdata0) < 0){
if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0)
goto done;
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
@@ -844,20 +892,35 @@ api_data_put(clicon_handle h,
goto ok;
}
xdata = xml_child_i(xdata0,0);
+#ifdef RESTCONF_NS_DATA_CHECK
+ /* 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)
+ */
+ if (ys_module_by_xml(yspec, xdata, &ymoddata) < 0)
+ goto done;
+ if (ymoddata && ymodapi){
+ if (ymoddata != ymodapi){
+ if (netconf_malformed_message_xml(&xerr, "Data is not prefixed with matching namespace") < 0)
+ goto done;
+ if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
+ clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
+ goto done;
+ }
+ if (api_return_err(h, r, xe, pretty, use_xml) < 0)
+ goto done;
+ goto ok;
+ }
+ }
+#endif /* RESTCONF_NS_DATA_CHECK */
+
/* Add operation (create/replace) as attribute */
if ((xa = xml_new("operation", xdata, NULL)) == NULL)
goto done;
xml_type_set(xa, CX_ATTR);
if (xml_value_set(xa, xml_operation2str(op)) < 0)
goto done;
-#if 0
- if (debug){
- cbuf *ccc=cbuf_new();
- if (clicon_xml2cbuf(ccc, xdata0, 0, 0) < 0)
- goto done;
- clicon_debug(1, "%s DATA:%s", __FUNCTION__, cbuf_get(ccc));
- }
-#endif
+
/* Top-of tree, no api-path
* Replace xparent with x, ie bottom of api-path with data
*/
@@ -875,6 +938,7 @@ api_data_put(clicon_handle h,
* Not top-of-tree.
*/
clicon_debug(1, "%s x:%s xbot:%s",__FUNCTION__, dname, xml_name(xbot));
+
/* Check same symbol in api-path as data */
if (strcmp(dname, xml_name(xbot))){
if (netconf_operation_failed_xml(&xerr, "protocol", "Not same symbol in api-path as data") < 0)
@@ -895,13 +959,13 @@ api_data_put(clicon_handle h,
* That is why the conditional is somewhat hairy
*/
xparent = xml_parent(xbot);
- if (y){
+ if (ybot){
/* Ensure list keys match between uri and data. That is:
* If data is on the form: -d {"a":{"k":1}} where a is list or leaf-list
* then uri-path must be ../a=1
* match_list_key() checks if this is true
*/
- if (match_list_keys(y, xdata, xbot) < 0){
+ if (match_list_keys(ybot, xdata, xbot) < 0){
if (netconf_operation_failed_xml(&xerr, "protocol", "api-path keys do not match data keys") < 0)
goto done;
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
@@ -916,7 +980,7 @@ api_data_put(clicon_handle h,
* If data is on the form: -d {"k":1} and its parent is a list "a"
* then the uri-path must be "../a=1 (you cannot change a's key)"
*/
- if ((yp = yang_parent_get(y)) != NULL &&
+ if ((yp = yang_parent_get(ybot)) != NULL &&
yang_keyword_get(yp) == Y_LIST){
if ((ret = yang_key_match(yp, dname)) < 0)
goto done;
@@ -967,6 +1031,7 @@ api_data_put(clicon_handle h,
clicon_debug(1, "%s xml: %s api_path:%s",__FUNCTION__, cbuf_get(cbx), api_path);
if (clicon_rpc_netconf(h, cbuf_get(cbx), &xret, NULL) < 0)
goto done;
+
if ((xe = xpath_first(xret, "//rpc-error")) != NULL){
if (api_return_err(h, r, xe, pretty, use_xml) < 0)
goto done;
diff --git a/include/clixon_custom.h b/include/clixon_custom.h
index c302d0ed..d5d46c16 100644
--- a/include/clixon_custom.h
+++ b/include/clixon_custom.h
@@ -44,3 +44,7 @@
/* Use new xml_insert code on sorted xml lists
*/
#define USE_XML_INSERT
+
+/* Make namespace check on RESTCONF PUT and POST -d data
+ */
+#define RESTCONF_NS_DATA_CHECK
diff --git a/test/test_nacm_ext.sh b/test/test_nacm_ext.sh
index cd66b01c..e2207ea8 100755
--- a/test/test_nacm_ext.sh
+++ b/test/test_nacm_ext.sh
@@ -183,10 +183,10 @@ new "admin edit nacm"
expecteq "$(curl -u andy:bar -sS -X PUT -d '{"nacm-example:x": 1}' http://localhost/restconf/data/nacm-example:x)" 0 ""
new "limited edit nacm"
-expecteq "$(curl -u wilma:bar -sS -X PUT -d '{"x": 2}' http://localhost/restconf/data/nacm-example:x)" 0 '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "access-denied","error-severity": "error","error-message": "default deny"}}}
'
+expecteq "$(curl -u wilma:bar -sS -X PUT -d '{"nacm-example:x": 2}' http://localhost/restconf/data/nacm-example:x)" 0 '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "access-denied","error-severity": "error","error-message": "default deny"}}}
'
new "guest edit nacm"
-expecteq "$(curl -u guest:bar -sS -X PUT -d '{"x": 3}' http://localhost/restconf/data/nacm-example:x)" 0 '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "access-denied","error-severity": "error","error-message": "access denied"}}}
'
+expecteq "$(curl -u guest:bar -sS -X PUT -d '{"nacm-example:x": 3}' http://localhost/restconf/data/nacm-example:x)" 0 '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "access-denied","error-severity": "error","error-message": "access denied"}}}
'
new "cli show conf as admin"
expectfn "$clixon_cli -1 -U andy -l o -f $cfg show conf" 0 "^x 1;$"
diff --git a/test/test_nacm_module_read.sh b/test/test_nacm_module_read.sh
index 8204b6a4..16755175 100755
--- a/test/test_nacm_module_read.sh
+++ b/test/test_nacm_module_read.sh
@@ -153,7 +153,7 @@ new "commit it"
expecteof "$clixon_netconf -qf $cfg" 0 "]]>]]>" "^]]>]]>$"
new "enable nacm"
-expecteq "$(curl -u andy:bar -sS -X PUT -d '{"enable-nacm": true}' http://localhost/restconf/data/ietf-netconf-acm:nacm/enable-nacm)" 0 ""
+expecteq "$(curl -u andy:bar -sS -X PUT -d '{"ietf-netconf-acm:enable-nacm": true}' http://localhost/restconf/data/ietf-netconf-acm:nacm/enable-nacm)" 0 ""
#--------------- nacm enabled
@@ -256,7 +256,7 @@ expecteof "$clixon_netconf -U guest -qf $cfg" 0 ']]>]]>" "^]]>]]>$"
new "enable nacm"
- expecteq "$(curl -u andy:bar -sS -X PUT -d '{"enable-nacm": true}' http://localhost/restconf/data/ietf-netconf-acm:nacm/enable-nacm)" 0 ""
+ expecteq "$(curl -u andy:bar -sS -X PUT -d '{"ietf-netconf-acm:enable-nacm": true}' http://localhost/restconf/data/ietf-netconf-acm:nacm/enable-nacm)" 0 ""
}
#--------------- enable nacm
diff --git a/test/test_nacm_protocol.sh b/test/test_nacm_protocol.sh
index 3e6089ce..c9092ac9 100755
--- a/test/test_nacm_protocol.sh
+++ b/test/test_nacm_protocol.sh
@@ -162,7 +162,7 @@ new "commit it"
expecteof "$clixon_netconf -qf $cfg" 0 "]]>]]>" "^]]>]]>$"
new "enable nacm"
-expecteq "$(curl -u andy:bar -sS -X PUT -d '{"enable-nacm": true}' http://localhost/restconf/data/ietf-netconf-acm:nacm/enable-nacm)" 0 ""
+expecteq "$(curl -u andy:bar -sS -X PUT -d '{"ietf-netconf-acm:enable-nacm": true}' http://localhost/restconf/data/ietf-netconf-acm:nacm/enable-nacm)" 0 ""
#--------------- nacm enabled
diff --git a/test/test_restconf2.sh b/test/test_restconf2.sh
index 11a4b89a..84aba720 100755
--- a/test/test_restconf2.sh
+++ b/test/test_restconf2.sh
@@ -95,6 +95,9 @@ expectfn 'curl -s -X POST -d {"example:cont1":{"interface":{"type":"regular"}}}
new "restconf POST initial tree"
expectfn 'curl -s -X POST -d {"example:cont1":{"interface":{"name":"local0","type":"regular"}}} http://localhost/restconf/data' 0 ""
+new "restconf POST top without namespace"
+expectfn 'curl -s -X POST -d {"cont1":{"interface":{"name":"local0","type":"regular"}}} http://localhost/restconf/data' 0 '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "unknown-element","error-info": {"bad-element": "cont1"},"error-severity": "error","error-message": "Unassigned yang spec"}}}'
+
new "restconf GET datastore initial"
expectfn "curl -s -X GET http://localhost/restconf/data/example:cont1" 0 '{"example:cont1": {"interface": \[{"name": "local0","type": "regular"}\]}}'
@@ -113,17 +116,19 @@ new "restconf GET if-type"
expectfn "curl -s -X GET http://localhost/restconf/data/example:cont1/interface=local0/type" 0 '{"example:type": "regular"}'
new "restconf POST interface without mandatory type"
-expectfn 'curl -s -X POST http://localhost/restconf/data/example:cont1 -d {"interface":{"name":"TEST"}} http://localhost/restconf/data/example:cont1' 0 '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "missing-element","error-info": {"bad-element": "type"},"error-severity": "error","error-message": "Mandatory variable"}}}
'
+expectfn 'curl -s -X POST http://localhost/restconf/data/example:cont1 -d {"example:interface":{"name":"TEST"}}' 0 '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "missing-element","error-info": {"bad-element": "type"},"error-severity": "error","error-message": "Mandatory variable"}}}
'
new "restconf POST interface without mandatory key"
-expectfn 'curl -s -X POST http://localhost/restconf/data/example:cont1 -d {"interface":{"type":"regular"}}' 0 '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "missing-element","error-info": {"bad-element": "name"},"error-severity": "error","error-message": "Mandatory key"}}}
'
+expectfn 'curl -s -X POST http://localhost/restconf/data/example:cont1 -d {"example:interface":{"type":"regular"}}' 0 '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "missing-element","error-info": {"bad-element": "name"},"error-severity": "error","error-message": "Mandatory key"}}}
'
new "restconf POST interface"
expectfn 'curl -s -X POST -d {"example:interface":{"name":"TEST","type":"eth0"}} http://localhost/restconf/data/example:cont1' 0 ""
-# XXX should it be example:interface?
+new "restconf POST interface without namespace"
+expectfn 'curl -s -X POST -d {"interface":{"name":"TEST2","type":"eth0"}} http://localhost/restconf/data/example:cont1' 0 '{"ietf-restconf:errors" : {"error": {"error-type": "rpc","error-tag": "malformed-message","error-severity": "error","error-message": "Data is not prefixed with matching namespace"}}}'
+
new "restconf POST again"
-expecteq "$(curl -s -X POST -d '{"interface":{"name":"TEST","type":"eth0"}}' http://localhost/restconf/data/example:cont1)" 0 '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "data-exists","error-severity": "error","error-message": "Data already exists; cannot create new resource"}}}
'
+expecteq "$(curl -s -X POST -d '{"example:interface":{"name":"TEST","type":"eth0"}}' http://localhost/restconf/data/example:cont1)" 0 '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "data-exists","error-severity": "error","error-message": "Data already exists; cannot create new resource"}}}
'
new "restconf POST from top"
expecteq "$(curl -s -X POST -d '{"example:cont1":{"interface":{"name":"TEST","type":"eth0"}}}' http://localhost/restconf/data)" 0 '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "data-exists","error-severity": "error","error-message": "Data already exists; cannot create new resource"}}}
'
@@ -162,16 +167,16 @@ new "restconf PUT initial datastore again"
expectfn 'curl -s -X PUT -d {"data":{"example:cont1":{"interface":{"name":"local0","type":"regular"}}}} http://localhost/restconf/data' 0 ""
new "restconf PUT change interface"
-expectfn 'curl -s -X PUT -d {"interface":{"name":"local0","type":"atm0"}} http://localhost/restconf/data/example:cont1/interface=local0' 0 ""
+expectfn 'curl -s -X PUT -d {"example:interface":{"name":"local0","type":"atm0"}} http://localhost/restconf/data/example:cont1/interface=local0' 0 ""
new "restconf GET datastore atm"
expectfn "curl -s -X GET http://localhost/restconf/data/example:cont1" 0 '{"example:cont1": {"interface": \[{"name": "local0","type": "atm0"}\]}}'
new "restconf PUT add interface"
-expectfn 'curl -s -X PUT -d {"interface":{"name":"TEST","type":"eth0"}} http://localhost/restconf/data/example:cont1/interface=TEST' 0 ""
+expectfn 'curl -s -X PUT -d {"example:interface":{"name":"TEST","type":"eth0"}} http://localhost/restconf/data/example:cont1/interface=TEST' 0 ""
new "restconf PUT change key error"
-expectfn 'curl -is -X PUT -d {"interface":{"name":"ALPHA","type":"eth0"}} http://localhost/restconf/data/example:cont1/interface=TEST' 0 '{"ietf-restconf:errors" : {"error": {"error-type": "protocol","error-tag": "operation-failed","error-severity": "error","error-message": "api-path keys do not match data keys"}}}'
+expectfn 'curl -is -X PUT -d {"example:interface":{"name":"ALPHA","type":"eth0"}} http://localhost/restconf/data/example:cont1/interface=TEST' 0 '{"ietf-restconf:errors" : {"error": {"error-type": "protocol","error-tag": "operation-failed","error-severity": "error","error-message": "api-path keys do not match data keys"}}}'
new "restconf PUT change type to eth0 (non-key sub-element to list)"
expectfn 'curl -s -X PUT -d {"example:type":"eth0"} http://localhost/restconf/data/example:cont1/interface=local0/type' 0 ""
diff --git a/test/test_restconf_listkey.sh b/test/test_restconf_listkey.sh
index 4a33b21a..2426e4b9 100755
--- a/test/test_restconf_listkey.sh
+++ b/test/test_restconf_listkey.sh
@@ -93,6 +93,9 @@ expectfn 'curl -s -X PUT http://localhost/restconf/data/list:c/a=x,y -d {"list:a
new "restconf PUT change whole list entry (same keys)"
expectfn 'curl -s -X PUT http://localhost/restconf/data/list:c/a=x,y -d {"list:a":{"b":"x","c":"y","nonkey":"z"}}' 0 ''
+new "restconf PUT change whole list entry (no namespace)(expect fail)"
+expectfn 'curl -s -X PUT http://localhost/restconf/data/list:c/a=x,y -d {"a":{"b":"x","c":"y","nonkey":"z"}}' 0 '{"ietf-restconf:errors" : {"error": {"error-type": "rpc","error-tag": "malformed-message","error-severity": "error","error-message": "Data is not prefixed with matching namespace"}}}'
+
new "restconf PUT change list entry (wrong keys)(expect fail)"
expectfn 'curl -s -X PUT http://localhost/restconf/data/list:c/a=x,y -d {"list:a":{"b":"y","c":"x"}}' 0 '{"ietf-restconf:errors" : {"error": {"error-type": "protocol","error-tag": "operation-failed","error-severity": "error","error-message": "api-path keys do not match data keys"}}}'
@@ -127,10 +130,10 @@ new "restconf PUT list-list single first key"
expectfn 'curl -s -X PUT http://localhost/restconf/data/list:c/a=x/e=z/f -d {"f":"z"}' 0 '{"ietf-restconf:errors" : {"error": {"error-type": "rpc","error-tag": "malformed-message","error-severity": "error","error-message": "List key a length mismatch"}}}'
new "restconf PUT list-list just key ok"
-expectfn 'curl -s -X PUT http://localhost/restconf/data/list:c/a=x,y/e=z/f -d {"f":"z"}' 0 ''
+expectfn 'curl -s -X PUT http://localhost/restconf/data/list:c/a=x,y/e=z/f -d {"list:f":"z"}' 0 ''
new "restconf PUT list-list just key just key wrong value (should fail)"
-expectfn 'curl -s -X PUT http://localhost/restconf/data/list:c/a=x,y/e=z/f -d {"f":"wrong"}' 0 '{"ietf-restconf:errors" : {"error": {"error-type": "protocol","error-tag": "operation-failed","error-severity": "error","error-message": "api-path keys do not match data keys"}}}'
+expectfn 'curl -s -X PUT http://localhost/restconf/data/list:c/a=x,y/e=z/f -d {"list:f":"wrong"}' 0 '{"ietf-restconf:errors" : {"error": {"error-type": "protocol","error-tag": "operation-failed","error-severity": "error","error-message": "api-path keys do not match data keys"}}}'
new "restconf PUT add list+leaf-list entry"
expectfn 'curl -s -X PUT http://localhost/restconf/data/list:c/a=x,y/f=u -d {"list:f":"u"}' 0 ''