fix(downloads): resume Deepbrid open-ended ranges safely

Accept Deepbrid's open-ended 206 Content-Range response when the total is numeric, derive the missing end byte safely, and prefer byte-exact HTTP totals over rounded provider metadata. Preserve complete archive files on standard HTTP 416 responses when provider metadata is slightly smaller. Add end-to-end resume regressions that separate the final eight bytes and prove no retry, truncation, deletion, or second request occurs.
This commit is contained in:
Sucukdeluxe
2026-08-24 08:26:45 +02:00
parent 1b7caba2eb
commit 7fe438ba5d
2 changed files with 191 additions and 35 deletions
+24 -15
View File
@@ -510,13 +510,13 @@ function parseContentRange(contentRange: string | null): ParsedContentRange | nu
if (!contentRange) {
return null;
}
const match = contentRange.match(/^bytes\s+(\d+)-(\d+)\/(\d+|\*)$/i);
if (!match) {
return null;
}
const start = Number(match[1]);
const end = Number(match[2]);
const total = match[3] === "*" ? null : Number(match[3]);
const match = contentRange.match(/^bytes\s+(\d+)-(\d*)\/(\d+|\*)$/i);
if (!match) {
return null;
}
const start = Number(match[1]);
const total = match[3] === "*" ? null : Number(match[3]);
const end = match[2] ? Number(match[2]) : total === null ? NaN : total - 1;
if (!Number.isFinite(start) || !Number.isFinite(end) || start < 0 || end < start) {
return null;
}
@@ -526,9 +526,18 @@ function parseContentRange(contentRange: string | null): ParsedContentRange | nu
return { start, end, total };
}
function parseContentRangeTotal(contentRange: string | null): number | null {
return parseContentRange(contentRange)?.total ?? null;
}
function parseContentRangeTotal(contentRange: string | null): number | null {
const parsed = parseContentRange(contentRange)?.total;
if (parsed !== null && parsed !== undefined) {
return parsed;
}
const match = contentRange?.match(/^bytes\s+\*\/(\d+)$/i);
if (!match) {
return null;
}
const total = Number(match[1]);
return Number.isSafeInteger(total) && total > 0 ? total : null;
}
function parseContentDispositionFilename(contentDisposition: string | null): string {
if (!contentDisposition) {
@@ -11132,11 +11141,11 @@ export class DownloadManager extends EventEmitter {
contentLength,
totalFromRange
});
} else if (knownTotal && knownTotal > 0) {
item.totalBytes = knownTotal;
} else if (totalFromRange) {
item.totalBytes = totalFromRange;
} else if (contentLength > 0) {
} else if (totalFromRange) {
item.totalBytes = totalFromRange;
} else if (knownTotal && knownTotal > 0) {
item.totalBytes = knownTotal;
} else if (contentLength > 0) {
item.totalBytes = response.status === 206 ? existingBytes + contentLength : contentLength;
}
const completionPlan = planDownloadCompletion({