Fix bdecode busy-loop on truncated torrent payloads.
Malformed bencode could set pos.i to NaN and hang Jest forever; guard the decoder and align the no-url-list fixture with current qbt behavior.
This commit is contained in:
@@ -17,38 +17,57 @@ function bencode(v) {
|
||||
]);
|
||||
}
|
||||
|
||||
// Minimal bencode decoder — returns Buffers for byte strings
|
||||
// Minimal bencode decoder — returns Buffers for byte strings.
|
||||
// Throws on truncated / malformed input (never busy-loops).
|
||||
function bdecode(buf, pos = { i: 0 }) {
|
||||
if (!Buffer.isBuffer(buf) || pos.i < 0 || pos.i >= buf.length) {
|
||||
throw new Error('bdecode: truncated');
|
||||
}
|
||||
const c = buf[pos.i];
|
||||
if (c === 0x69) { // 'i'
|
||||
pos.i++;
|
||||
const end = buf.indexOf(0x65, pos.i); // 'e'
|
||||
if (end < 0) throw new Error('bdecode: bad int');
|
||||
const n = parseInt(buf.slice(pos.i, end).toString(), 10);
|
||||
if (!Number.isFinite(n)) throw new Error('bdecode: bad int');
|
||||
pos.i = end + 1;
|
||||
return n;
|
||||
}
|
||||
if (c === 0x6c) { // 'l'
|
||||
pos.i++;
|
||||
const arr = [];
|
||||
while (buf[pos.i] !== 0x65) arr.push(bdecode(buf, pos));
|
||||
while (pos.i < buf.length && buf[pos.i] !== 0x65) {
|
||||
arr.push(bdecode(buf, pos));
|
||||
}
|
||||
if (pos.i >= buf.length || buf[pos.i] !== 0x65) {
|
||||
throw new Error('bdecode: unclosed list');
|
||||
}
|
||||
pos.i++;
|
||||
return arr;
|
||||
}
|
||||
if (c === 0x64) { // 'd'
|
||||
pos.i++;
|
||||
const obj = {};
|
||||
while (buf[pos.i] !== 0x65) {
|
||||
while (pos.i < buf.length && buf[pos.i] !== 0x65) {
|
||||
const key = bdecode(buf, pos).toString('utf8');
|
||||
obj[key] = bdecode(buf, pos);
|
||||
}
|
||||
if (pos.i >= buf.length || buf[pos.i] !== 0x65) {
|
||||
throw new Error('bdecode: unclosed dict');
|
||||
}
|
||||
pos.i++;
|
||||
return obj;
|
||||
}
|
||||
// byte string: "N:..."
|
||||
const colon = buf.indexOf(0x3a, pos.i); // ':'
|
||||
if (colon < 0 || colon >= buf.length) throw new Error('bdecode: bad string');
|
||||
const len = parseInt(buf.slice(pos.i, colon).toString(), 10);
|
||||
pos.i = colon + 1 + len;
|
||||
return buf.slice(colon + 1, pos.i);
|
||||
if (!Number.isFinite(len) || len < 0) throw new Error('bdecode: bad string length');
|
||||
const start = colon + 1;
|
||||
const end = start + len;
|
||||
if (end > buf.length) throw new Error('bdecode: string past end');
|
||||
pos.i = end;
|
||||
return buf.slice(start, end);
|
||||
}
|
||||
|
||||
// Build a minimal .torrent with an HTTP webseed and zeroed piece hashes.
|
||||
|
||||
Reference in New Issue
Block a user