-
-
Notifications
You must be signed in to change notification settings - Fork 83
/
not_found.ts
103 lines (90 loc) · 2.67 KB
/
not_found.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
import { join, posix } from "../deps/path.ts";
import type { Middleware } from "../core.ts";
export interface Options {
root: string;
page404: string;
directoryIndex?: boolean;
}
/** Show a 404 page */
export default function notFound(options: Options): Middleware {
let { root, page404, directoryIndex } = options;
if (page404.endsWith("/")) {
page404 += "index.html";
}
return async (request, next) => {
const response = await next(request);
if (response.status === 404) {
const { headers, status } = response;
headers.set("content-type", "text/html");
try {
const body = await Deno.readFile(join(root, page404));
return new Response(body, { status, headers });
} catch {
if (directoryIndex) {
const { pathname } = new URL(request.url);
const body = await getDirectoryIndex(root, pathname);
return new Response(body, { status, headers });
}
}
}
return response;
};
}
/** Generate the default body for a 404 response */
async function getDirectoryIndex(root: string, file: string): Promise<string> {
const folders: [string, string][] = [];
const files: [string, string][] = [];
try {
for await (const info of Deno.readDir(join(root, file))) {
info.isDirectory
? folders.push([`${info.name}/`, `📁 ${info.name}/`])
: files.push([
info.name === "index.html" ? "./" : info.name,
`📄 ${info.name}`,
]);
}
} catch {
// It's not a directory, so scan the parent directory
try {
const base = posix.dirname(file);
for await (const info of Deno.readDir(join(root, base))) {
info.isDirectory
? folders.push([posix.join(base, `${info.name}/`), `📁 ${info.name}/`])
: files.push([
posix.join(base, info.name === "index.html" ? "./" : info.name),
`📄 ${info.name}`,
]);
}
} catch {
// Ignore
}
}
const content = folders.concat(files);
if (file.match(/.+\/.+/)) {
content.unshift(["../", ".."]);
}
return `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>404 - Not found</title>
<style> body { font-family: sans-serif; max-width: 40em; margin: auto; padding: 2em; line-height: 1.5; }</style>
</head>
<body>
<h1>404 - Not found</h1>
<p>The URL <code>${file}</code> does not exist</p>
<ul>
${
content.map(([url, name]) => `
<li>
<a href="${url}">
${name}
</a>
</li>`).join("\n")
}
</ul>
</body>
</html>`;
}