setHeaderForResponse(res, "Content-Type", contentType); } else if (context.options.mimeTypeDefault) { setHeaderForResponse(res, "Content-Type", context.options.mimeTypeDefault); } } if (!getHeaderFromResponse(res, "Accept-Ranges")) { setHeaderForResponse(res, "Accept-Ranges", "bytes"); } const rangeHeader = getHeaderFromRequest(req, "range"); let start; let end; if (rangeHeader && BYTES_RANGE_REGEXP.test(rangeHeader)) { const size = await new Promise(resolve => { /** @type {import("fs").lstat} */ context.outputFileSystem.lstat(filename, (error, stats) => { if (error) { context.logger.error(error); return; } resolve(stats.size); }); }); // eslint-disable-next-line global-require const parsedRanges = require("range-parser")(size, rangeHeader, { combine: true }); if (parsedRanges === -1) { const message = "Unsatisfiable range for 'Range' header."; context.logger.error(message); const existingHeaders = getHeaderNames(res); for (let i = 0; i < existingHeaders.length; i++) { res.removeHeader(existingHeaders[i]); } setStatusCode(res, 416); setHeaderForResponse(res, "Content-Range", getValueContentRangeHeader("bytes", size)); setHeaderForResponse(res, "Content-Type", "text/html; charset=utf-8"); /** @type {string | Buffer | import("fs").ReadStream} */ let document = createHtmlDocument(416, `Error: ${message}`); let byteLength = Buffer.byteLength(document); setHeaderForResponse(res, "Content-Length", Buffer.byteLength(document)); if (context.options.modifyResponseData) { ({ data: document, byteLength } = context.options.modifyResponseData(req, res, document, byteLength)); } send(req, res, document, byteLength); return; } else if (parsedRanges === -2) { context.logger.error("A malformed 'Range' header was provided. A regular response will be sent for this request."); } else if (parsedRanges.length > 1) { context.logger.error("A 'Range' header with multiple ranges was provided. Multiple ranges are not supported, so a regular response will be sent for this request."); } if (parsedRanges !== -2 && parsedRanges.length === 1) { // Content-Range setStatusCode(res, 206); setHeaderForResponse(res, "Content-Range", getValueContentRangeHeader("bytes", size, /** @type {import("range-parser").Ranges} */parsedRanges[0])); [{ start, end }] = parsedRanges; } } const isFsSupportsStream = typeof context.outputFileSystem.createReadStream === "function"; let bufferOrStream; let byteLength; try { if (typeof start !== "undefined" && typeof end !== "undefined" && isFsSupportsStream) { bufferOrStream = /** @type {import("fs").createReadStream} */ context.outputFileSystem.createReadStream(filename, { start, end }); byteLength = end - start + 1; } else { bufferOrStream = /** @type {import("fs").readFileSync} */context.outputFileSystem.readFileSync(filename); ({ byteLength } = bufferOrStream); } } catch (_ignoreError) { await goNext(); return; } if (context.options.modifyResponseData) { ({ data: bufferOrStream, byteLength } = context.options.modifyResponseData(req, res, bufferOrStream, byteLength)); } send(req, res, bufferOrStream, byteLength); } }; } module.exports = wrapper;