/* $Id$ */ /* * Copyright (c) 2016 Kristaps Dzonsons * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include #include #include #include #include #include #include #include "extern.h" /* * Start with five pages. * As you add more pages, you'll start by giving them an identifier key * in this enum. */ enum page { PAGE_INDEX, PAGE_BOOKS, PAGE_AUTHORS, PAGE_SERIES, PAGE__MAX }; static const char *const pages[PAGE__MAX] = { "index", /* PAGE_INDEX */ "books", /* PAGE_BOOKS */ "authors", /* PAGE_AUTHORS */ "series", /* PAGE_SERIES */ }; /* * Fill out all HTTP secure headers. * Use the existing document's MIME type. */ static void http_alloc(struct kreq *r, enum khttp code) { khttp_head(r, kresps[KRESP_STATUS], "%s", khttps[code]); khttp_head(r, kresps[KRESP_CONTENT_TYPE], "%s", kmimetypes[r->mime]); khttp_head(r, "X-Content-Type-Options", "nosniff"); khttp_head(r, "X-Frame-Options", "DENY"); khttp_head(r, "X-XSS-Protection", "1; mode=block"); } /* * Fill out all headers with http_alloc() then start the HTTP document * body (no more headers after this point!) */ static void http_open(struct kreq *r, enum khttp code) { http_alloc(r, code); khttp_body(r); } static void sendbooks(struct kreq *r) { struct kjsonreq req; http_open(r, KHTTP_200); kjson_open(&req, r); kjson_obj_open(&req); kjson_putstringp($req, "data", "books"); kjson_obj_close(&req); kjson_close(&req); } static void sendauthors(struct kreq *r) { struct kjsonreq req; http_open(r, KHTTP_200); kjson_open(&req, r); kjson_obj_open(&req); kjson_putstringp($req, "data", "authors"); kjson_obj_close(&req); kjson_close(&req); } static void sendseries(struct kreq *r) { struct kjsonreq req; http_open(r, KHTTP_200); kjson_open(&req, r); kjson_obj_open(&req); kjson_putstringp($req, "data", "series"); kjson_obj_close(&req); kjson_close(&req); } static void sendindex(struct kreq *r) { struct kjsonreq req; http_open(r, KHTTP_200); kjson_open(&req, r); kjson_obj_open(&req); kjson_putstringp($req, "data", "index"); kjson_obj_close(&req); kjson_close(&req); } int main(void) { struct kreq r; enum kcgi_err er; struct user *u; /* Log into a separate logfile (not system log). */ kutil_openlog(LOGFILE); /* Actually parse HTTP document. */ er = khttp_parse(&r, keys, KEY__MAX, pages, PAGE__MAX, PAGE_INDEX); if (KCGI_OK != er) { fprintf(stderr, "HTTP parse error: %d\n", er); return(EXIT_FAILURE); } #ifdef __OpenBSD__ if (-1 == pledge("stdio rpath cpath wpath flock fattr", NULL)) { kutil_warn(&r, NULL, "pledge"); khttp_free(&r); return(EXIT_FAILURE); } #endif /* * Front line of defence: make sure we're a proper method, make * sure we're a page, make sure we're a JSON file. */ if (KMETHOD_GET != r.method && KMETHOD_POST != r.method) { http_open(&r, KHTTP_405); khttp_free(&r); return(EXIT_SUCCESS); } else if (PAGE__MAX == r.page || KMIME_APP_JSON != r.mime) { http_open(&r, KHTTP_404); khttp_puts(&r, "Page not found."); khttp_free(&r); return(EXIT_SUCCESS); } if ( ! db_open(&r, DATADIR "/" DATABASE)) { http_open(&r, KHTTP_500); json_emptydoc(&r); khttp_free(&r); return(EXIT_SUCCESS); } switch (r.page) { case (PAGE_INDEX): sendindex(&r); break; case (PAGE_BOOKS): sendbooks(&r); break; case (PAGE_AUTHORS): sendauthors(&r); break; case (PAGE_SERIES): sendseries(&r); break; default: abort(); } db_close(&r); khttp_free(&r); return(EXIT_SUCCESS); }