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