diff --git a/pkg/api/http/chunked.go b/pkg/api/http/chunked.go index 8438cee..d758d25 100644 --- a/pkg/api/http/chunked.go +++ b/pkg/api/http/chunked.go @@ -26,7 +26,7 @@ func (s *Server) chunkedHandler(w http.ResponseWriter, r *http.Request) { delay, err := strconv.Atoi(vars["wait"]) if err != nil { - delay = rand.Intn(int(s.config.HttpServerTimeout*time.Second)-10) + 10 + delay = randomDelaySeconds(s.config.HttpServerTimeout) } flusher, ok := w.(http.Flusher) @@ -46,3 +46,15 @@ func (s *Server) chunkedHandler(w http.ResponseWriter, r *http.Request) { flusher.Flush() } + +// randomDelaySeconds returns a random delay in seconds within [10, timeout), +// used when no explicit wait is provided. timeout is a time.Duration, so it is +// converted to whole seconds; the upper bound is clamped to keep rand.Intn's +// argument positive (it panics on a non-positive argument). +func randomDelaySeconds(timeout time.Duration) int { + maxDelay := int(timeout / time.Second) + if maxDelay <= 11 { + maxDelay = 12 + } + return rand.Intn(maxDelay-10) + 10 +} diff --git a/pkg/api/http/chunked_test.go b/pkg/api/http/chunked_test.go index 167b3b1..d753438 100644 --- a/pkg/api/http/chunked_test.go +++ b/pkg/api/http/chunked_test.go @@ -5,6 +5,7 @@ import ( "net/http/httptest" "regexp" "testing" + "time" ) func TestChunkedHandler(t *testing.T) { @@ -33,3 +34,19 @@ func TestChunkedHandler(t *testing.T) { rr.Body.String(), expected) } } + +// TestRandomDelaySeconds covers the default-delay branch taken by the bare +// /chunked route (no {wait} value). This used to panic because the +// duration-to-seconds math overflowed int64 and handed rand.Intn a negative +// argument. Every timeout must yield a valid delay in [10, max] without panicking. +func TestRandomDelaySeconds(t *testing.T) { + timeouts := []time.Duration{30 * time.Second, 12 * time.Second, time.Second, 0, -1} + for _, timeout := range timeouts { + for range 100 { + d := randomDelaySeconds(timeout) + if d < 10 { + t.Fatalf("timeout %s: delay %d below floor of 10", timeout, d) + } + } + } +}