Add HTTP range request support for video streaming
Safari and other browsers require Accept-Ranges: bytes and 206 Partial Content responses to play video. Without this, large videos fail to load (especially in Safari) because the entire file had to buffer in memory before sending. - Replace readFile + Buffer with createReadStream for efficient streaming - Parse Range header (start-end, start-, and suffix -N forms) - Return 206 Partial Content with Content-Range for range requests - Return 416 Range Not Satisfiable for out-of-bounds ranges - Add Accept-Ranges: bytes to all raw file responses Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -125,6 +125,51 @@ describe('GET /f/:id and GET /f/:id/raw', () => {
|
||||
const res = await ctx.app.inject({ method: 'GET', url: `/f/${fileId}/raw` });
|
||||
expect(res.statusCode).toBe(200);
|
||||
expect(res.body).toBe('hello!');
|
||||
expect(res.headers['accept-ranges']).toBe('bytes');
|
||||
});
|
||||
|
||||
it('returns 206 for a byte range request', async () => {
|
||||
const res = await ctx.app.inject({
|
||||
method: 'GET',
|
||||
url: `/f/${fileId}/raw`,
|
||||
headers: { range: 'bytes=0-3' },
|
||||
});
|
||||
expect(res.statusCode).toBe(206);
|
||||
expect(res.headers['content-range']).toBe('bytes 0-3/6');
|
||||
expect(res.headers['content-length']).toBe('4');
|
||||
expect(res.body).toBe('hell');
|
||||
});
|
||||
|
||||
it('returns 206 for an open-ended range request', async () => {
|
||||
const res = await ctx.app.inject({
|
||||
method: 'GET',
|
||||
url: `/f/${fileId}/raw`,
|
||||
headers: { range: 'bytes=2-' },
|
||||
});
|
||||
expect(res.statusCode).toBe(206);
|
||||
expect(res.headers['content-range']).toBe('bytes 2-5/6');
|
||||
expect(res.body).toBe('llo!');
|
||||
});
|
||||
|
||||
it('returns 206 for a suffix range request', async () => {
|
||||
const res = await ctx.app.inject({
|
||||
method: 'GET',
|
||||
url: `/f/${fileId}/raw`,
|
||||
headers: { range: 'bytes=-3' },
|
||||
});
|
||||
expect(res.statusCode).toBe(206);
|
||||
expect(res.headers['content-range']).toBe('bytes 3-5/6');
|
||||
expect(res.body).toBe('lo!');
|
||||
});
|
||||
|
||||
it('returns 416 for an unsatisfiable range', async () => {
|
||||
const res = await ctx.app.inject({
|
||||
method: 'GET',
|
||||
url: `/f/${fileId}/raw`,
|
||||
headers: { range: 'bytes=100-200' },
|
||||
});
|
||||
expect(res.statusCode).toBe(416);
|
||||
expect(res.headers['content-range']).toBe('bytes */6');
|
||||
});
|
||||
|
||||
it('returns 404 for unknown file', async () => {
|
||||
|
||||
Reference in New Issue
Block a user