Support Range header in genieacs-fs
This commit is contained in:
1 parent
02665faa9f
commit
f7e75caf2c
1 file changed
+52
-3
@@ -51,6 +51,27 @@ const getFile = memoize(
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
async function* partialContent(
|
||||||
|
chunks: Iterable<Buffer>,
|
||||||
|
start: number,
|
||||||
|
end: number
|
||||||
|
): AsyncIterable<Buffer> {
|
||||||
|
let bytesToSkip = start;
|
||||||
|
let bytesToRead = end - start;
|
||||||
|
|
||||||
|
for (let chunk of chunks) {
|
||||||
|
if (bytesToRead <= 0) return;
|
||||||
|
if (bytesToSkip >= chunk.length) {
|
||||||
|
bytesToSkip -= chunk.length;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
chunk = chunk.subarray(bytesToSkip, bytesToSkip + bytesToRead);
|
||||||
|
bytesToRead -= chunk.length;
|
||||||
|
bytesToSkip = 0;
|
||||||
|
yield chunk;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export async function listener(
|
export async function listener(
|
||||||
request: IncomingMessage,
|
request: IncomingMessage,
|
||||||
response: ServerResponse
|
response: ServerResponse
|
||||||
@@ -81,9 +102,37 @@ export async function listener(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
response.writeHead(200, {
|
let start = 0;
|
||||||
|
let end = file.length;
|
||||||
|
const rangeRequest = !!request.headers.range;
|
||||||
|
|
||||||
|
if (rangeRequest) {
|
||||||
|
const match = request.headers.range.match(/^bytes=(\d*)-(\d*)$/);
|
||||||
|
let rangeSatisfiable = false;
|
||||||
|
if (match && (match[1] || match[2])) {
|
||||||
|
if (match[2]) end = parseInt(match[2]) + 1;
|
||||||
|
if (match[1]) start = parseInt(match[1]);
|
||||||
|
else start = file.length - parseInt(match[2]);
|
||||||
|
rangeSatisfiable = start < end && end <= file.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!rangeSatisfiable) {
|
||||||
|
response.writeHead(416, {
|
||||||
|
"Content-Range": `bytes */${file.length}`,
|
||||||
|
"Content-Length": "0",
|
||||||
|
});
|
||||||
|
response.end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
response.writeHead(rangeRequest ? 206 : 200, {
|
||||||
"Content-Type": "application/octet-stream",
|
"Content-Type": "application/octet-stream",
|
||||||
"Content-Length": file.length,
|
"Content-Length": end - start,
|
||||||
|
"Accept-Ranges": "bytes",
|
||||||
|
...(rangeRequest && {
|
||||||
|
"Content-Range": `bytes ${start}-${end - 1}/${file.length}`,
|
||||||
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
logger.accessInfo(log);
|
logger.accessInfo(log);
|
||||||
@@ -99,7 +148,7 @@ export async function listener(
|
|||||||
filename
|
filename
|
||||||
);
|
);
|
||||||
|
|
||||||
pipeline(Readable.from(chunks), response, () => {
|
pipeline(Readable.from(partialContent(chunks, start, end)), response, () => {
|
||||||
// Ignore errors resulting from client disconnecting
|
// Ignore errors resulting from client disconnecting
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user