From cea574659750329e53ce5426966d16220adfce88 Mon Sep 17 00:00:00 2001 From: Olof hagsand Date: Sun, 14 Jun 2020 18:01:31 +0200 Subject: [PATCH] Fixed: The module `clixon-rfc5277` was always enabled, but should only be enabled when `CLICON_STREAM_DISCOVERY_RFC5277` is enabled. --- CHANGELOG.md | 4 + apps/restconf/restconf_fcgi_lib.c | 174 +++++++++++++++--------------- test/test_restconf.sh | 4 +- test/test_restconf_jukebox.sh | 2 +- 4 files changed, 94 insertions(+), 90 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c08d934f..3a0b3b9a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -60,6 +60,10 @@ Expected: July 2020 * Added new function `clicon_xml2str()` to complement xml_print and others that returns a malloced string. * Added new function `xml_child_index_each()` to iterate over the children of an XML node according to the order defined by an explicit index variable. This is a complement to `xml_child_each()` which iterates using the default order. +### Corrected Bugs + +* Fixed: The module `clixon-rfc5277` was always enabled, but should only be enabled when `CLICON_STREAM_DISCOVERY_RFC5277` is enabled. + ## 4.5.0 12 May 2020 diff --git a/apps/restconf/restconf_fcgi_lib.c b/apps/restconf/restconf_fcgi_lib.c index 5ed0d86b..34ae8c0c 100644 --- a/apps/restconf/restconf_fcgi_lib.c +++ b/apps/restconf/restconf_fcgi_lib.c @@ -65,166 +65,166 @@ #include "restconf_fcgi_lib.h" /*! HTTP error 400 - * @param[in] r Fastcgi request handle + * @param[in] req Fastcgi request handle */ int restconf_badrequest(clicon_handle h, - FCGX_Request *r) + FCGX_Request *req) { char *path; path = clixon_restconf_param_get(h, "REQUEST_URI"); - FCGX_SetExitStatus(400, r->out); - FCGX_FPrintF(r->out, "Status: 400 Bad Request\r\n"); /* 400 bad request */ - FCGX_FPrintF(r->out, "Content-Type: text/html\r\n\r\n"); - FCGX_FPrintF(r->out, "

Clixon Bad request/h1>\n"); - FCGX_FPrintF(r->out, "The requested URL %s or data is in some way badly formed.\n", + FCGX_SetExitStatus(400, req->out); + FCGX_FPrintF(req->out, "Status: 400 Bad Request\r\n"); /* 400 bad request */ + FCGX_FPrintF(req->out, "Content-Type: text/html\r\n\r\n"); + FCGX_FPrintF(req->out, "

Clixon Bad request/h1>\n"); + FCGX_FPrintF(req->out, "The requested URL %s or data is in some way badly formed.\n", path); return 0; } /*! HTTP error 401 - * @param[in] r Fastcgi request handle + * @param[in] req Fastcgi request handle */ int restconf_unauthorized(clicon_handle h, - FCGX_Request *r) + FCGX_Request *req) { char *path; path = clixon_restconf_param_get(h, "REQUEST_URI"); - FCGX_SetExitStatus(401, r->out); - FCGX_FPrintF(r->out, "Status: 401 Unauthorized\r\n"); /* 401 unauthorized */ - FCGX_FPrintF(r->out, "Content-Type: text/html\r\n\r\n"); - FCGX_FPrintF(r->out, "access-denied\n"); - FCGX_FPrintF(r->out, "The requested URL %s was unauthorized.\n", path); + FCGX_SetExitStatus(401, req->out); + FCGX_FPrintF(req->out, "Status: 401 Unauthorized\r\n"); /* 401 unauthorized */ + FCGX_FPrintF(req->out, "Content-Type: text/html\r\n\r\n"); + FCGX_FPrintF(req->out, "access-denied\n"); + FCGX_FPrintF(req->out, "The requested URL %s was unauthorized.\n", path); return 0; } /*! HTTP error 403 - * @param[in] r Fastcgi request handle + * @param[in] req Fastcgi request handle */ int restconf_forbidden(clicon_handle h, - FCGX_Request *r) + FCGX_Request *req) { char *path; path = clixon_restconf_param_get(h, "REQUEST_URI"); - FCGX_SetExitStatus(403, r->out); - FCGX_FPrintF(r->out, "Status: 403 Forbidden\r\n"); /* 403 forbidden */ - FCGX_FPrintF(r->out, "Content-Type: text/html\r\n\r\n"); - FCGX_FPrintF(r->out, "

Forbidden

