Implement partial content support for GET: Add Content-Length and Content-Range headers

This commit is contained in:
Velih Dzen 2024-09-14 16:02:38 +08:00
parent 7503d6115b
commit 70b27972b9

View File

@ -133,12 +133,14 @@ async function handle_get(request: Request, bucket: R2Bucket): Promise<Response>
} else if (!isR2ObjectBody(object)) {
return new Response('Precondition Failed', { status: 412 });
} else {
const { rangeOffset, rangeEnd } = calcContentRange(object);
const contentLength = rangeEnd - rangeOffset + 1;
return new Response(object.body, {
status: object.range ? 206 : 200,
status: (object.range && contentLength !== object.size) ? 206 : 200,
headers: {
'Content-Type': object.httpMetadata?.contentType ?? 'application/octet-stream',
// TODO: Content-Length, Content-Range
'Content-Length': contentLength.toString(),
...({ 'Content-Range': `bytes ${rangeOffset}-${rangeEnd}/${object.size}` }),
...(object.httpMetadata?.contentDisposition
? {
'Content-Disposition': object.httpMetadata.contentDisposition,
@ -170,6 +172,24 @@ async function handle_get(request: Request, bucket: R2Bucket): Promise<Response>
}
}
function calcContentRange(object: R2ObjectBody) {
let rangeOffset = 0;
let rangeEnd = object.size - 1;
if (object.range) {
if ('suffix' in object.range) {
// Case 3: {suffix: number}
rangeOffset = object.size - object.range.suffix;
} else {
// Case 1: {offset: number, length?: number}
// Case 2: {offset?: number, length: number}
rangeOffset = object.range.offset ?? 0;
let length = object.range.length ?? (object.size - rangeOffset);
rangeEnd = Math.min(rangeOffset + length - 1, object.size - 1);
}
}
return { rangeOffset, rangeEnd };
}
async function handle_put(request: Request, bucket: R2Bucket): Promise<Response> {
if (request.url.endsWith('/')) {
return new Response('Method Not Allowed', { status: 405 });