diff options
author | justanothercatgirl <sotov@twistea.su> | 2025-03-27 12:52:11 +0300 |
---|---|---|
committer | justanothercatgirl <sotov@twistea.su> | 2025-03-27 12:52:11 +0300 |
commit | 82742d5d13dc7b0691a79c79f8e62782fcb16e10 (patch) | |
tree | 48d077549ed667d2a54171b82eb7608cb8edaf3e | |
parent | 8542ec17d3df989f3df9fd03af7a447bf730dc13 (diff) |
Doing SQL (work in progress)
-rw-r--r-- | .gitignore | 4 | ||||
-rw-r--r-- | Makefile | 47 | ||||
-rw-r--r-- | README.md | 47 | ||||
m--------- | c_headers | 0 | ||||
-rw-r--r-- | compile_flags.txt | 1 | ||||
-rw-r--r-- | endpoints.c | 42 | ||||
-rw-r--r-- | include/common.h | 15 | ||||
-rw-r--r-- | include/sql.h | 6 | ||||
-rw-r--r-- | main.c | 50 | ||||
-rw-r--r-- | src/common.c | 40 | ||||
-rw-r--r-- | src/endpoints.c | 195 | ||||
-rw-r--r-- | src/main.c | 104 | ||||
-rw-r--r-- | src/mime.c | 9 | ||||
-rw-r--r-- | src/mime_gen.c.gperf | 992 | ||||
-rw-r--r-- | src/sql.c | 13 | ||||
-rw-r--r-- | www/docs.html | 116 | ||||
-rw-r--r-- | www/form.html | 21 | ||||
-rw-r--r-- | www/index.html | 32 |
18 files changed, 1629 insertions, 105 deletions
@@ -2,3 +2,7 @@ *.o rename.ld main +mime.h +test/ +build/ +*.inc @@ -1,26 +1,47 @@ # Makefile -CFLAGS += -Ic_headers/include +GPERF = gperf +CC = cc -all: main endpoints.so +CFLAGS += -Ic_headers/include -Iinclude -ggdb +BLDDIR ?= build -.PHONY: all clean +all: $(BLDDIR) endpoints.so main -endpoints.o: endpoints.c - $(CC) -c $< $(CFLAGS) -o $@ +.PHONY: all clean $(BLDDIR) -rename.ld: endpoints.o +$(BLDDIR): + mkdir -p $(BLDDIR) + + +# endpoints +$(BLDDIR)/endpoints.o: src/endpoints.c $(BLDDIR)/rename.ld $(BLDDIR) + # PIC here is important + $(CC) -fPIC -c $< $(CFLAGS) -o $@ + +$(BLDDIR)/rename.ld: $(BLDDIR)/endpoints.o $(BLDDIR) # Looks terrible - # All it does it generates renaming + # All it does is generating ld script that creates aliases for functions echo SECTIONS { > $@ - @readelf --syms endpoints.o | awk '/FUNC/ && /GLOBAL/ {printf "\t%s = %s;\n", gensub(/_/, "/", "g", $$8), $$8;}' >> $@ + @readelf --syms --wide $(BLDDIR)/endpoints.o | awk '/FUNC/ && /GLOBAL/ && /ENDP/ {old = $$8; gsub(/_/, "/", $$8); gsub(/ENDP/, "", $$8); printf "\t%s = %s;\n", $$8, old }' >> $@ echo } >> $@ -endpoints.so: endpoints.o rename.ld - $(CC) -shared -Wl,rename.ld $< -fPIE -o $@ +endpoints.so: $(BLDDIR)/endpoints.o $(BLDDIR)/common.o $(BLDDIR)/mime.o + $(CC) -shared -fPIE -Wl,$(BLDDIR)/rename.ld $^ -lmicrohttpd -o $@ + + +# main +src/mime.c.inc: src/mime_gen.c.gperf + $(GPERF) -IGCt -K key -H __mimetype_hash -N __mimetype_get_helper -W mimetype_words $< > $@ + +$(BLDDIR)/mime.o: src/mime.c src/mime.c.inc + $(CC) -c $(CFLAGS) -o $@ $< + +$(BLDDIR)/%.o: src/%.c + $(CC) -c $(CFLAGS) -o $@ $^ -main: main.c - $(CC) $< $(CFLAGS) -ldl -lmicrohttpd -o $@ +main: $(BLDDIR)/main.o $(BLDDIR)/mime.o $(BLDDIR)/common.o + $(CC) $(CFLAGS) $^ -ldl -lmicrohttpd -lsqlite3 -o $@ clean: - $(RM) main endpoints.o endpoints.so rename.ld + $(RM) $(BLDDIR)/* main endpoints.o endpoints.so rename.ld include/mime.h.inc diff --git a/README.md b/README.md new file mode 100644 index 0000000..ca47fd4 --- /dev/null +++ b/README.md @@ -0,0 +1,47 @@ +# What is this? +This is a URL shortener, a sort of a backend project practice. It uses GNU's +`libmicrohttpd` and `sqlite3` the database. The reason for me chosing +`libmicrohttpd` is simple: it's lightweight and does not have too much magic. +The reason for me chosing `sqlite` as a database is even simpler: it's fucking +based. + +Sadly, I think I might want to run this inside a docker container on my server, +because it's C after and I'm no expect on security. Maybe I'll run it in a +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 + executable's location). +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` + +# API +Pretty small. See [html docs page](www/docs.html). + +# Build +## Requirements +0. `gperf` +0. `cc` +0. linker that supports `.ld` scripts +0. `libmicrohttpd` installed with headers available. +0. `sqlite` installed with headers available. +0. git submodules cloned ([c\_headers](https://git.twistea.su/cgit/c_headers)) +all of the paths can be configured in [`Makefile`](Makefile) +## Steps +`make` + +# License +AGPL. Sorry fellas, gotta stay free (as in "freedom"). + +# Contributing +[my email](mailto:sotov@twistea.su) + +I highly doubt that anyone whould contribute to this meme of a project, but you +know better, so mail me if you want. I accept modifications in code as tar'ed +archives of git repos. diff --git a/c_headers b/c_headers -Subproject 1c857416928744d359bc3fc63cd765219bf0cb1 +Subproject 08b786a6770c172f433e28b0eb1e893f4fbae40 diff --git a/compile_flags.txt b/compile_flags.txt index 64a88c8..5feac12 100644 --- a/compile_flags.txt +++ b/compile_flags.txt @@ -1 +1,2 @@ -Ic_headers/include +-Iinclude diff --git a/endpoints.c b/endpoints.c deleted file mode 100644 index 789f48a..0000000 --- a/endpoints.c +++ /dev/null @@ -1,42 +0,0 @@ -#include <stdlib.h> -#include <string.h> - -#include "microhttpd.h" - -#define CONTAINER_IMPLEMENTATION -#define JACSON_IMPLEMENTATION -#include <jacson.h> - -// not accessible in browser because ALL URLs start with / (or with _ in dylib) -char* duplicate(const char* x) { - size_t len = strlen(x); - char* ret = malloc(len+1); - memcpy(ret, x, len); - ret[len] = '\0'; - return ret; -} - -// index, path: / -char* _(struct MHD_Connection* connection) { - const char* resp = "<html><body>This is an index page!</body></html>"; - return duplicate(resp); -} - -// home, path: /home -char* _home(struct MHD_Connection* connection) { - const char* resp = "<html><body>" - "<h1>This is a HOME page!</h1>" - "<div style=\"height:10000px;\"></div>" - "<a href=\"/hidden/hentai\">Don't click me! :0</a>" - "</body></html>"; - return duplicate(resp); -} - -// hentai, path: /hidden/hentai -char* _hidden_hentai(struct MHD_Connection* connection) { - const char* resp = "<html><style>a{text-decoration:none;}</style><body>" - "<p>what did you expect to see...</p>" - "<a href=\"https://pornhub.com\"> </a>" - "</body></html>"; - return duplicate(resp); -} diff --git a/include/common.h b/include/common.h new file mode 100644 index 0000000..539ba3a --- /dev/null +++ b/include/common.h @@ -0,0 +1,15 @@ +#ifndef COMMON_H + +#include <microhttpd.h> + +#include <unistd.h> +#include <fcntl.h> +#include <sys/stat.h> + +typedef struct MHD_Response*(*endpoint)(struct MHD_Connection*, int *status); +typedef char *(*query_func)(const char *path); + +char *duplicate(const char *x); +struct MHD_Response *get_from_file(const char *path); + +#endif // COMMON_H diff --git a/include/sql.h b/include/sql.h new file mode 100644 index 0000000..e14167b --- /dev/null +++ b/include/sql.h @@ -0,0 +1,6 @@ +#ifndef SQL_H +#define SQL_H + +extern const char *INIT_SQL, *INSERT_SQL, *DELETE_SQL; + +#endif @@ -1,50 +0,0 @@ -#include <stdio.h> -#include <string.h> -#include <dlfcn.h> - -#include "microhttpd.h" - -typedef char*(*endpoint)(struct MHD_Connection*); - -enum MHD_Result process_connection(void *dylib, struct MHD_Connection *connection, const char *url, - const char *method, const char *version, const char *upload_data, - size_t *upload_data_size, void **req_cls) -{ - printf("\nurl: %s\nmethod:%s\nversion:%s\nupload_data:%s\nsize:%zu\n", - url, method, version, upload_data, *upload_data_size); - /* Load function with the name of the url from shared library */ - endpoint handler = dlsym(dylib, url); - struct MHD_Response *res; int status; - if (handler != NULL) { - fprintf(stderr, "Accessed at url\t%s\n", url); - char* response = handler(connection); - res = MHD_create_response_from_buffer(strlen(response), response, MHD_RESPMEM_MUST_FREE); - status = MHD_HTTP_OK; - } else { - fprintf(stderr, "Failed to access at url\t%s\n", url); - const char* error = "<html><body>Error 404: Page does not exist</body></html>"; - res = MHD_create_response_from_buffer(strlen(error), (void*)error, MHD_RESPMEM_PERSISTENT); - status = MHD_HTTP_NOT_FOUND; - } - MHD_queue_response(connection, status, res); - MHD_destroy_response(res); - return MHD_YES; -} - - -int main(){ - void* dylib = dlopen("./endpoints.so", RTLD_NOW); - if (!dylib) { - fprintf(stderr, "Could not open dynamic library: %s\n", dlerror()); - return 1; - } - struct MHD_Daemon *daemon = MHD_start_daemon(MHD_USE_POLL | MHD_USE_INTERNAL_POLLING_THREAD, 8080, NULL, NULL, process_connection, dylib, MHD_OPTION_END); - if (daemon == NULL) { - perror("daemon"); - fprintf(stderr, "could not initialize daemon\n"); - return 1; - } - getchar(); - MHD_stop_daemon(daemon); - return 0; -} diff --git a/src/common.c b/src/common.c new file mode 100644 index 0000000..7d8d836 --- /dev/null +++ b/src/common.c @@ -0,0 +1,40 @@ +#include "common.h" +#include "mime.h" + +#include <log.h> + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +char *duplicate(const char* x) { + size_t len = strlen(x); + char* ret = malloc(len+1); + memcpy(ret, x, len); + ret[len] = '\0'; + return ret; +} +// either get a file in a directory %URL or www/%URL.html +struct MHD_Response *get_from_file(const char* path) { + int fd = open(path, O_RDONLY); + if (fd < 0) { + size_t psz = strlen(path); + char *wwwdx = malloc(psz + 4 + 5 + 1); + strcpy(wwwdx, "www/"); + strcpy(wwwdx + 4, path); + strcpy(wwwdx + 4 + psz, ".html"); + fd = open(wwwdx, O_RDONLY); + free(wwwdx); + if (fd < 0) return NULL; + } + struct stat st; + if (fstat(fd, &st) < 0) return NULL; + struct MHD_Response *res = MHD_create_response_from_fd(st.st_size, fd); + size_t len, lastdot; + for (len = lastdot = 0; path[len]; ++len) + if (len[path] == '.') lastdot = len; + if (lastdot++) + MHD_add_response_header(res, "Content-Type", mimetype_get(path + lastdot, len - lastdot)); + LDEBUGF("mimetype = %s\n", mimetype_get(path + lastdot, len - lastdot)); + return res; +} diff --git a/src/endpoints.c b/src/endpoints.c new file mode 100644 index 0000000..990ef29 --- /dev/null +++ b/src/endpoints.c @@ -0,0 +1,195 @@ +#include <stdbool.h> +#include <stdarg.h> +#include <limits.h> + +#include <unistd.h> +#include <fcntl.h> +#include <sys/stat.h> + +#include <microhttpd.h> + +#define CONTAINER_IMPLEMENTATION +#define JACSON_IMPLEMENTATION +#define JACSON_EXPORT_RSNPRINTF +#include <jacson.h> + +#define COMMON_IMPLEMENTATION +#include <common.h> + +const char *const JSON_ERROR = "{\"error\":\"%s\"}"; +const char *const HTML_ERROR = "<!DOCTYPE html><html><body>Error: %s</body></html>"; +const char *const JSON_SERVER_ERROR = "{\"error\":\"%s\",\"what\":\"%s\"}"; +const char *const HTML_SERVER_ERROR = "<!DOCTYPE html><html><body>Error: %s<br>Server error message: <p style=\"font-style: monospace\">%s</p></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>"; + +struct global_args { + enum { + GA_FMT_JSON = 0, + GA_FMT_HTML = 1 + } format; +}; + +struct fmt_const { + const char *error, *server_error, *content_type; +}; +static struct fmt_const fmts[] = { + [GA_FMT_JSON] = {JSON_ERROR, JSON_SERVER_ERROR, "application/json"}, + [GA_FMT_HTML] = {HTML_ERROR, HTML_SERVER_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); +} + +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); + return MHD_YES; +} + +struct global_args parse_global_args(struct MHD_Connection *connection) { + const char* key, *val; + struct global_args ret = { .format = GA_FMT_JSON }; + key = "format"; + if ( (val = MHD_lookup_connection_value(connection, MHD_GET_ARGUMENT_KIND, key)) + && !strcmp(val, "html")) ret.format = GA_FMT_HTML; + return ret; +} + +char *db_add_url(const char *url, const char *path) { + return "test"; +} + +bool db_del_url(const char *path) { + return false; +} + +// dong: output parameter +char *db_get_info(const char *path, long *dong) { + *dong = 0; + return NULL; +} + +char *db_get_url(const char *path) { + return NULL; +} + +// alphabet: 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ +// returns 0 if no conversion is available +static inline char itoc(register unsigned long l) { +#ifdef __GNUC__ + char add[256] = { + [0 ... 9] = '0', + [10 ... 35] = 'a' - 10, + [36 ... 61] = 'A' - 10 - 26, + }; + return (l < 62) * (l + add[l]); +#else + if (l < 10) return '0' + l; + if (l < 10 + 26) return 'a' + l - 10; + if (l < 10 + 2 * 26) return 'A' + l - 10 - 26; + return '\0'; +#endif +} +// returns negative number if conversion not available +static inline unsigned long ctoi(register char c) { +#ifdef __GNUC__ + char sub[127] = { + [0 ... '0'-1] = 128, + ['0' ... '9'] = '0', + ['A' ... 'Z'] = 'A' - 26 - 10, + ['a' ... 'z'] = 'a' - 10, + }; + return c - sub[c]; +#else + TODO; +#endif +} +// buf must be at least 12 characters (11 for strnig and 1 for termination byte) +// returns a pointer from which the string starts +static char *itou(register unsigned long i, register char *buf) { + register ssize_t ind = 11; + buf[ind] = '\0'; + buf[ind - 1] = '0'; + while (ind >= 0 && i) { + buf[--ind] = itoc(i % 62); + i /= 62; + } + return buf + ind; +} +static unsigned long utoi(const char *s) { + register unsigned long result = 0; + while (*s) { + result *= 62; + result += ctoi(*s); + ++s; + } + return result; +} + +// index, path: / +struct MHD_Response *ENDP_(struct MHD_Connection* connection, int *status) { + return get_from_file("www/index.html"); +} + +// 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) fprintf(stderr, "test = %s\n", val); + fprintf(stderr, "test pointer = %p", val); + return MHD_create_response_from_buffer(html.ln, html.str, MHD_RESPMEM_MUST_FREE); +} + +// API, path: /api/linkadd +struct MHD_Response *ENDP_api_linkadd(struct MHD_Connection *connection, int *status) { + const char *url = NULL, *path = NULL; + char *newurl; + struct sb resp = {malloc(64), 63, 0}; + 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 = MHD_HTTP_BAD_REQUEST; + sbprintf(&resp, fmts[glob.format].error, INSUFFICIENT_ARGUMENTS); + goto exit; + } + path = MHD_lookup_connection_value(connection, MHD_GET_ARGUMENT_KIND, "try"); + if ((newurl = db_add_url(url, path)) == NULL) { + *status = MHD_HTTP_INTERNAL_SERVER_ERROR; + sbprintf(&resp, fmts[glob.format].server_error, SERVER_ERRORMSG, "database write failed"); + goto exit; + } + if (glob.format == GA_FMT_JSON) sbprintf(&resp, "{\"url\":\"%s\"}", newurl); + else sbprintf(&resp, "%sYour URL: <a href\"%s\">/%s</a>%s", HTML_PROLOGUE, newurl, newurl, HTML_EPILOGUE); +exit: + response = MHD_create_response_from_buffer(resp.ln, resp.str, 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) { + +} + +// API, path: /api/linkget +struct MHD_Response *ENDP_api_linkget(struct MHD_Connection *connection, int *status) { } diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..36df30a --- /dev/null +++ b/src/main.c @@ -0,0 +1,104 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <dlfcn.h> + +#include <microhttpd.h> +#include <sqlite3.h> + +#include <log.h> +#define COMMON_IMPLEMENTATION +#include <common.h> + +/* sqlite leastunused implementation */ +struct slidid { sqlite3_int64 il, in, res; }; +void step_leastunused(sqlite3_context* ctx, int argc, sqlite3_value** argv) { + struct slidid *idx = sqlite3_aggregate_context(ctx, sizeof *idx); + if (idx->res) return; + idx->in = sqlite3_value_int64(argv[0]); + if (idx->il + 1 != idx->in) idx->res = idx->il + 1; + idx->il = idx->in; +} +void final_leastunused(sqlite3_context* ctx) { + struct slidid *idx = sqlite3_aggregate_context(ctx, 0); + sqlite3_result_int(ctx, idx->res); +} + +sqlite3 *sqlite_init(const char *db) { + sqlite3 *ret; + sqlite3_open_v2(db, &ret, SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE, NULL); + if (ret == NULL) LCRIT(1, "could not open sqlite3 database"); + sqlite3_create_function(ret, "leastunused", 1, SQLITE_UTF8, NULL, NULL, step_leastunused, final_leastunused); + return ret; +} + +enum MHD_Result process_connection(void *dylib, struct MHD_Connection *connection, const char *url, + const char *method, const char *version, const char *upload_data, + size_t *upload_data_size, void **req_cls) +{ + LDEBUGF("\nurl: %s\nmethod:%s\nversion:%s\nupload_data:%s\nsize:%zu\n", + url, method, version, upload_data, *upload_data_size); + /* Load function with the name of the url from shared library */ + endpoint handler = dlsym(dylib, url); + query_func query = dlsym(dylib, "db_get_url"); + struct MHD_Response *res; + int status = MHD_HTTP_OK; + const char *response; + char *newurl; + if (query == NULL) { + response = "<!DOCTYPE html><html><body>Temporary server error: could not open database</body></html>"; + res = MHD_create_response_from_buffer(strlen(response), (void*)response, MHD_RESPMEM_PERSISTENT); + status = MHD_HTTP_INTERNAL_SERVER_ERROR; + goto response; + } + if (strcasecmp(method, "GET")) { + status = MHD_HTTP_METHOD_NOT_ALLOWED; + res = MHD_create_response_from_buffer(18, "Method not allowed", MHD_RESPMEM_PERSISTENT); + goto response; + } + if (handler != NULL) { + /* endpoint access */ + LINFOF("Accessed endpoint at url %s", url); + res = handler(connection, &status); + } else if ((newurl = query(url)) != NULL) { + LINFOF("Redirect from %s to %s", url, newurl); + /* if (newurl == NULL) { */ + /* free(newurl); */ + /* response = "<!DOCTYPE html><html><body>Page does not exist</body></html>"; */ + /* res = MHD_create_response_from_buffer(strlen(response), (void*)response, MHD_RESPMEM_PERSISTENT); */ + /* status = MHD_HTTP_NOT_FOUND; */ + /* goto response; */ + /* } */ + response = "<!DOCTYPE html><html><body>Recirecting...</body></html>"; + res = MHD_create_response_from_buffer(strlen(response), (void*)response, MHD_RESPMEM_PERSISTENT); + MHD_add_response_header(res, "Location", newurl); + status = MHD_HTTP_FOUND; + } else if ((res = get_from_file(url + 1)) != NULL) { + /* fallback file access */ + LINFOF("Accessed file at url %s", url); + } else { + /* error */ + LINFOF("Failed access to endpoint\t%s", url); + const char* error = "\"resource does not exist\""; + res = MHD_create_response_from_buffer(strlen(error), (void*)error, MHD_RESPMEM_PERSISTENT); + status = MHD_HTTP_NOT_FOUND; + } +response: + MHD_queue_response(connection, status, res); + MHD_destroy_response(res); + return MHD_YES; +} + + +int main(int argc, char *argv[]){ + void* dylib = dlopen("./endpoints.so", RTLD_NOW); + if (!dylib) LCRITF(1, "Could not open dynamic library: %s\n", dlerror()); + struct MHD_Daemon *daemon = MHD_start_daemon(MHD_USE_POLL | MHD_USE_INTERNAL_POLLING_THREAD, 8080, NULL, NULL, process_connection, dylib, MHD_OPTION_END); + if (daemon == NULL) LCRITV(1, "could not initialize daemon"); + + getchar(); + + dlclose(dylib); + MHD_stop_daemon(daemon); + return 0; +} diff --git a/src/mime.c b/src/mime.c new file mode 100644 index 0000000..621b5b7 --- /dev/null +++ b/src/mime.c @@ -0,0 +1,9 @@ +#include "mime.h" +#include "mime.c.inc" + +const char *mimetype_get(register const char *str, register size_t len) { + const struct __mimetype_keyword *kwd = __mimetype_get_helper(str, len); + if (kwd == NULL) return "application/octet-stream"; + return kwd->val; +} + diff --git a/src/mime_gen.c.gperf b/src/mime_gen.c.gperf new file mode 100644 index 0000000..4c4d0e1 --- /dev/null +++ b/src/mime_gen.c.gperf @@ -0,0 +1,992 @@ +%{ +#include <mime.h> +#include <stddef.h> +%} +struct __mimetype_keyword { + const char *key; + const char *val; +}; +%% +ez, "application/andrew-inset" +aw, "application/applixware" +atom, "application/atom+xml" +atomcat, "application/atomcat+xml" +atomsvc, "application/atomsvc+xml" +ccxml, "application/ccxml+xml" +cdmia, "application/cdmi-capability" +cdmic, "application/cdmi-container" +cdmid, "application/cdmi-domain" +cdmio, "application/cdmi-object" +cdmiq, "application/cdmi-queue" +cu, "application/cu-seeme" +davmount, "application/davmount+xml" +dbk, "application/docbook+xml" +dssc, "application/dssc+der" +xdssc, "application/dssc+xml" +ecma, "application/ecmascript" +emma, "application/emma+xml" +epub, "application/epub+zip" +exi, "application/exi" +pfr, "application/font-tdpfr" +gml, "application/gml+xml" +gpx, "application/gpx+xml" +gxf, "application/gxf" +stk, "application/hyperstudio" +ink, "application/inkml+xml" +inkml, "application/inkml+xml" +ipfix, "application/ipfix" +jar, "application/java-archive" +ser, "application/java-serialized-object" +class, "application/java-vm" +js, "application/javascript" +json, "application/json" +jsonml, "application/jsonml+json" +lostxml, "application/lost+xml" +hqx, "application/mac-binhex40" +cpt, "application/mac-compactpro" +mads, "application/mads+xml" +mrc, "application/marc" +mrcx, "application/marcxml+xml" +ma, "application/mathematica" +nb, "application/mathematica" +mb, "application/mathematica" +mathml, "application/mathml+xml" +mbox, "application/mbox" +mscml, "application/mediaservercontrol+xml" +metalink, "application/metalink+xml" +meta4, "application/metalink4+xml" +mets, "application/mets+xml" +mods, "application/mods+xml" +m21, "application/mp21" +mp21, "application/mp21" +mp4s, "application/mp4" +doc, "application/msword" +dot, "application/msword" +mxf, "application/mxf" +bin, "application/octet-stream" +dms, "application/octet-stream" +lrf, "application/octet-stream" +mar, "application/octet-stream" +so, "application/octet-stream" +dist, "application/octet-stream" +distz, "application/octet-stream" +pkg, "application/octet-stream" +bpk, "application/octet-stream" +dump, "application/octet-stream" +elc, "application/octet-stream" +deploy, "application/octet-stream" +oda, "application/oda" +opf, "application/oebps-package+xml" +ogx, "application/ogg" +omdoc, "application/omdoc+xml" +onetoc, "application/onenote" +onetoc2, "application/onenote" +onetmp, "application/onenote" +onepkg, "application/onenote" +oxps, "application/oxps" +xer, "application/patch-ops-error+xml" +pdf, "application/pdf" +pgp, "application/pgp-encrypted" +asc, "application/pgp-signature" +sig, "application/pgp-signature" +prf, "application/pics-rules" +p10, "application/pkcs10" +p7m, "application/pkcs7-mime" +p7c, "application/pkcs7-mime" +p7s, "application/pkcs7-signature" +p8, "application/pkcs8" +ac, "application/pkix-attr-cert" +cer, "application/pkix-cert" +crl, "application/pkix-crl" +pkipath, "application/pkix-pkipath" +pki, "application/pkixcmp" +pls, "application/pls+xml" +ai, "application/postscript" +eps, "application/postscript" +ps, "application/postscript" +cww, "application/prs.cww" +pskcxml, "application/pskc+xml" +rdf, "application/rdf+xml" +rif, "application/reginfo+xml" +rnc, "application/relax-ng-compact-syntax" +rl, "application/resource-lists+xml" +rld, "application/resource-lists-diff+xml" +rs, "application/rls-services+xml" +gbr, "application/rpki-ghostbusters" +mft, "application/rpki-manifest" +roa, "application/rpki-roa" +rsd, "application/rsd+xml" +rss, "application/rss+xml" +rtf, "application/rtf" +sbml, "application/sbml+xml" +scq, "application/scvp-cv-request" +scs, "application/scvp-cv-response" +spq, "application/scvp-vp-request" +spp, "application/scvp-vp-response" +sdp, "application/sdp" +setpay, "application/set-payment-initiation" +setreg, "application/set-registration-initiation" +shf, "application/shf+xml" +smi, "application/smil+xml" +smil, "application/smil+xml" +rq, "application/sparql-query" +srx, "application/sparql-results+xml" +gram, "application/srgs" +grxml, "application/srgs+xml" +sru, "application/sru+xml" +ssdl, "application/ssdl+xml" +ssml, "application/ssml+xml" +tei, "application/tei+xml" +teicorpus, "application/tei+xml" +tfi, "application/thraud+xml" +tsd, "application/timestamped-data" +plb, "application/vnd.3gpp.pic-bw-large" +psb, "application/vnd.3gpp.pic-bw-small" +pvb, "application/vnd.3gpp.pic-bw-var" +tcap, "application/vnd.3gpp2.tcap" +pwn, "application/vnd.3m.post-it-notes" +aso, "application/vnd.accpac.simply.aso" +imp, "application/vnd.accpac.simply.imp" +acu, "application/vnd.acucobol" +atc, "application/vnd.acucorp" +acutc, "application/vnd.acucorp" +air, "application/vnd.adobe.air-application-installer-package+zip" +fcdt, "application/vnd.adobe.formscentral.fcdt" +fxp, "application/vnd.adobe.fxp" +fxpl, "application/vnd.adobe.fxp" +xdp, "application/vnd.adobe.xdp+xml" +xfdf, "application/vnd.adobe.xfdf" +ahead, "application/vnd.ahead.space" +azf, "application/vnd.airzip.filesecure.azf" +azs, "application/vnd.airzip.filesecure.azs" +azw, "application/vnd.amazon.ebook" +acc, "application/vnd.americandynamics.acc" +ami, "application/vnd.amiga.ami" +apk, "application/vnd.android.package-archive" +cii, "application/vnd.anser-web-certificate-issue-initiation" +fti, "application/vnd.anser-web-funds-transfer-initiation" +atx, "application/vnd.antix.game-component" +mpkg, "application/vnd.apple.installer+xml" +m3u8, "application/vnd.apple.mpegurl" +swi, "application/vnd.aristanetworks.swi" +iota, "application/vnd.astraea-software.iota" +aep, "application/vnd.audiograph" +mpm, "application/vnd.blueice.multipass" +bmi, "application/vnd.bmi" +rep, "application/vnd.businessobjects" +cdxml, "application/vnd.chemdraw+xml" +mmd, "application/vnd.chipnuts.karaoke-mmd" +cdy, "application/vnd.cinderella" +cla, "application/vnd.claymore" +rp9, "application/vnd.cloanto.rp9" +c4g, "application/vnd.clonk.c4group" +c4d, "application/vnd.clonk.c4group" +c4f, "application/vnd.clonk.c4group" +c4p, "application/vnd.clonk.c4group" +c4u, "application/vnd.clonk.c4group" +c11amc, "application/vnd.cluetrust.cartomobile-config" +c11amz, "application/vnd.cluetrust.cartomobile-config-pkg" +csp, "application/vnd.commonspace" +cdbcmsg, "application/vnd.contact.cmsg" +cmc, "application/vnd.cosmocaller" +clkx, "application/vnd.crick.clicker" +clkk, "application/vnd.crick.clicker.keyboard" +clkp, "application/vnd.crick.clicker.palette" +clkt, "application/vnd.crick.clicker.template" +clkw, "application/vnd.crick.clicker.wordbank" +wbs, "application/vnd.criticaltools.wbs+xml" +pml, "application/vnd.ctc-posml" +ppd, "application/vnd.cups-ppd" +car, "application/vnd.curl.car" +pcurl, "application/vnd.curl.pcurl" +dart, "application/vnd.dart" +rdz, "application/vnd.data-vision.rdz" +uvf, "application/vnd.dece.data" +uvvf, "application/vnd.dece.data" +uvd, "application/vnd.dece.data" +uvvd, "application/vnd.dece.data" +uvt, "application/vnd.dece.ttml+xml" +uvvt, "application/vnd.dece.ttml+xml" +uvx, "application/vnd.dece.unspecified" +uvvx, "application/vnd.dece.unspecified" +uvz, "application/vnd.dece.zip" +uvvz, "application/vnd.dece.zip" +fe_launch, "application/vnd.denovo.fcselayout-link" +dna, "application/vnd.dna" +mlp, "application/vnd.dolby.mlp" +dpg, "application/vnd.dpgraph" +dfac, "application/vnd.dreamfactory" +kpxx, "application/vnd.ds-keypoint" +ait, "application/vnd.dvb.ait" +svc, "application/vnd.dvb.service" +geo, "application/vnd.dynageo" +mag, "application/vnd.ecowin.chart" +nml, "application/vnd.enliven" +esf, "application/vnd.epson.esf" +msf, "application/vnd.epson.msf" +qam, "application/vnd.epson.quickanime" +slt, "application/vnd.epson.salt" +ssf, "application/vnd.epson.ssf" +es3, "application/vnd.eszigno3+xml" +et3, "application/vnd.eszigno3+xml" +ez2, "application/vnd.ezpix-album" +ez3, "application/vnd.ezpix-package" +fdf, "application/vnd.fdf" +mseed, "application/vnd.fdsn.mseed" +seed, "application/vnd.fdsn.seed" +dataless, "application/vnd.fdsn.seed" +gph, "application/vnd.flographit" +ftc, "application/vnd.fluxtime.clip" +fm, "application/vnd.framemaker" +frame, "application/vnd.framemaker" +maker, "application/vnd.framemaker" +book, "application/vnd.framemaker" +fnc, "application/vnd.frogans.fnc" +ltf, "application/vnd.frogans.ltf" +fsc, "application/vnd.fsc.weblaunch" +oas, "application/vnd.fujitsu.oasys" +oa2, "application/vnd.fujitsu.oasys2" +oa3, "application/vnd.fujitsu.oasys3" +fg5, "application/vnd.fujitsu.oasysgp" +bh2, "application/vnd.fujitsu.oasysprs" +ddd, "application/vnd.fujixerox.ddd" +xdw, "application/vnd.fujixerox.docuworks" +xbd, "application/vnd.fujixerox.docuworks.binder" +fzs, "application/vnd.fuzzysheet" +txd, "application/vnd.genomatix.tuxedo" +ggb, "application/vnd.geogebra.file" +ggt, "application/vnd.geogebra.tool" +gex, "application/vnd.geometry-explorer" +gre, "application/vnd.geometry-explorer" +gxt, "application/vnd.geonext" +g2w, "application/vnd.geoplan" +g3w, "application/vnd.geospace" +gmx, "application/vnd.gmx" +kml, "application/vnd.google-earth.kml+xml" +kmz, "application/vnd.google-earth.kmz" +gqf, "application/vnd.grafeq" +gqs, "application/vnd.grafeq" +gac, "application/vnd.groove-account" +ghf, "application/vnd.groove-help" +gim, "application/vnd.groove-identity-message" +grv, "application/vnd.groove-injector" +gtm, "application/vnd.groove-tool-message" +tpl, "application/vnd.groove-tool-template" +vcg, "application/vnd.groove-vcard" +hal, "application/vnd.hal+xml" +zmm, "application/vnd.handheld-entertainment+xml" +hbci, "application/vnd.hbci" +les, "application/vnd.hhe.lesson-player" +hpgl, "application/vnd.hp-hpgl" +hpid, "application/vnd.hp-hpid" +hps, "application/vnd.hp-hps" +jlt, "application/vnd.hp-jlyt" +pcl, "application/vnd.hp-pcl" +pclxl, "application/vnd.hp-pclxl" +sfd-hdstx, "application/vnd.hydrostatix.sof-data" +mpy, "application/vnd.ibm.minipay" +afp, "application/vnd.ibm.modcap" +listafp, "application/vnd.ibm.modcap" +list3820, "application/vnd.ibm.modcap" +irm, "application/vnd.ibm.rights-management" +sc, "application/vnd.ibm.secure-container" +icc, "application/vnd.iccprofile" +icm, "application/vnd.iccprofile" +igl, "application/vnd.igloader" +ivp, "application/vnd.immervision-ivp" +ivu, "application/vnd.immervision-ivu" +igm, "application/vnd.insors.igm" +xpw, "application/vnd.intercon.formnet" +xpx, "application/vnd.intercon.formnet" +i2g, "application/vnd.intergeo" +qbo, "application/vnd.intu.qbo" +qfx, "application/vnd.intu.qfx" +rcprofile, "application/vnd.ipunplugged.rcprofile" +irp, "application/vnd.irepository.package+xml" +xpr, "application/vnd.is-xpr" +fcs, "application/vnd.isac.fcs" +jam, "application/vnd.jam" +rms, "application/vnd.jcp.javame.midlet-rms" +jisp, "application/vnd.jisp" +joda, "application/vnd.joost.joda-archive" +ktz, "application/vnd.kahootz" +ktr, "application/vnd.kahootz" +karbon, "application/vnd.kde.karbon" +chrt, "application/vnd.kde.kchart" +kfo, "application/vnd.kde.kformula" +flw, "application/vnd.kde.kivio" +kon, "application/vnd.kde.kontour" +kpr, "application/vnd.kde.kpresenter" +kpt, "application/vnd.kde.kpresenter" +ksp, "application/vnd.kde.kspread" +kwd, "application/vnd.kde.kword" +kwt, "application/vnd.kde.kword" +htke, "application/vnd.kenameaapp" +kia, "application/vnd.kidspiration" +kne, "application/vnd.kinar" +knp, "application/vnd.kinar" +skp, "application/vnd.koan" +skd, "application/vnd.koan" +skt, "application/vnd.koan" +skm, "application/vnd.koan" +sse, "application/vnd.kodak-descriptor" +lasxml, "application/vnd.las.las+xml" +lbd, "application/vnd.llamagraphics.life-balance.desktop" +lbe, "application/vnd.llamagraphics.life-balance.exchange+xml" +123, "application/vnd.lotus-1-2-3" +apr, "application/vnd.lotus-approach" +pre, "application/vnd.lotus-freelance" +nsf, "application/vnd.lotus-notes" +org, "application/vnd.lotus-organizer" +scm, "application/vnd.lotus-screencam" +lwp, "application/vnd.lotus-wordpro" +portpkg, "application/vnd.macports.portpkg" +mcd, "application/vnd.mcd" +mc1, "application/vnd.medcalcdata" +cdkey, "application/vnd.mediastation.cdkey" +mwf, "application/vnd.mfer" +mfm, "application/vnd.mfmp" +flo, "application/vnd.micrografx.flo" +igx, "application/vnd.micrografx.igx" +mif, "application/vnd.mif" +daf, "application/vnd.mobius.daf" +dis, "application/vnd.mobius.dis" +mbk, "application/vnd.mobius.mbk" +mqy, "application/vnd.mobius.mqy" +msl, "application/vnd.mobius.msl" +plc, "application/vnd.mobius.plc" +txf, "application/vnd.mobius.txf" +mpn, "application/vnd.mophun.application" +mpc, "application/vnd.mophun.certificate" +xul, "application/vnd.mozilla.xul+xml" +cil, "application/vnd.ms-artgalry" +cab, "application/vnd.ms-cab-compressed" +xls, "application/vnd.ms-excel" +xlm, "application/vnd.ms-excel" +xla, "application/vnd.ms-excel" +xlc, "application/vnd.ms-excel" +xlt, "application/vnd.ms-excel" +xlw, "application/vnd.ms-excel" +xlam, "application/vnd.ms-excel.addin.macroenabled.12" +xlsb, "application/vnd.ms-excel.sheet.binary.macroenabled.12" +xlsm, "application/vnd.ms-excel.sheet.macroenabled.12" +xltm, "application/vnd.ms-excel.template.macroenabled.12" +eot, "application/vnd.ms-fontobject" +chm, "application/vnd.ms-htmlhelp" +ims, "application/vnd.ms-ims" +lrm, "application/vnd.ms-lrm" +thmx, "application/vnd.ms-officetheme" +cat, "application/vnd.ms-pki.seccat" +stl, "application/vnd.ms-pki.stl" +ppt, "application/vnd.ms-powerpoint" +pps, "application/vnd.ms-powerpoint" +pot, "application/vnd.ms-powerpoint" +ppam, "application/vnd.ms-powerpoint.addin.macroenabled.12" +pptm, "application/vnd.ms-powerpoint.presentation.macroenabled.12" +sldm, "application/vnd.ms-powerpoint.slide.macroenabled.12" +ppsm, "application/vnd.ms-powerpoint.slideshow.macroenabled.12" +potm, "application/vnd.ms-powerpoint.template.macroenabled.12" +mpp, "application/vnd.ms-project" +mpt, "application/vnd.ms-project" +docm, "application/vnd.ms-word.document.macroenabled.12" +dotm, "application/vnd.ms-word.template.macroenabled.12" +wps, "application/vnd.ms-works" +wks, "application/vnd.ms-works" +wcm, "application/vnd.ms-works" +wdb, "application/vnd.ms-works" +wpl, "application/vnd.ms-wpl" +xps, "application/vnd.ms-xpsdocument" +mseq, "application/vnd.mseq" +mus, "application/vnd.musician" +msty, "application/vnd.muvee.style" +taglet, "application/vnd.mynfc" +nlu, "application/vnd.neurolanguage.nlu" +ntf, "application/vnd.nitf" +nitf, "application/vnd.nitf" +nnd, "application/vnd.noblenet-directory" +nns, "application/vnd.noblenet-sealer" +nnw, "application/vnd.noblenet-web" +ngdat, "application/vnd.nokia.n-gage.data" +n-gage, "application/vnd.nokia.n-gage.symbian.install" +rpst, "application/vnd.nokia.radio-preset" +rpss, "application/vnd.nokia.radio-presets" +edm, "application/vnd.novadigm.edm" +edx, "application/vnd.novadigm.edx" +ext, "application/vnd.novadigm.ext" +odc, "application/vnd.oasis.opendocument.chart" +otc, "application/vnd.oasis.opendocument.chart-template" +odb, "application/vnd.oasis.opendocument.database" +odf, "application/vnd.oasis.opendocument.formula" +odft, "application/vnd.oasis.opendocument.formula-template" +odg, "application/vnd.oasis.opendocument.graphics" +otg, "application/vnd.oasis.opendocument.graphics-template" +odi, "application/vnd.oasis.opendocument.image" +oti, "application/vnd.oasis.opendocument.image-template" +odp, "application/vnd.oasis.opendocument.presentation" +otp, "application/vnd.oasis.opendocument.presentation-template" +ods, "application/vnd.oasis.opendocument.spreadsheet" +ots, "application/vnd.oasis.opendocument.spreadsheet-template" +odt, "application/vnd.oasis.opendocument.text" +odm, "application/vnd.oasis.opendocument.text-master" +ott, "application/vnd.oasis.opendocument.text-template" +oth, "application/vnd.oasis.opendocument.text-web" +xo, "application/vnd.olpc-sugar" +dd2, "application/vnd.oma.dd2+xml" +oxt, "application/vnd.openofficeorg.extension" +pptx, "application/vnd.openxmlformats-officedocument.presentationml.presentation" +sldx, "application/vnd.openxmlformats-officedocument.presentationml.slide" +ppsx, "application/vnd.openxmlformats-officedocument.presentationml.slideshow" +potx, "application/vnd.openxmlformats-officedocument.presentationml.template" +xlsx, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" +xltx, "application/vnd.openxmlformats-officedocument.spreadsheetml.template" +docx, "application/vnd.openxmlformats-officedocument.wordprocessingml.document" +dotx, "application/vnd.openxmlformats-officedocument.wordprocessingml.template" +mgp, "application/vnd.osgeo.mapguide.package" +dp, "application/vnd.osgi.dp" +esa, "application/vnd.osgi.subsystem" +pdb, "application/vnd.palm" +pqa, "application/vnd.palm" +oprc, "application/vnd.palm" +paw, "application/vnd.pawaafile" +str, "application/vnd.pg.format" +ei6, "application/vnd.pg.osasli" +efif, "application/vnd.picsel" +wg, "application/vnd.pmi.widget" +plf, "application/vnd.pocketlearn" +pbd, "application/vnd.powerbuilder6" +box, "application/vnd.previewsystems.box" +mgz, "application/vnd.proteus.magazine" +qps, "application/vnd.publishare-delta-tree" +ptid, "application/vnd.pvi.ptid1" +qxd, "application/vnd.quark.quarkxpress" +qxt, "application/vnd.quark.quarkxpress" +qwd, "application/vnd.quark.quarkxpress" +qwt, "application/vnd.quark.quarkxpress" +qxl, "application/vnd.quark.quarkxpress" +qxb, "application/vnd.quark.quarkxpress" +bed, "application/vnd.realvnc.bed" +mxl, "application/vnd.recordare.musicxml" +musicxml, "application/vnd.recordare.musicxml+xml" +cryptonote, "application/vnd.rig.cryptonote" +cod, "application/vnd.rim.cod" +rm, "application/vnd.rn-realmedia" +rmvb, "application/vnd.rn-realmedia-vbr" +link66, "application/vnd.route66.link66+xml" +st, "application/vnd.sailingtracker.track" +see, "application/vnd.seemail" +sema, "application/vnd.sema" +semd, "application/vnd.semd" +semf, "application/vnd.semf" +ifm, "application/vnd.shana.informed.formdata" +itp, "application/vnd.shana.informed.formtemplate" +iif, "application/vnd.shana.informed.interchange" +ipk, "application/vnd.shana.informed.package" +twd, "application/vnd.simtech-mindmapper" +twds, "application/vnd.simtech-mindmapper" +mmf, "application/vnd.smaf" +teacher, "application/vnd.smart.teacher" +sdkm, "application/vnd.solent.sdkm+xml" +sdkd, "application/vnd.solent.sdkm+xml" +dxp, "application/vnd.spotfire.dxp" +sfs, "application/vnd.spotfire.sfs" +sdc, "application/vnd.stardivision.calc" +sda, "application/vnd.stardivision.draw" +sdd, "application/vnd.stardivision.impress" +smf, "application/vnd.stardivision.math" +sdw, "application/vnd.stardivision.writer" +vor, "application/vnd.stardivision.writer" +sgl, "application/vnd.stardivision.writer-global" +smzip, "application/vnd.stepmania.package" +sm, "application/vnd.stepmania.stepchart" +sxc, "application/vnd.sun.xml.calc" +stc, "application/vnd.sun.xml.calc.template" +sxd, "application/vnd.sun.xml.draw" +std, "application/vnd.sun.xml.draw.template" +sxi, "application/vnd.sun.xml.impress" +sti, "application/vnd.sun.xml.impress.template" +sxm, "application/vnd.sun.xml.math" +sxw, "application/vnd.sun.xml.writer" +sxg, "application/vnd.sun.xml.writer.global" +stw, "application/vnd.sun.xml.writer.template" +sus, "application/vnd.sus-calendar" +susp, "application/vnd.sus-calendar" +svd, "application/vnd.svd" +sis, "application/vnd.symbian.install" +sisx, "application/vnd.symbian.install" +xsm, "application/vnd.syncml+xml" +bdm, "application/vnd.syncml.dm+wbxml" +xdm, "application/vnd.syncml.dm+xml" +tao, "application/vnd.tao.intent-module-archive" +pcap, "application/vnd.tcpdump.pcap" +cap, "application/vnd.tcpdump.pcap" +dmp, "application/vnd.tcpdump.pcap" +tmo, "application/vnd.tmobile-livetv" +tpt, "application/vnd.trid.tpt" +mxs, "application/vnd.triscape.mxs" +tra, "application/vnd.trueapp" +ufd, "application/vnd.ufdl" +ufdl, "application/vnd.ufdl" +utz, "application/vnd.uiq.theme" +umj, "application/vnd.umajin" +unityweb, "application/vnd.unity" +uoml, "application/vnd.uoml+xml" +vcx, "application/vnd.vcx" +vsd, "application/vnd.visio" +vst, "application/vnd.visio" +vss, "application/vnd.visio" +vsw, "application/vnd.visio" +vis, "application/vnd.visionary" +vsf, "application/vnd.vsf" +wbxml, "application/vnd.wap.wbxml" +wmlc, "application/vnd.wap.wmlc" +wmlsc, "application/vnd.wap.wmlscriptc" +wtb, "application/vnd.webturbo" +nbp, "application/vnd.wolfram.player" +wpd, "application/vnd.wordperfect" +wqd, "application/vnd.wqd" +stf, "application/vnd.wt.stf" +xar, "application/vnd.xara" +xfdl, "application/vnd.xfdl" +hvd, "application/vnd.yamaha.hv-dic" +hvs, "application/vnd.yamaha.hv-script" +hvp, "application/vnd.yamaha.hv-voice" +osf, "application/vnd.yamaha.openscoreformat" +osfpvg, "application/vnd.yamaha.openscoreformat.osfpvg+xml" +saf, "application/vnd.yamaha.smaf-audio" +spf, "application/vnd.yamaha.smaf-phrase" +cmp, "application/vnd.yellowriver-custom-menu" +zir, "application/vnd.zul" +zirz, "application/vnd.zul" +zaz, "application/vnd.zzazz.deck+xml" +vxml, "application/voicexml+xml" +wgt, "application/widget" +hlp, "application/winhlp" +wsdl, "application/wsdl+xml" +wspolicy, "application/wspolicy+xml" +7z, "application/x-7z-compressed" +abw, "application/x-abiword" +ace, "application/x-ace-compressed" +dmg, "application/x-apple-diskimage" +aab, "application/x-authorware-bin" +x32, "application/x-authorware-bin" +u32, "application/x-authorware-bin" +vox, "application/x-authorware-bin" +aam, "application/x-authorware-map" +aas, "application/x-authorware-seg" +bcpio, "application/x-bcpio" +torrent, "application/x-bittorrent" +blb, "application/x-blorb" +blorb, "application/x-blorb" +bz, "application/x-bzip" +bz2, "application/x-bzip2" +boz, "application/x-bzip2" +cbr, "application/x-cbr" +cba, "application/x-cbr" +cbt, "application/x-cbr" +cbz, "application/x-cbr" +cb7, "application/x-cbr" +vcd, "application/x-cdlink" +cfs, "application/x-cfs-compressed" +chat, "application/x-chat" +pgn, "application/x-chess-pgn" +nsc, "application/x-conference" +cpio, "application/x-cpio" +csh, "application/x-csh" +deb, "application/x-debian-package" +udeb, "application/x-debian-package" +dgc, "application/x-dgc-compressed" +dir, "application/x-director" +dcr, "application/x-director" +dxr, "application/x-director" +cst, "application/x-director" +cct, "application/x-director" +cxt, "application/x-director" +w3d, "application/x-director" +fgd, "application/x-director" +swa, "application/x-director" +wad, "application/x-doom" +ncx, "application/x-dtbncx+xml" +dtb, "application/x-dtbook+xml" +res, "application/x-dtbresource+xml" +dvi, "application/x-dvi" +evy, "application/x-envoy" +eva, "application/x-eva" +bdf, "application/x-font-bdf" +gsf, "application/x-font-ghostscript" +psf, "application/x-font-linux-psf" +otf, "application/x-font-otf" +pcf, "application/x-font-pcf" +snf, "application/x-font-snf" +ttf, "application/x-font-ttf" +ttc, "application/x-font-ttf" +pfa, "application/x-font-type1" +pfb, "application/x-font-type1" +pfm, "application/x-font-type1" +afm, "application/x-font-type1" +woff, "application/font-woff" +arc, "application/x-freearc" +spl, "application/x-futuresplash" +gca, "application/x-gca-compressed" +ulx, "application/x-glulx" +gnumeric, "application/x-gnumeric" +gramps, "application/x-gramps-xml" +gtar, "application/x-gtar" +hdf, "application/x-hdf" +install, "application/x-install-instructions" +iso, "application/x-iso9660-image" +jnlp, "application/x-java-jnlp-file" +latex, "application/x-latex" +lzh, "application/x-lzh-compressed" +lha, "application/x-lzh-compressed" +mie, "application/x-mie" +prc, "application/x-mobipocket-ebook" +mobi, "application/x-mobipocket-ebook" +applicat, "application/x-ms-application" +lnk, "application/x-ms-shortcut" +wmd, "application/x-ms-wmd" +wmz, "application/x-msmetafile" +xbap, "application/x-ms-xbap" +mdb, "application/x-msaccess" +obd, "application/x-msbinder" +crd, "application/x-mscardfile" +clp, "application/x-msclip" +exe, "application/x-msdownload" +dll, "application/x-msdownload" +com, "application/x-msdownload" +bat, "application/x-msdownload" +msi, "application/x-msdownload" +mvb, "application/x-msmediaview" +m13, "application/x-msmediaview" +m14, "application/x-msmediaview" +wmf, "application/x-msmetafile" +emf, "application/x-msmetafile" +emz, "application/x-msmetafile" +mny, "application/x-msmoney" +pub, "application/x-mspublisher" +scd, "application/x-msschedule" +trm, "application/x-msterminal" +wri, "application/x-mswrite" +nc, "application/x-netcdf" +cdf, "application/x-netcdf" +nzb, "application/x-nzb" +p12, "application/x-pkcs12" +pfx, "application/x-pkcs12" +p7b, "application/x-pkcs7-certificates" +spc, "application/x-pkcs7-certificates" +p7r, "application/x-pkcs7-certreqresp" +rar, "application/x-rar-compressed" +ris, "application/x-research-info-systems" +sh, "application/x-sh" +shar, "application/x-shar" +swf, "application/x-shockwave-flash" +xap, "application/x-silverlight-app" +sql, "application/x-sql" +sit, "application/x-stuffit" +sitx, "application/x-stuffitx" +srt, "application/x-subrip" +sv4cpio, "application/x-sv4cpio" +sv4crc, "application/x-sv4crc" +t3, "application/x-t3vm-image" +gam, "application/x-tads" +tar, "application/x-tar" +tcl, "application/x-tcl" +tex, "application/x-tex" +tfm, "application/x-tex-tfm" +texinfo, "application/x-texinfo" +texi, "application/x-texinfo" +obj, "application/x-tgif" +ustar, "application/x-ustar" +src, "application/x-wais-source" +der, "application/x-x509-ca-cert" +crt, "application/x-x509-ca-cert" +fig, "application/x-xfig" +xlf, "application/x-xliff+xml" +xpi, "application/x-xpinstall" +xz, "application/x-xz" +z1, "application/x-zmachine" +z2, "application/x-zmachine" +z3, "application/x-zmachine" +z4, "application/x-zmachine" +z5, "application/x-zmachine" +z6, "application/x-zmachine" +z7, "application/x-zmachine" +z8, "application/x-zmachine" +xaml, "application/xaml+xml" +xdf, "application/xcap-diff+xml" +xenc, "application/xenc+xml" +xhtml, "application/xhtml+xml" +xht, "application/xhtml+xml" +xml, "application/xml" +xsl, "application/xml" +dtd, "application/xml-dtd" +xop, "application/xop+xml" +xpl, "application/xproc+xml" +xslt, "application/xslt+xml" +xspf, "application/xspf+xml" +mxml, "application/xv+xml" +xhvml, "application/xv+xml" +xvml, "application/xv+xml" +xvm, "application/xv+xml" +yang, "application/yang" +yin, "application/yin+xml" +zip, "application/zip" +adp, "audio/adpcm" +au, "audio/basic" +snd, "audio/basic" +mid, "audio/midi" +midi, "audio/midi" +kar, "audio/midi" +rmi, "audio/midi" +mp4a, "audio/mp4" +mpga, "audio/mpeg" +mp2, "audio/mpeg" +mp2a, "audio/mpeg" +mp3, "audio/mpeg" +m2a, "audio/mpeg" +m3a, "audio/mpeg" +oga, "audio/ogg" +ogg, "audio/ogg" +spx, "audio/ogg" +s3m, "audio/s3m" +sil, "audio/silk" +uva, "audio/vnd.dece.audio" +uvva, "audio/vnd.dece.audio" +eol, "audio/vnd.digital-winds" +dra, "audio/vnd.dra" +dts, "audio/vnd.dts" +dtshd, "audio/vnd.dts.hd" +lvp, "audio/vnd.lucent.voice" +pya, "audio/vnd.ms-playready.media.pya" +ecelp4800, "audio/vnd.nuera.ecelp4800" +ecelp7470, "audio/vnd.nuera.ecelp7470" +ecelp9600, "audio/vnd.nuera.ecelp9600" +rip, "audio/vnd.rip" +weba, "audio/webm" +aac, "audio/x-aac" +aif, "audio/x-aiff" +aiff, "audio/x-aiff" +aifc, "audio/x-aiff" +caf, "audio/x-caf" +flac, "audio/x-flac" +mka, "audio/x-matroska" +m3u, "audio/x-mpegurl" +wax, "audio/x-ms-wax" +wma, "audio/x-ms-wma" +ram, "audio/x-pn-realaudio" +ra, "audio/x-pn-realaudio" +rmp, "audio/x-pn-realaudio-plugin" +wav, "audio/x-wav" +xm, "audio/xm" +cdx, "chemical/x-cdx" +cif, "chemical/x-cif" +cmdf, "chemical/x-cmdf" +cml, "chemical/x-cml" +csml, "chemical/x-csml" +xyz, "chemical/x-xyz" +bmp, "image/bmp" +cgm, "image/cgm" +g3, "image/g3fax" +gif, "image/gif" +ief, "image/ief" +jpeg, "image/jpeg" +jpg, "image/jpeg" +jpe, "image/jpeg" +ktx, "image/ktx" +png, "image/png" +btif, "image/prs.btif" +sgi, "image/sgi" +svg, "image/svg+xml" +svgz, "image/svg+xml" +tiff, "image/tiff" +tif, "image/tiff" +psd, "image/vnd.adobe.photoshop" +uvi, "image/vnd.dece.graphic" +uvvi, "image/vnd.dece.graphic" +uvg, "image/vnd.dece.graphic" +uvvg, "image/vnd.dece.graphic" +sub, "text/vnd.dvb.subtitle" +djvu, "image/vnd.djvu" +djv, "image/vnd.djvu" +dwg, "image/vnd.dwg" +dxf, "image/vnd.dxf" +fbs, "image/vnd.fastbidsheet" +fpx, "image/vnd.fpx" +fst, "image/vnd.fst" +mmr, "image/vnd.fujixerox.edmics-mmr" +rlc, "image/vnd.fujixerox.edmics-rlc" +mdi, "image/vnd.ms-modi" +wdp, "image/vnd.ms-photo" +npx, "image/vnd.net-fpx" +wbmp, "image/vnd.wap.wbmp" +xif, "image/vnd.xiff" +webp, "image/webp" +3ds, "image/x-3ds" +ras, "image/x-cmu-raster" +cmx, "image/x-cmx" +fh, "image/x-freehand" +fhc, "image/x-freehand" +fh4, "image/x-freehand" +fh5, "image/x-freehand" +fh7, "image/x-freehand" +ico, "image/x-icon" +sid, "image/x-mrsid-image" +pcx, "image/x-pcx" +pic, "image/x-pict" +pct, "image/x-pict" +pnm, "image/x-portable-anymap" +pbm, "image/x-portable-bitmap" +pgm, "image/x-portable-graymap" +ppm, "image/x-portable-pixmap" +rgb, "image/x-rgb" +tga, "image/x-tga" +xbm, "image/x-xbitmap" +xpm, "image/x-xpixmap" +xwd, "image/x-xwindowdump" +eml, "message/rfc822" +mime, "message/rfc822" +igs, "model/iges" +iges, "model/iges" +msh, "model/mesh" +mesh, "model/mesh" +silo, "model/mesh" +dae, "model/vnd.collada+xml" +dwf, "model/vnd.dwf" +gdl, "model/vnd.gdl" +gtw, "model/vnd.gtw" +mts, "model/vnd.mts" +vtu, "model/vnd.vtu" +wrl, "model/vrml" +vrml, "model/vrml" +x3db, "model/x3d+binary" +x3dbz, "model/x3d+binary" +x3dv, "model/x3d+vrml" +x3dvz, "model/x3d+vrml" +x3d, "model/x3d+xml" +x3dz, "model/x3d+xml" +appcache, "text/cache-manifest" +ics, "text/calendar" +ifb, "text/calendar" +css, "text/css" +csv, "text/csv" +html, "text/html" +htm, "text/html" +n3, "text/n3" +txt, "text/plain" +text, "text/plain" +conf, "text/plain" +def, "text/plain" +list, "text/plain" +log, "text/plain" +in, "text/plain" +dsc, "text/prs.lines.tag" +rtx, "text/richtext" +sgml, "text/sgml" +sgm, "text/sgml" +tsv, "text/tab-separated-values" +t, "text/troff" +tr, "text/troff" +roff, "text/troff" +man, "text/troff" +me, "text/troff" +ms, "text/troff" +ttl, "text/turtle" +uri, "text/uri-list" +uris, "text/uri-list" +urls, "text/uri-list" +vcard, "text/vcard" +curl, "text/vnd.curl" +dcurl, "text/vnd.curl.dcurl" +scurl, "text/vnd.curl.scurl" +mcurl, "text/vnd.curl.mcurl" +fly, "text/vnd.fly" +flx, "text/vnd.fmi.flexstor" +gv, "text/vnd.graphviz" +3dml, "text/vnd.in3d.3dml" +spot, "text/vnd.in3d.spot" +jad, "text/vnd.sun.j2me.app-descriptor" +wml, "text/vnd.wap.wml" +wmls, "text/vnd.wap.wmlscript" +s, "text/x-asm" +asm, "text/x-asm" +c, "text/x-c" +cc, "text/x-c" +cxx, "text/x-c" +cpp, "text/x-c" +h, "text/x-c" +hh, "text/x-c" +dic, "text/x-c" +f, "text/x-fortran" +for, "text/x-fortran" +f77, "text/x-fortran" +f90, "text/x-fortran" +java, "text/x-java-source" +opml, "text/x-opml" +p, "text/x-pascal" +pas, "text/x-pascal" +nfo, "text/x-nfo" +etx, "text/x-setext" +sfv, "text/x-sfv" +uu, "text/x-uuencode" +vcs, "text/x-vcalendar" +vcf, "text/x-vcard" +3gp, "video/3gpp" +3g2, "video/3gpp2" +h261, "video/h261" +h263, "video/h263" +h264, "video/h264" +jpgv, "video/jpeg" +jpm, "video/jpm" +jpgm, "video/jpm" +mj2, "video/mj2" +mjp2, "video/mj2" +mp4, "video/mp4" +mp4v, "video/mp4" +mpg4, "video/mp4" +mpeg, "video/mpeg" +mpg, "video/mpeg" +mpe, "video/mpeg" +m1v, "video/mpeg" +m2v, "video/mpeg" +ogv, "video/ogg" +qt, "video/quicktime" +mov, "video/quicktime" +uvh, "video/vnd.dece.hd" +uvvh, "video/vnd.dece.hd" +uvm, "video/vnd.dece.mobile" +uvvm, "video/vnd.dece.mobile" +uvp, "video/vnd.dece.pd" +uvvp, "video/vnd.dece.pd" +uvs, "video/vnd.dece.sd" +uvvs, "video/vnd.dece.sd" +uvv, "video/vnd.dece.video" +uvvv, "video/vnd.dece.video" +dvb, "video/vnd.dvb.file" +fvt, "video/vnd.fvt" +mxu, "video/vnd.mpegurl" +m4u, "video/vnd.mpegurl" +pyv, "video/vnd.ms-playready.media.pyv" +uvu, "video/vnd.uvvu.mp4" +uvvu, "video/vnd.uvvu.mp4" +viv, "video/vnd.vivo" +webm, "video/webm" +f4v, "video/x-f4v" +fli, "video/x-fli" +flv, "video/x-flv" +m4v, "video/x-m4v" +mkv, "video/x-matroska" +mk3d, "video/x-matroska" +mks, "video/x-matroska" +mng, "video/x-mng" +asf, "video/x-ms-asf" +asx, "video/x-ms-asf" +vob, "video/x-ms-vob" +wm, "video/x-ms-wm" +wmv, "video/x-ms-wmv" +wmx, "video/x-ms-wmx" +wvx, "video/x-ms-wvx" +avi, "video/x-msvideo" +movie, "video/x-sgi-movie" +smv, "video/x-smv" +ice, "x-conference/x-cooltalk" +zst, "application/zstd" +gz, "application/gzip" diff --git a/src/sql.c b/src/sql.c new file mode 100644 index 0000000..6054745 --- /dev/null +++ b/src/sql.c @@ -0,0 +1,13 @@ +#include "sql.h" + +const char +*INIT_SQL = + "CREATE TABLE IF NOT EXISTS links (" + "id INTEGER PRIMARY KEY," + "url STRING NOT NULL," + "created INTEGER NOT NULL" + ");", +*INSERT_SQL = + "INSERT INTO links (url,created)" + "VALUES (?1, ?2);", +*DELETE_SQL = "DELETE FROM links WHERE id = ?1;"; diff --git a/www/docs.html b/www/docs.html new file mode 100644 index 0000000..a2fa287 --- /dev/null +++ b/www/docs.html @@ -0,0 +1,116 @@ +<!DOCTYPE html> +<html> + <style> + table{border-collapse:collapse;} + table,td,th{border:1px solid #000;padding:10px;} + span,table td{font-family:monospace;} + table td:nth-child(3),.uns{font-family:unset;} + table caption{font-weight:bold;margin:10px;} + </style> + <head> + <title>JAC's link shortener</title> + </head> + <body> + <h3>What is this?</h3> + <p>This is a link shortener. A sort of a backend practice, but it should run 24/7/53/<While I pay for my VPS> after I finish writing it.</p> + <h3>Documentation conventions</h3> + <p>All documentation assumes that the server is running <span>server.com</span> on port 80 without https, and you are trying to shorten a link to <span>example.com</span>.</p> + <p>All (non-global) parameters are mandatory, unless marked with question mark <span>?</span> sign.</p> + <p>PATH means part in url after the first slash: e.g. in link <span>http://server.com/short</span>, "short" is PATH, while URL means full shortened link.</p> + <h3>API reference</h3> + <p>The API follows this convention: everything is done through GET requests, client supplies all necessary parameters in URLencoded format. + Whatever server returns depends on parameters; it may be application/json (for programmable API) OR text/html (to render in HTML)</p> + <p>Example request: <span>http://ln.twistea.su/api/linkadd?url=https%3A%2F%2Fexample.com&format=html</span>.<br> + This request may return something like: <span><a href="http://server.com/DEADF00D">your link: DEADF00D</a></span></p> + <p>Note: server may return json string like <span>null</span> or <span>true</span>: according to + <a href="https://www.rfc-editor.org/rfc/rfc8259#section-13">rfc-8259</a>, this is valid json and clients have to handle this accordingly.</p> + <p>Errors are returned like this: <span>{"error": description}</span> (some endpoints may return null / false to indicate failure). + Description may be any of the following: <ul> + <li><span>insufficient arguments</span>: not enough parameters provided to the endpoint.</li> + <li><span>invalid arguments</span>: argument's type/value does not match with what server expects.</li> + <li><span>occupied</span>: the path at which the link was attempted to be created is occupied already.</li> + <li><span>server error</span>: something went wrong on the server. Will include additional json field "what" with error message.</li> + <li><span>unknown</span>: server does not know what the hell went wrong</li> + </ul>Plese note that the HTTP return status for malformed request may be BAD_REQUEST (400) or INTERNAL_SERVER_ERROR (500)</p> + <table> + <thead> + <caption>Table 1. Global parameters (applicable to all endpoints)</caption> + <tr> + <th>Key</th> + <th>Value</th> + <th>Description</th> + <th>Default</th> + </tr> + </thead> + <tbody> + <tr> + <td>format</td> + <td><span>json | html</span></td> + <td>How to return the result of request. <tt>html</tt> should only be used to embed it in a web page.</td> + <td><span>json</span></td> + </tr> + <!-- + <tr> + <td></td> + <td></td> + <td></td> + <td></td> + </tr> + --> + </tbody> + </table> + <table> + <thead> + <caption>Table 2. Endpoints description</caption> + <tr> + <th rowspan=2>Endpoint</th> + <th colspan=2>Parameters</th> + <th rowspan=2>Response object</th> + </tr> + <tr> + <th>key</th> + <th>value</th> + </tr> + </thead> + <tbody> + <tr> + <td rowspan=2>/api/linkadd</td> + <td>url</td> + <td>string: a link to be shortened</td> + <td rowspan=2>{"url": "https://server.com/PATH"} | error + </td> + </tr> + <tr> + <td>try?</td> + <td class="uns">string: <span>PATH</span> to try to put link under <br> + (if not occupied, WITHOUT <span>https://server.com/</span>)</td> + </tr> + <tr> + <td>/api/linkdel</td> + <td>path</td> + <td>string: PATH to delete the link from</td> + <td>true | false</td> + </tr> + <tr> + <td>/api/linkget</td> + <td>path</td> + <td>string: PATH to get link info from</td> + <td>{"url": "original url", created: int unix_timestamp}<br> + OR null + </td> + </tr> + <tr> + <td>/PATH</td> + <td colspan=3 class="uns">Returns an HTML page with redirection message and returns <span>302 (HTTP_FOUND)</span>, with + <span>Location</span> header set to shortened URL</td> + </tr> + <td>/getargs</td> + <td colspan=3 class="uns">Get an HTML page with a list of all parameters provided to the endpoint. Used for testing.</td> + </tr> + + </tbody> + </table> + <h3> Examples of API usage: </h3> + <p>This section is unfinished.</p> + </body> +</html> diff --git a/www/form.html b/www/form.html new file mode 100644 index 0000000..79eb7b1 --- /dev/null +++ b/www/form.html @@ -0,0 +1,21 @@ +<!DOCTYPE html> + +<html> + <head><meta charset="utf-8"></head> + <body> + <form action="/getargs?a=b&c=d&" method="get" class="form-example" target="tgt"> + <div> + <label>The url ot be shortened:</label> + <input type="text" name="url" required/> + </div> + <div> + <label>Try to allocate at this addess (optional):</label> + <input type="text" name="try"/> + </div> + <input name="format" value="htlm" hidden="true"/> + <input type="submit" value="Test arguments" /> + </form> + + <iframe name="tgt"/> + </body> +</html> diff --git a/www/index.html b/www/index.html new file mode 100644 index 0000000..a2af744 --- /dev/null +++ b/www/index.html @@ -0,0 +1,32 @@ +<!DOCTYPE html> +<html> + <style> + body{margin:auto;width:40vw;} + iframe{height:2em;margin:auto;width:100%;} + label{display:inline-block;text-align:right;width:12vw;} + input{width:25vw;margin:0.5em;} + input[type=submit]{width:50%;margin:0.5em auto;display:block;} + h1,h3,p{text-align:center;} + </style> + <head> + <title>JAC's link shortener</title> + </head> + <body> + <h1>JAC's link shortener</h1> + <p>Try it out!</p> + <form action="/api/linkadd" target="result"> + <div> + <label>URL:</label> + <input type="url"name="url"required/> + </div> + <div> + <label>Path (optional):</label> + <input type="text"name="try"/> + </div> + <input name="format"value="html"hidden/> + <input type="submit"value="Shorten URL!"/> + </form> + <h3>Result:</h3> + <iframe name="result"scrolling="no"/> + </body> +</html> |