mirror of
https://github.com/CyberMind-FR/secubox-deb.git
synced 2026-07-28 21:17:36 +00:00
fix(torrent): stream.js Critical/Important review fixes (ref #917)
Critical: Change file.stream({start,end}) → file.createReadStream({start,end})
to match real webtorrent ^2.5.1 API (WHATWG ReadableStream vs Node Readable).
Important #1: RFC 7233 compliance — clamp end >= total to total-1 instead
of rejecting with 416. Only reject when start >= total or start > end.
Important #2: Attach stream error handlers to prevent unhandled crashes
on peer disconnect or missing pieces.
Minor: Add tests for range clamping (bytes=50-999999 on 100-byte file)
and out-of-range fileIdx. All 6 tests passing (green).
Co-Authored-By: Gerald KERMA <devel@cybermind.fr>
This commit is contained in:
parent
a6cc0df720
commit
d45803db0c
|
|
@ -22,18 +22,23 @@ export async function handleStream(engine, req, res) {
|
|||
const range = req.headers.range;
|
||||
if (!range) {
|
||||
res.writeHead(200, { 'Content-Length': total, 'Content-Type': type, 'Accept-Ranges': 'bytes' });
|
||||
file.stream({ start: 0, end: total - 1 }).pipe(res);
|
||||
const stream = file.createReadStream({ start: 0, end: total - 1 });
|
||||
stream.on('error', () => { try { res.destroy(); } catch {} });
|
||||
stream.pipe(res);
|
||||
return;
|
||||
}
|
||||
const m = /bytes=(\d+)-(\d*)/.exec(range);
|
||||
const start = m ? Number(m[1]) : 0;
|
||||
const end = m && m[2] ? Number(m[2]) : total - 1;
|
||||
if (start >= total || end >= total || start > end) {
|
||||
let start = m ? Number(m[1]) : 0;
|
||||
let end = m && m[2] ? Number(m[2]) : total - 1;
|
||||
if (end >= total) end = total - 1;
|
||||
if (start >= total || start > end) {
|
||||
res.writeHead(416, { 'Content-Range': `bytes */${total}` }); res.end(); return;
|
||||
}
|
||||
res.writeHead(206, { 'Content-Range': `bytes ${start}-${end}/${total}`,
|
||||
'Content-Length': end - start + 1, 'Content-Type': type, 'Accept-Ranges': 'bytes' });
|
||||
file.stream({ start, end }).pipe(res);
|
||||
const stream = file.createReadStream({ start, end });
|
||||
stream.on('error', () => { try { res.destroy(); } catch {} });
|
||||
stream.pipe(res);
|
||||
}
|
||||
|
||||
function mimeOf(name) { const e = (/\.([A-Za-z0-9]+)$/.exec(name) || [])[1]; return MIME[(e || '').toLowerCase()] || 'application/octet-stream'; }
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ function fakeRes() {
|
|||
const lower = o => Object.fromEntries(Object.entries(o).map(([k, v]) => [k.toLowerCase(), v]));
|
||||
function fakeEngine(len = 100) {
|
||||
const file = { name: 'movie.mp4', length: len,
|
||||
stream: ({ start, end }) => Readable.from([`bytes[${start}-${end}]`]) };
|
||||
createReadStream: ({ start, end }) => Readable.from([`bytes[${start}-${end}]`]) };
|
||||
return { get: () => ({ files: [file] }) };
|
||||
}
|
||||
|
||||
|
|
@ -58,3 +58,17 @@ test('unknown infohash returns 404', async () => {
|
|||
await handleStream({ get: () => null }, { params: { infohash: 'z', fileIdx: '0' }, headers: {} }, res);
|
||||
assert.equal(res.statusCode, 404);
|
||||
});
|
||||
|
||||
test('range clamping: bytes=50-999999 on 100-byte file returns 206 with clamped end', async () => {
|
||||
const res = fakeRes();
|
||||
await handleStream(fakeEngine(100), { params: { infohash: 'a', fileIdx: '0' }, headers: { range: 'bytes=50-999999' } }, res);
|
||||
assert.equal(res.statusCode, 206);
|
||||
assert.equal(res.headers['content-range'], 'bytes 50-99/100');
|
||||
assert.equal(res.headers['content-length'], 50);
|
||||
});
|
||||
|
||||
test('out-of-range fileIdx returns 404', async () => {
|
||||
const res = fakeRes();
|
||||
await handleStream(fakeEngine(100), { params: { infohash: 'a', fileIdx: '5' }, headers: {} }, res);
|
||||
assert.equal(res.statusCode, 404);
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user