diff --git a/CHANGELOG.md b/CHANGELOG.md
index eb2fe361..a20c959b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -251,6 +251,7 @@
### Corrected Bugs
+* Return 404 Not found error if restconf GET does not return requested instance
* Fixed [Wrong yang-generated cli code for typeref identityref combination #88](https://github.com/clicon/clixon/issues/88)
* Fixed [identityref validation fails when using typedef #87](https://github.com/clicon/clixon/issues/87)
* Fixed a problem with some netconf error messages caused restconf daemon to exit due to no XML encoding
diff --git a/apps/restconf/clixon_restconf.h b/apps/restconf/clixon_restconf.h
index 4c93c104..06c6ed86 100644
--- a/apps/restconf/clixon_restconf.h
+++ b/apps/restconf/clixon_restconf.h
@@ -55,7 +55,7 @@ int test(FCGX_Request *r, int dbg);
cbuf *readdata(FCGX_Request *r);
int get_user_cookie(char *cookiestr, char *attribute, char **val);
int api_return_err(clicon_handle h, FCGX_Request *r, cxobj *xerr,
- int pretty, int use_xml);
+ int pretty, int use_xml, int code);
#endif /* _CLIXON_RESTCONF_H_ */
diff --git a/apps/restconf/restconf_lib.c b/apps/restconf/restconf_lib.c
index 8bcb7c38..e7613f87 100644
--- a/apps/restconf/restconf_lib.c
+++ b/apps/restconf/restconf_lib.c
@@ -394,13 +394,16 @@ get_user_cookie(char *cookiestr,
* @param[in] xerr XML error message from backend
* @param[in] pretty Set to 1 for pretty-printed xml/json output
* @param[in] use_xml Set to 0 for JSON and 1 for XML
+ * @param[in] code If 0 use rfc8040 sec 7 netconf2restconf error-tag mapping
+ * otherwise use this code
*/
int
api_return_err(clicon_handle h,
FCGX_Request *r,
cxobj *xerr,
int pretty,
- int use_xml)
+ int use_xml,
+ int code0)
{
int retval = -1;
cbuf *cb = NULL;
@@ -417,8 +420,12 @@ api_return_err(clicon_handle h,
goto ok;
}
tagstr = xml_body(xtag);
- if ((code = restconf_err2code(tagstr)) < 0)
- code = 500; /* internal server error */
+ if (code0 != 0)
+ code = code0;
+ else{
+ if ((code = restconf_err2code(tagstr)) < 0)
+ code = 500; /* internal server error */
+ }
if ((reason_phrase = restconf_code2reason(code)) == NULL)
reason_phrase="";
if (xml_name_set(xerr, "error") < 0)
diff --git a/apps/restconf/restconf_lib.h b/apps/restconf/restconf_lib.h
index 57839bc8..1b90ef30 100644
--- a/apps/restconf/restconf_lib.h
+++ b/apps/restconf/restconf_lib.h
@@ -60,7 +60,7 @@ int test(FCGX_Request *r, int dbg);
cbuf *readdata(FCGX_Request *r);
int get_user_cookie(char *cookiestr, char *attribute, char **val);
int api_return_err(clicon_handle h, FCGX_Request *r, cxobj *xerr,
- int pretty, int use_xml);
+ int pretty, int use_xml, int code);
int restconf_terminate(clicon_handle h);
#endif /* _RESTCONF_LIB_H_ */
diff --git a/apps/restconf/restconf_main.c b/apps/restconf/restconf_main.c
index 92822e80..cc6dabef 100644
--- a/apps/restconf/restconf_main.c
+++ b/apps/restconf/restconf_main.c
@@ -397,7 +397,7 @@ api_restconf(clicon_handle h,
if (netconf_access_denied_xml(&xret, "protocol", "The requested URL was unauthorized") < 0)
goto done;
if ((xerr = xpath_first(xret, "//rpc-error")) != NULL){
- if (api_return_err(h, r, xerr, pretty, use_xml) < 0)
+ if (api_return_err(h, r, xerr, pretty, use_xml, 0) < 0)
goto done;
goto ok;
}
diff --git a/apps/restconf/restconf_methods.c b/apps/restconf/restconf_methods.c
index 79571982..9a288f5b 100644
--- a/apps/restconf/restconf_methods.c
+++ b/apps/restconf/restconf_methods.c
@@ -214,7 +214,7 @@ api_data_get2(clicon_handle h,
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
goto done;
}
- if (api_return_err(h, r, xe, pretty, use_xml) < 0)
+ if (api_return_err(h, r, xe, pretty, use_xml, 0) < 0)
goto done;
goto ok;
}
@@ -227,7 +227,7 @@ api_data_get2(clicon_handle h,
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
goto done;
}
- if (api_return_err(h, r, xe, pretty, use_xml) < 0)
+ if (api_return_err(h, r, xe, pretty, use_xml, 0) < 0)
goto done;
goto ok;
}
@@ -246,7 +246,7 @@ api_data_get2(clicon_handle h,
#endif
/* Check if error return */
if ((xe = xpath_first(xret, "//rpc-error")) != NULL){
- if (api_return_err(h, r, xe, pretty, use_xml) < 0)
+ if (api_return_err(h, r, xe, pretty, use_xml, 0) < 0)
goto done;
goto ok;
}
@@ -277,7 +277,20 @@ api_data_get2(clicon_handle h,
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
goto done;
}
- if (api_return_err(h, r, xe, pretty, use_xml) < 0)
+ if (api_return_err(h, r, xe, pretty, use_xml, 0) < 0)
+ goto done;
+ goto ok;
+ }
+ /* Check if not exists */
+ if (xlen == 0){
+ /* 4.3: If a retrieval request for a data resource represents an
+ instance that does not exist, then an error response containing
+ a "404 Not Found" status-line MUST be returned by the server.
+ The error-tag value "invalid-value" is used in this case. */
+ if (netconf_invalid_value_xml(&xe, "application", "Instance does not exist") < 0)
+ goto done;
+ /* override invalid-value default 400 with 404 */
+ if (api_return_err(h, r, xe, pretty, use_xml, 404) < 0)
goto done;
goto ok;
}
@@ -487,7 +500,7 @@ api_data_post(clicon_handle h,
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
goto done;
}
- if (api_return_err(h, r, xe, pretty, use_xml) < 0)
+ if (api_return_err(h, r, xe, pretty, use_xml, 0) < 0)
goto done;
goto ok;
}
@@ -501,7 +514,7 @@ api_data_post(clicon_handle h,
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
goto done;
}
- if (api_return_err(h, r, xe, pretty, use_xml) < 0)
+ if (api_return_err(h, r, xe, pretty, use_xml, 0) < 0)
goto done;
goto ok;
}
@@ -514,7 +527,7 @@ api_data_post(clicon_handle h,
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
goto done;
}
- if (api_return_err(h, r, xe, pretty, use_xml) < 0)
+ if (api_return_err(h, r, xe, pretty, use_xml, 0) < 0)
goto done;
goto ok;
}
@@ -523,7 +536,7 @@ api_data_post(clicon_handle h,
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
goto done;
}
- if (api_return_err(h, r, xe, pretty, use_xml) < 0)
+ if (api_return_err(h, r, xe, pretty, use_xml, 0) < 0)
goto done;
goto ok;
}
@@ -538,7 +551,7 @@ api_data_post(clicon_handle h,
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
goto done;
}
- if (api_return_err(h, r, xe, pretty, use_xml) < 0)
+ if (api_return_err(h, r, xe, pretty, use_xml, 0) < 0)
goto done;
goto ok;
}
@@ -560,14 +573,15 @@ api_data_post(clicon_handle h,
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)
+#if 0
+ 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));
+ }
+#endif
+ if (api_return_err(h, r, xe, pretty, use_xml, 0) < 0)
goto done;
goto ok;
}
@@ -599,7 +613,7 @@ api_data_post(clicon_handle h,
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)
+ if (api_return_err(h, r, xe, pretty, use_xml, 0) < 0)
goto done;
goto ok;
}
@@ -621,7 +635,7 @@ api_data_post(clicon_handle h,
/* log errors from discard, but ignore */
if ((xpath_first(xretdis, "//rpc-error")) != NULL)
clicon_log(LOG_WARNING, "%s: discard-changes failed which may lead candidate in an inconsistent state", __FUNCTION__);
- if (api_return_err(h, r, xe, pretty, use_xml) < 0) /* Use original xe */
+ if (api_return_err(h, r, xe, pretty, use_xml, 0) < 0) /* Use original xe */
goto done;
goto ok;
}
@@ -835,7 +849,7 @@ api_data_put(clicon_handle h,
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
goto done;
}
- if (api_return_err(h, r, xe, pretty, use_xml) < 0)
+ if (api_return_err(h, r, xe, pretty, use_xml, 0) < 0)
goto done;
goto ok;
}
@@ -850,7 +864,7 @@ api_data_put(clicon_handle h,
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
goto done;
}
- if (api_return_err(h, r, xe, pretty, use_xml) < 0)
+ if (api_return_err(h, r, xe, pretty, use_xml, 0) < 0)
goto done;
goto ok;
}
@@ -863,7 +877,7 @@ api_data_put(clicon_handle h,
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
goto done;
}
- if (api_return_err(h, r, xe, pretty, use_xml) < 0)
+ if (api_return_err(h, r, xe, pretty, use_xml, 0) < 0)
goto done;
goto ok;
}
@@ -872,7 +886,7 @@ api_data_put(clicon_handle h,
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
goto done;
}
- if (api_return_err(h, r, xe, pretty, use_xml) < 0)
+ if (api_return_err(h, r, xe, pretty, use_xml, 0) < 0)
goto done;
goto ok;
}
@@ -887,7 +901,7 @@ api_data_put(clicon_handle h,
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
goto done;
}
- if (api_return_err(h, r, xe, pretty, use_xml) < 0)
+ if (api_return_err(h, r, xe, pretty, use_xml, 0) < 0)
goto done;
goto ok;
}
@@ -907,7 +921,7 @@ api_data_put(clicon_handle h,
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
goto done;
}
- if (api_return_err(h, r, xe, pretty, use_xml) < 0)
+ if (api_return_err(h, r, xe, pretty, use_xml, 0) < 0)
goto done;
goto ok;
}
@@ -947,7 +961,7 @@ api_data_put(clicon_handle h,
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
goto done;
}
- if (api_return_err(h, r, xe, pretty, use_xml) < 0)
+ if (api_return_err(h, r, xe, pretty, use_xml, 0) < 0)
goto done;
goto ok;
}
@@ -972,7 +986,7 @@ api_data_put(clicon_handle h,
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
goto done;
}
- if (api_return_err(h, r, xe, pretty, use_xml) < 0)
+ if (api_return_err(h, r, xe, pretty, use_xml, 0) < 0)
goto done;
goto ok;
}
@@ -996,7 +1010,7 @@ api_data_put(clicon_handle h,
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
goto done;
}
- if (api_return_err(h, r, xe, pretty, use_xml) < 0)
+ if (api_return_err(h, r, xe, pretty, use_xml, 0) < 0)
goto done;
goto ok;
}
@@ -1033,7 +1047,7 @@ api_data_put(clicon_handle h,
goto done;
if ((xe = xpath_first(xret, "//rpc-error")) != NULL){
- if (api_return_err(h, r, xe, pretty, use_xml) < 0)
+ if (api_return_err(h, r, xe, pretty, use_xml, 0) < 0)
goto done;
goto ok;
}
@@ -1054,7 +1068,7 @@ api_data_put(clicon_handle h,
/* log errors from discard, but ignore */
if ((xpath_first(xretdis, "//rpc-error")) != NULL)
clicon_log(LOG_WARNING, "%s: discard-changes failed which may lead candidate in an inconsistent state", __FUNCTION__);
- if (api_return_err(h, r, xe, pretty, use_xml) < 0)
+ if (api_return_err(h, r, xe, pretty, use_xml, 0) < 0)
goto done;
goto ok;
}
@@ -1187,7 +1201,7 @@ api_data_delete(clicon_handle h,
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
goto done;
}
- if (api_return_err(h, r, xe, pretty, use_xml) < 0)
+ if (api_return_err(h, r, xe, pretty, use_xml, 0) < 0)
goto done;
goto ok;
}
@@ -1211,7 +1225,7 @@ api_data_delete(clicon_handle h,
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)
+ if (api_return_err(h, r, xe, pretty, use_xml, 0) < 0)
goto done;
goto ok;
}
@@ -1233,7 +1247,7 @@ api_data_delete(clicon_handle h,
/* log errors from discard, but ignore */
if ((xpath_first(xretdis, "//rpc-error")) != NULL)
clicon_log(LOG_WARNING, "%s: discard-changes failed which may lead candidate in an inconsistent state", __FUNCTION__);
- if (api_return_err(h, r, xe, pretty, use_xml) < 0)
+ if (api_return_err(h, r, xe, pretty, use_xml, 0) < 0)
goto done;
goto ok;
}
@@ -1425,7 +1439,7 @@ api_operations_post_input(clicon_handle h,
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
goto done;
}
- if (api_return_err(h, r, xe, pretty, use_xml) < 0)
+ if (api_return_err(h, r, xe, pretty, use_xml, 0) < 0)
goto done;
goto fail;
}
@@ -1438,7 +1452,7 @@ api_operations_post_input(clicon_handle h,
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
goto done;
}
- if (api_return_err(h, r, xe, pretty, use_xml) < 0)
+ if (api_return_err(h, r, xe, pretty, use_xml, 0) < 0)
goto done;
goto fail;
}
@@ -1447,7 +1461,7 @@ api_operations_post_input(clicon_handle h,
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
goto done;
}
- if (api_return_err(h, r, xe, pretty, use_xml) < 0)
+ if (api_return_err(h, r, xe, pretty, use_xml, 0) < 0)
goto done;
goto fail;
}
@@ -1480,7 +1494,7 @@ api_operations_post_input(clicon_handle h,
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
goto done;
}
- if (api_return_err(h, r, xe, pretty, use_xml) < 0)
+ if (api_return_err(h, r, xe, pretty, use_xml, 0) < 0)
goto done;
goto fail;
}
@@ -1554,7 +1568,7 @@ api_operations_post_output(clicon_handle h,
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
goto done;
}
- if (api_return_err(h, r, xe, pretty, use_xml) < 0)
+ if (api_return_err(h, r, xe, pretty, use_xml, 0) < 0)
goto done;
goto fail;
}
@@ -1591,7 +1605,7 @@ api_operations_post_output(clicon_handle h,
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
goto done;
}
- if (api_return_err(h, r, xe, pretty, use_xml) < 0)
+ if (api_return_err(h, r, xe, pretty, use_xml, 0) < 0)
goto done;
goto fail;
}
@@ -1724,7 +1738,7 @@ api_operations_post(clicon_handle h,
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
goto done;
}
- if (api_return_err(h, r, xe, pretty, use_xml) < 0)
+ if (api_return_err(h, r, xe, pretty, use_xml, 0) < 0)
goto done;
goto ok;
}
@@ -1743,7 +1757,7 @@ api_operations_post(clicon_handle h,
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
goto done;
}
- if (api_return_err(h, r, xe, pretty, use_xml) < 0)
+ if (api_return_err(h, r, xe, pretty, use_xml, 0) < 0)
goto done;
goto ok;
}
@@ -1754,7 +1768,7 @@ api_operations_post(clicon_handle h,
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
goto done;
}
- if (api_return_err(h, r, xe, pretty, use_xml) < 0)
+ if (api_return_err(h, r, xe, pretty, use_xml, 0) < 0)
goto done;
goto ok;
}
@@ -1783,7 +1797,7 @@ api_operations_post(clicon_handle h,
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
goto done;
}
- if (api_return_err(h, r, xe, pretty, use_xml) < 0)
+ if (api_return_err(h, r, xe, pretty, use_xml, 0) < 0)
goto done;
goto ok;
}
@@ -1823,7 +1837,7 @@ api_operations_post(clicon_handle h,
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
goto ok;
}
- if (api_return_err(h, r, xe, pretty, use_xml) < 0)
+ if (api_return_err(h, r, xe, pretty, use_xml, 0) < 0)
goto done;
goto ok;
}
@@ -1852,7 +1866,7 @@ api_operations_post(clicon_handle h,
goto done;
/* Local error: return it and quit */
if ((xe = xpath_first(xret, "rpc-reply/rpc-error")) != NULL){
- if (api_return_err(h, r, xe, pretty, use_xml) < 0)
+ if (api_return_err(h, r, xe, pretty, use_xml, 0) < 0)
goto done;
goto ok;
}
@@ -1861,7 +1875,7 @@ api_operations_post(clicon_handle h,
if (clicon_rpc_netconf_xml(h, xtop, &xret, NULL) < 0)
goto done;
if ((xe = xpath_first(xret, "rpc-reply/rpc-error")) != NULL){
- if (api_return_err(h, r, xe, pretty, use_xml) < 0)
+ if (api_return_err(h, r, xe, pretty, use_xml, 0) < 0)
goto done;
goto ok;
}
diff --git a/apps/restconf/restconf_stream.c b/apps/restconf/restconf_stream.c
index 3d34c798..5c633347 100644
--- a/apps/restconf/restconf_stream.c
+++ b/apps/restconf/restconf_stream.c
@@ -269,7 +269,7 @@ restconf_stream(clicon_handle h,
if (clicon_rpc_netconf(h, cbuf_get(cb), &xret, &s) < 0)
goto done;
if ((xe = xpath_first(xret, "rpc-reply/rpc-error")) != NULL){
- if (api_return_err(h, r, xe, pretty, use_xml) < 0)
+ if (api_return_err(h, r, xe, pretty, use_xml, 0) < 0)
goto done;
goto ok;
}
@@ -417,7 +417,7 @@ api_stream(clicon_handle h,
if (netconf_access_denied_xml(&xret, "protocol", "The requested URL was unauthorized") < 0)
goto done;
if ((xerr = xpath_first(xret, "//rpc-error")) != NULL){
- if (api_return_err(h, r, xerr, pretty, use_xml) < 0)
+ if (api_return_err(h, r, xerr, pretty, use_xml, 0) < 0)
goto done;
goto ok;
}
diff --git a/lib/clixon/clixon_netconf_lib.h b/lib/clixon/clixon_netconf_lib.h
index f3651da5..83fc2117 100644
--- a/lib/clixon/clixon_netconf_lib.h
+++ b/lib/clixon/clixon_netconf_lib.h
@@ -43,6 +43,7 @@
*/
int netconf_in_use(cbuf *cb, char *type, char *message);
int netconf_invalid_value(cbuf *cb, char *type, char *message);
+int netconf_invalid_value_xml(cxobj **xret, char *type, char *message);
int netconf_too_big(cbuf *cb, char *type, char *message);
int netconf_missing_attribute(cbuf *cb, char *type, char *info, char *message);
int netconf_bad_attribute(cbuf *cb, char *type, char *info, char *message);
diff --git a/lib/src/clixon_netconf_lib.c b/lib/src/clixon_netconf_lib.c
index bf59a9bb..56bceacd 100644
--- a/lib/src/clixon_netconf_lib.c
+++ b/lib/src/clixon_netconf_lib.c
@@ -108,6 +108,48 @@ netconf_in_use(cbuf *cb,
goto done;
}
+/*! Create Netconf invalid-value error XML tree according to RFC 6241 Appendix A
+ *
+ * The request specifies an unacceptable value for one or more parameters.
+ * @param[out] xret Error XML tree. Free with xml_free after use
+ * @param[in] type Error type: "application" or "protocol"
+ * @param[in] message Error message (will be XML encoded)
+ */
+int
+netconf_invalid_value_xml(cxobj **xret,
+ char *type,
+ char *message)
+{
+ int retval =-1;
+ cxobj *xerr;
+ char *encstr = NULL;
+
+ if (*xret == NULL){
+ if ((*xret = xml_new("rpc-reply", NULL, NULL)) == NULL)
+ goto done;
+ }
+ else if (xml_name_set(*xret, "rpc-reply") < 0)
+ goto done;
+ if ((xerr = xml_new("rpc-error", *xret, NULL)) == NULL)
+ goto done;
+ if (xml_parse_va(&xerr, NULL, "%s"
+ "invalid-value"
+ "error", type) < 0)
+ goto done;
+ if (message){
+ if (xml_chardata_encode(&encstr, "%s", message) < 0)
+ goto done;
+ if (xml_parse_va(&xerr, NULL, "%s",
+ encstr) < 0)
+ goto done;
+ }
+ retval = 0;
+ done:
+ if (encstr)
+ free(encstr);
+ return retval;
+}
+
/*! Create Netconf invalid-value error XML tree according to RFC 6241 Appendix A
*
* The request specifies an unacceptable value for one or more parameters.
@@ -120,6 +162,20 @@ netconf_invalid_value(cbuf *cb,
char *type,
char *message)
{
+#if 1
+ int retval = -1;
+ cxobj *xret = NULL;
+
+ if (netconf_invalid_value_xml(&xret, type, message) < 0)
+ goto done;
+ if (clicon_xml2cbuf(cb, xret, 0, 0) < 0)
+ goto done;
+ retval = 0;
+ done:
+ if (xret)
+ xml_free(xret);
+ return retval;
+#else
int retval = -1;
char *encstr = NULL;
@@ -145,6 +201,7 @@ netconf_invalid_value(cbuf *cb,
err:
clicon_err(OE_XML, errno, "cprintf");
goto done;
+#endif
}
/*! Create Netconf too-big error XML tree according to RFC 6241 Appendix A
diff --git a/test/test_nacm.sh b/test/test_nacm.sh
index 042b6d75..c50308ab 100755
--- a/test/test_nacm.sh
+++ b/test/test_nacm.sh
@@ -132,8 +132,7 @@ wait_backend
wait_restconf
new "auth get"
-expecteq "$(curl -u andy:bar -sS -X GET http://localhost/restconf/data/nacm-example:x)" 0 'null
-
'
+expecteq "$(curl -u andy:bar -sS -X GET http://localhost/restconf/data/nacm-example:x)" 0 '{"ietf-restconf:errors" : {"error": {"rpc-error": {"error-type": "application","error-tag": "invalid-value","error-severity": "error","error-message": "Instance does not exist"}}}}
'
# explicitly disable nacm (regression on netgate bug)
new "disable nacm"
diff --git a/test/test_nacm_default.sh b/test/test_nacm_default.sh
index 7bceadbf..224c8b78 100755
--- a/test/test_nacm_default.sh
+++ b/test/test_nacm_default.sh
@@ -115,8 +115,7 @@ EOF
;;
1) ret='{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "access-denied","error-severity": "error","error-message": "default deny"}}}
'
;;
- 2) ret='null
-
'
+ 2) ret='{"ietf-restconf:errors" : {"error": {"rpc-error": {"error-type": "application","error-tag": "invalid-value","error-severity": "error","error-message": "Instance does not exist"}}}}
'
;;
esac
@@ -140,8 +139,7 @@ EOF
;;
1) ret='{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "access-denied","error-severity": "error","error-message": "default deny"}}}
'
;;
- 2) ret='null
-
'
+ 2) ret='{"ietf-restconf:errors" : {"error": {"rpc-error": {"error-type": "application","error-tag": "invalid-value","error-severity": "error","error-message": "Instance does not exist"}}}}
'
;;
3) ret='{"nacm-example:x": 42}
'
diff --git a/test/test_nacm_module_read.sh b/test/test_nacm_module_read.sh
index 365d6dcf..6b64ab90 100755
--- a/test/test_nacm_module_read.sh
+++ b/test/test_nacm_module_read.sh
@@ -200,8 +200,7 @@ expecteq "$(curl -u wilma:bar -sS -X GET http://localhost/restconf/data/clixon-e
'
new "limit read other module fail"
-expecteq "$(curl -u wilma:bar -sS -X GET http://localhost/restconf/data/nacm-example:x)" 0 'null
-
'
+expecteq "$(curl -u wilma:bar -sS -X GET http://localhost/restconf/data/nacm-example:x)" 0 '{"ietf-restconf:errors" : {"error": {"rpc-error": {"error-type": "application","error-tag": "invalid-value","error-severity": "error","error-message": "Instance does not exist"}}}}
'
new "limit read state OK"
expecteq "$(curl -u wilma:bar -sS -X GET http://localhost/restconf/data/clixon-example:state)" 0 '{"clixon-example:state": {"op": ["42","41","43"]}}
diff --git a/test/test_nacm_protocol.sh b/test/test_nacm_protocol.sh
index 4aa851cd..59ce33c7 100755
--- a/test/test_nacm_protocol.sh
+++ b/test/test_nacm_protocol.sh
@@ -191,9 +191,8 @@ expecteq "$(curl -u guest:bar -sS -X DELETE http://localhost/restconf/data)" 0 '
new "deny-delete-config: limited fail (restconf) ok"
expecteq "$(curl -u wilma:bar -sS -X DELETE http://localhost/restconf/data)" 0 ''
-new "admin get nacm (should be null)"
-expecteq "$(curl -u andy:bar -sS -X GET http://localhost/restconf/data/nacm-example:x)" 0 'null
-
'
+new "admin get nacm (should fail)"
+expecteq "$(curl -u andy:bar -sS -X GET http://localhost/restconf/data/nacm-example:x)" 0 '{"ietf-restconf:errors" : {"error": {"rpc-error": {"error-type": "application","error-tag": "invalid-value","error-severity": "error","error-message": "Instance does not exist"}}}}
'
new "deny-delete-config: admin ok (restconf)"
expecteq "$(curl -u andy:bar -sS -X DELETE http://localhost/restconf/data)" 0 ''
diff --git a/test/test_restconf2.sh b/test/test_restconf2.sh
index 84aba720..ec1486d7 100755
--- a/test/test_restconf2.sh
+++ b/test/test_restconf2.sh
@@ -137,7 +137,7 @@ new "restconf DELETE"
expectfn 'curl -s -X DELETE http://localhost/restconf/data/example:cont1' 0 ""
new "restconf GET null datastore"
-expectfn "curl -s -X GET http://localhost/restconf/data/example:cont1" 0 'null'
+expectfn "curl -s -X GET http://localhost/restconf/data/example:cont1" 0 '{"ietf-restconf:errors" : {"error": {"rpc-error": {"error-type": "application","error-tag": "invalid-value","error-severity": "error","error-message": "Instance does not exist"}}}}'
new "restconf POST initial tree"
expectfn 'curl -s -X POST -d {"example:cont1":{"interface":{"name":"local0","type":"regular"}}} http://localhost/restconf/data' 0 ""
@@ -149,7 +149,7 @@ new "restconf DELETE whole datastore"
expectfn 'curl -s -X DELETE http://localhost/restconf/data' 0 ""
new "restconf GET null datastore"
-expectfn "curl -s -X GET http://localhost/restconf/data/example:cont1" 0 'null'
+expectfn "curl -s -X GET http://localhost/restconf/data/example:cont1" 0 '{"ietf-restconf:errors" : {"error": {"rpc-error": {"error-type": "application","error-tag": "invalid-value","error-severity": "error","error-message": "Instance does not exist"}}}}'
new "restconf PUT initial datastore"
expectfn 'curl -s -X PUT -d {"data":{"example:cont1":{"interface":{"name":"local0","type":"regular"}}}} http://localhost/restconf/data' 0 ""
diff --git a/test/test_restconf_err.sh b/test/test_restconf_err.sh
new file mode 100755
index 00000000..fb5e27da
--- /dev/null
+++ b/test/test_restconf_err.sh
@@ -0,0 +1,120 @@
+#!/bin/bash
+# Restconf error-code functionality
+# See RFC8040
+# Testcases:
+# Sec 4.3 (GET): If a retrieval request for a data resource represents an
+# instance that does not exist, then an error response containing a "404 Not
+# Found" status-line MUST be returned by the server. The error-tag
+# value "invalid-value" is used in this case.
+
+# Magic line must be first in script (see README.md)
+s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi
+
+APPNAME=example
+
+cfg=$dir/conf.xml
+fyang=$dir/restconf.yang
+fxml=$dir/initial.xml
+
+# example
+cat < $cfg
+
+ $cfg
+ /usr/local/share/clixon
+ $IETFRFC
+ $fyang
+ false
+ /usr/local/var/$APPNAME/$APPNAME.sock
+ $dir/restconf.pidfile
+ /usr/local/var/$APPNAME
+
+EOF
+
+cat < $fyang
+module example{
+ yang-version 1.1;
+ namespace "urn:example:clixon";
+ prefix ex;
+ list a {
+ key k;
+ leaf k {
+ type int32;
+ }
+ leaf description{
+ type string;
+ }
+ leaf b{
+ type string;
+ }
+ container c{
+ presence "for test";
+ }
+ list d{
+ key k;
+ leaf k {
+ type string;
+ }
+ }
+ }
+}
+EOF
+
+# Initial tree
+XML=$(cat <0No leaf b, No container c, No leaf d
+EOF
+ )
+
+new "test params: -f $cfg"
+
+if [ $BE -ne 0 ]; then
+ new "kill old backend"
+ sudo clixon_backend -zf $cfg
+ if [ $? -ne 0 ]; then
+ err
+ fi
+ sudo pkill clixon_backend # to be sure
+ new "start backend -s init -f $cfg"
+ start_backend -s init -f $cfg
+fi
+
+new "kill old restconf daemon"
+sudo pkill -u www-data -f "/www-data/clixon_restconf"
+
+new "start restconf daemon"
+start_restconf -f $cfg
+
+new "waiting"
+wait_backend
+wait_restconf
+
+new "restconf POST initial tree"
+expecteq "$(curl -s -X POST -H 'Content-Type: application/yang-data+xml' -d "$XML" http://localhost/restconf/data)" 0 ''
+
+new "restconf GET initial datastore"
+expecteq "$(curl -s -X GET -H 'Accept: application/yang-data+xml' http://localhost/restconf/data/example:a)" 0 "$XML
+
"
+
+new "restconf GET non-existent container header"
+expectfn "curl -s -I -X GET http://localhost/restconf/data/example:a/c" 0 "HTTP/1.1 404 Not Found"
+
+new "restconf GET non-existent container body"
+expectfn "curl -s -X GET http://localhost/restconf/data/example:a/c" 0 '{"ietf-restconf:errors" : {"error": {"rpc-error": {"error-type": "application","error-tag": "invalid-value","error-severity": "error","error-message": "Instance does not exist"}}}}'
+
+new "Kill restconf daemon"
+stop_restconf
+
+if [ $BE -eq 0 ]; then
+ exit # BE
+fi
+
+new "Kill backend"
+# Check if premature kill
+pid=`pgrep -u root -f clixon_backend`
+if [ -z "$pid" ]; then
+ err "backend already dead"
+fi
+# kill backend
+stop_backend -f $cfg
+
+rm -rf $dir