Notes/src/createPartialContentHandler.ts

61 lines
2.4 KiB
TypeScript
Raw Normal View History

import { Request, Response } from "express";
import { parseRangeHeader } from "./parseRangeHeader";
import { RangeParserError } from "./RangeParserError";
import { Logger } from "./Logger";
import { ContentProvider } from "./ContentProvider";
import { ContentDoesNotExistError } from "./ContentDoesNotExistError";
import {
getRangeHeader,
setContentRangeHeader,
setContentTypeHeader,
setContentDispositionHeader,
setAcceptRangesHeader,
setContentLengthHeader,
setCacheControlHeaderNoCache
} from "./utils";
2019-03-12 10:53:04 +05:30
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(totalSize, res);
return getStream().pipe(res);
}
setContentRangeHeader(range, totalSize, res);
let { start, end } = range;
setContentLengthHeader(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);
2019-03-19 15:05:08 +05:30
return getStream(range).pipe(res);
};
}