diff options
-rw-r--r-- | .gitignore | 5 | ||||
-rw-r--r-- | Makefile | 25 | ||||
-rw-r--r-- | README.md | 12 | ||||
m--------- | c_headers | 0 | ||||
-rw-r--r-- | compile_flags.txt | 1 | ||||
-rw-r--r-- | config.env.default | 1 | ||||
-rw-r--r-- | favicon.ico | 0 | ||||
-rw-r--r-- | include/common.h | 2 | ||||
-rw-r--r-- | jals.db | bin | 16384 -> 8192 bytes | |||
-rw-r--r-- | src/endpoints.c | 80 | ||||
-rw-r--r-- | src/main.c | 20 | ||||
-rw-r--r-- | template/args.html.ste | 12 | ||||
-rw-r--r-- | template/linkadd.html.ste | 11 | ||||
-rw-r--r-- | www/form-test.html (renamed from www/form.html) | 0 | ||||
-rw-r--r-- | www/index.html | 6 |
15 files changed, 110 insertions, 65 deletions
@@ -6,3 +6,8 @@ mime.h test/ build/ *.inc +*.db +*.ico +linkadd.html +args.html +config.env @@ -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 + +run: main endpoints.so + env $(shell cat config.env) ./main @@ -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 -Subproject 08b786a6770c172f433e28b0eb1e893f4fbae40 +Subproject 588976a9a16eaa0f1b694587b459b2b264e5fe4 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 --- a/favicon.ico +++ /dev/null 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 <fcntl.h> #include <sys/stat.h> -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); Binary files differdiff --git a/src/endpoints.c b/src/endpoints.c index 8d1c05f..d8efb0c 100644 --- a/src/endpoints.c +++ b/src/endpoints.c @@ -8,25 +8,30 @@ #include <microhttpd.h> +#include "common.h" +#include "sql.h" #include <log.h> #define CONTAINER_IMPLEMENTATION #define JACSON_IMPLEMENTATION #define JACSON_EXPORT_RSNPRINTF #include <jacson.h> - -#include "common.h" -#include "sql.h" +#define STRINGBUILDER_IMPLEMENTATION +#include <stringbuilder.h> + +#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 = "<!DOCTYPE html><html><body>Error: %s</body></html>"; -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 = "<!DOCTYPE html><html><head><meta charset=\"utf-8\"></head><body>"; -const char *const HTML_EPILOGUE = "</html></body>"; +const char *HTTPHOSTNAME = "http://127.0.0.1"; 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 }; @@ -71,56 +63,54 @@ struct MHD_Response *ENDP_(struct MHD_Connection* connection, int *status) { } 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, "<li><p style=\"font-style:monospace;\">%s: %s</p></li>", key, value); + jac_sb *html = cls; + jac_sb_snprintf(html, "<li><p style=\"font-style:monospace;\">%s: %s</p></li>", 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, - "<!DOCTYPE html><html><head><meta charset=\"utf-8\"></head><body><h3>List of arguments</h3><ol>"); - MHD_get_connection_values(connection, MHD_GET_ARGUMENT_KIND, &arg_builder, &html); - html.ln += __jacson_rsnprintf(&html.str, &html.sz, html.ln, "</ol></body></html>"); - 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: <a href=\"/%s\">/%s</a>%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) { } // 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) { } @@ -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 = "<!DOCTYPE html><html><body>Recirecting...</body></html>"; @@ -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 @@ +<!DOCTYPE html> +<html> + <head> + <meta charset="utf-8"> + </head> + <body> + <h3> List of arguments </h3> + <ol> + %MHD_get_connection_values(connection, MHD_GET_ARGUMENT_KIND, &arg_builder, &resp);% + </ol> + </body> +</html> 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 @@ +<!DOCTYPE html><html> + <head> + <meta charset="utf-8"/> + <style>*{margin:0;padding:0;text-align:center;}</style> + </head> + <body> + <p> Your URL: + <a href="/%OUT(newurlp);%">%OUT(HTTPHOSTNAME);%/%OUT(newurlp);%</a> + </p> + </body> +</html> diff --git a/www/form.html b/www/form-test.html index 79eb7b1..79eb7b1 100644 --- a/www/form.html +++ b/www/form-test.html diff --git a/www/index.html b/www/index.html index ed48fc5..973c32b 100644 --- a/www/index.html +++ b/www/index.html @@ -12,10 +12,9 @@ <title>JAC's link shortener</title> </head> <body> - <div> <h1>Just another link shortener</h1> <p>Try it out!</p> - <form action="/api/linkadd" target="result"> + <form action="/api/linkadd" target="result" accept-charset="utf-8"> <div> <label>URL:</label> <input type="url"name="url"required/> @@ -28,8 +27,7 @@ <input type="submit"value="Shorten URL!"/> </form> <h3>Result:</h3> - <iframe name="result"scrolling="no"/> - </div> + <iframe name="result"scrolling="no"></iframe> <p> For API documentation, go to <a href="/docs">documentation page</a></p> </body> </html> |