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) {