[TEMP] save

This commit is contained in:
Tobias Waldekranz
2023-04-12 09:36:50 +02:00
parent 7eec8c2964
commit 964a4c755e
4 changed files with 399 additions and 36 deletions
+2 -1
View File
@@ -17,8 +17,9 @@ AC_PROG_INSTALL
# Check for pkg-config first, warn if it's not installed
PKG_PROG_PKG_CONFIG
PKG_CHECK_MODULES([sysrepo], [sysrepo >= 2.2.36])
PKG_CHECK_MODULES([fcgi], [fcgi >= 2.4.2])
PKG_CHECK_MODULES([sysrepo], [sysrepo >= 2.2.36])
PKG_CHECK_MODULES([libyang], [libyang >= 2.1.55])
# Plugin installation path for sysrepo-plugind
dnl PKG_CHECK_VAR([srpdplugindir], [sysrepo], [SRPD_PLUGINS_PATH])
+2 -2
View File
@@ -2,5 +2,5 @@ sbin_PROGRAMS = sysrest
sysrest_SOURCES = main.c
sysrest_CFLAGS = -Wall -Wextra -Werror -Wno-unused-parameter \
$(sysrepo_CFLAGS) $(fcgi_CFLAGS)
sysrest_LDADD = $(sysrepo_LIBS) $(fcgi_LIBS)
$(libyang_CFLAGS) $(sysrepo_CFLAGS) $(fcgi_CFLAGS)
sysrest_LDADD = $(libyang_LIBS) $(sysrepo_LIBS) $(fcgi_LIBS)
+290 -33
View File
@@ -9,8 +9,120 @@
#include <fcgiapp.h>
#include <libyang/libyang.h>
#include <libyang/plugins_exts.h>
#include <sysrepo.h>
#include <sysrepo_types.h>
static const char *rootpath = "/restconf/";
enum http_method {
HTTP_GET,
HTTP_HEAD,
HTTP_PATCH,
HTTP_POST,
HTTP_PUT,
HTTP_INVALID
};
/* struct memstream { */
/* FILE *fp; */
/* char *buf; */
/* size_t len; */
/* }; */
/* struct res { */
/* struct memstream head; */
/* struct memstream entity; */
/* }; */
/* int res_push_header(struct res *res, const char *key, const char *valfmt, ...) */
/* { */
/* fprintf */
/* } */
/* int res_respond_to(struct res *res, FCGX_Request *req) */
/* { */
/* } */
/* int res_init(struct res *res) */
/* { */
/* res->head.fp = open_memstream(&res->head.buf, &res->head.len); */
/* if (!res->head.fp) */
/* goto err; */
/* res->entity.fp = open_memstream(&res->entity.buf, &res->entity.len); */
/* if (!res->entity.fp) */
/* goto err_free_head; */
/* return 0; */
/* err_free_head: */
/* fclose(res->head.fp); */
/* err: */
/* return -ENOMEM; */
/* } */
struct req {
FCGX_Request r;
enum http_method method;
char *uri;
union {
struct {
char *path;
} data;
};
};
static enum http_method req_parse_method(struct req *req)
{
const char *str = FCGX_GetParam("REQUEST_METHOD", req->r.envp);
if (!str)
return HTTP_INVALID;
if (!strcmp(str, "GET"))
return HTTP_GET;
if (!strcmp(str, "HEAD"))
return HTTP_HEAD;
if (!strcmp(str, "PATCH"))
return HTTP_PATCH;
if (!strcmp(str, "POST"))
return HTTP_POST;
if (!strcmp(str, "PUT"))
return HTTP_PUT;
return HTTP_INVALID;
}
static int req_init(struct req *req)
{
const char *uri;
req->method = req_parse_method(req);
uri = FCGX_GetParam("REQUEST_URI", req->r.envp);
if (!uri)
return -EINVAL;
req->uri = strdup(uri);
if (!req->uri)
return -EINVAL;
return 0;
}
static int req_fini(struct req *req)
{
free(req->uri);
return 0;
}
static void dumpenv(char **envp)
{
fprintf(stderr, "ENV:\n");
@@ -19,16 +131,19 @@ static void dumpenv(char **envp)
}
}
int serve_host_meta(FCGX_Request *req)
int serve_host_meta(struct req *req)
{
const char *method;
size_t len;
char *buf;
FILE *fp;
method = FCGX_GetParam("REQUEST_METHOD", req->envp);
if (!method || (strcmp(method, "GET") && strcmp(method, "HEAD")))
switch (req->method) {
case HTTP_GET:
case HTTP_HEAD:
break;
default:
return -EINVAL;
}
fp = open_memstream(&buf, &len);
if (!fp)
@@ -40,61 +155,203 @@ int serve_host_meta(FCGX_Request *req)
"</XRD>", rootpath);
fclose(fp);
FCGX_FPrintF(req->out, "Content-Type: application/xrd+xml\r\n");
FCGX_FPrintF(req->out, "Content-Length: %zd\r\n", len);
FCGX_FPrintF(req->out, "Connection: close\r\n");
FCGX_PutS("\r\n", req->out);
FCGX_FPrintF(req->r.out, "Content-Type: application/xrd+xml\r\n");
FCGX_FPrintF(req->r.out, "Content-Length: %zd\r\n", len);
FCGX_FPrintF(req->r.out, "Connection: close\r\n");
FCGX_PutS("\r\n", req->r.out);
if (!strcmp(method, "GET"))
FCGX_PutStr(buf, len, req->out);
if (req->method == HTTP_GET)
FCGX_PutStr(buf, len, req->r.out);
free(buf);
FCGX_Finish_r(req);
FCGX_Finish_r(&req->r);
return 0;
}
int serve_restconf(FCGX_Request *req)
int hex2bin(char *hex)
{
FCGX_FPrintF(req->out, "Content-type: text/html\r\n\r\n");
FCGX_FPrintF(req->out, "RESTCONF\r\n");
FCGX_Finish_r(req);
int i, out;
for (i = 0, out = 0; i < 2; i++) {
out <<= 4;
if (hex[i] >= '0' && hex[i] <= '9')
out |= hex[0] - '0';
else if (hex[i] >= 'a' && hex[i] <= 'f')
out |= hex[0] - 'a';
else if (hex[i] >= 'A' && hex[i] <= 'F')
out |= hex[0] - 'A';
else
return -EINVAL;
}
if (out < 0 || out >= 0x80)
/* No UTF-8 support */
return -EINVAL;
return out;
}
int unpercent(char *tok)
{
char *in, *out, *end;
int escaped;
in = out = tok;
for (; *in; in++, out++) {
if (*in != '%') {
*out = *in;
continue;
}
escaped = hex2bin(in + 1);
if (escaped < 0)
return escaped;
*out = escaped;
in += 2;
}
*out = '\0';
return 0;
}
int xpath_from_uri(struct ly_ctx *ly, char *uri, char **xpathp)
{
}
int uri_resolve_r(sr_data_t **nodep, char **urip, char **toksave)
{
char *tok;
int err;
tok = strtok_r(*toksave ? NULL : *urip, "/", toksave);
if (!tok)
return 0;
err = unpercent(tok);
if (err)
return err;
}
int uri_resolve(sr_session_ctx_t *sess, char *uri, struct lyd_node **nodep)
{
sr_data_t *node;
char *toksave = NULL;
int err;
err = sr_get_subtree(sess, "/", 0, &node);
if (err)
return err;
err = uri_resolve_r(&node, &uri, &toksave);
if (err)
return err;
tok = srst_uritok(uri);
if (!tok)
return 0;
}
int serve_restconf_data(struct req *req)
{
sr_session_ctx_t *sess;
sr_conn_ctx_t *conn;
sr_data_t *data;
int err = 0;
FILE *fp;
char *buf;
size_t len = 0;
if (req->method != HTTP_GET) {
err = -EINVAL;
goto err;
}
if (sr_connect(SR_CONN_DEFAULT, &conn)) {
err = -EIO;
goto err;
}
if (sr_session_start(conn, SR_DS_RUNNING, &sess)) {
err = -EIO;
goto err_disconnect;
}
sr_get_data(sess, req->data.path, 0, 0, 0, &data);
fp = open_memstream(&buf, &len);
lyd_print_file(fp, data ? data->tree : NULL, LYD_JSON, LYD_PRINT_WITHSIBLINGS);
fclose(fp);
FCGX_FPrintF(req->r.out, "Content-Type: application/yang-data+json\r\n");
FCGX_FPrintF(req->r.out, "Content-Length: %zd\r\n", len);
FCGX_FPrintF(req->r.out, "Connection: close\r\n");
FCGX_PutS("\r\n", req->r.out);
FCGX_PutStr(buf, len, req->r.out);
free(buf);
FCGX_Finish_r(&req->r);
return 0;
err_disconnect:
sr_disconnect(conn);
err:
return err;
}
int serve_restconf(struct req *req)
{
char *uri = req->uri + strlen(rootpath);
if (!strncmp(uri, "data/", strlen("data/"))) {
req->data.path = uri + strlen("data/");
return serve_restconf_data(req);
}
return -EINVAL;
}
int serve(int sd)
{
FCGX_Request req;
const char *uri;
struct req req;
int err = 0;
for (FCGX_InitRequest(&req, sd, 0);
FCGX_Accept_r(&req) == 0;
FCGX_InitRequest(&req, sd, 0)) {
dumpenv(req.envp);
uri = FCGX_GetParam("REQUEST_URI", req.envp);
if (!uri)
for (FCGX_InitRequest(&req.r, sd, 0);
FCGX_Accept_r(&req.r) == 0;
FCGX_InitRequest(&req.r, sd, 0)) {
if (req_init(&req))
continue;
if (!strcmp(uri, "/.well-known/host-meta"))
dumpenv(req.r.envp);
if (!strcmp(req.uri, "/.well-known/host-meta"))
err = serve_host_meta(&req);
else if (!strncmp(uri, rootpath, strlen(rootpath)))
else if (!strncmp(req.uri, rootpath, strlen(rootpath)))
err = serve_restconf(&req);
else
err = -EINVAL;
if (err) {
FCGX_FPrintF(req.out, "Status: 400 Bad Request\r\n");
FCGX_FPrintF(req.out, "Content-Type: text/html\r\n");
FCGX_FPrintF(req.out, "Connection: close\r\n");
FCGX_PutS("\r\n", req.out);
FCGX_Finish_r(&req);
break;
FCGX_FPrintF(req.r.out, "Status: 400 Bad Request\r\n");
FCGX_FPrintF(req.r.out, "Content-Type: text/html\r\n");
FCGX_FPrintF(req.r.out, "Connection: close\r\n");
FCGX_PutS("\r\n", req.r.out);
FCGX_Finish_r(&req.r);
}
req_fini(&req);
}
FCGX_Free(&req, sd);
FCGX_Free(&req.r, sd);
if (err)
fprintf(stderr, "Unable to handle request: %d\n", err);
+105
View File
@@ -0,0 +1,105 @@
#include <errno.h>
#include <grp.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <libyang/libyang.h>
int hex2bin(char *hex)
{
int i, out;
for (i = 0, out = 0; i < 2; i++) {
out <<= 4;
if (hex[i] >= '0' && hex[i] <= '9')
out |= hex[0] - '0';
else if (hex[i] >= 'a' && hex[i] <= 'f')
out |= hex[0] - 'a';
else if (hex[i] >= 'A' && hex[i] <= 'F')
out |= hex[0] - 'A';
else
return -EINVAL;
}
if (out < 0 || out >= 0x80)
/* No UTF-8 support */
return -EINVAL;
return out;
}
int unpercent(char *text)
{
char *in, *out, *end;
int escaped;
in = out = text;
for (; *in; in++, out++) {
if (*in != '%') {
*out = *in;
continue;
}
escaped = hex2bin(in + 1);
if (escaped < 0)
return escaped;
*out = escaped;
in += 2;
}
*out = '\0';
return 0;
}
struct uri_node {
char *module;
char *name;
char *keyv[8];
};
int uri_node_from_seg(char *seg, struct uri_node *n)
{
int keyc = 0;
char *delim;
memset(n, 0, sizeof(*n));
delim = strchr(seg, ':');
if (delim) {
*delim++ = '\0';
n->module = seg;
n->name = seg = delim;
} else {
n->name = seg;
}
delim = strchr(seg, '=');
if (!delim)
return 0;
do {
if (keyc >= 7)
return -EINVAL;
*delim++ = '\0';
n->keyv[keyc++] = seg = delim;
} while ((delim = strchr(seg, ','); keyc++));
return 0;
}
int xpath_from_uri(struct ly_ctx *ly, char *uri, char **xpathp)
{
}
int main(void)
{
}