als-send-file
Version:
file serving with advanced options for caching, headers, and error handling, compatible with Express middleware.
47 lines (43 loc) • 1.79 kB
JavaScript
const { createReadStream } = require('fs');
const rangeParser = require('range-parser');
const {basename} = require('path')
/**
* Sends a file to the client with support for ranges and error handling.
* @param {http.IncomingMessage} req - The request object.
* @param {http.ServerResponse} res - The response object.
* @param {string} filePath - The path to the file.
* @param {Object} stats - The file stats object.
* @param {Function} httpErrorHandler - Function to handle HTTP errors.
*/
async function sendFile(req, res, filePath, stats, httpErrorHandler) {
const options = {}
if (req.headers.range) {
const ranges = rangeParser(stats.size, req.headers.range); // Parse Range header
if (ranges === -1 || ranges.type !== 'bytes' || ranges.length > 1) {
return httpErrorHandler(res,416, 'Range is not valid')
}
const { start, end } = ranges[0];
res.statusCode = 206;
res.setHeader('Content-Range', `bytes ${start}-${end}/${stats.size}`);
res.setHeader('Content-Length', (end - start + 1).toString());
options.start = start;
options.end = end;
}
const fileStream = createReadStream(filePath, options);
return new Promise((resolve, reject) => {
let closed = false
const close = (err) => {
fileStream.destroy();
if (res.finished || closed) return resolve()
closed = true
if(err) httpErrorHandler(res,500,err)
else res.end()
resolve()
}
fileStream.on('error', () => close(`file ${basename(filePath)} error`));
fileStream.on('end', close);
res.on('close', close);
fileStream.pipe(res); // Passing data from a stream to a response
})
}
module.exports = sendFile