Add friendly HTML 404 page
This commit is contained in:
parent
af3e75508c
commit
345c291c1b
|
|
@ -283,6 +283,78 @@ static bool amduatd_http_send_json(int fd,
|
||||||
fd, code, reason, "application/json", body, len, head_only);
|
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),
|
||||||
|
"<!doctype html>\n"
|
||||||
|
"<html lang=\"en\">\n"
|
||||||
|
"<head>\n"
|
||||||
|
" <meta charset=\"utf-8\" />\n"
|
||||||
|
" <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n"
|
||||||
|
" <title>amduatd — Not Found</title>\n"
|
||||||
|
" <style>\n"
|
||||||
|
" :root{color-scheme:light dark;}\n"
|
||||||
|
" body{font-family:ui-sans-serif,system-ui,-apple-system,Segoe UI,Roboto,Ubuntu,Cantarell,Noto Sans,Arial,sans-serif;"
|
||||||
|
" margin:0;line-height:1.4;}\n"
|
||||||
|
" .wrap{max-width:860px;margin:0 auto;padding:40px 20px;}\n"
|
||||||
|
" .card{border:1px solid rgba(127,127,127,.35);border-radius:14px;padding:22px;"
|
||||||
|
" background:rgba(127,127,127,.06);}\n"
|
||||||
|
" h1{margin:0 0 6px;font-size:22px;}\n"
|
||||||
|
" p{margin:8px 0;opacity:.9;}\n"
|
||||||
|
" code{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,monospace;"
|
||||||
|
" font-size:13px;}\n"
|
||||||
|
" ul{margin:10px 0 0;padding-left:18px;}\n"
|
||||||
|
" a{color:inherit;}\n"
|
||||||
|
" .muted{opacity:.75;}\n"
|
||||||
|
" </style>\n"
|
||||||
|
"</head>\n"
|
||||||
|
"<body>\n"
|
||||||
|
" <div class=\"wrap\">\n"
|
||||||
|
" <div class=\"card\">\n"
|
||||||
|
" <h1>404 — Not Found</h1>\n"
|
||||||
|
" <p>amduatd didn’t recognize <code>%s %s</code>.</p>\n"
|
||||||
|
" <p class=\"muted\">Try one of these:</p>\n"
|
||||||
|
" <ul>\n"
|
||||||
|
" <li><a href=\"/v1/meta\">/v1/meta</a></li>\n"
|
||||||
|
" <li><a href=\"/v1/contract\">/v1/contract</a></li>\n"
|
||||||
|
" </ul>\n"
|
||||||
|
" <p class=\"muted\">Artifact bytes: <code>/v1/artifacts/<ref></code></p>\n"
|
||||||
|
" </div>\n"
|
||||||
|
" </div>\n"
|
||||||
|
"</body>\n"
|
||||||
|
"</html>\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,
|
static const char *amduatd_query_param(const char *path,
|
||||||
const char *key,
|
const char *key,
|
||||||
char *out_value,
|
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,
|
static bool amduatd_handle_get_artifact(int fd,
|
||||||
amduat_asl_store_t *store,
|
amduat_asl_store_t *store,
|
||||||
|
const amduatd_http_req_t *req,
|
||||||
const char *path,
|
const char *path,
|
||||||
bool head_only) {
|
bool head_only) {
|
||||||
char no_query[1024];
|
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));
|
amduatd_path_without_query(path, no_query, sizeof(no_query));
|
||||||
|
|
||||||
if (strncmp(no_query, "/v1/artifacts/", 14) != 0) {
|
if (strncmp(no_query, "/v1/artifacts/", 14) != 0) {
|
||||||
return amduatd_http_send_text(fd, 404, "Not Found", "not found\n",
|
(void)head_only;
|
||||||
head_only);
|
return amduatd_http_send_not_found(fd, req);
|
||||||
}
|
}
|
||||||
ref_text = no_query + 14;
|
ref_text = no_query + 14;
|
||||||
if (ref_text[0] == '\0') {
|
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);
|
err = amduat_asl_store_get(store, ref, &artifact);
|
||||||
free((void *)ref.digest.data);
|
free((void *)ref.digest.data);
|
||||||
if (err == AMDUAT_ASL_STORE_ERR_NOT_FOUND) {
|
if (err == AMDUAT_ASL_STORE_ERR_NOT_FOUND) {
|
||||||
return amduatd_http_send_text(fd, 404, "Not Found", "not found\n",
|
if (!head_only) {
|
||||||
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) {
|
if (err != AMDUAT_ASL_STORE_OK) {
|
||||||
amduat_asl_artifact_free(&artifact);
|
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,
|
static bool amduatd_handle_head_artifact(int fd,
|
||||||
amduat_asl_store_t *store,
|
amduat_asl_store_t *store,
|
||||||
|
const amduatd_http_req_t *req,
|
||||||
const char *path) {
|
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,
|
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 &&
|
if (strcmp(req.method, "GET") == 0 &&
|
||||||
strncmp(no_query, "/v1/artifacts/", 14) == 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 &&
|
if (strcmp(req.method, "HEAD") == 0 &&
|
||||||
strncmp(no_query, "/v1/artifacts/", 14) == 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) {
|
static void amduatd_print_usage(FILE *stream) {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue