@marcel91200 / caddy Mirror · read-only / commits / de6b7800
Fork 0

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, 19:45 UTC

caddyhttp: Add server options `keepalive_idle` and `keepalive_count` (#7298)

* Add Server options KeepAliveIdle (keepalive_idle) and KeepAliveCount (keepalive_count) Signed-off-by: Joshua McBeth <joshua.mcbeth@gmail.com> * Add Server option KeepAliveDisable (keepalive_disable) Signed-off-by: Joshua McBeth <joshua.mcbeth@gmail.com> * Remove Server option KeepAliveDisable (keepalive_disable), disable when interval is negative Signed-off-by: Joshua McBeth <joshua.mcbeth@gmail.com> * Add keepalive parameters to caddyfiletest Signed-off-by: Joshua McBeth <joshua.mcbeth@gmail.com> --------- Signed-off-by: Joshua McBeth <joshua.mcbeth@gmail.com>

joshuamcbeth committed Oct 14, 2025 at 14:03 UTC de6b78009b840eb395c33b8d65c5d32746df38b6
4 files changed +52 -2
caddyconfig/httpcaddyfile/serveroptions.go
+26
@@ -18,6 +18,7 @@ import (
18 "encoding/json"
19 "fmt"
20 "slices"
21 + "strconv"
22
23 "github.com/dustin/go-humanize"
24
@@ -42,6 +43,8 @@ type serverOptions struct {
43 WriteTimeout caddy.Duration
44 IdleTimeout caddy.Duration
45 KeepAliveInterval caddy.Duration
46 + KeepAliveIdle caddy.Duration
47 + KeepAliveCount int
48 MaxHeaderBytes int
49 EnableFullDuplex bool
50 Protocols []string
@@ -142,6 +145,7 @@ func unmarshalCaddyfileServerOptions(d *caddyfile.Dispenser) (any, error) {
145 return nil, d.Errf("unrecognized timeouts option '%s'", d.Val())
146 }
147 }
148 +
149 case "keepalive_interval":
150 if !d.NextArg() {
151 return nil, d.ArgErr()
@@ -152,6 +156,26 @@ func unmarshalCaddyfileServerOptions(d *caddyfile.Dispenser) (any, error) {
156 }
157 serverOpts.KeepAliveInterval = caddy.Duration(dur)
158
159 + case "keepalive_idle":
160 + if !d.NextArg() {
161 + return nil, d.ArgErr()
162 + }
163 + dur, err := caddy.ParseDuration(d.Val())
164 + if err != nil {
165 + return nil, d.Errf("parsing keepalive idle duration: %v", err)
166 + }
167 + serverOpts.KeepAliveIdle = caddy.Duration(dur)
168 +
169 + case "keepalive_count":
170 + if !d.NextArg() {
171 + return nil, d.ArgErr()
172 + }
173 + cnt, err := strconv.ParseInt(d.Val(), 10, 32)
174 + if err != nil {
175 + return nil, d.Errf("parsing keepalive count int: %v", err)
176 + }
177 + serverOpts.KeepAliveCount = int(cnt)
178 +
179 case "max_header_size":
180 var sizeStr string
181 if !d.AllArgs(&sizeStr) {
@@ -309,6 +333,8 @@ func applyServerOptions(
333 server.WriteTimeout = opts.WriteTimeout
334 server.IdleTimeout = opts.IdleTimeout
335 server.KeepAliveInterval = opts.KeepAliveInterval
336 + server.KeepAliveIdle = opts.KeepAliveIdle
337 + server.KeepAliveCount = opts.KeepAliveCount
338 server.MaxHeaderBytes = opts.MaxHeaderBytes
339 server.EnableFullDuplex = opts.EnableFullDuplex
340 server.Protocols = opts.Protocols
caddytest/integration/caddyfile_adapt/global_server_options_single.caddyfiletest
+7 -1
@@ -18,6 +18,9 @@
18 trusted_proxies static private_ranges
19 client_ip_headers Custom-Real-Client-IP X-Forwarded-For
20 client_ip_headers A-Third-One
21 + keepalive_interval 20s
22 + keepalive_idle 20s
23 + keepalive_count 10
24 }
25 }
26
@@ -45,6 +48,9 @@ foo.com {
48 "read_header_timeout": 30000000000,
49 "write_timeout": 30000000000,
50 "idle_timeout": 30000000000,
51 + "keepalive_interval": 20000000000,
52 + "keepalive_idle": 20000000000,
53 + "keepalive_count": 10,
54 "max_header_bytes": 100000000,
55 "enable_full_duplex": true,
56 "routes": [
@@ -89,4 +95,4 @@ foo.com {
95 }
96 }
97 }
92 -}
\ No newline at end of file
98 +}
modules/caddyhttp/app.go
+2
@@ -538,6 +538,8 @@ func (app *App) Start() error {
538 KeepAliveConfig: net.KeepAliveConfig{
539 Enable: srv.KeepAliveInterval >= 0,
540 Interval: time.Duration(srv.KeepAliveInterval),
541 + Idle: time.Duration(srv.KeepAliveIdle),
542 + Count: srv.KeepAliveCount,
543 },
544 })
545 if err != nil {
modules/caddyhttp/server.go
+17 -1
@@ -76,9 +76,25 @@ type Server struct {
76
77 // KeepAliveInterval is the interval at which TCP keepalive packets
78 // are sent to keep the connection alive at the TCP layer when no other
79 - // data is being transmitted. The default is 15s.
79 + // data is being transmitted.
80 + // If zero, the default is 15s.
81 + // If negative, keepalive packets are not sent and other keepalive parameters
82 + // are ignored.
83 KeepAliveInterval caddy.Duration `json:"keepalive_interval,omitempty"`
84
85 + // KeepAliveIdle is the time that the connection must be idle before
86 + // the first TCP keep-alive probe is sent when no other data is being
87 + // transmitted.
88 + // If zero, the default is 15s.
89 + // If negative, underlying socket value is unchanged.
90 + KeepAliveIdle caddy.Duration `json:"keepalive_idle,omitempty"`
91 +
92 + // KeepAliveCount is the maximum number of TCP keep-alive probes that
93 + // should be sent before dropping a connection.
94 + // If zero, the default is 9.
95 + // If negative, underlying socket value is unchanged.
96 + KeepAliveCount int `json:"keepalive_count,omitempty"`
97 +
98 // MaxHeaderBytes is the maximum size to parse from a client's
99 // HTTP request headers.
100 MaxHeaderBytes int `json:"max_header_bytes,omitempty"`