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:
2026-06-20 23:28:26 +09:00
parent c4c03dde60
commit e3505855c1
8 changed files with 255 additions and 79 deletions

View File

@@ -97,7 +97,12 @@ func flagLabel(o *Opt) string {
case Int:
b.WriteString("=N")
case Float:
b.WriteString("=RATIO")
// seed-time is a count of minutes; only seed-ratio is an actual ratio.
if o.Long == "seed-time" {
b.WriteString("=MIN")
} else {
b.WriteString("=RATIO")
}
case Enum:
b.WriteString("=" + strings.Join(o.Enum, "|"))
default:

View File

@@ -2,6 +2,7 @@ package cli
import (
"fmt"
"math"
"strconv"
"strings"
)
@@ -105,5 +106,10 @@ func parseSize(s string) (int64, error) {
if n < 0 {
return 0, fmt.Errorf("negative size %q", s)
}
// Reject a value whose unit multiply would overflow int64 and silently wrap to
// a bogus (positive or negative) byte count.
if mult > 1 && n > math.MaxInt64/mult {
return 0, fmt.Errorf("size %q too large", s)
}
return n * mult, nil
}