aboutsummaryrefslogtreecommitdiffstats
path: root/src/endpoints.c
diff options
context:
space:
mode:
authorjustanothercatgirl <sotov@twistea.su>2025-03-27 12:52:11 +0300
committerjustanothercatgirl <sotov@twistea.su>2025-03-27 12:52:11 +0300
commit82742d5d13dc7b0691a79c79f8e62782fcb16e10 (patch)
tree48d077549ed667d2a54171b82eb7608cb8edaf3e /src/endpoints.c
parent8542ec17d3df989f3df9fd03af7a447bf730dc13 (diff)
Doing SQL (work in progress)
Diffstat (limited to 'src/endpoints.c')
-rw-r--r--src/endpoints.c195
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) { }