diff --git a/CHANGELOG.md b/CHANGELOG.md index fd54b4bc..e5dc0304 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,8 @@ ### Major New features * Restconf RFC 8040 increased feature compliance - * RESTCONF PATCH (plain patch) is supported according to RFC 8040 4.6.1 + * RESTCONF PATCH (plain patch) is being implemented according to RFC 8040 4.6.1 + * Work-in-progress, expected done by 4.1.0 * RESTCONF "insert" and "point" query parameters supported * Applies to ordered-by-user leaf and leaf-lists * RESTCONF PUT/POST erroneously returned 200 OK. Instead restconf now returns: diff --git a/apps/restconf/restconf_methods.c b/apps/restconf/restconf_methods.c index 200ea022..fd263954 100644 --- a/apps/restconf/restconf_methods.c +++ b/apps/restconf/restconf_methods.c @@ -134,6 +134,7 @@ Mapping netconf error-tag -> status code * Minimal support: * 200 OK * Allow: HEAD,GET,PUT,DELETE,OPTIONS + * @see RFC5789 PATCH Method for HTTP Section 3.2 */ int api_data_options(clicon_handle h, @@ -141,7 +142,8 @@ api_data_options(clicon_handle h, { clicon_debug(1, "%s", __FUNCTION__); FCGX_SetExitStatus(200, r->out); /* OK */ - FCGX_FPrintF(r->out, "Allow: OPTIONS,HEAD,GET,POST,PUT,DELETE\r\n"); + FCGX_FPrintF(r->out, "Allow: OPTIONS,HEAD,GET,POST,PUT,PATCH,DELETE\r\n"); + FCGX_FPrintF(r->out, "Accept-Patch: application/yang-data+xml,application/yang-data+json\r\n"); FCGX_FPrintF(r->out, "\r\n"); return 0; } diff --git a/test/test_restconf.sh b/test/test_restconf.sh index 068c6f56..a50ab9c0 100755 --- a/test/test_restconf.sh +++ b/test/test_restconf.sh @@ -101,11 +101,11 @@ expecteq "$(curl -s -H 'Accept: application/yang-data+json' -G http://localhost/ ' new "restconf options. RFC 8040 4.1" -expectfn "curl -i -s -X OPTIONS http://localhost/restconf/data" 0 "Allow: OPTIONS,HEAD,GET,POST,PUT,DELETE" +expectpart "$(curl -is -X OPTIONS http://localhost/restconf/data)" 0 "Allow: OPTIONS,HEAD,GET,POST,PUT,PATCH,DELETE" -new "restconf head. RFC 8040 4.2" -expectfn "curl -s -I http://localhost/restconf/data" 0 "HTTP/1.1 200 OK" -#Content-Type: application/yang-data+json" +# -I means HEAD +new "restconf HEAD. RFC 8040 4.2" +expectpart "$(curl -si -I -H "Accept: application/yang-data+json" http://localhost/restconf/data)" 0 "HTTP/1.1 200 OK" "Content-Type: application/yang-data+json" new "restconf empty rpc" expectpart "$(curl -si -X POST -H "Content-Type: application/yang-data+json" -d {\"clixon-example:input\":null} http://localhost/restconf/operations/clixon-example:empty)" 0 "HTTP/1.1 204 No Content" diff --git a/test/test_restconf_jukebox.sh b/test/test_restconf_jukebox.sh index e14e6442..411adf9c 100755 --- a/test/test_restconf_jukebox.sh +++ b/test/test_restconf_jukebox.sh @@ -1,6 +1,6 @@ #!/bin/bash # Restconf RFC8040 Appendix A and B "jukebox" example - +# Not supported: B.2.2 if-unmodified # Magic line must be first in script (see README.md) s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi @@ -92,10 +92,6 @@ new "B.2.1. Add Data Resources again (conflict - not in RFC)" expectpart "$(curl -si -X POST -H 'Content-Type: application/yang-data+xml' http://localhost/restconf/data/example-jukebox:jukebox/library/artist=Foo%20Fighters -d 'Wasting Light2011')" 0 "HTTP/1.1 409 Conflict" -new "B.2.2. Added genre" -# Here the jbox identity is added -expectpart "$(curl -si -X PUT -H 'Content-Type: application/yang-data+json' http://localhost/restconf/data/example-jukebox:jukebox/library/artist=Foo%20Fighters/album=Wasting%20Light -d '{"example-jukebox:album":[{"name":"Wasting Light","genre":"example-jukebox:alternative","year":2011}]}')" 0 "HTTP/1.1 204 No Content" - new "4.5. PUT replace content (xml encoding)" expectpart "$(curl -si -X PUT -H 'Content-Type: application/yang-data+xml' http://localhost/restconf/data/example-jukebox:jukebox/library/artist=Foo%20Fighters/album=Wasting%20Light -d 'Wasting Lightjbox:alternative2011')" 0 "HTTP/1.1 204 No Content" @@ -105,6 +101,9 @@ expectpart "$(curl -si -X PUT -H 'Content-Type: application/yang-data+json' http new "4.5. Check jukebox content: 1 Clash and 1 Foo fighters album" expectpart "$(curl -si -X GET http://localhost/restconf/data/example-jukebox:jukebox -H 'Accept: application/yang-data+xml')" 0 'HTTP/1.1 200 OK' 'ClashLondon Calling1979Foo FightersWasting Lightjbox:alternative2011' +new "B.2.2. Added genre (preamble to actual test)" +expectpart "$(curl -si -X PUT -H 'Content-Type: application/yang-data+json' http://localhost/restconf/data/example-jukebox:jukebox/library/artist=Foo%20Fighters/album=Wasting%20Light -d '{"example-jukebox:album":[{"name":"Wasting Light","genre":"example-jukebox:alternative","year":2011}]}')" 0 "HTTP/1.1 204 No Content" + # First use of PATCH new "B.2.2. Detect Datastore Resource Entity-Tag Change (XXX if-unmodified)" expectpart "$(curl -si -X PATCH -H 'Content-Type: application/yang-data+json' http://localhost/restconf/data/example-jukebox:jukebox/library/artist=Foo%20Fighters/album=Wasting%20Light/genre -d '{"example-jukebox:genre":"example-jukebox:alternative"}')" 0 'HTTP/1.1 204 No Content' @@ -116,7 +115,7 @@ new "B.2.3. Check patch system" expectpart "$(curl -si -X GET http://localhost/restconf/data/example-system:system -H 'Accept: application/yang-data+xml')" 0 'HTTP/1.1 200 OK' 'true' new "B.2.3. Check jukebox: 1 Clash, 2 Foo Fighters, 1 Nick Cave" -expectpart "$(curl -si -X GET http://localhost/restconf/data/example-jukebox:jukebox -H 'Accept: application/yang-data+xml')" 0 'HTTP/1.1 200 OK' 'ClashLondon Calling1979Foo FightersOne by One2012Wasting Lightalternative2011Nick Cave and the Bad SeedsTender Prey1988' +expectpart "$(curl -si -X GET http://localhost/restconf/data/example-jukebox:jukebox -H 'Accept: application/yang-data+xml')" 0 'HTTP/1.1 200 OK' 'ClashLondon Calling1979Foo FightersOne by One2012Wasting Lightalternative2011Nick Cave and the Bad SeedsTender Prey1988' new "B.2.4. Replace a Datastore Resource" expectpart "$(curl -si -X PUT -H 'Content-Type: application/yang-data+xml' http://localhost/restconf/data -d 'Foo FightersOne by One2012Nick Cave and the Bad SeedsTender Prey1988')" 0 "HTTP/1.1 204 No Content" @@ -124,6 +123,12 @@ expectpart "$(curl -si -X PUT -H 'Content-Type: application/yang-data+xml' http: new "B.2.4. Check replace" expectpart "$(curl -si -X GET http://localhost/restconf/data/example-jukebox:jukebox -H 'Accept: application/yang-data+xml')" 0 'HTTP/1.1 200 OK' 'Foo FightersOne by One2012Nick Cave and the Bad SeedsTender Prey1988' +new "B.2.5. Edit a Data Resource (add Nick cave album The good son)" +expectpart "$(curl -si -X PATCH http://localhost/restconf/data/example-jukebox:jukebox/library/artist=Nick%20Cave%20and%20the%20Bad%20Seeds -H 'Content-Type: application/yang-data+xml' -d 'Nick Cave and the Bad SeedsThe Good Son1990')" 0 'HTTP/1.1 204 No Content' + +new "B.2.5. Check edit" +expectpart "$(curl -si -X GET http://localhost/restconf/data/example-jukebox:jukebox/library/artist=Nick%20Cave%20and%20the%20Bad%20Seeds -H 'Accept: application/yang-data+xml')" 0 'HTTP/1.1 200 OK' 'Nick Cave and the Bad SeedsTender Prey1988The Good Son1990' + new "restconf DELETE whole datastore" expectfn 'curl -s -X DELETE http://localhost/restconf/data' 0 "" @@ -182,9 +187,7 @@ expectpart "$(curl -si -X GET http://localhost/restconf/data/example-jukebox:ext if false; then # NYI -new "B.2.2. Detect Datastore Resource Entity-Tag Change" -new "B.2.3. Edit a Datastore Resource" -new "B.2.5. Edit a Data Resource" +new "B.2.2. Detect Datastore Resource Entity-Tag Change" # XXX done except entity-changed new 'B.3.1. "content" Parameter' new 'B.3.2. "depth" Parameter' new 'B.3.3. "fields" Parameter' diff --git a/test/test_restconf_patch.sh b/test/test_restconf_patch.sh index ec539163..932d8a58 100755 --- a/test/test_restconf_patch.sh +++ b/test/test_restconf_patch.sh @@ -1,5 +1,5 @@ #!/bin/bash -# Restconf RFC8040 plain patch +# Restconf RFC8040 plain patch Sec 4.6 / 4.6.1 # Magic line must be first in script (see README.md) s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi @@ -49,6 +49,22 @@ new "waiting" wait_backend wait_restconf +# also in test_restconf.sh +new "MUST support the PATCH method for a plain patch" +expectpart "$(curl -is -X OPTIONS http://localhost/restconf/data)" 0 "HTTP/1.1 200 OK" "Allow: OPTIONS,HEAD,GET,POST,PUT,PATCH,DELETE" "Accept-Patch: application/yang-data+xml,application/yang-data+json" + +new "If the target resource instance does not exist, the server MUST NOT create it." +expectpart "$(curl -si -X PATCH -H 'Content-Type: application/yang-data+json' http://localhost/restconf/data/example-jukebox:jukebox -d '{"example-jukebox:jukebox":null}')" 0 "HTTP/1.1 400 Bad Request" + +new "Create it with PUT instead" +expectpart "$(curl -si -X PUT -H 'Content-Type: application/yang-data+json' http://localhost/restconf/data/example-jukebox:jukebox -d '{"example-jukebox:jukebox":null}')" 0 "HTTP/1.1 201 Created" + +new "THEN change it with PATCH" +expectpart "$(curl -si -X PATCH -H 'Content-Type: application/yang-data+json' http://localhost/restconf/data/example-jukebox:jukebox -d '{"example-jukebox:jukebox":{"library":{"artist":{"name":"Clash"}}}}')" 0 "HTTP/1.1 204 No Content" + +new "Check content" +expectpart "$(curl -si -X GET http://localhost/restconf/data/example-jukebox:jukebox -H 'Accept: application/yang-data+json')" 0 'HTTP/1.1 200 OK' '{"example-jukebox:jukebox":{"library":{"artist":\[{"name":"Clash"}\]}}}' + new "Kill restconf daemon" stop_restconf