Skip to content

Commit 302c092

Browse files
committed
Fix panic on GET /chunked from integer overflow
HttpServerTimeout is a time.Duration (nanoseconds); the default-delay branch scaled it by time.Second again, overflowing int64 to a negative value and passing it to rand.Intn, which panics. The bare /chunked route (no wait param) hit this on every request. Convert the timeout to whole seconds in a guarded helper that keeps rand.Intn's argument positive, and add a regression test.
1 parent 349544d commit 302c092

2 files changed

Lines changed: 30 additions & 1 deletion

File tree

pkg/api/http/chunked.go

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ func (s *Server) chunkedHandler(w http.ResponseWriter, r *http.Request) {
2626

2727
delay, err := strconv.Atoi(vars["wait"])
2828
if err != nil {
29-
delay = rand.Intn(int(s.config.HttpServerTimeout*time.Second)-10) + 10
29+
delay = randomDelaySeconds(s.config.HttpServerTimeout)
3030
}
3131

3232
flusher, ok := w.(http.Flusher)
@@ -46,3 +46,15 @@ func (s *Server) chunkedHandler(w http.ResponseWriter, r *http.Request) {
4646

4747
flusher.Flush()
4848
}
49+
50+
// randomDelaySeconds returns a random delay in seconds within [10, timeout),
51+
// used when no explicit wait is provided. timeout is a time.Duration, so it is
52+
// converted to whole seconds; the upper bound is clamped to keep rand.Intn's
53+
// argument positive (it panics on a non-positive argument).
54+
func randomDelaySeconds(timeout time.Duration) int {
55+
maxDelay := int(timeout / time.Second)
56+
if maxDelay <= 11 {
57+
maxDelay = 12
58+
}
59+
return rand.Intn(maxDelay-10) + 10
60+
}

pkg/api/http/chunked_test.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"net/http/httptest"
66
"regexp"
77
"testing"
8+
"time"
89
)
910

1011
func TestChunkedHandler(t *testing.T) {
@@ -33,3 +34,19 @@ func TestChunkedHandler(t *testing.T) {
3334
rr.Body.String(), expected)
3435
}
3536
}
37+
38+
// TestRandomDelaySeconds covers the default-delay branch taken by the bare
39+
// /chunked route (no {wait} value). This used to panic because the
40+
// duration-to-seconds math overflowed int64 and handed rand.Intn a negative
41+
// argument. Every timeout must yield a valid delay in [10, max] without panicking.
42+
func TestRandomDelaySeconds(t *testing.T) {
43+
timeouts := []time.Duration{30 * time.Second, 12 * time.Second, time.Second, 0, -1}
44+
for _, timeout := range timeouts {
45+
for range 100 {
46+
d := randomDelaySeconds(timeout)
47+
if d < 10 {
48+
t.Fatalf("timeout %s: delay %d below floor of 10", timeout, d)
49+
}
50+
}
51+
}
52+
}

0 commit comments

Comments
 (0)