diff options
author | Michael McVady <femtonaut@gmail.com> | 2023-10-26 23:29:11 -0500 |
---|---|---|
committer | Michael McVady <femtonaut@gmail.com> | 2023-10-26 23:34:42 -0500 |
commit | a997ec6727b467fd72510a56bfe7a67eb04dbcf9 (patch) | |
tree | bbd1babe15bb83db10d831061a4dd5110638589c | |
parent | e24dfc3412648c8b07a32a59774ed21f5058f7e0 (diff) |
Remove JSON API
-rw-r--r-- | conf/clog.conf | 5 | ||||
-rw-r--r-- | src/clog.c | 142 | ||||
-rw-r--r-- | src/queries.h | 17 | ||||
-rwxr-xr-x | tests.py | 121 |
4 files changed, 46 insertions, 239 deletions
diff --git a/conf/clog.conf b/conf/clog.conf index 01e1715..9a5e340 100644 --- a/conf/clog.conf +++ b/conf/clog.conf @@ -12,11 +12,12 @@ privsep worker { root /var/chroot/clog - # skip chroot + skip chroot } seccomp_tracing no +validator v_uuid regex ^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$ validator v_number regex ^[0-9]*$ validator v_text function v_example_func @@ -65,7 +66,7 @@ domain * { handler post_form methods post - validate post id v_number + validate post id v_uuid validate post title v_number validate post body v_text } @@ -23,21 +23,17 @@ KORE_SECCOMP_FILTER("clog", KORE_SYSCALL_ALLOW(uname) ) -enum accept_type { ACCEPT_JSON, ACCEPT_HTML }; - enum content_type { CONTENT_JSON, CONTENT_X_WWW_FORM_URLENCODED }; enum query_status { QUERY_STATUS_OK, QUERY_STATUS_ERROR, QUERY_STATUS_NOT_FOUND }; struct post_query { char *id; - enum accept_type accept_type; int status; struct kore_buf *result; }; -static const char *accept_json = "application/json"; static const char *database = "db"; static const char * const error_msg[] = { @@ -48,23 +44,19 @@ static const char * const error_msg[] = { [HTTP_STATUS_INTERNAL_ERROR] = "There was an error processing the request.", // 500 }; -void post_query_init(struct post_query *pq, enum accept_type accept_type, const char *id); +void post_query_init(struct post_query *pq, const char *id); void post_query_cleanup(struct post_query *pq); int validate_uuid(const char *uuid); -enum accept_type get_accept_type(struct http_request *req); - int http_ok_resp( struct http_request *req, - enum accept_type accept_type, enum http_status_code status, struct kore_buf *result ); int http_err_resp( struct http_request *req, - enum accept_type accept_type, enum http_status_code status ); @@ -90,13 +82,12 @@ int sql_render_posts(struct kore_pgsql *sql, struct post_query *pq); static void process_md_output(const MD_CHAR *, MD_SIZE size, void *); static int render_md(const char *, struct kore_buf *); -void post_query_init(struct post_query *pq, enum accept_type accept_type, const char *id) { +void post_query_init(struct post_query *pq, const char *id) { if (id != NULL) pq->id = kore_strdup(id); else pq->id = NULL; - pq->accept_type = accept_type; pq->status = QUERY_STATUS_OK; pq->result = kore_buf_alloc(0); } @@ -135,47 +126,22 @@ int validate_uuid(const char *uuid) { return KORE_RESULT_OK; } -enum accept_type get_accept_type(struct http_request *req) { - int err = 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) - return ACCEPT_JSON; - } - - return ACCEPT_HTML; -} - int http_ok_resp( struct http_request *req, - enum accept_type accept_type, enum http_status_code status, struct kore_buf *result ) { struct kore_buf *resp_buf = kore_buf_alloc(0); const char *body = kore_buf_stringify(result, NULL); - if (accept_type == ACCEPT_JSON) { - http_response_header(req, "content-type", "application/json; charset=utf-8"); - kore_buf_append( - resp_buf, - body, - strlen(body) - ); - } 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_append( - resp_buf, - body, - strlen(body) - ); - 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"); + kore_buf_append(resp_buf, asset_index_begin_html, asset_len_index_begin_html); + kore_buf_append( + resp_buf, + body, + strlen(body) + ); + kore_buf_append(resp_buf, asset_index_end_html, asset_len_index_end_html); http_response( req, @@ -191,28 +157,18 @@ int http_ok_resp( int http_err_resp( struct http_request *req, - enum accept_type accept_type, enum http_status_code status ) { struct kore_buf *resp_buf = kore_buf_alloc(0); - if (accept_type == ACCEPT_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_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, @@ -246,7 +202,7 @@ int get_form(struct http_request *req) { asset_len_post_edit_html ); - http_ok_resp(req, ACCEPT_HTML, HTTP_STATUS_OK, resp_buf); + http_ok_resp(req, HTTP_STATUS_OK, resp_buf); kore_buf_free(resp_buf); @@ -294,7 +250,7 @@ int post_form(struct http_request *req) { kore_buf_stringify(html_buf, NULL) ); - http_ok_resp(req, ACCEPT_HTML, HTTP_STATUS_OK, resp_buf); + http_ok_resp(req, HTTP_STATUS_OK, resp_buf); kore_buf_free(html_buf); kore_buf_free(resp_buf); @@ -306,13 +262,13 @@ int post_form(struct http_request *req) { int get_posts(struct http_request *req) { struct post_query pq; - post_query_init(&pq, get_accept_type(req), NULL); + post_query_init(&pq, NULL); (void) sql_select_posts(&pq); if (pq.status != QUERY_STATUS_OK) - http_err_resp(req, pq.accept_type, HTTP_STATUS_INTERNAL_ERROR); + http_err_resp(req, HTTP_STATUS_INTERNAL_ERROR); else - http_ok_resp(req, pq.accept_type, HTTP_STATUS_OK, pq.result); + http_ok_resp(req, HTTP_STATUS_OK, pq.result); post_query_cleanup(&pq); @@ -324,24 +280,24 @@ int get_posts_resource(struct http_request *req) { struct post_query pq; - post_query_init(&pq, get_accept_type(req), req->path + strlen("/posts/")); + post_query_init(&pq, req->path + strlen("/posts/")); // Check for valid resource UUID kore_log(LOG_DEBUG, "Resource id /posts/%s.", pq.id); err = validate_uuid(pq.id); if (err == KORE_RESULT_ERROR) { kore_log(LOG_ERR, "Invalid post id %s.", pq.id); - http_err_resp(req, pq.accept_type, HTTP_STATUS_NOT_FOUND); + http_err_resp(req, HTTP_STATUS_NOT_FOUND); goto out; } (void) sql_select_posts(&pq); if (pq.status == QUERY_STATUS_NOT_FOUND) - http_err_resp(req, pq.accept_type, HTTP_STATUS_NOT_FOUND); + http_err_resp(req, HTTP_STATUS_NOT_FOUND); else if (pq.status == QUERY_STATUS_ERROR) - http_err_resp(req, pq.accept_type, HTTP_STATUS_INTERNAL_ERROR); + http_err_resp(req, HTTP_STATUS_INTERNAL_ERROR); else - http_ok_resp(req, pq.accept_type, HTTP_STATUS_OK, pq.result); + http_ok_resp(req, HTTP_STATUS_OK, pq.result); out: ; @@ -355,8 +311,6 @@ int post_posts(struct http_request *req) { int status = HTTP_STATUS_CREATED; - enum accept_type accept_type = get_accept_type(req); - const char *id = NULL; const char *title = NULL; const char *body = NULL; @@ -414,7 +368,7 @@ int post_posts(struct http_request *req) { out: ; - http_err_resp(req, accept_type, status); + http_err_resp(req, status); kore_json_cleanup(&json); @@ -426,8 +380,6 @@ int put_posts(struct http_request *req) { int status = HTTP_STATUS_OK; - enum accept_type accept_type = get_accept_type(req); - const char *id = NULL; const char *title = NULL; const char *body = NULL; @@ -444,7 +396,7 @@ int put_posts(struct http_request *req) { err = validate_uuid(id); if (err == KORE_RESULT_ERROR) { kore_log(LOG_ERR, "Invalid post id %s.", id); - http_err_resp(req, accept_type, HTTP_STATUS_NOT_FOUND); + http_err_resp(req, HTTP_STATUS_NOT_FOUND); goto out; } @@ -483,7 +435,7 @@ int put_posts(struct http_request *req) { out: ; - http_err_resp(req, accept_type, status); + http_err_resp(req, status); kore_json_cleanup(&json); @@ -512,7 +464,7 @@ int sql_select_posts(struct post_query *pq) { // Query a post. err = kore_pgsql_query_params( &sql, - pq->accept_type == ACCEPT_HTML ? q_select_html_post : q_select_json_post, + q_select_post, 0, // return string data 1, // param count KORE_PGSQL_PARAM_TEXT(pq->id) @@ -520,8 +472,8 @@ int sql_select_posts(struct post_query *pq) { } else { // Query all posts. err = kore_pgsql_query( - &sql, - pq->accept_type == ACCEPT_HTML ? q_select_html_posts : q_select_json_posts + &sql, + q_select_posts ); } @@ -531,12 +483,6 @@ int sql_select_posts(struct post_query *pq) { goto out; } - // XXX Always tuples from the above Postgres queries, need to check the length for results. - if (pq->accept_type == ACCEPT_JSON && kore_pgsql_getlength(&sql, 0, 0) == 0) { - pq->status = QUERY_STATUS_NOT_FOUND; - goto out; - } - // TODO: Add test for this; When database is empty, don't return 404 for base request. if (pq->id != NULL && kore_pgsql_ntuples(&sql) == 0) { pq->status = QUERY_STATUS_NOT_FOUND; @@ -555,7 +501,6 @@ out: ; int delete_posts(struct http_request *req) { int err = 0; - enum accept_type accept_type = get_accept_type(req); const char *id = req->path + strlen("/posts/"); // Check for valid resource UUID @@ -563,19 +508,19 @@ int delete_posts(struct http_request *req) { err = validate_uuid(id); if (err == KORE_RESULT_ERROR) { kore_log(LOG_ERR, "Invalid post id %s.", id); - http_err_resp(req, accept_type, HTTP_STATUS_NOT_FOUND); + http_err_resp(req, HTTP_STATUS_NOT_FOUND); goto out; } err = sql_delete_posts(id); // FIXME: should 404 if id doesn't exist. // if (pq.status == QUERY_STATUS_NOT_FOUND) - // http_err_resp(req, pq.accept_type, HTTP_STATUS_NOT_FOUND); + // http_err_resp(req, HTTP_STATUS_NOT_FOUND); if (err == KORE_RESULT_ERROR) - http_err_resp(req, accept_type, HTTP_STATUS_INTERNAL_ERROR); + http_err_resp(req, HTTP_STATUS_INTERNAL_ERROR); else // TODO: test this, it should explode. - http_err_resp(req, accept_type, HTTP_STATUS_OK); + http_err_resp(req, HTTP_STATUS_OK); out: ; @@ -594,17 +539,6 @@ int sql_render_posts(struct kore_pgsql *sql, struct post_query *pq) { const char *created_at = NULL; const char *body = NULL; - if (pq->accept_type == ACCEPT_JSON) { - kore_buf_append( - pq->result, - kore_pgsql_getvalue(sql, 0, 0), - kore_pgsql_getlength(sql, 0, 0) - ); - return KORE_RESULT_OK; - } - - // pg->accept_type == ACCEPT_HTML - // Allocate a buffer to render the markdown as HTML into. html_buf = kore_buf_alloc(0); diff --git a/src/queries.h b/src/queries.h index 2334874..ffc9c7b 100644 --- a/src/queries.h +++ b/src/queries.h @@ -1,26 +1,13 @@ -const char *q_select_html_post = +const char *q_select_post = "SELECT id, title, created_at::DATE, body " "FROM posts " "WHERE id = $1;"; -const char *q_select_html_posts = +const char *q_select_posts = "SELECT id, title, created_at::DATE, body " "FROM posts " "ORDER BY updated_at DESC;"; -const char *q_select_json_post = -"SELECT JSON_AGG(ROW_TO_JSON(row)) FROM (" - "SELECT id, title, body, created_at, updated_at " - "FROM posts " - "WHERE id = $1" -") row;"; - -const char *q_select_json_posts = -"SELECT JSON_AGG(ROW_TO_JSON(row)) FROM (" - "SELECT id, title, body, created_at, updated_at " - "FROM posts " - "ORDER BY updated_at DESC" -") row;"; const char *q_insert_posts = "INSERT INTO posts " @@ -1,5 +1,4 @@ #!/usr/bin/env python3 -import json import logging import sys import uuid @@ -79,130 +78,16 @@ def test_html_get_post_not_found(): assert "Resource not found" in text -def test_json_get_post(): - url = f"{POSTS_URL}/{POST_UUID}" - r = requests.get(url, headers=JSON_ACCEPT_HEADER) - assert r.status_code == 200 - j = r.json() - post = j[0] - assert len(j) == 1 - assert "A Solid Breakdown of the Linux Font Rendering Stack" == post["title"] - assert "hinting and anti-aliasing" in post["body"] - - -def test_json_get_posts(): - url = POSTS_URL - r = requests.get(url, headers=JSON_ACCEPT_HEADER) - assert r.status_code == 200 - j = r.json() - assert len(j) >= 1 - text = json.dumps(j) - assert "A Solid Breakdown of the Linux Font Rendering Stack" in text - assert "hinting and anti-aliasing" in text - assert "Debugging CGI / CGit" in text - - -def test_json_post_posts(): - url = POSTS_URL - uuid_ = str(uuid.uuid4()) - data = {"id": uuid_, "title": "title", "body": "body"} - r = requests.post(url, headers=JSON_ACCEPT_HEADER, json=data) - assert r.status_code == 201 - j = r.json() - assert "Resource created successfully." == j - - url = f"{POSTS_URL}/{uuid_}" - r = requests.get(url, headers=JSON_ACCEPT_HEADER) - assert r.status_code == 200 - j = r.json() - assert len(j) == 1 - assert "title" == j[0]["title"] - assert "body" == j[0]["body"] - - r = requests.delete(url, headers=JSON_ACCEPT_HEADER) - assert r.status_code == 200 - j = r.json() - - -def test_json_put_posts(): - url = POSTS_URL - uuid_ = str(uuid.uuid4()) - data = {"id": uuid_, "title": "title", "body": "body"} - r = requests.post(url, headers=JSON_ACCEPT_HEADER, json=data) - assert r.status_code == 201 - j = r.json() - assert "Resource created successfully." == j - - url = f"{POSTS_URL}/{uuid_}" - r = requests.get(url, headers=JSON_ACCEPT_HEADER) - assert r.status_code == 200 - j = r.json() - assert len(j) == 1 - assert "title" == j[0]["title"] - assert "body" == j[0]["body"] - - data = {"title": "title2", "body": "body2"} - r = requests.put(url, headers=JSON_ACCEPT_HEADER, json=data) - assert r.status_code == 200 - j = r.json() - assert "OK" == j - - url = f"{POSTS_URL}/{uuid_}" - r = requests.get(url, headers=JSON_ACCEPT_HEADER) - assert r.status_code == 200 - j = r.json() - assert len(j) == 1 - assert "title2" == j[0]["title"] - assert "body2" == j[0]["body"] - - r = requests.delete(url, headers=JSON_ACCEPT_HEADER) - assert r.status_code == 200 - j = r.json() - -def test_json_delete_posts(): - url = POSTS_URL - uuid_ = DELETE_UUID - data = {"id": uuid_, "title": "title", "body": "body"} - - # Create post copy-pasta. - r = requests.post(url, headers=JSON_ACCEPT_HEADER, json=data) - assert r.status_code == 201 - j = r.json() - - url = f"{POSTS_URL}/{uuid_}" - r = requests.delete(url, headers=JSON_ACCEPT_HEADER) - assert r.status_code == 200 - j = r.json() - - r = requests.get(url, headers=JSON_ACCEPT_HEADER) - assert r.status_code == 404 - j = r.json() - - -def test_json_get_post_not_found(): - url = f"{POSTS_URL}/{BAD_UUID}" - r = requests.get(url, headers=JSON_ACCEPT_HEADER) - assert r.status_code == 404 - j = r.json() - assert "Resource not found" in j - - url = f"{POSTS_URL}/{INVALID_UUID}" - r = requests.delete(url, headers=JSON_ACCEPT_HEADER) - assert r.status_code == 404 - j = r.json() - assert "Resource not found" in j - - def main(): winner = True for func in dir(sys.modules[__name__]): if func.startswith("test_"): try: globals()[func]() - except Exception: + except Exception as e: winner = False - log.exception(f"🚫 {func} failed 🚫🏆") - print(f"🚫 {func} failed 🚫🏆") + log.exception(f"🚫 {func} failed {e} 🚫") + print(f"🚫 {func} failed {e} 🚫") if winner: log.info("🏆 You're winner !") |