Restconf: Fixed http accept/content-type logic

yang mem-leak
This commit is contained in:
Olof hagsand 2024-09-16 13:47:28 +02:00
parent f1d9e26755
commit 158ea40b59
6 changed files with 63 additions and 58 deletions

View file

@ -282,19 +282,20 @@ api_http_data_file(clixon_handle h,
char *pathname, char *pathname,
int head) int head)
{ {
int retval = -1; int retval = -1;
cbuf *cbfile = NULL; cbuf *cbfile = NULL;
char *filename = NULL; char *filename = NULL;
cbuf *cbdata = NULL; cbuf *cbdata = NULL;
FILE *f = NULL; FILE *f = NULL;
off_t fsz = 0; off_t fsz = 0;
long fsize; long fsize;
char *www_data_root = NULL; char *www_data_root = NULL;
char *suffix; char *suffix;
char *media; char *media;
int ret; char *buf = NULL;
char *buf = NULL; size_t sz;
size_t sz; char *media_list = NULL;
int ret;
clixon_debug(CLIXON_DBG_RESTCONF, ""); clixon_debug(CLIXON_DBG_RESTCONF, "");
if ((cbfile = cbuf_new()) == NULL){ if ((cbfile = cbuf_new()) == NULL){
@ -305,7 +306,6 @@ api_http_data_file(clixon_handle h,
clixon_err(OE_RESTCONF, ENOENT, "CLICON_HTTP_DATA_ROOT missing"); clixon_err(OE_RESTCONF, ENOENT, "CLICON_HTTP_DATA_ROOT missing");
goto done; goto done;
} }
cprintf(cbfile, "%s", www_data_root); cprintf(cbfile, "%s", www_data_root);
if (pathname){ if (pathname){
if (strlen(pathname) && pathname[0] != '/'){ if (strlen(pathname) && pathname[0] != '/'){
@ -331,6 +331,19 @@ api_http_data_file(clixon_handle h,
if ((media = clicon_str2str(mime_map, suffix)) == NULL) if ((media = clicon_str2str(mime_map, suffix)) == NULL)
media = "application/octet-stream"; media = "application/octet-stream";
} }
/* 5. Accepted media_out: should check text/html, JavaScript, image, and css
*/
if ((media_list = restconf_param_get(h, "HTTP_ACCEPT")) != NULL){
if (restconf_media_in_list(media, media_list) != 1 &&
restconf_media_in_list("*/*", media_list) != 1) {
/* If the server does not support any of the requested
* output encodings for a request, then it MUST return an error response
* with a "406 Not Acceptable" status-line. */
if (restconf_not_acceptable(h, req, 1, HTTP_DATA_TEXT_HTML) < 0)
goto done;
goto ok;
}
}
/* Size could have been taken from stat() but this reduces the race condition interval /* Size could have been taken from stat() but this reduces the race condition interval
* There is still one without flock * There is still one without flock
*/ */
@ -416,12 +429,11 @@ api_http_data(clixon_handle h,
{ {
int retval = -1; int retval = -1;
char *request_method = NULL; char *request_method = NULL;
char *media_list = NULL;
int head = 0; int head = 0;
int options = 0; int options = 0;
int ret;
cbuf *indata = NULL; cbuf *indata = NULL;
char *path = NULL; char *path = NULL;
int ret;
clixon_debug(CLIXON_DBG_RESTCONF, ""); clixon_debug(CLIXON_DBG_RESTCONF, "");
if (req == NULL){ if (req == NULL){
@ -467,20 +479,6 @@ api_http_data(clixon_handle h,
goto done; goto done;
goto ok; goto ok;
} }
/* 5. Accepted media_out: should check text/html, JavaScript, image, and css
*/
if ((media_list = restconf_param_get(h, "HTTP_ACCEPT")) != NULL){
if (restconf_media_in_list("text/html", media_list) != 1 &&
restconf_media_in_list("*/*", media_list) != 1
&& 0) { /* XXX: not yet */
/* If the server does not support any of the requested
* output encodings for a request, then it MUST return an error response
* with a "406 Not Acceptable" status-line. */
if (restconf_not_acceptable(h, req, 1, HTTP_DATA_TEXT_HTML) < 0)
goto done;
goto ok;
}
}
/* 6. Authenticate /* 6. Authenticate
* Note, error handling may need change since it is restconf based * Note, error handling may need change since it is restconf based
*/ */

View file

@ -78,7 +78,7 @@ openconfig:
./getopenconfig.sh ./getopenconfig.sh
docker: clixon yang openconfig $(DOCKERFILE) docker: clixon yang openconfig $(DOCKERFILE)
sudo docker build -f $(DOCKERFILE) -t $(IMG) $(DOCKERFLAGS) . sudo docker build --progress plain -f $(DOCKERFILE) -t $(IMG) $(DOCKERFLAGS) .
push: push:
sudo docker push $(IMG) sudo docker push $(IMG)

View file

@ -912,11 +912,16 @@ ys_free1(yang_stmt *ys,
{ {
rpc_callback_t *rc; rpc_callback_t *rc;
cg_var *cv; cg_var *cv;
cvec *cvv;
if ((cv = ys->ys_cv) != NULL){ // To not trigger asserts if ((cv = ys->ys_cv) != NULL){
ys->ys_cv = NULL; ys->ys_cv = NULL;
cv_free(cv); cv_free(cv);
} }
if ((cvv = ys->ys_cvec) != NULL){
ys->ys_cvec = NULL;
cvec_free(cvv);
}
if (ys->ys_argument){ if (ys->ys_argument){
free(ys->ys_argument); free(ys->ys_argument);
ys->ys_argument = NULL; ys->ys_argument = NULL;

View file

@ -1,5 +1,5 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# Run valgrind leak test for cli, restconf, netconf or background. # Run valgrind leak test for backend, restconf, cli, netconf or snmp.
# Stop on first error # Stop on first error
# Typical run: ./mem.sh 2>&1 | tee mylog # Typical run: ./mem.sh 2>&1 | tee mylog
@ -7,32 +7,22 @@
: ${pattern:=test_*.sh} : ${pattern:=test_*.sh}
# Run valgrindtest once, args: # Run valgrindtest once, args:
# what: (cli|netconf|restconf|backend)* # no args means all # what: (backend|restconf|cli|netconf|snmp)* # no args means all
function memonce(){ function memonce(){
what=$1 what=$1
valgrindfile=$(mktemp) valgrindfile=$(mktemp)
echo "valgrindfile:$valgrindfile" echo "valgrindfile:$valgrindfile"
clixon_cli=
clixon_netconf=
clixon_backend= clixon_backend=
clixon_restconf= clixon_restconf=
clixon_cli=
clixon_netconf=
clixon_snmp= clixon_snmp=
case "$what" in case "$what" in
'cli')
valgrindtest=1
: ${DEMWAIT:=5} # valgrind backend needs some time to get up
clixon_cli="/usr/bin/valgrind --leak-check=full --show-leak-kinds=all --suppressions=./valgrind-clixon.supp --track-fds=yes --trace-children=no --child-silent-after-fork=yes --log-file=$valgrindfile clixon_cli"
;;
'netconf')
valgrindtest=1
: ${DEMWAIT:=5} # valgrind backend needs some time to get up
clixon_netconf="/usr/bin/valgrind --leak-check=full --show-leak-kinds=all --suppressions=./valgrind-clixon.supp --track-fds=yes --trace-children=no --child-silent-after-fork=yes --log-file=$valgrindfile clixon_netconf"
;;
'backend') 'backend')
valgrindtest=2 # This means backend valgrind test valgrindtest=2 # This means backend valgrind test
: ${DEMWAIT:=10} # valgrind backend needs some time to get up : ${DEMWAIT:=10} # valgrind backend needs some time to get up
# trace-children=no for test_restconf_rpc.sh # trace-children=no for test_restconf_rpc.sh
sudo chown root $valgrindfile sudo chown root $valgrindfile
sudo chmod 777 $valgrindfile sudo chmod 777 $valgrindfile
@ -40,9 +30,19 @@ function memonce(){
;; ;;
'restconf') 'restconf')
valgrindtest=3 # This means restconf valgrind test valgrindtest=3 # This means restconf valgrind test
: ${DEMWAIT:=15} # valgrind backend needs some time to get up : ${DEMWAIT:=15} # valgrind backend needs some time to get up
clixon_restconf="/usr/bin/valgrind --num-callers=50 --leak-check=full --show-leak-kinds=all --suppressions=./valgrind-clixon.supp --track-fds=yes --trace-children=no --child-silent-after-fork=yes --log-file=$valgrindfile clixon_restconf" clixon_restconf="/usr/bin/valgrind --num-callers=50 --leak-check=full --show-leak-kinds=all --suppressions=./valgrind-clixon.supp --track-fds=yes --trace-children=no --child-silent-after-fork=yes --log-file=$valgrindfile clixon_restconf"
;;
'cli')
valgrindtest=1
: ${DEMWAIT:=5} # valgrind backend needs some time to get up
clixon_cli="/usr/bin/valgrind --leak-check=full --show-leak-kinds=all --suppressions=./valgrind-clixon.supp --track-fds=yes --trace-children=no --child-silent-after-fork=yes --log-file=$valgrindfile clixon_cli"
;;
'netconf')
valgrindtest=1
: ${DEMWAIT:=5} # valgrind backend needs some time to get up
clixon_netconf="/usr/bin/valgrind --leak-check=full --show-leak-kinds=all --suppressions=./valgrind-clixon.supp --track-fds=yes --trace-children=no --child-silent-after-fork=yes --log-file=$valgrindfile clixon_netconf"
;; ;;
'snmp') 'snmp')
valgrindtest=4 # This means snmp valgrind test valgrindtest=4 # This means snmp valgrind test
@ -50,9 +50,8 @@ function memonce(){
: ${DEMWAIT:=15} # valgrind snmp needs some time to get up : ${DEMWAIT:=15} # valgrind snmp needs some time to get up
clixon_snmp="/usr/bin/valgrind --num-callers=50 --leak-check=full --show-leak-kinds=all --suppressions=./valgrind-clixon.supp --track-fds=yes --trace-children=no --child-silent-after-fork=yes --log-file=$valgrindfile clixon_snmp" clixon_snmp="/usr/bin/valgrind --num-callers=50 --leak-check=full --show-leak-kinds=all --suppressions=./valgrind-clixon.supp --track-fds=yes --trace-children=no --child-silent-after-fork=yes --log-file=$valgrindfile clixon_snmp"
;; ;;
*) *)
echo "usage: $0 cli|netconf|restconf|backend|snmp" # valgrind memleak checks echo "usage: $0 backend|restconf|cli|netconf|snmp" # valgrind memleak checks
rm -f $valgrindfile rm -f $valgrindfile
exit -1 exit -1
;; ;;
@ -108,9 +107,9 @@ fi
# First run sanity # First run sanity
for c in $cmds; do for c in $cmds; do
if [ $c != cli -a $c != netconf -a $c != restconf -a $c != backend -a $c != snmp ]; then if [ $c != backend -a $c != restconf -a $c != cli -a $c != netconf -a $c != snmp ]; then
echo "c:$c" echo "c:$c"
echo "usage: $0 [cli|netconf|restconf|backend|snmp]+" echo "usage: $0 [backend||restconf|cli|netconf|snmp]+"
echo " with no args run all" echo " with no args run all"
exit -1 exit -1
fi fi

View file

@ -213,10 +213,8 @@ EOF
expectpart "$(curl $CURLOPTS -X GET -H 'Accept: wrong/media,*/*' $proto://localhost/data/index.html)" 0 "HT expectpart "$(curl $CURLOPTS -X GET -H 'Accept: wrong/media,*/*' $proto://localhost/data/index.html)" 0 "HT
TP/$HVER 200" "Content-Type: text/html" "<title>Welcome to Clixon!</title>" TP/$HVER 200" "Content-Type: text/html" "<title>Welcome to Clixon!</title>"
if false; then # XXX Se step 5 in api_http_data, unclear which media should be accepted
new "Server does not support list of medias Expect 406" new "Server does not support list of medias Expect 406"
expectpart "$(curl $CURLOPTS -X GET -H 'Accept: wrong/media' $proto://localhost/data/index.html)" 0 "HTTP/$HVER 406" "content-type: text/html" "<error-message>Unacceptable output encoding</error-message>" expectpart "$(curl $CURLOPTS -X GET -H 'Accept: wrong/media' $proto://localhost/data/index.html)" 0 "HTTP/$HVER 406" "content-type: text/html" "<error-message>Unacceptable output encoding</error-message>"
fi
new "WWW get dir -> expect index.html" new "WWW get dir -> expect index.html"
expectpart "$(curl $CURLOPTS -X GET -H 'Accept: text/html' $proto://localhost/data)" 0 "HTTP/$HVER 200" "Content-Type: text/html" "<title>Welcome to Clixon!</title>" expectpart "$(curl $CURLOPTS -X GET -H 'Accept: text/html' $proto://localhost/data)" 0 "HTTP/$HVER 200" "Content-Type: text/html" "<title>Welcome to Clixon!</title>"
@ -231,7 +229,13 @@ fi
mv $dir/www/data/tmp.index.html $dir/www/data/index.html mv $dir/www/data/tmp.index.html $dir/www/data/index.html
new "WWW get css" new "WWW get css"
expectpart "$(curl $CURLOPTS -X GET -H 'Accept: text/html' $proto://localhost/data/example.css)" 0 "HTTP/$HVER 200" "Content-Type: text/css" "display: inline;" --not-- "Content-Type: text/html" expectpart "$(curl $CURLOPTS -X GET -H 'Accept: text/css' $proto://localhost/data/example.css)" 0 "HTTP/$HVER 200" "Content-Type: text/css" "display: inline;" --not-- "Content-Type: text/html"
new "WWW get css accept *"
expectpart "$(curl $CURLOPTS -X GET -H 'Accept: text/html,*/*' $proto://localhost/data/example.css)" 0 "HTTP/$HVER 200" "Content-Type: text/css" "display: inline;" --not-- "Content-Type: text/html"
new "WWW get css, operation-not-supported"
expectpart "$(curl $CURLOPTS -X GET -H 'Accept: text/html' $proto://localhost/data/example.css)" 0 "HTTP/$HVER 406" "operation-not-supported"
new "WWW head" new "WWW head"
expectpart "$(curl $CURLOPTS --head -H 'Accept: text/html' $proto://localhost/data/index.html)" 0 "HTTP/$HVER 200" "Content-Type: text/html" --not-- "<title>Welcome to Clixon!</title>" expectpart "$(curl $CURLOPTS --head -H 'Accept: text/html' $proto://localhost/data/index.html)" 0 "HTTP/$HVER 200" "Content-Type: text/html" --not-- "<title>Welcome to Clixon!</title>"

View file

@ -197,9 +197,8 @@ wait_restconf
new "Create album London Calling with PUT" new "Create album London Calling with PUT"
expectpart "$(curl -u andy:bar $CURLOPTS -X PUT -H 'Content-Type: application/yang-data+json' $RCPROTO://localhost/restconf/data/example-jukebox:jukebox/library/artist=Clash/album=London%20Calling -d '{"example-jukebox:album":{"name":"London Calling"}}')" 0 "HTTP/$HVER 201" expectpart "$(curl -u andy:bar $CURLOPTS -X PUT -H 'Content-Type: application/yang-data+json' $RCPROTO://localhost/restconf/data/example-jukebox:jukebox/library/artist=Clash/album=London%20Calling -d '{"example-jukebox:album":{"name":"London Calling"}}')" 0 "HTTP/$HVER 201"
#new "The message-body for a plain patch MUST be present" new "The message-body for a plain patch MUST be present"
# XXX Hangs in SSL 3.3.2 expectpart "$(curl -u andy:bar $CURLOPTS -X PATCH -H 'Content-Type: application/yang-data+json' $RCPROTO://localhost/restconf/data/example-jukebox:jukebox/library/artist=Beatles -d '')" 0 "HTTP/$HVER 400" "The message-body MUST contain exactly one instance of the expected data resource"
#expectpart "$(curl -u andy:bar $CURLOPTS -X PATCH -H 'Content-Type: application/yang-data+json' $RCPROTO://localhost/restconf/data/example-jukebox:jukebox/library/artist=Beatles -d '')" 0 "HTTP/$HVER 400" kalle
# Plain patch can be used to create or update, but not delete, a child # Plain patch can be used to create or update, but not delete, a child
# resource within the target resource. # resource within the target resource.