From dadf4a778ab6e17c7a074e60083992cd60bc349e Mon Sep 17 00:00:00 2001 From: Olof hagsand Date: Wed, 26 Jan 2022 13:48:20 +0100 Subject: [PATCH] * 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 --- CHANGELOG.md | 6 + apps/backend/backend_plugin.c | 1 - apps/backend/clixon_backend_handle.c | 1 - apps/backend/clixon_backend_transaction.c | 1 - apps/cli/cli_plugin.c | 1 - apps/restconf/Makefile.in | 23 +- apps/restconf/README.md | 11 +- apps/restconf/clixon_http1.c | 248 +++++++ .../{restconf_evhtp.h => clixon_http1.h} | 18 +- apps/restconf/clixon_http1_parse.h | 71 ++ apps/restconf/clixon_http1_parse.l | 164 +++++ apps/restconf/clixon_http1_parse.y | 289 ++++++++ apps/restconf/restconf_api_native.c | 11 +- apps/restconf/restconf_evhtp.c | 681 ------------------ apps/restconf/restconf_handle.c | 1 - apps/restconf/restconf_main_native.c | 278 +++---- apps/restconf/restconf_native.c | 13 +- apps/restconf/restconf_native.h | 7 +- apps/restconf/restconf_nghttp2.c | 25 +- configure | 145 +--- configure.ac | 31 +- doc/DEVELOP.md | 11 + docker/base/Dockerfile | 17 +- docker/clixon-dev/Dockerfile | 16 +- docker/main/Dockerfile.native | 17 +- docker/main/startsystem_native.sh | 2 +- include/clixon_config.h.in | 11 +- lib/clixon/clixon_string.h | 4 +- lib/src/clixon_api_path_parse.l | 2 - lib/src/clixon_file.c | 31 +- lib/src/clixon_instance_id_parse.l | 2 - lib/src/clixon_json_parse.l | 2 - lib/src/clixon_string.c | 37 +- lib/src/clixon_xml_io.c | 4 +- lib/src/clixon_xpath_parse.l | 2 - lib/src/clixon_yang_parse.l | 7 +- lib/src/clixon_yang_parse.y | 50 +- test/README.md | 2 +- test/cicd/Makefile.in | 2 +- test/cicd/cicd.sh | 6 - test/config.sh.in | 6 +- test/fuzz/backend/README.md | 2 +- test/lib.sh | 6 +- test/test_perf_restconf.sh | 2 +- test/test_restconf.sh | 6 +- test/test_restconf_basic_auth.sh | 4 +- test/test_restconf_err.sh | 11 +- test/test_restconf_http_upgrade.sh | 10 +- test/test_restconf_internal.sh | 6 +- test/test_restconf_internal_usecases.sh | 6 +- test/test_restconf_netns.sh | 8 +- test/vagrant/vagrant.sh | 10 - yang/clixon/clixon-restconf@2021-05-20.yang | 6 +- 53 files changed, 1061 insertions(+), 1273 deletions(-) create mode 100644 apps/restconf/clixon_http1.c rename apps/restconf/{restconf_evhtp.h => clixon_http1.h} (76%) create mode 100644 apps/restconf/clixon_http1_parse.h create mode 100644 apps/restconf/clixon_http1_parse.l create mode 100644 apps/restconf/clixon_http1_parse.y delete mode 100644 apps/restconf/restconf_evhtp.c diff --git a/CHANGELOG.md b/CHANGELOG.md index d44230e7..5b3138dd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -36,6 +36,12 @@ ## 5.6.0 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 Users may have to change how they access the system diff --git a/apps/backend/backend_plugin.c b/apps/backend/backend_plugin.c index a3a04f2c..a3c18d46 100644 --- a/apps/backend/backend_plugin.c +++ b/apps/backend/backend_plugin.c @@ -45,7 +45,6 @@ #include #include #include -#include #include #include #include diff --git a/apps/backend/clixon_backend_handle.c b/apps/backend/clixon_backend_handle.c index f64f97bd..a5d0fb43 100644 --- a/apps/backend/clixon_backend_handle.c +++ b/apps/backend/clixon_backend_handle.c @@ -44,7 +44,6 @@ #include #include #include -#include #include #include #include diff --git a/apps/backend/clixon_backend_transaction.c b/apps/backend/clixon_backend_transaction.c index 994446a6..793a277f 100644 --- a/apps/backend/clixon_backend_transaction.c +++ b/apps/backend/clixon_backend_transaction.c @@ -46,7 +46,6 @@ #include #include #include -#include #include #include #include diff --git a/apps/cli/cli_plugin.c b/apps/cli/cli_plugin.c index e198c658..357e984e 100644 --- a/apps/cli/cli_plugin.c +++ b/apps/cli/cli_plugin.c @@ -49,7 +49,6 @@ #include #define __USE_GNU /* For RTLD_DEFAULT */ #include -#include #include #include #include diff --git a/apps/restconf/Makefile.in b/apps/restconf/Makefile.in index 0ee7f5b0..4c52e621 100644 --- a/apps/restconf/Makefile.in +++ b/apps/restconf/Makefile.in @@ -100,10 +100,10 @@ APPSRC += restconf_methods_post.c APPSRC += restconf_methods_get.c APPSRC += restconf_methods_patch.c APPSRC += restconf_root.c +APPSRC += clixon_http1.c APPSRC += restconf_main_$(with_restconf).c ifeq ($(with_restconf),native) APPSRC += restconf_native.c -APPSRC += restconf_evhtp.c # HTTP/1 APPSRC += restconf_nghttp2.c # HTTP/2 endif @@ -113,7 +113,10 @@ ifeq ($(with_restconf),fcgi) APPSRC += restconf_stream_$(with_restconf).c endif -APPOBJ = $(APPSRC:.c=.o) +# internal http/1 parser +YACCOBJS = lex.clixon_http1_parse.o clixon_http1_parse.tab.o + +APPOBJ = $(APPSRC:.c=.o) $(YACCOBJS) # Accessible from plugin # XXX actually this does not work properly, there are functions in lib @@ -125,6 +128,8 @@ LIBSRC += restconf_api_$(with_restconf).c LIBOBJ = $(LIBSRC:.c=.o) + + # This lib is very small but used for clixon restconf applications to access clixon restconf lib # functions. Mostly for future use MYNAME = clixon_restconf @@ -147,6 +152,7 @@ $(top_srcdir)/lib/src/$(CLIXON_LIB): clean: rm -f $(LIBOBJ) *.core $(APPL) $(APPOBJ) *.o $(MYLIBDYNAMIC) $(MYLIBSTATIC) $(MYLIBSO) $(MYLIBLINK) # extra .o to clean residue if with_restconf changes rm -f *.gcda *.gcno *.gcov # coverage + rm -f clixon_http1_parse.tab.[ch] clixon_http1_parse.[co] lex.clixon_http1_parse.c distclean: clean rm -f Makefile *~ .depend @@ -191,6 +197,19 @@ uninstall: .c.o: $(CC) $(INCLUDES) -D__PROGRAM__=\"clixon_restconf\" $(CPPFLAGS) $(CFLAGS) -c $< +# http1 parser +lex.clixon_http1_parse.c : clixon_http1_parse.l clixon_http1_parse.tab.h + $(LEX) -Pclixon_http1_parse clixon_http1_parse.l # -d is debug + +clixon_http1_parse.tab.h: clixon_http1_parse.y + $(YACC) -l -d -b clixon_http1_parse -p clixon_http1_parse clixon_http1_parse.y # -t is debug + +# extra rule to avoid parallell yaccs +clixon_http1_parse.tab.c: clixon_http1_parse.tab.h + +lex.clixon_http1_parse.o : lex.clixon_http1_parse.c clixon_http1_parse.tab.h + $(CC) $(INCLUDES) $(CPPFLAGS) $(CFLAGS) -Wno-error -c $< + ifeq ($(LINKAGE),dynamic) $(APPL): $(MYLIBDYNAMIC) else diff --git a/apps/restconf/README.md b/apps/restconf/README.md index aee444c1..dfe02905 100644 --- a/apps/restconf/README.md +++ b/apps/restconf/README.md @@ -6,19 +6,10 @@ * [Nchan Streams](#nchan) * [Debugging](#debugging) -There are two installation instructions: for libevhtp and nginx. +There are two installation instructions: for native and nginx. ## Native -Download, build and install libevhtp from source. Prereqs: libevent and ssl -``` - sudo git clone https://github.com/clicon/clixon-libevhtp.git - cd clixon-libevhtp - ./configure --libdir=/usr/lib - make - sudo make install -``` - Configure clixon with native restconf: ``` ./configure --with-restconf=native diff --git a/apps/restconf/clixon_http1.c b/apps/restconf/clixon_http1.c new file mode 100644 index 00000000..b8f22452 --- /dev/null +++ b/apps/restconf/clixon_http1.c @@ -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 +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_LIBNGHTTP2 +#include +#endif + +/* cligen */ +#include + +/* clixon */ +#include + +#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 will be: + * @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; +} diff --git a/apps/restconf/restconf_evhtp.h b/apps/restconf/clixon_http1.h similarity index 76% rename from apps/restconf/restconf_evhtp.h rename to apps/restconf/clixon_http1.h index c140d2fa..b91f3773 100644 --- a/apps/restconf/restconf_evhtp.h +++ b/apps/restconf/clixon_http1.h @@ -2,7 +2,6 @@ * ***** BEGIN LICENSE BLOCK ***** - Copyright (C) 2009-2019 Olof Hagsand Copyright (C) 2020-2022 Olof Hagsand and Rubicon Communications, LLC(Netgate) This file is part of CLIXON. @@ -31,17 +30,18 @@ the terms of any one of the Apache License version 2 or the GPL. ***** END LICENSE BLOCK ***** - * - * Virtual clixon restconf API functions. - */ -#ifndef _RESTCONF_EVHTP_H_ -#define _RESTCONF_EVHTP_H_ + * HTTP/1.1 parser according to RFC 7230 + */ +#ifndef _CLIXON_HTTP1_H_ +#define _CLIXON_HTTP1_H_ /* * Prototypes */ -void restconf_path_root(evhtp_request_t *req, void *arg); -void restconf_path_wellknown(evhtp_request_t *req, void *arg); +int clixon_http1_parse_file(clicon_handle h, restconf_conn *rc, FILE *f, const char *filename); +int clixon_http1_parse_string(clicon_handle h, restconf_conn *rc, char *str); +int clixon_http1_parse_buf(clicon_handle h, restconf_conn *rc, char *buf, size_t n); +int restconf_http1_path_root(clicon_handle h, restconf_conn *rc); -#endif /* _RESTCONF_EVHTP_H_ */ +#endif /* _CLIXON_HTTP1_H_ */ diff --git a/apps/restconf/clixon_http1_parse.h b/apps/restconf/clixon_http1_parse.h new file mode 100644 index 00000000..1578b236 --- /dev/null +++ b/apps/restconf/clixon_http1_parse.h @@ -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_ */ diff --git a/apps/restconf/clixon_http1_parse.l b/apps/restconf/clixon_http1_parse.l new file mode 100644 index 00000000..2ebd0099 --- /dev/null +++ b/apps/restconf/clixon_http1_parse.l @@ -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 +#include +#include +#include +#include + +#ifdef HAVE_LIBNGHTTP2 +#include +#endif + +#include "clixon_http1_parse.tab.h" /* generated */ + +#include +#include + +#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 + +%% +<> { return X_EOF; } +[ ] { BEGIN(REQTARG); return SP; } +{token} { clixon_http1_parselval.string = yytext; + return TOKEN; } +. { clixon_http1_parseerror(_HY, "LEXICAL ERROR\n"); return -1; } + +\? { BEGIN(REQUERY); return QMARK; } +\/ { return SLASH; } +[ ] { return SP; } +HTTP { BEGIN(REQHTTP); return HTTP; } +{pchar}+ { clixon_http1_parselval.string = yytext; + return PCHARS; } +. { clixon_http1_parseerror(_HY, "LEXICAL ERROR\n"); return -1; } + +\/ { return SLASH; } +[ ] { return SP; } +HTTP { BEGIN(REQHTTP); return HTTP; } +{query}+ { clixon_http1_parselval.string = yytext; + return QUERY; } +. { clixon_http1_parseerror(_HY, "LEXICAL ERROR\n"); return -1; } + +\r\n { BEGIN(FLDNAME); return CRLF; _HY->hy_linenum++; } +\/ { return SLASH; } +\. { return DOT; } +[0-9] { clixon_http1_parselval.intval = atoi(yytext); + return DIGIT; } +. { clixon_http1_parseerror(_HY, "LEXICAL ERROR\n"); return -1; } + +: { BEGIN(FLDVALUE); return COLON; } +\r\n { return CRLF; _HY->hy_linenum++; } +[ \t\n]+ { return RWS; } +{token} { clixon_http1_parselval.string = yytext; + return TOKEN; } +. { clixon_http1_parseerror(_HY, "LEXICAL ERROR\n"); return -1; } +\r\n { BEGIN(FLDNAME); return CRLF; _HY->hy_linenum++; } +[ \t\n]+ { return RWS; } +. { 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; +} + diff --git a/apps/restconf/clixon_http1_parse.y b/apps/restconf/clixon_http1_parse.y new file mode 100644 index 00000000..f722a841 --- /dev/null +++ b/apps/restconf/clixon_http1_parse.y @@ -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 PCHARS +%token QUERY +%token TOKEN +%token VCHAR +%token DIGIT + +%type absolute_paths +%type 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 +#include +#include +#include +#include + +#ifdef HAVE_LIBNGHTTP2 +#include +#endif + +#include +#include + +#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 = *( 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 = *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 + | +; + +%% + diff --git a/apps/restconf/restconf_api_native.c b/apps/restconf/restconf_api_native.c index ef15f52b..46fd7526 100644 --- a/apps/restconf/restconf_api_native.c +++ b/apps/restconf/restconf_api_native.c @@ -50,13 +50,6 @@ #include #include -#ifdef HAVE_LIBEVHTP -/* evhtp */ -#define EVHTP_DISABLE_REGEX -#define EVHTP_DISABLE_EVTHR -#include -#endif /* HAVE_LIBEVHTP */ - #ifdef HAVE_LIBNGHTTP2 #include #endif @@ -71,8 +64,8 @@ #include "restconf_api.h" /* Virtual api */ #include "restconf_native.h" -/*! Add HTTP header field name and value to reply, evhtp specific - * @param[in] req Evhtp http request handle +/*! Add HTTP header field name and value to reply + * @param[in] req request handle * @param[in] name HTTP header field name * @param[in] vfmt HTTP header field value format string w variable parameter * @see eg RFC 7230 diff --git a/apps/restconf/restconf_evhtp.c b/apps/restconf/restconf_evhtp.c deleted file mode 100644 index 31f99a5a..00000000 --- a/apps/restconf/restconf_evhtp.c +++ /dev/null @@ -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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -/* cligen */ -#include - -/* clicon */ -#include - -#ifdef HAVE_LIBEVHTP -#include /* evbuffer */ -#define EVHTP_DISABLE_REGEX -#define EVHTP_DISABLE_EVTHR - -#include - -#endif /* HAVE_LIBEVHTP */ - -#ifdef HAVE_LIBNGHTTP2 /* To get restconf_native.h include files right */ -#include -#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 ?=&= 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 */ - diff --git a/apps/restconf/restconf_handle.c b/apps/restconf/restconf_handle.c index 080589d3..eb94931e 100644 --- a/apps/restconf/restconf_handle.c +++ b/apps/restconf/restconf_handle.c @@ -44,7 +44,6 @@ #include #include #include -#include #include #include #include diff --git a/apps/restconf/restconf_main_native.c b/apps/restconf/restconf_main_native.c index e9a0f282..ca27bece 100644 --- a/apps/restconf/restconf_main_native.c +++ b/apps/restconf/restconf_main_native.c @@ -49,18 +49,6 @@ * +--------------------+ * Note restconf_request may need to be extended eg backpointer to rs? * - * +--------------------+ +--------------------+ - * | evhtp_connection | -----> | evhtp_t (core) | - * +--------------------+ +--------------------+ - * |request ^ - * v | conn - * +--------------------+ +--------------------+ - * | evhtp_request | --> uri | evhtp_uri | - * +--------------------+ +--------------------+ - * | (created by parser) | | | - * v v v v - * headers/buffers/method/... authority path query - * * Buffer handling: * c * | @@ -121,12 +109,6 @@ #include "clixon_config.h" /* generated by config & autoconf */ #endif -/* The clixon evhtp code can be compiled with or without threading support - * The choice is set at libevhtp compile time by cmake. Eg: - * cmake -DEVHTP_DISABLE_EVTHR=ON # Disable threads. - * Default in testing is disabled threads. - */ - #include #include #include @@ -151,16 +133,6 @@ /* clicon */ #include -#ifdef HAVE_LIBEVHTP -/* evhtp */ -#include /* evbuffer */ -#define EVHTP_DISABLE_REGEX -#define EVHTP_DISABLE_EVTHR - -#include - -#endif /* HAVE_LIBEVHTP */ - #ifdef HAVE_LIBNGHTTP2 /* nghttp2 */ #include @@ -173,12 +145,12 @@ #include "restconf_err.h" #include "restconf_root.h" #include "restconf_native.h" /* Restconf-openssl mode specific headers*/ -#ifdef HAVE_LIBEVHTP -#include "restconf_evhtp.h" /* http/1 */ -#endif #ifdef HAVE_LIBNGHTTP2 #include "restconf_nghttp2.h" /* http/2 */ #endif +#ifdef HAVE_HTTP1 +#include "clixon_http1.h" +#endif /* Command line options to be passed to getopt(3) */ #define RESTCONF_OPTS "hD:f:E:l:p:y:a:u:rW:R:o:" @@ -352,9 +324,7 @@ clixon_openssl_log_cb(void *handle, return 0; } -/* - * see restconf_config ->cv_evhtp_init(x2) -> cx_evhtp_socket -> - * evhtp_ssl_init:4757 +/*! Init openSSL */ static int init_openssl(void) @@ -425,7 +395,7 @@ restconf_verify_certs(int preverify_ok, * - 0 (preferity_ok) the session terminates here in SSL negotiation, an http client * will get a low level error (not http reply) * - 1 Check if the cert is valid using SSL_get_verify_result(rc->rc_ssl) - * @see restconf_evhtp_sanity and restconf_nghttp2_sanity where this is done for http/1 and http/2 + * @see restconf_nghttp2_sanity where this is done for http/1 and http/2 */ return 1; } @@ -479,7 +449,7 @@ alpn_select_proto_cb(SSL *ssl, inp++; if (clicon_debug_get()) /* debug print the protoocol */ alpn_proto_dump(__FUNCTION__, (const char*)inp, len); -#ifdef HAVE_LIBEVHTP +#ifdef HAVE_HTTP1 if (pref < 10 && len == 8 && strncmp((char*)inp, "http/1.1", len) == 0){ *outlen = len; *out = inp; @@ -503,8 +473,6 @@ alpn_select_proto_cb(SSL *ssl, } /* - * see restconf_config ->cv_evhtp_init(x2) -> cx_evhtp_socket -> - * evhtp_ssl_init:4794 */ static SSL_CTX * restconf_ssl_context_create(clicon_handle h) @@ -535,8 +503,6 @@ restconf_ssl_context_create(clicon_handle h) } /* - * see restconf_config ->cv_evhtp_init(x2) -> cx_evhtp_socket -> - * evhtp_ssl_init: 4886 * @param[in] ctx SSL context * @param[in] server_cert_path Server cert * @param[in] server_key_path Server private key @@ -595,7 +561,7 @@ restconf_ssl_context_configure(clixon_handle h, return retval; } -/*! Utility function to close restconf server ssl/evhtp socket. +/*! Utility function to close restconf server ssl socket. * There are many variants to closing, one could probably make this more generic * and always use this function, but it is difficult. */ @@ -618,10 +584,6 @@ Note that in this case SSL_ERROR_ZERO_RETURN does not necessarily indicate that } SSL_free(rc->rc_ssl); rc->rc_ssl = NULL; -#ifdef HAVE_LIBEVHTP - if (rc->rc_evconn) - rc->rc_evconn->ssl = NULL; -#endif } if (close(rc->rc_s) < 0){ clicon_err(OE_UNIX, errno, "close"); @@ -675,7 +637,67 @@ send_badrequest(clicon_handle h, return retval; } -/*! New data connection after accept, receive and reply on data sockte +#if 0 +#define IFILE "/var/tmp/clixon-mirror/ifile" +#define FMTDIR "/var/tmp/clixon-mirror/" + +static FILE *myf = NULL; + +static int +mirror_pkt(const char *buf, + ssize_t n) +{ + int retval = -1; + + if (fwrite(buf, 1, n, myf) != n){ + perror("fopen"); + goto done; + } + retval = 0; + done: + return retval; +} + +static int +mirror_new(void) +{ + int retval = -1; + static uint64_t u64 = 0; + cbuf *cb = cbuf_new(); + FILE *ifile; + + if ((ifile = fopen(IFILE, "r+")) == NULL){ + perror("fopen r+ ifile"); + } + else { + if (fscanf(ifile, "%" PRIu64, &u64) < 0){ + perror("fscanf ifile"); + goto done; + } + fclose(ifile); + } + if (myf != NULL) + fclose(myf); + cprintf(cb, FMTDIR "%" PRIu64 ".dump", u64); + if ((myf = fopen(cbuf_get(cb), "w")) == NULL){ + perror("fopen"); + goto done; + } + cbuf_free(cb); + u64++; + if ((ifile = fopen(IFILE, "w")) == NULL){ + perror("fopen w+ ifile"); + goto done; + } + fprintf(ifile, "%" PRIu64, u64); + fclose(ifile); + retval = 0; + done: + return retval; +} +#endif + +/*! New data connection after accept, receive and reply on data socket * * @param[in] s Socket where message arrived. read from this. * @param[in] arg Client entry (from). @@ -683,10 +705,10 @@ send_badrequest(clicon_handle h, * @retval -1 Error Terminates backend and is never called). Instead errors are * propagated back to client. * @see restconf_accept_client where this callback is registered - * @note read buffer is limited. More data can be read in two ways: either evhtp returns a buffer + * @note read buffer is limited. More data can be read in two ways: returns a buffer * with 100 Continue, in which case that is replied and the function returns and the client sends * more data. - * OR evhtp returns 0 with no reply, then this is assumed to mean read more data from the socket. + * OR returns 0 with no reply, then this is assumed to mean read more data from the socket. */ static int restconf_connection(int s, @@ -701,9 +723,8 @@ restconf_connection(int s, #ifdef HAVE_LIBNGHTTP2 int ret; #endif -#ifdef HAVE_LIBEVHTP +#ifdef HAVE_HTTP1 clicon_handle h; - evhtp_connection_t *evconn = NULL; restconf_stream_data *sd; #endif @@ -765,7 +786,7 @@ restconf_connection(int s, continue; } } - clicon_debug(1, "%s (ssl)read:%zd", __FUNCTION__, n); + clicon_debug(1, "%s read:%zd", __FUNCTION__, n); if (n == 0){ clicon_debug(1, "%s n=0 closing socket", __FUNCTION__); if (restconf_close_ssl_socket(rc, 0) < 0) @@ -774,99 +795,43 @@ restconf_connection(int s, rc = NULL; goto ok; } +#if 0 + if (mirror_pkt(buf, n) < 0) + goto done; +#endif switch (rc->rc_proto){ -#ifdef HAVE_LIBEVHTP +#ifdef HAVE_HTTP1 case HTTP_10: case HTTP_11: h = rc->rc_h; - /* parse incoming packet using evhtp - * signature: - */ - evconn = rc->rc_evconn; - /* This is the main call to EVHTP parser */ - if (connection_parse_nobev(buf, n, evconn) < 0){ - clicon_debug(1, "%s connection_parse error", __FUNCTION__); - /* XXX To get more nuanced evhtp error check - * htparser_get_error(conn->parser) - */ + if (clixon_http1_parse_buf(h, rc, buf, n) < 0){ if (send_badrequest(h, rc->rc_s, rc->rc_ssl, "application/yang-data+xml", "protocolmalformed-messageThe requested URL or a header is in some way badly formed") < 0) goto done; - SSL_free(rc->rc_ssl); - rc->rc_ssl = NULL; - evconn->ssl = NULL; - if (close(rc->rc_s) < 0){ - clicon_err(OE_UNIX, errno, "close"); + } + else{ + if (restconf_http1_path_root(h, rc) < 0) goto done; - } - clixon_event_unreg_fd(rc->rc_s, restconf_connection); - clicon_debug(1, "%s evconn-free (%p) 2", __FUNCTION__, evconn); - restconf_conn_free(rc); - goto ok; - } /* connection_parse_nobev */ + } clicon_debug(1, "%s connection_parse OK", __FUNCTION__); /* default stream */ if ((sd = restconf_stream_find(rc, 0)) == NULL){ clicon_err(OE_RESTCONF, EINVAL, "restconf stream not found"); goto done; } - if (evconn->bev != NULL){ - struct evbuffer *ev; - size_t buflen0; - size_t buflen1; - char *buf = NULL; - - if ((ev = bufferevent_get_output(evconn->bev)) != NULL){ - buflen0 = evbuffer_get_length(ev); - buflen1 = buflen0 - rc->rc_bufferevent_output_offset; - if (buflen1 > 0){ - buf = (char*)evbuffer_pullup(ev, -1); - /* XXX Here if -1 in api_root - * HTTP/1.1 0 UNKNOWN\r\nContent-Length: 0 - * And output_buffer is NULL - */ - /* If evhtp has print an output buffer, clixon whould not have done it - * Shouldnt happen - */ - if (cbuf_len(sd->sd_outp_buf)){ - clicon_debug(1, "%s Warning: evhtp printed output buffer, but clixon output buffer is non-empty %s", - __FUNCTION__, cbuf_get(sd->sd_outp_buf)); - cbuf_reset(sd->sd_outp_buf); - } - if (cbuf_append_buf(sd->sd_outp_buf, buf, buflen1) < 0){ - clicon_err(OE_UNIX, errno, "cbuf_append_buf"); - goto done; - } - /* XXX Cant get drain to work, need to keep an offset */ - evbuffer_drain(ev, -1); - rc->rc_bufferevent_output_offset += buflen1; - } - } - if (cbuf_len(sd->sd_outp_buf) == 0) - readmore = 1; - else { - if (buf_write(cbuf_get(sd->sd_outp_buf), cbuf_len(sd->sd_outp_buf), - rc->rc_s, rc->rc_ssl) < 0) - goto done; - cvec_reset(sd->sd_outp_hdrs); /* Can be done in native_send_reply */ - cbuf_reset(sd->sd_outp_buf); - } - } - else{ - if (send_badrequest(h, rc->rc_s, rc->rc_ssl, "application/yang-data+xml", - "protocolmalformed-messageNo evhtp output") < 0) - goto done; - } + if (buf_write(cbuf_get(sd->sd_outp_buf), cbuf_len(sd->sd_outp_buf), + rc->rc_s, rc->rc_ssl) < 0) + goto done; + cvec_reset(sd->sd_outp_hdrs); /* Can be done in native_send_reply */ + cbuf_reset(sd->sd_outp_buf); if (rc->rc_exit){ /* Server-initiated exit for http/2 */ SSL_free(rc->rc_ssl); rc->rc_ssl = NULL; - evconn->ssl = NULL; if (close(rc->rc_s) < 0){ clicon_err(OE_UNIX, errno, "close"); goto done; } clixon_event_unreg_fd(rc->rc_s, restconf_connection); - clicon_debug(1, "%s evconn-free (%p) 2", __FUNCTION__, evconn); restconf_conn_free(rc); goto ok; } @@ -916,7 +881,7 @@ restconf_connection(int s, } #endif break; -#endif /* HAVE_LIBEVHTP */ +#endif /* HAVE_HTTP1 */ #ifdef HAVE_LIBNGHTTP2 case HTTP_2: if (rc->rc_exit){ /* Server-initiated exit for http/2 */ @@ -1119,10 +1084,9 @@ restconf_accept_client(int fd, clicon_debug(1, "%s %d", __FUNCTION__, fd); #ifdef HAVE_LIBNGHTTP2 -#ifndef HAVE_LIBEVHTP +#ifndef HAVE_HTTP1 proto = HTTP_2; /* If nghttp2 only let default be 2.0 */ #endif - /* If also evhtp, keep HTTP_11 */ #endif if ((rsock = (restconf_socket *)arg) == NULL){ clicon_err(OE_YANG, EINVAL, "rsock is NULL"); @@ -1313,28 +1277,14 @@ restconf_accept_client(int fd, } /* if ssl */ rc->rc_proto = proto; switch (rc->rc_proto){ -#ifdef HAVE_LIBEVHTP +#ifdef HAVE_HTTP1 case HTTP_10: - case HTTP_11:{ - evhtp_t *evhtp = (evhtp_t *)rh->rh_arg; - evhtp_connection_t *evconn; - - /* Create evhtp-specific struct */ - if ((evconn = evhtp_connection_new_server(evhtp, rc->rc_s)) == NULL){ - clicon_err(OE_UNIX, errno, "evhtp_connection_new_server"); - goto done; - } - /* Mutual pointers, from generic rc to evhtp specific and from evhtp conn to generic - */ - rc->rc_evconn = evconn; /* Generic to specific */ - evconn->arg = rc; /* Specific to generic */ - evconn->ssl = rc->rc_ssl; /* evhtp */ + case HTTP_11: /* Create a default stream for http/1 */ if (restconf_stream_data_new(rc, 0) == NULL) goto done; - } break; -#endif /* HAVE_LIBEVHTP */ +#endif /* HAVE_HTTP1 */ #ifdef HAVE_LIBNGHTTP2 case HTTP_2:{ if (http2_session_init(rc) < 0){ @@ -1365,6 +1315,10 @@ restconf_accept_client(int fd, default: break; } /* switch proto */ +#if 0 + if (mirror_new() < 0) + goto done; +#endif if (clixon_event_reg_fd(rc->rc_s, restconf_connection, (void*)rc, "restconf client socket") < 0) goto done; ok: @@ -1376,6 +1330,8 @@ restconf_accept_client(int fd, return retval; } /* restconf_accept_client */ +/*! + */ static int restconf_native_terminate(clicon_handle h) { @@ -1396,18 +1352,6 @@ restconf_native_terminate(clicon_handle h) } if (rh->rh_ctx) SSL_CTX_free(rh->rh_ctx); -#ifdef HAVE_LIBEVHTP - { - evhtp_t *evhtp = (evhtp_t *)rh->rh_arg; - if (evhtp){ - if (evhtp->evbase) - event_base_free(evhtp->evbase); - evhtp_free(evhtp); - rh->rh_arg = NULL; - } - } -#endif /* HAVE_LIBEVHTP */ - free(rh); } EVP_cleanup(); @@ -1581,10 +1525,6 @@ restconf_openssl_init(clicon_handle h, cxobj **vec = NULL; size_t veclen; int i; -#ifdef HAVE_LIBEVHTP - evhtp_t *evhtp = NULL; - struct event_base *evbase = NULL; -#endif /* HAVE_LIBEVHTP */ clicon_debug(1, "%s", __FUNCTION__); /* flag used for sanity of certs */ @@ -1639,28 +1579,6 @@ restconf_openssl_init(clicon_handle h, } rh = restconf_native_handle_get(h); rh->rh_ctx = ctx; -#ifdef HAVE_LIBEVHTP - /* evhtp stuff */ /* XXX move this to global level */ - if ((evbase = event_base_new()) == NULL){ - clicon_err(OE_UNIX, errno, "event_base_new"); - goto done; - } - /* This is socket create a new evhtp_t instance */ - if ((evhtp = evhtp_new((void*)evbase, h)) == NULL){ - clicon_err(OE_UNIX, errno, "evhtp_new"); - goto done; - } - rh->rh_arg = evhtp; - if (evhtp_set_cb(evhtp, "/" RESTCONF_API, restconf_path_root, h) == NULL){ - clicon_err(OE_EVENTS, errno, "evhtp_set_cb"); - goto done; - } - /* Callback to be executed for all /restconf api calls */ - if (evhtp_set_cb(evhtp, RESTCONF_WELL_KNOWN, restconf_path_wellknown, h) == NULL){ - clicon_err(OE_EVENTS, errno, "evhtp_set_cb"); - goto done; - } -#endif /* HAVE_LIBEVHTP */ /* get the list of socket config-data */ if (xpath_vec(xrestconf, nsc, "socket", &vec, &veclen) < 0) goto done; diff --git a/apps/restconf/restconf_native.c b/apps/restconf/restconf_native.c index a42ebac9..f7a5ee3b 100644 --- a/apps/restconf/restconf_native.c +++ b/apps/restconf/restconf_native.c @@ -66,14 +66,7 @@ #include "restconf_lib.h" /* generic shared with plugins */ #include "restconf_handle.h" #include "restconf_err.h" -#ifdef HAVE_LIBEVHTP -#include /* evbuffer */ -#define EVHTP_DISABLE_REGEX -#define EVHTP_DISABLE_EVTHR -#include - -#endif #ifdef HAVE_LIBNGHTTP2 #include #endif @@ -167,7 +160,7 @@ restconf_conn_new(clicon_handle h, return rc; } -/*! Free clixon/cbuf resources related to an evhtp connection +/*! Free clixon/cbuf resources related to a connection * @param[in] rc restconf connection */ int @@ -182,10 +175,6 @@ restconf_conn_free(restconf_conn *rc) #ifdef HAVE_LIBNGHTTP2 if (rc->rc_ngsession) nghttp2_session_del(rc->rc_ngsession); -#endif -#ifdef HAVE_LIBEVHTP - if (rc->rc_evconn) - evhtp_connection_free(rc->rc_evconn); /* evhtp */ #endif /* Free all streams */ while ((sd = rc->rc_streams) != NULL) { diff --git a/apps/restconf/restconf_native.h b/apps/restconf/restconf_native.h index 0d16c54b..482bf2fa 100644 --- a/apps/restconf/restconf_native.h +++ b/apps/restconf/restconf_native.h @@ -79,7 +79,7 @@ typedef struct { struct restconf_conn *sd_conn; /* Backpointer to connection this stream is part of */ restconf_http_proto sd_proto; /* http protocol XXX not sure this is needed */ cvec *sd_qvec; /* Query parameters, ie ?a=b&c=d */ - void *sd_req; /* Lib-specific request, eg evhtp_request_t * */ + void *sd_req; /* Lib-specific request */ int sd_upgrade2; /* Upgrade to http/2 */ uint8_t *sd_settings2; /* Settings for upgrade to http/2 request */ } restconf_stream_data; @@ -98,9 +98,6 @@ typedef struct restconf_conn { int rc_exit; /* Set to close socket server-side (NYI) */ /* Decision to keep lib-specific data here, otherwise new struct necessary * drawback is specific includes need to go everywhere */ -#ifdef HAVE_LIBEVHTP - evhtp_connection_t *rc_evconn; -#endif #ifdef HAVE_LIBNGHTTP2 nghttp2_session *rc_ngsession; /* XXX Not sure it is needed */ #endif @@ -125,7 +122,7 @@ typedef struct { typedef struct { SSL_CTX *rh_ctx; /* SSL context */ restconf_socket *rh_sockets; /* List of restconf server (ready for accept) sockets */ - void *rh_arg; /* Packet specific handle (eg evhtp) */ + void *rh_arg; /* Packet specific handle */ } restconf_native_handle; /* diff --git a/apps/restconf/restconf_nghttp2.c b/apps/restconf/restconf_nghttp2.c index 805bae05..5d275ed9 100644 --- a/apps/restconf/restconf_nghttp2.c +++ b/apps/restconf/restconf_nghttp2.c @@ -50,12 +50,6 @@ #include "clixon_config.h" /* generated by config & autoconf */ #endif -/* The clixon evhtp code can be compiled with or without threading support - * The choice is set at libevhtp compile time by cmake. Eg: - * cmake -DEVHTP_DISABLE_EVTHR=ON # Disable threads. - * Default in testing is disabled threads. - */ - #include #include #include @@ -80,14 +74,6 @@ /* clicon */ #include -#ifdef HAVE_LIBEVHTP /* To get restconf_native.h include files right */ -/* evhtp */ -#include /* evbuffer */ -#define EVHTP_DISABLE_REGEX -#define EVHTP_DISABLE_EVTHR -#include -#endif /* HAVE_LIBEVHTP */ - #ifdef HAVE_LIBNGHTTP2 #include #endif @@ -279,12 +265,11 @@ recv_callback(nghttp2_session *session, /*! Callback for each incoming http request for path / * - * This are all messages except /.well-known, Registered with evhtp_set_cb + * This are all messages except /.well-known, * - * @param[in] req evhtp http request structure defining the incoming message - * @param[in] arg cx_evhtp handle clixon specific fields + * @param[in] sd session stream struct (http/1 has a single) * @retval void - * Discussion: problematic if fatal error -1 is returneod from clixon routines + * Discussion: problematic if fatal error -1 is returned from clixon routines * without actually terminating. Consider: * 1) sending some error? and/or * 2) terminating the process? @@ -338,10 +323,6 @@ restconf_nghttp2_path(restconf_stream_data *sd) retval = 0; done: clicon_debug(1, "%s %d", __FUNCTION__, retval); - /* Catch all on fatal error. This does not terminate the process but closes request stream */ - // if (retval < 0){ - // evhtp_send_reply(req, EVHTP_RES_ERROR); - // } if (cvv) cvec_free(cvv); if (oneline) diff --git a/configure b/configure index 18a78310..ac5a1067 100755 --- a/configure +++ b/configure @@ -636,8 +636,8 @@ YANG_STANDARD_DIR YANG_INSTALLDIR CLIXON_YANG_PATCH with_libxml2 +HAVE_HTTP1 HAVE_LIBNGHTTP2 -HAVE_LIBEVHTP with_restconf LINKAGE LIBSTATIC_SUFFIX @@ -720,7 +720,7 @@ with_cligen enable_yang_patch enable_publish with_restconf -enable_evhtp +enable_http1 enable_nghttp2 with_configfile with_libxml2 @@ -1370,7 +1370,7 @@ Optional Features: --enable-yang-patch Enable YANG patch, RFC 8072, default: no --enable-publish Enable publish of notification streams using SSE and 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 --disable-nghttp2 Disable nghttp2 for native restconf http/2, ie http/1 only @@ -3385,10 +3385,10 @@ test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' # Set to native or fcgi -> compile apps/restconf -HAVE_LIBEVHTP=false - # consider using neutral constant such as with-http1 HAVE_LIBNGHTTP2=false # consider using neutral constant such as with-http2 +HAVE_HTTP1=false + # Where Clixon installs its YANG specs @@ -5070,7 +5070,6 @@ fi $as_echo "#define WITH_RESTCONF_FCGI 1" >>confdefs.h # For c-code that cant use strings elif test "x${with_restconf}" == xnative; then - { $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; } if ${ac_cv_lib_ssl_OPENSSL_init_ssl_+:} false; then : @@ -5165,136 +5164,26 @@ else as_fn_error $? "libcrypto missing" "$LINENO" 5 fi - # Check if evhtp is enabled for http/1 - # Check whether --enable-evhtp was given. -if test "${enable_evhtp+set}" = set; then : - enableval=$enable_evhtp; + # Check if http/1 enabled + # Check whether --enable-http1 was given. +if test "${enable_http1+set}" = set; then : + enableval=$enable_http1; if test "$enableval" = no; then - ac_enable_evhtp=no + ac_enable_http1=no else - ac_enable_evhtp=yes + ac_enable_http1=yes fi else - ac_enable_evhtp=yes + ac_enable_http1=yes 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 -" -if test "x$ac_cv_header_evhtp_evhtp_h" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_EVHTP_EVHTP_H 1 -_ACEOF - -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 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: checking http1 is enabled: $ac_enable_http1" >&5 +$as_echo "checking http1 is enabled: $ac_enable_http1" >&6; } + if test "$ac_enable_http1" = "yes"; then + $as_echo "#define HAVE_HTTP1 true" >>confdefs.h + # Must be tree/false (not 0/1) used in shells fi # Check if nghttp2 is enabled for http/2 diff --git a/configure.ac b/configure.ac index 3ef1c091..8d0dbae2 100644 --- a/configure.ac +++ b/configure.ac @@ -114,8 +114,8 @@ AC_SUBST(SH_SUFFIX) AC_SUBST(LIBSTATIC_SUFFIX) AC_SUBST(LINKAGE) 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_HTTP1,false) AC_SUBST(with_libxml2) AC_SUBST(CLIXON_YANG_PATCH) # Where Clixon installs its YANG specs @@ -223,31 +223,22 @@ if test "x${with_restconf}" == xfcgi; then 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 elif test "x${with_restconf}" == xnative; then - 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])) - # Check if evhtp is enabled for http/1 - AC_ARG_ENABLE(evhtp, AS_HELP_STRING([--disable-evhtp],[Disable evhtp for native restconf http/1, ie http/2 only]),[ + # Check if http/1 enabled + 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 - ac_enable_evhtp=no + ac_enable_http1=no else - ac_enable_evhtp=yes + ac_enable_http1=yes fi ], - [ ac_enable_evhtp=yes]) - AC_MSG_RESULT(checking evhtp is enabled: $ac_enable_evhtp) - if test "$ac_enable_evhtp" = "yes"; then - AC_CHECK_HEADERS(evhtp/evhtp.h, - [], - 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 + [ ac_enable_http1=yes]) + + AC_MSG_RESULT(checking http1 is enabled: $ac_enable_http1) + if test "$ac_enable_http1" = "yes"; then + AC_DEFINE(HAVE_HTTP1,true) # Must be tree/false (not 0/1) used in shells + fi # Check if nghttp2 is enabled for http/2 AC_ARG_ENABLE(nghttp2, AS_HELP_STRING([--disable-nghttp2],[Disable nghttp2 for native restconf http/2, ie http/1 only]),[ diff --git a/doc/DEVELOP.md b/doc/DEVELOP.md index d66aac54..7cf7c6c2 100644 --- a/doc/DEVELOP.md +++ b/doc/DEVELOP.md @@ -242,6 +242,16 @@ To turn callgrind off/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 What to think about when doing a new release. * Ensure all tests run OK @@ -257,6 +267,7 @@ What to think about when doing a new release. git tag -a git push origin ``` +* Add a github "release" and copy release info from CHANGELOG After release: * Bump minor version and add a "PRE": diff --git a/docker/base/Dockerfile b/docker/base/Dockerfile index 9c23a6d0..f5692d2e 100644 --- a/docker/base/Dockerfile +++ b/docker/base/Dockerfile @@ -38,26 +38,12 @@ MAINTAINER Olof Hagsand # For clixon and cligen RUN apk add --update git make build-base gcc flex bison curl-dev -# evhtp dependencies -RUN apk add --update libevent libevent-dev - # nghttp2 dependencies RUN apk add --update nghttp2 # Create a directory to hold source-code, dependencies etc 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 WORKDIR /clixon @@ -79,7 +65,7 @@ WORKDIR /clixon/clixon COPY 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 install @@ -109,4 +95,3 @@ EXPOSE 443/tcp RUN adduser -D -H clicon COPY --from=0 /clixon/build/ /usr/local/ -COPY --from=0 /usr/local/lib/libevhtp.so* /usr/local/lib/ diff --git a/docker/clixon-dev/Dockerfile b/docker/clixon-dev/Dockerfile index 821c64d0..26748594 100644 --- a/docker/clixon-dev/Dockerfile +++ b/docker/clixon-dev/Dockerfile @@ -38,26 +38,12 @@ MAINTAINER Olof Hagsand # For clixon and cligen RUN apk add --update git make build-base gcc flex bison curl-dev -# evhtp dependencies -RUN apk add --update libevent libevent-dev - # nghttp2 dependencies RUN apk add --update nghttp2 # Create a directory to hold source-code, dependencies etc 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 WORKDIR /clixon @@ -79,7 +65,7 @@ WORKDIR /clixon/clixon COPY 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 install diff --git a/docker/main/Dockerfile.native b/docker/main/Dockerfile.native index 3e031283..6300da3c 100644 --- a/docker/main/Dockerfile.native +++ b/docker/main/Dockerfile.native @@ -38,9 +38,6 @@ MAINTAINER Olof Hagsand # For clixon and cligen RUN apk add --update git make build-base gcc flex bison curl-dev -# evhtp dependencies -RUN apk add --update libevent libevent-dev - # nghttp2 dependencies 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 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 WORKDIR /clixon @@ -94,7 +80,7 @@ WORKDIR /clixon/clixon COPY 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 install @@ -148,7 +134,6 @@ EXPOSE 443/tcp RUN adduser -D -H clicon 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/experimental/ COPY --from=0 /usr/local/share/openconfig/* /usr/local/share/openconfig/ diff --git a/docker/main/startsystem_native.sh b/docker/main/startsystem_native.sh index 9d0cf5bc..255cc3b8 100755 --- a/docker/main/startsystem_native.sh +++ b/docker/main/startsystem_native.sh @@ -31,7 +31,7 @@ # # ***** 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 # _inside_ the container at start in runtime. It gets environment variables # from the start.sh script. diff --git a/include/clixon_config.h.in b/include/clixon_config.h.in index 28e6f78e..bcbd87fb 100644 --- a/include/clixon_config.h.in +++ b/include/clixon_config.h.in @@ -27,9 +27,6 @@ /* Define to 1 if you have the header file. */ #undef HAVE_CLIGEN_CLIGEN_H -/* Define to 1 if you have the header file. */ -#undef HAVE_EVHTP_EVHTP_H - /* Define to 1 if you have the `getpeereid' function. */ #undef HAVE_GETPEEREID @@ -54,12 +51,6 @@ /* Define to 1 if you have the `dl' library (-ldl). */ #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). */ #undef HAVE_LIBFCGI @@ -69,6 +60,8 @@ /* Define to 1 if you have the `nghttp2' library (-lnghttp2). */ #undef HAVE_LIBNGHTTP2 +#undef HAVE_HTTP1 + /* Define to 1 if you have the `socket' library (-lsocket). */ #undef HAVE_LIBSOCKET diff --git a/lib/clixon/clixon_string.h b/lib/clixon/clixon_string.h index 902d521f..2bf4c6f7 100644 --- a/lib/clixon/clixon_string.h +++ b/lib/clixon/clixon_string.h @@ -89,6 +89,7 @@ static inline char * strdup4(char *str) */ char **clicon_strsep(char *string, char *delim, int *nvec0); 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 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))); @@ -102,7 +103,8 @@ int clicon_str2int_search(const map_str2int *mstab, char *str, int upper); int nodeid_split(char *nodeid, char **prefix, char **id); char *clixon_trim(char *str); char *clixon_trim2(char *str, char *trims); -int clicon_strcmp(char *s1, char *s2); +int clicon_strcmp(char *s1, char *s2); + #ifndef HAVE_STRNDUP char *clicon_strndup (const char *, size_t); diff --git a/lib/src/clixon_api_path_parse.l b/lib/src/clixon_api_path_parse.l index 304af125..b3eebab5 100644 --- a/lib/src/clixon_api_path_parse.l +++ b/lib/src/clixon_api_path_parse.l @@ -82,8 +82,6 @@ /* typecast macro */ #define _AY ((clixon_api_path_yacc *)_ay) -#define MAXBUF 4*4*64*1024 - #undef clixon_api_path_parsewrap int clixon_api_path_parsewrap(void) diff --git a/lib/src/clixon_file.c b/lib/src/clixon_file.c index 75523835..2a0b7199 100644 --- a/lib/src/clixon_file.c +++ b/lib/src/clixon_file.c @@ -172,6 +172,11 @@ clicon_files_recursive(const char *dir, * do something with dp[i].d_name; * free(dp); * @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 clicon_file_dirent(const char *dir, @@ -180,7 +185,7 @@ clicon_file_dirent(const char *dir, mode_t type) { int retval = -1; - DIR *dirp; + DIR *dirp = NULL; int res; int nent; regex_t re; @@ -188,11 +193,8 @@ clicon_file_dirent(const char *dir, char filename[MAXPATHLEN]; struct stat st; struct dirent *dent; - struct dirent *tmp; struct dirent *new = NULL; -#if 0 /* revert of https://github.com/clicon/clixon/pull/238 */ int direntStructSize; -#endif *ent = NULL; nent = 0; @@ -225,25 +227,18 @@ clicon_file_dirent(const char *dir, if ((type & st.st_mode) == 0) continue; } -#if 0 /* revert of https://github.com/clicon/clixon/pull/238 */ 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 ((tmp = realloc(new, (nent+1)*direntStructSize)) == NULL) { -#else - if ((tmp = realloc(new, (nent+1)*sizeof(struct dirent))) == NULL) { -#endif + if ((new = realloc(new, (nent+1)*sizeof(struct dirent))) == NULL) { clicon_err(OE_UNIX, errno, "realloc"); goto quit; - } - new = tmp; -#if 0 /* revert of https://github.com/clicon/clixon/pull/238 */ + } /* realloc */ clicon_debug(1, "%s memcpy(%p %p %u", __FUNCTION__, &new[nent], dent, direntStructSize); - memcpy(&new[nent], dent, direntStructSize); /* XXX Invalid write of size 8 */ -#else - memcpy(&new[nent], dent, sizeof(*dent)); -#endif + /* man (3) readdir: + * By implication, the use sizeof(struct dirent) to capture the size of the record including + * the size of d_name is also incorrect. */ + memset(&new[nent], 0, sizeof(struct dirent)); + memcpy(&new[nent], dent, direntStructSize); nent++; - } /* while */ qsort((void *)new, nent, sizeof(*new), clicon_file_dirent_sort); diff --git a/lib/src/clixon_instance_id_parse.l b/lib/src/clixon_instance_id_parse.l index e7934a42..2eb004a6 100644 --- a/lib/src/clixon_instance_id_parse.l +++ b/lib/src/clixon_instance_id_parse.l @@ -79,8 +79,6 @@ /* typecast macro */ #define _IY ((clixon_instance_id_yacc *)_iy) -#define MAXBUF 4*4*64*1024 - #undef clixon_instance_id_parsewrap int clixon_instance_id_parsewrap(void) diff --git a/lib/src/clixon_json_parse.l b/lib/src/clixon_json_parse.l index 0bc5b250..1be3d38f 100644 --- a/lib/src/clixon_json_parse.l +++ b/lib/src/clixon_json_parse.l @@ -65,8 +65,6 @@ /* typecast macro */ #define _JY ((clixon_json_yacc *)_yy) -#define MAXBUF 4*4*64*1024 - #undef clixon_json_parsewrap int clixon_json_parsewrap(void) diff --git a/lib/src/clixon_string.c b/lib/src/clixon_string.c index 0163203c..bfcb2eeb 100644 --- a/lib/src/clixon_string.c +++ b/lib/src/clixon_string.c @@ -149,6 +149,39 @@ clicon_strjoin(int argc, 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 * @param[in] string * @param[in] delim @@ -564,7 +597,7 @@ xml_chardata_cbuf_append(cbuf *cb, * @retval -1 error * @code * cvec *cvv = NULL; - * if (uri_str2cvec("a=b&c=d", ';', '=', 1, &cvv) < 0) + * if (uri_str2cvec("a=b&c=d", '&', '=', 1, &cvv) < 0) * err; * @endcode * @@ -840,6 +873,7 @@ clicon_strcmp(char *s1, return strcmp(s1, s2); } + /*! strndup() for systems without it, such as xBSD */ #ifndef HAVE_STRNDUP @@ -908,4 +942,3 @@ main(int argc, char **argv) } #endif /* Test program */ - diff --git a/lib/src/clixon_xml_io.c b/lib/src/clixon_xml_io.c index 0a3da700..70934b02 100644 --- a/lib/src/clixon_xml_io.c +++ b/lib/src/clixon_xml_io.c @@ -640,8 +640,8 @@ clixon_xml_parse_file(FILE *fp, int oldxmlbuflen; int failed = 0; - if (xt==NULL){ - clicon_err(OE_XML, EINVAL, "xt is NULL"); + if (xt==NULL || fp == NULL){ + clicon_err(OE_XML, EINVAL, "arg is NULL"); return -1; } if (yb == YB_MODULE && yspec == NULL){ diff --git a/lib/src/clixon_xpath_parse.l b/lib/src/clixon_xpath_parse.l index 008ea220..b0332d22 100644 --- a/lib/src/clixon_xpath_parse.l +++ b/lib/src/clixon_xpath_parse.l @@ -69,8 +69,6 @@ /* typecast macro */ #define _XPY ((clixon_xpath_yacc *)_yy) -#define MAXBUF 4*4*64*1024 - #undef clixon_xpath_parsewrap int clixon_xpath_parsewrap(void) diff --git a/lib/src/clixon_yang_parse.l b/lib/src/clixon_yang_parse.l index 60dfd9db..6ce16cf5 100644 --- a/lib/src/clixon_yang_parse.l +++ b/lib/src/clixon_yang_parse.l @@ -35,7 +35,7 @@ * @see https://tools.ietf.org/html/rfc6020 YANG 1.0 * @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 - * does (where x is not n|t|"|\). See mode DQESC + * does (where x is not n|t|(y)?(x):(y)) -#define MIN(x,y) ((x)<(y)?(x):(y)) - #undef clixon_yang_parsewrap int clixon_yang_parsewrap(void) diff --git a/lib/src/clixon_yang_parse.y b/lib/src/clixon_yang_parse.y index fe6b4607..cd0dc1e7 100644 --- a/lib/src/clixon_yang_parse.y +++ b/lib/src/clixon_yang_parse.y @@ -78,7 +78,6 @@ %type identifier_ref_str %type bool_str - /* rfc 6020 keywords 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: @@ -154,7 +153,6 @@ %token K_YANG_VERSION %token K_YIN_ELEMENT - /* Deviate keywords */ %token D_NOT_SUPPORTED @@ -192,6 +190,7 @@ #include #include "clixon_queue.h" +#include "clixon_string.h" #include "clixon_hash.h" #include "clixon_handle.h" #include "clixon_err.h" @@ -351,37 +350,6 @@ ysp_add_push(clixon_yang_yacc *yy, 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 ';' - { 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"); _PARSE_DEBUG("unknown-stmt -> ustring : ustring ;"); } | 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"); } _PARSE_DEBUG("unknown-stmt -> ustring : ustring sep string ;"); } | 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"); } '{' yang_stmts '}' { if (ystack_pop(_yy) < 0) _YYERROR("unknown_stmt"); _PARSE_DEBUG("unknown-stmt -> ustring : ustring { yang-stmts }"); } | 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"); } '{' yang_stmts '}' { if (ystack_pop(_yy) < 0) _YYERROR("unknown_stmt"); @@ -1850,10 +1818,10 @@ ustring : ustring CHARS ; 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"); } | '/' 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"); } ; @@ -1887,7 +1855,7 @@ desc_schema_nodeid : node_identifier { $$= $1; _PARSE_DEBUG("descendant-schema-nodeid -> node_identifier"); } | 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"); } ; @@ -1926,7 +1894,7 @@ node_identifier : IDENTIFIER { $$=$1; _PARSE_DEBUG("identifier-ref-arg-str -> string"); } | 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"); } ; diff --git a/test/README.md b/test/README.md index bfd433ab..f8de2d95 100644 --- a/test/README.md +++ b/test/README.md @@ -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. -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. diff --git a/test/cicd/Makefile.in b/test/cicd/Makefile.in index 25335901..f70a8a67 100644 --- a/test/cicd/Makefile.in +++ b/test/cicd/Makefile.in @@ -46,7 +46,7 @@ SHELL = /bin/sh # eg : # 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 HOSTS= -include site.mk diff --git a/test/cicd/cicd.sh b/test/cicd/cicd.sh index 649151dc..5b9095ad 100755 --- a/test/cicd/cicd.sh +++ b/test/cicd/cicd.sh @@ -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;./configure)" 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 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)" diff --git a/test/config.sh.in b/test/config.sh.in index 9ec69bd3..82ec7276 100755 --- a/test/config.sh.in +++ b/test/config.sh.in @@ -1,7 +1,7 @@ #!/usr/bin/env bash # ***** 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 # @@ -37,11 +37,11 @@ # This is for RESTCONF. There are three options: # --without-restconf No restconf support # --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 "" HAVE_LIBNGHTTP2=@HAVE_LIBNGHTTP2@ -HAVE_LIBEVHTP=@HAVE_LIBEVHTP@ +HAVE_HTTP1=@HAVE_HTTP1@ # This is for libxml2 XSD regex engine # Note this only enables the compiling of the code. In order to actually diff --git a/test/fuzz/backend/README.md b/test/fuzz/backend/README.md index 65a32524..4c6bfc94 100644 --- a/test/fuzz/backend/README.md +++ b/test/fuzz/backend/README.md @@ -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: ``` - 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 sudo make install diff --git a/test/lib.sh b/test/lib.sh index e2542008..5bf0a0c2 100755 --- a/test/lib.sh +++ b/test/lib.sh @@ -102,11 +102,11 @@ DEFAULTHELLO=" $foutput2 && mv $foutput2 $foutput # Create a file to compare with 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 echo "HTTP/1.1 101 Switching Protocols " > $ftest echo "Upgrade: h2c " >> $ftest diff --git a/test/test_restconf.sh b/test/test_restconf.sh index 4103b2d6..b0c88b9e 100755 --- a/test/test_restconf.sh +++ b/test/test_restconf.sh @@ -164,7 +164,7 @@ function testrun() fi #------------------------------------------------------- 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 HVER=1.1 @@ -213,7 +213,7 @@ function testrun() fi #------------------------------------------------------- HTTP/2 ONLY - elif [ ${HAVE_LIBNGHTTP2} = true -a ${HAVE_LIBEVHTP} = false ]; then + elif [ ${HAVE_LIBNGHTTP2} = true -a ${HAVE_HTTP1} = false ]; then HVER=2 new "wait restconf" @@ -539,7 +539,7 @@ function testrun() # Go thru all combinations of IPv4/IPv6, http/https, local/backend config if [ "${WITH_RESTCONF}" = "fcgi" ]; then protos="http" -elif ${HAVE_LIBEVHTP}; then +elif ${HAVE_HTTP1}; then protos="http" # No plain http for http/2 only fi if [ "${WITH_RESTCONF}" = "native" ]; then diff --git a/test/test_restconf_basic_auth.sh b/test/test_restconf_basic_auth.sh index 8e67c576..428fc1d3 100755 --- a/test/test_restconf_basic_auth.sh +++ b/test/test_restconf_basic_auth.sh @@ -14,8 +14,8 @@ # Magic line must be first in script (see README.md) s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi -if ! ${HAVE_LIBEVHTP}; then - echo "...skipped: LIBEVHTP is false, must run with http/1 (evhtp)" +if ! ${HAVE_HTTP1}; then + echo "...skipped: Must run with http/1" if [ "$s" = $0 ]; then exit 0; else return 0; fi fi diff --git a/test/test_restconf_err.sh b/test/test_restconf_err.sh index 5103f8e3..7657c791 100755 --- a/test/test_restconf_err.sh +++ b/test/test_restconf_err.sh @@ -23,9 +23,9 @@ # Magic line must be first in script (see README.md) s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi -# Does not work with evhtpnative http/2-only -if [ "${WITH_RESTCONF}" = "native" -a ${HAVE_LIBEVHTP} = false ]; then - echo "...skipped: LIBEVHTP is false, must run with http/1 (evhtp)" +# Does not work with native http/2-only +if [ "${WITH_RESTCONF}" = "native" -a ${HAVE_HTTP1} = false ]; then + echo "...skipped: must run with http/1" if [ "$s" = $0 ]; then exit 0; else return 0; fi fi @@ -206,7 +206,7 @@ expectpart "$(curl $CURLOPTS -X GET -H 'Accept: application/yang-data+xml' $RCPR if [ false -a ! ${HAVE_LIBNGHTTP2} ] ; then # Look for netcat or nc for direct socket http calls 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 netcat=nc else @@ -241,9 +241,8 @@ Host: localhost Accept: application/yang-data+xml 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" expectpart "$(${netcat} 127.0.0.1 80 <&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 @@ -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" 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" wait_restconf diff --git a/test/test_restconf_internal.sh b/test/test_restconf_internal.sh index fbc0aa43..8e27e905 100755 --- a/test/test_restconf_internal.sh +++ b/test/test_restconf_internal.sh @@ -14,9 +14,9 @@ # Magic line must be first in script (see README.md) s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi -# Does not work with evhtpnative http/2-only -if [ "${WITH_RESTCONF}" = "native" -a ${HAVE_LIBEVHTP} = false ]; then - echo "...skipped: LIBEVHTP is false, must run with http/1 (evhtp)" +# Does not work with native http/2-only +if [ "${WITH_RESTCONF}" = "native" -a ${HAVE_HTTP1} = false ]; then + echo "...skipped: Must run with http/1" if [ "$s" = $0 ]; then exit 0; else return 0; fi fi diff --git a/test/test_restconf_internal_usecases.sh b/test/test_restconf_internal_usecases.sh index 0ca627b4..7a733751 100755 --- a/test/test_restconf_internal_usecases.sh +++ b/test/test_restconf_internal_usecases.sh @@ -25,9 +25,9 @@ # Magic line must be first in script (see README.md) s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi -# Does not work with evhtpnative http/2-only -if [ "${WITH_RESTCONF}" = "native" -a ${HAVE_LIBEVHTP} = false ]; then - echo "...skipped: LIBEVHTP is false, must run with http/1 (evhtp)" +# Does not work with native http/2-only +if [ "${WITH_RESTCONF}" = "native" -a ${HAVE_HTTP1} = false ]; then + echo "...skipped: Must run with http/1" if [ "$s" = $0 ]; then exit 0; else return 0; fi fi diff --git a/test/test_restconf_netns.sh b/test/test_restconf_netns.sh index 4f1e2188..93613527 100755 --- a/test/test_restconf_netns.sh +++ b/test/test_restconf_netns.sh @@ -16,8 +16,8 @@ if [ "${WITH_RESTCONF}" != "native" ]; then if [ "$s" = $0 ]; then exit 0; else return 0; fi # skip fi -if ! ${HAVE_LIBEVHTP}; then - echo "...skipped: LIBEVHTP is false, must run with http/1 (evhtp)" +if ! ${HAVE_HTTP1}; then + echo "...skipped: HAVE_HTTP1 is false, must run with http/1" if [ "$s" = $0 ]; then exit 0; else return 0; fi fi @@ -197,7 +197,7 @@ new "netconf commit" expecteof "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO]]>]]>" "^]]>]]>$" # NOTE http/1.1 -if ${HAVE_LIBEVHTP}; then +if ${HAVE_HTTP1}; then 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" 'a42
' 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" expectpart "$(sudo ip netns exec $netns curl $CURLOPTS -X POST -H 'Content-Type: application/yang-data+xml' -d 'b99' https://$vaddr/restconf/data/clixon-example:table)" 0 "HTTP/$HVER 201" -if ${HAVE_LIBEVHTP}; then +if ${HAVE_HTTP1}; then # NOTE http/1.1 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" 'b99' diff --git a/test/vagrant/vagrant.sh b/test/vagrant/vagrant.sh index 46545cde..00d05cfe 100755 --- a/test/vagrant/vagrant.sh +++ b/test/vagrant/vagrant.sh @@ -215,7 +215,6 @@ case $release in ;; native) $sshcmd sudo apt install -y libssl-dev - $sshcmd sudo apt install -y libevent-dev # evhtp $sshcmd sudo apt install -y libnghttp2-dev # nghttp2 ;; esac @@ -269,15 +268,6 @@ case ${with_restconf} in . ./nginx.sh $dir $idfile $port $wwwuser ;; 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 diff --git a/yang/clixon/clixon-restconf@2021-05-20.yang b/yang/clixon/clixon-restconf@2021-05-20.yang index 74c5d651..1c557240 100644 --- a/yang/clixon/clixon-restconf@2021-05-20.yang +++ b/yang/clixon/clixon-restconf@2021-05-20.yang @@ -71,7 +71,7 @@ module clixon-restconf { proxy solution. That is, a reverse proxy is the HTTP front-end and the restconf daemon listens 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 { @@ -183,10 +183,10 @@ module clixon-restconf { description "Path to FastCGI unix socket. Should be specified in webserver 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"; } - /* Second, evhtp-specific options */ + /* Second, local native options */ leaf server-cert-path { type string; description