fix(downloads): harden automatic capture and aria2 transfers

- Pass prepared redirect URIs to Aria2 while preserving stable source identities.

- Fence effective-connection telemetry and retry lifecycle transitions by control epoch.

- Keep credentialed routes conservative across redirects, mirrors, and inline URL credentials.

- Preflight destination access and preserve actionable retryable permission errors in the UI.

- Add adversarial regression coverage for ranges, redirects, retries, telemetry, and enqueue failures.
This commit is contained in:
NimBold
2026-08-15 14:31:38 +03:30
parent 92cfaa26ce
commit f77fd0be3f
14 changed files with 846 additions and 90 deletions
+7
View File
@@ -8,6 +8,13 @@ import type { DownloadErrorKind } from '../bindings/DownloadErrorKind';
export const classifyDownloadError = (message: unknown): DownloadErrorKind | undefined => {
if (typeof message !== 'string') return undefined;
const lower = message.toLowerCase();
if (
lower.includes('destination access retryable')
|| lower.includes('could not write to the selected folder')
|| lower.includes('selected folder could not be verified')
) {
return 'destinationAccess';
}
if (
lower.includes('aria2 error code 19')
|| (
+15
View File
@@ -58,6 +58,21 @@ describe('Properties connection presentation', () => {
});
});
it('shows effective Aria2 connections when the transfer is degraded', () => {
expect(getPropertiesConnectionPresentation({
isMedia: false,
isTorrent: false,
connections: 16,
activeConnections: 1,
requestedConnections: 16,
effectiveConnections: 1,
})).toMatchObject({
kind: 'aria2',
labelKey: 'connections',
value: '1 / 1',
});
});
it('does not use tellActive connections for the Torrent header', () => {
expect(getPropertiesConnectionPresentation({
isMedia: false,
+2 -2
View File
@@ -25,7 +25,7 @@ export const getPropertiesProgress = (
: resolveDownloadFraction(snapshot);
export const getPropertiesConnectionPresentation = (
snapshot: Pick<PropertiesSnapshot, 'isMedia' | 'isTorrent' | 'connections' | 'activeConnections' | 'requestedConnections' | 'torrentConnectedPeers' | 'torrentConnectedSeeders'>,
snapshot: Pick<PropertiesSnapshot, 'isMedia' | 'isTorrent' | 'connections' | 'activeConnections' | 'requestedConnections' | 'effectiveConnections' | 'torrentConnectedPeers' | 'torrentConnectedSeeders'>,
): PropertiesConnectionPresentation => {
if (snapshot.isMedia === true) {
return {
@@ -53,6 +53,6 @@ export const getPropertiesConnectionPresentation = (
kind: 'aria2',
showHeaderMetric: true,
labelKey: 'connections',
value: `${displayCount(snapshot.activeConnections)} / ${displayCount(snapshot.requestedConnections ?? snapshot.connections)}`,
value: `${displayCount(snapshot.activeConnections)} / ${displayCount(snapshot.effectiveConnections ?? snapshot.requestedConnections ?? snapshot.connections)}`,
};
};