* HTTP/1 native parser as part of the RESTCONF client
* Fixed memory error in opendir/readdir in clicon_file_dirent * Remove MAXPATH in parsers * New string-del function
This commit is contained in:
parent
0ed34b4fab
commit
dadf4a778a
53 changed files with 1061 additions and 1273 deletions
|
|
@ -100,10 +100,10 @@ APPSRC += restconf_methods_post.c
|
|||
APPSRC += restconf_methods_get.c
|
||||
APPSRC += restconf_methods_patch.c
|
||||
APPSRC += restconf_root.c
|
||||
APPSRC += clixon_http1.c
|
||||
APPSRC += restconf_main_$(with_restconf).c
|
||||
ifeq ($(with_restconf),native)
|
||||
APPSRC += restconf_native.c
|
||||
APPSRC += restconf_evhtp.c # HTTP/1
|
||||
APPSRC += restconf_nghttp2.c # HTTP/2
|
||||
endif
|
||||
|
||||
|
|
@ -113,7 +113,10 @@ ifeq ($(with_restconf),fcgi)
|
|||
APPSRC += restconf_stream_$(with_restconf).c
|
||||
endif
|
||||
|
||||
APPOBJ = $(APPSRC:.c=.o)
|
||||
# internal http/1 parser
|
||||
YACCOBJS = lex.clixon_http1_parse.o clixon_http1_parse.tab.o
|
||||
|
||||
APPOBJ = $(APPSRC:.c=.o) $(YACCOBJS)
|
||||
|
||||
# Accessible from plugin
|
||||
# XXX actually this does not work properly, there are functions in lib
|
||||
|
|
@ -125,6 +128,8 @@ LIBSRC += restconf_api_$(with_restconf).c
|
|||
|
||||
LIBOBJ = $(LIBSRC:.c=.o)
|
||||
|
||||
|
||||
|
||||
# This lib is very small but used for clixon restconf applications to access clixon restconf lib
|
||||
# functions. Mostly for future use
|
||||
MYNAME = clixon_restconf
|
||||
|
|
@ -147,6 +152,7 @@ $(top_srcdir)/lib/src/$(CLIXON_LIB):
|
|||
clean:
|
||||
rm -f $(LIBOBJ) *.core $(APPL) $(APPOBJ) *.o $(MYLIBDYNAMIC) $(MYLIBSTATIC) $(MYLIBSO) $(MYLIBLINK) # extra .o to clean residue if with_restconf changes
|
||||
rm -f *.gcda *.gcno *.gcov # coverage
|
||||
rm -f clixon_http1_parse.tab.[ch] clixon_http1_parse.[co] lex.clixon_http1_parse.c
|
||||
|
||||
distclean: clean
|
||||
rm -f Makefile *~ .depend
|
||||
|
|
@ -191,6 +197,19 @@ uninstall:
|
|||
.c.o:
|
||||
$(CC) $(INCLUDES) -D__PROGRAM__=\"clixon_restconf\" $(CPPFLAGS) $(CFLAGS) -c $<
|
||||
|
||||
# http1 parser
|
||||
lex.clixon_http1_parse.c : clixon_http1_parse.l clixon_http1_parse.tab.h
|
||||
$(LEX) -Pclixon_http1_parse clixon_http1_parse.l # -d is debug
|
||||
|
||||
clixon_http1_parse.tab.h: clixon_http1_parse.y
|
||||
$(YACC) -l -d -b clixon_http1_parse -p clixon_http1_parse clixon_http1_parse.y # -t is debug
|
||||
|
||||
# extra rule to avoid parallell yaccs
|
||||
clixon_http1_parse.tab.c: clixon_http1_parse.tab.h
|
||||
|
||||
lex.clixon_http1_parse.o : lex.clixon_http1_parse.c clixon_http1_parse.tab.h
|
||||
$(CC) $(INCLUDES) $(CPPFLAGS) $(CFLAGS) -Wno-error -c $<
|
||||
|
||||
ifeq ($(LINKAGE),dynamic)
|
||||
$(APPL): $(MYLIBDYNAMIC)
|
||||
else
|
||||
|
|
|
|||
|
|
@ -6,19 +6,10 @@
|
|||
* [Nchan Streams](#nchan)
|
||||
* [Debugging](#debugging)
|
||||
|
||||
There are two installation instructions: for libevhtp and nginx.
|
||||
There are two installation instructions: for native and nginx.
|
||||
|
||||
## Native
|
||||
|
||||
Download, build and install libevhtp from source. Prereqs: libevent and ssl
|
||||
```
|
||||
sudo git clone https://github.com/clicon/clixon-libevhtp.git
|
||||
cd clixon-libevhtp
|
||||
./configure --libdir=/usr/lib
|
||||
make
|
||||
sudo make install
|
||||
```
|
||||
|
||||
Configure clixon with native restconf:
|
||||
```
|
||||
./configure --with-restconf=native
|
||||
|
|
|
|||
248
apps/restconf/clixon_http1.c
Normal file
248
apps/restconf/clixon_http1.c
Normal file
|
|
@ -0,0 +1,248 @@
|
|||
/*
|
||||
*
|
||||
***** BEGIN LICENSE BLOCK *****
|
||||
|
||||
Copyright (C) 2020-2022 Olof Hagsand and Rubicon Communications, LLC(Netgate)
|
||||
|
||||
This file is part of CLIXON.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
Alternatively, the contents of this file may be used under the terms of
|
||||
the GNU General Public License Version 3 or later (the "GPL"),
|
||||
in which case the provisions of the GPL are applicable instead
|
||||
of those above. If you wish to allow use of your version of this file only
|
||||
under the terms of the GPL, and not to allow others to
|
||||
use your version of this file under the terms of Apache License version 2,
|
||||
indicate your decision by deleting the provisions above and replace them with
|
||||
the notice and other provisions required by the GPL. If you do not delete
|
||||
the provisions above, a recipient may use your version of this file under
|
||||
the terms of any one of the Apache License version 2 or the GPL.
|
||||
|
||||
***** END LICENSE BLOCK *****
|
||||
|
||||
* HTTP/1.1 parser according to RFC 7230
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "clixon_config.h" /* generated by config & autoconf */
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
#include <syslog.h>
|
||||
#include <errno.h>
|
||||
#include <openssl/ssl.h>
|
||||
|
||||
#ifdef HAVE_LIBNGHTTP2
|
||||
#include <nghttp2/nghttp2.h>
|
||||
#endif
|
||||
|
||||
/* cligen */
|
||||
#include <cligen/cligen.h>
|
||||
|
||||
/* clixon */
|
||||
#include <clixon/clixon.h>
|
||||
|
||||
#include "restconf_lib.h"
|
||||
#include "restconf_native.h"
|
||||
#include "clixon_http1_parse.h"
|
||||
|
||||
/* Size of xml read buffer */
|
||||
#define BUFLEN 1024
|
||||
|
||||
static int
|
||||
_http1_parse(clicon_handle h,
|
||||
restconf_conn *rc,
|
||||
char *str,
|
||||
const char *filename)
|
||||
{
|
||||
int retval = -1;
|
||||
clixon_http1_yacc hy = {0,};
|
||||
char *ptr;
|
||||
size_t sz;
|
||||
|
||||
clicon_debug(2, "%s", __FUNCTION__);
|
||||
if (strlen(str) == 0)
|
||||
goto ok;
|
||||
hy.hy_parse_string = str;
|
||||
hy.hy_name = filename;
|
||||
hy.hy_h = h;
|
||||
hy.hy_rc = rc;
|
||||
hy.hy_linenum = 1;
|
||||
if (http1_scan_init(&hy) < 0)
|
||||
goto done;
|
||||
if (http1_parse_init(&hy) < 0)
|
||||
goto done;
|
||||
ptr = clixon_http1_parsetext;
|
||||
if (clixon_http1_parseparse(&hy) != 0) { /* yacc returns 1 on error */
|
||||
if (filename)
|
||||
clicon_log(LOG_NOTICE, "HTTP1 error: on line %d in %s", hy.hy_linenum, filename);
|
||||
else
|
||||
clicon_log(LOG_NOTICE, "HTTP1 error: on line %d", hy.hy_linenum);
|
||||
if (clicon_errno == 0)
|
||||
clicon_err(OE_RESTCONF, 0, "HTTP1 parser error with no error code (should not happen)");
|
||||
goto done;
|
||||
}
|
||||
if (0){
|
||||
sz = (clixon_http1_parsetext - ptr) + strlen(clixon_http1_parsetext);
|
||||
fprintf(stderr,"%s %p diff:%ld %ld\n", __FUNCTION__,
|
||||
clixon_http1_parsetext,
|
||||
sz,
|
||||
strlen(ptr)
|
||||
);
|
||||
}
|
||||
http1_parse_exit(&hy);
|
||||
http1_scan_exit(&hy);
|
||||
ok:
|
||||
retval = 0;
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Read an XML definition from file and parse it into a parse-tree, advanced API
|
||||
*
|
||||
* @param[in] fd A file descriptor containing the XML file (as ASCII characters)
|
||||
* @param[in] yb How to bind yang to XML top-level when parsing
|
||||
* @param[in] yspec Yang specification (only if bind is TOP or CONFIG)
|
||||
* @param[in,out] xt Pointer to XML parse tree. If empty, create.
|
||||
* @param[out] xerr Pointer to XML error tree, if retval is 0
|
||||
* @retval 1 Parse OK and all yang assignment made
|
||||
* @retval 0 Parse OK but yang assigment not made (or only partial) and xerr set
|
||||
* @retval -1 Error with clicon_err called. Includes parse error
|
||||
*
|
||||
* @code
|
||||
* cxobj *xt = NULL;
|
||||
* cxobj *xerr = NULL;
|
||||
* FILE *f;
|
||||
* if ((f = fopen(filename, "r")) == NULL)
|
||||
* err;
|
||||
* if ((ret = clixon_xml_parse_file(f, YB_MODULE, yspec, &xt, &xerr)) < 0)
|
||||
* err;
|
||||
* xml_free(xt);
|
||||
* @endcode
|
||||
* @see clixon_xml_parse_string
|
||||
* @see clixon_json_parse_file
|
||||
* @note, If xt empty, a top-level symbol will be added so that <tree../> will be: <top><tree.../></tree></top>
|
||||
* @note May block on file I/O
|
||||
*/
|
||||
int
|
||||
clixon_http1_parse_file(clicon_handle h,
|
||||
restconf_conn *rc,
|
||||
FILE *f,
|
||||
const char *filename)
|
||||
{
|
||||
int retval = -1;
|
||||
int ret;
|
||||
char ch;
|
||||
char *buf = NULL;
|
||||
char *ptr;
|
||||
int buflen = BUFLEN; /* start size */
|
||||
int len = 0;
|
||||
int oldbuflen;
|
||||
|
||||
clicon_debug(1, "%s %s", __FUNCTION__, filename);
|
||||
if (f == NULL){
|
||||
clicon_err(OE_RESTCONF, EINVAL, "f is NULL");
|
||||
goto done;
|
||||
}
|
||||
if ((buf = malloc(buflen)) == NULL){
|
||||
clicon_err(OE_XML, errno, "malloc");
|
||||
goto done;
|
||||
}
|
||||
memset(buf, 0, buflen);
|
||||
ptr = buf;
|
||||
while (1){
|
||||
if ((ret = fread(&ch, 1, 1, f)) < 0){
|
||||
clicon_err(OE_XML, errno, "read");
|
||||
break;
|
||||
}
|
||||
if (ret != 0){
|
||||
buf[len++] = ch;
|
||||
}
|
||||
if (ret == 0) { /* buffer read */
|
||||
if (_http1_parse(h, rc, ptr, filename) < 0)
|
||||
goto done;
|
||||
break;
|
||||
}
|
||||
if (len >= buflen-1){ /* Space: one for the null character */
|
||||
oldbuflen = buflen;
|
||||
buflen *= 2;
|
||||
if ((buf = realloc(buf, buflen)) == NULL){
|
||||
clicon_err(OE_XML, errno, "realloc");
|
||||
goto done;
|
||||
}
|
||||
memset(buf+oldbuflen, 0, buflen-oldbuflen);
|
||||
ptr = buf;
|
||||
}
|
||||
} /* while */
|
||||
retval = 0;
|
||||
done:
|
||||
if (buf)
|
||||
free(buf);
|
||||
return retval;
|
||||
}
|
||||
|
||||
int
|
||||
clixon_http1_parse_string(clicon_handle h,
|
||||
restconf_conn *rc,
|
||||
char *str)
|
||||
{
|
||||
return _http1_parse(h, rc, str, "http1-parse");
|
||||
}
|
||||
|
||||
/*! Convert buffer to null-terminated string
|
||||
* I dont know how to do this without copying, OR
|
||||
* input flex with a non-null terminated string
|
||||
*/
|
||||
int
|
||||
clixon_http1_parse_buf(clicon_handle h,
|
||||
restconf_conn *rc,
|
||||
char *buf,
|
||||
size_t n)
|
||||
{
|
||||
char *str = NULL;
|
||||
|
||||
if ((str = malloc(n+1)) == NULL){
|
||||
clicon_err(OE_RESTCONF, errno, "malloc");
|
||||
return -1;
|
||||
}
|
||||
memcpy(str, buf, n);
|
||||
str[n] = '\0';
|
||||
return _http1_parse(h, rc, str, "http1-parse");
|
||||
}
|
||||
|
||||
/*!
|
||||
* @param[in] h Clixon handle
|
||||
* @param[in] rc Clixon request connect pointer
|
||||
*/
|
||||
int
|
||||
restconf_http1_path_root(clicon_handle h,
|
||||
restconf_conn *rc)
|
||||
{
|
||||
int retval = -1;
|
||||
restconf_stream_data *sd;
|
||||
|
||||
clicon_debug(1, "------------");
|
||||
if ((sd = restconf_stream_find(rc, 0)) == NULL){
|
||||
clicon_err(OE_RESTCONF, EINVAL, "No stream_data");
|
||||
goto done;
|
||||
}
|
||||
retval = 0;
|
||||
done:
|
||||
clicon_debug(1, "%s %d", __FUNCTION__, retval);
|
||||
return retval;
|
||||
}
|
||||
|
|
@ -2,7 +2,6 @@
|
|||
*
|
||||
***** BEGIN LICENSE BLOCK *****
|
||||
|
||||
Copyright (C) 2009-2019 Olof Hagsand
|
||||
Copyright (C) 2020-2022 Olof Hagsand and Rubicon Communications, LLC(Netgate)
|
||||
|
||||
This file is part of CLIXON.
|
||||
|
|
@ -31,17 +30,18 @@
|
|||
the terms of any one of the Apache License version 2 or the GPL.
|
||||
|
||||
***** END LICENSE BLOCK *****
|
||||
*
|
||||
* Virtual clixon restconf API functions.
|
||||
*/
|
||||
|
||||
#ifndef _RESTCONF_EVHTP_H_
|
||||
#define _RESTCONF_EVHTP_H_
|
||||
* HTTP/1.1 parser according to RFC 7230
|
||||
*/
|
||||
#ifndef _CLIXON_HTTP1_H_
|
||||
#define _CLIXON_HTTP1_H_
|
||||
|
||||
/*
|
||||
* Prototypes
|
||||
*/
|
||||
void restconf_path_root(evhtp_request_t *req, void *arg);
|
||||
void restconf_path_wellknown(evhtp_request_t *req, void *arg);
|
||||
int clixon_http1_parse_file(clicon_handle h, restconf_conn *rc, FILE *f, const char *filename);
|
||||
int clixon_http1_parse_string(clicon_handle h, restconf_conn *rc, char *str);
|
||||
int clixon_http1_parse_buf(clicon_handle h, restconf_conn *rc, char *buf, size_t n);
|
||||
int restconf_http1_path_root(clicon_handle h, restconf_conn *rc);
|
||||
|
||||
#endif /* _RESTCONF_EVHTP_H_ */
|
||||
#endif /* _CLIXON_HTTP1_H_ */
|
||||
71
apps/restconf/clixon_http1_parse.h
Normal file
71
apps/restconf/clixon_http1_parse.h
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
*
|
||||
***** BEGIN LICENSE BLOCK *****
|
||||
|
||||
Copyright (C) 2020-2022 Olof Hagsand and Rubicon Communications, LLC(Netgate)
|
||||
|
||||
This file is part of CLIXON.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
Alternatively, the contents of this file may be used under the terms of
|
||||
the GNU General Public License Version 3 or later (the "GPL"),
|
||||
in which case the provisions of the GPL are applicable instead
|
||||
of those above. If you wish to allow use of your version of this file only
|
||||
under the terms of the GPL, and not to allow others to
|
||||
use your version of this file under the terms of Apache License version 2,
|
||||
indicate your decision by deleting the provisions above and replace them with
|
||||
the notice and other provisions required by the GPL. If you do not delete
|
||||
the provisions above, a recipient may use your version of this file under
|
||||
the terms of any one of the Apache License version 2 or the GPL.
|
||||
|
||||
***** END LICENSE BLOCK *****
|
||||
|
||||
* HTTP/1.1 parser according to RFC 7230
|
||||
*/
|
||||
#ifndef _CLIXON_HTTP1_PARSE_H_
|
||||
#define _CLIXON_HTTP1_PARSE_H_
|
||||
|
||||
/*
|
||||
* Types
|
||||
*/
|
||||
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 */
|
||||
int hy_linenum; /* Number of \n in parsed buffer */
|
||||
char *hy_parse_string; /* original (copy of) parse string */
|
||||
void *hy_lexbuf; /* internal parse buffer from lex */
|
||||
void *hy_top;
|
||||
};
|
||||
typedef struct clixon_http1_yacc clixon_http1_yacc;
|
||||
|
||||
/*
|
||||
* Variables
|
||||
*/
|
||||
extern char *clixon_http1_parsetext;
|
||||
|
||||
/*
|
||||
* Prototypes
|
||||
*/
|
||||
int http1_scan_init(clixon_http1_yacc *);
|
||||
int http1_scan_exit(clixon_http1_yacc *);
|
||||
|
||||
int http1_parse_init(clixon_http1_yacc *);
|
||||
int http1_parse_exit(clixon_http1_yacc *);
|
||||
|
||||
int clixon_http1_parselex(void *);
|
||||
int clixon_http1_parseparse(void *);
|
||||
void clixon_http1_parseerror(void *, char*);
|
||||
|
||||
#endif /* _CLIXON_HTTP1_PARSE_H_ */
|
||||
164
apps/restconf/clixon_http1_parse.l
Normal file
164
apps/restconf/clixon_http1_parse.l
Normal file
|
|
@ -0,0 +1,164 @@
|
|||
/*
|
||||
*
|
||||
***** BEGIN LICENSE BLOCK *****
|
||||
|
||||
Copyright (C) 2020-2022 Olof Hagsand and Rubicon Communications, LLC(Netgate)
|
||||
|
||||
This file is part of CLIXON.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
Alternatively, the contents of this file may be used under the terms of
|
||||
the GNU General Public License Version 3 or later (the "GPL"),
|
||||
in which case the provisions of the GPL are applicable instead
|
||||
of those above. If you wish to allow use of your version of this file only
|
||||
under the terms of the GPL, and not to allow others to
|
||||
use your version of this file under the terms of Apache License version 2,
|
||||
indicate your decision by deleting the provisions above and replace them with
|
||||
the notice and other provisions required by the GPL. If you do not delete
|
||||
the provisions above, a recipient may use your version of this file under
|
||||
the terms of any one of the Apache License version 2 or the GPL.
|
||||
|
||||
***** END LICENSE BLOCK *****
|
||||
*
|
||||
* HTTP/1.1 parser according to RFC 7230
|
||||
*
|
||||
The following core rules are included by reference, as defined in
|
||||
[RFC5234], Appendix B.1: ALPHA (letters), CR (carriage return), CRLF
|
||||
(CR LF), CTL (controls), DIGIT (decimal 0-9), DQUOTE (double quote),
|
||||
HEXDIG (hexadecimal 0-9/A-F/a-f), HTAB (horizontal tab), LF (line
|
||||
feed), OCTET (any 8-bit sequence of data), SP (space), and VCHAR (any
|
||||
visible [USASCII] character).
|
||||
*/
|
||||
|
||||
%{
|
||||
|
||||
#include "clixon_config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <errno.h>
|
||||
#include <openssl/ssl.h>
|
||||
|
||||
#ifdef HAVE_LIBNGHTTP2
|
||||
#include <nghttp2/nghttp2.h>
|
||||
#endif
|
||||
|
||||
#include "clixon_http1_parse.tab.h" /* generated */
|
||||
|
||||
#include <cligen/cligen.h>
|
||||
#include <clixon/clixon.h>
|
||||
|
||||
#include "restconf_lib.h"
|
||||
#include "restconf_native.h"
|
||||
#include "clixon_http1_parse.h"
|
||||
|
||||
/* Redefine main lex function so that you can send arguments to it: _yy is added to arg list */
|
||||
#define YY_DECL int clixon_http1_parselex(void *_hy)
|
||||
|
||||
/* Dont use input function (use user-buffer) */
|
||||
#define YY_NO_INPUT
|
||||
|
||||
/* typecast macro */
|
||||
#define _HY ((clixon_http1_yacc *)_hy)
|
||||
|
||||
#undef clixon_api_path_parsewrap
|
||||
int
|
||||
clixon_http1_parsewrap(void)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
%}
|
||||
|
||||
tchar [!#$%&'*+\-\.^_`|~0-9A-Za-z]
|
||||
token {tchar}{tchar}*
|
||||
pchar [A-Za-z0-9\-\._~!$&'()*+,;=:@]|%[0-9a-fA-F][0-9a-fA-F]
|
||||
query [A-Za-z0-9\-\._~!$&'()*+,;=:@?/]|%[0-9a-fA-F][0-9a-fA-F]
|
||||
|
||||
%x REQLINE
|
||||
%x REQTARG
|
||||
%x REQUERY
|
||||
%x REQHTTP
|
||||
%x FLDNAME
|
||||
%x FLDVALUE
|
||||
|
||||
%%
|
||||
<REQLINE,REQTARG,REQUERY,REQHTTP,FLDNAME,FLDVALUE><<EOF>> { return X_EOF; }
|
||||
<REQLINE>[ ] { BEGIN(REQTARG); return SP; }
|
||||
<REQLINE>{token} { clixon_http1_parselval.string = yytext;
|
||||
return TOKEN; }
|
||||
<REQLINE>. { clixon_http1_parseerror(_HY, "LEXICAL ERROR\n"); return -1; }
|
||||
|
||||
<REQTARG>\? { BEGIN(REQUERY); return QMARK; }
|
||||
<REQTARG>\/ { return SLASH; }
|
||||
<REQTARG>[ ] { return SP; }
|
||||
<REQTARG>HTTP { BEGIN(REQHTTP); return HTTP; }
|
||||
<REQUERY>{pchar}+ { clixon_http1_parselval.string = yytext;
|
||||
return PCHARS; }
|
||||
<REQTARG>. { clixon_http1_parseerror(_HY, "LEXICAL ERROR\n"); return -1; }
|
||||
|
||||
<REQUERY>\/ { return SLASH; }
|
||||
<REQUERY>[ ] { return SP; }
|
||||
<REQUERY>HTTP { BEGIN(REQHTTP); return HTTP; }
|
||||
<REQUERY>{query}+ { clixon_http1_parselval.string = yytext;
|
||||
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>[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 { return CRLF; _HY->hy_linenum++; }
|
||||
<FLDNAME>[ \t\n]+ { return RWS; }
|
||||
<FLDNAME>{token} { clixon_http1_parselval.string = yytext;
|
||||
return TOKEN; }
|
||||
<FLDNAME>. { clixon_http1_parseerror(_HY, "LEXICAL ERROR\n"); return -1; }
|
||||
<FLDVALUE>\r\n { BEGIN(FLDNAME); return CRLF; _HY->hy_linenum++; }
|
||||
<FLDVALUE>[ \t\n]+ { return RWS; }
|
||||
<FLDVALUE>. { clixon_http1_parselval.string = yytext;
|
||||
return VCHAR; }
|
||||
%%
|
||||
|
||||
/*! Initialize scanner.
|
||||
*/
|
||||
int
|
||||
http1_scan_init(clixon_http1_yacc *hy)
|
||||
{
|
||||
BEGIN(REQLINE);
|
||||
hy->hy_lexbuf = yy_scan_string(hy->hy_parse_string);
|
||||
#if 1 /* XXX: just to use unput to avoid warning */
|
||||
if (0)
|
||||
yyunput(0, "");
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* free buffers
|
||||
* Even within Flex version 2.5 (this is assumed), freeing buffers is different.
|
||||
*/
|
||||
int
|
||||
http1_scan_exit(clixon_http1_yacc *hy)
|
||||
{
|
||||
yy_delete_buffer(hy->hy_lexbuf);
|
||||
clixon_http1_parselex_destroy(); /* modern */
|
||||
return 0;
|
||||
}
|
||||
|
||||
289
apps/restconf/clixon_http1_parse.y
Normal file
289
apps/restconf/clixon_http1_parse.y
Normal file
|
|
@ -0,0 +1,289 @@
|
|||
/*
|
||||
*
|
||||
***** BEGIN LICENSE BLOCK *****
|
||||
|
||||
Copyright (C) 2020-2022 Olof Hagsand and Rubicon Communications, LLC(Netgate)
|
||||
|
||||
This file is part of CLIXON.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
Alternatively, the contents of this file may be used under the terms of
|
||||
the GNU General Public License Version 3 or later (the "GPL"),
|
||||
in which case the provisions of the GPL are applicable instead
|
||||
of those above. If you wish to allow use of your version of this file only
|
||||
under the terms of the GPL, and not to allow others to
|
||||
use your version of this file under the terms of Apache License version 2,
|
||||
indicate your decision by deleting the provisions above and replace them with
|
||||
the notice and other provisions required by the GPL. If you do not delete
|
||||
the provisions above, a recipient may use your version of this file under
|
||||
the terms of any one of the Apache License version 2 or the GPL.
|
||||
|
||||
***** END LICENSE BLOCK *****
|
||||
|
||||
* HTTP/1.1 parser according to RFC 7230 Appendix B
|
||||
*/
|
||||
|
||||
%start http_message
|
||||
|
||||
/* Must be here to define YYSTYPE */
|
||||
%union {
|
||||
char *string;
|
||||
int intval;
|
||||
}
|
||||
|
||||
%token SP
|
||||
%token CRLF
|
||||
%token RWS
|
||||
%token SLASH
|
||||
%token QMARK
|
||||
%token DOT
|
||||
%token HTTP
|
||||
%token COLON
|
||||
%token X_EOF
|
||||
|
||||
%token <string> PCHARS
|
||||
%token <string> QUERY
|
||||
%token <string> TOKEN
|
||||
%token <string> VCHAR
|
||||
%token <intval> DIGIT
|
||||
|
||||
%type <string> absolute_paths
|
||||
%type <string> absolute_path
|
||||
|
||||
%lex-param {void *_hy} /* Add this argument to parse() and lex() function */
|
||||
%parse-param {void *_hy}
|
||||
|
||||
%{
|
||||
/* Here starts user C-code */
|
||||
|
||||
/* typecast macro */
|
||||
#define _HY ((clixon_http1_yacc *)_hy)
|
||||
|
||||
#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
|
||||
|
||||
#include "clixon_config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <errno.h>
|
||||
#include <openssl/ssl.h>
|
||||
|
||||
#ifdef HAVE_LIBNGHTTP2
|
||||
#include <nghttp2/nghttp2.h>
|
||||
#endif
|
||||
|
||||
#include <cligen/cligen.h>
|
||||
#include <clixon/clixon.h>
|
||||
|
||||
#include "restconf_lib.h"
|
||||
#include "restconf_handle.h"
|
||||
#include "restconf_native.h"
|
||||
#include "clixon_http1_parse.h"
|
||||
|
||||
/* 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.
|
||||
*/
|
||||
#if 0
|
||||
#define _PARSE_DEBUG(s) clicon_debug(1,(s))
|
||||
#define _PARSE_DEBUG1(s, s1) clicon_debug(1,(s), (s1))
|
||||
#else
|
||||
#define _PARSE_DEBUG(s)
|
||||
#define _PARSE_DEBUG1(s, s1)
|
||||
#endif
|
||||
|
||||
/*
|
||||
also called from yacc generated code *
|
||||
*/
|
||||
|
||||
void
|
||||
clixon_http1_parseerror(void *_hy,
|
||||
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);
|
||||
return;
|
||||
}
|
||||
|
||||
int
|
||||
http1_parse_init(clixon_http1_yacc *hy)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
http1_parse_exit(clixon_http1_yacc *hy)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
http1_parse_query(clixon_http1_yacc *hy,
|
||||
char *query)
|
||||
{
|
||||
int retval = -1;
|
||||
restconf_stream_data *sd = NULL;
|
||||
|
||||
if ((sd = restconf_stream_find(hy->hy_rc, 0)) == NULL)
|
||||
goto ok;
|
||||
if (uri_str2cvec(query, '&', '=', 1, &sd->sd_qvec) < 0)
|
||||
goto done;
|
||||
ok:
|
||||
retval = 0;
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
%}
|
||||
|
||||
%%
|
||||
|
||||
/* 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
|
||||
{ _HY->hy_top=NULL; _PARSE_DEBUG("http-message -> request-line header-fields ACCEPT"); YYACCEPT; }
|
||||
;
|
||||
|
||||
/* 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
|
||||
*/
|
||||
method : TOKEN
|
||||
{
|
||||
if (restconf_param_set(_HY->hy_h, "REQUEST_METHOD", $1) < 0)
|
||||
YYABORT;
|
||||
_PARSE_DEBUG("method -> TOKEN");
|
||||
}
|
||||
;
|
||||
|
||||
/* request-target = origin-form / absolute-form / authority-form / asterisk-form *
|
||||
* origin-form = absolute-path [ "?" query ] */
|
||||
request_target : absolute_paths
|
||||
{
|
||||
if (restconf_param_set(_HY->hy_h, "REQUEST_URI", $1) < 0)
|
||||
YYABORT;
|
||||
_PARSE_DEBUG("request-target -> absolute-paths");
|
||||
}
|
||||
| absolute_paths QMARK QUERY
|
||||
{
|
||||
if (restconf_param_set(_HY->hy_h, "REQUEST_URI", $1) < 0)
|
||||
YYABORT;
|
||||
if (http1_parse_query(_HY->hy_h, $3) < 0)
|
||||
YYABORT;
|
||||
_PARSE_DEBUG("request-target -> absolute-paths ? query");
|
||||
}
|
||||
;
|
||||
|
||||
/* query = <query, see [RFC3986], Section 3.4>
|
||||
* query = *( pchar / "/" / "?" )
|
||||
*/
|
||||
/*
|
||||
query : query query1 { _PARSE_DEBUG("query -> query1"); }
|
||||
| { _PARSE_DEBUG("query -> "); }
|
||||
;
|
||||
|
||||
query1 : PCHARS { _PARSE_DEBUG("query1 -> PCHARS"); }
|
||||
| SLASH { _PARSE_DEBUG("query1 -> /"); }
|
||||
| QMARK { _PARSE_DEBUG("query1 -> ?"); }
|
||||
;
|
||||
*/
|
||||
|
||||
/* absolute-path = 1*( "/" segment ) */
|
||||
absolute_paths : absolute_paths absolute_path
|
||||
{
|
||||
if (($$ = clixon_string_del_join($1, "/", $2)) == NULL) YYABORT;
|
||||
_PARSE_DEBUG("absolute-paths -> absolute-paths absolute -path");
|
||||
}
|
||||
| absolute_path
|
||||
{ $$ = strdup($1);
|
||||
_PARSE_DEBUG("absolute-paths -> absolute -path");
|
||||
}
|
||||
;
|
||||
|
||||
/* segment = <segment, see [RFC3986], Section 3.3>
|
||||
* segment = *pchar
|
||||
* pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
|
||||
* unreserved = ALPHA / DIGIT / "-" / "." / }"_" / "~"
|
||||
* pct-encoded = "%" HEXDIG HEXDIG
|
||||
* sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
|
||||
* / "*" / "+" / "," / ";" / "="
|
||||
*/
|
||||
absolute_path : SLASH PCHARS
|
||||
{ $$=$2; _PARSE_DEBUG("absolute-path -> PCHARS"); }
|
||||
;
|
||||
|
||||
HTTP_version : HTTP SLASH DIGIT DOT DIGIT
|
||||
{ _PARSE_DEBUG("HTTP-version -> HTTP / DIGIT . DIGIT"); }
|
||||
;
|
||||
|
||||
/*------------------------------------------ hdr fields
|
||||
*( header-field CRLF ) */
|
||||
header_fields : header_fields header_field CRLF
|
||||
{ _PARSE_DEBUG("header-fields -> header-fields header-field CRLF"); }
|
||||
| { _PARSE_DEBUG("header-fields -> "); }
|
||||
;
|
||||
|
||||
/* header-field = field-name ":" OWS field-value OWS */
|
||||
header_field : field_name COLON ows field_values ows
|
||||
{ _PARSE_DEBUG("header-field -> field-name : field-values"); }
|
||||
;
|
||||
|
||||
/* field-name = token */
|
||||
field_name : TOKEN { _PARSE_DEBUG("field-name -> TOKEN"); }
|
||||
;
|
||||
|
||||
/* field-value = *( field-content / obs-fold ) */
|
||||
field_values : field_values field_content
|
||||
{ _PARSE_DEBUG("field-values -> field-values field-content"); }
|
||||
| { _PARSE_DEBUG("field-values -> "); }
|
||||
;
|
||||
|
||||
/* field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ] */
|
||||
field_content : field_vchars { _PARSE_DEBUG("field-content -> field-vchars"); }
|
||||
;
|
||||
|
||||
/* field-vchar = VCHAR / obs-text */
|
||||
field_vchars : field_vchars RWS VCHAR
|
||||
{ _PARSE_DEBUG("field-vchars -> field-vchars VCHAR"); }
|
||||
| VCHAR { _PARSE_DEBUG("field-vchars -> VCHAR"); }
|
||||
;
|
||||
|
||||
/* The OWS rule is used where zero or more linear whitespace octets
|
||||
OWS = *( SP / HTAB )
|
||||
; optional whitespace
|
||||
RWS = 1*( SP / HTAB )
|
||||
; required whitespace
|
||||
*/
|
||||
ows : RWS
|
||||
|
|
||||
;
|
||||
|
||||
%%
|
||||
|
||||
|
|
@ -50,13 +50,6 @@
|
|||
#include <openssl/ssl.h>
|
||||
#include <openssl/err.h>
|
||||
|
||||
#ifdef HAVE_LIBEVHTP
|
||||
/* evhtp */
|
||||
#define EVHTP_DISABLE_REGEX
|
||||
#define EVHTP_DISABLE_EVTHR
|
||||
#include <evhtp/evhtp.h>
|
||||
#endif /* HAVE_LIBEVHTP */
|
||||
|
||||
#ifdef HAVE_LIBNGHTTP2
|
||||
#include <nghttp2/nghttp2.h>
|
||||
#endif
|
||||
|
|
@ -71,8 +64,8 @@
|
|||
#include "restconf_api.h" /* Virtual api */
|
||||
#include "restconf_native.h"
|
||||
|
||||
/*! Add HTTP header field name and value to reply, evhtp specific
|
||||
* @param[in] req Evhtp http request handle
|
||||
/*! 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
|
||||
* @see eg RFC 7230
|
||||
|
|
|
|||
|
|
@ -1,681 +0,0 @@
|
|||
/*
|
||||
*
|
||||
***** BEGIN LICENSE BLOCK *****
|
||||
|
||||
Copyright (C) 2009-2019 Olof Hagsand
|
||||
Copyright (C) 2020-2022 Olof Hagsand and Rubicon Communications, LLC(Netgate)
|
||||
|
||||
This file is part of CLIXON.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
Alternatively, the contents of this file may be used under the terms of
|
||||
the GNU General Public License Version 3 or later (the "GPL"),
|
||||
in which case the provisions of the GPL are applicable instead
|
||||
of those above. If you wish to allow use of your version of this file only
|
||||
under the terms of the GPL, and not to allow others to
|
||||
use your version of this file under the terms of Apache License version 2,
|
||||
indicate your decision by deleting the provisions above and replace them with
|
||||
the notice and other provisions required by the GPL. If you do not delete
|
||||
the provisions above, a recipient may use your version of this file under
|
||||
the terms of any one of the Apache License version 2 or the GPL.
|
||||
|
||||
***** END LICENSE BLOCK *****
|
||||
|
||||
* Evhtp specific HTTP/1 code complementing restconf_main_native.c
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "clixon_config.h" /* generated by config & autoconf */
|
||||
#endif
|
||||
|
||||
/* The clixon evhtp code can be compiled with or without threading support
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <syslog.h>
|
||||
#include <pwd.h>
|
||||
#include <ctype.h>
|
||||
#include <signal.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/socket.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/resource.h>
|
||||
|
||||
#include <openssl/ssl.h>
|
||||
|
||||
/* cligen */
|
||||
#include <cligen/cligen.h>
|
||||
|
||||
/* clicon */
|
||||
#include <clixon/clixon.h>
|
||||
|
||||
#ifdef HAVE_LIBEVHTP
|
||||
#include <event2/buffer.h> /* evbuffer */
|
||||
#define EVHTP_DISABLE_REGEX
|
||||
#define EVHTP_DISABLE_EVTHR
|
||||
|
||||
#include <evhtp/evhtp.h>
|
||||
|
||||
#endif /* HAVE_LIBEVHTP */
|
||||
|
||||
#ifdef HAVE_LIBNGHTTP2 /* To get restconf_native.h include files right */
|
||||
#include <nghttp2/nghttp2.h>
|
||||
#endif
|
||||
|
||||
/* restconf */
|
||||
#include "restconf_lib.h" /* generic shared with plugins */
|
||||
#include "restconf_handle.h"
|
||||
#include "restconf_api.h" /* generic not shared with plugins */
|
||||
#include "restconf_err.h"
|
||||
#include "restconf_root.h"
|
||||
#include "restconf_native.h" /* Restconf-openssl mode specific headers*/
|
||||
#ifdef HAVE_LIBEVHTP
|
||||
#include "restconf_evhtp.h" /* evhtp http/1 */
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LIBEVHTP
|
||||
static char*
|
||||
evhtp_method2str(enum htp_method m)
|
||||
{
|
||||
switch (m){
|
||||
case htp_method_GET:
|
||||
return "GET";
|
||||
break;
|
||||
case htp_method_HEAD:
|
||||
return "HEAD";
|
||||
break;
|
||||
case htp_method_POST:
|
||||
return "POST";
|
||||
break;
|
||||
case htp_method_PUT:
|
||||
return "PUT";
|
||||
break;
|
||||
case htp_method_DELETE:
|
||||
return "DELETE";
|
||||
break;
|
||||
case htp_method_OPTIONS:
|
||||
return "OPTIONS";
|
||||
break;
|
||||
case htp_method_PATCH:
|
||||
return "PATCH";
|
||||
break;
|
||||
#ifdef NOTUSED
|
||||
case htp_method_MKCOL:
|
||||
return "MKCOL";
|
||||
break;
|
||||
case htp_method_COPY:
|
||||
return "COPY";
|
||||
break;
|
||||
case htp_method_MOVE:
|
||||
return "MOVE";
|
||||
break;
|
||||
case htp_method_OPTIONS:
|
||||
return "OPTIONS";
|
||||
break;
|
||||
case htp_method_PROPFIND:
|
||||
return "PROPFIND";
|
||||
break;
|
||||
case htp_method_PROPPATCH:
|
||||
return "PROPPATCH";
|
||||
break;
|
||||
case htp_method_LOCK:
|
||||
return "LOCK";
|
||||
break;
|
||||
case htp_method_UNLOCK:
|
||||
return "UNLOCK";
|
||||
break;
|
||||
case htp_method_TRACE:
|
||||
return "TRACE";
|
||||
break;
|
||||
case htp_method_CONNECT:
|
||||
return "CONNECT";
|
||||
break;
|
||||
#endif /* NOTUSED */
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
evhtp_print_header(evhtp_header_t *header,
|
||||
void *arg)
|
||||
{
|
||||
clicon_debug(1, "%s %s %s", __FUNCTION__, header->key, header->val);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
evhtp_query_iterator(evhtp_header_t *hdr,
|
||||
void *arg)
|
||||
{
|
||||
cvec *qvec = (cvec *)arg;
|
||||
char *key;
|
||||
char *val;
|
||||
char *valu = NULL; /* unescaped value */
|
||||
cg_var *cv;
|
||||
|
||||
key = hdr->key;
|
||||
val = hdr->val;
|
||||
if (uri_percent_decode(val, &valu) < 0)
|
||||
return -1;
|
||||
if ((cv = cvec_add(qvec, CGV_STRING)) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "cvec_add");
|
||||
return -1;
|
||||
}
|
||||
cv_name_set(cv, key);
|
||||
cv_string_set(cv, valu);
|
||||
if (valu)
|
||||
free(valu);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! Translate http header by capitalizing, prepend w HTTP_ and - -> _
|
||||
* Example: Host -> HTTP_HOST
|
||||
*/
|
||||
static int
|
||||
evhtp_convert_fcgi(evhtp_header_t *hdr,
|
||||
void *arg)
|
||||
{
|
||||
clicon_handle h = (clicon_handle)arg;
|
||||
|
||||
return restconf_convert_hdr(h, hdr->key, hdr->val);
|
||||
}
|
||||
|
||||
/*! convert parameters from evhtp to fcgi-like parameters used by clixon
|
||||
*
|
||||
* While all these params come via one call in fcgi, the information must be taken from
|
||||
* several different places in evhtp
|
||||
* @param[in] h Clicon handle
|
||||
* @param[in] req Evhtp request struct
|
||||
* @param[out] qvec Query parameters, ie the ?<id>=<val>&<id>=<val> stuff
|
||||
* @retval 1 OK continue
|
||||
* @retval 0 Fail, dont continue
|
||||
* @retval -1 Error
|
||||
* The following parameters are set:
|
||||
* QUERY_STRING
|
||||
* REQUEST_METHOD
|
||||
* REQUEST_URI
|
||||
* HTTPS
|
||||
* HTTP_HOST
|
||||
* HTTP_ACCEPT
|
||||
* HTTP_CONTENT_TYPE
|
||||
* @note there may be more used by an application plugin
|
||||
*/
|
||||
static int
|
||||
convert_evhtp_params2clixon(clicon_handle h,
|
||||
evhtp_request_t *req,
|
||||
cvec *qvec)
|
||||
{
|
||||
int retval = -1;
|
||||
htp_method meth;
|
||||
evhtp_uri_t *uri;
|
||||
evhtp_path_t *path;
|
||||
evhtp_ssl_t *ssl = NULL;
|
||||
char *subject = NULL;
|
||||
cvec *cvv = NULL;
|
||||
char *cn;
|
||||
cxobj *xerr = NULL;
|
||||
int pretty;
|
||||
|
||||
if ((uri = req->uri) == NULL){
|
||||
clicon_err(OE_DAEMON, EFAULT, "No uri");
|
||||
goto done;
|
||||
}
|
||||
if ((path = uri->path) == NULL){
|
||||
clicon_err(OE_DAEMON, EFAULT, "No path");
|
||||
goto done;
|
||||
}
|
||||
meth = evhtp_request_get_method(req);
|
||||
|
||||
/* QUERY_STRING in fcgi but go direct to the info instead of putting it in a string?
|
||||
* This is different from all else: Ie one could have re-created a string here but
|
||||
* that would mean double parsing,...
|
||||
*/
|
||||
if (qvec && uri->query)
|
||||
if (evhtp_kvs_for_each(uri->query, evhtp_query_iterator, qvec) < 0){
|
||||
clicon_err(OE_CFG, errno, "evhtp_kvs_for_each");
|
||||
goto done;
|
||||
}
|
||||
if (restconf_param_set(h, "REQUEST_METHOD", evhtp_method2str(meth)) < 0)
|
||||
goto done;
|
||||
if (restconf_param_set(h, "REQUEST_URI", path->full) < 0)
|
||||
goto done;
|
||||
clicon_debug(1, "%s proto:%d", __FUNCTION__, req->proto);
|
||||
pretty = restconf_pretty_get(h);
|
||||
/* XXX: Any two http numbers seem accepted by evhtp, like 1.99, 99.3 as http/1.1*/
|
||||
if (req->proto != EVHTP_PROTO_10 &&
|
||||
req->proto != EVHTP_PROTO_11){
|
||||
if (netconf_invalid_value_xml(&xerr, "protocol", "Invalid HTTP version number") < 0)
|
||||
goto done;
|
||||
/* Select json as default since content-type header may not be accessible yet */
|
||||
if (api_return_err0(h, req, xerr, pretty, YANG_DATA_JSON, 0) < 0)
|
||||
goto done;
|
||||
goto fail;
|
||||
}
|
||||
clicon_debug(1, "%s conn->ssl:%d", __FUNCTION__, req->conn->ssl?1:0);
|
||||
/* Slightly awkward way of taking cert subject and CN and add it to restconf parameters
|
||||
* instead of accessing it directly */
|
||||
if ((ssl = req->conn->ssl) != NULL){
|
||||
if (restconf_param_set(h, "HTTPS", "https") < 0) /* some string or NULL */
|
||||
goto done;
|
||||
/* SSL subject fields, eg CN (Common Name) , can add more here? */
|
||||
if (ssl_x509_name_oneline(req->conn->ssl, &subject) < 0)
|
||||
goto done;
|
||||
if (subject != NULL) {
|
||||
if (uri_str2cvec(subject, '/', '=', 1, &cvv) < 0)
|
||||
goto done;
|
||||
if ((cn = cvec_find_str(cvv, "CN")) != NULL){
|
||||
if (restconf_param_set(h, "SSL_CN", cn) < 0) /* Can be used by callback */
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Translate all http headers by capitalizing, prepend w HTTP_ and - -> _
|
||||
* Example: Host -> HTTP_HOST
|
||||
*/
|
||||
if (evhtp_headers_for_each(req->headers_in, evhtp_convert_fcgi, h) < 0)
|
||||
goto done;
|
||||
retval = 1;
|
||||
done:
|
||||
clicon_debug(1, "%s %d", __FUNCTION__, retval);
|
||||
if (subject)
|
||||
free(subject);
|
||||
if (xerr)
|
||||
xml_free(xerr);
|
||||
if (cvv)
|
||||
cvec_free(cvv);
|
||||
return retval;
|
||||
fail:
|
||||
retval = 0;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*! We got -1 back from lower layers, create a 500 Internal Server error
|
||||
* Catch all on fatal error. This does not terminate the process but closes request
|
||||
* stream
|
||||
*/
|
||||
static int
|
||||
evhtp_internal_error(evhtp_request_t *req)
|
||||
{
|
||||
if (strlen(clicon_err_reason) &&
|
||||
req->buffer_out){
|
||||
evbuffer_add_printf(req->buffer_out, "%s", clicon_err_reason);
|
||||
evhtp_send_reply(req, EVHTP_RES_500);
|
||||
}
|
||||
clicon_err_reset();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! Send reply
|
||||
* @see htp__create_reply_
|
||||
*/
|
||||
static int
|
||||
native_send_reply(restconf_conn *rc,
|
||||
restconf_stream_data *sd,
|
||||
evhtp_request_t *req)
|
||||
{
|
||||
int retval = -1;
|
||||
|
||||
cg_var *cv;
|
||||
int minor;
|
||||
int major;
|
||||
|
||||
switch (req->proto) {
|
||||
case EVHTP_PROTO_10:
|
||||
if (req->flags & EVHTP_REQ_FLAG_KEEPALIVE) {
|
||||
/* protocol is HTTP/1.0 and clients wants to keep established */
|
||||
if (restconf_reply_header(sd, "Connection", "keep-alive") < 0)
|
||||
goto done;
|
||||
}
|
||||
major = htparser_get_major(req->conn->parser); /* XXX Look origin */
|
||||
minor = htparser_get_minor(req->conn->parser);
|
||||
break;
|
||||
case EVHTP_PROTO_11:
|
||||
if (!(req->flags & EVHTP_REQ_FLAG_KEEPALIVE)) {
|
||||
/* protocol is HTTP/1.1 but client wanted to close */
|
||||
if (restconf_reply_header(sd, "Connection", "keep-alive") < 0)
|
||||
goto done;
|
||||
}
|
||||
major = htparser_get_major(req->conn->parser);
|
||||
minor = htparser_get_minor(req->conn->parser);
|
||||
break;
|
||||
default:
|
||||
/* this sometimes happens when a response is made but paused before
|
||||
* the method has been parsed */
|
||||
major = 1;
|
||||
minor = 0;
|
||||
break;
|
||||
}
|
||||
cprintf(sd->sd_outp_buf, "HTTP/%u.%u %u %s\r\n",
|
||||
major,
|
||||
minor,
|
||||
sd->sd_code,
|
||||
restconf_code2reason(sd->sd_code));
|
||||
/* Loop over headers */
|
||||
cv = NULL;
|
||||
while ((cv = cvec_each(sd->sd_outp_hdrs, cv)) != NULL)
|
||||
cprintf(sd->sd_outp_buf, "%s: %s\r\n", cv_name_get(cv), cv_string_get(cv));
|
||||
cprintf(sd->sd_outp_buf, "\r\n");
|
||||
// cvec_reset(rc->rc_outp_hdrs); /* Is now done in restconf_connection but can be done here */
|
||||
retval = 0;
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*!
|
||||
*/
|
||||
static int
|
||||
restconf_evhtp_reply(restconf_conn *rc,
|
||||
restconf_stream_data *sd,
|
||||
evhtp_request_t *req)
|
||||
{
|
||||
int retval = -1;
|
||||
|
||||
req->status = sd->sd_code;
|
||||
req->flags |= EVHTP_REQ_FLAG_FINISHED; /* Signal to evhtp to read next request */
|
||||
/* 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
|
||||
* server MUST NOT send a Content-Length header field in any 2xx
|
||||
* (Successful) response to a CONNECT request (Section 4.3.6 of
|
||||
* [RFC7231]).
|
||||
*/
|
||||
if (sd->sd_code != 204 && sd->sd_code > 199)
|
||||
if (restconf_reply_header(sd, "Content-Length", "%zu", sd->sd_body_len) < 0)
|
||||
goto done;
|
||||
/* Create reply and write headers */
|
||||
if (native_send_reply(rc, sd, req) < 0)
|
||||
goto done;
|
||||
/* Write a body */
|
||||
if (sd->sd_body){
|
||||
cbuf_append_str(sd->sd_outp_buf, cbuf_get(sd->sd_body));
|
||||
}
|
||||
retval = 0;
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
#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.
|
||||
* @retval -1 Error
|
||||
* @retval 0 Yes, upgrade dont proceed with request
|
||||
* @retval 1 No upgrade, proceed with request
|
||||
* @note currently upgrade header is checked always if nghttp2 is configured but may be a
|
||||
* runtime config option
|
||||
*/
|
||||
static int
|
||||
evhtp_upgrade_http2(clicon_handle h,
|
||||
restconf_stream_data *sd)
|
||||
{
|
||||
int retval = -1;
|
||||
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;
|
||||
if (api_return_err0(h, sd, xerr, 1, YANG_DATA_JSON, 0) < 0)
|
||||
goto done;
|
||||
if (xerr)
|
||||
xml_free(xerr);
|
||||
}
|
||||
else {
|
||||
if (restconf_reply_header(sd, "Connection", "Upgrade") < 0)
|
||||
goto done;
|
||||
if (restconf_reply_header(sd, "Upgrade", "h2c") < 0)
|
||||
goto done;
|
||||
if (restconf_reply_send(sd, 101, NULL, 0) < 0) /* Swithcing protocols */
|
||||
goto done;
|
||||
/* Signal http/2 upgrade to http/2 to upper restconf_connection handling */
|
||||
sd->sd_upgrade2 = 1;
|
||||
if ((settings = restconf_param_get(h, "HTTP_HTTP2_Settings")) != NULL &&
|
||||
(sd->sd_settings2 = (uint8_t*)strdup(settings)) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "strdup");
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
retval = 0; /* Yes, upgrade or error */
|
||||
}
|
||||
else
|
||||
retval = 1; /* No upgrade, proceed with request */
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
#endif /* HAVE_LIBNGHTTP2 */
|
||||
|
||||
/*! Callback for each incoming http request for path /
|
||||
*
|
||||
* This are all messages except /.well-known, Registered with evhtp_set_cb
|
||||
*
|
||||
* @param[in] req evhtp http request structure defining the incoming message
|
||||
* @param[in] arg cx_evhtp handle clixon specific fields
|
||||
* @retval void
|
||||
* Discussion: problematic if fatal error -1 is returneod from clixon routines
|
||||
* without actually terminating. Consider:
|
||||
* 1) sending some error? and/or
|
||||
* 2) terminating the process?
|
||||
*/
|
||||
void
|
||||
restconf_path_root(evhtp_request_t *req,
|
||||
void *arg)
|
||||
{
|
||||
int retval = -1;
|
||||
clicon_handle h;
|
||||
int ret;
|
||||
evhtp_connection_t *evconn;
|
||||
restconf_conn *rc;
|
||||
restconf_stream_data *sd;
|
||||
size_t len;
|
||||
unsigned char *buf;
|
||||
int keep_params = 0; /* set to 1 if dont delete params */
|
||||
|
||||
clicon_debug(1, "------------");
|
||||
if ((h = (clicon_handle)arg) == NULL){
|
||||
clicon_err(OE_RESTCONF, EINVAL, "arg is NULL");
|
||||
evhtp_internal_error(req);
|
||||
goto done;
|
||||
}
|
||||
/* evhtp connect struct */
|
||||
if ((evconn = evhtp_request_get_connection(req)) == NULL){
|
||||
clicon_err(OE_DAEMON, EFAULT, "evhtp_request_get_connection");
|
||||
evhtp_internal_error(req);
|
||||
goto done;
|
||||
}
|
||||
/* get clixon request connect pointer from generic evhtp application pointer */
|
||||
rc = evconn->arg;
|
||||
if ((sd = restconf_stream_find(rc, 0)) == NULL){
|
||||
clicon_err(OE_RESTCONF, EINVAL, "No stream_data");
|
||||
evhtp_internal_error(req);
|
||||
goto done;
|
||||
}
|
||||
sd->sd_req = req;
|
||||
sd->sd_proto = (req->proto == EVHTP_PROTO_10)?HTTP_10:HTTP_11;
|
||||
/* input debug */
|
||||
if (clicon_debug_get())
|
||||
evhtp_headers_for_each(req->headers_in, evhtp_print_header, h);
|
||||
/* Query vector, ie the ?a=x&b=y stuff */
|
||||
if (sd->sd_qvec)
|
||||
cvec_free(sd->sd_qvec);
|
||||
if ((sd->sd_qvec = cvec_new(0)) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "cvec_new");
|
||||
evhtp_internal_error(req);
|
||||
goto done;
|
||||
}
|
||||
/* Get indata
|
||||
*/
|
||||
if ((len = evbuffer_get_length(req->buffer_in)) > 0){
|
||||
if ((buf = evbuffer_pullup(req->buffer_in, len)) == NULL){
|
||||
clicon_err(OE_CFG, errno, "evbuffer_pullup");
|
||||
goto done;
|
||||
}
|
||||
cbuf_reset(sd->sd_indata);
|
||||
/* Note the pullup may not be null-terminated */
|
||||
cbuf_append_buf(sd->sd_indata, buf, len);
|
||||
}
|
||||
/* Convert parameters from evhtp to fcgi-like parameters used by clixon
|
||||
* ret = 0 means an error has already been sent
|
||||
*/
|
||||
if ((ret = convert_evhtp_params2clixon(h, req, sd->sd_qvec)) < 0){
|
||||
evhtp_internal_error(req);
|
||||
goto done;
|
||||
}
|
||||
/* Check sanity of session, eg ssl client cert validation, may set rc_exit */
|
||||
if (restconf_connection_sanity(h, rc, sd) < 0)
|
||||
goto done;
|
||||
if (rc->rc_exit == 0){
|
||||
#ifdef HAVE_LIBNGHTTP2
|
||||
if (ret == 1){
|
||||
if ((ret = evhtp_upgrade_http2(h, sd)) < 0){
|
||||
evhtp_internal_error(req);
|
||||
goto done;
|
||||
}
|
||||
if (ret == 0)
|
||||
keep_params = 1;
|
||||
}
|
||||
#endif
|
||||
if (ret == 1){
|
||||
/* call generic function */
|
||||
if (api_root_restconf(h, sd, sd->sd_qvec) < 0){
|
||||
evhtp_internal_error(req);
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Clear input request parameters from this request */
|
||||
if (!keep_params && restconf_param_del_all(h) < 0){
|
||||
evhtp_internal_error(req);
|
||||
goto done;
|
||||
}
|
||||
/* All parameters for sending a reply are here
|
||||
*/
|
||||
if (sd->sd_code){
|
||||
if (restconf_evhtp_reply(rc, sd, req) < 0){
|
||||
evhtp_internal_error(req);
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
retval = 0;
|
||||
done:
|
||||
clicon_debug(1, "%s %d", __FUNCTION__, retval);
|
||||
return; /* void */
|
||||
}
|
||||
|
||||
/*! /.well-known callback
|
||||
*
|
||||
* @param[in] req evhtp http request structure defining the incoming message
|
||||
* @param[in] arg cx_evhtp handle clixon specific fields
|
||||
* @retval void
|
||||
*/
|
||||
void
|
||||
restconf_path_wellknown(evhtp_request_t *req,
|
||||
void *arg)
|
||||
{
|
||||
int retval = -1;
|
||||
clicon_handle h;
|
||||
int ret;
|
||||
evhtp_connection_t *evconn;
|
||||
restconf_conn *rc;
|
||||
restconf_stream_data *sd;
|
||||
int keep_params = 0; /* set to 1 if dont delete params */
|
||||
|
||||
clicon_debug(1, "------------");
|
||||
if ((h = (clicon_handle)arg) == NULL){
|
||||
clicon_err(OE_RESTCONF, EINVAL, "arg is NULL");
|
||||
evhtp_internal_error(req);
|
||||
goto done;
|
||||
}
|
||||
/* evhtp connect struct */
|
||||
if ((evconn = evhtp_request_get_connection(req)) == NULL){
|
||||
clicon_err(OE_DAEMON, EFAULT, "evhtp_request_get_connection");
|
||||
evhtp_internal_error(req);
|
||||
goto done;
|
||||
}
|
||||
/* get clixon request connect pointer from generic evhtp application pointer */
|
||||
rc = evconn->arg;
|
||||
if ((sd = restconf_stream_find(rc, 0)) == NULL){
|
||||
clicon_err(OE_RESTCONF, EINVAL, "No stream_data");
|
||||
evhtp_internal_error(req);
|
||||
goto done;
|
||||
}
|
||||
sd->sd_req = req;
|
||||
sd->sd_proto = (req->proto == EVHTP_PROTO_10)?HTTP_10:HTTP_11;
|
||||
/* input debug */
|
||||
if (clicon_debug_get())
|
||||
evhtp_headers_for_each(req->headers_in, evhtp_print_header, h);
|
||||
/* Query vector, ie the ?a=x&b=y stuff */
|
||||
if ((sd->sd_qvec = cvec_new(0)) ==NULL){
|
||||
clicon_err(OE_UNIX, errno, "cvec_new");
|
||||
evhtp_internal_error(req);
|
||||
goto done;
|
||||
}
|
||||
/* Convert parameters from evhtp to fcgi-like parameters used by clixon
|
||||
* ret = 0 means an error has already been sent
|
||||
*/
|
||||
if ((ret = convert_evhtp_params2clixon(h, req, sd->sd_qvec)) < 0){
|
||||
evhtp_internal_error(req);
|
||||
goto done;
|
||||
}
|
||||
/* Check sanity of session, eg ssl client cert validation, may set rc_exit */
|
||||
if (restconf_connection_sanity(h, rc, sd) < 0)
|
||||
goto done;
|
||||
if (rc->rc_exit == 0){
|
||||
#ifdef HAVE_LIBNGHTTP2
|
||||
if (ret == 1){
|
||||
if ((ret = evhtp_upgrade_http2(h, sd)) < 0){
|
||||
evhtp_internal_error(req);
|
||||
goto done;
|
||||
}
|
||||
if (ret == 0)
|
||||
keep_params = 1;
|
||||
}
|
||||
#endif
|
||||
if (ret == 1){
|
||||
/* call generic function */
|
||||
if (api_well_known(h, sd) < 0){
|
||||
evhtp_internal_error(req);
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Clear input request parameters from this request */
|
||||
if (!keep_params && restconf_param_del_all(h) < 0){
|
||||
evhtp_internal_error(req);
|
||||
goto done;
|
||||
}
|
||||
/* All parameters for sending a reply are here
|
||||
*/
|
||||
if (sd->sd_code){
|
||||
if (restconf_evhtp_reply(rc, sd, req) < 0){
|
||||
evhtp_internal_error(req);
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
retval = 0;
|
||||
done:
|
||||
clicon_debug(1, "%s %d", __FUNCTION__, retval);
|
||||
return; /* void */
|
||||
}
|
||||
#endif /* HAVE_LIBEVHTP */
|
||||
|
||||
|
|
@ -44,7 +44,6 @@
|
|||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <inttypes.h>
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
|
|
|
|||
|
|
@ -49,18 +49,6 @@
|
|||
* +--------------------+
|
||||
* Note restconf_request may need to be extended eg backpointer to rs?
|
||||
*
|
||||
* +--------------------+ +--------------------+
|
||||
* | evhtp_connection | -----> | evhtp_t (core) |
|
||||
* +--------------------+ +--------------------+
|
||||
* |request ^
|
||||
* v | conn
|
||||
* +--------------------+ +--------------------+
|
||||
* | evhtp_request | --> uri | evhtp_uri |
|
||||
* +--------------------+ +--------------------+
|
||||
* | (created by parser) | | |
|
||||
* v v v v
|
||||
* headers/buffers/method/... authority path query
|
||||
*
|
||||
* Buffer handling:
|
||||
* c
|
||||
* |
|
||||
|
|
@ -121,12 +109,6 @@
|
|||
#include "clixon_config.h" /* generated by config & autoconf */
|
||||
#endif
|
||||
|
||||
/* The clixon evhtp code can be compiled with or without threading support
|
||||
* The choice is set at libevhtp compile time by cmake. Eg:
|
||||
* cmake -DEVHTP_DISABLE_EVTHR=ON # Disable threads.
|
||||
* Default in testing is disabled threads.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
|
@ -151,16 +133,6 @@
|
|||
/* clicon */
|
||||
#include <clixon/clixon.h>
|
||||
|
||||
#ifdef HAVE_LIBEVHTP
|
||||
/* evhtp */
|
||||
#include <event2/buffer.h> /* evbuffer */
|
||||
#define EVHTP_DISABLE_REGEX
|
||||
#define EVHTP_DISABLE_EVTHR
|
||||
|
||||
#include <evhtp/evhtp.h>
|
||||
|
||||
#endif /* HAVE_LIBEVHTP */
|
||||
|
||||
#ifdef HAVE_LIBNGHTTP2
|
||||
/* nghttp2 */
|
||||
#include <nghttp2/nghttp2.h>
|
||||
|
|
@ -173,12 +145,12 @@
|
|||
#include "restconf_err.h"
|
||||
#include "restconf_root.h"
|
||||
#include "restconf_native.h" /* Restconf-openssl mode specific headers*/
|
||||
#ifdef HAVE_LIBEVHTP
|
||||
#include "restconf_evhtp.h" /* http/1 */
|
||||
#endif
|
||||
#ifdef HAVE_LIBNGHTTP2
|
||||
#include "restconf_nghttp2.h" /* http/2 */
|
||||
#endif
|
||||
#ifdef HAVE_HTTP1
|
||||
#include "clixon_http1.h"
|
||||
#endif
|
||||
|
||||
/* Command line options to be passed to getopt(3) */
|
||||
#define RESTCONF_OPTS "hD:f:E:l:p:y:a:u:rW:R:o:"
|
||||
|
|
@ -352,9 +324,7 @@ clixon_openssl_log_cb(void *handle,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* see restconf_config ->cv_evhtp_init(x2) -> cx_evhtp_socket ->
|
||||
* evhtp_ssl_init:4757
|
||||
/*! Init openSSL
|
||||
*/
|
||||
static int
|
||||
init_openssl(void)
|
||||
|
|
@ -425,7 +395,7 @@ restconf_verify_certs(int preverify_ok,
|
|||
* - 0 (preferity_ok) the session terminates here in SSL negotiation, an http client
|
||||
* will get a low level error (not http reply)
|
||||
* - 1 Check if the cert is valid using SSL_get_verify_result(rc->rc_ssl)
|
||||
* @see restconf_evhtp_sanity and restconf_nghttp2_sanity where this is done for http/1 and http/2
|
||||
* @see restconf_nghttp2_sanity where this is done for http/1 and http/2
|
||||
*/
|
||||
return 1;
|
||||
}
|
||||
|
|
@ -479,7 +449,7 @@ alpn_select_proto_cb(SSL *ssl,
|
|||
inp++;
|
||||
if (clicon_debug_get()) /* debug print the protoocol */
|
||||
alpn_proto_dump(__FUNCTION__, (const char*)inp, len);
|
||||
#ifdef HAVE_LIBEVHTP
|
||||
#ifdef HAVE_HTTP1
|
||||
if (pref < 10 && len == 8 && strncmp((char*)inp, "http/1.1", len) == 0){
|
||||
*outlen = len;
|
||||
*out = inp;
|
||||
|
|
@ -503,8 +473,6 @@ alpn_select_proto_cb(SSL *ssl,
|
|||
}
|
||||
|
||||
/*
|
||||
* see restconf_config ->cv_evhtp_init(x2) -> cx_evhtp_socket ->
|
||||
* evhtp_ssl_init:4794
|
||||
*/
|
||||
static SSL_CTX *
|
||||
restconf_ssl_context_create(clicon_handle h)
|
||||
|
|
@ -535,8 +503,6 @@ restconf_ssl_context_create(clicon_handle h)
|
|||
}
|
||||
|
||||
/*
|
||||
* see restconf_config ->cv_evhtp_init(x2) -> cx_evhtp_socket ->
|
||||
* evhtp_ssl_init: 4886
|
||||
* @param[in] ctx SSL context
|
||||
* @param[in] server_cert_path Server cert
|
||||
* @param[in] server_key_path Server private key
|
||||
|
|
@ -595,7 +561,7 @@ restconf_ssl_context_configure(clixon_handle h,
|
|||
return retval;
|
||||
}
|
||||
|
||||
/*! Utility function to close restconf server ssl/evhtp socket.
|
||||
/*! 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.
|
||||
*/
|
||||
|
|
@ -618,10 +584,6 @@ Note that in this case SSL_ERROR_ZERO_RETURN does not necessarily indicate that
|
|||
}
|
||||
SSL_free(rc->rc_ssl);
|
||||
rc->rc_ssl = NULL;
|
||||
#ifdef HAVE_LIBEVHTP
|
||||
if (rc->rc_evconn)
|
||||
rc->rc_evconn->ssl = NULL;
|
||||
#endif
|
||||
}
|
||||
if (close(rc->rc_s) < 0){
|
||||
clicon_err(OE_UNIX, errno, "close");
|
||||
|
|
@ -675,7 +637,67 @@ send_badrequest(clicon_handle h,
|
|||
return retval;
|
||||
}
|
||||
|
||||
/*! New data connection after accept, receive and reply on data sockte
|
||||
#if 0
|
||||
#define IFILE "/var/tmp/clixon-mirror/ifile"
|
||||
#define FMTDIR "/var/tmp/clixon-mirror/"
|
||||
|
||||
static FILE *myf = NULL;
|
||||
|
||||
static int
|
||||
mirror_pkt(const char *buf,
|
||||
ssize_t n)
|
||||
{
|
||||
int retval = -1;
|
||||
|
||||
if (fwrite(buf, 1, n, myf) != n){
|
||||
perror("fopen");
|
||||
goto done;
|
||||
}
|
||||
retval = 0;
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int
|
||||
mirror_new(void)
|
||||
{
|
||||
int retval = -1;
|
||||
static uint64_t u64 = 0;
|
||||
cbuf *cb = cbuf_new();
|
||||
FILE *ifile;
|
||||
|
||||
if ((ifile = fopen(IFILE, "r+")) == NULL){
|
||||
perror("fopen r+ ifile");
|
||||
}
|
||||
else {
|
||||
if (fscanf(ifile, "%" PRIu64, &u64) < 0){
|
||||
perror("fscanf ifile");
|
||||
goto done;
|
||||
}
|
||||
fclose(ifile);
|
||||
}
|
||||
if (myf != NULL)
|
||||
fclose(myf);
|
||||
cprintf(cb, FMTDIR "%" PRIu64 ".dump", u64);
|
||||
if ((myf = fopen(cbuf_get(cb), "w")) == NULL){
|
||||
perror("fopen");
|
||||
goto done;
|
||||
}
|
||||
cbuf_free(cb);
|
||||
u64++;
|
||||
if ((ifile = fopen(IFILE, "w")) == NULL){
|
||||
perror("fopen w+ ifile");
|
||||
goto done;
|
||||
}
|
||||
fprintf(ifile, "%" PRIu64, u64);
|
||||
fclose(ifile);
|
||||
retval = 0;
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*! New data connection after accept, receive and reply on data socket
|
||||
*
|
||||
* @param[in] s Socket where message arrived. read from this.
|
||||
* @param[in] arg Client entry (from).
|
||||
|
|
@ -683,10 +705,10 @@ send_badrequest(clicon_handle h,
|
|||
* @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: either evhtp returns a buffer
|
||||
* @note read buffer is limited. More data can be read in two ways: returns a buffer
|
||||
* with 100 Continue, in which case that is replied and the function returns and the client sends
|
||||
* more data.
|
||||
* OR evhtp returns 0 with no reply, then this is assumed to mean read more data from the socket.
|
||||
* OR returns 0 with no reply, then this is assumed to mean read more data from the socket.
|
||||
*/
|
||||
static int
|
||||
restconf_connection(int s,
|
||||
|
|
@ -701,9 +723,8 @@ restconf_connection(int s,
|
|||
#ifdef HAVE_LIBNGHTTP2
|
||||
int ret;
|
||||
#endif
|
||||
#ifdef HAVE_LIBEVHTP
|
||||
#ifdef HAVE_HTTP1
|
||||
clicon_handle h;
|
||||
evhtp_connection_t *evconn = NULL;
|
||||
restconf_stream_data *sd;
|
||||
#endif
|
||||
|
||||
|
|
@ -765,7 +786,7 @@ restconf_connection(int s,
|
|||
continue;
|
||||
}
|
||||
}
|
||||
clicon_debug(1, "%s (ssl)read:%zd", __FUNCTION__, n);
|
||||
clicon_debug(1, "%s read:%zd", __FUNCTION__, n);
|
||||
if (n == 0){
|
||||
clicon_debug(1, "%s n=0 closing socket", __FUNCTION__);
|
||||
if (restconf_close_ssl_socket(rc, 0) < 0)
|
||||
|
|
@ -774,99 +795,43 @@ restconf_connection(int s,
|
|||
rc = NULL;
|
||||
goto ok;
|
||||
}
|
||||
#if 0
|
||||
if (mirror_pkt(buf, n) < 0)
|
||||
goto done;
|
||||
#endif
|
||||
switch (rc->rc_proto){
|
||||
#ifdef HAVE_LIBEVHTP
|
||||
#ifdef HAVE_HTTP1
|
||||
case HTTP_10:
|
||||
case HTTP_11:
|
||||
h = rc->rc_h;
|
||||
/* parse incoming packet using evhtp
|
||||
* signature:
|
||||
*/
|
||||
evconn = rc->rc_evconn;
|
||||
/* This is the main call to EVHTP parser */
|
||||
if (connection_parse_nobev(buf, n, evconn) < 0){
|
||||
clicon_debug(1, "%s connection_parse error", __FUNCTION__);
|
||||
/* XXX To get more nuanced evhtp error check
|
||||
* htparser_get_error(conn->parser)
|
||||
*/
|
||||
if (clixon_http1_parse_buf(h, rc, buf, n) < 0){
|
||||
if (send_badrequest(h, rc->rc_s, rc->rc_ssl, "application/yang-data+xml",
|
||||
"<errors xmlns=\"urn:ietf:params:xml:ns:yang:ietf-restconf\"><error><error-type>protocol</error-type><error-tag>malformed-message</error-tag><error-message>The requested URL or a header is in some way badly formed</error-message></error></errors>") < 0)
|
||||
goto done;
|
||||
SSL_free(rc->rc_ssl);
|
||||
rc->rc_ssl = NULL;
|
||||
evconn->ssl = NULL;
|
||||
if (close(rc->rc_s) < 0){
|
||||
clicon_err(OE_UNIX, errno, "close");
|
||||
}
|
||||
else{
|
||||
if (restconf_http1_path_root(h, rc) < 0)
|
||||
goto done;
|
||||
}
|
||||
clixon_event_unreg_fd(rc->rc_s, restconf_connection);
|
||||
clicon_debug(1, "%s evconn-free (%p) 2", __FUNCTION__, evconn);
|
||||
restconf_conn_free(rc);
|
||||
goto ok;
|
||||
} /* connection_parse_nobev */
|
||||
}
|
||||
clicon_debug(1, "%s connection_parse OK", __FUNCTION__);
|
||||
/* default stream */
|
||||
if ((sd = restconf_stream_find(rc, 0)) == NULL){
|
||||
clicon_err(OE_RESTCONF, EINVAL, "restconf stream not found");
|
||||
goto done;
|
||||
}
|
||||
if (evconn->bev != NULL){
|
||||
struct evbuffer *ev;
|
||||
size_t buflen0;
|
||||
size_t buflen1;
|
||||
char *buf = NULL;
|
||||
|
||||
if ((ev = bufferevent_get_output(evconn->bev)) != NULL){
|
||||
buflen0 = evbuffer_get_length(ev);
|
||||
buflen1 = buflen0 - rc->rc_bufferevent_output_offset;
|
||||
if (buflen1 > 0){
|
||||
buf = (char*)evbuffer_pullup(ev, -1);
|
||||
/* XXX Here if -1 in api_root
|
||||
* HTTP/1.1 0 UNKNOWN\r\nContent-Length: 0
|
||||
* And output_buffer is NULL
|
||||
*/
|
||||
/* If evhtp has print an output buffer, clixon whould not have done it
|
||||
* Shouldnt happen
|
||||
*/
|
||||
if (cbuf_len(sd->sd_outp_buf)){
|
||||
clicon_debug(1, "%s Warning: evhtp printed output buffer, but clixon output buffer is non-empty %s",
|
||||
__FUNCTION__, cbuf_get(sd->sd_outp_buf));
|
||||
cbuf_reset(sd->sd_outp_buf);
|
||||
}
|
||||
if (cbuf_append_buf(sd->sd_outp_buf, buf, buflen1) < 0){
|
||||
clicon_err(OE_UNIX, errno, "cbuf_append_buf");
|
||||
goto done;
|
||||
}
|
||||
/* XXX Cant get drain to work, need to keep an offset */
|
||||
evbuffer_drain(ev, -1);
|
||||
rc->rc_bufferevent_output_offset += buflen1;
|
||||
}
|
||||
}
|
||||
if (cbuf_len(sd->sd_outp_buf) == 0)
|
||||
readmore = 1;
|
||||
else {
|
||||
if (buf_write(cbuf_get(sd->sd_outp_buf), cbuf_len(sd->sd_outp_buf),
|
||||
rc->rc_s, rc->rc_ssl) < 0)
|
||||
goto done;
|
||||
cvec_reset(sd->sd_outp_hdrs); /* Can be done in native_send_reply */
|
||||
cbuf_reset(sd->sd_outp_buf);
|
||||
}
|
||||
}
|
||||
else{
|
||||
if (send_badrequest(h, rc->rc_s, rc->rc_ssl, "application/yang-data+xml",
|
||||
"<errors xmlns=\"urn:ietf:params:xml:ns:yang:ietf-restconf\"><error><error-type>protocol</error-type><error-tag>malformed-message</error-tag><error-message>No evhtp output</error-message></error></errors>") < 0)
|
||||
goto done;
|
||||
}
|
||||
if (buf_write(cbuf_get(sd->sd_outp_buf), cbuf_len(sd->sd_outp_buf),
|
||||
rc->rc_s, rc->rc_ssl) < 0)
|
||||
goto done;
|
||||
cvec_reset(sd->sd_outp_hdrs); /* Can be done in native_send_reply */
|
||||
cbuf_reset(sd->sd_outp_buf);
|
||||
if (rc->rc_exit){ /* Server-initiated exit for http/2 */
|
||||
SSL_free(rc->rc_ssl);
|
||||
rc->rc_ssl = NULL;
|
||||
evconn->ssl = NULL;
|
||||
if (close(rc->rc_s) < 0){
|
||||
clicon_err(OE_UNIX, errno, "close");
|
||||
goto done;
|
||||
}
|
||||
clixon_event_unreg_fd(rc->rc_s, restconf_connection);
|
||||
clicon_debug(1, "%s evconn-free (%p) 2", __FUNCTION__, evconn);
|
||||
restconf_conn_free(rc);
|
||||
goto ok;
|
||||
}
|
||||
|
|
@ -916,7 +881,7 @@ restconf_connection(int s,
|
|||
}
|
||||
#endif
|
||||
break;
|
||||
#endif /* HAVE_LIBEVHTP */
|
||||
#endif /* HAVE_HTTP1 */
|
||||
#ifdef HAVE_LIBNGHTTP2
|
||||
case HTTP_2:
|
||||
if (rc->rc_exit){ /* Server-initiated exit for http/2 */
|
||||
|
|
@ -1119,10 +1084,9 @@ restconf_accept_client(int fd,
|
|||
|
||||
clicon_debug(1, "%s %d", __FUNCTION__, fd);
|
||||
#ifdef HAVE_LIBNGHTTP2
|
||||
#ifndef HAVE_LIBEVHTP
|
||||
#ifndef HAVE_HTTP1
|
||||
proto = HTTP_2; /* If nghttp2 only let default be 2.0 */
|
||||
#endif
|
||||
/* If also evhtp, keep HTTP_11 */
|
||||
#endif
|
||||
if ((rsock = (restconf_socket *)arg) == NULL){
|
||||
clicon_err(OE_YANG, EINVAL, "rsock is NULL");
|
||||
|
|
@ -1313,28 +1277,14 @@ restconf_accept_client(int fd,
|
|||
} /* if ssl */
|
||||
rc->rc_proto = proto;
|
||||
switch (rc->rc_proto){
|
||||
#ifdef HAVE_LIBEVHTP
|
||||
#ifdef HAVE_HTTP1
|
||||
case HTTP_10:
|
||||
case HTTP_11:{
|
||||
evhtp_t *evhtp = (evhtp_t *)rh->rh_arg;
|
||||
evhtp_connection_t *evconn;
|
||||
|
||||
/* Create evhtp-specific struct */
|
||||
if ((evconn = evhtp_connection_new_server(evhtp, rc->rc_s)) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "evhtp_connection_new_server");
|
||||
goto done;
|
||||
}
|
||||
/* Mutual pointers, from generic rc to evhtp specific and from evhtp conn to generic
|
||||
*/
|
||||
rc->rc_evconn = evconn; /* Generic to specific */
|
||||
evconn->arg = rc; /* Specific to generic */
|
||||
evconn->ssl = rc->rc_ssl; /* evhtp */
|
||||
case HTTP_11:
|
||||
/* Create a default stream for http/1 */
|
||||
if (restconf_stream_data_new(rc, 0) == NULL)
|
||||
goto done;
|
||||
}
|
||||
break;
|
||||
#endif /* HAVE_LIBEVHTP */
|
||||
#endif /* HAVE_HTTP1 */
|
||||
#ifdef HAVE_LIBNGHTTP2
|
||||
case HTTP_2:{
|
||||
if (http2_session_init(rc) < 0){
|
||||
|
|
@ -1365,6 +1315,10 @@ restconf_accept_client(int fd,
|
|||
default:
|
||||
break;
|
||||
} /* switch proto */
|
||||
#if 0
|
||||
if (mirror_new() < 0)
|
||||
goto done;
|
||||
#endif
|
||||
if (clixon_event_reg_fd(rc->rc_s, restconf_connection, (void*)rc, "restconf client socket") < 0)
|
||||
goto done;
|
||||
ok:
|
||||
|
|
@ -1376,6 +1330,8 @@ restconf_accept_client(int fd,
|
|||
return retval;
|
||||
} /* restconf_accept_client */
|
||||
|
||||
/*!
|
||||
*/
|
||||
static int
|
||||
restconf_native_terminate(clicon_handle h)
|
||||
{
|
||||
|
|
@ -1396,18 +1352,6 @@ restconf_native_terminate(clicon_handle h)
|
|||
}
|
||||
if (rh->rh_ctx)
|
||||
SSL_CTX_free(rh->rh_ctx);
|
||||
#ifdef HAVE_LIBEVHTP
|
||||
{
|
||||
evhtp_t *evhtp = (evhtp_t *)rh->rh_arg;
|
||||
if (evhtp){
|
||||
if (evhtp->evbase)
|
||||
event_base_free(evhtp->evbase);
|
||||
evhtp_free(evhtp);
|
||||
rh->rh_arg = NULL;
|
||||
}
|
||||
}
|
||||
#endif /* HAVE_LIBEVHTP */
|
||||
|
||||
free(rh);
|
||||
}
|
||||
EVP_cleanup();
|
||||
|
|
@ -1581,10 +1525,6 @@ restconf_openssl_init(clicon_handle h,
|
|||
cxobj **vec = NULL;
|
||||
size_t veclen;
|
||||
int i;
|
||||
#ifdef HAVE_LIBEVHTP
|
||||
evhtp_t *evhtp = NULL;
|
||||
struct event_base *evbase = NULL;
|
||||
#endif /* HAVE_LIBEVHTP */
|
||||
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
/* flag used for sanity of certs */
|
||||
|
|
@ -1639,28 +1579,6 @@ restconf_openssl_init(clicon_handle h,
|
|||
}
|
||||
rh = restconf_native_handle_get(h);
|
||||
rh->rh_ctx = ctx;
|
||||
#ifdef HAVE_LIBEVHTP
|
||||
/* evhtp stuff */ /* XXX move this to global level */
|
||||
if ((evbase = event_base_new()) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "event_base_new");
|
||||
goto done;
|
||||
}
|
||||
/* This is socket create a new evhtp_t instance */
|
||||
if ((evhtp = evhtp_new((void*)evbase, h)) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "evhtp_new");
|
||||
goto done;
|
||||
}
|
||||
rh->rh_arg = evhtp;
|
||||
if (evhtp_set_cb(evhtp, "/" RESTCONF_API, restconf_path_root, h) == NULL){
|
||||
clicon_err(OE_EVENTS, errno, "evhtp_set_cb");
|
||||
goto done;
|
||||
}
|
||||
/* Callback to be executed for all /restconf api calls */
|
||||
if (evhtp_set_cb(evhtp, RESTCONF_WELL_KNOWN, restconf_path_wellknown, h) == NULL){
|
||||
clicon_err(OE_EVENTS, errno, "evhtp_set_cb");
|
||||
goto done;
|
||||
}
|
||||
#endif /* HAVE_LIBEVHTP */
|
||||
/* get the list of socket config-data */
|
||||
if (xpath_vec(xrestconf, nsc, "socket", &vec, &veclen) < 0)
|
||||
goto done;
|
||||
|
|
|
|||
|
|
@ -66,14 +66,7 @@
|
|||
#include "restconf_lib.h" /* generic shared with plugins */
|
||||
#include "restconf_handle.h"
|
||||
#include "restconf_err.h"
|
||||
#ifdef HAVE_LIBEVHTP
|
||||
#include <event2/buffer.h> /* evbuffer */
|
||||
#define EVHTP_DISABLE_REGEX
|
||||
#define EVHTP_DISABLE_EVTHR
|
||||
|
||||
#include <evhtp/evhtp.h>
|
||||
|
||||
#endif
|
||||
#ifdef HAVE_LIBNGHTTP2
|
||||
#include <nghttp2/nghttp2.h>
|
||||
#endif
|
||||
|
|
@ -167,7 +160,7 @@ restconf_conn_new(clicon_handle h,
|
|||
return rc;
|
||||
}
|
||||
|
||||
/*! Free clixon/cbuf resources related to an evhtp connection
|
||||
/*! Free clixon/cbuf resources related to a connection
|
||||
* @param[in] rc restconf connection
|
||||
*/
|
||||
int
|
||||
|
|
@ -182,10 +175,6 @@ restconf_conn_free(restconf_conn *rc)
|
|||
#ifdef HAVE_LIBNGHTTP2
|
||||
if (rc->rc_ngsession)
|
||||
nghttp2_session_del(rc->rc_ngsession);
|
||||
#endif
|
||||
#ifdef HAVE_LIBEVHTP
|
||||
if (rc->rc_evconn)
|
||||
evhtp_connection_free(rc->rc_evconn); /* evhtp */
|
||||
#endif
|
||||
/* Free all streams */
|
||||
while ((sd = rc->rc_streams) != NULL) {
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ typedef struct {
|
|||
struct restconf_conn *sd_conn; /* Backpointer to connection this stream is part of */
|
||||
restconf_http_proto sd_proto; /* http protocol XXX not sure this is needed */
|
||||
cvec *sd_qvec; /* Query parameters, ie ?a=b&c=d */
|
||||
void *sd_req; /* Lib-specific request, eg evhtp_request_t * */
|
||||
void *sd_req; /* Lib-specific request */
|
||||
int sd_upgrade2; /* Upgrade to http/2 */
|
||||
uint8_t *sd_settings2; /* Settings for upgrade to http/2 request */
|
||||
} restconf_stream_data;
|
||||
|
|
@ -98,9 +98,6 @@ typedef struct restconf_conn {
|
|||
int rc_exit; /* Set to close socket server-side (NYI) */
|
||||
/* Decision to keep lib-specific data here, otherwise new struct necessary
|
||||
* drawback is specific includes need to go everywhere */
|
||||
#ifdef HAVE_LIBEVHTP
|
||||
evhtp_connection_t *rc_evconn;
|
||||
#endif
|
||||
#ifdef HAVE_LIBNGHTTP2
|
||||
nghttp2_session *rc_ngsession; /* XXX Not sure it is needed */
|
||||
#endif
|
||||
|
|
@ -125,7 +122,7 @@ typedef struct {
|
|||
typedef struct {
|
||||
SSL_CTX *rh_ctx; /* SSL context */
|
||||
restconf_socket *rh_sockets; /* List of restconf server (ready for accept) sockets */
|
||||
void *rh_arg; /* Packet specific handle (eg evhtp) */
|
||||
void *rh_arg; /* Packet specific handle */
|
||||
} restconf_native_handle;
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -50,12 +50,6 @@
|
|||
#include "clixon_config.h" /* generated by config & autoconf */
|
||||
#endif
|
||||
|
||||
/* The clixon evhtp code can be compiled with or without threading support
|
||||
* The choice is set at libevhtp compile time by cmake. Eg:
|
||||
* cmake -DEVHTP_DISABLE_EVTHR=ON # Disable threads.
|
||||
* Default in testing is disabled threads.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
|
@ -80,14 +74,6 @@
|
|||
/* clicon */
|
||||
#include <clixon/clixon.h>
|
||||
|
||||
#ifdef HAVE_LIBEVHTP /* To get restconf_native.h include files right */
|
||||
/* evhtp */
|
||||
#include <event2/buffer.h> /* evbuffer */
|
||||
#define EVHTP_DISABLE_REGEX
|
||||
#define EVHTP_DISABLE_EVTHR
|
||||
#include <evhtp/evhtp.h>
|
||||
#endif /* HAVE_LIBEVHTP */
|
||||
|
||||
#ifdef HAVE_LIBNGHTTP2
|
||||
#include <nghttp2/nghttp2.h>
|
||||
#endif
|
||||
|
|
@ -279,12 +265,11 @@ recv_callback(nghttp2_session *session,
|
|||
|
||||
/*! Callback for each incoming http request for path /
|
||||
*
|
||||
* This are all messages except /.well-known, Registered with evhtp_set_cb
|
||||
* This are all messages except /.well-known,
|
||||
*
|
||||
* @param[in] req evhtp http request structure defining the incoming message
|
||||
* @param[in] arg cx_evhtp handle clixon specific fields
|
||||
* @param[in] sd session stream struct (http/1 has a single)
|
||||
* @retval void
|
||||
* Discussion: problematic if fatal error -1 is returneod from clixon routines
|
||||
* Discussion: problematic if fatal error -1 is returned from clixon routines
|
||||
* without actually terminating. Consider:
|
||||
* 1) sending some error? and/or
|
||||
* 2) terminating the process?
|
||||
|
|
@ -338,10 +323,6 @@ restconf_nghttp2_path(restconf_stream_data *sd)
|
|||
retval = 0;
|
||||
done:
|
||||
clicon_debug(1, "%s %d", __FUNCTION__, retval);
|
||||
/* Catch all on fatal error. This does not terminate the process but closes request stream */
|
||||
// if (retval < 0){
|
||||
// evhtp_send_reply(req, EVHTP_RES_ERROR);
|
||||
// }
|
||||
if (cvv)
|
||||
cvec_free(cvv);
|
||||
if (oneline)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue