* 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
|
|
@ -36,6 +36,12 @@
|
||||||
## 5.6.0
|
## 5.6.0
|
||||||
Expected: March 2022
|
Expected: March 2022
|
||||||
|
|
||||||
|
### New features
|
||||||
|
|
||||||
|
* HTTP/1 native parser as part of the RESTCONF client
|
||||||
|
* Replaced libevhtp/libevent2 with internal http1 parser
|
||||||
|
* Replace configure option `--disable-evhtp` with `--disable-http1` for disabling HTTP/1 whihc is on by default
|
||||||
|
|
||||||
### API changes on existing protocol/config features
|
### API changes on existing protocol/config features
|
||||||
|
|
||||||
Users may have to change how they access the system
|
Users may have to change how they access the system
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,6 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
#include <dirent.h>
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,6 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <dirent.h>
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,6 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <dirent.h>
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,6 @@
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#define __USE_GNU /* For RTLD_DEFAULT */
|
#define __USE_GNU /* For RTLD_DEFAULT */
|
||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
#include <dirent.h>
|
|
||||||
#include <libgen.h>
|
#include <libgen.h>
|
||||||
#include <grp.h>
|
#include <grp.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
|
|
||||||
|
|
@ -100,10 +100,10 @@ APPSRC += restconf_methods_post.c
|
||||||
APPSRC += restconf_methods_get.c
|
APPSRC += restconf_methods_get.c
|
||||||
APPSRC += restconf_methods_patch.c
|
APPSRC += restconf_methods_patch.c
|
||||||
APPSRC += restconf_root.c
|
APPSRC += restconf_root.c
|
||||||
|
APPSRC += clixon_http1.c
|
||||||
APPSRC += restconf_main_$(with_restconf).c
|
APPSRC += restconf_main_$(with_restconf).c
|
||||||
ifeq ($(with_restconf),native)
|
ifeq ($(with_restconf),native)
|
||||||
APPSRC += restconf_native.c
|
APPSRC += restconf_native.c
|
||||||
APPSRC += restconf_evhtp.c # HTTP/1
|
|
||||||
APPSRC += restconf_nghttp2.c # HTTP/2
|
APPSRC += restconf_nghttp2.c # HTTP/2
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
|
@ -113,7 +113,10 @@ ifeq ($(with_restconf),fcgi)
|
||||||
APPSRC += restconf_stream_$(with_restconf).c
|
APPSRC += restconf_stream_$(with_restconf).c
|
||||||
endif
|
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
|
# Accessible from plugin
|
||||||
# XXX actually this does not work properly, there are functions in lib
|
# 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)
|
LIBOBJ = $(LIBSRC:.c=.o)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# This lib is very small but used for clixon restconf applications to access clixon restconf lib
|
# This lib is very small but used for clixon restconf applications to access clixon restconf lib
|
||||||
# functions. Mostly for future use
|
# functions. Mostly for future use
|
||||||
MYNAME = clixon_restconf
|
MYNAME = clixon_restconf
|
||||||
|
|
@ -147,6 +152,7 @@ $(top_srcdir)/lib/src/$(CLIXON_LIB):
|
||||||
clean:
|
clean:
|
||||||
rm -f $(LIBOBJ) *.core $(APPL) $(APPOBJ) *.o $(MYLIBDYNAMIC) $(MYLIBSTATIC) $(MYLIBSO) $(MYLIBLINK) # extra .o to clean residue if with_restconf changes
|
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 *.gcda *.gcno *.gcov # coverage
|
||||||
|
rm -f clixon_http1_parse.tab.[ch] clixon_http1_parse.[co] lex.clixon_http1_parse.c
|
||||||
|
|
||||||
distclean: clean
|
distclean: clean
|
||||||
rm -f Makefile *~ .depend
|
rm -f Makefile *~ .depend
|
||||||
|
|
@ -191,6 +197,19 @@ uninstall:
|
||||||
.c.o:
|
.c.o:
|
||||||
$(CC) $(INCLUDES) -D__PROGRAM__=\"clixon_restconf\" $(CPPFLAGS) $(CFLAGS) -c $<
|
$(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)
|
ifeq ($(LINKAGE),dynamic)
|
||||||
$(APPL): $(MYLIBDYNAMIC)
|
$(APPL): $(MYLIBDYNAMIC)
|
||||||
else
|
else
|
||||||
|
|
|
||||||
|
|
@ -6,19 +6,10 @@
|
||||||
* [Nchan Streams](#nchan)
|
* [Nchan Streams](#nchan)
|
||||||
* [Debugging](#debugging)
|
* [Debugging](#debugging)
|
||||||
|
|
||||||
There are two installation instructions: for libevhtp and nginx.
|
There are two installation instructions: for native and nginx.
|
||||||
|
|
||||||
## Native
|
## 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 clixon with native restconf:
|
||||||
```
|
```
|
||||||
./configure --with-restconf=native
|
./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 *****
|
***** BEGIN LICENSE BLOCK *****
|
||||||
|
|
||||||
Copyright (C) 2009-2019 Olof Hagsand
|
|
||||||
Copyright (C) 2020-2022 Olof Hagsand and Rubicon Communications, LLC(Netgate)
|
Copyright (C) 2020-2022 Olof Hagsand and Rubicon Communications, LLC(Netgate)
|
||||||
|
|
||||||
This file is part of CLIXON.
|
This file is part of CLIXON.
|
||||||
|
|
@ -31,17 +30,18 @@
|
||||||
the terms of any one of the Apache License version 2 or the GPL.
|
the terms of any one of the Apache License version 2 or the GPL.
|
||||||
|
|
||||||
***** END LICENSE BLOCK *****
|
***** END LICENSE BLOCK *****
|
||||||
*
|
|
||||||
* Virtual clixon restconf API functions.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _RESTCONF_EVHTP_H_
|
* HTTP/1.1 parser according to RFC 7230
|
||||||
#define _RESTCONF_EVHTP_H_
|
*/
|
||||||
|
#ifndef _CLIXON_HTTP1_H_
|
||||||
|
#define _CLIXON_HTTP1_H_
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Prototypes
|
* Prototypes
|
||||||
*/
|
*/
|
||||||
void restconf_path_root(evhtp_request_t *req, void *arg);
|
int clixon_http1_parse_file(clicon_handle h, restconf_conn *rc, FILE *f, const char *filename);
|
||||||
void restconf_path_wellknown(evhtp_request_t *req, void *arg);
|
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/ssl.h>
|
||||||
#include <openssl/err.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
|
#ifdef HAVE_LIBNGHTTP2
|
||||||
#include <nghttp2/nghttp2.h>
|
#include <nghttp2/nghttp2.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -71,8 +64,8 @@
|
||||||
#include "restconf_api.h" /* Virtual api */
|
#include "restconf_api.h" /* Virtual api */
|
||||||
#include "restconf_native.h"
|
#include "restconf_native.h"
|
||||||
|
|
||||||
/*! Add HTTP header field name and value to reply, evhtp specific
|
/*! Add HTTP header field name and value to reply
|
||||||
* @param[in] req Evhtp http request handle
|
* @param[in] req request handle
|
||||||
* @param[in] name HTTP header field name
|
* @param[in] name HTTP header field name
|
||||||
* @param[in] vfmt HTTP header field value format string w variable parameter
|
* @param[in] vfmt HTTP header field value format string w variable parameter
|
||||||
* @see eg RFC 7230
|
* @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 <string.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <dirent.h>
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
|
|
||||||
|
|
@ -49,18 +49,6 @@
|
||||||
* +--------------------+
|
* +--------------------+
|
||||||
* Note restconf_request may need to be extended eg backpointer to rs?
|
* 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:
|
* Buffer handling:
|
||||||
* c
|
* c
|
||||||
* |
|
* |
|
||||||
|
|
@ -121,12 +109,6 @@
|
||||||
#include "clixon_config.h" /* generated by config & autoconf */
|
#include "clixon_config.h" /* generated by config & autoconf */
|
||||||
#endif
|
#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 <stdio.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
@ -151,16 +133,6 @@
|
||||||
/* clicon */
|
/* clicon */
|
||||||
#include <clixon/clixon.h>
|
#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
|
#ifdef HAVE_LIBNGHTTP2
|
||||||
/* nghttp2 */
|
/* nghttp2 */
|
||||||
#include <nghttp2/nghttp2.h>
|
#include <nghttp2/nghttp2.h>
|
||||||
|
|
@ -173,12 +145,12 @@
|
||||||
#include "restconf_err.h"
|
#include "restconf_err.h"
|
||||||
#include "restconf_root.h"
|
#include "restconf_root.h"
|
||||||
#include "restconf_native.h" /* Restconf-openssl mode specific headers*/
|
#include "restconf_native.h" /* Restconf-openssl mode specific headers*/
|
||||||
#ifdef HAVE_LIBEVHTP
|
|
||||||
#include "restconf_evhtp.h" /* http/1 */
|
|
||||||
#endif
|
|
||||||
#ifdef HAVE_LIBNGHTTP2
|
#ifdef HAVE_LIBNGHTTP2
|
||||||
#include "restconf_nghttp2.h" /* http/2 */
|
#include "restconf_nghttp2.h" /* http/2 */
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef HAVE_HTTP1
|
||||||
|
#include "clixon_http1.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Command line options to be passed to getopt(3) */
|
/* Command line options to be passed to getopt(3) */
|
||||||
#define RESTCONF_OPTS "hD:f:E:l:p:y:a:u:rW:R:o:"
|
#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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*! Init openSSL
|
||||||
* see restconf_config ->cv_evhtp_init(x2) -> cx_evhtp_socket ->
|
|
||||||
* evhtp_ssl_init:4757
|
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
init_openssl(void)
|
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
|
* - 0 (preferity_ok) the session terminates here in SSL negotiation, an http client
|
||||||
* will get a low level error (not http reply)
|
* will get a low level error (not http reply)
|
||||||
* - 1 Check if the cert is valid using SSL_get_verify_result(rc->rc_ssl)
|
* - 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;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
@ -479,7 +449,7 @@ alpn_select_proto_cb(SSL *ssl,
|
||||||
inp++;
|
inp++;
|
||||||
if (clicon_debug_get()) /* debug print the protoocol */
|
if (clicon_debug_get()) /* debug print the protoocol */
|
||||||
alpn_proto_dump(__FUNCTION__, (const char*)inp, len);
|
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){
|
if (pref < 10 && len == 8 && strncmp((char*)inp, "http/1.1", len) == 0){
|
||||||
*outlen = len;
|
*outlen = len;
|
||||||
*out = inp;
|
*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 *
|
static SSL_CTX *
|
||||||
restconf_ssl_context_create(clicon_handle h)
|
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] ctx SSL context
|
||||||
* @param[in] server_cert_path Server cert
|
* @param[in] server_cert_path Server cert
|
||||||
* @param[in] server_key_path Server private key
|
* @param[in] server_key_path Server private key
|
||||||
|
|
@ -595,7 +561,7 @@ restconf_ssl_context_configure(clixon_handle h,
|
||||||
return retval;
|
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
|
* There are many variants to closing, one could probably make this more generic
|
||||||
* and always use this function, but it is difficult.
|
* 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);
|
SSL_free(rc->rc_ssl);
|
||||||
rc->rc_ssl = NULL;
|
rc->rc_ssl = NULL;
|
||||||
#ifdef HAVE_LIBEVHTP
|
|
||||||
if (rc->rc_evconn)
|
|
||||||
rc->rc_evconn->ssl = NULL;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
if (close(rc->rc_s) < 0){
|
if (close(rc->rc_s) < 0){
|
||||||
clicon_err(OE_UNIX, errno, "close");
|
clicon_err(OE_UNIX, errno, "close");
|
||||||
|
|
@ -675,7 +637,67 @@ send_badrequest(clicon_handle h,
|
||||||
return retval;
|
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] s Socket where message arrived. read from this.
|
||||||
* @param[in] arg Client entry (from).
|
* @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
|
* @retval -1 Error Terminates backend and is never called). Instead errors are
|
||||||
* propagated back to client.
|
* propagated back to client.
|
||||||
* @see restconf_accept_client where this callback is registered
|
* @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
|
* with 100 Continue, in which case that is replied and the function returns and the client sends
|
||||||
* more data.
|
* 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
|
static int
|
||||||
restconf_connection(int s,
|
restconf_connection(int s,
|
||||||
|
|
@ -701,9 +723,8 @@ restconf_connection(int s,
|
||||||
#ifdef HAVE_LIBNGHTTP2
|
#ifdef HAVE_LIBNGHTTP2
|
||||||
int ret;
|
int ret;
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_LIBEVHTP
|
#ifdef HAVE_HTTP1
|
||||||
clicon_handle h;
|
clicon_handle h;
|
||||||
evhtp_connection_t *evconn = NULL;
|
|
||||||
restconf_stream_data *sd;
|
restconf_stream_data *sd;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
@ -765,7 +786,7 @@ restconf_connection(int s,
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
clicon_debug(1, "%s (ssl)read:%zd", __FUNCTION__, n);
|
clicon_debug(1, "%s read:%zd", __FUNCTION__, n);
|
||||||
if (n == 0){
|
if (n == 0){
|
||||||
clicon_debug(1, "%s n=0 closing socket", __FUNCTION__);
|
clicon_debug(1, "%s n=0 closing socket", __FUNCTION__);
|
||||||
if (restconf_close_ssl_socket(rc, 0) < 0)
|
if (restconf_close_ssl_socket(rc, 0) < 0)
|
||||||
|
|
@ -774,99 +795,43 @@ restconf_connection(int s,
|
||||||
rc = NULL;
|
rc = NULL;
|
||||||
goto ok;
|
goto ok;
|
||||||
}
|
}
|
||||||
|
#if 0
|
||||||
|
if (mirror_pkt(buf, n) < 0)
|
||||||
|
goto done;
|
||||||
|
#endif
|
||||||
switch (rc->rc_proto){
|
switch (rc->rc_proto){
|
||||||
#ifdef HAVE_LIBEVHTP
|
#ifdef HAVE_HTTP1
|
||||||
case HTTP_10:
|
case HTTP_10:
|
||||||
case HTTP_11:
|
case HTTP_11:
|
||||||
h = rc->rc_h;
|
h = rc->rc_h;
|
||||||
/* parse incoming packet using evhtp
|
if (clixon_http1_parse_buf(h, rc, buf, n) < 0){
|
||||||
* 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 (send_badrequest(h, rc->rc_s, rc->rc_ssl, "application/yang-data+xml",
|
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)
|
"<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;
|
goto done;
|
||||||
SSL_free(rc->rc_ssl);
|
}
|
||||||
rc->rc_ssl = NULL;
|
else{
|
||||||
evconn->ssl = NULL;
|
if (restconf_http1_path_root(h, rc) < 0)
|
||||||
if (close(rc->rc_s) < 0){
|
|
||||||
clicon_err(OE_UNIX, errno, "close");
|
|
||||||
goto done;
|
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__);
|
clicon_debug(1, "%s connection_parse OK", __FUNCTION__);
|
||||||
/* default stream */
|
/* default stream */
|
||||||
if ((sd = restconf_stream_find(rc, 0)) == NULL){
|
if ((sd = restconf_stream_find(rc, 0)) == NULL){
|
||||||
clicon_err(OE_RESTCONF, EINVAL, "restconf stream not found");
|
clicon_err(OE_RESTCONF, EINVAL, "restconf stream not found");
|
||||||
goto done;
|
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),
|
if (buf_write(cbuf_get(sd->sd_outp_buf), cbuf_len(sd->sd_outp_buf),
|
||||||
rc->rc_s, rc->rc_ssl) < 0)
|
rc->rc_s, rc->rc_ssl) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
cvec_reset(sd->sd_outp_hdrs); /* Can be done in native_send_reply */
|
cvec_reset(sd->sd_outp_hdrs); /* Can be done in native_send_reply */
|
||||||
cbuf_reset(sd->sd_outp_buf);
|
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 (rc->rc_exit){ /* Server-initiated exit for http/2 */
|
if (rc->rc_exit){ /* Server-initiated exit for http/2 */
|
||||||
SSL_free(rc->rc_ssl);
|
SSL_free(rc->rc_ssl);
|
||||||
rc->rc_ssl = NULL;
|
rc->rc_ssl = NULL;
|
||||||
evconn->ssl = NULL;
|
|
||||||
if (close(rc->rc_s) < 0){
|
if (close(rc->rc_s) < 0){
|
||||||
clicon_err(OE_UNIX, errno, "close");
|
clicon_err(OE_UNIX, errno, "close");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
clixon_event_unreg_fd(rc->rc_s, restconf_connection);
|
clixon_event_unreg_fd(rc->rc_s, restconf_connection);
|
||||||
clicon_debug(1, "%s evconn-free (%p) 2", __FUNCTION__, evconn);
|
|
||||||
restconf_conn_free(rc);
|
restconf_conn_free(rc);
|
||||||
goto ok;
|
goto ok;
|
||||||
}
|
}
|
||||||
|
|
@ -916,7 +881,7 @@ restconf_connection(int s,
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
#endif /* HAVE_LIBEVHTP */
|
#endif /* HAVE_HTTP1 */
|
||||||
#ifdef HAVE_LIBNGHTTP2
|
#ifdef HAVE_LIBNGHTTP2
|
||||||
case HTTP_2:
|
case HTTP_2:
|
||||||
if (rc->rc_exit){ /* Server-initiated exit for 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);
|
clicon_debug(1, "%s %d", __FUNCTION__, fd);
|
||||||
#ifdef HAVE_LIBNGHTTP2
|
#ifdef HAVE_LIBNGHTTP2
|
||||||
#ifndef HAVE_LIBEVHTP
|
#ifndef HAVE_HTTP1
|
||||||
proto = HTTP_2; /* If nghttp2 only let default be 2.0 */
|
proto = HTTP_2; /* If nghttp2 only let default be 2.0 */
|
||||||
#endif
|
#endif
|
||||||
/* If also evhtp, keep HTTP_11 */
|
|
||||||
#endif
|
#endif
|
||||||
if ((rsock = (restconf_socket *)arg) == NULL){
|
if ((rsock = (restconf_socket *)arg) == NULL){
|
||||||
clicon_err(OE_YANG, EINVAL, "rsock is NULL");
|
clicon_err(OE_YANG, EINVAL, "rsock is NULL");
|
||||||
|
|
@ -1313,28 +1277,14 @@ restconf_accept_client(int fd,
|
||||||
} /* if ssl */
|
} /* if ssl */
|
||||||
rc->rc_proto = proto;
|
rc->rc_proto = proto;
|
||||||
switch (rc->rc_proto){
|
switch (rc->rc_proto){
|
||||||
#ifdef HAVE_LIBEVHTP
|
#ifdef HAVE_HTTP1
|
||||||
case HTTP_10:
|
case HTTP_10:
|
||||||
case HTTP_11:{
|
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 */
|
|
||||||
/* Create a default stream for http/1 */
|
/* Create a default stream for http/1 */
|
||||||
if (restconf_stream_data_new(rc, 0) == NULL)
|
if (restconf_stream_data_new(rc, 0) == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
#endif /* HAVE_LIBEVHTP */
|
#endif /* HAVE_HTTP1 */
|
||||||
#ifdef HAVE_LIBNGHTTP2
|
#ifdef HAVE_LIBNGHTTP2
|
||||||
case HTTP_2:{
|
case HTTP_2:{
|
||||||
if (http2_session_init(rc) < 0){
|
if (http2_session_init(rc) < 0){
|
||||||
|
|
@ -1365,6 +1315,10 @@ restconf_accept_client(int fd,
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
} /* switch proto */
|
} /* 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)
|
if (clixon_event_reg_fd(rc->rc_s, restconf_connection, (void*)rc, "restconf client socket") < 0)
|
||||||
goto done;
|
goto done;
|
||||||
ok:
|
ok:
|
||||||
|
|
@ -1376,6 +1330,8 @@ restconf_accept_client(int fd,
|
||||||
return retval;
|
return retval;
|
||||||
} /* restconf_accept_client */
|
} /* restconf_accept_client */
|
||||||
|
|
||||||
|
/*!
|
||||||
|
*/
|
||||||
static int
|
static int
|
||||||
restconf_native_terminate(clicon_handle h)
|
restconf_native_terminate(clicon_handle h)
|
||||||
{
|
{
|
||||||
|
|
@ -1396,18 +1352,6 @@ restconf_native_terminate(clicon_handle h)
|
||||||
}
|
}
|
||||||
if (rh->rh_ctx)
|
if (rh->rh_ctx)
|
||||||
SSL_CTX_free(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);
|
free(rh);
|
||||||
}
|
}
|
||||||
EVP_cleanup();
|
EVP_cleanup();
|
||||||
|
|
@ -1581,10 +1525,6 @@ restconf_openssl_init(clicon_handle h,
|
||||||
cxobj **vec = NULL;
|
cxobj **vec = NULL;
|
||||||
size_t veclen;
|
size_t veclen;
|
||||||
int i;
|
int i;
|
||||||
#ifdef HAVE_LIBEVHTP
|
|
||||||
evhtp_t *evhtp = NULL;
|
|
||||||
struct event_base *evbase = NULL;
|
|
||||||
#endif /* HAVE_LIBEVHTP */
|
|
||||||
|
|
||||||
clicon_debug(1, "%s", __FUNCTION__);
|
clicon_debug(1, "%s", __FUNCTION__);
|
||||||
/* flag used for sanity of certs */
|
/* flag used for sanity of certs */
|
||||||
|
|
@ -1639,28 +1579,6 @@ restconf_openssl_init(clicon_handle h,
|
||||||
}
|
}
|
||||||
rh = restconf_native_handle_get(h);
|
rh = restconf_native_handle_get(h);
|
||||||
rh->rh_ctx = ctx;
|
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 */
|
/* get the list of socket config-data */
|
||||||
if (xpath_vec(xrestconf, nsc, "socket", &vec, &veclen) < 0)
|
if (xpath_vec(xrestconf, nsc, "socket", &vec, &veclen) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
|
||||||
|
|
@ -66,14 +66,7 @@
|
||||||
#include "restconf_lib.h" /* generic shared with plugins */
|
#include "restconf_lib.h" /* generic shared with plugins */
|
||||||
#include "restconf_handle.h"
|
#include "restconf_handle.h"
|
||||||
#include "restconf_err.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
|
#ifdef HAVE_LIBNGHTTP2
|
||||||
#include <nghttp2/nghttp2.h>
|
#include <nghttp2/nghttp2.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -167,7 +160,7 @@ restconf_conn_new(clicon_handle h,
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Free clixon/cbuf resources related to an evhtp connection
|
/*! Free clixon/cbuf resources related to a connection
|
||||||
* @param[in] rc restconf connection
|
* @param[in] rc restconf connection
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
|
|
@ -182,10 +175,6 @@ restconf_conn_free(restconf_conn *rc)
|
||||||
#ifdef HAVE_LIBNGHTTP2
|
#ifdef HAVE_LIBNGHTTP2
|
||||||
if (rc->rc_ngsession)
|
if (rc->rc_ngsession)
|
||||||
nghttp2_session_del(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
|
#endif
|
||||||
/* Free all streams */
|
/* Free all streams */
|
||||||
while ((sd = rc->rc_streams) != NULL) {
|
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 */
|
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 */
|
restconf_http_proto sd_proto; /* http protocol XXX not sure this is needed */
|
||||||
cvec *sd_qvec; /* Query parameters, ie ?a=b&c=d */
|
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 */
|
int sd_upgrade2; /* Upgrade to http/2 */
|
||||||
uint8_t *sd_settings2; /* Settings for upgrade to http/2 request */
|
uint8_t *sd_settings2; /* Settings for upgrade to http/2 request */
|
||||||
} restconf_stream_data;
|
} restconf_stream_data;
|
||||||
|
|
@ -98,9 +98,6 @@ typedef struct restconf_conn {
|
||||||
int rc_exit; /* Set to close socket server-side (NYI) */
|
int rc_exit; /* Set to close socket server-side (NYI) */
|
||||||
/* Decision to keep lib-specific data here, otherwise new struct necessary
|
/* Decision to keep lib-specific data here, otherwise new struct necessary
|
||||||
* drawback is specific includes need to go everywhere */
|
* drawback is specific includes need to go everywhere */
|
||||||
#ifdef HAVE_LIBEVHTP
|
|
||||||
evhtp_connection_t *rc_evconn;
|
|
||||||
#endif
|
|
||||||
#ifdef HAVE_LIBNGHTTP2
|
#ifdef HAVE_LIBNGHTTP2
|
||||||
nghttp2_session *rc_ngsession; /* XXX Not sure it is needed */
|
nghttp2_session *rc_ngsession; /* XXX Not sure it is needed */
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -125,7 +122,7 @@ typedef struct {
|
||||||
typedef struct {
|
typedef struct {
|
||||||
SSL_CTX *rh_ctx; /* SSL context */
|
SSL_CTX *rh_ctx; /* SSL context */
|
||||||
restconf_socket *rh_sockets; /* List of restconf server (ready for accept) sockets */
|
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;
|
} restconf_native_handle;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
|
|
@ -50,12 +50,6 @@
|
||||||
#include "clixon_config.h" /* generated by config & autoconf */
|
#include "clixon_config.h" /* generated by config & autoconf */
|
||||||
#endif
|
#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 <stdio.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
@ -80,14 +74,6 @@
|
||||||
/* clicon */
|
/* clicon */
|
||||||
#include <clixon/clixon.h>
|
#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
|
#ifdef HAVE_LIBNGHTTP2
|
||||||
#include <nghttp2/nghttp2.h>
|
#include <nghttp2/nghttp2.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -279,12 +265,11 @@ recv_callback(nghttp2_session *session,
|
||||||
|
|
||||||
/*! Callback for each incoming http request for path /
|
/*! 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] sd session stream struct (http/1 has a single)
|
||||||
* @param[in] arg cx_evhtp handle clixon specific fields
|
|
||||||
* @retval void
|
* @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:
|
* without actually terminating. Consider:
|
||||||
* 1) sending some error? and/or
|
* 1) sending some error? and/or
|
||||||
* 2) terminating the process?
|
* 2) terminating the process?
|
||||||
|
|
@ -338,10 +323,6 @@ restconf_nghttp2_path(restconf_stream_data *sd)
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
clicon_debug(1, "%s %d", __FUNCTION__, retval);
|
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)
|
if (cvv)
|
||||||
cvec_free(cvv);
|
cvec_free(cvv);
|
||||||
if (oneline)
|
if (oneline)
|
||||||
|
|
|
||||||
145
configure
vendored
145
configure
vendored
|
|
@ -636,8 +636,8 @@ YANG_STANDARD_DIR
|
||||||
YANG_INSTALLDIR
|
YANG_INSTALLDIR
|
||||||
CLIXON_YANG_PATCH
|
CLIXON_YANG_PATCH
|
||||||
with_libxml2
|
with_libxml2
|
||||||
|
HAVE_HTTP1
|
||||||
HAVE_LIBNGHTTP2
|
HAVE_LIBNGHTTP2
|
||||||
HAVE_LIBEVHTP
|
|
||||||
with_restconf
|
with_restconf
|
||||||
LINKAGE
|
LINKAGE
|
||||||
LIBSTATIC_SUFFIX
|
LIBSTATIC_SUFFIX
|
||||||
|
|
@ -720,7 +720,7 @@ with_cligen
|
||||||
enable_yang_patch
|
enable_yang_patch
|
||||||
enable_publish
|
enable_publish
|
||||||
with_restconf
|
with_restconf
|
||||||
enable_evhtp
|
enable_http1
|
||||||
enable_nghttp2
|
enable_nghttp2
|
||||||
with_configfile
|
with_configfile
|
||||||
with_libxml2
|
with_libxml2
|
||||||
|
|
@ -1370,7 +1370,7 @@ Optional Features:
|
||||||
--enable-yang-patch Enable YANG patch, RFC 8072, default: no
|
--enable-yang-patch Enable YANG patch, RFC 8072, default: no
|
||||||
--enable-publish Enable publish of notification streams using SSE and
|
--enable-publish Enable publish of notification streams using SSE and
|
||||||
curl
|
curl
|
||||||
--disable-evhtp Disable evhtp for native restconf http/1, ie http/2
|
--disable-http1 Disable http1 for native restconf http/1, ie http/2
|
||||||
only
|
only
|
||||||
--disable-nghttp2 Disable nghttp2 for native restconf http/2, ie
|
--disable-nghttp2 Disable nghttp2 for native restconf http/2, ie
|
||||||
http/1 only
|
http/1 only
|
||||||
|
|
@ -3385,10 +3385,10 @@ test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
|
||||||
|
|
||||||
|
|
||||||
# Set to native or fcgi -> compile apps/restconf
|
# Set to native or fcgi -> compile apps/restconf
|
||||||
HAVE_LIBEVHTP=false
|
|
||||||
# consider using neutral constant such as with-http1
|
|
||||||
HAVE_LIBNGHTTP2=false
|
HAVE_LIBNGHTTP2=false
|
||||||
# consider using neutral constant such as with-http2
|
# consider using neutral constant such as with-http2
|
||||||
|
HAVE_HTTP1=false
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Where Clixon installs its YANG specs
|
# Where Clixon installs its YANG specs
|
||||||
|
|
@ -5070,7 +5070,6 @@ fi
|
||||||
$as_echo "#define WITH_RESTCONF_FCGI 1" >>confdefs.h
|
$as_echo "#define WITH_RESTCONF_FCGI 1" >>confdefs.h
|
||||||
# For c-code that cant use strings
|
# For c-code that cant use strings
|
||||||
elif test "x${with_restconf}" == xnative; then
|
elif test "x${with_restconf}" == xnative; then
|
||||||
|
|
||||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for OPENSSL_init_ssl in -lssl" >&5
|
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for OPENSSL_init_ssl in -lssl" >&5
|
||||||
$as_echo_n "checking for OPENSSL_init_ssl in -lssl... " >&6; }
|
$as_echo_n "checking for OPENSSL_init_ssl in -lssl... " >&6; }
|
||||||
if ${ac_cv_lib_ssl_OPENSSL_init_ssl_+:} false; then :
|
if ${ac_cv_lib_ssl_OPENSSL_init_ssl_+:} false; then :
|
||||||
|
|
@ -5165,136 +5164,26 @@ else
|
||||||
as_fn_error $? "libcrypto missing" "$LINENO" 5
|
as_fn_error $? "libcrypto missing" "$LINENO" 5
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Check if evhtp is enabled for http/1
|
# Check if http/1 enabled
|
||||||
# Check whether --enable-evhtp was given.
|
# Check whether --enable-http1 was given.
|
||||||
if test "${enable_evhtp+set}" = set; then :
|
if test "${enable_http1+set}" = set; then :
|
||||||
enableval=$enable_evhtp;
|
enableval=$enable_http1;
|
||||||
if test "$enableval" = no; then
|
if test "$enableval" = no; then
|
||||||
ac_enable_evhtp=no
|
ac_enable_http1=no
|
||||||
else
|
else
|
||||||
ac_enable_evhtp=yes
|
ac_enable_http1=yes
|
||||||
fi
|
fi
|
||||||
|
|
||||||
else
|
else
|
||||||
ac_enable_evhtp=yes
|
ac_enable_http1=yes
|
||||||
fi
|
fi
|
||||||
|
|
||||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: checking evhtp is enabled: $ac_enable_evhtp" >&5
|
|
||||||
$as_echo "checking evhtp is enabled: $ac_enable_evhtp" >&6; }
|
|
||||||
if test "$ac_enable_evhtp" = "yes"; then
|
|
||||||
for ac_header in evhtp/evhtp.h
|
|
||||||
do :
|
|
||||||
ac_fn_c_check_header_compile "$LINENO" "evhtp/evhtp.h" "ac_cv_header_evhtp_evhtp_h" "$ac_includes_default
|
|
||||||
#define EVHTP_DISABLE_REGEX
|
|
||||||
#define EVHTP_DISABLE_EVTHR
|
|
||||||
|
|
||||||
"
|
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: checking http1 is enabled: $ac_enable_http1" >&5
|
||||||
if test "x$ac_cv_header_evhtp_evhtp_h" = xyes; then :
|
$as_echo "checking http1 is enabled: $ac_enable_http1" >&6; }
|
||||||
cat >>confdefs.h <<_ACEOF
|
if test "$ac_enable_http1" = "yes"; then
|
||||||
#define HAVE_EVHTP_EVHTP_H 1
|
$as_echo "#define HAVE_HTTP1 true" >>confdefs.h
|
||||||
_ACEOF
|
# Must be tree/false (not 0/1) used in shells
|
||||||
|
|
||||||
else
|
|
||||||
as_fn_error $? "evhtp header missing. See https://github.com/clicon/libevhtp" "$LINENO" 5
|
|
||||||
fi
|
|
||||||
|
|
||||||
done
|
|
||||||
|
|
||||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for event_init in -levent" >&5
|
|
||||||
$as_echo_n "checking for event_init in -levent... " >&6; }
|
|
||||||
if ${ac_cv_lib_event_event_init+:} false; then :
|
|
||||||
$as_echo_n "(cached) " >&6
|
|
||||||
else
|
|
||||||
ac_check_lib_save_LIBS=$LIBS
|
|
||||||
LIBS="-levent $LIBS"
|
|
||||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
|
||||||
/* end confdefs.h. */
|
|
||||||
|
|
||||||
/* Override any GCC internal prototype to avoid an error.
|
|
||||||
Use char because int might match the return type of a GCC
|
|
||||||
builtin and then its argument prototype would still apply. */
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C"
|
|
||||||
#endif
|
|
||||||
char event_init ();
|
|
||||||
int
|
|
||||||
main ()
|
|
||||||
{
|
|
||||||
return event_init ();
|
|
||||||
;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
_ACEOF
|
|
||||||
if ac_fn_c_try_link "$LINENO"; then :
|
|
||||||
ac_cv_lib_event_event_init=yes
|
|
||||||
else
|
|
||||||
ac_cv_lib_event_event_init=no
|
|
||||||
fi
|
|
||||||
rm -f core conftest.err conftest.$ac_objext \
|
|
||||||
conftest$ac_exeext conftest.$ac_ext
|
|
||||||
LIBS=$ac_check_lib_save_LIBS
|
|
||||||
fi
|
|
||||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_event_event_init" >&5
|
|
||||||
$as_echo "$ac_cv_lib_event_event_init" >&6; }
|
|
||||||
if test "x$ac_cv_lib_event_event_init" = xyes; then :
|
|
||||||
cat >>confdefs.h <<_ACEOF
|
|
||||||
#define HAVE_LIBEVENT 1
|
|
||||||
_ACEOF
|
|
||||||
|
|
||||||
LIBS="-levent $LIBS"
|
|
||||||
|
|
||||||
else
|
|
||||||
as_fn_error $? "libevent missing" "$LINENO" 5
|
|
||||||
fi
|
|
||||||
|
|
||||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for evhtp_new in -levhtp" >&5
|
|
||||||
$as_echo_n "checking for evhtp_new in -levhtp... " >&6; }
|
|
||||||
if ${ac_cv_lib_evhtp_evhtp_new+:} false; then :
|
|
||||||
$as_echo_n "(cached) " >&6
|
|
||||||
else
|
|
||||||
ac_check_lib_save_LIBS=$LIBS
|
|
||||||
LIBS="-levhtp -levent -lssl -lcrypto $LIBS"
|
|
||||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
|
||||||
/* end confdefs.h. */
|
|
||||||
|
|
||||||
/* Override any GCC internal prototype to avoid an error.
|
|
||||||
Use char because int might match the return type of a GCC
|
|
||||||
builtin and then its argument prototype would still apply. */
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C"
|
|
||||||
#endif
|
|
||||||
char evhtp_new ();
|
|
||||||
int
|
|
||||||
main ()
|
|
||||||
{
|
|
||||||
return evhtp_new ();
|
|
||||||
;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
_ACEOF
|
|
||||||
if ac_fn_c_try_link "$LINENO"; then :
|
|
||||||
ac_cv_lib_evhtp_evhtp_new=yes
|
|
||||||
else
|
|
||||||
ac_cv_lib_evhtp_evhtp_new=no
|
|
||||||
fi
|
|
||||||
rm -f core conftest.err conftest.$ac_objext \
|
|
||||||
conftest$ac_exeext conftest.$ac_ext
|
|
||||||
LIBS=$ac_check_lib_save_LIBS
|
|
||||||
fi
|
|
||||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_evhtp_evhtp_new" >&5
|
|
||||||
$as_echo "$ac_cv_lib_evhtp_evhtp_new" >&6; }
|
|
||||||
if test "x$ac_cv_lib_evhtp_evhtp_new" = xyes; then :
|
|
||||||
cat >>confdefs.h <<_ACEOF
|
|
||||||
#define HAVE_LIBEVHTP 1
|
|
||||||
_ACEOF
|
|
||||||
|
|
||||||
LIBS="-levhtp $LIBS"
|
|
||||||
|
|
||||||
else
|
|
||||||
as_fn_error $? "libevhtp missing" "$LINENO" 5
|
|
||||||
fi
|
|
||||||
|
|
||||||
HAVE_LIBEVHTP=true
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Check if nghttp2 is enabled for http/2
|
# Check if nghttp2 is enabled for http/2
|
||||||
|
|
|
||||||
29
configure.ac
29
configure.ac
|
|
@ -114,8 +114,8 @@ AC_SUBST(SH_SUFFIX)
|
||||||
AC_SUBST(LIBSTATIC_SUFFIX)
|
AC_SUBST(LIBSTATIC_SUFFIX)
|
||||||
AC_SUBST(LINKAGE)
|
AC_SUBST(LINKAGE)
|
||||||
AC_SUBST(with_restconf) # Set to native or fcgi -> compile apps/restconf
|
AC_SUBST(with_restconf) # Set to native or fcgi -> compile apps/restconf
|
||||||
AC_SUBST(HAVE_LIBEVHTP,false) # consider using neutral constant such as with-http1
|
|
||||||
AC_SUBST(HAVE_LIBNGHTTP2,false) # consider using neutral constant such as with-http2
|
AC_SUBST(HAVE_LIBNGHTTP2,false) # consider using neutral constant such as with-http2
|
||||||
|
AC_SUBST(HAVE_HTTP1,false)
|
||||||
AC_SUBST(with_libxml2)
|
AC_SUBST(with_libxml2)
|
||||||
AC_SUBST(CLIXON_YANG_PATCH)
|
AC_SUBST(CLIXON_YANG_PATCH)
|
||||||
# Where Clixon installs its YANG specs
|
# Where Clixon installs its YANG specs
|
||||||
|
|
@ -223,30 +223,21 @@ if test "x${with_restconf}" == xfcgi; then
|
||||||
AC_CHECK_LIB(fcgi, FCGX_Init,, AC_MSG_ERROR([libfcgi-dev missing]))
|
AC_CHECK_LIB(fcgi, FCGX_Init,, AC_MSG_ERROR([libfcgi-dev missing]))
|
||||||
AC_DEFINE(WITH_RESTCONF_FCGI, 1, [Use fcgi restconf mode]) # For c-code that cant use strings
|
AC_DEFINE(WITH_RESTCONF_FCGI, 1, [Use fcgi restconf mode]) # For c-code that cant use strings
|
||||||
elif test "x${with_restconf}" == xnative; then
|
elif test "x${with_restconf}" == xnative; then
|
||||||
|
|
||||||
AC_CHECK_LIB(ssl, OPENSSL_init_ssl ,, AC_MSG_ERROR([libssl missing]))
|
AC_CHECK_LIB(ssl, OPENSSL_init_ssl ,, AC_MSG_ERROR([libssl missing]))
|
||||||
AC_CHECK_LIB(crypto, CRYPTO_new_ex_data, , AC_MSG_ERROR([libcrypto missing]))
|
AC_CHECK_LIB(crypto, CRYPTO_new_ex_data, , AC_MSG_ERROR([libcrypto missing]))
|
||||||
# Check if evhtp is enabled for http/1
|
# Check if http/1 enabled
|
||||||
AC_ARG_ENABLE(evhtp, AS_HELP_STRING([--disable-evhtp],[Disable evhtp for native restconf http/1, ie http/2 only]),[
|
AC_ARG_ENABLE(http1, AS_HELP_STRING([--disable-http1],[Disable http1 for native restconf http/1, ie http/2 only]),[
|
||||||
if test "$enableval" = no; then
|
if test "$enableval" = no; then
|
||||||
ac_enable_evhtp=no
|
ac_enable_http1=no
|
||||||
else
|
else
|
||||||
ac_enable_evhtp=yes
|
ac_enable_http1=yes
|
||||||
fi
|
fi
|
||||||
],
|
],
|
||||||
[ ac_enable_evhtp=yes])
|
[ ac_enable_http1=yes])
|
||||||
AC_MSG_RESULT(checking evhtp is enabled: $ac_enable_evhtp)
|
|
||||||
if test "$ac_enable_evhtp" = "yes"; then
|
AC_MSG_RESULT(checking http1 is enabled: $ac_enable_http1)
|
||||||
AC_CHECK_HEADERS(evhtp/evhtp.h,
|
if test "$ac_enable_http1" = "yes"; then
|
||||||
[],
|
AC_DEFINE(HAVE_HTTP1,true) # Must be tree/false (not 0/1) used in shells
|
||||||
AC_MSG_ERROR([evhtp header missing. See https://github.com/clicon/libevhtp]),
|
|
||||||
[AC_INCLUDES_DEFAULT[
|
|
||||||
#define EVHTP_DISABLE_REGEX
|
|
||||||
#define EVHTP_DISABLE_EVTHR
|
|
||||||
]])
|
|
||||||
AC_CHECK_LIB(event, event_init,, AC_MSG_ERROR([libevent missing]))
|
|
||||||
AC_CHECK_LIB(evhtp, evhtp_new,, AC_MSG_ERROR([libevhtp missing]),[-levent -lssl -lcrypto])
|
|
||||||
HAVE_LIBEVHTP=true
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Check if nghttp2 is enabled for http/2
|
# Check if nghttp2 is enabled for http/2
|
||||||
|
|
|
||||||
|
|
@ -242,6 +242,16 @@ To turn callgrind off/on:
|
||||||
callgrind_control -i on
|
callgrind_control -i on
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### valgrind and gdb
|
||||||
|
|
||||||
|
```
|
||||||
|
valgrind --vgdb=yes --vgdb-error=0 clixon_cli
|
||||||
|
|
||||||
|
gdb clixon_cli
|
||||||
|
(gdb) target remote | /usr/lib/valgrind/../../bin/vgdb --pid=1311 # see output from valgrind
|
||||||
|
(gdb) cont
|
||||||
|
```
|
||||||
|
|
||||||
## New release
|
## New release
|
||||||
What to think about when doing a new release.
|
What to think about when doing a new release.
|
||||||
* Ensure all tests run OK
|
* Ensure all tests run OK
|
||||||
|
|
@ -257,6 +267,7 @@ What to think about when doing a new release.
|
||||||
git tag -a <version>
|
git tag -a <version>
|
||||||
git push origin <version>
|
git push origin <version>
|
||||||
```
|
```
|
||||||
|
* Add a github "release" and copy release info from CHANGELOG
|
||||||
|
|
||||||
After release:
|
After release:
|
||||||
* Bump minor version and add a "PRE":
|
* Bump minor version and add a "PRE":
|
||||||
|
|
|
||||||
|
|
@ -38,26 +38,12 @@ MAINTAINER Olof Hagsand <olof@hagsand.se>
|
||||||
# For clixon and cligen
|
# For clixon and cligen
|
||||||
RUN apk add --update git make build-base gcc flex bison curl-dev
|
RUN apk add --update git make build-base gcc flex bison curl-dev
|
||||||
|
|
||||||
# evhtp dependencies
|
|
||||||
RUN apk add --update libevent libevent-dev
|
|
||||||
|
|
||||||
# nghttp2 dependencies
|
# nghttp2 dependencies
|
||||||
RUN apk add --update nghttp2
|
RUN apk add --update nghttp2
|
||||||
|
|
||||||
# Create a directory to hold source-code, dependencies etc
|
# Create a directory to hold source-code, dependencies etc
|
||||||
RUN mkdir /clixon
|
RUN mkdir /clixon
|
||||||
|
|
||||||
# clone libevhtp
|
|
||||||
WORKDIR /clixon
|
|
||||||
|
|
||||||
RUN git clone https://github.com/clicon/clixon-libevhtp.git
|
|
||||||
WORKDIR /clixon/clixon-libevhtp
|
|
||||||
RUN ./configure
|
|
||||||
|
|
||||||
RUN make
|
|
||||||
RUN mkdir /usr/local/include
|
|
||||||
RUN make install
|
|
||||||
|
|
||||||
RUN mkdir /clixon/build
|
RUN mkdir /clixon/build
|
||||||
WORKDIR /clixon
|
WORKDIR /clixon
|
||||||
|
|
||||||
|
|
@ -79,7 +65,7 @@ WORKDIR /clixon/clixon
|
||||||
COPY clixon .
|
COPY clixon .
|
||||||
|
|
||||||
# Configure, build and install clixon
|
# Configure, build and install clixon
|
||||||
RUN ./configure --prefix=/clixon/build --with-cligen=/clixon/build --with-restconf=native --enable-nghttp2 --enable-evhtp
|
RUN ./configure --prefix=/clixon/build --with-cligen=/clixon/build --with-restconf=native --enable-nghttp2 --enable-http1
|
||||||
|
|
||||||
RUN make
|
RUN make
|
||||||
RUN make install
|
RUN make install
|
||||||
|
|
@ -109,4 +95,3 @@ EXPOSE 443/tcp
|
||||||
RUN adduser -D -H clicon
|
RUN adduser -D -H clicon
|
||||||
|
|
||||||
COPY --from=0 /clixon/build/ /usr/local/
|
COPY --from=0 /clixon/build/ /usr/local/
|
||||||
COPY --from=0 /usr/local/lib/libevhtp.so* /usr/local/lib/
|
|
||||||
|
|
|
||||||
|
|
@ -38,26 +38,12 @@ MAINTAINER Olof Hagsand <olof@hagsand.se>
|
||||||
# For clixon and cligen
|
# For clixon and cligen
|
||||||
RUN apk add --update git make build-base gcc flex bison curl-dev
|
RUN apk add --update git make build-base gcc flex bison curl-dev
|
||||||
|
|
||||||
# evhtp dependencies
|
|
||||||
RUN apk add --update libevent libevent-dev
|
|
||||||
|
|
||||||
# nghttp2 dependencies
|
# nghttp2 dependencies
|
||||||
RUN apk add --update nghttp2
|
RUN apk add --update nghttp2
|
||||||
|
|
||||||
# Create a directory to hold source-code, dependencies etc
|
# Create a directory to hold source-code, dependencies etc
|
||||||
RUN mkdir /clixon
|
RUN mkdir /clixon
|
||||||
|
|
||||||
# clone libevhtp
|
|
||||||
WORKDIR /clixon
|
|
||||||
|
|
||||||
RUN git clone https://github.com/clicon/clixon-libevhtp.git
|
|
||||||
WORKDIR /clixon/clixon-libevhtp
|
|
||||||
RUN ./configure
|
|
||||||
|
|
||||||
RUN make
|
|
||||||
RUN mkdir /usr/local/include
|
|
||||||
RUN make install
|
|
||||||
|
|
||||||
RUN mkdir /clixon/build
|
RUN mkdir /clixon/build
|
||||||
WORKDIR /clixon
|
WORKDIR /clixon
|
||||||
|
|
||||||
|
|
@ -79,7 +65,7 @@ WORKDIR /clixon/clixon
|
||||||
COPY clixon .
|
COPY clixon .
|
||||||
|
|
||||||
# Configure, build and install clixon
|
# Configure, build and install clixon
|
||||||
RUN ./configure --prefix=/clixon/build --with-cligen=/clixon/build --with-restconf=native --enable-nghttp2 --enable-evhtp
|
RUN ./configure --prefix=/clixon/build --with-cligen=/clixon/build --with-restconf=native --enable-nghttp2 --enable-http1
|
||||||
|
|
||||||
RUN make
|
RUN make
|
||||||
RUN make install
|
RUN make install
|
||||||
|
|
|
||||||
|
|
@ -38,9 +38,6 @@ MAINTAINER Olof Hagsand <olof@hagsand.se>
|
||||||
# For clixon and cligen
|
# For clixon and cligen
|
||||||
RUN apk add --update git make build-base gcc flex bison curl-dev
|
RUN apk add --update git make build-base gcc flex bison curl-dev
|
||||||
|
|
||||||
# evhtp dependencies
|
|
||||||
RUN apk add --update libevent libevent-dev
|
|
||||||
|
|
||||||
# nghttp2 dependencies
|
# nghttp2 dependencies
|
||||||
RUN apk add --update nghttp2
|
RUN apk add --update nghttp2
|
||||||
|
|
||||||
|
|
@ -62,17 +59,6 @@ RUN git clone https://github.com/openconfig/public
|
||||||
# Create a directory to hold source-code, dependencies etc
|
# Create a directory to hold source-code, dependencies etc
|
||||||
RUN mkdir /clixon
|
RUN mkdir /clixon
|
||||||
|
|
||||||
# clone libevhtp
|
|
||||||
WORKDIR /clixon
|
|
||||||
|
|
||||||
RUN git clone https://github.com/clicon/clixon-libevhtp.git
|
|
||||||
WORKDIR /clixon/clixon-libevhtp
|
|
||||||
RUN ./configure
|
|
||||||
|
|
||||||
RUN make
|
|
||||||
RUN mkdir /usr/local/include
|
|
||||||
RUN make install
|
|
||||||
|
|
||||||
RUN mkdir /clixon/build
|
RUN mkdir /clixon/build
|
||||||
WORKDIR /clixon
|
WORKDIR /clixon
|
||||||
|
|
||||||
|
|
@ -94,7 +80,7 @@ WORKDIR /clixon/clixon
|
||||||
COPY clixon .
|
COPY clixon .
|
||||||
|
|
||||||
# Configure, build and install clixon
|
# Configure, build and install clixon
|
||||||
RUN ./configure --prefix=/clixon/build --with-cligen=/clixon/build --with-restconf=native --enable-nghttp2 --enable-evhtp --with-yang-standard-dir=/usr/local/share/yang/standard
|
RUN ./configure --prefix=/clixon/build --with-cligen=/clixon/build --with-restconf=native --enable-nghttp2 --enable-http1 --with-yang-standard-dir=/usr/local/share/yang/standard
|
||||||
|
|
||||||
RUN make
|
RUN make
|
||||||
RUN make install
|
RUN make install
|
||||||
|
|
@ -148,7 +134,6 @@ EXPOSE 443/tcp
|
||||||
RUN adduser -D -H clicon
|
RUN adduser -D -H clicon
|
||||||
|
|
||||||
COPY --from=0 /clixon/build/ /usr/local/
|
COPY --from=0 /clixon/build/ /usr/local/
|
||||||
COPY --from=0 /usr/local/lib/libevhtp.so* /usr/local/lib/
|
|
||||||
COPY --from=0 /usr/local/share/yang/* /usr/local/share/yang/standard/
|
COPY --from=0 /usr/local/share/yang/* /usr/local/share/yang/standard/
|
||||||
COPY --from=0 /usr/local/share/yang/* /usr/local/share/yang/experimental/
|
COPY --from=0 /usr/local/share/yang/* /usr/local/share/yang/experimental/
|
||||||
COPY --from=0 /usr/local/share/openconfig/* /usr/local/share/openconfig/
|
COPY --from=0 /usr/local/share/openconfig/* /usr/local/share/openconfig/
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@
|
||||||
#
|
#
|
||||||
# ***** END LICENSE BLOCK *****
|
# ***** END LICENSE BLOCK *****
|
||||||
|
|
||||||
# Clixon startscript for evhtp and https
|
# Clixon startscript for native restconf and https
|
||||||
# This script is copied into the container on build time and runs
|
# This script is copied into the container on build time and runs
|
||||||
# _inside_ the container at start in runtime. It gets environment variables
|
# _inside_ the container at start in runtime. It gets environment variables
|
||||||
# from the start.sh script.
|
# from the start.sh script.
|
||||||
|
|
|
||||||
|
|
@ -27,9 +27,6 @@
|
||||||
/* Define to 1 if you have the <cligen/cligen.h> header file. */
|
/* Define to 1 if you have the <cligen/cligen.h> header file. */
|
||||||
#undef HAVE_CLIGEN_CLIGEN_H
|
#undef HAVE_CLIGEN_CLIGEN_H
|
||||||
|
|
||||||
/* Define to 1 if you have the <evhtp/evhtp.h> header file. */
|
|
||||||
#undef HAVE_EVHTP_EVHTP_H
|
|
||||||
|
|
||||||
/* Define to 1 if you have the `getpeereid' function. */
|
/* Define to 1 if you have the `getpeereid' function. */
|
||||||
#undef HAVE_GETPEEREID
|
#undef HAVE_GETPEEREID
|
||||||
|
|
||||||
|
|
@ -54,12 +51,6 @@
|
||||||
/* Define to 1 if you have the `dl' library (-ldl). */
|
/* Define to 1 if you have the `dl' library (-ldl). */
|
||||||
#undef HAVE_LIBDL
|
#undef HAVE_LIBDL
|
||||||
|
|
||||||
/* Define to 1 if you have the `event' library (-levent). */
|
|
||||||
#undef HAVE_LIBEVENT
|
|
||||||
|
|
||||||
/* Define to 1 if you have the `evhtp' library (-levhtp). */
|
|
||||||
#undef HAVE_LIBEVHTP
|
|
||||||
|
|
||||||
/* Define to 1 if you have the `fcgi' library (-lfcgi). */
|
/* Define to 1 if you have the `fcgi' library (-lfcgi). */
|
||||||
#undef HAVE_LIBFCGI
|
#undef HAVE_LIBFCGI
|
||||||
|
|
||||||
|
|
@ -69,6 +60,8 @@
|
||||||
/* Define to 1 if you have the `nghttp2' library (-lnghttp2). */
|
/* Define to 1 if you have the `nghttp2' library (-lnghttp2). */
|
||||||
#undef HAVE_LIBNGHTTP2
|
#undef HAVE_LIBNGHTTP2
|
||||||
|
|
||||||
|
#undef HAVE_HTTP1
|
||||||
|
|
||||||
/* Define to 1 if you have the `socket' library (-lsocket). */
|
/* Define to 1 if you have the `socket' library (-lsocket). */
|
||||||
#undef HAVE_LIBSOCKET
|
#undef HAVE_LIBSOCKET
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -89,6 +89,7 @@ static inline char * strdup4(char *str)
|
||||||
*/
|
*/
|
||||||
char **clicon_strsep(char *string, char *delim, int *nvec0);
|
char **clicon_strsep(char *string, char *delim, int *nvec0);
|
||||||
char *clicon_strjoin (int argc, char **argv, char *delim);
|
char *clicon_strjoin (int argc, char **argv, char *delim);
|
||||||
|
char *clixon_string_del_join(char *str1, char *del, char *str2);
|
||||||
int clixon_strsplit(char *nodeid, const int delim, char **prefix, char **id);
|
int clixon_strsplit(char *nodeid, const int delim, char **prefix, char **id);
|
||||||
int uri_str2cvec(char *string, char delim1, char delim2, int decode, cvec **cvp);
|
int uri_str2cvec(char *string, char delim1, char delim2, int decode, cvec **cvp);
|
||||||
int uri_percent_encode(char **encp, const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
|
int uri_percent_encode(char **encp, const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
|
||||||
|
|
@ -104,6 +105,7 @@ char *clixon_trim(char *str);
|
||||||
char *clixon_trim2(char *str, char *trims);
|
char *clixon_trim2(char *str, char *trims);
|
||||||
int clicon_strcmp(char *s1, char *s2);
|
int clicon_strcmp(char *s1, char *s2);
|
||||||
|
|
||||||
|
|
||||||
#ifndef HAVE_STRNDUP
|
#ifndef HAVE_STRNDUP
|
||||||
char *clicon_strndup (const char *, size_t);
|
char *clicon_strndup (const char *, size_t);
|
||||||
#endif /* ! HAVE_STRNDUP */
|
#endif /* ! HAVE_STRNDUP */
|
||||||
|
|
|
||||||
|
|
@ -82,8 +82,6 @@
|
||||||
/* typecast macro */
|
/* typecast macro */
|
||||||
#define _AY ((clixon_api_path_yacc *)_ay)
|
#define _AY ((clixon_api_path_yacc *)_ay)
|
||||||
|
|
||||||
#define MAXBUF 4*4*64*1024
|
|
||||||
|
|
||||||
#undef clixon_api_path_parsewrap
|
#undef clixon_api_path_parsewrap
|
||||||
int
|
int
|
||||||
clixon_api_path_parsewrap(void)
|
clixon_api_path_parsewrap(void)
|
||||||
|
|
|
||||||
|
|
@ -172,6 +172,11 @@ clicon_files_recursive(const char *dir,
|
||||||
* do something with dp[i].d_name;
|
* do something with dp[i].d_name;
|
||||||
* free(dp);
|
* free(dp);
|
||||||
* @endcode
|
* @endcode
|
||||||
|
* @note "ent" is an array with n fixed entries
|
||||||
|
* But this is not what is returned from the syscall, see man readdir:
|
||||||
|
* ... the use sizeof(struct dirent) to capture the size of the record including
|
||||||
|
* the size of d_name is also incorrect.
|
||||||
|
* @note May block on file I/O
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
clicon_file_dirent(const char *dir,
|
clicon_file_dirent(const char *dir,
|
||||||
|
|
@ -180,7 +185,7 @@ clicon_file_dirent(const char *dir,
|
||||||
mode_t type)
|
mode_t type)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
DIR *dirp;
|
DIR *dirp = NULL;
|
||||||
int res;
|
int res;
|
||||||
int nent;
|
int nent;
|
||||||
regex_t re;
|
regex_t re;
|
||||||
|
|
@ -188,11 +193,8 @@ clicon_file_dirent(const char *dir,
|
||||||
char filename[MAXPATHLEN];
|
char filename[MAXPATHLEN];
|
||||||
struct stat st;
|
struct stat st;
|
||||||
struct dirent *dent;
|
struct dirent *dent;
|
||||||
struct dirent *tmp;
|
|
||||||
struct dirent *new = NULL;
|
struct dirent *new = NULL;
|
||||||
#if 0 /* revert of https://github.com/clicon/clixon/pull/238 */
|
|
||||||
int direntStructSize;
|
int direntStructSize;
|
||||||
#endif
|
|
||||||
|
|
||||||
*ent = NULL;
|
*ent = NULL;
|
||||||
nent = 0;
|
nent = 0;
|
||||||
|
|
@ -225,25 +227,18 @@ clicon_file_dirent(const char *dir,
|
||||||
if ((type & st.st_mode) == 0)
|
if ((type & st.st_mode) == 0)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
#if 0 /* revert of https://github.com/clicon/clixon/pull/238 */
|
|
||||||
direntStructSize = offsetof(struct dirent, d_name) + strlen(dent->d_name) + 1;
|
direntStructSize = offsetof(struct dirent, d_name) + strlen(dent->d_name) + 1;
|
||||||
clicon_debug(1, "%s %u %u %lu", __FUNCTION__, nent, direntStructSize, sizeof(struct dirent));
|
if ((new = realloc(new, (nent+1)*sizeof(struct dirent))) == NULL) {
|
||||||
if ((tmp = realloc(new, (nent+1)*direntStructSize)) == NULL) {
|
|
||||||
#else
|
|
||||||
if ((tmp = realloc(new, (nent+1)*sizeof(struct dirent))) == NULL) {
|
|
||||||
#endif
|
|
||||||
clicon_err(OE_UNIX, errno, "realloc");
|
clicon_err(OE_UNIX, errno, "realloc");
|
||||||
goto quit;
|
goto quit;
|
||||||
}
|
} /* realloc */
|
||||||
new = tmp;
|
|
||||||
#if 0 /* revert of https://github.com/clicon/clixon/pull/238 */
|
|
||||||
clicon_debug(1, "%s memcpy(%p %p %u", __FUNCTION__, &new[nent], dent, direntStructSize);
|
clicon_debug(1, "%s memcpy(%p %p %u", __FUNCTION__, &new[nent], dent, direntStructSize);
|
||||||
memcpy(&new[nent], dent, direntStructSize); /* XXX Invalid write of size 8 */
|
/* man (3) readdir:
|
||||||
#else
|
* By implication, the use sizeof(struct dirent) to capture the size of the record including
|
||||||
memcpy(&new[nent], dent, sizeof(*dent));
|
* the size of d_name is also incorrect. */
|
||||||
#endif
|
memset(&new[nent], 0, sizeof(struct dirent));
|
||||||
|
memcpy(&new[nent], dent, direntStructSize);
|
||||||
nent++;
|
nent++;
|
||||||
|
|
||||||
} /* while */
|
} /* while */
|
||||||
|
|
||||||
qsort((void *)new, nent, sizeof(*new), clicon_file_dirent_sort);
|
qsort((void *)new, nent, sizeof(*new), clicon_file_dirent_sort);
|
||||||
|
|
|
||||||
|
|
@ -79,8 +79,6 @@
|
||||||
/* typecast macro */
|
/* typecast macro */
|
||||||
#define _IY ((clixon_instance_id_yacc *)_iy)
|
#define _IY ((clixon_instance_id_yacc *)_iy)
|
||||||
|
|
||||||
#define MAXBUF 4*4*64*1024
|
|
||||||
|
|
||||||
#undef clixon_instance_id_parsewrap
|
#undef clixon_instance_id_parsewrap
|
||||||
int
|
int
|
||||||
clixon_instance_id_parsewrap(void)
|
clixon_instance_id_parsewrap(void)
|
||||||
|
|
|
||||||
|
|
@ -65,8 +65,6 @@
|
||||||
/* typecast macro */
|
/* typecast macro */
|
||||||
#define _JY ((clixon_json_yacc *)_yy)
|
#define _JY ((clixon_json_yacc *)_yy)
|
||||||
|
|
||||||
#define MAXBUF 4*4*64*1024
|
|
||||||
|
|
||||||
#undef clixon_json_parsewrap
|
#undef clixon_json_parsewrap
|
||||||
int
|
int
|
||||||
clixon_json_parsewrap(void)
|
clixon_json_parsewrap(void)
|
||||||
|
|
|
||||||
|
|
@ -149,6 +149,39 @@ clicon_strjoin(int argc,
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! Join two string with delimiter.
|
||||||
|
* @param[in] str1 string 1 (will be freed) (optional)
|
||||||
|
* @param[in] del delimiter string (not freed) cannot be NULL (but "")
|
||||||
|
* @param[in] str2 string 2 (will be freed)
|
||||||
|
* @see clicon_strjoin
|
||||||
|
*/
|
||||||
|
char*
|
||||||
|
clixon_string_del_join(char *str1,
|
||||||
|
char *del,
|
||||||
|
char *str2)
|
||||||
|
{
|
||||||
|
char *str;
|
||||||
|
int len;
|
||||||
|
|
||||||
|
len = strlen(str2) + 1;
|
||||||
|
|
||||||
|
if (str1)
|
||||||
|
len += strlen(str1);
|
||||||
|
len += strlen(del);
|
||||||
|
if ((str = malloc(len)) == NULL){
|
||||||
|
clicon_err(OE_UNIX, errno, "malloc");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (str1){
|
||||||
|
snprintf(str, len, "%s%s%s", str1, del, str2);
|
||||||
|
free(str1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
snprintf(str, len, "%s%s", del, str2);
|
||||||
|
free(str2);
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
/*! Split a string once into two parts: prefix and suffix
|
/*! Split a string once into two parts: prefix and suffix
|
||||||
* @param[in] string
|
* @param[in] string
|
||||||
* @param[in] delim
|
* @param[in] delim
|
||||||
|
|
@ -564,7 +597,7 @@ xml_chardata_cbuf_append(cbuf *cb,
|
||||||
* @retval -1 error
|
* @retval -1 error
|
||||||
* @code
|
* @code
|
||||||
* cvec *cvv = NULL;
|
* cvec *cvv = NULL;
|
||||||
* if (uri_str2cvec("a=b&c=d", ';', '=', 1, &cvv) < 0)
|
* if (uri_str2cvec("a=b&c=d", '&', '=', 1, &cvv) < 0)
|
||||||
* err;
|
* err;
|
||||||
* @endcode
|
* @endcode
|
||||||
*
|
*
|
||||||
|
|
@ -840,6 +873,7 @@ clicon_strcmp(char *s1,
|
||||||
return strcmp(s1, s2);
|
return strcmp(s1, s2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*! strndup() for systems without it, such as xBSD
|
/*! strndup() for systems without it, such as xBSD
|
||||||
*/
|
*/
|
||||||
#ifndef HAVE_STRNDUP
|
#ifndef HAVE_STRNDUP
|
||||||
|
|
@ -908,4 +942,3 @@ main(int argc, char **argv)
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* Test program */
|
#endif /* Test program */
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -640,8 +640,8 @@ clixon_xml_parse_file(FILE *fp,
|
||||||
int oldxmlbuflen;
|
int oldxmlbuflen;
|
||||||
int failed = 0;
|
int failed = 0;
|
||||||
|
|
||||||
if (xt==NULL){
|
if (xt==NULL || fp == NULL){
|
||||||
clicon_err(OE_XML, EINVAL, "xt is NULL");
|
clicon_err(OE_XML, EINVAL, "arg is NULL");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (yb == YB_MODULE && yspec == NULL){
|
if (yb == YB_MODULE && yspec == NULL){
|
||||||
|
|
|
||||||
|
|
@ -69,8 +69,6 @@
|
||||||
/* typecast macro */
|
/* typecast macro */
|
||||||
#define _XPY ((clixon_xpath_yacc *)_yy)
|
#define _XPY ((clixon_xpath_yacc *)_yy)
|
||||||
|
|
||||||
#define MAXBUF 4*4*64*1024
|
|
||||||
|
|
||||||
#undef clixon_xpath_parsewrap
|
#undef clixon_xpath_parsewrap
|
||||||
int
|
int
|
||||||
clixon_xpath_parsewrap(void)
|
clixon_xpath_parsewrap(void)
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@
|
||||||
* @see https://tools.ietf.org/html/rfc6020 YANG 1.0
|
* @see https://tools.ietf.org/html/rfc6020 YANG 1.0
|
||||||
* @see https://tools.ietf.org/html/rfc7950 YANG 1.1
|
* @see https://tools.ietf.org/html/rfc7950 YANG 1.1
|
||||||
* @note differences in double quoted strings: 1.1 does not allow \x, but 1.0
|
* @note differences in double quoted strings: 1.1 does not allow \x, but 1.0
|
||||||
* does (where x is not n|t|"|\). See mode DQESC
|
* does (where x is not n|t|<double quote)|\). See mode DQESC
|
||||||
*/
|
*/
|
||||||
|
|
||||||
%{
|
%{
|
||||||
|
|
@ -67,11 +67,6 @@
|
||||||
/* typecast macro */
|
/* typecast macro */
|
||||||
#define _YY ((clixon_yang_yacc *)_yy)
|
#define _YY ((clixon_yang_yacc *)_yy)
|
||||||
|
|
||||||
#define MAXBUF 4*4*64*1024
|
|
||||||
|
|
||||||
#define MAX(x,y) ((x)>(y)?(x):(y))
|
|
||||||
#define MIN(x,y) ((x)<(y)?(x):(y))
|
|
||||||
|
|
||||||
#undef clixon_yang_parsewrap
|
#undef clixon_yang_parsewrap
|
||||||
int
|
int
|
||||||
clixon_yang_parsewrap(void)
|
clixon_yang_parsewrap(void)
|
||||||
|
|
|
||||||
|
|
@ -78,7 +78,6 @@
|
||||||
%type <string> identifier_ref_str
|
%type <string> identifier_ref_str
|
||||||
%type <string> bool_str
|
%type <string> bool_str
|
||||||
|
|
||||||
|
|
||||||
/* rfc 6020 keywords
|
/* rfc 6020 keywords
|
||||||
See also enum rfc_6020 in clicon_yang.h. There, the constants have Y_ prefix instead of K_
|
See also enum rfc_6020 in clicon_yang.h. There, the constants have Y_ prefix instead of K_
|
||||||
* Wanted to unify these (K_ and Y_) but gave up for several reasons:
|
* Wanted to unify these (K_ and Y_) but gave up for several reasons:
|
||||||
|
|
@ -154,7 +153,6 @@
|
||||||
%token K_YANG_VERSION
|
%token K_YANG_VERSION
|
||||||
%token K_YIN_ELEMENT
|
%token K_YIN_ELEMENT
|
||||||
|
|
||||||
|
|
||||||
/* Deviate keywords
|
/* Deviate keywords
|
||||||
*/
|
*/
|
||||||
%token D_NOT_SUPPORTED
|
%token D_NOT_SUPPORTED
|
||||||
|
|
@ -192,6 +190,7 @@
|
||||||
#include <cligen/cligen.h>
|
#include <cligen/cligen.h>
|
||||||
|
|
||||||
#include "clixon_queue.h"
|
#include "clixon_queue.h"
|
||||||
|
#include "clixon_string.h"
|
||||||
#include "clixon_hash.h"
|
#include "clixon_hash.h"
|
||||||
#include "clixon_handle.h"
|
#include "clixon_handle.h"
|
||||||
#include "clixon_err.h"
|
#include "clixon_err.h"
|
||||||
|
|
@ -351,37 +350,6 @@ ysp_add_push(clixon_yang_yacc *yy,
|
||||||
return ys;
|
return ys;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Join two string with delimiter.
|
|
||||||
* @param[in] str1 string 1 (will be freed) (optional)
|
|
||||||
* @param[in] del delimiter string (not freed) cannot be NULL (but "")
|
|
||||||
* @param[in] str2 string 2 (will be freed)
|
|
||||||
*/
|
|
||||||
static char*
|
|
||||||
string_del_join(char *str1,
|
|
||||||
char *del,
|
|
||||||
char *str2)
|
|
||||||
{
|
|
||||||
char *str;
|
|
||||||
int len;
|
|
||||||
|
|
||||||
len = strlen(str2) + 1;
|
|
||||||
|
|
||||||
if (str1)
|
|
||||||
len += strlen(str1);
|
|
||||||
len += strlen(del);
|
|
||||||
if ((str = malloc(len)) == NULL){
|
|
||||||
clicon_err(OE_UNIX, errno, "malloc");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
if (str1){
|
|
||||||
snprintf(str, len, "%s%s%s", str1, del, str2);
|
|
||||||
free(str1);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
snprintf(str, len, "%s%s", del, str2);
|
|
||||||
free(str2);
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
|
|
||||||
%}
|
%}
|
||||||
|
|
||||||
|
|
@ -1640,23 +1608,23 @@ deviate_replace_substmt : type_stmt { _PARSE_DEBUG("deviate-replace-subs
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
unknown_stmt : ustring ':' ustring optsep ';'
|
unknown_stmt : ustring ':' ustring optsep ';'
|
||||||
{ char *id; if ((id=string_del_join($1, ":", $3)) == NULL) _YYERROR("unknown_stmt");
|
{ char *id; if ((id=clixon_string_del_join($1, ":", $3)) == NULL) _YYERROR("unknown_stmt");
|
||||||
if (ysp_add(_yy, Y_UNKNOWN, id, NULL) == NULL) _YYERROR("unknown_stmt");
|
if (ysp_add(_yy, Y_UNKNOWN, id, NULL) == NULL) _YYERROR("unknown_stmt");
|
||||||
_PARSE_DEBUG("unknown-stmt -> ustring : ustring ;");
|
_PARSE_DEBUG("unknown-stmt -> ustring : ustring ;");
|
||||||
}
|
}
|
||||||
| ustring ':' ustring sep string optsep ';'
|
| ustring ':' ustring sep string optsep ';'
|
||||||
{ char *id; if ((id=string_del_join($1, ":", $3)) == NULL) _YYERROR("unknown_stmt");
|
{ char *id; if ((id=clixon_string_del_join($1, ":", $3)) == NULL) _YYERROR("unknown_stmt");
|
||||||
if (ysp_add(_yy, Y_UNKNOWN, id, $5) == NULL){ _YYERROR("unknown_stmt"); }
|
if (ysp_add(_yy, Y_UNKNOWN, id, $5) == NULL){ _YYERROR("unknown_stmt"); }
|
||||||
_PARSE_DEBUG("unknown-stmt -> ustring : ustring sep string ;");
|
_PARSE_DEBUG("unknown-stmt -> ustring : ustring sep string ;");
|
||||||
}
|
}
|
||||||
| ustring ':' ustring optsep
|
| ustring ':' ustring optsep
|
||||||
{ char *id; if ((id=string_del_join($1, ":", $3)) == NULL) _YYERROR("unknown_stmt");
|
{ char *id; if ((id=clixon_string_del_join($1, ":", $3)) == NULL) _YYERROR("unknown_stmt");
|
||||||
if (ysp_add_push(_yy, Y_UNKNOWN, id, NULL) == NULL) _YYERROR("unknown_stmt"); }
|
if (ysp_add_push(_yy, Y_UNKNOWN, id, NULL) == NULL) _YYERROR("unknown_stmt"); }
|
||||||
'{' yang_stmts '}'
|
'{' yang_stmts '}'
|
||||||
{ if (ystack_pop(_yy) < 0) _YYERROR("unknown_stmt");
|
{ if (ystack_pop(_yy) < 0) _YYERROR("unknown_stmt");
|
||||||
_PARSE_DEBUG("unknown-stmt -> ustring : ustring { yang-stmts }"); }
|
_PARSE_DEBUG("unknown-stmt -> ustring : ustring { yang-stmts }"); }
|
||||||
| ustring ':' ustring sep string optsep
|
| ustring ':' ustring sep string optsep
|
||||||
{ char *id; if ((id=string_del_join($1, ":", $3)) == NULL) _YYERROR("unknown_stmt");
|
{ char *id; if ((id=clixon_string_del_join($1, ":", $3)) == NULL) _YYERROR("unknown_stmt");
|
||||||
if (ysp_add_push(_yy, Y_UNKNOWN, id, $5) == NULL) _YYERROR("unknown_stmt"); }
|
if (ysp_add_push(_yy, Y_UNKNOWN, id, $5) == NULL) _YYERROR("unknown_stmt"); }
|
||||||
'{' yang_stmts '}'
|
'{' yang_stmts '}'
|
||||||
{ if (ystack_pop(_yy) < 0) _YYERROR("unknown_stmt");
|
{ if (ystack_pop(_yy) < 0) _YYERROR("unknown_stmt");
|
||||||
|
|
@ -1850,10 +1818,10 @@ ustring : ustring CHARS
|
||||||
;
|
;
|
||||||
|
|
||||||
abs_schema_nodeid : abs_schema_nodeid '/' node_identifier
|
abs_schema_nodeid : abs_schema_nodeid '/' node_identifier
|
||||||
{ if (($$=string_del_join($1, "/", $3)) == NULL) _YYERROR("abs_schema_nodeid");
|
{ if (($$=clixon_string_del_join($1, "/", $3)) == NULL) _YYERROR("abs_schema_nodeid");
|
||||||
_PARSE_DEBUG("absolute-schema-nodeid -> absolute-schema-nodeid / node-identifier"); }
|
_PARSE_DEBUG("absolute-schema-nodeid -> absolute-schema-nodeid / node-identifier"); }
|
||||||
| '/' node_identifier
|
| '/' node_identifier
|
||||||
{ if (($$=string_del_join(NULL, "/", $2)) == NULL) _YYERROR("abs_schema_nodeid");
|
{ if (($$=clixon_string_del_join(NULL, "/", $2)) == NULL) _YYERROR("abs_schema_nodeid");
|
||||||
_PARSE_DEBUG("absolute-schema-nodeid -> / node-identifier"); }
|
_PARSE_DEBUG("absolute-schema-nodeid -> / node-identifier"); }
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
@ -1887,7 +1855,7 @@ desc_schema_nodeid : node_identifier
|
||||||
{ $$= $1;
|
{ $$= $1;
|
||||||
_PARSE_DEBUG("descendant-schema-nodeid -> node_identifier"); }
|
_PARSE_DEBUG("descendant-schema-nodeid -> node_identifier"); }
|
||||||
| node_identifier abs_schema_nodeid
|
| node_identifier abs_schema_nodeid
|
||||||
{ if (($$=string_del_join($1, "", $2)) == NULL) _YYERROR("desc_schema_nodeid");
|
{ if (($$=clixon_string_del_join($1, "", $2)) == NULL) _YYERROR("desc_schema_nodeid");
|
||||||
_PARSE_DEBUG("descendant-schema-nodeid -> node_identifier abs_schema_nodeid"); }
|
_PARSE_DEBUG("descendant-schema-nodeid -> node_identifier abs_schema_nodeid"); }
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
@ -1926,7 +1894,7 @@ node_identifier : IDENTIFIER
|
||||||
{ $$=$1;
|
{ $$=$1;
|
||||||
_PARSE_DEBUG("identifier-ref-arg-str -> string"); }
|
_PARSE_DEBUG("identifier-ref-arg-str -> string"); }
|
||||||
| IDENTIFIER ':' IDENTIFIER
|
| IDENTIFIER ':' IDENTIFIER
|
||||||
{ if (($$=string_del_join($1, ":", $3)) == NULL) _YYERROR("node_identifier");
|
{ if (($$=clixon_string_del_join($1, ":", $3)) == NULL) _YYERROR("node_identifier");
|
||||||
_PARSE_DEBUG("identifier-ref-arg-str -> prefix : string"); }
|
_PARSE_DEBUG("identifier-ref-arg-str -> prefix : string"); }
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -114,7 +114,7 @@ For example, in FreeBSD, add:
|
||||||
|
|
||||||
For fcgi/nginx you need to setup https in the nginx config file, independently of clixon.
|
For fcgi/nginx you need to setup https in the nginx config file, independently of clixon.
|
||||||
|
|
||||||
If you use evhtp with `configure --with-restconf=evhtp`, you can prepend the tests with RCPROTO=https which will run all restconf tests with SSL https and server certs.
|
If you use native with `configure --with-restconf=http1`, you can prepend the tests with RCPROTO=https which will run all restconf tests with SSL https and server certs.
|
||||||
|
|
||||||
Ensure the server keys are in order, as follows.
|
Ensure the server keys are in order, as follows.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,7 @@ SHELL = /bin/sh
|
||||||
# eg :
|
# eg :
|
||||||
# HOSTS += vandal.hagsand.com # i86_32 ubuntu
|
# HOSTS += vandal.hagsand.com # i86_32 ubuntu
|
||||||
# ...
|
# ...
|
||||||
# You can also set RESTCONF to fcgi or evhtp
|
# You can also set RESTCONF to fcgi or native
|
||||||
RESTCONF=fcgi
|
RESTCONF=fcgi
|
||||||
HOSTS=
|
HOSTS=
|
||||||
-include site.mk
|
-include site.mk
|
||||||
|
|
|
||||||
|
|
@ -42,12 +42,6 @@ ssh -t $h "test -d src/cligen || (cd src;git clone https://github.com/clicon/cli
|
||||||
ssh -t $h "(cd src/cligen;git pull origin master)"
|
ssh -t $h "(cd src/cligen;git pull origin master)"
|
||||||
ssh -t $h "(cd src/cligen;./configure)"
|
ssh -t $h "(cd src/cligen;./configure)"
|
||||||
ssh -t $h "(cd src/cligen; /tmp/cligen-mk.sh)"
|
ssh -t $h "(cd src/cligen; /tmp/cligen-mk.sh)"
|
||||||
# pull git changes and build clixon-libevhtp
|
|
||||||
ssh -t $h "test -d src || mkdir src"
|
|
||||||
ssh -t $h "test -d src/clixon-libevhtp || (cd src;git clone https://github.com/clicon/clixon-libevhtp.git)"
|
|
||||||
ssh -t $h "(cd src/clixon-libevhtp;git pull origin master)"
|
|
||||||
ssh -t $h "(cd src/clixon-libevhtp;./configure)"
|
|
||||||
ssh -t $h "(cd src/clixon-libevhtp; /tmp/cligen-mk.sh)" # re-use cligen
|
|
||||||
# pull git changes and build clixon
|
# pull git changes and build clixon
|
||||||
ssh -t $h "test -d src/clixon || (cd src;git clone https://github.com/clicon/clixon.git)"
|
ssh -t $h "test -d src/clixon || (cd src;git clone https://github.com/clicon/clixon.git)"
|
||||||
ssh -t $h "(cd src/clixon;git pull origin master)"
|
ssh -t $h "(cd src/clixon;git pull origin master)"
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# ***** BEGIN LICENSE BLOCK *****
|
# ***** BEGIN LICENSE BLOCK *****
|
||||||
#
|
#
|
||||||
# Copyright (C) 2020-2021 Olof Hagsand and Rubicon Communications, LLC
|
# Copyright (C) 2020-2022 Olof Hagsand and Rubicon Communications, LLC
|
||||||
#
|
#
|
||||||
# This file is part of CLIXON
|
# This file is part of CLIXON
|
||||||
#
|
#
|
||||||
|
|
@ -37,11 +37,11 @@
|
||||||
# This is for RESTCONF. There are three options:
|
# This is for RESTCONF. There are three options:
|
||||||
# --without-restconf No restconf support
|
# --without-restconf No restconf support
|
||||||
# --with-restconf=fcgi FCGI interface for separate web reverse proxy like nginx
|
# --with-restconf=fcgi FCGI interface for separate web reverse proxy like nginx
|
||||||
# --with-restconf=native Integration with embedded web server libevhtp
|
# --with-restconf=native Integration with embedded web server
|
||||||
WITH_RESTCONF=@with_restconf@ # native, fcgi or ""
|
WITH_RESTCONF=@with_restconf@ # native, fcgi or ""
|
||||||
|
|
||||||
HAVE_LIBNGHTTP2=@HAVE_LIBNGHTTP2@
|
HAVE_LIBNGHTTP2=@HAVE_LIBNGHTTP2@
|
||||||
HAVE_LIBEVHTP=@HAVE_LIBEVHTP@
|
HAVE_HTTP1=@HAVE_HTTP1@
|
||||||
|
|
||||||
# This is for libxml2 XSD regex engine
|
# This is for libxml2 XSD regex engine
|
||||||
# Note this only enables the compiling of the code. In order to actually
|
# Note this only enables the compiling of the code. In order to actually
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ Make a modification to how Clixon sends internal messages in `include/clixon_cus
|
||||||
|
|
||||||
Build clixon statically with the afl-clang compiler:
|
Build clixon statically with the afl-clang compiler:
|
||||||
```
|
```
|
||||||
CC=/usr/bin/afl-clang-fast LINKAGE=static ./configure --with-restconf=evhtp
|
CC=/usr/bin/afl-clang-fast LINKAGE=static ./configure --with-restconf=native
|
||||||
make clean
|
make clean
|
||||||
make
|
make
|
||||||
sudo make install
|
sudo make install
|
||||||
|
|
|
||||||
|
|
@ -102,11 +102,11 @@ DEFAULTHELLO="<?xml version=\"1.0\" encoding=\"UTF-8\"?><hello $DEFAULTNS><capab
|
||||||
# Set HTTP version 1.1 or 2
|
# Set HTTP version 1.1 or 2
|
||||||
if ${HAVE_LIBNGHTTP2}; then
|
if ${HAVE_LIBNGHTTP2}; then
|
||||||
HVER=2
|
HVER=2
|
||||||
if ${HAVE_LIBEVHTP}; then
|
if ${HAVE_HTTP1}; then
|
||||||
# This is if evhtp is enabled (unset proto=HTTP_2 in restconf_accept_client)
|
# This is if http/1 is enabled (unset proto=HTTP_2 in restconf_accept_client)
|
||||||
CURLOPTS="${CURLOPTS} --http2"
|
CURLOPTS="${CURLOPTS} --http2"
|
||||||
else
|
else
|
||||||
# This is if evhtp is disabled (set proto=HTTP_2 in restconf_accept_client)
|
# This is if http/1 is disabled (set proto=HTTP_2 in restconf_accept_client)
|
||||||
CURLOPTS="${CURLOPTS} --http2-prior-knowledge"
|
CURLOPTS="${CURLOPTS} --http2-prior-knowledge"
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
|
|
|
||||||
|
|
@ -150,7 +150,7 @@ sed '/Connection:/d' $foutput > $foutput2 && mv $foutput2 $foutput
|
||||||
|
|
||||||
# Create a file to compare with
|
# Create a file to compare with
|
||||||
if ${HAVE_LIBNGHTTP2}; then
|
if ${HAVE_LIBNGHTTP2}; then
|
||||||
if [ ${HAVE_LIBEVHTP} -a ${RCPROTO} = http ]; then
|
if [ ${HAVE_HTTP1} -a ${RCPROTO} = http ]; then
|
||||||
# Add 101 switch protocols for http 1->2 upgrade
|
# Add 101 switch protocols for http 1->2 upgrade
|
||||||
echo "HTTP/1.1 101 Switching Protocols
" > $ftest
|
echo "HTTP/1.1 101 Switching Protocols
" > $ftest
|
||||||
echo "Upgrade: h2c
" >> $ftest
|
echo "Upgrade: h2c
" >> $ftest
|
||||||
|
|
|
||||||
|
|
@ -164,7 +164,7 @@ function testrun()
|
||||||
fi
|
fi
|
||||||
|
|
||||||
#------------------------------------------------------- HTTP/1 + HTTP/2
|
#------------------------------------------------------- HTTP/1 + HTTP/2
|
||||||
if [ ${HAVE_LIBNGHTTP2} = true -a ${HAVE_LIBEVHTP} = true ]; then
|
if [ ${HAVE_LIBNGHTTP2} = true -a ${HAVE_HTTP1} = true ]; then
|
||||||
|
|
||||||
if [ $proto = http ]; then # No plain http/2
|
if [ $proto = http ]; then # No plain http/2
|
||||||
HVER=1.1
|
HVER=1.1
|
||||||
|
|
@ -213,7 +213,7 @@ function testrun()
|
||||||
fi
|
fi
|
||||||
|
|
||||||
#------------------------------------------------------- HTTP/2 ONLY
|
#------------------------------------------------------- HTTP/2 ONLY
|
||||||
elif [ ${HAVE_LIBNGHTTP2} = true -a ${HAVE_LIBEVHTP} = false ]; then
|
elif [ ${HAVE_LIBNGHTTP2} = true -a ${HAVE_HTTP1} = false ]; then
|
||||||
HVER=2
|
HVER=2
|
||||||
|
|
||||||
new "wait restconf"
|
new "wait restconf"
|
||||||
|
|
@ -539,7 +539,7 @@ function testrun()
|
||||||
# Go thru all combinations of IPv4/IPv6, http/https, local/backend config
|
# Go thru all combinations of IPv4/IPv6, http/https, local/backend config
|
||||||
if [ "${WITH_RESTCONF}" = "fcgi" ]; then
|
if [ "${WITH_RESTCONF}" = "fcgi" ]; then
|
||||||
protos="http"
|
protos="http"
|
||||||
elif ${HAVE_LIBEVHTP}; then
|
elif ${HAVE_HTTP1}; then
|
||||||
protos="http" # No plain http for http/2 only
|
protos="http" # No plain http for http/2 only
|
||||||
fi
|
fi
|
||||||
if [ "${WITH_RESTCONF}" = "native" ]; then
|
if [ "${WITH_RESTCONF}" = "native" ]; then
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,8 @@
|
||||||
# Magic line must be first in script (see README.md)
|
# Magic line must be first in script (see README.md)
|
||||||
s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi
|
s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi
|
||||||
|
|
||||||
if ! ${HAVE_LIBEVHTP}; then
|
if ! ${HAVE_HTTP1}; then
|
||||||
echo "...skipped: LIBEVHTP is false, must run with http/1 (evhtp)"
|
echo "...skipped: Must run with http/1"
|
||||||
if [ "$s" = $0 ]; then exit 0; else return 0; fi
|
if [ "$s" = $0 ]; then exit 0; else return 0; fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,9 +23,9 @@
|
||||||
# Magic line must be first in script (see README.md)
|
# Magic line must be first in script (see README.md)
|
||||||
s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi
|
s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi
|
||||||
|
|
||||||
# Does not work with evhtpnative http/2-only
|
# Does not work with native http/2-only
|
||||||
if [ "${WITH_RESTCONF}" = "native" -a ${HAVE_LIBEVHTP} = false ]; then
|
if [ "${WITH_RESTCONF}" = "native" -a ${HAVE_HTTP1} = false ]; then
|
||||||
echo "...skipped: LIBEVHTP is false, must run with http/1 (evhtp)"
|
echo "...skipped: must run with http/1"
|
||||||
if [ "$s" = $0 ]; then exit 0; else return 0; fi
|
if [ "$s" = $0 ]; then exit 0; else return 0; fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
@ -206,7 +206,7 @@ expectpart "$(curl $CURLOPTS -X GET -H 'Accept: application/yang-data+xml' $RCPR
|
||||||
if [ false -a ! ${HAVE_LIBNGHTTP2} ] ; then
|
if [ false -a ! ${HAVE_LIBNGHTTP2} ] ; then
|
||||||
# Look for netcat or nc for direct socket http calls
|
# Look for netcat or nc for direct socket http calls
|
||||||
if [ -n "$(type netcat 2> /dev/null)" ]; then
|
if [ -n "$(type netcat 2> /dev/null)" ]; then
|
||||||
netcat="netcat -w 1" # -N works on evhtp but not fcgi
|
netcat="netcat -w 1" # -N does not work on fcgi
|
||||||
elif [ -n "$(type nc 2> /dev/null)" ]; then
|
elif [ -n "$(type nc 2> /dev/null)" ]; then
|
||||||
netcat=nc
|
netcat=nc
|
||||||
else
|
else
|
||||||
|
|
@ -241,9 +241,8 @@ Host: localhost
|
||||||
Accept: application/yang-data+xml
|
Accept: application/yang-data+xml
|
||||||
|
|
||||||
EOF
|
EOF
|
||||||
)" 0 "HTTP/$HVER 405" kalle # nginx uses "method not allowed" evhtp "not allowed"
|
)" 0 "HTTP/$HVER 405" kalle # nginx uses "method not allowed"
|
||||||
|
|
||||||
# XXX error from evhtp parsing, should pick up error code
|
|
||||||
new "restconf GET wrong http version raw"
|
new "restconf GET wrong http version raw"
|
||||||
expectpart "$(${netcat} 127.0.0.1 80 <<EOF
|
expectpart "$(${netcat} 127.0.0.1 80 <<EOF
|
||||||
GET /restconf/data/example:a=0 HTTP/a.1
|
GET /restconf/data/example:a=0 HTTP/a.1
|
||||||
|
|
|
||||||
|
|
@ -16,8 +16,8 @@ if [ "${WITH_RESTCONF}" != "native" ]; then
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Cant make it work in sum.sh...
|
# Cant make it work in sum.sh...
|
||||||
if ! ${HAVE_LIBEVHTP}; then
|
if ! ${HAVE_HTTP1}; then
|
||||||
echo "...skipped: LIBEVHTP is false, must run with http/1 (evhtp)"
|
echo "...skipped: must run with http/1"
|
||||||
if [ "$s" = $0 ]; then exit 0; else return 0; fi
|
if [ "$s" = $0 ]; then exit 0; else return 0; fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
@ -85,7 +85,7 @@ function testrun()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if [ ${HAVE_LIBNGHTTP2} = false -a ${HAVE_LIBEVHTP} = true ]; then # http/1 only
|
if [ ${HAVE_LIBNGHTTP2} = false -a ${HAVE_HTTP1} = true ]; then # http/1 only
|
||||||
|
|
||||||
new "wait restconf"
|
new "wait restconf"
|
||||||
wait_restconf
|
wait_restconf
|
||||||
|
|
@ -106,7 +106,7 @@ function testrun()
|
||||||
echo "curl -Ssik --http2-prior-knowledge -X GET http://localhost/.well-known/host-meta"
|
echo "curl -Ssik --http2-prior-knowledge -X GET http://localhost/.well-known/host-meta"
|
||||||
expectpart "$(curl -Ssik --http2-prior-knowledge -X GET http://localhost/.well-known/host-meta 2>&1)" "16 52 55"
|
expectpart "$(curl -Ssik --http2-prior-knowledge -X GET http://localhost/.well-known/host-meta 2>&1)" "16 52 55"
|
||||||
|
|
||||||
elif [ ${HAVE_LIBNGHTTP2} = true -a ${HAVE_LIBEVHTP} = false ]; then # http/2 only
|
elif [ ${HAVE_LIBNGHTTP2} = true -a ${HAVE_HTTP1} = false ]; then # http/2 only
|
||||||
|
|
||||||
sleep 2 # Cannot do wait restconf
|
sleep 2 # Cannot do wait restconf
|
||||||
|
|
||||||
|
|
@ -141,7 +141,7 @@ function testrun()
|
||||||
expectpart "$(curl -Ssik --http2-prior-knowledge -X GET http://localhost/.well-known/host-meta 2>&1)" 0 "HTTP/2 405"
|
expectpart "$(curl -Ssik --http2-prior-knowledge -X GET http://localhost/.well-known/host-meta 2>&1)" 0 "HTTP/2 405"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
elif [ ${HAVE_LIBNGHTTP2} = true -a ${HAVE_LIBEVHTP} = true ]; then # http/1 + http/2
|
elif [ ${HAVE_LIBNGHTTP2} = true -a ${HAVE_HTTP1} = true ]; then # http/1 + http/2
|
||||||
|
|
||||||
new "wait restconf"
|
new "wait restconf"
|
||||||
wait_restconf
|
wait_restconf
|
||||||
|
|
|
||||||
|
|
@ -14,9 +14,9 @@
|
||||||
# Magic line must be first in script (see README.md)
|
# Magic line must be first in script (see README.md)
|
||||||
s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi
|
s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi
|
||||||
|
|
||||||
# Does not work with evhtpnative http/2-only
|
# Does not work with native http/2-only
|
||||||
if [ "${WITH_RESTCONF}" = "native" -a ${HAVE_LIBEVHTP} = false ]; then
|
if [ "${WITH_RESTCONF}" = "native" -a ${HAVE_HTTP1} = false ]; then
|
||||||
echo "...skipped: LIBEVHTP is false, must run with http/1 (evhtp)"
|
echo "...skipped: Must run with http/1"
|
||||||
if [ "$s" = $0 ]; then exit 0; else return 0; fi
|
if [ "$s" = $0 ]; then exit 0; else return 0; fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,9 +25,9 @@
|
||||||
# Magic line must be first in script (see README.md)
|
# Magic line must be first in script (see README.md)
|
||||||
s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi
|
s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi
|
||||||
|
|
||||||
# Does not work with evhtpnative http/2-only
|
# Does not work with native http/2-only
|
||||||
if [ "${WITH_RESTCONF}" = "native" -a ${HAVE_LIBEVHTP} = false ]; then
|
if [ "${WITH_RESTCONF}" = "native" -a ${HAVE_HTTP1} = false ]; then
|
||||||
echo "...skipped: LIBEVHTP is false, must run with http/1 (evhtp)"
|
echo "...skipped: Must run with http/1"
|
||||||
if [ "$s" = $0 ]; then exit 0; else return 0; fi
|
if [ "$s" = $0 ]; then exit 0; else return 0; fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,8 +16,8 @@ if [ "${WITH_RESTCONF}" != "native" ]; then
|
||||||
if [ "$s" = $0 ]; then exit 0; else return 0; fi # skip
|
if [ "$s" = $0 ]; then exit 0; else return 0; fi # skip
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if ! ${HAVE_LIBEVHTP}; then
|
if ! ${HAVE_HTTP1}; then
|
||||||
echo "...skipped: LIBEVHTP is false, must run with http/1 (evhtp)"
|
echo "...skipped: HAVE_HTTP1 is false, must run with http/1"
|
||||||
if [ "$s" = $0 ]; then exit 0; else return 0; fi
|
if [ "$s" = $0 ]; then exit 0; else return 0; fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
@ -197,7 +197,7 @@ new "netconf commit"
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO<rpc $DEFAULTNS><commit/></rpc>]]>]]>" "^<rpc-reply $DEFAULTNS><ok/></rpc-reply>]]>]]>$"
|
expecteof "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO<rpc $DEFAULTNS><commit/></rpc>]]>]]>" "^<rpc-reply $DEFAULTNS><ok/></rpc-reply>]]>]]>$"
|
||||||
|
|
||||||
# NOTE http/1.1
|
# NOTE http/1.1
|
||||||
if ${HAVE_LIBEVHTP}; then
|
if ${HAVE_HTTP1}; then
|
||||||
new "restconf http get config on default netns"
|
new "restconf http get config on default netns"
|
||||||
expectpart "$(curl $CURLOPTS -X GET -H 'Accept: application/yang-data+xml' http://127.0.0.1/restconf/data/clixon-example:table)" 0 "HTTP/1.1 200" '<table xmlns="urn:example:clixon"><parameter><name>a</name><value>42</value></parameter></table>'
|
expectpart "$(curl $CURLOPTS -X GET -H 'Accept: application/yang-data+xml' http://127.0.0.1/restconf/data/clixon-example:table)" 0 "HTTP/1.1 200" '<table xmlns="urn:example:clixon"><parameter><name>a</name><value>42</value></parameter></table>'
|
||||||
fi
|
fi
|
||||||
|
|
@ -211,7 +211,7 @@ expectpart "$(sudo ip netns exec $netns curl $CURLOPTS -X GET -H 'Accept: applic
|
||||||
new "restconf https/SSL put table b"
|
new "restconf https/SSL put table b"
|
||||||
expectpart "$(sudo ip netns exec $netns curl $CURLOPTS -X POST -H 'Content-Type: application/yang-data+xml' -d '<parameter xmlns="urn:example:clixon"><name>b</name><value>99</value></parameter>' https://$vaddr/restconf/data/clixon-example:table)" 0 "HTTP/$HVER 201"
|
expectpart "$(sudo ip netns exec $netns curl $CURLOPTS -X POST -H 'Content-Type: application/yang-data+xml' -d '<parameter xmlns="urn:example:clixon"><name>b</name><value>99</value></parameter>' https://$vaddr/restconf/data/clixon-example:table)" 0 "HTTP/$HVER 201"
|
||||||
|
|
||||||
if ${HAVE_LIBEVHTP}; then
|
if ${HAVE_HTTP1}; then
|
||||||
# NOTE http/1.1
|
# NOTE http/1.1
|
||||||
new "restconf http get table b on default ns"
|
new "restconf http get table b on default ns"
|
||||||
expectpart "$(curl $CURLOPTS -X GET -H 'Accept: application/yang-data+xml' http://127.0.0.1/restconf/data/clixon-example:table/parameter=b)" 0 "HTTP/1.1 200" '<parameter xmlns="urn:example:clixon"><name>b</name><value>99</value></parameter>'
|
expectpart "$(curl $CURLOPTS -X GET -H 'Accept: application/yang-data+xml' http://127.0.0.1/restconf/data/clixon-example:table/parameter=b)" 0 "HTTP/1.1 200" '<parameter xmlns="urn:example:clixon"><name>b</name><value>99</value></parameter>'
|
||||||
|
|
|
||||||
|
|
@ -215,7 +215,6 @@ case $release in
|
||||||
;;
|
;;
|
||||||
native)
|
native)
|
||||||
$sshcmd sudo apt install -y libssl-dev
|
$sshcmd sudo apt install -y libssl-dev
|
||||||
$sshcmd sudo apt install -y libevent-dev # evhtp
|
|
||||||
$sshcmd sudo apt install -y libnghttp2-dev # nghttp2
|
$sshcmd sudo apt install -y libnghttp2-dev # nghttp2
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
@ -269,15 +268,6 @@ case ${with_restconf} in
|
||||||
. ./nginx.sh $dir $idfile $port $wwwuser
|
. ./nginx.sh $dir $idfile $port $wwwuser
|
||||||
;;
|
;;
|
||||||
native)
|
native)
|
||||||
$sshcmd << EOF
|
|
||||||
test -d src || mkdir src
|
|
||||||
cd src
|
|
||||||
test -d clixon-libevhtp || git clone https://github.com/clicon/clixon-libevhtp.git
|
|
||||||
cd clixon-libevhtp;
|
|
||||||
./configure --libdir=/usr/lib # otherwise in /usr/local/lib where RH dont look
|
|
||||||
make
|
|
||||||
sudo make install
|
|
||||||
EOF
|
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -71,7 +71,7 @@ module clixon-restconf {
|
||||||
proxy solution.
|
proxy solution.
|
||||||
That is, a reverse proxy is the HTTP front-end and the restconf daemon listens
|
That is, a reverse proxy is the HTTP front-end and the restconf daemon listens
|
||||||
to a fcgi socket.
|
to a fcgi socket.
|
||||||
The alternative is the internal HTTP solution using evhtp.";
|
The alternative is the internal native HTTP solution.";
|
||||||
}
|
}
|
||||||
|
|
||||||
feature allow-auth-none {
|
feature allow-auth-none {
|
||||||
|
|
@ -183,10 +183,10 @@ module clixon-restconf {
|
||||||
description
|
description
|
||||||
"Path to FastCGI unix socket. Should be specified in webserver
|
"Path to FastCGI unix socket. Should be specified in webserver
|
||||||
Eg in nginx: fastcgi_pass unix:/www-data/clicon_restconf.sock
|
Eg in nginx: fastcgi_pass unix:/www-data/clicon_restconf.sock
|
||||||
Only if with-restconf=fcgi, NOT evhtp
|
Only if with-restconf=fcgi, NOT native
|
||||||
This replaces CLICON_RESTCONF_PATH option in clixon-config.yang";
|
This replaces CLICON_RESTCONF_PATH option in clixon-config.yang";
|
||||||
}
|
}
|
||||||
/* Second, evhtp-specific options */
|
/* Second, local native options */
|
||||||
leaf server-cert-path {
|
leaf server-cert-path {
|
||||||
type string;
|
type string;
|
||||||
description
|
description
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue