C-style update: Unified comment, retvals in order, remove trailing spaces
Changed function name for `clicon_debug` functions
This commit is contained in:
parent
6e314dd96f
commit
62348fc9c7
204 changed files with 6047 additions and 4904 deletions
|
|
@ -39,7 +39,7 @@
|
|||
/*
|
||||
* Types
|
||||
*/
|
||||
struct clixon_http1_yacc {
|
||||
struct clixon_http1_yacc {
|
||||
const char *hy_name; /* Name of syntax (for error string) */
|
||||
clicon_handle hy_h; /* Clixon handle */
|
||||
restconf_conn *hy_rc; /* Connection handle */
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@
|
|||
#define _HY ((clixon_http1_yacc *)_hy)
|
||||
|
||||
#undef clixon_api_path_parsewrap
|
||||
int
|
||||
int
|
||||
clixon_http1_parsewrap(void)
|
||||
{
|
||||
return 1;
|
||||
|
|
@ -100,35 +100,35 @@ query [A-Za-z0-9\-\._~!$&'()*+,;=:@?/]|%[0-9a-fA-F][0-9a-fA-F]
|
|||
<REQLINE,REQTARG,REQUERY,REQHTTP,FLDNAME,FLDVALUE><<EOF>> { return X_EOF; }
|
||||
<REQLINE>[ ] { BEGIN(REQTARG); return SP; }
|
||||
<REQLINE>{token} { clixon_http1_parselval.string = strdup(yytext);
|
||||
return TOKEN; }
|
||||
return TOKEN; }
|
||||
<REQLINE>. { clixon_http1_parseerror(_HY, "LEXICAL ERROR\n"); return -1; }
|
||||
|
||||
<REQTARG>\? { BEGIN(REQUERY); return QMARK; }
|
||||
<REQTARG>\/ { return SLASH; }
|
||||
<REQTARG>[ ] { BEGIN(REQHTTP); return SP; }
|
||||
<REQTARG>{pchar}+ { clixon_http1_parselval.string = yytext;
|
||||
return PCHARS; }
|
||||
return PCHARS; }
|
||||
<REQTARG>. { clixon_http1_parseerror(_HY, "LEXICAL ERROR\n"); return -1; }
|
||||
|
||||
<REQUERY>\/ { return SLASH; }
|
||||
<REQUERY>[ ] { BEGIN(REQHTTP); return SP; }
|
||||
<REQUERY>{query}+ { clixon_http1_parselval.string = strdup(yytext);
|
||||
return QUERY; }
|
||||
return QUERY; }
|
||||
<REQUERY>. { clixon_http1_parseerror(_HY, "LEXICAL ERROR\n"); return -1; }
|
||||
|
||||
<REQHTTP>\r\n { BEGIN(FLDNAME); return CRLF; _HY->hy_linenum++; }
|
||||
<REQHTTP>\/ { return SLASH; }
|
||||
<REQHTTP>\. { return DOT; }
|
||||
<REQHTTP>HTTP { BEGIN(REQHTTP); return HTTP; }
|
||||
<REQHTTP>[0-9] { clixon_http1_parselval.intval = atoi(yytext);
|
||||
<REQHTTP>HTTP { BEGIN(REQHTTP); return HTTP; }
|
||||
<REQHTTP>[0-9] { clixon_http1_parselval.intval = atoi(yytext);
|
||||
return DIGIT; }
|
||||
<REQHTTP>. { clixon_http1_parseerror(_HY, "LEXICAL ERROR\n"); return -1; }
|
||||
|
||||
<FLDNAME>: { BEGIN(FLDVALUE); return COLON; }
|
||||
<FLDNAME>\r\n { BEGIN(BODYM); return CRLF; _HY->hy_linenum++; }
|
||||
<FLDNAME>[ \t]+ { return RWS; }
|
||||
<FLDNAME>{token} { clixon_http1_parselval.string = strdup(yytext);
|
||||
return TOKEN; }
|
||||
<FLDNAME>{token} { clixon_http1_parselval.string = strdup(yytext);
|
||||
return TOKEN; }
|
||||
<FLDNAME>. { clixon_http1_parseerror(_HY, "LEXICAL ERROR\n"); return -1; }
|
||||
|
||||
<FLDVALUE>\r\n { BEGIN(FLDNAME); return CRLF; _HY->hy_linenum++; }
|
||||
|
|
@ -141,7 +141,7 @@ query [A-Za-z0-9\-\._~!$&'()*+,;=:@?/]|%[0-9a-fA-F][0-9a-fA-F]
|
|||
return BODY; }
|
||||
<BODYM>\n { clixon_http1_parselval.string = strdup(yytext);
|
||||
_HY->hy_linenum++;
|
||||
return BODY; }
|
||||
return BODY; }
|
||||
<BODYM><<EOF>> { return X_EOF; }
|
||||
|
||||
%%
|
||||
|
|
@ -155,7 +155,7 @@ http1_scan_init(clixon_http1_yacc *hy)
|
|||
hy->hy_lexbuf = yy_scan_string(hy->hy_parse_string);
|
||||
#if 1 /* XXX: just to use unput to avoid warning */
|
||||
if (0)
|
||||
yyunput(0, "");
|
||||
yyunput(0, "");
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
|
|
@ -172,4 +172,3 @@ http1_scan_exit(clixon_http1_yacc *hy)
|
|||
clixon_http1_parselex_destroy(); /* modern */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@
|
|||
#define _YYERROR(msg) {clicon_err(OE_XML, 0, "YYERROR %s '%s' %d", (msg), clixon_http1_parsetext, _HY->hy_linenum); YYERROR;}
|
||||
|
||||
/* add _yy to error parameters */
|
||||
#define YY_(msgid) msgid
|
||||
#define YY_(msgid) msgid
|
||||
|
||||
#include "clixon_config.h"
|
||||
|
||||
|
|
@ -106,29 +106,29 @@
|
|||
|
||||
/* Best debugging is to enable PARSE_DEBUG below and add -d to the LEX compile statement in the Makefile
|
||||
* And then run the testcase with -D 1
|
||||
* Disable it to stop any calls to clicon_debug. Having it on by default would mean very large debug outputs.
|
||||
* Disable it to stop any calls to clixon_debug. Having it on by default would mean very large debug outputs.
|
||||
*/
|
||||
#if 0
|
||||
#define _PARSE_DEBUG(s) clicon_debug(1,(s))
|
||||
#define _PARSE_DEBUG1(s, s1) clicon_debug(1,(s), (s1))
|
||||
#define _PARSE_DEBUG(s) clixon_debug(1,(s))
|
||||
#define _PARSE_DEBUG1(s, s1) clixon_debug(1,(s), (s1))
|
||||
#else
|
||||
#define _PARSE_DEBUG(s)
|
||||
#define _PARSE_DEBUG1(s, s1)
|
||||
#endif
|
||||
|
||||
/*
|
||||
/*
|
||||
also called from yacc generated code *
|
||||
*/
|
||||
|
||||
void
|
||||
void
|
||||
clixon_http1_parseerror(void *_hy,
|
||||
char *s)
|
||||
{
|
||||
clicon_err(OE_RESTCONF, 0, "%s on line %d: %s at or before: '%s'",
|
||||
char *s)
|
||||
{
|
||||
clicon_err(OE_RESTCONF, 0, "%s on line %d: %s at or before: '%s'",
|
||||
_HY->hy_name,
|
||||
_HY->hy_linenum ,
|
||||
s,
|
||||
clixon_http1_parsetext);
|
||||
_HY->hy_linenum,
|
||||
s,
|
||||
clixon_http1_parsetext);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -151,7 +151,7 @@ http1_parse_query(clixon_http1_yacc *hy,
|
|||
int retval = -1;
|
||||
restconf_stream_data *sd = NULL;
|
||||
|
||||
clicon_debug(1, "%s: ?%s ", __FUNCTION__, query);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s: ?%s ", __FUNCTION__, query);
|
||||
if ((sd = restconf_stream_find(hy->hy_rc, 0)) == NULL){
|
||||
clicon_err(OE_RESTCONF, 0, "stream 0 not found");
|
||||
goto done;
|
||||
|
|
@ -170,7 +170,7 @@ http1_body(clixon_http1_yacc *hy,
|
|||
int retval = -1;
|
||||
restconf_stream_data *sd = NULL;
|
||||
|
||||
clicon_debug(1, "%s: %s ", __FUNCTION__, body);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s: %s ", __FUNCTION__, body);
|
||||
if ((sd = restconf_stream_find(hy->hy_rc, 0)) == NULL){
|
||||
clicon_err(OE_RESTCONF, 0, "stream 0 not found");
|
||||
goto done;
|
||||
|
|
@ -200,11 +200,11 @@ http1_parse_header_field(clixon_http1_yacc *hy,
|
|||
return retval;
|
||||
}
|
||||
|
||||
%}
|
||||
%}
|
||||
|
||||
%%
|
||||
|
||||
/* start-line *( header-field CRLF ) CRLF [ message-body ]
|
||||
/* start-line *( header-field CRLF ) CRLF [ message-body ]
|
||||
* start-line = request-line / status-line (only request-line here, ignore status-line)
|
||||
*/
|
||||
http_message : request_line header_fields CRLF body X_EOF
|
||||
|
|
@ -215,7 +215,7 @@ http_message : request_line header_fields CRLF body X_EOF
|
|||
}
|
||||
_PARSE_DEBUG("http-message -> request-line header-fields body");
|
||||
YYACCEPT;
|
||||
}
|
||||
}
|
||||
;
|
||||
|
||||
body : body BODY
|
||||
|
|
@ -224,22 +224,22 @@ body : body BODY
|
|||
free($2);
|
||||
YYABORT;
|
||||
}
|
||||
else
|
||||
else
|
||||
free($2);
|
||||
_PARSE_DEBUG("body -> body BODY");
|
||||
}
|
||||
| ERROR { _PARSE_DEBUG("body -> ERROR"); YYABORT; /* shouldnt happen */ }
|
||||
| { _PARSE_DEBUG("body -> "); $$ = NULL; }
|
||||
| ERROR { _PARSE_DEBUG("body -> ERROR"); YYABORT; /* shouldnt happen */ }
|
||||
| { _PARSE_DEBUG("body -> "); $$ = NULL; }
|
||||
;
|
||||
|
||||
/* request-line = method SP request-target SP HTTP-version CRLF */
|
||||
request_line : method SP request_target SP HTTP_version CRLF
|
||||
{
|
||||
{
|
||||
_PARSE_DEBUG("request-line -> method request-target HTTP_version CRLF");
|
||||
}
|
||||
;
|
||||
|
||||
/*
|
||||
/*
|
||||
The request methods defined by this specification can be found in
|
||||
Section 4 of [RFC7231], along with information regarding the HTTP
|
||||
http://www.iana.org/assignments/http-methods/http-methods.xhtml
|
||||
|
|
@ -331,7 +331,7 @@ HTTP_version : HTTP SLASH DIGIT DOT DIGIT
|
|||
/* make sanity check later */
|
||||
_HY->hy_rc->rc_proto_d1 = $3;
|
||||
_HY->hy_rc->rc_proto_d2 = $5;
|
||||
clicon_debug(1, "clixon_http1_parse: http/%d.%d", $3, $5);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "clixon_http1_parse: http/%d.%d", $3, $5);
|
||||
_PARSE_DEBUG("HTTP-version -> HTTP / DIGIT . DIGIT");
|
||||
}
|
||||
;
|
||||
|
|
@ -388,7 +388,7 @@ field_vchars : field_vchars RWS VCHARS
|
|||
RWS = 1*( SP / HTAB )
|
||||
; required whitespace
|
||||
*/
|
||||
ows : RWS
|
||||
ows : RWS
|
||||
|
|
||||
;
|
||||
|
||||
|
|
|
|||
|
|
@ -87,8 +87,8 @@ static const map_str2str mime_map[] = {
|
|||
/*! Check if uri path denotes a data path
|
||||
*
|
||||
* @param[in] h Clixon handle
|
||||
* @retval 0 No, not a data path, or not enabled
|
||||
* @retval 1 Yes, a data path and "data" points to www-data if given
|
||||
* @retval 0 No, not a data path, or not enabled
|
||||
*/
|
||||
int
|
||||
api_path_is_data(clicon_handle h)
|
||||
|
|
@ -103,7 +103,7 @@ api_path_is_data(clicon_handle h)
|
|||
goto done;
|
||||
if ((http_data_path = clicon_option_str(h, "CLICON_HTTP_DATA_PATH")) == NULL)
|
||||
goto done;
|
||||
if (strlen(path) < strlen(http_data_path))
|
||||
if (strlen(path) < strlen(http_data_path))
|
||||
goto done;
|
||||
if (path[0] != '/')
|
||||
goto done;
|
||||
|
|
@ -117,6 +117,7 @@ api_path_is_data(clicon_handle h)
|
|||
}
|
||||
|
||||
/*! Generic restconf error function on get/head request
|
||||
*
|
||||
* @param[in] h Clixon handle
|
||||
* @param[in] req Generic http handle
|
||||
* @param[in] code Error code
|
||||
|
|
@ -130,7 +131,7 @@ api_http_data_err(clicon_handle h,
|
|||
int retval = -1;
|
||||
cbuf *cb = NULL;
|
||||
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
|
||||
if ((cb = cbuf_new()) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "cbuf_new");
|
||||
goto done;
|
||||
|
|
@ -152,23 +153,24 @@ api_http_data_err(clicon_handle h,
|
|||
// ok:
|
||||
retval = 0;
|
||||
done:
|
||||
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s retval:%d", __FUNCTION__, retval);
|
||||
if (cb)
|
||||
cbuf_free(cb);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Check validity of path, may only be regular dir or file
|
||||
*
|
||||
* No .., soft link, ~, etc
|
||||
* @param[in] h Clicon handle
|
||||
* @param[in] h Clixon handle
|
||||
* @param[in] req Generic Www handle (can be part of clixon handle)
|
||||
* @param[in] prefix Prefix of path0, where to start file check
|
||||
* @param[in,out] cbpath Filepath as cbuf, internal redirection may change it
|
||||
* @param[out] fp Open file, if retval = 1
|
||||
* @param[out] fsz Size of file, if retval = 1
|
||||
* @retval -1 Error
|
||||
* @retval 0 Invalid
|
||||
* @retval 1 OK, fp,fsz set
|
||||
* @retval 0 Invalid
|
||||
* @retval -1 Error
|
||||
*/
|
||||
static int
|
||||
http_data_check_file_path(clicon_handle h,
|
||||
|
|
@ -190,7 +192,7 @@ http_data_check_file_path(clicon_handle h,
|
|||
goto done;
|
||||
}
|
||||
p = cbuf_get(cbpath);
|
||||
clicon_debug(1, "%s %s", __FUNCTION__, p);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s %s", __FUNCTION__, p);
|
||||
if (strncmp(prefix, p, strlen(prefix)) != 0){
|
||||
clicon_err(OE_UNIX, EINVAL, "prefix is not prefix of cbpath");
|
||||
goto done;
|
||||
|
|
@ -200,31 +202,31 @@ http_data_check_file_path(clicon_handle h,
|
|||
p[i] = '\0';
|
||||
/* Ensure not soft link */
|
||||
if (lstat(p, &fstat) < 0){
|
||||
clicon_debug(1, "%s Error lstat(%s):%s", __FUNCTION__, p, strerror(errno));
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s Error lstat(%s):%s", __FUNCTION__, p, strerror(errno));
|
||||
code = 404;
|
||||
goto invalid;
|
||||
}
|
||||
if (!S_ISDIR(fstat.st_mode)){
|
||||
clicon_debug(1, "%s Error lstat(%s): Not dir", __FUNCTION__, p);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s Error lstat(%s): Not dir", __FUNCTION__, p);
|
||||
code = 403;
|
||||
goto invalid;
|
||||
}
|
||||
p[i] = '/';
|
||||
}
|
||||
else if (p[i] == '~'){
|
||||
clicon_debug(1, "%s Error lstat(%s): ~ not allowed in file path", __FUNCTION__, p);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s Error lstat(%s): ~ not allowed in file path", __FUNCTION__, p);
|
||||
code = 403;
|
||||
goto invalid;
|
||||
}
|
||||
else if (p[i] == '.' && i>strlen(prefix) && p[i-1] == '.'){
|
||||
clicon_debug(1, "%s Error lstat(%s): .. not allowed in file path", __FUNCTION__, p);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s Error lstat(%s): .. not allowed in file path", __FUNCTION__, p);
|
||||
code = 403;
|
||||
goto invalid;
|
||||
}
|
||||
}
|
||||
/* Resulting file (ensure not soft link) */
|
||||
if (lstat(p, &fstat) < 0){
|
||||
clicon_debug(1, "%s Error lstat(%s):%s", __FUNCTION__, p, strerror(errno));
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s Error lstat(%s):%s", __FUNCTION__, p, strerror(errno));
|
||||
code = 404;
|
||||
goto invalid;
|
||||
}
|
||||
|
|
@ -233,22 +235,22 @@ http_data_check_file_path(clicon_handle h,
|
|||
if (S_ISDIR(fstat.st_mode)){
|
||||
cprintf(cbpath, "/%s", HTTP_DATA_INTERNAL_REDIRECT);
|
||||
p = cbuf_get(cbpath);
|
||||
clicon_debug(1, "%s internal redirect: %s", __FUNCTION__, p);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s internal redirect: %s", __FUNCTION__, p);
|
||||
if (lstat(p, &fstat) < 0){
|
||||
clicon_debug(1, "%s Error lstat(%s):%s", __FUNCTION__, p, strerror(errno));
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s Error lstat(%s):%s", __FUNCTION__, p, strerror(errno));
|
||||
code = 404;
|
||||
goto invalid;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (!S_ISREG(fstat.st_mode)){
|
||||
clicon_debug(1, "%s Error lstat(%s): Not regular file", __FUNCTION__, p);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s Error lstat(%s): Not regular file", __FUNCTION__, p);
|
||||
code = 403;
|
||||
goto invalid;
|
||||
}
|
||||
*fsz = fstat.st_size;
|
||||
if ((f = fopen(p, "rb")) == NULL){
|
||||
clicon_debug(1, "%s Error fopen(%s) %s", __FUNCTION__, p, strerror(errno));
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s Error fopen(%s) %s", __FUNCTION__, p, strerror(errno));
|
||||
code = 403;
|
||||
goto invalid;
|
||||
}
|
||||
|
|
@ -257,17 +259,20 @@ http_data_check_file_path(clicon_handle h,
|
|||
done:
|
||||
return retval;
|
||||
invalid:
|
||||
if (api_http_data_err(h, req, code) < 0)
|
||||
if (api_http_data_err(h, req, code) < 0)
|
||||
goto done;
|
||||
retval = 0;
|
||||
goto done;
|
||||
}
|
||||
|
||||
|
||||
/*! Read file data request
|
||||
* @param[in] h Clicon handle
|
||||
*
|
||||
* @param[in] h Clixon handle
|
||||
* @param[in] req Generic Www handle (can be part of clixon handle)
|
||||
* @param[in] pathname With stripped prefix (eg /data), ultimately a filename
|
||||
* @param[in] head HEAD not GET
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
* @note: primitive file handling, just check if file exists and read it all
|
||||
* XXX 1: Buffer copying once too many, see #if 0 below
|
||||
*/
|
||||
|
|
@ -291,7 +296,7 @@ api_http_data_file(clicon_handle h,
|
|||
char *buf = NULL;
|
||||
size_t sz;
|
||||
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
|
||||
if ((cbfile = cbuf_new()) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "cbuf_new");
|
||||
goto done;
|
||||
|
|
@ -304,9 +309,9 @@ api_http_data_file(clicon_handle h,
|
|||
cprintf(cbfile, "%s", www_data_root);
|
||||
if (pathname){
|
||||
if (strlen(pathname) && pathname[0] != '/'){
|
||||
clicon_debug(1, "%s Error fopen(%s) pathname not prefixed with /",
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s Error fopen(%s) pathname not prefixed with /",
|
||||
__FUNCTION__, pathname);
|
||||
if (api_http_data_err(h, req, 404) < 0)
|
||||
if (api_http_data_err(h, req, 404) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
|
|
@ -333,7 +338,7 @@ api_http_data_file(clicon_handle h,
|
|||
fsize = ftell(f);
|
||||
/* Extra sanity check, had some problems with wrong file types */
|
||||
if (fsz != fsize){
|
||||
clicon_debug(1, "%s Error file %s size mismatch sz:%zu vs %li",
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s Error file %s size mismatch sz:%zu vs %li",
|
||||
__FUNCTION__, filename, (size_t)fsz, fsize);
|
||||
if (api_http_data_err(h, req, 500) < 0) /* Internal error? */
|
||||
goto done;
|
||||
|
|
@ -357,7 +362,7 @@ api_http_data_file(clicon_handle h,
|
|||
}
|
||||
sz = (size_t)ret;
|
||||
if (sz != 1){
|
||||
clicon_debug(1, "%s Error fread(%s) sz:%zu", __FUNCTION__, filename, sz);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s Error fread(%s) sz:%zu", __FUNCTION__, filename, sz);
|
||||
if (api_http_data_err(h, req, 500) < 0) /* Internal error? */
|
||||
goto done;
|
||||
goto ok;
|
||||
|
|
@ -371,7 +376,7 @@ api_http_data_file(clicon_handle h,
|
|||
if (restconf_reply_send(req, 200, cbdata, head) < 0)
|
||||
goto done;
|
||||
cbdata = NULL; /* consumed by reply-send */
|
||||
clicon_debug(1, "%s Read %s OK", __FUNCTION__, filename);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s Read %s OK", __FUNCTION__, filename);
|
||||
ok:
|
||||
retval = 0;
|
||||
done:
|
||||
|
|
@ -396,10 +401,12 @@ api_http_data_file(clicon_handle h,
|
|||
* 5. indata should be NULL (no write operations)
|
||||
* 6. Limited media: text/html, JavaScript, image, and css
|
||||
* 7. Authentication as restconf
|
||||
* @param[in] h Clicon handle
|
||||
* @param[in] h Clixon handle
|
||||
* @param[in] req Generic Www handle (can be part of clixon handle)
|
||||
* @param[in] qvec Query parameters, ie the ?<id>=<val>&<id>=<val> stuff
|
||||
* @param[in] pathname With stripped prefix (eg /data), ultimately a filename
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
* Need to enable clixon-restconf.yang www-data feature
|
||||
*/
|
||||
int
|
||||
|
|
@ -416,7 +423,7 @@ api_http_data(clicon_handle h,
|
|||
cbuf *indata = NULL;
|
||||
char *path = NULL;
|
||||
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
|
||||
if (req == NULL){
|
||||
errno = EINVAL;
|
||||
goto done;
|
||||
|
|
@ -442,7 +449,7 @@ api_http_data(clicon_handle h,
|
|||
else {
|
||||
if (api_http_data_err(h, req, 405) < 0) /* method not allowed */
|
||||
goto done;
|
||||
goto ok;
|
||||
goto ok;
|
||||
}
|
||||
/* 3. query parameters not accepted */
|
||||
if (qvec != NULL){
|
||||
|
|
@ -460,7 +467,7 @@ api_http_data(clicon_handle h,
|
|||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
/* 5. Accepted media_out: should check text/html, JavaScript, image, and css
|
||||
/* 5. Accepted media_out: should check text/html, JavaScript, image, and css
|
||||
*/
|
||||
if ((media_str = restconf_param_get(h, "HTTP_ACCEPT")) == NULL){
|
||||
}
|
||||
|
|
@ -491,6 +498,6 @@ api_http_data(clicon_handle h,
|
|||
done:
|
||||
if (path)
|
||||
free(path);
|
||||
clicon_debug(1, "%s %d", __FUNCTION__, retval);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s %d", __FUNCTION__, retval);
|
||||
return retval;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ extern "C" {
|
|||
* Types
|
||||
*/
|
||||
/*! RESTCONF media types
|
||||
*
|
||||
* @see http_media_map
|
||||
* @note DUPLICATED in restconf_lib.h
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -69,6 +69,7 @@
|
|||
|
||||
|
||||
/*! HTTP headers done, if there is a message body coming next
|
||||
*
|
||||
* @param[in] req Fastcgi request handle
|
||||
* @retval body Handle for body handling (in fcgi same as req)
|
||||
*
|
||||
|
|
@ -86,9 +87,12 @@ restconf_reply_body_start(void *req0)
|
|||
}
|
||||
|
||||
/*! Add HTTP header field name and value to reply, fcgi specific
|
||||
*
|
||||
* @param[in] req Fastcgi request handle
|
||||
* @param[in] name HTTP header field name
|
||||
* @param[in] vfmt HTTP header field value format string w variable parameter
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
* @see eg RFC 7230
|
||||
*/
|
||||
int
|
||||
|
|
@ -102,7 +106,7 @@ restconf_reply_header(void *req0,
|
|||
size_t vlen;
|
||||
char *value = NULL;
|
||||
va_list ap;
|
||||
|
||||
|
||||
if (req == NULL || name == NULL || vfmt == NULL){
|
||||
clicon_err(OE_CFG, EINVAL, "req, name or value is NULL");
|
||||
return -1;
|
||||
|
|
@ -116,14 +120,14 @@ restconf_reply_header(void *req0,
|
|||
goto done;
|
||||
}
|
||||
/* second round: compute actual value */
|
||||
va_start(ap, vfmt);
|
||||
va_start(ap, vfmt);
|
||||
if (vsnprintf(value, vlen+1, vfmt, ap) < 0){
|
||||
clicon_err(OE_UNIX, errno, "vsnprintf");
|
||||
va_end(ap);
|
||||
goto done;
|
||||
}
|
||||
va_end(ap);
|
||||
FCGX_FPrintF(req->out, "%s: %s\r\n", name, value);
|
||||
FCGX_FPrintF(req->out, "%s: %s\r\n", name, value);
|
||||
retval = 0;
|
||||
done:
|
||||
if (value)
|
||||
|
|
@ -132,9 +136,12 @@ restconf_reply_header(void *req0,
|
|||
}
|
||||
|
||||
/*! Add HTTP message body to reply, fcgi specific
|
||||
*
|
||||
* @param[in] req Fastcgi request handle
|
||||
* @param[in,out] content_len This is for Content-Length header
|
||||
* @param[in] bfmt HTTP message body format string w variable parameter
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
* @see eg RFC 7230
|
||||
*/
|
||||
int
|
||||
|
|
@ -163,14 +170,14 @@ restconf_reply_body_add(void *req0,
|
|||
goto done;
|
||||
}
|
||||
/* second round: compute actual body */
|
||||
va_start(ap, bfmt);
|
||||
va_start(ap, bfmt);
|
||||
if (vsnprintf(body, blen+1, bfmt, ap) < 0){
|
||||
clicon_err(OE_UNIX, errno, "vsnprintf");
|
||||
va_end(ap);
|
||||
goto done;
|
||||
}
|
||||
va_end(ap);
|
||||
FCGX_FPrintF(req->out, "%s", body);
|
||||
FCGX_FPrintF(req->out, "%s", body);
|
||||
/* Increment in/out Content-Length parameter */
|
||||
if (content_len){
|
||||
sz = strlen(body);
|
||||
|
|
@ -184,12 +191,14 @@ restconf_reply_body_add(void *req0,
|
|||
}
|
||||
|
||||
/*! Send HTTP reply with potential message body
|
||||
* @param[in] req Fastcgi request handle
|
||||
* @param[in] code Status code
|
||||
* @param[in] cb Body as a cbuf if non-NULL. Note is consumed
|
||||
* @param[in] head Only send headers, dont send body.
|
||||
*
|
||||
*
|
||||
* Prerequisites: status code set, headers given, body if wanted set
|
||||
* @param[in] req Fastcgi request handle
|
||||
* @param[in] code Status code
|
||||
* @param[in] cb Body as a cbuf if non-NULL. Note is consumed
|
||||
* @param[in] head Only send headers, dont send body.
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
*/
|
||||
int
|
||||
restconf_reply_send(void *req0,
|
||||
|
|
@ -222,6 +231,7 @@ restconf_reply_send(void *req0,
|
|||
}
|
||||
|
||||
/*! Get input data from http request, eg such as curl -X PUT http://... <indata>
|
||||
*
|
||||
* @param[in] req Fastcgi request handle
|
||||
* @retval indata
|
||||
* @retval NULL Error
|
||||
|
|
|
|||
|
|
@ -65,9 +65,12 @@
|
|||
#include "restconf_native.h"
|
||||
|
||||
/*! Add HTTP header field name and value to reply
|
||||
*
|
||||
* @param[in] req request handle
|
||||
* @param[in] name HTTP header field name
|
||||
* @param[in] vfmt HTTP header field value format string w variable parameter
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
* @see eg RFC 7230
|
||||
*/
|
||||
int
|
||||
|
|
@ -83,7 +86,7 @@ restconf_reply_header(void *req0,
|
|||
char *value = NULL;
|
||||
va_list ap;
|
||||
|
||||
clicon_debug(1, "%s %s", __FUNCTION__, name);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s %s", __FUNCTION__, name);
|
||||
if (sd == NULL || name == NULL || vfmt == NULL){
|
||||
clicon_err(OE_CFG, EINVAL, "sd, name or value is NULL");
|
||||
goto done;
|
||||
|
|
@ -102,7 +105,7 @@ restconf_reply_header(void *req0,
|
|||
goto done;
|
||||
}
|
||||
/* Second round: compute actual value */
|
||||
va_start(ap, vfmt);
|
||||
va_start(ap, vfmt);
|
||||
if (vsnprintf(value, vlen+1, vfmt, ap) < 0){
|
||||
clicon_err(OE_UNIX, errno, "vsnprintf");
|
||||
va_end(ap);
|
||||
|
|
@ -121,11 +124,13 @@ restconf_reply_header(void *req0,
|
|||
}
|
||||
|
||||
/*! Send HTTP reply with potential message body
|
||||
* @param[in] req http request handle
|
||||
* @param[in] code Status code
|
||||
* @param[in] cb Body as a cbuf if non-NULL. Note: is consumed
|
||||
* @param[in] head Only send headers, dont send body.
|
||||
*
|
||||
*
|
||||
* @param[in] req http request handle
|
||||
* @param[in] code Status code
|
||||
* @param[in] cb Body as a cbuf if non-NULL. Note: is consumed
|
||||
* @param[in] head Only send headers, dont send body.
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
* Prerequisites: status code set, headers given, body if wanted set
|
||||
*/
|
||||
int
|
||||
|
|
@ -137,7 +142,7 @@ restconf_reply_send(void *req0,
|
|||
int retval = -1;
|
||||
restconf_stream_data *sd = (restconf_stream_data *)req0;
|
||||
|
||||
clicon_debug(1, "%s code:%d", __FUNCTION__, code);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s code:%d", __FUNCTION__, code);
|
||||
if (sd == NULL){
|
||||
clicon_err(OE_CFG, EINVAL, "sd is NULL");
|
||||
goto done;
|
||||
|
|
@ -145,7 +150,7 @@ restconf_reply_send(void *req0,
|
|||
sd->sd_code = code;
|
||||
if (cb != NULL){
|
||||
if (cbuf_len(cb)){
|
||||
sd->sd_body_len = cbuf_len(cb);
|
||||
sd->sd_body_len = cbuf_len(cb);
|
||||
if (head){
|
||||
cbuf_free(cb);
|
||||
}
|
||||
|
|
@ -156,17 +161,18 @@ restconf_reply_send(void *req0,
|
|||
}
|
||||
else{
|
||||
cbuf_free(cb);
|
||||
sd->sd_body_len = 0;
|
||||
sd->sd_body_len = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
sd->sd_body_len = 0;
|
||||
sd->sd_body_len = 0;
|
||||
retval = 0;
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Get input data from http request, eg such as curl -X PUT http://... <indata>
|
||||
*
|
||||
* @param[in] req Request handle
|
||||
* @note: reuses cbuf from stream-data
|
||||
*/
|
||||
|
|
@ -175,7 +181,7 @@ restconf_get_indata(void *req0)
|
|||
{
|
||||
restconf_stream_data *sd = (restconf_stream_data *)req0;
|
||||
cbuf *cb = NULL;
|
||||
|
||||
|
||||
if (sd == NULL){
|
||||
clicon_err(OE_CFG, EINVAL, "sd is NULL");
|
||||
goto done;
|
||||
|
|
|
|||
|
|
@ -70,10 +70,13 @@
|
|||
#include "restconf_err.h"
|
||||
|
||||
/*! HTTP error 405 Not Allowed
|
||||
*
|
||||
* @param[in] req Generic http handle
|
||||
* @param[in] allow Which methods are allowed
|
||||
* @param[in] pretty Pretty-print of reply
|
||||
* @param[in] media_out Restconf output media
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
*/
|
||||
int
|
||||
restconf_method_notallowed(clicon_handle h,
|
||||
|
|
@ -100,7 +103,10 @@ restconf_method_notallowed(clicon_handle h,
|
|||
}
|
||||
|
||||
/*! HTTP error 415 Unsupported media
|
||||
*
|
||||
* @param[in] req Generic http handle
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
* RFC8040, section 5.2:
|
||||
* If the server does not support the requested input encoding for a request, then it MUST
|
||||
* return an error response with a "415 Unsupported Media Type" status-line
|
||||
|
|
@ -117,7 +123,7 @@ restconf_unsupported_media(clicon_handle h,
|
|||
if (netconf_operation_not_supported_xml(&xerr, "protocol", "Unsupported Media Type") < 0)
|
||||
goto done;
|
||||
/* override with 415 netconf->restoconf translation which gives a 405 */
|
||||
if (api_return_err0(h, req, xerr, pretty, media, 415) < 0)
|
||||
if (api_return_err0(h, req, xerr, pretty, media, 415) < 0)
|
||||
goto done;
|
||||
retval = 0;
|
||||
done:
|
||||
|
|
@ -129,7 +135,9 @@ restconf_unsupported_media(clicon_handle h,
|
|||
/*! HTTP error 406 Not acceptable
|
||||
*
|
||||
* @param[in] req Generic http handle
|
||||
* RFC8040, section 5.2:
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
* @see RFC8040, section 5.2:
|
||||
* 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.
|
||||
*/
|
||||
|
|
@ -145,7 +153,7 @@ restconf_not_acceptable(clicon_handle h,
|
|||
if (netconf_operation_not_supported_xml(&xerr, "protocol", "Unacceptable output encoding") < 0)
|
||||
goto done;
|
||||
/* Override with 415 netconf->restoconf translation which gives a 405 */
|
||||
if (api_return_err0(h, req, xerr, pretty, media, 415) < 0)
|
||||
if (api_return_err0(h, req, xerr, pretty, media, 415) < 0)
|
||||
goto done;
|
||||
if (restconf_reply_send(req, 415, NULL, 0) < 0)
|
||||
goto done;
|
||||
|
|
@ -179,6 +187,7 @@ restconf_notimplemented(clicon_handle h,
|
|||
}
|
||||
|
||||
/*! Generic restconf error function on get/head request
|
||||
*
|
||||
* @param[in] h Clixon handle
|
||||
* @param[in] req Generic http handle
|
||||
* @param[in] xerr XML error message (eg from backend, or from a clixon_netconf_lib function)
|
||||
|
|
@ -186,6 +195,8 @@ restconf_notimplemented(clicon_handle h,
|
|||
* @param[in] media Output media
|
||||
* @param[in] code If 0 use rfc8040 sec 7 netconf2restconf error-tag mapping
|
||||
* otherwise use this code
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
* xerr should be on the form: <rpc-error>... otherwise an internal error is generated
|
||||
* @note there are special cases see code
|
||||
*/
|
||||
|
|
@ -202,12 +213,12 @@ api_return_err(clicon_handle h,
|
|||
cbuf *cberr = NULL;
|
||||
cxobj *xtag;
|
||||
char *tagstr;
|
||||
int code;
|
||||
int code;
|
||||
cxobj *xerr2 = NULL;
|
||||
cxobj *xmsg;
|
||||
char *mb;
|
||||
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
|
||||
if ((cb = cbuf_new()) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "cbuf_new");
|
||||
goto done;
|
||||
|
|
@ -238,7 +249,7 @@ api_return_err(clicon_handle h,
|
|||
}
|
||||
}
|
||||
#if 1
|
||||
clicon_debug_xml(1, xerr, "%s Send error:", __FUNCTION__);
|
||||
clixon_debug_xml(CLIXON_DBG_DEFAULT, xerr, "%s Send error:", __FUNCTION__);
|
||||
#endif
|
||||
if (xml_name_set(xerr, "error") < 0)
|
||||
goto done;
|
||||
|
|
@ -265,17 +276,17 @@ api_return_err(clicon_handle h,
|
|||
if (strcmp(tagstr, "invalid-value") == 0 &&
|
||||
(xmsg = xpath_first(xerr, NULL, "error-message")) != NULL &&
|
||||
(mb = xml_body(xmsg)) != NULL &&
|
||||
strcmp(mb, "Invalid HTTP data method") == 0)
|
||||
strcmp(mb, "Invalid HTTP data method") == 0)
|
||||
code = 404; /* Not found */
|
||||
}
|
||||
}
|
||||
}
|
||||
if (restconf_reply_header(req, "Content-Type", "%s", restconf_media_int2str(media)) < 0) // XXX
|
||||
goto done;
|
||||
switch (media){
|
||||
case YANG_DATA_XML:
|
||||
case YANG_PATCH_XML:
|
||||
case YANG_PAGINATION_XML:
|
||||
clicon_debug(1, "%s code:%d", __FUNCTION__, code);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s code:%d", __FUNCTION__, code);
|
||||
if (pretty){
|
||||
cprintf(cb, " <errors xmlns=\"urn:ietf:params:xml:ns:yang:ietf-restconf\">\n");
|
||||
if (clixon_xml2cbuf(cb, xerr, 2, pretty, NULL, -1, 0) < 0)
|
||||
|
|
@ -291,7 +302,7 @@ api_return_err(clicon_handle h,
|
|||
break;
|
||||
case YANG_DATA_JSON:
|
||||
case YANG_PATCH_JSON:
|
||||
clicon_debug(1, "%s code:%d", __FUNCTION__, code);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s code:%d", __FUNCTION__, code);
|
||||
if (pretty){
|
||||
cprintf(cb, "{\n\"ietf-restconf:errors\" : ");
|
||||
if (clixon_json2cbuf(cb, xerr, pretty, 0, 0) < 0)
|
||||
|
|
@ -318,7 +329,7 @@ api_return_err(clicon_handle h,
|
|||
// ok:
|
||||
retval = 0;
|
||||
done:
|
||||
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s retval:%d", __FUNCTION__, retval);
|
||||
if (cb)
|
||||
cbuf_free(cb);
|
||||
if (cberr)
|
||||
|
|
@ -337,6 +348,8 @@ api_return_err(clicon_handle h,
|
|||
* @param[in] media Output media
|
||||
* @param[in] code If 0 use rfc8040 sec 7 netconf2restconf error-tag mapping
|
||||
* otherwise use this code
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
* @see api_return_err where top level is expected to be <rpc-error>
|
||||
*/
|
||||
int
|
||||
|
|
|
|||
|
|
@ -77,6 +77,7 @@
|
|||
* entries in the struct below.
|
||||
*/
|
||||
/*! Backend specific handle added to header CLICON handle
|
||||
*
|
||||
* This file should only contain access functions for the _specific_
|
||||
* entries in the struct below.
|
||||
* @note The top part must be equivalent to struct clicon_handle in clixon_handle.c
|
||||
|
|
@ -88,7 +89,7 @@ struct restconf_handle {
|
|||
clicon_hash_t *rh_data; /* internal clicon data (HDR) */
|
||||
clicon_hash_t *rh_db_elmnt; /* xml datastore element cache data */
|
||||
event_stream_t *rh_stream; /* notification streams, see clixon_stream.[ch] */
|
||||
|
||||
|
||||
/* ------ end of common handle ------ */
|
||||
clicon_hash_t *rh_params; /* restconf parameters, including http headers */
|
||||
clixon_auth_type_t rh_auth_type; /* authentication type */
|
||||
|
|
@ -110,6 +111,7 @@ restconf_handle_init(void)
|
|||
}
|
||||
|
||||
/*! Deallocates a backend handle, including all client structs
|
||||
*
|
||||
* @note: handle 'h' cannot be used in calls after this
|
||||
* @see backend_client_rm
|
||||
*/
|
||||
|
|
@ -117,7 +119,7 @@ int
|
|||
restconf_handle_exit(clicon_handle h)
|
||||
{
|
||||
struct restconf_handle *rh = handle(h);
|
||||
|
||||
|
||||
if (rh->rh_fcgi_socket)
|
||||
free(rh->rh_fcgi_socket);
|
||||
clicon_handle_exit(h); /* frees h and options (and streams) */
|
||||
|
|
@ -125,7 +127,8 @@ restconf_handle_exit(clicon_handle h)
|
|||
}
|
||||
|
||||
/*! Get restconf http parameter
|
||||
* @param[in] h Clicon handle
|
||||
*
|
||||
* @param[in] h Clixon handle
|
||||
* @param[in] name Data name
|
||||
* @retval val Data value as string
|
||||
* Currently using clixon runtime data but there is risk for colliding names
|
||||
|
|
@ -142,7 +145,8 @@ restconf_param_get(clicon_handle h,
|
|||
}
|
||||
|
||||
/*! Set restconf http parameter
|
||||
* @param[in] h Clicon handle
|
||||
*
|
||||
* @param[in] h Clixon handle
|
||||
* @param[in] name Data name
|
||||
* @param[in] val Data value as null-terminated string
|
||||
* @retval 0 OK
|
||||
|
|
@ -156,7 +160,7 @@ restconf_param_set(clicon_handle h,
|
|||
{
|
||||
struct restconf_handle *rh = handle(h);
|
||||
|
||||
clicon_debug(1, "%s: %s=%s", __FUNCTION__, param, val);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s: %s=%s", __FUNCTION__, param, val);
|
||||
if (rh->rh_params == NULL)
|
||||
if ((rh->rh_params = clicon_hash_init()) == NULL)
|
||||
return -1;
|
||||
|
|
@ -164,7 +168,8 @@ restconf_param_set(clicon_handle h,
|
|||
}
|
||||
|
||||
/*! Delete all restconf http parameter
|
||||
* @param[in] h Clicon handle
|
||||
*
|
||||
* @param[in] h Clixon handle
|
||||
* @param[in] name Data name
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
|
|
@ -175,7 +180,7 @@ restconf_param_del_all(clicon_handle h)
|
|||
{
|
||||
int retval = -1;
|
||||
struct restconf_handle *rh = handle(h);
|
||||
|
||||
|
||||
if (rh->rh_params != NULL){
|
||||
if (clicon_hash_free(rh->rh_params) < 0)
|
||||
goto done;
|
||||
|
|
@ -187,7 +192,8 @@ restconf_param_del_all(clicon_handle h)
|
|||
}
|
||||
|
||||
/*! Get restconf http parameter
|
||||
* @param[in] h Clicon handle
|
||||
*
|
||||
* @param[in] h Clixon handle
|
||||
* @retval auth_type
|
||||
*/
|
||||
clixon_auth_type_t
|
||||
|
|
@ -199,7 +205,8 @@ restconf_auth_type_get(clicon_handle h)
|
|||
}
|
||||
|
||||
/*! Set restconf http parameter
|
||||
* @param[in] h Clicon handle
|
||||
*
|
||||
* @param[in] h Clixon handle
|
||||
* @param[in] name Data name
|
||||
* @param[in] val Data value as null-terminated string
|
||||
* @retval 0 OK
|
||||
|
|
@ -217,7 +224,8 @@ restconf_auth_type_set(clicon_handle h,
|
|||
}
|
||||
|
||||
/*! Get restconf pretty-print (for replies)
|
||||
* @param[in] h Clicon handle
|
||||
*
|
||||
* @param[in] h Clixon handle
|
||||
* @retval pretty
|
||||
*/
|
||||
int
|
||||
|
|
@ -229,7 +237,8 @@ restconf_pretty_get(clicon_handle h)
|
|||
}
|
||||
|
||||
/*! Set restconf pretty-print
|
||||
* @param[in] h Clicon handle
|
||||
*
|
||||
* @param[in] h Clixon handle
|
||||
* @param[in] pretty 0 or 1
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
|
|
@ -245,6 +254,7 @@ restconf_pretty_set(clicon_handle h,
|
|||
}
|
||||
|
||||
/*! Get restconf http-data
|
||||
*
|
||||
* @param[in] h Clixon handle
|
||||
* @retval 0 Yes, http-data enabled
|
||||
* @retval 1 No, http-data disabled
|
||||
|
|
@ -258,6 +268,7 @@ restconf_http_data_get(clicon_handle h)
|
|||
}
|
||||
|
||||
/*! Set restconf http-data
|
||||
*
|
||||
* @param[in] h Clixon handle
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
|
|
@ -273,7 +284,8 @@ restconf_http_data_set(clicon_handle h,
|
|||
}
|
||||
|
||||
/*! Get restconf fcgi socket path
|
||||
* @param[in] h Clicon handle
|
||||
*
|
||||
* @param[in] h Clixon handle
|
||||
* @retval socketpath
|
||||
*/
|
||||
char*
|
||||
|
|
@ -285,7 +297,8 @@ restconf_fcgi_socket_get(clicon_handle h)
|
|||
}
|
||||
|
||||
/*! Set restconf fcgi socketpath
|
||||
* @param[in] h Clicon handle
|
||||
*
|
||||
* @param[in] h Clixon handle
|
||||
* @param[in] name Data name
|
||||
* @param[in] val Data value as null-terminated string
|
||||
* @retval 0 OK
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@
|
|||
#include "clixon_http_data.h"
|
||||
|
||||
/* Size of xml read buffer */
|
||||
#define BUFLEN 1024
|
||||
#define BUFLEN 1024
|
||||
|
||||
/*! HTTP/1 parsing function. Input is string and side-effect is populating connection structs
|
||||
*
|
||||
|
|
@ -80,7 +80,7 @@
|
|||
* @retval 0 Parse OK
|
||||
* @retval -1 Error with clicon_err called.
|
||||
*/
|
||||
static int
|
||||
static int
|
||||
_http1_parse(clicon_handle h,
|
||||
restconf_conn *rc,
|
||||
char *str,
|
||||
|
|
@ -90,7 +90,7 @@ _http1_parse(clicon_handle h,
|
|||
clixon_http1_yacc hy = {0,};
|
||||
int ret;
|
||||
|
||||
clicon_debug(1, "%s:\n%s", __FUNCTION__, str);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s:\n%s", __FUNCTION__, str);
|
||||
if (strlen(str) == 0)
|
||||
goto ok;
|
||||
hy.hy_parse_string = str;
|
||||
|
|
@ -119,7 +119,7 @@ _http1_parse(clicon_handle h,
|
|||
ok:
|
||||
retval = 0;
|
||||
done:
|
||||
clicon_debug(1, "%s %d", __FUNCTION__, retval);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s %d", __FUNCTION__, retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
|
@ -147,7 +147,7 @@ clixon_http1_parse_file(clicon_handle h,
|
|||
int len = 0;
|
||||
int oldbuflen;
|
||||
|
||||
clicon_debug(1, "%s %s", __FUNCTION__, filename);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s %s", __FUNCTION__, filename);
|
||||
if (f == NULL){
|
||||
clicon_err(OE_RESTCONF, EINVAL, "f is NULL");
|
||||
goto done;
|
||||
|
|
@ -197,7 +197,7 @@ clixon_http1_parse_file(clicon_handle h,
|
|||
* @retval 0 Parse OK
|
||||
* @retval -1 Error with clicon_err called.
|
||||
*/
|
||||
int
|
||||
int
|
||||
clixon_http1_parse_string(clicon_handle h,
|
||||
restconf_conn *rc,
|
||||
char *str)
|
||||
|
|
@ -217,7 +217,7 @@ clixon_http1_parse_string(clicon_handle h,
|
|||
* @note Had preferred to do this without copying, OR
|
||||
* input flex with a non-null terminated string
|
||||
*/
|
||||
int
|
||||
int
|
||||
clixon_http1_parse_buf(clicon_handle h,
|
||||
restconf_conn *rc,
|
||||
char *buf,
|
||||
|
|
@ -225,7 +225,7 @@ clixon_http1_parse_buf(clicon_handle h,
|
|||
{
|
||||
char *str = NULL;
|
||||
int ret;
|
||||
|
||||
|
||||
if ((str = malloc(n+1)) == NULL){
|
||||
clicon_err(OE_RESTCONF, errno, "malloc");
|
||||
return -1;
|
||||
|
|
@ -239,6 +239,7 @@ clixon_http1_parse_buf(clicon_handle h,
|
|||
|
||||
#ifdef HAVE_LIBNGHTTP2
|
||||
/*! Check http/1 UPGRADE to http/2
|
||||
*
|
||||
* If upgrade headers are encountered AND http/2 is configured, then
|
||||
* - add upgrade headers or signal error
|
||||
* - set http2 flag get settings to and signal to upper layer to do the actual transition.
|
||||
|
|
@ -256,13 +257,13 @@ http1_upgrade_http2(clicon_handle h,
|
|||
char *str;
|
||||
char *settings;
|
||||
cxobj *xerr = NULL;
|
||||
|
||||
|
||||
if ((str = restconf_param_get(h, "HTTP_UPGRADE")) != NULL &&
|
||||
clicon_option_bool(h, "CLICON_RESTCONF_HTTP2_PLAIN") == 1){
|
||||
/* Only accept "h2c" */
|
||||
if (strcmp(str, "h2c") != 0){
|
||||
if (netconf_invalid_value_xml(&xerr, "protocol", "Invalid upgrade token") < 0)
|
||||
goto done;
|
||||
goto done;
|
||||
if (api_return_err0(h, sd, xerr, 1, YANG_DATA_JSON, 0) < 0)
|
||||
goto done;
|
||||
if (xerr)
|
||||
|
|
@ -301,7 +302,7 @@ restconf_http1_reply(restconf_conn *rc,
|
|||
int retval = -1;
|
||||
cg_var *cv;
|
||||
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
|
||||
/* If body, add a content-length header
|
||||
* A server MUST NOT send a Content-Length header field in any response
|
||||
* with a status code of 1xx (Informational) or 204 (No Content). A
|
||||
|
|
@ -311,7 +312,7 @@ restconf_http1_reply(restconf_conn *rc,
|
|||
*/
|
||||
if (sd->sd_code != 204 && sd->sd_code > 199)
|
||||
if (restconf_reply_header(sd, "Content-Length", "%zu", sd->sd_body_len) < 0)
|
||||
goto done;
|
||||
goto done;
|
||||
/* Create reply and write headers */
|
||||
#if 0 /* XXX need some keep-alive logic here */
|
||||
/* protocol is HTTP/1.0 and clients wants to keep established */
|
||||
|
|
@ -342,9 +343,12 @@ restconf_http1_reply(restconf_conn *rc,
|
|||
return retval;
|
||||
}
|
||||
|
||||
/*!
|
||||
/*! restconf http1 path root
|
||||
*
|
||||
* @param[in] h Clixon handle
|
||||
* @param[in] rc Clixon request connect pointer
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
*/
|
||||
int
|
||||
restconf_http1_path_root(clicon_handle h,
|
||||
|
|
@ -360,8 +364,8 @@ restconf_http1_path_root(clicon_handle h,
|
|||
#ifdef HAVE_LIBNGHTTP2
|
||||
int ret;
|
||||
#endif
|
||||
|
||||
clicon_debug(1, "------------");
|
||||
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "------------");
|
||||
pretty = restconf_pretty_get(h);
|
||||
if ((sd = restconf_stream_find(rc, 0)) == NULL){
|
||||
clicon_err(OE_RESTCONF, EINVAL, "No stream_data");
|
||||
|
|
@ -392,7 +396,7 @@ restconf_http1_path_root(clicon_handle h,
|
|||
*/
|
||||
if (sd->sd_path != NULL){
|
||||
free(sd->sd_path);
|
||||
sd->sd_path = NULL;
|
||||
sd->sd_path = NULL;
|
||||
}
|
||||
#endif
|
||||
if ((sd->sd_path = restconf_uripath(rc->rc_h)) == NULL)
|
||||
|
|
@ -459,7 +463,7 @@ restconf_http1_path_root(clicon_handle h,
|
|||
goto done;
|
||||
retval = 0;
|
||||
done:
|
||||
clicon_debug(1, "%s %d", __FUNCTION__, retval);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s %d", __FUNCTION__, retval);
|
||||
if (subject)
|
||||
free(subject);
|
||||
if (xerr)
|
||||
|
|
@ -486,7 +490,7 @@ http1_check_expect(clicon_handle h,
|
|||
{
|
||||
int retval = -1;
|
||||
char *val;
|
||||
|
||||
|
||||
if ((val = restconf_param_get(h, "HTTP_EXPECT")) != NULL &&
|
||||
strcmp(val, "100-continue") == 0){ /* just drop if not well-formed */
|
||||
sd->sd_code = 100;
|
||||
|
|
@ -521,7 +525,7 @@ http1_check_content_length(clicon_handle h,
|
|||
int retval = -1;
|
||||
char *val;
|
||||
int len;
|
||||
|
||||
|
||||
if ((val = restconf_param_get(h, "HTTP_CONTENT_LENGTH")) == NULL ||
|
||||
(len = atoi(val)) == 0)
|
||||
*status = 0;
|
||||
|
|
|
|||
|
|
@ -125,7 +125,7 @@ Mapping netconf error-tag -> status code
|
|||
static const map_str2int netconf_restconf_map[] = {
|
||||
{"in-use", 409},
|
||||
{"invalid-value", 400}, /* or 404 special case if msg is: "Invalid HTTP data method" handled in api_return_err */
|
||||
{"invalid-value", 404},
|
||||
{"invalid-value", 404},
|
||||
{"invalid-value", 406},
|
||||
{"too-big", 413}, /* request */
|
||||
{"too-big", 400}, /* response */
|
||||
|
|
@ -137,7 +137,7 @@ static const map_str2int netconf_restconf_map[] = {
|
|||
{"unknown-element", 400},
|
||||
{"unknown-namespace", 400},
|
||||
{"access-denied", 403}, /* or 401 special case if msg is: "The requested URL was unauthorized" handled in api_return_err */
|
||||
{"access-denied", 401},
|
||||
{"access-denied", 401},
|
||||
{"lock-denied", 409},
|
||||
{"resource-denied", 409},
|
||||
{"rollback-failed", 500},
|
||||
|
|
@ -157,7 +157,7 @@ static const map_str2int netconf_restconf_map[] = {
|
|||
static const map_str2int http_reason_phrase_map[] = {
|
||||
{"Continue", 100},
|
||||
{"Switching Protocols", 101},
|
||||
{"OK", 200},
|
||||
{"OK", 200},
|
||||
{"Created", 201},
|
||||
{"Accepted", 202},
|
||||
{"Non-Authoritative Information", 203},
|
||||
|
|
@ -215,7 +215,7 @@ static const map_str2int http_media_map[] = {
|
|||
static const map_str2int http_proto_map[] = {
|
||||
{"http/1.0", HTTP_10},
|
||||
{"http/1.1", HTTP_11},
|
||||
{"http/2", HTTP_2},
|
||||
{"http/2", HTTP_2},
|
||||
{NULL, -1}
|
||||
};
|
||||
|
||||
|
|
@ -262,7 +262,7 @@ restconf_proto2str(int proto)
|
|||
* media-type = type "/" subtype *( OWS ";" OWS parameter )
|
||||
* type = token
|
||||
* subtype = token
|
||||
*
|
||||
*
|
||||
*/
|
||||
restconf_media
|
||||
restconf_content_type(clicon_handle h)
|
||||
|
|
@ -291,7 +291,7 @@ restconf_convert_hdr(clicon_handle h,
|
|||
int i;
|
||||
char c;
|
||||
size_t len;
|
||||
|
||||
|
||||
if ((cb = cbuf_new()) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "cbuf_new");
|
||||
goto done;
|
||||
|
|
@ -322,10 +322,12 @@ restconf_convert_hdr(clicon_handle h,
|
|||
* @param[in] cookiestr cookie string according to rfc6265 (modified)
|
||||
* @param[in] attribute cookie attribute
|
||||
* @param[out] val malloced cookie value, free with free()
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
*/
|
||||
int
|
||||
get_user_cookie(char *cookiestr,
|
||||
char *attribute,
|
||||
get_user_cookie(char *cookiestr,
|
||||
char *attribute,
|
||||
char **val)
|
||||
{
|
||||
int retval = -1;
|
||||
|
|
@ -345,7 +347,7 @@ get_user_cookie(char *cookiestr,
|
|||
return retval;
|
||||
}
|
||||
|
||||
/*! Clean and close all state of restconf process (but dont exit).
|
||||
/*! Clean and close all state of restconf process (but dont exit).
|
||||
*
|
||||
* Cannot use h after this
|
||||
* @param[in] h Clixon handle
|
||||
|
|
@ -358,7 +360,7 @@ restconf_terminate(clicon_handle h)
|
|||
cxobj *x;
|
||||
int fs; /* fgcx socket */
|
||||
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
|
||||
if ((fs = clicon_socket_get(h)) != -1)
|
||||
close(fs);
|
||||
/* Delete all plugins, and RPC callbacks */
|
||||
|
|
@ -376,8 +378,8 @@ restconf_terminate(clicon_handle h)
|
|||
xpath_optimize_exit();
|
||||
restconf_handle_exit(h);
|
||||
clixon_err_exit();
|
||||
clicon_debug(1, "%s pid:%u done", __FUNCTION__, getpid());
|
||||
clicon_log_exit(); /* Must be after last clicon_debug */
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s pid:%u done", __FUNCTION__, getpid());
|
||||
clicon_log_exit(); /* Must be after last clixon_debug */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -492,10 +494,10 @@ restconf_insert_attributes(cxobj *xdata,
|
|||
/*! Callback for yang extensions ietf-restconf:yang-data
|
||||
*
|
||||
* @param[in] h Clixon handle
|
||||
* @param[in] yext Yang node of extension
|
||||
* @param[in] yext Yang node of extension
|
||||
* @param[in] ys Yang node of (unknown) statement belonging to extension
|
||||
* @retval 0 OK, all callbacks executed OK
|
||||
* @retval -1 Error in one callback
|
||||
* @retval 0 OK, all callbacks executed OK
|
||||
* @retval -1 Error in one callback
|
||||
* @note This extension adds semantics to YANG according to RFC8040 as follows:
|
||||
* - The list-stmt is not required to have a key-stmt defined.(NB!!)
|
||||
* - The if-feature-stmt is ignored if present.
|
||||
|
|
@ -516,13 +518,13 @@ restconf_main_extension_cb(clicon_handle h,
|
|||
yang_stmt *ymod;
|
||||
yang_stmt *yc;
|
||||
yang_stmt *yn = NULL;
|
||||
|
||||
|
||||
ymod = ys_module(yext);
|
||||
modname = yang_argument_get(ymod);
|
||||
extname = yang_argument_get(yext);
|
||||
if (strcmp(modname, "ietf-restconf") != 0 || strcmp(extname, "yang-data") != 0)
|
||||
goto ok;
|
||||
clicon_debug(1, "%s Enabled extension:%s:%s", __FUNCTION__, modname, extname);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s Enabled extension:%s:%s", __FUNCTION__, modname, extname);
|
||||
if ((yc = yang_find(ys, 0, NULL)) == NULL)
|
||||
goto ok;
|
||||
if ((yn = ys_dup(yc)) == NULL)
|
||||
|
|
@ -566,7 +568,9 @@ restconf_uripath(clicon_handle h)
|
|||
|
||||
/*! Drop privileges from root to user (or already at user)
|
||||
*
|
||||
* @param[in] h Clicon handle
|
||||
* @param[in] h Clixon handle
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
* Group set to CLICON_SOCK_GROUP to communicate with backend
|
||||
*/
|
||||
int
|
||||
|
|
@ -579,8 +583,8 @@ restconf_drop_privileges(clicon_handle h)
|
|||
gid_t gid = -1;
|
||||
char *user;
|
||||
enum priv_mode_t priv_mode = PM_NONE;
|
||||
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
|
||||
/* Sanity check: backend group exists */
|
||||
if ((group = clicon_sock_group(h)) == NULL){
|
||||
clicon_err(OE_FATAL, 0, "clicon_sock_group option not set");
|
||||
|
|
@ -635,7 +639,7 @@ restconf_drop_privileges(clicon_handle h)
|
|||
case PM_NONE:
|
||||
break; /* catched above */
|
||||
}
|
||||
clicon_debug(1, "%s dropped privileges from root to %s(%d)",
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s dropped privileges from root to %s(%d)",
|
||||
__FUNCTION__, user, newuid);
|
||||
ok:
|
||||
retval = 0;
|
||||
|
|
@ -643,8 +647,9 @@ restconf_drop_privileges(clicon_handle h)
|
|||
return retval;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @param[in] h Clicon handle
|
||||
/*! restconf auth cb
|
||||
*
|
||||
* @param[in] h Clixon handle
|
||||
* @param[in] req Generic Www handle (can be part of clixon handle)
|
||||
* @param[in] pretty Pretty-print
|
||||
* @param[in] media_out Restconf output media
|
||||
|
|
@ -666,9 +671,9 @@ restconf_authentication_cb(clicon_handle h,
|
|||
cxobj *xret = NULL;
|
||||
cxobj *xerr;
|
||||
char *anonymous = NULL;
|
||||
|
||||
|
||||
auth_type = restconf_auth_type_get(h);
|
||||
clicon_debug(1, "%s auth-type:%s", __FUNCTION__, clixon_auth_type_int2str(auth_type));
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s auth-type:%s", __FUNCTION__, clixon_auth_type_int2str(auth_type));
|
||||
ret = 0;
|
||||
authenticated = 0;
|
||||
/* ret: -1 Error, 0: Ignore/not handled, 1: OK see authenticated parameter */
|
||||
|
|
@ -689,7 +694,7 @@ restconf_authentication_cb(clicon_handle h,
|
|||
if ((anonymous = clicon_option_str(h, "CLICON_ANONYMOUS_USER")) == NULL){
|
||||
break; /* not authenticated */
|
||||
}
|
||||
clicon_username_set(h, anonymous);
|
||||
clicon_username_set(h, anonymous);
|
||||
authenticated = 1;
|
||||
break;
|
||||
case CLIXON_AUTH_CLIENT_CERTIFICATE: {
|
||||
|
|
@ -701,7 +706,7 @@ restconf_authentication_cb(clicon_handle h,
|
|||
}
|
||||
break;
|
||||
}
|
||||
case CLIXON_AUTH_USER:
|
||||
case CLIXON_AUTH_USER:
|
||||
authenticated = 0;
|
||||
break;
|
||||
}
|
||||
|
|
@ -720,7 +725,7 @@ restconf_authentication_cb(clicon_handle h,
|
|||
/* If set but no user, set a dummy user */
|
||||
retval = 1;
|
||||
done:
|
||||
clicon_debug(1, "%s retval:%d authenticated:%d user:%s",
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s retval:%d authenticated:%d user:%s",
|
||||
__FUNCTION__, retval, authenticated, clicon_username_get(h));
|
||||
if (username)
|
||||
free(username);
|
||||
|
|
@ -752,7 +757,7 @@ restconf_config_init(clicon_handle h,
|
|||
int auth_type;
|
||||
yang_stmt *yspec;
|
||||
yang_stmt *y;
|
||||
|
||||
|
||||
if ((yspec = clicon_dbspec_yang(h)) == NULL){
|
||||
clicon_err(OE_FATAL, 0, "No DB_SPEC");
|
||||
goto done;
|
||||
|
|
@ -763,7 +768,7 @@ restconf_config_init(clicon_handle h,
|
|||
if ((x = xpath_first(xrestconf, nsc, "enable")) != NULL &&
|
||||
(enable = xml_body(x)) != NULL){
|
||||
if (strcmp(enable, "false") == 0){
|
||||
clicon_debug(1, "%s restconf disabled", __FUNCTION__);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s restconf disabled", __FUNCTION__);
|
||||
goto disable;
|
||||
}
|
||||
}
|
||||
|
|
@ -794,7 +799,7 @@ restconf_config_init(clicon_handle h,
|
|||
strcmp(bstr, "true") == 0) {
|
||||
restconf_http_data_set(h, 1);
|
||||
}
|
||||
else
|
||||
else
|
||||
restconf_http_data_set(h, 0);
|
||||
|
||||
/* Check if fcgi-socket is true and that feature is enabled
|
||||
|
|
@ -817,14 +822,16 @@ restconf_config_init(clicon_handle h,
|
|||
}
|
||||
|
||||
/*! Create and bind restconf socket
|
||||
*
|
||||
*
|
||||
* @param[in] netns0 Network namespace, special value "default" is same as NULL
|
||||
* @param[in] addrstr Address as string, eg "0.0.0.0", "::"
|
||||
* @param[in] addrtype One of inet:ipv4-address or inet:ipv6-address
|
||||
* @param[in] port TCP port
|
||||
* @param[in] backlog Listen backlog, queie of pending connections
|
||||
* @param[in] flags Socket flags OR:ed in with the socket(2) type parameter
|
||||
* @param[in] backlog Listen backlog, queie of pending connections
|
||||
* @param[in] flags Socket flags OR:ed in with the socket(2) type parameter
|
||||
* @param[out] ss Server socket (bound for accept)
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
*/
|
||||
int
|
||||
restconf_socket_init(const char *netns0,
|
||||
|
|
@ -841,7 +848,7 @@ restconf_socket_init(const char *netns0,
|
|||
size_t sa_len;
|
||||
const char *netns;
|
||||
|
||||
clicon_debug(1, "%s %s %s %s %hu", __FUNCTION__, netns0, addrtype, addrstr, port);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s %s %s %s %hu", __FUNCTION__, netns0, addrtype, addrstr, port);
|
||||
/* netns default -> NULL */
|
||||
if (netns0 != NULL && strcmp(netns0, RESTCONF_NETNS_DEFAULT)==0)
|
||||
netns = NULL;
|
||||
|
|
@ -851,10 +858,10 @@ restconf_socket_init(const char *netns0,
|
|||
goto done;
|
||||
if (clixon_netns_socket(netns, sa, sa_len, backlog, flags, addrstr, ss) < 0)
|
||||
goto done;
|
||||
clicon_debug(1, "%s ss=%d", __FUNCTION__, *ss);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s ss=%d", __FUNCTION__, *ss);
|
||||
retval = 0;
|
||||
done:
|
||||
clicon_debug(1, "%s %d", __FUNCTION__, retval);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s %d", __FUNCTION__, retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ extern "C" {
|
|||
* Types
|
||||
*/
|
||||
/*! RESTCONF media types
|
||||
*
|
||||
* @see http_media_map
|
||||
* @note DUPLICATED in clixon_restconf.h
|
||||
*/
|
||||
|
|
@ -76,7 +77,7 @@ enum restconf_http_proto{
|
|||
HTTP_2
|
||||
};
|
||||
typedef enum restconf_http_proto restconf_http_proto;
|
||||
|
||||
|
||||
/*
|
||||
* Prototypes
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -91,8 +91,11 @@
|
|||
#define RESTCONF_OPTS "hD:f:E:l:C:p:d:y:a:u:rW:R:o:"
|
||||
|
||||
/*! Convert FCGI parameters to clixon runtime data
|
||||
*
|
||||
* @param[in] h Clixon handle
|
||||
* @param[in] envp Fastcgi request handle parameter array on the format "<param>=<value>"
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
* @see https://nginx.org/en/docs/http/ngx_http_core_module.html#var_https
|
||||
*/
|
||||
static int
|
||||
|
|
@ -104,7 +107,7 @@ fcgi_params_set(clicon_handle h,
|
|||
char *param = NULL;
|
||||
char *val = NULL;
|
||||
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
|
||||
for (i = 0; envp[i] != NULL; i++){ /* on the form <param>=<value> */
|
||||
if (clixon_strsplit(envp[i], '=', ¶m, &val) < 0)
|
||||
goto done;
|
||||
|
|
@ -121,7 +124,7 @@ fcgi_params_set(clicon_handle h,
|
|||
}
|
||||
retval = 0;
|
||||
done:
|
||||
clicon_debug(1, "%s %d", __FUNCTION__, retval);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s %d", __FUNCTION__, retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
|
@ -134,7 +137,7 @@ restconf_main_config(clicon_handle h,
|
|||
{
|
||||
int retval = -1;
|
||||
struct passwd *pw;
|
||||
cxobj *xconfig = NULL;
|
||||
cxobj *xconfig = NULL;
|
||||
cxobj *xrestconf = NULL;
|
||||
uint32_t id = 0;
|
||||
cxobj *xerr = NULL;
|
||||
|
|
@ -144,7 +147,7 @@ restconf_main_config(clicon_handle h,
|
|||
|
||||
/* 1. try inline configure option */
|
||||
if (inline_config != NULL && strlen(inline_config)){
|
||||
clicon_debug(1, "restconf_main_fcgi using restconf inline config");
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "restconf_main_fcgi using restconf inline config");
|
||||
if ((ret = clixon_xml_parse_string(inline_config, YB_MODULE, yspec, &xrestconf, &xerr)) < 0)
|
||||
goto done;
|
||||
if (ret == 0){
|
||||
|
|
@ -217,19 +220,19 @@ static clicon_handle _CLICON_HANDLE = NULL;
|
|||
*/
|
||||
static int _MYSOCK;
|
||||
|
||||
/*! Signall terminates process
|
||||
/*! Signal terminates process
|
||||
*/
|
||||
static void
|
||||
restconf_sig_term(int arg)
|
||||
{
|
||||
static int i=0;
|
||||
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
|
||||
if (i++ == 0)
|
||||
clicon_log(LOG_NOTICE, "%s: %s: pid: %u Signal %d",
|
||||
clicon_log(LOG_NOTICE, "%s: %s: pid: %u Signal %d",
|
||||
__PROGRAM__, __FUNCTION__, getpid(), arg);
|
||||
else{
|
||||
clicon_debug(1, "%s done", __FUNCTION__);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s done", __FUNCTION__);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
|
|
@ -237,11 +240,12 @@ restconf_sig_term(int arg)
|
|||
* is entered, it will terminate.
|
||||
* However there may be a case of sockets closing rather abruptly for clients
|
||||
*/
|
||||
clixon_exit_set(1);
|
||||
clixon_exit_set(1);
|
||||
close(_MYSOCK);
|
||||
}
|
||||
|
||||
/*! Reap stream child
|
||||
*
|
||||
* XXX The -1 should be changed to proper pid, see eg clixon_process_waitpid
|
||||
*/
|
||||
static void
|
||||
|
|
@ -255,8 +259,9 @@ restconf_sig_child(int arg)
|
|||
}
|
||||
|
||||
/*! Usage help routine
|
||||
*
|
||||
* @param[in] h Clixon handle
|
||||
* @param[in] argv0 command line
|
||||
* @param[in] h Clicon handle
|
||||
*/
|
||||
static void
|
||||
usage(clicon_handle h,
|
||||
|
|
@ -285,9 +290,9 @@ usage(clicon_handle h,
|
|||
}
|
||||
|
||||
/*! Main routine for fastcgi restconf */
|
||||
int
|
||||
main(int argc,
|
||||
char **argv)
|
||||
int
|
||||
main(int argc,
|
||||
char **argv)
|
||||
{
|
||||
int retval = -1;
|
||||
int sock;
|
||||
|
|
@ -318,7 +323,7 @@ main(int argc,
|
|||
enum format_enum config_dump_format = FORMAT_XML;
|
||||
|
||||
/* In the startup, logs to stderr & debug flag set later */
|
||||
clicon_log_init(__PROGRAM__, LOG_INFO, logdst);
|
||||
clicon_log_init(__PROGRAM__, LOG_INFO, logdst);
|
||||
|
||||
/* Create handle */
|
||||
if ((h = restconf_handle_init()) == NULL)
|
||||
|
|
@ -355,12 +360,12 @@ main(int argc,
|
|||
break;
|
||||
} /* switch getopt */
|
||||
|
||||
/*
|
||||
/*
|
||||
* Logs, error and debug to stderr or syslog, set debug level
|
||||
*/
|
||||
clicon_log_init(__PROGRAM__, dbg?LOG_DEBUG:LOG_INFO, logdst);
|
||||
clicon_log_init(__PROGRAM__, dbg?LOG_DEBUG:LOG_INFO, logdst);
|
||||
|
||||
clicon_debug_init(dbg, NULL);
|
||||
clixon_debug_init(dbg, NULL);
|
||||
clicon_log(LOG_NOTICE, "%s fcgi: %u Started", __PROGRAM__, getpid());
|
||||
if (set_signal(SIGTERM, restconf_sig_term, NULL) < 0){
|
||||
clicon_err(OE_DAEMON, errno, "Setting signal");
|
||||
|
|
@ -450,10 +455,10 @@ main(int argc,
|
|||
|
||||
if ((sz = clicon_option_int(h, "CLICON_LOG_STRING_LIMIT")) != 0)
|
||||
clicon_log_string_limit_set(sz);
|
||||
|
||||
|
||||
/* Set default namespace according to CLICON_NAMESPACE_NETCONF_DEFAULT */
|
||||
xml_nsctx_namespace_netconf_default(h);
|
||||
|
||||
|
||||
/* Add (hardcoded) netconf features in case ietf-netconf loaded here
|
||||
* Otherwise it is loaded in netconf_module_load below
|
||||
*/
|
||||
|
|
@ -470,7 +475,7 @@ main(int argc,
|
|||
goto done;
|
||||
/* In case ietf-yang-metadata is loaded by application, handle annotation extension */
|
||||
if (yang_metadata_init(h) < 0)
|
||||
goto done;
|
||||
goto done;
|
||||
/* Load restconf plugins before yangs are loaded (eg extension callbacks) */
|
||||
if ((dir = clicon_restconf_dir(h)) != NULL)
|
||||
if (clixon_plugins_load(h, CLIXON_PLUGIN_INIT, dir, NULL) < 0)
|
||||
|
|
@ -510,7 +515,7 @@ main(int argc,
|
|||
/* Load yang restconf module */
|
||||
if (yang_spec_parse_module(h, "ietf-restconf", NULL, yspec)< 0)
|
||||
goto done;
|
||||
|
||||
|
||||
#ifdef CLIXON_YANG_PATCH
|
||||
/* Load yang restconf patch module */
|
||||
if (yang_spec_parse_module(h, "ietf-yang-patch", NULL, yspec)< 0)
|
||||
|
|
@ -520,7 +525,7 @@ main(int argc,
|
|||
/* Add netconf yang spec, used as internal protocol */
|
||||
if (netconf_module_load(h) < 0)
|
||||
goto done;
|
||||
|
||||
|
||||
/* Add system modules */
|
||||
if (clicon_option_bool(h, "CLICON_STREAM_DISCOVERY_RFC8040") &&
|
||||
yang_spec_parse_module(h, "ietf-restconf-monitoring", NULL, yspec)< 0)
|
||||
|
|
@ -561,7 +566,7 @@ main(int argc,
|
|||
clicon_err(OE_CFG, errno, "FCGX_Init");
|
||||
goto done;
|
||||
}
|
||||
clicon_debug(1, "restconf_main: Opening FCGX socket: %s", sockpath);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "restconf_main: Opening FCGX socket: %s", sockpath);
|
||||
if ((sock = FCGX_OpenSocket(sockpath, 10)) < 0){
|
||||
clicon_err(OE_CFG, errno, "FCGX_OpenSocket");
|
||||
goto done;
|
||||
|
|
@ -596,7 +601,7 @@ main(int argc,
|
|||
* @see clicon_hello_req
|
||||
*/
|
||||
clicon_data_set(h, "session-transport", "cl:restconf");
|
||||
|
||||
|
||||
if (FCGX_InitRequest(req, sock, 0) != 0){
|
||||
clicon_err(OE_CFG, errno, "FCGX_InitRequest");
|
||||
goto done;
|
||||
|
|
@ -608,7 +613,7 @@ main(int argc,
|
|||
clicon_err(OE_CFG, errno, "FCGX_Accept_r");
|
||||
goto done;
|
||||
}
|
||||
clicon_debug(1, "------------");
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "------------");
|
||||
|
||||
/* Translate from FCGI parameter form to Clixon runtime data
|
||||
* XXX: potential name collision?
|
||||
|
|
@ -616,7 +621,7 @@ main(int argc,
|
|||
if (fcgi_params_set(h, req->envp) < 0)
|
||||
goto done;
|
||||
if ((path = restconf_param_get(h, "REQUEST_URI")) == NULL){
|
||||
clicon_debug(1, "NULL URI");
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "NULL URI");
|
||||
}
|
||||
else {
|
||||
/* Matching algorithm:
|
||||
|
|
@ -637,7 +642,7 @@ main(int argc,
|
|||
if (uri_str2cvec(query, '&', '=', 1, &qvec) < 0)
|
||||
goto done;
|
||||
if (api_root_restconf(h, req, qvec) < 0)
|
||||
goto done;
|
||||
goto done;
|
||||
}
|
||||
else if (api_path_is_stream(h)){
|
||||
query = restconf_param_get(h, "QUERY_STRING");
|
||||
|
|
@ -648,9 +653,9 @@ main(int argc,
|
|||
(void)api_stream(h, req, qvec, &finish);
|
||||
}
|
||||
else{
|
||||
clicon_debug(1, "top-level %s not found", path);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "top-level %s not found", path);
|
||||
if (netconf_invalid_value_xml(&xerr, "protocol", "Top-level path not found") < 0)
|
||||
goto done;
|
||||
goto done;
|
||||
if (api_return_err0(h, req, xerr, 1, YANG_DATA_JSON, 0) < 0)
|
||||
goto done;
|
||||
if (xerr){
|
||||
|
|
|
|||
|
|
@ -180,11 +180,13 @@ static int session_id_context = 1;
|
|||
|
||||
/*! Set restconf native handle
|
||||
*
|
||||
* @param[in] h Clicon handle
|
||||
* @param[in] rh Restconf native handle (malloced pointer)
|
||||
* @param[in] h Clixon handle
|
||||
* @param[in] rh Restconf native handle (malloced pointer)
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
*/
|
||||
static int
|
||||
restconf_native_handle_set(clicon_handle h,
|
||||
restconf_native_handle_set(clicon_handle h,
|
||||
restconf_native_handle *rh)
|
||||
{
|
||||
clicon_hash_t *cdat = clicon_data(h);
|
||||
|
|
@ -215,7 +217,7 @@ clixon_openssl_log_cb(void *handle,
|
|||
int suberr,
|
||||
cbuf *cb)
|
||||
{
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
|
||||
ERR_print_errors_cb(print_cb, cb);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -224,7 +226,7 @@ clixon_openssl_log_cb(void *handle,
|
|||
*/
|
||||
static int
|
||||
init_openssl(void)
|
||||
{
|
||||
{
|
||||
int retval = -1;
|
||||
|
||||
/* In Openssl 1.1 lib inits itself (?)
|
||||
|
|
@ -241,7 +243,8 @@ init_openssl(void)
|
|||
return retval;
|
||||
}
|
||||
|
||||
/*!
|
||||
/*! Verify cert
|
||||
*
|
||||
* The verify_callback function is used to control the behaviour when the SSL_VERIFY_PEER flag
|
||||
* is set. It must be supplied by the application and receives two arguments: preverify_ok
|
||||
* indicates, whether the verification of the certificate in question was passed
|
||||
|
|
@ -258,23 +261,22 @@ restconf_verify_certs(int preverify_ok,
|
|||
int depth;
|
||||
// SSL *ssl;
|
||||
// clicon_handle h;
|
||||
|
||||
err_cert = X509_STORE_CTX_get_current_cert(store);
|
||||
err = X509_STORE_CTX_get_error(store);
|
||||
depth = X509_STORE_CTX_get_error_depth(store);
|
||||
// ssl = X509_STORE_CTX_get_ex_data(store, SSL_get_ex_data_X509_STORE_CTX_idx());
|
||||
|
||||
clicon_debug(1, "%s preverify_ok:%d err:%d depth:%d", __FUNCTION__, preverify_ok, err, depth);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s preverify_ok:%d err:%d depth:%d", __FUNCTION__, preverify_ok, err, depth);
|
||||
X509_NAME_oneline(X509_get_subject_name(err_cert), buf, 256);
|
||||
switch (err){
|
||||
case X509_V_ERR_HOSTNAME_MISMATCH:
|
||||
clicon_debug(1, "%s X509_V_ERR_HOSTNAME_MISMATCH", __FUNCTION__);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s X509_V_ERR_HOSTNAME_MISMATCH", __FUNCTION__);
|
||||
break;
|
||||
case X509_V_ERR_CERT_HAS_EXPIRED:
|
||||
clicon_debug(1, "%s X509_V_ERR_CERT_HAS_EXPIRED", __FUNCTION__);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s X509_V_ERR_CERT_HAS_EXPIRED", __FUNCTION__);
|
||||
break;
|
||||
case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
|
||||
clicon_debug(1, "%s X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT", __FUNCTION__);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT", __FUNCTION__);
|
||||
break;
|
||||
}
|
||||
/* Catch a too long certificate chain. should be +1 in SSL_CTX_set_verify_depth() */
|
||||
|
|
@ -282,7 +284,7 @@ restconf_verify_certs(int preverify_ok,
|
|||
preverify_ok = 0;
|
||||
err = X509_V_ERR_CERT_CHAIN_TOO_LONG;
|
||||
X509_STORE_CTX_set_error(store, err);
|
||||
}
|
||||
}
|
||||
else{
|
||||
/* Verify the CA name */
|
||||
}
|
||||
|
|
@ -303,7 +305,7 @@ alpn_proto_dump(const char *label,
|
|||
const char *inp,
|
||||
unsigned len)
|
||||
{
|
||||
clicon_debug(1, "%s %.*s", label, (int)len, inp);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s %.*s", label, (int)len, inp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -325,13 +327,13 @@ alpn_select_proto_cb(SSL *ssl,
|
|||
unsigned char len;
|
||||
int pref = 0;
|
||||
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
|
||||
/* select http/1.1 */
|
||||
inp = (unsigned char*)in;
|
||||
while ((inp-in) < inlen) {
|
||||
len = *inp;
|
||||
inp++;
|
||||
if (clicon_debug_get()) /* debug print the protoocol */
|
||||
if (clixon_debug_get()) /* debug print the protoocol */
|
||||
alpn_proto_dump(__FUNCTION__, (const char*)inp, len);
|
||||
#ifdef HAVE_HTTP1
|
||||
if (pref < 10 && len == 8 && strncmp((char*)inp, "http/1.1", len) == 0){
|
||||
|
|
@ -454,18 +456,18 @@ restconf_listcerts(SSL *ssl)
|
|||
X509 *cert;
|
||||
char *line;
|
||||
|
||||
clicon_debug(1, "%s get peer certificates:", __FUNCTION__);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s get peer certificates:", __FUNCTION__);
|
||||
if ((cert = SSL_get_peer_certificate(ssl)) != NULL) { /* Get certificates (if available) */
|
||||
if ((line = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0)) != NULL){
|
||||
clicon_debug(1, "Subject: %s", line);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "Subject: %s", line);
|
||||
free(line);
|
||||
}
|
||||
if ((line = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0)) != NULL){
|
||||
clicon_debug(1, "Issuer: %s", line);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "Issuer: %s", line);
|
||||
free(line);
|
||||
}
|
||||
if ((line = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0)) != NULL){
|
||||
clicon_debug(1, "Subject: %s", line);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "Subject: %s", line);
|
||||
free(line);
|
||||
}
|
||||
X509_free(cert);
|
||||
|
|
@ -475,7 +477,7 @@ restconf_listcerts(SSL *ssl)
|
|||
#endif/* debug */
|
||||
|
||||
/*! Check if a "cert" file exists
|
||||
*
|
||||
*
|
||||
* @param[in] xrestconf XML tree containing restconf config
|
||||
* @param[in] name Name of configured "cert" name
|
||||
* @param[out] var String variable
|
||||
|
|
@ -515,6 +517,8 @@ restconf_checkcert_file(cxobj *xrestconf,
|
|||
*
|
||||
* @param[in] fd Socket (unix or ip)
|
||||
* @param[in] arg typecast clicon_handle
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
* @see openssl_init_socket where this callback is registered
|
||||
*/
|
||||
static int
|
||||
|
|
@ -530,11 +534,11 @@ restconf_accept_client(int fd,
|
|||
char *name = NULL;
|
||||
void *addr;
|
||||
|
||||
clicon_debug(1, "%s %d", __FUNCTION__, fd);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s %d", __FUNCTION__, fd);
|
||||
if ((rsock = (restconf_socket *)arg) == NULL){
|
||||
clicon_err(OE_YANG, EINVAL, "rsock is NULL");
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
h = rsock->rs_h;
|
||||
len = sizeof(from);
|
||||
if ((s = accept(rsock->rs_ss, &from, &len)) < 0){
|
||||
|
|
@ -566,7 +570,7 @@ restconf_accept_client(int fd,
|
|||
}
|
||||
if (inet_ntop(from.sa_family, addr, rsock->rs_from_addr, INET6_ADDRSTRLEN) < 0)
|
||||
goto done;
|
||||
clicon_debug(1, "%s type:%s from:%s, dest:%s port:%hu", __FUNCTION__,
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s type:%s from:%s, dest:%s port:%hu", __FUNCTION__,
|
||||
rsock->rs_addrtype,
|
||||
rsock->rs_from_addr,
|
||||
rsock->rs_addrstr,
|
||||
|
|
@ -577,7 +581,7 @@ restconf_accept_client(int fd,
|
|||
goto done;
|
||||
retval = 0;
|
||||
done:
|
||||
clicon_debug(1, "%s retval %d", __FUNCTION__, retval);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s retval %d", __FUNCTION__, retval);
|
||||
if (name)
|
||||
free(name);
|
||||
return retval;
|
||||
|
|
@ -592,7 +596,7 @@ restconf_native_terminate(clicon_handle h)
|
|||
restconf_socket *rsock;
|
||||
restconf_conn *rc;
|
||||
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
|
||||
if ((rn = restconf_native_handle_get(h)) != NULL){
|
||||
while ((rsock = rn->rn_sockets) != NULL){
|
||||
while ((rc = rsock->rs_conns) != NULL){
|
||||
|
|
@ -702,11 +706,11 @@ restconf_clixon_backend(clicon_handle h,
|
|||
|
||||
/*! Per-socket openssl inits
|
||||
*
|
||||
* @param[in] h Clicon handle
|
||||
* @param[in] h Clixon handle
|
||||
* @param[in] xs XML config of single restconf socket
|
||||
* @param[in] nsc Namespace context
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
* @retval -1 Error
|
||||
*/
|
||||
static int
|
||||
openssl_init_socket(clicon_handle h,
|
||||
|
|
@ -723,7 +727,7 @@ openssl_init_socket(clicon_handle h,
|
|||
restconf_socket *rsock = NULL; /* openssl per socket struct */
|
||||
struct timeval now;
|
||||
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
|
||||
/*
|
||||
* Create per-socket openssl handle
|
||||
* See restconf_native_terminate for freeing
|
||||
|
|
@ -782,7 +786,7 @@ openssl_init_socket(clicon_handle h,
|
|||
/* ss is a server socket that the clients connect to. The callback
|
||||
therefore accepts clients on ss */
|
||||
rsock->rs_ss = ss;
|
||||
if (clixon_event_reg_fd(rsock->rs_ss, restconf_accept_client, rsock, "restconf socket") < 0)
|
||||
if (clixon_event_reg_fd(rsock->rs_ss, restconf_accept_client, rsock, "restconf socket") < 0)
|
||||
goto done;
|
||||
}
|
||||
retval = 0;
|
||||
|
|
@ -793,7 +797,7 @@ openssl_init_socket(clicon_handle h,
|
|||
/*! Init openssl, open and register server socket (ready for accept)
|
||||
*
|
||||
* Given a fully populated configuration tree.
|
||||
* @param[in] h Clicon handle
|
||||
* @param[in] h Clixon handle
|
||||
* @param[in] dbg0 Manually set debug flag, if set overrides configuration setting
|
||||
* @param[in] xrestconf XML tree containing restconf config
|
||||
* @retval 0 OK
|
||||
|
|
@ -820,7 +824,7 @@ restconf_openssl_init(clicon_handle h,
|
|||
size_t veclen;
|
||||
int i;
|
||||
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
|
||||
/* flag used for sanity of certs */
|
||||
ssl_enable = xpath_first(xrestconf, nsc, "socket[ssl='true']") != NULL;
|
||||
/* Auth type set in config */
|
||||
|
|
@ -830,7 +834,7 @@ restconf_openssl_init(clicon_handle h,
|
|||
(x = xpath_first(xrestconf, nsc, "debug")) != NULL &&
|
||||
(bstr = xml_body(x)) != NULL){
|
||||
dbg = atoi(bstr);
|
||||
clicon_debug_init(dbg, NULL);
|
||||
clixon_debug_init(dbg, NULL);
|
||||
/* If debug was enabled here from config and not initially,
|
||||
* print clixn options and loaded yang files
|
||||
*/
|
||||
|
|
@ -889,7 +893,7 @@ restconf_openssl_init(clicon_handle h,
|
|||
return retval;
|
||||
}
|
||||
|
||||
/*! Read restconf from config
|
||||
/*! Read restconf from config
|
||||
*
|
||||
* After SEVERAL iterations the code now does as follows:
|
||||
* - init clixon
|
||||
|
|
@ -897,13 +901,13 @@ restconf_openssl_init(clicon_handle h,
|
|||
* - if local config found, open sockets accordingly and exit function
|
||||
* - If no local config found, query backend for config and open sockets.
|
||||
* That is, EITHER local config OR read config from backend once
|
||||
* @param[in] h Clicon handle
|
||||
* @param[in] h Clixon handle
|
||||
* @param[in] inline_config If set, restconf conf is given by -R command-line
|
||||
* @param[out] xrestconf XML restconf config, malloced (if retval = 1)
|
||||
* @retval 1 OK (and xrestconf set)
|
||||
* @retval 0 Fail - no config
|
||||
* @retval -1 Error
|
||||
*/
|
||||
*/
|
||||
int
|
||||
restconf_clixon_init(clicon_handle h,
|
||||
char *inline_config,
|
||||
|
|
@ -984,7 +988,6 @@ restconf_clixon_init(clicon_handle h,
|
|||
/* Load yang restconf module */
|
||||
if (yang_spec_parse_module(h, "ietf-restconf", NULL, yspec)< 0)
|
||||
goto done;
|
||||
|
||||
#ifdef CLIXON_YANG_PATCH
|
||||
/* Load yang restconf patch module */
|
||||
if (yang_spec_parse_module(h, "ietf-yang-patch", NULL, yspec)< 0)
|
||||
|
|
@ -1010,7 +1013,7 @@ restconf_clixon_init(clicon_handle h,
|
|||
if (clicon_nsctx_global_set(h, nsctx_global) < 0)
|
||||
goto done;
|
||||
if (inline_config != NULL && strlen(inline_config)){
|
||||
clicon_debug(1, "%s reading from inline config", __FUNCTION__);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s reading from inline config", __FUNCTION__);
|
||||
if ((ret = clixon_xml_parse_string(inline_config, YB_MODULE, yspec, &xrestconf, &xerr)) < 0)
|
||||
goto done;
|
||||
if (ret == 0){
|
||||
|
|
@ -1032,10 +1035,10 @@ restconf_clixon_init(clicon_handle h,
|
|||
goto done;
|
||||
}
|
||||
else if (clicon_option_bool(h, "CLICON_BACKEND_RESTCONF_PROCESS") == 0){
|
||||
clicon_debug(1, "%s reading from clixon config", __FUNCTION__);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s reading from clixon config", __FUNCTION__);
|
||||
/* If not read from backend, try to get restconf config from local config-file */
|
||||
if ((xrestconf = clicon_conf_restconf(h)) != NULL){
|
||||
/*! Basic config init, set auth-type, pretty, etc ret 0 means disabled */
|
||||
/* Basic config init, set auth-type, pretty, etc ret 0 means disabled */
|
||||
if ((ret = restconf_config_init(h, xrestconf)) < 0)
|
||||
goto done;
|
||||
/* ret == 1 means this config is OK */
|
||||
|
|
@ -1050,7 +1053,7 @@ restconf_clixon_init(clicon_handle h,
|
|||
/* If no local config, or it is disabled, try to query backend of config.
|
||||
*/
|
||||
else {
|
||||
clicon_debug(1, "%s reading from backend datastore config", __FUNCTION__);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s reading from backend datastore config", __FUNCTION__);
|
||||
if ((ret = restconf_clixon_backend(h, xrestconfp)) < 0)
|
||||
goto done;
|
||||
if (ret == 0)
|
||||
|
|
@ -1075,7 +1078,7 @@ restconf_sig_term(int arg)
|
|||
{
|
||||
static int i=0;
|
||||
|
||||
clicon_log(LOG_NOTICE, "%s: %s: pid: %u Signal %d",
|
||||
clicon_log(LOG_NOTICE, "%s: %s: pid: %u Signal %d",
|
||||
__PROGRAM__, __FUNCTION__, getpid(), arg);
|
||||
if (i++ > 0) /* Allow one sigterm before proper exit */
|
||||
exit(-1);
|
||||
|
|
@ -1083,13 +1086,13 @@ restconf_sig_term(int arg)
|
|||
* is entered, it will terminate.
|
||||
* However there may be a case of sockets closing rather abruptly for clients
|
||||
*/
|
||||
clixon_exit_set(1);
|
||||
clixon_exit_set(1);
|
||||
}
|
||||
|
||||
/*! Usage help routine
|
||||
*
|
||||
* @param[in] argv0 command line
|
||||
* @param[in] h Clicon handle
|
||||
* @param[in] h Clixon handle
|
||||
*/
|
||||
static void
|
||||
usage(clicon_handle h,
|
||||
|
|
@ -1138,7 +1141,7 @@ main(int argc,
|
|||
|
||||
/* In the startup, logs to stderr & debug flag set later */
|
||||
clicon_log_init(__PROGRAM__, LOG_INFO, logdst);
|
||||
|
||||
|
||||
/* Create handle */
|
||||
if ((h = restconf_handle_init()) == NULL)
|
||||
goto done;
|
||||
|
|
@ -1175,7 +1178,7 @@ main(int argc,
|
|||
/*
|
||||
* Logs, error and debug to stderr or syslog, set debug level
|
||||
*/
|
||||
clicon_log_init(__PROGRAM__, dbg?LOG_DEBUG:LOG_INFO, logdst);
|
||||
clicon_log_init(__PROGRAM__, dbg?LOG_DEBUG:LOG_INFO, logdst);
|
||||
|
||||
/*
|
||||
* Register error category and error/log callbacks for openssl special error handling
|
||||
|
|
@ -1195,7 +1198,7 @@ main(int argc,
|
|||
) < 0)
|
||||
goto done;
|
||||
#endif
|
||||
clicon_debug_init(dbg, NULL);
|
||||
clixon_debug_init(dbg, NULL);
|
||||
clicon_log(LOG_NOTICE, "%s native %u Started", __PROGRAM__, getpid());
|
||||
if (set_signal(SIGTERM, restconf_sig_term, NULL) < 0){
|
||||
clicon_err(OE_DAEMON, errno, "Setting signal");
|
||||
|
|
@ -1214,7 +1217,6 @@ main(int argc,
|
|||
if (clicon_options_main(h) < 0)
|
||||
goto done;
|
||||
// stream_path = clicon_option_str(h, "CLICON_STREAM_PATH");
|
||||
|
||||
/* Now rest of options, some overwrite option file */
|
||||
optind = 1;
|
||||
opterr = 0;
|
||||
|
|
@ -1280,7 +1282,7 @@ main(int argc,
|
|||
|
||||
/* Init restconf auth-type */
|
||||
restconf_auth_type_set(h, CLIXON_AUTH_NONE);
|
||||
|
||||
|
||||
/* Explicit dump of config (also debug dump below). */
|
||||
if (config_dump){
|
||||
if (clicon_option_dump1(h, stdout, config_dump_format, 1) < 0)
|
||||
|
|
@ -1297,7 +1299,7 @@ main(int argc,
|
|||
if (clixon_plugin_start_all(h) < 0)
|
||||
goto done;
|
||||
|
||||
/* Clixon inits / configs */
|
||||
/* Clixon inits / configs */
|
||||
if ((ret = restconf_clixon_init(h, inline_config, &xrestconf)) < 0)
|
||||
goto done;
|
||||
if (ret == 0){ /* restconf disabled */
|
||||
|
|
@ -1305,7 +1307,7 @@ main(int argc,
|
|||
retval = 0;
|
||||
goto done;
|
||||
}
|
||||
/* Create and stroe global openssl handle */
|
||||
/* Create and stroe global openssl handle */
|
||||
if ((rn = malloc(sizeof *rn)) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "malloc");
|
||||
goto done;
|
||||
|
|
@ -1313,7 +1315,7 @@ main(int argc,
|
|||
memset(rn, 0, sizeof *rn);
|
||||
if (restconf_native_handle_set(h, rn) < 0)
|
||||
goto done;
|
||||
/* Openssl inits */
|
||||
/* Openssl inits */
|
||||
if (restconf_openssl_init(h, dbg, xrestconf) < 0)
|
||||
goto done;
|
||||
/* Drop privileges if started as root to CLICON_RESTCONF_USER
|
||||
|
|
@ -1327,13 +1329,13 @@ main(int argc,
|
|||
*/
|
||||
clicon_data_set(h, "session-transport", "cl:restconf");
|
||||
|
||||
/* Main event loop */
|
||||
/* Main event loop */
|
||||
if (clixon_event_loop(h) < 0)
|
||||
goto done;
|
||||
ok:
|
||||
retval = 0;
|
||||
done:
|
||||
clicon_debug(1, "restconf_main_openssl done");
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "restconf_main_openssl done");
|
||||
if (xrestconf)
|
||||
xml_free(xrestconf);
|
||||
restconf_native_terminate(h);
|
||||
|
|
|
|||
|
|
@ -78,10 +78,12 @@
|
|||
#include "restconf_methods.h"
|
||||
|
||||
/*! REST OPTIONS method
|
||||
*
|
||||
* According to restconf
|
||||
* @param[in] h Clixon handle
|
||||
* @param[in] req Generic Www handle
|
||||
*
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
* @code
|
||||
* curl -G http://localhost/restconf/data/interfaces/interface=eth0
|
||||
* @endcode
|
||||
|
|
@ -96,7 +98,7 @@ api_data_options(clicon_handle h,
|
|||
{
|
||||
int retval = -1;
|
||||
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
|
||||
if (restconf_reply_header(req, "Allow", "OPTIONS,HEAD,GET,POST,PUT,PATCH,DELETE") < 0)
|
||||
goto done;
|
||||
if (restconf_reply_header(req, "Accept-Patch", "application/yang-data+xml,application/yang-data+json") < 0)
|
||||
|
|
@ -117,7 +119,7 @@ api_data_options(clicon_handle h,
|
|||
* @param[in] x1 First XML tree (eg data)
|
||||
* @param[in] x2 Second XML tree (eg api-path)
|
||||
* @retval 0 Yes, keys match
|
||||
* @retval -1 No, keys do not match
|
||||
* @retval -1 No, keys do not match
|
||||
* If the target resource represents a YANG leaf-list, then the PUT
|
||||
* method MUST NOT change the value of the leaf-list instance.
|
||||
*
|
||||
|
|
@ -140,14 +142,14 @@ match_list_keys(yang_stmt *y,
|
|||
char *key1;
|
||||
char *key2;
|
||||
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
|
||||
switch (yang_keyword_get(y)){
|
||||
case Y_LIST:
|
||||
if ((cvk = yang_cvec_get(y)) == NULL) /* Use Y_LIST cache, see ys_populate_list() */
|
||||
break;
|
||||
cvi = NULL;
|
||||
while ((cvi = cvec_each(cvk, cvi)) != NULL) {
|
||||
keyname = cv_string_get(cvi);
|
||||
keyname = cv_string_get(cvi);
|
||||
if ((xkey2 = xml_find(x2, keyname)) == NULL)
|
||||
goto done; /* No key in api-path */
|
||||
if ((key2 = xml_body(xkey2)) == NULL)
|
||||
|
|
@ -174,11 +176,12 @@ match_list_keys(yang_stmt *y,
|
|||
ok:
|
||||
retval = 0;
|
||||
done:
|
||||
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s retval:%d", __FUNCTION__, retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Common PUT plain PATCH method
|
||||
*
|
||||
* Code checks if object exists.
|
||||
* PUT: If it does not, set op to create, otherwise replace
|
||||
* PATCH: If it does not, fail, otherwise replace/merge
|
||||
|
|
@ -187,13 +190,15 @@ match_list_keys(yang_stmt *y,
|
|||
* @param[in] pretty Pretty-print
|
||||
* @param[in] media_in Restconf input media
|
||||
* @param[in] media_out Restconf output media
|
||||
*/
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
*/
|
||||
int
|
||||
api_data_write(clicon_handle h,
|
||||
void *req,
|
||||
char *api_path0,
|
||||
void *req,
|
||||
char *api_path0,
|
||||
int pi,
|
||||
cvec *qvec,
|
||||
cvec *qvec,
|
||||
char *data,
|
||||
int pretty,
|
||||
restconf_media media_in,
|
||||
|
|
@ -230,9 +235,9 @@ api_data_write(clicon_handle h,
|
|||
yang_bind yb;
|
||||
char *xpath = NULL;
|
||||
char *attr;
|
||||
|
||||
clicon_debug(1, "%s api_path:\"%s\"", __FUNCTION__, api_path0);
|
||||
clicon_debug(1, "%s data:\"%s\"", __FUNCTION__, data);
|
||||
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s api_path:\"%s\"", __FUNCTION__, api_path0);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s data:\"%s\"", __FUNCTION__, data);
|
||||
if ((yspec = clicon_dbspec_yang(h)) == NULL){
|
||||
clicon_err(OE_FATAL, 0, "No DB_SPEC");
|
||||
goto done;
|
||||
|
|
@ -290,7 +295,7 @@ api_data_write(clicon_handle h,
|
|||
if (api_path){ /* XXX mv to copy? */
|
||||
cxobj *xfrom;
|
||||
cxobj *xac;
|
||||
|
||||
|
||||
if (api_path && (strcmp(api_path, "/") != 0))
|
||||
xfrom = xml_parent(xbot);
|
||||
else
|
||||
|
|
@ -393,7 +398,7 @@ api_data_write(clicon_handle h,
|
|||
goto done;
|
||||
/* Top-of tree, no api-path
|
||||
* Replace xparent with x, ie bottom of api-path with data
|
||||
*/
|
||||
*/
|
||||
dname = xml_name(xdata);
|
||||
if (api_path==NULL) {
|
||||
if (strcmp(dname, NETCONF_OUTPUT_DATA)!=0){
|
||||
|
|
@ -422,9 +427,9 @@ api_data_write(clicon_handle h,
|
|||
/* There is an api-path that defines an element in the datastore tree.
|
||||
* Not top-of-tree.
|
||||
*/
|
||||
clicon_debug(1, "%s Comparing bottom-of api-path (%s) with top-of-data (%s)",__FUNCTION__, xml_name(xbot), dname);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s Comparing bottom-of api-path (%s) with top-of-data (%s)",__FUNCTION__, xml_name(xbot), dname);
|
||||
|
||||
/* Check same symbol in api-path as data */
|
||||
/* Check same symbol in api-path as data */
|
||||
if (strcmp(dname, xml_name(xbot))){
|
||||
if (netconf_bad_element_xml(&xerr, "application", dname,
|
||||
"Data element does not match api-path") < 0)
|
||||
|
|
@ -439,7 +444,7 @@ api_data_write(clicon_handle h,
|
|||
* or the object is the key element:
|
||||
* eg xpath:obj=a/key data:<key>b</key>
|
||||
* That is why the conditional is somewhat hairy
|
||||
*/
|
||||
*/
|
||||
xparent = xml_parent(xbot);
|
||||
if (ybot){
|
||||
/* Ensure list keys match between uri and data. That is:
|
||||
|
|
@ -479,7 +484,7 @@ api_data_write(clicon_handle h,
|
|||
}
|
||||
if (xtop != xbot) /* Should always be true */
|
||||
xml_purge(xbot);
|
||||
if (xml_addsub(xparent, xdata) < 0)
|
||||
if (xml_addsub(xparent, xdata) < 0)
|
||||
goto done;
|
||||
/* If restconf insert/point attributes are present, translate to netconf */
|
||||
if (restconf_insert_attributes(xdata, qvec) < 0)
|
||||
|
|
@ -487,11 +492,11 @@ api_data_write(clicon_handle h,
|
|||
/* 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, &namespace) < 0){
|
||||
clicon_debug(1, "%s G done", __FUNCTION__);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s G done", __FUNCTION__);
|
||||
goto done;
|
||||
}
|
||||
if (namespace == NULL){
|
||||
clicon_debug_xml(1, xparent, "%s xparent:", __FUNCTION__);
|
||||
clixon_debug_xml(1, xparent, "%s xparent:", __FUNCTION__);
|
||||
/* XXX */
|
||||
}
|
||||
/* Set xmlns="" default namespace attribute (if diff from default) */
|
||||
|
|
@ -535,12 +540,12 @@ api_data_write(clicon_handle h,
|
|||
if (clixon_xml2cbuf(cbx, xtop, 0, 0, NULL, -1, 0) < 0)
|
||||
goto done;
|
||||
cprintf(cbx, "</edit-config></rpc>");
|
||||
clicon_debug(1, "%s xml: %s api_path:%s",__FUNCTION__, cbuf_get(cbx), api_path);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s xml: %s api_path:%s",__FUNCTION__, cbuf_get(cbx), api_path);
|
||||
if (clicon_rpc_netconf(h, cbuf_get(cbx), &xret, NULL) < 0)
|
||||
goto done;
|
||||
if ((xe = xpath_first(xret, NULL, "//rpc-error")) != NULL){
|
||||
if (api_return_err(h, req, xe, pretty, media_out, 0) < 0)
|
||||
goto done;
|
||||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
if ((xe = xpath_first(xret, NULL, "//ok")) != NULL &&
|
||||
|
|
@ -551,11 +556,11 @@ api_data_write(clicon_handle h,
|
|||
}
|
||||
else
|
||||
if (restconf_reply_send(req, 204, NULL, 0) < 0) /* No content */
|
||||
goto done;
|
||||
goto done;
|
||||
ok:
|
||||
retval = 0;
|
||||
done:
|
||||
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s retval:%d", __FUNCTION__, retval);
|
||||
if (xpath)
|
||||
free(xpath);
|
||||
if (nsc)
|
||||
|
|
@ -578,6 +583,7 @@ api_data_write(clicon_handle h,
|
|||
} /* api_data_write */
|
||||
|
||||
/*! Generic REST PUT method
|
||||
*
|
||||
* @param[in] h Clixon handle
|
||||
* @param[in] req Generic Www handle
|
||||
* @param[in] api_path According to restconf (Sec 3.5.3.1 in rfc8040)
|
||||
|
|
@ -587,6 +593,8 @@ api_data_write(clicon_handle h,
|
|||
* @param[in] pretty Set to 1 for pretty-printed xml/json output
|
||||
* @param[in] media_out Output media
|
||||
* @param[in] ds 0 if "data" resource, 1 if rfc8527 "ds" resource
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
* @note restconf PUT is mapped to edit-config replace.
|
||||
* @see RFC8040 Sec 4.5 PUT
|
||||
* @see api_data_post
|
||||
|
|
@ -613,10 +621,10 @@ api_data_write(clicon_handle h,
|
|||
*/
|
||||
int
|
||||
api_data_put(clicon_handle h,
|
||||
void *req,
|
||||
char *api_path0,
|
||||
void *req,
|
||||
char *api_path0,
|
||||
int pi,
|
||||
cvec *qvec,
|
||||
cvec *qvec,
|
||||
char *data,
|
||||
int pretty,
|
||||
restconf_media media_out,
|
||||
|
|
@ -627,9 +635,10 @@ api_data_put(clicon_handle h,
|
|||
media_in = restconf_content_type(h);
|
||||
return api_data_write(h, req, api_path0, pi, qvec, data, pretty,
|
||||
media_in, media_out, 0, ds);
|
||||
}
|
||||
}
|
||||
|
||||
/*! Generic REST PATCH method for plain patch
|
||||
*
|
||||
* @param[in] h Clixon handle
|
||||
* @param[in] req Generic Www handle
|
||||
* @param[in] api_path According to restconf (Sec 3.5.3.1 in rfc8040)
|
||||
|
|
@ -639,6 +648,8 @@ api_data_put(clicon_handle h,
|
|||
* @param[in] pretty Set to 1 for pretty-printed xml/json output
|
||||
* @param[in] media_out Output media
|
||||
* @param[in] ds 0 if "data" resource, 1 if rfc8527 "ds" resource
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
* Netconf: <edit-config> (nc:operation="merge")
|
||||
* See RFC8040 Sec 4.6.1
|
||||
* Plain patch can be used to create or update, but not delete, a child
|
||||
|
|
@ -648,10 +659,10 @@ api_data_put(clicon_handle h,
|
|||
*/
|
||||
int
|
||||
api_data_patch(clicon_handle h,
|
||||
void *req,
|
||||
char *api_path0,
|
||||
void *req,
|
||||
char *api_path0,
|
||||
int pi,
|
||||
cvec *qvec,
|
||||
cvec *qvec,
|
||||
char *data,
|
||||
int pretty,
|
||||
restconf_media media_out,
|
||||
|
|
@ -682,9 +693,10 @@ api_data_patch(clicon_handle h,
|
|||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/*! Generic REST DELETE method translated to edit-config
|
||||
*
|
||||
* @param[in] h Clixon handle
|
||||
* @param[in] req Generic Www handle
|
||||
* @param[in] api_path According to restconf (Sec 3.5.3.1 in rfc8040)
|
||||
|
|
@ -692,6 +704,8 @@ api_data_patch(clicon_handle h,
|
|||
* @param[in] pretty Set to 1 for pretty-printed xml/json output
|
||||
* @param[in] media_out Output media
|
||||
* @param[in] ds 0 if "data" resource, 1 if rfc8527 "ds" resource
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
* See RFC 8040 Sec 4.7
|
||||
* Example:
|
||||
* curl -X DELETE http://127.0.0.1/restconf/data/interfaces/interface=eth0
|
||||
|
|
@ -699,7 +713,7 @@ api_data_patch(clicon_handle h,
|
|||
*/
|
||||
int
|
||||
api_data_delete(clicon_handle h,
|
||||
void *req,
|
||||
void *req,
|
||||
char *api_path,
|
||||
int pi,
|
||||
int pretty,
|
||||
|
|
@ -723,7 +737,7 @@ api_data_delete(clicon_handle h,
|
|||
int ret;
|
||||
cxobj *xe; /* xml error, no free */
|
||||
|
||||
clicon_debug(1, "%s api_path:%s", __FUNCTION__, api_path);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s api_path:%s", __FUNCTION__, api_path);
|
||||
if ((yspec = clicon_dbspec_yang(h)) == NULL){
|
||||
clicon_err(OE_FATAL, 0, "No DB_SPEC");
|
||||
goto done;
|
||||
|
|
@ -793,12 +807,12 @@ api_data_delete(clicon_handle h,
|
|||
goto ok;
|
||||
}
|
||||
if (restconf_reply_send(req, 204, NULL, 0) < 0)
|
||||
goto done;
|
||||
goto done;
|
||||
ok:
|
||||
retval = 0;
|
||||
done:
|
||||
if (cbx)
|
||||
cbuf_free(cbx);
|
||||
cbuf_free(cbx);
|
||||
if (xret)
|
||||
xml_free(xret);
|
||||
if (xretcom)
|
||||
|
|
@ -807,7 +821,7 @@ api_data_delete(clicon_handle h,
|
|||
xml_free(xretdis);
|
||||
if (xtop)
|
||||
xml_free(xtop);
|
||||
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s retval:%d", __FUNCTION__, retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -35,7 +35,6 @@
|
|||
* Restconf method implementation
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _RESTCONF_METHODS_H_
|
||||
#define _RESTCONF_METHODS_H_
|
||||
|
||||
|
|
@ -43,19 +42,19 @@
|
|||
* Prototypes
|
||||
*/
|
||||
int api_data_options(clicon_handle h, void *req);
|
||||
int api_data_write(clicon_handle h, void *req, char *api_path0,
|
||||
int api_data_write(clicon_handle h, void *req, char *api_path0,
|
||||
int pi,
|
||||
cvec *qvec, char *data,
|
||||
int pretty, restconf_media media_in, restconf_media media_out,
|
||||
int plain_patch, ietf_ds_t ds);
|
||||
|
||||
int api_data_put(clicon_handle h, void *req, char *api_path,
|
||||
int pi,
|
||||
int api_data_put(clicon_handle h, void *req, char *api_path,
|
||||
int pi,
|
||||
cvec *qvec, char *data,
|
||||
int pretty, restconf_media media_out, ietf_ds_t ds);
|
||||
|
||||
int api_data_patch(clicon_handle h, void *req, char *api_path,
|
||||
int pi,
|
||||
int api_data_patch(clicon_handle h, void *req, char *api_path,
|
||||
int pi,
|
||||
cvec *qvec, char *data, int pretty,
|
||||
restconf_media media_out, ietf_ds_t ds);
|
||||
|
||||
|
|
|
|||
|
|
@ -75,7 +75,9 @@ static int api_data_pagination(clicon_handle h, void *req, char *api_path, int p
|
|||
* @param[in] qvec Vector of query string (QUERY_STRING)
|
||||
* @param[in] pretty Set to 1 for pretty-printed xml/json output
|
||||
* @param[in] media_out Output media
|
||||
* @param[in] head If 1 is HEAD, otherwise GET
|
||||
* @param[in] head If 1 is HEAD, otherwise GET
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
* @code
|
||||
* curl -X GET http://localhost/restconf/data/interfaces/interface=eth0
|
||||
* @endcode
|
||||
|
|
@ -97,7 +99,7 @@ static int api_data_pagination(clicon_handle h, void *req, char *api_path, int p
|
|||
static int
|
||||
api_data_get2(clicon_handle h,
|
||||
void *req,
|
||||
char *api_path,
|
||||
char *api_path,
|
||||
int pi,
|
||||
cvec *qvec,
|
||||
int pretty,
|
||||
|
|
@ -125,8 +127,8 @@ api_data_get2(clicon_handle h,
|
|||
yang_stmt *y = NULL;
|
||||
char *defaults = NULL;
|
||||
cvec *nscd = NULL;
|
||||
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
|
||||
if ((yspec = clicon_dbspec_yang(h)) == NULL){
|
||||
clicon_err(OE_FATAL, 0, "No DB_SPEC");
|
||||
goto done;
|
||||
|
|
@ -137,7 +139,7 @@ api_data_get2(clicon_handle h,
|
|||
if (api_path){
|
||||
if ((xtop = xml_new("top", NULL, CX_ELMNT)) == NULL)
|
||||
goto done;
|
||||
/* Translate api-path to xml, but to validate the api-path, note: strict=1
|
||||
/* Translate api-path to xml, but to validate the api-path, note: strict=1
|
||||
* xtop and xbot unnecessary for this function but needed by function
|
||||
*/
|
||||
if ((ret = api_path2xml(api_path, yspec, xtop, YC_DATANODE, 1, &xbot, &y, &xerr)) < 0)
|
||||
|
|
@ -166,7 +168,7 @@ api_data_get2(clicon_handle h,
|
|||
}
|
||||
/* Check for content attribute */
|
||||
if ((attr = cvec_find_str(qvec, "content")) != NULL){
|
||||
clicon_debug(1, "%s content=%s", __FUNCTION__, attr);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s content=%s", __FUNCTION__, attr);
|
||||
if ((int)(content = netconf_content_str2int(attr)) == -1){
|
||||
if (netconf_bad_attribute_xml(&xerr, "application",
|
||||
"content", "Unrecognized value of content attribute") < 0)
|
||||
|
|
@ -178,7 +180,7 @@ api_data_get2(clicon_handle h,
|
|||
}
|
||||
/* Check for depth attribute */
|
||||
if ((attr = cvec_find_str(qvec, "depth")) != NULL){
|
||||
clicon_debug(1, "%s depth=%s", __FUNCTION__, attr);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s depth=%s", __FUNCTION__, attr);
|
||||
if (strcmp(attr, "unbounded") != 0){
|
||||
char *reason = NULL;
|
||||
if ((ret = parse_int32(attr, &depth, &reason)) < 0){
|
||||
|
|
@ -196,11 +198,11 @@ api_data_get2(clicon_handle h,
|
|||
}
|
||||
}
|
||||
if ((attr = cvec_find_str(qvec, "with-defaults")) != NULL){
|
||||
clicon_debug(1, "%s with_defaults=%s", __FUNCTION__, attr);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s with_defaults=%s", __FUNCTION__, attr);
|
||||
defaults = attr;
|
||||
}
|
||||
|
||||
clicon_debug(1, "%s path:%s", __FUNCTION__, xpath);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s path:%s", __FUNCTION__, xpath);
|
||||
ret = clicon_rpc_get(h, xpath, nsc, content, depth, defaults, &xret);
|
||||
|
||||
if (ret < 0){
|
||||
|
|
@ -214,8 +216,8 @@ api_data_get2(clicon_handle h,
|
|||
* We need to cut that tree to only the object.
|
||||
*/
|
||||
#if 0 /* DEBUG */
|
||||
if (clicon_debug_get())
|
||||
clicon_debug_xml(1, xret, "%s xret:", __FUNCTION__);
|
||||
if (clixon_debug_get())
|
||||
clixon_debug_xml(CLIXON_DBG_DEFAULT, xret, "%s xret:", __FUNCTION__);
|
||||
#endif
|
||||
/* Check if error return */
|
||||
if ((xe = xpath_first(xret, NULL, "//rpc-error")) != NULL){
|
||||
|
|
@ -290,7 +292,7 @@ api_data_get2(clicon_handle h,
|
|||
break;
|
||||
}
|
||||
}
|
||||
clicon_debug(1, "%s cbuf:%s", __FUNCTION__, cbuf_get(cbx));
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s cbuf:%s", __FUNCTION__, cbuf_get(cbx));
|
||||
if (restconf_reply_header(req, "Content-Type", "%s", restconf_media_int2str(media_out)) < 0)
|
||||
goto done;
|
||||
if (restconf_reply_header(req, "Cache-Control", "no-cache") < 0)
|
||||
|
|
@ -301,7 +303,7 @@ api_data_get2(clicon_handle h,
|
|||
ok:
|
||||
retval = 0;
|
||||
done:
|
||||
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s retval:%d", __FUNCTION__, retval);
|
||||
if (xpath)
|
||||
free(xpath);
|
||||
if (nscd)
|
||||
|
|
@ -322,6 +324,7 @@ api_data_get2(clicon_handle h,
|
|||
}
|
||||
|
||||
/*! GET Collection
|
||||
*
|
||||
* According to restconf collection draft. Lists, work in progress
|
||||
* @param[in] h Clixon handle
|
||||
* @param[in] req Generic Www handle
|
||||
|
|
@ -330,7 +333,9 @@ api_data_get2(clicon_handle h,
|
|||
* @param[in] qvec Vector of query string (QUERY_STRING)
|
||||
* @param[in] pretty Set to 1 for pretty-printed xml/json output
|
||||
* @param[in] media_out Output media
|
||||
* @param[in] head If 1 is HEAD, otherwise GET
|
||||
* @param[in] head If 1 is HEAD, otherwise GET
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
* @code
|
||||
* curl -X GET http://localhost/restconf/data/interfaces
|
||||
* @endcode
|
||||
|
|
@ -342,7 +347,7 @@ api_data_get2(clicon_handle h,
|
|||
static int
|
||||
api_data_pagination(clicon_handle h,
|
||||
void *req,
|
||||
char *api_path,
|
||||
char *api_path,
|
||||
int pi,
|
||||
cvec *qvec,
|
||||
int pretty,
|
||||
|
|
@ -375,8 +380,8 @@ api_data_pagination(clicon_handle h,
|
|||
char *sort;
|
||||
char *where;
|
||||
char *ns;
|
||||
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
|
||||
if ((yspec = clicon_dbspec_yang(h)) == NULL){
|
||||
clicon_err(OE_FATAL, 0, "No DB_SPEC");
|
||||
goto done;
|
||||
|
|
@ -425,7 +430,7 @@ api_data_pagination(clicon_handle h,
|
|||
|
||||
/* Check for content attribute */
|
||||
if ((attr = cvec_find_str(qvec, "content")) != NULL){
|
||||
clicon_debug(1, "%s content=%s", __FUNCTION__, attr);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s content=%s", __FUNCTION__, attr);
|
||||
if ((int)(content = netconf_content_str2int(attr)) == -1){
|
||||
if (netconf_bad_attribute_xml(&xerr, "application",
|
||||
"content", "Unrecognized value of content attribute") < 0)
|
||||
|
|
@ -439,7 +444,7 @@ api_data_pagination(clicon_handle h,
|
|||
goto ok;
|
||||
}
|
||||
}
|
||||
clicon_debug(1, "%s path:%s", __FUNCTION__, xpath);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s path:%s", __FUNCTION__, xpath);
|
||||
if (content != CONTENT_CONFIG && content != CONTENT_NONCONFIG && content != CONTENT_ALL){
|
||||
clicon_err(OE_XML, EINVAL, "Invalid content attribute %d", content);
|
||||
goto done;
|
||||
|
|
@ -447,7 +452,7 @@ api_data_pagination(clicon_handle h,
|
|||
/* Clixon extensions and collection attributes */
|
||||
/* Check for depth attribute */
|
||||
if ((attr = cvec_find_str(qvec, "depth")) != NULL){
|
||||
clicon_debug(1, "%s depth=%s", __FUNCTION__, attr);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s depth=%s", __FUNCTION__, attr);
|
||||
if (strcmp(attr, "unbounded") != 0){
|
||||
char *reason = NULL;
|
||||
if ((ret = parse_int32(attr, &depth, &reason)) < 0){
|
||||
|
|
@ -486,7 +491,7 @@ api_data_pagination(clicon_handle h,
|
|||
sort = cvec_find_str(qvec, "sort-by");
|
||||
where = cvec_find_str(qvec, "where");
|
||||
if (clicon_rpc_get_pageable_list(h, "running", xpath, nsc, content,
|
||||
depth, NULL, offset, limit, direction, sort, where,
|
||||
depth, NULL, offset, limit, direction, sort, where,
|
||||
&xret) < 0){
|
||||
if (netconf_operation_failed_xml(&xerr, "protocol", clicon_err_reason) < 0)
|
||||
goto done;
|
||||
|
|
@ -502,7 +507,7 @@ api_data_pagination(clicon_handle h,
|
|||
* We need to cut that tree to only the object.
|
||||
*/
|
||||
#if 0 /* DEBUG */
|
||||
clicon_debug_xml(1, xret, "%s xret:", __FUNCTION__);
|
||||
clixon_debug_xml(CLIXON_DBG_DEFAULT, xret, "%s xret:", __FUNCTION__);
|
||||
#endif
|
||||
/* Check if error return */
|
||||
if ((xe = xpath_first(xret, NULL, "//rpc-error")) != NULL){
|
||||
|
|
@ -538,7 +543,7 @@ api_data_pagination(clicon_handle h,
|
|||
}
|
||||
if (xml_rm(xp) < 0)
|
||||
goto done;
|
||||
if (xml_insert(xpr, xp, INS_LAST, NULL, NULL) < 0)
|
||||
if (xml_insert(xpr, xp, INS_LAST, NULL, NULL) < 0)
|
||||
goto done;
|
||||
}
|
||||
if (clixon_xml2cbuf(cbx, xpr, 0, pretty, NULL, -1, 0) < 0) /* Dont print top object? */
|
||||
|
|
@ -551,7 +556,7 @@ api_data_pagination(clicon_handle h,
|
|||
default:
|
||||
break;
|
||||
}
|
||||
clicon_debug(1, "%s cbuf:%s", __FUNCTION__, cbuf_get(cbx));
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s cbuf:%s", __FUNCTION__, cbuf_get(cbx));
|
||||
if (restconf_reply_header(req, "Content-Type", "%s", restconf_media_int2str(media_out)) < 0)
|
||||
goto done;
|
||||
if (restconf_reply_header(req, "Cache-Control", "no-cache") < 0)
|
||||
|
|
@ -562,7 +567,7 @@ api_data_pagination(clicon_handle h,
|
|||
ok:
|
||||
retval = 0;
|
||||
done:
|
||||
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s retval:%d", __FUNCTION__, retval);
|
||||
if (cbrpc)
|
||||
cbuf_free(cbrpc);
|
||||
if (xpath)
|
||||
|
|
@ -585,6 +590,11 @@ api_data_pagination(clicon_handle h,
|
|||
}
|
||||
|
||||
/*! REST HEAD method
|
||||
*
|
||||
* The HEAD method is sent by the client to retrieve just the header fields
|
||||
* that would be returned for the comparable GET method, without the
|
||||
* response message-body.
|
||||
* Relation to netconf: none
|
||||
* @param[in] h Clixon handle
|
||||
* @param[in] req Generic Www handle
|
||||
* @param[in] api_path According to restconf (Sec 3.5.3.1 in rfc8040)
|
||||
|
|
@ -593,11 +603,8 @@ api_data_pagination(clicon_handle h,
|
|||
* @param[in] pretty Set to 1 for pretty-printed xml/json output
|
||||
* @param[in] media_out Output media
|
||||
* @param[in] ds 0 if "data" resource, 1 if rfc8527 "ds" resource
|
||||
*
|
||||
* The HEAD method is sent by the client to retrieve just the header fields
|
||||
* that would be returned for the comparable GET method, without the
|
||||
* response message-body.
|
||||
* Relation to netconf: none
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
*/
|
||||
int
|
||||
api_data_head(clicon_handle h,
|
||||
|
|
@ -613,6 +620,7 @@ api_data_head(clicon_handle h,
|
|||
}
|
||||
|
||||
/*! REST GET method
|
||||
*
|
||||
* According to restconf
|
||||
* @param[in] h Clixon handle
|
||||
* @param[in] req Generic Www handle
|
||||
|
|
@ -623,6 +631,8 @@ api_data_head(clicon_handle h,
|
|||
* @param[in] pretty Set to 1 for pretty-printed xml/json output
|
||||
* @param[in] media_out Output media
|
||||
* @param[in] ds RFC8527 datastore
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
* @code
|
||||
* curl -G http://localhost/restconf/data/interfaces/interface=eth0
|
||||
* @endcode
|
||||
|
|
@ -640,7 +650,7 @@ api_data_head(clicon_handle h,
|
|||
int
|
||||
api_data_get(clicon_handle h,
|
||||
void *req,
|
||||
char *api_path,
|
||||
char *api_path,
|
||||
int pi,
|
||||
cvec *qvec,
|
||||
int pretty,
|
||||
|
|
@ -648,7 +658,7 @@ api_data_get(clicon_handle h,
|
|||
ietf_ds_t ds)
|
||||
{
|
||||
int retval = -1;
|
||||
|
||||
|
||||
switch (media_out){
|
||||
case YANG_DATA_XML:
|
||||
case YANG_DATA_JSON: /* ad-hoc algorithm in get to determine if a paginated request */
|
||||
|
|
@ -667,6 +677,7 @@ api_data_get(clicon_handle h,
|
|||
}
|
||||
|
||||
/*! GET restconf/operations resource
|
||||
*
|
||||
* @param[in] h Clixon handle
|
||||
* @param[in] req Generic Www handle
|
||||
* @param[in] path According to restconf (Sec 3.5.1.1 in [draft])
|
||||
|
|
@ -675,11 +686,12 @@ api_data_get(clicon_handle h,
|
|||
* @param[in] data Stream input data
|
||||
* @param[in] pretty Set to 1 for pretty-printed xml/json output
|
||||
* @param[in] media_out Output media
|
||||
*
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
* @code
|
||||
* curl -G http://localhost/restconf/operations
|
||||
* @endcode
|
||||
* RFC8040 Sec 3.3.2:
|
||||
* @see RFC8040 Sec 3.3.2:
|
||||
* This optional resource is a container that provides access to the
|
||||
* data-model-specific RPC operations supported by the server. The
|
||||
* server MAY omit this resource if no data-model-specific RPC
|
||||
|
|
@ -693,9 +705,9 @@ api_data_get(clicon_handle h,
|
|||
int
|
||||
api_operations_get(clicon_handle h,
|
||||
void *req,
|
||||
char *path,
|
||||
char *path,
|
||||
int pi,
|
||||
cvec *qvec,
|
||||
cvec *qvec,
|
||||
char *data,
|
||||
int pretty,
|
||||
restconf_media media_out)
|
||||
|
|
@ -708,8 +720,8 @@ api_operations_get(clicon_handle h,
|
|||
cbuf *cbx = NULL;
|
||||
cxobj *xt = NULL;
|
||||
int i;
|
||||
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
|
||||
yspec = clicon_dbspec_yang(h);
|
||||
if ((cbx = cbuf_new()) == NULL)
|
||||
goto done;
|
||||
|
|
@ -730,7 +742,7 @@ api_operations_get(clicon_handle h,
|
|||
i = 0;
|
||||
while ((ymod = yn_each(yspec, ymod)) != NULL) {
|
||||
namespace = yang_find_mynamespace(ymod);
|
||||
yc = NULL;
|
||||
yc = NULL;
|
||||
while ((yc = yn_each(ymod, yc)) != NULL) {
|
||||
if (yang_keyword_get(yc) != Y_RPC)
|
||||
continue;
|
||||
|
|
@ -777,7 +789,7 @@ api_operations_get(clicon_handle h,
|
|||
// ok:
|
||||
retval = 0;
|
||||
done:
|
||||
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s retval:%d", __FUNCTION__, retval);
|
||||
if (cbx)
|
||||
cbuf_free(cbx);
|
||||
if (xt)
|
||||
|
|
|
|||
|
|
@ -41,11 +41,11 @@
|
|||
/*
|
||||
* Prototypes
|
||||
*/
|
||||
int api_data_head(clicon_handle h, void *req, char *api_path, int pi,
|
||||
int api_data_head(clicon_handle h, void *req, char *api_path, int pi,
|
||||
cvec *qvec, int pretty, restconf_media media_out, ietf_ds_t ds);
|
||||
int api_data_get(clicon_handle h, void *req, char *api_path, int pi,
|
||||
int api_data_get(clicon_handle h, void *req, char *api_path, int pi,
|
||||
cvec *qvec, int pretty, restconf_media media_out, ietf_ds_t ds);
|
||||
int api_operations_get(clicon_handle h, void *req,
|
||||
int api_operations_get(clicon_handle h, void *req,
|
||||
char *api_path, int pi, cvec *qvec, char *data,
|
||||
int pretty, restconf_media media_out);
|
||||
|
||||
|
|
|
|||
|
|
@ -100,11 +100,12 @@ yang_patch_op2int(char *op)
|
|||
}
|
||||
|
||||
/*! Add square brackets after the surrounding curly brackets in JSON
|
||||
*
|
||||
* Needed, in order to modify the result of clixon_json2cbuf() to be valid input
|
||||
* to api_data_post() and api_data_write()
|
||||
* @param[in] x_simple_patch a cxobj to pass to clixon_json2cbuf()
|
||||
* @retva cbuf With the modified json
|
||||
* @retva NULL Error
|
||||
* @retval cbuf With the modified json
|
||||
* @retval NULL Error
|
||||
*/
|
||||
static cbuf*
|
||||
yang_patch_xml2json_modified_cbuf(cxobj *x_simple_patch)
|
||||
|
|
@ -150,7 +151,7 @@ yang_patch_xml2json_modified_cbuf(cxobj *x_simple_patch)
|
|||
return json_simple_patch;
|
||||
}
|
||||
|
||||
/*!yang_patch_strip_after_last_slash
|
||||
/*! yang_patch_strip_after_last_slash
|
||||
*
|
||||
* Strip /... from end of val
|
||||
* so that e.g. "/interface=eth2" becomes "/"
|
||||
|
|
@ -187,6 +188,7 @@ yang_patch_strip_after_last_slash(char* val)
|
|||
}
|
||||
|
||||
/*! YANG PATCH replace method
|
||||
*
|
||||
* @param[in] h Clixon handle
|
||||
* @param[in] req Generic Www handle
|
||||
* @param[in] pi Offset, where to start api-path
|
||||
|
|
@ -199,6 +201,8 @@ yang_patch_strip_after_last_slash(char* val)
|
|||
* @param[in] value_vec_len number of elements in the "value" array of an edit in YANG patch
|
||||
* @param[in] value_vec pointer to the "value" array of an edit in YANG patch
|
||||
* @param[in] x_simple_patch pointer to XML containing module name, e.g. <ietf-interfaces:interface/>
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
*/
|
||||
static int
|
||||
yang_patch_do_replace(clicon_handle h,
|
||||
|
|
@ -287,6 +291,7 @@ yang_patch_do_replace(clicon_handle h,
|
|||
}
|
||||
|
||||
/*! YANG PATCH create method
|
||||
*
|
||||
* @param[in] h Clixon handle
|
||||
* @param[in] req Generic Www handle
|
||||
* @param[in] pi Offset, where to start api-path
|
||||
|
|
@ -298,6 +303,8 @@ yang_patch_do_replace(clicon_handle h,
|
|||
* @param[in] value_vec_len number of elements in the "value" array of an edit in YANG patch
|
||||
* @param[in] value_vec pointer to the "value" array of an edit in YANG patch
|
||||
* @param[in] x_simple_patch pointer to XML containing module name, e.g. <ietf-interfaces:interface/>
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
*/
|
||||
static int
|
||||
yang_patch_do_create(clicon_handle h,
|
||||
|
|
@ -343,12 +350,13 @@ yang_patch_do_create(clicon_handle h,
|
|||
}
|
||||
|
||||
/*! YANG PATCH insert method
|
||||
* @param[in] h Clixon handle
|
||||
* @param[in] req Generic Www handle
|
||||
* @param[in] pi Offset, where to start api-path
|
||||
* @param[in] pretty Set to 1 for pretty-printed xml/json output
|
||||
* @param[in] media_out Output media
|
||||
* @param[in] ds 0 if "data" resource, 1 if rfc8527 "ds" resource
|
||||
*
|
||||
* @param[in] h Clixon handle
|
||||
* @param[in] req Generic Www handle
|
||||
* @param[in] pi Offset, where to start api-path
|
||||
* @param[in] pretty Set to 1 for pretty-printed xml/json output
|
||||
* @param[in] media_out Output media
|
||||
* @param[in] ds 0 if "data" resource, 1 if rfc8527 "ds" resource
|
||||
* @param[in] simple_patch_request_uri URI for patch request, e.g. "/restconf/data/ietf-interfaces:interfaces"
|
||||
* @param[in] value_vec_len number of elements in the "value" array of an edit in YANG patch
|
||||
* @param[in] value_vec pointer to the "value" array of an edit in YANG patch
|
||||
|
|
@ -356,6 +364,8 @@ yang_patch_do_create(clicon_handle h,
|
|||
* @param[in] where_val value in "where" field of edit in YANG patch
|
||||
* @param[in] api_path full API path, e.g. "/restconf/data/example-jukebox:jukebox/playlist=Foo-One"
|
||||
* @param[in] point_val value in "point" field of edit in YANG patch
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
*/
|
||||
static int
|
||||
yang_patch_do_insert(clicon_handle h,
|
||||
|
|
@ -431,19 +441,22 @@ yang_patch_do_insert(clicon_handle h,
|
|||
}
|
||||
|
||||
/*! YANG PATCH merge method
|
||||
* @param[in] h Clixon handle
|
||||
* @param[in] req Generic Www handle
|
||||
* @param[in] pi Offset, where to start api-path
|
||||
* @param[in] qvec Vector of query string (QUERY_STRING)
|
||||
* @param[in] pretty Set to 1 for pretty-printed xml/json output
|
||||
* @param[in] media_out Output media
|
||||
* @param[in] ds 0 if "data" resource, 1 if rfc8527 "ds" resource
|
||||
*
|
||||
* @param[in] h Clixon handle
|
||||
* @param[in] req Generic Www handle
|
||||
* @param[in] pi Offset, where to start api-path
|
||||
* @param[in] qvec Vector of query string (QUERY_STRING)
|
||||
* @param[in] pretty Set to 1 for pretty-printed xml/json output
|
||||
* @param[in] media_out Output media
|
||||
* @param[in] ds 0 if "data" resource, 1 if rfc8527 "ds" resource
|
||||
* @param[in] simple_patch_request_uri URI for patch request, e.g. "/restconf/data/ietf-interfaces:interfaces"
|
||||
* @param[in] value_vec_len number of elements in the "value" array of an edit in YANG patch
|
||||
* @param[in] value_vec pointer to the "value" array of an edit in YANG patch
|
||||
* @param[in] x_simple_patch pointer to XML containing module name, e.g. "<ietf-interfaces:interface/>"
|
||||
* @param[in] value_vec_len number of elements in the "value" array of an edit in YANG patch
|
||||
* @param[in] value_vec pointer to the "value" array of an edit in YANG patch
|
||||
* @param[in] x_simple_patch pointer to XML containing module name, e.g. "<ietf-interfaces:interface/>"
|
||||
* @param[in] where_val value in "where" field of edit in YANG patch
|
||||
* @param[in] key_xn XML with key tag and value, e.g. "<name>Foo-One</name>"
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
*/
|
||||
static int
|
||||
yang_patch_do_merge(clicon_handle h,
|
||||
|
|
@ -622,7 +635,7 @@ yang_patch_do_edit(clicon_handle h,
|
|||
yang_stmt *ybot = NULL;
|
||||
yang_stmt *ymod;
|
||||
|
||||
clicon_debug_xml(1, xn, "%s %d xn:", __FUNCTION__, __LINE__);
|
||||
clixon_debug_xml(1, xn, "%s %d xn:", __FUNCTION__, __LINE__);
|
||||
/* Create cbufs:s */
|
||||
if ((simple_patch_request_uri = cbuf_new()) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "cbuf_new");
|
||||
|
|
@ -655,7 +668,7 @@ yang_patch_do_edit(clicon_handle h,
|
|||
if (point_val == NULL || where_val == NULL){
|
||||
clicon_err(OE_YANG, 0, "point/where: expected element not found");
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Construct request URI
|
||||
cprintf(simple_patch_request_uri, "%s", uripath0);
|
||||
|
|
@ -704,7 +717,7 @@ yang_patch_do_edit(clicon_handle h,
|
|||
} else {
|
||||
// TODO - do not send error
|
||||
}
|
||||
api_data_delete(h, req, cbuf_get(simple_patch_request_uri), pi, pretty, YANG_DATA_JSON, ds);
|
||||
api_data_delete(h, req, cbuf_get(simple_patch_request_uri), pi, pretty, YANG_DATA_JSON, ds);
|
||||
}
|
||||
ok:
|
||||
retval = 0;
|
||||
|
|
@ -723,6 +736,7 @@ yang_patch_do_edit(clicon_handle h,
|
|||
}
|
||||
|
||||
/*! YANG PATCH method
|
||||
*
|
||||
* @param[in] h Clixon handle
|
||||
* @param[in] req Generic Www handle
|
||||
* @param[in] api_path0 According to restconf (Sec 3.5.3.1 in rfc8040)
|
||||
|
|
@ -755,7 +769,7 @@ api_data_yang_patch(clicon_handle h,
|
|||
{
|
||||
int retval = -1;
|
||||
int i;
|
||||
cxobj *xpatch = NULL;
|
||||
cxobj *xpatch = NULL;
|
||||
yang_stmt *yspec;
|
||||
char *api_path;
|
||||
cxobj *xerr = NULL; /* malloced must be freed */
|
||||
|
|
@ -764,7 +778,7 @@ api_data_yang_patch(clicon_handle h,
|
|||
size_t veclen;
|
||||
cxobj **vec = NULL;
|
||||
|
||||
clicon_debug(1, "%s api_path:\"%s\"", __FUNCTION__, api_path0);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s api_path:\"%s\"", __FUNCTION__, api_path0);
|
||||
if ((yspec = clicon_dbspec_yang(h)) == NULL){
|
||||
clicon_err(OE_FATAL, 0, "No DB_SPEC");
|
||||
goto done;
|
||||
|
|
@ -805,7 +819,7 @@ api_data_yang_patch(clicon_handle h,
|
|||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
/*
|
||||
/*
|
||||
* RFC 8072 2.1: The message-body MUST identify exactly one resource instance
|
||||
*/
|
||||
if (xml_child_nr_type(xpatch, CX_ELMNT) != 1){
|
||||
|
|
@ -819,7 +833,7 @@ api_data_yang_patch(clicon_handle h,
|
|||
if ((uripath0 = restconf_uripath(h)) == NULL)
|
||||
goto done;
|
||||
/* Find all edit operations and loop over them
|
||||
*/
|
||||
*/
|
||||
if (xpath_vec(xpatch, NULL, "yang-patch/edit", &vec, &veclen) < 0)
|
||||
goto done;
|
||||
for (i = 0; i < veclen; i++) {
|
||||
|
|
|
|||
|
|
@ -66,8 +66,11 @@
|
|||
#include "restconf_methods_post.h"
|
||||
|
||||
/*! Print location header from
|
||||
*
|
||||
* @param[in] req Generic Www handle
|
||||
* @param[in] xobj If set (eg POST) add to api-path
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
* $https “on” if connection operates in SSL mode, or an empty string otherwise
|
||||
* @note ports are ignored
|
||||
*/
|
||||
|
|
@ -116,6 +119,7 @@ http_location_header(clicon_handle h,
|
|||
}
|
||||
|
||||
/*! Generic REST POST method
|
||||
*
|
||||
* @param[in] h Clixon handle
|
||||
* @param[in] req Generic Www handle
|
||||
* @param[in] api_path According to restconf (Sec 3.5.3.1 in rfc8040)
|
||||
|
|
@ -153,9 +157,9 @@ http_location_header(clicon_handle h,
|
|||
int
|
||||
api_data_post(clicon_handle h,
|
||||
void *req,
|
||||
char *api_path,
|
||||
char *api_path,
|
||||
int pi,
|
||||
cvec *qvec,
|
||||
cvec *qvec,
|
||||
char *data,
|
||||
int pretty,
|
||||
restconf_media media_in,
|
||||
|
|
@ -179,14 +183,14 @@ api_data_post(clicon_handle h,
|
|||
cxobj *xretdis = NULL; /* return from discard-changes */
|
||||
cxobj *xerr = NULL; /* malloced must be freed */
|
||||
cxobj *xe; /* dont free */
|
||||
cxobj *x;
|
||||
cxobj *x;
|
||||
char *username;
|
||||
int ret;
|
||||
int nrchildren0 = 0;
|
||||
yang_bind yb;
|
||||
|
||||
clicon_debug(1, "%s api_path:\"%s\"", __FUNCTION__, api_path);
|
||||
clicon_debug(1, "%s data:\"%s\"", __FUNCTION__, data);
|
||||
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s api_path:\"%s\"", __FUNCTION__, api_path);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s data:\"%s\"", __FUNCTION__, data);
|
||||
if ((yspec = clicon_dbspec_yang(h)) == NULL){
|
||||
clicon_err(OE_FATAL, 0, "No DB_SPEC");
|
||||
goto done;
|
||||
|
|
@ -249,7 +253,7 @@ api_data_post(clicon_handle h,
|
|||
goto ok;
|
||||
}
|
||||
break;
|
||||
case YANG_DATA_JSON:
|
||||
case YANG_DATA_JSON:
|
||||
if ((ret = clixon_json_parse_string(data, 1, yb, yspec, &xbot, &xerr)) < 0){
|
||||
if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0)
|
||||
goto done;
|
||||
|
|
@ -272,7 +276,7 @@ api_data_post(clicon_handle h,
|
|||
/* RFC 8040 4.4.1: The message-body MUST contain exactly one instance of the
|
||||
* expected data resource.
|
||||
*/
|
||||
clicon_debug(1, "%s nrchildren0: %d", __FUNCTION__, nrchildren0);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s nrchildren0: %d", __FUNCTION__, nrchildren0);
|
||||
if (xml_child_nr_type(xbot, CX_ELMNT) - nrchildren0 != 1){
|
||||
if (netconf_malformed_message_xml(&xerr, "The message-body MUST contain exactly one instance of the expected data resource") < 0)
|
||||
goto done;
|
||||
|
|
@ -283,7 +287,7 @@ api_data_post(clicon_handle h,
|
|||
/* Find the actual (new) object, the single unmarked one */
|
||||
x = NULL;
|
||||
while ((x = xml_child_each(xbot, x, CX_ELMNT)) != NULL){
|
||||
if (xml_flag(x, XML_FLAG_MARK)){
|
||||
if (xml_flag(x, XML_FLAG_MARK)){
|
||||
xml_flag_reset(x, XML_FLAG_MARK);
|
||||
continue;
|
||||
}
|
||||
|
|
@ -326,7 +330,7 @@ api_data_post(clicon_handle h,
|
|||
if (restconf_insert_attributes(xdata, qvec) < 0)
|
||||
goto done;
|
||||
#if 1
|
||||
clicon_debug_xml(1, xdata, "%s xdata:", __FUNCTION__);
|
||||
clixon_debug_xml(1, xdata, "%s xdata:", __FUNCTION__);
|
||||
#endif
|
||||
|
||||
/* Create text buffer for transfer to backend */
|
||||
|
|
@ -365,7 +369,7 @@ api_data_post(clicon_handle h,
|
|||
if (clixon_xml2cbuf(cbx, xtop, 0, 0, NULL, -1, 0) < 0)
|
||||
goto done;
|
||||
cprintf(cbx, "</edit-config></rpc>");
|
||||
clicon_debug(1, "%s xml: %s api_path:%s",__FUNCTION__, cbuf_get(cbx), api_path);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s xml: %s api_path:%s",__FUNCTION__, cbuf_get(cbx), api_path);
|
||||
if (clicon_rpc_netconf(h, cbuf_get(cbx), &xret, NULL) < 0)
|
||||
goto done;
|
||||
if ((xe = xpath_first(xret, NULL, "//rpc-error")) != NULL){
|
||||
|
|
@ -376,11 +380,11 @@ api_data_post(clicon_handle h,
|
|||
if (http_location_header(h, req, xdata) < 0)
|
||||
goto done;
|
||||
if (restconf_reply_send(req, 201, NULL, 0) < 0)
|
||||
goto done;
|
||||
goto done;
|
||||
ok:
|
||||
retval = 0;
|
||||
done:
|
||||
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s retval:%d", __FUNCTION__, retval);
|
||||
if (xret)
|
||||
xml_free(xret);
|
||||
if (xerr)
|
||||
|
|
@ -392,11 +396,12 @@ api_data_post(clicon_handle h,
|
|||
if (xtop)
|
||||
xml_free(xtop);
|
||||
if (cbx)
|
||||
cbuf_free(cbx);
|
||||
cbuf_free(cbx);
|
||||
return retval;
|
||||
} /* api_data_post */
|
||||
|
||||
/*! Handle input data to api_operations_post
|
||||
*
|
||||
* @param[in] h Clixon handle
|
||||
* @param[in] req Generic Www handle
|
||||
* @param[in] data Stream input data
|
||||
|
|
@ -436,7 +441,7 @@ api_operations_post_input(clicon_handle h,
|
|||
int ret;
|
||||
restconf_media media_in;
|
||||
|
||||
clicon_debug(1, "%s %s", __FUNCTION__, data);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s %s", __FUNCTION__, data);
|
||||
if ((cbret = cbuf_new()) == NULL){
|
||||
clicon_err(OE_UNIX, 0, "cbuf_new");
|
||||
goto done;
|
||||
|
|
@ -486,7 +491,7 @@ api_operations_post_input(clicon_handle h,
|
|||
* <data><input xmlns="urn:example:clixon">...</input></data>
|
||||
*/
|
||||
#if 1
|
||||
clicon_debug_xml(1, xdata, "%s xdata:", __FUNCTION__);
|
||||
clixon_debug_xml(1, xdata, "%s xdata:", __FUNCTION__);
|
||||
#endif
|
||||
/* Validate that exactly only <input> tag */
|
||||
if ((xinput = xml_child_i_type(xdata, 0, CX_ELMNT)) == NULL ||
|
||||
|
|
@ -499,23 +504,23 @@ api_operations_post_input(clicon_handle h,
|
|||
}
|
||||
else
|
||||
if (netconf_malformed_message_xml(&xerr, "restconf RPC has malformed input statement (multiple or not called input)") < 0)
|
||||
goto done;
|
||||
goto done;
|
||||
if (api_return_err0(h, req, xerr, pretty, media_out, 0) < 0)
|
||||
goto done;
|
||||
goto fail;
|
||||
}
|
||||
// clicon_debug(1, "%s input validation passed", __FUNCTION__);
|
||||
// clixon_debug(CLIXON_DBG_DEFAULT, "%s input validation passed", __FUNCTION__);
|
||||
/* Add all input under <rpc>path */
|
||||
x = NULL;
|
||||
while ((x = xml_child_i_type(xinput, 0, CX_ELMNT)) != NULL)
|
||||
if (xml_addsub(xrpc, x) < 0)
|
||||
if (xml_addsub(xrpc, x) < 0)
|
||||
goto done;
|
||||
/* Here xrpc is: <myfn xmlns="uri"><x>42</x></myfn>
|
||||
*/
|
||||
// ok:
|
||||
retval = 1;
|
||||
done:
|
||||
clicon_debug(1, "%s retval: %d", __FUNCTION__, retval);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s retval: %d", __FUNCTION__, retval);
|
||||
if (cbret)
|
||||
cbuf_free(cbret);
|
||||
if (xerr)
|
||||
|
|
@ -529,6 +534,7 @@ api_operations_post_input(clicon_handle h,
|
|||
}
|
||||
|
||||
/*! Handle output data to api_operations_post
|
||||
*
|
||||
* @param[in] h Clixon handle
|
||||
* @param[in] req Generic Www handle
|
||||
* @param[in] xret XML reply messages from backend/handler
|
||||
|
|
@ -552,7 +558,6 @@ api_operations_post_output(clicon_handle h,
|
|||
int pretty,
|
||||
restconf_media media_out,
|
||||
cxobj **xoutputp)
|
||||
|
||||
{
|
||||
int retval = -1;
|
||||
cxobj *xoutput = NULL;
|
||||
|
|
@ -561,8 +566,8 @@ api_operations_post_output(clicon_handle h,
|
|||
cxobj *x;
|
||||
cxobj *xok;
|
||||
int isempty;
|
||||
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
|
||||
/* Validate that exactly only <rpc-reply> tag with exactly one element child */
|
||||
if ((xoutput = xml_child_i_type(xret, 0, CX_ELMNT)) == NULL ||
|
||||
strcmp(xml_name(xoutput),"rpc-reply") != 0
|
||||
|
|
@ -573,7 +578,7 @@ api_operations_post_output(clicon_handle h,
|
|||
*/
|
||||
){
|
||||
if (netconf_malformed_message_xml(&xerr, "restconf RPC does not have single input") < 0)
|
||||
goto done;
|
||||
goto done;
|
||||
if (api_return_err0(h, req, xerr, pretty, media_out, 0) < 0)
|
||||
goto done;
|
||||
goto fail;
|
||||
|
|
@ -583,7 +588,7 @@ api_operations_post_output(clicon_handle h,
|
|||
xml_name_set(xoutput, "output");
|
||||
/* xoutput should now look: <output><x xmlns="uri">0</x></output> */
|
||||
#if 1
|
||||
clicon_debug_xml(1, xoutput, "%s xoutput:", __FUNCTION__);
|
||||
clixon_debug_xml(1, xoutput, "%s xoutput:", __FUNCTION__);
|
||||
#endif
|
||||
/* Remove original netconf default namespace. Somewhat unsure what "output" belongs to? */
|
||||
if ((xa = xml_find_type(xoutput, NULL, "xmlns", CX_ATTR)) != NULL)
|
||||
|
|
@ -628,7 +633,7 @@ api_operations_post_output(clicon_handle h,
|
|||
if (isempty) {
|
||||
/* Internal error - invalid output from rpc handler */
|
||||
if (restconf_reply_send(req, 204, NULL, 0) < 0)
|
||||
goto done;
|
||||
goto done;
|
||||
goto fail;
|
||||
}
|
||||
/* Clear namespace of parameters */
|
||||
|
|
@ -644,7 +649,7 @@ api_operations_post_output(clicon_handle h,
|
|||
*xoutputp = xoutput;
|
||||
retval = 1;
|
||||
done:
|
||||
clicon_debug(1, "%s retval: %d", __FUNCTION__, retval);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s retval: %d", __FUNCTION__, retval);
|
||||
if (xerr)
|
||||
xml_free(xerr);
|
||||
return retval;
|
||||
|
|
@ -654,6 +659,7 @@ api_operations_post_output(clicon_handle h,
|
|||
}
|
||||
|
||||
/*! REST operation POST method
|
||||
*
|
||||
* @param[in] h Clixon handle
|
||||
* @param[in] req Generic Www handle
|
||||
* @param[in] api_path According to restconf (Sec 3.5.3.1 in rfc8040)
|
||||
|
|
@ -661,6 +667,8 @@ api_operations_post_output(clicon_handle h,
|
|||
* @param[in] data Stream input data
|
||||
* @param[in] pretty Set to 1 for pretty-printed xml/json output
|
||||
* @param[in] media_out Output media
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
* See RFC 8040 Sec 3.6 / 4.4.2
|
||||
* @note We map post to edit-config create.
|
||||
* POST {+restconf}/operations/<operation>
|
||||
|
|
@ -685,9 +693,9 @@ api_operations_post_output(clicon_handle h,
|
|||
int
|
||||
api_operations_post(clicon_handle h,
|
||||
void *req,
|
||||
char *api_path,
|
||||
char *api_path,
|
||||
int pi,
|
||||
cvec *qvec,
|
||||
cvec *qvec,
|
||||
char *data,
|
||||
int pretty,
|
||||
restconf_media media_out)
|
||||
|
|
@ -713,8 +721,8 @@ api_operations_post(clicon_handle h,
|
|||
yang_stmt *ys = NULL;
|
||||
char *namespace = NULL;
|
||||
int nr = 0;
|
||||
|
||||
clicon_debug(1, "%s json:\"%s\" path:\"%s\"", __FUNCTION__, data, api_path);
|
||||
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s json:\"%s\" path:\"%s\"", __FUNCTION__, data, api_path);
|
||||
/* 1. Initialize */
|
||||
if ((yspec = clicon_dbspec_yang(h)) == NULL){
|
||||
clicon_err(OE_FATAL, 0, "No DB_SPEC");
|
||||
|
|
@ -784,7 +792,7 @@ api_operations_post(clicon_handle h,
|
|||
* XML: <input xmlns="uri"><x>0</x></input>
|
||||
*/
|
||||
namespace = xml_find_type_value(xbot, NULL, "xmlns", CX_ATTR);
|
||||
clicon_debug(1, "%s : 4. Parse input data: %s", __FUNCTION__, data);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s : 4. Parse input data: %s", __FUNCTION__, data);
|
||||
if (data && strlen(data)){
|
||||
if ((ret = api_operations_post_input(h, req, data, yspec, yrpc, xbot,
|
||||
pretty, media_out)) < 0)
|
||||
|
|
@ -795,7 +803,7 @@ api_operations_post(clicon_handle h,
|
|||
/* Here xtop is:
|
||||
<rpc username="foo"><myfn xmlns="uri"><x>42</x></myfn></rpc> */
|
||||
#if 1
|
||||
clicon_debug_xml(1, xtop, "%s 5. Translate input args:", __FUNCTION__);
|
||||
clixon_debug_xml(1, xtop, "%s 5. Translate input args:", __FUNCTION__);
|
||||
#endif
|
||||
/* 6. Validate outgoing RPC and fill in defaults */
|
||||
if ((ret = xml_bind_yang_rpc(h, xtop, yspec, &xerr)) < 0) /* */
|
||||
|
|
@ -816,7 +824,7 @@ api_operations_post(clicon_handle h,
|
|||
* <rpc username="foo"><myfn xmlns="uri"><x>42</x><y>99</y></myfn></rpc>
|
||||
*/
|
||||
#if 0
|
||||
clicon_debug_xml(1, xtop, "%s 6. Validate and defaults:", __FUNCTION__);
|
||||
clixon_debug_xml(1, xtop, "%s 6. Validate and defaults:", __FUNCTION__);
|
||||
#endif
|
||||
/* 7. Send to RPC handler, either local or backend
|
||||
* Note (1) xtop is <rpc><method> xbot is <method>
|
||||
|
|
@ -857,7 +865,7 @@ api_operations_post(clicon_handle h,
|
|||
* <rpc-reply><x xmlns="uri">0</x></rpc-reply>
|
||||
*/
|
||||
#if 1
|
||||
clicon_debug_xml(1, xret, "%s Receive reply:", __FUNCTION__);
|
||||
clixon_debug_xml(1, xret, "%s Receive reply:", __FUNCTION__);
|
||||
#endif
|
||||
youtput = yang_find(yrpc, Y_OUTPUT, NULL);
|
||||
if ((ret = api_operations_post_output(h, req, xret, yspec, youtput, namespace,
|
||||
|
|
@ -889,7 +897,7 @@ api_operations_post(clicon_handle h,
|
|||
ok:
|
||||
retval = 0;
|
||||
done:
|
||||
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s retval:%d", __FUNCTION__, retval);
|
||||
if (prefix)
|
||||
free(prefix);
|
||||
if (id)
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@
|
|||
int api_data_post(clicon_handle h, void *req, char *api_path,
|
||||
int pi, cvec *qvec, char *data,
|
||||
int pretty,
|
||||
restconf_media media_in,
|
||||
restconf_media media_in,
|
||||
restconf_media media_out, ietf_ds_t ds);
|
||||
|
||||
int api_operations_post(clicon_handle h, void *req, char *api_path,
|
||||
|
|
|
|||
|
|
@ -80,7 +80,8 @@
|
|||
/* Forward */
|
||||
static int restconf_idle_cb(int fd, void *arg);
|
||||
|
||||
/*!
|
||||
/*! Create restconf stream
|
||||
*
|
||||
* @param[in] rc Restconf connection handle
|
||||
* @see restconf_stream_free
|
||||
*/
|
||||
|
|
@ -118,7 +119,8 @@ restconf_stream_data_new(restconf_conn *rc,
|
|||
return sd;
|
||||
}
|
||||
|
||||
/*!
|
||||
/*! Find restconf stream data
|
||||
*
|
||||
* @param[in] rc Restconf connection handle
|
||||
*/
|
||||
restconf_stream_data *
|
||||
|
|
@ -190,11 +192,12 @@ restconf_conn_new(clicon_handle h,
|
|||
rc->rc_callhome = rsock->rs_callhome;
|
||||
rc->rc_socket = rsock;
|
||||
INSQ(rc, rsock->rs_conns);
|
||||
clicon_debug(1, "%s %p", __FUNCTION__, rc);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s %p", __FUNCTION__, rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*! Free clixon/cbuf resources related to a connection
|
||||
*
|
||||
* @param[in] rc restconf connection
|
||||
*/
|
||||
static int
|
||||
|
|
@ -205,7 +208,7 @@ restconf_conn_free(restconf_conn *rc)
|
|||
restconf_socket *rsock;
|
||||
restconf_conn *rc1;
|
||||
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
|
||||
if (rc == NULL){
|
||||
clicon_err(OE_RESTCONF, EINVAL, "rc is NULL");
|
||||
goto done;
|
||||
|
|
@ -238,8 +241,11 @@ restconf_conn_free(restconf_conn *rc)
|
|||
}
|
||||
|
||||
/*! Given SSL connection, get peer certificate one-line name
|
||||
*
|
||||
* @param[in] ssl SSL session
|
||||
* @param[out] oneline Cert name one-line
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
*/
|
||||
int
|
||||
ssl_x509_name_oneline(SSL *ssl,
|
||||
|
|
@ -261,7 +267,7 @@ ssl_x509_name_oneline(SSL *ssl,
|
|||
if ((cert = SSL_get1_peer_certificate(ssl)) == NULL)
|
||||
goto ok;
|
||||
#endif
|
||||
if ((name = X509_get_subject_name(cert)) == NULL)
|
||||
if ((name = X509_get_subject_name(cert)) == NULL)
|
||||
goto ok;
|
||||
if ((p = X509_NAME_oneline(name, NULL, 0)) == NULL)
|
||||
goto ok;
|
||||
|
|
@ -308,7 +314,7 @@ restconf_connection_sanity(clicon_handle h,
|
|||
restconf_media media_out = YANG_DATA_JSON;
|
||||
char *media_str = NULL;
|
||||
char *oneline = NULL;
|
||||
|
||||
|
||||
/* 1) Check if http/2 non-tls is disabled */
|
||||
if (rc->rc_ssl == NULL &&
|
||||
rc->rc_proto == HTTP_2 &&
|
||||
|
|
@ -383,7 +389,7 @@ native_buf_write(clicon_handle h,
|
|||
char *buf,
|
||||
size_t buflen,
|
||||
restconf_conn *rc,
|
||||
const char *callfn)
|
||||
const char *callfn)
|
||||
{
|
||||
int retval = -1;
|
||||
ssize_t len;
|
||||
|
|
@ -400,7 +406,7 @@ native_buf_write(clicon_handle h,
|
|||
* 1. they are not "strings" in the sense they are not NULL-terminated
|
||||
* 2. they are often very long
|
||||
*/
|
||||
if (clicon_debug_get()) {
|
||||
if (clixon_debug_get()) {
|
||||
char *dbgstr = NULL;
|
||||
size_t sz;
|
||||
sz = buflen>256?256:buflen; /* Truncate to 256 */
|
||||
|
|
@ -410,7 +416,7 @@ native_buf_write(clicon_handle h,
|
|||
}
|
||||
memcpy(dbgstr, buf, sz);
|
||||
dbgstr[sz] = '\0';
|
||||
clicon_debug(1, "%s %s buflen:%zu buf:\n%s", __FUNCTION__, callfn, buflen, dbgstr);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s %s buflen:%zu buf:\n%s", __FUNCTION__, callfn, buflen, dbgstr);
|
||||
free(dbgstr);
|
||||
}
|
||||
while (totlen < buflen){
|
||||
|
|
@ -424,7 +430,7 @@ native_buf_write(clicon_handle h,
|
|||
goto closed; /* Close socket and ssl */
|
||||
}
|
||||
else if (er == EAGAIN){
|
||||
clicon_debug(1, "%s write EAGAIN", __FUNCTION__);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s write EAGAIN", __FUNCTION__);
|
||||
usleep(10000);
|
||||
continue;
|
||||
}
|
||||
|
|
@ -445,7 +451,7 @@ native_buf_write(clicon_handle h,
|
|||
if ((len = write(rc->rc_s, buf+totlen, buflen-totlen)) < 0){
|
||||
switch (errno){
|
||||
case EAGAIN: /* Operation would block */
|
||||
clicon_debug(1, "%s write EAGAIN", __FUNCTION__);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s write EAGAIN", __FUNCTION__);
|
||||
usleep(10000);
|
||||
continue;
|
||||
break;
|
||||
|
|
@ -465,7 +471,7 @@ native_buf_write(clicon_handle h,
|
|||
} /* while */
|
||||
retval = 1;
|
||||
done:
|
||||
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s retval:%d", __FUNCTION__, retval);
|
||||
return retval;
|
||||
closed:
|
||||
retval = 0;
|
||||
|
|
@ -473,13 +479,14 @@ native_buf_write(clicon_handle h,
|
|||
}
|
||||
|
||||
/*! Send early handcoded bad request reply before actual packet received, just after accept
|
||||
*
|
||||
* @param[in] h Clixon handle
|
||||
* @param[in] media
|
||||
* @param[in] body If given add message body using media
|
||||
* @param[in] rc Restconf connection, note may be closed in this
|
||||
* @retval 1 OK
|
||||
* @retval 0 OK, but socket write returned error, caller should close rc
|
||||
* @retval -1 Error
|
||||
* @retval 1 OK
|
||||
* @retval 0 OK, but socket write returned error, caller should close rc
|
||||
* @retval -1 Error
|
||||
* @see restconf_badrequest which can only be called in a request context
|
||||
*/
|
||||
static int
|
||||
|
|
@ -490,8 +497,8 @@ native_send_badrequest(clicon_handle h,
|
|||
{
|
||||
int retval = -1;
|
||||
cbuf *cb = NULL;
|
||||
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
|
||||
if ((cb = cbuf_new()) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "cbuf_new");
|
||||
goto done;
|
||||
|
|
@ -548,8 +555,8 @@ http1_native_clear_input(clicon_handle h,
|
|||
* @param[in] sz Size of input buffer
|
||||
* @param[out] np Bytes read
|
||||
* @param[out] again If set, read data again, do not continue processing
|
||||
* @retval -1 Error
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
*/
|
||||
static int
|
||||
read_ssl(restconf_conn *rc,
|
||||
|
|
@ -560,10 +567,10 @@ read_ssl(restconf_conn *rc,
|
|||
{
|
||||
int retval = -1;
|
||||
int sslerr;
|
||||
|
||||
|
||||
if ((*np = SSL_read(rc->rc_ssl, buf, sz)) <= 0){
|
||||
sslerr = SSL_get_error(rc->rc_ssl, *np);
|
||||
clicon_debug(1, "%s SSL_read() n:%zd errno:%d sslerr:%d", __FUNCTION__, *np, errno, sslerr);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s SSL_read() n:%zd errno:%d sslerr:%d", __FUNCTION__, *np, errno, sslerr);
|
||||
switch (sslerr){
|
||||
case SSL_ERROR_WANT_READ: /* 2 */
|
||||
/* SSL_ERROR_WANT_READ is returned when the last operation was a read operation
|
||||
|
|
@ -571,7 +578,7 @@ read_ssl(restconf_conn *rc,
|
|||
* That is, it can happen if restconf_socket_init() below is called
|
||||
* with SOCK_NONBLOCK
|
||||
*/
|
||||
clicon_debug(1, "%s SSL_read SSL_ERROR_WANT_READ", __FUNCTION__);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s SSL_read SSL_ERROR_WANT_READ", __FUNCTION__);
|
||||
usleep(1000);
|
||||
*again = 1;
|
||||
break;
|
||||
|
|
@ -580,13 +587,13 @@ read_ssl(restconf_conn *rc,
|
|||
break;
|
||||
default:
|
||||
clicon_log(LOG_WARNING, "%s SSL_read(): %s sslerr:%d", __FUNCTION__, strerror(errno), sslerr);
|
||||
*np = 0;
|
||||
*np = 0;
|
||||
break;
|
||||
} /* switch */
|
||||
}
|
||||
retval = 0;
|
||||
// done:
|
||||
clicon_debug(1, "%s %d", __FUNCTION__, retval);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s %d", __FUNCTION__, retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
|
@ -597,9 +604,9 @@ read_ssl(restconf_conn *rc,
|
|||
* @param[in] sz Size of input buffer
|
||||
* @param[out] np Bytes read
|
||||
* @param[out] again If set, read data again, do not continue processing
|
||||
* @retval -1 Error
|
||||
* @retval 0 Socket closed, quit
|
||||
* @retval 1 OK
|
||||
* @retval 0 Socket closed, quit
|
||||
* @retval -1 Error
|
||||
* XXX:
|
||||
* readmore/continue
|
||||
* goto ok
|
||||
|
|
@ -612,18 +619,18 @@ read_regular(restconf_conn *rc,
|
|||
int *again)
|
||||
{
|
||||
int retval = -1;
|
||||
|
||||
|
||||
if ((*np = read(rc->rc_s, buf, sz)) < 0){ /* XXX atomicio ? */
|
||||
switch(errno){
|
||||
case ECONNRESET:/* Connection reset by peer */
|
||||
clicon_debug(1, "%s %d Connection reset by peer", __FUNCTION__, rc->rc_s);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s %d Connection reset by peer", __FUNCTION__, rc->rc_s);
|
||||
if (restconf_close_ssl_socket(rc, __FUNCTION__, 0) < 0)
|
||||
goto done;
|
||||
retval = 0; /* Close socket and ssl */
|
||||
goto done;
|
||||
break;
|
||||
case EAGAIN:
|
||||
clicon_debug(1, "%s read EAGAIN", __FUNCTION__);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s read EAGAIN", __FUNCTION__);
|
||||
usleep(1000);
|
||||
*again = 1;
|
||||
break;
|
||||
|
|
@ -646,9 +653,9 @@ read_regular(restconf_conn *rc,
|
|||
* @param[in] buf Input buffer
|
||||
* @param[in] n Length of data in input buffer
|
||||
* @param[out] readmore If set, read data again, do not continue processing
|
||||
* @retval -1 Error
|
||||
* @retval 0 Socket closed, quit
|
||||
* @retval 1 OK
|
||||
* @retval 0 Socket closed, quit
|
||||
* @retval -1 Error
|
||||
*/
|
||||
static int
|
||||
restconf_http1_process(restconf_conn *rc,
|
||||
|
|
@ -662,7 +669,7 @@ restconf_http1_process(restconf_conn *rc,
|
|||
int ret;
|
||||
int status;
|
||||
cbuf *cberr = NULL;
|
||||
|
||||
|
||||
h = rc->rc_h;
|
||||
if ((sd = restconf_stream_find(rc, 0)) == NULL){
|
||||
clicon_err(OE_RESTCONF, EINVAL, "restconf stream not found");
|
||||
|
|
@ -803,7 +810,7 @@ restconf_http2_upgrade(restconf_conn *rc)
|
|||
{
|
||||
int retval = -1;
|
||||
restconf_stream_data *sd;
|
||||
|
||||
|
||||
if ((sd = restconf_stream_find(rc, 0)) == NULL){
|
||||
clicon_err(OE_RESTCONF, EINVAL, "restconf stream not found");
|
||||
goto done;
|
||||
|
|
@ -854,19 +861,20 @@ restconf_http2_upgrade(restconf_conn *rc)
|
|||
|
||||
retval = 0;
|
||||
done:
|
||||
return retval;
|
||||
return retval;
|
||||
}
|
||||
#endif /* HAVE_LIBHTTP1 */
|
||||
|
||||
/*! Restconf HTTP/2 processing after chunk of bytes read
|
||||
*
|
||||
* @param[in] rc Restconf connection
|
||||
* @param[in] buf Input buffer
|
||||
* @param[in] n Size of input buffer
|
||||
* @param[in] n Length of data in input buffer
|
||||
* @param[out] readmore If set, read data again, do not continue processing
|
||||
* @retval -1 Error
|
||||
* @retval 0 Socket closed, quit
|
||||
* @retval 1 OK
|
||||
* @retval 0 Socket closed, quit
|
||||
* @retval -1 Error
|
||||
*/
|
||||
static int
|
||||
restconf_http2_process(restconf_conn *rc,
|
||||
|
|
@ -878,7 +886,7 @@ restconf_http2_process(restconf_conn *rc,
|
|||
int ret;
|
||||
nghttp2_error ngerr;
|
||||
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
|
||||
if (rc->rc_exit){ /* Server-initiated exit for http/2 */
|
||||
if ((ngerr = nghttp2_session_terminate_session(rc->rc_ngsession, 0)) < 0){
|
||||
clicon_err(OE_NGHTTP2, ngerr, "nghttp2_session_terminate_session %d", ngerr);
|
||||
|
|
@ -905,13 +913,14 @@ restconf_http2_process(restconf_conn *rc,
|
|||
}
|
||||
retval = 1;
|
||||
done:
|
||||
clicon_debug(1, "%s %d", __FUNCTION__, retval);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s %d", __FUNCTION__, retval);
|
||||
return retval;
|
||||
}
|
||||
#endif /* HAVE_LIBNGHTTP2 */
|
||||
|
||||
/*! Get restconf native handle
|
||||
* @param[in] h Clicon handle
|
||||
*
|
||||
* @param[in] h Clixon handle
|
||||
* @retval rn Restconf native handle
|
||||
*/
|
||||
restconf_native_handle *
|
||||
|
|
@ -933,7 +942,7 @@ restconf_native_handle_get(clicon_handle h)
|
|||
* @param[in] s Socket where message arrived. read from this.
|
||||
* @param[in] arg Client entry (from).
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error Terminates backend and is never called). Instead errors are
|
||||
* @retval -1 Error Terminates backend and is never called). Instead errors are
|
||||
* propagated back to client.
|
||||
* @see restconf_accept_client where this callback is registered
|
||||
* @note read buffer is limited. More data can be read in two ways: returns a buffer
|
||||
|
|
@ -952,7 +961,7 @@ restconf_connection(int s,
|
|||
int readmore = 1;
|
||||
int ret;
|
||||
|
||||
clicon_debug(1, "%s %d", __FUNCTION__, s);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s %d", __FUNCTION__, s);
|
||||
if ((rc = (restconf_conn*)arg) == NULL){
|
||||
clicon_err(OE_RESTCONF, EINVAL, "arg is NULL");
|
||||
goto done;
|
||||
|
|
@ -963,7 +972,7 @@ restconf_connection(int s,
|
|||
}
|
||||
gettimeofday(&rc->rc_t, NULL); /* activity timer */
|
||||
while (readmore) {
|
||||
clicon_debug(1, "%s readmore", __FUNCTION__);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s readmore", __FUNCTION__);
|
||||
readmore = 0;
|
||||
/* Example: curl -Ssik -u wilma:bar -X GET https://localhost/restconf/data/example:x */
|
||||
if (rc->rc_ssl){
|
||||
|
|
@ -976,11 +985,11 @@ restconf_connection(int s,
|
|||
if (ret == 0)
|
||||
goto ok; /* abort here */
|
||||
}
|
||||
clicon_debug(1, "%s read:%zd", __FUNCTION__, n);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s read:%zd", __FUNCTION__, n);
|
||||
if (readmore)
|
||||
continue;
|
||||
if (n == 0){
|
||||
clicon_debug(1, "%s n=0 closing socket", __FUNCTION__);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s n=0 closing socket", __FUNCTION__);
|
||||
if (restconf_close_ssl_socket(rc, __FUNCTION__, 0) < 0)
|
||||
goto done;
|
||||
rc = NULL;
|
||||
|
|
@ -1020,15 +1029,18 @@ restconf_connection(int s,
|
|||
ok:
|
||||
retval = 0;
|
||||
done:
|
||||
clicon_debug(1, "%s retval %d", __FUNCTION__, retval);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s retval %d", __FUNCTION__, retval);
|
||||
return retval;
|
||||
} /* restconf_connection */
|
||||
|
||||
/*----------------------------- Close socket ------------------------------*/
|
||||
|
||||
/*! Close Restconf native connection socket and unregister callback
|
||||
*
|
||||
* For callhome also start reconnect timer
|
||||
* @param[in] rc rstconf connection
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
*/
|
||||
static int
|
||||
restconf_connection_close1(restconf_conn *rc)
|
||||
|
|
@ -1041,7 +1053,7 @@ restconf_connection_close1(restconf_conn *rc)
|
|||
goto done;
|
||||
}
|
||||
rsock = rc->rc_socket;
|
||||
clicon_debug(1, "%s \"%s\"", __FUNCTION__, rsock->rs_description);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s \"%s\"", __FUNCTION__, rsock->rs_description);
|
||||
if (close(rc->rc_s) < 0){
|
||||
clicon_err(OE_UNIX, errno, "close");
|
||||
goto done;
|
||||
|
|
@ -1056,16 +1068,19 @@ restconf_connection_close1(restconf_conn *rc)
|
|||
}
|
||||
retval = 0;
|
||||
done:
|
||||
clicon_debug(1, "%s %d", __FUNCTION__, retval);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s %d", __FUNCTION__, retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Utility function to close restconf server ssl socket.
|
||||
*
|
||||
* There are many variants to closing, one could probably make this more generic
|
||||
* and always use this function, but it is difficult.
|
||||
* @param[in] rc restconf connection
|
||||
* @param[in] callfn For debug
|
||||
* @param[in] dontshutdown If != 0, do not shutdown
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
*/
|
||||
int
|
||||
restconf_close_ssl_socket(restconf_conn *rc,
|
||||
|
|
@ -1077,16 +1092,15 @@ restconf_close_ssl_socket(restconf_conn *rc,
|
|||
int sslerr;
|
||||
int er;
|
||||
|
||||
clicon_debug(1, "%s %s", __FUNCTION__, callfn);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s %s", __FUNCTION__, callfn);
|
||||
if (rc->rc_ssl != NULL){
|
||||
if (!dontshutdown &&
|
||||
(ret = SSL_shutdown(rc->rc_ssl)) < 0){
|
||||
er = errno;
|
||||
sslerr = SSL_get_error(rc->rc_ssl, ret);
|
||||
clicon_debug(1, "%s errno:%s(%d) sslerr:%d", __FUNCTION__, strerror(er), er, sslerr);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s errno:%s(%d) sslerr:%d", __FUNCTION__, strerror(er), er, sslerr);
|
||||
if (sslerr == SSL_ERROR_SSL || /* 1 */
|
||||
sslerr == SSL_ERROR_ZERO_RETURN){ /* 6 */
|
||||
|
||||
}
|
||||
else if (sslerr == SSL_ERROR_SYSCALL){ /* 5 */
|
||||
/* Some non-recoverable, fatal I/O error occurred. The OpenSSL error queue
|
||||
|
|
@ -1112,14 +1126,16 @@ restconf_close_ssl_socket(restconf_conn *rc,
|
|||
goto done;
|
||||
retval = 0;
|
||||
done:
|
||||
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s retval:%d", __FUNCTION__, retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*------------------------------ Accept--------------------------------*/
|
||||
|
||||
/*! Check ALPN result
|
||||
* @proto[out] proto
|
||||
*
|
||||
* @param[in] h Clixon handle
|
||||
* @param[out] proto
|
||||
* @retval 1 OK with proto set
|
||||
* @retval 0 Fail, ALPN null or not recognized
|
||||
* @retval -1 Error
|
||||
|
|
@ -1133,8 +1149,8 @@ ssl_alpn_check(clicon_handle h,
|
|||
{
|
||||
int retval = -1;
|
||||
cbuf *cberr = NULL;
|
||||
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
|
||||
/* Alternatively, call restconf_str2proto but alpn is not a proper string */
|
||||
if (alpn && alpnlen == 8 && memcmp("http/1.1", alpn, 8) == 0){
|
||||
*proto = HTTP_11;
|
||||
|
|
@ -1152,7 +1168,7 @@ ssl_alpn_check(clicon_handle h,
|
|||
if (alpn != NULL){
|
||||
cprintf(cberr, "<errors xmlns=\"urn:ietf:params:xml:ns:yang:ietf-restconf\"><error><error-type>protocol</error-type><error-tag>malformed-message</error-tag><error-message>ALPN: protocol not recognized: %s</error-message></error></errors>", alpn);
|
||||
clicon_log(LOG_INFO, "%s Warning: %s", __FUNCTION__, cbuf_get(cberr));
|
||||
if (native_send_badrequest(h,
|
||||
if (native_send_badrequest(h,
|
||||
"application/yang-data+xml",
|
||||
cbuf_get(cberr), rc) < 0)
|
||||
goto done;
|
||||
|
|
@ -1165,7 +1181,7 @@ ssl_alpn_check(clicon_handle h,
|
|||
#if defined(HAVE_LIBNGHTTP2)
|
||||
char *pstr; /* Both http/1 and http/2 */
|
||||
int p = -1;
|
||||
|
||||
|
||||
pstr = clicon_option_str(h, "CLICON_NOALPN_DEFAULT");
|
||||
if (pstr)
|
||||
p = restconf_str2proto(pstr);
|
||||
|
|
@ -1186,7 +1202,7 @@ ssl_alpn_check(clicon_handle h,
|
|||
}
|
||||
retval = 1;
|
||||
done:
|
||||
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s retval:%d", __FUNCTION__, retval);
|
||||
if (cberr)
|
||||
cbuf_free(cberr);
|
||||
return retval;
|
||||
|
|
@ -1196,6 +1212,7 @@ ssl_alpn_check(clicon_handle h,
|
|||
} /* ssl_alpn_check */
|
||||
|
||||
/*! Accept new socket client. Note SSL not ip, this applies also to callhome
|
||||
*
|
||||
* @param[in] h Clixon handle
|
||||
* @param[in] s Socket (unix or ip)
|
||||
* @param[in] rsock Socket struct
|
||||
|
|
@ -1223,7 +1240,7 @@ restconf_ssl_accept_client(clicon_handle h,
|
|||
unsigned int alpnlen = 0;
|
||||
restconf_http_proto proto = HTTP_11; /* Non-SSL negotiation NYI */
|
||||
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
|
||||
#ifdef HAVE_LIBNGHTTP2
|
||||
#ifndef HAVE_HTTP1
|
||||
proto = HTTP_2; /* If nghttp2 only let default be 2.0 */
|
||||
|
|
@ -1238,13 +1255,13 @@ restconf_ssl_accept_client(clicon_handle h,
|
|||
*/
|
||||
if ((rc = restconf_conn_new(h, s, rsock)) == NULL)
|
||||
goto done;
|
||||
clicon_debug(1, "%s s:%d", __FUNCTION__, rc->rc_s);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s s:%d", __FUNCTION__, rc->rc_s);
|
||||
if (rsock->rs_ssl){
|
||||
if ((rc->rc_ssl = SSL_new(rn->rn_ctx)) == NULL){
|
||||
clicon_err(OE_SSL, 0, "SSL_new");
|
||||
goto done;
|
||||
}
|
||||
clicon_debug(1, "%s SSL_new(%p)", __FUNCTION__, rc->rc_ssl);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s SSL_new(%p)", __FUNCTION__, rc->rc_ssl);
|
||||
/* CCL_CTX_set_verify already set, need not call SSL_set_verify again for this server
|
||||
*/
|
||||
/* X509_CHECK_FLAG_NO_WILDCARDS disables wildcard expansion */
|
||||
|
|
@ -1281,11 +1298,11 @@ restconf_ssl_accept_client(clicon_handle h,
|
|||
* Both error cases: Call SSL_get_error() with the return value ret
|
||||
*/
|
||||
if ((ret = SSL_accept(rc->rc_ssl)) != 1) {
|
||||
clicon_debug(1, "%s SSL_accept() ret:%d errno:%d", __FUNCTION__, ret, er=errno);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s SSL_accept() ret:%d errno:%d", __FUNCTION__, ret, er=errno);
|
||||
e = SSL_get_error(rc->rc_ssl, ret);
|
||||
switch (e){
|
||||
case SSL_ERROR_SSL: /* 1 */
|
||||
clicon_debug(1, "%s SSL_ERROR_SSL (non-ssl message on ssl socket)", __FUNCTION__);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s SSL_ERROR_SSL (non-ssl message on ssl socket)", __FUNCTION__);
|
||||
#ifdef HTTP_ON_HTTPS_REPLY
|
||||
SSL_free(rc->rc_ssl);
|
||||
rc->rc_ssl = NULL;
|
||||
|
|
@ -1298,12 +1315,12 @@ restconf_ssl_accept_client(clicon_handle h,
|
|||
goto closed;
|
||||
break;
|
||||
case SSL_ERROR_SYSCALL: /* 5 */
|
||||
/* Some non-recoverable, fatal I/O error occurred. The OpenSSL error queue
|
||||
/* Some non-recoverable, fatal I/O error occurred. The OpenSSL error queue
|
||||
may contain more information on the error. For socket I/O on Unix systems,
|
||||
consult errno for details. If this error occurs then no further I/O
|
||||
operations should be performed on the connection and SSL_shutdown() must
|
||||
not be called.*/
|
||||
clicon_debug(1, "%s SSL_accept() SSL_ERROR_SYSCALL %d", __FUNCTION__, er);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s SSL_accept() SSL_ERROR_SYSCALL %d", __FUNCTION__, er);
|
||||
if (restconf_close_ssl_socket(rc, __FUNCTION__, 1) < 0)
|
||||
goto done;
|
||||
rc = NULL;
|
||||
|
|
@ -1316,7 +1333,7 @@ restconf_ssl_accept_client(clicon_handle h,
|
|||
* That is, it can happen if restconf_socket_init() below is called
|
||||
* with SOCK_NONBLOCK
|
||||
*/
|
||||
clicon_debug(1, "%s write SSL_ERROR_WANT_READ", __FUNCTION__);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s write SSL_ERROR_WANT_READ", __FUNCTION__);
|
||||
usleep(10000);
|
||||
readmore = 1;
|
||||
break;
|
||||
|
|
@ -1350,7 +1367,7 @@ restconf_ssl_accept_client(clicon_handle h,
|
|||
if (ret == 0){
|
||||
goto closed;
|
||||
}
|
||||
clicon_debug(1, "%s proto:%s", __FUNCTION__, restconf_proto2str(proto));
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s proto:%s", __FUNCTION__, restconf_proto2str(proto));
|
||||
|
||||
#if 0 /* Seems too early to fail here, instead let authentication callback deal with this */
|
||||
/* For client-cert authentication, check if any certs are present,
|
||||
|
|
@ -1388,7 +1405,7 @@ restconf_ssl_accept_client(clicon_handle h,
|
|||
const char *peername = SSL_get0_peername(rc->rc_ssl);
|
||||
if (peername != NULL) {
|
||||
/* Name checks were in scope and matched the peername */
|
||||
clicon_debug(1, "%s peername:%s", __FUNCTION__, peername);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s peername:%s", __FUNCTION__, peername);
|
||||
}
|
||||
}
|
||||
#if 0
|
||||
|
|
@ -1402,7 +1419,7 @@ restconf_ssl_accept_client(clicon_handle h,
|
|||
}
|
||||
#endif
|
||||
#if 0 /* debug */
|
||||
if (clicon_debug_get())
|
||||
if (clixon_debug_get())
|
||||
restconf_listcerts(rc->rc_ssl);
|
||||
#endif
|
||||
} /* if ssl */
|
||||
|
|
@ -1441,7 +1458,7 @@ restconf_ssl_accept_client(clicon_handle h,
|
|||
*rcp = rc;
|
||||
retval = 1; /* OK, up */
|
||||
done:
|
||||
clicon_debug(1, "%s retval %d", __FUNCTION__, retval);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s retval %d", __FUNCTION__, retval);
|
||||
if (name)
|
||||
free(name);
|
||||
return retval;
|
||||
|
|
@ -1457,7 +1474,7 @@ restconf_idle_timer_set(struct timeval t,
|
|||
{
|
||||
int retval = -1;
|
||||
cbuf *cb = NULL;
|
||||
|
||||
|
||||
if ((cb = cbuf_new()) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "cbuf_new");
|
||||
goto done;
|
||||
|
|
@ -1475,8 +1492,11 @@ restconf_idle_timer_set(struct timeval t,
|
|||
return retval;
|
||||
}
|
||||
|
||||
/*! idle timeout timer callback
|
||||
* @param[in] rc restconf connection, more specifically: callhome connection
|
||||
/*! Idle timeout timer callback
|
||||
*
|
||||
* @param[in] rc Restconf connection, more specifically: callhome connection
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
*
|
||||
* t0 tp t1 tn
|
||||
* |---------|-----------|--------------------|
|
||||
|
|
@ -1509,7 +1529,7 @@ restconf_idle_cb(int fd,
|
|||
clicon_err(OE_YANG, EINVAL, "rsock is NULL");
|
||||
goto done;
|
||||
}
|
||||
clicon_debug(1, "%s \"%s\"", __FUNCTION__, rsock->rs_description);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s \"%s\"", __FUNCTION__, rsock->rs_description);
|
||||
if (rc->rc_callhome && rsock->rs_periodic && rc->rc_s > 0 && rsock->rs_idle_timeout){
|
||||
gettimeofday(&now, NULL);
|
||||
timersub(&now, &rc->rc_t, &td); /* Last packet timestamp */
|
||||
|
|
@ -1520,7 +1540,7 @@ restconf_idle_cb(int fd,
|
|||
else{
|
||||
to.tv_sec = rsock->rs_idle_timeout;
|
||||
timeradd(&now, &to, &tn);
|
||||
clicon_debug(1, "%s now:%lu timeout:%lu.%lu", __FUNCTION__,
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s now:%lu timeout:%lu.%lu", __FUNCTION__,
|
||||
now.tv_sec, tn.tv_sec, tn.tv_usec);
|
||||
if (restconf_idle_timer_set(tn, rc, rsock->rs_description) < 0)
|
||||
goto done;
|
||||
|
|
@ -1538,6 +1558,7 @@ restconf_idle_timer_unreg(restconf_conn *rc)
|
|||
}
|
||||
|
||||
/*! Set callhome periodic idle-timeout
|
||||
*
|
||||
* 1) If callhome and periodic, set timer for t0+idle-timeout(ti)
|
||||
* 2) Timestamp any data passing on the socket(td)
|
||||
* 3) At timeout (ti) check if ti = td+idle-timeout (for first timeout same as t0=td),
|
||||
|
|
@ -1559,13 +1580,13 @@ restconf_idle_timer(restconf_conn *rc)
|
|||
if (rc == NULL || !rc->rc_callhome){
|
||||
clicon_err(OE_RESTCONF, EINVAL, "rc is NULL or not callhome");
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
rsock = rc->rc_socket;
|
||||
if (rsock == NULL || !rsock->rs_periodic || rsock->rs_idle_timeout==0){
|
||||
clicon_err(OE_YANG, EINVAL, "rsock is NULL or not periodic");
|
||||
goto done;
|
||||
}
|
||||
clicon_debug(1, "%s \"%s\" register", __FUNCTION__, rsock->rs_description);
|
||||
}
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s \"%s\" register", __FUNCTION__, rsock->rs_description);
|
||||
gettimeofday(&now, NULL);
|
||||
to.tv_sec = rsock->rs_idle_timeout;
|
||||
timeradd(&now, &to, &t);
|
||||
|
|
@ -1603,7 +1624,7 @@ restconf_callhome_cb(int fd,
|
|||
clicon_err(OE_YANG, EINVAL, "rsock is NULL");
|
||||
goto done;
|
||||
}
|
||||
clicon_debug(1, "%s \"%s\"", __FUNCTION__, rsock->rs_description);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s \"%s\"", __FUNCTION__, rsock->rs_description);
|
||||
h = rsock->rs_h;
|
||||
/* Already computed in restconf_socket_init, could be saved in rsock? */
|
||||
if (clixon_inet2sin(rsock->rs_addrtype, rsock->rs_addrstr, rsock->rs_port, sa, &sa_len) < 0)
|
||||
|
|
@ -1613,7 +1634,7 @@ restconf_callhome_cb(int fd,
|
|||
goto done;
|
||||
}
|
||||
if (connect(s, sa, sa_len) < 0){
|
||||
clicon_debug(1, "%s connect %hu fail:%d %s", __FUNCTION__, rsock->rs_port, errno, strerror(errno));
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s connect %hu fail:%d %s", __FUNCTION__, rsock->rs_port, errno, strerror(errno));
|
||||
close(s);
|
||||
rsock->rs_attempts++;
|
||||
/* Fail: Initiate new timer */
|
||||
|
|
@ -1621,7 +1642,7 @@ restconf_callhome_cb(int fd,
|
|||
goto done;
|
||||
}
|
||||
else {
|
||||
clicon_debug(1, "%s connect %hu OK", __FUNCTION__, rsock->rs_port);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s connect %hu OK", __FUNCTION__, rsock->rs_port);
|
||||
rsock->rs_attempts = 0;
|
||||
if ((ret = restconf_ssl_accept_client(h, s, rsock, &rc)) < 0)
|
||||
goto done;
|
||||
|
|
@ -1648,6 +1669,8 @@ restconf_callhome_timer_unreg(restconf_socket *rsock)
|
|||
* NYI: start-with, anchor-time
|
||||
* @param[in] rsock restconf_socket
|
||||
* @param[in] new if periodic: 1: Force a new period
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
* @see restconf_callhome_timer_unreg
|
||||
*/
|
||||
int
|
||||
|
|
@ -1659,12 +1682,12 @@ restconf_callhome_timer(restconf_socket *rsock,
|
|||
struct timeval t;
|
||||
struct timeval t1 = {0, 0};
|
||||
cbuf *cb = NULL;
|
||||
|
||||
|
||||
if (rsock == NULL || !rsock->rs_callhome){
|
||||
clicon_err(OE_YANG, EINVAL, "rsock is NULL or not callhome");
|
||||
goto done;
|
||||
}
|
||||
clicon_debug(1, "%s \"%s\"", __FUNCTION__, rsock->rs_description);
|
||||
}
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s \"%s\"", __FUNCTION__, rsock->rs_description);
|
||||
if (!rsock->rs_callhome)
|
||||
goto ok; /* shouldnt happen */
|
||||
gettimeofday(&now, NULL);
|
||||
|
|
@ -1692,9 +1715,9 @@ restconf_callhome_timer(restconf_socket *rsock,
|
|||
}
|
||||
cprintf(cb, "restconf callhome timer %s", rsock->rs_description);
|
||||
if (rsock->rs_description)
|
||||
clicon_debug(1, "%s registering \"%s\": +%lu", __FUNCTION__, rsock->rs_description, t.tv_sec-now.tv_sec);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s registering \"%s\": +%lu", __FUNCTION__, rsock->rs_description, t.tv_sec-now.tv_sec);
|
||||
else
|
||||
clicon_debug(1, "%s: %lu", __FUNCTION__, t.tv_sec);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s: %lu", __FUNCTION__, t.tv_sec);
|
||||
/* Should be only place restconf_callhome_cb is registered */
|
||||
if (clixon_event_reg_timeout(t,
|
||||
restconf_callhome_cb,
|
||||
|
|
@ -1710,7 +1733,8 @@ restconf_callhome_timer(restconf_socket *rsock,
|
|||
}
|
||||
|
||||
/*! Extract socket info from backend config
|
||||
* @param[in] h Clicon handle
|
||||
*
|
||||
* @param[in] h Clixon handle
|
||||
* @param[in] xs socket config
|
||||
* @param[in] nsc Namespace context
|
||||
* @param[out] rsock restconf socket data, filled in with many fields
|
||||
|
|
@ -1718,6 +1742,8 @@ restconf_callhome_timer(restconf_socket *rsock,
|
|||
* @param[out] address Address as string, eg "0.0.0.0", "::"
|
||||
* @param[out] addrtype One of inet:ipv4-address or inet:ipv6-address
|
||||
* @param[out] port TCP Port
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
*/
|
||||
int
|
||||
restconf_socket_extract(clicon_handle h,
|
||||
|
|
@ -1789,7 +1815,7 @@ restconf_socket_extract(clicon_handle h,
|
|||
* type inet:ipv6-address; <---
|
||||
* }
|
||||
*/
|
||||
*addrtype = yang_argument_get(ysub);
|
||||
*addrtype = yang_argument_get(ysub);
|
||||
if ((x = xpath_first(xs, nsc, "port")) != NULL &&
|
||||
(str = xml_body(x)) != NULL){
|
||||
if ((ret = parse_uint16(str, port, &reason)) < 0){
|
||||
|
|
@ -1820,7 +1846,7 @@ restconf_socket_extract(clicon_handle h,
|
|||
}
|
||||
else if (xpath_first(xs, nsc, "call-home/connection-type/periodic") != NULL){
|
||||
rsock->rs_periodic = 1;
|
||||
if ((x = xpath_first(xs, nsc, "call-home/connection-type/periodic/period")) != NULL &&
|
||||
if ((x = xpath_first(xs, nsc, "call-home/connection-type/periodic/period")) != NULL &&
|
||||
(str = xml_body(x)) != NULL){
|
||||
if ((ret = parse_uint32(str, &rsock->rs_period, &reason)) < 0){
|
||||
clicon_err(OE_XML, errno, "parse_uint16");
|
||||
|
|
@ -1829,9 +1855,9 @@ restconf_socket_extract(clicon_handle h,
|
|||
if (ret == 0){
|
||||
clicon_err(OE_XML, EINVAL, "Unrecognized value of period: %s", str);
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((x = xpath_first(xs, nsc, "call-home/connection-type/periodic/idle-timeout")) != NULL &&
|
||||
if ((x = xpath_first(xs, nsc, "call-home/connection-type/periodic/idle-timeout")) != NULL &&
|
||||
(str = xml_body(x)) != NULL){
|
||||
if ((ret = parse_uint16(str, &rsock->rs_idle_timeout, &reason)) < 0){
|
||||
clicon_err(OE_XML, errno, "parse_uint16");
|
||||
|
|
@ -1840,10 +1866,10 @@ restconf_socket_extract(clicon_handle h,
|
|||
if (ret == 0){
|
||||
clicon_err(OE_XML, EINVAL, "Unrecognized value of idle-timeout: %s", str);
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((x = xpath_first(xs, nsc, "call-home/reconnect-strategy/max-attempts")) != NULL &&
|
||||
if ((x = xpath_first(xs, nsc, "call-home/reconnect-strategy/max-attempts")) != NULL &&
|
||||
(str = xml_body(x)) != NULL){
|
||||
if ((ret = parse_uint8(str, &rsock->rs_max_attempts, &reason)) < 0){
|
||||
clicon_err(OE_XML, errno, "parse_uint8");
|
||||
|
|
@ -1852,7 +1878,7 @@ restconf_socket_extract(clicon_handle h,
|
|||
if (ret == 0){
|
||||
clicon_err(OE_XML, EINVAL, "Unrecognized value of max-attempts: %s", str);
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
retval = 0;
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ extern "C" {
|
|||
/*
|
||||
* Types
|
||||
*/
|
||||
|
||||
|
||||
/* Forward */
|
||||
struct restconf_conn;
|
||||
|
||||
|
|
@ -95,13 +95,13 @@ typedef struct {
|
|||
} restconf_stream_data;
|
||||
|
||||
typedef struct restconf_socket restconf_socket;
|
||||
|
||||
|
||||
/* Restconf connection handle
|
||||
* Per connection request
|
||||
*/
|
||||
typedef struct restconf_conn {
|
||||
qelem_t rc_qelem; /* List header */
|
||||
/* XXX rc_proto and rc_proto_d1/d2 may not both be necessary.
|
||||
/* XXX rc_proto and rc_proto_d1/d2 may not both be necessary.
|
||||
* remove rc_proto?
|
||||
*/
|
||||
int rc_callhome; /* 0: listen, 1: callhome */
|
||||
|
|
@ -188,7 +188,7 @@ int restconf_callhome_timer_unreg(restconf_socket *rsock);
|
|||
int restconf_callhome_timer(restconf_socket *rsock, int status);
|
||||
int restconf_socket_extract(clicon_handle h, cxobj *xs, cvec *nsc, restconf_socket *rsock,
|
||||
char **namespace, char **address, char **addrtype, uint16_t *port);
|
||||
|
||||
|
||||
#endif /* _RESTCONF_NATIVE_H_ */
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
|
|||
|
|
@ -92,7 +92,8 @@
|
|||
#define ARRLEN(x) (sizeof(x) / sizeof(x[0]))
|
||||
|
||||
/*! Map http2 frame types in nghttp2
|
||||
* I had expected it in in libnghttp2 but havent found it
|
||||
*
|
||||
* Had expected it in in libnghttp2 but havent found it
|
||||
*/
|
||||
static const map_str2int nghttp2_frame_type_map[] = {
|
||||
{"DATA", NGHTTP2_DATA},
|
||||
|
|
@ -119,7 +120,7 @@ clixon_nghttp2_log_cb(void *handle,
|
|||
int suberr,
|
||||
cbuf *cb)
|
||||
{
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
|
||||
cprintf(cb, "Fatal error: %s", nghttp2_strerror(suberr));
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -131,24 +132,28 @@ nghttp2_print_header(const uint8_t *name,
|
|||
const uint8_t *value,
|
||||
size_t valuelen)
|
||||
{
|
||||
clicon_debug(1, "%s %s", name, value);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s %s", name, value);
|
||||
}
|
||||
|
||||
/* Print HTTP headers to |f|. Please note that this function does not
|
||||
take into account that header name and value are sequence of
|
||||
octets, therefore they may contain non-printable characters. */
|
||||
/*! Print HTTP headers to |f|.
|
||||
*
|
||||
* Please note that this function does not
|
||||
* take into account that header name and value are sequence of
|
||||
* octets, therefore they may contain non-printable characters.
|
||||
*/
|
||||
static void
|
||||
nghttp2_print_headers(nghttp2_nv *nva,
|
||||
size_t nvlen)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < nvlen; ++i)
|
||||
for (i = 0; i < nvlen; ++i)
|
||||
nghttp2_print_header(nva[i].name, nva[i].namelen, nva[i].value, nva[i].valuelen);
|
||||
}
|
||||
#endif /* NOTUSED */
|
||||
|
||||
/*! Send data to remote peer, Send at most the |length| bytes of |data|.
|
||||
*
|
||||
* This callback is required if the application uses
|
||||
* `nghttp2_session_send()` to send data to the remote endpoint. If
|
||||
* the application uses solely `nghttp2_session_mem_send()` instead,
|
||||
|
|
@ -172,21 +177,21 @@ session_send_callback(nghttp2_session *session,
|
|||
ssize_t totlen = 0;
|
||||
int s;
|
||||
int sslerr;
|
||||
|
||||
clicon_debug(1, "%s buflen:%zu", __FUNCTION__, buflen);
|
||||
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s buflen:%zu", __FUNCTION__, buflen);
|
||||
s = rc->rc_s;
|
||||
while (totlen < buflen){
|
||||
if (rc->rc_ssl){
|
||||
if ((len = SSL_write(rc->rc_ssl, buf+totlen, buflen-totlen)) <= 0){
|
||||
er = errno;
|
||||
sslerr = SSL_get_error(rc->rc_ssl, len);
|
||||
clicon_debug(1, "%s SSL_write: errno:%s(%d) sslerr:%d", __FUNCTION__,
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s SSL_write: errno:%s(%d) sslerr:%d", __FUNCTION__,
|
||||
strerror(er),
|
||||
er,
|
||||
sslerr);
|
||||
switch (sslerr){
|
||||
case SSL_ERROR_WANT_WRITE: /* 3 */
|
||||
clicon_debug(1, "%s write SSL_ERROR_WANT_WRITE", __FUNCTION__);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s write SSL_ERROR_WANT_WRITE", __FUNCTION__);
|
||||
usleep(1000);
|
||||
continue;
|
||||
break;
|
||||
|
|
@ -196,11 +201,11 @@ session_send_callback(nghttp2_session *session,
|
|||
goto done; /* Cleanup in http2_recv() */
|
||||
}
|
||||
else if (er == EAGAIN){
|
||||
/* same as want_write above, but different behaviour on different
|
||||
/* same as want_write above, but different behaviour on different
|
||||
* platforms, linux here, freebsd want_write, or possibly differnt
|
||||
* ssl lib versions?
|
||||
*/
|
||||
clicon_debug(1, "%s write EAGAIN", __FUNCTION__);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s write EAGAIN", __FUNCTION__);
|
||||
usleep(1000);
|
||||
continue;
|
||||
}
|
||||
|
|
@ -220,7 +225,7 @@ session_send_callback(nghttp2_session *session,
|
|||
else{
|
||||
if ((len = write(s, buf+totlen, buflen-totlen)) < 0){
|
||||
if (errno == EAGAIN){
|
||||
clicon_debug(1, "%s write EAGAIN", __FUNCTION__);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s write EAGAIN", __FUNCTION__);
|
||||
usleep(10000);
|
||||
continue;
|
||||
}
|
||||
|
|
@ -247,10 +252,10 @@ session_send_callback(nghttp2_session *session,
|
|||
retval = 0;
|
||||
done:
|
||||
if (retval < 0){
|
||||
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s retval:%d", __FUNCTION__, retval);
|
||||
return retval;
|
||||
}
|
||||
clicon_debug(1, "%s retval:%zd", __FUNCTION__, totlen);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s retval:%zd", __FUNCTION__, totlen);
|
||||
return retval == 0 ? totlen : retval;
|
||||
}
|
||||
|
||||
|
|
@ -264,7 +269,7 @@ recv_callback(nghttp2_session *session,
|
|||
void *user_data)
|
||||
{
|
||||
// restconf_conn *rc = (restconf_conn *)user_data;
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -288,8 +293,8 @@ restconf_nghttp2_path(restconf_stream_data *sd)
|
|||
char *oneline = NULL;
|
||||
cvec *cvv = NULL;
|
||||
char *cn;
|
||||
|
||||
clicon_debug(1, "------------");
|
||||
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "------------");
|
||||
rc = sd->sd_conn;
|
||||
if ((h = rc->rc_h) == NULL){
|
||||
clicon_err(OE_RESTCONF, EINVAL, "arg is NULL");
|
||||
|
|
@ -327,21 +332,21 @@ restconf_nghttp2_path(restconf_stream_data *sd)
|
|||
}
|
||||
else if (api_path_is_restconf(h)){
|
||||
if (api_root_restconf(h, sd, sd->sd_qvec) < 0)
|
||||
goto done;
|
||||
goto done;
|
||||
}
|
||||
else if (api_path_is_data(h)){
|
||||
if (api_http_data(h, sd, sd->sd_qvec) < 0)
|
||||
goto done;
|
||||
}
|
||||
else if (api_root_restconf(h, sd, sd->sd_qvec) < 0) /* error handling */
|
||||
goto done;
|
||||
goto done;
|
||||
}
|
||||
/* Clear (fcgi) paramaters from this request */
|
||||
if (restconf_param_del_all(h) < 0)
|
||||
goto done;
|
||||
retval = 0;
|
||||
done:
|
||||
clicon_debug(1, "%s %d", __FUNCTION__, retval);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s %d", __FUNCTION__, retval);
|
||||
if (cvv)
|
||||
cvec_free(cvv);
|
||||
if (oneline)
|
||||
|
|
@ -350,6 +355,7 @@ restconf_nghttp2_path(restconf_stream_data *sd)
|
|||
}
|
||||
|
||||
/*! data callback, just pass pointer to cbuf
|
||||
*
|
||||
* XXX handle several chunks with cbuf
|
||||
*/
|
||||
static ssize_t
|
||||
|
|
@ -384,7 +390,7 @@ restconf_sd_read(nghttp2_session *session,
|
|||
#endif
|
||||
assert(cbuf_len(cb) > sd->sd_body_offset);
|
||||
remain = cbuf_len(cb) - sd->sd_body_offset;
|
||||
clicon_debug(1, "%s length:%zu totlen:%zu, offset:%zu remain:%zu",
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s length:%zu totlen:%zu, offset:%zu remain:%zu",
|
||||
__FUNCTION__,
|
||||
length,
|
||||
cbuf_len(cb),
|
||||
|
|
@ -400,7 +406,7 @@ restconf_sd_read(nghttp2_session *session,
|
|||
}
|
||||
memcpy(buf, cbuf_get(cb) + sd->sd_body_offset, len);
|
||||
sd->sd_body_offset += len;
|
||||
clicon_debug(1, "%s retval:%zu", __FUNCTION__, len);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s retval:%zu", __FUNCTION__, len);
|
||||
return len;
|
||||
}
|
||||
|
||||
|
|
@ -428,7 +434,7 @@ restconf_submit_response(nghttp2_session *session,
|
|||
hdr = &hdrs[i++];
|
||||
hdr->name = (uint8_t*)":status";
|
||||
snprintf(valstr, 15, "%u", sd->sd_code);
|
||||
clicon_debug(1, "%s status %d", __FUNCTION__, sd->sd_code);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s status %d", __FUNCTION__, sd->sd_code);
|
||||
hdr->value = (uint8_t*)valstr;
|
||||
hdr->namelen = strlen(":status");
|
||||
hdr->valuelen = strlen(valstr);
|
||||
|
|
@ -438,7 +444,7 @@ restconf_submit_response(nghttp2_session *session,
|
|||
while ((cv = cvec_each(sd->sd_outp_hdrs, cv)) != NULL){
|
||||
hdr = &hdrs[i++];
|
||||
hdr->name = (uint8_t*)cv_name_get(cv);
|
||||
clicon_debug(1, "%s hdr: %s", __FUNCTION__, hdr->name);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s hdr: %s", __FUNCTION__, hdr->name);
|
||||
hdr->value = (uint8_t*)cv_string_get(cv);
|
||||
hdr->namelen = strlen(cv_name_get(cv));
|
||||
hdr->valuelen = strlen(cv_string_get(cv));
|
||||
|
|
@ -453,7 +459,7 @@ restconf_submit_response(nghttp2_session *session,
|
|||
}
|
||||
retval = 0;
|
||||
done:
|
||||
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s retval:%d", __FUNCTION__, retval);
|
||||
if (hdrs)
|
||||
free(hdrs);
|
||||
return retval;
|
||||
|
|
@ -469,7 +475,7 @@ http2_exec(restconf_conn *rc,
|
|||
{
|
||||
int retval = -1;
|
||||
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
|
||||
if (sd->sd_path){
|
||||
free(sd->sd_path);
|
||||
sd->sd_path = NULL;
|
||||
|
|
@ -498,7 +504,7 @@ http2_exec(restconf_conn *rc,
|
|||
*/
|
||||
if (sd->sd_code != 204 && sd->sd_code > 199 && sd->sd_body_len)
|
||||
if (restconf_reply_header(sd, "Content-Length", "%zu", sd->sd_body_len) < 0)
|
||||
goto done;
|
||||
goto done;
|
||||
if (sd->sd_code){
|
||||
if (restconf_submit_response(session, rc, stream_id, sd) < 0)
|
||||
goto done;
|
||||
|
|
@ -508,7 +514,7 @@ http2_exec(restconf_conn *rc,
|
|||
}
|
||||
retval = 0;
|
||||
done:
|
||||
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s retval:%d", __FUNCTION__, retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
|
@ -523,8 +529,8 @@ on_frame_recv_callback(nghttp2_session *session,
|
|||
restconf_conn *rc = (restconf_conn *)user_data;
|
||||
restconf_stream_data *sd = NULL;
|
||||
char *query;
|
||||
|
||||
clicon_debug(1, "%s %s %d", __FUNCTION__,
|
||||
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s %s %d", __FUNCTION__,
|
||||
clicon_int2str(nghttp2_frame_type_map, frame->hd.type),
|
||||
frame->hd.stream_id);
|
||||
switch (frame->hd.type) {
|
||||
|
|
@ -566,7 +572,7 @@ on_invalid_frame_recv_callback(nghttp2_session *session,
|
|||
void *user_data)
|
||||
{
|
||||
// restconf_conn *rc = (restconf_conn *)user_data;
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -588,9 +594,9 @@ on_data_chunk_recv_callback(nghttp2_session *session,
|
|||
restconf_conn *rc = (restconf_conn *)user_data;
|
||||
restconf_stream_data *sd;
|
||||
|
||||
clicon_debug(1, "%s %d", __FUNCTION__, stream_id);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s %d", __FUNCTION__, stream_id);
|
||||
if ((sd = restconf_stream_find(rc, stream_id)) != NULL){
|
||||
cbuf_append_buf(sd->sd_indata, (void*)data, len);
|
||||
cbuf_append_buf(sd->sd_indata, (void*)data, len);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -603,7 +609,7 @@ before_frame_send_callback(nghttp2_session *session,
|
|||
void *user_data)
|
||||
{
|
||||
// restconf_conn *rc = (restconf_conn *)user_data;
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -615,7 +621,7 @@ on_frame_send_callback(nghttp2_session *session,
|
|||
void *user_data)
|
||||
{
|
||||
// restconf_conn *rc = (restconf_conn *)user_data;
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -628,7 +634,7 @@ on_frame_not_send_callback(nghttp2_session *session,
|
|||
void *user_data)
|
||||
{
|
||||
// restconf_conn *rc = (restconf_conn *)user_data;
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -642,7 +648,7 @@ on_stream_close_callback(nghttp2_session *session,
|
|||
{
|
||||
// restconf_conn *rc = (restconf_conn *)user_data;
|
||||
|
||||
clicon_debug(1, "%s %d %s", __FUNCTION__, error_code, nghttp2_strerror(error_code));
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s %d %s", __FUNCTION__, error_code, nghttp2_strerror(error_code));
|
||||
#if 0 // NOTNEEDED /* XXX think this is not necessary? */
|
||||
if (error_code){
|
||||
if (restconf_close_ssl_socket(rc, __FUNCTION__, 0) < 0)
|
||||
|
|
@ -662,7 +668,7 @@ on_begin_headers_callback(nghttp2_session *session,
|
|||
restconf_conn *rc = (restconf_conn *)user_data;
|
||||
restconf_stream_data *sd;
|
||||
|
||||
clicon_debug(1, "%s %s", __FUNCTION__, clicon_int2str(nghttp2_frame_type_map, frame->hd.type));
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s %s", __FUNCTION__, clicon_int2str(nghttp2_frame_type_map, frame->hd.type));
|
||||
if (frame->hd.type == NGHTTP2_HEADERS &&
|
||||
frame->headers.cat == NGHTTP2_HCAT_REQUEST) {
|
||||
sd = restconf_stream_data_new(rc, frame->hd.stream_id);
|
||||
|
|
@ -672,6 +678,7 @@ on_begin_headers_callback(nghttp2_session *session,
|
|||
}
|
||||
|
||||
/*! Map from nghttp2 headers to "fcgi" type parameters used in clixon code
|
||||
*
|
||||
* Both |name| and |value| are guaranteed to be NULL-terminated.
|
||||
*/
|
||||
static int
|
||||
|
|
@ -683,7 +690,7 @@ nghttp2_hdr2clixon(clicon_handle h,
|
|||
|
||||
if (strcmp(name, ":path") == 0){
|
||||
/* Including ?args, call restconf_uripath() to get only path */
|
||||
if (restconf_param_set(h, "REQUEST_URI", value) < 0)
|
||||
if (restconf_param_set(h, "REQUEST_URI", value) < 0)
|
||||
goto done;
|
||||
}
|
||||
else if (strcmp(name, ":method") == 0){
|
||||
|
|
@ -707,6 +714,7 @@ nghttp2_hdr2clixon(clicon_handle h,
|
|||
}
|
||||
|
||||
/*! Header name/value pair is received
|
||||
*
|
||||
* Both |name| and |value| are guaranteed to be NULL-terminated.
|
||||
* If the application uses `nghttp2_session_mem_recv()`, it can return
|
||||
* :enum:`NGHTTP2_ERR_PAUSE` to make `nghttp2_session_mem_recv()`
|
||||
|
|
@ -728,12 +736,12 @@ on_header_callback(nghttp2_session *session,
|
|||
switch (frame->hd.type){
|
||||
case NGHTTP2_HEADERS:
|
||||
assert (frame->headers.cat == NGHTTP2_HCAT_REQUEST);
|
||||
clicon_debug(1, "%s HEADERS %s %s", __FUNCTION__, name, value);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s HEADERS %s %s", __FUNCTION__, name, value);
|
||||
if (nghttp2_hdr2clixon(rc->rc_h, (char*)name, (char*)value) < 0)
|
||||
goto done;
|
||||
break;
|
||||
default:
|
||||
clicon_debug(1, "%s %s %s", __FUNCTION__, clicon_int2str(nghttp2_frame_type_map, frame->hd.type), name);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s %s %s", __FUNCTION__, clicon_int2str(nghttp2_frame_type_map, frame->hd.type), name);
|
||||
break;
|
||||
}
|
||||
retval = 0;
|
||||
|
|
@ -751,7 +759,7 @@ select_padding_callback(nghttp2_session *session,
|
|||
void *user_data)
|
||||
{
|
||||
// restconf_conn *rc = (restconf_conn *)user_data;
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
|
||||
return frame->hd.length;
|
||||
}
|
||||
|
||||
|
|
@ -767,12 +775,13 @@ data_source_read_length_callback(nghttp2_session *session,
|
|||
void *user_data)
|
||||
{
|
||||
// restconf_conn *rc = (restconf_conn *)user_data;
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
|
||||
return 0;
|
||||
}
|
||||
#endif /* NOTUSED */
|
||||
|
||||
/*! Invoked when a frame header is received.
|
||||
*
|
||||
* Unlike :type:`nghttp2_on_frame_recv_callback`, this callback will
|
||||
* also be called when frame header of CONTINUATION frame is received.
|
||||
*/
|
||||
|
|
@ -782,13 +791,14 @@ on_begin_frame_callback(nghttp2_session *session,
|
|||
void *user_data)
|
||||
{
|
||||
// restconf_conn *rc = (restconf_conn *)user_data;
|
||||
clicon_debug(1, "%s %s", __FUNCTION__, clicon_int2str(nghttp2_frame_type_map, hd->type));
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s %s", __FUNCTION__, clicon_int2str(nghttp2_frame_type_map, hd->type));
|
||||
if (hd->type == NGHTTP2_CONTINUATION)
|
||||
assert(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! Send complete DATA frame for no-copy
|
||||
*
|
||||
* Callback function invoked when :enum:`NGHTTP2_DATA_FLAG_NO_COPY` is
|
||||
* used in :type:`nghttp2_data_source_read_callback` to send complete
|
||||
* DATA frame.
|
||||
|
|
@ -801,7 +811,7 @@ send_data_callback(nghttp2_session *session,
|
|||
void *user_data)
|
||||
{
|
||||
// restconf_conn *rc = (restconf_conn *)user_data;
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -815,7 +825,7 @@ pack_extension_callback(nghttp2_session *session,
|
|||
void *user_data)
|
||||
{
|
||||
// restconf_conn *rc = (restconf_conn *)user_data;
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -828,7 +838,7 @@ unpack_extension_callback(nghttp2_session *session,
|
|||
void *user_data)
|
||||
{
|
||||
// restconf_conn *rc = (restconf_conn *)user_data;
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
|
||||
return 0;
|
||||
}
|
||||
#endif /* NOTUSED */
|
||||
|
|
@ -843,7 +853,7 @@ on_extension_chunk_recv_callback(nghttp2_session *session,
|
|||
void *user_data)
|
||||
{
|
||||
// restconf_conn *rc = (restconf_conn *)user_data;
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -856,7 +866,7 @@ error_callback(nghttp2_session *session,
|
|||
void *user_data)
|
||||
{
|
||||
// restconf_conn *rc = (restconf_conn *)user_data;
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -871,7 +881,7 @@ error_callback2(nghttp2_session *session,
|
|||
void *user_data)
|
||||
{
|
||||
// restconf_conn *rc = (restconf_conn *)user_data;
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
|
||||
clicon_err(OE_NGHTTP2, lib_error_code, "%s", msg);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -893,11 +903,11 @@ http2_recv(restconf_conn *rc,
|
|||
{
|
||||
int retval = -1;
|
||||
nghttp2_error ngerr;
|
||||
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
|
||||
if (rc->rc_ngsession == NULL){
|
||||
/* http2_session_init not called */
|
||||
clicon_err(OE_RESTCONF, EINVAL, "No nghttp2 session");
|
||||
clicon_err(OE_RESTCONF, EINVAL, "No nghttp2 session");
|
||||
goto done;
|
||||
}
|
||||
/* may make additional pending frames */
|
||||
|
|
@ -924,14 +934,14 @@ http2_recv(restconf_conn *rc,
|
|||
*/
|
||||
clicon_err_reset();
|
||||
if ((ngerr = nghttp2_session_send(rc->rc_ngsession)) != 0){
|
||||
if (clicon_errno)
|
||||
if (clicon_errno)
|
||||
goto done;
|
||||
else
|
||||
goto fail; /* Not fatal error */
|
||||
}
|
||||
retval = 1; /* OK */
|
||||
done:
|
||||
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s retval:%d", __FUNCTION__, retval);
|
||||
return retval;
|
||||
fail:
|
||||
retval = 0;
|
||||
|
|
@ -948,7 +958,7 @@ http2_send_server_connection(restconf_conn *rc)
|
|||
,{NGHTTP2_SETTINGS_ENABLE_PUSH, 0}};
|
||||
nghttp2_error ngerr;
|
||||
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
|
||||
if ((ngerr = nghttp2_submit_settings(rc->rc_ngsession,
|
||||
NGHTTP2_FLAG_NONE,
|
||||
iv,
|
||||
|
|
@ -962,7 +972,7 @@ http2_send_server_connection(restconf_conn *rc)
|
|||
}
|
||||
retval = 0;
|
||||
done:
|
||||
clicon_debug(1, "%s %d", __FUNCTION__, retval);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s %d", __FUNCTION__, retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -98,8 +98,11 @@ api_path_is_restconf(clicon_handle h)
|
|||
}
|
||||
|
||||
/*! Determine the root of the RESTCONF API by accessing /.well-known
|
||||
* @param[in] h Clicon handle
|
||||
* @param[in] req Generic Www handle (can be part of clixon handle)
|
||||
*
|
||||
* @param[in] h Clixon handle
|
||||
* @param[in] req Generic Www handle (can be part of clixon handle)
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
* @see RFC8040 3.1 and RFC7320
|
||||
* In line with the best practices defined by [RFC7320], RESTCONF
|
||||
* enables deployments to specify where the RESTCONF API is located.
|
||||
|
|
@ -113,7 +116,7 @@ api_well_known(clicon_handle h,
|
|||
cbuf *cb = NULL;
|
||||
int head;
|
||||
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
|
||||
if (req == NULL){
|
||||
errno = EINVAL;
|
||||
goto done;
|
||||
|
|
@ -150,12 +153,14 @@ api_well_known(clicon_handle h,
|
|||
}
|
||||
|
||||
/*! Retrieve the Top-Level API Resource /restconf/ (exact)
|
||||
* @param[in] h Clicon handle
|
||||
*
|
||||
* @param[in] h Clixon handle
|
||||
* @param[in] req Generic request handle
|
||||
* @param[in] method Http method
|
||||
* @param[in] pretty Pretty print
|
||||
* @param[in] media_out Restconf output media
|
||||
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
* @note Only returns null for operations and data,...
|
||||
* See RFC8040 3.3
|
||||
* @see api_root_restconf for accessing /restconf/ *
|
||||
|
|
@ -174,7 +179,7 @@ api_root_restconf_exact(clicon_handle h,
|
|||
cbuf *cb = NULL;
|
||||
int head;
|
||||
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
|
||||
head = strcmp(request_method, "HEAD") == 0;
|
||||
if (!head && strcmp(request_method, "GET") != 0){
|
||||
if (restconf_method_notallowed(h, req, "GET", pretty, media_out) < 0)
|
||||
|
|
@ -208,7 +213,7 @@ api_root_restconf_exact(clicon_handle h,
|
|||
goto done;
|
||||
break;
|
||||
case YANG_DATA_JSON:
|
||||
case YANG_PATCH_JSON:
|
||||
case YANG_PATCH_JSON:
|
||||
if (clixon_json2cbuf(cb, xt, pretty, 0, 0) < 0)
|
||||
goto done;
|
||||
break;
|
||||
|
|
@ -230,7 +235,7 @@ api_root_restconf_exact(clicon_handle h,
|
|||
|
||||
/** A stub implementation of the operational state datastore. The full
|
||||
* implementation is required by https://tools.ietf.org/html/rfc8527#section-3.1
|
||||
* @param[in] h Clicon handle
|
||||
* @param[in] h Clixon handle
|
||||
* @param[in] req Generic http handle
|
||||
* @param[in] pretty Pretty-print
|
||||
* @param[in] media_out Restconf output media
|
||||
|
|
@ -243,31 +248,33 @@ api_operational_state(clicon_handle h,
|
|||
restconf_media media_out)
|
||||
|
||||
{
|
||||
clicon_debug(1, "%s request method:%s", __FUNCTION__, request_method);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s request method:%s", __FUNCTION__, request_method);
|
||||
|
||||
/* We are not implementing this method at this time, 20201105 despite it
|
||||
* being mandatory https://tools.ietf.org/html/rfc8527#section-3.1 */
|
||||
return restconf_notimplemented(h, req, pretty, media_out);
|
||||
}
|
||||
|
||||
/*!
|
||||
/*! get yang lib version
|
||||
*
|
||||
* See https://tools.ietf.org/html/rfc7895
|
||||
* @param[in] pretty Pretty-print
|
||||
* @param[in] media_out Restconf output media
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
*/
|
||||
static int
|
||||
api_yang_library_version(clicon_handle h,
|
||||
void *req,
|
||||
int pretty,
|
||||
restconf_media media_out)
|
||||
|
||||
{
|
||||
int retval = -1;
|
||||
cxobj *xt = NULL;
|
||||
cbuf *cb = NULL;
|
||||
yang_stmt *yspec;
|
||||
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
|
||||
if (restconf_reply_header(req, "Content-Type", "%s", restconf_media_int2str(media_out)) < 0)
|
||||
goto done;
|
||||
if (restconf_reply_header(req, "Cache-Control", "no-cache") < 0)
|
||||
|
|
@ -312,6 +319,7 @@ api_yang_library_version(clicon_handle h,
|
|||
}
|
||||
|
||||
/*! Generic REST method, GET, PUT, DELETE, etc
|
||||
*
|
||||
* @param[in] h CLIXON handle
|
||||
* @param[in] r Fastcgi request handle
|
||||
* @param[in] api_path According to restconf (Sec 3.5.1.1 in [draft])
|
||||
|
|
@ -320,15 +328,17 @@ api_yang_library_version(clicon_handle h,
|
|||
* @param[in] qvec Vector of query string (QUERY_STRING)
|
||||
* @param[in] pretty Set to 1 for pretty-printed xml/json output
|
||||
* @param[in] media_out Restconf output media
|
||||
* @param[in] ds 0 if "data" resource, 1 if rfc8527 "ds" resource
|
||||
* @param[in] ds 0 if "data" resource, 1 if rfc8527 "ds" resource
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
*/
|
||||
static int
|
||||
api_data(clicon_handle h,
|
||||
void *req,
|
||||
char *api_path,
|
||||
cvec *pcvec,
|
||||
void *req,
|
||||
char *api_path,
|
||||
cvec *pcvec,
|
||||
int pi,
|
||||
cvec *qvec,
|
||||
cvec *qvec,
|
||||
char *data,
|
||||
int pretty,
|
||||
restconf_media media_out,
|
||||
|
|
@ -339,9 +349,9 @@ api_data(clicon_handle h,
|
|||
char *request_method;
|
||||
cxobj *xerr = NULL;
|
||||
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
|
||||
request_method = restconf_param_get(h, "REQUEST_METHOD");
|
||||
clicon_debug(1, "%s method:%s", __FUNCTION__, request_method);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s method:%s", __FUNCTION__, request_method);
|
||||
|
||||
/* https://tools.ietf.org/html/rfc8527#section-3.2 */
|
||||
/* We assume that dynamic datastores are read only at this time 20201105 */
|
||||
|
|
@ -355,7 +365,7 @@ api_data(clicon_handle h,
|
|||
if (strcmp(request_method, "OPTIONS")==0)
|
||||
retval = api_data_options(h, req);
|
||||
else if (strcmp(request_method, "HEAD")==0) {
|
||||
if (dynamic)
|
||||
if (dynamic)
|
||||
retval = restconf_method_notallowed(h, req, "GET,POST", pretty, media_out);
|
||||
else
|
||||
retval = api_data_head(h, req, api_path, pi, qvec, pretty, media_out, ds);
|
||||
|
|
@ -367,7 +377,7 @@ api_data(clicon_handle h,
|
|||
retval = api_data_post(h, req, api_path, pi, qvec, data, pretty, restconf_content_type(h), media_out, ds);
|
||||
}
|
||||
else if (strcmp(request_method, "PUT")==0) {
|
||||
if (read_only)
|
||||
if (read_only)
|
||||
retval = restconf_method_notallowed(h, req, "GET,POST", pretty, media_out);
|
||||
else
|
||||
retval = api_data_put(h, req, api_path, pi, qvec, data, pretty, media_out, ds);
|
||||
|
|
@ -379,17 +389,17 @@ api_data(clicon_handle h,
|
|||
retval = api_data_patch(h, req, api_path, pi, qvec, data, pretty, media_out, ds);
|
||||
}
|
||||
else if (strcmp(request_method, "DELETE")==0) {
|
||||
if (read_only)
|
||||
if (read_only)
|
||||
retval = restconf_method_notallowed(h, req, "GET,POST", pretty, media_out);
|
||||
else
|
||||
retval = api_data_delete(h, req, api_path, pi, pretty, media_out, ds);
|
||||
}
|
||||
else{
|
||||
if (netconf_invalid_value_xml(&xerr, "protocol", "Invalid HTTP data method") < 0)
|
||||
goto done;
|
||||
goto done;
|
||||
retval = api_return_err0(h, req, xerr, pretty, media_out, 0);
|
||||
}
|
||||
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s retval:%d", __FUNCTION__, retval);
|
||||
done:
|
||||
if (xerr)
|
||||
xml_free(xerr);
|
||||
|
|
@ -397,6 +407,7 @@ api_data(clicon_handle h,
|
|||
}
|
||||
|
||||
/*! Operations REST method, POST
|
||||
*
|
||||
* @param[in] h CLIXON handle
|
||||
* @param[in] req Generic Www handle (can be part of clixon handle)
|
||||
* @param[in] request_method eg GET,...
|
||||
|
|
@ -406,15 +417,17 @@ api_data(clicon_handle h,
|
|||
* @param[in] qvec Vector of query string (QUERY_STRING)
|
||||
* @param[in] data Stream input data
|
||||
* @param[in] media_out Output media
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
*/
|
||||
static int
|
||||
api_operations(clicon_handle h,
|
||||
void *req,
|
||||
void *req,
|
||||
char *request_method,
|
||||
char *path,
|
||||
cvec *pcvec,
|
||||
cvec *pcvec,
|
||||
int pi,
|
||||
cvec *qvec,
|
||||
cvec *qvec,
|
||||
char *data,
|
||||
int pretty,
|
||||
restconf_media media_out)
|
||||
|
|
@ -422,7 +435,7 @@ api_operations(clicon_handle h,
|
|||
int retval = -1;
|
||||
cxobj *xerr = NULL;
|
||||
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
|
||||
if (strcmp(request_method, "GET")==0)
|
||||
retval = api_operations_get(h, req, path, pi, qvec, data, pretty, media_out);
|
||||
else if (strcmp(request_method, "POST")==0)
|
||||
|
|
@ -430,7 +443,7 @@ api_operations(clicon_handle h,
|
|||
pretty, media_out);
|
||||
else{
|
||||
if (netconf_invalid_value_xml(&xerr, "protocol", "Invalid HTTP operations method") < 0)
|
||||
goto done;
|
||||
goto done;
|
||||
retval = api_return_err0(h, req, xerr, pretty, media_out, 0);
|
||||
}
|
||||
done:
|
||||
|
|
@ -440,9 +453,12 @@ api_operations(clicon_handle h,
|
|||
}
|
||||
|
||||
/*! Process a /restconf root input, this is the root of the restconf processing
|
||||
* @param[in] h Clicon handle
|
||||
* @param[in] req Generic Www handle (can be part of clixon handle)
|
||||
* @param[in] qvec Query parameters, ie the ?<id>=<val>&<id>=<val> stuff
|
||||
*
|
||||
* @param[in] h Clixon handle
|
||||
* @param[in] req Generic Www handle (can be part of clixon handle)
|
||||
* @param[in] qvec Query parameters, ie the ?<id>=<val>&<id>=<val> stuff
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
* @see api_root_restconf_exact for accessing /restconf/ exact
|
||||
*/
|
||||
int
|
||||
|
|
@ -466,7 +482,7 @@ api_root_restconf(clicon_handle h,
|
|||
int ret;
|
||||
cxobj *xerr = NULL;
|
||||
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
|
||||
if (req == NULL){
|
||||
errno = EINVAL;
|
||||
goto done;
|
||||
|
|
@ -476,7 +492,7 @@ api_root_restconf(clicon_handle h,
|
|||
goto done;
|
||||
pretty = restconf_pretty_get(h);
|
||||
/* Get media for output (proactive negotiation) RFC7231 by using
|
||||
* Accept:. This is for methods that have output, such as GET,
|
||||
* Accept:. This is for methods that have output, such as GET,
|
||||
* operation POST, etc
|
||||
* If accept is * default is yang-json
|
||||
*/
|
||||
|
|
@ -496,7 +512,7 @@ api_root_restconf(clicon_handle h,
|
|||
goto ok;
|
||||
}
|
||||
}
|
||||
clicon_debug(1, "%s ACCEPT: %s %s", __FUNCTION__, media_str, restconf_media_int2str(media_out));
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s ACCEPT: %s %s", __FUNCTION__, media_str, restconf_media_int2str(media_out));
|
||||
|
||||
if ((pvec = clicon_strsep(path, "/", &pn)) == NULL)
|
||||
goto done;
|
||||
|
|
@ -504,14 +520,14 @@ api_root_restconf(clicon_handle h,
|
|||
/* Sanity check of path. Should be /restconf/ */
|
||||
if (pn < 2){
|
||||
if (netconf_invalid_value_xml(&xerr, "protocol", "Invalid path, /restconf/ expected") < 0)
|
||||
goto done;
|
||||
goto done;
|
||||
if (api_return_err0(h, req, xerr, pretty, media_out, 0) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
if (strlen(pvec[0]) != 0){
|
||||
if (netconf_invalid_value_xml(&xerr, "protocol", "Invalid path, restconf api root expected") < 0)
|
||||
goto done;
|
||||
goto done;
|
||||
if (api_return_err0(h, req, xerr, pretty, media_out, 0) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
|
|
@ -522,19 +538,19 @@ api_root_restconf(clicon_handle h,
|
|||
}
|
||||
if ((api_resource = pvec[2]) == NULL){
|
||||
if (netconf_invalid_value_xml(&xerr, "protocol", "Invalid path, /restconf/ expected") < 0)
|
||||
goto done;
|
||||
goto done;
|
||||
if (api_return_err0(h, req, xerr, pretty, media_out, 0) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
clicon_debug(1, "%s: api_resource=%s", __FUNCTION__, api_resource);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s: api_resource=%s", __FUNCTION__, api_resource);
|
||||
if (uri_str2cvec(path, '/', '=', 1, &pcvec) < 0) /* rest url eg /album=ricky/foo */
|
||||
goto done;
|
||||
/* data */
|
||||
if ((cb = restconf_get_indata(req)) == NULL) /* XXX NYI ACTUALLY not always needed, do this later? */
|
||||
goto done;
|
||||
indata = cbuf_get(cb);
|
||||
clicon_debug(1, "%s DATA=%s", __FUNCTION__, indata);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s DATA=%s", __FUNCTION__, indata);
|
||||
|
||||
/* If present, check credentials. See "plugin_credentials" in plugin
|
||||
* retvals:
|
||||
|
|
@ -564,7 +580,7 @@ api_root_restconf(clicon_handle h,
|
|||
|
||||
if (4 > pn) { /* Malformed request, no "ietf-datastores:<datastore>" component */
|
||||
if (netconf_invalid_value_xml(&xerr, "protocol", "Invalid path, No ietf-datastores:<datastore> component") < 0)
|
||||
goto done;
|
||||
goto done;
|
||||
if (api_return_err0(h, req, xerr, pretty, media_out, 0) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
|
|
@ -587,7 +603,7 @@ api_root_restconf(clicon_handle h,
|
|||
}
|
||||
else { /* Malformed request, unsupported datastore type */
|
||||
if (netconf_invalid_value_xml(&xerr, "protocol", "Unsupported datastore type") < 0)
|
||||
goto done;
|
||||
goto done;
|
||||
if (api_return_err0(h, req, xerr, pretty, media_out, 0) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
|
|
@ -597,13 +613,13 @@ api_root_restconf(clicon_handle h,
|
|||
goto done;
|
||||
}
|
||||
else if (strcmp(api_resource, "operations") == 0){ /* rpc */
|
||||
if (api_operations(h, req, request_method, path, pcvec, 2, qvec, indata,
|
||||
if (api_operations(h, req, request_method, path, pcvec, 2, qvec, indata,
|
||||
pretty, media_out) < 0)
|
||||
goto done;
|
||||
}
|
||||
else{
|
||||
if (netconf_invalid_value_xml(&xerr, "protocol", "API-resource type") < 0)
|
||||
goto done;
|
||||
goto done;
|
||||
if (api_return_err0(h, req, xerr, pretty, media_out, 0) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
|
|
@ -611,7 +627,7 @@ api_root_restconf(clicon_handle h,
|
|||
ok:
|
||||
retval = 0;
|
||||
done:
|
||||
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s retval:%d", __FUNCTION__, retval);
|
||||
#ifdef WITH_RESTCONF_FCGI
|
||||
if (cb)
|
||||
cbuf_free(cb);
|
||||
|
|
|
|||
|
|
@ -116,12 +116,12 @@ struct stream_child{
|
|||
/* Linked list of children
|
||||
* @note could hang STREAM_CHILD list on clicon handle instead.
|
||||
*/
|
||||
static struct stream_child *STREAM_CHILD = NULL;
|
||||
static struct stream_child *STREAM_CHILD = NULL;
|
||||
|
||||
/*! Check if uri path denotes a stream/notification path
|
||||
*
|
||||
* @retval 0 No, not a stream path
|
||||
* @retval 1 Yes, a stream path
|
||||
* @retval 0 No, not a stream path
|
||||
*/
|
||||
int
|
||||
api_path_is_stream(clicon_handle h)
|
||||
|
|
@ -151,7 +151,7 @@ api_path_is_stream(clicon_handle h)
|
|||
/*! Find restconf child using PID and cleanup FCGI Request data
|
||||
*
|
||||
* For forked, called on SIGCHILD
|
||||
* @param[in] h Clicon handle
|
||||
* @param[in] h Clixon handle
|
||||
* @param[in] pid Process id of child
|
||||
* @note could hang STREAM_CHILD list on clicon handle instead.
|
||||
*/
|
||||
|
|
@ -160,7 +160,7 @@ stream_child_free(clicon_handle h,
|
|||
int pid)
|
||||
{
|
||||
struct stream_child *sc;
|
||||
|
||||
|
||||
if ((sc = STREAM_CHILD) != NULL){
|
||||
do {
|
||||
if (pid == sc->sc_pid){
|
||||
|
|
@ -177,6 +177,7 @@ stream_child_free(clicon_handle h,
|
|||
}
|
||||
|
||||
/*! Free all streams
|
||||
*
|
||||
* Typically called on restconf exit
|
||||
*/
|
||||
int
|
||||
|
|
@ -193,12 +194,15 @@ stream_child_freeall(clicon_handle h)
|
|||
}
|
||||
|
||||
/*! Callback when stream notifications arrive from backend
|
||||
*
|
||||
* @param[in] s Socket
|
||||
* @param[in] req Generic Www handle (can be part of clixon handle)
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
* @see netconf_notification_cb
|
||||
*/
|
||||
static int
|
||||
restconf_stream_cb(int s,
|
||||
restconf_stream_cb(int s,
|
||||
void *arg)
|
||||
{
|
||||
int retval = -1;
|
||||
|
|
@ -210,23 +214,23 @@ restconf_stream_cb(int s,
|
|||
cbuf *cb = NULL;
|
||||
int pretty = 0; /* XXX should be via arg */
|
||||
int ret;
|
||||
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
|
||||
/* get msg (this is the reason this function is called) */
|
||||
if (clicon_msg_rcv(s, NULL, 0, &reply, &eof) < 0){
|
||||
clicon_debug(1, "%s msg_rcv error", __FUNCTION__);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s msg_rcv error", __FUNCTION__);
|
||||
goto done;
|
||||
}
|
||||
clicon_debug(1, "%s msg: %s", __FUNCTION__, reply?reply->op_body:"null");
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s msg: %s", __FUNCTION__, reply?reply->op_body:"null");
|
||||
/* handle close from remote end: this will exit the client */
|
||||
if (eof){
|
||||
clicon_debug(1, "%s eof", __FUNCTION__);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s eof", __FUNCTION__);
|
||||
clicon_err(OE_PROTO, ESHUTDOWN, "Socket unexpected close");
|
||||
errno = ESHUTDOWN;
|
||||
FCGX_FPrintF(r->out, "SHUTDOWN\r\n");
|
||||
FCGX_FPrintF(r->out, "\r\n");
|
||||
FCGX_FFlush(r->out);
|
||||
clixon_exit_set(1);
|
||||
clixon_exit_set(1);
|
||||
goto done;
|
||||
}
|
||||
if ((ret = clicon_msg_decode(reply, NULL, NULL, &xtop, NULL)) < 0) /* XXX pass yang_spec */
|
||||
|
|
@ -262,7 +266,7 @@ restconf_stream_cb(int s,
|
|||
ok:
|
||||
retval = 0;
|
||||
done:
|
||||
clicon_debug(1, "%s retval: %d", __FUNCTION__, retval);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s retval: %d", __FUNCTION__, retval);
|
||||
if (xtop != NULL)
|
||||
xml_free(xtop);
|
||||
if (reply)
|
||||
|
|
@ -273,19 +277,22 @@ restconf_stream_cb(int s,
|
|||
}
|
||||
|
||||
/*! Send subscription to backend
|
||||
* @param[in] h Clicon handle
|
||||
*
|
||||
* @param[in] h Clixon handle
|
||||
* @param[in] req Generic Www handle (can be part of clixon handle)
|
||||
* @param[in] name Stream name
|
||||
* @param[in] qvec
|
||||
* @param[in] pretty Pretty-print json/xml reply
|
||||
* @param[in] media_out Restconf output media
|
||||
* @param[out] sp Socket -1 if not set
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
*/
|
||||
static int
|
||||
restconf_stream(clicon_handle h,
|
||||
void *req,
|
||||
char *name,
|
||||
cvec *qvec,
|
||||
cvec *qvec,
|
||||
int pretty,
|
||||
restconf_media media_out,
|
||||
int *sp)
|
||||
|
|
@ -299,7 +306,7 @@ restconf_stream(clicon_handle h,
|
|||
cg_var *cv;
|
||||
char *vname;
|
||||
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
|
||||
*sp = -1;
|
||||
if ((cb = cbuf_new()) == NULL){
|
||||
clicon_err(OE_XML, errno, "cbuf_new");
|
||||
|
|
@ -346,7 +353,7 @@ restconf_stream(clicon_handle h,
|
|||
ok:
|
||||
retval = 0;
|
||||
done:
|
||||
clicon_debug(1, "%s retval: %d", __FUNCTION__, retval);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s retval: %d", __FUNCTION__, retval);
|
||||
if (xret)
|
||||
xml_free(xret);
|
||||
if (cb)
|
||||
|
|
@ -359,18 +366,19 @@ restconf_stream(clicon_handle h,
|
|||
#include "restconf_stream.h"
|
||||
|
||||
/*! Listen sock callback (from proxy?)
|
||||
*
|
||||
* @param[in] s Socket
|
||||
* @param[in] req Generic Www handle (can be part of clixon handle)
|
||||
*/
|
||||
static int
|
||||
stream_checkuplink(int s,
|
||||
stream_checkuplink(int s,
|
||||
void *arg)
|
||||
{
|
||||
FCGX_Request *r = (FCGX_Request *)arg;
|
||||
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
|
||||
if (FCGX_GetError(r->out) != 0){ /* break loop */
|
||||
clicon_debug(1, "%s FCGX_GetError upstream", __FUNCTION__);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s FCGX_GetError upstream", __FUNCTION__);
|
||||
clixon_exit_set(1);
|
||||
}
|
||||
return 0;
|
||||
|
|
@ -383,10 +391,10 @@ stream_timeout(int s,
|
|||
struct timeval t;
|
||||
struct timeval t1;
|
||||
FCGX_Request *r = (FCGX_Request *)arg;
|
||||
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
|
||||
if (FCGX_GetError(r->out) != 0){ /* break loop */
|
||||
clicon_debug(1, "%s FCGX_GetError upstream", __FUNCTION__);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s FCGX_GetError upstream", __FUNCTION__);
|
||||
clixon_exit_set(1);
|
||||
}
|
||||
else{
|
||||
|
|
@ -396,13 +404,16 @@ stream_timeout(int s,
|
|||
clixon_event_reg_timeout(t, stream_timeout, arg, "Stream timeout");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*! Process a stream request
|
||||
* @param[in] h Clicon handle
|
||||
* @param[in] req Generic Www handle (can be part of clixon handle)
|
||||
* @param[in] qvec Query parameters, ie the ?<id>=<val>&<id>=<val> stuff
|
||||
* @param[out] finish Set to zero, if request should not be finnished by upper layer
|
||||
*
|
||||
* @param[in] h Clixon handle
|
||||
* @param[in] req Generic Www handle (can be part of clixon handle)
|
||||
* @param[in] qvec Query parameters, ie the ?<id>=<val>&<id>=<val> stuff
|
||||
* @param[out] finish Set to zero, if request should not be finnished by upper layer
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
*/
|
||||
int
|
||||
api_stream(clicon_handle h,
|
||||
|
|
@ -431,7 +442,7 @@ api_stream(clicon_handle h,
|
|||
struct stream_child *sc;
|
||||
#endif
|
||||
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__);
|
||||
streampath = clicon_option_str(h, "CLICON_STREAM_PATH");
|
||||
if ((path = restconf_uripath(h)) == NULL)
|
||||
goto done;
|
||||
|
|
@ -441,33 +452,33 @@ api_stream(clicon_handle h,
|
|||
/* Sanity check of path. Should be /stream/<name> */
|
||||
if (pn != 3){
|
||||
if (netconf_invalid_value_xml(&xerr, "protocol", "Invalid path, /stream/<name> expected") < 0)
|
||||
goto done;
|
||||
goto done;
|
||||
if (api_return_err0(h, req, xerr, pretty, media_out, 0) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
if (strlen(pvec[0]) != 0){
|
||||
if (netconf_invalid_value_xml(&xerr, "protocol", "Invalid path, /stream/<name> expected") < 0)
|
||||
goto done;
|
||||
goto done;
|
||||
if (api_return_err0(h, req, xerr, pretty, media_out, 0) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
if (strcmp(pvec[1], streampath)){
|
||||
if (netconf_invalid_value_xml(&xerr, "protocol", "Invalid path, /stream/<name> expected") < 0)
|
||||
goto done;
|
||||
goto done;
|
||||
if (api_return_err0(h, req, xerr, pretty, media_out, 0) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
if ((method = pvec[2]) == NULL){
|
||||
if (netconf_invalid_value_xml(&xerr, "protocol", "Invalid path, /stream/<name> expected") < 0)
|
||||
goto done;
|
||||
goto done;
|
||||
if (api_return_err0(h, req, xerr, pretty, media_out, 0) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
clicon_debug(1, "%s: method=%s", __FUNCTION__, method);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s: method=%s", __FUNCTION__, method);
|
||||
|
||||
if (uri_str2cvec(path, '/', '=', 1, &pcvec) < 0) /* rest url eg /album=ricky/foo */
|
||||
goto done;
|
||||
|
|
@ -475,7 +486,7 @@ api_stream(clicon_handle h,
|
|||
if ((cb = restconf_get_indata(req)) == NULL)
|
||||
goto done;
|
||||
indata = cbuf_get(cb);
|
||||
clicon_debug(1, "%s DATA=%s", __FUNCTION__, indata);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s DATA=%s", __FUNCTION__, indata);
|
||||
|
||||
/* If present, check credentials. See "plugin_credentials" in plugin
|
||||
* See RFC 8040 section 2.5
|
||||
|
|
@ -501,22 +512,22 @@ api_stream(clicon_handle h,
|
|||
cbuf_free(cbret);
|
||||
#endif /* STREAM_FORK */
|
||||
/* Listen to backend socket */
|
||||
if (clixon_event_reg_fd(s,
|
||||
restconf_stream_cb,
|
||||
req,
|
||||
"stream socket") < 0)
|
||||
goto done;
|
||||
if (clixon_event_reg_fd(rfcgi->listen_sock,
|
||||
stream_checkuplink,
|
||||
if (clixon_event_reg_fd(s,
|
||||
restconf_stream_cb,
|
||||
req,
|
||||
"stream socket") < 0)
|
||||
goto done;
|
||||
clicon_debug(1, "%s before loop", __FUNCTION__);
|
||||
if (clixon_event_reg_fd(rfcgi->listen_sock,
|
||||
stream_checkuplink,
|
||||
req,
|
||||
"stream socket") < 0)
|
||||
goto done;
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s before loop", __FUNCTION__);
|
||||
/* Poll upstream errors */
|
||||
stream_timeout(0, req);
|
||||
/* Start loop */
|
||||
clixon_event_loop(h);
|
||||
clicon_debug(1, "%s after loop", __FUNCTION__);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s after loop", __FUNCTION__);
|
||||
clicon_rpc_close_session(h);
|
||||
clixon_event_unreg_fd(s, restconf_stream_cb);
|
||||
close(s);
|
||||
|
|
@ -551,7 +562,7 @@ api_stream(clicon_handle h,
|
|||
ok:
|
||||
retval = 0;
|
||||
done:
|
||||
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
|
||||
clixon_debug(CLIXON_DBG_DEFAULT, "%s retval:%d", __FUNCTION__, retval);
|
||||
if (xerr)
|
||||
xml_free(xerr);
|
||||
if (pvec)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue