Add range header support to files.get (#6950)

This commit is contained in:
Tom Moor
2024-05-28 08:12:25 -04:00
committed by GitHub
parent f58f309321
commit 50bbe05334
4 changed files with 52 additions and 6 deletions

View File

@@ -15,6 +15,7 @@ import { Attachment } from "@server/models";
import AttachmentHelper from "@server/models/helpers/AttachmentHelper";
import { authorize } from "@server/policies";
import FileStorage from "@server/storage/files";
import LocalStorage from "@server/storage/files/LocalStorage";
import { APIContext } from "@server/types";
import { RateLimiterStrategy } from "@server/utils/RateLimiter";
import { getJWTPayload } from "@server/utils/jwt";
@@ -84,12 +85,12 @@ router.get(
"application/octet-stream"
);
ctx.attachment(fileName);
ctx.body = await FileStorage.getFileStream(key);
} else {
const attachment = await Attachment.findOne({
where: { key },
rejectOnEmpty: true,
});
authorize(actor, "read", attachment);
ctx.set("Cache-Control", cacheHeader);
@@ -97,11 +98,47 @@ router.get(
ctx.attachment(attachment.name, {
type: FileStorage.getContentDisposition(attachment.contentType),
});
ctx.body = attachment.stream;
}
// Handle byte range requests
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Range_requests
const stats = await (FileStorage as LocalStorage).stat(key);
const range = getByteRange(ctx, stats.size);
if (range) {
ctx.set("Content-Length", String(range.end - range.start + 1));
ctx.set(
"Content-Range",
`bytes ${range.start}-${range.end}/${stats.size}`
);
} else {
ctx.set("Content-Length", String(stats.size));
}
ctx.body = await FileStorage.getFileStream(key, range);
}
);
function getByteRange(
ctx: APIContext<T.FilesGetReq>,
size: number
): { start: number; end: number } | undefined {
const { range } = ctx.headers;
if (!range) {
return;
}
const match = range.match(/bytes=(\d+)-(\d+)?/);
if (!match) {
return;
}
const start = parseInt(match[1], 10);
const end = parseInt(match[2], 10) || size - 1;
return { start, end };
}
function getKeyFromContext(ctx: APIContext<T.FilesGetReq>): string {
const { key, sig } = ctx.input.query;
if (sig) {