From 345c291c1b2d5c82baf6d112a0f0c0c810efac8f Mon Sep 17 00:00:00 2001 From: Carl Niklas Rydberg Date: Mon, 22 Dec 2025 19:46:59 +0100 Subject: [PATCH] Add friendly HTML 404 page --- src/amduatd.c | 92 ++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 84 insertions(+), 8 deletions(-) diff --git a/src/amduatd.c b/src/amduatd.c index 8d6da77..6f46944 100644 --- a/src/amduatd.c +++ b/src/amduatd.c @@ -283,6 +283,78 @@ static bool amduatd_http_send_json(int fd, fd, code, reason, "application/json", body, len, head_only); } +static bool amduatd_http_req_wants_html(const amduatd_http_req_t *req) { + if (req == NULL) { + return false; + } + if (req->accept[0] == '\0') { + return false; + } + return strstr(req->accept, "text/html") != NULL; +} + +static bool amduatd_http_send_not_found(int fd, const amduatd_http_req_t *req) { + if (amduatd_http_req_wants_html(req)) { + const char *path = (req != NULL && req->path[0] != '\0') ? req->path : "/"; + const char *method = + (req != NULL && req->method[0] != '\0') ? req->method : "GET"; + char html[4096]; + int n = snprintf( + html, + sizeof(html), + "\n" + "\n" + "\n" + " \n" + " \n" + " amduatd — Not Found\n" + " \n" + "\n" + "\n" + "
\n" + "
\n" + "

404 — Not Found

\n" + "

amduatd didn’t recognize %s %s.

\n" + "

Try one of these:

\n" + " \n" + "

Artifact bytes: /v1/artifacts/<ref>

\n" + "
\n" + "
\n" + "\n" + "\n", + method, + path); + if (n <= 0 || (size_t)n >= sizeof(html)) { + return amduatd_http_send_text(fd, 404, "Not Found", "not found\n", false); + } + return amduatd_http_send_status(fd, + 404, + "Not Found", + "text/html; charset=utf-8", + (const uint8_t *)html, + (size_t)n, + false); + } + return amduatd_http_send_text(fd, 404, "Not Found", "not found\n", false); +} + static const char *amduatd_query_param(const char *path, const char *key, char *out_value, @@ -835,6 +907,7 @@ static bool amduatd_seed_api_contract(amduat_asl_store_t *store, static bool amduatd_handle_get_artifact(int fd, amduat_asl_store_t *store, + const amduatd_http_req_t *req, const char *path, bool head_only) { char no_query[1024]; @@ -850,8 +923,8 @@ static bool amduatd_handle_get_artifact(int fd, amduatd_path_without_query(path, no_query, sizeof(no_query)); if (strncmp(no_query, "/v1/artifacts/", 14) != 0) { - return amduatd_http_send_text(fd, 404, "Not Found", "not found\n", - head_only); + (void)head_only; + return amduatd_http_send_not_found(fd, req); } ref_text = no_query + 14; if (ref_text[0] == '\0') { @@ -880,8 +953,10 @@ static bool amduatd_handle_get_artifact(int fd, err = amduat_asl_store_get(store, ref, &artifact); free((void *)ref.digest.data); if (err == AMDUAT_ASL_STORE_ERR_NOT_FOUND) { - return amduatd_http_send_text(fd, 404, "Not Found", "not found\n", - head_only); + if (!head_only) { + return amduatd_http_send_not_found(fd, req); + } + return amduatd_http_send_text(fd, 404, "Not Found", "not found\n", true); } if (err != AMDUAT_ASL_STORE_OK) { amduat_asl_artifact_free(&artifact); @@ -924,8 +999,9 @@ static bool amduatd_handle_get_artifact(int fd, static bool amduatd_handle_head_artifact(int fd, amduat_asl_store_t *store, + const amduatd_http_req_t *req, const char *path) { - return amduatd_handle_get_artifact(fd, store, path, true); + return amduatd_handle_get_artifact(fd, store, req, path, true); } static bool amduatd_handle_post_artifacts(int fd, @@ -1453,14 +1529,14 @@ static bool amduatd_handle_conn(int fd, } if (strcmp(req.method, "GET") == 0 && strncmp(no_query, "/v1/artifacts/", 14) == 0) { - return amduatd_handle_get_artifact(fd, store, req.path, false); + return amduatd_handle_get_artifact(fd, store, &req, req.path, false); } if (strcmp(req.method, "HEAD") == 0 && strncmp(no_query, "/v1/artifacts/", 14) == 0) { - return amduatd_handle_head_artifact(fd, store, req.path); + return amduatd_handle_head_artifact(fd, store, &req, req.path); } - return amduatd_http_send_text(fd, 404, "Not Found", "not found\n", false); + return amduatd_http_send_not_found(fd, &req); } static void amduatd_print_usage(FILE *stream) {