\n"); - FCGX_FPrintF(r->out, "The requested URL %s was forbidden.\n", path); + FCGX_SetExitStatus(403, req->out); + FCGX_FPrintF(req->out, "Status: 403 Forbidden\r\n"); /* 403 forbidden */ + FCGX_FPrintF(req->out, "Content-Type: text/html\r\n\r\n"); + FCGX_FPrintF(req->out, "

Forbidden

\n"); + FCGX_FPrintF(req->out, "The requested URL %s was forbidden.\n", path); return 0; } /*! HTTP error 404 - * @param[in] r Fastcgi request handle + * @param[in] req Fastcgi request handle */ int restconf_notfound(clicon_handle h, - FCGX_Request *r) + FCGX_Request *req) { char *path; path = clixon_restconf_param_get(h, "REQUEST_URI"); - FCGX_SetExitStatus(404, r->out); - FCGX_FPrintF(r->out, "Status: 404 Not Found\r\n"); /* 404 not found */ - FCGX_FPrintF(r->out, "Content-Type: text/html\r\n\r\n"); - FCGX_FPrintF(r->out, "

Not Found

\n"); - FCGX_FPrintF(r->out, "Not Found\n"); - FCGX_FPrintF(r->out, "The requested URL %s was not found on this server.\n", + FCGX_SetExitStatus(404, req->out); + FCGX_FPrintF(req->out, "Status: 404 Not Found\r\n"); /* 404 not found */ + FCGX_FPrintF(req->out, "Content-Type: text/html\r\n\r\n"); + FCGX_FPrintF(req->out, "

Not Found

\n"); + FCGX_FPrintF(req->out, "Not Found\n"); + FCGX_FPrintF(req->out, "The requested URL %s was not found on this server.\n", path); return 0; } /*! HTTP error 406 Not acceptable - * @param[in] r Fastcgi request handle + * @param[in] req Fastcgi request handle */ int restconf_notacceptable(clicon_handle h, - FCGX_Request *r) + FCGX_Request *req) { char *path; path = clixon_restconf_param_get(h, "REQUEST_URI"); - FCGX_SetExitStatus(406, r->out); - FCGX_FPrintF(r->out, "Status: 406 Not Acceptable\r\n"); /* 406 not acceptible */ + FCGX_SetExitStatus(406, req->out); + FCGX_FPrintF(req->out, "Status: 406 Not Acceptable\r\n"); /* 406 not acceptible */ - FCGX_FPrintF(r->out, "Content-Type: text/html\r\n\r\n"); - FCGX_FPrintF(r->out, "

Not Acceptable

\n"); - FCGX_FPrintF(r->out, "Not Acceptable\n"); - FCGX_FPrintF(r->out, "The target resource does not have a current representation that would be acceptable to the user agent.\n", + FCGX_FPrintF(req->out, "Content-Type: text/html\r\n\r\n"); + FCGX_FPrintF(req->out, "

Not Acceptable

\n"); + FCGX_FPrintF(req->out, "Not Acceptable\n"); + FCGX_FPrintF(req->out, "The target resource does not have a current representation that would be acceptable to the user agent.\n", path); return 0; } /*! HTTP error 409 - * @param[in] r Fastcgi request handle + * @param[in] req Fastcgi request handle */ int -restconf_conflict(FCGX_Request *r) +restconf_conflict(FCGX_Request *req) { - FCGX_SetExitStatus(409, r->out); - FCGX_FPrintF(r->out, "Status: 409 Conflict\r\n"); /* 409 Conflict */ - FCGX_FPrintF(r->out, "Content-Type: text/html\r\n\r\n"); - FCGX_FPrintF(r->out, "

Data resource already exists

\n"); + FCGX_SetExitStatus(409, req->out); + FCGX_FPrintF(req->out, "Status: 409 Conflict\r\n"); /* 409 Conflict */ + FCGX_FPrintF(req->out, "Content-Type: text/html\r\n\r\n"); + FCGX_FPrintF(req->out, "

Data resource already exists

\n"); return 0; } /*! HTTP error 409 - * @param[in] r Fastcgi request handle + * @param[in] req Fastcgi request handle */ int -restconf_unsupported_media(FCGX_Request *r) +restconf_unsupported_media(FCGX_Request *req) { - FCGX_SetExitStatus(415, r->out); - FCGX_FPrintF(r->out, "Status: 415 Unsupported Media Type\r\n"); - FCGX_FPrintF(r->out, "Content-Type: text/html\r\n\r\n"); - FCGX_FPrintF(r->out, "

Unsupported Media Type

