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 /src/endpoints.c | |
parent | 8542ec17d3df989f3df9fd03af7a447bf730dc13 (diff) |
Doing SQL (work in progress)
Diffstat (limited to 'src/endpoints.c')
-rw-r--r-- | src/endpoints.c | 195 |
1 files changed, 195 insertions, 0 deletions
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) { } |