This commit is contained in:
nora 2025-08-16 17:20:27 +02:00
parent c752478c73
commit d59dae0707

150
h2.mjs
View file

@ -971,6 +971,11 @@ const handleConnection =
const payload = Buffer.from(body); const payload = Buffer.from(body);
const h2stream = streams.get(frame.streamIdentifier); const h2stream = streams.get(frame.streamIdentifier);
if (!h2stream) {
setImmediate(cb);
return;
}
const doWrite = () => { const doWrite = () => {
h2stream.flowControlWindowSize -= payload.length; h2stream.flowControlWindowSize -= payload.length;
@ -1117,6 +1122,36 @@ const handleConnection =
break; break;
} }
case FRAME_TYPE.RST_STREAM: {
const errorCode = frame.payload.readUint32BE();
if (frame.streamIdentifier === 0) {
socket.destroy();
}
streams.delete(frame.streamIdentifier);
if (debug) {
console.log("stream reset because of", ERROR_CODE_NAME[errorCode]);
}
break;
}
case FRAME_TYPE.PING: {
if (frame.streamIdentifier !== 0) {
socket.destroy();
}
socket.write(
encodeFrame({
type: FRAME_TYPE.PING,
flags: 0x01, // ACK
streamIdentifier: 0,
payload: frame.payload,
})
);
break;
}
case FRAME_TYPE.WINDOW_UPDATE: { case FRAME_TYPE.WINDOW_UPDATE: {
// whatever // whatever
const increment = frame.payload.readUint32BE(); const increment = frame.payload.readUint32BE();
@ -1202,6 +1237,8 @@ export const createH2Server = () => {
const { server, onConnection } = createH2Server(); const { server, onConnection } = createH2Server();
const rootPath = process.env.ROOT_PATH ?? ".";
server.on( server.on(
"request", "request",
/** /**
@ -1215,58 +1252,11 @@ server.on(
res.writeHead({ status: 405 }); res.writeHead({ status: 405 });
} }
const filepath = path.join(".", path.normalize(req.path)); const filepath = path.join(rootPath, path.normalize(req.path));
console.log("opening", filepath); console.log("opening", filepath);
fs.stat(filepath, (err, stat) => { const serveFile = (filepath, size) => {
if (err) {
if (err.code === "ENOENT") {
res.writeHead({ status: 404 });
} else {
console.error("failed to open", err);
res.writeHead({ status: 500 });
}
return;
}
if (stat.isDirectory()) {
fs.readdir(filepath, (err, files) => {
if (err) {
console.error("failed to read dir", err);
res.writeHead({ status: 500 });
return;
}
const html = `<ul>${files
.map(
(file) =>
`<li><a href="${encodeURIComponent(file)}">${file}</a></li>`
)
.join("\n")}</ul>`;
res.writeHead({
status: 200,
contentLength: html.length,
headers: [["content-type", "text/html; charset=utf-8"]],
});
res.body.write(html);
res.body.end();
});
return;
}
if (stat.isFile()) {
fs.open(filepath, (err, fd) => {
if (err) {
console.error("failed to read", err);
res.writeHead({ status: 500 });
return;
}
const size = stat.size;
const contentType = const contentType =
{ {
".html": "text/html; charset=utf-8", ".html": "text/html; charset=utf-8",
@ -1277,6 +1267,7 @@ server.on(
".jpeg": "image/jpeg", ".jpeg": "image/jpeg",
".webp": "image/webp", ".webp": "image/webp",
".avif": "image/avif", ".avif": "image/avif",
".svg": "image/svg+xml",
".woff": "font/woff", ".woff": "font/woff",
".woff2": "font/woff2", ".woff2": "font/woff2",
".txt": "text/plain", ".txt": "text/plain",
@ -1293,7 +1284,68 @@ server.on(
}); });
fileStream.pipe(res.body); fileStream.pipe(res.body);
};
fs.stat(filepath, (err, stat) => {
if (err) {
if (err.code === "ENOENT") {
res.writeHead({ status: 404 });
} else {
console.error("failed to open", err);
res.writeHead({ status: 500 });
}
return;
}
if (stat.isDirectory()) {
const indexhtml = path.join(filepath, "index.html");
fs.stat(indexhtml, (err, stat) => {
if (err) {
if (err.code === "ENOENT") {
fs.readdir(filepath, (err, files) => {
if (err) {
console.error("failed to read dir", err);
res.writeHead({ status: 500 });
return;
}
const html = `<ul>${files
.map(
(file) =>
`<li><a href="${encodeURIComponent(
file
)}">${file}</a></li>`
)
.join("\n")}</ul>`;
res.writeHead({
status: 200,
contentLength: html.length,
headers: [["content-type", "text/html; charset=utf-8"]],
}); });
res.body.write(html);
res.body.end();
});
return;
} else {
console.error("failed to stat index.html", err);
res.writeHead({ status: 500 });
}
return;
}
if (stat.isFile()) {
serveFile(indexhtml, stat.size);
} else {
console.error(`${indexhtml} exists but is not a regular file`);
res.writeHead({ status: 500 });
}
});
return;
}
if (stat.isFile()) {
serveFile(filepath, stat.size);
return; return;
} }