67 lines
2.5 KiB
JavaScript
67 lines
2.5 KiB
JavaScript
import { createServer } from "node:http";
|
|
import { readFile, stat } from "node:fs/promises";
|
|
import path from "node:path";
|
|
import { fileURLToPath } from "node:url";
|
|
const root = path.resolve(
|
|
path.dirname(fileURLToPath(import.meta.url)),
|
|
"..",
|
|
"dist",
|
|
);
|
|
const prefix = "/deep/nested/text/";
|
|
const types = new Map([
|
|
[".css", "text/css; charset=utf-8"],
|
|
[".html", "text/html; charset=utf-8"],
|
|
[".js", "text/javascript; charset=utf-8"],
|
|
[".json", "application/json; charset=utf-8"],
|
|
[".webmanifest", "application/manifest+json; charset=utf-8"],
|
|
[".svg", "image/svg+xml"],
|
|
[".md", "text/markdown; charset=utf-8"],
|
|
[".txt", "text/plain; charset=utf-8"],
|
|
[".wasm", "application/wasm"],
|
|
[".png", "image/png"],
|
|
[".jpg", "image/jpeg"],
|
|
[".webp", "image/webp"],
|
|
]);
|
|
const headers = {
|
|
"Content-Security-Policy":
|
|
"default-src 'self'; base-uri 'self'; object-src 'none'; frame-ancestors 'none'; form-action 'self'; script-src 'self' 'wasm-unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob:; media-src 'self' blob:; connect-src 'self'; worker-src 'self' blob:; manifest-src 'self'",
|
|
"Cross-Origin-Opener-Policy": "same-origin",
|
|
"Cross-Origin-Resource-Policy": "same-origin",
|
|
"Permissions-Policy":
|
|
"camera=(), microphone=(), geolocation=(), usb=(), payment=()",
|
|
"Referrer-Policy": "no-referrer",
|
|
"X-Content-Type-Options": "nosniff",
|
|
};
|
|
const server = createServer(async (request, response) => {
|
|
try {
|
|
const url = new URL(request.url ?? "/", "http://127.0.0.1");
|
|
const relative = decodeURIComponent(url.pathname).startsWith(prefix)
|
|
? decodeURIComponent(url.pathname).slice(prefix.length)
|
|
: decodeURIComponent(url.pathname).replace(/^\/+/, "");
|
|
const normalized = path.posix.normalize(relative || "index.html");
|
|
if (
|
|
normalized === ".." ||
|
|
normalized.startsWith("../") ||
|
|
path.isAbsolute(normalized)
|
|
) {
|
|
response.writeHead(400).end("Bad request");
|
|
return;
|
|
}
|
|
let file = path.join(root, normalized);
|
|
if ((await stat(file).catch(() => null))?.isDirectory())
|
|
file = path.join(file, "index.html");
|
|
const content = await readFile(file);
|
|
response.writeHead(200, {
|
|
"Content-Type":
|
|
types.get(path.extname(file)) ?? "application/octet-stream",
|
|
"Cache-Control": "no-cache",
|
|
...headers,
|
|
});
|
|
response.end(content);
|
|
} catch {
|
|
response.writeHead(404, { "Content-Type": "text/plain; charset=utf-8" });
|
|
response.end("Not found");
|
|
}
|
|
});
|
|
server.listen(4173, "127.0.0.1", () => console.log("Test server ready"));
|