#include #include #include #include #include #include #include #include "common.h" #include "sql.h" #include #define CONTAINER_IMPLEMENTATION #define JACSON_IMPLEMENTATION #define JACSON_EXPORT_RSNPRINTF #include #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 *HTTPHOSTNAME = "http://127.0.0.1:80"; struct global_args { enum { GA_FMT_JSON = 0, GA_FMT_HTML = 1 } format; }; struct fmt_const { const char *error, *content_type; }; static const struct fmt_const fmts[] = { [GA_FMT_JSON] = {JSON_ERROR,"application/json"}, [GA_FMT_HTML] = {HTML_ERROR,"text/html"} }; 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; } 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) { jac_sb *html = cls; jac_sb_snprintf(html, "
  • %s: %s

  • ", key, value ? value : "<none>"); return MHD_YES; } // path: /getargs 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(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; 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); 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 && *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); jac_sb_snprintf(&resp, fmts[glob.format].error, db_error(err)); goto exit; } 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.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(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(const char *method, struct MHD_Connection *connection, int *status) { return MHD_create_response_from_buffer(4, "TODO", MHD_RESPMEM_PERSISTENT); }