#include #include #include #include #include "assets.h" #include "../lib/md4c/src/entity.h" #include "../lib/md4c/src/entity.c" #include "../lib/md4c/src/md4c.h" #include "../lib/md4c/src/md4c.c" #include "../lib/md4c/src/md4c-html.h" #include "../lib/md4c/src/md4c-html.c" KORE_SECCOMP_FILTER("clog", KORE_SYSCALL_ALLOW(getdents64) ) int init(int); int post(struct http_request *); int posts(struct http_request *); int render_posts(struct http_request *, const char *); static void process_md_output(const MD_CHAR *, MD_SIZE size, void *); static int render_md(char *, struct kore_buf *); static const char *database = "db"; // Called when this module is loaded (see config) int init(int state) { // Register the database int err = kore_pgsql_register( database, "host=postgres port=5432 user=postgres password=postgres dbname=clog sslmode=disable" ); return err; } int post(struct http_request *req) { const char *resource; resource = req->path + strlen("/posts/"); kore_log(LOG_DEBUG, "Resource /posts/%s", resource); return render_posts(req, resource); } int posts(struct http_request *req) { return render_posts(req, NULL); } int render_posts(struct http_request *req, const char *resource) { // Errors int err; // Buffer for response struct kore_buf *resp_buf = kore_buf_alloc(0); // SQL vars struct kore_pgsql sql; int row, rows; // Post attributes/query results. char *id, *title, *created_at, *body; // Setup SQL kore_pgsql_init(&sql); // Initialise our kore_pgsql data structure with the database name // we want to connect to (note that we registered this earlier with // kore_pgsql_register()). We also say we will perform a synchronous // query (KORE_PGSQL_SYNC). err = kore_pgsql_setup(&sql, database, KORE_PGSQL_SYNC); kore_log(LOG_ERR, "kore_pgsql_setup: %d", err); if (!err) { kore_pgsql_logerror(&sql); goto out; } // Start writing HTML. kore_buf_append(resp_buf, asset_index_begin_html, asset_len_index_begin_html); // Query for posts, check for error. if (!resource) { // Query all posts. err = kore_pgsql_query( &sql, "SELECT id, title, created_at::DATE, body FROM posts " "ORDER BY updated_at DESC;" ); } else { // Query a post. err = kore_pgsql_query_params( &sql, "SELECT id, title, created_at::DATE, body FROM posts " "WHERE id = $1 " "ORDER BY updated_at DESC;", 0, 1, KORE_PGSQL_PARAM_TEXT(resource) ); } if (!err) { kore_pgsql_logerror(&sql); goto out; } // Iterate over posts and render them. rows = kore_pgsql_ntuples(&sql); for (row = 0; row < rows; row++) { id = kore_pgsql_getvalue(&sql, row, 0); title = kore_pgsql_getvalue(&sql, row, 1); created_at = kore_pgsql_getvalue(&sql, row, 2); body = kore_pgsql_getvalue(&sql, row, 3); kore_log(LOG_NOTICE, "id: '%s'; title '%s'", id, title); // Allocate a buffer to render the markdown as HTML into. struct kore_buf *html_buf = kore_buf_alloc(0); // Render MD. if (!render_md(body, html_buf)) { kore_log(LOG_ERR, "Error rendering markdown for entry %s.", id); kore_buf_free(html_buf); continue; } // Append rendered MD post. kore_buf_appendf( resp_buf, (const char *) asset_post_html, title, created_at, kore_buf_stringify(html_buf, NULL) ); kore_buf_free(html_buf); } out: ; // Finish building response. kore_buf_append(resp_buf, asset_index_end_html, asset_len_index_end_html); http_response_header(req, "content-type", "text/html; charset=utf-8"); http_response(req, HTTP_STATUS_OK, resp_buf->data, resp_buf->offset); // Cleanup. kore_pgsql_cleanup(&sql); kore_buf_free(resp_buf); return (KORE_RESULT_OK); } static int render_md(char *in, struct kore_buf *out) { int err; static unsigned parser_flags = 0; static unsigned renderer_flags = MD_HTML_FLAG_DEBUG; err = md_html( in, (MD_SIZE) strlen(in), process_md_output, (void*) out, parser_flags, renderer_flags ); if(err != 0) { kore_log(LOG_ERR, "Parsing Markdown failed.\n"); return -1; } return 1; } static void process_md_output(const MD_CHAR *html, MD_SIZE size, void *buf) { kore_buf_append((struct kore_buf *) buf, (const void *) html, (size_t) size); }