aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael McVady <femtonaut@gmail.com>2023-10-26 23:29:11 -0500
committerMichael McVady <femtonaut@gmail.com>2023-10-26 23:34:42 -0500
commita997ec6727b467fd72510a56bfe7a67eb04dbcf9 (patch)
treebbd1babe15bb83db10d831061a4dd5110638589c
parente24dfc3412648c8b07a32a59774ed21f5058f7e0 (diff)
Remove JSON API
-rw-r--r--conf/clog.conf5
-rw-r--r--src/clog.c142
-rw-r--r--src/queries.h17
-rwxr-xr-xtests.py121
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
}
diff --git a/src/clog.c b/src/clog.c
index 5be4a51..4bb5945 100644
--- a/src/clog.c
+++ b/src/clog.c
@@ -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 "
diff --git a/tests.py b/tests.py
index a8050eb..ab3b16a 100755
--- a/tests.py
+++ b/tests.py
@@ -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 !")