- Restconf native http/1 to http/2 upgrade (non-tls)
This commit is contained in:
parent
b711faade9
commit
4f513385e9
17 changed files with 286 additions and 122 deletions
|
|
@ -38,7 +38,9 @@ Expected: June 2021
|
||||||
* Enable using: `--with-restconf=native --enable-nghttp2`
|
* Enable using: `--with-restconf=native --enable-nghttp2`
|
||||||
* FCGI/nginx not affected only for `--with-restconf=native`
|
* FCGI/nginx not affected only for `--with-restconf=native`
|
||||||
* HTTP/1 co-exists, unless `--disable-evhtp` which results in http/2 only
|
* HTTP/1 co-exists, unless `--disable-evhtp` which results in http/2 only
|
||||||
* TLS ALPN upgrade works but http (non SSL) http/1->http/2 upgrade is not yet implemented
|
* Upgrade from HTTP/1.1 to HTTP/2
|
||||||
|
* https: ALPN upgrade
|
||||||
|
* http: Upgrade header
|
||||||
* YANG when statement in conjunction with grouping/uses/augment
|
* YANG when statement in conjunction with grouping/uses/augment
|
||||||
* Several cases were not implemented fully according to RFC 7950:
|
* Several cases were not implemented fully according to RFC 7950:
|
||||||
* Do not extend default values if when statements evaluate to false
|
* Do not extend default values if when statements evaluate to false
|
||||||
|
|
|
||||||
|
|
@ -151,12 +151,10 @@ restconf_reply_send(void *req0,
|
||||||
if (cb != NULL){
|
if (cb != NULL){
|
||||||
if (cbuf_len(cb)){
|
if (cbuf_len(cb)){
|
||||||
cprintf(cb, "\r\n");
|
cprintf(cb, "\r\n");
|
||||||
#if 0 /* Double for evhtp, single for nghttp2 */
|
sd->sd_body_len = cbuf_len(cb);
|
||||||
if (restconf_reply_header(sd, "Content-Length", "%d", cbuf_len(cb)) < 0)
|
if (head){
|
||||||
goto done;
|
|
||||||
#endif
|
|
||||||
if (head)
|
|
||||||
cbuf_free(cb);
|
cbuf_free(cb);
|
||||||
|
}
|
||||||
else{
|
else{
|
||||||
sd->sd_body = cb;
|
sd->sd_body = cb;
|
||||||
sd->sd_body_offset = 0;
|
sd->sd_body_offset = 0;
|
||||||
|
|
@ -164,17 +162,11 @@ restconf_reply_send(void *req0,
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
cbuf_free(cb);
|
cbuf_free(cb);
|
||||||
#if 0
|
sd->sd_body_len = 0;
|
||||||
if (restconf_reply_header(sd, "Content-Length", "0") < 0)
|
|
||||||
goto done;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#if 0
|
|
||||||
else
|
else
|
||||||
if (restconf_reply_header(sd, "Content-Length", "0") < 0)
|
sd->sd_body_len = 0;
|
||||||
goto done;
|
|
||||||
#endif
|
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
return retval;
|
return retval;
|
||||||
|
|
|
||||||
|
|
@ -195,7 +195,7 @@ evhtp_convert_fcgi(evhtp_header_t *hdr,
|
||||||
return restconf_convert_hdr(h, hdr->key, hdr->val);
|
return restconf_convert_hdr(h, hdr->key, hdr->val);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Map from evhtp information to "fcgi" type parameters used in clixon code
|
/*! 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
|
* While all these params come via one call in fcgi, the information must be taken from
|
||||||
* several different places in evhtp
|
* several different places in evhtp
|
||||||
|
|
@ -216,9 +216,9 @@ evhtp_convert_fcgi(evhtp_header_t *hdr,
|
||||||
* @note there may be more used by an application plugin
|
* @note there may be more used by an application plugin
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
evhtp_params_set(clicon_handle h,
|
convert_evhtp_params2clixon(clicon_handle h,
|
||||||
evhtp_request_t *req,
|
evhtp_request_t *req,
|
||||||
cvec *qvec)
|
cvec *qvec)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
htp_method meth;
|
htp_method meth;
|
||||||
|
|
@ -395,9 +395,9 @@ restconf_evhtp_reply(restconf_conn *rc,
|
||||||
* (Successful) response to a CONNECT request (Section 4.3.6 of
|
* (Successful) response to a CONNECT request (Section 4.3.6 of
|
||||||
* [RFC7231]).
|
* [RFC7231]).
|
||||||
*/
|
*/
|
||||||
if (restconf_reply_header(sd, "Content-Length", "%d",
|
if (sd->sd_code != 204 && sd->sd_code > 199)
|
||||||
(sd->sd_body!=NULL)?cbuf_len(sd->sd_body):0) < 0)
|
if (restconf_reply_header(sd, "Content-Length", "%lu", sd->sd_body_len) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
/* Create reply and write headers */
|
/* Create reply and write headers */
|
||||||
if (native_send_reply(rc, sd, req) < 0)
|
if (native_send_reply(rc, sd, req) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -410,6 +410,60 @@ restconf_evhtp_reply(restconf_conn *rc,
|
||||||
return retval;
|
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){
|
||||||
|
/* 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 /
|
/*! 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, Registered with evhtp_set_cb
|
||||||
|
|
@ -429,10 +483,12 @@ restconf_path_root(evhtp_request_t *req,
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
clicon_handle h;
|
clicon_handle h;
|
||||||
int ret;
|
int ret;
|
||||||
cvec *qvec = NULL;
|
|
||||||
evhtp_connection_t *evconn;
|
evhtp_connection_t *evconn;
|
||||||
restconf_conn *rc;
|
restconf_conn *rc;
|
||||||
restconf_stream_data *sd;
|
restconf_stream_data *sd;
|
||||||
|
size_t len;
|
||||||
|
unsigned char *buf;
|
||||||
|
int keep_params = 0; /* set to 1 if dont delete params */
|
||||||
|
|
||||||
clicon_debug(1, "------------");
|
clicon_debug(1, "------------");
|
||||||
if ((h = (clicon_handle)arg) == NULL){
|
if ((h = (clicon_handle)arg) == NULL){
|
||||||
|
|
@ -458,46 +514,48 @@ restconf_path_root(evhtp_request_t *req,
|
||||||
/* input debug */
|
/* input debug */
|
||||||
if (clicon_debug_get())
|
if (clicon_debug_get())
|
||||||
evhtp_headers_for_each(req->headers_in, evhtp_print_header, h);
|
evhtp_headers_for_each(req->headers_in, evhtp_print_header, h);
|
||||||
|
|
||||||
/* get accepted connection */
|
|
||||||
/* Query vector, ie the ?a=x&b=y stuff */
|
/* Query vector, ie the ?a=x&b=y stuff */
|
||||||
if ((qvec = cvec_new(0)) ==NULL){
|
if ((sd->sd_qvec = cvec_new(0)) ==NULL){
|
||||||
clicon_err(OE_UNIX, errno, "cvec_new");
|
clicon_err(OE_UNIX, errno, "cvec_new");
|
||||||
evhtp_internal_error(req);
|
evhtp_internal_error(req);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
/* Get indata
|
/* Get indata
|
||||||
*/
|
*/
|
||||||
{
|
if ((len = evbuffer_get_length(req->buffer_in)) > 0){
|
||||||
size_t len;
|
if ((buf = evbuffer_pullup(req->buffer_in, len)) == NULL){
|
||||||
unsigned char *buf;
|
clicon_err(OE_CFG, errno, "evbuffer_pullup");
|
||||||
|
goto done;
|
||||||
len = evbuffer_get_length(req->buffer_in);
|
|
||||||
if (len > 0){
|
|
||||||
if ((buf = evbuffer_pullup(req->buffer_in, len)) == NULL){
|
|
||||||
clicon_err(OE_CFG, errno, "evbuffer_pullup");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
/* Note the pullup may not be null-terminated */
|
|
||||||
cbuf_append_buf(sd->sd_indata, buf, len);
|
|
||||||
}
|
}
|
||||||
|
/* Note the pullup may not be null-terminated */
|
||||||
|
cbuf_append_buf(sd->sd_indata, buf, len);
|
||||||
}
|
}
|
||||||
/* set fcgi-like paramaters (ignore query vector)
|
/* Convert parameters from evhtp to fcgi-like parameters used by clixon
|
||||||
* ret = 0 means an error has already been sent
|
* ret = 0 means an error has already been sent
|
||||||
*/
|
*/
|
||||||
if ((ret = evhtp_params_set(h, req, qvec)) < 0){
|
if ((ret = convert_evhtp_params2clixon(h, req, sd->sd_qvec)) < 0){
|
||||||
evhtp_internal_error(req);
|
evhtp_internal_error(req);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
#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){
|
if (ret == 1){
|
||||||
/* call generic function */
|
/* call generic function */
|
||||||
if (api_root_restconf(h, sd, qvec) < 0){
|
if (api_root_restconf(h, sd, sd->sd_qvec) < 0){
|
||||||
evhtp_internal_error(req);
|
evhtp_internal_error(req);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Clear input request parameters from this request */
|
/* Clear input request parameters from this request */
|
||||||
if (restconf_param_del_all(h) < 0){
|
if (!keep_params && restconf_param_del_all(h) < 0){
|
||||||
evhtp_internal_error(req);
|
evhtp_internal_error(req);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
@ -512,8 +570,6 @@ restconf_path_root(evhtp_request_t *req,
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
clicon_debug(1, "%s %d", __FUNCTION__, retval);
|
clicon_debug(1, "%s %d", __FUNCTION__, retval);
|
||||||
if (qvec)
|
|
||||||
cvec_free(qvec);
|
|
||||||
return; /* void */
|
return; /* void */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -533,6 +589,7 @@ restconf_path_wellknown(evhtp_request_t *req,
|
||||||
evhtp_connection_t *evconn;
|
evhtp_connection_t *evconn;
|
||||||
restconf_conn *rc;
|
restconf_conn *rc;
|
||||||
restconf_stream_data *sd;
|
restconf_stream_data *sd;
|
||||||
|
int keep_params = 0; /* set to 1 if dont delete params */
|
||||||
|
|
||||||
clicon_debug(1, "------------");
|
clicon_debug(1, "------------");
|
||||||
if ((h = (clicon_handle)arg) == NULL){
|
if ((h = (clicon_handle)arg) == NULL){
|
||||||
|
|
@ -558,13 +615,29 @@ restconf_path_wellknown(evhtp_request_t *req,
|
||||||
/* input debug */
|
/* input debug */
|
||||||
if (clicon_debug_get())
|
if (clicon_debug_get())
|
||||||
evhtp_headers_for_each(req->headers_in, evhtp_print_header, h);
|
evhtp_headers_for_each(req->headers_in, evhtp_print_header, h);
|
||||||
/* get accepted connection */
|
/* Query vector, ie the ?a=x&b=y stuff */
|
||||||
|
if ((sd->sd_qvec = cvec_new(0)) ==NULL){
|
||||||
/* set fcgi-like paramaters (ignore query vector) */
|
clicon_err(OE_UNIX, errno, "cvec_new");
|
||||||
if ((ret = evhtp_params_set(h, req, NULL)) < 0){
|
|
||||||
evhtp_internal_error(req);
|
evhtp_internal_error(req);
|
||||||
goto done;
|
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;
|
||||||
|
}
|
||||||
|
#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){
|
if (ret == 1){
|
||||||
/* call generic function */
|
/* call generic function */
|
||||||
if (api_well_known(h, sd) < 0){
|
if (api_well_known(h, sd) < 0){
|
||||||
|
|
@ -573,7 +646,7 @@ restconf_path_wellknown(evhtp_request_t *req,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Clear input request parameters from this request */
|
/* Clear input request parameters from this request */
|
||||||
if (restconf_param_del_all(h) < 0){
|
if (!keep_params && restconf_param_del_all(h) < 0){
|
||||||
evhtp_internal_error(req);
|
evhtp_internal_error(req);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -97,7 +97,6 @@ int restconf_authentication_cb(clicon_handle h, void *req, int pretty, restcon
|
||||||
int restconf_config_init(clicon_handle h, cxobj *xrestconf);
|
int restconf_config_init(clicon_handle h, cxobj *xrestconf);
|
||||||
int restconf_socket_init(const char *netns0, const char *addrstr, const char *addrtype, uint16_t port, int backlog, int flags, int *ss);
|
int restconf_socket_init(const char *netns0, const char *addrstr, const char *addrtype, uint16_t port, int backlog, int flags, int *ss);
|
||||||
int restconf_socket_extract(clicon_handle h, cxobj *xs, cvec *nsc, char **namespace, char **address, char **addrtype, uint16_t *port, uint16_t *ssl);
|
int restconf_socket_extract(clicon_handle h, cxobj *xs, cvec *nsc, char **namespace, char **address, char **addrtype, uint16_t *port, uint16_t *ssl);
|
||||||
int restconf_convert_hdr(clicon_handle h, char *name, char *val);
|
|
||||||
|
|
||||||
#endif /* _RESTCONF_LIB_H_ */
|
#endif /* _RESTCONF_LIB_H_ */
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -585,7 +585,7 @@ restconf_ssl_context_configure(clixon_handle h,
|
||||||
* There are many variants to closing, one could probably make this more generic
|
* There are many variants to closing, one could probably make this more generic
|
||||||
* and always use this function, but it is difficult.
|
* and always use this function, but it is difficult.
|
||||||
*/
|
*/
|
||||||
static int
|
int
|
||||||
restconf_close_ssl_socket(restconf_conn *rc,
|
restconf_close_ssl_socket(restconf_conn *rc,
|
||||||
int shutdown)
|
int shutdown)
|
||||||
{
|
{
|
||||||
|
|
@ -594,9 +594,11 @@ restconf_close_ssl_socket(restconf_conn *rc,
|
||||||
#ifdef HAVE_LIBEVHTP
|
#ifdef HAVE_LIBEVHTP
|
||||||
evhtp_connection_t *evconn;
|
evhtp_connection_t *evconn;
|
||||||
|
|
||||||
evconn = rc->rc_evconn;
|
if ((evconn = rc->rc_evconn) != NULL){
|
||||||
clicon_debug(1, "%s evconn-free (%p) 1", __FUNCTION__, evconn);
|
clicon_debug(1, "%s evconn-free (%p)", __FUNCTION__, evconn);
|
||||||
evhtp_connection_free(evconn); /* evhtp */
|
if (evconn)
|
||||||
|
evhtp_connection_free(evconn); /* evhtp */
|
||||||
|
}
|
||||||
#endif /* HAVE_LIBEVHTP */
|
#endif /* HAVE_LIBEVHTP */
|
||||||
if (rc->rc_ssl != NULL){
|
if (rc->rc_ssl != NULL){
|
||||||
if (shutdown && (ret = SSL_shutdown(rc->rc_ssl)) < 0){
|
if (shutdown && (ret = SSL_shutdown(rc->rc_ssl)) < 0){
|
||||||
|
|
@ -714,9 +716,9 @@ restconf_connection(int s,
|
||||||
if ((n = read(rc->rc_s, buf, sizeof(buf))) < 0){ /* XXX atomicio ? */
|
if ((n = read(rc->rc_s, buf, sizeof(buf))) < 0){ /* XXX atomicio ? */
|
||||||
if (errno == ECONNRESET) {/* Connection reset by peer */
|
if (errno == ECONNRESET) {/* Connection reset by peer */
|
||||||
clicon_debug(1, "%s %d Connection reset by peer", __FUNCTION__, rc->rc_s);
|
clicon_debug(1, "%s %d Connection reset by peer", __FUNCTION__, rc->rc_s);
|
||||||
|
clixon_event_unreg_fd(rc->rc_s, restconf_connection);
|
||||||
close(rc->rc_s);
|
close(rc->rc_s);
|
||||||
restconf_conn_free(rc);
|
restconf_conn_free(rc);
|
||||||
clixon_event_unreg_fd(rc->rc_s, restconf_connection);
|
|
||||||
goto ok; /* Close socket and ssl */
|
goto ok; /* Close socket and ssl */
|
||||||
}
|
}
|
||||||
clicon_err(OE_XML, errno, "read");
|
clicon_err(OE_XML, errno, "read");
|
||||||
|
|
@ -762,7 +764,7 @@ restconf_connection(int s,
|
||||||
restconf_conn_free(rc);
|
restconf_conn_free(rc);
|
||||||
evhtp_connection_free(evconn);
|
evhtp_connection_free(evconn);
|
||||||
goto ok;
|
goto ok;
|
||||||
}
|
} /* connection_parse_nobev */
|
||||||
clicon_debug(1, "%s connection_parse OK", __FUNCTION__);
|
clicon_debug(1, "%s connection_parse OK", __FUNCTION__);
|
||||||
/* default stream */
|
/* default stream */
|
||||||
if ((sd = restconf_stream_find(rc, 0)) == NULL){
|
if ((sd = restconf_stream_find(rc, 0)) == NULL){
|
||||||
|
|
@ -816,6 +818,39 @@ restconf_connection(int s,
|
||||||
"<errors xmlns=\"urn:ietf:params:xml:ns:yang:ietf-restconf\"><error><error-type>protocol</error-type><error-tag>malformed-message</error-tag><error-message>No evhtp output</error-message></error></errors>") < 0)
|
"<errors xmlns=\"urn:ietf:params:xml:ns:yang:ietf-restconf\"><error><error-type>protocol</error-type><error-tag>malformed-message</error-tag><error-message>No evhtp output</error-message></error></errors>") < 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
#ifdef HAVE_LIBNGHTTP2
|
||||||
|
if (sd->sd_upgrade2){
|
||||||
|
nghttp2_error ngerr;
|
||||||
|
/* Switch to http/2 according to RFC 7540 Sec 3.2 and RFC 7230 Sec 6.7 */
|
||||||
|
rc->rc_proto = HTTP_2;
|
||||||
|
if (http2_session_init(rc) < 0){
|
||||||
|
restconf_close_ssl_socket(rc, 1);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
/* The HTTP/1.1 request that is sent prior to upgrade is assigned a
|
||||||
|
* stream identifier of 1 (see Section 5.1.1) with default priority
|
||||||
|
*/
|
||||||
|
sd->sd_stream_id = 1;
|
||||||
|
/* The first HTTP/2 frame sent by the server MUST be a server connection
|
||||||
|
* preface (Section 3.5) consisting of a SETTINGS frame (Section 6.5).
|
||||||
|
*/
|
||||||
|
if ((ngerr = nghttp2_session_upgrade2(rc->rc_ngsession,
|
||||||
|
sd->sd_settings2,
|
||||||
|
sd->sd_settings2?strlen((const char*)sd->sd_settings2):0,
|
||||||
|
0, /* XXX: 1 if HEAD */
|
||||||
|
NULL)) < 0){
|
||||||
|
clicon_err(OE_NGHTTP2, ngerr, "nghttp2_session_upgrade2");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if (http2_send_server_connection(rc) < 0){
|
||||||
|
restconf_close_ssl_socket(rc, 1);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
/* Use params from original http/1 session to http/2 stream */
|
||||||
|
if (http2_exec(rc, sd, rc->rc_ngsession, 1) < 0)
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
break;
|
break;
|
||||||
#endif /* HAVE_LIBEVHTP */
|
#endif /* HAVE_LIBEVHTP */
|
||||||
#ifdef HAVE_LIBNGHTTP2
|
#ifdef HAVE_LIBNGHTTP2
|
||||||
|
|
@ -834,7 +869,7 @@ restconf_connection(int s,
|
||||||
done:
|
done:
|
||||||
clicon_debug(1, "%s retval %d", __FUNCTION__, retval);
|
clicon_debug(1, "%s retval %d", __FUNCTION__, retval);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
} /* restconf_connection */
|
||||||
|
|
||||||
#if 0 /* debug */
|
#if 0 /* debug */
|
||||||
/*! Debug print all loaded certs
|
/*! Debug print all loaded certs
|
||||||
|
|
@ -983,7 +1018,7 @@ ssl_alpn_check(clicon_handle h,
|
||||||
if (cberr)
|
if (cberr)
|
||||||
cbuf_free(cberr);
|
cbuf_free(cberr);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
} /* ssl_alpn_check */
|
||||||
|
|
||||||
/*! Accept new socket client
|
/*! Accept new socket client
|
||||||
* @param[in] fd Socket (unix or ip)
|
* @param[in] fd Socket (unix or ip)
|
||||||
|
|
@ -1013,8 +1048,10 @@ restconf_accept_client(int fd,
|
||||||
|
|
||||||
clicon_debug(1, "%s %d", __FUNCTION__, fd);
|
clicon_debug(1, "%s %d", __FUNCTION__, fd);
|
||||||
#ifdef HAVE_LIBNGHTTP2
|
#ifdef HAVE_LIBNGHTTP2
|
||||||
/* If nghttp2 let default be 2.0 NOTE http protocol negotiation */
|
#ifndef HAVE_LIBEVHTP
|
||||||
proto = HTTP_2;
|
proto = HTTP_2; /* If nghttp2 only let default be 2.0 */
|
||||||
|
#endif
|
||||||
|
/* If also evhtp, keep HTTP_11 */
|
||||||
#endif
|
#endif
|
||||||
if ((rsock = (restconf_socket *)arg) == NULL){
|
if ((rsock = (restconf_socket *)arg) == NULL){
|
||||||
clicon_err(OE_YANG, EINVAL, "rsock is NULL");
|
clicon_err(OE_YANG, EINVAL, "rsock is NULL");
|
||||||
|
|
@ -1266,7 +1303,7 @@ restconf_accept_client(int fd,
|
||||||
if (name)
|
if (name)
|
||||||
free(name);
|
free(name);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
} /* restconf_accept_client */
|
||||||
|
|
||||||
static int
|
static int
|
||||||
restconf_native_terminate(clicon_handle h)
|
restconf_native_terminate(clicon_handle h)
|
||||||
|
|
@ -1599,7 +1636,7 @@ restconf_clixon_init(clicon_handle h,
|
||||||
clixon_plugin_t *cp = NULL;
|
clixon_plugin_t *cp = NULL;
|
||||||
char *str;
|
char *str;
|
||||||
cvec *nsctx_global = NULL; /* Global namespace context */
|
cvec *nsctx_global = NULL; /* Global namespace context */
|
||||||
cxobj *xrestconf;
|
cxobj *xrestconf = NULL;
|
||||||
cxobj *xerr = NULL;
|
cxobj *xerr = NULL;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -139,6 +139,10 @@ restconf_stream_free(restconf_stream_data *sd)
|
||||||
cbuf_free(sd->sd_body);
|
cbuf_free(sd->sd_body);
|
||||||
if (sd->sd_path)
|
if (sd->sd_path)
|
||||||
free(sd->sd_path);
|
free(sd->sd_path);
|
||||||
|
if (sd->sd_settings2)
|
||||||
|
free(sd->sd_settings2);
|
||||||
|
if (sd->sd_qvec)
|
||||||
|
cvec_free(sd->sd_qvec);
|
||||||
free(sd);
|
free(sd);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -71,16 +71,20 @@ typedef struct {
|
||||||
cvec *sd_outp_hdrs; /* List of output headers */
|
cvec *sd_outp_hdrs; /* List of output headers */
|
||||||
cbuf *sd_outp_buf; /* Output buffer */
|
cbuf *sd_outp_buf; /* Output buffer */
|
||||||
cbuf *sd_body; /* http output body as cbuf terminated with \r\n */
|
cbuf *sd_body; /* http output body as cbuf terminated with \r\n */
|
||||||
|
size_t sd_body_len; /* Content-Length, note for HEAD body body can be NULL and this non-zero */
|
||||||
size_t sd_body_offset; /* Offset into body */
|
size_t sd_body_offset; /* Offset into body */
|
||||||
cbuf *sd_indata; /* Receive/input data */
|
cbuf *sd_indata; /* Receive/input data */
|
||||||
char *sd_path; /* Uri path, uri-encoded, without args (eg ?) */
|
char *sd_path; /* Uri path, uri-encoded, without args (eg ?) */
|
||||||
uint16_t sd_code; /* If != 0 send a reply XXX: need reply flag? */
|
uint16_t sd_code; /* If != 0 send a reply XXX: need reply flag? */
|
||||||
struct restconf_conn *sd_conn; /* Backpointer to connection this stream is part of */
|
struct restconf_conn *sd_conn; /* Backpointer to connection this stream is part of */
|
||||||
restconf_http_proto sd_proto; /* http protocol XXX not sure this is needed */
|
restconf_http_proto sd_proto; /* http protocol XXX not sure this is needed */
|
||||||
|
cvec *sd_qvec; /* Query parameters, ie ?a=b&c=d */
|
||||||
void *sd_req; /* Lib-specific request, eg evhtp_request_t * */
|
void *sd_req; /* Lib-specific request, eg evhtp_request_t * */
|
||||||
|
int sd_upgrade2; /* Upgrade to http/2 */
|
||||||
|
uint8_t *sd_settings2; /* Settings for upgrade to http/2 request */
|
||||||
} restconf_stream_data;
|
} restconf_stream_data;
|
||||||
|
|
||||||
/* Restconf connection handle
|
/* Restconf connection handle
|
||||||
* Per connection request
|
* Per connection request
|
||||||
*/
|
*/
|
||||||
typedef struct restconf_conn {
|
typedef struct restconf_conn {
|
||||||
|
|
@ -133,6 +137,8 @@ restconf_conn *restconf_conn_new(clicon_handle h, int s);
|
||||||
int restconf_conn_free(restconf_conn *rc);
|
int restconf_conn_free(restconf_conn *rc);
|
||||||
int ssl_x509_name_oneline(SSL *ssl, char **oneline);
|
int ssl_x509_name_oneline(SSL *ssl, char **oneline);
|
||||||
|
|
||||||
|
int restconf_close_ssl_socket(restconf_conn *rc, int shutdown); /* XXX in restconf_main_native.c */
|
||||||
|
|
||||||
#endif /* _RESTCONF_NATIVE_H_ */
|
#endif /* _RESTCONF_NATIVE_H_ */
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|
|
||||||
|
|
@ -99,10 +99,9 @@
|
||||||
#include "restconf_err.h"
|
#include "restconf_err.h"
|
||||||
#include "restconf_root.h"
|
#include "restconf_root.h"
|
||||||
#include "restconf_native.h" /* Restconf-openssl mode specific headers*/
|
#include "restconf_native.h" /* Restconf-openssl mode specific headers*/
|
||||||
|
#ifdef HAVE_LIBNGHTTP2
|
||||||
#include "restconf_nghttp2.h" /* Restconf-openssl mode specific headers*/
|
#include "restconf_nghttp2.h" /* Restconf-openssl mode specific headers*/
|
||||||
|
|
||||||
#ifdef HAVE_LIBNGHTTP2 /* XXX MOVE */
|
|
||||||
|
|
||||||
#define ARRLEN(x) (sizeof(x) / sizeof(x[0]))
|
#define ARRLEN(x) (sizeof(x) / sizeof(x[0]))
|
||||||
|
|
||||||
/*! Map http2 frame types in nghttp2
|
/*! Map http2 frame types in nghttp2
|
||||||
|
|
@ -283,12 +282,10 @@ restconf_nghttp2_path(restconf_stream_data *sd)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
clicon_handle h;
|
clicon_handle h;
|
||||||
cvec *qvec = NULL;
|
|
||||||
char *query = NULL;
|
|
||||||
restconf_conn *rc;
|
restconf_conn *rc;
|
||||||
char *oneline = NULL;
|
char *oneline = NULL;
|
||||||
cvec *cvv = NULL;
|
cvec *cvv = NULL;
|
||||||
char *cn;
|
char *cn;
|
||||||
|
|
||||||
clicon_debug(1, "------------");
|
clicon_debug(1, "------------");
|
||||||
rc = sd->sd_conn;
|
rc = sd->sd_conn;
|
||||||
|
|
@ -296,15 +293,6 @@ restconf_nghttp2_path(restconf_stream_data *sd)
|
||||||
clicon_err(OE_RESTCONF, EINVAL, "arg is NULL");
|
clicon_err(OE_RESTCONF, EINVAL, "arg is NULL");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
/* get accepted connection */
|
|
||||||
/* Query vector, ie the ?a=x&b=y stuff */
|
|
||||||
query = restconf_param_get(h, "REQUEST_URI");
|
|
||||||
if ((query = index(query, '?')) != NULL){
|
|
||||||
query++;
|
|
||||||
if (strlen(query) &&
|
|
||||||
uri_str2cvec(query, '&', '=', 1, &qvec) < 0)
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
/* Slightly awkward way of taking SSL cert subject and CN and add it to restconf parameters
|
/* Slightly awkward way of taking SSL cert subject and CN and add it to restconf parameters
|
||||||
* instead of accessing it directly */
|
* instead of accessing it directly */
|
||||||
if (rc->rc_ssl != NULL){
|
if (rc->rc_ssl != NULL){
|
||||||
|
|
@ -325,7 +313,7 @@ restconf_nghttp2_path(restconf_stream_data *sd)
|
||||||
if (api_well_known(h, sd) < 0)
|
if (api_well_known(h, sd) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
else if (api_root_restconf(h, sd, qvec) < 0)
|
else if (api_root_restconf(h, sd, sd->sd_qvec) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
/* Clear (fcgi) paramaters from this request */
|
/* Clear (fcgi) paramaters from this request */
|
||||||
if (restconf_param_del_all(h) < 0)
|
if (restconf_param_del_all(h) < 0)
|
||||||
|
|
@ -341,8 +329,6 @@ restconf_nghttp2_path(restconf_stream_data *sd)
|
||||||
cvec_free(cvv);
|
cvec_free(cvv);
|
||||||
if (oneline)
|
if (oneline)
|
||||||
free(oneline);
|
free(oneline);
|
||||||
if (qvec)
|
|
||||||
cvec_free(qvec);
|
|
||||||
return retval; /* void */
|
return retval; /* void */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -429,7 +415,6 @@ restconf_submit_response(nghttp2_session *session,
|
||||||
hdr->value = (uint8_t*)valstr;
|
hdr->value = (uint8_t*)valstr;
|
||||||
hdr->namelen = strlen(":status");
|
hdr->namelen = strlen(":status");
|
||||||
hdr->valuelen = strlen(valstr);
|
hdr->valuelen = strlen(valstr);
|
||||||
clicon_debug(1, "%s val:'%s' valuelen:%lu", __FUNCTION__, hdr->value, hdr->valuelen);
|
|
||||||
hdr->flags = 0;
|
hdr->flags = 0;
|
||||||
|
|
||||||
cv = NULL;
|
cv = NULL;
|
||||||
|
|
@ -453,6 +438,49 @@ restconf_submit_response(nghttp2_session *session,
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! Simulate a received request in an upgrade scenario by talking the http/1 parameters
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
http2_exec(restconf_conn *rc,
|
||||||
|
restconf_stream_data *sd,
|
||||||
|
nghttp2_session *session,
|
||||||
|
int32_t stream_id)
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
|
||||||
|
if ((sd->sd_path = restconf_uripath(rc->rc_h)) == NULL)
|
||||||
|
goto done;
|
||||||
|
sd->sd_proto = HTTP_2; /* XXX is this necessary? */
|
||||||
|
if (strncmp(sd->sd_path, "/" RESTCONF_API, strlen("/" RESTCONF_API)) == 0 ||
|
||||||
|
strcmp(sd->sd_path, RESTCONF_WELL_KNOWN) == 0){
|
||||||
|
if (restconf_nghttp2_path(sd) < 0)
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
; /* ignore */
|
||||||
|
/* 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", "%lu", sd->sd_body_len) < 0)
|
||||||
|
goto done;
|
||||||
|
if (sd->sd_code){
|
||||||
|
if (restconf_submit_response(session, rc, stream_id, sd) < 0)
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* 500 Internal server error ? */
|
||||||
|
}
|
||||||
|
|
||||||
|
retval = 0;
|
||||||
|
done:
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
/*! A frame is received
|
/*! A frame is received
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
|
|
@ -463,6 +491,7 @@ on_frame_recv_callback(nghttp2_session *session,
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
restconf_conn *rc = (restconf_conn *)user_data;
|
restconf_conn *rc = (restconf_conn *)user_data;
|
||||||
restconf_stream_data *sd = NULL;
|
restconf_stream_data *sd = NULL;
|
||||||
|
char *query;
|
||||||
|
|
||||||
clicon_debug(1, "%s %s %d", __FUNCTION__,
|
clicon_debug(1, "%s %s %d", __FUNCTION__,
|
||||||
clicon_int2str(nghttp2_frame_type_map, frame->hd.type),
|
clicon_int2str(nghttp2_frame_type_map, frame->hd.type),
|
||||||
|
|
@ -473,33 +502,25 @@ on_frame_recv_callback(nghttp2_session *session,
|
||||||
/* Check that the client request has finished */
|
/* Check that the client request has finished */
|
||||||
if (frame->hd.flags & NGHTTP2_FLAG_END_STREAM) {
|
if (frame->hd.flags & NGHTTP2_FLAG_END_STREAM) {
|
||||||
/* For DATA and HEADERS frame, this callback may be called after
|
/* For DATA and HEADERS frame, this callback may be called after
|
||||||
on_stream_close_callback. Check that stream still alive.
|
* on_stream_close_callback. Check that stream still alive.
|
||||||
*/
|
*/
|
||||||
if ((sd = nghttp2_session_get_stream_user_data(session, frame->hd.stream_id)) == NULL)
|
if ((sd = nghttp2_session_get_stream_user_data(session, frame->hd.stream_id)) == NULL)
|
||||||
return 0;
|
return 0;
|
||||||
if ((sd->sd_path = restconf_uripath(rc->rc_h)) == NULL)
|
/* Query vector, ie the ?a=x&b=y stuff */
|
||||||
goto ok;
|
query = restconf_param_get(rc->rc_h, "REQUEST_URI");
|
||||||
sd->sd_proto = HTTP_2; /* XXX is this necessary? */
|
if ((query = index(query, '?')) != NULL){
|
||||||
if (strncmp(sd->sd_path, "/" RESTCONF_API, strlen("/" RESTCONF_API)) == 0 ||
|
query++;
|
||||||
strcmp(sd->sd_path, RESTCONF_WELL_KNOWN) == 0){
|
if (strlen(query) &&
|
||||||
if (restconf_nghttp2_path(sd) < 0)
|
uri_str2cvec(query, '&', '=', 1, &sd->sd_qvec) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
else
|
if (http2_exec(rc, sd, session, frame->hd.stream_id) < 0)
|
||||||
; /* ignore */
|
goto done;
|
||||||
if (sd->sd_code){
|
|
||||||
if (restconf_submit_response(session, rc, frame->hd.stream_id, sd) < 0)
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
/* 500 Internal server error ? */
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
ok:
|
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
return retval;
|
return retval;
|
||||||
|
|
@ -584,8 +605,16 @@ on_stream_close_callback(nghttp2_session *session,
|
||||||
void *user_data)
|
void *user_data)
|
||||||
{
|
{
|
||||||
// restconf_conn *rc = (restconf_conn *)user_data;
|
// restconf_conn *rc = (restconf_conn *)user_data;
|
||||||
clicon_debug(1, "%s", __FUNCTION__);
|
|
||||||
//session_data *sd = (session_data*)user_data;
|
clicon_debug(1, "%s %d %s", __FUNCTION__, error_code, nghttp2_strerror(error_code));
|
||||||
|
#ifdef NOTNEEDED /* XXX think this is not necessary? */
|
||||||
|
if (error_code){
|
||||||
|
if (restconf_close_ssl_socket(rc, 0) < 0)
|
||||||
|
return -1;
|
||||||
|
if (restconf_conn_free(rc) < 0)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,7 @@
|
||||||
* Prototypes
|
* Prototypes
|
||||||
*/
|
*/
|
||||||
int clixon_nghttp2_log_cb(void *handle, int suberr, cbuf *cb);
|
int clixon_nghttp2_log_cb(void *handle, int suberr, cbuf *cb);
|
||||||
|
int http2_exec(restconf_conn *rc, restconf_stream_data *sd, nghttp2_session *session, int32_t stream_id);
|
||||||
int http2_recv(restconf_conn *rc, const unsigned char *buf, size_t n);
|
int http2_recv(restconf_conn *rc, const unsigned char *buf, size_t n);
|
||||||
int http2_send_server_connection(restconf_conn *rc);
|
int http2_send_server_connection(restconf_conn *rc);
|
||||||
int http2_session_init(restconf_conn *rc);
|
int http2_session_init(restconf_conn *rc);
|
||||||
|
|
|
||||||
12
configure
vendored
12
configure
vendored
|
|
@ -637,7 +637,8 @@ CPP
|
||||||
wwwdir
|
wwwdir
|
||||||
enable_optyangs
|
enable_optyangs
|
||||||
with_libxml2
|
with_libxml2
|
||||||
with_http2
|
HAVE_LIBNGHTTP2
|
||||||
|
HAVE_LIBEVHTP
|
||||||
with_restconf
|
with_restconf
|
||||||
LINKAGE
|
LINKAGE
|
||||||
SH_SUFFIX
|
SH_SUFFIX
|
||||||
|
|
@ -3357,8 +3358,10 @@ test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
|
||||||
|
|
||||||
|
|
||||||
# Set to native or fcgi -> compile apps/restconf
|
# Set to native or fcgi -> compile apps/restconf
|
||||||
with_http2=false
|
HAVE_LIBEVHTP=false
|
||||||
|
# consider using neutral constant such as with-http1
|
||||||
|
HAVE_LIBNGHTTP2=false
|
||||||
|
# consider using neutral constant such as with-http2
|
||||||
|
|
||||||
|
|
||||||
# Home dir for web user, such as nginx fcgi sockets
|
# Home dir for web user, such as nginx fcgi sockets
|
||||||
|
|
@ -5283,6 +5286,7 @@ else
|
||||||
as_fn_error $? "libevhtp missing" "$LINENO" 5
|
as_fn_error $? "libevhtp missing" "$LINENO" 5
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
HAVE_LIBEVHTP=true
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Check if nghttp2 is enabled for http/2
|
# Check if nghttp2 is enabled for http/2
|
||||||
|
|
@ -5363,7 +5367,7 @@ else
|
||||||
as_fn_error $? "nghttp2 missing" "$LINENO" 5
|
as_fn_error $? "nghttp2 missing" "$LINENO" 5
|
||||||
fi
|
fi
|
||||||
|
|
||||||
with_http2=true
|
HAVE_LIBNGHTTP2=true
|
||||||
fi
|
fi
|
||||||
|
|
||||||
$as_echo "#define WITH_RESTCONF_NATIVE 1" >>confdefs.h
|
$as_echo "#define WITH_RESTCONF_NATIVE 1" >>confdefs.h
|
||||||
|
|
|
||||||
|
|
@ -96,7 +96,8 @@ AC_SUBST(LIBS)
|
||||||
AC_SUBST(SH_SUFFIX)
|
AC_SUBST(SH_SUFFIX)
|
||||||
AC_SUBST(LINKAGE)
|
AC_SUBST(LINKAGE)
|
||||||
AC_SUBST(with_restconf) # Set to native or fcgi -> compile apps/restconf
|
AC_SUBST(with_restconf) # Set to native or fcgi -> compile apps/restconf
|
||||||
AC_SUBST(with_http2,false)
|
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(with_libxml2)
|
AC_SUBST(with_libxml2)
|
||||||
AC_SUBST(enable_optyangs)
|
AC_SUBST(enable_optyangs)
|
||||||
# Home dir for web user, such as nginx fcgi sockets
|
# Home dir for web user, such as nginx fcgi sockets
|
||||||
|
|
@ -239,6 +240,7 @@ elif test "x${with_restconf}" == xnative; then
|
||||||
]])
|
]])
|
||||||
AC_CHECK_LIB(event, event_init,, AC_MSG_ERROR([libevent missing]))
|
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])
|
AC_CHECK_LIB(evhtp, evhtp_new,, AC_MSG_ERROR([libevhtp missing]),[-levent -lssl -lcrypto])
|
||||||
|
HAVE_LIBEVHTP=true
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Check if nghttp2 is enabled for http/2
|
# Check if nghttp2 is enabled for http/2
|
||||||
|
|
@ -254,7 +256,7 @@ elif test "x${with_restconf}" == xnative; then
|
||||||
if test "$ac_enable_nghttp2" = "yes"; then
|
if test "$ac_enable_nghttp2" = "yes"; then
|
||||||
AC_CHECK_HEADERS(nghttp2/nghttp2.h,[], AC_MSG_ERROR([nghttp2 missing]))
|
AC_CHECK_HEADERS(nghttp2/nghttp2.h,[], AC_MSG_ERROR([nghttp2 missing]))
|
||||||
AC_CHECK_LIB(nghttp2, nghttp2_session_server_new,, AC_MSG_ERROR([nghttp2 missing]))
|
AC_CHECK_LIB(nghttp2, nghttp2_session_server_new,, AC_MSG_ERROR([nghttp2 missing]))
|
||||||
with_http2=true
|
HAVE_LIBNGHTTP2=true
|
||||||
fi
|
fi
|
||||||
AC_DEFINE(WITH_RESTCONF_NATIVE, 1, [Use native restconf mode]) # For c-code that cant use strings
|
AC_DEFINE(WITH_RESTCONF_NATIVE, 1, [Use native restconf mode]) # For c-code that cant use strings
|
||||||
elif test "x${with_restconf}" == xno; then
|
elif test "x${with_restconf}" == xno; then
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,8 @@
|
||||||
# --with-restconf=native Integration with embedded web server libevhtp
|
# --with-restconf=native Integration with embedded web server libevhtp
|
||||||
WITH_RESTCONF=@with_restconf@ # native, fcgi or ""
|
WITH_RESTCONF=@with_restconf@ # native, fcgi or ""
|
||||||
|
|
||||||
WITH_HTTP2=@with_http2@ # true if nghttp2 is enabled, otherwise false
|
HAVE_LIBNGHTTP2=@HAVE_LIBNGHTTP2@
|
||||||
|
HAVE_LIBEVHTP=@HAVE_LIBEVHTP@
|
||||||
|
|
||||||
# This is for libxml2 XSD regex engine
|
# This is for libxml2 XSD regex engine
|
||||||
# Note this only enables the compiling of the code. In order to actually
|
# Note this only enables the compiling of the code. In order to actually
|
||||||
|
|
|
||||||
11
test/lib.sh
11
test/lib.sh
|
|
@ -100,14 +100,19 @@ DEFAULTHELLO="<?xml version=\"1.0\" encoding=\"UTF-8\"?><hello $DEFAULTNS><capab
|
||||||
# -k : insecure
|
# -k : insecure
|
||||||
: ${CURLOPTS:="-Ssik"}
|
: ${CURLOPTS:="-Ssik"}
|
||||||
# Set HTTP version 1.1 or 2
|
# Set HTTP version 1.1 or 2
|
||||||
if ${WITH_HTTP2}; then
|
if ${HAVE_LIBNGHTTP2}; then
|
||||||
CURLOPTS="${CURLOPTS} --http2-prior-knowledge"
|
|
||||||
HVER=2
|
HVER=2
|
||||||
|
if ${HAVE_LIBEVHTP}; then
|
||||||
|
# This is if evhtp is enabled (unset proto=HTTP_2 in restconf_accept_client)
|
||||||
|
CURLOPTS="${CURLOPTS} --http2"
|
||||||
|
else
|
||||||
|
# This is if evhtp is disabled (set proto=HTTP_2 in restconf_accept_client)
|
||||||
|
CURLOPTS="${CURLOPTS} --http2-prior-knowledge"
|
||||||
|
fi
|
||||||
else
|
else
|
||||||
HVER=1.1
|
HVER=1.1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
# Wait after daemons (backend/restconf) start. See mem.sh for valgrind
|
# Wait after daemons (backend/restconf) start. See mem.sh for valgrind
|
||||||
if [ "$(uname -m)" = "armv7l" ]; then
|
if [ "$(uname -m)" = "armv7l" ]; then
|
||||||
: ${DEMWAIT:=8}
|
: ${DEMWAIT:=8}
|
||||||
|
|
|
||||||
|
|
@ -143,8 +143,16 @@ sed -i '/Transfer-Encoding:/d' $foutput
|
||||||
sed -i '/Connection:/d' $foutput
|
sed -i '/Connection:/d' $foutput
|
||||||
|
|
||||||
# Create a file to compare with
|
# Create a file to compare with
|
||||||
if ${WITH_HTTP2}; then
|
if ${HAVE_LIBNGHTTP2}; then
|
||||||
echo "HTTP/$HVER 200
" > $ftest
|
if ${HAVE_LIBEVHTP}; then
|
||||||
|
# Add 101 switch protocols for http 1->2 upgrade
|
||||||
|
echo "HTTP/1.1 101 Switching Protocols
" > $ftest
|
||||||
|
echo "Upgrade: h2c
" >> $ftest
|
||||||
|
echo "
" >> $ftest
|
||||||
|
echo "HTTP/$HVER 200
" >> $ftest
|
||||||
|
else
|
||||||
|
echo "HTTP/$HVER 200
" > $ftest
|
||||||
|
fi
|
||||||
else
|
else
|
||||||
echo "HTTP/$HVER 200 OK
" > $ftest
|
echo "HTTP/$HVER 200 OK
" > $ftest
|
||||||
fi
|
fi
|
||||||
|
|
@ -157,6 +165,7 @@ echo "</data>
" >> $ftest
|
||||||
|
|
||||||
ret=$(diff -i $ftest $foutput)
|
ret=$(diff -i $ftest $foutput)
|
||||||
if [ $? -ne 0 ]; then
|
if [ $? -ne 0 ]; then
|
||||||
|
echo "$ret"
|
||||||
err1 "Matching running-db with $fconfigonly"
|
err1 "Matching running-db with $fconfigonly"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,7 @@ if [ "${WITH_RESTCONF}" = "native" ]; then
|
||||||
# Create server certs and CA
|
# Create server certs and CA
|
||||||
cacerts $cakey $cacert
|
cacerts $cakey $cacert
|
||||||
servercerts $cakey $cacert $srvkey $srvcert
|
servercerts $cakey $cacert $srvkey $srvcert
|
||||||
USEBACKEND=true
|
USEBACKEND=false
|
||||||
else
|
else
|
||||||
# Define default restconfig config: RESTCONFIG
|
# Define default restconfig config: RESTCONFIG
|
||||||
RESTCONFIG=$(restconf_config none false)
|
RESTCONFIG=$(restconf_config none false)
|
||||||
|
|
@ -169,9 +169,10 @@ function testrun()
|
||||||
wait_restconf
|
wait_restconf
|
||||||
|
|
||||||
new "restconf root discovery. RFC 8040 3.1 (xml+xrd)"
|
new "restconf root discovery. RFC 8040 3.1 (xml+xrd)"
|
||||||
|
echo "curl $CURLOPTS -X GET $proto://$addr/.well-known/host-meta"
|
||||||
expectpart "$(curl $CURLOPTS -X GET $proto://$addr/.well-known/host-meta)" 0 "HTTP/$HVER 200" "<XRD xmlns='http://docs.oasis-open.org/ns/xri/xrd-1.0'>" "<Link rel='restconf' href='/restconf'/>" "</XRD>"
|
expectpart "$(curl $CURLOPTS -X GET $proto://$addr/.well-known/host-meta)" 0 "HTTP/$HVER 200" "<XRD xmlns='http://docs.oasis-open.org/ns/xri/xrd-1.0'>" "<Link rel='restconf' href='/restconf'/>" "</XRD>"
|
||||||
|
|
||||||
if ! ${WITH_HTTP2}; then # http/2
|
if ! ${HAVE_LIBNGHTTP2}; then # http/2
|
||||||
|
|
||||||
if [ "${WITH_RESTCONF}" = "native" ]; then # XXX does not work with nginx
|
if [ "${WITH_RESTCONF}" = "native" ]; then # XXX does not work with nginx
|
||||||
new "restconf GET http/1.0 - returns 1.0"
|
new "restconf GET http/1.0 - returns 1.0"
|
||||||
|
|
|
||||||
|
|
@ -196,7 +196,7 @@ expectpart "$(curl $CURLOPTS -X GET -H 'Accept: application/yang-data+xml' $RCPR
|
||||||
# But leave it here for debugging where netcat works properly
|
# But leave it here for debugging where netcat works properly
|
||||||
# Alt try something like:
|
# Alt try something like:
|
||||||
# printf "Hello World!" | (exec 3<>/dev/tcp/127.0.0.1/80; cat >&3; cat <&3; exec 3<&-)
|
# printf "Hello World!" | (exec 3<>/dev/tcp/127.0.0.1/80; cat >&3; cat <&3; exec 3<&-)
|
||||||
if [ false -a ! ${WITH_HTTP2} ] ; then
|
if [ false -a ! ${HAVE_LIBNGHTTP2} ] ; then
|
||||||
# Look for netcat or nc for direct socket http calls
|
# Look for netcat or nc for direct socket http calls
|
||||||
if [ -n "$(type netcat 2> /dev/null)" ]; then
|
if [ -n "$(type netcat 2> /dev/null)" ]; then
|
||||||
netcat="netcat -w 1" # -N works on evhtp but not fcgi
|
netcat="netcat -w 1" # -N works on evhtp but not fcgi
|
||||||
|
|
|
||||||
|
|
@ -174,10 +174,9 @@ EOF
|
||||||
new "start backend -s init -f $cfg -- -sS $fstate"
|
new "start backend -s init -f $cfg -- -sS $fstate"
|
||||||
start_backend -s init -f $cfg -- -sS $fstate
|
start_backend -s init -f $cfg -- -sS $fstate
|
||||||
fi
|
fi
|
||||||
|
|
||||||
new "waiting"
|
|
||||||
wait_backend
|
|
||||||
fi
|
fi
|
||||||
|
new "wait backend"
|
||||||
|
wait_backend
|
||||||
|
|
||||||
if [ $RC -ne 0 ]; then
|
if [ $RC -ne 0 ]; then
|
||||||
new "kill old restconf daemon"
|
new "kill old restconf daemon"
|
||||||
|
|
@ -217,7 +216,7 @@ EOF
|
||||||
new "restconf get config"
|
new "restconf get config"
|
||||||
expectpart "$(curl $CURLOPTS -X GET -H "Accept: application/yang-data+xml" $RCPROTO://localhost/restconf/data?content=config)" 0 "HTTP/$HVER 200" "$XML"
|
expectpart "$(curl $CURLOPTS -X GET -H "Accept: application/yang-data+xml" $RCPROTO://localhost/restconf/data?content=config)" 0 "HTTP/$HVER 200" "$XML"
|
||||||
|
|
||||||
# Save partial state in state file with unknown removed (positive test)
|
new "Save partial state with unknowns removed in state file $fstate"
|
||||||
echo "$STATE1" > $fstate
|
echo "$STATE1" > $fstate
|
||||||
|
|
||||||
new "Get state (positive test)"
|
new "Get state (positive test)"
|
||||||
|
|
@ -226,7 +225,7 @@ EOF
|
||||||
new "restconf get state(positive)"
|
new "restconf get state(positive)"
|
||||||
expectpart "$(curl $CURLOPTS -X GET -H "Accept: application/yang-data+xml" $RCPROTO://localhost/restconf/data?content=nonconfig)" 0 "HTTP/$HVER 200" "$STATE1"
|
expectpart "$(curl $CURLOPTS -X GET -H "Accept: application/yang-data+xml" $RCPROTO://localhost/restconf/data?content=nonconfig)" 0 "HTTP/$HVER 200" "$STATE1"
|
||||||
|
|
||||||
# full state with unknowns
|
new "Save full state with unknowns in state file $fstate"
|
||||||
echo "$STATE0" > $fstate
|
echo "$STATE0" > $fstate
|
||||||
|
|
||||||
new "Get state (negative test)"
|
new "Get state (negative test)"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue