4 #include <microhttpd.h>
5 #include <yajl/yajl_gen.h>
9 #include "canned_responses.h"
13 yajl_gen_config yajl_c = { 0, 0 };
16 struct MHD_PostProcessor *pp;
22 struct MHD_PostProcessor *pp;
45 ssize_t GET_generate_list(void *cls, uint64_t pos, char *buf, size_t max) {
46 struct get_state *gs = cls;
47 const unsigned char *ybuf;
53 yajl_gen_get_buf(gs->g, &ybuf, &len);
54 size_t bytes_remaining = len - gs->yoff;
55 if (bytes_remaining > max) {
56 memcpy(buf, ybuf + gs->yoff, max);
60 memcpy(buf, ybuf + gs->yoff, bytes_remaining);
62 yajl_gen_clear(gs->g);
63 return bytes_remaining;
70 if (pos == 0) { /* Start iterating */
71 yajl_gen_array_open(gs->g);
74 /* Snarf one record */
75 json_generate_one_record(gs->g, NULL, gs->b, gs->entries[gs->i]);
78 yajl_gen_array_close(gs->g);
84 yajl_gen_get_buf(gs->g, &ybuf, &len);
86 memcpy(buf, ybuf, max);
90 memcpy(buf, ybuf, len);
91 yajl_gen_clear(gs->g);
96 void GET_generate_list_free(void *cls) {
97 struct get_state *gs = cls;
100 yajl_gen_free(gs->g);
105 ssize_t GET_generate_taglist(void *cls, uint64_t pos, char *buf, size_t max) {
106 struct tag_state *ts = cls;
108 const unsigned char *ybuf;
112 yajl_gen_get_buf(ts->g, &ybuf, &len);
113 size_t bytes_remaining = len - ts->yoff;
114 if (bytes_remaining > max) {
115 memcpy(buf, ybuf + ts->yoff, max);
119 memcpy(buf, ybuf + ts->yoff, bytes_remaining);
121 yajl_gen_clear(ts->g);
122 return bytes_remaining;
129 if (pos == 0) { /* Start iterating */
130 yajl_gen_array_open(ts->g);
133 /* Snarf one record */
134 b = blerg_open(ts->results[ts->i].author);
136 json_generate_one_record(ts->g, ts->results[ts->i].author, b, ts->results[ts->i].record);
141 yajl_gen_array_close(ts->g);
147 yajl_gen_get_buf(ts->g, &ybuf, &len);
149 memcpy(buf, ybuf, max);
153 memcpy(buf, ybuf, len);
154 yajl_gen_clear(ts->g);
159 void GET_generate_taglist_free(void *cls) {
160 struct tag_state *ts = cls;
162 yajl_gen_free(ts->g);
167 int POST_auth_iterator(void *cls, enum MHD_ValueKind kind, const char *key, const char *filename, const char *content_type, const char *transfer_encoding, const char *data, uint64_t off, size_t size) {
168 struct auth_state *as = cls;
170 if (strncmp(key, "username", 9) == 0) {
171 if (size > 32) size = 32;
172 memcpy(as->username, data, size);
173 as->username[size] = 0;
174 } else if (strncmp(key, "password", 9) == 0) {
175 if (size > 32) size = 32;
176 memcpy(as->password, data, size);
177 as->password[size] = 0;
183 int POST_put_iterator(void *cls, enum MHD_ValueKind kind, const char *key, const char *filename, const char *content_type, const char *transfer_encoding, const char *data, uint64_t off, size_t size) {
184 struct put_state *ps = cls;
186 if (strncmp(key, "data", 5) == 0) {
187 if (ps->data == NULL) {
188 ps->data_size = size;
189 ps->data = malloc(size);
191 if (ps->data_size + size > MAX_RECORD_SIZE) {
192 size = MAX_RECORD_SIZE - ps->data_size;
194 ps->data_size += size;
195 ps->data = realloc(ps->data, ps->data_size);
197 memcpy(ps->data + off, data, size);
198 if (ps->data_size == MAX_RECORD_SIZE)
200 } else if (strncmp(key, "username", 9) == 0) {
201 if (size > 32) size = 32;
202 memcpy(ps->username, data, size);
203 ps->username[size] = 0;
209 struct MHD_Response *create_response_for_range(struct blerg *b, uint64_t from, uint64_t to) {
210 struct MHD_Response *response;
211 struct get_state *gs = malloc(sizeof(struct get_state));
214 uint64_t record_count = blerg_get_record_count(b);
216 if (from > to || from >= record_count || to >= record_count || to - from > 99) {
222 gs->entries = make_sequential_list(from, to);
225 gs->g = yajl_gen_alloc(&yajl_c, NULL);
226 gs->yoff = gs->done = 0;
228 response = MHD_create_response_from_callback(-1, 262144, &GET_generate_list, gs, &GET_generate_list_free);
233 struct MHD_Response *create_tag_response(struct tag *results, uint64_t len) {
234 struct tag_state *ts = malloc(sizeof(struct tag_state));
235 ts->g = yajl_gen_alloc(&yajl_c, NULL);
236 ts->results = results;
238 ts->yoff = ts->done = 0;
240 return MHD_create_response_from_callback(-1, 262144, &GET_generate_taglist, ts, &GET_generate_taglist_free);
244 ahc_derp (void *cls, struct MHD_Connection *connection, const char *url, const char *method,
245 const char *version, const char *upload_data, size_t *upload_data_size, void **ptr) {
246 struct MHD_Response *response;
248 struct url_info info;
251 if (strncmp(url, "/get", 4) == 0 && strlen(url) > 4) {
253 if (strcmp(method, MHD_HTTP_METHOD_GET) != 0)
254 return respond_405(connection);
261 return respond_404(connection);
263 ret = parse_url_info(url + 5, &info);
264 if ((ret & URL_INFO_AUTHOR) == 0)
265 return respond_404(connection);
267 if (!blerg_exists(info.author))
268 return respond_404(connection);
272 struct blerg *b = blerg_open(info.author);
274 if ((ret & URL_INFO_RECORD) && (ret & URL_INFO_RECORD_TO)) {
275 response = create_response_for_range(b, info.record, info.record_to);
276 } else if (ret & URL_INFO_RECORD) {
277 ret = blerg_fetch(b, info.record, &data, &len);
281 return respond_404(connection);
282 response = MHD_create_response_from_data(len, data, MHD_YES, MHD_NO);
284 uint64_t record_count, from, to;
285 record_count = blerg_get_record_count(b);
286 if (record_count == 0) {
288 response = MHD_create_response_from_data(2, "[]", MHD_NO, MHD_NO);
290 to = record_count - 1;
291 from = (record_count > 50 ? to - 49 : 0);
292 response = create_response_for_range(b, from, to);
296 if (response == NULL) {
298 return respond_JSON_Failure(connection);
301 ret = MHD_queue_response(connection, MHD_HTTP_OK, response);
302 MHD_destroy_response(response);
304 } else if (strncmp(url, "/tag", 4) == 0 && strlen(url) > 4) {
306 if (strcmp(method, MHD_HTTP_METHOD_GET) != 0)
307 return respond_405(connection);
314 return respond_404(connection);
316 ret = parse_url_info(url + 5, &info);
317 if ((ret & URL_INFO_AUTHOR) == 0)
318 return respond_404(connection);
320 if (!tag_exists(info.author))
321 return respond_404(connection);
324 struct tag *taglist = tag_list(info.author, 0, &recs, -1);
327 response = MHD_create_response_from_data(2, "[]", MHD_NO, MHD_NO);
329 response = create_tag_response(taglist, recs);
332 if (response == NULL)
333 return respond_JSON_Failure(connection);
335 ret = MHD_queue_response(connection, MHD_HTTP_OK, response);
336 MHD_destroy_response(response);
339 } else if (strncmp(url, "/put", 4) == 0) {
340 struct put_state *ps = (struct put_state *) *ptr;
342 if (strcmp(method, MHD_HTTP_METHOD_POST) != 0)
343 return respond_405(connection);
346 return respond_404(connection);
350 struct put_state *ps = malloc(sizeof(struct put_state));
353 ps->pp = MHD_create_post_processor(connection, 16384, &POST_put_iterator, ps);
359 if (*upload_data_size) {
360 MHD_post_process(ps->pp, upload_data, *upload_data_size);
361 *upload_data_size = 0;
365 if (ps->data == NULL || ps->data_size == 0 || ps->username[0] == 0)
366 return respond_JSON_Failure(connection);
368 const char *given_token = MHD_lookup_connection_value(connection, MHD_COOKIE_KIND, "auth");
369 if (!auth_check_token(ps->username, given_token))
370 return respond_JSON_Failure(connection);
372 struct blerg *b = blerg_open(ps->username);
374 return respond_JSON_Failure(connection);
375 ret = blerg_store(b, ps->data, ps->data_size);
378 return respond_JSON_Failure(connection);
380 MHD_destroy_post_processor(ps->pp);
385 return respond_JSON_Success(connection);
386 } else if (strncmp(url, "/info", 5) == 0) {
390 if (strcmp(method, MHD_HTTP_METHOD_GET) != 0)
391 return respond_405(connection);
397 return respond_404(connection);
399 ret = parse_url_info(url + 6, &info);
400 if ((ret & URL_INFO_AUTHOR) == 0)
401 return respond_404(connection);
403 if (!blerg_exists(info.author))
404 return respond_404(connection);
408 struct blerg *b = blerg_open(info.author);
409 uint64_t record_count = blerg_get_record_count(b);
413 yajl_gen g = yajl_gen_alloc(&yajl_c, NULL);
414 yajl_gen_map_open(g);
415 yajl_gen_string(g, "record_count", 12);
416 snprintf(number, 21, "%llu", record_count);
417 yajl_gen_string(g, number, strlen(number));
418 yajl_gen_map_close(g);
420 const unsigned char *ybuf;
421 yajl_gen_get_buf(g, &ybuf, &len);
423 response = MHD_create_response_from_data(len, (void *)ybuf, MHD_NO, MHD_YES);
424 ret = MHD_queue_response(connection, MHD_HTTP_OK, response);
425 MHD_destroy_response(response);
430 } else if (strncmp(url, "/create", 8) == 0) {
431 struct auth_state *as = (struct auth_state *) *ptr;
434 if (strcmp(method, MHD_HTTP_METHOD_POST) != 0)
435 return respond_405(connection);
437 struct auth_state *as = malloc(sizeof(struct auth_state));
438 as->username[0] = as->password[0] = 0;
439 as->pp = MHD_create_post_processor(connection, 1024, &POST_auth_iterator, as);
444 if (*upload_data_size) {
445 MHD_post_process(as->pp, upload_data, *upload_data_size);
446 *upload_data_size = 0;
450 if (as->username[0] == 0 || as->password[0] == 0)
451 return respond_JSON_Failure(connection);
453 if (blerg_exists(as->username))
454 return respond_JSON_Failure(connection);
456 struct blerg *b = blerg_open(as->username);
458 auth_set_password(as->username, as->password);
460 MHD_destroy_post_processor(as->pp);
464 return respond_JSON_Success(connection);
465 } else if (strncmp(url, "/login", 7) == 0) {
466 struct auth_state *as = (struct auth_state *) *ptr;
469 if (strcmp(method, MHD_HTTP_METHOD_POST) != 0)
470 return respond_405(connection);
472 struct auth_state *as = malloc(sizeof(struct auth_state));
473 as->username[0] = as->password[0] = 0;
474 as->pp = MHD_create_post_processor(connection, 1024, &POST_auth_iterator, as);
479 if (*upload_data_size) {
480 MHD_post_process(as->pp, upload_data, *upload_data_size);
481 *upload_data_size = 0;
485 if (as->username[0] == 0 || as->password[0] == 0)
486 return respond_JSON_Failure(connection);
488 if (!auth_login(as->username, as->password))
489 return respond_JSON_Failure(connection);
491 response = MHD_create_response_from_data(strlen(JSON_SUCCESS), JSON_SUCCESS, MHD_NO, MHD_NO);
493 char *token = auth_get_token(as->username);
495 snprintf(data, 512, "auth=%s", token);
496 MHD_add_response_header(response, "Set-Cookie", data);
500 MHD_destroy_post_processor(as->pp);
504 ret = MHD_queue_response(connection, MHD_HTTP_OK, response);
505 MHD_destroy_response(response);
508 } else if (strncmp(url, "/logout", 8) == 0) {
509 struct auth_state *as = (struct auth_state *) *ptr;
512 if (strcmp(method, MHD_HTTP_METHOD_POST) != 0)
513 return respond_405(connection);
515 struct auth_state *as = malloc(sizeof(struct auth_state));
516 as->username[0] = as->password[0] = 0;
517 as->pp = MHD_create_post_processor(connection, 1024, &POST_auth_iterator, as);
522 if (*upload_data_size) {
523 MHD_post_process(as->pp, upload_data, *upload_data_size);
524 *upload_data_size = 0;
528 const char *given_token = MHD_lookup_connection_value(connection, MHD_COOKIE_KIND, "auth");
529 if (auth_check_token(as->username, given_token)) {
530 auth_logout(as->username);
531 return respond_JSON_Success(connection);
533 return respond_JSON_Failure(connection);
536 return respond_404(connection);
541 int main(int argc, char *argv[]) {
542 struct MHD_Daemon *daemon;
548 daemon = MHD_start_daemon(MHD_USE_DEBUG, 8080, NULL, NULL, &ahc_derp, NULL, MHD_OPTION_END);
549 if (daemon == NULL) {
550 fprintf(stderr, "Could not start web server\n");
555 FD_ZERO(&rs); FD_ZERO(&ws); FD_ZERO(&es);
556 if (MHD_get_fdset(daemon, &rs, &ws, &es, &max) != MHD_YES) {
557 fprintf(stderr, "Fatal error getting fd sets\n");
560 select(max + 1, &rs, &ws, &es, NULL);
563 MHD_stop_daemon(daemon);