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
125
126
|
#include <stdbool.h>
#include <stdarg.h>
#include <limits.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <microhttpd.h>
#include <log.h>
#define CONTAINER_IMPLEMENTATION
#define JACSON_IMPLEMENTATION
#define JACSON_EXPORT_RSNPRINTF
#include <jacson.h>
#include "common.h"
#include "sql.h"
const char *const JSON_ERROR = "{\"error\":\"%s\"}";
const char *const HTML_ERROR = "<!DOCTYPE html><html><body>Error: %s</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, *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, "<li><p style=\"font-style:monospace;\">%s: %s</p></li>", 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,
"<!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) 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: <a href=\"/%s\">/%s</a>%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) { }
|