* Restconf native http/1, first working version

* Renamed files clixon_http -> restconf_http
  * Split main file into restconf_native.c
  * Remove all evhtp code and libevhtp/libevent dependency
This commit is contained in:
Olof hagsand 2022-01-27 17:05:52 +01:00
parent dadf4a778a
commit 4aa74fa1d8
27 changed files with 1291 additions and 789 deletions

View file

@ -40,7 +40,11 @@
# --with-restconf=native Integration with embedded web server
WITH_RESTCONF=@with_restconf@ # native, fcgi or ""
HAVE_LIBNGHTTP2=@HAVE_LIBNGHTTP2@
# HTTP/2?
# If set, curl options are set to use --http2 which may not be what you want, ie
# you may want to force it to http/1 for example
# If so, override before test
: ${HAVE_LIBNGHTTP2:=@HAVE_LIBNGHTTP2@}o
HAVE_HTTP1=@HAVE_HTTP1@
# This is for libxml2 XSD regex engine
@ -85,4 +89,6 @@ LIBSTATIC_SUFFIX=@LIBSTATIC_SUFFIX@
LIBS="@LIBS@"
CLIXON_YANG_PATCH=@CLIXON_YANG_PATCH@
YANG_STANDARD_DIR=@YANG_STANDARD_DIR@
YANG_INSTALLDIR=@YANG_INSTALLDIR@

View file

@ -110,6 +110,7 @@ if ${HAVE_LIBNGHTTP2}; then
CURLOPTS="${CURLOPTS} --http2-prior-knowledge"
fi
else
CURLOPTS="${CURLOPTS} --http1.1"
HVER=1.1
fi

View file

@ -454,7 +454,7 @@ function testrun()
expectpart "$(curl $CURLOPTS -X POST -H "Content-Type: application/yang-data+json" -d '{"ietf-interfaces:description":"The-first-interface"}' $proto://$addr/restconf/data/ietf-interfaces:interfaces/interface=eth%2f0%2f0)" 0 "HTTP/$HVER 201"
new "Add nothing using POST (expect fail)"
expectpart "$(curl $CURLOPTS -X POST -H "Content-Type: application/yang-data+json" $proto://$addr/restconf/data/ietf-interfaces:interfaces/interface=eth%2f0%2f0)" 0 "HTTP/$HVER 400" '{"ietf-restconf:errors":{"error":{"error-type":"rpc","error-tag":"malformed-message","error-severity":"error","error-message":"The message-body MUST contain exactly one instance of the expected data resource"}}}'
expectpart "$(curl $CURLOPTS -X POST -H "Content-Type: application/yang-data+json" $proto://$addr/restconf/data/ietf-interfaces:interfaces/interface=eth%2f0%2f0)" 0 "HTTP/$HVER 400" '{"ietf-restconf:errors":{"error":{"error-type":"rpc","error-tag":"malformed-message","error-severity":"error","error-message":"The message-body of POST MUST contain exactly one instance of the expected data resource"}}}'
new "restconf Check description added"
expectpart "$(curl $CURLOPTS -X GET $proto://$addr/restconf/data/ietf-interfaces:interfaces)" 0 "HTTP/$HVER 200" '{"ietf-interfaces:interfaces":{"interface":\[{"name":"eth/0/0","description":"The-first-interface","type":"clixon-example:eth","enabled":true,"oper-status":"up","clixon-example:my-status":{"int":42,"str":"foo"}}\]}}'

131
test/test_restconf_continue.sh Executable file
View file

@ -0,0 +1,131 @@
#!/usr/bin/env bash
# Restconf HTTP/1.1 Expect/Continue functionality
# Trigger Expect by curl -H. Some curls seem to trigger one on large PUTs but not all
# Override default to use http/1.1
HAVE_LIBNGHTTP2=false
# 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
fjson=$dir/large.json
# Define default restconfig config: RESTCONFIG
RESTCONFIG=$(restconf_config none false)
# <CLICON_YANG_MODULE_MAIN>example</CLICON_YANG_MODULE_MAIN>
cat <<EOF > $cfg
<clixon-config xmlns="http://clicon.org/config">
<CLICON_FEATURE>clixon-restconf:allow-auth-none</CLICON_FEATURE> <!-- Use auth-type=none -->
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
<CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR>
<CLICON_YANG_MAIN_FILE>$fyang</CLICON_YANG_MAIN_FILE>
<CLICON_SOCK>/usr/local/var/$APPNAME/$APPNAME.sock</CLICON_SOCK>
<CLICON_BACKEND_PIDFILE>$dir/restconf.pidfile</CLICON_BACKEND_PIDFILE>
<CLICON_XMLDB_DIR>/usr/local/var/$APPNAME</CLICON_XMLDB_DIR>
$RESTCONFIG
</clixon-config>
EOF
cat <<EOF > $fyang
module example{
yang-version 1.1;
namespace "urn:example:clixon";
prefix ex;
/* Generic config data */
container table{
list parameter{
key name;
leaf name{
type string;
}
leaf value{
type string;
}
}
}
}
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 -f clixon_backend # to be sure
new "start backend -s init -f $cfg"
start_backend -s init -f $cfg
fi
new "wait backend"
wait_backend
if [ $RC -ne 0 ]; then
new "kill old restconf daemon"
stop_restconf_pre
new "start restconf daemon"
start_restconf -f $cfg
fi
new "wait restconf"
wait_restconf
new "generate large request"
# Add large put, curl seems to create a Expect:100-continue after 1024 bytes
# Alt: add in file if nr=5000 reacts with "Argument list too long"
echo -n '{"example:table":{"parameter":[' > $fjson
nr=10000
for (( i=0; i<$nr; i++ )); do
if [ $i -ne 0 ]; then
echo -n ",
" >> $fjson
fi
echo -n "{\"name\":\"A$i\",\"value\":\"$i\"}" >> $fjson
done
echo -n "]}}" >> $fjson
new "restconf large PUT"
expectpart "$(curl $CURLOPTS -X POST -H "Content-Type: application/yang-data+json" -H "Expect: 100-continue" -d @$fjson $RCPROTO://localhost/restconf/data)" 0 "HTTP/$HVER 100 Continue" "HTTP/$HVER 201"
new "restconf PUT with expect"
expectpart "$(curl $CURLOPTS -H "Expect: 100-continue" -X POST -H "Content-Type: application/yang-data+json" -d '{"example:parameter":[{"name":"A","value":"42"}]}' $RCPROTO://localhost/restconf/data/example:table)" 0 "HTTP/$HVER 100 Continue" "HTTP/$HVER 201"
new "restconf GET"
expectpart "$(curl $CURLOPTS -X GET $RCPROTO://localhost/restconf/data/example:table/parameter=A)" 0 "HTTP/$HVER 200" '{"example:parameter":\[{"name":"A","value":"42"}\]}'
if [ $RC -ne 0 ]; then
new "Kill restconf daemon"
stop_restconf
fi
if [ $BE -ne 0 ]; then
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
fi
# Set by restconf_config
unset RESTCONFIG
unset nr
unset HAVE_LIBNGHTTP2
rm -rf $dir
new "endtest"
endtest

