aboutsummaryrefslogtreecommitdiffstats
path: root/src/endpoints.c
blob: a4ac35a6a86cc2a69795a674863cda943a45e73b (plain)
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 : "&lt;none&gt;");
	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);
}