From 0eedaa2a2e5fc58789b268fdfc1b05e63dabc36b Mon Sep 17 00:00:00 2001 From: justanothercatgirl Date: Tue, 1 Apr 2025 21:37:43 +0300 Subject: Integrated STE into html generation & cleaned up code --- .gitignore | 5 +++ Makefile | 25 ++++++++++--- README.md | 12 ++++++- c_headers | 2 +- compile_flags.txt | 1 + config.env.default | 1 + favicon.ico | 0 include/common.h | 2 +- jals.db | Bin 16384 -> 0 bytes src/endpoints.c | 90 +++++++++++++++++++++++----------------------- src/main.c | 24 ++++++------- template/args.html.ste | 12 +++++++ template/linkadd.html.ste | 11 ++++++ www/form-test.html | 21 +++++++++++ www/form.html | 21 ----------- www/index.html | 6 ++-- 16 files changed, 143 insertions(+), 90 deletions(-) create mode 100644 config.env.default delete mode 100644 favicon.ico delete mode 100644 jals.db create mode 100644 template/args.html.ste create mode 100644 template/linkadd.html.ste create mode 100644 www/form-test.html delete mode 100644 www/form.html diff --git a/.gitignore b/.gitignore index 81fcc4c..8df7494 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,8 @@ mime.h test/ build/ *.inc +*.db +*.ico +linkadd.html +args.html +config.env diff --git a/Makefile b/Makefile index 372caed..1b71312 100644 --- a/Makefile +++ b/Makefile @@ -3,19 +3,30 @@ GPERF = gperf CC = gcc -CFLAGS += -Ic_headers/include -Iinclude -ggdb -Wall -Wextra -DDEFAULT_ENDPOINTS_PATH=\"./endpoints.so\" BLDDIR ?= build +CFLAGS += -Ic_headers/include -Iinclude -I$(BLDDIR) -ggdb -Wall -Wextra -DDEFAULT_ENDPOINTS_PATH=\"./endpoints.so\" all: $(BLDDIR) endpoints.so main -.PHONY: all clean $(BLDDIR) +.PHONY: all clean run $(BLDDIR): mkdir -p $(BLDDIR) +$(BLDDIR)/template: + mkdir -p $@ + +$(BLDDIR)/ste: c_headers/ste/ste.c + $(CC) -o $@ $< + + +$(BLDDIR)/template/%: template/%.ste $(BLDDIR)/ste $(BLDDIR)/template + $(BLDDIR)/ste -o $@ $< + # endpoints -$(BLDDIR)/endpoints.o: src/endpoints.c $(BLDDIR)/rename.ld $(BLDDIR) +$(BLDDIR)/endpoints.o: src/endpoints.c $(BLDDIR) \ + $(BLDDIR)/template/args.html $(BLDDIR)/template/linkadd.html # PIC here is important $(CC) -fPIC -c $< $(CFLAGS) -o $@ @@ -47,4 +58,10 @@ main: $(BLDDIR)/main.o $(BLDDIR)/mime.o $(BLDDIR)/common.o $(CC) $(CFLAGS) $^ -ldl -lmicrohttpd -lsqlite3 -o $@ clean: - $(RM) $(BLDDIR)/* main endpoints.o endpoints.so rename.ld include/mime.h.inc + $(RM) --recursive $(BLDDIR)/template/* $(BLDDIR)/* main endpoints.o endpoints.so rename.ld include/mime.h.inc + +veryclean: clean + $(RM) jals.db config.env + +run: main endpoints.so + env $(shell cat config.env) ./main diff --git a/README.md b/README.md index ca47fd4..dd4b35b 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,7 @@ chroot environment, who knows. # Features * Will try to process URLs in this order: + 0. Checks if API endpoint exists at that URL, and if it does, and executes it. 0. Checks if URL is a shortened link name, and if it is, redirects there. 0. Tries to send a file at the location pointed to by URL (relative to @@ -18,6 +19,7 @@ chroot environment, who knows. 0. Tries to format file like this: `www/{URL}.html` and display the page \[e.g. `/docs` -> `www/docs.html`\] 0. Returns 404 + * \[In future\]: uses `inotify` to track changes in `endpoints.so` and reload it * \[In future\]: `SIGUSR1` makes it reload `endpoints.so` @@ -26,6 +28,7 @@ Pretty small. See [html docs page](www/docs.html). # Build ## Requirements +0. `make` 0. `gperf` 0. `cc` 0. linker that supports `.ld` scripts @@ -36,8 +39,15 @@ all of the paths can be configured in [`Makefile`](Makefile) ## Steps `make` +# Run +0. Copy `config.env.default` to `config.env`, change environment variables in +there to match your needs +0. `make run`, or `env $(cat config.env) ./main`, or `. config.env && ./main`, +whichever fits your needs the most. + # License -AGPL. Sorry fellas, gotta stay free (as in "freedom"). +AGPL. Sorry fellas, gotta stay free (as in "freedom"). Also, +[sorry, google employees](https://opensource.google/documentation/reference/patching#forbidden) # Contributing [my email](mailto:sotov@twistea.su) diff --git a/c_headers b/c_headers index 08b786a..588976a 160000 --- a/c_headers +++ b/c_headers @@ -1 +1 @@ -Subproject commit 08b786a6770c172f433e28b0eb1e893f4fbae40a +Subproject commit 588976a9a16eaa0f1b694587b459b2b264e5fe49 diff --git a/compile_flags.txt b/compile_flags.txt index 5feac12..d8044a7 100644 --- a/compile_flags.txt +++ b/compile_flags.txt @@ -1,2 +1,3 @@ -Ic_headers/include -Iinclude +-Ibuild diff --git a/config.env.default b/config.env.default new file mode 100644 index 0000000..1af9713 --- /dev/null +++ b/config.env.default @@ -0,0 +1 @@ +HTTPHOSTNAME=http://localhost diff --git a/favicon.ico b/favicon.ico deleted file mode 100644 index e69de29..0000000 diff --git a/include/common.h b/include/common.h index 539ba3a..81b4ca2 100644 --- a/include/common.h +++ b/include/common.h @@ -6,7 +6,7 @@ #include #include -typedef struct MHD_Response*(*endpoint)(struct MHD_Connection*, int *status); +typedef struct MHD_Response*(*endpoint)(const char *method, struct MHD_Connection*, int *status); typedef char *(*query_func)(const char *path); char *duplicate(const char *x); diff --git a/jals.db b/jals.db deleted file mode 100644 index fdd26d0..0000000 Binary files a/jals.db and /dev/null differ diff --git a/src/endpoints.c b/src/endpoints.c index 8d1c05f..a4ac35a 100644 --- a/src/endpoints.c +++ b/src/endpoints.c @@ -8,25 +8,30 @@ #include +#include "common.h" +#include "sql.h" #include #define CONTAINER_IMPLEMENTATION #define JACSON_IMPLEMENTATION #define JACSON_EXPORT_RSNPRINTF #include - -#include "common.h" -#include "sql.h" +#define STRINGBUILDER_IMPLEMENTATION +#include + +#define OUT(arg) jac_sb_append_buf(&resp, arg) + +#define REQUIRE_METHOD(methodvar, methodstr, statusp) \ +do { \ + if (strcmp((methodvar), (methodstr)) != 0) { \ + *statusp = MHD_HTTP_METHOD_NOT_ALLOWED; \ + return NULL; \ + } \ +} while (0) const char *const JSON_ERROR = "{\"error\":\"%s\"}"; const char *const HTML_ERROR = "Error: %s"; -const char *const INSUFFICIENT_ARGUMENTS = "insufficient arguments"; -const char *const INVALID_ARGUMENTS = "invalid arguments"; -const char *const OCCUPIED = "occupied"; -const char *const SERVER_ERRORMSG = "server error"; -const char *const UNKNOWN = "unknown"; -const char *const HTML_PROLOGUE = ""; -const char *const HTML_EPILOGUE = ""; +const char *HTTPHOSTNAME = "http://127.0.0.1:80"; struct global_args { enum { @@ -43,19 +48,6 @@ static const struct fmt_const fmts[] = { [GA_FMT_HTML] = {HTML_ERROR,"text/html"} }; -// string builder -struct sb { - char* str; - size_t sz; - size_t ln; -}; - -size_t sbprintf(struct sb* s, const char* fmt, ...) { - va_list l; - va_start(l, fmt); - return s->ln += __jacson_vrsnprintf(&s->str, &s->sz, s->ln, fmt, l); -} - struct global_args parse_global_args(struct MHD_Connection *connection) { const char* key, *val; struct global_args ret = { .format = GA_FMT_JSON }; @@ -65,62 +57,68 @@ struct global_args parse_global_args(struct MHD_Connection *connection) { return ret; } +void init(const char *db) { + sqlite_init(db); + const char *new_httphostname = getenv("HTTPHOSTNAME"); + if (new_httphostname) HTTPHOSTNAME = new_httphostname; +} + // index, path: / struct MHD_Response *ENDP_(struct MHD_Connection* connection, int *status) { return get_from_file("www/index.html"); } enum MHD_Result arg_builder (void *cls, enum MHD_ValueKind kind, const char *key, const char *value) { - struct sb *html = cls; - html->ln += __jacson_rsnprintf(&html->str, &html->sz, html->ln, "
  • %s: %s

  • ", key, value); + jac_sb *html = cls; + jac_sb_snprintf(html, "
  • %s: %s

  • ", key, value ? value : "<none>"); return MHD_YES; } // path: /getargs -struct MHD_Response *ENDP_getargs(struct MHD_Connection *connection, int *status) { - struct sb html = {calloc(64, 1), 63, 0}; - html.ln += __jacson_rsnprintf(&html.str, &html.sz, html.ln, - "

    List of arguments

      "); - MHD_get_connection_values(connection, MHD_GET_ARGUMENT_KIND, &arg_builder, &html); - html.ln += __jacson_rsnprintf(&html.str, &html.sz, html.ln, "
    "); - const char *val = MHD_lookup_connection_value(connection, MHD_GET_ARGUMENT_KIND, "test"); - if (val) LDEBUGVF(stderr, "test = %s\n", val); - LDEBUGVF(stderr, "test pointer = %p", val); - return MHD_create_response_from_buffer(html.ln, html.str, MHD_RESPMEM_MUST_FREE); +struct MHD_Response *ENDP_getargs(const char *method, struct MHD_Connection *connection, int *status) { + jac_sb resp = jac_sb_new(64); +# include "template/args.html" + return MHD_create_response_from_buffer(resp.size, resp.data, MHD_RESPMEM_MUST_FREE); } // API, path: /api/linkadd -struct MHD_Response *ENDP_api_linkadd(struct MHD_Connection *connection, int *status) { +struct MHD_Response *ENDP_api_linkadd(const char *method, struct MHD_Connection *connection, int *status) { + REQUIRE_METHOD(method, "GET", status); const char *url = NULL, *path = NULL; char newurl[12] = {0}, *newurlp = newurl; - struct sb resp = {malloc(64), 63, 0}; + jac_sb resp = jac_sb_new(64); struct global_args glob = parse_global_args(connection); struct MHD_Response *response; if ((url = MHD_lookup_connection_value(connection, MHD_GET_ARGUMENT_KIND, "url")) == NULL || *url == '\0') { *status = db_error_status(DBERROR_ARGS); - sbprintf(&resp, fmts[glob.format].error, INSUFFICIENT_ARGUMENTS); + jac_sb_snprintf(&resp, fmts[glob.format].error, db_error(DBERROR_ARGS)); goto exit; } path = MHD_lookup_connection_value(connection, MHD_GET_ARGUMENT_KIND, "try"); - if (*path == '\0') path = NULL; + if (path && *path == '\0') path = NULL; enum dberror err; if ((err = db_add_url(url, path, &newurlp)) != DBERROR_SUCCESS) { LWARNVF("Database write failed with error %i. Sql error: %s", err, sqlite3_errmsg(state.db)); *status = db_error_status(err); - sbprintf(&resp, fmts[glob.format].error, db_error(err)); + jac_sb_snprintf(&resp, fmts[glob.format].error, db_error(err)); goto exit; } - if (glob.format == GA_FMT_JSON) sbprintf(&resp, "{\"url\":\"%s\"}", newurlp); - else sbprintf(&resp, "%sYour URL: /%s%s", HTML_PROLOGUE, newurlp, newurlp, HTML_EPILOGUE); + if (glob.format == GA_FMT_JSON) + jac_sb_snprintf(&resp, "{\"url\":\"%s\"}", newurlp); + else if (glob.format == GA_FMT_HTML) { +# include "template/linkadd.html" + } exit: - response = MHD_create_response_from_buffer(resp.ln, resp.str, MHD_RESPMEM_MUST_FREE); + response = MHD_create_response_from_buffer(resp.size, resp.data, MHD_RESPMEM_MUST_FREE); MHD_add_response_header(response, "Content-Type", fmts[glob.format].content_type); return response; } // API, path: /api/linkdel -struct MHD_Response *ENDP_api_linkdel(struct MHD_Connection *connection, int *status) { - +struct MHD_Response *ENDP_api_linkdel(const char *method, struct MHD_Connection *connection, int *status) { + return MHD_create_response_from_buffer(4, "TODO", MHD_RESPMEM_PERSISTENT); } // API, path: /api/linkget -struct MHD_Response *ENDP_api_linkget(struct MHD_Connection *connection, int *status) { } +struct MHD_Response *ENDP_api_linkget(const char *method, struct MHD_Connection *connection, int *status) { + return MHD_create_response_from_buffer(4, "TODO", MHD_RESPMEM_PERSISTENT); +} diff --git a/src/main.c b/src/main.c index 431a9a7..67c4559 100644 --- a/src/main.c +++ b/src/main.c @@ -49,7 +49,7 @@ enum MHD_Result process_connection(void *cls, struct MHD_Connection *connection, } else if (handler != NULL) { /* endpoint access */ LINFOF("Accessed endpoint at url %s", url); - res = handler(connection, &status); + res = handler(method, connection, &status); } else if ((newurl = arg->query(url + 1)) != NULL) { LINFOF("Redirect from %s to %s", url, newurl); response = "Recirecting..."; @@ -85,8 +85,8 @@ void reload_dylib(const char *so_path, const char *db_path) { if (!arg.dylib) LCRITVF(1, "Could not open dynamic library: %s\n", dlerror()); arg.query = dlsym(arg.dylib, "db_get_url"); if (!arg.query) LCRITVF(1, "Could not load `db_get_url` from shared library: %s", dlerror()); - arg.constructor = dlsym(arg.dylib, "sqlite_init"); - if (!arg.constructor) LCRITVF(1, "Could not load `sqlite_init` from shared library: %s", dlerror()); + arg.constructor = dlsym(arg.dylib, "init"); + if (!arg.constructor) LCRITVF(1, "Could not load `init` from shared library: %s", dlerror()); arg.constructor(db_path); arg.destructor = dlsym(arg.dylib, "sqlite_deinit"); if (!arg.destructor) LCRITVF(1, "Could not load `sqlite_deinit` from shared library: %s", dlerror()); @@ -118,15 +118,15 @@ int main(int argc, char *argv[]) { const char *dlpath = DEFAULT_ENDPOINTS_PATH; const char *dbpath = DEFAULT_DATABASE_PATH; struct MHD_Daemon *daemon = init(&sig, dlpath, dbpath); - /* while (reload_library == 0) { */ - /* sigsuspend(&sig); */ - /* if (reload_library == 1) { */ - /* reload_dylib(dlpath, dbpath); */ - /* reload_library = 0; */ - /* } */ - /* } */ - getchar(); - if (arg.destructor) arg.destructor(); + while (reload_library == 0) { + sigsuspend(&sig); + if (reload_library == 1) { + reload_dylib(dlpath, dbpath); + reload_library = 0; + } + } + getchar(); /* to be replaced with fork later */ + arg.destructor(); dlclose(arg.dylib); MHD_stop_daemon(daemon); return 0; diff --git a/template/args.html.ste b/template/args.html.ste new file mode 100644 index 0000000..965c06b --- /dev/null +++ b/template/args.html.ste @@ -0,0 +1,12 @@ + + + + + + +

    List of arguments

    +
      + %MHD_get_connection_values(connection, MHD_GET_ARGUMENT_KIND, &arg_builder, &resp);% +
    + + diff --git a/template/linkadd.html.ste b/template/linkadd.html.ste new file mode 100644 index 0000000..7fe3db3 --- /dev/null +++ b/template/linkadd.html.ste @@ -0,0 +1,11 @@ + + + + + + +

    Your URL: + %OUT(HTTPHOSTNAME);%/%OUT(newurlp);% +

    + + diff --git a/www/form-test.html b/www/form-test.html new file mode 100644 index 0000000..79eb7b1 --- /dev/null +++ b/www/form-test.html @@ -0,0 +1,21 @@ + + + + + +
    +
    + + +
    +
    + + +
    + + +
    + +

    For API documentation, go to documentation page

    -- cgit v1.2.3-70-g09d2