mirror of
https://github.com/TriliumNext/Notes.git
synced 2025-07-30 03:32:26 +08:00
61 lines
2.4 KiB
TypeScript
61 lines
2.4 KiB
TypeScript
import type { Request, Response } from "express";
|
|
import { parseRangeHeader } from "./parseRangeHeader.js";
|
|
import { RangeParserError } from "./RangeParserError.js";
|
|
import type { Logger } from "./Logger.js";
|
|
import type { ContentProvider } from "./ContentProvider.js";
|
|
import { ContentDoesNotExistError } from "./ContentDoesNotExistError.js";
|
|
import {
|
|
getRangeHeader,
|
|
setContentRangeHeader,
|
|
setContentTypeHeader,
|
|
setContentDispositionHeader,
|
|
setAcceptRangesHeader,
|
|
setContentLengthHeader,
|
|
setCacheControlHeaderNoCache
|
|
} from "./utils.js";
|
|
export function createPartialContentHandler(contentProvider: ContentProvider, logger: Logger) {
|
|
return async function handler(req: Request, res: Response) {
|
|
let content;
|
|
try {
|
|
content = await contentProvider(req);
|
|
} catch (error) {
|
|
logger.debug("createPartialContentHandler: ContentProvider threw exception: ", error);
|
|
if (error instanceof ContentDoesNotExistError) {
|
|
return res.status(404).send(error.message);
|
|
}
|
|
return res.sendStatus(500);
|
|
}
|
|
let { getStream, mimeType, fileName, totalSize } = content;
|
|
const rangeHeader = getRangeHeader(req);
|
|
let range;
|
|
try {
|
|
range = parseRangeHeader(rangeHeader, totalSize, logger);
|
|
} catch (error) {
|
|
logger.debug(`createPartialContentHandler: parseRangeHeader error: `, error);
|
|
if (error instanceof RangeParserError) {
|
|
setContentRangeHeader(null, totalSize, res);
|
|
return res.status(416).send(`Invalid value for Range: ${rangeHeader}`);
|
|
}
|
|
return res.sendStatus(500);
|
|
}
|
|
setContentTypeHeader(mimeType, res);
|
|
setContentDispositionHeader(fileName, res);
|
|
setAcceptRangesHeader(res);
|
|
// If range is not specified, or the file is empty, return the full stream
|
|
if (range === null) {
|
|
logger.debug("createPartialContentHandler: No range found, returning full content.");
|
|
setContentLengthHeader(String(totalSize), res);
|
|
return getStream().pipe(res);
|
|
}
|
|
setContentRangeHeader(range, totalSize, res);
|
|
let { start, end } = range;
|
|
setContentLengthHeader(String(start === end ? 0 : end - start + 1), res);
|
|
setCacheControlHeaderNoCache(res);
|
|
// Return 206 Partial Content status
|
|
logger.debug("createPartialContentHandler: Returning partial content for range: ", JSON.stringify(range));
|
|
res.status(206);
|
|
|
|
return getStream(range).pipe(res);
|
|
};
|
|
}
|