\n"); + FCGX_SetExitStatus(415, req->out); + FCGX_FPrintF(req->out, "Status: 415 Unsupported Media Type\r\n"); + FCGX_FPrintF(req->out, "Content-Type: text/html\r\n\r\n"); + FCGX_FPrintF(req->out, "

Unsupported Media Type

\n"); return 0; } /*! HTTP error 500 - * @param[in] r Fastcgi request handle + * @param[in] req Fastcgi request handle */ int restconf_internal_server_error(clicon_handle h, - FCGX_Request *r) + FCGX_Request *req) { char *path; clicon_debug(1, "%s", __FUNCTION__); path = clixon_restconf_param_get(h, "REQUEST_URI"); - FCGX_FPrintF(r->out, "Status: 500 Internal Server Error\r\n"); /* 500 internal server error */ - FCGX_FPrintF(r->out, "Content-Type: text/html\r\n\r\n"); - FCGX_FPrintF(r->out, "

Internal server error when accessing %s

\n", path); + FCGX_FPrintF(req->out, "Status: 500 Internal Server Error\r\n"); /* 500 internal server error */ + FCGX_FPrintF(req->out, "Content-Type: text/html\r\n\r\n"); + FCGX_FPrintF(req->out, "

Internal server error when accessing %s

\n", path); return 0; } /*! HTTP error 501 - * @param[in] r Fastcgi request handle + * @param[in] req Fastcgi request handle */ int -restconf_notimplemented(FCGX_Request *r) +restconf_notimplemented(FCGX_Request *req) { clicon_debug(1, "%s", __FUNCTION__); - FCGX_FPrintF(r->out, "Status: 501 Not Implemented\r\n"); - FCGX_FPrintF(r->out, "Content-Type: text/html\r\n\r\n"); - FCGX_FPrintF(r->out, "

Not Implemented/h1>\n"); + FCGX_FPrintF(req->out, "Status: 501 Not Implemented\r\n"); + FCGX_FPrintF(req->out, "Content-Type: text/html\r\n\r\n"); + FCGX_FPrintF(req->out, "

