1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
|
#include <stdbool.h>
#include <stdarg.h>
#include <limits.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <microhttpd.h>
#include "common.h"
#include "sql.h"
#include <log.h>
#define CONTAINER_IMPLEMENTATION
#define JACSON_IMPLEMENTATION
#define JACSON_EXPORT_RSNPRINTF
#include <jacson.h>
#define STRINGBUILDER_IMPLEMENTATION
#include <stringbuilder.h>
#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 = "<!DOCTYPE html><html><body>Error: %s</body></html>";
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, "<li><p style=\"font-style:monospace;\">%s: %s</p></li>", 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);
}
|