Commit Graph
9 Commits
Author SHA1 Message Date
imSp4rky 397cbae221 fix(downloader): accept a 200 whose body is exactly the requested byte-range slice
RFC 9110 permits a server to ignore Range and answer 200 with the whole
resource. When the item's slice starts at byte 0 and spans exactly the
response body, that 200 is byte-identical to the 206, so keep it instead of
burning all five attempts and failing the track. Every other 200 (nonzero
start, span mismatch, open-ended, encoded) still fails the attempt to
protect the merge.
2026-08-07 11:38:52 -06:00
imSp4rky e45cf15dd7 fix(downloader): fail closed on rnet content codings outside the old allowlist
The rnet branch zeroed content_length only for gzip/deflate/br, so an
unknown coding (zstd, future tokens) kept a bogus length and, worse, the
drop-the-partial-instead-of-Range-resuming guard could never fire on the
rnet path because content_encoded stayed False. Use the same fail-closed
_is_content_encoded check the requests branch uses.
2026-08-07 11:37:54 -06:00
imSp4rky 90a6164c56 test(downloader): make speed-limit tests immune to leaked cancel state
Any batch failure sets the process-global DOWNLOAD_CANCELLED, which
TokenBucket.consume waits on, so a test elsewhere could void every timing
assertion here; add the autouse clear fixture the other downloader test
modules already use. Also capture the debt sleep via a stub instead of
timing a real Event.wait, whose occasional spurious early wake tripped the
1.0s lower bound.
2026-08-07 11:36:53 -06:00
imSp4rky 431aa8fa54 fix(downloader): keep speed-limited batches in a single process
Spawned children re-import the module and start with no TokenBucket, so
--download-processes silently dropped a configured --speed-limit /
global_speed_limit for any 24+ segment batch. Fall back to the in-process
path while a limit is set (same gate as the ranged-parallel paths), log the
fallback, and document the interaction.
2026-08-07 11:36:17 -06:00
imSp4rky cfae8f8882 Merge branch 'dev' into feat/downloader-speed
Catch the branch up with dev (45 commits) so testers can run the perf work
against current dev.

Conflict resolutions:
- downloaders/requests.py: keep the branch's racing-gated read1, adaptive
  controller speed reporting and byte-range slice guards; take dev's
  content-encoding checks (raw reads are skipped on an encoded body) and its
  rolling SpeedWindow for the no-controller speed fallback. The single-URL
  ranged-parallel gate now requires no speed limit and no caller Range.
- service.py / session.py: keep the branch's TimeoutHTTPAdapter and retry
  config, raise POOL_MAX_SIZE to 64 so dev's pool-starvation fix survives
  (pool_block=True stalls threads on a pool smaller than the in-flight count).
- docs: dev split configuration.md into per-area pages, so the branch's rnet
  network option rows moved to reference/configuration/network.md.
2026-08-07 10:45:47 -06:00
imSp4rky d448ee8ff9 fix(downloader): decode content-encoded bodies instead of writing raw
Reading .raw skips urllib3's decoding, so brotli-served subtitles landed compressed and converted to empty files. Also drops a partial rather than Range-resuming an encoded body, since a Range indexes the encoded bytes.
2026-08-05 17:56:33 -06:00
imSp4rky 734df87bad feat(dl): add --speed-limit and serve global_speed_limit
Shared token bucket across all download threads; decimal suffixes (5M = 5.0 MB/s) or plain bytes/sec
2026-07-31 12:48:46 -06:00
imSp4rky b54aadea7a fix(downloader): honor Retry-After with cancel-safe backoff, add fault-injection bench and tests 2026-07-18 20:21:30 -06:00
imSp4rky 2adf8bad87 fix(downloader): validate 206 on byte-range segments and force identity encoding
Segments carrying their own Range (DASH SegmentBase, HLS EXT-X-BYTERANGE) now
fail the attempt when a server ignores the Range and returns 200, instead of
writing the whole parent resource as the segment and corrupting the merge. The
resume path no longer clobbers such a slice's Range, and retries rewrite the
slice whole. All segment GETs request Accept-Encoding: identity and the rnet
path mirrors the gzip guard, so transparent CDN (de)compression can't break the
Content-Length truncation check. Adds tests pinning these plus the adaptive
start-at-cap wiring and the small-segment tail-probe gate.
2026-07-16 00:00:26 -06:00