Not Implemented/h1>\n"); return 0; } /*! Print all FCGI headers - * @param[in] r Fastcgi request handle + * @param[in] req Fastcgi request handle * @see https://nginx.org/en/docs/http/ngx_http_core_module.html#var_https */ int -restconf_test(FCGX_Request *r, +restconf_test(FCGX_Request *req, int dbg) { - char **environ = r->envp; + char **environ = req->envp; int i; clicon_debug(1, "All environment vars:"); @@ -303,24 +303,24 @@ clixon_restconf_params_clear(clicon_handle h, } /*! - * @param[in] r Fastcgi request handle + * @param[in] req Fastcgi request handle */ cbuf * -readdata(FCGX_Request *r) +readdata(FCGX_Request *req) { int c; cbuf *cb; if ((cb = cbuf_new()) == NULL) return NULL; - while ((c = FCGX_GetChar(r->in)) != -1) + while ((c = FCGX_GetChar(req->in)) != -1) cprintf(cb, "%c", c); return cb; } /*! Return restconf error on get/head request * @param[in] h Clixon handle - * @param[in] r Fastcgi request handle + * @param[in] req Fastcgi request handle * @param[in] xerr XML error message from backend * @param[in] pretty Set to 1 for pretty-printed xml/json output * @param[in] media Output media @@ -329,7 +329,7 @@ readdata(FCGX_Request *r) */ int api_return_err(clicon_handle h, - FCGX_Request *r, + FCGX_Request *req, cxobj *xerr, int pretty, restconf_media media, @@ -381,23 +381,23 @@ api_return_err(clicon_handle h, } if ((reason_phrase = restconf_code2reason(code)) == NULL) reason_phrase=""; - FCGX_SetExitStatus(code, r->out); /* Created */ - FCGX_FPrintF(r->out, "Status: %d %s\r\n", code, reason_phrase); - FCGX_FPrintF(r->out, "Content-Type: %s\r\n\r\n", restconf_media_int2str(media)); + FCGX_SetExitStatus(code, req->out); /* Created */ + FCGX_FPrintF(req->out, "Status: %d %s\r\n", code, reason_phrase); + FCGX_FPrintF(req->out, "Content-Type: %s\r\n\r\n", restconf_media_int2str(media)); switch (media){ case YANG_DATA_XML: if (clicon_xml2cbuf(cb, xerr, 2, pretty, -1) < 0) goto done; clicon_debug(1, "%s code:%d err:%s", __FUNCTION__, code, cbuf_get(cb)); if (pretty){ - FCGX_FPrintF(r->out, " \n", cbuf_get(cb)); - FCGX_FPrintF(r->out, "%s", cbuf_get(cb)); - FCGX_FPrintF(r->out, " \r\n"); + FCGX_FPrintF(req->out, " \n", cbuf_get(cb)); + FCGX_FPrintF(req->out, "%s", cbuf_get(cb)); + FCGX_FPrintF(req->out, " \r\n"); } else { - FCGX_FPrintF(r->out, "", cbuf_get(cb)); - FCGX_FPrintF(r->out, "%s", cbuf_get(cb)); - FCGX_FPrintF(r->out, "\r\n"); + FCGX_FPrintF(req->out, "", cbuf_get(cb)); + FCGX_FPrintF(req->out, "%s", cbuf_get(cb)); + FCGX_FPrintF(req->out, "\r\n"); } break; case YANG_DATA_JSON: @@ -405,16 +405,16 @@ api_return_err(clicon_handle h, goto done; clicon_debug(1, "%s code:%d err:%s", __FUNCTION__, code, cbuf_get(cb)); if (pretty){ - FCGX_FPrintF(r->out, "{\n"); - FCGX_FPrintF(r->out, " \"ietf-restconf:errors\" : %s\n", + FCGX_FPrintF(req->out, "{\n"); + FCGX_FPrintF(req->out, " \"ietf-restconf:errors\" : %s\n", cbuf_get(cb)); - FCGX_FPrintF(r->out, "}\r\n"); + FCGX_FPrintF(req->out, "}\r\n"); } else{ - FCGX_FPrintF(r->out, "{"); - FCGX_FPrintF(r->out, "\"ietf-restconf:errors\":"); - FCGX_FPrintF(r->out, "%s", cbuf_get(cb)); - FCGX_FPrintF(r->out, "}\r\n"); + FCGX_FPrintF(req->out, "{"); + FCGX_FPrintF(req->out, "\"ietf-restconf:errors\":"); + FCGX_FPrintF(req->out, "%s", cbuf_get(cb)); + FCGX_FPrintF(req->out, "}\r\n"); } break; default: @@ -434,14 +434,14 @@ api_return_err(clicon_handle h, } /*! Print location header from FCGI environment - * @param[in] r Fastcgi request handle + * @param[in] req Fastcgi request handle * @param[in] xobj If set (eg POST) add to api-path * $https “on” if connection operates in SSL mode, or an empty string otherwise * @note ports are ignored */ int http_location(clicon_handle h, - FCGX_Request *r, + FCGX_Request *req, cxobj *xobj) { int retval = -1; @@ -460,14 +460,14 @@ http_location(clicon_handle h, } if (xml2api_path_1(xobj, cb) < 0) goto done; - FCGX_FPrintF(r->out, "Location: http%s://%s%s%s\r\n", + FCGX_FPrintF(req->out, "Location: http%s://%s%s%s\r\n", https?"s":"", host, request_uri, cbuf_get(cb)); } else - FCGX_FPrintF(r->out, "Location: http%s://%s%s\r\n", + FCGX_FPrintF(req->out, "Location: http%s://%s%s\r\n", https?"s":"", host, request_uri); diff --git a/test/test_restconf.sh b/test/test_restconf.sh index 72d81247..9bb0ff5c 100755 --- a/test/test_restconf.sh +++ b/test/test_restconf.sh @@ -73,11 +73,11 @@ expectpart "$(curl -si -X GET -H 'Accept: application/yang-data+xml' $RCPROTO:// # Should be alphabetically ordered new "restconf get restconf/operations. RFC8040 3.3.2 (json)" -expectpart "$(curl -si -X GET $RCPROTO://localhost/restconf/operations)" 0 'HTTP/1.1 200 OK' '{"operations":{"clixon-example:client-rpc":\[null\],"clixon-example:empty":\[null\],"clixon-example:optional":\[null\],"clixon-example:example":\[null\],"clixon-lib:debug":\[null\],"clixon-lib:ping":\[null\],"clixon-lib:stats":\[null\],"clixon-lib:restart-plugin":\[null\],"ietf-netconf:get-config":\[null\],"ietf-netconf:edit-config":\[null\],"ietf-netconf:copy-config":\[null\],"ietf-netconf:delete-config":\[null\],"ietf-netconf:lock":\[null\],"ietf-netconf:unlock":\[null\],"ietf-netconf:get":\[null\],"ietf-netconf:close-session":\[null\],"ietf-netconf:kill-session":\[null\],"ietf-netconf:commit":\[null\],"ietf-netconf:discard-changes":\[null\],"ietf-netconf:validate":\[null\],"clixon-rfc5277:create-subscription":\[null\]}}' +expectpart "$(curl -si -X GET $RCPROTO://localhost/restconf/operations)" 0 'HTTP/1.1 200 OK' '{"operations":{"clixon-example:client-rpc":\[null\],"clixon-example:empty":\[null\],"clixon-example:optional":\[null\],"clixon-example:example":\[null\],"clixon-lib:debug":\[null\],"clixon-lib:ping":\[null\],"clixon-lib:stats":\[null\],"clixon-lib:restart-plugin":\[null\],"ietf-netconf:get-config":\[null\],"ietf-netconf:edit-config":\[null\],"ietf-netconf:copy-config":\[null\],"ietf-netconf:delete-config":\[null\],"ietf-netconf:lock":\[null\],"ietf-netconf:unlock":\[null\],"ietf-netconf:get":\[null\],"ietf-netconf:close-session":\[null\],"ietf-netconf:kill-session":\[null\],"ietf-netconf:commit":\[null\],"ietf-netconf:discard-changes":\[null\],"ietf-netconf:validate":\[null\]}}' new "restconf get restconf/operations. RFC8040 3.3.2 (xml)" ret=$(curl -s -X GET -H "Accept: application/yang-data+xml" $RCPROTO://localhost/restconf/operations) -expect='' +expect='' match=`echo $ret | grep --null -Eo "$expect"` if [ -z "$match" ]; then err "$expect" "$ret" diff --git a/test/test_restconf_jukebox.sh b/test/test_restconf_jukebox.sh index 0cd91137..6301d2aa 100755 --- a/test/test_restconf_jukebox.sh +++ b/test/test_restconf_jukebox.sh @@ -101,7 +101,7 @@ expectpart "$(curl -si -X GET -H 'Accept: application/yang-data+xml' $RCPROTO:// # This just catches the header and the jukebox module, the RFC has foo and bar which # seems wrong to recreate new "B.1.2. Retrieve the Server Module Information" -expectpart "$(curl -si -X GET -H 'Accept: application/yang-data+json' $RCPROTO://localhost/restconf/data/ietf-yang-library:modules-state)" 0 "HTTP/1.1 200 OK" 'Cache-Control: no-cache' "Content-Type: application/yang-data+json" '{"ietf-yang-library:modules-state":{"module-set-id":"0","module":\[{"name":"clixon-lib","revision":"2020-04-23","namespace":"http://clicon.org/lib","conformance-type":"implement"},{"name":"clixon-rfc5277","revision":"2008-07-01","namespace":"urn:ietf:params:xml:ns:netmod:notification","conformance-type":"implement"},{"name":"example-events","revision":"","namespace":"urn:example:events","conformance-type":"implement"},{"name":"example-jukebox","revision":"2016-08-15","namespace":"http://example.com/ns/example-jukebox","conformance-type":"implement"},{"name":"example-system","revision":"","namespace":"http://example.com/ns/example-system","conformance-type":"implement"},{"name":"ietf-inet-types","revision":"2013-07-15","namespace":"urn:ietf:params:xml:ns:yang:ietf-inet-types","conformance-type":"implement"},' +expectpart "$(curl -si -X GET -H 'Accept: application/yang-data+json' $RCPROTO://localhost/restconf/data/ietf-yang-library:modules-state)" 0 "HTTP/1.1 200 OK" 'Cache-Control: no-cache' "Content-Type: application/yang-data+json" '{"ietf-yang-library:modules-state":{"module-set-id":"0","module":\[{"name":"clixon-lib","revision":"2020-04-23","namespace":"http://clicon.org/lib","conformance-type":"implement"},{"name":"example-events","revision":"","namespace":"urn:example:events","conformance-type":"implement"},{"name":"example-jukebox","revision":"2016-08-15","namespace":"http://example.com/ns/example-jukebox","conformance-type":"implement"},{"name":"example-system","revision":"","namespace":"http://example.com/ns/example-system","conformance-type":"implement"},{"name":"ietf-inet-types","revision":"2013-07-15","namespace":"urn:ietf:params:xml:ns:yang:ietf-inet-types","conformance-type":"implement"},' new "B.1.3. Retrieve the Server Capability Information" expectpart "$(curl -si -X GET -H 'Accept: application/yang-data+xml' $RCPROTO://localhost/restconf/data/ietf-restconf-monitoring:restconf-state/capabilities)" 0 "HTTP/1.1 200 OK" "Content-Type: application/yang-data+xml" 'Cache-Control: no-cache' 'urn:ietf:params:restconf:capability:defaults:1.0?basic-mode=expliciturn:ietf:params:restconf:capability:depth