feat(download): implement single-threaded fallback for non-range servers #146

Merged
fuzzy merged 2 commits from feat/single-threaded-fallback into main 2026-07-13 18:35:23 +00:00
Owner

What

Implement proper single-threaded fallback for servers that don't support range requests (HTTP) or REST (FTP). Refactor download path into range-based and full-download code paths.

Why

Without this, servers lacking range support would get Range headers or RetrFrom calls that could fail. Now they get a plain GET/Retr and stream the full response.

Testing

  • go vet ./... passes
  • go build ./... passes
  • golangci-lint run ./... passes
  • Pre-commit hooks pass

Breaking Changes

Internal refactor of download helpers — no public API changes.

Notes

  • runRangeDownload — existing path for parallel chunked downloads with Range/RetrFrom
  • runFullDownload — new path for single-stream download without byte-range headers
  • HTTP: uses plain GET (no Range header), reads full response via io.Copy
  • FTP: uses Retr (not RetrFrom), reads full response via io.Copy
  • Triggered when server lacks Accept-Ranges/REST, or file size is unknown (<= 0)
  • Single worker shown in log message

Closes #0060
Closes #0061
Closes #0062
Closes #0063

## What Implement proper single-threaded fallback for servers that don't support range requests (HTTP) or REST (FTP). Refactor download path into range-based and full-download code paths. ## Why Without this, servers lacking range support would get Range headers or RetrFrom calls that could fail. Now they get a plain GET/Retr and stream the full response. ## Testing - [x] `go vet ./...` passes - [x] `go build ./...` passes - [x] `golangci-lint run ./...` passes - [x] Pre-commit hooks pass ## Breaking Changes Internal refactor of download helpers — no public API changes. ## Notes - `runRangeDownload` — existing path for parallel chunked downloads with Range/RetrFrom - `runFullDownload` — new path for single-stream download without byte-range headers - HTTP: uses plain GET (no Range header), reads full response via `io.Copy` - FTP: uses `Retr` (not `RetrFrom`), reads full response via `io.Copy` - Triggered when server lacks Accept-Ranges/REST, or file size is unknown (<= 0) - Single worker shown in log message Closes #0060 Closes #0061 Closes #0062 Closes #0063
Closes #0060 Closes #0061 Closes #0062 Closes #0063
docs(roadmap): mark single-threaded fallback complete
All checks were successful
Test and Release / test (pull_request) Successful in 1m33s
Test and Release / lint (pull_request) Successful in 9m19s
d01c974611
fuzzy scheduled this pull request to auto merge when all checks succeed 2026-07-13 18:26:32 +00:00
the.auditor left a comment

Review: APPROVED

Verification

  • go vet ./... passes
  • go build ./... passes
  • golangci-lint v2 run ./... 0 issues

Changes

  • internal/downloader/download.go — Refactored download helpers into range-based (downloadHTTPRange, downloadFTPRange, runRangeDownload) and full-download (downloadHTTPFull, downloadFTPSingle, runFullDownload) code paths
  • runWorker dispatches based on fullDownload flag
  • Download() sets fullDownload when server lacks range/REST support or size unknown
  • Full download writes via io.Copy (no Range headers, no size limit)
  • ROADMAP.md — Marks Phase 2 single-threaded fallback items as [x]

Notes

  • Fixes #138 (empty file when Content-Length unknown) — full download path uses io.Copy instead of io.CopyN with zero size

Closes #0060, #0061, #0062, #0063 on merge.

## Review: APPROVED ### Verification - `go vet ./...` — ✅ passes - `go build ./...` — ✅ passes - `golangci-lint v2 run ./...` — ✅ 0 issues ### Changes - `internal/downloader/download.go` — Refactored download helpers into range-based (`downloadHTTPRange`, `downloadFTPRange`, `runRangeDownload`) and full-download (`downloadHTTPFull`, `downloadFTPSingle`, `runFullDownload`) code paths - `runWorker` dispatches based on `fullDownload` flag - `Download()` sets `fullDownload` when server lacks range/REST support or size unknown - Full download writes via `io.Copy` (no Range headers, no size limit) - ROADMAP.md — Marks Phase 2 single-threaded fallback items as [x] ### Notes - Fixes #138 (empty file when Content-Length unknown) — full download path uses `io.Copy` instead of `io.CopyN` with zero size Closes #0060, #0061, #0062, #0063 on merge.
fuzzy merged commit d01c974611 into main 2026-07-13 18:35:23 +00:00
fuzzy deleted branch feat/single-threaded-fallback 2026-07-13 18:35:24 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
thwap/pget!146
No description provided.