Fast and extensible multi-platform HTTP/1-2-3 web server with automatic HTTPS
Mirrored from https://github.com/Slazee/caddy.git
Synced Nov 11, 03:30 UTC
caddyhttp: document that negative idle timeouts disable them (#8146)
read_idle_timeout and write_idle_timeout default to 1 minute when zero, and the wrappers are only installed for positive values, so a negative value already disables them. Document it and cover it with tests, since it is the only way to opt out, for instance behind a reverse proxy that already protects from slow clients.
Kévin Dunglas committed
Oct 6, 2026 at 00:23 UTC
c65c2483365e2ef5102d6e3c0c73ef7bbb516d78
3 files changed
+66
-2
caddytest/integration/caddyfile_adapt/global_server_options_idle_disabled.caddyfiletest
new
+27
@@ -0,0 +1,27 @@
1
+{
2
+ servers {
3
+ timeouts {
4
+ read_body_idle -1s
5
+ write_idle -1s
6
+ }
7
+ }
8
+}
9
+
10
+:80 {
11
+}
12
+----------
13
+{
14
+ "apps": {
15
+ "http": {
16
+ "servers": {
17
+ "srv0": {
18
+ "listen": [
19
+ ":80"
20
+ ],
21
+ "read_idle_timeout": -1000000000,
22
+ "write_idle_timeout": -1000000000
23
+ }
24
+ }
25
+ }
26
+ }
27
+}
modules/caddyhttp/server.go
+4
-2
@@ -74,7 +74,8 @@ type Server struct {
74
// it mitigates slowloris-style attacks without penalizing large
75
// uploads from legitimately slow clients. Combine with ReadTimeout
76
// for a hard ceiling on top.
77
- // Default is 1 minute.
77
+ // Default is 1 minute. A negative value disables it, for instance
78
+ // behind a proxy that already buffers request bodies.
79
ReadIdleTimeout caddy.Duration `json:"read_idle_timeout,omitempty"`
80
81
// ReadMinRate, if set, requires the client to sustain at least this
@@ -97,7 +98,8 @@ type Server struct {
98
// response, or pauses between writes (e.g. SSE), is unaffected as
99
// long as each individual write keeps making progress. Combine
100
// with WriteTimeout for a hard ceiling on top.
100
- // Default is 1 minute.
101
+ // Default is 1 minute. A negative value disables it, for instance
102
+ // behind a proxy that already times out slow clients.
103
WriteIdleTimeout caddy.Duration `json:"write_idle_timeout,omitempty"`
104
105
// WriteMinRate is like ReadMinRate, but for writes to the client.
modules/caddyhttp/server_test.go
+35
@@ -1534,3 +1534,38 @@ func TestServer_ServeHTTP_DelayedHandlerErrorWritesErrorStatus(t *testing.T) {
1534
})
1535
}
1536
}
1537
+
1538
+func TestServer_ServeHTTP_IdleTimeouts(t *testing.T) {
1539
+ for _, tc := range []struct {
1540
+ name string
1541
+ timeout caddy.Duration
1542
+ applied bool
1543
+ }{
1544
+ {name: "positive", timeout: caddy.Duration(time.Minute), applied: true},
1545
+ {name: "negative disables", timeout: -1},
1546
+ } {
1547
+ t.Run(tc.name, func(t *testing.T) {
1548
+ var reader *IdleTimeoutReader
1549
+ var writer *IdleTimeoutWriter
1550
+ s := &Server{
1551
+ ReadIdleTimeout: tc.timeout,
1552
+ WriteIdleTimeout: tc.timeout,
1553
+ logger: zap.NewNop(),
1554
+ errorLogger: zap.NewNop(),
1555
+ primaryHandlerChain: HandlerFunc(func(_ http.ResponseWriter, r *http.Request) error {
1556
+ reader, writer = IdleTimeoutsFromContext(r.Context())
1557
+ return nil
1558
+ }),
1559
+ }
1560
+ ts := httptest.NewServer(http.HandlerFunc(s.ServeHTTP))
1561
+ t.Cleanup(ts.Close)
1562
+
1563
+ resp, err := ts.Client().Post(ts.URL, "text/plain", strings.NewReader("x"))
1564
+ require.NoError(t, err)
1565
+ resp.Body.Close()
1566
+
1567
+ assert.Equal(t, tc.applied, reader != nil)
1568
+ assert.Equal(t, tc.applied, writer != nil)
1569
+ })
1570
+ }
1571
+}