* Identity/identityref mapped between XML and JSON

This commit is contained in:
Olof hagsand 2019-07-28 18:09:55 +02:00
parent ccc95b2826
commit 70ebfa4d80
22 changed files with 779 additions and 133 deletions

View file

@ -78,6 +78,7 @@ APPSRC = restconf_main.c
APPSRC += restconf_methods.c
APPSRC += restconf_methods_post.c
APPSRC += restconf_methods_get.c
APPSRC += restconf_methods_patch.c
APPSRC += restconf_stream.c
APPOBJ = $(APPSRC:.c=.o)

View file

@ -78,8 +78,9 @@
/* restconf */
#include "restconf_lib.h"
#include "restconf_methods.h"
#include "restconf_methods_post.h"
#include "restconf_methods_get.h"
#include "restconf_methods_post.h"
#include "restconf_methods_patch.h"
#include "restconf_stream.h"
/* Command line options to be passed to getopt(3) */

View file

@ -288,7 +288,7 @@ api_data_put(clicon_handle h,
char *namespace0;
char *dname;
clicon_debug(1, "%s api_path:\"%s\" json:\"%s\"",
clicon_debug(1, "%s api_path:\"%s\" data:\"%s\"",
__FUNCTION__, api_path0, data);
if ((yspec = clicon_dbspec_yang(h)) == NULL){
clicon_err(OE_FATAL, 0, "No DB_SPEC");
@ -336,6 +336,12 @@ api_data_put(clicon_handle h,
}
}
else{
/* Data here cannot cannot be Yang populated since it is loosely
* hanging without top symbols.
* And if it is not yang populated, it cant be translated properly
* from JSON to XML.
* Therefore, yang population is done later after addsub below
*/
if ((ret = json_parse_str(data, yspec, &xdata0, &xerr)) < 0){
if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0)
goto done;
@ -487,6 +493,21 @@ api_data_put(clicon_handle h,
xml_purge(xbot);
if (xml_addsub(xparent, xdata) < 0)
goto done;
/* xbot is already populated, resolve yang for added xdata too */
if (xml_apply0(xdata, CX_ELMNT, xml_spec_populate, yspec) < 0)
goto done;
if (!parse_xml){
/* json2xml decode could not be done above in json_parse,
need to be done here instead */
if ((ret = json2xml_decode(xdata, &xerr)) < 0)
goto done;
if (ret == 0){
if (api_return_err(h, r, xerr, pretty, use_xml, 0) < 0)
goto done;
goto ok;
}
}
/* If we already have that default namespace, remove it in child */
if ((xa = xml_find_type(xdata, NULL, "xmlns", CX_ATTR)) != NULL){
if (xml2ns(xparent, NULL, &namespace0) < 0)
@ -495,6 +516,7 @@ api_data_put(clicon_handle h,
if (strcmp(namespace0, xml_value(xa))==0)
xml_purge(xa);
}
}
/* Create text buffer for transfer to backend */
if ((cbx = cbuf_new()) == NULL)
@ -613,29 +635,6 @@ api_data_put(clicon_handle h,
return retval;
} /* api_data_put */
/*! Generic REST PATCH method
* @param[in] h CLIXON handle
* @param[in] r Fastcgi request handle
* @param[in] api_path According to restconf (Sec 3.5.3.1 in rfc8040)
* @param[in] pcvec Vector of path ie DOCUMENT_URI element
* @param[in] pi Offset, where to start pcvec
* @param[in] qvec Vector of query string (QUERY_STRING)
* @param[in] data Stream input data
* Netconf: <edit-config> (nc:operation="merge")
* See RFC8040 Sec 4.6
*/
int
api_data_patch(clicon_handle h,
FCGX_Request *r,
char *api_path,
cvec *pcvec,
int pi,
cvec *qvec,
char *data)
{
notimplemented(r);
return 0;
}
/*! Generic REST DELETE method translated to edit-config
* @param[in] h CLIXON handle

View file

@ -46,9 +46,6 @@ int api_data_put(clicon_handle h, FCGX_Request *r, char *api_path,
cvec *pcvec, int pi,
cvec *qvec, char *data,
int pretty, int use_xml, int parse_xml);
int api_data_patch(clicon_handle h, FCGX_Request *r, char *api_path,
cvec *pcvec, int pi,
cvec *qvec, char *data);
int api_data_delete(clicon_handle h, FCGX_Request *r, char *api_path, int pi,
int pretty, int use_xml);

View file

@ -60,7 +60,6 @@
#include <fcgiapp.h> /* Need to be after clixon_xml-h due to attribute format */
#include "restconf_lib.h"
#include "restconf_methods.h"
#include "restconf_methods_get.h"
/*! Generic GET (both HEAD and GET)
@ -187,6 +186,17 @@ api_data_get2(clicon_handle h,
goto done;
}
else{
#if 0
if (debug){
cbuf *ccc=cbuf_new();
if (clicon_xml2cbuf(ccc, xret, 0, 0) < 0)
goto done;
clicon_debug(1, "%s xret: %s",
__FUNCTION__, cbuf_get(ccc));
cbuf_free(ccc);
}
#endif
if (xml2json_cbuf(cbx, xret, pretty) < 0)
goto done;
}

View file

@ -0,0 +1,151 @@
/*
*
***** BEGIN LICENSE BLOCK *****
Copyright (C) 2009-2019 Olof Hagsand
This file is part of CLIXON.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Alternatively, the contents of this file may be used under the terms of
the GNU General Public License Version 3 or later (the "GPL"),
in which case the provisions of the GPL are applicable instead
of those above. If you wish to allow use of your version of this file only
under the terms of the GPL, and not to allow others to
use your version of this file under the terms of Apache License version 2,
indicate your decision by deleting the provisions above and replace them with
the notice and other provisions required by the GPL. If you do not delete
the provisions above, a recipient may use your version of this file under
the terms of any one of the Apache License version 2 or the GPL.
***** END LICENSE BLOCK *****
*/
/*
* See rfc8040
* sudo apt-get install libfcgi-dev
* gcc -o fastcgi fastcgi.c -lfcgi
* sudo su -c "/www-data/clixon_restconf -D 1 f /usr/local/etc/example.xml " -s /bin/sh www-data
* This is the interface:
* api/data/profile=<name>/metric=<name> PUT data:enable=<flag>
* api/test
+----------------------------+--------------------------------------+
| 100 Continue | POST accepted, 201 should follow |
| 200 OK | Success with response message-body |
| 201 Created | POST to create a resource success |
| 204 No Content | Success without response message- |
| | body |
| 304 Not Modified | Conditional operation not done |
| 400 Bad Request | Invalid request message |
| 401 Unauthorized | Client cannot be authenticated |
| 403 Forbidden | Access to resource denied |
| 404 Not Found | Resource target or resource node not |
| | found |
| 405 Method Not Allowed | Method not allowed for target |
| | resource |
| 409 Conflict | Resource or lock in use |
| 412 Precondition Failed | Conditional method is false |
| 413 Request Entity Too | too-big error |
| Large | |
| 414 Request-URI Too Large | too-big error |
| 415 Unsupported Media Type | non RESTCONF media type |
| 500 Internal Server Error | operation-failed |
| 501 Not Implemented | unknown-operation |
| 503 Service Unavailable | Recoverable server error |
+----------------------------+--------------------------------------+
Mapping netconf error-tag -> status code
+-------------------------+-------------+
| <error&#8209;tag> | status code |
+-------------------------+-------------+
| in-use | 409 |
| invalid-value | 400 |
| too-big | 413 |
| missing-attribute | 400 |
| bad-attribute | 400 |
| unknown-attribute | 400 |
| bad-element | 400 |
| unknown-element | 400 |
| unknown-namespace | 400 |
| access-denied | 403 |
| lock-denied | 409 |
| resource-denied | 409 |
| rollback-failed | 500 |
| data-exists | 409 |
| data-missing | 409 |
| operation-not-supported | 501 |
| operation-failed | 500 |
| partial-operation | 500 |
| malformed-message | 400 |
+-------------------------+-------------+
* "api-path" is "URI-encoded path expression" definition in RFC8040 3.5.3
*/
#ifdef HAVE_CONFIG_H
#include "clixon_config.h" /* generated by config & autoconf */
#endif
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <signal.h>
#include <syslog.h>
#include <fcntl.h>
#include <assert.h>
#include <time.h>
#include <signal.h>
#include <limits.h>
#include <sys/time.h>
#include <sys/wait.h>
/* cligen */
#include <cligen/cligen.h>
/* clicon */
#include <clixon/clixon.h>
#include <fcgiapp.h> /* Need to be after clixon_xml-h due to attribute format */
#include "restconf_lib.h"
#include "restconf_methods_patch.h"
/*! Generic REST PATCH method
* @param[in] h CLIXON handle
* @param[in] r Fastcgi request handle
* @param[in] api_path According to restconf (Sec 3.5.3.1 in rfc8040)
* @param[in] pcvec Vector of path ie DOCUMENT_URI element
* @param[in] pi Offset, where to start pcvec
* @param[in] qvec Vector of query string (QUERY_STRING)
* @param[in] data Stream input data
* Netconf: <edit-config> (nc:operation="merge")
* See RFC8040 Sec 4.6
*/
int
api_data_patch(clicon_handle h,
FCGX_Request *r,
char *api_path,
cvec *pcvec,
int pi,
cvec *qvec,
char *data)
{
notimplemented(r);
return 0;
}

View file

@ -0,0 +1,48 @@
/*
*
***** BEGIN LICENSE BLOCK *****
Copyright (C) 2009-2019 Olof Hagsand
This file is part of CLIXON.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Alternatively, the contents of this file may be used under the terms of
the GNU General Public License Version 3 or later (the "GPL"),
in which case the provisions of the GPL are applicable instead
of those above. If you wish to allow use of your version of this file only
under the terms of the GPL, and not to allow others to
use your version of this file under the terms of Apache License version 2,
indicate your decision by deleting the provisions above and replace them with
the notice and other provisions required by the GPL. If you do not delete
the provisions above, a recipient may use your version of this file under
the terms of any one of the Apache License version 2 or the GPL.
***** END LICENSE BLOCK *****
* Restconf method implementation
*/
#ifndef _RESTCONF_METHODS_PATCH_H_
#define _RESTCONF_METHODS_PATCH_H_
/*
* Prototypes
*/
int api_data_patch(clicon_handle h, FCGX_Request *r, char *api_path,
cvec *pcvec, int pi,
cvec *qvec, char *data);
#endif /* _RESTCONF_METHODS_PATCH_H_ */

View file

@ -62,7 +62,6 @@
#include <fcgiapp.h> /* Need to be after clixon_xml.h due to attribute format */
#include "restconf_lib.h"
#include "restconf_methods.h"
#include "restconf_methods_post.h"
/*! Generic REST POST method
@ -129,9 +128,10 @@ api_data_post(clicon_handle h,
cxobj *xerr = NULL; /* malloced must be freed */
cxobj *xe; /* dont free */
char *username;
int nullspec = 0;
int ret;
clicon_debug(1, "%s api_path:\"%s\" json:\"%s\"",
clicon_debug(1, "%s api_path:\"%s\" data:\"%s\"",
__FUNCTION__,
api_path, data);
if ((yspec = clicon_dbspec_yang(h)) == NULL){
@ -178,6 +178,15 @@ api_data_post(clicon_handle h,
}
}
else {
/* Data here cannot cannot (always) be Yang populated since it is
* loosely hanging without top symbols.
* And if it is not yang populated, it cant be translated properly
* from JSON to XML.
* Therefore, yang population is done later after addsub below
* Further complication is that if data is root resource, then it will
* work, so I need to check below that it didnt.
* THIS could be simplified.
*/
if ((ret = json_parse_str(data, yspec, &xdata0, &xerr)) < 0){
if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0)
goto done;
@ -245,9 +254,24 @@ api_data_post(clicon_handle h,
/* Replace xbot with x, ie bottom of api-path with data */
if (xml_addsub(xbot, xdata) < 0)
goto done;
/* xbot is already populated, resolve yang for added xdata too */
if (xml_spec_populate(xdata, yspec) < 0)
/* xbot is already populated, resolve yang for added xdata too
*/
nullspec = (xml_spec(xdata) == NULL);
if (xml_apply0(xdata, CX_ELMNT, xml_spec_populate, yspec) < 0)
goto done;
if (!parse_xml && nullspec){
/* json2xml decode may not have been done above in json_parse,
need to be done here instead
UNLESS it is a root resource, then json-parse does right
*/
if ((ret = json2xml_decode(xdata, &xerr)) < 0)
goto done;
if (ret == 0){
if (api_return_err(h, r, xerr, pretty, use_xml, 0) < 0)
goto done;
goto ok;
}
}
/* Create text buffer for transfer to backend */
if ((cbx = cbuf_new()) == NULL){