Source code

Revision control

Copy as Markdown

Other Tools

#!/usr/bin/env node
const http2 = require("http2");
const fs = require("fs");
const path = require("path");
const [directory = ".", certFile, keyFile] = process.argv.slice(2);
const opts = certFile
? { cert: fs.readFileSync(certFile), key: fs.readFileSync(keyFile) }
: {};
const server = certFile ? http2.createSecureServer(opts) : http2.createServer();
server.on("stream", (stream, headers) => {
const reqPath = headers[":path"];
let filePath = path.join(directory, reqPath);
if (
!path.resolve(filePath).startsWith(path.resolve(directory) + path.sep) &&
path.resolve(filePath) !== path.resolve(directory)
) {
stream.respond({ ":status": 403 });
stream.end();
return;
}
if (filePath.endsWith("/")) {
filePath += "index.html";
}
console.log(`${headers[":method"]} ${reqPath}`);
const ext = path.extname(filePath);
const contentType =
{
".html": "text/html",
".js": "application/javascript",
".css": "text/css",
".json": "application/json",
".png": "image/png",
".jpg": "image/jpeg",
".gif": "image/gif",
".svg": "image/svg+xml",
".ico": "image/x-icon",
}[ext] || "application/octet-stream";
fs.createReadStream(filePath)
.on("error", () => {
stream.respond({ ":status": 404 });
stream.end();
})
.on("open", () => {
stream.respond({ ":status": 200, "content-type": contentType });
})
.pipe(stream);
});
const protocol = certFile ? "https" : "http";
server.listen(8000, () => {
console.log(`HTTP/2 server (${protocol}) listening on port 8000`);
console.log(`Serving files from: ${path.resolve(directory)}`);
});
server.on("error", err => {
console.error("Server error:", err);
});