45 lines
1.0 KiB
JavaScript
45 lines
1.0 KiB
JavaScript
import { createReadStream } from 'node:fs';
|
|
import { stat } from 'node:fs/promises';
|
|
import { extname } from 'node:path';
|
|
import { httpError } from '../http/httpError.mjs';
|
|
import { mimeTypes } from './mimeTypes.mjs';
|
|
import { resolveInside } from './resolveInside.mjs';
|
|
|
|
export async function serveFile(response, root, pathname, method) {
|
|
const filePath = resolveInside(root, pathname);
|
|
|
|
if (!filePath) {
|
|
throw httpError(403, 'Forbidden');
|
|
}
|
|
|
|
const fileStat = await getFileStat(filePath);
|
|
|
|
response.writeHead(200, {
|
|
'Content-Length': fileStat.size,
|
|
'Content-Type': mimeTypes[extname(filePath).toLowerCase()] || 'application/octet-stream',
|
|
'X-Content-Type-Options': 'nosniff',
|
|
});
|
|
|
|
if (method === 'HEAD') {
|
|
response.end();
|
|
return;
|
|
}
|
|
|
|
createReadStream(filePath).pipe(response);
|
|
}
|
|
|
|
async function getFileStat(filePath) {
|
|
let fileStat;
|
|
try {
|
|
fileStat = await stat(filePath);
|
|
} catch {
|
|
throw httpError(404, 'Not found');
|
|
}
|
|
|
|
if (!fileStat.isFile()) {
|
|
throw httpError(404, 'Not found');
|
|
}
|
|
|
|
return fileStat;
|
|
}
|