View file

@ -20,6 +20,11 @@
# plugin should be visible in the error message.
# XXX does not test rpc-error from backend in api_return_err?
# Override default to use http/1.1
# Force to HTTP 1.1 no SSL due to netcat
RCPROTO=http
HAVE_LIBNGHTTP2=false
# Magic line must be first in script (see README.md)
s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi
@ -37,9 +42,6 @@ fyang2=$dir/augment.yang
fxml=$dir/initial.xml
fstate=$dir/state.xml
RCPROTO=http # Force to http due to netcat
HVER=1.1
# Define default restconfig config: RESTCONFIG
RESTCONFIG=$(restconf_config none false)
@ -203,15 +205,15 @@ expectpart "$(curl $CURLOPTS -X GET -H 'Accept: application/yang-data+xml' $RCPR
# But leave it here for debugging where netcat works properly
# Alt try something like:
# printf "Hello World!" | (exec 3<>/dev/tcp/127.0.0.1/80; cat >&3; cat <&3; exec 3<&-)
if [ false -a ! ${HAVE_LIBNGHTTP2} ] ; then
# Look for netcat or nc for direct socket http calls
if [ -n "$(type netcat 2> /dev/null)" ]; then
netcat="netcat -w 1" # -N does not work on fcgi
elif [ -n "$(type nc 2> /dev/null)" ]; then
netcat=nc
else
err1 "netcat/nc not found"
fi
# Look for netcat or nc for direct socket http calls
if [ -n "$(type netcat 2> /dev/null)" ]; then
netcat="netcat -w 1" # -N does not work on fcgi
elif [ -n "$(type nc 2> /dev/null)" ]; then
netcat=nc
else
netcat=
fi
if [ -n "$netcat" ]; then
# new "restconf try fuzz crash"
# expectpart "$(${netcat} 127.0.0.1 80 < ~/tmp/crashes/id:000000,sig:06,src:000493+000365,op:splice,rep:8)" 0 "HTTP/$HVER 400"
@ -236,12 +238,12 @@ EOF
new "restconf PUT not allowed"
expectpart "$(${netcat} 127.0.0.1 80 <<EOF
PUT /restconf/.well-known/host-meta HTTP/$HVER
PUT /.well-known/host-meta HTTP/$HVER
Host: localhost
Accept: application/yang-data+xml
EOF
)" 0 "HTTP/$HVER 405" kalle # nginx uses "method not allowed"
)" 0 "HTTP/$HVER 405" # nginx uses "method not allowed"
new "restconf GET wrong http version raw"
expectpart "$(${netcat} 127.0.0.1 80 <<EOF
@ -252,7 +254,7 @@ Accept: application/yang-data+xml
EOF
)" 0 "HTTP/$HVER 400" # native: '<error-tag>malformed-message</error-tag><error-message>The requested URL or a header is in some way badly formed</error-message>'
fi # Http/1.1 and netcat Cannot get to work on all platforms
fi # netcat Cannot get to work on all platforms
new "restconf XYZ not found"
expectpart "$(curl $CURLOPTS -X XYS -H 'Accept: application/yang-data+xml' $RCPROTO://localhost/restconf/data/example:a=0)" 0 "HTTP/$HVER 404"
@ -335,6 +337,7 @@ fi
unset RESTCONFIG
unset HVER
unset RCPROTO
unset HAVE_LIBNGHTTP2
rm -rf $dir

View file

@ -145,7 +145,7 @@ function rpcoperation()
}
# This test is confusing:
# The whole restconf config is in clixon-config wich binds 0.0.0.0:80 which will be the only
# The whole restconf config is in clixon-config which binds 0.0.0.0:80 which will be the only
# config the restconf daemon ever reads.
# However, enable (and debug) flag is stored in running db but only backend will ever read that.
# It just controls how restconf is started, but thereafter the restconf daemon reads the static db in clixon-config file