diff options
-rw-r--r-- | README.md | 10 | ||||
-rw-r--r-- | conf/clog.conf | 9 | ||||
-rw-r--r-- | src/clog.c | 110 | ||||
-rwxr-xr-x | tests.py | 25 |
4 files changed, 105 insertions, 49 deletions
@@ -37,3 +37,13 @@ seccomp_tracing no * Have `tests.py` load and drop database. +Add functions: + +get_request_type +render_json_error +render_html_error + +insert_post + +only do HTTP stuff at the edge. + diff --git a/conf/clog.conf b/conf/clog.conf index 0cf3d26..9653e94 100644 --- a/conf/clog.conf +++ b/conf/clog.conf @@ -24,24 +24,19 @@ domain * { route / { handler posts + methods get } route /posts { handler posts - # TODO Handle HTTP POST request. methods get post } route ^/posts/[a-z0-9\-]+$ { - handler post + handler GET_post methods get } - route /toys { - handler toys - methods get post - } - route ^/.*$ { handler redirect } @@ -39,6 +39,7 @@ static const char *accept_json = "application/json"; static const char *database = "db"; static const char * const error_msg[] = { + [HTTP_STATUS_BAD_REQUEST] = "There was an error processing the request data.", [HTTP_STATUS_NOT_FOUND] = "Resource not found.", [HTTP_STATUS_INTERNAL_ERROR] = "There was an error processing the request.", }; @@ -50,15 +51,12 @@ int validate_uuid(const char *input); int redirect(struct http_request *req); -int post(struct http_request *req); +int GET_post(struct http_request *req); +int POST_post(struct http_request *req); int posts(struct http_request *req); int render_posts(struct http_request *req, const char *resource); -int render_posts_query(struct post_request *post_req); - -int toys(struct http_request *req); -int get_toys(struct http_request *req); -int post_toys(struct http_request *req); +int query_posts(struct post_request *post_req); static void process_md_output(const MD_CHAR *, MD_SIZE size, void *); static int render_md(const char *, struct kore_buf *); @@ -115,18 +113,25 @@ redirect(struct http_request *req) { } int -post(struct http_request *req) { +GET_post(struct http_request *req) { const char *resource = NULL; resource = req->path + strlen("/posts/"); kore_log(LOG_DEBUG, "Resource /posts/%s", resource); - return render_posts(req, resource); + (void) render_posts(req, resource); + + return KORE_RESULT_OK; } int posts(struct http_request *req) { - return render_posts(req, NULL); + if (req->method == HTTP_METHOD_GET) + (void) render_posts(req, NULL); + else if (req->method == HTTP_METHOD_POST) + (void) POST_post(req); + + return KORE_RESULT_OK; } int @@ -154,8 +159,9 @@ render_posts(struct http_request *req, const char *resource) { if (post_req.type == JSON) { http_response_header(post_req.req, "content-type", "application/json; charset=utf-8"); - (void) render_posts_query(&post_req); - if (post_req.resp_status != HTTP_STATUS_OK) { + (void) query_posts(&post_req); + // TOOD: Create a status_ok function + if (post_req.resp_status != HTTP_STATUS_OK && post_req.resp_status != HTTP_STATUS_CREATED) { kore_buf_appendf( post_req.resp_buf, (const char *) asset_error_json, @@ -168,8 +174,8 @@ render_posts(struct http_request *req, const char *resource) { kore_buf_append(post_req.resp_buf, asset_index_begin_html, asset_len_index_begin_html); - (void) render_posts_query(&post_req); - if (post_req.resp_status != HTTP_STATUS_OK) { + (void) query_posts(&post_req); + if (post_req.resp_status != HTTP_STATUS_OK && post_req.resp_status != HTTP_STATUS_CREATED) { kore_buf_appendf( post_req.resp_buf, (const char *) asset_error_html, @@ -194,7 +200,7 @@ render_posts(struct http_request *req, const char *resource) { int -render_posts_query(struct post_request *post_req) { +query_posts(struct post_request *post_req) { int err = 0; int row = 0, rows = 0; @@ -317,28 +323,10 @@ out: ; } int -toys(struct http_request *req) { - if (req->method == HTTP_METHOD_GET) - get_toys(req); - else if (req->method == HTTP_METHOD_POST) - post_toys(req); - - return KORE_RESULT_OK; -} - -int -get_toys(struct http_request *req) { - - http_response(req, HTTP_STATUS_OK, "OK", strlen("OK")); - - return KORE_RESULT_OK; -} - -int -post_toys(struct http_request *req) { +POST_post(struct http_request *req) { int err = 0; - int status = HTTP_STATUS_OK; + int status = HTTP_STATUS_CREATED; struct kore_json_item *item = NULL; @@ -349,10 +337,6 @@ post_toys(struct http_request *req) { struct kore_json json; struct kore_pgsql sql; - // const char *json_str = "{\"id\": \"00000000-0000-0000-0000-000000000000\", " - // "\"title\": \"title\", \"body\": \"body\"}"; - - // kore_json_init(&json, json_str, strlen(json_str)); kore_json_init(&json, req->http_body->data, req->http_body->length); kore_pgsql_init(&sql); @@ -376,7 +360,7 @@ post_toys(struct http_request *req) { // Check for valid resource ID/UUID err = validate_uuid(id); if (err == KORE_RESULT_ERROR) { - status = HTTP_STATUS_NOT_FOUND; + status = HTTP_STATUS_BAD_REQUEST; kore_log(LOG_ERR, "Invalid post UUID %s.", id); goto out; } @@ -413,7 +397,7 @@ post_toys(struct http_request *req) { err = kore_pgsql_query_params( &sql, "INSERT INTO posts (id, title, body) " - "VALUES ($1, $2, $3);", + "VALUES ($1, $2, $3) RETURNING id;", 0, 3, KORE_PGSQL_PARAM_TEXT(id), @@ -429,11 +413,53 @@ post_toys(struct http_request *req) { out: ; + if (status == HTTP_STATUS_CREATED) + render_posts(req, id); + else { // ERRORs + int type = HTML; + struct kore_buf *resp_buf = kore_buf_alloc(0); + const char *accept = NULL; + + err = http_request_header(req, "accept", &accept); + if (err == KORE_RESULT_OK) { + kore_log(LOG_DEBUG, "Accept: %s", accept); + if (strncmp(accept, accept_json, sizeof(*accept_json)) == 0) + type = JSON; + else + type = HTML; + } + + if (type == JSON) { + http_response_header(req, "content-type", "application/json; charset=utf-8"); + kore_buf_appendf( + resp_buf, + (const char *) asset_error_json, + error_msg[status] + ); + } else { + http_response_header(req, "content-type", "text/html; charset=utf-8"); + kore_buf_append(resp_buf, asset_index_begin_html, asset_len_index_begin_html); + kore_buf_appendf( + resp_buf, + (const char *) asset_error_html, + error_msg[status] + ); + kore_buf_append(resp_buf, asset_index_end_html, asset_len_index_end_html); + } + + http_response( + req, + status, + resp_buf->data, + resp_buf->offset + ); + + kore_buf_free(resp_buf); + } + kore_json_cleanup(&json); kore_pgsql_cleanup(&sql); - http_response(req, status, NULL, 0); - return KORE_RESULT_OK; } @@ -2,6 +2,7 @@ import json import sys +import uuid import requests @@ -94,6 +95,30 @@ def test_json_get_posts(): assert "Debugging CGI / CGit" in text +def test_json_post_posts(): + url = f"{BASE_URL}/posts" + uuid_ = str(uuid.uuid4()) + data = {"id": uuid_, "title": "title", "body": "body"} + r = requests.post(url, headers={"Accept": "application/json"}, json=data) + # FIXME need to refactor to fix status code here. + # assert r.status_code == 201 + assert r.status_code == 200 + j = r.json() + + assert len(j) == 1 + assert "title" == j[0]["title"] + assert "body" == j[0]["body"] + + url = f"{BASE_URL}/posts/{uuid_}" + r = requests.get(url, headers={"Accept": "application/json"}) + assert r.status_code == 200 + j = r.json() + + assert len(j) == 1 + assert "title" == j[0]["title"] + assert "body" == j[0]["body"] + + def test_json_get_post_not_found(): url = f"{BASE_URL}/posts/{BAD_UUID}" r = requests.get(url, headers={"Accept": "application/json"}) |