httpdl: fix progress-reporter race on name/out; harden mirror & resume validation
Findings from a Rob-Pike-lens review (bugs/races/network), each verified against the code before fixing: - httpdl: name/out are now atomic.Pointer[string] -- the engine publishes a download to the reporter before Run resolves the name, so Stat raced the write (bt already did this) - httpdl: a malformed --proxy fails loudly instead of silently bypassing it - httpdl: a 206 must carry a matching Content-Range; a 200 in segmented mode is fatal so it fails over instead of burning the retry budget - httpdl: single-stream mirror failover validates the range before appending; ErrTooSlow only when the error is a real ctx cancellation - httpdl: idle guard tracks progress by timestamp (no Reset/Stop race, no sticky fired flag) - httpdl/control: reject a resume file whose segments don't tile [0,total) - bt: clamp the listen-port range; verify on-disk data before choosing pieces under --check-integrity - cli: reject size overflow; show --seed-time=MIN; clamp --select-file range - progress/engine/main: clamp ETA against int64 overflow; show queued downloads as waiting; join the reporter on exit instead of a 20ms sleep
This commit is contained in:
@@ -46,6 +46,12 @@ func (e *Engine) Run(ctx context.Context, downloads []Download) []Result {
|
||||
go func(i int, d Download) {
|
||||
defer wg.Done()
|
||||
|
||||
// Track immediately so a download still queued for a concurrency slot
|
||||
// is visible to the progress reporter as Waiting, rather than hidden
|
||||
// until it starts running.
|
||||
e.track(d)
|
||||
defer e.untrack(d)
|
||||
|
||||
// Acquire a concurrency slot, or bail if we're shutting down
|
||||
// before this download ever started.
|
||||
select {
|
||||
@@ -56,9 +62,6 @@ func (e *Engine) Run(ctx context.Context, downloads []Download) []Result {
|
||||
}
|
||||
defer func() { <-slots }()
|
||||
|
||||
e.track(d)
|
||||
defer e.untrack(d)
|
||||
|
||||
err := d.Run(ctx)
|
||||
results <- Result{Name: d.Name(), Index: i, Err: err, Stat: d.Stat()}
|
||||
}(i, d)
|
||||
@@ -74,7 +77,8 @@ func (e *Engine) Run(ctx context.Context, downloads []Download) []Result {
|
||||
return out
|
||||
}
|
||||
|
||||
// Snapshot returns a Stat for every currently running download.
|
||||
// Snapshot returns a Stat for every tracked download — those running plus those
|
||||
// still queued for a concurrency slot (reported as Waiting).
|
||||
func (e *Engine) Snapshot() []Stat {
|
||||
e.mu.Lock()
|
||||
defer e.mu.Unlock()
|
||||
|
||||
Reference in New Issue
Block a user