#include #include #include #include #include #include #include #include #define CONTAINER_IMPLEMENTATION #define JACSON_IMPLEMENTATION #define JACSON_EXPORT_RSNPRINTF #include #include "common.h" #include "sql.h" const char *const JSON_ERROR = "{\"error\":\"%s\"}"; const char *const HTML_ERROR = "Error: %s"; 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 = ""; const char *const HTML_EPILOGUE = ""; 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"} }; // 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 }; key = "format"; if ( (val = MHD_lookup_connection_value(connection, MHD_GET_ARGUMENT_KIND, key)) && !strcmp(val, "html")) ret.format = GA_FMT_HTML; return ret; } // 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) { struct sb *html = cls; html->ln += __jacson_rsnprintf(&html->str, &html->sz, html->ln, "
  • %s: %s

  • ", key, value); 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, "

    List of arguments

      "); MHD_get_connection_values(connection, MHD_GET_ARGUMENT_KIND, &arg_builder, &html); html.ln += __jacson_rsnprintf(&html.str, &html.sz, html.ln, "
    "); 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); } // API, path: /api/linkadd struct MHD_Response *ENDP_api_linkadd(struct MHD_Connection *connection, int *status) { const char *url = NULL, *path = NULL; char newurl[12] = {0}, *newurlp = 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 = db_error_status(DBERROR_ARGS); sbprintf(&resp, fmts[glob.format].error, INSUFFICIENT_ARGUMENTS); goto exit; } path = MHD_lookup_connection_value(connection, MHD_GET_ARGUMENT_KIND, "try"); if (*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)); goto exit; } if (glob.format == GA_FMT_JSON) sbprintf(&resp, "{\"url\":\"%s\"}", newurlp); else sbprintf(&resp, "%sYour URL: /%s%s", HTML_PROLOGUE, newurlp, newurlp, 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) { }